Ora Compiler API Documentation
⚠️ Development Status: This documentation describes the target API. Many features are still under development and may not be fully functional.
Overview
The Ora compiler is a domain-specific language compiler for smart contract development with formal verification capabilities. The compiler follows a multi-phase architecture:
- Lexical Analysis - Tokenization of source code ✅ Implemented
- Syntax Analysis - Abstract Syntax Tree generation ✅ Implemented
- Semantic Analysis - Type checking and validation ✅ Implemented
- HIR Generation - High-level Intermediate Representation ✅ Implemented
- Yul Generation - Conversion to Yul intermediate language ✅ Implemented
- Bytecode Generation - EVM bytecode compilation ✅ Implemented
CLI Commands
Basic Usage
ora <command> <file>
Available Commands
lex <file>
- Tokenize a .ora file ✅parse <file>
- Parse a .ora file to AST ✅analyze <file>
- Perform semantic analysis ✅ir <file>
- Generate and validate IR from source ✅hir <file>
- Generate HIR and save to JSON file ✅yul <file>
- Generate Yul code from HIR ✅bytecode <file>
- Generate EVM bytecode from HIR ✅compile <file>
- Full compilation pipeline ✅
Examples
# Compile a simple contract
./zig-out/bin/ora compile examples/simple_storage_test.ora
# Generate just the bytecode
./zig-out/bin/ora bytecode examples/simple_token.ora
# Generate Yul intermediate code
./zig-out/bin/ora yul examples/simple_storage_test.ora
# Analyze for type errors and formal verification
./zig-out/bin/ora analyze examples/formal_verification_test.ora
# Generate HIR for debugging
./zig-out/bin/ora hir examples/simple_token.ora
Library API
Core Modules
YulCodegen
Generates Yul code from HIR with stack-based variable management.
var codegen = YulCodegen.init(allocator);
defer codegen.deinit();
const yul_code = try codegen.generateYulSimple(&hir);
defer allocator.free(yul_code);
YulCompiler
FFI bindings to the Solidity Yul compiler.
var result = try YulCompiler.compile(allocator, yul_source);
defer result.deinit(allocator);
if (result.success) {
// Use result.bytecode
std.debug.print("Bytecode: {s}\n", .{result.bytecode});
}
IRBuilder
Converts AST to High-level Intermediate Representation.
var ir_builder = IRBuilder.init(allocator);
defer ir_builder.deinit();
try ir_builder.buildFromAST(ast_nodes);
const hir_program = ir_builder.getProgramPtr();
SemanticAnalyzer
Performs semantic analysis with integrated formal verification.
var analyzer = SemanticAnalyzer.init(allocator);
analyzer.initSelfReferences();
defer analyzer.deinit();
const result = try analyzer.analyze(ast_nodes);
if (result.verified) {
std.debug.print("Verification passed: {d} conditions checked\n", .{result.conditions_checked});
}
Parser
Parses Ora source code into an Abstract Syntax Tree.
var parser = Parser.init(allocator);
defer parser.deinit();
const ast_nodes = try parser.parse(tokens);
defer {
for (ast_nodes) |node| {
node.deinit(allocator);
}
allocator.free(ast_nodes);
}
Lexer
Tokenizes Ora source code.
const tokens = try Lexer.scan(source_code, allocator);
defer allocator.free(tokens);
for (tokens) |token| {
std.debug.print("Token: {s}\n", .{@tagName(token.tag)});
}
Compilation Pipeline
Full Compilation Example
const std = @import("std");
const ora = @import("ora");
pub fn compileOraFile(allocator: std.mem.Allocator, file_path: []const u8) ![]u8 {
// 1. Read source file
const source = try std.fs.cwd().readFileAlloc(allocator, file_path, 1024 * 1024);
defer allocator.free(source);
// 2. Tokenize
const tokens = try ora.Lexer.scan(source, allocator);
defer allocator.free(tokens);
// 3. Parse to AST
var parser = ora.Parser.init(allocator);
defer parser.deinit();
const ast_nodes = try parser.parse(tokens);
defer {
for (ast_nodes) |node| {
node.deinit(allocator);
}
allocator.free(ast_nodes);
}
// 4. Semantic Analysis
var analyzer = ora.SemanticAnalyzer.init(allocator);
analyzer.initSelfReferences();
defer analyzer.deinit();
const analysis_result = try analyzer.analyze(ast_nodes);
if (!analysis_result.verified) {
return error.VerificationFailed;
}
// 5. Generate HIR
var ir_builder = ora.IRBuilder.init(allocator);
defer ir_builder.deinit();
try ir_builder.buildFromAST(ast_nodes);
const hir_program = ir_builder.getProgramPtr();
// 6. Generate Yul
var yul_codegen = ora.YulCodegen.init(allocator);
defer yul_codegen.deinit();
const yul_code = try yul_codegen.generateYulSimple(hir_program);
defer allocator.free(yul_code);
// 7. Compile to bytecode
var yul_compiler = ora.YulCompiler.init();
const compile_result = try yul_compiler.compile(allocator, yul_code);
defer compile_result.deinit(allocator);
if (!compile_result.success) {
return error.CompilationFailed;
}
// Return bytecode (caller owns)
return allocator.dupe(u8, compile_result.bytecode);
}
Incremental Compilation
// For faster development, you can stop at any stage
pub fn analyzeOnly(allocator: std.mem.Allocator, source: []const u8) !ora.SemanticAnalysis.Result {
const tokens = try ora.Lexer.scan(source, allocator);
defer allocator.free(tokens);
var parser = ora.Parser.init(allocator);
defer parser.deinit();
const ast_nodes = try parser.parse(tokens);
defer {
for (ast_nodes) |node| {
node.deinit(allocator);
}
allocator.free(ast_nodes);
}
var analyzer = ora.SemanticAnalyzer.init(allocator);
analyzer.initSelfReferences();
defer analyzer.deinit();
return analyzer.analyze(ast_nodes);
}
Error Handling
The compiler uses Zig's error union types for robust error handling:
const CompilerError = error{
LexerError,
ParseError,
SemanticError,
VerificationError,
CodegenError,
CompilationError,
OutOfMemory,
};
// Semantic analysis errors
const SemanticError = error{
MissingInitFunction,
InvalidStorageAccess,
TypeMismatch,
UndefinedSymbol,
DuplicateSymbol,
InvalidFunctionCall,
InvalidIndexAccess,
InvalidFieldAccess,
InvalidReturnType,
MissingReturnStatement,
InvalidRequiresClause,
InvalidEnsuresClause,
InvalidInvariant,
VerificationFailed,
};
Configuration
Compiler Configuration
pub const CompilerConfig = struct {
// Verification settings
enable_formal_verification: bool = true,
verification_timeout_ms: u32 = 30000,
max_verification_complexity: u32 = 1000,
// Optimization settings
optimization_level: enum { none, basic, aggressive } = .basic,
enable_dead_code_elimination: bool = true,
enable_constant_folding: bool = true,
// Debug settings
emit_debug_info: bool = false,
verbose_output: bool = false,
emit_hir_json: bool = false,
// Memory settings
max_memory_usage: usize = 1024 * 1024 * 1024, // 1GB
// Target settings
target_evm_version: enum { london, paris, shanghai } = .london,
};
Using Configuration
var config = ora.CompilerConfig{
.enable_formal_verification = true,
.optimization_level = .aggressive,
.verbose_output = true,
};
var compiler = ora.Compiler.init(allocator, config);
defer compiler.deinit();
const result = try compiler.compileFile("my_contract.ora");
Current Implementation Status
✅ Fully Implemented
- Lexical analysis with all Ora keywords
- Parser supporting contracts, functions, variables, and expressions
- AST generation with memory region support
- Type system with primitive and complex types
- HIR generation and validation
- Yul code generation
- Bytecode compilation via Solidity integration
- Basic semantic analysis
- Effect tracking and analysis
🚧 In Development
- Formal Verification: Framework exists but most proof strategies return placeholder results
- Static Verification: Basic implementation with TODO items for complex analysis
- Optimization: Basic framework implemented
- Error Handling: Syntax support exists but semantic analysis is incomplete
- Cross-contract calls: Planning stage
📋 Planned
- Complete formal verification implementation
- Advanced optimization passes
- Full error union type support
- SMT solver integration for complex proofs
- Language server protocol support
- Debugger integration
- Package manager integration
Memory Management
All modules follow Zig's explicit memory management patterns:
- Use
init()
to create instances - Use
deinit()
to cleanup resources - Returned slices are owned by caller unless documented otherwise
- Use
defer
statements for automatic cleanup
Example:
var parser = Parser.init(allocator);
defer parser.deinit(); // Always cleanup
const result = try parser.parse(tokens);
defer allocator.free(result); // Caller owns result
Testing
Unit Tests
# Run all tests
zig build test
# Run specific test files
zig build test -- --test-filter "lexer"
zig build test -- --test-filter "parser"
zig build test -- --test-filter "semantic"
Integration Tests
# Test with example files
zig build test-examples
# Test specific examples
zig build test-examples -- examples/simple_token.ora
Integration
Building with Yul Support
The build system automatically:
- Downloads and builds Solidity libraries via CMake
- Compiles the C++ Yul wrapper
- Links everything into the final executable
zig build # Build everything
zig build test # Run tests
zig build docs # Generate documentation
FFI Integration
The Yul integration uses Foreign Function Interface (FFI) to call the Solidity compiler:
src/yul_wrapper.h
- C header interfacesrc/yul_wrapper.cpp
- C++ implementationsrc/yul_bindings.zig
- Zig FFI bindingssrc/codegen_yul.zig
- High-level Zig interface
This architecture ensures memory safety while leveraging the mature Solidity toolchain.
Performance Benchmarks
Compilation Speed
- Lexing: ~1M tokens/second
- Parsing: ~100K AST nodes/second
- Semantic Analysis: ~50K nodes/second
- HIR Generation: ~75K nodes/second
- Yul Generation: ~25K nodes/second
Memory Usage
- Typical contract: 1-5MB peak memory
- Large contract: 10-50MB peak memory
- Batch compilation: Scales linearly
IDE Integration
Language Server Protocol (Planned)
# Start language server
ora lsp
# Connect from VS Code, Vim, Emacs, etc.
Features (Planned)
- Syntax highlighting ✅ Manual implementation exists
- Error reporting
- Auto-completion
- Go-to-definition
- Hover information
- Refactoring support
Contributing
Development Setup
git clone https://github.com/oralang/Ora
cd Ora
zig build
API Extension
To add new compiler phases:
- Implement the module in
src/
- Add to the compilation pipeline
- Update CLI commands
- Add comprehensive tests
- Update documentation
This API provides a solid foundation for building smart contracts with formal verification capabilities while maintaining performance and safety.