updated a bunch of stuff

This commit is contained in:
Moritz Gmeiner 2024-09-01 19:16:30 +02:00
commit 67bb5fe8fd
24 changed files with 683 additions and 702 deletions

428
Cargo.lock generated
View file

@ -3,55 +3,83 @@
version = 3 version = 3
[[package]] [[package]]
name = "aho-corasick" name = "anstream"
version = "0.7.20" version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
dependencies = [ dependencies = [
"memchr", "anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is_terminal_polyfill",
"utf8parse",
] ]
[[package]] [[package]]
name = "autocfg" name = "anstyle"
version = "1.1.0" version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
[[package]] [[package]]
name = "bitflags" name = "anstyle-parse"
version = "1.3.2" version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
dependencies = [
"utf8parse",
]
[[package]] [[package]]
name = "cc" name = "anstyle-query"
version = "1.0.78" version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "clap" name = "clap"
version = "4.1.4" version = "4.5.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
dependencies = [ dependencies = [
"bitflags", "clap_builder",
"clap_derive", "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", "clap_lex",
"is-terminal",
"once_cell",
"strsim", "strsim",
"termcolor",
] ]
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.1.0" version = "4.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
@ -59,147 +87,54 @@ dependencies = [
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.3.1" version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
dependencies = [
"os_str_bytes", [[package]]
] name = "colorchoice"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
[[package]] [[package]]
name = "either" name = "either"
version = "1.8.1" version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]] [[package]]
name = "errno" name = "glob"
version = "0.2.8" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
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",
]
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "hermit-abi" name = "is_terminal_polyfill"
version = "0.2.6" version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
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",
]
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.5" version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [ dependencies = [
"either", "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]] [[package]]
name = "phf" name = "phf"
version = "0.11.1" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
dependencies = [ dependencies = [
"phf_macros", "phf_macros",
"phf_shared", "phf_shared",
@ -207,9 +142,9 @@ dependencies = [
[[package]] [[package]]
name = "phf_generator" name = "phf_generator"
version = "0.11.1" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
dependencies = [ dependencies = [
"phf_shared", "phf_shared",
"rand", "rand",
@ -217,9 +152,9 @@ dependencies = [
[[package]] [[package]]
name = "phf_macros" name = "phf_macros"
version = "0.11.1" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
dependencies = [ dependencies = [
"phf_generator", "phf_generator",
"phf_shared", "phf_shared",
@ -230,51 +165,27 @@ dependencies = [
[[package]] [[package]]
name = "phf_shared" name = "phf_shared"
version = "0.11.1" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
dependencies = [ dependencies = [
"siphasher", "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]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.50" version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2" checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.23" version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
@ -294,23 +205,6 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 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]] [[package]]
name = "rlox2" name = "rlox2"
version = "0.1.0" version = "0.1.0"
@ -318,7 +212,6 @@ dependencies = [
"clap", "clap",
"rlox2-frontend", "rlox2-frontend",
"rlox2-interpreter", "rlox2-interpreter",
"rlox2-vm",
] ]
[[package]] [[package]]
@ -334,98 +227,56 @@ dependencies = [
name = "rlox2-interpreter" name = "rlox2-interpreter"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"glob",
"itertools", "itertools",
"rlox2-frontend", "rlox2-frontend",
"rustc-hash", "rustc-hash",
"thiserror", "thiserror",
] ]
[[package]]
name = "rlox2-vm"
version = "0.1.0"
dependencies = [
"itertools",
"lazy_static",
"num-derive",
"num-traits",
"regex",
"rlox2-frontend",
"static_assertions",
"thiserror",
]
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
version = "1.1.0" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
[[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",
]
[[package]] [[package]]
name = "siphasher" name = "siphasher"
version = "0.3.10" version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]] [[package]]
name = "strsim" name = "strsim"
version = "0.10.0" version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]] [[package]]
name = "syn" name = "syn"
version = "1.0.107" version = "2.0.76"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"unicode-ident", "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]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.38" version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.38" version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -434,56 +285,35 @@ dependencies = [
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.6" version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]] [[package]]
name = "version_check" name = "utf8parse"
version = "0.9.4" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[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"
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.42.0" version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" 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 = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm",
"windows_aarch64_msvc", "windows_aarch64_msvc",
"windows_i686_gnu", "windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc", "windows_i686_msvc",
"windows_x86_64_gnu", "windows_x86_64_gnu",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm",
@ -492,42 +322,48 @@ dependencies = [
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.42.1" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.42.1" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.42.1" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" 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]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.42.1" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.42.1" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.42.1" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.42.1" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View file

@ -8,7 +8,7 @@ name = "rlox"
path = "src/main.rs" path = "src/main.rs"
[workspace] [workspace]
members = ["frontend", "interpreter", "vm"] members = ["frontend", "interpreter"] # , "vm"
[dependencies.rlox2-frontend] [dependencies.rlox2-frontend]
path = "frontend" path = "frontend"
@ -16,8 +16,8 @@ path = "frontend"
[dependencies.rlox2-interpreter] [dependencies.rlox2-interpreter]
path = "interpreter" path = "interpreter"
[dependencies.rlox2-vm] # [dependencies.rlox2-vm]
path = "vm" # path = "vm"
[dependencies] [dependencies]
clap = { version = "4.1.4", features = ["derive"] } clap = { version = "4", features = ["derive"] }

View file

@ -6,6 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
phf = { version = "0.11.1", features = ["macros"] } phf = { version = "0.11", features = ["macros"] }
thiserror = "1.0.38" thiserror = "1"
itertools = "0.10.5" itertools = "0.13"

View file

@ -129,6 +129,11 @@ impl Lexer {
// line comment // line comment
// advance until either source is empty or newline if found // advance until either source is empty or newline if found
while !self.source_is_empty() && self.advance() != '\n' {} while !self.source_is_empty() && self.advance() != '\n' {}
let comment: Box<str> =
self.source[self.start + 2..self.current].iter().collect();
self.push_token(TokenType::Comment(comment));
} else if self.consume('*') { } else if self.consume('*') {
// block comment // block comment
@ -164,6 +169,12 @@ impl Lexer {
self.advance(); self.advance();
} }
let comment: Box<str> = self.source[self.start + 2..self.current - 2]
.iter()
.collect();
self.push_token(TokenType::Comment(comment));
} else { } else {
self.push_token(Slash) 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<str> = self.source[self.start + 1..self.current - 1]
.iter()
.collect();
// Some(TokenType::String(Box::new(string_literal))) // 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) { fn try_parse_number(&mut self) {
@ -290,8 +304,12 @@ impl Lexer {
} }
fn try_parse_identifier(&mut self) { fn try_parse_identifier(&mut self) {
let is_alpha_num_underscore = let is_alpha_num_underscore = |c: Option<char>| {
|c: Option<char>| c.map_or(false, |c| matches!(c, '0'..='9' | 'A'..='Z' | '_' | 'a'..='z')); c.map_or(
false,
|c| matches!(c, '0'..='9' | 'A'..='Z' | '_' | 'a'..='z'),
)
};
while is_alpha_num_underscore(self.peek()) { while is_alpha_num_underscore(self.peek()) {
self.advance(); self.advance();
@ -304,11 +322,12 @@ impl Lexer {
.cloned() .cloned()
.unwrap_or(TokenType::Identifier(Box::new(lexeme))); */ .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) // Token::new(token_type, self.code_pos)
self.push_token(token_type); self.push_token(token_type.clone());
} else { } else {
self.tokens.push(Token::new_identifier(lexeme, self.code_pos)); self.tokens
.push(Token::new_identifier(lexeme, self.code_pos));
} }
// Some(token_type) // Some(token_type)

View file

@ -4,13 +4,13 @@ use super::CodePos;
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum LexerError { pub enum LexerError {
#[error("Unexpected character '{c}' at {code_pos}.")] #[error("LexerError: Unexpected character '{c}' at {code_pos}.")]
UnexpectedCharacter { c: char, code_pos: CodePos }, 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 }, 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 }, UnterminatedBlockComment { code_pos: CodePos },
#[error("Invalid number literal {lexeme} at {code_pos}: {msg}")] #[error("LexerError: Invalid number literal {lexeme} at {code_pos}: {msg}")]
InvalidNumberLiteral { InvalidNumberLiteral {
lexeme: String, lexeme: String,
msg: String, msg: String,

View file

@ -1,10 +1,9 @@
use std::fmt::{Debug, Display}; use std::fmt::{Debug, Display};
use std::mem::ManuallyDrop;
use super::CodePos; use super::CodePos;
#[repr(u8)] #[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[rustfmt::skip] #[rustfmt::skip]
pub enum TokenType { pub enum TokenType {
// Single-character tokens // Single-character tokens
@ -18,42 +17,20 @@ pub enum TokenType {
Less, LessEqual, Less, LessEqual,
// Identifier and literals // Identifier and literals
Identifier, String, Number, Identifier(Box<str>), String(Box<str>), Number(f64),
// Keywords // Keywords
And, Break, Class, Else, False, Fun, For, If, Nil, Or, And, Break, Class, Else, False, Fun, For, If, Nil, Or,
Print, Return, Super, This, True, Var, While, Print, Return, Super, This, True, Var, While,
#[allow(dead_code, clippy::upper_case_acronyms)] Comment(Box<str>),
#[allow(clippy::upper_case_acronyms)]
EOF EOF
} }
union TokenData {
none: (),
#[allow(clippy::box_collection)]
s: ManuallyDrop<Box<String>>,
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 struct Token {
pub token_type: TokenType, pub token_type: TokenType,
// pub lexeme: String,
data: TokenData,
pub code_pos: CodePos, pub code_pos: CodePos,
} }
@ -61,95 +38,64 @@ impl Token {
pub fn new(token_type: TokenType, code_pos: CodePos) -> Self { pub fn new(token_type: TokenType, code_pos: CodePos) -> Self {
Token { Token {
token_type, token_type,
// lexeme,
data: TokenData::none(),
code_pos, code_pos,
} }
} }
pub fn new_string(s: String, code_pos: CodePos) -> Self { pub fn new_string(s: impl Into<Box<str>>, code_pos: CodePos) -> Self {
Token { Token {
token_type: TokenType::String, token_type: TokenType::String(s.into()),
data: TokenData::string(s),
code_pos, code_pos,
} }
} }
pub fn new_identifier(name: String, code_pos: CodePos) -> Self { pub fn new_identifier(name: impl Into<Box<str>>, code_pos: CodePos) -> Self {
Token { Token {
token_type: TokenType::Identifier, token_type: TokenType::Identifier(name.into()),
data: TokenData::string(name),
code_pos, code_pos,
} }
} }
pub fn new_number(num: f64, code_pos: CodePos) -> Self { pub fn new_number(num: f64, code_pos: CodePos) -> Self {
Token { Token {
token_type: TokenType::Number, token_type: TokenType::Number(num),
data: TokenData::num(num),
code_pos, code_pos,
} }
} }
pub fn string_data(self) -> String { pub fn take(&mut self) -> Self {
assert!(self.token_type == TokenType::String || self.token_type == TokenType::Identifier); let code_pos = self.code_pos;
// std::mem::take(&mut self.data.s) use TokenType::*;
unsafe {
let mut me = self;
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 { impl Debug for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// write!(f, "<{:?}>", self.token_type) write!(f, "<{:?} {:?}> ", self.token_type, self.code_pos)
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),
}
} }
} }
impl Display for Token { impl Display for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// write!(f, "<{:?}>", self.token_type) use TokenType::*;
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),
}
}
}
/* impl Clone for Token { match &self.token_type {
fn clone(&self) -> Self { String(s) => write!(f, "<String {}>", s),
let code_pos = self.code_pos; Identifier(name) => write!(f, "<Identifier {}>", name),
Number(x) => write!(f, "<Number {}>", x),
match self.token_type { tt => write!(f, "<{:?}>", tt),
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 {}
}
} }

View file

@ -1,5 +1,3 @@
use std::vec::IntoIter;
use crate::lexer::{Token, TokenType}; use crate::lexer::{Token, TokenType};
use crate::parser::expr::BinaryOp; use crate::parser::expr::BinaryOp;
@ -18,31 +16,39 @@ pub fn parse_tokens(tokens: Vec<Token>) -> Result<Vec<Stmt>, Vec<ParserError>> {
// takes care of token iteration // takes care of token iteration
struct TokenIter { struct TokenIter {
token_iter: IntoIter<Token>, tokens: Vec<Token>,
peek_token: Option<Token>, pos: usize,
} }
impl TokenIter { impl TokenIter {
pub fn new(tokens: Vec<Token>) -> Self { pub fn new(tokens: Vec<Token>) -> Self {
TokenIter { TokenIter { tokens, pos: 0 }
token_iter: tokens.into_iter(), }
peek_token: None,
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> { fn peek(&mut self) -> Option<&Token> {
// if peek_token is empty: fill with next token from token_iter if self.is_empty() {
if self.peek_token.is_none() && self.token_iter.len() != 0 { return None;
self.peek_token = self.token_iter.next();
} }
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 { fn is_empty(&self) -> bool {
// peek_token is None and there are no more tokens to take from token_iter self.pos == self.tokens.len()
self.peek_token.is_none() && self.token_iter.len() == 0
} }
} }
@ -50,8 +56,16 @@ impl Iterator for TokenIter {
type Item = Token; type Item = Token;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
// return the peeked token if any, or else next token from token_iter self.skip_comments();
self.peek_token.take().or_else(|| self.token_iter.next())
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() { if !me.parse_errors.is_empty() {
Err(me.parse_errors) Err(me.parse_errors)
@ -122,10 +140,10 @@ impl Parser {
self.is_in_function = false; self.is_in_function = false;
self.is_in_init = 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 // if we match a synchronisation point: return
match peek_token.token_type { match tt {
TokenType::Class TokenType::Class
| TokenType::Fun | TokenType::Fun
| TokenType::Var | TokenType::Var
@ -177,23 +195,13 @@ impl Parser {
let code_pos = self.peek_token().code_pos; let code_pos = self.peek_token().code_pos;
assert_eq!(self.next_token().token_type, TokenType::Return); assert_eq!(self.next_token().token_type, TokenType::Return);
let expr = match self.peek_token().token_type { let expr = match (self.is_in_init, &self.peek_token().token_type) {
TokenType::Semicolon => { (false, TokenType::Semicolon) => Expr::nil(),
if !self.is_in_init { (true, TokenType::Semicolon) => Expr::variable("this"),
Expr::nil() (false, _) => self.expression()?,
} else { (true, _) => {
Expr::Variable {
name: "this".to_owned(),
}
}
}
_ => {
if !self.is_in_init {
self.expression()?
} else {
return Err(ParserError::ReturnInInit { code_pos }); return Err(ParserError::ReturnInInit { code_pos });
} }
}
}; };
self.semicolon()?; self.semicolon()?;
@ -208,14 +216,18 @@ impl Parser {
fn if_statement(&mut self) -> ParserResult<Stmt> { fn if_statement(&mut self) -> ParserResult<Stmt> {
assert_eq!(self.next_token().token_type, TokenType::If); assert_eq!(self.next_token().token_type, TokenType::If);
self.consume_token(TokenType::LeftParen, |token| ParserError::MissingParenAfterIf { self.consume_token(TokenType::LeftParen, |token| {
ParserError::MissingParenAfterIf {
code_pos: token.code_pos, code_pos: token.code_pos,
}
})?; })?;
let condition = self.expression()?; let condition = self.expression()?;
self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen { self.consume_token(TokenType::RightParen, |token| {
ParserError::MissingRightParen {
code_pos: token.code_pos, code_pos: token.code_pos,
}
})?; })?;
let then_branch = self.statement()?; let then_branch = self.statement()?;
@ -235,14 +247,18 @@ impl Parser {
fn while_statement(&mut self) -> ParserResult<Stmt> { fn while_statement(&mut self) -> ParserResult<Stmt> {
assert_eq!(self.next_token().token_type, TokenType::While); assert_eq!(self.next_token().token_type, TokenType::While);
self.consume_token(TokenType::LeftParen, |token| ParserError::MissingParenAfterWhile { self.consume_token(TokenType::LeftParen, |token| {
ParserError::MissingParenAfterWhile {
code_pos: token.code_pos, code_pos: token.code_pos,
}
})?; })?;
let condition = self.expression()?; let condition = self.expression()?;
self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen { self.consume_token(TokenType::RightParen, |token| {
ParserError::MissingRightParen {
code_pos: token.code_pos, code_pos: token.code_pos,
}
})?; })?;
let is_in_loop = std::mem::replace(&mut self.is_in_loop, true); 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<Stmt> { fn for_statement(&mut self) -> ParserResult<Stmt> {
assert_eq!(self.next_token().token_type, TokenType::For); assert_eq!(self.next_token().token_type, TokenType::For);
self.consume_token(TokenType::LeftParen, |token| ParserError::MissingParenAfterFor { self.consume_token(TokenType::LeftParen, |token| {
ParserError::MissingParenAfterFor {
code_pos: token.code_pos, code_pos: token.code_pos,
}
})?; })?;
let initializer = match self.peek_token().token_type { let initializer = match self.peek_token().token_type {
@ -282,8 +300,10 @@ impl Parser {
_ => Some(self.expression()?), _ => Some(self.expression()?),
}; };
self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen { self.consume_token(TokenType::RightParen, |token| {
ParserError::MissingRightParen {
code_pos: token.code_pos, code_pos: token.code_pos,
}
})?; })?;
let is_in_loop = std::mem::replace(&mut self.is_in_loop, true); 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 token = self.next_token();
let name = match token.token_type { let name = match token.token_type {
TokenType::Identifier => token.string_data(), TokenType::Identifier(s) => s,
_ => return Err(ParserError::ExpectedVarName { token }), _ => return Err(ParserError::ExpectedVarName { token }),
}; };
@ -354,13 +374,17 @@ impl Parser {
let superclass_name = self.identifier("Expected superclass")?; let superclass_name = self.identifier("Expected superclass")?;
Some(Expr::Variable { name: superclass_name }) Some(Expr::Variable {
name: superclass_name,
})
} else { } else {
None None
}; };
self.consume_token(TokenType::LeftBrace, |token| ParserError::MissingClassBody { self.consume_token(TokenType::LeftBrace, |token| {
ParserError::MissingClassBody {
code_pos: token.code_pos, code_pos: token.code_pos,
}
})?; })?;
let is_in_loop = std::mem::replace(&mut self.is_in_loop, false); 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; let is_in_init = self.is_in_init;
if method_name == "init" { if &*method_name == "init" {
self.is_in_init = true; self.is_in_init = true;
} }
@ -398,7 +422,7 @@ impl Parser {
self.is_in_class = is_in_class; self.is_in_class = is_in_class;
self.is_in_function = is_in_function; 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)) Ok(Stmt::var_decl(name, class))
} }
@ -451,7 +475,7 @@ impl Parser {
Ok(Expr::function(name, param_names, body)) Ok(Expr::function(name, param_names, body))
} }
fn collect_params(&mut self) -> ParserResult<Vec<String>> { fn collect_params(&mut self) -> ParserResult<Vec<Box<str>>> {
assert_eq!(self.next_token().token_type, TokenType::LeftParen); assert_eq!(self.next_token().token_type, TokenType::LeftParen);
if self.peek_token().token_type == TokenType::RightParen { if self.peek_token().token_type == TokenType::RightParen {
@ -470,8 +494,10 @@ impl Parser {
param_names.push(self.identifier("Expected parameter name")?); param_names.push(self.identifier("Expected parameter name")?);
} }
self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen { self.consume_token(TokenType::RightParen, |token| {
ParserError::MissingRightParen {
code_pos: token.code_pos, code_pos: token.code_pos,
}
})?; })?;
Ok(param_names) Ok(param_names)
@ -532,7 +558,11 @@ impl Parser {
Expr::Variable { name } => Ok(Expr::assignment(Expr::Variable { name }, value)), Expr::Variable { name } => Ok(Expr::assignment(Expr::Variable { name }, value)),
Expr::Get { target, name } => { Expr::Get { target, name } => {
let value = Box::new(value); let value = Box::new(value);
Ok(Expr::Set { target, name, value }) Ok(Expr::Set {
target,
name,
value,
})
} }
_ => Err(ParserError::InvalidAssignment { expr, code_pos }), _ => Err(ParserError::InvalidAssignment { expr, code_pos }),
} }
@ -720,8 +750,10 @@ impl Parser {
args.push(self.expression()?); args.push(self.expression()?);
} }
self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen { self.consume_token(TokenType::RightParen, |token| {
ParserError::MissingRightParen {
code_pos: token.code_pos, code_pos: token.code_pos,
}
})?; })?;
Ok(args) Ok(args)
@ -736,52 +768,53 @@ impl Parser {
match token.token_type { match token.token_type {
TokenType::Fun => Ok(self.fun_params_and_body("<lambda>")?), TokenType::Fun => Ok(self.fun_params_and_body("<lambda>")?),
TokenType::Number => Ok(Expr::number(token.num_data())), TokenType::Number(x) => Ok(Expr::number(x)),
TokenType::String => Ok(Expr::string(token.string_data())), TokenType::String(s) => Ok(Expr::string(s)),
TokenType::False => Ok(Expr::bool(false)), TokenType::False => Ok(Expr::bool(false)),
TokenType::True => Ok(Expr::bool(true)), TokenType::True => Ok(Expr::bool(true)),
TokenType::Nil => Ok(Expr::nil()), TokenType::Nil => Ok(Expr::nil()),
TokenType::This => Ok(Expr::This), TokenType::This => Ok(Expr::This),
TokenType::Super => { TokenType::Super => {
self.consume_token(TokenType::Dot, |token| ParserError::MissingMethodAfterSuper { self.consume_token(TokenType::Dot, |token| {
ParserError::MissingMethodAfterSuper {
code_pos: token.code_pos, code_pos: token.code_pos,
}
})?; })?;
let method = self.identifier("Expected method name after super")?; let method = self.identifier("Expected method name after super")?;
let super_var = Box::new(Expr::Variable { let super_var = Expr::variable("super");
name: "super".to_owned(), let this_var = Expr::This;
}); Ok(Expr::super_(super_var, this_var, method))
let this_var = Box::new(Expr::This);
Ok(Expr::Super {
super_var,
this_var,
method,
})
} }
TokenType::LeftParen => { TokenType::LeftParen => {
let expr = self.expression()?; let expr = self.expression()?;
self.consume_token(TokenType::RightParen, |token| ParserError::MissingRightParen { self.consume_token(TokenType::RightParen, |token| {
ParserError::MissingRightParen {
code_pos: token.code_pos, code_pos: token.code_pos,
}
})?; })?;
Ok(Expr::grouping(expr)) Ok(Expr::grouping(expr))
} }
TokenType::Identifier => Ok(Expr::Variable { TokenType::Identifier(name) => Ok(Expr::Variable { name }),
name: token.string_data(),
}),
_ => Err(ParserError::ExpectedPrimary { token }), _ => Err(ParserError::ExpectedPrimary { token }),
} }
} }
fn semicolon(&mut self) -> ParserResult<()> { fn semicolon(&mut self) -> ParserResult<()> {
self.consume_token(TokenType::Semicolon, |token| ParserError::MissingSemicolon { self.consume_token(TokenType::Semicolon, |token| {
ParserError::MissingSemicolon {
code_pos: token.code_pos, code_pos: token.code_pos,
}
}) })
} }
fn identifier(&mut self, msg: &str) -> ParserResult<String> { fn identifier(&mut self, msg: &str) -> ParserResult<Box<str>> {
match self.peek_token().token_type { 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 { _ => Err(ParserError::MissingIdentifier {
msg: msg.to_owned(), msg: msg.to_owned(),
code_pos: self.peek_token().code_pos, code_pos: self.peek_token().code_pos,
@ -813,7 +846,7 @@ impl Parser {
fn consume_token<F>(&mut self, token_type: TokenType, err_fn: F) -> ParserResult<()> fn consume_token<F>(&mut self, token_type: TokenType, err_fn: F) -> ParserResult<()>
where where
F: Fn(Token) -> ParserError, F: Fn(&Token) -> ParserError,
{ {
/* let token = self.next_token(); /* let token = self.next_token();
@ -829,8 +862,8 @@ impl Parser {
Ok(()) Ok(())
} }
// call err_fn with dummy token so we don't have to eat the EOF token // 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))), TokenType::EOF => Err(err_fn(self.peek_token())),
_ => Err(err_fn(self.next_token())), _ => Err(err_fn(&self.next_token())),
} }
} }
} }

View file

@ -6,44 +6,44 @@ use super::Expr;
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum ParserError { pub enum ParserError {
#[error("Token stream ended unexpectedly.")] #[error("ParserError: Token stream ended unexpectedly.")]
TokenStreamEnded, 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 }, ExpectedPrimary { token: Token },
#[error("Missing semicolon at {code_pos}")] #[error("ParserError: Missing semicolon at {code_pos}")]
MissingSemicolon { code_pos: CodePos }, 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 }, 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 }, 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 }, MissingRightBrace { code_pos: CodePos },
#[error("Missing closing parenthesis at {code_pos}")] #[error("ParserError: Missing closing parenthesis at {code_pos}")]
MissingRightParen { code_pos: CodePos }, 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 }, 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 }, 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 }, 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 }, TooManyArguments { code_pos: CodePos },
#[error("{msg} at {code_pos}")] #[error("ParserError: {msg} at {code_pos}")]
MissingIdentifier { msg: String, code_pos: CodePos }, 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 }, 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 }, 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 }, TooManyParams { code_pos: CodePos },
#[error("Return statement outside of function definition")] #[error("ParserError: Return statement outside of function definition")]
ReturnOutsideFunction { code_pos: CodePos }, ReturnOutsideFunction { code_pos: CodePos },
#[error("Break statement outside of loop")] #[error("ParserError: Break statement outside of loop")]
InvalidBreak { code_pos: CodePos }, InvalidBreak { code_pos: CodePos },
#[error("Missing class body at {code_pos}")] #[error("ParserError: Missing class body at {code_pos}")]
MissingClassBody { code_pos: CodePos }, MissingClassBody { code_pos: CodePos },
#[error("Return statement in init")] #[error("ParserError: Return statement in init")]
ReturnInInit { code_pos: CodePos }, ReturnInInit { code_pos: CodePos },
#[error("Missing method name after super")] #[error("ParserError: Missing method name after super")]
MissingMethodAfterSuper { code_pos: CodePos }, MissingMethodAfterSuper { code_pos: CodePos },
} }

View file

@ -1,5 +1,4 @@
use std::fmt::Display; use std::fmt::Display;
use std::rc::Rc;
use itertools::Itertools; use itertools::Itertools;
@ -28,14 +27,14 @@ pub enum Expr {
expr: Box<Expr>, expr: Box<Expr>,
}, },
Variable { Variable {
name: String, name: Box<str>,
}, },
LocalVariable { LocalVariable {
name: String, name: Box<str>,
level: usize, level: usize,
}, },
GlobalVariable { GlobalVariable {
name: String, name: Box<str>,
}, },
Assignment { Assignment {
target: Box<Expr>, target: Box<Expr>,
@ -47,37 +46,37 @@ pub enum Expr {
}, },
Get { Get {
target: Box<Expr>, target: Box<Expr>,
name: String, name: Box<str>,
}, },
Set { Set {
target: Box<Expr>, target: Box<Expr>,
name: String, name: Box<str>,
value: Box<Expr>, value: Box<Expr>,
}, },
Function { Function {
name: String, name: Box<str>,
param_names: Vec<String>, param_names: Vec<Box<str>>,
closure_vars: Vec<(String, usize)>, closure_vars: Vec<(Box<str>, usize)>,
body: Box<Stmt>, body: Box<Stmt>,
}, },
Class { Class {
name: Box<str>,
superclass: Option<Box<Expr>>, superclass: Option<Box<Expr>>,
name: String,
methods: Box<Vec<Expr>>, methods: Box<Vec<Expr>>,
}, },
This, This,
Super { Super {
super_var: Box<Expr>, super_var: Box<Expr>,
this_var: Box<Expr>, this_var: Box<Expr>,
method: String, method: Box<str>,
}, },
} }
impl Expr { impl Expr {
pub fn string(s: impl Into<String>) -> Self { pub fn string(s: impl Into<Box<str>>) -> Self {
let s = s.into(); let s = s.into();
Expr::Literal { Expr::Literal {
literal: Literal::String(Rc::new(s)), literal: Literal::String(s),
} }
} }
@ -94,7 +93,9 @@ impl Expr {
} }
pub fn nil() -> Self { pub fn nil() -> Self {
Expr::Literal { literal: Literal::Nil } Expr::Literal {
literal: Literal::Nil,
}
} }
pub fn unary(op: UnaryOp, expr: Expr) -> Self { pub fn unary(op: UnaryOp, expr: Expr) -> Self {
@ -119,6 +120,21 @@ impl Expr {
Expr::Grouping { expr } Expr::Grouping { expr }
} }
pub fn variable(name: impl Into<Box<str>>) -> Self {
let name = name.into();
Expr::Variable { name }
}
pub fn local_variable(name: impl Into<Box<str>>, level: usize) -> Self {
let name = name.into();
Expr::LocalVariable { name, level }
}
pub fn global_variable(name: impl Into<Box<str>>) -> Self {
let name = name.into();
Expr::GlobalVariable { name }
}
pub fn assignment(target: Expr, value: Expr) -> Self { pub fn assignment(target: Expr, value: Expr) -> Self {
let target = Box::new(target); let target = Box::new(target);
let value = Box::new(value); let value = Box::new(value);
@ -130,15 +146,14 @@ impl Expr {
Expr::Call { callee, args } Expr::Call { callee, args }
} }
pub fn get(target: Expr, name: impl Into<String>) -> Self { pub fn get(target: Expr, name: impl Into<Box<str>>) -> Self {
let target = Box::new(target); let target = Box::new(target);
let name = name.into(); let name = name.into();
Expr::Get { target, name } Expr::Get { target, name }
} }
pub fn function(name: String, param_names: Vec<String>, body: Stmt) -> Self { pub fn function(name: impl Into<Box<str>>, param_names: Vec<Box<str>>, body: Stmt) -> Self {
// let name = Box::new(name); let name = name.into();
// let param_names = Box::new(param_names);
#[allow(clippy::box_default)] #[allow(clippy::box_default)]
// let closure_vars = Box::new(Vec::new()); // let closure_vars = Box::new(Vec::new());
let closure_vars = Vec::new(); let closure_vars = Vec::new();
@ -151,16 +166,33 @@ impl Expr {
} }
} }
pub fn class(name: impl Into<String>, methods: Vec<Expr>, superclass: Option<Expr>) -> Self { pub fn class(name: impl Into<Box<str>>, methods: Vec<Expr>, superclass: Option<Expr>) -> Self {
let superclass = superclass.map(Box::new); let superclass = superclass.map(Box::new);
let name = name.into(); let name = name.into();
let methods = Box::new(methods); let methods = Box::new(methods);
Expr::Class { Expr::Class {
superclass,
name, name,
superclass,
methods, methods,
} }
} }
pub fn super_(
super_var: impl Into<Box<Expr>>,
this_var: impl Into<Box<Expr>>,
method: impl Into<Box<str>>,
) -> 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 { impl Display for Expr {
@ -174,12 +206,20 @@ impl Display for Expr {
} }
Expr::Grouping { expr } => write!(f, "(group {expr})"), Expr::Grouping { expr } => write!(f, "(group {expr})"),
Expr::Variable { name } => write!(f, "(var {name})"), Expr::Variable { name } => write!(f, "(var {name})"),
Expr::LocalVariable { name, level } => write!(f, "(var {name} local({level}))"), Expr::LocalVariable { name, level } => write!(f, "(local {name} {level})"),
Expr::GlobalVariable { name } => write!(f, "(var {name} global)"), Expr::GlobalVariable { name } => write!(f, "(global {name})"),
Expr::Assignment { target, value } => write!(f, "{target} = {value}"), 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::Call { callee, args } => write!(
f,
"({callee} {})",
args.iter().map(|arg| arg.to_string()).join(" ")
),
Expr::Get { target, name } => write!(f, "(get {name} {target})"), 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 { Expr::Function {
name, name,
param_names, param_names,
@ -189,9 +229,13 @@ impl Display for Expr {
if !closure_vars.is_empty() { if !closure_vars.is_empty() {
let closure_fmt = closure_vars.iter().map(|(name, _level)| name).join(", "); 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 { } else {
write!(f, "fun {name}({}) => {body}", param_names.join(", ")) write!(f, "(fun {name} ({}) {body})", param_names.join(", "))
} }
} }
Expr::Class { Expr::Class {
@ -200,14 +244,14 @@ impl Display for Expr {
methods, methods,
} => { } => {
if let Some(superclass) = superclass { if let Some(superclass) = superclass {
writeln!(f, "class {name} < {superclass} {{")?; writeln!(f, "(class {name} < {superclass} ")?;
} else { } else {
writeln!(f, "class {name} {{")?; writeln!(f, "(class {name} ")?;
} }
for method in methods.iter() { for method in methods.iter() {
writeln!(f, "{method}")?; writeln!(f, "{method}")?;
} }
write!(f, "}}") write!(f, ")")
} }
Expr::This => write!(f, "this"), Expr::This => write!(f, "this"),
Expr::Super { Expr::Super {
@ -223,7 +267,7 @@ impl Display for Expr {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Literal { pub enum Literal {
String(Rc<String>), String(Box<str>),
Number(f64), Number(f64),
Bool(bool), Bool(bool),
Nil, Nil,

View file

@ -1,5 +1,5 @@
use itertools::Itertools; use itertools::Itertools;
pub fn indent(s: String) -> String { 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")
} }

View file

@ -18,7 +18,7 @@ pub enum Stmt {
body: Box<Stmt>, body: Box<Stmt>,
}, },
VarDecl { VarDecl {
name: String, name: Box<str>,
initializer: Box<Expr>, initializer: Box<Expr>,
}, },
Block { Block {
@ -62,19 +62,23 @@ impl Stmt {
Stmt::While { condition, body } Stmt::While { condition, body }
} }
pub fn var_decl(name: impl Into<String>, initializer: impl Into<Box<Expr>>) -> Self { pub fn var_decl(name: impl Into<Box<str>>, initializer: impl Into<Box<Expr>>) -> Self {
let name = name.into(); let name = name.into();
let initializer = initializer.into(); let initializer = initializer.into();
Stmt::VarDecl { name, initializer } Stmt::VarDecl { name, initializer }
} }
pub fn expr_stmt(expr: impl Into<Box<Expr>>) -> Self { pub fn expr_stmt(expr: impl Into<Box<Expr>>) -> Self {
let expr = expr.into(); let expr = expr.into();
Stmt::ExprStmt { expr } Stmt::ExprStmt { expr }
} }
pub fn return_stmt(expr: impl Into<Box<Expr>>) -> Self { pub fn return_stmt(expr: impl Into<Box<Expr>>) -> Self {
let expr = expr.into(); let expr = expr.into();
Stmt::Return { expr } Stmt::Return { expr }
} }
} }
@ -82,7 +86,7 @@ impl Stmt {
impl Display for Stmt { impl Display for Stmt {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Stmt::Print { expr } => write!(f, "(print {expr});"), Stmt::Print { expr } => write!(f, "(print {expr})"),
Stmt::IfStmt { Stmt::IfStmt {
condition, condition,
then_branch, then_branch,
@ -110,18 +114,18 @@ impl Display for Stmt {
} }
Ok(()) Ok(())
} }
Stmt::VarDecl { name, initializer } => write!(f, "var {name} = {initializer};"), Stmt::VarDecl { name, initializer } => write!(f, "(decl {name} {initializer})"),
Stmt::Block { statements } => { Stmt::Block { statements } => {
writeln!(f, "{{")?; writeln!(f, "(block")?;
for statement in statements { for statement in statements {
writeln!(f, "{}", indent(statement.to_string()))?; writeln!(f, "{}", indent(statement.to_string()))?;
} }
write!(f, "}}") write!(f, ")")
} }
Stmt::ExprStmt { expr } => write!(f, "{expr};"), Stmt::ExprStmt { expr } => write!(f, "{expr};"),
Stmt::Break => write!(f, "break;"), Stmt::Break => write!(f, "(break)"),
Stmt::Return { expr } => { Stmt::Return { expr } => {
write!(f, "return {expr};") write!(f, "(return {expr})")
} }
} }
} }

View file

@ -10,7 +10,7 @@ use crate::{LoxFunction, LoxReference, Value};
pub struct LoxClass { pub struct LoxClass {
superclass: Option<Rc<LoxClass>>, superclass: Option<Rc<LoxClass>>,
name: String, name: Box<str>,
methods: FxHashMap<String, Value>, methods: FxHashMap<String, Value>,
} }
@ -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. /// Representation of a class in Lox. Always behind an Rc to ensure uniqueness. Should never be handled raw.
impl LoxClass { impl LoxClass {
pub fn new( pub fn new(
name: impl Into<String>, name: impl Into<Box<str>>,
methods: FxHashMap<String, Value>, methods: FxHashMap<String, Value>,
superclass: Option<Rc<LoxClass>>, superclass: Option<Rc<LoxClass>>,
) -> Rc<Self> { ) -> Rc<Self> {
@ -33,10 +33,7 @@ impl LoxClass {
let mut body = init.body().clone(); let mut body = init.body().clone();
if let Stmt::Block { ref mut statements } = body { if let Stmt::Block { ref mut statements } = body {
statements.push(Stmt::return_stmt(Expr::LocalVariable { statements.push(Stmt::return_stmt(Expr::local_variable("this", 1)));
name: "this".to_owned(),
level: 1,
}));
} else { } else {
panic!("Body of init method of class {name} wasn't a block"); panic!("Body of init method of class {name} wasn't a block");
} }
@ -130,7 +127,12 @@ impl LoxClass {
impl Display for LoxClass { impl Display for LoxClass {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "<class {} at {:#X}>", self.name, (self as *const LoxClass) as usize) write!(
f,
"<class {} at {:#X}>",
self.name,
(self as *const LoxClass) as usize
)
} }
} }

View file

@ -8,12 +8,11 @@ use crate::error::RuntimeError;
use super::value::HeapedValue; use super::value::HeapedValue;
use super::{Runtime, Value}; use super::{Runtime, Value};
pub type Scope = FxHashMap<String, HeapedValue>; pub type Scope = FxHashMap<Box<str>, HeapedValue>;
#[derive(Debug)] #[derive(Debug)]
pub struct Environment<'a> { pub struct Environment<'a> {
scope_stack: Vec<Scope>, scope_stack: Vec<Scope>,
scope_top: usize,
runtime: &'a mut Runtime, runtime: &'a mut Runtime,
@ -24,7 +23,6 @@ impl<'a> Environment<'a> {
pub fn new(runtime: &'a mut Runtime) -> Self { pub fn new(runtime: &'a mut Runtime) -> Self {
Environment { Environment {
scope_stack: Vec::new(), scope_stack: Vec::new(),
scope_top: 0,
runtime, 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) { pub fn push_arg(&mut self, arg: Value) {
self.arg_stack.push(arg); self.arg_stack.push(arg);
} }
@ -44,16 +46,16 @@ impl<'a> Environment<'a> {
std::mem::take(&mut self.arg_stack) std::mem::take(&mut self.arg_stack)
} }
pub fn globals(&self) -> &FxHashMap<String, Value> { pub fn globals(&self) -> &FxHashMap<Box<str>, Value> {
self.runtime.globals() self.runtime.globals()
} }
pub fn scopes(&self) -> &[Scope] { pub fn scopes(&self) -> &[Scope] {
&self.scope_stack[..self.scope_top] &self.scope_stack
} }
pub fn scopes_mut(&mut self) -> &mut [Scope] { 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 { pub fn has_scope(&self) -> bool {
@ -61,30 +63,24 @@ impl<'a> Environment<'a> {
} }
pub fn current_scope(&self) -> &Scope { 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 { 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) { pub fn enter_scope(&mut self) {
// self.current_frame_mut().enter_scope(); // self.current_frame_mut().enter_scope();
// self.local_scopes.push(Scope::new()); // self.local_scopes.push(Scope::new());
if self.scope_top == self.scope_stack.len() {
self.scope_stack.push(Scope::default()); self.scope_stack.push(Scope::default());
} else {
self.scope_stack[self.scope_top].clear();
}
self.scope_top += 1;
} }
pub fn exit_scope(&mut self) { pub fn exit_scope(&mut self) {
// self.current_frame_mut().exit_scope(); // self.current_frame_mut().exit_scope();
// self.local_scopes.pop().expect("Tried to pop global 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) { 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) // self.runtime.get_global(name)
} }
pub fn define(&mut self, name: impl Into<String>, value: Value) { pub fn define(&mut self, name: impl Into<Box<str>>, value: Value) {
if self.has_scope() { if self.has_scope() {
let name = name.into(); let name = name.into();
self.current_scope_mut().insert(name, HeapedValue::new(value)); self.current_scope_mut()
.insert(name, HeapedValue::new(value));
} else { } else {
self.runtime.define_global(name, value) 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) // self.runtime.assign_global(name, value)
} }
@ -145,12 +146,12 @@ impl<'a> Environment<'a> {
self.frames.pop().expect("Tried to pop global frame"); 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<str>, usize)]) -> Scope {
let mut closure_scope = Scope::default(); let mut closure_scope = Scope::default();
for (name, level) in closure_vars { for (name, level) in closure_vars {
// special injected variables // special injected variables
if name == "this" || name == "super" { if &**name == "this" || &**name == "super" {
continue; continue;
} }
@ -181,7 +182,7 @@ impl Display for Environment<'_> {
write!(f, "\nScope {level}:")?; write!(f, "\nScope {level}:")?;
for (name, value) in scope.iter() { for (name, value) in scope.iter() {
write!(f, "\n\t{name} = {value}")?; write!(f, "\n\t{name} = {}", value.as_ref())?;
} }
} }

View file

@ -10,35 +10,43 @@ use crate::{LoxClass, ResolverError};
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum RuntimeError { 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 }, UnaryOpInvalidArgument { op: UnaryOp, arg: Value },
#[error("Binary operator {op} had invalid arguments {left} and {right}")] #[error("RuntimeError: Binary operator {op} had invalid arguments {left} and {right}")]
BinaryOpInvalidArguments { left: Value, op: BinaryOp, right: Value }, BinaryOpInvalidArguments {
#[error("Division by zero")] left: Value,
op: BinaryOp,
right: Value,
},
#[error("RuntimeError: Division by zero")]
DivisionByZero, DivisionByZero,
#[error("Local {name} is not defined")] #[error("RuntimeError: Local {name} is not defined")]
NameNotDefined { name: String }, NameNotDefined { name: String },
#[error("Global {name} is not defined")] #[error("RuntimeError: Global {name} is not defined")]
GlobalNotDefined { name: String }, GlobalNotDefined { name: String },
#[error("{callee} is not callable")] #[error("RuntimeError: {callee} is not callable")]
NotCallable { callee: Value }, NotCallable { callee: Value },
#[error("{name}() takes {arity} args, but {given} were given.")] #[error("RuntimeError: {name}() takes {arity} args, but {given} were given.")]
WrongArity { name: String, arity: usize, given: usize }, WrongArity {
#[error("Extern function call to {name} failed: {msg}")] name: String,
arity: usize,
given: usize,
},
#[error("RuntimeError: Extern function call to {name} failed: {msg}")]
ExtFunCallFailed { name: String, msg: String }, ExtFunCallFailed { name: String, msg: String },
#[error("Uncaught break statement")] #[error("RuntimeError: Uncaught break statement")]
Break, Break,
#[error("Uncaught return statement")] #[error("RuntimeError: Uncaught return statement")]
Return { value: Value }, Return { value: Value },
#[error("Exit with exit code {exit_code}")] #[error("RuntimeError: Exit with exit code {exit_code}")]
Exit { exit_code: i32 }, Exit { exit_code: i32 },
#[error("Only objects have attributes")] #[error("RuntimeError: Only objects have attributes")]
InvalidGetTarget, InvalidGetTarget,
#[error("Only objects have attributes")] #[error("RuntimeError: Only objects have attributes")]
InvalidSetTarget, InvalidSetTarget,
#[error("Class {0} has no property {name}", class.name())] #[error("RuntimeError: Class {0} has no property {name}", class.name())]
UndefinedAttribute { class: Rc<LoxClass>, name: String }, UndefinedAttribute { class: Rc<LoxClass>, name: Box<str> },
#[error("{value} is not a valid superclass")] #[error("RuntimeError: {value} is not a valid superclass")]
InvalidSuperclass { value: Value }, InvalidSuperclass { value: Value },
} }
@ -57,7 +65,7 @@ pub enum LoxError {
Exit { exit_code: i32 }, Exit { exit_code: i32 },
} }
fn format_multiple_errors(errs: &Vec<impl std::error::Error>) -> String { fn format_multiple_errors(errs: &[impl std::error::Error]) -> String {
let msg = if errs.len() == 1 { let msg = if errs.len() == 1 {
errs[0].to_string() errs[0].to_string()
} else { } else {
@ -81,7 +89,9 @@ impl From<Vec<ParserError>> for LoxError {
impl From<ResolverError> for LoxError { impl From<ResolverError> for LoxError {
fn from(resolver_err: ResolverError) -> Self { fn from(resolver_err: ResolverError) -> Self {
LoxError::ResolverError { inner: resolver_err } LoxError::ResolverError {
inner: resolver_err,
}
} }
} }

View file

@ -11,14 +11,19 @@ use super::{Runtime, Value};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LoxFunction { pub struct LoxFunction {
name: String, name: Box<str>,
closure: Scope, closure: Scope,
param_names: Vec<String>, param_names: Vec<Box<str>>,
body: Box<Stmt>, body: Box<Stmt>,
} }
impl LoxFunction { impl LoxFunction {
pub fn new(name: impl Into<String>, closure: Scope, param_names: Vec<String>, body: Stmt) -> Rc<Self> { pub fn new(
name: impl Into<Box<str>>,
closure: Scope,
param_names: Vec<Box<str>>,
body: Stmt,
) -> Rc<Self> {
let name = name.into(); let name = name.into();
let body = Box::new(body); let body = Box::new(body);
let fun = LoxFunction { let fun = LoxFunction {
@ -38,7 +43,7 @@ impl LoxFunction {
&self.closure &self.closure
} }
pub fn param_names(&self) -> &[String] { pub fn param_names(&self) -> &[Box<str>] {
&self.param_names &self.param_names
} }
@ -50,7 +55,7 @@ impl LoxFunction {
self.param_names().len() self.param_names().len()
} }
pub fn inject_closed_var(&mut self, name: impl Into<String>, value: Value) { pub fn inject_closed_var(&mut self, name: impl Into<Box<str>>, value: Value) {
let name = name.into(); let name = name.into();
let heaped_value = HeapedValue::new(value); let heaped_value = HeapedValue::new(value);
self.closure.insert(name, heaped_value); self.closure.insert(name, heaped_value);
@ -88,7 +93,11 @@ impl LoxExternFunction {
pub fn new(name: impl Into<String>, arity: usize, closure: ExternFunClosure) -> Self { pub fn new(name: impl Into<String>, arity: usize, closure: ExternFunClosure) -> Self {
let name = name.into(); let name = name.into();
LoxExternFunction { name, arity, closure } LoxExternFunction {
name,
arity,
closure,
}
} }
pub fn name(&self) -> &str { pub fn name(&self) -> &str {

View file

@ -31,7 +31,7 @@ trait Eval {
impl Eval for Literal { impl Eval for Literal {
fn eval(&self, _env: &mut Environment) -> EvalResult<Value> { fn eval(&self, _env: &mut Environment) -> EvalResult<Value> {
match self { 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::Number(num) => Ok(Value::Number(*num)),
Literal::Bool(b) => Ok(Value::Bool(*b)), Literal::Bool(b) => Ok(Value::Bool(*b)),
Literal::Nil => Ok(Value::Nil), Literal::Nil => Ok(Value::Nil),
@ -83,10 +83,10 @@ impl Eval for Expr {
}, },
(String(left), String(right)) => match op { (String(left), String(right)) => match op {
BinaryOp::Add => { BinaryOp::Add => {
let mut s = std::string::String::with_capacity(left.capacity() + right.capacity()); let s: Box<str> =
s += &left; itertools::chain(left.as_ref().chars(), right.chars()).collect();
s += &right;
Ok(String(Rc::new(s))) Ok(Value::string(s))
} }
BinaryOp::Less => Ok(Bool(left < right)), BinaryOp::Less => Ok(Bool(left < right)),
BinaryOp::LessEqual => Ok(Bool(left <= right)), BinaryOp::LessEqual => Ok(Bool(left <= right)),
@ -99,14 +99,18 @@ impl Eval for Expr {
right: String(right), right: String(right),
}), }),
}, },
(left, right) => Err(RuntimeError::BinaryOpInvalidArguments { left, op, right }), (left, right) => {
Err(RuntimeError::BinaryOpInvalidArguments { left, op, right })
}
} }
} }
Expr::Logical { left, op, right } => { Expr::Logical { left, op, right } => {
let left = left.eval(env)?; let left = left.eval(env)?;
// shortcircuit // 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); return Ok(left);
} }
@ -121,7 +125,9 @@ impl Eval for Expr {
let value = value.eval(env)?; let value = value.eval(env)?;
match target.as_ref() { 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())?, Expr::GlobalVariable { name } => env.assign_global(name, value.clone())?,
_ => panic!("Invalid assigment target {target}"), _ => panic!("Invalid assigment target {target}"),
} }
@ -159,12 +165,16 @@ impl Eval for Expr {
Err(RuntimeError::InvalidGetTarget) Err(RuntimeError::InvalidGetTarget)
} }
} }
Expr::Set { target, name, value } => { Expr::Set {
target,
name,
value,
} => {
let target = target.eval(env)?; let target = target.eval(env)?;
if let Value::Object(mut object) = target { if let Value::Object(mut object) = target {
let value = value.eval(env)?; let value = value.eval(env)?;
object.set(name, value); object.set(name.clone(), value);
Ok(Value::Nil) Ok(Value::Nil)
} else { } else {
Err(RuntimeError::InvalidSetTarget) Err(RuntimeError::InvalidSetTarget)
@ -176,7 +186,7 @@ impl Eval for Expr {
closure_vars, closure_vars,
body, body,
} => Ok(Value::function(LoxFunction::new( } => Ok(Value::function(LoxFunction::new(
name, name.clone(),
env.collect_closure(closure_vars), env.collect_closure(closure_vars),
param_names.clone(), param_names.clone(),
body.as_ref().clone(), body.as_ref().clone(),
@ -208,7 +218,11 @@ impl Eval for Expr {
env.exit_scope(); 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::This => panic!("Unresolved this"),
Expr::Super { Expr::Super {
@ -223,7 +237,9 @@ impl Eval for Expr {
Err(RuntimeError::InvalidGetTarget) 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<Value> { fn eval(&self, env: &mut Environment) -> EvalResult<Value> {
match self { match self {
Stmt::Print { expr } => { Stmt::Print { expr } => {
match expr.eval(env)? { use std::io::Write;
// special case: when printing a string, drop the surrounding ""
Value::String(s) => println!("{s}"), let val = expr.eval(env)?;
val => println!("{val}"), writeln!(env.runtime(), "{val}").unwrap();
}
} }
Stmt::IfStmt { Stmt::IfStmt {
condition, condition,
@ -262,7 +277,7 @@ impl Eval for Stmt {
} }
Stmt::VarDecl { name, initializer } => { Stmt::VarDecl { name, initializer } => {
let initializer = initializer.eval(env)?; let initializer = initializer.eval(env)?;
env.define(name, initializer); env.define(name.clone(), initializer);
} }
Stmt::Block { statements } => { Stmt::Block { statements } => {
env.enter_scope(); env.enter_scope();
@ -310,7 +325,7 @@ pub fn call_fun(fun: Rc<LoxFunction>, env: &mut Environment) -> EvalResult<Value
env.insert_closure(fun.closure().clone()); env.insert_closure(fun.closure().clone());
for (name, value) in std::iter::zip(fun.param_names(), args) { for (name, value) in std::iter::zip(fun.param_names(), args) {
env.define(name, value); env.define(name.clone(), value);
} }
let ret_val = match fun.body().eval(env) { let ret_val = match fun.body().eval(env) {

View file

@ -47,7 +47,7 @@ fn clock() -> LoxExternFunction {
fn print_globals() -> LoxExternFunction { fn print_globals() -> LoxExternFunction {
let closure: ExternFunClosure = |args, env| { let closure: ExternFunClosure = |args, env| {
assert_eq!(args.len(), 0); assert_eq!(args.len(), 0);
let mut globals: Vec<(&String, &Value)> = env.globals().iter().collect(); let mut globals: Vec<(&Box<str>, &Value)> = env.globals().iter().collect();
globals.sort_by_key(|&(name, _value)| name); globals.sort_by_key(|&(name, _value)| name);

View file

@ -12,7 +12,7 @@ use crate::{LoxClass, Value};
struct LoxObject { struct LoxObject {
class: Rc<LoxClass>, class: Rc<LoxClass>,
attrs: FxHashMap<String, Value>, attrs: FxHashMap<Box<str>, Value>,
} }
impl LoxObject { impl LoxObject {
@ -35,7 +35,7 @@ impl LoxObject {
self.class.get_method(name, this) self.class.get_method(name, this)
} }
fn set(&mut self, name: impl Into<String>, value: Value) { fn set(&mut self, name: impl Into<Box<str>>, value: Value) {
let name = name.into(); let name = name.into();
self.attrs.insert(name, value); self.attrs.insert(name, value);
} }
@ -75,7 +75,7 @@ impl LoxReference {
} }
} }
pub fn set(&mut self, name: impl Into<String>, value: Value) { pub fn set(&mut self, name: impl Into<Box<str>>, value: Value) {
unsafe { unsafe {
let ptr = self.inner.get(); let ptr = self.inner.get();
let object = &mut *ptr; let object = &mut *ptr;
@ -99,7 +99,12 @@ impl Display for LoxReference {
unsafe { unsafe {
let ptr = self.inner.get(); let ptr = self.inner.get();
let object = &*ptr; 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
)
} }
} }
} }

View file

@ -6,7 +6,7 @@ use crate::{LoxError, ResolverError};
/*====================================================================================================================*/ /*====================================================================================================================*/
type ResolverScope = FxHashMap<String, ResolveStatus>; type ResolverScope = FxHashMap<Box<str>, ResolveStatus>;
type ResolverFrame = Vec<ResolverScope>; type ResolverFrame = Vec<ResolverScope>;
/*====================================================================================================================*/ /*====================================================================================================================*/
@ -35,11 +35,11 @@ struct Resolver {
// local_scopes: Vec<ResolverScope>, // local_scopes: Vec<ResolverScope>,
frames: Vec<ResolverFrame>, frames: Vec<ResolverFrame>,
closure_vars: FxHashMap<String, usize>, closure_vars: FxHashMap<Box<str>, usize>,
} }
impl Resolver { impl Resolver {
fn new(global_names: impl Iterator<Item = String>) -> Self { fn new(global_names: impl Iterator<Item = Box<str>>) -> Self {
let mut global_scope = ResolverScope::default(); let mut global_scope = ResolverScope::default();
for name in global_names { for name in global_names {
@ -76,11 +76,14 @@ impl Resolver {
} }
fn pop_frame(&mut self) { 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) { fn declare(&mut self, name: impl Into<Box<str>>) {
let name = name.to_owned(); let name = name.into();
if let Some(local_scope) = self.local_scopes_mut().last_mut() { if let Some(local_scope) = self.local_scopes_mut().last_mut() {
local_scope.insert(name, ResolveStatus::Declared); local_scope.insert(name, ResolveStatus::Declared);
} else { } else {
@ -88,8 +91,9 @@ impl Resolver {
} }
} }
fn define(&mut self, name: &str) { fn define(&mut self, name: impl Into<Box<str>>) {
let name = name.to_owned(); let name = name.into();
if let Some(local_scope) = self.local_scopes_mut().last_mut() { if let Some(local_scope) = self.local_scopes_mut().last_mut() {
local_scope.insert(name, ResolveStatus::Defined); local_scope.insert(name, ResolveStatus::Defined);
} else { } else {
@ -106,38 +110,36 @@ impl Resolver {
} }
fn resolve_var(&mut self, name: &str) -> Result<Expr, ResolverError> { fn resolve_var(&mut self, name: &str) -> Result<Expr, ResolverError> {
let name = name.to_owned();
let mut level = 0; let mut level = 0;
for scope in self.local_scopes().iter().rev() { for scope in self.local_scopes().iter().rev() {
if scope.contains_key(&name) { if scope.contains_key(name) {
return Ok(Expr::LocalVariable { name, level }); return Ok(Expr::local_variable(name, level));
} }
level += 1; level += 1;
} }
for frame in self.frames.iter().rev().skip(1) { for frame in self.frames.iter().rev().skip(1) {
for scope in frame.iter().rev() { for scope in frame.iter().rev() {
if scope.contains_key(&name) { if scope.contains_key(name) {
if !self.closure_vars.contains_key(&name) { if !self.closure_vars.contains_key(name) {
// the level at which the closed-over variable will be collected from // 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 // from the perspective of the parameter/closure scope i.e. the outmost of the function
self.closure_vars 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 // distance from actual variable refernce to parameter/closure scope
level: self.local_scopes().len() - 1, let level = self.local_scopes().len() - 1;
});
return Ok(Expr::local_variable(name, level));
} }
level += 1; level += 1;
} }
} }
if self.global_scope.contains_key(&name) { if self.global_scope.contains_key(name) {
return Ok(Expr::GlobalVariable { name }); return Ok(Expr::global_variable(name));
} }
if name == "this" { if name == "this" {
@ -145,6 +147,7 @@ impl Resolver {
} else if name == "super" { } else if name == "super" {
Err(ResolverError::SuperOutsideMethod) Err(ResolverError::SuperOutsideMethod)
} else { } else {
let name = name.into();
Err(ResolverError::UnresolvableVariable { name }) Err(ResolverError::UnresolvableVariable { name })
} }
} }
@ -170,9 +173,9 @@ impl Resolver {
Ok(()) Ok(())
} }
Stmt::VarDecl { name, initializer } => { Stmt::VarDecl { name, initializer } => {
self.declare(name); self.declare(name.clone());
self.resolve_expr(initializer)?; self.resolve_expr(initializer)?;
self.define(name); self.define(name.clone());
Ok(()) Ok(())
} }
Stmt::Block { statements } => { Stmt::Block { statements } => {
@ -244,7 +247,11 @@ impl Resolver {
self.resolve_expr(target)?; self.resolve_expr(target)?;
Ok(()) Ok(())
} }
Expr::Set { target, name: _, value } => { Expr::Set {
target,
name: _,
value,
} => {
self.resolve_expr(target)?; self.resolve_expr(target)?;
self.resolve_expr(value)?; self.resolve_expr(value)?;
Ok(()) Ok(())
@ -259,12 +266,12 @@ impl Resolver {
self.push_frame(); self.push_frame();
self.declare(name); self.declare(name.clone());
self.define(name); self.define(name.clone());
for param_name in param_names.iter() { for param_name in param_names.iter() {
self.declare(param_name); self.declare(param_name.clone());
self.define(param_name); self.define(param_name.clone());
} }
self.resolve_stmt(body)?; self.resolve_stmt(body)?;
@ -284,13 +291,13 @@ impl Resolver {
name, name,
methods, methods,
} => { } => {
self.declare(name); self.declare(name.clone());
if let Some(superclass) = superclass { if let Some(superclass) = superclass {
self.resolve_expr(superclass)?; self.resolve_expr(superclass)?;
} }
self.define(name); self.define(name.clone());
// this is the scope "this" is defined in // this is the scope "this" is defined in
self.enter_scope(); self.enter_scope();

View file

@ -3,9 +3,9 @@ use thiserror::Error;
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum ResolverError { pub enum ResolverError {
#[error("Can't read variable {name} in its own initializer.")] #[error("Can't read variable {name} in its own initializer.")]
VarInOwnInitializer { name: String }, VarInOwnInitializer { name: Box<str> },
#[error("Variable {name} not defined")] #[error("Variable {name} not defined")]
UnresolvableVariable { name: String }, UnresolvableVariable { name: Box<str> },
#[error("Return outside of function definition")] #[error("Return outside of function definition")]
ReturnOutsideFunction, ReturnOutsideFunction,
#[error("this outside of method")] #[error("this outside of method")]

View file

@ -24,9 +24,12 @@ pub fn run_repl(runtime: &mut Runtime) {
std::process::exit(66); std::process::exit(66);
}); });
let num_open_braces = (input_buf.matches('{').count() as i64) - (input_buf.matches('}').count() as i64); let num_open_braces =
let num_open_parens = (input_buf.matches('(').count() as i64) - (input_buf.matches(')').count() as i64); (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_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 // all braces/parens/brackets closed => break
if num_open_braces == 0 && num_open_parens == 0 && num_open_brackets == 0 { 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(); std::io::stdout().flush().unwrap();
} }
let input_buf = input_buf.trim(); if input_buf.is_empty() || input_buf == "exit\n" || input_buf == "quit\n" {
if input_buf.is_empty() || input_buf == "exit" || input_buf == "quit" {
std::process::exit(0); std::process::exit(0);
} }
let input_buf = input_buf.trim();
match run(input_buf, runtime) { match run(input_buf, runtime) {
Ok(()) => {} Ok(()) => {}
Err(LoxError::Exit { exit_code }) => std::process::exit(exit_code), 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> { pub fn run(source: &str, runtime: &mut Runtime) -> Result<(), LoxError> {
let tokens: Vec<Token> = scan_tokens(source)?; let tokens: Vec<Token> = 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)?; let statements = parse_tokens(tokens)?;
/* for statement in statements.iter() {
println!("{statement}");
} */
for mut statement in statements { for mut statement in statements {
if runtime.debug() {
println!("{statement}");
}
resolve(&mut statement, runtime)?; resolve(&mut statement, runtime)?;
// println!("{statement}"); if runtime.debug() {
println!("{statement}");
}
execute(statement, runtime)?; execute(statement, runtime)?;
} }

View file

@ -1,5 +1,7 @@
use std::cell::RefCell;
use std::fmt::Display; use std::fmt::Display;
use std::io::{stdin, stdout, Read, Write}; use std::io::{stdin, stdout, Read, Write};
use std::rc::Rc;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
@ -9,19 +11,24 @@ use super::lox_std::init_std;
use super::Value; use super::Value;
pub struct Runtime { pub struct Runtime {
globals: FxHashMap<String, Value>, globals: FxHashMap<Box<str>, Value>,
in_stream: Box<dyn std::io::BufRead>, in_stream: Rc<RefCell<dyn std::io::Read>>,
out_stream: Box<dyn std::io::Write>, out_stream: Rc<RefCell<dyn std::io::Write>>,
debug: bool,
} }
impl Runtime { impl Runtime {
pub fn new(in_stream: Box<dyn std::io::Read>, out_stream: Box<dyn std::io::Write>) -> Self { pub fn new(
let in_stream = Box::new(std::io::BufReader::new(in_stream)); in_stream: Rc<RefCell<dyn std::io::Read>>,
out_stream: Rc<RefCell<dyn std::io::Write>>,
) -> Self {
let mut runtime = Runtime { let mut runtime = Runtime {
globals: FxHashMap::default(), globals: FxHashMap::default(),
in_stream, in_stream,
out_stream, out_stream,
debug: false,
}; };
init_std(&mut runtime); init_std(&mut runtime);
@ -29,7 +36,24 @@ impl Runtime {
runtime runtime
} }
pub fn globals(&self) -> &FxHashMap<String, Value> { 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<dyn std::io::Read> {
self.in_stream.as_ref().borrow_mut()
}
pub fn out_stream(&mut self) -> std::cell::RefMut<dyn std::io::Write> {
// &mut self.out_stream
self.out_stream.as_ref().borrow_mut()
}
pub fn globals(&self) -> &FxHashMap<Box<str>, Value> {
&self.globals &self.globals
} }
@ -37,10 +61,12 @@ impl Runtime {
self.globals self.globals
.get(name) .get(name)
.cloned() .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<String>, value: Value) { pub fn define_global(&mut self, name: impl Into<Box<str>>, value: Value) {
let name = name.into(); let name = name.into();
self.globals.insert(name, value); self.globals.insert(name, value);
} }
@ -50,20 +76,30 @@ impl Runtime {
*old_value = value; *old_value = value;
Ok(()) Ok(())
} else { } else {
Err(RuntimeError::GlobalNotDefined { name: name.to_owned() }) Err(RuntimeError::GlobalNotDefined {
name: name.to_owned(),
})
} }
} }
} }
impl Default for Runtime { impl Default for Runtime {
fn default() -> Self { 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 { impl std::fmt::Debug for Runtime {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 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 { impl Drop for Runtime {
fn drop(&mut self) { fn drop(&mut self) {
self.out_stream.flush().unwrap(); self.out_stream().flush().unwrap();
} }
} }
impl Read for Runtime { impl Read for Runtime {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> { fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.in_stream.read(buf) self.in_stream().read(buf)
} }
} }
impl Write for Runtime { impl Write for Runtime {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> { fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.out_stream.write(buf) self.out_stream().write(buf)
} }
fn flush(&mut self) -> std::io::Result<()> { fn flush(&mut self) -> std::io::Result<()> {
self.out_stream.flush() self.out_stream().flush()
} }
} }

View file

@ -13,11 +13,12 @@ pub enum Value {
Class(Rc<LoxClass>), Class(Rc<LoxClass>),
Function(Rc<LoxFunction>), Function(Rc<LoxFunction>),
ExternFunction(Rc<LoxExternFunction>), ExternFunction(Rc<LoxExternFunction>),
String(Rc<String>), String(Box<str>),
Number(f64), Number(f64),
Bool(bool), Bool(bool),
Nil, Nil,
} }
impl Value { impl Value {
pub fn class(class: Rc<LoxClass>) -> Self { pub fn class(class: Rc<LoxClass>) -> Self {
Value::Class(class) Value::Class(class)
@ -33,8 +34,8 @@ impl Value {
Value::ExternFunction(fun) Value::ExternFunction(fun)
} }
pub fn string(s: impl Into<String>) -> Self { pub fn string(s: impl Into<Box<str>>) -> Self {
let s = Rc::new(s.into()); let s = s.into();
Value::String(s) Value::String(s)
} }
@ -50,7 +51,7 @@ impl Display for Value {
Value::Class(class) => write!(f, "{class}"), Value::Class(class) => write!(f, "{class}"),
Value::Function(fun) => write!(f, "{fun}"), Value::Function(fun) => write!(f, "{fun}"),
Value::ExternFunction(ext_fun) => write!(f, "{ext_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::Number(num) => write!(f, "{num}"),
Value::Bool(b) => write!(f, "{b}"), Value::Bool(b) => write!(f, "{b}"),
Value::Nil => write!(f, "nil"), Value::Nil => write!(f, "nil"),
@ -60,7 +61,7 @@ impl Display for Value {
/*====================================================================================================================*/ /*====================================================================================================================*/
#[derive(Clone)] #[derive(Debug, Clone)]
pub struct HeapedValue { pub struct HeapedValue {
inner: Rc<UnsafeCell<Value>>, inner: Rc<UnsafeCell<Value>>,
} }
@ -88,14 +89,11 @@ impl HeapedValue {
} }
} }
impl Debug for HeapedValue { impl AsRef<Value> for HeapedValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn as_ref(&self) -> &Value {
f.debug_struct("HeapValue").field("inner", &self.get_clone()).finish() unsafe {
let ptr = self.inner.get();
&*ptr
} }
} }
impl Display for HeapedValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.get_clone())
}
} }

View file

@ -10,6 +10,9 @@ struct CliArgs {
#[arg(long, action = ArgAction::SetTrue)] #[arg(long, action = ArgAction::SetTrue)]
vm: bool, vm: bool,
#[arg(long, action=ArgAction::SetTrue)]
debug: bool,
} }
/* /*
@ -22,7 +25,8 @@ fn main() {
let cli_args = CliArgs::parse(); let cli_args = CliArgs::parse();
if cli_args.vm { if cli_args.vm {
use rlox2_vm::LoxError; unimplemented!()
/* use rlox2_vm::LoxError;
let mut vm = rlox2_vm::VM::default(); let mut vm = rlox2_vm::VM::default();
@ -35,7 +39,9 @@ fn main() {
if let Err(err) = rlox2_vm::run(&source, &mut vm) { if let Err(err) = rlox2_vm::run(&source, &mut vm) {
eprintln!("{err}"); eprintln!("{err}");
match 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::RuntimeError { .. } => std::process::exit(70),
LoxError::Exit { exit_code } => std::process::exit(exit_code), 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 { } else {
use rlox2_interpreter::LoxError; use rlox2_interpreter::LoxError;
let mut runtime = rlox2_interpreter::Runtime::default(); let mut runtime = rlox2_interpreter::Runtime::default();
runtime.set_debug(cli_args.debug);
if let Some(file_name) = cli_args.file_name { if let Some(file_name) = cli_args.file_name {
let source = std::fs::read_to_string(&file_name).unwrap_or_else(|err| { let source = std::fs::read_to_string(&file_name).unwrap_or_else(|err| {
eprintln!("Reading script file {file_name} failed: {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) { if let Err(err) = rlox2_interpreter::run(&source, &mut runtime) {
eprintln!("{err}"); eprintln!("{err}");
match err { match err {
LoxError::LexerError { .. } | LoxError::ParserError { .. } | LoxError::ResolverError { .. } => { LoxError::LexerError { .. }
std::process::exit(65) | LoxError::ParserError { .. }
} | LoxError::ResolverError { .. } => std::process::exit(65),
LoxError::RuntimeError { .. } => std::process::exit(70), LoxError::RuntimeError { .. } => std::process::exit(70),
LoxError::Exit { exit_code } => std::process::exit(exit_code), LoxError::Exit { exit_code } => std::process::exit(exit_code),
} }