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