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"),
};
}
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: _ } => {
// handled in SymbolTable
}

View File

@@ -1,6 +1,10 @@
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)]
pub struct Param {
@@ -27,6 +31,11 @@ pub enum Stmt {
op: Token,
value: Expr,
},
Destructure {
targets: Vec<Token>,
op: Token,
value: Expr,
},
Const {
name: Token,
value: Token,
@@ -322,6 +331,18 @@ impl Parser {
Ok(Stmt::Break)
} else if self.match_token(&[TokenType::KeywordContinue]) {
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 {
let expr = self.expression()?;
if self.match_token(&[TokenType::Equal]) {

View File

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

View File

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

View File

@@ -176,6 +176,26 @@ impl<'a> TypeChecker<'a> {
_ => 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: _ } => {
// handled in SymbolTable
}
@@ -257,7 +277,7 @@ impl<'a> TypeChecker<'a> {
if params[0].var_type.lexeme != "i64" {
return error!(
&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" {