Skip to main content

ParserContext

Trait ParserContext 

Source
pub trait ParserContext: Sized {
Show 18 methods // Required methods fn new_context() -> Self; fn new_fragment(&self) -> Self; fn push_literal<T: 'static + Clone>(&mut self, value: T, span: Span); fn apply_op( &mut self, op_lookup: &OpLookup, name: &str, arity: usize, start: Span, end: Span, ) -> Result<()>; fn apply_member( &mut self, lookup: &OpLookup, name: &str, name_span: ExprSpan, explicit_args: Option<usize>, start: Span, end: Span, ) -> Result<()>; fn make_record( &mut self, lookup: &OpLookup, name: &str, name_span: ExprSpan, fields: Vec<(String, ExprSpan)>, ambient_start: usize, start: Span, end: Span, ) -> Result<()>; fn apply_logical( &mut self, name: &str, rhs: Self, start: Span, end: Span, ) -> Result<()>; fn join2( &mut self, then_fragment: Self, else_fragment: Option<Self>, start: Span, end: Span, ) -> Result<()>; fn make_tuple( &mut self, n: usize, ambient_start: usize, start: Span, end: Span, ) -> Result<()>; fn make_array( &mut self, n: usize, ambient_start: usize, start: Span, end: Span, ) -> Result<()>; fn make_annotated_array( &mut self, n: usize, ambient_start: usize, annotation: AnnotatedArray<'_>, start: Span, end: Span, ) -> Result<()>; fn peek_tuple_arity(&self) -> Option<usize>; fn tuple_index( &mut self, index: usize, start: Span, end: Span, ) -> Result<()>; fn current_stack_offset(&self) -> usize; fn apply_cast( &mut self, op_lookup: &OpLookup, type_name: &str, start: Span, end: Span, ) -> Result<()>; // Provided methods fn resolves_closure_types() -> bool { ... } fn push_closure( &mut self, param_types: Vec<ValueType>, params: Vec<ClosureParam>, body: Self, span: Span, ) -> Result<()> { ... } fn output_type_id(&self) -> Option<TypeId> { ... }
}
Expand description

The pluggable target a grammar production emits into.

Each method mirrors one operation the grammar in lib.rs needs. Implementations decide what “emitting” means: DynSegmentContext executes immediately into a stack machine; a future AST-building context would instead record a tree node.

Required Methods§

Source

fn new_context() -> Self

Creates a fresh, empty context with no operations recorded yet.

Source

fn new_fragment(&self) -> Self

Creates an empty fragment for building an alternate branch (one side of a short-circuiting ||/&&, or an if/else branch), independent of self.

  • Precondition: self matches whatever precondition the implementation’s equivalent of DynSegment::new_fragment requires (for DynSegmentContext, a condition value already present).
Source

fn push_literal<T: 'static + Clone>(&mut self, value: T, span: Span)

Pushes a literal value with the source span of the token it came from.

Source

fn apply_op( &mut self, op_lookup: &OpLookup, name: &str, arity: usize, start: Span, end: Span, ) -> Result<()>

Applies a named operator or zero-arity identifier lookup, using op_lookup to resolve it against whatever this context currently holds.

§Errors

Returns Err if op_lookup cannot resolve name for arity operands.

Source

fn apply_member( &mut self, lookup: &OpLookup, name: &str, name_span: ExprSpan, explicit_args: Option<usize>, start: Span, end: Span, ) -> Result<()>

Applies a direct named operation to the receiver and explicit arguments in source order.

None preserves .name; Some(0) preserves .name(). Both consume one receiver. name_span identifies the member label for diagnostics; start/end cover the expression.

  • Precondition: the receiver and explicit_args.unwrap_or(0) arguments are emitted.
  • Complexity: O(n) for n operands, plus operation lookup in runtime contexts.
§Errors

Returns an error if a runtime context cannot resolve the operation.

§Examples
use cel_parser::{AstContext, ExprSpan, OpLookup};
use cel_parser::parser_context::ParserContext;
use proc_macro2::Span;
let mut context = AstContext::new_context();
let span = Span::call_site();
context.push_literal(1i32, span);
context.apply_member(&OpLookup::new(), "custom", ExprSpan { start: span, end: span },
    None, span, span).unwrap();
Source

fn make_record( &mut self, lookup: &OpLookup, name: &str, name_span: ExprSpan, fields: Vec<(String, ExprSpan)>, ambient_start: usize, start: Span, end: Span, ) -> Result<()>

Constructs a record from named fields emitted exactly once in source order.

  • Precondition: one value per field follows ambient_start in this context.
  • Complexity: O(f² + f * d + r) for f fields, descriptor depth d and r schemas.
§Errors

Runtime contexts reject unknown schemas, invalid field sets, mismatched types, or constructor emitter failures; syntax-only contexts preserve unresolved names.

§Examples

See OpLookup::construct_record.

Source

fn apply_logical( &mut self, name: &str, rhs: Self, start: Span, end: Span, ) -> Result<()>

Applies a short-circuiting logical operator ("||" or "&&"), consuming a leading condition value already present on self and folding in rhs, the already-parsed right-hand-side fragment.

  • Precondition: name is "||" or "&&", and rhs produces exactly one value.
§Errors

Implementations that validate operand types during parsing (e.g. DynSegmentContext) return Err if the leading condition value isn’t a bool. Implementations that defer type validation to a later phase (e.g. crate::ast::AstContext) never return Err here.

Source

fn join2( &mut self, then_fragment: Self, else_fragment: Option<Self>, start: Span, end: Span, ) -> Result<()>

Joins a previously-built fragment into self, consuming a leading condition value already present on self. then_fragment’s contribution is used when the condition is true; else_fragment’s when false, or None if the source had no else/else if at all. start/end cover the whole if/else construct.

  • Precondition: neither fragment takes arguments, and each produces exactly one value.
§Errors

Implementations that validate operand types during parsing (e.g. DynSegmentContext) return Err if the leading condition value isn’t a bool or if the fragments’ produced types don’t match — including when else_fragment is None, which such implementations treat as an implicit () fragment (so a non-() then-branch with no else is still an error). Implementations that defer type validation to a later phase (e.g. crate::ast::AstContext) never return Err here, and record whether else_fragment was None directly (see crate::Expr::If) instead of synthesizing anything.

Source

fn make_tuple( &mut self, n: usize, ambient_start: usize, start: Span, end: Span, ) -> Result<()>

Combines the last n emitted values into a single tuple value. start/end cover the whole (...) construct.

§Errors

Returns an error if the tuple’s frame or canonical layout cannot be represented.

Source

fn make_array( &mut self, n: usize, ambient_start: usize, start: Span, end: Span, ) -> Result<()>

Combines the last n emitted values into a single homogeneous array value. start/end cover the whole [...] construct, and ambient_start is the stack offset the first element was emitted at (as reported by Self::current_stack_offset before parsing it).

  • Precondition: n >= 1 and exactly n values have been emitted since ambient_start.
§Errors

Implementations that validate operand types during parsing (e.g. DynSegmentContext) return Err if the elements’ complete recursive runtime shapes differ, or if the array’s storage layout cannot be represented. Implementations that defer type validation to a later phase (e.g. crate::ast::AstContext) never return Err here.

Source

fn make_annotated_array( &mut self, n: usize, ambient_start: usize, annotation: AnnotatedArray<'_>, start: Span, end: Span, ) -> Result<()>

Combines the last n emitted values into a single array value, honoring annotation’s optional type ascription.

This is the method the grammar actually calls for every array literal; Self::make_array is the unannotated special case an implementation may delegate to. There is deliberately no default implementation: an annotation changes what the literal means ([]: [Celsius] is an empty array of a specific type), so an implementation that silently dropped it would misreport the literal’s type rather than fail to compile.

An implementation that needs runtime array metadata immediately (e.g. DynSegmentContext) calls AnnotatedArray::resolve_element_type; one that defers semantic checking (e.g. crate::ast::AstContext) records the syntax returned by AnnotatedArray::into_parts.

  • Precondition: exactly n values have been emitted since ambient_start.
§Errors

Returns Err under Self::make_array’s conditions, and additionally — for an implementation that resolves the annotation here — if the annotation names an unknown type, does not name a complete array type, or disagrees with the collected elements.

Source

fn peek_tuple_arity(&self) -> Option<usize>

Returns the arity of the tuple currently on top, or None if the top value isn’t a tuple.

Source

fn tuple_index(&mut self, index: usize, start: Span, end: Span) -> Result<()>

Replaces the tuple on top with its index-th element. start/end cover the base expression through the index token.

  • Precondition: peek_tuple_arity() returns Some(arity) with index < arity.
§Errors

Returns an error if the selected field’s transfer frame cannot be represented.

Source

fn current_stack_offset(&self) -> usize

Returns the current stack offset, used to compute tuple layouts.

Source

fn apply_cast( &mut self, op_lookup: &OpLookup, type_name: &str, start: Span, end: Span, ) -> Result<()>

Applies a cast (expr as Type), consuming the operand already present on self and replacing it with the converted value. type_name is the target type’s bare identifier text (e.g. "i32", "bool", "String"), unresolved by the grammar itself.

§Errors

Implementations that validate operand types during parsing (e.g. DynSegmentContext) return Err if type_name isn’t a recognized cast-target type, or if no conversion from the operand’s current type to it is registered. Implementations that defer type validation to a later phase (e.g. crate::ast::AstContext) never return Err here.

Provided Methods§

Source

fn resolves_closure_types() -> bool

Returns whether closure annotations must resolve while parsing rather than remain syntax.

§Examples
use cel_parser::{AstContext, parser_context::ParserContext};
assert!(!AstContext::resolves_closure_types());
Source

fn push_closure( &mut self, param_types: Vec<ValueType>, params: Vec<ClosureParam>, body: Self, span: Span, ) -> Result<()>

Packages a fully-parsed, independent nested context — the body of a closure literal — as a value pushed onto self, given the closure’s declared parameter types in two parallel forms: param_types (each parameter’s complete runtime shape, in order) for an implementation that executes, and params (each parameter’s name, span, and unresolved type expression) for one that builds an AST instead. An implementation uses whichever it needs and ignores the other.

The default implementation reports closures as unsupported, so a ParserContext implementation that has no use for them needs no changes to keep compiling.

  • Precondition: body was built via Self::new_context() and its own argument-binding mechanism, in the same style Self::new_context’s other consumers already use.
§Errors

Returns Err if this ParserContext implementation doesn’t support closures, or (for an implementation that validates during parsing) if body is otherwise unsuitable — e.g. DynSegmentContext rejects a body that doesn’t produce exactly one value.

Source

fn output_type_id(&self) -> Option<TypeId>

Returns the TypeId of the single value self currently holds, or None if that isn’t known/applicable for this ParserContext implementation.

Used by the closure-literal grammar production to infer a closure’s return type from its already-compiled body, mirroring Self::peek_tuple_arity’s “ask the context what it currently holds” shape, generalized from “is it a tuple” to “what type is it”.

The default implementation returns None, matching Self::push_closure’s default “unsupported” behavior — an implementation with no notion of a parse-time runtime type (e.g. an AST-building context) simply can’t answer this, which surfaces to the caller the same way an empty or multi-valued body does (a plain parse error), and in practice never matters for such an implementation anyway, since its push_closure override (if any) would reject the closure regardless.

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementors§