array indexing, nested array literals

This commit is contained in:
2025-06-29 10:36:55 +02:00
parent 26598fe6f2
commit 574b9fd37c
6 changed files with 79 additions and 61 deletions

View File

@@ -1,10 +1,5 @@
func main[] : I64 func main[] : I64
let xs: Array = [5849, 3869, 2859] let xs: Array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
Array.push(xs, 5242) for x in 0..3
Array.push(xs, 6533) for y in 0..3
Array.push(xs, 4574) print_i64(xs[y][x])
for i in 0..Array.size(xs)
xs
|> Array.nth(i)
|> print_i64()

View File

@@ -8,16 +8,16 @@ func do_quicksort[arr: Array, low: I64, high: I64] : I64
do_quicksort(arr, i + 1, high) do_quicksort(arr, i + 1, high)
func partition[arr: Array, low: I64, high: I64] : I64 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 let i: I64 = low - 1
for j in (low)..high for j in (low)..high
if Array.nth(arr, j) <= pivot if arr[j] <= pivot
i = i + 1 i = i + 1
let temp: I64 = Array.nth(arr, i) let temp: I64 = arr[i]
Array.set(arr, i, Array.nth(arr, j)) Array.set(arr, i, arr[j])
Array.set(arr, j, temp) Array.set(arr, j, temp)
let temp: I64 = Array.nth(arr, i + 1) let temp: I64 = arr[i + 1]
Array.set(arr, i + 1, Array.nth(arr, high)) Array.set(arr, i + 1, arr[high])
Array.set(arr, high, temp) Array.set(arr, high, temp)
return i + 1 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] let arr: Array = [340, 252, 352, 117, 650, 652, 322, 175, 714, 268, 725, 664]
for i in 0..Array.size(arr) for i in 0..Array.size(arr)
print_i64(Array.nth(arr, i)) print_i64(arr[i])
print("------------") print("------------")
quicksort(arr) quicksort(arr)
for i in 0..Array.size(arr) for i in 0..Array.size(arr)
print_i64(Array.nth(arr, i)) print_i64(arr[i])

View File

@@ -1,14 +1,15 @@
func rule110_step[state: Array] : Array func rule110_step[state: Array] : Array
let new_state: 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 let left: Bool = false
if i - 1 >= 0 if i - 1 >= 0
left = Array.nth(state, i-1) left = state[i-1]
let center: Bool = Array.nth(state, i) let center: Bool = state[i]
let right: Bool = false let right: Bool = false
if i + 1 < Array.size(state) if i + 1 < state_len
right = Array.nth(state, i+1) right = state[i+1]
Array.push(new_state, !((!left && !center && !right) || (left && !center && !right) || (left && center && right))) 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 func to_str[state: Array]: String
let out: String = malloc(Array.size(state)) let out: String = malloc(Array.size(state))
for i in 0..Array.size(state) for i in 0..Array.size(state)
if Array.nth(state, i) if state[i]
String.set(out, i, '#') String.set(out, i, '#')
else else
String.set(out, i, ' ') String.set(out, i, ' ')

View File

@@ -58,8 +58,6 @@ macro_rules! emit {
} }
static REGISTERS: [&str; 6] = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]; 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 { pub struct CodegenX86_64 {
output: String, output: String,
@@ -234,12 +232,6 @@ OS.listdir:
pop r14 pop r14
ret ret
section .text.Array.nth
Array.nth:
mov rax, [rdi]
mov rax, [rax + rsi*8]
ret
section .text.Array.set section .text.Array.set
Array.set: Array.set:
mov rax, [rdi] mov rax, [rdi]
@@ -302,11 +294,6 @@ Array.free:
var_type, var_type,
initializer, 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)?; self.compile_expr(env, initializer)?;
let offset = env.define_var(name.lexeme.clone(), var_type.lexeme); let offset = env.define_var(name.lexeme.clone(), var_type.lexeme);
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset); emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
@@ -353,10 +340,6 @@ Array.free:
return_type, return_type,
body, body,
} => { } => {
if !TYPES.contains(&return_type.lexeme.as_str()) {
return error!(&name.loc, format!("unknown type: {}", return_type.lexeme));
}
// TODO // TODO
if name.lexeme == "main" { if name.lexeme == "main" {
emit!(&mut self.output, "global {}", name.lexeme); emit!(&mut self.output, "global {}", name.lexeme);
@@ -377,7 +360,7 @@ Array.free:
Some(x) => x, Some(x) => x,
None => return error!(&name.loc, "only up to 6 params allowed"), 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)?; self.compile_stmt(env, *body)?;
@@ -625,16 +608,24 @@ Array.free:
} }
Expr::ArrayLiteral(exprs) => { Expr::ArrayLiteral(exprs) => {
emit!(&mut self.output, " call Array.new"); 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 { for expr in exprs {
self.compile_expr(env, expr)?; self.compile_expr(env, expr)?;
emit!(&mut self.output, " mov rsi, rax"); 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, " 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(()) Ok(())

View File

@@ -67,8 +67,15 @@ pub enum Expr {
args: Vec<Expr>, args: Vec<Expr>,
}, },
ArrayLiteral(Vec<Expr>), ArrayLiteral(Vec<Expr>),
Index {
expr: Box<Expr>,
index: Box<Expr>,
},
} }
// TODO: currently they are all just 8 byte values
static TYPES: [&str; 6] = ["U8", "I64", "String", "Bool", "Ptr", "Array"];
pub struct Parser { pub struct Parser {
tokens: Vec<Token>, tokens: Vec<Token>,
current: usize, current: usize,
@@ -120,7 +127,12 @@ impl Parser {
loop { loop {
let var_name = self.consume(TokenType::Identifier, "expected parameter name")?; let var_name = self.consume(TokenType::Identifier, "expected parameter name")?;
self.consume(TokenType::Colon, "expected ':' after parameter name")?; self.consume(TokenType::Colon, "expected ':' after parameter name")?;
let var_type = self.consume(TokenType::Identifier, "expected parameter type")?; 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 }); params.push(Param { var_type, var_name });
if !self.match_token(&[TokenType::Comma]) { if !self.match_token(&[TokenType::Comma]) {
break; break;
@@ -131,6 +143,9 @@ impl Parser {
self.consume(TokenType::RightBracket, "expected ']' after arguments")?; self.consume(TokenType::RightBracket, "expected ']' after arguments")?;
self.consume(TokenType::Colon, "expected ':' after '['")?; self.consume(TokenType::Colon, "expected ':' after '['")?;
let return_type = self.consume(TokenType::Identifier, "expected return type")?; 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; self.is_inside_function = true;
let body = Box::new(self.block()?); let body = Box::new(self.block()?);
@@ -147,7 +162,12 @@ impl Parser {
fn let_declaration(&mut self) -> Result<Stmt, ZernError> { fn let_declaration(&mut self) -> Result<Stmt, ZernError> {
let name = self.consume(TokenType::Identifier, "expected variable name")?; let name = self.consume(TokenType::Identifier, "expected variable name")?;
self.consume(TokenType::Colon, "expected ':' after variable name")?; self.consume(TokenType::Colon, "expected ':' after variable name")?;
let var_type = self.consume(TokenType::Identifier, "expected variable type")?; 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")?; self.consume(TokenType::Equal, "expected '=' after variable type")?;
let initializer = self.expression()?; let initializer = self.expression()?;
Ok(Stmt::Let { Ok(Stmt::Let {
@@ -401,7 +421,8 @@ impl Parser {
fn call(&mut self) -> Result<Expr, ZernError> { fn call(&mut self) -> Result<Expr, ZernError> {
let mut expr = self.primary()?; let mut expr = self.primary()?;
while self.match_token(&[TokenType::LeftParen]) { loop {
if self.match_token(&[TokenType::LeftParen]) {
let mut args = vec![]; let mut args = vec![];
if !self.check(&TokenType::RightParen) { if !self.check(&TokenType::RightParen) {
loop { loop {
@@ -419,6 +440,16 @@ impl Parser {
paren, paren,
args, 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;
}
} }
Ok(expr) Ok(expr)

View File

@@ -26,4 +26,4 @@ func main[] : I64
let files: Array = OS.listdir("examples/") let files: Array = OS.listdir("examples/")
for i in 0..Array.size(files) for i in 0..Array.size(files)
run_test(Array.nth(files, i)) run_test(files[i])