pub struct Parser<'a> {
line_no: i64,
state: State,
cursor: Option<ChunkCursor<'a>>,
version: Option<Version>,
extension_parser: ExtensionParser,
extension_registry: ExtensionRegistry,
relation_parser: RelationParser<'a>,
}Expand description
A parser for Substrait query plans in text format.
The Parser converts human-readable Substrait text format into Substrait
protobuf plans. It handles both the extensions section (which defines
functions, types, etc.) and the plan section (which defines the actual query
structure).
§Usage
The simplest entry point is the static parse() method:
use substrait_explain::Parser;
let plan_text = r#"
=== Plan
Root[c, d]
Project[$1, 42]
Read[schema.table => a:i64, b:string?]
"#;
let plan = Parser::parse(plan_text).unwrap();§Input Format
The parser expects input in the following format:
=== Extensions
URNs:
@ 1: https://github.com/substrait-io/substrait/blob/main/extensions/functions_arithmetic.yaml
Functions:
# 10 @ 1: add
=== Plan
Root[columns]
Relation[arguments => columns]
ChildRelation[arguments => columns]- Extensions section (optional): Defines URNs and function/type declarations
- Plan section (required): Defines the query structure with indented relations
§Error Handling
The parser provides detailed error information including:
- Line number where the error occurred
- The actual line content that failed to parse
- Specific error type and description
use substrait_explain::Parser;
let invalid_plan = r#"
=== Plan
InvalidRelation[invalid syntax]
"#;
match Parser::parse(invalid_plan) {
Ok(plan) => println!("Successfully parsed"),
Err(e) => eprintln!("Parse error: {}", e),
}§Supported Relations
The parser supports all standard Substrait relations:
Read[table => columns]- Read from a tableProject[expressions]- Project columns/expressionsFilter[condition => columns]- Filter rowsRoot[columns]- Root relation with output columns- And more…
§Extensions Support
The parser fully supports Substrait Simple Extensions, allowing you to:
- Define custom functions with URNs and anchors
- Reference functions by name in expressions
- Use custom types and type variations
use substrait_explain::Parser;
let plan_with_extensions = r#"
=== Extensions
URNs:
@ 1: https://example.com/functions.yaml
Functions:
# 10 @ 1: my_custom_function
=== Plan
Root[result]
Project[my_custom_function($0, $1):i32]
Read[table => col1:i32, col2:i32]
"#;
let plan = Parser::parse(plan_with_extensions).unwrap();§Performance
The parser is designed for efficiency:
- Single-pass parsing with minimal allocations
- Early error detection and reporting
- Memory-efficient tree building
§Thread Safety
Parser instances are not thread-safe and should not be shared between threads.
However, the static parse() method is safe to call from multiple threads.
Fields§
§line_no: i64§state: State§cursor: Option<ChunkCursor<'a>>Cursor over the remaining input, advanced one chunk at a time by
next_chunk. None before parsing starts and once
the input is exhausted.
version: Option<Version>The plan version from an optional === Version section
extension_parser: ExtensionParser§extension_registry: ExtensionRegistry§relation_parser: RelationParser<'a>Implementations§
Source§impl<'a> Parser<'a>
impl<'a> Parser<'a>
Sourcepub fn parse(input: &str) -> ParseResult
pub fn parse(input: &str) -> ParseResult
Parse a Substrait plan from text format.
This is the main entry point for parsing.
The input should be in the Substrait text format, which consists of:
- An optional extensions section starting with “=== Extensions”
- A plan section starting with “=== Plan”
- Indented relation definitions
§Examples
Simple parsing:
use substrait_explain::Parser;
let plan_text = r#"
=== Plan
Root[result]
Read[table => col:i32]
"#;
let plan = Parser::parse(plan_text).unwrap();
assert_eq!(plan.relations.len(), 1);§Errors
Returns a ParseError if the input cannot be parsed.
Sourcepub fn with_extension_registry(self, registry: ExtensionRegistry) -> Self
pub fn with_extension_registry(self, registry: ExtensionRegistry) -> Self
Configure the parser to use the specified extension registry.
Sourcepub fn parse_plan(self, input: &'a str) -> ParseResult
pub fn parse_plan(self, input: &'a str) -> ParseResult
Parse a Substrait plan with the current parser configuration.
Sourcefn next_chunk(&mut self) -> (&'a str, i64)
fn next_chunk(&mut self) -> (&'a str, i64)
Group the next chunk out of the cursor: always its first physical line,
plus any - continuation lines indented one level deeper while we are
in the plan section.
For consistency, chunks always end with no newline.
Sourcefn parse_line(&mut self, line: &'a str) -> Result<(), ParseError>
fn parse_line(&mut self, line: &'a str) -> Result<(), ParseError>
Parse a single line of input.
Sourcefn parse_section_header(&mut self, line: &str) -> Result<State, ParseError>
fn parse_section_header(&mut self, line: &str) -> Result<State, ParseError>
Sourcefn parse_version_header(&self, line: &str) -> Result<Version, ParseError>
fn parse_version_header(&self, line: &str) -> Result<Version, ParseError>
Parse the === Version <major>.<minor>.<patch> header line and store
the resulting Version, leaving producer / git_hash empty
Sourcefn parse_version(&mut self, line: IndentedLine<'_>) -> Result<(), ParseError>
fn parse_version(&mut self, line: IndentedLine<'_>) -> Result<(), ParseError>
Parses a single line from the version section: an indented
producer: / git_hash: detail line. Section headers are
intercepted by parse_line before reaching here.
Sourcefn parse_version_detail(&mut self, line: &str) -> Result<(), ParseError>
fn parse_version_detail(&mut self, line: &str) -> Result<(), ParseError>
Parse an indented producer: / git_hash: detail line, mutating the
Version set by parse_version_header.
Sourcefn parse_extensions(
&mut self,
line: IndentedLine<'_>,
) -> Result<(), ExtensionParseError>
fn parse_extensions( &mut self, line: IndentedLine<'_>, ) -> Result<(), ExtensionParseError>
Parse a single line from the extensions section of the input.
Section headers are intercepted by parse_line
before reaching here.
Sourcefn build_plan(self) -> Result<Plan, ParseError>
fn build_plan(self) -> Result<Plan, ParseError>
Build the plan from the parser state with warning collection.