Please implement a parser for the H-Exprs language using the pest PEG parser generator in Rust. This is a compact notation for open hypergraphs with S-expression-like syntax.
name: [a-zA-Z][a-zA-Z0-9_-]+
variable: name | _
expr:
| '(' expr+ ')' // composition of expressions
| '{' expr+ '}' // tensoring of expressions
| '[' variable* '.' variable* ']' // frobenius relation
| name // primitive operation
- Variables (in frobenius relations) are scoped to the entire expression
- The dot
.in[vars . vars]separates input variables from output variables [vars]without dot is shorthand for identity:[x y] ≡ [x y . x y]_represents anonymous/unbound variables- Names are primitive operations when not in frobenius relations
Create a pest grammar file defining:
// Define the complete grammar using pest syntax
// Include proper whitespace handling with WHITESPACE rule
// Handle comments if desired with COMMENT rule
// Ensure left-recursion is avoided (pest requirement)
Key pest rules to implement:
name- Identifier patternvariable- Named variable or anonymous_frobenius_full- Full form[vars . vars]frobenius_identity- Identity shorthand[vars]frobenius- Either formcomposition-(expr+)tensor-{expr+}operation- Bare operation nameexpr- Main expression ruleprogram- Top-level rule
Define AST types to represent:
#[derive(Debug, Clone, PartialEq)]
pub enum Expr {
Composition(Vec<Expr>),
Tensor(Vec<Expr>),
Frobenius { inputs: Vec<Variable>, outputs: Vec<Variable> },
Operation(String),
}
#[derive(Debug, Clone, PartialEq)]
pub enum Variable {
Named(String),
Anonymous,
}Implement parser using pest:
use pest::Parser;
use pest_derive::Parser;
#[derive(Parser)]
#[grammar = "grammar.pest"]
pub struct HExprParser;
// Implement conversion from pest::Pairs to AST
impl From<pest::iterators::Pair<'_, Rule>> for Expr { ... }Key functions:
parse_expr- Convert pest pairs to ASTparse_variable- Handle named/anonymous variablesparse_frobenius- Handle both full and identity formsbuild_ast- Main AST construction function
Include comprehensive tests for these examples:
Basic frobenius relations:
"[x x . x]" // 2->1 join
"[x . x x]" // 1->2 split
"[x y]" // 2->2 identity (shorthand)
"[_]" // anonymous identity
"([x.][.x])" // identity via compositionComplex expressions:
"({[_] -} +)" // subtraction (pointfree)
"([x y.] ([.y] - [z.]) [.x z] +)" // subtraction (pointed)
"[x y . y x]" // explicit swap relationEdge cases:
"[.]" // empty inputs/outputs
"[x .]" // discard x
"[. x]" // create x
"[_ _ . _]" // dispell 2, summon 1- Leverage pest's built-in error reporting
- Provide meaningful error messages for common mistakes
- Handle whitespace and comments appropriately
- Validate semantic constraints during AST construction
src/
├── main.rs // CLI interface for testing
├── lib.rs // Library exports
├── ast.rs // AST type definitions
├── parser.rs // pest parser implementation
├── tests.rs // Comprehensive test suite
└── grammar.pest // pest grammar definition
[package]
name = "h-exprs"
version = "0.1.0"
edition = "2021"
[dependencies]
pest = "2.7"
pest_derive = "2.1"
clap = "4.0" # for CLI interface- Use
WHITESPACE = _{ " " | "\t" | "\n" | "\r" }for automatic whitespace handling - Avoid left-recursion - pest is PEG-based
- Use
@for atomic rules and_for silent rules where appropriate - Consider using
$for string capture when needed
- Make sure expression lists use
+(one or more) not*(zero or more) - Handle the dot separator carefully in frobenius relations
- Use pest's built-in precedence handling if needed
- Consider making whitespace handling explicit in key places
- Convert pest's tree structure to your clean AST types
- Handle the identity shorthand transformation:
[x y]→[x y . x y] - Validate variable names during AST construction
- Preserve source location information if useful for error reporting
- Complete Rust project with Cargo.toml and grammar.pest
- Well-documented parser implementation using pest
- Clean AST types representing the language structure
- Comprehensive test suite covering all grammar rules
- CLI tool to parse, validate, and pretty-print H-expressions
- Clear error messages leveraging pest's error reporting
The goal is a clean, maintainable parser that takes advantage of pest's grammar-first approach while correctly handling the compositional structure and variable scoping semantics of H-Exprs.