destructuring multiple returns
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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]) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)?
|
||||
|
||||
@@ -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" {
|
||||
|
||||
Reference in New Issue
Block a user