M src/abase.rs => src/abase.rs +71 -200
@@ 1,190 1,66 @@
//! Base -- the lowest level IR in Effem before generating the output machine code.
use crate::prelude::*;
-use fem::{Expr as FExpr, Type};
-use std::collections::HashSet;
-
-#[derive(Clone, Debug)]
-pub enum GlobDef {
- FunDef(FunDef),
- VarDef(GVarDef),
- Alias(DefId),
-}
-
-#[derive(Clone, Debug)]
-pub struct FunDef {
- // Nested definitions (including anonymous functions)
- pub children: HashSet<DefId>,
- pub params: Vec<LocalId>,
- pub body: Block<Option<Operation>>,
-}
-
-#[derive(Clone, Debug)]
-pub struct GVarDef {
- pub children: HashSet<DefId>,
- pub body: Block<Option<Operation>>,
-}
-
-#[derive(Debug, Clone)]
-pub struct Block<Leaf> {
- pub stms: Vec<Stm>,
- pub tail: Box<Flow<Leaf>>,
-}
-
-#[derive(Debug, Clone)]
-pub enum Stm {
- Let { lhs: LocalId, rhs: Flow<Option<Operation>> },
-}
-
-#[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 Operation {
- Binop(Binop, Operand, Operand),
- Call(Operand, Vec<Operand>),
- Wrap(Operand),
-}
-
-#[derive(Debug, Clone, Copy)]
-pub enum Binop {
- Add,
- Sub,
- Mul,
- Quot,
- Rem,
- Lt,
- Gt,
- Leq,
- Geq,
- Eq,
- Neq,
-}
-
-#[derive(Debug, Clone, Copy)]
-pub enum Operand {
- Const(Const),
- // Extern Extern
- Local(LocalId),
- Global(DefId),
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
-pub enum Const {
- Bool(bool),
- I8(i8),
- I16(i16),
- I32(i32),
- I64(i64),
- Int(isize),
- N8(u8),
- N16(u16),
- N32(u32),
- N64(u64),
- Nat(usize),
- F64(f64),
-}
-
-macro_rules! impl_const_from {
- ($t:ty, $c:expr) => {
- impl From<$t> for Const {
- fn from(x: $t) -> Const {
- $c(x)
- }
- }
- };
-}
-
-impl_const_from!(bool, Const::Bool);
-impl_const_from!(i8, Const::I8);
-impl_const_from!(i16, Const::I16);
-impl_const_from!(i32, Const::I32);
-impl_const_from!(i64, Const::I64);
-impl_const_from!(isize, Const::Int);
-impl_const_from!(u8, Const::N8);
-impl_const_from!(u16, Const::N16);
-impl_const_from!(u32, Const::N32);
-impl_const_from!(u64, Const::N64);
-impl_const_from!(usize, Const::Nat);
-impl_const_from!(f64, Const::F64);
-
-macro_rules! impl_const_arithm_binop {
- ($op_trait:ty, $op_name:ident) => {
- impl $op_trait for Const {
- type Output = Option<Const>;
- fn $op_name(self, other: Self) -> Self::Output {
- match (self, other) {
- (Const::I8(x), Const::I8(y)) => Some(x.$op_name(y).into()),
- (Const::I16(x), Const::I16(y)) => Some(x.$op_name(y).into()),
- (Const::I32(x), Const::I32(y)) => Some(x.$op_name(y).into()),
- (Const::I64(x), Const::I64(y)) => Some(x.$op_name(y).into()),
- (Const::Int(x), Const::Int(y)) => Some(x.$op_name(y).into()),
- (Const::N8(x), Const::N8(y)) => Some(x.$op_name(y).into()),
- (Const::N16(x), Const::N16(y)) => Some(x.$op_name(y).into()),
- (Const::N32(x), Const::N32(y)) => Some(x.$op_name(y).into()),
- (Const::N64(x), Const::N64(y)) => Some(x.$op_name(y).into()),
- (Const::Nat(x), Const::Nat(y)) => Some(x.$op_name(y).into()),
- (Const::F64(x), Const::F64(y)) => Some(x.$op_name(y).into()),
- _ => None,
- }
- }
- }
- };
-}
-
-impl_const_arithm_binop!(std::ops::Add, add);
-impl_const_arithm_binop!(std::ops::Sub, sub);
-impl_const_arithm_binop!(std::ops::Mul, mul);
-impl_const_arithm_binop!(std::ops::Div, div);
-impl_const_arithm_binop!(std::ops::Rem, rem);
+use base::*;
+use fem::{Expr as FExpr, ExprKind as FExprKind, Type};
+use std::collections::{HashMap, HashSet};
pub fn abase_def(cache: &mut Cache, rhs: &FExpr) -> Result<GlobDef> {
- AbaseDef::new(cache).run(rhs)
+ if let FExprKind::Fun(params, body) = &rhs.kind {
+ AbaseDef::new(cache).run_fun(params, body).map(GlobDef::FunDef)
+ } else {
+ AbaseDef::new(cache).run_var(rhs).map(GlobDef::VarDef)
+ }
}
#[derive(Debug)]
struct AbaseDef<'c> {
cache: &'c mut Cache,
children: HashSet<DefId>,
- vars: Vec<LocalId>,
- n_locals: u32,
- stms: Vec<Stm>,
+ locals: HashMap<LocalId, Operand>,
+ stm_arena: Vec<Stm>,
+ block_arena: Vec<Block>,
+ current_stms: Vec<StmRef>,
}
impl<'c> AbaseDef<'c> {
fn new(cache: &'c mut Cache) -> Self {
- Self { cache, children: HashSet::new(), vars: vec![], n_locals: 0, stms: vec![] }
+ Self {
+ cache,
+ children: HashSet::new(),
+ locals: HashMap::new(),
+ stm_arena: vec![],
+ block_arena: vec![],
+ current_stms: vec![],
+ }
}
- fn run(mut self, rhs: &FExpr) -> Result<GlobDef> {
- match self.abase(rhs)? {
- 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, tail: Box::new(Flow::Leaf(Some(Operation::Wrap(rand)))) },
- })),
- },
- tail => Ok(GlobDef::VarDef(GVarDef {
- children: self.children,
- body: Block { stms: self.stms, tail: Box::new(tail) },
- })),
- }
+ fn run_var(mut self, rhs: &FExpr) -> Result<GVarDef> {
+ let root = self.enter_block(|self_| self_.abase(rhs))?;
+ // TODO: assert ret is not Local
+ Ok(GVarDef {
+ children: self.children,
+ body: Body { stm_arena: self.stm_arena, block_arena: self.block_arena, root },
+ })
+ }
+
+ fn run_fun(mut self, params: &[(PubIdent, LocalId)], body: &FExpr) -> Result<FunDef> {
+ self.locals.extend(params.iter().enumerate().map(|(i, &(_, lid @ LocalId(i2)))| {
+ debug_assert_eq!(i, i2 as usize);
+ (lid, Operand::Param(ParamRef(i2)))
+ }));
+ let root = self.enter_block(|self_| self_.abase(body))?;
+ Ok(FunDef {
+ children: self.children,
+ params: params.iter().map(|_| ()).collect(),
+ body: Body { stm_arena: self.stm_arena, block_arena: self.block_arena, root },
+ })
}
- fn abase(&mut self, expr: &FExpr) -> Result<Flow<Option<Operation>>> {
+ fn abase(&mut self, expr: &FExpr) -> Result<Flow> {
use crate::fem::ExprKind::*;
- fn wrap(rand: Operand) -> Flow<Option<Operation>> {
- Flow::Leaf(Some(Operation::Wrap(rand)))
+ fn wrap(rand: Operand) -> Flow {
+ Flow::Produce(Operation::Wrap(rand))
}
match &expr.kind {
Bool(x) => Ok(wrap(Operand::Const(Const::Bool(*x)))),
@@ 231,10 107,9 @@ impl<'c> AbaseDef<'c> {
Ok(Operation::Call(f, xs))
}
}
- .map(|ration| Flow::Leaf(Some(ration))),
+ .map(Flow::Produce),
Var(ResName { res: Res::Def(id) }) => Ok(wrap(Operand::Global(*id))),
- &Var(ResName { res: Res::Local(LocalId(id)) }) =>
- Ok(wrap(Operand::Local(*self.vars.get(id as usize).unwrap_or_else(|| todo!())))),
+ &Var(ResName { res: Res::Local(id) }) => Ok(wrap(self.locals[&id])),
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."),
@@ 258,48 133,44 @@ impl<'c> AbaseDef<'c> {
// TODO: closures. capture free vars etc.
fn abase_fun(&mut self, params: &[(PubIdent, LocalId)], body: &FExpr) -> Result<Operand> {
- let old_children = std::mem::take(&mut self.children);
- let old_vars = std::mem::take(&mut self.vars);
-
- debug_assert!(params.iter().enumerate().all(|(i, &(_, LocalId(param_id)))| param_id as usize == i));
- let params = params.iter().map(|_| self.gen_local()).collect::<Vec<_>>();
- self.vars.extend(¶ms);
-
- let body = self.enter_block(|self_| self_.abase(body))?;
-
- let new_children = std::mem::replace(&mut self.children, old_children);
- self.vars = old_vars;
-
- let def = FunDef { children: new_children, params, body };
- let fid = self.cache.insert_base_anon(GlobDef::FunDef(def));
+ let fdef = AbaseDef::new(self.cache).run_fun(params, body)?;
+ let fid = self.cache.insert_base_anon(GlobDef::FunDef(fdef));
self.children.insert(fid);
-
Ok(Operand::Global(fid))
}
- 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 tail = Box::new(f(self)?);
- let new_stms = std::mem::replace(&mut self.stms, old_stms);
- Ok(Block { stms: new_stms, tail })
+ fn enter_block(&mut self, f: impl FnOnce(&mut Self) -> Result<Flow>) -> Result<BlockRef> {
+ let old_stms = std::mem::take(&mut self.current_stms);
+ let tail = f(self)?;
+ let new_stms = std::mem::replace(&mut self.current_stms, old_stms);
+ Ok(self.add_block(Block { stms: new_stms, tail }))
}
- fn gen_local(&mut self) -> LocalId {
- assert!(self.n_locals < u32::MAX);
- self.n_locals += 1;
- LocalId(self.n_locals - 1)
+ fn add_block(&mut self, block: Block) -> BlockRef {
+ let i = self.block_arena.len();
+ assert!(i < u32::MAX as usize);
+ self.block_arena.push(block);
+ BlockRef(i as u32)
}
- fn let_anon_soft(&mut self, rhs: Flow<Option<Operation>>) -> Result<Operand> {
+ fn let_anon_soft(&mut self, rhs: Flow) -> Result<Operand> {
match rhs {
- Flow::Leaf(Some(Operation::Wrap(rand))) => Ok(rand),
+ Flow::Produce(Operation::Wrap(rand)) => Ok(rand),
_ => self.let_anon_hard(rhs),
}
}
- 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))
+ fn let_anon_hard(&mut self, rhs: Flow) -> Result<Operand> {
+ let lhs = self.add_stm(Stm::Let { rhs });
+ Ok(Operand::Var(lhs))
+ }
+
+ fn add_stm(&mut self, stm: Stm) -> StmRef {
+ let i = self.stm_arena.len();
+ assert!(i < u32::MAX as usize);
+ self.stm_arena.push(stm);
+ let stm_ref = StmRef(i as u32);
+ self.current_stms.push(stm_ref);
+ stm_ref
}
}
A src/base.rs => src/base.rs +171 -0
@@ 0,0 1,171 @@
+use crate::prelude::*;
+use std::collections::HashSet;
+
+#[derive(Clone, Debug)]
+pub enum GlobDef {
+ FunDef(FunDef),
+ VarDef(GVarDef),
+}
+
+#[derive(Clone, Debug)]
+pub struct FunDef {
+ // Nested definitions (including anonymous functions)
+ pub children: HashSet<DefId>,
+ pub params: Vec<()>,
+ pub body: Body,
+}
+
+#[derive(Clone, Debug)]
+pub struct GVarDef {
+ pub children: HashSet<DefId>,
+ pub body: Body,
+}
+
+#[derive(Debug, Clone)]
+pub struct Body {
+ pub stm_arena: Vec<Stm>,
+ pub block_arena: Vec<Block>,
+ pub root: BlockRef,
+}
+
+#[derive(Debug, Clone)]
+pub struct Block {
+ pub stms: Vec<StmRef>,
+ pub tail: Flow,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct BlockRef(pub u32);
+
+#[derive(Debug, Clone)]
+pub enum Stm {
+ Let { rhs: Flow },
+ // Store { val: Operand, dst: Operand },
+ // VoidCall { proc: Operand, out: Option<Operand>, args: Vec<Pass<Operand>> }
+ // SLoop (Loop ())
+ // SBranch (Branch ())
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct StmRef(pub u32);
+
+#[derive(Debug, Clone)]
+pub enum Flow {
+ Diverge(Diverge),
+ // Void,
+ Produce(Operation),
+ // Continue(Vec<Operand>) // only valid in loops
+}
+
+#[derive(Debug, Clone)]
+pub enum Diverge {
+ If(Operand, BlockRef, BlockRef),
+}
+
+// pub struct Loop {
+// pub params: Vec<(LocalId, Operand)>,
+// pub body: Block,
+// }
+
+#[derive(Clone, Debug)]
+pub enum Operation {
+ Binop(Binop, Operand, Operand),
+ Call(Operand, Vec<Operand>),
+ Wrap(Operand),
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum Binop {
+ Add,
+ Sub,
+ Mul,
+ Quot,
+ Rem,
+ Lt,
+ Gt,
+ Leq,
+ Geq,
+ Eq,
+ Neq,
+}
+
+#[derive(Debug, Clone, Copy)]
+pub enum Operand {
+ Const(Const),
+ // Extern Extern
+ Var(StmRef),
+ Param(ParamRef),
+ Global(DefId),
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct ParamRef(pub u32);
+
+#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
+pub enum Const {
+ Bool(bool),
+ I8(i8),
+ I16(i16),
+ I32(i32),
+ I64(i64),
+ Int(isize),
+ N8(u8),
+ N16(u16),
+ N32(u32),
+ N64(u64),
+ Nat(usize),
+ F64(f64),
+}
+
+macro_rules! impl_const_from {
+ ($t:ty, $c:expr) => {
+ impl From<$t> for Const {
+ fn from(x: $t) -> Const {
+ $c(x)
+ }
+ }
+ };
+}
+
+impl_const_from!(bool, Const::Bool);
+impl_const_from!(i8, Const::I8);
+impl_const_from!(i16, Const::I16);
+impl_const_from!(i32, Const::I32);
+impl_const_from!(i64, Const::I64);
+impl_const_from!(isize, Const::Int);
+impl_const_from!(u8, Const::N8);
+impl_const_from!(u16, Const::N16);
+impl_const_from!(u32, Const::N32);
+impl_const_from!(u64, Const::N64);
+impl_const_from!(usize, Const::Nat);
+impl_const_from!(f64, Const::F64);
+
+macro_rules! impl_const_arithm_binop {
+ ($op_trait:ty, $op_name:ident) => {
+ impl $op_trait for Const {
+ type Output = Option<Const>;
+ fn $op_name(self, other: Self) -> Self::Output {
+ match (self, other) {
+ (Const::I8(x), Const::I8(y)) => Some(x.$op_name(y).into()),
+ (Const::I16(x), Const::I16(y)) => Some(x.$op_name(y).into()),
+ (Const::I32(x), Const::I32(y)) => Some(x.$op_name(y).into()),
+ (Const::I64(x), Const::I64(y)) => Some(x.$op_name(y).into()),
+ (Const::Int(x), Const::Int(y)) => Some(x.$op_name(y).into()),
+ (Const::N8(x), Const::N8(y)) => Some(x.$op_name(y).into()),
+ (Const::N16(x), Const::N16(y)) => Some(x.$op_name(y).into()),
+ (Const::N32(x), Const::N32(y)) => Some(x.$op_name(y).into()),
+ (Const::N64(x), Const::N64(y)) => Some(x.$op_name(y).into()),
+ (Const::Nat(x), Const::Nat(y)) => Some(x.$op_name(y).into()),
+ (Const::F64(x), Const::F64(y)) => Some(x.$op_name(y).into()),
+ _ => None,
+ }
+ }
+ }
+ };
+}
+
+impl_const_arithm_binop!(std::ops::Add, add);
+impl_const_arithm_binop!(std::ops::Sub, sub);
+impl_const_arithm_binop!(std::ops::Mul, mul);
+impl_const_arithm_binop!(std::ops::Div, div);
+impl_const_arithm_binop!(std::ops::Rem, rem);
M src/cache.rs => src/cache.rs +11 -12
@@ 23,8 23,8 @@ pub struct Cache {
resolveds: HashMap<DefId, RExpr>,
sigs: HashMap<DefId, Fetch<fem::Type>>,
checkeds: HashMap<DefId, Fetch<fem::Expr>>,
- abaseds: HashMap<DefId, abase::GlobDef>,
- evaluateds: HashMap<DefId, abase::Operand>,
+ abaseds: HashMap<DefId, base::GlobDef>,
+ evaluateds: HashMap<DefId, base::Operand>,
}
impl Cache {
@@ 49,35 49,34 @@ impl Cache {
}
}
- pub fn fetch_evaluated_at(&mut self, fundef_query: DefId, args: &[abase::Operand]) -> Result<abase::Operand> {
+ pub fn fetch_evaluated_at(&mut self, fundef_query: DefId, args: &[base::Operand]) -> Result<base::Operand> {
#[cfg(debug_assertions)]
- for arg in args.iter().filter(|arg| matches!(arg, abase::Operand::Local(_))) {
- panic!("ice: Local operand {arg:?} as arg to another function");
+ for arg in args.iter().filter(|arg| !matches!(arg, base::Operand::Const(_) | base::Operand::Global(_))) {
+ panic!("ice: Local scope operand {arg:?} as arg to another function");
}
let _ = self.fetch_evaluated(fundef_query)?;
match self.abaseds[&fundef_query] {
- abase::GlobDef::FunDef(ref fdef) => eval::eval_fun_at(self, &fdef.clone(), args),
+ base::GlobDef::FunDef(ref fdef) => eval::eval_fun_at(self, &fdef.clone(), args),
ref def => panic!("ice: {def:?} is not a function def. Cannot evaluate at arguments."),
}
}
- pub fn fetch_evaluated(&mut self, def_query: DefId) -> Result<&abase::Operand> {
+ pub fn fetch_evaluated(&mut self, def_query: DefId) -> Result<&base::Operand> {
if self.evaluateds.contains_key(&def_query) {
Ok(self.evaluateds.get(&def_query).unwrap())
} else {
let base = self.fetch_base(def_query)?.clone();
let val = match base {
- abase::GlobDef::VarDef(def) => eval::eval_var(self, &def)?,
- abase::GlobDef::Alias(target) => self.fetch_evaluated(target)?.clone(),
- abase::GlobDef::FunDef(_) => abase::Operand::Global(def_query),
+ base::GlobDef::VarDef(def) => eval::eval_var(self, &def)?,
+ base::GlobDef::FunDef(_) => base::Operand::Global(def_query),
};
self.evaluateds.insert(def_query, val);
Ok(&self.evaluateds[&def_query])
}
}
- pub fn fetch_base(&mut self, def_query: DefId) -> Result<&abase::GlobDef> {
+ pub fn fetch_base(&mut self, def_query: DefId) -> Result<&base::GlobDef> {
Ok(if self.abaseds.contains_key(&def_query) {
&self.abaseds[&def_query]
} else {
@@ 91,7 90,7 @@ impl Cache {
})
}
- pub fn insert_base_anon(&mut self, def: abase::GlobDef) -> DefId {
+ pub fn insert_base_anon(&mut self, def: base::GlobDef) -> DefId {
let def_id = self.gen_def_id();
self.abaseds.insert(def_id, def);
def_id
M src/eval.rs => src/eval.rs +45 -48
@@ 1,57 1,75 @@
use crate::prelude::*;
use abase::*;
+use base::*;
use std::collections::HashMap;
pub fn eval_fun_at(cache: &mut Cache, def: &FunDef, args: &[Operand]) -> Result<Operand> {
- EvalDef::new(cache).run_fun(&def.params, args, &def.body)
+ EvalDef::new(cache, &def.body, args).run()
}
pub fn eval_var(cache: &mut Cache, def: &GVarDef) -> Result<Operand> {
- EvalDef::new(cache).run_var(&def.body)
+ EvalDef::new(cache, &def.body, &[]).run()
}
#[derive(Debug)]
-struct EvalDef<'c> {
+struct EvalDef<'c, 'd, 'a> {
cache: &'c mut Cache,
- regs: HashMap<LocalId, Operand>,
+ body: &'d Body,
+ args: &'a [Operand],
+ vars: HashMap<StmRef, Operand>,
}
-impl<'c> EvalDef<'c> {
- fn new(cache: &'c mut Cache) -> Self {
- Self { cache, regs: HashMap::new() }
+impl<'c, 'd, 'a> EvalDef<'c, 'd, 'a> {
+ fn new(cache: &'c mut Cache, body: &'d Body, args: &'a [Operand]) -> Self {
+ Self { cache, body, args, vars: HashMap::new() }
}
- 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);
- }
- for stm in &body.stms {
- self.eval_stm(stm)?;
+ fn run(mut self) -> Result<Operand> {
+ self.eval_block_ref(self.body.root)
+ }
+
+ fn eval_block_ref(&mut self, BlockRef(i): BlockRef) -> Result<Operand> {
+ self.eval_block(&self.body.block_arena[i as usize])
+ }
+
+ fn eval_block(&mut self, block: &Block) -> Result<Operand> {
+ self.eval_stms(&block.stms)?;
+ self.eval_div(&block.tail)
+ }
+
+ fn eval_stms(&mut self, stms: &[StmRef]) -> Result<()> {
+ for &stm in stms {
+ self.eval_stm_ref(stm)?;
}
- self.eval_div(&body.tail)
+ Ok(())
}
- fn run_var(mut self, body: &Block<Option<Operation>>) -> Result<Operand> {
- self.eval_stms(&body.stms)?;
- self.eval_div(&body.tail)
+ fn eval_stm_ref(&mut self, lhs @ StmRef(i): StmRef) -> Result<()> {
+ let stm = &self.body.stm_arena[i as usize];
+ match stm {
+ Stm::Let { rhs } => {
+ let val = self.eval_div(rhs)?;
+ self.vars.insert(lhs, val);
+ Ok(())
+ }
+ }
}
- fn eval_div(&mut self, div: &Flow<Option<Operation>>) -> Result<Operand> {
- use abase::Const::*;
+ fn eval_div(&mut self, div: &Flow) -> Result<Operand> {
+ use base::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)),
+ Flow::Produce(ration) => self.eval_op(ration),
+ &Flow::Diverge(Diverge::If(pred, conseq, alt)) => match self.eval_operand(pred)? {
+ Const(Bool(true)) => self.eval_block_ref(conseq),
+ Const(Bool(false)) => self.eval_block_ref(alt),
pe => panic!("ice: `if` expects const bool predicate, found {pe:?}"),
},
}
}
fn eval_op(&mut self, ration: &Operation) -> Result<Operand> {
- use abase::Const::*;
+ use base::Const::*;
use Binop::*;
use Operand::*;
match ration {
@@ 82,34 100,13 @@ impl<'c> EvalDef<'c> {
}
}
- fn eval_stms(&mut self, stms: &[Stm]) -> Result<()> {
- for stm in stms {
- self.eval_stm(stm)?;
- }
- Ok(())
- }
-
- fn eval_stm(&mut self, stm: &Stm) -> Result<()> {
- match stm {
- Stm::Let { lhs, rhs } => {
- let val = self.eval_div(rhs)?;
- self.regs.insert(*lhs, val);
- Ok(())
- }
- }
- }
-
fn eval_operand(&mut self, mut rand: Operand) -> Result<Operand> {
let max_loops = 64;
for _ in 0..max_loops {
match rand {
Operand::Const(_) => return Ok(rand),
- Operand::Local(id) =>
- if let Some(val) = self.regs.get(&id) {
- rand = *val;
- } else {
- panic!("ice: undefined local {rand:?}\nregs: {:?}", self.regs)
- },
+ Operand::Param(ParamRef(i)) => rand = self.args[i as usize],
+ Operand::Var(x) => rand = self.vars[&x],
Operand::Global(id) => match *self.cache.fetch_evaluated(id)? {
Operand::Global(id2) if id == id2 => return Ok(Operand::Global(id)),
rand2 => rand = rand2,
M src/main.rs => src/main.rs +2 -0
@@ 5,6 5,7 @@
#![allow(clippy::map_entry)]
mod abase;
+mod base;
mod cache;
mod check;
mod desugar;
@@ 72,6 73,7 @@ fn parse_source_file_path(p: &Path) -> (&Path, &str) {
mod test {
use super::*;
use abase::*;
+ use base::*;
use diag::Result;
use eval::*;
use std::assert_matches::assert_matches;
M src/prelude.rs => src/prelude.rs +1 -1
@@ 1,4 1,4 @@
-pub(crate) use crate::{abase, cache, check, diag, eval, fem, lex, name, parse, resolve};
+pub(crate) use crate::{abase, base, cache, check, diag, eval, fem, lex, name, parse, resolve};
pub(crate) use cache::{Cache, Fetch};
pub(crate) use diag::*;
pub(crate) use name::*;