parse variadic functions
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
use std::{collections::HashMap, fmt::Write};
|
use std::{collections::HashMap, fmt::Write};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
parser::{Expr, Stmt},
|
parser::{Expr, Params, Stmt},
|
||||||
symbol_table::SymbolTable,
|
symbol_table::SymbolTable,
|
||||||
tokenizer::{Token, TokenType, ZernError, error},
|
tokenizer::{Token, TokenType, ZernError, error},
|
||||||
};
|
};
|
||||||
@@ -317,20 +317,27 @@ _builtin_environ:
|
|||||||
emit!(&mut self.output, " mov rbp, rsp");
|
emit!(&mut self.output, " mov rbp, rsp");
|
||||||
emit!(&mut self.output, " sub rsp, 256"); // TODO: eww
|
emit!(&mut self.output, " sub rsp, 256"); // TODO: eww
|
||||||
|
|
||||||
for (i, param) in params.iter().enumerate() {
|
match params {
|
||||||
let offset = env
|
Params::Normal(params) => {
|
||||||
.define_var(param.var_name.lexeme.clone(), param.var_type.lexeme.clone());
|
for (i, param) in params.iter().enumerate() {
|
||||||
if let Some(reg) = REGISTERS.get(i) {
|
let offset = env.define_var(
|
||||||
emit!(&mut self.output, " mov QWORD [rbp-{}], {}", offset, reg);
|
param.var_name.lexeme.clone(),
|
||||||
} else {
|
param.var_type.lexeme.clone(),
|
||||||
let stack_offset = 16 + 8 * (i - REGISTERS.len());
|
);
|
||||||
emit!(
|
if let Some(reg) = REGISTERS.get(i) {
|
||||||
&mut self.output,
|
emit!(&mut self.output, " mov QWORD [rbp-{}], {}", offset, reg);
|
||||||
" mov rax, QWORD [rbp+{}]",
|
} else {
|
||||||
stack_offset
|
let stack_offset = 16 + 8 * (i - REGISTERS.len());
|
||||||
);
|
emit!(
|
||||||
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
|
&mut self.output,
|
||||||
|
" mov rax, QWORD [rbp+{}]",
|
||||||
|
stack_offset
|
||||||
|
);
|
||||||
|
emit!(&mut self.output, " mov QWORD [rbp-{}], rax", offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Params::Variadic(_name) => todo!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.compile_stmt(env, body)?;
|
self.compile_stmt(env, body)?;
|
||||||
|
|||||||
@@ -6,6 +6,12 @@ pub struct Param {
|
|||||||
pub var_name: Token,
|
pub var_name: Token,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Params {
|
||||||
|
Normal(Vec<Param>),
|
||||||
|
Variadic(Token),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Stmt {
|
pub enum Stmt {
|
||||||
Expression(Expr),
|
Expression(Expr),
|
||||||
@@ -38,7 +44,7 @@ pub enum Stmt {
|
|||||||
},
|
},
|
||||||
Function {
|
Function {
|
||||||
name: Token,
|
name: Token,
|
||||||
params: Vec<Param>,
|
params: Params,
|
||||||
return_type: Token,
|
return_type: Token,
|
||||||
body: Box<Stmt>,
|
body: Box<Stmt>,
|
||||||
exported: bool,
|
exported: bool,
|
||||||
@@ -164,17 +170,25 @@ impl Parser {
|
|||||||
let name = self.consume(TokenType::Identifier, "expected function name")?;
|
let name = self.consume(TokenType::Identifier, "expected function name")?;
|
||||||
self.consume(TokenType::LeftBracket, "expected '[' after function name")?;
|
self.consume(TokenType::LeftBracket, "expected '[' after function name")?;
|
||||||
|
|
||||||
|
let mut variadic_param: Option<Token> = None;
|
||||||
let mut params = vec![];
|
let mut params = vec![];
|
||||||
if !self.check(&TokenType::RightBracket) {
|
if !self.check(&TokenType::RightBracket) {
|
||||||
loop {
|
if self.match_token(&[TokenType::DoubleDot]) {
|
||||||
let var_name = self.consume(TokenType::Identifier, "expected parameter name")?;
|
variadic_param =
|
||||||
self.consume(TokenType::Colon, "expected ':' after parameter name")?;
|
Some(self.consume(TokenType::Identifier, "expected variadic parameter name")?);
|
||||||
|
} else {
|
||||||
|
loop {
|
||||||
|
let var_name =
|
||||||
|
self.consume(TokenType::Identifier, "expected 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")?;
|
||||||
|
|
||||||
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,6 +201,10 @@ impl Parser {
|
|||||||
let body = Box::new(self.block()?);
|
let body = Box::new(self.block()?);
|
||||||
self.is_inside_function = false;
|
self.is_inside_function = false;
|
||||||
|
|
||||||
|
let params = match variadic_param {
|
||||||
|
Some(name) => Params::Variadic(name),
|
||||||
|
None => Params::Normal(params),
|
||||||
|
};
|
||||||
Ok(Stmt::Function {
|
Ok(Stmt::Function {
|
||||||
name,
|
name,
|
||||||
params,
|
params,
|
||||||
|
|||||||
@@ -1007,7 +1007,7 @@ func os.urandom?[n: i64]: ptr
|
|||||||
let fd: i64 = _builtin_syscall(SYS_openat, -100, "/dev/urandom", 0, 0)
|
let fd: i64 = _builtin_syscall(SYS_openat, -100, "/dev/urandom", 0, 0)
|
||||||
if fd < 0
|
if fd < 0
|
||||||
mem.free(buffer)
|
mem.free(buffer)
|
||||||
err.set(ERR_READ_FAILED, "os.urandom?: failed to open /dev/urandom")
|
err.set(ERR_OPEN_FAILED, "os.urandom?: failed to open /dev/urandom")
|
||||||
return 0 as ptr
|
return 0 as ptr
|
||||||
|
|
||||||
let bytes_read: i64 = _builtin_syscall(SYS_read, fd, buffer, n)
|
let bytes_read: i64 = _builtin_syscall(SYS_read, fd, buffer, n)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
parser::Stmt,
|
parser::{Params, Stmt},
|
||||||
tokenizer::{ZernError, error},
|
tokenizer::{ZernError, error},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -100,13 +100,24 @@ impl SymbolTable {
|
|||||||
if self.is_name_defined(&name.lexeme) {
|
if self.is_name_defined(&name.lexeme) {
|
||||||
return error!(name.loc, format!("tried to redefine '{}'", name.lexeme));
|
return error!(name.loc, format!("tried to redefine '{}'", name.lexeme));
|
||||||
}
|
}
|
||||||
self.functions.insert(
|
match params {
|
||||||
name.lexeme.clone(),
|
Params::Normal(params) => self.functions.insert(
|
||||||
FnType {
|
name.lexeme.clone(),
|
||||||
return_type: return_type.lexeme.clone(),
|
FnType {
|
||||||
params: Some(params.iter().map(|x| x.var_type.lexeme.clone()).collect()),
|
return_type: return_type.lexeme.clone(),
|
||||||
},
|
params: Some(
|
||||||
);
|
params.iter().map(|x| x.var_type.lexeme.clone()).collect(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Params::Variadic(name) => self.functions.insert(
|
||||||
|
name.lexeme.clone(),
|
||||||
|
FnType {
|
||||||
|
return_type: return_type.lexeme.clone(),
|
||||||
|
params: None,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
Stmt::Struct { name, fields } => {
|
Stmt::Struct { name, fields } => {
|
||||||
if self.is_name_defined(&name.lexeme) {
|
if self.is_name_defined(&name.lexeme) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
parser::{Expr, Stmt},
|
parser::{Expr, Params, Stmt},
|
||||||
symbol_table::{SymbolTable, Type},
|
symbol_table::{SymbolTable, Type},
|
||||||
tokenizer::{TokenType, ZernError, error},
|
tokenizer::{TokenType, ZernError, error},
|
||||||
};
|
};
|
||||||
@@ -171,22 +171,32 @@ impl<'a> TypeChecker<'a> {
|
|||||||
return error!(&name.loc, "main function must return i64");
|
return error!(&name.loc, "main function must return i64");
|
||||||
}
|
}
|
||||||
|
|
||||||
if !params.is_empty() && params.len() != 2 {
|
match params {
|
||||||
return error!(&name.loc, "main function must accept 0 or 2 parameters");
|
Params::Normal(params) => {
|
||||||
}
|
if !params.is_empty() && params.len() != 2 {
|
||||||
|
return error!(
|
||||||
|
&name.loc,
|
||||||
|
"main function must accept 0 or 2 parameters"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if params.len() == 2 {
|
if params.len() == 2 {
|
||||||
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 a i64"
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
if params[1].var_type.lexeme != "ptr" {
|
||||||
|
return error!(
|
||||||
|
&name.loc,
|
||||||
|
"second parameter of the main function must be a ptr"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if params[1].var_type.lexeme != "ptr" {
|
Params::Variadic(_) => {
|
||||||
return error!(
|
return error!(&name.loc, "main function cannot be variadic");
|
||||||
&name.loc,
|
|
||||||
"second parameter of the main function must be a ptr"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,15 +212,25 @@ impl<'a> TypeChecker<'a> {
|
|||||||
|
|
||||||
env.push_scope();
|
env.push_scope();
|
||||||
|
|
||||||
for param in params {
|
match params {
|
||||||
if !self.is_valid_type_name(¶m.var_type.lexeme) {
|
Params::Normal(params) => {
|
||||||
return error!(
|
for param in params {
|
||||||
¶m.var_name.loc,
|
if !self.is_valid_type_name(¶m.var_type.lexeme) {
|
||||||
"unrecognized type: ".to_owned() + ¶m.var_type.lexeme
|
return error!(
|
||||||
);
|
¶m.var_name.loc,
|
||||||
}
|
"unrecognized type: ".to_owned() + ¶m.var_type.lexeme
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
env.define_var(param.var_name.lexeme.clone(), param.var_type.lexeme.clone());
|
env.define_var(
|
||||||
|
param.var_name.lexeme.clone(),
|
||||||
|
param.var_type.lexeme.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Params::Variadic(name) => {
|
||||||
|
env.define_var(name.lexeme.clone(), "ptr".into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.typecheck_stmt(env, body)?;
|
self.typecheck_stmt(env, body)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user