mirror of
https://github.com/MorizzG/rlox.git
synced 2025-12-06 04:12:42 +00:00
updated a bunch of stuff
This commit is contained in:
parent
660464638f
commit
67bb5fe8fd
24 changed files with 683 additions and 702 deletions
428
Cargo.lock
generated
428
Cargo.lock
generated
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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"] }
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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 {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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 },
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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})")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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")]
|
||||||
|
|
|
||||||
|
|
@ -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)?;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
src/main.rs
20
src/main.rs
|
|
@ -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),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue