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> {
|
struct Reducer<'a> {
|
||||||
symbol_table: &'a SymbolTable,
|
symbol_table: &'a SymbolTable,
|
||||||
functions: HashMap<DefId, Callable>,
|
functions: HashMap<DefId, FunctionDefinition>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Reducer<'a> {
|
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) {
|
fn insert_function_definition(&mut self, item_id: &ast::ItemId, statements: &ast::Block) {
|
||||||
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
|
let symbol = self.symbol_table.lookup_symbol(item_id).unwrap();
|
||||||
let def_id = symbol.def_id.clone();
|
let def_id = symbol.def_id.clone();
|
||||||
let callable = Callable::UserDefined {
|
let function_def = FunctionDefinition {
|
||||||
body: self.function(statements)
|
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 {
|
fn expression(&mut self, expr: &ast::Expression) -> Expression {
|
||||||
@ -140,7 +140,7 @@ impl<'a> Reducer<'a> {
|
|||||||
match builtin {
|
match builtin {
|
||||||
Some(op) => {
|
Some(op) => {
|
||||||
Expression::Call {
|
Expression::Call {
|
||||||
f: Function::Builtin(op),
|
f: Box::new(Expression::Callable(Function::Builtin(op))),
|
||||||
args: vec![self.expression(arg)],
|
args: vec![self.expression(arg)],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,7 +174,7 @@ impl<'a> Reducer<'a> {
|
|||||||
},
|
},
|
||||||
Some(op) => {
|
Some(op) => {
|
||||||
Expression::Call {
|
Expression::Call {
|
||||||
f: Function::Builtin(op),
|
f: Box::new(Expression::Callable(Function::Builtin(op))),
|
||||||
args: vec![self.expression(lhs), self.expression(rhs)],
|
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 {
|
fn value(&mut self, qualified_name: &ast::QualifiedName) -> Expression {
|
||||||
let ast::QualifiedName { id, components, .. } = qualified_name;
|
use SymbolSpec::*;
|
||||||
println!("Qualified name: {:?}", qualified_name);
|
|
||||||
let maybe_symbol = self.symbol_table.lookup_symbol(&qualified_name.id);
|
|
||||||
println!("Symbol? {:?}", maybe_symbol);
|
|
||||||
|
|
||||||
|
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
|
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.
|
/// statements, in an executable context will likely just be a pointer to the main() function.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ReducedIR {
|
pub struct ReducedIR {
|
||||||
functions: HashMap<DefId, Callable>,
|
pub functions: HashMap<DefId, FunctionDefinition>,
|
||||||
pub entrypoint: Vec<Statement>,
|
pub entrypoint: Vec<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,14 +238,6 @@ impl ReducedIR {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Callable {
|
|
||||||
Builtin(Builtin),
|
|
||||||
UserDefined {
|
|
||||||
body: Vec<Statement>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Expression(Expression),
|
Expression(Expression),
|
||||||
@ -245,12 +252,17 @@ pub enum Statement {
|
|||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
Tuple(Vec<Expression>),
|
Tuple(Vec<Expression>),
|
||||||
|
Lookup {
|
||||||
|
id: DefId, //TODO eventually not everything that can be looked up will have a DefId
|
||||||
|
kind: Lookup,
|
||||||
|
},
|
||||||
Assign {
|
Assign {
|
||||||
lval: DefId,
|
lval: DefId,
|
||||||
rval: Box<Expression>,
|
rval: Box<Expression>,
|
||||||
},
|
},
|
||||||
|
Callable(Function),
|
||||||
Call {
|
Call {
|
||||||
f: Function,
|
f: Box<Expression>,
|
||||||
args: Vec<Expression>
|
args: Vec<Expression>
|
||||||
},
|
},
|
||||||
Unimplemented,
|
Unimplemented,
|
||||||
@ -258,11 +270,23 @@ pub enum Expression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Function {
|
pub struct FunctionDefinition {
|
||||||
Builtin(Builtin),
|
body: Vec<Statement>
|
||||||
Defined(DefId),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Function {
|
||||||
|
Builtin(Builtin),
|
||||||
|
UserDefined(DefId)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Lookup {
|
||||||
|
LocalVar,
|
||||||
|
GlobalVar,
|
||||||
|
Function,
|
||||||
|
Param,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Literal {
|
pub enum Literal {
|
||||||
|
@ -23,6 +23,12 @@ pub struct DefId {
|
|||||||
idx: u32,
|
idx: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DefId {
|
||||||
|
pub fn as_u32(&self) -> u32 {
|
||||||
|
self.idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Display for DefId {
|
impl fmt::Display for DefId {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "DefId:{}", self.idx)
|
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
|
//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
|
//local vars without interfering with other lookups. Also some type definitions
|
||||||
//should be scoped in a similar way.
|
//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)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum SymbolSpec {
|
pub enum SymbolSpec {
|
||||||
Func(Vec<TypeName>),
|
Func(Vec<TypeName>),
|
||||||
|
@ -74,7 +74,6 @@ impl<'a> ScopeResolver<'a> {
|
|||||||
if components.len() == 1 {
|
if components.len() == 1 {
|
||||||
let local_name: Rc<String> = components[0].clone();
|
let local_name: Rc<String> = components[0].clone();
|
||||||
let name_type = self.lexical_scopes.lookup(&local_name);
|
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 {
|
match name_type {
|
||||||
Some(NameType::Import(fqsn)) => {
|
Some(NameType::Import(fqsn)) => {
|
||||||
let symbol = self.symbol_table.fqsn_to_symbol.get(&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())] };
|
let fqsn = Fqsn { scopes: vec![Scope::Name(local_name.clone())] };
|
||||||
self.symbol_table.add_symbol(id, fqsn, spec);
|
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 {
|
} else {
|
||||||
let fqsn = Fqsn { scopes: components.iter().map(|name| Scope::Name(name.clone())).collect() };
|
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::symbol_table::{DefId};
|
||||||
use crate::util::ScopeStack;
|
use crate::util::ScopeStack;
|
||||||
|
|
||||||
@ -9,7 +9,20 @@ type EvalResult<T> = Result<T, String>;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct State<'a> {
|
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)]
|
#[derive(Debug)]
|
||||||
@ -47,6 +60,7 @@ fn paren_wrapped(terms: impl Iterator<Item=String>) -> String {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum RuntimeValue {
|
enum RuntimeValue {
|
||||||
Expression(Expression),
|
Expression(Expression),
|
||||||
|
Function(FunctionDefinition),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Expression> for RuntimeValue {
|
impl From<Expression> for RuntimeValue {
|
||||||
@ -76,7 +90,8 @@ fn expr_to_repl(expr: &Expression) -> String {
|
|||||||
impl RuntimeValue {
|
impl RuntimeValue {
|
||||||
fn to_repl(&self) -> String {
|
fn to_repl(&self) -> String {
|
||||||
match self {
|
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>> {
|
pub fn evaluate(&mut self, reduced: ReducedIR, repl: bool) -> Vec<Result<String, String>> {
|
||||||
let mut acc = 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() {
|
for statement in reduced.entrypoint.into_iter() {
|
||||||
match self.statement(statement) {
|
match self.statement(statement) {
|
||||||
Ok(Some(output)) if repl => {
|
Ok(Some(output)) if repl => {
|
||||||
@ -108,10 +128,10 @@ impl<'a> State<'a> {
|
|||||||
|
|
||||||
fn statement(&mut self, stmt: Statement) -> EvalResult<Option<RuntimeValue>> {
|
fn statement(&mut self, stmt: Statement) -> EvalResult<Option<RuntimeValue>> {
|
||||||
match stmt {
|
match stmt {
|
||||||
Statement::Binding { id, expr, constant } => {
|
Statement::Binding { ref id, expr, constant } => {
|
||||||
println!("eval() binding id: {}", id);
|
println!("eval() binding id: {}", id);
|
||||||
let evaluated = self.expression(expr)?;
|
let evaluated = self.expression(expr)?;
|
||||||
self.environments.insert(id, evaluated.into());
|
self.environments.insert(id.into(), evaluated.into());
|
||||||
Ok(None)
|
Ok(None)
|
||||||
},
|
},
|
||||||
Statement::Expression(expr) => {
|
Statement::Expression(expr) => {
|
||||||
@ -126,18 +146,38 @@ impl<'a> State<'a> {
|
|||||||
Ok(match expression {
|
Ok(match expression {
|
||||||
lit @ Expression::Literal(_) => lit,
|
lit @ Expression::Literal(_) => lit,
|
||||||
Expression::Tuple(items) => Expression::Tuple(items.into_iter().map(|expr| self.expression(expr)).collect::<EvalResult<Vec<Expression>>>()?),
|
Expression::Tuple(items) => Expression::Tuple(items.into_iter().map(|expr| self.expression(expr)).collect::<EvalResult<Vec<Expression>>>()?),
|
||||||
Expression::Assign { lval, box rval } => {
|
Expression::Lookup { ref id, kind } => {
|
||||||
let mut env = self.environments.lookup(&lval);
|
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
|
Unimplemented
|
||||||
},
|
},
|
||||||
Expression::Call { f, args } => self.call_expression(f, args)?,
|
Expression::Call { box f, args } => self.call_expression(f, args)?,
|
||||||
Unimplemented => Unimplemented,
|
Unimplemented => Unimplemented,
|
||||||
Expression::ReductionError(e) => return Err(e.into()),
|
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())
|
Err("Call expression not implemented".to_string().into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user