Converted to multiple-evaluator logic

Now I have (basically) full single-step evaluation and it works fine
This commit is contained in:
greg 2017-01-03 01:53:44 -08:00
parent ba8f67441f
commit f158b6c712
2 changed files with 37 additions and 56 deletions

View File

@ -12,67 +12,53 @@ enum SideEffect {
AddFunctionBinding(Function), AddFunctionBinding(Function),
} }
struct EnvFrame { pub struct Evaluator<'a> {
parent: Option<&'a Evaluator<'a>>,
functions: HashMap<String, Function>, functions: HashMap<String, Function>,
variables: HashMap<String, Expression>, variables: HashMap<String, Expression>,
} }
impl EnvFrame { impl<'a> Evaluator<'a> {
fn new() -> EnvFrame { pub fn new(parent: Option<&'a Evaluator>) -> Evaluator<'a> {
EnvFrame { Evaluator {
functions: HashMap::new(), functions: HashMap::new(),
variables: HashMap::new(), variables: HashMap::new(),
parent: parent,
} }
} }
}
pub struct Evaluator {
frames: Vec<EnvFrame>,
}
impl Evaluator {
pub fn new() -> Evaluator {
Evaluator { frames: vec![EnvFrame::new()] }
}
pub fn run(&mut self, ast: AST) -> Vec<String> { pub fn run(&mut self, ast: AST) -> Vec<String> {
ast.into_iter() ast.into_iter()
.map(|astnode| self.reduce(astnode)) .map(|astnode| format!("{}", self.reduce(astnode)))
.collect() .collect()
} }
fn add_binding(&mut self, var: String, value: Expression) { fn add_binding(&mut self, var: String, value: Expression) {
match self.frames.last_mut() { self.variables.insert(var, value);
Some(frame) => frame.variables.insert(var, value),
None => panic!("Evaluator should ensure that frames always has at least one element"),
};
} }
fn lookup_binding(&self, var: String) -> Option<Expression> { fn lookup_binding(&self, var: String) -> Option<Expression> {
for frame in self.frames.iter().rev() { match self.variables.get(&var) {
match frame.variables.get(&var) { Some(expr) => Some(expr.clone()),
None => (), None => match self.parent {
Some(expr) => return Some(expr.clone()), Some(env) => env.lookup_binding(var),
None => None
} }
} }
None
} }
fn add_function(&mut self, name: String, function: Function) { fn add_function(&mut self, name: String, function: Function) {
match self.frames.last_mut() { self.functions.insert(name, function);
Some(frame) => frame.functions.insert(name, function),
None => panic!("Evaluator should ensure that frames always has at least one element"),
};
} }
fn lookup_function(&self, name: String) -> Option<Function> { fn lookup_function(&self, name: String) -> Option<Function> {
for frame in self.frames.iter().rev() { match self.functions.get(&name) {
match frame.functions.get(&name) { Some(func) => Some(func.clone()),
None => (), None => match self.parent {
Some(function) => return Some(function.clone()), Some(env) => env.lookup_function(name),
None => None
} }
} }
None
} }
} }
@ -115,16 +101,15 @@ impl Expression {
} }
} }
impl Evaluator { impl<'a> Evaluator<'a> {
fn reduce(&mut self, mut node: ASTNode) -> String { fn reduce(&mut self, mut node: ASTNode) -> ASTNode {
loop { loop {
node = self.step(node); node = self.step(node);
if !node.is_reducible() { if !node.is_reducible() {
break; break;
} }
} }
node
format!("{}", node)
} }
fn step(&mut self, node: ASTNode) -> ASTNode { fn step(&mut self, node: ASTNode) -> ASTNode {
@ -280,6 +265,7 @@ impl Evaluator {
fn reduce_call(&mut self, name: String, arguments: Vec<Expression>) -> Reduction<Expression> { fn reduce_call(&mut self, name: String, arguments: Vec<Expression>) -> Reduction<Expression> {
use parser::Expression::*; use parser::Expression::*;
use parser::ASTNode::*;
// ugly hack for now // ugly hack for now
if name == "print" { if name == "print" {
@ -290,7 +276,6 @@ impl Evaluator {
return (Null, Some(SideEffect::Print(s))); return (Null, Some(SideEffect::Print(s)));
} }
let function = match self.lookup_function(name) { let function = match self.lookup_function(name) {
Some(func) => func, Some(func) => func,
None => return (Null, None), None => return (Null, None),
@ -300,25 +285,21 @@ impl Evaluator {
return (Null, None); return (Null, None);
} }
let mut frame = EnvFrame::new(); let mut evaluator = Evaluator::new(Some(self));
for (binding, expr) in function.prototype.parameters.iter().zip(arguments.iter()) { for (binding, expr) in function.prototype.parameters.iter().zip(arguments.iter()) {
frame.variables.insert(binding.clone(), expr.clone()); evaluator.add_binding(binding.clone(), expr.clone());
} }
self.frames.push(frame); let nodes = function.body.iter().map(|expr| ASTNode::ExprNode(expr.clone()));
let mut retval = Null; let mut retval = Null;
for expr in function.body.iter() { for n in nodes {
retval = expr.clone(); retval = match evaluator.reduce(n) {
while retval.is_reducible() { ExprNode(expr) => expr,
let r = self.reduce_expr(retval); FuncDefNode(_) => panic!("This should never happen! A maximally-reduced node\
retval = r.0; should never be a function definition!")
if let Some(s) = r.1 { };
self.perform_side_effect(s);
}
}
} }
self.frames.pop();
(retval, None) (retval, None)
} }
} }

View File

@ -67,7 +67,7 @@ fn run_noninteractive(filename: &str, compile: bool) {
if compile { if compile {
compilation_sequence(ast, filename); compilation_sequence(ast, filename);
} else { } else {
let mut evaluator = Evaluator::new(); let mut evaluator = Evaluator::new(None);
let results = evaluator.run(ast); let results = evaluator.run(ast);
for result in results.iter() { for result in results.iter() {
println!("{}", result); println!("{}", result);
@ -80,18 +80,18 @@ fn run_repl() {
let initial_state = InterpreterState { let initial_state = InterpreterState {
show_tokens: false, show_tokens: false,
show_parse: false, show_parse: false,
evaluator: Evaluator::new(), evaluator: Evaluator::new(None),
}; };
REPL::with_prompt_and_state(Box::new(repl_handler), ">> ", initial_state).run(); REPL::with_prompt_and_state(Box::new(repl_handler), ">> ", initial_state).run();
} }
struct InterpreterState { struct InterpreterState<'a> {
show_tokens: bool, show_tokens: bool,
show_parse: bool, show_parse: bool,
evaluator: Evaluator, evaluator: Evaluator<'a>,
} }
impl ReplState for InterpreterState { impl<'a> ReplState for InterpreterState<'a> {
fn update_state(&mut self, input: &Vec<&str>) { fn update_state(&mut self, input: &Vec<&str>) {
match input[..] { match input[..] {
["set", "show", "tokens", "true"] => { ["set", "show", "tokens", "true"] => {