Nested loops should work now
This commit is contained in:
parent
d3518ef510
commit
e6a0e06384
109
src/ast.rs
109
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::<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
131
src/codegen.rs
Normal 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(),
|
||||
}
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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(
|
||||
|
2
test.js
2
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());
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user