From c061c6d038b2e0a31c68a3cb5e112aa015097aeb Mon Sep 17 00:00:00 2001 From: azur Date: Sat, 4 Mar 2023 23:20:43 +0700 Subject: [PATCH] allow let without body --- Cargo.lock | 313 ++++++++++++++++++++++++++++++++++++++++++++++ a.hlm | 14 +-- src/asts/ast.rs | 31 ++--- src/asts/js.rs | 46 ++++--- src/asts/past.rs | 4 +- src/read/parse.rs | 11 +- src/trans/low.rs | 54 +++++--- 7 files changed, 407 insertions(+), 66 deletions(-) create mode 100644 Cargo.lock diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..fc0cd4f --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,313 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chumsky" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23170228b96236b5a7299057ac284a321457700bc8c41a4476052f0f4ba5349d" +dependencies = [ + "hashbrown", + "stacker", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[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.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "quote" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "renxi" +version = "0.1.0" +dependencies = [ + "chumsky", + "structopt", +] + +[[package]] +name = "stacker" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "winapi", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "unicode-ident" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775c11906edafc97bc378816b94585fbd9a054eabaf86fdd0ced94af449efab7" + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[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" diff --git a/a.hlm b/a.hlm index f46b3ec..abdc8fd 100644 --- a/a.hlm +++ b/a.hlm @@ -1,9 +1,7 @@ -func add (x: num) num = (\a: num -> a + 1)(x); +let x: num = 34, + y: num = 35 +in + println(x + y); -println( - { - println("Hello"); - return let x: num = 17 * 2 in - add(x); - } + 34 -); \ No newline at end of file +let foo: num = 69; +println(foo); \ No newline at end of file diff --git a/src/asts/ast.rs b/src/asts/ast.rs index 0f58700..d58b46f 100644 --- a/src/asts/ast.rs +++ b/src/asts/ast.rs @@ -16,7 +16,7 @@ pub enum BinaryOp { #[derive(Clone, Debug)] pub enum Literal { - Num(i64), Str(String), Bool(bool), + Num(i64), Str(String), Bool(bool), Unit, } /// Enum to represent internal expression @@ -31,19 +31,19 @@ pub enum Expr { Call(Box, Vec), Lambda { - args: Vec<(String, Type)>, + args: Vec, body: Vec, }, + Defines(Vec<(String, Self)>), Return(Box), } #[derive(Clone, Debug)] pub enum Stmt { Expr(Expr), - Let(Vec<(String, Type, Expr)>), Func { name: String, - args: Vec<(String, Type)>, + args: Vec, ret: Type, body: Expr, }, @@ -56,6 +56,7 @@ impl Display for Expr { Literal::Num(n) => write!(f, "{}", n), Literal::Str(s) => write!(f, "\"{}\"", s), Literal::Bool(b) => write!(f, "{}", b), + Literal::Unit => write!(f, "()"), }, Expr::Sym(s) => write!(f, "{}", s), Expr::Vec(v) => { @@ -79,8 +80,8 @@ impl Display for Expr { }, Expr::Lambda { args, body } => { write!(f, "(lambda ")?; - for (name, ty) in args { - write!(f, "[{} {}]", name, ty)?; + for arg in args { + write!(f, " {}", arg)?; } if body.len() == 1 { write!(f, " {})", body[0]) @@ -92,6 +93,13 @@ impl Display for Expr { write!(f, "))") } }, + Expr::Defines(defs) => { + write!(f, "(defs ")?; + for (name, expr) in defs { + write!(f, "({} {})", name, expr)?; + } + write!(f, ")") + }, Expr::Return(e) => write!(f, "(return {})", e), } } @@ -101,17 +109,10 @@ impl Display for Stmt { fn fmt(&self, f: &mut Formatter) -> FmtResult { match self { Stmt::Expr(e) => write!(f, "{}", e), - Stmt::Let(vars) => { - write!(f, "(let")?; - for (name, ty, e) in vars { - write!(f, " [{} {} {}]", name, ty, e)?; - } - write!(f, ")") - }, Stmt::Func { name, args, ret, body } => { write!(f, "(defn {} [", name)?; - for (name, ty) in args { - write!(f, "[{} {}]", name, ty)?; + for name in args { + write!(f, " {}", name)?; } write!(f, "] {} {})", ret, body) }, diff --git a/src/asts/js.rs b/src/asts/js.rs index dffe879..49b6385 100644 --- a/src/asts/js.rs +++ b/src/asts/js.rs @@ -2,7 +2,7 @@ use std::fmt::{Display, Formatter, Result as FmtResult}; use crate::trans::ty::Type; #[derive(Clone, Debug)] -pub enum JSLiteral { Num(i64), Str(String), Bool(bool) } +pub enum JSLiteral { Num(i64), Str(String), Bool(bool), Undefined } /// Enum to represent javascript expression #[derive(Clone, Debug)] @@ -16,19 +16,19 @@ pub enum JSExpr { Call(Box, Vec), Method(Box, String, Vec), Lambda { - args: Vec<(String, Type)>, + args: Vec, body: Vec, }, + Defines(Vec<(String, Self)>), Return(Box), } #[derive(Clone, Debug)] pub enum JSStmt { Expr(JSExpr), - Let(Vec<(String, Type, JSExpr)>), Func { name: String, - args: Vec<(String, Type)>, + args: Vec, ret: Type, body: JSExpr, }, @@ -38,9 +38,10 @@ impl Display for JSExpr { fn fmt(&self, f: &mut Formatter) -> FmtResult { match self { JSExpr::Lit(l) => match l { - JSLiteral::Num(n) => write!(f, "{}", n), - JSLiteral::Str(s) => write!(f, "'{}'", s), - JSLiteral::Bool(b) => write!(f, "{}", b), + JSLiteral::Num(n) => write!(f, "{}", n), + JSLiteral::Str(s) => write!(f, "'{}'", s), + JSLiteral::Bool(b) => write!(f, "{}", b), + JSLiteral::Undefined => write!(f, "undefined"), }, JSExpr::Sym(s) => write!(f, "{}", s), JSExpr::Array(v) => { @@ -81,7 +82,7 @@ impl Display for JSExpr { }, JSExpr::Lambda { args, body } => { write!(f, "((")?; - for (i, (name, _ty)) in args.iter().enumerate() { + for (i, name) in args.iter().enumerate() { if i > 0 { write!(f, ", ")?; } @@ -98,6 +99,23 @@ impl Display for JSExpr { write!(f, "}})") } }, + JSExpr::Defines(vs) => { + write!(f, "let [")?; + for (i, (name, _)) in vs.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{}", name)?; + } + write!(f, "] = [")?; + for (i, (_, expr)) in vs.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{}", expr)?; + } + write!(f, "]") + } JSExpr::Return(e) => write!(f, "return {}", e), } } @@ -107,20 +125,10 @@ impl Display for JSStmt { fn fmt(&self, f: &mut Formatter) -> FmtResult { match self { JSStmt::Expr(e) => write!(f, "{}", e), - JSStmt::Let(vars) => { - write!(f, "let ")?; - for (i, (name, _ty, e)) in vars.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - write!(f, "{} = {}", name, e)?; - } - write!(f, ";") - }, JSStmt::Func { name, args, ret: _, body } => { // const name = (args) => body; write!(f, "const {} = (", name)?; - for (i, (name, _ty)) in args.iter().enumerate() { + for (i, name) in args.iter().enumerate() { if i > 0 { write!(f, ", ")?; } diff --git a/src/asts/past.rs b/src/asts/past.rs index 1c4bf6b..c2c0942 100644 --- a/src/asts/past.rs +++ b/src/asts/past.rs @@ -16,7 +16,7 @@ pub enum PBinaryOp { } #[derive(Clone, Debug)] -pub enum PLiteral { Num(i64), Str(String), Bool(bool) } +pub enum PLiteral { Num(i64), Str(String), Bool(bool), Unit } #[derive(Clone, Debug)] pub enum PExpr { @@ -36,7 +36,7 @@ pub enum PExpr { }, Let { vars: Vec<(String, Type, Spanned)>, - body: Box>, + body: Option>>, }, Block(Vec>), Return(Box>), diff --git a/src/read/parse.rs b/src/read/parse.rs index 4e83033..60942d9 100644 --- a/src/read/parse.rs +++ b/src/read/parse.rs @@ -295,10 +295,16 @@ pub fn expr_parser() -> impl P> { .then(expr.clone()) .map(|(vars, body)| PExpr::Let { vars, - body: Box::new(body), + body: Some(Box::new(body)), }) .boxed() - .labelled("let..in"); + .labelled("let with expression"); + + let let_def = just(Token::Let) + .ignore_then(let_binds) + .map(|vars| PExpr::Let { vars, body: None }) + .boxed() + .labelled("let definition"); let block = nested_parser( expr.clone() @@ -322,6 +328,7 @@ pub fn expr_parser() -> impl P> { .or(paren_expr) .or(lam) .or(let_in) + .or(let_def) .or(block) .or(ret) .map_with_span(|e, s| (e, s)) diff --git a/src/trans/low.rs b/src/trans/low.rs index 74bc36a..daffbf5 100644 --- a/src/trans/low.rs +++ b/src/trans/low.rs @@ -10,13 +10,21 @@ pub fn translate_stmt(stmt: PStmt) -> Stmt { PStmt::Let(vars) => todo!(), PStmt::Func { name, args, ret, body } => Stmt::Func { name, - args, + args: args.into_iter().map(|(name, _ty)| name).collect(), ret, body: translate_expr(body.0), }, } } +pub fn exprs_to_lam(es: Vec) -> Expr { + let lam = Expr::Lambda { + args: vec![], + body: es.into_iter().map(|e| translate_expr(e)).collect(), + }; + Expr::Call(Box::new(lam), vec![]) +} + pub fn translate_expr(expr: PExpr) -> Expr { match expr { PExpr::Error => panic!("Error in expression!"), @@ -25,6 +33,7 @@ pub fn translate_expr(expr: PExpr) -> Expr { PLiteral::Num(n) => Literal::Num(n), PLiteral::Str(s) => Literal::Str(s), PLiteral::Bool(b) => Literal::Bool(b), + PLiteral::Unit => Literal::Unit, }), PExpr::Sym(s) => Expr::Sym(s), PExpr::Vec(v) => Expr::Vec(v.into_iter().map(|e| translate_expr(e.0)).collect()), @@ -61,30 +70,32 @@ pub fn translate_expr(expr: PExpr) -> Expr { args.into_iter().map(|a| translate_expr(a.0)).collect(), ), PExpr::Lambda { args, body } => Expr::Lambda { - args, + args: args.into_iter().map(|(name, _ty)| name).collect(), body: vec![translate_expr((*body).0)], }, PExpr::Let { vars, body } => { - let mut expr: Expr = translate_expr(body.0); // The expression we're building up - for (name, ty, val) in vars.into_iter().rev() { // Reverse so we can build up the lambda - // e.g.: let x : t = e1 in e2; => (lambda (x : t) = e2)(e1) - // Build up the lambda - expr = Expr::Lambda { - args: vec![(name, ty)], - body: vec![expr], - }; - // Call the lambda with the value - let val = translate_expr(val.0); - expr = Expr::Call(Box::new(expr), vec![val]); + if let Some(body) = body { + let mut expr: Expr = translate_expr(body.0); // The expression we're building up + for (name, _ty, val) in vars.into_iter().rev() { // Reverse so we can build up the lambda + // e.g.: let x : t = e1 in e2; => (lambda (x : t) = e2)(e1) + // Build up the lambda + expr = Expr::Lambda { + args: vec![name], + body: vec![expr], + }; + // Call the lambda with the value + let val = translate_expr(val.0); + expr = Expr::Call(Box::new(expr), vec![val]); + } + expr + } else { + Expr::Defines(vars.into_iter().map(|(name, _ty, val)| { + (name, translate_expr(val.0)) + }).collect()) } - expr }, PExpr::Block(es) => { - let lam = Expr::Lambda { - args: vec![], - body: es.into_iter().map(|e| translate_expr(e.0)).collect(), - }; - Expr::Call(Box::new(lam), vec![]) + exprs_to_lam(es.into_iter().map(|e| e.0).collect()) }, PExpr::Return(e) => Expr::Return(Box::new(translate_expr((*e).0))), } @@ -93,7 +104,6 @@ pub fn translate_expr(expr: PExpr) -> Expr { pub fn translate_js_stmt(stmt: Stmt) -> JSStmt { match stmt { Stmt::Expr(e) => JSStmt::Expr(translate_js_expr(e)), - Stmt::Let(vars) => todo!(), Stmt::Func { name, args, ret, body } => JSStmt::Func { name, args, @@ -109,6 +119,7 @@ pub fn translate_js_expr(expr: Expr) -> JSExpr { Literal::Num(n) => JSExpr::Lit(JSLiteral::Num(n)), Literal::Str(s) => JSExpr::Lit(JSLiteral::Str(s)), Literal::Bool(b) => JSExpr::Lit(JSLiteral::Bool(b)), + Literal::Unit => JSExpr::Lit(JSLiteral::Undefined), }, Expr::Sym(s) => JSExpr::Sym(s), Expr::Vec(v) => JSExpr::Array(v.into_iter().map(translate_js_expr).collect()), @@ -162,6 +173,9 @@ pub fn translate_js_expr(expr: Expr) -> JSExpr { args, body: body.into_iter().map(translate_js_expr).collect(), }, + Expr::Defines(defs) => JSExpr::Defines(defs.into_iter().map(|(name, val)| { + (name, translate_js_expr(val)) + }).collect()), Expr::Return(e) => JSExpr::Return(Box::new(translate_js_expr(*e))), } } \ No newline at end of file