Goiaba: An experimental Go compiler, written in Rust

1 month ago 1

An experimental Go parser and WebAssembly compiler written in Rust. Goiaba translates Go source code into WebAssembly bytecode, enabling Go programs to run in web browsers and other WebAssembly environments.

  • Parse Go source code into an Abstract Syntax Tree (AST)
  • Compile Go functions to WebAssembly modules
  • Support for fundamental Go language features (functions, control flow, arithmetic)
  • Export Go functions for use in JavaScript/WebAssembly environments
  • Export Go functions for use in Rust through C ABI
  • Export Go functions for use in Zig through C ABI
  • Command-line interface for compilation
  • Programmatic API for integration into Rust projects

Add to your Cargo.toml:

[dependencies] goiaba = "*"

Basic compilation:

goiaba main.go -o main.wasm

Compile with verbose output:

goiaba input.go --output output.wasm --verbose

Generate a complete web project with HTML and JavaScript:

goiaba main.go -w ./web-project

Advanced usage with multiple options:

goiaba calculator.go -o calc.wasm -w ./demo --verbose
use goiaba::wasm::compiler::compile_str; fn main() { let go_source = r#" package main //export add func add(x int, y int) int { return x + y } "#; let wasm_bytes = compile_str(go_source) .expect("Failed to compile Go to WASM"); // Write to file or use with a WASM runtime std::fs::write("output.wasm", wasm_bytes) .expect("Failed to write WASM file"); }
use goiaba::wasm::compiler::compile_str; use wasmtime::{Engine, Instance, Module, Store}; fn main() { let go_source = r#" package main //export add func add(x int, y int) int { return x + y } "#; let wasm_bytes = compile_str(go_source) .expect("Failed to compile Go to WASM"); // Create a WASM runtime let engine = Engine::default(); let module = Module::from_binary(&engine, &wasm_bytes) .expect("Failed to load WASM module"); let mut store = Store::new(&engine, ()); // Instantiate the module let instance = Instance::new(&mut store, &module, &[]) .expect("Failed to instantiate module"); // Get the exported function let add_func = instance .get_typed_func::<(i32, i32), i32>(&mut store, "add") .expect("Failed to get 'add' function"); // Call the function let result = add_func .call(&mut store, (5, 3)) .expect("Failed to call 'add' function"); assert_eq!(result, 8); }
use goiaba::parser::parse_str; fn main() { let source = r#" package main func fibonacci(n int) int { if n <= 1 { return n } return fibonacci(n-1) + fibonacci(n-2) } "#; match parse_str(source) { Ok((objects, file)) => { println!("Successfully parsed Go source code"); // Access AST nodes through objects and file } Err(err) => { eprintln!("Parse error: {}", err); } } }
  • Function definitions with parameters and return types
  • Integer arithmetic operations (+, -, *, /, %)
  • Comparison operations (<, >, <=, >=, ==, !=)
  • Bitwise operations (&, |, ^, <<, >>)
  • Logical operations (&&, ||, !)
  • Variable declarations and assignments
  • If-else statements and nested conditionals
  • For loops with initialization, condition, and post statements
  • Recursive function calls
  • Function calls with multiple arguments
  • Increment and decrement operators (++, --)
  • Unary operators (-, !)
  • Struct types with field access and assignment
  • Composite literals for struct initialization
  • Arrays and slices
  • String literals and operations
  • Switch statements
  • Pointer operations
  • Methods on types
  • Interfaces
  • Multiple return values
  • Defer statements
  • Panic and recover
  • Goroutines and channels
  • Package imports
  • Standard library support

To make Go functions callable from WebAssembly, use the //export directive:

//export function_name func function_name(param1 int, param2 int) int { return param1 + param2 }

The exported name will be used in the WebAssembly module exports.

  • Go source code parsing to Abstract Syntax Tree (AST)
  • Translation of Go constructs to WebAssembly representations
  • WebAssembly bytecode generation
  • Function definitions with parameter and return types
  • Variable declarations and assignments
  • Control flow statements (if/else, for loops)
  • Exportable WASM functions
  • Arithmetic operations (+, -, *, /, %)
  • Comparison operations (<, >, <=, >=, ==, !=)
  • Bitwise operations (&, |, ^, <<, >>)
  • Logical operations (&&, ||, !)
  • Increment/decrement operators (++, --)
  • Recursive function calls
  • Struct types with field access and assignment
  • Command-line interface
  • Unary operators (negation, logical NOT)
  • Arrays and slices
  • String literals and operations
  • Switch statements
  • Pointer dereferencing and operations
  • Methods on types
  • Interfaces
  • Multiple return values
  • Defer statements
  • Panic and recover
  • Package imports
  • Standard library functions
  • Floating-point operations
  • Memory management optimizations
  • Goroutines and channels
  • Complete standard library support
  • Source maps for debugging
  • Optimization passes for generated WASM
  • JavaScript bindings generation (wasm-bindgen)
  • Rust code generation
  • Zig code generation
  • LLVM-IR target compilation

Goiaba consists of several key components:

  1. Parser: Lexical analysis and syntax parsing of Go source code
  2. AST: Internal representation of Go program structure
  3. Translator: Conversion from Go AST to WebAssembly IR
  4. Compiler: Generation of WebAssembly bytecode
  5. CLI: Command-line interface for user interaction

Performance Considerations

The generated WebAssembly code prioritizes correctness over optimization. Future versions will include:

  • Dead code elimination
  • Constant folding
  • Register allocation improvements
  • Memory access optimization
  • Function inlining for small functions

Contributions are welcome. Please ensure all tests pass before submitting pull requests:

cargo test cargo clippy cargo fmt

Run the test suite:

Current limitations of the compiler, yet to be added:

  • No garbage collection (manual memory management)
  • Limited standard library support
  • No concurrency primitives (goroutines, channels)
  • Single file compilation only
  • No optimizer passes

BSD-3-Clause

Copyright (c) 2024 Raphael Amorim

This project builds upon concepts from the Go language specification and WebAssembly standards. Parser implementation is adapted from the Goscript project.

Read Entire Article