1use std::fmt::Display;
21
22use crate::common::TextLocation;
23use crate::mel::ast::{
24 BinaryInfixOperator, ComparisonOperator, LogicOperator, MathOperator, MemberAccessOperator,
25 StringConcatOperator, TernaryOperator,
26};
27use crate::mel::{
28 analysis::{self, Analyzed},
29 ast::{
30 self, Argument, ArgumentList, AstVisitor, AstVisitorDriver, AstVisitorResult, BinaryExpr,
31 FunctionCall, Identifier,
32 },
33};
34
35impl Display for MemberAccessOperator {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 write!(f, " . ")
38 }
39}
40
41impl Display for BinaryInfixOperator {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 match self {
44 BinaryInfixOperator::Logic(logic_operator) => write!(f, "{logic_operator}"),
45 BinaryInfixOperator::Comparison(comparison_operator) => {
46 write!(f, "{comparison_operator}")
47 }
48 BinaryInfixOperator::Math(math_operator) => write!(f, "{math_operator}"),
49 BinaryInfixOperator::Concat(string_concat_operator) => {
50 write!(f, "{string_concat_operator}")
51 }
52 BinaryInfixOperator::MemberAccess(member_access_operator) => {
53 write!(f, "{member_access_operator}")
54 }
55 }
56 }
57}
58
59impl Display for ComparisonOperator {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 match self {
62 ComparisonOperator::Eq => write!(f, "=="),
63 ComparisonOperator::Ne => write!(f, "!="),
64 ComparisonOperator::Lt => write!(f, "<"),
65 ComparisonOperator::Lte => write!(f, "<="),
66 ComparisonOperator::Gt => write!(f, ">"),
67 ComparisonOperator::Gte => write!(f, ">="),
68 ComparisonOperator::Re => write!(f, "~="),
69 ComparisonOperator::IP => write!(f, "ipmatch"),
70 }
71 }
72}
73
74impl Display for LogicOperator {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 match self {
77 LogicOperator::And => write!(f, "and"),
78 LogicOperator::Or => write!(f, "or"),
79 }
80 }
81}
82
83impl Display for StringConcatOperator {
84 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85 write!(f, "concat")
86 }
87}
88
89impl Display for MathOperator {
90 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91 match self {
92 MathOperator::Plus => write!(f, "plus"),
93 MathOperator::Minus => write!(f, "minus"),
94 MathOperator::Multiply => write!(f, "multiply"),
95 MathOperator::Divide => write!(f, "divide"),
96 MathOperator::Modulo => write!(f, "modulo"),
97 }
98 }
99}
100
101impl Display for TernaryOperator {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 match self {
104 TernaryOperator::Question => write!(f, "?"),
105 TernaryOperator::Colon => write!(f, ":"),
106 }
107 }
108}
109
110impl Display for ast::Literal {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 match self {
113 ast::Literal::Boolean(bl) => write!(f, "{bl}"),
114 ast::Literal::Number(nl) => write!(f, "{nl}"),
115 ast::Literal::String(sl) => write!(f, "{sl}"),
116 ast::Literal::Regex(rl) => write!(f, "{rl}"),
117 ast::Literal::IPAddress(ip) => write!(f, "{ip}"),
118 }
119 }
120}
121
122impl Display for ast::BooleanLiteral {
123 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
124 match self {
125 ast::BooleanLiteral::True => write!(f, "true"),
126 ast::BooleanLiteral::False => write!(f, "false"),
127 }
128 }
129}
130
131impl Display for ast::NumberLiteral {
132 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133 write!(f, "{}", self.literal)
134 }
135}
136
137impl Display for ast::StringLiteral {
138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139 write!(f, "{}", self.literal)
140 }
141}
142
143impl Display for ast::RegexLiteral {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 write!(f, "{}", self.literal)
146 }
147}
148
149impl Display for ast::IPAddressLiteral {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 write!(f, "{}", self.literal)
152 }
153}
154
155impl Display for analysis::CompiledConstant {
156 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157 match self {
158 analysis::CompiledConstant::Integer(i) => write!(f, "{i}"),
159 analysis::CompiledConstant::String(s) => write!(f, "{s}"),
160 analysis::CompiledConstant::Boolean(b) => write!(f, "{b}"),
161 analysis::CompiledConstant::IPAddress(ip) => write!(f, "{ip}"),
162 }
163 }
164}
165
166#[derive(Debug, Clone, Default)]
167pub struct AstTextSerializerError {}
168
169pub struct AstTextSerializer {}
170
171pub struct AstTextSerializerContext {
172 pub serialized: String,
173 pub indent: usize,
174}
175
176impl AstTextSerializerContext {
177 fn indent(&self) -> Self {
178 AstTextSerializerContext {
179 serialized: self.serialized.clone(),
180 indent: self.indent + 1,
181 }
182 }
183 fn unindent(&self) -> Self {
184 AstTextSerializerContext {
185 serialized: self.serialized.clone(),
186 indent: self.indent - 1,
187 }
188 }
189 fn append(&self, addition: String) -> Self {
190 AstTextSerializerContext {
191 serialized: self.serialized.clone() + &addition,
192 indent: self.indent,
193 }
194 }
195}
196
197impl AstVisitor<AstTextSerializerContext, (), AstTextSerializerError> for AstTextSerializer {
198 fn visit_function_call(
199 &self,
200 ast: &FunctionCall<()>,
201 context: AstTextSerializerContext,
202 driver: &AstVisitorDriver,
203 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
204 let mut context =
205 context.append(("\t".repeat(context.indent) + "Function Call:\n").to_string());
206
207 context = context.indent();
208 context = context.append("\t".repeat(context.indent) + "Callee:\n");
209
210 context = driver.visit(&ast.callee, self, context.indent())?;
211 context = context.append("\n".into());
212 context = context.unindent();
213 context = context.unindent();
214
215 context = self.visit_argument_list(&ast.arguments, context.indent(), driver)?;
216 Ok(context.unindent())
217 }
218
219 fn visit_identifier(
220 &self,
221 ast: &Identifier<()>,
222 context: AstTextSerializerContext,
223 _driver: &AstVisitorDriver,
224 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
225 let output = "\t".repeat(context.indent) + "Identifier: " + &ast.identifier;
226 Ok(context.append(output))
227 }
228
229 fn visit_argument_list(
230 &self,
231 ast: &ArgumentList<()>,
232 context: AstTextSerializerContext,
233 driver: &AstVisitorDriver,
234 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
235 let mut context = context.append("\t".repeat(context.indent) + "Arguments:\n");
236 context = context.indent();
237 let mut first = true;
238 for arg in &ast.arguments {
239 if !first {
240 context = context.append("\n".into())
241 }
242 first = false;
243 context = self.visit_argument(arg, context, driver)?;
244 }
245 Ok(context.unindent())
246 }
247
248 fn visit_argument(
249 &self,
250 ast: &Argument<()>,
251 context: AstTextSerializerContext,
252 driver: &AstVisitorDriver,
253 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
254 driver.visit(&ast.expr, self, context)
255 }
256
257 fn visit_binary_expr(
258 &self,
259 ast: &BinaryExpr<()>,
260 context: AstTextSerializerContext,
261 driver: &AstVisitorDriver,
262 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
263 let mut context = context.append("\t".repeat(context.indent) + "Binary Expression:\n");
264
265 context = context.indent();
266
267 context = context.append("\t".repeat(context.indent) + "Left:\n");
268 context = driver.visit(&ast.left, self, context.indent())?;
269 context = context.unindent();
270
271 context = context.append("\n".into());
272
273 context = context.append("\t".repeat(context.indent) + &format!("Operation: {}\n", ast.op));
274
275 context = context.append("\t".repeat(context.indent) + "Right:\n");
276 context = driver.visit(&ast.right, self, context.indent())?;
277 context = context.unindent();
278
279 context = context.unindent();
280 Ok(context)
281 }
282
283 fn visit_literal(
284 &self,
285 ast: (&ast::Literal, &TextLocation, &()),
286 context: AstTextSerializerContext,
287 _driver: &AstVisitorDriver,
288 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
289 Ok(context.append("\t".repeat(context.indent) + "Literal: " + &ast.0.to_string()))
290 }
291
292 fn visit_ternary_expr(
293 &self,
294 ast: &ast::TernaryExpr<()>,
295 context: AstTextSerializerContext,
296 driver: &AstVisitorDriver,
297 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
298 let mut context = context.append("\t".repeat(context.indent) + "Ternary Expression:\n");
299
300 context = context.indent();
301
302 context = context.append("\t".repeat(context.indent) + "Condition:\n");
303 context = driver.visit(&ast.condition, self, context.indent())?;
304 context = context.unindent();
305
306 context = context.append("\n".into());
307
308 context = context.append("\t".repeat(context.indent) + "Yes:\n");
309 context = driver.visit(&ast.yes, self, context.indent())?;
310 context = context.unindent();
311
312 context = context.append("\n".into());
313
314 context = context.append("\t".repeat(context.indent) + "No:\n");
315 context = driver.visit(&ast.no, self, context.indent())?;
316 context = context.unindent();
317
318 context = context.unindent();
319 Ok(context)
320 }
321
322 fn visit_member_access_expr(
323 &self,
324 ast: &ast::MemberAccessExpression<()>,
325 context: AstTextSerializerContext,
326 driver: &AstVisitorDriver,
327 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
328 let mut context =
329 context.append("\t".repeat(context.indent) + "Member Access Expression:\n");
330
331 context = context.indent();
332 context = context.append("\t".repeat(context.indent) + "Base:\n");
333 context = driver.visit(&ast.base, self, context.indent())?;
334 context = context.append("\n".into());
335 context = context.unindent();
336
337 context = context.append("\t".repeat(context.indent) + "Member:\n");
338 context = self.visit_identifier(&ast.member, context.indent(), driver)?;
339 context = context.unindent();
340
341 context = context.unindent();
342 Ok(context)
343 }
344}
345
346#[cfg(test)]
347mod tests {
348 use crate::mel::{
349 compiler::compile,
350 serializer::{AstTextSerializer, AstTextSerializerContext, AstVisitorDriver},
351 };
352
353 #[test]
354 fn serialize_function_call() {
355 let code = "testing(one(hello),b)";
356 let expected = "Function Call:
357\tCallee:
358\t\tIdentifier: testing
359\tArguments:
360\t\tFunction Call:
361\t\t\tCallee:
362\t\t\t\tIdentifier: one
363\t\t\tArguments:
364\t\t\t\tIdentifier: hello
365\t\tIdentifier: b";
366
367 let compile_result = compile(code);
368 let ast = compile_result.expect("Compilation error");
369
370 let driver = AstVisitorDriver {};
371 let visitor = AstTextSerializer {};
372 let context = AstTextSerializerContext {
373 serialized: "".to_string(),
374 indent: 0,
375 };
376 let result = driver
377 .visit(&ast, &visitor, context)
378 .expect("Could not serialize");
379 pretty_assertions::assert_eq!(result.serialized, expected);
380 }
381
382 #[test]
383 fn serialize_binary_expr() {
384 let code = "a and b";
385 let expected = "Binary Expression:
386\tLeft:
387\t\tIdentifier: a
388\tOperation: and
389\tRight:
390\t\tIdentifier: b";
391
392 let compile_result = compile(code);
393 let ast = compile_result.expect("Compilation error");
394
395 let driver = AstVisitorDriver {};
396 let visitor = AstTextSerializer {};
397 let context = AstTextSerializerContext {
398 serialized: "".to_string(),
399 indent: 0,
400 };
401 let result = driver
402 .visit(&ast, &visitor, context)
403 .expect("Could not serialize");
404 pretty_assertions::assert_eq!(result.serialized, expected);
405 }
406
407 #[test]
408 fn serialize_binary_regex_expr() {
409 let code = "a ~= \"/[0-9]/\"";
410 let expected = "Binary Expression:
411\tLeft:
412\t\tIdentifier: a
413\tOperation: ~=
414\tRight:
415\t\tLiteral: /[0-9]/";
416
417 let compile_result = compile(code);
418 let ast = compile_result.expect("Compilation error");
419
420 let driver = AstVisitorDriver {};
421 let visitor = AstTextSerializer {};
422 let context = AstTextSerializerContext {
423 serialized: "".to_string(),
424 indent: 0,
425 };
426 let result = driver
427 .visit(&ast, &visitor, context)
428 .expect("Could not serialize");
429 pretty_assertions::assert_eq!(result.serialized, expected);
430 }
431
432 #[test]
433 fn serialize_binary_math_expr() {
434 let code = "a + b";
435 let expected = "Binary Expression:
436\tLeft:
437\t\tIdentifier: a
438\tOperation: plus
439\tRight:
440\t\tIdentifier: b";
441
442 let compile_result = compile(code);
443 let ast = compile_result.expect("Compilation error");
444
445 let driver = AstVisitorDriver {};
446 let visitor = AstTextSerializer {};
447 let context = AstTextSerializerContext {
448 serialized: "".to_string(),
449 indent: 0,
450 };
451 let result = driver
452 .visit(&ast, &visitor, context)
453 .expect("Could not serialize");
454 pretty_assertions::assert_eq!(result.serialized, expected);
455 }
456
457 #[test]
458 fn serialize_binary_math_expr_associative() {
459 let code = "a + b - c";
460 let expected = "Binary Expression:
461\tLeft:
462\t\tBinary Expression:
463\t\t\tLeft:
464\t\t\t\tIdentifier: a
465\t\t\tOperation: plus
466\t\t\tRight:
467\t\t\t\tIdentifier: b
468\tOperation: minus
469\tRight:
470\t\tIdentifier: c";
471
472 let compile_result = compile(code);
473 let ast = compile_result.expect("Compilation error");
474 let driver = AstVisitorDriver {};
475 let visitor = AstTextSerializer {};
476 let context = AstTextSerializerContext {
477 serialized: "".to_string(),
478 indent: 0,
479 };
480 let result = driver
481 .visit(&ast, &visitor, context)
482 .expect("Could not serialize");
483 pretty_assertions::assert_eq!(result.serialized, expected);
484 }
485
486 #[test]
487 fn serialize_binary_math_expr_grouped() {
488 let code = "(a + b) - c";
489 let expected = "Binary Expression:
490\tLeft:
491\t\tBinary Expression:
492\t\t\tLeft:
493\t\t\t\tIdentifier: a
494\t\t\tOperation: plus
495\t\t\tRight:
496\t\t\t\tIdentifier: b
497\tOperation: minus
498\tRight:
499\t\tIdentifier: c";
500
501 let compile_result = compile(code);
502 let ast = compile_result.expect("Compilation error");
503
504 let driver = AstVisitorDriver {};
505 let visitor = AstTextSerializer {};
506 let context = AstTextSerializerContext {
507 serialized: "".to_string(),
508 indent: 0,
509 };
510 let result = driver
511 .visit(&ast, &visitor, context)
512 .expect("Could not serialize");
513 pretty_assertions::assert_eq!(result.serialized, expected);
514 }
515
516 #[test]
517 fn serialize_binary_math_expr_grouped_right() {
518 let code = "a + (b - c)";
519 let expected = "Binary Expression:
520\tLeft:
521\t\tIdentifier: a
522\tOperation: plus
523\tRight:
524\t\tBinary Expression:
525\t\t\tLeft:
526\t\t\t\tIdentifier: b
527\t\t\tOperation: minus
528\t\t\tRight:
529\t\t\t\tIdentifier: c";
530
531 let compile_result = compile(code);
532 let ast = compile_result.expect("Compilation error");
533
534 let driver = AstVisitorDriver {};
535 let visitor = AstTextSerializer {};
536 let context = AstTextSerializerContext {
537 serialized: "".to_string(),
538 indent: 0,
539 };
540 let result = driver
541 .visit(&ast, &visitor, context)
542 .expect("Could not serialize");
543 pretty_assertions::assert_eq!(result.serialized, expected);
544 }
545
546 #[test]
547 fn serialize_binary_math_expr_grouped_right2() {
548 let code = "a * (b % c)";
549 let expected = "Binary Expression:
550\tLeft:
551\t\tIdentifier: a
552\tOperation: multiply
553\tRight:
554\t\tBinary Expression:
555\t\t\tLeft:
556\t\t\t\tIdentifier: b
557\t\t\tOperation: modulo
558\t\t\tRight:
559\t\t\t\tIdentifier: c";
560
561 let compile_result = compile(code);
562 let ast = compile_result.expect("Compilation error");
563
564 let driver = AstVisitorDriver {};
565 let visitor = AstTextSerializer {};
566 let context = AstTextSerializerContext {
567 serialized: "".to_string(),
568 indent: 0,
569 };
570 let result = driver
571 .visit(&ast, &visitor, context)
572 .expect("Could not serialize");
573 pretty_assertions::assert_eq!(result.serialized, expected);
574 }
575
576 #[test]
577 fn serialize_boolean_expression() {
578 let code = "true or false";
579 let expected = "Binary Expression:
580\tLeft:
581\t\tLiteral: true
582\tOperation: or
583\tRight:
584\t\tLiteral: false";
585
586 let compile_result = compile(code);
587 let ast = compile_result.expect("Compilation error");
588
589 let driver = AstVisitorDriver {};
590 let visitor = AstTextSerializer {};
591 let context = AstTextSerializerContext {
592 serialized: "".to_string(),
593 indent: 0,
594 };
595 let result = driver
596 .visit(&ast, &visitor, context)
597 .expect("Could not serialize");
598 pretty_assertions::assert_eq!(result.serialized, expected);
599 }
600
601 #[test]
602 fn serialize_boolean_expression2() {
603 let code = "true < false";
604 let expected = "Binary Expression:
605\tLeft:
606\t\tLiteral: true
607\tOperation: <
608\tRight:
609\t\tLiteral: false";
610
611 let compile_result = compile(code);
612 let ast = compile_result.expect("Compilation error");
613
614 let driver = AstVisitorDriver {};
615 let visitor = AstTextSerializer {};
616 let context = AstTextSerializerContext {
617 serialized: "".to_string(),
618 indent: 0,
619 };
620 let result = driver
621 .visit(&ast, &visitor, context)
622 .expect("Could not serialize");
623 pretty_assertions::assert_eq!(result.serialized, expected);
624 }
625
626 #[test]
627 fn serialize_boolean_expression3() {
628 let code = "(1 < 2) != true";
629 let expected = "Binary Expression:
630\tLeft:
631\t\tBinary Expression:
632\t\t\tLeft:
633\t\t\t\tLiteral: 1
634\t\t\tOperation: <
635\t\t\tRight:
636\t\t\t\tLiteral: 2
637\tOperation: !=
638\tRight:
639\t\tLiteral: true";
640 let compile_result = compile(code);
641 let ast = compile_result.expect("Compilation error");
642
643 let driver = AstVisitorDriver {};
644 let visitor = AstTextSerializer {};
645 let context = AstTextSerializerContext {
646 serialized: "".to_string(),
647 indent: 0,
648 };
649 let result = driver
650 .visit(&ast, &visitor, context)
651 .expect("Could not serialize");
652 pretty_assertions::assert_eq!(result.serialized, expected);
653 }
654
655 #[test]
656 fn serialize_number_expression() {
657 let code = "5 + 4";
658 let expected = "Binary Expression:
659\tLeft:
660\t\tLiteral: 5
661\tOperation: plus
662\tRight:
663\t\tLiteral: 4";
664
665 let compile_result = compile(code);
666 let ast = compile_result.expect("Compilation error");
667
668 let driver = AstVisitorDriver {};
669 let visitor = AstTextSerializer {};
670 let context = AstTextSerializerContext {
671 serialized: "".to_string(),
672 indent: 0,
673 };
674 let result = driver
675 .visit(&ast, &visitor, context)
676 .expect("Could not serialize");
677 pretty_assertions::assert_eq!(result.serialized, expected);
678 }
679
680 #[test]
681 fn serialize_string_expression() {
682 let code = "\"testing\" . \"one\"";
683 let expected = "Binary Expression:
684\tLeft:
685\t\tLiteral: testing
686\tOperation: concat
687\tRight:
688\t\tLiteral: one";
689
690 let compile_result = compile(code);
691 let ast = compile_result.expect("Compilation error");
692
693 let driver = AstVisitorDriver {};
694 let visitor = AstTextSerializer {};
695 let context = AstTextSerializerContext {
696 serialized: "".to_string(),
697 indent: 0,
698 };
699 let result = driver
700 .visit(&ast, &visitor, context)
701 .expect("Could not serialize");
702 pretty_assertions::assert_eq!(result.serialized, expected);
703 }
704
705 #[test]
706 fn serialize_ternary_expr() {
707 let code = "true ? 1 : 5";
708 let expected = "Ternary Expression:
709\tCondition:
710\t\tLiteral: true
711\tYes:
712\t\tLiteral: 1
713\tNo:
714\t\tLiteral: 5";
715
716 let compile_result = compile(code);
717 let ast = compile_result.expect("Compilation error");
718
719 let driver = AstVisitorDriver {};
720 let visitor = AstTextSerializer {};
721 let context = AstTextSerializerContext {
722 serialized: "".to_string(),
723 indent: 0,
724 };
725 let result = driver
726 .visit(&ast, &visitor, context)
727 .expect("Could not serialize");
728 pretty_assertions::assert_eq!(result.serialized, expected);
729 }
730
731 #[test]
732 fn serialize_ternary_expr_proper_associativity() {
733 let code = "true ? a : false ? \"b\" : 10";
734 let expected = "Ternary Expression:
735\tCondition:
736\t\tLiteral: true
737\tYes:
738\t\tIdentifier: a
739\tNo:
740\t\tTernary Expression:
741\t\t\tCondition:
742\t\t\t\tLiteral: false
743\t\t\tYes:
744\t\t\t\tLiteral: b
745\t\t\tNo:
746\t\t\t\tLiteral: 10";
747
748 let compile_result = compile(code);
749 let ast = compile_result.expect("Compilation error");
750
751 let driver = AstVisitorDriver {};
752 let visitor = AstTextSerializer {};
753 let context = AstTextSerializerContext {
754 serialized: "".to_string(),
755 indent: 0,
756 };
757 let result = driver
758 .visit(&ast, &visitor, context)
759 .expect("Could not serialize");
760 pretty_assertions::assert_eq!(result.serialized, expected);
761 }
762
763 #[test]
764 fn serialize_member_access_expression() {
765 let code = "a^b^c";
766 let expected = "Member Access Expression:
767\tBase:
768\t\tMember Access Expression:
769\t\t\tBase:
770\t\t\t\tIdentifier: a
771\t\t\tMember:
772\t\t\t\tIdentifier: b
773\tMember:
774\t\tIdentifier: c";
775
776 let compile_result = compile(code);
777 let ast = compile_result.expect("Compilation error");
778
779 let driver = AstVisitorDriver {};
780 let visitor = AstTextSerializer {};
781 let context = AstTextSerializerContext {
782 serialized: "".to_string(),
783 indent: 0,
784 };
785 let result = driver
786 .visit(&ast, &visitor, context)
787 .expect("Could not serialize");
788 pretty_assertions::assert_eq!(result.serialized, expected);
789 }
790}
791
792impl AstVisitor<AstTextSerializerContext, Analyzed, AstTextSerializerError> for AstTextSerializer {
793 fn visit_function_call(
794 &self,
795 ast: &FunctionCall<Analyzed>,
796 context: AstTextSerializerContext,
797 driver: &AstVisitorDriver,
798 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
799 let mut context =
800 context.append(("\t".repeat(context.indent) + "Function Call:\n").to_string());
801
802 context = context.indent();
803 context = context.append("\t".repeat(context.indent) + "Callee:\n");
804
805 context = driver.visit(&ast.callee, self, context.indent())?;
806 context = context.append("\n".into());
807 context = context.unindent();
808 context = context.unindent();
809
810 context = self.visit_argument_list(&ast.arguments, context.indent(), driver)?;
811
812 context = context.append("\n".into());
813 context = context.append("\t".repeat(context.indent) + &format!("Type: {}", ast.aug.tipe));
814
815 Ok(context.unindent())
816 }
817
818 fn visit_identifier(
819 &self,
820 ast: &Identifier<Analyzed>,
821 context: AstTextSerializerContext,
822 _driver: &AstVisitorDriver,
823 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
824 let output = "\t".repeat(context.indent) + "Identifier: " + &ast.identifier;
825 Ok(context.append(output))
826 }
827
828 fn visit_argument_list(
829 &self,
830 ast: &ArgumentList<Analyzed>,
831 context: AstTextSerializerContext,
832 driver: &AstVisitorDriver,
833 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
834 let mut context = context.append("\t".repeat(context.indent) + "Arguments:\n");
835 context = context.indent();
836 let mut first = true;
837 for arg in &ast.arguments {
838 if !first {
839 context = context.append("\n".into())
840 }
841 first = false;
842 context = self.visit_argument(arg, context, driver)?;
843 }
844 Ok(context.unindent())
845 }
846
847 fn visit_argument(
848 &self,
849 ast: &Argument<Analyzed>,
850 context: AstTextSerializerContext,
851 driver: &AstVisitorDriver,
852 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
853 driver.visit(&ast.expr, self, context)
854 }
855
856 fn visit_binary_expr(
857 &self,
858 ast: &BinaryExpr<Analyzed>,
859 context: AstTextSerializerContext,
860 driver: &AstVisitorDriver,
861 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
862 let mut context = context.append("\t".repeat(context.indent) + "Binary Expression:\n");
863
864 context = context.indent();
865
866 context = context.append("\t".repeat(context.indent) + "Left:\n");
867 context = driver.visit(&ast.left, self, context.indent())?;
868 context = context.unindent();
869
870 context = context.append("\n".into());
871
872 context = context.append("\t".repeat(context.indent) + &format!("Operation: {}\n", ast.op));
873
874 context = context.append("\t".repeat(context.indent) + "Right:\n");
875 context = driver.visit(&ast.right, self, context.indent())?;
876 context = context.unindent();
877
878 context = context.append("\n".into());
879 context = context.append("\t".repeat(context.indent) + &format!("Type: {}", ast.aug.tipe));
880 context = context.append("\n".into());
881
882 context = context.append(
883 "\t".repeat(context.indent)
884 + &ast
885 .aug
886 .constant
887 .as_ref()
888 .map(|c| format!("Constant value: {c}"))
889 .unwrap_or("Not a constant".to_string()),
890 );
891
892 context = context.unindent();
893 Ok(context)
894 }
895
896 fn visit_literal(
897 &self,
898 ast: (&ast::Literal, &TextLocation, &Analyzed),
899 context: AstTextSerializerContext,
900 _driver: &AstVisitorDriver,
901 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
902 let mut context =
903 context.append("\t".repeat(context.indent) + "Literal: " + &ast.0.to_string());
904 context = context.append("\n".into());
905
906 context = context.indent();
907
908 context = context.append("\t".repeat(context.indent) + &format!("Type: {}", ast.2.tipe));
909 context = context.append("\n".into());
910
911 context = context.append(
912 "\t".repeat(context.indent)
913 + &ast
914 .2
915 .constant
916 .as_ref()
917 .map(|c| format!("Constant value: {c}"))
918 .unwrap_or("Not a constant".to_string()),
919 );
920 Ok(context.unindent())
921 }
922
923 fn visit_ternary_expr(
924 &self,
925 ast: &ast::TernaryExpr<Analyzed>,
926 context: AstTextSerializerContext,
927 driver: &AstVisitorDriver,
928 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
929 let mut context = context.append("\t".repeat(context.indent) + "Ternary Expression:\n");
930
931 context = context.indent();
932
933 context = context.append("\t".repeat(context.indent) + "Condition:\n");
934 context = driver.visit(&ast.condition, self, context.indent())?;
935 context = context.unindent();
936
937 context = context.append("\n".into());
938
939 context = context.append("\t".repeat(context.indent) + "Yes:\n");
940 context = driver.visit(&ast.yes, self, context.indent())?;
941 context = context.unindent();
942
943 context = context.append("\n".into());
944
945 context = context.append("\t".repeat(context.indent) + "No:\n");
946 context = driver.visit(&ast.no, self, context.indent())?;
947 context = context.unindent();
948
949 context = context.append("\n".into());
950
951 context = context.append("\t".repeat(context.indent) + &format!("Type: {}", ast.aug.tipe));
952 context = context.append("\n".into());
953
954 context = context.append(
955 "\t".repeat(context.indent)
956 + &ast
957 .aug
958 .constant
959 .as_ref()
960 .map(|c| format!("Constant value: {c}"))
961 .unwrap_or("Not a constant".to_string()),
962 );
963
964 context = context.unindent();
965 Ok(context)
966 }
967
968 fn visit_member_access_expr(
969 &self,
970 ast: &ast::MemberAccessExpression<Analyzed>,
971 context: AstTextSerializerContext,
972 driver: &AstVisitorDriver,
973 ) -> AstVisitorResult<AstTextSerializerContext, AstTextSerializerError> {
974 let mut context =
975 context.append("\t".repeat(context.indent) + "Member Access Expression:\n");
976
977 context = context.indent();
978 context = context.append("\t".repeat(context.indent) + "Base:\n");
979 context = driver.visit(&ast.base, self, context.indent())?;
980 context = context.append("\n".into());
981 context = context.unindent();
982
983 context = context.append("\t".repeat(context.indent) + "Member:\n");
984 context = self.visit_identifier(&ast.member, context.indent(), driver)?;
985 context = context.append("\n".into());
986 context = context.unindent();
987
988 context = context.append("\t".repeat(context.indent) + &format!("Type: {}", ast.aug.tipe));
989 context = context.append("\n".into());
990
991 context = context.append(
992 "\t".repeat(context.indent)
993 + &ast
994 .aug
995 .constant
996 .as_ref()
997 .map(|c| format!("Constant value: {c}"))
998 .unwrap_or("Not a constant".to_string()),
999 );
1000
1001 context = context.unindent();
1002
1003 Ok(context)
1004 }
1005}
1006
1007#[cfg(test)]
1008mod analyzed_serializer_tests {
1009 use crate::mel::types::{
1010 self, SimpleParamTypeChecker, Struct,
1011 Type::{self, Function},
1012 };
1013 use crate::mel::{
1014 analysis::{MelAnalysisContext, MelOptimizer, MelTypeChecker},
1015 compiler::compile,
1016 serializer::{AstTextSerializer, AstTextSerializerContext, AstVisitorDriver},
1017 };
1018
1019 #[test]
1020 fn serialize_analyzed_string_expression() {
1021 let code = "\"testing\" . \"one\"";
1022 let expected = "Binary Expression:
1023\tLeft:
1024\t\tLiteral: testing
1025\t\t\tType: String
1026\t\t\tConstant value: testing
1027\tOperation: concat
1028\tRight:
1029\t\tLiteral: one
1030\t\t\tType: String
1031\t\t\tConstant value: one
1032\tType: String
1033\tConstant value: testingone";
1034
1035 let compile_result = compile(code);
1036 let ast = compile_result.expect("Compilation error");
1037
1038 let driver = AstVisitorDriver {};
1039 let visitor = MelTypeChecker {};
1040 let context = MelAnalysisContext::default();
1041 let result = driver
1042 .visit(&ast, &visitor, context)
1043 .expect("Could not analyze");
1044
1045 let driver = AstVisitorDriver {};
1046 let visitor = MelOptimizer {};
1047 let result = driver
1048 .visit(&ast, &visitor, result)
1049 .expect("Could not analyze");
1050
1051 let result = result.expr.expect("Could not get the analyzed expression");
1052
1053 let driver = AstVisitorDriver {};
1054 let visitor = AstTextSerializer {};
1055 let context = AstTextSerializerContext {
1056 serialized: "".to_string(),
1057 indent: 0,
1058 };
1059 let result = driver
1060 .visit(&result, &visitor, context)
1061 .expect("Could not serialize");
1062 pretty_assertions::assert_eq!(result.serialized, expected);
1063 }
1064
1065 #[test]
1066 fn serialize_analyzed_function_call() {
1067 let code = "use(5)";
1068 let expected = "Function Call:
1069\tCallee:
1070\t\tIdentifier: use
1071\tArguments:
1072\t\tLiteral: 5
1073\t\t\tType: Integer
1074\t\t\tNot a constant
1075\tType: Integer";
1076
1077 let compile_result = compile(code);
1078 let ast = compile_result.expect("Compilation error");
1079
1080 let driver = AstVisitorDriver {};
1081 let visitor = MelTypeChecker {};
1082 let mut context = MelAnalysisContext::default();
1083
1084 context = context.update_scopes(&context.scopes.insert(
1085 "use",
1086 Function(
1087 "use".to_string(),
1088 || Type::Integer,
1089 || {
1090 Box::new(SimpleParamTypeChecker {
1091 p: types::ParameterTypesList {
1092 params: vec![Type::Integer],
1093 },
1094 })
1095 },
1096 ),
1097 ));
1098
1099 let result = driver
1100 .visit(&ast, &visitor, context)
1101 .expect("Could not analyze");
1102
1103 let driver = AstVisitorDriver {};
1104 let visitor = MelOptimizer {};
1105 let result = driver
1106 .visit(&ast, &visitor, result)
1107 .expect("Could not analyze");
1108
1109 let result = result.expr.expect("Could not get the analyzed expression");
1110
1111 let driver = AstVisitorDriver {};
1112 let visitor = AstTextSerializer {};
1113 let context = AstTextSerializerContext {
1114 serialized: "".to_string(),
1115 indent: 0,
1116 };
1117 let result = driver
1118 .visit(&result, &visitor, context)
1119 .expect("Could not serialize");
1120 pretty_assertions::assert_eq!(result.serialized, expected);
1121 }
1122
1123 #[test]
1124 fn serialize_analyzed_comparison_expr() {
1125 let code = "5 < 4";
1126 let expected = "Binary Expression:
1127\tLeft:
1128\t\tLiteral: 5
1129\t\t\tType: Integer
1130\t\t\tConstant value: 5
1131\tOperation: <
1132\tRight:
1133\t\tLiteral: 4
1134\t\t\tType: Integer
1135\t\t\tConstant value: 4
1136\tType: Bool
1137\tNot a constant";
1138
1139 let compile_result = compile(code);
1140 let ast = compile_result.expect("Compilation error");
1141
1142 let driver = AstVisitorDriver {};
1143 let visitor = MelTypeChecker {};
1144 let context = MelAnalysisContext::default();
1145
1146 let result = driver
1147 .visit(&ast, &visitor, context)
1148 .expect("Could not analyze");
1149
1150 let driver = AstVisitorDriver {};
1151 let visitor = MelOptimizer {};
1152 let result = driver
1153 .visit(&ast, &visitor, result)
1154 .expect("Could not analyze");
1155
1156 let result = result.expr.expect("Could not get the analyzed expression");
1157
1158 let driver = AstVisitorDriver {};
1159 let visitor = AstTextSerializer {};
1160 let context = AstTextSerializerContext {
1161 serialized: "".to_string(),
1162 indent: 0,
1163 };
1164 let result = driver
1165 .visit(&result, &visitor, context)
1166 .expect("Could not serialize");
1167 pretty_assertions::assert_eq!(result.serialized, expected);
1168 }
1169
1170 #[test]
1171 fn serialize_analyzed_ternary_expr() {
1172 let code = "true ? 1 : 5";
1173 let expected = "Ternary Expression:
1174\tCondition:
1175\t\tLiteral: true
1176\t\t\tType: Bool
1177\t\t\tConstant value: true
1178\tYes:
1179\t\tLiteral: 1
1180\t\t\tType: Integer
1181\t\t\tConstant value: 1
1182\tNo:
1183\t\tLiteral: 5
1184\t\t\tType: Integer
1185\t\t\tConstant value: 5
1186\tType: Integer
1187\tConstant value: 1";
1188
1189 let compile_result = compile(code);
1190 let ast = compile_result.expect("Compilation error");
1191
1192 let driver = AstVisitorDriver {};
1193 let visitor = MelTypeChecker {};
1194 let context = MelAnalysisContext::default();
1195
1196 let result = driver
1197 .visit(&ast, &visitor, context)
1198 .expect("Could not analyze");
1199
1200 let driver = AstVisitorDriver {};
1201 let visitor = MelOptimizer {};
1202 let result = driver
1203 .visit(&ast, &visitor, result)
1204 .expect("Could not analyze");
1205
1206 let result = result.expr.expect("Could not get the analyzed expression");
1207
1208 let driver = AstVisitorDriver {};
1209 let visitor = AstTextSerializer {};
1210 let context = AstTextSerializerContext {
1211 serialized: "".to_string(),
1212 indent: 0,
1213 };
1214 let result = driver
1215 .visit(&result, &visitor, context)
1216 .expect("Could not serialize");
1217 pretty_assertions::assert_eq!(result.serialized, expected);
1218 }
1219
1220 #[test]
1221 fn serialize_analyzed_ternary_expr2() {
1222 let code = "false ? 1 : (5 + 2 + 3)";
1223 let expected = "Ternary Expression:
1224\tCondition:
1225\t\tLiteral: false
1226\t\t\tType: Bool
1227\t\t\tConstant value: false
1228\tYes:
1229\t\tLiteral: 1
1230\t\t\tType: Integer
1231\t\t\tConstant value: 1
1232\tNo:
1233\t\tBinary Expression:
1234\t\t\tLeft:
1235\t\t\t\tBinary Expression:
1236\t\t\t\t\tLeft:
1237\t\t\t\t\t\tLiteral: 5
1238\t\t\t\t\t\t\tType: Integer
1239\t\t\t\t\t\t\tConstant value: 5
1240\t\t\t\t\tOperation: plus
1241\t\t\t\t\tRight:
1242\t\t\t\t\t\tLiteral: 2
1243\t\t\t\t\t\t\tType: Integer
1244\t\t\t\t\t\t\tConstant value: 2
1245\t\t\t\t\tType: Integer
1246\t\t\t\t\tConstant value: 7
1247\t\t\tOperation: plus
1248\t\t\tRight:
1249\t\t\t\tLiteral: 3
1250\t\t\t\t\tType: Integer
1251\t\t\t\t\tConstant value: 3
1252\t\t\tType: Integer
1253\t\t\tConstant value: 10
1254\tType: Integer
1255\tConstant value: 10";
1256
1257 let compile_result = compile(code);
1258 let ast = compile_result.expect("Compilation error");
1259
1260 let driver = AstVisitorDriver {};
1261 let visitor = MelTypeChecker {};
1262 let context = MelAnalysisContext::default();
1263
1264 let result = driver
1265 .visit(&ast, &visitor, context)
1266 .expect("Could not analyze");
1267
1268 let driver = AstVisitorDriver {};
1269 let visitor = MelOptimizer {};
1270 let result = driver
1271 .visit(&ast, &visitor, result)
1272 .expect("Could not analyze");
1273
1274 let result = result.expr.expect("Could not get the analyzed expression");
1275
1276 let driver = AstVisitorDriver {};
1277 let visitor = AstTextSerializer {};
1278 let context = AstTextSerializerContext {
1279 serialized: "".to_string(),
1280 indent: 0,
1281 };
1282 let result = driver
1283 .visit(&result, &visitor, context)
1284 .expect("Could not serialize");
1285 pretty_assertions::assert_eq!(result.serialized, expected);
1286 }
1287
1288 #[test]
1289 fn serialize_analyzed_member_access_binary_expr_nested() {
1290 let code = "req^incoming^headers . \"testing\"";
1291 let expected = "Binary Expression:
1292\tLeft:
1293\t\tMember Access Expression:
1294\t\t\tBase:
1295\t\t\t\tMember Access Expression:
1296\t\t\t\t\tBase:
1297\t\t\t\t\t\tIdentifier: req
1298\t\t\t\t\tMember:
1299\t\t\t\t\t\tIdentifier: incoming
1300\t\t\t\t\tType: Struct: Name: headers, Fields: headers
1301\t\t\t\t\tNot a constant
1302\t\t\tMember:
1303\t\t\t\tIdentifier: headers
1304\t\t\tType: String
1305\t\t\tNot a constant
1306\tOperation: concat
1307\tRight:
1308\t\tLiteral: testing
1309\t\t\tType: String
1310\t\t\tNot a constant
1311\tType: String
1312\tNot a constant";
1313
1314 let compile_result = compile(code);
1315 let ast = compile_result.expect("Compilation error");
1316
1317 let driver = AstVisitorDriver {};
1318 let visitor = MelTypeChecker {};
1319 let mut context = MelAnalysisContext::default();
1320
1321 let mut headers = Struct::new("headers");
1322 headers.insert_field("headers", Type::String);
1323
1324 let mut reqs = Struct::new("req");
1325 reqs.insert_field("incoming", Type::Struct(headers));
1326
1327 context = context.update_scopes(&context.scopes.insert("req", Type::Struct(reqs)));
1328
1329 let result = driver
1330 .visit(&ast, &visitor, context)
1331 .expect("Could not analyze");
1332
1333 let result = result.expr.expect("Could not get the analyzed expression");
1334
1335 let driver = AstVisitorDriver {};
1336 let visitor = AstTextSerializer {};
1337 let context = AstTextSerializerContext {
1338 serialized: "".to_string(),
1339 indent: 0,
1340 };
1341 let result = driver
1342 .visit(&result, &visitor, context)
1343 .expect("Could not serialize");
1344 pretty_assertions::assert_eq!(result.serialized, expected);
1345 }
1346
1347 #[test]
1348 fn serialize_analyzed_member_access_binary_expr() {
1349 let code = "req^incoming and true";
1350 let expected = "Binary Expression:
1351\tLeft:
1352\t\tMember Access Expression:
1353\t\t\tBase:
1354\t\t\t\tIdentifier: req
1355\t\t\tMember:
1356\t\t\t\tIdentifier: incoming
1357\t\t\tType: Bool
1358\t\t\tNot a constant
1359\tOperation: and
1360\tRight:
1361\t\tLiteral: true
1362\t\t\tType: Bool
1363\t\t\tNot a constant
1364\tType: Bool
1365\tNot a constant";
1366
1367 let compile_result = compile(code);
1368 let ast = compile_result.expect("Compilation error");
1369
1370 let driver = AstVisitorDriver {};
1371 let visitor = MelTypeChecker {};
1372 let mut context = MelAnalysisContext::default();
1373
1374 let mut reqs = Struct::new("req");
1375 reqs.insert_field("incoming", Type::Boolean);
1376
1377 context = context.update_scopes(&context.scopes.insert("req", Type::Struct(reqs)));
1378
1379 let result = driver
1380 .visit(&ast, &visitor, context)
1381 .expect("Could not analyze");
1382
1383 let result = result.expr.expect("Could not get the analyzed expression");
1384
1385 let driver = AstVisitorDriver {};
1386 let visitor = AstTextSerializer {};
1387 let context = AstTextSerializerContext {
1388 serialized: "".to_string(),
1389 indent: 0,
1390 };
1391 let result = driver
1392 .visit(&result, &visitor, context)
1393 .expect("Could not serialize");
1394 pretty_assertions::assert_eq!(result.serialized, expected);
1395 }
1396
1397 #[test]
1398 fn serialize_analyzed_member_access_function_call_expr() {
1399 let code = "req^callable(5)";
1400 let expected = "Function Call:
1401\tCallee:
1402\t\tMember Access Expression:
1403\t\t\tBase:
1404\t\t\t\tIdentifier: req
1405\t\t\tMember:
1406\t\t\t\tIdentifier: callable
1407\t\t\tType: Name: callable Return Type: Bool, Parameter Types: Integer
1408\t\t\tNot a constant
1409\tArguments:
1410\t\tLiteral: 5
1411\t\t\tType: Integer
1412\t\t\tNot a constant
1413\tType: Bool";
1414
1415 let compile_result = compile(code);
1416 let ast = compile_result.expect("Compilation error");
1417
1418 let driver = AstVisitorDriver {};
1419 let visitor = MelTypeChecker {};
1420 let mut context = MelAnalysisContext::default();
1421
1422 let mut reqs = Struct::new("req");
1423
1424 reqs.insert_field(
1425 "callable",
1426 Function(
1427 "callable".to_string(),
1428 || Type::Boolean,
1429 || {
1430 Box::new(SimpleParamTypeChecker {
1431 p: types::ParameterTypesList {
1432 params: vec![Type::Integer],
1433 },
1434 })
1435 },
1436 ),
1437 );
1438 context = context.update_scopes(&context.scopes.insert("req", Type::Struct(reqs)));
1439
1440 let result = driver
1441 .visit(&ast, &visitor, context)
1442 .expect("Could not analyze");
1443
1444 let result = result.expr.expect("Could not get the analyzed expression");
1445
1446 let driver = AstVisitorDriver {};
1447 let visitor = AstTextSerializer {};
1448 let context = AstTextSerializerContext {
1449 serialized: "".to_string(),
1450 indent: 0,
1451 };
1452 let result = driver
1453 .visit(&result, &visitor, context)
1454 .expect("Could not serialize");
1455 pretty_assertions::assert_eq!(result.serialized, expected);
1456 }
1457}