Implement loop keyword
- Loop is a combination of `while` and `for`
- `loop cond { }` acts exactly like `while`
- `loop cond; advance { }` acts like `for` without init
This commit is contained in:
parent
c49a5ec0e2
commit
c4f5b89456
@ -40,6 +40,21 @@ impl Interpreter {
|
|||||||
let result = self.resolve_expr(expr);
|
let result = self.resolve_expr(expr);
|
||||||
println!("Result = {:?}", result);
|
println!("Result = {:?}", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Statement::Loop(lop) => {
|
||||||
|
// loop runs as long condition != 0
|
||||||
|
loop {
|
||||||
|
if matches!(self.resolve_expr(lop.condition.clone()), Value::I64(0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.run(lop.body.clone());
|
||||||
|
|
||||||
|
if let Some(adv) = &lop.advancement {
|
||||||
|
self.resolve_expr(adv.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/lexer.rs
17
src/lexer.rs
@ -10,12 +10,20 @@ pub enum Token {
|
|||||||
/// Identifier (name for variables, functions, ...)
|
/// Identifier (name for variables, functions, ...)
|
||||||
Ident(String),
|
Ident(String),
|
||||||
|
|
||||||
|
Loop,
|
||||||
|
|
||||||
/// Left Parenthesis ('(')
|
/// Left Parenthesis ('(')
|
||||||
LParen,
|
LParen,
|
||||||
|
|
||||||
/// Right Parenthesis (')')
|
/// Right Parenthesis (')')
|
||||||
RParen,
|
RParen,
|
||||||
|
|
||||||
|
/// Left curly braces ({)
|
||||||
|
LBraces,
|
||||||
|
|
||||||
|
/// Right curly braces (})
|
||||||
|
RBraces,
|
||||||
|
|
||||||
/// Plus (+)
|
/// Plus (+)
|
||||||
Add,
|
Add,
|
||||||
|
|
||||||
@ -147,6 +155,8 @@ impl<'a> Lexer<'a> {
|
|||||||
'<' => tokens.push(Token::LAngle),
|
'<' => tokens.push(Token::LAngle),
|
||||||
'>' => tokens.push(Token::RAngle),
|
'>' => tokens.push(Token::RAngle),
|
||||||
'=' => tokens.push(Token::Equ),
|
'=' => tokens.push(Token::Equ),
|
||||||
|
'{' => tokens.push(Token::LBraces),
|
||||||
|
'}' => tokens.push(Token::RBraces),
|
||||||
|
|
||||||
// Lex numbers
|
// Lex numbers
|
||||||
ch @ '0'..='9' => {
|
ch @ '0'..='9' => {
|
||||||
@ -187,7 +197,12 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tokens.push(Token::Ident(ident));
|
let token = match ident.as_str() {
|
||||||
|
"loop" => Token::Loop,
|
||||||
|
_ => Token::Ident(ident),
|
||||||
|
};
|
||||||
|
|
||||||
|
tokens.push(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Don't panic, keep calm
|
//TODO: Don't panic, keep calm
|
||||||
|
|||||||
@ -81,9 +81,20 @@ pub enum Expression {
|
|||||||
UnOp(UnOpType, Box<Expression>),
|
UnOp(UnOpType, Box<Expression>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub struct Loop {
|
||||||
|
/// The condition that determines if the loop should continue
|
||||||
|
pub condition: Expression,
|
||||||
|
/// This is executed after each loop to advance the condition variables
|
||||||
|
pub advancement: Option<Expression>,
|
||||||
|
/// The loop body that is executed each loop
|
||||||
|
pub body: Ast,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Expr(Expression),
|
Expr(Expression),
|
||||||
|
Loop(Loop),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||||
@ -111,6 +122,10 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
self.next();
|
self.next();
|
||||||
}
|
}
|
||||||
Token::EoF => break,
|
Token::EoF => break,
|
||||||
|
Token::RBraces => {
|
||||||
|
self.next();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// By default try to lex a statement
|
// By default try to lex a statement
|
||||||
_ => {
|
_ => {
|
||||||
@ -124,14 +139,59 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_stmt(&mut self) -> Statement {
|
fn parse_stmt(&mut self) -> Statement {
|
||||||
let expr = self.parse_expr();
|
match self.peek() {
|
||||||
|
Token::Loop => Statement::Loop(self.parse_loop()),
|
||||||
|
|
||||||
// After a statement, there must be a semicolon
|
// If it is not a loop, try to lex as an expression
|
||||||
if !matches!(self.next(), Token::Semicolon) {
|
_ => {
|
||||||
panic!("Expected semicolon after statement");
|
let stmt = Statement::Expr(self.parse_expr());
|
||||||
|
|
||||||
|
// After a statement, there must be a semicolon
|
||||||
|
if !matches!(self.next(), Token::Semicolon) {
|
||||||
|
panic!("Expected semicolon after statement");
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop i < 1_000; i = i +1 {
|
||||||
|
// if i % 3 == 0 | i % 5 == 0 {
|
||||||
|
// sum = sum + i;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn parse_loop(&mut self) -> Loop {
|
||||||
|
if !matches!(self.next(), Token::Loop) {
|
||||||
|
panic!("Error lexing loop: Expected loop token");
|
||||||
}
|
}
|
||||||
|
|
||||||
Statement::Expr(expr)
|
let condition = self.parse_expr();
|
||||||
|
let mut advancement = None;
|
||||||
|
|
||||||
|
let body;
|
||||||
|
|
||||||
|
match self.next() {
|
||||||
|
Token::LBraces => {
|
||||||
|
body = self.parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
Token::Semicolon => {
|
||||||
|
advancement = Some(self.parse_expr());
|
||||||
|
|
||||||
|
if !matches!(self.next(), Token::LBraces) {
|
||||||
|
panic!("Error lexing loop: Expected '{{'")
|
||||||
|
}
|
||||||
|
|
||||||
|
body = self.parse();
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => panic!("Error lexing loop: Expected ';' or '{{'")
|
||||||
|
}
|
||||||
|
|
||||||
|
Loop { condition, advancement, body }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_expr(&mut self) -> Expression {
|
fn parse_expr(&mut self) -> Expression {
|
||||||
@ -228,16 +288,16 @@ impl BinOpType {
|
|||||||
|
|
||||||
fn precedence(&self) -> u8 {
|
fn precedence(&self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
BinOpType::BOr => 0,
|
BinOpType::Declare => 0,
|
||||||
BinOpType::BXor => 1,
|
BinOpType::Assign => 1,
|
||||||
BinOpType::BAnd => 2,
|
BinOpType::BOr => 2,
|
||||||
BinOpType::EquEqu | BinOpType::NotEqu => 3,
|
BinOpType::BXor => 3,
|
||||||
BinOpType::Less | BinOpType::LessEqu | BinOpType::Greater | BinOpType::GreaterEqu => 4,
|
BinOpType::BAnd => 4,
|
||||||
BinOpType::Shl | BinOpType::Shr => 5,
|
BinOpType::EquEqu | BinOpType::NotEqu => 5,
|
||||||
BinOpType::Add | BinOpType::Sub => 6,
|
BinOpType::Less | BinOpType::LessEqu | BinOpType::Greater | BinOpType::GreaterEqu => 6,
|
||||||
BinOpType::Mul | BinOpType::Div | BinOpType::Mod => 7,
|
BinOpType::Shl | BinOpType::Shr => 7,
|
||||||
BinOpType::Assign => 8,
|
BinOpType::Add | BinOpType::Sub => 8,
|
||||||
BinOpType::Declare => 9,
|
BinOpType::Mul | BinOpType::Div | BinOpType::Mod => 9,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user