diff --git a/src/emitter.rs b/src/emitter.rs index d40df94..cf7ad2e 100644 --- a/src/emitter.rs +++ b/src/emitter.rs @@ -5,14 +5,16 @@ use crate::parser; pub struct LexicalContext<'a> { parent: Option<&'a LexicalContext<'a>>, - local: HashSet + local: HashSet, + is_tail: bool, } impl <'a> LexicalContext<'a> { pub fn toplevel() -> Self { LexicalContext { parent: None, - local: HashSet::new() + local: HashSet::new(), + is_tail: false, } } #[allow(dead_code)] @@ -20,6 +22,7 @@ impl <'a> LexicalContext<'a> { LexicalContext { parent: Some(parent), local: HashSet::new(), + is_tail: false, } } fn contains(&self, s: &str) -> bool { @@ -53,7 +56,32 @@ pub fn emit(w: &mut dyn Write, stmt: &parser::Stmt, ctx: &mut LexicalContext) -> emit_expr(w, expr, ctx)?; writeln!(w, ";")?; } - _ => todo!(), + parser::Stmt::Funcall(call) => { + emit_expr(w, call, ctx)?; + writeln!(w, ";")?; + } + parser::Stmt::Conditional(if_blocks, else_block) => { + let mut first_block = true; + for if_block in if_blocks { + if first_block { + write!(w, "if (")?; + } else { + write!(w, " else if(")?; + } + first_block = false; + emit_expr(w, &if_block.guard, ctx)?; + writeln!(w, ") {{")?; + let mut block_ctx = LexicalContext::new(ctx); + emit_expr(w, &if_block.block, &mut block_ctx)?; + writeln!(w, "}}")?; + } + if let Some(block) = else_block { + writeln!(w, "else {{")?; + let mut block_ctx = LexicalContext::new(ctx); + emit_expr(w, block, &mut block_ctx)?; + writeln!(w, "}}")?; + } + } } Ok(()) } @@ -66,6 +94,42 @@ pub fn emit_expr(w: &mut dyn Write, expr: &parser::Expr, ctx: &mut LexicalContex parser::Expr::Atom(atom) => { write!(w, "{}", atom)?; } + parser::Expr::Funcall(id, args) => { + write!(w, "{}", id)?; + if args.is_empty() { + write!(w, "()")?; + } + for arg in args { + write!(w, "(")?; + emit_expr(w, arg, ctx)?; + write!(w, ")")?; + } + } + parser::Expr::Funcdef(arg, body) => { + if let Some(arg) = arg { + writeln!(w, "function ({}){{", arg)?; + } else { + writeln!(w, "function (){{")?; + } + let mut fun_ctx = LexicalContext::new(ctx); + fun_ctx.is_tail = true; + emit_expr(w, body.as_ref(), &mut fun_ctx)?; + write!(w, "}}")?; + } + parser::Expr::Block(stmts) => { + let mut peek_iter = stmts.iter().peekable(); + while let Some(stmt) = peek_iter.next() { + if peek_iter.peek().is_none() { + write!(w, "return ")?; + } + emit(w, stmt, ctx)?; + } + } + parser::Expr::Plus(e1, e2) => { + emit_expr(w, e1.as_ref(), ctx)?; + write!(w, " + ")?; + emit_expr(w, e2.as_ref(), ctx)?; + } _ => todo!(), } Ok(()) diff --git a/src/evaluator.rs b/src/evaluator.rs index 000dd49..f53c306 100644 --- a/src/evaluator.rs +++ b/src/evaluator.rs @@ -49,9 +49,11 @@ pub fn eval(ast: &parser::Stmt, env: &mut Env) { match res { Atom::Bool(true) => { matched = true; - for stmt in block { - eval(stmt, env); - } + if let parser::Expr::Block(block) = block { + for stmt in block { + eval(stmt, env); + } + } break; } Atom::Bool(false) => continue, diff --git a/src/parser.rs b/src/parser.rs index c35416a..45623b4 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -43,7 +43,7 @@ impl fmt::Display for Atom { #[derive(Debug,PartialEq,Clone)] pub struct GuardedBlock { pub guard: Expr, - pub block: Vec, + pub block: Expr, } peg::parser! { @@ -93,14 +93,14 @@ peg::parser! { = "{" _ stop() indent() __* a:assignment()+ dedent() __* "}" _ { Expr::Object(a) } rule _if() -> GuardedBlock - = "if" _ g:expr() b:indented_block() { + = "if" _ g:expr() b:block() { GuardedBlock { guard: g, block: b, } } rule elif() -> GuardedBlock - = "elif" _ g:expr() b:indented_block() { + = "elif" _ g:expr() b:block() { GuardedBlock { guard: g, block: b @@ -333,11 +333,11 @@ else vec![ GuardedBlock { guard: Expr::Id("foo".to_string()), - block: vec![Stmt::Funcall(Expr::Funcall("bar".to_string(), vec![]))] + block: Expr::Block(vec![Stmt::Funcall(Expr::Funcall("bar".to_string(), vec![]))]) }, GuardedBlock { guard: Expr::Id("baz".to_string()), - block: vec![Stmt::Funcall(Expr::Funcall("foobar".to_string(), vec![]))] + block: Expr::Block(vec![Stmt::Funcall(Expr::Funcall("foobar".to_string(), vec![]))]) }, ], Some(Expr::Block(vec![Stmt::Funcall(Expr::Funcall("quux".to_string(), vec![]))])),