continue statements now working

This commit is contained in:
2025-11-25 01:47:49 -07:00
parent 05b16d59a4
commit 81f412453b
6 changed files with 79 additions and 8 deletions

View File

@@ -106,3 +106,44 @@ fn test_while_loop() -> anyhow::Result<()> {
Ok(())
}
#[test]
fn test_loop_continue() -> anyhow::Result<()> {
let compiled = compile! {
debug
"
let a = 0;
loop {
a = a + 1;
if (a < 5) {
continue;
}
break;
}
"
};
// Labels: L1 (start), L2 (end), L3 (if end)
assert_eq!(
compiled,
indoc! {
"
j main
main:
move r8 0 #a
L1:
add r1 r8 1
move r8 r1 #a
slt r2 r8 5
beq r2 0 L3
j L1
L3:
j L2
j L1
L2:
"
}
);
Ok(())
}

View File

@@ -77,7 +77,7 @@ pub struct Compiler<'a, W: std::io::Write> {
config: CompilerConfig,
temp_counter: usize,
label_counter: usize,
loop_stack: Vec<String>, // Stores the 'end' label of the current loops
loop_stack: Vec<(String, String)>, // Stores (start_label, end_label)
}
impl<'a, W: std::io::Write> Compiler<'a, W> {
@@ -160,6 +160,10 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
self.expression_break()?;
Ok(None)
}
Expression::Continue => {
self.expression_continue()?;
Ok(None)
}
Expression::DeviceDeclaration(expr_dev) => {
self.expression_device(expr_dev)?;
Ok(None)
@@ -592,8 +596,9 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
let start_label = self.next_label_name();
let end_label = self.next_label_name();
// Push end label to stack for 'break'
self.loop_stack.push(end_label.clone());
// Push labels to stack for 'break' and 'continue'
self.loop_stack
.push((start_label.clone(), end_label.clone()));
self.write_output(format!("{start_label}:"))?;
@@ -617,8 +622,9 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
let start_label = self.next_label_name();
let end_label = self.next_label_name();
// Push end label to stack for 'break'
self.loop_stack.push(end_label.clone());
// Push labels to stack for 'break' and 'continue'
self.loop_stack
.push((start_label.clone(), end_label.clone()));
self.write_output(format!("{start_label}:"))?;
@@ -645,8 +651,8 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
}
fn expression_break(&mut self) -> Result<(), Error> {
if let Some(label) = self.loop_stack.last() {
self.write_output(format!("j {label}"))?;
if let Some((_, end_label)) = self.loop_stack.last() {
self.write_output(format!("j {end_label}"))?;
Ok(())
} else {
// This is a semantic error, but for now we can return a generic error
@@ -655,6 +661,15 @@ impl<'a, W: std::io::Write> Compiler<'a, W> {
}
}
fn expression_continue(&mut self) -> Result<(), Error> {
if let Some((start_label, _)) = self.loop_stack.last() {
self.write_output(format!("j {start_label}"))?;
Ok(())
} else {
Err(Error::Unknown("Continue statement outside of loop".into()))
}
}
/// Helper to resolve a location to a register string (e.g., "r0").
/// Note: This does not handle Stack locations automatically, as they require
/// instruction emission to load. Use `compile_operand` for general handling.

View File

@@ -235,6 +235,16 @@ impl Parser {
Expression::Break
}
// match continue statements
TokenType::Keyword(Keyword::Continue) => {
// make sure the next token is a semi-colon
let next = token_from_option!(self.get_next()?);
if !token_matches!(next, TokenType::Symbol(Symbol::Semicolon)) {
return Err(Error::UnexpectedToken(next.clone()));
}
Expression::Continue
}
// match syscalls with a `syscall` keyword
TokenType::Identifier(ref id) if SysCall::is_syscall(id) => {
Expression::Syscall(self.syscall()?)
@@ -1192,3 +1202,4 @@ impl Parser {
}
}
}

View File

@@ -214,6 +214,7 @@ pub enum Expression {
Binary(BinaryExpression),
Block(BlockExpression),
Break,
Continue,
Declaration(String, Box<Expression>),
DeviceDeclaration(DeviceDeclarationExpression),
Function(FunctionExpression),
@@ -237,6 +238,7 @@ impl std::fmt::Display for Expression {
Expression::Binary(e) => write!(f, "{}", e),
Expression::Block(e) => write!(f, "{}", e),
Expression::Break => write!(f, "break"),
Expression::Continue => write!(f, "continue"),
Expression::Declaration(id, e) => write!(f, "(let {} = {})", id, e),
Expression::DeviceDeclaration(e) => write!(f, "{}", e),
Expression::Function(e) => write!(f, "{}", e),
@@ -254,4 +256,3 @@ impl std::fmt::Display for Expression {
}
}
}

View File

@@ -410,6 +410,7 @@ impl Tokenizer {
"loop" if next_ws!() => keyword!(Loop),
"break" if next_ws!() => keyword!(Break),
"while" if next_ws!() => keyword!(While),
"continue" if next_ws!() => keyword!(Continue),
// boolean literals
"true" if next_ws!() => {

View File

@@ -210,6 +210,8 @@ impl Symbol {
#[derive(Debug, PartialEq, Hash, Eq, Clone, Copy)]
pub enum Keyword {
/// Represents the `continue` keyword
Continue,
/// Represents the `let` keyword
Let,
/// Represents the `fn` keyword