From 05be7588818f1486ecc0553b5335ac6ace49ee12 Mon Sep 17 00:00:00 2001 From: azur Date: Fri, 3 Mar 2023 03:31:52 +0700 Subject: [PATCH] block + return expressions --- a.hlm | 20 +++++--------------- src/main.rs | 2 +- src/read/parse.rs | 40 ++++++++++++++++++++++++++++++---------- src/read/past.rs | 14 +++++++++++++- src/trans/ast.rs | 14 ++++++++++++-- src/trans/js.rs | 15 +++++++++++++-- src/trans/low.rs | 17 +++++++++++++---- 7 files changed, 87 insertions(+), 35 deletions(-) diff --git a/a.hlm b/a.hlm index 1b601c8..a58260c 100644 --- a/a.hlm +++ b/a.hlm @@ -1,15 +1,5 @@ -let name: str = "john"; -println("Hello, " + name + "!"); - -let a: num = 17, b: num = 35 in - let c: num = a * 2 in - println(b + c); - -// func foo (a: int, b: int) { -// let c = a * 2; -// -// let res = b + c in -// return res + a; -// } - -println((\x: int -> x + 1)(1)); \ No newline at end of file +println({ + println("Hello"); + return let x: num = 17 * 2 in + x + 1; +} + 34); \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index a9742c1..b953628 100644 --- a/src/main.rs +++ b/src/main.rs @@ -49,6 +49,6 @@ fn main() { .into_iter() .map(|e| e.map(|c| c.to_string())) .chain(parse_errs.into_iter().map(|e| e.map(|t| t.to_string()))) - .for_each(|e| println!("{}", e)); + .for_each(|e| println!("[{:?} {:?}] {}", e.span(), e.label(), e)); } } diff --git a/src/read/parse.rs b/src/read/parse.rs index bbc35ae..3918eba 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, In, Func, + Let, In, Func, Return, } impl Display for Token { @@ -63,9 +63,10 @@ impl Display for Token { Token::Lambda => write!(f, "\\"), Token::Arrow => write!(f, "->"), - Token::Let => write!(f, "let"), - Token::In => write!(f, "in"), - Token::Func => write!(f, "func"), + Token::Let => write!(f, "let"), + Token::In => write!(f, "in"), + Token::Func => write!(f, "func"), + Token::Return => write!(f, "return"), } } } @@ -119,12 +120,13 @@ pub fn lexer() -> impl Parser, Error = Simple> { let kw = text::ident() .map(|s: String| match s.as_str() { - "true" => Token::Bool(true), - "false" => Token::Bool(false), - "let" => Token::Let, - "in" => Token::In, - "func" => Token::Func, - _ => Token::Sym(s), + "true" => Token::Bool(true), + "false" => Token::Bool(false), + "let" => Token::Let, + "in" => Token::In, + "func" => Token::Func, + "return" => Token::Return, + _ => Token::Sym(s), }); let token = num @@ -298,12 +300,30 @@ pub fn expr_parser() -> impl P> { .boxed() .labelled("let..in"); + let block = nested_parser( + expr.clone() + .separated_by(just(Token::Semicolon)) + .allow_trailing(), + Delim::Brace, + |_| Vec::new(), + ) + .map(PExpr::Block) + .labelled("block"); + + let ret = just(Token::Return) + .ignore_then(expr.clone()) + .map(Box::new) + .map(PExpr::Return) + .labelled("return"); + let atom = lit .or(sym) .or(vec) .or(paren_expr) .or(lam) .or(let_in) + .or(block) + .or(ret) .map_with_span(|e, s| (e, s)) .boxed() .labelled("atom"); diff --git a/src/read/past.rs b/src/read/past.rs index 6560cf7..5a6bc43 100644 --- a/src/read/past.rs +++ b/src/read/past.rs @@ -18,7 +18,6 @@ pub enum PBinaryOp { #[derive(Clone, Debug)] pub enum PLiteral { Num(i64), Str(String), Bool(bool) } -/// Enum to represent a parsed expression #[derive(Clone, Debug)] pub enum PExpr { Error, @@ -39,4 +38,17 @@ pub enum PExpr { vars: Vec<(String, Type, Spanned)>, body: Box>, }, + Block(Vec>), + Return(Box>), +} + +#[derive(Clone, Debug)] +pub enum PStmt { + Expr(Spanned), + Let(Vec<(String, Type, Spanned)>), + Func { + name: String, + args: Vec<(String, Type)>, + body: Box>, + }, } \ No newline at end of file diff --git a/src/trans/ast.rs b/src/trans/ast.rs index c3b4442..d2db545 100644 --- a/src/trans/ast.rs +++ b/src/trans/ast.rs @@ -32,8 +32,9 @@ pub enum Expr { Call(Box, Vec), Lambda { args: Vec<(String, Type)>, - body: Box, + body: Vec, }, + Return(Box), } impl Display for Expr { @@ -69,8 +70,17 @@ impl Display for Expr { for (name, ty) in args { write!(f, "[{} {}]", name, ty)?; } - write!(f, " {})", body) + if body.len() == 1 { + write!(f, " {})", body[0]) + } else { + write!(f, " (do")?; + for e in body { + write!(f, " {}", e)?; + } + write!(f, "))") + } }, + Expr::Return(e) => write!(f, "(return {})", e), } } } \ No newline at end of file diff --git a/src/trans/js.rs b/src/trans/js.rs index 9329cfe..294b710 100644 --- a/src/trans/js.rs +++ b/src/trans/js.rs @@ -17,8 +17,9 @@ pub enum JSExpr { Method(Box, String, Vec), Lambda { args: Vec<(String, Type)>, - body: Box, + body: Vec, }, + Return(Box), } impl Display for JSExpr { @@ -74,8 +75,18 @@ impl Display for JSExpr { } write!(f, "{}", name)?; } - write!(f, ") => {})", body) + // write!(f, ") => {})", body) + if body.len() == 1 { + write!(f, ") => {})", body[0]) + } else { + write!(f, ") => {{")?; + for e in body { + write!(f, "{};", e)?; + } + write!(f, "}})") + } }, + JSExpr::Return(e) => write!(f, "return {}", e), } } } \ No newline at end of file diff --git a/src/trans/low.rs b/src/trans/low.rs index 878b85b..f55fbf6 100644 --- a/src/trans/low.rs +++ b/src/trans/low.rs @@ -49,7 +49,7 @@ pub fn translate_expr(expr: PExpr) -> Expr { ), PExpr::Lambda { args, body } => Expr::Lambda { args, - body: Box::new(translate_expr((*body).0)), + body: vec![translate_expr((*body).0)], }, PExpr::Let { vars, body } => { let mut expr: Expr = translate_expr(body.0); // The expression we're building up @@ -58,14 +58,22 @@ pub fn translate_expr(expr: PExpr) -> Expr { // Build up the lambda expr = Expr::Lambda { args: vec![(name, ty)], - body: Box::new(expr), + body: vec![expr], }; // Call the lambda with the value let val = translate_expr(val.0); expr = Expr::Call(Box::new(expr), vec![val]); } 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![]) + }, + PExpr::Return(e) => Expr::Return(Box::new(translate_expr((*e).0))), } } @@ -126,7 +134,8 @@ pub fn translate_js(expr: Expr) -> JSExpr { } Expr::Lambda { args, body } => JSExpr::Lambda { args, - body: Box::new(translate_js(*body)), + body: body.into_iter().map(translate_js).collect(), }, + Expr::Return(e) => JSExpr::Return(Box::new(translate_js(*e))), } } \ No newline at end of file