pub struct Parser<C: ParserContext> { /* private fields */ }Expand description
A recursive descent parser for expressions, generic over the ParserContext it emits
into.
CELParser is a type alias for Parser<DynSegmentContext> and remains the concrete type
most callers use; it behaves identically to how CELParser always has, before this type
became generic.
§Examples
§Basic Usage
use cel_parser::OpLookup;
use cel_parser::CELParser;
use proc_macro2::TokenStream;
use std::str::FromStr;
let input = TokenStream::from_str("10").unwrap();
let mut parser = CELParser::new(OpLookup::new());
let result = parser.parse_tokens(input.into_iter());
assert!(result.is_ok());§Error Formatting
use annotate_snippets::Renderer;
use cel_parser::OpLookup;
use cel_parser::CELParser;
use proc_macro2::TokenStream;
use std::str::FromStr;
let line = line!() + 1;
let source = r#"
10 + 20 30
"#; // Invalid: missing operator
let input = TokenStream::from_str(source).unwrap();
let mut parser = CELParser::new(OpLookup::new());
if let Err(e) = parser.parse_tokens(input.into_iter()) {
// Format error starting at line 1
println!("{}", e.format_rustc_style(source, file!(), line, &Renderer::plain()));
}Implementations§
Source§impl<C: ParserContext> Parser<C>
impl<C: ParserContext> Parser<C>
Sourcepub fn new(op_lookup: OpLookup) -> Self
pub fn new(op_lookup: OpLookup) -> Self
Creates a new CEL parser with the given operation lookup.
No tokens are set at construction; use set_tokens,
parse_tokens_ctx, or parse_str_ctx
to parse.
§Arguments
op_lookup- Operation lookup for resolving operators and identifiers
Sourcepub fn with_type_resolver<R>(op_lookup: OpLookup, type_resolver: R) -> Selfwhere
R: TypeResolver + 'static,
pub fn with_type_resolver<R>(op_lookup: OpLookup, type_resolver: R) -> Selfwhere
R: TypeResolver + 'static,
Creates a new CEL parser with the given operation lookup and leaf type resolver.
Existing callers that need only the built-in CEL scalar types should continue to use
new; this constructor is for hosts that want additional named CEL types
without coupling cel-parser to their own registry implementation.
§Examples
use cel_parser::{CELParser, OpLookup, ResolvedLeafType};
use cel_runtime::ValueType;
#[derive(Clone)]
struct Celsius(i32);
let resolver = [(
"Celsius",
ResolvedLeafType::new("Celsius", ValueType::leaf::<Celsius>()),
)];
let mut segment = CELParser::with_type_resolver(OpLookup::new(), resolver)
.parse_str("[]: [Celsius]")
.unwrap();
let array = segment.call0::<cel_runtime::OwnedValue>().unwrap().try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<Celsius>>>().unwrap();
assert!(array.into_vec().is_empty());Sourcepub fn set_type_resolver<R>(&mut self, type_resolver: R)where
R: TypeResolver + 'static,
pub fn set_type_resolver<R>(&mut self, type_resolver: R)where
R: TypeResolver + 'static,
Replaces this parser’s named-type resolver.
Every subsequent parse resolves annotation type names through type_resolver instead of
the one this parser was built with.
§Examples
use cel_parser::{CELParser, OpLookup, ResolvedLeafType};
use cel_runtime::ValueType;
#[derive(Clone)]
struct Celsius(i32);
let mut parser = CELParser::new(OpLookup::new());
assert!(parser.parse_str("[]: [Celsius]").is_err());
parser.set_type_resolver([(
"Celsius",
ResolvedLeafType::new("Celsius", ValueType::leaf::<Celsius>()),
)]);
assert!(parser.parse_str("[]: [Celsius]").is_ok());Sourcepub fn resolve_type_expr(&self, expr: &TypeExpr) -> Result<ResolvedType>
pub fn resolve_type_expr(&self, expr: &TypeExpr) -> Result<ResolvedType>
Resolves expr through this parser’s configured leaf type resolver.
§Errors
Returns Err if some named leaf in expr is not recognized.
Sourcepub fn set_tokens(&mut self, tokens: TokenStreamIter)
pub fn set_tokens(&mut self, tokens: TokenStreamIter)
Sets the token stream for parsing, resetting internal state.
Call before is_expression or use
parse_tokens_ctx which sets tokens and parses in one step.
Sourcepub fn set_lex_tokens(&mut self, tokens: Peekable<LexLexer>)
pub fn set_lex_tokens(&mut self, tokens: Peekable<LexLexer>)
Sets the token stream from an existing LexLexer iterator for inline expression parsing.
Resets the context. Use together with parse_expression_ctx
and take_lex_tokens to share a token stream between adam-lang and
CELParser.
Sourcepub fn unbalanced_delimiter_count(&self) -> i32
pub fn unbalanced_delimiter_count(&self) -> i32
Returns the net number of opening delimiters this parser has consumed since the last
set_tokens/set_lex_tokens call, that
remain unmatched by a corresponding closing delimiter.
Always 0 after a successful top-level parse: every delimiter this grammar opens (an
if-expression’s branch braces, a tuple/group literal’s or call’s parens), it also
closes. Positive after a parse that returned Err from partway through a production that
had already consumed one or more opening delimiters before failing — e.g. an
if-expression whose then-branch fails to parse consumes the branch’s opening { before
erroring out, never reaching the matching }.
An embedding caller that shares its own token stream with this parser (via
set_lex_tokens/take_lex_tokens), and
tracks its own nesting depth over that same stream, cannot otherwise tell a delimiter this
parser left dangling apart from one still genuinely open in the caller’s own grammar,
since both use the same Delimiter kinds. Reading this count immediately after reclaiming
the stream — regardless of whether the parse succeeded or failed — and folding it into the
caller’s own depth counter keeps that counter consistent with the physical nesting left
behind in the stream.
Sourcepub fn parse_expression_ctx(&mut self) -> Result<C>
pub fn parse_expression_ctx(&mut self) -> Result<C>
Parses one expression from the current token stream and returns the built context.
Unlike parse_str_ctx, this method does not require
end-of-stream, allowing adam-lang to parse an expression embedded within a larger token
stream.
§Errors
Returns an error if the input does not contain a valid expression.
- Complexity: O(n) in the number of tokens in the expression.
Sourcepub fn parse_expression_ctx_restricted(
&mut self,
restriction: ExpressionRestriction,
) -> Result<C>
pub fn parse_expression_ctx_restricted( &mut self, restriction: ExpressionRestriction, ) -> Result<C>
Parses one expression under restriction, restoring the previous mode on every result.
Does not require end-of-stream, so the enclosing grammar retains its body brace.
- Complexity: O(n) in the expression’s token count.
§Errors
Returns an error for a malformed expression or a context’s semantic rejection.
§Examples
Sourcepub fn parse_literal_pattern_ctx(&mut self) -> Result<C>
pub fn parse_literal_pattern_ctx(&mut self) -> Result<C>
Parses one literal_pattern from the current token stream and returns the built context.
Like parse_expression_ctx, this does not require
end-of-stream, letting a caller (e.g. adam-lang’s conditional_branch) parse just the
pattern before continuing with its own grammar.
§Errors
Returns an error if the input does not contain a valid literal_pattern.
Sourcepub fn take_lex_tokens(&mut self) -> Option<Peekable<LexLexer>>
pub fn take_lex_tokens(&mut self) -> Option<Peekable<LexLexer>>
Returns the remaining token stream after expression parsing.
Call after parse_expression_ctx to recover the
shared LexLexer for continued adam-lang parsing.
Sourcepub fn parse_tokens_ctx(&mut self, tokens: TokenStreamIter) -> Result<C>
pub fn parse_tokens_ctx(&mut self, tokens: TokenStreamIter) -> Result<C>
Parses a token stream into a context value.
Sets the token source, runs the expression grammar, and returns the context on success.
§Errors
Returns an error if the input does not contain a valid CEL expression.
Sourcepub fn parse_str_ctx(&mut self, s: &str) -> Result<C>
pub fn parse_str_ctx(&mut self, s: &str) -> Result<C>
Parses a string into a context value.
Tokenizes the string then parses; equivalent to
parse_tokens_ctx(TokenStream::from_str(s)?.into_iter()).
§Errors
Returns an error on lex failure or if the input does not contain a valid CEL expression.
Sourcepub fn parse_type_expr(&mut self) -> Result<TypeExpr>
pub fn parse_type_expr(&mut self) -> Result<TypeExpr>
Parses one complete type_expr from the current token stream.
Unlike parse_type_expr_str, this method does not require
ownership of the whole source string; it consumes only as many tokens as the type
expression itself needs from the current stream.
§Errors
Returns an error if the current token stream does not begin with a valid type expression.
Sourcepub fn parse_type_expr_tokens(
&mut self,
tokens: TokenStreamIter,
) -> Result<TypeExpr>
pub fn parse_type_expr_tokens( &mut self, tokens: TokenStreamIter, ) -> Result<TypeExpr>
Parses one complete type_expr from tokens.
§Errors
Returns an error if tokens does not contain a valid complete type expression.
Sourcepub fn parse_type_expr_str(&mut self, s: &str) -> Result<TypeExpr>
pub fn parse_type_expr_str(&mut self, s: &str) -> Result<TypeExpr>
Parses one complete type_expr from s.
§Errors
Returns an error on lex failure or if s does not contain a valid complete type
expression.
Sourcepub fn op_lookup_mut(&mut self) -> &mut OpLookup
pub fn op_lookup_mut(&mut self) -> &mut OpLookup
Returns a mutable reference to the operation lookup.
This allows customization of the operations available during parsing, such as adding new scopes for custom operations or identifiers.
§Examples
use cel_parser::op_table::OpLookup;
use cel_parser::CELParser;
use cel_runtime::DynSegment;
use proc_macro2::TokenStream;
use std::any::TypeId;
use std::str::FromStr;
let input = TokenStream::from_str("10 + 20").unwrap();
let mut lookup = OpLookup::new();
lookup.push_scope(|name, segment, num_operands, _span| {
let matches = {
let top = segment.peek_stack_infos(num_operands);
name == "+" && top.len() == 2 && top[0].value_type.type_id() == TypeId::of::<i32>()
};
if matches {
segment.op2(|a: i32, b: i32| a + b + 1)?; // Custom addition
Ok(true)
} else {
Ok(false)
}
});
let mut parser = CELParser::new(lookup);
parser.set_tokens(input.into_iter());Sourcepub fn is_expression(&mut self) -> Result<bool>
pub fn is_expression(&mut self) -> Result<bool>
expression = range_expression.
Sourcepub fn parse_type_expression(&mut self) -> Result<TypeExpr>
pub fn parse_type_expression(&mut self) -> Result<TypeExpr>
type_expression = identifier [ "(" [ type_expression { "," type_expression } ] ")" ] | "[" type_expression "]" | "(" [ type_expression ["," [ type_expression { "," type_expression } ]] ] ")" .
() is the empty tuple type (0 elements); (T) is grouping (same as bare T); (T,)
is a 1-element tuple; (T, U, ...) is n-element, no trailing comma. [T] names an
array type whose elements have type T. Name(A, B) applies zero or more type
arguments to a named (generic) type.
§Errors
Returns an error if a named leaf is missing, if an array, tuple, or type-argument list is
malformed, or if a closing ]/) is missing.
Source§impl Parser<DynSegmentContext>
impl Parser<DynSegmentContext>
Sourcepub fn parse_expression(&mut self) -> Result<DynSegment>
pub fn parse_expression(&mut self) -> Result<DynSegment>
Parses one expression from the current token stream and returns the segment.
Unlike parse_str, this method does not require end-of-stream,
allowing adam-lang to parse an expression embedded within a larger token stream.
§Errors
Returns an error if the input does not contain a valid expression.
- Complexity: O(n) in the number of tokens in the expression.
Sourcepub fn parse_expression_restricted(
&mut self,
restriction: ExpressionRestriction,
) -> Result<DynSegment>
pub fn parse_expression_restricted( &mut self, restriction: ExpressionRestriction, ) -> Result<DynSegment>
Sourcepub fn parse_literal_pattern(&mut self) -> Result<DynSegment>
pub fn parse_literal_pattern(&mut self) -> Result<DynSegment>
Sourcepub fn parse_tokens(&mut self, tokens: TokenStreamIter) -> Result<DynSegment>
pub fn parse_tokens(&mut self, tokens: TokenStreamIter) -> Result<DynSegment>
Parses a token stream into a [DynSegment].
Sets the token source, runs the expression grammar, and returns the segment on success.
§Errors
Returns an error if the input does not contain a valid CEL expression.
- Complexity: O(n) in the number of tokens.
Sourcepub fn parse_str(&mut self, s: &str) -> Result<DynSegment>
pub fn parse_str(&mut self, s: &str) -> Result<DynSegment>
Parses a string into a [DynSegment].
Tokenizes the string then parses; equivalent to
parse_tokens(TokenStream::from_str(s)?.into_iter()).
§Errors
Returns an error on lex failure or if the input does not contain a valid CEL expression.
- Complexity: O(n) in the length of
s.
Source§impl Parser<AstContext>
impl Parser<AstContext>
Sourcepub fn parse_expression_ast(&mut self) -> Result<Expr>
pub fn parse_expression_ast(&mut self) -> Result<Expr>
Parses one expression from the current token stream and returns the built Expr.
Unlike parse_str_ast, this method does not require
end-of-stream, allowing adam-lang to parse an expression embedded within a larger token
stream.
§Errors
Returns an error if the input does not contain a valid expression.
- Complexity: O(n) in the number of tokens in the expression.
Sourcepub fn parse_tokens_ast(&mut self, tokens: TokenStreamIter) -> Result<Expr>
pub fn parse_tokens_ast(&mut self, tokens: TokenStreamIter) -> Result<Expr>
Sourcepub fn parse_str_ast(&mut self, s: &str) -> Result<Expr>
pub fn parse_str_ast(&mut self, s: &str) -> Result<Expr>
Parses a string into an Expr tree.
Tokenizes the string then parses; equivalent to
parse_tokens_ast(TokenStream::from_str(s)?.into_iter()).
§Errors
Returns an error on lex failure or if the input does not contain a valid CEL expression.
- Complexity: O(n) in the length of
s.
§Examples
use cel_parser::{AstContext, Expr, OpLookup, Parser};
let mut parser = Parser::<AstContext>::new(OpLookup::new());
let expr = parser.parse_str_ast("1 + 2").unwrap();
assert!(matches!(expr, Expr::Op { .. }));