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 serde::{Deserialize, Serialize};
|
||||||
use ron::from_str;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum AstNodeKind {
|
pub enum AstNodeKind {
|
||||||
@ -45,114 +44,6 @@ impl AstNode {
|
|||||||
subnodes,
|
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
|
// Primitives
|
||||||
pub fn integer(num: i64) -> AstNode {
|
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 ast;
|
||||||
pub mod parse;
|
pub mod parse;
|
||||||
|
pub mod codegen;
|
||||||
|
use codegen::{Wasm, SymbolGenerator};
|
||||||
|
|
||||||
pub fn compile<T: Into<String>>(src: T) -> Vec<u8> {
|
pub fn compile<T: Into<String>>(src: T) -> Vec<u8> {
|
||||||
wat::parse_str(compile_wat(src)).unwrap()
|
wat::parse_str(compile_wat(src)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile_wat<T: Into<String>>(src: T) -> String {
|
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()))?));
|
token(r"=").map(|matched| Ok(to_string(&AstNode::assign("".into(), AstNode::null()))?));
|
||||||
let COMMA = token(r"[,]");
|
let COMMA = token(r"[,]");
|
||||||
let expression = Parser::custom(parse_expression);
|
let expression = Parser::custom(parse_expression);
|
||||||
// Statement parser.
|
|
||||||
let statement = Parser::custom(parse_statement);
|
let statement = Parser::custom(parse_statement);
|
||||||
// Return statement parser.
|
|
||||||
let return_statement = RETURN.clone().ignore()
|
let return_statement = RETURN.clone().ignore()
|
||||||
.and(expression.clone())
|
.and(expression.clone())
|
||||||
.and(SEMICOLON.clone().ignore())
|
.and(SEMICOLON.clone().ignore())
|
||||||
@ -57,11 +55,8 @@ fn parse_statement(src: String) -> Result<(String, String), String> {
|
|||||||
let data = from_str::<AstNode>(&matched)?;
|
let data = from_str::<AstNode>(&matched)?;
|
||||||
Ok(to_string(&AstNode::function_return(data))?)
|
Ok(to_string(&AstNode::function_return(data))?)
|
||||||
});
|
});
|
||||||
// return_statement.parse(src.clone())
|
|
||||||
// Expression statement parser.
|
|
||||||
let expression_statement = expression.clone()
|
let expression_statement = expression.clone()
|
||||||
.and(SEMICOLON.clone().ignore());
|
.and(SEMICOLON.clone().ignore());
|
||||||
// If statement parser.
|
|
||||||
let if_statement = IF.clone().ignore()
|
let if_statement = IF.clone().ignore()
|
||||||
.and(
|
.and(
|
||||||
LEFT_PAREN.clone().ignore()
|
LEFT_PAREN.clone().ignore()
|
||||||
@ -86,7 +81,6 @@ fn parse_statement(src: String) -> Result<(String, String), String> {
|
|||||||
let consequence = from_str::<AstNode>(&others[1])?;
|
let consequence = from_str::<AstNode>(&others[1])?;
|
||||||
Ok(to_string(&AstNode::if_statement(conditional, consequence, alternative))?)
|
Ok(to_string(&AstNode::if_statement(conditional, consequence, alternative))?)
|
||||||
});
|
});
|
||||||
// if_statement.parse(src.clone())
|
|
||||||
let while_statement = WHILE.clone().ignore()
|
let while_statement = WHILE.clone().ignore()
|
||||||
.and(
|
.and(
|
||||||
LEFT_PAREN.clone().ignore()
|
LEFT_PAREN.clone().ignore()
|
||||||
@ -100,7 +94,6 @@ fn parse_statement(src: String) -> Result<(String, String), String> {
|
|||||||
let body = from_str::<AstNode>(&data[1])?;
|
let body = from_str::<AstNode>(&data[1])?;
|
||||||
Ok(to_string(&AstNode::while_loop(conditional, body))?)
|
Ok(to_string(&AstNode::while_loop(conditional, body))?)
|
||||||
});
|
});
|
||||||
// while_statement.parse(src.clone())
|
|
||||||
let var_statement = VAR.clone().ignore()
|
let var_statement = VAR.clone().ignore()
|
||||||
.and(IDENTIFIER.clone())
|
.and(IDENTIFIER.clone())
|
||||||
.and(ASSIGN.clone().ignore())
|
.and(ASSIGN.clone().ignore())
|
||||||
@ -112,7 +105,6 @@ fn parse_statement(src: String) -> Result<(String, String), String> {
|
|||||||
let value = from_str::<AstNode>(&data[1])?;
|
let value = from_str::<AstNode>(&data[1])?;
|
||||||
Ok(to_string(&AstNode::variable_definition(name, value))?)
|
Ok(to_string(&AstNode::variable_definition(name, value))?)
|
||||||
});
|
});
|
||||||
// var_statement.parse(src.clone())
|
|
||||||
let assignment_statement = IDENTIFIER.clone()
|
let assignment_statement = IDENTIFIER.clone()
|
||||||
.and(ASSIGN.clone().ignore())
|
.and(ASSIGN.clone().ignore())
|
||||||
.and(expression.clone())
|
.and(expression.clone())
|
||||||
@ -123,7 +115,6 @@ fn parse_statement(src: String) -> Result<(String, String), String> {
|
|||||||
let value = from_str::<AstNode>(&data[1])?;
|
let value = from_str::<AstNode>(&data[1])?;
|
||||||
Ok(to_string(&AstNode::assign(name, value))?)
|
Ok(to_string(&AstNode::assign(name, value))?)
|
||||||
});
|
});
|
||||||
// asssignment_statement.parse(src.clone())
|
|
||||||
let block_statement = LEFT_BRACE.clone().ignore()
|
let block_statement = LEFT_BRACE.clone().ignore()
|
||||||
.and(statement.clone().repeat_range(0..usize::MAX))
|
.and(statement.clone().repeat_range(0..usize::MAX))
|
||||||
.and(RIGHT_BRACE.clone().ignore())
|
.and(RIGHT_BRACE.clone().ignore())
|
||||||
@ -135,7 +126,6 @@ fn parse_statement(src: String) -> Result<(String, String), String> {
|
|||||||
}
|
}
|
||||||
Ok(to_string(&AstNode::block(statements))?)
|
Ok(to_string(&AstNode::block(statements))?)
|
||||||
});
|
});
|
||||||
// block_statement.parse(src.clone())
|
|
||||||
let args = IDENTIFIER.clone()
|
let args = IDENTIFIER.clone()
|
||||||
.and(
|
.and(
|
||||||
COMMA.clone().ignore()
|
COMMA.clone().ignore()
|
||||||
@ -152,7 +142,6 @@ fn parse_statement(src: String) -> Result<(String, String), String> {
|
|||||||
}
|
}
|
||||||
Ok(to_string(&args)?)
|
Ok(to_string(&args)?)
|
||||||
});
|
});
|
||||||
// args.parse(src.clone())
|
|
||||||
let function_statement = FUNCTION.clone().ignore()
|
let function_statement = FUNCTION.clone().ignore()
|
||||||
.and(IDENTIFIER.clone())
|
.and(IDENTIFIER.clone())
|
||||||
.and(
|
.and(
|
||||||
|
2
test.js
2
test.js
@ -1,5 +1,5 @@
|
|||||||
require("webassembly")
|
require("webassembly")
|
||||||
.load("out.wasm")
|
.load("out.wasm")
|
||||||
.then(module => {
|
.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