1pub mod ast;
335mod compile;
336pub use compile::compile_expr;
337mod error;
338mod fmt;
339pub mod lex_lexer;
340pub mod op_table;
341pub mod registered_ops;
342pub use registered_ops::{
343 OperationEmitter, OperationSignature, RecordEmitter, RecordField, RecordSchema,
344};
345pub mod parser_context;
346pub mod trivia;
347pub mod ty;
348pub mod type_expr;
349
350pub use ast::{AstContext, ClosureParam, Expr, ExprSpan, Literal, LogicalOp, RecordInit};
351pub use error::{
352 CELError, FormatRustcStyle, ParseError, SourceSpan, SpanContext, SpanLabel, format_multi_span,
353};
354pub use fmt::{
355 format_expr, format_expr_header, format_expr_header_with_layout, format_expr_restricted,
356 format_expr_with_layout,
357};
358pub use op_table::{OpLookup, OperandTypes, builtin_operand_types};
359pub use parser_context::{DynSegmentContext, ParserContext};
360pub use proc_macro2::LineColumn;
361pub use trivia::Comment;
362pub use ty::Ty;
363pub use type_expr::{
364 ResolvedArrayType, ResolvedLeafType, ResolvedType, TypeExpr, TypeResolver,
365 builtin_type_resolver, resolve_builtin_named_type,
366};
367
368use lex_lexer::{LexLexer, Literal as CelLiteral, Token, TokenStreamIter};
369
370use cel_runtime::DynSegment;
371use proc_macro2::{Delimiter, Span, TokenStream};
372#[cfg(test)]
373use std::any::TypeId;
374use std::collections::HashMap;
375use std::iter::Peekable;
376use std::str::FromStr;
377
378pub type Result<T> = std::result::Result<T, ParseError>;
383
384fn push_literal_token<C: ParserContext>(output: &mut C, lit: CelLiteral) -> Result<()> {
391 match lit {
392 CelLiteral::Int(integer) => {
393 let span = integer.span();
394 match integer.suffix() {
395 "" | "i32" => output.push_literal(
396 integer.base10_parse::<i32>().map_err(|e| {
397 ParseError::new(
398 format!("invalid i32 literal `{integer}`: {e}"),
399 integer.span(),
400 )
401 })?,
402 span,
403 ),
404 "u8" => output.push_literal(
405 integer.base10_parse::<u8>().map_err(|e| {
406 ParseError::new(
407 format!("invalid u8 literal `{integer}`: {e}"),
408 integer.span(),
409 )
410 })?,
411 span,
412 ),
413 "u16" => output.push_literal(
414 integer.base10_parse::<u16>().map_err(|e| {
415 ParseError::new(
416 format!("invalid u16 literal `{integer}`: {e}"),
417 integer.span(),
418 )
419 })?,
420 span,
421 ),
422 "u32" => output.push_literal(
423 integer.base10_parse::<u32>().map_err(|e| {
424 ParseError::new(
425 format!("invalid u32 literal `{integer}`: {e}"),
426 integer.span(),
427 )
428 })?,
429 span,
430 ),
431 "u64" => output.push_literal(
432 integer.base10_parse::<u64>().map_err(|e| {
433 ParseError::new(
434 format!("invalid u64 literal `{integer}`: {e}"),
435 integer.span(),
436 )
437 })?,
438 span,
439 ),
440 "u128" => output.push_literal(
441 integer.base10_parse::<u128>().map_err(|e| {
442 ParseError::new(
443 format!("invalid u128 literal `{integer}`: {e}"),
444 integer.span(),
445 )
446 })?,
447 span,
448 ),
449 "usize" => output.push_literal(
450 integer.base10_parse::<usize>().map_err(|e| {
451 ParseError::new(
452 format!("invalid usize literal `{integer}`: {e}"),
453 integer.span(),
454 )
455 })?,
456 span,
457 ),
458 "i8" => output.push_literal(
459 integer.base10_parse::<i8>().map_err(|e| {
460 ParseError::new(
461 format!("invalid i8 literal `{integer}`: {e}"),
462 integer.span(),
463 )
464 })?,
465 span,
466 ),
467 "i16" => output.push_literal(
468 integer.base10_parse::<i16>().map_err(|e| {
469 ParseError::new(
470 format!("invalid i16 literal `{integer}`: {e}"),
471 integer.span(),
472 )
473 })?,
474 span,
475 ),
476 "i64" => output.push_literal(
477 integer.base10_parse::<i64>().map_err(|e| {
478 ParseError::new(
479 format!("invalid i64 literal `{integer}`: {e}"),
480 integer.span(),
481 )
482 })?,
483 span,
484 ),
485 "i128" => output.push_literal(
486 integer.base10_parse::<i128>().map_err(|e| {
487 ParseError::new(
488 format!("invalid i128 literal `{integer}`: {e}"),
489 integer.span(),
490 )
491 })?,
492 span,
493 ),
494 "isize" => output.push_literal(
495 integer.base10_parse::<isize>().map_err(|e| {
496 ParseError::new(
497 format!("invalid isize literal `{integer}`: {e}"),
498 integer.span(),
499 )
500 })?,
501 span,
502 ),
503 suffix => {
504 return Err(ParseError::new(
505 format!("invalid integer literal suffix: `{suffix}`"),
506 integer.span(),
507 ));
508 }
509 };
510 }
511 CelLiteral::Float(float) => {
512 let span = float.span();
513 match float.suffix() {
514 "" | "f64" => output.push_literal(
515 float.base10_parse::<f64>().map_err(|e| {
516 ParseError::new(format!("invalid f64 literal `{float}`: {e}"), float.span())
517 })?,
518 span,
519 ),
520 "f32" => output.push_literal(
521 float.base10_parse::<f32>().map_err(|e| {
522 ParseError::new(format!("invalid f32 literal `{float}`: {e}"), float.span())
523 })?,
524 span,
525 ),
526 suffix => {
527 return Err(ParseError::new(
528 format!("invalid float literal suffix: `{suffix}`"),
529 float.span(),
530 ));
531 }
532 };
533 }
534 CelLiteral::Str(string) => {
535 let span = string.span();
536 output.push_literal(string.value(), span);
537 }
538 CelLiteral::Bool(lit_bool) => {
539 let span = lit_bool.span();
540 output.push_literal(lit_bool.value, span);
541 }
542 CelLiteral::Char(ch) => {
543 let span = ch.span();
544 output.push_literal(ch.value(), span);
545 }
546 CelLiteral::Byte(byte) => {
547 let span = byte.span();
548 output.push_literal(byte.value(), span);
549 }
550 CelLiteral::ByteStr(byte_str) => {
551 let span = byte_str.span();
552 output.push_literal(byte_str.value(), span);
553 }
554 CelLiteral::CStr(c_str) => {
555 let span = c_str.span();
556 output.push_literal(c_str.value(), span);
557 }
558 other => {
559 return Err(ParseError::new(
560 format!("unsupported literal: {other:?}"),
561 other.span(),
562 ));
563 }
564 }
565 Ok(())
566}
567
568pub fn validate_literal(lit: &CelLiteral) -> Result<()> {
588 push_literal_token(&mut DynSegmentContext::new_context(), lit.clone())
589}
590
591pub fn literal_expr(lit: &CelLiteral) -> Result<Expr> {
608 let mut context = AstContext::new_context();
609 push_literal_token(&mut context, lit.clone())?;
610 Ok(context.into_expr())
611}
612
613fn closure_param_type_from_type_expr(
619 type_expr: &TypeExpr,
620 resolver: &dyn TypeResolver,
621) -> Result<cel_runtime::ValueType> {
622 type_expr
623 .resolve(resolver)?
624 .into_value_type()
625 .map_err(|error| {
626 let span = type_expr.span();
627 ParseError::new_range(error.to_string(), span.start, span.end)
628 })
629}
630
631pub struct Parser<C: ParserContext> {
676 tokens: Option<Peekable<LexLexer>>,
677 context: C,
678 op_lookup: OpLookup,
679 type_resolver: Box<dyn TypeResolver>,
680 last_span: Span,
681 unbalanced_delimiters: i32,
687 restriction: ExpressionRestriction,
688}
689
690#[derive(Clone, Copy, Debug, PartialEq, Eq)]
703pub enum ExpressionRestriction {
704 None,
706 NoStructLiteral,
708}
709
710pub type CELParser = Parser<DynSegmentContext>;
718
719impl<C: ParserContext> Parser<C> {
720 pub fn new(op_lookup: OpLookup) -> Self {
733 Self::with_boxed_type_resolver(op_lookup, type_expr::builtin_type_resolver())
734 }
735
736 pub fn with_type_resolver<R>(op_lookup: OpLookup, type_resolver: R) -> Self
762 where
763 R: TypeResolver + 'static,
764 {
765 Self::with_boxed_type_resolver(op_lookup, Box::new(type_resolver))
766 }
767
768 fn with_boxed_type_resolver(op_lookup: OpLookup, type_resolver: Box<dyn TypeResolver>) -> Self {
770 Parser {
771 tokens: None,
772 context: C::new_context(),
773 op_lookup,
774 type_resolver,
775 last_span: Span::call_site(),
776 unbalanced_delimiters: 0,
777 restriction: ExpressionRestriction::None,
778 }
779 }
780
781 pub fn set_type_resolver<R>(&mut self, type_resolver: R)
805 where
806 R: TypeResolver + 'static,
807 {
808 self.type_resolver = Box::new(type_resolver);
809 }
810
811 pub fn resolve_type_expr(&self, expr: &TypeExpr) -> Result<ResolvedType> {
820 expr.resolve(self.type_resolver.as_ref())
821 }
822
823 pub fn set_tokens(&mut self, tokens: TokenStreamIter) {
831 self.tokens = Some(LexLexer::new(tokens).peekable());
832 self.context = C::new_context();
833 self.last_span = Span::call_site();
834 self.unbalanced_delimiters = 0;
835 }
836
837 pub fn set_lex_tokens(&mut self, tokens: std::iter::Peekable<lex_lexer::LexLexer>) {
846 self.tokens = Some(tokens);
847 self.context = C::new_context();
848 self.last_span = Span::call_site();
849 self.unbalanced_delimiters = 0;
850 }
851
852 pub fn unbalanced_delimiter_count(&self) -> i32 {
875 self.unbalanced_delimiters
876 }
877
878 pub fn parse_expression_ctx(&mut self) -> Result<C> {
893 self.parse_expression_ctx_restricted(ExpressionRestriction::None)
894 }
895
896 pub fn parse_expression_ctx_restricted(
908 &mut self,
909 restriction: ExpressionRestriction,
910 ) -> Result<C> {
911 if !self.with_restriction(restriction, |p| p.is_expression())? {
912 return Err(self.error_at("expression expected"));
913 }
914 Ok(std::mem::replace(&mut self.context, C::new_context()))
915 }
916
917 fn with_restriction<T>(
921 &mut self,
922 restriction: ExpressionRestriction,
923 parse: impl FnOnce(&mut Self) -> Result<T>,
924 ) -> Result<T> {
925 let previous = std::mem::replace(&mut self.restriction, restriction);
926 let result = parse(self);
927 self.restriction = previous;
928 result
929 }
930
931 fn is_ordinary_expression(&mut self) -> Result<bool> {
937 self.with_restriction(ExpressionRestriction::None, |p| p.is_expression())
938 }
939
940 pub fn parse_literal_pattern_ctx(&mut self) -> Result<C> {
962 if !self.is_literal_pattern()? {
963 return Err(self.error_at("literal pattern expected"));
964 }
965 Ok(std::mem::replace(&mut self.context, C::new_context()))
966 }
967
968 pub(crate) fn parse_nested_context<F>(&mut self, f: F) -> Result<C>
983 where
984 F: FnOnce(&mut Self) -> Result<bool>,
985 {
986 let outer = std::mem::replace(&mut self.context, C::new_context());
987 let outcome = f(self);
988 let nested = std::mem::replace(&mut self.context, outer);
989 match outcome {
990 Ok(true) => Ok(nested),
991 Ok(false) => Err(self.error_at("expected expression")),
992 Err(e) => Err(e),
993 }
994 }
995
996 pub fn take_lex_tokens(&mut self) -> Option<std::iter::Peekable<lex_lexer::LexLexer>> {
1004 self.tokens.take()
1005 }
1006
1007 pub fn parse_tokens_ctx(&mut self, tokens: TokenStreamIter) -> Result<C> {
1034 self.set_tokens(tokens);
1035 if !self.is_expression()? {
1036 return Err(self.error_at("expression expected"));
1037 }
1038 if self.peek_token().is_some() {
1039 return Err(self.error_at("unexpected token"));
1040 }
1041 Ok(std::mem::replace(&mut self.context, C::new_context()))
1042 }
1043
1044 pub fn parse_str_ctx(&mut self, s: &str) -> Result<C> {
1060 let input = TokenStream::from_str(s).map_err(|e| ParseError::from_lex_error(s, e))?;
1061 self.parse_tokens_ctx(input.into_iter())
1062 }
1063
1064 pub fn parse_type_expr(&mut self) -> Result<TypeExpr> {
1077 self.parse_type_expression()
1078 }
1079
1080 pub fn parse_type_expr_tokens(&mut self, tokens: TokenStreamIter) -> Result<TypeExpr> {
1089 self.set_tokens(tokens);
1090 let expr = self.parse_type_expr()?;
1091 if self.peek_token().is_some() {
1092 return Err(self.error_at("unexpected token"));
1093 }
1094 Ok(expr)
1095 }
1096
1097 pub fn parse_type_expr_str(&mut self, s: &str) -> Result<TypeExpr> {
1122 let input = TokenStream::from_str(s).map_err(|e| ParseError::from_lex_error(s, e))?;
1123 self.parse_type_expr_tokens(input.into_iter())
1124 }
1125
1126 pub fn op_lookup_mut(&mut self) -> &mut OpLookup {
1159 &mut self.op_lookup
1160 }
1161
1162 fn advance(&mut self) {
1174 use lex_lexer::HasSpan;
1175 let token = self
1176 .tokens
1177 .as_mut()
1178 .expect("tokens set")
1179 .next()
1180 .expect("token required to advance");
1181 match &token {
1182 Token::OpenDelim {
1183 delimiter: Delimiter::Brace | Delimiter::Bracket | Delimiter::Parenthesis,
1184 ..
1185 } => self.unbalanced_delimiters += 1,
1186 Token::CloseDelim {
1187 delimiter: Delimiter::Brace | Delimiter::Bracket | Delimiter::Parenthesis,
1188 ..
1189 } => self.unbalanced_delimiters -= 1,
1190 _ => {}
1191 }
1192 self.last_span = token.span();
1193 }
1194
1195 fn peek_span(&mut self) -> Option<Span> {
1197 self.peek_token().map(|token| {
1198 use lex_lexer::HasSpan;
1199 token.span()
1200 })
1201 }
1202
1203 fn peek_token(&mut self) -> Option<&Token> {
1207 self.tokens.as_mut().expect("tokens set").peek()
1208 }
1209
1210 fn error_at(&mut self, message: &str) -> ParseError {
1212 let span = match self.peek_token() {
1213 Some(token) => {
1214 use lex_lexer::HasSpan;
1215 token.span()
1216 }
1217 None => Span::call_site(),
1218 };
1219 ParseError::new(message, span)
1220 }
1221
1222 fn is_punctuation(&mut self, target: &str) -> bool {
1224 match self.peek_token() {
1225 Some(Token::Punct { op, .. }) if op == target => {
1226 self.advance();
1227 true
1228 }
1229 _ => false,
1230 }
1231 }
1232
1233 fn is_keyword(&mut self, keyword: &str) -> bool {
1235 match self.peek_token() {
1236 Some(Token::Identifier(ident)) if ident == keyword => {
1237 self.advance();
1238 true
1239 }
1240 _ => false,
1241 }
1242 }
1243
1244 fn expect_identifier(&mut self, message: &str) -> Result<String> {
1250 match self.peek_token() {
1251 Some(Token::Identifier(ident)) => {
1252 let name = ident.to_string();
1253 self.advance();
1254 Ok(name)
1255 }
1256 _ => Err(self.error_at(message)),
1257 }
1258 }
1259
1260 fn is_open_paren(&mut self) -> bool {
1262 if matches!(
1263 self.peek_token(),
1264 Some(Token::OpenDelim {
1265 delimiter: Delimiter::Parenthesis,
1266 ..
1267 })
1268 ) {
1269 self.advance();
1270 true
1271 } else {
1272 false
1273 }
1274 }
1275
1276 fn is_close_paren(&mut self) -> bool {
1278 if matches!(
1279 self.peek_token(),
1280 Some(Token::CloseDelim {
1281 delimiter: Delimiter::Parenthesis,
1282 ..
1283 })
1284 ) {
1285 self.advance();
1286 true
1287 } else {
1288 false
1289 }
1290 }
1291
1292 fn is_close_bracket(&mut self) -> bool {
1294 if matches!(
1295 self.peek_token(),
1296 Some(Token::CloseDelim {
1297 delimiter: Delimiter::Bracket,
1298 ..
1299 })
1300 ) {
1301 self.advance();
1302 true
1303 } else {
1304 false
1305 }
1306 }
1307
1308 pub fn is_expression(&mut self) -> Result<bool> {
1313 if self.is_punctuation("||") {
1314 self.is_closure_expression(true)
1315 } else if self.is_punctuation("|") {
1316 self.is_closure_expression(false)
1317 } else {
1318 self.is_range_expression()
1319 }
1320 }
1321
1322 fn is_or_expression(&mut self) -> Result<bool> {
1329 let start_span = self.peek_span();
1330 if self.is_and_expression()? {
1331 while self.is_punctuation("||") {
1332 let mut rhs_fragment = self.context.new_fragment();
1333 std::mem::swap(&mut self.context, &mut rhs_fragment);
1334 if !self.is_and_expression()? {
1335 return Err(self.error_at("expected and_expression"));
1336 }
1337 std::mem::swap(&mut self.context, &mut rhs_fragment);
1338 self.context.apply_logical(
1339 "||",
1340 rhs_fragment,
1341 start_span.expect("production has token at start"),
1342 self.last_span,
1343 )?;
1344 }
1345 Ok(true)
1346 } else {
1347 Ok(false)
1348 }
1349 }
1350
1351 fn is_and_expression(&mut self) -> Result<bool> {
1358 let start_span = self.peek_span();
1359 if self.is_comparison_expression()? {
1360 while self.is_punctuation("&&") {
1361 let mut rhs_fragment = self.context.new_fragment();
1362 std::mem::swap(&mut self.context, &mut rhs_fragment);
1363 if !self.is_comparison_expression()? {
1364 return Err(self.error_at("expected comparison_expression"));
1365 }
1366 std::mem::swap(&mut self.context, &mut rhs_fragment);
1367 self.context.apply_logical(
1368 "&&",
1369 rhs_fragment,
1370 start_span.expect("production has token at start"),
1371 self.last_span,
1372 )?;
1373 }
1374 Ok(true)
1375 } else {
1376 Ok(false)
1377 }
1378 }
1379
1380 fn is_comparison_expression(&mut self) -> Result<bool> {
1383 let start_span = self.peek_span();
1384 if self.is_bitwise_or_expression()? {
1385 let op_name = if self.is_punctuation("==") {
1387 Some("==")
1388 } else if self.is_punctuation("!=") {
1389 Some("!=")
1390 } else if self.is_punctuation("<=") {
1391 Some("<=")
1392 } else if self.is_punctuation(">=") {
1393 Some(">=")
1394 } else if self.is_punctuation("<") {
1395 Some("<")
1396 } else if self.is_punctuation(">") {
1397 Some(">")
1398 } else {
1399 None
1400 };
1401
1402 if let Some(op_name) = op_name {
1403 if !self.is_bitwise_or_expression()? {
1404 return Err(self.error_at("expected bitwise_or_expression"));
1405 }
1406 self.context.apply_op(
1407 &self.op_lookup,
1408 op_name,
1409 2,
1410 start_span.expect("production has token at start"),
1411 self.last_span,
1412 )?;
1413 }
1414 Ok(true)
1415 } else {
1416 Ok(false)
1417 }
1418 }
1419
1420 fn is_range_expression(&mut self) -> Result<bool> {
1444 let start_span = self.peek_span();
1445
1446 if self.is_punctuation("..=") {
1447 if !self.is_or_expression()? {
1448 return Err(self.error_at("expected or_expression"));
1449 }
1450 self.context.apply_op(
1451 &self.op_lookup,
1452 "range_to_inclusive",
1453 1,
1454 start_span.expect("production has token at start"),
1455 self.last_span,
1456 )?;
1457 return Ok(true);
1458 }
1459
1460 if self.is_punctuation("..") {
1461 if self.is_or_expression()? {
1462 self.context.apply_op(
1463 &self.op_lookup,
1464 "range_to",
1465 1,
1466 start_span.expect("production has token at start"),
1467 self.last_span,
1468 )?;
1469 } else {
1470 self.context.apply_op(
1471 &self.op_lookup,
1472 "range_full",
1473 0,
1474 start_span.expect("production has token at start"),
1475 self.last_span,
1476 )?;
1477 }
1478 return Ok(true);
1479 }
1480
1481 if self.is_or_expression()? {
1482 if self.is_punctuation("..=") {
1483 if !self.is_or_expression()? {
1484 return Err(self.error_at("expected or_expression"));
1485 }
1486 self.context.apply_op(
1487 &self.op_lookup,
1488 "range_inclusive",
1489 2,
1490 start_span.expect("production has token at start"),
1491 self.last_span,
1492 )?;
1493 } else if self.is_punctuation("..") {
1494 if self.is_or_expression()? {
1495 self.context.apply_op(
1496 &self.op_lookup,
1497 "range",
1498 2,
1499 start_span.expect("production has token at start"),
1500 self.last_span,
1501 )?;
1502 } else {
1503 self.context.apply_op(
1504 &self.op_lookup,
1505 "range_from",
1506 1,
1507 start_span.expect("production has token at start"),
1508 self.last_span,
1509 )?;
1510 }
1511 }
1512 Ok(true)
1513 } else {
1514 Ok(false)
1515 }
1516 }
1517
1518 fn is_bitwise_or_expression(&mut self) -> Result<bool> {
1520 let start_span = self.peek_span();
1521 if self.is_bitwise_xor_expression()? {
1522 while self.is_punctuation("|") {
1523 if !self.is_bitwise_xor_expression()? {
1524 return Err(self.error_at("expected bitwise_xor_expression"));
1525 }
1526 self.context.apply_op(
1527 &self.op_lookup,
1528 "|",
1529 2,
1530 start_span.expect("production has token at start"),
1531 self.last_span,
1532 )?;
1533 }
1534 Ok(true)
1535 } else {
1536 Ok(false)
1537 }
1538 }
1539
1540 fn is_bitwise_xor_expression(&mut self) -> Result<bool> {
1542 let start_span = self.peek_span();
1543 if self.is_bitwise_and_expression()? {
1544 while self.is_punctuation("^") {
1545 if !self.is_bitwise_and_expression()? {
1546 return Err(self.error_at("expected bitwise_and_expression"));
1547 }
1548 self.context.apply_op(
1549 &self.op_lookup,
1550 "^",
1551 2,
1552 start_span.expect("production has token at start"),
1553 self.last_span,
1554 )?;
1555 }
1556 Ok(true)
1557 } else {
1558 Ok(false)
1559 }
1560 }
1561
1562 fn is_bitwise_and_expression(&mut self) -> Result<bool> {
1564 let start_span = self.peek_span();
1565 if self.is_bitwise_shift_expression()? {
1566 while self.is_punctuation("&") {
1567 if !self.is_bitwise_shift_expression()? {
1568 return Err(self.error_at("expected bitwise_shift_expression"));
1569 }
1570 self.context.apply_op(
1571 &self.op_lookup,
1572 "&",
1573 2,
1574 start_span.expect("production has token at start"),
1575 self.last_span,
1576 )?;
1577 }
1578 Ok(true)
1579 } else {
1580 Ok(false)
1581 }
1582 }
1583
1584 fn is_bitwise_shift_expression(&mut self) -> Result<bool> {
1586 let start_span = self.peek_span();
1587 if self.is_additive_expression()? {
1588 loop {
1589 let op_name = if self.is_punctuation("<<") {
1590 Some("<<")
1591 } else if self.is_punctuation(">>") {
1592 Some(">>")
1593 } else {
1594 None
1595 };
1596
1597 if let Some(op_name) = op_name {
1598 if !self.is_additive_expression()? {
1599 return Err(self.error_at("expected additive_expression"));
1600 }
1601 self.context.apply_op(
1602 &self.op_lookup,
1603 op_name,
1604 2,
1605 start_span.expect("production has token at start"),
1606 self.last_span,
1607 )?;
1608 } else {
1609 break;
1610 }
1611 }
1612 Ok(true)
1613 } else {
1614 Ok(false)
1615 }
1616 }
1617
1618 fn is_additive_expression(&mut self) -> Result<bool> {
1620 let start_span = self.peek_span();
1621 if self.is_multiplicative_expression()? {
1622 loop {
1623 let op_name = if self.is_punctuation("+") {
1624 Some("+")
1625 } else if self.is_punctuation("-") {
1626 Some("-")
1627 } else {
1628 None
1629 };
1630
1631 if let Some(op_name) = op_name {
1632 if !self.is_multiplicative_expression()? {
1633 return Err(self.error_at("expected multiplicative_expression"));
1634 }
1635 self.context.apply_op(
1636 &self.op_lookup,
1637 op_name,
1638 2,
1639 start_span.expect("production has token at start"),
1640 self.last_span,
1641 )?;
1642 } else {
1643 break;
1644 }
1645 }
1646 Ok(true)
1647 } else {
1648 Ok(false)
1649 }
1650 }
1651
1652 fn is_multiplicative_expression(&mut self) -> Result<bool> {
1654 let start_span = self.peek_span();
1655 if self.is_cast_expression()? {
1656 loop {
1657 let op_name = if self.is_punctuation("*") {
1658 Some("*")
1659 } else if self.is_punctuation("/") {
1660 Some("/")
1661 } else if self.is_punctuation("%") {
1662 Some("%")
1663 } else {
1664 None
1665 };
1666
1667 if let Some(op_name) = op_name {
1668 if !self.is_cast_expression()? {
1669 return Err(self.error_at("expected cast_expression"));
1670 }
1671 self.context.apply_op(
1672 &self.op_lookup,
1673 op_name,
1674 2,
1675 start_span.expect("production has token at start"),
1676 self.last_span,
1677 )?;
1678 } else {
1679 break;
1680 }
1681 }
1682 Ok(true)
1683 } else {
1684 Ok(false)
1685 }
1686 }
1687
1688 fn is_cast_expression(&mut self) -> Result<bool> {
1698 let start_span = self.peek_span();
1699 if self.is_unary_expression()? {
1700 while self.is_keyword("as") {
1701 let type_name = match self.peek_token() {
1702 Some(Token::Identifier(ident)) => ident.to_string(),
1703 _ => return Err(self.error_at("expected type name after `as`")),
1704 };
1705 self.advance();
1706 self.context.apply_cast(
1707 &self.op_lookup,
1708 &type_name,
1709 start_span.expect("production has token at start"),
1710 self.last_span,
1711 )?;
1712 }
1713 Ok(true)
1714 } else {
1715 Ok(false)
1716 }
1717 }
1718
1719 fn is_unary_expression(&mut self) -> Result<bool> {
1721 let start_span = self.peek_span();
1722 let op_name = if self.is_punctuation("-") {
1723 Some("-")
1724 } else if self.is_punctuation("!") {
1725 Some("!")
1726 } else {
1727 None
1728 };
1729
1730 if let Some(op_name) = op_name {
1731 if !self.is_unary_expression()? {
1732 return Err(self.error_at("expected unary_expression"));
1733 }
1734 self.context.apply_op(
1735 &self.op_lookup,
1736 op_name,
1737 1,
1738 start_span.expect("production has token at start"),
1739 self.last_span,
1740 )?;
1741 Ok(true)
1742 } else {
1743 self.is_postfix_expression()
1744 }
1745 }
1746
1747 fn is_literal_pattern(&mut self) -> Result<bool> {
1759 let start_span = self.peek_span();
1760 let negated = self.is_punctuation("-");
1761 match self.peek_token() {
1762 Some(Token::Literal(lit)) => {
1763 let lit_clone = lit.clone();
1764 self.advance();
1765 push_literal_token(&mut self.context, lit_clone)?;
1766 if negated {
1767 self.context.apply_op(
1768 &self.op_lookup,
1769 "-",
1770 1,
1771 start_span.expect("production has token at start"),
1772 self.last_span,
1773 )?;
1774 }
1775 Ok(true)
1776 }
1777 _ if negated => Err(self.error_at("expected literal after `-`")),
1778 _ => Ok(false),
1779 }
1780 }
1781
1782 fn is_postfix_expression(&mut self) -> Result<bool> {
1800 let start_span = self.peek_span();
1801 if !self.is_primary_expression()? {
1802 return Ok(false);
1803 }
1804 loop {
1805 if let Some(arg_count) = self.postfix_arguments()? {
1806 self.context.apply_op(
1808 &self.op_lookup,
1809 "()",
1810 arg_count + 1,
1811 start_span.expect("production has token at start"),
1812 self.last_span,
1813 )?;
1814 } else if self.is_punctuation(".") {
1815 match self.peek_token() {
1816 Some(Token::Identifier(_)) => {
1817 let name_start = self.peek_span().expect("member has a name token");
1818 let name = self.expect_identifier("expected member name")?;
1819 let name_span = ExprSpan {
1820 start: name_start,
1821 end: name_start,
1822 };
1823 let explicit_args = self.postfix_arguments()?;
1824 self.context.apply_member(
1825 &self.op_lookup,
1826 &name,
1827 name_span,
1828 explicit_args,
1829 start_span.expect("production has token at start"),
1830 self.last_span,
1831 )?;
1832 }
1833 Some(Token::Literal(CelLiteral::Int(integer))) => {
1834 let integer = integer.clone();
1835 if !integer.suffix().is_empty() {
1836 return Err(self.error_at("tuple index must be an unsuffixed integer"));
1837 }
1838 self.advance();
1839 let index = integer.base10_parse::<usize>().map_err(|e| {
1840 ParseError::new(
1841 format!("invalid tuple index `{integer}`: {e}"),
1842 integer.span(),
1843 )
1844 })?;
1845 self.apply_tuple_index(
1846 index,
1847 start_span.expect("production has token at start"),
1848 )?;
1849 }
1850 Some(Token::Literal(CelLiteral::Float(float))) => {
1851 let float = float.clone();
1852 if !float.suffix().is_empty() {
1853 return Err(self.error_at("tuple index must be an unsuffixed integer"));
1854 }
1855 let digits = float.base10_digits();
1864 let Some((first, second)) = digits.split_once('.') else {
1865 return Err(self.error_at(
1866 "tuple index chain must use decimal notation (e.g. `.0.1`)",
1867 ));
1868 };
1869 self.advance();
1870 let first_index = first.parse::<usize>().map_err(|e| {
1871 ParseError::new(
1872 format!("invalid tuple index `{first}`: {e}"),
1873 float.span(),
1874 )
1875 })?;
1876 let second_index = second.parse::<usize>().map_err(|e| {
1877 ParseError::new(
1878 format!("invalid tuple index `{second}`: {e}"),
1879 float.span(),
1880 )
1881 })?;
1882 let idx_start = start_span.expect("production has token at start");
1883 self.apply_tuple_index(first_index, idx_start)?;
1884 self.apply_tuple_index(second_index, idx_start)?;
1885 }
1886 _ => return Err(self.error_at("expected integer or member name after '.'")),
1887 }
1888 } else {
1889 break;
1890 }
1891 }
1892 Ok(true)
1893 }
1894
1895 fn postfix_arguments(&mut self) -> Result<Option<usize>> {
1904 if !self.is_open_paren() {
1905 return Ok(None);
1906 }
1907 if self.is_close_paren() {
1908 return Ok(Some(0));
1909 }
1910 let count = self.parameter_list()?;
1911 if !self.is_close_paren() {
1912 return Err(self.error_at("expected closing parenthesis"));
1913 }
1914 Ok(Some(count))
1915 }
1916
1917 fn apply_tuple_index(&mut self, index: usize, start: Span) -> Result<()> {
1923 self.context.tuple_index(index, start, self.last_span)?;
1924 Ok(())
1925 }
1926
1927 fn parameter_list(&mut self) -> Result<usize> {
1939 if !self.is_ordinary_expression()? {
1940 return Err(self.error_at("expected expression"));
1941 }
1942 let mut count = 1;
1943 while self.is_punctuation(",") {
1944 if !self.is_ordinary_expression()? {
1945 return Err(self.error_at("expected expression after comma"));
1946 }
1947 count += 1;
1948 }
1949 Ok(count)
1950 }
1951
1952 fn is_primary_expression(&mut self) -> Result<bool> {
1969 match self.peek_token() {
1970 Some(Token::Literal(lit)) => {
1971 let lit_clone = lit.clone();
1972 self.advance();
1973 push_literal_token(&mut self.context, lit_clone)?;
1974 Ok(true)
1975 }
1976 Some(Token::Identifier(ident)) => {
1977 let ident_name = ident.to_string();
1978 let ident_span = ident.span();
1979 self.advance();
1980
1981 if ident_name == "if" {
1982 return self.is_if_expression(ident_span);
1983 }
1984 if matches!(ident_name.as_str(), "else" | "as") {
1985 return Err(ParseError::new(
1986 "reserved keyword is not a value name",
1987 ident_span,
1988 ));
1989 }
1990
1991 if self.restriction == ExpressionRestriction::None
1992 && matches!(
1993 self.peek_token(),
1994 Some(Token::OpenDelim {
1995 delimiter: Delimiter::Brace,
1996 ..
1997 })
1998 )
1999 {
2000 return self.is_record_fields(&ident_name, ident_span);
2001 }
2002
2003 self.context
2004 .apply_op(&self.op_lookup, &ident_name, 0, ident_span, ident_span)?;
2005
2006 Ok(true)
2007 }
2008 Some(Token::OpenDelim {
2009 delimiter: Delimiter::Parenthesis,
2010 ..
2011 }) => self.is_tuple_or_group(),
2012 Some(Token::OpenDelim {
2013 delimiter: Delimiter::Bracket,
2014 ..
2015 }) => self.is_array_expression(),
2016 _ => Ok(false),
2017 }
2018 }
2019
2020 fn is_record_fields(&mut self, name: &str, name_token: Span) -> Result<bool> {
2029 self.advance();
2030 let ambient_start = self.context.current_stack_offset();
2031 let mut fields = Vec::new();
2032 if !matches!(
2033 self.peek_token(),
2034 Some(Token::CloseDelim {
2035 delimiter: Delimiter::Brace,
2036 ..
2037 })
2038 ) {
2039 loop {
2040 let Some(Token::Identifier(field)) = self.peek_token() else {
2041 return Err(self.error_at("expected record field name"));
2042 };
2043 let field_name = field.to_string();
2044 let field_span = field.span();
2045 self.advance();
2046 if !self.is_punctuation(":") {
2047 return Err(self.error_at("expected `:` after record field name"));
2048 }
2049 if !self.is_ordinary_expression()? {
2050 return Err(self.error_at("expected record field expression"));
2051 }
2052 fields.push((
2053 field_name,
2054 ExprSpan {
2055 start: field_span,
2056 end: field_span,
2057 },
2058 ));
2059 if !self.is_punctuation(",") {
2060 break;
2061 }
2062 }
2063 }
2064 if !matches!(
2065 self.peek_token(),
2066 Some(Token::CloseDelim {
2067 delimiter: Delimiter::Brace,
2068 ..
2069 })
2070 ) {
2071 return Err(self.error_at("expected `,` or `}` after record field"));
2072 }
2073 self.advance();
2074 self.context.make_record(
2075 &self.op_lookup,
2076 name,
2077 ExprSpan {
2078 start: name_token,
2079 end: name_token,
2080 },
2081 fields,
2082 ambient_start,
2083 name_token,
2084 self.last_span,
2085 )?;
2086 Ok(true)
2087 }
2088
2089 fn is_tuple_or_group(&mut self) -> Result<bool> {
2101 let open_span = self
2102 .peek_span()
2103 .expect("tuple_or_group requires an opening '(' token");
2104 self.advance();
2105 if matches!(
2107 self.peek_token(),
2108 Some(Token::CloseDelim {
2109 delimiter: Delimiter::Parenthesis,
2110 ..
2111 })
2112 ) {
2113 self.advance();
2114 self.context.make_tuple(
2115 0,
2116 self.context.current_stack_offset(),
2117 open_span,
2118 self.last_span,
2119 )?;
2120 return Ok(true);
2121 }
2122 let ambient_start = self.context.current_stack_offset();
2123 if !self.is_ordinary_expression()? {
2124 return Err(self.error_at("expected expression"));
2125 }
2126 if matches!(
2127 self.peek_token(),
2128 Some(Token::CloseDelim {
2129 delimiter: Delimiter::Parenthesis,
2130 ..
2131 })
2132 ) {
2133 self.advance();
2135 return Ok(true);
2136 }
2137 if !self.is_punctuation(",") {
2138 return Err(self.error_at("expected ',' or closing parenthesis"));
2139 }
2140 let mut count = 1;
2141 if matches!(
2142 self.peek_token(),
2143 Some(Token::CloseDelim {
2144 delimiter: Delimiter::Parenthesis,
2145 ..
2146 })
2147 ) {
2148 self.advance();
2150 self.context
2151 .make_tuple(count, ambient_start, open_span, self.last_span)?;
2152 return Ok(true);
2153 }
2154 loop {
2155 if !self.is_ordinary_expression()? {
2156 return Err(self.error_at("expected expression after ','"));
2157 }
2158 count += 1;
2159 if matches!(
2160 self.peek_token(),
2161 Some(Token::CloseDelim {
2162 delimiter: Delimiter::Parenthesis,
2163 ..
2164 })
2165 ) {
2166 self.advance();
2167 break;
2168 }
2169 if !self.is_punctuation(",") {
2170 return Err(self.error_at("expected ',' or closing parenthesis"));
2171 }
2172 }
2173 self.context
2174 .make_tuple(count, ambient_start, open_span, self.last_span)?;
2175 Ok(true)
2176 }
2177
2178 fn is_array_expression(&mut self) -> Result<bool> {
2197 let open_span = self
2198 .peek_span()
2199 .expect("array_expression requires an opening '[' token");
2200 self.advance();
2201 let ambient_start = self.context.current_stack_offset();
2202 let mut count = 0usize;
2203 if !self.is_close_bracket() {
2204 if !self.is_ordinary_expression()? {
2205 return Err(self.error_at("expected expression"));
2206 }
2207 count = 1;
2208 loop {
2209 if self.is_close_bracket() {
2210 break;
2211 }
2212 if !self.is_punctuation(",") {
2213 return Err(self.error_at("expected ',' or closing ']'"));
2214 }
2215 if !self.is_ordinary_expression()? {
2218 return Err(self.error_at("expected expression after ','"));
2219 }
2220 count += 1;
2221 }
2222 }
2223
2224 let mut type_annotation = None;
2225 let mut annotation_span = None;
2226 if self.is_punctuation(":") {
2227 let colon_span = self.last_span;
2228 let annotation = self.parse_type_expression()?;
2229 let annotation_end = annotation.span().end;
2230 annotation_span = Some(ExprSpan {
2231 start: colon_span,
2232 end: annotation_end,
2233 });
2234 type_annotation = Some(annotation);
2235 }
2236
2237 if count == 0 && type_annotation.is_none() {
2238 return Err(ParseError::new_range(
2239 "an empty array literal has no inferable element type; \
2240 see https://github.com/stlab/cel-rs/issues/212"
2241 .to_string(),
2242 open_span,
2243 self.last_span,
2244 ));
2245 }
2246
2247 let type_resolver = self.type_resolver.as_ref();
2248 let mut resolve_array_type = |type_expr: &TypeExpr| {
2249 let resolved = type_expr.resolve(type_resolver)?;
2250 ResolvedArrayType::from_resolved_type(resolved, type_expr.span())
2251 };
2252 self.context.make_annotated_array(
2253 count,
2254 ambient_start,
2255 parser_context::AnnotatedArray::new(
2256 &mut resolve_array_type,
2257 type_annotation,
2258 annotation_span,
2259 ),
2260 open_span,
2261 self.last_span,
2262 )?;
2263 Ok(true)
2264 }
2265
2266 pub fn parse_type_expression(&mut self) -> Result<TypeExpr> {
2283 if let Some(Token::Identifier(_)) = self.peek_token() {
2284 let name = self.expect_identifier("expected a type name")?;
2285 let name_span = self.last_span;
2286 let mut args = Vec::new();
2287 let mut end_span = name_span;
2288 if self.is_open_paren() {
2289 if !self.is_close_paren() {
2290 args.push(self.parse_type_expression()?);
2291 while self.is_punctuation(",") {
2292 args.push(self.parse_type_expression()?);
2293 }
2294 if !self.is_close_paren() {
2295 return Err(
2296 self.error_at("expected ',' or closing ')' in type argument list")
2297 );
2298 }
2299 }
2300 end_span = self.last_span;
2301 }
2302 return Ok(TypeExpr::Named {
2303 name,
2304 args,
2305 span: ExprSpan {
2306 start: name_span,
2307 end: end_span,
2308 },
2309 });
2310 }
2311
2312 if matches!(
2313 self.peek_token(),
2314 Some(Token::OpenDelim {
2315 delimiter: Delimiter::Bracket,
2316 ..
2317 })
2318 ) {
2319 let open_span = self
2320 .peek_span()
2321 .expect("array type expression requires an opening '[' token");
2322 self.advance();
2323 if self.is_close_bracket() {
2324 return Err(ParseError::new_range(
2325 "expected a type expression after '['".to_string(),
2326 open_span,
2327 self.last_span,
2328 ));
2329 }
2330 let element = self.parse_type_expression()?;
2331 if !self.is_close_bracket() {
2332 return Err(self.error_at("expected closing ']' after array type expression"));
2333 }
2334 return Ok(TypeExpr::Array {
2335 element: Box::new(element),
2336 span: ExprSpan {
2337 start: open_span,
2338 end: self.last_span,
2339 },
2340 });
2341 }
2342
2343 if !self.is_open_paren() {
2344 return Err(self.error_at("expected a type name, '[' or '('"));
2345 }
2346 let open_span = self.last_span;
2347 if self.is_close_paren() {
2348 return Ok(TypeExpr::Tuple {
2349 elements: Vec::new(),
2350 span: ExprSpan {
2351 start: open_span,
2352 end: self.last_span,
2353 },
2354 });
2355 }
2356
2357 let first = self.parse_type_expression()?;
2358 if self.is_close_paren() {
2359 let span = ExprSpan {
2360 start: open_span,
2361 end: self.last_span,
2362 };
2363 return Ok(match first {
2364 TypeExpr::Named { name, args, .. } => TypeExpr::Named { name, args, span },
2365 TypeExpr::Array { element, .. } => TypeExpr::Array { element, span },
2366 TypeExpr::Tuple { elements, .. } => TypeExpr::Tuple { elements, span },
2367 });
2368 }
2369 if !self.is_punctuation(",") {
2370 return Err(self.error_at("expected ',' or closing ')'"));
2371 }
2372 if self.is_close_paren() {
2373 return Ok(TypeExpr::Tuple {
2374 elements: vec![first],
2375 span: ExprSpan {
2376 start: open_span,
2377 end: self.last_span,
2378 },
2379 });
2380 }
2381 let mut elements = vec![first];
2382 loop {
2383 elements.push(self.parse_type_expression()?);
2384 if self.is_close_paren() {
2385 break;
2386 }
2387 if !self.is_punctuation(",") {
2388 return Err(self.error_at("expected ',' or closing ')'"));
2389 }
2390 }
2391 Ok(TypeExpr::Tuple {
2392 elements,
2393 span: ExprSpan {
2394 start: open_span,
2395 end: self.last_span,
2396 },
2397 })
2398 }
2399
2400 fn is_closure_expression(&mut self, params_already_closed: bool) -> Result<bool> {
2431 let start_span = self.last_span;
2432 let mut params: Vec<(String, Span, Option<cel_runtime::ValueType>, TypeExpr)> = Vec::new();
2433 if !params_already_closed {
2434 loop {
2435 let name = self.expect_identifier("expected closure parameter name")?;
2436 let name_span = self.last_span;
2437 if !self.is_punctuation(":") {
2438 return Err(self.error_at("expected ':' after closure parameter name"));
2439 }
2440 let ty_ast = self.parse_type_expression()?;
2441 let ty = if C::resolves_closure_types() {
2442 Some(closure_param_type_from_type_expr(
2443 &ty_ast,
2444 self.type_resolver.as_ref(),
2445 )?)
2446 } else {
2447 None
2448 };
2449 params.push((name, name_span, ty, ty_ast));
2450 if self.is_punctuation(",") {
2451 continue;
2452 }
2453 break;
2454 }
2455 if !self.is_punctuation("|") {
2456 return Err(self.error_at("expected ',' or closing '|'"));
2457 }
2458 }
2459
2460 let mut param_types = Vec::with_capacity(params.len());
2461 let mut ast_params = Vec::with_capacity(params.len());
2462 let mut param_table = HashMap::with_capacity(params.len());
2463 for (index, (name, name_span, ty, ty_ast)) in params.into_iter().enumerate() {
2465 if let Some(ty) = &ty {
2466 param_types.push(ty.clone());
2467 }
2468 ast_params.push(ClosureParam {
2469 name: name.clone(),
2470 name_span: ExprSpan {
2471 start: name_span,
2472 end: name_span,
2473 },
2474 type_expr: ty_ast,
2475 });
2476 param_table.insert(name, (index, ty));
2477 }
2478 if let Some(error) = ast::closure_parameter_diagnostics(&ast_params)
2479 .into_iter()
2480 .next()
2481 {
2482 return Err(error);
2483 }
2484 let isolated = self.op_lookup.isolate_scopes();
2485 self.op_lookup
2486 .push_scope(move |name, segment, arity, _span| {
2487 if arity != 0 {
2488 return Ok(false);
2489 }
2490 let Some((idx, ty)) = param_table.get(name) else {
2491 return Ok(false);
2492 };
2493 if let Some(ty) = ty {
2494 ty.push_argument(segment, *idx)?;
2495 }
2496 Ok(true)
2497 });
2498
2499 let body_result = self.parse_nested_context(|p| p.is_expression());
2500 self.op_lookup.pop_scope();
2501 self.op_lookup.restore_scopes(isolated);
2502 let body = body_result?;
2503
2504 self.context
2505 .push_closure(param_types, ast_params, body, start_span)?;
2506 Ok(true)
2507 }
2508
2509 fn is_if_expression(&mut self, if_span: Span) -> Result<bool> {
2522 if !self.with_restriction(ExpressionRestriction::NoStructLiteral, |p| {
2523 p.is_expression()
2524 })? {
2525 return Err(self.error_at("expected condition after `if`"));
2526 }
2527 match self.peek_token() {
2528 Some(Token::OpenDelim {
2529 delimiter: Delimiter::Brace,
2530 ..
2531 }) => {
2532 self.advance();
2533 }
2534 _ => return Err(self.error_at("expected `{` after if condition")),
2535 }
2536 let mut then_fragment = self.context.new_fragment();
2537 std::mem::swap(&mut self.context, &mut then_fragment);
2538 if !self.is_ordinary_expression()? {
2539 return Err(self.error_at("expected expression in then-branch"));
2540 }
2541 std::mem::swap(&mut self.context, &mut then_fragment);
2542 match self.peek_token() {
2543 Some(Token::CloseDelim {
2544 delimiter: Delimiter::Brace,
2545 ..
2546 }) => {
2547 self.advance();
2548 }
2549 _ => return Err(self.error_at("expected `}` after then-branch")),
2550 }
2551 let else_fragment = if self.is_keyword("else") {
2552 if self.is_keyword("if") {
2553 let elif_span = self.last_span;
2555 let mut fragment = self.context.new_fragment();
2556 std::mem::swap(&mut self.context, &mut fragment);
2557 self.is_if_expression(elif_span)?;
2558 std::mem::swap(&mut self.context, &mut fragment);
2559 Some(fragment)
2560 } else {
2561 match self.peek_token() {
2563 Some(Token::OpenDelim {
2564 delimiter: Delimiter::Brace,
2565 ..
2566 }) => {
2567 self.advance();
2568 }
2569 _ => return Err(self.error_at("expected `{` or `if` after `else`")),
2570 }
2571 let mut fragment = self.context.new_fragment();
2572 std::mem::swap(&mut self.context, &mut fragment);
2573 if !self.is_ordinary_expression()? {
2574 return Err(self.error_at("expected expression in else-branch"));
2575 }
2576 std::mem::swap(&mut self.context, &mut fragment);
2577 match self.peek_token() {
2578 Some(Token::CloseDelim {
2579 delimiter: Delimiter::Brace,
2580 ..
2581 }) => {
2582 self.advance();
2583 }
2584 _ => return Err(self.error_at("expected `}` after else-branch")),
2585 }
2586 Some(fragment)
2587 }
2588 } else {
2589 None
2593 };
2594 self.context
2595 .join2(then_fragment, else_fragment, if_span, self.last_span)
2596 .map_err(|e| ParseError::new_range(e.to_string(), if_span, self.last_span))?;
2597 Ok(true)
2598 }
2599}
2600
2601impl Parser<DynSegmentContext> {
2602 pub fn parse_expression(&mut self) -> Result<DynSegment> {
2616 self.parse_expression_ctx()
2617 .map(DynSegmentContext::into_inner)
2618 }
2619
2620 pub fn parse_expression_restricted(
2630 &mut self,
2631 restriction: ExpressionRestriction,
2632 ) -> Result<DynSegment> {
2633 self.parse_expression_ctx_restricted(restriction)
2634 .map(DynSegmentContext::into_inner)
2635 }
2636
2637 pub fn parse_literal_pattern(&mut self) -> Result<DynSegment> {
2648 self.parse_literal_pattern_ctx()
2649 .map(DynSegmentContext::into_inner)
2650 }
2651
2652 pub fn parse_tokens(&mut self, tokens: TokenStreamIter) -> Result<DynSegment> {
2673 self.parse_tokens_ctx(tokens)
2674 .map(DynSegmentContext::into_inner)
2675 }
2676
2677 pub fn parse_str(&mut self, s: &str) -> Result<DynSegment> {
2695 self.parse_str_ctx(s).map(DynSegmentContext::into_inner)
2696 }
2697}
2698
2699impl Parser<AstContext> {
2700 pub fn parse_expression_ast(&mut self) -> Result<Expr> {
2715 self.parse_expression_ctx().map(AstContext::into_expr)
2716 }
2717
2718 pub fn parse_tokens_ast(&mut self, tokens: TokenStreamIter) -> Result<Expr> {
2741 self.parse_tokens_ctx(tokens).map(AstContext::into_expr)
2742 }
2743
2744 pub fn parse_str_ast(&mut self, s: &str) -> Result<Expr> {
2765 self.parse_str_ctx(s).map(AstContext::into_expr)
2766 }
2767}
2768
2769#[cfg(test)]
2770mod tests {
2771 use super::*;
2772 use annotate_snippets::Renderer;
2773
2774 #[test]
2775 fn simple_expression() {
2776 let mut parser = CELParser::new(OpLookup::new());
2777 let result = parser.parse_str("10");
2778 assert!(result.is_ok());
2779 assert_eq!(result.unwrap().call0::<i32>().unwrap(), 10);
2780 }
2781
2782 #[test]
2783 fn parse_nested_context_compiles_an_independent_segment_without_disturbing_the_outer_one()
2784 -> anyhow::Result<()> {
2785 let mut parser = CELParser::new(OpLookup::new());
2786 parser.set_tokens(quote::quote! { 1 + 2 }.into_iter());
2787 parser
2789 .context
2790 .push_literal(100i32, proc_macro2::Span::call_site());
2791
2792 let nested = parser
2793 .parse_nested_context(|p| p.is_or_expression())
2794 .map_err(|e| anyhow::anyhow!("{}", e))?;
2795
2796 assert_eq!(parser.context.into_inner().call0::<i32>()?, 100);
2798 assert_eq!(nested.into_inner().call0::<i32>()?, 3);
2800 Ok(())
2801 }
2802
2803 #[test]
2804 fn unbalanced_delimiter_count_is_zero_before_any_parse() {
2805 let parser = CELParser::new(OpLookup::new());
2806 assert_eq!(parser.unbalanced_delimiter_count(), 0);
2807 }
2808
2809 #[test]
2810 fn unbalanced_delimiter_count_is_zero_after_a_successful_parse() {
2811 let mut parser = CELParser::new(OpLookup::new());
2812 parser.parse_str("(1 + 2)").unwrap();
2813 assert_eq!(parser.unbalanced_delimiter_count(), 0);
2814 }
2815
2816 #[test]
2817 fn unbalanced_delimiter_count_reports_a_brace_left_dangling_by_a_failed_if_expression() {
2818 let mut parser = CELParser::new(OpLookup::new());
2819 let err = match parser.parse_str("if true { }") {
2820 Err(e) => e,
2821 Ok(_) => panic!("an empty then-branch must fail to parse"),
2822 };
2823 assert!(err.message().contains("then-branch"));
2824 assert_eq!(parser.unbalanced_delimiter_count(), 1);
2825 }
2826
2827 #[test]
2828 fn unbalanced_delimiter_count_reports_a_paren_left_dangling_by_a_failed_tuple_literal() {
2829 let mut parser = CELParser::new(OpLookup::new());
2830 if parser.parse_str("(+)").is_ok() {
2831 panic!("`+` alone cannot start an expression");
2832 }
2833 assert_eq!(parser.unbalanced_delimiter_count(), 1);
2834 }
2835
2836 #[test]
2837 fn unbalanced_delimiter_count_resets_when_a_new_parse_begins() {
2838 let mut parser = CELParser::new(OpLookup::new());
2839 if parser.parse_str("(+)").is_ok() {
2840 panic!("`+` alone cannot start an expression");
2841 }
2842 assert_eq!(parser.unbalanced_delimiter_count(), 1);
2843 parser.parse_str("1 + 2").unwrap();
2844 assert_eq!(parser.unbalanced_delimiter_count(), 0);
2845 }
2846
2847 #[test]
2848 fn integer_literal_i32_suffix() {
2849 let mut parser = CELParser::new(OpLookup::new());
2850 let result = parser.parse_str("10i32");
2851 assert!(result.is_ok());
2852 assert_eq!(result.unwrap().call0::<i32>().unwrap(), 10);
2853 }
2854
2855 #[test]
2856 fn invalid_integer_suffix() {
2857 let mut parser = CELParser::new(OpLookup::new());
2858 let err = match parser.parse_str("10xyz") {
2859 Err(e) => e,
2860 Ok(_) => panic!("expected parse error for invalid integer suffix"),
2861 };
2862 assert!(err.message().contains("invalid integer literal suffix"));
2863 assert!(err.message().contains("xyz"));
2864 }
2865
2866 #[test]
2867 fn validate_literal_accepts_a_well_formed_integer() {
2868 let lit: lex_lexer::Literal = syn::parse_str("5i32").unwrap();
2869 assert!(validate_literal(&lit).is_ok());
2870 }
2871
2872 #[test]
2873 fn validate_literal_accepts_a_well_formed_float() {
2874 let lit: lex_lexer::Literal = syn::parse_str("1.5f64").unwrap();
2875 assert!(validate_literal(&lit).is_ok());
2876 }
2877
2878 #[test]
2879 fn validate_literal_rejects_an_unrecognized_integer_suffix() {
2880 let lit: lex_lexer::Literal = syn::parse_str("10xyz").unwrap();
2881 let err = validate_literal(&lit).expect_err("unrecognized suffix must be rejected");
2882 assert!(err.message().contains("invalid integer literal suffix"));
2883 }
2884
2885 #[test]
2886 fn validate_literal_rejects_an_out_of_range_integer() {
2887 let lit: lex_lexer::Literal = syn::parse_str("999i8").unwrap();
2888 let err = validate_literal(&lit).expect_err("out-of-range literal must be rejected");
2889 assert!(err.message().contains("invalid i8 literal"));
2890 }
2891
2892 #[test]
2893 fn float_literal() {
2894 let mut parser = CELParser::new(OpLookup::new());
2895 let result = parser.parse_str("42.14");
2896 assert!(result.is_ok());
2897 let value = result.unwrap().call0::<f64>().unwrap();
2898 assert!((value - 42.14).abs() < 1e-10);
2899 }
2900
2901 #[test]
2902 fn float_literal_f64_suffix() {
2903 let mut parser = CELParser::new(OpLookup::new());
2904 let result = parser.parse_str("42.14f64");
2905 assert!(result.is_ok());
2906 let value = result.unwrap().call0::<f64>().unwrap();
2907 assert!((value - 42.14).abs() < 1e-10);
2908 }
2909
2910 #[test]
2911 fn float_literal_f32_suffix() {
2912 let mut parser = CELParser::new(OpLookup::new());
2913 let result = parser.parse_str("42.14f32");
2914 assert!(result.is_ok());
2915 let value = result.unwrap().call0::<f32>().unwrap();
2916 assert!((value - 42.14f32).abs() < 1e-6);
2917 }
2918
2919 #[test]
2920 fn invalid_float_suffix() {
2921 let mut parser = CELParser::new(OpLookup::new());
2922 let err = match parser.parse_str("3.14xyz") {
2923 Err(e) => e,
2924 Ok(_) => panic!("expected parse error for invalid float suffix"),
2925 };
2926 assert!(err.message().contains("invalid float literal suffix"));
2927 assert!(err.message().contains("xyz"));
2928 }
2929
2930 #[test]
2931 fn boolean_literal() {
2932 let mut parser = CELParser::new(OpLookup::new());
2933 let result = parser.parse_str("true");
2934 assert!(result.is_ok());
2935 assert!(result.unwrap().call0::<bool>().unwrap());
2936 }
2937
2938 #[test]
2939 fn string_literal() {
2940 let mut parser = CELParser::new(OpLookup::new());
2941 let result = parser.parse_str(r#""hello""#);
2942 assert!(result.is_ok());
2943 assert_eq!(result.unwrap().call0::<String>().unwrap(), "hello");
2944 }
2945
2946 #[test]
2947 fn string_concatenation() {
2948 let mut parser = CELParser::new(OpLookup::new());
2949 let result = parser.parse_str(r#""a" + "b""#);
2950 assert!(result.is_ok());
2951 assert_eq!(result.unwrap().call0::<String>().unwrap(), "ab");
2952 }
2953
2954 #[test]
2955 fn incomplete_expression() {
2956 let mut parser = CELParser::new(OpLookup::new());
2957 let result = parser.parse_str("10 + 25 25");
2958 let err = match result {
2959 Ok(_) => panic!("expected parse error"),
2960 Err(e) => e,
2961 };
2962 assert_eq!(err.message(), "unexpected token");
2963 }
2964
2965 #[test]
2966 fn arithmetic_expression() {
2967 let mut parser = CELParser::new(OpLookup::new());
2968 let result = parser.parse_str("10 + 20 * 30");
2969 assert!(result.is_ok());
2970 }
2971
2972 #[test]
2973 fn parenthesized_expression() {
2974 let mut parser = CELParser::new(OpLookup::new());
2975 let result = parser.parse_str("(10 + 20) * 30");
2976 assert!(result.is_ok());
2977 }
2978
2979 #[test]
2980 fn unit_still_parses_as_unit() {
2981 let mut parser = CELParser::new(OpLookup::new());
2982 let mut seg = parser.parse_str("()").unwrap();
2983 seg.call0::<()>().unwrap();
2984 }
2985
2986 #[test]
2987 fn single_paren_expression_is_grouping_not_tuple() {
2988 let mut parser = CELParser::new(OpLookup::new());
2989 let mut seg = parser.parse_str("(1i32 + 2i32)").unwrap();
2990 assert_eq!(seg.call0::<i32>().unwrap(), 3);
2991 }
2992
2993 #[test]
2994 fn one_tuple_requires_trailing_comma() {
2995 let mut parser = CELParser::new(OpLookup::new());
2996 let mut seg = parser.parse_str("(1i32,)").unwrap();
2997 assert_eq!(seg.peek_tuple_arity(), Some(1));
2998 seg.tuple_index(0).unwrap();
2999 assert_eq!(seg.call0::<i32>().unwrap(), 1);
3000 }
3001
3002 #[test]
3003 fn two_element_tuple_no_trailing_comma() {
3004 let mut parser = CELParser::new(OpLookup::new());
3005 let seg: DynSegment = parser.parse_str(r#"("Hello", 42i32)"#).unwrap();
3006 assert_eq!(seg.peek_tuple_arity(), Some(2));
3007 }
3008
3009 #[test]
3010 fn trailing_comma_rejected_for_arity_two() {
3011 let mut parser = CELParser::new(OpLookup::new());
3012 let result = parser.parse_str("(1i32, 2i32,)");
3013 assert!(result.is_err(), "trailing comma is only valid for 1-tuples");
3014 }
3015
3016 #[test]
3017 fn missing_comma_between_elements_is_an_error() {
3018 let mut parser = CELParser::new(OpLookup::new());
3019 let result = parser.parse_str("(1i32 2i32)");
3020 assert!(result.is_err());
3021 }
3022
3023 #[test]
3024 fn index_first_element_of_tuple() {
3025 let mut parser = CELParser::new(OpLookup::new());
3026 let mut seg = parser.parse_str("(10i32, 20i32).0").unwrap();
3027 assert_eq!(seg.call0::<i32>().unwrap(), 10);
3028 }
3029
3030 #[test]
3031 fn tuple_element_can_be_arithmetic_expression() {
3032 let mut parser = CELParser::new(OpLookup::new());
3033 let mut seg = parser.parse_str("(1i32 + 2i32, 3i32).0").unwrap();
3034 assert_eq!(seg.call0::<i32>().unwrap(), 3);
3035 }
3036
3037 #[test]
3038 fn tuple_second_element_can_be_arithmetic_expression() {
3039 let mut parser = CELParser::new(OpLookup::new());
3040 let mut seg = parser.parse_str("(1i32 + 2i32, 3i32).1").unwrap();
3041 assert_eq!(seg.call0::<i32>().unwrap(), 3);
3042 }
3043
3044 #[test]
3045 fn tuple_ambient_start_correct_after_sibling_expression() {
3046 let mut parser = CELParser::new(OpLookup::new());
3050 let mut seg = parser
3051 .parse_str("(1i32 + 2i32) + 3i32 + (4i32, 5i32).0")
3052 .unwrap();
3053 assert_eq!(seg.call0::<i32>().unwrap(), 10);
3054 }
3055
3056 #[test]
3057 fn tuple_index_inside_if_then_branch() {
3058 let mut parser = CELParser::new(OpLookup::new());
3062 let mut seg = parser
3063 .parse_str("if true { (10i32, 20i32).1 } else { 0i32 }")
3064 .unwrap();
3065 assert_eq!(seg.call0::<i32>().unwrap(), 20);
3066 }
3067
3068 #[test]
3069 fn tuple_index_inside_if_else_branch() {
3070 let mut parser = CELParser::new(OpLookup::new());
3071 let mut seg = parser
3072 .parse_str("if false { 0i32 } else { (10i32, 20i32).1 }")
3073 .unwrap();
3074 assert_eq!(seg.call0::<i32>().unwrap(), 20);
3075 }
3076
3077 #[test]
3078 fn tuple_index_inside_and_rhs() {
3079 let mut parser = CELParser::new(OpLookup::new());
3080 let mut seg = parser
3081 .parse_str("(1i32, 2i32).1 == 2i32 && (10i32, 20i32).1 == 20i32")
3082 .unwrap();
3083 assert!(seg.call0::<bool>().unwrap());
3084 }
3085
3086 #[test]
3087 fn tuple_index_inside_or_rhs() {
3088 let mut parser = CELParser::new(OpLookup::new());
3089 let mut seg = parser
3090 .parse_str("(1i32, 2i32).1 == 99i32 || (10i32, 20i32).1 == 20i32")
3091 .unwrap();
3092 assert!(seg.call0::<bool>().unwrap());
3093 }
3094
3095 #[test]
3096 fn tuple_containing_indexed_nested_tuple_result() {
3097 let mut parser = CELParser::new(OpLookup::new());
3105 let mut seg = parser.parse_str("(0u8, (7u8, 2u64).0).1").unwrap();
3106 assert_eq!(seg.call0::<u8>().unwrap(), 7);
3107 }
3108
3109 #[test]
3110 fn index_second_element_of_tuple() {
3111 let mut parser = CELParser::new(OpLookup::new());
3112 let mut seg = parser.parse_str("(10i32, 20i32).1").unwrap();
3113 assert_eq!(seg.call0::<i32>().unwrap(), 20);
3114 }
3115
3116 #[test]
3117 fn indexing_combined_with_addition() {
3118 let mut parser = CELParser::new(OpLookup::new());
3119 let mut seg = parser.parse_str("5i32 + (0i32, 1i32).1").unwrap();
3120 assert_eq!(seg.call0::<i32>().unwrap(), 6);
3121 }
3122
3123 #[test]
3124 fn indexing_combined_with_addition_on_the_right() {
3125 let mut parser = CELParser::new(OpLookup::new());
3126 let mut seg = parser.parse_str("(0i32, 1i32).1 + 5i32").unwrap();
3127 assert_eq!(seg.call0::<i32>().unwrap(), 6);
3128 }
3129
3130 #[test]
3131 fn out_of_range_index_is_a_parse_error() {
3132 let mut parser = CELParser::new(OpLookup::new());
3133 let result = parser.parse_str("(1i32, 2i32).5");
3134 assert!(result.is_err());
3135 }
3136
3137 #[test]
3138 fn indexing_a_non_tuple_is_a_parse_error() {
3139 let mut parser = CELParser::new(OpLookup::new());
3140 let result = parser.parse_str("1i32.0");
3141 assert!(result.is_err());
3142 }
3143
3144 #[test]
3145 fn suffixed_index_is_a_parse_error() {
3146 let mut parser = CELParser::new(OpLookup::new());
3147 let result = parser.parse_str("(1i32, 2i32).0i32");
3148 assert!(result.is_err());
3149 }
3150
3151 #[test]
3152 fn chained_tuple_index_into_nested_tuple() {
3153 let mut parser = CELParser::new(OpLookup::new());
3163 let mut seg = parser
3164 .parse_str(r#"("a", (10i32, 20i32)).1.0"#)
3165 .expect("chained .1.0 index should parse");
3166 assert_eq!(seg.call0::<i32>().unwrap(), 10);
3167 }
3168
3169 #[test]
3170 fn chained_tuple_index_suffixed_second_part_is_a_parse_error() {
3171 let mut parser = CELParser::new(OpLookup::new());
3174 let result = parser.parse_str("(1i32, 2i32).0.1i32");
3175 assert!(result.is_err());
3176 }
3177
3178 #[test]
3179 fn chained_tuple_index_scientific_notation_is_a_parse_error_not_a_panic() {
3180 let mut parser = CELParser::new(OpLookup::new());
3184 let result = parser.parse_str("(1i32, 2i32).1e2");
3185 assert!(result.is_err());
3186 }
3187
3188 #[test]
3190 fn invalid_tuple_selector_conversion_retains_its_token_span() {
3191 let mut parser = CELParser::new(OpLookup::new());
3192 for (source, expected) in [
3193 ("(1.0f64,).184467440737095516160", 10..31),
3194 ("(1.0f64,).0.1e0", 10..15),
3195 ("(1.0f64,).184467440737095516160, host", 10..31),
3196 ("(1.0f64,).0.1e0, host", 10..15),
3197 ] {
3198 let error = parser.parse_str(source).err().expect("invalid selector");
3199 assert_eq!(
3200 SourceSpan::from_proc_macro2_range(
3201 error.span(),
3202 error.end_span().unwrap_or(error.span())
3203 )
3204 .to_byte_range(source),
3205 expected,
3206 "{source}"
3207 );
3208 }
3209 }
3210
3211 #[test]
3212 fn complex_expression() {
3213 let mut parser = CELParser::new(OpLookup::new());
3214 let result = parser.parse_str("10 + 20 * (30 - 5) / 2");
3215 assert!(result.is_ok());
3216 }
3217
3218 #[test]
3219 fn logical_expression() {
3220 let mut parser = CELParser::new(OpLookup::new());
3221 let result = parser.parse_str("true && false || true");
3222 assert!(result.is_ok());
3223 }
3224
3225 #[test]
3226 fn comparison_expression() {
3227 let mut parser = CELParser::new(OpLookup::new());
3228 let result = parser.parse_str("10 == 20 && 30 > 40");
3229 assert!(result.is_ok());
3230 }
3231
3232 #[test]
3233 fn bitwise_expression() {
3234 let mut parser = CELParser::new(OpLookup::new());
3235 let result = parser.parse_str("1 | 2 & 3 ^ 4");
3236 assert!(result.is_ok());
3237 }
3238
3239 #[test]
3240 fn shift_expression() {
3241 let mut parser = CELParser::new(OpLookup::new());
3242 let result = parser.parse_str("8u32 << 2u32 + 16u32 >> 1u32");
3243 assert!(result.is_ok());
3244 }
3245
3246 #[test]
3247 fn unary_expression() {
3248 let mut parser = CELParser::new(OpLookup::new());
3249 let result = parser.parse_str("-10 + -20");
3250 assert!(result.is_ok());
3251 }
3252
3253 #[test]
3254 fn double_negation() {
3255 let mut parser = CELParser::new(OpLookup::new());
3256 let result = parser.parse_str("!!true");
3257 assert!(
3258 result.is_ok(),
3259 "Failed to parse !!true: {}",
3260 result.err().unwrap()
3261 );
3262 assert!(result.unwrap().call0::<bool>().unwrap());
3263 }
3264
3265 #[test]
3266 fn double_minus() {
3267 let mut parser = CELParser::new(OpLookup::new());
3268 let result = parser.parse_str("--5");
3269 assert!(
3270 result.is_ok(),
3271 "Failed to parse --5: {}",
3272 result.err().unwrap()
3273 );
3274 assert_eq!(result.unwrap().call0::<i32>().unwrap(), 5);
3275 }
3276
3277 #[test]
3278 fn chained_unary_expression() {
3279 let mut parser = CELParser::new(OpLookup::new());
3280 let result = parser.parse_str("!!false || !!true");
3281 if let Err(ref e) = result {
3282 eprintln!("Error: {:?}", e);
3283 eprintln!("Error message: {}", e.message());
3284 }
3285 assert!(result.is_ok(), "Failed to parse: {}", result.err().unwrap());
3286 assert!(result.unwrap().call0::<bool>().unwrap());
3287 }
3288
3289 #[test]
3290 fn cast_expression_parses_and_executes() {
3291 let mut parser = CELParser::new(OpLookup::new());
3292 let result = parser.parse_str("1024i32 as f64");
3293 assert_eq!(result.unwrap().call0::<f64>().unwrap(), 1024.0);
3294 }
3295
3296 #[test]
3297 fn cast_expression_chains_left_to_right() {
3298 let mut parser = CELParser::new(OpLookup::new());
3302 let result = parser.parse_str("1.5f64 as i32 as f64");
3303 assert_eq!(result.unwrap().call0::<f64>().unwrap(), 1.0);
3304 }
3305
3306 #[test]
3307 fn unary_negation_binds_tighter_than_cast() {
3308 let mut parser = CELParser::new(OpLookup::new());
3314 let mut seg = parser.parse_str("-1i32 as u32").expect(
3315 "parses: unary negation is registered for i32, and i32 -> u32 is a valid cast pair",
3316 );
3317 let err = seg.call0::<u32>().unwrap_err();
3318 let full = format!("{err:#}");
3322 assert!(
3323 full.contains("does not fit"),
3324 "expected an out-of-range cast error, got: {full}"
3325 );
3326 }
3327
3328 #[test]
3329 fn cast_binds_tighter_than_multiplicative_operators() {
3330 let mut parser = CELParser::new(OpLookup::new());
3337 let result = parser.parse_str("2i32 * 3i32 as f64");
3338 assert!(result.is_err(), "expected a type-mismatch parse error");
3339 }
3340
3341 #[test]
3342 fn cast_binds_tighter_than_additive_operators() {
3343 let mut parser = CELParser::new(OpLookup::new());
3347 let result = parser.parse_str("1i32 + 2i32 as f64");
3348 assert!(result.is_err(), "expected a type-mismatch parse error");
3349 }
3350
3351 #[test]
3352 fn invalid_expression() {
3353 let mut parser = CELParser::new(OpLookup::new());
3354 let result = parser.parse_str("+");
3355 assert!(result.is_err());
3356 }
3357
3358 #[test]
3359 fn error_formatting() {
3360 let source = "10 + 20 30";
3361 let mut parser = CELParser::new(OpLookup::new());
3362 let result = parser.parse_str(source);
3363
3364 assert!(result.is_err());
3365
3366 let err = match &result {
3367 Ok(_) => panic!("expected parse error"),
3368 Err(e) => e,
3369 };
3370 assert_eq!(err.message(), "unexpected token");
3371
3372 let formatted = err.format_rustc_style(source, "test.cel", 1u32, &Renderer::plain());
3373 assert!(formatted.contains("error: unexpected token"));
3374 assert!(formatted.contains("test.cel:1:"));
3375 assert!(formatted.contains("1 | 10 + 20 30"));
3376 assert!(formatted.contains("^"));
3377 }
3378
3379 #[test]
3380 fn error_formatting_with_line_offset() {
3381 let source = "10 + 20 30";
3382 let mut parser = CELParser::new(OpLookup::new());
3383 let result = parser.parse_str(source);
3384
3385 assert!(result.is_err());
3386
3387 let err = match &result {
3388 Ok(_) => panic!("expected parse error"),
3389 Err(e) => e,
3390 };
3391 let formatted = err.format_rustc_style(source, "large_file.rs", 42u32, &Renderer::plain());
3392 assert!(formatted.contains("error: unexpected token"));
3393 assert!(formatted.contains("large_file.rs:42:"));
3394 assert!(formatted.contains("42 | 10 + 20 30"));
3395 assert!(formatted.contains("^"));
3396 }
3397
3398 #[test]
3399 fn print_error_formatting() {
3400 let line = line!() + 1;
3401 let source = r#"
3402
3403 10 + 20 30 // Unexpected token
3404
3405 "#;
3406
3407 let mut parser = CELParser::new(OpLookup::new());
3408 let result = parser.parse_str(source);
3409
3410 assert!(result.is_err(), "Expected parsing to fail");
3411
3412 let err = match &result {
3413 Ok(_) => panic!("expected parse error"),
3414 Err(e) => e,
3415 };
3416 eprintln!(
3417 "DEBUG: span.start.line = {}, span.start.column = {}",
3418 err.span().start().line,
3419 err.span().start().column
3420 );
3421
3422 let formatted_error = err.format_rustc_style(source, file!(), line, &Renderer::plain());
3423 println!("{}", formatted_error);
3424
3425 let formatted = formatted_error;
3426
3427 let expected_line = line + 2;
3428
3429 assert!(
3430 formatted.contains("error: unexpected token"),
3431 "Should contain error message, got: {}",
3432 formatted
3433 );
3434 assert!(
3435 formatted.contains(&format!("{}:", expected_line)),
3436 "Should show error on line {}, got: {}",
3437 expected_line,
3438 formatted
3439 );
3440 assert!(
3441 formatted.contains("30"),
3442 "Should show the source line with '30', got: {}",
3443 formatted
3444 );
3445 assert!(
3446 formatted.contains("^"),
3447 "Should have carets pointing to error, got: {}",
3448 formatted
3449 );
3450 }
3451
3452 #[test]
3453 fn test_addition_execution() -> anyhow::Result<()> {
3454 let mut parser = CELParser::new(OpLookup::new());
3455 let mut segment = parser
3456 .parse_str("10 + 20")
3457 .map_err(|e| anyhow::anyhow!("{}", e))?;
3458 let result = segment.call0::<i32>()?;
3459 assert_eq!(result, 30);
3460 Ok(())
3461 }
3462
3463 #[test]
3464 fn test_multiplication_execution() -> anyhow::Result<()> {
3465 let mut parser = CELParser::new(OpLookup::new());
3466 let mut segment = parser
3467 .parse_str("3 * 7")
3468 .map_err(|e| anyhow::anyhow!("{}", e))?;
3469 let result = segment.call0::<i32>()?;
3470 assert_eq!(result, 21);
3471 Ok(())
3472 }
3473
3474 #[test]
3475 fn test_complex_arithmetic_execution() -> anyhow::Result<()> {
3476 let mut parser = CELParser::new(OpLookup::new());
3477 let mut segment = parser
3478 .parse_str("10 + 20 * 3")
3479 .map_err(|e| anyhow::anyhow!("{}", e))?;
3480 let result = segment.call0::<i32>()?;
3481 assert_eq!(result, 70);
3482 Ok(())
3483 }
3484
3485 #[test]
3486 fn test_parenthesized_arithmetic_execution() -> anyhow::Result<()> {
3487 let mut parser = CELParser::new(OpLookup::new());
3488 let mut segment = parser
3489 .parse_str("(10 + 20) * 3")
3490 .map_err(|e| anyhow::anyhow!("{}", e))?;
3491 let result = segment.call0::<i32>()?;
3492 assert_eq!(result, 90);
3493 Ok(())
3494 }
3495
3496 #[test]
3497 fn test_comparison_execution() -> anyhow::Result<()> {
3498 let mut parser = CELParser::new(OpLookup::new());
3499 let mut segment = parser
3500 .parse_str("10 < 20")
3501 .map_err(|e| anyhow::anyhow!("{}", e))?;
3502 let result = segment.call0::<bool>()?;
3503 assert!(result);
3504 Ok(())
3505 }
3506
3507 #[test]
3508 fn test_logical_and_execution() -> anyhow::Result<()> {
3509 let mut parser = CELParser::new(OpLookup::new());
3510 let mut segment = parser
3511 .parse_str("true && false")
3512 .map_err(|e| anyhow::anyhow!("{}", e))?;
3513 let result = segment.call0::<bool>()?;
3514 assert!(!result);
3515 Ok(())
3516 }
3517
3518 #[test]
3519 fn test_unary_negation_execution() -> anyhow::Result<()> {
3520 let mut parser = CELParser::new(OpLookup::new());
3521 let mut segment = parser
3522 .parse_str("-42")
3523 .map_err(|e| anyhow::anyhow!("{}", e))?;
3524 let result = segment.call0::<i32>()?;
3525 assert_eq!(result, -42);
3526 Ok(())
3527 }
3528
3529 #[test]
3530 fn test_logical_not_execution() -> anyhow::Result<()> {
3531 let mut parser = CELParser::new(OpLookup::new());
3532 let mut segment = parser
3533 .parse_str("!true")
3534 .map_err(|e| anyhow::anyhow!("{}", e))?;
3535 let result = segment.call0::<bool>()?;
3536 assert!(!result);
3537 Ok(())
3538 }
3539
3540 #[test]
3541 fn test_u32_addition_execution() -> anyhow::Result<()> {
3542 let mut parser = CELParser::new(OpLookup::new());
3543 let mut segment = parser
3544 .parse_str("10u32 + 20u32")
3545 .map_err(|e| anyhow::anyhow!("{}", e))?;
3546 let result = segment.call0::<u32>()?;
3547 assert_eq!(result, 30);
3548 Ok(())
3549 }
3550
3551 #[test]
3552 fn test_identifier_with_scope() -> anyhow::Result<()> {
3553 let mut lookup = OpLookup::new();
3554 lookup.push_scope(|name, segment, num_operands, _span| {
3555 if num_operands == 0 {
3556 match name {
3557 "x" => {
3558 segment.op0(|| 10i32);
3559 Ok(true)
3560 }
3561 "y" => {
3562 segment.op0(|| 20i32);
3563 Ok(true)
3564 }
3565 _ => Ok(false),
3566 }
3567 } else {
3568 Ok(false)
3569 }
3570 });
3571 let mut parser = CELParser::new(lookup);
3572 let mut segment = parser
3573 .parse_str("x + y")
3574 .map_err(|e| anyhow::anyhow!("{}", e))?;
3575 let result = segment.call0::<i32>()?;
3576 assert_eq!(result, 30);
3577 Ok(())
3578 }
3579
3580 #[test]
3581 fn test_undefined_identifier_error() {
3582 let mut parser = CELParser::new(OpLookup::new());
3583 let result = parser.parse_str("undefined_var + 10");
3584
3585 assert!(result.is_err());
3586 if let Err(e) = result {
3587 let error_msg = format!("{:?}", e);
3588 assert!(
3589 error_msg.contains("undefined identifier: `undefined_var`"),
3590 "Error message should contain 'undefined identifier: `undefined_var`', got: {}",
3591 error_msg
3592 );
3593 }
3594 }
3595
3596 #[test]
3597 fn test_identifier_scope_error_propagated() {
3598 let mut lookup = OpLookup::new();
3599 lookup.push_scope(|name, _segment, num_operands, _span| {
3600 if name == "bad_id" && num_operands == 0 {
3601 return Err(anyhow::anyhow!("custom identifier rejected"));
3602 }
3603 Ok(false)
3604 });
3605 let mut parser = CELParser::new(lookup);
3606 let err = match parser.parse_str("bad_id + 1") {
3607 Err(e) => e,
3608 Ok(_) => panic!("scope Err should propagate, not become Undefined identifier"),
3609 };
3610 assert!(
3611 err.message().contains("custom identifier rejected"),
3612 "expected scope error message, got: {}",
3613 err.message()
3614 );
3615 assert!(
3616 !err.message().contains("undefined identifier:"),
3617 "scope Err must not be rewritten as undefined identifier"
3618 );
3619 }
3620
3621 #[test]
3622 fn test_undefined_identifier_error_formatting() {
3623 let input = "undefined_var + 10";
3624 let mut parser = CELParser::new(OpLookup::new());
3625 let result = parser.parse_str(input);
3626
3627 assert!(result.is_err());
3628 if let Err(e) = result {
3629 let formatted_error = e.format_rustc_style(input, "test.cel", 1, &Renderer::plain());
3630 assert!(formatted_error.contains("undefined identifier"));
3631 assert!(formatted_error.contains("undefined_var"));
3632 assert!(formatted_error.contains("test.cel"));
3633 }
3634 }
3635
3636 #[test]
3637 fn test_float_arithmetic_execution() -> anyhow::Result<()> {
3638 let mut parser = CELParser::new(OpLookup::new());
3639 let mut segment = parser
3640 .parse_str("3.5 * 2.0")
3641 .map_err(|e| anyhow::anyhow!("{}", e))?;
3642 let result = segment.call0::<f64>()?;
3643 assert_eq!(result, 7.0);
3644 Ok(())
3645 }
3646
3647 #[test]
3648 fn call_empty_arg_list() -> anyhow::Result<()> {
3649 let mut lookup = OpLookup::new();
3650 lookup.push_scope(
3651 |name, segment, num_operands, _span| match (name, num_operands) {
3652 ("f", 0) => {
3653 segment.op0(|| 0i32);
3654 Ok(true)
3655 }
3656 ("()", 1) => {
3657 segment.op1(|_callee: i32| 99i32)?;
3658 Ok(true)
3659 }
3660 _ => Ok(false),
3661 },
3662 );
3663 let mut parser = CELParser::new(lookup);
3664 let mut segment = parser
3665 .parse_str("f()")
3666 .map_err(|e| anyhow::anyhow!("{}", e))?;
3667 assert_eq!(segment.call0::<i32>()?, 99);
3668 Ok(())
3669 }
3670
3671 #[test]
3672 fn call_single_arg() -> anyhow::Result<()> {
3673 let mut lookup = OpLookup::new();
3674 lookup.push_scope(
3675 |name, segment, num_operands, _span| match (name, num_operands) {
3676 ("f", 0) => {
3677 segment.op0(|| 0i32);
3678 Ok(true)
3679 }
3680 ("()", 2) => {
3681 segment.op2(|_callee: i32, arg: i32| arg)?;
3682 Ok(true)
3683 }
3684 _ => Ok(false),
3685 },
3686 );
3687 let mut parser = CELParser::new(lookup);
3688 let mut segment = parser
3689 .parse_str("f(42)")
3690 .map_err(|e| anyhow::anyhow!("{}", e))?;
3691 assert_eq!(segment.call0::<i32>()?, 42);
3692 Ok(())
3693 }
3694
3695 #[test]
3696 fn call_multiple_args() -> anyhow::Result<()> {
3697 let mut lookup = OpLookup::new();
3698 lookup.push_scope(
3699 |name, segment, num_operands, _span| match (name, num_operands) {
3700 ("f", 0) => {
3701 segment.op0(|| 0i32);
3702 Ok(true)
3703 }
3704 ("()", 3) => {
3705 segment.op3(|_callee: i32, arg1: i32, arg2: i32| arg1 + arg2)?;
3706 Ok(true)
3707 }
3708 _ => Ok(false),
3709 },
3710 );
3711 let mut parser = CELParser::new(lookup);
3712 let mut segment = parser
3713 .parse_str("f(10, 32)")
3714 .map_err(|e| anyhow::anyhow!("{}", e))?;
3715 assert_eq!(segment.call0::<i32>()?, 42);
3716 Ok(())
3717 }
3718
3719 #[test]
3720 fn call_missing_closing_paren() {
3721 let mut lookup = OpLookup::new();
3722 lookup.push_scope(
3723 |name, segment, num_operands, _span| match (name, num_operands) {
3724 ("f", 0) => {
3725 segment.op0(|| 0i32);
3726 Ok(true)
3727 }
3728 _ => Ok(false),
3729 },
3730 );
3731 let mut parser = CELParser::new(lookup);
3732 let err = match parser.parse_str("f(42 43)") {
3733 Err(e) => e,
3734 Ok(_) => panic!("expected parse error for missing closing parenthesis"),
3735 };
3736 assert_eq!(err.message(), "expected closing parenthesis");
3737 }
3738
3739 #[test]
3740 fn call_trailing_comma() {
3741 let mut lookup = OpLookup::new();
3742 lookup.push_scope(
3743 |name, segment, num_operands, _span| match (name, num_operands) {
3744 ("f", 0) => {
3745 segment.op0(|| 0i32);
3746 Ok(true)
3747 }
3748 _ => Ok(false),
3749 },
3750 );
3751 let mut parser = CELParser::new(lookup);
3752 let err = match parser.parse_str("f(42,)") {
3753 Err(e) => e,
3754 Ok(_) => panic!("expected parse error for trailing comma"),
3755 };
3756 assert_eq!(err.message(), "expected expression after comma");
3757 }
3758
3759 #[test]
3760 fn call_undefined_call_op() {
3761 let mut lookup = OpLookup::new();
3762 lookup.push_scope(
3763 |name, segment, num_operands, _span| match (name, num_operands) {
3764 ("f", 0) => {
3765 segment.op0(|| 0i32);
3766 Ok(true)
3767 }
3768 _ => Ok(false),
3769 },
3770 );
3771 let mut parser = CELParser::new(lookup);
3772 let err = match parser.parse_str("f()") {
3773 Err(e) => e,
3774 Ok(_) => panic!("expected error when () operator is not registered"),
3775 };
3776 assert!(
3777 err.message().starts_with("no operation"),
3778 "error should report no operation found, got: {}",
3779 err.message()
3780 );
3781 }
3782
3783 #[test]
3784 fn call_leading_comma_reports_expected_expression_at_the_comma() {
3785 let mut lookup = OpLookup::new();
3786 lookup.push_scope(
3787 |name, segment, num_operands, _span| match (name, num_operands) {
3788 ("f", 0) => {
3789 segment.op0(|| 0i32);
3790 Ok(true)
3791 }
3792 _ => Ok(false),
3793 },
3794 );
3795 let mut parser = CELParser::new(lookup);
3796 let err = match parser.parse_str("f(,5)") {
3797 Err(e) => e,
3798 Ok(_) => panic!("expected parse error for leading comma"),
3799 };
3800 assert_eq!(err.message(), "expected expression");
3801 }
3802
3803 #[test]
3804 fn call_chained() -> anyhow::Result<()> {
3805 let mut lookup = OpLookup::new();
3806 lookup.push_scope(
3807 |name, segment, num_operands, _span| match (name, num_operands) {
3808 ("f", 0) => {
3809 segment.op0(|| 0i32);
3810 Ok(true)
3811 }
3812 ("()", 1) => {
3813 segment.op1r(|callee: i32| {
3814 callee
3815 .checked_add(7)
3816 .ok_or_else(|| anyhow::anyhow!("overflow"))
3817 })?;
3818 Ok(true)
3819 }
3820 _ => Ok(false),
3821 },
3822 );
3823 let mut parser = CELParser::new(lookup);
3824 let mut segment = parser
3825 .parse_str("f()()")
3826 .map_err(|e| anyhow::anyhow!("{}", e))?;
3827 assert_eq!(segment.call0::<i32>()?, 14);
3828 Ok(())
3829 }
3830
3831 #[test]
3832 fn op_type_mismatch_error_spans_full_expression() {
3833 let source = r#""Hello" + 32.0"#;
3834 let mut parser = CELParser::new(OpLookup::new());
3835 let err = match parser.parse_str(source) {
3836 Err(e) => e,
3837 Ok(_) => panic!("expected parse error for type mismatch"),
3838 };
3839 assert!(
3840 err.message().starts_with("no operation"),
3841 "expected 'no operation' prefix, got: {}",
3842 err.message()
3843 );
3844 let end_span = err.end_span().expect("op-lookup errors carry an end span");
3845 assert!(
3846 end_span.end().column >= 14,
3847 "end span should reach the end of 32.0 (expected end.column >= 14, got {})",
3848 end_span.end().column
3849 );
3850 }
3851
3852 #[test]
3853 fn and_short_circuits_on_false() {
3854 let mut parser = CELParser::new(OpLookup::new());
3857 let mut segment = parser
3858 .parse_str("false && (1i32 / 0i32 == 0i32)")
3859 .expect("should parse");
3860 assert!(!segment.call0::<bool>().unwrap());
3861 }
3862
3863 #[test]
3864 fn and_evaluates_rhs_when_lhs_true() {
3865 let mut parser = CELParser::new(OpLookup::new());
3866 let mut segment = parser.parse_str("true && false").expect("should parse");
3867 assert!(!segment.call0::<bool>().unwrap());
3868 }
3869
3870 #[test]
3871 fn and_chained_short_circuits() {
3872 let mut parser = CELParser::new(OpLookup::new());
3873 let mut segment = parser
3874 .parse_str("true && false && (1i32 / 0i32 == 0i32)")
3875 .expect("should parse");
3876 assert!(!segment.call0::<bool>().unwrap());
3877 }
3878
3879 #[test]
3880 fn and_lhs_type_error() {
3881 let mut parser = CELParser::new(OpLookup::new());
3883 let err = match parser.parse_str("1i32 && true") {
3884 Err(e) => e,
3885 Ok(_) => panic!("lhs i32 should fail for &&"),
3886 };
3887 assert!(err.end_span().is_some());
3888 }
3889
3890 #[test]
3891 fn or_lhs_type_error() {
3892 let mut parser = CELParser::new(OpLookup::new());
3894 let err = match parser.parse_str("1i32 || true") {
3895 Err(e) => e,
3896 Ok(_) => panic!("lhs i32 should fail for ||"),
3897 };
3898 assert!(err.end_span().is_some());
3899 }
3900
3901 #[test]
3902 fn or_short_circuits_on_true() {
3903 let mut parser = CELParser::new(OpLookup::new());
3906 let mut segment = parser
3907 .parse_str("true || (1i32 / 0i32 == 0i32)")
3908 .expect("should parse");
3909 assert!(segment.call0::<bool>().unwrap());
3910 }
3911
3912 #[test]
3913 fn or_evaluates_rhs_when_lhs_false() {
3914 let mut parser = CELParser::new(OpLookup::new());
3915 let mut segment = parser.parse_str("false || true").expect("should parse");
3916 assert!(segment.call0::<bool>().unwrap());
3917 }
3918
3919 #[test]
3920 fn or_chained() {
3921 let mut parser = CELParser::new(OpLookup::new());
3922 let mut segment = parser
3923 .parse_str("true || false || false")
3924 .expect("should parse");
3925 assert!(segment.call0::<bool>().unwrap());
3926 }
3927
3928 #[test]
3929 fn if_true_branch_selected() {
3930 let mut parser = CELParser::new(OpLookup::new());
3931 let mut segment = parser
3932 .parse_str("if true { 1i32 } else { 2i32 }")
3933 .expect("should parse");
3934 assert_eq!(segment.call0::<i32>().unwrap(), 1);
3935 }
3936
3937 #[test]
3938 fn if_false_branch_selected() {
3939 let mut parser = CELParser::new(OpLookup::new());
3940 let mut segment = parser
3941 .parse_str("if false { 1i32 } else { 2i32 }")
3942 .expect("should parse");
3943 assert_eq!(segment.call0::<i32>().unwrap(), 2);
3944 }
3945
3946 #[test]
3947 fn if_else_if_first_branch() {
3948 let mut parser = CELParser::new(OpLookup::new());
3949 let mut segment = parser
3950 .parse_str("if true { 1i32 } else if false { 2i32 } else { 3i32 }")
3951 .expect("should parse");
3952 assert_eq!(segment.call0::<i32>().unwrap(), 1);
3953 }
3954
3955 #[test]
3956 fn if_else_if_middle_branch() {
3957 let mut parser = CELParser::new(OpLookup::new());
3958 let mut segment = parser
3959 .parse_str("if false { 1i32 } else if true { 2i32 } else { 3i32 }")
3960 .expect("should parse");
3961 assert_eq!(segment.call0::<i32>().unwrap(), 2);
3962 }
3963
3964 #[test]
3965 fn if_else_if_last_branch() {
3966 let mut parser = CELParser::new(OpLookup::new());
3967 let mut segment = parser
3968 .parse_str("if false { 1i32 } else if false { 2i32 } else { 3i32 }")
3969 .expect("should parse");
3970 assert_eq!(segment.call0::<i32>().unwrap(), 3);
3971 }
3972
3973 #[test]
3974 fn if_omitted_else_unit_branch() {
3975 let mut parser = CELParser::new(OpLookup::new());
3976 let mut segment = parser.parse_str("if true { () }").expect("should parse");
3977 segment.call0::<()>().expect("should execute");
3978 }
3979
3980 #[test]
3981 fn if_omitted_else_rejects_non_unit_then() {
3982 let mut parser = CELParser::new(OpLookup::new());
3984 assert!(parser.parse_str("if false { 1i32 }").is_err());
3985 }
3986
3987 #[test]
3988 fn if_branch_type_mismatch_is_error() {
3989 let mut parser = CELParser::new(OpLookup::new());
3990 assert!(parser.parse_str("if true { 1i32 } else { true }").is_err());
3991 }
3992
3993 #[test]
3994 fn if_branch_tuple_arity_mismatch_is_error() {
3995 let mut parser = CELParser::new(OpLookup::new());
4000 let result = parser.parse_str("if false { (1i32, 2i32) } else { (3i64, 4i64, 5i64) }.0");
4001 assert!(
4002 result.is_err(),
4003 "branches with different tuple shapes must not be accepted"
4004 );
4005 }
4006
4007 #[test]
4008 fn if_branch_tuple_element_type_mismatch_is_error() {
4009 let mut parser = CELParser::new(OpLookup::new());
4010 let result = parser.parse_str("if false { (1i32, 2i32) } else { (3i64, 4i64) }.0");
4011 assert!(
4012 result.is_err(),
4013 "branches with the same arity but different element types must not be accepted"
4014 );
4015 }
4016
4017 #[test]
4018 fn if_missing_open_brace_is_error() {
4019 let mut parser = CELParser::new(OpLookup::new());
4020 assert!(parser.parse_str("if true 1i32 } else { 2i32 }").is_err());
4021 }
4022
4023 #[test]
4024 fn if_missing_else_after_brace_is_fine() {
4025 let mut parser = CELParser::new(OpLookup::new());
4027 let mut segment = parser.parse_str("if false { () }").expect("should parse");
4028 segment.call0::<()>().expect("should execute");
4029 }
4030
4031 #[test]
4032 fn if_trailing_else_is_error() {
4033 let mut parser = CELParser::new(OpLookup::new());
4035 assert!(parser.parse_str("if true { () } else").is_err());
4036 }
4037
4038 #[test]
4039 fn parse_expression_stops_before_comma() -> anyhow::Result<()> {
4040 use lex_lexer::LexLexer;
4041 let stream: proc_macro2::TokenStream = "10i32 + 20i32, 5i32".parse().unwrap();
4042 let mut parser = CELParser::new(OpLookup::new());
4043 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
4044 let mut seg = parser
4045 .parse_expression()
4046 .map_err(|e| anyhow::anyhow!("{}", e))?;
4047 let result: i32 = seg.call0()?;
4048 assert_eq!(result, 30);
4049 let remaining: Vec<_> = parser.take_lex_tokens().expect("tokens present").collect();
4050 assert_eq!(
4052 remaining.len(),
4053 2,
4054 "expected 2 remaining tokens (comma and 5i32)"
4055 );
4056 Ok(())
4057 }
4058
4059 #[test]
4060 fn parse_expression_on_empty_input_returns_error() {
4061 use lex_lexer::LexLexer;
4062 let stream: proc_macro2::TokenStream = "".parse().unwrap();
4063 let mut parser = CELParser::new(OpLookup::new());
4064 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
4065 let result = parser.parse_expression();
4066 assert!(result.is_err(), "expected Err for empty input");
4067 }
4068
4069 #[test]
4070 fn parse_literal_pattern_accepts_a_bare_literal() -> anyhow::Result<()> {
4071 use lex_lexer::LexLexer;
4072 let stream: proc_macro2::TokenStream = "5i32".parse().unwrap();
4073 let mut parser = CELParser::new(OpLookup::new());
4074 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
4075 let mut seg = parser
4076 .parse_literal_pattern()
4077 .map_err(|e| anyhow::anyhow!("{}", e))?;
4078 assert_eq!(seg.call0::<i32>()?, 5);
4079 Ok(())
4080 }
4081
4082 #[test]
4083 fn parse_literal_pattern_accepts_a_negated_integer_literal() -> anyhow::Result<()> {
4084 use lex_lexer::LexLexer;
4085 let stream: proc_macro2::TokenStream = "-5i32".parse().unwrap();
4086 let mut parser = CELParser::new(OpLookup::new());
4087 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
4088 let mut seg = parser
4089 .parse_literal_pattern()
4090 .map_err(|e| anyhow::anyhow!("{}", e))?;
4091 assert_eq!(seg.call0::<i32>()?, -5);
4092 Ok(())
4093 }
4094
4095 #[test]
4096 fn parse_literal_pattern_accepts_a_negated_float_literal() -> anyhow::Result<()> {
4097 use lex_lexer::LexLexer;
4098 let stream: proc_macro2::TokenStream = "-1.5f64".parse().unwrap();
4099 let mut parser = CELParser::new(OpLookup::new());
4100 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
4101 let mut seg = parser
4102 .parse_literal_pattern()
4103 .map_err(|e| anyhow::anyhow!("{}", e))?;
4104 assert_eq!(seg.call0::<f64>()?, -1.5);
4105 Ok(())
4106 }
4107
4108 #[test]
4109 fn parse_literal_pattern_stops_before_a_trailing_operator() -> anyhow::Result<()> {
4110 use lex_lexer::LexLexer;
4111 let stream: proc_macro2::TokenStream = "1i32 + 2i32".parse().unwrap();
4112 let mut parser = CELParser::new(OpLookup::new());
4113 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
4114 let mut seg = parser
4115 .parse_literal_pattern()
4116 .map_err(|e| anyhow::anyhow!("{}", e))?;
4117 assert_eq!(seg.call0::<i32>()?, 1);
4118 let remaining: Vec<_> = parser.take_lex_tokens().expect("tokens present").collect();
4119 assert_eq!(
4120 remaining.len(),
4121 2,
4122 "expected 2 remaining tokens (+ and 2i32)"
4123 );
4124 Ok(())
4125 }
4126
4127 #[test]
4128 fn parse_literal_pattern_rejects_a_dash_not_followed_by_a_literal() {
4129 use lex_lexer::LexLexer;
4130 let stream: proc_macro2::TokenStream = "-mode".parse().unwrap();
4131 let mut parser = CELParser::new(OpLookup::new());
4132 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
4133 assert!(parser.parse_literal_pattern().is_err());
4134 }
4135
4136 #[test]
4137 fn parse_literal_pattern_rejects_negating_an_unsigned_literal() {
4138 use lex_lexer::LexLexer;
4139 let stream: proc_macro2::TokenStream = "-1u32".parse().unwrap();
4140 let mut parser = CELParser::new(OpLookup::new());
4141 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
4142 assert!(parser.parse_literal_pattern().is_err());
4143 }
4144
4145 #[test]
4146 fn parse_literal_pattern_rejects_a_bare_identifier() {
4147 use lex_lexer::LexLexer;
4148 let stream: proc_macro2::TokenStream = "mode".parse().unwrap();
4149 let mut parser = CELParser::new(OpLookup::new());
4150 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
4151 assert!(parser.parse_literal_pattern().is_err());
4152 }
4153
4154 #[test]
4155 fn parse_literal_pattern_rejects_a_tuple() {
4156 use lex_lexer::LexLexer;
4157 let stream: proc_macro2::TokenStream = "(1i32, 2i32)".parse().unwrap();
4158 let mut parser = CELParser::new(OpLookup::new());
4159 parser.set_lex_tokens(LexLexer::new(stream.into_iter()).peekable());
4160 assert!(parser.parse_literal_pattern().is_err());
4161 }
4162
4163 #[test]
4164 fn closure_literal_with_one_param_compiles_and_calls() -> anyhow::Result<()> {
4165 let mut parser = CELParser::new(OpLookup::new());
4166 let mut segment = parser
4167 .parse_str("|x: i32| x + 1")
4168 .map_err(|e| anyhow::anyhow!("{}", e))?;
4169 let closure: cel_runtime::DynClosure = segment.call0()?;
4170 let x = 5i32;
4171 assert_eq!(closure.call::<i32>(&[&x])?, 6);
4172 Ok(())
4173 }
4174
4175 #[test]
4176 fn closure_literal_with_zero_params_compiles_and_calls() -> anyhow::Result<()> {
4177 let mut parser = CELParser::new(OpLookup::new());
4178 let mut segment = parser
4179 .parse_str("|| 42")
4180 .map_err(|e| anyhow::anyhow!("{}", e))?;
4181 let closure: cel_runtime::DynClosure = segment.call0()?;
4182 assert_eq!(closure.call::<i32>(&[])?, 42);
4183 Ok(())
4184 }
4185
4186 #[test]
4187 fn closure_literal_with_two_params_compiles_and_calls_in_order() -> anyhow::Result<()> {
4188 let mut parser = CELParser::new(OpLookup::new());
4189 let mut segment = parser
4190 .parse_str("|a: i32, b: i32| a - b")
4191 .map_err(|e| anyhow::anyhow!("{}", e))?;
4192 let closure: cel_runtime::DynClosure = segment.call0()?;
4193 let (a, b) = (10i32, 3i32);
4194 assert_eq!(closure.call::<i32>(&[&a, &b])?, 7);
4195 Ok(())
4196 }
4197
4198 #[test]
4199 fn closure_literal_with_tuple_typed_param_compiles_and_calls() -> anyhow::Result<()> {
4200 let mut parser = CELParser::new(OpLookup::new());
4201 let mut segment = parser
4202 .parse_str("|r: (i32, i32)| r.0 + r.1")
4203 .map_err(|e| anyhow::anyhow!("{}", e))?;
4204 let closure: cel_runtime::DynClosure = segment.call0()?;
4205
4206 let mut pair = DynSegment::new::<()>();
4208 let ambient_start = pair.current_stack_offset();
4209 pair.just(10i32);
4210 pair.annotate_top(crate::op_table::builtin_value_type(TypeId::of::<i32>()).unwrap())?;
4211 pair.just(20i32);
4212 pair.annotate_top(crate::op_table::builtin_value_type(TypeId::of::<i32>()).unwrap())?;
4213 pair.make_tuple(2, ambient_start)?;
4214 let pair = pair.call_dyn_value(&[])?;
4215
4216 assert_eq!(closure.call::<i32>(&[&pair])?, 30);
4217 Ok(())
4218 }
4219
4220 #[test]
4221 fn closure_param_accepts_a_builtin_generic_type() -> anyhow::Result<()> {
4222 let mut parser = CELParser::new(OpLookup::new());
4223 let mut segment = parser
4224 .parse_str("|r: RangeInclusive(f64)| r")
4225 .map_err(|e| anyhow::anyhow!("{}", e))?;
4226 let closure: cel_runtime::DynClosure = segment.call0()?;
4227 let range = 1.0f64..=2.0f64;
4228 assert_eq!(
4229 closure.call::<std::ops::RangeInclusive<f64>>(&[&range])?,
4230 1.0..=2.0
4231 );
4232 Ok(())
4233 }
4234
4235 #[test]
4236 fn closure_param_accepts_an_array_type() {
4237 let mut parser = CELParser::new(OpLookup::new());
4238 let mut segment = parser.parse_str("(|xs: [i32]| xs)([1, 2])").unwrap();
4239 let array = segment
4240 .call0::<cel_runtime::OwnedValue>()
4241 .unwrap()
4242 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()
4243 .unwrap();
4244 assert_eq!(array.as_slice(), &[1, 2]);
4245 }
4246
4247 #[test]
4248 fn closure_body_referencing_an_undeclared_name_is_a_parse_error() {
4249 let mut parser = CELParser::new(OpLookup::new());
4250 let err = parser.parse_str("|x: i32| x + y");
4251 assert!(err.is_err());
4252 }
4253
4254 #[test]
4255 fn nested_closure_referencing_only_its_own_param_compiles_and_calls() -> anyhow::Result<()> {
4256 let mut parser = CELParser::new(OpLookup::new());
4257 let mut segment = parser
4263 .parse_str("|x: i32| |y: i32| y + 1")
4264 .map_err(|e| anyhow::anyhow!("{}", e))?;
4265 let outer: cel_runtime::DynClosure = segment.call0()?;
4266 let x = 0i32;
4267 let inner: cel_runtime::DynClosure = outer.call(&[&x])?;
4268 let y = 41i32;
4269 assert_eq!(inner.call::<i32>(&[&y])?, 42);
4270 Ok(())
4271 }
4272
4273 #[test]
4274 fn closure_body_cannot_see_an_enclosing_scopes_names() {
4275 let mut lookup = OpLookup::new();
4278 lookup.push_scope(|name, segment, arity, _span| {
4279 if name == "outer_only" && arity == 0 {
4280 segment.just(1i32);
4281 Ok(true)
4282 } else {
4283 Ok(false)
4284 }
4285 });
4286 let mut parser = CELParser::new(lookup);
4287 let err = parser.parse_str("|x: i32| x + outer_only");
4288 assert!(err.is_err());
4289 }
4290
4291 #[test]
4292 fn ast_context_parses_a_one_param_closure() {
4293 let mut parser = Parser::<AstContext>::new(OpLookup::new());
4294 let expr = parser.parse_str_ast("|x: i32| x").unwrap();
4295 let Expr::Closure { params, body, .. } = expr else {
4296 panic!("expected Closure");
4297 };
4298 assert_eq!(params.len(), 1);
4299 assert_eq!(params[0].name, "x");
4300 assert!(matches!(
4301 ¶ms[0].type_expr,
4302 TypeExpr::Named { name, args, .. } if name == "i32" && args.is_empty()
4303 ));
4304 assert!(matches!(*body, Expr::Ident { ref name, .. } if name == "x"));
4305 }
4306
4307 #[test]
4308 fn ast_context_parses_a_zero_param_closure() {
4309 let mut parser = Parser::<AstContext>::new(OpLookup::new());
4310 let expr = parser.parse_str_ast("|| 1i32").unwrap();
4311 let Expr::Closure { params, .. } = expr else {
4312 panic!("expected Closure");
4313 };
4314 assert!(params.is_empty());
4315 }
4316
4317 #[test]
4318 fn ast_context_parses_a_tuple_typed_closure_param() {
4319 let mut parser = Parser::<AstContext>::new(OpLookup::new());
4320 let expr = parser.parse_str_ast("|x: (i32, f64)| x.0").unwrap();
4321 let Expr::Closure { params, .. } = expr else {
4322 panic!("expected Closure");
4323 };
4324 match ¶ms[0].type_expr {
4325 TypeExpr::Tuple { elements, .. } => assert_eq!(elements.len(), 2),
4326 other => panic!("expected Tuple, got {other:?}"),
4327 }
4328 }
4329
4330 #[test]
4331 fn range_expression_constructs_a_range() {
4332 let mut parser = CELParser::new(OpLookup::new());
4333 let mut seg = parser.parse_str("1i32..5i32").unwrap();
4334 assert_eq!(seg.call0::<std::ops::Range<i32>>().unwrap(), 1i32..5i32);
4335 }
4336
4337 #[test]
4338 fn range_inclusive_expression_constructs_a_range_inclusive() {
4339 let mut parser = CELParser::new(OpLookup::new());
4340 let mut seg = parser.parse_str("1i32..=5i32").unwrap();
4341 assert_eq!(
4342 seg.call0::<std::ops::RangeInclusive<i32>>().unwrap(),
4343 1i32..=5i32
4344 );
4345 }
4346
4347 #[test]
4348 fn range_from_expression_constructs_a_range_from() {
4349 let mut parser = CELParser::new(OpLookup::new());
4350 let mut seg = parser.parse_str("3i32..").unwrap();
4351 assert_eq!(seg.call0::<std::ops::RangeFrom<i32>>().unwrap(), 3i32..);
4352 }
4353
4354 #[test]
4355 fn range_to_expression_constructs_a_range_to() {
4356 let mut parser = CELParser::new(OpLookup::new());
4357 let mut seg = parser.parse_str("..7i32").unwrap();
4358 assert_eq!(seg.call0::<std::ops::RangeTo<i32>>().unwrap(), ..7i32);
4359 }
4360
4361 #[test]
4362 fn range_to_inclusive_expression_constructs_a_range_to_inclusive() {
4363 let mut parser = CELParser::new(OpLookup::new());
4364 let mut seg = parser.parse_str("..=7i32").unwrap();
4365 assert_eq!(
4366 seg.call0::<std::ops::RangeToInclusive<i32>>().unwrap(),
4367 ..=7i32
4368 );
4369 }
4370
4371 #[test]
4372 fn range_full_expression_constructs_a_range_full() {
4373 let mut parser = CELParser::new(OpLookup::new());
4374 let mut seg = parser.parse_str("..").unwrap();
4375 seg.call0::<std::ops::RangeFull>().unwrap();
4376 }
4377
4378 #[test]
4379 fn range_endpoints_are_full_or_expressions() {
4380 let mut parser = CELParser::new(OpLookup::new());
4383 let mut seg = parser.parse_str("1i32 + 2i32..3i32 * 4i32").unwrap();
4384 assert_eq!(seg.call0::<std::ops::Range<i32>>().unwrap(), 3i32..12i32);
4385 }
4386
4387 #[test]
4388 fn chained_ranges_are_a_parse_error() {
4389 let mut parser = CELParser::new(OpLookup::new());
4394 let result = parser.parse_str("1i32..2i32..3i32");
4395 assert!(result.is_err(), "expected a parse error, got Ok");
4396 }
4397
4398 #[test]
4399 fn range_to_inclusive_without_a_right_operand_is_a_parse_error() {
4400 let mut parser = CELParser::new(OpLookup::new());
4402 let result = parser.parse_str("..=");
4403 assert!(result.is_err(), "expected a parse error, got Ok");
4404 }
4405
4406 #[test]
4407 fn range_endpoint_absorbs_a_trailing_comparison_confirming_or_expression_operands() {
4408 let mut parser = CELParser::new(OpLookup::new());
4414 let err = match parser.parse_str("1i32..5i32 == true") {
4415 Err(e) => e,
4416 Ok(_) => panic!("expected a parse error"),
4417 };
4418 let message = err.message();
4419 assert!(
4420 message.starts_with("no operation `==`"),
4421 "expected a 'no operation `==`' error, got: {message}"
4422 );
4423 assert!(
4424 !message.contains("Range"),
4425 "expected the error to be about `i32`/`bool` (the inner endpoint's own comparison), \
4426 not `Range<i32>` (which would mean `..` grabbed only `5i32` and `==` applied afterward \
4427 to an already-built range) — got: {message}"
4428 );
4429 }
4430
4431 #[test]
4432 fn parameter_list_accepts_a_range_expression() -> anyhow::Result<()> {
4433 let mut lookup = OpLookup::new();
4434 lookup.push_scope(
4435 |name, segment, num_operands, _span| match (name, num_operands) {
4436 ("f", 0) => {
4437 segment.op0(|| 0i32);
4438 Ok(true)
4439 }
4440 ("()", 2) => {
4441 segment.op2(|_callee: i32, arg: std::ops::Range<i32>| arg)?;
4442 Ok(true)
4443 }
4444 _ => Ok(false),
4445 },
4446 );
4447 let mut parser = CELParser::new(lookup);
4448 let mut segment = parser
4449 .parse_str("f(1i32..5i32)")
4450 .map_err(|e| anyhow::anyhow!("{}", e))?;
4451 assert_eq!(segment.call0::<std::ops::Range<i32>>()?, 1i32..5i32);
4452 Ok(())
4453 }
4454
4455 #[test]
4456 fn tuple_or_group_accepts_a_range_expression() -> anyhow::Result<()> {
4457 let mut parser = CELParser::new(OpLookup::new());
4458 let mut seg = parser.parse_str("(1i32..5i32)").unwrap();
4459 assert_eq!(seg.call0::<std::ops::Range<i32>>().unwrap(), 1i32..5i32);
4460 Ok(())
4461 }
4462
4463 #[test]
4464 fn if_expression_branches_accept_range_expressions() {
4465 let mut parser = CELParser::new(OpLookup::new());
4466 let mut seg = parser
4467 .parse_str("if true { 1i32..5i32 } else { 2i32..6i32 }")
4468 .unwrap();
4469 assert_eq!(seg.call0::<std::ops::Range<i32>>().unwrap(), 1i32..5i32);
4470 }
4471
4472 #[test]
4473 fn closure_body_accepts_a_range_expression() -> anyhow::Result<()> {
4474 let mut parser = CELParser::new(OpLookup::new());
4475 let mut segment = parser
4476 .parse_str("|| 1i32..5i32")
4477 .map_err(|e| anyhow::anyhow!("{}", e))?;
4478 let closure: cel_runtime::DynClosure = segment.call0()?;
4479 assert_eq!(closure.call::<std::ops::Range<i32>>(&[])?, 1i32..5i32);
4480 Ok(())
4481 }
4482
4483 fn array_parse_error(source: &str) -> ParseError {
4485 let mut parser = CELParser::new(OpLookup::new());
4486 match parser.parse_str(source) {
4487 Err(e) => e,
4488 Ok(_) => panic!("expected a parse error for `{source}`"),
4489 }
4490 }
4491
4492 #[test]
4493 fn array_literal_evaluates_to_its_elements_in_source_order() -> anyhow::Result<()> {
4494 let mut parser = CELParser::new(OpLookup::new());
4495 let mut segment = parser
4496 .parse_str("[0i32, 1i32, 2i32]")
4497 .map_err(|e| anyhow::anyhow!("{}", e))?;
4498 let array = segment
4499 .call0::<cel_runtime::OwnedValue>()?
4500 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4501 assert_eq!(array.into_vec(), vec![0, 1, 2]);
4502 Ok(())
4503 }
4504
4505 #[test]
4506 fn typed_array_annotation_preserves_unsuffixed_non_empty_inference() -> anyhow::Result<()> {
4507 let mut parser = CELParser::new(OpLookup::new());
4508 let mut segment = parser
4509 .parse_str("[0, 1]")
4510 .map_err(|e| anyhow::anyhow!("{}", e))?;
4511 let array = segment
4512 .call0::<cel_runtime::OwnedValue>()?
4513 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4514 assert_eq!(array.into_vec(), vec![0, 1]);
4515 Ok(())
4516 }
4517
4518 #[test]
4519 fn typed_array_annotation_evaluates_to_the_declared_scalar_type() -> anyhow::Result<()> {
4520 let mut parser = CELParser::new(OpLookup::new());
4521 let mut segment = parser
4522 .parse_str("[0, 1]: [i32]")
4523 .map_err(|e| anyhow::anyhow!("{}", e))?;
4524 let array = segment
4525 .call0::<cel_runtime::OwnedValue>()?
4526 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4527 assert_eq!(array.into_vec(), vec![0, 1]);
4528 Ok(())
4529 }
4530
4531 #[test]
4532 fn typed_array_annotation_evaluates_to_the_declared_f64_type() -> anyhow::Result<()> {
4533 let mut parser = CELParser::new(OpLookup::new());
4534 let mut segment = parser
4535 .parse_str("[1.0, 42.5]: [f64]")
4536 .map_err(|e| anyhow::anyhow!("{}", e))?;
4537 let array = segment
4538 .call0::<cel_runtime::OwnedValue>()?
4539 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<f64>>>()?;
4540 assert_eq!(array.into_vec(), vec![1.0, 42.5]);
4541 Ok(())
4542 }
4543
4544 #[test]
4545 fn typed_array_annotation_constructs_a_typed_empty_array() -> anyhow::Result<()> {
4546 let mut parser = CELParser::new(OpLookup::new());
4547 let mut segment = parser
4548 .parse_str("[]: [i32]")
4549 .map_err(|e| anyhow::anyhow!("{}", e))?;
4550 let array = segment
4551 .call0::<cel_runtime::OwnedValue>()?
4552 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4553 assert!(array.into_vec().is_empty());
4554 Ok(())
4555 }
4556
4557 #[test]
4558 fn typed_array_annotation_constructs_a_nested_typed_empty_array() -> anyhow::Result<()> {
4559 let mut parser = CELParser::new(OpLookup::new());
4560 let mut segment = parser
4561 .parse_str("[]: [[i32]]")
4562 .map_err(|e| anyhow::anyhow!("{}", e))?;
4563 let array = segment
4564 .call0::<cel_runtime::OwnedValue>()?
4565 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>>(
4566 )?;
4567 assert!(array.into_vec().is_empty());
4568 Ok(())
4569 }
4570
4571 #[test]
4572 fn single_element_array_literal_needs_no_trailing_comma() -> anyhow::Result<()> {
4573 let mut parser = CELParser::new(OpLookup::new());
4574 let mut segment = parser
4575 .parse_str("[7i32]")
4576 .map_err(|e| anyhow::anyhow!("{}", e))?;
4577 let array = segment
4578 .call0::<cel_runtime::OwnedValue>()?
4579 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4580 assert_eq!(array.into_vec(), vec![7]);
4581 Ok(())
4582 }
4583
4584 #[test]
4585 fn array_elements_can_be_arbitrary_expressions() -> anyhow::Result<()> {
4586 let mut parser = CELParser::new(OpLookup::new());
4587 let mut segment = parser
4588 .parse_str("[1i32 + 2i32, if true { 4i32 } else { 5i32 }]")
4589 .map_err(|e| anyhow::anyhow!("{}", e))?;
4590 let array = segment
4591 .call0::<cel_runtime::OwnedValue>()?
4592 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4593 assert_eq!(array.into_vec(), vec![3, 4]);
4594 Ok(())
4595 }
4596
4597 #[test]
4598 fn empty_array_literal_is_rejected_with_a_dedicated_diagnostic() {
4599 let err = array_parse_error("[]");
4600 assert!(
4601 err.message().contains("empty array"),
4602 "got: {}",
4603 err.message()
4604 );
4605 assert!(
4606 err.message().contains("issues/212"),
4607 "the diagnostic must reference the contextual-typing issue, got: {}",
4608 err.message()
4609 );
4610 }
4611
4612 #[test]
4613 fn array_literal_rejects_a_trailing_comma() {
4614 let err = array_parse_error("[0i32,]");
4615 assert!(
4616 err.message().contains("expected expression after ','"),
4617 "got: {}",
4618 err.message()
4619 );
4620 }
4621
4622 #[test]
4623 fn array_literal_requires_a_comma_between_elements() {
4624 let err = array_parse_error("[0i32 1i32]");
4625 assert!(
4626 err.message().contains("expected ',' or closing ']'"),
4627 "got: {}",
4628 err.message()
4629 );
4630 }
4631
4632 #[test]
4633 fn array_literal_rejects_a_mismatched_element_naming_its_index() {
4634 let err = array_parse_error("[0i32, 1.0f64]");
4635 assert!(
4636 err.message().contains("array element 1"),
4637 "got: {}",
4638 err.message()
4639 );
4640 }
4641
4642 #[test]
4643 fn array_literal_accepts_a_tuple_element() {
4644 use cel_runtime::{ArrayOf, Cons, Leaf, Nil};
4645 let body = CELParser::new(OpLookup::new())
4646 .parse_str("[(0i32, 1i32)]")
4647 .unwrap();
4648 assert!(
4649 body.prepare::<Nil, ArrayOf<Cons<Leaf<i32>, Cons<Leaf<i32>, Nil>>>>()
4650 .is_ok()
4651 );
4652 }
4653
4654 #[test]
4655 fn nested_array_literal_evaluates_to_an_array_of_arrays() -> anyhow::Result<()> {
4656 let mut parser = CELParser::new(OpLookup::new());
4657 let mut segment = parser
4658 .parse_str("[[0i32], [1i32]]")
4659 .map_err(|e| anyhow::anyhow!("{}", e))?;
4660 let array = segment
4661 .call0::<cel_runtime::OwnedValue>()?
4662 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>>(
4663 )?;
4664 let rows: Vec<_> = array
4665 .into_vec()
4666 .into_iter()
4667 .map(|row| row.into_vec())
4668 .collect();
4669 assert_eq!(rows, vec![vec![0], vec![1]]);
4670 Ok(())
4671 }
4672
4673 #[test]
4674 fn nested_array_literal_rejects_a_recursive_element_mismatch() {
4675 let err = array_parse_error("[[0i32], [1.0f64]]");
4676 assert!(
4677 err.message().contains("array element 1"),
4678 "got: {}",
4679 err.message()
4680 );
4681 }
4682
4683 #[test]
4684 fn nested_array_literal_rejects_a_depth_mismatch() {
4685 let err = array_parse_error("[[0i32], [[1i32]]]");
4686 assert!(
4687 err.message().contains("array element 1"),
4688 "got: {}",
4689 err.message()
4690 );
4691 }
4692
4693 #[test]
4694 fn typed_array_annotation_rejects_an_exact_element_type_mismatch() {
4695 let err = array_parse_error("[0, 1]: [f64]");
4696 assert!(
4697 err.message().contains("expected f64"),
4698 "got: {}",
4699 err.message()
4700 );
4701 assert!(err.message().contains("type i32"), "got: {}", err.message());
4702 }
4703
4704 #[test]
4705 fn typed_array_annotation_rejects_a_recursive_element_type_mismatch() {
4706 let err = array_parse_error("[[0, 1]]: [[f64]]");
4709 assert!(
4710 err.message().contains("expected [f64]"),
4711 "got: {}",
4712 err.message()
4713 );
4714 assert!(
4715 err.message().contains("type [i32]"),
4716 "got: {}",
4717 err.message()
4718 );
4719 }
4720
4721 #[test]
4722 fn typed_array_annotation_mismatch_names_the_registered_type_not_its_rust_path() {
4723 let resolver = [(
4724 "Celsius",
4725 ResolvedLeafType::new("Celsius", cel_runtime::ValueType::leaf::<Celsius>()),
4726 )];
4727 let mut parser = CELParser::with_type_resolver(OpLookup::new(), resolver);
4728 let err = match parser.parse_str("[0]: [Celsius]") {
4729 Err(e) => e,
4730 Ok(_) => panic!("expected `[0]: [Celsius]` to reject its `i32` element"),
4731 };
4732 assert!(
4733 err.message().contains("expected Celsius"),
4734 "the registered annotation name must survive into the diagnostic, got: {}",
4735 err.message()
4736 );
4737 assert!(
4738 !err.message().contains("::"),
4739 "no Rust type path may leak into the diagnostic, got: {}",
4740 err.message()
4741 );
4742 }
4743
4744 #[test]
4747 fn typed_array_annotation_rejects_a_nested_custom_element_type_mismatch() {
4748 #[derive(Clone)]
4749 struct CustomB;
4750
4751 let resolver = [
4752 (
4753 "Celsius",
4754 ResolvedLeafType::new("Celsius", cel_runtime::ValueType::leaf::<Celsius>()),
4755 ),
4756 (
4757 "CustomB",
4758 ResolvedLeafType::new("CustomB", cel_runtime::ValueType::leaf::<CustomB>()),
4759 ),
4760 ];
4761 let mut parser = CELParser::with_type_resolver(OpLookup::new(), resolver);
4762 let err = match parser.parse_str("[[]: [Celsius]]: [[CustomB]]") {
4763 Err(e) => e,
4764 Ok(_) => panic!("expected the inner annotation to conflict with the outer one"),
4765 };
4766 assert!(
4767 err.message().contains("expected [CustomB]"),
4768 "got: {}",
4769 err.message()
4770 );
4771 assert!(
4772 err.message().contains("[Celsius]"),
4773 "got: {}",
4774 err.message()
4775 );
4776 }
4777
4778 #[test]
4779 fn typed_array_annotation_rejects_an_unknown_type_name() {
4780 let err = array_parse_error("[0]: [Nope]");
4781 assert!(
4782 err.message().contains("unknown type `Nope`"),
4783 "got: {}",
4784 err.message()
4785 );
4786 }
4787
4788 #[test]
4789 fn typed_array_annotation_requires_a_complete_array_type() {
4790 let err = array_parse_error("[0]: i32");
4791 assert!(
4792 err.message()
4793 .contains("array annotations must name a complete array type"),
4794 "got: {}",
4795 err.message()
4796 );
4797 }
4798
4799 #[test]
4800 fn typed_array_annotation_accepts_tuple_array_elements() {
4801 use cel_runtime::{ArrayOf, Cons, Leaf, Nil};
4802 let body = CELParser::new(OpLookup::new())
4803 .parse_str("[]: [(i32, f64)]")
4804 .unwrap();
4805 assert!(
4806 body.prepare::<Nil, ArrayOf<Cons<Leaf<i32>, Cons<Leaf<f64>, Nil>>>>()
4807 .is_ok()
4808 );
4809 }
4810
4811 #[test]
4812 fn array_literal_is_accepted_as_a_call_argument() -> anyhow::Result<()> {
4813 let mut lookup = OpLookup::new();
4814 lookup.push_scope(
4815 |name, segment, num_operands, _span| match (name, num_operands) {
4816 ("len", 0) => {
4817 segment.op0(|| 0i32);
4818 Ok(true)
4819 }
4820 ("()", 2) => {
4821 segment.op2_repr::<cel_runtime::Leaf<i32>, cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>, cel_runtime::Leaf<i32>, _>(
4822 |_callee, arg| arg.len() as i32)?;
4823 Ok(true)
4824 }
4825 _ => Ok(false),
4826 },
4827 );
4828 let mut parser = CELParser::new(lookup);
4829 let mut segment = parser
4830 .parse_str("len([1i32, 2i32, 3i32])")
4831 .map_err(|e| anyhow::anyhow!("{}", e))?;
4832 assert_eq!(segment.call0::<i32>()?, 3);
4833 Ok(())
4834 }
4835
4836 #[test]
4837 fn array_literal_is_accepted_as_a_tuple_element() -> anyhow::Result<()> {
4838 let mut parser = CELParser::new(OpLookup::new());
4839 let mut segment = parser
4840 .parse_str("([1i32, 2i32], 3i32).0")
4841 .map_err(|e| anyhow::anyhow!("{}", e))?;
4842 let array = segment
4843 .call0::<cel_runtime::OwnedValue>()?
4844 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4845 assert_eq!(array.into_vec(), vec![1, 2]);
4846 Ok(())
4847 }
4848
4849 #[test]
4850 fn array_literal_is_accepted_inside_an_if_branch() -> anyhow::Result<()> {
4851 let mut parser = CELParser::new(OpLookup::new());
4852 let mut segment = parser
4853 .parse_str("if true { [1i32, 2i32] } else { [3i32, 4i32] }")
4854 .map_err(|e| anyhow::anyhow!("{}", e))?;
4855 let array = segment
4856 .call0::<cel_runtime::OwnedValue>()?
4857 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4858 assert_eq!(array.into_vec(), vec![1, 2]);
4859 Ok(())
4860 }
4861
4862 #[test]
4863 fn array_literal_is_accepted_as_a_closure_body() -> anyhow::Result<()> {
4864 let mut parser = CELParser::new(OpLookup::new());
4865 let mut segment = parser
4866 .parse_str("|x: i32| [x, x]")
4867 .map_err(|e| anyhow::anyhow!("{}", e))?;
4868 let closure: cel_runtime::DynClosure = segment.call0()?;
4869 let x = 5i32;
4870 let array = closure
4871 .call::<cel_runtime::OwnedValue>(&[&x])?
4872 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4873 assert_eq!(array.into_vec(), vec![5, 5]);
4874 Ok(())
4875 }
4876
4877 #[test]
4878 fn array_ambient_start_is_correct_after_a_sibling_expression() -> anyhow::Result<()> {
4879 let mut parser = CELParser::new(OpLookup::new());
4886 let mut segment = parser
4887 .parse_str("(1u8 + 2u8, [3i32, 4i32]).1")
4888 .map_err(|e| anyhow::anyhow!("{}", e))?;
4889 let array = segment
4890 .call0::<cel_runtime::OwnedValue>()?
4891 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<i32>>>()?;
4892 assert_eq!(array.into_vec(), vec![3, 4]);
4893 Ok(())
4894 }
4895
4896 struct Celsius(i32);
4899
4900 struct Fahrenheit(i32);
4903
4904 struct FName;
4906
4907 struct GName;
4909
4910 struct HName;
4912
4913 fn temperature_lookup(homogeneous: bool) -> OpLookup {
4917 let mut lookup = OpLookup::new();
4918 lookup.push_scope(
4919 move |name, segment, num_operands, _span| match (name, num_operands) {
4920 ("f", 0) => {
4921 segment.op0(|| FName);
4922 Ok(true)
4923 }
4924 ("g", 0) => {
4925 segment.op0(|| GName);
4926 Ok(true)
4927 }
4928 ("h", 0) => {
4929 segment.op0(|| HName);
4930 Ok(true)
4931 }
4932 ("()", 1) => {
4933 let Some(callee) = segment
4934 .peek_stack_infos(1)
4935 .first()
4936 .map(|i| i.value_type.type_id())
4937 else {
4938 return Ok(false);
4939 };
4940 if callee == TypeId::of::<FName>() {
4941 segment.op1(|_: FName| Celsius(0))?;
4942 } else if callee == TypeId::of::<GName>() {
4943 segment.op1(|_: GName| Celsius(1))?;
4944 } else if callee == TypeId::of::<HName>() {
4945 if homogeneous {
4946 segment.op1(|_: HName| Celsius(2))?;
4947 } else {
4948 segment.op1(|_: HName| Fahrenheit(2))?;
4949 }
4950 } else {
4951 return Ok(false);
4952 }
4953 Ok(true)
4954 }
4955 _ => Ok(false),
4956 },
4957 );
4958 lookup
4959 }
4960
4961 #[test]
4962 fn array_literal_of_calls_returning_a_custom_type_converts_to_its_vector() -> anyhow::Result<()>
4963 {
4964 let mut parser = CELParser::new(temperature_lookup(true));
4965 let mut segment = parser
4966 .parse_str("[f(), g(), h()]")
4967 .map_err(|e| anyhow::anyhow!("{}", e))?;
4968 let array = segment
4969 .call0::<cel_runtime::OwnedValue>()?
4970 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<Celsius>>>()?;
4971 let degrees: Vec<i32> = array.into_vec().into_iter().map(|c| c.0).collect();
4972 assert_eq!(degrees, vec![0, 1, 2]);
4973 Ok(())
4974 }
4975
4976 #[test]
4977 fn array_literal_of_one_custom_typed_call_evaluates_to_that_type() -> anyhow::Result<()> {
4978 let mut parser = CELParser::new(temperature_lookup(false));
4981 let mut segment = parser
4982 .parse_str("[h()]")
4983 .map_err(|e| anyhow::anyhow!("{}", e))?;
4984 let array = segment
4985 .call0::<cel_runtime::OwnedValue>()?
4986 .try_into_typed::<cel_runtime::ArrayOf<cel_runtime::Leaf<Fahrenheit>>>()?;
4987 let degrees: Vec<i32> = array.into_vec().into_iter().map(|f| f.0).collect();
4988 assert_eq!(degrees, vec![2]);
4989 Ok(())
4990 }
4991
4992 #[test]
4993 fn array_literal_of_calls_rejects_a_mismatched_return_type_before_execution() {
4994 let mut parser = CELParser::new(temperature_lookup(false));
4997 let err = match parser.parse_str("[f(), g(), h()]") {
4998 Err(e) => e,
4999 Ok(_) => panic!("expected `[f(), g(), h()]` with a mismatched `h` to fail"),
5000 };
5001 let message = err.message();
5002 assert!(message.contains("array element 2"), "got: {message}");
5003 assert!(message.contains("Fahrenheit"), "got: {message}");
5004 assert!(message.contains("Celsius"), "got: {message}");
5005 }
5006
5007 #[test]
5008 fn static_check_and_execution_agree_on_a_nested_custom_typed_array() -> anyhow::Result<()> {
5009 const SOURCE: &str = "[[f(), g()], [h()]]";
5010
5011 let mut ast_parser = Parser::<AstContext>::new(OpLookup::new());
5015 let expr = ast_parser
5016 .parse_str_ast(SOURCE)
5017 .map_err(|e| anyhow::anyhow!("{}", e))?;
5018 let (ty, diagnostics) = ty::check_expr(&expr, &|_name| Ty::Any);
5019 let messages: Vec<String> = diagnostics
5020 .iter()
5021 .map(|d| d.message().to_string())
5022 .collect();
5023 assert!(messages.is_empty(), "unexpected diagnostics: {messages:?}");
5024 assert_eq!(ty, Ty::Array(Box::new(Ty::Array(Box::new(Ty::Any)))));
5025
5026 let mut parser = CELParser::new(temperature_lookup(true));
5028 let mut segment = parser
5029 .parse_str(SOURCE)
5030 .map_err(|e| anyhow::anyhow!("{}", e))?;
5031 let array = segment.call0::<cel_runtime::OwnedValue>()?.try_into_typed::<cel_runtime::ArrayOf<cel_runtime::ArrayOf<cel_runtime::Leaf<Celsius>>>>()?;
5032 let mut rows: Vec<Vec<i32>> = Vec::new();
5033 for row in array.into_vec() {
5034 rows.push(row.into_vec().into_iter().map(|c| c.0).collect());
5035 }
5036 assert_eq!(rows, vec![vec![0, 1], vec![2]]);
5037 Ok(())
5038 }
5039}
5040
5041#[cfg(test)]
5042mod playground {
5043 use super::*;
5044 use annotate_snippets::Renderer;
5045
5046 #[test]
5047 fn custom_scope_identifier() -> Result<()> {
5048 let mut lookup = OpLookup::new();
5049 lookup.push_scope(|name, segment, _num_operands, _span| {
5050 if name == "constant" {
5051 segment.just(42i64);
5052 return Ok(true);
5053 }
5054 Ok(false)
5055 });
5056 let mut parser = CELParser::new(lookup);
5057 let mut segment = parser.parse_str("constant == 42i64 && 15i64 < constant")?;
5058 assert!(segment.call0::<bool>().unwrap());
5059 Ok(())
5060 }
5061 #[test]
5062 fn literal_types() {
5063 use CELParser;
5064 use op_table::OpLookup;
5065 let source = r#"
5066 b'a'
5067 "#;
5068 assert_eq!(
5069 CELParser::new(OpLookup::new())
5070 .parse_str(source)
5071 .unwrap()
5072 .call0::<u8>()
5073 .unwrap(),
5074 b'a'
5075 );
5076 }
5077
5078 #[test]
5079 fn expression_macro_error3() {
5080 use CELParser;
5081 use op_table::OpLookup;
5082
5083 let line = line!() + 1;
5084 let source = r#"
5085 "Hello" + "World" + 32.0
5086 "#;
5087 match CELParser::new(OpLookup::new()).parse_str(source) {
5088 Ok(_) => panic!("expected parse error"),
5089 Err(e) => println!(
5090 "{}",
5091 e.format_rustc_style(source, file!(), line, &Renderer::styled())
5092 ),
5093 }
5094 }
5095
5096 #[test]
5097 fn arithmetic_overflow_error() {
5098 use error::FormatRustcStyle;
5099
5100 let line = line!() + 1;
5101 let source = r#"
5102 1 + 1 +
5103 2147483646 + 1
5104 "#;
5105 let mut seg = CELParser::new(OpLookup::new())
5106 .parse_str(source)
5107 .expect("parses successfully");
5108 match seg.call0::<i32>() {
5109 Ok(v) => panic!("expected overflow, got {v}"),
5110 Err(e) => println!(
5111 "{}",
5112 e.format_rustc_style(source, file!(), line, &Renderer::styled())
5113 ),
5114 }
5115 }
5116}