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) { if let Recursion::Continue = v.module(module_spec) {
walk_block(v, &module_spec.contents); walk_block(v, &module_spec.contents);
}, },
Flow(ref _flow_control) => { Flow(ref flow_control) => match flow_control {
//TODO do something with flow control in Visitor FlowControl::Return(Some(ref retval)) => {
walk_expression(v, retval);
} }
_ => (),
},
} }
} }
} }

View File

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

View File

@ -172,7 +172,7 @@ impl<'a> State<'a> {
type_context: &TypeContext, type_context: &TypeContext,
repl: bool, repl: bool,
) -> Vec<Result<String, String>> { ) -> 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) evaluator.evaluate(reduced, repl)
} }
} }

View File

@ -21,7 +21,7 @@ fn evaluate_input(input: &str) -> Result<String, String> {
symbol_table.debug(); symbol_table.debug();
let mut state = State::new(); 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); let mut outputs = evaluator.evaluate(reduced_ir, true);
outputs.pop().unwrap() outputs.pop().unwrap()
} }
@ -378,3 +378,18 @@ let value = Klewos::Klewos { a: 50, b: "nah" }
eval_assert(source, r#"(50, "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)"#);
}