While loops

This commit is contained in:
Greg Shuflin 2021-11-01 12:35:25 -07:00
parent f28f4eab78
commit d9f53abeb2
5 changed files with 82 additions and 6 deletions

View File

@ -1,5 +1,10 @@
# Immediate TODOs / General Code Cleanup # Immediate TODOs / General Code Cleanup
## Evaluator
* Make the evaluator take ReducedIR items by reference
## Testing ## Testing
* Make an automatic (macro-based?) system for numbering compiler errors, this should be every type of error * Make an automatic (macro-based?) system for numbering compiler errors, this should be every type of error

View File

@ -181,7 +181,15 @@ impl<'a, 'b> Reducer<'a, 'b> {
Expression::Call { f: Box::new(constructor), args: ordered_args } Expression::Call { f: Box::new(constructor), args: ordered_args }
} }
Index { .. } => Expression::ReductionError("Index expr not implemented".to_string()), Index { .. } => Expression::ReductionError("Index expr not implemented".to_string()),
WhileExpression { .. } => Expression::ReductionError("While expr not implemented".to_string()), WhileExpression { condition, body } => {
let cond = Box::new(if let Some(condition) = condition {
self.expression(condition)
} else {
Expression::Literal(Literal::Bool(true))
});
let statements = self.function_internal_block(body);
Expression::Loop { cond, statements }
}
ForExpression { .. } => Expression::ReductionError("For expr not implemented".to_string()), ForExpression { .. } => Expression::ReductionError("For expr not implemented".to_string()),
ListLiteral { .. } => Expression::ReductionError("ListLiteral expr not implemented".to_string()), ListLiteral { .. } => Expression::ReductionError("ListLiteral expr not implemented".to_string()),
Access { name, expr } => Access { name, expr } =>
@ -271,6 +279,7 @@ impl<'a, 'b> Reducer<'a, 'b> {
} }
fn prefix(&mut self, prefix: &ast::PrefixOp, arg: &ast::Expression) -> Expression { fn prefix(&mut self, prefix: &ast::PrefixOp, arg: &ast::Expression) -> Expression {
println!("PREFIX: {:?} and ARG: {:?}", prefix, arg);
let builtin: Option<Builtin> = TryFrom::try_from(prefix).ok(); let builtin: Option<Builtin> = TryFrom::try_from(prefix).ok();
match builtin { match builtin {
Some(op) => Expression::Call { Some(op) => Expression::Call {

View File

@ -58,6 +58,7 @@ pub enum Expression {
Call { f: Box<Expression>, args: Vec<Expression> }, Call { f: Box<Expression>, args: Vec<Expression> },
Conditional { cond: Box<Expression>, then_clause: Vec<Statement>, else_clause: Vec<Statement> }, Conditional { cond: Box<Expression>, then_clause: Vec<Statement>, else_clause: Vec<Statement> },
CaseMatch { cond: Box<Expression>, alternatives: Vec<Alternative> }, CaseMatch { cond: Box<Expression>, alternatives: Vec<Alternative> },
Loop { cond: Box<Expression>, statements: Vec<Statement> },
ReductionError(String), ReductionError(String),
} }

View File

@ -16,15 +16,22 @@ enum StatementOutput {
Nothing, Nothing,
} }
#[derive(Debug, Clone, Copy)]
enum LoopControlFlow {
Break,
Continue,
}
pub struct Evaluator<'a, 'b> { pub struct Evaluator<'a, 'b> {
type_context: &'b TypeContext, type_context: &'b TypeContext,
state: &'b mut State<'a>, state: &'b mut State<'a>,
early_returning: bool, early_returning: bool,
loop_control: Option<LoopControlFlow>,
} }
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 { pub(crate) fn new(state: &'b mut State<'a>, type_context: &'b TypeContext) -> Self {
Self { state, type_context, early_returning: false } Self { state, type_context, early_returning: false, loop_control: None }
} }
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>> {
@ -61,12 +68,14 @@ impl<'a, 'b> Evaluator<'a, 'b> {
if self.early_returning { if self.early_returning {
break; break;
} }
if let Some(_) = self.loop_control {
break;
}
} }
Ok(if let Some(ret) = retval { 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<StatementOutput> { 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)?;
@ -82,8 +91,14 @@ impl<'a, 'b> Evaluator<'a, 'b> {
self.early_returning = true; self.early_returning = true;
Ok(StatementOutput::Primitive(evaluated)) Ok(StatementOutput::Primitive(evaluated))
} }
Statement::Break => unimplemented!(), Statement::Break => {
Statement::Continue => unimplemented!(), self.loop_control = Some(LoopControlFlow::Break);
Ok(StatementOutput::Nothing)
}
Statement::Continue => {
self.loop_control = Some(LoopControlFlow::Continue);
Ok(StatementOutput::Nothing)
}
} }
} }
@ -150,6 +165,7 @@ impl<'a, 'b> Evaluator<'a, 'b> {
} }
Expression::CaseMatch { box cond, alternatives } => Expression::CaseMatch { box cond, alternatives } =>
self.case_match_expression(cond, alternatives)?, self.case_match_expression(cond, alternatives)?,
Expression::Loop { box cond, statements } => self.loop_expression(cond, statements)?,
Expression::ReductionError(e) => return Err(e.into()), Expression::ReductionError(e) => return Err(e.into()),
Expression::Access { name, box expr } => { Expression::Access { name, box expr } => {
let expr = self.expression(expr)?; let expr = self.expression(expr)?;
@ -176,6 +192,37 @@ impl<'a, 'b> Evaluator<'a, 'b> {
}) })
} }
fn loop_expression(&mut self, cond: Expression, statements: Vec<Statement>) -> EvalResult<Primitive> {
let existing = self.loop_control;
let output = self.loop_expression_inner(cond, statements);
self.loop_control = existing;
output
}
fn loop_expression_inner(
&mut self,
cond: Expression,
statements: Vec<Statement>,
) -> EvalResult<Primitive> {
loop {
let cond = self.expression(cond.clone())?;
match cond {
Primitive::Literal(Literal::Bool(true)) => (),
Primitive::Literal(Literal::Bool(false)) => break,
e => return Err(format!("Loop condition evaluates to non-boolean: {:?}", e).into()),
};
//TODO eventually loops shoudl be able to return something
let _output = self.block(statements.clone())?;
match self.loop_control {
None | Some(LoopControlFlow::Continue) => (),
Some(LoopControlFlow::Break) => {
break;
}
}
}
Ok(Primitive::unit())
}
fn case_match_expression( fn case_match_expression(
&mut self, &mut self,
cond: Expression, cond: Expression,

View File

@ -412,5 +412,19 @@ let z = marbuk(5, 6)
(x, y, z) (x, y, z)
"#; "#;
eval_assert(source, "((100, 100), (5, 2), (50, 50))"); eval_assert(source, "((100, 100), (5, 2), (50, 50))");
}
#[test]
fn loops() {
let source = r#"
let mut a = 0
let mut count = 0
while !(a == 5) {
a = a + 1
count = count + 100
}
count
"#;
eval_assert(source, "500");
} }