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
|
# 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
|
||||||
|
@ -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 {
|
||||||
|
@ -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),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user