diff --git a/Cargo.lock b/Cargo.lock index bf3e5fa..37cc2e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,55 +3,83 @@ version = 3 [[package]] -name = "aho-corasick" -version = "0.7.20" +name = "anstream" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ - "memchr", + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", ] [[package]] -name = "autocfg" -version = "1.1.0" +name = "anstyle" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] -name = "bitflags" -version = "1.3.2" +name = "anstyle-parse" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] [[package]] -name = "cc" -version = "1.0.78" +name = "anstyle-query" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys", +] [[package]] name = "clap" -version = "4.1.4" +version = "4.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" +checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" dependencies = [ - "bitflags", + "clap_builder", "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +dependencies = [ + "anstream", + "anstyle", "clap_lex", - "is-terminal", - "once_cell", "strsim", - "termcolor", ] [[package]] name = "clap_derive" -version = "4.1.0" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", "syn", @@ -59,147 +87,54 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.3.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" -dependencies = [ - "os_str_bytes", -] +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "either" -version = "1.8.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] -name = "errno" -version = "0.2.8" +name = "glob" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" -dependencies = [ - "errno-dragonfly", - "libc", - "winapi", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "heck" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] -name = "hermit-abi" -version = "0.2.6" +name = "is_terminal_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "is-terminal" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189" -dependencies = [ - "hermit-abi", - "io-lifetimes", - "rustix", - "windows-sys", -] +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" -version = "0.10.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] -[[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.139" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" - -[[package]] -name = "linux-raw-sys" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "num-derive" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66" - -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - [[package]] name = "phf" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ "phf_macros", "phf_shared", @@ -207,9 +142,9 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ "phf_shared", "rand", @@ -217,9 +152,9 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ "phf_generator", "phf_shared", @@ -230,51 +165,27 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ "siphasher", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" -version = "1.0.50" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -294,23 +205,6 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -[[package]] -name = "regex" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" - [[package]] name = "rlox2" version = "0.1.0" @@ -318,7 +212,6 @@ dependencies = [ "clap", "rlox2-frontend", "rlox2-interpreter", - "rlox2-vm", ] [[package]] @@ -334,98 +227,56 @@ dependencies = [ name = "rlox2-interpreter" version = "0.1.0" dependencies = [ + "glob", "itertools", "rlox2-frontend", "rustc-hash", "thiserror", ] -[[package]] -name = "rlox2-vm" -version = "0.1.0" -dependencies = [ - "itertools", - "lazy_static", - "num-derive", - "num-traits", - "regex", - "rlox2-frontend", - "static_assertions", - "thiserror", -] - [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustix" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys", -] +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "siphasher" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "1.0.107" +version = "2.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", @@ -434,56 +285,35 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "version_check" -version = "0.9.4" +name = "utf8parse" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "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-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -492,42 +322,48 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml index 97455b0..66c265f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ name = "rlox" path = "src/main.rs" [workspace] -members = ["frontend", "interpreter", "vm"] +members = ["frontend", "interpreter"] # , "vm" [dependencies.rlox2-frontend] path = "frontend" @@ -16,8 +16,8 @@ path = "frontend" [dependencies.rlox2-interpreter] path = "interpreter" -[dependencies.rlox2-vm] -path = "vm" +# [dependencies.rlox2-vm] +# path = "vm" [dependencies] -clap = { version = "4.1.4", features = ["derive"] } +clap = { version = "4", features = ["derive"] } diff --git a/frontend/Cargo.toml b/frontend/Cargo.toml index a8f6fdd..3e970c6 100644 --- a/frontend/Cargo.toml +++ b/frontend/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -phf = { version = "0.11.1", features = ["macros"] } -thiserror = "1.0.38" -itertools = "0.10.5" +phf = { version = "0.11", features = ["macros"] } +thiserror = "1" +itertools = "0.13" diff --git a/frontend/src/lexer/_lexer.rs b/frontend/src/lexer/_lexer.rs index 190b545..b1f7088 100644 --- a/frontend/src/lexer/_lexer.rs +++ b/frontend/src/lexer/_lexer.rs @@ -129,6 +129,11 @@ impl Lexer { // line comment // advance until either source is empty or newline if found while !self.source_is_empty() && self.advance() != '\n' {} + + let comment: Box = + self.source[self.start + 2..self.current].iter().collect(); + + self.push_token(TokenType::Comment(comment)); } else if self.consume('*') { // block comment @@ -164,6 +169,12 @@ impl Lexer { self.advance(); } + + let comment: Box = self.source[self.start + 2..self.current - 2] + .iter() + .collect(); + + self.push_token(TokenType::Comment(comment)); } else { self.push_token(Slash) } @@ -237,10 +248,13 @@ impl Lexer { } } - let string_literal = self.source[self.start + 1..self.current - 1].iter().collect(); + let string_literal: Box = self.source[self.start + 1..self.current - 1] + .iter() + .collect(); // Some(TokenType::String(Box::new(string_literal))) - self.tokens.push(Token::new_string(string_literal, self.code_pos)); + self.tokens + .push(Token::new_string(string_literal, self.code_pos)); } fn try_parse_number(&mut self) { @@ -290,8 +304,12 @@ impl Lexer { } fn try_parse_identifier(&mut self) { - let is_alpha_num_underscore = - |c: Option| c.map_or(false, |c| matches!(c, '0'..='9' | 'A'..='Z' | '_' | 'a'..='z')); + let is_alpha_num_underscore = |c: Option| { + c.map_or( + false, + |c| matches!(c, '0'..='9' | 'A'..='Z' | '_' | 'a'..='z'), + ) + }; while is_alpha_num_underscore(self.peek()) { self.advance(); @@ -304,11 +322,12 @@ impl Lexer { .cloned() .unwrap_or(TokenType::Identifier(Box::new(lexeme))); */ - if let Some(&token_type) = KEYWORDS.get(&lexeme) { + if let Some(token_type) = KEYWORDS.get(&lexeme) { // Token::new(token_type, self.code_pos) - self.push_token(token_type); + self.push_token(token_type.clone()); } else { - self.tokens.push(Token::new_identifier(lexeme, self.code_pos)); + self.tokens + .push(Token::new_identifier(lexeme, self.code_pos)); } // Some(token_type) diff --git a/frontend/src/lexer/error.rs b/frontend/src/lexer/error.rs index 39279bd..1993732 100644 --- a/frontend/src/lexer/error.rs +++ b/frontend/src/lexer/error.rs @@ -4,13 +4,13 @@ use super::CodePos; #[derive(Error, Debug)] pub enum LexerError { - #[error("Unexpected character '{c}' at {code_pos}.")] + #[error("LexerError: Unexpected character '{c}' at {code_pos}.")] UnexpectedCharacter { c: char, code_pos: CodePos }, - #[error("Unterminated string literal starting at {code_pos}.")] + #[error("LexerError: Unterminated string literal starting at {code_pos}.")] UnterminatedStringLiteral { code_pos: CodePos }, - #[error("Unterminated block comment starting at {code_pos}.")] + #[error("LexerError: Unterminated block comment starting at {code_pos}.")] UnterminatedBlockComment { code_pos: CodePos }, - #[error("Invalid number literal {lexeme} at {code_pos}: {msg}")] + #[error("LexerError: Invalid number literal {lexeme} at {code_pos}: {msg}")] InvalidNumberLiteral { lexeme: String, msg: String, diff --git a/frontend/src/lexer/token.rs b/frontend/src/lexer/token.rs index 4005ccd..7d49ec7 100644 --- a/frontend/src/lexer/token.rs +++ b/frontend/src/lexer/token.rs @@ -1,10 +1,9 @@ use std::fmt::{Debug, Display}; -use std::mem::ManuallyDrop; use super::CodePos; #[repr(u8)] -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, PartialEq)] #[rustfmt::skip] pub enum TokenType { // Single-character tokens @@ -18,42 +17,20 @@ pub enum TokenType { Less, LessEqual, // Identifier and literals - Identifier, String, Number, + Identifier(Box), String(Box), Number(f64), // Keywords And, Break, Class, Else, False, Fun, For, If, Nil, Or, Print, Return, Super, This, True, Var, While, - #[allow(dead_code, clippy::upper_case_acronyms)] + Comment(Box), + + #[allow(clippy::upper_case_acronyms)] EOF } -union TokenData { - none: (), - #[allow(clippy::box_collection)] - s: ManuallyDrop>, - num: f64, -} - -impl TokenData { - fn none() -> Self { - TokenData { none: () } - } - - fn string(s: String) -> Self { - let s = ManuallyDrop::new(Box::new(s)); - TokenData { s } - } - - fn num(num: f64) -> Self { - TokenData { num } - } -} - pub struct Token { pub token_type: TokenType, - // pub lexeme: String, - data: TokenData, pub code_pos: CodePos, } @@ -61,95 +38,64 @@ impl Token { pub fn new(token_type: TokenType, code_pos: CodePos) -> Self { Token { token_type, - // lexeme, - data: TokenData::none(), code_pos, } } - pub fn new_string(s: String, code_pos: CodePos) -> Self { + pub fn new_string(s: impl Into>, code_pos: CodePos) -> Self { Token { - token_type: TokenType::String, - data: TokenData::string(s), + token_type: TokenType::String(s.into()), code_pos, } } - pub fn new_identifier(name: String, code_pos: CodePos) -> Self { + pub fn new_identifier(name: impl Into>, code_pos: CodePos) -> Self { Token { - token_type: TokenType::Identifier, - data: TokenData::string(name), + token_type: TokenType::Identifier(name.into()), code_pos, } } pub fn new_number(num: f64, code_pos: CodePos) -> Self { Token { - token_type: TokenType::Number, - data: TokenData::num(num), + token_type: TokenType::Number(num), code_pos, } } - pub fn string_data(self) -> String { - assert!(self.token_type == TokenType::String || self.token_type == TokenType::Identifier); + pub fn take(&mut self) -> Self { + let code_pos = self.code_pos; - // std::mem::take(&mut self.data.s) - unsafe { - let mut me = self; + use TokenType::*; - let s = std::mem::take(&mut me.data.s); + let token_type = match &mut self.token_type { + String(s) => String(std::mem::take(s)), + Identifier(name) => Identifier(std::mem::take(name)), + other => other.clone(), + }; - *ManuallyDrop::into_inner(s) + Token { + token_type, + code_pos, } } - - pub fn num_data(self) -> f64 { - assert_eq!(self.token_type, TokenType::Number); - - unsafe { self.data.num } - } } impl Debug for Token { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // write!(f, "<{:?}>", self.token_type) - match self.token_type { - TokenType::Number => unsafe { write!(f, "<{:?}({})>", self.token_type, self.data.num) }, - TokenType::String => unsafe { write!(f, "<{:?}({})>", self.token_type, self.data.s.as_ref()) }, - TokenType::Identifier => unsafe { write!(f, "<{:?}({})>", self.token_type, self.data.s.as_ref()) }, - _ => write!(f, "<{:?}>", self.token_type), - } + write!(f, "<{:?} {:?}> ", self.token_type, self.code_pos) } } impl Display for Token { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // write!(f, "<{:?}>", self.token_type) - match self.token_type { - TokenType::Number => unsafe { write!(f, "<{:?}({})>", self.token_type, self.data.num) }, - TokenType::String => unsafe { write!(f, "<{:?}({})>", self.token_type, self.data.s.as_ref()) }, - TokenType::Identifier => unsafe { write!(f, "<{:?}({})>", self.token_type, self.data.s.as_ref()) }, - _ => write!(f, "<{:?}>", self.token_type), + use TokenType::*; + + match &self.token_type { + String(s) => write!(f, "", s), + Identifier(name) => write!(f, "", name), + Number(x) => write!(f, "", x), + tt => write!(f, "<{:?}>", tt), } } } - -/* impl Clone for Token { - fn clone(&self) -> Self { - let code_pos = self.code_pos; - - match self.token_type { - TokenType::Number => Token::new_number(self.num_data(), code_pos), - TokenType::String => unsafe { Token::new_string(self.data.s.as_ref().clone(), code_pos) }, - TokenType::Identifier => unsafe { Token::new_identifier(self.data.s.as_ref().clone(), code_pos) }, - token_type => Token::new(token_type, code_pos), - } - } -} */ - -impl Drop for Token { - fn drop(&mut self) { - if self.token_type == TokenType::String {} - } -} diff --git a/frontend/src/parser/_parser.rs b/frontend/src/parser/_parser.rs index ce8f2db..8f4558c 100644 --- a/frontend/src/parser/_parser.rs +++ b/frontend/src/parser/_parser.rs @@ -1,5 +1,3 @@ -use std::vec::IntoIter; - use crate::lexer::{Token, TokenType}; use crate::parser::expr::BinaryOp; @@ -18,31 +16,39 @@ pub fn parse_tokens(tokens: Vec) -> Result, Vec> { // takes care of token iteration struct TokenIter { - token_iter: IntoIter, + tokens: Vec, - peek_token: Option, + pos: usize, } impl TokenIter { pub fn new(tokens: Vec) -> Self { - TokenIter { - token_iter: tokens.into_iter(), - peek_token: None, + TokenIter { tokens, pos: 0 } + } + + fn skip_comments(&mut self) { + while !self.is_empty() && matches![self.tokens[self.pos].token_type, TokenType::Comment(_)] + { + self.pos += 1; // skip comment token } } fn peek(&mut self) -> Option<&Token> { - // if peek_token is empty: fill with next token from token_iter - if self.peek_token.is_none() && self.token_iter.len() != 0 { - self.peek_token = self.token_iter.next(); + if self.is_empty() { + return None; } - self.peek_token.as_ref() + self.skip_comments(); + + let token = &self.tokens[self.pos]; + + assert!(!matches!(token.token_type, TokenType::Comment(_))); + + Some(token) } fn is_empty(&self) -> bool { - // peek_token is None and there are no more tokens to take from token_iter - self.peek_token.is_none() && self.token_iter.len() == 0 + self.pos == self.tokens.len() } } @@ -50,8 +56,16 @@ impl Iterator for TokenIter { type Item = Token; fn next(&mut self) -> Option { - // return the peeked token if any, or else next token from token_iter - self.peek_token.take().or_else(|| self.token_iter.next()) + self.skip_comments(); + + self.pos += 1; + + assert!(!matches!( + self.tokens[self.pos - 1].token_type, + TokenType::Comment(_) + )); + + Some(self.tokens[self.pos - 1].take()) } } @@ -101,7 +115,11 @@ impl Parser { } } - assert_eq!(me.next_token().token_type, TokenType::EOF); + assert_eq!( + me.next_token().token_type, + TokenType::EOF, + "last token wasn't EOF" + ); if !me.parse_errors.is_empty() { Err(me.parse_errors) @@ -122,10 +140,10 @@ impl Parser { self.is_in_function = false; self.is_in_init = false; - let peek_token = self.peek_token(); + let tt = &self.peek_token().token_type; // if we match a synchronisation point: return - match peek_token.token_type { + match tt { TokenType::Class | TokenType::Fun | TokenType::Var @@ -177,22 +195,12 @@ impl Parser { let code_pos = self.peek_token().code_pos; assert_eq!(self.next_token().token_type, TokenType::Return); - let expr = match self.peek_token().token_type { - TokenType::Semicolon => { - if !self.is_in_init { - Expr::nil() - } else { - Expr::Variable { - name: "this".to_owned(), - } - } - } - _ => { - if !self.is_in_init { - self.expression()? - } else { - return Err(ParserError::ReturnInInit { code_pos }); - } + let expr = match (self.is_in_init, &self.peek_token().token_type) { + (false, TokenType::Semicolon) => Expr::nil(), + (true, TokenType::Semicolon) => Expr::variable("this"), + (false, _) => self.expression()?, + (true, _) => { + return Err(ParserError::ReturnInInit { code_pos }); } }; @@ -208,14 +216,18 @@ impl Parser { fn if_statement(&mut self) -> ParserResult { assert_eq!(self.next_token().token_type, TokenType::If); - self.consume_token(TokenType::LeftParen, |token| ParserError::MissingParenAfterIf { - code_pos: token.code_pos, + self.consume_token(TokenType::LeftParen, |token| { + ParserError::MissingParenAfterIf { + code_pos: token.code_pos, + } })?; let condition = self.expression()?; - self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen { - code_pos: token.code_pos, + self.consume_token(TokenType::RightParen, |token| { + ParserError::MissingRightParen { + code_pos: token.code_pos, + } })?; let then_branch = self.statement()?; @@ -235,14 +247,18 @@ impl Parser { fn while_statement(&mut self) -> ParserResult { assert_eq!(self.next_token().token_type, TokenType::While); - self.consume_token(TokenType::LeftParen, |token| ParserError::MissingParenAfterWhile { - code_pos: token.code_pos, + self.consume_token(TokenType::LeftParen, |token| { + ParserError::MissingParenAfterWhile { + code_pos: token.code_pos, + } })?; let condition = self.expression()?; - self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen { - code_pos: token.code_pos, + self.consume_token(TokenType::RightParen, |token| { + ParserError::MissingRightParen { + code_pos: token.code_pos, + } })?; let is_in_loop = std::mem::replace(&mut self.is_in_loop, true); @@ -257,8 +273,10 @@ impl Parser { fn for_statement(&mut self) -> ParserResult { assert_eq!(self.next_token().token_type, TokenType::For); - self.consume_token(TokenType::LeftParen, |token| ParserError::MissingParenAfterFor { - code_pos: token.code_pos, + self.consume_token(TokenType::LeftParen, |token| { + ParserError::MissingParenAfterFor { + code_pos: token.code_pos, + } })?; let initializer = match self.peek_token().token_type { @@ -282,8 +300,10 @@ impl Parser { _ => Some(self.expression()?), }; - self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen { - code_pos: token.code_pos, + self.consume_token(TokenType::RightParen, |token| { + ParserError::MissingRightParen { + code_pos: token.code_pos, + } })?; let is_in_loop = std::mem::replace(&mut self.is_in_loop, true); @@ -326,7 +346,7 @@ impl Parser { let token = self.next_token(); let name = match token.token_type { - TokenType::Identifier => token.string_data(), + TokenType::Identifier(s) => s, _ => return Err(ParserError::ExpectedVarName { token }), }; @@ -354,13 +374,17 @@ impl Parser { let superclass_name = self.identifier("Expected superclass")?; - Some(Expr::Variable { name: superclass_name }) + Some(Expr::Variable { + name: superclass_name, + }) } else { None }; - self.consume_token(TokenType::LeftBrace, |token| ParserError::MissingClassBody { - code_pos: token.code_pos, + self.consume_token(TokenType::LeftBrace, |token| { + ParserError::MissingClassBody { + code_pos: token.code_pos, + } })?; let is_in_loop = std::mem::replace(&mut self.is_in_loop, false); @@ -381,7 +405,7 @@ impl Parser { })?; let is_in_init = self.is_in_init; - if method_name == "init" { + if &*method_name == "init" { self.is_in_init = true; } @@ -398,7 +422,7 @@ impl Parser { self.is_in_class = is_in_class; self.is_in_function = is_in_function; - let class = Expr::class(&name, methods, superclass); + let class = Expr::class(name.clone(), methods, superclass); Ok(Stmt::var_decl(name, class)) } @@ -451,7 +475,7 @@ impl Parser { Ok(Expr::function(name, param_names, body)) } - fn collect_params(&mut self) -> ParserResult> { + fn collect_params(&mut self) -> ParserResult>> { assert_eq!(self.next_token().token_type, TokenType::LeftParen); if self.peek_token().token_type == TokenType::RightParen { @@ -470,8 +494,10 @@ impl Parser { param_names.push(self.identifier("Expected parameter name")?); } - self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen { - code_pos: token.code_pos, + self.consume_token(TokenType::RightParen, |token| { + ParserError::MissingRightParen { + code_pos: token.code_pos, + } })?; Ok(param_names) @@ -532,7 +558,11 @@ impl Parser { Expr::Variable { name } => Ok(Expr::assignment(Expr::Variable { name }, value)), Expr::Get { target, name } => { let value = Box::new(value); - Ok(Expr::Set { target, name, value }) + Ok(Expr::Set { + target, + name, + value, + }) } _ => Err(ParserError::InvalidAssignment { expr, code_pos }), } @@ -720,8 +750,10 @@ impl Parser { args.push(self.expression()?); } - self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen { - code_pos: token.code_pos, + self.consume_token(TokenType::RightParen, |token| { + ParserError::MissingRightParen { + code_pos: token.code_pos, + } })?; Ok(args) @@ -736,52 +768,53 @@ impl Parser { match token.token_type { TokenType::Fun => Ok(self.fun_params_and_body("")?), - TokenType::Number => Ok(Expr::number(token.num_data())), - TokenType::String => Ok(Expr::string(token.string_data())), + TokenType::Number(x) => Ok(Expr::number(x)), + TokenType::String(s) => Ok(Expr::string(s)), TokenType::False => Ok(Expr::bool(false)), TokenType::True => Ok(Expr::bool(true)), TokenType::Nil => Ok(Expr::nil()), TokenType::This => Ok(Expr::This), TokenType::Super => { - self.consume_token(TokenType::Dot, |token| ParserError::MissingMethodAfterSuper { - code_pos: token.code_pos, + self.consume_token(TokenType::Dot, |token| { + ParserError::MissingMethodAfterSuper { + code_pos: token.code_pos, + } })?; let method = self.identifier("Expected method name after super")?; - let super_var = Box::new(Expr::Variable { - name: "super".to_owned(), - }); - let this_var = Box::new(Expr::This); - Ok(Expr::Super { - super_var, - this_var, - method, - }) + let super_var = Expr::variable("super"); + let this_var = Expr::This; + Ok(Expr::super_(super_var, this_var, method)) } TokenType::LeftParen => { let expr = self.expression()?; - self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen { - code_pos: token.code_pos, + self.consume_token(TokenType::RightParen, |token| { + ParserError::MissingRightParen { + code_pos: token.code_pos, + } })?; Ok(Expr::grouping(expr)) } - TokenType::Identifier => Ok(Expr::Variable { - name: token.string_data(), - }), + TokenType::Identifier(name) => Ok(Expr::Variable { name }), _ => Err(ParserError::ExpectedPrimary { token }), } } fn semicolon(&mut self) -> ParserResult<()> { - self.consume_token(TokenType::Semicolon, |token| ParserError::MissingSemicolon { - code_pos: token.code_pos, + self.consume_token(TokenType::Semicolon, |token| { + ParserError::MissingSemicolon { + code_pos: token.code_pos, + } }) } - fn identifier(&mut self, msg: &str) -> ParserResult { + fn identifier(&mut self, msg: &str) -> ParserResult> { match self.peek_token().token_type { - TokenType::Identifier => Ok(self.next_token().string_data()), + TokenType::Identifier(_) => match self.next_token().token_type { + TokenType::Identifier(s) => Ok(s), + _ => unreachable!(), + }, _ => Err(ParserError::MissingIdentifier { msg: msg.to_owned(), code_pos: self.peek_token().code_pos, @@ -813,7 +846,7 @@ impl Parser { fn consume_token(&mut self, token_type: TokenType, err_fn: F) -> ParserResult<()> where - F: Fn(Token) -> ParserError, + F: Fn(&Token) -> ParserError, { /* let token = self.next_token(); @@ -829,8 +862,8 @@ impl Parser { Ok(()) } // call err_fn with dummy token so we don't have to eat the EOF token - TokenType::EOF => Err(err_fn(Token::new(TokenType::EOF, self.peek_token().code_pos))), - _ => Err(err_fn(self.next_token())), + TokenType::EOF => Err(err_fn(self.peek_token())), + _ => Err(err_fn(&self.next_token())), } } } diff --git a/frontend/src/parser/error.rs b/frontend/src/parser/error.rs index 47216f1..a801790 100644 --- a/frontend/src/parser/error.rs +++ b/frontend/src/parser/error.rs @@ -6,44 +6,44 @@ use super::Expr; #[derive(Error, Debug)] pub enum ParserError { - #[error("Token stream ended unexpectedly.")] + #[error("ParserError: Token stream ended unexpectedly.")] TokenStreamEnded, - #[error("Expected a primary expression, but found a {token} token instead at {0}.", token.code_pos)] + #[error("ParserError: Expected a primary expression, but found a {token} token instead at {0}.", token.code_pos)] ExpectedPrimary { token: Token }, - #[error("Missing semicolon at {code_pos}")] + #[error("ParserError: Missing semicolon at {code_pos}")] MissingSemicolon { code_pos: CodePos }, - #[error("Expected variable name at {0}, got {token} instead", token.code_pos)] + #[error("ParserError: Expected variable name at {0}, got {token} instead", token.code_pos)] ExpectedVarName { token: Token }, - #[error("Can't assign to {expr} at {code_pos}")] + #[error("ParserError: Can't assign to {expr} at {code_pos}")] InvalidAssignment { expr: Expr, code_pos: CodePos }, - #[error("Missing closing curly brace at {code_pos}")] + #[error("ParserError: Missing closing curly brace at {code_pos}")] MissingRightBrace { code_pos: CodePos }, - #[error("Missing closing parenthesis at {code_pos}")] + #[error("ParserError: Missing closing parenthesis at {code_pos}")] MissingRightParen { code_pos: CodePos }, - #[error("Missing parenthesis after if at {code_pos}")] + #[error("ParserError: Missing parenthesis after if at {code_pos}")] MissingParenAfterIf { code_pos: CodePos }, - #[error("Missing parenthesis after while at {code_pos}")] + #[error("ParserError: Missing parenthesis after while at {code_pos}")] MissingParenAfterWhile { code_pos: CodePos }, - #[error("Missing parenthesis after for at {code_pos}")] + #[error("ParserError: Missing parenthesis after for at {code_pos}")] MissingParenAfterFor { code_pos: CodePos }, - #[error("Call at {code_pos} has too many arguments")] + #[error("ParserError: Call at {code_pos} has too many arguments")] TooManyArguments { code_pos: CodePos }, - #[error("{msg} at {code_pos}")] + #[error("ParserError: {msg} at {code_pos}")] MissingIdentifier { msg: String, code_pos: CodePos }, - #[error("Missing arguments to function declaration at {code_pos}")] + #[error("ParserError: Missing arguments to function declaration at {code_pos}")] MissingFunctionArgs { code_pos: CodePos }, - #[error("Missing body to function declaration at {code_pos}")] + #[error("ParserError: Missing body to function declaration at {code_pos}")] MissingFunctionBody { code_pos: CodePos }, - #[error("Function declaration at {code_pos} has too many parameters")] + #[error("ParserError: Function declaration at {code_pos} has too many parameters")] TooManyParams { code_pos: CodePos }, - #[error("Return statement outside of function definition")] + #[error("ParserError: Return statement outside of function definition")] ReturnOutsideFunction { code_pos: CodePos }, - #[error("Break statement outside of loop")] + #[error("ParserError: Break statement outside of loop")] InvalidBreak { code_pos: CodePos }, - #[error("Missing class body at {code_pos}")] + #[error("ParserError: Missing class body at {code_pos}")] MissingClassBody { code_pos: CodePos }, - #[error("Return statement in init")] + #[error("ParserError: Return statement in init")] ReturnInInit { code_pos: CodePos }, - #[error("Missing method name after super")] + #[error("ParserError: Missing method name after super")] MissingMethodAfterSuper { code_pos: CodePos }, } diff --git a/frontend/src/parser/expr.rs b/frontend/src/parser/expr.rs index 110b401..b8be8e4 100644 --- a/frontend/src/parser/expr.rs +++ b/frontend/src/parser/expr.rs @@ -1,5 +1,4 @@ use std::fmt::Display; -use std::rc::Rc; use itertools::Itertools; @@ -28,14 +27,14 @@ pub enum Expr { expr: Box, }, Variable { - name: String, + name: Box, }, LocalVariable { - name: String, + name: Box, level: usize, }, GlobalVariable { - name: String, + name: Box, }, Assignment { target: Box, @@ -47,37 +46,37 @@ pub enum Expr { }, Get { target: Box, - name: String, + name: Box, }, Set { target: Box, - name: String, + name: Box, value: Box, }, Function { - name: String, - param_names: Vec, - closure_vars: Vec<(String, usize)>, + name: Box, + param_names: Vec>, + closure_vars: Vec<(Box, usize)>, body: Box, }, Class { + name: Box, superclass: Option>, - name: String, methods: Box>, }, This, Super { super_var: Box, this_var: Box, - method: String, + method: Box, }, } impl Expr { - pub fn string(s: impl Into) -> Self { + pub fn string(s: impl Into>) -> Self { let s = s.into(); Expr::Literal { - literal: Literal::String(Rc::new(s)), + literal: Literal::String(s), } } @@ -94,7 +93,9 @@ impl Expr { } pub fn nil() -> Self { - Expr::Literal { literal: Literal::Nil } + Expr::Literal { + literal: Literal::Nil, + } } pub fn unary(op: UnaryOp, expr: Expr) -> Self { @@ -119,6 +120,21 @@ impl Expr { Expr::Grouping { expr } } + pub fn variable(name: impl Into>) -> Self { + let name = name.into(); + Expr::Variable { name } + } + + pub fn local_variable(name: impl Into>, level: usize) -> Self { + let name = name.into(); + Expr::LocalVariable { name, level } + } + + pub fn global_variable(name: impl Into>) -> Self { + let name = name.into(); + Expr::GlobalVariable { name } + } + pub fn assignment(target: Expr, value: Expr) -> Self { let target = Box::new(target); let value = Box::new(value); @@ -130,15 +146,14 @@ impl Expr { Expr::Call { callee, args } } - pub fn get(target: Expr, name: impl Into) -> Self { + pub fn get(target: Expr, name: impl Into>) -> Self { let target = Box::new(target); let name = name.into(); Expr::Get { target, name } } - pub fn function(name: String, param_names: Vec, body: Stmt) -> Self { - // let name = Box::new(name); - // let param_names = Box::new(param_names); + pub fn function(name: impl Into>, param_names: Vec>, body: Stmt) -> Self { + let name = name.into(); #[allow(clippy::box_default)] // let closure_vars = Box::new(Vec::new()); let closure_vars = Vec::new(); @@ -151,16 +166,33 @@ impl Expr { } } - pub fn class(name: impl Into, methods: Vec, superclass: Option) -> Self { + pub fn class(name: impl Into>, methods: Vec, superclass: Option) -> Self { let superclass = superclass.map(Box::new); let name = name.into(); let methods = Box::new(methods); + Expr::Class { - superclass, name, + superclass, methods, } } + + pub fn super_( + super_var: impl Into>, + this_var: impl Into>, + method: impl Into>, + ) -> Self { + let super_var = super_var.into(); + let this_var = this_var.into(); + let method = method.into(); + + Expr::Super { + super_var, + this_var, + method, + } + } } impl Display for Expr { @@ -174,12 +206,20 @@ impl Display for Expr { } Expr::Grouping { expr } => write!(f, "(group {expr})"), Expr::Variable { name } => write!(f, "(var {name})"), - Expr::LocalVariable { name, level } => write!(f, "(var {name} local({level}))"), - Expr::GlobalVariable { name } => write!(f, "(var {name} global)"), - Expr::Assignment { target, value } => write!(f, "{target} = {value}"), - Expr::Call { callee, args } => write!(f, "({callee} {})", args.iter().map(|arg| arg.to_string()).join(" ")), + Expr::LocalVariable { name, level } => write!(f, "(local {name} {level})"), + Expr::GlobalVariable { name } => write!(f, "(global {name})"), + Expr::Assignment { target, value } => write!(f, "(set {target} {value})"), + Expr::Call { callee, args } => write!( + f, + "({callee} {})", + args.iter().map(|arg| arg.to_string()).join(" ") + ), Expr::Get { target, name } => write!(f, "(get {name} {target})"), - Expr::Set { target, name, value } => write!(f, "(set {name} {target} {value})"), + Expr::Set { + target, + name, + value, + } => write!(f, "(set {name} {target} {value})"), Expr::Function { name, param_names, @@ -189,9 +229,13 @@ impl Display for Expr { if !closure_vars.is_empty() { let closure_fmt = closure_vars.iter().map(|(name, _level)| name).join(", "); - write!(f, "fun [{closure_fmt}] {name}({}) => {body}", param_names.join(", ")) + write!( + f, + "(fun [{closure_fmt}] {name} ({}) {body})", + param_names.join(", ") + ) } else { - write!(f, "fun {name}({}) => {body}", param_names.join(", ")) + write!(f, "(fun {name} ({}) {body})", param_names.join(", ")) } } Expr::Class { @@ -200,14 +244,14 @@ impl Display for Expr { methods, } => { if let Some(superclass) = superclass { - writeln!(f, "class {name} < {superclass} {{")?; + writeln!(f, "(class {name} < {superclass} ")?; } else { - writeln!(f, "class {name} {{")?; + writeln!(f, "(class {name} ")?; } for method in methods.iter() { writeln!(f, "{method}")?; } - write!(f, "}}") + write!(f, ")") } Expr::This => write!(f, "this"), Expr::Super { @@ -223,7 +267,7 @@ impl Display for Expr { #[derive(Debug, Clone)] pub enum Literal { - String(Rc), + String(Box), Number(f64), Bool(bool), Nil, diff --git a/frontend/src/parser/misc.rs b/frontend/src/parser/misc.rs index 1fd6fff..2b9dd7b 100644 --- a/frontend/src/parser/misc.rs +++ b/frontend/src/parser/misc.rs @@ -1,5 +1,5 @@ use itertools::Itertools; pub fn indent(s: String) -> String { - s.split('\n').map(|line| format!("\t{line}")).join("\n") + s.split('\n').map(|line| format!(" {line}")).join("\n") } diff --git a/frontend/src/parser/stmt.rs b/frontend/src/parser/stmt.rs index db0506a..57f6b06 100644 --- a/frontend/src/parser/stmt.rs +++ b/frontend/src/parser/stmt.rs @@ -18,7 +18,7 @@ pub enum Stmt { body: Box, }, VarDecl { - name: String, + name: Box, initializer: Box, }, Block { @@ -62,19 +62,23 @@ impl Stmt { Stmt::While { condition, body } } - pub fn var_decl(name: impl Into, initializer: impl Into>) -> Self { + pub fn var_decl(name: impl Into>, initializer: impl Into>) -> Self { let name = name.into(); + let initializer = initializer.into(); + Stmt::VarDecl { name, initializer } } pub fn expr_stmt(expr: impl Into>) -> Self { let expr = expr.into(); + Stmt::ExprStmt { expr } } pub fn return_stmt(expr: impl Into>) -> Self { let expr = expr.into(); + Stmt::Return { expr } } } @@ -82,7 +86,7 @@ impl Stmt { impl Display for Stmt { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Stmt::Print { expr } => write!(f, "(print {expr});"), + Stmt::Print { expr } => write!(f, "(print {expr})"), Stmt::IfStmt { condition, then_branch, @@ -110,18 +114,18 @@ impl Display for Stmt { } Ok(()) } - Stmt::VarDecl { name, initializer } => write!(f, "var {name} = {initializer};"), + Stmt::VarDecl { name, initializer } => write!(f, "(decl {name} {initializer})"), Stmt::Block { statements } => { - writeln!(f, "{{")?; + writeln!(f, "(block")?; for statement in statements { writeln!(f, "{}", indent(statement.to_string()))?; } - write!(f, "}}") + write!(f, ")") } Stmt::ExprStmt { expr } => write!(f, "{expr};"), - Stmt::Break => write!(f, "break;"), + Stmt::Break => write!(f, "(break)"), Stmt::Return { expr } => { - write!(f, "return {expr};") + write!(f, "(return {expr})") } } } diff --git a/interpreter/src/class.rs b/interpreter/src/class.rs index bb67dac..20cc1e7 100644 --- a/interpreter/src/class.rs +++ b/interpreter/src/class.rs @@ -10,7 +10,7 @@ use crate::{LoxFunction, LoxReference, Value}; pub struct LoxClass { superclass: Option>, - name: String, + name: Box, methods: FxHashMap, } @@ -18,7 +18,7 @@ pub struct LoxClass { /// Representation of a class in Lox. Always behind an Rc to ensure uniqueness. Should never be handled raw. impl LoxClass { pub fn new( - name: impl Into, + name: impl Into>, methods: FxHashMap, superclass: Option>, ) -> Rc { @@ -33,10 +33,7 @@ impl LoxClass { let mut body = init.body().clone(); if let Stmt::Block { ref mut statements } = body { - statements.push(Stmt::return_stmt(Expr::LocalVariable { - name: "this".to_owned(), - level: 1, - })); + statements.push(Stmt::return_stmt(Expr::local_variable("this", 1))); } else { panic!("Body of init method of class {name} wasn't a block"); } @@ -130,7 +127,12 @@ impl LoxClass { impl Display for LoxClass { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "", self.name, (self as *const LoxClass) as usize) + write!( + f, + "", + self.name, + (self as *const LoxClass) as usize + ) } } diff --git a/interpreter/src/environment.rs b/interpreter/src/environment.rs index 339f44e..1ba4947 100644 --- a/interpreter/src/environment.rs +++ b/interpreter/src/environment.rs @@ -8,12 +8,11 @@ use crate::error::RuntimeError; use super::value::HeapedValue; use super::{Runtime, Value}; -pub type Scope = FxHashMap; +pub type Scope = FxHashMap, HeapedValue>; #[derive(Debug)] pub struct Environment<'a> { scope_stack: Vec, - scope_top: usize, runtime: &'a mut Runtime, @@ -24,7 +23,6 @@ impl<'a> Environment<'a> { pub fn new(runtime: &'a mut Runtime) -> Self { Environment { scope_stack: Vec::new(), - scope_top: 0, runtime, @@ -32,6 +30,10 @@ impl<'a> Environment<'a> { } } + pub fn runtime(&mut self) -> &mut Runtime { + self.runtime + } + pub fn push_arg(&mut self, arg: Value) { self.arg_stack.push(arg); } @@ -44,16 +46,16 @@ impl<'a> Environment<'a> { std::mem::take(&mut self.arg_stack) } - pub fn globals(&self) -> &FxHashMap { + pub fn globals(&self) -> &FxHashMap, Value> { self.runtime.globals() } pub fn scopes(&self) -> &[Scope] { - &self.scope_stack[..self.scope_top] + &self.scope_stack } pub fn scopes_mut(&mut self) -> &mut [Scope] { - &mut self.scope_stack[..self.scope_top] + &mut self.scope_stack } pub fn has_scope(&self) -> bool { @@ -61,30 +63,24 @@ impl<'a> Environment<'a> { } pub fn current_scope(&self) -> &Scope { - &self.scope_stack[self.scope_top - 1] + self.scope_stack.last().unwrap() } pub fn current_scope_mut(&mut self) -> &mut Scope { - &mut self.scope_stack[self.scope_top - 1] + self.scope_stack.last_mut().unwrap() } pub fn enter_scope(&mut self) { // self.current_frame_mut().enter_scope(); // self.local_scopes.push(Scope::new()); - if self.scope_top == self.scope_stack.len() { - self.scope_stack.push(Scope::default()); - } else { - self.scope_stack[self.scope_top].clear(); - } - - self.scope_top += 1; + self.scope_stack.push(Scope::default()); } pub fn exit_scope(&mut self) { // self.current_frame_mut().exit_scope(); // self.local_scopes.pop().expect("Tried to pop global scope"); - self.scope_top -= 1; + self.scope_stack.pop(); } pub fn insert_closure(&mut self, closure: Scope) { @@ -108,14 +104,17 @@ impl<'a> Environment<'a> { } } - Err(RuntimeError::NameNotDefined { name: name.to_owned() }) + Err(RuntimeError::NameNotDefined { + name: name.to_owned(), + }) // self.runtime.get_global(name) } - pub fn define(&mut self, name: impl Into, value: Value) { + pub fn define(&mut self, name: impl Into>, value: Value) { if self.has_scope() { let name = name.into(); - self.current_scope_mut().insert(name, HeapedValue::new(value)); + self.current_scope_mut() + .insert(name, HeapedValue::new(value)); } else { self.runtime.define_global(name, value) } @@ -133,7 +132,9 @@ impl<'a> Environment<'a> { } } - Err(RuntimeError::NameNotDefined { name: name.to_owned() }) + Err(RuntimeError::NameNotDefined { + name: name.to_owned(), + }) // self.runtime.assign_global(name, value) } @@ -145,12 +146,12 @@ impl<'a> Environment<'a> { self.frames.pop().expect("Tried to pop global frame"); } */ - pub fn collect_closure(&self, closure_vars: &[(String, usize)]) -> Scope { + pub fn collect_closure(&self, closure_vars: &[(Box, usize)]) -> Scope { let mut closure_scope = Scope::default(); for (name, level) in closure_vars { // special injected variables - if name == "this" || name == "super" { + if &**name == "this" || &**name == "super" { continue; } @@ -181,7 +182,7 @@ impl Display for Environment<'_> { write!(f, "\nScope {level}:")?; for (name, value) in scope.iter() { - write!(f, "\n\t{name} = {value}")?; + write!(f, "\n\t{name} = {}", value.as_ref())?; } } diff --git a/interpreter/src/error.rs b/interpreter/src/error.rs index 1467393..bef079c 100644 --- a/interpreter/src/error.rs +++ b/interpreter/src/error.rs @@ -10,35 +10,43 @@ use crate::{LoxClass, ResolverError}; #[derive(Error, Debug)] pub enum RuntimeError { - #[error("Unary operator {op} had invalid argument {arg}")] + #[error("RuntimeError: Unary operator {op} had invalid argument {arg}")] UnaryOpInvalidArgument { op: UnaryOp, arg: Value }, - #[error("Binary operator {op} had invalid arguments {left} and {right}")] - BinaryOpInvalidArguments { left: Value, op: BinaryOp, right: Value }, - #[error("Division by zero")] + #[error("RuntimeError: Binary operator {op} had invalid arguments {left} and {right}")] + BinaryOpInvalidArguments { + left: Value, + op: BinaryOp, + right: Value, + }, + #[error("RuntimeError: Division by zero")] DivisionByZero, - #[error("Local {name} is not defined")] + #[error("RuntimeError: Local {name} is not defined")] NameNotDefined { name: String }, - #[error("Global {name} is not defined")] + #[error("RuntimeError: Global {name} is not defined")] GlobalNotDefined { name: String }, - #[error("{callee} is not callable")] + #[error("RuntimeError: {callee} is not callable")] NotCallable { callee: Value }, - #[error("{name}() takes {arity} args, but {given} were given.")] - WrongArity { name: String, arity: usize, given: usize }, - #[error("Extern function call to {name} failed: {msg}")] + #[error("RuntimeError: {name}() takes {arity} args, but {given} were given.")] + WrongArity { + name: String, + arity: usize, + given: usize, + }, + #[error("RuntimeError: Extern function call to {name} failed: {msg}")] ExtFunCallFailed { name: String, msg: String }, - #[error("Uncaught break statement")] + #[error("RuntimeError: Uncaught break statement")] Break, - #[error("Uncaught return statement")] + #[error("RuntimeError: Uncaught return statement")] Return { value: Value }, - #[error("Exit with exit code {exit_code}")] + #[error("RuntimeError: Exit with exit code {exit_code}")] Exit { exit_code: i32 }, - #[error("Only objects have attributes")] + #[error("RuntimeError: Only objects have attributes")] InvalidGetTarget, - #[error("Only objects have attributes")] + #[error("RuntimeError: Only objects have attributes")] InvalidSetTarget, - #[error("Class {0} has no property {name}", class.name())] - UndefinedAttribute { class: Rc, name: String }, - #[error("{value} is not a valid superclass")] + #[error("RuntimeError: Class {0} has no property {name}", class.name())] + UndefinedAttribute { class: Rc, name: Box }, + #[error("RuntimeError: {value} is not a valid superclass")] InvalidSuperclass { value: Value }, } @@ -57,7 +65,7 @@ pub enum LoxError { Exit { exit_code: i32 }, } -fn format_multiple_errors(errs: &Vec) -> String { +fn format_multiple_errors(errs: &[impl std::error::Error]) -> String { let msg = if errs.len() == 1 { errs[0].to_string() } else { @@ -81,7 +89,9 @@ impl From> for LoxError { impl From for LoxError { fn from(resolver_err: ResolverError) -> Self { - LoxError::ResolverError { inner: resolver_err } + LoxError::ResolverError { + inner: resolver_err, + } } } diff --git a/interpreter/src/function.rs b/interpreter/src/function.rs index 6aebe57..5f0f0c0 100644 --- a/interpreter/src/function.rs +++ b/interpreter/src/function.rs @@ -11,14 +11,19 @@ use super::{Runtime, Value}; #[derive(Debug, Clone)] pub struct LoxFunction { - name: String, + name: Box, closure: Scope, - param_names: Vec, + param_names: Vec>, body: Box, } impl LoxFunction { - pub fn new(name: impl Into, closure: Scope, param_names: Vec, body: Stmt) -> Rc { + pub fn new( + name: impl Into>, + closure: Scope, + param_names: Vec>, + body: Stmt, + ) -> Rc { let name = name.into(); let body = Box::new(body); let fun = LoxFunction { @@ -38,7 +43,7 @@ impl LoxFunction { &self.closure } - pub fn param_names(&self) -> &[String] { + pub fn param_names(&self) -> &[Box] { &self.param_names } @@ -50,7 +55,7 @@ impl LoxFunction { self.param_names().len() } - pub fn inject_closed_var(&mut self, name: impl Into, value: Value) { + pub fn inject_closed_var(&mut self, name: impl Into>, value: Value) { let name = name.into(); let heaped_value = HeapedValue::new(value); self.closure.insert(name, heaped_value); @@ -88,7 +93,11 @@ impl LoxExternFunction { pub fn new(name: impl Into, arity: usize, closure: ExternFunClosure) -> Self { let name = name.into(); - LoxExternFunction { name, arity, closure } + LoxExternFunction { + name, + arity, + closure, + } } pub fn name(&self) -> &str { diff --git a/interpreter/src/interpret.rs b/interpreter/src/interpret.rs index d12ead7..264067b 100644 --- a/interpreter/src/interpret.rs +++ b/interpreter/src/interpret.rs @@ -31,7 +31,7 @@ trait Eval { impl Eval for Literal { fn eval(&self, _env: &mut Environment) -> EvalResult { match self { - Literal::String(s) => Ok(Value::String(Rc::clone(s))), + Literal::String(s) => Ok(Value::String(s.clone())), Literal::Number(num) => Ok(Value::Number(*num)), Literal::Bool(b) => Ok(Value::Bool(*b)), Literal::Nil => Ok(Value::Nil), @@ -83,10 +83,10 @@ impl Eval for Expr { }, (String(left), String(right)) => match op { BinaryOp::Add => { - let mut s = std::string::String::with_capacity(left.capacity() + right.capacity()); - s += &left; - s += &right; - Ok(String(Rc::new(s))) + let s: Box = + itertools::chain(left.as_ref().chars(), right.chars()).collect(); + + Ok(Value::string(s)) } BinaryOp::Less => Ok(Bool(left < right)), BinaryOp::LessEqual => Ok(Bool(left <= right)), @@ -99,14 +99,18 @@ impl Eval for Expr { right: String(right), }), }, - (left, right) => Err(RuntimeError::BinaryOpInvalidArguments { left, op, right }), + (left, right) => { + Err(RuntimeError::BinaryOpInvalidArguments { left, op, right }) + } } } Expr::Logical { left, op, right } => { let left = left.eval(env)?; // shortcircuit - if *op == LogicalOp::Or && left.is_truthy() || *op == LogicalOp::And && !left.is_truthy() { + if *op == LogicalOp::Or && left.is_truthy() + || *op == LogicalOp::And && !left.is_truthy() + { return Ok(left); } @@ -121,7 +125,9 @@ impl Eval for Expr { let value = value.eval(env)?; match target.as_ref() { - Expr::LocalVariable { name, level } => env.assign(name, value.clone(), *level)?, + Expr::LocalVariable { name, level } => { + env.assign(name, value.clone(), *level)? + } Expr::GlobalVariable { name } => env.assign_global(name, value.clone())?, _ => panic!("Invalid assigment target {target}"), } @@ -159,12 +165,16 @@ impl Eval for Expr { Err(RuntimeError::InvalidGetTarget) } } - Expr::Set { target, name, value } => { + Expr::Set { + target, + name, + value, + } => { let target = target.eval(env)?; if let Value::Object(mut object) = target { let value = value.eval(env)?; - object.set(name, value); + object.set(name.clone(), value); Ok(Value::Nil) } else { Err(RuntimeError::InvalidSetTarget) @@ -176,7 +186,7 @@ impl Eval for Expr { closure_vars, body, } => Ok(Value::function(LoxFunction::new( - name, + name.clone(), env.collect_closure(closure_vars), param_names.clone(), body.as_ref().clone(), @@ -208,7 +218,11 @@ impl Eval for Expr { env.exit_scope(); - Ok(Value::class(LoxClass::new(name, methods, superclass))) + Ok(Value::class(LoxClass::new( + name.clone(), + methods, + superclass, + ))) } Expr::This => panic!("Unresolved this"), Expr::Super { @@ -223,7 +237,9 @@ impl Eval for Expr { Err(RuntimeError::InvalidGetTarget) } } - (super_val, this_val) => panic!("super evaluated to {super_val} and this evaluated to {this_val}"), + (super_val, this_val) => { + panic!("super evaluated to {super_val} and this evaluated to {this_val}") + } }, } } @@ -233,11 +249,10 @@ impl Eval for Stmt { fn eval(&self, env: &mut Environment) -> EvalResult { match self { Stmt::Print { expr } => { - match expr.eval(env)? { - // special case: when printing a string, drop the surrounding "" - Value::String(s) => println!("{s}"), - val => println!("{val}"), - } + use std::io::Write; + + let val = expr.eval(env)?; + writeln!(env.runtime(), "{val}").unwrap(); } Stmt::IfStmt { condition, @@ -262,7 +277,7 @@ impl Eval for Stmt { } Stmt::VarDecl { name, initializer } => { let initializer = initializer.eval(env)?; - env.define(name, initializer); + env.define(name.clone(), initializer); } Stmt::Block { statements } => { env.enter_scope(); @@ -310,7 +325,7 @@ pub fn call_fun(fun: Rc, env: &mut Environment) -> EvalResult LoxExternFunction { fn print_globals() -> LoxExternFunction { let closure: ExternFunClosure = |args, env| { assert_eq!(args.len(), 0); - let mut globals: Vec<(&String, &Value)> = env.globals().iter().collect(); + let mut globals: Vec<(&Box, &Value)> = env.globals().iter().collect(); globals.sort_by_key(|&(name, _value)| name); diff --git a/interpreter/src/object.rs b/interpreter/src/object.rs index 5148221..d857658 100644 --- a/interpreter/src/object.rs +++ b/interpreter/src/object.rs @@ -12,7 +12,7 @@ use crate::{LoxClass, Value}; struct LoxObject { class: Rc, - attrs: FxHashMap, + attrs: FxHashMap, Value>, } impl LoxObject { @@ -35,7 +35,7 @@ impl LoxObject { self.class.get_method(name, this) } - fn set(&mut self, name: impl Into, value: Value) { + fn set(&mut self, name: impl Into>, value: Value) { let name = name.into(); self.attrs.insert(name, value); } @@ -75,7 +75,7 @@ impl LoxReference { } } - pub fn set(&mut self, name: impl Into, value: Value) { + pub fn set(&mut self, name: impl Into>, value: Value) { unsafe { let ptr = self.inner.get(); let object = &mut *ptr; @@ -99,7 +99,12 @@ impl Display for LoxReference { unsafe { let ptr = self.inner.get(); let object = &*ptr; - write!(f, "<{} object at {:#X}>", object.class().name(), ptr as usize) + write!( + f, + "<{} object at {:#X}>", + object.class().name(), + ptr as usize + ) } } } diff --git a/interpreter/src/resolver/_resolver.rs b/interpreter/src/resolver/_resolver.rs index d1e74ac..48c98f8 100644 --- a/interpreter/src/resolver/_resolver.rs +++ b/interpreter/src/resolver/_resolver.rs @@ -6,7 +6,7 @@ use crate::{LoxError, ResolverError}; /*====================================================================================================================*/ -type ResolverScope = FxHashMap; +type ResolverScope = FxHashMap, ResolveStatus>; type ResolverFrame = Vec; /*====================================================================================================================*/ @@ -35,11 +35,11 @@ struct Resolver { // local_scopes: Vec, frames: Vec, - closure_vars: FxHashMap, + closure_vars: FxHashMap, usize>, } impl Resolver { - fn new(global_names: impl Iterator) -> Self { + fn new(global_names: impl Iterator>) -> Self { let mut global_scope = ResolverScope::default(); for name in global_names { @@ -76,11 +76,14 @@ impl Resolver { } fn pop_frame(&mut self) { - self.frames.pop().expect("Tried to pop non-existant ResolverFrame"); + self.frames + .pop() + .expect("Tried to pop non-existant ResolverFrame"); } - fn declare(&mut self, name: &str) { - let name = name.to_owned(); + fn declare(&mut self, name: impl Into>) { + let name = name.into(); + if let Some(local_scope) = self.local_scopes_mut().last_mut() { local_scope.insert(name, ResolveStatus::Declared); } else { @@ -88,8 +91,9 @@ impl Resolver { } } - fn define(&mut self, name: &str) { - let name = name.to_owned(); + fn define(&mut self, name: impl Into>) { + let name = name.into(); + if let Some(local_scope) = self.local_scopes_mut().last_mut() { local_scope.insert(name, ResolveStatus::Defined); } else { @@ -106,38 +110,36 @@ impl Resolver { } fn resolve_var(&mut self, name: &str) -> Result { - let name = name.to_owned(); - let mut level = 0; for scope in self.local_scopes().iter().rev() { - if scope.contains_key(&name) { - return Ok(Expr::LocalVariable { name, level }); + if scope.contains_key(name) { + return Ok(Expr::local_variable(name, level)); } level += 1; } for frame in self.frames.iter().rev().skip(1) { for scope in frame.iter().rev() { - if scope.contains_key(&name) { - if !self.closure_vars.contains_key(&name) { + if scope.contains_key(name) { + if !self.closure_vars.contains_key(name) { // the level at which the closed-over variable will be collected from // from the perspective of the parameter/closure scope i.e. the outmost of the function self.closure_vars - .insert(name.clone(), level - self.local_scopes().len()); + .insert(name.into(), level - self.local_scopes().len()); } - return Ok(Expr::LocalVariable { - name, - // distance from actual variable refernce to parameter/closure scope - level: self.local_scopes().len() - 1, - }); + + // distance from actual variable refernce to parameter/closure scope + let level = self.local_scopes().len() - 1; + + return Ok(Expr::local_variable(name, level)); } level += 1; } } - if self.global_scope.contains_key(&name) { - return Ok(Expr::GlobalVariable { name }); + if self.global_scope.contains_key(name) { + return Ok(Expr::global_variable(name)); } if name == "this" { @@ -145,6 +147,7 @@ impl Resolver { } else if name == "super" { Err(ResolverError::SuperOutsideMethod) } else { + let name = name.into(); Err(ResolverError::UnresolvableVariable { name }) } } @@ -170,9 +173,9 @@ impl Resolver { Ok(()) } Stmt::VarDecl { name, initializer } => { - self.declare(name); + self.declare(name.clone()); self.resolve_expr(initializer)?; - self.define(name); + self.define(name.clone()); Ok(()) } Stmt::Block { statements } => { @@ -244,7 +247,11 @@ impl Resolver { self.resolve_expr(target)?; Ok(()) } - Expr::Set { target, name: _, value } => { + Expr::Set { + target, + name: _, + value, + } => { self.resolve_expr(target)?; self.resolve_expr(value)?; Ok(()) @@ -259,12 +266,12 @@ impl Resolver { self.push_frame(); - self.declare(name); - self.define(name); + self.declare(name.clone()); + self.define(name.clone()); for param_name in param_names.iter() { - self.declare(param_name); - self.define(param_name); + self.declare(param_name.clone()); + self.define(param_name.clone()); } self.resolve_stmt(body)?; @@ -284,13 +291,13 @@ impl Resolver { name, methods, } => { - self.declare(name); + self.declare(name.clone()); if let Some(superclass) = superclass { self.resolve_expr(superclass)?; } - self.define(name); + self.define(name.clone()); // this is the scope "this" is defined in self.enter_scope(); diff --git a/interpreter/src/resolver/error.rs b/interpreter/src/resolver/error.rs index 7fdd17a..4516490 100644 --- a/interpreter/src/resolver/error.rs +++ b/interpreter/src/resolver/error.rs @@ -3,9 +3,9 @@ use thiserror::Error; #[derive(Error, Debug)] pub enum ResolverError { #[error("Can't read variable {name} in its own initializer.")] - VarInOwnInitializer { name: String }, + VarInOwnInitializer { name: Box }, #[error("Variable {name} not defined")] - UnresolvableVariable { name: String }, + UnresolvableVariable { name: Box }, #[error("Return outside of function definition")] ReturnOutsideFunction, #[error("this outside of method")] diff --git a/interpreter/src/run.rs b/interpreter/src/run.rs index 5397de3..a58c5a0 100644 --- a/interpreter/src/run.rs +++ b/interpreter/src/run.rs @@ -24,9 +24,12 @@ pub fn run_repl(runtime: &mut Runtime) { std::process::exit(66); }); - let num_open_braces = (input_buf.matches('{').count() as i64) - (input_buf.matches('}').count() as i64); - let num_open_parens = (input_buf.matches('(').count() as i64) - (input_buf.matches(')').count() as i64); - let num_open_brackets = (input_buf.matches('[').count() as i64) - (input_buf.matches(']').count() as i64); + let num_open_braces = + (input_buf.matches('{').count() as i64) - (input_buf.matches('}').count() as i64); + let num_open_parens = + (input_buf.matches('(').count() as i64) - (input_buf.matches(')').count() as i64); + let num_open_brackets = + (input_buf.matches('[').count() as i64) - (input_buf.matches(']').count() as i64); // all braces/parens/brackets closed => break if num_open_braces == 0 && num_open_parens == 0 && num_open_brackets == 0 { @@ -47,12 +50,12 @@ pub fn run_repl(runtime: &mut Runtime) { std::io::stdout().flush().unwrap(); } - let input_buf = input_buf.trim(); - - if input_buf.is_empty() || input_buf == "exit" || input_buf == "quit" { + if input_buf.is_empty() || input_buf == "exit\n" || input_buf == "quit\n" { std::process::exit(0); } + let input_buf = input_buf.trim(); + match run(input_buf, runtime) { Ok(()) => {} Err(LoxError::Exit { exit_code }) => std::process::exit(exit_code), @@ -64,20 +67,25 @@ pub fn run_repl(runtime: &mut Runtime) { pub fn run(source: &str, runtime: &mut Runtime) -> Result<(), LoxError> { let tokens: Vec = scan_tokens(source)?; - let token_str = itertools::Itertools::join(&mut tokens.iter().map(|token| token.to_string()), " "); + if runtime.debug() { + let token_str = + itertools::Itertools::join(&mut tokens.iter().map(|token| token.to_string()), " "); - println!("{token_str}"); + println!("{token_str}"); + } let statements = parse_tokens(tokens)?; - /* for statement in statements.iter() { - println!("{statement}"); - } */ - for mut statement in statements { + if runtime.debug() { + println!("{statement}"); + } + resolve(&mut statement, runtime)?; - // println!("{statement}"); + if runtime.debug() { + println!("{statement}"); + } execute(statement, runtime)?; } diff --git a/interpreter/src/runtime.rs b/interpreter/src/runtime.rs index 73a0dd0..baff0b0 100644 --- a/interpreter/src/runtime.rs +++ b/interpreter/src/runtime.rs @@ -1,5 +1,7 @@ +use std::cell::RefCell; use std::fmt::Display; use std::io::{stdin, stdout, Read, Write}; +use std::rc::Rc; use rustc_hash::FxHashMap; @@ -9,19 +11,24 @@ use super::lox_std::init_std; use super::Value; pub struct Runtime { - globals: FxHashMap, + globals: FxHashMap, Value>, - in_stream: Box, - out_stream: Box, + in_stream: Rc>, + out_stream: Rc>, + + debug: bool, } impl Runtime { - pub fn new(in_stream: Box, out_stream: Box) -> Self { - let in_stream = Box::new(std::io::BufReader::new(in_stream)); + pub fn new( + in_stream: Rc>, + out_stream: Rc>, + ) -> Self { let mut runtime = Runtime { globals: FxHashMap::default(), in_stream, out_stream, + debug: false, }; init_std(&mut runtime); @@ -29,7 +36,24 @@ impl Runtime { runtime } - pub fn globals(&self) -> &FxHashMap { + pub fn set_debug(&mut self, debug: bool) { + self.debug = debug; + } + + pub fn debug(&self) -> bool { + self.debug + } + + pub fn in_stream(&mut self) -> std::cell::RefMut { + self.in_stream.as_ref().borrow_mut() + } + + pub fn out_stream(&mut self) -> std::cell::RefMut { + // &mut self.out_stream + self.out_stream.as_ref().borrow_mut() + } + + pub fn globals(&self) -> &FxHashMap, Value> { &self.globals } @@ -37,10 +61,12 @@ impl Runtime { self.globals .get(name) .cloned() - .ok_or_else(|| RuntimeError::GlobalNotDefined { name: name.to_owned() }) + .ok_or_else(|| RuntimeError::GlobalNotDefined { + name: name.to_owned(), + }) } - pub fn define_global(&mut self, name: impl Into, value: Value) { + pub fn define_global(&mut self, name: impl Into>, value: Value) { let name = name.into(); self.globals.insert(name, value); } @@ -50,20 +76,30 @@ impl Runtime { *old_value = value; Ok(()) } else { - Err(RuntimeError::GlobalNotDefined { name: name.to_owned() }) + Err(RuntimeError::GlobalNotDefined { + name: name.to_owned(), + }) } } } impl Default for Runtime { fn default() -> Self { - Runtime::new(Box::new(std::io::BufReader::new(stdin())), Box::new(stdout())) + // let buf_reader = std::io::BufReader::new(stdin()); + // let buf_reader_boxed = Box::new(&mut buf_reader); + + let in_stream = Rc::new(RefCell::new(stdin())); + let out_stream = Rc::new(RefCell::new(stdout())); + + Runtime::new(in_stream, out_stream) } } impl std::fmt::Debug for Runtime { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Runtime").field("globals", &self.globals).finish() + f.debug_struct("Runtime") + .field("globals", &self.globals) + .finish() } } @@ -81,22 +117,22 @@ impl Display for Runtime { impl Drop for Runtime { fn drop(&mut self) { - self.out_stream.flush().unwrap(); + self.out_stream().flush().unwrap(); } } impl Read for Runtime { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { - self.in_stream.read(buf) + self.in_stream().read(buf) } } impl Write for Runtime { fn write(&mut self, buf: &[u8]) -> std::io::Result { - self.out_stream.write(buf) + self.out_stream().write(buf) } fn flush(&mut self) -> std::io::Result<()> { - self.out_stream.flush() + self.out_stream().flush() } } diff --git a/interpreter/src/value.rs b/interpreter/src/value.rs index 0e75b25..3f550b1 100644 --- a/interpreter/src/value.rs +++ b/interpreter/src/value.rs @@ -13,11 +13,12 @@ pub enum Value { Class(Rc), Function(Rc), ExternFunction(Rc), - String(Rc), + String(Box), Number(f64), Bool(bool), Nil, } + impl Value { pub fn class(class: Rc) -> Self { Value::Class(class) @@ -33,8 +34,8 @@ impl Value { Value::ExternFunction(fun) } - pub fn string(s: impl Into) -> Self { - let s = Rc::new(s.into()); + pub fn string(s: impl Into>) -> Self { + let s = s.into(); Value::String(s) } @@ -50,7 +51,7 @@ impl Display for Value { Value::Class(class) => write!(f, "{class}"), Value::Function(fun) => write!(f, "{fun}"), Value::ExternFunction(ext_fun) => write!(f, "{ext_fun}"), - Value::String(s) => write!(f, "\"{s}\""), + Value::String(s) => write!(f, "{s}"), Value::Number(num) => write!(f, "{num}"), Value::Bool(b) => write!(f, "{b}"), Value::Nil => write!(f, "nil"), @@ -60,7 +61,7 @@ impl Display for Value { /*====================================================================================================================*/ -#[derive(Clone)] +#[derive(Debug, Clone)] pub struct HeapedValue { inner: Rc>, } @@ -88,14 +89,11 @@ impl HeapedValue { } } -impl Debug for HeapedValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("HeapValue").field("inner", &self.get_clone()).finish() - } -} - -impl Display for HeapedValue { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.get_clone()) +impl AsRef for HeapedValue { + fn as_ref(&self) -> &Value { + unsafe { + let ptr = self.inner.get(); + &*ptr + } } } diff --git a/src/main.rs b/src/main.rs index 1c6782b..f81f1e0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,9 @@ struct CliArgs { #[arg(long, action = ArgAction::SetTrue)] vm: bool, + + #[arg(long, action=ArgAction::SetTrue)] + debug: bool, } /* @@ -22,7 +25,8 @@ fn main() { let cli_args = CliArgs::parse(); if cli_args.vm { - use rlox2_vm::LoxError; + unimplemented!() + /* use rlox2_vm::LoxError; let mut vm = rlox2_vm::VM::default(); @@ -35,7 +39,9 @@ fn main() { if let Err(err) = rlox2_vm::run(&source, &mut vm) { eprintln!("{err}"); match err { - LoxError::LexerError { .. } | LoxError::CompileError { .. } => std::process::exit(65), + LoxError::LexerError { .. } | LoxError::CompileError { .. } => { + std::process::exit(65) + } LoxError::RuntimeError { .. } => std::process::exit(70), LoxError::Exit { exit_code } => std::process::exit(exit_code), } @@ -46,12 +52,14 @@ fn main() { } } - rlox2_vm::run_repl(&mut vm); + rlox2_vm::run_repl(&mut vm); */ } else { use rlox2_interpreter::LoxError; let mut runtime = rlox2_interpreter::Runtime::default(); + runtime.set_debug(cli_args.debug); + if let Some(file_name) = cli_args.file_name { let source = std::fs::read_to_string(&file_name).unwrap_or_else(|err| { eprintln!("Reading script file {file_name} failed: {err}"); @@ -61,9 +69,9 @@ fn main() { if let Err(err) = rlox2_interpreter::run(&source, &mut runtime) { eprintln!("{err}"); match err { - LoxError::LexerError { .. } | LoxError::ParserError { .. } | LoxError::ResolverError { .. } => { - std::process::exit(65) - } + LoxError::LexerError { .. } + | LoxError::ParserError { .. } + | LoxError::ResolverError { .. } => std::process::exit(65), LoxError::RuntimeError { .. } => std::process::exit(70), LoxError::Exit { exit_code } => std::process::exit(exit_code), }