Use iterative semantics for reduction

Becuase if you try to make reduce() recursive you blow out the stack.

Incidentally, "let a = 0; while a < 999999; let a = a + 1 end" is a neat
thing to try at this stage of the game
This commit is contained in:
greg 2015-08-14 00:02:23 -07:00
parent ddb09b453d
commit ae3a030ad8
1 changed files with 23 additions and 8 deletions

View File

@ -41,9 +41,12 @@ impl Environment {
pub fn evaluate(ast: AST, env: Environment) -> (String, Environment) { pub fn evaluate(ast: AST, env: Environment) -> (String, Environment) {
let (reduced_ast, final_env) = reduce((ast, env)); let mut reduction = (ast, env);
while is_reducable(&reduction.0) {
reduction = reduce(reduction);
}
let output = match reduced_ast { let output = match reduction.0 {
DoNothing => "".to_string(), DoNothing => "".to_string(),
Number(n) => format!("{}", n), Number(n) => format!("{}", n),
LangString(s) => format!("\"{}\"", s), LangString(s) => format!("\"{}\"", s),
@ -53,7 +56,19 @@ pub fn evaluate(ast: AST, env: Environment) -> (String, Environment) {
other => format!("reducing {:?} not implemented", other) other => format!("reducing {:?} not implemented", other)
}; };
(output, final_env) (output, reduction.1)
}
fn is_reducable(ast: &AST) -> bool {
match *ast {
DoNothing => false,
Number(_) => false,
LangString(_) => false,
Null => false,
LangFalse => false,
LangTrue => false,
_ => true
}
} }
fn reduce(evr: EvalResult) -> EvalResult { fn reduce(evr: EvalResult) -> EvalResult {
@ -62,14 +77,14 @@ fn reduce(evr: EvalResult) -> EvalResult {
match ast { match ast {
IfStatement(if_clause, then_clause, else_clause) => { IfStatement(if_clause, then_clause, else_clause) => {
let (condition, new_env) = reduce((*if_clause, env)); let (condition, new_env) = (*if_clause, env);
match condition { match condition {
Null | LangFalse => match else_clause { Null | LangFalse => match else_clause {
Some(cl) => reduce((*cl, new_env)), Some(cl) => (*cl, new_env),
None => (DoNothing, new_env) None => (DoNothing, new_env)
}, },
_ => reduce((*then_clause, new_env)) _ => (*then_clause, new_env)
} }
}, },
@ -79,7 +94,7 @@ fn reduce(evr: EvalResult) -> EvalResult {
Null | LangFalse => (DoNothing, env), Null | LangFalse => (DoNothing, env),
_ => { _ => {
let (_, new_env) = reduce((*body.clone(), env)); let (_, new_env) = reduce((*body.clone(), env));
reduce((WhileStatement(condition, body), new_env)) (WhileStatement(condition, body), new_env)
} }
} }
}, },
@ -88,7 +103,7 @@ fn reduce(evr: EvalResult) -> EvalResult {
let (reduced_lhs, new_env) = reduce((*lhs, env)); let (reduced_lhs, new_env) = reduce((*lhs, env));
let (reduced_rhs, new_env2) = reduce((*rhs, new_env)); let (reduced_rhs, new_env2) = reduce((*rhs, new_env));
let result: AST = reduce_binop(*op, reduced_lhs, reduced_rhs); let result: AST = reduce_binop(*op, reduced_lhs, reduced_rhs);
reduce((result, new_env2)) (result, new_env2)
}, },
Name(name) => { Name(name) => {