From b6a38101f7d39709d60cba74f299f92a06588654 Mon Sep 17 00:00:00 2001 From: Sofia Date: Thu, 19 Mar 2026 17:31:12 +0200 Subject: [PATCH] Add parsing of elseif and else --- examples/test.lua | 55 ++++++--------------------------------- src/ast.rs | 43 ++++++++++++++++++++++++++---- src/compile.rs | 27 ++++++++++++++----- src/token_stream/lexer.rs | 6 +++++ 4 files changed, 73 insertions(+), 58 deletions(-) diff --git a/examples/test.lua b/examples/test.lua index bce02ce..2fa6c80 100644 --- a/examples/test.lua +++ b/examples/test.lua @@ -1,49 +1,10 @@ -global b = 5 -function add(x) - return function (y) - x = x + 1 - b = b + 1 - return x + y, 1, 2, b - end +local test = 10 +if test == 10 then + print("first") +elseif test == 11 then + print("second") +else + print("third") end - -function min(x, y) - local m = x - if y < x then - m = y - end - return m -end - - -function f(x, ...) - local b = {10, ..., add(10)(15)} - return x + 5, b -end - -global sometable = {} -sometable["hello"] = { 100, 150, add(10)(15) } -print(#sometable["hello"]) -sometable["hello"].there = "my dude" -print(sometable.hello.there) - -print(max(11.12345, 9)) -print(add(10)(15)) -print(add(10)(15)) -print(b) -print(min(11, 9)) -print(10 - 15) -print("hello there!") -print(true or 0) - -global value, table = f(10, 11, 12) - -print("hello") -for i=1,#table do - print(table[i]) - if i > 2 then - goto test - end -end -::test:: +print("after") diff --git a/src/ast.rs b/src/ast.rs index 4af6c5f..9ca6e25 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -234,7 +234,12 @@ impl Parse for Block { while !matches!( stream.peek(), - Some(Token::Keyword(Keyword::End) | Token::Eof) + Some( + Token::Keyword(Keyword::End) + | Token::Keyword(Keyword::ElseIf) + | Token::Keyword(Keyword::Else) + | Token::Eof + ) ) { statements.push(stream.parse()?); } @@ -254,7 +259,11 @@ pub enum Statement { ExpressionList, ), Return(ExpressionList), - If(Node, Block), + If { + if_part: (Node, Block), + elif: Vec<(Node, Block)>, + else_block: Block, + }, Expression(Node), NumericalFor( Node, @@ -296,11 +305,35 @@ impl Parse for Statement { Ok(Statement::Return(stream.parse()?)) } else if peeked == Some(Token::Keyword(Keyword::If)) { stream.next(); // Consume if - let cond = stream.parse()?; + let if_cond = stream.parse()?; stream.expect(Token::Keyword(Keyword::Then))?; - let then = stream.parse()?; + let if_block = stream.parse()?; + + let mut elif = Vec::new(); + while let Some(Token::Keyword(Keyword::ElseIf)) = stream.peek() { + stream.next(); + let elif_cond = stream.parse()?; + stream.expect(Token::Keyword(Keyword::Then))?; + let elif_block = stream.parse()?; + elif.push((elif_cond, elif_block)); + } + + let else_block = if let Some(Token::Keyword(Keyword::Else)) = stream.peek() { + stream.next(); + stream.parse()? + } else { + Block { + statements: Vec::new(), + _meta: Metadata::empty(), + } + }; + stream.expect(Token::Keyword(Keyword::End))?; - Ok(Self::If(cond, then)) + Ok(Self::If { + if_part: (if_cond, if_block), + elif: elif, + else_block, + }) } else if let Some(Token::Keyword(Keyword::Local | Keyword::Global)) = peeked { let access_modifier = match stream.next() { Some(Token::Keyword(Keyword::Local)) => AccessModifier::Local, diff --git a/src/compile.rs b/src/compile.rs index 0f40dd9..73183b4 100644 --- a/src/compile.rs +++ b/src/compile.rs @@ -187,10 +187,21 @@ impl Statement { } constants } - Statement::If(cond, then) => { + Statement::If { + if_part, + elif, + else_block, + } => { let mut constants = HashSet::new(); - constants.extend(cond.kind.find_constants(scope)); - constants.extend(then.find_constants(scope, Vec::new())); + constants.extend(if_part.0.kind.find_constants(scope)); + constants.extend(if_part.1.find_constants(scope, Vec::new())); + + for (cond, block) in elif { + constants.extend(cond.kind.find_constants(scope)); + constants.extend(block.find_constants(scope, Vec::new())); + } + + constants.extend(else_block.find_constants(scope, Vec::new())); constants } Statement::Expression(expr) => expr.kind.find_constants(scope), @@ -397,8 +408,12 @@ impl Statement { }, ))); } - Statement::If(expr, block) => { - let (instr, regs) = expr.kind.compile(state, scope, Some(1)); + Statement::If { + if_part, + elif, + else_block, + } => { + let (instr, regs) = if_part.0.kind.compile(state, scope, Some(1)); instructions.extend(instr); let local = scope.register_counter.next(); @@ -408,7 +423,7 @@ impl Statement { 0, ))); - let block_instructions = block.compile(state, scope); + let block_instructions = if_part.1.compile(state, scope); instructions.push(PreInstr::Instr(Instruction::Jmp( block_instructions.len() as i32 ))); diff --git a/src/token_stream/lexer.rs b/src/token_stream/lexer.rs index 0d98ebf..746a5e9 100644 --- a/src/token_stream/lexer.rs +++ b/src/token_stream/lexer.rs @@ -15,6 +15,8 @@ pub enum Keyword { Global, Return, If, + ElseIf, + Else, Then, True, False, @@ -35,6 +37,8 @@ impl Keyword { "global" => Keyword::Global, "return" => Keyword::Return, "if" => Keyword::If, + "elseif" => Keyword::ElseIf, + "else" => Keyword::Else, "then" => Keyword::Then, "true" => Keyword::True, "false" => Keyword::False, @@ -58,6 +62,8 @@ impl ToString for Keyword { Keyword::Global => "global", Keyword::Return => "return", Keyword::If => "if", + Keyword::ElseIf => "elif", + Keyword::Else => "else", Keyword::Then => "then", Keyword::True => "true", Keyword::False => "false",