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
Goiaba consists of several key components:
- Parser: Lexical analysis and syntax parsing of Go source code
- AST: Internal representation of Go program structure
- Translator: Conversion from Go AST to WebAssembly IR
- Compiler: Generation of WebAssembly bytecode
- CLI: Command-line interface for user interaction
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.