├── .gitignore
├── .travis.yml
├── Cargo.lock
├── Cargo.toml
├── LICENSE_APACHE
├── LICENSE_MIT
├── README.md
├── iec
├── Cargo.toml
└── src
│ ├── diagnostics.rs
│ ├── ecs.rs
│ ├── hir.rs
│ ├── lib.rs
│ └── passes
│ ├── basic_blocks.rs
│ ├── mod.rs
│ ├── register_builtins.rs
│ ├── symbol_table.rs
│ └── variable_discovery.rs
├── runner
├── Cargo.toml
└── src
│ └── main.rs
└── syntax
├── Cargo.toml
├── build.rs
├── examples
└── iec_parse.rs
├── src
├── ast.rs
├── grammar.lalrpop
├── lib.rs
├── macros.rs
└── utils.rs
└── tests
├── compile_test.rs
└── data
├── function_block.st
├── hello_world.st
├── id_function.st
└── struct_decl.st
/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: rust
2 | sudo: false
3 | cache: cargo
4 |
5 | rust:
6 | # Any::type_id() requires 1.24, which is currently in beta
7 | # - stable
8 | - nightly
9 |
10 | script:
11 | - cargo build --all --verbose
12 | - cargo test --all --verbose
13 |
14 | before_deploy:
15 | - cargo doc --all --verbose
16 | - echo ' ' > target/doc/index.html
17 |
18 | deploy:
19 | provider: pages
20 | skip_cleanup: true
21 | github_token: $GITHUB_TOKEN
22 | keep_history: true
23 | local_dir: target/doc
24 | on:
25 | branch: master
--------------------------------------------------------------------------------
/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | [[package]]
4 | name = "aho-corasick"
5 | version = "0.7.1"
6 | source = "registry+https://github.com/rust-lang/crates.io-index"
7 | dependencies = [
8 | "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
9 | ]
10 |
11 | [[package]]
12 | name = "ansi_term"
13 | version = "0.11.0"
14 | source = "registry+https://github.com/rust-lang/crates.io-index"
15 | dependencies = [
16 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
17 | ]
18 |
19 | [[package]]
20 | name = "argon2rs"
21 | version = "0.2.5"
22 | source = "registry+https://github.com/rust-lang/crates.io-index"
23 | dependencies = [
24 | "blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
25 | "scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
26 | ]
27 |
28 | [[package]]
29 | name = "arrayvec"
30 | version = "0.4.10"
31 | source = "registry+https://github.com/rust-lang/crates.io-index"
32 | dependencies = [
33 | "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
34 | ]
35 |
36 | [[package]]
37 | name = "ascii-canvas"
38 | version = "1.0.0"
39 | source = "registry+https://github.com/rust-lang/crates.io-index"
40 | dependencies = [
41 | "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
42 | ]
43 |
44 | [[package]]
45 | name = "atty"
46 | version = "0.2.11"
47 | source = "registry+https://github.com/rust-lang/crates.io-index"
48 | dependencies = [
49 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
50 | "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
51 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
52 | ]
53 |
54 | [[package]]
55 | name = "autocfg"
56 | version = "0.1.2"
57 | source = "registry+https://github.com/rust-lang/crates.io-index"
58 |
59 | [[package]]
60 | name = "backtrace"
61 | version = "0.3.14"
62 | source = "registry+https://github.com/rust-lang/crates.io-index"
63 | dependencies = [
64 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
65 | "backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
66 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
67 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
68 | "rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
69 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
70 | ]
71 |
72 | [[package]]
73 | name = "backtrace-sys"
74 | version = "0.1.28"
75 | source = "registry+https://github.com/rust-lang/crates.io-index"
76 | dependencies = [
77 | "cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)",
78 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
79 | ]
80 |
81 | [[package]]
82 | name = "bit-set"
83 | version = "0.5.1"
84 | source = "registry+https://github.com/rust-lang/crates.io-index"
85 | dependencies = [
86 | "bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
87 | ]
88 |
89 | [[package]]
90 | name = "bit-vec"
91 | version = "0.5.1"
92 | source = "registry+https://github.com/rust-lang/crates.io-index"
93 |
94 | [[package]]
95 | name = "bitflags"
96 | version = "1.0.4"
97 | source = "registry+https://github.com/rust-lang/crates.io-index"
98 |
99 | [[package]]
100 | name = "blake2-rfc"
101 | version = "0.2.18"
102 | source = "registry+https://github.com/rust-lang/crates.io-index"
103 | dependencies = [
104 | "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
105 | "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
106 | ]
107 |
108 | [[package]]
109 | name = "block-buffer"
110 | version = "0.7.0"
111 | source = "registry+https://github.com/rust-lang/crates.io-index"
112 | dependencies = [
113 | "block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
114 | "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
115 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
116 | "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
117 | ]
118 |
119 | [[package]]
120 | name = "block-padding"
121 | version = "0.1.3"
122 | source = "registry+https://github.com/rust-lang/crates.io-index"
123 | dependencies = [
124 | "byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
125 | ]
126 |
127 | [[package]]
128 | name = "byte-tools"
129 | version = "0.3.1"
130 | source = "registry+https://github.com/rust-lang/crates.io-index"
131 |
132 | [[package]]
133 | name = "byteorder"
134 | version = "1.3.1"
135 | source = "registry+https://github.com/rust-lang/crates.io-index"
136 |
137 | [[package]]
138 | name = "cc"
139 | version = "1.0.32"
140 | source = "registry+https://github.com/rust-lang/crates.io-index"
141 |
142 | [[package]]
143 | name = "cfg-if"
144 | version = "0.1.7"
145 | source = "registry+https://github.com/rust-lang/crates.io-index"
146 |
147 | [[package]]
148 | name = "chrono"
149 | version = "0.4.6"
150 | source = "registry+https://github.com/rust-lang/crates.io-index"
151 | dependencies = [
152 | "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
153 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
154 | "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
155 | ]
156 |
157 | [[package]]
158 | name = "clap"
159 | version = "2.32.0"
160 | source = "registry+https://github.com/rust-lang/crates.io-index"
161 | dependencies = [
162 | "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
163 | "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
164 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
165 | "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
166 | "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
167 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
168 | "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
169 | ]
170 |
171 | [[package]]
172 | name = "cloudabi"
173 | version = "0.0.3"
174 | source = "registry+https://github.com/rust-lang/crates.io-index"
175 | dependencies = [
176 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
177 | ]
178 |
179 | [[package]]
180 | name = "codespan"
181 | version = "0.2.1"
182 | source = "registry+https://github.com/rust-lang/crates.io-index"
183 | dependencies = [
184 | "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
185 | "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
186 | "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
187 | "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
188 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
189 | "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
190 | ]
191 |
192 | [[package]]
193 | name = "codespan-reporting"
194 | version = "0.2.1"
195 | source = "registry+https://github.com/rust-lang/crates.io-index"
196 | dependencies = [
197 | "codespan 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
198 | "termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
199 | ]
200 |
201 | [[package]]
202 | name = "constant_time_eq"
203 | version = "0.1.3"
204 | source = "registry+https://github.com/rust-lang/crates.io-index"
205 |
206 | [[package]]
207 | name = "ctor"
208 | version = "0.1.7"
209 | source = "registry+https://github.com/rust-lang/crates.io-index"
210 | dependencies = [
211 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
212 | "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
213 | ]
214 |
215 | [[package]]
216 | name = "diff"
217 | version = "0.1.11"
218 | source = "registry+https://github.com/rust-lang/crates.io-index"
219 |
220 | [[package]]
221 | name = "difference"
222 | version = "2.0.0"
223 | source = "registry+https://github.com/rust-lang/crates.io-index"
224 |
225 | [[package]]
226 | name = "digest"
227 | version = "0.8.0"
228 | source = "registry+https://github.com/rust-lang/crates.io-index"
229 | dependencies = [
230 | "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
231 | ]
232 |
233 | [[package]]
234 | name = "dirs"
235 | version = "1.0.5"
236 | source = "registry+https://github.com/rust-lang/crates.io-index"
237 | dependencies = [
238 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
239 | "redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
240 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
241 | ]
242 |
243 | [[package]]
244 | name = "docopt"
245 | version = "1.0.2"
246 | source = "registry+https://github.com/rust-lang/crates.io-index"
247 | dependencies = [
248 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
249 | "regex 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
250 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
251 | "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
252 | "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
253 | ]
254 |
255 | [[package]]
256 | name = "either"
257 | version = "1.5.1"
258 | source = "registry+https://github.com/rust-lang/crates.io-index"
259 |
260 | [[package]]
261 | name = "ena"
262 | version = "0.11.0"
263 | source = "registry+https://github.com/rust-lang/crates.io-index"
264 | dependencies = [
265 | "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
266 | ]
267 |
268 | [[package]]
269 | name = "failure"
270 | version = "0.1.5"
271 | source = "registry+https://github.com/rust-lang/crates.io-index"
272 | dependencies = [
273 | "backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
274 | "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
275 | ]
276 |
277 | [[package]]
278 | name = "failure_derive"
279 | version = "0.1.5"
280 | source = "registry+https://github.com/rust-lang/crates.io-index"
281 | dependencies = [
282 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
283 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
284 | "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
285 | "synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
286 | ]
287 |
288 | [[package]]
289 | name = "fake-simd"
290 | version = "0.1.2"
291 | source = "registry+https://github.com/rust-lang/crates.io-index"
292 |
293 | [[package]]
294 | name = "fixedbitset"
295 | version = "0.1.9"
296 | source = "registry+https://github.com/rust-lang/crates.io-index"
297 |
298 | [[package]]
299 | name = "fuchsia-cprng"
300 | version = "0.1.1"
301 | source = "registry+https://github.com/rust-lang/crates.io-index"
302 |
303 | [[package]]
304 | name = "generic-array"
305 | version = "0.12.0"
306 | source = "registry+https://github.com/rust-lang/crates.io-index"
307 | dependencies = [
308 | "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
309 | ]
310 |
311 | [[package]]
312 | name = "heapsize"
313 | version = "0.4.2"
314 | source = "registry+https://github.com/rust-lang/crates.io-index"
315 | dependencies = [
316 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
317 | ]
318 |
319 | [[package]]
320 | name = "heapsize_derive"
321 | version = "0.1.4"
322 | source = "registry+https://github.com/rust-lang/crates.io-index"
323 | dependencies = [
324 | "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
325 | "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
326 | "synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
327 | ]
328 |
329 | [[package]]
330 | name = "heck"
331 | version = "0.3.1"
332 | source = "registry+https://github.com/rust-lang/crates.io-index"
333 | dependencies = [
334 | "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
335 | ]
336 |
337 | [[package]]
338 | name = "iec"
339 | version = "0.1.0"
340 | dependencies = [
341 | "codespan 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
342 | "codespan-reporting 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
343 | "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
344 | "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
345 | "iec_syntax 0.1.0",
346 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
347 | "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
348 | "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
349 | "typename 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
350 | ]
351 |
352 | [[package]]
353 | name = "iec_runner"
354 | version = "0.1.0"
355 | dependencies = [
356 | "codespan 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
357 | "codespan-reporting 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
358 | "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
359 | "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
360 | "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
361 | "iec 0.1.0",
362 | "iec_syntax 0.1.0",
363 | "lalrpop-util 0.16.3 (registry+https://github.com/rust-lang/crates.io-index)",
364 | "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
365 | "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
366 | "slog-term 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
367 | "slog_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
368 | "structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
369 | ]
370 |
371 | [[package]]
372 | name = "iec_syntax"
373 | version = "0.1.0"
374 | dependencies = [
375 | "codespan 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
376 | "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
377 | "heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
378 | "lalrpop 0.16.3 (registry+https://github.com/rust-lang/crates.io-index)",
379 | "lalrpop-util 0.16.3 (registry+https://github.com/rust-lang/crates.io-index)",
380 | "pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
381 | "regex 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
382 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
383 | "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
384 | "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)",
385 | "structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
386 | "sum_type 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
387 | ]
388 |
389 | [[package]]
390 | name = "isatty"
391 | version = "0.1.9"
392 | source = "registry+https://github.com/rust-lang/crates.io-index"
393 | dependencies = [
394 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
395 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
396 | "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
397 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
398 | ]
399 |
400 | [[package]]
401 | name = "itertools"
402 | version = "0.8.0"
403 | source = "registry+https://github.com/rust-lang/crates.io-index"
404 | dependencies = [
405 | "either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
406 | ]
407 |
408 | [[package]]
409 | name = "itoa"
410 | version = "0.4.3"
411 | source = "registry+https://github.com/rust-lang/crates.io-index"
412 |
413 | [[package]]
414 | name = "kernel32-sys"
415 | version = "0.2.2"
416 | source = "registry+https://github.com/rust-lang/crates.io-index"
417 | dependencies = [
418 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
419 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
420 | ]
421 |
422 | [[package]]
423 | name = "lalrpop"
424 | version = "0.16.3"
425 | source = "registry+https://github.com/rust-lang/crates.io-index"
426 | dependencies = [
427 | "ascii-canvas 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
428 | "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
429 | "bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
430 | "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
431 | "docopt 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
432 | "ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
433 | "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
434 | "lalrpop-util 0.16.3 (registry+https://github.com/rust-lang/crates.io-index)",
435 | "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
436 | "regex 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
437 | "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
438 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
439 | "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
440 | "sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
441 | "string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)",
442 | "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
443 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
444 | ]
445 |
446 | [[package]]
447 | name = "lalrpop-util"
448 | version = "0.16.3"
449 | source = "registry+https://github.com/rust-lang/crates.io-index"
450 |
451 | [[package]]
452 | name = "lazy_static"
453 | version = "1.3.0"
454 | source = "registry+https://github.com/rust-lang/crates.io-index"
455 |
456 | [[package]]
457 | name = "libc"
458 | version = "0.2.51"
459 | source = "registry+https://github.com/rust-lang/crates.io-index"
460 |
461 | [[package]]
462 | name = "log"
463 | version = "0.4.6"
464 | source = "registry+https://github.com/rust-lang/crates.io-index"
465 | dependencies = [
466 | "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
467 | ]
468 |
469 | [[package]]
470 | name = "memchr"
471 | version = "2.2.0"
472 | source = "registry+https://github.com/rust-lang/crates.io-index"
473 |
474 | [[package]]
475 | name = "new_debug_unreachable"
476 | version = "1.0.3"
477 | source = "registry+https://github.com/rust-lang/crates.io-index"
478 |
479 | [[package]]
480 | name = "nodrop"
481 | version = "0.1.13"
482 | source = "registry+https://github.com/rust-lang/crates.io-index"
483 |
484 | [[package]]
485 | name = "num-integer"
486 | version = "0.1.39"
487 | source = "registry+https://github.com/rust-lang/crates.io-index"
488 | dependencies = [
489 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
490 | ]
491 |
492 | [[package]]
493 | name = "num-traits"
494 | version = "0.2.6"
495 | source = "registry+https://github.com/rust-lang/crates.io-index"
496 |
497 | [[package]]
498 | name = "opaque-debug"
499 | version = "0.2.2"
500 | source = "registry+https://github.com/rust-lang/crates.io-index"
501 |
502 | [[package]]
503 | name = "ordermap"
504 | version = "0.3.5"
505 | source = "registry+https://github.com/rust-lang/crates.io-index"
506 |
507 | [[package]]
508 | name = "output_vt100"
509 | version = "0.1.2"
510 | source = "registry+https://github.com/rust-lang/crates.io-index"
511 | dependencies = [
512 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
513 | ]
514 |
515 | [[package]]
516 | name = "petgraph"
517 | version = "0.4.13"
518 | source = "registry+https://github.com/rust-lang/crates.io-index"
519 | dependencies = [
520 | "fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
521 | "ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
522 | ]
523 |
524 | [[package]]
525 | name = "phf_generator"
526 | version = "0.7.24"
527 | source = "registry+https://github.com/rust-lang/crates.io-index"
528 | dependencies = [
529 | "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
530 | "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
531 | ]
532 |
533 | [[package]]
534 | name = "phf_shared"
535 | version = "0.7.24"
536 | source = "registry+https://github.com/rust-lang/crates.io-index"
537 | dependencies = [
538 | "siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
539 | ]
540 |
541 | [[package]]
542 | name = "precomputed-hash"
543 | version = "0.1.1"
544 | source = "registry+https://github.com/rust-lang/crates.io-index"
545 |
546 | [[package]]
547 | name = "pretty_assertions"
548 | version = "0.6.1"
549 | source = "registry+https://github.com/rust-lang/crates.io-index"
550 | dependencies = [
551 | "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
552 | "ctor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
553 | "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
554 | "output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
555 | ]
556 |
557 | [[package]]
558 | name = "proc-macro2"
559 | version = "0.4.27"
560 | source = "registry+https://github.com/rust-lang/crates.io-index"
561 | dependencies = [
562 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
563 | ]
564 |
565 | [[package]]
566 | name = "quote"
567 | version = "0.3.15"
568 | source = "registry+https://github.com/rust-lang/crates.io-index"
569 |
570 | [[package]]
571 | name = "quote"
572 | version = "0.6.11"
573 | source = "registry+https://github.com/rust-lang/crates.io-index"
574 | dependencies = [
575 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
576 | ]
577 |
578 | [[package]]
579 | name = "rand"
580 | version = "0.6.5"
581 | source = "registry+https://github.com/rust-lang/crates.io-index"
582 | dependencies = [
583 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
584 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
585 | "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
586 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
587 | "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
588 | "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
589 | "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
590 | "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
591 | "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
592 | "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
593 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
594 | ]
595 |
596 | [[package]]
597 | name = "rand_chacha"
598 | version = "0.1.1"
599 | source = "registry+https://github.com/rust-lang/crates.io-index"
600 | dependencies = [
601 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
602 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
603 | ]
604 |
605 | [[package]]
606 | name = "rand_core"
607 | version = "0.3.1"
608 | source = "registry+https://github.com/rust-lang/crates.io-index"
609 | dependencies = [
610 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
611 | ]
612 |
613 | [[package]]
614 | name = "rand_core"
615 | version = "0.4.0"
616 | source = "registry+https://github.com/rust-lang/crates.io-index"
617 |
618 | [[package]]
619 | name = "rand_hc"
620 | version = "0.1.0"
621 | source = "registry+https://github.com/rust-lang/crates.io-index"
622 | dependencies = [
623 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
624 | ]
625 |
626 | [[package]]
627 | name = "rand_isaac"
628 | version = "0.1.1"
629 | source = "registry+https://github.com/rust-lang/crates.io-index"
630 | dependencies = [
631 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
632 | ]
633 |
634 | [[package]]
635 | name = "rand_jitter"
636 | version = "0.1.3"
637 | source = "registry+https://github.com/rust-lang/crates.io-index"
638 | dependencies = [
639 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
640 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
641 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
642 | ]
643 |
644 | [[package]]
645 | name = "rand_os"
646 | version = "0.1.3"
647 | source = "registry+https://github.com/rust-lang/crates.io-index"
648 | dependencies = [
649 | "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
650 | "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
651 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
652 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
653 | "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
654 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
655 | ]
656 |
657 | [[package]]
658 | name = "rand_pcg"
659 | version = "0.1.2"
660 | source = "registry+https://github.com/rust-lang/crates.io-index"
661 | dependencies = [
662 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
663 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
664 | ]
665 |
666 | [[package]]
667 | name = "rand_xorshift"
668 | version = "0.1.1"
669 | source = "registry+https://github.com/rust-lang/crates.io-index"
670 | dependencies = [
671 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
672 | ]
673 |
674 | [[package]]
675 | name = "rdrand"
676 | version = "0.4.0"
677 | source = "registry+https://github.com/rust-lang/crates.io-index"
678 | dependencies = [
679 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
680 | ]
681 |
682 | [[package]]
683 | name = "redox_syscall"
684 | version = "0.1.51"
685 | source = "registry+https://github.com/rust-lang/crates.io-index"
686 |
687 | [[package]]
688 | name = "redox_termios"
689 | version = "0.1.1"
690 | source = "registry+https://github.com/rust-lang/crates.io-index"
691 | dependencies = [
692 | "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
693 | ]
694 |
695 | [[package]]
696 | name = "redox_users"
697 | version = "0.3.0"
698 | source = "registry+https://github.com/rust-lang/crates.io-index"
699 | dependencies = [
700 | "argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
701 | "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
702 | "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
703 | "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
704 | ]
705 |
706 | [[package]]
707 | name = "regex"
708 | version = "1.1.3"
709 | source = "registry+https://github.com/rust-lang/crates.io-index"
710 | dependencies = [
711 | "aho-corasick 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
712 | "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
713 | "regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
714 | "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
715 | "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
716 | ]
717 |
718 | [[package]]
719 | name = "regex-syntax"
720 | version = "0.6.6"
721 | source = "registry+https://github.com/rust-lang/crates.io-index"
722 | dependencies = [
723 | "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
724 | ]
725 |
726 | [[package]]
727 | name = "rustc-demangle"
728 | version = "0.1.13"
729 | source = "registry+https://github.com/rust-lang/crates.io-index"
730 |
731 | [[package]]
732 | name = "ryu"
733 | version = "0.2.7"
734 | source = "registry+https://github.com/rust-lang/crates.io-index"
735 |
736 | [[package]]
737 | name = "scoped_threadpool"
738 | version = "0.1.9"
739 | source = "registry+https://github.com/rust-lang/crates.io-index"
740 |
741 | [[package]]
742 | name = "serde"
743 | version = "1.0.89"
744 | source = "registry+https://github.com/rust-lang/crates.io-index"
745 |
746 | [[package]]
747 | name = "serde_derive"
748 | version = "1.0.89"
749 | source = "registry+https://github.com/rust-lang/crates.io-index"
750 | dependencies = [
751 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
752 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
753 | "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
754 | ]
755 |
756 | [[package]]
757 | name = "serde_json"
758 | version = "1.0.39"
759 | source = "registry+https://github.com/rust-lang/crates.io-index"
760 | dependencies = [
761 | "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
762 | "ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
763 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
764 | ]
765 |
766 | [[package]]
767 | name = "sha2"
768 | version = "0.8.0"
769 | source = "registry+https://github.com/rust-lang/crates.io-index"
770 | dependencies = [
771 | "block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
772 | "digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
773 | "fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
774 | "opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
775 | ]
776 |
777 | [[package]]
778 | name = "siphasher"
779 | version = "0.2.3"
780 | source = "registry+https://github.com/rust-lang/crates.io-index"
781 |
782 | [[package]]
783 | name = "slog"
784 | version = "2.4.1"
785 | source = "registry+https://github.com/rust-lang/crates.io-index"
786 |
787 | [[package]]
788 | name = "slog-async"
789 | version = "2.3.0"
790 | source = "registry+https://github.com/rust-lang/crates.io-index"
791 | dependencies = [
792 | "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
793 | "take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
794 | "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
795 | ]
796 |
797 | [[package]]
798 | name = "slog-term"
799 | version = "2.4.0"
800 | source = "registry+https://github.com/rust-lang/crates.io-index"
801 | dependencies = [
802 | "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
803 | "isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
804 | "slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
805 | "term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
806 | "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
807 | ]
808 |
809 | [[package]]
810 | name = "slog_derive"
811 | version = "0.1.1"
812 | source = "registry+https://github.com/rust-lang/crates.io-index"
813 | dependencies = [
814 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
815 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
816 | "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
817 | ]
818 |
819 | [[package]]
820 | name = "string_cache"
821 | version = "0.7.3"
822 | source = "registry+https://github.com/rust-lang/crates.io-index"
823 | dependencies = [
824 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
825 | "new_debug_unreachable 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
826 | "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
827 | "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
828 | "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
829 | "string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
830 | "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
831 | ]
832 |
833 | [[package]]
834 | name = "string_cache_codegen"
835 | version = "0.4.2"
836 | source = "registry+https://github.com/rust-lang/crates.io-index"
837 | dependencies = [
838 | "phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
839 | "phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)",
840 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
841 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
842 | "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
843 | ]
844 |
845 | [[package]]
846 | name = "string_cache_shared"
847 | version = "0.3.0"
848 | source = "registry+https://github.com/rust-lang/crates.io-index"
849 |
850 | [[package]]
851 | name = "strsim"
852 | version = "0.7.0"
853 | source = "registry+https://github.com/rust-lang/crates.io-index"
854 |
855 | [[package]]
856 | name = "structopt"
857 | version = "0.2.15"
858 | source = "registry+https://github.com/rust-lang/crates.io-index"
859 | dependencies = [
860 | "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
861 | "structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)",
862 | ]
863 |
864 | [[package]]
865 | name = "structopt-derive"
866 | version = "0.2.15"
867 | source = "registry+https://github.com/rust-lang/crates.io-index"
868 | dependencies = [
869 | "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
870 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
871 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
872 | "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
873 | ]
874 |
875 | [[package]]
876 | name = "sum_type"
877 | version = "0.1.1"
878 | source = "registry+https://github.com/rust-lang/crates.io-index"
879 |
880 | [[package]]
881 | name = "syn"
882 | version = "0.11.11"
883 | source = "registry+https://github.com/rust-lang/crates.io-index"
884 | dependencies = [
885 | "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
886 | "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
887 | "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
888 | ]
889 |
890 | [[package]]
891 | name = "syn"
892 | version = "0.15.29"
893 | source = "registry+https://github.com/rust-lang/crates.io-index"
894 | dependencies = [
895 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
896 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
897 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
898 | ]
899 |
900 | [[package]]
901 | name = "synom"
902 | version = "0.11.3"
903 | source = "registry+https://github.com/rust-lang/crates.io-index"
904 | dependencies = [
905 | "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
906 | ]
907 |
908 | [[package]]
909 | name = "synstructure"
910 | version = "0.5.2"
911 | source = "registry+https://github.com/rust-lang/crates.io-index"
912 | dependencies = [
913 | "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
914 | "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
915 | ]
916 |
917 | [[package]]
918 | name = "synstructure"
919 | version = "0.10.1"
920 | source = "registry+https://github.com/rust-lang/crates.io-index"
921 | dependencies = [
922 | "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
923 | "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
924 | "syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)",
925 | "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
926 | ]
927 |
928 | [[package]]
929 | name = "take_mut"
930 | version = "0.2.2"
931 | source = "registry+https://github.com/rust-lang/crates.io-index"
932 |
933 | [[package]]
934 | name = "term"
935 | version = "0.4.6"
936 | source = "registry+https://github.com/rust-lang/crates.io-index"
937 | dependencies = [
938 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
939 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
940 | ]
941 |
942 | [[package]]
943 | name = "term"
944 | version = "0.5.2"
945 | source = "registry+https://github.com/rust-lang/crates.io-index"
946 | dependencies = [
947 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
948 | "dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
949 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
950 | ]
951 |
952 | [[package]]
953 | name = "termcolor"
954 | version = "1.0.4"
955 | source = "registry+https://github.com/rust-lang/crates.io-index"
956 | dependencies = [
957 | "wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
958 | ]
959 |
960 | [[package]]
961 | name = "termion"
962 | version = "1.5.1"
963 | source = "registry+https://github.com/rust-lang/crates.io-index"
964 | dependencies = [
965 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
966 | "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
967 | "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
968 | ]
969 |
970 | [[package]]
971 | name = "textwrap"
972 | version = "0.10.0"
973 | source = "registry+https://github.com/rust-lang/crates.io-index"
974 | dependencies = [
975 | "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
976 | ]
977 |
978 | [[package]]
979 | name = "thread_local"
980 | version = "0.3.6"
981 | source = "registry+https://github.com/rust-lang/crates.io-index"
982 | dependencies = [
983 | "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
984 | ]
985 |
986 | [[package]]
987 | name = "time"
988 | version = "0.1.42"
989 | source = "registry+https://github.com/rust-lang/crates.io-index"
990 | dependencies = [
991 | "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
992 | "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)",
993 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
994 | ]
995 |
996 | [[package]]
997 | name = "typename"
998 | version = "0.1.0"
999 | source = "registry+https://github.com/rust-lang/crates.io-index"
1000 | dependencies = [
1001 | "typename_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
1002 | ]
1003 |
1004 | [[package]]
1005 | name = "typename_derive"
1006 | version = "0.1.1"
1007 | source = "registry+https://github.com/rust-lang/crates.io-index"
1008 | dependencies = [
1009 | "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
1010 | "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
1011 | ]
1012 |
1013 | [[package]]
1014 | name = "typenum"
1015 | version = "1.10.0"
1016 | source = "registry+https://github.com/rust-lang/crates.io-index"
1017 |
1018 | [[package]]
1019 | name = "ucd-util"
1020 | version = "0.1.3"
1021 | source = "registry+https://github.com/rust-lang/crates.io-index"
1022 |
1023 | [[package]]
1024 | name = "unicode-segmentation"
1025 | version = "1.2.1"
1026 | source = "registry+https://github.com/rust-lang/crates.io-index"
1027 |
1028 | [[package]]
1029 | name = "unicode-width"
1030 | version = "0.1.5"
1031 | source = "registry+https://github.com/rust-lang/crates.io-index"
1032 |
1033 | [[package]]
1034 | name = "unicode-xid"
1035 | version = "0.0.4"
1036 | source = "registry+https://github.com/rust-lang/crates.io-index"
1037 |
1038 | [[package]]
1039 | name = "unicode-xid"
1040 | version = "0.1.0"
1041 | source = "registry+https://github.com/rust-lang/crates.io-index"
1042 |
1043 | [[package]]
1044 | name = "utf8-ranges"
1045 | version = "1.0.2"
1046 | source = "registry+https://github.com/rust-lang/crates.io-index"
1047 |
1048 | [[package]]
1049 | name = "vec_map"
1050 | version = "0.8.1"
1051 | source = "registry+https://github.com/rust-lang/crates.io-index"
1052 |
1053 | [[package]]
1054 | name = "winapi"
1055 | version = "0.2.8"
1056 | source = "registry+https://github.com/rust-lang/crates.io-index"
1057 |
1058 | [[package]]
1059 | name = "winapi"
1060 | version = "0.3.6"
1061 | source = "registry+https://github.com/rust-lang/crates.io-index"
1062 | dependencies = [
1063 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1064 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1065 | ]
1066 |
1067 | [[package]]
1068 | name = "winapi-build"
1069 | version = "0.1.1"
1070 | source = "registry+https://github.com/rust-lang/crates.io-index"
1071 |
1072 | [[package]]
1073 | name = "winapi-i686-pc-windows-gnu"
1074 | version = "0.4.0"
1075 | source = "registry+https://github.com/rust-lang/crates.io-index"
1076 |
1077 | [[package]]
1078 | name = "winapi-util"
1079 | version = "0.1.2"
1080 | source = "registry+https://github.com/rust-lang/crates.io-index"
1081 | dependencies = [
1082 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
1083 | ]
1084 |
1085 | [[package]]
1086 | name = "winapi-x86_64-pc-windows-gnu"
1087 | version = "0.4.0"
1088 | source = "registry+https://github.com/rust-lang/crates.io-index"
1089 |
1090 | [[package]]
1091 | name = "wincolor"
1092 | version = "1.0.1"
1093 | source = "registry+https://github.com/rust-lang/crates.io-index"
1094 | dependencies = [
1095 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
1096 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
1097 | ]
1098 |
1099 | [metadata]
1100 | "checksum aho-corasick 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "765f00fadb78fa7c796b21e3d6928affd322fc9d4a44febec6b452f6a9ef8deb"
1101 | "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
1102 | "checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
1103 | "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
1104 | "checksum ascii-canvas 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b385d69402821a1c254533a011a312531cbcc0e3e24f19bbb4747a5a2daf37e2"
1105 | "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
1106 | "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799"
1107 | "checksum backtrace 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "cd5a90e2b463010cd0e0ce9a11d4a9d5d58d9f41d4a6ba3dcaf9e68b466e88b4"
1108 | "checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
1109 | "checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
1110 | "checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
1111 | "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
1112 | "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
1113 | "checksum block-buffer 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49665c62e0e700857531fa5d3763e91b539ff1abeebd56808d378b495870d60d"
1114 | "checksum block-padding 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d75255892aeb580d3c566f213a2b6fdc1c66667839f45719ee1d30ebf2aea591"
1115 | "checksum byte-tools 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7"
1116 | "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
1117 | "checksum cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ad0daef304fa0b4238f5f7ed7178774b43b06f6a9b6509f6642bef4ff1f7b9b2"
1118 | "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
1119 | "checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
1120 | "checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
1121 | "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
1122 | "checksum codespan 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "004def512a9848b23a68ed110927d102b0e6d9f3dc732e28570879afde051f8c"
1123 | "checksum codespan-reporting 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab081a14ab8f9598ce826890fe896d0addee68c7a58ab49008369ccbb51510a8"
1124 | "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
1125 | "checksum ctor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9a43db2bba5cafdc6aa068c892a518e477ee0df3705e53ec70247a9ff93546d5"
1126 | "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a"
1127 | "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
1128 | "checksum digest 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05f47366984d3ad862010e22c7ce81a7dbcaebbdfb37241a620f8b6596ee135c"
1129 | "checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
1130 | "checksum docopt 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "db2906c2579b5b7207fc1e328796a9a8835dc44e22dbe8e460b1d636f9a7b225"
1131 | "checksum either 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c67353c641dc847124ea1902d69bd753dee9bb3beff9aa3662ecf86c971d1fac"
1132 | "checksum ena 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f56c93cc076508c549d9bb747f79aa9b4eb098be7b8cad8830c3137ef52d1e00"
1133 | "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
1134 | "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
1135 | "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
1136 | "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
1137 | "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
1138 | "checksum generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c0f28c2f5bfb5960175af447a2da7c18900693738343dc896ffbcabd9839592"
1139 | "checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461"
1140 | "checksum heapsize_derive 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "46f96d52fb1564059fc97b85ef6165728cc30198ab60073bf114c66c4c89bb5d"
1141 | "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
1142 | "checksum isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e31a8281fc93ec9693494da65fbf28c0c2aa60a2eaec25dc58e2f31952e95edc"
1143 | "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
1144 | "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
1145 | "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
1146 | "checksum lalrpop 0.16.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4e2e80bee40b22bca46665b4ef1f3cd88ed0fb043c971407eac17a0712c02572"
1147 | "checksum lalrpop-util 0.16.3 (registry+https://github.com/rust-lang/crates.io-index)" = "33b27d8490dbe1f9704b0088d61e8d46edc10d5673a8829836c6ded26a9912c7"
1148 | "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
1149 | "checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917"
1150 | "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
1151 | "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
1152 | "checksum new_debug_unreachable 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f40f005c60db6e03bae699e414c58bf9aa7ea02a2d0b9bfbcf19286cc4c82b30"
1153 | "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
1154 | "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
1155 | "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
1156 | "checksum opaque-debug 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "93f5bb2e8e8dec81642920ccff6b61f1eb94fa3020c5a325c9851ff604152409"
1157 | "checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
1158 | "checksum output_vt100 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9"
1159 | "checksum petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f"
1160 | "checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662"
1161 | "checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
1162 | "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
1163 | "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
1164 | "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
1165 | "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
1166 | "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
1167 | "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
1168 | "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
1169 | "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
1170 | "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
1171 | "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
1172 | "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
1173 | "checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832"
1174 | "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
1175 | "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
1176 | "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
1177 | "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
1178 | "checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85"
1179 | "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
1180 | "checksum redox_users 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fe5204c3a17e97dde73f285d49be585df59ed84b50a872baf416e73b62c3828"
1181 | "checksum regex 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2faa04d391c92f3d7d3207dc7eec10e52ae663ca70f282044ce6f735a17d62e0"
1182 | "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
1183 | "checksum rustc-demangle 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "adacaae16d02b6ec37fdc7acfcddf365978de76d1983d3ee22afc260e1ca9619"
1184 | "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
1185 | "checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
1186 | "checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560"
1187 | "checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c"
1188 | "checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d"
1189 | "checksum sha2 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b4d8bfd0e469f417657573d8451fb33d16cfe0989359b93baf3a1ffc639543d"
1190 | "checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
1191 | "checksum slog 2.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e1a2eec401952cd7b12a84ea120e2d57281329940c3f93c2bf04f462539508e"
1192 | "checksum slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e544d16c6b230d84c866662fe55e31aacfca6ae71e6fc49ae9a311cb379bfc2f"
1193 | "checksum slog-term 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5951a808c40f419922ee014c15b6ae1cd34d963538b57d8a4778b9ca3fff1e0b"
1194 | "checksum slog_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eff3b513cf2e0d1a60e1aba152dc72bedc5b05585722bb3cebd7bcb1e31b98f"
1195 | "checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423"
1196 | "checksum string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eea1eee654ef80933142157fdad9dd8bc43cf7c74e999e369263496f04ff4da"
1197 | "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc"
1198 | "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
1199 | "checksum structopt 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3d0760c312538987d363c36c42339b55f5ee176ea8808bbe4543d484a291c8d1"
1200 | "checksum structopt-derive 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "528aeb7351d042e6ffbc2a6fb76a86f9b622fdf7c25932798e7a82cb03bc94c6"
1201 | "checksum sum_type 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fcaf0ad86cfe6e1a9ccd145baa65fb1856a8a4b7cc1440b3a13f2b1f93a96fa"
1202 | "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
1203 | "checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2"
1204 | "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
1205 | "checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
1206 | "checksum synstructure 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cf318c34a2f8381a4f3d4db2c91b45bca2b1cd8cbe56caced900647be164800c"
1207 | "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
1208 | "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1"
1209 | "checksum term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42"
1210 | "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f"
1211 | "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
1212 | "checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
1213 | "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
1214 | "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
1215 | "checksum typename 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07c6494e04fa9e31404425680954aac69080337a6e9a946b475578962674482f"
1216 | "checksum typename_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9be293eee17e33e38c7f0c9ab50b4b8a3a41599bff6325fba57427713a7a3af1"
1217 | "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
1218 | "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
1219 | "checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1"
1220 | "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
1221 | "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
1222 | "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
1223 | "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737"
1224 | "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
1225 | "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
1226 | "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
1227 | "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
1228 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1229 | "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
1230 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1231 | "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba"
1232 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | members = ["syntax", "iec", "runner"]
--------------------------------------------------------------------------------
/LICENSE_APACHE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
--------------------------------------------------------------------------------
/LICENSE_MIT:
--------------------------------------------------------------------------------
1 | Copyright (c) 2018 Michael Bryan
2 |
3 | Permission is hereby granted, free of charge, to any
4 | person obtaining a copy of this software and associated
5 | documentation files (the "Software"), to deal in the
6 | Software without restriction, including without
7 | limitation the rights to use, copy, modify, merge,
8 | publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software
10 | is furnished to do so, subject to the following
11 | conditions:
12 |
13 | The above copyright notice and this permission notice
14 | shall be included in all copies or substantial portions
15 | of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 | DEALINGS IN THE SOFTWARE.
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # IEC 61131-3 Compiler
2 |
3 | [](https://travis-ci.com/Michael-F-Bryan/iec)
4 |
5 | ([API Docs])
6 |
7 | A proof-of-concept IEC 61131-3 Compiler.
8 |
9 | > **Warning:** This project is still in development. Not (yet) fit for human
10 | > consumption.
11 | >
12 | > This project has been superseded by [Michael-F-Bryan/rustmatic](https://github.com/Michael-F-Bryan/rustmatic).
13 |
14 | ## License
15 |
16 | This project is licensed under either of
17 |
18 | * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
19 | http://www.apache.org/licenses/LICENSE-2.0)
20 | * MIT license ([LICENSE-MIT](LICENSE-MIT) or
21 | http://opensource.org/licenses/MIT)
22 |
23 | at your option.
24 |
25 | ### Contribution
26 |
27 | Unless you explicitly state otherwise, any contribution intentionally
28 | submitted for inclusion in the work by you, as defined in the Apache-2.0
29 | license, shall be dual licensed as above, without any additional terms or
30 | conditions.
31 |
32 | [API Docs]: https://michael-f-bryan.github.io/iec
33 |
--------------------------------------------------------------------------------
/iec/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "iec"
3 | version = "0.1.0"
4 | authors = ["Michael Bryan "]
5 | edition = "2018"
6 |
7 | [dependencies]
8 | iec_syntax = { path = "../syntax" }
9 | serde_derive = "1.0"
10 | serde = "1.0"
11 | codespan-reporting = "0.2.1"
12 | codespan = "0.2.1"
13 | typename = "0.1"
14 | heapsize_derive = "0.1.4"
15 | heapsize = "0.4.2"
16 | slog = "2.4.1"
17 |
--------------------------------------------------------------------------------
/iec/src/diagnostics.rs:
--------------------------------------------------------------------------------
1 | use codespan_reporting::{Diagnostic, Severity};
2 |
3 | /// A collection of user diagnostics.
4 | #[derive(Debug, Clone, Default)]
5 | pub struct Diagnostics(Vec);
6 |
7 | impl Diagnostics {
8 | pub fn new() -> Diagnostics {
9 | Diagnostics::default()
10 | }
11 |
12 | pub fn push(&mut self, diag: Diagnostic) {
13 | self.0.push(diag);
14 | }
15 |
16 | fn has(&self, severity: Severity) -> bool {
17 | self.0.iter().any(|diag| diag.severity >= severity)
18 | }
19 |
20 | pub fn has_errors(&self) -> bool {
21 | self.has(Severity::Error)
22 | }
23 |
24 | pub fn diagnostics(&self) -> &[Diagnostic] {
25 | &self.0
26 | }
27 |
28 | pub fn len(&self) -> usize {
29 | self.0.len()
30 | }
31 |
32 | pub fn is_empty(&self) -> bool {
33 | self.0.is_empty()
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/iec/src/ecs.rs:
--------------------------------------------------------------------------------
1 | //! Super simple ECS-style building blocks, tailored for managing the various
2 | //! side-tables and data structures generated during the compilation process.
3 |
4 | use heapsize::HeapSizeOf;
5 | use heapsize_derive::HeapSizeOf;
6 | use serde_derive::{Deserialize, Serialize};
7 | use std::any::{Any, TypeId};
8 | use std::cell::{Ref, RefCell, RefMut};
9 | use std::collections::HashMap;
10 | use std::fmt::Debug;
11 | use std::fmt::{self, Formatter};
12 | use std::rc::Rc;
13 | use std::sync::atomic::{AtomicUsize, Ordering};
14 | use typename::TypeName;
15 |
16 | /// An opaque ID used to represent an entity.
17 | ///
18 | /// The normal method of creating an [`EntityId`] is to add it to a
19 | /// [`Container`] with [`Container::insert()`]. [`Default::default()`] yields a
20 | /// "placeholder" [`EntityId`] which can be used when a temporary [`EntityId`]
21 | /// is required so that the real value can be filled in at a later time.
22 | #[derive(
23 | Default,
24 | Copy,
25 | Clone,
26 | PartialEq,
27 | Eq,
28 | Hash,
29 | Ord,
30 | PartialOrd,
31 | HeapSizeOf,
32 | Serialize,
33 | Deserialize,
34 | )]
35 | pub struct EntityId(u32);
36 |
37 | impl EntityId {
38 | pub fn is_placeholder(&self) -> bool {
39 | *self == EntityId::default()
40 | }
41 | }
42 |
43 | impl Debug for EntityId {
44 | fn fmt(&self, f: &mut Formatter) -> fmt::Result {
45 | // deliberately override Debug so we *don't* break lines on alternate
46 | // output (i.e. `println!("{:#?}", some_entity_id)`).
47 | write!(f, "EntityId({})", self.0)
48 | }
49 | }
50 |
51 | impl slog::Value for EntityId {
52 | fn serialize(
53 | &self,
54 | _record: &slog::Record,
55 | key: slog::Key,
56 | ser: &mut dyn slog::Serializer,
57 | ) -> slog::Result {
58 | ser.emit_u32(key, self.0)
59 | }
60 | }
61 |
62 | /// Abstract component type.
63 | pub trait Component: TypeName + HeapSizeOf + Any + Debug + 'static {}
64 |
65 | impl Component for C {}
66 |
67 | /// A counter which generates atomically incrementing [`EntityId`]s.
68 | #[derive(Debug, Default, TypeName, HeapSizeOf)]
69 | struct EntityGenerator {
70 | last_id: AtomicUsize,
71 | }
72 |
73 | impl EntityGenerator {
74 | pub fn next_id(&self) -> EntityId {
75 | let next_id = self.last_id.fetch_add(1, Ordering::Relaxed);
76 | EntityId(next_id as u32)
77 | }
78 | }
79 |
80 | /// A resource container used to access the various components stored inside.
81 | ///
82 | /// There are two general categories of component which can be stored in a
83 | /// [`Resources`]. Most of the time you'll be using "normal" [`Component`]s,
84 | /// these are accessed with the usual [`Resources::get()`] and
85 | /// [`Resources::get_mut()`] methods and let you associate data with a specific
86 | /// [`EntityId`].
87 | ///
88 | /// However there will be times when the usual [`EntityId`] -> [`Component`]
89 | /// relation doesn't make sense. In this case you can register a "singleton
90 | /// component".
91 | ///
92 | /// # Panics
93 | ///
94 | /// Most of the methods on [`Resources`] rely on a component being registered
95 | /// before you can access the [`Container`] which holds the various instances of
96 | /// the component.
97 | #[derive(Default)]
98 | pub struct Resources {
99 | counter: Rc,
100 | items: HashMap>,
101 | singletons: HashMap>,
102 | vtables: HashMap,
103 | }
104 |
105 | impl Resources {
106 | pub fn new() -> Resources {
107 | Resources::default()
108 | }
109 |
110 | /// Registers a [`Component`] type so we can set up containers and stash
111 | /// away some useful metadata.
112 | ///
113 | /// There is no way to "unregister" a component after it has been
114 | /// registered.
115 | pub fn register(&mut self) {
116 | self.assert_not_already_registered::();
117 |
118 | let type_id = TypeId::of::();
119 | let ids = Rc::clone(&self.counter);
120 | let container = Container::::new(ids);
121 |
122 | let boxed_container = Box::new(RefCell::new(container));
123 | self.items.insert(type_id, boxed_container as Box);
124 | self.vtables
125 | .insert(type_id, ContainerVtable::for_component_container::());
126 | }
127 |
128 | /// Register a singleton component.
129 | pub fn register_singleton(&mut self) {
130 | self.assert_not_already_registered::();
131 |
132 | let type_id = TypeId::of::();
133 | self.singletons
134 | .insert(type_id, Box::new(RefCell::new(C::default())));
135 | self.vtables
136 | .insert(type_id, ContainerVtable::for_singleton::());
137 | }
138 |
139 | fn assert_not_already_registered(&self) {
140 | let type_id = TypeId::of::();
141 | assert!(
142 | !self.items.contains_key(&type_id),
143 | "\"{}\" is already registered as a normal component",
144 | C::type_name()
145 | );
146 | assert!(
147 | !self.singletons.contains_key(&type_id),
148 | "\"{}\" is already registered as a singleton component",
149 | C::type_name()
150 | );
151 | }
152 |
153 | fn ensure_registered(&mut self) {
154 | let type_id = TypeId::of::();
155 | if !self.items.contains_key(&type_id) {
156 | self.register::();
157 | }
158 | }
159 |
160 | fn ensure_singleton_registered(&mut self) {
161 | let type_id = TypeId::of::();
162 | if !self.singletons.contains_key(&type_id) {
163 | self.register_singleton::();
164 | }
165 | }
166 |
167 | fn lookup(&self) -> &RefCell> {
168 | let type_id = TypeId::of::();
169 |
170 | let container = match self.items.get(&type_id) {
171 | Some(c) => c,
172 | None => panic!("Unable to find the container for \"{}\", did you forget to register it?)", C::type_name()),
173 | };
174 |
175 | match container.downcast_ref::>>() {
176 | Some(c) => c,
177 | None => unreachable!(
178 | "Something went really wrong when registering \"{}\"",
179 | C::type_name()
180 | ),
181 | }
182 | }
183 |
184 | fn lookup_singleton(&self) -> &RefCell {
185 | let type_id = TypeId::of::();
186 |
187 | let container = match self.singletons.get(&type_id) {
188 | Some(c) => c,
189 | None => panic!("Unable to find the \"{}\" singleton, did you forget to register it?)", C::type_name()),
190 | };
191 |
192 | match container.downcast_ref::>() {
193 | Some(c) => c,
194 | None => unreachable!(
195 | "Something went really wrong when registering \"{}\"",
196 | C::type_name()
197 | ),
198 | }
199 | }
200 |
201 | /// Look up the container for a particular component.
202 | pub fn get(&self) -> Ref<'_, Container> {
203 | self.lookup::().borrow()
204 | }
205 |
206 | /// Get a mutable reference to a component container.
207 | pub fn get_mut(&self) -> RefMut<'_, Container> {
208 | self.lookup::().borrow_mut()
209 | }
210 |
211 | /// Look up a singleton component.
212 | pub fn get_singleton(&self) -> Ref<'_, C> {
213 | self.lookup_singleton::().borrow()
214 | }
215 |
216 | /// Get a mutable reference to a singleton component.
217 | pub fn get_singleton_mut(&self) -> RefMut<'_, C> {
218 | self.lookup_singleton::().borrow_mut()
219 | }
220 |
221 | pub fn component_names(&self) -> impl Iterator- {
222 | self.vtables
223 | .values()
224 | .map(|vtable| vtable.component_name.as_str())
225 | }
226 |
227 | pub fn is_registered(&self) -> bool {
228 | let type_id = TypeId::of::();
229 | self.vtables.contains_key(&type_id)
230 | }
231 | }
232 |
233 | impl Debug for Resources {
234 | fn fmt(&self, f: &mut Formatter) -> fmt::Result {
235 | let mut map = f.debug_map();
236 |
237 | let items = self.items.iter().chain(self.singletons.iter());
238 |
239 | for (type_id, container) in items {
240 | let vtable = &self.vtables[type_id];
241 | let debug = vtable.debug(&**container);
242 | map.entry(&vtable.component_name, &debug);
243 | }
244 |
245 | map.finish()
246 | }
247 | }
248 |
249 | impl HeapSizeOf for Resources {
250 | fn heap_size_of_children(&self) -> usize {
251 | let Resources {
252 | counter: _,
253 | ref items,
254 | ref singletons,
255 | ref vtables,
256 | } = *self;
257 |
258 | vtables.heap_size_of_children()
259 | + heap_size_of_any(
260 | |ty, item| vtables[&ty].heap_size_of(item),
261 | singletons,
262 | )
263 | + heap_size_of_any(
264 | |ty, item| vtables[&ty].heap_size_of(item),
265 | items,
266 | )
267 | }
268 | }
269 |
270 | fn heap_size_of_any(
271 | item_heapsize: impl Fn(TypeId, &dyn Any) -> usize,
272 | container: &HashMap>,
273 | ) -> usize {
274 | use std::mem::size_of;
275 |
276 | let overhead = container.capacity()
277 | * (size_of::>() + size_of::() + size_of::());
278 |
279 | let item_sizes = container.iter().fold(0, |n, (key, value)| {
280 | n + key.heap_size_of_children() + item_heapsize(*key, &**value)
281 | });
282 |
283 | overhead + item_sizes
284 | }
285 |
286 | /// A fancy lookup table mapping for associating a [`Component`] with a
287 | /// particular [`EntityId`].
288 | #[derive(Clone, TypeName)]
289 | pub struct Container {
290 | counter: Rc,
291 | items: HashMap,
292 | }
293 |
294 | impl Container {
295 | fn new(counter: Rc) -> Container {
296 | Container {
297 | counter,
298 | items: HashMap::new(),
299 | }
300 | }
301 |
302 | pub fn get(&self, id: EntityId) -> Option<&C> {
303 | self.items.get(&id)
304 | }
305 |
306 | pub fn get_mut(&mut self, id: EntityId) -> Option<&mut C> {
307 | self.items.get_mut(&id)
308 | }
309 |
310 | /// Add a component to the [`Container`], returning the [`EntityId`] it was
311 | /// given.
312 | pub fn insert(&mut self, item: C) -> EntityId {
313 | let id = self.counter.next_id();
314 | self.items.insert(id, item);
315 | id
316 | }
317 |
318 | /// Iterate over all the components in this [`Container`].
319 | pub fn iter<'this>(
320 | &'this self,
321 | ) -> impl Iterator
- + 'this {
322 | self.items.iter().map(|(&id, c)| (id, c))
323 | }
324 |
325 | /// Mutably iterate over all the components in this [`Container`].
326 | pub fn iter_mut<'this>(
327 | &'this mut self,
328 | ) -> impl Iterator
- + 'this {
329 | self.items.iter_mut().map(|(&id, c)| (id, c))
330 | }
331 |
332 | pub fn len(&self) -> usize {
333 | self.items.len()
334 | }
335 |
336 | pub fn is_empty(&self) -> bool {
337 | self.items.is_empty()
338 | }
339 | }
340 |
341 | impl Debug for Container {
342 | fn fmt(&self, f: &mut Formatter) -> fmt::Result {
343 | f.debug_map().entries(self.items.iter()).finish()
344 | }
345 | }
346 |
347 | impl Default for Container {
348 | fn default() -> Container {
349 | Container {
350 | counter: Default::default(),
351 | items: Default::default(),
352 | }
353 | }
354 | }
355 |
356 | impl HeapSizeOf for Container {
357 | fn heap_size_of_children(&self) -> usize {
358 | let Container {
359 | counter: _,
360 | ref items,
361 | } = *self;
362 |
363 | items.heap_size_of_children()
364 | }
365 | }
366 |
367 | type DebugFunc = fn(container: &dyn Any, f: &mut Formatter) -> fmt::Result;
368 | type HeapsizeFunc = fn(container: &dyn Any) -> usize;
369 |
370 | /// A vtable used to store container metadata and helper functions.
371 | #[derive(Clone)]
372 | struct ContainerVtable {
373 | debug: DebugFunc,
374 | heap_size: HeapsizeFunc,
375 | /// The [`TypeId`] for the expected container. The container is usually a
376 | /// `RefCell>`.
377 | container_type_id: TypeId,
378 | component_type_id: TypeId,
379 | component_name: String,
380 | }
381 |
382 | impl ContainerVtable {
383 | fn for_component_container() -> ContainerVtable
384 | where
385 | C: Component,
386 | {
387 | ContainerVtable {
388 | debug: |c, f| {
389 | c.downcast_ref::>>()
390 | .expect("Incorrect container type")
391 | .borrow()
392 | .fmt(f)
393 | },
394 | heap_size: |c| {
395 | c.downcast_ref::>>()
396 | .expect("Incorrect container type")
397 | .borrow()
398 | .heap_size_of_children()
399 | },
400 | container_type_id: TypeId::of::>>(),
401 | component_type_id: TypeId::of::(),
402 | component_name: C::type_name(),
403 | }
404 | }
405 |
406 | fn for_singleton() -> ContainerVtable
407 | where
408 | C: Component,
409 | {
410 | ContainerVtable {
411 | debug: |c, f| {
412 | c.downcast_ref::>()
413 | .expect("Incorrect singleton type")
414 | .borrow()
415 | .fmt(f)
416 | },
417 | heap_size: |c| {
418 | c.downcast_ref::>()
419 | .expect("Incorrect singleton type")
420 | .borrow()
421 | .heap_size_of_children()
422 | },
423 | container_type_id: TypeId::of::>(),
424 | component_type_id: TypeId::of::(),
425 | component_name: C::type_name(),
426 | }
427 | }
428 |
429 | fn debug<'a>(&self, container: &'a dyn Any) -> impl Debug + 'a {
430 | debug_assert_eq!(
431 | container.type_id(),
432 | self.container_type_id,
433 | "Expected a {} container",
434 | self.component_name
435 | );
436 |
437 | VtableDebug {
438 | func: self.debug,
439 | item: container,
440 | }
441 | }
442 |
443 | fn heap_size_of(&self, container: &dyn Any) -> usize {
444 | (self.heap_size)(container)
445 | }
446 | }
447 |
448 | impl HeapSizeOf for ContainerVtable {
449 | fn heap_size_of_children(&self) -> usize {
450 | let ContainerVtable {
451 | debug: _,
452 | heap_size: _,
453 | container_type_id: _,
454 | component_type_id: _,
455 | ref component_name,
456 | } = *self;
457 |
458 | component_name.heap_size_of_children()
459 | }
460 | }
461 |
462 | struct VtableDebug<'a> {
463 | func: DebugFunc,
464 | item: &'a dyn Any,
465 | }
466 |
467 | impl<'a> Debug for VtableDebug<'a> {
468 | fn fmt(&self, f: &mut Formatter) -> fmt::Result {
469 | (self.func)(self.item, f)
470 | }
471 | }
472 |
473 | use std::ops::{Deref, DerefMut};
474 |
475 | // imported so rustdoc can wire up links correctly
476 | #[allow(unused_imports)]
477 | use crate::passes::Pass;
478 |
479 | /// An adaptor trait for retrieving a particular [`Component`] container from
480 | /// the world.
481 | ///
482 | /// This enables nice things like passing a tuple of [`Component`]s to a
483 | /// [`Pass`].
484 | pub trait FromResources<'r>: Sized {
485 | fn from_resources(r: &'r Resources) -> Self;
486 | fn ensure_registered(r: &mut Resources);
487 | }
488 |
489 | /// A read-only reference to a [`Container`] of [`Component`]s.
490 | #[derive(Debug, TypeName)]
491 | pub struct Read<'r, C: Component>(Ref<'r, Container>);
492 |
493 | impl<'r, C: Component> FromResources<'r> for Read<'r, C> {
494 | fn from_resources(r: &'r Resources) -> Self {
495 | Read(r.get())
496 | }
497 |
498 | fn ensure_registered(r: &mut Resources) {
499 | r.ensure_registered::();
500 | }
501 | }
502 |
503 | impl<'r, C: Component> Deref for Read<'r, C> {
504 | type Target = Container;
505 |
506 | fn deref(&self) -> &Self::Target {
507 | self.0.deref()
508 | }
509 | }
510 |
511 | /// A reference to a [`Container`] of [`Component`]s which supports mutation.
512 | #[derive(Debug, TypeName)]
513 | pub struct ReadWrite<'r, C: Component>(RefMut<'r, Container>);
514 |
515 | impl<'r, C: Component> FromResources<'r> for ReadWrite<'r, C> {
516 | fn from_resources(r: &'r Resources) -> Self {
517 | ReadWrite(r.get_mut())
518 | }
519 |
520 | fn ensure_registered(r: &mut Resources) {
521 | r.ensure_registered::();
522 | }
523 | }
524 |
525 | impl<'r, C: Component> Deref for ReadWrite<'r, C> {
526 | type Target = Container;
527 |
528 | fn deref(&self) -> &Self::Target {
529 | self.0.deref()
530 | }
531 | }
532 |
533 | impl<'r, C: Component> DerefMut for ReadWrite<'r, C> {
534 | fn deref_mut(&mut self) -> &mut Self::Target {
535 | self.0.deref_mut()
536 | }
537 | }
538 |
539 | /// An immutable reference to a singleton component.
540 | #[derive(Debug, TypeName)]
541 | pub struct Singleton<'r, T: Component + Default>(Ref<'r, T>);
542 |
543 | impl<'r, T: Component + Default> FromResources<'r> for Singleton<'r, T> {
544 | fn from_resources(r: &'r Resources) -> Self {
545 | Singleton(r.get_singleton())
546 | }
547 |
548 | fn ensure_registered(r: &mut Resources) {
549 | r.ensure_singleton_registered::();
550 | }
551 | }
552 |
553 | impl<'r, C: Component + Default> Deref for Singleton<'r, C> {
554 | type Target = C;
555 |
556 | fn deref(&self) -> &Self::Target {
557 | self.0.deref()
558 | }
559 | }
560 |
561 | /// A mutable reference to a singleton component.
562 | #[derive(Debug, TypeName)]
563 | pub struct SingletonMut<'r, T: Component + Default>(RefMut<'r, T>);
564 |
565 | impl<'r, T: Component + Default> FromResources<'r> for SingletonMut<'r, T> {
566 | fn from_resources(r: &'r Resources) -> Self {
567 | SingletonMut(r.get_singleton_mut())
568 | }
569 |
570 | fn ensure_registered(r: &mut Resources) {
571 | r.ensure_singleton_registered::();
572 | }
573 | }
574 |
575 | impl<'r, C: Component + Default> Deref for SingletonMut<'r, C> {
576 | type Target = C;
577 |
578 | fn deref(&self) -> &Self::Target {
579 | self.0.deref()
580 | }
581 | }
582 |
583 | impl<'r, C: Component + Default> DerefMut for SingletonMut<'r, C> {
584 | fn deref_mut(&mut self) -> &mut Self::Target {
585 | self.0.deref_mut()
586 | }
587 | }
588 |
589 | macro_rules! tuple_from_resource {
590 | ($first:ident $(,$tail:tt)+) => {
591 | tuple_from_resource!(@IMPL $first $(, $tail)*);
592 | tuple_from_resource!($($tail),*);
593 | };
594 | ($first:ident) => {
595 | tuple_from_resource!(@IMPL $first);
596 | tuple_from_resource!(@IMPL);
597 | };
598 | (@IMPL $($letter:ident),*) => {
599 | #[allow(unused_variables)]
600 | impl<'r, $( $letter, )* > FromResources<'r> for ( $( $letter, )* )
601 | where
602 | $(
603 | $letter : FromResources<'r>,
604 | )*
605 | {
606 | #[allow(unused_variables)]
607 | fn from_resources(r: &'r Resources) -> Self {
608 | ( $( $letter::from_resources(r), )* )
609 | }
610 |
611 | fn ensure_registered(r: &mut Resources) {
612 | $(
613 | $letter::ensure_registered(r);
614 | )*
615 | }
616 | }
617 | };
618 | }
619 |
620 | tuple_from_resource!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
621 |
622 | #[cfg(test)]
623 | mod tests {
624 | use super::*;
625 |
626 | #[derive(Debug, Default, Copy, Clone, PartialEq, TypeName, HeapSizeOf)]
627 | struct RandomComponent(u32);
628 |
629 | #[test]
630 | fn generate_valid_vtables() {
631 | let vtable =
632 | ContainerVtable::for_component_container::();
633 |
634 | assert!(vtable.component_name.ends_with("RandomComponent"));
635 | assert_eq!(vtable.component_type_id, TypeId::of::());
636 |
637 | let container = RefCell::new(Container::default());
638 | container.borrow_mut().insert(RandomComponent(42));
639 |
640 | let debug_format = format!("{:?}", vtable.debug(&container));
641 | let actual = format!("{:?}", container.borrow());
642 | assert_eq!(actual, debug_format);
643 |
644 | let got_heapsize = vtable.heap_size_of(&container);
645 | let actual = container.heap_size_of_children();
646 | assert_eq!(got_heapsize, actual);
647 | }
648 |
649 | #[test]
650 | fn register_the_random_component() {
651 | let mut res = Resources::default();
652 | res.register::();
653 |
654 | let vtable = res.vtables.values().next().unwrap();
655 |
656 | assert_eq!(vtable.component_name, RandomComponent::type_name());
657 | assert_eq!(vtable.component_type_id, TypeId::of::());
658 | assert_eq!(
659 | vtable.container_type_id,
660 | TypeId::of::>>()
661 | );
662 | }
663 |
664 | #[test]
665 | fn get_a_component_container() {
666 | let mut res = Resources::default();
667 | res.register::();
668 |
669 | let _got = res.get::();
670 |
671 | assert_eq!(res.items.len(), 1);
672 | assert_eq!(res.vtables.len(), 1);
673 | let component_name = RandomComponent::type_name();
674 | assert_eq!(res.component_names().next().unwrap(), component_name);
675 | }
676 |
677 | #[test]
678 | fn debug_print_resources() {
679 | let mut res = Resources::default();
680 | res.register::();
681 |
682 | let got = format!("{:?}", res);
683 |
684 | let key = format!("\"{}\"", RandomComponent::type_name());
685 | assert!(got.contains(&key));
686 | }
687 |
688 | #[test]
689 | fn get_resource_heapsize() {
690 | let mut res = Resources::default();
691 | res.register::();
692 |
693 | let size = res.heap_size_of_children();
694 | assert_eq!(size, 928);
695 | }
696 |
697 | #[test]
698 | fn use_a_singleton_component() {
699 | let mut res = Resources::default();
700 | res.register_singleton::();
701 |
702 | assert!(res.items.is_empty());
703 | assert_eq!(res.vtables.len(), 1);
704 | assert_eq!(res.singletons.len(), 1);
705 |
706 | {
707 | let mut got = res.get_singleton_mut::();
708 | got.0 = 7;
709 | }
710 |
711 | {
712 | let got = res.get_singleton::();
713 | assert_eq!(got.0, 7);
714 | }
715 | }
716 |
717 | #[test]
718 | #[should_panic]
719 | fn you_cant_register_twice() {
720 | let mut res = Resources::default();
721 | res.register::();
722 | res.register_singleton::();
723 | }
724 | }
725 |
--------------------------------------------------------------------------------
/iec/src/hir.rs:
--------------------------------------------------------------------------------
1 | //! The compiler's high-level intermediate representation.
2 |
3 | use crate::ecs::{EntityId, Resources};
4 | use heapsize_derive::HeapSizeOf;
5 | use serde_derive::{Deserialize, Serialize};
6 | use typename::TypeName;
7 |
8 | #[derive(Debug, TypeName, HeapSizeOf)]
9 | pub struct CompilationUnit {
10 | pub resources: Resources,
11 | }
12 |
13 | #[derive(Debug, Clone, PartialEq, TypeName, HeapSizeOf)]
14 | pub struct Program {
15 | pub name: String,
16 | pub variables: Vec,
17 | }
18 |
19 | #[derive(Debug, Clone, PartialEq, TypeName, HeapSizeOf)]
20 | pub struct Function {
21 | pub name: String,
22 | pub variables: Vec,
23 | }
24 |
25 | #[derive(Debug, Clone, PartialEq, TypeName, HeapSizeOf)]
26 | pub struct FunctionBlock {
27 | pub name: String,
28 | pub variables: Vec,
29 | }
30 |
31 | #[derive(Debug, Clone, PartialEq, TypeName, HeapSizeOf)]
32 | pub struct Type {
33 | pub name: String,
34 | }
35 |
36 | #[derive(
37 | Debug, Clone, PartialEq, TypeName, Serialize, Deserialize, HeapSizeOf,
38 | )]
39 | pub struct Variable {
40 | /// The item this variable is defined in.
41 | pub parent: Symbol,
42 | /// The variable's type.
43 | pub ty: EntityId,
44 | /// The variable's name, if one exists.
45 | pub name: Option,
46 | }
47 |
48 | #[derive(
49 | Debug, Copy, Clone, PartialEq, TypeName, HeapSizeOf, Serialize, Deserialize,
50 | )]
51 | pub enum Symbol {
52 | Program(EntityId),
53 | Function(EntityId),
54 | FunctionBlock(EntityId),
55 | Type(EntityId),
56 | }
57 |
58 | impl From for EntityId {
59 | fn from(s: Symbol) -> EntityId {
60 | match s {
61 | Symbol::Program(id)
62 | | Symbol::Type(id)
63 | | Symbol::Function(id)
64 | | Symbol::FunctionBlock(id) => id,
65 | }
66 | }
67 | }
68 |
69 | /// A three address code instruction.
70 | #[derive(
71 | Debug,
72 | TypeName,
73 | Copy,
74 | Clone,
75 | PartialEq,
76 | Eq,
77 | Hash,
78 | HeapSizeOf,
79 | Serialize,
80 | Deserialize,
81 | )]
82 | pub enum Instruction {}
83 |
84 | #[derive(
85 | TypeName, Debug, Clone, PartialEq, HeapSizeOf, Serialize, Deserialize,
86 | )]
87 | pub struct BasicBlock {}
88 |
--------------------------------------------------------------------------------
/iec/src/lib.rs:
--------------------------------------------------------------------------------
1 | //! The "*middle-end*" of the `iec` compiler.
2 | //!
3 | //! The `iec` crate's main job is to process the *Abstract Syntax Tree* parsed
4 | //! by the frontend ([`iec_syntax`]), turn it into a more compiler-friendly
5 | //! format, apply typechecking and other semantic analyses, then pass it over
6 | //! to a backend (e.g. [`cranelift`]) for code generation.
7 | //!
8 | //! The compiler takes a lot of inspiration from the *Entity-Component-System*
9 | //! (ECS) architecture used in modern games. Perhaps unsurprisingly, this
10 | //! architecture turns out to be equally well suited to compilers.
11 | //!
12 | //! > *Note:* If you aren't familiar with ECS, the [`specs`] crate is a very
13 | //! > well designed ECS implementation with a lot of good tutorials and
14 | //! > documentation. Feel free to browse that project if you want a more
15 | //! > in-depth understanding of how an ECS works.
16 | //!
17 | //! [`specs`]: https://github.com/slide-rs/specs
18 | //! [`cranelift`]: https://github.com/CraneStation/cranelift
19 |
20 | mod diagnostics;
21 | pub mod ecs;
22 | pub mod hir;
23 | pub mod passes;
24 |
25 | pub use crate::diagnostics::Diagnostics;
26 | pub use crate::ecs::EntityId;
27 | pub use crate::hir::CompilationUnit;
28 | pub use crate::passes::process;
29 |
--------------------------------------------------------------------------------
/iec/src/passes/basic_blocks.rs:
--------------------------------------------------------------------------------
1 | use super::symbol_table::SymbolTable;
2 | use super::{Pass, PassContext};
3 | use crate::ecs::{Container, EntityId, Read, ReadWrite, Singleton};
4 | use crate::hir::{BasicBlock, Instruction, Program, Symbol, Type, Variable};
5 | use crate::Diagnostics;
6 | use iec_syntax::Item;
7 | use typename::TypeName;
8 |
9 | #[derive(TypeName)]
10 | pub enum BasicBlocks {}
11 |
12 | impl<'r> Pass<'r> for BasicBlocks {
13 | type Arg = iec_syntax::File;
14 | type Storage = (
15 | ReadWrite<'r, Program>,
16 | Read<'r, Variable>,
17 | Singleton<'r, SymbolTable>,
18 | Read<'r, Type>,
19 | ReadWrite<'r, Instruction>,
20 | ReadWrite<'r, BasicBlock>,
21 | );
22 | const DESCRIPTION: &'static str = "Convert item bodies into basic blocks";
23 |
24 | fn run(ast: &Self::Arg, ctx: &mut PassContext<'_>, storage: Self::Storage) {
25 | let (mut programs, variables, symbols, types, instructions, blocks) =
26 | storage;
27 |
28 | for item in &ast.items {
29 | let (body, name) = match item {
30 | Item::Program(ref p) => (&p.body, &p.name.value),
31 | _ => unimplemented!(),
32 | };
33 | let symbol = symbols
34 | .get(name)
35 | .expect("the symbol table pass ensures this exists");
36 |
37 | let entry_block = to_basic_blocks(
38 | symbol,
39 | body,
40 | &variables,
41 | &types,
42 | &mut ctx.diags,
43 | );
44 | }
45 | }
46 | }
47 |
48 | fn to_basic_blocks(
49 | parent: Symbol,
50 | body: &[iec_syntax::Statement],
51 | variables: &Container,
52 | types: &Container,
53 | diags: &mut Diagnostics,
54 | ) -> EntityId {
55 | unimplemented!()
56 | }
57 |
--------------------------------------------------------------------------------
/iec/src/passes/mod.rs:
--------------------------------------------------------------------------------
1 | //! The internals for the `iec` compiler can be thought of as a series of
2 | //! passes, where each pass does some processing on the provided input before
3 | //! updating the world.
4 |
5 | pub mod basic_blocks;
6 | pub mod register_builtins;
7 | pub mod symbol_table;
8 | pub mod variable_discovery;
9 |
10 | pub use self::basic_blocks::BasicBlocks;
11 | pub use self::register_builtins::RegisterBuiltins;
12 | pub use self::symbol_table::SymbolTableResolution;
13 | pub use self::variable_discovery::VariableDiscovery;
14 |
15 | use crate::ecs::FromResources;
16 | use crate::ecs::Resources;
17 | use crate::hir::CompilationUnit;
18 | use crate::Diagnostics;
19 | use heapsize::HeapSizeOf;
20 | use slog::{Discard, Logger};
21 | use std::time::Instant;
22 | use typename::TypeName;
23 |
24 | /// The "system" part of your typical Entity-Component-System application.
25 | ///
26 | /// Each [`Pass`] should be its own state-less chunk of logic, essentially a
27 | /// fancy function for updating the world.
28 | pub trait Pass<'r>: TypeName {
29 | /// Extra arguments passed into the [`Pass<'_>`] from the outside.
30 | type Arg: ?Sized;
31 | /// State which should be retrieved from [`Resources`] to be updated/read by
32 | /// the [`Pass`<'_>].
33 | type Storage: FromResources<'r>;
34 | /// A one-line description of what the pass is meant to do.
35 | const DESCRIPTION: &'static str;
36 |
37 | /// Execute the pass.
38 | fn run(args: &Self::Arg, ctx: &mut PassContext<'_>, storage: Self::Storage);
39 | }
40 |
41 | pub fn run_pass<'r, P: Pass<'r>>(
42 | r: &'r mut Resources,
43 | arg: &'r P::Arg,
44 | ctx: &mut PassContext<'_>,
45 | ) {
46 | let mut ctx = ctx.with(slog::o!("pass" => P::type_name()));
47 | slog::debug!(ctx.logger, "Pass started";
48 | "description" => P::DESCRIPTION,
49 | "resource-usage" => r.heap_size_of_children());
50 | let start = Instant::now();
51 |
52 | P::Storage::ensure_registered(r);
53 | let storage = P::Storage::from_resources(r);
54 | P::run(arg, &mut ctx, storage);
55 |
56 | let duration = Instant::now() - start;
57 | slog::debug!(ctx.logger, "Pass complete";
58 | "execution-time" => format_args!("{}.{:06}s", duration.as_secs(), duration.subsec_micros()),
59 | "resource-usage" => r.heap_size_of_children());
60 | }
61 |
62 | /// Process the provided AST and execute semantic analysis.
63 | pub fn process(
64 | ast: &iec_syntax::File,
65 | ctx: &mut PassContext<'_>,
66 | ) -> CompilationUnit {
67 | let mut resources = Resources::new();
68 |
69 | run_pass::(&mut resources, &(), ctx);
70 | run_pass::(&mut resources, ast, ctx);
71 | run_pass::(&mut resources, ast, ctx);
72 | run_pass::(&mut resources, ast, ctx);
73 |
74 | CompilationUnit { resources }
75 | }
76 |
77 | /// Contextual information given to each pass.
78 | #[derive(Debug)]
79 | pub struct PassContext<'a> {
80 | pub diags: &'a mut Diagnostics,
81 | pub logger: Logger,
82 | }
83 |
84 | impl<'a> PassContext<'a> {
85 | pub fn new_nop_logger(diags: &'a mut Diagnostics) -> PassContext<'a> {
86 | PassContext {
87 | diags,
88 | logger: Logger::root(Discard, slog::o!()),
89 | }
90 | }
91 |
92 | pub fn with(&mut self, pairs: slog::OwnedKV) -> PassContext<'_>
93 | where
94 | T: slog::SendSyncRefUnwindSafeKV + 'static,
95 | {
96 | PassContext {
97 | diags: self.diags,
98 | logger: self.logger.new(pairs),
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/iec/src/passes/register_builtins.rs:
--------------------------------------------------------------------------------
1 | use super::symbol_table::SymbolTable;
2 | use super::{Pass, PassContext};
3 | use crate::ecs::{ReadWrite, SingletonMut};
4 | use crate::hir::{Symbol, Type};
5 | use typename::TypeName;
6 |
7 | #[derive(TypeName)]
8 | pub enum RegisterBuiltins {}
9 |
10 | pub const BUILTIN_TYPES: &[&str] = &[
11 | "byte", "word", "dword", "int", "dint", "real", "lreal", "time", "date",
12 | "char", "string",
13 | ];
14 |
15 | impl<'r> Pass<'r> for RegisterBuiltins {
16 | type Arg = ();
17 | type Storage = (SingletonMut<'r, SymbolTable>, ReadWrite<'r, Type>);
18 | const DESCRIPTION: &'static str = "Register builtin types and functions";
19 |
20 | fn run(_: &Self::Arg, _ctx: &mut PassContext<'_>, storage: Self::Storage) {
21 | let (mut symbol_table, mut types) = storage;
22 |
23 | for name in BUILTIN_TYPES {
24 | let type_id = types.insert(Type {
25 | name: name.to_string(),
26 | });
27 | symbol_table.insert(name, Symbol::Type(type_id));
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/iec/src/passes/symbol_table.rs:
--------------------------------------------------------------------------------
1 | use super::{Pass, PassContext};
2 | use crate::ecs::{Container, ReadWrite, SingletonMut};
3 | use crate::hir::{Function, FunctionBlock, Program, Symbol};
4 | use codespan_reporting::{Diagnostic, Label};
5 | use heapsize_derive::HeapSizeOf;
6 | use iec_syntax::Item;
7 | use serde_derive::{Deserialize, Serialize};
8 | use std::collections::HashMap;
9 | use typename::TypeName;
10 |
11 | /// A cache for looking up a component based on its identifier.
12 | #[derive(
13 | Debug,
14 | Default,
15 | Clone,
16 | PartialEq,
17 | TypeName,
18 | HeapSizeOf,
19 | Serialize,
20 | Deserialize,
21 | )]
22 | pub struct SymbolTable(HashMap);
23 |
24 | impl SymbolTable {
25 | pub fn insert(&mut self, name: &str, sym: Symbol) {
26 | self.0.insert(name.to_lowercase(), sym);
27 | }
28 |
29 | pub fn get(&self, name: &str) -> Option {
30 | let name = name.to_lowercase();
31 | self.0.get(&name).cloned()
32 | }
33 |
34 | pub fn inner(&self) -> &HashMap {
35 | &self.0
36 | }
37 |
38 | pub fn inner_mut(&mut self) -> &mut HashMap {
39 | &mut self.0
40 | }
41 |
42 | pub fn check_for_duplicate_ident(
43 | &self,
44 | ident: &iec_syntax::Identifier,
45 | ) -> Option {
46 | if self.get(&ident.value).is_none() {
47 | None
48 | } else {
49 | Some(
50 | Diagnostic::new_error("Name is already declared").with_label(
51 | Label::new_primary(ident.span)
52 | .with_message("Duplicate declared here"),
53 | ),
54 | )
55 | }
56 | }
57 | }
58 |
59 | #[derive(TypeName)]
60 | pub enum SymbolTableResolution {}
61 |
62 | impl<'r> Pass<'r> for SymbolTableResolution {
63 | type Arg = iec_syntax::File;
64 | type Storage = (
65 | SingletonMut<'r, SymbolTable>,
66 | ReadWrite<'r, Program>,
67 | ReadWrite<'r, Function>,
68 | ReadWrite<'r, FunctionBlock>,
69 | );
70 | const DESCRIPTION: &'static str = "Find all know identifiers";
71 |
72 | fn run(
73 | arg: &iec_syntax::File,
74 | ctx: &mut PassContext<'_>,
75 | storage: Self::Storage,
76 | ) {
77 | let (
78 | mut symbol_table,
79 | mut programs,
80 | mut functions,
81 | mut function_blocks,
82 | ) = storage;
83 |
84 | for item in &arg.items {
85 | match item {
86 | Item::Program(ref p) => {
87 | register_program(p, &mut programs, ctx, &mut symbol_table)
88 | }
89 | Item::Function(ref f) => {
90 | register_function(f, &mut functions, ctx, &mut symbol_table)
91 | }
92 | Item::FunctionBlock(ref fb) => register_function_block(
93 | fb,
94 | &mut function_blocks,
95 | ctx,
96 | &mut symbol_table,
97 | ),
98 | }
99 | }
100 | }
101 | }
102 |
103 | fn register_program(
104 | p: &iec_syntax::Program,
105 | programs: &mut Container,
106 | ctx: &mut PassContext<'_>,
107 | symbol_table: &mut SymbolTable,
108 | ) {
109 | if let Some(d) = symbol_table.check_for_duplicate_ident(&p.name) {
110 | ctx.diags.push(d);
111 | return;
112 | }
113 |
114 | let program = Program {
115 | name: p.name.value.clone(),
116 | variables: Vec::new(),
117 | };
118 | let program_id = programs.insert(program);
119 | symbol_table.insert(&p.name.value, Symbol::Program(program_id));
120 | slog::debug!(ctx.logger, "Found a program";
121 | "name" => &p.name.value,
122 | "id" => program_id);
123 | }
124 |
125 | fn register_function_block(
126 | fb: &iec_syntax::FunctionBlock,
127 | function_blocks: &mut Container,
128 | ctx: &mut PassContext<'_>,
129 | symbol_table: &mut SymbolTable,
130 | ) {
131 | if let Some(d) = symbol_table.check_for_duplicate_ident(&fb.name) {
132 | ctx.diags.push(d);
133 | return;
134 | }
135 |
136 | let function_block = FunctionBlock {
137 | name: fb.name.value.clone(),
138 | variables: Vec::new(),
139 | };
140 | let function_block_id = function_blocks.insert(function_block);
141 | symbol_table
142 | .insert(&fb.name.value, Symbol::FunctionBlock(function_block_id));
143 | slog::debug!(ctx.logger, "Found a function block";
144 | "name" => &fb.name.value,
145 | "id" => function_block_id);
146 | }
147 |
148 | fn register_function(
149 | f: &iec_syntax::Function,
150 | functions: &mut Container,
151 | ctx: &mut PassContext<'_>,
152 | symbol_table: &mut SymbolTable,
153 | ) {
154 | if let Some(d) = symbol_table.check_for_duplicate_ident(&f.name) {
155 | ctx.diags.push(d);
156 | return;
157 | }
158 |
159 | let function = Function {
160 | name: f.name.value.clone(),
161 | variables: Vec::new(),
162 | };
163 | let function_id = functions.insert(function);
164 | symbol_table.insert(&f.name.value, Symbol::Function(function_id));
165 | slog::debug!(ctx.logger, "Found a function";
166 | "name" => &f.name.value,
167 | "id" => function_id);
168 | }
169 |
170 | #[cfg(test)]
171 | mod tests {
172 | use super::*;
173 | use crate::ecs::Resources;
174 | use crate::Diagnostics;
175 | use iec_syntax::File;
176 |
177 | #[test]
178 | fn identify_function_blocks_and_programs() {
179 | let ast = File {
180 | items: vec![
181 | iec_syntax::quote!(program main {}).into(),
182 | iec_syntax::quote!(function_block FUnc {}).into(),
183 | ],
184 | span: Default::default(),
185 | };
186 | let mut resources = Resources::new();
187 | let mut diags = Diagnostics::new();
188 |
189 | crate::passes::run_pass::(
190 | &mut resources,
191 | &ast,
192 | &mut PassContext::new_nop_logger(&mut diags),
193 | );
194 |
195 | // we should have updated the symbol table appropriately
196 | let symbol_table = resources.get_singleton::();
197 | assert_eq!(symbol_table.0.len(), 2);
198 | assert!(symbol_table.0.contains_key("main"));
199 | assert!(symbol_table.0.contains_key("func"));
200 |
201 | let programs = resources.get::();
202 | assert_eq!(programs.len(), 1);
203 | let symbol = symbol_table.get("main").unwrap();
204 | let program = programs.get(symbol.into()).unwrap();
205 | assert_eq!(program.name, "main");
206 |
207 | let function_blocks = resources.get::();
208 | assert_eq!(function_blocks.len(), 1);
209 | assert_eq!(function_blocks.len(), 1);
210 | let symbol = symbol_table.get("FUnc").unwrap();
211 | let func = function_blocks.get(symbol.into()).unwrap();
212 | assert_eq!(func.name, "FUnc");
213 | }
214 | }
215 |
--------------------------------------------------------------------------------
/iec/src/passes/variable_discovery.rs:
--------------------------------------------------------------------------------
1 | use super::symbol_table::SymbolTable;
2 | use super::{Pass, PassContext};
3 | use crate::ecs::{Container, EntityId, ReadWrite, Singleton};
4 | use crate::hir::{Function, FunctionBlock, Program, Symbol, Variable};
5 | use crate::Diagnostics;
6 | use codespan_reporting::{Diagnostic, Label};
7 | use iec_syntax::Item;
8 | use std::collections::HashMap;
9 | use typename::TypeName;
10 |
11 | #[derive(TypeName)]
12 | pub enum VariableDiscovery {}
13 |
14 | impl<'r> Pass<'r> for VariableDiscovery {
15 | type Arg = iec_syntax::File;
16 | type Storage = (
17 | Singleton<'r, SymbolTable>,
18 | ReadWrite<'r, Variable>,
19 | ReadWrite<'r, Program>,
20 | ReadWrite<'r, Function>,
21 | ReadWrite<'r, FunctionBlock>,
22 | );
23 | const DESCRIPTION: &'static str = "Resolve variable declarations in each program, function, or function block";
24 |
25 | fn run(
26 | args: &Self::Arg,
27 | ctx: &mut PassContext<'_>,
28 | storage: Self::Storage,
29 | ) {
30 | let (
31 | symbol_table,
32 | mut variables,
33 | mut programs,
34 | mut functions,
35 | mut function_blocks,
36 | ) = storage;
37 |
38 | for item in &args.items {
39 | let (var_blocks, name) = match item {
40 | Item::Program(ref p) => (&p.var_blocks, &p.name.value),
41 | Item::Function(ref f) => (&f.var_blocks, &f.name.value),
42 | Item::FunctionBlock(ref fb) => (&fb.var_blocks, &fb.name.value),
43 | };
44 | let symbol = symbol_table.get(name)
45 | .expect("We should have found all symbols when constructing the symbol table");
46 |
47 | let variable_ids = resolve_variables(
48 | symbol,
49 | &symbol_table,
50 | var_blocks,
51 | &mut variables,
52 | ctx.diags,
53 | );
54 |
55 | slog::debug!(ctx.logger, "Analysed item";
56 | "name" => name,
57 | "symbol" => format_args!("{:?}", symbol),
58 | "variable-count" => variable_ids.len());
59 |
60 | const ERR_MSG: &str =
61 | "The item should have been added during symbol table discovery";
62 |
63 | match symbol {
64 | Symbol::Program(p) => {
65 | let p = programs.get_mut(p).expect(ERR_MSG);
66 | p.variables = variable_ids;
67 | }
68 | Symbol::Function(f) => {
69 | let f = functions.get_mut(f).expect(ERR_MSG);
70 | f.variables = variable_ids;
71 | }
72 | Symbol::FunctionBlock(fb) => {
73 | let fb = function_blocks.get_mut(fb).expect(ERR_MSG);
74 | fb.variables = variable_ids;
75 | }
76 | Symbol::Type(_) => unreachable!(),
77 | }
78 | }
79 | }
80 | }
81 |
82 | fn resolve_variables(
83 | parent_scope: Symbol,
84 | symbol_table: &SymbolTable,
85 | blocks: &[iec_syntax::VarBlock],
86 | variables: &mut Container,
87 | diags: &mut Diagnostics,
88 | ) -> Vec {
89 | let mut names = HashMap::new();
90 | let mut ids = Vec::new();
91 |
92 | for block in blocks {
93 | for decl in &block.declarations {
94 | let name = &decl.ident.value;
95 | let to_lower = name.to_lowercase();
96 |
97 | if let Some(&original_span) = names.get(&to_lower) {
98 | diags.push(
99 | Diagnostic::new_error("Duplicate variable declarations")
100 | .with_label(
101 | Label::new_primary(decl.ident.span)
102 | .with_message("Duplicate declared here"),
103 | )
104 | .with_label(
105 | Label::new_secondary(original_span).with_message(
106 | "Original variable was declared here",
107 | ),
108 | ),
109 | );
110 | continue;
111 | }
112 |
113 | let ty = symbol_table.get(&decl.ty.value);
114 |
115 | let type_id = match ty {
116 | Some(Symbol::Type(id)) => id,
117 | Some(_) => {
118 | diags.push(
119 | Diagnostic::new_error("Expected the name of a type")
120 | .with_label(Label::new_primary(decl.ty.span)),
121 | );
122 | continue;
123 | }
124 | None => {
125 | diags.push(
126 | Diagnostic::new_error("Unknown type")
127 | .with_label(Label::new_primary(decl.ty.span)),
128 | );
129 | continue;
130 | }
131 | };
132 |
133 | names.insert(to_lower, decl.ident.span);
134 | let id = variables.insert(Variable {
135 | parent: parent_scope,
136 | ty: type_id,
137 | name: Some(name.clone()),
138 | });
139 | ids.push(id);
140 | }
141 | }
142 |
143 | ids
144 | }
145 |
146 | #[cfg(test)]
147 | mod tests {
148 | use super::*;
149 |
150 | #[test]
151 | fn discover_some_variables() {
152 | let block = iec_syntax::quote!(var { x: int; });
153 | let mut variables = Container::default();
154 | let mut diags = Diagnostics::new();
155 | let mut symbols = SymbolTable::default();
156 |
157 | symbols.insert("int", Symbol::Type(EntityId::default()));
158 |
159 | let got = resolve_variables(
160 | Symbol::Function(EntityId::default()),
161 | &symbols,
162 | &[block],
163 | &mut variables,
164 | &mut diags,
165 | );
166 |
167 | assert_eq!(diags.len(), 0);
168 | assert_eq!(variables.len(), 1);
169 | assert_eq!(got.len(), 1);
170 |
171 | let (id, var) = variables.iter().next().unwrap();
172 |
173 | assert!(got.contains(&id));
174 | assert_eq!(var.name, Some(String::from("x")));
175 | }
176 |
177 | #[test]
178 | fn duplicate_variable_declarations() {
179 | let block = iec_syntax::quote!(var { x: int; X: int; });
180 | let mut variables = Container::default();
181 | let mut diags = Diagnostics::new();
182 | let mut symbols = SymbolTable::default();
183 | symbols.insert("int", Symbol::Type(EntityId::default()));
184 |
185 | let got = resolve_variables(
186 | Symbol::Function(EntityId::default()),
187 | &symbols,
188 | &[block],
189 | &mut variables,
190 | &mut diags,
191 | );
192 |
193 | assert!(diags.has_errors());
194 | assert_eq!(got.len(), 1);
195 | assert_eq!(variables.len(), 1);
196 | }
197 |
198 | #[test]
199 | fn unknown_type() {
200 | let block = iec_syntax::quote!(var { x: int; y: string; });
201 | let mut variables = Container::default();
202 | let mut diags = Diagnostics::new();
203 | let symbols = SymbolTable::default();
204 |
205 | let got = resolve_variables(
206 | Symbol::Function(EntityId::default()),
207 | &symbols,
208 | &[block],
209 | &mut variables,
210 | &mut diags,
211 | );
212 |
213 | assert!(diags.has_errors());
214 | assert_eq!(diags.len(), 2);
215 | assert!(got.is_empty());
216 | assert!(variables.is_empty());
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/runner/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "iec_runner"
3 | version = "0.1.0"
4 | authors = ["Michael Bryan "]
5 | edition = "2018"
6 |
7 | [[bin]]
8 | name = "iecc"
9 | path = "src/main.rs"
10 |
11 | [dependencies]
12 | slog-async = "2.3.0"
13 | slog-term = "2.4.0"
14 | slog = "2.4.1"
15 | structopt = "0.2.15"
16 | iec = { path = "../iec" }
17 | iec_syntax = { path = "../syntax" }
18 | slog_derive = "0.1.1"
19 | codespan = "0.2.1"
20 | codespan-reporting = "0.2.1"
21 | failure = "0.1.5"
22 | failure_derive = "0.1.5"
23 | lalrpop-util = "0.16.3"
24 | heapsize = "0.4.2"
25 |
--------------------------------------------------------------------------------
/runner/src/main.rs:
--------------------------------------------------------------------------------
1 | //! The `main` function for the `iec` compiler.
2 | //!
3 | //! This crate doesn't really add new functionality to the compiler, instead it
4 | //! glues together the front-end ([`iec_syntax`]), middle-end ([`iec`]), and
5 | //! back-end to produce a functional compilation tool.
6 |
7 | use codespan::{ByteOffset, ByteSpan, CodeMap, FileMap};
8 | use codespan_reporting::termcolor::{ColorChoice, StandardStream};
9 | use codespan_reporting::{Diagnostic, Label};
10 | use failure::{Error, ResultExt};
11 | use heapsize::HeapSizeOf;
12 | use iec::passes::PassContext;
13 | use iec::{CompilationUnit, Diagnostics};
14 | use iec_syntax::File;
15 | use slog::{Drain, Level, Logger};
16 | use slog_derive::KV;
17 | use std::str::FromStr;
18 | use std::time::Instant;
19 | use structopt::StructOpt;
20 |
21 | fn main() {
22 | let args = Args::from_args();
23 | let logger = create_logger(args.verbosity);
24 |
25 | if let Err(e) = run(&args, &logger) {
26 | slog::error!(logger, "{}", e);
27 | for cause in e.iter_causes() {
28 | slog::warn!(logger, "Caused by: {}", cause);
29 | }
30 |
31 | drop(logger);
32 |
33 | let bt = e.backtrace().to_string();
34 |
35 | if !bt.trim().is_empty() {
36 | eprintln!("{}", bt);
37 | }
38 |
39 | std::process::exit(1);
40 | }
41 | }
42 |
43 | fn run(args: &Args, logger: &Logger) -> Result<(), Error> {
44 | slog::info!(logger, "Started the application"; &args);
45 | let start = Instant::now();
46 | let mut map = CodeMap::new();
47 |
48 | let fm = map
49 | .add_filemap_from_disk(&args.file)
50 | .context("Unable to read the file into memory")?;
51 |
52 | slog::debug!(logger, "Read the file to disk";
53 | "filename" => fm.name().as_ref().display(),
54 | "size" => fm.src().len());
55 |
56 | let syntax_logger = logger.new(slog::o!("stage" => "syntactic-analysis"));
57 | slog::debug!(syntax_logger, "Starting syntactic analysis");
58 | let start_syntax = Instant::now();
59 |
60 | let file = match syntactic_analysis(&fm) {
61 | Ok(f) => f,
62 | Err(e) => {
63 | let ss = StandardStream::stdout(ColorChoice::Auto);
64 | codespan_reporting::emit(ss, &map, &e)?;
65 | return Ok(());
66 | }
67 | };
68 |
69 | let duration = Instant::now() - start_syntax;
70 | slog::debug!(syntax_logger, "Finished syntactic analysis";
71 | "memory-usage" => file.heap_size_of_children(),
72 | "execution-time" => format_args!("{}.{:03}s", duration.as_secs(), duration.subsec_millis()));
73 |
74 | let mut diags = Diagnostics::new();
75 |
76 | let semantic_logger = logger.new(slog::o!("stage" => "semantic-analysis"));
77 | slog::debug!(semantic_logger, "Started semantic analysis");
78 | let start_semantics = Instant::now();
79 |
80 | let cu = semantic_analysis(&file, &mut diags, logger);
81 |
82 | if diags.has_errors() {
83 | let mut ss = StandardStream::stdout(ColorChoice::Auto);
84 | for diagnostic in diags.diagnostics() {
85 | codespan_reporting::emit(&mut ss, &map, diagnostic)?;
86 | }
87 | return Ok(());
88 | }
89 |
90 | let duration = Instant::now() - start_semantics;
91 | slog::debug!(semantic_logger, "Finished semantic analysis";
92 | "execution-time" => format_args!("{}.{:03}s", duration.as_secs(), duration.subsec_millis()),
93 | "memory-usage" => cu.heap_size_of_children() + file.heap_size_of_children());
94 |
95 | let duration = Instant::now() - start;
96 | slog::info!(logger, "Compilation finished";
97 | "execution-time" => format_args!("{}.{:03}s", duration.as_secs(), duration.subsec_millis()));
98 |
99 | slog::debug!(logger, "{:#?}", cu);
100 | Ok(())
101 | }
102 |
103 | fn semantic_analysis(
104 | file: &File,
105 | diags: &mut Diagnostics,
106 | logger: &Logger,
107 | ) -> CompilationUnit {
108 | let mut ctx = PassContext {
109 | diags,
110 | logger: logger.new(slog::o!("stage" => "semantic-analysis")),
111 | };
112 | iec::process(file, &mut ctx)
113 | }
114 |
115 | fn syntactic_analysis(file: &FileMap) -> Result {
116 | let offset = ByteOffset(file.span().start().0 as i64 - 2);
117 |
118 | iec_syntax::File::from_str(file.src())
119 | .map_err(|e| e.map_location(|l| l - offset))
120 | .map_err(|e| match e {
121 | lalrpop_util::ParseError::InvalidToken { location } => {
122 | Diagnostic::new_error("Invalid token").with_label(
123 | Label::new_primary(ByteSpan::from_offset(
124 | location,
125 | ByteOffset(1),
126 | )),
127 | )
128 | }
129 |
130 | lalrpop_util::ParseError::ExtraToken {
131 | token: (start, tok, end),
132 | } => Diagnostic::new_error(format!(
133 | "Encountered \"{}\" when it wasn't expected",
134 | tok
135 | ))
136 | .with_label(Label::new_primary(ByteSpan::new(start, end))),
137 |
138 | lalrpop_util::ParseError::UnrecognizedToken {
139 | token: Some((start, tok, end)),
140 | expected,
141 | } => Diagnostic::new_error(format!(
142 | "Found \"{}\" but was expecting {}",
143 | tok,
144 | expected.join(", ")
145 | ))
146 | .with_label(Label::new_primary(ByteSpan::new(start, end))),
147 |
148 | lalrpop_util::ParseError::UnrecognizedToken {
149 | token: None,
150 | expected,
151 | } => Diagnostic::new_error(format!(
152 | "Expected one of {}",
153 | expected.join(", ")
154 | )),
155 |
156 | lalrpop_util::ParseError::User { error } => {
157 | Diagnostic::new_error(error.to_string())
158 | }
159 | })
160 | }
161 |
162 | #[derive(Debug, Clone, PartialEq, StructOpt, KV)]
163 | pub struct Args {
164 | #[structopt(help = "The file to compile")]
165 | pub file: String,
166 | #[structopt(
167 | short = "v",
168 | long = "verbose",
169 | parse(from_occurrences),
170 | help = "Generate more verbose output"
171 | )]
172 | pub verbosity: u32,
173 | }
174 |
175 | fn create_logger(verbosity: u32) -> Logger {
176 | let decorator = slog_term::TermDecorator::new().stderr().build();
177 | let drain = slog_term::CompactFormat::new(decorator).build().fuse();
178 | let drain = slog_async::Async::new(drain).build().fuse();
179 |
180 | let level = match verbosity {
181 | 0 => Level::Warning,
182 | 1 => Level::Info,
183 | 2 => Level::Debug,
184 | _ => Level::Trace,
185 | };
186 |
187 | slog::Logger::root(drain.filter_level(level).fuse(), slog::o!())
188 | }
189 |
--------------------------------------------------------------------------------
/syntax/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "iec_syntax"
3 | version = "0.1.0"
4 | authors = ["Michael Bryan "]
5 | edition = "2018"
6 | description = "Parser/lexer frontend for an IEC 61131-3 compiler."
7 | license = "MIT OR Apache-2.0"
8 | readme = "../README.md"
9 |
10 | [dependencies]
11 | regex = "1"
12 | lalrpop-util = "0.16"
13 | codespan = { version = "0.2.1", features = ["serialization", "memory_usage"] }
14 | serde = "1.0"
15 | serde_derive = "1.0"
16 | sum_type = "0.1.1"
17 | heapsize_derive = "0.1.4"
18 | heapsize = "0.4.2"
19 |
20 | [build-dependencies]
21 | lalrpop = "0.16"
22 |
23 | [dev-dependencies]
24 | pretty_assertions = "0.6.1"
25 | serde_json = "1.0"
26 | structopt = "0.2.15"
27 |
--------------------------------------------------------------------------------
/syntax/build.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | lalrpop::process_root().unwrap();
3 | }
4 |
--------------------------------------------------------------------------------
/syntax/examples/iec_parse.rs:
--------------------------------------------------------------------------------
1 | use iec_syntax::File;
2 | use std::io::{self, Read};
3 | use std::path::{Path, PathBuf};
4 | use std::str::FromStr;
5 | use structopt::StructOpt;
6 |
7 | fn main() {
8 | let args = Args::from_args();
9 | let mut input = args.input().unwrap();
10 |
11 | let mut buffer = String::new();
12 | input.read_to_string(&mut buffer).unwrap();
13 |
14 | let file: File = buffer.parse().unwrap();
15 |
16 | match args.format {
17 | OutputFormat::Rust => println!("{:#?}", file),
18 | OutputFormat::Json => {
19 | serde_json::to_writer(io::stdout(), &file).unwrap()
20 | }
21 | OutputFormat::PrettyJson => {
22 | serde_json::to_writer_pretty(io::stdout(), &file).unwrap()
23 | }
24 | }
25 | }
26 |
27 | #[derive(StructOpt)]
28 | #[structopt(
29 | about = "Parse some Structured Text into the corresponding Abstract Syntax Tree"
30 | )]
31 | struct Args {
32 | #[structopt(
33 | default_value = "-",
34 | parse(from_os_str),
35 | help = "The file to read (defaults to stdin)"
36 | )]
37 | file: PathBuf,
38 | #[structopt(
39 | short = "f",
40 | long = "format",
41 | default_value = "rust",
42 | raw(possible_values = "&[\"rust\", \"json\", \"pretty\"]"),
43 | help = "The format to use when displaying the AST"
44 | )]
45 | format: OutputFormat,
46 | }
47 |
48 | impl Args {
49 | fn input(&self) -> io::Result> {
50 | if self.file == Path::new("-") {
51 | Ok(Box::new(io::stdin()))
52 | } else {
53 | std::fs::File::open(&self.file)
54 | .map(|f| Box::new(f) as Box)
55 | }
56 | }
57 | }
58 |
59 | #[derive(Debug, Copy, Clone, PartialEq, Eq)]
60 | pub enum OutputFormat {
61 | Json,
62 | PrettyJson,
63 | Rust,
64 | }
65 |
66 | impl FromStr for OutputFormat {
67 | type Err = &'static str;
68 |
69 | fn from_str(s: &str) -> Result {
70 | let lowercase = s.to_lowercase();
71 |
72 | match lowercase.as_str() {
73 | "json" => Ok(OutputFormat::Json),
74 | "pretty" => Ok(OutputFormat::PrettyJson),
75 | "rust" => Ok(OutputFormat::Rust),
76 | _ => Err("Expected a valid output format"),
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/syntax/src/ast.rs:
--------------------------------------------------------------------------------
1 | use codespan::ByteSpan;
2 | use heapsize::HeapSizeOf;
3 | use heapsize_derive::HeapSizeOf;
4 | use serde_derive::{Deserialize, Serialize};
5 | use std::any::Any;
6 |
7 | pub trait AstNode: Any + HeapSizeOf {
8 | fn span(&self) -> ByteSpan;
9 | }
10 |
11 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
12 | pub struct File {
13 | pub items: Vec
- ,
14 | pub span: ByteSpan,
15 | }
16 |
17 | sum_type::sum_type! {
18 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
19 | pub enum Item {
20 | Program,
21 | Function,
22 | FunctionBlock,
23 | }
24 | }
25 |
26 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
27 | pub struct Function {
28 | pub name: Identifier,
29 | pub return_value: Identifier,
30 | pub var_blocks: Vec,
31 | pub body: Vec,
32 | pub span: ByteSpan,
33 | }
34 |
35 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
36 | pub struct FunctionBlock {
37 | pub name: Identifier,
38 | pub var_blocks: Vec,
39 | pub body: Vec,
40 | pub span: ByteSpan,
41 | }
42 |
43 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
44 | pub struct Program {
45 | pub name: Identifier,
46 | pub var_blocks: Vec,
47 | pub body: Vec,
48 | pub span: ByteSpan,
49 | }
50 |
51 | sum_type::sum_type! {
52 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
53 | pub enum Statement {
54 | Assignment,
55 | FunctionCall,
56 | ForLoop,
57 | WhileLoop,
58 | RepeatLoop,
59 | Exit,
60 | Return,
61 | IfStatement,
62 | }
63 | }
64 |
65 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
66 | pub struct IfStatement {
67 | pub condition: Expression,
68 | pub body: Vec,
69 | pub span: ByteSpan,
70 | }
71 |
72 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
73 | pub struct Exit {
74 | pub span: ByteSpan,
75 | }
76 |
77 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
78 | pub struct Return {
79 | pub span: ByteSpan,
80 | }
81 |
82 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
83 | pub struct Identifier {
84 | pub value: String,
85 | pub span: ByteSpan,
86 | }
87 |
88 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
89 | pub struct DottedIdentifier {
90 | pub pieces: Vec,
91 | pub span: ByteSpan,
92 | }
93 |
94 | impl From for DottedIdentifier {
95 | fn from(id: Identifier) -> DottedIdentifier {
96 | let span = id.span;
97 | DottedIdentifier {
98 | pieces: vec![id],
99 | span: span,
100 | }
101 | }
102 | }
103 |
104 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
105 | pub struct Declaration {
106 | pub ident: Identifier,
107 | pub ty: Identifier,
108 | pub span: ByteSpan,
109 | }
110 |
111 | impl Declaration {
112 | pub fn new(
113 | ident: Identifier,
114 | ty: Identifier,
115 | span: ByteSpan,
116 | ) -> Declaration {
117 | Declaration { ident, ty, span }
118 | }
119 | }
120 |
121 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
122 | pub struct Assignment {
123 | pub variable: DottedIdentifier,
124 | pub value: Expression,
125 | pub span: ByteSpan,
126 | }
127 |
128 | sum_type::sum_type! {
129 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
130 | pub enum Expression {
131 | Literal(Literal),
132 | Variable(DottedIdentifier),
133 | Binary(BinaryExpression),
134 | Unary(UnaryExpression),
135 | FunctionCall(FunctionCall),
136 | }
137 | }
138 |
139 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
140 | pub struct BinaryExpression {
141 | pub left: Box,
142 | pub right: Box,
143 | pub op: BinOp,
144 | pub span: ByteSpan,
145 | }
146 |
147 | #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
148 | pub enum BinOp {
149 | Add,
150 | Subtract,
151 | Or,
152 | Xor,
153 | And,
154 | Equals,
155 | NotEquals,
156 | LessThan,
157 | GreaterThan,
158 | LessThanOrEqual,
159 | GreaterThanOrEqual,
160 | Multiply,
161 | Divide,
162 | Modulo,
163 | Not,
164 | Exponent,
165 | }
166 |
167 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
168 | pub struct UnaryExpression {
169 | pub value: Box,
170 | pub op: UnaryOp,
171 | pub span: ByteSpan,
172 | }
173 |
174 | #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
175 | pub enum UnaryOp {
176 | Not,
177 | Negate,
178 | }
179 |
180 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
181 | pub struct Literal {
182 | pub kind: LiteralKind,
183 | pub span: ByteSpan,
184 | }
185 |
186 | impl Literal {
187 | pub fn new>(kind: K, span: ByteSpan) -> Literal {
188 | Literal {
189 | kind: kind.into(),
190 | span,
191 | }
192 | }
193 | }
194 |
195 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
196 | pub enum LiteralKind {
197 | Boolean(bool),
198 | Integer(i64),
199 | Float(f64),
200 | String(String),
201 | }
202 |
203 | impl From for LiteralKind {
204 | fn from(other: bool) -> LiteralKind {
205 | LiteralKind::Boolean(other)
206 | }
207 | }
208 |
209 | impl From for LiteralKind {
210 | fn from(other: i64) -> LiteralKind {
211 | LiteralKind::Integer(other)
212 | }
213 | }
214 |
215 | impl From for LiteralKind {
216 | fn from(other: f64) -> LiteralKind {
217 | LiteralKind::Float(other)
218 | }
219 | }
220 |
221 | impl From for LiteralKind {
222 | fn from(other: String) -> LiteralKind {
223 | LiteralKind::String(other)
224 | }
225 | }
226 |
227 | impl<'a> From<&'a str> for LiteralKind {
228 | fn from(other: &'a str) -> LiteralKind {
229 | LiteralKind::String(other.to_string())
230 | }
231 | }
232 |
233 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
234 | pub struct FunctionCall {
235 | pub name: Identifier,
236 | pub args: Vec,
237 | pub span: ByteSpan,
238 | }
239 |
240 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
241 | pub enum FunctionArg {
242 | Bare(Expression),
243 | Named(Assignment),
244 | }
245 |
246 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
247 | pub struct ForLoop {
248 | pub variable: Identifier,
249 | pub start: Expression,
250 | pub end: Expression,
251 | pub step: Option,
252 | pub body: Vec,
253 | pub span: ByteSpan,
254 | }
255 |
256 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
257 | pub struct WhileLoop {
258 | pub condition: Expression,
259 | pub body: Vec,
260 | pub span: ByteSpan,
261 | }
262 |
263 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
264 | pub struct RepeatLoop {
265 | pub condition: Expression,
266 | pub body: Vec,
267 | pub span: ByteSpan,
268 | }
269 |
270 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
271 | pub struct VarBlock {
272 | pub kind: VarBlockKind,
273 | pub declarations: Vec,
274 | pub span: ByteSpan,
275 | }
276 |
277 | #[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
278 | pub enum VarBlockKind {
279 | Local,
280 | Input,
281 | Output,
282 | InputOutput,
283 | }
284 |
285 | macro_rules! impl_ast_node {
286 | ($name:tt => $($variant:tt)|*) => {
287 | impl AstNode for $name {
288 | fn span(&self) -> ByteSpan {
289 | match self {
290 | $(
291 | $name::$variant(ref inner) => inner.span(),
292 | )*
293 | }
294 | }
295 | }
296 | };
297 | ($($name:ty,)*) => {
298 | $(
299 | impl AstNode for $name {
300 | fn span(&self) -> ByteSpan {
301 | self.span
302 | }
303 | }
304 | )*
305 | };
306 | }
307 |
308 | impl_ast_node!(
309 | Literal,
310 | Assignment,
311 | Declaration,
312 | Identifier,
313 | BinaryExpression,
314 | UnaryExpression,
315 | FunctionCall,
316 | Return,
317 | ForLoop,
318 | WhileLoop,
319 | RepeatLoop,
320 | Exit,
321 | VarBlock,
322 | Program,
323 | File,
324 | FunctionBlock,
325 | Function,
326 | DottedIdentifier,
327 | IfStatement,
328 | );
329 | impl_ast_node!(Item => Function | FunctionBlock | Program);
330 | impl_ast_node!(Expression => Literal | Binary | Unary | Variable | FunctionCall);
331 | impl_ast_node!(Statement => FunctionCall | Assignment | Return | ForLoop |
332 | WhileLoop | RepeatLoop | Exit | IfStatement);
333 | impl_ast_node!(FunctionArg => Bare | Named);
334 |
335 | #[cfg(test)]
336 | mod tests {
337 | use super::*;
338 | use crate::utils::*;
339 | use pretty_assertions::assert_eq;
340 |
341 | macro_rules! parse_test {
342 | ($name:ident, $parser:tt, $input:expr => $expected:expr) => {
343 | #[test]
344 | fn $name() {
345 | #[allow(unused_imports)]
346 | use $crate::grammar::*;
347 | let got = $parser::new().parse($input).unwrap();
348 | assert_eq!(got, $expected.into());
349 | }
350 | };
351 | }
352 |
353 | parse_test!(simple_ident, IdentParser, "hello" => Identifier { value: "hello".to_string(), span: s(0, 5) });
354 | parse_test!(ident_with_numbers, IdentParser, "hello_45" => Identifier { value: "hello_45".to_string(), span: s(0, 8) });
355 |
356 | parse_test!(example_decl, DeclParser, "x: Bool" => Declaration {
357 | ident: Identifier { value: "x".to_string(), span: s(0, 1) },
358 | ty: Identifier { value: "Bool".to_string(), span: s(3, 7) },
359 | span: s(0, 7),
360 | });
361 |
362 | parse_test!(assign_literal, AssignmentParser, "meaning_of_life := 42" => Assignment {
363 | variable: Identifier{ value: "meaning_of_life".to_string(), span: s(0, 15) }.into(),
364 | value: Expression::Literal(Literal {
365 | kind: LiteralKind::Integer(42),
366 | span: s(19, 21),
367 | }),
368 | span: s(0, 21),
369 | });
370 |
371 | parse_test!(function_call, ExprParser, "foo()" => Expression::FunctionCall(FunctionCall {
372 | name: Identifier { value: "foo".to_string(), span: s(0, 3) },
373 | args: Vec::new(),
374 | span: s(0, 5),
375 | }));
376 |
377 | parse_test!(function_call_with_args, ExprParser, "foo(1, second := 2)" => Expression::FunctionCall(FunctionCall {
378 | name: Identifier { value: "foo".to_string(), span: s(0, 3) },
379 | args: vec![
380 | FunctionArg::Bare(Expression::Literal(Literal::new(1, s(4, 5)))),
381 | FunctionArg::Named(Assignment {
382 | variable: Identifier { value: "second".to_string(), span: s(7, 13) }.into(),
383 | value: Expression::Literal(Literal::new(2, s(17, 18))),
384 | span: s(7, 18),
385 | }),
386 | ],
387 | span: s(0, 19),
388 | }));
389 |
390 | parse_test!(binary_op, ExprParser, "5+5" => Expression::Binary(BinaryExpression {
391 | left: Box::new(Expression::Literal(Literal {
392 | kind: LiteralKind::Integer(5),
393 | span: s(0, 1),
394 | })),
395 | right: Box::new(Expression::Literal(Literal {
396 | kind: LiteralKind::Integer(5),
397 | span: s(2, 3),
398 | })),
399 | op: BinOp::Add,
400 | span: s(0, 3),
401 | }));
402 |
403 | parse_test!(super_complex_expression, ExprParser, "5*5 + add(-(9**2), -34/pi)" =>
404 | Expression::Binary(BinaryExpression {
405 | left: Box::new(Expression::Binary(BinaryExpression {
406 | left: Box::new(Expression::Literal(Literal {
407 | kind: LiteralKind::Integer(5),
408 | span: s(0, 1),
409 | })),
410 | right: Box::new(Expression::Literal(Literal {
411 | kind: LiteralKind::Integer(5),
412 | span: s(2, 3),
413 | })),
414 | op: BinOp::Multiply,
415 | span: s(0, 3),
416 | })),
417 | right: Box::new(Expression::FunctionCall(FunctionCall {
418 | name: Identifier {
419 | value: String::from("add"),
420 | span: s(6, 9),
421 | },
422 | args: vec![
423 | FunctionArg::Bare(Expression::Unary(UnaryExpression {
424 | value: Box::new(Expression::Binary(BinaryExpression {
425 | left: Box::new(Expression::Literal(Literal {
426 | kind: LiteralKind::Integer(9),
427 | span: s(12, 13),
428 | })),
429 | right: Box::new(Expression::Literal(Literal {
430 | kind: LiteralKind::Integer(2),
431 | span: s(15, 16),
432 | })),
433 | op: BinOp::Exponent,
434 | span: s(12, 16),
435 | })),
436 | op: UnaryOp::Negate,
437 | span: s(10, 17),
438 | })),
439 | FunctionArg::Bare(Expression::Binary(BinaryExpression {
440 | left: Box::new(Expression::Literal(Literal {
441 | kind: LiteralKind::Integer(-34),
442 | span: s(19, 22),
443 | })),
444 | right: Box::new(Expression::Variable(Identifier {
445 | value: String::from("pi"),
446 | span: s(23, 25),
447 | }.into())),
448 | op: BinOp::Divide,
449 | span: s(19, 25),
450 | })),
451 | ],
452 | span: s(6, 26),
453 | })),
454 | op: BinOp::Add,
455 | span: s(0, 26),
456 | })
457 | );
458 |
459 | parse_test!(exit_statement, StmtParser, "exit" => Statement::Exit(Exit { span: s(0, 4)}));
460 | parse_test!(return_statement, StmtParser, "reTUrn" => Statement::Return(Return { span: s(0, 6)}));
461 |
462 | parse_test!(simple_for_loop, IterationStatementParser, "for x:= 0 TO 5 do return; end_for" =>
463 | Statement::ForLoop(ForLoop {
464 | variable: Identifier {
465 | value: String::from("x"),
466 | span: s(4, 5),
467 | },
468 | start: Expression::Literal(
469 | Literal {
470 | kind: LiteralKind::Integer(0),
471 | span: s(8, 9),
472 | }
473 | ),
474 | end: Expression::Literal(
475 | Literal {
476 | kind: LiteralKind::Integer(5),
477 | span: s(13, 14),
478 | }
479 | ),
480 | step: None,
481 | body: vec![
482 | Statement::Return(
483 | Return {
484 | span: s(18, 24),
485 | }
486 | )
487 | ],
488 | span: s(0, 33),
489 | }));
490 |
491 | parse_test!(while_loop, IterationStatementParser, "while true do end_while" =>
492 | Statement::WhileLoop(WhileLoop {
493 | condition: Expression::Literal(Literal {
494 | kind: LiteralKind::Boolean(true),
495 | span: s(6, 10),
496 | }),
497 | body: Vec::new(),
498 | span: s(0, 23),
499 | }));
500 |
501 | parse_test!(repeat_loop, IterationStatementParser, "repeat return; until true end_repeat" =>
502 | Statement::RepeatLoop(RepeatLoop {
503 | condition: Expression::Literal(Literal {
504 | kind: LiteralKind::Boolean(true),
505 | span: s(21, 25),
506 | }),
507 | body: vec![
508 | Statement::Return(Return { span: s(7, 13) }),
509 | ],
510 | span: s(0, 36),
511 | }));
512 |
513 | parse_test!(single_var_block, BlockParser, "var i: INT; end_var" => VarBlock {
514 | kind: VarBlockKind::Local,
515 | declarations: vec![Declaration {
516 | ident: Identifier {
517 | value: String::from("i"),
518 | span: s(4, 5),
519 | },
520 | ty: Identifier {
521 | value: String::from("INT"),
522 | span: s(7, 10),
523 | },
524 | span: s(4, 10),
525 | }],
526 | span: s(0, 19),
527 | });
528 |
529 | const EXAMPLE_PROGRAM: &str = "
530 | PROGRAM main
531 | VAR
532 | i : INT;
533 | END_VAR
534 |
535 | i := 0;
536 | REPEAT
537 | i := i + 1;
538 | UNTIL i >= 10
539 | END_REPEAT;
540 | END_PROGRAM";
541 |
542 | fn example_program_parsed() -> Program {
543 | Program {
544 | name: Identifier {
545 | value: String::from("main"),
546 | span: s(9, 13),
547 | },
548 | var_blocks: vec![VarBlock {
549 | kind: VarBlockKind::Local,
550 | declarations: vec![Declaration {
551 | ident: Identifier {
552 | value: String::from("i"),
553 | span: s(30, 31),
554 | },
555 | ty: Identifier {
556 | value: String::from("INT"),
557 | span: s(34, 37),
558 | },
559 | span: s(30, 37),
560 | }],
561 | span: s(18, 50),
562 | }],
563 | body: vec![
564 | Statement::Assignment(Assignment {
565 | variable: Identifier {
566 | value: String::from("i"),
567 | span: s(56, 57),
568 | }
569 | .into(),
570 | value: Expression::Literal(Literal {
571 | kind: LiteralKind::Integer(0),
572 | span: s(61, 62),
573 | }),
574 | span: s(56, 62),
575 | }),
576 | Statement::RepeatLoop(RepeatLoop {
577 | condition: Expression::Binary(BinaryExpression {
578 | left: Box::new(Expression::Variable(
579 | Identifier {
580 | value: String::from("i"),
581 | span: s(105, 106),
582 | }
583 | .into(),
584 | )),
585 | right: Box::new(Expression::Literal(Literal {
586 | kind: LiteralKind::Integer(10),
587 | span: s(110, 112),
588 | })),
589 | op: BinOp::GreaterThanOrEqual,
590 | span: s(105, 112),
591 | }),
592 | body: vec![Statement::Assignment(Assignment {
593 | variable: Identifier {
594 | value: String::from("i"),
595 | span: s(83, 84),
596 | }
597 | .into(),
598 | value: Expression::Binary(BinaryExpression {
599 | left: Box::new(Expression::Variable(
600 | Identifier {
601 | value: String::from("i"),
602 | span: s(88, 89),
603 | }
604 | .into(),
605 | )),
606 | right: Box::new(Expression::Literal(Literal {
607 | kind: LiteralKind::Integer(1),
608 | span: s(92, 93),
609 | })),
610 | op: BinOp::Add,
611 | span: s(88, 93),
612 | }),
613 | span: s(83, 93),
614 | })],
615 | span: s(68, 127),
616 | }),
617 | ],
618 | span: s(1, 140),
619 | }
620 | }
621 |
622 | parse_test!(trivial_program, ProgramParser, EXAMPLE_PROGRAM => example_program_parsed());
623 |
624 | parse_test!(dotted_identifier, ExprParser, "x.y.z" => Expression::Variable(DottedIdentifier {
625 | pieces: vec![
626 | Identifier {
627 | value: "x".to_string(),
628 | span: s(0, 1),
629 | },
630 | Identifier {
631 | value: "y".to_string(),
632 | span: s(2, 3),
633 | },
634 | Identifier {
635 | value: "z".to_string(),
636 | span: s(4, 5),
637 | },
638 | ],
639 | span: s(0, 5),
640 | }));
641 |
642 | parse_test!(if_statement, IfParser, "if true then return; end_if" => IfStatement {
643 | condition: Expression::Literal(Literal{ kind: LiteralKind::Boolean(true), span: s(3, 7) }),
644 | body: vec![
645 | Statement::Return(Return { span: s(13, 19) }),
646 | ],
647 | span: s(0, 27),
648 | });
649 | }
650 |
--------------------------------------------------------------------------------
/syntax/src/grammar.lalrpop:
--------------------------------------------------------------------------------
1 | use crate::utils::{s, bop, unop};
2 | use crate::ast::*;
3 |
4 | grammar;
5 |
6 | match {
7 | // keywords get first priority
8 | r"(?i)and" => AND,
9 | r"(?i)begin" => BEGIN,
10 | r"(?i)by" => BY,
11 | r"(?i)do" => DO,
12 | r"(?i)else" => ELSE,
13 | r"(?i)end_for" => END_FOR,
14 | r"(?i)end_function_block" => END_FUNCTION_BLOCK,
15 | r"(?i)end_function" => END_FUNCTION,
16 | r"(?i)end_if" => END_IF,
17 | r"(?i)end_program" => END_PROGRAM,
18 | r"(?i)end_repeat" => END_REPEAT,
19 | r"(?i)end_var" => END_VAR,
20 | r"(?i)end_while" => END_WHILE,
21 | r"(?i)exit" => EXIT,
22 | r"(?i)false" => FALSE,
23 | r"(?i)for" => FOR,
24 | r"(?i)function_block" => FUNCTION_BLOCK,
25 | r"(?i)function" => FUNCTION,
26 | r"(?i)if" => IF,
27 | r"(?i)not" => NOT,
28 | r"(?i)or" => OR,
29 | r"(?i)program" => PROGRAM,
30 | r"(?i)repeat" => REPEAT,
31 | r"(?i)return" => RETURN,
32 | r"(?i)then" => THEN,
33 | r"(?i)to" => TO,
34 | r"(?i)true" => TRUE,
35 | r"(?i)until" => UNTIL,
36 | r"(?i)var_input_output" => VAR_INPUT_OUTPUT,
37 | r"(?i)var_input" => VAR_INPUT,
38 | r"(?i)var_output" => VAR_OUTPUT,
39 | r"(?i)var" => VAR,
40 | r"(?i)while" => WHILE,
41 | r"(?i)xor" => XOR,
42 | } else {
43 | r"-?\d+" => INTEGER,
44 | } else {
45 | r"[\w_][\w_\d]*" => IDENT,
46 | _,
47 | }
48 |
49 | pub File: File = {
50 | => File { items, span: s(l, r) },
51 | };
52 |
53 | Item: Item = {
54 | => <>.into(),
55 | => <>.into(),
56 | => <>.into(),
57 | };
58 |
59 | Function: Function = {
60 | FUNCTION ":" BEGIN
61 |
62 |
63 | END_FUNCTION =>
64 | Function {
65 | name,
66 | var_blocks,
67 | return_value,
68 | body,
69 | span: s(l, r),
70 | },
71 | };
72 |
73 | FunctionBlock: FunctionBlock = {
74 | FUNCTION_BLOCK
75 |
76 | BEGIN
77 |
78 | END_FUNCTION_BLOCK => FunctionBlock {
79 | name,
80 | var_blocks,
81 | body,
82 | span: s(l, r),
83 | },
84 | };
85 |
86 | pub Statements: Vec = {
87 | => stmts,
88 | };
89 |
90 | statement_with_semicolon: Statement = {
91 | ";" => <>,
92 | };
93 |
94 | pub Stmt: Statement = {
95 | => <>.into(),
96 | => <>.into(),
97 | => <>,
98 | => <>.into(),
99 | EXIT => Statement::Exit(Exit { span: s(l, r) }),
100 | RETURN => Statement::Return(Return { span: s(l, r) }),
101 | };
102 |
103 | pub If: IfStatement = {
104 | IF THEN END_IF => IfStatement { condition, body, span: s(l, r) },
105 | };
106 |
107 | pub Ident: Identifier = {
108 | => Identifier { value: id.to_string(), span: s(l, r) },
109 | };
110 |
111 | pub Decl: Declaration = {
112 | ":" => Declaration::new(id, ty, s(l, r)),
113 | };
114 |
115 | pub Lit: Literal = {
116 | => Literal::new(kind, s(l, r)),
117 | };
118 |
119 | LiteralKind: LiteralKind = {
120 | INTEGER => LiteralKind::Integer(<>.parse().unwrap()),
121 | TRUE => LiteralKind::Boolean(true),
122 | FALSE => LiteralKind::Boolean(false),
123 | };
124 |
125 | pub Assignment: Assignment = {
126 | ":=" => Assignment { variable: id, value, span: s(l, r) },
127 | };
128 |
129 | pub Expr: Expression = {
130 | OR => bop(left, right, BinOp::Or, s(l, r)),
131 | => <>,
132 | };
133 |
134 | XorExpr: Expression = {
135 | XOR => bop(left, right, BinOp::Xor, s(l, r)),
136 | => <>,
137 | };
138 |
139 | AndExpr: Expression = {
140 | AND => bop(left, right, BinOp::And, s(l, r)),
141 | => <>,
142 | };
143 |
144 | Comparison: Expression = {
145 | "=" => bop(left, right, BinOp::Equals, s(l, r)),
146 | "<>" => bop(left, right, BinOp::NotEquals, s(l, r)),
147 | => <>,
148 | };
149 |
150 | EquExpression: Expression = {
151 | "<" => bop(left, right, BinOp::LessThan, s(l, r)),
152 | "<=" => bop(left, right, BinOp::LessThanOrEqual, s(l, r)),
153 | ">" => bop(left, right, BinOp::GreaterThan, s(l, r)),
154 | ">=" => bop(left, right, BinOp::GreaterThanOrEqual, s(l, r)),
155 | => <>,
156 | };
157 |
158 | AddExpression: Expression = {
159 | "+" => bop(left, right, BinOp::Add, s(l, r)),
160 | "-" => bop(left, right, BinOp::Subtract, s(l, r)),
161 | => <>,
162 | };
163 |
164 | Term: Expression = {
165 |