1use crate::compiler::expression::ExpressionError;
2use crate::compiler::expression::function_call::FunctionCallError;
3use crate::compiler::{
4 CompileConfig, Function, Program, TypeDef,
5 expression::{
6 Abort, Array, Assignment, Block, Container, Expr, Expression, FunctionArgument,
7 FunctionCall, Group, IfStatement, Literal, Noop, Not, Object, Op, Predicate, Query, Return,
8 Target, Unary, Variable, assignment, function_call, literal, predicate, query,
9 },
10 parser::ast::RootExpr,
11 program::ProgramInfo,
12};
13use crate::diagnostic::{DiagnosticList, DiagnosticMessage};
14use crate::parser::ast::{self, Node, QueryTarget};
15use crate::path::PathPrefix;
16use crate::path::{OwnedTargetPath, OwnedValuePath};
17use crate::prelude::{ArgumentList, expression};
18use crate::value::Value;
19
20use super::state::TypeState;
21
22pub(crate) type DiagnosticsMessages = Vec<Box<dyn DiagnosticMessage>>;
23
24pub struct CompilationResult {
25 pub program: Program,
26 pub warnings: DiagnosticList,
27 pub config: CompileConfig,
28}
29
30pub struct Compiler<'a> {
35 fns: &'a [Box<dyn Function>],
36 diagnostics: DiagnosticsMessages,
37 fallible: bool,
38 abortable: bool,
39 external_queries: Vec<OwnedTargetPath>,
40 external_assignments: Vec<OwnedTargetPath>,
41
42 skip_missing_query_target: Vec<(QueryTarget, OwnedValuePath)>,
48
49 fallible_expression_error: Option<CompilerError>,
58
59 config: CompileConfig,
60}
61
62#[derive(Debug)]
65pub(crate) enum CompilerError {
66 FunctionCallError(FunctionCallError),
67 ExpressionError(ExpressionError),
68}
69
70impl CompilerError {
71 fn to_diagnostic(&self) -> &dyn DiagnosticMessage {
72 match self {
73 CompilerError::FunctionCallError(e) => e,
74 CompilerError::ExpressionError(e) => e,
75 }
76 }
77
78 fn into_diagnostic_boxed(self) -> Box<dyn DiagnosticMessage> {
79 match self {
80 CompilerError::FunctionCallError(e) => Box::new(e),
81 CompilerError::ExpressionError(e) => Box::new(e),
82 }
83 }
84}
85
86impl<'a> Compiler<'a> {
87 pub fn compile(
101 fns: &'a [Box<dyn Function>],
102 ast: crate::parser::Program,
103 state: &TypeState,
104 config: CompileConfig,
105 ) -> Result<CompilationResult, DiagnosticList> {
106 let initial_state = state.clone();
107 let mut state = state.clone();
108
109 let mut compiler = Self {
110 fns,
111 diagnostics: vec![],
112 fallible: false,
113 abortable: false,
114 external_queries: vec![],
115 external_assignments: vec![],
116 skip_missing_query_target: vec![],
117 fallible_expression_error: None,
118 config,
119 };
120 let expressions = compiler.compile_root_exprs(ast, &mut state);
121
122 let (errors, warnings): (Vec<_>, Vec<_>) =
123 compiler.diagnostics.into_iter().partition(|diagnostic| {
124 matches!(
125 diagnostic.severity(),
126 crate::diagnostic::Severity::Bug | crate::diagnostic::Severity::Error
127 )
128 });
129
130 if !errors.is_empty() {
131 return Err(errors.into());
132 }
133
134 let result = CompilationResult {
135 program: Program {
136 expressions: Block::new_inline(expressions),
137 info: ProgramInfo {
138 fallible: compiler.fallible,
139 abortable: compiler.abortable,
140 target_queries: compiler.external_queries,
141 target_assignments: compiler.external_assignments,
142 },
143 initial_state,
144 },
145 warnings: warnings.into(),
146 config: compiler.config,
147 };
148 Ok(result)
149 }
150
151 fn compile_exprs(
152 &mut self,
153 nodes: impl IntoIterator<Item = Node<ast::Expr>>,
154 state: &mut TypeState,
155 ) -> Option<Vec<Expr>> {
156 let mut exprs = vec![];
157 for node in nodes {
158 let expr = self.compile_expr(node, state)?;
159 exprs.push(expr);
160 }
161 Some(exprs)
162 }
163
164 fn compile_expr(&mut self, node: Node<ast::Expr>, state: &mut TypeState) -> Option<Expr> {
165 use ast::Expr::{
166 Abort, Assignment, Container, FunctionCall, IfStatement, Literal, Op, Query, Return,
167 Unary, Variable,
168 };
169 let original_state = state.clone();
170
171 let span = node.span();
172 let expr = match node.into_inner() {
173 Literal(node) => self.compile_literal(node, state),
174 Container(node) => self.compile_container(node, state).map(Into::into),
175 IfStatement(node) => self.compile_if_statement(node, state).map(Into::into),
176 Op(node) => self.compile_op(node, state).map(Into::into),
177 Assignment(node) => self.compile_assignment(node, state).map(Into::into),
178 Query(node) => self.compile_query(node, state).map(Into::into),
179 FunctionCall(node) => self
180 .compile_function_call(node, state)
181 .map(|function_call| {
182 let v = function_call
183 .warnings
184 .iter()
185 .cloned()
186 .map(|w| Box::new(w) as Box<dyn DiagnosticMessage>)
187 .collect::<Vec<_>>();
188
189 self.diagnostics.extend(v);
190 function_call.into()
191 }),
192 Variable(node) => self.compile_variable(node, state).map(Into::into),
193 Unary(node) => self.compile_unary(node, state).map(Into::into),
194 Abort(node) => self.compile_abort(node, state).map(Into::into),
195 Return(node) => self.compile_return(node, state).map(Into::into),
196 }?;
197
198 let type_def = expr.type_info(&original_state).result;
204 if type_def.is_fallible() && self.fallible_expression_error.is_none() {
205 self.fallible_expression_error = Some(CompilerError::ExpressionError(
206 expression::ExpressionError::Fallible { span },
207 ));
208 }
209
210 Some(expr)
211 }
212
213 fn compile_literal(&mut self, node: Node<ast::Literal>, state: &mut TypeState) -> Option<Expr> {
214 use ast::Literal::{Boolean, Float, Integer, Null, RawString, Regex, String, Timestamp};
215 use bytes::Bytes;
216
217 let (span, lit) = node.take();
218
219 let literal = match lit {
220 String(template) => {
221 if let Some(v) = template.as_literal_string() {
222 Ok(Literal::String(Bytes::from(v.to_string())))
223 } else {
224 return self.compile_expr(
226 Node::new(span, template.rewrite_to_concatenated_strings()),
227 state,
228 );
229 }
230 }
231 RawString(v) => Ok(Literal::String(Bytes::from(v))),
232 Integer(v) => Ok(Literal::Integer(v)),
233 Float(v) => Ok(Literal::Float(v)),
234 Boolean(v) => Ok(Literal::Boolean(v)),
235 Regex(v) => regex::Regex::new(&v)
236 .map_err(|err| literal::Error::from((span, err)))
237 .map(|r| Literal::Regex(r.into())),
238 Timestamp(v) => v
240 .parse()
241 .map(Literal::Timestamp)
242 .map_err(|err| literal::Error::from((span, err))),
243 Null => Ok(Literal::Null),
244 };
245
246 literal
247 .map(Into::into)
248 .map_err(|err| self.diagnostics.push(Box::new(err)))
249 .ok()
250 }
251
252 fn compile_container(
253 &mut self,
254 node: Node<ast::Container>,
255 state: &mut TypeState,
256 ) -> Option<Container> {
257 use ast::Container::{Array, Block, Group, Object};
258
259 let variant = match node.into_inner() {
260 Group(node) => self.compile_group(*node, state)?.into(),
261 Block(node) => self.compile_block(node, state)?.into(),
262 Array(node) => self.compile_array(node, state)?.into(),
263 Object(node) => self.compile_object(node, state)?.into(),
264 };
265
266 Some(Container::new(variant))
267 }
268
269 fn compile_group(&mut self, node: Node<ast::Group>, state: &mut TypeState) -> Option<Group> {
270 let expr = self.compile_expr(node.into_inner().into_inner(), state)?;
271
272 Some(Group::new(expr))
273 }
274
275 fn compile_root_exprs(
276 &mut self,
277 nodes: impl IntoIterator<Item = Node<ast::RootExpr>>,
278 state: &mut TypeState,
279 ) -> Vec<Expr> {
280 let mut node_exprs = vec![];
281
282 for root_expr in nodes {
283 match root_expr.into_inner() {
284 RootExpr::Expr(node_expr) => {
285 self.fallible_expression_error = None;
286
287 if let Some(expr) = self.compile_expr(node_expr, state) {
288 if let Some(error) = self.fallible_expression_error.take() {
289 self.diagnostics.push(error.into_diagnostic_boxed());
290 }
291
292 node_exprs.push(expr);
293 }
294 }
295 RootExpr::Error(err) => self.handle_parser_error(err),
296 }
297 }
298
299 if node_exprs.is_empty() {
300 node_exprs.push(Expr::Noop(Noop));
301 }
302 node_exprs
303 }
304
305 fn compile_block(&mut self, node: Node<ast::Block>, state: &mut TypeState) -> Option<Block> {
306 self.compile_block_with_type(node, state)
307 .map(|(block, _type_def)| block)
308 }
309
310 fn compile_block_with_type(
311 &mut self,
312 node: Node<ast::Block>,
313 state: &mut TypeState,
314 ) -> Option<(Block, TypeDef)> {
315 let original_state = state.clone();
316 let exprs = self.compile_exprs(node.into_inner().into_iter(), state)?;
317 let block = Block::new_scoped(exprs);
318
319 *state = original_state;
322 let result = block.apply_type_info(state);
323 Some((block, result))
324 }
325
326 fn compile_array(&mut self, node: Node<ast::Array>, state: &mut TypeState) -> Option<Array> {
327 let exprs = self.compile_exprs(node.into_inner().into_iter(), state)?;
328
329 Some(Array::new(exprs))
330 }
331
332 fn compile_object(&mut self, node: Node<ast::Object>, state: &mut TypeState) -> Option<Object> {
333 let (keys, exprs): (Vec<String>, Vec<Option<Expr>>) = node
334 .into_inner()
335 .into_iter()
336 .map(|(k, expr)| (k.into_inner(), self.compile_expr(expr, state)))
337 .unzip();
338
339 let exprs = exprs.into_iter().collect::<Option<Vec<_>>>()?;
340
341 Some(Object::new(
342 keys.into_iter()
343 .zip(exprs)
344 .map(|(key, value)| (key.into(), value))
345 .collect(),
346 ))
347 }
348
349 fn compile_if_statement(
350 &mut self,
351 node: Node<ast::IfStatement>,
352 state: &mut TypeState,
353 ) -> Option<IfStatement> {
354 let ast::IfStatement {
355 predicate,
356 if_node,
357 else_node,
358 } = node.into_inner();
359
360 let original_state = state.clone();
361
362 let predicate = self
363 .compile_predicate(predicate, state)?
364 .map_err(|err| self.diagnostics.push(Box::new(err)))
365 .ok()?;
366
367 let after_predicate_state = state.clone();
368
369 let if_block = self.compile_block(if_node, state)?;
370
371 let else_block = if let Some(else_node) = else_node {
372 *state = after_predicate_state;
373 Some(self.compile_block(else_node, state)?)
374 } else {
375 None
376 };
377
378 let if_statement = IfStatement {
379 predicate,
380 if_block,
381 else_block,
382 };
383
384 *state = original_state;
387 if_statement.apply_type_info(state);
388 Some(if_statement)
389 }
390
391 fn compile_predicate(
392 &mut self,
393 node: Node<ast::Predicate>,
394 state: &mut TypeState,
395 ) -> Option<predicate::Result> {
396 use ast::Predicate::{Many, One};
397
398 let (span, predicate) = node.take();
399
400 let exprs = match predicate {
401 One(node) => vec![self.compile_expr(*node, state)?],
402 Many(nodes) => self.compile_exprs(nodes, state)?,
403 };
404
405 Some(Predicate::new(
406 Node::new(span, exprs),
407 state,
408 self.fallible_expression_error
409 .as_ref()
410 .map(CompilerError::to_diagnostic),
411 ))
412 }
413
414 fn compile_op(&mut self, node: Node<ast::Op>, state: &mut TypeState) -> Option<Op> {
415 use crate::parser::ast::Opcode;
416
417 let original_state = state.clone();
418
419 let op = node.into_inner();
420 let ast::Op(lhs, opcode, rhs) = op;
421
422 let lhs_span = lhs.span();
423 let lhs = Node::new(lhs_span, self.compile_expr(*lhs, state)?);
424
425 if opcode.inner() == &Opcode::Err {
428 self.fallible_expression_error = None;
429 }
430
431 let fallible_expression_error = self.fallible_expression_error.take();
433
434 let rhs_span = rhs.span();
435 let rhs = Node::new(rhs_span, self.compile_expr(*rhs, state)?);
436
437 let op = Op::new(lhs, opcode, rhs, state)
438 .map_err(|err| self.diagnostics.push(Box::new(err)))
439 .ok()?;
440
441 let type_info = op.type_info(&original_state);
442
443 if self.fallible_expression_error.is_none() {
445 self.fallible_expression_error = fallible_expression_error;
446 }
447
448 if type_info.result.is_infallible() {
449 self.fallible_expression_error = None;
451 }
452
453 *state = type_info.state;
456 Some(op)
457 }
458
459 fn rewrite_to_merge(
461 &mut self,
462 span: crate::diagnostic::Span,
463 target: &Node<ast::AssignmentTarget>,
464 expr: Box<Node<ast::Expr>>,
465 state: &mut TypeState,
466 ) -> Option<Box<Node<Expr>>> {
467 Some(Box::new(Node::new(
468 span,
469 Expr::Op(self.compile_op(
470 Node::new(
471 span,
472 ast::Op(
473 Box::new(Node::new(target.span(), target.inner().to_expr(span))),
474 Node::new(span, ast::Opcode::Merge),
475 expr,
476 ),
477 ),
478 state,
479 )?),
480 )))
481 }
482
483 fn compile_assignment(
484 &mut self,
485 node: Node<ast::Assignment>,
486 state: &mut TypeState,
487 ) -> Option<Assignment> {
488 use assignment::Variant;
489 use ast::{
490 Assignment::{Infallible, Single},
491 AssignmentOp,
492 };
493
494 let original_state = state.clone();
495
496 let assignment = node.into_inner();
497
498 let node = match assignment {
499 Single { target, op, expr } => {
500 let span = expr.span();
501
502 match op {
503 AssignmentOp::Assign => {
504 let expr = self
505 .compile_expr(*expr, state)
506 .map(|expr| Box::new(Node::new(span, expr)))
507 .or_else(|| {
508 self.skip_missing_assignment_target(&target.clone().into_inner());
509 None
510 })?;
511
512 Node::new(span, Variant::Single { target, expr })
513 }
514 AssignmentOp::Merge => {
515 let expr = self.rewrite_to_merge(span, &target, expr, state)?;
516 Node::new(span, Variant::Single { target, expr })
517 }
518 }
519 }
520 Infallible { ok, err, op, expr } => {
521 let span = expr.span();
522
523 let node = match op {
524 AssignmentOp::Assign => {
525 let expr = self
526 .compile_expr(*expr, state)
527 .map(|expr| Box::new(Node::new(span, expr)))
528 .or_else(|| {
529 self.skip_missing_assignment_target(&ok.clone().into_inner());
530 self.skip_missing_assignment_target(&err.clone().into_inner());
531 None
532 })?;
533
534 let node = Variant::Infallible {
535 ok,
536 err,
537 expr,
538 default: Value::Null,
539 };
540 Node::new(span, node)
541 }
542 AssignmentOp::Merge => {
543 let expr = self.rewrite_to_merge(span, &ok, expr, state)?;
544 let node = Variant::Infallible {
545 ok,
546 err,
547 expr,
548 default: Value::Null,
549 };
550
551 Node::new(span, node)
552 }
553 };
554
555 self.fallible_expression_error = None;
559
560 node
561 }
562 };
563
564 let assignment = Assignment::new(
565 node,
566 state,
567 self.fallible_expression_error.as_ref(),
568 &self.config,
569 )
570 .map_err(|err| self.diagnostics.push(Box::new(err)))
571 .ok()?;
572
573 for target in assignment.targets() {
578 if let assignment::Target::External(path) = target {
579 self.external_assignments.push(path);
580 }
581 }
582
583 *state = original_state;
586 assignment.apply_type_info(state);
587
588 Some(assignment)
589 }
590
591 fn compile_query(&mut self, node: Node<ast::Query>, state: &mut TypeState) -> Option<Query> {
592 let ast::Query { target, path } = node.into_inner();
593
594 if self
595 .skip_missing_query_target
596 .contains(&(target.clone().into_inner(), path.clone().into_inner()))
597 {
598 return None;
599 }
600
601 let path = path.into_inner();
602 let target = self.compile_query_target(target, state)?;
603
604 if let Target::External(prefix) = target {
609 let target_path = OwnedTargetPath {
610 prefix,
611 path: path.clone(),
612 };
613 self.external_queries.push(target_path);
614 }
615
616 Some(Query::new(target, path))
617 }
618
619 fn compile_query_target(
620 &mut self,
621 node: Node<ast::QueryTarget>,
622 state: &mut TypeState,
623 ) -> Option<query::Target> {
624 use ast::QueryTarget::{Container, External, FunctionCall, Internal};
625
626 let span = node.span();
627
628 let target = match node.into_inner() {
629 External(prefix) => Target::External(prefix),
630 Internal(ident) => {
631 let variable = self.compile_variable(Node::new(span, ident), state)?;
632 Target::Internal(variable)
633 }
634 Container(container) => {
635 let container = self.compile_container(Node::new(span, container), state)?;
636 Target::Container(container)
637 }
638 FunctionCall(call) => {
639 let call = self.compile_function_call(Node::new(span, call), state)?;
640 Target::FunctionCall(call)
641 }
642 };
643
644 Some(target)
645 }
646
647 #[allow(clippy::unused_self)]
648 pub(crate) fn check_function_deprecations(
649 &mut self,
650 _func: &FunctionCall,
651 _args: &ArgumentList,
652 ) {
653 }
654
655 fn compile_function_call(
656 &mut self,
657 node: Node<ast::FunctionCall>,
658 state: &mut TypeState,
659 ) -> Option<FunctionCall> {
660 let call_span = node.span();
661 let ast::FunctionCall {
662 ident,
663 abort_on_error,
664 arguments,
665 closure,
666 } = node.into_inner();
667
668 let original_state = state.clone();
669 if ident.as_deref() == "get" {
673 self.external_queries.push(OwnedTargetPath::event_root());
674 }
675
676 let arguments: Vec<_> = arguments
677 .into_iter()
678 .map(|node| {
679 Some(Node::new(
680 node.span(),
681 self.compile_function_argument(node, state)?,
682 ))
683 })
684 .collect::<Option<_>>()?;
685
686 if abort_on_error {
687 self.fallible = true;
688 }
689
690 let (closure_variables, closure_block) = match closure {
691 Some(closure) => {
692 let span = closure.span();
693 let ast::FunctionClosure { variables, block } = closure.into_inner();
694 (Some(Node::new(span, variables)), Some(block))
695 }
696 None => (None, None),
697 };
698
699 let local_snapshot = state.local.clone();
704
705 let state_before_function = original_state.clone();
710
711 let function_info = function_call::Builder::new(
714 call_span,
715 ident,
716 abort_on_error,
717 arguments,
718 self.fns,
719 &state_before_function,
720 state,
721 closure_variables,
722 )
723 .map_err(|err| self.diagnostics.push(Box::new(err)))
726 .ok()
727 .and_then(|builder| {
728 let block = match closure_block {
729 None => None,
730 Some(block) => {
731 let span = block.span();
732 match self.compile_block_with_type(block, state) {
733 Some(block_with_type) => Some(Node::new(span, block_with_type)),
734 None => return None,
735 }
736 }
737 };
738
739 let arg_list = builder.get_arg_list().clone();
740
741 builder
742 .compile(
743 &state_before_function,
744 state,
745 block,
746 local_snapshot,
747 &mut self.config,
748 )
749 .map_err(|err| self.diagnostics.push(Box::new(err)))
750 .ok()
751 .map(|result| {
752 if let Some(e) = result.error {
753 self.fallible_expression_error = Some(CompilerError::FunctionCallError(e));
754 }
755 (arg_list, result.function_call)
756 })
757 });
758
759 if let Some((args, function)) = &function_info {
760 self.check_function_deprecations(function, args);
761 *state = function.type_info(&original_state).state;
763 }
764
765 function_info.map(|info| info.1)
766 }
767
768 fn compile_function_argument(
769 &mut self,
770 node: Node<ast::FunctionArgument>,
771 state: &mut TypeState,
772 ) -> Option<FunctionArgument> {
773 let ast::FunctionArgument {
774 ident,
775 expr: ast_expr,
776 } = node.into_inner();
777 let span = ast_expr.span();
778 let expr = self.compile_expr(ast_expr, state)?;
779 let node = Node::new(span, expr);
780
781 Some(FunctionArgument::new(ident, node))
782 }
783
784 fn compile_variable(
785 &mut self,
786 node: Node<ast::Ident>,
787 state: &mut TypeState,
788 ) -> Option<Variable> {
789 let (span, ident) = node.take();
790
791 if self
792 .skip_missing_query_target
793 .contains(&(QueryTarget::Internal(ident.clone()), OwnedValuePath::root()))
794 {
795 return None;
796 }
797
798 Variable::new(span, ident, &state.local)
799 .map_err(|err| self.diagnostics.push(Box::new(err)))
800 .ok()
801 }
802
803 fn compile_unary(&mut self, node: Node<ast::Unary>, state: &mut TypeState) -> Option<Unary> {
804 use ast::Unary::Not;
805
806 let variant = match node.into_inner() {
807 Not(node) => self.compile_not(node, state)?.into(),
808 };
809
810 Some(Unary::new(variant))
811 }
812
813 fn compile_not(&mut self, node: Node<ast::Not>, state: &mut TypeState) -> Option<Not> {
814 let (not, expr) = node.into_inner().take();
815
816 let node = Node::new(expr.span(), self.compile_expr(*expr, state)?);
817
818 Not::new(node, not.span(), state)
819 .map_err(|err| self.diagnostics.push(Box::new(err)))
820 .ok()
821 }
822
823 fn compile_abort(&mut self, node: Node<ast::Abort>, state: &mut TypeState) -> Option<Abort> {
824 self.abortable = true;
825 let (span, abort) = node.take();
826 let message = match abort.message {
827 Some(node) => {
828 Some((*node).map_option(|expr| self.compile_expr(Node::new(span, expr), state))?)
829 }
830 None => None,
831 };
832
833 Abort::new(span, message, state)
834 .map_err(|err| self.diagnostics.push(Box::new(err)))
835 .ok()
836 }
837
838 fn compile_return(&mut self, node: Node<ast::Return>, state: &mut TypeState) -> Option<Return> {
839 let (span, r#return) = node.take();
840
841 let expr = self.compile_expr(*r#return.expr, state)?;
842 let node = Node::new(span, expr);
843
844 Return::new(span, node, state)
845 .map_err(|err| self.diagnostics.push(Box::new(err)))
846 .ok()
847 }
848
849 fn handle_parser_error(&mut self, error: crate::parser::Error) {
850 self.diagnostics.push(Box::new(error));
851 }
852
853 fn skip_missing_assignment_target(&mut self, target: &ast::AssignmentTarget) {
854 let query = match &target {
855 ast::AssignmentTarget::Noop => return,
856 ast::AssignmentTarget::Query(ast::Query { target, path }) => {
857 (target.clone().into_inner(), path.clone().into_inner())
858 }
859 ast::AssignmentTarget::Internal(ident, path) => (
860 QueryTarget::Internal(ident.clone()),
861 path.clone().unwrap_or_else(OwnedValuePath::root),
862 ),
863 ast::AssignmentTarget::External(path) => {
864 let prefix = path.as_ref().map_or(PathPrefix::Event, |x| x.prefix);
865 let path = path.clone().map_or_else(OwnedValuePath::root, |x| x.path);
866 (QueryTarget::External(prefix), path)
867 }
868 };
869
870 self.skip_missing_query_target.push(query);
871 }
872}