From cc188a233bcd9093c4dd1532bb1035bbea82bf1f Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 3 Aug 2024 20:23:52 -0400 Subject: [PATCH] Overhaul project structure --- Cargo.lock | 913 +----------- dust-lang/examples/interpreter_async.rs | 52 - dust-lang/examples/pretty_errors.rs | 29 - dust-lang/src/abstract_tree/as.rs | 85 -- dust-lang/src/abstract_tree/assignment.rs | 231 --- dust-lang/src/abstract_tree/async_block.rs | 88 -- dust-lang/src/abstract_tree/block.rs | 124 -- .../src/abstract_tree/built_in_function.rs | 305 ---- .../src/abstract_tree/enum_declaration.rs | 148 -- dust-lang/src/abstract_tree/expression.rs | 174 --- dust-lang/src/abstract_tree/for.rs | 99 -- dust-lang/src/abstract_tree/function_call.rs | 381 ----- dust-lang/src/abstract_tree/if_else.rs | 231 --- dust-lang/src/abstract_tree/list_index.rs | 165 --- dust-lang/src/abstract_tree/logic.rs | 378 ----- dust-lang/src/abstract_tree/loop.rs | 73 - dust-lang/src/abstract_tree/map_index.rs | 187 --- dust-lang/src/abstract_tree/math.rs | 361 ----- dust-lang/src/abstract_tree/mod.rs | 229 --- dust-lang/src/abstract_tree/statement.rs | 204 --- .../src/abstract_tree/structure_definition.rs | 91 -- dust-lang/src/abstract_tree/type_alias.rs | 65 - .../src/abstract_tree/type_constructor.rs | 280 ---- dust-lang/src/abstract_tree/use.rs | 115 -- dust-lang/src/abstract_tree/value_node.rs | 818 ----------- dust-lang/src/abstract_tree/while.rs | 93 -- dust-lang/src/bytecode.rs | 327 ----- dust-lang/src/context.rs | 305 ---- dust-lang/src/error.rs | 221 --- dust-lang/src/interpreter.rs | 520 ------- dust-lang/src/lex.rs | 132 ++ dust-lang/src/lexer.rs | 573 -------- dust-lang/src/lib.rs | 19 +- dust-lang/src/parse.rs | 243 +++ dust-lang/src/parser/mod.rs | 781 ---------- dust-lang/src/parser/tests.rs | 1307 ----------------- dust-lang/src/standard_library.rs | 133 -- dust-lang/src/token.rs | 13 + dust-lang/src/type.rs | 8 +- dust-lang/src/value.rs | 413 +----- dust-lang/tests/enums.rs | 48 - dust-lang/tests/expressions.rs | 42 - dust-lang/tests/functions.rs | 165 --- dust-lang/tests/statements.rs | 74 - dust-lang/tests/structs.rs | 121 -- dust-lang/tests/validation.rs | 80 - dust-lang/tests/values.rs | 160 -- dust-lang/tests/variables.rs | 36 - dust-shell/Cargo.toml | 10 - dust-shell/src/cli.rs | 167 --- dust-shell/src/main.rs | 145 +- 51 files changed, 413 insertions(+), 11549 deletions(-) delete mode 100644 dust-lang/examples/interpreter_async.rs delete mode 100644 dust-lang/examples/pretty_errors.rs delete mode 100644 dust-lang/src/abstract_tree/as.rs delete mode 100644 dust-lang/src/abstract_tree/assignment.rs delete mode 100644 dust-lang/src/abstract_tree/async_block.rs delete mode 100644 dust-lang/src/abstract_tree/block.rs delete mode 100644 dust-lang/src/abstract_tree/built_in_function.rs delete mode 100644 dust-lang/src/abstract_tree/enum_declaration.rs delete mode 100644 dust-lang/src/abstract_tree/expression.rs delete mode 100644 dust-lang/src/abstract_tree/for.rs delete mode 100644 dust-lang/src/abstract_tree/function_call.rs delete mode 100644 dust-lang/src/abstract_tree/if_else.rs delete mode 100644 dust-lang/src/abstract_tree/list_index.rs delete mode 100644 dust-lang/src/abstract_tree/logic.rs delete mode 100644 dust-lang/src/abstract_tree/loop.rs delete mode 100644 dust-lang/src/abstract_tree/map_index.rs delete mode 100644 dust-lang/src/abstract_tree/math.rs delete mode 100644 dust-lang/src/abstract_tree/mod.rs delete mode 100644 dust-lang/src/abstract_tree/statement.rs delete mode 100644 dust-lang/src/abstract_tree/structure_definition.rs delete mode 100644 dust-lang/src/abstract_tree/type_alias.rs delete mode 100644 dust-lang/src/abstract_tree/type_constructor.rs delete mode 100644 dust-lang/src/abstract_tree/use.rs delete mode 100644 dust-lang/src/abstract_tree/value_node.rs delete mode 100644 dust-lang/src/abstract_tree/while.rs delete mode 100644 dust-lang/src/bytecode.rs delete mode 100644 dust-lang/src/context.rs delete mode 100644 dust-lang/src/error.rs delete mode 100644 dust-lang/src/interpreter.rs create mode 100644 dust-lang/src/lex.rs delete mode 100644 dust-lang/src/lexer.rs create mode 100644 dust-lang/src/parse.rs delete mode 100644 dust-lang/src/parser/mod.rs delete mode 100644 dust-lang/src/parser/tests.rs delete mode 100644 dust-lang/src/standard_library.rs create mode 100644 dust-lang/src/token.rs delete mode 100644 dust-lang/tests/enums.rs delete mode 100644 dust-lang/tests/expressions.rs delete mode 100644 dust-lang/tests/functions.rs delete mode 100644 dust-lang/tests/statements.rs delete mode 100644 dust-lang/tests/structs.rs delete mode 100644 dust-lang/tests/validation.rs delete mode 100644 dust-lang/tests/values.rs delete mode 100644 dust-lang/tests/variables.rs delete mode 100644 dust-shell/src/cli.rs diff --git a/Cargo.lock b/Cargo.lock index 8265264..ac7e6e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,21 +29,6 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "anstream" version = "0.6.13" @@ -92,23 +77,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "arboard" -version = "3.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2041f1943049c7978768d84e6d0fd95de98b76d6c4727b09e78ec253d29fa58" -dependencies = [ - "clipboard-win", - "log", - "objc", - "objc-foundation", - "objc_id", - "parking_lot", - "thiserror", - "wl-clipboard-rs", - "x11rb", -] - [[package]] name = "ariadne" version = "0.4.0" @@ -119,45 +87,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" -dependencies = [ - "serde", -] - -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - -[[package]] -name = "bumpalo" -version = "3.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" - [[package]] name = "cc" version = "1.0.90" @@ -170,25 +99,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - -[[package]] -name = "chrono" -version = "0.4.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "serde", - "windows-targets 0.52.4", -] - [[package]] name = "chumsky" version = "1.0.0-alpha.6" @@ -230,7 +140,7 @@ version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn", @@ -242,15 +152,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" -[[package]] -name = "clipboard-win" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d517d4b86184dbb111d3556a10f1c8a04da7428d2987bf1081602bf11c3aa9ee" -dependencies = [ - "error-code", -] - [[package]] name = "colorchoice" version = "1.0.0" @@ -267,12 +168,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "core-foundation-sys" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" - [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -298,58 +193,6 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" -[[package]] -name = "crossterm" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" -dependencies = [ - "bitflags 2.5.0", - "crossterm_winapi", - "libc", - "mio", - "parking_lot", - "serde", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm_winapi" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" -dependencies = [ - "winapi", -] - -[[package]] -name = "derive-new" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "dlib" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" -dependencies = [ - "libloading", -] - -[[package]] -name = "downcast-rs" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" - [[package]] name = "dust-lang" version = "0.5.0" @@ -369,17 +212,6 @@ dependencies = [ [[package]] name = "dust-shell" version = "0.1.0" -dependencies = [ - "ariadne", - "clap", - "colored", - "dust-lang", - "env_logger", - "log", - "nu-ansi-term", - "reedline", - "ron", -] [[package]] name = "either" @@ -410,79 +242,6 @@ dependencies = [ "log", ] -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "error-code" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" - -[[package]] -name = "fallible-iterator" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" - -[[package]] -name = "fallible-streaming-iterator" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "fd-lock" -version = "3.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" -dependencies = [ - "cfg-if", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "gethostname" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" -dependencies = [ - "libc", - "windows-targets 0.48.5", -] - [[package]] name = "getrandom" version = "0.2.12" @@ -504,99 +263,24 @@ dependencies = [ "allocator-api2", ] -[[package]] -name = "hashlink" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692eaaf7f7607518dd3cef090f1474b61edc5301d8012f09579920df68b725ee" -dependencies = [ - "hashbrown", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", -] - [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "indexmap" -version = "2.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" -[[package]] -name = "js-sys" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" -dependencies = [ - "wasm-bindgen", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -609,206 +293,24 @@ version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" -[[package]] -name = "libloading" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" -dependencies = [ - "cfg-if", - "windows-targets 0.52.4", -] - -[[package]] -name = "libsqlite3-sys" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" -dependencies = [ - "cc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" - -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - [[package]] name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - [[package]] name = "memchr" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.48.0", -] - -[[package]] -name = "nix" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" -dependencies = [ - "bitflags 2.5.0", - "cfg-if", - "cfg_aliases", - "libc", -] - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nu-ansi-term" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd2800e1520bdc966782168a627aa5d1ad92e33b984bf7c7615d31280c83ff14" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "num-traits" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - -[[package]] -name = "objc-foundation" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" -dependencies = [ - "block", - "objc", - "objc_id", -] - -[[package]] -name = "objc_id" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" -dependencies = [ - "objc", -] - [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "os_pipe" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57119c3b893986491ec9aa85056780d3a0f3cf4da7cc09dd3650dbd6c6738fb9" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.48.5", -] - -[[package]] -name = "petgraph" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" -dependencies = [ - "fixedbitset", - "indexmap", -] - -[[package]] -name = "pkg-config" -version = "0.3.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" - [[package]] name = "ppv-lite86" version = "0.2.17" @@ -833,15 +335,6 @@ dependencies = [ "cc", ] -[[package]] -name = "quick-xml" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" -dependencies = [ - "memchr", -] - [[package]] name = "quote" version = "1.0.35" @@ -901,38 +394,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "reedline" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413a9fa6a5d8c937d3ae1e975bfb6a918bb0b6cdfae6a10416218c837a31b8fc" -dependencies = [ - "arboard", - "chrono", - "crossterm", - "fd-lock", - "itertools", - "nu-ansi-term", - "rusqlite", - "serde", - "serde_json", - "strip-ansi-escapes", - "strum", - "strum_macros", - "thiserror", - "unicode-segmentation", - "unicode-width", -] - [[package]] name = "regex" version = "1.10.3" @@ -979,69 +440,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" -[[package]] -name = "ron" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" -dependencies = [ - "base64", - "bitflags 2.5.0", - "serde", - "serde_derive", -] - -[[package]] -name = "rusqlite" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" -dependencies = [ - "bitflags 2.5.0", - "fallible-iterator", - "fallible-streaming-iterator", - "hashlink", - "libsqlite3-sys", - "smallvec", -] - -[[package]] -name = "rustix" -version = "0.38.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" -dependencies = [ - "bitflags 2.5.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustversion" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" - [[package]] name = "ryu" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "serde" version = "1.0.203" @@ -1073,42 +477,6 @@ dependencies = [ "serde", ] -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-mio" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" -dependencies = [ - "libc", - "mio", - "signal-hook", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "smallvec" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" - [[package]] name = "stacker" version = "0.1.15" @@ -1122,40 +490,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "strip-ansi-escapes" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa" -dependencies = [ - "vte", -] - [[package]] name = "strsim" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" -[[package]] -name = "strum" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" - -[[package]] -name = "strum_macros" -version = "0.25.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - [[package]] name = "syn" version = "2.0.53" @@ -1167,64 +507,12 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "tempfile" -version = "3.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" -dependencies = [ - "cfg-if", - "fastrand", - "rustix", - "windows-sys 0.52.0", -] - -[[package]] -name = "thiserror" -version = "1.0.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tree_magic_mini" -version = "3.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ee137597cdb361b55a4746983e4ac1b35ab6024396a419944ad473bb915265" -dependencies = [ - "fnv", - "home", - "memchr", - "nom", - "once_cell", - "petgraph", -] - [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" -[[package]] -name = "unicode-segmentation" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" - [[package]] name = "unicode-width" version = "0.1.11" @@ -1237,171 +525,18 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "vte" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197" -dependencies = [ - "utf8parse", - "vte_generate_state_changes", -] - -[[package]] -name = "vte_generate_state_changes" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" -dependencies = [ - "proc-macro2", - "quote", -] - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasm-bindgen" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" - -[[package]] -name = "wayland-backend" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d50fa61ce90d76474c87f5fc002828d81b32677340112b4ef08079a9d459a40" -dependencies = [ - "cc", - "downcast-rs", - "rustix", - "scoped-tls", - "smallvec", - "wayland-sys", -] - -[[package]] -name = "wayland-client" -version = "0.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82fb96ee935c2cea6668ccb470fb7771f6215d1691746c2d896b447a00ad3f1f" -dependencies = [ - "bitflags 2.5.0", - "rustix", - "wayland-backend", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols" -version = "0.31.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4" -dependencies = [ - "bitflags 2.5.0", - "wayland-backend", - "wayland-client", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols-wlr" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1f61b76b6c2d8742e10f9ba5c3737f6530b4c243132c2a2ccc8aa96fe25cd6" -dependencies = [ - "bitflags 2.5.0", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-scanner", -] - -[[package]] -name = "wayland-scanner" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b3a62929287001986fb58c789dce9b67604a397c15c611ad9f747300b6c283" -dependencies = [ - "proc-macro2", - "quick-xml", - "quote", -] - -[[package]] -name = "wayland-sys" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15a0c8eaff5216d07f226cb7a549159267f3467b289d9a2e52fd3ef5aae2b7af" -dependencies = [ - "dlib", - "log", - "pkg-config", -] - [[package]] name = "winapi" version = "0.3.9" @@ -1424,15 +559,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.4", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -1565,43 +691,6 @@ version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" -[[package]] -name = "wl-clipboard-rs" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b41773911497b18ca8553c3daaf8ec9fe9819caf93d451d3055f69de028adb" -dependencies = [ - "derive-new", - "libc", - "log", - "nix", - "os_pipe", - "tempfile", - "thiserror", - "tree_magic_mini", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "wayland-protocols-wlr", -] - -[[package]] -name = "x11rb" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f25ead8c7e4cba123243a6367da5d3990e0d3affa708ea19dce96356bd9f1a" -dependencies = [ - "gethostname", - "rustix", - "x11rb-protocol", -] - -[[package]] -name = "x11rb-protocol" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e63e71c4b8bd9ffec2c963173a4dc4cbde9ee96961d4fcb4429db9929b606c34" - [[package]] name = "yansi" version = "0.5.1" diff --git a/dust-lang/examples/interpreter_async.rs b/dust-lang/examples/interpreter_async.rs deleted file mode 100644 index 1b3a985..0000000 --- a/dust-lang/examples/interpreter_async.rs +++ /dev/null @@ -1,52 +0,0 @@ -use std::{ - sync::{mpsc::channel, Arc}, - thread, - time::Duration, -}; - -use dust_lang::*; - -fn run_fibnacci(interpreter: &Interpreter, i: u8) -> Value { - // These double brackets are not Dust syntax, it's just an escape sequence for Rust's format! - // macro. - let source = Arc::from(format!( - " - fib = fn (i: int) -> int {{ - if i <= 1 {{ - i - }} else {{ - fib(i - 1) + fib(i - 2) - }} - }} - - fib({i})" - )); - - interpreter - .run(Arc::from(i.to_string()), source) - .unwrap() // Panic if there are errors. - .unwrap() // Panic if the no value is returned. -} - -fn main() { - let interpreter = Interpreter::new(); - let (tx, rx) = channel(); - - for i in 1..10 { - let interpreter = interpreter.clone(); - let tx = tx.clone(); - - println!("Spawning thread for fib({})", i); - - thread::spawn(move || { - let value = run_fibnacci(&interpreter, i); - - tx.send(value).unwrap(); - }); - } - - // Give the threads half a second to finish. - while let Ok(value) = rx.recv_timeout(Duration::from_millis(500)) { - println!("{}", value); - } -} diff --git a/dust-lang/examples/pretty_errors.rs b/dust-lang/examples/pretty_errors.rs deleted file mode 100644 index 815cfd6..0000000 --- a/dust-lang/examples/pretty_errors.rs +++ /dev/null @@ -1,29 +0,0 @@ -// It's very easy to get nice-looking error messages from the Dust's top-level error type. - -use std::{io::stderr, sync::Arc}; - -use ariadne::sources; -use dust_lang::Interpreter; - -fn main() { - let interpreter = Interpreter::new(); - - // First, we'll run some bad code. - let error = interpreter - .run( - Arc::from("bad code"), - Arc::from( - " - x = 1 + 'a' - y: float = 'hello' - ", - ), - ) - .unwrap_err(); - - for report in error.build_reports() { - report - .write_for_stdout(sources(interpreter.sources()), stderr()) - .unwrap(); - } -} diff --git a/dust-lang/src/abstract_tree/as.rs b/dust-lang/src/abstract_tree/as.rs deleted file mode 100644 index d3d8e9c..0000000 --- a/dust-lang/src/abstract_tree/as.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::{ - borrow::Borrow, - fmt::{self, Display, Formatter}, -}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - value::ValueInner, - Value, -}; - -use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type, TypeConstructor}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct As { - expression: Expression, - constructor: TypeConstructor, -} - -impl As { - pub fn new(expression: Expression, constructor: TypeConstructor) -> Self { - Self { - expression, - constructor, - } - } -} - -impl AbstractNode for As { - fn define_and_validate( - &self, - _context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - self.expression - .define_and_validate(_context, _manage_memory, scope)?; - - match self.constructor { - TypeConstructor::Raw(_) => {} - _ => todo!("Create an error for this occurence"), - }; - - Ok(()) - } - - fn evaluate( - self, - context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - let expression_position = self.expression.position(); - let evaluation = self.expression.evaluate(context, _manage_memory, scope)?; - let value = if let Some(Evaluation::Return(value)) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(expression_position), - )); - }; - let r#type = self.constructor.construct(context)?; - let (from_value, to_type): (&ValueInner, Type) = (value.inner().borrow(), r#type); - - let converted = match (from_value, to_type) { - (_, Type::String) => Value::string(value.to_string()), - _ => todo!("Create an error for this occurence"), - }; - - Ok(Some(Evaluation::Return(converted))) - } - - fn expected_type(&self, context: &Context) -> Result, ValidationError> { - self.constructor.construct(context).map(Some) - } -} - -impl Display for As { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{} as {}", self.expression, self.constructor) - } -} diff --git a/dust-lang/src/abstract_tree/assignment.rs b/dust-lang/src/abstract_tree/assignment.rs deleted file mode 100644 index f472b31..0000000 --- a/dust-lang/src/abstract_tree/assignment.rs +++ /dev/null @@ -1,231 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - error::{RuntimeError, ValidationError}, - identifier::Identifier, - value::ValueInner, - Context, Value, -}; - -use super::{ - AbstractNode, Evaluation, SourcePosition, Statement, Type, TypeConstructor, WithPosition, -}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct Assignment { - identifier: WithPosition, - constructor: Option, - operator: AssignmentOperator, - statement: Box, -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum AssignmentOperator { - Assign, - AddAssign, - SubAssign, -} - -impl Assignment { - pub fn new( - identifier: WithPosition, - constructor: Option, - operator: AssignmentOperator, - statement: Statement, - ) -> Self { - Self { - identifier, - constructor, - operator, - statement: Box::new(statement), - } - } -} - -impl AbstractNode for Assignment { - fn define_and_validate( - &self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - let r#type = if let Some(constructor) = &self.constructor { - constructor.construct(context)? - } else if let Some(r#type) = self.statement.expected_type(context)? { - r#type - } else { - return Err(ValidationError::CannotAssignToNone( - self.statement.last_evaluated_statement().position(), - )); - }; - - context.set_type(self.identifier.node.clone(), r#type, scope)?; - self.statement - .define_and_validate(context, manage_memory, scope)?; - - let statement_type = self.statement.expected_type(context)?; - - if statement_type.is_none() { - return Err(ValidationError::CannotAssignToNone( - self.statement.last_evaluated_statement().position(), - )); - } - - if let (Some(expected_type_constructor), Some(actual_type)) = - (&self.constructor, statement_type) - { - let expected_type = expected_type_constructor.construct(context)?; - - expected_type - .check(&actual_type) - .map_err(|conflict| ValidationError::TypeCheck { - conflict, - actual_position: self.statement.last_evaluated_statement().position(), - expected_position: Some(expected_type_constructor.position()), - })?; - } - - Ok(()) - } - - fn evaluate( - self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - let evaluation = self.statement.evaluate(context, manage_memory, scope)?; - let right = match evaluation { - Some(Evaluation::Return(value)) => value, - evaluation => return Ok(evaluation), - }; - - match self.operator { - AssignmentOperator::Assign => { - context.set_value(self.identifier.node, right, scope)?; - } - AssignmentOperator::AddAssign => { - let left_option = if manage_memory { - context.use_value(&self.identifier.node)? - } else { - context.get_value(&self.identifier.node)? - }; - - if let Some(left) = left_option { - let new_value = match (left.inner().as_ref(), right.inner().as_ref()) { - (ValueInner::Integer(left), ValueInner::Integer(right)) => { - let sum = left.saturating_add(*right); - - Value::integer(sum) - } - (ValueInner::Float(left), ValueInner::Float(right)) => { - let sum = left + right; - - Value::float(sum) - } - (ValueInner::Float(left), ValueInner::Integer(right)) => { - let sum = left + *right as f64; - - Value::float(sum) - } - (ValueInner::Integer(left), ValueInner::Float(right)) => { - let sum = *left as f64 + right; - - Value::float(sum) - } - _ => { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(self.identifier.position), - )) - } - }; - context.set_value(self.identifier.node, new_value, scope)?; - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::VariableNotFound { - identifier: self.identifier.node, - position: self.identifier.position, - }, - )); - } - } - AssignmentOperator::SubAssign => { - let left_option = if manage_memory { - context.use_value(&self.identifier.node)? - } else { - context.get_value(&self.identifier.node)? - }; - - if let Some(left) = left_option { - let new_value = match (left.inner().as_ref(), right.inner().as_ref()) { - (ValueInner::Integer(left), ValueInner::Integer(right)) => { - let difference = left.saturating_sub(*right); - - Value::integer(difference) - } - (ValueInner::Float(left), ValueInner::Float(right)) => { - let difference = left - right; - - Value::float(difference) - } - (ValueInner::Float(left), ValueInner::Integer(right)) => { - let difference = left - *right as f64; - - Value::float(difference) - } - (ValueInner::Integer(left), ValueInner::Float(right)) => { - let difference = *left as f64 - right; - - Value::float(difference) - } - _ => { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(self.identifier.position), - )) - } - }; - context.set_value(self.identifier.node, new_value, scope)?; - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::VariableNotFound { - identifier: self.identifier.node, - position: self.identifier.position, - }, - )); - } - } - } - - Ok(None) - } - - fn expected_type(&self, _: &Context) -> Result, ValidationError> { - Ok(None) - } -} - -impl Display for Assignment { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let Assignment { - identifier, - constructor, - operator, - statement, - } = self; - write!(f, "{} ", identifier.node)?; - - if let Some(constructor) = constructor { - write!(f, ": {constructor} ")?; - } - - match operator { - AssignmentOperator::Assign => write!(f, "="), - AssignmentOperator::AddAssign => write!(f, "+="), - AssignmentOperator::SubAssign => write!(f, "-="), - }?; - - write!(f, " {statement}") - } -} diff --git a/dust-lang/src/abstract_tree/async_block.rs b/dust-lang/src/abstract_tree/async_block.rs deleted file mode 100644 index 8872c64..0000000 --- a/dust-lang/src/abstract_tree/async_block.rs +++ /dev/null @@ -1,88 +0,0 @@ -use std::{ - fmt::{self, Display, Formatter}, - sync::Mutex, -}; - -use rayon::prelude::*; -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, -}; - -use super::{AbstractNode, Evaluation, SourcePosition, Statement, Type}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct AsyncBlock { - statements: Vec, -} - -impl AsyncBlock { - pub fn new(statements: Vec) -> Self { - Self { statements } - } -} - -impl AbstractNode for AsyncBlock { - fn define_and_validate( - &self, - _context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - for statement in &self.statements { - statement.define_and_validate(_context, manage_memory, scope)?; - } - - Ok(()) - } - - fn evaluate( - self, - _context: &Context, - _: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - let final_result = Mutex::new(Ok(None)); - let statement_count = self.statements.len(); - let error_option = self.statements.into_par_iter().enumerate().find_map_any( - |(index, statement)| -> Option { - let result = statement.evaluate(_context, false, scope); - - if let Err(error) = result { - return Some(error); - } - - if index == statement_count - 1 { - // It is safe to unwrap here because only one thread uses the Mutex - *final_result.lock().unwrap() = result; - } - - None - }, - ); - - if let Some(error) = error_option { - Err(error) - } else { - final_result.into_inner()? - } - } - - fn expected_type(&self, _context: &Context) -> Result, ValidationError> { - self.statements.last().unwrap().expected_type(_context) - } -} - -impl Display for AsyncBlock { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "async {{")?; - - for statement in &self.statements { - write!(f, "{statement}")?; - } - - write!(f, "}}") - } -} diff --git a/dust-lang/src/abstract_tree/block.rs b/dust-lang/src/abstract_tree/block.rs deleted file mode 100644 index ba106de..0000000 --- a/dust-lang/src/abstract_tree/block.rs +++ /dev/null @@ -1,124 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, -}; - -use super::{AbstractNode, Evaluation, SourcePosition, Statement, Type}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct Block { - statements: Vec, -} - -impl Block { - pub fn new(statements: Vec) -> Self { - Self { statements } - } - - pub fn first_statement(&self) -> &Statement { - self.statements.first().unwrap() - } - - pub fn last_statement(&self) -> &Statement { - self.statements.last().unwrap() - } -} - -impl AbstractNode for Block { - fn define_and_validate( - &self, - _context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - for statement in &self.statements { - statement.define_and_validate(_context, _manage_memory, scope)?; - } - - Ok(()) - } - - fn evaluate( - self, - _context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - let mut previous = None; - - for statement in self.statements { - previous = statement.evaluate(_context, _manage_memory, scope)?; - } - - Ok(previous) - } - - fn expected_type(&self, _context: &Context) -> Result, ValidationError> { - self.last_statement().expected_type(_context) - } -} - -impl Display for Block { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "{{ ")?; - - for statement in &self.statements { - write!(f, "{statement} ")?; - } - - write!(f, "}}") - } -} - -#[cfg(test)] -mod tests { - use crate::{ - abstract_tree::{Expression, ValueNode, WithPos}, - Value, - }; - - use super::*; - - #[test] - fn run_returns_value_of_final_statement() { - let block = Block::new(vec![ - Statement::Expression(Expression::Value( - ValueNode::Integer(1).with_position((0, 0)), - )), - Statement::Expression(Expression::Value( - ValueNode::Integer(2).with_position((0, 0)), - )), - Statement::Expression(Expression::Value( - ValueNode::Integer(42).with_position((0, 0)), - )), - ]); - - assert_eq!( - block - .evaluate(&Context::new(), true, SourcePosition(0, 0)) - .unwrap(), - Some(Evaluation::Return(Value::integer(42))) - ) - } - - #[test] - fn expected_type_returns_type_of_final_statement() { - let block = Block::new(vec![ - Statement::Expression(Expression::Value( - ValueNode::String("42".to_string()).with_position((0, 0)), - )), - Statement::Expression(Expression::Value( - ValueNode::Integer(42).with_position((0, 0)), - )), - ]); - - assert_eq!( - block.expected_type(&Context::new()), - Ok(Some(Type::Integer)) - ) - } -} diff --git a/dust-lang/src/abstract_tree/built_in_function.rs b/dust-lang/src/abstract_tree/built_in_function.rs deleted file mode 100644 index b8fc9e9..0000000 --- a/dust-lang/src/abstract_tree/built_in_function.rs +++ /dev/null @@ -1,305 +0,0 @@ -use std::{ - fmt::{self, Display, Formatter}, - fs::read_to_string, - io::stdin, - thread::sleep, - time::Duration, -}; - -use serde::{Deserialize, Serialize}; -use serde_json::from_str; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - identifier::Identifier, - value::ValueInner, - Value, -}; - -use super::Type; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum BuiltInFunction { - Length, - ReadLine, - ReadFile, - Sleep, - WriteLine, - JsonParse, -} - -impl BuiltInFunction { - pub fn r#type(&self) -> Type { - match self { - BuiltInFunction::Length => Length::r#type(), - BuiltInFunction::ReadLine => ReadLine::r#type(), - BuiltInFunction::ReadFile => ReadFile::r#type(), - BuiltInFunction::Sleep => Sleep::r#type(), - BuiltInFunction::WriteLine => WriteLine::r#type(), - BuiltInFunction::JsonParse => JsonParse::r#type(), - } - } - - pub fn call( - &self, - context: &Context, - manage_memory: bool, - ) -> Result, RuntimeError> { - match self { - BuiltInFunction::Length => Length::call(context, manage_memory), - BuiltInFunction::ReadLine => ReadLine::call(context, manage_memory), - BuiltInFunction::ReadFile => ReadFile::call(context, manage_memory), - BuiltInFunction::Sleep => Sleep::call(context, manage_memory), - BuiltInFunction::WriteLine => WriteLine::call(context, manage_memory), - BuiltInFunction::JsonParse => JsonParse::call(context, manage_memory), - } - } -} - -impl Display for BuiltInFunction { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let display = match self { - BuiltInFunction::Length => "__LENGTH__", - BuiltInFunction::ReadLine => "__READ_LINE__", - BuiltInFunction::ReadFile => "__READ_FILE__", - BuiltInFunction::Sleep => "__SLEEP__", - BuiltInFunction::WriteLine => "__WRITE_LINE__", - BuiltInFunction::JsonParse => "__JSON_PARSE__", - }; - - write!(f, "{display}") - } -} - -trait FunctionLogic { - fn r#type() -> Type; - fn call(context: &Context, manage_memory: bool) -> Result, RuntimeError>; -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -struct Length; - -impl FunctionLogic for Length { - fn r#type() -> Type { - Type::Function { - type_parameters: None, - value_parameters: Some(vec![( - Identifier::from("list"), - Type::ListOf(Box::new(Type::Any)), - )]), - return_type: Some(Box::new(Type::Integer)), - } - } - - fn call(context: &Context, _: bool) -> Result, RuntimeError> { - let value = if let Some(value) = context.get_value(&Identifier::from("input"))? { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::BuiltInFunctionFailure("input does not exist"), - )); - }; - let list = if let ValueInner::List(list) = value.inner().as_ref() { - list - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::BuiltInFunctionFailure("list is not a list"), - )); - }; - - Ok(Some(Value::integer(list.len() as i64))) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -struct ReadFile; - -impl FunctionLogic for ReadFile { - fn r#type() -> Type { - Type::Function { - type_parameters: None, - value_parameters: Some(vec![(Identifier::from("path"), Type::String)]), - return_type: Some(Box::new(Type::String)), - } - } - - fn call(context: &Context, _: bool) -> Result, RuntimeError> { - let value = if let Some(value) = context.get_value(&Identifier::from("path"))? { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::BuiltInFunctionFailure("path does not exist"), - )); - }; - let path = if let ValueInner::String(string) = value.inner().as_ref() { - string - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::BuiltInFunctionFailure("path is not a string"), - )); - }; - let file_content = read_to_string(path)?; - - Ok(Some(Value::string(file_content))) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -struct ReadLine; - -impl FunctionLogic for ReadLine { - fn r#type() -> Type { - Type::Function { - type_parameters: None, - value_parameters: None, - return_type: Some(Box::new(Type::String)), - } - } - - fn call(_: &Context, _: bool) -> Result, RuntimeError> { - let mut user_input = String::new(); - - stdin().read_line(&mut user_input)?; - - Ok(Some(Value::string(user_input.trim_end_matches('\n')))) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -struct Sleep; - -impl FunctionLogic for Sleep { - fn r#type() -> Type { - Type::Function { - type_parameters: None, - value_parameters: Some(vec![(Identifier::from("milliseconds"), Type::Integer)]), - return_type: None, - } - } - - fn call(context: &Context, _: bool) -> Result, RuntimeError> { - let value = if let Some(value) = context.get_value(&Identifier::from("milliseconds"))? { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::BuiltInFunctionFailure("milliseconds does not exist"), - )); - }; - let milliseconds = if let ValueInner::Integer(integer) = value.inner().as_ref() { - integer - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::BuiltInFunctionFailure("milliseconds is not an integer"), - )); - }; - - sleep(Duration::from_millis(*milliseconds as u64)); - - Ok(None) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -struct WriteLine; - -impl FunctionLogic for WriteLine { - fn r#type() -> Type { - Type::Function { - type_parameters: None, - value_parameters: Some(vec![(Identifier::from("output"), Type::String)]), - return_type: None, - } - } - - fn call(context: &Context, _: bool) -> Result, RuntimeError> { - let value = if let Some(value) = context.get_value(&Identifier::from("output"))? { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::BuiltInFunctionFailure("output does not exist"), - )); - }; - let output = if let ValueInner::String(string) = value.inner().as_ref() { - string - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::BuiltInFunctionFailure("output is not a string"), - )); - }; - - println!("{output}"); - - Ok(None) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -struct JsonParse; - -impl FunctionLogic for JsonParse { - fn r#type() -> Type { - let type_t = Type::Generic { - identifier: Identifier::from("T"), - concrete_type: None, - }; - - Type::Function { - type_parameters: Some(vec![Identifier::from("T")]), - value_parameters: Some(vec![(Identifier::from("input"), type_t.clone())]), - return_type: Some(Box::new(type_t)), - } - } - - fn call(context: &Context, _: bool) -> Result, RuntimeError> { - let target_type = if let Some(r#type) = context.get_type(&Identifier::from("T"))? { - r#type - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::BuiltInFunctionFailure("T does not exist"), - )); - }; - let value = if let Some(value) = context.get_value(&Identifier::from("input"))? { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::BuiltInFunctionFailure("input does not exist"), - )); - }; - let input = if let ValueInner::String(string) = value.inner().as_ref() { - string - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::BuiltInFunctionFailure("input is not a string"), - )); - }; - - fn parse_value(input: &str, r#type: Type) -> Result { - let value = match r#type { - Type::Any => from_str::(input)?, - Type::Boolean => Value::boolean(from_str::(input)?), - Type::Enum { .. } => todo!(), - Type::Float => Value::float(from_str::(input)?), - Type::Function { .. } => todo!(), - Type::Generic { concrete_type, .. } => { - if let Some(r#type) = concrete_type { - parse_value(input, *r#type)? - } else { - todo!("Create an error for this occurence"); - } - } - Type::Integer => Value::integer(from_str::(input)?), - Type::List { .. } => todo!(), - Type::ListOf(_) => todo!(), - Type::Map(_) => todo!(), - Type::Range => todo!(), - Type::String => Value::string(from_str::(input)?), - Type::Structure { .. } => todo!(), - }; - - Ok(value) - } - - parse_value(input, target_type).map(Some) - } -} diff --git a/dust-lang/src/abstract_tree/enum_declaration.rs b/dust-lang/src/abstract_tree/enum_declaration.rs deleted file mode 100644 index 01f7084..0000000 --- a/dust-lang/src/abstract_tree/enum_declaration.rs +++ /dev/null @@ -1,148 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - identifier::Identifier, -}; - -use super::{AbstractNode, Evaluation, SourcePosition, Type, TypeConstructor, WithPosition}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct EnumDeclaration { - name: WithPosition, - type_parameters: Option>>, - variants: Vec, -} - -impl EnumDeclaration { - pub fn new( - name: WithPosition, - type_parameters: Option>>, - variants: Vec, - ) -> Self { - Self { - name, - type_parameters, - variants, - } - } -} - -impl AbstractNode for EnumDeclaration { - fn define_and_validate( - &self, - context: &Context, - _: bool, - _scope: SourcePosition, - ) -> Result<(), ValidationError> { - let EnumDeclaration { - name, - type_parameters, - variants, - } = self; - - let type_parameters = type_parameters.as_ref().map(|parameters| { - parameters - .iter() - .map(|identifier| Type::Generic { - identifier: identifier.node.clone(), - concrete_type: None, - }) - .collect() - }); - let mut type_variants = Vec::with_capacity(variants.len()); - - for EnumVariant { name, content } in variants { - let types = if let Some(content) = content { - let mut types = Vec::with_capacity(content.len()); - - for constructor in content { - let r#type = constructor.construct(context)?; - - types.push(r#type); - } - - Some(types) - } else { - None - }; - - type_variants.push((name.node.clone(), types)); - } - - let r#type = Type::Enum { - name: name.node.clone(), - type_parameters, - variants: type_variants, - }; - let final_node_position = if let Some(constructors) = &self.variants.last().unwrap().content - { - constructors.last().unwrap().position() - } else { - self.variants.last().unwrap().name.position - }; - let scope = SourcePosition(self.name.position.0, final_node_position.1); - - context.set_type(name.node.clone(), r#type, scope)?; - - Ok(()) - } - - fn evaluate( - self, - _: &Context, - _: bool, - _scope: SourcePosition, - ) -> Result, RuntimeError> { - Ok(None) - } - - fn expected_type(&self, _: &Context) -> Result, ValidationError> { - Ok(None) - } -} - -impl Display for EnumDeclaration { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let EnumDeclaration { - name, - type_parameters, - variants, - } = self; - - write!(f, "enum {}", name.node)?; - - if let Some(parameters) = type_parameters { - write!(f, "<")?; - for WithPosition { node, .. } in parameters { - write!(f, "{node}, ")?; - } - write!(f, ">")?; - } - - for EnumVariant { name, content } in variants { - write!(f, "{}", name.node)?; - - if let Some(content) = content { - write!(f, "(")?; - - for constructor in content { - write!(f, "{constructor}, ")?; - } - - write!(f, ")")?; - } - } - - Ok(()) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct EnumVariant { - pub name: WithPosition, - pub content: Option>, -} diff --git a/dust-lang/src/abstract_tree/expression.rs b/dust-lang/src/abstract_tree/expression.rs deleted file mode 100644 index ce038fa..0000000 --- a/dust-lang/src/abstract_tree/expression.rs +++ /dev/null @@ -1,174 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - identifier::Identifier, -}; - -use super::{ - AbstractNode, As, Evaluation, FunctionCall, ListIndex, Logic, MapIndex, Math, SourcePosition, - Type, ValueNode, WithPosition, -}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum Expression { - As(WithPosition>), - FunctionCall(WithPosition), - Identifier(WithPosition), - MapIndex(WithPosition>), - ListIndex(WithPosition>), - Logic(WithPosition>), - Math(WithPosition>), - Value(WithPosition), -} - -impl Expression { - pub fn position(&self) -> SourcePosition { - match self { - Expression::As(inner) => inner.position, - Expression::FunctionCall(inner) => inner.position, - Expression::Identifier(inner) => inner.position, - Expression::MapIndex(inner) => inner.position, - Expression::ListIndex(inner) => inner.position, - Expression::Logic(inner) => inner.position, - Expression::Math(inner) => inner.position, - Expression::Value(inner) => inner.position, - } - } -} - -impl AbstractNode for Expression { - fn define_and_validate( - &self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - match self { - Expression::As(r#as) => r#as.node.define_and_validate(context, manage_memory, scope), - Expression::FunctionCall(function_call) => { - function_call - .node - .define_and_validate(context, manage_memory, scope) - } - Expression::Identifier(identifier) => { - let found = context.add_expected_use(&identifier.node)?; - - if found { - Ok(()) - } else { - Err(ValidationError::VariableNotFound { - identifier: identifier.node.clone(), - position: identifier.position, - }) - } - } - Expression::MapIndex(map_index) => { - map_index - .node - .define_and_validate(context, manage_memory, scope) - } - Expression::ListIndex(list_index) => { - list_index - .node - .define_and_validate(context, manage_memory, scope) - } - Expression::Logic(logic) => { - logic - .node - .define_and_validate(context, manage_memory, scope) - } - Expression::Math(math) => math.node.define_and_validate(context, manage_memory, scope), - Expression::Value(value_node) => { - value_node - .node - .define_and_validate(context, manage_memory, scope) - } - } - } - - fn evaluate( - self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - match self { - Expression::As(r#as) => r#as.node.evaluate(context, manage_memory, scope), - Expression::FunctionCall(function_call) => { - function_call.node.evaluate(context, manage_memory, scope) - } - Expression::Identifier(identifier) => { - let value_option = if manage_memory { - context.use_value(&identifier.node)? - } else { - context.get_value(&identifier.node)? - }; - - if let Some(value) = value_option { - Ok(Some(Evaluation::Return(value))) - } else { - Err(RuntimeError::ValidationFailure( - ValidationError::VariableNotFound { - identifier: identifier.node.clone(), - position: identifier.position, - }, - )) - } - } - Expression::MapIndex(map_index) => { - map_index.node.evaluate(context, manage_memory, scope) - } - Expression::ListIndex(list_index) => { - list_index.node.evaluate(context, manage_memory, scope) - } - Expression::Logic(logic) => logic.node.evaluate(context, manage_memory, scope), - Expression::Math(math) => math.node.evaluate(context, manage_memory, scope), - Expression::Value(value_node) => { - value_node.node.evaluate(context, manage_memory, scope) - } - } - } - - fn expected_type(&self, _context: &Context) -> Result, ValidationError> { - match self { - Expression::As(r#as) => r#as.node.expected_type(_context), - Expression::FunctionCall(function_call) => function_call.node.expected_type(_context), - Expression::Identifier(identifier) => { - let get_type = _context.get_type(&identifier.node)?; - - if get_type.is_none() { - Err(ValidationError::VariableNotFound { - identifier: identifier.node.clone(), - position: identifier.position, - }) - } else { - Ok(get_type) - } - } - Expression::MapIndex(map_index) => map_index.node.expected_type(_context), - Expression::ListIndex(list_index) => list_index.node.expected_type(_context), - Expression::Logic(logic) => logic.node.expected_type(_context), - Expression::Math(math) => math.node.expected_type(_context), - Expression::Value(value_node) => value_node.node.expected_type(_context), - } - } -} - -impl Display for Expression { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Expression::As(inner) => write!(f, "{}", inner.node), - Expression::FunctionCall(inner) => write!(f, "{}", inner.node), - Expression::Identifier(inner) => write!(f, "{}", inner.node), - Expression::MapIndex(inner) => write!(f, "{}", inner.node), - Expression::ListIndex(inner) => write!(f, "{}", inner.node), - Expression::Logic(inner) => write!(f, "{}", inner.node), - Expression::Math(inner) => write!(f, "{}", inner.node), - Expression::Value(inner) => write!(f, "{}", inner.node), - } - } -} diff --git a/dust-lang/src/abstract_tree/for.rs b/dust-lang/src/abstract_tree/for.rs deleted file mode 100644 index ce3f50b..0000000 --- a/dust-lang/src/abstract_tree/for.rs +++ /dev/null @@ -1,99 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - identifier::Identifier, -}; - -use super::{AbstractNode, Block, Evaluation, Expression, Statement, Type}; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct For { - identifier: Identifier, - expression: Expression, - block: Block, - - #[serde(skip)] - context: Context, -} - -impl For { - pub fn new(identifier: Identifier, expression: Expression, block: Block) -> Self { - Self { - identifier, - expression, - block, - context: Context::new(None), - } - } -} - -impl AbstractNode for For { - fn define_types(&self, context: &Context) -> Result<(), ValidationError> { - self.context.set_parent(context.clone())?; - self.expression.define_types(context)?; - - let collection_type = - self.expression - .expected_type(context)? - .ok_or(ValidationError::ExpectedExpression( - self.expression.position(), - ))?; - - let item_type = if let Type::Range = collection_type { - Type::Integer - } else { - todo!("Create an error for this occurence"); - }; - - self.context.set_type(self.identifier.clone(), item_type)?; - - for statement in self.block.statements() { - statement.define_types(&self.context)?; - } - - Ok(()) - } - - fn validate(&self, context: &Context, manage_memory: bool) -> Result<(), ValidationError> { - todo!() - } - - fn evaluate( - self, - context: &Context, - manage_memory: bool, - ) -> Result, RuntimeError> { - todo!() - } - - fn expected_type( - &self, - context: &crate::context::Context, - ) -> Result, ValidationError> { - todo!() - } -} - -impl Eq for For {} - -impl PartialEq for For { - fn eq(&self, other: &Self) -> bool { - self.identifier == other.identifier - && self.expression == other.expression - && self.block == other.block - } -} - -impl PartialOrd for For { - fn partial_cmp(&self, other: &Self) -> Option { - todo!() - } -} - -impl Ord for For { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - todo!() - } -} diff --git a/dust-lang/src/abstract_tree/function_call.rs b/dust-lang/src/abstract_tree/function_call.rs deleted file mode 100644 index 9fec472..0000000 --- a/dust-lang/src/abstract_tree/function_call.rs +++ /dev/null @@ -1,381 +0,0 @@ -use std::{ - cmp::Ordering, - fmt::{self, Display, Formatter}, -}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - value::ValueInner, -}; - -use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type, TypeConstructor}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct FunctionCall { - function_expression: Box, - type_arguments: Option>, - value_arguments: Option>, -} - -impl FunctionCall { - pub fn new( - function_expression: Expression, - type_arguments: Option>, - value_arguments: Option>, - ) -> Self { - FunctionCall { - function_expression: Box::new(function_expression), - type_arguments, - value_arguments, - } - } -} - -impl AbstractNode for FunctionCall { - fn define_and_validate( - &self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - self.function_expression - .define_and_validate(context, manage_memory, scope)?; - - if let Some(value_arguments) = &self.value_arguments { - for expression in value_arguments { - expression.define_and_validate(context, manage_memory, scope)?; - } - } - - let function_node_type = - if let Some(r#type) = self.function_expression.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - self.function_expression.position(), - )); - }; - - if let Type::Function { - type_parameters, - value_parameters, - return_type: _, - } = function_node_type - { - match (type_parameters, &self.type_arguments) { - (Some(parameters), Some(arguments)) => { - if parameters.len() != arguments.len() { - return Err(ValidationError::WrongTypeArguments { - arguments: arguments.clone(), - parameters: parameters.clone(), - }); - } - - for (identifier, constructor) in parameters.into_iter().zip(arguments.iter()) { - let r#type = constructor.construct(context)?; - - context.set_type( - identifier, - r#type, - self.function_expression.position(), - )?; - } - } - (Some(parameters), None) => { - return Err(ValidationError::WrongTypeArguments { - arguments: Vec::with_capacity(0), - parameters: parameters.clone(), - }); - } - (None, Some(arguments)) => { - return Err(ValidationError::WrongTypeArguments { - arguments: arguments.clone(), - parameters: Vec::with_capacity(0), - }); - } - (None, None) => {} - } - - match (value_parameters, &self.value_arguments) { - (Some(parameters), Some(arguments)) => { - for ((identifier, _), expression) in parameters.iter().zip(arguments.iter()) { - let r#type = if let Some(r#type) = expression.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - expression.position(), - )); - }; - - context.set_type( - identifier.clone(), - r#type, - self.function_expression.position(), - )?; - } - - if parameters.len() != arguments.len() { - return Err(ValidationError::WrongValueArguments { - parameters, - arguments: arguments.clone(), - }); - } - } - (Some(parameters), None) => { - return Err(ValidationError::WrongValueArguments { - parameters, - arguments: Vec::with_capacity(0), - }); - } - (None, Some(arguments)) => { - return Err(ValidationError::WrongValueArguments { - parameters: Vec::with_capacity(0), - arguments: arguments.clone(), - }); - } - (None, None) => {} - } - - return Ok(()); - } - - Err(ValidationError::ExpectedFunction { - actual: function_node_type, - position: self.function_expression.position(), - }) - } - - fn evaluate( - self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - let function_position = self.function_expression.position(); - let evaluation = self - .function_expression - .evaluate(context, manage_memory, scope)?; - let value = if let Some(Evaluation::Return(value)) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(function_position), - )); - }; - - if let ValueInner::Function(function) = value.inner().as_ref() { - let type_arguments = if let Some(type_arguments) = self.type_arguments { - let mut types = Vec::with_capacity(type_arguments.len()); - - for constructor in type_arguments { - types.push(constructor.construct(context)?) - } - - Some(types) - } else { - None - }; - let value_arguments = if let Some(value_arguments) = self.value_arguments { - let mut values = Vec::with_capacity(value_arguments.len()); - - for expression in value_arguments { - let position = expression.position(); - let evaluation = (expression.evaluate(context, manage_memory, scope)?).ok_or( - RuntimeError::ValidationFailure(ValidationError::ExpectedValueStatement( - position, - )), - )?; - let value = if let Evaluation::Return(value) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(position), - )); - }; - - values.push(value); - } - - Some(values) - } else { - None - }; - - return function - .clone() - .call(Some(context), type_arguments, value_arguments); - } - - if let ValueInner::BuiltInFunction(function) = value.inner().as_ref() { - let (type_parameters, value_parameters, _) = if let Type::Function { - type_parameters, - value_parameters, - return_type, - } = function.r#type() - { - (type_parameters, value_parameters, return_type) - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedFunction { - actual: function.r#type(), - position: function_position, - }, - )); - }; - - if let (Some(type_parameters), Some(type_arguments)) = - (type_parameters, self.type_arguments) - { - for (identifier, constructor) in - type_parameters.into_iter().zip(type_arguments.into_iter()) - { - let r#type = constructor.construct(context)?; - - context.set_type(identifier.clone(), r#type, function_position)?; - } - } - - if let (Some(parameters), Some(arguments)) = (value_parameters, self.value_arguments) { - for ((identifier, _), expression) in - parameters.into_iter().zip(arguments.into_iter()) - { - let position = expression.position(); - let evaluation = expression.evaluate(context, manage_memory, scope)?; - let value = if let Some(Evaluation::Return(value)) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(position), - )); - }; - - context.set_value(identifier.clone(), value, function_position)?; - } - } - - return function - .call(context, manage_memory) - .map(|option| option.map(Evaluation::Return)); - } - - Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedFunction { - actual: value.r#type(context)?, - position: function_position, - }, - )) - } - - fn expected_type(&self, context: &Context) -> Result, ValidationError> { - let expression_type = self.function_expression.expected_type(context)?.ok_or( - ValidationError::ExpectedValueStatement(self.function_expression.position()), - )?; - - let (type_parameters, return_type) = if let Type::Function { - type_parameters, - return_type, - .. - } = expression_type - { - (type_parameters, return_type) - } else { - return Err(ValidationError::ExpectedFunction { - actual: expression_type, - position: self.function_expression.position(), - }); - }; - - if let Some(Type::Generic { - identifier: return_identifier, - concrete_type: None, - }) = return_type.clone().map(|r#box| *r#box) - { - if let (Some(parameters), Some(arguments)) = (type_parameters, &self.type_arguments) { - for (identifier, constructor) in parameters.into_iter().zip(arguments.iter()) { - if identifier == return_identifier { - let r#type = constructor.construct(context)?; - - return Ok(Some(Type::Generic { - identifier, - concrete_type: Some(Box::new(r#type)), - })); - } - } - } - } - - Ok(return_type.map(|r#box| *r#box)) - } -} - -impl Display for FunctionCall { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let FunctionCall { - function_expression, - type_arguments, - value_arguments, - .. - } = self; - - write!(f, "{function_expression}")?; - - if let Some(type_arguments) = type_arguments { - write!(f, "::<")?; - - for constructor in type_arguments { - write!(f, "{constructor}, ")?; - } - - write!(f, ">")?; - } - - write!(f, "(")?; - - if let Some(value_arguments) = value_arguments { - for expression in value_arguments { - write!(f, "{expression}, ")?; - } - } - - write!(f, ")")?; - - Ok(()) - } -} - -impl Eq for FunctionCall {} - -impl PartialEq for FunctionCall { - fn eq(&self, other: &Self) -> bool { - self.function_expression == other.function_expression - && self.type_arguments == other.type_arguments - && self.value_arguments == other.value_arguments - } -} - -impl PartialOrd for FunctionCall { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for FunctionCall { - fn cmp(&self, other: &Self) -> Ordering { - let expression_cmp = self.function_expression.cmp(&other.function_expression); - - if expression_cmp.is_eq() { - let type_arg_cmp = self.type_arguments.cmp(&other.type_arguments); - - if type_arg_cmp.is_eq() { - self.value_arguments.cmp(&other.value_arguments) - } else { - type_arg_cmp - } - } else { - expression_cmp - } - } -} diff --git a/dust-lang/src/abstract_tree/if_else.rs b/dust-lang/src/abstract_tree/if_else.rs deleted file mode 100644 index d6cbd6a..0000000 --- a/dust-lang/src/abstract_tree/if_else.rs +++ /dev/null @@ -1,231 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - value::ValueInner, -}; - -use super::{AbstractNode, Block, Evaluation, Expression, SourcePosition, Type, WithPosition}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct IfElse { - if_expression: Expression, - if_block: WithPosition, - else_ifs: Option)>>, - else_block: Option>, -} - -impl IfElse { - pub fn new( - if_expression: Expression, - if_block: WithPosition, - else_ifs: Option)>>, - else_block: Option>, - ) -> Self { - Self { - if_expression, - if_block, - else_ifs, - else_block, - } - } -} - -impl AbstractNode for IfElse { - fn define_and_validate( - &self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - self.if_expression - .define_and_validate(context, manage_memory, scope)?; - self.if_block - .node - .define_and_validate(context, manage_memory, scope)?; - - let if_expression_type = if let Some(r#type) = self.if_expression.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - self.if_expression.position(), - )); - }; - let if_block_type = self.if_block.node.expected_type(context)?; - - if let Some(else_ifs) = &self.else_ifs { - for (expression, block) in else_ifs { - let expression_type = expression.expected_type(context)?; - - if let Some(Type::Boolean) = expression_type { - block - .node - .define_and_validate(context, manage_memory, scope)?; - - let else_if_block_type = block.node.expected_type(context)?; - - if let (Some(expected), Some(actual)) = (&if_block_type, else_if_block_type) { - expected - .check(&actual) - .map_err(|conflict| ValidationError::TypeCheck { - conflict, - actual_position: self.if_block.node.last_statement().position(), - - expected_position: Some(self.if_expression.position()), - })?; - } - } else { - return Err(ValidationError::ExpectedBoolean { - actual: if_expression_type, - position: self.if_expression.position(), - }); - } - } - } - - if let Some(block) = &self.else_block { - block - .node - .define_and_validate(context, manage_memory, scope)?; - - let else_if_block_type = block.node.expected_type(context)?; - - if let (Some(expected), Some(actual)) = (if_block_type, else_if_block_type) { - expected - .check(&actual) - .map_err(|conflict| ValidationError::TypeCheck { - conflict, - actual_position: self.if_block.node.last_statement().position(), - expected_position: Some(self.if_expression.position()), - })?; - } - } - - Ok(()) - } - - fn evaluate( - self, - context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - let if_position = self.if_expression.position(); - let evaluation = self - .if_expression - .evaluate(context, _manage_memory, scope)?; - let value = if let Some(Evaluation::Return(value)) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(if_position), - )); - }; - - if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() { - if *if_boolean { - return self.if_block.node.evaluate(context, _manage_memory, scope); - } - - if let Some(else_ifs) = self.else_ifs { - for (expression, block) in else_ifs { - let expression_position = expression.position(); - let evaluation = expression.evaluate(context, _manage_memory, scope)?; - let value = if let Some(Evaluation::Return(value)) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(expression_position), - )); - }; - - if let ValueInner::Boolean(else_if_boolean) = value.inner().as_ref() { - if *else_if_boolean { - return block.node.evaluate(context, _manage_memory, scope); - } - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedBoolean { - actual: value.r#type(context)?, - position: expression_position, - }, - )); - } - } - } - - if let Some(else_statement) = self.else_block { - else_statement.node.evaluate(context, _manage_memory, scope) - } else { - Ok(None) - } - } else { - Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedBoolean { - actual: value.r#type(context)?, - position: if_position, - }, - )) - } - } - - fn expected_type(&self, _context: &Context) -> Result, ValidationError> { - self.if_block.node.expected_type(_context) - } -} - -impl Display for IfElse { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let IfElse { - if_expression, - if_block, - else_ifs, - else_block, - } = self; - - write!(f, "if {if_expression} {}", if_block.node)?; - - if let Some(else_ifs) = else_ifs { - for (expression, block) in else_ifs { - write!(f, "else if {expression} {}", block.node)?; - } - } - - if let Some(else_block) = else_block { - write!(f, "{}", else_block.node)?; - } - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use crate::{ - abstract_tree::{Statement, ValueNode, WithPos}, - Value, - }; - - use super::*; - - #[test] - fn simple_if() { - assert_eq!( - IfElse::new( - Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), - Block::new(vec![Statement::Expression(Expression::Value( - ValueNode::String("foo".to_string()).with_position((0, 0)) - ))]) - .with_position((0, 0)), - Some(Vec::with_capacity(0)), - None - ) - .evaluate(&Context::new(), true, SourcePosition(0, 0)) - .unwrap(), - Some(Evaluation::Return(Value::string("foo".to_string()))) - ) - } -} diff --git a/dust-lang/src/abstract_tree/list_index.rs b/dust-lang/src/abstract_tree/list_index.rs deleted file mode 100644 index 351f41d..0000000 --- a/dust-lang/src/abstract_tree/list_index.rs +++ /dev/null @@ -1,165 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, -}; - -use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type, ValueNode, WithPosition}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct ListIndex { - collection: Expression, - index: Expression, -} - -impl ListIndex { - pub fn new(left: Expression, right: Expression) -> Self { - Self { - collection: left, - index: right, - } - } -} - -impl AbstractNode for ListIndex { - fn define_and_validate( - &self, - context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - self.collection - .define_and_validate(context, _manage_memory, scope)?; - self.index - .define_and_validate(context, _manage_memory, scope)?; - - let collection_type = if let Some(r#type) = self.collection.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - self.collection.position(), - )); - }; - let index_type = if let Some(r#type) = self.index.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - self.index.position(), - )); - }; - - match collection_type { - Type::List { - length: _, - item_type: _, - } => { - if index_type == Type::Integer { - Ok(()) - } else { - Err(ValidationError::CannotIndexWith { - collection_type, - collection_position: self.collection.position(), - index_type, - index_position: self.index.position(), - }) - } - } - Type::ListOf(_) => todo!(), - _ => Err(ValidationError::CannotIndex { - r#type: collection_type, - position: self.collection.position(), - }), - } - } - - fn evaluate( - self, - context: &Context, - _clear_variables: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - let left_position = self.collection.position(); - let left_evaluation = self.collection.evaluate(context, _clear_variables, scope)?; - let left_value = if let Some(Evaluation::Return(value)) = left_evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(left_position), - )); - }; - let right_position = self.index.position(); - let right_evaluation = self.index.evaluate(context, _clear_variables, scope)?; - let right_value = if let Some(Evaluation::Return(value)) = right_evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(right_position), - )); - }; - - if let (Some(list), Some(index)) = (left_value.as_list(), right_value.as_integer()) { - let found_item = list.get(index as usize); - - if let Some(item) = found_item { - Ok(Some(Evaluation::Return(item.clone()))) - } else { - Ok(None) - } - } else { - Err(RuntimeError::ValidationFailure( - ValidationError::CannotIndexWith { - collection_type: left_value.r#type(context)?, - collection_position: left_position, - index_type: right_value.r#type(context)?, - index_position: right_position, - }, - )) - } - } - - fn expected_type(&self, _context: &Context) -> Result, ValidationError> { - let left_type = if let Some(r#type) = self.collection.expected_type(_context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - self.collection.position(), - )); - }; - - if let ( - Expression::Value(WithPosition { - node: ValueNode::List(expression_list), - .. - }), - Expression::Value(WithPosition { - node: ValueNode::Integer(index), - .. - }), - ) = (&self.collection, &self.index) - { - let expression = if let Some(expression) = expression_list.get(*index as usize) { - expression - } else { - return Ok(None); - }; - - expression.expected_type(_context) - } else { - Err(ValidationError::CannotIndex { - r#type: left_type, - position: self.collection.position(), - }) - } - } -} - -impl Display for ListIndex { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let ListIndex { collection, index } = self; - - write!(f, "{collection}[{index}]") - } -} diff --git a/dust-lang/src/abstract_tree/logic.rs b/dust-lang/src/abstract_tree/logic.rs deleted file mode 100644 index ce1008a..0000000 --- a/dust-lang/src/abstract_tree/logic.rs +++ /dev/null @@ -1,378 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - value::ValueInner, - Value, -}; - -use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum Logic { - Equal(Expression, Expression), - NotEqual(Expression, Expression), - Greater(Expression, Expression), - Less(Expression, Expression), - GreaterOrEqual(Expression, Expression), - LessOrEqual(Expression, Expression), - And(Expression, Expression), - Or(Expression, Expression), - Not(Expression), -} - -impl AbstractNode for Logic { - fn define_and_validate( - &self, - context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - match self { - Logic::Equal(left, right) - | Logic::NotEqual(left, right) - | Logic::Greater(left, right) - | Logic::Less(left, right) - | Logic::GreaterOrEqual(left, right) - | Logic::LessOrEqual(left, right) => { - left.define_and_validate(context, _manage_memory, scope)?; - right.define_and_validate(context, _manage_memory, scope)?; - - let left_type = if let Some(r#type) = left.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement(left.position())); - }; - let right_type = if let Some(r#type) = right.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement(right.position())); - }; - - left_type - .check(&right_type) - .map_err(|conflict| ValidationError::TypeCheck { - conflict, - actual_position: left.position(), - expected_position: Some(right.position()), - })?; - - Ok(()) - } - Logic::And(left, right) | Logic::Or(left, right) => { - left.define_and_validate(context, _manage_memory, scope)?; - right.define_and_validate(context, _manage_memory, scope)?; - - let left_type = if let Some(r#type) = left.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement(left.position())); - }; - let right_type = if let Some(r#type) = right.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement(right.position())); - }; - - if let Type::Boolean = left_type { - } else { - return Err(ValidationError::ExpectedBoolean { - actual: left_type, - position: left.position(), - }); - } - - if let Type::Boolean = right_type { - } else { - return Err(ValidationError::ExpectedBoolean { - actual: right_type, - position: right.position(), - }); - } - - Ok(()) - } - Logic::Not(expression) => { - expression.define_and_validate(context, _manage_memory, scope)?; - - let expression_type = if let Some(r#type) = expression.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - expression.position(), - )); - }; - - if let Type::Boolean = expression_type { - Ok(()) - } else { - Err(ValidationError::ExpectedBoolean { - actual: expression_type, - position: expression.position(), - }) - } - } - } - } - - fn evaluate( - self, - context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - let run_and_expect_value = |expression: Expression| -> Result { - let expression_position = expression.position(); - let evaluation = expression.evaluate(context, _manage_memory, scope)?; - let value = if let Some(Evaluation::Return(value)) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(expression_position), - )); - }; - - Ok(value) - }; - - let run_and_expect_boolean = |expression: Expression| -> Result { - let expression_position = expression.position(); - let evaluation = expression.evaluate(context, _manage_memory, scope)?; - let value = if let Some(Evaluation::Return(value)) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(expression_position), - )); - }; - - if let ValueInner::Boolean(boolean) = value.inner().as_ref() { - Ok(*boolean) - } else { - Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedBoolean { - actual: value.r#type(context)?, - position: expression_position, - }, - )) - } - }; - - let boolean = match self { - Logic::Equal(left, right) => { - let (left_value, right_value) = - (run_and_expect_value(left)?, run_and_expect_value(right)?); - - left_value == right_value - } - Logic::NotEqual(left, right) => { - let (left_value, right_value) = - (run_and_expect_value(left)?, run_and_expect_value(right)?); - - left_value != right_value - } - Logic::Greater(left, right) => { - let (left_value, right_value) = - (run_and_expect_value(left)?, run_and_expect_value(right)?); - - left_value > right_value - } - Logic::Less(left, right) => { - let (left_value, right_value) = - (run_and_expect_value(left)?, run_and_expect_value(right)?); - - left_value < right_value - } - Logic::GreaterOrEqual(left, right) => { - let (left_value, right_value) = - (run_and_expect_value(left)?, run_and_expect_value(right)?); - - left_value >= right_value - } - Logic::LessOrEqual(left, right) => { - let (left_value, right_value) = - (run_and_expect_value(left)?, run_and_expect_value(right)?); - - left_value <= right_value - } - Logic::And(left, right) => { - let (left_boolean, right_boolean) = ( - run_and_expect_boolean(left)?, - run_and_expect_boolean(right)?, - ); - - left_boolean && right_boolean - } - Logic::Or(left, right) => { - let (left_boolean, right_boolean) = ( - run_and_expect_boolean(left)?, - run_and_expect_boolean(right)?, - ); - - left_boolean || right_boolean - } - Logic::Not(expression) => { - let boolean = run_and_expect_boolean(expression)?; - - !boolean - } - }; - - Ok(Some(Evaluation::Return(Value::boolean(boolean)))) - } - - fn expected_type(&self, _context: &Context) -> Result, ValidationError> { - Ok(Some(Type::Boolean)) - } -} - -impl Display for Logic { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Logic::Equal(left, right) => write!(f, "{left} == {right}"), - Logic::NotEqual(left, right) => write!(f, "{left} != {right}"), - Logic::Greater(left, right) => write!(f, "{left} > {right}"), - Logic::Less(left, right) => write!(f, "{left} < {right}"), - Logic::GreaterOrEqual(left, right) => write!(f, "{left} >= {right}"), - Logic::LessOrEqual(left, right) => write!(f, "{left} <= {right}"), - Logic::And(left, right) => write!(f, "{left} && {right}"), - Logic::Or(left, right) => write!(f, "{left} || {right}"), - Logic::Not(expression) => write!(f, "!{expression}"), - } - } -} - -#[cfg(test)] -mod tests { - use crate::abstract_tree::{ValueNode, WithPos}; - - use super::*; - - #[test] - fn equal() { - assert_eq!( - Logic::Equal( - Expression::Value(ValueNode::Integer(42).with_position((0, 0))), - Expression::Value(ValueNode::Integer(42).with_position((0, 0))) - ) - .evaluate(&Context::new(), true, SourcePosition(0, 0)), - Ok(Some(Evaluation::Return(Value::boolean(true)))) - ) - } - - #[test] - fn not_equal() { - assert_eq!( - Logic::NotEqual( - Expression::Value(ValueNode::Integer(42).with_position((0, 0))), - Expression::Value(ValueNode::Integer(43).with_position((0, 0))) - ) - .evaluate(&Context::new(), true, SourcePosition(0, 0)), - Ok(Some(Evaluation::Return(Value::boolean(true)))) - ) - } - - #[test] - fn greater() { - assert_eq!( - Logic::Greater( - Expression::Value(ValueNode::Integer(43).with_position((0, 0))), - Expression::Value(ValueNode::Integer(42).with_position((0, 0))) - ) - .evaluate(&Context::new(), true, SourcePosition(0, 0)), - Ok(Some(Evaluation::Return(Value::boolean(true)))) - ) - } - - #[test] - fn less() { - assert_eq!( - Logic::Less( - Expression::Value(ValueNode::Integer(42).with_position((0, 0))), - Expression::Value(ValueNode::Integer(43).with_position((0, 0))) - ) - .evaluate(&Context::new(), true, SourcePosition(0, 0)), - Ok(Some(Evaluation::Return(Value::boolean(true)))) - ) - } - - #[test] - fn greater_or_equal() { - assert_eq!( - Logic::GreaterOrEqual( - Expression::Value(ValueNode::Integer(42).with_position((0, 0))), - Expression::Value(ValueNode::Integer(41).with_position((0, 0))) - ) - .evaluate(&Context::new(), true, SourcePosition(0, 0)), - Ok(Some(Evaluation::Return(Value::boolean(true)))) - ); - - assert_eq!( - Logic::GreaterOrEqual( - Expression::Value(ValueNode::Integer(42).with_position((0, 0))), - Expression::Value(ValueNode::Integer(42).with_position((0, 0))), - ) - .evaluate(&Context::new(), true, SourcePosition(0, 0)), - Ok(Some(Evaluation::Return(Value::boolean(true)))) - ); - } - - #[test] - fn less_or_equal() { - assert_eq!( - Logic::LessOrEqual( - Expression::Value(ValueNode::Integer(41).with_position((0, 0))), - Expression::Value(ValueNode::Integer(42).with_position((0, 0))), - ) - .evaluate(&Context::new(), true, SourcePosition(0, 0)), - Ok(Some(Evaluation::Return(Value::boolean(true)))) - ); - - assert_eq!( - Logic::LessOrEqual( - Expression::Value(ValueNode::Integer(42).with_position((0, 0))), - Expression::Value(ValueNode::Integer(42).with_position((0, 0))), - ) - .evaluate(&Context::new(), true, SourcePosition(0, 0)), - Ok(Some(Evaluation::Return(Value::boolean(true)))) - ); - } - - #[test] - fn and() { - assert_eq!( - Logic::And( - Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), - Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), - ) - .evaluate(&Context::new(), true, SourcePosition(0, 0)), - Ok(Some(Evaluation::Return(Value::boolean(true)))) - ) - } - - #[test] - fn or() { - assert_eq!( - Logic::Or( - Expression::Value(ValueNode::Boolean(true).with_position((0, 0))), - Expression::Value(ValueNode::Boolean(false).with_position((0, 0))), - ) - .evaluate(&Context::new(), true, SourcePosition(0, 0)), - Ok(Some(Evaluation::Return(Value::boolean(true)))) - ) - } - - #[test] - fn not() { - assert_eq!( - Logic::Not(Expression::Value( - ValueNode::Boolean(false).with_position((0, 0)) - )) - .evaluate(&Context::new(), true, SourcePosition(0, 0)), - Ok(Some(Evaluation::Return(Value::boolean(true)))) - ) - } -} diff --git a/dust-lang/src/abstract_tree/loop.rs b/dust-lang/src/abstract_tree/loop.rs deleted file mode 100644 index c972a94..0000000 --- a/dust-lang/src/abstract_tree/loop.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, -}; - -use super::{AbstractNode, Evaluation, SourcePosition, Statement, Type}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct Loop { - statements: Vec, -} - -impl Loop { - pub fn new(statements: Vec) -> Self { - Self { statements } - } - - pub fn last_statement(&self) -> &Statement { - self.statements.last().unwrap() - } -} - -impl AbstractNode for Loop { - fn define_and_validate( - &self, - _context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - for statement in &self.statements { - statement.define_and_validate(_context, false, scope)?; - } - - Ok(()) - } - - fn evaluate( - self, - _context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - loop { - for statement in &self.statements { - let run = statement.clone().evaluate(_context, false, scope)?; - - if let Some(Evaluation::Break) = run { - return Ok(run); - } - } - } - } - - fn expected_type(&self, _context: &Context) -> Result, ValidationError> { - self.last_statement().expected_type(_context) - } -} - -impl Display for Loop { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "loop {{ ")?; - - for statement in &self.statements { - write!(f, "{statement}")?; - } - - write!(f, " }}") - } -} diff --git a/dust-lang/src/abstract_tree/map_index.rs b/dust-lang/src/abstract_tree/map_index.rs deleted file mode 100644 index 1c0d3ac..0000000 --- a/dust-lang/src/abstract_tree/map_index.rs +++ /dev/null @@ -1,187 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - value::ValueInner, -}; - -use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type, ValueNode, WithPosition}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct MapIndex { - collection: Expression, - index: Expression, -} - -impl MapIndex { - pub fn new(left: Expression, right: Expression) -> Self { - Self { - collection: left, - index: right, - } - } -} - -impl AbstractNode for MapIndex { - fn define_and_validate( - &self, - context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - self.collection - .define_and_validate(context, _manage_memory, scope)?; - - let collection_type = if let Some(r#type) = self.collection.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - self.collection.position(), - )); - }; - - if let (Type::Map(fields), Expression::Identifier(identifier)) = - (collection_type, &self.index) - { - if !fields.contains_key(&identifier.node) { - return Err(ValidationError::FieldNotFound { - identifier: identifier.node.clone(), - position: identifier.position, - }); - } - } - - if let Expression::Identifier(_) = &self.index { - Ok(()) - } else { - self.index - .define_and_validate(context, _manage_memory, scope) - } - } - - fn evaluate( - self, - context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - let collection_position = self.collection.position(); - let evaluation = self.collection.evaluate(context, _manage_memory, scope)?; - let collection = if let Some(Evaluation::Return(value)) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(collection_position), - )); - }; - - if let (ValueInner::Map(map), Expression::Identifier(index)) = - (collection.inner().as_ref(), self.index) - { - let eval_option = map.get(&index.node).cloned().map(Evaluation::Return); - - Ok(eval_option) - } else { - Err(RuntimeError::ValidationFailure( - ValidationError::CannotIndex { - r#type: collection.r#type(context)?, - position: collection_position, - }, - )) - } - } - - fn expected_type(&self, context: &Context) -> Result, ValidationError> { - if let (Expression::Identifier(collection), Expression::Identifier(index)) = - (&self.collection, &self.index) - { - let r#type = if let Some(r#type) = context.get_type(&collection.node)? { - r#type - } else { - return Err(ValidationError::VariableNotFound { - identifier: collection.node.clone(), - position: collection.position, - }); - }; - - if let Type::Map(map) = r#type { - return if let Some(r#type) = map.get(&index.node) { - Ok(Some(r#type.clone())) - } else { - Err(ValidationError::FieldNotFound { - identifier: index.node.clone(), - position: index.position, - }) - }; - }; - } - - if let ( - Expression::Value(WithPosition { - node: ValueNode::Map(properties), - .. - }), - Expression::Identifier(index), - ) = (&self.collection, &self.index) - { - for (property, constructor_option, expression) in properties { - if property == &index.node { - return if let Some(constructor) = constructor_option { - let r#type = constructor.clone().construct(context)?; - - Ok(Some(r#type)) - } else { - expression.expected_type(context) - }; - } - } - - return Ok(None); - } - - if let ( - Expression::Value(WithPosition { - node: ValueNode::Structure { fields, .. }, - .. - }), - Expression::Identifier(index), - ) = (&self.collection, &self.index) - { - return if let Some(type_result) = fields.iter().find_map(|(property, expression)| { - if property.node == index.node { - Some(expression.expected_type(context)) - } else { - None - } - }) { - type_result - } else { - Ok(None) - }; - } - - let collection_type = if let Some(r#type) = self.collection.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - self.collection.position(), - )); - }; - - Err(ValidationError::CannotIndex { - r#type: collection_type, - position: self.collection.position(), - }) - } -} - -impl Display for MapIndex { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let MapIndex { collection, index } = self; - - write!(f, "{collection}.{index}") - } -} diff --git a/dust-lang/src/abstract_tree/math.rs b/dust-lang/src/abstract_tree/math.rs deleted file mode 100644 index 2955d2c..0000000 --- a/dust-lang/src/abstract_tree/math.rs +++ /dev/null @@ -1,361 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - value::ValueInner, - Value, -}; - -use super::{AbstractNode, Evaluation, Expression, SourcePosition, Type}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum Math { - Add(Expression, Expression), - Subtract(Expression, Expression), - Multiply(Expression, Expression), - Divide(Expression, Expression), - Modulo(Expression, Expression), -} - -impl AbstractNode for Math { - fn define_and_validate( - &self, - context: &Context, - _manage_memory: bool, - _scope: SourcePosition, - ) -> Result<(), ValidationError> { - match self { - Math::Add(left, right) => { - let left_type = if let Some(r#type) = left.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement(left.position())); - }; - let right_type = if let Some(r#type) = right.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement(right.position())); - }; - - match (&left_type, &right_type) { - (Type::Integer, Type::Integer) => Ok(()), - (Type::Float, Type::Float) => Ok(()), - (Type::String, Type::String) => Ok(()), - (Type::Integer, _) => { - Err(ValidationError::ExpectedIntegerOrFloat(right.position())) - } - (Type::Float, _) => { - Err(ValidationError::ExpectedIntegerOrFloat(right.position())) - } - (Type::String, _) => Err(ValidationError::ExpectedString { - actual: right_type, - position: right.position(), - }), - (_, _) => Err(ValidationError::ExpectedIntegerFloatOrString { - actual: right_type, - position: right.position(), - }), - } - } - Math::Subtract(left, right) - | Math::Multiply(left, right) - | Math::Divide(left, right) - | Math::Modulo(left, right) => { - let left_type = if let Some(r#type) = left.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement(left.position())); - }; - let right_type = if let Some(r#type) = right.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement(right.position())); - }; - - if let Type::Integer | Type::Float = left_type { - if let Type::Integer | Type::Float = right_type { - Ok(()) - } else { - Err(ValidationError::ExpectedIntegerOrFloat(right.position())) - } - } else { - Err(ValidationError::ExpectedIntegerOrFloat(left.position())) - } - } - } - } - - fn evaluate( - self, - _context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - let run_and_expect_value = - |position: SourcePosition, expression: Expression| -> Result { - let evaluation = expression.evaluate(_context, _manage_memory, scope)?; - let value = if let Some(Evaluation::Return(value)) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(position), - )); - }; - - Ok(value) - }; - - let value = match self { - Math::Add(left, right) => { - let left_position = left.position(); - let left_value = run_and_expect_value(left_position, left)?; - let right_position = right.position(); - let right_value = run_and_expect_value(right_position, right)?; - - match (left_value.inner().as_ref(), right_value.inner().as_ref()) { - (ValueInner::Integer(left), ValueInner::Integer(right)) => { - let sum = left.saturating_add(*right); - - Value::integer(sum) - } - (ValueInner::Float(left), ValueInner::Float(right)) => { - let sum = left + right; - - Value::float(sum) - } - (ValueInner::Float(left), ValueInner::Integer(right)) => { - let sum = left + *right as f64; - - Value::float(sum) - } - (ValueInner::Integer(left), ValueInner::Float(right)) => { - let sum = *left as f64 + right; - - Value::float(sum) - } - (ValueInner::String(left), ValueInner::String(right)) => { - let mut concatenated = String::with_capacity(left.len() + right.len()); - - concatenated.extend(left.chars().chain(right.chars())); - - Value::string(concatenated) - } - (ValueInner::Integer(_) | ValueInner::Float(_), _) => { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(right_position), - )) - } - _ => { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(left_position), - )) - } - } - } - Math::Subtract(left, right) => { - let left_position = left.position(); - let left_value = run_and_expect_value(left_position, left)?; - let right_position = right.position(); - let right_value = run_and_expect_value(right_position, right)?; - - match (left_value.inner().as_ref(), right_value.inner().as_ref()) { - (ValueInner::Integer(left), ValueInner::Integer(right)) => { - let difference = left.saturating_sub(*right); - - Value::integer(difference) - } - (ValueInner::Float(left), ValueInner::Float(right)) => { - let difference = left - right; - - Value::float(difference) - } - (ValueInner::Float(left), ValueInner::Integer(right)) => { - let difference = left - *right as f64; - - Value::float(difference) - } - (ValueInner::Integer(left), ValueInner::Float(right)) => { - let difference = *left as f64 - right; - - Value::float(difference) - } - (ValueInner::Integer(_) | ValueInner::Float(_), _) => { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(right_position), - )) - } - _ => { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(left_position), - )) - } - } - } - Math::Multiply(left, right) => { - let left_position = left.position(); - let left_value = run_and_expect_value(left_position, left)?; - let right_position = right.position(); - let right_value = run_and_expect_value(right_position, right)?; - - match (left_value.inner().as_ref(), right_value.inner().as_ref()) { - (ValueInner::Integer(left), ValueInner::Integer(right)) => { - let product = left.saturating_mul(*right); - - Value::integer(product) - } - (ValueInner::Float(left), ValueInner::Float(right)) => { - let product = left * right; - - Value::float(product) - } - (ValueInner::Float(left), ValueInner::Integer(right)) => { - let product = left * *right as f64; - - Value::float(product) - } - (ValueInner::Integer(left), ValueInner::Float(right)) => { - let product = *left as f64 * right; - - Value::float(product) - } - (ValueInner::Integer(_) | ValueInner::Float(_), _) => { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(right_position), - )) - } - _ => { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(left_position), - )) - } - } - } - Math::Divide(left, right) => { - let left_position = left.position(); - let left_value = run_and_expect_value(left_position, left)?; - let right_position = right.position(); - let right_value = run_and_expect_value(right_position, right)?; - - match (left_value.inner().as_ref(), right_value.inner().as_ref()) { - (ValueInner::Integer(left), ValueInner::Integer(right)) => { - let quotient = left.saturating_div(*right); - - Value::integer(quotient) - } - (ValueInner::Float(left), ValueInner::Float(right)) => { - let quotient = left / right; - - Value::float(quotient) - } - (ValueInner::Float(left), ValueInner::Integer(right)) => { - let quotient = left / *right as f64; - - Value::float(quotient) - } - (ValueInner::Integer(left), ValueInner::Float(right)) => { - let quotient = *left as f64 / right; - - Value::float(quotient) - } - (ValueInner::Integer(_) | ValueInner::Float(_), _) => { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(right_position), - )) - } - _ => { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(left_position), - )) - } - } - } - Math::Modulo(left, right) => { - let left_position = left.position(); - let left_value = run_and_expect_value(left_position, left)?; - let right_position = right.position(); - let right_value = run_and_expect_value(right_position, right)?; - - match (left_value.inner().as_ref(), right_value.inner().as_ref()) { - (ValueInner::Integer(left), ValueInner::Integer(right)) => { - let remainder = left % right; - - Value::integer(remainder) - } - (ValueInner::Float(left), ValueInner::Float(right)) => { - let remainder = left % right; - - Value::float(remainder) - } - (ValueInner::Float(left), ValueInner::Integer(right)) => { - let remainder = left % *right as f64; - - Value::float(remainder) - } - (ValueInner::Integer(left), ValueInner::Float(right)) => { - let remainder = *left as f64 % right; - - Value::float(remainder) - } - (ValueInner::Integer(_) | ValueInner::Float(_), _) => { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(right_position), - )) - } - _ => { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedIntegerOrFloat(left_position), - )) - } - } - } - }; - - Ok(Some(Evaluation::Return(value))) - } - - fn expected_type(&self, _context: &Context) -> Result, ValidationError> { - match self { - Math::Add(left, right) - | Math::Subtract(left, right) - | Math::Multiply(left, right) - | Math::Divide(left, right) - | Math::Modulo(left, right) => { - let left_type = if let Some(r#type) = left.expected_type(_context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement(left.position())); - }; - let right_type = if let Some(r#type) = right.expected_type(_context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement(right.position())); - }; - - if let Type::Float = left_type { - return Ok(Some(Type::Float)); - } - - if let Type::Float = right_type { - return Ok(Some(Type::Float)); - } - - Ok(Some(left_type)) - } - } - } -} - -impl Display for Math { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Math::Add(left, right) => write!(f, "{left} + {right}"), - Math::Subtract(left, right) => write!(f, "{left} - {right}"), - Math::Multiply(left, right) => write!(f, "{left} * {right}"), - Math::Divide(left, right) => write!(f, "{left} / {right}"), - Math::Modulo(left, right) => write!(f, "{left} % {right}"), - } - } -} diff --git a/dust-lang/src/abstract_tree/mod.rs b/dust-lang/src/abstract_tree/mod.rs deleted file mode 100644 index 1fb5418..0000000 --- a/dust-lang/src/abstract_tree/mod.rs +++ /dev/null @@ -1,229 +0,0 @@ -pub mod r#as; -pub mod assignment; -pub mod async_block; -pub mod block; -pub mod built_in_function; -pub mod enum_declaration; -pub mod expression; -pub mod function_call; -pub mod if_else; -pub mod list_index; -pub mod logic; -pub mod r#loop; -pub mod map_index; -pub mod math; -pub mod statement; -pub mod structure_definition; -pub mod type_alias; -pub mod type_constructor; -pub mod r#use; -pub mod value_node; -pub mod r#while; - -use std::{ - cmp::Ordering, - fmt::{self, Display, Formatter}, - ops::Index, -}; - -use chumsky::span::{SimpleSpan, Span}; -use serde::{Deserialize, Serialize}; - -pub use self::{ - assignment::{Assignment, AssignmentOperator}, - async_block::AsyncBlock, - block::Block, - built_in_function::BuiltInFunction, - enum_declaration::{EnumDeclaration, EnumVariant}, - expression::Expression, - function_call::FunctionCall, - if_else::IfElse, - list_index::ListIndex, - logic::Logic, - map_index::MapIndex, - math::Math, - r#as::As, - r#loop::Loop, - r#use::Use, - r#while::While, - statement::Statement, - structure_definition::StructureDefinition, - type_alias::TypeAlias, - type_constructor::{FunctionTypeConstructor, ListTypeConstructor, TypeConstructor}, - value_node::ValueNode, -}; - -use crate::{ - context::Context, - error::{DustError, RuntimeError, ValidationError}, - r#type::Type, - Value, -}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct WithPosition { - pub node: T, - pub position: SourcePosition, -} - -pub trait WithPos: Sized { - fn with_position>(self, span: T) -> WithPosition { - WithPosition { - node: self, - position: span.into(), - } - } -} - -impl WithPos for T {} - -#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct SourcePosition(pub usize, pub usize); - -impl Display for SourcePosition { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "({}, {})", self.0, self.1) - } -} - -impl From for SourcePosition { - fn from(span: SimpleSpan) -> Self { - SourcePosition(span.start(), span.end()) - } -} - -impl From<(usize, usize)> for SourcePosition { - fn from((start, end): (usize, usize)) -> Self { - SourcePosition(start, end) - } -} - -#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] -pub enum Evaluation { - Break, - Continue, - Return(Value), -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct AbstractTree(Vec); - -impl AbstractTree { - pub fn new(mut statements: Vec) -> Self { - statements.sort_by(|left, right| match (&left, &right) { - (Statement::StructureDefinition(_), _) => Ordering::Less, - (_, Statement::StructureDefinition(_)) => Ordering::Greater, - (_, _) => Ordering::Equal, - }); - - AbstractTree(statements) - } - - pub fn run( - self, - context: &Context, - manage_memory: bool, - ) -> Result, Vec> { - let mut errors = Vec::new(); - let global_scope = SourcePosition(0, usize::MAX); - - for statement in &self.0 { - let validation_result = - statement.define_and_validate(context, manage_memory, global_scope); - - if let Err(error) = validation_result { - errors.push(DustError::Validation { - error, - position: statement.position(), - }); - } - } - - if !errors.is_empty() { - return Err(errors); - } - - let mut previous_value = None; - - for statement in self.0 { - let position = statement.position(); - let run = statement.evaluate(context, manage_memory, global_scope); - - match run { - Ok(evaluation) => match evaluation { - Some(Evaluation::Return(value)) => previous_value = Some(value), - None => previous_value = None, - _ => {} - }, - Err(runtime_error) => { - return Err(vec![DustError::Runtime { - error: runtime_error, - position, - }]); - } - } - } - - Ok(previous_value) - } -} - -impl Index for AbstractTree { - type Output = Statement; - - fn index(&self, index: usize) -> &Self::Output { - &self.0[index] - } -} - -impl AbstractNode for AbstractTree { - fn define_and_validate( - &self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - for statement in &self.0 { - statement.define_and_validate(context, manage_memory, scope)?; - } - - Ok(()) - } - - fn evaluate( - self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - let mut previous = None; - - for statement in self.0 { - previous = statement.evaluate(context, manage_memory, scope)?; - } - - Ok(previous) - } - - fn expected_type(&self, context: &Context) -> Result, ValidationError> { - self.0.last().unwrap().expected_type(context) - } -} - -pub trait AbstractNode { - fn define_and_validate( - &self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError>; - - fn evaluate( - self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError>; - - fn expected_type(&self, context: &Context) -> Result, ValidationError>; -} diff --git a/dust-lang/src/abstract_tree/statement.rs b/dust-lang/src/abstract_tree/statement.rs deleted file mode 100644 index d148145..0000000 --- a/dust-lang/src/abstract_tree/statement.rs +++ /dev/null @@ -1,204 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, -}; - -use super::{ - AbstractNode, Assignment, AsyncBlock, Block, EnumDeclaration, Evaluation, Expression, IfElse, - Loop, SourcePosition, StructureDefinition, Type, TypeAlias, Use, While, WithPosition, -}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum Statement { - Assignment(WithPosition), - AsyncBlock(WithPosition), - Block(WithPosition), - Break(WithPosition<()>), - IfElse(WithPosition), - Loop(WithPosition), - Null(WithPosition<()>), - StructureDefinition(WithPosition), - TypeAlias(WithPosition), - EnumDeclaration(WithPosition), - Expression(Expression), - While(WithPosition), - Use(WithPosition), -} - -impl Statement { - pub fn position(&self) -> SourcePosition { - match self { - Statement::Assignment(inner) => inner.position, - Statement::AsyncBlock(inner) => inner.position, - Statement::Block(inner) => inner.position, - Statement::Break(inner) => inner.position, - Statement::Expression(expression) => expression.position(), - Statement::IfElse(inner) => inner.position, - Statement::Loop(inner) => inner.position, - Statement::Null(inner) => inner.position, - Statement::StructureDefinition(inner) => inner.position, - Statement::TypeAlias(inner) => inner.position, - Statement::EnumDeclaration(inner) => inner.position, - Statement::While(inner) => inner.position, - Statement::Use(inner) => inner.position, - } - } - - pub fn last_evaluated_statement(&self) -> &Self { - match self { - Statement::Block(inner) => inner.node.last_statement(), - Statement::Loop(inner) => inner.node.last_statement(), - statement => statement, - } - } -} - -impl AbstractNode for Statement { - fn define_and_validate( - &self, - _context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - log::trace!("Validating statement at {}", self.position()); - - match self { - Statement::Assignment(assignment) => { - assignment - .node - .define_and_validate(_context, _manage_memory, scope) - } - Statement::AsyncBlock(async_block) => { - async_block - .node - .define_and_validate(_context, _manage_memory, scope) - } - Statement::Block(block) => { - block - .node - .define_and_validate(_context, _manage_memory, scope) - } - Statement::EnumDeclaration(enum_declaration) => enum_declaration - .node - .define_and_validate(_context, _manage_memory, scope), - Statement::Expression(expression) => { - expression.define_and_validate(_context, _manage_memory, scope) - } - Statement::IfElse(if_else) => { - if_else - .node - .define_and_validate(_context, _manage_memory, scope) - } - Statement::Loop(r#loop) => { - r#loop - .node - .define_and_validate(_context, _manage_memory, scope) - } - Statement::StructureDefinition(struct_definition) => struct_definition - .node - .define_and_validate(_context, _manage_memory, scope), - Statement::TypeAlias(type_alias) => { - type_alias - .node - .define_and_validate(_context, _manage_memory, scope) - } - Statement::While(r#while) => { - r#while - .node - .define_and_validate(_context, _manage_memory, scope) - } - Statement::Use(r#use) => { - r#use - .node - .define_and_validate(_context, _manage_memory, scope) - } - Statement::Break(_) | Statement::Null(_) => Ok(()), - } - } - - fn evaluate( - self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - log::trace!("Evaluating statement at {}", self.position()); - - let result = match self { - Statement::Assignment(assignment) => { - assignment.node.evaluate(context, manage_memory, scope) - } - Statement::AsyncBlock(async_block) => { - async_block.node.evaluate(context, manage_memory, scope) - } - Statement::Block(block) => block.node.evaluate(context, manage_memory, scope), - Statement::Break(_) => Ok(Some(Evaluation::Break)), - Statement::Expression(expression) => expression.evaluate(context, manage_memory, scope), - Statement::IfElse(if_else) => if_else.node.evaluate(context, manage_memory, scope), - Statement::Loop(r#loop) => r#loop.node.evaluate(context, manage_memory, scope), - Statement::Null(_) => Ok(None), - Statement::StructureDefinition(structure_definition) => structure_definition - .node - .evaluate(context, manage_memory, scope), - Statement::TypeAlias(type_alias) => { - type_alias.node.evaluate(context, manage_memory, scope) - } - Statement::EnumDeclaration(type_alias) => { - type_alias.node.evaluate(context, manage_memory, scope) - } - Statement::While(r#while) => r#while.node.evaluate(context, manage_memory, scope), - Statement::Use(r#use) => r#use.node.evaluate(context, manage_memory, scope), - }; - - if manage_memory { - context.clean()?; - } - - result - } - - fn expected_type(&self, _context: &Context) -> Result, ValidationError> { - match self { - Statement::Expression(expression) => expression.expected_type(_context), - Statement::IfElse(if_else) => if_else.node.expected_type(_context), - Statement::Block(block) => block.node.expected_type(_context), - Statement::AsyncBlock(async_block) => async_block.node.expected_type(_context), - Statement::Assignment(assignment) => assignment.node.expected_type(_context), - Statement::Loop(r#loop) => r#loop.node.expected_type(_context), - Statement::StructureDefinition(struct_definition) => { - struct_definition.node.expected_type(_context) - } - Statement::TypeAlias(type_alias) => type_alias.node.expected_type(_context), - Statement::EnumDeclaration(enum_declaration) => { - enum_declaration.node.expected_type(_context) - } - Statement::While(r#while) => r#while.node.expected_type(_context), - Statement::Use(r#use) => r#use.node.expected_type(_context), - Statement::Break(_) | Statement::Null(_) => Ok(None), - } - } -} - -impl Display for Statement { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Statement::Assignment(inner) => write!(f, "{}", inner.node), - Statement::AsyncBlock(inner) => write!(f, "{}", inner.node), - Statement::Block(inner) => write!(f, "{}", inner.node), - Statement::Break(_) => write!(f, "break"), - Statement::IfElse(inner) => write!(f, "{}", inner.node), - Statement::Loop(inner) => write!(f, "{}", inner.node), - Statement::Null(_) => write!(f, ";"), - Statement::StructureDefinition(inner) => write!(f, "{}", inner.node), - Statement::TypeAlias(inner) => write!(f, "{}", inner.node), - Statement::EnumDeclaration(inner) => write!(f, "{}", inner.node), - Statement::Expression(expression) => write!(f, "{expression}"), - Statement::While(inner) => write!(f, "{}", inner.node), - Statement::Use(inner) => write!(f, "{}", inner.node), - } - } -} diff --git a/dust-lang/src/abstract_tree/structure_definition.rs b/dust-lang/src/abstract_tree/structure_definition.rs deleted file mode 100644 index 5840445..0000000 --- a/dust-lang/src/abstract_tree/structure_definition.rs +++ /dev/null @@ -1,91 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - identifier::Identifier, -}; - -use super::{AbstractNode, Evaluation, SourcePosition, Type, TypeConstructor}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct StructureDefinition { - name: Identifier, - fields: Vec<(Identifier, TypeConstructor)>, -} - -impl StructureDefinition { - pub fn new(name: Identifier, fields: Vec<(Identifier, TypeConstructor)>) -> Self { - Self { name, fields } - } -} - -impl AbstractNode for StructureDefinition { - fn define_and_validate( - &self, - context: &Context, - _: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - let mut fields = Vec::with_capacity(self.fields.len()); - - for (identifier, constructor) in &self.fields { - let r#type = constructor.construct(context)?; - - fields.push((identifier.clone(), r#type)); - } - - let struct_type = Type::Structure { - name: self.name.clone(), - fields, - }; - - context.set_type(self.name.clone(), struct_type, scope)?; - - Ok(()) - } - - fn evaluate( - self, - context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - let mut fields = Vec::with_capacity(self.fields.len()); - - for (identifier, constructor) in self.fields { - let r#type = constructor.construct(context)?; - - fields.push((identifier, r#type)); - } - - let struct_type = Type::Structure { - name: self.name.clone(), - fields, - }; - - context.set_type(self.name, struct_type, scope)?; - - Ok(None) - } - - fn expected_type(&self, _: &Context) -> Result, ValidationError> { - Ok(None) - } -} - -impl Display for StructureDefinition { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let StructureDefinition { name, fields } = self; - - write!(f, "struct {name} {{ ")?; - - for (identifer, constructor) in fields { - write!(f, "{identifer}: {constructor}, ")?; - } - - write!(f, " }}") - } -} diff --git a/dust-lang/src/abstract_tree/type_alias.rs b/dust-lang/src/abstract_tree/type_alias.rs deleted file mode 100644 index c1e4ba8..0000000 --- a/dust-lang/src/abstract_tree/type_alias.rs +++ /dev/null @@ -1,65 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - identifier::Identifier, -}; - -use super::{AbstractNode, Evaluation, SourcePosition, Type, TypeConstructor, WithPosition}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct TypeAlias { - identifier: WithPosition, - constructor: TypeConstructor, -} - -impl TypeAlias { - pub fn new(identifier: WithPosition, constructor: TypeConstructor) -> Self { - Self { - identifier, - constructor, - } - } -} - -impl AbstractNode for TypeAlias { - fn define_and_validate( - &self, - context: &Context, - _: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - let r#type = self.constructor.construct(context)?; - - context.set_type(self.identifier.node.clone(), r#type, scope)?; - - Ok(()) - } - - fn evaluate( - self, - _: &Context, - _: bool, - _: SourcePosition, - ) -> Result, RuntimeError> { - Ok(None) - } - - fn expected_type(&self, _: &Context) -> Result, ValidationError> { - Ok(None) - } -} - -impl Display for TypeAlias { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let TypeAlias { - identifier, - constructor, - } = self; - - write!(f, "type {} = {constructor}", identifier.node) - } -} diff --git a/dust-lang/src/abstract_tree/type_constructor.rs b/dust-lang/src/abstract_tree/type_constructor.rs deleted file mode 100644 index b0a9979..0000000 --- a/dust-lang/src/abstract_tree/type_constructor.rs +++ /dev/null @@ -1,280 +0,0 @@ -use std::{ - collections::BTreeMap, - fmt::{self, Display, Formatter}, -}; - -use chumsky::container::Container; -use serde::{Deserialize, Serialize}; - -use crate::{context::Context, error::ValidationError, identifier::Identifier}; - -use super::{SourcePosition, Type, WithPosition}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum TypeConstructor { - Function(WithPosition), - Invokation(TypeInvokationConstructor), - List(WithPosition), - ListOf(WithPosition>), - Map(WithPosition, TypeConstructor)>>), - Raw(WithPosition), -} - -impl TypeConstructor { - pub fn position(&self) -> SourcePosition { - match self { - TypeConstructor::Function(WithPosition { position, .. }) => *position, - TypeConstructor::Invokation(TypeInvokationConstructor { - identifier, - type_arguments, - }) => { - if let Some(arguments) = type_arguments { - SourcePosition( - identifier.position.0, - arguments.last().unwrap().position().1, - ) - } else { - SourcePosition(identifier.position.0, identifier.position.1) - } - } - TypeConstructor::List(WithPosition { position, .. }) => *position, - TypeConstructor::ListOf(WithPosition { position, .. }) => *position, - TypeConstructor::Map(WithPosition { position, .. }) => *position, - TypeConstructor::Raw(WithPosition { position, .. }) => *position, - } - } - - pub fn construct(&self, context: &Context) -> Result { - let r#type = match self { - TypeConstructor::Invokation(TypeInvokationConstructor { identifier, .. }) => { - let invoked_type = if let Some(r#type) = context.get_type(&identifier.node)? { - r#type - } else { - return Ok(Type::Generic { - identifier: identifier.node.clone(), - concrete_type: None, - }); - }; - - if let Type::Enum { - name, - type_parameters, - variants, - } = invoked_type - { - let mut mapped_variants = Vec::with_capacity(variants.len()); - - for (variant_name, content) in variants { - mapped_variants.push((variant_name.clone(), content.clone())); - } - - Type::Enum { - name, - type_parameters: type_parameters.clone(), - variants: mapped_variants, - } - } else { - invoked_type - } - } - TypeConstructor::Function(function_type_constructor) => { - let FunctionTypeConstructor { - type_parameters: declared_type_parameters, - value_parameters: declared_value_parameters, - return_type, - } = &function_type_constructor.node; - - let type_parameters = declared_type_parameters.as_ref().map(|identifiers| { - identifiers - .iter() - .map(|identifier| identifier.node.clone()) - .collect() - }); - let value_parameters = - if let Some(declared_value_parameters) = declared_value_parameters { - let mut parameters = Vec::with_capacity(declared_value_parameters.len()); - - for (identifier, constructor) in declared_value_parameters { - let r#type = constructor.construct(context)?; - - parameters.push((identifier.node.clone(), r#type)); - } - - Some(parameters) - } else { - None - }; - - let return_type = if let Some(constructor) = return_type { - Some(Box::new(constructor.construct(context)?)) - } else { - None - }; - - Type::Function { - type_parameters, - value_parameters, - return_type, - } - } - TypeConstructor::List(constructor) => { - let ListTypeConstructor { length, item_type } = &constructor.node; - let constructed_type = item_type.construct(context)?; - - Type::List { - length: *length, - item_type: Box::new(constructed_type), - } - } - TypeConstructor::ListOf(item_type) => { - let item_type = item_type.node.construct(context)?; - - Type::ListOf(Box::new(item_type)) - } - TypeConstructor::Map(field_type_constructors) => { - let mut field_types = BTreeMap::with_capacity(field_type_constructors.node.len()); - - for (identifier, constructor) in &field_type_constructors.node { - let r#type = constructor.construct(context)?; - - field_types.insert(identifier.node.clone(), r#type); - } - - Type::Map(field_types) - } - TypeConstructor::Raw(raw_type) => match raw_type.node { - RawTypeConstructor::Any => Type::Any, - RawTypeConstructor::Boolean => Type::Boolean, - RawTypeConstructor::Float => Type::Float, - RawTypeConstructor::Integer => Type::Integer, - RawTypeConstructor::Range => Type::Range, - RawTypeConstructor::String => Type::String, - }, - }; - - Ok(r#type) - } -} - -impl Display for TypeConstructor { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - TypeConstructor::Function(WithPosition { node, .. }) => write!(f, "{node}")?, - TypeConstructor::Invokation(type_invokation) => write!(f, "{type_invokation}")?, - TypeConstructor::List(WithPosition { node, .. }) => write!(f, "{node}")?, - TypeConstructor::ListOf(WithPosition { node, .. }) => write!(f, "{node}")?, - TypeConstructor::Map(WithPosition { node, .. }) => { - write!(f, "{{ ")?; - - for (identifier, constructor) in node { - write!(f, "{}: {constructor}, ", identifier.node)?; - } - - write!(f, "}}")?; - } - TypeConstructor::Raw(WithPosition { node, .. }) => write!(f, "{node}")?, - } - - Ok(()) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub enum RawTypeConstructor { - Any, - Boolean, - Float, - Integer, - Range, - String, -} - -impl Display for RawTypeConstructor { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - RawTypeConstructor::Any => write!(f, "any"), - RawTypeConstructor::Boolean => write!(f, "bool"), - RawTypeConstructor::Float => write!(f, "float"), - RawTypeConstructor::Integer => write!(f, "int"), - RawTypeConstructor::Range => write!(f, "range"), - RawTypeConstructor::String => write!(f, "str"), - } - } -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct FunctionTypeConstructor { - pub type_parameters: Option>>, - pub value_parameters: Option, TypeConstructor)>>, - pub return_type: Option>, -} - -impl Display for FunctionTypeConstructor { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "fn ")?; - - if let Some(parameters) = &self.type_parameters { - write!(f, "<")?; - - for identifier in parameters { - write!(f, "{}, ", identifier.node)?; - } - - write!(f, ">")?; - } - - if let Some(parameters) = &self.value_parameters { - for (identifier, constructor) in parameters { - write!(f, "{}: {constructor}", identifier.node)?; - } - } - - write!(f, "(")?; - - write!(f, ")")?; - - Ok(()) - } -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct ListTypeConstructor { - pub length: usize, - pub item_type: Box, -} - -impl Display for ListTypeConstructor { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let ListTypeConstructor { length, item_type } = self; - - write!(f, "[{item_type}; {length}]") - } -} - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct TypeInvokationConstructor { - pub identifier: WithPosition, - pub type_arguments: Option>, -} -impl Display for TypeInvokationConstructor { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let TypeInvokationConstructor { - identifier, - type_arguments, - } = self; - - write!(f, "{}", identifier.node)?; - - if let Some(arguments) = type_arguments { - write!(f, "(")?; - - for constructor in arguments { - write!(f, "{constructor}, ")?; - } - - write!(f, ")")?; - } - - Ok(()) - } -} diff --git a/dust-lang/src/abstract_tree/use.rs b/dust-lang/src/abstract_tree/use.rs deleted file mode 100644 index 877511d..0000000 --- a/dust-lang/src/abstract_tree/use.rs +++ /dev/null @@ -1,115 +0,0 @@ -use std::{ - fmt::{self, Display, Formatter}, - path::Path, - sync::{Arc, RwLock}, -}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - standard_library::{std_fs_compiled, std_io_compiled, std_json_compiled, std_thread_compiled}, - Type, -}; - -use super::{AbstractNode, AbstractTree, Evaluation, SourcePosition}; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Use { - path: String, - - #[serde(skip)] - abstract_tree: Arc>>, -} - -impl Use { - pub fn new(path: String) -> Self { - Self { - path, - abstract_tree: Arc::new(RwLock::new(None)), - } - } -} - -impl AbstractNode for Use { - fn define_and_validate( - &self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - let abstract_tree = match self.path.as_str() { - "std.fs" => std_fs_compiled().clone(), - "std.json" => std_json_compiled().clone(), - "std.io" => std_io_compiled().clone(), - "std.thread" => std_thread_compiled().clone(), - _ => { - if Path::new(&self.path).exists() { - todo!() - } else { - return Err(ValidationError::CannotUsePath(self.path.clone())); - } - } - }; - - *self.abstract_tree.write()? = Some(abstract_tree); - - if let Some(abstract_tree) = self.abstract_tree.read()?.as_ref() { - abstract_tree.define_and_validate(context, manage_memory, scope) - } else { - Err(ValidationError::Uninitialized) - } - } - - fn evaluate( - self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - if let Some(abstract_tree) = self.abstract_tree.read()?.as_ref() { - abstract_tree - .clone() - .evaluate(context, manage_memory, scope) - } else { - Err(RuntimeError::ValidationFailure( - ValidationError::Uninitialized, - )) - } - } - - fn expected_type(&self, context: &Context) -> Result, ValidationError> { - if let Some(abstract_tree) = self.abstract_tree.read()?.as_ref() { - abstract_tree.expected_type(context) - } else { - Err(ValidationError::Uninitialized) - } - } -} - -impl Display for Use { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "use {}", self.path) - } -} - -impl Eq for Use {} - -impl PartialEq for Use { - fn eq(&self, other: &Self) -> bool { - self.path == other.path - } -} - -impl PartialOrd for Use { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Use { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.path.cmp(&other.path) - } -} diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs deleted file mode 100644 index 59a04de..0000000 --- a/dust-lang/src/abstract_tree/value_node.rs +++ /dev/null @@ -1,818 +0,0 @@ -use std::{ - cmp::Ordering, - collections::BTreeMap, - fmt::{self, Display, Formatter}, - ops::Range, -}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - identifier::Identifier, - Value, -}; - -use super::{ - AbstractNode, Block, BuiltInFunction, Evaluation, Expression, SourcePosition, Type, - TypeConstructor, WithPos, WithPosition, -}; - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub enum ValueNode { - Boolean(bool), - BuiltInFunction(BuiltInFunction), - EnumInstance { - type_name: WithPosition, - type_arguments: Option>, - variant: WithPosition, - content: Option>, - }, - Float(f64), - Integer(i64), - List(Vec), - Map(Vec<(Identifier, Option, Expression)>), - Range(Range), - String(String), - Structure { - name: WithPosition, - fields: Vec<(WithPosition, Expression)>, - }, - Function(FunctionNode), -} - -impl ValueNode { - pub fn function( - type_parameters: Option>, - value_parameters: Option>, - return_type: Option, - body: WithPosition, - ) -> Self { - ValueNode::Function(FunctionNode { - type_parameters, - value_parameters, - return_type, - body, - context: Context::new(), - }) - } -} - -impl AbstractNode for ValueNode { - fn define_and_validate( - &self, - context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - if let ValueNode::List(list) = self { - let mut items = list.iter(); - let first_item = if let Some(item) = items.next() { - item - } else { - return Ok(()); - }; - let first_item_type = if let Some(r#type) = first_item.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - first_item.position(), - )); - }; - - for item in items { - item.define_and_validate(context, _manage_memory, scope)?; - - let item_type = if let Some(r#type) = item.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement(item.position())); - }; - - first_item_type.check(&item_type).map_err(|conflict| { - ValidationError::TypeCheck { - conflict, - actual_position: item.position(), - expected_position: Some(first_item.position()), - } - })? - } - } - - if let ValueNode::EnumInstance { - type_name, - type_arguments, - variant, - content, - } = self - { - if let Some(expression) = content { - expression.define_and_validate(context, _manage_memory, scope)?; - } - - if let Some(Type::Enum { - variants, - type_parameters, - .. - }) = context.get_type(&type_name.node)? - { - if let (Some(parameters), Some(arguments)) = (type_parameters, type_arguments) { - if arguments.len() != parameters.len() { - return Err(ValidationError::WrongTypeArgumentsCount { - expected: parameters.len(), - actual: arguments.len(), - position: arguments.last().unwrap().position(), - }); - } - - let found = variants - .into_iter() - .any(|(identifier, _)| identifier == variant.node); - - if !found { - return Err(ValidationError::EnumVariantNotFound { - identifier: variant.node.clone(), - position: variant.position, - }); - } - } - } else { - return Err(ValidationError::EnumDefinitionNotFound { - identifier: type_name.node.clone(), - position: Some(type_name.position), - }); - } - } - - if let ValueNode::Map(map_assignments) = self { - for (_identifier, constructor_option, expression) in map_assignments { - expression.define_and_validate(context, _manage_memory, scope)?; - - if let Some(constructor) = constructor_option { - let actual_type = if let Some(r#type) = expression.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - expression.position(), - )); - }; - let expected_type = constructor.clone().construct(context)?; - - expected_type.check(&actual_type).map_err(|conflict| { - ValidationError::TypeCheck { - conflict, - actual_position: expression.position(), - expected_position: Some(constructor.position()), - } - })?; - } - } - - return Ok(()); - } - - if let ValueNode::Function(FunctionNode { - return_type, - body, - type_parameters, - value_parameters, - context: function_context, - }) = self - { - function_context.inherit_variables_from(context)?; - - if let Some(type_parameters) = type_parameters { - for identifier in type_parameters { - function_context.set_type( - identifier.clone(), - Type::Generic { - identifier: identifier.clone(), - concrete_type: None, - }, - (0, usize::MAX).into(), - )?; - } - } - - if let Some(value_parameters) = value_parameters { - for (identifier, type_constructor) in value_parameters { - let r#type = type_constructor.clone().construct(context)?; - - function_context.set_type( - identifier.clone(), - r#type, - (0, usize::MAX).into(), - )?; - } - } - - body.node - .define_and_validate(function_context, _manage_memory, scope)?; - - let ((expected_return, expected_position), actual_return) = - match (return_type, body.node.expected_type(function_context)?) { - (Some(constructor), Some(r#type)) => ( - (constructor.construct(context)?, constructor.position()), - r#type, - ), - (None, Some(_)) => { - return Err(ValidationError::ExpectedNonValueStatement( - body.node.last_statement().position(), - )) - } - (Some(constructor), None) => { - return Err(ValidationError::ExpectedValueStatement( - constructor.position(), - )) - } - (None, None) => return Ok(()), - }; - - expected_return.check(&actual_return).map_err(|conflict| { - ValidationError::TypeCheck { - conflict, - actual_position: body.position, - expected_position: Some(expected_position), - } - })?; - - return Ok(()); - } - - if let ValueNode::Structure { - name, - fields: expressions, - } = self - { - if !context.contains(&name.node, scope)? { - return Err(ValidationError::VariableNotFound { - identifier: name.node.clone(), - position: name.position, - }); - } - - if let Some(Type::Structure { - name: _, - fields: types, - }) = context.get_type(&name.node)? - { - for ((_, expression), (_, expected_type)) in expressions.iter().zip(types.iter()) { - expression.define_and_validate(context, _manage_memory, scope)?; - - let actual_type = if let Some(r#type) = expression.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - expression.position(), - )); - }; - - expected_type.check(&actual_type).map_err(|conflict| { - ValidationError::TypeCheck { - conflict, - actual_position: expression.position(), - expected_position: None, - } - })? - } - } - } - - Ok(()) - } - - fn evaluate( - self, - context: &Context, - manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - let value = match self { - ValueNode::Boolean(boolean) => Value::boolean(boolean), - ValueNode::EnumInstance { - type_name, - type_arguments, - variant, - content: expressions, - } => { - let content = if let Some(expression) = expressions { - let position = expression.position(); - let evaluation = expression.evaluate(context, manage_memory, scope)?; - - if let Some(Evaluation::Return(value)) = evaluation { - Some(value) - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(position), - )); - } - } else { - None - }; - let type_arguments = if let Some(arguments) = type_arguments { - let mut types = Vec::with_capacity(arguments.len()); - - for constructor in arguments { - let r#type = constructor.construct(context)?; - - types.push(r#type); - } - - Some(types) - } else { - None - }; - - Value::enum_instance(type_name.node, type_arguments, variant.node, content) - } - ValueNode::Float(float) => Value::float(float), - ValueNode::Integer(integer) => Value::integer(integer), - ValueNode::List(expression_list) => { - let mut value_list = Vec::with_capacity(expression_list.len()); - - for expression in expression_list { - let position = expression.position(); - let evaluation = expression.evaluate(context, manage_memory, scope)?; - let value = if let Some(Evaluation::Return(value)) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(position), - )); - }; - - value_list.push(value); - } - - Value::list(value_list) - } - ValueNode::Map(property_list) => { - let mut property_map = BTreeMap::new(); - - for (identifier, _type, expression) in property_list { - let position = expression.position(); - let evaluation = expression.evaluate(context, manage_memory, scope)?; - let value = if let Some(Evaluation::Return(value)) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(position), - )); - }; - - property_map.insert(identifier, value); - } - - Value::map(property_map) - } - ValueNode::Range(range) => Value::range(range), - ValueNode::String(string) => Value::string(string), - ValueNode::Function(FunctionNode { - type_parameters, - value_parameters, - return_type, - body, - .. - }) => { - let outer_context = context; - let value_parameters = if let Some(value_parameters) = value_parameters { - let mut parameters = Vec::with_capacity(value_parameters.len()); - - for (identifier, constructor) in value_parameters { - let r#type = constructor.construct(outer_context)?; - - parameters.push((identifier, r#type)); - } - - Some(parameters) - } else { - None - }; - let return_type = if let Some(constructor) = return_type { - Some(constructor.construct(outer_context)?) - } else { - None - }; - - Value::function(type_parameters, value_parameters, return_type, body.node) - } - ValueNode::Structure { - name, - fields: expressions, - } => { - let mut fields = Vec::with_capacity(expressions.len()); - - for (identifier, expression) in expressions { - let position = expression.position(); - let evaluation = expression.evaluate(context, manage_memory, scope)?; - let value = if let Some(Evaluation::Return(value)) = evaluation { - value - } else { - return Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(position), - )); - }; - - fields.push((identifier.node, value)); - } - - Value::structure(name.node, fields) - } - ValueNode::BuiltInFunction(function) => Value::built_in_function(function), - }; - - Ok(Some(Evaluation::Return(value))) - } - - fn expected_type(&self, context: &Context) -> Result, ValidationError> { - let r#type = match self { - ValueNode::Boolean(_) => Type::Boolean, - ValueNode::EnumInstance { type_name, .. } => { - if let Some(r#type) = context.get_type(&type_name.node)? { - r#type - } else { - return Err(ValidationError::EnumDefinitionNotFound { - identifier: type_name.node.clone(), - position: Some(type_name.position), - }); - } - } - ValueNode::Float(_) => Type::Float, - ValueNode::Integer(_) => Type::Integer, - ValueNode::List(expressions) => { - let first_item = expressions.first().unwrap(); - let item_type = if let Some(r#type) = first_item.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - first_item.position(), - )); - }; - - Type::List { - length: expressions.len(), - item_type: Box::new(item_type), - } - } - ValueNode::Map(fields) => { - let mut field_types = BTreeMap::new(); - - for (identifier, constructor_option, expression) in fields { - let r#type = if let Some(constructor) = constructor_option { - constructor.construct(context)? - } else if let Some(r#type) = expression.expected_type(context)? { - r#type - } else { - return Err(ValidationError::CannotAssignToNone(expression.position())); - }; - - field_types.insert(identifier.clone(), r#type); - } - - Type::Map(field_types) - } - ValueNode::Range(_) => Type::Range, - ValueNode::String(_) => Type::String, - ValueNode::Function(FunctionNode { - type_parameters, - value_parameters, - return_type, - .. - }) => { - let value_parameters = if let Some(value_parameters) = value_parameters { - let mut parameters = Vec::with_capacity(value_parameters.len()); - - for (identifier, type_constructor) in value_parameters { - let r#type = type_constructor.clone().construct(context)?; - - parameters.push((identifier.clone(), r#type)); - } - - Some(parameters) - } else { - None - }; - let type_parameters = type_parameters - .clone() - .map(|parameters| parameters.into_iter().collect()); - let return_type = if let Some(constructor) = return_type { - Some(Box::new(constructor.construct(context)?)) - } else { - None - }; - - Type::Function { - type_parameters, - value_parameters, - return_type, - } - } - ValueNode::Structure { - name, - fields: expressions, - } => { - let mut types = Vec::with_capacity(expressions.len()); - - for (identifier, expression) in expressions { - let r#type = if let Some(r#type) = expression.expected_type(context)? { - r#type - } else { - return Err(ValidationError::ExpectedValueStatement( - expression.position(), - )); - }; - - types.push(( - identifier.clone(), - r#type.with_position(expression.position()), - )); - } - - Type::Structure { - name: name.node.clone(), - fields: types - .into_iter() - .map(|(identifier, r#type)| (identifier.node, r#type.node)) - .collect(), - } - } - ValueNode::BuiltInFunction(built_in_function) => built_in_function.r#type(), - }; - - Ok(Some(r#type)) - } -} - -impl Eq for ValueNode {} - -impl PartialOrd for ValueNode { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for ValueNode { - fn cmp(&self, other: &Self) -> Ordering { - use self::ValueNode::*; - - match (self, other) { - (Boolean(left), Boolean(right)) => left.cmp(right), - (Boolean(_), _) => Ordering::Greater, - (Float(left), Float(right)) => left.total_cmp(right), - (Float(_), _) => Ordering::Greater, - (Integer(left), Integer(right)) => left.cmp(right), - (Integer(_), _) => Ordering::Greater, - (List(left), List(right)) => left.cmp(right), - (List(_), _) => Ordering::Greater, - (Map(left), Map(right)) => left.cmp(right), - (Map(_), _) => Ordering::Greater, - (Range(left), Range(right)) => { - let start_cmp = left.start.cmp(&right.start); - - if start_cmp.is_eq() { - left.end.cmp(&right.end) - } else { - start_cmp - } - } - (Range(_), _) => Ordering::Greater, - (String(left), String(right)) => left.cmp(right), - (String(_), _) => Ordering::Greater, - ( - EnumInstance { - type_name: left_name, - type_arguments: left_type_args, - variant: left_variant, - content: left_content, - }, - EnumInstance { - type_name: right_name, - type_arguments: right_type_args, - variant: right_variant, - content: right_content, - }, - ) => { - let name_cmp = left_name.cmp(right_name); - - if name_cmp.is_eq() { - let type_arg_cmp = left_type_args.cmp(right_type_args); - - if type_arg_cmp.is_eq() { - let variant_cmp = left_variant.cmp(right_variant); - - if variant_cmp.is_eq() { - left_content.cmp(right_content) - } else { - variant_cmp - } - } else { - type_arg_cmp - } - } else { - name_cmp - } - } - (EnumInstance { .. }, _) => Ordering::Greater, - ( - Function(FunctionNode { - type_parameters: left_type_arguments, - value_parameters: left_parameters, - return_type: left_return, - body: left_body, - .. - }), - Function(FunctionNode { - type_parameters: right_type_arguments, - value_parameters: right_parameters, - return_type: right_return, - body: right_body, - .. - }), - ) => { - let parameter_cmp = left_parameters.cmp(right_parameters); - - if parameter_cmp.is_eq() { - let return_cmp = left_return.cmp(right_return); - - if return_cmp.is_eq() { - let type_argument_cmp = left_type_arguments.cmp(right_type_arguments); - - if type_argument_cmp.is_eq() { - left_body.cmp(right_body) - } else { - type_argument_cmp - } - } else { - return_cmp - } - } else { - parameter_cmp - } - } - (Function { .. }, _) => Ordering::Greater, - ( - Structure { - name: left_name, - fields: left_fields, - }, - Structure { - name: right_name, - fields: right_fields, - }, - ) => { - let name_cmp = left_name.cmp(right_name); - - if name_cmp.is_eq() { - left_fields.cmp(right_fields) - } else { - name_cmp - } - } - (Structure { .. }, _) => Ordering::Greater, - (BuiltInFunction(left), BuiltInFunction(right)) => left.cmp(right), - (BuiltInFunction(_), _) => Ordering::Greater, - } - } -} - -impl Display for ValueNode { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - ValueNode::Boolean(boolean) => write!(f, "{boolean}"), - ValueNode::BuiltInFunction(built_in_function) => write!(f, "{built_in_function}"), - ValueNode::EnumInstance { - type_name, - type_arguments, - variant, - content, - } => { - write!(f, "{}", type_name.node)?; - - if let Some(types) = type_arguments { - write!(f, "::<")?; - - for (index, r#type) in types.iter().enumerate() { - if index > 0 { - write!(f, ", ")?; - } - - write!(f, "{type}")?; - } - - write!(f, ">")?; - } - - write!(f, "::{}", variant.node)?; - - if let Some(expression) = content { - write!(f, "({expression})")?; - } - - Ok(()) - } - ValueNode::Float(float) => write!(f, "{float}"), - ValueNode::Integer(integer) => write!(f, "{integer}"), - ValueNode::List(expressions) => { - for expression in expressions { - write!(f, "{expression}")?; - } - - Ok(()) - } - ValueNode::Map(fields) => { - write!(f, "{{ ")?; - - for (identifier, type_option, expression) in fields { - write!(f, "{identifier}")?; - - if let Some(r#type) = type_option { - write!(f, ": {type}")?; - } - - write!(f, " = {expression}")?; - } - - write!(f, " }}") - } - ValueNode::Range(range) => write!(f, "{}..{}", range.start, range.end), - ValueNode::String(string) => write!(f, "{string}"), - ValueNode::Structure { name, fields } => { - write!(f, "{}", name.node)?; - - for (identifier, expression) in fields { - write!(f, "{} = {expression},", identifier.node)?; - } - - Ok(()) - } - ValueNode::Function(FunctionNode { - type_parameters, - value_parameters, - return_type, - body, - .. - }) => { - write!(f, "fn ")?; - - if let Some(type_parameters) = type_parameters { - write!(f, "<")?; - - for identifier in type_parameters { - write!(f, "{identifier}")?; - } - - write!(f, ">")?; - } - - if let Some(value_parameters) = value_parameters { - write!(f, "(")?; - - for (identifier, constructor) in value_parameters { - write!(f, "{identifier}: {constructor}")?; - } - - write!(f, ")")?; - } - - if let Some(r#type) = return_type { - write!(f, " -> {type}")?; - } - - write!(f, " {}", body.node) - } - } - } -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct FunctionNode { - type_parameters: Option>, - value_parameters: Option>, - return_type: Option, - body: WithPosition, - - #[serde(skip)] - context: Context, -} - -impl Clone for FunctionNode { - fn clone(&self) -> Self { - FunctionNode { - type_parameters: self.type_parameters.clone(), - value_parameters: self.value_parameters.clone(), - return_type: self.return_type.clone(), - body: self.body.clone(), - context: Context::new(), - } - } -} - -impl PartialEq for FunctionNode { - fn eq(&self, other: &Self) -> bool { - self.type_parameters == other.type_parameters - && self.value_parameters == other.value_parameters - && self.return_type == other.return_type - && self.body == other.body - } -} diff --git a/dust-lang/src/abstract_tree/while.rs b/dust-lang/src/abstract_tree/while.rs deleted file mode 100644 index 7669eef..0000000 --- a/dust-lang/src/abstract_tree/while.rs +++ /dev/null @@ -1,93 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use serde::{Deserialize, Serialize}; - -use crate::{ - context::Context, - error::{RuntimeError, ValidationError}, - value::ValueInner, - Value, -}; - -use super::{AbstractNode, Evaluation, Expression, SourcePosition, Statement, Type}; - -#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] -pub struct While { - expression: Expression, - statements: Vec, -} - -impl While { - pub fn new(expression: Expression, statements: Vec) -> Self { - Self { - expression, - statements, - } - } -} - -impl AbstractNode for While { - fn define_and_validate( - &self, - _context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result<(), ValidationError> { - self.expression - .define_and_validate(_context, false, scope)?; - - for statement in &self.statements { - statement.define_and_validate(_context, false, scope)?; - } - - Ok(()) - } - - fn evaluate( - self, - _context: &Context, - _manage_memory: bool, - scope: SourcePosition, - ) -> Result, RuntimeError> { - let get_boolean = || -> Result { - let expression_position = self.expression.position(); - let evaluation = self.expression.clone().evaluate(_context, false, scope)?; - - if let Some(Evaluation::Return(value)) = evaluation { - Ok(value) - } else { - Err(RuntimeError::ValidationFailure( - ValidationError::ExpectedValueStatement(expression_position), - )) - } - }; - - while let ValueInner::Boolean(true) = get_boolean()?.inner().as_ref() { - for statement in &self.statements { - let evaluation = statement.clone().evaluate(_context, false, scope)?; - - if let Some(Evaluation::Break) = evaluation { - return Ok(evaluation); - } - } - } - - Ok(None) - } - - fn expected_type(&self, _context: &Context) -> Result, ValidationError> { - self.statements.last().unwrap().expected_type(_context) - } -} - -impl Display for While { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "while {} {{", self.expression)?; - - for statement in &self.statements { - write!(f, "{statement}")?; - } - - write!(f, "}}") - } -} diff --git a/dust-lang/src/bytecode.rs b/dust-lang/src/bytecode.rs deleted file mode 100644 index 35f61fa..0000000 --- a/dust-lang/src/bytecode.rs +++ /dev/null @@ -1,327 +0,0 @@ -use crate::{identifier::Identifier, Value}; - -pub type Span = (usize, usize); - -#[derive(Debug, PartialEq, Clone)] -pub enum LexError { - IntegerParseError(std::num::ParseIntError), -} - -impl From for LexError { - fn from(v: std::num::ParseIntError) -> Self { - Self::IntegerParseError(v) - } -} - -#[derive(Debug, PartialEq, Clone)] -pub enum Token { - Eof, - Equal, - Identifier(Identifier), - Integer(i64), - Plus, - Star, - LeftParenthesis, - RightParenthesis, -} - -pub fn lex(input: &str) -> Result, LexError> { - let mut lexer = Lexer::new(input); - let mut tokens = Vec::new(); - - loop { - let (token, span) = lexer.next_token()?; - let is_eof = matches!(token, Token::Eof); - - tokens.push((token, span)); - - if is_eof { - break; - } - } - - Ok(tokens) -} - -#[derive(Debug, Clone)] -pub struct Lexer<'a> { - input: &'a str, - position: usize, -} - -impl<'a> Lexer<'a> { - pub fn new(input: &'a str) -> Self { - Lexer { input, position: 0 } - } - - fn next_char(&mut self) -> Option { - self.input[self.position..].chars().next().map(|c| { - self.position += c.len_utf8(); - c - }) - } - - pub fn next_token(&mut self) -> Result<(Token, Span), LexError> { - self.skip_whitespace(); - - let (token, span) = if let Some(c) = self.peek_char() { - match c { - '0'..='9' => self.lex_number()?, - 'a'..='z' | 'A'..='Z' => self.lex_identifier()?, - '+' => { - self.position += 1; - (Token::Plus, (self.position - 1, self.position)) - } - '*' => { - self.position += 1; - (Token::Star, (self.position - 1, self.position)) - } - '(' => { - self.position += 1; - (Token::LeftParenthesis, (self.position - 1, self.position)) - } - ')' => { - self.position += 1; - (Token::RightParenthesis, (self.position - 1, self.position)) - } - '=' => { - self.position += 1; - (Token::Equal, (self.position - 1, self.position)) - } - _ => (Token::Eof, (self.position, self.position)), - } - } else { - (Token::Eof, (self.position, self.position)) - }; - - Ok((token, span)) - } - - fn skip_whitespace(&mut self) { - while let Some(c) = self.peek_char() { - if c.is_whitespace() { - self.next_char(); - } else { - break; - } - } - } - - fn peek_char(&self) -> Option { - self.input[self.position..].chars().next() - } - - fn lex_number(&mut self) -> Result<(Token, Span), LexError> { - let start_pos = self.position; - - while let Some(c) = self.peek_char() { - if c.is_ascii_digit() { - self.next_char(); - } else { - break; - } - } - - let integer = self.input[start_pos..self.position].parse::()?; - - Ok((Token::Integer(integer), (start_pos, self.position))) - } - - fn lex_identifier(&mut self) -> Result<(Token, Span), LexError> { - let start_pos = self.position; - - while let Some(c) = self.peek_char() { - if c.is_ascii_alphanumeric() { - self.next_char(); - } else { - break; - } - } - - let identifier = &self.input[start_pos..self.position]; - let token = Token::Identifier(Identifier::new(identifier)); - - Ok((token, (start_pos, self.position))) - } -} - -#[derive(Debug, PartialEq, Clone)] -pub enum Instruction { - Add(Box<(Instruction, Instruction)>), - Assign(Box<(Instruction, Instruction)>), - Constant(Value), - Identifier(Identifier), - Multiply(Box<(Instruction, Instruction)>), -} - -#[derive(Debug, PartialEq, Clone)] -pub enum ParseError { - LexError(LexError), - ExpectedClosingParenthesis, - UnexpectedToken(Token), -} - -impl From for ParseError { - fn from(v: LexError) -> Self { - Self::LexError(v) - } -} - -pub struct Parser<'a> { - lexer: Lexer<'a>, - current_token: Token, -} - -impl<'a> Parser<'a> { - pub fn new(lexer: Lexer<'a>) -> Self { - let mut lexer = lexer; - let current_token = lexer - .next_token() - .map(|(token, _)| token) - .unwrap_or(Token::Eof); - - Parser { - lexer, - current_token, - } - } - - pub fn parse(&mut self) -> Result { - self.parse_instruction(0) - } - - fn next_token(&mut self) -> Result<(), ParseError> { - self.current_token = self.lexer.next_token()?.0; - - Ok(()) - } - - fn parse_instruction(&mut self, precedence: u8) -> Result { - let mut left = self.parse_primary()?; - - while precedence < self.current_precedence() { - match &self.current_token { - Token::Plus => { - self.next_token()?; - - let right = self.parse_instruction(self.current_precedence())?; - left = Instruction::Add(Box::new((left, right))); - } - Token::Star => { - self.next_token()?; - - let right = self.parse_instruction(self.current_precedence())?; - left = Instruction::Multiply(Box::new((left, right))); - } - Token::Equal => { - self.next_token()?; - - let right = self.parse_instruction(self.current_precedence())?; - left = Instruction::Assign(Box::new((left, right))); - } - _ => break, - } - } - - Ok(left) - } - - fn parse_primary(&mut self) -> Result { - match self.current_token.clone() { - Token::Integer(int) => { - self.next_token()?; - Ok(Instruction::Constant(Value::integer(int))) - } - Token::Identifier(identifier) => { - self.next_token()?; - Ok(Instruction::Identifier(identifier)) - } - Token::LeftParenthesis => { - self.next_token()?; - - let instruction = self.parse_instruction(0)?; - - if let Token::RightParenthesis = self.current_token { - self.next_token()?; - } else { - return Err(ParseError::ExpectedClosingParenthesis); - } - - Ok(instruction) - } - _ => Err(ParseError::UnexpectedToken(self.current_token.clone())), - } - } - - fn current_precedence(&self) -> u8 { - match self.current_token { - Token::Equal => 3, - Token::Plus => 1, - Token::Star => 2, - _ => 0, - } - } -} - -#[cfg(test)] -mod tests { - use crate::{identifier::Identifier, Value}; - - use super::{lex, Instruction, Lexer, Parser, Token}; - - #[test] - fn lex_api() { - let input = "1 + 2 * 3"; - - assert_eq!( - lex(input), - Ok(vec![ - (Token::Integer(1), (0, 1)), - (Token::Plus, (2, 3)), - (Token::Integer(2), (4, 5)), - (Token::Star, (6, 7)), - (Token::Integer(3), (8, 9)), - (Token::Eof, (9, 9)), - ]) - ); - } - - #[test] - fn parser() { - let input = "1 + 2 * 3"; - let lexer = Lexer::new(input); - let mut parser = Parser::new(lexer); - - assert_eq!( - parser.parse(), - Ok(Instruction::Add(Box::new(( - Instruction::Constant(Value::integer(1)), - Instruction::Multiply(Box::new(( - Instruction::Constant(Value::integer(2)), - Instruction::Constant(Value::integer(3)) - ))) - )))) - ); - } - - #[test] - fn assignment() { - let input = "a = 1 + 2 * 3"; - let lexer = Lexer::new(input); - let mut parser = Parser::new(lexer); - - assert_eq!( - parser.parse(), - Ok(Instruction::Assign(Box::new(( - Instruction::Identifier(Identifier::new("a")), - Instruction::Add(Box::new(( - Instruction::Constant(Value::integer(1)), - Instruction::Multiply(Box::new(( - Instruction::Constant(Value::integer(2)), - Instruction::Constant(Value::integer(3)) - ))) - ))) - )))) - ); - } -} diff --git a/dust-lang/src/context.rs b/dust-lang/src/context.rs deleted file mode 100644 index 388fc18..0000000 --- a/dust-lang/src/context.rs +++ /dev/null @@ -1,305 +0,0 @@ -use std::{ - cmp::Ordering, - collections::HashMap, - fmt::Debug, - sync::{Arc, RwLock}, -}; - -use log::trace; -use rand::random; - -use crate::{ - abstract_tree::SourcePosition, - error::{PoisonError, ValidationError}, - identifier::Identifier, - standard_library::core_context, - value::ValueInner, - Type, Value, -}; - -type VariableInfo = (VariableData, UsageData, SourcePosition); - -#[derive(Clone, Debug)] -pub struct Context { - id: u32, - variables: Arc>>, - is_clean: Arc>, -} - -impl Context { - pub fn new() -> Self { - Context { - id: random(), - variables: Arc::new(RwLock::new(HashMap::new())), - is_clean: Arc::new(RwLock::new(true)), - } - } - - pub fn new_with_std_core() -> Result { - let new = Context::with_variables_from(core_context())?; - - Ok(new) - } - - pub fn with_variables_from(other: &Context) -> Result { - let variables = other.variables.read()?.clone(); - - Ok(Context { - id: random(), - variables: Arc::new(RwLock::new(variables)), - is_clean: Arc::new(RwLock::new(true)), - }) - } - - pub fn inherit_variables_from(&self, other: &Context) -> Result<(), PoisonError> { - let (get_self_variables, get_other_variables) = - (self.variables.try_write(), other.variables.try_read()); - - if let (Ok(mut self_variables), Ok(other_variables)) = - (get_self_variables, get_other_variables) - { - self_variables.extend(other_variables.iter().filter_map( - |(identifier, (variable, usage, position))| { - trace!("Inheriting {identifier}"); - - if let VariableData::Type(r#type) = variable { - match r#type { - Type::Enum { .. } | Type::Function { .. } | Type::Structure { .. } => { - return Some(( - identifier.clone(), - (variable.clone(), usage.clone(), *position), - )) - } - _ => {} - } - } - - if let VariableData::Value(value) = variable { - match value.inner().as_ref() { - ValueInner::BuiltInFunction(_) | ValueInner::Function(_) => { - return Some(( - identifier.clone(), - (variable.clone(), usage.clone(), *position), - )) - } - _ => {} - } - } - - None - }, - )); - } - - Ok(()) - } - - pub fn contains( - &self, - identifier: &Identifier, - scope: SourcePosition, - ) -> Result { - log::trace!("Checking that {identifier} exists"); - - let variables = self.variables.read()?; - - if let Some((_, _, variable_scope)) = variables.get(identifier) { - if scope.0 >= variable_scope.0 && scope.1 <= variable_scope.1 { - return Ok(true); - } - } else { - trace!("Denying access to {identifier}, out of scope") - } - - Ok(false) - } - - pub fn get_type(&self, identifier: &Identifier) -> Result, ValidationError> { - log::trace!("Getting {identifier}'s type"); - - let variables = self.variables.read()?; - - if let Some((data, _, _)) = variables.get(identifier) { - let r#type = match data { - VariableData::Type(r#type) => r#type.clone(), - VariableData::Value(value) => value.r#type(self)?, - }; - - Ok(Some(r#type.clone())) - } else { - Ok(None) - } - } - - pub fn use_value(&self, identifier: &Identifier) -> Result, PoisonError> { - log::trace!("Using {identifier}'s value"); - - let variables = self.variables.read()?; - - if let Some((VariableData::Value(value), usage_data, _)) = variables.get(identifier) { - usage_data.inner().write()?.actual += 1; - *self.is_clean.write()? = false; - - Ok(Some(value.clone())) - } else { - Ok(None) - } - } - - pub fn get_value(&self, identifier: &Identifier) -> Result, PoisonError> { - log::trace!("Getting {identifier}'s value"); - - let variables = self.variables.read()?; - - if let Some((VariableData::Value(value), _, _)) = variables.get(identifier) { - Ok(Some(value.clone())) - } else { - Ok(None) - } - } - - pub fn set_type( - &self, - identifier: Identifier, - r#type: Type, - scope: SourcePosition, - ) -> Result<(), PoisonError> { - log::debug!("Setting {identifier} to type {}", r#type); - - let mut variables = self.variables.write()?; - let (usage_data, scope) = variables - .remove(&identifier) - .map(|(_, old_usage_data, old_scope)| (old_usage_data, old_scope)) - .unwrap_or_else(|| (UsageData::new(), scope)); - - variables.insert(identifier, (VariableData::Type(r#type), usage_data, scope)); - - Ok(()) - } - - pub fn set_value( - &self, - identifier: Identifier, - value: Value, - scope: SourcePosition, - ) -> Result<(), PoisonError> { - log::debug!("Setting {identifier} to value {value}"); - - let mut variables = self.variables.write()?; - let (usage_data, scope) = variables - .remove(&identifier) - .map(|(_, old_usage_data, old_scope)| (old_usage_data, old_scope)) - .unwrap_or_else(|| (UsageData::new(), scope)); - - variables.insert(identifier, (VariableData::Value(value), usage_data, scope)); - - Ok(()) - } - - pub fn add_expected_use(&self, identifier: &Identifier) -> Result { - log::trace!("Adding expected use for variable {identifier}"); - - let variables = self.variables.read()?; - - if let Some((_, usage_data, _)) = variables.get(identifier) { - usage_data.inner().write()?.expected += 1; - - Ok(true) - } else { - Ok(false) - } - } - - pub fn clean(&self) -> Result<(), PoisonError> { - if *self.is_clean.read()? { - return Ok(()); - } - - self.variables.write()?.retain( - |identifier, (value_data, usage_data, _)| match value_data { - VariableData::Type(_) => true, - VariableData::Value(_) => { - let usage = usage_data.inner().read().unwrap(); - - if usage.actual < usage.expected { - true - } else { - log::trace!("Removing {identifier}"); - - false - } - } - }, - ); - - *self.is_clean.write()? = true; - - Ok(()) - } - - pub fn is_clean(&mut self) -> Result { - Ok(*self.is_clean.read()?) - } -} - -impl Default for Context { - fn default() -> Self { - Context::new() - } -} - -impl Eq for Context {} - -impl PartialEq for Context { - fn eq(&self, other: &Self) -> bool { - self.id == other.id - } -} - -impl PartialOrd for Context { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Context { - fn cmp(&self, other: &Self) -> Ordering { - self.id.cmp(&other.id) - } -} - -#[derive(Clone, Debug, PartialEq)] -pub enum VariableData { - Type(Type), - Value(Value), -} - -#[derive(Clone, Debug)] -pub struct UsageData(Arc>); - -impl UsageData { - pub fn inner(&self) -> &Arc> { - &self.0 - } -} - -#[derive(Clone, Debug)] -pub struct UsageDataInner { - pub actual: u32, - pub expected: u32, -} - -impl UsageData { - pub fn new() -> Self { - UsageData(Arc::new(RwLock::new(UsageDataInner { - actual: 0, - expected: 0, - }))) - } -} - -impl Default for UsageData { - fn default() -> Self { - UsageData::new() - } -} diff --git a/dust-lang/src/error.rs b/dust-lang/src/error.rs deleted file mode 100644 index 78bf902..0000000 --- a/dust-lang/src/error.rs +++ /dev/null @@ -1,221 +0,0 @@ -use std::{io, sync::PoisonError as StdPoisonError}; - -use chumsky::{prelude::Rich, span::Span}; - -use crate::{ - abstract_tree::{Expression, SourcePosition, TypeConstructor}, - identifier::Identifier, - lexer::Token, - Type, -}; - -#[derive(Debug, PartialEq)] -pub enum DustError { - Lex { - expected: String, - span: (usize, usize), - reason: String, - }, - Parse { - expected: String, - span: (usize, usize), - found: Option, - }, - Runtime { - error: RuntimeError, - position: SourcePosition, - }, - Validation { - error: ValidationError, - position: SourcePosition, - }, -} - -impl From> for DustError { - fn from(error: Rich<'_, char>) -> Self { - DustError::Lex { - expected: error.expected().map(|error| error.to_string()).collect(), - span: (error.span().start(), error.span().end()), - reason: error.reason().to_string(), - } - } -} - -impl<'src> From>> for DustError { - fn from(error: Rich<'_, Token<'src>>) -> Self { - DustError::Parse { - expected: error.expected().map(|error| error.to_string()).collect(), - span: (error.span().start(), error.span().end()), - found: error.found().map(|token| token.to_string()), - } - } -} - -#[derive(Debug)] -pub enum RuntimeError { - Io(io::Error), - RwLockPoison(PoisonError), - ValidationFailure(ValidationError), - SerdeJson(serde_json::Error), - Use(Vec), -} - -impl From for RuntimeError { - fn from(error: PoisonError) -> Self { - RuntimeError::RwLockPoison(error) - } -} - -impl From> for RuntimeError { - fn from(_: StdPoisonError) -> Self { - RuntimeError::RwLockPoison(PoisonError) - } -} - -impl From for RuntimeError { - fn from(error: ValidationError) -> Self { - RuntimeError::ValidationFailure(error) - } -} - -impl From for RuntimeError { - fn from(error: io::Error) -> Self { - RuntimeError::Io(error) - } -} - -impl From for RuntimeError { - fn from(error: serde_json::Error) -> Self { - RuntimeError::SerdeJson(error) - } -} - -impl PartialEq for RuntimeError { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (RuntimeError::Io(_), RuntimeError::Io(_)) => false, - (RuntimeError::RwLockPoison(_), RuntimeError::RwLockPoison(_)) => true, - (RuntimeError::ValidationFailure(left), RuntimeError::ValidationFailure(right)) => { - left == right - } - _ => false, - } - } -} - -#[derive(Debug, PartialEq)] -pub enum ValidationError { - /// A node needs to be initialized before it can be validated. - Uninitialized, - BuiltInFunctionFailure(&'static str), - CannotAssignToNone(SourcePosition), - CannotIndex { - r#type: Type, - position: SourcePosition, - }, - CannotIndexWith { - collection_type: Type, - collection_position: SourcePosition, - index_type: Type, - index_position: SourcePosition, - }, - CannotUsePath(String), - ExpectedString { - actual: Type, - position: SourcePosition, - }, - ExpectedList { - actual: Type, - position: SourcePosition, - }, - ExpectedBoolean { - actual: Type, - position: SourcePosition, - }, - ExpectedFunction { - actual: Type, - position: SourcePosition, - }, - ExpectedIntegerOrFloat(SourcePosition), - ExpectedIntegerFloatOrString { - actual: Type, - position: SourcePosition, - }, - FullTypeNotKnown { - identifier: Identifier, - position: SourcePosition, - }, - ExpectedValueStatement(SourcePosition), - ExpectedNonValueStatement(SourcePosition), - RwLockPoison(PoisonError), - TypeCheck { - /// The mismatch that caused the error. - conflict: TypeConflict, - - /// The position of the item that gave the "actual" type. - actual_position: SourcePosition, - - /// The position of the item that gave the "expected" type. - expected_position: Option, - }, - WrongTypeArguments { - parameters: Vec, - arguments: Vec, - }, - WrongValueArguments { - parameters: Vec<(Identifier, Type)>, - arguments: Vec, - }, - VariableNotFound { - identifier: Identifier, - position: SourcePosition, - }, - FieldNotFound { - identifier: Identifier, - position: SourcePosition, - }, - EnumDefinitionNotFound { - identifier: Identifier, - position: Option, - }, - EnumVariantNotFound { - identifier: Identifier, - position: SourcePosition, - }, - WrongTypeArgumentsCount { - expected: usize, - actual: usize, - position: SourcePosition, - }, - StructDefinitionNotFound { - identifier: Identifier, - position: Option, - }, -} - -impl From for ValidationError { - fn from(error: PoisonError) -> Self { - ValidationError::RwLockPoison(error) - } -} - -impl From> for ValidationError { - fn from(_: StdPoisonError) -> Self { - ValidationError::RwLockPoison(PoisonError) - } -} - -#[derive(Debug, PartialEq)] -pub struct PoisonError; - -impl From> for PoisonError { - fn from(_: StdPoisonError) -> Self { - PoisonError - } -} - -#[derive(Debug, PartialEq)] -pub struct TypeConflict { - pub actual: Type, - pub expected: Type, -} diff --git a/dust-lang/src/interpreter.rs b/dust-lang/src/interpreter.rs deleted file mode 100644 index 6bc68c2..0000000 --- a/dust-lang/src/interpreter.rs +++ /dev/null @@ -1,520 +0,0 @@ -use std::{ - collections::{hash_map, HashMap}, - ops::Range, - sync::{Arc, RwLock}, -}; - -use ariadne::{Color, Fmt, Label, Report, ReportKind}; - -use crate::{ - abstract_tree::AbstractTree, - context::Context, - error::{DustError, RuntimeError, TypeConflict, ValidationError}, - lexer::{lex, Token}, - parser::parse, - standard_library::core_context, - Type, Value, -}; - -pub fn interpret(source_id: &str, source: &str) -> Result, InterpreterError> { - let interpreter = Interpreter::new(); - - interpreter.run(Arc::from(source_id), Arc::from(source)) -} - -/// Interpreter, lexer and parser for the Dust programming language. -/// -/// You must provide the interpreter with an ID for each piece of code you pass to it. These are -/// used to identify the source of errors and to provide more detailed error messages. -#[derive(Clone, Debug)] -pub struct Interpreter { - contexts: Arc, Context>>>, - sources: Arc, Arc>>>, -} - -impl Interpreter { - pub fn new() -> Self { - Interpreter { - contexts: Arc::new(RwLock::new(HashMap::new())), - sources: Arc::new(RwLock::new(HashMap::new())), - } - } - - /// Lexes the source code and returns a list of tokens. - pub fn lex<'src>( - &self, - source_id: Arc, - source: &'src Arc, - ) -> Result>, InterpreterError> { - self.sources - .write() - .unwrap() - .insert(source_id.clone(), source.clone()); - - lex(source.as_ref()) - .map(|tokens| tokens.into_iter().map(|(token, _)| token).collect()) - .map_err(|errors| InterpreterError { - source_id: source_id.clone(), - errors, - }) - } - - /// Parses the source code and returns an abstract syntax tree. - pub fn parse( - &self, - source_id: Arc, - source: &Arc, - ) -> Result { - self.sources - .write() - .unwrap() - .insert(source_id.clone(), source.clone()); - - parse(&lex(source).map_err(|errors| InterpreterError { - source_id: source_id.clone(), - errors, - })?) - .map_err(|errors| InterpreterError { source_id, errors }) - } - - /// Runs the source code and returns the result. - pub fn run( - &self, - source_id: Arc, - source: Arc, - ) -> Result, InterpreterError> { - let mut sources = self.sources.write().unwrap(); - - sources.insert(source_id.clone(), source.clone()); - - let tokens = lex(source.as_ref()).map_err(|errors| InterpreterError { - source_id: source_id.clone(), - errors, - })?; - let abstract_tree = parse(&tokens).map_err(|errors| InterpreterError { - source_id: source_id.clone(), - errors, - })?; - let context = self.get_or_create_context(&source_id); - let value_option = abstract_tree - .run(&context, true) - .map_err(|errors| InterpreterError { source_id, errors })?; - - Ok(value_option) - } - - pub fn sources(&self) -> hash_map::IntoIter, Arc> { - self.sources.read().unwrap().clone().into_iter() - } - - fn get_or_create_context(&self, source_id: &Arc) -> Context { - let mut contexts = self.contexts.write().unwrap(); - - if let Some(context) = contexts.get(source_id) { - context.clone() - } else { - let context = core_context().clone(); - - contexts.insert(source_id.clone(), context.clone()); - - context - } - } -} - -impl Default for Interpreter { - fn default() -> Self { - Self::new() - } -} - -#[derive(Debug, PartialEq)] -/// An error that occurred during the interpretation of a piece of code. -/// -/// Each error has a source ID that identifies the piece of code that caused the error, and a list -/// of errors that occurred during the interpretation of that code. -pub struct InterpreterError { - source_id: Arc, - errors: Vec, -} - -impl InterpreterError { - pub fn new(source_id: Arc, errors: Vec) -> Self { - InterpreterError { source_id, errors } - } - - pub fn errors(&self) -> &Vec { - &self.errors - } -} - -impl InterpreterError { - /// Converts the error into a list of user-friendly reports that can be printed to the console. - pub fn build_reports<'a>(self) -> Vec, Range)>> { - let token_color = Color::Yellow; - let type_color = Color::Green; - let identifier_color = Color::Blue; - - let mut reports = Vec::new(); - - for error in self.errors { - let (mut builder, validation_error) = match error { - DustError::Lex { - expected, - span, - reason, - } => { - let description = if expected.is_empty() { - "Invalid character.".to_string() - } else { - format!("Expected {expected}.") - }; - - ( - Report::build( - ReportKind::Custom("Lexing Error", Color::Yellow), - self.source_id.clone(), - span.1, - ) - .with_message(description) - .with_label( - Label::new((self.source_id.clone(), span.0..span.1)) - .with_message(reason) - .with_color(Color::Red), - ), - None, - ) - } - DustError::Parse { - expected, - span, - found, - } => { - let description = if expected.is_empty() { - "Invalid token.".to_string() - } else { - format!("Expected {expected}.") - }; - let found = found - .unwrap_or_else(|| "End of input".to_string()) - .fg(token_color); - - ( - Report::build( - ReportKind::Custom("Parsing Error", Color::Yellow), - self.source_id.clone(), - span.1, - ) - .with_message(description) - .with_label( - Label::new((self.source_id.clone(), span.0..span.1)) - .with_message(format!("{found} is not valid in this position.")) - .with_color(Color::Red), - ), - None, - ) - } - DustError::Validation { error, position } => ( - Report::build( - ReportKind::Custom("Validation Error", Color::Magenta), - self.source_id.clone(), - position.1, - ) - .with_message("The syntax is valid but this code would cause an error.") - .with_note( - "This error was detected by the interpreter before running the code.", - ), - Some(error), - ), - DustError::Runtime { error, position } => { - let note = match &error { - RuntimeError::Io(io_error) => &io_error.to_string(), - RuntimeError::RwLockPoison(_) => todo!(), - RuntimeError::ValidationFailure(_) => { - "This is the interpreter's fault. Please submit a bug with this error message." - } - RuntimeError::SerdeJson(serde_json_error) => &serde_json_error.to_string(), - RuntimeError::Use(_) => todo!(), - }; - - ( - Report::build( - ReportKind::Custom("Runtime Error", Color::Red), - self.source_id.clone(), - position.1, - ) - .with_message("An error occured that forced the program to exit. There may be unexpected side-effects because the program could not finish.") - .with_note(note) - .with_label( - Label::new((self.source_id.clone(), position.0..position.1)).with_message("Error occured here.") - ), - if let RuntimeError::ValidationFailure(validation_error) = error { - Some(validation_error) - } else { - None - }, - ) - } - }; - - if let Some(validation_error) = validation_error { - match validation_error { - ValidationError::CannotAssignToNone(postion) => { - builder.add_label( - Label::new((self.source_id.clone(), postion.0..postion.1)) - .with_message( - "This statement does not yield a value, you cannot assign a variable to it." - ), - ); - } - ValidationError::ExpectedBoolean { actual, position } => { - builder.add_label( - Label::new((self.source_id.clone(), position.0..position.1)) - .with_message(format!( - "Expected {} but got {}.", - "boolean".fg(type_color), - actual.fg(type_color) - )), - ); - } - ValidationError::ExpectedIntegerOrFloat(position) => { - builder.add_label( - Label::new((self.source_id.clone(), position.0..position.1)) - .with_message(format!( - "Expected {} or {}.", - "integer".fg(type_color), - "float".fg(type_color) - )), - ); - } - ValidationError::FullTypeNotKnown { - identifier, - position, - } => builder.add_label( - Label::new((self.source_id.clone(), position.0..position.1)).with_message( - format!( - "The full type for {} must be known.", - identifier.fg(identifier_color) - ), - ), - ), - ValidationError::RwLockPoison(_) => todo!(), - ValidationError::TypeCheck { - conflict: TypeConflict { actual, expected }, - actual_position, - expected_position, - } => { - if let Type::Generic { - concrete_type: None, - .. - } = actual - { - builder = builder.with_help("Try specifying the type using turbofish."); - } - - let actual_type_message = if let Some(position) = expected_position { - builder.add_label( - Label::new((self.source_id.clone(), position.0..position.1)) - .with_message(format!( - "Type {} established here.", - expected.fg(type_color) - )), - ); - - format!("Got type {} here.", actual.fg(type_color)) - } else { - format!( - "Got type {} but expected {}.", - actual.fg(type_color), - expected.fg(type_color) - ) - }; - - builder.add_label( - Label::new(( - self.source_id.clone(), - actual_position.0..actual_position.1, - )) - .with_message(actual_type_message), - ) - } - ValidationError::VariableNotFound { - identifier, - position, - } => builder.add_label( - Label::new((self.source_id.clone(), position.0..position.1)).with_message( - format!( - "Variable {} does not exist in this context.", - identifier.fg(identifier_color) - ), - ), - ), - ValidationError::CannotIndex { r#type, position } => builder.add_label( - Label::new((self.source_id.clone(), position.0..position.1)).with_message( - format!("Cannot index into a {}.", r#type.fg(type_color)), - ), - ), - ValidationError::CannotIndexWith { - collection_type, - collection_position, - index_type, - index_position, - } => { - builder = builder.with_message(format!( - "Cannot index into {} with {}.", - collection_type.clone().fg(type_color), - index_type.clone().fg(type_color) - )); - - builder.add_labels([ - Label::new(( - self.source_id.clone(), - collection_position.0..collection_position.1, - )) - .with_message(format!( - "This has type {}.", - collection_type.fg(type_color), - )), - Label::new(( - self.source_id.clone(), - index_position.0..index_position.1, - )) - .with_message(format!("This has type {}.", index_type.fg(type_color),)), - ]) - } - ValidationError::ExpectedValueStatement(position) => builder.add_label( - Label::new((self.source_id.clone(), position.0..position.1)) - .with_message("Expected a statement that yields a value."), - ), - ValidationError::ExpectedNonValueStatement(position) => { - builder.add_label( - Label::new((self.source_id.clone(), position.0..position.1)) - .with_message("Expected a statement that does not yield a value."), - ); - builder.add_label( - Label::new((self.source_id.clone(), position.0..position.1)) - .with_message("Try adding a semicolon here."), - ); - } - ValidationError::ExpectedFunction { actual, position } => builder.add_label( - Label::new((self.source_id.clone(), position.0..position.1)).with_message( - format!( - "Expected a function value but got {}.", - actual.fg(type_color) - ), - ), - ), - ValidationError::FieldNotFound { - identifier, - position, - } => builder.add_label( - Label::new((self.source_id.clone(), position.0..position.1)).with_message( - format!( - "This map has no field named {}.", - identifier.fg(identifier_color) - ), - ), - ), - ValidationError::WrongTypeArguments { - parameters, - arguments, - } => { - builder = builder.with_message(format!( - "Expected {parameters:?} arguments but got {arguments:?}." - )); - } - ValidationError::WrongValueArguments { - parameters, - arguments, - } => { - builder = builder.with_message(format!( - "Expected {parameters:?} arguments but got {arguments:?}." - )); - } - ValidationError::ExpectedIntegerFloatOrString { actual, position } => { - builder = builder.with_message(format!( - "Expected an {}, {} or {}.", - Type::Integer.fg(type_color), - Type::Float.fg(type_color), - Type::String.fg(type_color) - )); - - builder.add_label( - Label::new((self.source_id.clone(), position.0..position.1)) - .with_message(format!("This has type {}.", actual.fg(type_color),)), - ) - } - ValidationError::ExpectedString { .. } => todo!(), - ValidationError::EnumDefinitionNotFound { - identifier, - position, - } => { - let message = format!( - "The enum {} does not exist in this context.", - identifier.fg(identifier_color), - ); - - if let Some(position) = position { - builder.add_label( - Label::new((self.source_id.clone(), position.0..position.1)) - .with_message(message), - ) - } else { - builder = builder.with_message(message); - } - } - ValidationError::EnumVariantNotFound { .. } => todo!(), - ValidationError::ExpectedList { .. } => todo!(), - ValidationError::BuiltInFunctionFailure(reason) => builder - .add_label(Label::new((self.source_id.clone(), 0..0)).with_message(reason)), - ValidationError::CannotUsePath(_) => todo!(), - ValidationError::Uninitialized => todo!(), - ValidationError::WrongTypeArgumentsCount { - expected, - actual, - position, - } => builder.add_label( - Label::new((self.source_id.clone(), position.0..position.1)).with_message( - format!( - "Expected {} type arguments but got {}.", - expected.fg(type_color), - actual.fg(type_color) - ), - ), - ), - ValidationError::StructDefinitionNotFound { - identifier, - position, - } => todo!(), - } - } - - let report = builder.finish(); - - reports.push(report); - } - - reports - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::{ - abstract_tree::{AbstractNode, SourcePosition}, - standard_library::std_full_compiled, - }; - - #[test] - fn load_standard_library() { - let context = Context::new(); - - for abstract_tree in std_full_compiled() { - abstract_tree - .define_and_validate(&context, true, SourcePosition(0, usize::MAX)) - .unwrap(); - abstract_tree.run(&context, true).unwrap(); - } - } -} diff --git a/dust-lang/src/lex.rs b/dust-lang/src/lex.rs new file mode 100644 index 0000000..e1dd97f --- /dev/null +++ b/dust-lang/src/lex.rs @@ -0,0 +1,132 @@ +use crate::{Identifier, Span, Token}; + +#[derive(Debug, PartialEq, Clone)] +pub enum LexError { + IntegerParseError(std::num::ParseIntError), +} + +impl From for LexError { + fn from(v: std::num::ParseIntError) -> Self { + Self::IntegerParseError(v) + } +} + +pub fn lex(input: &str) -> Result, LexError> { + let mut lexer = Lexer::new(input); + let mut tokens = Vec::new(); + + loop { + let (token, span) = lexer.next_token()?; + let is_eof = matches!(token, Token::Eof); + + tokens.push((token, span)); + + if is_eof { + break; + } + } + + Ok(tokens) +} + +#[derive(Debug, Clone)] +pub struct Lexer<'a> { + input: &'a str, + position: usize, +} + +impl<'a> Lexer<'a> { + pub fn new(input: &'a str) -> Self { + Lexer { input, position: 0 } + } + + fn next_char(&mut self) -> Option { + self.input[self.position..].chars().next().map(|c| { + self.position += c.len_utf8(); + c + }) + } + + pub fn next_token(&mut self) -> Result<(Token, Span), LexError> { + self.skip_whitespace(); + + let (token, span) = if let Some(c) = self.peek_char() { + match c { + '0'..='9' => self.lex_number()?, + 'a'..='z' | 'A'..='Z' => self.lex_identifier()?, + '+' => { + self.position += 1; + (Token::Plus, (self.position - 1, self.position)) + } + '*' => { + self.position += 1; + (Token::Star, (self.position - 1, self.position)) + } + '(' => { + self.position += 1; + (Token::LeftParenthesis, (self.position - 1, self.position)) + } + ')' => { + self.position += 1; + (Token::RightParenthesis, (self.position - 1, self.position)) + } + '=' => { + self.position += 1; + (Token::Equal, (self.position - 1, self.position)) + } + _ => (Token::Eof, (self.position, self.position)), + } + } else { + (Token::Eof, (self.position, self.position)) + }; + + Ok((token, span)) + } + + fn skip_whitespace(&mut self) { + while let Some(c) = self.peek_char() { + if c.is_whitespace() { + self.next_char(); + } else { + break; + } + } + } + + fn peek_char(&self) -> Option { + self.input[self.position..].chars().next() + } + + fn lex_number(&mut self) -> Result<(Token, Span), LexError> { + let start_pos = self.position; + + while let Some(c) = self.peek_char() { + if c.is_ascii_digit() { + self.next_char(); + } else { + break; + } + } + + let integer = self.input[start_pos..self.position].parse::()?; + + Ok((Token::Integer(integer), (start_pos, self.position))) + } + + fn lex_identifier(&mut self) -> Result<(Token, Span), LexError> { + let start_pos = self.position; + + while let Some(c) = self.peek_char() { + if c.is_ascii_alphanumeric() { + self.next_char(); + } else { + break; + } + } + + let identifier = &self.input[start_pos..self.position]; + let token = Token::Identifier(Identifier::new(identifier)); + + Ok((token, (start_pos, self.position))) + } +} diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs deleted file mode 100644 index f298aa1..0000000 --- a/dust-lang/src/lexer.rs +++ /dev/null @@ -1,573 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use chumsky::prelude::*; - -use crate::error::DustError; - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum Token<'src> { - Boolean(bool), - Comment(&'src str), - Integer(i64), - Float(f64), - String(&'src str), - Identifier(&'src str), - Symbol(Symbol), - Keyword(Keyword), - Use(&'src str), -} - -impl<'src> Display for Token<'src> { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Token::Boolean(boolean) => write!(f, "{boolean}"), - Token::Comment(comment) => write!(f, "// {comment}"), - Token::Integer(integer) => write!(f, "{integer}"), - Token::Float(float) => write!(f, "{float}"), - Token::String(string) => write!(f, "{string}"), - Token::Identifier(string) => write!(f, "{string}"), - Token::Symbol(control) => write!(f, "{control}"), - Token::Keyword(keyword) => write!(f, "{keyword}"), - Token::Use(path) => write!(f, "use {path}"), - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum Keyword { - Any, - As, - Async, - Bool, - Break, - Else, - Enum, - Float, - Fn, - Int, - If, - JsonParse, - Length, - Map, - None, - Range, - ReadFile, - ReadLine, - Sleep, - Struct, - Str, - Type, - Loop, - While, - WriteLine, -} - -impl Display for Keyword { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - match self { - Keyword::Any => write!(f, "any"), - Keyword::As => write!(f, "as"), - Keyword::Async => write!(f, "async"), - Keyword::Bool => write!(f, "bool"), - Keyword::Break => write!(f, "break"), - Keyword::Else => write!(f, "else"), - Keyword::Enum => write!(f, "enum"), - Keyword::Float => write!(f, "float"), - Keyword::Fn => write!(f, "fn"), - Keyword::Int => write!(f, "int"), - Keyword::If => write!(f, "if"), - Keyword::Map => write!(f, "map"), - Keyword::None => write!(f, "none"), - Keyword::Range => write!(f, "range"), - Keyword::Struct => write!(f, "struct"), - Keyword::Str => write!(f, "str"), - Keyword::Loop => write!(f, "loop"), - Keyword::While => write!(f, "while"), - Keyword::Type => write!(f, "type"), - Keyword::JsonParse => write!(f, "JSON_PARSE"), - Keyword::Length => write!(f, "LENGTH"), - Keyword::ReadFile => write!(f, "READ_FILE"), - Keyword::ReadLine => write!(f, "READ_LINE"), - Keyword::Sleep => write!(f, "SLEEP"), - Keyword::WriteLine => write!(f, "WRITE_LINE"), - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum Symbol { - Plus, - PlusEqual, - DoubleAmpersand, - Colon, - Comma, - CurlyClose, - CurlyOpen, - Slash, - Dollar, - Dot, - DoubleColon, - DoubleDot, - DoubleEqual, - DoubleUnderscore, - Equal, - FatArrow, - Greater, - GreaterOrEqual, - Less, - LessOrEqual, - Percent, - Asterisk, - Exclamation, - NotEqual, - DoublePipe, - ParenClose, - ParenOpen, - Pipe, - Semicolon, - SkinnyArrow, - SquareClose, - SquareOpen, - MinusEqual, - Minus, -} - -impl Display for Symbol { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - Symbol::Asterisk => write!(f, "*"), - Symbol::Colon => write!(f, ":"), - Symbol::Comma => write!(f, ","), - Symbol::CurlyClose => write!(f, "}}"), - Symbol::CurlyOpen => write!(f, "{{"), - Symbol::Dollar => write!(f, "$"), - Symbol::Dot => write!(f, "."), - Symbol::DoubleAmpersand => write!(f, "&&"), - Symbol::DoubleColon => write!(f, "::"), - Symbol::DoubleDot => write!(f, ".."), - Symbol::DoubleEqual => write!(f, "=="), - Symbol::DoublePipe => write!(f, "||"), - Symbol::DoubleUnderscore => write!(f, "__"), - Symbol::Equal => write!(f, "="), - Symbol::Exclamation => write!(f, "!"), - Symbol::FatArrow => write!(f, "=>"), - Symbol::Greater => write!(f, ">"), - Symbol::GreaterOrEqual => write!(f, ">="), - Symbol::Less => write!(f, "<"), - Symbol::LessOrEqual => write!(f, "<="), - Symbol::Minus => write!(f, "-"), - Symbol::MinusEqual => write!(f, "-="), - Symbol::NotEqual => write!(f, "!="), - Symbol::ParenClose => write!(f, ")"), - Symbol::ParenOpen => write!(f, "("), - Symbol::Percent => write!(f, "%"), - Symbol::Pipe => write!(f, "|"), - Symbol::Plus => write!(f, "+"), - Symbol::PlusEqual => write!(f, "+="), - Symbol::Semicolon => write!(f, ";"), - Symbol::SkinnyArrow => write!(f, "->"), - Symbol::Slash => write!(f, "/"), - Symbol::SquareClose => write!(f, "]"), - Symbol::SquareOpen => write!(f, "["), - } - } -} - -pub fn lex(source: &str) -> Result, Vec> { - lexer() - .parse(source) - .into_result() - .map_err(|errors| errors.into_iter().map(|error| error.into()).collect()) -} - -pub fn lexer<'src>() -> impl Parser< - 'src, - &'src str, - Vec<(Token<'src>, SimpleSpan)>, - extra::Err>>, -> { - let line_comment = just("//") - .ignore_then( - none_of('\n') - .repeated() - .to_slice() - .map(|text: &str| Token::Comment(text.trim())), - ) - .then_ignore(just('\n').or_not()); - - let multi_line_comment = just("/*") - .ignore_then( - none_of('*') - .repeated() - .to_slice() - .map(|text: &str| Token::Comment(text.trim())), - ) - .then_ignore(just("*/")); - - let boolean = choice(( - just("true").to(Token::Boolean(true)), - just("false").to(Token::Boolean(false)), - )); - - let float_numeric = just('-') - .or_not() - .then(text::int(10)) - .then(just('.').then(text::digits(10))) - .then(just('e').then(text::digits(10)).or_not()) - .to_slice() - .map(|text: &str| Token::Float(text.parse().unwrap())); - - let float = choice(( - float_numeric, - just("Infinity").to(Token::Float(f64::INFINITY)), - just("-Infinity").to(Token::Float(f64::NEG_INFINITY)), - just("NaN").to(Token::Float(f64::NAN)), - )); - - let integer = just('-') - .or_not() - .then(text::int(10)) - .to_slice() - .map(|text: &str| { - let integer = text.parse().unwrap(); - - Token::Integer(integer) - }); - - let delimited_string = |delimiter| { - just(delimiter) - .then(none_of(delimiter).repeated()) - .then(just(delimiter)) - .to_slice() - .map(|text: &str| Token::String(&text[1..text.len() - 1])) - }; - - let string = choice(( - delimited_string('\''), - delimited_string('"'), - delimited_string('`'), - )); - - let keyword = choice(( - just("any").to(Token::Keyword(Keyword::Any)), - just("async").to(Token::Keyword(Keyword::Async)), - just("as").to(Token::Keyword(Keyword::As)), - just("bool").to(Token::Keyword(Keyword::Bool)), - just("break").to(Token::Keyword(Keyword::Break)), - just("enum").to(Token::Keyword(Keyword::Enum)), - just("else").to(Token::Keyword(Keyword::Else)), - just("float").to(Token::Keyword(Keyword::Float)), - just("fn").to(Token::Keyword(Keyword::Fn)), - just("int").to(Token::Keyword(Keyword::Int)), - just("if").to(Token::Keyword(Keyword::If)), - just("map").to(Token::Keyword(Keyword::Map)), - just("none").to(Token::Keyword(Keyword::None)), - just("range").to(Token::Keyword(Keyword::Range)), - just("struct").to(Token::Keyword(Keyword::Struct)), - just("str").to(Token::Keyword(Keyword::Str)), - just("type").to(Token::Keyword(Keyword::Type)), - just("loop").to(Token::Keyword(Keyword::Loop)), - just("while").to(Token::Keyword(Keyword::While)), - just("JSON_PARSE").to(Token::Keyword(Keyword::JsonParse)), - just("LENGTH").to(Token::Keyword(Keyword::Length)), - just("READ_FILE").to(Token::Keyword(Keyword::ReadFile)), - just("READ_LINE").to(Token::Keyword(Keyword::ReadLine)), - just("SLEEP").to(Token::Keyword(Keyword::Sleep)), - just("WRITE_LINE").to(Token::Keyword(Keyword::WriteLine)), - )); - - let symbol = choice([ - just("!=").to(Token::Symbol(Symbol::NotEqual)), - just("!").to(Token::Symbol(Symbol::Exclamation)), - just("$").to(Token::Symbol(Symbol::Dollar)), - just("%").to(Token::Symbol(Symbol::Percent)), - just("&&").to(Token::Symbol(Symbol::DoubleAmpersand)), - just("(").to(Token::Symbol(Symbol::ParenOpen)), - just(")").to(Token::Symbol(Symbol::ParenClose)), - just("*").to(Token::Symbol(Symbol::Asterisk)), - just("+=").to(Token::Symbol(Symbol::PlusEqual)), - just("+").to(Token::Symbol(Symbol::Plus)), - just(",").to(Token::Symbol(Symbol::Comma)), - just("->").to(Token::Symbol(Symbol::SkinnyArrow)), - just("-=").to(Token::Symbol(Symbol::MinusEqual)), - just("-").to(Token::Symbol(Symbol::Minus)), - just("..").to(Token::Symbol(Symbol::DoubleDot)), - just(".").to(Token::Symbol(Symbol::Dot)), - just("/").to(Token::Symbol(Symbol::Slash)), - just("::").to(Token::Symbol(Symbol::DoubleColon)), - just(":").to(Token::Symbol(Symbol::Colon)), - just(";").to(Token::Symbol(Symbol::Semicolon)), - just("<=").to(Token::Symbol(Symbol::LessOrEqual)), - just("<").to(Token::Symbol(Symbol::Less)), - just("=>").to(Token::Symbol(Symbol::FatArrow)), - just("==").to(Token::Symbol(Symbol::DoubleEqual)), - just("=").to(Token::Symbol(Symbol::Equal)), - just(">=").to(Token::Symbol(Symbol::GreaterOrEqual)), - just(">").to(Token::Symbol(Symbol::Greater)), - just("[").to(Token::Symbol(Symbol::SquareOpen)), - just("]").to(Token::Symbol(Symbol::SquareClose)), - just("__").to(Token::Symbol(Symbol::DoubleUnderscore)), - just("{").to(Token::Symbol(Symbol::CurlyOpen)), - just("}").to(Token::Symbol(Symbol::CurlyClose)), - just("||").to(Token::Symbol(Symbol::DoublePipe)), - just("|").to(Token::Symbol(Symbol::Pipe)), - ]); - - let identifier = text::ident().map(|text: &str| Token::Identifier(text)); - - let r#use = just("use").padded().ignore_then( - none_of(" \n\r;") - .repeated() - .to_slice() - .map(|text: &str| Token::Use(text.trim())), - ); - - choice(( - line_comment, - multi_line_comment, - boolean, - float, - integer, - string, - keyword, - symbol, - r#use, - identifier, - )) - .map_with(|token: Token, state| (token, state.span())) - .padded() - .repeated() - .collect() -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn r#use() { - assert_eq!( - lex("use std.io").unwrap(), - vec![(Token::Use("std.io"), (0..10).into())] - ); - - assert_eq!( - lex("use https://example.com/std.ds").unwrap(), - vec![(Token::Use("https://example.com/std.ds"), (0..30).into())] - ); - } - - #[test] - fn line_comment() { - assert_eq!( - lex("// 42").unwrap(), - vec![(Token::Comment("42"), (0..5).into())] - ); - - assert_eq!( - lex("1// 42//2").unwrap(), - vec![ - (Token::Integer(1), (0..1).into()), - (Token::Comment("42//2"), (1..9).into()), - ] - ); - assert_eq!( - lex(" - 1 - // 42 - 2 - ") - .unwrap(), - vec![ - (Token::Integer(1), (17..18).into()), - (Token::Comment("42"), (35..41).into()), - (Token::Integer(2), (57..58).into()), - ] - ); - } - - #[test] - fn multi_line_comment() { - assert_eq!( - lex("/* 42 */").unwrap(), - vec![(Token::Comment("42"), (0..8).into())] - ); - - assert_eq!( - lex("1/* 42//2 */").unwrap(), - vec![ - (Token::Integer(1), (0..1).into()), - (Token::Comment("42//2"), (1..12).into()), - ] - ); - assert_eq!( - lex(" - 1 - /* - 42 - */ - 2 - ") - .unwrap(), - vec![ - (Token::Integer(1), (17..18).into()), - (Token::Comment("42"), (35..79).into()), - (Token::Integer(2), (96..97).into()), - ] - ); - } - - #[test] - fn range() { - assert_eq!( - lex("1..10").unwrap(), - vec![ - (Token::Integer(1), (0..1).into()), - (Token::Symbol(Symbol::DoubleDot), (1..3).into()), - (Token::Integer(10), (3..5).into()) - ] - ) - } - - #[test] - fn math_operators() { - assert_eq!( - lex("1 + 1").unwrap(), - vec![ - (Token::Integer(1), (0..1).into()), - (Token::Symbol(Symbol::Plus), (2..3).into()), - (Token::Integer(1), (4..5).into()) - ] - ) - } - - #[test] - fn keywords() { - assert_eq!(lex("int").unwrap()[0].0, Token::Keyword(Keyword::Int)) - } - - #[test] - fn identifier() { - assert_eq!(lex("x").unwrap()[0].0, Token::Identifier("x")); - assert_eq!(lex("foobar").unwrap()[0].0, Token::Identifier("foobar")); - assert_eq!(lex("HELLO").unwrap()[0].0, Token::Identifier("HELLO")); - } - - #[test] - fn r#true() { - assert_eq!(lex("true").unwrap()[0].0, Token::Boolean(true)); - } - - #[test] - fn r#false() { - assert_eq!(lex("false").unwrap()[0].0, Token::Boolean(false)); - } - - #[test] - fn positive_float() { - assert_eq!(lex("0.0").unwrap()[0].0, Token::Float(0.0)); - assert_eq!(lex("42.0").unwrap()[0].0, Token::Float(42.0)); - - let max_float = f64::MAX.to_string() + ".0"; - - assert_eq!(lex(&max_float).unwrap()[0].0, Token::Float(f64::MAX)); - - let min_positive_float = f64::MIN_POSITIVE.to_string(); - - assert_eq!( - lex(&min_positive_float).unwrap()[0].0, - Token::Float(f64::MIN_POSITIVE) - ); - } - - #[test] - fn negative_float() { - assert_eq!(lex("-0.0").unwrap()[0].0, Token::Float(-0.0)); - assert_eq!(lex("-42.0").unwrap()[0].0, Token::Float(-42.0)); - - let min_float = f64::MIN.to_string() + ".0"; - - assert_eq!(lex(&min_float).unwrap()[0].0, Token::Float(f64::MIN)); - - let max_negative_float = format!("-{}", f64::MIN_POSITIVE); - - assert_eq!( - lex(&max_negative_float).unwrap()[0].0, - Token::Float(-f64::MIN_POSITIVE) - ); - } - - #[test] - fn other_float() { - assert_eq!(lex("Infinity").unwrap()[0].0, Token::Float(f64::INFINITY)); - assert_eq!( - lex("-Infinity").unwrap()[0].0, - Token::Float(f64::NEG_INFINITY) - ); - - if let Token::Float(float) = &lex("NaN").unwrap()[0].0 { - assert!(float.is_nan()); - } else { - panic!("Expected a float.") - } - } - - #[test] - fn positive_integer() { - for i in 0..10 { - let source = i.to_string(); - let tokens = lex(&source).unwrap(); - - assert_eq!(tokens[0].0, Token::Integer(i)) - } - - assert_eq!(lex("42").unwrap()[0].0, Token::Integer(42)); - - let maximum_integer = i64::MAX.to_string(); - - assert_eq!( - lex(&maximum_integer).unwrap()[0].0, - Token::Integer(i64::MAX) - ); - } - - #[test] - fn negative_integer() { - for i in -9..1 { - let source = i.to_string(); - let tokens = lex(&source).unwrap(); - - assert_eq!(tokens[0].0, Token::Integer(i)) - } - - assert_eq!(lex("-42").unwrap()[0].0, Token::Integer(-42)); - - let minimum_integer = i64::MIN.to_string(); - - assert_eq!( - lex(&minimum_integer).unwrap()[0].0, - Token::Integer(i64::MIN) - ); - } - - #[test] - fn double_quoted_string() { - assert_eq!(lex("\"\"").unwrap()[0].0, Token::String("")); - assert_eq!(lex("\"42\"").unwrap()[0].0, Token::String("42")); - assert_eq!(lex("\"foobar\"").unwrap()[0].0, Token::String("foobar")); - } - - #[test] - fn single_quoted_string() { - assert_eq!(lex("''").unwrap()[0].0, Token::String("")); - assert_eq!(lex("'42'").unwrap()[0].0, Token::String("42")); - assert_eq!(lex("'foobar'").unwrap()[0].0, Token::String("foobar")); - } - - #[test] - fn grave_quoted_string() { - assert_eq!(lex("``").unwrap()[0].0, Token::String("")); - assert_eq!(lex("`42`").unwrap()[0].0, Token::String("42")); - assert_eq!(lex("`foobar`").unwrap()[0].0, Token::String("foobar")); - } -} diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 239fed1..da06fc3 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -7,21 +7,16 @@ The [interpreter] module contains the `Interpreter` struct, which is used to lex interpret Dust code. The `interpret` function is a convenience function that creates a new `Interpreter` and runs the given source code. */ -pub mod abstract_tree; -pub mod bytecode; -pub mod context; -pub mod error; pub mod identifier; -pub mod interpreter; -pub mod lexer; -pub mod parser; -pub mod standard_library; +pub mod lex; +pub mod parse; +pub mod token; pub mod r#type; pub mod value; -pub use context::Context; -pub use interpreter::{interpret, Interpreter, InterpreterError}; -pub use lexer::{lex, lexer}; -pub use parser::{parse, parser}; +pub use identifier::Identifier; pub use r#type::Type; +pub use token::Token; pub use value::Value; + +pub type Span = (usize, usize); diff --git a/dust-lang/src/parse.rs b/dust-lang/src/parse.rs new file mode 100644 index 0000000..cddd35e --- /dev/null +++ b/dust-lang/src/parse.rs @@ -0,0 +1,243 @@ +use crate::{ + identifier::Identifier, + lex::{LexError, Lexer}, + Span, Token, Value, +}; + +#[derive(Debug, PartialEq, Clone)] +pub enum Instruction { + Add(Box<(Instruction, Instruction)>), + Assign(Box<(Instruction, Instruction)>), + Constant(Value), + Identifier(Identifier), + Multiply(Box<(Instruction, Instruction)>), +} + +#[derive(Debug, PartialEq, Clone)] +pub enum ParseError { + LexError(LexError), + ExpectedClosingParenthesis, + UnexpectedToken(Token), +} + +impl From for ParseError { + fn from(v: LexError) -> Self { + Self::LexError(v) + } +} + +pub struct Parser<'src> { + lexer: Lexer<'src>, + current: (Token, Span), +} + +impl<'src> Parser<'src> { + pub fn new(lexer: Lexer<'src>) -> Self { + let mut lexer = lexer; + let current_token = lexer + .next_token() + .map(|(token, _)| token) + .unwrap_or(Token::Eof); + + Parser { + lexer, + current: (current_token, (0, 0)), + } + } + + pub fn parse(&mut self) -> Result<(Instruction, Span), ParseError> { + self.parse_instruction(0) + } + + fn next_token(&mut self) -> Result<(), ParseError> { + self.current = self.lexer.next_token()?; + + Ok(()) + } + + fn parse_instruction(&mut self, precedence: u8) -> Result<(Instruction, Span), ParseError> { + let (left_instruction, left_span) = self.parse_primary()?; + + if precedence < self.current_precedence() { + match &self.current { + (Token::Plus, _) => { + self.next_token()?; + + let (right_instruction, right_span) = + self.parse_instruction(self.current_precedence())?; + + return Ok(( + Instruction::Add(Box::new((left_instruction, right_instruction))), + (left_span.0, right_span.1), + )); + } + (Token::Star, _) => { + self.next_token()?; + + let (right_instruction, right_span) = + self.parse_instruction(self.current_precedence())?; + + return Ok(( + Instruction::Multiply(Box::new((left_instruction, right_instruction))), + (left_span.0, right_span.1), + )); + } + (Token::Equal, _) => { + self.next_token()?; + + let (right_instruction, right_span) = + self.parse_instruction(self.current_precedence())?; + + return Ok(( + Instruction::Assign(Box::new((left_instruction, right_instruction))), + (left_span.0, right_span.1), + )); + } + _ => {} + } + } + + Ok((left_instruction, left_span)) + } + + fn parse_primary(&mut self) -> Result<(Instruction, Span), ParseError> { + match self.current.clone() { + (Token::Integer(int), span) => { + self.next_token()?; + Ok((Instruction::Constant(Value::integer(int)), span)) + } + (Token::Identifier(identifier), span) => { + self.next_token()?; + Ok((Instruction::Identifier(identifier), span)) + } + (Token::LeftParenthesis, left_span) => { + self.next_token()?; + + let (instruction, _) = self.parse_instruction(0)?; + + if let (Token::RightParenthesis, right_span) = self.current { + self.next_token()?; + + Ok((instruction, (left_span.0, right_span.1))) + } else { + Err(ParseError::ExpectedClosingParenthesis) + } + } + _ => Err(ParseError::UnexpectedToken(self.current.0.clone())), + } + } + + fn current_precedence(&self) -> u8 { + match self.current { + (Token::Equal, _) => 3, + (Token::Plus, _) => 1, + (Token::Star, _) => 2, + _ => 0, + } + } +} + +#[cfg(test)] +mod tests { + use crate::{identifier::Identifier, lex::lex, Value}; + + use super::{Instruction, Lexer, Parser, Token}; + + #[test] + fn add() { + let input = "1 + 2"; + let lexer = Lexer::new(input); + let mut parser = Parser::new(lexer); + + assert_eq!( + parser.parse(), + Ok(( + Instruction::Add(Box::new(( + Instruction::Constant(Value::integer(1)), + Instruction::Constant(Value::integer(2)) + ))), + (0, 5) + )) + ); + } + + #[test] + fn multiply() { + let input = "1 * 2"; + let lexer = Lexer::new(input); + let mut parser = Parser::new(lexer); + + assert_eq!( + parser.parse(), + Ok(( + Instruction::Multiply(Box::new(( + Instruction::Constant(Value::integer(1)), + Instruction::Constant(Value::integer(2)) + ))), + (0, 5) + )) + ); + } + + #[test] + fn add_and_multiply() { + let input = "1 + 2 * 3"; + + assert_eq!( + lex(input), + Ok(vec![ + (Token::Integer(1), (0, 1)), + (Token::Plus, (2, 3)), + (Token::Integer(2), (4, 5)), + (Token::Star, (6, 7)), + (Token::Integer(3), (8, 9)), + (Token::Eof, (9, 9)), + ]) + ); + } + + #[test] + fn parser() { + let input = "1 + 2 * 3"; + let lexer = Lexer::new(input); + let mut parser = Parser::new(lexer); + + assert_eq!( + parser.parse(), + Ok(( + Instruction::Add(Box::new(( + Instruction::Constant(Value::integer(1)), + Instruction::Multiply(Box::new(( + Instruction::Constant(Value::integer(2)), + Instruction::Constant(Value::integer(3)) + ))) + ))), + (0, 9) + )) + ); + } + + #[test] + fn assignment() { + let input = "a = 1 + 2 * 3"; + let lexer = Lexer::new(input); + let mut parser = Parser::new(lexer); + + assert_eq!( + parser.parse(), + Ok(( + Instruction::Assign(Box::new(( + Instruction::Identifier(Identifier::new("a")), + Instruction::Add(Box::new(( + Instruction::Constant(Value::integer(1)), + Instruction::Multiply(Box::new(( + Instruction::Constant(Value::integer(2)), + Instruction::Constant(Value::integer(3)) + ))) + ))) + ))), + (0, 13) + )) + ); + } +} diff --git a/dust-lang/src/parser/mod.rs b/dust-lang/src/parser/mod.rs deleted file mode 100644 index 7155117..0000000 --- a/dust-lang/src/parser/mod.rs +++ /dev/null @@ -1,781 +0,0 @@ -#[cfg(test)] -mod tests; - -use chumsky::{input::SpannedInput, pratt::*, prelude::*}; - -use crate::{ - abstract_tree::*, - error::DustError, - identifier::Identifier, - lexer::{Keyword, Symbol, Token}, -}; - -use self::{ - built_in_function::BuiltInFunction, - enum_declaration::EnumVariant, - type_constructor::{RawTypeConstructor, TypeInvokationConstructor}, -}; - -pub type ParserInput<'src> = - SpannedInput, SimpleSpan, &'src [(Token<'src>, SimpleSpan)]>; - -pub type ParserExtra<'src> = extra::Err, SimpleSpan>>; - -pub fn parse<'src>( - tokens: &'src [(Token<'src>, SimpleSpan)], -) -> Result> { - parser(false) - .parse(tokens.spanned((tokens.len()..tokens.len()).into())) - .into_result() - .map_err(|errors| { - errors - .into_iter() - .map(DustError::from) - .collect::>() - }) -} - -pub fn parser<'src>( - allow_built_ins: bool, -) -> impl Parser<'src, ParserInput<'src>, AbstractTree, ParserExtra<'src>> { - let comment = select_ref! { - Token::Comment(_) => {} - }; - - let identifier = select! { - Token::Identifier(text) => Identifier::from(text), - }; - - let positioned_identifier = - identifier.map_with(|identifier, state| identifier.with_position(state.span())); - - let basic_value = select! { - Token::Boolean(boolean) => ValueNode::Boolean(boolean), - Token::Float(float) => ValueNode::Float(float), - Token::Integer(integer) => ValueNode::Integer(integer), - Token::String(text) => ValueNode::String(text.to_string()), - } - .map_with(|value, state| Expression::Value(value.with_position(state.span()))); - - let raw_integer = select! { - Token::Integer(integer) => integer - }; - - let type_constructor = recursive(|type_constructor| { - let primitive_type = choice(( - just(Token::Keyword(Keyword::Any)).to(RawTypeConstructor::Any), - just(Token::Keyword(Keyword::Bool)).to(RawTypeConstructor::Boolean), - just(Token::Keyword(Keyword::Float)).to(RawTypeConstructor::Float), - just(Token::Keyword(Keyword::Int)).to(RawTypeConstructor::Integer), - just(Token::Keyword(Keyword::Range)).to(RawTypeConstructor::Range), - just(Token::Keyword(Keyword::Str)).to(RawTypeConstructor::String), - )) - .map_with(|raw_constructor, state| { - TypeConstructor::Raw(raw_constructor.with_position(state.span())) - }); - - type TypeParameters = Vec>; - type ValueParameters = Vec<(WithPosition, TypeConstructor)>; - type FunctionTypeParameters = (Option, ValueParameters); - - let function_type = just(Token::Keyword(Keyword::Fn)) - .ignore_then( - positioned_identifier - .separated_by(just(Token::Symbol(Symbol::Comma))) - .at_least(1) - .collect() - .delimited_by( - just(Token::Symbol(Symbol::Less)), - just(Token::Symbol(Symbol::Greater)), - ) - .or_not(), - ) - .then( - positioned_identifier - .then_ignore(just(Token::Symbol(Symbol::Colon))) - .then(type_constructor.clone()) - .separated_by(just(Token::Symbol(Symbol::Comma))) - .collect() - .delimited_by( - just(Token::Symbol(Symbol::ParenOpen)), - just(Token::Symbol(Symbol::ParenClose)), - ), - ) - .then( - just(Token::Symbol(Symbol::SkinnyArrow)) - .ignore_then(type_constructor.clone()) - .or_not(), - ) - .map_with( - |((type_parameters, value_parameters), return_type): ( - FunctionTypeParameters, - Option, - ), - state| { - let value_parameters = if value_parameters.is_empty() { - None - } else { - Some(value_parameters) - }; - - TypeConstructor::Function( - FunctionTypeConstructor { - type_parameters, - value_parameters, - return_type: return_type.map(Box::new), - } - .with_position(state.span()), - ) - }, - ); - - let list_type = type_constructor - .clone() - .then_ignore(just(Token::Symbol(Symbol::Semicolon))) - .then(raw_integer) - .delimited_by( - just(Token::Symbol(Symbol::SquareOpen)), - just(Token::Symbol(Symbol::SquareClose)), - ) - .map_with(|(item_type, length), state| { - TypeConstructor::List( - ListTypeConstructor { - length: length as usize, - item_type: Box::new(item_type), - } - .with_position(state.span()), - ) - }); - - let list_of_type = type_constructor - .clone() - .delimited_by( - just(Token::Symbol(Symbol::SquareOpen)), - just(Token::Symbol(Symbol::SquareClose)), - ) - .map_with(|item_type, state| { - TypeConstructor::ListOf(Box::new(item_type).with_position(state.span())) - }); - - let type_invokation = positioned_identifier - .then( - type_constructor - .clone() - .separated_by(just(Token::Symbol(Symbol::Comma))) - .at_least(1) - .allow_trailing() - .collect() - .delimited_by( - just(Token::Symbol(Symbol::ParenOpen)), - just(Token::Symbol(Symbol::ParenClose)), - ) - .or_not(), - ) - .map(|(identifier, type_arguments)| { - TypeConstructor::Invokation(TypeInvokationConstructor { - identifier, - type_arguments, - }) - }); - - let map_type = positioned_identifier - .then_ignore(just(Token::Symbol(Symbol::Colon))) - .then(type_constructor.clone()) - .separated_by(just(Token::Symbol(Symbol::Comma))) - .collect() - .delimited_by( - just(Token::Symbol(Symbol::CurlyOpen)), - just(Token::Symbol(Symbol::CurlyClose)), - ) - .map_with( - |fields: Vec<(WithPosition, TypeConstructor)>, state| { - TypeConstructor::Map(fields.with_position(state.span())) - }, - ); - - choice(( - map_type, - type_invokation, - function_type, - list_type, - list_of_type, - primitive_type, - )) - }); - - let type_specification = - just(Token::Symbol(Symbol::Colon)).ignore_then(type_constructor.clone()); - - let statement = recursive(|statement| { - let block = statement - .clone() - .repeated() - .at_least(1) - .collect() - .delimited_by( - just(Token::Symbol(Symbol::CurlyOpen)), - just(Token::Symbol(Symbol::CurlyClose)), - ) - .map_with(|statements, state| Block::new(statements).with_position(state.span())); - - let expression = recursive(|expression| { - let identifier_expression = identifier.map_with(|identifier, state| { - Expression::Identifier(identifier.with_position(state.span())) - }); - - let range = raw_integer - .then_ignore(just(Token::Symbol(Symbol::DoubleDot))) - .then(raw_integer) - .map_with(|(start, end), state| { - Expression::Value(ValueNode::Range(start..end).with_position(state.span())) - }); - - let list = expression - .clone() - .separated_by(just(Token::Symbol(Symbol::Comma))) - .allow_trailing() - .collect() - .delimited_by( - just(Token::Symbol(Symbol::SquareOpen)), - just(Token::Symbol(Symbol::SquareClose)), - ) - .map_with(|list, state| { - Expression::Value(ValueNode::List(list).with_position(state.span())) - }); - - let map_fields = identifier - .then(type_specification.clone().or_not()) - .then_ignore(just(Token::Symbol(Symbol::Equal))) - .then(expression.clone()) - .map(|((identifier, r#type), expression)| (identifier, r#type, expression)); - - let map = map_fields - .separated_by(just(Token::Symbol(Symbol::Comma)).or_not()) - .allow_trailing() - .collect() - .delimited_by( - just(Token::Symbol(Symbol::CurlyOpen)), - just(Token::Symbol(Symbol::CurlyClose)), - ) - .map_with(|map_assigment_list, state| { - Expression::Value( - ValueNode::Map(map_assigment_list).with_position(state.span()), - ) - }); - - type TypeParameters = Vec; - type ValueParameters = Vec<(Identifier, TypeConstructor)>; - type FunctionParameters = (Option, ValueParameters); - - let turbofish = just(Token::Symbol(Symbol::DoubleColon)).ignore_then( - type_constructor - .clone() - .separated_by(just(Token::Symbol(Symbol::Comma))) - .at_least(1) - .collect() - .delimited_by( - just(Token::Symbol(Symbol::Less)), - just(Token::Symbol(Symbol::Greater)), - ), - ); - - let function = just(Token::Keyword(Keyword::Fn)) - .ignore_then( - identifier - .separated_by(just(Token::Symbol(Symbol::Comma))) - .at_least(1) - .allow_trailing() - .collect() - .delimited_by( - just(Token::Symbol(Symbol::Less)), - just(Token::Symbol(Symbol::Greater)), - ) - .or_not(), - ) - .then( - identifier - .then_ignore(just(Token::Symbol(Symbol::Colon))) - .then(type_constructor.clone()) - .separated_by(just(Token::Symbol(Symbol::Comma))) - .allow_trailing() - .collect() - .delimited_by( - just(Token::Symbol(Symbol::ParenOpen)), - just(Token::Symbol(Symbol::ParenClose)), - ), - ) - .then( - just(Token::Symbol(Symbol::SkinnyArrow)) - .ignore_then(type_constructor.clone()) - .or_not(), - ) - .then(block.clone()) - .map_with( - |(((type_parameters, value_parameters), return_type), body): ( - (FunctionParameters, Option), - WithPosition, - ), - state| { - let value_parameters = if value_parameters.is_empty() { - None - } else { - Some(value_parameters) - }; - - Expression::Value( - ValueNode::function( - type_parameters, - value_parameters, - return_type, - body, - ) - .with_position(state.span()), - ) - }, - ); - - let enum_instance = positioned_identifier - .then(turbofish.clone().or_not()) - .then_ignore(just(Token::Symbol(Symbol::DoubleColon))) - .then(positioned_identifier) - .then(expression.clone().or_not()) - .map_with(|(((type_name, type_arguments), variant), content), state| { - Expression::Value( - ValueNode::EnumInstance { - type_name, - type_arguments, - variant, - content: content.map(Box::new), - } - .with_position(state.span()), - ) - }); - - let underscored = |keyword| { - just(Token::Keyword(keyword)).delimited_by( - just(Token::Symbol(Symbol::DoubleUnderscore)), - just(Token::Symbol(Symbol::DoubleUnderscore)), - ) - }; - - let built_in_function = choice(( - underscored(Keyword::Length).map_with(|_, state| { - Expression::Value( - ValueNode::BuiltInFunction(BuiltInFunction::Length) - .with_position(state.span()), - ) - }), - underscored(Keyword::ReadLine).map_with(|_, state| { - Expression::Value( - ValueNode::BuiltInFunction(BuiltInFunction::ReadLine) - .with_position(state.span()), - ) - }), - underscored(Keyword::ReadFile).map_with(|_, state| { - Expression::Value( - ValueNode::BuiltInFunction(BuiltInFunction::ReadFile) - .with_position(state.span()), - ) - }), - underscored(Keyword::Sleep).map_with(|_, state| { - Expression::Value( - ValueNode::BuiltInFunction(BuiltInFunction::Sleep) - .with_position(state.span()), - ) - }), - underscored(Keyword::WriteLine).map_with(|_, state| { - Expression::Value( - ValueNode::BuiltInFunction(BuiltInFunction::WriteLine) - .with_position(state.span()), - ) - }), - underscored(Keyword::JsonParse).map_with(|_, state| { - Expression::Value( - ValueNode::BuiltInFunction(BuiltInFunction::JsonParse) - .with_position(state.span()), - ) - }), - )) - .validate(move |expression, state, emitter| { - if !allow_built_ins { - emitter.emit(Rich::custom( - state.span(), - "Built-in functions can only be used by the standard library.", - )) - } - - expression - }); - - let atom = choice(( - built_in_function, - enum_instance.clone(), - range, - function.clone(), - list.clone(), - map.clone(), - basic_value, - identifier_expression, - expression.clone().delimited_by( - just(Token::Symbol(Symbol::ParenOpen)), - just(Token::Symbol(Symbol::ParenClose)), - ), - )); - - let logic_math_indexes_as_and_function_calls = atom.pratt(( - // Logic - prefix( - 2, - just(Token::Symbol(Symbol::Exclamation)), - |_, expression, span| { - Expression::Logic(Box::new(Logic::Not(expression)).with_position(span)) - }, - ), - infix( - left(1), - just(Token::Symbol(Symbol::DoubleEqual)), - |left, _, right, span| { - Expression::Logic(Box::new(Logic::Equal(left, right)).with_position(span)) - }, - ), - infix( - left(1), - just(Token::Symbol(Symbol::NotEqual)), - |left, _, right, span| { - Expression::Logic( - Box::new(Logic::NotEqual(left, right)).with_position(span), - ) - }, - ), - infix( - left(1), - just(Token::Symbol(Symbol::Greater)), - |left, _, right, span| { - Expression::Logic(Box::new(Logic::Greater(left, right)).with_position(span)) - }, - ), - infix( - left(1), - just(Token::Symbol(Symbol::Less)), - |left, _, right, span| { - Expression::Logic(Box::new(Logic::Less(left, right)).with_position(span)) - }, - ), - infix( - left(1), - just(Token::Symbol(Symbol::GreaterOrEqual)), - |left, _, right, span| { - Expression::Logic( - Box::new(Logic::GreaterOrEqual(left, right)).with_position(span), - ) - }, - ), - infix( - left(1), - just(Token::Symbol(Symbol::LessOrEqual)), - |left, _, right, span| { - Expression::Logic( - Box::new(Logic::LessOrEqual(left, right)).with_position(span), - ) - }, - ), - infix( - left(1), - just(Token::Symbol(Symbol::DoubleAmpersand)), - |left, _, right, span| { - Expression::Logic(Box::new(Logic::And(left, right)).with_position(span)) - }, - ), - infix( - left(1), - just(Token::Symbol(Symbol::DoublePipe)), - |left, _, right, span| { - Expression::Logic(Box::new(Logic::Or(left, right)).with_position(span)) - }, - ), - // Math - infix( - left(1), - just(Token::Symbol(Symbol::Plus)), - |left, _, right, span| { - Expression::Math(Box::new(Math::Add(left, right)).with_position(span)) - }, - ), - infix( - left(1), - just(Token::Symbol(Symbol::Minus)), - |left, _, right, span| { - Expression::Math(Box::new(Math::Subtract(left, right)).with_position(span)) - }, - ), - infix( - left(2), - just(Token::Symbol(Symbol::Asterisk)), - |left, _, right, span| { - Expression::Math(Box::new(Math::Multiply(left, right)).with_position(span)) - }, - ), - infix( - left(2), - just(Token::Symbol(Symbol::Slash)), - |left, _, right, span| { - Expression::Math(Box::new(Math::Divide(left, right)).with_position(span)) - }, - ), - infix( - left(1), - just(Token::Symbol(Symbol::Percent)), - |left, _, right, span| { - Expression::Math(Box::new(Math::Modulo(left, right)).with_position(span)) - }, - ), - // Indexes - infix( - left(4), - just(Token::Symbol(Symbol::Dot)), - |left, _, right, span| { - Expression::MapIndex( - Box::new(MapIndex::new(left, right)).with_position(span), - ) - }, - ), - postfix( - 3, - expression.clone().delimited_by( - just(Token::Symbol(Symbol::SquareOpen)), - just(Token::Symbol(Symbol::SquareClose)), - ), - |left, right, span| { - Expression::ListIndex( - Box::new(ListIndex::new(left, right)).with_position(span), - ) - }, - ), - // Function call - postfix( - 3, - turbofish.clone().or_not().then( - expression - .clone() - .separated_by(just(Token::Symbol(Symbol::Comma))) - .collect() - .delimited_by( - just(Token::Symbol(Symbol::ParenOpen)), - just(Token::Symbol(Symbol::ParenClose)), - ), - ), - |function_expression, - (type_parameters, value_parameters): ( - Option>, - Vec, - ), - span| { - let value_parameters = if value_parameters.is_empty() { - None - } else { - Some(value_parameters) - }; - - Expression::FunctionCall( - FunctionCall::new( - function_expression, - type_parameters, - value_parameters, - ) - .with_position(span), - ) - }, - ), - // As - postfix( - 2, - just(Token::Keyword(Keyword::As)).ignore_then(type_constructor.clone()), - |expression, constructor, span| { - Expression::As( - Box::new(As::new(expression, constructor)).with_position(span), - ) - }, - ), - )); - - choice(( - logic_math_indexes_as_and_function_calls, - built_in_function, - enum_instance, - range, - function, - list, - map, - basic_value, - identifier_expression, - )) - }); - - let expression_statement = expression.clone().map(Statement::Expression); - - let async_block = just(Token::Keyword(Keyword::Async)) - .ignore_then(statement.clone().repeated().collect().delimited_by( - just(Token::Symbol(Symbol::CurlyOpen)), - just(Token::Symbol(Symbol::CurlyClose)), - )) - .map_with(|statements, state| { - Statement::AsyncBlock(AsyncBlock::new(statements).with_position(state.span())) - }); - - let r#break = just(Token::Keyword(Keyword::Break)) - .map_with(|_, state| Statement::Break(().with_position(state.span()))); - - let assignment = positioned_identifier - .then(type_specification.clone().or_not()) - .then(choice(( - just(Token::Symbol(Symbol::Equal)).to(AssignmentOperator::Assign), - just(Token::Symbol(Symbol::PlusEqual)).to(AssignmentOperator::AddAssign), - just(Token::Symbol(Symbol::MinusEqual)).to(AssignmentOperator::SubAssign), - ))) - .then(statement.clone()) - .map_with(|(((identifier, r#type), operator), statement), state| { - Statement::Assignment( - Assignment::new(identifier, r#type, operator, statement) - .with_position(state.span()), - ) - }); - - let block_statement = block.clone().map(Statement::Block); - - let r#loop = statement - .clone() - .repeated() - .at_least(1) - .collect() - .delimited_by( - just(Token::Keyword(Keyword::Loop)).then(just(Token::Symbol(Symbol::CurlyOpen))), - just(Token::Symbol(Symbol::CurlyClose)), - ) - .map_with(|statements, state| { - Statement::Loop(Loop::new(statements).with_position(state.span())) - }); - - let r#while = just(Token::Keyword(Keyword::While)) - .ignore_then(expression.clone()) - .then(statement.clone().repeated().collect().delimited_by( - just(Token::Symbol(Symbol::CurlyOpen)), - just(Token::Symbol(Symbol::CurlyClose)), - )) - .map_with(|(expression, statements), state| { - Statement::While(While::new(expression, statements).with_position(state.span())) - }); - - let if_else = just(Token::Keyword(Keyword::If)) - .ignore_then(expression.clone()) - .then(block.clone()) - .then( - just(Token::Keyword(Keyword::Else)) - .ignore_then(just(Token::Keyword(Keyword::If))) - .ignore_then(expression.clone()) - .then(block.clone()) - .repeated() - .at_least(1) - .collect() - .or_not(), - ) - .then( - just(Token::Keyword(Keyword::Else)) - .ignore_then(block.clone()) - .or_not(), - ) - .map_with( - |(((if_expression, if_block), else_ifs), else_block), state| { - Statement::IfElse( - IfElse::new(if_expression, if_block, else_ifs, else_block) - .with_position(state.span()), - ) - }, - ); - - let type_alias = just(Token::Keyword(Keyword::Type)) - .ignore_then(positioned_identifier) - .then_ignore(just(Token::Symbol(Symbol::Equal))) - .then(type_constructor.clone()) - .map_with(|(identifier, constructor), state| { - Statement::TypeAlias( - TypeAlias::new(identifier, constructor).with_position(state.span()), - ) - }); - - let enum_variant = positioned_identifier - .then( - type_constructor - .clone() - .separated_by(just(Token::Symbol(Symbol::Comma))) - .collect() - .delimited_by( - just(Token::Symbol(Symbol::ParenOpen)), - just(Token::Symbol(Symbol::ParenClose)), - ) - .or_not(), - ) - .map(|(identifier, constructors)| EnumVariant { - name: identifier, - content: constructors, - }); - - let enum_declaration = just(Token::Keyword(Keyword::Enum)) - .ignore_then(positioned_identifier) - .then( - positioned_identifier - .separated_by(just(Token::Symbol(Symbol::Comma))) - .allow_trailing() - .collect() - .delimited_by( - just(Token::Symbol(Symbol::Less)), - just(Token::Symbol(Symbol::Greater)), - ) - .or_not(), - ) - .then( - enum_variant - .separated_by(just(Token::Symbol(Symbol::Comma))) - .allow_trailing() - .at_least(1) - .collect() - .delimited_by( - just(Token::Symbol(Symbol::CurlyOpen)), - just(Token::Symbol(Symbol::CurlyClose)), - ), - ) - .map_with(|((name, type_parameters), variants), state| { - Statement::EnumDeclaration( - EnumDeclaration::new(name, type_parameters, variants) - .with_position(state.span()), - ) - }); - - let r#use = select! { - Token::Use(text) => text, - } - .map_with(|text, state| { - Statement::Use(Use::new(text.to_string()).with_position(state.span())) - }); - - let null = just(Token::Symbol(Symbol::Semicolon)) - .ignored() - .map_with(|_, state| Statement::Null(().with_position(state.span()))); - - comment.repeated().or_not().ignore_then(choice(( - assignment, - expression_statement, - async_block, - if_else, - r#break, - block_statement, - r#loop, - r#while, - type_alias, - enum_declaration, - r#use, - null, - ))) - }); - - statement.repeated().collect().map(AbstractTree::new) -} diff --git a/dust-lang/src/parser/tests.rs b/dust-lang/src/parser/tests.rs deleted file mode 100644 index 5d993fc..0000000 --- a/dust-lang/src/parser/tests.rs +++ /dev/null @@ -1,1307 +0,0 @@ -use crate::lexer::lex; - -use super::*; - -#[test] -fn map_type() { - assert_eq!( - parse(&lex("type Map = { x: int, y: str }").unwrap()).unwrap()[0], - Statement::TypeAlias( - TypeAlias::new( - Identifier::new("Map").with_position((5, 8)), - TypeConstructor::Map( - vec![ - ( - Identifier::new("x").with_position((13, 14)), - TypeConstructor::Raw( - RawTypeConstructor::Integer.with_position((16, 19)) - ) - ), - ( - Identifier::new("y").with_position((21, 22)), - TypeConstructor::Raw( - RawTypeConstructor::String.with_position((24, 27)) - ) - ) - ] - .with_position((11, 29)) - ) - ) - .with_position((0, 29)) - ) - ); -} - -#[test] -fn type_invokation() { - assert_eq!( - parse(&lex("x: Foo(int) = Foo::Bar(42)").unwrap()).unwrap()[0], - Statement::Assignment( - Assignment::new( - Identifier::new("x").with_position((0, 1)), - Some(TypeConstructor::Invokation(TypeInvokationConstructor { - identifier: Identifier::new("Foo").with_position((3, 6)), - type_arguments: Some(vec![TypeConstructor::Raw( - RawTypeConstructor::Integer.with_position((7, 10)) - )]), - })), - AssignmentOperator::Assign, - Statement::Expression(Expression::Value( - ValueNode::EnumInstance { - type_name: Identifier::new("Foo").with_position((14, 17)), - type_arguments: None, - variant: Identifier::new("Bar").with_position((19, 22)), - content: Some(Box::new(Expression::Value( - ValueNode::Integer(42).with_position((23, 25)) - ))) - } - .with_position((14, 26)) - )) - ) - .with_position((0, 26)) - ) - ); -} - -#[test] -fn enum_instance_with_type_arguments() { - assert_eq!( - parse(&lex("Foo::::Bar(42)").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::EnumInstance { - type_name: Identifier::new("Foo").with_position((0, 3)), - type_arguments: Some(vec![ - TypeConstructor::Raw(RawTypeConstructor::Integer.with_position((6, 9))), - TypeConstructor::Raw(RawTypeConstructor::String.with_position((11, 14))) - ]), - variant: Identifier::new("Bar").with_position((17, 20)), - content: Some(Box::new(Expression::Value( - ValueNode::Integer(42).with_position((21, 23)) - ))) - } - .with_position((0, 24)) - )) - ); -} - -#[test] -fn enum_instance() { - assert_eq!( - parse(&lex("Foo::Bar(42)").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::EnumInstance { - type_name: Identifier::new("Foo").with_position((0, 3)), - type_arguments: None, - variant: Identifier::new("Bar").with_position((5, 8)), - content: Some(Box::new(Expression::Value( - ValueNode::Integer(42).with_position((9, 11)) - ))) - } - .with_position((0, 12)) - )) - ); -} - -#[test] -fn enum_declaration() { - assert_eq!( - parse(&lex("enum MyEnum { X, Y }").unwrap()).unwrap()[0], - Statement::EnumDeclaration( - EnumDeclaration::new( - Identifier::new("MyEnum").with_position((5, 11)), - None, - vec![ - EnumVariant { - name: Identifier::new("X").with_position((14, 15)), - content: None - }, - EnumVariant { - name: Identifier::new("Y").with_position((17, 18)), - content: None - } - ], - ) - .with_position((0, 20)) - ) - ); -} - -#[test] -fn enum_with_contents() { - assert_eq!( - parse(&lex("enum MyEnum { X(str, int), Y(int) }").unwrap()).unwrap()[0], - Statement::EnumDeclaration( - EnumDeclaration::new( - Identifier::new("MyEnum").with_position((5, 11)), - None, - vec![ - EnumVariant { - name: Identifier::new("X").with_position((14, 15)), - content: Some(vec![ - TypeConstructor::Raw( - RawTypeConstructor::String.with_position((16, 19)) - ), - TypeConstructor::Raw( - RawTypeConstructor::Integer.with_position((21, 24)) - ), - ]) - }, - EnumVariant { - name: Identifier::new("Y").with_position((27, 28)), - content: Some(vec![TypeConstructor::Raw( - RawTypeConstructor::Integer.with_position((29, 32)) - ),]) - } - ] - ) - .with_position((0, 35)) - ) - ); -} - -#[test] -fn enum_with_type_parameters() { - assert_eq!( - parse(&lex("enum MyEnum { X(T), Y(U) }").unwrap()).unwrap()[0], - Statement::EnumDeclaration( - EnumDeclaration::new( - Identifier::new("MyEnum").with_position((5, 11)), - Some(vec![ - Identifier::new("T").with_position((13, 14)), - Identifier::new("U").with_position((16, 17)) - ]), - vec![ - EnumVariant { - name: Identifier::new("X").with_position((21, 22)), - content: Some(vec![TypeConstructor::Invokation( - TypeInvokationConstructor { - identifier: Identifier::new("T").with_position((23, 24)), - type_arguments: None - } - )]) - }, - EnumVariant { - name: Identifier::new("Y").with_position((27, 28)), - content: Some(vec![TypeConstructor::Invokation( - TypeInvokationConstructor { - identifier: Identifier::new("U").with_position((29, 30)), - type_arguments: None - } - )]) - }, - ] - ) - .with_position((0, 33)) - ) - ); -} - -// Reuse these tests when structures are reimplemented -// #[test] -// fn structure_instance() { -// assert_eq!( -// parse( -// &lex(" -// Foo { -// bar = 42, -// baz = 'hiya', -// } -// ") -// .unwrap() -// ) -// .unwrap()[0], -// Statement::Expression(Expression::Value( -// ValueNode::Structure { -// name: Identifier::new("Foo").with_position((21, 24)), -// fields: vec![ -// ( -// Identifier::new("bar").with_position((0, 0)), -// Expression::Value(ValueNode::Integer(42).with_position((57, 59))) -// ), -// ( -// Identifier::new("baz").with_position((0, 0)), -// Expression::Value( -// ValueNode::String("hiya".to_string()).with_position((91, 97)) -// ) -// ), -// ] -// } -// .with_position((21, 120)) -// )) -// ) -// } - -// #[test] -// fn structure_definition() { -// assert_eq!( -// parse( -// &lex(" -// struct Foo { -// bar : int, -// baz : str, -// } -// ") -// .unwrap() -// ) -// .unwrap()[0], -// Statement::StructureDefinition( -// StructureDefinition::new( -// Identifier::new("Foo"), -// vec![ -// ( -// Identifier::new("bar"), -// TypeConstructor::Type(Type::Integer.with_position((64, 67))) -// ), -// ( -// Identifier::new("baz"), -// TypeConstructor::Type(Type::String.with_position((99, 102))) -// ), -// ] -// ) -// .with_position((21, 125)) -// ) -// ) -// } - -#[test] -fn r#as() { - assert_eq!( - parse(&lex("1 as str").unwrap()).unwrap()[0], - Statement::Expression(Expression::As( - Box::new(As::new( - Expression::Value(ValueNode::Integer(1).with_position((0, 1))), - TypeConstructor::Raw(RawTypeConstructor::String.with_position((5, 8))) - )) - .with_position((0, 8)) - )) - ) -} - -#[test] -fn built_in_function() { - let tokens = lex("__READ_LINE__").unwrap(); - let statements = parser(true) - .parse(tokens.spanned((tokens.len()..tokens.len()).into())) - .into_result() - .map_err(|errors| { - errors - .into_iter() - .map(DustError::from) - .collect::>() - }) - .unwrap(); - - assert_eq!( - statements[0], - Statement::Expression(Expression::Value( - ValueNode::BuiltInFunction(BuiltInFunction::ReadLine).with_position((0, 13)) - )) - ); -} - -#[test] -fn built_in_function_with_arg() { - let tokens = lex("__WRITE_LINE__('hiya')").unwrap(); - let statements = parser(true) - .parse(tokens.spanned((tokens.len()..tokens.len()).into())) - .into_result() - .map_err(|errors| { - errors - .into_iter() - .map(DustError::from) - .collect::>() - }) - .unwrap(); - - assert_eq!( - statements[0], - Statement::Expression(Expression::FunctionCall( - FunctionCall::new( - Expression::Value( - ValueNode::BuiltInFunction(BuiltInFunction::WriteLine).with_position((0, 14)) - ), - None, - Some(vec![Expression::Value( - ValueNode::String("hiya".to_string()).with_position((15, 21)) - )]) - ) - .with_position((0, 22)) - )) - ); -} - -#[test] -fn async_block() { - assert_eq!( - parse( - &lex(" - async { - 1 - 2 - 3 - } - ") - .unwrap() - ) - .unwrap()[0], - Statement::AsyncBlock( - AsyncBlock::new(vec![ - Statement::Expression(Expression::Value( - ValueNode::Integer(1).with_position((53, 54)) - )), - Statement::Expression(Expression::Value( - ValueNode::Integer(2).with_position((79, 80)) - )), - Statement::Expression(Expression::Value( - ValueNode::Integer(3).with_position((105, 106)) - )), - ]) - .with_position((21, 128)) - ) - ) -} - -#[test] -fn map_index() { - assert_eq!( - parse(&lex("{ x = 42 }.x").unwrap()).unwrap()[0], - Statement::Expression(Expression::MapIndex( - Box::new(MapIndex::new( - Expression::Value( - ValueNode::Map(vec![( - Identifier::new("x"), - None, - Expression::Value(ValueNode::Integer(42).with_position((6, 8))) - )]) - .with_position((0, 10)) - ), - Expression::Identifier(Identifier::new("x").with_position((11, 12))) - )) - .with_position((0, 12)) - )) - ); - assert_eq!( - parse(&lex("foo.x").unwrap()).unwrap()[0], - Statement::Expression(Expression::MapIndex( - Box::new(MapIndex::new( - Expression::Identifier(Identifier::new("foo").with_position((0, 3))), - Expression::Identifier(Identifier::new("x").with_position((4, 5))) - )) - .with_position((0, 5)) - )) - ); -} - -#[test] -fn r#while() { - assert_eq!( - parse(&lex("while true { output('hi') }").unwrap()).unwrap()[0], - Statement::While( - While::new( - Expression::Value(ValueNode::Boolean(true).with_position((6, 10))), - vec![Statement::Expression(Expression::FunctionCall( - FunctionCall::new( - Expression::Identifier(Identifier::new("output").with_position((13, 19))), - None, - Some(vec![Expression::Value( - ValueNode::String("hi".to_string()).with_position((20, 24)) - )]) - ) - .with_position((13, 25)) - ))] - ) - .with_position((0, 27)) - ) - ) -} - -#[test] -fn boolean_type() { - assert_eq!( - parse(&lex("foobar : bool = true").unwrap()).unwrap()[0], - Statement::Assignment( - Assignment::new( - Identifier::new("foobar").with_position((0, 6)), - Some(TypeConstructor::Raw( - RawTypeConstructor::Boolean.with_position((9, 13)) - )), - AssignmentOperator::Assign, - Statement::Expression(Expression::Value( - ValueNode::Boolean(true).with_position((16, 20)) - )) - ) - .with_position((0, 20)) - ) - ); -} - -#[test] -fn list_type() { - assert_eq!( - parse(&lex("foobar: [int; 2] = []").unwrap()).unwrap()[0], - Statement::Assignment( - Assignment::new( - Identifier::new("foobar").with_position((0, 6)), - Some(TypeConstructor::List( - ListTypeConstructor { - length: 2, - item_type: Box::new(TypeConstructor::Raw( - RawTypeConstructor::Integer.with_position((9, 12)) - )) - } - .with_position((8, 16)) - )), - AssignmentOperator::Assign, - Statement::Expression(Expression::Value( - ValueNode::List(vec![]).with_position((19, 21)) - )) - ) - .with_position((0, 21)) - ) - ); -} - -#[test] -fn list_of_type() { - assert_eq!( - parse(&lex("foobar : [bool] = [true]").unwrap()).unwrap()[0], - Statement::Assignment( - Assignment::new( - Identifier::new("foobar").with_position((0, 6)), - Some(TypeConstructor::ListOf( - Box::new(TypeConstructor::Raw( - RawTypeConstructor::Boolean.with_position((10, 14)) - )) - .with_position((9, 15)) - )), - AssignmentOperator::Assign, - Statement::Expression(Expression::Value( - ValueNode::List(vec![Expression::Value( - ValueNode::Boolean(true).with_position((19, 23)) - )]) - .with_position((18, 24)) - )) - ) - .with_position((0, 24)) - ) - ); -} - -#[test] -fn function_type() { - assert_eq!( - parse(&lex("type Foo = fn (x: int)").unwrap()).unwrap()[0], - Statement::TypeAlias( - TypeAlias::new( - Identifier::new("Foo").with_position((5, 8)), - TypeConstructor::Function( - FunctionTypeConstructor { - type_parameters: Some(vec![Identifier::new("T").with_position((15, 16))]), - value_parameters: Some(vec![( - Identifier::new("x").with_position((19, 20)), - TypeConstructor::Raw( - RawTypeConstructor::Integer.with_position((22, 25)) - ) - )]), - return_type: None - } - .with_position((11, 26)) - ) - ) - .with_position((0, 26)) - ) - ); -} - -#[test] -fn function_type_with_return() { - assert_eq!( - parse(&lex("type Foo = fn (x: int) -> T").unwrap()).unwrap()[0], - Statement::TypeAlias( - TypeAlias::new( - Identifier::new("Foo").with_position((5, 8)), - TypeConstructor::Function( - FunctionTypeConstructor { - type_parameters: Some(vec![Identifier::new("T").with_position((15, 16))]), - value_parameters: Some(vec![( - Identifier::new("x").with_position((19, 20)), - TypeConstructor::Raw( - RawTypeConstructor::Integer.with_position((22, 25)) - ) - )]), - return_type: Some(Box::new(TypeConstructor::Invokation( - TypeInvokationConstructor { - identifier: Identifier::new("T").with_position((30, 31)), - type_arguments: None - } - ))) - } - .with_position((11, 31)) - ) - ) - .with_position((0, 31)) - ) - ); -} - -#[test] -fn function_call() { - assert_eq!( - parse(&lex("foobar()").unwrap()).unwrap()[0], - Statement::Expression(Expression::FunctionCall( - FunctionCall::new( - Expression::Identifier(Identifier::new("foobar").with_position((0, 6))), - None, - None, - ) - .with_position((0, 8)) - )) - ) -} - -#[test] -fn function_call_with_arguments() { - assert_eq!( - parse(&lex("foobar::('hi')").unwrap()).unwrap()[0], - Statement::Expression(Expression::FunctionCall( - FunctionCall::new( - Expression::Identifier(Identifier::new("foobar").with_position((0, 6))), - Some(vec![TypeConstructor::Raw( - RawTypeConstructor::String.with_position((9, 12)) - )]), - Some(vec![Expression::Value( - ValueNode::String("hi".to_string()).with_position((14, 18)) - )]), - ) - .with_position((0, 19)) - )) - ) -} - -#[test] -fn range() { - assert_eq!( - parse(&lex("1..10").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Range(1..10).with_position((0, 5)) - )) - ) -} - -#[test] -fn function() { - assert_eq!( - parse(&lex("fn () -> int { 0 }").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::function( - None, - None, - Some(TypeConstructor::Raw( - RawTypeConstructor::Integer.with_position((9, 12)) - )), - Block::new(vec![Statement::Expression(Expression::Value( - ValueNode::Integer(0).with_position((15, 16)) - ))]) - .with_position((13, 18)), - ) - .with_position((0, 18)) - ),) - ); - - assert_eq!( - parse(&lex("fn (x: int) -> int { x }").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::function( - None, - Some(vec![( - Identifier::new("x"), - TypeConstructor::Raw(RawTypeConstructor::Integer.with_position((7, 10))) - )]), - Some(TypeConstructor::Raw( - RawTypeConstructor::Integer.with_position((15, 18)) - )), - Block::new(vec![Statement::Expression(Expression::Identifier( - Identifier::new("x").with_position((21, 22)) - ))]) - .with_position((19, 24)), - ) - .with_position((0, 24)) - ),) - ); -} - -#[test] -fn function_with_type_arguments() { - assert_eq!( - parse(&lex("fn (x: T, y: U) -> T { x }").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::function( - Some(vec![Identifier::new("T"), Identifier::new("U"),]), - Some(vec![ - ( - Identifier::new("x"), - TypeConstructor::Invokation(TypeInvokationConstructor { - identifier: Identifier::new("T").with_position((14, 15)), - type_arguments: None, - }) - ), - ( - Identifier::new("y"), - TypeConstructor::Invokation(TypeInvokationConstructor { - identifier: Identifier::new("U").with_position((20, 21)), - type_arguments: None, - }) - ) - ]), - Some(TypeConstructor::Invokation(TypeInvokationConstructor { - identifier: Identifier::new("T").with_position((26, 27)), - type_arguments: None, - })), - Block::new(vec![Statement::Expression(Expression::Identifier( - Identifier::new("x").with_position((30, 31)) - ))]) - .with_position((28, 33)), - ) - .with_position((0, 33)) - )) - ) -} - -#[test] -fn r#if() { - assert_eq!( - parse(&lex("if true { 'foo' }").unwrap()).unwrap()[0], - Statement::IfElse( - IfElse::new( - Expression::Value(ValueNode::Boolean(true).with_position((3, 7))), - Block::new(vec![Statement::Expression(Expression::Value( - ValueNode::String("foo".to_string()).with_position((10, 15)) - ))]) - .with_position((8, 17)), - None, - None - ) - .with_position((0, 17)) - ) - ); -} - -#[test] -fn if_else() { - assert_eq!( - parse(&lex("if true {'foo' } else { 'bar' }").unwrap()).unwrap()[0], - Statement::IfElse( - IfElse::new( - Expression::Value(ValueNode::Boolean(true).with_position((3, 7))), - Block::new(vec![Statement::Expression(Expression::Value( - ValueNode::String("foo".to_string()).with_position((9, 14)) - ))]) - .with_position((8, 16)), - None, - Some( - Block::new(vec![Statement::Expression(Expression::Value( - ValueNode::String("bar".to_string()).with_position((24, 29)) - ))]) - .with_position((22, 31)) - ) - ) - .with_position((0, 31)), - ) - ) -} - -#[test] -fn map() { - assert_eq!( - parse(&lex("{ foo = 'bar' }").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Map(vec![( - Identifier::new("foo"), - None, - Expression::Value(ValueNode::String("bar".to_string()).with_position((8, 13))) - )]) - .with_position((0, 15)) - ),) - ); - assert_eq!( - parse(&lex("{ x = 1, y = 2, }").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Map(vec![ - ( - Identifier::new("x"), - None, - Expression::Value(ValueNode::Integer(1).with_position((6, 7))) - ), - ( - Identifier::new("y"), - None, - Expression::Value(ValueNode::Integer(2).with_position((13, 14))) - ), - ]) - .with_position((0, 17)) - ),) - ); - assert_eq!( - parse(&lex("{ x = 1 y = 2 }").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Map(vec![ - ( - Identifier::new("x"), - None, - Expression::Value(ValueNode::Integer(1).with_position((6, 7))) - ), - ( - Identifier::new("y"), - None, - Expression::Value(ValueNode::Integer(2).with_position((12, 13))) - ), - ]) - .with_position((0, 15)) - )) - ); -} - -#[test] -fn math() { - assert_eq!( - parse(&lex("1 + 1").unwrap()).unwrap()[0], - Statement::Expression(Expression::Math( - Box::new(Math::Add( - Expression::Value(ValueNode::Integer(1).with_position((0, 1))), - Expression::Value(ValueNode::Integer(1).with_position((4, 5))) - )) - .with_position((0, 5)) - )) - ); -} - -#[test] -fn r#loop() { - assert_eq!( - parse(&lex("loop { 42 }").unwrap()).unwrap()[0], - Statement::Loop( - Loop::new(vec![Statement::Expression(Expression::Value( - ValueNode::Integer(42).with_position((7, 9)) - ))]) - .with_position((0, 11)) - ) - ); -} - -#[test] -fn complex_loop() { - assert_eq!( - parse(&lex("loop { if i > 2 { break } else { i += 1 } }").unwrap()).unwrap()[0], - Statement::Loop( - Loop::new(vec![Statement::IfElse( - IfElse::new( - Expression::Logic( - Box::new(Logic::Greater( - Expression::Identifier(Identifier::new("i").with_position((10, 11))), - Expression::Value(ValueNode::Integer(2).with_position((14, 15))) - )) - .with_position((10, 15)) - ), - Block::new(vec![Statement::Break(().with_position((18, 23)))]) - .with_position((16, 25)), - None, - Some( - Block::new(vec![Statement::Assignment( - Assignment::new( - Identifier::new("i").with_position((33, 34)), - None, - AssignmentOperator::AddAssign, - Statement::Expression(Expression::Value( - ValueNode::Integer(1).with_position((38, 39)) - )) - ) - .with_position((33, 39)) - )]) - .with_position((31, 41)) - ) - ) - .with_position((7, 41)) - )]) - .with_position((0, 43)) - ) - ); -} - -#[test] -fn block() { - assert_eq!( - parse(&lex("{ x }").unwrap()).unwrap()[0], - Statement::Block( - Block::new(vec![Statement::Expression(Expression::Identifier( - Identifier::new("x").with_position((2, 3)) - ),)]) - .with_position((0, 5)) - ) - ); - - assert_eq!( - parse( - &lex(" - { - x - y - z - } - ") - .unwrap() - ) - .unwrap()[0], - Statement::Block( - Block::new(vec![ - Statement::Expression(Expression::Identifier( - Identifier::new("x").with_position((39, 40)) - )), - Statement::Expression(Expression::Identifier( - Identifier::new("y").with_position((61, 62)) - )), - Statement::Expression(Expression::Identifier( - Identifier::new("z").with_position((83, 84)) - )), - ]) - .with_position((17, 102)), - ) - ); - - assert_eq!( - parse( - &lex(" - { - 1 == 1 - z - } - ") - .unwrap() - ) - .unwrap()[0], - Statement::Block( - Block::new(vec![ - Statement::Expression(Expression::Logic( - Box::new(Logic::Equal( - Expression::Value(ValueNode::Integer(1).with_position((39, 40))), - Expression::Value(ValueNode::Integer(1).with_position((44, 45))) - )) - .with_position((39, 45)) - )), - Statement::Expression(Expression::Identifier( - Identifier::new("z").with_position((66, 67)) - )), - ]) - .with_position((17, 85)), - ) - ); -} - -#[test] -fn identifier() { - assert_eq!( - parse(&lex("x").unwrap()).unwrap()[0], - Statement::Expression(Expression::Identifier( - Identifier::new("x").with_position((0, 1)) - )) - ); - assert_eq!( - parse(&lex("foobar").unwrap()).unwrap()[0], - Statement::Expression(Expression::Identifier( - Identifier::new("foobar").with_position((0, 6)) - )) - ); - assert_eq!( - parse(&lex("HELLO").unwrap()).unwrap()[0], - Statement::Expression(Expression::Identifier( - Identifier::new("HELLO").with_position((0, 5)) - )) - ); -} - -#[test] -fn assignment() { - assert_eq!( - parse(&lex("foobar = 1").unwrap()).unwrap()[0], - Statement::Assignment( - Assignment::new( - Identifier::new("foobar").with_position((0, 6)), - None, - AssignmentOperator::Assign, - Statement::Expression(Expression::Value( - ValueNode::Integer(1).with_position((9, 10)) - )) - ) - .with_position((0, 10)), - ) - ); -} - -#[test] -fn assignment_with_type() { - assert_eq!( - parse(&lex("foobar: int = 1").unwrap()).unwrap()[0], - Statement::Assignment( - Assignment::new( - Identifier::new("foobar").with_position((0, 6)), - Some(TypeConstructor::Raw( - RawTypeConstructor::Integer.with_position((8, 11)) - )), - AssignmentOperator::Assign, - Statement::Expression(Expression::Value( - ValueNode::Integer(1).with_position((14, 15)) - )) - ) - .with_position((0, 15)), - ) - ); -} - -#[test] -fn logic() { - assert_eq!( - parse(&lex("x == 1").unwrap()).unwrap()[0], - Statement::Expression(Expression::Logic( - Box::new(Logic::Equal( - Expression::Identifier(Identifier::new("x").with_position((0, 1))), - Expression::Value(ValueNode::Integer(1).with_position((5, 6))), - )) - .with_position((0, 6)) - )) - ); - - assert_eq!( - parse(&lex("(x == 1) && (y == 2)").unwrap()).unwrap()[0], - Statement::Expression(Expression::Logic( - Box::new(Logic::And( - Expression::Logic( - Box::new(Logic::Equal( - Expression::Identifier(Identifier::new("x").with_position((1, 2))), - Expression::Value(ValueNode::Integer(1).with_position((6, 7))), - )) - .with_position((1, 7)) - ), - Expression::Logic( - Box::new(Logic::Equal( - Expression::Identifier(Identifier::new("y").with_position((13, 14))), - Expression::Value(ValueNode::Integer(2).with_position((18, 19))), - )) - .with_position((13, 19)) - ) - )) - .with_position((0, 20)) - )) - ); - - assert_eq!( - parse(&lex("(x == 1) && (y == 2) && true").unwrap()).unwrap()[0], - Statement::Expression(Expression::Logic( - Box::new(Logic::And( - Expression::Logic( - Box::new(Logic::And( - Expression::Logic( - Box::new(Logic::Equal( - Expression::Identifier(Identifier::new("x").with_position((1, 2))), - Expression::Value(ValueNode::Integer(1).with_position((6, 7))) - )) - .with_position((1, 7)) - ), - Expression::Logic( - Box::new(Logic::Equal( - Expression::Identifier( - Identifier::new("y").with_position((13, 14)) - ), - Expression::Value(ValueNode::Integer(2).with_position((18, 19))) - )) - .with_position((13, 19)) - ), - )) - .with_position((0, 20)) - ), - Expression::Value(ValueNode::Boolean(true).with_position((24, 28))) - )) - .with_position((0, 28)) - )) - ); -} - -#[test] -fn list() { - assert_eq!( - parse(&lex("[]").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::List(Vec::with_capacity(0)).with_position((0, 2)) - ),) - ); - assert_eq!( - parse(&lex("[42]").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::List(vec![Expression::Value( - ValueNode::Integer(42).with_position((1, 3)) - )]) - .with_position((0, 4)) - )) - ); - assert_eq!( - parse(&lex("[42, 'foo', 'bar', [1, 2, 3,]]").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::List(vec![ - Expression::Value(ValueNode::Integer(42).with_position((1, 3))), - Expression::Value(ValueNode::String("foo".to_string()).with_position((5, 10))), - Expression::Value(ValueNode::String("bar".to_string()).with_position((12, 17))), - Expression::Value( - ValueNode::List(vec![ - Expression::Value(ValueNode::Integer(1).with_position((20, 21))), - Expression::Value(ValueNode::Integer(2).with_position((23, 24))), - Expression::Value(ValueNode::Integer(3).with_position((26, 27))), - ]) - .with_position((19, 29)) - ) - ]) - .with_position((0, 30)) - ),) - ); -} - -#[test] -fn r#true() { - assert_eq!( - parse(&lex("true").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Boolean(true).with_position((0, 4)) - )) - ); -} - -#[test] -fn r#false() { - assert_eq!( - parse(&lex("false").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Boolean(false).with_position((0, 5)) - )) - ); -} - -#[test] -fn positive_float() { - assert_eq!( - parse(&lex("0.0").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Float(0.0).with_position((0, 3)) - )) - ); - assert_eq!( - parse(&lex("42.0").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Float(42.0).with_position((0, 4)) - )) - ); - - let max_float = f64::MAX.to_string() + ".0"; - - assert_eq!( - parse(&lex(&max_float).unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Float(f64::MAX).with_position((0, 311)) - )) - ); - - let min_positive_float = f64::MIN_POSITIVE.to_string(); - - assert_eq!( - parse(&lex(&min_positive_float).unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Float(f64::MIN_POSITIVE).with_position((0, 326)) - ),) - ); -} - -#[test] -fn negative_float() { - assert_eq!( - parse(&lex("-0.0").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Float(-0.0).with_position((0, 4)) - )) - ); - assert_eq!( - parse(&lex("-42.0").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Float(-42.0).with_position((0, 5)) - )) - ); - - let min_float = f64::MIN.to_string() + ".0"; - - assert_eq!( - parse(&lex(&min_float).unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Float(f64::MIN).with_position((0, 312)) - )) - ); - - let max_negative_float = format!("-{}", f64::MIN_POSITIVE); - - assert_eq!( - parse(&lex(&max_negative_float).unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Float(-f64::MIN_POSITIVE).with_position((0, 327)) - ),) - ); -} - -#[test] -fn other_float() { - assert_eq!( - parse(&lex("Infinity").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Float(f64::INFINITY).with_position((0, 8)) - )) - ); - assert_eq!( - parse(&lex("-Infinity").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Float(f64::NEG_INFINITY).with_position((0, 9)) - )) - ); - - if let Statement::Expression(Expression::Value(WithPosition { - node: ValueNode::Float(float), - .. - })) = &parse(&lex("NaN").unwrap()).unwrap()[0] - { - assert!(float.is_nan()); - } else { - panic!("Expected a float."); - } -} - -#[test] -fn positive_integer() { - for i in 0..10 { - let source = i.to_string(); - let tokens = lex(&source).unwrap(); - let statements = parse(&tokens).unwrap(); - - assert_eq!( - statements[0], - Statement::Expression(Expression::Value( - ValueNode::Integer(i).with_position((0, 1)) - )) - ) - } - - assert_eq!( - parse(&lex("42").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Integer(42).with_position((0, 2)) - )) - ); - - let maximum_integer = i64::MAX.to_string(); - - assert_eq!( - parse(&lex(&maximum_integer).unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Integer(i64::MAX).with_position((0, 19)) - )) - ); -} - -#[test] -fn negative_integer() { - for i in -9..0 { - let source = i.to_string(); - let tokens = lex(&source).unwrap(); - let statements = parse(&tokens).unwrap(); - - assert_eq!( - statements[0], - Statement::Expression(Expression::Value( - ValueNode::Integer(i).with_position((0, 2)) - )) - ) - } - - assert_eq!( - parse(&lex("-42").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Integer(-42).with_position((0, 3)) - )) - ); - - let minimum_integer = i64::MIN.to_string(); - - assert_eq!( - parse(&lex(&minimum_integer).unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::Integer(i64::MIN).with_position((0, 20)) - )) - ); -} - -#[test] -fn double_quoted_string() { - assert_eq!( - parse(&lex("\"\"").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::String("".to_string()).with_position((0, 2)) - )) - ); - assert_eq!( - parse(&lex("\"42\"").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::String("42".to_string()).with_position((0, 4)) - ),) - ); - assert_eq!( - parse(&lex("\"foobar\"").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::String("foobar".to_string()).with_position((0, 8)) - ),) - ); -} - -#[test] -fn single_quoted_string() { - assert_eq!( - parse(&lex("''").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::String("".to_string()).with_position((0, 2)) - )) - ); - assert_eq!( - parse(&lex("'42'").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::String("42".to_string()).with_position((0, 4)) - ),) - ); - assert_eq!( - parse(&lex("'foobar'").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::String("foobar".to_string()).with_position((0, 8)) - ),) - ); -} - -#[test] -fn grave_quoted_string() { - assert_eq!( - parse(&lex("``").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::String("".to_string()).with_position((0, 2)) - )) - ); - assert_eq!( - parse(&lex("`42`").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::String("42".to_string()).with_position((0, 4)) - ),) - ); - assert_eq!( - parse(&lex("`foobar`").unwrap()).unwrap()[0], - Statement::Expression(Expression::Value( - ValueNode::String("foobar".to_string()).with_position((0, 8)) - ),) - ); -} diff --git a/dust-lang/src/standard_library.rs b/dust-lang/src/standard_library.rs deleted file mode 100644 index 0a7ead4..0000000 --- a/dust-lang/src/standard_library.rs +++ /dev/null @@ -1,133 +0,0 @@ -use std::sync::{Arc, OnceLock}; - -use crate::{ - abstract_tree::{AbstractNode, AbstractTree, SourcePosition}, - context::Context, - lexer::lex, - parser, -}; -use chumsky::prelude::*; - -pub fn std_full_compiled() -> [AbstractTree; 5] { - [ - std_core_compiled().clone(), - std_fs_compiled().clone(), - std_io_compiled().clone(), - std_json_compiled().clone(), - std_thread_compiled().clone(), - ] -} - -pub const STD_CORE: &str = include_str!("../../std/core.ds"); -pub const STD_FS: &str = include_str!("../../std/fs.ds"); -pub const STD_IO: &str = include_str!("../../std/io.ds"); -pub const STD_JSON: &str = include_str!("../../std/json.ds"); -pub const STD_THREAD: &str = include_str!("../../std/thread.ds"); - -static CORE_CONTEXT: OnceLock = OnceLock::new(); - -pub fn core_context<'a>() -> &'a Context { - CORE_CONTEXT.get_or_init(|| { - let context = Context::new(); - let std_core = std_core_compiled().clone(); - let global_scope = SourcePosition(0, usize::MAX); - - std_core - .define_and_validate(&context, true, global_scope) - .expect("Failed to validate std.core"); - std_core - .evaluate(&context, true, global_scope) - .expect("Failed to evaluate std.core"); - - context - }) -} - -static CORE_SOURCE: OnceLock<(Arc, Arc)> = OnceLock::new(); - -pub fn core_source<'a>() -> &'a (Arc, Arc) { - CORE_SOURCE.get_or_init(|| (Arc::from("std/core.ds"), Arc::from(STD_CORE))) -} - -static STD_SOURCES: OnceLock<[(Arc, Arc); 4]> = OnceLock::new(); - -pub fn std_sources<'a>() -> &'a [(Arc, Arc); 4] { - STD_SOURCES.get_or_init(|| { - [ - (Arc::from("std/fs.ds"), Arc::from(STD_FS)), - (Arc::from("std/io.ds"), Arc::from(STD_IO)), - (Arc::from("std/json.ds"), Arc::from(STD_JSON)), - (Arc::from("std/thread.ds"), Arc::from(STD_THREAD)), - ] - }) -} - -static STD_CORE_COMPILED: OnceLock = OnceLock::new(); - -pub fn std_core_compiled<'a>() -> &'a AbstractTree { - STD_CORE_COMPILED.get_or_init(|| { - let tokens = lex(STD_CORE).expect("Failed to lex"); - let abstract_tree = parser(true) - .parse(tokens.spanned((tokens.len()..tokens.len()).into())) - .into_result() - .expect("Failed to parse"); - - abstract_tree - }) -} - -static STD_FS_COMPILED: OnceLock = OnceLock::new(); - -pub fn std_fs_compiled<'a>() -> &'a AbstractTree { - STD_FS_COMPILED.get_or_init(|| { - let tokens = lex(STD_FS).expect("Failed to lex"); - let abstract_tree = parser(true) - .parse(tokens.spanned((tokens.len()..tokens.len()).into())) - .into_result() - .expect("Failed to parse"); - - abstract_tree - }) -} - -static STD_IO_COMPILED: OnceLock = OnceLock::new(); - -pub fn std_io_compiled<'a>() -> &'a AbstractTree { - STD_IO_COMPILED.get_or_init(|| { - let tokens = lex(STD_IO).expect("Failed to lex"); - let abstract_tree = parser(true) - .parse(tokens.spanned((tokens.len()..tokens.len()).into())) - .into_result() - .expect("Failed to parse"); - - abstract_tree - }) -} - -static STD_JSON_COMPILED: OnceLock = OnceLock::new(); - -pub fn std_json_compiled<'a>() -> &'a AbstractTree { - STD_JSON_COMPILED.get_or_init(|| { - let tokens = lex(STD_JSON).expect("Failed to lex"); - let abstract_tree = parser(true) - .parse(tokens.spanned((tokens.len()..tokens.len()).into())) - .into_result() - .expect("Failed to parse"); - - abstract_tree - }) -} - -static STD_THREAD_COMPILED: OnceLock = OnceLock::new(); - -pub fn std_thread_compiled<'a>() -> &'a AbstractTree { - STD_THREAD_COMPILED.get_or_init(|| { - let tokens = lex(STD_THREAD).expect("Failed to lex"); - let abstract_tree = parser(true) - .parse(tokens.spanned((tokens.len()..tokens.len()).into())) - .into_result() - .expect("Failed to parse"); - - abstract_tree - }) -} diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs new file mode 100644 index 0000000..42615aa --- /dev/null +++ b/dust-lang/src/token.rs @@ -0,0 +1,13 @@ +use crate::Identifier; + +#[derive(Debug, PartialEq, Clone)] +pub enum Token { + Eof, + Equal, + Identifier(Identifier), + Integer(i64), + Plus, + Star, + LeftParenthesis, + RightParenthesis, +} diff --git a/dust-lang/src/type.rs b/dust-lang/src/type.rs index a162a44..263ea9e 100644 --- a/dust-lang/src/type.rs +++ b/dust-lang/src/type.rs @@ -19,7 +19,13 @@ use std::{ use clap::error::Result; use serde::{Deserialize, Serialize}; -use crate::{error::TypeConflict, identifier::Identifier}; +use crate::identifier::Identifier; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct TypeConflict { + pub expected: Type, + pub actual: Type, +} #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] /// Description of a kind of value. diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index 4903a1d..645fa86 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -7,20 +7,13 @@ use std::{ }; use chumsky::container::Container; -use log::{debug, trace}; use serde::{ de::Visitor, - ser::{SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple}, + ser::{SerializeMap, SerializeSeq, SerializeTuple}, Deserialize, Deserializer, Serialize, }; -use crate::{ - abstract_tree::{AbstractNode, Block, BuiltInFunction, Evaluation, SourcePosition}, - context::Context, - error::{RuntimeError, ValidationError}, - identifier::Identifier, - Type, -}; +use crate::{identifier::Identifier, Type}; #[derive(Clone, Debug, PartialEq)] pub struct Value(Arc); @@ -34,24 +27,6 @@ impl Value { Value(Arc::new(ValueInner::Boolean(boolean))) } - pub fn built_in_function(function: BuiltInFunction) -> Self { - Value(Arc::new(ValueInner::BuiltInFunction(function))) - } - - pub fn enum_instance( - type_name: Identifier, - type_arguments: Option>, - variant: Identifier, - content: Option, - ) -> Self { - Value(Arc::new(ValueInner::EnumInstance { - type_name, - type_arguments, - variant, - content, - })) - } - pub fn float(float: f64) -> Self { Value(Arc::new(ValueInner::Float(float))) } @@ -76,26 +51,8 @@ impl Value { Value(Arc::new(ValueInner::String(to_string.to_string()))) } - pub fn function( - type_parameters: Option>, - value_parameters: Option>, - return_type: Option, - body: Block, - ) -> Self { - Value(Arc::new(ValueInner::Function(Function::new( - type_parameters, - value_parameters, - return_type, - body, - )))) - } - - pub fn structure(name: Identifier, fields: Vec<(Identifier, Value)>) -> Self { - Value(Arc::new(ValueInner::Structure { name, fields })) - } - - pub fn r#type(&self, context: &Context) -> Result { - self.0.r#type(context) + pub fn r#type(&self) -> Type { + self.0.r#type() } pub fn as_boolean(&self) -> Option { @@ -127,32 +84,6 @@ impl Display for Value { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self.inner().as_ref() { ValueInner::Boolean(boolean) => write!(f, "{boolean}"), - ValueInner::EnumInstance { - type_name, - type_arguments, - variant, - content, - } => { - write!(f, "{type_name}::")?; - - if let Some(types) = type_arguments { - write!(f, "::<")?; - - for r#type in types { - write!(f, "{type}, ")?; - } - - write!(f, ">")?; - } - - write!(f, "::{variant}(")?; - - if let Some(value) = content { - write!(f, "{value}")?; - } - - write!(f, ")") - } ValueInner::Float(float) => { write!(f, "{float}")?; @@ -191,55 +122,6 @@ impl Display for Value { } ValueInner::Range(range) => write!(f, "{}..{}", range.start, range.end), ValueInner::String(string) => write!(f, "{string}"), - ValueInner::Function(Function { - type_parameters, - value_parameters, - return_type, - body, - .. - }) => { - write!(f, "fn ")?; - - if let Some(type_parameters) = type_parameters { - write!(f, "<")?; - - for (index, identifier) in type_parameters.iter().enumerate() { - if index == type_parameters.len() - 1 { - write!(f, "{}", identifier)?; - } else { - write!(f, "{} ", identifier)?; - } - } - - write!(f, ">")?; - } - - write!(f, "(")?; - - if let Some(value_parameters) = value_parameters { - for (identifier, r#type) in value_parameters { - write!(f, "{identifier}: {}", r#type)?; - } - } - - write!(f, ")")?; - - if let Some(return_type) = return_type { - write!(f, " -> {return_type}")? - } - - write!(f, " {body}") - } - ValueInner::Structure { name, fields } => { - write!(f, "{name} {{")?; - - for (key, value) in fields { - write!(f, "{key} = {value},")?; - } - - write!(f, "}}") - } - ValueInner::BuiltInFunction(built_in_function) => write!(f, "{built_in_function}"), } } } @@ -265,38 +147,7 @@ impl Serialize for Value { { match self.0.as_ref() { ValueInner::Boolean(boolean) => serializer.serialize_bool(*boolean), - ValueInner::EnumInstance { - type_name, - type_arguments, - variant, - content, - } => { - let mut struct_ser = serializer.serialize_struct("EnumInstance", 3)?; - - struct_ser.serialize_field("type_name", type_name)?; - struct_ser.serialize_field("type_arguments", type_arguments)?; - struct_ser.serialize_field("variant", variant)?; - struct_ser.serialize_field("content", content)?; - - struct_ser.end() - } ValueInner::Float(float) => serializer.serialize_f64(*float), - ValueInner::Function(Function { - type_parameters, - value_parameters, - return_type, - body, - .. - }) => { - let mut struct_ser = serializer.serialize_struct("Function", 4)?; - - struct_ser.serialize_field("type_parameters", type_parameters)?; - struct_ser.serialize_field("value_parameters", value_parameters)?; - struct_ser.serialize_field("return_type", return_type)?; - struct_ser.serialize_field("body", body)?; - - struct_ser.end() - } ValueInner::Integer(integer) => serializer.serialize_i64(*integer), ValueInner::List(list) => { let mut list_ser = serializer.serialize_seq(Some(list.len()))?; @@ -325,15 +176,6 @@ impl Serialize for Value { tuple_ser.end() } ValueInner::String(string) => serializer.serialize_str(string), - ValueInner::Structure { name, fields } => { - let mut struct_ser = serializer.serialize_struct("Structure", 2)?; - - struct_ser.serialize_field("name", name)?; - struct_ser.serialize_field("fields", fields)?; - - struct_ser.end() - } - ValueInner::BuiltInFunction(_) => todo!(), } } } @@ -583,44 +425,22 @@ impl<'de> Deserialize<'de> for Value { #[derive(Clone, Debug, PartialEq)] pub enum ValueInner { Boolean(bool), - BuiltInFunction(BuiltInFunction), - EnumInstance { - type_name: Identifier, - type_arguments: Option>, - variant: Identifier, - content: Option, - }, Float(f64), - Function(Function), Integer(i64), List(Vec), Map(BTreeMap), Range(Range), String(String), - Structure { - name: Identifier, - fields: Vec<(Identifier, Value)>, - }, } impl ValueInner { - pub fn r#type(&self, context: &Context) -> Result { - let r#type = match self { + pub fn r#type(&self) -> Type { + match self { ValueInner::Boolean(_) => Type::Boolean, - ValueInner::EnumInstance { type_name, .. } => { - if let Some(r#type) = context.get_type(type_name)? { - r#type - } else { - return Err(ValidationError::EnumDefinitionNotFound { - identifier: type_name.clone(), - position: None, - }); - } - } ValueInner::Float(_) => Type::Float, ValueInner::Integer(_) => Type::Integer, ValueInner::List(values) => { - let item_type = values.first().unwrap().r#type(context)?; + let item_type = values.first().unwrap().r#type(); Type::List { length: values.len(), @@ -631,7 +451,7 @@ impl ValueInner { let mut type_map = BTreeMap::with_capacity(value_map.len()); for (identifier, value) in value_map { - let r#type = value.r#type(context)?; + let r#type = value.r#type(); type_map.insert(identifier.clone(), r#type); } @@ -640,29 +460,7 @@ impl ValueInner { } ValueInner::Range(_) => Type::Range, ValueInner::String(_) => Type::String, - ValueInner::Function(function) => { - let return_type = function.return_type.clone().map(Box::new); - - Type::Function { - type_parameters: function.type_parameters().clone(), - value_parameters: function.value_parameters().clone(), - return_type, - } - } - ValueInner::Structure { name, .. } => { - if let Some(r#type) = context.get_type(name)? { - r#type - } else { - return Err(ValidationError::StructDefinitionNotFound { - identifier: name.clone(), - position: None, - }); - } - } - ValueInner::BuiltInFunction(function) => function.r#type(), - }; - - Ok(r#type) + } } } @@ -701,199 +499,6 @@ impl Ord for ValueInner { (Range(_), _) => Ordering::Greater, (String(left), String(right)) => left.cmp(right), (String(_), _) => Ordering::Greater, - ( - EnumInstance { - type_name: left_name, - type_arguments: left_arguments, - variant: left_variant, - content: left_content, - }, - EnumInstance { - type_name: right_name, - type_arguments: right_arguments, - variant: right_variant, - content: right_content, - }, - ) => { - let name_cmp = left_name.cmp(right_name); - - if name_cmp.is_eq() { - let argument_cmp = left_arguments.cmp(right_arguments); - - if argument_cmp.is_eq() { - let variant_cmp = left_variant.cmp(right_variant); - - if variant_cmp.is_eq() { - left_content.cmp(right_content) - } else { - variant_cmp - } - } else { - argument_cmp - } - } else { - name_cmp - } - } - (EnumInstance { .. }, _) => Ordering::Greater, - (Function(left), Function(right)) => left.cmp(right), - (Function(_), _) => Ordering::Greater, - ( - Structure { - name: left_name, - fields: left_fields, - }, - Structure { - name: right_name, - fields: right_fields, - }, - ) => { - let name_cmp = left_name.cmp(right_name); - - if name_cmp.is_eq() { - left_fields.cmp(right_fields) - } else { - name_cmp - } - } - (Structure { .. }, _) => Ordering::Greater, - (BuiltInFunction(left), BuiltInFunction(right)) => left.cmp(right), - (BuiltInFunction(_), _) => Ordering::Greater, - } - } -} - -#[derive(Debug)] -pub struct Function { - type_parameters: Option>, - value_parameters: Option>, - return_type: Option, - body: Block, - context: Context, -} - -impl Function { - pub fn new( - type_parameters: Option>, - value_parameters: Option>, - return_type: Option, - body: Block, - ) -> Self { - Self { - type_parameters, - value_parameters, - return_type, - body, - context: Context::new(), - } - } - - pub fn type_parameters(&self) -> &Option> { - &self.type_parameters - } - - pub fn value_parameters(&self) -> &Option> { - &self.value_parameters - } - - pub fn body(&self) -> &Block { - &self.body - } - - pub fn call( - self, - outer_context: Option<&Context>, - type_arguments: Option>, - value_arguments: Option>, - ) -> Result, RuntimeError> { - trace!("Setting function call variables"); - - if let Some(outer_context) = outer_context { - if &self.context == outer_context { - log::debug!("Recursion detected"); - } - - self.context.inherit_variables_from(outer_context)?; - } - - if let (Some(type_parameters), Some(type_arguments)) = - (self.type_parameters, type_arguments) - { - for (identifier, r#type) in type_parameters.into_iter().zip(type_arguments.into_iter()) - { - self.context - .set_type(identifier.clone(), r#type, SourcePosition(0, usize::MAX))?; - } - } - - if let (Some(value_parameters), Some(value_arguments)) = - (self.value_parameters, value_arguments) - { - for ((identifier, _), value) in value_parameters - .into_iter() - .zip(value_arguments.into_iter()) - { - self.context - .set_value(identifier.clone(), value, SourcePosition(0, usize::MAX))?; - } - } - - debug!("Calling function"); - - self.body - .evaluate(&self.context, false, SourcePosition(0, usize::MAX)) - } -} - -impl Clone for Function { - fn clone(&self) -> Self { - Function { - type_parameters: self.type_parameters.clone(), - value_parameters: self.value_parameters.clone(), - return_type: self.return_type.clone(), - body: self.body.clone(), - context: Context::new(), - } - } -} - -impl Eq for Function {} - -impl PartialEq for Function { - fn eq(&self, other: &Self) -> bool { - self.type_parameters == other.type_parameters - && self.value_parameters == other.value_parameters - && self.return_type == other.return_type - && self.body == other.body - } -} - -impl PartialOrd for Function { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for Function { - fn cmp(&self, other: &Self) -> Ordering { - let type_param_cmp = self.type_parameters().cmp(&other.type_parameters); - - if type_param_cmp.is_eq() { - let value_param_cmp = self.value_parameters.cmp(&other.value_parameters); - - if value_param_cmp.is_eq() { - let return_type_cmp = self.return_type.cmp(&other.return_type); - - if return_type_cmp.is_eq() { - self.body.cmp(&other.body) - } else { - return_type_cmp - } - } else { - value_param_cmp - } - } else { - type_param_cmp } } } diff --git a/dust-lang/tests/enums.rs b/dust-lang/tests/enums.rs deleted file mode 100644 index db44e53..0000000 --- a/dust-lang/tests/enums.rs +++ /dev/null @@ -1,48 +0,0 @@ -use dust_lang::{identifier::Identifier, *}; - -#[test] -fn simple_enum() { - assert_eq!( - interpret( - "test", - " - enum FooBar { - Foo, - Bar, - } - - FooBar::Foo - " - ), - Ok(Some(Value::enum_instance( - Identifier::new("FooBar"), - None, - Identifier::new("Foo"), - None - ))) - ); -} - -#[test] -fn big_enum() { - assert_eq!( - interpret( - "test", - " - enum FooBarBaz { - Foo(T), - Bar(U), - Baz(V), - } - - FooBarBaz::::Baz(42.0) - " - ), - Ok(Some(Value::enum_instance( - Identifier::new("FooBarBaz"), - Some(vec![Type::Integer, Type::String, Type::Float]), - Identifier::new("Baz"), - Some(Value::float(42.0)), - ))) - ); -} diff --git a/dust-lang/tests/expressions.rs b/dust-lang/tests/expressions.rs deleted file mode 100644 index 90b26c7..0000000 --- a/dust-lang/tests/expressions.rs +++ /dev/null @@ -1,42 +0,0 @@ -use dust_lang::*; - -#[test] -fn logic() { - assert_eq!( - interpret("test", "1 == 1").unwrap(), - Some(Value::boolean(true)) - ); - assert_eq!( - interpret("test", "('42' == '42') && (42 != 0)").unwrap(), - Some(Value::boolean(true)) - ); -} - -#[test] -fn math() { - assert_eq!(interpret("test", "1 + 1").unwrap(), Some(Value::integer(2))); - assert_eq!( - interpret("test", "2 * (21 + 19 + 1 * 2) / 2").unwrap(), - Some(Value::integer(42)) - ); -} - -#[test] -fn list_index() { - assert_eq!( - interpret("test", "foo = [1, 2, 3]; foo[2]").unwrap(), - Some(Value::integer(3)) - ); -} - -#[test] -fn map_index() { - assert_eq!( - interpret("test", "{ x = 3 }.x").unwrap(), - Some(Value::integer(3)) - ); - assert_eq!( - interpret("test", "foo = { x = 3 }; foo.x").unwrap(), - Some(Value::integer(3)) - ); -} diff --git a/dust-lang/tests/functions.rs b/dust-lang/tests/functions.rs deleted file mode 100644 index 8be61d1..0000000 --- a/dust-lang/tests/functions.rs +++ /dev/null @@ -1,165 +0,0 @@ -use abstract_tree::{Expression, ValueNode, WithPos}; -use dust_lang::*; -use error::{DustError, ValidationError}; -use identifier::Identifier; - -#[test] -fn function_scope() { - assert_eq!( - interpret( - "test", - " - x = 2 - - foo = fn () -> int { - x = 42 - x - } - - x = 1 - - foo() - " - ), - Ok(Some(Value::integer(42))) - ); -} - -#[test] -fn function_call_with_type_argument() { - assert_eq!( - interpret( - "test", - " - foobar = fn (x: T) -> T { x } - foobar::(42) - ", - ), - Ok(Some(Value::integer(42))) - ); -} - -#[test] -fn function_call() { - assert_eq!( - interpret( - "test", - " - foobar = fn (message: str) -> str { message } - foobar('Hiya') - ", - ), - Ok(Some(Value::string("Hiya".to_string()))) - ); -} - -#[test] -fn callback() { - assert_eq!( - interpret( - "test", - " - foobar = fn (cb: fn () -> str) -> str { - cb() - } - foobar(fn () -> str { 'Hiya' }) - ", - ), - Ok(Some(Value::string("Hiya".to_string()))) - ); -} - -#[test] -fn built_in_function_call() { - assert_eq!( - interpret("test", "use std.io io.write_line('Hiya')"), - Ok(None) - ); -} - -#[test] -fn function_context_captures_values() { - assert_eq!( - interpret( - "test", - " - bar = fn () -> int { 2 } - foo = fn () -> int { bar() } - foo() - " - ), - Ok(Some(Value::integer(2))) - ); -} - -#[test] -fn recursion() { - assert_eq!( - interpret( - "test", - " - fib = fn (i: int) -> int { - if i <= 1 { - i - } else { - fib(i - 1) + fib(i - 2) - } - } - - fib(7) - " - ), - Ok(Some(Value::integer(13))) - ); -} - -#[test] -fn value_argument_error() { - assert_eq!( - interpret( - "test", - " - foobar = fn (a: int, b: int) -> int { a + b } - foobar(1) - " - ), - Err(InterpreterError::new( - "test".into(), - vec![DustError::Validation { - error: ValidationError::WrongValueArguments { - parameters: vec![ - (Identifier::new("a"), Type::Integer), - (Identifier::new("b"), Type::Integer), - ], - arguments: vec![Expression::Value( - ValueNode::Integer(1).with_position((78, 79)), - )], - }, - position: (71, 80).into() - }] - )) - ); -} - -#[test] -fn type_argument_error() { - assert_eq!( - interpret( - "test", - " - foobar = fn (a: T) -> T { a } - foobar(1) - " - ), - Err(InterpreterError::new( - "test".into(), - vec![DustError::Validation { - error: ValidationError::WrongTypeArguments { - parameters: vec![Identifier::new("T")], - arguments: vec![] - }, - position: (59, 68).into() - }] - )) - ); -} diff --git a/dust-lang/tests/statements.rs b/dust-lang/tests/statements.rs deleted file mode 100644 index 429e46b..0000000 --- a/dust-lang/tests/statements.rs +++ /dev/null @@ -1,74 +0,0 @@ -mod validation; - -use dust_lang::*; - -#[test] -fn async_block() { - assert_eq!( - interpret( - "test", - " - x = 41 - async { - x += 1 - 5 - } - x - " - ), - Ok(Some(Value::integer(42))) - ) -} - -#[test] -fn loops_and_breaks() { - assert_eq!( - interpret( - "test", - " - i = 0 - loop { - if i == 3 { - break - } else { - i += 1 - } - } - i - " - ), - Ok(Some(Value::integer(3))) - ); - assert_eq!( - interpret( - "test", - " - foobar = { - while true { - break - } - 'foobar' - } - - foobar - " - ), - Ok(Some(Value::string("foobar".to_string()))) - ); -} - -#[test] -fn r#if() { - assert_eq!( - interpret("test", "if true { 'foobar' }"), - Ok(Some(Value::string("foobar".to_string()))) - ) -} - -#[test] -fn if_else() { - assert_eq!( - interpret("test", "if false { 'foo' } else { 'bar' }"), - Ok(Some(Value::string("bar".to_string()))) - ) -} diff --git a/dust-lang/tests/structs.rs b/dust-lang/tests/structs.rs deleted file mode 100644 index a5fc082..0000000 --- a/dust-lang/tests/structs.rs +++ /dev/null @@ -1,121 +0,0 @@ -// Reuse these tests when structures are reimplemented -// use dust_lang::{ -// abstract_tree::{Type, WithPos}, -// error::{DustError, TypeConflict, ValidationError}, -// identifier::Identifier, -// interpret, Value, -// }; - -// #[test] -// fn simple_structure() { -// assert_eq!( -// interpret( -// "test", -// " -// struct Foo { -// bar : int, -// baz : str, -// } - -// Foo { -// bar = 42, -// baz = 'hiya', -// } -// " -// ), -// Ok(Some(Value::structure( -// Identifier::new("Foo").with_position((127, 130)), -// vec![ -// (Identifier::new("bar"), Value::integer(42)), -// (Identifier::new("baz"), Value::string("hiya".to_string())), -// ] -// ))) -// ) -// } - -// #[test] -// fn field_type_error() { -// assert_eq!( -// interpret( -// "test", -// " -// struct Foo { -// bar : int, -// } - -// Foo { -// bar = 'hiya', -// } -// " -// ) -// .unwrap_err() -// .errors(), -// &vec![DustError::Validation { -// error: ValidationError::TypeCheck { -// conflict: TypeConflict { -// actual: Type::String, -// expected: Type::Integer -// }, -// actual_position: (128, 134).into(), -// expected_position: Some((56, 59).into()), -// }, -// position: (96, 153).into() -// }] -// ) -// } - -// #[test] -// fn nested_structure() { -// assert_eq!( -// interpret( -// "test", -// " -// struct Bar { -// baz : int -// } -// struct Foo { -// bar : Bar -// } - -// Foo { -// bar = Bar { -// baz = 42 -// } -// } -// " -// ), -// Ok(Some(Value::structure( -// Identifier::new("Foo").with_position((172, 175)), -// vec![( -// Identifier::new("bar"), -// Value::structure( -// Identifier::new("Bar").with_position((204, 207)), -// vec![(Identifier::new("baz"), Value::integer(42))] -// ) -// ),] -// ))) -// ) -// } - -// #[test] -// fn undefined_struct() { -// assert_eq!( -// interpret( -// "test", -// " -// Foo { -// bar = 42 -// } -// " -// ) -// .unwrap_err() -// .errors(), -// &vec![DustError::Validation { -// error: ValidationError::VariableNotFound { -// identifier: Identifier::new("Foo"), -// position: (17, 20).into() -// }, -// position: (17, 69).into() -// }] -// ) -// } diff --git a/dust-lang/tests/validation.rs b/dust-lang/tests/validation.rs deleted file mode 100644 index 971c20e..0000000 --- a/dust-lang/tests/validation.rs +++ /dev/null @@ -1,80 +0,0 @@ -use dust_lang::{ - error::{DustError, TypeConflict, ValidationError}, - identifier::Identifier, - *, -}; - -#[test] -fn set_variable_with_type_error() { - assert_eq!( - interpret("test", "foobar: str = true") - .unwrap_err() - .errors(), - &vec![DustError::Validation { - error: ValidationError::TypeCheck { - conflict: TypeConflict { - actual: Type::Boolean, - expected: Type::String - }, - actual_position: (14, 18).into(), - expected_position: Some((8, 11).into()) - }, - position: (0, 18).into() - }] - ); -} - -#[test] -fn function_return_type_error() { - assert_eq!( - interpret( - "test", - " - foo = fn () -> str { 'foo' } - - bar: int = foo() - " - ) - .unwrap_err() - .errors(), - &vec![DustError::Validation { - error: ValidationError::TypeCheck { - conflict: TypeConflict { - actual: Type::String, - expected: Type::Integer - }, - actual_position: (66, 71).into(), - expected_position: Some((60, 63).into()) - }, - position: (55, 71).into() - }] - ); -} - -#[test] -fn scope() { - assert_eq!( - interpret( - "test", - " - x = 1 - - foo = fn () -> int { - x - 1 - } - - foo() - " - ) - .unwrap_err() - .errors(), - &vec![DustError::Validation { - error: ValidationError::VariableNotFound { - identifier: Identifier::new("x"), - position: (69, 70).into() - }, - position: (32, 102).into() - }] - ); -} diff --git a/dust-lang/tests/values.rs b/dust-lang/tests/values.rs deleted file mode 100644 index 5fbd43f..0000000 --- a/dust-lang/tests/values.rs +++ /dev/null @@ -1,160 +0,0 @@ -use std::collections::BTreeMap; - -use dust_lang::{ - error::{DustError, TypeConflict, ValidationError}, - identifier::Identifier, - Type, *, -}; - -#[test] -fn none() { - assert_eq!(interpret("test", "x = 9"), Ok(None)); - assert_eq!(interpret("test", "x = 1 + 1"), Ok(None)); -} - -#[test] -fn integer() { - assert_eq!(interpret("test", "1"), Ok(Some(Value::integer(1)))); - assert_eq!(interpret("test", "123"), Ok(Some(Value::integer(123)))); - assert_eq!(interpret("test", "-666"), Ok(Some(Value::integer(-666)))); -} - -#[test] -fn integer_saturation() { - assert_eq!( - interpret("test", "9223372036854775807 + 1"), - Ok(Some(Value::integer(i64::MAX))) - ); - assert_eq!( - interpret("test", "-9223372036854775808 - 1"), - Ok(Some(Value::integer(i64::MIN))) - ); -} - -#[test] -fn float() { - assert_eq!( - interpret("test", "1.7976931348623157e308"), - Ok(Some(Value::float(f64::MAX))) - ); - assert_eq!( - interpret("test", "-1.7976931348623157e308"), - Ok(Some(Value::float(f64::MIN))) - ); -} - -#[test] -fn float_saturation() { - assert_eq!( - interpret("test", "1.7976931348623157e308 + 1"), - Ok(Some(Value::float(f64::MAX))) - ); - assert_eq!( - interpret("test", "-1.7976931348623157e308 - 1"), - Ok(Some(Value::float(f64::MIN))) - ); -} - -#[test] -fn string() { - assert_eq!( - interpret("test", "\"one\""), - Ok(Some(Value::string("one".to_string()))) - ); - assert_eq!( - interpret("test", "'one'"), - Ok(Some(Value::string("one".to_string()))) - ); - assert_eq!( - interpret("test", "`one`"), - Ok(Some(Value::string("one".to_string()))) - ); - assert_eq!( - interpret("test", "`'one'`"), - Ok(Some(Value::string("'one'".to_string()))) - ); - assert_eq!( - interpret("test", "'`one`'"), - Ok(Some(Value::string("`one`".to_string()))) - ); - assert_eq!( - interpret("test", "\"'one'\""), - Ok(Some(Value::string("'one'".to_string()))) - ); -} - -#[test] -fn list() { - assert_eq!( - interpret("test", "[1, 2, 3]"), - Ok(Some(Value::list(vec![ - Value::integer(1), - Value::integer(2), - Value::integer(3), - ]))) - ); -} - -#[test] -fn empty_list() { - assert_eq!(interpret("test", "[]"), Ok(Some(Value::list(Vec::new())))); -} - -#[test] -fn map() { - let mut map = BTreeMap::new(); - - map.insert(Identifier::new("x"), Value::integer(1)); - map.insert(Identifier::new("foo"), Value::string("bar".to_string())); - - assert_eq!( - interpret("test", "{ x = 1, foo = 'bar' }"), - Ok(Some(Value::map(map))) - ); -} - -#[test] -fn empty_map() { - assert_eq!( - interpret("test", "{}"), - Ok(Some(Value::map(BTreeMap::new()))) - ); -} - -#[test] -fn map_types() { - let mut map = BTreeMap::new(); - - map.insert(Identifier::new("x"), Value::integer(1)); - map.insert(Identifier::new("foo"), Value::string("bar".to_string())); - - assert_eq!( - interpret("test", "{ x : int = 1, foo : str = 'bar' }"), - Ok(Some(Value::map(map))) - ); -} - -#[test] -fn map_type_errors() { - assert_eq!( - interpret("test", "{ foo : bool = 'bar' }") - .unwrap_err() - .errors(), - &vec![DustError::Validation { - error: ValidationError::TypeCheck { - conflict: TypeConflict { - actual: Type::String, - expected: Type::Boolean - }, - actual_position: (15, 20).into(), - expected_position: Some((8, 12).into()), - }, - position: (0, 22).into() - }] - ); -} - -#[test] -fn range() { - assert_eq!(interpret("test", "0..100"), Ok(Some(Value::range(0..100)))); -} diff --git a/dust-lang/tests/variables.rs b/dust-lang/tests/variables.rs deleted file mode 100644 index ccb390f..0000000 --- a/dust-lang/tests/variables.rs +++ /dev/null @@ -1,36 +0,0 @@ -use dust_lang::{ - abstract_tree::{Block, Expression, Statement, WithPos}, - identifier::Identifier, - Type, *, -}; - -#[test] -fn set_and_get_variable() { - assert_eq!( - interpret("test", "foobar = true; foobar"), - Ok(Some(Value::boolean(true))) - ); -} - -#[test] -fn set_variable_with_type() { - assert_eq!( - interpret("test", "foobar: bool = true; foobar"), - Ok(Some(Value::boolean(true))) - ); -} - -#[test] -fn function_variable() { - assert_eq!( - interpret("test", "foobar = fn (x: int) -> int { x }; foobar"), - Ok(Some(Value::function( - None, - Some(vec![(Identifier::new("x"), Type::Integer)]), - Some(Type::Integer), - Block::new(vec![Statement::Expression(Expression::Identifier( - Identifier::new("x").with_position((30, 31)) - ))]), - ))) - ); -} diff --git a/dust-shell/Cargo.toml b/dust-shell/Cargo.toml index c8ec455..263888d 100644 --- a/dust-shell/Cargo.toml +++ b/dust-shell/Cargo.toml @@ -1,6 +1,5 @@ [package] name = "dust-shell" -description = "Command line shell for the Dust programming language" version = "0.1.0" authors.workspace = true edition.workspace = true @@ -9,12 +8,3 @@ readme.workspace = true repository.workspace = true [dependencies] -ariadne = "0.4.0" -clap = { version = "4.5.3", features = ["derive"] } -colored = "2.1.0" -dust-lang = { path = "../dust-lang" } -env_logger = "0.11.3" -log = "0.4.21" -nu-ansi-term = "0.50.0" -reedline = { version = "0.30.0", features = ["sqlite", "system_clipboard"] } -ron = "0.8.1" diff --git a/dust-shell/src/cli.rs b/dust-shell/src/cli.rs deleted file mode 100644 index aa9b8ef..0000000 --- a/dust-shell/src/cli.rs +++ /dev/null @@ -1,167 +0,0 @@ -use std::{ - borrow::Cow, - io::{self, stderr}, - path::PathBuf, - process::Command, - sync::Arc, -}; - -use ariadne::sources; -use dust_lang::*; -use nu_ansi_term::{Color, Style}; -use reedline::{ - default_emacs_keybindings, ColumnarMenu, DefaultHinter, EditCommand, Emacs, KeyCode, - KeyModifiers, MenuBuilder, Prompt, Reedline, ReedlineEvent, ReedlineMenu, Signal, - SqliteBackedHistory, -}; - -pub fn run_shell() -> Result<(), io::Error> { - let interpreter = Interpreter::new(); - let mut keybindings = default_emacs_keybindings(); - - keybindings.add_binding( - KeyModifiers::CONTROL, - KeyCode::Char(' '), - ReedlineEvent::Edit(vec![EditCommand::InsertNewline]), - ); - keybindings.add_binding( - KeyModifiers::NONE, - KeyCode::Enter, - ReedlineEvent::SubmitOrNewline, - ); - keybindings.add_binding( - KeyModifiers::NONE, - KeyCode::Tab, - ReedlineEvent::Edit(vec![EditCommand::InsertString(" ".to_string())]), - ); - keybindings.add_binding( - KeyModifiers::NONE, - KeyCode::Tab, - ReedlineEvent::Multiple(vec![ - ReedlineEvent::Menu("context menu".to_string()), - ReedlineEvent::MenuNext, - ]), - ); - - let edit_mode = Box::new(Emacs::new(keybindings)); - let history = Box::new( - SqliteBackedHistory::with_file(PathBuf::from("target/history"), None, None) - .expect("Error loading history."), - ); - let hinter = Box::new(DefaultHinter::default().with_style(Style::new().dimmed())); - - let mut line_editor = Reedline::create() - .with_edit_mode(edit_mode) - .with_history(history) - .with_hinter(hinter) - .use_kitty_keyboard_enhancement(true) - .with_menu(ReedlineMenu::EngineCompleter(Box::new( - ColumnarMenu::default() - .with_name("context menu") - .with_text_style(Style::default().fg(Color::White)) - .with_columns(1) - .with_column_padding(10), - ))); - let mut prompt = StarshipPrompt::new(); - - prompt.reload(); - - loop { - let sig = line_editor.read_line(&prompt); - - match sig { - Ok(Signal::Success(buffer)) => { - if buffer.trim().is_empty() { - continue; - } - - let run_result = interpreter.run(Arc::from("input"), Arc::from(buffer.as_str())); - - match run_result { - Ok(Some(value)) => { - println!("{value}") - } - Ok(None) => {} - Err(error) => { - let reports = error.build_reports(); - - for report in reports { - let cache = sources(interpreter.sources()); - report.write_for_stdout(cache, stderr()).unwrap(); - } - } - } - - prompt.reload(); - } - Ok(Signal::CtrlD) | Ok(Signal::CtrlC) => { - println!("\nLeaving the Dust shell."); - break; - } - x => { - println!("Unknown event: {:?}", x); - } - } - } - - Ok(()) -} - -struct StarshipPrompt { - left: String, - right: String, -} - -impl StarshipPrompt { - fn new() -> Self { - Self { - left: String::new(), - right: String::new(), - } - } - - fn reload(&mut self) { - let run_starship_left = Command::new("starship").arg("prompt").output(); - let run_starship_right = Command::new("starship") - .args(["prompt", "--right"]) - .output(); - let left_prompt = if let Ok(output) = &run_starship_left { - String::from_utf8_lossy(&output.stdout).trim().to_string() - } else { - ">".to_string() - }; - let right_prompt = if let Ok(output) = &run_starship_right { - String::from_utf8_lossy(&output.stdout).trim().to_string() - } else { - "".to_string() - }; - - self.left = left_prompt; - self.right = right_prompt; - } -} - -impl Prompt for StarshipPrompt { - fn render_prompt_left(&self) -> Cow { - Cow::Borrowed(&self.left) - } - - fn render_prompt_right(&self) -> Cow { - Cow::Borrowed(&self.right) - } - - fn render_prompt_indicator(&self, _prompt_mode: reedline::PromptEditMode) -> Cow { - Cow::Borrowed(" ") - } - - fn render_prompt_multiline_indicator(&self) -> Cow { - Cow::Borrowed("") - } - - fn render_prompt_history_search_indicator( - &self, - _history_search: reedline::PromptHistorySearch, - ) -> Cow { - Cow::Borrowed("") - } -} diff --git a/dust-shell/src/main.rs b/dust-shell/src/main.rs index 648e850..e7a11a9 100644 --- a/dust-shell/src/main.rs +++ b/dust-shell/src/main.rs @@ -1,146 +1,3 @@ -//! Command line interface for the dust programming language. -mod cli; - -use ariadne::sources; -use clap::Parser; -use cli::run_shell; -use colored::Colorize; -use log::Level; - -use std::{ - collections::hash_map, - fs::read_to_string, - io::{stderr, Write}, - sync::Arc, -}; - -use dust_lang::Interpreter; - -/// Command-line arguments to be parsed. -#[derive(Parser, Debug)] -#[command(author, version, about, long_about = None)] -struct Args { - /// Dust source code to evaluate. - #[arg(short, long)] - command: Option, - - // Display lexer tokens of the input source. - #[arg(short, long)] - lex: bool, - - // Display abstract tree of the input source. - #[arg(short, long)] - parse: bool, - - #[arg(long)] - compile: bool, - - /// Location of the file to run. - path: Option, -} - fn main() { - env_logger::Builder::from_env("DUST_LOG") - .format(|buffer, record| { - let args = record.args(); - let log_level = match record.level() { - Level::Trace => "TRACE".cyan().bold(), - Level::Warn => "WARN".yellow().bold(), - Level::Debug => "DEBUG".green().bold(), - Level::Error => "ERROR".red().bold(), - Level::Info => "INFO".white().bold(), - }; - - writeln!(buffer, "[{}] {}", log_level, args) - }) - .init(); - - let args = Args::parse(); - let interpreter = Interpreter::new(); - - let (source_id, source): (Arc, Arc) = if let Some(path) = args.path { - let source = read_to_string(&path).unwrap(); - - (Arc::from(path.as_str()), Arc::from(source)) - } else if let Some(command) = args.command { - (Arc::from("command"), Arc::from(command)) - } else { - match run_shell() { - Ok(_) => {} - Err(error) => eprintln!("{error}"), - } - - return; - }; - - if args.lex { - match interpreter.lex(source_id, &source) { - Ok(tokens) => println!("{tokens:?}"), - Err(error) => { - for report in error.build_reports() { - report - .write_for_stdout( - sources::, Arc, hash_map::IntoIter, Arc>>( - interpreter.sources(), - ), - stderr(), - ) - .unwrap(); - } - } - } - - return; - } - - if args.parse { - match interpreter.parse(source_id, &source) { - Ok(abstract_tree) => println!("{abstract_tree:?}"), - Err(error) => { - for report in error.build_reports() { - report - .write_for_stdout(sources(interpreter.sources()), stderr()) - .unwrap(); - } - } - } - - return; - } - - if args.compile { - match interpreter.parse(source_id, &source) { - Ok(abstract_tree) => { - let ron = ron::to_string(&abstract_tree).unwrap(); - - println!("{ron}") - } - Err(error) => { - for report in error.build_reports() { - report - .write_for_stdout(sources(interpreter.sources()), stderr()) - .unwrap(); - } - } - } - - return; - } - - let run_result = interpreter.run(source_id.clone(), source); - - match run_result { - Ok(value) => { - if let Some(value) = value { - println!("{value}") - } - } - Err(error) => { - for report in error.build_reports() { - report - .write_for_stdout(sources(interpreter.sources()), stderr()) - .unwrap(); - } - } - } + println!("Hello, world!"); }