M src/ast.rs +4 -0
@@ 196,6 196,10 @@ pub enum Expr {
Loop {
body: Vec<Expr>,
},
+ While {
+ cond: Box<Expr>,
+ body: Vec<Expr>,
+ },
Lambda {
signature: Signature,
body: Vec<Expr>,
M src/format.rs +7 -0
@@ 228,6 228,13 @@ fn unparse_expr(e: &Expr, indent: usize,
unparse_exprs(body, indent + 1, out)?;
writeln!(out, "end")
}
+ E::While { cond, body } => {
+ write!(out, "while ")?;
+ unparse_expr(cond, 0, out)?;
+ writeln!(out, " do")?;
+ unparse_exprs(body, indent + 1, out)?;
+ writeln!(out, "end")
+ }
E::Lambda { signature, body } => {
write!(out, "fn")?;
unparse_sig(signature, out)?;
M src/hir.rs +19 -0
@@ 636,6 636,25 @@ fn lower_expr(expr: &ast::Expr) -> ExprN
let nbody = lower_exprs(body);
Loop { body: nbody }
}
+ E::While { cond, body } => {
+ // While loops just get turned into a Loop containing
+ // if not cond then break end
+ let inverted_cond = E::UniOp {
+ op: UOp::Not,
+ rhs: cond.clone(),
+ };
+ let test = lower_expr(&inverted_cond);
+ let brk = vec![ExprNode::new(Break)];
+ // As per above, we need to always have an "else" end case
+ let else_case = ExprNode::bool(true);
+ let else_exprs = lower_exprs(&[ast::Expr::TupleCtor { body: vec![] }]);
+ let if_expr = ExprNode::new(If {
+ cases: vec![(test, brk), (else_case, else_exprs)],
+ });
+ let mut nbody = lower_exprs(body);
+ nbody.insert(0, if_expr);
+ Loop { body: nbody }
+ }
E::Lambda { signature, body } => {
let nsig = lower_signature(signature);
let nbody = lower_exprs(body);
M src/parser.rs +18 -0
@@ 150,6 150,8 @@ pub enum TokenKind {
Else,
#[regex("loop[ \n]*")]
Loop,
+ #[regex("while[ \n]*")]
+ While,
#[regex("do[ \n]*")]
Do,
#[token("return")]
@@ 1010,6 1012,7 @@ impl<'input> Parser<'input> {
T::Let => self.parse_let(),
T::If => self.parse_if(),
T::Loop => self.parse_loop(),
+ T::While => self.parse_while_loop(),
T::Do => self.parse_block(),
T::Fn => self.parse_lambda(),
T::Return => self.parse_return(),
@@ 1290,6 1293,21 @@ impl<'input> Parser<'input> {
ast::Expr::Loop { body }
}
+ /// while = "while" expr "do" {expr} "end"
+ fn parse_while_loop(&mut self) -> ast::Expr {
+ self.expect(T::While);
+ let cond = self
+ .parse_expr(0)
+ .expect("While loop condition was not an expression?");
+ self.expect(T::Do);
+ let body = self.parse_exprs();
+ self.expect(T::End);
+ ast::Expr::While {
+ cond: Box::new(cond),
+ body,
+ }
+ }
+
/// block = "do" {expr} "end"
fn parse_block(&mut self) -> ast::Expr {
self.expect(T::Do);
A => tests/programs/test_while1.gt +27 -0
@@ 0,0 1,27 @@
+-- Format:
+-- status: success
+-- Compile:
+-- status: success
+--
+-- Run:
+-- status: success
+-- stdout: 21
+
+fn main() {} =
+ __println(fib(8))
+end
+
+-- Iterative fib implementation, with a while loop
+fn fib(num I32) I32 =
+ let mut x I32 = 0
+ let mut y I32 = 1
+ let mut z I32 = 0
+ let mut i I32 = 0
+ while i < num do
+ z = x + y
+ x = y
+ y = z
+ i = i + 1
+ end
+ x
+end