@@ 16,39 16,44 @@ pub struct FunDef {
// Nested definitions (including anonymous functions)
pub children: HashSet<DefId>,
pub params: Vec<LocalId>,
- pub body: Block<Return>,
+ pub body: Block<Option<Operation>>,
}
#[derive(Clone, Debug)]
pub struct GVarDef {
pub children: HashSet<DefId>,
- pub body: Block<Operand>,
+ pub body: Block<Option<Operation>>,
}
-#[derive(Clone, Debug)]
-pub struct Block<Term> {
+#[derive(Debug, Clone)]
+pub struct Block<Leaf> {
pub stms: Vec<Stm>,
- pub term: Term,
+ pub tail: Box<Flow<Leaf>>,
}
-#[derive(Clone, Debug)]
+#[derive(Debug, Clone)]
pub enum Stm {
- Let { lhs: LocalId, rhs: Expr },
+ Let { lhs: LocalId, rhs: Flow<Option<Operation>> },
}
-#[derive(Clone, Debug)]
-pub enum Return {
- Val(Expr),
- // Void,
+#[derive(Debug, Clone)]
+pub enum Flow<Leaf> {
+ Diverge(Diverge<Leaf>),
+ Leaf(Leaf),
+}
+
+#[derive(Debug, Clone)]
+pub enum Diverge<Leaf> {
+ If(Operand, Block<Leaf>, Block<Leaf>),
}
#[derive(Clone, Debug)]
-pub enum Expr {
+pub enum Operation {
Binop(Binop, Operand, Operand),
Call(Operand, Vec<Operand>),
- Operand(Operand),
- If(Operand, Block<Box<Expr>>, Block<Box<Expr>>),
+ Wrap(Operand),
}
+
#[derive(Debug, Clone, Copy)]
pub enum Binop {
Add,
@@ 161,26 166,29 @@ impl<'c> AbaseDef<'c> {
fn run(mut self, rhs: &FExpr) -> Result<GlobDef> {
match self.abase(rhs)? {
- Expr::Operand(rand) => match rand {
+ Flow::Leaf(Some(Operation::Wrap(rand))) => match rand {
Operand::Local(id) => panic!("ice: result of abasing def is a local reference {id:?}"),
Operand::Global(id) => Ok(GlobDef::Alias(id)),
_ => Ok(GlobDef::VarDef(GVarDef {
children: self.children,
- body: Block { stms: self.stms, term: rand },
+ body: Block { stms: self.stms, tail: Box::new(Flow::Leaf(Some(Operation::Wrap(rand)))) },
})),
},
- term => {
- let term = self.let_anon_soft(term)?;
- Ok(GlobDef::VarDef(GVarDef { children: self.children, body: Block { stms: self.stms, term } }))
- }
+ tail => Ok(GlobDef::VarDef(GVarDef {
+ children: self.children,
+ body: Block { stms: self.stms, tail: Box::new(tail) },
+ })),
}
}
- fn abase(&mut self, expr: &FExpr) -> Result<Expr> {
+ fn abase(&mut self, expr: &FExpr) -> Result<Flow<Option<Operation>>> {
use crate::fem::ExprKind::*;
+ fn wrap(rand: Operand) -> Flow<Option<Operation>> {
+ Flow::Leaf(Some(Operation::Wrap(rand)))
+ }
match &expr.kind {
- Bool(x) => Ok(Expr::Operand(Operand::Const(Const::Bool(*x)))),
- &Int(x) => Ok(Expr::Operand(Operand::Const(match expr.typ {
+ Bool(x) => Ok(wrap(Operand::Const(Const::Bool(*x)))),
+ &Int(x) => Ok(wrap(Operand::Const(match expr.typ {
Type::Int { width: 8, signed: true } => Const::I8(x as i8),
Type::Int { width: 16, signed: true } => Const::I16(x as i16),
Type::Int { width: 32, signed: true } => Const::I32(x as i32),
@@ 194,8 202,8 @@ impl<'c> AbaseDef<'c> {
Type::NSize => Const::Nat(x as usize),
ref t => panic!("ice: integer expr has non-integer type {t}"),
}))),
- F64(x) => Ok(Expr::Operand(Operand::Const(Const::F64(*x)))),
- Fun(ps, b) => Ok(Expr::Operand(self.abase_fun(ps, b)?)),
+ F64(x) => Ok(wrap(Operand::Const(Const::F64(*x)))),
+ Fun(ps, b) => Ok(wrap(self.abase_fun(ps, b)?)),
App(f, xs) => match &f.kind {
Var(ResName { res: Res::Prim(p) }) => match p {
Prim::Add => self.abase_binop(xs, Binop::Add),
@@ 220,31 228,32 @@ impl<'c> AbaseDef<'c> {
self.let_anon_soft(x)
})
.collect::<Result<Vec<Operand>>>()?;
- Ok(Expr::Call(f, xs))
+ Ok(Operation::Call(f, xs))
}
- },
- Var(ResName { res: Res::Def(id) }) => Ok(Expr::Operand(Operand::Global(*id))),
+ }
+ .map(|ration| Flow::Leaf(Some(ration))),
+ Var(ResName { res: Res::Def(id) }) => Ok(wrap(Operand::Global(*id))),
&Var(ResName { res: Res::Local(LocalId(id)) }) =>
- Ok(Expr::Operand(Operand::Local(*self.vars.get(id as usize).unwrap_or_else(|| todo!())))),
+ Ok(wrap(Operand::Local(*self.vars.get(id as usize).unwrap_or_else(|| todo!())))),
Var(ResName { res: Res::Prim(_) }) => todo!(), // TODO: generate a closure around the op or smth
Var(ResName { res: Res::Module(_) }) =>
panic!("ice: found module id in expr context when abasing. Should've been caught by type checker."),
If(pred, conseq, alt) => {
let pred_a = self.abase(pred)?;
let pred_a = self.let_anon_soft(pred_a)?;
- let conseq_a = self.enter_block(|self_| self_.abase(conseq).map(Box::new))?;
- let alt_a = self.enter_block(|self_| self_.abase(alt).map(Box::new))?;
- Ok(Expr::If(pred_a, conseq_a, alt_a))
+ let conseq_a = self.enter_block(|self_| self_.abase(conseq))?;
+ let alt_a = self.enter_block(|self_| self_.abase(alt))?;
+ Ok(Flow::Diverge(Diverge::If(pred_a, conseq_a, alt_a)))
}
}
}
- fn abase_binop(&mut self, xs: &[FExpr], op: Binop) -> Result<Expr> {
+ fn abase_binop(&mut self, xs: &[FExpr], op: Binop) -> Result<Operation> {
let x = self.abase(&xs[0])?;
let x = self.let_anon_soft(x)?;
let y = self.abase(&xs[1])?;
let y = self.let_anon_soft(y)?;
- Ok(Expr::Binop(op, x, y))
+ Ok(Operation::Binop(op, x, y))
}
// TODO: closures. capture free vars etc.
@@ 256,7 265,7 @@ impl<'c> AbaseDef<'c> {
let params = params.iter().map(|_| self.gen_local()).collect::<Vec<_>>();
self.vars.extend(¶ms);
- let body = self.enter_block(|self_| self_.abase(body).map(Return::Val))?;
+ let body = self.enter_block(|self_| self_.abase(body))?;
let new_children = std::mem::replace(&mut self.children, old_children);
self.vars = old_vars;
@@ 268,11 277,11 @@ impl<'c> AbaseDef<'c> {
Ok(Operand::Global(fid))
}
- fn enter_block<T>(&mut self, f: impl FnOnce(&mut Self) -> Result<T>) -> Result<Block<T>> {
+ fn enter_block<Leaf>(&mut self, f: impl FnOnce(&mut Self) -> Result<Flow<Leaf>>) -> Result<Block<Leaf>> {
let old_stms = std::mem::take(&mut self.stms);
- let term = f(self)?;
+ let tail = Box::new(f(self)?);
let new_stms = std::mem::replace(&mut self.stms, old_stms);
- Ok(Block { stms: new_stms, term })
+ Ok(Block { stms: new_stms, tail })
}
fn gen_local(&mut self) -> LocalId {
@@ 281,13 290,14 @@ impl<'c> AbaseDef<'c> {
LocalId(self.n_locals - 1)
}
- fn let_anon_soft(&mut self, rhs: Expr) -> Result<Operand> {
+ fn let_anon_soft(&mut self, rhs: Flow<Option<Operation>>) -> Result<Operand> {
match rhs {
- Expr::Operand(rand) => Ok(rand),
+ Flow::Leaf(Some(Operation::Wrap(rand))) => Ok(rand),
_ => self.let_anon_hard(rhs),
}
}
- fn let_anon_hard(&mut self, rhs: Expr) -> Result<Operand> {
+
+ fn let_anon_hard(&mut self, rhs: Flow<Option<Operation>>) -> Result<Operand> {
let lhs = self.gen_local();
self.stms.push(Stm::Let { lhs, rhs });
Ok(Operand::Local(lhs))
@@ 21,29 21,41 @@ impl<'c> EvalDef<'c> {
Self { cache, regs: HashMap::new() }
}
- fn run_fun(mut self, params: &[LocalId], args: &[Operand], body: &Block<Return>) -> Result<Operand> {
+ fn run_fun(mut self, params: &[LocalId], args: &[Operand], body: &Block<Option<Operation>>) -> Result<Operand> {
for (id, arg) in params.iter().zip(args) {
- self.regs.insert(*id, arg.clone());
+ self.regs.insert(*id, *arg);
}
for stm in &body.stms {
self.eval_stm(stm)?;
}
- match &body.term {
- Return::Val(tail) => self.eval(tail),
- }
+ self.eval_div(&body.tail)
}
- fn run_var(mut self, body: &Block<Operand>) -> Result<Operand> {
+ fn run_var(mut self, body: &Block<Option<Operation>>) -> Result<Operand> {
self.eval_stms(&body.stms)?;
- self.eval_operand(body.term)
+ self.eval_div(&body.tail)
+ }
+
+ fn eval_div(&mut self, div: &Flow<Option<Operation>>) -> Result<Operand> {
+ use abase::Const::*;
+ use Operand::*;
+ match div {
+ Flow::Leaf(Some(ration)) => self.eval_op(ration),
+ Flow::Leaf(None) => todo!(),
+ Flow::Diverge(Diverge::If(pred, conseq, alt)) => match self.eval_operand(*pred)? {
+ Const(Bool(true)) => self.eval_stms(&conseq.stms).and_then(|()| self.eval_div(&conseq.tail)),
+ Const(Bool(false)) => self.eval_stms(&alt.stms).and_then(|()| self.eval_div(&alt.tail)),
+ pe => panic!("ice: `if` expects const bool predicate, found {pe:?}"),
+ },
+ }
}
- fn eval(&mut self, expr: &Expr) -> Result<Operand> {
+ fn eval_op(&mut self, ration: &Operation) -> Result<Operand> {
use abase::Const::*;
use Binop::*;
use Operand::*;
- match expr {
- &Expr::Binop(op, x, y) => match (self.eval_operand(x)?, self.eval_operand(y)?) {
+ match ration {
+ &Operation::Binop(op, x, y) => match (self.eval_operand(x)?, self.eval_operand(y)?) {
(Const(x), Const(y)) => Ok(Const(match op {
Add => (x + y).unwrap(),
Sub => (x - y).unwrap(),
@@ 59,19 71,14 @@ impl<'c> EvalDef<'c> {
})),
(x_e, y_e) => panic!("ice: cannot apply binary operation {op:?} to {x_e:?} and {y_e:?}"),
},
- Expr::Call(f, xs) => match self.eval_operand(*f)? {
+ Operation::Call(f, xs) => match self.eval_operand(*f)? {
Global(fid) => {
let xs = xs.iter().map(|x| self.eval_operand(*x)).collect::<Result<Vec<_>>>()?;
self.cache.fetch_evaluated_at(fid, &xs)
}
fe => panic!("ice: applying non-function {fe:?} ({f:?})"),
},
- &Expr::Operand(rand) => self.eval_operand(rand),
- Expr::If(pred, conseq, alt) => match self.eval_operand(*pred)? {
- Const(Bool(true)) => self.eval_stms(&conseq.stms).and_then(|()| self.eval(&conseq.term)),
- Const(Bool(false)) => self.eval_stms(&alt.stms).and_then(|()| self.eval(&alt.term)),
- pe => panic!("ice: `if` expects const bool predicate, found {pe:?}"),
- },
+ &Operation::Wrap(rand) => self.eval_operand(rand),
}
}
@@ 85,7 92,7 @@ impl<'c> EvalDef<'c> {
fn eval_stm(&mut self, stm: &Stm) -> Result<()> {
match stm {
Stm::Let { lhs, rhs } => {
- let val = self.eval(rhs)?;
+ let val = self.eval_div(rhs)?;
self.regs.insert(*lhs, val);
Ok(())
}
@@ 99,7 106,7 @@ impl<'c> EvalDef<'c> {
Operand::Const(_) => return Ok(rand),
Operand::Local(id) =>
if let Some(val) = self.regs.get(&id) {
- rand = val.clone();
+ rand = *val;
} else {
panic!("ice: undefined local {rand:?}\nregs: {:?}", self.regs)
},