From 574b9fd37c5d234d4b557acee350ef501dcd3c45 Mon Sep 17 00:00:00 2001 From: Toni Date: Sun, 29 Jun 2025 10:36:55 +0200 Subject: [PATCH] array indexing, nested array literals --- examples/arrays.zr | 13 +++------ examples/quicksort.zr | 16 ++++++------ examples/rule110.zr | 13 ++++----- src/codegen_x86_64.rs | 35 +++++++++---------------- src/parser.rs | 61 ++++++++++++++++++++++++++++++++----------- test.zr | 2 +- 6 files changed, 79 insertions(+), 61 deletions(-) diff --git a/examples/arrays.zr b/examples/arrays.zr index d03aa0c..ceacf89 100644 --- a/examples/arrays.zr +++ b/examples/arrays.zr @@ -1,10 +1,5 @@ func main[] : I64 - let xs: Array = [5849, 3869, 2859] - Array.push(xs, 5242) - Array.push(xs, 6533) - Array.push(xs, 4574) - - for i in 0..Array.size(xs) - xs - |> Array.nth(i) - |> print_i64() \ No newline at end of file + let xs: Array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] + for x in 0..3 + for y in 0..3 + print_i64(xs[y][x]) \ No newline at end of file diff --git a/examples/quicksort.zr b/examples/quicksort.zr index 9994087..c556a7f 100644 --- a/examples/quicksort.zr +++ b/examples/quicksort.zr @@ -8,16 +8,16 @@ func do_quicksort[arr: Array, low: I64, high: I64] : I64 do_quicksort(arr, i + 1, high) func partition[arr: Array, low: I64, high: I64] : I64 - let pivot: I64 = Array.nth(arr, high) + let pivot: I64 = arr[high] let i: I64 = low - 1 for j in (low)..high - if Array.nth(arr, j) <= pivot + if arr[j] <= pivot i = i + 1 - let temp: I64 = Array.nth(arr, i) - Array.set(arr, i, Array.nth(arr, j)) + let temp: I64 = arr[i] + Array.set(arr, i, arr[j]) Array.set(arr, j, temp) - let temp: I64 = Array.nth(arr, i + 1) - Array.set(arr, i + 1, Array.nth(arr, high)) + let temp: I64 = arr[i + 1] + Array.set(arr, i + 1, arr[high]) Array.set(arr, high, temp) return i + 1 @@ -25,10 +25,10 @@ func main[] : I64 let arr: Array = [340, 252, 352, 117, 650, 652, 322, 175, 714, 268, 725, 664] for i in 0..Array.size(arr) - print_i64(Array.nth(arr, i)) + print_i64(arr[i]) print("------------") quicksort(arr) for i in 0..Array.size(arr) - print_i64(Array.nth(arr, i)) \ No newline at end of file + print_i64(arr[i]) \ No newline at end of file diff --git a/examples/rule110.zr b/examples/rule110.zr index d34058e..410a7f6 100644 --- a/examples/rule110.zr +++ b/examples/rule110.zr @@ -1,14 +1,15 @@ func rule110_step[state: Array] : Array let new_state: Array = [] + let state_len: I64 = Array.size(state) - for i in 0..Array.size(state) + for i in 0..state_len let left: Bool = false if i - 1 >= 0 - left = Array.nth(state, i-1) - let center: Bool = Array.nth(state, i) + left = state[i-1] + let center: Bool = state[i] let right: Bool = false - if i + 1 < Array.size(state) - right = Array.nth(state, i+1) + if i + 1 < state_len + right = state[i+1] Array.push(new_state, !((!left && !center && !right) || (left && !center && !right) || (left && center && right))) @@ -17,7 +18,7 @@ func rule110_step[state: Array] : Array func to_str[state: Array]: String let out: String = malloc(Array.size(state)) for i in 0..Array.size(state) - if Array.nth(state, i) + if state[i] String.set(out, i, '#') else String.set(out, i, ' ') diff --git a/src/codegen_x86_64.rs b/src/codegen_x86_64.rs index 1edac7f..0cf9ee0 100644 --- a/src/codegen_x86_64.rs +++ b/src/codegen_x86_64.rs @@ -58,8 +58,6 @@ macro_rules! emit { } static REGISTERS: [&str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; -// TODO: currently they are all just 8 byte values -static TYPES: [&str; 6] = ["U8", "I64", "String", "Bool", "Ptr", "Array"]; pub struct CodegenX86_64 { output: String, @@ -234,12 +232,6 @@ OS.listdir: pop r14 ret -section .text.Array.nth -Array.nth: - mov rax, [rdi] - mov rax, [rax + rsi*8] - ret - section .text.Array.set Array.set: mov rax, [rdi] @@ -302,11 +294,6 @@ Array.free: var_type, initializer, } => { - // TODO: types - if !TYPES.contains(&var_type.lexeme.as_str()) { - return error!(&name.loc, format!("unknown type: {}", var_type.lexeme)); - } - self.compile_expr(env, initializer)?; let offset = env.define_var(name.lexeme.clone(), var_type.lexeme); emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); @@ -353,10 +340,6 @@ Array.free: return_type, body, } => { - if !TYPES.contains(&return_type.lexeme.as_str()) { - return error!(&name.loc, format!("unknown type: {}", return_type.lexeme)); - } - // TODO if name.lexeme == "main" { emit!(&mut self.output, "global {}", name.lexeme); @@ -377,7 +360,7 @@ Array.free: Some(x) => x, None => return error!(&name.loc, "only up to 6 params allowed"), }; - emit!(&mut self.output, " mov QWORD [rbp-{}], {}", offset, reg,); + emit!(&mut self.output, " mov QWORD [rbp-{}], {}", offset, reg); } self.compile_stmt(env, *body)?; @@ -625,16 +608,24 @@ Array.free: } Expr::ArrayLiteral(exprs) => { emit!(&mut self.output, " call Array.new"); - emit!(&mut self.output, " mov r12, rax"); + emit!(&mut self.output, " push rax"); - // TODO: nested array literals probably dont work for expr in exprs { self.compile_expr(env, expr)?; emit!(&mut self.output, " mov rsi, rax"); - emit!(&mut self.output, " mov rdi, r12"); + emit!(&mut self.output, " pop rdi"); + emit!(&mut self.output, " push rdi"); emit!(&mut self.output, " call Array.push"); } - emit!(&mut self.output, " mov rax, r12"); + emit!(&mut self.output, " pop rax"); + } + Expr::Index { expr, index } => { + self.compile_expr(env, *expr)?; + emit!(&mut self.output, " push rax"); + self.compile_expr(env, *index)?; + emit!(&mut self.output, " pop rbx"); + emit!(&mut self.output, " mov rbx, [rbx]"); + emit!(&mut self.output, " mov rax, [rbx + rax*8]"); } } Ok(()) diff --git a/src/parser.rs b/src/parser.rs index a73b414..365435b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -67,8 +67,15 @@ pub enum Expr { args: Vec, }, ArrayLiteral(Vec), + Index { + expr: Box, + index: Box, + }, } +// TODO: currently they are all just 8 byte values +static TYPES: [&str; 6] = ["U8", "I64", "String", "Bool", "Ptr", "Array"]; + pub struct Parser { tokens: Vec, current: usize, @@ -120,7 +127,12 @@ impl Parser { loop { let var_name = self.consume(TokenType::Identifier, "expected parameter name")?; self.consume(TokenType::Colon, "expected ':' after parameter name")?; + let var_type = self.consume(TokenType::Identifier, "expected parameter type")?; + if !TYPES.contains(&var_type.lexeme.as_str()) { + return error!(&name.loc, format!("unknown type: {}", var_type.lexeme)); + } + params.push(Param { var_type, var_name }); if !self.match_token(&[TokenType::Comma]) { break; @@ -131,6 +143,9 @@ impl Parser { self.consume(TokenType::RightBracket, "expected ']' after arguments")?; self.consume(TokenType::Colon, "expected ':' after '['")?; let return_type = self.consume(TokenType::Identifier, "expected return type")?; + if !TYPES.contains(&return_type.lexeme.as_str()) { + return error!(&name.loc, format!("unknown type: {}", return_type.lexeme)); + } self.is_inside_function = true; let body = Box::new(self.block()?); @@ -147,7 +162,12 @@ impl Parser { fn let_declaration(&mut self) -> Result { let name = self.consume(TokenType::Identifier, "expected variable name")?; self.consume(TokenType::Colon, "expected ':' after variable name")?; + let var_type = self.consume(TokenType::Identifier, "expected variable type")?; + if !TYPES.contains(&var_type.lexeme.as_str()) { + return error!(&name.loc, format!("unknown type: {}", var_type.lexeme)); + } + self.consume(TokenType::Equal, "expected '=' after variable type")?; let initializer = self.expression()?; Ok(Stmt::Let { @@ -401,24 +421,35 @@ impl Parser { fn call(&mut self) -> Result { let mut expr = self.primary()?; - while self.match_token(&[TokenType::LeftParen]) { - let mut args = vec![]; - if !self.check(&TokenType::RightParen) { - loop { - args.push(self.expression()?); - if !self.match_token(&[TokenType::Comma]) { - break; + loop { + if self.match_token(&[TokenType::LeftParen]) { + let mut args = vec![]; + if !self.check(&TokenType::RightParen) { + loop { + args.push(self.expression()?); + if !self.match_token(&[TokenType::Comma]) { + break; + } } } + + let paren = self.consume(TokenType::RightParen, "expected ')' after arguments")?; + + expr = Expr::Call { + callee: Box::new(expr), + paren, + args, + }; + } else if self.match_token(&[TokenType::LeftBracket]) { + let index = self.expression()?; + self.consume(TokenType::RightBracket, "expected ']' after index")?; + expr = Expr::Index { + expr: Box::new(expr), + index: Box::new(index), + } + } else { + break; } - - let paren = self.consume(TokenType::RightParen, "expected ')' after arguments")?; - - expr = Expr::Call { - callee: Box::new(expr), - paren, - args, - }; } Ok(expr) diff --git a/test.zr b/test.zr index 41eefff..5f2bc80 100644 --- a/test.zr +++ b/test.zr @@ -26,4 +26,4 @@ func main[] : I64 let files: Array = OS.listdir("examples/") for i in 0..Array.size(files) - run_test(Array.nth(files, i)) \ No newline at end of file + run_test(files[i]) \ No newline at end of file