~jojo/effem

afdbcfdbedf4c35a7dc34ab6e004c1c53aabcc2c — JoJo 3 months ago 798d0fc
fix infinite recursion on recursive def
8 files changed, 133 insertions(+), 45 deletions(-)

M src/abase.rs
M src/cache.rs
M src/check.rs
M src/diag.rs
M src/eval.rs
M src/main.rs
M src/parse.rs
M src/prelude.rs
M src/abase.rs => src/abase.rs +1 -4
@@ 223,10 223,7 @@ impl<'c> AbaseDef<'c> {
                    Ok(Expr::Call(f, xs))
                }
            },
            Var(ResName { res: Res::Def(id) }) => {
                let _ = self.cache.fetch_base(*id)?;
                Ok(Expr::Operand(Operand::Global(*id)))
            }
            Var(ResName { res: Res::Def(id) }) => Ok(Expr::Operand(Operand::Global(*id))),
            Var(ResName { res: Res::Local(id) }) =>
                Ok(Expr::Operand(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

M src/cache.rs => src/cache.rs +90 -27
@@ 3,9 3,11 @@ use parse::{Expr as PExpr, Module as PModule};
use resolve::Expr as RExpr;
use std::borrow::Borrow;
use std::collections::hash_map::{Entry, HashMap};
use std::hash::Hash;
use std::path::{Path, PathBuf};
use std::rc::Rc;

#[derive(Debug)]
pub struct Cache {
    root_dir: PathBuf,
    n_defs: u32,


@@ 13,13 15,14 @@ pub struct Cache {
    sources: HashMap<FileId, String>,
    file_paths: HashMap<FileId, PathBuf>,
    module_files: HashMap<ModuleId, FileId>,
    parsed_modules: HashMap<ModuleId, PModule>,
    parsed_modules: HashMap<ModuleId, HashMap<String, (Loc, PExpr)>>,
    parent_modules: HashMap<DefId, ModuleId>,
    resolved_names: HashMap<FullName<String>, Res>,
    resolved_names_rev: HashMap<Res, FullName<String>>,
    module_local_resolved_names: HashMap<ModuleId, HashMap<String, Res>>,
    resolveds: HashMap<DefId, RExpr>,
    checkeds: HashMap<DefId, fem::Expr>,
    sigs: HashMap<DefId, Fetch<fem::Type>>,
    checkeds: HashMap<DefId, Fetch<fem::Expr>>,
    abaseds: HashMap<DefId, abase::GlobDef>,
    evaluateds: HashMap<DefId, abase::Operand>,
}


@@ 39,6 42,7 @@ impl Cache {
            parent_modules: HashMap::new(),
            module_local_resolved_names: HashMap::new(),
            resolveds: HashMap::new(),
            sigs: HashMap::new(),
            checkeds: HashMap::new(),
            abaseds: HashMap::new(),
            evaluateds: HashMap::new(),


@@ 72,21 76,48 @@ impl Cache {
        Ok(if self.abaseds.contains_key(&def_query) {
            &self.abaseds[&def_query]
        } else {
            let checked: fem::Expr = self.fetch_checked(def_query)?.clone();
            let checked: fem::Expr = match self.fetch_checked(def_query)? {
                Fetch::Done(x) => x.clone(),
                Fetch::Sentinel => panic!("ice: sentinel value when fetching checked in fetch_base"),
            };
            let base = abase::abase_def(self, &checked)?;
            self.abaseds.insert(def_query, base);
            &self.abaseds[&def_query]
        })
    }

    pub fn fetch_checked(&mut self, def_query: DefId) -> Result<&fem::Expr> {
    pub fn fetch_checked(&mut self, def_query: DefId) -> Result<Fetch<&fem::Expr>> {
        if self.checkeds.contains_key(&def_query) {
            Ok(&self.checkeds[&def_query])
            Ok(self.checkeds[&def_query].as_ref())
        } else {
            self.checkeds.insert(def_query, Fetch::Sentinel);
            let desugared: RExpr = self.fetch_desugared(def_query)?.clone();
            let checked = check::check_def(self, &desugared)?;
            self.checkeds.insert(def_query, checked);
            Ok(&self.checkeds[&def_query])
            self.checkeds.insert(def_query, Fetch::Done(checked));
            Ok(self.checkeds[&def_query].as_ref())
        }
    }

    pub fn fetch_sig(&mut self, def_query: DefId) -> Result<Fetch<&fem::Type>> {
        if self.sigs.contains_key(&def_query) {
            Ok(self.sigs[&def_query].as_ref())
        } else {
            self.sigs.insert(def_query, Fetch::Sentinel);
            let desugared: RExpr = self.fetch_desugared(def_query)?.clone();
            if let resolve::ExprKind::Annot(_, sig) = &desugared.kind {
                if let Some(sig) = sig.to_fem() {
                    self.sigs.insert(def_query, Fetch::Done(sig));
                    return Ok(self.sigs[&def_query].as_ref());
                }
            }
            match self.fetch_checked(def_query)? {
                Fetch::Done(checked) => {
                    let typ = checked.typ.clone();
                    self.sigs.insert(def_query, Fetch::Done(typ));
                    Ok(self.sigs[&def_query].as_ref())
                }
                Fetch::Sentinel => Ok(Fetch::Sentinel),
            }
        }
    }



@@ 110,8 141,8 @@ impl Cache {
                *self.parent_modules.get(&def_id).expect("ice: if there's a def id, there should be a parent module");
            let def_ident = self.fetch_def_name(def_id).last().clone();
            let module = self.fetch_parsed_module(module_id)?;
            let parsed = module.defs[&def_ident].clone();
            let resolved = resolve::resolve_def(self, module_id, &parsed)?;
            let parsed = module[&def_ident].clone();
            let resolved = resolve::resolve_def(self, module_id, &parsed.1)?;
            self.resolveds.insert(def_id, resolved);
            Ok(&self.resolveds[&def_id])
        }


@@ 135,11 166,15 @@ impl Cache {
        if self.module_local_resolved_names.contains_key(&module_id) {
            Ok(&self.module_local_resolved_names[&module_id])
        } else {
            let def_idents: Vec<String> = self.fetch_parsed_module(module_id)?.defs.keys().cloned().collect();
            let ids = def_idents
                .into_iter()
                .map(|def_ident| (def_ident.clone(), Res::Def(self.gen_def_resolution(def_ident, module_id))))
                .chain(PRELUDE.iter().map(|(ident, res)| (ident.to_string(), *res)))
            let def_idents: Vec<String> = self.fetch_parsed_module(module_id)?.keys().cloned().collect();
            let ids = PRELUDE
                .iter()
                .map(|(ident, res)| (ident.to_string(), *res))
                .chain(
                    def_idents
                        .into_iter()
                        .map(|def_ident| (def_ident.clone(), Res::Def(self.gen_def_resolution(def_ident, module_id)))),
                )
                .collect();
            self.module_local_resolved_names.insert(module_id, ids);
            Ok(&self.module_local_resolved_names[&module_id])


@@ 178,7 213,7 @@ impl Cache {
            match self.fetch_global_resolved_name(&module_name)? {
                Res::Module(module_id) => {
                    let module = self.fetch_parsed_module(module_id)?;
                    if module.defs.contains_key(&def_ident.s) {
                    if module.contains_key(&def_ident.s) {
                        return Ok(Res::Def(self.gen_def_resolution(def_ident.s, module_id)));
                    }
                }


@@ 220,16 255,22 @@ impl Cache {
    }

    fn gen_def_resolution(&mut self, def_ident: String, module_id: ModuleId) -> DefId {
        assert!(self.n_defs < u32::MAX);
        debug_assert!(self.fetch_parsed_module(module_id).unwrap().defs.contains_key(&def_ident));
        debug_assert!(self.fetch_parsed_module(module_id).unwrap().contains_key(&def_ident));
        let def_name = self.fetch_module_name(module_id).clone().with(def_ident);
        let def_id = self.n_defs;
        let res = Res::Def(def_id);
        self.n_defs += 1;
        self.resolved_names.insert(def_name.clone(), res);
        self.resolved_names_rev.insert(res, def_name.clone());
        self.parent_modules.insert(def_id, module_id);
        def_id
        match self.resolved_names.get(&def_name) {
            Some(Res::Def(def_id)) => *def_id,
            Some(res) => panic!("ice: fetching/generating definition resolution for name {def_name}, but that name already resolves to {res:?}"),
            None => {
                assert!(self.n_defs < u32::MAX);
                let def_id = self.n_defs;
                let res = Res::Def(def_id);
                self.n_defs += 1;
                self.resolved_names.insert(def_name.clone(), res);
                self.resolved_names_rev.insert(res, def_name.clone());
                self.parent_modules.insert(def_id, module_id);
                def_id
            }
        }
    }

    pub fn fetch_def_name(&self, def_id: DefId) -> &FullName<String> {


@@ 242,7 283,7 @@ impl Cache {
            .expect("ice: if we have a module id, there should be a reverse")
    }

    pub fn fetch_parsed_module(&mut self, module_id: ModuleId) -> Result<&PModule> {
    pub fn fetch_parsed_module(&mut self, module_id: ModuleId) -> Result<&HashMap<String, (Loc, PExpr)>> {
        if !self.parsed_modules.contains_key(&module_id) {
            // TODO: nested modules in the same file?
            let file_id = *self


@@ 251,8 292,15 @@ impl Cache {
                .expect("ice: there should be a corresponding file id for each module id");
            let src = self.fetch_source(file_id)?;
            let tokens = lex::lex(Some(file_id), src)?;
            let parsed = parse::parse(Some(file_id), src, &tokens)?;
            self.parsed_modules.insert(module_id, parsed);
            let parsed = parse::parse(Some(file_id), &tokens)?;
            let mut dedup: HashMap<String, (Loc, PExpr)> = HashMap::new();
            for (lhs, rhs) in parsed.defs {
                let (lhs, loc) = (lhs.substr_in(src), Loc::new(Some(file_id), lhs.start));
                if dedup.insert(lhs.to_string(), (loc, rhs)).is_some() {
                    return Err(Error::Resolve(ResolveErr::DupDef(loc)));
                }
            }
            self.parsed_modules.insert(module_id, dedup);
        }
        Ok(&self.parsed_modules[&module_id])
    }


@@ 274,3 322,18 @@ impl Cache {
        self.file_paths.get(&file_id).expect("ice: we shouldn't have a file id without an associated file path")
    }
}

#[derive(Debug, Clone)]
pub enum Fetch<T> {
    Done(T),
    Sentinel,
}

impl<T> Fetch<T> {
    pub fn as_ref(&self) -> Fetch<&T> {
        match *self {
            Fetch::Done(ref x) => Fetch::Done(x),
            Fetch::Sentinel => Fetch::Sentinel,
        }
    }
}

M src/check.rs => src/check.rs +4 -1
@@ 73,7 73,10 @@ impl<'c> CheckDef<'c> {
                }
            },
            Rek::Var(r @ ResName { res: Res::Def(id) }) => {
                let typ = self.cache.fetch_checked(*id).map(|Expr { typ, .. }| typ.clone())?;
                let typ = match self.cache.fetch_sig(*id)? {
                    Fetch::Done(typ) => typ.clone(),
                    Fetch::Sentinel => return err(InferRecursive(expr.loc, *id)),
                };
                Ok(Expr { typ, kind: ExprKind::Var(r.clone()) })
            }
            Rek::Var(r @ ResName { res: Res::Local(id) }) => match self.get_local(*id) {

M src/diag.rs => src/diag.rs +4 -0
@@ 61,6 61,7 @@ pub enum TypeErr {
    InferLambdaParam(PubIdent),
    AppNonFun(Loc, FType),
    ModuleIsNotExpr(Loc, ModuleId),
    InferRecursive(Loc, DefId),
}

impl TypeErr {


@@ 79,6 80,7 @@ impl TypeErr {
            InferLambdaParam(ident) => ident.loc.error(cache, "Can't infer type of lambda parameter (yet). Maybe surround the lambda in a type annotation to have the type checked instead of inferred."),
            AppNonFun(loc, t) => loc.error(cache, format!("Expected a function to apply, found a {t}.")),
            ModuleIsNotExpr(loc, _mid) => loc.error(cache, "Expected an expression, but this name resolves to a module."),
            InferRecursive(loc, _def_id) => loc.error(cache, "Recursion when inferring the type of this definition. Adding type signatures to top-level definitions will probably help.")
        }
    }
}


@@ 89,6 91,7 @@ pub enum ResolveErr {
    InvalidRootNamespace(PubIdent),
    Unresolved(FullName<PubIdent>),
    ParentIsNotModule(Loc, FullName<PubIdent>),
    DupDef(Loc),
}

impl ResolveErr {


@@ 106,6 109,7 @@ impl ResolveErr {
                .error(cache, format!("Failed to resolve the name `{name}` to any existing module or definition.")),
            ParentIsNotModule(loc, parent) =>
                loc.error(cache, format!("The parent `{}` does not resolve to a module.", parent)),
            DupDef(loc) => loc.error(cache, format!("Duplicate definition of this name in this module.")),
        }
    }
}

M src/eval.rs => src/eval.rs +1 -0
@@ 10,6 10,7 @@ pub fn eval_var(cache: &mut Cache, def: &GVarDef) -> Result<Operand> {
    EvalDef::new(cache, &def.defs).run_var(&def.body)
}

#[derive(Debug)]
struct EvalDef<'c, 'd> {
    cache: &'c mut Cache,
    local_defs: HashMap<LocalId, &'d GlobDef>,

M src/main.rs => src/main.rs +19 -0
@@ 225,4 225,23 @@ mod test {
        ";
        assert_matches!(run_tmp(src), Err(_))
    }

    #[test]
    fn test_dup_def() {
        let src = "
            (def main 123)
            (def main 456)
        ";
        assert_matches!(run_tmp(src), Err(_))
    }

    #[test]
    fn test_factorial() {
        let src = "
            (def main (factorial 10))
            (def factorial (of (Fun [Int] Int)
                               (fun [n] (if (= n 0) 1 (* n (factorial (- n 1)))))))
        ";
        assert_matches!(run_tmp(src), Ok(Operand::Const(Const::Int(3628800))))
    }
}

M src/parse.rs => src/parse.rs +10 -9
@@ 4,8 4,9 @@ use std::collections::{HashMap, HashSet};
use std::iter::once;
use std::path::Path;

#[derive(Debug)]
pub struct Module {
    pub defs: HashMap<String, Expr>,
    pub defs: Vec<(PrivIdent, Expr)>,
}

// TODO: Parse directly to indexed flat tree.


@@ 98,12 99,12 @@ impl std::fmt::Display for Type {
    }
}

pub fn parse<'s>(file: Option<FileId>, src: &'s str, tokens: &[Token<'s>]) -> std::result::Result<Module, ParseErr> {
pub fn parse<'s>(file: Option<FileId>, tokens: &[Token<'s>]) -> std::result::Result<Module, ParseErr> {
    let inp = Inp { tokens, dist: 0, context: file.map(|file| Loc::FileGeneral { file }).unwrap_or(Loc::AnonGeneral) };
    let go = move || {
        let (inp, defs) = many0(def)(inp)?;
        end(inp)?;
        Ok(Module { defs: defs.into_iter().map(|(lhs, rhs)| (lhs.substr_in(src).to_owned(), rhs)).collect() })
        Ok(Module { defs })
    };
    go()
}


@@ 479,9 480,9 @@ mod test {
    #[test]
    fn test_arithm() {
        let src = "(def x (+ 1.0 2.0))";
        let m = parse(None, src, &lex(None, src).unwrap()).unwrap();
        let m = parse(None, &lex(None, src).unwrap()).unwrap();
        assert_matches!(
            &m.defs["x"],
            &m.defs[0].1,
            Expr{kind:ExprKind::App(f, xs),..}
            if matches!(&**f, Expr{ kind: ExprKind::Var(name), ..} if name.segments.len() == 1 && matches!(name.segments[0], PrivIdent { start: 8, len: 1 }))
            && matches!(&xs[..], [Expr{kind:ExprKind::F64(x1),..}, Expr{kind:ExprKind::F64(x2),..}] if *x1 == 1.0 && *x2 == 2.0)


@@ 491,9 492,9 @@ mod test {
    #[test]
    fn test_lambda() {
        let src = "(def add (fun [x y] (+ x y)))";
        let m = parse(None, src, &lex(None, src).unwrap()).unwrap();
        let m = parse(None, &lex(None, src).unwrap()).unwrap();
        assert_matches!(
            &m.defs["add"],
            &m.defs[0].1,
            Expr{kind:ExprKind::Fun(ps, b),..}
            if matches!(ps[..], [PrivIdent { start: 15, len: 1 }, PrivIdent { start: 17, len: 1 }])
            && matches!(&**b, Expr{kind:ExprKind::App(f, xs),..}


@@ 505,9 506,9 @@ mod test {
    #[test]
    fn test_expr_annotation1() {
        let src = "(def foo (of F64 123.0))";
        let m = parse(None, src, &lex(None, src).unwrap()).unwrap();
        let m = parse(None, &lex(None, src).unwrap()).unwrap();
        assert_matches!(
            &m.defs["foo"],
            &m.defs[0].1,
            Expr{kind:ExprKind::Annot(e, t),..}
            if matches!(&**e, Expr{kind:ExprKind::F64(x),..} if *x == 123.0)
            && matches!(t, Type::F64)

M src/prelude.rs => src/prelude.rs +4 -4
@@ 1,16 1,16 @@
pub(crate) use crate::{abase, cache, check, diag, eval, fem, lex, name, parse, resolve};
pub(crate) use cache::Cache;
pub(crate) use cache::{Cache, Fetch};
pub(crate) use diag::*;
pub(crate) use name::*;

// pub fn mapl<A1, A2, B>((a, b): (A1, B), f: impl Fn(A1) -> A2) -> (A2, B) {
// pub fn mapl<A1, A2, B>((a, b): (A1, B), f: impl FnOnce(A1) -> A2) -> (A2, B) {
//     (f(a), b)
// }

pub fn mapr<A, B1, B2>((a, b): (A, B1), f: impl Fn(B1) -> B2) -> (A, B2) {
pub fn mapr<A, B1, B2>((a, b): (A, B1), f: impl FnOnce(B1) -> B2) -> (A, B2) {
    (a, f(b))
}

// pub fn bimap<A1, A2, B1, B2>((a, b): (A1, B1), f: impl Fn(A1) -> A2, g: impl Fn(B1) -> B2) -> (A2, B2) {
// pub fn bimap<A1, A2, B1, B2>((a, b): (A1, B1), f: impl FnOnce(A1) -> A2, g: impl FnOnce(B1) -> B2) -> (A2, B2) {
//     (f(a), g(b))
// }