function parameters
This commit is contained in:
parent
7f49c2d7a3
commit
bc02423fbd
5 changed files with 125 additions and 63 deletions
10
src/data.rs
10
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<Statement>);
|
||||
|
||||
|
|
|
@ -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,40 +23,54 @@ 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);
|
||||
|
@ -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,7 +108,7 @@ 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}");
|
||||
}
|
||||
|
@ -158,19 +164,16 @@ 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");
|
||||
|
@ -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);
|
||||
|
|
23
src/main.rs
23
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());
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
22
src/types.rs
22
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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue