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