mirror of https://github.com/azur1s/bobbylisp.git
198 lines
7.3 KiB
Rust
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))),
|
|
}
|
|
} |