From 7b055d79b574d8e3ea13fba972da69085be7078d Mon Sep 17 00:00:00 2001 From: Jeff Date: Wed, 11 Sep 2024 23:07:20 -0400 Subject: [PATCH] Begin rewrite with register-based bytecode --- Cargo.lock | 211 ++++++---- dust-lang/src/chunk.rs | 79 ++-- dust-lang/src/dust_error.rs | 20 +- dust-lang/src/instruction.rs | 305 +++++++++----- dust-lang/src/lib.rs | 55 +-- dust-lang/src/{parser.rs => parser/mod.rs} | 387 ++++------------- dust-lang/src/parser/tests.rs | 33 ++ dust-lang/src/run.rs | 47 --- dust-lang/src/token.rs | 8 +- dust-lang/src/vm.rs | 465 --------------------- dust-lang/tests/operations.rs | 9 - dust-lang/tests/values.rs | 49 --- dust-lang/tests/variables.rs | 33 -- dust-shell/src/main.rs | 130 +++--- 14 files changed, 542 insertions(+), 1289 deletions(-) rename dust-lang/src/{parser.rs => parser/mod.rs} (67%) create mode 100644 dust-lang/src/parser/tests.rs delete mode 100644 dust-lang/src/run.rs delete mode 100644 dust-lang/src/vm.rs delete mode 100644 dust-lang/tests/operations.rs delete mode 100644 dust-lang/tests/values.rs delete mode 100644 dust-lang/tests/variables.rs diff --git a/Cargo.lock b/Cargo.lock index e9ffb36..b190207 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -23,15 +23,16 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.13" +version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] @@ -43,32 +44,38 @@ checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anstyle-parse" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.2" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.2" +version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" dependencies = [ "anstyle", "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]] name = "cfg-if" version = "1.0.0" @@ -77,9 +84,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "4.5.14" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c937d4061031a6d0c8da4b9a4f98a172fc2976dfb1c19213a9cf7d0d3c837e36" +checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac" dependencies = [ "clap_builder", "clap_derive", @@ -87,9 +94,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.14" +version = "4.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85379ba512b21a328adf887e85f7742d12e96eb31f3ef077df4ffc26b506ffed" +checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73" dependencies = [ "anstream", "anstyle", @@ -117,9 +124,9 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" [[package]] name = "colorchoice" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" [[package]] name = "colored" @@ -152,9 +159,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "dust-lang" @@ -182,15 +189,15 @@ dependencies = [ [[package]] name = "either" -version = "1.10.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "env_filter" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" dependencies = [ "log", "regex", @@ -211,9 +218,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", @@ -233,10 +240,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] -name = "itoa" -version = "1.0.10" +name = "is_terminal_polyfill" +version = "1.70.1" 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]] name = "lazy_static" @@ -246,9 +259,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "log" @@ -258,30 +271,33 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -318,9 +334,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -338,9 +354,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -350,9 +366,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -361,30 +377,30 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "serde" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", @@ -393,11 +409,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] @@ -410,9 +427,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.53" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -421,9 +438,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-width" @@ -433,9 +450,9 @@ checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "utf8parse" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "wasi" @@ -458,7 +475,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.4", + "windows-targets 0.52.6", ] [[package]] @@ -478,17 +495,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.4", - "windows_aarch64_msvc 0.52.4", - "windows_i686_gnu 0.52.4", - "windows_i686_msvc 0.52.4", - "windows_x86_64_gnu 0.52.4", - "windows_x86_64_gnullvm 0.52.4", - "windows_x86_64_msvc 0.52.4", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -499,9 +517,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -511,9 +529,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -523,9 +541,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.6" 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]] name = "windows_i686_msvc" @@ -535,9 +559,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -547,9 +571,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -559,9 +583,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -571,6 +595,27 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.6" 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", +] diff --git a/dust-lang/src/chunk.rs b/dust-lang/src/chunk.rs index e9b983f..4ee9c3c 100644 --- a/dust-lang/src/chunk.rs +++ b/dust-lang/src/chunk.rs @@ -4,9 +4,9 @@ use serde::{Deserialize, Serialize}; use crate::{AnnotatedError, Identifier, Instruction, Span, Value}; -#[derive(Clone, Serialize, Deserialize)] +#[derive(Clone)] pub struct Chunk { - code: Vec<(u8, Span)>, + code: Vec<(Instruction, Span)>, constants: Vec>, identifiers: Vec, scope_depth: usize, @@ -23,7 +23,7 @@ impl Chunk { } pub fn with_data( - code: Vec<(u8, Span)>, + code: Vec<(Instruction, Span)>, constants: Vec, identifiers: Vec, ) -> Self { @@ -47,17 +47,21 @@ impl Chunk { 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 .get(offset) .ok_or(ChunkError::CodeIndexOfBounds { offset, position }) } - pub fn push_code>(&mut self, into_byte: T, position: Span) { - self.code.push((into_byte.into(), position)); + pub fn push_code(&mut self, instruction: Instruction, position: Span) { + 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 .get(index as usize) .ok_or(ChunkError::ConstantIndexOutOfBounds { index, position }) @@ -68,23 +72,15 @@ impl Chunk { }) } - pub fn use_constant(&mut self, index: u8, position: Span) -> Result { - let index = index as usize; - + pub fn use_constant(&mut self, index: u16, position: Span) -> Result { self.constants - .get_mut(index) - .ok_or_else(|| ChunkError::ConstantIndexOutOfBounds { - index: index as u8, - position, - })? + .get_mut(index as usize) + .ok_or_else(|| ChunkError::ConstantIndexOutOfBounds { index, position })? .take() - .ok_or(ChunkError::ConstantAlreadyUsed { - index: index as u8, - position, - }) + .ok_or(ChunkError::ConstantAlreadyUsed { index, position }) } - pub fn push_constant(&mut self, value: Value, position: Span) -> Result { + pub fn push_constant(&mut self, value: Value, position: Span) -> Result { let starting_length = self.constants.len(); if starting_length + 1 > (u8::MAX as usize) { @@ -92,7 +88,7 @@ impl Chunk { } else { 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) } - 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 .get(index as usize) .ok_or(ChunkError::IdentifierIndexOutOfBounds { index, position }) @@ -120,14 +116,14 @@ impl Chunk { &self, identifier: &Identifier, position: Span, - ) -> Result { + ) -> Result { self.identifiers .iter() .rev() .enumerate() .find_map(|(index, local)| { if &local.identifier == identifier { - Some(index as u8) + Some(index as u16) } else { None } @@ -142,7 +138,7 @@ impl Chunk { &mut self, identifier: Identifier, position: Span, - ) -> Result { + ) -> Result { let starting_length = self.identifiers.len(); if starting_length + 1 > (u8::MAX as usize) { @@ -153,7 +149,7 @@ impl Chunk { 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 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_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_underline); output.push_str("\n Code \n"); output.push_str("------ ------------ ------------\n"); output.push_str("OFFSET POSITION INSTRUCTION\n"); output.push_str("------ ------------ ------------\n"); - let mut previous = None; - - 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(); + for (offset, (instruction, position)) in self.code.iter().enumerate() { let display = format!( "{offset:4} {:12} {}\n", position.to_string(), @@ -216,8 +199,6 @@ impl Chunk { ); output.push_str(&display); - - previous = Some(instruction); } output.push_str("\n Constants\n"); @@ -296,18 +277,18 @@ pub enum ChunkError { position: Span, }, ConstantAlreadyUsed { - index: u8, + index: u16, position: Span, }, ConstantOverflow { position: Span, }, ConstantIndexOutOfBounds { - index: u8, + index: u16, position: Span, }, IdentifierIndexOutOfBounds { - index: u8, + index: u16, position: Span, }, IdentifierOverflow { diff --git a/dust-lang/src/dust_error.rs b/dust-lang/src/dust_error.rs index 2fe243e..a83200f 100644 --- a/dust-lang/src/dust_error.rs +++ b/dust-lang/src/dust_error.rs @@ -1,6 +1,6 @@ use annotate_snippets::{Level, Renderer, Snippet}; -use crate::{vm::VmError, LexError, ParseError, Span}; +use crate::{LexError, ParseError, Span}; #[derive(Debug, PartialEq)] pub enum DustError<'src> { @@ -12,10 +12,6 @@ pub enum DustError<'src> { error: ParseError, source: &'src str, }, - Runtime { - error: VmError, - source: &'src str, - }, } impl<'src> DustError<'src> { @@ -24,20 +20,6 @@ impl<'src> DustError<'src> { let renderer = Renderer::styled(); 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 } => { let position = error.position(); let label = format!("Parse error: {}", error.description()); diff --git a/dust-lang/src/instruction.rs b/dust-lang/src/instruction.rs index b0641e8..684a3ae 100644 --- a/dust-lang/src/instruction.rs +++ b/dust-lang/src/instruction.rs @@ -1,141 +1,214 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - use crate::{Chunk, Span}; -#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)] -pub enum Instruction { - Constant = 0, - Return = 1, - Pop = 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, +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct Instruction { + opcode: OpCode, + to_register: u8, + arguments: [u8; 2], } impl Instruction { - pub fn from_byte(byte: u8) -> Option { - match byte { - 0 => Some(Instruction::Constant), - 1 => Some(Instruction::Return), - 2 => Some(Instruction::Pop), - 3 => Some(Instruction::DeclareVariable), - 4 => Some(Instruction::GetVariable), - 5 => Some(Instruction::SetVariable), - 6 => Some(Instruction::Negate), - 7 => Some(Instruction::Not), - 8 => Some(Instruction::Add), - 9 => Some(Instruction::Subtract), - 10 => Some(Instruction::Multiply), - 11 => Some(Instruction::Divide), - 12 => Some(Instruction::Greater), - 13 => Some(Instruction::Less), - 14 => Some(Instruction::GreaterEqual), - 15 => Some(Instruction::LessEqual), - 16 => Some(Instruction::Equal), - 17 => Some(Instruction::NotEqual), - 18 => Some(Instruction::And), - 19 => Some(Instruction::Or), - _ => None, + pub fn r#move(to_register: u8, from_register: u8) -> Instruction { + Instruction { + opcode: OpCode::Move, + to_register, + arguments: [from_register, 0], + } + } + + pub fn close(to_register: u8) -> Instruction { + Instruction { + opcode: OpCode::Close, + to_register, + arguments: [0, 0], + } + } + + pub fn load_constant(to_register: u8, constant_index: u16) -> Instruction { + Instruction { + opcode: OpCode::LoadConstant, + to_register, + arguments: constant_index.to_le_bytes(), + } + } + + 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 { - let dummy_position = Span(0, 0); - - match self { - Instruction::Constant => { - let (argument, position) = *chunk.get_code(offset + 1, dummy_position).unwrap(); - let value_display = chunk - .get_constant(argument, position) - .map(|value| value.to_string()) - .unwrap_or_else(|error| format!("{error:?}")); - - format!("CONSTANT {value_display}") + match self.opcode { + OpCode::Move => format!( + "{:04} MOVE R{} R{}", + offset, self.to_register, self.arguments[0] + ), + OpCode::Close => { + format!("{:04} CLOSE R{}", offset, self.to_register) } - Instruction::Return => "RETURN".to_string(), - Instruction::Pop => "POP".to_string(), + OpCode::LoadConstant => { + 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), + }; - // Variables - Instruction::DeclareVariable => { - let (argument, _) = chunk.get_code(offset + 1, dummy_position).unwrap(); - let identifier_display = chunk - .get_identifier(*argument) - .map(|identifier| identifier.to_string()) - .unwrap_or_else(|| "ERROR".to_string()); - - format!("DECLARE_VARIABLE {identifier_display}") + format!( + "{:04} LOAD_CONSTANT R{} C{} {}", + offset, self.to_register, constant_index, constant_display + ) } - Instruction::GetVariable => { - let (argument, _) = chunk.get_code(offset + 1, dummy_position).unwrap(); - let identifier_display = chunk - .get_identifier(*argument) - .map(|identifier| identifier.to_string()) - .unwrap_or_else(|| "ERROR".to_string()); + OpCode::DeclareVariable => { + let variable_index = u16::from_le_bytes([self.arguments[0], self.arguments[1]]); - format!("GET_VARIABLE {identifier_display}") + 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]]); - Instruction::SetVariable => { - let (argument, _) = chunk.get_code(offset + 1, dummy_position).unwrap(); - let identifier_display = chunk - .get_identifier(*argument) - .map(|identifier| identifier.to_string()) - .unwrap_or_else(|| "ERROR".to_string()); - - format!("SET_VARIABLE {identifier_display}") + 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]]); - // Unary - Instruction::Negate => "NEGATE".to_string(), - Instruction::Not => "NOT".to_string(), - - // 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(), + 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), } } } -impl Display for Instruction { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{self:?}") - } +#[derive(Clone, Copy, Debug, PartialEq)] +enum OpCode { + // Stack manipulation + Move, + Close, + + // Constants + LoadConstant, + + // Variables + DeclareVariable, + GetVariable, + SetVariable, + + // Binary operations + Add, + Subtract, + Multiply, + Divide, + + // Unary operations + Negate, + + // Control flow + Return, } -impl From for u8 { - fn from(instruction: Instruction) -> Self { - instruction as u8 +#[cfg(test)] +mod tests { + use std::mem::size_of; + + use super::*; + + #[test] + fn instruction_is_32_bits() { + assert_eq!(size_of::(), 4); } } diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 8357e15..14271aa 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -1,34 +1,18 @@ -//! The Dust programming language. -//! -//! To get started, you can use the `run` function to run a Dust program. -//! -//! ```rust -//! use dust_lang::{run, Value}; -//! -//! let program = " -//! let foo = 21 -//! let bar = 2 -//! 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; +mod chunk; +mod constructor; +mod dust_error; +mod identifier; +mod instruction; +mod lexer; +mod parser; +mod token; +mod r#type; +mod value; -pub use chunk::{Chunk, ChunkError, Local}; -pub use constructor::{ConstructError, Constructor}; +use std::fmt::Display; + +pub use chunk::{Chunk, ChunkError}; +pub use constructor::Constructor; pub use dust_error::{AnnotatedError, DustError}; pub use identifier::Identifier; pub use instruction::Instruction; @@ -36,18 +20,13 @@ pub use lexer::{lex, LexError, Lexer}; pub use parser::{parse, ParseError, Parser}; pub use r#type::{EnumType, FunctionType, RangeableType, StructType, Type, TypeConflict}; pub use token::{Token, TokenKind, TokenOwned}; -pub use value::{Struct, Value, ValueError}; -pub use vm::{run, Vm}; +pub use value::{Enum, Function, Struct, Value}; -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct Span(pub usize, pub usize); 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) } } diff --git a/dust-lang/src/parser.rs b/dust-lang/src/parser/mod.rs similarity index 67% rename from dust-lang/src/parser.rs rename to dust-lang/src/parser/mod.rs index b7c3e0a..b792d4c 100644 --- a/dust-lang/src/parser.rs +++ b/dust-lang/src/parser/mod.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use std::{ fmt::{self, Display, Formatter}, mem, @@ -24,12 +27,13 @@ pub fn parse(source: &str) -> Result { #[derive(Debug)] pub struct Parser<'src> { - lexer: Lexer<'src>, chunk: Chunk, - previous_token: Token<'src>, - previous_position: Span, + lexer: Lexer<'src>, + current_register: u8, current_token: Token<'src>, current_position: Span, + previous_token: Token<'src>, + previous_position: Span, } impl<'src> Parser<'src> { @@ -42,10 +46,11 @@ impl<'src> Parser<'src> { Parser { lexer, chunk: Chunk::new(), - previous_token: Token::Eof, - previous_position: Span(0, 0), + current_register: 0, current_token, 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) } + 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> { if self.is_eof() { return Ok(()); @@ -90,16 +109,19 @@ impl<'src> Parser<'src> { } } - fn emit_byte>(&mut self, into_byte: T, position: Span) { - self.chunk.push_code(into_byte.into(), position); + fn emit_instruction(&mut self, instruction: Instruction, position: Span) { + self.chunk.push_code(instruction, position); } fn emit_constant(&mut self, value: Value) -> Result<(), ParseError> { let position = self.previous_position; let constant_index = self.chunk.push_constant(value, position)?; - self.emit_byte(Instruction::Constant, position); - self.emit_byte(constant_index, position); + self.emit_instruction( + Instruction::load_constant(self.current_register, constant_index), + position, + ); + self.increment_register()?; Ok(()) } @@ -180,7 +202,9 @@ impl<'src> Parser<'src> { fn parse_unary(&mut self, _allow_assignment: bool) -> Result<(), ParseError> { let operator_position = self.previous_position; 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 { expected: vec![TokenKind::Minus], @@ -191,7 +215,7 @@ impl<'src> Parser<'src> { }; self.parse_expression()?; - self.emit_byte(byte, operator_position); + self.emit_instruction(byte, operator_position); Ok(()) } @@ -205,12 +229,18 @@ impl<'src> Parser<'src> { 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 { - TokenKind::Plus => Instruction::Add, - TokenKind::Minus => Instruction::Subtract, - TokenKind::Star => Instruction::Multiply, - TokenKind::Slash => Instruction::Divide, - TokenKind::DoubleAmpersand => Instruction::And, + TokenKind::Plus => Instruction::add(to_register, left_register, right_register), + TokenKind::Minus => Instruction::subtract(to_register, left_register, right_register), + TokenKind::Star => Instruction::multiply(to_register, left_register, right_register), + TokenKind::Slash => Instruction::divide(to_register, left_register, right_register), _ => { return Err(ParseError::ExpectedTokenMultiple { expected: vec![ @@ -225,7 +255,7 @@ impl<'src> Parser<'src> { } }; - self.emit_byte(byte, operator_position); + self.emit_instruction(byte, operator_position); Ok(()) } @@ -240,11 +270,17 @@ impl<'src> Parser<'src> { if allow_assignment && self.allow(TokenKind::Equal)? { 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 { - self.emit_byte(Instruction::GetVariable, self.previous_position); - self.emit_byte(identifier_index, self.previous_position); + self.emit_instruction( + Instruction::get_variable(self.current_register - 1, identifier_index), + self.previous_position, + ); } Ok(()) @@ -254,7 +290,7 @@ impl<'src> Parser<'src> { &mut self, token: TokenOwned, position: Span, - ) -> Result { + ) -> Result { if let TokenOwned::Identifier(text) = token { let identifier = Identifier::new(text); @@ -291,8 +327,10 @@ impl<'src> Parser<'src> { .next_back() .map_or(false, |local| local.depth > self.chunk.scope_depth()) { - self.emit_byte(Instruction::Pop, self.current_position); - self.chunk.pop_identifier(); + self.emit_instruction( + Instruction::close(self.current_register), + self.current_position, + ); } Ok(()) @@ -326,7 +364,7 @@ impl<'src> Parser<'src> { if is_expression_statement && !contains_block && !has_semicolon { let end = self.previous_position.1; - self.emit_byte(Instruction::Return, Span(start, end)) + self.emit_instruction(Instruction::r#return(), Span(start, end)) } Ok(()) @@ -353,8 +391,11 @@ impl<'src> Parser<'src> { let identifier_index = self.chunk.declare_variable(identifier, position)?; - self.emit_byte(Instruction::DeclareVariable, position); - self.emit_byte(identifier_index, position); + self.emit_instruction( + Instruction::set_variable(self.current_register, identifier_index), + position, + ); + self.increment_register()?; Ok(()) } @@ -618,6 +659,9 @@ pub enum ParseError { identifier: Identifier, position: Span, }, + RegisterOverflow { + position: Span, + }, // Wrappers around foreign errors Chunk(ChunkError), @@ -646,6 +690,7 @@ impl AnnotatedError for ParseError { Self::ExpectedTokenMultiple { .. } => "Expected one of multiple tokens", Self::InvalidAssignmentTarget { .. } => "Invalid assignment target", Self::UndefinedVariable { .. } => "Undefined variable", + Self::RegisterOverflow { .. } => "Register overflow", Self::Chunk { .. } => "Chunk error", Self::Lex(_) => "Lex error", Self::ParseIntError { .. } => "Failed to parse integer", @@ -654,9 +699,7 @@ impl AnnotatedError for ParseError { fn details(&self) -> Option { match self { - Self::ExpectedExpression { found, .. } => { - Some(format!("Expected an expression, found \"{found}\"")) - } + Self::ExpectedExpression { found, .. } => Some(format!("Found \"{found}\"")), Self::ExpectedToken { expected, found, .. } => Some(format!("Expected \"{expected}\", found \"{found}\"")), @@ -664,11 +707,12 @@ impl AnnotatedError for ParseError { expected, found, .. } => Some(format!("Expected one of {expected:?}, found \"{found}\"")), Self::InvalidAssignmentTarget { found, .. } => { - Some(format!("Invalid assignment target \"{found}\"")) + Some(format!("Invalid assignment target, found \"{found}\"")) } Self::UndefinedVariable { identifier, .. } => { Some(format!("Undefined variable \"{identifier}\"")) } + Self::RegisterOverflow { .. } => None, Self::Chunk(error) => error.details(), Self::Lex(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::InvalidAssignmentTarget { position, .. } => *position, Self::UndefinedVariable { position, .. } => *position, + Self::RegisterOverflow { position } => *position, Self::Chunk(error) => error.position(), Self::Lex(error) => error.position(), Self::ParseIntError { position, .. } => *position, @@ -694,283 +739,3 @@ impl From for ParseError { 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![], - )) - ); - } -} diff --git a/dust-lang/src/parser/tests.rs b/dust-lang/src/parser/tests.rs new file mode 100644 index 0000000..eced36a --- /dev/null +++ b/dust-lang/src/parser/tests.rs @@ -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![] + )) + ); +} diff --git a/dust-lang/src/run.rs b/dust-lang/src/run.rs deleted file mode 100644 index 8077798..0000000 --- a/dust-lang/src/run.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::{parse, DustError, Value, Vm}; - -pub fn run(source: &str) -> Result, 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)))); - } -} diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs index a0d5fe1..531a1dc 100644 --- a/dust-lang/src/token.rs +++ b/dust-lang/src/token.rs @@ -1,10 +1,8 @@ //! Token and TokenOwned types. use std::fmt::{self, Display, Formatter}; -use serde::{Deserialize, Serialize}; - /// Source code token. -#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[derive(Debug, PartialEq)] pub enum Token<'src> { // End of file Eof, @@ -293,7 +291,7 @@ impl<'src> Display for Token<'src> { /// Owned version of `Token`, which owns all the strings. /// /// This is used for errors. -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Clone)] pub enum TokenOwned { Eof, @@ -412,7 +410,7 @@ impl Display for TokenOwned { } /// Token representation that holds no data. -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Clone)] pub enum TokenKind { Eof, diff --git a/dust-lang/src/vm.rs b/dust-lang/src/vm.rs deleted file mode 100644 index ca50aea..0000000 --- a/dust-lang/src/vm.rs +++ /dev/null @@ -1,465 +0,0 @@ -use crate::{ - dust_error::AnnotatedError, parse, Chunk, ChunkError, DustError, Identifier, Instruction, Span, - Value, ValueError, -}; - -pub fn run(source: &str) -> Result, 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, -} - -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, 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 { - 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 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 { - 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)))); - } -} diff --git a/dust-lang/tests/operations.rs b/dust-lang/tests/operations.rs deleted file mode 100644 index 5b559be..0000000 --- a/dust-lang/tests/operations.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-lang/tests/values.rs b/dust-lang/tests/values.rs deleted file mode 100644 index 556e2e4..0000000 --- a/dust-lang/tests/values.rs +++ /dev/null @@ -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')))); -} diff --git a/dust-lang/tests/variables.rs b/dust-lang/tests/variables.rs deleted file mode 100644 index d4eff10..0000000 --- a/dust-lang/tests/variables.rs +++ /dev/null @@ -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)))); -} diff --git a/dust-shell/src/main.rs b/dust-shell/src/main.rs index 66bdaf3..932f7e2 100644 --- a/dust-shell/src/main.rs +++ b/dust-shell/src/main.rs @@ -1,78 +1,78 @@ -use std::{fs::read_to_string, io::Write}; +// use std::{fs::read_to_string, io::Write}; -use clap::Parser; -use colored::Colorize; -use dust_lang::{parse, run}; -use log::Level; +// use clap::Parser; +// use colored::Colorize; +// use dust_lang::{parse, run}; +// use log::Level; -#[derive(Parser)] -struct Cli { - #[arg(short, long)] - command: Option, +// #[derive(Parser)] +// struct Cli { +// #[arg(short, long)] +// command: Option, - #[arg(short, long)] - parse: bool, +// #[arg(short, long)] +// parse: bool, - path: Option, -} +// path: Option, +// } fn main() { - env_logger::builder() - .parse_env("DUST_LOG") - .format(|buf, record| { - let level = match record.level() { - Level::Error => "ERROR".red(), - Level::Warn => "WARN".yellow(), - Level::Info => "INFO".white(), - Level::Debug => "DEBUG".blue(), - Level::Trace => "TRACE".purple(), - } - .bold(); - let level_display = format!("[{level:^5}]").white().on_black(); - let module = record - .module_path() - .map(|path| path.split("::").last().unwrap_or("unknown")) - .unwrap_or("unknown") - .dimmed(); + // env_logger::builder() + // .parse_env("DUST_LOG") + // .format(|buf, record| { + // let level = match record.level() { + // Level::Error => "ERROR".red(), + // Level::Warn => "WARN".yellow(), + // Level::Info => "INFO".white(), + // Level::Debug => "DEBUG".blue(), + // Level::Trace => "TRACE".purple(), + // } + // .bold(); + // let level_display = format!("[{level:^5}]").white().on_black(); + // let module = record + // .module_path() + // .map(|path| path.split("::").last().unwrap_or("unknown")) + // .unwrap_or("unknown") + // .dimmed(); - writeln!(buf, "{level_display} {module:^6} {}", record.args()) - }) - .init(); + // writeln!(buf, "{level_display} {module:^6} {}", record.args()) + // }) + // .init(); - let args = Cli::parse(); + // let args = Cli::parse(); - if let Some(command) = &args.command { - if args.parse { - parse_and_display_errors(command); - } else { - run_and_display_errors(command); - } - } else if let Some(path) = &args.path { - let source = read_to_string(path).expect("Failed to read file"); + // if let Some(command) = &args.command { + // if args.parse { + // parse_and_display_errors(command); + // } else { + // run_and_display_errors(command); + // } + // } else if let Some(path) = &args.path { + // let source = read_to_string(path).expect("Failed to read file"); - if args.parse { - parse_and_display_errors(&source); - } else { - run_and_display_errors(&source); - } - } + // if args.parse { + // parse_and_display_errors(&source); + // } else { + // run_and_display_errors(&source); + // } + // } } -fn parse_and_display_errors(source: &str) { - match parse(source) { - Ok(chunk) => println!("{}", chunk.disassemble("Dust CLI Input")), - Err(error) => { - eprintln!("{:?}", error); - } - } -} +// fn parse_and_display_errors(source: &str) { +// match parse(source) { +// Ok(chunk) => println!("{}", chunk.disassemble("Dust CLI Input")), +// Err(error) => { +// eprintln!("{:?}", error); +// } +// } +// } -fn run_and_display_errors(source: &str) { - match run(source) { - Ok(Some(value)) => println!("{}", value), - Ok(_) => {} - Err(error) => { - eprintln!("{}", error.report()); - } - } -} +// fn run_and_display_errors(source: &str) { +// match run(source) { +// Ok(Some(value)) => println!("{}", value), +// Ok(_) => {} +// Err(error) => { +// eprintln!("{}", error.report()); +// } +// } +// }