mirror of https://github.com/azur1s/bobbylisp.git
`|>` operator folding
parent
cfca9828f6
commit
ff79c39cde
|
@ -39,7 +39,7 @@ dependencies = [
|
|||
name = "compiler"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"parser",
|
||||
"lower",
|
||||
"vm",
|
||||
]
|
||||
|
||||
|
|
|
@ -4,5 +4,5 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
parser = { path = "../parser" }
|
||||
lower = { path = "../lower" }
|
||||
vm = { path = "../vm" }
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(clippy::new_without_default)]
|
||||
#![allow(clippy::only_used_in_recursion)]
|
||||
use parser::{Expr, Literal, Span, Stmt};
|
||||
use lower::model::{BinaryOp, Expr, Literal, Stmt, UnaryOp};
|
||||
use vm::model::Instr;
|
||||
|
||||
pub struct Compiler {}
|
||||
|
@ -26,58 +26,58 @@ impl Compiler {
|
|||
let mut instrs = vec![];
|
||||
let count = xs.len();
|
||||
for x in xs {
|
||||
instrs.extend(self.compile_expr(x.0));
|
||||
instrs.extend(self.compile_expr(x));
|
||||
}
|
||||
instrs.push(Instr::ListMake(count));
|
||||
instrs
|
||||
}
|
||||
Expr::Unary(op, x) => {
|
||||
let mut instrs = self.compile_expr(x.0);
|
||||
instrs.extend(match op.0 {
|
||||
parser::UnaryOp::Neg => vec![Instr::NumPush(-1), Instr::NumMul],
|
||||
parser::UnaryOp::Not => vec![Instr::BoolNot],
|
||||
let mut instrs = self.compile_expr(*x);
|
||||
instrs.extend(match op {
|
||||
UnaryOp::Neg => vec![Instr::NumPush(-1), Instr::NumMul],
|
||||
UnaryOp::Not => vec![Instr::BoolNot],
|
||||
});
|
||||
instrs
|
||||
}
|
||||
Expr::Binary(op, x, y) => {
|
||||
let mut instrs = self.compile_expr(y.0);
|
||||
instrs.extend(self.compile_expr(x.0));
|
||||
instrs.push(match op.0 {
|
||||
parser::BinaryOp::Add => Instr::NumAdd,
|
||||
parser::BinaryOp::Sub => Instr::NumSub,
|
||||
parser::BinaryOp::Mul => Instr::NumMul,
|
||||
parser::BinaryOp::Div => Instr::NumDiv,
|
||||
parser::BinaryOp::Eq => Instr::NumEq,
|
||||
parser::BinaryOp::Ne => Instr::NumNe,
|
||||
parser::BinaryOp::Lt => Instr::NumLt,
|
||||
parser::BinaryOp::Gt => Instr::NumGt,
|
||||
parser::BinaryOp::Le => Instr::NumLe,
|
||||
parser::BinaryOp::Ge => Instr::NumGe,
|
||||
parser::BinaryOp::And => Instr::BoolAnd,
|
||||
parser::BinaryOp::Or => Instr::BoolOr,
|
||||
parser::BinaryOp::Pipe => todo!(),
|
||||
let mut instrs = self.compile_expr(*y);
|
||||
instrs.extend(self.compile_expr(*x));
|
||||
instrs.push(match op {
|
||||
BinaryOp::Add => Instr::NumAdd,
|
||||
BinaryOp::Sub => Instr::NumSub,
|
||||
BinaryOp::Mul => Instr::NumMul,
|
||||
BinaryOp::Div => Instr::NumDiv,
|
||||
BinaryOp::Eq => Instr::NumEq,
|
||||
BinaryOp::Ne => Instr::NumNe,
|
||||
BinaryOp::Lt => Instr::NumLt,
|
||||
BinaryOp::Gt => Instr::NumGt,
|
||||
BinaryOp::Le => Instr::NumLe,
|
||||
BinaryOp::Ge => Instr::NumGe,
|
||||
BinaryOp::And => Instr::BoolAnd,
|
||||
BinaryOp::Or => Instr::BoolOr,
|
||||
BinaryOp::Pipe => todo!(),
|
||||
});
|
||||
instrs
|
||||
}
|
||||
Expr::Lambda(args, body) => {
|
||||
vec![Instr::FuncMake(args, self.compile_expr(body.0))]
|
||||
vec![Instr::FuncMake(args, self.compile_expr(*body))]
|
||||
}
|
||||
Expr::Call(f, xs) => {
|
||||
let mut instrs = vec![];
|
||||
for x in xs {
|
||||
instrs.extend(self.compile_expr(x.0));
|
||||
instrs.extend(self.compile_expr(x));
|
||||
}
|
||||
match &f.0 {
|
||||
Expr::Sym(fname) => match fname.as_str() {
|
||||
match *f {
|
||||
Expr::Sym(ref fname) => match fname.as_str() {
|
||||
"print" => instrs.push(Instr::Print),
|
||||
"println" => instrs.push(Instr::PrintLn),
|
||||
_ => {
|
||||
instrs.extend(self.compile_expr(f.0));
|
||||
instrs.extend(self.compile_expr(*f));
|
||||
instrs.push(Instr::FuncApply);
|
||||
}
|
||||
},
|
||||
Expr::Lambda(_, _) => {
|
||||
instrs.extend(self.compile_expr(f.0));
|
||||
instrs.extend(self.compile_expr(*f));
|
||||
instrs.push(Instr::FuncApply);
|
||||
}
|
||||
_ => todo!(),
|
||||
|
@ -89,7 +89,7 @@ impl Compiler {
|
|||
let binds = binds
|
||||
.into_iter()
|
||||
.flat_map(|(name, expr)| {
|
||||
let mut instrs = self.compile_expr(expr.0);
|
||||
let mut instrs = self.compile_expr(expr);
|
||||
instrs.extend(vec![Instr::Set(name)]);
|
||||
instrs
|
||||
})
|
||||
|
@ -101,7 +101,7 @@ impl Compiler {
|
|||
instrs.extend(vec![
|
||||
Instr::FuncMake(
|
||||
vec![],
|
||||
binds.into_iter().chain(self.compile_expr(e.0)).collect(),
|
||||
binds.into_iter().chain(self.compile_expr(*e)).collect(),
|
||||
),
|
||||
Instr::FuncApply,
|
||||
]);
|
||||
|
@ -113,10 +113,10 @@ impl Compiler {
|
|||
instrs
|
||||
}
|
||||
Expr::If(c, t, f) => {
|
||||
let mut instrs = self.compile_expr(c.0);
|
||||
let t = self.compile_expr(t.0);
|
||||
let mut instrs = self.compile_expr(*c);
|
||||
let t = self.compile_expr(*t);
|
||||
if let Some(f) = f {
|
||||
let f = self.compile_expr(f.0);
|
||||
let f = self.compile_expr(*f);
|
||||
instrs.push(Instr::JumpIfFalse(t.len() + 1));
|
||||
instrs.extend(t);
|
||||
instrs.push(Instr::Jump(f.len()));
|
||||
|
@ -130,7 +130,7 @@ impl Compiler {
|
|||
Expr::Do(es) => {
|
||||
let mut instrs = vec![];
|
||||
for e in es {
|
||||
instrs.extend(self.compile_expr(e.0));
|
||||
instrs.extend(self.compile_expr(e));
|
||||
}
|
||||
instrs
|
||||
}
|
||||
|
@ -141,11 +141,11 @@ impl Compiler {
|
|||
match stmt {
|
||||
Stmt::Fun(name, args, body) => {
|
||||
let is_main = name == "main";
|
||||
let mut instrs = match body.0 {
|
||||
let mut instrs = match body {
|
||||
// If the body is a lambda then we don't have to compile
|
||||
// it into a function
|
||||
Expr::Lambda(_, _) => self.compile_expr(body.0),
|
||||
_ => vec![Instr::FuncMake(args, self.compile_expr(body.0))],
|
||||
Expr::Lambda(_, _) => self.compile_expr(body),
|
||||
_ => vec![Instr::FuncMake(args, self.compile_expr(body))],
|
||||
};
|
||||
instrs.push(Instr::Set(name));
|
||||
if is_main {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use compiler::Compiler;
|
||||
use lower::Lower;
|
||||
use lower::{model::converts, Lower};
|
||||
use parser::{lex, parse, report};
|
||||
use vm::exec::Executor;
|
||||
|
||||
|
@ -12,10 +12,11 @@ fn main() {
|
|||
let (ast, parse_errors) = parse(tokens, src.len());
|
||||
|
||||
if let Some(ast) = ast {
|
||||
let stripped = converts(ast);
|
||||
let mut lower = Lower::new();
|
||||
let last = lower.opt_stmts(ast.iter().map(|(s, _)| s.clone()).collect());
|
||||
let lowered = lower.opt_stmts(stripped);
|
||||
let mut compiler = Compiler::new();
|
||||
let instrs = compiler.compile_program(last);
|
||||
let instrs = compiler.compile_program(lowered);
|
||||
// instrs.iter().for_each(|i| println!("{:?}", i));
|
||||
let mut executor = Executor::new(instrs);
|
||||
match executor.run() {
|
||||
|
|
|
@ -8,5 +8,9 @@ end
|
|||
fun double x = x * 2
|
||||
|
||||
fun main = do
|
||||
x |> \a -> println(a)
|
||||
|
||||
1
|
||||
|> \a -> succ(a)
|
||||
|> \b -> double(b)
|
||||
|> \c -> println(c)
|
||||
end
|
|
@ -1,7 +1,6 @@
|
|||
#![allow(clippy::new_without_default)]
|
||||
use parser::*;
|
||||
|
||||
type SExpr = (Expr, std::ops::Range<usize>);
|
||||
pub mod model;
|
||||
use crate::model::{BinaryOp, Expr, Stmt};
|
||||
|
||||
pub struct Lower {}
|
||||
|
||||
|
@ -12,42 +11,52 @@ impl Lower {
|
|||
|
||||
pub fn opt_stmts(&self, ss: Vec<Stmt>) -> Vec<Stmt> {
|
||||
ss.into_iter()
|
||||
.flat_map(|s| self.opt_stmt(s.clone()).unwrap_or_else(|| vec![s]))
|
||||
.map(|s| self.opt_stmt(s.clone()).unwrap_or(s))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn opt_stmt(&self, s: Stmt) -> Option<Vec<Stmt>> {
|
||||
pub fn opt_stmt(&self, s: Stmt) -> Option<Stmt> {
|
||||
match s {
|
||||
// Stmt::Fun(name, args, body) => Some(vec![Stmt::Fun(
|
||||
// name,
|
||||
// args,
|
||||
// self.opt_expr(body.0).unwrap_or_else(|| vec![body.0]),
|
||||
// )]),
|
||||
Stmt::Fun(name, args, body) => Some(Stmt::Fun(
|
||||
name,
|
||||
args,
|
||||
self.opt_expr(body.clone()).unwrap_or(body),
|
||||
)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn opt_exprs(&self, es: Vec<Expr>) -> Vec<Expr> {
|
||||
es.into_iter()
|
||||
.flat_map(|e| self.opt_expr(e.clone()).unwrap_or_else(|| vec![e]))
|
||||
.map(|e| self.opt_expr(e.clone()).unwrap_or(e))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn opt_expr(&self, e: Expr) -> Option<Vec<Expr>> {
|
||||
pub fn opt_expr(&self, e: Expr) -> Option<Expr> {
|
||||
match e {
|
||||
Expr::Binary((BinaryOp::Pipe, _), left, right) => Some(self.fold_pipe(*left, *right)),
|
||||
Expr::Binary(BinaryOp::Pipe, left, right) => Some(self.fold_pipe(*left, *right)),
|
||||
Expr::Lambda(args, body) => Some(Expr::Lambda(
|
||||
args,
|
||||
Box::new(self.opt_expr(*body.clone()).unwrap_or(*body)),
|
||||
)),
|
||||
Expr::Do(es) => Some(Expr::Do(self.opt_exprs(es))),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_pipe(&self, left: SExpr, right: SExpr) -> Vec<Expr> {
|
||||
vec![Expr::Call(Box::new(right), vec![left])]
|
||||
fn fold_pipe(&self, left: Expr, right: Expr) -> Expr {
|
||||
Expr::Call(
|
||||
Box::new(self.opt_expr(right.clone()).unwrap_or(right)),
|
||||
vec![self.opt_expr(left.clone()).unwrap_or(left)],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::model::convert_expr;
|
||||
use parser::{lex, parse_expr};
|
||||
|
||||
#[test]
|
||||
fn test_fold_pipe() {
|
||||
|
@ -62,8 +71,9 @@ mod test {
|
|||
assert!(es.is_empty());
|
||||
|
||||
let ex = ex.unwrap();
|
||||
let ex = convert_expr(ex);
|
||||
let l = Lower::new();
|
||||
let ex = l.opt_expr(ex.0).unwrap();
|
||||
let ex = l.opt_expr(ex).unwrap();
|
||||
println!("{:?}", ex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
use crate::model;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Literal {
|
||||
Num(i64),
|
||||
Bool(bool),
|
||||
Str(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum UnaryOp {
|
||||
Neg,
|
||||
Not,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum BinaryOp {
|
||||
Add,
|
||||
Sub,
|
||||
Mul,
|
||||
Div,
|
||||
Lt,
|
||||
Le,
|
||||
Gt,
|
||||
Ge,
|
||||
Eq,
|
||||
Ne,
|
||||
And,
|
||||
Or,
|
||||
Pipe,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Expr {
|
||||
Error,
|
||||
|
||||
Literal(Literal),
|
||||
Sym(String),
|
||||
Vec(Vec<Self>),
|
||||
Unary(UnaryOp, Box<Self>),
|
||||
Binary(BinaryOp, Box<Self>, Box<Self>),
|
||||
Lambda(Vec<String>, Box<Self>),
|
||||
Call(Box<Self>, Vec<Self>),
|
||||
Let(Vec<(String, Self)>, Option<Box<Self>>),
|
||||
If(Box<Self>, Box<Self>, Option<Box<Self>>),
|
||||
Do(Vec<Expr>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Stmt {
|
||||
Fun(String, Vec<String>, Expr),
|
||||
}
|
||||
|
||||
pub fn converts(s: Vec<(parser::Stmt, std::ops::Range<usize>)>) -> Vec<model::Stmt> {
|
||||
s.into_iter().map(|(s, _)| convert(s)).collect()
|
||||
}
|
||||
|
||||
pub fn convert(s: parser::Stmt) -> model::Stmt {
|
||||
match s {
|
||||
parser::Stmt::Fun(name, args, body) => model::Stmt::Fun(name, args, convert_expr(body)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_expr(e: (parser::Expr, std::ops::Range<usize>)) -> model::Expr {
|
||||
match e.0 {
|
||||
parser::Expr::Error => model::Expr::Error,
|
||||
|
||||
parser::Expr::Literal(l) => match l {
|
||||
parser::Literal::Num(n) => model::Expr::Literal(model::Literal::Num(n)),
|
||||
parser::Literal::Bool(b) => model::Expr::Literal(model::Literal::Bool(b)),
|
||||
parser::Literal::Str(s) => model::Expr::Literal(model::Literal::Str(s)),
|
||||
},
|
||||
parser::Expr::Sym(s) => model::Expr::Sym(s),
|
||||
parser::Expr::Vec(es) => model::Expr::Vec(es.into_iter().map(convert_expr).collect()),
|
||||
parser::Expr::Unary(op, e) => {
|
||||
model::Expr::Unary(convert_unary_op(op.0), Box::new(convert_expr(*e)))
|
||||
}
|
||||
parser::Expr::Binary(op, left, right) => model::Expr::Binary(
|
||||
convert_binary_op(op.0),
|
||||
Box::new(convert_expr(*left)),
|
||||
Box::new(convert_expr(*right)),
|
||||
),
|
||||
parser::Expr::Lambda(args, body) => {
|
||||
model::Expr::Lambda(args, Box::new(convert_expr(*body)))
|
||||
}
|
||||
parser::Expr::Call(f, args) => model::Expr::Call(
|
||||
Box::new(convert_expr(*f)),
|
||||
args.into_iter().map(convert_expr).collect(),
|
||||
),
|
||||
parser::Expr::Let(bindings, body) => model::Expr::Let(
|
||||
bindings
|
||||
.into_iter()
|
||||
.map(|(s, e)| (s, convert_expr(e)))
|
||||
.collect(),
|
||||
body.map(|e| Box::new(convert_expr(*e))),
|
||||
),
|
||||
parser::Expr::If(cond, then, else_) => model::Expr::If(
|
||||
Box::new(convert_expr(*cond)),
|
||||
Box::new(convert_expr(*then)),
|
||||
else_.map(|e| Box::new(convert_expr(*e))),
|
||||
),
|
||||
parser::Expr::Do(es) => model::Expr::Do(es.into_iter().map(convert_expr).collect()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_unary_op(op: parser::UnaryOp) -> model::UnaryOp {
|
||||
match op {
|
||||
parser::UnaryOp::Neg => model::UnaryOp::Neg,
|
||||
parser::UnaryOp::Not => model::UnaryOp::Not,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_binary_op(op: parser::BinaryOp) -> model::BinaryOp {
|
||||
match op {
|
||||
parser::BinaryOp::Add => model::BinaryOp::Add,
|
||||
parser::BinaryOp::Sub => model::BinaryOp::Sub,
|
||||
parser::BinaryOp::Mul => model::BinaryOp::Mul,
|
||||
parser::BinaryOp::Div => model::BinaryOp::Div,
|
||||
parser::BinaryOp::Lt => model::BinaryOp::Lt,
|
||||
parser::BinaryOp::Le => model::BinaryOp::Le,
|
||||
parser::BinaryOp::Gt => model::BinaryOp::Gt,
|
||||
parser::BinaryOp::Ge => model::BinaryOp::Ge,
|
||||
parser::BinaryOp::Eq => model::BinaryOp::Eq,
|
||||
parser::BinaryOp::Ne => model::BinaryOp::Ne,
|
||||
parser::BinaryOp::And => model::BinaryOp::And,
|
||||
parser::BinaryOp::Or => model::BinaryOp::Or,
|
||||
parser::BinaryOp::Pipe => model::BinaryOp::Pipe,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue