From bc02423fbdec8b974fefb287024acf861e489ea2 Mon Sep 17 00:00:00 2001 From: tezlm Date: Mon, 2 Oct 2023 00:48:28 -0700 Subject: [PATCH] function parameters --- src/data.rs | 10 ++++- src/generator.rs | 101 +++++++++++++++++++++++++---------------------- src/main.rs | 23 +++++++---- src/parser.rs | 32 ++++++++++++--- src/types.rs | 22 ++++++++++- 5 files changed, 125 insertions(+), 63 deletions(-) diff --git a/src/data.rs b/src/data.rs index 97e89d7..6e00419 100644 --- a/src/data.rs +++ b/src/data.rs @@ -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); diff --git a/src/generator.rs b/src/generator.rs index 139d1b0..9cef89d 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -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, @@ -15,9 +15,7 @@ pub struct Generator { impl Generator { pub fn new(output: Box) -> 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); diff --git a/src/main.rs b/src/main.rs index 69bdc11..d5ced3a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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()); diff --git a/src/parser.rs b/src/parser.rs index 75e6573..dfacd42 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -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, + pub funcs: HashMap, 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) } diff --git a/src/types.rs b/src/types.rs index c5e2211..2e23153 100644 --- a/src/types.rs +++ b/src/types.rs @@ -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(), } } }