bobbylisp/src/trans/low.rs

198 lines
7.3 KiB
Rust

use crate::asts::{
past::*,
ast::*,
js::*,
};
pub fn translate_stmt(stmt: PStmt) -> Stmt {
match stmt {
PStmt::Expr(e) => Stmt::Expr(translate_expr(e.0)),
PStmt::Func { name, args, ret, body } => Stmt::Func {
name,
args: args.into_iter().map(|(name, _ty)| name).collect(),
ret,
body: translate_expr(body.0),
},
}
}
pub fn exprs_to_lam(es: Vec<PExpr>) -> Expr {
let lam = Expr::Lambda {
args: vec![],
body: es.into_iter().map(translate_expr).collect(),
};
Expr::Call(Box::new(lam), vec![])
}
pub fn translate_expr(expr: PExpr) -> Expr {
match expr {
PExpr::Error => panic!("Error in expression!"),
PExpr::Lit(l) => Expr::Lit(match l {
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()),
PExpr::Unary(op, e) => Expr::UnaryOp(match op.0 {
PUnaryOp::Neg => UnaryOp::Neg,
PUnaryOp::Not => UnaryOp::Not,
}, Box::new(translate_expr((*e).0))),
PExpr::Binary((op, _), e1, e2) => Expr::BinaryOp(
match op {
PBinaryOp::Add => BinaryOp::Add,
PBinaryOp::Sub => BinaryOp::Sub,
PBinaryOp::Mul => BinaryOp::Mul,
PBinaryOp::Div => BinaryOp::Div,
PBinaryOp::Mod => BinaryOp::Mod,
PBinaryOp::Eq => BinaryOp::Eq,
PBinaryOp::Neq => BinaryOp::Neq,
PBinaryOp::Lt => BinaryOp::Lt,
PBinaryOp::Gt => BinaryOp::Gt,
PBinaryOp::Lte => BinaryOp::Lte,
PBinaryOp::Gte => BinaryOp::Gte,
PBinaryOp::And => BinaryOp::And,
PBinaryOp::Or => BinaryOp::Or,
},
Box::new(translate_expr((*e1).0)),
Box::new(translate_expr((*e2).0)),
),
PExpr::Call(f, args) => Expr::Call(
Box::new(translate_expr((*f).0)),
args.into_iter().map(|a| translate_expr(a.0)).collect(),
),
PExpr::Lambda { args, body } => Expr::Lambda {
args: args.into_iter().map(|(name, _ty)| name).collect(),
body: vec![translate_expr((*body).0)],
},
PExpr::Let { vars, body } => {
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())
}
},
PExpr::If { cond, t, f } => Expr::If {
cond: Box::new(translate_expr((*cond).0)),
t: Box::new(translate_expr((*t).0)),
f: Box::new(translate_expr((*f).0)),
},
PExpr::Block(es) => {
exprs_to_lam(es.into_iter().map(|e| e.0).collect())
},
PExpr::Return(e) => Expr::Return(Box::new(translate_expr((*e).0))),
}
}
pub fn translate_js_stmt(stmt: Stmt) -> JSStmt {
match stmt {
Stmt::Expr(e) => JSStmt::Expr(translate_js_expr(e)),
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)),
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()),
Expr::UnaryOp(op, e) => JSExpr::Op(match op {
UnaryOp::Neg => "-",
UnaryOp::Not => "!",
}, Box::new(translate_js_expr(*e)), None),
Expr::BinaryOp(op, e1, e2) => JSExpr::Op(match op {
BinaryOp::Add => "+",
BinaryOp::Sub => "-",
BinaryOp::Mul => "*",
BinaryOp::Div => "/",
BinaryOp::Mod => "%",
BinaryOp::Eq => "==",
BinaryOp::Neq => "!=",
BinaryOp::Lt => "<",
BinaryOp::Gt => ">",
BinaryOp::Lte => "<=",
BinaryOp::Gte => ">=",
BinaryOp::And => "&&",
BinaryOp::Or => "||",
}, Box::new(translate_js_expr(*e1)), Some(Box::new(translate_js_expr(*e2)))),
Expr::Call(f, args) => {
match *f {
Expr::Sym(ref s) => {
match s.as_str() {
"println" => JSExpr::Call(
Box::new(JSExpr::Method(
Box::new(JSExpr::Sym("console".to_string())),
"log".to_string(),
)),
args.into_iter().map(translate_js_expr).collect()),
"print" => JSExpr::Call(
Box::new(JSExpr::Method(
Box::new(JSExpr::Method(
Box::new(JSExpr::Sym("process".to_string())),
"stdout".to_string(),
)),
"write".to_string(),
)),
args.into_iter().map(translate_js_expr).collect()),
_ => JSExpr::Call(
Box::new(translate_js_expr(*f)),
args.into_iter().map(translate_js_expr).collect(),
),
}
},
_ => JSExpr::Call(
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_expr).collect(),
},
Expr::If { cond, t, f } => JSExpr::If {
cond: Box::new(translate_js_expr(*cond)),
t: Box::new(translate_js_expr(*t)),
f: Box::new(translate_js_expr(*f)),
},
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))),
}
}