Continuing work on reduced ir

This commit is contained in:
Greg Shuflin 2021-10-24 02:54:21 -07:00
parent 82de5c6e27
commit bd698629ff
4 changed files with 114 additions and 35 deletions

View File

@ -15,7 +15,7 @@ pub fn reduce(ast: &ast::AST, symbol_table: &SymbolTable) -> ReducedIR {
struct Reducer<'a> {
symbol_table: &'a SymbolTable,
functions: HashMap<DefId, Callable>,
functions: HashMap<DefId, FunctionDefinition>,
}
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::*;
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<DefId, Callable>,
pub functions: HashMap<DefId, FunctionDefinition>,
pub entrypoint: Vec<Statement>,
}
@ -223,14 +238,6 @@ impl ReducedIR {
}
}
#[derive(Debug)]
pub enum Callable {
Builtin(Builtin),
UserDefined {
body: Vec<Statement>
}
}
#[derive(Debug)]
pub enum Statement {
Expression(Expression),
@ -245,12 +252,17 @@ pub enum Statement {
pub enum Expression {
Literal(Literal),
Tuple(Vec<Expression>),
Lookup {
id: DefId, //TODO eventually not everything that can be looked up will have a DefId
kind: Lookup,
},
Assign {
lval: DefId,
rval: Box<Expression>,
},
Callable(Function),
Call {
f: Function,
f: Box<Expression>,
args: Vec<Expression>
},
Unimplemented,
@ -258,11 +270,23 @@ pub enum Expression {
}
#[derive(Debug)]
pub enum Function {
Builtin(Builtin),
Defined(DefId),
pub struct FunctionDefinition {
body: Vec<Statement>
}
#[derive(Debug)]
pub enum Function {
Builtin(Builtin),
UserDefined(DefId)
}
#[derive(Debug)]
pub enum Lookup {
LocalVar,
GlobalVar,
Function,
Param,
}
#[derive(Debug)]
pub enum Literal {

View File

@ -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<TypeName>),

View File

@ -74,7 +74,6 @@ impl<'a> ScopeResolver<'a> {
if components.len() == 1 {
let local_name: Rc<String> = 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() };

View File

@ -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<T> = Result<T, String>;
#[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<Item=String>) -> String {
#[derive(Debug)]
enum RuntimeValue {
Expression(Expression),
Function(FunctionDefinition),
}
impl From<Expression> 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) => "<function>".to_string(),
}
}
}
@ -91,6 +106,11 @@ impl<'a> State<'a> {
pub fn evaluate(&mut self, reduced: ReducedIR, repl: bool) -> Vec<Result<String, String>> {
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<Option<RuntimeValue>> {
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::<EvalResult<Vec<Expression>>>()?),
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<Expression>) -> EvalResult<Expression> {
fn call_expression(&mut self, f: Expression, args: Vec<Expression>) -> EvalResult<Expression> {
Err("Call expression not implemented".to_string().into())
}
}