Implement return control flow

This commit is contained in:
Greg Shuflin 2021-11-01 01:42:04 -07:00
parent 7289504ab7
commit f4d3282090
4 changed files with 62 additions and 20 deletions

View File

@ -47,9 +47,12 @@ pub fn walk_block<V: ASTVisitor>(v: &mut V, block: &Block) {
if let Recursion::Continue = v.module(module_spec) {
walk_block(v, &module_spec.contents);
},
Flow(ref _flow_control) => {
//TODO do something with flow control in Visitor
}
Flow(ref flow_control) => match flow_control {
FlowControl::Return(Some(ref retval)) => {
walk_expression(v, retval);
}
_ => (),
},
}
}
}

View File

@ -10,12 +10,23 @@ use crate::{
util::ScopeStack,
};
#[derive(Debug)]
enum StatementOutput {
Primitive(Primitive),
Nothing,
}
pub struct Evaluator<'a, 'b> {
pub type_context: &'b TypeContext,
pub state: &'b mut State<'a>,
type_context: &'b TypeContext,
state: &'b mut State<'a>,
early_returning: bool,
}
impl<'a, 'b> Evaluator<'a, 'b> {
pub(crate) fn new(state: &'b mut State<'a>, type_context: &'b TypeContext) -> Self {
Self { state, type_context, early_returning: false }
}
pub fn evaluate(&mut self, reduced: ReducedIR, repl: bool) -> Vec<Result<String, String>> {
let mut acc = vec![];
for (def_id, function) in reduced.functions.into_iter() {
@ -25,7 +36,8 @@ impl<'a, 'b> Evaluator<'a, 'b> {
for statement in reduced.entrypoint.into_iter() {
match self.statement(statement) {
Ok(Some(output)) if repl => acc.push(Ok(output.to_repl(self.type_context))),
Ok(StatementOutput::Primitive(output)) if repl =>
acc.push(Ok(output.to_repl(self.type_context))),
Ok(_) => (),
Err(error) => {
acc.push(Err(error.msg));
@ -38,27 +50,38 @@ impl<'a, 'b> Evaluator<'a, 'b> {
fn block(&mut self, statements: Vec<Statement>) -> EvalResult<Primitive> {
//TODO need to handle breaks, returns, etc.
let mut ret = None;
let mut retval = None;
for stmt in statements.into_iter() {
if let Some(prim) = self.statement(stmt)? {
ret = Some(prim);
match self.statement(stmt)? {
StatementOutput::Nothing => (),
StatementOutput::Primitive(prim) => {
retval = Some(prim);
}
};
if self.early_returning {
break;
}
}
Ok(if let Some(ret) = ret { ret } else { self.expression(Expression::unit())? })
Ok(if let Some(ret) = retval { ret } else { self.expression(Expression::unit())? })
}
fn statement(&mut self, stmt: Statement) -> EvalResult<Option<Primitive>> {
fn statement(&mut self, stmt: Statement) -> EvalResult<StatementOutput> {
println!("Statement: {:?}", stmt);
match stmt {
Statement::Binding { ref id, expr, constant: _ } => {
let evaluated = self.expression(expr)?;
self.state.environments.insert(id.into(), evaluated.into());
Ok(None)
Ok(StatementOutput::Nothing)
}
Statement::Expression(expr) => {
let evaluated = self.expression(expr)?;
Ok(Some(evaluated))
Ok(StatementOutput::Primitive(evaluated))
}
Statement::Return(expr) => {
let evaluated = self.expression(expr)?;
self.early_returning = true;
Ok(StatementOutput::Primitive(evaluated))
}
Statement::Return(expr) => unimplemented!(),
Statement::Break => unimplemented!(),
Statement::Continue => unimplemented!(),
}
@ -199,9 +222,10 @@ impl<'a, 'b> Evaluator<'a, 'b> {
let mut new_scope = self.state.environments.new_scope(None);
if matches(&cond, &alt.pattern, &mut new_scope) {
let mut new_state = State { environments: new_scope };
let mut evaluator = Evaluator { state: &mut new_state, type_context: self.type_context };
return evaluator.block(alt.item);
let mut evaluator = Evaluator::new(&mut new_state, self.type_context);
let output = evaluator.block(alt.item);
self.early_returning = evaluator.early_returning;
return output;
}
}
Err("No valid match in match expression".into())
@ -363,7 +387,7 @@ impl<'a, 'b> Evaluator<'a, 'b> {
}
let mut frame_state = State { environments: self.state.environments.new_scope(None) };
let mut evaluator = Evaluator { state: &mut frame_state, type_context: self.type_context };
let mut evaluator = Evaluator::new(&mut frame_state, self.type_context);
for (n, evaled) in evaluated_args.into_iter().enumerate() {
let n = n as u8;

View File

@ -172,7 +172,7 @@ impl<'a> State<'a> {
type_context: &TypeContext,
repl: bool,
) -> Vec<Result<String, String>> {
let mut evaluator = evaluator::Evaluator { state: self, type_context };
let mut evaluator = evaluator::Evaluator::new(self, type_context);
evaluator.evaluate(reduced, repl)
}
}

View File

@ -21,7 +21,7 @@ fn evaluate_input(input: &str) -> Result<String, String> {
symbol_table.debug();
let mut state = State::new();
let mut evaluator = Evaluator { state: &mut state, type_context: &type_context };
let mut evaluator = Evaluator::new(&mut state, &type_context);
let mut outputs = evaluator.evaluate(reduced_ir, true);
outputs.pop().unwrap()
}
@ -378,3 +378,18 @@ let value = Klewos::Klewos { a: 50, b: "nah" }
eval_assert(source, r#"(50, "nah")"#);
}
#[test]
fn early_return() {
let source = r#"
fn chnurmek(a: Int): Int {
if a == 5 then {
return 9999;
}
return (a + 2);
}
(chnurmek(5), chnurmek(0))
"#;
eval_assert(source, r#"(9999, 2)"#);
}