break and continue

This commit is contained in:
2025-07-02 13:56:30 +02:00
parent a0bee3f5ca
commit c53a7cd631
7 changed files with 48 additions and 16 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@
/out*
/TODO
/musl-*
/vscode

View File

@@ -17,5 +17,5 @@ func main[] : I64
n = n + i
if num_divisors(n) > 500
print_i64(n)
return 0
break
i = i + 1

View File

@@ -7,5 +7,5 @@ func main[] : I64
found = found + 1
if found == 10001
print_i64(i)
return 0
break
i = i + 1

View File

@@ -7,7 +7,7 @@ func main[] : I64
if guess == answer
print("You win!")
return 0
break
else if guess < answer
print("Too low!")
else

View File

@@ -13,6 +13,8 @@ pub struct Var {
pub struct Env {
scopes: Vec<HashMap<String, Var>>,
next_offset: usize,
loop_begin_label: String,
loop_end_label: String,
}
impl Env {
@@ -20,6 +22,8 @@ impl Env {
Env {
scopes: vec![HashMap::new()],
next_offset: 8,
loop_begin_label: String::new(),
loop_end_label: String::new(),
}
}
@@ -310,16 +314,21 @@ _builtin_array_free:
emit!(&mut self.output, "{}:", end_label);
}
Stmt::While { condition, body } => {
let begin_label = self.label();
let end_label = self.label();
let old_loop_begin_label = env.loop_begin_label.clone();
let old_loop_end_label = env.loop_end_label.clone();
env.loop_begin_label = self.label();
env.loop_end_label = self.label();
emit!(&mut self.output, "{}:", begin_label);
emit!(&mut self.output, "{}:", env.loop_begin_label);
self.compile_expr(env, condition)?;
emit!(&mut self.output, " test rax, rax");
emit!(&mut self.output, " je {}", end_label);
emit!(&mut self.output, " je {}", env.loop_end_label);
self.compile_stmt(env, *body.clone())?;
emit!(&mut self.output, " jmp {}", begin_label);
emit!(&mut self.output, "{}:", end_label);
emit!(&mut self.output, " jmp {}", env.loop_begin_label);
emit!(&mut self.output, "{}:", env.loop_end_label);
env.loop_begin_label = old_loop_begin_label;
env.loop_end_label = old_loop_end_label;
}
Stmt::Function {
name,
@@ -371,28 +380,40 @@ _builtin_array_free:
end,
body,
} => {
let begin_label = self.label();
let end_label = self.label();
let old_loop_begin_label = env.loop_begin_label.clone();
let old_loop_end_label = env.loop_end_label.clone();
env.loop_begin_label = self.label();
env.loop_end_label = self.label();
env.push_scope();
let offset = env.define_var(var.lexeme, "I64".into());
self.compile_expr(env, start)?;
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
emit!(&mut self.output, "{}:", begin_label);
emit!(&mut self.output, "{}:", env.loop_begin_label);
emit!(&mut self.output, " mov rax, QWORD [rbp-{}]", offset);
emit!(&mut self.output, " push rax");
self.compile_expr(env, end)?;
emit!(&mut self.output, " pop rcx");
emit!(&mut self.output, " cmp rcx, rax");
emit!(&mut self.output, " jge {}", end_label);
emit!(&mut self.output, " jge {}", env.loop_end_label);
self.compile_stmt(env, *body)?;
emit!(&mut self.output, " mov rax, QWORD [rbp-{}]", offset);
emit!(&mut self.output, " add rax, 1");
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
emit!(&mut self.output, " jmp {}", begin_label);
emit!(&mut self.output, "{}:", end_label);
emit!(&mut self.output, " jmp {}", env.loop_begin_label);
emit!(&mut self.output, "{}:", env.loop_end_label);
env.pop_scope();
env.loop_begin_label = old_loop_begin_label;
env.loop_end_label = old_loop_end_label;
}
Stmt::Break => {
emit!(&mut self.output, " jmp {}", env.loop_end_label);
}
Stmt::Continue => {
// TODO: skips incrementing when used in a for loop
emit!(&mut self.output, " jmp {}", env.loop_begin_label);
}
}
Ok(())

View File

@@ -37,6 +37,8 @@ pub enum Stmt {
body: Box<Stmt>,
},
Return(Expr),
Break,
Continue,
}
#[derive(Debug, Clone)]
@@ -193,6 +195,10 @@ impl Parser {
self.for_statement()
} else if self.match_token(&[TokenType::KeywordReturn]) {
Ok(Stmt::Return(self.expression()?))
} else if self.match_token(&[TokenType::KeywordBreak]) {
Ok(Stmt::Break)
} else if self.match_token(&[TokenType::KeywordContinue]) {
Ok(Stmt::Continue)
} else {
Ok(Stmt::Expression(self.expression()?))
}

View File

@@ -43,6 +43,8 @@ pub enum TokenType {
KeywordIn,
KeywordFunc,
KeywordReturn,
KeywordBreak,
KeywordContinue,
Indent,
Dedent,
@@ -335,6 +337,8 @@ impl Tokenizer {
"in" => TokenType::KeywordIn,
"func" => TokenType::KeywordFunc,
"return" => TokenType::KeywordReturn,
"break" => TokenType::KeywordBreak,
"continue" => TokenType::KeywordContinue,
"true" => TokenType::True,
"false" => TokenType::False,
_ => TokenType::Identifier,