From 89db9e8b1e986574685fe6398429a8174def08ae Mon Sep 17 00:00:00 2001 From: azur Date: Tue, 13 Dec 2022 23:02:41 +0700 Subject: [PATCH] :trollface: --- Cargo.lock | 136 +++++++----------- Cargo.toml | 11 +- README.md | 34 ----- build.sh | 61 -------- checker/Cargo.toml | 7 - checker/src/lib.rs | 1 - checker/src/syntax.rs | 0 codegen/Cargo.toml | 7 - codegen/src/lib.rs | 192 ------------------------- core/Cargo.toml | 11 -- core/src/main.rs | 48 ------- core/src/util.rs | 38 ----- examples/a.sial | 16 +++ examples/factorial.hz | 7 - examples/generics.hz | 6 - examples/ht.sial | 42 ++++++ examples/sim.sial | 8 ++ rust-toolchain.toml | 2 - rustfmt.toml | 1 + syntax/Cargo.toml | 7 - syntax/src/ast.rs | 111 --------------- syntax/src/lex.rs | 121 ---------------- syntax/src/lib.rs | 5 - syntax/src/mod.rs | 3 - syntax/src/parse.rs | 311 ----------------------------------------- transformer/Cargo.toml | 7 - transformer/src/lib.rs | 0 27 files changed, 121 insertions(+), 1072 deletions(-) delete mode 100644 README.md delete mode 100755 build.sh delete mode 100644 checker/Cargo.toml delete mode 100644 checker/src/lib.rs delete mode 100644 checker/src/syntax.rs delete mode 100644 codegen/Cargo.toml delete mode 100644 codegen/src/lib.rs delete mode 100644 core/Cargo.toml delete mode 100644 core/src/main.rs delete mode 100644 core/src/util.rs create mode 100644 examples/a.sial delete mode 100644 examples/factorial.hz delete mode 100644 examples/generics.hz create mode 100644 examples/ht.sial create mode 100644 examples/sim.sial delete mode 100644 rust-toolchain.toml create mode 100644 rustfmt.toml delete mode 100644 syntax/Cargo.toml delete mode 100644 syntax/src/ast.rs delete mode 100644 syntax/src/lex.rs delete mode 100644 syntax/src/lib.rs delete mode 100644 syntax/src/mod.rs delete mode 100644 syntax/src/parse.rs delete mode 100644 transformer/Cargo.toml delete mode 100644 transformer/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 582c937..c49ca3c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,14 +12,12 @@ dependencies = [ ] [[package]] -name = "atty" -version = "0.2.14" +name = "ariadne" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +checksum = "f1cb2a2046bea8ce5e875551f5772024882de0b540c7f93dfc5d6cf1ca8b030c" dependencies = [ - "hermit-abi", - "libc", - "winapi", + "yansi", ] [[package]] @@ -28,13 +26,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "checker" -version = "0.1.0" -dependencies = [ - "syntax", -] - [[package]] name = "chumsky" version = "0.8.0" @@ -45,28 +36,18 @@ dependencies = [ ] [[package]] -name = "codegen" +name = "compiler" version = "0.1.0" dependencies = [ - "syntax", -] - -[[package]] -name = "colored" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" -dependencies = [ - "atty", - "lazy_static", - "winapi", + "parser", + "vm", ] [[package]] name = "const-random" -version = "0.1.13" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f590d95d011aa80b063ffe3253422ed5aa462af4e9867d43ce8337562bac77c4" +checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e" dependencies = [ "const-random-macro", "proc-macro-hack", @@ -74,12 +55,12 @@ dependencies = [ [[package]] name = "const-random-macro" -version = "0.1.13" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "615f6e27d000a2bffbc7f2f6a8669179378fa27ee4d0a509e985dfc0a7defb40" +checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb" dependencies = [ "getrandom", - "lazy_static", + "once_cell", "proc-macro-hack", "tiny-keccak", ] @@ -91,10 +72,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] -name = "getrandom" -version = "0.2.6" +name = "entry" +version = "0.1.0" +dependencies = [ + "compiler", + "parser", + "vm", +] + +[[package]] +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ "cfg-if", "libc", @@ -102,49 +98,31 @@ dependencies = [ ] [[package]] -name = "hermit-abi" -version = "0.1.19" +name = "libc" +version = "0.2.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] +checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" [[package]] -name = "hzc" +name = "once_cell" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" + +[[package]] +name = "parser" version = "0.1.0" dependencies = [ - "checker", - "codegen", - "colored", - "syntax", + "ariadne", + "chumsky", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.124" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a41fed9d98f27ab1c6d161da622a4fa35e8a54a8adc24bbf3ddd0ef70b0e50" - [[package]] name = "proc-macro-hack" version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" -[[package]] -name = "syntax" -version = "0.1.0" -dependencies = [ - "chumsky", -] - [[package]] name = "tiny-keccak" version = "2.0.2" @@ -155,36 +133,20 @@ dependencies = [ ] [[package]] -name = "transformer" +name = "vm" version = "0.1.0" dependencies = [ - "syntax", + "fnv", ] [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] -name = "winapi" -version = "0.3.9" +name = "yansi" +version = "0.5.1" 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" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/Cargo.toml b/Cargo.toml index df87439..1e8b8fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,7 @@ [workspace] members = [ - "core", - "syntax", - "checker", - "transformer", - "codegen", -] \ No newline at end of file + "entry", + "parser", + "compiler", + "vm", +] diff --git a/README.md b/README.md deleted file mode 100644 index 654959d..0000000 --- a/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Hazure -Programming language that compiles to Typescript! - -Note: Everything in this project can be changed at anytime! (I'm still finding out what work best for lots of thing) if you have an idea, feel free to create an issues about it, or even create a PR! (I'd be very happy) - -# Prerequistie -- `node`/`deno` for running Typescript -- Rust (if you're going to build from source) -- (Optional) if you use Vim, you can get the syntax highlighting [here](https://github.com/azur1s/hazure.vim) - -# Installing -Currently there is only a build script on linux: -``` -$ curl -s https://raw.githubusercontent.com/azur1s/hazure/master/build.sh | bash -s -... -$ hzc --help -``` -or if you want to build in debug mode: -``` -curl -s https://raw.githubusercontent.com/azur1s/hazure/master/build.sh | bash -s d -... -$ hzc --help -``` - -# Contributing -Found a bug? Found a better way to do something? Make a pull request or tell me in the issues tab! Anything contributions helps :D - -Steps to build: -1) Clone this repo `https://github.com/azur1s/hazure.git` -2) Build executable `cargo build` -3) Try running some examples! `hzc compile path/to/file.hz` - -# License -Hazure is licensed under both [MIT license](https://github.com/azur1s/hazure/blob/master/LICENSE-MIT) and [Apache License](https://github.com/azur1s/hazure/blob/master/LICENSE-APACHE) diff --git a/build.sh b/build.sh deleted file mode 100755 index ed1160a..0000000 --- a/build.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env bash - -# Exit if subprocess return non-zero exit code -set -e - -# Log function -log () { - echo -e "\033[0;32m[LOG]\033[0m $1" -} -err () { - echo -e "\033[0;31m[ERR]\033[0m $1" -} - -# This will always be true unless there is -# missing executable that we need to use -install_pass=true - -# Check if $1 is installed -check_installed () { - if ! command -v $1 -h &> /dev/null - then - err "$1 is not installed" - if [ install_pass ]; then - install_pass=false - fi - fi -} - -check_installed cargo -check_installed git -check_installed deno # deno is required for running transpiled program - -# If all of the above is installed -if [ ! install_pass ]; then - exit 1 -fi -log "Dependencies is installed. Cloning..." - -rm -rf ~/.cache/hazure/build/ -git clone https://github.com/azur1s/hazure.git ~/.cache/hazure/build/ - -cd ~/.cache/hazure/build/ - -if [[ $1 == *"d"* ]]; then - log "Building in debug..." - cargo build - rm ~/bin/hzc -f - mv ~/.cache/hazure/build/target/debug/hzc ~/bin/hzc -else - log "Building..." - cargo build --release - rm ~/bin/hzc -f - mv ~/.cache/hazure/build/target/release/hzc ~/bin/hzc -fi - -log "Build done. Cleaning up..." - -rm -rf ~/.cache/hazure/build/ - -log "Done." -hzc -v diff --git a/checker/Cargo.toml b/checker/Cargo.toml deleted file mode 100644 index cab0fcd..0000000 --- a/checker/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "checker" -version = "0.1.0" -edition = "2021" - -[dependencies] -syntax = { path = "../syntax" } diff --git a/checker/src/lib.rs b/checker/src/lib.rs deleted file mode 100644 index a80cdbc..0000000 --- a/checker/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod syntax; \ No newline at end of file diff --git a/checker/src/syntax.rs b/checker/src/syntax.rs deleted file mode 100644 index e69de29..0000000 diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml deleted file mode 100644 index 02d27b1..0000000 --- a/codegen/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "codegen" -version = "0.1.0" -edition = "2021" - -[dependencies] -syntax = { path = "../syntax" } \ No newline at end of file diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs deleted file mode 100644 index 4d32b60..0000000 --- a/codegen/src/lib.rs +++ /dev/null @@ -1,192 +0,0 @@ -use syntax::{ast::*, lex::Span}; - -/// A struct that contains emitted code. -pub struct Codegen { - /// The emitted code. - /// When the codegen is done, this will be joined into a single string - pub emitted: Vec, - /// Finalized code in bytes - pub finalized: Vec, -} - -impl Default for Codegen { fn default() -> Self { Self::new() } } - -impl Codegen { - pub fn new() -> Codegen { - Codegen { emitted: Vec::new(), finalized: Vec::new() } - } - - /// Emit a string to the output. - pub fn emit>(&mut self, s: S) { - self.emitted.push(s.into()); - } - - pub fn gen(&mut self, ast: Vec<(Expr, Span)>) { - for (expr, _) in ast { - self.emit(self.gen_expr(&expr, true)); - } - } - - fn gen_expr(&self, expr: &Expr, semicolon: bool) -> String { - #[macro_export] - macro_rules! semicolon { () => { if semicolon { ";" } else { "" } }; } - - match expr { - Expr::Literal(lit) => self.gen_literal(&lit.0), - Expr::Identifier(name) => { format!("_{}{}", name.0, semicolon!()) }, - Expr::Tuple(elems) | Expr::Vector(elems) => { format!("[{}{}]", elems.iter().map(|e| self.gen_expr(&e.0, false)).collect::>().join(", "), semicolon!()) }, - Expr::Object { fields } => { - format!("{{{}}}", - fields.iter().map(|(name, expr)| format!("{}: {}", name.0, self.gen_expr(&expr.0, false))).collect::>().join(",\n ")) - }, - - Expr::Unary { op, rhs } => { format!("{}{}", op, self.gen_expr(&rhs.0, false)) }, - Expr::Binary { op, lhs, rhs } => { - format!("{}{}{}{}", self.gen_expr(&lhs.0, false), op, self.gen_expr(&rhs.0, false), semicolon!()) - }, - - Expr::Call { name, args } => { - format!( - "{}({}){}", - self.gen_expr(&name.0, false), - args - .iter() - .map(|arg| self.gen_expr(&arg.0, false)) - .collect::>() - .join(", "), - semicolon!()) - }, - Expr::Method { obj, name, args } => { - format!( - "{}.{}({}){}", - self.gen_expr(&obj.0, false), - self.gen_expr(&name.0, false).trim_start_matches('_'), - args - .iter() - .map(|arg| self.gen_expr(&arg.0, false)) - .collect::>() - .join(", "), - semicolon!()) - }, - Expr::Access { obj, name } => { - format!("{}.{}", self.gen_expr(&obj.0, false), self.gen_expr(&name.0, false).trim_start_matches('_')) - }, - Expr::Intrinsic { name, args } => { - if let Expr::Identifier(name) = &name.0 { - match name.0.as_str() { - "write" => { format!("console.log({})", args.iter().map(|arg| self.gen_expr(&arg.0, false)).collect::>().join(", ")) }, - _ => unimplemented!(), - } - } else { - panic!("Expected identifier for intrinsic name"); - } - }, - - Expr::Define { name, typehint, value } => { - format!( - "let _{} : {} = {}{}", - name.0, - self.gen_typehint(&typehint.0), - self.gen_expr(&value.0, false), - semicolon!()) - }, - Expr::Redefine { name, value } => { - format!( - "_{} = {}{}", - name.0, - self.gen_expr(&value.0, false), - semicolon!()) - }, - - Expr::Function { name, generics, args, typehint, body } => { - format!( - "const _{} = {}({}): {} => {{{}}}{}\n", - name.0, - if generics.is_empty() { "".to_string() } else { - format!("<{}>", - generics.iter().map(|g| g.0.clone()).collect::>().join(", ")) - }, - args - .iter() - .map(|arg| format!("_{}: {}", arg.0.0, self.gen_typehint(&arg.1.0))) - .collect::>() - .join(", "), - self.gen_typehint(&typehint.0), - self.gen_expr(&body.0, false), - semicolon!()) - }, - - Expr::If { cond, t, f } => { - format!( - "if ({}) {{{}}} else {{{}}}", - self.gen_expr(&cond.0, false), - self.gen_expr(&t.0, false), - self.gen_expr(&f.0, false)) - }, - - Expr::Do { body } => { - format!( - "{{\n{}}}\n", - body.0.iter().map(|e| self.gen_expr(&e.0, false)).collect::>().join("\n")) - }, - - Expr::Return(expr) => { - format!("return {}\n", self.gen_expr(&expr.0, true)) - }, - - #[allow(unreachable_patterns)] - _ => { dbg!(expr); todo!() }, - } - } - - fn gen_literal(&self, lit: &Literal) -> String { - match lit { - Literal::Int(i) => format!("{}", i), - Literal::String(s) => format!("\"{}\"", s), - Literal::Boolean(b) => format!("{}", b), - } - } - - fn gen_typehint(&self, typehint: &Typehint) -> String { - match typehint { - Typehint::Builtin(ty) => { - match ty { - BuiltinType::Any => "any", - BuiltinType::Null => "null", - BuiltinType::Undefined => "undefined", - BuiltinType::Boolean => "boolean", - BuiltinType::Int => "number", - BuiltinType::String => "string", - }.to_string() - }, - Typehint::Single(ty) => ty.clone(), - - Typehint::Tuple(tys) => format!("[{}]", tys - .iter() - .map(|ty| self.gen_typehint(&ty.0)).collect::>().join(", ")), - Typehint::Vector(ty) => format!("{}[]", self.gen_typehint(&ty.0)), - - Typehint::Function(args, ret) => { - let args_ty = args.iter().map(|arg| self.gen_typehint(&arg.0)).collect::>(); - let return_ty = self.gen_typehint(&ret.0); - format!( "({}) => {}", - args_ty - .iter() - .enumerate() - .map(|(i, arg)| format!("__{}: {}", i, arg)) // Maybe use this in the future - .collect::>() - .join(", "), - return_ty) - }, - - Typehint::Union(tys) => tys - .iter() - .map(|ty| self.gen_typehint(&ty.0)).collect::>().join(" | "), - } - } - - /// Finalize the code generation. - pub fn finalize(&mut self) { - self.finalized = self.emitted.join("\n").as_bytes().to_vec(); - } -} \ No newline at end of file diff --git a/core/Cargo.toml b/core/Cargo.toml deleted file mode 100644 index 69d4899..0000000 --- a/core/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "hzc" -version = "0.1.0" -edition = "2021" - -[dependencies] -syntax = { path = "../syntax" } -checker = { path = "../checker" } -codegen = { path = "../codegen" } - -colored = "2.0.0" \ No newline at end of file diff --git a/core/src/main.rs b/core/src/main.rs deleted file mode 100644 index bbbb5c4..0000000 --- a/core/src/main.rs +++ /dev/null @@ -1,48 +0,0 @@ -use std::{fs::File, io::Write}; - -use syntax::{lex::lex, parse::parse}; -use codegen::Codegen; - -pub mod util; - -fn main() { - let path = std::env::args().nth(1).expect("No file specified"); - let input = std::fs::read_to_string(path).expect("Failed to read file"); - - let time = std::time::Instant::now(); - - // - // Lex - // - let (tokens, lex_errs) = lex(input.to_string()); - - if !lex_errs.is_empty() { - println!("Lex error(s): {:#?}", lex_errs); - return; - } - - // - // Parse - // - let (ast, parse_errs) = parse(tokens.unwrap(), input.chars().count()); - - if !parse_errs.is_empty() || ast.is_none() { - println!("Parse error(s): {:#?}", parse_errs); - return; - } - - println!("{:#?}", ast.as_ref().unwrap()); - info!("Parsed in {}ms", time.elapsed().as_millis()); - - // - // Codegen - // - let mut codegen = Codegen::new(); - codegen.gen(ast.unwrap()); - codegen.finalize(); - - let mut file = File::create("out.ts").unwrap(); - file.write_all(&codegen.finalized).unwrap(); - - info!("Generated {} bytes in {} ms", codegen.finalized.len(), time.elapsed().as_millis()); -} diff --git a/core/src/util.rs b/core/src/util.rs deleted file mode 100644 index d7eab17..0000000 --- a/core/src/util.rs +++ /dev/null @@ -1,38 +0,0 @@ -use colored::Colorize; - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum LogLevel { Debug, Info, Warn, Error } - -fn prefix (level: LogLevel) -> String { - match level { - LogLevel::Debug => "DEBG ".bright_black(), - LogLevel::Info => "INFO ".blue(), - LogLevel::Warn => "WARN ".yellow(), - LogLevel::Error => "ERRO ".red(), - }.to_string() -} - -pub fn log >(level: LogLevel, message: S) { - println!("{}{}", prefix(level), message.into()); -} - -#[macro_export] -macro_rules! info { - ($($arg:tt)*) => { - $crate::util::log( $crate::util::LogLevel::Info, format!($($arg)*) ); - }; -} - -#[macro_export] -macro_rules! warn { - ($($arg:tt)*) => { - $crate::util::log( $crate::util::LogLevel::Warn, format!($($arg)*) ); - }; -} - -#[macro_export] -macro_rules! error { - ($($arg:tt)*) => { - $crate::util::log( $crate::util::LogLevel::Error, format!($($arg)*) ); - }; -} \ No newline at end of file diff --git a/examples/a.sial b/examples/a.sial new file mode 100644 index 0000000..7be7929 --- /dev/null +++ b/examples/a.sial @@ -0,0 +1,16 @@ +fun succ x = do + let one = 1 + let y = x + one in y +end + +fun double x = x * 2 + +fun main = do + let add = \x y -> x + y in + succ(34) + |> \x -> add(34, x) + |> \x -> println(x) + + let result = add(34, 35) + println(result) +end \ No newline at end of file diff --git a/examples/factorial.hz b/examples/factorial.hz deleted file mode 100644 index 961a323..0000000 --- a/examples/factorial.hz +++ /dev/null @@ -1,7 +0,0 @@ -factorial (n : int) : int = - if n == 0 - | return 1 - | return n * factorial(n - 1) - -result : int = factorial(5) -@write(result) \ No newline at end of file diff --git a/examples/generics.hz b/examples/generics.hz deleted file mode 100644 index 5f20345..0000000 --- a/examples/generics.hz +++ /dev/null @@ -1,6 +0,0 @@ -print T (x : T) : void = @write(x) - -a : int = 123 -print(a) -b : string = "Hello, World!" -print(b) \ No newline at end of file diff --git a/examples/ht.sial b/examples/ht.sial new file mode 100644 index 0000000..b582a2c --- /dev/null +++ b/examples/ht.sial @@ -0,0 +1,42 @@ +import http from "http" + +-- Define a custom type to represent a user +type User = + id: number, + name: string, +end + +-- Define a function to handle incoming HTTP requests +fun handle_request + req: http.IncomingMessage, + res: http.ServerResponse, += do + let user_id = req.url.split("/")[1] + let name = + match user_id + | 12345 -> Some("John Smith") + | 727 -> Some("Foo Bar") + else None + + match name + | Some name -> do + let user = User(user_id, name) + res.statusCode = 200 + res.setHeader("Content-Type", "application/json") + res.write(JSON.stringify(user)) + end + | None -> do + res.statusCode = 404 + res.write("User not found") + end + + res.end() +end + +fun main = do + let + port = 8080, + server = http.createServer(handle_request), + in + server.listen(port, fun -> println("HTTP server listening on port 8080")) +end diff --git a/examples/sim.sial b/examples/sim.sial new file mode 100644 index 0000000..43c7df4 --- /dev/null +++ b/examples/sim.sial @@ -0,0 +1,8 @@ +fun foo = \x -> x + +fun main = do + foo(1) + [1, 2, 3] + true + print("Hello, World") +end \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index 271800c..0000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "nightly" \ No newline at end of file diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..d4d3d50 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +version = "Two" \ No newline at end of file diff --git a/syntax/Cargo.toml b/syntax/Cargo.toml deleted file mode 100644 index 4c16812..0000000 --- a/syntax/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "syntax" -version = "0.1.0" -edition = "2021" - -[dependencies] -chumsky = "0.8.0" \ No newline at end of file diff --git a/syntax/src/ast.rs b/syntax/src/ast.rs deleted file mode 100644 index a4643c7..0000000 --- a/syntax/src/ast.rs +++ /dev/null @@ -1,111 +0,0 @@ -use std::fmt::Display; - -pub type Spanned = (T, std::ops::Range); - -#[derive(Clone, Debug)] -pub enum BuiltinType { - Any, Null, Undefined, - Boolean, Int, String, -} - -#[derive(Clone, Debug)] -pub enum Typehint { - Builtin(BuiltinType), - Single(String), - Tuple(Vec>), - Vector(Box>), - Function(Vec>, Box>), - Union(Vec>), -} - -#[derive(Clone, Debug)] -pub enum Literal { - Int(i64), - String(String), - Boolean(bool), -} - -#[derive(Clone, Debug)] -pub enum UnaryOp { Minus, Not } - -impl Display for UnaryOp { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - UnaryOp::Minus => write!(f, "-"), - UnaryOp::Not => write!(f, "!"), - } - } -} - -#[derive(Clone, Debug)] -pub enum BinaryOp { - Plus, Minus, Multiply, Divide, Modulus, - Equal, NotEqual, Less, Greater, -} - -impl Display for BinaryOp { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - BinaryOp::Plus => write!(f, "+"), - BinaryOp::Minus => write!(f, "-"), - BinaryOp::Multiply => write!(f, "*"), - BinaryOp::Divide => write!(f, "/"), - BinaryOp::Modulus => write!(f, "%"), - BinaryOp::Equal => write!(f, "==="), - BinaryOp::NotEqual => write!(f, "!=="), - BinaryOp::Less => write!(f, "<"), - BinaryOp::Greater => write!(f, ">"), - } - } -} - -#[derive(Clone, Debug)] -pub enum Expr { - Literal(Spanned), - Identifier(Spanned), - Tuple(Vec>), - Vector(Vec>), - Object { - fields: Vec<(Spanned, Spanned)>, - }, - - Unary { op: UnaryOp, rhs: Box> }, - Binary { op: BinaryOp, lhs: Box>, rhs: Box> }, - - Call { name: Box>, args: Vec> }, - Method { obj: Box>, name: Box>, args: Vec> }, - Access { obj: Box>, name: Box> }, - Intrinsic { name: Box>, args: Vec> }, - - Define { - name: Spanned, - typehint: Spanned, - value: Box> - }, - Redefine { - name: Spanned, - value: Box> - }, - Function { - name: Spanned, - generics: Vec>, - args: Vec<(Spanned, Spanned)>, - typehint: Spanned, - body: Box> - }, - - If { - cond: Box>, - t: Box>, - f: Box> - }, - Do { - body: Spanned>> - }, - - Return(Box>), -} - -#[derive(Clone, Debug)] -pub enum Stmt { -} \ No newline at end of file diff --git a/syntax/src/lex.rs b/syntax/src/lex.rs deleted file mode 100644 index 18c5b9f..0000000 --- a/syntax/src/lex.rs +++ /dev/null @@ -1,121 +0,0 @@ -use chumsky::prelude::*; - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum Delimiter { Paren, Bracket, Brace } - -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum Token { - // Keywords - KwFun, KwSet, - KwDo, KwEnd, - KwIf, - KwCase, KwOf, - KwReturn, - - // Literals - Int(i64), Boolean(bool), - String(String), Identifier(String), - - // Operators - Plus, Minus, Multiply, Divide, Modulus, - Not, Equal, NotEqual, Less, Greater, - Arrow, And, Or, - - // Symbols & Delimiters - Assign, Dot, Comma, Colon, Semicolon, At, Hash, - Open(Delimiter), Close(Delimiter), -} - -pub type Span = std::ops::Range; -pub fn lexer() -> impl Parser, Error = Simple> { - let int = text::int(10) - .map(|s: String| Token::Int(s.parse().unwrap())); - - let string = just('"') - .ignore_then(filter(|c| *c != '"').repeated()) - .then_ignore(just('"')) - .collect::() - .map(Token::String); - - let symbol = choice(( - just("->").to(Token::Arrow), - - just('+').to(Token::Plus), - just('-').to(Token::Minus), - just('*').to(Token::Multiply), - just('/').to(Token::Divide), - just('%').to(Token::Modulus), - - just('&').to(Token::And), - just('|').to(Token::Or), - - just("!=").to(Token::NotEqual), - just('!').or(just('¬')).to(Token::Not), - just("==").to(Token::Equal), - - just('<').to(Token::Less), - just('>').to(Token::Greater), - - just('=').to(Token::Assign), - just('.').to(Token::Dot), - just(',').to(Token::Comma), - just(':').to(Token::Colon), - just(';').to(Token::Semicolon), - just('@').to(Token::At), - just('#').to(Token::Hash), - )); - - let delim = choice(( - just('(').to(Token::Open(Delimiter::Paren)), - just(')').to(Token::Close(Delimiter::Paren)), - just('[').to(Token::Open(Delimiter::Bracket)), - just(']').to(Token::Close(Delimiter::Bracket)), - just('{').to(Token::Open(Delimiter::Brace)), - just('}').to(Token::Close(Delimiter::Brace)), - )); - - let keyword = text::ident().map(|s: String| match s.as_str() { - "true" => Token::Boolean(true), - "false" => Token::Boolean(false), - - "fun" => Token::KwFun, - "set" => Token::KwSet, - "do" => Token::KwDo, - "end" => Token::KwEnd, - "if" => Token::KwIf, - "case" => Token::KwCase, - "of" => Token::KwOf, - "return" => Token::KwReturn, - _ => Token::Identifier(s), - }); - - let token = int - .or(string) - .or(symbol) - .or(delim) - .or(keyword) - .recover_with(skip_then_retry_until([])); - - // let comment = just("--").then(take_until(just('\n'))).padded(); - let comment = just('-') - .then_ignore(just('{') - .ignore_then(none_of('}').ignored().repeated()) - .then_ignore(just("}-")) - .or(just('-').ignore_then(none_of('\n').ignored().repeated())) - ) - .padded() - .ignored() - .repeated(); - - token - .padded_by(comment) - .map_with_span(|token, span| (token, span)) - .padded() - .repeated() -} - -#[allow(clippy::type_complexity)] -pub fn lex(src: String) -> (Option)>>, Vec>) { - let (tokens, lex_error) = lexer().parse_recovery(src.as_str()); - (tokens, lex_error) -} \ No newline at end of file diff --git a/syntax/src/lib.rs b/syntax/src/lib.rs deleted file mode 100644 index 44709bd..0000000 --- a/syntax/src/lib.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![feature(trait_alias)] - -pub mod lex; -pub mod parse; -pub mod ast; \ No newline at end of file diff --git a/syntax/src/mod.rs b/syntax/src/mod.rs deleted file mode 100644 index dd22a03..0000000 --- a/syntax/src/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod lex; -pub mod parse; -pub mod ast; \ No newline at end of file diff --git a/syntax/src/parse.rs b/syntax/src/parse.rs deleted file mode 100644 index ffc2411..0000000 --- a/syntax/src/parse.rs +++ /dev/null @@ -1,311 +0,0 @@ -use super::{*, ast::*, lex::{Token, Delimiter}}; -use chumsky::{prelude::*, Stream}; - -pub trait P = chumsky::Parser> + Clone; - -fn identifier() -> impl P> { - filter_map(|span, token| match token { - Token::Identifier(s) => Ok((s, span)), - _ => Err(Simple::expected_input_found(span, Vec::new(), Some(token))), - }).labelled("identifier") -} - -fn literal() -> impl P> { - filter_map(|span, token| match token { - Token::Int(i) => Ok((ast::Literal::Int(i), span)), - Token::Boolean(b) => Ok((ast::Literal::Boolean(b), span)), - Token::String(s) => Ok((ast::Literal::String(s), span)), - _ => Err(Simple::expected_input_found(span, Vec::new(), Some(token))), - }).labelled("literal") -} - -fn typehint_parser() -> impl P> { - recursive(|ty| { - - let single = filter_map(|span, token| match token { - Token::Identifier(s) => Ok(( - match s.as_str() { - "any" => ast::Typehint::Builtin(ast::BuiltinType::Any), - "null" => ast::Typehint::Builtin(ast::BuiltinType::Null), - "undefined" => ast::Typehint::Builtin(ast::BuiltinType::Undefined), - "bool" => ast::Typehint::Builtin(ast::BuiltinType::Boolean), - "int" => ast::Typehint::Builtin(ast::BuiltinType::Int), - "string" => ast::Typehint::Builtin(ast::BuiltinType::String), - _ => Typehint::Single(s), - }, span)), - _ => Err(Simple::expected_input_found(span, Vec::new(), Some(token))), - }); - - let tuple = single - .separated_by(just(Token::Comma)) - .allow_trailing() - .delimited_by( - just(Token::Open(Delimiter::Paren)), - just(Token::Close(Delimiter::Paren))) - .map_with_span(|args, span| {( Typehint::Tuple(args), span )}); - - let vector = single - .delimited_by( - just(Token::Open(Delimiter::Bracket)), - just(Token::Close(Delimiter::Bracket))) - .map_with_span(|arg, span| {( Typehint::Vector(Box::new(arg)), span )}); - - let function = ty.clone() - .separated_by(just(Token::Comma)) - .allow_trailing() - .delimited_by( - just(Token::Or), - just(Token::Or)) - .then_ignore(just(Token::Arrow)) - .then(ty.clone()) - .map_with_span(|(args, ret), span| {( Typehint::Function(args, Box::new(ret)), span )}); - - let union_ty = ty.clone() - .separated_by(just(Token::Or)) - .allow_trailing() - .delimited_by( - just(Token::Open(Delimiter::Paren)), - just(Token::Close(Delimiter::Paren))) - .map_with_span(|args, span| {( Typehint::Union(args), span )}); - - single - .or(tuple) - .or(vector) - .or(function) - .or(union_ty) - }) -} - -fn expr_parser() -> impl P> { - recursive(|expr| { - - // Atom ::= Literal - // | Identifier - // | Vector - // | Tuple - // | Object - - let args = expr.clone().separated_by(just(Token::Comma)).allow_trailing(); - - let vec = args.clone().delimited_by( - just(Token::Open(Delimiter::Bracket)), - just(Token::Close(Delimiter::Bracket))) - .map_with_span(|args, span| {( Expr::Vector(args), span )}); - - let tuple = args.clone().delimited_by( - just(Token::Open(Delimiter::Paren)), - just(Token::Close(Delimiter::Paren))) - .map_with_span(|args, span| {( Expr::Tuple(args), span )}); - - let object = identifier() - .then_ignore(just(Token::Colon)) - .then(expr.clone()) - .separated_by(just(Token::Comma)) - .allow_trailing() - .delimited_by( - just(Token::Open(Delimiter::Brace)), - just(Token::Close(Delimiter::Brace))) - .map_with_span(|args, span| {( Expr::Object { fields: args }, span )}); - - let atom = literal().map_with_span(|literal, span| {( Expr::Literal(literal), span )}) - .or(identifier().map_with_span(|ident, span| {( Expr::Identifier(ident), span )})) - .or(vec) - .or(tuple) - .or(object) - .labelled("atom"); - - // Call ::= Identifier '(' ( Expr ( ',' Expr )* )? ')' - // Method ::= Identifier '.' Identifier ( '(' ( Expr ( ',' Expr )* )? ')' ) - // Access ::= Identifier '.' Idnetifier - // Intrinsic ::= '@' Call - // Unary ::= UnaryOp ( Call | Intrinsic ) - // Binary ::= Unary BinaryOp Unary - - let identexpr = identifier().map_with_span(|ident, span| {( Expr::Identifier(ident), span )}); - - let call = atom.clone() - .then( - args.clone().delimited_by( - just(Token::Open(Delimiter::Paren)), - just(Token::Close(Delimiter::Paren))) - .repeated()) - .foldl(|name, args| {( Expr::Call { name: Box::new(name.clone()), args }, name.1 )}).labelled("call"); - - let intrinsic = just(Token::At).ignore_then(atom.clone()) - .then( - args.clone().delimited_by( - just(Token::Open(Delimiter::Paren)), - just(Token::Close(Delimiter::Paren))) - .repeated()) - .foldl(|name, args| {( Expr::Intrinsic { name: Box::new(name.clone()), args }, name.1 )}).labelled("intrinsic"); - - let method = just(Token::Hash) - .ignore_then(identexpr.clone()) - .then_ignore(just(Token::Dot)) - .then(atom.clone()) - .then( - args.clone().delimited_by( - just(Token::Open(Delimiter::Paren)), - just(Token::Close(Delimiter::Paren))) - .repeated()) - .map_with_span(|((name, method), args), span| {( Expr::Method { - obj: Box::new(name), - name: Box::new(method), - args: args.into_iter().flatten().collect() - }, span )}).labelled("method"); - - let access = just(Token::Colon) - .ignore_then(identexpr) - .then_ignore(just(Token::Dot)) - .then(atom.clone()) - .map_with_span(|(obj, name), span| {( Expr::Access { obj: Box::new(obj), name: Box::new(name) }, span )}).labelled("access"); - - let unary = choice(( - just(Token::Minus).to(UnaryOp::Minus), - just(Token::Not).to(UnaryOp::Not))) - .repeated() - .then(call.or(intrinsic).or(method).or(access)) - .foldr(|op, rhs| {( Expr::Unary { op, rhs: Box::new(rhs.clone()) }, rhs.1 )}); - - let factor = unary.clone().then( - choice(( - just(Token::Multiply).to(BinaryOp::Multiply), - just(Token::Divide).to(BinaryOp::Divide), - just(Token::Modulus).to(BinaryOp::Modulus))) - .then(unary) - .repeated()) - .foldl(|lhs, (op, rhs)| {( - Expr::Binary { - lhs: Box::new(lhs), op, rhs: Box::new(rhs.clone()), - }, rhs.1)}); - - let term = factor.clone().then( - choice(( - just(Token::Plus).to(BinaryOp::Plus), - just(Token::Minus).to(BinaryOp::Minus))) - .then(factor) - .repeated()) - .foldl(|lhs, (op, rhs)| {( - Expr::Binary { - lhs: Box::new(lhs), op, rhs: Box::new(rhs.clone()), - }, rhs.1)}); - - let compare = term.clone().then( - choice(( - just(Token::Equal).to(BinaryOp::Equal), - just(Token::NotEqual).to(BinaryOp::NotEqual), - just(Token::Less).to(BinaryOp::Less), - just(Token::Greater).to(BinaryOp::Greater))) - .then(term) - .repeated()) - .foldl(|lhs, (op, rhs)| {( - Expr::Binary { - lhs: Box::new(lhs), op, rhs: Box::new(rhs.clone()), - }, rhs.1)}); - - // Do ::= 'do' Expr* 'end' - // Define ::= Identifier ':' Typehint '=' Expr - // Redefine ::= 'set' Identifier '=' Expr - // Function ::= 'fun' Identifier ( Identifier* ) '(' ( Identifier ':' Typehint ( ',' Identifier ':' Typehint )* )? ')' ':' Typehint '=' Expr - // If ::= 'if' Expr '|' Expr '|' Expr - // Return ::= 'return' Expr - // Note: This section's `Expr` might actually mean `Expr | Do` - - let do_block = expr.clone().repeated() - .delimited_by( - just(Token::KwDo), - just(Token::KwEnd)) - .map_with_span(|body, span| {( Expr::Do {body: (body, span.clone())}, span )}); - - let define = identifier() - // Type hint - .then(just(Token::Colon).ignore_then(typehint_parser())) - // Body - .then(just(Token::Assign).ignore_then(do_block.clone().or(expr.clone()))) - .map_with_span(|((ident, typehint), expr), span| { - (Expr::Define { name: *Box::new(ident), typehint, value: Box::new(expr) }, span) - }); - - let redefine = just(Token::KwSet) - .ignore_then(identifier()) - // Body - .then(just(Token::Assign).ignore_then(do_block.clone().or(expr.clone()))) - .map_with_span(|(ident, expr), span| { - (Expr::Redefine { name: *Box::new(ident), value: Box::new(expr) }, span) - }); - - let function = identifier() - // Generic - .then(identifier().repeated()) - // Arguments - .then( - identifier() - .then_ignore(just(Token::Colon)) - .then(typehint_parser()) - .delimited_by( - just(Token::Open(Delimiter::Paren)), - just(Token::Close(Delimiter::Paren))) - .repeated()) - // Return type hint - .then_ignore(just(Token::Colon)) - .then(typehint_parser()) - // Body - .then_ignore(just(Token::Assign)) - .then(do_block.clone().or(expr.clone())) - .map(|((((name, generics), args), typehint), body)| { - ( Expr::Function { - name: *Box::new(name), - generics, - args: args.into_iter().map(|(name, typehint)| { - (name, *Box::new(typehint)) - }).collect(), - typehint, - body: Box::new(body.clone()) }, body.1 )}); - - let if_else = just(Token::KwIf) - // Condition - .ignore_then(expr.clone()) - // True branch - .then_ignore(just(Token::Or)) - .then(do_block.clone().or(expr.clone())) - // False branch - .then_ignore(just(Token::Or)) - .then(do_block.clone().or(expr.clone())) - .map_with_span(|((cond, then), else_), span| { - (Expr::If { cond: Box::new(cond), t: Box::new(then), f: Box::new(else_) }, span) - }); - - let return_ = just(Token::KwReturn) - .ignore_then(expr.clone()) - .map_with_span(|expr, span| {( Expr::Return(Box::new(expr)), span )}); - - // Expr ::= Define - // | Redefine - // | Function - // | Do - // | Return - // | If - // | Binary - - define - .or(redefine) - .or(function) - .or(do_block) - .or(return_) - .or(if_else) - .or(compare) - }).labelled("expression") -} - -#[allow(clippy::type_complexity)] -pub fn parse(tokens: Vec<(Token, std::ops::Range)>, len: usize) -> (Option)>>, Vec>) { - let (ast, parse_error) = expr_parser() - .repeated() - .then_ignore(end()) - .parse_recovery(Stream::from_iter( - len..len + 1, - tokens.into_iter(), - )); - - (ast, parse_error) -} \ No newline at end of file diff --git a/transformer/Cargo.toml b/transformer/Cargo.toml deleted file mode 100644 index c45bc22..0000000 --- a/transformer/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "transformer" -version = "0.1.0" -edition = "2021" - -[dependencies] -syntax = { path = "../syntax" } \ No newline at end of file diff --git a/transformer/src/lib.rs b/transformer/src/lib.rs deleted file mode 100644 index e69de29..0000000