Skip to content

Commit

Permalink
started trn module working on wat and wasm
Browse files Browse the repository at this point in the history
  • Loading branch information
hyouteki committed Aug 12, 2024
1 parent 2a7db7b commit bd8533a
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 41 deletions.
2 changes: 1 addition & 1 deletion eg/fib.irl.dot → eg/test.dot
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
digraph "./eg/fib.irl.dot" {
digraph "./eg/test.dot" {
subgraph cluster_fib {
label="fib";
graph [style=filled];
Expand Down
4 changes: 2 additions & 2 deletions eg/fib.irl.dot.svg → eg/test.dot.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
33 changes: 0 additions & 33 deletions eg/test.irl.dot

This file was deleted.

Binary file added eg/test.wasm
Binary file not shown.
20 changes: 20 additions & 0 deletions eg/test.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
(module
(func $fib (export "fib") (param $n i32) (result i32)
(block $1
)
(block $begin
)
(block $end
)
(block $4
br $begin
)
i32.const 0
)
(func $main (export "main") (result i32)
br $1
(block $1
)
i32.const 0
)
)
34 changes: 34 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ pub struct CliOptions {
pub cfg: bool,
pub debug: bool,
pub verbose: bool,
pub wat: bool,
pub wasm: bool,
}

impl CliOptions {
Expand All @@ -16,15 +18,37 @@ impl CliOptions {
cfg: *compile_args.unwrap().get_one::<bool>("cfg").unwrap(),
debug: *compile_args.unwrap().get_one::<bool>("debug").unwrap(),
verbose: *compile_args.unwrap().get_one::<bool>("verbose").unwrap(),
wat: *compile_args.unwrap().get_one::<bool>("wat").unwrap(),
wasm: *compile_args.unwrap().get_one::<bool>("wasm").unwrap(),
}
}
pub fn verbose_message(&self, message: String) {
if self.verbose {println!("{}: info: {}", self.filepath, message);}
}
pub fn verbose_error(&self, message: String) {
if self.verbose {println!("{}: error: {}", self.filepath, message);}
}
pub fn run_command(&self, args: &[&str]) {
if args.is_empty() {return;}

let binpath = args.get(0).cloned().unwrap_or_default();
let mut command = std::process::Command::new(binpath);
for arg in &args[1..] {
command.arg(arg);
}

let output = command.output().expect("failed to execute command");
if !output.status.success() {
let stderr = std::str::from_utf8(&output.stderr).expect("Invalid UTF-8 in stderr");
self.verbose_message(format!("error: {}", stderr));
}
}
}

pub fn cli() -> Command {
Command::new("irl")
.version("1.0")
.author("Hyouteki")
.about("Intermediate Representation Language: Minimal implementation of LLVM")
.subcommand_required(true)
.arg_required_else_help(true)
Expand Down Expand Up @@ -57,5 +81,15 @@ pub fn cli() -> Command {
.required(false)
.action(ArgAction::SetTrue)
.help("Sets info level to verbose"))
.arg(Arg::new("wat")
.long("wat")
.required(false)
.action(ArgAction::SetTrue)
.help("Generates WAT"))
.arg(Arg::new("wasm")
.long("wasm")
.required(false)
.action(ArgAction::SetTrue)
.help("Generates WASM"))
)
}
13 changes: 8 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::fe::{lexer::Lexer, parser::Parser, ast::AstNode};
use crate::mw::default_ast_pass_manager::*;
use crate::opt::{default_compiler_pass_manager::*, cfg::*};
use crate::trn::transpiler::*;
use crate::cli::CliOptions;
use std::process::Command;

pub mod fe;
pub mod mw;
pub mod opt;
pub mod trn;
pub mod cli;

fn main() {
Expand Down Expand Up @@ -42,10 +43,10 @@ fn main() {
let mut cfg_table: Vec<ControlFlowGraph> = cfg_table_from_program(&ast);
run_default_compiler_pass_manager(&mut cfg_table);
if options.cfg {
let dot_filepath: String = format!("{}.dot", options.filepath.clone());
dump_cfg_table_to_svg(&cfg_table, dot_filepath.clone());
Command::new("dot").arg("-Tsvg").arg("-O").arg(dot_filepath.clone());
options.verbose_message(format!("created control flow graph svg '{}'", dot_filepath));
let dot_filepath: String = replace_extension(options.filepath.clone(), "irl", "dot");
dump_cfg_table_to_svg(&cfg_table, dot_filepath.to_string());
options.run_command(&["dot", "-Tsvg", "-O", dot_filepath.as_str()]);
options.verbose_error(format!("created control flow graph svg '{}.svg'", dot_filepath));
}
options.verbose_message(format!("OPT over"));

Expand All @@ -60,4 +61,6 @@ fn main() {
println!("{}", node);
}
}

transpile(&options, &ast, options.filepath.clone());
}
2 changes: 2 additions & 0 deletions src/trn/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod transpiler;
pub mod wat_transpiler;
34 changes: 34 additions & 0 deletions src/trn/transpiler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use std::{fs::File, io::Write};
use crate::{fe::ast::*, cli::*};
use crate::trn::wat_transpiler::WatTranspiler;

pub trait Transpiler {
fn transpile(&self, nodes: &Vec<AstNode>) -> Vec<String>;
}

fn remove_extension(filepath: String, ext: &str) -> String {
filepath.as_str().trim_end_matches(ext).to_string()
}

pub fn replace_extension(filepath: String, old_ext: &str, new_ext: &str) -> String {
format!("{}{}", remove_extension(filepath, old_ext), new_ext)
}

pub fn transpilation_mode<T: Transpiler + 'static>(transpiler: T, nodes: &Vec<AstNode>,
output_filepath: String) {
let mut file = File::create(output_filepath).expect("could not create file");
for line in transpiler.transpile(nodes).iter() {
file.write_all(line.as_bytes()).expect("could not write line");
file.write_all(b"\n").expect("could not write new line");
}
}

pub fn transpile(options: &CliOptions, nodes: &Vec<AstNode>, filepath: String) {
if options.wat || options.wasm {
let wat_filepath: String = replace_extension(filepath.clone(), "irl", "wat");
transpilation_mode(WatTranspiler{}, nodes, wat_filepath.clone());
if !options.wasm {return;}
let wasm_filepath: String = replace_extension(filepath.clone(), "irl", "wasm");
options.run_command(&["wat2wasm", wat_filepath.as_str(), "-o", wasm_filepath.as_str()]);
}
}
62 changes: 62 additions & 0 deletions src/trn/wat_transpiler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::collections::HashSet;
use crate::fe::ast::*;
use crate::trn::transpiler::Transpiler;

pub struct WatTranspiler;

impl Transpiler for WatTranspiler {
fn transpile(&self, nodes: &Vec<AstNode>) -> Vec<String> {
let mut lines: Vec<String> = Vec::new();
lines.push(String::from("(module"));
lines.append(&mut transpile_nodes_to_wat(nodes, 1, &mut HashSet::new()));
lines.push(String::from(")"));
lines
}
}

fn transpile_nodes_to_wat(nodes: &Vec<AstNode>, indent_sz: usize,
vis_labels: &mut HashSet<String>) -> Vec<String> {

let mut lines: Vec<String> = Vec::new();
for node in nodes.iter() {
lines.append(&mut transpile_node_to_wat(node, indent_sz, vis_labels));
}
lines
}

fn make_line(indent_sz: usize, text: String) -> String {let mut line: String = String::new();
for _ in 0..indent_sz {line.push_str(" ");}
line.push_str(&text);
line
}

fn transpile_node_to_wat(node: &AstNode, indent_sz: usize, vis_labels: &mut HashSet<String>) -> Vec<String> {
let mut lines: Vec<String> = Vec::new();
match node {
AstNode::Function(function_node) => {
let mut line: String = make_line(indent_sz, format!("(func ${} (export \"{}\")",
function_node.name, function_node.name));
for arg_name in function_node.args.iter() {
line += &format!(" (param ${} i32)", arg_name);
}
line += " (result i32)";
lines.push(line);
lines.append(&mut transpile_nodes_to_wat(&function_node.body, indent_sz+1, vis_labels));
lines.push(make_line(indent_sz+1, String::from("i32.const 0")));
lines.push(make_line(indent_sz, String::from(" )")));
}
AstNode::Label(label_node) => {
lines.push(make_line(indent_sz, format!("(block ${}", label_node.name)));
vis_labels.insert(label_node.name.clone());
lines.append(&mut transpile_nodes_to_wat(&label_node.body, indent_sz+1, vis_labels));
lines.push(make_line(indent_sz, String::from(")")));
}
AstNode::Goto(goto_node) => {
if vis_labels.contains(&goto_node.name) {
lines.push(make_line(indent_sz, format!("br ${}", goto_node.name)));
}
}
_ => {}
}
lines
}

0 comments on commit bd8533a

Please sign in to comment.