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:
parent
ddb09b453d
commit
ae3a030ad8
@ -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) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user