diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ea8c4bf7f35f6f77f75d92ad8ce8349f6e81ddba --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000000000000000000000000000000000..bea6bbd39b14927d56ffb803015103f3cd74364f --- /dev/null +++ b/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/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000000000000000000000000000000000..81fd7d6445b0e9f3835a06f4d171a165fa46f1cb --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "blight" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "4.4.12", features = ["derive"] } +miette = { version = "5.10.0", features = ["fancy"] } +thiserror = "1.0.53" diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..82fb15a15eaf91f9c3404d3cea62956c431dfe31 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Blight + +Blight sure is a programming language. diff --git a/examples/easy.blight b/examples/easy.blight new file mode 100644 index 0000000000000000000000000000000000000000..d54d5e36b65b6981e239ee87bb074f5aab481232 --- /dev/null +++ b/examples/easy.blight @@ -0,0 +1,3 @@ +var x: int = 0; +var y: float = 0; +var z: bigint = 0; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..578110b0fc2363d80b4af6eb0c20a4b69c972460 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,40 @@ +use std::path::PathBuf; + +use miette::{Result, NamedSource}; +use clap::{Parser, Subcommand}; + +mod 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 { + /// lists test values + file: PathBuf + }, +} + +fn main() -> Result<()> { + let cli = Cli::parse(); + + match cli.command { + Commands::Compile { file } => { + let contents = std::fs::read_to_string(file.clone()).unwrap(); + let result = transpile::transpile(contents.clone())?; + std::fs::write(file.with_extension("js"), result).unwrap(); + } + } + + Ok(()) +} diff --git a/src/transpile/ast.rs b/src/transpile/ast.rs new file mode 100644 index 0000000000000000000000000000000000000000..20923286fc1c33ec99c224493b8ccf56401f3a5c --- /dev/null +++ b/src/transpile/ast.rs @@ -0,0 +1,102 @@ +use miette::{Result, Diagnostic}; +use thiserror::Error; + +use super::tokenizer::Token; +use super::util::PeekableIterator; + +#[derive(Error, Diagnostic, Debug)] +#[error("AstError")] +struct AstError { + #[help] + error: String +} + +impl AstError { + fn new(error: &'static str) -> AstError { + AstError { error: String::from(error) } + } +} + +#[derive(Debug)] +pub enum Type { + Int, + Float, + Bigint +} + +#[derive(Debug)] +pub enum Ast { + VariableDeclaration { + name: String, + typ: Type, + value: Box + }, + Number(String), +} + +fn parse_expression(tokens: &mut dyn PeekableIterator) -> Result { + match tokens.next() { + Some(token) => match token { + Token::Number(number) => Token::Number(number.clone()), + _ => return Err(AstError::new("Expected expression, but did not get it").into()) + }, + None => return Err(AstError::new("Expected expression, but got nothing instead").into()) + + }; + Ok(Ast::Number(String::from("10"))) +} + +/// Precondition: There is at least one token in the iterator +fn parse_statement(tokens: &mut dyn PeekableIterator) -> Result { + match tokens.next().unwrap() { + Token::Var => { + let name = match tokens.next() { + Some(Token::Identifier(name)) => name, + _ => return Err(AstError::new("Expected identifier after var").into()) + }; + let typ = match tokens.next() { + Some(Token::Colon) => { + match tokens.next() { + Some(Token::Identifier(typ)) => { + match typ.as_str() { + "int" => Type::Int, + "float" => Type::Float, + "bigint" => Type::Bigint, + _ => return Err(AstError::new("Expected type after colon").into()) + } + }, + _ => return Err(AstError::new("Expected type after colon").into()) + } + }, + _ => 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(), + typ, + value: Box::new(value), + }) + }, + Token::Number(number) => Ok(Ast::Number(number.clone())), + _ => return Err(AstError::new("Unexpected token").into()) + } +} + + +pub fn parse(tokens: Vec) -> Result> { + let mut iter = tokens.iter().peekable(); + let mut ast: Vec = Vec::new(); + + while iter.peek().is_some() { + ast.push(parse_statement(&mut iter)?); + } + + Ok(ast) +} diff --git a/src/transpile/mod.rs b/src/transpile/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..cd1b4299d1fa893eed5378d1b4b40c556f101790 --- /dev/null +++ b/src/transpile/mod.rs @@ -0,0 +1,19 @@ +use miette::{Result}; + +mod tokenizer; +mod ast; +mod walker; + +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)?; + print!("{:?}", tree); + // 3. Transpile the AST into javascript + let result = walker::transpile(tree); + // 4. Return the javascript + return Ok(result); +} diff --git a/src/transpile/tokenizer.rs b/src/transpile/tokenizer.rs new file mode 100644 index 0000000000000000000000000000000000000000..d5cc33087f4eca2f4b86b704178b751866b12fbf --- /dev/null +++ b/src/transpile/tokenizer.rs @@ -0,0 +1,101 @@ +use miette::{Result, Diagnostic}; +use thiserror::Error; + +#[derive(Error, Diagnostic, Debug)] +#[error("UnknownCharacter")] +struct UnknownCharacter { + #[help] + error: String +} + +#[derive(Debug, Clone)] +pub enum Operator { + Add, + Substract, + Multiply, + Divide, +} + +#[derive(Debug, Clone)] +pub enum Token { + // Literals + Identifier(String), + Number(String), + // Keywords + Var, + 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((i, 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), + _ => tokens.push(Token::Identifier(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), + '=' => tokens.push(Token::Equals), + ';' => tokens.push(Token::Semicolon), + '+' => tokens.push(Token::Operator(Operator::Add)), + '-' => tokens.push(Token::Operator(Operator::Substract)), + '*' => tokens.push(Token::Operator(Operator::Multiply)), + '/' => tokens.push(Token::Operator(Operator::Divide)), + s if s.is_whitespace() => (), + _ => { + return Err(UnknownCharacter { error: format!("Unsupported character: {}", c)}.into()) + } + } + } + None => break, + } + } + + Ok(tokens) +} diff --git a/src/transpile/util.rs b/src/transpile/util.rs new file mode 100644 index 0000000000000000000000000000000000000000..6c14555c0d66cb65392181a00798fd2a90d6e332 --- /dev/null +++ b/src/transpile/util.rs @@ -0,0 +1,11 @@ +// Rust why do you not have a peekable iterator in the standard library? +// Stolen from https://users.rust-lang.org/t/peekable-argument-there-has-to-be-a-simpler-way/6959 +pub trait PeekableIterator : std::iter::Iterator { + fn peek(&mut self) -> Option<&Self::Item>; +} + +impl PeekableIterator for std::iter::Peekable { + fn peek(&mut self) -> Option<&Self::Item> { + std::iter::Peekable::peek(self) + } +} diff --git a/src/transpile/walker.rs b/src/transpile/walker.rs new file mode 100644 index 0000000000000000000000000000000000000000..368619b2a5f8007016126864428f6aee5e8b4b0d --- /dev/null +++ b/src/transpile/walker.rs @@ -0,0 +1,23 @@ +use super::ast::{Ast, Type}; + +fn transpile_helper(tree: Ast) -> String { + match tree { + Ast::Number(number) => format!("{}", number), + Ast::VariableDeclaration { name, typ, value } => { + match typ { + Type::Bigint => format!("let {} = BigInt({});\n", name, transpile_helper(*value)), + _ => format!("let {} = {};\n", name, transpile_helper(*value)) + } + }, + } +} + +pub fn transpile(forest: Vec) -> String { + let mut result = String::new(); + + for tree in forest { + result.push_str(&transpile_helper(tree)); + } + + result +}