oxur-ast
Rust AST ↔ S-expression bidirectional conversion library with CLI tool.
Overview
oxur-ast provides a comprehensive toolkit for working with Rust Abstract Syntax Trees (AST) using S-expression syntax. It includes:
- Rust parsing - Parse real Rust source code into AST structures via
syn - S-expression parsing - Convert S-expression strings and files into structured data
- S-expression printing - Format S-expressions with customizable indentation
- File I/O - Read and write S-expressions from/to files
- AST building - Transform S-expressions into Rust AST structures
- Position tracking - Maintain source location information throughout parsing
- CLI tool -
astercommand-line tool for conversions and verification - Round-trip verification - Ensure conversion integrity
Features
S-expression Support
The library supports the following S-expression types:
- Symbols:
foo,bar,MyStruct - Keywords:
:name,:type,:value - Strings:
"hello","world\n" - Numbers:
42,-17,0 - Nil:
nil - Lists:
(foo bar baz),(:key value)
File I/O
Read and write S-expressions directly from/to files:
use ;
#
String Parsing
Parse S-expressions from strings:
use Parser;
#
Printing
Format S-expressions with customizable indentation:
use ;
#
AST Building
Convert S-expressions into Rust AST structures:
use AstBuilder;
use Parser;
#
Rust Parsing Integration
Parse real Rust source code into AST structures:
use parse_rust_file;
use Generator;
use print_sexp;
#
CLI Tool: aster
The aster command-line tool provides convenient commands for AST conversions and verification.
Installation
Commands
Convert Rust to S-expression:
# Output to stdout
# Save to file
# Compact format
Convert S-expression to Rust:
# Output to stdout
# Save to file
Verify round-trip conversion:
# Basic verification
# Verbose output
End-to-End Examples
Example 1: S-expression → Rust → Compiled Binary
This example demonstrates creating a Rust program from an S-expression representation, compiling it, and running it.
Step 1: Create project structure
Step 2: Create Cargo.toml
Step 3: Create src/main.sexp (hello world in S-expression format)
Step 4: Convert S-expression to Rust
Step 5: Compile the program
Step 6: Run the compiled binary
Output:
Hello from Oxur (via S-expression)!
Example 2: Rust → S-expression → Comparison
This example demonstrates converting Rust code to S-expression format and comparing it with the previous example.
Step 1: Create project structure
Step 2: Create Cargo.toml
Step 3: Create src/main.rs (hello world in Rust)
Step 4: Convert Rust to S-expression
Step 5: Compare the two S-expression representations
The diff shows the minimal differences - primarily just the string literal content:
- :tokens (TokenStream :source "\"Hello from Oxur (via S-expression)!\""))
+ :tokens (TokenStream :source "\"Hello from Oxur (via Rust)!\""))
This demonstrates that:
- Bidirectional conversion works - Rust ↔ S-expression conversions are equivalent
- Round-trip integrity - Converting back and forth preserves AST structure
- Semantic equivalence - The only differences are in the actual content (string literals), not the structure
Architecture
Rust Source → syn → oxur AST → Generator → S-expression
↑ ↓
└────── Builder ← Parser ──┘
Examples
The crate includes several examples demonstrating different features:
Parse Rust File
Parse a Rust source file and display AST information:
Convert File
Convert a Rust source file to S-expression format:
Parse Example
Basic S-expression parsing from files and strings:
Build Simple Crate
Building Rust AST structures from S-expression files:
File I/O
Comprehensive file I/O operations including reading, writing, and round-trip:
Test Data Organization
The crate includes a comprehensive test data directory (test-data/) with:
Examples (by complexity)
- simple/: Basic S-expressions (nil, numbers, symbols, keywords, strings, lists)
- intermediate/: Moderate complexity (functions, macro calls, paths, blocks)
- complex/: Advanced structures (full crates, deeply nested blocks)
Fixtures (by AST node type)
- crate/: Crate structures
- item/: Item definitions (functions, etc.)
- expr/: Expression nodes
- stmt/: Statement nodes
- block/: Block expressions
Error Cases
Test files that should fail to parse:
- unterminated-list.sexp: Missing closing parenthesis
- unexpected-close.sexp: Unexpected closing parenthesis
- unterminated-string.sexp: Missing closing quote
- invalid-escape.sexp: Invalid escape sequence
See test-data/README.md for detailed documentation.
API Documentation
Parser
use Parser;
#
Printer
use ;
#
AstBuilder
use AstBuilder;
use Parser;
#
Error Handling
The library provides detailed error types:
ParseError::EmptyInput: Empty input providedParseError::UnterminatedList: Missing closing parenthesisParseError::UnexpectedCloseParen: Unexpected closing parenthesisParseError::LexError: Lexical analysis errors (invalid escape, unterminated string)ParseError::FileReadError: Failed to read fileBuildError: AST building errors with position information
Testing
Run all tests:
Run specific test suite:
Performance Benchmarks
Run performance benchmarks:
The benchmark suite includes:
- parse_rust: Parsing Rust source code via syn
- generate_sexp: Generating S-expressions from AST
- parse_sexp: Parsing S-expression text
- build_ast: Building AST from S-expressions
- round_trip: Full round-trip conversion (Rust → S-expr → AST)
License
See the main repository for license information.
Contributing
Contributions are welcome! Please see the main repository for guidelines.