Converted to multiple-evaluator logic
Now I have (basically) full single-step evaluation and it works fine
This commit is contained in:
parent
ba8f67441f
commit
f158b6c712
83
src/eval.rs
83
src/eval.rs
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
src/main.rs
10
src/main.rs
@ -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"] => {
|
||||||
|
Loading…
Reference in New Issue
Block a user