1pub mod ast;
318mod error;
319mod fmt;
320pub mod lex_lexer;
321pub mod op_table;
322pub mod registered_ops;
323pub use registered_ops::{
324 OperationEmitter, OperationSignature, RecordEmitter, RecordField, RecordSchema,
325};
326pub mod parser_context;
327pub mod trivia;
328pub mod ty;
329pub mod type_expr;
330
331pub use ast::{AstContext, ClosureParam, Expr, ExprSpan, Literal, LogicalOp, RecordInit};
332pub use error::{
333 CELError, FormatRustcStyle, ParseError, SourceSpan, SpanContext, SpanLabel, format_multi_span,
334};
335pub use fmt::{
336 format_expr, format_expr_header, format_expr_header_with_layout, format_expr_restricted,
337 format_expr_with_layout,
338};
339pub use op_table::{OpLookup, OperandTypes, builtin_operand_types};
340pub use parser_context::{DynSegmentContext, ParserContext};
341pub use proc_macro2::LineColumn;
342pub use trivia::Comment;
343pub use ty::Ty;
344pub use type_expr::{
345 ResolvedArrayType, ResolvedLeafType, ResolvedType, TypeExpr, TypeResolver,
346 builtin_type_resolver, resolve_builtin_named_type,
347};
348
349use lex_lexer::{LexLexer, Literal as CelLiteral, Token, TokenStreamIter};
350
351use cel_runtime::DynSegment;
352use proc_macro2::{Delimiter, Span, TokenStream};
353#[cfg(test)]
354use std::any::TypeId;
355use std::collections::HashMap;
356use std::iter::Peekable;
357use std::str::FromStr;
358
359pub type Result<T> = std::result::Result<T, ParseError>;
361
362fn push_literal_token<C: ParserContext>(output: &mut C, lit: CelLiteral) -> Result<()> {
369 match lit {
370 CelLiteral::Int(integer) => {
371 let span = integer.span();
372 match integer.suffix() {
373 "" | "i32" => output.push_literal(
374 integer.base10_parse::<i32>().map_err(|e| {
375 ParseError::new(
376 format!("invalid i32 literal `{integer}`: {e}"),
377 integer.span(),
378 )
379 })?,
380 span,
381 ),
382 "u8" => output.push_literal(
383 integer.base10_parse::<u8>().map_err(|e| {
384 ParseError::new(
385 format!("invalid u8 literal `{integer}`: {e}"),
386 integer.span(),
387 )
388 })?,
389 span,
390 ),
391 "u16" => output.push_literal(
392 integer.base10_parse::<u16>().map_err(|e| {
393 ParseError::new(
394 format!("invalid u16 literal `{integer}`: {e}"),
395 integer.span(),
396 )
397 })?,
398 span,
399 ),
400 "u32" => output.push_literal(
401 integer.base10_parse::<u32>().map_err(|e| {
402 ParseError::new(
403 format!("invalid u32 literal `{integer}`: {e}"),
404 integer.span(),
405 )
406 })?,
407 span,
408 ),
409 "u64" => output.push_literal(
410 integer.base10_parse::<u64>().map_err(|e| {
411 ParseError::new(
412 format!("invalid u64 literal `{integer}`: {e}"),
413 integer.span(),
414 )
415 })?,
416 span,
417 ),
418 "u128" => output.push_literal(
419 integer.base10_parse::<u128>().map_err(|e| {
420 ParseError::new(
421 format!("invalid u128 literal `{integer}`: {e}"),
422 integer.span(),
423 )
424 })?,
425 span,
426 ),
427 "usize" => output.push_literal(
428 integer.base10_parse::<usize>().map_err(|e| {
429 ParseError::new(
430 format!("invalid usize literal `{integer}`: {e}"),
431 integer.span(),
432 )
433 })?,
434 span,
435 ),
436 "i8" => output.push_literal(
437 integer.base10_parse::<i8>().map_err(|e| {
438 ParseError::new(
439 format!("invalid i8 literal `{integer}`: {e}"),
440 integer.span(),
441 )
442 })?,
443 span,
444 ),
445 "i16" => output.push_literal(
446 integer.base10_parse::<i16>().map_err(|e| {
447 ParseError::new(
448 format!("invalid i16 literal `{integer}`: {e}"),
449 integer.span(),
450 )
451 })?,
452 span,
453 ),
454 "i64" => output.push_literal(
455 integer.base10_parse::<i64>().map_err(|e| {
456 ParseError::new(
457 format!("invalid i64 literal `{integer}`: {e}"),
458 integer.span(),
459 )
460 })?,
461 span,
462 ),
463 "i128" => output.push_literal(
464 integer.base10_parse::<i128>().map_err(|e| {
465 ParseError::new(
466 format!("invalid i128 literal `{integer}`: {e}"),
467 integer.span(),
468 )
469 })?,
470 span,
471 ),
472 "isize" => output.push_literal(
473 integer.base10_parse::<isize>().map_err(|e| {
474 ParseError::new(
475 format!("invalid isize literal `{integer}`: {e}"),
476 integer.span(),
477 )
478 })?,
479 span,
480 ),
481 suffix => {
482 return Err(ParseError::new(
483 format!("invalid integer literal suffix: `{suffix}`"),
484 integer.span(),
485 ));
486 }
487 };
488 }
489 CelLiteral::Float(float) => {
490 let span = float.span();
491 match float.suffix() {
492 "" | "f64" => output.push_literal(
493 float.base10_parse::<f64>().map_err(|e| {
494 ParseError::new(format!("invalid f64 literal `{float}`: {e}"), float.span())
495 })?,
496 span,
497 ),
498 "f32" => output.push_literal(
499 float.base10_parse::<f32>().map_err(|e| {
500 ParseError::new(format!("invalid f32 literal `{float}`: {e}"), float.span())
501 })?,
502 span,
503 ),
504 suffix => {
505 return Err(ParseError::new(
506 format!("invalid float literal suffix: `{suffix}`"),
507 float.span(),
508 ));
509 }
510 };
511 }
512 CelLiteral::Str(string) => {
513 let span = string.span();
514 output.push_literal(string.value(), span);
515 }
516 CelLiteral::Bool(lit_bool) => {
517 let span = lit_bool.span();
518 output.push_literal(lit_bool.value, span);
519 }
520 CelLiteral::Char(ch) => {
521 let span = ch.span();
522 output.push_literal(ch.value(), span);
523 }
524 CelLiteral::Byte(byte) => {
525 let span = byte.span();
526 output.push_literal(byte.value(), span);
527 }
528 CelLiteral::ByteStr(byte_str) => {
529 let span = byte_str.span();
530 output.push_literal(byte_str.value(), span);
531 }
532 CelLiteral::CStr(c_str) => {
533 let span = c_str.span();
534 output.push_literal(c_str.value(), span);
535 }
536 other => {
537 return Err(ParseError::new(
538 format!("unsupported literal: {other:?}"),
539 other.span(),
540 ));
541 }
542 }
543 Ok(())
544}
545
546pub fn validate_literal(lit: &CelLiteral) -> Result<()> {
558 push_literal_token(&mut DynSegmentContext::new_context(), lit.clone())
559}
560
561fn closure_param_type_from_type_expr(
567 type_expr: &TypeExpr,
568 resolver: &dyn TypeResolver,
569) -> Result<cel_runtime::ValueType> {
570 type_expr
571 .resolve(resolver)?
572 .into_value_type()
573 .map_err(|error| {
574 let span = type_expr.span();
575 ParseError::new_range(error.to_string(), span.start, span.end)
576 })
577}
578
579pub struct Parser<C: ParserContext> {
624 tokens: Option<Peekable<LexLexer>>,
625 context: C,
626 op_lookup: OpLookup,
627 type_resolver: Box<dyn TypeResolver>,
628 last_span: Span,
629 unbalanced_delimiters: i32,
635 restriction: ExpressionRestriction,
636}
637
638#[derive(Clone, Copy, Debug, PartialEq, Eq)]
651pub enum ExpressionRestriction {
652 None,
654 NoStructLiteral,
656}
657
658pub type CELParser = Parser<DynSegmentContext>;
663
664impl<C: ParserContext> Parser<C> {
665 pub fn new(op_lookup: OpLookup) -> Self {
675 Self::with_boxed_type_resolver(op_lookup, type_expr::builtin_type_resolver())
676 }
677
678 pub fn with_type_resolver<R>(op_lookup: OpLookup, type_resolver: R) -> Self
704 where
705 R: TypeResolver + 'static,
706 {
707 Self::with_boxed_type_resolver(op_lookup, Box::new(type_resolver))
708 }
709
710 fn with_boxed_type_resolver(op_lookup: OpLookup, type_resolver: Box<dyn TypeResolver>) -> Self {
712 Parser {
713 tokens: None,
714 context: C::new_context(),
715 op_lookup,
716 type_resolver,
717 last_span: Span::call_site(),
718 unbalanced_delimiters: 0,
719 restriction: ExpressionRestriction::None,
720 }
721 }
722
723 pub fn set_type_resolver<R>(&mut self, type_resolver: R)
747 where
748 R: TypeResolver + 'static,
749 {
750 self.type_resolver = Box::new(type_resolver);
751 }
752
753 pub fn resolve_type_expr(&self, expr: &TypeExpr) -> Result<ResolvedType> {
759 expr.resolve(self.type_resolver.as_ref())
760 }
761
762 pub fn set_tokens(&mut self, tokens: TokenStreamIter) {
767 self.tokens = Some(LexLexer::new(tokens).peekable());
768 self.context = C::new_context();
769 self.last_span = Span::call_site();
770 self.unbalanced_delimiters = 0;
771 }
772
773 pub fn set_lex_tokens(&mut self, tokens: std::iter::Peekable<lex_lexer::LexLexer>) {
779 self.tokens = Some(tokens);
780 self.context = C::new_context();
781 self.last_span = Span::call_site();
782 self.unbalanced_delimiters = 0;
783 }
784
785 pub fn unbalanced_delimiter_count(&self) -> i32 {
805 self.unbalanced_delimiters
806 }
807
808 pub fn parse_expression_ctx(&mut self) -> Result<C> {
820 self.parse_expression_ctx_restricted(ExpressionRestriction::None)
821 }
822
823 pub fn parse_expression_ctx_restricted(
835 &mut self,
836 restriction: ExpressionRestriction,
837 ) -> Result<C> {
838 if !self.with_restriction(restriction, |p| p.is_expression())? {
839 return Err(self.error_at("expression expected"));
840 }
841 Ok(std::mem::replace(&mut self.context, C::new_context()))
842 }
843
844 fn with_restriction<T>(
848 &mut self,
849 restriction: ExpressionRestriction,
850 parse: impl FnOnce(&mut Self) -> Result<T>,
851 ) -> Result<T> {
852 let previous = std::mem::replace(&mut self.restriction, restriction);
853 let result = parse(self);
854 self.restriction = previous;
855 result
856 }
857
858 fn is_ordinary_expression(&mut self) -> Result<bool> {
864 self.with_restriction(ExpressionRestriction::None, |p| p.is_expression())
865 }
866
867 pub fn parse_literal_pattern_ctx(&mut self) -> Result<C> {
877 if !self.is_literal_pattern()? {
878 return Err(self.error_at("literal pattern expected"));
879 }
880 Ok(std::mem::replace(&mut self.context, C::new_context()))
881 }
882
883 pub(crate) fn parse_nested_context<F>(&mut self, f: F) -> Result<C>
898 where
899 F: FnOnce(&mut Self) -> Result<bool>,
900 {
901 let outer = std::mem::replace(&mut self.context, C::new_context());
902 let outcome = f(self);
903 let nested = std::mem::replace(&mut self.context, outer);
904 match outcome {
905 Ok(true) => Ok(nested),
906 Ok(false) => Err(self.error_at("expected expression")),
907 Err(e) => Err(e),
908 }
909 }
910
911 pub fn take_lex_tokens(&mut self) -> Option<std::iter::Peekable<lex_lexer::LexLexer>> {
916 self.tokens.take()
917 }
918
919 pub fn parse_tokens_ctx(&mut self, tokens: TokenStreamIter) -> Result<C> {
927 self.set_tokens(tokens);
928 if !self.is_expression()? {
929 return Err(self.error_at("expression expected"));
930 }
931 if self.peek_token().is_some() {
932 return Err(self.error_at("unexpected token"));
933 }
934 Ok(std::mem::replace(&mut self.context, C::new_context()))
935 }
936
937 pub fn parse_str_ctx(&mut self, s: &str) -> Result<C> {
946 let input = TokenStream::from_str(s).map_err(|e| ParseError::from_lex_error(s, e))?;
947 self.parse_tokens_ctx(input.into_iter())
948 }
949
950 pub fn parse_type_expr(&mut self) -> Result<TypeExpr> {
960 self.parse_type_expression()
961 }
962
963 pub fn parse_type_expr_tokens(&mut self, tokens: TokenStreamIter) -> Result<TypeExpr> {
969 self.set_tokens(tokens);
970 let expr = self.parse_type_expr()?;
971 if self.peek_token().is_some() {
972 return Err(self.error_at("unexpected token"));
973 }
974 Ok(expr)
975 }
976
977 pub fn parse_type_expr_str(&mut self, s: &str) -> Result<TypeExpr> {
984 let input = TokenStream::from_str(s).map_err(|e| ParseError::from_lex_error(s, e))?;
985 self.parse_type_expr_tokens(input.into_iter())
986 }
987
988 pub fn op_lookup_mut(&mut self) -> &mut OpLookup {
1021 &mut self.op_lookup
1022 }
1023
1024 fn advance(&mut self) {
1036 use lex_lexer::HasSpan;
1037 let token = self
1038 .tokens
1039 .as_mut()
1040 .expect("tokens set")
1041 .next()
1042 .expect("token required to advance");
1043 match &token {
1044 Token::OpenDelim {
1045 delimiter: Delimiter::Brace | Delimiter::Bracket | Delimiter::Parenthesis,
1046 ..
1047 } => self.unbalanced_delimiters += 1,
1048 Token::CloseDelim {
1049 delimiter: Delimiter::Brace | Delimiter::Bracket | Delimiter::Parenthesis,
1050 ..
1051 } => self.unbalanced_delimiters -= 1,
1052 _ => {}
1053 }
1054 self.last_span = token.span();
1055 }
1056
1057 fn peek_span(&mut self) -> Option<Span> {
1059 self.peek_token().map(|token| {
1060 use lex_lexer::HasSpan;
1061 token.span()
1062 })
1063 }
1064
1065 fn peek_token(&mut self) -> Option<&Token> {
1069 self.tokens.as_mut().expect("tokens set").peek()
1070 }
1071
1072 fn error_at(&mut self, message: &str) -> ParseError {
1074 let span = match self.peek_token() {
1075 Some(token) => {
1076 use lex_lexer::HasSpan;
1077 token.span()
1078 }
1079 None => Span::call_site(),
1080 };
1081 ParseError::new(message, span)
1082 }
1083
1084 fn is_punctuation(&mut self, target: &str) -> bool {
1086 match self.peek_token() {
1087 Some(Token::Punct { op, .. }) if op == target => {
1088 self.advance();
1089 true
1090 }
1091 _ => false,
1092 }
1093 }
1094
1095 fn is_keyword(&mut self, keyword: &str) -> bool {
1097 match self.peek_token() {
1098 Some(Token::Identifier(ident)) if ident == keyword => {
1099 self.advance();
1100 true
1101 }
1102 _ => false,
1103 }
1104 }
1105
1106 fn expect_identifier(&mut self, message: &str) -> Result<String> {
1112 match self.peek_token() {
1113 Some(Token::Identifier(ident)) => {
1114 let name = ident.to_string();
1115 self.advance();
1116 Ok(name)
1117 }
1118 _ => Err(self.error_at(message)),
1119 }
1120 }
1121
1122 fn is_open_paren(&mut self) -> bool {
1124 if matches!(
1125 self.peek_token(),
1126 Some(Token::OpenDelim {
1127 delimiter: Delimiter::Parenthesis,
1128 ..
1129 })
1130 ) {
1131 self.advance();
1132 true
1133 } else {
1134 false
1135 }
1136 }
1137
1138 fn is_close_paren(&mut self) -> bool {
1140 if matches!(
1141 self.peek_token(),
1142 Some(Token::CloseDelim {
1143 delimiter: Delimiter::Parenthesis,
1144 ..
1145 })
1146 ) {
1147 self.advance();
1148 true
1149 } else {
1150 false
1151 }
1152 }
1153
1154 fn is_close_bracket(&mut self) -> bool {
1156 if matches!(
1157 self.peek_token(),
1158 Some(Token::CloseDelim {
1159 delimiter: Delimiter::Bracket,
1160 ..
1161 })
1162 ) {
1163 self.advance();
1164 true
1165 } else {
1166 false
1167 }
1168 }
1169
1170 pub fn is_expression(&mut self) -> Result<bool> {
1172 self.is_range_expression()
1173 }
1174
1175 fn is_or_expression(&mut self) -> Result<bool> {
1182 let start_span = self.peek_span();
1183 if self.is_and_expression()? {
1184 while self.is_punctuation("||") {
1185 let mut rhs_fragment = self.context.new_fragment();
1186 std::mem::swap(&mut self.context, &mut rhs_fragment);
1187 if !self.is_and_expression()? {
1188 return Err(self.error_at("expected and_expression"));
1189 }
1190 std::mem::swap(&mut self.context, &mut rhs_fragment);
1191 self.context.apply_logical(
1192 "||",
1193 rhs_fragment,
1194 start_span.expect("production has token at start"),
1195 self.last_span,
1196 )?;
1197 }
1198 Ok(true)
1199 } else {
1200 Ok(false)
1201 }
1202 }
1203
1204 fn is_and_expression(&mut self) -> Result<bool> {
1211 let start_span = self.peek_span();
1212 if self.is_comparison_expression()? {
1213 while self.is_punctuation("&&") {
1214 let mut rhs_fragment = self.context.new_fragment();
1215 std::mem::swap(&mut self.context, &mut rhs_fragment);
1216 if !self.is_comparison_expression()? {
1217 return Err(self.error_at("expected comparison_expression"));
1218 }
1219 std::mem::swap(&mut self.context, &mut rhs_fragment);
1220 self.context.apply_logical(
1221 "&&",
1222 rhs_fragment,
1223 start_span.expect("production has token at start"),
1224 self.last_span,
1225 )?;
1226 }
1227 Ok(true)
1228 } else {
1229 Ok(false)
1230 }
1231 }
1232
1233 fn is_comparison_expression(&mut self) -> Result<bool> {
1236 let start_span = self.peek_span();
1237 if self.is_bitwise_or_expression()? {
1238 let op_name = if self.is_punctuation("==") {
1240 Some("==")
1241 } else if self.is_punctuation("!=") {
1242 Some("!=")
1243 } else if self.is_punctuation("<=") {
1244 Some("<=")
1245 } else if self.is_punctuation(">=") {
1246 Some(">=")
1247 } else if self.is_punctuation("<") {
1248 Some("<")
1249 } else if self.is_punctuation(">") {
1250 Some(">")
1251 } else {
1252 None
1253 };
1254
1255 if let Some(op_name) = op_name {
1256 if !self.is_bitwise_or_expression()? {
1257 return Err(self.error_at("expected bitwise_or_expression"));
1258 }
1259 self.context.apply_op(
1260 &self.op_lookup,
1261 op_name,
1262 2,
1263 start_span.expect("production has token at start"),
1264 self.last_span,
1265 )?;
1266 }
1267 Ok(true)
1268 } else {
1269 Ok(false)
1270 }
1271 }
1272
1273 fn is_range_expression(&mut self) -> Result<bool> {
1297 let start_span = self.peek_span();
1298
1299 if self.is_punctuation("..=") {
1300 if !self.is_or_expression()? {
1301 return Err(self.error_at("expected or_expression"));
1302 }
1303 self.context.apply_op(
1304 &self.op_lookup,
1305 "range_to_inclusive",
1306 1,
1307 start_span.expect("production has token at start"),
1308 self.last_span,
1309 )?;
1310 return Ok(true);
1311 }
1312
1313 if self.is_punctuation("..") {
1314 if self.is_or_expression()? {
1315 self.context.apply_op(
1316 &self.op_lookup,
1317 "range_to",
1318 1,
1319 start_span.expect("production has token at start"),
1320 self.last_span,
1321 )?;
1322 } else {
1323 self.context.apply_op(
1324 &self.op_lookup,
1325 "range_full",
1326 0,
1327 start_span.expect("production has token at start"),
1328 self.last_span,
1329 )?;
1330 }
1331 return Ok(true);
1332 }
1333
1334 if self.is_or_expression()? {
1335 if self.is_punctuation("..=") {
1336 if !self.is_or_expression()? {
1337 return Err(self.error_at("expected or_expression"));
1338 }
1339 self.context.apply_op(
1340 &self.op_lookup,
1341 "range_inclusive",
1342 2,
1343 start_span.expect("production has token at start"),
1344 self.last_span,
1345 )?;
1346 } else if self.is_punctuation("..") {
1347 if self.is_or_expression()? {
1348 self.context.apply_op(
1349 &self.op_lookup,
1350 "range",
1351 2,
1352 start_span.expect("production has token at start"),
1353 self.last_span,
1354 )?;
1355 } else {
1356 self.context.apply_op(
1357 &self.op_lookup,
1358 "range_from",
1359 1,
1360 start_span.expect("production has token at start"),
1361 self.last_span,
1362 )?;
1363 }
1364 }
1365 Ok(true)
1366 } else {
1367 Ok(false)
1368 }
1369 }
1370
1371 fn is_bitwise_or_expression(&mut self) -> Result<bool> {
1373 let start_span = self.peek_span();
1374 if self.is_bitwise_xor_expression()? {
1375 while self.is_punctuation("|") {
1376 if !self.is_bitwise_xor_expression()? {
1377 return Err(self.error_at("expected bitwise_xor_expression"));
1378 }
1379 self.context.apply_op(
1380 &self.op_lookup,
1381 "|",
1382 2,
1383 start_span.expect("production has token at start"),
1384 self.last_span,
1385 )?;
1386 }
1387 Ok(true)
1388 } else {
1389 Ok(false)
1390 }
1391 }
1392
1393 fn is_bitwise_xor_expression(&mut self) -> Result<bool> {
1395 let start_span = self.peek_span();
1396 if self.is_bitwise_and_expression()? {
1397 while self.is_punctuation("^") {
1398 if !self.is_bitwise_and_expression()? {
1399 return Err(self.error_at("expected bitwise_and_expression"));
1400 }
1401 self.context.apply_op(
1402 &self.op_lookup,
1403 "^",
1404 2,
1405 start_span.expect("production has token at start"),
1406 self.last_span,
1407 )?;
1408 }
1409 Ok(true)
1410 } else {
1411 Ok(false)
1412 }
1413 }
1414
1415 fn is_bitwise_and_expression(&mut self) -> Result<bool> {
1417 let start_span = self.peek_span();
1418 if self.is_bitwise_shift_expression()? {
1419 while self.is_punctuation("&") {
1420 if !self.is_bitwise_shift_expression()? {
1421 return Err(self.error_at("expected bitwise_shift_expression"));
1422 }
1423 self.context.apply_op(
1424 &self.op_lookup,
1425 "&",
1426 2,
1427 start_span.expect("production has token at start"),
1428 self.last_span,
1429 )?;
1430 }
1431 Ok(true)
1432 } else {
1433 Ok(false)
1434 }
1435 }
1436
1437 fn is_bitwise_shift_expression(&mut self) -> Result<bool> {
1439 let start_span = self.peek_span();
1440 if self.is_additive_expression()? {
1441 loop {
1442 let op_name = if self.is_punctuation("<<") {
1443 Some("<<")
1444 } else if self.is_punctuation(">>") {
1445 Some(">>")
1446 } else {
1447 None
1448 };
1449
1450 if let Some(op_name) = op_name {
1451 if !self.is_additive_expression()? {
1452 return Err(self.error_at("expected additive_expression"));
1453 }
1454 self.context.apply_op(
1455 &self.op_lookup,
1456 op_name,
1457 2,
1458 start_span.expect("production has token at start"),
1459 self.last_span,
1460 )?;
1461 } else {
1462 break;
1463 }
1464 }
1465 Ok(true)
1466 } else {
1467 Ok(false)
1468 }
1469 }
1470
1471 fn is_additive_expression(&mut self) -> Result<bool> {
1473 let start_span = self.peek_span();
1474 if self.is_multiplicative_expression()? {
1475 loop {
1476 let op_name = if self.is_punctuation("+") {
1477 Some("+")
1478 } else if self.is_punctuation("-") {
1479 Some("-")
1480 } else {
1481 None
1482 };
1483
1484 if let Some(op_name) = op_name {
1485 if !self.is_multiplicative_expression()? {
1486 return Err(self.error_at("expected multiplicative_expression"));
1487 }
1488 self.context.apply_op(
1489 &self.op_lookup,
1490 op_name,
1491 2,
1492 start_span.expect("production has token at start"),
1493 self.last_span,
1494 )?;
1495 } else {
1496 break;
1497 }
1498 }
1499 Ok(true)
1500 } else {
1501 Ok(false)
1502 }
1503 }
1504
1505 fn is_multiplicative_expression(&mut self) -> Result<bool> {
1507 let start_span = self.peek_span();
1508 if self.is_cast_expression()? {
1509 loop {
1510 let op_name = if self.is_punctuation("*") {
1511 Some("*")
1512 } else if self.is_punctuation("/") {
1513 Some("/")
1514 } else if self.is_punctuation("%") {
1515 Some("%")
1516 } else {
1517 None
1518 };
1519
1520 if let Some(op_name) = op_name {
1521 if !self.is_cast_expression()? {
1522 return Err(self.error_at("expected cast_expression"));
1523 }
1524 self.context.apply_op(
1525 &self.op_lookup,
1526 op_name,
1527 2,
1528 start_span.expect("production has token at start"),
1529 self.last_span,
1530 )?;
1531 } else {
1532 break;
1533 }
1534 }
1535 Ok(true)
1536 } else {
1537 Ok(false)
1538 }
1539 }
1540
1541 fn is_cast_expression(&mut self) -> Result<bool> {
1551 let start_span = self.peek_span();
1552 if self.is_unary_expression()? {
1553 while self.is_keyword("as") {
1554 let type_name = match self.peek_token() {
1555 Some(Token::Identifier(ident)) => ident.to_string(),
1556 _ => return Err(self.error_at("expected type name after `as`")),
1557 };
1558 self.advance();
1559 self.context.apply_cast(
1560 &self.op_lookup,
1561 &type_name,
1562 start_span.expect("production has token at start"),
1563 self.last_span,
1564 )?;
1565 }
1566 Ok(true)
1567 } else {
1568 Ok(false)
1569 }
1570 }
1571
1572 fn is_unary_expression(&mut self) -> Result<bool> {
1574 let start_span = self.peek_span();
1575 let op_name = if self.is_punctuation("-") {
1576 Some("-")
1577 } else if self.is_punctuation("!") {
1578 Some("!")
1579 } else {
1580 None
1581 };
1582
1583 if let Some(op_name) = op_name {
1584 if !self.is_unary_expression()? {
1585 return Err(self.error_at("expected unary_expression"));
1586 }
1587 self.context.apply_op(
1588 &self.op_lookup,
1589 op_name,
1590 1,
1591 start_span.expect("production has token at start"),
1592 self.last_span,
1593 )?;
1594 Ok(true)
1595 } else {
1596 self.is_postfix_expression()
1597 }
1598 }
1599
1600 fn is_literal_pattern(&mut self) -> Result<bool> {
1612 let start_span = self.peek_span();
1613 let negated = self.is_punctuation("-");
1614 match self.peek_token() {
1615 Some(Token::Literal(lit)) => {
1616 let lit_clone = lit.clone();
1617 self.advance();
1618 push_literal_token(&mut self.context, lit_clone)?;
1619 if negated {
1620 self.context.apply_op(
1621 &self.op_lookup,
1622 "-",
1623 1,
1624 start_span.expect("production has token at start"),
1625 self.last_span,
1626 )?;
1627 }
1628 Ok(true)
1629 }
1630 _ if negated => Err(self.error_at("expected literal after `-`")),
1631 _ => Ok(false),
1632 }
1633 }
1634
1635 fn is_postfix_expression(&mut self) -> Result<bool> {
1646 let start_span = self.peek_span();
1647 if !self.is_primary_expression()? {
1648 return Ok(false);
1649 }
1650 loop {
1651 if let Some(arg_count) = self.postfix_arguments()? {
1652 self.context.apply_op(
1654 &self.op_lookup,
1655 "()",
1656 arg_count + 1,
1657 start_span.expect("production has token at start"),
1658 self.last_span,
1659 )?;
1660 } else if self.is_punctuation(".") {
1661 match self.peek_token() {
1662 Some(Token::Identifier(_)) => {
1663 let name_start = self.peek_span().expect("member has a name token");
1664 let name = self.expect_identifier("expected member name")?;
1665 let name_span = ExprSpan {
1666 start: name_start,
1667 end: name_start,
1668 };
1669 let explicit_args = self.postfix_arguments()?;
1670 self.context.apply_member(
1671 &self.op_lookup,
1672 &name,
1673 name_span,
1674 explicit_args,
1675 start_span.expect("production has token at start"),
1676 self.last_span,
1677 )?;
1678 }
1679 Some(Token::Literal(CelLiteral::Int(integer))) => {
1680 let integer = integer.clone();
1681 if !integer.suffix().is_empty() {
1682 return Err(self.error_at("tuple index must be an unsuffixed integer"));
1683 }
1684 self.advance();
1685 let index = integer.base10_parse::<usize>().map_err(|e| {
1686 self.error_at(&format!("invalid tuple index `{integer}`: {e}"))
1687 })?;
1688 self.apply_tuple_index(
1689 index,
1690 start_span.expect("production has token at start"),
1691 )?;
1692 }
1693 Some(Token::Literal(CelLiteral::Float(float))) => {
1694 let float = float.clone();
1695 if !float.suffix().is_empty() {
1696 return Err(self.error_at("tuple index must be an unsuffixed integer"));
1697 }
1698 let digits = float.base10_digits();
1707 let Some((first, second)) = digits.split_once('.') else {
1708 return Err(self.error_at(
1709 "tuple index chain must use decimal notation (e.g. `.0.1`)",
1710 ));
1711 };
1712 self.advance();
1713 let first_index = first.parse::<usize>().map_err(|e| {
1714 self.error_at(&format!("invalid tuple index `{first}`: {e}"))
1715 })?;
1716 let second_index = second.parse::<usize>().map_err(|e| {
1717 self.error_at(&format!("invalid tuple index `{second}`: {e}"))
1718 })?;
1719 let idx_start = start_span.expect("production has token at start");
1720 self.apply_tuple_index(first_index, idx_start)?;
1721 self.apply_tuple_index(second_index, idx_start)?;
1722 }
1723 _ => return Err(self.error_at("expected integer or member name after '.'")),
1724 }
1725 } else {
1726 break;
1727 }
1728 }
1729 Ok(true)
1730 }
1731
1732 fn postfix_arguments(&mut self) -> Result<Option<usize>> {
1741 if !self.is_open_paren() {
1742 return Ok(None);
1743 }
1744 if self.is_close_paren() {
1745 return Ok(Some(0));
1746 }
1747 let count = self.parameter_list()?;
1748 if !self.is_close_paren() {
1749 return Err(self.error_at("expected closing parenthesis"));
1750 }
1751 Ok(Some(count))
1752 }
1753
1754 fn apply_tuple_index(&mut self, index: usize, start: Span) -> Result<()> {
1762 let arity = self
1763 .context
1764 .peek_tuple_arity()
1765 .ok_or_else(|| self.error_at("'.N' requires a tuple"))?;
1766 if index >= arity {
1767 return Err(self.error_at(&format!(
1768 "tuple index `{index}` out of range for tuple of arity {arity}"
1769 )));
1770 }
1771 self.context.tuple_index(index, start, self.last_span)?;
1772 Ok(())
1773 }
1774
1775 fn parameter_list(&mut self) -> Result<usize> {
1787 if !self.is_ordinary_expression()? {
1788 return Err(self.error_at("expected expression"));
1789 }
1790 let mut count = 1;
1791 while self.is_punctuation(",") {
1792 if !self.is_ordinary_expression()? {
1793 return Err(self.error_at("expected expression after comma"));
1794 }
1795 count += 1;
1796 }
1797 Ok(count)
1798 }
1799
1800 fn is_primary_expression(&mut self) -> Result<bool> {
1823 if self.is_punctuation("||") {
1824 return self.is_closure_expression(true);
1825 }
1826 if self.is_punctuation("|") {
1827 return self.is_closure_expression(false);
1828 }
1829 match self.peek_token() {
1830 Some(Token::Literal(lit)) => {
1831 let lit_clone = lit.clone();
1832 self.advance();
1833 push_literal_token(&mut self.context, lit_clone)?;
1834 Ok(true)
1835 }
1836 Some(Token::Identifier(ident)) => {
1837 let ident_name = ident.to_string();
1838 let ident_span = ident.span();
1839 self.advance();
1840
1841 if ident_name == "if" {
1842 return self.is_if_expression(ident_span);
1843 }
1844
1845 if self.restriction == ExpressionRestriction::None
1846 && matches!(
1847 self.peek_token(),
1848 Some(Token::OpenDelim {
1849 delimiter: Delimiter::Brace,
1850 ..
1851 })
1852 )
1853 {
1854 return self.is_record_fields(&ident_name, ident_span);
1855 }
1856
1857 self.context
1858 .apply_op(&self.op_lookup, &ident_name, 0, ident_span, ident_span)?;
1859
1860 Ok(true)
1861 }
1862 Some(Token::OpenDelim {
1863 delimiter: Delimiter::Parenthesis,
1864 ..
1865 }) => self.is_tuple_or_group(),
1866 Some(Token::OpenDelim {
1867 delimiter: Delimiter::Bracket,
1868 ..
1869 }) => self.is_array_expression(),
1870 _ => Ok(false),
1871 }
1872 }
1873
1874 fn is_record_fields(&mut self, name: &str, name_token: Span) -> Result<bool> {
1883 self.advance();
1884 let ambient_start = self.context.current_stack_offset();
1885 let mut fields = Vec::new();
1886 loop {
1887 if matches!(
1888 self.peek_token(),
1889 Some(Token::CloseDelim {
1890 delimiter: Delimiter::Brace,
1891 ..
1892 })
1893 ) {
1894 self.advance();
1895 break;
1896 }
1897 let Some(Token::Identifier(field)) = self.peek_token() else {
1898 return Err(self.error_at("expected record field name"));
1899 };
1900 let field_name = field.to_string();
1901 let field_span = field.span();
1902 self.advance();
1903 if !self.is_punctuation(":") {
1904 return Err(self.error_at("expected `:` after record field name"));
1905 }
1906 if !self.is_ordinary_expression()? {
1907 return Err(self.error_at("expected record field expression"));
1908 }
1909 fields.push((
1910 field_name,
1911 ExprSpan {
1912 start: field_span,
1913 end: field_span,
1914 },
1915 ));
1916 if matches!(
1917 self.peek_token(),
1918 Some(Token::CloseDelim {
1919 delimiter: Delimiter::Brace,
1920 ..
1921 })
1922 ) {
1923 self.advance();
1924 break;
1925 }
1926 if !self.is_punctuation(",") {
1927 return Err(self.error_at("expected `,` or `}` after record field"));
1928 }
1929 }
1930 self.context.make_record(
1931 &self.op_lookup,
1932 name,
1933 ExprSpan {
1934 start: name_token,
1935 end: name_token,
1936 },
1937 fields,
1938 ambient_start,
1939 name_token,
1940 self.last_span,
1941 )?;
1942 Ok(true)
1943 }
1944
1945 fn is_tuple_or_group(&mut self) -> Result<bool> {
1957 let open_span = self
1958 .peek_span()
1959 .expect("tuple_or_group requires an opening '(' token");
1960 self.advance();
1961 if matches!(
1963 self.peek_token(),
1964 Some(Token::CloseDelim {
1965 delimiter: Delimiter::Parenthesis,
1966 ..
1967 })
1968 ) {
1969 self.advance();
1970 self.context.make_tuple(
1971 0,
1972 self.context.current_stack_offset(),
1973 open_span,
1974 self.last_span,
1975 )?;
1976 return Ok(true);
1977 }
1978 let ambient_start = self.context.current_stack_offset();
1979 if !self.is_ordinary_expression()? {
1980 return Err(self.error_at("expected expression"));
1981 }
1982 if matches!(
1983 self.peek_token(),
1984 Some(Token::CloseDelim {
1985 delimiter: Delimiter::Parenthesis,
1986 ..
1987 })
1988 ) {
1989 self.advance();
1991 return Ok(true);
1992 }
1993 if !self.is_punctuation(",") {
1994 return Err(self.error_at("expected ',' or closing parenthesis"));
1995 }
1996 let mut count = 1;
1997 if matches!(
1998 self.peek_token(),
1999 Some(Token::CloseDelim {
2000 delimiter: Delimiter::Parenthesis,
2001 ..
2002 })
2003 ) {
2004 self.advance();
2006 self.context
2007 .make_tuple(count, ambient_start, open_span, self.last_span)?;
2008 return Ok(true);
2009 }
2010 loop {
2011 if !self.is_ordinary_expression()? {
2012 return Err(self.error_at("expected expression after ','"));
2013 }
2014 count += 1;
2015 if matches!(
2016 self.peek_token(),
2017 Some(Token::CloseDelim {
2018 delimiter: Delimiter::Parenthesis,
2019 ..
2020 })
2021 ) {
2022 self.advance();
2023 break;
2024 }
2025 if !self.is_punctuation(",") {
2026 return Err(self.error_at("expected ',' or closing parenthesis"));
2027 }
2028 }
2029 self.context
2030 .make_tuple(count, ambient_start, open_span, self.last_span)?;
2031 Ok(true)
2032 }
2033
2034 fn is_array_expression(&mut self) -> Result<bool> {
2053 let open_span = self
2054 .peek_span()
2055 .expect("array_expression requires an opening '[' token");
2056 self.advance();
2057 let ambient_start = self.context.current_stack_offset();
2058 let mut count = 0usize;
2059 if !self.is_close_bracket() {
2060 if !self.is_ordinary_expression()? {
2061 return Err(self.error_at("expected expression"));
2062 }
2063 count = 1;
2064 loop {
2065 if self.is_close_bracket() {
2066 break;
2067 }
2068 if !self.is_punctuation(",") {
2069 return Err(self.error_at("expected ',' or closing ']'"));
2070 }
2071 if !self.is_ordinary_expression()? {
2074 return Err(self.error_at("expected expression after ','"));
2075 }
2076 count += 1;
2077 }
2078 }
2079
2080 let mut type_annotation = None;
2081 let mut annotation_span = None;
2082 if self.is_punctuation(":") {
2083 let colon_span = self.last_span;
2084 let annotation = self.parse_type_expression()?;
2085 let annotation_end = annotation.span().end;
2086 annotation_span = Some(ExprSpan {
2087 start: colon_span,
2088 end: annotation_end,
2089 });
2090 type_annotation = Some(annotation);
2091 }
2092
2093 if count == 0 && type_annotation.is_none() {
2094 return Err(ParseError::new_range(
2095 "an empty array literal has no inferable element type; \
2096 see https://github.com/stlab/cel-rs/issues/212"
2097 .to_string(),
2098 open_span,
2099 self.last_span,
2100 ));
2101 }
2102
2103 let type_resolver = self.type_resolver.as_ref();
2104 let mut resolve_array_type = |type_expr: &TypeExpr| {
2105 let resolved = type_expr.resolve(type_resolver)?;
2106 ResolvedArrayType::from_resolved_type(resolved, type_expr.span())
2107 };
2108 self.context.make_annotated_array(
2109 count,
2110 ambient_start,
2111 parser_context::AnnotatedArray::new(
2112 &mut resolve_array_type,
2113 type_annotation,
2114 annotation_span,
2115 ),
2116 open_span,
2117 self.last_span,
2118 )?;
2119 Ok(true)
2120 }
2121
2122 pub fn parse_type_expression(&mut self) -> Result<TypeExpr> {
2136 if let Some(Token::Identifier(_)) = self.peek_token() {
2137 let name = self.expect_identifier("expected a type name")?;
2138 let name_span = self.last_span;
2139 let mut args = Vec::new();
2140 let mut end_span = name_span;
2141 if self.is_open_paren() {
2142 if !self.is_close_paren() {
2143 args.push(self.parse_type_expression()?);
2144 while self.is_punctuation(",") {
2145 args.push(self.parse_type_expression()?);
2146 }
2147 if !self.is_close_paren() {
2148 return Err(
2149 self.error_at("expected ',' or closing ')' in type argument list")
2150 );
2151 }
2152 }
2153 end_span = self.last_span;
2154 }
2155 return Ok(TypeExpr::Named {
2156 name,
2157 args,
2158 span: ExprSpan {
2159 start: name_span,
2160 end: end_span,
2161 },
2162 });
2163 }
2164
2165 if matches!(
2166 self.peek_token(),
2167 Some(Token::OpenDelim {
2168 delimiter: Delimiter::Bracket,
2169 ..
2170 })
2171 ) {
2172 let open_span = self
2173 .peek_span()
2174 .expect("array type expression requires an opening '[' token");
2175 self.advance();
2176 if self.is_close_bracket() {
2177 return Err(ParseError::new_range(
2178 "expected a type expression after '['".to_string(),
2179 open_span,
2180 self.last_span,
2181 ));
2182 }
2183 let element = self.parse_type_expression()?;
2184 if !self.is_close_bracket() {
2185 return Err(self.error_at("expected closing ']' after array type expression"));
2186 }
2187 return Ok(TypeExpr::Array {
2188 element: Box::new(element),
2189 span: ExprSpan {
2190 start: open_span,
2191 end: self.last_span,
2192 },
2193 });
2194 }
2195
2196 if !self.is_open_paren() {
2197 return Err(self.error_at("expected a type name, '[' or '('"));
2198 }
2199 let open_span = self.last_span;
2200 if self.is_close_paren() {
2201 return Ok(TypeExpr::Tuple {
2202 elements: Vec::new(),
2203 span: ExprSpan {
2204 start: open_span,
2205 end: self.last_span,
2206 },
2207 });
2208 }
2209
2210 let first = self.parse_type_expression()?;
2211 if self.is_close_paren() {
2212 let span = ExprSpan {
2213 start: open_span,
2214 end: self.last_span,
2215 };
2216 return Ok(match first {
2217 TypeExpr::Named { name, args, .. } => TypeExpr::Named { name, args, span },
2218 TypeExpr::Array { element, .. } => TypeExpr::Array { element, span },
2219 TypeExpr::Tuple { elements, .. } => TypeExpr::Tuple { elements, span },
2220 });
2221 }
2222 if !self.is_punctuation(",") {
2223 return Err(self.error_at("expected ',' or closing ')'"));
2224 }
2225 if self.is_close_paren() {
2226 return Ok(TypeExpr::Tuple {
2227 elements: vec![first],
2228 span: ExprSpan {
2229 start: open_span,
2230 end: self.last_span,
2231 },
2232 });
2233 }
2234 let mut elements = vec![first];
2235 loop {
2236 elements.push(self.parse_type_expression()?);
2237 if self.is_close_paren() {
2238 break;
2239 }
2240 if !self.is_punctuation(",") {
2241 return Err(self.error_at("expected ',' or closing ')'"));
2242 }
2243 }
2244 Ok(TypeExpr::Tuple {
2245 elements,
2246 span: ExprSpan {
2247 start: open_span,
2248 end: self.last_span,
2249 },
2250 })
2251 }
2252
2253 fn is_closure_expression(&mut self, params_already_closed: bool) -> Result<bool> {
2283 let start_span = self.last_span;
2284 let mut params: Vec<(String, Span, Option<cel_runtime::ValueType>, TypeExpr)> = Vec::new();
2285 if !params_already_closed {
2286 loop {
2287 let name = self.expect_identifier("expected closure parameter name")?;
2288 let name_span = self.last_span;
2289 if !self.is_punctuation(":") {
2290 return Err(self.error_at("expected ':' after closure parameter name"));
2291 }
2292 let ty_ast = self.parse_type_expression()?;
2293 let ty = if C::resolves_closure_types() {
2294 Some(closure_param_type_from_type_expr(
2295 &ty_ast,
2296 self.type_resolver.as_ref(),
2297 )?)
2298 } else {
2299 None
2300 };
2301 params.push((name, name_span, ty, ty_ast));
2302 if self.is_punctuation(",") {
2303 continue;
2304 }
2305 break;
2306 }
2307 if !self.is_punctuation("|") {
2308 return Err(self.error_at("expected ',' or closing '|'"));
2309 }
2310 }
2311
2312 let param_types = params
2313 .iter()
2314 .filter_map(|(_, _, ty, _)| ty.clone())
2315 .collect();
2316 let ast_params: Vec<ClosureParam> = params
2317 .iter()
2318 .map(|(name, name_span, _, ty_ast)| ClosureParam {
2319 name: name.clone(),
2320 name_span: ExprSpan {
2321 start: *name_span,
2322 end: *name_span,
2323 },
2324 type_expr: ty_ast.clone(),
2325 })
2326 .collect();
2327 let isolated = self.op_lookup.isolate_scopes();
2328 let param_table: HashMap<String, (usize, Option<cel_runtime::ValueType>)> = params
2329 .into_iter()
2330 .enumerate()
2331 .map(|(idx, (name, _, ty, _))| (name, (idx, ty)))
2332 .collect();
2333 self.op_lookup
2334 .push_scope(move |name, segment, arity, _span| {
2335 if arity != 0 {
2336 return Ok(false);
2337 }
2338 let Some((idx, ty)) = param_table.get(name) else {
2339 return Ok(false);
2340 };
2341 if let Some(ty) = ty {
2342 ty.push_argument(segment, *idx)?;
2343 }
2344 Ok(true)
2345 });
2346
2347 let body_result = self.parse_nested_context(|p| p.is_expression());
2348 self.op_lookup.pop_scope();
2349 self.op_lookup.restore_scopes(isolated);
2350 let body = body_result?;
2351
2352 self.context
2353 .push_closure(param_types, ast_params, body, start_span)?;
2354 Ok(true)
2355 }
2356
2357 fn is_if_expression(&mut self, if_span: Span) -> Result<bool> {
2370 if !self.with_restriction(ExpressionRestriction::NoStructLiteral, |p| {
2371 p.is_expression()
2372 })? {
2373 return Err(self.error_at("expected condition after `if`"));
2374 }
2375 match self.peek_token() {
2376 Some(Token::OpenDelim {
2377 delimiter: Delimiter::Brace,
2378 ..
2379 }) => {
2380 self.advance();
2381 }
2382 _ => return Err(self.error_at("expected `{` after if condition")),
2383 }
2384 let mut then_fragment = self.context.new_fragment();
2385 std::mem::swap(&mut self.context, &mut then_fragment);
2386 if !self.is_ordinary_expression()? {
2387 return Err(self.error_at("expected expression in then-branch"));
2388 }
2389 std::mem::swap(&mut self.context, &mut then_fragment);
2390 match self.peek_token() {
2391 Some(Token::CloseDelim {
2392 delimiter: Delimiter::Brace,
2393 ..
2394 }) => {
2395 self.advance();
2396 }
2397 _ => return Err(self.error_at("expected `}` after then-branch")),
2398 }
2399 let else_fragment = if self.is_keyword("else") {
2400 if self.is_keyword("if") {
2401 let elif_span = self.last_span;
2403 let mut fragment = self.context.new_fragment();
2404 std::mem::swap(&mut self.context, &mut fragment);
2405 self.is_if_expression(elif_span)?;
2406 std::mem::swap(&mut self.context, &mut fragment);
2407 Some(fragment)
2408 } else {
2409 match self.peek_token() {
2411 Some(Token::OpenDelim {
2412 delimiter: Delimiter::Brace,
2413 ..
2414 }) => {
2415 self.advance();
2416 }
2417 _ => return Err(self.error_at("expected `{` or `if` after `else`")),
2418 }
2419 let mut fragment = self.context.new_fragment();
2420 std::mem::swap(&mut self.context, &mut fragment);
2421 if !self.is_ordinary_expression()? {
2422 return Err(self.error_at("expected expression in else-branch"));
2423 }
2424 std::mem::swap(&mut self.context, &mut fragment);
2425 match self.peek_token() {
2426 Some(Token::CloseDelim {
2427 delimiter: Delimiter::Brace,
2428 ..
2429 }) => {
2430 self.advance();
2431 }
2432 _ => return Err(self.error_at("expected `}` after else-branch")),
2433 }
2434 Some(fragment)
2435 }
2436 } else {
2437 None
2441 };
2442 self.context
2443 .join2(then_fragment, else_fragment, if_span, self.last_span)
2444 .map_err(|e| ParseError::new_range(e.to_string(), if_span, self.last_span))?;
2445 Ok(true)
2446 }
2447}
2448
2449impl Parser<DynSegmentContext> {
2450 pub fn parse_expression(&mut self) -> Result<DynSegment> {
2461 self.parse_expression_ctx()
2462 .map(DynSegmentContext::into_inner)
2463 }
2464
2465 pub fn parse_expression_restricted(
2475 &mut self,
2476 restriction: ExpressionRestriction,
2477 ) -> Result<DynSegment> {
2478 self.parse_expression_ctx_restricted(restriction)
2479 .map(DynSegmentContext::into_inner)
2480 }
2481
2482 pub fn parse_literal_pattern(&mut self) -> Result<DynSegment> {
2490 self.parse_literal_pattern_ctx()
2491 .map(DynSegmentContext::into_inner)
2492 }
2493
2494 pub fn parse_tokens(&mut self, tokens: TokenStreamIter) -> Result<DynSegment> {
2504 self.parse_tokens_ctx(tokens)
2505 .map(DynSegmentContext::into_inner)
2506 }
2507
2508 pub fn parse_str(&mut self, s: &str) -> Result<DynSegment> {
2519 self.parse_str_ctx(s).map(DynSegmentContext::into_inner)
2520 }
2521}
2522
2523impl Parser<AstContext> {
2524 pub fn parse_expression_ast(&mut self) -> Result<Expr> {
2536 self.parse_expression_ctx().map(AstContext::into_expr)
2537 }
2538
2539 pub fn parse_tokens_ast(&mut self, tokens: TokenStreamIter) -> Result<Expr> {
2549 self.parse_tokens_ctx(tokens).map(AstContext::into_expr)
2550 }
2551
2552 pub fn parse_str_ast(&mut self, s: &str) -> Result<Expr> {
2573 self.parse_str_ctx(s).map(AstContext::into_expr)
2574 }
2575}
2576
2577#[cfg(test)]
2578mod tests {
2579 use super::*;
2580 use annotate_snippets::Renderer;
2581
2582 #[test]
2583 fn simple_expression() {
2584 let mut parser = CELParser::new(OpLookup::new());
2585 let result = parser.parse_str("10");
2586 assert!(result.is_ok());
2587 assert_eq!(result.unwrap().call0::<i32>().unwrap(), 10);
2588 }
2589
2590 #[test]
2591 fn parse_nested_context_compiles_an_independent_segment_without_disturbing_the_outer_one()
2592 -> anyhow::Result<()> {
2593 let mut parser = CELParser::new(OpLookup::new());
2594 parser.set_tokens(quote::quote! { 1 + 2 }.into_iter());
2595 parser
2597 .context
2598 .push_literal(100i32, proc_macro2::Span::call_site());
2599
2600 let nested = parser
2601 .parse_nested_context(|p| p.is_or_expression())
2602 .map_err(|e| anyhow::anyhow!("{}", e))?;
2603
2604 assert_eq!(parser.context.into_inner().call0::<i32>()?, 100);
2606 assert_eq!(nested.into_inner().call0::<i32>()?, 3);
2608 Ok(())
2609 }
2610
2611 #[test]
2612 fn unbalanced_delimiter_count_is_zero_before_any_parse() {
2613 let parser = CELParser::new(OpLookup::new());
2614 assert_eq!(parser.unbalanced_delimiter_count(), 0);
2615 }
2616
2617 #[test]
2618 fn unbalanced_delimiter_count_is_zero_after_a_successful_parse() {
2619 let mut parser = CELParser::new(OpLookup::new());
2620 parser.parse_str("(1 + 2)").unwrap();
2621 assert_eq!(parser.unbalanced_delimiter_count(), 0);
2622 }
2623
2624 #[test]
2625 fn unbalanced_delimiter_count_reports_a_brace_left_dangling_by_a_failed_if_expression() {
2626 let mut parser = CELParser::new(OpLookup::new());
2627 let err = match parser.parse_str("if true { }") {
2628 Err(e) => e,
2629 Ok(_) => panic!("an empty then-branch must fail to parse"),
2630 };
2631 assert!(err.message().contains("then-branch"));
2632 assert_eq!(parser.unbalanced_delimiter_count(), 1);
2633 }
2634
2635 #[test]
2636 fn unbalanced_delimiter_count_reports_a_paren_left_dangling_by_a_failed_tuple_literal() {
2637 let mut parser = CELParser::new(OpLookup::new());
2638 if parser.parse_str("(+)").is_ok() {
2639 panic!("`+` alone cannot start an expression");
2640 }
2641 assert_eq!(parser.unbalanced_delimiter_count(), 1);
2642 }
2643
2644 #[test]
2645 fn unbalanced_delimiter_count_resets_when_a_new_parse_begins() {
2646 let mut parser = CELParser::new(OpLookup::new());
2647 if parser.parse_str("(+)").is_ok() {
2648 panic!("`+` alone cannot start an expression");
2649 }
2650 assert_eq!(parser.unbalanced_delimiter_count(), 1);
2651 parser.parse_str("1 + 2").unwrap();
2652 assert_eq!(parser.unbalanced_delimiter_count(), 0);
2653 }
2654
2655 #[test]
2656 fn integer_literal_i32_suffix() {
2657 let mut parser = CELParser::new(OpLookup::new());
2658 let result = parser.parse_str("10i32");
2659 assert!(result.is_ok());
2660 assert_eq!(result.unwrap().call0::<i32>().unwrap(), 10);
2661 }
2662
2663 #[test]
2664 fn invalid_integer_suffix() {
2665 let mut parser = CELParser::new(OpLookup::new());
2666 let err = match parser.parse_str("10xyz") {
2667 Err(e) => e,
2668 Ok(_) => panic!("expected parse error for invalid integer suffix"),
2669 };
2670 assert!(err.message().contains("invalid integer literal suffix"));
2671 assert!(err.message().contains("xyz"));
2672 }
2673
2674 #[test]
2675 fn validate_literal_accepts_a_well_formed_integer() {
2676 let lit: lex_lexer::Literal = syn::parse_str("5i32").unwrap();
2677 assert!(validate_literal(&lit).is_ok());
2678 }
2679
2680 #[test]
2681 fn validate_literal_accepts_a_well_formed_float() {
2682 let lit: lex_lexer::Literal = syn::parse_str("1.5f64").unwrap();
2683 assert!(validate_literal(&lit).is_ok());
2684 }
2685
2686 #[test]
2687 fn validate_literal_rejects_an_unrecognized_integer_suffix() {
2688 let lit: lex_lexer::Literal = syn::parse_str("10xyz").unwrap();
2689 let err = validate_literal(&lit).expect_err("unrecognized suffix must be rejected");
2690 assert!(err.message().contains("invalid integer literal suffix"));
2691 }
2692
2693 #[test]
2694 fn validate_literal_rejects_an_out_of_range_integer() {
2695 let lit: lex_lexer::Literal = syn::parse_str("999i8").unwrap();
2696 let err = validate_literal(&lit).expect_err("out-of-range literal must be rejected");
2697 assert!(err.message().contains("invalid i8 literal"));
2698 }
2699
2700 #[test]
2701 fn float_literal() {
2702 let mut parser = CELParser::new(OpLookup::new());
2703 let result = parser.parse_str("42.14");
2704 assert!(result.is_ok());
2705 let value = result.unwrap().call0::<f64>().unwrap();
2706 assert!((value - 42.14).abs() < 1e-10);
2707 }
2708
2709 #[test]
2710 fn float_literal_f64_suffix() {
2711 let mut parser = CELParser::new(OpLookup::new());
2712 let result = parser.parse_str("42.14f64");
2713 assert!(result.is_ok());
2714 let value = result.unwrap().call0::<f64>().unwrap();
2715 assert!((value - 42.14).abs() < 1e-10);
2716 }
2717
2718 #[test]
2719 fn float_literal_f32_suffix() {
2720 let mut parser = CELParser::new(OpLookup::new());
2721 let result = parser.parse_str("42.14f32");
2722 assert!(result.is_ok());
2723 let value = result.unwrap().call0::<f32>().unwrap();
2724 assert!((value - 42.14f32).abs() < 1e-6);
2725 }
2726
2727 #[test]
2728 fn invalid_float_suffix() {
2729 let mut parser = CELParser::new(OpLookup::new());
2730 let err = match parser.parse_str("3.14xyz") {
2731 Err(e) => e,
2732 Ok(_) => panic!("expected parse error for invalid float suffix"),
2733 };
2734 assert!(err.message().contains("invalid float literal suffix"));
2735 assert!(err.message().contains("xyz"));
2736 }
2737
2738 #[test]
2739 fn boolean_literal() {
2740 let mut parser = CELParser::new(OpLookup::new());
2741 let result = parser.parse_str("true");
2742 assert!(result.is_ok());
2743 assert!(result.unwrap().call0::<bool>().unwrap());
2744 }
2745
2746 #[test]
2747 fn string_literal() {
2748 let mut parser = CELParser::new(OpLookup::new());
2749 let result = parser.parse_str(r#""hello""#);
2750 assert!(result.is_ok());
2751 assert_eq!(result.unwrap().call0::<String>().unwrap(), "hello");
2752 }
2753
2754 #[test]
2755 fn string_concatenation() {
2756 let mut parser = CELParser::new(OpLookup::new());
2757 let result = parser.parse_str(r#""a" + "b""#);
2758 assert!(result.is_ok());
2759 assert_eq!(result.unwrap().call0::<String>().unwrap(), "ab");
2760 }
2761
2762 #[test]
2763 fn incomplete_expression() {
2764 let mut parser = CELParser::new(OpLookup::new());
2765 let result = parser.parse_str("10 + 25 25");
2766 let err = match result {
2767 Ok(_) => panic!("expected parse error"),
2768 Err(e) => e,
2769 };
2770 assert_eq!(err.message(), "unexpected token");
2771 }
2772
2773 #[test]
2774 fn arithmetic_expression() {
2775 let mut parser = CELParser::new(OpLookup::new());
2776 let result = parser.parse_str("10 + 20 * 30");
2777 assert!(result.is_ok());
2778 }
2779
2780 #[test]
2781 fn parenthesized_expression() {
2782 let mut parser = CELParser::new(OpLookup::new());
2783 let result = parser.parse_str("(10 + 20) * 30");
2784 assert!(result.is_ok());
2785 }
2786
2787 #[test]
2788 fn unit_still_parses_as_unit() {
2789 let mut parser = CELParser::new(OpLookup::new());
2790 let mut seg = parser.parse_str("()").unwrap();
2791 seg.call0::<()>().unwrap();
2792 }
2793
2794 #[test]
2795 fn single_paren_expression_is_grouping_not_tuple() {
2796 let mut parser = CELParser::new(OpLookup::new());
2797 let mut seg = parser.parse_str("(1i32 + 2i32)").unwrap();
2798 assert_eq!(seg.call0::<i32>().unwrap(), 3);
2799 }
2800
2801 #[test]
2802 fn one_tuple_requires_trailing_comma() {
2803 let mut parser = CELParser::new(OpLookup::new());
2804 let mut seg = parser.parse_str("(1i32,)").unwrap();
2805 assert_eq!(seg.peek_tuple_arity(), Some(1));
2806 seg.tuple_index(0).unwrap();
2807 assert_eq!(seg.call0::<i32>().unwrap(), 1);
2808 }
2809
2810 #[test]
2811 fn two_element_tuple_no_trailing_comma() {
2812 let mut parser = CELParser::new(OpLookup::new());
2813 let seg: DynSegment = parser.parse_str(r#"("Hello", 42i32)"#).unwrap();
2814 assert_eq!(seg.peek_tuple_arity(), Some(2));
2815 }
2816
2817 #[test]
2818 fn trailing_comma_rejected_for_arity_two() {
2819 let mut parser = CELParser::new(OpLookup::new());
2820 let result = parser.parse_str("(1i32, 2i32,)");
2821 assert!(result.is_err(), "trailing comma is only valid for 1-tuples");
2822 }
2823
2824 #[test]
2825 fn missing_comma_between_elements_is_an_error() {
2826 let mut parser = CELParser::new(OpLookup::new());
2827 let result = parser.parse_str("(1i32 2i32)");
2828 assert!(result.is_err());
2829 }
2830
2831 #[test]
2832 fn index_first_element_of_tuple() {
2833 let mut parser = CELParser::new(OpLookup::new());
2834 let mut seg = parser.parse_str("(10i32, 20i32).0").unwrap();
2835 assert_eq!(seg.call0::<i32>().unwrap(), 10);
2836 }
2837
2838 #[test]
2839 fn tuple_element_can_be_arithmetic_expression() {
2840 let mut parser = CELParser::new(OpLookup::new());
2841 let mut seg = parser.parse_str("(1i32 + 2i32, 3i32).0").unwrap();
2842 assert_eq!(seg.call0::<i32>().unwrap(), 3);
2843 }
2844
2845 #[test]
2846 fn tuple_second_element_can_be_arithmetic_expression() {
2847 let mut parser = CELParser::new(OpLookup::new());
2848 let mut seg = parser.parse_str("(1i32 + 2i32, 3i32).1").unwrap();
2849 assert_eq!(seg.call0::<i32>().unwrap(), 3);
2850 }
2851
2852 #[test]
2853 fn tuple_ambient_start_correct_after_sibling_expression() {
2854 let mut parser = CELParser::new(OpLookup::new());
2858 let mut seg = parser
2859 .parse_str("(1i32 + 2i32) + 3i32 + (4i32, 5i32).0")
2860 .unwrap();
2861 assert_eq!(seg.call0::<i32>().unwrap(), 10);
2862 }
2863
2864 #[test]
2865 fn tuple_index_inside_if_then_branch() {
2866 let mut parser = CELParser::new(OpLookup::new());
2870 let mut seg = parser
2871 .parse_str("if true { (10i32, 20i32).1 } else { 0i32 }")
2872 .unwrap();
2873 assert_eq!(seg.call0::<i32>().unwrap(), 20);
2874 }
2875
2876 #[test]
2877 fn tuple_index_inside_if_else_branch() {
2878 let mut parser = CELParser::new(OpLookup::new());
2879 let mut seg = parser
2880 .parse_str("if false { 0i32 } else { (10i32, 20i32).1 }")
2881 .unwrap();
2882 assert_eq!(seg.call0::<i32>().unwrap(), 20);
2883 }
2884
2885 #[test]
2886 fn tuple_index_inside_and_rhs() {
2887 let mut parser = CELParser::new(OpLookup::new());
2888 let mut seg = parser
2889 .parse_str("(1i32, 2i32).1 == 2i32 && (10i32, 20i32).1 == 20i32")
2890 .unwrap();
2891 assert!(seg.call0::<bool>().unwrap());
2892 }
2893
2894 #[test]
2895 fn tuple_index_inside_or_rhs() {
2896 let mut parser = CELParser::new(OpLookup::new());
2897 let mut seg = parser
2898 .parse_str("(1i32, 2i32).1 == 99i32 || (10i32, 20i32).1 == 20i32")
2899 .unwrap();
2900 assert!(seg.call0::<bool>().unwrap());
2901 }
2902
2903 #[test]
2904 fn tuple_containing_indexed_nested_tuple_result() {
2905 let mut parser = CELParser::new(OpLookup::new());
2913 let mut seg = parser.parse_str("(0u8, (7u8, 2u64).0).1").unwrap();
2914 assert_eq!(seg.call0::<u8>().unwrap(), 7);
2915 }
2916
2917 #[test]
2918 fn index_second_element_of_tuple() {
2919 let mut parser = CELParser::new(OpLookup::new());
2920 let mut seg = parser.parse_str("(10i32, 20i32).1").unwrap();
2921 assert_eq!(seg.call0::<i32>().unwrap(), 20);
2922 }
2923
2924 #[test]
2925 fn indexing_combined_with_addition() {
2926 let mut parser = CELParser::new(OpLookup::new());
2927 let mut seg = parser.parse_str("5i32 + (0i32, 1i32).1").unwrap();
2928 assert_eq!(seg.call0::<i32>().unwrap(), 6);
2929 }
2930
2931 #[test]
2932 fn indexing_combined_with_addition_on_the_right() {
2933 let mut parser = CELParser::new(OpLookup::new());
2934 let mut seg = parser.parse_str("(0i32, 1i32).1 + 5i32").unwrap();
2935 assert_eq!(seg.call0::<i32>().unwrap(), 6);
2936 }
2937
2938 #[test]
2939 fn out_of_range_index_is_a_parse_error() {
2940 let mut parser = CELParser::new(OpLookup::new());
2941 let result = parser.parse_str("(1i32, 2i32).5");
2942 assert!(result.is_err());
2943 }
2944
2945 #[test]
2946 fn indexing_a_non_tuple_is_a_parse_error() {
2947 let mut parser = CELParser::new(OpLookup::new());
2948 let result = parser.parse_str("1i32.0");
2949 assert!(result.is_err());
2950 }
2951
2952 #[test]
2953 fn suffixed_index_is_a_parse_error() {
2954 let mut parser = CELParser::new(OpLookup::new());
2955 let result = parser.parse_str("(1i32, 2i32).0i32");
2956 assert!(result.is_err());
2957 }
2958
2959 #[test]
2960 fn chained_tuple_index_into_nested_tuple() {
2961 let mut parser = CELParser::new(OpLookup::new());
2971 let mut seg = parser
2972 .parse_str(r#"("a", (10i32, 20i32)).1.0"#)
2973 .expect("chained .1.0 index should parse");
2974 assert_eq!(seg.call0::<i32>().unwrap(), 10);
2975 }
2976
2977 #[test]
2978 fn chained_tuple_index_suffixed_second_part_is_a_parse_error() {
2979 let mut parser = CELParser::new(OpLookup::new());
2982 let result = parser.parse_str("(1i32, 2i32).0.1i32");
2983 assert!(result.is_err());
2984 }
2985
2986 #[test]
2987 fn chained_tuple_index_scientific_notation_is_a_parse_error_not_a_panic() {
2988 let mut parser = CELParser::new(OpLookup::new());
2992 let result = parser.parse_str("(1i32, 2i32).1e2");
2993 assert!(result.is_err());
2994 }
2995
2996 #[test]
2997 fn complex_expression() {
2998 let mut parser = CELParser::new(OpLookup::new());
2999 let result = parser.parse_str("10 + 20 * (30 - 5) / 2");
3000 assert!(result.is_ok());
3001 }
3002
3003 #[test]
3004 fn logical_expression() {
3005 let mut parser = CELParser::new(OpLookup::new());
3006 let result = parser.parse_str("true && false || true");
3007 assert!(result.is_ok());
3008 }
3009
3010 #[test]
3011 fn comparison_expression() {
3012 let mut parser = CELParser::new(OpLookup::new());
3013 let result = parser.parse_str("10 == 20 && 30 > 40");
3014 assert!(result.is_ok());
3015 }
3016
3017 #[test]
3018 fn bitwise_expression() {
3019 let mut parser = CELParser::new(OpLookup::new());
3020 let result = parser.parse_str("1 | 2 & 3 ^ 4");
3021 assert!(result.is_ok());
3022 }
3023
3024 #[test]
3025 fn shift_expression() {
3026 let mut parser = CELParser::new(OpLookup::new());
3027 let result = parser.parse_str("8u32 << 2u32 + 16u32 >> 1u32");
3028 assert!(result.is_ok());
3029 }
3030
3031 #[test]
3032 fn unary_expression() {
3033 let mut parser = CELParser::new(OpLookup::new());
3034 let result = parser.parse_str("-10 + -20");
3035 assert!(result.is_ok());
3036 }
3037
3038 #[test]
3039 fn double_negation() {
3040 let mut parser = CELParser::new(OpLookup::new());
3041 let result = parser.parse_str("!!true");
3042 assert!(
3043 result.is_ok(),
3044 "Failed to parse !!true: {}",
3045 result.err().unwrap()
3046 );
3047 assert!(result.unwrap().call0::<bool>().unwrap());
3048 }
3049
3050 #[test]
3051 fn double_minus() {
3052 let mut parser = CELParser::new(OpLookup::new());
3053 let result = parser.parse_str("--5");
3054 assert!(
3055 result.is_ok(),
3056 "Failed to parse --5: {}",
3057 result.err().unwrap()
3058 );
3059 assert_eq!(result.unwrap().call0::<i32>().unwrap(), 5);
3060 }
3061
3062 #[test]
3063 fn chained_unary_expression() {
3064 let mut parser = CELParser::new(OpLookup::new());
3065 let result = parser.parse_str("!!false || !!true");
3066 if let Err(ref e) = result {
3067 eprintln!("Error: {:?}", e);
3068 eprintln!("Error message: {}", e.message());
3069 }
3070 assert!(result.is_ok(), "Failed to parse: {}", result.err().unwrap());
3071 assert!(result.unwrap().call0::<bool>().unwrap());
3072 }
3073
3074 #[test]
3075 fn cast_expression_parses_and_executes() {
3076 let mut parser = CELParser::new(OpLookup::new());
3077 let result = parser.parse_str("1024i32 as f64");
3078 assert_eq!(result.unwrap().call0::<f64>().unwrap(), 1024.0);
3079 }
3080
3081 #[test]
3082 fn cast_expression_chains_left_to_right() {
3083 let mut parser = CELParser::new(OpLookup::new());
3087 let result = parser.parse_str("1.5f64 as i32 as f64");
3088 assert_eq!(result.unwrap().call0::<f64>().unwrap(), 1.0);
3089 }
3090
3091 #[test]
3092 fn cast_binds_tighter_than_unary_negation() {
3093 let mut parser = CELParser::new(OpLookup::new());
3099 let mut seg = parser.parse_str("-1i32 as u32").expect(
3100 "parses: unary negation is registered for i32, and i32 -> u32 is a valid cast pair",
3101 );
3102 let err = seg.call0::<u32>().unwrap_err();
3103 let full = format!("{err:#}");
3107 assert!(
3108 full.contains("does not fit"),
3109 "expected an out-of-range cast error, got: {full}"
3110 );
3111 }
3112
3113 #[test]
3114 fn cast_binds_tighter_than_multiplicative_operators() {
3115 let mut parser = CELParser::new(OpLookup::new());
3122 let result = parser.parse_str("2i32 * 3i32 as f64");
3123 assert!(result.is_err(), "expected a type-mismatch parse error");
3124 }
3125
3126 #[test]
3127 fn cast_binds_tighter_than_additive_operators() {
3128 let mut parser = CELParser::new(OpLookup::new());
3132 let result = parser.parse_str("1i32 + 2i32 as f64");
3133 assert!(result.is_err(), "expected a type-mismatch parse error");
3134 }
3135
3136 #[test]
3137 fn invalid_expression() {
3138 let mut parser = CELParser::new(OpLookup::new());
3139 let result = parser.parse_str("+");
3140 assert!(result.is_err());
3141 }
3142
3143 #[test]
3144 fn error_formatting() {
3145 let source = "10 + 20 30";
3146 let mut parser = CELParser::new(OpLookup::new());
3147 let result = parser.parse_str(source);
3148
3149 assert!(result.is_err());
3150
3151 let err = match &result {
3152 Ok(_) => panic!("expected parse error"),
3153 Err(e) => e,
3154 };
3155 assert_eq!(err.message(), "unexpected token");
3156
3157 let formatted = err.format_rustc_style(source, "test.cel", 1u32, &Renderer::plain());
3158 assert!(formatted.contains("error: unexpected token"));
3159 assert!(formatted.contains("test.cel:1:"));
3160 assert!(formatted.contains("1 | 10 + 20 30"));
3161 assert!(formatted.contains("^"));
3162 }
3163
3164 #[test]
3165 fn error_formatting_with_line_offset() {
3166 let source = "10 + 20 30";
3167 let mut parser = CELParser::new(OpLookup::new());
3168 let result = parser.parse_str(source);
3169
3170 assert!(result.is_err());
3171
3172 let err = match &result {
3173 Ok(_) => panic!("expected parse error"),
3174 Err(e) => e,
3175 };
3176 let formatted = err.format_rustc_style(source, "large_file.rs", 42u32, &Renderer::plain());
3177 assert!(formatted.contains("error: unexpected token"));
3178 assert!(formatted.contains("large_file.rs:42:"));
3179 assert!(formatted.contains("42 | 10 + 20 30"));
3180 assert!(formatted.contains("^"));
3181 }
3182
3183 #[test]
3184 fn print_error_formatting() {
3185 let line = line!() + 1;
3186 let source = r#"
3187
3188 10 + 20 30 // Unexpected token
3189
3190 "#;
3191
3192 let mut parser = CELParser::new(OpLookup::new());
3193 let result = parser.parse_str(source);
3194
3195 assert!(result.is_err(), "Expected parsing to fail");
3196
3197 let err = match &result {
3198 Ok(_) => panic!("expected parse error"),
3199 Err(e) => e,
3200 };
3201 eprintln!(
3202 "DEBUG: span.start.line = {}, span.start.column = {}",
3203 err.span().start().line,
3204 err.span().start().column
3205 );
3206
3207 let formatted_error = err.format_rustc_style(source, file!(), line, &Renderer::plain());
3208 println!("{}", formatted_error);
3209
3210 let formatted = formatted_error;
3211
3212 let expected_line = line + 2;
3213
3214 assert!(
3215 formatted.contains("error: unexpected token"),
3216 "Should contain error message, got: {}",
3217 formatted
3218 );
3219 assert!(
3220 formatted.contains(&format!("{}:", expected_line)),
3221 "Should show error on line {}, got: {}",
3222 expected_line,
3223 formatted
3224 );
3225 assert!(
3226 formatted.contains("30"),
3227 "Should show the source line with '30', got: {}",
3228 formatted
3229 );
3230 assert!(
3231 formatted.contains("^"),
3232 "Should have carets pointing to error, got: {}",
3233 formatted
3234 );
3235 }
3236
3237 #[test]
3238 fn test_addition_execution() -> anyhow::Result<()> {
3239 let mut parser = CELParser::new(OpLookup::new());
3240 let mut segment = parser
3241 .parse_str("10 + 20")
3242 .map_err(|e| anyhow::anyhow!("{}", e))?;
3243 let result = segment.call0::<i32>()?;
3244 assert_eq!(result, 30);
3245 Ok(())
3246 }
3247
3248 #[test]
3249 fn test_multiplication_execution() -> anyhow::Result<()> {
3250 let mut parser = CELParser::new(OpLookup::new());
3251 let mut segment = parser
3252 .parse_str("3 * 7")
3253 .map_err(|e| anyhow::anyhow!("{}", e))?;
3254 let result = segment.call0::<i32>()?;
3255 assert_eq!(result, 21);
3256 Ok(())
3257 }
3258
3259 #[test]
3260 fn test_complex_arithmetic_execution() -> anyhow::Result<()> {
3261 let mut parser = CELParser::new(OpLookup::new());
3262 let mut segment = parser
3263 .parse_str("10 + 20 * 3")
3264 .map_err(|e| anyhow::anyhow!("{}", e))?;
3265 let result = segment.call0::<i32>()?;
3266 assert_eq!(result, 70);
3267 Ok(())
3268 }
3269
3270 #[test]
3271 fn test_parenthesized_arithmetic_execution() -> anyhow::Result<()> {
3272 let mut parser = CELParser::new(OpLookup::new());
3273 let mut segment = parser
3274 .parse_str("(10 + 20) * 3")
3275 .map_err(|e| anyhow::anyhow!("{}", e))?;
3276 let result = segment.call0::<i32>()?;
3277 assert_eq!(result, 90);
3278 Ok(())
3279 }
3280
3281 #[test]
3282 fn test_comparison_execution() -> anyhow::Result<()> {
3283 let mut parser = CELParser::new(OpLookup::new());
3284 let mut segment = parser
3285 .parse_str("10 < 20")
3286 .map_err(|e| anyhow::anyhow!("{}", e))?;
3287 let result = segment.call0::<bool>()?;
3288 assert!(result);
3289 Ok(())
3290 }
3291
3292 #[test]
3293 fn test_logical_and_execution() -> anyhow::Result<()> {
3294 let mut parser = CELParser::new(OpLookup::new());
3295 let mut segment = parser
3296 .parse_str("true && false")
3297 .map_err(|e| anyhow::anyhow!("{}", e))?;
3298 let result = segment.call0::<bool>()?;
3299 assert!(!result);
3300 Ok(())
3301 }
3302
3303 #[test]
3304 fn test_unary_negation_execution() -> anyhow::Result<()> {
3305 let mut parser = CELParser::new(OpLookup::new());
3306 let mut segment = parser
3307 .parse_str("-42")
3308 .map_err(|e| anyhow::anyhow!("{}", e))?;
3309 let result = segment.call0::<i32>()?;
3310 assert_eq!(result, -42);
3311 Ok(())
3312 }
3313
3314 #[test]
3315 fn test_logical_not_execution() -> anyhow::Result<()> {
3316 let mut parser = CELParser::new(OpLookup::new());
3317 let mut segment = parser
3318 .parse_str("!true")
3319 .map_err(|e| anyhow::anyhow!("{}", e))?;
3320 let result = segment.call0::<bool>()?;
3321 assert!(!result);
3322 Ok(())
3323 }
3324
3325 #[test]
3326 fn test_u32_addition_execution() -> anyhow::Result<()> {
3327 let mut parser = CELParser::new(OpLookup::new());
3328 let mut segment = parser
3329 .parse_str("10u32 + 20u32")
3330 .map_err(|e| anyhow::anyhow!("{}", e))?;
3331 let result = segment.call0::<u32>()?;
3332 assert_eq!(result, 30);
3333 Ok(())
3334 }
3335
3336 #[test]
3337 fn test_identifier_with_scope() -> anyhow::Result<()> {
3338 let mut lookup = OpLookup::new();
3339 lookup.push_scope(|name, segment, num_operands, _span| {
3340 if num_operands == 0 {
3341 match name {
3342 "x" => {
3343 segment.op0(|| 10i32);
3344 Ok(true)
3345 }
3346 "y" => {
3347 segment.op0(|| 20i32);
3348 Ok(true)
3349 }
3350 _ => Ok(false),
3351 }
3352 } else {
3353 Ok(false)
3354 }
3355 });
3356 let mut parser = CELParser::new(lookup);
3357 let mut segment = parser
3358 .parse_str("x + y")
3359 .map_err(|e| anyhow::anyhow!("{}", e))?;
3360 let result = segment.call0::<i32>()?;
3361 assert_eq!(result, 30);
3362 Ok(())
3363 }
3364
3365 #[test]
3366 fn test_undefined_identifier_error() {
3367 let mut parser = CELParser::new(OpLookup::new());
3368 let result = parser.parse_str("undefined_var + 10");
3369
3370 assert!(result.is_err());
3371 if let Err(e) = result {
3372 let error_msg = format!("{:?}", e);
3373 assert!(
3374 error_msg.contains("undefined identifier: `undefined_var`"),
3375 "Error message should contain 'undefined identifier: `undefined_var`', got: {}",
3376 error_msg
3377 );
3378 }
3379 }
3380
3381 #[test]
3382 fn test_identifier_scope_error_propagated() {
3383 let mut lookup = OpLookup::new();
3384 lookup.push_scope(|name, _segment, num_operands, _span| {
3385 if name == "bad_id" && num_operands == 0 {
3386 return Err(anyhow::anyhow!("custom identifier rejected"));
3387 }
3388 Ok(false)
3389 });
3390 let mut parser = CELParser::new(lookup);
3391 let err = match parser.parse_str("bad_id + 1") {
3392 Err(e) => e,
3393 Ok(_) => panic!("scope Err should propagate, not become Undefined identifier"),
3394 };
3395 assert!(
3396 err.message().contains("custom identifier rejected"),
3397 "expected scope error message, got: {}",
3398 err.message()
3399 );
3400 assert!(
3401 !err.message().contains("undefined identifier:"),
3402 "scope Err must not be rewritten as undefined identifier"
3403 );
3404 }
3405
3406 #[test]
3407 fn test_undefined_identifier_error_formatting() {
3408 let input = "undefined_var + 10";
3409 let mut parser = CELParser::new(OpLookup::new());
3410 let result = parser.parse_str(input);
3411
3412 assert!(result.is_err());
3413 if let Err(e) = result {
3414 let formatted_error = e.format_rustc_style(input, "test.cel", 1, &Renderer::plain());
3415 assert!(formatted_error.contains("undefined identifier"));
3416 assert!(formatted_error.contains("undefined_var"));
3417 assert!(formatted_error.contains("test.cel"));
3418 }
3419 }
3420
3421 #[test]
3422 fn test_float_arithmetic_execution() -> anyhow::Result<()> {
3423 let mut parser = CELParser::new(OpLookup::new());
3424 let mut segment = parser
3425 .parse_str("3.5 * 2.0")
3426 .map_err(|e| anyhow::anyhow!("{}", e))?;
3427 let result = segment.call0::<f64>()?;
3428 assert_eq!(result, 7.0);
3429 Ok(())
3430 }
3431
3432 #[test]
3433 fn call_empty_arg_list() -> anyhow::Result<()> {
3434 let mut lookup = OpLookup::new();
3435 lookup.push_scope(
3436 |name, segment, num_operands, _span| match (name, num_operands) {
3437 ("f", 0) => {
3438 segment.op0(|| 0i32);
3439 Ok(true)
3440 }
3441 ("()", 1) => {
3442 segment.op1(|_callee: i32| 99i32)?;
3443 Ok(true)
3444 }
3445 _ => Ok(false),
3446 },
3447 );
3448 let mut parser = CELParser::new(lookup);
3449 let mut segment = parser
3450 .parse_str("f()")
3451 .map_err(|e| anyhow::anyhow!("{}", e))?;
3452 assert_eq!(segment.call0::<i32>()?, 99);
3453 Ok(())
3454 }
3455
3456 #[test]
3457 fn call_single_arg() -> anyhow::Result<()> {
3458 let mut lookup = OpLookup::new();
3459 lookup.push_scope(
3460 |name, segment, num_operands, _span| match (name, num_operands) {
3461 ("f", 0) => {
3462 segment.op0(|| 0i32);
3463 Ok(true)
3464 }
3465 ("()", 2) => {
3466 segment.op2(|_callee: i32, arg: i32| arg)?;
3467 Ok(true)
3468 }
3469 _ => Ok(false),
3470 },
3471 );
3472 let mut parser = CELParser::new(lookup);
3473 let mut segment = parser
3474 .parse_str("f(42)")
3475 .map_err(|e| anyhow::anyhow!("{}", e))?;
3476 assert_eq!(segment.call0::<i32>()?, 42);
3477 Ok(())
3478 }
3479
3480 #[test]
3481 fn call_multiple_args() -> anyhow::Result<()> {
3482 let mut lookup = OpLookup::new();
3483 lookup.push_scope(
3484 |name, segment, num_operands, _span| match (name, num_operands) {
3485 ("f", 0) => {
3486 segment.op0(|| 0i32);
3487 Ok(true)
3488 }
3489 ("()", 3) => {
3490 segment.op3(|_callee: i32, arg1: i32, arg2: i32| arg1 + arg2)?;
3491 Ok(true)
3492 }
3493 _ => Ok(false),
3494 },
3495 );
3496 let mut parser = CELParser::new(lookup);
3497 let mut segment = parser
3498 .parse_str("f(10, 32)")
3499 .map_err(|e| anyhow::anyhow!("{}", e))?;
3500 assert_eq!(segment.call0::<i32>()?, 42);
3501 Ok(())
3502 }
3503
3504 #[test]
3505 fn call_missing_closing_paren() {
3506 let mut lookup = OpLookup::new();
3507 lookup.push_scope(
3508 |name, segment, num_operands, _span| match (name, num_operands) {
3509 ("f", 0) => {
3510 segment.op0(|| 0i32);
3511 Ok(true)
3512 }
3513 _ => Ok(false),
3514 },
3515 );
3516 let mut parser = CELParser::new(lookup);
3517 let err = match parser.parse_str("f(42 43)") {
3518 Err(e) => e,
3519 Ok(_) => panic!("expected parse error for missing closing parenthesis"),
3520 };
3521 assert_eq!(err.message(), "expected closing parenthesis");
3522 }
3523
3524 #[test]
3525 fn call_trailing_comma() {
3526 let mut lookup = OpLookup::new();
3527 lookup.push_scope(
3528 |name, segment, num_operands, _span| match (name, num_operands) {
3529 ("f", 0) => {
3530 segment.op0(|| 0i32);
3531 Ok(true)
3532 }
3533 _ => Ok(false),
3534 },
3535 );
3536 let mut parser = CELParser::new(lookup);
3537 let err = match parser.parse_str("f(42,)") {
3538 Err(e) => e,
3539 Ok(_) => panic!("expected parse error for trailing comma"),
3540 };
3541 assert_eq!(err.message(), "expected expression after comma");
3542 }
3543
3544 #[test]
3545 fn call_undefined_call_op() {
3546 let mut lookup = OpLookup::new();
3547 lookup.push_scope(
3548 |name, segment, num_operands, _span| match (name, num_operands) {
3549 ("f", 0) => {
3550 segment.op0(|| 0i32);
3551 Ok(true)
3552 }
3553 _ => Ok(false),
3554 },
3555 );
3556 let mut parser = CELParser::new(lookup);
3557 let err = match parser.parse_str("f()") {
3558 Err(e) => e,
3559 Ok(_) => panic!("expected error when () operator is not registered"),
3560 };
3561 assert!(
3562 err.message().starts_with("no operation"),
3563 "error should report no operation found, got: {}",
3564 err.message()
3565 );
3566 }
3567
3568 #[test]
3569 fn call_leading_comma_reports_expected_expression_at_the_comma() {
3570 let mut lookup = OpLookup::new();
3571 lookup.push_scope(
3572 |name, segment, num_operands, _span| match (name, num_operands) {
3573 ("f", 0) => {
3574 segment.op0(|| 0i32);
3575 Ok(true)
3576 }
3577 _ => Ok(false),
3578 },
3579 );
3580 let mut parser = CELParser::new(lookup);
3581 let err = match parser.parse_str("f(,5)") {
3582 Err(e) => e,
3583 Ok(_) => panic!("expected parse error for leading comma"),
3584 };
3585 assert_eq!(err.message(), "expected expression");
3586 }
3587
3588 #[test]
3589 fn call_chained() -> anyhow::Result<()> {
3590 let mut lookup = OpLookup::new();
3591 lookup.push_scope(
3592 |name, segment, num_operands, _span| match (name, num_operands) {
3593 ("f", 0) => {
3594 segment.op0(|| 0i32);
3595 Ok(true)
3596 }
3597 ("()", 1) => {
3598 segment.op1(|_callee: i32| 7i32)?;
3599 Ok(true)
3600 }
3601 _ => Ok(false),
3602 },
3603 );
3604 let mut parser = CELParser::new(lookup);
3605 let mut segment = parser
3606 .parse_str("f()()")
3607 .map_err(|e| anyhow::anyhow!("{}", e))?;
3608 assert_eq!(segment.call0::<i32>()?, 7);
3609 Ok(())
3610 }
3611
3612 #[test]
3613 fn op_type_mismatch_error_spans_full_expression() {
3614 let source = r#""Hello" + 32.0"#;
3615 let mut parser = CELParser::new(OpLookup::new());
3616 let err = match parser.parse_str(source) {
3617 Err(e) => e,
3618 Ok(_) => panic!("expected parse error for type mismatch"),
3619 };
3620 assert!(
3621 err.message().starts_with("no operation"),
3622 "expected 'no operation' prefix, got: {}",
3623 err.message()
3624 );
3625 let end_span = err.end_span().expect("op-lookup errors carry an end span");
3626 assert!(
3627 end_span.end().column >= 14,
3628 "end span should reach the end of 32.0 (expected end.column >= 14, got {})",
3629 end_span.end().column
3630 );
3631 }
3632
3633 #[test]
3634 fn and_short_circuits_on_false() {
3635 let mut parser = CELParser::new(OpLookup::new());
3638 let mut segment = parser
3639 .parse_str("false && (1i32 / 0i32 == 0i32)")
3640 .expect("should parse");
3641 assert!(!segment.call0::<bool>().unwrap());
3642 }
3643
3644 #[test]
3645 fn and_evaluates_rhs_when_lhs_true() {
3646 let mut parser = CELParser::new(OpLookup::new());
3647 let mut segment = parser.parse_str("true && false").expect("should parse");
3648 assert!(!segment.call0::<bool>().unwrap());
3649 }
3650
3651 #[test]
3652 fn and_chained_short_circuits() {
3653 let mut parser = CELParser::new(OpLookup::new());
3654 let mut segment = parser
3655 .parse_str("false && false && false")
3656 .expect("should parse");
3657 assert!(!segment.call0::<bool>().unwrap());
3658 }
3659
3660 #[test]
3661 fn and_lhs_type_error() {
3662 let mut parser = CELParser::new(OpLookup::new());
3664 let err = match parser.parse_str("1i32 && true") {
3665 Err(e) => e,
3666 Ok(_) => panic!("lhs i32 should fail for &&"),
3667 };
3668 assert!(err.end_span().is_some());
3669 }
3670
3671 #[test]
3672 fn or_lhs_type_error() {
3673 let mut parser = CELParser::new(OpLookup::new());
3675 let err = match parser.parse_str("1i32 || true") {
3676 Err(e) => e,
3677 Ok(_) => panic!("lhs i32 should fail for ||"),
3678 };
3679 assert!(err.end_span().is_some());
3680 }
3681
3682 #[test]
3683 fn or_short_circuits_on_true() {
3684 let mut parser = CELParser::new(OpLookup::new());
3687 let mut segment = parser
3688 .parse_str("true || (1i32 / 0i32 == 0i32)")
3689 .expect("should parse");
3690 assert!(segment.call0::<bool>().unwrap());
3691 }
3692
3693 #[test]
3694 fn or_evaluates_rhs_when_lhs_false() {
3695 let mut parser = CELParser::new(OpLookup::new());
3696 let mut segment = parser.parse_str("false || true").expect("should parse");
3697 assert!(segment.call0::<bool>().unwrap());
3698 }
3699
3700 #[test]
3701 fn or_chained() {
3702 let mut parser = CELParser::new(OpLookup::new());
3703 let mut segment = parser
3704 .parse_str("true || false || false")
3705 .expect("should parse");
3706 assert!(segment.call0::<bool>().unwrap());
3707 }
3708
3709 #[test]
3710 fn if_true_branch_selected() {
3711 let mut parser = CELParser::new(OpLookup::new());
3712 let mut segment = parser
3713 .parse_str("if true { 1i32 } else { 2i32 }")
3714 .expect("should parse");
3715 assert_eq!(segment.call0::<i32>().unwrap(), 1);
3716 }
3717
3718 #[test]
3719 fn if_false_branch_selected() {
3720 let mut parser = CELParser::new(OpLookup::new());
3721 let mut segment = parser
3722 .parse_str("if false { 1i32 } else { 2i32 }")
3723 .expect("should parse");
3724 assert_eq!(segment.call0::<i32>().unwrap(), 2);
3725 }
3726
3727 #[test]
3728 fn if_else_if_first_branch() {
3729 let mut parser = CELParser::new(OpLookup::new());
3730 let mut segment = parser
3731 .parse_str("if true { 1i32 } else if false { 2i32 } else { 3i32 }")
3732 .expect("should parse");
3733 assert_eq!(segment.call0::<i32>().unwrap(), 1);
3734 }
3735
3736 #[test]
3737 fn if_else_if_middle_branch() {
3738 let mut parser = CELParser::new(OpLookup::new());
3739 let mut segment = parser
3740 .parse_str("if false { 1i32 } else if true { 2i32 } else { 3i32 }")
3741 .expect("should parse");
3742 assert_eq!(segment.call0::<i32>().unwrap(), 2);
3743 }
3744
3745 #[test]
3746 fn if_else_if_last_branch() {
3747 let mut parser = CELParser::new(OpLookup::new());
3748 let mut segment = parser
3749 .parse_str("if false { 1i32 } else if false { 2i32 } else { 3i32 }")
3750 .expect("should parse");
3751 assert_eq!(segment.call0::<i32>().unwrap(), 3);
3752 }
3753
3754 #[test]
3755 fn if_omitted_else_unit_branch() {
3756 let mut parser = CELParser::new(OpLookup::new());
3757 let mut segment = parser.parse_str("if true { () }").expect("should parse");
3758 segment.call0::<()>().expect("should execute");
3759 }
3760
3761 #[test]
3762 fn if_omitted_else_rejects_non_unit_then() {
3763 let mut parser = CELParser::new(OpLookup::new());
3765 assert!(parser.parse_str("if false { 1i32 }").is_err());
3766 }
3767
3768 #[test]
3769 fn if_branch_type_mismatch_is_error() {
3770 let mut parser = CELParser::new(OpLookup::new());
3771 assert!(parser.parse_str("if true { 1i32 } else { true }").is_err());
3772 }
3773
3774 #[test]
3775 fn if_branch_tuple_arity_mismatch_is_error() {
3776 let mut parser = CELParser::new(OpLookup::new());
3781 let result = parser.parse_str("if false { (1i32, 2i32) } else { (3i64, 4i64, 5i64) }.0");
3782 assert!(
3783 result.is_err(),
3784 "branches with different tuple shapes must not be accepted"
3785 );
3786 }
3787
3788 #[test]
3789 fn if_branch_tuple_element_type_mismatch_is_error() {
3790 let mut parser = CELParser::new(OpLookup::new());
3791 let result = parser.parse_str("if false { (1i32, 2i32) } else { (3i64, 4i64) }.0");
3792 assert!(
3793 result.is_err(),
3794 "branches with the same arity but different element types must not be accepted"
3795 );
3796 }
3797
3798 #[test]
3799 fn if_missing_open_brace_is_error() {
3800 let mut parser = CELParser::new(OpLookup::new());
3801 assert!(parser.parse_str("if true 1i32 } else { 2i32 }").is_err());
3802 }
3803
3804 #[test]
3805 fn if_missing_else_after_brace_is_fine() {
3806 let mut parser = CELParser::new(OpLookup::new());
3808 let mut segment = parser.parse_str("if false { () }").expect("should parse");
3809 segment.call0::<()>().expect("should execute");
3810 }
3811
3812 #[test]
3813 fn if_trailing_else_is_error() {
3814 let mut parser = CELParser::new(OpLookup::new());
3816 assert!(parser.parse_str("if true { () } else").is_err());
3817 }
3818
3819 #[test]
3820 fn parse_expression_stops_before_comma() -> anyhow::Result<()> {
3821 use lex_lexer::LexLexer;
3822 let stream: proc_macro2::TokenStream = "10i32 + 20i32, 5i32".parse().unwrap();
3823 let mut parser = CELParser::new(OpLookup::new());
3824 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
3825 let mut seg = parser
3826 .parse_expression()
3827 .map_err(|e| anyhow::anyhow!("{}", e))?;
3828 let result: i32 = seg.call0()?;
3829 assert_eq!(result, 30);
3830 let remaining: Vec<_> = parser.take_lex_tokens().expect("tokens present").collect();
3831 assert_eq!(
3833 remaining.len(),
3834 2,
3835 "expected 2 remaining tokens (comma and 5i32)"
3836 );
3837 Ok(())
3838 }
3839
3840 #[test]
3841 fn parse_expression_on_empty_input_returns_error() {
3842 use lex_lexer::LexLexer;
3843 let stream: proc_macro2::TokenStream = "".parse().unwrap();
3844 let mut parser = CELParser::new(OpLookup::new());
3845 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
3846 let result = parser.parse_expression();
3847 assert!(result.is_err(), "expected Err for empty input");
3848 }
3849
3850 #[test]
3851 fn parse_literal_pattern_accepts_a_bare_literal() -> anyhow::Result<()> {
3852 use lex_lexer::LexLexer;
3853 let stream: proc_macro2::TokenStream = "5i32".parse().unwrap();
3854 let mut parser = CELParser::new(OpLookup::new());
3855 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
3856 let mut seg = parser
3857 .parse_literal_pattern()
3858 .map_err(|e| anyhow::anyhow!("{}", e))?;
3859 assert_eq!(seg.call0::<i32>()?, 5);
3860 Ok(())
3861 }
3862
3863 #[test]
3864 fn parse_literal_pattern_accepts_a_negated_integer_literal() -> anyhow::Result<()> {
3865 use lex_lexer::LexLexer;
3866 let stream: proc_macro2::TokenStream = "-5i32".parse().unwrap();
3867 let mut parser = CELParser::new(OpLookup::new());
3868 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
3869 let mut seg = parser
3870 .parse_literal_pattern()
3871 .map_err(|e| anyhow::anyhow!("{}", e))?;
3872 assert_eq!(seg.call0::<i32>()?, -5);
3873 Ok(())
3874 }
3875
3876 #[test]
3877 fn parse_literal_pattern_accepts_a_negated_float_literal() -> anyhow::Result<()> {
3878 use lex_lexer::LexLexer;
3879 let stream: proc_macro2::TokenStream = "-1.5f64".parse().unwrap();
3880 let mut parser = CELParser::new(OpLookup::new());
3881 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
3882 let mut seg = parser
3883 .parse_literal_pattern()
3884 .map_err(|e| anyhow::anyhow!("{}", e))?;
3885 assert_eq!(seg.call0::<f64>()?, -1.5);
3886 Ok(())
3887 }
3888
3889 #[test]
3890 fn parse_literal_pattern_stops_before_a_trailing_operator() -> anyhow::Result<()> {
3891 use lex_lexer::LexLexer;
3892 let stream: proc_macro2::TokenStream = "1i32 + 2i32".parse().unwrap();
3893 let mut parser = CELParser::new(OpLookup::new());
3894 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
3895 let mut seg = parser
3896 .parse_literal_pattern()
3897 .map_err(|e| anyhow::anyhow!("{}", e))?;
3898 assert_eq!(seg.call0::<i32>()?, 1);
3899 let remaining: Vec<_> = parser.take_lex_tokens().expect("tokens present").collect();
3900 assert_eq!(
3901 remaining.len(),
3902 2,
3903 "expected 2 remaining tokens (+ and 2i32)"
3904 );
3905 Ok(())
3906 }
3907
3908 #[test]
3909 fn parse_literal_pattern_rejects_a_dash_not_followed_by_a_literal() {
3910 use lex_lexer::LexLexer;
3911 let stream: proc_macro2::TokenStream = "-mode".parse().unwrap();
3912 let mut parser = CELParser::new(OpLookup::new());
3913 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
3914 assert!(parser.parse_literal_pattern().is_err());
3915 }
3916
3917 #[test]
3918 fn parse_literal_pattern_rejects_negating_an_unsigned_literal() {
3919 use lex_lexer::LexLexer;
3920 let stream: proc_macro2::TokenStream = "-1u32".parse().unwrap();
3921 let mut parser = CELParser::new(OpLookup::new());
3922 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
3923 assert!(parser.parse_literal_pattern().is_err());
3924 }
3925
3926 #[test]
3927 fn parse_literal_pattern_rejects_a_bare_identifier() {
3928 use lex_lexer::LexLexer;
3929 let stream: proc_macro2::TokenStream = "mode".parse().unwrap();
3930 let mut parser = CELParser::new(OpLookup::new());
3931 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
3932 assert!(parser.parse_literal_pattern().is_err());
3933 }
3934
3935 #[test]
3936 fn parse_literal_pattern_rejects_a_tuple() {
3937 use lex_lexer::LexLexer;
3938 let stream: proc_macro2::TokenStream = "(1i32, 2i32)".parse().unwrap();
3939 let mut parser = CELParser::new(OpLookup::new());
3940 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
3941 assert!(parser.parse_literal_pattern().is_err());
3942 }
3943
3944 #[test]
3945 fn closure_literal_with_one_param_compiles_and_calls() -> anyhow::Result<()> {
3946 let mut parser = CELParser::new(OpLookup::new());
3947 let mut segment = parser
3948 .parse_str("|x: i32| x + 1")
3949 .map_err(|e| anyhow::anyhow!("{}", e))?;
3950 let closure: cel_runtime::DynClosure = segment.call0()?;
3951 let x = 5i32;
3952 assert_eq!(closure.call::<i32>(&[&x])?, 6);
3953 Ok(())
3954 }
3955
3956 #[test]
3957 fn closure_literal_with_zero_params_compiles_and_calls() -> anyhow::Result<()> {
3958 let mut parser = CELParser::new(OpLookup::new());
3959 let mut segment = parser
3960 .parse_str("|| 42")
3961 .map_err(|e| anyhow::anyhow!("{}", e))?;
3962 let closure: cel_runtime::DynClosure = segment.call0()?;
3963 assert_eq!(closure.call::<i32>(&[])?, 42);
3964 Ok(())
3965 }
3966
3967 #[test]
3968 fn closure_literal_with_two_params_compiles_and_calls_in_order() -> anyhow::Result<()> {
3969 let mut parser = CELParser::new(OpLookup::new());
3970 let mut segment = parser
3971 .parse_str("|a: i32, b: i32| a - b")
3972 .map_err(|e| anyhow::anyhow!("{}", e))?;
3973 let closure: cel_runtime::DynClosure = segment.call0()?;
3974 let (a, b) = (10i32, 3i32);
3975 assert_eq!(closure.call::<i32>(&[&a, &b])?, 7);
3976 Ok(())
3977 }
3978
3979 #[test]
3980 fn closure_literal_with_tuple_typed_param_compiles_and_calls() -> anyhow::Result<()> {
3981 let mut parser = CELParser::new(OpLookup::new());
3982 let mut segment = parser
3983 .parse_str("|r: (i32, i32)| r.0 + r.1")
3984 .map_err(|e| anyhow::anyhow!("{}", e))?;
3985 let closure: cel_runtime::DynClosure = segment.call0()?;
3986
3987 let mut pair = DynSegment::new::<()>();
3989 let ambient_start = pair.current_stack_offset();
3990 pair.just(10i32);
3991 pair.annotate_top(crate::op_table::builtin_value_type(TypeId::of::<i32>()).unwrap())?;
3992 pair.just(20i32);
3993 pair.annotate_top(crate::op_table::builtin_value_type(TypeId::of::<i32>()).unwrap())?;
3994 pair.make_tuple(2, ambient_start)?;
3995 let pair = pair.call_dyn_value(&[])?;
3996
3997 assert_eq!(closure.call::<i32>(&[&pair])?, 30);
3998 Ok(())
3999 }
4000
4001 #[test]
4002 fn closure_param_accepts_a_builtin_generic_type() -> anyhow::Result<()> {
4003 let mut parser = CELParser::new(OpLookup::new());
4004 let mut segment = parser
4005 .parse_str("|r: RangeInclusive(f64)| r")
4006 .map_err(|e| anyhow::anyhow!("{}", e))?;
4007 let closure: cel_runtime::DynClosure = segment.call0()?;
4008 let range = 1.0f64..=2.0f64;
4009 assert_eq!(
4010 closure.call::<std::ops::RangeInclusive<f64>>(&[&range])?,
4011 1.0..=2.0
4012 );
4013 Ok(())
4014 }
4015
4016 #[test]
4017 fn closure_param_accepts_an_array_type() {
4018 let mut parser = CELParser::new(OpLookup::new());
4019 let mut segment = parser.parse_str("(|xs: [i32]| xs)([1, 2])").unwrap();
4020 let array = segment
4021 .call0::<cel_runtime::OwnedValue>()
4022 .unwrap()
4023 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()
4024 .unwrap();
4025 assert_eq!(array.as_slice(), &[1, 2]);
4026 }
4027
4028 #[test]
4029 fn closure_body_referencing_an_undeclared_name_is_a_parse_error() {
4030 let mut parser = CELParser::new(OpLookup::new());
4031 let err = parser.parse_str("|x: i32| x + y");
4032 assert!(err.is_err());
4033 }
4034
4035 #[test]
4036 fn nested_closure_referencing_only_its_own_param_compiles_and_calls() -> anyhow::Result<()> {
4037 let mut parser = CELParser::new(OpLookup::new());
4038 let mut segment = parser
4044 .parse_str("|x: i32| |y: i32| y + 1")
4045 .map_err(|e| anyhow::anyhow!("{}", e))?;
4046 let outer: cel_runtime::DynClosure = segment.call0()?;
4047 let x = 0i32;
4048 let inner: cel_runtime::DynClosure = outer.call(&[&x])?;
4049 let y = 41i32;
4050 assert_eq!(inner.call::<i32>(&[&y])?, 42);
4051 Ok(())
4052 }
4053
4054 #[test]
4055 fn closure_body_cannot_see_an_enclosing_scopes_names() {
4056 let mut lookup = OpLookup::new();
4059 lookup.push_scope(|name, segment, arity, _span| {
4060 if name == "outer_only" && arity == 0 {
4061 segment.just(1i32);
4062 Ok(true)
4063 } else {
4064 Ok(false)
4065 }
4066 });
4067 let mut parser = CELParser::new(lookup);
4068 let err = parser.parse_str("|x: i32| x + outer_only");
4069 assert!(err.is_err());
4070 }
4071
4072 #[test]
4073 fn ast_context_parses_a_one_param_closure() {
4074 let mut parser = Parser::<AstContext>::new(OpLookup::new());
4075 let expr = parser.parse_str_ast("|x: i32| x").unwrap();
4076 let Expr::Closure { params, body, .. } = expr else {
4077 panic!("expected Closure");
4078 };
4079 assert_eq!(params.len(), 1);
4080 assert_eq!(params[0].name, "x");
4081 assert!(matches!(
4082 ¶ms[0].type_expr,
4083 TypeExpr::Named { name, args, .. } if name == "i32" && args.is_empty()
4084 ));
4085 assert!(matches!(*body, Expr::Ident { ref name, .. } if name == "x"));
4086 }
4087
4088 #[test]
4089 fn ast_context_parses_a_zero_param_closure() {
4090 let mut parser = Parser::<AstContext>::new(OpLookup::new());
4091 let expr = parser.parse_str_ast("|| 1i32").unwrap();
4092 let Expr::Closure { params, .. } = expr else {
4093 panic!("expected Closure");
4094 };
4095 assert!(params.is_empty());
4096 }
4097
4098 #[test]
4099 fn ast_context_parses_a_tuple_typed_closure_param() {
4100 let mut parser = Parser::<AstContext>::new(OpLookup::new());
4101 let expr = parser.parse_str_ast("|x: (i32, f64)| x.0").unwrap();
4102 let Expr::Closure { params, .. } = expr else {
4103 panic!("expected Closure");
4104 };
4105 match ¶ms[0].type_expr {
4106 TypeExpr::Tuple { elements, .. } => assert_eq!(elements.len(), 2),
4107 other => panic!("expected Tuple, got {other:?}"),
4108 }
4109 }
4110
4111 #[test]
4112 fn range_expression_constructs_a_range() {
4113 let mut parser = CELParser::new(OpLookup::new());
4114 let mut seg = parser.parse_str("1i32..5i32").unwrap();
4115 assert_eq!(seg.call0::<std::ops::Range<i32>>().unwrap(), 1i32..5i32);
4116 }
4117
4118 #[test]
4119 fn range_inclusive_expression_constructs_a_range_inclusive() {
4120 let mut parser = CELParser::new(OpLookup::new());
4121 let mut seg = parser.parse_str("1i32..=5i32").unwrap();
4122 assert_eq!(
4123 seg.call0::<std::ops::RangeInclusive<i32>>().unwrap(),
4124 1i32..=5i32
4125 );
4126 }
4127
4128 #[test]
4129 fn range_from_expression_constructs_a_range_from() {
4130 let mut parser = CELParser::new(OpLookup::new());
4131 let mut seg = parser.parse_str("3i32..").unwrap();
4132 assert_eq!(seg.call0::<std::ops::RangeFrom<i32>>().unwrap(), 3i32..);
4133 }
4134
4135 #[test]
4136 fn range_to_expression_constructs_a_range_to() {
4137 let mut parser = CELParser::new(OpLookup::new());
4138 let mut seg = parser.parse_str("..7i32").unwrap();
4139 assert_eq!(seg.call0::<std::ops::RangeTo<i32>>().unwrap(), ..7i32);
4140 }
4141
4142 #[test]
4143 fn range_to_inclusive_expression_constructs_a_range_to_inclusive() {
4144 let mut parser = CELParser::new(OpLookup::new());
4145 let mut seg = parser.parse_str("..=7i32").unwrap();
4146 assert_eq!(
4147 seg.call0::<std::ops::RangeToInclusive<i32>>().unwrap(),
4148 ..=7i32
4149 );
4150 }
4151
4152 #[test]
4153 fn range_full_expression_constructs_a_range_full() {
4154 let mut parser = CELParser::new(OpLookup::new());
4155 let mut seg = parser.parse_str("..").unwrap();
4156 seg.call0::<std::ops::RangeFull>().unwrap();
4157 }
4158
4159 #[test]
4160 fn range_endpoints_are_full_or_expressions() {
4161 let mut parser = CELParser::new(OpLookup::new());
4164 let mut seg = parser.parse_str("1i32 + 2i32..3i32 * 4i32").unwrap();
4165 assert_eq!(seg.call0::<std::ops::Range<i32>>().unwrap(), 3i32..12i32);
4166 }
4167
4168 #[test]
4169 fn chained_ranges_are_a_parse_error() {
4170 let mut parser = CELParser::new(OpLookup::new());
4175 let result = parser.parse_str("1i32..2i32..3i32");
4176 assert!(result.is_err(), "expected a parse error, got Ok");
4177 }
4178
4179 #[test]
4180 fn range_to_inclusive_without_a_right_operand_is_a_parse_error() {
4181 let mut parser = CELParser::new(OpLookup::new());
4183 let result = parser.parse_str("..=");
4184 assert!(result.is_err(), "expected a parse error, got Ok");
4185 }
4186
4187 #[test]
4188 fn range_endpoint_absorbs_a_trailing_comparison_confirming_or_expression_operands() {
4189 let mut parser = CELParser::new(OpLookup::new());
4195 let err = match parser.parse_str("1i32..5i32 == true") {
4196 Err(e) => e,
4197 Ok(_) => panic!("expected a parse error"),
4198 };
4199 let message = err.message();
4200 assert!(
4201 message.starts_with("no operation `==`"),
4202 "expected a 'no operation `==`' error, got: {message}"
4203 );
4204 assert!(
4205 !message.contains("Range"),
4206 "expected the error to be about `i32`/`bool` (the inner endpoint's own comparison), \
4207 not `Range<i32>` (which would mean `..` grabbed only `5i32` and `==` applied afterward \
4208 to an already-built range) — got: {message}"
4209 );
4210 }
4211
4212 #[test]
4213 fn parameter_list_accepts_a_range_expression() -> anyhow::Result<()> {
4214 let mut lookup = OpLookup::new();
4215 lookup.push_scope(
4216 |name, segment, num_operands, _span| match (name, num_operands) {
4217 ("f", 0) => {
4218 segment.op0(|| 0i32);
4219 Ok(true)
4220 }
4221 ("()", 2) => {
4222 segment.op2(|_callee: i32, arg: std::ops::Range<i32>| arg)?;
4223 Ok(true)
4224 }
4225 _ => Ok(false),
4226 },
4227 );
4228 let mut parser = CELParser::new(lookup);
4229 let mut segment = parser
4230 .parse_str("f(1i32..5i32)")
4231 .map_err(|e| anyhow::anyhow!("{}", e))?;
4232 assert_eq!(segment.call0::<std::ops::Range<i32>>()?, 1i32..5i32);
4233 Ok(())
4234 }
4235
4236 #[test]
4237 fn tuple_or_group_accepts_a_range_expression() -> anyhow::Result<()> {
4238 let mut parser = CELParser::new(OpLookup::new());
4239 let mut seg = parser.parse_str("(1i32..5i32)").unwrap();
4240 assert_eq!(seg.call0::<std::ops::Range<i32>>().unwrap(), 1i32..5i32);
4241 Ok(())
4242 }
4243
4244 #[test]
4245 fn if_expression_branches_accept_range_expressions() {
4246 let mut parser = CELParser::new(OpLookup::new());
4247 let mut seg = parser
4248 .parse_str("if true { 1i32..5i32 } else { 2i32..6i32 }")
4249 .unwrap();
4250 assert_eq!(seg.call0::<std::ops::Range<i32>>().unwrap(), 1i32..5i32);
4251 }
4252
4253 #[test]
4254 fn closure_body_accepts_a_range_expression() -> anyhow::Result<()> {
4255 let mut parser = CELParser::new(OpLookup::new());
4256 let mut segment = parser
4257 .parse_str("|| 1i32..5i32")
4258 .map_err(|e| anyhow::anyhow!("{}", e))?;
4259 let closure: cel_runtime::DynClosure = segment.call0()?;
4260 assert_eq!(closure.call::<std::ops::Range<i32>>(&[])?, 1i32..5i32);
4261 Ok(())
4262 }
4263
4264 fn array_parse_error(source: &str) -> ParseError {
4266 let mut parser = CELParser::new(OpLookup::new());
4267 match parser.parse_str(source) {
4268 Err(e) => e,
4269 Ok(_) => panic!("expected a parse error for `{source}`"),
4270 }
4271 }
4272
4273 #[test]
4274 fn array_literal_evaluates_to_its_elements_in_source_order() -> anyhow::Result<()> {
4275 let mut parser = CELParser::new(OpLookup::new());
4276 let mut segment = parser
4277 .parse_str("[0i32, 1i32, 2i32]")
4278 .map_err(|e| anyhow::anyhow!("{}", e))?;
4279 let array = segment
4280 .call0::<cel_runtime::OwnedValue>()?
4281 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4282 assert_eq!(array.into_vec(), vec![0, 1, 2]);
4283 Ok(())
4284 }
4285
4286 #[test]
4287 fn typed_array_annotation_preserves_unsuffixed_non_empty_inference() -> anyhow::Result<()> {
4288 let mut parser = CELParser::new(OpLookup::new());
4289 let mut segment = parser
4290 .parse_str("[0, 1]")
4291 .map_err(|e| anyhow::anyhow!("{}", e))?;
4292 let array = segment
4293 .call0::<cel_runtime::OwnedValue>()?
4294 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4295 assert_eq!(array.into_vec(), vec![0, 1]);
4296 Ok(())
4297 }
4298
4299 #[test]
4300 fn typed_array_annotation_evaluates_to_the_declared_scalar_type() -> anyhow::Result<()> {
4301 let mut parser = CELParser::new(OpLookup::new());
4302 let mut segment = parser
4303 .parse_str("[0, 1]: [i32]")
4304 .map_err(|e| anyhow::anyhow!("{}", e))?;
4305 let array = segment
4306 .call0::<cel_runtime::OwnedValue>()?
4307 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4308 assert_eq!(array.into_vec(), vec![0, 1]);
4309 Ok(())
4310 }
4311
4312 #[test]
4313 fn typed_array_annotation_evaluates_to_the_declared_f64_type() -> anyhow::Result<()> {
4314 let mut parser = CELParser::new(OpLookup::new());
4315 let mut segment = parser
4316 .parse_str("[1.0, 42.5]: [f64]")
4317 .map_err(|e| anyhow::anyhow!("{}", e))?;
4318 let array = segment
4319 .call0::<cel_runtime::OwnedValue>()?
4320 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<f64>>>()?;
4321 assert_eq!(array.into_vec(), vec![1.0, 42.5]);
4322 Ok(())
4323 }
4324
4325 #[test]
4326 fn typed_array_annotation_constructs_a_typed_empty_array() -> anyhow::Result<()> {
4327 let mut parser = CELParser::new(OpLookup::new());
4328 let mut segment = parser
4329 .parse_str("[]: [i32]")
4330 .map_err(|e| anyhow::anyhow!("{}", e))?;
4331 let array = segment
4332 .call0::<cel_runtime::OwnedValue>()?
4333 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4334 assert!(array.into_vec().is_empty());
4335 Ok(())
4336 }
4337
4338 #[test]
4339 fn typed_array_annotation_constructs_a_nested_typed_empty_array() -> anyhow::Result<()> {
4340 let mut parser = CELParser::new(OpLookup::new());
4341 let mut segment = parser
4342 .parse_str("[]: [[i32]]")
4343 .map_err(|e| anyhow::anyhow!("{}", e))?;
4344 let array = segment
4345 .call0::<cel_runtime::OwnedValue>()?
4346 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>>(
4347 )?;
4348 assert!(array.into_vec().is_empty());
4349 Ok(())
4350 }
4351
4352 #[test]
4353 fn single_element_array_literal_needs_no_trailing_comma() -> anyhow::Result<()> {
4354 let mut parser = CELParser::new(OpLookup::new());
4355 let mut segment = parser
4356 .parse_str("[7i32]")
4357 .map_err(|e| anyhow::anyhow!("{}", e))?;
4358 let array = segment
4359 .call0::<cel_runtime::OwnedValue>()?
4360 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4361 assert_eq!(array.into_vec(), vec![7]);
4362 Ok(())
4363 }
4364
4365 #[test]
4366 fn array_elements_can_be_arbitrary_expressions() -> anyhow::Result<()> {
4367 let mut parser = CELParser::new(OpLookup::new());
4368 let mut segment = parser
4369 .parse_str("[1i32 + 2i32, if true { 4i32 } else { 5i32 }]")
4370 .map_err(|e| anyhow::anyhow!("{}", e))?;
4371 let array = segment
4372 .call0::<cel_runtime::OwnedValue>()?
4373 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4374 assert_eq!(array.into_vec(), vec![3, 4]);
4375 Ok(())
4376 }
4377
4378 #[test]
4379 fn empty_array_literal_is_rejected_with_a_dedicated_diagnostic() {
4380 let err = array_parse_error("[]");
4381 assert!(
4382 err.message().contains("empty array"),
4383 "got: {}",
4384 err.message()
4385 );
4386 assert!(
4387 err.message().contains("issues/212"),
4388 "the diagnostic must reference the contextual-typing issue, got: {}",
4389 err.message()
4390 );
4391 }
4392
4393 #[test]
4394 fn array_literal_rejects_a_trailing_comma() {
4395 let err = array_parse_error("[0i32,]");
4396 assert!(
4397 err.message().contains("expected expression after ','"),
4398 "got: {}",
4399 err.message()
4400 );
4401 }
4402
4403 #[test]
4404 fn array_literal_requires_a_comma_between_elements() {
4405 let err = array_parse_error("[0i32 1i32]");
4406 assert!(
4407 err.message().contains("expected ',' or closing ']'"),
4408 "got: {}",
4409 err.message()
4410 );
4411 }
4412
4413 #[test]
4414 fn array_literal_rejects_a_mismatched_element_naming_its_index() {
4415 let err = array_parse_error("[0i32, 1.0f64]");
4416 assert!(
4417 err.message().contains("array element 1"),
4418 "got: {}",
4419 err.message()
4420 );
4421 }
4422
4423 #[test]
4424 fn array_literal_accepts_a_tuple_element() {
4425 use cel_runtime::{ArrayOf, Cons, Leaf, Nil};
4426 let body = CELParser::new(OpLookup::new())
4427 .parse_str("[(0i32, 1i32)]")
4428 .unwrap();
4429 assert!(
4430 body.prepare::<Nil, ArrayOf<Cons<Leaf<i32>, Cons<Leaf<i32>, Nil>>>>()
4431 .is_ok()
4432 );
4433 }
4434
4435 #[test]
4436 fn nested_array_literal_evaluates_to_an_array_of_arrays() -> anyhow::Result<()> {
4437 let mut parser = CELParser::new(OpLookup::new());
4438 let mut segment = parser
4439 .parse_str("[[0i32], [1i32]]")
4440 .map_err(|e| anyhow::anyhow!("{}", e))?;
4441 let array = segment
4442 .call0::<cel_runtime::OwnedValue>()?
4443 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>>(
4444 )?;
4445 let inner = array.into_vec();
4446 assert_eq!(inner.len(), 2);
4447 let mut values = Vec::new();
4448 for element in inner {
4449 values.extend(element.into_vec());
4450 }
4451 assert_eq!(values, vec![0, 1]);
4452 Ok(())
4453 }
4454
4455 #[test]
4456 fn nested_array_literal_rejects_a_recursive_element_mismatch() {
4457 let err = array_parse_error("[[0i32], [1.0f64]]");
4458 assert!(
4459 err.message().contains("array element 1"),
4460 "got: {}",
4461 err.message()
4462 );
4463 }
4464
4465 #[test]
4466 fn nested_array_literal_rejects_a_depth_mismatch() {
4467 let err = array_parse_error("[[0i32], [[1i32]]]");
4468 assert!(
4469 err.message().contains("array element 1"),
4470 "got: {}",
4471 err.message()
4472 );
4473 }
4474
4475 #[test]
4476 fn typed_array_annotation_rejects_an_exact_element_type_mismatch() {
4477 let err = array_parse_error("[0, 1]: [f64]");
4478 assert!(
4479 err.message().contains("expected f64"),
4480 "got: {}",
4481 err.message()
4482 );
4483 assert!(err.message().contains("type i32"), "got: {}", err.message());
4484 }
4485
4486 #[test]
4487 fn typed_array_annotation_rejects_a_recursive_element_type_mismatch() {
4488 let err = array_parse_error("[[0, 1]]: [[f64]]");
4491 assert!(
4492 err.message().contains("expected [f64]"),
4493 "got: {}",
4494 err.message()
4495 );
4496 assert!(
4497 err.message().contains("type [i32]"),
4498 "got: {}",
4499 err.message()
4500 );
4501 }
4502
4503 #[test]
4504 fn typed_array_annotation_mismatch_names_the_registered_type_not_its_rust_path() {
4505 let resolver = [(
4506 "Celsius",
4507 ResolvedLeafType::new("Celsius", cel_runtime::ValueType::leaf::<Celsius>()),
4508 )];
4509 let mut parser = CELParser::with_type_resolver(OpLookup::new(), resolver);
4510 let err = match parser.parse_str("[0]: [Celsius]") {
4511 Err(e) => e,
4512 Ok(_) => panic!("expected `[0]: [Celsius]` to reject its `i32` element"),
4513 };
4514 assert!(
4515 err.message().contains("expected Celsius"),
4516 "the registered annotation name must survive into the diagnostic, got: {}",
4517 err.message()
4518 );
4519 assert!(
4520 !err.message().contains("::"),
4521 "no Rust type path may leak into the diagnostic, got: {}",
4522 err.message()
4523 );
4524 }
4525
4526 #[test]
4529 fn typed_array_annotation_rejects_a_nested_custom_element_type_mismatch() {
4530 #[derive(Clone)]
4531 struct CustomB;
4532
4533 let resolver = [
4534 (
4535 "Celsius",
4536 ResolvedLeafType::new("Celsius", cel_runtime::ValueType::leaf::<Celsius>()),
4537 ),
4538 (
4539 "CustomB",
4540 ResolvedLeafType::new("CustomB", cel_runtime::ValueType::leaf::<CustomB>()),
4541 ),
4542 ];
4543 let mut parser = CELParser::with_type_resolver(OpLookup::new(), resolver);
4544 let err = match parser.parse_str("[[]: [Celsius]]: [[CustomB]]") {
4545 Err(e) => e,
4546 Ok(_) => panic!("expected the inner annotation to conflict with the outer one"),
4547 };
4548 assert!(
4549 err.message().contains("expected [CustomB]"),
4550 "got: {}",
4551 err.message()
4552 );
4553 assert!(
4554 err.message().contains("[Celsius]"),
4555 "got: {}",
4556 err.message()
4557 );
4558 }
4559
4560 #[test]
4561 fn typed_array_annotation_rejects_an_unknown_type_name() {
4562 let err = array_parse_error("[0]: [Nope]");
4563 assert!(
4564 err.message().contains("unknown type `Nope`"),
4565 "got: {}",
4566 err.message()
4567 );
4568 }
4569
4570 #[test]
4571 fn typed_array_annotation_requires_a_complete_array_type() {
4572 let err = array_parse_error("[0]: i32");
4573 assert!(
4574 err.message()
4575 .contains("array annotations must name a complete array type"),
4576 "got: {}",
4577 err.message()
4578 );
4579 }
4580
4581 #[test]
4582 fn typed_array_annotation_accepts_tuple_array_elements() {
4583 use cel_runtime::{ArrayOf, Cons, Leaf, Nil};
4584 let body = CELParser::new(OpLookup::new())
4585 .parse_str("[]: [(i32, f64)]")
4586 .unwrap();
4587 assert!(
4588 body.prepare::<Nil, ArrayOf<Cons<Leaf<i32>, Cons<Leaf<f64>, Nil>>>>()
4589 .is_ok()
4590 );
4591 }
4592
4593 #[test]
4594 fn array_literal_is_accepted_as_a_call_argument() -> anyhow::Result<()> {
4595 let mut lookup = OpLookup::new();
4596 lookup.push_scope(
4597 |name, segment, num_operands, _span| match (name, num_operands) {
4598 ("len", 0) => {
4599 segment.op0(|| 0i32);
4600 Ok(true)
4601 }
4602 ("()", 2) => {
4603 segment.op2_repr::<cel_runtime::Leaf<i32>, cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>, cel_runtime::Leaf<i32>, _>(
4604 |_callee, arg| arg.len() as i32)?;
4605 Ok(true)
4606 }
4607 _ => Ok(false),
4608 },
4609 );
4610 let mut parser = CELParser::new(lookup);
4611 let mut segment = parser
4612 .parse_str("len([1i32, 2i32, 3i32])")
4613 .map_err(|e| anyhow::anyhow!("{}", e))?;
4614 assert_eq!(segment.call0::<i32>()?, 3);
4615 Ok(())
4616 }
4617
4618 #[test]
4619 fn array_literal_is_accepted_as_a_tuple_element() -> anyhow::Result<()> {
4620 let mut parser = CELParser::new(OpLookup::new());
4621 let mut segment = parser
4622 .parse_str("([1i32, 2i32], 3i32).0")
4623 .map_err(|e| anyhow::anyhow!("{}", e))?;
4624 let array = segment
4625 .call0::<cel_runtime::OwnedValue>()?
4626 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4627 assert_eq!(array.into_vec(), vec![1, 2]);
4628 Ok(())
4629 }
4630
4631 #[test]
4632 fn array_literal_is_accepted_inside_an_if_branch() -> anyhow::Result<()> {
4633 let mut parser = CELParser::new(OpLookup::new());
4634 let mut segment = parser
4635 .parse_str("if true { [1i32, 2i32] } else { [3i32, 4i32] }")
4636 .map_err(|e| anyhow::anyhow!("{}", e))?;
4637 let array = segment
4638 .call0::<cel_runtime::OwnedValue>()?
4639 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4640 assert_eq!(array.into_vec(), vec![1, 2]);
4641 Ok(())
4642 }
4643
4644 #[test]
4645 fn array_literal_is_accepted_as_a_closure_body() -> anyhow::Result<()> {
4646 let mut parser = CELParser::new(OpLookup::new());
4647 let mut segment = parser
4648 .parse_str("|x: i32| [x, x]")
4649 .map_err(|e| anyhow::anyhow!("{}", e))?;
4650 let closure: cel_runtime::DynClosure = segment.call0()?;
4651 let x = 5i32;
4652 let array = closure
4653 .call::<cel_runtime::OwnedValue>(&[&x])?
4654 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4655 assert_eq!(array.into_vec(), vec![5, 5]);
4656 Ok(())
4657 }
4658
4659 #[test]
4660 fn array_ambient_start_is_correct_after_a_sibling_expression() -> anyhow::Result<()> {
4661 let mut parser = CELParser::new(OpLookup::new());
4668 let mut segment = parser
4669 .parse_str("(1u8 + 2u8, [3i32, 4i32]).1")
4670 .map_err(|e| anyhow::anyhow!("{}", e))?;
4671 let array = segment
4672 .call0::<cel_runtime::OwnedValue>()?
4673 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4674 assert_eq!(array.into_vec(), vec![3, 4]);
4675 Ok(())
4676 }
4677
4678 struct Celsius(i32);
4681
4682 struct Fahrenheit(i32);
4685
4686 struct FName;
4688
4689 struct GName;
4691
4692 struct HName;
4694
4695 fn temperature_lookup(homogeneous: bool) -> OpLookup {
4699 let mut lookup = OpLookup::new();
4700 lookup.push_scope(
4701 move |name, segment, num_operands, _span| match (name, num_operands) {
4702 ("f", 0) => {
4703 segment.op0(|| FName);
4704 Ok(true)
4705 }
4706 ("g", 0) => {
4707 segment.op0(|| GName);
4708 Ok(true)
4709 }
4710 ("h", 0) => {
4711 segment.op0(|| HName);
4712 Ok(true)
4713 }
4714 ("()", 1) => {
4715 let Some(callee) = segment
4716 .peek_stack_infos(1)
4717 .first()
4718 .map(|i| i.value_type.type_id())
4719 else {
4720 return Ok(false);
4721 };
4722 if callee == TypeId::of::<FName>() {
4723 segment.op1(|_: FName| Celsius(0))?;
4724 } else if callee == TypeId::of::<GName>() {
4725 segment.op1(|_: GName| Celsius(1))?;
4726 } else if callee == TypeId::of::<HName>() {
4727 if homogeneous {
4728 segment.op1(|_: HName| Celsius(2))?;
4729 } else {
4730 segment.op1(|_: HName| Fahrenheit(2))?;
4731 }
4732 } else {
4733 return Ok(false);
4734 }
4735 Ok(true)
4736 }
4737 _ => Ok(false),
4738 },
4739 );
4740 lookup
4741 }
4742
4743 #[test]
4744 fn array_literal_of_calls_returning_a_custom_type_converts_to_its_vector() -> anyhow::Result<()>
4745 {
4746 let mut parser = CELParser::new(temperature_lookup(true));
4747 let mut segment = parser
4748 .parse_str("[f(), g(), h()]")
4749 .map_err(|e| anyhow::anyhow!("{}", e))?;
4750 let array = segment
4751 .call0::<cel_runtime::OwnedValue>()?
4752 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<Celsius>>>()?;
4753 let degrees: Vec<i32> = array.into_vec().into_iter().map(|c| c.0).collect();
4754 assert_eq!(degrees, vec![0, 1, 2]);
4755 Ok(())
4756 }
4757
4758 #[test]
4759 fn array_literal_of_one_custom_typed_call_evaluates_to_that_type() -> anyhow::Result<()> {
4760 let mut parser = CELParser::new(temperature_lookup(false));
4763 let mut segment = parser
4764 .parse_str("[h()]")
4765 .map_err(|e| anyhow::anyhow!("{}", e))?;
4766 let array = segment
4767 .call0::<cel_runtime::OwnedValue>()?
4768 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<Fahrenheit>>>()?;
4769 let degrees: Vec<i32> = array.into_vec().into_iter().map(|f| f.0).collect();
4770 assert_eq!(degrees, vec![2]);
4771 Ok(())
4772 }
4773
4774 #[test]
4775 fn array_literal_of_calls_rejects_a_mismatched_return_type_before_execution() {
4776 let mut parser = CELParser::new(temperature_lookup(false));
4779 let err = match parser.parse_str("[f(), g(), h()]") {
4780 Err(e) => e,
4781 Ok(_) => panic!("expected `[f(), g(), h()]` with a mismatched `h` to fail"),
4782 };
4783 let message = err.message();
4784 assert!(message.contains("array element 2"), "got: {message}");
4785 assert!(message.contains("Fahrenheit"), "got: {message}");
4786 assert!(message.contains("Celsius"), "got: {message}");
4787 }
4788
4789 #[test]
4790 fn static_check_and_execution_agree_on_a_nested_custom_typed_array() -> anyhow::Result<()> {
4791 const SOURCE: &str = "[[f(), g()], [h()]]";
4792
4793 let mut ast_parser = Parser::<AstContext>::new(OpLookup::new());
4797 let expr = ast_parser
4798 .parse_str_ast(SOURCE)
4799 .map_err(|e| anyhow::anyhow!("{}", e))?;
4800 let (ty, diagnostics) = ty::check_expr(&expr, &|_name| Ty::Any);
4801 let messages: Vec<String> = diagnostics
4802 .iter()
4803 .map(|d| d.message().to_string())
4804 .collect();
4805 assert!(messages.is_empty(), "unexpected diagnostics: {messages:?}");
4806 assert_eq!(ty, Ty::Array(Box::new(Ty::Array(Box::new(Ty::Any)))));
4807
4808 let mut parser = CELParser::new(temperature_lookup(true));
4810 let mut segment = parser
4811 .parse_str(SOURCE)
4812 .map_err(|e| anyhow::anyhow!("{}", e))?;
4813 let array = segment.call0::<cel_runtime::OwnedValue>()?.try_into_typed::<cel_runtime::ArrayOf<cel_runtime::ArrayOf<cel_runtime::Leaf<Celsius>>>>()?;
4814 let mut rows: Vec<Vec<i32>> = Vec::new();
4815 for row in array.into_vec() {
4816 rows.push(row.into_vec().into_iter().map(|c| c.0).collect());
4817 }
4818 assert_eq!(rows, vec![vec![0, 1], vec![2]]);
4819 Ok(())
4820 }
4821}
4822
4823#[cfg(test)]
4824mod playground {
4825 use super::*;
4826 use annotate_snippets::Renderer;
4827
4828 #[test]
4829 fn custom_scope_identifier() -> Result<()> {
4830 let mut lookup = OpLookup::new();
4831 lookup.push_scope(|name, segment, _num_operands, _span| {
4832 if name == "constant" {
4833 segment.just(42i64);
4834 return Ok(true);
4835 }
4836 Ok(false)
4837 });
4838 let mut parser = CELParser::new(lookup);
4839 let line = line!() + 1;
4840 let source = r#"
4841 (("hello" + " world") == constant) && (15i64 < constant)
4842 "#;
4843 match parser.parse_str(source) {
4844 Ok(mut seg) => println!("{:?}", seg.call0::<bool>()),
4845 Err(e) => println!(
4846 "{}",
4847 e.format_rustc_style(source, file!(), line, &Renderer::styled())
4848 ),
4849 }
4850 Ok(())
4851 }
4852 #[test]
4853 fn literal_types() {
4854 use CELParser;
4855 use op_table::OpLookup;
4856 let source = r#"
4857 b'a'
4858 "#;
4859 println!(
4860 "{:?}",
4861 CELParser::new(OpLookup::new())
4862 .parse_str(source)
4863 .unwrap()
4864 .call0::<u8>()
4865 )
4866 }
4867
4868 #[test]
4869 fn expression_macro_error3() {
4870 use CELParser;
4871 use op_table::OpLookup;
4872
4873 let line = line!() + 1;
4874 let source = r#"
4875 "Hello" + "World" + 32.0
4876 "#;
4877 match CELParser::new(OpLookup::new()).parse_str(source) {
4878 Ok(_) => panic!("expected parse error"),
4879 Err(e) => println!(
4880 "{}",
4881 e.format_rustc_style(source, file!(), line, &Renderer::styled())
4882 ),
4883 }
4884 }
4885
4886 #[test]
4887 fn arithmetic_overflow_error() {
4888 use error::FormatRustcStyle;
4889
4890 let line = line!() + 1;
4891 let source = r#"
4892 1 + 1 +
4893 2147483646 + 1
4894 "#;
4895 let mut seg = CELParser::new(OpLookup::new())
4896 .parse_str(source)
4897 .expect("parses successfully");
4898 match seg.call0::<i32>() {
4899 Ok(v) => panic!("expected overflow, got {v}"),
4900 Err(e) => println!(
4901 "{}",
4902 e.format_rustc_style(source, file!(), line, &Renderer::styled())
4903 ),
4904 }
4905 }
4906}