Code generation
This commit is contained in:
parent
d95c8dc278
commit
1c3d7c6bd1
122
src/ast.rs
122
src/ast.rs
@ -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,
|
||||
|
16
src/main.rs
16
src/main.rs
@ -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(())
|
||||
}
|
||||
|
@ -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>>(¶ms[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),
|
||||
)?)
|
||||
|
Loading…
x
Reference in New Issue
Block a user