destructuring multiple returns

This commit is contained in:
2026-05-28 16:55:16 +02:00
parent eb14607f2a
commit 0b16cc4513
5 changed files with 73 additions and 2 deletions

View File

@@ -275,6 +275,31 @@ _builtin_environ:
_ => return error!(&op.loc, "invalid assignment target"), _ => return error!(&op.loc, "invalid assignment target"),
}; };
} }
Stmt::Destructure { targets, op, value } => {
self.compile_expr(env, value)?;
for (i, target) in targets.iter().enumerate() {
let reg = match i {
0 => "rax",
1 => "rdx",
_ => {
return error!(
&op.loc,
"destructuring more than 2 values not implemented yet"
);
}
};
let offset = match env.get_var(&target.lexeme) {
Some(var) => var.stack_offset,
None => {
let types: Vec<&str> = self.expr_types[&value.id].split(',').collect();
env.define_var(target.lexeme.clone(), types[i].to_string())
}
};
emit!(&mut self.output, " mov QWORD [rbp-{}], {}", offset, reg);
}
}
Stmt::Const { name: _, value: _ } => { Stmt::Const { name: _, value: _ } => {
// handled in SymbolTable // handled in SymbolTable
} }

View File

@@ -1,6 +1,10 @@
use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::atomic::{AtomicUsize, Ordering};
use crate::tokenizer::{Token, TokenType, ZernError, error}; use crate::tokenizer::{
Token,
TokenType::{self, Identifier},
ZernError, error,
};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Param { pub struct Param {
@@ -27,6 +31,11 @@ pub enum Stmt {
op: Token, op: Token,
value: Expr, value: Expr,
}, },
Destructure {
targets: Vec<Token>,
op: Token,
value: Expr,
},
Const { Const {
name: Token, name: Token,
value: Token, value: Token,
@@ -322,6 +331,18 @@ impl Parser {
Ok(Stmt::Break) Ok(Stmt::Break)
} else if self.match_token(&[TokenType::KeywordContinue]) { } else if self.match_token(&[TokenType::KeywordContinue]) {
Ok(Stmt::Continue) Ok(Stmt::Continue)
} else if self.match_token(&[TokenType::Tilde]) {
let mut targets = vec![];
loop {
targets.push(self.consume(Identifier, "expected an identifier")?);
if !self.match_token(&[TokenType::Comma]) {
break;
}
}
let op = self.consume(TokenType::Colon, "expected ':'")?;
self.consume(TokenType::Equal, "expected '=' after ':'")?;
let value = self.expression()?;
Ok(Stmt::Destructure { targets, op, value })
} else { } else {
let expr = self.expression()?; let expr = self.expression()?;
if self.match_token(&[TokenType::Equal]) { if self.match_token(&[TokenType::Equal]) {

View File

@@ -123,6 +123,9 @@ func mem.free[x: any] : void
return 0 return 0
blk := (x as ptr - MEM_BLOCK_SIZE) as mem.Block blk := (x as ptr - MEM_BLOCK_SIZE) as mem.Block
if blk->free
return 0
blk->free = true blk->free = true
next := blk->next next := blk->next

View File

@@ -24,6 +24,7 @@ pub enum TokenType {
ShiftLeft, ShiftLeft,
ShiftRight, ShiftRight,
Arrow, Arrow,
Tilde,
Equal, Equal,
DoubleEqual, DoubleEqual,
@@ -159,6 +160,7 @@ impl Tokenizer {
'%' => self.add_token(TokenType::Mod)?, '%' => self.add_token(TokenType::Mod)?,
'^' => self.add_token(TokenType::Xor)?, '^' => self.add_token(TokenType::Xor)?,
':' => self.add_token(TokenType::Colon)?, ':' => self.add_token(TokenType::Colon)?,
'~' => self.add_token(TokenType::Tilde)?,
'-' => { '-' => {
if self.match_char('>') { if self.match_char('>') {
self.add_token(TokenType::Arrow)? self.add_token(TokenType::Arrow)?

View File

@@ -176,6 +176,26 @@ impl<'a> TypeChecker<'a> {
_ => return error!(&op.loc, "invalid assignment target"), _ => return error!(&op.loc, "invalid assignment target"),
} }
} }
Stmt::Destructure { targets, op, value } => {
let value_type = self.typecheck_expr(env, value)?;
let types: Vec<&str> = value_type.split(',').collect();
if types.len() != targets.len() {
return error!(
&op.loc,
"destructure target count does not match return count"
);
}
for (target, ty) in targets.iter().zip(types.iter()) {
match env.get_var_type(&target.lexeme) {
Some(existing) => {
expect_type!(ty.to_string(), *existing, target.loc);
}
None => {
env.define_var(target.lexeme.clone(), ty.to_string());
}
}
}
}
Stmt::Const { name: _, value: _ } => { Stmt::Const { name: _, value: _ } => {
// handled in SymbolTable // handled in SymbolTable
} }
@@ -257,7 +277,7 @@ impl<'a> TypeChecker<'a> {
if params[0].var_type.lexeme != "i64" { if params[0].var_type.lexeme != "i64" {
return error!( return error!(
&name.loc, &name.loc,
"first parameter of the main function must be a i64" "first parameter of the main function must be an i64"
); );
} }
if params[1].var_type.lexeme != "ptr" { if params[1].var_type.lexeme != "ptr" {