diff --git a/a.hlm b/a.hlm index a58260c..da14833 100644 --- a/a.hlm +++ b/a.hlm @@ -1,5 +1,9 @@ -println({ - println("Hello"); - return let x: num = 17 * 2 in - x + 1; -} + 34); \ No newline at end of file +func add x: num -> num = x + 1; + +println( + { + println("Hello"); + return let x: num = 17 * 2 in + add(x); + } + 34 +); \ No newline at end of file diff --git a/sketch.hlm b/sketch.hlm deleted file mode 100644 index a5a20a2..0000000 --- a/sketch.hlm +++ /dev/null @@ -1,21 +0,0 @@ -println({ - println("Hello"); - return let x: num = 17 * 2 in - x + 1; -} + 34); - -//---------- - -let stack = []; - -push("Hello"); -console.log(pop()); -push(17) -push(2) -push(pop() * pop()); -push(pop() + 1); -// [35] - -push(34) -push(pop() + pop()) // [35] + 34 -console.log(pop()); \ No newline at end of file diff --git a/src/asts/ast.rs b/src/asts/ast.rs index 715915f..0f58700 100644 --- a/src/asts/ast.rs +++ b/src/asts/ast.rs @@ -37,6 +37,18 @@ pub enum Expr { Return(Box), } +#[derive(Clone, Debug)] +pub enum Stmt { + Expr(Expr), + Let(Vec<(String, Type, Expr)>), + Func { + name: String, + args: Vec<(String, Type)>, + ret: Type, + body: Expr, + }, +} + impl Display for Expr { fn fmt(&self, f: &mut Formatter) -> FmtResult { match self { @@ -83,4 +95,26 @@ impl Display for Expr { Expr::Return(e) => write!(f, "(return {})", e), } } +} + +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)?; + } + write!(f, "] {} {})", ret, body) + }, + } + } } \ No newline at end of file diff --git a/src/asts/js.rs b/src/asts/js.rs index 7ecada1..dffe879 100644 --- a/src/asts/js.rs +++ b/src/asts/js.rs @@ -22,6 +22,18 @@ pub enum JSExpr { Return(Box), } +#[derive(Clone, Debug)] +pub enum JSStmt { + Expr(JSExpr), + Let(Vec<(String, Type, JSExpr)>), + Func { + name: String, + args: Vec<(String, Type)>, + ret: Type, + body: JSExpr, + }, +} + impl Display for JSExpr { fn fmt(&self, f: &mut Formatter) -> FmtResult { match self { @@ -89,4 +101,33 @@ impl Display for JSExpr { JSExpr::Return(e) => write!(f, "return {}", e), } } +} + +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() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{}", name)?; + } + write!(f, ") => {};", body) + }, + } + } } \ No newline at end of file diff --git a/src/asts/past.rs b/src/asts/past.rs index 38fb626..1c4bf6b 100644 --- a/src/asts/past.rs +++ b/src/asts/past.rs @@ -49,6 +49,7 @@ pub enum PStmt { Func { name: String, args: Vec<(String, Type)>, + ret: Type, body: Box>, }, } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 8594433..131da14 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ use std::io::Write; use args::Options; use read::parse::{lex, parse}; use structopt::StructOpt; -use trans::low::{translate_expr, translate_js}; +use trans::low::{translate_stmt, translate_js_stmt}; fn main() { let opt = Options::from_args(); @@ -17,15 +17,15 @@ fn main() { let (tokens, lex_errs) = lex(src.to_owned()); let parse_errs = if let Some(tokens) = tokens { - let (ast, parse_errs) = parse(tokens, src.len()); + let (past, parse_errs) = parse(tokens, src.len()); - if let Some(ast) = ast { - let nexprs = ast.into_iter().map(|(e, _)| translate_expr(e)).collect::>(); - let jsexprs = nexprs.into_iter().map(translate_js).collect::>(); + if let Some(past) = past { + let ast = past.into_iter().map(|(e, _)| translate_stmt(e)).collect::>(); + let js = ast.into_iter().map(translate_js_stmt).collect::>(); let mut file = std::fs::File::create(opt.output.unwrap_or("out.js".into())) .expect("Failed to create file"); - let s = jsexprs + let s = js .into_iter() .map(|e| { let s = format!("{}", e); diff --git a/src/read/parse.rs b/src/read/parse.rs index e316d07..2e89698 100644 --- a/src/read/parse.rs +++ b/src/read/parse.rs @@ -442,11 +442,44 @@ pub fn exprs_parser() -> impl P>> { .repeated() } +pub fn stmt_parser() -> impl P> { + let func = just(Token::Func) + .ignore_then(symbol_parser()) + .then( + symbol_parser() + .then_ignore(just(Token::Colon)) + .then(type_parser()) + .separated_by(just(Token::Comma)) + ) + .then_ignore(just(Token::Arrow)) + .then(type_parser()) + .then_ignore(just(Token::Assign)) + .then(expr_parser().map(Box::new)) + .map(|(((name, args), ret), body)| PStmt::Func { + name, + args, + ret, + body, + }); + + let expr = expr_parser().map(PStmt::Expr); + + func + .or(expr) + .map_with_span(|s, span| (s, span)) +} + +pub fn stmts_parser() -> impl P>> { + stmt_parser() + .then_ignore(just(Token::Semicolon)) + .repeated() +} + pub fn parse( tokens: Vec>, len: usize, -) -> (Option>>, Vec>) { - let (ast, parse_error) = exprs_parser() +) -> (Option>>, Vec>) { + let (ast, parse_error) = stmts_parser() .then_ignore(end()) .parse_recovery(Stream::from_iter(len..len + 1, tokens.into_iter())); diff --git a/src/trans/low.rs b/src/trans/low.rs index 6b0ae85..74bc36a 100644 --- a/src/trans/low.rs +++ b/src/trans/low.rs @@ -4,6 +4,19 @@ use crate::asts::{ js::*, }; +pub fn translate_stmt(stmt: PStmt) -> Stmt { + match stmt { + PStmt::Expr(e) => Stmt::Expr(translate_expr(e.0)), + PStmt::Let(vars) => todo!(), + PStmt::Func { name, args, ret, body } => Stmt::Func { + name, + args, + ret, + body: translate_expr(body.0), + }, + } +} + pub fn translate_expr(expr: PExpr) -> Expr { match expr { PExpr::Error => panic!("Error in expression!"), @@ -77,7 +90,20 @@ pub fn translate_expr(expr: PExpr) -> Expr { } } -pub fn translate_js(expr: Expr) -> JSExpr { +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, + ret, + body: translate_js_expr(body), + }, + } +} + +pub fn translate_js_expr(expr: Expr) -> JSExpr { match expr { Expr::Lit(l) => match l { Literal::Num(n) => JSExpr::Lit(JSLiteral::Num(n)), @@ -85,12 +111,12 @@ pub fn translate_js(expr: Expr) -> JSExpr { Literal::Bool(b) => JSExpr::Lit(JSLiteral::Bool(b)), }, Expr::Sym(s) => JSExpr::Sym(s), - Expr::Vec(v) => JSExpr::Array(v.into_iter().map(translate_js).collect()), + Expr::Vec(v) => JSExpr::Array(v.into_iter().map(translate_js_expr).collect()), Expr::UnaryOp(op, e) => JSExpr::Op(match op { UnaryOp::Neg => "-", UnaryOp::Not => "!", - }, Box::new(translate_js(*e)), None), + }, Box::new(translate_js_expr(*e)), None), Expr::BinaryOp(op, e1, e2) => JSExpr::Op(match op { BinaryOp::Add => "+", BinaryOp::Sub => "-", @@ -107,7 +133,7 @@ pub fn translate_js(expr: Expr) -> JSExpr { BinaryOp::And => "&&", BinaryOp::Or => "||", - }, Box::new(translate_js(*e1)), Some(Box::new(translate_js(*e2)))), + }, Box::new(translate_js_expr(*e1)), Some(Box::new(translate_js_expr(*e2)))), Expr::Call(f, args) => { match *f { @@ -117,25 +143,25 @@ pub fn translate_js(expr: Expr) -> JSExpr { JSExpr::Method( Box::new(JSExpr::Sym("console".to_string())), "log".to_string(), - args.into_iter().map(translate_js).collect(), + args.into_iter().map(translate_js_expr).collect(), ) }, _ => JSExpr::Call( - Box::new(translate_js(*f)), - args.into_iter().map(translate_js).collect(), + Box::new(translate_js_expr(*f)), + args.into_iter().map(translate_js_expr).collect(), ), } }, _ => JSExpr::Call( - Box::new(translate_js(*f)), - args.into_iter().map(translate_js).collect(), + Box::new(translate_js_expr(*f)), + args.into_iter().map(translate_js_expr).collect(), ), } } Expr::Lambda { args, body } => JSExpr::Lambda { args, - body: body.into_iter().map(translate_js).collect(), + body: body.into_iter().map(translate_js_expr).collect(), }, - Expr::Return(e) => JSExpr::Return(Box::new(translate_js(*e))), + Expr::Return(e) => JSExpr::Return(Box::new(translate_js_expr(*e))), } } \ No newline at end of file