From e6a0e0638426de118011ccc8485e218c400a59dc Mon Sep 17 00:00:00 2001 From: Garen Tyler Date: Thu, 10 Dec 2020 20:40:00 -0700 Subject: [PATCH] Nested loops should work now --- src/ast.rs | 109 --------------------------------------- src/codegen.rs | 131 +++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 +- src/parse/mod.rs | 11 ---- test.js | 2 +- test.pvt | 9 ++-- 6 files changed, 140 insertions(+), 127 deletions(-) create mode 100644 src/codegen.rs diff --git a/src/ast.rs b/src/ast.rs index 258ec8c..0d40b92 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use ron::from_str; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub enum AstNodeKind { @@ -45,114 +44,6 @@ impl AstNode { subnodes, } } - pub fn emit(&self) -> String { - use AstNodeKind::*; - match self.kind { - // Primitives - Integer => format!("(i32.const {})", self.value), - Identifier => format!("(get_local ${})", self.value), - // Unary operators - Not => format!("(i32.eq (i32.const 0) {})", self.subnodes[1].emit()), - // Infix operators - NotEqual => format!("(i32.ne {} {})", self.subnodes[0].emit(), self.subnodes[1].emit()), - Equal => format!("(i32.eq {} {})", self.subnodes[0].emit(), self.subnodes[1].emit()), - Add => format!("(i32.add {} {})", self.subnodes[0].emit(), self.subnodes[1].emit()), - Subtract => format!("(i32.sub {} {})", self.subnodes[0].emit(), self.subnodes[1].emit()), - Multiply => format!("(i32.mul {} {})", self.subnodes[0].emit(), self.subnodes[1].emit()), - Divide => format!("(i32.div_s {} {})", self.subnodes[0].emit(), self.subnodes[1].emit()), - // Control flow - Block => { - let mut out = String::new(); - for node in &self.subnodes { - out += ""; - out += &node.emit(); - } - out - } - IfStatement => { - let mut out = String::new(); - out += &format!("(if {} (then {})", self.subnodes[0].emit(), self.subnodes[1].emit()); // Emit the conditional and consequence. - if let Some(alternative) = self.subnodes.get(2) { - out += &format!(" (else {})", alternative.emit()); // Emit the alternative. - } - out += ")"; - out - } - WhileLoop => { - let loop_symbol = "while_loop"; // TODO: Make generate unique symbol for nested loops. - let mut out = String::new(); - out += &format!("(block ${}_wrapper", loop_symbol); - out += &format!(" (loop ${}_loop", loop_symbol); - out += &format!(" {}", self.subnodes[1].emit()); - out += &format!(" (br_if ${}_wrapper (i32.eq (i32.const 0) {}))", loop_symbol, self.subnodes[0].emit()); - out += &format!(" (br ${}_loop)", loop_symbol); - out += "))"; - out - } - Program => { - let mut out = String::new(); - out += "(module"; - let mut exported = vec![]; - for node in &self.subnodes { - out += " "; - out += &node.emit(); - if node.kind == FunctionDefinition { - exported.push(node.value.clone()); - } - } - for export in exported { - out += &format!(" (export \"{0}\" (func ${0}))", export); - } - out += ")"; - out - } - // Functions and variables - FunctionCall => { - let mut out = String::new(); - out += &format!("(call ${}", from_str::(&self.value).unwrap().value); - for n in &self.subnodes { - out += " "; - out += &n.emit(); - } - out += ")"; - out - }, - FunctionReturn => format!("{} (return)", self.subnodes[0].emit()), - FunctionDefinition => { - let mut out = String::new(); - out += &format!("(func ${}", self.value); - let body = self.subnodes[0].clone(); - for n in &self.subnodes[1..] { - out += &format!(" (param ${} i32)", n.value); - } - let mut func_returns_value = false; - let mut index = 0; - loop { - if index >= body.subnodes.len() { - break; - } - match body.subnodes[index].kind { - AstNodeKind::FunctionReturn => func_returns_value = true, - _ => {} - } - index += 1; - } - if func_returns_value { - out += " (result i32)"; - } - for n in &body.subnodes { - out += " "; - out += &n.emit(); - } - out += ")"; - out - } - VariableDeclaration => format!("(local ${} i32)", self.value), - Assign => format!("(set_local ${} {})", self.value, self.subnodes[0].emit()), - // Blank node / other - Null | _ => "".into(), - } - } // Primitives pub fn integer(num: i64) -> AstNode { diff --git a/src/codegen.rs b/src/codegen.rs new file mode 100644 index 0000000..e017116 --- /dev/null +++ b/src/codegen.rs @@ -0,0 +1,131 @@ +use ron::from_str; +use crate::ast::{AstNode, AstNodeKind}; + +pub struct SymbolGenerator { + counter: usize, +} +impl SymbolGenerator { + pub fn new() -> SymbolGenerator { + SymbolGenerator { + counter: 0, + } + } + pub fn next(&mut self) -> usize { + self.counter += 1; + self.counter + } +} + +pub trait Wasm { + fn emit(&self, symbol_generator: &mut SymbolGenerator) -> String; +} +impl Wasm for AstNode { + fn emit(&self, s: &mut SymbolGenerator) -> String { + use AstNodeKind::*; + match self.kind { + // Primitives + Integer => format!("(i32.const {})", self.value), + Identifier => format!("(get_local ${})", self.value), + // Unary operators + Not => format!("(i32.eq (i32.const 0) {})", self.subnodes[1].emit(s)), + // Infix operators + NotEqual => format!("(i32.ne {} {})", self.subnodes[0].emit(s), self.subnodes[1].emit(s)), + Equal => format!("(i32.eq {} {})", self.subnodes[0].emit(s), self.subnodes[1].emit(s)), + Add => format!("(i32.add {} {})", self.subnodes[0].emit(s), self.subnodes[1].emit(s)), + Subtract => format!("(i32.sub {} {})", self.subnodes[0].emit(s), self.subnodes[1].emit(s)), + Multiply => format!("(i32.mul {} {})", self.subnodes[0].emit(s), self.subnodes[1].emit(s)), + Divide => format!("(i32.div_s {} {})", self.subnodes[0].emit(s), self.subnodes[1].emit(s)), + // Control flow + Block => { + let mut out = String::new(); + for node in &self.subnodes { + out += ""; + out += &node.emit(s); + } + out + } + IfStatement => { + let mut out = String::new(); + out += &format!("(if {} (then {})", self.subnodes[0].emit(s), self.subnodes[1].emit(s)); // Emit the conditional and consequence. + if let Some(alternative) = self.subnodes.get(2) { + out += &format!(" (else {})", alternative.emit(s)); // Emit the alternative. + } + out += ")"; + out + } + WhileLoop => { + let loop_symbol = format!("while{}", s.next()); // TODO: Make generate unique symbol for nested loops. + let mut out = String::new(); + out += &format!("(block ${}_wrapper", loop_symbol); + out += &format!(" (loop ${}_loop", loop_symbol); + out += &format!(" {}", self.subnodes[1].emit(s)); + out += &format!(" (br_if ${}_wrapper (i32.eq (i32.const 0) {}))", loop_symbol, self.subnodes[0].emit(s)); + out += &format!(" (br ${}_loop)", loop_symbol); + out += "))"; + out + } + Program => { + let mut out = String::new(); + out += "(module"; + let mut exported = vec![]; + for node in &self.subnodes { + out += " "; + out += &node.emit(s); + if node.kind == FunctionDefinition { + exported.push(node.value.clone()); + } + } + for export in exported { + out += &format!(" (export \"{0}\" (func ${0}))", export); + } + out += ")"; + out + } + // Functions and variables + FunctionCall => { + let mut out = String::new(); + out += &format!("(call ${}", from_str::(&self.value).unwrap().value); + for n in &self.subnodes { + out += " "; + out += &n.emit(s); + } + out += ")"; + out + }, + FunctionReturn => format!("{} (return)", self.subnodes[0].emit(s)), + FunctionDefinition => { + let mut out = String::new(); + out += &format!("(func ${}", self.value); + let body = self.subnodes[0].clone(); + for n in &self.subnodes[1..] { + out += &format!(" (param ${} i32)", n.value); + } + let mut func_returns_value = false; + let mut index = 0; + loop { + if index >= body.subnodes.len() { + break; + } + match body.subnodes[index].kind { + AstNodeKind::FunctionReturn => func_returns_value = true, + _ => {} + } + index += 1; + } + if func_returns_value { + out += " (result i32)"; + } + for n in &body.subnodes { + out += " "; + out += &n.emit(s); + } + out += ")"; + out + } + VariableDeclaration => format!("(local ${} i32)", self.value), + Assign => format!("(set_local ${} {})", self.value, self.subnodes[0].emit(s)), + // Blank node / other + Null | _ => "".into(), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index c8450c1..874bb90 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,11 +7,14 @@ extern crate wat; pub mod ast; pub mod parse; +pub mod codegen; +use codegen::{Wasm, SymbolGenerator}; pub fn compile>(src: T) -> Vec { wat::parse_str(compile_wat(src)).unwrap() } pub fn compile_wat>(src: T) -> String { - parse::parse(src).emit() + let mut s = SymbolGenerator::new(); + parse::parse(src).emit(&mut s) } diff --git a/src/parse/mod.rs b/src/parse/mod.rs index fd7b88d..1d57617 100644 --- a/src/parse/mod.rs +++ b/src/parse/mod.rs @@ -47,9 +47,7 @@ fn parse_statement(src: String) -> Result<(String, String), String> { token(r"=").map(|matched| Ok(to_string(&AstNode::assign("".into(), AstNode::null()))?)); let COMMA = token(r"[,]"); let expression = Parser::custom(parse_expression); - // Statement parser. let statement = Parser::custom(parse_statement); - // Return statement parser. let return_statement = RETURN.clone().ignore() .and(expression.clone()) .and(SEMICOLON.clone().ignore()) @@ -57,11 +55,8 @@ fn parse_statement(src: String) -> Result<(String, String), String> { let data = from_str::(&matched)?; Ok(to_string(&AstNode::function_return(data))?) }); - // return_statement.parse(src.clone()) - // Expression statement parser. let expression_statement = expression.clone() .and(SEMICOLON.clone().ignore()); - // If statement parser. let if_statement = IF.clone().ignore() .and( LEFT_PAREN.clone().ignore() @@ -86,7 +81,6 @@ fn parse_statement(src: String) -> Result<(String, String), String> { let consequence = from_str::(&others[1])?; Ok(to_string(&AstNode::if_statement(conditional, consequence, alternative))?) }); - // if_statement.parse(src.clone()) let while_statement = WHILE.clone().ignore() .and( LEFT_PAREN.clone().ignore() @@ -100,7 +94,6 @@ fn parse_statement(src: String) -> Result<(String, String), String> { let body = from_str::(&data[1])?; Ok(to_string(&AstNode::while_loop(conditional, body))?) }); - // while_statement.parse(src.clone()) let var_statement = VAR.clone().ignore() .and(IDENTIFIER.clone()) .and(ASSIGN.clone().ignore()) @@ -112,7 +105,6 @@ fn parse_statement(src: String) -> Result<(String, String), String> { let value = from_str::(&data[1])?; Ok(to_string(&AstNode::variable_definition(name, value))?) }); - // var_statement.parse(src.clone()) let assignment_statement = IDENTIFIER.clone() .and(ASSIGN.clone().ignore()) .and(expression.clone()) @@ -123,7 +115,6 @@ fn parse_statement(src: String) -> Result<(String, String), String> { let value = from_str::(&data[1])?; Ok(to_string(&AstNode::assign(name, value))?) }); - // asssignment_statement.parse(src.clone()) let block_statement = LEFT_BRACE.clone().ignore() .and(statement.clone().repeat_range(0..usize::MAX)) .and(RIGHT_BRACE.clone().ignore()) @@ -135,7 +126,6 @@ fn parse_statement(src: String) -> Result<(String, String), String> { } Ok(to_string(&AstNode::block(statements))?) }); - // block_statement.parse(src.clone()) let args = IDENTIFIER.clone() .and( COMMA.clone().ignore() @@ -152,7 +142,6 @@ fn parse_statement(src: String) -> Result<(String, String), String> { } Ok(to_string(&args)?) }); - // args.parse(src.clone()) let function_statement = FUNCTION.clone().ignore() .and(IDENTIFIER.clone()) .and( diff --git a/test.js b/test.js index b6d620e..661418f 100644 --- a/test.js +++ b/test.js @@ -1,5 +1,5 @@ require("webassembly") .load("out.wasm") .then(module => { - console.log("3 + 2 is " + module.exports.main(3)); + console.log("3 + 2 is " + module.exports.main()); }); diff --git a/test.pvt b/test.pvt index bd8cd23..192dbee 100644 --- a/test.pvt +++ b/test.pvt @@ -1,6 +1,5 @@ -function main(num) { - return num + a(2); -} -function a(num) { - return num; +function main() { + var num1 = 5; + var num2 = 4; + return num1 * num2; }