Nested loops should work now

This commit is contained in:
Garen Tyler 2020-12-10 20:40:00 -07:00
parent d3518ef510
commit e6a0e06384
6 changed files with 140 additions and 127 deletions

View File

@ -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::<AstNode>(&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 {

131
src/codegen.rs Normal file
View File

@ -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::<AstNode>(&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(),
}
}
}

View File

@ -7,11 +7,14 @@ extern crate wat;
pub mod ast;
pub mod parse;
pub mod codegen;
use codegen::{Wasm, SymbolGenerator};
pub fn compile<T: Into<String>>(src: T) -> Vec<u8> {
wat::parse_str(compile_wat(src)).unwrap()
}
pub fn compile_wat<T: Into<String>>(src: T) -> String {
parse::parse(src).emit()
let mut s = SymbolGenerator::new();
parse::parse(src).emit(&mut s)
}

View File

@ -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::<AstNode>(&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::<AstNode>(&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::<AstNode>(&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::<AstNode>(&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::<AstNode>(&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(

View File

@ -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());
});

View File

@ -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;
}