diff --git a/Cargo.lock b/Cargo.lock index 1b2c50aa6993e7c2c390a8f63419886974c8828d..431bca49c99604d1ff65f499ed5cd500516225f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -65,6 +65,16 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "ast" +version = "0.1.0" +dependencies = [ + "miette", + "thiserror", + "tokenizer", + "util", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -154,10 +164,12 @@ checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" name = "cli" version = "0.1.0" dependencies = [ + "ast", "clap", - "compiler", + "js_printer", "miette", "thiserror", + "tokenizer", ] [[package]] @@ -166,15 +178,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" -[[package]] -name = "compiler" -version = "0.1.0" -dependencies = [ - "clap", - "miette", - "thiserror", -] - [[package]] name = "errno" version = "0.3.8" @@ -220,6 +223,23 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" +[[package]] +name = "js_ast" +version = "0.1.0" +dependencies = [ + "miette", + "thiserror", +] + +[[package]] +name = "js_printer" +version = "0.1.0" +dependencies = [ + "ast", + "miette", + "thiserror", +] + [[package]] name = "libc" version = "0.2.152" @@ -429,6 +449,15 @@ dependencies = [ "syn", ] +[[package]] +name = "tokenizer" +version = "0.1.0" +dependencies = [ + "miette", + "thiserror", + "util", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -453,6 +482,10 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "util" +version = "0.1.0" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 04e6fe5d55c6c53bf947177c60713e1378cf567d..d356ed10d06269bec3fb99d25e5382e14ac1b2c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://github.com/lino-levan/blight" [workspace] resolver = "2" -members = ["cli", "compiler"] +members = ["crates/cli", "crates/util", "crates/tokenizer", "crates/ast", "crates/js_ast", "crates/js_printer"] [workspace.dependencies] clap = { version = "4.4.12", features = ["derive"] } diff --git a/README.md b/README.md index 82fb15a15eaf91f9c3404d3cea62956c431dfe31..a8c86bb587ee9cc3e6675df01bc6b647fa07b107 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,17 @@ # Blight Blight sure is a programming language. + +## Developing + +Compiling a file: + +```bash +cargo run compile --stdout ./examples/basics/fib.blight +``` + +Running the compiler on a file: + +```bash +cargo run run ./examples/basics/fib.blight +``` diff --git a/cli/Cargo.lock b/cli/Cargo.lock deleted file mode 100644 index bea6bbd39b14927d56ffb803015103f3cd74364f..0000000000000000000000000000000000000000 --- a/cli/Cargo.lock +++ /dev/null @@ -1,532 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "anstream" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" - -[[package]] -name = "anstyle-parse" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" -dependencies = [ - "anstyle", - "windows-sys", -] - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "backtrace-ext" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" -dependencies = [ - "backtrace", -] - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "blight" -version = "0.1.0" -dependencies = [ - "clap", - "miette", - "thiserror", -] - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "4.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" - -[[package]] -name = "is-terminal" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" -dependencies = [ - "hermit-abi", - "rustix", - "windows-sys", -] - -[[package]] -name = "is_ci" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" - -[[package]] -name = "libc" -version = "0.2.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" - -[[package]] -name = "linux-raw-sys" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "miette" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" -dependencies = [ - "backtrace", - "backtrace-ext", - "is-terminal", - "miette-derive", - "once_cell", - "owo-colors", - "supports-color", - "supports-hyperlinks", - "supports-unicode", - "terminal_size", - "textwrap", - "thiserror", - "unicode-width", -] - -[[package]] -name = "miette-derive" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "owo-colors" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" - -[[package]] -name = "proc-macro2" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dd5e8a1f1029c43224ad5898e50140c2aebb1705f19e67c918ebf5b9e797fe1" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a37c9326af5ed140c86a46655b5278de879853be5573c01df185b6f49a580a" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustix" -version = "0.38.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "smawk" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "supports-color" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89" -dependencies = [ - "is-terminal", - "is_ci", -] - -[[package]] -name = "supports-hyperlinks" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d" -dependencies = [ - "is-terminal", -] - -[[package]] -name = "supports-unicode" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6c2cb240ab5dd21ed4906895ee23fe5a48acdbd15a3ce388e7b62a9b66baf7" -dependencies = [ - "is-terminal", -] - -[[package]] -name = "syn" -version = "2.0.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d27c2c202598d05175a6dd3af46824b7f747f8d8e9b14c623f19fa5069735d" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "terminal_size" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "textwrap" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" -dependencies = [ - "smawk", - "unicode-linebreak", - "unicode-width", -] - -[[package]] -name = "thiserror" -version = "1.0.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cd5904763bad08ad5513ddbb12cf2ae273ca53fa9f68e843e236ec6dfccc09" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-linebreak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" - -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/cli/Cargo.toml b/cli/Cargo.toml deleted file mode 100644 index 4c78486f051c7be24ce335e4b1bae1fa253936d0..0000000000000000000000000000000000000000 --- a/cli/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "cli" -version = "0.1.0" -edition = "2021" - -[[bin]] -name = "blight" -path = "./src/main.rs" - -[dependencies] -clap.workspace = true -miette.workspace = true -thiserror.workspace = true - -compiler = { path = "../compiler" } diff --git a/cli/src/main.rs b/cli/src/main.rs deleted file mode 100644 index 42abe1f2d065601a8e60a0d289fd66e133f794d9..0000000000000000000000000000000000000000 --- a/cli/src/main.rs +++ /dev/null @@ -1,99 +0,0 @@ -use std::path::PathBuf; - -use clap::{Parser, Subcommand}; -use miette::Result; - -use compiler::transpile; - -#[derive(Parser)] -#[command(author, version, about, long_about = None)] -struct Cli { - /// Turn debugging information on - #[arg(short, long, action = clap::ArgAction::Count)] - debug: u8, - - #[command(subcommand)] - command: Commands, -} - -#[derive(Subcommand)] -enum Commands { - /// Compiles a file into javascript - Compile { - file: PathBuf, - // Whether to output to stdout instead of a file - #[arg(long, default_value_t = false)] - stdout: bool, - }, - Run { - file: PathBuf, - /// What javascript runtime to use - #[arg(short, long, default_value = "deno")] - runtime: String, - }, -} - -fn get_runtime(runtime: &String) -> String { - match std::env::var("USER") { - Ok(user) if user == "dave" => String::from("bun"), - _ => runtime.clone(), - } -} - -fn main() -> Result<()> { - let cli = Cli::parse(); - - match cli.command { - Commands::Compile { file, stdout } => { - let contents = std::fs::read_to_string(file.clone()).unwrap(); - let result = transpile(contents.clone())?; - - if stdout { - println!("{}", result); - } else { - std::fs::write(file.with_extension("js"), result).unwrap(); - } - } - Commands::Run { file, runtime } => { - let contents = std::fs::read_to_string(file.clone()).unwrap(); - let result = transpile(contents.clone())?; - let mut temp_file = std::env::temp_dir(); - temp_file.push("temp.js"); - std::fs::write(temp_file.clone(), result).unwrap(); - - let rt = get_runtime(&runtime); - - match rt.as_str() { - "deno" => { - let output = std::process::Command::new("deno") - .arg("run") - .arg("-A") - .arg(temp_file) - .output() - .expect("Failed to execute process"); - println!("{}", String::from_utf8_lossy(&output.stdout)); - } - "node" => { - let output = std::process::Command::new("node") - .arg(temp_file) - .output() - .expect("Failed to execute process"); - println!("{}", String::from_utf8_lossy(&output.stdout)); - } - "bun" => { - let output = std::process::Command::new("bun") - .arg("run") - .arg(temp_file) - .output() - .expect("Failed to execute process"); - println!("{}", String::from_utf8_lossy(&output.stdout)); - } - _ => { - println!("Unknown runtime: {}", runtime); - } - } - } - } - - Ok(()) -} diff --git a/compiler/Cargo.lock b/compiler/Cargo.lock deleted file mode 100644 index bea6bbd39b14927d56ffb803015103f3cd74364f..0000000000000000000000000000000000000000 --- a/compiler/Cargo.lock +++ /dev/null @@ -1,532 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "anstream" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" - -[[package]] -name = "anstyle-parse" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" -dependencies = [ - "anstyle", - "windows-sys", -] - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "backtrace-ext" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" -dependencies = [ - "backtrace", -] - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "blight" -version = "0.1.0" -dependencies = [ - "clap", - "miette", - "thiserror", -] - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clap" -version = "4.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - -[[package]] -name = "errno" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "gimli" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" - -[[package]] -name = "is-terminal" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" -dependencies = [ - "hermit-abi", - "rustix", - "windows-sys", -] - -[[package]] -name = "is_ci" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" - -[[package]] -name = "libc" -version = "0.2.151" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" - -[[package]] -name = "linux-raw-sys" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" - -[[package]] -name = "memchr" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" - -[[package]] -name = "miette" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" -dependencies = [ - "backtrace", - "backtrace-ext", - "is-terminal", - "miette-derive", - "once_cell", - "owo-colors", - "supports-color", - "supports-hyperlinks", - "supports-unicode", - "terminal_size", - "textwrap", - "thiserror", - "unicode-width", -] - -[[package]] -name = "miette-derive" -version = "5.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "object" -version = "0.32.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "owo-colors" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" - -[[package]] -name = "proc-macro2" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dd5e8a1f1029c43224ad5898e50140c2aebb1705f19e67c918ebf5b9e797fe1" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a37c9326af5ed140c86a46655b5278de879853be5573c01df185b6f49a580a" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustix" -version = "0.38.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "smawk" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "supports-color" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89" -dependencies = [ - "is-terminal", - "is_ci", -] - -[[package]] -name = "supports-hyperlinks" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d" -dependencies = [ - "is-terminal", -] - -[[package]] -name = "supports-unicode" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6c2cb240ab5dd21ed4906895ee23fe5a48acdbd15a3ce388e7b62a9b66baf7" -dependencies = [ - "is-terminal", -] - -[[package]] -name = "syn" -version = "2.0.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d27c2c202598d05175a6dd3af46824b7f747f8d8e9b14c623f19fa5069735d" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "terminal_size" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "textwrap" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" -dependencies = [ - "smawk", - "unicode-linebreak", - "unicode-width", -] - -[[package]] -name = "thiserror" -version = "1.0.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cd5904763bad08ad5513ddbb12cf2ae273ca53fa9f68e843e236ec6dfccc09" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-linebreak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" - -[[package]] -name = "unicode-width" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" - -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/compiler/Cargo.toml b/compiler/Cargo.toml deleted file mode 100644 index 2911f52bbe3e96a2ce75fd999ac8193d946d622f..0000000000000000000000000000000000000000 --- a/compiler/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "compiler" -version = "0.1.0" -edition = "2021" - -[lib] - -[dependencies] -clap.workspace = true -miette.workspace = true -thiserror.workspace = true diff --git a/compiler/src/ast/error.rs b/compiler/src/ast/error.rs deleted file mode 100644 index f698cb95d6c28ff61e24bab5161acbd133992c78..0000000000000000000000000000000000000000 --- a/compiler/src/ast/error.rs +++ /dev/null @@ -1,17 +0,0 @@ -use miette::Diagnostic; -use thiserror::Error; - -#[derive(Error, Diagnostic, Debug)] -#[error("AstError")] -pub struct AstError { - #[help] - error: String, -} - -impl AstError { - pub fn new(error: &'static str) -> AstError { - AstError { - error: String::from(error), - } - } -} diff --git a/compiler/src/ast/mod.rs b/compiler/src/ast/mod.rs deleted file mode 100644 index 7207f0bf0ffd68f9f55f01a3ef7ff00125893ae8..0000000000000000000000000000000000000000 --- a/compiler/src/ast/mod.rs +++ /dev/null @@ -1,26 +0,0 @@ -use miette::Result; - -mod error; -mod parse_block; -mod parse_expression; -mod parse_statement; -mod parse_type; -mod types; - -pub use super::tokenizer::Token; - -use parse_statement::parse_statement; -use types::ParserContext; - -pub use types::{Ast, Block, Type}; - -pub fn parse(tokens: Vec) -> Result> { - let mut ctx = ParserContext::new(tokens); - let mut ast: Vec = Vec::new(); - - while !ctx.empty() { - ast.push(parse_statement(&mut ctx)?); - } - - Ok(ast) -} diff --git a/compiler/src/ast/parse_block.rs b/compiler/src/ast/parse_block.rs deleted file mode 100644 index eb74a773d89edefac89123e4815b58d34490bbdf..0000000000000000000000000000000000000000 --- a/compiler/src/ast/parse_block.rs +++ /dev/null @@ -1,54 +0,0 @@ -use miette::Result; - -use super::error::AstError; -use super::parse_expression::parse_expression; -use super::parse_statement::parse_statement; -use super::types::Block; -use super::types::ParserContext; -use super::Token; - -pub fn parse_block(tokens: &mut ParserContext) -> Result { - match tokens.next() { - Some(Token::OpenBracket) => (), - _ => return Err(AstError::new("Expected { when parsing block").into()), - } - - let mut value = Vec::new(); - let mut implicit_return = false; - - loop { - match tokens.peek() { - Some(Token::ClosedBracket) => { - tokens.next(); - break; - } - _ => (), - } - - let current_cursor = tokens.cursor; - let result = parse_statement(tokens); - - match result { - Ok(ast) => value.push(ast), - Err(_) => { - tokens.cursor = current_cursor; - value.push(parse_expression(tokens)?); - implicit_return = true; - match tokens.peek() { - Some(Token::ClosedBracket) => (), - _ => { - return Err(AstError::new( - "Expected closed bracket after expression in function body", - ) - .into()); - } - } - } - } - } - - Ok(Block { - value, - implicit_return, - }) -} diff --git a/compiler/src/ast/parse_expression.rs b/compiler/src/ast/parse_expression.rs deleted file mode 100644 index 2ce6a45866c7e308019b409fdf4f034d2f3dd424..0000000000000000000000000000000000000000 --- a/compiler/src/ast/parse_expression.rs +++ /dev/null @@ -1,116 +0,0 @@ -use miette::Result; - -use super::error::AstError; -use super::parse_block::parse_block; -use super::types::{Ast, ParserContext}; -use super::Token; - -pub fn parse_expression(tokens: &mut ParserContext) -> Result { - let left = match tokens.next() { - Some(token) => match token { - Token::Number(number) => Ast::Number(number.clone()), - Token::String(string) => Ast::String(string.clone()), - Token::True => Ast::Bool(true), - Token::False => Ast::Bool(false), - Token::OpenBracket => { - // FRICK we consumed the open bracket - // we need to put the cursor back - tokens.back(); - Ast::Block(parse_block(tokens)?) - } - Token::If => { - let condition = parse_expression(tokens)?; - - let value = parse_block(tokens)?; - - let mut else_value = None; - - match tokens.peek() { - Some(Token::Else) => { - tokens.next(); - match tokens.peek() { - Option::Some(Token::If) => { - else_value = Some(Box::new(parse_expression(tokens)?)); - } - Option::Some(Token::OpenBracket) => { - else_value = Some(Box::new(Ast::Block(parse_block(tokens)?))); - } - _ => { - return Err(AstError::new( - "Expected if or open bracket after else in if statement", - ) - .into()) - } - } - } - _ => (), - } - - return Ok(Ast::If { - condition: Box::new(condition), - value, - else_value, - }); - } - Token::Identifier(name) => match tokens.peek() { - Some(Token::OpenParanthesis) => { - tokens.next(); - - let mut arguments = Vec::new(); - - loop { - match tokens.peek() { - Some(Token::ClosedParanthesis) => { - tokens.next(); - break; - } - _ => (), - } - arguments.push(parse_expression(tokens)?); - - match tokens.peek() { - Some(Token::Comma) => { - tokens.next(); - } - Some(Token::ClosedParanthesis) => (), - _ => { - return Err(AstError::new( - "Expected ) or , but found something else instead.", - ) - .into()) - } - } - } - - Ast::FunctionCall { - name: name.clone(), - arguments, - } - } - _ => Ast::Identifier(name.clone()), - }, - _ => { - println!("token: {:?}", token); - return Err(AstError::new("Expected expression, but did not get it").into()); - } - }, - None => return Err(AstError::new("Expected expression, but got nothing instead").into()), - }; - - match tokens.peek() { - Some(token) => match token { - Token::Operator(operator) => { - tokens.next(); - return Ok(Ast::Operation { - operator: operator.clone(), - left: Box::new(left), - right: Box::new(parse_expression(tokens)?), - }); - } - _ => (), - }, - _ => (), - } - - Ok(left) -} diff --git a/compiler/src/ast/parse_statement.rs b/compiler/src/ast/parse_statement.rs deleted file mode 100644 index 6d034218d390d38b5ae957ee3dde9bdcf2976459..0000000000000000000000000000000000000000 --- a/compiler/src/ast/parse_statement.rs +++ /dev/null @@ -1,268 +0,0 @@ -use miette::Result; - -use super::error::AstError; -use super::parse_block::parse_block; -use super::parse_expression::parse_expression; -use super::parse_type::parse_type; -use super::types::{Argument, Ast, ParserContext}; -use super::Token; - -/// Precondition: There is at least one token in the iterator -pub fn parse_statement(tokens: &mut ParserContext) -> Result { - let token = tokens.next().unwrap(); - match token { - Token::Pub => { - match tokens.peek() { - Some(Token::Let) | Some(Token::Var) | Some(Token::Function) => (), - _ => return Err(AstError::new("Expected let, var, or fn after pub").into()), - } - - let inner = parse_statement(tokens)?; - - return Ok(Ast::Public { - value: Box::new(inner), - }); - } - Token::Let => { - let name = match tokens.next() { - Some(Token::Identifier(name)) => name, - _ => return Err(AstError::new("Expected identifier after var").into()), - }; - let return_type = match tokens.next() { - Some(Token::Colon) => parse_type(tokens)?, - _ => return Err(AstError::new("Expected colon after identifier").into()), - }; - let value = match tokens.next() { - Some(Token::Equals) => parse_expression(tokens)?, - _ => return Err(AstError::new("Expected equals after identifier").into()), - }; - match tokens.next() { - Some(Token::Semicolon) => (), - _ => { - return Err( - AstError::new("Expected semicolon after variable declaration").into(), - ) - } - }; - Ok(Ast::ConstantDeclaration { - name: name.clone(), - return_type, - value: Box::new(value), - }) - } - Token::Var => { - let name = match tokens.next() { - Some(Token::Identifier(name)) => name, - _ => return Err(AstError::new("Expected identifier after var").into()), - }; - let return_type = match tokens.next() { - Some(Token::Colon) => parse_type(tokens)?, - _ => return Err(AstError::new("Expected colon after identifier").into()), - }; - let value = match tokens.next() { - Some(Token::Equals) => parse_expression(tokens)?, - _ => return Err(AstError::new("Expected equals after identifier").into()), - }; - match tokens.next() { - Some(Token::Semicolon) => (), - _ => { - return Err( - AstError::new("Expected semicolon after variable declaration").into(), - ) - } - }; - Ok(Ast::VariableDeclaration { - name: name.clone(), - return_type, - value: Box::new(value), - }) - } - Token::Return => { - let expression = parse_expression(tokens)?; - - match tokens.next() { - Some(Token::Semicolon) => (), - _ => return Err(AstError::new("Expected semicolon after return statement").into()), - }; - - Ok(Ast::Return { - return_value: Box::new(expression), - }) - } - Token::Function => { - let name = match tokens.next() { - Some(Token::Identifier(name)) => name.clone(), - _ => return Err(AstError::new("Expected identifier after fn").into()), - }; - - match tokens.next() { - Some(Token::OpenParanthesis) => (), - _ => { - return Err(AstError::new( - "Expected open paranthesis after identifier in function", - ) - .into()) - } - }; - - let mut arguments = Vec::new(); - - loop { - match tokens.peek() { - Some(Token::ClosedParanthesis) => { - tokens.next(); - break; - } - _ => (), - } - - let argument_name = match tokens.next() { - Some(Token::Identifier(name)) => name, - _ => { - return Err(AstError::new( - "Expected identifier for argument name in function", - ) - .into()) - } - }; - - let return_type = match tokens.next() { - Some(Token::Colon) => parse_type(tokens)?, - _ => return Err(AstError::new("Expected colon after identifier").into()), - }; - - match tokens.peek() { - Some(Token::Comma) => { - tokens.next(); - } - _ => (), - } - - arguments.push(Argument { - name: argument_name.clone(), - return_type, - }) - } - - let return_type = match tokens.next() { - Some(Token::RightArrow) => parse_type(tokens)?, - _ => { - return Err(AstError::new( - "Expected right arrow after argument list in function", - ) - .into()) - } - }; - - match tokens.peek() { - Some(Token::OpenBracket) => (), - _ => { - return Err(AstError::new( - "Expected open bracket after type in function declaration", - ) - .into()) - } - }; - - let block = parse_block(tokens)?; - - return Ok(Ast::Function { - name, - arguments, - return_type, - block, - }); - } - Token::If => { - let condition = parse_expression(tokens)?; - - let value = parse_block(tokens)?; - - let mut else_value = None; - - match tokens.peek() { - Some(Token::Else) => { - tokens.next(); - match tokens.peek() { - Option::Some(Token::If) => { - else_value = Some(Box::new(parse_expression(tokens)?)); - } - Option::Some(Token::OpenBracket) => { - else_value = Some(Box::new(Ast::Block(parse_block(tokens)?))); - } - _ => { - return Err(AstError::new( - "Expected if or open bracket after else in if statement", - ) - .into()) - } - } - } - _ => (), - } - - return Ok(Ast::If { - condition: Box::new(condition), - value, - else_value, - }); - } - Token::Identifier(name) => match tokens.peek() { - Some(Token::OpenParanthesis) => { - tokens.next(); - - let mut arguments = Vec::new(); - - loop { - match tokens.peek() { - Some(Token::ClosedParanthesis) => { - tokens.next(); - break; - } - _ => (), - } - arguments.push(parse_expression(tokens)?); - - match tokens.peek() { - Some(Token::Comma) => { - tokens.next(); - } - Some(Token::ClosedParanthesis) => (), - _ => { - return Err(AstError::new( - "Expected ) or , but found something else instead.", - ) - .into()) - } - } - } - - match tokens.next() { - Some(Token::Semicolon) => (), - _ => return Err(AstError::new("Expected semicolon after function call").into()), - }; - - Ok(Ast::FunctionCall { - name: name.clone(), - arguments, - }) - } - _ => Err(AstError::new("Unexpected identifier").into()), - }, - Token::Comment(comment) => Ok(Ast::Comment(comment.clone())), - Token::DocComment(comment) => { - let mut concatted_comments = comment.clone(); - loop { - match tokens.peek() { - Some(Token::DocComment(comment)) => { - concatted_comments.push_str(format!("\n{}", comment).as_str()); - tokens.next(); - } - _ => break, - } - } - Ok(Ast::DocComment(concatted_comments)) - } - _ => return Err(AstError::new("Unexpected token").into()), - } -} diff --git a/compiler/src/ast/parse_type.rs b/compiler/src/ast/parse_type.rs deleted file mode 100644 index 1d895c4cc5d7e1318610434de4c998dfb2cb6864..0000000000000000000000000000000000000000 --- a/compiler/src/ast/parse_type.rs +++ /dev/null @@ -1,19 +0,0 @@ -use miette::Result; - -use super::error::AstError; -use super::types::{ParserContext, Type}; -use super::Token; - -pub fn parse_type(tokens: &mut ParserContext) -> Result { - match tokens.next() { - Some(Token::Identifier(typ)) => match typ.as_str() { - "int" => Ok(Type::Int), - "float" => Ok(Type::Float), - "bigint" => Ok(Type::Bigint), - "bool" => Ok(Type::Bool), - "string" => Ok(Type::String), - _ => return Err(AstError::new("Expected type").into()), - }, - _ => return Err(AstError::new("Expected type").into()), - } -} diff --git a/compiler/src/ast/types.rs b/compiler/src/ast/types.rs deleted file mode 100644 index 9ae6193937927925b377858e1cba6b3c01067502..0000000000000000000000000000000000000000 --- a/compiler/src/ast/types.rs +++ /dev/null @@ -1,110 +0,0 @@ -// TODO(lino-levan): Split up AST into expressions, statements, etc. - -use crate::tokenizer::Token; -use crate::util::Operator; - -#[derive(Debug)] -pub struct ParserContext { - pub tokens: Vec, - pub cursor: usize, -} - -impl ParserContext { - pub fn new(tokens: Vec) -> ParserContext { - ParserContext { tokens, cursor: 0 } - } - - pub fn empty(&self) -> bool { - self.cursor == self.tokens.len() - } - - pub fn back(&mut self) { - self.cursor -= 1; - } - - pub fn next(&mut self) -> Option { - if self.cursor == self.tokens.len() { - return None; - } - - let token = self.tokens[self.cursor].clone(); - self.cursor += 1; - Some(token) - } - - pub fn peek(&self) -> Option { - if self.cursor == self.tokens.len() { - return None; - } - - Some(self.tokens[self.cursor].clone()) - } -} - -#[derive(Debug)] -pub enum Type { - Int, - Float, - Bigint, - Bool, - String, -} - -#[derive(Debug)] -pub struct Block { - pub value: Vec, - pub implicit_return: bool, -} - -#[derive(Debug)] -pub struct Argument { - pub name: String, - pub return_type: Type, -} - -#[derive(Debug)] -pub enum Ast { - Public { - value: Box, - }, - ConstantDeclaration { - name: String, - return_type: Type, - value: Box, - }, - VariableDeclaration { - name: String, - return_type: Type, - value: Box, - }, - Operation { - operator: Operator, - left: Box, - right: Box, - }, - Return { - return_value: Box, - }, - Function { - name: String, - arguments: Vec, - return_type: Type, - block: Block, - }, - FunctionCall { - name: String, - arguments: Vec, - }, - If { - condition: Box, - value: Block, - else_value: Option>, - }, - Block(Block), - Number(String), - Bool(bool), - String(String), - Identifier(String), - Comment(String), - DocComment(String), -} diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs deleted file mode 100644 index 620f35e5419e15c1ef1aff95a41adf78f40590a9..0000000000000000000000000000000000000000 --- a/compiler/src/lib.rs +++ /dev/null @@ -1,20 +0,0 @@ -use miette::Result; - -pub mod ast; -pub mod tokenizer; -pub mod printer; - -pub mod util; - -pub fn transpile(content: String) -> Result { - // 1. Tokenize the input - let tokens = tokenizer::tokenize(content)?; - // 2. Parse the tokens into an AST - let tree = ast::parse(tokens)?; - // 3. Type check the AST - // type_check(tree.clone())?; - // 4. Transpile the AST into javascript - let result = printer::transpile(tree)?; - // 5. Return the javascript - return Ok(result); -} diff --git a/compiler/src/printer/mod.rs b/compiler/src/printer/mod.rs deleted file mode 100644 index fb310f0a88210c1429169a2f1149e4f70c386ec0..0000000000000000000000000000000000000000 --- a/compiler/src/printer/mod.rs +++ /dev/null @@ -1,139 +0,0 @@ -use miette::Result; - -use super::ast::{Ast, Type}; - -fn transpile_helper(tree: &Ast) -> Result { - Ok(match tree { - Ast::Number(number) => format!("{}", number), - Ast::Identifier(name) => format!("{}", name), - Ast::Bool(value) => format!("{}", value), - Ast::String(value) => format!("\"{}\"", value), - Ast::Comment(comment) => format!("// {}\n", comment), - Ast::DocComment(comment) => format!("/** {} */\n", comment), - Ast::Operation { - operator, - left, - right, - } => format!( - "{} {} {}", - transpile_helper(left)?, - operator.clone().to_string(), - transpile_helper(right)? - ), - Ast::Public { value } => format!("export {}", transpile_helper(value)?), - Ast::VariableDeclaration { - name, - return_type, - value, - } => match return_type { - Type::Bigint => format!("let {} = BigInt({});\n", name, transpile_helper(value)?), - _ => format!("let {} = {};\n", name, transpile_helper(value)?), - }, - Ast::ConstantDeclaration { - name, - return_type, - value, - } => match return_type { - Type::Bigint => format!("const {} = BigInt({});\n", name, transpile_helper(value)?), - _ => format!("const {} = {};\n", name, transpile_helper(value)?), - }, - Ast::Return { return_value } => format!("return {};\n", transpile_helper(return_value)?), - Ast::Function { - name, - arguments, - return_type: _, - block, - } => { - let mut result = format!("function {}(", name); - - for (i, argument) in arguments.iter().enumerate() { - if i == 0 { - result += argument.name.as_str(); - } else { - result += format!(", {}", argument.name).as_str(); - } - } - - result += ") {\n"; - - for (i, statement) in block.value.iter().enumerate() { - if block.implicit_return && i == block.value.len() - 1 { - result += format!("return {};\n", transpile_helper(statement)?).as_str(); - break; - } - result += transpile_helper(statement)?.as_str(); - } - - result += "}\n"; - - result - } - Ast::If { - condition, - value, - else_value, - } => { - let mut result = format!("if ({}) {{\n", transpile_helper(condition)?,); - - for (i, statement) in value.value.iter().enumerate() { - if value.implicit_return && i == value.value.len() - 1 { - result += format!("return {};\n", transpile_helper(statement)?).as_str(); - break; - } - result += transpile_helper(statement)?.as_str(); - } - - result += "}"; - - if let Some(val) = else_value { - result += format!(" else {{\n{}}}", transpile_helper(val)?).as_str(); - } else { - result += "\n"; - } - - result - } - Ast::FunctionCall { name, arguments } => { - let mut result = match name.as_str() { - "print" => String::from("console.log("), - _ => format!("{}(", name), - }; - - for (i, argument) in arguments.iter().enumerate() { - if i == 0 { - result += transpile_helper(argument)?.as_str(); - } else { - result += format!(", {}", transpile_helper(argument)?).as_str(); - } - } - - result += ")"; - - result - } - Ast::Block(block) => { - let mut result = String::from("(()=>{\n"); - for (i, statement) in block.value.iter().enumerate() { - if block.implicit_return && i == block.value.len() - 1 { - result += format!("return {};\n", transpile_helper(statement)?).as_str(); - break; - } - result += transpile_helper(statement)?.as_str(); - } - - result += "})()\n"; - - result - } - }) -} - -pub fn transpile(forest: Vec) -> Result { - let mut result = String::new(); - - for tree in forest { - result.push_str(&transpile_helper(&tree)?); - } - - Ok(result) -} diff --git a/compiler/src/tokenizer.rs b/compiler/src/tokenizer.rs deleted file mode 100644 index df7b1ca200f8d84b970300c6a390c3e24c248276..0000000000000000000000000000000000000000 --- a/compiler/src/tokenizer.rs +++ /dev/null @@ -1,199 +0,0 @@ -use miette::{Diagnostic, Result}; -use thiserror::Error; - -use super::util::Operator; - -#[derive(Error, Diagnostic, Debug)] -#[error("UnknownCharacter")] -struct UnknownCharacter { - #[help] - error: String, -} - -#[derive(Debug, Clone)] -pub enum Token { - // Literals - Identifier(String), - Number(String), - String(String), - // Comments - Comment(String), - DocComment(String), - // Keywords - True, - False, - Let, - Var, - If, - Else, - Return, - Pub, - Function, - RightArrow, - Comma, - OpenParanthesis, - ClosedParanthesis, - OpenBracket, - ClosedBracket, - Colon, - Equals, - Semicolon, - // Operators - Operator(Operator), -} - -pub fn tokenize(content: String) -> Result> { - let mut tokens: Vec = Vec::new(); - let mut chars = content.chars().enumerate().peekable(); - - loop { - match chars.next() { - Some((_, c)) => match c { - 'a'..='z' | 'A'..='Z' | '_' => { - let mut current_token = String::new(); - current_token.push(c); - loop { - let c = chars.peek(); - if c.is_none() { - break; - } - let (_, c) = c.unwrap(); - match c { - 'a'..='z' | 'A'..='Z' | '_' | '0'..='9' => { - current_token.push(*c); - chars.next(); - } - _ => break, - } - } - - match current_token.as_str() { - "var" => tokens.push(Token::Var), - "let" => tokens.push(Token::Let), - "if" => tokens.push(Token::If), - "else" => tokens.push(Token::Else), - "pub" => tokens.push(Token::Pub), - "fn" => tokens.push(Token::Function), - "return" => tokens.push(Token::Return), - "true" => tokens.push(Token::True), - "false" => tokens.push(Token::False), - _ => tokens.push(Token::Identifier(current_token)), - } - } - '"' => { - let mut current_token = String::new(); - loop { - let c = chars.next(); - if c.is_none() { - break; - } - let (_, c) = c.unwrap(); - match c { - '"' => break, - _ => current_token.push(c), - } - } - tokens.push(Token::String(current_token)); - } - '0'..='9' => { - let mut current_token = String::new(); - current_token.push(c); - loop { - let c = chars.peek(); - if c.is_none() { - break; - } - let (_, c) = c.unwrap(); - match c { - '0'..='9' => { - current_token.push(*c); - chars.next(); - } - _ => break, - } - } - tokens.push(Token::Number(current_token)); - } - ':' => tokens.push(Token::Colon), - '=' => match chars.peek() { - Some((_, '=')) => { - chars.next(); - tokens.push(Token::Operator(Operator::Equals)); - } - _ => tokens.push(Token::Equals), - }, - ';' => tokens.push(Token::Semicolon), - '>' => tokens.push(Token::Operator(Operator::GreaterThan)), - '+' => tokens.push(Token::Operator(Operator::Add)), - '-' => match chars.peek() { - Some((_, '>')) => { - chars.next(); - tokens.push(Token::RightArrow); - } - _ => tokens.push(Token::Operator(Operator::Substract)), - }, - '*' => match chars.peek() { - Some((_, '*')) => { - chars.next(); - tokens.push(Token::Operator(Operator::Power)); - } - _ => tokens.push(Token::Operator(Operator::Multiply)), - }, - '/' => { - match chars.peek() { - Some((_, '/')) => { - chars.next(); // Consume the second slash - - let is_doc_comment = match chars.peek() { - Some((_, '/')) => { - chars.next(); // Consume the third slash - true - } - _ => false, - }; - - let mut comment = String::new(); - loop { - let c = chars.next(); - if c.is_none() { - break; - } - let (_, c) = c.unwrap(); - match c { - '\n' => break, - _ => { - comment.push(c.clone()); - } - } - } - - comment = comment.trim().to_string(); - - if is_doc_comment { - tokens.push(Token::DocComment(comment)); - } else { - tokens.push(Token::Comment(comment)); - } - } - _ => tokens.push(Token::Operator(Operator::Divide)), - } - } - ',' => tokens.push(Token::Comma), - '(' => tokens.push(Token::OpenParanthesis), - ')' => tokens.push(Token::ClosedParanthesis), - '{' => tokens.push(Token::OpenBracket), - '}' => tokens.push(Token::ClosedBracket), - s if s.is_whitespace() => (), - _ => { - return Err(UnknownCharacter { - error: format!("Unsupported character: {}", c), - } - .into()) - } - }, - None => break, - } - } - - Ok(tokens) -} diff --git a/compiler/src/util.rs b/compiler/src/util.rs deleted file mode 100644 index 25de3ac1c7c30d6191678c51bb23193e298bd284..0000000000000000000000000000000000000000 --- a/compiler/src/util.rs +++ /dev/null @@ -1,24 +0,0 @@ -#[derive(Debug, Clone)] -pub enum Operator { - Add, - Substract, - Multiply, - Divide, - Power, - Equals, - GreaterThan, -} - -impl Operator { - pub fn to_string(self) -> String { - String::from(match self { - Self::Add => "+", - Self::Substract => "-", - Self::Divide => "/", - Self::Multiply => "*", - Self::Power => "**", - Self::Equals => "===", - Self::GreaterThan => ">", - }) - } -} diff --git a/crates/ast/Cargo.toml b/crates/ast/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..2f57e0d3305382b701e02b9ba80ee44d14c7d822 --- /dev/null +++ b/crates/ast/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "ast" +version = "0.1.0" +edition = "2021" + +[lib] + +[dependencies] +miette.workspace = true +thiserror.workspace = true + +tokenizer = { path = "../tokenizer" } +util = { path = "../util" } diff --git a/crates/ast/src/error.rs b/crates/ast/src/error.rs new file mode 100644 index 0000000000000000000000000000000000000000..f698cb95d6c28ff61e24bab5161acbd133992c78 --- /dev/null +++ b/crates/ast/src/error.rs @@ -0,0 +1,17 @@ +use miette::Diagnostic; +use thiserror::Error; + +#[derive(Error, Diagnostic, Debug)] +#[error("AstError")] +pub struct AstError { + #[help] + error: String, +} + +impl AstError { + pub fn new(error: &'static str) -> AstError { + AstError { + error: String::from(error), + } + } +} diff --git a/crates/ast/src/lib.rs b/crates/ast/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..8ba4651df3847987415e038f685d975ab26229b0 --- /dev/null +++ b/crates/ast/src/lib.rs @@ -0,0 +1,26 @@ +use miette::Result; + +mod error; +mod parse_block; +mod parse_expression; +mod parse_statement; +mod parse_type; +mod types; + +use tokenizer::Token; + +use parse_statement::parse_statement; +use types::ParserContext; + +pub use types::{Ast, Block, Type}; + +pub fn parse(tokens: Vec) -> Result> { + let mut ctx = ParserContext::new(tokens); + let mut ast: Vec = Vec::new(); + + while !ctx.empty() { + ast.push(parse_statement(&mut ctx)?); + } + + Ok(ast) +} diff --git a/crates/ast/src/parse_block.rs b/crates/ast/src/parse_block.rs new file mode 100644 index 0000000000000000000000000000000000000000..c074466d00afb74240012c5d37631596e5cbc374 --- /dev/null +++ b/crates/ast/src/parse_block.rs @@ -0,0 +1,55 @@ +use miette::Result; + +use tokenizer::Token; + +use super::error::AstError; +use super::parse_expression::parse_expression; +use super::parse_statement::parse_statement; +use super::types::Block; +use super::types::ParserContext; + +pub fn parse_block(tokens: &mut ParserContext) -> Result { + match tokens.next() { + Some(Token::OpenBracket) => (), + _ => return Err(AstError::new("Expected { when parsing block").into()), + } + + let mut value = Vec::new(); + let mut implicit_return = false; + + loop { + match tokens.peek() { + Some(Token::ClosedBracket) => { + tokens.next(); + break; + } + _ => (), + } + + let current_cursor = tokens.cursor; + let result = parse_statement(tokens); + + match result { + Ok(ast) => value.push(ast), + Err(_) => { + tokens.cursor = current_cursor; + value.push(parse_expression(tokens)?); + implicit_return = true; + match tokens.peek() { + Some(Token::ClosedBracket) => (), + _ => { + return Err(AstError::new( + "Expected closed bracket after expression in function body", + ) + .into()); + } + } + } + } + } + + Ok(Block { + value, + implicit_return, + }) +} diff --git a/crates/ast/src/parse_expression.rs b/crates/ast/src/parse_expression.rs new file mode 100644 index 0000000000000000000000000000000000000000..022a870acabd00c2031b97d4fbfe8a35a51f0709 --- /dev/null +++ b/crates/ast/src/parse_expression.rs @@ -0,0 +1,117 @@ +use miette::Result; + +use tokenizer::Token; + +use super::error::AstError; +use super::parse_block::parse_block; +use super::types::{Ast, ParserContext}; + +pub fn parse_expression(tokens: &mut ParserContext) -> Result { + let left = match tokens.next() { + Some(token) => match token { + Token::Number(number) => Ast::Number(number.clone()), + Token::String(string) => Ast::String(string.clone()), + Token::True => Ast::Bool(true), + Token::False => Ast::Bool(false), + Token::OpenBracket => { + // FRICK we consumed the open bracket + // we need to put the cursor back + tokens.back(); + Ast::Block(parse_block(tokens)?) + } + Token::If => { + let condition = parse_expression(tokens)?; + + let value = parse_block(tokens)?; + + let mut else_value = None; + + match tokens.peek() { + Some(Token::Else) => { + tokens.next(); + match tokens.peek() { + Option::Some(Token::If) => { + else_value = Some(Box::new(parse_expression(tokens)?)); + } + Option::Some(Token::OpenBracket) => { + else_value = Some(Box::new(Ast::Block(parse_block(tokens)?))); + } + _ => { + return Err(AstError::new( + "Expected if or open bracket after else in if statement", + ) + .into()) + } + } + } + _ => (), + } + + return Ok(Ast::If { + condition: Box::new(condition), + value, + else_value, + }); + } + Token::Identifier(name) => match tokens.peek() { + Some(Token::OpenParanthesis) => { + tokens.next(); + + let mut arguments = Vec::new(); + + loop { + match tokens.peek() { + Some(Token::ClosedParanthesis) => { + tokens.next(); + break; + } + _ => (), + } + arguments.push(parse_expression(tokens)?); + + match tokens.peek() { + Some(Token::Comma) => { + tokens.next(); + } + Some(Token::ClosedParanthesis) => (), + _ => { + return Err(AstError::new( + "Expected ) or , but found something else instead.", + ) + .into()) + } + } + } + + Ast::FunctionCall { + name: name.clone(), + arguments, + } + } + _ => Ast::Identifier(name.clone()), + }, + _ => { + println!("token: {:?}", token); + return Err(AstError::new("Expected expression, but did not get it").into()); + } + }, + None => return Err(AstError::new("Expected expression, but got nothing instead").into()), + }; + + match tokens.peek() { + Some(token) => match token { + Token::Operator(operator) => { + tokens.next(); + return Ok(Ast::Operation { + operator: operator.clone(), + left: Box::new(left), + right: Box::new(parse_expression(tokens)?), + }); + } + _ => (), + }, + _ => (), + } + + Ok(left) +} diff --git a/crates/ast/src/parse_statement.rs b/crates/ast/src/parse_statement.rs new file mode 100644 index 0000000000000000000000000000000000000000..c7b78e92a5babc909209de498c7e1596016547e4 --- /dev/null +++ b/crates/ast/src/parse_statement.rs @@ -0,0 +1,269 @@ +use miette::Result; + +use tokenizer::Token; + +use super::error::AstError; +use super::parse_block::parse_block; +use super::parse_expression::parse_expression; +use super::parse_type::parse_type; +use super::types::{Argument, Ast, ParserContext}; + +/// Precondition: There is at least one token in the iterator +pub fn parse_statement(tokens: &mut ParserContext) -> Result { + let token = tokens.next().unwrap(); + match token { + Token::Pub => { + match tokens.peek() { + Some(Token::Let) | Some(Token::Var) | Some(Token::Function) => (), + _ => return Err(AstError::new("Expected let, var, or fn after pub").into()), + } + + let inner = parse_statement(tokens)?; + + return Ok(Ast::Public { + value: Box::new(inner), + }); + } + Token::Let => { + let name = match tokens.next() { + Some(Token::Identifier(name)) => name, + _ => return Err(AstError::new("Expected identifier after var").into()), + }; + let return_type = match tokens.next() { + Some(Token::Colon) => parse_type(tokens)?, + _ => return Err(AstError::new("Expected colon after identifier").into()), + }; + let value = match tokens.next() { + Some(Token::Equals) => parse_expression(tokens)?, + _ => return Err(AstError::new("Expected equals after identifier").into()), + }; + match tokens.next() { + Some(Token::Semicolon) => (), + _ => { + return Err( + AstError::new("Expected semicolon after variable declaration").into(), + ) + } + }; + Ok(Ast::ConstantDeclaration { + name: name.clone(), + return_type, + value: Box::new(value), + }) + } + Token::Var => { + let name = match tokens.next() { + Some(Token::Identifier(name)) => name, + _ => return Err(AstError::new("Expected identifier after var").into()), + }; + let return_type = match tokens.next() { + Some(Token::Colon) => parse_type(tokens)?, + _ => return Err(AstError::new("Expected colon after identifier").into()), + }; + let value = match tokens.next() { + Some(Token::Equals) => parse_expression(tokens)?, + _ => return Err(AstError::new("Expected equals after identifier").into()), + }; + match tokens.next() { + Some(Token::Semicolon) => (), + _ => { + return Err( + AstError::new("Expected semicolon after variable declaration").into(), + ) + } + }; + Ok(Ast::VariableDeclaration { + name: name.clone(), + return_type, + value: Box::new(value), + }) + } + Token::Return => { + let expression = parse_expression(tokens)?; + + match tokens.next() { + Some(Token::Semicolon) => (), + _ => return Err(AstError::new("Expected semicolon after return statement").into()), + }; + + Ok(Ast::Return { + return_value: Box::new(expression), + }) + } + Token::Function => { + let name = match tokens.next() { + Some(Token::Identifier(name)) => name.clone(), + _ => return Err(AstError::new("Expected identifier after fn").into()), + }; + + match tokens.next() { + Some(Token::OpenParanthesis) => (), + _ => { + return Err(AstError::new( + "Expected open paranthesis after identifier in function", + ) + .into()) + } + }; + + let mut arguments = Vec::new(); + + loop { + match tokens.peek() { + Some(Token::ClosedParanthesis) => { + tokens.next(); + break; + } + _ => (), + } + + let argument_name = match tokens.next() { + Some(Token::Identifier(name)) => name, + _ => { + return Err(AstError::new( + "Expected identifier for argument name in function", + ) + .into()) + } + }; + + let return_type = match tokens.next() { + Some(Token::Colon) => parse_type(tokens)?, + _ => return Err(AstError::new("Expected colon after identifier").into()), + }; + + match tokens.peek() { + Some(Token::Comma) => { + tokens.next(); + } + _ => (), + } + + arguments.push(Argument { + name: argument_name.clone(), + return_type, + }) + } + + let return_type = match tokens.next() { + Some(Token::RightArrow) => parse_type(tokens)?, + _ => { + return Err(AstError::new( + "Expected right arrow after argument list in function", + ) + .into()) + } + }; + + match tokens.peek() { + Some(Token::OpenBracket) => (), + _ => { + return Err(AstError::new( + "Expected open bracket after type in function declaration", + ) + .into()) + } + }; + + let block = parse_block(tokens)?; + + return Ok(Ast::Function { + name, + arguments, + return_type, + block, + }); + } + Token::If => { + let condition = parse_expression(tokens)?; + + let value = parse_block(tokens)?; + + let mut else_value = None; + + match tokens.peek() { + Some(Token::Else) => { + tokens.next(); + match tokens.peek() { + Option::Some(Token::If) => { + else_value = Some(Box::new(parse_expression(tokens)?)); + } + Option::Some(Token::OpenBracket) => { + else_value = Some(Box::new(Ast::Block(parse_block(tokens)?))); + } + _ => { + return Err(AstError::new( + "Expected if or open bracket after else in if statement", + ) + .into()) + } + } + } + _ => (), + } + + return Ok(Ast::If { + condition: Box::new(condition), + value, + else_value, + }); + } + Token::Identifier(name) => match tokens.peek() { + Some(Token::OpenParanthesis) => { + tokens.next(); + + let mut arguments = Vec::new(); + + loop { + match tokens.peek() { + Some(Token::ClosedParanthesis) => { + tokens.next(); + break; + } + _ => (), + } + arguments.push(parse_expression(tokens)?); + + match tokens.peek() { + Some(Token::Comma) => { + tokens.next(); + } + Some(Token::ClosedParanthesis) => (), + _ => { + return Err(AstError::new( + "Expected ) or , but found something else instead.", + ) + .into()) + } + } + } + + match tokens.next() { + Some(Token::Semicolon) => (), + _ => return Err(AstError::new("Expected semicolon after function call").into()), + }; + + Ok(Ast::FunctionCall { + name: name.clone(), + arguments, + }) + } + _ => Err(AstError::new("Unexpected identifier").into()), + }, + Token::Comment(comment) => Ok(Ast::Comment(comment.clone())), + Token::DocComment(comment) => { + let mut concatted_comments = comment.clone(); + loop { + match tokens.peek() { + Some(Token::DocComment(comment)) => { + concatted_comments.push_str(format!("\n{}", comment).as_str()); + tokens.next(); + } + _ => break, + } + } + Ok(Ast::DocComment(concatted_comments)) + } + _ => return Err(AstError::new("Unexpected token").into()), + } +} diff --git a/crates/ast/src/parse_type.rs b/crates/ast/src/parse_type.rs new file mode 100644 index 0000000000000000000000000000000000000000..9b061cdcc6f8483921a1067e99f81d91252ffb88 --- /dev/null +++ b/crates/ast/src/parse_type.rs @@ -0,0 +1,20 @@ +use miette::Result; + +use tokenizer::Token; + +use super::error::AstError; +use super::types::{ParserContext, Type}; + +pub fn parse_type(tokens: &mut ParserContext) -> Result { + match tokens.next() { + Some(Token::Identifier(typ)) => match typ.as_str() { + "int" => Ok(Type::Int), + "float" => Ok(Type::Float), + "bigint" => Ok(Type::Bigint), + "bool" => Ok(Type::Bool), + "string" => Ok(Type::String), + _ => return Err(AstError::new("Expected type").into()), + }, + _ => return Err(AstError::new("Expected type").into()), + } +} diff --git a/crates/ast/src/types.rs b/crates/ast/src/types.rs new file mode 100644 index 0000000000000000000000000000000000000000..d6fb9048e1bb0234378cec9be32298379699f2dd --- /dev/null +++ b/crates/ast/src/types.rs @@ -0,0 +1,110 @@ +// TODO(lino-levan): Split up AST into expressions, statements, etc. + +use tokenizer::Token; +use util::Operator; + +#[derive(Debug)] +pub struct ParserContext { + pub tokens: Vec, + pub cursor: usize, +} + +impl ParserContext { + pub fn new(tokens: Vec) -> ParserContext { + ParserContext { tokens, cursor: 0 } + } + + pub fn empty(&self) -> bool { + self.cursor == self.tokens.len() + } + + pub fn back(&mut self) { + self.cursor -= 1; + } + + pub fn next(&mut self) -> Option { + if self.cursor == self.tokens.len() { + return None; + } + + let token = self.tokens[self.cursor].clone(); + self.cursor += 1; + Some(token) + } + + pub fn peek(&self) -> Option { + if self.cursor == self.tokens.len() { + return None; + } + + Some(self.tokens[self.cursor].clone()) + } +} + +#[derive(Debug)] +pub enum Type { + Int, + Float, + Bigint, + Bool, + String, +} + +#[derive(Debug)] +pub struct Block { + pub value: Vec, + pub implicit_return: bool, +} + +#[derive(Debug)] +pub struct Argument { + pub name: String, + pub return_type: Type, +} + +#[derive(Debug)] +pub enum Ast { + Public { + value: Box, + }, + ConstantDeclaration { + name: String, + return_type: Type, + value: Box, + }, + VariableDeclaration { + name: String, + return_type: Type, + value: Box, + }, + Operation { + operator: Operator, + left: Box, + right: Box, + }, + Return { + return_value: Box, + }, + Function { + name: String, + arguments: Vec, + return_type: Type, + block: Block, + }, + FunctionCall { + name: String, + arguments: Vec, + }, + If { + condition: Box, + value: Block, + else_value: Option>, + }, + Block(Block), + Number(String), + Bool(bool), + String(String), + Identifier(String), + Comment(String), + DocComment(String), +} diff --git a/crates/cli/Cargo.lock b/crates/cli/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..bea6bbd39b14927d56ffb803015103f3cd74364f --- /dev/null +++ b/crates/cli/Cargo.lock @@ -0,0 +1,532 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "anstream" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "backtrace-ext" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537beee3be4a18fb023b570f80e3ae28003db9167a751266b259926e25539d50" +dependencies = [ + "backtrace", +] + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "blight" +version = "0.1.0" +dependencies = [ + "clap", + "miette", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "is-terminal" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys", +] + +[[package]] +name = "is_ci" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616cde7c720bb2bb5824a224687d8f77bfd38922027f01d825cd7453be5099fb" + +[[package]] +name = "libc" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "linux-raw-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "miette" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59bb584eaeeab6bd0226ccf3509a69d7936d148cf3d036ad350abe35e8c6856e" +dependencies = [ + "backtrace", + "backtrace-ext", + "is-terminal", + "miette-derive", + "once_cell", + "owo-colors", + "supports-color", + "supports-hyperlinks", + "supports-unicode", + "terminal_size", + "textwrap", + "thiserror", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "5.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e7bc1560b95a3c4a25d03de42fe76ca718ab92d1a22a55b9b4cf67b3ae635c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "proc-macro2" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd5e8a1f1029c43224ad5898e50140c2aebb1705f19e67c918ebf5b9e797fe1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22a37c9326af5ed140c86a46655b5278de879853be5573c01df185b6f49a580a" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustix" +version = "0.38.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "supports-color" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6398cde53adc3c4557306a96ce67b302968513830a77a95b2b17305d9719a89" +dependencies = [ + "is-terminal", + "is_ci", +] + +[[package]] +name = "supports-hyperlinks" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d" +dependencies = [ + "is-terminal", +] + +[[package]] +name = "supports-unicode" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6c2cb240ab5dd21ed4906895ee23fe5a48acdbd15a3ce388e7b62a9b66baf7" +dependencies = [ + "is-terminal", +] + +[[package]] +name = "syn" +version = "2.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d27c2c202598d05175a6dd3af46824b7f747f8d8e9b14c623f19fa5069735d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "terminal_size" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "textwrap" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2cd5904763bad08ad5513ddbb12cf2ae273ca53fa9f68e843e236ec6dfccc09" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..081c5f730700279570c4bfab7384d165da019b61 --- /dev/null +++ b/crates/cli/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "cli" +version = "0.1.0" +edition = "2021" + +[[bin]] +name = "blight" +path = "./src/main.rs" + +[dependencies] +clap.workspace = true +miette.workspace = true +thiserror.workspace = true + +tokenizer = { path = "../tokenizer" } +ast = { path = "../ast" } +js_printer = { path = "../js_printer" } diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..35a97b220d8865da2dfa990e4b0c2cb200fe0a5f --- /dev/null +++ b/crates/cli/src/main.rs @@ -0,0 +1,120 @@ +use std::path::PathBuf; + +use clap::{Parser, Subcommand}; +use miette::Result; + +use tokenizer; +use ast; +use js_printer; + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +struct Cli { + /// Turn debugging information on + #[arg(short, long, action = clap::ArgAction::Count)] + debug: u8, + + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + /// Compiles a file into javascript + Compile { + file: PathBuf, + // Whether to output to stdout instead of a file + #[arg(long, default_value_t = false)] + stdout: bool, + }, + Run { + file: PathBuf, + /// What javascript runtime to use + #[arg(short, long, default_value = "deno")] + runtime: String, + }, +} + +fn get_runtime(runtime: &String) -> String { + match std::env::var("USER") { + Ok(user) if user == "dave" => String::from("bun"), + _ => runtime.clone(), + } +} + + +pub fn transpile(content: String) -> Result { + // 1. Tokenize the input + let tokens = tokenizer::tokenize(content)?; + // 2. Parse the tokens into an AST + let blight_ast = ast::parse(tokens)?; + // 3. Type check the AST + // type_check(tree.clone())?; + // 4. Optimize the AST + // optimize(tree.clone())?; + // 5. Translate the AST into javascript + // translate(tree.clone())?; + // 6. Print the JS AST + let javascript = js_printer::transpile(blight_ast)?; + // 7. Return the javascript + return Ok(javascript); +} + + +fn main() -> Result<()> { + let cli = Cli::parse(); + + match cli.command { + Commands::Compile { file, stdout } => { + let contents = std::fs::read_to_string(file.clone()).unwrap(); + let result = transpile(contents.clone())?; + + if stdout { + println!("{}", result); + } else { + std::fs::write(file.with_extension("js"), result).unwrap(); + } + } + Commands::Run { file, runtime } => { + let contents = std::fs::read_to_string(file.clone()).unwrap(); + let result = transpile(contents.clone())?; + let mut temp_file = std::env::temp_dir(); + temp_file.push("temp.js"); + std::fs::write(temp_file.clone(), result).unwrap(); + + let rt = get_runtime(&runtime); + + match rt.as_str() { + "deno" => { + let output = std::process::Command::new("deno") + .arg("run") + .arg("-A") + .arg(temp_file) + .output() + .expect("Failed to execute process"); + println!("{}", String::from_utf8_lossy(&output.stdout)); + } + "node" => { + let output = std::process::Command::new("node") + .arg(temp_file) + .output() + .expect("Failed to execute process"); + println!("{}", String::from_utf8_lossy(&output.stdout)); + } + "bun" => { + let output = std::process::Command::new("bun") + .arg("run") + .arg(temp_file) + .output() + .expect("Failed to execute process"); + println!("{}", String::from_utf8_lossy(&output.stdout)); + } + _ => { + println!("Unknown runtime: {}", runtime); + } + } + } + } + + Ok(()) +} diff --git a/crates/js_ast/Cargo.toml b/crates/js_ast/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..c7f8ec140f6dcdd2810a7842a509e7fae4214bcd --- /dev/null +++ b/crates/js_ast/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "js_ast" +version = "0.1.0" +edition = "2021" + +[lib] + +[dependencies] +miette.workspace = true +thiserror.workspace = true diff --git a/crates/js_ast/src/lib.rs b/crates/js_ast/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/crates/js_printer/Cargo.toml b/crates/js_printer/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..6ba59bf96c3a398efd353cd18596d91d7eabcf4e --- /dev/null +++ b/crates/js_printer/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "js_printer" +version = "0.1.0" +edition = "2021" + +[lib] + +[dependencies] +miette.workspace = true +thiserror.workspace = true + +ast = { path = "../ast" } diff --git a/crates/js_printer/src/lib.rs b/crates/js_printer/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..13a4bd6d2c11f2aa0f7e0d7627b8c58ffc3ace47 --- /dev/null +++ b/crates/js_printer/src/lib.rs @@ -0,0 +1,139 @@ +use miette::Result; + +use ast::{Ast, Type}; + +fn transpile_helper(tree: &Ast) -> Result { + Ok(match tree { + Ast::Number(number) => format!("{}", number), + Ast::Identifier(name) => format!("{}", name), + Ast::Bool(value) => format!("{}", value), + Ast::String(value) => format!("\"{}\"", value), + Ast::Comment(comment) => format!("// {}\n", comment), + Ast::DocComment(comment) => format!("/** {} */\n", comment), + Ast::Operation { + operator, + left, + right, + } => format!( + "{} {} {}", + transpile_helper(left)?, + operator.clone().to_string(), + transpile_helper(right)? + ), + Ast::Public { value } => format!("export {}", transpile_helper(value)?), + Ast::VariableDeclaration { + name, + return_type, + value, + } => match return_type { + Type::Bigint => format!("let {} = BigInt({});\n", name, transpile_helper(value)?), + _ => format!("let {} = {};\n", name, transpile_helper(value)?), + }, + Ast::ConstantDeclaration { + name, + return_type, + value, + } => match return_type { + Type::Bigint => format!("const {} = BigInt({});\n", name, transpile_helper(value)?), + _ => format!("const {} = {};\n", name, transpile_helper(value)?), + }, + Ast::Return { return_value } => format!("return {};\n", transpile_helper(return_value)?), + Ast::Function { + name, + arguments, + return_type: _, + block, + } => { + let mut result = format!("function {}(", name); + + for (i, argument) in arguments.iter().enumerate() { + if i == 0 { + result += argument.name.as_str(); + } else { + result += format!(", {}", argument.name).as_str(); + } + } + + result += ") {\n"; + + for (i, statement) in block.value.iter().enumerate() { + if block.implicit_return && i == block.value.len() - 1 { + result += format!("return {};\n", transpile_helper(statement)?).as_str(); + break; + } + result += transpile_helper(statement)?.as_str(); + } + + result += "}\n"; + + result + } + Ast::If { + condition, + value, + else_value, + } => { + let mut result = format!("if ({}) {{\n", transpile_helper(condition)?,); + + for (i, statement) in value.value.iter().enumerate() { + if value.implicit_return && i == value.value.len() - 1 { + result += format!("return {};\n", transpile_helper(statement)?).as_str(); + break; + } + result += transpile_helper(statement)?.as_str(); + } + + result += "}"; + + if let Some(val) = else_value { + result += format!(" else {{\n{}}}", transpile_helper(val)?).as_str(); + } else { + result += "\n"; + } + + result + } + Ast::FunctionCall { name, arguments } => { + let mut result = match name.as_str() { + "print" => String::from("console.log("), + _ => format!("{}(", name), + }; + + for (i, argument) in arguments.iter().enumerate() { + if i == 0 { + result += transpile_helper(argument)?.as_str(); + } else { + result += format!(", {}", transpile_helper(argument)?).as_str(); + } + } + + result += ")"; + + result + } + Ast::Block(block) => { + let mut result = String::from("(()=>{\n"); + for (i, statement) in block.value.iter().enumerate() { + if block.implicit_return && i == block.value.len() - 1 { + result += format!("return {};\n", transpile_helper(statement)?).as_str(); + break; + } + result += transpile_helper(statement)?.as_str(); + } + + result += "})()\n"; + + result + } + }) +} + +pub fn transpile(forest: Vec) -> Result { + let mut result = String::new(); + + for tree in forest { + result.push_str(&transpile_helper(&tree)?); + } + + Ok(result) +} diff --git a/crates/tokenizer/Cargo.toml b/crates/tokenizer/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..21243ee5fc409f648340819f1b792d721c214741 --- /dev/null +++ b/crates/tokenizer/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "tokenizer" +version = "0.1.0" +edition = "2021" + +[lib] + +[dependencies] +miette.workspace = true +thiserror.workspace = true + +util = { path = "../util" } diff --git a/crates/tokenizer/src/lib.rs b/crates/tokenizer/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..85b4a6fe3443285dd78fe062f7ac5575a7057611 --- /dev/null +++ b/crates/tokenizer/src/lib.rs @@ -0,0 +1,199 @@ +use miette::{Diagnostic, Result}; +use thiserror::Error; + +use util::Operator; + +#[derive(Error, Diagnostic, Debug)] +#[error("UnknownCharacter")] +struct UnknownCharacter { + #[help] + error: String, +} + +#[derive(Debug, Clone)] +pub enum Token { + // Literals + Identifier(String), + Number(String), + String(String), + // Comments + Comment(String), + DocComment(String), + // Keywords + True, + False, + Let, + Var, + If, + Else, + Return, + Pub, + Function, + RightArrow, + Comma, + OpenParanthesis, + ClosedParanthesis, + OpenBracket, + ClosedBracket, + Colon, + Equals, + Semicolon, + // Operators + Operator(Operator), +} + +pub fn tokenize(content: String) -> Result> { + let mut tokens: Vec = Vec::new(); + let mut chars = content.chars().enumerate().peekable(); + + loop { + match chars.next() { + Some((_, c)) => match c { + 'a'..='z' | 'A'..='Z' | '_' => { + let mut current_token = String::new(); + current_token.push(c); + loop { + let c = chars.peek(); + if c.is_none() { + break; + } + let (_, c) = c.unwrap(); + match c { + 'a'..='z' | 'A'..='Z' | '_' | '0'..='9' => { + current_token.push(*c); + chars.next(); + } + _ => break, + } + } + + match current_token.as_str() { + "var" => tokens.push(Token::Var), + "let" => tokens.push(Token::Let), + "if" => tokens.push(Token::If), + "else" => tokens.push(Token::Else), + "pub" => tokens.push(Token::Pub), + "fn" => tokens.push(Token::Function), + "return" => tokens.push(Token::Return), + "true" => tokens.push(Token::True), + "false" => tokens.push(Token::False), + _ => tokens.push(Token::Identifier(current_token)), + } + } + '"' => { + let mut current_token = String::new(); + loop { + let c = chars.next(); + if c.is_none() { + break; + } + let (_, c) = c.unwrap(); + match c { + '"' => break, + _ => current_token.push(c), + } + } + tokens.push(Token::String(current_token)); + } + '0'..='9' => { + let mut current_token = String::new(); + current_token.push(c); + loop { + let c = chars.peek(); + if c.is_none() { + break; + } + let (_, c) = c.unwrap(); + match c { + '0'..='9' => { + current_token.push(*c); + chars.next(); + } + _ => break, + } + } + tokens.push(Token::Number(current_token)); + } + ':' => tokens.push(Token::Colon), + '=' => match chars.peek() { + Some((_, '=')) => { + chars.next(); + tokens.push(Token::Operator(Operator::Equals)); + } + _ => tokens.push(Token::Equals), + }, + ';' => tokens.push(Token::Semicolon), + '>' => tokens.push(Token::Operator(Operator::GreaterThan)), + '+' => tokens.push(Token::Operator(Operator::Add)), + '-' => match chars.peek() { + Some((_, '>')) => { + chars.next(); + tokens.push(Token::RightArrow); + } + _ => tokens.push(Token::Operator(Operator::Substract)), + }, + '*' => match chars.peek() { + Some((_, '*')) => { + chars.next(); + tokens.push(Token::Operator(Operator::Power)); + } + _ => tokens.push(Token::Operator(Operator::Multiply)), + }, + '/' => { + match chars.peek() { + Some((_, '/')) => { + chars.next(); // Consume the second slash + + let is_doc_comment = match chars.peek() { + Some((_, '/')) => { + chars.next(); // Consume the third slash + true + } + _ => false, + }; + + let mut comment = String::new(); + loop { + let c = chars.next(); + if c.is_none() { + break; + } + let (_, c) = c.unwrap(); + match c { + '\n' => break, + _ => { + comment.push(c.clone()); + } + } + } + + comment = comment.trim().to_string(); + + if is_doc_comment { + tokens.push(Token::DocComment(comment)); + } else { + tokens.push(Token::Comment(comment)); + } + } + _ => tokens.push(Token::Operator(Operator::Divide)), + } + } + ',' => tokens.push(Token::Comma), + '(' => tokens.push(Token::OpenParanthesis), + ')' => tokens.push(Token::ClosedParanthesis), + '{' => tokens.push(Token::OpenBracket), + '}' => tokens.push(Token::ClosedBracket), + s if s.is_whitespace() => (), + _ => { + return Err(UnknownCharacter { + error: format!("Unsupported character: {}", c), + } + .into()) + } + }, + None => break, + } + } + + Ok(tokens) +} diff --git a/crates/util/Cargo.toml b/crates/util/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..8729b70b0ce2b0b1139b6defbbcdee89deea81cc --- /dev/null +++ b/crates/util/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "util" +version = "0.1.0" +edition = "2021" + +[lib] + +[dependencies] diff --git a/crates/util/src/lib.rs b/crates/util/src/lib.rs new file mode 100644 index 0000000000000000000000000000000000000000..25de3ac1c7c30d6191678c51bb23193e298bd284 --- /dev/null +++ b/crates/util/src/lib.rs @@ -0,0 +1,24 @@ +#[derive(Debug, Clone)] +pub enum Operator { + Add, + Substract, + Multiply, + Divide, + Power, + Equals, + GreaterThan, +} + +impl Operator { + pub fn to_string(self) -> String { + String::from(match self { + Self::Add => "+", + Self::Substract => "-", + Self::Divide => "/", + Self::Multiply => "*", + Self::Power => "**", + Self::Equals => "===", + Self::GreaterThan => ">", + }) + } +}