~jojo/effem

0b998cedf4910eba99a45f196b8a7800483e6b32 — JoJo 3 months ago 205a36e
add blocks & other functionality to base
3 files changed, 121 insertions(+), 28 deletions(-)

M src/abase.rs
M src/eval.rs
M src/main.rs
M src/abase.rs => src/abase.rs +55 -16
@@ 3,7 3,7 @@
use crate::cache::Cache;
use crate::fem::Expr as FExpr;
use crate::name::*;
use anyhow::anyhow;
use anyhow::{anyhow, Result};

#[derive(Clone)]
pub enum GlobDef {


@@ 15,15 15,32 @@ pub enum GlobDef {
#[derive(Clone)]
pub struct FunDef {
    // Nested definitions (including anonymous functions)
    defs: Vec<(LocalId, GlobDef)>,
    params: Vec<()>,
    body: Expr,
    pub defs: Vec<(LocalId, GlobDef)>,
    pub params: Vec<()>,
    pub body: Block<Return>,
}

#[derive(Clone)]
pub struct GVarDef {
    defs: Vec<(LocalId, GlobDef)>,
    body: Expr,
    pub defs: Vec<(LocalId, GlobDef)>,
    pub body: Block<Operand>,
}

#[derive(Clone)]
pub struct Block<Term> {
    pub stms: Vec<Stm>,
    pub term: Term,
}

#[derive(Clone)]
pub enum Stm {
    Let { lhs: LocalId, rhs: Expr },
}

#[derive(Clone)]
pub enum Return {
    Val(Expr),
    Void,
}

#[derive(Clone)]


@@ 41,12 58,12 @@ pub enum Operand {
    Global(DefId),
}

#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum Const {
    F64(f64),
}

pub fn abase_def(cache: &mut Cache, rhs: &FExpr) -> anyhow::Result<GlobDef> {
pub fn abase_def(cache: &mut Cache, rhs: &FExpr) -> Result<GlobDef> {
    AbaseDef::new(cache).run(rhs)
}



@@ 55,14 72,15 @@ struct AbaseDef<'c> {
    defs: Vec<(LocalId, GlobDef)>,
    vars: Vec<LocalId>,
    n_locals: u32,
    stms: Vec<Stm>,
}

impl<'c> AbaseDef<'c> {
    fn new(cache: &'c mut Cache) -> Self {
        Self { cache, defs: vec![], vars: vec![], n_locals: 0 }
        Self { cache, defs: vec![], vars: vec![], n_locals: 0, stms: vec![] }
    }

    fn run(mut self, rhs: &FExpr) -> anyhow::Result<GlobDef> {
    fn run(mut self, rhs: &FExpr) -> Result<GlobDef> {
        match self.abase(rhs)? {
            Expr::Operand(rand) => match rand {
                Operand::Local(id) => {


@@ 72,20 90,35 @@ impl<'c> AbaseDef<'c> {
                    Ok(self.defs.pop().unwrap().1)
                }
                Operand::Global(id) => Ok(GlobDef::Alias(id)),
                _ => Ok(GlobDef::VarDef(GVarDef { defs: self.defs, body: Expr::Operand(rand) })),
                _ => Ok(GlobDef::VarDef(GVarDef { defs: self.defs, body: Block { stms: self.stms, term: rand } })),
            },
            body => Ok(GlobDef::VarDef(GVarDef { defs: self.defs, body })),
            term => {
                let term = self.emit_let_anon(term)?;
                Ok(GlobDef::VarDef(GVarDef { defs: self.defs, body: Block { stms: self.stms, term } }))
            }
        }
    }

    fn abase(&mut self, expr: &FExpr) -> anyhow::Result<Expr> {
    fn abase(&mut self, expr: &FExpr) -> Result<Expr> {
        match *expr {
            FExpr::F64(x) => Ok(Expr::Operand(Operand::Const(Const::F64(x)))),
            FExpr::Fun(ref ps, ref b) => Ok(Expr::Operand(Operand::Local(self.abase_fun(ps, b)?))),
            FExpr::App(ref f, ref xs) => Ok(match **f {
                FExpr::Var(ResName { res: Res::Prim(p) }) => match p {
                    Prim::Add => todo!(),
                    Prim::Mul => todo!(),
                    Prim::Add => {
                        let x = self.abase(&xs[0])?;
                        let x = self.emit_let_anon(x)?;
                        let y = self.abase(&xs[1])?;
                        let y = self.emit_let_anon(y)?;
                        Expr::Add(x, y)
                    }
                    Prim::Mul => {
                        let x = self.abase(&xs[0])?;
                        let x = self.emit_let_anon(x)?;
                        let y = self.abase(&xs[1])?;
                        let y = self.emit_let_anon(y)?;
                        Expr::Mul(x, y)
                    }
                },
                _ => todo!(),
            }),


@@ 100,7 133,7 @@ impl<'c> AbaseDef<'c> {
        }
    }

    fn abase_fun(&mut self, params: &[(PubIdent, LocalId)], body: &FExpr) -> anyhow::Result<LocalId> {
    fn abase_fun(&mut self, params: &[(PubIdent, LocalId)], body: &FExpr) -> Result<LocalId> {
        // TODO: closures. capture free vars etc.

        todo!()


@@ 111,4 144,10 @@ impl<'c> AbaseDef<'c> {
        self.n_locals += 1;
        self.n_locals - 1
    }

    fn emit_let_anon(&mut self, rhs: Expr) -> Result<Operand> {
        let lhs = self.gen_local();
        self.stms.push(Stm::Let { lhs, rhs });
        Ok(Operand::Local(lhs))
    }
}

M src/eval.rs => src/eval.rs +61 -7
@@ 1,10 1,13 @@
use crate::abase::{Expr, GlobDef};
use crate::abase::{Const, Expr, FunDef, GVarDef, GlobDef, Operand, Stm};
use crate::{cache::Cache, name::*};
use anyhow::Result;
use std::collections::HashMap;

#[derive(Debug, Clone, PartialEq)]
pub enum Val {
    F64(f64),
}
// #[derive(Debug, Clone, PartialEq)]
// pub enum Val {
//     F64(f64),
// }
pub type Val = Const;

impl std::ops::Add for Val {
    type Output = Val;


@@ 23,6 26,57 @@ impl std::ops::Mul for Val {
    }
}

pub fn eval_def(cache: &mut Cache, def: &GlobDef) -> anyhow::Result<Val> {
    todo!()
pub fn eval_def(cache: &mut Cache, def: &GlobDef) -> Result<Val> {
    EvalDef::new(cache).run(def)
}

struct EvalDef<'c> {
    cache: &'c mut Cache,
    regs: HashMap<LocalId, Val>,
}

impl<'c> EvalDef<'c> {
    fn new(cache: &'c mut Cache) -> Self {
        Self { cache, regs: HashMap::new() }
    }

    fn run(mut self, def: &GlobDef) -> Result<Val> {
        match def {
            GlobDef::FunDef(FunDef { defs, params, body }) => todo!(),
            GlobDef::VarDef(GVarDef { defs, body }) if defs.is_empty() => {
                for stm in &body.stms {
                    self.eval_stm(stm)?;
                }
                self.eval_operand(&body.term)
            }
            GlobDef::VarDef(GVarDef { defs, body }) => todo!(),
            GlobDef::Alias(target) => self.cache.fetch_evaluated(*target).cloned(),
        }
    }

    fn eval(&mut self, expr: &Expr) -> Result<Val> {
        match expr {
            Expr::Add(x, y) => Ok(self.eval_operand(x)? + self.eval_operand(y)?),
            Expr::Mul(x, y) => Ok(self.eval_operand(x)? * self.eval_operand(y)?),
            Expr::Operand(rand) => self.eval_operand(rand),
        }
    }

    fn eval_stm(&mut self, stm: &Stm) -> Result<()> {
        match stm {
            Stm::Let { lhs, rhs } => {
                let val = self.eval(rhs)?;
                self.regs.insert(*lhs, val);
                Ok(())
            }
        }
    }

    fn eval_operand(&mut self, rand: &Operand) -> Result<Val> {
        match rand {
            Operand::Const(x) => Ok(x.clone()),
            Operand::Local(id) => Ok(self.regs.get(id).unwrap_or_else(|| todo!()).clone()),
            Operand::Global(id) => self.cache.fetch_evaluated(*id).cloned(),
        }
    }
}

M src/main.rs => src/main.rs +5 -5
@@ 56,17 56,17 @@ mod test {

    #[test]
    fn test_main_literal() {
        assert_eq!(run_tmp("(def main 123.456)").unwrap(), Val::F64(123.456))
        assert!(matches!(run_tmp("(def main 123.456)"), Ok(Val::F64(x)) if x == 123.456))
    }

    #[test]
    fn test_main_arithm1() {
        assert_eq!(run_tmp("(def main (+.prim. 1.0 2.0))").unwrap(), Val::F64(3.0))
        assert!(matches!(run_tmp("(def main (+.prim. 1.0 2.0))"), Ok(Val::F64(x)) if x == 3.0))
    }

    #[test]
    fn test_main_arithm2() {
        assert_eq!(run_tmp("(def main (+.prim. (*.prim. 13.0 100.0) 37.0))").unwrap(), Val::F64(1337.0))
        assert!(matches!(run_tmp("(def main (+.prim. (*.prim. 13.0 100.0) 37.0))"), Ok(Val::F64(x)) if x == 1337.0))
    }

    #[test]


@@ 75,7 75,7 @@ mod test {
            (def x 1300.0)
            (def main (+ x 37.0))
        ";
        assert_eq!(run_tmp(src).unwrap(), Val::F64(1337.0))
        assert!(matches!(run_tmp(src), Ok(Val::F64(x)) if x == 1337.0))
    }

    #[test]


@@ 84,6 84,6 @@ mod test {
            (def main (double 21.0))
            (def double (fun [x] (* x 2.0)))
        ";
        assert_eq!(run_tmp(src).unwrap(), Val::F64(42.0))
        assert!(matches!(run_tmp(src), Ok(Val::F64(x)) if x == 42.0))
    }
}