Begin rewrite with register-based bytecode
This commit is contained in:
parent
974310ffab
commit
7b055d79b5
211
Cargo.lock
generated
211
Cargo.lock
generated
@ -4,9 +4,9 @@ version = 3
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.2"
|
version = "1.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
|
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@ -23,15 +23,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.13"
|
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 = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
|
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"anstyle-parse",
|
"anstyle-parse",
|
||||||
"anstyle-query",
|
"anstyle-query",
|
||||||
"anstyle-wincon",
|
"anstyle-wincon",
|
||||||
"colorchoice",
|
"colorchoice",
|
||||||
|
"is_terminal_polyfill",
|
||||||
"utf8parse",
|
"utf8parse",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -43,32 +44,38 @@ checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-parse"
|
name = "anstyle-parse"
|
||||||
version = "0.2.3"
|
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 = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"utf8parse",
|
"utf8parse",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-query"
|
name = "anstyle-query"
|
||||||
version = "1.0.2"
|
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 = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-wincon"
|
name = "anstyle-wincon"
|
||||||
version = "3.0.2"
|
version = "3.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@ -77,9 +84,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.14"
|
version = "4.5.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c937d4061031a6d0c8da4b9a4f98a172fc2976dfb1c19213a9cf7d0d3c837e36"
|
checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@ -87,9 +94,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.14"
|
version = "4.5.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85379ba512b21a328adf887e85f7742d12e96eb31f3ef077df4ffc26b506ffed"
|
checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@ -117,9 +124,9 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
version = "1.0.0"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colored"
|
name = "colored"
|
||||||
@ -152,9 +159,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.19"
|
version = "0.8.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
|
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dust-lang"
|
name = "dust-lang"
|
||||||
@ -182,15 +189,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.10.0"
|
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 = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "env_filter"
|
name = "env_filter"
|
||||||
version = "0.1.0"
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
|
checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"regex",
|
"regex",
|
||||||
@ -211,9 +218,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.12"
|
version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
@ -233,10 +240,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.0.10"
|
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 = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
|
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
@ -246,9 +259,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.153"
|
version = "0.2.158"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
@ -258,30 +271,33 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.1"
|
version = "2.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.17"
|
version = "0.2.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.79"
|
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 = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
|
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.35"
|
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 = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@ -318,9 +334,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.9.0"
|
version = "1.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd"
|
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"either",
|
"either",
|
||||||
"rayon-core",
|
"rayon-core",
|
||||||
@ -338,9 +354,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.10.3"
|
version = "1.10.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
|
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
@ -350,9 +366,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-automata"
|
name = "regex-automata"
|
||||||
version = "0.4.6"
|
version = "0.4.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
|
checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
@ -361,30 +377,30 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.8.2"
|
version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.17"
|
version = "1.0.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.203"
|
version = "1.0.210"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.203"
|
version = "1.0.210"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -393,11 +409,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.117"
|
version = "1.0.128"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
|
"memchr",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@ -410,9 +427,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.53"
|
version = "2.0.77"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
|
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -421,9 +438,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.12"
|
version = "1.0.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-width"
|
name = "unicode-width"
|
||||||
@ -433,9 +450,9 @@ checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf8parse"
|
name = "utf8parse"
|
||||||
version = "0.2.1"
|
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 = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
@ -458,7 +475,7 @@ 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 = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets 0.52.4",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -478,17 +495,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.52.4"
|
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 = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
|
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm 0.52.4",
|
"windows_aarch64_gnullvm 0.52.6",
|
||||||
"windows_aarch64_msvc 0.52.4",
|
"windows_aarch64_msvc 0.52.6",
|
||||||
"windows_i686_gnu 0.52.4",
|
"windows_i686_gnu 0.52.6",
|
||||||
"windows_i686_msvc 0.52.4",
|
"windows_i686_gnullvm",
|
||||||
"windows_x86_64_gnu 0.52.4",
|
"windows_i686_msvc 0.52.6",
|
||||||
"windows_x86_64_gnullvm 0.52.4",
|
"windows_x86_64_gnu 0.52.6",
|
||||||
"windows_x86_64_msvc 0.52.4",
|
"windows_x86_64_gnullvm 0.52.6",
|
||||||
|
"windows_x86_64_msvc 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -499,9 +517,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.52.4"
|
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 = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
@ -511,9 +529,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.52.4"
|
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 = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
@ -523,9 +541,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.52.4"
|
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 = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
|
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"
|
||||||
@ -535,9 +559,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.52.4"
|
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 = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
@ -547,9 +571,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.52.4"
|
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 = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
@ -559,9 +583,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.52.4"
|
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 = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
@ -571,6 +595,27 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.52.4"
|
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 = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"zerocopy-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zerocopy-derive"
|
||||||
|
version = "0.7.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
@ -4,9 +4,9 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
use crate::{AnnotatedError, Identifier, Instruction, Span, Value};
|
use crate::{AnnotatedError, Identifier, Instruction, Span, Value};
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone)]
|
||||||
pub struct Chunk {
|
pub struct Chunk {
|
||||||
code: Vec<(u8, Span)>,
|
code: Vec<(Instruction, Span)>,
|
||||||
constants: Vec<Option<Value>>,
|
constants: Vec<Option<Value>>,
|
||||||
identifiers: Vec<Local>,
|
identifiers: Vec<Local>,
|
||||||
scope_depth: usize,
|
scope_depth: usize,
|
||||||
@ -23,7 +23,7 @@ impl Chunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_data(
|
pub fn with_data(
|
||||||
code: Vec<(u8, Span)>,
|
code: Vec<(Instruction, Span)>,
|
||||||
constants: Vec<Value>,
|
constants: Vec<Value>,
|
||||||
identifiers: Vec<Local>,
|
identifiers: Vec<Local>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
@ -47,17 +47,21 @@ impl Chunk {
|
|||||||
self.scope_depth
|
self.scope_depth
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_code(&self, offset: usize, position: Span) -> Result<&(u8, Span), ChunkError> {
|
pub fn get_code(
|
||||||
|
&self,
|
||||||
|
offset: usize,
|
||||||
|
position: Span,
|
||||||
|
) -> Result<&(Instruction, Span), ChunkError> {
|
||||||
self.code
|
self.code
|
||||||
.get(offset)
|
.get(offset)
|
||||||
.ok_or(ChunkError::CodeIndexOfBounds { offset, position })
|
.ok_or(ChunkError::CodeIndexOfBounds { offset, position })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_code<T: Into<u8>>(&mut self, into_byte: T, position: Span) {
|
pub fn push_code(&mut self, instruction: Instruction, position: Span) {
|
||||||
self.code.push((into_byte.into(), position));
|
self.code.push((instruction, position));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_constant(&self, index: u8, position: Span) -> Result<&Value, ChunkError> {
|
pub fn get_constant(&self, index: u16, position: Span) -> Result<&Value, ChunkError> {
|
||||||
self.constants
|
self.constants
|
||||||
.get(index as usize)
|
.get(index as usize)
|
||||||
.ok_or(ChunkError::ConstantIndexOutOfBounds { index, position })
|
.ok_or(ChunkError::ConstantIndexOutOfBounds { index, position })
|
||||||
@ -68,23 +72,15 @@ impl Chunk {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_constant(&mut self, index: u8, position: Span) -> Result<Value, ChunkError> {
|
pub fn use_constant(&mut self, index: u16, position: Span) -> Result<Value, ChunkError> {
|
||||||
let index = index as usize;
|
|
||||||
|
|
||||||
self.constants
|
self.constants
|
||||||
.get_mut(index)
|
.get_mut(index as usize)
|
||||||
.ok_or_else(|| ChunkError::ConstantIndexOutOfBounds {
|
.ok_or_else(|| ChunkError::ConstantIndexOutOfBounds { index, position })?
|
||||||
index: index as u8,
|
|
||||||
position,
|
|
||||||
})?
|
|
||||||
.take()
|
.take()
|
||||||
.ok_or(ChunkError::ConstantAlreadyUsed {
|
.ok_or(ChunkError::ConstantAlreadyUsed { index, position })
|
||||||
index: index as u8,
|
|
||||||
position,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_constant(&mut self, value: Value, position: Span) -> Result<u8, ChunkError> {
|
pub fn push_constant(&mut self, value: Value, position: Span) -> Result<u16, ChunkError> {
|
||||||
let starting_length = self.constants.len();
|
let starting_length = self.constants.len();
|
||||||
|
|
||||||
if starting_length + 1 > (u8::MAX as usize) {
|
if starting_length + 1 > (u8::MAX as usize) {
|
||||||
@ -92,7 +88,7 @@ impl Chunk {
|
|||||||
} else {
|
} else {
|
||||||
self.constants.push(Some(value));
|
self.constants.push(Some(value));
|
||||||
|
|
||||||
Ok(starting_length as u8)
|
Ok(starting_length as u16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,7 +98,7 @@ impl Chunk {
|
|||||||
.any(|local| &local.identifier == identifier)
|
.any(|local| &local.identifier == identifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_local(&self, index: u8, position: Span) -> Result<&Local, ChunkError> {
|
pub fn get_local(&self, index: u16, position: Span) -> Result<&Local, ChunkError> {
|
||||||
self.identifiers
|
self.identifiers
|
||||||
.get(index as usize)
|
.get(index as usize)
|
||||||
.ok_or(ChunkError::IdentifierIndexOutOfBounds { index, position })
|
.ok_or(ChunkError::IdentifierIndexOutOfBounds { index, position })
|
||||||
@ -120,14 +116,14 @@ impl Chunk {
|
|||||||
&self,
|
&self,
|
||||||
identifier: &Identifier,
|
identifier: &Identifier,
|
||||||
position: Span,
|
position: Span,
|
||||||
) -> Result<u8, ChunkError> {
|
) -> Result<u16, ChunkError> {
|
||||||
self.identifiers
|
self.identifiers
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find_map(|(index, local)| {
|
.find_map(|(index, local)| {
|
||||||
if &local.identifier == identifier {
|
if &local.identifier == identifier {
|
||||||
Some(index as u8)
|
Some(index as u16)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -142,7 +138,7 @@ impl Chunk {
|
|||||||
&mut self,
|
&mut self,
|
||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
position: Span,
|
position: Span,
|
||||||
) -> Result<u8, ChunkError> {
|
) -> Result<u16, ChunkError> {
|
||||||
let starting_length = self.identifiers.len();
|
let starting_length = self.identifiers.len();
|
||||||
|
|
||||||
if starting_length + 1 > (u8::MAX as usize) {
|
if starting_length + 1 > (u8::MAX as usize) {
|
||||||
@ -153,7 +149,7 @@ impl Chunk {
|
|||||||
depth: self.scope_depth,
|
depth: self.scope_depth,
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(starting_length as u8)
|
Ok(starting_length as u16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,32 +179,19 @@ impl Chunk {
|
|||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
|
|
||||||
let name_length = name.len();
|
let name_length = name.len();
|
||||||
let buffer_length = 32_usize.saturating_sub(name_length + 2);
|
let buffer_length = 34_usize.saturating_sub(name_length + 2);
|
||||||
let name_buffer = " ".repeat(buffer_length / 2);
|
let name_buffer = " ".repeat(buffer_length / 2);
|
||||||
let name_line = format!("{name_buffer} {name} {name_buffer}\n");
|
let name_line = format!("\n{name_buffer}{name}{name_buffer}\n");
|
||||||
|
let name_underline = format!("{name_buffer}{}{name_buffer}\n", "-".repeat(name_length));
|
||||||
|
|
||||||
output.push_str(&name_line);
|
output.push_str(&name_line);
|
||||||
|
output.push_str(&name_underline);
|
||||||
output.push_str("\n Code \n");
|
output.push_str("\n Code \n");
|
||||||
output.push_str("------ ------------ ------------\n");
|
output.push_str("------ ------------ ------------\n");
|
||||||
output.push_str("OFFSET POSITION INSTRUCTION\n");
|
output.push_str("OFFSET POSITION INSTRUCTION\n");
|
||||||
output.push_str("------ ------------ ------------\n");
|
output.push_str("------ ------------ ------------\n");
|
||||||
|
|
||||||
let mut previous = None;
|
for (offset, (instruction, position)) in self.code.iter().enumerate() {
|
||||||
|
|
||||||
for (offset, (byte, position)) in self.code.iter().enumerate() {
|
|
||||||
if let Some(
|
|
||||||
Instruction::Constant
|
|
||||||
| Instruction::DeclareVariable
|
|
||||||
| Instruction::GetVariable
|
|
||||||
| Instruction::SetVariable,
|
|
||||||
) = previous
|
|
||||||
{
|
|
||||||
previous = None;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let instruction = Instruction::from_byte(*byte).unwrap();
|
|
||||||
let display = format!(
|
let display = format!(
|
||||||
"{offset:4} {:12} {}\n",
|
"{offset:4} {:12} {}\n",
|
||||||
position.to_string(),
|
position.to_string(),
|
||||||
@ -216,8 +199,6 @@ impl Chunk {
|
|||||||
);
|
);
|
||||||
|
|
||||||
output.push_str(&display);
|
output.push_str(&display);
|
||||||
|
|
||||||
previous = Some(instruction);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
output.push_str("\n Constants\n");
|
output.push_str("\n Constants\n");
|
||||||
@ -296,18 +277,18 @@ pub enum ChunkError {
|
|||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
ConstantAlreadyUsed {
|
ConstantAlreadyUsed {
|
||||||
index: u8,
|
index: u16,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
ConstantOverflow {
|
ConstantOverflow {
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
ConstantIndexOutOfBounds {
|
ConstantIndexOutOfBounds {
|
||||||
index: u8,
|
index: u16,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
IdentifierIndexOutOfBounds {
|
IdentifierIndexOutOfBounds {
|
||||||
index: u8,
|
index: u16,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
IdentifierOverflow {
|
IdentifierOverflow {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use annotate_snippets::{Level, Renderer, Snippet};
|
use annotate_snippets::{Level, Renderer, Snippet};
|
||||||
|
|
||||||
use crate::{vm::VmError, LexError, ParseError, Span};
|
use crate::{LexError, ParseError, Span};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum DustError<'src> {
|
pub enum DustError<'src> {
|
||||||
@ -12,10 +12,6 @@ pub enum DustError<'src> {
|
|||||||
error: ParseError,
|
error: ParseError,
|
||||||
source: &'src str,
|
source: &'src str,
|
||||||
},
|
},
|
||||||
Runtime {
|
|
||||||
error: VmError,
|
|
||||||
source: &'src str,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> DustError<'src> {
|
impl<'src> DustError<'src> {
|
||||||
@ -24,20 +20,6 @@ impl<'src> DustError<'src> {
|
|||||||
let renderer = Renderer::styled();
|
let renderer = Renderer::styled();
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
DustError::Runtime { error, source } => {
|
|
||||||
let position = error.position();
|
|
||||||
let label = format!("Runtime error: {}", error.description());
|
|
||||||
let details = error
|
|
||||||
.details()
|
|
||||||
.unwrap_or_else(|| "While running this code".to_string());
|
|
||||||
let message = Level::Error.title(&label).snippet(
|
|
||||||
Snippet::source(source)
|
|
||||||
.fold(true)
|
|
||||||
.annotation(Level::Error.span(position.0..position.1).label(&details)),
|
|
||||||
);
|
|
||||||
|
|
||||||
report.push_str(&renderer.render(message).to_string());
|
|
||||||
}
|
|
||||||
DustError::Parse { error, source } => {
|
DustError::Parse { error, source } => {
|
||||||
let position = error.position();
|
let position = error.position();
|
||||||
let label = format!("Parse error: {}", error.description());
|
let label = format!("Parse error: {}", error.description());
|
||||||
|
@ -1,141 +1,214 @@
|
|||||||
use std::fmt::{self, Display, Formatter};
|
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{Chunk, Span};
|
use crate::{Chunk, Span};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub enum Instruction {
|
pub struct Instruction {
|
||||||
Constant = 0,
|
opcode: OpCode,
|
||||||
Return = 1,
|
to_register: u8,
|
||||||
Pop = 2,
|
arguments: [u8; 2],
|
||||||
|
|
||||||
// Variables
|
|
||||||
DeclareVariable = 3,
|
|
||||||
GetVariable = 4,
|
|
||||||
SetVariable = 5,
|
|
||||||
|
|
||||||
// Unary
|
|
||||||
Negate = 6,
|
|
||||||
Not = 7,
|
|
||||||
|
|
||||||
// Binary
|
|
||||||
Add = 8,
|
|
||||||
Subtract = 9,
|
|
||||||
Multiply = 10,
|
|
||||||
Divide = 11,
|
|
||||||
Greater = 12,
|
|
||||||
Less = 13,
|
|
||||||
GreaterEqual = 14,
|
|
||||||
LessEqual = 15,
|
|
||||||
Equal = 16,
|
|
||||||
NotEqual = 17,
|
|
||||||
And = 18,
|
|
||||||
Or = 19,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instruction {
|
impl Instruction {
|
||||||
pub fn from_byte(byte: u8) -> Option<Self> {
|
pub fn r#move(to_register: u8, from_register: u8) -> Instruction {
|
||||||
match byte {
|
Instruction {
|
||||||
0 => Some(Instruction::Constant),
|
opcode: OpCode::Move,
|
||||||
1 => Some(Instruction::Return),
|
to_register,
|
||||||
2 => Some(Instruction::Pop),
|
arguments: [from_register, 0],
|
||||||
3 => Some(Instruction::DeclareVariable),
|
}
|
||||||
4 => Some(Instruction::GetVariable),
|
}
|
||||||
5 => Some(Instruction::SetVariable),
|
|
||||||
6 => Some(Instruction::Negate),
|
pub fn close(to_register: u8) -> Instruction {
|
||||||
7 => Some(Instruction::Not),
|
Instruction {
|
||||||
8 => Some(Instruction::Add),
|
opcode: OpCode::Close,
|
||||||
9 => Some(Instruction::Subtract),
|
to_register,
|
||||||
10 => Some(Instruction::Multiply),
|
arguments: [0, 0],
|
||||||
11 => Some(Instruction::Divide),
|
}
|
||||||
12 => Some(Instruction::Greater),
|
}
|
||||||
13 => Some(Instruction::Less),
|
|
||||||
14 => Some(Instruction::GreaterEqual),
|
pub fn load_constant(to_register: u8, constant_index: u16) -> Instruction {
|
||||||
15 => Some(Instruction::LessEqual),
|
Instruction {
|
||||||
16 => Some(Instruction::Equal),
|
opcode: OpCode::LoadConstant,
|
||||||
17 => Some(Instruction::NotEqual),
|
to_register,
|
||||||
18 => Some(Instruction::And),
|
arguments: constant_index.to_le_bytes(),
|
||||||
19 => Some(Instruction::Or),
|
}
|
||||||
_ => None,
|
}
|
||||||
|
|
||||||
|
pub fn declare_variable(to_register: u8, variable_index: u16) -> Instruction {
|
||||||
|
Instruction {
|
||||||
|
opcode: OpCode::DeclareVariable,
|
||||||
|
to_register,
|
||||||
|
arguments: variable_index.to_le_bytes(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_variable(to_register: u8, variable_index: u16) -> Instruction {
|
||||||
|
Instruction {
|
||||||
|
opcode: OpCode::GetVariable,
|
||||||
|
to_register,
|
||||||
|
arguments: variable_index.to_le_bytes(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_variable(from_register: u8, variable_index: u16) -> Instruction {
|
||||||
|
Instruction {
|
||||||
|
opcode: OpCode::SetVariable,
|
||||||
|
to_register: from_register,
|
||||||
|
arguments: variable_index.to_le_bytes(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add(to_register: u8, left_register: u8, right_register: u8) -> Instruction {
|
||||||
|
Instruction {
|
||||||
|
opcode: OpCode::Add,
|
||||||
|
to_register,
|
||||||
|
arguments: [left_register, right_register],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn subtract(to_register: u8, left_register: u8, right_register: u8) -> Instruction {
|
||||||
|
Instruction {
|
||||||
|
opcode: OpCode::Subtract,
|
||||||
|
to_register,
|
||||||
|
arguments: [left_register, right_register],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn multiply(to_register: u8, left_register: u8, right_register: u8) -> Instruction {
|
||||||
|
Instruction {
|
||||||
|
opcode: OpCode::Multiply,
|
||||||
|
to_register,
|
||||||
|
arguments: [left_register, right_register],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn divide(to_register: u8, left_register: u8, right_register: u8) -> Instruction {
|
||||||
|
Instruction {
|
||||||
|
opcode: OpCode::Divide,
|
||||||
|
to_register,
|
||||||
|
arguments: [left_register, right_register],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn negate(to_register: u8, from_register: u8) -> Instruction {
|
||||||
|
Instruction {
|
||||||
|
opcode: OpCode::Negate,
|
||||||
|
to_register,
|
||||||
|
arguments: [from_register, 0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn r#return() -> Instruction {
|
||||||
|
Instruction {
|
||||||
|
opcode: OpCode::Return,
|
||||||
|
to_register: 0,
|
||||||
|
arguments: [0, 0],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn disassemble(&self, chunk: &Chunk, offset: usize) -> String {
|
pub fn disassemble(&self, chunk: &Chunk, offset: usize) -> String {
|
||||||
let dummy_position = Span(0, 0);
|
match self.opcode {
|
||||||
|
OpCode::Move => format!(
|
||||||
match self {
|
"{:04} MOVE R{} R{}",
|
||||||
Instruction::Constant => {
|
offset, self.to_register, self.arguments[0]
|
||||||
let (argument, position) = *chunk.get_code(offset + 1, dummy_position).unwrap();
|
),
|
||||||
let value_display = chunk
|
OpCode::Close => {
|
||||||
.get_constant(argument, position)
|
format!("{:04} CLOSE R{}", offset, self.to_register)
|
||||||
.map(|value| value.to_string())
|
|
||||||
.unwrap_or_else(|error| format!("{error:?}"));
|
|
||||||
|
|
||||||
format!("CONSTANT {value_display}")
|
|
||||||
}
|
}
|
||||||
Instruction::Return => "RETURN".to_string(),
|
OpCode::LoadConstant => {
|
||||||
Instruction::Pop => "POP".to_string(),
|
let constant_index = u16::from_le_bytes(self.arguments);
|
||||||
|
let constant_display = match chunk.get_constant(constant_index, Span(0, 0)) {
|
||||||
|
Ok(value) => value.to_string(),
|
||||||
|
Err(error) => format!("{:?}", error),
|
||||||
|
};
|
||||||
|
|
||||||
|
format!(
|
||||||
|
"{:04} LOAD_CONSTANT R{} C{} {}",
|
||||||
|
offset, self.to_register, constant_index, constant_display
|
||||||
|
)
|
||||||
|
}
|
||||||
|
OpCode::DeclareVariable => {
|
||||||
|
let variable_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]);
|
||||||
|
|
||||||
|
format!(
|
||||||
|
"{:04} DECLARE_VARIABLE V{} R{}",
|
||||||
|
offset, variable_index, self.to_register
|
||||||
|
)
|
||||||
|
}
|
||||||
|
OpCode::GetVariable => {
|
||||||
|
let variable_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]);
|
||||||
|
|
||||||
|
format!(
|
||||||
|
"{:04} GET_VARIABLE R{} V{}",
|
||||||
|
offset, self.to_register, variable_index
|
||||||
|
)
|
||||||
|
}
|
||||||
|
OpCode::SetVariable => {
|
||||||
|
let variable_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]);
|
||||||
|
|
||||||
|
format!(
|
||||||
|
"{:04} SET_VARIABLE V{} R{}",
|
||||||
|
offset, variable_index, self.to_register
|
||||||
|
)
|
||||||
|
}
|
||||||
|
OpCode::Add => format!(
|
||||||
|
"{:04} ADD R{} = R{} + R{}",
|
||||||
|
offset, self.to_register, self.arguments[0], self.arguments[1]
|
||||||
|
),
|
||||||
|
OpCode::Subtract => format!(
|
||||||
|
"{:04} SUBTRACT R{} = R{} - R{}",
|
||||||
|
offset, self.to_register, self.arguments[0], self.arguments[1]
|
||||||
|
),
|
||||||
|
OpCode::Multiply => format!(
|
||||||
|
"{:04} MULTIPLY R{} = R{} * R{}",
|
||||||
|
offset, self.to_register, self.arguments[0], self.arguments[1]
|
||||||
|
),
|
||||||
|
OpCode::Divide => format!(
|
||||||
|
"{:04} DIVIDE R{} = R{} / R{}",
|
||||||
|
offset, self.to_register, self.arguments[0], self.arguments[1]
|
||||||
|
),
|
||||||
|
OpCode::Negate => format!(
|
||||||
|
"{:04} NEGATE R{} = !R{}",
|
||||||
|
offset, self.to_register, self.arguments[0]
|
||||||
|
),
|
||||||
|
OpCode::Return => format!("{:04} RETURN", offset),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
enum OpCode {
|
||||||
|
// Stack manipulation
|
||||||
|
Move,
|
||||||
|
Close,
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
LoadConstant,
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
Instruction::DeclareVariable => {
|
DeclareVariable,
|
||||||
let (argument, _) = chunk.get_code(offset + 1, dummy_position).unwrap();
|
GetVariable,
|
||||||
let identifier_display = chunk
|
SetVariable,
|
||||||
.get_identifier(*argument)
|
|
||||||
.map(|identifier| identifier.to_string())
|
|
||||||
.unwrap_or_else(|| "ERROR".to_string());
|
|
||||||
|
|
||||||
format!("DECLARE_VARIABLE {identifier_display}")
|
// Binary operations
|
||||||
}
|
Add,
|
||||||
Instruction::GetVariable => {
|
Subtract,
|
||||||
let (argument, _) = chunk.get_code(offset + 1, dummy_position).unwrap();
|
Multiply,
|
||||||
let identifier_display = chunk
|
Divide,
|
||||||
.get_identifier(*argument)
|
|
||||||
.map(|identifier| identifier.to_string())
|
|
||||||
.unwrap_or_else(|| "ERROR".to_string());
|
|
||||||
|
|
||||||
format!("GET_VARIABLE {identifier_display}")
|
// Unary operations
|
||||||
|
Negate,
|
||||||
|
|
||||||
|
// Control flow
|
||||||
|
Return,
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::SetVariable => {
|
#[cfg(test)]
|
||||||
let (argument, _) = chunk.get_code(offset + 1, dummy_position).unwrap();
|
mod tests {
|
||||||
let identifier_display = chunk
|
use std::mem::size_of;
|
||||||
.get_identifier(*argument)
|
|
||||||
.map(|identifier| identifier.to_string())
|
|
||||||
.unwrap_or_else(|| "ERROR".to_string());
|
|
||||||
|
|
||||||
format!("SET_VARIABLE {identifier_display}")
|
use super::*;
|
||||||
}
|
|
||||||
|
|
||||||
// Unary
|
#[test]
|
||||||
Instruction::Negate => "NEGATE".to_string(),
|
fn instruction_is_32_bits() {
|
||||||
Instruction::Not => "NOT".to_string(),
|
assert_eq!(size_of::<Instruction>(), 4);
|
||||||
|
|
||||||
// Binary
|
|
||||||
Instruction::Add => "ADD".to_string(),
|
|
||||||
Instruction::Subtract => "SUBTRACT".to_string(),
|
|
||||||
Instruction::Multiply => "MULTIPLY".to_string(),
|
|
||||||
Instruction::Divide => "DIVIDE".to_string(),
|
|
||||||
Instruction::Greater => "GREATER".to_string(),
|
|
||||||
Instruction::Less => "LESS".to_string(),
|
|
||||||
Instruction::GreaterEqual => "GREATER_EQUAL".to_string(),
|
|
||||||
Instruction::LessEqual => "LESS_EQUAL".to_string(),
|
|
||||||
Instruction::Equal => "EQUAL".to_string(),
|
|
||||||
Instruction::NotEqual => "NOT_EQUAL".to_string(),
|
|
||||||
Instruction::And => "AND".to_string(),
|
|
||||||
Instruction::Or => "OR".to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Instruction {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{self:?}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Instruction> for u8 {
|
|
||||||
fn from(instruction: Instruction) -> Self {
|
|
||||||
instruction as u8
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,34 +1,18 @@
|
|||||||
//! The Dust programming language.
|
mod chunk;
|
||||||
//!
|
mod constructor;
|
||||||
//! To get started, you can use the `run` function to run a Dust program.
|
mod dust_error;
|
||||||
//!
|
mod identifier;
|
||||||
//! ```rust
|
mod instruction;
|
||||||
//! use dust_lang::{run, Value};
|
mod lexer;
|
||||||
//!
|
mod parser;
|
||||||
//! let program = "
|
mod token;
|
||||||
//! let foo = 21
|
mod r#type;
|
||||||
//! let bar = 2
|
mod value;
|
||||||
//! foo * bar
|
|
||||||
//! ";
|
|
||||||
//!
|
|
||||||
//! let the_answer = run(program).unwrap();
|
|
||||||
//!
|
|
||||||
//! assert_eq!(the_answer, Some(Value::integer(42)));
|
|
||||||
//! ```
|
|
||||||
pub mod chunk;
|
|
||||||
pub mod constructor;
|
|
||||||
pub mod dust_error;
|
|
||||||
pub mod identifier;
|
|
||||||
pub mod instruction;
|
|
||||||
pub mod lexer;
|
|
||||||
pub mod parser;
|
|
||||||
pub mod token;
|
|
||||||
pub mod r#type;
|
|
||||||
pub mod value;
|
|
||||||
pub mod vm;
|
|
||||||
|
|
||||||
pub use chunk::{Chunk, ChunkError, Local};
|
use std::fmt::Display;
|
||||||
pub use constructor::{ConstructError, Constructor};
|
|
||||||
|
pub use chunk::{Chunk, ChunkError};
|
||||||
|
pub use constructor::Constructor;
|
||||||
pub use dust_error::{AnnotatedError, DustError};
|
pub use dust_error::{AnnotatedError, DustError};
|
||||||
pub use identifier::Identifier;
|
pub use identifier::Identifier;
|
||||||
pub use instruction::Instruction;
|
pub use instruction::Instruction;
|
||||||
@ -36,18 +20,13 @@ pub use lexer::{lex, LexError, Lexer};
|
|||||||
pub use parser::{parse, ParseError, Parser};
|
pub use parser::{parse, ParseError, Parser};
|
||||||
pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict};
|
pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict};
|
||||||
pub use token::{Token, TokenKind, TokenOwned};
|
pub use token::{Token, TokenKind, TokenOwned};
|
||||||
pub use value::{Struct, Value, ValueError};
|
pub use value::{Enum, Function, Struct, Value};
|
||||||
pub use vm::{run, Vm};
|
|
||||||
|
|
||||||
use std::fmt::{self, Display, Formatter};
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
|
||||||
pub struct Span(pub usize, pub usize);
|
pub struct Span(pub usize, pub usize);
|
||||||
|
|
||||||
impl Display for Span {
|
impl Display for Span {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "({}, {})", self.0, self.1)
|
write!(f, "({}, {})", self.0, self.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
mem,
|
mem,
|
||||||
@ -24,12 +27,13 @@ pub fn parse(source: &str) -> Result<Chunk, DustError> {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Parser<'src> {
|
pub struct Parser<'src> {
|
||||||
lexer: Lexer<'src>,
|
|
||||||
chunk: Chunk,
|
chunk: Chunk,
|
||||||
previous_token: Token<'src>,
|
lexer: Lexer<'src>,
|
||||||
previous_position: Span,
|
current_register: u8,
|
||||||
current_token: Token<'src>,
|
current_token: Token<'src>,
|
||||||
current_position: Span,
|
current_position: Span,
|
||||||
|
previous_token: Token<'src>,
|
||||||
|
previous_position: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'src> Parser<'src> {
|
impl<'src> Parser<'src> {
|
||||||
@ -42,10 +46,11 @@ impl<'src> Parser<'src> {
|
|||||||
Parser {
|
Parser {
|
||||||
lexer,
|
lexer,
|
||||||
chunk: Chunk::new(),
|
chunk: Chunk::new(),
|
||||||
previous_token: Token::Eof,
|
current_register: 0,
|
||||||
previous_position: Span(0, 0),
|
|
||||||
current_token,
|
current_token,
|
||||||
current_position,
|
current_position,
|
||||||
|
previous_token: Token::Eof,
|
||||||
|
previous_position: Span(0, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +58,20 @@ impl<'src> Parser<'src> {
|
|||||||
matches!(self.current_token, Token::Eof)
|
matches!(self.current_token, Token::Eof)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn increment_register(&mut self) -> Result<(), ParseError> {
|
||||||
|
let current = self.current_register;
|
||||||
|
|
||||||
|
if current == u8::MAX {
|
||||||
|
Err(ParseError::RegisterOverflow {
|
||||||
|
position: self.current_position,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.current_register += 1;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn advance(&mut self) -> Result<(), ParseError> {
|
fn advance(&mut self) -> Result<(), ParseError> {
|
||||||
if self.is_eof() {
|
if self.is_eof() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -90,16 +109,19 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_byte<T: Into<u8>>(&mut self, into_byte: T, position: Span) {
|
fn emit_instruction(&mut self, instruction: Instruction, position: Span) {
|
||||||
self.chunk.push_code(into_byte.into(), position);
|
self.chunk.push_code(instruction, position);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_constant(&mut self, value: Value) -> Result<(), ParseError> {
|
fn emit_constant(&mut self, value: Value) -> Result<(), ParseError> {
|
||||||
let position = self.previous_position;
|
let position = self.previous_position;
|
||||||
let constant_index = self.chunk.push_constant(value, position)?;
|
let constant_index = self.chunk.push_constant(value, position)?;
|
||||||
|
|
||||||
self.emit_byte(Instruction::Constant, position);
|
self.emit_instruction(
|
||||||
self.emit_byte(constant_index, position);
|
Instruction::load_constant(self.current_register, constant_index),
|
||||||
|
position,
|
||||||
|
);
|
||||||
|
self.increment_register()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -180,7 +202,9 @@ impl<'src> Parser<'src> {
|
|||||||
fn parse_unary(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
|
fn parse_unary(&mut self, _allow_assignment: bool) -> Result<(), ParseError> {
|
||||||
let operator_position = self.previous_position;
|
let operator_position = self.previous_position;
|
||||||
let byte = match self.previous_token.kind() {
|
let byte = match self.previous_token.kind() {
|
||||||
TokenKind::Minus => Instruction::Negate,
|
TokenKind::Minus => {
|
||||||
|
Instruction::negate(self.current_register, self.current_register - 1)
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ParseError::ExpectedTokenMultiple {
|
return Err(ParseError::ExpectedTokenMultiple {
|
||||||
expected: vec![TokenKind::Minus],
|
expected: vec![TokenKind::Minus],
|
||||||
@ -191,7 +215,7 @@ impl<'src> Parser<'src> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
self.emit_byte(byte, operator_position);
|
self.emit_instruction(byte, operator_position);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -205,12 +229,18 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
self.parse(rule.precedence.increment())?;
|
self.parse(rule.precedence.increment())?;
|
||||||
|
|
||||||
|
let to_register = if self.current_register < 2 {
|
||||||
|
self.current_register + 2
|
||||||
|
} else {
|
||||||
|
self.current_register
|
||||||
|
};
|
||||||
|
let left_register = to_register - 1;
|
||||||
|
let right_register = to_register - 2;
|
||||||
let byte = match operator {
|
let byte = match operator {
|
||||||
TokenKind::Plus => Instruction::Add,
|
TokenKind::Plus => Instruction::add(to_register, left_register, right_register),
|
||||||
TokenKind::Minus => Instruction::Subtract,
|
TokenKind::Minus => Instruction::subtract(to_register, left_register, right_register),
|
||||||
TokenKind::Star => Instruction::Multiply,
|
TokenKind::Star => Instruction::multiply(to_register, left_register, right_register),
|
||||||
TokenKind::Slash => Instruction::Divide,
|
TokenKind::Slash => Instruction::divide(to_register, left_register, right_register),
|
||||||
TokenKind::DoubleAmpersand => Instruction::And,
|
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ParseError::ExpectedTokenMultiple {
|
return Err(ParseError::ExpectedTokenMultiple {
|
||||||
expected: vec![
|
expected: vec![
|
||||||
@ -225,7 +255,7 @@ impl<'src> Parser<'src> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
self.emit_byte(byte, operator_position);
|
self.emit_instruction(byte, operator_position);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -240,11 +270,17 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
if allow_assignment && self.allow(TokenKind::Equal)? {
|
if allow_assignment && self.allow(TokenKind::Equal)? {
|
||||||
self.parse_expression()?;
|
self.parse_expression()?;
|
||||||
self.emit_byte(Instruction::SetVariable, self.previous_position);
|
|
||||||
self.emit_byte(identifier_index, self.previous_position);
|
self.emit_instruction(
|
||||||
|
Instruction::set_variable(self.current_register, identifier_index),
|
||||||
|
self.previous_position,
|
||||||
|
);
|
||||||
|
self.increment_register()?;
|
||||||
} else {
|
} else {
|
||||||
self.emit_byte(Instruction::GetVariable, self.previous_position);
|
self.emit_instruction(
|
||||||
self.emit_byte(identifier_index, self.previous_position);
|
Instruction::get_variable(self.current_register - 1, identifier_index),
|
||||||
|
self.previous_position,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -254,7 +290,7 @@ impl<'src> Parser<'src> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
token: TokenOwned,
|
token: TokenOwned,
|
||||||
position: Span,
|
position: Span,
|
||||||
) -> Result<u8, ParseError> {
|
) -> Result<u16, ParseError> {
|
||||||
if let TokenOwned::Identifier(text) = token {
|
if let TokenOwned::Identifier(text) = token {
|
||||||
let identifier = Identifier::new(text);
|
let identifier = Identifier::new(text);
|
||||||
|
|
||||||
@ -291,8 +327,10 @@ impl<'src> Parser<'src> {
|
|||||||
.next_back()
|
.next_back()
|
||||||
.map_or(false, |local| local.depth > self.chunk.scope_depth())
|
.map_or(false, |local| local.depth > self.chunk.scope_depth())
|
||||||
{
|
{
|
||||||
self.emit_byte(Instruction::Pop, self.current_position);
|
self.emit_instruction(
|
||||||
self.chunk.pop_identifier();
|
Instruction::close(self.current_register),
|
||||||
|
self.current_position,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -326,7 +364,7 @@ impl<'src> Parser<'src> {
|
|||||||
if is_expression_statement && !contains_block && !has_semicolon {
|
if is_expression_statement && !contains_block && !has_semicolon {
|
||||||
let end = self.previous_position.1;
|
let end = self.previous_position.1;
|
||||||
|
|
||||||
self.emit_byte(Instruction::Return, Span(start, end))
|
self.emit_instruction(Instruction::r#return(), Span(start, end))
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -353,8 +391,11 @@ impl<'src> Parser<'src> {
|
|||||||
|
|
||||||
let identifier_index = self.chunk.declare_variable(identifier, position)?;
|
let identifier_index = self.chunk.declare_variable(identifier, position)?;
|
||||||
|
|
||||||
self.emit_byte(Instruction::DeclareVariable, position);
|
self.emit_instruction(
|
||||||
self.emit_byte(identifier_index, position);
|
Instruction::set_variable(self.current_register, identifier_index),
|
||||||
|
position,
|
||||||
|
);
|
||||||
|
self.increment_register()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -618,6 +659,9 @@ pub enum ParseError {
|
|||||||
identifier: Identifier,
|
identifier: Identifier,
|
||||||
position: Span,
|
position: Span,
|
||||||
},
|
},
|
||||||
|
RegisterOverflow {
|
||||||
|
position: Span,
|
||||||
|
},
|
||||||
|
|
||||||
// Wrappers around foreign errors
|
// Wrappers around foreign errors
|
||||||
Chunk(ChunkError),
|
Chunk(ChunkError),
|
||||||
@ -646,6 +690,7 @@ impl AnnotatedError for ParseError {
|
|||||||
Self::ExpectedTokenMultiple { .. } => "Expected one of multiple tokens",
|
Self::ExpectedTokenMultiple { .. } => "Expected one of multiple tokens",
|
||||||
Self::InvalidAssignmentTarget { .. } => "Invalid assignment target",
|
Self::InvalidAssignmentTarget { .. } => "Invalid assignment target",
|
||||||
Self::UndefinedVariable { .. } => "Undefined variable",
|
Self::UndefinedVariable { .. } => "Undefined variable",
|
||||||
|
Self::RegisterOverflow { .. } => "Register overflow",
|
||||||
Self::Chunk { .. } => "Chunk error",
|
Self::Chunk { .. } => "Chunk error",
|
||||||
Self::Lex(_) => "Lex error",
|
Self::Lex(_) => "Lex error",
|
||||||
Self::ParseIntError { .. } => "Failed to parse integer",
|
Self::ParseIntError { .. } => "Failed to parse integer",
|
||||||
@ -654,9 +699,7 @@ impl AnnotatedError for ParseError {
|
|||||||
|
|
||||||
fn details(&self) -> Option<String> {
|
fn details(&self) -> Option<String> {
|
||||||
match self {
|
match self {
|
||||||
Self::ExpectedExpression { found, .. } => {
|
Self::ExpectedExpression { found, .. } => Some(format!("Found \"{found}\"")),
|
||||||
Some(format!("Expected an expression, found \"{found}\""))
|
|
||||||
}
|
|
||||||
Self::ExpectedToken {
|
Self::ExpectedToken {
|
||||||
expected, found, ..
|
expected, found, ..
|
||||||
} => Some(format!("Expected \"{expected}\", found \"{found}\"")),
|
} => Some(format!("Expected \"{expected}\", found \"{found}\"")),
|
||||||
@ -664,11 +707,12 @@ impl AnnotatedError for ParseError {
|
|||||||
expected, found, ..
|
expected, found, ..
|
||||||
} => Some(format!("Expected one of {expected:?}, found \"{found}\"")),
|
} => Some(format!("Expected one of {expected:?}, found \"{found}\"")),
|
||||||
Self::InvalidAssignmentTarget { found, .. } => {
|
Self::InvalidAssignmentTarget { found, .. } => {
|
||||||
Some(format!("Invalid assignment target \"{found}\""))
|
Some(format!("Invalid assignment target, found \"{found}\""))
|
||||||
}
|
}
|
||||||
Self::UndefinedVariable { identifier, .. } => {
|
Self::UndefinedVariable { identifier, .. } => {
|
||||||
Some(format!("Undefined variable \"{identifier}\""))
|
Some(format!("Undefined variable \"{identifier}\""))
|
||||||
}
|
}
|
||||||
|
Self::RegisterOverflow { .. } => None,
|
||||||
Self::Chunk(error) => error.details(),
|
Self::Chunk(error) => error.details(),
|
||||||
Self::Lex(error) => Some(error.to_string()),
|
Self::Lex(error) => Some(error.to_string()),
|
||||||
Self::ParseIntError { error, .. } => Some(error.to_string()),
|
Self::ParseIntError { error, .. } => Some(error.to_string()),
|
||||||
@ -682,6 +726,7 @@ impl AnnotatedError for ParseError {
|
|||||||
Self::ExpectedTokenMultiple { position, .. } => *position,
|
Self::ExpectedTokenMultiple { position, .. } => *position,
|
||||||
Self::InvalidAssignmentTarget { position, .. } => *position,
|
Self::InvalidAssignmentTarget { position, .. } => *position,
|
||||||
Self::UndefinedVariable { position, .. } => *position,
|
Self::UndefinedVariable { position, .. } => *position,
|
||||||
|
Self::RegisterOverflow { position } => *position,
|
||||||
Self::Chunk(error) => error.position(),
|
Self::Chunk(error) => error.position(),
|
||||||
Self::Lex(error) => error.position(),
|
Self::Lex(error) => error.position(),
|
||||||
Self::ParseIntError { position, .. } => *position,
|
Self::ParseIntError { position, .. } => *position,
|
||||||
@ -694,283 +739,3 @@ impl From<LexError> for ParseError {
|
|||||||
Self::Lex(error)
|
Self::Lex(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::Local;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn block() {
|
|
||||||
let source = "{ 42; 42 }";
|
|
||||||
let test_chunk = parse(source);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
test_chunk,
|
|
||||||
Ok(Chunk::with_data(
|
|
||||||
vec![
|
|
||||||
(Instruction::Constant as u8, Span(2, 4)),
|
|
||||||
(0, Span(2, 4)),
|
|
||||||
(Instruction::Constant as u8, Span(6, 8)),
|
|
||||||
(1, Span(6, 8)),
|
|
||||||
(Instruction::Return as u8, Span(6, 8)),
|
|
||||||
],
|
|
||||||
vec![Value::integer(42), Value::integer(42)],
|
|
||||||
vec![]
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn add_variables() {
|
|
||||||
let source = "let x = 42; let y = 42; x + y";
|
|
||||||
let test_chunk = parse(source);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
test_chunk,
|
|
||||||
Ok(Chunk::with_data(
|
|
||||||
vec![
|
|
||||||
(Instruction::Constant as u8, Span(8, 10)),
|
|
||||||
(0, Span(8, 10)),
|
|
||||||
(Instruction::DeclareVariable as u8, Span(4, 5)),
|
|
||||||
(0, Span(4, 5)),
|
|
||||||
(Instruction::Constant as u8, Span(20, 22)),
|
|
||||||
(1, Span(20, 22)),
|
|
||||||
(Instruction::DeclareVariable as u8, Span(16, 17)),
|
|
||||||
(1, Span(16, 17)),
|
|
||||||
(Instruction::GetVariable as u8, Span(24, 25)),
|
|
||||||
(0, Span(24, 25)),
|
|
||||||
(Instruction::GetVariable as u8, Span(28, 29)),
|
|
||||||
(1, Span(28, 29)),
|
|
||||||
(Instruction::Add as u8, Span(26, 27)),
|
|
||||||
(Instruction::Return as u8, Span(24, 29)),
|
|
||||||
],
|
|
||||||
vec![Value::integer(42), Value::integer(42)],
|
|
||||||
vec![
|
|
||||||
Local {
|
|
||||||
identifier: Identifier::new("x"),
|
|
||||||
depth: 0,
|
|
||||||
},
|
|
||||||
Local {
|
|
||||||
identifier: Identifier::new("y"),
|
|
||||||
depth: 0,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn let_statement() {
|
|
||||||
let source = "let x = 42;";
|
|
||||||
let test_chunk = parse(source);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
test_chunk,
|
|
||||||
Ok(Chunk::with_data(
|
|
||||||
vec![
|
|
||||||
(Instruction::Constant as u8, Span(8, 10)),
|
|
||||||
(0, Span(8, 10)),
|
|
||||||
(Instruction::DeclareVariable as u8, Span(4, 5)),
|
|
||||||
(0, Span(4, 5)),
|
|
||||||
],
|
|
||||||
vec![Value::integer(42)],
|
|
||||||
vec![Local {
|
|
||||||
identifier: Identifier::new("x"),
|
|
||||||
depth: 0,
|
|
||||||
}],
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn string() {
|
|
||||||
let source = "\"Hello, World!\"";
|
|
||||||
let test_chunk = parse(source);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
test_chunk,
|
|
||||||
Ok(Chunk::with_data(
|
|
||||||
vec![
|
|
||||||
(Instruction::Constant as u8, Span(0, 15)),
|
|
||||||
(0, Span(0, 15)),
|
|
||||||
(Instruction::Return as u8, Span(0, 15)),
|
|
||||||
],
|
|
||||||
vec![Value::string("Hello, World!")],
|
|
||||||
vec![],
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn integer() {
|
|
||||||
let source = "42";
|
|
||||||
let test_chunk = parse(source);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
test_chunk,
|
|
||||||
Ok(Chunk::with_data(
|
|
||||||
vec![
|
|
||||||
(Instruction::Constant as u8, Span(0, 2)),
|
|
||||||
(0, Span(0, 2)),
|
|
||||||
(Instruction::Return as u8, Span(0, 2)),
|
|
||||||
],
|
|
||||||
vec![Value::integer(42)],
|
|
||||||
vec![],
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn boolean() {
|
|
||||||
let source = "true";
|
|
||||||
let test_chunk = parse(source);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
test_chunk,
|
|
||||||
Ok(Chunk::with_data(
|
|
||||||
vec![
|
|
||||||
(Instruction::Constant as u8, Span(0, 4)),
|
|
||||||
(0, Span(0, 4)),
|
|
||||||
(Instruction::Return as u8, Span(0, 4)),
|
|
||||||
],
|
|
||||||
vec![Value::boolean(true)],
|
|
||||||
vec![],
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn grouping() {
|
|
||||||
let source = "(42 + 42) * 2";
|
|
||||||
let test_chunk = parse(source);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
test_chunk,
|
|
||||||
Ok(Chunk::with_data(
|
|
||||||
vec![
|
|
||||||
(Instruction::Constant as u8, Span(1, 3)),
|
|
||||||
(0, Span(1, 3)),
|
|
||||||
(Instruction::Constant as u8, Span(6, 8)),
|
|
||||||
(1, Span(6, 8)),
|
|
||||||
(Instruction::Add as u8, Span(4, 5)),
|
|
||||||
(Instruction::Constant as u8, Span(12, 13)),
|
|
||||||
(2, Span(12, 13)),
|
|
||||||
(Instruction::Multiply as u8, Span(10, 11)),
|
|
||||||
(Instruction::Return as u8, Span(0, 13)),
|
|
||||||
],
|
|
||||||
vec![Value::integer(42), Value::integer(42), Value::integer(2)],
|
|
||||||
vec![],
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn negation() {
|
|
||||||
let source = "-(42)";
|
|
||||||
let test_chunk = parse(source);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
test_chunk,
|
|
||||||
Ok(Chunk::with_data(
|
|
||||||
vec![
|
|
||||||
(Instruction::Constant as u8, Span(2, 4)),
|
|
||||||
(0, Span(2, 4)),
|
|
||||||
(Instruction::Negate as u8, Span(0, 1)),
|
|
||||||
(Instruction::Return as u8, Span(0, 5)),
|
|
||||||
],
|
|
||||||
vec![Value::integer(42)],
|
|
||||||
vec![],
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn addition() {
|
|
||||||
let source = "42 + 42";
|
|
||||||
let test_chunk = parse(source);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
test_chunk,
|
|
||||||
Ok(Chunk::with_data(
|
|
||||||
vec![
|
|
||||||
(Instruction::Constant as u8, Span(0, 2)),
|
|
||||||
(0, Span(0, 2)),
|
|
||||||
(Instruction::Constant as u8, Span(5, 7)),
|
|
||||||
(1, Span(5, 7)),
|
|
||||||
(Instruction::Add as u8, Span(3, 4)),
|
|
||||||
(Instruction::Return as u8, Span(0, 7)),
|
|
||||||
],
|
|
||||||
vec![Value::integer(42), Value::integer(42)],
|
|
||||||
vec![],
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn subtraction() {
|
|
||||||
let source = "42 - 42";
|
|
||||||
let test_chunk = parse(source);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
test_chunk,
|
|
||||||
Ok(Chunk::with_data(
|
|
||||||
vec![
|
|
||||||
(Instruction::Constant as u8, Span(0, 2)),
|
|
||||||
(0, Span(0, 2)),
|
|
||||||
(Instruction::Constant as u8, Span(5, 7)),
|
|
||||||
(1, Span(5, 7)),
|
|
||||||
(Instruction::Subtract as u8, Span(3, 4)),
|
|
||||||
(Instruction::Return as u8, Span(0, 7)),
|
|
||||||
],
|
|
||||||
vec![Value::integer(42), Value::integer(42)],
|
|
||||||
vec![],
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn multiplication() {
|
|
||||||
let source = "42 * 42";
|
|
||||||
let test_chunk = parse(source);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
test_chunk,
|
|
||||||
Ok(Chunk::with_data(
|
|
||||||
vec![
|
|
||||||
(Instruction::Constant as u8, Span(0, 2)),
|
|
||||||
(0, Span(0, 2)),
|
|
||||||
(Instruction::Constant as u8, Span(5, 7)),
|
|
||||||
(1, Span(5, 7)),
|
|
||||||
(Instruction::Multiply as u8, Span(3, 4)),
|
|
||||||
(Instruction::Return as u8, Span(0, 7)),
|
|
||||||
],
|
|
||||||
vec![Value::integer(42), Value::integer(42)],
|
|
||||||
vec![],
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn division() {
|
|
||||||
let source = "42 / 42";
|
|
||||||
let test_chunk = parse(source);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
test_chunk,
|
|
||||||
Ok(Chunk::with_data(
|
|
||||||
vec![
|
|
||||||
(Instruction::Constant as u8, Span(0, 2)),
|
|
||||||
(0, Span(0, 2)),
|
|
||||||
(Instruction::Constant as u8, Span(5, 7)),
|
|
||||||
(1, Span(5, 7)),
|
|
||||||
(Instruction::Divide as u8, Span(3, 4)),
|
|
||||||
(Instruction::Return as u8, Span(0, 7)),
|
|
||||||
],
|
|
||||||
vec![Value::integer(42), Value::integer(42)],
|
|
||||||
vec![],
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
33
dust-lang/src/parser/tests.rs
Normal file
33
dust-lang/src/parser/tests.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn integer() {
|
||||||
|
assert_eq!(
|
||||||
|
parse("42"),
|
||||||
|
Ok(Chunk::with_data(
|
||||||
|
vec![
|
||||||
|
(Instruction::load_constant(0, 0), Span(0, 2)),
|
||||||
|
(Instruction::r#return(), Span(0, 2)),
|
||||||
|
],
|
||||||
|
vec![Value::integer(42),],
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add() {
|
||||||
|
assert_eq!(
|
||||||
|
parse("1 + 2"),
|
||||||
|
Ok(Chunk::with_data(
|
||||||
|
vec![
|
||||||
|
(Instruction::load_constant(0, 0), Span(0, 1)),
|
||||||
|
(Instruction::load_constant(1, 1), Span(4, 5)),
|
||||||
|
(Instruction::add(2, 1, 0), Span(2, 3)),
|
||||||
|
(Instruction::r#return(), Span(0, 5)),
|
||||||
|
],
|
||||||
|
vec![Value::integer(1), Value::integer(2),],
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
@ -1,47 +0,0 @@
|
|||||||
use crate::{parse, DustError, Value, Vm};
|
|
||||||
|
|
||||||
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
|
||||||
let chunk = parse(source)?;
|
|
||||||
|
|
||||||
let mut vm = Vm::new(chunk);
|
|
||||||
|
|
||||||
vm.run()
|
|
||||||
.map_err(|error| DustError::Runtime { error, source })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn add_variables() {
|
|
||||||
let source = "let foo = 21; let bar = 21; foo + bar";
|
|
||||||
let result = run(source);
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::integer(42))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn variable() {
|
|
||||||
let source = "let foo = 42; foo";
|
|
||||||
let result = run(source);
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::integer(42))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn integer() {
|
|
||||||
let source = "42";
|
|
||||||
let result = run(source);
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::integer(42))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn addition() {
|
|
||||||
let source = "21 + 21";
|
|
||||||
let result = run(source);
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::integer(42))));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,10 +1,8 @@
|
|||||||
//! Token and TokenOwned types.
|
//! Token and TokenOwned types.
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
/// Source code token.
|
/// Source code token.
|
||||||
#[derive(Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Token<'src> {
|
pub enum Token<'src> {
|
||||||
// End of file
|
// End of file
|
||||||
Eof,
|
Eof,
|
||||||
@ -293,7 +291,7 @@ impl<'src> Display for Token<'src> {
|
|||||||
/// Owned version of `Token`, which owns all the strings.
|
/// Owned version of `Token`, which owns all the strings.
|
||||||
///
|
///
|
||||||
/// This is used for errors.
|
/// This is used for errors.
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum TokenOwned {
|
pub enum TokenOwned {
|
||||||
Eof,
|
Eof,
|
||||||
|
|
||||||
@ -412,7 +410,7 @@ impl Display for TokenOwned {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Token representation that holds no data.
|
/// Token representation that holds no data.
|
||||||
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum TokenKind {
|
pub enum TokenKind {
|
||||||
Eof,
|
Eof,
|
||||||
|
|
||||||
|
@ -1,465 +0,0 @@
|
|||||||
use crate::{
|
|
||||||
dust_error::AnnotatedError, parse, Chunk, ChunkError, DustError, Identifier, Instruction, Span,
|
|
||||||
Value, ValueError,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn run(source: &str) -> Result<Option<Value>, DustError> {
|
|
||||||
let chunk = parse(source)?;
|
|
||||||
|
|
||||||
let mut vm = Vm::new(chunk);
|
|
||||||
|
|
||||||
vm.run()
|
|
||||||
.map_err(|error| DustError::Runtime { error, source })
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq)]
|
|
||||||
pub struct Vm {
|
|
||||||
chunk: Chunk,
|
|
||||||
ip: usize,
|
|
||||||
stack: Vec<Value>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Vm {
|
|
||||||
const STACK_SIZE: usize = 256;
|
|
||||||
|
|
||||||
pub fn new(chunk: Chunk) -> Self {
|
|
||||||
Self {
|
|
||||||
chunk,
|
|
||||||
ip: 0,
|
|
||||||
stack: Vec::with_capacity(Self::STACK_SIZE),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run(&mut self) -> Result<Option<Value>, VmError> {
|
|
||||||
let mut current_position = Span(0, 0);
|
|
||||||
|
|
||||||
while let Ok((byte, position)) = self.read(current_position).copied() {
|
|
||||||
current_position = position;
|
|
||||||
|
|
||||||
let instruction = Instruction::from_byte(byte)
|
|
||||||
.ok_or_else(|| VmError::InvalidInstruction(byte, position))?;
|
|
||||||
|
|
||||||
log::trace!("Running instruction {instruction} at {position}");
|
|
||||||
|
|
||||||
match instruction {
|
|
||||||
Instruction::Constant => {
|
|
||||||
let (argument, _) = *self.read(position)?;
|
|
||||||
let value = self.chunk.use_constant(argument, position)?;
|
|
||||||
|
|
||||||
log::trace!("Pushing constant {value}");
|
|
||||||
|
|
||||||
self.push(value, position)?;
|
|
||||||
}
|
|
||||||
Instruction::Return => {
|
|
||||||
let value = self.pop(position)?;
|
|
||||||
|
|
||||||
log::trace!("Returning {value}");
|
|
||||||
|
|
||||||
return Ok(Some(value));
|
|
||||||
}
|
|
||||||
Instruction::Pop => {
|
|
||||||
let value = self.pop(position)?;
|
|
||||||
|
|
||||||
log::trace!("Popping {value:?}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Variables
|
|
||||||
Instruction::DeclareVariable => {
|
|
||||||
let (argument, _) = *self.read(position)?;
|
|
||||||
let identifier = self
|
|
||||||
.chunk
|
|
||||||
.get_identifier(argument)
|
|
||||||
.ok_or_else(|| VmError::UndeclaredVariable { position })?;
|
|
||||||
let value = self.stack.remove(argument as usize);
|
|
||||||
|
|
||||||
log::trace!("Declaring {identifier} as value {value}",);
|
|
||||||
|
|
||||||
self.push(value, position)?;
|
|
||||||
}
|
|
||||||
Instruction::GetVariable => {
|
|
||||||
let (argument, _) = *self.read(position)?;
|
|
||||||
let identifier = self
|
|
||||||
.chunk
|
|
||||||
.get_identifier(argument)
|
|
||||||
.ok_or_else(|| VmError::UndeclaredVariable { position })?;
|
|
||||||
let value = self.stack.remove(argument as usize);
|
|
||||||
|
|
||||||
log::trace!("Getting {identifier} as value {value}",);
|
|
||||||
|
|
||||||
self.push(value, position)?;
|
|
||||||
}
|
|
||||||
Instruction::SetVariable => {
|
|
||||||
let (argument, _) = *self.read(position)?;
|
|
||||||
let identifier = self
|
|
||||||
.chunk
|
|
||||||
.get_identifier(argument)
|
|
||||||
.ok_or_else(|| VmError::UndeclaredVariable { position })?
|
|
||||||
.clone();
|
|
||||||
|
|
||||||
if !self.chunk.contains_identifier(&identifier) {
|
|
||||||
return Err(VmError::UndefinedVariable {
|
|
||||||
identifier: identifier.clone(),
|
|
||||||
position,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let value = self.pop(position)?;
|
|
||||||
|
|
||||||
log::trace!("Setting {identifier} to {value}");
|
|
||||||
|
|
||||||
self.stack[argument as usize] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unary
|
|
||||||
Instruction::Negate => {
|
|
||||||
let negated = self
|
|
||||||
.pop(position)?
|
|
||||||
.negate()
|
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
|
||||||
|
|
||||||
self.push(negated, position)?;
|
|
||||||
}
|
|
||||||
Instruction::Not => {
|
|
||||||
let not = self
|
|
||||||
.pop(position)?
|
|
||||||
.not()
|
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
|
||||||
|
|
||||||
self.push(not, position)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Binary
|
|
||||||
Instruction::Add => {
|
|
||||||
let right = self.pop(position)?;
|
|
||||||
let left = self.pop(position)?;
|
|
||||||
let sum = left
|
|
||||||
.add(&right)
|
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
|
||||||
|
|
||||||
self.push(sum, position)?;
|
|
||||||
}
|
|
||||||
Instruction::Subtract => {
|
|
||||||
let right = self.pop(position)?;
|
|
||||||
let left = self.pop(position)?;
|
|
||||||
let difference = left
|
|
||||||
.subtract(&right)
|
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
|
||||||
|
|
||||||
self.push(difference, position)?;
|
|
||||||
}
|
|
||||||
Instruction::Multiply => {
|
|
||||||
let right = self.pop(position)?;
|
|
||||||
let left = self.pop(position)?;
|
|
||||||
let product = left
|
|
||||||
.multiply(&right)
|
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
|
||||||
|
|
||||||
self.push(product, position)?;
|
|
||||||
}
|
|
||||||
Instruction::Divide => {
|
|
||||||
let right = self.pop(position)?;
|
|
||||||
let left = self.pop(position)?;
|
|
||||||
let quotient = left
|
|
||||||
.divide(&right)
|
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
|
||||||
|
|
||||||
self.push(quotient, position)?;
|
|
||||||
}
|
|
||||||
Instruction::Greater => {
|
|
||||||
let right = self.pop(position)?;
|
|
||||||
let left = self.pop(position)?;
|
|
||||||
let greater = left
|
|
||||||
.greater_than(&right)
|
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
|
||||||
|
|
||||||
self.push(greater, position)?;
|
|
||||||
}
|
|
||||||
Instruction::Less => {
|
|
||||||
let right = self.pop(position)?;
|
|
||||||
let left = self.pop(position)?;
|
|
||||||
let less = left
|
|
||||||
.less_than(&right)
|
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
|
||||||
|
|
||||||
self.push(less, position)?;
|
|
||||||
}
|
|
||||||
Instruction::GreaterEqual => {
|
|
||||||
let right = self.pop(position)?;
|
|
||||||
let left = self.pop(position)?;
|
|
||||||
let greater_equal = left
|
|
||||||
.greater_than_or_equal(&right)
|
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
|
||||||
|
|
||||||
self.push(greater_equal, position)?;
|
|
||||||
}
|
|
||||||
Instruction::LessEqual => {
|
|
||||||
let right = self.pop(position)?;
|
|
||||||
let left = self.pop(position)?;
|
|
||||||
let less_equal = left
|
|
||||||
.less_than_or_equal(&right)
|
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
|
||||||
|
|
||||||
self.push(less_equal, position)?;
|
|
||||||
}
|
|
||||||
Instruction::Equal => {
|
|
||||||
let right = self.pop(position)?;
|
|
||||||
let left = self.pop(position)?;
|
|
||||||
let equal = left
|
|
||||||
.equal(&right)
|
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
|
||||||
|
|
||||||
self.push(equal, position)?;
|
|
||||||
}
|
|
||||||
Instruction::NotEqual => {
|
|
||||||
let right = self.pop(position)?;
|
|
||||||
let left = self.pop(position)?;
|
|
||||||
let not_equal = left
|
|
||||||
.not_equal(&right)
|
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
|
||||||
|
|
||||||
self.push(not_equal, position)?;
|
|
||||||
}
|
|
||||||
Instruction::And => {
|
|
||||||
let right = self.pop(position)?;
|
|
||||||
let left = self.pop(position)?;
|
|
||||||
let and = left
|
|
||||||
.and(&right)
|
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
|
||||||
|
|
||||||
self.push(and, position)?;
|
|
||||||
}
|
|
||||||
Instruction::Or => {
|
|
||||||
let right = self.pop(position)?;
|
|
||||||
let left = self.pop(position)?;
|
|
||||||
let or = left
|
|
||||||
.or(&right)
|
|
||||||
.map_err(|error| VmError::Value { error, position })?;
|
|
||||||
|
|
||||||
self.push(or, position)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push(&mut self, value: Value, position: Span) -> Result<(), VmError> {
|
|
||||||
if self.stack.len() == Self::STACK_SIZE {
|
|
||||||
Err(VmError::StackOverflow(position))
|
|
||||||
} else {
|
|
||||||
self.stack.push(value);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pop(&mut self, position: Span) -> Result<Value, VmError> {
|
|
||||||
if let Some(stacked) = self.stack.pop() {
|
|
||||||
Ok(stacked)
|
|
||||||
} else {
|
|
||||||
Err(VmError::StackUnderflow(position))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read(&mut self, position: Span) -> Result<&(u8, Span), VmError> {
|
|
||||||
let current = self.chunk.get_code(self.ip, position)?;
|
|
||||||
|
|
||||||
self.ip += 1;
|
|
||||||
|
|
||||||
Ok(current)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub enum VmError {
|
|
||||||
InvalidInstruction(u8, Span),
|
|
||||||
StackOverflow(Span),
|
|
||||||
StackUnderflow(Span),
|
|
||||||
UndeclaredVariable {
|
|
||||||
position: Span,
|
|
||||||
},
|
|
||||||
UndefinedVariable {
|
|
||||||
identifier: Identifier,
|
|
||||||
position: Span,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Wrappers for foreign errors
|
|
||||||
Chunk(ChunkError),
|
|
||||||
Value {
|
|
||||||
error: ValueError,
|
|
||||||
position: Span,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ChunkError> for VmError {
|
|
||||||
fn from(v: ChunkError) -> Self {
|
|
||||||
Self::Chunk(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AnnotatedError for VmError {
|
|
||||||
fn title() -> &'static str {
|
|
||||||
"Runtime Error"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn description(&self) -> &'static str {
|
|
||||||
match self {
|
|
||||||
Self::InvalidInstruction(_, _) => "Invalid instruction",
|
|
||||||
Self::StackOverflow(_) => "Stack overflow",
|
|
||||||
Self::StackUnderflow(_) => "Stack underflow",
|
|
||||||
Self::UndeclaredVariable { .. } => "Undeclared variable",
|
|
||||||
Self::UndefinedVariable { .. } => "Undefined variable",
|
|
||||||
Self::Chunk(_) => "Chunk error",
|
|
||||||
Self::Value { .. } => "Value error",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn details(&self) -> Option<String> {
|
|
||||||
match self {
|
|
||||||
Self::InvalidInstruction(byte, _) => Some(format!(
|
|
||||||
"The byte {byte} does not correspond to a valid instruction"
|
|
||||||
)),
|
|
||||||
Self::StackOverflow(position) => Some(format!("Stack overflow at {position}")),
|
|
||||||
Self::StackUnderflow(position) => Some(format!("Stack underflow at {position}")),
|
|
||||||
Self::UndeclaredVariable { .. } => Some("Variable is not declared".to_string()),
|
|
||||||
Self::UndefinedVariable { identifier, .. } => {
|
|
||||||
Some(format!("{identifier} is not in scope"))
|
|
||||||
}
|
|
||||||
Self::Chunk(error) => error.details(),
|
|
||||||
Self::Value { error, .. } => Some(error.to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn position(&self) -> Span {
|
|
||||||
match self {
|
|
||||||
Self::InvalidInstruction(_, position) => *position,
|
|
||||||
Self::StackUnderflow(position) => *position,
|
|
||||||
Self::StackOverflow(position) => *position,
|
|
||||||
Self::UndeclaredVariable { position } => *position,
|
|
||||||
Self::UndefinedVariable { position, .. } => *position,
|
|
||||||
Self::Chunk(error) => error.position(),
|
|
||||||
Self::Value { position, .. } => *position,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
pub mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn negation() {
|
|
||||||
let mut chunk = Chunk::new();
|
|
||||||
let dummy_position = Span(0, 0);
|
|
||||||
let constant = chunk
|
|
||||||
.push_constant(Value::integer(42), dummy_position)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
chunk.push_code(Instruction::Constant as u8, dummy_position);
|
|
||||||
chunk.push_code(constant, dummy_position);
|
|
||||||
chunk.push_code(Instruction::Negate as u8, dummy_position);
|
|
||||||
chunk.push_code(Instruction::Return as u8, dummy_position);
|
|
||||||
|
|
||||||
let mut vm = Vm::new(chunk);
|
|
||||||
let result = vm.run();
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::integer(-42))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn addition() {
|
|
||||||
let mut chunk = Chunk::new();
|
|
||||||
let dummy_position = Span(0, 0);
|
|
||||||
let left = chunk
|
|
||||||
.push_constant(Value::integer(42), dummy_position)
|
|
||||||
.unwrap();
|
|
||||||
let right = chunk
|
|
||||||
.push_constant(Value::integer(23), dummy_position)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
chunk.push_code(Instruction::Constant, dummy_position);
|
|
||||||
chunk.push_code(left, dummy_position);
|
|
||||||
chunk.push_code(Instruction::Constant, dummy_position);
|
|
||||||
chunk.push_code(right, dummy_position);
|
|
||||||
chunk.push_code(Instruction::Add, dummy_position);
|
|
||||||
chunk.push_code(Instruction::Return, dummy_position);
|
|
||||||
|
|
||||||
let mut vm = Vm::new(chunk);
|
|
||||||
let result = vm.run();
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::integer(65))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn subtraction() {
|
|
||||||
let mut chunk = Chunk::new();
|
|
||||||
let dummy_position = Span(0, 0);
|
|
||||||
let left = chunk
|
|
||||||
.push_constant(Value::integer(42), dummy_position)
|
|
||||||
.unwrap();
|
|
||||||
let right = chunk
|
|
||||||
.push_constant(Value::integer(23), dummy_position)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
chunk.push_code(Instruction::Constant, dummy_position);
|
|
||||||
chunk.push_code(left, dummy_position);
|
|
||||||
chunk.push_code(Instruction::Constant, dummy_position);
|
|
||||||
chunk.push_code(right, dummy_position);
|
|
||||||
chunk.push_code(Instruction::Subtract, dummy_position);
|
|
||||||
chunk.push_code(Instruction::Return, dummy_position);
|
|
||||||
|
|
||||||
let mut vm = Vm::new(chunk);
|
|
||||||
let result = vm.run();
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::integer(19))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn multiplication() {
|
|
||||||
let mut chunk = Chunk::new();
|
|
||||||
let dummy_position = Span(0, 0);
|
|
||||||
let left = chunk
|
|
||||||
.push_constant(Value::integer(42), dummy_position)
|
|
||||||
.unwrap();
|
|
||||||
let right = chunk
|
|
||||||
.push_constant(Value::integer(23), dummy_position)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
chunk.push_code(Instruction::Constant, dummy_position);
|
|
||||||
chunk.push_code(left, dummy_position);
|
|
||||||
chunk.push_code(Instruction::Constant, dummy_position);
|
|
||||||
chunk.push_code(right, dummy_position);
|
|
||||||
chunk.push_code(Instruction::Multiply, dummy_position);
|
|
||||||
chunk.push_code(Instruction::Return, dummy_position);
|
|
||||||
|
|
||||||
let mut vm = Vm::new(chunk);
|
|
||||||
let result = vm.run();
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::integer(966))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
|
|
||||||
fn division() {
|
|
||||||
let mut chunk = Chunk::new();
|
|
||||||
let dummy_position = Span(0, 0);
|
|
||||||
let left = chunk
|
|
||||||
.push_constant(Value::integer(42), dummy_position)
|
|
||||||
.unwrap();
|
|
||||||
let right = chunk
|
|
||||||
.push_constant(Value::integer(23), dummy_position)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
chunk.push_code(Instruction::Constant, dummy_position);
|
|
||||||
chunk.push_code(left, dummy_position);
|
|
||||||
chunk.push_code(Instruction::Constant, dummy_position);
|
|
||||||
chunk.push_code(right, dummy_position);
|
|
||||||
chunk.push_code(Instruction::Divide, dummy_position);
|
|
||||||
chunk.push_code(Instruction::Return, dummy_position);
|
|
||||||
|
|
||||||
let mut vm = Vm::new(chunk);
|
|
||||||
let result = vm.run();
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::integer(1))));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
use dust_lang::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn addition() {
|
|
||||||
let source = "21 + 21";
|
|
||||||
let result = run(source);
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::integer(42))));
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
use dust_lang::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn integer() {
|
|
||||||
let source = "42";
|
|
||||||
let result = run(source);
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::integer(42))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn float() {
|
|
||||||
let source = "42.0";
|
|
||||||
let result = run(source);
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::float(42.0))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn string() {
|
|
||||||
let source = "\"Hello, World!\"";
|
|
||||||
let result = run(source);
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::string("Hello, World!"))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn boolean() {
|
|
||||||
let source = "true";
|
|
||||||
let result = run(source);
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::boolean(true))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn byte() {
|
|
||||||
let source = "0x42";
|
|
||||||
let result = run(source);
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::byte(0x42))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn character() {
|
|
||||||
let source = "'a'";
|
|
||||||
let result = run(source);
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::character('a'))));
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
use dust_lang::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn add_variables() {
|
|
||||||
let source = "let foo = 21; let bar = 21; foo + bar";
|
|
||||||
let result = run(source);
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::integer(42))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn variable() {
|
|
||||||
let source = "let foo = 42; foo";
|
|
||||||
let result = run(source);
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::integer(42))));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn lots_of_variables() {
|
|
||||||
env_logger::builder().is_test(true).try_init().unwrap();
|
|
||||||
|
|
||||||
let source = "
|
|
||||||
let foo = 1;
|
|
||||||
let bar = 2;
|
|
||||||
let baz = 3;
|
|
||||||
let qux = 4;
|
|
||||||
let quux = 5;
|
|
||||||
foo + bar + baz + qux + quux";
|
|
||||||
let result = run(source);
|
|
||||||
|
|
||||||
assert_eq!(result, Ok(Some(Value::integer(15))));
|
|
||||||
}
|
|
@ -1,78 +1,78 @@
|
|||||||
use std::{fs::read_to_string, io::Write};
|
// use std::{fs::read_to_string, io::Write};
|
||||||
|
|
||||||
use clap::Parser;
|
// use clap::Parser;
|
||||||
use colored::Colorize;
|
// use colored::Colorize;
|
||||||
use dust_lang::{parse, run};
|
// use dust_lang::{parse, run};
|
||||||
use log::Level;
|
// use log::Level;
|
||||||
|
|
||||||
#[derive(Parser)]
|
// #[derive(Parser)]
|
||||||
struct Cli {
|
// struct Cli {
|
||||||
#[arg(short, long)]
|
// #[arg(short, long)]
|
||||||
command: Option<String>,
|
// command: Option<String>,
|
||||||
|
|
||||||
#[arg(short, long)]
|
// #[arg(short, long)]
|
||||||
parse: bool,
|
// parse: bool,
|
||||||
|
|
||||||
path: Option<String>,
|
// path: Option<String>,
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
env_logger::builder()
|
// env_logger::builder()
|
||||||
.parse_env("DUST_LOG")
|
// .parse_env("DUST_LOG")
|
||||||
.format(|buf, record| {
|
// .format(|buf, record| {
|
||||||
let level = match record.level() {
|
// let level = match record.level() {
|
||||||
Level::Error => "ERROR".red(),
|
// Level::Error => "ERROR".red(),
|
||||||
Level::Warn => "WARN".yellow(),
|
// Level::Warn => "WARN".yellow(),
|
||||||
Level::Info => "INFO".white(),
|
// Level::Info => "INFO".white(),
|
||||||
Level::Debug => "DEBUG".blue(),
|
// Level::Debug => "DEBUG".blue(),
|
||||||
Level::Trace => "TRACE".purple(),
|
// Level::Trace => "TRACE".purple(),
|
||||||
}
|
// }
|
||||||
.bold();
|
// .bold();
|
||||||
let level_display = format!("[{level:^5}]").white().on_black();
|
// let level_display = format!("[{level:^5}]").white().on_black();
|
||||||
let module = record
|
// let module = record
|
||||||
.module_path()
|
// .module_path()
|
||||||
.map(|path| path.split("::").last().unwrap_or("unknown"))
|
// .map(|path| path.split("::").last().unwrap_or("unknown"))
|
||||||
.unwrap_or("unknown")
|
// .unwrap_or("unknown")
|
||||||
.dimmed();
|
// .dimmed();
|
||||||
|
|
||||||
writeln!(buf, "{level_display} {module:^6} {}", record.args())
|
// writeln!(buf, "{level_display} {module:^6} {}", record.args())
|
||||||
})
|
// })
|
||||||
.init();
|
// .init();
|
||||||
|
|
||||||
let args = Cli::parse();
|
// let args = Cli::parse();
|
||||||
|
|
||||||
if let Some(command) = &args.command {
|
// if let Some(command) = &args.command {
|
||||||
if args.parse {
|
// if args.parse {
|
||||||
parse_and_display_errors(command);
|
// parse_and_display_errors(command);
|
||||||
} else {
|
// } else {
|
||||||
run_and_display_errors(command);
|
// run_and_display_errors(command);
|
||||||
}
|
// }
|
||||||
} else if let Some(path) = &args.path {
|
// } else if let Some(path) = &args.path {
|
||||||
let source = read_to_string(path).expect("Failed to read file");
|
// let source = read_to_string(path).expect("Failed to read file");
|
||||||
|
|
||||||
if args.parse {
|
// if args.parse {
|
||||||
parse_and_display_errors(&source);
|
// parse_and_display_errors(&source);
|
||||||
} else {
|
// } else {
|
||||||
run_and_display_errors(&source);
|
// run_and_display_errors(&source);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_and_display_errors(source: &str) {
|
// fn parse_and_display_errors(source: &str) {
|
||||||
match parse(source) {
|
// match parse(source) {
|
||||||
Ok(chunk) => println!("{}", chunk.disassemble("Dust CLI Input")),
|
// Ok(chunk) => println!("{}", chunk.disassemble("Dust CLI Input")),
|
||||||
Err(error) => {
|
// Err(error) => {
|
||||||
eprintln!("{:?}", error);
|
// eprintln!("{:?}", error);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn run_and_display_errors(source: &str) {
|
// fn run_and_display_errors(source: &str) {
|
||||||
match run(source) {
|
// match run(source) {
|
||||||
Ok(Some(value)) => println!("{}", value),
|
// Ok(Some(value)) => println!("{}", value),
|
||||||
Ok(_) => {}
|
// Ok(_) => {}
|
||||||
Err(error) => {
|
// Err(error) => {
|
||||||
eprintln!("{}", error.report());
|
// eprintln!("{}", error.report());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
Loading…
Reference in New Issue
Block a user