From bd698629ff6cc7163ed7aea861594ebd9b849a1a Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Sun, 24 Oct 2021 02:54:21 -0700 Subject: [PATCH] Continuing work on reduced ir --- schala-lang/language/src/reduced_ir/mod.rs | 70 +++++++++++++------ schala-lang/language/src/symbol_table/mod.rs | 9 +++ .../language/src/symbol_table/resolver.rs | 10 ++- .../language/src/tree_walk_eval/mod.rs | 60 +++++++++++++--- 4 files changed, 114 insertions(+), 35 deletions(-) diff --git a/schala-lang/language/src/reduced_ir/mod.rs b/schala-lang/language/src/reduced_ir/mod.rs index a8ea03b..664b682 100644 --- a/schala-lang/language/src/reduced_ir/mod.rs +++ b/schala-lang/language/src/reduced_ir/mod.rs @@ -15,7 +15,7 @@ pub fn reduce(ast: &ast::AST, symbol_table: &SymbolTable) -> ReducedIR { struct Reducer<'a> { symbol_table: &'a SymbolTable, - functions: HashMap, + functions: HashMap, } impl<'a> Reducer<'a> { @@ -98,10 +98,10 @@ impl<'a> Reducer<'a> { fn insert_function_definition(&mut self, item_id: &ast::ItemId, statements: &ast::Block) { let symbol = self.symbol_table.lookup_symbol(item_id).unwrap(); let def_id = symbol.def_id.clone(); - let callable = Callable::UserDefined { + let function_def = FunctionDefinition { body: self.function(statements) }; - self.functions.insert(def_id, callable); + self.functions.insert(def_id, function_def); } fn expression(&mut self, expr: &ast::Expression) -> Expression { @@ -140,7 +140,7 @@ impl<'a> Reducer<'a> { match builtin { Some(op) => { Expression::Call { - f: Function::Builtin(op), + f: Box::new(Expression::Callable(Function::Builtin(op))), args: vec![self.expression(arg)], } } @@ -174,7 +174,7 @@ impl<'a> Reducer<'a> { }, Some(op) => { Expression::Call { - f: Function::Builtin(op), + f: Box::new(Expression::Callable(Function::Builtin(op))), args: vec![self.expression(lhs), self.expression(rhs)], } } @@ -186,12 +186,27 @@ impl<'a> Reducer<'a> { } fn value(&mut self, qualified_name: &ast::QualifiedName) -> Expression { - let ast::QualifiedName { id, components, .. } = qualified_name; - println!("Qualified name: {:?}", qualified_name); - let maybe_symbol = self.symbol_table.lookup_symbol(&qualified_name.id); - println!("Symbol? {:?}", maybe_symbol); + use SymbolSpec::*; - Expression::Unimplemented + let ast::QualifiedName { id, components, .. } = qualified_name; + + let symbol = match self.symbol_table.lookup_symbol(&qualified_name.id) { + Some(s) => s, + None => return Expression::ReductionError(format!("No symbol found for name: {:?}", qualified_name)) + }; + let Symbol { def_id, spec, .. } = symbol; + match spec { + Func(_) => Expression::Lookup { id: def_id.clone(), kind: Lookup::Function }, + GlobalBinding => Expression::Lookup { id: def_id.clone(), kind: Lookup::GlobalVar }, + LocalVariable => Expression::Lookup { id: def_id.clone(), kind: Lookup::LocalVar }, + FunctionParam(_) => Expression::Lookup { id: def_id.clone(), kind: Lookup::Param }, + DataConstructor { index, arity, .. } => { + Expression::Unimplemented + }, + RecordConstructor { .. } => { + Expression::ReductionError(format!("The symbol for value {:?} is unexpectdly a RecordConstructor", qualified_name)) + }, + } } } @@ -200,7 +215,7 @@ impl<'a> Reducer<'a> { /// statements, in an executable context will likely just be a pointer to the main() function. #[derive(Debug)] pub struct ReducedIR { - functions: HashMap, + pub functions: HashMap, pub entrypoint: Vec, } @@ -223,14 +238,6 @@ impl ReducedIR { } } -#[derive(Debug)] -pub enum Callable { - Builtin(Builtin), - UserDefined { - body: Vec - } -} - #[derive(Debug)] pub enum Statement { Expression(Expression), @@ -245,12 +252,17 @@ pub enum Statement { pub enum Expression { Literal(Literal), Tuple(Vec), + Lookup { + id: DefId, //TODO eventually not everything that can be looked up will have a DefId + kind: Lookup, + }, Assign { lval: DefId, rval: Box, }, + Callable(Function), Call { - f: Function, + f: Box, args: Vec }, Unimplemented, @@ -258,11 +270,23 @@ pub enum Expression { } #[derive(Debug)] -pub enum Function { - Builtin(Builtin), - Defined(DefId), +pub struct FunctionDefinition { + body: Vec } +#[derive(Debug)] +pub enum Function { + Builtin(Builtin), + UserDefined(DefId) +} + +#[derive(Debug)] +pub enum Lookup { + LocalVar, + GlobalVar, + Function, + Param, +} #[derive(Debug)] pub enum Literal { diff --git a/schala-lang/language/src/symbol_table/mod.rs b/schala-lang/language/src/symbol_table/mod.rs index a1e4aa4..d77639f 100644 --- a/schala-lang/language/src/symbol_table/mod.rs +++ b/schala-lang/language/src/symbol_table/mod.rs @@ -23,6 +23,12 @@ pub struct DefId { idx: u32, } +impl DefId { + pub fn as_u32(&self) -> u32 { + self.idx + } +} + impl fmt::Display for DefId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "DefId:{}", self.idx) @@ -221,6 +227,9 @@ impl fmt::Display for Symbol { //It would be good if individual functions could in parallel look up their own //local vars without interfering with other lookups. Also some type definitions //should be scoped in a similar way. +// +//Also it makes sense that non-globals should not use DefId's, particularly not +//function parameters (even though they are currently assigned). #[derive(Debug, Clone)] pub enum SymbolSpec { Func(Vec), diff --git a/schala-lang/language/src/symbol_table/resolver.rs b/schala-lang/language/src/symbol_table/resolver.rs index 0458b13..7b53ec0 100644 --- a/schala-lang/language/src/symbol_table/resolver.rs +++ b/schala-lang/language/src/symbol_table/resolver.rs @@ -74,7 +74,6 @@ impl<'a> ScopeResolver<'a> { if components.len() == 1 { let local_name: Rc = components[0].clone(); let name_type = self.lexical_scopes.lookup(&local_name); - println!("resolver.rs lookup_name_in_scope: {:?} with name_type {:?}", name, name_type); match name_type { Some(NameType::Import(fqsn)) => { let symbol = self.symbol_table.fqsn_to_symbol.get(&fqsn); @@ -92,7 +91,14 @@ impl<'a> ScopeResolver<'a> { let fqsn = Fqsn { scopes: vec![Scope::Name(local_name.clone())] }; self.symbol_table.add_symbol(id, fqsn, spec); }, - None => (), + None => { + //TODO see if I can reduce this duplicate code + let fqsn = Fqsn { scopes: vec![Scope::Name(local_name.clone())] }; + let symbol = self.symbol_table.fqsn_to_symbol.get(&fqsn); + if let Some(symbol) = symbol { + self.symbol_table.id_to_symbol.insert(id.clone(), symbol.clone()); + } + } } } else { let fqsn = Fqsn { scopes: components.iter().map(|name| Scope::Name(name.clone())).collect() }; diff --git a/schala-lang/language/src/tree_walk_eval/mod.rs b/schala-lang/language/src/tree_walk_eval/mod.rs index 92c22b9..81f6cc9 100644 --- a/schala-lang/language/src/tree_walk_eval/mod.rs +++ b/schala-lang/language/src/tree_walk_eval/mod.rs @@ -1,4 +1,4 @@ -use crate::reduced_ir::{ReducedIR, Expression, Function, Statement, Literal}; +use crate::reduced_ir::{ReducedIR, Expression, Lookup, Function, FunctionDefinition, Statement, Literal}; use crate::symbol_table::{DefId}; use crate::util::ScopeStack; @@ -9,7 +9,20 @@ type EvalResult = Result; #[derive(Debug)] pub struct State<'a> { - environments: ScopeStack<'a, DefId, RuntimeValue>, + environments: ScopeStack<'a, Memory, RuntimeValue>, +} + +//TODO - eh, I dunno, maybe it doesn't matter exactly how memory works in the tree-walking +//evaluator +#[derive(Debug, PartialEq, Eq, Hash, Clone)] +enum Memory { + Index(u32) +} + +impl From<&DefId> for Memory { + fn from(id: &DefId) -> Self { + Self::Index(id.as_u32()) + } } #[derive(Debug)] @@ -47,6 +60,7 @@ fn paren_wrapped(terms: impl Iterator) -> String { #[derive(Debug)] enum RuntimeValue { Expression(Expression), + Function(FunctionDefinition), } impl From for RuntimeValue { @@ -76,7 +90,8 @@ fn expr_to_repl(expr: &Expression) -> String { impl RuntimeValue { fn to_repl(&self) -> String { match self { - RuntimeValue::Expression(ref expr) => expr_to_repl(expr) + RuntimeValue::Expression(ref expr) => expr_to_repl(expr), + RuntimeValue::Function(ref expr) => "".to_string(), } } } @@ -91,6 +106,11 @@ impl<'a> State<'a> { pub fn evaluate(&mut self, reduced: ReducedIR, repl: bool) -> Vec> { let mut acc = vec![]; + for (def_id, function) in reduced.functions.into_iter() { + let mem = (&def_id).into(); + self.environments.insert(mem, RuntimeValue::Function(function)); + } + for statement in reduced.entrypoint.into_iter() { match self.statement(statement) { Ok(Some(output)) if repl => { @@ -108,10 +128,10 @@ impl<'a> State<'a> { fn statement(&mut self, stmt: Statement) -> EvalResult> { match stmt { - Statement::Binding { id, expr, constant } => { + Statement::Binding { ref id, expr, constant } => { println!("eval() binding id: {}", id); let evaluated = self.expression(expr)?; - self.environments.insert(id, evaluated.into()); + self.environments.insert(id.into(), evaluated.into()); Ok(None) }, Statement::Expression(expr) => { @@ -126,18 +146,38 @@ impl<'a> State<'a> { Ok(match expression { lit @ Expression::Literal(_) => lit, Expression::Tuple(items) => Expression::Tuple(items.into_iter().map(|expr| self.expression(expr)).collect::>>()?), - Expression::Assign { lval, box rval } => { - let mut env = self.environments.lookup(&lval); + Expression::Lookup { ref id, kind } => { + let mem = id.into(); + match kind { + Lookup::Function => { + if self.environments.lookup(&mem).is_some() { + Expression::Callable(Function::UserDefined(id.clone())) + } else { + return Err(format!("Function not found for id: {}", id)); + } + }, + kind @ Lookup::LocalVar | kind @ Lookup::GlobalVar | kind @ Lookup::Param => { + match self.environments.lookup(&mem) { + //Some(RuntimeValue::Expression(expr)) => (*expr).clone(), + Some(RuntimeValue::Expression(expr)) => Unimplemented, + _ => return Err(format!("Nothing found for variable lookup {} of kind {:?}", id, kind)), + } + }, + } + }, + Expression::Assign { ref lval, box rval } => { + let mem = lval.into(); + let mut env = self.environments.lookup(&mem); Unimplemented }, - Expression::Call { f, args } => self.call_expression(f, args)?, + Expression::Call { box f, args } => self.call_expression(f, args)?, Unimplemented => Unimplemented, Expression::ReductionError(e) => return Err(e.into()), - _ => Expression::Literal(Literal::Nat(69420)), + e => return Err(format!("Can't yet handle {:?}", e)), }) } - fn call_expression(&mut self, f: Function, args: Vec) -> EvalResult { + fn call_expression(&mut self, f: Expression, args: Vec) -> EvalResult { Err("Call expression not implemented".to_string().into()) } }