function parameters

This commit is contained in:
tezlm 2023-10-02 00:48:28 -07:00
parent 7f49c2d7a3
commit bc02423fbd
Signed by: tezlm
GPG key ID: 649733FCD94AFBBA
5 changed files with 125 additions and 63 deletions

View file

@ -38,12 +38,20 @@ pub enum Statement {
Let(String, Expr),
// Type(String, Type),
Expr(Expr),
Func(String, Type, Block),
Func(Func),
// Break,
// Continue,
// Type,
}
#[derive(Debug, Clone)]
pub struct Func {
pub name: String,
pub params: Vec<(String, Type)>,
pub ret: Type,
pub block: Block
}
#[derive(Debug, Clone)]
pub struct Block(pub Vec<Statement>);

View file

@ -5,9 +5,9 @@ optimizations
- write negative numberss directly instead of as positive + sign flip
*/
use crate::Error;
use crate::data::{Expr, Literal, BinaryOp, PrefixOp, Statement, Pattern, Type, self, Block};
use crate::data::{self, BinaryOp, Block, Expr, Func, Literal, Pattern, PrefixOp, Statement, Type};
use crate::parser::Context;
use crate::Error;
pub struct Generator {
output: Box<dyn std::io::Write>,
@ -15,9 +15,7 @@ pub struct Generator {
impl Generator {
pub fn new(output: Box<dyn std::io::Write>) -> Generator {
Generator {
output
}
Generator { output }
}
fn write_module(&mut self, stmts: &[Statement]) -> Result<(), Error> {
@ -25,42 +23,56 @@ impl Generator {
write!(self.output, "(module");
for stmt in stmts {
match stmt {
Statement::Func(name, ret, block) => {
ctx.locals.insert(name.clone(), ret.clone());
},
Statement::Let(..) | Statement::Expr(..) => return Err(Error::syn("incorrect top level statement")),
Statement::Func(Func { name, ret, params, .. }) => {
ctx.funcs.insert(name.clone(), (params.clone(), ret.clone()));
}
Statement::Let(..) | Statement::Expr(..) => {
return Err(Error::syn("incorrect top level statement"))
}
};
}
for stmt in stmts {
match stmt {
Statement::Func(name, ret, block) => self.write_func(&ctx, name, ret, block)?,
Statement::Let(..) | Statement::Expr(..) => return Err(Error::syn("incorrect top level statement")),
Statement::Func(func) => self.write_func(&ctx, func)?,
Statement::Let(..) | Statement::Expr(..) => {
return Err(Error::syn("incorrect top level statement"))
}
};
}
write!(self.output, ")");
Ok(())
}
fn write_func(&mut self, ctx: &Context, name: &str, ret: &Type, block: &Block) -> Result<(), Error> {
write!(self.output, " (func ${name}");
if name == "main" {
fn write_func(&mut self, ctx: &Context, func: &Func) -> Result<(), Error> {
write!(self.output, " (func ${}", func.name);
if func.name == "main" {
write!(self.output, " (export \"_start\")");
}
if !ret.is_empty() {
write!(self.output, " (result {})", ret.string());
}
write!(self.output, " (local $match i32)");
writeln!(self.output);
let expr = Expr::Block(block.clone());
let expr = Expr::Block(func.block.clone());
let mut ctx = ctx.clone();
let mut exprs = Vec::new();
let inferred = block.infer(&ctx)?;
if ret != &inferred {
return Err(Error::TypeError(format!("fn should return {ret:?}, but instead returns {inferred:?}")));
for (name, ty) in &func.params {
ctx.locals.insert(name.clone(), ty.clone());
write!(self.output, " (param ${} {})", name, ty.string());
}
if !func.ret.is_empty() {
write!(self.output, " (result {})", func.ret.string());
}
writeln!(self.output);
writeln!(self.output, "(local $match i32)");
let inferred = func.block.infer(&ctx)?;
if func.ret != inferred {
return Err(Error::TypeError(format!(
"fn should return {:?}, but instead returns {inferred:?}",
func.ret
)));
}
get_locals(&expr, &mut ctx, &mut exprs);
for (name, _) in &exprs {
@ -75,9 +87,9 @@ impl Generator {
gen_expr(expr, &ctx);
println!("local.set ${name}");
}
gen_expr(&expr, &ctx);
write!(self.output, ")");
Ok(())
@ -85,12 +97,6 @@ impl Generator {
}
pub fn generate(statements: &[Statement]) -> Result<(), Error> {
let expr = match &statements[0] {
Statement::Expr(expr) => expr.clone(),
Statement::Func(name, ty, block) => data::Expr::Block(data::Block(vec![Statement::Func(name.clone(), ty.clone(), block.clone())])),
_ => todo!(),
};
let mut gen = Generator::new(Box::new(std::io::stdout()));
gen.write_module(statements)
}
@ -102,9 +108,9 @@ fn gen_expr(expr: &Expr, ctx: &Context) {
Literal::Float(f) => println!("f64.const {f}"),
Literal::Boolean(b) => println!("i32.const {}", if *b { 1 } else { 0 }),
_ => todo!(),
}
},
Expr::Variable(name) => {
println!("local.get ${name}");
println!("local.get ${name}");
}
Expr::Binary(op, a, b) => {
gen_expr(&a, ctx);
@ -122,7 +128,7 @@ fn gen_expr(expr: &Expr, ctx: &Context) {
BinaryOp::Sub => println!("{ty}.sub"),
BinaryOp::Div => println!("{ty}.div_u"), // do i _u or _s?
BinaryOp::Mod => println!("{ty}.rem_u"),
BinaryOp::Eq => println!("{ty}.eq"),
BinaryOp::Eq => println!("{ty}.eq"),
BinaryOp::Neq => println!("{ty}.neq"),
BinaryOp::Less => println!("{ty}.lt_u"),
BinaryOp::Greater => println!("{ty}.gt_u"),
@ -138,7 +144,7 @@ fn gen_expr(expr: &Expr, ctx: &Context) {
}
return;
}
gen_expr(e, ctx);
match op {
PrefixOp::Minus => {
@ -158,21 +164,18 @@ fn gen_expr(expr: &Expr, ctx: &Context) {
}
// FIXME: awful code until i fix patching up parser and lexer
Expr::Match(cond, arms) => {
println!(";; --- set match variable");
gen_expr(cond, ctx);
println!("local.set $match");
println!(";; --- generate match");
for (idx, (pat, expr)) in arms.iter().enumerate() {
match pat {
Pattern::Literal(lit) => match lit {
Literal::Integer(int) => println!("i32.const {}", int),
Literal::Boolean(b) => println!("i32.const {}", if *b { 1 } else { 0 }),
_ => todo!(),
}
},
};
println!("local.get $match");
println!("i32.eq");
println!("(if (result i32) (then");
@ -186,7 +189,6 @@ fn gen_expr(expr: &Expr, ctx: &Context) {
}
}
println!("{}", ")".repeat(arms.len() * 2));
println!(";; --- done");
}
Expr::Block(b) => {
for (i, stmt) in b.0.iter().enumerate() {
@ -197,11 +199,14 @@ fn gen_expr(expr: &Expr, ctx: &Context) {
println!("drop");
}
}
_ => {},
_ => {}
}
}
}
Expr::Call(func, _) => {
Expr::Call(func, args) => {
for expr in args {
gen_expr(expr, ctx);
}
println!("call ${func}");
}
};
@ -218,12 +223,12 @@ fn get_locals(expr: &Expr, ctx: &mut Context, exprs: &mut Vec<(String, Expr)>) {
exprs.push((name.clone(), expr.clone()));
}
Statement::Expr(expr) => get_locals(&expr, ctx, exprs),
Statement::Func(name, ret, ..) => {
Statement::Func(Func { name, ret, .. }) => {
ctx.locals.insert(name.clone(), todo!());
},
}
}
}
},
}
Expr::Unary(_, expr) => get_locals(&expr, ctx, exprs),
Expr::Binary(_, a, b) => {
get_locals(&a, ctx, exprs);

View file

@ -39,17 +39,26 @@ fn main() {
// }
// }
// ".into());
// let mut lexer = lexer::Lexer::new("
// fn main() -> i32 {
// two() * three()
// }
// fn two() -> i32 {
// (2 * 2) / 2
// }
// fn three() -> i32 {
// 10 * 6 / 20
// }
// ".into());
let mut lexer = lexer::Lexer::new("
fn main() -> i32 {
two() * three()
add_three(30)
}
fn two() -> i32 {
(2 * 2) / 2
}
fn three() -> i32 {
10 * 6 / 20
fn add_three(n: i32) -> i32 {
n + 3
}
".into());

View file

@ -1,6 +1,6 @@
use std::collections::HashMap;
use crate::data::{BinaryOp, Block, Expr, Literal, Pattern, PrefixOp, Statement, Type};
use crate::data::{BinaryOp, Block, Expr, Literal, Pattern, PrefixOp, Statement, Type, Func};
use crate::lexer::{Token, Symbol};
use crate::Error;
@ -12,6 +12,7 @@ pub struct Parser {
#[derive(Debug, Clone)]
pub struct Context {
pub locals: HashMap<String, Type>,
pub funcs: HashMap<String, (Vec<(String, Type)>, Type)>,
}
impl Parser {
@ -60,7 +61,20 @@ impl Parser {
self.eat(Token::Fn)?;
let name = self.parse_ident()?;
self.eat(Token::OpenParan)?;
// TODO: parameters
let mut params = vec![];
while !self.peek_tok().is_some_and(|tok| tok == &Token::CloseParan) {
let name = self.parse_ident()?;
self.eat(Token::Symbol(Symbol::Colon))?;
let ty = self.parse_type()?;
params.push((name, ty));
if self.peek_tok() == Some(&Token::Symbol(Symbol::Comma)) {
self.eat(Token::Symbol(Symbol::Comma))?;
} else {
break;
}
}
self.eat(Token::CloseParan)?;
let ret = if self.peek_tok().is_some_and(|tok| tok == &Token::Symbol(Symbol::ThinArrow)) {
self.eat(Token::Symbol(Symbol::ThinArrow))?;
@ -71,7 +85,7 @@ impl Parser {
self.eat(Token::OpenBrace)?;
let block = self.parse_block()?;
self.eat(Token::CloseBrace)?;
Statement::Func(name, ret, block)
Statement::Func(Func { name, params, ret, block })
}
_ => Statement::Expr(self.parse_expr(0)?),
};
@ -138,9 +152,17 @@ impl Parser {
let ident = ident.clone();
if self.peek_tok().is_some_and(|t| *t == Token::OpenParan) {
self.eat(Token::OpenParan);
// TODO: function parameters
let mut params = vec![];
while !self.peek_tok().is_some_and(|tok| tok == &Token::CloseParan) {
params.push(self.parse_expr(0)?);
if self.peek_tok() == Some(&Token::Symbol(Symbol::Comma)) {
self.eat(Token::Symbol(Symbol::Comma))?;
} else {
break;
}
}
self.eat(Token::CloseParan);
Expr::Call(ident, vec![])
Expr::Call(ident, params)
} else {
Expr::Variable(ident)
}

View file

@ -44,8 +44,25 @@ impl Expr {
Ok(match_ty)
}
Self::Block(block) => block.infer(ctx),
Self::Call(name, ..) => match ctx.locals.get(name) {
Some(ty) => Ok(ty.clone()),
Self::Call(name, args) => match ctx.funcs.get(name) {
Some((params, ret)) => {
if args.len() < params.len() {
return Err(Error::ty("missing parameters"));
}
if args.len() > params.len() {
return Err(Error::ty("too many parameters"));
}
for (arg, (name, ty)) in args.iter().zip(params) {
let got = arg.infer(ctx)?;
if got != *ty {
return Err(Error::TypeError(format!("wrong type for {name}: it should've been {ty:?} but you put a {got:?}", )));
}
}
Ok(ret.clone())
}
None => Err(Error::ReferenceError(format!(
"cannot find variable {name}"
))),
@ -149,6 +166,7 @@ impl Context {
pub fn new() -> Context {
Context {
locals: HashMap::new(),
funcs: HashMap::new(),
}
}
}