Code generation

This commit is contained in:
Garen Tyler 2020-12-10 19:53:38 -07:00
parent d95c8dc278
commit 1c3d7c6bd1
4 changed files with 144 additions and 52 deletions

View File

@ -1,4 +1,6 @@
use serde::{Deserialize, Serialize};
use ron::from_str;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum AstNodeKind {
// Primitives
@ -23,6 +25,7 @@ pub enum AstNodeKind {
FunctionReturn,
FunctionDefinition,
VariableDefinition,
VariableDeclaration,
Assign,
// Blank node
Null,
@ -42,48 +45,112 @@ impl AstNode {
subnodes,
}
}
pub fn emit(&self, f: &mut dyn std::fmt::Write) -> std::fmt::Result {
pub fn emit(&self) -> String {
use AstNodeKind::*;
match self.kind {
Integer => write!(f, "i32.const {}\n", self.value),
Identifier => write!(f, "get_local ${}\n", self.value),
Add => {
self.subnodes[0].emit(f)?;
self.subnodes[1].emit(f)?;
write!(f, "i32.add\n")
// 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 => {
write!(f, "(module\n")?;
let mut out = String::new();
out += "(module";
let mut exported = vec![];
for node in &self.subnodes {
node.emit(f)?;
out += " ";
out += &node.emit();
if node.kind == FunctionDefinition {
exported.push(node.value.clone());
}
}
for export in exported {
write!(f, "(export \"{0}\" (func ${0}))\n", export)?;
out += &format!(" (export \"{0}\" (func ${0}))", export);
}
write!(f, ")")
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 => {
write!(f, "(func ${}", self.value)?;
// let body = self.subnodes[0];
for a in &self.subnodes[1..] {
write!(f, " (param ${} i32)", a.value)?;
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);
}
write!(f, " (result i32)\n")?;
self.subnodes[0].emit(f)?;
write!(f, ")\n")
let mut func_returns_value = false;
let mut index = 0;
loop {
if index >= body.subnodes.len() {
break;
}
Block => {
for node in &self.subnodes {
node.emit(f)?;
match body.subnodes[index].kind {
AstNodeKind::FunctionReturn => func_returns_value = true,
_ => {}
}
write!(f, "")
index += 1;
}
FunctionReturn => self.subnodes[0].emit(f),
_ => Ok(()),
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(),
}
}
@ -219,6 +286,13 @@ impl AstNode {
subnodes: vec![value],
}
}
pub fn variable_declaration(name: String) -> AstNode {
AstNode {
kind: AstNodeKind::VariableDeclaration,
value: name,
subnodes: vec![],
}
}
pub fn assign(name: String, value: AstNode) -> AstNode {
AstNode {
kind: AstNodeKind::Assign,

View File

@ -4,13 +4,19 @@ use std::fs::File;
use std::io::prelude::*;
fn main() -> std::io::Result<()> {
let src = r#"function add(left, right) { return left + right; }"#;
let src = r#"
function a(num) {
return num;
}
function main(num) {
var amt = a(2);
return num + amt;
}"#;
let ast = pivot::parse(src);
// println!("{}", ast);
let mut code = String::new();
ast.emit(&mut code);
println!("{}", ast);
let code = ast.emit();
println!("{}", code);
let binary = wat::parse_str(code).unwrap();
let mut file = File::create("out.wasm")?.write_all(&binary)?;
File::create("out.wasm")?.write_all(&binary)?;
Ok(())
}

View File

@ -1,15 +1,22 @@
mod combinators;
use crate::ast::AstNode;
use crate::ast::{AstNode, AstNodeKind};
use combinators::Parser;
use ron::{from_str, to_string};
pub fn parse<T: Into<String>>(src: T) -> AstNode {
let src: String = src.into();
let parse_program = Parser::custom(parse_statement)
let whitespace = Parser::regex(r"[ \n\r\t]+");
let comments = Parser::regex(r"[/][/].*").or(Parser::regex(r"[/][*].*[*][/]"));
let ignored = whitespace.or(comments).repeat_range(0..usize::MAX);
let statement = ignored.optional().ignore().and(Parser::custom(parse_statement));
let parse_program = statement.clone()
.repeat_range(0..usize::MAX)
.map(|matched| {
let data = from_str::<Vec<String>>(&matched)?;
for d in &data {
println!("{}", d);
}
let mut statements = vec![];
for d in data {
statements.push(from_str::<AstNode>(&d)?);
@ -159,29 +166,31 @@ fn parse_statement(src: String) -> Result<(String, String), String> {
.and(block_statement.clone())
.map(|matched| {
let data = from_str::<Vec<String>>(&matched)?;
for d in &data {
println!("{}", d);
}
let body = from_str::<AstNode>(&data[1])?;
println!("body: {}", body);
let mut body = from_str::<AstNode>(&data[1])?;
let data = from_str::<Vec<String>>(&data[0])?;
for d in &data {
println!("{}", d);
}
let name = from_str::<AstNode>(&data[0])?.value;
println!("name: {}", name);
let params = from_str::<Vec<String>>(&data[1])?;
let mut parameters = vec![];
if params.len() != 0 {
for p in from_str::<Vec<String>>(&params[0])? {
parameters.push(from_str::<AstNode>(&p)?);
}
println!("{:?}", parameters);
}
// Hoist variable definitions.
let mut vars = vec![];
let mut others = vec![];
for node in &body.subnodes {
match node.kind {
AstNodeKind::VariableDefinition => {
vars.push(AstNode::variable_declaration(node.value.clone()));
others.push(AstNode::assign(node.value.clone(), node.subnodes[0].clone()))
},
_ => others.push(node.clone()),
}
}
vars.append(&mut others);
body.subnodes = vars;
Ok(to_string(&AstNode::function_definition(name, parameters, body))?)
})
.map(|matched| {
let function_definition = from_str::<AstNode>(&matched)?;
println!("{}", function_definition);
Ok(matched)
});
return_statement.clone()
.or(if_statement.clone())
@ -283,9 +292,12 @@ fn parse_expression(src: String) -> Result<(String, String), String> {
let callee = data[0].clone();
let args = from_str::<Vec<String>>(&data[1])?;
let mut ast_args = vec![];
if let Some(args) = args.get(0) {
let args = from_str::<Vec<String>>(&args)?;
for arg in &args {
ast_args.push(from_str::<AstNode>(arg)?);
}
}
Ok(to_string(
&AstNode::function_call(callee, ast_args),
)?)

View File

@ -1,5 +1,5 @@
require("webassembly")
.load("out.wasm")
.then(module => {
console.log("2 + 2 is " + module.exports.add(2, 2));
console.log("3 + 2 is " + module.exports.main(3));
});