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

View File

@ -4,13 +4,19 @@ use std::fs::File;
use std::io::prelude::*; use std::io::prelude::*;
fn main() -> std::io::Result<()> { 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); let ast = pivot::parse(src);
// println!("{}", ast); println!("{}", ast);
let mut code = String::new(); let code = ast.emit();
ast.emit(&mut code);
println!("{}", code); println!("{}", code);
let binary = wat::parse_str(code).unwrap(); 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(()) Ok(())
} }

View File

@ -1,15 +1,22 @@
mod combinators; mod combinators;
use crate::ast::AstNode; use crate::ast::{AstNode, AstNodeKind};
use combinators::Parser; use combinators::Parser;
use ron::{from_str, to_string}; use ron::{from_str, to_string};
pub fn parse<T: Into<String>>(src: T) -> AstNode { pub fn parse<T: Into<String>>(src: T) -> AstNode {
let src: String = src.into(); 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) .repeat_range(0..usize::MAX)
.map(|matched| { .map(|matched| {
let data = from_str::<Vec<String>>(&matched)?; let data = from_str::<Vec<String>>(&matched)?;
for d in &data {
println!("{}", d);
}
let mut statements = vec![]; let mut statements = vec![];
for d in data { for d in data {
statements.push(from_str::<AstNode>(&d)?); statements.push(from_str::<AstNode>(&d)?);
@ -159,29 +166,31 @@ fn parse_statement(src: String) -> Result<(String, String), String> {
.and(block_statement.clone()) .and(block_statement.clone())
.map(|matched| { .map(|matched| {
let data = from_str::<Vec<String>>(&matched)?; let data = from_str::<Vec<String>>(&matched)?;
for d in &data { let mut body = from_str::<AstNode>(&data[1])?;
println!("{}", d);
}
let body = from_str::<AstNode>(&data[1])?;
println!("body: {}", body);
let data = from_str::<Vec<String>>(&data[0])?; let data = from_str::<Vec<String>>(&data[0])?;
for d in &data {
println!("{}", d);
}
let name = from_str::<AstNode>(&data[0])?.value; let name = from_str::<AstNode>(&data[0])?.value;
println!("name: {}", name);
let params = from_str::<Vec<String>>(&data[1])?; let params = from_str::<Vec<String>>(&data[1])?;
let mut parameters = vec![]; let mut parameters = vec![];
if params.len() != 0 {
for p in from_str::<Vec<String>>(&params[0])? { for p in from_str::<Vec<String>>(&params[0])? {
parameters.push(from_str::<AstNode>(&p)?); 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))?) 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() return_statement.clone()
.or(if_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 callee = data[0].clone();
let args = from_str::<Vec<String>>(&data[1])?; let args = from_str::<Vec<String>>(&data[1])?;
let mut ast_args = vec![]; let mut ast_args = vec![];
if let Some(args) = args.get(0) {
let args = from_str::<Vec<String>>(&args)?;
for arg in &args { for arg in &args {
ast_args.push(from_str::<AstNode>(arg)?); ast_args.push(from_str::<AstNode>(arg)?);
} }
}
Ok(to_string( Ok(to_string(
&AstNode::function_call(callee, ast_args), &AstNode::function_call(callee, ast_args),
)?) )?)

View File

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