├── .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 | [![Build Status](https://travis-ci.com/Michael-F-Bryan/iec.svg?branch=master)](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 | "*" => bop(left, right, BinOp::Multiply, s(l, r)), 166 | "/" => bop(left, right, BinOp::Divide, s(l, r)), 167 | "%" => bop(left, right, BinOp::Modulo, s(l, r)), 168 | => <>, 169 | }; 170 | 171 | PowerExpression: Expression = { 172 | "**" => bop(left, right, BinOp::Exponent, s(l, r)), 173 | => <>, 174 | }; 175 | 176 | UnaryExpression: Expression = { 177 | "-" => unop(expr, UnaryOp::Negate, s(l, r)), 178 | NOT => unop(expr, UnaryOp::Not, s(l, r)), 179 | => <>, 180 | }; 181 | 182 | PrimaryExpression: Expression = { 183 | "(" ")" => <>, 184 | => Expression::Literal(<>), 185 | => Expression::Variable(<>.into()), 186 | => Expression::FunctionCall(<>), 187 | }; 188 | 189 | DottedIdentifier: DottedIdentifier = { 190 | )*> => DottedIdentifier { 191 | pieces: ::std::iter::once(first).chain(tail).collect(), 192 | span: s(l, r), 193 | }, 194 | }; 195 | 196 | FunctionCall: FunctionCall = { 197 | "(" > ")" => FunctionCall { 198 | name, args, span: s(l, r), 199 | }, 200 | }; 201 | 202 | FuncArg: FunctionArg = { 203 | => FunctionArg::Named(<>), 204 | => FunctionArg::Bare(<>), 205 | }; 206 | 207 | pub IterationStatement: Statement = { 208 | => <>, 209 | => <>, 210 | => <>, 211 | }; 212 | 213 | ForLoop: Statement = { 214 | FOR ":=" TO 215 | )?> DO END_FOR => Statement::ForLoop(ForLoop { 216 | variable: var, 217 | start, 218 | end, 219 | step, 220 | body, 221 | span: s(l, r) 222 | }), 223 | } 224 | 225 | WhileLoop: Statement = { 226 | WHILE DO END_WHILE => Statement::WhileLoop(WhileLoop { 227 | condition, 228 | body, 229 | span: s(l, r), 230 | }), 231 | } 232 | 233 | RepeatLoop: Statement = { 234 | REPEAT UNTIL ";"? END_REPEAT => Statement::RepeatLoop(RepeatLoop { 235 | condition, 236 | body, 237 | span: s(l, r), 238 | }), 239 | } 240 | 241 | pub Block: VarBlock = { 242 | , 243 | }; 244 | 245 | VarBlock: VarBlock = { 246 | VAR ";")*> END_VAR => VarBlock { kind: VarBlockKind::Local, declarations: decls, span: s(l, r) }, 247 | VAR_INPUT ";")*> END_VAR => VarBlock { kind: VarBlockKind::Input, declarations: decls, span: s(l, r) }, 248 | VAR_OUTPUT ";")*> END_VAR => VarBlock { kind: VarBlockKind::Output, declarations: decls, span: s(l, r) }, 249 | VAR_INPUT_OUTPUT ";")*> END_VAR => VarBlock { kind: VarBlockKind::InputOutput, declarations: decls, span: s(l, r) }, 250 | }; 251 | 252 | pub Program: Program = { 253 | PROGRAM END_PROGRAM => 254 | Program { name, var_blocks, body, span: s(l, r) } 255 | }; 256 | 257 | Comma: Vec = { 258 | ",")*> => match e { 259 | None => v, 260 | Some(e) => { 261 | let mut v = v; 262 | v.push(e); 263 | v 264 | } 265 | } 266 | }; -------------------------------------------------------------------------------- /syntax/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate lalrpop_util; 3 | 4 | #[macro_export] 5 | macro_rules! defer { 6 | ($value:expr, $ty:ident, $( $variant:ident )|* => |$name:ident| $eval:block) => { 7 | match $value { 8 | $( 9 | $ty::$variant(ref $name) => $eval, 10 | )* 11 | } 12 | }; 13 | } 14 | 15 | #[macro_use] 16 | pub mod macros; 17 | 18 | mod ast; 19 | mod utils; 20 | 21 | pub use crate::ast::*; 22 | pub type ParseError = lalrpop_util::ParseError; 23 | 24 | lalrpop_util::lalrpop_mod!( 25 | #[allow(dead_code)] 26 | grammar 27 | ); 28 | 29 | use codespan::ByteIndex; 30 | 31 | macro_rules! impl_from_str { 32 | ($name:ident => $parser:ident) => { 33 | impl ::std::str::FromStr for $crate::$name { 34 | type Err = $crate::ParseError; 35 | 36 | fn from_str(s: &str) -> Result { 37 | $crate::grammar::$parser::new() 38 | .parse(s) 39 | .map_err(|e| e.map_location(|loc| ByteIndex(loc as u32))) 40 | .map_err(|e| e.map_token(|tok| tok.to_string())) 41 | } 42 | } 43 | }; 44 | ($( $name:ident => $parser:ident;)*) => { 45 | $( 46 | impl_from_str!($name => $parser); 47 | )* 48 | }; 49 | } 50 | 51 | impl_from_str! { 52 | File => FileParser; 53 | Program => ProgramParser; 54 | Expression => ExprParser; 55 | Statement => StmtParser; 56 | } 57 | -------------------------------------------------------------------------------- /syntax/src/macros.rs: -------------------------------------------------------------------------------- 1 | /// A macro for concisely generating syntax trees. 2 | /// 3 | /// # Examples 4 | /// 5 | /// ```rust 6 | /// use iec_syntax::{Declaration, VarBlock, Program, Statement}; 7 | /// 8 | /// // declarations look identical to normal Structured Text 9 | /// let decl: Declaration = iec_syntax::quote!(x: int); 10 | /// assert_eq!(decl.ident.value, "x"); 11 | /// assert_eq!(decl.ty.value, "int"); 12 | /// 13 | /// // var blocks use "{" and "}" instead of var/end_var 14 | /// let var: VarBlock = iec_syntax::quote!(var { x: int; }); 15 | /// assert_eq!(var.declarations.len(), 1); 16 | /// 17 | /// // An empty program is equally as simple 18 | /// let program: Program = iec_syntax::quote!(program asd {}); 19 | /// assert_eq!(program.name.value, "asd"); 20 | /// assert!(program.body.is_empty()); 21 | /// 22 | /// // programs can also have var blocks 23 | /// let program_2: Program = iec_syntax::quote!(program asd { var {}}); 24 | /// assert_eq!(program_2.var_blocks.len(), 1); 25 | /// 26 | /// // statements are followed by a semicolon 27 | /// let assign: Statement = iec_syntax::quote!(meaning_of_life := 42;); 28 | /// ``` 29 | #[macro_export] 30 | macro_rules! quote { 31 | (program $name:ident { 32 | var { $($vars:tt)* } 33 | 34 | $($tail:tt)* 35 | }) => { 36 | $crate::Program { 37 | name: $crate::quote!(@IDENT $name), 38 | var_blocks: vec![$crate::quote!(var { $($vars) * })], 39 | body: Vec::new(), 40 | span: Default::default(), 41 | } 42 | }; 43 | (program $name:ident { 44 | $($tail:tt)* 45 | }) => { 46 | $crate::Program { 47 | name: $crate::quote!(@IDENT $name), 48 | var_blocks: Vec::new(), 49 | body: Vec::new(), 50 | span: Default::default(), 51 | } 52 | }; 53 | (var { $($tail:tt)* }) => { 54 | $crate::VarBlock { 55 | kind: $crate::VarBlockKind::Local, 56 | declarations: $crate::quote!($($tail)*), 57 | span: Default::default(), 58 | } 59 | }; 60 | (function_block $name:ident { $($tail:tt)* }) => { 61 | $crate::FunctionBlock { 62 | name: $crate::quote!(@IDENT $name), 63 | var_blocks: Vec::new(), 64 | body: vec![], 65 | span: Default::default(), 66 | } 67 | }; 68 | ($( $name:ident : $type:ident; )*) => { 69 | vec![ 70 | $( $crate::quote!($name : $type) ),* 71 | ] 72 | }; 73 | ($name:ident := $value:expr; ) => { 74 | $crate::Statement::Assignment($crate::Assignment { 75 | variable: $crate::quote!($name), 76 | value: $crate::Expression::Literal($crate::Literal { 77 | kind: $value.into(), 78 | span: Default::default(), 79 | }), 80 | span: Default::default(), 81 | }) 82 | }; 83 | ($name:ident : $type:ident) => { 84 | $crate::Declaration { 85 | ident: $crate::quote!(@IDENT $name), 86 | ty: $crate::quote!(@IDENT $type), 87 | span: Default::default(), 88 | } 89 | }; 90 | ($ident:ident $( . $rest:ident )*) => { 91 | $crate::DottedIdentifier { 92 | pieces: vec![ 93 | $crate::quote!(@IDENT $ident), 94 | $($crate::quote!(@IDENT $rest)),* 95 | ], 96 | span: Default::default(), 97 | } 98 | }; 99 | (@IDENT $id:ident) => { 100 | $crate::Identifier { 101 | value: stringify!($id).to_string(), 102 | span: Default::default(), 103 | } 104 | }; 105 | } 106 | -------------------------------------------------------------------------------- /syntax/src/utils.rs: -------------------------------------------------------------------------------- 1 | use crate::{BinOp, BinaryExpression, Expression, UnaryExpression, UnaryOp}; 2 | use codespan::{ByteIndex, ByteSpan}; 3 | 4 | pub(crate) fn s(start: usize, end: usize) -> ByteSpan { 5 | ByteSpan::new(ByteIndex(start as u32), ByteIndex(end as u32)) 6 | } 7 | 8 | pub(crate) fn bop(l: L, r: R, op: BinOp, span: ByteSpan) -> Expression 9 | where 10 | L: Into, 11 | R: Into, 12 | { 13 | let expr = BinaryExpression { 14 | left: Box::new(l.into()), 15 | right: Box::new(r.into()), 16 | op, 17 | span, 18 | }; 19 | 20 | Expression::Binary(expr) 21 | } 22 | 23 | pub(crate) fn unop(expr: E, op: UnaryOp, span: ByteSpan) -> Expression 24 | where 25 | E: Into, 26 | { 27 | Expression::Unary(UnaryExpression { 28 | value: Box::new(expr.into()), 29 | op, 30 | span, 31 | }) 32 | } 33 | -------------------------------------------------------------------------------- /syntax/tests/compile_test.rs: -------------------------------------------------------------------------------- 1 | macro_rules! parse_file { 2 | ($( $filename:ident),* $(,)*) => { 3 | $( 4 | #[test] 5 | fn $filename() { 6 | use std::path::Path; 7 | let path = Path::new(env!("CARGO_MANIFEST_DIR")) 8 | .join("tests") 9 | .join("data") 10 | .join(concat!(stringify!($filename), ".st")); 11 | 12 | assert!(path.exists(), "\"{}\" doesn't exist", path.display()); 13 | 14 | let body = std::fs::read_to_string(&path).unwrap(); 15 | 16 | let file: iec_syntax::File = body.parse().unwrap(); 17 | 18 | let jason = serde_json::to_string_pretty(&file).unwrap(); 19 | println!("{}", jason); 20 | } 21 | )* 22 | }; 23 | ($filename:ident) => { 24 | }; 25 | } 26 | 27 | parse_file! { 28 | hello_world, 29 | id_function, 30 | // function_block, 31 | // struct_decl, 32 | } 33 | -------------------------------------------------------------------------------- /syntax/tests/data/function_block.st: -------------------------------------------------------------------------------- 1 | FUNCTION_BLOCK mqttRuntime 2 | 3 | VAR_INPUT 4 | IN : BOOL; 5 | RES : BOOL; 6 | END_VAR 7 | 8 | VAR_OUTPUT 9 | RTIME : TIME; 10 | END_VAR 11 | 12 | VAR 13 | last : DINT; 14 | now : DINT; 15 | run : DINT; 16 | FP_IN : BOOL; 17 | END_VAR 18 | 19 | BEGIN 20 | 21 | IF IN AND NOT FP_IN THEN 22 | last := 0; 23 | FP_IN := true; 24 | END_IF; 25 | 26 | IF NOT IN AND FP_IN THEN 27 | FP_IN := false; 28 | END_IF; 29 | 30 | 31 | IF IN AND NOT RES THEN 32 | now := DWORD_TO_DINT(Unixtime()); 33 | IF last = 0 THEN 34 | last := now; 35 | ELSE 36 | run := run + (now - last); 37 | last := now; 38 | END_IF; 39 | 40 | END_IF; 41 | 42 | IF IN AND RES THEN 43 | run := 0; 44 | now := 0; 45 | last := 0; 46 | ELSIF NOT IN AND RES THEN 47 | run := 0; 48 | now := 0; 49 | last := 0; 50 | END_IF; 51 | 52 | IF run >= 2073600 THEN 53 | run := 0; 54 | END_IF; 55 | 56 | RTIME := DINT_TO_TIME(run * 1000); 57 | 58 | END_FUNCTION_BLOCK 59 | -------------------------------------------------------------------------------- /syntax/tests/data/hello_world.st: -------------------------------------------------------------------------------- 1 | PROGRAM MAIN 2 | VAR 3 | i: int; 4 | count: int; 5 | END_VAR 6 | 7 | for i := 0 TO 7 do 8 | count := count + i; 9 | end_for; 10 | 11 | END_PROGRAM -------------------------------------------------------------------------------- /syntax/tests/data/id_function.st: -------------------------------------------------------------------------------- 1 | FUNCTION mqttGetNextMessageID : INT 2 | BEGIN 3 | mqttData.nextMsgId := mqttData.nextMsgId + 1; 4 | 5 | IF (mqttData.nextMsgId <= 0) THEN 6 | mqttData.nextMsgId := 1; 7 | END_IF; 8 | 9 | mqttGetNextMessageID := mqttData.nextMsgId; 10 | END_FUNCTION 11 | -------------------------------------------------------------------------------- /syntax/tests/data/struct_decl.st: -------------------------------------------------------------------------------- 1 | TYPE UDT_STRUCTANYPTR 2 | STRUCT 3 | S7Code : BYTE; // Code for S7 = 0x10 4 | DataType : BYTE; // Code for data type = 0x02 = byte 5 | Length : INT; // Repetition factor = Send/receive length 6 | DBNumber : INT; // Data block Number 7 | MemoryArea : BYTE; // Specified memory area = 0x84 = data block 8 | ByteAddressMSB : BYTE; // Byte address most significant bits 9 | ByteAddressLSB : WORD; // Byte address least significant bits 10 | END_STRUCT 11 | END_TYPE --------------------------------------------------------------------------------