1use core::error::Error;
2use std::{cell::RefCell, fmt::Display, mem, ops::Deref, rc::Rc, sync::Arc};
3
4use antlr4rust::{
5 InputStream, Parser as AntlrParser,
6 common_token_stream::CommonTokenStream,
7 error_listener::ErrorListener,
8 errors::ANTLRError,
9 parser::ParserNodeType,
10 parser_rule_context::ParserRuleContext,
11 recognizer::Recognizer,
12 token::{CommonToken, Token},
13 token_factory::TokenFactory,
14 tree::{ParseTree, ParseTreeVisitorCompat, VisitChildren},
15};
16
17use crate::{
18 common::{
19 ast,
20 ast::{
21 CallExpr, EntryExpr, Expr, IdedEntryExpr, IdedExpr, ListExpr, MapEntryExpr, MapExpr, SelectExpr,
22 SourceInfo, StructExpr, StructFieldExpr, operators,
23 },
24 value::CelVal,
25 },
26 parser::{
27 generated,
28 generated::{
29 BoolFalseContext, BoolTrueContext, BytesContext, CalcContext, CalcContextAttrs, ConditionalAndContext,
30 ConditionalOrContext, ConstantLiteralContext, ConstantLiteralContextAttrs, CreateListContext,
31 CreateMessageContext, CreateStructContext, DoubleContext, ExprContext, FieldInitializerListContext,
32 GlobalCallContext, IdentContext, IndexContext, IndexContextAttrs, IntContext, ListInitContextAll,
33 LogicalNotContext, LogicalNotContextAttrs, MapInitializerListContextAll, MemberCallContext,
34 MemberCallContextAttrs, MemberExprContext, MemberExprContextAttrs, NegateContext, NegateContextAttrs,
35 NestedContext, NullContext, OptFieldContextAttrs, PrimaryExprContext, PrimaryExprContextAttrs,
36 RelationContext, RelationContextAttrs, SelectContext, SelectContextAttrs, StartContext, StartContextAttrs,
37 StringContext, UintContext,
38 },
39 macros, parse,
40 },
41};
42
43pub struct MacroExprHelper<'a> {
44 helper: &'a mut ParserHelper,
45 id: u64,
46}
47
48impl MacroExprHelper<'_> {
49 pub fn next_expr(&mut self, expr: Expr) -> IdedExpr {
50 self.helper.next_expr_for(self.id, expr)
51 }
52
53 pub(crate) fn pos_for(&self, id: u64) -> Option<(isize, isize)> {
54 self.helper.source_info.pos_for(id)
55 }
56}
57
58#[derive(Debug)]
59pub struct ParseErrors {
60 pub errors: Vec<ParseError>,
61}
62
63impl Display for ParseErrors {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 for (i, e) in self.errors.iter().enumerate() {
66 if i != 0 {
67 writeln!(f)?;
68 }
69 write!(f, "{e}")?;
70 }
71 Ok(())
72 }
73}
74
75impl Error for ParseErrors {}
76
77#[allow(dead_code)]
78#[derive(Debug)]
79pub struct ParseError {
80 pub source: Option<Box<dyn Error + Send + Sync + 'static>>,
81 pub pos: (isize, isize),
82 pub msg: String,
83 pub expr_id: u64,
84 pub source_info: Option<Arc<SourceInfo>>,
85}
86
87impl Display for ParseError {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 write!(f, "ERROR: <input>:{}:{}: {}", self.pos.0, self.pos.1, self.msg)?;
90 if let Some(info) = &self.source_info {
91 if let Some(line) = info.snippet(self.pos.0 - 1) {
92 write!(f, "\n| {line}")?;
93 write!(f, "\n| {:.>width$}", "^", width = self.pos.1 as usize)?;
94 }
95 }
96 Ok(())
97 }
98}
99
100impl Error for ParseError {}
101
102pub struct Parser {
103 ast: ast::Ast,
104 helper: ParserHelper,
105 errors: Vec<ParseError>,
106}
107
108impl Parser {
109 pub fn new() -> Self {
110 Self {
111 ast: ast::Ast {
112 expr: IdedExpr::default(),
113 },
114 helper: ParserHelper::default(),
115 errors: Vec::default(),
116 }
117 }
118
119 fn new_logic_manager(&self, func: &str, term: IdedExpr) -> LogicManager {
120 LogicManager {
121 function: func.to_string(),
122 terms: vec![term],
123 ops: vec![],
124 }
125 }
126
127 fn global_call_or_macro(&mut self, id: u64, func_name: String, args: Vec<IdedExpr>) -> IdedExpr {
128 match macros::find_expander(&func_name, None, &args) {
129 None => IdedExpr {
130 id,
131 expr: Expr::Call(CallExpr {
132 target: None,
133 func_name,
134 args,
135 }),
136 },
137 Some(expander) => {
138 let mut helper = MacroExprHelper {
139 helper: &mut self.helper,
140 id,
141 };
142 match expander(&mut helper, None, args) {
143 Ok(expr) => expr,
144 Err(err) => self.report_parse_error(None, err),
145 }
146 }
147 }
148 }
149
150 fn receiver_call_or_macro(
151 &mut self,
152 id: u64,
153 func_name: String,
154 target: IdedExpr,
155 args: Vec<IdedExpr>,
156 ) -> IdedExpr {
157 match macros::find_expander(&func_name, Some(&target), &args) {
158 None => IdedExpr {
159 id,
160 expr: Expr::Call(CallExpr {
161 target: Some(Box::new(target)),
162 func_name,
163 args,
164 }),
165 },
166 Some(expander) => {
167 let mut helper = MacroExprHelper {
168 helper: &mut self.helper,
169 id,
170 };
171 match expander(&mut helper, Some(target), args) {
172 Ok(expr) => expr,
173 Err(err) => self.report_parse_error(None, err),
174 }
175 }
176 }
177 }
178
179 pub fn parse(mut self, source: &str) -> Result<IdedExpr, ParseErrors> {
180 let parse_errors = Rc::new(RefCell::new(Vec::<ParseError>::new()));
181 let stream = InputStream::new(source);
182 let mut lexer = generated::CELLexer::new(stream);
183 lexer.remove_error_listeners();
184 lexer.add_error_listener(Box::new(ParserErrorListener {
185 parse_errors: parse_errors.clone(),
186 }));
187
188 self.helper.source_info.source = source.into();
190
191 let mut prsr = generated::CELParser::new(CommonTokenStream::new(lexer));
192 prsr.remove_error_listeners();
193 prsr.add_error_listener(Box::new(ParserErrorListener {
194 parse_errors: parse_errors.clone(),
195 }));
196 let r = match prsr.start() {
197 Ok(t) => Ok(self.visit(t.deref())),
198 Err(e) => Err(ParseError {
199 source: Some(Box::new(e)),
200 pos: (0, 0),
201 msg: "UNKNOWN".to_string(),
202 expr_id: 0,
203 source_info: None,
204 }),
205 };
206
207 let info = self.helper.source_info;
208 let source_info = Arc::new(info);
209
210 let mut errors = parse_errors.take();
211 errors.extend(self.errors);
212 errors.sort_by(|a, b| a.pos.cmp(&b.pos));
213
214 if errors.is_empty() {
215 r.map_err(|e| ParseErrors {
216 errors: vec![e],
217 })
218 } else {
219 Err(ParseErrors {
220 errors: errors
221 .into_iter()
222 .map(|mut e: ParseError| {
223 e.source_info = Some(source_info.clone());
224 e
225 })
226 .collect(),
227 })
228 }
229 }
230
231 fn field_initializer_list(&mut self, ctx: &FieldInitializerListContext<'_>) -> Vec<IdedEntryExpr> {
232 let mut fields = Vec::with_capacity(ctx.fields.len());
233 for (i, field) in ctx.fields.iter().enumerate() {
234 if i >= ctx.cols.len() || i >= ctx.values.len() {
235 return vec![];
236 }
237 let id = self.helper.next_id(&ctx.cols[i]);
238
239 match field.escapeIdent() {
240 None => {
241 self.report_error::<ParseError, _>(field.start().deref(), None, "unsupported ident type");
242 continue;
243 }
244 Some(ident) => {
245 let field_name = ident.get_text().to_string();
246 let value = self.visit(ctx.values[i].as_ref());
247 if let Some(opt) = &field.opt {
248 self.report_error::<ParseError, _>(opt.as_ref(), None, "unsupported syntax '?'");
249 continue;
250 }
251 fields.push(IdedEntryExpr {
252 id,
253 expr: EntryExpr::StructField(StructFieldExpr {
254 field: field_name,
255 value,
256 optional: false,
257 }),
258 });
259 }
260 }
261 }
262 fields
263 }
264
265 fn map_initializer_list(&mut self, ctx: &MapInitializerListContextAll) -> Vec<IdedEntryExpr> {
266 if ctx.keys.is_empty() {
267 return vec![];
268 }
269 let mut entries = Vec::with_capacity(ctx.cols.len());
270 let keys = &ctx.keys;
271 let vals = &ctx.values;
272 for (i, col) in ctx.cols.iter().enumerate() {
273 if i >= keys.len() || i >= vals.len() {
274 return vec![];
275 }
276 let id = self.helper.next_id(col);
277 let key = self.visit(keys[i].as_ref());
278 if let Some(opt) = &keys[i].opt {
279 self.report_error::<ParseError, _>(opt.as_ref(), None, "unsupported syntax '?'");
280 continue;
281 }
282 let value = self.visit(vals[i].as_ref());
283 entries.push(IdedEntryExpr {
284 id,
285 expr: EntryExpr::MapEntry(MapEntryExpr {
286 key,
287 value,
288 optional: false,
289 }),
290 })
291 }
292 entries
293 }
294
295 fn list_initializer_list(&mut self, ctx: &ListInitContextAll) -> Vec<IdedExpr> {
296 let mut list = Vec::default();
297 for e in &ctx.elems {
298 match &e.e {
299 None => return Vec::default(),
300 Some(exp) => {
301 if let Some(opt) = &e.opt {
302 self.report_error::<ParseError, _>(opt.as_ref(), None, "unsupported syntax '?'");
303 continue;
304 }
305 list.push(self.visit(exp.as_ref()));
306 }
307 }
308 }
309 list
310 }
311
312 fn report_error<E: Error + Send + Sync + 'static, S: Into<String>>(
313 &mut self,
314 token: &CommonToken,
315 e: Option<E>,
316 s: S,
317 ) -> IdedExpr {
318 let error = ParseError {
319 source: e.map(|e| e.into()),
320 pos: (token.line, token.column + 1),
321 msg: s.into(),
322 expr_id: 0,
323 source_info: None,
324 };
325 self.report_parse_error(Some(token), error)
326 }
327
328 fn report_parse_error(&mut self, token: Option<&CommonToken>, mut e: ParseError) -> IdedExpr {
329 let expr = if let Some(token) = token {
330 self.helper.next_expr(token, Expr::default())
331 } else {
332 IdedExpr {
333 id: 0,
334 expr: Expr::default(),
335 }
336 };
337 e.expr_id = expr.id;
338 self.errors.push(e);
339 expr
340 }
341}
342
343struct ParserErrorListener {
344 parse_errors: Rc<RefCell<Vec<ParseError>>>,
345}
346
347impl<'a, T: Recognizer<'a>> ErrorListener<'a, T> for ParserErrorListener {
348 fn syntax_error(
349 &self,
350 _recognizer: &T,
351 offending_symbol: Option<&<T::TF as TokenFactory<'a>>::Inner>,
352 line: isize,
353 column: isize,
354 msg: &str,
355 _error: Option<&ANTLRError>,
356 ) {
357 match offending_symbol {
358 Some(offending_symbol) if offending_symbol.get_token_type() == generated::cellexer::WHITESPACE => {}
359 _ => self.parse_errors.borrow_mut().push(ParseError {
360 source: None,
361 pos: (line, column + 1),
362 msg: format!("Syntax error: {msg}"),
363 expr_id: 0,
364 source_info: None,
365 }),
366 }
367 }
368}
369
370impl Default for Parser {
371 fn default() -> Self {
372 Self::new()
373 }
374}
375
376impl ParseTreeVisitorCompat<'_> for Parser {
377 type Node = generated::CELParserContextType;
378 type Return = IdedExpr;
379 fn temp_result(&mut self) -> &mut Self::Return {
380 &mut self.ast.expr
381 }
382
383 fn visit(&mut self, node: &<Self::Node as ParserNodeType<'_>>::Type) -> Self::Return {
384 self.visit_node(node);
386 mem::take(self.temp_result())
387 }
388
389 fn aggregate_results(&self, _aggregate: Self::Return, next: Self::Return) -> Self::Return {
390 next
391 }
392}
393
394impl generated::CELVisitorCompat<'_> for Parser {
395 fn visit_start(&mut self, ctx: &StartContext<'_>) -> Self::Return {
396 match &ctx.expr() {
397 None => self.report_error::<ParseError, _>(ctx.start().deref(), None, "No `ExprContextAll`!"),
398 Some(expr) => self.visit(expr.as_ref()),
399 }
400 }
401
402 fn visit_expr(&mut self, ctx: &ExprContext<'_>) -> Self::Return {
403 match &ctx.op {
404 None => match &ctx.e {
405 None => self.report_error::<ParseError, _>(ctx.start().deref(), None, "No `ConditionalOrContextAll`!"),
406 Some(e) => <Self as ParseTreeVisitorCompat>::visit(self, e.as_ref()),
407 },
408 Some(op) => {
409 if let (Some(e), Some(e1), Some(e2)) = (&ctx.e, &ctx.e1, &ctx.e2) {
410 let result = self.visit(e.as_ref());
411 let op_id = self.helper.next_id(op);
412 let if_true = self.visit(e1.as_ref());
413 let if_false = self.visit(e2.as_ref());
414 self.global_call_or_macro(
415 op_id,
416 operators::CONDITIONAL.to_string(),
417 vec![result, if_true, if_false],
418 )
419 } else {
420 self.report_error::<ParseError, _>(
421 ctx.start().deref(),
422 None,
423 format!("Incomplete `ExprContext` for `{}` expression!", operators::CONDITIONAL),
424 )
425 }
426 }
427 }
428 }
429
430 fn visit_conditionalOr(&mut self, ctx: &ConditionalOrContext<'_>) -> Self::Return {
431 let result = match &ctx.e {
432 None => {
433 self.report_error::<ParseError, _>(ctx.start().deref(), None, "No `ConditionalAndContextAll`!");
434 IdedExpr::default()
435 }
436 Some(e) => <Self as ParseTreeVisitorCompat>::visit(self, e.as_ref()),
437 };
438 if ctx.ops.is_empty() {
439 result
440 } else {
441 let mut l = self.new_logic_manager(operators::LOGICAL_OR, result);
442 let rest = &ctx.e1;
443 if ctx.ops.len() > rest.len() {
444 self.report_error::<ParseError, _>(&ctx.start(), None, "unexpected character, wanted '||'");
446 return IdedExpr::default();
447 }
448 for (i, op) in ctx.ops.iter().enumerate() {
449 let next = self.visit(rest[i].deref());
450 let op_id = self.helper.next_id(op);
451 l.add_term(op_id, next)
452 }
453 l.expr()
454 }
455 }
456
457 fn visit_conditionalAnd(&mut self, ctx: &ConditionalAndContext<'_>) -> Self::Return {
458 let result = match &ctx.e {
459 None => self.report_error::<ParseError, _>(ctx.start().deref(), None, "No `RelationContextAll`!"),
460 Some(e) => <Self as ParseTreeVisitorCompat>::visit(self, e.as_ref()),
461 };
462 if ctx.ops.is_empty() {
463 result
464 } else {
465 let mut l = self.new_logic_manager(operators::LOGICAL_AND, result);
466 let rest = &ctx.e1;
467 if ctx.ops.len() > rest.len() {
468 self.report_error::<ParseError, _>(&ctx.start(), None, "unexpected character, wanted '&&'");
470 return IdedExpr::default();
471 }
472 for (i, op) in ctx.ops.iter().enumerate() {
473 let next = self.visit(rest[i].deref());
474 let op_id = self.helper.next_id(op);
475 l.add_term(op_id, next)
476 }
477 l.expr()
478 }
479 }
480
481 fn visit_relation(&mut self, ctx: &RelationContext<'_>) -> Self::Return {
482 if ctx.op.is_none() {
483 match ctx.calc() {
484 None => self.report_error::<ParseError, _>(ctx.start().deref(), None, "No `CalcContextAll`!"),
485 Some(calc) => <Self as ParseTreeVisitorCompat>::visit(self, calc.as_ref()),
486 }
487 } else {
488 match &ctx.op {
489 None => <Self as ParseTreeVisitorCompat>::visit_children(self, ctx),
490 Some(op) => {
491 if let (Some(lhs), Some(rhs)) = (ctx.relation(0), ctx.relation(1)) {
492 let lhs = self.visit(lhs.as_ref());
493 let op_id = self.helper.next_id(op.as_ref());
494 let rhs = self.visit(rhs.as_ref());
495 match operators::find_operator(op.get_text()) {
496 None => {
497 self.report_error::<ParseError, _>(
498 op.as_ref(),
499 None,
500 format!("Unknown `{}` operator!", op.get_text()),
501 );
502 IdedExpr::default()
503 }
504 Some(op) => self.global_call_or_macro(op_id, op.to_string(), vec![lhs, rhs]),
505 }
506 } else {
507 self.report_error::<ParseError, _>(
508 ctx.start().deref(),
509 None,
510 format!("Incomplete `RelationContext` for `{:?}`!", ctx.op),
511 )
512 }
513 }
514 }
515 }
516 }
517
518 fn visit_calc(&mut self, ctx: &CalcContext<'_>) -> Self::Return {
519 match &ctx.op {
520 None => match &ctx.unary() {
521 None => self.report_error::<ParseError, _>(ctx.start().deref(), None, "No `UnaryContextAll`!"),
522 Some(unary) => self.visit(unary.as_ref()),
523 },
524 Some(op) => {
525 if let (Some(lhs), Some(rhs)) = (ctx.calc(0), ctx.calc(1)) {
526 let lhs = self.visit(lhs.as_ref());
527 let op_id = self.helper.next_id(op);
528 let rhs = self.visit(rhs.as_ref());
529 match operators::find_operator(op.get_text()) {
530 None => self.report_error::<ParseError, _>(
531 op,
532 None,
533 format!("Unknown `{}` operator!", op.get_text()),
534 ),
535 Some(op) => self.global_call_or_macro(op_id, op.to_string(), vec![lhs, rhs]),
536 }
537 } else {
538 self.report_error::<ParseError, _>(ctx.start().deref(), None, "Incomplete `CalcContext`!")
539 }
540 }
541 }
542 }
543
544 fn visit_MemberExpr(&mut self, ctx: &MemberExprContext<'_>) -> Self::Return {
545 match &ctx.member() {
546 None => self.report_error::<ParseError, _>(&ctx.start(), None, "No `MemberContextAll`!"),
547 Some(ctx) => <Self as ParseTreeVisitorCompat>::visit(self, ctx.as_ref()),
548 }
549 }
550
551 fn visit_LogicalNot(&mut self, ctx: &LogicalNotContext<'_>) -> Self::Return {
552 match &ctx.member() {
553 None => {
554 self.report_error::<ParseError, _>(&ctx.start(), None, "No `MemberContextAll`!");
555 IdedExpr::default()
556 }
557 Some(member) => {
558 if ctx.ops.len().is_multiple_of(2) {
559 self.visit(member.as_ref());
560 }
561 let op_id = self.helper.next_id(&ctx.ops[0]);
562 let target = self.visit(member.as_ref());
563 self.global_call_or_macro(op_id, operators::LOGICAL_NOT.to_string(), vec![target])
564 }
565 }
566 }
567
568 fn visit_Negate(&mut self, ctx: &NegateContext<'_>) -> Self::Return {
569 match &ctx.member() {
570 None => self.report_error::<ParseError, _>(&ctx.start(), None, "No `MemberContextAll`!"),
571 Some(member) => {
572 if ctx.ops.len().is_multiple_of(2) {
573 self.visit(member.as_ref());
574 }
575 let op_id = self.helper.next_id(&ctx.ops[0]);
576 let target = self.visit(member.as_ref());
577 self.global_call_or_macro(op_id, operators::NEGATE.to_string(), vec![target])
578 }
579 }
580 }
581
582 fn visit_MemberCall(&mut self, ctx: &MemberCallContext<'_>) -> Self::Return {
583 if let (Some(operand), Some(id), Some(open)) = (&ctx.member(), &ctx.id, &ctx.open) {
584 let operand = self.visit(operand.as_ref());
585 let id = id.get_text();
586 let op_id = self.helper.next_id(open.as_ref());
587 let args = ctx
588 .args
589 .iter()
590 .flat_map(|arg| &arg.e)
591 .map(|arg| self.visit(arg.deref()))
592 .collect::<Vec<IdedExpr>>();
593 self.receiver_call_or_macro(op_id, id.to_string(), operand, args)
594 } else {
595 self.report_error::<ParseError, _>(&ctx.start(), None, "Incomplete `MemberCallContext`!")
596 }
597 }
598
599 fn visit_Select(&mut self, ctx: &SelectContext<'_>) -> Self::Return {
600 if let (Some(member), Some(id), Some(op)) = (&ctx.member(), &ctx.id, &ctx.op) {
601 let operand = self.visit(member.as_ref());
602 let field = id.get_text();
603 if let Some(_opt) = &ctx.opt {
604 return self.report_error::<ParseError, _>(op.as_ref(), None, "unsupported syntax '.?'");
605 }
606 self.helper.next_expr(
607 op.as_ref(),
608 Expr::Select(SelectExpr {
609 operand: Box::new(operand),
610 field,
611 test: false,
612 }),
613 )
614 } else {
615 self.report_error::<ParseError, _>(&ctx.start(), None, "Incomplete `SelectContext`!")
616 }
617 }
618
619 fn visit_PrimaryExpr(&mut self, ctx: &PrimaryExprContext<'_>) -> Self::Return {
620 match &ctx.primary() {
621 None => self.report_error::<ParseError, _>(&ctx.start(), None, "No `PrimaryContextAll`!"),
622 Some(primary) => <Self as ParseTreeVisitorCompat>::visit(self, primary.as_ref()),
623 }
624 }
625
626 fn visit_Index(&mut self, ctx: &IndexContext<'_>) -> Self::Return {
627 if let (Some(member), Some(index)) = (&ctx.member(), &ctx.index) {
628 let target = self.visit(member.as_ref());
629 match &ctx.op {
630 None => self.report_error::<ParseError, _>(&ctx.start(), None, "No `Index`!"),
631 Some(op) => {
632 let op_id = self.helper.next_id(op);
633 let index = self.visit(index.as_ref());
634 if let Some(_opt) = &ctx.opt {
635 return self.report_error::<ParseError, _>(op.as_ref(), None, "unsupported syntax '[?'");
636 }
637 self.global_call_or_macro(op_id, operators::INDEX.to_string(), vec![target, index])
638 }
639 }
640 } else {
641 self.report_error::<ParseError, _>(&ctx.start(), None, "Incomplete `IndexContext`!")
642 }
643 }
644
645 fn visit_Ident(&mut self, ctx: &IdentContext<'_>) -> Self::Return {
646 match &ctx.id {
647 None => {
648 self.report_error::<ParseError, _>(&ctx.start(), None, "No `Identifier`!");
649 IdedExpr::default()
650 }
651 Some(id) => {
652 let ident = id.clone().text;
653 self.helper.next_expr(id.deref(), Expr::Ident(ident.to_string()))
654 }
655 }
656 }
657
658 fn visit_GlobalCall(&mut self, ctx: &GlobalCallContext<'_>) -> Self::Return {
659 match &ctx.id {
660 None => IdedExpr::default(),
661 Some(id) => {
662 let mut id = id.get_text().to_string();
663 if ctx.leadingDot.is_some() {
664 id = format!(".{id}");
665 }
666 let op_id = self.helper.next_id_for_token(ctx.op.as_deref());
667 let args = ctx
668 .args
669 .iter()
670 .flat_map(|arg| &arg.e)
671 .map(|arg| self.visit(arg.deref()))
672 .collect::<Vec<IdedExpr>>();
673 self.global_call_or_macro(op_id, id, args)
674 }
675 }
676 }
677
678 fn visit_Nested(&mut self, ctx: &NestedContext<'_>) -> Self::Return {
679 match &ctx.e {
680 None => {
681 self.report_error::<ParseError, _>(ctx.start().deref(), None, "No `ExprContextAll`!");
682 IdedExpr::default()
683 }
684 Some(e) => self.visit(e.as_ref()),
685 }
686 }
687
688 fn visit_CreateList(&mut self, ctx: &CreateListContext<'_>) -> Self::Return {
689 let list_id = self.helper.next_id_for_token(ctx.op.as_deref());
690 let elements = match &ctx.elems {
691 None => Vec::default(),
692 Some(elements) => self.list_initializer_list(elements.deref()),
693 };
694 IdedExpr {
695 id: list_id,
696 expr: Expr::List(ListExpr {
697 elements,
698 }),
699 }
700 }
701
702 fn visit_CreateStruct(&mut self, ctx: &CreateStructContext<'_>) -> Self::Return {
703 let struct_id = self.helper.next_id_for_token(ctx.op.as_deref());
704 let entries = match &ctx.entries {
705 Some(entries) => self.map_initializer_list(entries.deref()),
706 None => Vec::default(),
707 };
708 IdedExpr {
709 id: struct_id,
710 expr: Expr::Map(MapExpr {
711 entries,
712 }),
713 }
714 }
715
716 fn visit_CreateMessage(&mut self, ctx: &CreateMessageContext<'_>) -> Self::Return {
717 let mut message_name = String::new();
718 for id in &ctx.ids {
719 if !message_name.is_empty() {
720 message_name.push('.');
721 }
722 message_name.push_str(id.get_text());
723 }
724 if ctx.leadingDot.is_some() {
725 message_name = format!(".{message_name}");
726 }
727 let op_id = match &ctx.op {
728 None => {
729 self.report_error::<ParseError, _>(&ctx.start(), None, "No `CommonToken`!");
730 return IdedExpr::default();
731 }
732 Some(op) => self.helper.next_id(op.as_ref()),
733 };
734 let entries = match &ctx.entries {
735 None => vec![],
736 Some(entries) => self.field_initializer_list(entries),
737 };
738 IdedExpr {
739 id: op_id,
740 expr: Expr::Struct(StructExpr {
741 type_name: message_name,
742 entries,
743 }),
744 }
745 }
746
747 fn visit_ConstantLiteral(&mut self, ctx: &ConstantLiteralContext<'_>) -> Self::Return {
748 <Self as ParseTreeVisitorCompat>::visit(self, ctx.literal().as_deref().expect("Has to have literal!"))
749 }
750
751 fn visit_Int(&mut self, ctx: &IntContext<'_>) -> Self::Return {
752 let string = ctx.get_text();
753 let token = ctx.tok.as_ref().expect("Has to have int!");
754 let val = match if let Some(string) = string.strip_prefix("0x") {
755 i64::from_str_radix(string, 16)
756 } else {
757 string.parse::<i64>()
758 } {
759 Ok(v) => v,
760 Err(e) => return self.report_error(token, Some(e), "invalid int literal"),
761 };
762 self.helper.next_expr(token, Expr::Literal(CelVal::Int(val)))
763 }
764
765 fn visit_Uint(&mut self, ctx: &UintContext<'_>) -> Self::Return {
766 let mut string = ctx.get_text();
767 string.truncate(string.len() - 1);
768 let token = ctx.tok.as_ref().expect("Has to have uint!");
769 let val = match if let Some(string) = string.strip_prefix("0x") {
770 u64::from_str_radix(string, 16)
771 } else {
772 string.parse::<u64>()
773 } {
774 Ok(v) => v,
775 Err(e) => return self.report_error(token, Some(e), "invalid uint literal"),
776 };
777 self.helper.next_expr(token, Expr::Literal(CelVal::UInt(val)))
778 }
779
780 fn visit_Float(&mut self, ctx: &DoubleContext<'_>) -> Self::Return {
781 let string = ctx.get_text();
782 let token = ctx.tok.as_ref().expect("Has to have float!");
783 match string.parse::<f64>() {
784 Ok(d) if d.is_finite() => self.helper.next_expr(token, Expr::Literal(CelVal::Float(d))),
785 Err(e) => self.report_error(token, Some(e), "invalid float literal"),
786 _ => self.report_error(token, None::<ParseError>, "invalid float literal"),
787 }
788 }
789
790 fn visit_String(&mut self, ctx: &StringContext<'_>) -> Self::Return {
791 let token = ctx.tok.as_deref().expect("Has to have string!");
792 match parse::parse_string(&ctx.get_text()) {
793 Ok(string) => self.helper.next_expr(token, Expr::Literal(CelVal::String(string))),
794 Err(e) => self.report_error::<ParseError, _>(token, None, format!("invalid string literal: {e:?}")),
795 }
796 }
797
798 fn visit_Bytes(&mut self, ctx: &BytesContext<'_>) -> Self::Return {
799 let token = ctx.tok.as_deref().expect("Has to have bytes!");
800 let string = ctx.get_text();
801 match parse::parse_bytes(&string[2..string.len() - 1]) {
802 Ok(bytes) => self.helper.next_expr(token, Expr::Literal(CelVal::Bytes(bytes))),
803 Err(e) => {
804 self.report_error::<ParseError, _>(token, None, format!("invalid bytes literal: {e:?}"));
805 IdedExpr::default()
806 }
807 }
808 }
809
810 fn visit_BoolTrue(&mut self, ctx: &BoolTrueContext<'_>) -> Self::Return {
811 self.helper.next_expr(
812 ctx.tok.as_deref().expect("Has to be `true`!"),
813 Expr::Literal(CelVal::Boolean(true)),
814 )
815 }
816
817 fn visit_BoolFalse(&mut self, ctx: &BoolFalseContext<'_>) -> Self::Return {
818 self.helper.next_expr(
819 ctx.tok.as_deref().expect("Has to be `false`!"),
820 Expr::Literal(CelVal::Boolean(false)),
821 )
822 }
823
824 fn visit_Null(&mut self, ctx: &NullContext<'_>) -> Self::Return {
825 self.helper
826 .next_expr(ctx.tok.as_deref().expect("Has to be `null`!"), Expr::Literal(CelVal::Null))
827 }
828}
829
830pub struct ParserHelper {
831 source_info: SourceInfo,
832 next_id: u64,
833}
834
835impl Default for ParserHelper {
836 fn default() -> Self {
837 Self {
838 source_info: SourceInfo::default(),
839 next_id: 1,
840 }
841 }
842}
843
844impl ParserHelper {
845 fn next_id(&mut self, token: &CommonToken) -> u64 {
846 let id = self.next_id;
847 self.source_info.add_offset(id, token.start as u32, token.stop as u32);
848 self.next_id += 1;
849 id
850 }
851
852 fn next_id_for_token(&mut self, token: Option<&CommonToken>) -> u64 {
853 match token {
854 None => 0,
855 Some(token) => self.next_id(token),
856 }
857 }
858
859 fn next_id_for(&mut self, id: u64) -> u64 {
860 let (start, stop) = self.source_info.offset_for(id).expect("invalid offset");
861 let id = self.next_id;
862 self.source_info.add_offset(id, start, stop);
863 self.next_id += 1;
864 id
865 }
866
867 pub fn next_expr(&mut self, token: &CommonToken, expr: Expr) -> IdedExpr {
868 IdedExpr {
869 id: self.next_id(token),
870 expr,
871 }
872 }
873
874 pub fn next_expr_for(&mut self, id: u64, expr: Expr) -> IdedExpr {
875 IdedExpr {
876 id: self.next_id_for(id),
877 expr,
878 }
879 }
880}
881
882struct LogicManager {
883 function: String,
884 terms: Vec<IdedExpr>,
885 ops: Vec<u64>,
886}
887
888impl LogicManager {
889 pub(crate) fn expr(mut self) -> IdedExpr {
890 if self.terms.len() == 1 {
891 self.terms.pop().expect("expected at least one term")
892 } else {
893 self.balanced_tree(0, self.ops.len() - 1)
894 }
895 }
896
897 pub(crate) fn add_term(&mut self, op_id: u64, expr: IdedExpr) {
898 self.terms.push(expr);
899 self.ops.push(op_id);
900 }
901
902 fn balanced_tree(&mut self, lo: usize, hi: usize) -> IdedExpr {
903 let mid = (lo + hi).div_ceil(2);
904
905 let left = if mid == lo {
906 mem::take(&mut self.terms[mid])
907 } else {
908 self.balanced_tree(lo, mid - 1)
909 };
910
911 let right = if mid == hi {
912 mem::take(&mut self.terms[mid + 1])
913 } else {
914 self.balanced_tree(mid + 1, hi)
915 };
916
917 IdedExpr {
918 id: self.ops[mid],
919 expr: Expr::Call(CallExpr {
920 target: None,
921 func_name: self.function.clone(),
922 args: vec![left, right],
923 }),
924 }
925 }
926}
927
928#[cfg(test)]
929mod tests {
930 use std::iter;
931
932 use super::*;
933 use crate::{
934 IdedExpr,
935 common::ast::{ComprehensionExpr, EntryExpr, Expr},
936 };
937
938 struct TestInfo {
939 i: &'static str,
941
942 p: &'static str,
944
945 e: &'static str,
947 }
956 #[test]
957 fn test() {
958 let test_cases = [
959 TestInfo {
960 i: r#""A""#,
961 p: r#""A"^#1:*expr.Constant_StringValue#"#,
962 e: "",
963 },
964 TestInfo {
965 i: r#"true"#,
966 p: r#"true^#1:*expr.Constant_BoolValue#"#,
967 e: "",
968 },
969 TestInfo {
970 i: r#"false"#,
971 p: r#"false^#1:*expr.Constant_BoolValue#"#,
972 e: "",
973 },
974 TestInfo {
975 i: "0",
976 p: "0^#1:*expr.Constant_Int64Value#",
977 e: "",
978 },
979 TestInfo {
980 i: "42",
981 p: "42^#1:*expr.Constant_Int64Value#",
982 e: "",
983 },
984 TestInfo {
985 i: "0xF",
986 p: "15^#1:*expr.Constant_Int64Value#",
987 e: "",
988 },
989 TestInfo {
990 i: "0u",
991 p: "0u^#1:*expr.Constant_Uint64Value#",
992 e: "",
993 },
994 TestInfo {
995 i: "23u",
996 p: "23u^#1:*expr.Constant_Uint64Value#",
997 e: "",
998 },
999 TestInfo {
1000 i: "24u",
1001 p: "24u^#1:*expr.Constant_Uint64Value#",
1002 e: "",
1003 },
1004 TestInfo {
1005 i: "0xFu",
1006 p: "15u^#1:*expr.Constant_Uint64Value#",
1007 e: "",
1008 },
1009 TestInfo {
1010 i: "-1",
1011 p: "-1^#1:*expr.Constant_Int64Value#",
1012 e: "",
1013 },
1014 TestInfo {
1015 i: "4--4",
1016 p: r#"_-_(
1017 4^#1:*expr.Constant_Int64Value#,
1018 -4^#3:*expr.Constant_Int64Value#
1019)^#2:*expr.Expr_CallExpr#"#,
1020 e: "",
1021 },
1022 TestInfo {
1023 i: "4--4.1",
1024 p: r#"_-_(
1025 4^#1:*expr.Constant_Int64Value#,
1026 -4.1^#3:*expr.Constant_FloatValue#
1027)^#2:*expr.Expr_CallExpr#"#,
1028 e: "",
1029 },
1030 TestInfo {
1031 i: r#"b"abc""#,
1032 p: r#"b"abc"^#1:*expr.Constant_BytesValue#"#,
1033 e: "",
1034 },
1035 TestInfo {
1036 i: "23.39",
1037 p: "23.39^#1:*expr.Constant_FloatValue#",
1038 e: "",
1039 },
1040 TestInfo {
1041 i: "!a",
1042 p: "!_(
1043 a^#2:*expr.Expr_IdentExpr#
1044)^#1:*expr.Expr_CallExpr#",
1045 e: "",
1046 },
1047 TestInfo {
1048 i: "null",
1049 p: "null^#1:*expr.Constant_NullValue#",
1050 e: "",
1051 },
1052 TestInfo {
1053 i: "a",
1054 p: "a^#1:*expr.Expr_IdentExpr#",
1055 e: "",
1056 },
1057 TestInfo {
1058 i: "a?b:c",
1059 p: "_?_:_(
1060 a^#1:*expr.Expr_IdentExpr#,
1061 b^#3:*expr.Expr_IdentExpr#,
1062 c^#4:*expr.Expr_IdentExpr#
1063)^#2:*expr.Expr_CallExpr#",
1064 e: "",
1065 },
1066 TestInfo {
1067 i: "a || b",
1068 p: "_||_(
1069 a^#1:*expr.Expr_IdentExpr#,
1070 b^#2:*expr.Expr_IdentExpr#
1071)^#3:*expr.Expr_CallExpr#",
1072 e: "",
1073 },
1074 TestInfo {
1075 i: "a || b || c || d || e || f ",
1076 p: "_||_(
1077 _||_(
1078 _||_(
1079 a^#1:*expr.Expr_IdentExpr#,
1080 b^#2:*expr.Expr_IdentExpr#
1081 )^#3:*expr.Expr_CallExpr#,
1082 c^#4:*expr.Expr_IdentExpr#
1083 )^#5:*expr.Expr_CallExpr#,
1084 _||_(
1085 _||_(
1086 d^#6:*expr.Expr_IdentExpr#,
1087 e^#8:*expr.Expr_IdentExpr#
1088 )^#9:*expr.Expr_CallExpr#,
1089 f^#10:*expr.Expr_IdentExpr#
1090 )^#11:*expr.Expr_CallExpr#
1091)^#7:*expr.Expr_CallExpr#",
1092 e: "",
1093 },
1094 TestInfo {
1095 i: "a && b",
1096 p: "_&&_(
1097 a^#1:*expr.Expr_IdentExpr#,
1098 b^#2:*expr.Expr_IdentExpr#
1099)^#3:*expr.Expr_CallExpr#",
1100 e: "",
1101 },
1102 TestInfo {
1103 i: "a && b && c && d && e && f && g",
1104 p: "_&&_(
1105 _&&_(
1106 _&&_(
1107 a^#1:*expr.Expr_IdentExpr#,
1108 b^#2:*expr.Expr_IdentExpr#
1109 )^#3:*expr.Expr_CallExpr#,
1110 _&&_(
1111 c^#4:*expr.Expr_IdentExpr#,
1112 d^#6:*expr.Expr_IdentExpr#
1113 )^#7:*expr.Expr_CallExpr#
1114 )^#5:*expr.Expr_CallExpr#,
1115 _&&_(
1116 _&&_(
1117 e^#8:*expr.Expr_IdentExpr#,
1118 f^#10:*expr.Expr_IdentExpr#
1119 )^#11:*expr.Expr_CallExpr#,
1120 g^#12:*expr.Expr_IdentExpr#
1121 )^#13:*expr.Expr_CallExpr#
1122)^#9:*expr.Expr_CallExpr#",
1123 e: "",
1124 },
1125 TestInfo {
1126 i: "a && b && c && d || e && f && g && h",
1127 p: "_||_(
1128 _&&_(
1129 _&&_(
1130 a^#1:*expr.Expr_IdentExpr#,
1131 b^#2:*expr.Expr_IdentExpr#
1132 )^#3:*expr.Expr_CallExpr#,
1133 _&&_(
1134 c^#4:*expr.Expr_IdentExpr#,
1135 d^#6:*expr.Expr_IdentExpr#
1136 )^#7:*expr.Expr_CallExpr#
1137 )^#5:*expr.Expr_CallExpr#,
1138 _&&_(
1139 _&&_(
1140 e^#8:*expr.Expr_IdentExpr#,
1141 f^#9:*expr.Expr_IdentExpr#
1142 )^#10:*expr.Expr_CallExpr#,
1143 _&&_(
1144 g^#11:*expr.Expr_IdentExpr#,
1145 h^#13:*expr.Expr_IdentExpr#
1146 )^#14:*expr.Expr_CallExpr#
1147 )^#12:*expr.Expr_CallExpr#
1148)^#15:*expr.Expr_CallExpr#",
1149 e: "",
1150 },
1151 TestInfo {
1152 i: "a + b",
1153 p: "_+_(
1154 a^#1:*expr.Expr_IdentExpr#,
1155 b^#3:*expr.Expr_IdentExpr#
1156)^#2:*expr.Expr_CallExpr#",
1157 e: "",
1158 },
1159 TestInfo {
1160 i: "a - b",
1161 p: "_-_(
1162 a^#1:*expr.Expr_IdentExpr#,
1163 b^#3:*expr.Expr_IdentExpr#
1164)^#2:*expr.Expr_CallExpr#",
1165 e: "",
1166 },
1167 TestInfo {
1168 i: "a * b",
1169 p: "_*_(
1170 a^#1:*expr.Expr_IdentExpr#,
1171 b^#3:*expr.Expr_IdentExpr#
1172)^#2:*expr.Expr_CallExpr#",
1173 e: "",
1174 },
1175 TestInfo {
1176 i: "a / b",
1177 p: "_/_(
1178 a^#1:*expr.Expr_IdentExpr#,
1179 b^#3:*expr.Expr_IdentExpr#
1180)^#2:*expr.Expr_CallExpr#",
1181 e: "",
1182 },
1183 TestInfo {
1184 i: "a % b",
1185 p: "_%_(
1186 a^#1:*expr.Expr_IdentExpr#,
1187 b^#3:*expr.Expr_IdentExpr#
1188)^#2:*expr.Expr_CallExpr#",
1189 e: "",
1190 },
1191 TestInfo {
1192 i: "a in b",
1193p: "",
1198 e: "ERROR: <input>:1:3: Unknown `in` operator!\n| a in b\n| ..^",
1199 },
1200 TestInfo {
1201 i: "a == b",
1202 p: "_==_(
1203 a^#1:*expr.Expr_IdentExpr#,
1204 b^#3:*expr.Expr_IdentExpr#
1205)^#2:*expr.Expr_CallExpr#",
1206 e: "",
1207 },
1208 TestInfo {
1209 i: "a != b",
1210 p: "_!=_(
1211 a^#1:*expr.Expr_IdentExpr#,
1212 b^#3:*expr.Expr_IdentExpr#
1213)^#2:*expr.Expr_CallExpr#",
1214 e: "",
1215 },
1216 TestInfo {
1217 i: "a > b",
1218 p: "_>_(
1219 a^#1:*expr.Expr_IdentExpr#,
1220 b^#3:*expr.Expr_IdentExpr#
1221)^#2:*expr.Expr_CallExpr#",
1222 e: "",
1223 },
1224 TestInfo {
1225 i: "a >= b",
1226 p: "_>=_(
1227 a^#1:*expr.Expr_IdentExpr#,
1228 b^#3:*expr.Expr_IdentExpr#
1229)^#2:*expr.Expr_CallExpr#",
1230 e: "",
1231 },
1232 TestInfo {
1233 i: "a < b",
1234 p: "_<_(
1235 a^#1:*expr.Expr_IdentExpr#,
1236 b^#3:*expr.Expr_IdentExpr#
1237)^#2:*expr.Expr_CallExpr#",
1238 e: "",
1239 },
1240 TestInfo {
1241 i: "a <= b",
1242 p: "_<=_(
1243 a^#1:*expr.Expr_IdentExpr#,
1244 b^#3:*expr.Expr_IdentExpr#
1245)^#2:*expr.Expr_CallExpr#",
1246 e: "",
1247 },
1248 TestInfo {
1249 i: "a.b",
1250 p: "a^#1:*expr.Expr_IdentExpr#.b^#2:*expr.Expr_SelectExpr#",
1251 e: "",
1252 },
1253 TestInfo {
1254 i: "a.b.c",
1255 p: "a^#1:*expr.Expr_IdentExpr#.b^#2:*expr.Expr_SelectExpr#.c^#3:*expr.Expr_SelectExpr#",
1256 e: "",
1257 },
1258 TestInfo {
1259 i: "a[b]",
1260 p: "_[_](
1261 a^#1:*expr.Expr_IdentExpr#,
1262 b^#3:*expr.Expr_IdentExpr#
1263)^#2:*expr.Expr_CallExpr#",
1264 e: "",
1265 },
1266 TestInfo {
1267 i: "(a)",
1268 p: "a^#1:*expr.Expr_IdentExpr#",
1269 e: "",
1270 },
1271 TestInfo {
1272 i: "((a))",
1273 p: "a^#1:*expr.Expr_IdentExpr#",
1274 e: "",
1275 },
1276 TestInfo {
1277 i: "a()",
1278 p: "a()^#1:*expr.Expr_CallExpr#",
1279 e: "",
1280 },
1281 TestInfo {
1282 i: "a(b)",
1283 p: "a(
1284 b^#2:*expr.Expr_IdentExpr#
1285)^#1:*expr.Expr_CallExpr#",
1286 e: "",
1287 },
1288 TestInfo {
1289 i: "a(b, c)",
1290 p: "a(
1291 b^#2:*expr.Expr_IdentExpr#,
1292 c^#3:*expr.Expr_IdentExpr#
1293)^#1:*expr.Expr_CallExpr#",
1294 e: "",
1295 },
1296 TestInfo {
1297 i: "a.b()",
1298 p: "a^#1:*expr.Expr_IdentExpr#.b()^#2:*expr.Expr_CallExpr#",
1299 e: "",
1300 },
1301 TestInfo {
1302 i: "a.b(c)",
1303 p: "a^#1:*expr.Expr_IdentExpr#.b(
1304 c^#3:*expr.Expr_IdentExpr#
1305)^#2:*expr.Expr_CallExpr#",
1306 e: "",
1307 },
1308 TestInfo {
1309 i: "foo{ }",
1310 p: "foo{}^#1:*expr.Expr_StructExpr#",
1311 e: "",
1312 },
1313 TestInfo {
1314 i: "foo{ a:b }",
1315 p: "foo{
1316 a:b^#3:*expr.Expr_IdentExpr#^#2:*expr.Expr_CreateStruct_Entry#
1317}^#1:*expr.Expr_StructExpr#",
1318 e: "",
1319 },
1320 TestInfo {
1321 i: "foo{ a:b, c:d }",
1322 p: "foo{
1323 a:b^#3:*expr.Expr_IdentExpr#^#2:*expr.Expr_CreateStruct_Entry#,
1324 c:d^#5:*expr.Expr_IdentExpr#^#4:*expr.Expr_CreateStruct_Entry#
1325}^#1:*expr.Expr_StructExpr#",
1326 e: "",
1327 },
1328 TestInfo {
1329 i: "{}",
1330 p: "{}^#1:*expr.Expr_StructExpr#",
1331 e: "",
1332 },
1333 TestInfo {
1334 i: "{a: b, c: d}",
1335 p: "{
1336 a^#3:*expr.Expr_IdentExpr#:b^#4:*expr.Expr_IdentExpr#^#2:*expr.Expr_CreateStruct_Entry#,
1337 c^#6:*expr.Expr_IdentExpr#:d^#7:*expr.Expr_IdentExpr#^#5:*expr.Expr_CreateStruct_Entry#
1338}^#1:*expr.Expr_StructExpr#",
1339 e: "",
1340 },
1341 TestInfo {
1342 i: "[]",
1343 p: "[]^#1:*expr.Expr_ListExpr#",
1344 e: "",
1345 },
1346 TestInfo {
1347 i: "[a]",
1348 p: "[
1349 a^#2:*expr.Expr_IdentExpr#
1350]^#1:*expr.Expr_ListExpr#",
1351 e: "",
1352 },
1353 TestInfo {
1354 i: "[a, b, c]",
1355 p: "[
1356 a^#2:*expr.Expr_IdentExpr#,
1357 b^#3:*expr.Expr_IdentExpr#,
1358 c^#4:*expr.Expr_IdentExpr#
1359]^#1:*expr.Expr_ListExpr#",
1360 e: "",
1361 },
1362 TestInfo {
1363 i: "has(m.f)",
1364 p: "m^#2:*expr.Expr_IdentExpr#.f~test-only~^#4:*expr.Expr_SelectExpr#",
1365 e: "",
1366 },
1367 TestInfo {
1368 i: "m.any(v, f)",
1369 p: "__comprehension__(
1370// Variable
1371v,
1372// Target
1373m^#1:*expr.Expr_IdentExpr#,
1374// Accumulator
1375@result,
1376// Init
1377false^#5:*expr.Constant_BoolValue#,
1378// LoopCondition
1379@not_strictly_false(
1380 !_(
1381 @result^#6:*expr.Expr_IdentExpr#
1382 )^#7:*expr.Expr_CallExpr#
1383)^#8:*expr.Expr_CallExpr#,
1384// LoopStep
1385_||_(
1386 @result^#9:*expr.Expr_IdentExpr#,
1387 f^#4:*expr.Expr_IdentExpr#
1388)^#10:*expr.Expr_CallExpr#,
1389// Result
1390@result^#11:*expr.Expr_IdentExpr#)^#12:*expr.Expr_ComprehensionExpr#",
1391 e: "",
1392 },
1393 TestInfo {
1394 i: "m.all(v, f)",
1395 p: "__comprehension__(
1396// Variable
1397v,
1398// Target
1399m^#1:*expr.Expr_IdentExpr#,
1400// Accumulator
1401@result,
1402// Init
1403true^#5:*expr.Constant_BoolValue#,
1404// LoopCondition
1405@not_strictly_false(
1406 @result^#6:*expr.Expr_IdentExpr#
1407)^#7:*expr.Expr_CallExpr#,
1408// LoopStep
1409_&&_(
1410 @result^#8:*expr.Expr_IdentExpr#,
1411 f^#4:*expr.Expr_IdentExpr#
1412)^#9:*expr.Expr_CallExpr#,
1413// Result
1414@result^#10:*expr.Expr_IdentExpr#)^#11:*expr.Expr_ComprehensionExpr#",
1415 e: "",
1416 },
1417TestInfo {
1447 i: "m.map(v, f)",
1448 p: "__comprehension__(
1449// Variable
1450v,
1451// Target
1452m^#1:*expr.Expr_IdentExpr#,
1453// Accumulator
1454@result,
1455// Init
1456[]^#5:*expr.Expr_ListExpr#,
1457// LoopCondition
1458true^#6:*expr.Constant_BoolValue#,
1459// LoopStep
1460_+_(
1461 @result^#7:*expr.Expr_IdentExpr#,
1462 [
1463 f^#4:*expr.Expr_IdentExpr#
1464 ]^#8:*expr.Expr_ListExpr#
1465)^#9:*expr.Expr_CallExpr#,
1466// Result
1467@result^#10:*expr.Expr_IdentExpr#)^#11:*expr.Expr_ComprehensionExpr#",
1468 e: "",
1469 },
1470TestInfo {
1499 i: "m.filter(v, p)",
1500 p: "__comprehension__(
1501// Variable
1502v,
1503// Target
1504m^#1:*expr.Expr_IdentExpr#,
1505// Accumulator
1506@result,
1507// Init
1508[]^#5:*expr.Expr_ListExpr#,
1509// LoopCondition
1510true^#6:*expr.Constant_BoolValue#,
1511// LoopStep
1512_?_:_(
1513 p^#4:*expr.Expr_IdentExpr#,
1514 _+_(
1515 @result^#7:*expr.Expr_IdentExpr#,
1516 [
1517 v^#3:*expr.Expr_IdentExpr#
1518 ]^#8:*expr.Expr_ListExpr#
1519 )^#9:*expr.Expr_CallExpr#,
1520 @result^#10:*expr.Expr_IdentExpr#
1521)^#11:*expr.Expr_CallExpr#,
1522// Result
1523@result^#12:*expr.Expr_IdentExpr#)^#13:*expr.Expr_ComprehensionExpr#",
1524 e: "",
1525 },
1526 TestInfo {
1528 i: "0xFFFFFFFFFFFFFFFFF",
1529 p: "",
1530 e: "ERROR: <input>:1:1: invalid int literal
1531| 0xFFFFFFFFFFFFFFFFF
1532| ^",
1533 },
1534TestInfo {
1542 i: "1.99e90000009",
1543 p: "",
1544 e: "ERROR: <input>:1:1: invalid float literal
1545| 1.99e90000009
1546| ^",
1547 },
1548 TestInfo {
1549 i: "{",
1550 p: "",
1551 e: "ERROR: <input>:1:2: Syntax error: mismatched input '<EOF>' expecting {'[', '{', '}', '(', '.', ',', '-', '!', '?', 'true', 'false', 'null', NUM_FLOAT, NUM_INT, NUM_UINT, STRING, BYTES, IDENTIFIER}
1552| {
1553| .^",
1554 },
1555 TestInfo {
1556 i: "*@a | b",
1557 p: "",
1558 e: "ERROR: <input>:1:1: Syntax error: extraneous input '*' expecting {'[', '{', '(', '.', '-', '!', 'true', 'false', 'null', NUM_FLOAT, NUM_INT, NUM_UINT, STRING, BYTES, IDENTIFIER}
1559| *@a | b
1560| ^
1561ERROR: <input>:1:2: Syntax error: token recognition error at: '@'
1562| *@a | b
1563| .^
1564ERROR: <input>:1:5: Syntax error: token recognition error at: '| '
1565| *@a | b
1566| ....^
1567ERROR: <input>:1:7: Syntax error: extraneous input 'b' expecting <EOF>
1568| *@a | b
1569| ......^",
1570 },
1571 TestInfo {
1572 i: "a | b",
1573 p: "",
1574 e: "ERROR: <input>:1:3: Syntax error: token recognition error at: '| '
1575| a | b
1576| ..^
1577ERROR: <input>:1:5: Syntax error: extraneous input 'b' expecting <EOF>
1578| a | b
1579| ....^",
1580 },
1581 TestInfo {
1582 i: "a.?b && a[?b]",
1583 p: "",
1584 e: "ERROR: <input>:1:2: unsupported syntax '.?'
1585| a.?b && a[?b]
1586| .^
1587ERROR: <input>:1:10: unsupported syntax '[?'
1588| a.?b && a[?b]
1589| .........^",
1590 },
1591 TestInfo {
1592 i: "a.?b && a[?b]",
1593 p: "",
1594 e: "ERROR: <input>:1:2: unsupported syntax '.?'
1595| a.?b && a[?b]
1596| .^
1597ERROR: <input>:1:10: unsupported syntax '[?'
1598| a.?b && a[?b]
1599| .........^",
1600 },
1601 TestInfo {
1602 i: r#"Msg{?field: value} && {?"key": value}"#,
1603 p: "",
1604 e: r#"ERROR: <input>:1:5: unsupported syntax '?'
1605| Msg{?field: value} && {?"key": value}
1606| ....^
1607ERROR: <input>:1:24: unsupported syntax '?'
1608| Msg{?field: value} && {?"key": value}
1609| .......................^"#,
1610 },
1611 TestInfo {
1612 i: "has(m)",
1613 p: "",
1614 e: "ERROR: <input>:1:5: invalid argument to has() macro
1615| has(m)
1616| ....^"
1617 },
1618 TestInfo {
1619 i: "1.all(2, 3)",
1620 p: "",
1621 e: "ERROR: <input>:1:7: argument must be a simple name
1622| 1.all(2, 3)
1623| ......^",
1624 },
1625 ];
1626
1627 for test_case in test_cases {
1628 let parser = Parser::new();
1629 let result = parser.parse(test_case.i);
1630 if !test_case.p.is_empty() {
1631 assert_eq!(
1632 to_go_like_string(result.as_ref().expect("Expected an AST")),
1633 test_case.p,
1634 "Expr `{}` failed",
1635 test_case.i
1636 );
1637 }
1638
1639 if !test_case.e.is_empty() {
1640 assert_eq!(
1641 format!("{}", result.as_ref().expect_err("Expected an Err!")),
1642 test_case.e,
1643 "Error on `{}` failed",
1644 test_case.i
1645 )
1646 }
1647 }
1648 }
1649
1650 fn to_go_like_string(expr: &IdedExpr) -> String {
1651 let mut writer = DebugWriter::default();
1652 writer.buffer(expr);
1653 writer.done()
1654 }
1655
1656 struct DebugWriter {
1657 buffer: String,
1658 indents: usize,
1659 line_start: bool,
1660 }
1661
1662 impl Default for DebugWriter {
1663 fn default() -> Self {
1664 Self {
1665 buffer: String::default(),
1666 indents: 0,
1667 line_start: true,
1668 }
1669 }
1670 }
1671
1672 impl DebugWriter {
1673 fn buffer(&mut self, expr: &IdedExpr) -> &Self {
1674 let e = match &expr.expr {
1675 Expr::Unspecified => "UNSPECIFIED!",
1676 Expr::Call(call) => {
1677 if let Some(target) = &call.target {
1678 self.buffer(target);
1679 self.push(".");
1680 }
1681 self.push(call.func_name.as_str());
1682 self.push("(");
1683 if !call.args.is_empty() {
1684 self.inc_indent();
1685 self.newline();
1686 for i in 0..call.args.len() {
1687 if i > 0 {
1688 self.push(",");
1689 self.newline();
1690 }
1691 self.buffer(&call.args[i]);
1692 }
1693 self.dec_indent();
1694 self.newline();
1695 }
1696 self.push(")");
1697 &format!("^#{}:{}#", expr.id, "*expr.Expr_CallExpr")
1698 }
1699 Expr::Comprehension(comprehension) => {
1700 self.push("__comprehension__(\n");
1701 self.push_comprehension(comprehension);
1702 &format!(")^#{}:{}#", expr.id, "*expr.Expr_ComprehensionExpr")
1703 }
1704 Expr::Ident(id) => &format!("{}^#{}:{}#", id, expr.id, "*expr.Expr_IdentExpr"),
1705 Expr::List(list) => {
1706 self.push("[");
1707 if !list.elements.is_empty() {
1708 self.inc_indent();
1709 self.newline();
1710 for (i, element) in list.elements.iter().enumerate() {
1711 if i > 0 {
1712 self.push(",");
1713 self.newline();
1714 }
1715 self.buffer(element);
1716 }
1717 self.dec_indent();
1718 self.newline();
1719 }
1720 self.push("]");
1721 &format!("^#{}:{}#", expr.id, "*expr.Expr_ListExpr")
1722 }
1723 Expr::Literal(val) => match val {
1724 CelVal::String(s) => &format!("\"{s}\"^#{}:{}#", expr.id, "*expr.Constant_StringValue"),
1725 CelVal::Boolean(b) => &format!("{b}^#{}:{}#", expr.id, "*expr.Constant_BoolValue"),
1726 CelVal::Int(i) => &format!("{i}^#{}:{}#", expr.id, "*expr.Constant_Int64Value"),
1727 CelVal::UInt(u) => &format!("{u}u^#{}:{}#", expr.id, "*expr.Constant_Uint64Value"),
1728 CelVal::Float(f) => &format!("{f}^#{}:{}#", expr.id, "*expr.Constant_FloatValue"),
1729 CelVal::Bytes(bytes) => &format!(
1730 "b\"{}\"^#{}:{}#",
1731 String::from_utf8_lossy(bytes),
1732 expr.id,
1733 "*expr.Constant_BytesValue"
1734 ),
1735 CelVal::Null => &format!("null^#{}:{}#", expr.id, "*expr.Constant_NullValue"),
1736 t => &format!("WUT? {t:?}"),
1737 },
1738 Expr::Map(map) => {
1739 self.push("{");
1740 self.inc_indent();
1741 if !map.entries.is_empty() {
1742 self.newline();
1743 }
1744 for (i, entry) in map.entries.iter().enumerate() {
1745 match &entry.expr {
1746 EntryExpr::StructField(_) => panic!("WAT?!"),
1747 EntryExpr::MapEntry(e) => {
1748 self.buffer(&e.key);
1749 self.push(":");
1750 self.buffer(&e.value);
1751 self.push(&format!("^#{}:{}#", entry.id, "*expr.Expr_CreateStruct_Entry"));
1752 }
1753 }
1754 if i < map.entries.len() - 1 {
1755 self.push(",");
1756 }
1757 self.newline();
1758 }
1759 self.dec_indent();
1760 self.push("}");
1761 &format!("^#{}:{}#", expr.id, "*expr.Expr_StructExpr")
1762 }
1763 Expr::Select(select) => {
1764 self.buffer(select.operand.deref());
1765 let suffix = if select.test { "~test-only~" } else { "" };
1766 &format!(".{}{}^#{}:{}#", select.field, suffix, expr.id, "*expr.Expr_SelectExpr")
1767 }
1768 Expr::Struct(s) => {
1769 self.push(&s.type_name);
1770 self.push("{");
1771 self.inc_indent();
1772 if !s.entries.is_empty() {
1773 self.newline();
1774 }
1775 for (i, entry) in s.entries.iter().enumerate() {
1776 match &entry.expr {
1777 EntryExpr::StructField(field) => {
1778 self.push(&field.field);
1779 self.push(":");
1780 self.buffer(&field.value);
1781 self.push(&format!("^#{}:{}#", entry.id, "*expr.Expr_CreateStruct_Entry"));
1782 }
1783 EntryExpr::MapEntry(_) => panic!("WAT?!"),
1784 }
1785 if i < s.entries.len() - 1 {
1786 self.push(",");
1787 }
1788 self.newline();
1789 }
1790 self.dec_indent();
1791 self.push("}");
1792 &format!("^#{}:{}#", expr.id, "*expr.Expr_StructExpr")
1793 }
1794 };
1795 self.push(e);
1796 self
1797 }
1798
1799 fn push(&mut self, literal: &str) {
1800 self.indent();
1801 self.buffer.push_str(literal);
1802 }
1803
1804 fn indent(&mut self) {
1805 if self.line_start {
1806 self.line_start = false;
1807 self.buffer
1808 .push_str(iter::repeat_n(" ", self.indents).collect::<String>().as_str())
1809 }
1810 }
1811
1812 fn newline(&mut self) {
1813 self.buffer.push('\n');
1814 self.line_start = true;
1815 }
1816
1817 fn inc_indent(&mut self) {
1818 self.indents += 1;
1819 }
1820
1821 fn dec_indent(&mut self) {
1822 self.indents -= 1;
1823 }
1824
1825 fn done(self) -> String {
1826 self.buffer
1827 }
1828
1829 fn push_comprehension(&mut self, comprehension: &ComprehensionExpr) {
1830 self.push("// Variable\n");
1831 self.push(comprehension.iter_var.as_str());
1832 self.push(",\n");
1833 self.push("// Target\n");
1834 self.buffer(&comprehension.iter_range);
1835 self.push(",\n");
1836 self.push("// Accumulator\n");
1837 self.push(comprehension.accu_var.as_str());
1838 self.push(",\n");
1839 self.push("// Init\n");
1840 self.buffer(&comprehension.accu_init);
1841 self.push(",\n");
1842 self.push("// LoopCondition\n");
1843 self.buffer(&comprehension.loop_cond);
1844 self.push(",\n");
1845 self.push("// LoopStep\n");
1846 self.buffer(&comprehension.loop_step);
1847 self.push(",\n");
1848 self.push("// Result\n");
1849 self.buffer(&comprehension.result);
1850 }
1851 }
1852}