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

3
.gitignore vendored
View File

@@ -1,4 +1,5 @@
/target /target
/out* /out*
/TODO /TODO
/musl-* /musl-*
/vscode

View File

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

View File

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

View File

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

View File

@@ -13,6 +13,8 @@ pub struct Var {
pub struct Env { pub struct Env {
scopes: Vec<HashMap<String, Var>>, scopes: Vec<HashMap<String, Var>>,
next_offset: usize, next_offset: usize,
loop_begin_label: String,
loop_end_label: String,
} }
impl Env { impl Env {
@@ -20,6 +22,8 @@ impl Env {
Env { Env {
scopes: vec![HashMap::new()], scopes: vec![HashMap::new()],
next_offset: 8, 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); emit!(&mut self.output, "{}:", end_label);
} }
Stmt::While { condition, body } => { Stmt::While { condition, body } => {
let begin_label = self.label(); let old_loop_begin_label = env.loop_begin_label.clone();
let end_label = self.label(); 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)?; self.compile_expr(env, condition)?;
emit!(&mut self.output, " test rax, rax"); 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())?; self.compile_stmt(env, *body.clone())?;
emit!(&mut self.output, " jmp {}", begin_label); emit!(&mut self.output, " jmp {}", env.loop_begin_label);
emit!(&mut self.output, "{}:", end_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 { Stmt::Function {
name, name,
@@ -371,28 +380,40 @@ _builtin_array_free:
end, end,
body, body,
} => { } => {
let begin_label = self.label(); let old_loop_begin_label = env.loop_begin_label.clone();
let end_label = self.label(); 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(); env.push_scope();
let offset = env.define_var(var.lexeme, "I64".into()); let offset = env.define_var(var.lexeme, "I64".into());
self.compile_expr(env, start)?; self.compile_expr(env, start)?;
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); 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, " mov rax, QWORD [rbp-{}]", offset);
emit!(&mut self.output, " push rax"); emit!(&mut self.output, " push rax");
self.compile_expr(env, end)?; self.compile_expr(env, end)?;
emit!(&mut self.output, " pop rcx"); emit!(&mut self.output, " pop rcx");
emit!(&mut self.output, " cmp rcx, rax"); 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)?; self.compile_stmt(env, *body)?;
emit!(&mut self.output, " mov rax, QWORD [rbp-{}]", offset); emit!(&mut self.output, " mov rax, QWORD [rbp-{}]", offset);
emit!(&mut self.output, " add rax, 1"); emit!(&mut self.output, " add rax, 1");
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
emit!(&mut self.output, " jmp {}", begin_label); emit!(&mut self.output, " jmp {}", env.loop_begin_label);
emit!(&mut self.output, "{}:", end_label); emit!(&mut self.output, "{}:", env.loop_end_label);
env.pop_scope(); 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(()) Ok(())

View File

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

View File

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