While loops
This commit is contained in:
parent
f28f4eab78
commit
d9f53abeb2
5
TODO.md
5
TODO.md
@ -1,5 +1,10 @@
|
||||
# Immediate TODOs / General Code Cleanup
|
||||
|
||||
|
||||
## Evaluator
|
||||
|
||||
* Make the evaluator take ReducedIR items by reference
|
||||
|
||||
## Testing
|
||||
|
||||
* Make an automatic (macro-based?) system for numbering compiler errors, this should be every type of error
|
||||
|
@ -181,7 +181,15 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
||||
Expression::Call { f: Box::new(constructor), args: ordered_args }
|
||||
}
|
||||
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()),
|
||||
ListLiteral { .. } => Expression::ReductionError("ListLiteral expr not implemented".to_string()),
|
||||
Access { name, expr } =>
|
||||
@ -271,6 +279,7 @@ impl<'a, 'b> Reducer<'a, 'b> {
|
||||
}
|
||||
|
||||
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();
|
||||
match builtin {
|
||||
Some(op) => Expression::Call {
|
||||
|
@ -58,6 +58,7 @@ pub enum Expression {
|
||||
Call { f: Box<Expression>, args: Vec<Expression> },
|
||||
Conditional { cond: Box<Expression>, then_clause: Vec<Statement>, else_clause: Vec<Statement> },
|
||||
CaseMatch { cond: Box<Expression>, alternatives: Vec<Alternative> },
|
||||
Loop { cond: Box<Expression>, statements: Vec<Statement> },
|
||||
ReductionError(String),
|
||||
}
|
||||
|
||||
|
@ -16,15 +16,22 @@ enum StatementOutput {
|
||||
Nothing,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
enum LoopControlFlow {
|
||||
Break,
|
||||
Continue,
|
||||
}
|
||||
|
||||
pub struct Evaluator<'a, 'b> {
|
||||
type_context: &'b TypeContext,
|
||||
state: &'b mut State<'a>,
|
||||
early_returning: bool,
|
||||
loop_control: Option<LoopControlFlow>,
|
||||
}
|
||||
|
||||
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 }
|
||||
Self { state, type_context, early_returning: false, loop_control: None }
|
||||
}
|
||||
|
||||
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 {
|
||||
break;
|
||||
}
|
||||
if let Some(_) = self.loop_control {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(if let Some(ret) = retval { ret } else { self.expression(Expression::unit())? })
|
||||
}
|
||||
|
||||
fn statement(&mut self, stmt: Statement) -> EvalResult<StatementOutput> {
|
||||
println!("Statement: {:?}", stmt);
|
||||
match stmt {
|
||||
Statement::Binding { ref id, expr, constant: _ } => {
|
||||
let evaluated = self.expression(expr)?;
|
||||
@ -82,8 +91,14 @@ impl<'a, 'b> Evaluator<'a, 'b> {
|
||||
self.early_returning = true;
|
||||
Ok(StatementOutput::Primitive(evaluated))
|
||||
}
|
||||
Statement::Break => unimplemented!(),
|
||||
Statement::Continue => unimplemented!(),
|
||||
Statement::Break => {
|
||||
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 } =>
|
||||
self.case_match_expression(cond, alternatives)?,
|
||||
Expression::Loop { box cond, statements } => self.loop_expression(cond, statements)?,
|
||||
Expression::ReductionError(e) => return Err(e.into()),
|
||||
Expression::Access { name, box 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(
|
||||
&mut self,
|
||||
cond: Expression,
|
||||
|
@ -412,5 +412,19 @@ let z = marbuk(5, 6)
|
||||
(x, y, z)
|
||||
"#;
|
||||
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");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user