From 174eba6e36ea46fe077a58050527a1d181572f42 Mon Sep 17 00:00:00 2001 From: Luka Dornhecker Date: Sun, 9 Oct 2022 20:14:49 +0200 Subject: [PATCH] wip --- Cargo.lock | 288 +++++++++++++++++++++++----------------- librbf/Cargo.toml | 4 +- librbf/src/ast.rs | 5 +- librbf/src/jit.rs | 24 ++-- librbf/src/lib.rs | 4 +- librbf/src/optimizer.rs | 107 +++++++++++++++ librbf/src/parser.rs | 277 +++++++++++++++++++------------------- librbf/tests/parser.rs | 232 ++++++++++++++++---------------- rbf/src/main.rs | 30 ++++- 9 files changed, 580 insertions(+), 391 deletions(-) create mode 100644 librbf/src/optimizer.rs diff --git a/Cargo.lock b/Cargo.lock index 6ba2fa6..39632da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,325 +1,369 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" +dependencies = [ + "const-random", +] + [[package]] name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] -name = "ascii" -version = "0.9.1" +name = "ariadne" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1cb2a2046bea8ce5e875551f5772024882de0b540c7f93dfc5d6cf1ca8b030c" +dependencies = [ + "yansi", +] [[package]] name = "atty" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "termion", + "winapi", ] [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "byteorder" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" [[package]] name = "cfg-if" -version = "0.1.6" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chumsky" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d02796e4586c6c41aeb68eae9bfb4558a522c35f1430c14b40136c3706e09e4" +dependencies = [ + "ahash", +] [[package]] name = "clap" version = "2.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "const-random" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f590d95d011aa80b063ffe3253422ed5aa462af4e9867d43ce8337562bac77c4" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "const-random-macro", + "proc-macro-hack", ] [[package]] -name = "combine" -version = "3.6.6" +name = "const-random-macro" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "615f6e27d000a2bffbc7f2f6a8669179378fa27ee4d0a509e985dfc0a7defb40" dependencies = [ - "ascii 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "lazy_static", + "proc-macro-hack", + "tiny-keccak", ] +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "dynasm" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62a59fbab09460c1569eeea9b5e4cf62f13f5198b1c2ba0e5196dd7fdd17cd42" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "byteorder", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "dynasmrt" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bec3edae2841d37b1c3dc7f3fd403c9061f26e9ffeeee97a3ea909b1bb2ef1" dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "dynasm 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "dynasm", + "memmap", ] [[package]] -name = "either" -version = "1.5.0" +name = "getrandom" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.48" +version = "0.2.134" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "329c933548736bc49fd575ee68c89e8be4d260064184389a5b77517cddd99ffb" [[package]] name = "librbf" version = "0.1.0" dependencies = [ - "combine 3.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "dynasm 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "dynasmrt 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memchr" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "ariadne", + "chumsky", + "dynasm", + "dynasmrt", + "libc", ] [[package]] name = "memmap" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "winapi", ] [[package]] name = "proc-macro-error" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc175e9777c3116627248584e8f8b3e2987405cabe1c0adf7d1dd28f09dc7880" dependencies = [ - "proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", ] [[package]] name = "proc-macro-error-attr" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cc9795ca17eb581285ec44936da7fc2335a3f34f2ddd13118b6f4d515435c50" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", + "syn-mid", + "version_check", ] +[[package]] +name = "proc-macro-hack" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" + [[package]] name = "proc-macro2" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid", ] [[package]] name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] name = "rbf" version = "0.1.0" dependencies = [ - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", - "librbf 0.1.0", + "clap", + "librbf", ] [[package]] name = "redox_syscall" version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" [[package]] name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" dependencies = [ - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall", ] [[package]] name = "strsim" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" [[package]] name = "syn" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] name = "syn-mid" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" dependencies = [ - "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "redox_syscall", + "redox_termios", ] [[package]] name = "textwrap" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" dependencies = [ - "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", ] [[package]] name = "unicode-width" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" [[package]] name = "vec_map" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" [[package]] name = "version_check" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" [[package]] -name = "void" -version = "1.0.2" +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[metadata] -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum ascii 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a5fc969a8ce2c9c0c4b0429bb8431544f6658283c8326ba5ff8c762b75369335" -"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" -"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" -"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" -"checksum combine 3.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "3d64b57f9d8186d72311c241e580409b31e5d340c67fd2d9c74f05eda6d3aa54" -"checksum dynasm 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "62a59fbab09460c1569eeea9b5e4cf62f13f5198b1c2ba0e5196dd7fdd17cd42" -"checksum dynasmrt 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bec3edae2841d37b1c3dc7f3fd403c9061f26e9ffeeee97a3ea909b1bb2ef1" -"checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" -"checksum memchr 2.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e1dd4eaac298c32ce07eb6ed9242eda7d82955b9170b7d6db59b2e02cc63fcb8" -"checksum memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b" -"checksum proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fc175e9777c3116627248584e8f8b3e2987405cabe1c0adf7d1dd28f09dc7880" -"checksum proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3cc9795ca17eb581285ec44936da7fc2335a3f34f2ddd13118b6f4d515435c50" -"checksum proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" -"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" -"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238" -"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" -"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" -"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/librbf/Cargo.toml b/librbf/Cargo.toml index 1e5dc72..4ff7bcb 100644 --- a/librbf/Cargo.toml +++ b/librbf/Cargo.toml @@ -2,9 +2,11 @@ name = "librbf" version = "0.1.0" authors = ["Luka Dornhecker "] +edition = "2021" [dependencies] -combine = "3.4" +chumsky = "0.8.0" +ariadne = "0.1.5" dynasm = "1.0" dynasmrt = "1.0" libc = "0.2.48" diff --git a/librbf/src/ast.rs b/librbf/src/ast.rs index 3ecd136..9d5c101 100755 --- a/librbf/src/ast.rs +++ b/librbf/src/ast.rs @@ -1,5 +1,8 @@ /// A Vector of [`Instruction`](enum.Instruction.html) representing a Brainfuck program. -pub type Program = Vec; +pub type Program = Vec>; + +pub type Span = std::ops::Range; +pub type Spanned = (T, Span); /// An enum representing all brainfuck instructions. #[derive(Clone, Debug, PartialEq)] diff --git a/librbf/src/jit.rs b/librbf/src/jit.rs index 79dd172..abf8395 100644 --- a/librbf/src/jit.rs +++ b/librbf/src/jit.rs @@ -1,10 +1,12 @@ -use ast::{Instruction::*, Program}; -use dynasm::dynasm; -use dynasmrt::{DynasmApi, DynasmLabelApi, ExecutableBuffer}; use std::io::Read; use std::io::{self, Write}; use std::mem; +use dynasm::dynasm; +use dynasmrt::{DynasmApi, DynasmLabelApi, ExecutableBuffer}; + +use crate::ast::{Instruction::*, Program}; + extern "C" fn putchar(c: u8) { print!("{}", c as char); } @@ -100,43 +102,43 @@ impl Jit { fn gen(&mut self, program: &Program) { for ins in program.iter() { match ins { - &Move(i) => { + &(Move(i), _) => { dynasm!(self.ops ; add rbx, i as _ ); } - &Add(i) => { + &(Add(i), _) => { dynasm!(self.ops ; add BYTE [rbx], i as _ ); } - Write => { + (Write, _) => { dynasm!(self.ops ; movzx rdi, [rbx] ; mov rax, QWORD putchar as _ ; call rax ); } - Read => { + (Read, _) => { dynasm!(self.ops ; mov rax, QWORD getchar as _ ; call rax ; mov [rbx], al ); } - Set(i) => { + (Set(i), _) => { dynasm!(self.ops ; mov BYTE [rbx], (i % 0xFF) as _ ); } - &Mul(offset, mul) => { + &(Mul(offset, mul), _) => { dynasm!(self.ops ; mov al, mul as _ ; mul BYTE [rbx] ; add [rbx + offset as _], al ); } - &Scan(i) => { + &(Scan(i), _) => { let move_label = self.ops.new_dynamic_label(); let rest_label = self.ops.new_dynamic_label(); dynasm!(self.ops @@ -149,7 +151,7 @@ impl Jit { ; =>rest_label ); } - Loop(body) => { + (Loop(body), _) => { let body_label = self.ops.new_dynamic_label(); let rest_label = self.ops.new_dynamic_label(); dynasm!(self.ops diff --git a/librbf/src/lib.rs b/librbf/src/lib.rs index 2b768c5..f6d9929 100755 --- a/librbf/src/lib.rs +++ b/librbf/src/lib.rs @@ -1,14 +1,14 @@ extern crate dynasm; extern crate dynasmrt; -#[macro_use] -extern crate combine; extern crate libc; mod ast; mod jit; +mod optimizer; mod parser; pub use ast::*; pub use jit::Jit; +pub use optimizer::optimize; pub use parser::parse; diff --git a/librbf/src/optimizer.rs b/librbf/src/optimizer.rs new file mode 100644 index 0000000..2d3cb1a --- /dev/null +++ b/librbf/src/optimizer.rs @@ -0,0 +1,107 @@ +use std::collections::HashMap; + +use crate::ast::{Instruction::*, Program, Spanned}; + +fn opt(program: Program) -> Program { + let mut iter = program.iter().peekable(); + let mut prog: Program = vec![]; + + while let Some(current) = iter.next() { + match (current, iter.peek()) { + ((Add(0), _), _) => (), + ((Move(0), _), _) => (), + + ((Add(a), span_a), Some((Add(b), span_b))) => { + iter.next(); + prog.push((Add(a + b), span_a.start..span_b.end)); + } + ((Move(a), span_a), Some((Move(b), span_b))) => { + iter.next(); + prog.push((Move(a + b), span_a.start..span_b.end)); + } + + ((Loop(body), span), _) => { + if let Some(optimized_body) = optimize_loop((body.clone(), span.clone())) { + prog.extend(optimized_body); + } + } + ((Set(a), span_set), Some((Add(b), span_add))) => { + iter.next(); + prog.push((Set(a + b), span_set.start..span_add.end)); + } + + ((Add(_), _), Some(&set @ (Set(_), _))) | ((Set(_), _), Some(&set @ (Set(_), _))) => { + iter.next(); + prog.push(set.clone()); + } + + ((Set(0), _), Some((Loop(_), _))) => { + iter.next(); + prog.push(current.clone()) + } + ((Set(0), _), Some((Mul(_, _), _))) => { + prog.push(current.clone()); + while let Some((Mul(_, _), _)) = iter.next() {} + } + _ => prog.push(current.clone()), + } + } + prog +} + +fn optimize_loop(program: Spanned) -> Option { + match &program.0[..] { + [] => None, + [(Set(0), _)] => Some(vec![(Set(0), program.1)]), + [(Add(-1), _)] => Some(vec![(Set(0), program.1)]), + [(Move(n), _)] => Some(vec![(Scan(*n), program.1)]), + _ => Some(optimize_mul((optimize(program.0), program.1))), + } +} + +fn optimize_mul(program: Spanned) -> Program { + let mut muls = HashMap::new(); + let mut offset = 0; + let mut is_mul = true; + + for ins in program.0.iter() { + match ins { + (Add(i), _) => *muls.entry(offset).or_insert(0) += i, + (Move(i), _) => offset += i, + _ => is_mul = false, + } + if is_mul == false { + break; + } + } + + if !is_mul || offset != 0 || muls.get(&0) != Some(&-1) { + return vec![(Loop(program.0), program.1)]; + } + + let mut result: Vec<_> = muls + .iter() + .map(|(&k, &v)| { + if k == 0 { + None + } else { + Some((Mul(k, v), program.1.clone())) + } + }) + .filter_map(|x| x) + .collect(); + + result.push((Set(0), program.1)); + result +} + +pub fn optimize(program: Program) -> Program { + let mut opt_a = opt(program); + let mut opt_b = opt(opt_a.clone()); + + while opt_a != opt_b { + opt_a = opt(opt_b.clone()); + opt_b = opt(opt_a.clone()); + } + opt_b +} diff --git a/librbf/src/parser.rs b/librbf/src/parser.rs index 6bf9d63..a17a761 100755 --- a/librbf/src/parser.rs +++ b/librbf/src/parser.rs @@ -1,152 +1,163 @@ -use std::collections::HashMap; -use std::io::Read; - -use ast::Instruction::*; -use ast::*; - -use combine::byte::byte; -use combine::{ - between, choice, eof, many, many1, satisfy, skip_many, - stream::{buffered::BufferedStream, state::State, ReadStream}, - Parser, Stream, -}; - -parser! { - #[inline(always)] - fn program[I]()(I) -> Program - where [I: Stream] - { - let comments = || skip_many(satisfy(|c| !"+-><,.[]".bytes().any(|t| t == c))); - let chars = |c| many1::, _>(byte(c)); - - let add = chars(b'+').map(|s: _| Add(s.len() as i64)); - let sub = chars(b'-').map(|s: _| Add(-(s.len() as i64))); - let left = chars(b'<').map(|s: _| Move(-(s.len() as i64))); - let right = chars(b'>').map(|s: _| Move(s.len() as i64)); - let read = byte(b',').map(|_| Read); - let write = byte(b'.').map(|_| Write); - - let bfloop = between(byte(b'['), byte(b']'), program()).map(Loop); - - let instruction = choice(( - add, - sub, - left, - right, - read, - write, - bfloop - )).skip(comments()); - - ( - comments(), - many(instruction) - ).map(|(_comments, instructions)| instructions) - } +use crate::ast::Instruction::*; +use crate::ast::*; + +use ariadne::{Color, Fmt, Label, Report, Source}; +use chumsky::error::SimpleReason; +use chumsky::prelude::*; + +fn program() -> impl Parser> { + recursive(|prog| { + let counted = |neg, pos, m: fn(i64) -> _| { + just(neg) + .repeated() + .at_least(1) + .map(move |i| m(-(i.len() as i64))) + .or(just(pos) + .repeated() + .at_least(1) + .map(move |i| m(i.len() as i64))) + .map_with_span(|i, span| (i, span)) + }; + let add = counted('-', '+', Add); + let mov = counted('<', '>', Move); + let write = just('.').map_with_span(|_, span| (Write, span)); + let read = just(',').map_with_span(|_, span| (Read, span)); + choice((add, mov, write, read)) + .or(prog + .delimited_by(just('['), just(']')) + .map_with_span(|l, span| (Loop(l), span))) + .recover_with(nested_delimiters('[', ']', [], |_| { + unreachable!(); + })) + .recover_with(skip_then_retry_until([']'])) + .padded_by(none_of("+-[]<>,.").repeated()) + .repeated() + }) + .then_ignore(end()) } -fn optimize(program: Program) -> Program { - let mut iter = program.iter().peekable(); - let mut prog: Program = vec![]; - - while let Some(current) = iter.next() { - match (current, iter.peek()) { - (Add(0), _) => (), - (Move(0), _) => (), - - (Add(a), Some(Add(b))) => { - iter.next(); - prog.push(Add(a + b)) - } - (Move(a), Some(Move(b))) => { - iter.next(); - prog.push(Move(a + b)) - } +#[derive(Debug)] +pub struct ParseError(Vec>); - (Loop(ref body), _) => { - if let Some(optimized_body) = optimize_loop(body.clone()) { - prog.extend(optimized_body); - } - } +pub struct ErrorReport(Vec); - (Set(a), Some(Add(b))) => { - iter.next(); - prog.push(Set(a + b)) - } - (Add(_), Some(Set(a))) => { - iter.next(); - prog.push(Set(*a)) - } - (Set(_), Some(Set(a))) => { - iter.next(); - prog.push(Set(*a)) - } - (Set(0), Some(Loop(_))) => { - iter.next(); - prog.push(Set(0)) - } - (Set(0), Some(Mul(_, _))) => { - prog.push(Set(0)); - while let Some(Mul(_, _)) = iter.next() {} - } - - _ => prog.push(current.clone()), +impl ErrorReport { + pub fn eprint(self, source: &str) { + for report in self.0.into_iter() { + report.eprint(Source::from(source)).unwrap(); } } - prog } -fn optimize_loop(program: Program) -> Option> { - match *program { - [] => None, - [Add(-1)] => Some(vec![Set(0)]), - [Move(n)] => Some(vec![Scan(n)]), - [Set(0)] => Some(vec![Set(0)]), - _ => Some(optimize_mul(optimize(program))), - } -} - -fn optimize_mul(program: Program) -> Vec { - let mut muls = HashMap::new(); - let mut offset = 0; - let mut is_mul = true; - - for ins in program.iter() { - match ins { - Add(i) => *muls.entry(offset).or_insert(0) += i, - Move(i) => offset += i, - _ => is_mul = false, - } +impl ParseError { + pub fn is_error(&self) -> bool { + self.0.len() > 0 } - if !is_mul || offset != 0 || muls.get(&0) != Some(&-1) { - return vec![Loop(program)]; + pub fn report(&self) -> ErrorReport { + let reports = self + .0 + .iter() + .map(|e| e.clone().map(|c| c.to_string())) + .map(|e| { + let report = Report::build(ariadne::ReportKind::Error, (), e.span().start); + let report = match e.reason() { + SimpleReason::Unclosed { span, delimiter } => report + .with_message(format!( + "Unclosed delimiter {}", + delimiter.fg(Color::Yellow) + )) + .with_label(Label::new(span.clone()).with_message(format!( + "Unclosed delimiter {}", + delimiter.fg(Color::Yellow) + ))), + SimpleReason::Unexpected => report + .with_message(format!( + "{}, expected {}", + if e.found().is_some() { + "Unexpected token in input" + } else { + "Unexpected end of input" + }, + if e.expected().len() == 0 { + "something else".to_string() + } else { + e.expected() + .map(|expected| match expected { + Some(expected) => expected.fg(Color::Cyan).to_string(), + None => "end of input".to_string(), + }) + .collect::>() + .join(", ") + } + )) + .with_label( + Label::new(e.span()) + .with_message(format!( + "Unexpected token {}", + e.found() + .unwrap_or(&"end of file".to_string()) + .fg(Color::Red) + )) + .with_color(Color::Red), + ), + SimpleReason::Custom(_) => todo!(), + }; + report.finish() + }) + .collect::>(); + ErrorReport(reports) } +} - let mut result: Vec<_> = muls - .iter() - .map(|(&k, &v)| if k == 0 { None } else { Some(Mul(k, v)) }) - .filter_map(|x| x) - .collect(); - result.push(Set(0)); - result +pub fn parse(input: &str) -> (Option, ParseError) { + let (prog, err) = program().parse_recovery(input); + (prog, ParseError(err)) } -fn opt(program: Program) -> Program { - let mut opt_a = optimize(program); - let mut opt_b = optimize(opt_a.clone()); +#[cfg(test)] +mod test { + use crate::{ast::Instruction::*, Program}; - while opt_a != opt_b { - opt_a = optimize(opt_b.clone()); - opt_b = optimize(opt_a.clone()); + fn parse(input: &str) -> Program { + crate::parse(input).0.unwrap() } - opt_b -} + #[test] + fn it_parses_simple_programs() { + assert_eq!(parse("."), vec![(Write, 0..1)]); + assert_eq!(parse(".."), vec![(Write, 0..1), (Write, 1..2)]); + assert_eq!(parse(","), vec![(Read, 0..1)]); + assert_eq!(parse(",,"), vec![(Read, 0..1), (Read, 1..2)]); + assert_eq!(parse("++++"), vec![(Add(4), 0..4)]); + assert_eq!(parse("----"), vec![(Add(-4), 0..4)]); + assert_eq!(parse("++++---"), vec![(Add(4), 0..4), (Add(-3), 4..7)]); + assert_eq!(parse("++++ ---"), vec![(Add(4), 0..4), (Add(-3), 5..8)]); + assert_eq!(parse("++++@---"), vec![(Add(4), 0..4), (Add(-3), 5..8)]); + assert_eq!(parse("f + o - o"), vec![(Add(1), 2..3), (Add(-1), 6..7)]); + assert_eq!(parse(">>>>"), vec![(Move(4), 0..4)]); + assert_eq!(parse("<<<<"), vec![(Move(-4), 0..4)]); + assert_eq!(parse(">>>><<<"), vec![(Move(4), 0..4), (Move(-3), 4..7)]); + assert_eq!(parse(">>>> <<<"), vec![(Move(4), 0..4), (Move(-3), 5..8)]); + assert_eq!(parse(">>>>@<<<"), vec![(Move(4), 0..4), (Move(-3), 5..8)]); + assert_eq!(parse("f > o < o"), vec![(Move(1), 2..3), (Move(-1), 6..7)]); + } -/// Parses Brainfuck source and returns a [Program](type.Program.html). -pub fn parse(input: R) -> Program { - let stream = BufferedStream::new(State::new(ReadStream::new(input)), 1); - let ((prog, _eof), _state) = (program(), eof()).parse(stream).unwrap(); - opt(prog) + #[test] + fn it_parses_loops() { + assert_eq!(parse("[]"), vec![(Loop(vec![]), 0..2)]); + assert_eq!(parse("[-]"), vec![(Loop(vec![(Add(-1), 1..2)]), 0..3)]); + assert_eq!( + parse("[[-]]"), + vec![(Loop(vec![(Loop(vec![(Add(-1), 2..3)]), 1..4)]), 0..5)] + ); + + assert_eq!( + parse("[+][-]"), + vec![ + (Loop(vec![(Add(1), 1..2)]), 0..3), + (Loop(vec![(Add(-1), 4..5)]), 3..6), + ] + ); + } } diff --git a/librbf/tests/parser.rs b/librbf/tests/parser.rs index e217ae2..a99c324 100755 --- a/librbf/tests/parser.rs +++ b/librbf/tests/parser.rs @@ -2,119 +2,119 @@ extern crate librbf; use librbf::{Instruction::*, Program}; -fn parse(input: &str) -> Program { - librbf::parse(input.as_bytes()) -} - -#[test] -fn it_parses_an_empty_program() { - assert_eq!(parse(""), vec![]); -} - -#[test] -fn it_parses_an_empty_program_with_comments() { - assert_eq!(parse(" foo bar baz "), []); -} - -#[test] -fn it_parses_a_very_very_simple_program() { - assert_eq!(parse(" ++++ "), [Add(4)]); -} - -#[test] -fn it_parses_a_very_simple_program() { - assert_eq!( - parse(">+<-,."), - [Move(1), Add(1), Move(-1), Add(-1), Read, Write] - ); -} - -#[test] -fn it_groups_consecutive_adds() { - assert_eq!(parse("++---+-----"), [Add(-5)]); -} - -#[test] -fn it_groups_consecutive_adds_with_comments() { - assert_eq!(parse("-foo-++++\n+bar++- --"), [Add(2)]); -} - -#[test] -fn it_groups_consecutive_moves() { - assert_eq!(parse("<<<><>>>>"), [Move(1)]); -} - -#[test] -fn it_groups_consecutive_moves_with_comments() { - assert_eq!(parse(">foo><<<<\n>bar>>< <<"), [Move(-2)]); -} - -#[test] -fn it_parses_simple_loops() { - assert_eq!(parse("-[+]+"), [Add(-1), Loop(vec![Add(1)]), Add(1)]); -} - -#[test] -fn it_omits_empty_loops() { - assert_eq!(parse("++[][]+"), [Add(3)]); -} - -#[test] -fn it_omits_empty_nested_loops() { - assert_eq!(parse("++[[[][]][[][]][]]+"), [Add(3)]); -} - -#[test] -fn it_parses_nested_loops() { - let expected = vec![ - Add(-1), - Loop(vec![Add(2), Loop(vec![Add(-2)]), Loop(vec![Add(2)])]), - Add(1), - ]; - assert_eq!(parse("-[++[--][++]]+"), expected); -} - -#[test] -fn it_omits_zero_adds() { - assert_eq!(parse(".++ --."), [Write, Write]) -} - -#[test] -fn it_omits_zero_moves() { - assert_eq!(parse(".>> <<."), [Write, Write]) -} - -#[test] -fn it_transforms_a_scan_loop_into_a_scan() { - assert_eq!(parse("[-]"), [Set(0)]); -} - -#[test] -fn it_combines_set_with_following_adds() { - assert_eq!(parse("[-]+++"), [Set(3)]); -} - -#[test] -fn it_omits_adds_after_sets() { - assert_eq!(parse("+++[-]+"), [Set(1)]); -} - -#[test] -fn it_omits_sets_before_sets() { - assert_eq!(parse("[-]+++++[-]--"), [Set(-2)]); -} - -#[test] -fn it_omits_loops_after_set_0() { - assert_eq!(parse("[-][>+.<-]."), [Set(0), Write]); -} - -#[test] -fn it_omits_muls_after_set_0() { - assert_eq!(parse("[-][>+<-]."), [Set(0), Write]); -} - -#[test] -fn it_transforms_move_loops_into_scans() { - assert_eq!(parse("[>>>>]"), [Scan(4)]); -} +// fn parse(input: &str) -> Program { +// librbf::parse(input.as_bytes()) +// } + +// #[test] +// fn it_parses_an_empty_program() { +// assert_eq!(parse(""), vec![]); +// } + +// #[test] +// fn it_parses_an_empty_program_with_comments() { +// assert_eq!(parse(" foo bar baz "), []); +// } + +// #[test] +// fn it_parses_a_very_very_simple_program() { +// assert_eq!(parse(" ++++ "), [Add(4)]); +// } + +// #[test] +// fn it_parses_a_very_simple_program() { +// assert_eq!( +// parse(">+<-,."), +// [Move(1), Add(1), Move(-1), Add(-1), Read, Write] +// ); +// } + +// #[test] +// fn it_groups_consecutive_adds() { +// assert_eq!(parse("++---+-----"), [Add(-5)]); +// } + +// #[test] +// fn it_groups_consecutive_adds_with_comments() { +// assert_eq!(parse("-foo-++++\n+bar++- --"), [Add(2)]); +// } + +// #[test] +// fn it_groups_consecutive_moves() { +// assert_eq!(parse("<<<><>>>>"), [Move(1)]); +// } + +// #[test] +// fn it_groups_consecutive_moves_with_comments() { +// assert_eq!(parse(">foo><<<<\n>bar>>< <<"), [Move(-2)]); +// } + +// #[test] +// fn it_parses_simple_loops() { +// assert_eq!(parse("-[+]+"), [Add(-1), Loop(vec![Add(1)]), Add(1)]); +// } + +// #[test] +// fn it_omits_empty_loops() { +// assert_eq!(parse("++[][]+"), [Add(3)]); +// } + +// #[test] +// fn it_omits_empty_nested_loops() { +// assert_eq!(parse("++[[[][]][[][]][]]+"), [Add(3)]); +// } + +// #[test] +// fn it_parses_nested_loops() { +// let expected = vec![ +// Add(-1), +// Loop(vec![Add(2), Loop(vec![Add(-2)]), Loop(vec![Add(2)])]), +// Add(1), +// ]; +// assert_eq!(parse("-[++[--][++]]+"), expected); +// } + +// #[test] +// fn it_omits_zero_adds() { +// assert_eq!(parse(".++ --."), [Write, Write]) +// } + +// #[test] +// fn it_omits_zero_moves() { +// assert_eq!(parse(".>> <<."), [Write, Write]) +// } + +// #[test] +// fn it_transforms_a_scan_loop_into_a_scan() { +// assert_eq!(parse("[-]"), [Set(0)]); +// } + +// #[test] +// fn it_combines_set_with_following_adds() { +// assert_eq!(parse("[-]+++"), [Set(3)]); +// } + +// #[test] +// fn it_omits_adds_after_sets() { +// assert_eq!(parse("+++[-]+"), [Set(1)]); +// } + +// #[test] +// fn it_omits_sets_before_sets() { +// assert_eq!(parse("[-]+++++[-]--"), [Set(-2)]); +// } + +// #[test] +// fn it_omits_loops_after_set_0() { +// assert_eq!(parse("[-][>+.<-]."), [Set(0), Write]); +// } + +// #[test] +// fn it_omits_muls_after_set_0() { +// assert_eq!(parse("[-][>+<-]."), [Set(0), Write]); +// } + +// #[test] +// fn it_transforms_move_loops_into_scans() { +// assert_eq!(parse("[>>>>]"), [Scan(4)]); +// } diff --git a/rbf/src/main.rs b/rbf/src/main.rs index 11480e5..0c4f161 100755 --- a/rbf/src/main.rs +++ b/rbf/src/main.rs @@ -1,10 +1,11 @@ extern crate clap; extern crate librbf; -use std::fs::File; use std::io::Write; +use std::process::exit; +use std::{fs::File, io::Read}; -use librbf::{parse, Jit}; +use librbf::{optimize, parse, Jit}; use clap::{App, AppSettings, Arg}; @@ -36,10 +37,29 @@ fn main() { ) .get_matches(); - let source_path = matches.value_of("PROGRAM").unwrap(); - let file = File::open(source_path).expect("Could not read program"); + let source = { + let source_path = matches.value_of("PROGRAM").unwrap(); + let mut file = File::open(source_path).expect("Could not open file"); + let mut source = String::new(); + file.read_to_string(&mut source) + .expect("Could not read file"); + source + }; - let program = parse(file); + let (program, err) = parse(&source); + + if err.is_error() { + err.report().eprint(&source); + exit(1); + } + + let program = if let Some(prog) = program { + prog + } else { + exit(1); + }; + + let program = optimize(program); if let Some("ast") = matches.value_of("emit") { println!("{:?}", program);