diff --git a/b.hlm b/b.hlm index aa8e810..b3223e5 100644 --- a/b.hlm +++ b/b.hlm @@ -1,4 +1,12 @@ println((\x: num -> x + 35)(34)); -16---1*3/-f(16)+8%-2; +16---1*3/-16+8%-2; -a(b, c(d(e, f), g(h), i), j(k, l), m); \ No newline at end of file +let a: num = 1 in + println(a); + +let b: num = 1; +let x: num = 34, y: num = 35; + +let c: num = 5 in + let d: num = 10, e: num = 2 in + println(c * d + b - 2); \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index b498337..d5d71e7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -39,7 +39,8 @@ fn main() { let jsexprs = nexprs.into_iter().map(translate_js).collect::>(); for expr in &jsexprs { - println!("{}", expr); + let s = format!("{}", expr); + println!("{}{}", s, if s.ends_with(';') { "" } else { ";" }); } println!(); } diff --git a/src/read/parse.rs b/src/read/parse.rs index 23f57fc..c34a196 100644 --- a/src/read/parse.rs +++ b/src/read/parse.rs @@ -20,7 +20,7 @@ pub enum Token { Open(Delim), Close(Delim), Lambda, Arrow, - Let, Func, + Let, In, Func, } impl Display for Token { @@ -64,6 +64,7 @@ impl Display for Token { Token::Arrow => write!(f, "->"), Token::Let => write!(f, "let"), + Token::In => write!(f, "in"), Token::Func => write!(f, "func"), } } @@ -121,6 +122,7 @@ pub fn lexer() -> impl Parser, Error = Simple> { "true" => Token::Bool(true), "false" => Token::Bool(false), "let" => Token::Let, + "in" => Token::In, "func" => Token::Func, _ => Token::Sym(s), }); @@ -275,11 +277,42 @@ pub fn expr_parser() -> impl P> { }) .labelled("lambda"); + let let_binds = symbol_parser() + .then_ignore(just(Token::Colon)) + .then(type_parser()) + .then_ignore(just(Token::Assign)) + .then(expr.clone()) + .map(|((sym, ty), body)| (sym, ty, body)) + .separated_by(just(Token::Comma)) + .allow_trailing() + .labelled("let bindings"); + + let let_in = just(Token::Let) + .ignore_then(let_binds.clone()) + .then_ignore(just(Token::In)) + .then(expr.clone()) + .map(|(vars, body)| PExpr::Let { + vars, + body: Some(Box::new(body)), + }) + .boxed() + .labelled("let..in"); + + let let_def = just(Token::Let) + .ignore_then(let_binds) + .map(|vars| PExpr::Let { + vars, + body: None, + }) + .labelled("let"); + let atom = lit .or(sym) .or(vec) .or(paren_expr) .or(lam) + .or(let_in) + .or(let_def) .map_with_span(|e, s| (e, s)) .boxed() .labelled("atom"); diff --git a/src/read/past.rs b/src/read/past.rs index adf9323..0adc159 100644 --- a/src/read/past.rs +++ b/src/read/past.rs @@ -36,7 +36,7 @@ pub enum PExpr { body: Box>, }, Let { - vars: Vec<(String, Type, Self)>, - body: Box, + vars: Vec<(String, Type, Spanned)>, + body: Option>>, }, } \ No newline at end of file diff --git a/src/trans/ast.rs b/src/trans/ast.rs index c3b4442..98c20a0 100644 --- a/src/trans/ast.rs +++ b/src/trans/ast.rs @@ -34,6 +34,7 @@ pub enum Expr { args: Vec<(String, Type)>, body: Box, }, + Define(Vec<(String, Box)>), } impl Display for Expr { @@ -71,6 +72,11 @@ impl Display for Expr { } write!(f, " {})", body) }, + Expr::Define(vars) => { + vars.iter().try_for_each(|(name, val)| { + write!(f, "(define {} {})", name, val) + }) + }, } } } \ No newline at end of file diff --git a/src/trans/js.rs b/src/trans/js.rs index 9329cfe..e55e7a6 100644 --- a/src/trans/js.rs +++ b/src/trans/js.rs @@ -19,6 +19,7 @@ pub enum JSExpr { args: Vec<(String, Type)>, body: Box, }, + Let(Vec<(String, Box)>), } impl Display for JSExpr { @@ -76,6 +77,11 @@ impl Display for JSExpr { } write!(f, ") => {})", body) }, + JSExpr::Let(vars) => { + vars.iter().try_for_each(|(name, expr)| { + write!(f, "let {} = {};", name, expr) + }) + }, } } } \ No newline at end of file diff --git a/src/trans/low.rs b/src/trans/low.rs index 427e728..3179fdf 100644 --- a/src/trans/low.rs +++ b/src/trans/low.rs @@ -52,21 +52,34 @@ pub fn translate_expr(expr: PExpr) -> Expr { body: Box::new(translate_expr((*body).0)), }, PExpr::Let { vars, body } => { - let mut expr: Expr = translate_expr(*body); // 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 end => (lambda (x : t) = e2)(e1) + 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, ty)], - body: Box::new(expr), - }; - // Call the lambda with the value - let val = translate_expr(val); - expr = Expr::Call(Box::new(expr), vec![val]); + // Build up the lambda + expr = Expr::Lambda { + args: vec![(name, ty)], + body: Box::new(expr), + }; + // Call the lambda with the value + let val = translate_expr(val.0); + expr = Expr::Call(Box::new(expr), vec![val]); + } + + expr + } else { + // e.g. let a : t = 1; => (define a 1) + // let a : t = 2, b : t = 3; => (define a 2) (define b 3) + let mut xs: Vec<(String, Box)> = vec![]; + + for (name, _, val) in vars { + let val = translate_expr(val.0); + xs.push((name, Box::new(val))); + } + + Expr::Define(xs) } - - expr } } } @@ -130,5 +143,13 @@ pub fn translate_js(expr: Expr) -> JSExpr { args, body: Box::new(translate_js(*body)), }, + Expr::Define(xs) => { + let ns = xs + .into_iter() + .map(|(name, val)| (name, Box::new(translate_js(*val)))) + .collect(); + + JSExpr::Let(ns) + } } } \ No newline at end of file