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),
|
Let(String, Expr),
|
||||||
// Type(String, Type),
|
// Type(String, Type),
|
||||||
Expr(Expr),
|
Expr(Expr),
|
||||||
Func(String, Type, Block),
|
Func(Func),
|
||||||
// Break,
|
// Break,
|
||||||
// Continue,
|
// Continue,
|
||||||
// Type,
|
// Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Func {
|
||||||
|
pub name: String,
|
||||||
|
pub params: Vec<(String, Type)>,
|
||||||
|
pub ret: Type,
|
||||||
|
pub block: Block
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Block(pub Vec<Statement>);
|
pub struct Block(pub Vec<Statement>);
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@ optimizations
|
||||||
- write negative numberss directly instead of as positive + sign flip
|
- write negative numberss directly instead of as positive + sign flip
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::Error;
|
use crate::data::{self, BinaryOp, Block, Expr, Func, Literal, Pattern, PrefixOp, Statement, Type};
|
||||||
use crate::data::{Expr, Literal, BinaryOp, PrefixOp, Statement, Pattern, Type, self, Block};
|
|
||||||
use crate::parser::Context;
|
use crate::parser::Context;
|
||||||
|
use crate::Error;
|
||||||
|
|
||||||
pub struct Generator {
|
pub struct Generator {
|
||||||
output: Box<dyn std::io::Write>,
|
output: Box<dyn std::io::Write>,
|
||||||
|
@ -15,9 +15,7 @@ pub struct Generator {
|
||||||
|
|
||||||
impl Generator {
|
impl Generator {
|
||||||
pub fn new(output: Box<dyn std::io::Write>) -> Generator {
|
pub fn new(output: Box<dyn std::io::Write>) -> Generator {
|
||||||
Generator {
|
Generator { output }
|
||||||
output
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_module(&mut self, stmts: &[Statement]) -> Result<(), Error> {
|
fn write_module(&mut self, stmts: &[Statement]) -> Result<(), Error> {
|
||||||
|
@ -25,40 +23,54 @@ impl Generator {
|
||||||
write!(self.output, "(module");
|
write!(self.output, "(module");
|
||||||
for stmt in stmts {
|
for stmt in stmts {
|
||||||
match stmt {
|
match stmt {
|
||||||
Statement::Func(name, ret, block) => {
|
Statement::Func(Func { name, ret, params, .. }) => {
|
||||||
ctx.locals.insert(name.clone(), ret.clone());
|
ctx.funcs.insert(name.clone(), (params.clone(), ret.clone()));
|
||||||
},
|
}
|
||||||
Statement::Let(..) | Statement::Expr(..) => return Err(Error::syn("incorrect top level statement")),
|
Statement::Let(..) | Statement::Expr(..) => {
|
||||||
|
return Err(Error::syn("incorrect top level statement"))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
for stmt in stmts {
|
for stmt in stmts {
|
||||||
match stmt {
|
match stmt {
|
||||||
Statement::Func(name, ret, block) => self.write_func(&ctx, name, ret, block)?,
|
Statement::Func(func) => self.write_func(&ctx, func)?,
|
||||||
Statement::Let(..) | Statement::Expr(..) => return Err(Error::syn("incorrect top level statement")),
|
Statement::Let(..) | Statement::Expr(..) => {
|
||||||
|
return Err(Error::syn("incorrect top level statement"))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
write!(self.output, ")");
|
write!(self.output, ")");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_func(&mut self, ctx: &Context, name: &str, ret: &Type, block: &Block) -> Result<(), Error> {
|
fn write_func(&mut self, ctx: &Context, func: &Func) -> Result<(), Error> {
|
||||||
write!(self.output, " (func ${name}");
|
write!(self.output, " (func ${}", func.name);
|
||||||
if name == "main" {
|
if func.name == "main" {
|
||||||
write!(self.output, " (export \"_start\")");
|
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 ctx = ctx.clone();
|
||||||
let mut exprs = Vec::new();
|
let mut exprs = Vec::new();
|
||||||
|
|
||||||
let inferred = block.infer(&ctx)?;
|
for (name, ty) in &func.params {
|
||||||
if ret != &inferred {
|
ctx.locals.insert(name.clone(), ty.clone());
|
||||||
return Err(Error::TypeError(format!("fn should return {ret:?}, but instead returns {inferred:?}")));
|
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);
|
get_locals(&expr, &mut ctx, &mut exprs);
|
||||||
|
@ -85,12 +97,6 @@ impl Generator {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(statements: &[Statement]) -> Result<(), Error> {
|
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()));
|
let mut gen = Generator::new(Box::new(std::io::stdout()));
|
||||||
gen.write_module(statements)
|
gen.write_module(statements)
|
||||||
}
|
}
|
||||||
|
@ -102,7 +108,7 @@ fn gen_expr(expr: &Expr, ctx: &Context) {
|
||||||
Literal::Float(f) => println!("f64.const {f}"),
|
Literal::Float(f) => println!("f64.const {f}"),
|
||||||
Literal::Boolean(b) => println!("i32.const {}", if *b { 1 } else { 0 }),
|
Literal::Boolean(b) => println!("i32.const {}", if *b { 1 } else { 0 }),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
},
|
||||||
Expr::Variable(name) => {
|
Expr::Variable(name) => {
|
||||||
println!("local.get ${name}");
|
println!("local.get ${name}");
|
||||||
}
|
}
|
||||||
|
@ -122,7 +128,7 @@ fn gen_expr(expr: &Expr, ctx: &Context) {
|
||||||
BinaryOp::Sub => println!("{ty}.sub"),
|
BinaryOp::Sub => println!("{ty}.sub"),
|
||||||
BinaryOp::Div => println!("{ty}.div_u"), // do i _u or _s?
|
BinaryOp::Div => println!("{ty}.div_u"), // do i _u or _s?
|
||||||
BinaryOp::Mod => println!("{ty}.rem_u"),
|
BinaryOp::Mod => println!("{ty}.rem_u"),
|
||||||
BinaryOp::Eq => println!("{ty}.eq"),
|
BinaryOp::Eq => println!("{ty}.eq"),
|
||||||
BinaryOp::Neq => println!("{ty}.neq"),
|
BinaryOp::Neq => println!("{ty}.neq"),
|
||||||
BinaryOp::Less => println!("{ty}.lt_u"),
|
BinaryOp::Less => println!("{ty}.lt_u"),
|
||||||
BinaryOp::Greater => println!("{ty}.gt_u"),
|
BinaryOp::Greater => println!("{ty}.gt_u"),
|
||||||
|
@ -158,19 +164,16 @@ fn gen_expr(expr: &Expr, ctx: &Context) {
|
||||||
}
|
}
|
||||||
// FIXME: awful code until i fix patching up parser and lexer
|
// FIXME: awful code until i fix patching up parser and lexer
|
||||||
Expr::Match(cond, arms) => {
|
Expr::Match(cond, arms) => {
|
||||||
println!(";; --- set match variable");
|
|
||||||
gen_expr(cond, ctx);
|
gen_expr(cond, ctx);
|
||||||
println!("local.set $match");
|
println!("local.set $match");
|
||||||
|
|
||||||
println!(";; --- generate match");
|
|
||||||
|
|
||||||
for (idx, (pat, expr)) in arms.iter().enumerate() {
|
for (idx, (pat, expr)) in arms.iter().enumerate() {
|
||||||
match pat {
|
match pat {
|
||||||
Pattern::Literal(lit) => match lit {
|
Pattern::Literal(lit) => match lit {
|
||||||
Literal::Integer(int) => println!("i32.const {}", int),
|
Literal::Integer(int) => println!("i32.const {}", int),
|
||||||
Literal::Boolean(b) => println!("i32.const {}", if *b { 1 } else { 0 }),
|
Literal::Boolean(b) => println!("i32.const {}", if *b { 1 } else { 0 }),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("local.get $match");
|
println!("local.get $match");
|
||||||
|
@ -186,7 +189,6 @@ fn gen_expr(expr: &Expr, ctx: &Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!("{}", ")".repeat(arms.len() * 2));
|
println!("{}", ")".repeat(arms.len() * 2));
|
||||||
println!(";; --- done");
|
|
||||||
}
|
}
|
||||||
Expr::Block(b) => {
|
Expr::Block(b) => {
|
||||||
for (i, stmt) in b.0.iter().enumerate() {
|
for (i, stmt) in b.0.iter().enumerate() {
|
||||||
|
@ -197,11 +199,14 @@ fn gen_expr(expr: &Expr, ctx: &Context) {
|
||||||
println!("drop");
|
println!("drop");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {},
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Call(func, _) => {
|
Expr::Call(func, args) => {
|
||||||
|
for expr in args {
|
||||||
|
gen_expr(expr, ctx);
|
||||||
|
}
|
||||||
println!("call ${func}");
|
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()));
|
exprs.push((name.clone(), expr.clone()));
|
||||||
}
|
}
|
||||||
Statement::Expr(expr) => get_locals(&expr, ctx, exprs),
|
Statement::Expr(expr) => get_locals(&expr, ctx, exprs),
|
||||||
Statement::Func(name, ret, ..) => {
|
Statement::Func(Func { name, ret, .. }) => {
|
||||||
ctx.locals.insert(name.clone(), todo!());
|
ctx.locals.insert(name.clone(), todo!());
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
Expr::Unary(_, expr) => get_locals(&expr, ctx, exprs),
|
Expr::Unary(_, expr) => get_locals(&expr, ctx, exprs),
|
||||||
Expr::Binary(_, a, b) => {
|
Expr::Binary(_, a, b) => {
|
||||||
get_locals(&a, ctx, exprs);
|
get_locals(&a, ctx, exprs);
|
||||||
|
|
23
src/main.rs
23
src/main.rs
|
@ -39,17 +39,26 @@ fn main() {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// ".into());
|
// ".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("
|
let mut lexer = lexer::Lexer::new("
|
||||||
fn main() -> i32 {
|
fn main() -> i32 {
|
||||||
two() * three()
|
add_three(30)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn two() -> i32 {
|
fn add_three(n: i32) -> i32 {
|
||||||
(2 * 2) / 2
|
n + 3
|
||||||
}
|
|
||||||
|
|
||||||
fn three() -> i32 {
|
|
||||||
10 * 6 / 20
|
|
||||||
}
|
}
|
||||||
".into());
|
".into());
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::HashMap;
|
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::lexer::{Token, Symbol};
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ pub struct Parser {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
pub locals: HashMap<String, Type>,
|
pub locals: HashMap<String, Type>,
|
||||||
|
pub funcs: HashMap<String, (Vec<(String, Type)>, Type)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
|
@ -60,7 +61,20 @@ impl Parser {
|
||||||
self.eat(Token::Fn)?;
|
self.eat(Token::Fn)?;
|
||||||
let name = self.parse_ident()?;
|
let name = self.parse_ident()?;
|
||||||
self.eat(Token::OpenParan)?;
|
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)?;
|
self.eat(Token::CloseParan)?;
|
||||||
let ret = if self.peek_tok().is_some_and(|tok| tok == &Token::Symbol(Symbol::ThinArrow)) {
|
let ret = if self.peek_tok().is_some_and(|tok| tok == &Token::Symbol(Symbol::ThinArrow)) {
|
||||||
self.eat(Token::Symbol(Symbol::ThinArrow))?;
|
self.eat(Token::Symbol(Symbol::ThinArrow))?;
|
||||||
|
@ -71,7 +85,7 @@ impl Parser {
|
||||||
self.eat(Token::OpenBrace)?;
|
self.eat(Token::OpenBrace)?;
|
||||||
let block = self.parse_block()?;
|
let block = self.parse_block()?;
|
||||||
self.eat(Token::CloseBrace)?;
|
self.eat(Token::CloseBrace)?;
|
||||||
Statement::Func(name, ret, block)
|
Statement::Func(Func { name, params, ret, block })
|
||||||
}
|
}
|
||||||
_ => Statement::Expr(self.parse_expr(0)?),
|
_ => Statement::Expr(self.parse_expr(0)?),
|
||||||
};
|
};
|
||||||
|
@ -138,9 +152,17 @@ impl Parser {
|
||||||
let ident = ident.clone();
|
let ident = ident.clone();
|
||||||
if self.peek_tok().is_some_and(|t| *t == Token::OpenParan) {
|
if self.peek_tok().is_some_and(|t| *t == Token::OpenParan) {
|
||||||
self.eat(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);
|
self.eat(Token::CloseParan);
|
||||||
Expr::Call(ident, vec![])
|
Expr::Call(ident, params)
|
||||||
} else {
|
} else {
|
||||||
Expr::Variable(ident)
|
Expr::Variable(ident)
|
||||||
}
|
}
|
||||||
|
|
22
src/types.rs
22
src/types.rs
|
@ -44,8 +44,25 @@ impl Expr {
|
||||||
Ok(match_ty)
|
Ok(match_ty)
|
||||||
}
|
}
|
||||||
Self::Block(block) => block.infer(ctx),
|
Self::Block(block) => block.infer(ctx),
|
||||||
Self::Call(name, ..) => match ctx.locals.get(name) {
|
Self::Call(name, args) => match ctx.funcs.get(name) {
|
||||||
Some(ty) => Ok(ty.clone()),
|
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!(
|
None => Err(Error::ReferenceError(format!(
|
||||||
"cannot find variable {name}"
|
"cannot find variable {name}"
|
||||||
))),
|
))),
|
||||||
|
@ -149,6 +166,7 @@ impl Context {
|
||||||
pub fn new() -> Context {
|
pub fn new() -> Context {
|
||||||
Context {
|
Context {
|
||||||
locals: HashMap::new(),
|
locals: HashMap::new(),
|
||||||
|
funcs: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue