Code generation
This commit is contained in:
parent
d95c8dc278
commit
1c3d7c6bd1
124
src/ast.rs
124
src/ast.rs
@ -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() {
|
||||||
Block => {
|
break;
|
||||||
for node in &self.subnodes {
|
}
|
||||||
node.emit(f)?;
|
match body.subnodes[index].kind {
|
||||||
|
AstNodeKind::FunctionReturn => func_returns_value = true,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
index += 1;
|
||||||
}
|
}
|
||||||
write!(f, "")
|
if func_returns_value {
|
||||||
|
out += " (result i32)";
|
||||||
|
}
|
||||||
|
for n in &body.subnodes {
|
||||||
|
out += " ";
|
||||||
|
out += &n.emit();
|
||||||
|
}
|
||||||
|
out += ")";
|
||||||
|
out
|
||||||
}
|
}
|
||||||
FunctionReturn => self.subnodes[0].emit(f),
|
VariableDeclaration => format!("(local ${} i32)", self.value),
|
||||||
_ => Ok(()),
|
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,
|
||||||
|
16
src/main.rs
16
src/main.rs
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -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![];
|
||||||
for p in from_str::<Vec<String>>(¶ms[0])? {
|
if params.len() != 0 {
|
||||||
parameters.push(from_str::<AstNode>(&p)?);
|
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))?)
|
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,8 +292,11 @@ 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![];
|
||||||
for arg in &args {
|
if let Some(args) = args.get(0) {
|
||||||
ast_args.push(from_str::<AstNode>(arg)?);
|
let args = from_str::<Vec<String>>(&args)?;
|
||||||
|
for arg in &args {
|
||||||
|
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),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user