From 6c55ea0a62cdec6fda73961301314506f468efbd Mon Sep 17 00:00:00 2001 From: JoJo Date: Fri, 20 Oct 2023 12:55:48 +0200 Subject: [PATCH] resolve unrooted names (defs in same module & prelude (+, *)) --- src/abase.rs | 15 ++++++---- src/cache.rs | 76 +++++++++++++++++++++++++++++++++++++------------- src/main.rs | 10 +++++++ src/name.rs | 31 ++++++++++++++++++++ src/resolve.rs | 19 ++++--------- 5 files changed, 111 insertions(+), 40 deletions(-) diff --git a/src/abase.rs b/src/abase.rs index 9ed1275..3439b0d 100644 --- a/src/abase.rs +++ b/src/abase.rs @@ -3,6 +3,7 @@ use crate::cache::Cache; use crate::fem::Expr as FExpr; use crate::name::*; +use anyhow::anyhow; #[derive(Clone)] pub enum Expr { @@ -12,15 +13,17 @@ pub enum Expr { } pub fn abase(cache: &mut Cache, expr: &FExpr) -> anyhow::Result { - Ok(match *expr { - FExpr::F64(x) => Expr::F64(x), - FExpr::App(ref f, ref xs) => match **f { + match *expr { + FExpr::F64(x) => Ok(Expr::F64(x)), + FExpr::App(ref f, ref xs) => Ok(match **f { FExpr::Var(ResName { res: Res::Prim(p) }) => match p { Prim::Add => Expr::Add(Box::new(abase(cache, &xs[0])?), Box::new(abase(cache, &xs[1])?)), Prim::Mul => Expr::Mul(Box::new(abase(cache, &xs[0])?), Box::new(abase(cache, &xs[1])?)), }, _ => todo!(), - }, - FExpr::Var(_) => todo!(), - }) + }), + FExpr::Var(ResName { res: Res::Def(id) }) => cache.fetch_base(id).cloned(), + FExpr::Var(ResName { res: Res::Prim(prim) }) => + Err(anyhow!("error: can't abase primitive `{prim}` in isolation")), + } } diff --git a/src/cache.rs b/src/cache.rs index 146106c..7076c31 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -4,7 +4,7 @@ use crate::resolve::{self, Expr as RExpr}; use crate::{abase, eval, fem, lex}; use anyhow::{anyhow, Context}; use std::borrow::Borrow; -use std::collections::HashMap; +use std::collections::hash_map::{Entry, HashMap}; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -14,6 +14,7 @@ pub struct Cache { parsed_modules: HashMap, resolved_names: HashMap, resolved_names_rev: HashMap, + module_local_resolved_names: HashMap>, resolveds: HashMap, // desugareds: HashMap, abaseds: HashMap, @@ -28,24 +29,27 @@ impl Cache { parsed_modules: HashMap::new(), resolved_names: HashMap::new(), resolved_names_rev: HashMap::new(), + module_local_resolved_names: HashMap::new(), resolveds: HashMap::new(), abaseds: HashMap::new(), evaluateds: HashMap::new(), } } - pub fn fetch_evaluated(&mut self, def_query: DefId) -> anyhow::Result<&eval::Val> { - 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 = eval::eval(self, &base)?; - self.evaluateds.insert(def_query, val); - Ok(&self.evaluateds[&def_query]) + pub fn fetch_evaluated(&mut self, query: Res) -> anyhow::Result<&eval::Val> { + match query { + Res::Prim(_prim) => todo!(), + Res::Def(id) if self.evaluateds.contains_key(&id) => Ok(self.evaluateds.get(&id).unwrap()), + Res::Def(id) => { + let base = self.fetch_base(id)?.clone(); + let val = eval::eval(self, &base)?; + self.evaluateds.insert(id, val); + Ok(&self.evaluateds[&id]) + } } } - pub fn fetch_base<'c>(&'c mut self, def_query: DefId) -> anyhow::Result<&'c abase::Expr> { + pub fn fetch_base(&mut self, def_query: DefId) -> anyhow::Result<&abase::Expr> { Ok(if self.abaseds.contains_key(&def_query) { &self.abaseds[&def_query] } else { @@ -98,13 +102,45 @@ impl Cache { Ok((name, parsed)) } - pub fn fetch_module_local_resolved_names(&mut self, _module: &FullName) -> anyhow::Result<&HashMap> { - todo!() + pub fn fetch_module_local_resolved_names( + &mut self, + module_name: &FullName, + ) -> anyhow::Result<&HashMap> { + static PRELUDE: &[(&str, &[&str])] = &[("+", &["prim", "+"]), ("*", &["prim", "*"])]; + fn prelude_owned() -> impl Iterator { + PRELUDE.iter().map(|(ident, name)| { + (PubIdent(ident.to_string()), FullName(name.iter().map(|x| x.to_string()).collect())) + }) + } + + if self.module_local_resolved_names.contains_key(module_name) { + Ok(&self.module_local_resolved_names[module_name]) + } else { + let def_names: Vec = self.fetch_parsed_module(module_name)?.defs.keys().cloned().collect(); + let ids = def_names + .into_iter() + .map(|k| (k.clone(), module_name.with(k))) + .chain(prelude_owned()) + .map(|(def_ident, name)| self.fetch_global_resolved_name(&name).map(|id| (def_ident, id))) + .collect::>()?; + self.module_local_resolved_names.insert(module_name.clone(), ids); + Ok(&self.module_local_resolved_names[module_name]) + } } - pub fn fetch_global_resolved_name(&mut self, name: &FullName) -> anyhow::Result { - if let Some(&res) = self.resolved_names.get(name) { - Ok(res) + pub fn fetch_global_resolved_name(&mut self, name: &FullName) -> anyhow::Result { + assert!(name.0.len() > 1); + if name.0[0] == "prim" { + if name.0.len() != 2 { + todo!() // Err + } + match name.0[1].as_str() { + "+" => Ok(Res::Prim(Prim::Add)), + "*" => Ok(Res::Prim(Prim::Mul)), + _ => todo!(), // Err + } + } else if let Some(&res) = self.resolved_names.get(name) { + Ok(Res::Def(res)) } else { let (def_ident, module_name) = name.0.split_last().expect("ice: query should be nonempty"); let module = self.fetch_parsed_module(&FullName(module_name.to_vec()))?; @@ -113,7 +149,7 @@ impl Cache { let id = self.resolved_names.len() as u32; self.resolved_names.insert(name.clone(), id); self.resolved_names_rev.insert(id, name.clone()); - Ok(id) + Ok(Res::Def(id)) } else { Err(anyhow!("item {def_ident:?} is not defined in module {module_name:?}")) } @@ -122,22 +158,22 @@ impl Cache { pub fn fetch_parsed_module(&mut self, module_name: &FullName) -> anyhow::Result<&PModule> { let (path, src) = self.fetch_source(module_name)?; - let tokens = lex::lex(Some(path.into()), &src)?; - let parsed = parse::parse(Some(path.into()), &src, &tokens)?; + let tokens = lex::lex(Some(path.into()), src)?; + let parsed = parse::parse(Some(path.into()), src, &tokens)?; self.parsed_modules.insert(module_name.clone(), parsed); Ok(&self.parsed_modules[module_name]) } pub fn fetch_source(&mut self, module_name: &FullName) -> anyhow::Result<(&Path, &str)> { if self.sources.contains_key(module_name) { - let &(ref path, ref src) = &self.sources[module_name]; + let (path, src) = &self.sources[module_name]; Ok((path, src)) } else { let path = find_module(&self.root_dir, module_name)?; let src = std::fs::read_to_string(&path).with_context(|| format!("ice: Failed to read source from {path:?}"))?; self.sources.insert(module_name.clone(), (path, src)); - let &(ref path, ref src) = &self.sources[module_name]; + let (path, src) = &self.sources[module_name]; Ok((path, src)) } } diff --git a/src/main.rs b/src/main.rs index 57e5d48..0c2a5ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ #![feature(entry_insert, is_ascii_octdigit, trait_alias, assert_matches)] #![allow(unused_imports)] +#![allow(clippy::map_entry)] mod abase; mod cache; @@ -63,4 +64,13 @@ mod test { fn test_main_arithm2() { assert_eq!(run_tmp("(def main (+.prim. (*.prim. 13.0 100.0) 37.0))").unwrap(), Val::F64(1337.0)) } + + #[test] + fn test_main_arithm_var() { + let src = " + (def x 1300.0) + (def main (+ x 37.0)) + "; + assert_eq!(run_tmp(src).unwrap(), Val::F64(1337.0)) + } } diff --git a/src/name.rs b/src/name.rs index bc00a68..f7d6a50 100644 --- a/src/name.rs +++ b/src/name.rs @@ -50,9 +50,40 @@ pub enum Prim { Mul = 1, } +impl std::fmt::Display for Prim { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!( + f, + "{}", + match self { + Prim::Add => "+", + Prim::Mul => "*", + } + ) + } +} + /// E.g. ["dep", "std", "str", "Str", "new"] represents the path "new.Str.str.std.dep." #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct FullName(pub Vec); + +impl FullName { + pub fn with(&self, element: PubIdent) -> Self { + let mut name = self.clone(); + name.0.push(element.0); + name + } +} + +impl std::fmt::Display for FullName { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + for seg in self.0.iter().rev() { + write!(f, "{}.", seg)? + } + Ok(()) + } +} + // The span of an identifier in the original source code string where the ident occured. Bookkeeping of source string // must be handled manually. // diff --git a/src/resolve.rs b/src/resolve.rs index bcb01c7..6182c72 100644 --- a/src/resolve.rs +++ b/src/resolve.rs @@ -1,5 +1,5 @@ use crate::{cache::*, name::*, parse}; -use anyhow::Result; +use anyhow::{anyhow, Result}; use std::borrow::Cow; // https://rustc-dev-guide.rust-lang.org/name-resolution.html @@ -28,25 +28,16 @@ pub fn resolve_parsed_name(cache: &mut Cache, occuring_in_module: &FullName, pna let (_, src) = cache.fetch_source(occuring_in_module)?; let name = pname.segments.iter().map(|seg| seg.in_source(src).to_owned()).collect::>(); if pname.rooted { - if name[0] == "prim" { - if name.len() != 2 { - todo!() // Err - } - match name[1].as_str() { - "+" => Ok(Res::Prim(Prim::Add)), - "*" => Ok(Res::Prim(Prim::Mul)), - _ => todo!(), // Err - } - } else { - cache.fetch_global_resolved_name(&FullName(name)).map(Res::Def) - } + cache.fetch_global_resolved_name(&FullName(name)) } else { match name.split_first() { Some((first, [])) => cache .fetch_module_local_resolved_names(occuring_in_module)? .get(&PubIdent(first.clone())) .cloned() - .ok_or_else(|| todo!()), + .ok_or_else(|| { + anyhow!("error: couldn' find definition `{}` in module `{}`", first, occuring_in_module) + }), Some((_first, _rest)) => todo!(), None => todo!(), // Err } -- 2.45.2