functions

This commit is contained in:
tezlm 2023-10-02 00:14:55 -07:00
parent c1820ef6ff
commit 7f49c2d7a3
Signed by: tezlm
GPG key ID: 649733FCD94AFBBA
6 changed files with 192 additions and 90 deletions

View file

@ -38,7 +38,7 @@ pub enum Statement {
Let(String, Expr),
// Type(String, Type),
Expr(Expr),
// Func(String, ...),
Func(String, Type, Block),
// Break,
// Continue,
// Type,
@ -54,7 +54,7 @@ pub enum Expr {
Binary(BinaryOp, Box<Expr>, Box<Expr>),
Unary(PrefixOp, Box<Expr>),
Match(Box<Expr>, Vec<(Pattern, Expr)>),
// Call(String, Vec<Expr>),
Call(String, Vec<Expr>),
Block(Block),
}
@ -82,7 +82,7 @@ pub enum Type {
// Struct(HashMap<String, Type>),
// Enum(HashMap<String, Option<Type>>),
// Newtype(HashMap<String, Type>),
// Function(Vec<Type>, Box<Type>),
// Function(Vec<Type10 >, Box<Type>),
Tuple(Vec<Type>),
}
@ -146,3 +146,27 @@ impl PrefixOp {
Some(op)
}
}
impl Type {
pub fn empty() -> Type {
Type::Tuple(vec![])
}
pub fn is_empty(&self) -> bool {
self == &Type::Tuple(vec![])
}
// FIXME: use actual types
pub fn string(&self) -> String {
match self {
Self::Integer => "i32".into(),
Self::Float => "f32".into(),
Self::Boolean => "i32".into(),
Self::Tuple(v) => {
let s: Vec<_> = v.into_iter().map(Type::string).collect();
format!("({})", s.join(", "))
},
_ => unimplemented!(),
}
}
}

View file

@ -5,7 +5,8 @@ optimizations
- write negative numberss directly instead of as positive + sign flip
*/
use crate::data::{Expr, Literal, BinaryOp, PrefixOp, Statement, Pattern, Type};
use crate::Error;
use crate::data::{Expr, Literal, BinaryOp, PrefixOp, Statement, Pattern, Type, self, Block};
use crate::parser::Context;
pub struct Generator {
@ -19,43 +20,79 @@ impl Generator {
}
}
fn write_module(&mut self) {
fn write_module(&mut self, stmts: &[Statement]) -> Result<(), Error> {
let mut ctx = Context::new();
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")),
};
}
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")),
};
}
write!(self.output, ")");
Ok(())
}
fn write_func(&mut self) {
write!(self.output, "(func ");
fn write_func(&mut self, ctx: &Context, name: &str, ret: &Type, block: &Block) -> Result<(), Error> {
write!(self.output, " (func ${name}");
if 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 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:?}")));
}
get_locals(&expr, &mut ctx, &mut exprs);
for (name, _) in &exprs {
let ty = match ctx.locals.get(name).unwrap() {
Type::Integer => "i32",
Type::Float => "f64",
_ => todo!(),
};
println!("(local ${name} {ty})");
}
for (name, expr) in &exprs {
gen_expr(expr, &ctx);
println!("local.set ${name}");
}
gen_expr(&expr, &ctx);
write!(self.output, ")");
Ok(())
}
}
pub fn generate(expr: &Expr) {
println!();
println!();
let mut ctx = Context::new();
let mut exprs = Vec::new();
get_locals(expr, &mut ctx, &mut exprs);
// println!(r#"(module (func (export "_start") (local $match i32)"#);
println!(r#"(module (func (export "_start") (result i32) (local $match i32)"#);
// println!(r#"(module (func (export "_start") (result f64) (local $match f64)"#);
for (name, _) in &exprs {
let ty = match ctx.locals.get(name).unwrap() {
Type::Integer => "i32",
Type::Float => "f64",
_ => todo!(),
};
println!("(local ${name} {ty})");
}
for (name, expr) in &exprs {
gen_expr(expr, &ctx);
println!("local.set ${name}");
}
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!(),
};
gen_expr(&expr, &ctx);
// println!("drop");
println!("))");
let mut gen = Generator::new(Box::new(std::io::stdout()));
gen.write_module(statements)
}
fn gen_expr(expr: &Expr, ctx: &Context) {
@ -164,6 +201,9 @@ fn gen_expr(expr: &Expr, ctx: &Context) {
}
}
}
Expr::Call(func, _) => {
println!("call ${func}");
}
};
}
@ -178,6 +218,9 @@ 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, ..) => {
ctx.locals.insert(name.clone(), todo!());
},
}
}
},

View file

@ -29,17 +29,29 @@ pub struct Bar {
}
fn main() {
// let mut lexer = lexer::Lexer::new("{ let foo = 8; let bar = foo * 3; foo + bar < 10 }".into());
// let mut lexer = lexer::Lexer::new("{ let foo = 8; let bar = foo * -3; foo + bar }".into());
// let mut lexer = lexer::Lexer::new("123 + 456".into());
let mut lexer = lexer::Lexer::new("{
let foo = 8;
let bar = foo * -3;
match foo + bar < 10 {
true => 123,
false => 456,
// let mut lexer = lexer::Lexer::new("
// fn main() -> i32 {
// let foo = 8;
// let bar = foo * -3;
// match foo + bar < 10 {
// true => 123,
// false => 456,
// }
// }
// ".into());
let mut lexer = lexer::Lexer::new("
fn main() -> i32 {
two() * three()
}
}".into());
fn two() -> i32 {
(2 * 2) / 2
}
fn three() -> i32 {
10 * 6 / 20
}
".into());
let mut tokens = vec![];
loop {
@ -53,7 +65,7 @@ fn main() {
}
}
dbg!(&tokens);
// dbg!(&tokens);
let mut parser = parser::Parser::new(tokens);
let mut statements = vec![];
@ -61,14 +73,14 @@ fn main() {
match parser.next() {
Ok(None) => break,
Ok(Some(tree)) => {
dbg!(&tree);
match &tree {
Statement::Let(..) => todo!(),
Statement::Expr(expr) => match expr.infer(&Context::new()) {
Ok(ty) => eprintln!("type: {:?}", ty),
Err(err) => eprintln!("err: {:?}", err),
},
};
// dbg!(&tree);
// match &tree {
// Statement::Expr(expr) => match expr.infer(&Context::new()) {
// Ok(ty) => eprintln!("type: {:?}", ty),
// Err(err) => eprintln!("err: {:?}", err),
// },
// _ => todo!(),
// };
statements.push(tree);
}
Err(error) => {
@ -78,10 +90,7 @@ fn main() {
}
}
let expr = match &statements[0] {
Statement::Expr(expr) => expr,
_ => todo!(),
};
generator::generate(expr);
if let Err(err) = generator::generate(&statements) {
panic!("{:?}", err);
}
}

View file

@ -51,26 +51,60 @@ impl Parser {
let stmt = match tok {
Token::Let => {
self.eat(Token::Let)?;
let name = match self.next_tok() {
Some(Token::Ident(ident)) => ident.to_string(),
Some(tk) => {
return Err(Error::SyntaxError(format!(
"expected identifier, got {tk:?}"
)))
}
None => {
return Err(Error::SyntaxError(format!("expected identifier, got eof")))
}
};
let name = self.parse_ident()?;
self.eat(Token::Symbol(Symbol::Set))?;
let expr = self.parse_expr(0)?;
Statement::Let(name, expr)
}
Token::Fn => {
self.eat(Token::Fn)?;
let name = self.parse_ident()?;
self.eat(Token::OpenParan)?;
// TODO: parameters
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))?;
self.parse_type()?
} else {
Type::empty()
};
self.eat(Token::OpenBrace)?;
let block = self.parse_block()?;
self.eat(Token::CloseBrace)?;
Statement::Func(name, ret, block)
}
_ => Statement::Expr(self.parse_expr(0)?),
};
Ok(Some(stmt))
}
fn parse_type(&mut self) -> Result<Type, Error> {
let Some(tok) = self.next_tok() else {
return Err(Error::SyntaxError(format!("unexpected eof")));
};
match tok {
Token::Ident(ident) => match ident.as_str() {
"i32" => Ok(Type::Integer),
_ => return Err(Error::TypeError(format!("unknown type {ident}"))),
},
_ => todo!(),
}
}
fn parse_ident(&mut self) -> Result<String, Error> {
match self.next_tok() {
Some(Token::Ident(ident)) => Ok(ident.to_string()),
Some(tk) => {
return Err(Error::SyntaxError(format!(
"expected identifier, got {tk:?}"
)))
}
None => {
return Err(Error::SyntaxError(format!("expected identifier, got eof")))
}
}
}
fn parse_block(&mut self) -> Result<Block, Error> {
let mut statements = vec![];
loop {
@ -103,8 +137,10 @@ impl Parser {
Token::Ident(ident) => {
let ident = ident.clone();
if self.peek_tok().is_some_and(|t| *t == Token::OpenParan) {
// function calls
todo!()
self.eat(Token::OpenParan);
// TODO: function parameters
self.eat(Token::CloseParan);
Expr::Call(ident, vec![])
} else {
Expr::Variable(ident)
}

View file

@ -44,6 +44,12 @@ impl Expr {
Ok(match_ty)
}
Self::Block(block) => block.infer(ctx),
Self::Call(name, ..) => match ctx.locals.get(name) {
Some(ty) => Ok(ty.clone()),
None => Err(Error::ReferenceError(format!(
"cannot find variable {name}"
))),
},
}
}
}
@ -103,15 +109,16 @@ impl PrefixOp {
impl Block {
pub fn infer(&self, ctx: &Context) -> Result<Type, Error> {
let mut ctx = ctx.clone();
let mut ty = Type::Tuple(vec![]);
let mut ty = Type::empty();
for statement in &self.0 {
match statement {
Statement::Expr(expr) => ty = expr.infer(&ctx)?,
Statement::Let(name, expr) => {
let var_ty = expr.infer(&ctx)?;
ctx.locals.insert(name.clone(), var_ty);
ty = Type::Tuple(vec![]);
ty = Type::empty();
}
_ => (),
}
}
Ok(ty)

View file

@ -1,18 +1 @@
(module (func (export "_start") (result i32) (local $match i32)
(local $foo i32)
(local $bar i32)
i32.const 8
local.set $foo
local.get $foo
i32.const -3
i32.mul
local.set $bar
;; --- set match variable
local.get $foo
local.get $bar
i32.add
i32.const 10
i32.lt_u
local.set $match
local.get $match
))
(module (func $name (export "_start") (result i32) i32.const 10))