diff --git a/blank.html b/blank.html
new file mode 100644
index 0000000..d17ee78
--- /dev/null
+++ b/blank.html
@@ -0,0 +1,2 @@
+
+
diff --git a/src/data.rs b/src/data.rs
index 567eaa8..a900289 100644
--- a/src/data.rs
+++ b/src/data.rs
@@ -1,4 +1,4 @@
-use std::collections::HashMap;
+// TODO: TypedStatement and TypedExpression?
use crate::lexer::{Token, Symbol};
@@ -18,7 +18,6 @@ pub enum BinaryOp {
LogicOr,
// TODO
// Set,
- Comma,
}
#[derive(Debug, Clone)]
@@ -50,7 +49,8 @@ pub struct Func {
pub name: String,
pub params: Vec<(String, Type)>,
pub ret: Type,
- pub block: Block
+ pub block: Block,
+ pub public: bool,
}
#[derive(Debug, Clone)]
@@ -109,7 +109,7 @@ impl BinaryOp {
Self::BitOr => (6, 7),
Self::LogicAnd => (4, 5),
Self::LogicOr => (2, 3),
- Self::Comma => (0, 1),
+ // Self::Comma => (0, 1),
}
}
@@ -169,10 +169,10 @@ impl Type {
pub fn string(&self) -> String {
match self {
Self::Integer => "i32".into(),
- Self::Float => "f32".into(),
+ Self::Float => "f64".into(),
Self::Boolean => "i32".into(),
Self::Tuple(v) => {
- let s: Vec<_> = v.into_iter().map(Type::string).collect();
+ let s: Vec<_> = v.iter().map(Type::string).collect();
format!("({})", s.join(", "))
},
_ => unimplemented!(),
diff --git a/src/error.rs b/src/error.rs
index 2cb8549..22c918f 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -3,6 +3,7 @@ pub enum Error {
SyntaxError(String),
TypeError(String),
ReferenceError(String),
+ IoError(std::io::Error),
}
impl Error {
@@ -14,3 +15,9 @@ impl Error {
Error::TypeError(what.to_string())
}
}
+
+impl From for Error {
+ fn from(value: std::io::Error) -> Self {
+ Error::IoError(value)
+ }
+}
diff --git a/src/generator.rs b/src/generator.rs
index 7368161..e644c05 100644
--- a/src/generator.rs
+++ b/src/generator.rs
@@ -1,11 +1,13 @@
/*
optimizations
-- use i32.eqz when comparing to zero
-- write negative numberss directly instead of as positive + sign flip
+- [ ] use i32.eqz when comparing to zero
+- [x] write negative numbers directly instead of as positive + sign flip
+- [ ] replace `local.set` + `local.get` with `local.tee`
+- [ ] don't create local variables at all if they're only used once
*/
-use crate::data::{self, BinaryOp, Block, Expr, Func, Literal, Pattern, PrefixOp, Statement, Type};
+use crate::data::{BinaryOp, Expr, Func, Literal, Pattern, PrefixOp, Statement, Type};
use crate::parser::Context;
use crate::Error;
@@ -13,57 +15,86 @@ pub struct Generator {
output: Box,
}
+struct Allocator {
+ count: u32,
+}
+
+// const PRELUDE: &str = r#"
+// ;; begin prelude
+// (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))
+// (export "memory" (memory 0))
+// ;; (func $print (param $offset i32) (param $length i32)
+// (func $print (param $string i32)
+// ;; (i32.store (i32.const 0) (local.get $offset)) ;; iov.iov_base (pointer to string)
+// ;; (i32.store (i32.const 4) (local.get $length)) ;; iov.iov_len (length of string)
+// ;; (call $fd_write
+// ;; (i32.const 1) ;; fd: stdout = 1
+// ;; (i32.const 0) ;; data: pointer to memory - this is the first memory we create (index 0)
+// ;; (i32.const 1) ;; data_len: there's 1 string
+// ;; (i32.const 0) ;; nwritten: i don't care about this, write it wherever
+// ;; )
+// ;; drop
+// )
+// ;; end prelude
+// "#;
+
impl Generator {
pub fn new(output: Box) -> Generator {
Generator { output }
}
- fn write_module(&mut self, stmts: &[Statement]) -> Result<(), Error> {
+ pub fn write_module(&mut self, stmts: &[Statement]) -> Result<(), Error> {
+ writeln!(self.output, "(module")?;
let mut ctx = Context::new();
- write!(self.output, "(module");
+ // ctx.funcs.insert("print".to_string(), (vec![("message".to_string(), Type::String)], Type::empty()));
+
+ // writeln!(self.output, "{}", PRELUDE)?;
+
+ let mut gctx = GenContext::new();
+ let mut alloc = Allocator::new();
+ get_locals(&Expr::Block(crate::data::Block(stmts.to_vec())), &mut alloc, &mut ctx, &mut gctx);
+ // get_strings(&Expr::Block(crate::data::Block(stmts.to_vec())), &mut gctx);
+ // if !gctx.strings.is_empty() {
+ // writeln!(self.output, "(memory 1)")?;
+ // for (s, offset) in &mut gctx.strings {
+ // writeln!(self.output, "(data $strings (i32.const {}) \"{}\")", offset, s.replace("\n", "\\n").replace("\"", "\\\""))?;
+ // }
+ // }
+
for stmt in stmts {
match stmt {
- Statement::Func(Func { name, ret, params, .. }) => {
- ctx.funcs.insert(name.clone(), (params.clone(), ret.clone()));
- }
+ Statement::Func(func) => self.write_func(&gctx, &ctx, func)?,
Statement::Let(..) | Statement::TailExpr(..) | Statement::Expr (..) => {
return Err(Error::syn("incorrect top level statement"))
}
};
}
- for stmt in stmts {
- match stmt {
- Statement::Func(func) => self.write_func(&ctx, func)?,
- _ => {
- return Err(Error::syn("incorrect top level statement"))
- }
- };
- }
- write!(self.output, ")");
+ writeln!(self.output, ")")?;
Ok(())
}
- fn write_func(&mut self, ctx: &Context, func: &Func) -> Result<(), Error> {
- write!(self.output, " (func ${}", func.name);
+ fn write_func(&mut self, parent_gctx: &GenContext, ctx: &Context, func: &Func) -> Result<(), Error> {
+ write!(self.output, "(func ${}", func.name)?;
if func.name == "main" {
- write!(self.output, " (export \"_start\")");
+ write!(self.output, " (export \"_start\")")?;
+ } else if func.public {
+ write!(self.output, " (export \"{}\")", func.name)?;
}
let expr = Expr::Block(func.block.clone());
let mut ctx = ctx.clone();
- let mut exprs = Vec::new();
for (name, ty) in &func.params {
ctx.locals.insert(name.clone(), ty.clone());
- write!(self.output, " (param ${} {})", name, ty.string());
+ write!(self.output, " (param ${} {})", name, ty.string())?;
}
if !func.ret.is_empty() {
- write!(self.output, " (result {})", func.ret.string());
+ write!(self.output, " (result {})", func.ret.string())?;
}
- writeln!(self.output);
- writeln!(self.output, "(local $match i32)");
+ writeln!(self.output)?;
+ writeln!(self.output, "(local $match i32)")?;
let inferred = func.block.infer(&ctx)?;
if func.ret != inferred {
@@ -73,170 +104,263 @@ impl Generator {
)));
}
- get_locals(&expr, &mut ctx, &mut exprs);
+ let mut alloc = Allocator::new();
+ let mut gctx = GenContext::new();
+ get_locals(&expr, &mut alloc, &mut ctx, &mut gctx);
+ let exprs = gctx.exprs;
- for (name, _) in &exprs {
- let ty = match ctx.locals.get(name).unwrap() {
+ for (name, expr) in &exprs {
+ let ty = match expr.infer(&ctx).unwrap() {
Type::Integer => "i32",
Type::Float => "f64",
+ // Type::String => "i32",
_ => todo!(),
};
- println!("(local ${name} {ty})");
+ writeln!(self.output, "(local ${name} {ty})")?;
}
for (name, expr) in &exprs {
- gen_expr(expr, &ctx);
- println!("local.set ${name}");
+ self.gen_expr(expr, parent_gctx, &ctx)?;
+ writeln!(self.output, "local.set ${name}")?;
}
- gen_expr(&expr, &ctx);
+ self.gen_expr(&expr, parent_gctx, &ctx)?;
- write!(self.output, ")");
+ writeln!(self.output, ")")?;
Ok(())
}
+
+ fn gen_expr(&mut self, expr: &Expr, parent_gctx: &GenContext, ctx: &Context) -> Result<(), Error> {
+ match expr {
+ Expr::Literal(lit) => match lit {
+ Literal::Integer(int) => writeln!(self.output, "i32.const {int}")?,
+ Literal::Float(f) => writeln!(self.output, "f64.const {f}")?,
+ Literal::Boolean(b) => writeln!(self.output, "i32.const {}", if *b { 1 } else { 0 })?,
+ // Literal::String(s) => writeln!(self.output, "i32.const {}", parent_gctx.strings.iter().find_map(|(s2, off)| (s == s2).then_some(off)).unwrap())?,
+ _ => todo!(),
+ },
+ Expr::Variable(name) => {
+ writeln!(self.output, "local.get ${name}")?;
+ }
+ Expr::Binary(op, a, b) => {
+ self.gen_expr(a, parent_gctx, ctx)?;
+ self.gen_expr(b, parent_gctx, ctx)?;
+
+ let ty = match expr.infer(ctx).unwrap() {
+ Type::Integer => "i32",
+ Type::Float => "f64",
+ Type::Boolean => "i32",
+ _ => todo!(),
+ };
+ match op {
+ BinaryOp::Add => writeln!(self.output, "{ty}.add")?,
+ BinaryOp::Mul => writeln!(self.output, "{ty}.mul")?,
+ BinaryOp::Sub => writeln!(self.output, "{ty}.sub")?,
+ BinaryOp::Div => writeln!(self.output, "{ty}.div_u")?, // do i _u or _s?
+ BinaryOp::Mod => writeln!(self.output, "{ty}.rem_u")?,
+ BinaryOp::Eq => writeln!(self.output, "{ty}.eq")?,
+ BinaryOp::Neq => writeln!(self.output, "{ty}.neq")?,
+ BinaryOp::Less => writeln!(self.output, "{ty}.lt_u")?,
+ BinaryOp::Greater => writeln!(self.output, "{ty}.gt_u")?,
+ _ => todo!(),
+ }
+ }
+ Expr::Unary(op, e) => {
+ if let Expr::Literal(lit) = e.as_ref() {
+ match lit {
+ Literal::Integer(int) => writeln!(self.output, "i32.const {}", -int)?,
+ Literal::Float(f) => writeln!(self.output, "f64.const {}", -f)?,
+ _ => todo!(),
+ }
+ return Ok(());
+ }
+
+ self.gen_expr(e, parent_gctx, ctx)?;
+ match op {
+ PrefixOp::Minus => {
+ // this is so inefficent, but i don't care
+ writeln!(self.output, "i32.const -1")?;
+ writeln!(self.output, "i32.mul")?;
+ }
+ PrefixOp::LogicNot => {
+ writeln!(self.output, "i32.eqz")?;
+ }
+ PrefixOp::BitNot => {
+ // TODO: do i flip the sign bit?
+ writeln!(self.output, "i32.const {}", i32::MAX)?;
+ writeln!(self.output, "i32.xor")?;
+ }
+ }
+ }
+ // FIXME: awful code until i fix patching up parser and lexer
+ Expr::Match(cond, arms) => {
+ self.gen_expr(cond, parent_gctx, ctx)?;
+ writeln!(self.output, "local.set $match")?;
+
+ for (idx, (pat, expr)) in arms.iter().enumerate() {
+ match pat {
+ Pattern::Literal(lit) => match lit {
+ Literal::Integer(int) => writeln!(self.output, "i32.const {}", int)?,
+ Literal::Boolean(b) => writeln!(self.output, "i32.const {}", if *b { 1 } else { 0 })?,
+ _ => todo!(),
+ },
+ };
+
+ writeln!(self.output, "local.get $match")?;
+ writeln!(self.output, "i32.eq")?;
+ writeln!(self.output, "(if (result i32) (then")?;
+ self.gen_expr(expr, parent_gctx, ctx)?;
+
+ if idx == arms.len() - 1 {
+ // TODO: verify its actually unreachable earlier on
+ writeln!(self.output, ") (else unreachable")?;
+ } else {
+ writeln!(self.output, ") (else")?;
+ }
+ }
+ writeln!(self.output, "{}", ")".repeat(arms.len() * 2))?;
+ }
+ Expr::Block(b) => {
+ let mut ctx = ctx.clone();
+ for (_i, stmt) in b.0.iter().enumerate() {
+ match stmt {
+ Statement::TailExpr(expr) => {
+ self.gen_expr(expr, parent_gctx, &ctx)?;
+ }
+ Statement::Expr(expr) => {
+ self.gen_expr(expr, parent_gctx, &ctx)?;
+ if !expr.infer(&ctx).unwrap().is_empty() {
+ writeln!(self.output, "drop")?;
+ }
+ }
+ Statement::Let(name, expr) => {
+ let ty = expr.infer(&ctx).unwrap();
+ ctx.locals.insert(name.clone(), ty);
+ // exprs.push((name.clone(), expr.clone()));
+ }
+ _ => {}
+ }
+ }
+ }
+ Expr::Call(func, args) => {
+ expr.infer(ctx)?;
+ for expr in args {
+ self.gen_expr(expr, parent_gctx, ctx)?;
+ }
+ writeln!(self.output, "call ${func}")?;
+ }
+ };
+ Ok(())
+ }
}
-pub fn generate(statements: &[Statement]) -> Result<(), Error> {
- let mut gen = Generator::new(Box::new(std::io::stdout()));
- gen.write_module(statements)
+// FIXME: not sure what i was thinking
+impl Allocator {
+ fn new() -> Allocator {
+ Allocator {
+ count: 0,
+ }
+ }
+
+ fn alloc_ident(&mut self, name: &str) -> String {
+ // self.count += 1;
+ // format!("{name}_{}", self.count)
+ name.to_string()
+ }
}
-fn gen_expr(expr: &Expr, ctx: &Context) {
- match expr {
- Expr::Literal(lit) => match lit {
- Literal::Integer(int) => println!("i32.const {int}"),
- 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}");
- }
- Expr::Binary(op, a, b) => {
- gen_expr(&a, ctx);
- gen_expr(&b, ctx);
-
- let ty = match expr.infer(&ctx).unwrap() {
- Type::Integer => "i32",
- Type::Float => "f64",
- Type::Boolean => "i32",
- _ => todo!(),
- };
- match op {
- BinaryOp::Add => println!("{ty}.add"),
- BinaryOp::Mul => println!("{ty}.mul"),
- 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::Neq => println!("{ty}.neq"),
- BinaryOp::Less => println!("{ty}.lt_u"),
- BinaryOp::Greater => println!("{ty}.gt_u"),
- _ => todo!(),
- }
- }
- Expr::Unary(op, e) => {
- if let Expr::Literal(lit) = e.as_ref() {
- match lit {
- Literal::Integer(int) => println!("i32.const {}", -int),
- Literal::Float(f) => println!("f64.const {}", -f),
- _ => unreachable!(),
- }
- return;
- }
-
- gen_expr(e, ctx);
- match op {
- PrefixOp::Minus => {
- // this is so inefficent, but i don't care
- println!("i32.const -1");
- println!("i32.mul");
- }
- PrefixOp::LogicNot => {
- println!("i32.eqz");
- }
- PrefixOp::BitNot => {
- // TODO: do i flip the sign bit?
- println!("i32.const {}", i32::MAX);
- println!("i32.xor");
- }
- }
- }
- // FIXME: awful code until i fix patching up parser and lexer
- Expr::Match(cond, arms) => {
- gen_expr(cond, ctx);
- println!("local.set $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");
- gen_expr(expr, ctx);
-
- if idx == arms.len() - 1 {
- // TODO: verify its actually unreachable earlier on
- println!(") (else unreachable");
- } else {
- println!(") (else");
- }
- }
- println!("{}", ")".repeat(arms.len() * 2));
- }
- Expr::Block(b) => {
- for (i, stmt) in b.0.iter().enumerate() {
- match stmt {
- Statement::TailExpr(expr) => {
- gen_expr(expr, &ctx);
- }
- Statement::Expr(expr) => {
- gen_expr(expr, &ctx);
- println!("drop");
- }
- _ => {}
- }
- }
- }
- Expr::Call(func, args) => {
- for expr in args {
- gen_expr(expr, ctx);
- }
- println!("call ${func}");
- }
- };
+#[derive(Debug)]
+struct GenContext {
+ exprs: Vec<(String, Expr)>,
+ strings: Vec<(String, usize)>,
}
-// FIXME: block scoped variables
-fn get_locals(expr: &Expr, ctx: &mut Context, exprs: &mut Vec<(String, Expr)>) {
+impl GenContext {
+ pub fn new() -> GenContext {
+ GenContext {
+ exprs: vec![],
+ strings: vec![],
+ }
+ }
+}
+
+fn get_locals(expr: &Expr, alloc: &mut Allocator, ctx: &mut Context, gctx: &mut GenContext) {
match expr {
Expr::Block(b) => {
for stmt in &b.0 {
match stmt {
Statement::Let(name, expr) => {
+ // FIXME: block scoped variables (name collisions)
+ get_locals(expr, alloc, ctx, gctx);
+
let ty = expr.infer(ctx).unwrap();
ctx.locals.insert(name.clone(), ty);
- exprs.push((name.clone(), expr.clone()));
+ gctx.exprs.push((alloc.alloc_ident(name), expr.clone()));
}
- Statement::TailExpr(expr) => get_locals(&expr, ctx, exprs),
- Statement::Expr(expr) => get_locals(&expr, ctx, exprs),
- Statement::Func(Func { name, ret, .. }) => {
- ctx.locals.insert(name.clone(), todo!());
+ Statement::TailExpr(expr) => get_locals(expr, alloc, ctx, gctx),
+ Statement::Expr(expr) => get_locals(expr, alloc, ctx, gctx),
+ Statement::Func(Func { name, ret, params, .. }) => {
+ ctx.funcs.insert(name.clone(), (params.clone(), ret.clone()));
}
}
}
}
- Expr::Unary(_, expr) => get_locals(&expr, ctx, exprs),
+ Expr::Unary(_, expr) => get_locals(expr, alloc, ctx, gctx),
Expr::Binary(_, a, b) => {
- get_locals(&a, ctx, exprs);
- get_locals(&b, ctx, exprs);
+ get_locals(a, alloc, ctx, gctx);
+ get_locals(b, alloc, ctx, gctx);
}
- _ => (),
+ Expr::Literal(Literal::String(s)) => {
+ let offset = gctx.strings.last().map(|(s, off)| off + s.len()).unwrap_or(8);
+ gctx.strings.push((s.clone(), offset));
+ }
+ Expr::Match(pat, arms) => {
+ get_locals(pat, alloc, ctx, gctx);
+ for (_, arm) in arms {
+ get_locals(arm, alloc, ctx, gctx);
+ }
+ }
+ Expr::Call(_, exprs) => {
+ for expr in exprs {
+ get_locals(expr, alloc, ctx, gctx);
+ }
+ }
+ Expr::Variable(..) | Expr::Literal(..) => (),
}
}
+
+// fn get_strings(expr: &Expr, gctx: &mut GenContext) {
+// match expr {
+// Expr::Block(b) => {
+// for stmt in &b.0 {
+// match stmt {
+// Statement::Let(_, expr) => get_strings(expr, gctx),
+// Statement::TailExpr(expr) => get_strings(expr, gctx),
+// Statement::Expr(expr) => get_strings(expr, gctx),
+// Statement::Func(Func { block, .. }) => get_strings(&Expr::Block(block.clone()), gctx),
+// }
+// }
+// }
+// Expr::Unary(_, expr) => get_strings(expr, gctx),
+// Expr::Binary(_, a, b) => {
+// get_strings(a, gctx);
+// get_strings(b, gctx);
+// }
+// Expr::Literal(Literal::String(s)) => {
+// let offset = gctx.strings.last().map(|(s, off)| off + s.len()).unwrap_or(8);
+// gctx.strings.push((s.clone(), offset));
+// }
+// Expr::Match(pat, arms) => {
+// get_strings(pat, gctx);
+// for (_, arm) in arms {
+// get_strings(arm, gctx);
+// }
+// }
+// Expr::Call(_, exprs) => {
+// for expr in exprs {
+// get_strings(expr, gctx);
+// }
+// }
+// Expr::Variable(..) | Expr::Literal(..) => (),
+// }
+// }
diff --git a/src/lexer.rs b/src/lexer.rs
index 6ac76de..9949537 100644
--- a/src/lexer.rs
+++ b/src/lexer.rs
@@ -24,6 +24,7 @@ pub enum Token {
True, False,
If, Else, Match,
While, Loop, For, Break, Continue,
+ Pub,
}
#[rustfmt::skip]
@@ -89,6 +90,7 @@ impl Lexer {
"for" => Token::For,
"break" => Token::Break,
"continue" => Token::Continue,
+ "pub" => Token::Pub,
ident => Token::Ident(ident.to_string()),
},
ch if ch.is_whitespace() => {
@@ -103,7 +105,7 @@ impl Lexer {
fn lex_number(&mut self) -> Result {
let mut buffer = String::new();
let radix = match (self.input[self.pos], self.input.get(self.pos + 1)) {
- ('0', Some(ch)) if ch.is_digit(10) => 10,
+ ('0', Some(ch)) if ch.is_ascii_digit() => 10,
('0', Some(ch)) => {
self.pos += 2;
match ch {
diff --git a/src/main.rs b/src/main.rs
index f4eab72..bf39815 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,7 +4,7 @@ a second time when generating (so the types are known), there should be
a better way
*/
-#![allow(unused)]
+#![allow(dead_code, clippy::single_match, clippy::only_used_in_recursion)]
mod data;
mod error;
@@ -14,19 +14,7 @@ mod parser;
mod types;
pub use error::Error;
-use parser::Context;
-
-use crate::data::Statement;
-
-pub struct Foo {
- a: u8,
- b: Bar,
-}
-
-pub struct Bar {
- a: u8,
- b: i32,
-}
+use generator::Generator;
fn main() {
// let mut lexer = lexer::Lexer::new("
@@ -54,21 +42,44 @@ fn main() {
// ".into());
let mut lexer = lexer::Lexer::new("
fn main() -> i32 {
- if is_three(add_four(-1)) {
+ let n = -1;
+ if is_three(add_four(n)) {
20
} else {
30
}
}
- fn add_four(n: i32) -> i32 {
+ pub fn add_four(n: i32) -> i32 {
n + 4
}
fn is_three(n: i32) -> bool {
n == 3
}
+
+ fn add_four_float(n: f64) -> f64 {
+ n + 4.0
+ }
".into());
+ // let mut lexer = lexer::Lexer::new("
+ // fn main() -> i32 {
+ // let x = {
+ // let y = 20;
+ // y + 10
+ // };
+ // x
+ // }
+ // ".into());
+ // let mut lexer = lexer::Lexer::new(r#"
+ // fn main() {
+ // let x = "example string!\n";
+ // let y = "another str.\n";
+ // print(x);
+ // print(y);
+ // print("Hello, world!");
+ // }
+ // "#.into());
let mut tokens = vec![];
loop {
@@ -89,17 +100,7 @@ fn main() {
loop {
match parser.next() {
Ok(None) => break,
- Ok(Some(tree)) => {
- // 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);
- }
+ Ok(Some(tree)) => statements.push(tree),
Err(error) => {
eprintln!("error: {:?}", error);
return;
@@ -107,7 +108,11 @@ fn main() {
}
}
- if let Err(err) = generator::generate(&statements) {
+ // dbg!(&statements);
+
+ let mut gen = Generator::new(Box::new(std::io::stdout()));
+
+ if let Err(err) = gen.write_module(&statements) {
panic!("{:?}", err);
}
}
diff --git a/src/parser.rs b/src/parser.rs
index 3aaf8c3..b39fd64 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -47,7 +47,7 @@ impl Parser {
fn parse_statement(&mut self) -> Result