Continuing work on reduced ir
This commit is contained in:
parent
82de5c6e27
commit
bd698629ff
@ -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::*;
|
||||
|
||||
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<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 {
|
||||
|
@ -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>),
|
||||
|
@ -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() };
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user