1use std::cmp::Ordering;
2use std::collections::{BTreeMap, HashSet};
3use std::mem::size_of;
4
5pub(crate) mod execution;
6pub(crate) mod pattern;
7pub use pattern::{Pattern, PatternKind, copy_pattern, dispose_pattern, pattern_names};
8pub(crate) mod prepared;
9use prepared::{
10 Frame, Preparation, PreparedArgument, PreparedGenerator, PreparedKind, PreparedValue,
11 RuntimeValue,
12};
13
14use crate::runtime_types::{annotate, check_known_type, compatible_declarations, copy_declaration};
15use crate::{Bindings, Budget, DeclaredType, Located, Location, QueryError, QueryErrorCategory};
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19pub struct NominalTypeId(pub u64);
20
21#[derive(Clone, Copy, Debug, PartialEq, Eq)]
23pub struct NominalMemberId(pub u64);
24
25#[derive(Debug)]
29pub struct NominalMember {
30 pub type_id: NominalTypeId,
31 pub member_id: NominalMemberId,
32 pub declaration_order: usize,
33 pub type_name: String,
34 pub member_name: String,
35}
36
37impl PartialEq for NominalMember {
38 fn eq(&self, other: &Self) -> bool {
39 self.type_id == other.type_id && self.member_id == other.member_id
40 }
41}
42impl Eq for NominalMember {}
43
44#[derive(Debug, PartialEq, Eq)]
46pub enum ValueKey {
47 Integer(i64),
48 Member(NominalMember),
49}
50
51#[derive(Clone, Copy, Debug, PartialEq, Eq)]
52pub enum ValueKeyType {
53 Integer,
54 Member(NominalTypeId),
55}
56
57#[derive(Debug, PartialEq, Eq)]
60pub struct KeyAxis {
61 pub key_type: ValueKeyType,
62 pub keys: Vec<ValueKey>,
63}
64
65#[derive(Debug, PartialEq)]
67pub struct KeyedEntry {
68 pub key: Vec<ValueKey>,
69 pub value: ConstructedValue,
70}
71
72#[derive(Debug, PartialEq, Eq)]
76pub struct KeyedArrayType {
77 pub axes: Option<Vec<ValueKeyType>>,
78 pub elements: Vec<ValueType>,
79}
80
81#[derive(Clone, Copy, Debug, PartialEq, Eq)]
84pub enum SetElementType {
85 Boolean,
86 Integer,
87 Float,
88 Member(NominalTypeId),
89}
90
91#[derive(Debug, PartialEq)]
100pub enum ConstructedValue {
101 Absent,
102 Declared {
104 value: Box<Self>,
105 declaration: DeclaredType<()>,
106 },
107 Boolean(bool),
108 Integer(i64),
109 Float(f64),
110 String(String),
111 Member(NominalMember),
112 KeyedArray {
113 axes: Vec<KeyAxis>,
114 entries: Vec<KeyedEntry>,
115 },
116 Array(Vec<Self>),
117 Tuple(Vec<Self>),
118 Record(Vec<(String, Self)>),
119 Set {
120 element_type: Option<SetElementType>,
121 elements: Vec<Self>,
122 },
123}
124
125pub(crate) fn dispose_constructed_value(value: ConstructedValue) {
127 let mut pending = vec![value];
128 while let Some(value) = pending.pop() {
129 match value {
130 ConstructedValue::Declared { value, declaration } => {
131 crate::functions::dispose_declaration(declaration);
132 pending.push(*value);
133 }
134 ConstructedValue::Array(values) | ConstructedValue::Tuple(values) => {
135 pending.extend(values);
136 }
137 ConstructedValue::Record(fields) => {
138 pending.extend(fields.into_iter().map(|(_, value)| value));
139 }
140 ConstructedValue::KeyedArray { entries, .. } => {
141 pending.extend(entries.into_iter().map(|entry| entry.value));
142 }
143 ConstructedValue::Set { elements, .. } => pending.extend(elements),
144 ConstructedValue::Absent
145 | ConstructedValue::Boolean(_)
146 | ConstructedValue::Integer(_)
147 | ConstructedValue::Float(_)
148 | ConstructedValue::String(_)
149 | ConstructedValue::Member(_) => {}
150 }
151 }
152}
153
154#[derive(Debug, PartialEq, Eq)]
157pub enum ArrayType {
158 Positions(Vec<ValueType>),
159 Elements(Vec<ValueType>),
160}
161
162#[derive(Debug, PartialEq, Eq)]
166pub enum ValueType {
167 Absent,
168 Declared {
170 actual: Box<Self>,
171 declaration: DeclaredType<()>,
172 },
173 ScalarKind,
176 Boolean,
177 Integer,
178 Float,
179 String,
180 Member(NominalTypeId),
181 KeyedArray(KeyedArrayType),
182 Array(ArrayType),
183 ArrayKind(Vec<Self>),
185 Tuple(Vec<Self>),
186 TupleKind,
188 Record(Vec<(String, Self)>),
189 RecordKind,
191 Set(Option<SetElementType>),
192 Unestablished,
193}
194
195#[derive(Clone, Copy, Debug, PartialEq, Eq)]
196pub enum ValueUnaryOperator {
197 Positive,
198 Negative,
199 Not,
200}
201
202#[derive(Clone, Copy, Debug, PartialEq, Eq)]
203pub enum ValueBinaryOperator {
204 Add,
205 Subtract,
206 Multiply,
207 Divide,
208 IntegerDivide,
209 Modulo,
210 Less,
211 LessEqual,
212 Greater,
213 GreaterEqual,
214 Equal,
215 NotEqual,
216 In,
217 And,
218 Or,
219 Concatenate,
220 Contains,
222 StartsWith,
224 EndsWith,
226}
227
228#[derive(Clone, Copy, Debug, PartialEq, Eq)]
229pub enum ValueConstructor {
230 Array,
231 Set,
232}
233
234#[derive(Clone, Copy, Debug, PartialEq, Eq)]
238pub enum ValueReducer {
239 Length,
240 Sum,
241 Forall,
242 Exists,
243}
244
245#[derive(Clone, Copy, Debug, PartialEq, Eq)]
247pub enum ValueExtremum {
248 Min,
249 Max,
250}
251
252#[derive(Debug, PartialEq, Eq)]
254pub enum SortSelector {
255 Value,
257 Field(String),
259}
260
261pub type ValueExpression<Q = ()> = Located<ValueExpressionKind<Q>>;
262
263pub(crate) const PREDICATE_SUBJECT: &str = "\0predicate";
265
266#[derive(Debug, PartialEq)]
271pub struct PredicateArgument<Q = ()> {
272 pub argument: Option<Pattern>,
275 pub body: Box<ValueExpression<Q>>,
276}
277impl<Q> PredicateArgument<Q> {
278 pub fn bind_value(self, subject: ValueExpression<Q>) -> ValueExpression<Q> {
282 let range = self.body.range.clone();
283 Located::new(
284 ValueExpressionKind::SubjectScope {
285 subject: Box::new(subject),
286 argument: self,
287 },
288 range,
289 )
290 }
291 pub fn bind(self, subject: ValueExpression<Q>) -> ValueExpression<Q> {
295 let range = self.body.range.clone();
296 Located::new(
297 ValueExpressionKind::PredicateScope {
298 subject: Box::new(subject),
299 predicate: self,
300 },
301 range,
302 )
303 }
304}
305
306#[derive(Debug, PartialEq)]
310pub enum ValueExpressionKind<Q = ()> {
311 Literal(ConstructedValue),
312 CurrentInput,
314 Queue {
316 items: Box<ValueExpression<Q>>,
317 element: Option<Located<crate::SignatureType>>,
318 },
319 PopFront(Box<ValueExpression<Q>>),
321 PushBackAll {
322 queue: Box<ValueExpression<Q>>,
323 items: Box<ValueExpression<Q>>,
324 },
325 IdentitySet {
327 element: Located<crate::SignatureType>,
328 },
329 Insert {
330 set: Box<ValueExpression<Q>>,
331 item: Box<ValueExpression<Q>>,
332 },
333 NativeQuery(Box<Q>),
335 NativeValue(Box<Q>),
338 Call {
340 function: Located<String>,
341 arguments: Vec<ValueExpression<Q>>,
342 },
343 Fold {
374 items: Box<ValueExpression<Q>>,
375 initial: Box<ValueExpression<Q>>,
376 step: Located<String>,
377 },
378 Scan {
380 items: Box<ValueExpression<Q>>,
381 initial: Box<ValueExpression<Q>>,
382 step: Located<String>,
383 },
384 One(Box<ValueExpression<Q>>),
386 Name(String),
387 PredicateSubject,
389 SubjectScope {
391 subject: Box<ValueExpression<Q>>,
392 argument: PredicateArgument<Q>,
393 },
394 PredicateScope {
396 subject: Box<ValueExpression<Q>>,
397 predicate: PredicateArgument<Q>,
398 },
399 Occurs(Box<ValueExpression<Q>>),
400 Absent(Box<ValueExpression<Q>>),
401 Lookup {
402 value: Box<ValueExpression<Q>>,
403 key: Box<ValueExpression<Q>>,
404 },
405 HasKey {
406 value: Box<ValueExpression<Q>>,
407 key: Box<ValueExpression<Q>>,
408 },
409 Default {
410 value: Box<ValueExpression<Q>>,
411 fallback: Box<ValueExpression<Q>>,
412 },
413 Array(Vec<ValueExpression<Q>>),
414 Tuple(Vec<ValueExpression<Q>>),
415 Record(Vec<(Located<String>, ValueExpression<Q>)>),
416 Dictionary(Vec<(ValueExpression<Q>, ValueExpression<Q>)>),
418 DictionaryComprehension {
419 clauses: Vec<Located<ValueGenerator<Q>>>,
420 key: Box<ValueExpression<Q>>,
421 head: Box<ValueExpression<Q>>,
422 },
423 Set(Vec<ValueExpression<Q>>),
424 KeyedArray {
427 axes: Option<Vec<KeyAxis>>,
428 declared_axis_sources: Option<Vec<ValueExpression<Q>>>,
430 entries: Vec<(ValueExpression<Q>, ValueExpression<Q>)>,
431 },
432 KeyedComprehension {
434 clauses: Vec<Located<ValueGenerator<Q>>>,
435 key: Box<ValueExpression<Q>>,
436 head: Box<ValueExpression<Q>>,
437 declared_axis_sources: Option<Vec<ValueExpression<Q>>>,
438 empty_axis_sources: Option<Vec<ValueExpression<Q>>>,
440 },
441 Unary {
442 operator: ValueUnaryOperator,
443 operand: Box<ValueExpression<Q>>,
444 },
445 Binary {
446 operator: ValueBinaryOperator,
447 left: Box<ValueExpression<Q>>,
448 right: Box<ValueExpression<Q>>,
449 },
450 Field {
451 value: Box<ValueExpression<Q>>,
452 field: Located<String>,
453 },
454 TupleAccess {
455 value: Box<ValueExpression<Q>>,
456 position: Located<usize>,
457 },
458 ArrayAccess {
459 array: Box<ValueExpression<Q>>,
460 index: Box<ValueExpression<Q>>,
461 },
462 IndexSet(Box<ValueExpression<Q>>),
463 Entries(Box<ValueExpression<Q>>),
466 ZipExact {
469 left: Box<ValueExpression<Q>>,
470 right: Box<ValueExpression<Q>>,
471 },
472 Reduce {
474 operator: ValueReducer,
475 array: Box<ValueExpression<Q>>,
476 },
477 Filter {
479 array: Box<ValueExpression<Q>>,
480 predicate: PredicateArgument<Q>,
481 },
482 Sort {
488 array: Box<ValueExpression<Q>>,
489 selector: Option<Located<SortSelector>>,
490 descending: bool,
491 },
492 Unique(Box<ValueExpression<Q>>),
495 Tally(Box<ValueExpression<Q>>),
497 Extremum {
500 operator: ValueExtremum,
501 array: Box<ValueExpression<Q>>,
502 field: Option<Located<String>>,
503 },
504 GroupBy {
510 rows: Box<ValueExpression<Q>>,
511 field: Located<String>,
512 },
513 Require {
516 condition: Box<ValueExpression<Q>>,
517 value: Box<ValueExpression<Q>>,
518 message: Located<String>,
519 },
520 Range {
521 lower: Box<ValueExpression<Q>>,
522 upper: Box<ValueExpression<Q>>,
523 },
524 Conditional {
526 branches: Vec<(ValueExpression<Q>, ValueExpression<Q>)>,
527 otherwise: Box<ValueExpression<Q>>,
528 },
529 Loop {
572 states: Vec<(Located<String>, ValueExpression<Q>)>,
573 body: Box<ValueExpression<Q>>,
574 },
575 Break(Box<ValueExpression<Q>>),
577 Continue(Vec<ValueExpression<Q>>),
579 Block {
581 bindings: Vec<(Pattern, ValueExpression<Q>)>,
582 value: Box<ValueExpression<Q>>,
583 },
584 ValueMatch {
586 subject: Box<ValueExpression<Q>>,
587 arms: Vec<ValueMatchArm<Q>>,
588 },
589 Comprehension {
590 constructor: ValueConstructor,
591 clauses: Vec<Located<ValueGenerator<Q>>>,
592 head: Box<ValueExpression<Q>>,
593 },
594}
595
596#[derive(Debug, PartialEq)]
598pub struct ValueMatchArm<Q = ()> {
599 pub pattern: Pattern,
600 pub guard: Option<ValueExpression<Q>>,
601 pub value: ValueExpression<Q>,
602}
603
604#[derive(Debug, PartialEq)]
607pub enum ValueGenerator<Q = ()> {
608 In {
609 binders: Vec<Pattern>,
610 source: ValueExpression<Q>,
611 filter: Option<ValueExpression<Q>>,
612 },
613 Bind {
614 binder: Pattern,
615 value: ValueExpression<Q>,
616 filter: Option<ValueExpression<Q>>,
617 },
618}
619
620#[derive(Debug)]
623pub struct ConstructedRead {
624 value: RuntimeValue,
625 location: Location,
626 declaration: Option<DeclaredType<()>>,
627}
628impl ConstructedRead {
629 pub(crate) fn from_runtime(
630 value: RuntimeValue,
631 location: Location,
632 declaration: Option<DeclaredType<()>>,
633 ) -> Self {
634 Self {
635 value,
636 location,
637 declaration,
638 }
639 }
640 pub fn value(&self) -> &ConstructedValue {
641 self.value.as_ref()
642 }
643 pub fn declared_type(&self) -> Option<&DeclaredType<()>> {
647 self.declaration
648 .as_ref()
649 .or_else(|| declaration(self.value.as_ref()))
650 }
651 pub fn into_owned(self, budget: &mut Budget) -> Result<ConstructedValue, QueryError> {
656 budget.within_evaluation(1, self.location.clone(), |budget| {
657 let value = self.value.materialize(budget, &self.location)?;
658 if let Some(declaration) = self.declaration {
659 annotate(value, declaration, budget, &self.location)
660 } else {
661 Ok(value)
662 }
663 })
664 }
665}
666
667pub trait ValueArguments<Q, E: From<QueryError>> {
670 fn evaluate(
671 &mut self,
672 expression: &ValueExpression<Q>,
673 queries: &mut dyn ValueQueryHost<Q, Error = E>,
674 budget: &mut Budget,
675 ) -> Result<ConstructedRead, E>;
676}
677
678pub trait ValueQueryHost<Q> {
682 type Error: From<QueryError>;
683
684 fn current_input_types(
687 &mut self,
688 range: &std::ops::Range<usize>,
689 _budget: &mut Budget,
690 ) -> Result<Vec<ValueType>, QueryError> {
691 Err(QueryError::query(
692 range.clone(),
693 "constructed current input is unavailable",
694 ))
695 }
696 fn read_current_input(
699 &mut self,
700 range: &std::ops::Range<usize>,
701 _budget: &mut Budget,
702 ) -> Result<ConstructedValue, Self::Error> {
703 Err(QueryError::query(range.clone(), "constructed current input is unavailable").into())
704 }
705
706 fn predicate_subject_types(
709 &mut self,
710 range: &std::ops::Range<usize>,
711 _budget: &mut Budget,
712 ) -> Result<Vec<ValueType>, QueryError> {
713 Err(QueryError::query(
714 range.clone(),
715 "unnamed argument is only available in a predicate",
716 ))
717 }
718 fn read_predicate_subject(
719 &mut self,
720 range: &std::ops::Range<usize>,
721 _budget: &mut Budget,
722 ) -> Result<ConstructedValue, Self::Error> {
723 Err(QueryError::query(
724 range.clone(),
725 "unnamed argument is only available in a predicate",
726 )
727 .into())
728 }
729
730 fn prepare_computation(
733 &mut self,
734 _expression: &ValueExpression<Q>,
735 _budget: &mut Budget,
736 ) -> Result<(), QueryError> {
737 Ok(())
738 }
739 fn worklist_id(
741 &mut self,
742 expression: &ValueExpression<Q>,
743 _budget: &mut Budget,
744 ) -> Result<usize, QueryError> {
745 Err(QueryError::query(
746 expression.range.clone(),
747 "computational values require a native function host",
748 ))
749 }
750 fn worklist_types(
753 &mut self,
754 expression: &ValueExpression<Q>,
755 _budget: &mut Budget,
756 ) -> Result<Vec<ValueType>, QueryError> {
757 Err(QueryError::query(
758 expression.range.clone(),
759 "computational values require a native function host",
760 ))
761 }
762
763 fn function(
766 &mut self,
767 name: &Located<String>,
768 _budget: &mut Budget,
769 ) -> Result<(usize, usize), QueryError> {
770 Err(QueryError::query(
771 name.range.clone(),
772 "named functions require a function request",
773 ))
774 }
775 fn function_types(
776 &mut self,
777 name: &Located<String>,
778 budget: &mut Budget,
779 ) -> Result<Vec<ValueType>, QueryError> {
780 self.function(name, budget)?;
781 Ok(vec![ValueType::Unestablished])
782 }
783 fn accumulator_function(
786 &mut self,
787 step: &Located<String>,
788 _budget: &mut Budget,
789 ) -> Result<(usize, Vec<ValueType>), QueryError> {
790 Err(QueryError::query(
791 step.range.clone(),
792 "named accumulators require a function request",
793 ))
794 }
795 fn native_value_types(
796 &mut self,
797 _query: &Q,
798 _locals: &[(&str, Vec<ValueType>)],
799 _budget: &mut Budget,
800 range: &std::ops::Range<usize>,
801 ) -> Result<Vec<ValueType>, QueryError> {
802 Err(QueryError::query(
803 range.clone(),
804 "native values require a function request",
805 ))
806 }
807 fn enter_scope(
809 &mut self,
810 _budget: &mut Budget,
811 _range: &std::ops::Range<usize>,
812 ) -> Result<(), QueryError> {
813 Ok(())
814 }
815 fn leave_scope(&mut self) {}
816 fn prepare_pattern(
818 &mut self,
819 _pattern: &Pattern,
820 _source: &ValueExpression<Q>,
821 _budget: &mut Budget,
822 ) -> Result<(), QueryError> {
823 Ok(())
824 }
825 fn prepare_local(
826 &mut self,
827 _name: &Located<String>,
828 _value: &ValueExpression<Q>,
829 _types: &[ValueType],
830 _budget: &mut Budget,
831 ) -> Result<(), QueryError> {
832 Ok(())
833 }
834 fn prepare_generator(
839 &mut self,
840 _binder: &Pattern,
841 _source: &ValueExpression<Q>,
842 _types: &[ValueType],
843 _element: bool,
844 _budget: &mut Budget,
845 ) -> Result<(), QueryError> {
846 Ok(())
847 }
848 fn prepare_predicate(
851 &mut self,
852 _argument: Option<&Pattern>,
853 _source: &ValueExpression<Q>,
854 _types: &[ValueType],
855 _element: bool,
856 _budget: &mut Budget,
857 ) -> Result<(), QueryError> {
858 Ok(())
859 }
860 fn query_types(
861 &mut self,
862 query: &Q,
863 locals: &[(&str, Vec<ValueType>)],
864 budget: &mut Budget,
865 range: &std::ops::Range<usize>,
866 ) -> Result<Vec<ValueType>, QueryError>;
867 fn evaluate_query(
868 &mut self,
869 query: &Q,
870 locals: &[(&str, ConstructedValue)],
871 budget: &mut Budget,
872 ) -> Result<ConstructedValue, Self::Error>;
873 fn read_binding(
874 &mut self,
875 name: &str,
876 range: &std::ops::Range<usize>,
877 budget: &mut Budget,
878 ) -> Result<ConstructedValue, Self::Error>;
879 fn evaluate_query_with_shared_locals(
882 &mut self,
883 query: &Q,
884 locals: &[(&str, std::sync::Arc<ConstructedValue>)],
885 budget: &mut Budget,
886 range: &std::ops::Range<usize>,
887 ) -> Result<ConstructedValue, Self::Error> {
888 let location = Location::Query(range.clone());
889 let mut owned = metadata_vec(locals.len(), budget, &location)?;
890 for (name, value) in locals {
891 owned.push((
892 *name,
893 copy_constructed_value(value, budget, location.clone())?,
894 ));
895 }
896 self.evaluate_query(query, &owned, budget)
897 }
898 fn query_arguments<'q>(
900 &self,
901 _query: &'q Q,
902 _budget: &mut Budget,
903 _range: &std::ops::Range<usize>,
904 ) -> Result<Vec<&'q ValueExpression<Q>>, QueryError> {
905 Ok(Vec::new())
906 }
907 fn evaluate_query_with_arguments(
909 &mut self,
910 query: &Q,
911 locals: &[(&str, std::sync::Arc<ConstructedValue>)],
912 _arguments: &mut dyn ValueArguments<Q, Self::Error>,
913 budget: &mut Budget,
914 range: &std::ops::Range<usize>,
915 ) -> Result<ConstructedValue, Self::Error> {
916 self.evaluate_query_with_shared_locals(query, locals, budget, range)
917 }
918 fn read_shared_binding(
922 &mut self,
923 _name: &str,
924 _range: &std::ops::Range<usize>,
925 _budget: &mut Budget,
926 ) -> Result<Option<std::sync::Arc<ConstructedValue>>, Self::Error> {
927 Ok(None)
928 }
929 fn validate_name(
930 &mut self,
931 _name: &str,
932 _range: &std::ops::Range<usize>,
933 _budget: &mut Budget,
934 ) -> Result<(), QueryError> {
935 Ok(())
936 }
937}
938
939struct NoQueries<'a> {
940 bindings: Option<&'a Bindings<ConstructedValue>>,
941}
942impl ValueQueryHost<()> for NoQueries<'_> {
943 type Error = QueryError;
944 fn query_types(
945 &mut self,
946 _: &(),
947 _: &[(&str, Vec<ValueType>)],
948 _: &mut Budget,
949 range: &std::ops::Range<usize>,
950 ) -> Result<Vec<ValueType>, QueryError> {
951 Err(QueryError::query(
952 range.clone(),
953 "native queries are unavailable in this value expression",
954 ))
955 }
956 fn evaluate_query(
957 &mut self,
958 _: &(),
959 _: &[(&str, ConstructedValue)],
960 _: &mut Budget,
961 ) -> Result<ConstructedValue, QueryError> {
962 Err(QueryError::query(
963 0..0,
964 "native queries are unavailable in this value expression",
965 ))
966 }
967 fn read_shared_binding(
968 &mut self,
969 name: &str,
970 range: &std::ops::Range<usize>,
971 budget: &mut Budget,
972 ) -> Result<Option<std::sync::Arc<ConstructedValue>>, QueryError> {
973 budget.charge(1, Location::Query(range.clone()))?;
974 Ok(Some(
975 self.bindings
976 .expect("runtime value bindings")
977 .shared(name, range.clone())?,
978 ))
979 }
980
981 fn read_binding(
982 &mut self,
983 name: &str,
984 range: &std::ops::Range<usize>,
985 budget: &mut Budget,
986 ) -> Result<ConstructedValue, QueryError> {
987 copy_constructed_value(
988 self.bindings
989 .expect("runtime value bindings")
990 .get(name, range.clone())?,
991 budget,
992 Location::Query(range.clone()),
993 )
994 }
995}
996
997pub fn value_expression_types(
1002 expression: &ValueExpression,
1003 binding_types: &BTreeMap<String, ValueType>,
1004 budget: &mut Budget,
1005) -> Result<Vec<ValueType>, QueryError> {
1006 Analysis::new(
1007 Globals::Types(binding_types),
1008 &mut NoQueries { bindings: None },
1009 )
1010 .walk(expression, budget)
1011}
1012
1013pub fn query_value_types<Q, H: ValueQueryHost<Q>>(
1018 expression: &ValueExpression<Q>,
1019 binding_types: &BTreeMap<String, Vec<ValueType>>,
1020 queries: &mut H,
1021 budget: &mut Budget,
1022) -> Result<Vec<ValueType>, QueryError> {
1023 Analysis::new(Globals::Facts(binding_types), queries).walk(expression, budget)
1024}
1025
1026pub fn free_query_value_names<Q, H: ValueQueryHost<Q>>(
1031 expression: &ValueExpression<Q>,
1032 binding_types: &BTreeMap<String, Vec<ValueType>>,
1033 queries: &mut H,
1034 budget: &mut Budget,
1035) -> Result<Vec<Located<String>>, QueryError> {
1036 let mut analysis = Analysis::new(Globals::Facts(binding_types), queries);
1037 analysis.walk(expression, budget)?;
1038 Ok(analysis.free)
1039}
1040
1041pub fn evaluate_query_value<Q, H: ValueQueryHost<Q>>(
1046 expression: &ValueExpression<Q>,
1047 binding_types: &BTreeMap<String, Vec<ValueType>>,
1048 queries: &mut H,
1049 budget: &mut Budget,
1050) -> Result<ConstructedValue, H::Error> {
1051 let prepared = prepare_query_value(expression, binding_types, queries, budget)?;
1052 let mut frame = Frame::new(
1053 prepared.names,
1054 budget,
1055 &Location::Query(expression.range.clone()),
1056 )?;
1057 run(
1058 &prepared.expression,
1059 queries,
1060 &mut frame,
1061 budget,
1062 &mut |_, _, _| Ok(()),
1063 )
1064}
1065
1066pub(crate) struct PreparedQueryValue<'a, Q> {
1067 expression: PreparedValue<'a, Q>,
1068 names: Vec<&'a str>,
1069 pub types: Vec<ValueType>,
1070}
1071pub(crate) fn prepare_query_value<'a, Q, H: ValueQueryHost<Q>>(
1072 expression: &'a ValueExpression<Q>,
1073 binding_types: &BTreeMap<String, Vec<ValueType>>,
1074 queries: &mut H,
1075 budget: &mut Budget,
1076) -> Result<PreparedQueryValue<'a, Q>, QueryError> {
1077 let types = query_value_types(expression, binding_types, queries, budget)?;
1078 let mut preparation = Preparation::new();
1079 let expression = preparation.resolve(expression, queries, budget)?;
1080 Ok(PreparedQueryValue {
1081 expression,
1082 names: preparation.names,
1083 types,
1084 })
1085}
1086impl<'a, Q> PreparedQueryValue<'a, Q> {
1087 pub fn frame(&self, budget: &mut Budget) -> Result<Frame<'a>, QueryError> {
1088 let mut names = metadata_vec(
1089 self.names.len(),
1090 budget,
1091 &Location::Query(self.expression.range.clone()),
1092 )?;
1093 names.extend_from_slice(&self.names);
1094 Frame::new(
1095 names,
1096 budget,
1097 &Location::Query(self.expression.range.clone()),
1098 )
1099 }
1100 pub fn evaluate<H: ValueQueryHost<Q>>(
1101 &'a self,
1102 queries: &mut H,
1103 frame: &mut Frame<'a>,
1104 budget: &mut Budget,
1105 ) -> Result<ConstructedValue, H::Error> {
1106 run(&self.expression, queries, frame, budget, &mut |_, _, _| {
1107 Ok(())
1108 })
1109 }
1110}
1111
1112pub fn take_one<T>(mut values: Vec<T>, range: std::ops::Range<usize>) -> Result<T, QueryError> {
1117 if values.len() != 1 {
1118 return Err(QueryError::query(range, "one requires exactly one value"));
1119 }
1120 Ok(values.pop().expect("one child"))
1121}
1122
1123pub fn count_value(
1128 count: usize,
1129 budget: &mut Budget,
1130 location: Location,
1131) -> Result<ConstructedValue, QueryError> {
1132 let count =
1133 i64::try_from(count).map_err(|_| error(&location, "count exceeds signed 64-bit range"))?;
1134 scalar(ConstructedValue::Integer(count), budget, &location)
1135}
1136
1137pub fn validate_value_expression(
1143 expression: &ValueExpression,
1144 binding_types: &BTreeMap<String, ValueType>,
1145 budget: &mut Budget,
1146) -> Result<(), QueryError> {
1147 Analysis::new(
1148 Globals::Types(binding_types),
1149 &mut NoQueries { bindings: None },
1150 )
1151 .walk(expression, budget)?;
1152 Ok(())
1153}
1154
1155pub fn free_value_names(
1162 expression: &ValueExpression,
1163 binding_types: &BTreeMap<String, ValueType>,
1164 budget: &mut Budget,
1165) -> Result<Vec<Located<String>>, QueryError> {
1166 let mut queries = NoQueries { bindings: None };
1167 let mut analysis = Analysis::new(Globals::Types(binding_types), &mut queries);
1168 analysis.walk(expression, budget)?;
1169 Ok(analysis.free)
1170}
1171
1172pub fn constructed_value_type(
1179 value: &ConstructedValue,
1180 budget: &mut Budget,
1181 location: Location,
1182) -> Result<ValueType, QueryError> {
1183 budget.within_evaluation(1, location.clone(), |budget| {
1184 budget.charge(1, location.clone())?;
1185 match value {
1186 ConstructedValue::Absent => Ok(ValueType::Absent),
1187 ConstructedValue::Declared { value, declaration } => {
1188 crate::admit_constructed(value, declaration, budget, location.clone())?;
1189 Ok(ValueType::Declared {
1190 actual: Box::new(constructed_value_type(value, budget, location.clone())?),
1191 declaration: copy_declaration(declaration, budget, &location)?,
1192 })
1193 }
1194 ConstructedValue::Boolean(_) => Ok(ValueType::Boolean),
1195 ConstructedValue::Integer(_) => Ok(ValueType::Integer),
1196 ConstructedValue::Float(value) => {
1197 finite(*value, &location)?;
1198 Ok(ValueType::Float)
1199 }
1200 ConstructedValue::String(_) => Ok(ValueType::String),
1201 ConstructedValue::Member(member) => {
1202 member_bytes(member, budget, &location)?;
1203 Ok(ValueType::Member(member.type_id))
1204 }
1205 ConstructedValue::KeyedArray { axes, entries } => {
1206 check_keyed(axes, entries, budget, &location)?;
1207 let axes = axis_types(axes, budget, &location)?;
1208 let mut elements = metadata_vec(entries.len(), budget, &location)?;
1209 for entry in entries {
1210 elements.push(constructed_value_type(
1211 &entry.value,
1212 budget,
1213 location.clone(),
1214 )?);
1215 }
1216 Ok(ValueType::KeyedArray(KeyedArrayType {
1217 axes: Some(axes),
1218 elements,
1219 }))
1220 }
1221 ConstructedValue::Array(values) | ConstructedValue::Tuple(values) => {
1222 let mut types = metadata_vec(values.len(), budget, &location)?;
1223 for value in values {
1224 types.push(constructed_value_type(value, budget, location.clone())?);
1225 }
1226 Ok(if matches!(value, ConstructedValue::Array(_)) {
1227 ValueType::Array(ArrayType::Positions(types))
1228 } else {
1229 ValueType::Tuple(types)
1230 })
1231 }
1232 ConstructedValue::Record(fields) => {
1233 check_value_labels(fields, budget, &location)?;
1234 let mut types = metadata_vec(fields.len(), budget, &location)?;
1235 for (label, value) in fields {
1236 budget.charge(label.len(), location.clone())?;
1237 let ty = constructed_value_type(value, budget, location.clone())?;
1238 types.push((label.to_owned(), ty));
1239 }
1240 Ok(ValueType::Record(types))
1241 }
1242 ConstructedValue::Set {
1243 element_type,
1244 elements,
1245 } => {
1246 check_set(*element_type, elements, budget, &location)?;
1247 Ok(ValueType::Set(*element_type))
1248 }
1249 }
1250 })
1251}
1252
1253pub fn evaluate_value(
1263 expression: &ValueExpression,
1264 bindings: &Bindings<ConstructedValue>,
1265 budget: &mut Budget,
1266) -> Result<ConstructedValue, QueryError> {
1267 evaluate_value_with_host_validation(expression, bindings, budget, |_, _, _| Ok(()))
1268}
1269
1270pub fn evaluate_value_with_host_validation(
1282 expression: &ValueExpression,
1283 bindings: &Bindings<ConstructedValue>,
1284 budget: &mut Budget,
1285 mut check_value: impl FnMut(&ConstructedValue, &mut Budget, &Location) -> Result<(), QueryError>,
1286) -> Result<ConstructedValue, QueryError> {
1287 let mut queries = NoQueries {
1288 bindings: Some(bindings),
1289 };
1290 let mut analysis = Analysis::new(Globals::Available(bindings), &mut queries);
1291 analysis.walk(expression, budget)?;
1292 let mut types = BTreeMap::new();
1293 for name in analysis.free {
1294 let location = Location::Query(name.range.clone());
1295 let mut fallback_only = false;
1296 for candidate in &analysis.fallback_names {
1297 budget.charge(
1298 1 + candidate.value.len().min(name.value.len()),
1299 location.clone(),
1300 )?;
1301 if candidate.value == name.value {
1302 fallback_only = true;
1303 break;
1304 }
1305 }
1306 budget.charge(1, location.clone())?;
1307 admit_diagnostic("undefined binding: ", &name.value, budget, &location)?;
1308 let value = bindings.get(&name.value, name.range)?;
1309 let ty = if !fallback_only {
1310 constructed_value_type(value, budget, location)?
1311 } else {
1312 shallow_type(value, budget, &location)?
1313 };
1314 types.insert(name.value, ty);
1315 }
1316 validate_value_expression(expression, &types, budget)?;
1317 let mut preparation = Preparation::new();
1318 let prepared = preparation.resolve(expression, &mut queries, budget)?;
1319 let mut frame = Frame::new(
1320 preparation.names,
1321 budget,
1322 &Location::Query(expression.range.clone()),
1323 )?;
1324 run(
1325 &prepared,
1326 &mut NoQueries {
1327 bindings: Some(bindings),
1328 },
1329 &mut frame,
1330 budget,
1331 &mut check_value,
1332 )
1333}
1334
1335pub fn copy_constructed_value(
1343 value: &ConstructedValue,
1344 budget: &mut Budget,
1345 location: Location,
1346) -> Result<ConstructedValue, QueryError> {
1347 let (units, bytes) = copy_size(value, budget, &location)?;
1348 budget.charge(bytes, location.clone())?;
1349 budget.charge_results(units, location.clone())?;
1350 copy_admitted(value, budget, &location)
1351}
1352
1353impl ConstructedValue {
1354 pub fn data(&self) -> &Self {
1356 let mut value = self;
1357 while let Self::Declared { value: inner, .. } = value {
1358 value = inner;
1359 }
1360 value
1361 }
1362
1363 pub fn occurs(&self) -> bool {
1365 !matches!(self.data(), Self::Absent)
1366 }
1367
1368 pub fn into_data(self) -> Self {
1370 let mut value = self;
1371 while let Self::Declared { value: inner, .. } = value {
1372 value = *inner;
1373 }
1374 value
1375 }
1376}
1377
1378fn declaration(value: &ConstructedValue) -> Option<&DeclaredType<()>> {
1379 match value {
1380 ConstructedValue::Declared { declaration, .. } => Some(declaration),
1381 _ => None,
1382 }
1383}
1384
1385fn underlying<K>(mut declaration: &DeclaredType<K>) -> &DeclaredType<K> {
1386 while let DeclaredType::Optional(child) = declaration {
1387 declaration = child;
1388 }
1389 declaration
1390}
1391
1392fn declared_facts(
1393 declaration: &DeclaredType<()>,
1394 budget: &mut Budget,
1395 location: &Location,
1396) -> Result<ValueType, QueryError> {
1397 budget.within_evaluation(1, location.clone(), |budget| {
1398 budget.charge(1, location.clone())?;
1399 Ok(match declaration {
1400 DeclaredType::Optional(child) => declared_facts(child, budget, location)?,
1401 DeclaredType::Boolean => ValueType::Boolean,
1402 DeclaredType::Integer => ValueType::Integer,
1403 DeclaredType::Float => ValueType::Float,
1404 DeclaredType::String => ValueType::String,
1405 DeclaredType::Member(id) => ValueType::Member(*id),
1406 DeclaredType::Set(element) => ValueType::Set(Some(*element)),
1407 DeclaredType::Array(child) => ValueType::ArrayKind(one_type(
1408 declared_fact(child, ValueType::Unestablished, budget, location)?,
1409 budget,
1410 location,
1411 )?),
1412 DeclaredType::Sequence(child) => ValueType::Array(ArrayType::Elements(one_type(
1413 declared_fact(child, ValueType::Unestablished, budget, location)?,
1414 budget,
1415 location,
1416 )?)),
1417 DeclaredType::Keyed(child) => ValueType::KeyedArray(KeyedArrayType {
1418 axes: None,
1419 elements: one_type(
1420 declared_fact(child, ValueType::Unestablished, budget, location)?,
1421 budget,
1422 location,
1423 )?,
1424 }),
1425 DeclaredType::Tuple(children) => {
1426 let mut fields = metadata_vec(children.len(), budget, location)?;
1427 for child in children {
1428 fields.push(declared_fact(
1429 child,
1430 ValueType::Unestablished,
1431 budget,
1432 location,
1433 )?);
1434 }
1435 ValueType::Tuple(fields)
1436 }
1437 DeclaredType::Record(children) => {
1438 let mut fields = metadata_vec(children.len(), budget, location)?;
1439 for (label, child) in children {
1440 budget.charge(label.len(), location.clone())?;
1441 fields.push((
1442 label.clone(),
1443 declared_fact(child, ValueType::Unestablished, budget, location)?,
1444 ));
1445 }
1446 ValueType::Record(fields)
1447 }
1448 DeclaredType::Native(()) | DeclaredType::Queue(_) | DeclaredType::IdentitySet(()) => {
1449 return Err(error(location, "native declaration requires a host"));
1450 }
1451 })
1452 })
1453}
1454
1455fn declared_fact(
1456 declaration: &DeclaredType<()>,
1457 actual: ValueType,
1458 budget: &mut Budget,
1459 location: &Location,
1460) -> Result<ValueType, QueryError> {
1461 budget.charge(1, location.clone())?;
1462 Ok(ValueType::Declared {
1463 actual: Box::new(actual),
1464 declaration: copy_declaration(declaration, budget, location)?,
1465 })
1466}
1467
1468fn shape_type(
1471 ty: ValueType,
1472 budget: &mut Budget,
1473 location: &Location,
1474) -> Result<ValueType, QueryError> {
1475 let ValueType::Declared {
1476 actual,
1477 declaration,
1478 } = ty
1479 else {
1480 return Ok(ty);
1481 };
1482 let actual = match *actual {
1483 ValueType::Unestablished => return declared_facts(&declaration, budget, location),
1484 ValueType::ScalarKind
1485 if matches!(
1486 underlying(&declaration),
1487 DeclaredType::Boolean
1488 | DeclaredType::Integer
1489 | DeclaredType::Float
1490 | DeclaredType::String
1491 ) =>
1492 {
1493 return declared_facts(&declaration, budget, location);
1494 }
1495 actual => shape_type(actual, budget, location)?,
1496 };
1497 Ok(match (actual, underlying(&declaration)) {
1498 (ValueType::Array(array), DeclaredType::Array(child) | DeclaredType::Sequence(child)) => {
1499 let positional = matches!(array, ArrayType::Positions(_));
1500 let (ArrayType::Positions(entries) | ArrayType::Elements(entries)) = array;
1501 let mut fields = metadata_vec(entries.len(), budget, location)?;
1502 for entry in entries {
1503 fields.push(declared_fact(child, entry, budget, location)?);
1504 }
1505 if fields.is_empty() {
1506 push_metadata(
1507 &mut fields,
1508 declared_fact(child, ValueType::Unestablished, budget, location)?,
1509 budget,
1510 location,
1511 )?;
1512 return Ok(ValueType::Array(ArrayType::Elements(fields)));
1513 }
1514 ValueType::Array(if positional {
1515 ArrayType::Positions(fields)
1516 } else {
1517 ArrayType::Elements(fields)
1518 })
1519 }
1520 (
1521 ValueType::KeyedArray(mut keyed),
1522 DeclaredType::Array(child) | DeclaredType::Keyed(child),
1523 ) => {
1524 let mut fields = metadata_vec(keyed.elements.len(), budget, location)?;
1525 for entry in keyed.elements {
1526 fields.push(declared_fact(child, entry, budget, location)?);
1527 }
1528 if fields.is_empty() {
1529 push_metadata(
1530 &mut fields,
1531 declared_fact(child, ValueType::Unestablished, budget, location)?,
1532 budget,
1533 location,
1534 )?;
1535 }
1536 keyed.elements = fields;
1537 ValueType::KeyedArray(keyed)
1538 }
1539 (ValueType::Tuple(entries), DeclaredType::Tuple(children)) => {
1540 let mut fields = metadata_vec(entries.len(), budget, location)?;
1541 for (entry, child) in entries.into_iter().zip(children) {
1542 fields.push(declared_fact(child, entry, budget, location)?);
1543 }
1544 ValueType::Tuple(fields)
1545 }
1546 (ValueType::Record(entries), DeclaredType::Record(children)) => {
1547 let mut fields = metadata_vec(entries.len(), budget, location)?;
1548 for (label, entry) in entries {
1549 let child = record_declaration(children, &label, budget, location)?;
1550 fields.push((label, declared_fact(child, entry, budget, location)?));
1551 }
1552 ValueType::Record(fields)
1553 }
1554 (actual, _) => actual,
1555 })
1556}
1557
1558fn record_declaration<'a, K>(
1559 fields: &'a [(String, DeclaredType<K>)],
1560 label: &str,
1561 budget: &mut Budget,
1562 location: &Location,
1563) -> Result<&'a DeclaredType<K>, QueryError> {
1564 for (candidate, declaration) in fields {
1565 budget.charge(1 + label.len().min(candidate.len()), location.clone())?;
1566 if label == candidate {
1567 return Ok(declaration);
1568 }
1569 }
1570 Err(error(location, "record label outside declared schema"))
1571}
1572
1573fn expose(
1574 value: ConstructedValue,
1575 budget: &mut Budget,
1576 location: &Location,
1577) -> Result<ConstructedValue, QueryError> {
1578 let ConstructedValue::Declared { value, declaration } = value else {
1579 return Ok(value);
1580 };
1581 let mut value = expose(*value, budget, location)?;
1582 match (&mut value, underlying(&declaration)) {
1583 (
1584 ConstructedValue::Array(values),
1585 DeclaredType::Array(child) | DeclaredType::Sequence(child),
1586 ) => {
1587 for value in values {
1588 annotate_child(value, child, budget, location)?;
1589 }
1590 }
1591 (ConstructedValue::Tuple(values), DeclaredType::Tuple(children)) => {
1592 for (value, child) in values.iter_mut().zip(children) {
1593 annotate_child(value, child, budget, location)?;
1594 }
1595 }
1596 (ConstructedValue::Record(values), DeclaredType::Record(children)) => {
1597 for (label, value) in values {
1598 annotate_child(
1599 value,
1600 record_declaration(children, label, budget, location)?,
1601 budget,
1602 location,
1603 )?;
1604 }
1605 }
1606 (
1607 ConstructedValue::KeyedArray { entries, .. },
1608 DeclaredType::Array(child) | DeclaredType::Keyed(child),
1609 ) => {
1610 for entry in entries {
1611 annotate_child(&mut entry.value, child, budget, location)?;
1612 }
1613 }
1614 _ => {}
1615 }
1616 Ok(value)
1617}
1618
1619fn annotate_child(
1620 value: &mut ConstructedValue,
1621 declaration: &DeclaredType<()>,
1622 budget: &mut Budget,
1623 location: &Location,
1624) -> Result<(), QueryError> {
1625 let declaration = copy_declaration(declaration, budget, location)?;
1626 let child = std::mem::replace(value, ConstructedValue::Absent);
1627 *value = annotate(child, declaration, budget, location)?;
1628 Ok(())
1629}
1630
1631fn shallow_type(
1632 value: &ConstructedValue,
1633 budget: &mut Budget,
1634 location: &Location,
1635) -> Result<ValueType, QueryError> {
1636 Ok(match value {
1637 ConstructedValue::Declared { declaration, .. } => {
1638 declared_fact(declaration, ValueType::Unestablished, budget, location)?
1639 }
1640 ConstructedValue::Absent => ValueType::Absent,
1641 ConstructedValue::Boolean(_) => ValueType::Boolean,
1642 ConstructedValue::Integer(_) => ValueType::Integer,
1643 ConstructedValue::Float(value) => {
1644 finite(*value, location)?;
1645 ValueType::Float
1646 }
1647 ConstructedValue::String(_) => ValueType::String,
1648 ConstructedValue::Member(member) => ValueType::Member(member.type_id),
1649 ConstructedValue::Array(_) => ValueType::Array(ArrayType::Elements(Vec::new())),
1650 ConstructedValue::Tuple(_) => ValueType::TupleKind,
1651 ConstructedValue::Record(_) => ValueType::RecordKind,
1652 ConstructedValue::Set { .. } => ValueType::Set(None),
1653 ConstructedValue::KeyedArray { .. } => ValueType::KeyedArray(KeyedArrayType {
1654 axes: None,
1655 elements: Vec::new(),
1656 }),
1657 })
1658}
1659
1660fn access_type(
1661 ty: ValueType,
1662 keys: &[ValueType],
1663 label: Option<&str>,
1664 optional: bool,
1665 budget: &mut Budget,
1666 location: &Location,
1667) -> Result<Vec<ValueType>, QueryError> {
1668 let mut child = None;
1669 if let ValueType::Declared { declaration, .. } = &ty {
1670 child = match underlying(declaration) {
1671 DeclaredType::Record(fields) => match label {
1672 Some(label) => Some(copy_declaration(
1673 record_declaration(fields, label, budget, location)?,
1674 budget,
1675 location,
1676 )?),
1677 None => None,
1678 },
1679 DeclaredType::Array(element)
1680 | DeclaredType::Sequence(element)
1681 | DeclaredType::Keyed(element) => Some(copy_declaration(element, budget, location)?),
1682 _ => None,
1683 };
1684 }
1685 let mut result = Vec::new();
1686 match shape_type(ty, budget, location)? {
1687 record @ (ValueType::RecordKind | ValueType::Record(_)) => {
1688 for key in keys {
1689 let key = shape_type(copy_type(key, budget, location)?, budget, location)?;
1690 if !matches!(
1691 key,
1692 ValueType::String | ValueType::ScalarKind | ValueType::Unestablished
1693 ) {
1694 return Err(error(location, "record lookup needs a string label"));
1695 }
1696 }
1697 if let ValueType::Record(fields) = record {
1698 for (candidate, ty) in fields {
1699 budget.charge(
1700 1 + label.map_or(0, |label| label.len().min(candidate.len())),
1701 location.clone(),
1702 )?;
1703 if label.is_none_or(|label| label == candidate) {
1704 push_metadata(&mut result, ty, budget, location)?;
1705 }
1706 }
1707 } else {
1708 push_metadata(&mut result, ValueType::Unestablished, budget, location)?;
1709 }
1710 }
1711 ValueType::Array(ArrayType::Positions(elements) | ArrayType::Elements(elements)) => {
1712 for key in keys {
1713 require_type(key, ScalarRequirement::Integer, location)?;
1714 }
1715 result = elements;
1716 }
1717 ValueType::ArrayKind(elements) => {
1718 let mut facts = None;
1719 merge_key_facts(&mut facts, keys, budget, location)?;
1720 result = elements;
1721 }
1722 ValueType::KeyedArray(keyed) => {
1723 let mut facts = None;
1724 merge_key_facts(&mut facts, keys, budget, location)?;
1725 if let Some(axes) = &keyed.axes {
1726 check_key_facts(&facts, axes, budget, location)?;
1727 }
1728 result = keyed.elements;
1729 }
1730 ValueType::Unestablished => {
1731 push_metadata(&mut result, ValueType::Unestablished, budget, location)?
1732 }
1733 _ => return Err(error(location, "lookup needs a record or array")),
1734 }
1735 if let Some(child) = child {
1736 return one_type(
1737 declared_fact(
1738 &if optional {
1739 DeclaredType::Optional(Box::new(child))
1740 } else {
1741 child
1742 },
1743 ValueType::Unestablished,
1744 budget,
1745 location,
1746 )?,
1747 budget,
1748 location,
1749 );
1750 }
1751 if optional {
1752 push_metadata(&mut result, ValueType::Absent, budget, location)?;
1753 }
1754 Ok(result)
1755}
1756
1757fn access_declaration<'a, K>(
1758 declaration: &'a DeclaredType<K>,
1759 key: &ConstructedValue,
1760 budget: &mut Budget,
1761 location: &Location,
1762) -> Result<Option<&'a DeclaredType<K>>, QueryError> {
1763 Ok(match underlying(declaration) {
1764 DeclaredType::Record(fields) => {
1765 let ConstructedValue::String(label) = key.data() else {
1766 return Err(error(location, "record lookup needs a string label"));
1767 };
1768 Some(record_declaration(fields, label, budget, location)?)
1769 }
1770 DeclaredType::Array(child) | DeclaredType::Sequence(child) | DeclaredType::Keyed(child) => {
1771 Some(child)
1772 }
1773 _ => None,
1774 })
1775}
1776
1777fn optional_position(
1778 value: &ConstructedValue,
1779 key: ConstructedValue,
1780 budget: &mut Budget,
1781 location: &Location,
1782) -> Result<Option<usize>, QueryError> {
1783 match value.data() {
1784 ConstructedValue::Record(fields) => {
1785 let ConstructedValue::String(label) = key.into_data() else {
1786 return Err(error(location, "record lookup needs a string label"));
1787 };
1788 for (index, (candidate, _)) in fields.iter().enumerate() {
1789 budget.charge(1 + label.len().min(candidate.len()), location.clone())?;
1790 if label == *candidate {
1791 return Ok(Some(index));
1792 }
1793 }
1794 Ok(None)
1795 }
1796 ConstructedValue::Array(values) => {
1797 let position = integer(key, location)?;
1798 budget.charge(1, location.clone())?;
1799 Ok(usize::try_from(position)
1800 .ok()
1801 .and_then(|position| position.checked_sub(1))
1802 .filter(|&index| index < values.len()))
1803 }
1804 ConstructedValue::KeyedArray { axes, entries } => {
1805 let key = value_keys(key.into_data(), budget, location)?;
1806 if key.len() != axes.len() {
1807 return Err(error(location, "key rank mismatch"));
1808 }
1809 for (component, axis) in key.iter().zip(axes) {
1810 budget.charge(1, location.clone())?;
1811 if key_type(component) != axis.key_type {
1812 return Err(error(location, "incompatible key type"));
1813 }
1814 for candidate in &axis.keys {
1816 compare_keys(component, candidate, budget, location)?;
1817 }
1818 }
1819 for (index, entry) in entries.iter().enumerate() {
1820 budget.charge(1, location.clone())?;
1821 if equal_keys(&key, &entry.key, budget, location)? {
1822 return Ok(Some(index));
1823 }
1824 }
1825 Ok(None)
1826 }
1827 _ => Err(error(location, "lookup needs a record or array")),
1828 }
1829}
1830
1831fn error(location: &Location, message: impl Into<String>) -> QueryError {
1832 QueryError {
1833 location: location.clone(),
1834 message: message.into(),
1835 category: QueryErrorCategory::Other,
1836 }
1837}
1838
1839fn admit_diagnostic(
1842 prefix: &str,
1843 value: &str,
1844 budget: &mut Budget,
1845 location: &Location,
1846) -> Result<(), QueryError> {
1847 let len = sum(prefix.len(), value.len(), location)?;
1848 allocation::<u8>(len, location)?;
1849 budget.charge(len, location.clone())
1850}
1851
1852fn sum(a: usize, b: usize, location: &Location) -> Result<usize, QueryError> {
1853 a.checked_add(b)
1854 .ok_or_else(|| error(location, "allocation size overflow"))
1855}
1856
1857pub(crate) fn allocation<T>(len: usize, location: &Location) -> Result<(), QueryError> {
1858 if len
1859 .checked_mul(size_of::<T>())
1860 .is_none_or(|size| size > isize::MAX as usize)
1861 {
1862 return Err(error(location, "allocation size overflow"));
1863 }
1864 Ok(())
1865}
1866
1867fn metadata_vec<T>(
1868 len: usize,
1869 budget: &mut Budget,
1870 location: &Location,
1871) -> Result<Vec<T>, QueryError> {
1872 allocation::<T>(len, location)?;
1873 budget.charge(len, location.clone())?;
1874 Ok(Vec::with_capacity(len))
1875}
1876
1877fn push_metadata<T>(
1878 values: &mut Vec<T>,
1879 value: T,
1880 budget: &mut Budget,
1881 location: &Location,
1882) -> Result<(), QueryError> {
1883 allocation::<T>(sum(values.len(), 1, location)?, location)?;
1884 budget.charge(1, location.clone())?;
1885 values.push(value);
1886 Ok(())
1887}
1888
1889fn admit_container<T>(
1890 len: usize,
1891 budget: &mut Budget,
1892 location: &Location,
1893) -> Result<Vec<T>, QueryError> {
1894 allocation::<T>(len, location)?;
1895 budget.charge(sum(len, 1, location)?, location.clone())?;
1896 budget.charge_results(sum(len, 1, location)?, location.clone())?;
1897 Ok(Vec::with_capacity(len))
1898}
1899
1900fn finite(value: f64, location: &Location) -> Result<(), QueryError> {
1901 if !value.is_finite() {
1902 return Err(error(location, "nonfinite float"));
1903 }
1904 Ok(())
1905}
1906
1907fn member_bytes(
1908 member: &NominalMember,
1909 budget: &mut Budget,
1910 location: &Location,
1911) -> Result<usize, QueryError> {
1912 allocation::<u8>(member.type_name.len(), location)?;
1913 allocation::<u8>(member.member_name.len(), location)?;
1914 let bytes = sum(member.type_name.len(), member.member_name.len(), location)?;
1915 budget.charge(sum(1, bytes, location)?, location.clone())?;
1916 Ok(bytes)
1917}
1918
1919pub(crate) fn check_member_pair(
1920 left: &NominalMember,
1921 right: &NominalMember,
1922 budget: &mut Budget,
1923 location: &Location,
1924) -> Result<(), QueryError> {
1925 budget.charge(1, location.clone())?;
1926 if left.type_id != right.type_id {
1927 return Ok(());
1928 }
1929 budget.charge(
1930 left.type_name.len().min(right.type_name.len()),
1931 location.clone(),
1932 )?;
1933 if left.type_name != right.type_name {
1934 return Err(error(location, "inconsistent nominal type name"));
1935 }
1936 if left.member_id == right.member_id {
1937 budget.charge(
1938 left.member_name.len().min(right.member_name.len()),
1939 location.clone(),
1940 )?;
1941 if left.declaration_order != right.declaration_order
1942 || left.member_name != right.member_name
1943 {
1944 return Err(error(location, "inconsistent nominal member metadata"));
1945 }
1946 } else if left.declaration_order == right.declaration_order {
1947 return Err(error(
1948 location,
1949 "distinct nominal members share declaration order",
1950 ));
1951 }
1952 Ok(())
1953}
1954
1955fn copy_member_admitted(member: &NominalMember) -> NominalMember {
1956 NominalMember {
1957 type_id: member.type_id,
1958 member_id: member.member_id,
1959 declaration_order: member.declaration_order,
1960 type_name: member.type_name.to_owned(),
1961 member_name: member.member_name.to_owned(),
1962 }
1963}
1964
1965fn key_value(key: ValueKey) -> ConstructedValue {
1966 match key {
1967 ValueKey::Integer(value) => ConstructedValue::Integer(value),
1968 ValueKey::Member(member) => ConstructedValue::Member(member),
1969 }
1970}
1971
1972fn key_type(key: &ValueKey) -> ValueKeyType {
1973 match key {
1974 ValueKey::Integer(_) => ValueKeyType::Integer,
1975 ValueKey::Member(member) => ValueKeyType::Member(member.type_id),
1976 }
1977}
1978
1979fn key_set_type(ty: ValueKeyType) -> SetElementType {
1980 match ty {
1981 ValueKeyType::Integer => SetElementType::Integer,
1982 ValueKeyType::Member(id) => SetElementType::Member(id),
1983 }
1984}
1985
1986fn compare_keys(
1987 left: &ValueKey,
1988 right: &ValueKey,
1989 budget: &mut Budget,
1990 location: &Location,
1991) -> Result<Ordering, QueryError> {
1992 budget.charge(1, location.clone())?;
1993 match (left, right) {
1994 (ValueKey::Integer(a), ValueKey::Integer(b)) => Ok(a.cmp(b)),
1995 (ValueKey::Member(a), ValueKey::Member(b)) if a.type_id == b.type_id => {
1996 check_member_pair(a, b, budget, location)?;
1997 Ok(if a.member_id == b.member_id {
1998 Ordering::Equal
1999 } else {
2000 a.declaration_order.cmp(&b.declaration_order)
2001 })
2002 }
2003 _ => Err(error(location, "incompatible keyed dimension type")),
2004 }
2005}
2006
2007fn keys_size(
2008 keys: &[ValueKey],
2009 budget: &mut Budget,
2010 location: &Location,
2011) -> Result<(usize, usize), QueryError> {
2012 allocation::<ValueKey>(keys.len(), location)?;
2013 let units = keys
2014 .len()
2015 .checked_mul(2)
2016 .ok_or_else(|| error(location, "key size overflow"))?;
2017 let mut bytes = 0;
2018 for key in keys {
2019 budget.charge(1, location.clone())?;
2020 if let ValueKey::Member(member) = key {
2021 bytes = sum(bytes, member_bytes(member, budget, location)?, location)?;
2022 }
2023 }
2024 Ok((units, bytes))
2025}
2026
2027fn copy_keys_admitted(
2028 keys: &[ValueKey],
2029 budget: &mut Budget,
2030 location: &Location,
2031) -> Result<Vec<ValueKey>, QueryError> {
2032 let mut copied = Vec::with_capacity(keys.len());
2033 for key in keys {
2034 budget.charge(1, location.clone())?;
2035 copied.push(match key {
2036 ValueKey::Integer(value) => ValueKey::Integer(*value),
2037 ValueKey::Member(member) => ValueKey::Member(copy_member_admitted(member)),
2038 });
2039 }
2040 Ok(copied)
2041}
2042
2043fn copy_key(
2044 key: &ValueKey,
2045 budget: &mut Budget,
2046 location: &Location,
2047) -> Result<ValueKey, QueryError> {
2048 budget.charge(1, location.clone())?;
2049 budget.charge_results(1, location.clone())?;
2050 Ok(match key {
2051 ValueKey::Integer(value) => ValueKey::Integer(*value),
2052 ValueKey::Member(member) => {
2053 let bytes = member_bytes(member, budget, location)?;
2054 budget.charge(bytes, location.clone())?;
2055 ValueKey::Member(copy_member_admitted(member))
2056 }
2057 })
2058}
2059
2060fn check_axes(
2061 axes: &[KeyAxis],
2062 budget: &mut Budget,
2063 location: &Location,
2064) -> Result<(), QueryError> {
2065 if axes.is_empty() {
2066 return Err(error(
2067 location,
2068 "keyed arrays need nonzero rank and established axes",
2069 ));
2070 }
2071 for axis in axes {
2072 budget.charge(1, location.clone())?;
2073 for (index, key) in axis.keys.iter().enumerate() {
2074 budget.charge(1, location.clone())?;
2075 if key_type(key) != axis.key_type {
2076 return Err(error(location, "axis key type mismatch"));
2077 }
2078 if let ValueKey::Member(member) = key {
2079 member_bytes(member, budget, location)?;
2080 }
2081 for previous in &axis.keys[..index] {
2082 if compare_keys(previous, key, budget, location)? == Ordering::Equal {
2083 return Err(error(location, "duplicate axis key"));
2084 }
2085 }
2086 }
2087 }
2088 let members = axes
2089 .iter()
2090 .flat_map(|axis| &axis.keys)
2091 .filter_map(|key| match key {
2092 ValueKey::Member(member) => Some(member),
2093 ValueKey::Integer(_) => None,
2094 });
2095 for (index, member) in members.clone().enumerate() {
2096 for previous in members.clone().take(index) {
2097 check_member_pair(previous, member, budget, location)?;
2098 }
2099 }
2100 Ok(())
2101}
2102
2103fn copy_axes(
2104 axes: &[KeyAxis],
2105 budget: &mut Budget,
2106 location: &Location,
2107) -> Result<Vec<KeyAxis>, QueryError> {
2108 check_axes(axes, budget, location)?;
2109 allocation::<KeyAxis>(axes.len(), location)?;
2110 budget.charge(axes.len(), location.clone())?;
2111 budget.charge_results(axes.len(), location.clone())?;
2112 let mut copied = Vec::with_capacity(axes.len());
2113 for axis in axes {
2114 let (units, bytes) = keys_size(&axis.keys, budget, location)?;
2115 budget.charge(bytes, location.clone())?;
2116 budget.charge_results(units, location.clone())?;
2117 copied.push(KeyAxis {
2118 key_type: axis.key_type,
2119 keys: copy_keys_admitted(&axis.keys, budget, location)?,
2120 });
2121 }
2122 Ok(copied)
2123}
2124
2125fn copy_axis_types(
2126 types: &[ValueKeyType],
2127 budget: &mut Budget,
2128 location: &Location,
2129) -> Result<Vec<ValueKeyType>, QueryError> {
2130 if types.is_empty() {
2131 return Err(error(location, "keyed arrays need nonzero rank"));
2132 }
2133 let mut copied = metadata_vec(types.len(), budget, location)?;
2134 for ty in types {
2135 budget.charge(1, location.clone())?;
2136 copied.push(*ty);
2137 }
2138 Ok(copied)
2139}
2140
2141fn axis_types(
2142 axes: &[KeyAxis],
2143 budget: &mut Budget,
2144 location: &Location,
2145) -> Result<Vec<ValueKeyType>, QueryError> {
2146 let mut types = metadata_vec(axes.len(), budget, location)?;
2147 for axis in axes {
2148 budget.charge(1, location.clone())?;
2149 types.push(axis.key_type);
2150 }
2151 Ok(types)
2152}
2153
2154fn same_axis_types(
2155 left: &[ValueKeyType],
2156 right: &[ValueKeyType],
2157 budget: &mut Budget,
2158 location: &Location,
2159) -> Result<bool, QueryError> {
2160 budget.charge(1, location.clone())?;
2161 if left.len() != right.len() {
2162 return Ok(false);
2163 }
2164 for (a, b) in left.iter().zip(right) {
2165 budget.charge(1, location.clone())?;
2166 if a != b {
2167 return Ok(false);
2168 }
2169 }
2170 Ok(true)
2171}
2172
2173fn key_positions(
2174 key: &[ValueKey],
2175 axes: &[KeyAxis],
2176 budget: &mut Budget,
2177 location: &Location,
2178) -> Result<Vec<usize>, QueryError> {
2179 if key.len() != axes.len() {
2180 return Err(error(location, "key rank mismatch"));
2181 }
2182 let mut positions = metadata_vec(key.len(), budget, location)?;
2183 for (key, axis) in key.iter().zip(axes) {
2184 budget.charge(1, location.clone())?;
2185 if key_type(key) != axis.key_type {
2186 return Err(error(location, "incompatible keyed dimension type"));
2187 }
2188 let mut position = None;
2189 for (index, existing) in axis.keys.iter().enumerate() {
2191 if compare_keys(key, existing, budget, location)? == Ordering::Equal {
2192 position = Some(index);
2193 }
2194 }
2195 positions
2196 .push(position.ok_or_else(|| error(location, "key is absent from established axis"))?);
2197 }
2198 Ok(positions)
2199}
2200
2201fn compare_positions(
2202 left: &[usize],
2203 right: &[usize],
2204 budget: &mut Budget,
2205 location: &Location,
2206) -> Result<Ordering, QueryError> {
2207 for (a, b) in left.iter().zip(right) {
2208 budget.charge(1, location.clone())?;
2209 let order = a.cmp(b);
2210 if order != Ordering::Equal {
2211 return Ok(order);
2212 }
2213 }
2214 Ok(Ordering::Equal)
2215}
2216
2217fn equal_keys(
2218 left: &[ValueKey],
2219 right: &[ValueKey],
2220 budget: &mut Budget,
2221 location: &Location,
2222) -> Result<bool, QueryError> {
2223 budget.charge(1, location.clone())?;
2224 if left.len() != right.len() {
2225 return Ok(false);
2226 }
2227 for (a, b) in left.iter().zip(right) {
2228 if compare_keys(a, b, budget, location)? != Ordering::Equal {
2229 return Ok(false);
2230 }
2231 }
2232 Ok(true)
2233}
2234
2235fn check_keyed(
2236 axes: &[KeyAxis],
2237 entries: &[KeyedEntry],
2238 budget: &mut Budget,
2239 location: &Location,
2240) -> Result<(), QueryError> {
2241 check_axes(axes, budget, location)?;
2242 let mut previous: Option<Vec<usize>> = None;
2243 for entry in entries {
2244 budget.charge(1, location.clone())?;
2245 let positions = key_positions(&entry.key, axes, budget, location)?;
2246 if let Some(previous) = previous
2247 && compare_positions(&previous, &positions, budget, location)? != Ordering::Less
2248 {
2249 return Err(error(
2250 location,
2251 "keyed entries must be unique and in row-major order",
2252 ));
2253 }
2254 previous = Some(positions);
2255 }
2256 let members = axes
2257 .iter()
2258 .flat_map(|axis| &axis.keys)
2259 .chain(entries.iter().flat_map(|entry| &entry.key))
2260 .filter_map(|key| match key {
2261 ValueKey::Member(member) => Some(member),
2262 ValueKey::Integer(_) => None,
2263 });
2264 for (index, member) in members.clone().enumerate() {
2265 for previous in members.clone().take(index) {
2266 check_member_pair(previous, member, budget, location)?;
2267 }
2268 }
2269 Ok(())
2270}
2271
2272fn value_keys(
2273 value: ConstructedValue,
2274 budget: &mut Budget,
2275 location: &Location,
2276) -> Result<Vec<ValueKey>, QueryError> {
2277 let value = expose(value, budget, location)?;
2278 let values = match value {
2279 ConstructedValue::Tuple(values) if !values.is_empty() => values,
2280 value @ (ConstructedValue::Integer(_) | ConstructedValue::Member(_)) => {
2281 let mut values = metadata_vec(1, budget, location)?;
2282 values.push(value);
2283 values
2284 }
2285 _ => {
2286 return Err(error(
2287 location,
2288 "key needs an integer, member or nonempty flat tuple",
2289 ));
2290 }
2291 };
2292 allocation::<ValueKey>(values.len(), location)?;
2293 budget.charge(values.len(), location.clone())?;
2294 budget.charge_results(values.len(), location.clone())?;
2295 let mut keys = Vec::with_capacity(values.len());
2296 for value in values {
2297 budget.charge(1, location.clone())?;
2298 keys.push(match value.into_data() {
2299 ConstructedValue::Integer(value) => ValueKey::Integer(value),
2300 ConstructedValue::Member(member) => ValueKey::Member(member),
2301 _ => return Err(error(location, "key components need integers or members")),
2302 });
2303 }
2304 Ok(keys)
2305}
2306
2307fn infer_axes(
2308 entries: &[Located<KeyedEntry>],
2309 budget: &mut Budget,
2310 location: &Location,
2311) -> Result<Vec<KeyAxis>, QueryError> {
2312 let Some(first) = entries.first() else {
2313 return Err(error(location, "unestablished empty keyed axes"));
2314 };
2315 if first.value.key.is_empty() {
2316 return Err(error(location, "keyed arrays need nonzero rank"));
2317 }
2318 allocation::<KeyAxis>(first.value.key.len(), location)?;
2319 budget.charge(first.value.key.len(), location.clone())?;
2320 budget.charge_results(first.value.key.len(), location.clone())?;
2321 let mut axes = Vec::with_capacity(first.value.key.len());
2322 for key in &first.value.key {
2323 axes.push(KeyAxis {
2324 key_type: key_type(key),
2325 keys: Vec::new(),
2326 });
2327 }
2328 for entry in entries {
2329 let key_location = Location::Query(entry.range.clone());
2330 if entry.value.key.len() != axes.len() {
2331 return Err(error(&key_location, "key rank mismatch"));
2332 }
2333 for (key, axis) in entry.value.key.iter().zip(&mut axes) {
2334 if key_type(key) != axis.key_type {
2335 return Err(error(&key_location, "incompatible keyed dimension type"));
2336 }
2337 let mut position = axis.keys.len();
2338 let mut found = false;
2339 for (index, existing) in axis.keys.iter().enumerate() {
2340 match compare_keys(key, existing, budget, &key_location)? {
2341 Ordering::Equal => found = true,
2342 Ordering::Less if position == axis.keys.len() => position = index,
2343 _ => {}
2344 }
2345 }
2346 if !found {
2347 let key = copy_key(key, budget, &key_location)?;
2348 allocation::<ValueKey>(sum(axis.keys.len(), 1, &key_location)?, &key_location)?;
2349 budget.charge(
2350 sum(1, axis.keys.len() - position, &key_location)?,
2351 key_location.clone(),
2352 )?;
2353 budget.charge_results(1, key_location.clone())?;
2354 axis.keys.insert(position, key);
2355 }
2356 }
2357 }
2358 Ok(axes)
2359}
2360
2361fn finish_keyed(
2362 axes: Option<Vec<KeyAxis>>,
2363 mut entries: Vec<Located<KeyedEntry>>,
2364 budget: &mut Budget,
2365 location: &Location,
2366) -> Result<ConstructedValue, QueryError> {
2367 let axes = match axes {
2368 Some(axes) => {
2369 check_axes(&axes, budget, location)?;
2370 axes
2371 }
2372 None => infer_axes(&entries, budget, location)?,
2373 };
2374 let mut positions = metadata_vec(entries.len(), budget, location)?;
2375 for entry in &entries {
2376 positions.push(key_positions(
2377 &entry.value.key,
2378 &axes,
2379 budget,
2380 &Location::Query(entry.range.clone()),
2381 )?);
2382 }
2383 for index in 1..entries.len() {
2386 let mut cursor = index;
2387 while cursor > 0 {
2388 let key_location = Location::Query(entries[cursor].range.clone());
2389 match compare_positions(
2390 &positions[cursor - 1],
2391 &positions[cursor],
2392 budget,
2393 &key_location,
2394 )? {
2395 Ordering::Equal => return Err(error(&key_location, "duplicate full key")),
2396 Ordering::Less => break,
2397 Ordering::Greater => {
2398 budget.charge(2, key_location)?;
2399 entries.swap(cursor - 1, cursor);
2400 positions.swap(cursor - 1, cursor);
2401 cursor -= 1;
2402 }
2403 }
2404 }
2405 }
2406 let mut values = metadata_vec(entries.len(), budget, location)?;
2407 for entry in entries {
2408 values.push(entry.value);
2409 }
2410 check_keyed(&axes, &values, budget, location)?;
2411 Ok(ConstructedValue::KeyedArray {
2412 axes,
2413 entries: values,
2414 })
2415}
2416
2417fn source_axis(
2418 value: ConstructedValue,
2419 budget: &mut Budget,
2420 location: &Location,
2421) -> Result<KeyAxis, QueryError> {
2422 let empty = match value.data() {
2423 ConstructedValue::Array(values)
2424 | ConstructedValue::Set {
2425 elements: values, ..
2426 } => values.is_empty(),
2427 ConstructedValue::KeyedArray { entries, .. } => entries.is_empty(),
2428 _ => false,
2429 };
2430 let declared = if empty && let Some(declaration) = declaration(&value) {
2431 let facts = declared_facts(declaration, budget, location)?;
2432 source_key_type(std::slice::from_ref(&facts), budget, location)?
2433 } else {
2434 None
2435 };
2436 let value = expose(value, budget, location)?;
2437 let (declared, values) = match value {
2438 ConstructedValue::Array(values) => (declared, values),
2439 ConstructedValue::KeyedArray { entries, .. } => {
2440 let mut values = metadata_vec(entries.len(), budget, location)?;
2441 for entry in entries {
2442 budget.charge(1, location.clone())?;
2443 values.push(entry.value);
2444 }
2445 (declared, values)
2446 }
2447 ConstructedValue::Set {
2448 element_type,
2449 elements,
2450 } => {
2451 let ty = match element_type {
2452 Some(SetElementType::Integer) => Some(ValueKeyType::Integer),
2453 Some(SetElementType::Member(id)) => Some(ValueKeyType::Member(id)),
2454 _ => None,
2455 };
2456 (ty.or(declared), elements)
2457 }
2458 _ => {
2459 return Err(error(
2460 location,
2461 "axis source needs an integer or member array/set",
2462 ));
2463 }
2464 };
2465 allocation::<ValueKey>(values.len(), location)?;
2468 budget.charge(values.len(), location.clone())?;
2469 budget.charge_results(values.len(), location.clone())?;
2470 let mut keys = Vec::with_capacity(values.len());
2471 let mut ty = declared;
2472 for value in values {
2473 budget.charge(1, location.clone())?;
2474 let key = match value.into_data() {
2475 ConstructedValue::Integer(value) => ValueKey::Integer(value),
2476 ConstructedValue::Member(member) => ValueKey::Member(member),
2477 _ => {
2478 return Err(error(
2479 location,
2480 "axis source needs integer or member elements",
2481 ));
2482 }
2483 };
2484 if ty.is_some_and(|ty| ty != key_type(&key)) {
2485 return Err(error(location, "incompatible axis source type"));
2486 }
2487 ty = Some(key_type(&key));
2488 keys.push(key);
2489 }
2490 let axis = KeyAxis {
2491 key_type: ty.ok_or_else(|| error(location, "unestablished empty keyed axis"))?,
2492 keys,
2493 };
2494 check_axes(std::slice::from_ref(&axis), budget, location)?;
2495 Ok(axis)
2496}
2497
2498fn scalar_set_type(value: &ConstructedValue) -> Option<SetElementType> {
2499 match value.data() {
2500 ConstructedValue::Boolean(_) => Some(SetElementType::Boolean),
2501 ConstructedValue::Integer(_) => Some(SetElementType::Integer),
2502 ConstructedValue::Float(_) => Some(SetElementType::Float),
2503 ConstructedValue::Member(member) => Some(SetElementType::Member(member.type_id)),
2504 _ => None,
2505 }
2506}
2507
2508fn compare_set_values(
2509 left: &ConstructedValue,
2510 right: &ConstructedValue,
2511 budget: &mut Budget,
2512 location: &Location,
2513) -> Result<Ordering, QueryError> {
2514 budget.charge(1, location.clone())?;
2515 match (left.data(), right.data()) {
2516 (ConstructedValue::Boolean(a), ConstructedValue::Boolean(b)) => Ok(a.cmp(b)),
2517 (ConstructedValue::Integer(a), ConstructedValue::Integer(b)) => Ok(a.cmp(b)),
2518 (ConstructedValue::Float(a), ConstructedValue::Float(b)) => {
2519 finite(*a, location)?;
2520 finite(*b, location)?;
2521 Ok(a.partial_cmp(b).expect("finite floats are ordered"))
2522 }
2523 (ConstructedValue::Member(a), ConstructedValue::Member(b)) => {
2524 check_member_pair(a, b, budget, location)?;
2525 if a.type_id != b.type_id {
2526 return Err(error(location, "incompatible nominal types"));
2527 }
2528 Ok(if a.member_id == b.member_id {
2529 Ordering::Equal
2530 } else {
2531 a.declaration_order.cmp(&b.declaration_order)
2532 })
2533 }
2534 _ => Err(error(
2535 location,
2536 "set elements must have one supported scalar type",
2537 )),
2538 }
2539}
2540
2541fn check_set(
2542 element_type: Option<SetElementType>,
2543 elements: &[ConstructedValue],
2544 budget: &mut Budget,
2545 location: &Location,
2546) -> Result<(), QueryError> {
2547 if element_type.is_none() && !elements.is_empty() {
2548 return Err(error(location, "a nonempty set needs its element type"));
2549 }
2550 for (index, value) in elements.iter().enumerate() {
2551 budget.charge(1, location.clone())?;
2552 if scalar_set_type(value) != element_type {
2553 return Err(error(location, "set element type mismatch"));
2554 }
2555 match value.data() {
2556 ConstructedValue::Float(value) => finite(*value, location)?,
2557 ConstructedValue::Member(member) => {
2558 member_bytes(member, budget, location)?;
2559 }
2560 _ => {}
2561 }
2562 for previous in &elements[..index] {
2563 if compare_set_values(previous, value, budget, location)? == Ordering::Equal {
2564 return Err(error(location, "set elements must be unique"));
2565 }
2566 }
2567 }
2568 Ok(())
2569}
2570
2571fn check_value_labels<T>(
2572 fields: &[(String, T)],
2573 budget: &mut Budget,
2574 location: &Location,
2575) -> Result<(), QueryError> {
2576 for (index, (label, _)) in fields.iter().enumerate() {
2577 for (previous, _) in &fields[..index] {
2578 budget.charge(
2579 sum(1, label.len().min(previous.len()), location)?,
2580 location.clone(),
2581 )?;
2582 if label == previous {
2583 return Err(error(location, "duplicate record label"));
2584 }
2585 }
2586 }
2587 Ok(())
2588}
2589
2590fn copy_size(
2591 value: &ConstructedValue,
2592 budget: &mut Budget,
2593 location: &Location,
2594) -> Result<(usize, usize), QueryError> {
2595 budget.within_evaluation(1, location.clone(), |budget| {
2596 budget.charge(1, location.clone())?;
2597 let mut units = 1;
2598 let mut bytes = 0;
2599 match value {
2600 ConstructedValue::Absent
2601 | ConstructedValue::Boolean(_)
2602 | ConstructedValue::Integer(_) => {}
2603 ConstructedValue::Declared { value, declaration } => {
2604 crate::admit_constructed(value, declaration, budget, location.clone())?;
2605 let (child_units, child_bytes) = copy_size(value, budget, location)?;
2606 units = sum(units, child_units, location)?;
2607 bytes = child_bytes;
2608 }
2610 ConstructedValue::Float(value) => finite(*value, location)?,
2611 ConstructedValue::Member(member) => {
2612 bytes = member_bytes(member, budget, location)?;
2613 }
2614 ConstructedValue::KeyedArray { axes, entries } => {
2615 check_keyed(axes, entries, budget, location)?;
2616 allocation::<KeyAxis>(axes.len(), location)?;
2617 allocation::<KeyedEntry>(entries.len(), location)?;
2618 units = sum(units, sum(axes.len(), entries.len(), location)?, location)?;
2619 for axis in axes {
2620 let (key_units, key_bytes) = keys_size(&axis.keys, budget, location)?;
2621 units = sum(units, key_units, location)?;
2622 bytes = sum(bytes, key_bytes, location)?;
2623 }
2624 for entry in entries {
2625 let (key_units, key_bytes) = keys_size(&entry.key, budget, location)?;
2626 let (child_units, child_bytes) = copy_size(&entry.value, budget, location)?;
2627 units = sum(units, sum(key_units, child_units, location)?, location)?;
2628 bytes = sum(bytes, sum(key_bytes, child_bytes, location)?, location)?;
2629 }
2630 }
2631 ConstructedValue::String(value) => {
2632 allocation::<u8>(value.len(), location)?;
2633 bytes = value.len();
2634 }
2635 ConstructedValue::Array(values)
2636 | ConstructedValue::Tuple(values)
2637 | ConstructedValue::Set {
2638 elements: values, ..
2639 } => {
2640 allocation::<ConstructedValue>(values.len(), location)?;
2641 if let ConstructedValue::Set { element_type, .. } = value {
2642 check_set(*element_type, values, budget, location)?;
2643 }
2644 units = sum(units, values.len(), location)?;
2645 for value in values {
2646 let (child_units, child_bytes) = copy_size(value, budget, location)?;
2647 units = sum(units, child_units, location)?;
2648 bytes = sum(bytes, child_bytes, location)?;
2649 }
2650 }
2651 ConstructedValue::Record(fields) => {
2652 allocation::<(String, ConstructedValue)>(fields.len(), location)?;
2653 check_value_labels(fields, budget, location)?;
2654 units = sum(units, fields.len(), location)?;
2655 for (label, value) in fields {
2656 allocation::<u8>(label.len(), location)?;
2657 let (child_units, child_bytes) = copy_size(value, budget, location)?;
2658 units = sum(units, child_units, location)?;
2659 bytes = sum(bytes, sum(label.len(), child_bytes, location)?, location)?;
2660 }
2661 }
2662 }
2663 Ok((units, bytes))
2664 })
2665}
2666
2667fn copy_admitted(
2668 value: &ConstructedValue,
2669 budget: &mut Budget,
2670 location: &Location,
2671) -> Result<ConstructedValue, QueryError> {
2672 budget.within_evaluation(1, location.clone(), |budget| {
2673 budget.charge(1, location.clone())?;
2674 Ok(match value {
2675 ConstructedValue::Absent => ConstructedValue::Absent,
2676 ConstructedValue::Declared { value, declaration } => ConstructedValue::Declared {
2677 value: Box::new(copy_admitted(value, budget, location)?),
2678 declaration: copy_declaration(declaration, budget, location)?,
2679 },
2680 ConstructedValue::Boolean(value) => ConstructedValue::Boolean(*value),
2681 ConstructedValue::Integer(value) => ConstructedValue::Integer(*value),
2682 ConstructedValue::Float(value) => ConstructedValue::Float(*value),
2683 ConstructedValue::String(value) => ConstructedValue::String(value.to_owned()),
2684 ConstructedValue::Member(member) => {
2685 ConstructedValue::Member(copy_member_admitted(member))
2686 }
2687 ConstructedValue::KeyedArray { axes, entries } => {
2688 let mut copied_axes = Vec::with_capacity(axes.len());
2689 for axis in axes {
2690 budget.charge(1, location.clone())?;
2691 copied_axes.push(KeyAxis {
2692 key_type: axis.key_type,
2693 keys: copy_keys_admitted(&axis.keys, budget, location)?,
2694 });
2695 }
2696 let mut copied_entries = Vec::with_capacity(entries.len());
2697 for entry in entries {
2698 budget.charge(1, location.clone())?;
2699 copied_entries.push(KeyedEntry {
2700 key: copy_keys_admitted(&entry.key, budget, location)?,
2701 value: copy_admitted(&entry.value, budget, location)?,
2702 });
2703 }
2704 ConstructedValue::KeyedArray {
2705 axes: copied_axes,
2706 entries: copied_entries,
2707 }
2708 }
2709 ConstructedValue::Array(values)
2710 | ConstructedValue::Tuple(values)
2711 | ConstructedValue::Set {
2712 elements: values, ..
2713 } => {
2714 let mut copied = Vec::with_capacity(values.len());
2715 for value in values {
2716 copied.push(copy_admitted(value, budget, location)?);
2717 }
2718 match value {
2719 ConstructedValue::Array(_) => ConstructedValue::Array(copied),
2720 ConstructedValue::Tuple(_) => ConstructedValue::Tuple(copied),
2721 ConstructedValue::Set { element_type, .. } => ConstructedValue::Set {
2722 element_type: *element_type,
2723 elements: copied,
2724 },
2725 _ => unreachable!("matched collection"),
2726 }
2727 }
2728 ConstructedValue::Record(fields) => {
2729 let mut copied = Vec::with_capacity(fields.len());
2730 for (label, value) in fields {
2731 copied.push((label.to_owned(), copy_admitted(value, budget, location)?));
2732 }
2733 ConstructedValue::Record(copied)
2734 }
2735 })
2736 })
2737}
2738
2739fn copy_type(
2740 ty: &ValueType,
2741 budget: &mut Budget,
2742 location: &Location,
2743) -> Result<ValueType, QueryError> {
2744 budget.within_evaluation(1, location.clone(), |budget| {
2745 budget.charge(1, location.clone())?;
2746 Ok(match ty {
2747 ValueType::Absent => ValueType::Absent,
2748 ValueType::Declared {
2749 actual,
2750 declaration,
2751 } => ValueType::Declared {
2752 actual: Box::new(copy_type(actual, budget, location)?),
2753 declaration: copy_declaration(declaration, budget, location)?,
2754 },
2755 ValueType::ScalarKind => ValueType::ScalarKind,
2756 ValueType::Boolean => ValueType::Boolean,
2757 ValueType::Integer => ValueType::Integer,
2758 ValueType::Float => ValueType::Float,
2759 ValueType::String => ValueType::String,
2760 ValueType::Member(id) => ValueType::Member(*id),
2761 ValueType::KeyedArray(keyed) => {
2762 let axes = match &keyed.axes {
2763 Some(axes) => Some(copy_axis_types(axes, budget, location)?),
2764 None => None,
2765 };
2766 ValueType::KeyedArray(KeyedArrayType {
2767 axes,
2768 elements: copy_types(&keyed.elements, budget, location)?,
2769 })
2770 }
2771 ValueType::Unestablished => ValueType::Unestablished,
2772 ValueType::TupleKind => ValueType::TupleKind,
2773 ValueType::RecordKind => ValueType::RecordKind,
2774 ValueType::Set(element_type) => ValueType::Set(*element_type),
2775 ValueType::Array(array) => {
2776 let (ArrayType::Positions(entries) | ArrayType::Elements(entries)) = array;
2777 let entries = copy_types(entries, budget, location)?;
2778 ValueType::Array(match array {
2779 ArrayType::Positions(_) => ArrayType::Positions(entries),
2780 ArrayType::Elements(_) => ArrayType::Elements(entries),
2781 })
2782 }
2783 ValueType::ArrayKind(elements) => {
2784 ValueType::ArrayKind(copy_types(elements, budget, location)?)
2785 }
2786 ValueType::Tuple(entries) => ValueType::Tuple(copy_types(entries, budget, location)?),
2787 ValueType::Record(fields) => {
2788 check_value_labels(fields, budget, location)?;
2789 let mut copied = metadata_vec(fields.len(), budget, location)?;
2790 for (label, ty) in fields {
2791 budget.charge(label.len(), location.clone())?;
2792 copied.push((label.to_owned(), copy_type(ty, budget, location)?));
2793 }
2794 ValueType::Record(copied)
2795 }
2796 })
2797 })
2798}
2799
2800fn copy_types(
2801 types: &[ValueType],
2802 budget: &mut Budget,
2803 location: &Location,
2804) -> Result<Vec<ValueType>, QueryError> {
2805 let mut copied = metadata_vec(types.len(), budget, location)?;
2806 for ty in types {
2807 copied.push(copy_type(ty, budget, location)?);
2808 }
2809 Ok(copied)
2810}
2811
2812fn one_type(
2813 ty: ValueType,
2814 budget: &mut Budget,
2815 location: &Location,
2816) -> Result<Vec<ValueType>, QueryError> {
2817 let mut types = metadata_vec(1, budget, location)?;
2818 types.push(ty);
2819 Ok(types)
2820}
2821
2822fn append_types(
2823 target: &mut Vec<ValueType>,
2824 types: Vec<ValueType>,
2825 budget: &mut Budget,
2826 location: &Location,
2827) -> Result<(), QueryError> {
2828 allocation::<ValueType>(sum(target.len(), types.len(), location)?, location)?;
2829 budget.charge(types.len(), location.clone())?;
2830 target.extend(types);
2831 Ok(())
2832}
2833
2834enum Globals<'a> {
2835 Types(&'a BTreeMap<String, ValueType>),
2836 Facts(&'a BTreeMap<String, Vec<ValueType>>),
2837 Available(&'a Bindings<ConstructedValue>),
2838}
2839
2840fn check_loop_terminal<Q>(
2842 kind: &ValueExpressionKind<Q>,
2843 transfer: Option<usize>,
2844 location: &Location,
2845) -> Result<(), QueryError> {
2846 match (kind, transfer) {
2847 (ValueExpressionKind::Break(_), Some(_)) => Ok(()),
2848 (ValueExpressionKind::Continue(values), Some(arity)) if values.len() == arity => Ok(()),
2849 (ValueExpressionKind::Continue(_), Some(_)) => {
2850 Err(error(location, "loop state argument count mismatch"))
2851 }
2852 (ValueExpressionKind::Break(_) | ValueExpressionKind::Continue(_), None) => Err(error(
2853 location,
2854 "loop transfer requires a terminal loop body position",
2855 )),
2856 (
2857 ValueExpressionKind::Block { .. }
2858 | ValueExpressionKind::Conditional { .. }
2859 | ValueExpressionKind::ValueMatch { .. },
2860 Some(_),
2861 )
2862 | (_, None) => Ok(()),
2863 (_, Some(_)) => Err(error(
2864 location,
2865 "loop body path must end in break or continue",
2866 )),
2867 }
2868}
2869
2870struct Analysis<'a, 'h, Q, H> {
2871 queries: &'h mut H,
2872 query: std::marker::PhantomData<Q>,
2873 globals: Globals<'a>,
2874 locals: Vec<(&'a str, Vec<ValueType>)>,
2875 free: Vec<Located<String>>,
2876 fallback_names: Vec<Located<String>>,
2877 fallback: bool,
2878}
2879
2880impl<'a, 'h, Q: 'a, H: ValueQueryHost<Q>> Analysis<'a, 'h, Q, H> {
2881 fn new(globals: Globals<'a>, queries: &'h mut H) -> Self {
2882 Self {
2883 globals,
2884 queries,
2885 query: std::marker::PhantomData,
2886 locals: Vec::new(),
2887 free: Vec::new(),
2888 fallback_names: Vec::new(),
2889 fallback: false,
2890 }
2891 }
2892
2893 fn global_exists(
2894 &self,
2895 name: &str,
2896 range: std::ops::Range<usize>,
2897 budget: &mut Budget,
2898 ) -> Result<bool, QueryError> {
2899 admit_diagnostic(
2900 "undefined binding: ",
2901 name,
2902 budget,
2903 &Location::Query(range.clone()),
2904 )?;
2905 Ok(match self.globals {
2906 Globals::Types(types) => types.contains_key(name),
2907 Globals::Facts(types) => types.contains_key(name),
2908 Globals::Available(bindings) => bindings.get(name, range).is_ok(),
2909 })
2910 }
2911
2912 fn name(
2913 &mut self,
2914 name: &str,
2915 expression: &ValueExpression<Q>,
2916 budget: &mut Budget,
2917 ) -> Result<Vec<ValueType>, QueryError> {
2918 let location = Location::Query(expression.range.clone());
2919 if name == "_" {
2920 return Err(error(&location, "discard binder cannot be read"));
2921 }
2922 for (local, types) in self.locals.iter().rev() {
2923 budget.charge(
2924 sum(1, name.len().min(local.len()), &location)?,
2925 location.clone(),
2926 )?;
2927 if name == *local {
2928 return copy_types(types, budget, &location);
2929 }
2930 }
2931 self.queries
2932 .validate_name(name, &expression.range, budget)?;
2933 admit_diagnostic("undefined binding: ", name, budget, &location)?;
2934 let types = match self.globals {
2935 Globals::Types(types) => one_type(
2936 copy_type(
2937 types
2938 .get(name)
2939 .ok_or_else(|| error(&location, format!("undefined binding: {name}")))?,
2940 budget,
2941 &location,
2942 )?,
2943 budget,
2944 &location,
2945 )?,
2946 Globals::Facts(types) => copy_types(
2947 types
2948 .get(name)
2949 .ok_or_else(|| error(&location, format!("undefined binding: {name}")))?,
2950 budget,
2951 &location,
2952 )?,
2953 Globals::Available(bindings) => {
2954 let value = bindings.get(name, expression.range.clone())?;
2955 let ty = if !self.fallback
2956 && matches!(
2957 value,
2958 ConstructedValue::Array(_)
2959 | ConstructedValue::Tuple(_)
2960 | ConstructedValue::Record(_)
2961 | ConstructedValue::Set { .. }
2962 | ConstructedValue::KeyedArray { .. }
2963 ) {
2964 ValueType::Unestablished
2965 } else {
2966 shallow_type(value, budget, &location)?
2967 };
2968 one_type(ty, budget, &location)?
2969 }
2970 };
2971 let mut found = false;
2972 for previous in &self.free {
2973 budget.charge(
2974 sum(1, name.len().min(previous.value.len()), &location)?,
2975 location.clone(),
2976 )?;
2977 if previous.value == name {
2978 found = true;
2979 break;
2980 }
2981 }
2982 if self.fallback && !found {
2983 budget.charge(name.len(), location.clone())?;
2984 push_metadata(
2985 &mut self.fallback_names,
2986 Located::new(name.to_owned(), expression.range.clone()),
2987 budget,
2988 &location,
2989 )?;
2990 } else if !self.fallback {
2991 let mut selected = None;
2992 for (index, previous) in self.fallback_names.iter().enumerate() {
2993 budget.charge(1 + name.len().min(previous.value.len()), location.clone())?;
2994 if previous.value == name {
2995 selected = Some(index);
2996 break;
2997 }
2998 }
2999 if let Some(index) = selected {
3000 self.fallback_names.remove(index);
3001 }
3002 }
3003 if !found {
3004 budget.charge(name.len(), location.clone())?;
3005 push_metadata(
3006 &mut self.free,
3007 Located::new(name.to_owned(), expression.range.clone()),
3008 budget,
3009 &location,
3010 )?;
3011 }
3012 Ok(types)
3013 }
3014
3015 fn walk(
3016 &mut self,
3017 expression: &'a ValueExpression<Q>,
3018 budget: &mut Budget,
3019 ) -> Result<Vec<ValueType>, QueryError> {
3020 self.walk_control(expression, budget, None)
3021 }
3022
3023 fn walk_control(
3024 &mut self,
3025 expression: &'a ValueExpression<Q>,
3026 budget: &mut Budget,
3027 transfer: Option<usize>,
3028 ) -> Result<Vec<ValueType>, QueryError> {
3029 let location = Location::Query(expression.range.clone());
3030 budget.within_evaluation(1, location.clone(), |budget| {
3031 budget.charge(1, location.clone())?;
3032 check_loop_terminal(&expression.value, transfer, &location)?;
3033 self.node(expression, budget, &location, transfer)
3034 })
3035 }
3036
3037 fn node(
3038 &mut self,
3039 expression: &'a ValueExpression<Q>,
3040 budget: &mut Budget,
3041 location: &Location,
3042 transfer: Option<usize>,
3043 ) -> Result<Vec<ValueType>, QueryError> {
3044 self.queries.prepare_computation(expression, budget)?;
3045 match &expression.value {
3046 ValueExpressionKind::Queue { items, .. } => {
3047 self.walk(items, budget)?;
3048 self.queries.worklist_types(expression, budget)
3049 }
3050 ValueExpressionKind::IdentitySet { .. } => {
3051 self.queries.worklist_types(expression, budget)
3052 }
3053 ValueExpressionKind::PopFront(queue) => {
3054 self.walk(queue, budget)?;
3055 self.queries.worklist_types(expression, budget)
3056 }
3057 ValueExpressionKind::PushBackAll { queue, items } => {
3058 self.walk(queue, budget)?;
3059 self.walk(items, budget)?;
3060 self.queries.worklist_types(expression, budget)
3061 }
3062 ValueExpressionKind::Insert { set, item } => {
3063 self.walk(set, budget)?;
3064 self.walk(item, budget)?;
3065 self.queries.worklist_types(expression, budget)
3066 }
3067 ValueExpressionKind::Call {
3068 function,
3069 arguments,
3070 } => {
3071 let (_, arity) = self.queries.function(function, budget)?;
3072 if arguments.len() != arity {
3073 return Err(error(location, "function argument count mismatch"));
3074 }
3075 for argument in arguments {
3076 self.walk(argument, budget)?;
3077 }
3078 self.queries.function_types(function, budget)
3079 }
3080 ValueExpressionKind::Fold {
3081 items,
3082 initial,
3083 step,
3084 }
3085 | ValueExpressionKind::Scan {
3086 items,
3087 initial,
3088 step,
3089 } => {
3090 let (_, state) = self.queries.accumulator_function(step, budget)?;
3091 let types = self.walk(items, budget)?;
3092 for ty in types {
3093 if !matches!(
3094 shape_type(ty, budget, location)?,
3095 ValueType::Array(_) | ValueType::ArrayKind(_) | ValueType::Unestablished
3096 ) {
3097 return Err(error(
3098 &Location::Query(items.range.clone()),
3099 "named accumulator needs a positional sequence",
3100 ));
3101 }
3102 }
3103 self.walk(initial, budget)?;
3104 if matches!(expression.value, ValueExpressionKind::Scan { .. }) {
3105 one_type(
3106 ValueType::Array(ArrayType::Elements(state)),
3107 budget,
3108 location,
3109 )
3110 } else {
3111 Ok(state)
3112 }
3113 }
3114 ValueExpressionKind::NativeValue(query) => {
3115 self.queries
3116 .native_value_types(query, &self.locals, budget, &expression.range)
3117 }
3118 ValueExpressionKind::Literal(value) => {
3119 let ty = if self.fallback {
3120 shallow_type(value, budget, location)?
3121 } else {
3122 constructed_value_type(value, budget, location.clone())?
3123 };
3124 one_type(ty, budget, location)
3125 }
3126 ValueExpressionKind::Occurs(value) | ValueExpressionKind::Absent(value) => {
3127 self.walk(value, budget)?;
3128 one_type(ValueType::Boolean, budget, location)
3129 }
3130 ValueExpressionKind::Lookup { value, key }
3131 | ValueExpressionKind::HasKey { value, key } => {
3132 let values = self.walk(value, budget)?;
3133 let keys = self.walk(key, budget)?;
3134 let label = match &key.value {
3135 ValueExpressionKind::Literal(ConstructedValue::String(label)) => {
3136 Some(label.as_str())
3137 }
3138 _ => None,
3139 };
3140 let mut result = Vec::new();
3141 for value in values {
3142 append_types(
3143 &mut result,
3144 access_type(value, &keys, label, true, budget, location)?,
3145 budget,
3146 location,
3147 )?;
3148 }
3149 if matches!(expression.value, ValueExpressionKind::HasKey { .. }) {
3150 one_type(ValueType::Boolean, budget, location)
3151 } else {
3152 Ok(result)
3153 }
3154 }
3155 ValueExpressionKind::Default { value, fallback } => {
3156 let left = self.walk(value, budget)?;
3157 let saved = self.fallback;
3158 self.fallback = true;
3159 let right = self.walk(fallback, budget);
3160 self.fallback = saved;
3161 let right = right?;
3162 for a in &left {
3163 for b in &right {
3164 if !compatible_types(a, b, budget, location)? {
3165 return Err(error(
3166 location,
3167 "default needs compatible underlying types",
3168 ));
3169 }
3170 }
3171 }
3172 let mut result = Vec::new();
3173 for ty in left.into_iter().chain(right) {
3174 let ty = match ty {
3175 ValueType::Absent => continue,
3176 ValueType::Declared {
3177 actual,
3178 declaration,
3179 } => {
3180 let declaration =
3181 copy_declaration(underlying(&declaration), budget, location)?;
3182 ValueType::Declared {
3183 actual: Box::new(if matches!(*actual, ValueType::Absent) {
3184 ValueType::Unestablished
3185 } else {
3186 *actual
3187 }),
3188 declaration,
3189 }
3190 }
3191 ty => ty,
3192 };
3193 push_metadata(&mut result, ty, budget, location)?;
3194 }
3195 if result.is_empty() {
3196 one_type(ValueType::Absent, budget, location)
3197 } else {
3198 Ok(result)
3199 }
3200 }
3201 ValueExpressionKind::CurrentInput => {
3202 self.queries.current_input_types(&expression.range, budget)
3203 }
3204 ValueExpressionKind::Name(name) => self.name(name, expression, budget),
3205 ValueExpressionKind::PredicateSubject => {
3206 if !self
3207 .locals
3208 .iter()
3209 .any(|(name, _)| *name == PREDICATE_SUBJECT)
3210 {
3211 return self
3212 .queries
3213 .predicate_subject_types(&expression.range, budget);
3214 }
3215 self.name(PREDICATE_SUBJECT, expression, budget)
3216 }
3217 ValueExpressionKind::SubjectScope { subject, argument } => {
3218 let types = self.walk(subject, budget)?;
3219 self.scoped_types(argument, subject, &types, false, budget)
3220 }
3221 ValueExpressionKind::PredicateScope { subject, predicate } => {
3222 let types = self.walk(subject, budget)?;
3223 let result = self.scoped_types(predicate, subject, &types, false, budget)?;
3224 predicate_types(&result, budget, &predicate.body.range)?;
3225 one_type(ValueType::Boolean, budget, location)
3226 }
3227 ValueExpressionKind::NativeQuery(query) => {
3228 self.queries
3229 .query_types(query, &self.locals, budget, &expression.range)
3230 }
3231 ValueExpressionKind::One(array) => {
3232 let mut result = Vec::new();
3233 for ty in self.walk(array, budget)? {
3234 match shape_type(ty, budget, location)? {
3235 ValueType::Array(
3236 ArrayType::Positions(types) | ArrayType::Elements(types),
3237 )
3238 | ValueType::ArrayKind(types) => {
3239 append_types(&mut result, types, budget, location)?
3240 }
3241 ValueType::Unestablished => {
3242 push_metadata(&mut result, ValueType::Unestablished, budget, location)?
3243 }
3244 _ => return Err(error(location, "one needs a positional array")),
3245 }
3246 }
3247 if result.is_empty() {
3248 push_metadata(&mut result, ValueType::Unestablished, budget, location)?;
3249 }
3250 Ok(result)
3251 }
3252 ValueExpressionKind::Array(children) => {
3253 let mut entries = metadata_vec(children.len(), budget, location)?;
3254 let mut exact = true;
3255 for child in children {
3256 let types = self.walk(child, budget)?;
3257 exact &= types.len() == 1;
3258 entries.push(types);
3259 }
3260 let mut types = Vec::new();
3261 for entries in entries {
3262 append_types(&mut types, entries, budget, location)?;
3263 }
3264 one_type(
3265 ValueType::Array(if exact {
3266 ArrayType::Positions(types)
3267 } else {
3268 ArrayType::Elements(types)
3269 }),
3270 budget,
3271 location,
3272 )
3273 }
3274 ValueExpressionKind::Tuple(children) => {
3275 let positions = self.positions(children.iter(), budget, location)?;
3276 let mut types = metadata_vec(positions.len(), budget, location)?;
3277 for position in positions {
3278 types.push(ValueType::Tuple(position));
3279 }
3280 Ok(types)
3281 }
3282 ValueExpressionKind::Record(fields) => {
3283 for (index, (label, _)) in fields.iter().enumerate() {
3284 for (previous, _) in &fields[..index] {
3285 budget.charge(
3286 sum(1, label.value.len().min(previous.value.len()), location)?,
3287 location.clone(),
3288 )?;
3289 if label.value == previous.value {
3290 return Err(QueryError::query(
3291 label.range.clone(),
3292 "duplicate record label",
3293 ));
3294 }
3295 }
3296 }
3297 let positions =
3298 self.positions(fields.iter().map(|(_, value)| value), budget, location)?;
3299 let mut types = metadata_vec(positions.len(), budget, location)?;
3300 for position in positions {
3301 let mut result = metadata_vec(fields.len(), budget, location)?;
3302 for ((label, _), ty) in fields.iter().zip(position) {
3303 budget.charge(label.value.len(), Location::Query(label.range.clone()))?;
3304 result.push((label.value.to_owned(), ty));
3305 }
3306 types.push(ValueType::Record(result));
3307 }
3308 Ok(types)
3309 }
3310 ValueExpressionKind::Dictionary(entries) => {
3311 for (key, value) in entries {
3312 for ty in self.walk(key, budget)? {
3313 require_type(
3314 &ty,
3315 ScalarRequirement::String,
3316 &Location::Query(key.range.clone()),
3317 )?;
3318 }
3319 self.walk(value, budget)?;
3320 }
3321 one_type(ValueType::RecordKind, budget, location)
3322 }
3323 ValueExpressionKind::DictionaryComprehension { clauses, key, head } => {
3324 let saved = self.locals.len();
3325 let result = (|| {
3326 self.clauses(clauses, budget)?;
3327 for ty in self.walk(key, budget)? {
3328 require_type(
3329 &ty,
3330 ScalarRequirement::String,
3331 &Location::Query(key.range.clone()),
3332 )?;
3333 }
3334 self.walk(head, budget)?;
3335 one_type(ValueType::RecordKind, budget, location)
3336 })();
3337 self.locals.truncate(saved);
3338 result
3339 }
3340 ValueExpressionKind::Set(children) => {
3341 let mut element_type = None;
3342 for child in children {
3343 merge_set_types(
3344 &mut element_type,
3345 &self.walk(child, budget)?,
3346 budget,
3347 location,
3348 )?;
3349 }
3350 one_type(ValueType::Set(element_type), budget, location)
3351 }
3352 ValueExpressionKind::KeyedArray {
3353 axes,
3354 declared_axis_sources,
3355 entries,
3356 } => {
3357 if axes.is_some() && declared_axis_sources.is_some() {
3358 return Err(error(
3359 location,
3360 "conflicting concrete axes and declared axis sources",
3361 ));
3362 }
3363 let source_facts = declared_axis_sources
3364 .as_ref()
3365 .map(|sources| self.axis_sources(sources, budget, location))
3366 .transpose()?;
3367 let mut facts = None;
3368 let established = match axes {
3369 Some(axes) => {
3370 check_axes(axes, budget, location)?;
3371 Some(axis_types(axes, budget, location)?)
3372 }
3373 None => None,
3374 };
3375 let mut elements = Vec::new();
3376 for (key, value) in entries {
3377 let key_location = Location::Query(key.range.clone());
3378 merge_key_facts(&mut facts, &self.walk(key, budget)?, budget, &key_location)?;
3379 if let Some(axes) = &established {
3380 check_key_facts(&facts, axes, budget, &key_location)?;
3381 }
3382 if let Some(sources) = &source_facts {
3383 check_source_facts(&facts, sources, budget, &key_location)?;
3384 }
3385 append_types(&mut elements, self.walk(value, budget)?, budget, location)?;
3386 }
3387 let axes = match established {
3388 Some(axes) => Some(axes),
3389 None => established_facts(source_facts.or(facts), budget, location)?,
3390 };
3391 if entries.is_empty() && axes.is_none() && declared_axis_sources.is_none() {
3392 return Err(error(location, "unestablished empty keyed axes"));
3393 }
3394 one_type(
3395 ValueType::KeyedArray(KeyedArrayType { axes, elements }),
3396 budget,
3397 location,
3398 )
3399 }
3400 ValueExpressionKind::KeyedComprehension {
3401 clauses,
3402 key,
3403 head,
3404 declared_axis_sources,
3405 empty_axis_sources,
3406 } => {
3407 if declared_axis_sources.is_some() && empty_axis_sources.is_some() {
3408 return Err(error(
3409 location,
3410 "conflicting declared and fallback axis sources",
3411 ));
3412 }
3413 let sources = declared_axis_sources
3415 .as_ref()
3416 .or(empty_axis_sources.as_ref());
3417 let source_facts = sources
3418 .map(|sources| self.axis_sources(sources, budget, location))
3419 .transpose()?;
3420 let saved = self.locals.len();
3421 let result = (|| {
3422 self.clauses(clauses, budget)?;
3423 let mut facts = None;
3424 merge_key_facts(
3425 &mut facts,
3426 &self.walk(key, budget)?,
3427 budget,
3428 &Location::Query(key.range.clone()),
3429 )?;
3430 let elements = self.walk(head, budget)?;
3431 if let Some(source_facts) = &source_facts {
3432 check_source_facts(
3433 &facts,
3434 source_facts,
3435 budget,
3436 &Location::Query(key.range.clone()),
3437 )?;
3438 }
3439 let axes = if declared_axis_sources.is_some() {
3440 established_facts(source_facts, budget, location)?
3441 } else {
3442 established_facts(facts, budget, location)?
3443 };
3444 one_type(
3445 ValueType::KeyedArray(KeyedArrayType { axes, elements }),
3446 budget,
3447 location,
3448 )
3449 })();
3450 self.locals.truncate(saved);
3451 result
3452 }
3453 ValueExpressionKind::Unary { operator, operand } => {
3454 let types = self.walk(operand, budget)?;
3455 let mut result = metadata_vec(types.len(), budget, location)?;
3456 for ty in types {
3457 budget.charge(1, location.clone())?;
3458 match operator {
3459 ValueUnaryOperator::Not => {
3460 require_type(&ty, ScalarRequirement::Boolean, location)?;
3461 result.push(ValueType::Boolean);
3462 }
3463 ValueUnaryOperator::Positive | ValueUnaryOperator::Negative => {
3464 require_type(&ty, ScalarRequirement::Numeric, location)?;
3465 result.push(ty);
3466 }
3467 }
3468 }
3469 Ok(result)
3470 }
3471 ValueExpressionKind::Binary {
3472 operator,
3473 left,
3474 right,
3475 } => {
3476 let left = self.walk(left, budget)?;
3477 let right = self.walk(right, budget)?;
3478 let mut result = Vec::new();
3479 for a in &left {
3480 for b in &right {
3481 budget.charge(1, location.clone())?;
3482 let ty = binary_type(*operator, a, b, budget, location)?;
3483 push_metadata(&mut result, ty, budget, location)?;
3484 }
3485 }
3486 Ok(result)
3487 }
3488 ValueExpressionKind::Field { value, field } => {
3489 let types = self.walk(value, budget)?;
3490 let mut result = Vec::new();
3491 for ty in types {
3492 if let ValueType::Declared { declaration, .. } = &ty
3493 && let DeclaredType::Record(fields) = underlying(declaration)
3494 {
3495 let selected = record_declaration(fields, &field.value, budget, location)?;
3496 push_metadata(
3497 &mut result,
3498 declared_fact(selected, ValueType::Unestablished, budget, location)?,
3499 budget,
3500 location,
3501 )?;
3502 continue;
3503 }
3504 let selected = match shape_type(ty, budget, location)? {
3505 ValueType::Record(fields) => {
3506 let mut selected = None;
3507 for (label, ty) in fields {
3508 budget.charge(
3509 sum(1, label.len().min(field.value.len()), location)?,
3510 location.clone(),
3511 )?;
3512 if label == field.value {
3513 selected = Some(ty);
3514 }
3515 }
3516 selected.unwrap_or(ValueType::Unestablished)
3517 }
3518 ValueType::Unestablished | ValueType::RecordKind => {
3519 ValueType::Unestablished
3520 }
3521 _ => return Err(error(location, "field access needs a record")),
3522 };
3523 push_metadata(&mut result, selected, budget, location)?;
3524 }
3525 Ok(result)
3526 }
3527 ValueExpressionKind::TupleAccess { value, position } => {
3528 let types = self.walk(value, budget)?;
3529 let mut result = Vec::new();
3530 for ty in types {
3531 budget.charge(1, location.clone())?;
3532 let selected = match shape_type(ty, budget, location)? {
3533 ValueType::Tuple(entries) => {
3534 budget.charge(entries.len().min(position.value), location.clone())?;
3535 position
3536 .value
3537 .checked_sub(1)
3538 .and_then(|index| entries.into_iter().nth(index))
3539 .unwrap_or(ValueType::Unestablished)
3540 }
3541 ValueType::Unestablished | ValueType::TupleKind => ValueType::Unestablished,
3542 _ => return Err(error(location, "tuple access needs a tuple")),
3543 };
3544 push_metadata(&mut result, selected, budget, location)?;
3545 }
3546 Ok(result)
3547 }
3548 ValueExpressionKind::ArrayAccess { array, index } => {
3549 let arrays = self.walk(array, budget)?;
3550 let indices = self.walk(index, budget)?;
3551 let constant = match index.value {
3552 ValueExpressionKind::Literal(ConstructedValue::Integer(value)) => Some(value),
3553 _ => None,
3554 };
3555 let mut result = Vec::new();
3556 for array in arrays {
3557 if matches!(&array, ValueType::Record(_) | ValueType::RecordKind)
3558 || matches!(&array, ValueType::Declared { declaration, .. }
3559 if matches!(underlying(declaration), DeclaredType::Record(_)))
3560 {
3561 let label = match &index.value {
3562 ValueExpressionKind::Literal(ConstructedValue::String(label)) => {
3563 Some(label.as_str())
3564 }
3565 _ => None,
3566 };
3567 append_types(
3568 &mut result,
3569 access_type(array, &indices, label, false, budget, location)?,
3570 budget,
3571 location,
3572 )?;
3573 continue;
3574 }
3575 match shape_type(array, budget, location)? {
3576 ValueType::ArrayKind(elements) => {
3577 let mut facts = None;
3578 merge_key_facts(&mut facts, &indices, budget, location)?;
3579 append_types(&mut result, elements, budget, location)?;
3580 }
3581 ValueType::KeyedArray(keyed) => {
3582 let mut facts = None;
3583 merge_key_facts(&mut facts, &indices, budget, location)?;
3584 if let Some(axes) = &keyed.axes {
3585 check_key_facts(&facts, axes, budget, location)?;
3586 }
3587 append_types(&mut result, keyed.elements, budget, location)?;
3588 }
3589 ValueType::Array(array) => {
3590 for ty in &indices {
3591 require_type(ty, ScalarRequirement::Integer, location)?;
3592 }
3593 match array {
3594 _ if constant.is_some_and(|position| position <= 0) => {
3595 push_metadata(
3596 &mut result,
3597 ValueType::Unestablished,
3598 budget,
3599 location,
3600 )?;
3601 }
3602 ArrayType::Positions(entries) if constant.is_some() => {
3603 let position =
3604 usize::try_from(constant.expect("constant checked")).ok();
3605 budget.charge(
3606 entries.len().min(position.unwrap_or(0)),
3607 location.clone(),
3608 )?;
3609 let ty = position
3610 .and_then(|position| position.checked_sub(1))
3611 .and_then(|index| entries.into_iter().nth(index))
3612 .unwrap_or(ValueType::Unestablished);
3613 push_metadata(&mut result, ty, budget, location)?;
3614 }
3615 ArrayType::Positions(entries) | ArrayType::Elements(entries) => {
3616 append_types(&mut result, entries, budget, location)?
3617 }
3618 }
3619 }
3620 ValueType::Unestablished => {
3621 for ty in &indices {
3622 if matches!(ty, ValueType::String) {
3623 continue;
3624 }
3625 let mut facts = None;
3626 merge_key_facts(
3627 &mut facts,
3628 std::slice::from_ref(ty),
3629 budget,
3630 location,
3631 )?;
3632 }
3633 push_metadata(&mut result, ValueType::Unestablished, budget, location)?;
3634 }
3635 _ => return Err(error(location, "array access needs an array or record")),
3636 }
3637 }
3638 if result.is_empty() {
3639 push_metadata(&mut result, ValueType::Unestablished, budget, location)?;
3640 }
3641 Ok(result)
3642 }
3643 ValueExpressionKind::IndexSet(array) => {
3644 let mut result = Vec::new();
3645 for ty in self.walk(array, budget)? {
3646 budget.charge(1, location.clone())?;
3647 let element_type = match shape_type(ty, budget, location)? {
3648 ValueType::Array(_) => Some(SetElementType::Integer),
3649 ValueType::KeyedArray(keyed) => match keyed.axes {
3650 Some(axes) if axes.len() == 1 => Some(key_set_type(axes[0])),
3651 Some(_) => return Err(error(location, "index_set needs rank one")),
3652 None => None,
3653 },
3654 ValueType::ArrayKind(_) | ValueType::Unestablished => None,
3655 _ => return Err(error(location, "index_set needs an array")),
3656 };
3657 push_metadata(&mut result, ValueType::Set(element_type), budget, location)?;
3658 }
3659 Ok(result)
3660 }
3661 ValueExpressionKind::Entries(array) => {
3662 let mut result = Vec::new();
3663 for ty in self.walk(array, budget)? {
3664 budget.charge(1, location.clone())?;
3665 let keyed = match shape_type(ty, budget, location)? {
3666 ValueType::KeyedArray(keyed) => keyed,
3667 ValueType::ArrayKind(elements) => KeyedArrayType {
3668 axes: None,
3669 elements,
3670 },
3671 ValueType::Unestablished => {
3672 push_metadata(&mut result, ValueType::Unestablished, budget, location)?;
3673 continue;
3674 }
3675 _ => return Err(error(location, "entries needs a keyed array")),
3676 };
3677 let key = match keyed.axes {
3678 Some(axes) => {
3679 let mut components = metadata_vec(axes.len(), budget, location)?;
3680 for axis in axes {
3681 budget.charge(1, location.clone())?;
3682 components.push(match axis {
3683 ValueKeyType::Integer => ValueType::Integer,
3684 ValueKeyType::Member(id) => ValueType::Member(id),
3685 });
3686 }
3687 if components.len() == 1 {
3688 components.pop().expect("rank one")
3689 } else {
3690 ValueType::Tuple(components)
3691 }
3692 }
3693 None => ValueType::Unestablished,
3694 };
3695 let mut records = metadata_vec(keyed.elements.len(), budget, location)?;
3696 for value in keyed.elements {
3697 let mut fields = metadata_vec(2, budget, location)?;
3698 budget.charge("key".len() + "value".len(), location.clone())?;
3699 fields.push(("key".into(), copy_type(&key, budget, location)?));
3700 fields.push(("value".into(), value));
3701 records.push(ValueType::Record(fields));
3702 }
3703 push_metadata(
3704 &mut result,
3705 ValueType::Array(ArrayType::Elements(records)),
3706 budget,
3707 location,
3708 )?;
3709 }
3710 Ok(result)
3711 }
3712 ValueExpressionKind::ZipExact { left, right } => {
3713 let left = self.walk(left, budget)?;
3714 let right = self.walk(right, budget)?;
3715 let mut result = Vec::new();
3716 for a in &left {
3717 for b in &right {
3718 let ty = zip_exact_type(a, b, budget, location)?;
3719 push_metadata(&mut result, ty, budget, location)?;
3720 }
3721 }
3722 Ok(result)
3723 }
3724 ValueExpressionKind::Reduce { operator, array } => {
3725 for ty in self.walk(array, budget)? {
3726 budget.charge(1, location.clone())?;
3727 let elements = match shape_type(ty, budget, location)? {
3728 ValueType::Array(
3729 ArrayType::Positions(elements) | ArrayType::Elements(elements),
3730 )
3731 | ValueType::ArrayKind(elements) => elements,
3732 ValueType::KeyedArray(keyed) => keyed.elements,
3733 ValueType::Unestablished => continue,
3734 _ => return Err(error(location, "reducer needs an array")),
3735 };
3736 if let Some(requirement) = match operator {
3737 ValueReducer::Length => None,
3738 ValueReducer::Sum => Some(ScalarRequirement::Integer),
3739 ValueReducer::Forall | ValueReducer::Exists => {
3740 Some(ScalarRequirement::Boolean)
3741 }
3742 } {
3743 for element in elements {
3744 budget.charge(1, location.clone())?;
3745 require_type(&element, requirement, location)?;
3746 }
3747 }
3748 }
3749 one_type(
3750 match operator {
3751 ValueReducer::Length | ValueReducer::Sum => ValueType::Integer,
3752 ValueReducer::Forall | ValueReducer::Exists => ValueType::Boolean,
3753 },
3754 budget,
3755 location,
3756 )
3757 }
3758 ValueExpressionKind::Filter { array, predicate } => {
3759 let mut elements = Vec::new();
3760 for ty in self.walk(array, budget)? {
3761 append_types(
3762 &mut elements,
3763 filter_elements(ty, budget, location)?,
3764 budget,
3765 location,
3766 )?;
3767 }
3768 if elements.is_empty() {
3769 push_metadata(&mut elements, ValueType::Unestablished, budget, location)?;
3770 }
3771 let result = self.scoped_types(predicate, array, &elements, true, budget)?;
3772 predicate_types(&result, budget, &predicate.body.range)?;
3773 one_type(
3774 ValueType::Array(ArrayType::Elements(elements)),
3775 budget,
3776 location,
3777 )
3778 }
3779 ValueExpressionKind::Sort {
3780 array, selector, ..
3781 } => {
3782 let mut result = Vec::new();
3783 for ty in self.walk(array, budget)? {
3784 let ty = sort_type(ty, selector.as_ref(), budget, location)?;
3785 push_metadata(&mut result, ty, budget, location)?;
3786 }
3787 Ok(result)
3788 }
3789 ValueExpressionKind::Extremum { array, field, .. } => {
3790 let mut result = Vec::new();
3791 for ty in self.walk(array, budget)? {
3792 let elements = ordering_elements(
3793 ty,
3794 field
3795 .as_ref()
3796 .map(|field| Located::new(field.value.as_str(), field.range.clone())),
3797 budget,
3798 location,
3799 )?;
3800 append_types(&mut result, elements, budget, location)?;
3801 }
3802 push_metadata(&mut result, ValueType::Absent, budget, location)?;
3803 Ok(result)
3804 }
3805 ValueExpressionKind::Unique(array) | ValueExpressionKind::Tally(array) => {
3806 let tally = matches!(expression.value, ValueExpressionKind::Tally(_));
3807 let mut result = Vec::new();
3808 for ty in self.walk(array, budget)? {
3809 let retained = if !tally {
3810 match &ty {
3811 ValueType::Declared { declaration, .. } => {
3812 Some(copy_declaration(declaration, budget, location)?)
3813 }
3814 _ => None,
3815 }
3816 } else {
3817 None
3818 };
3819 let elements = scalar_pipeline_elements(ty, tally, budget, location)?;
3820 let mut ty = if tally {
3821 if elements.is_empty() {
3822 ValueType::Record(Vec::new())
3823 } else {
3824 ValueType::RecordKind
3825 }
3826 } else {
3827 ValueType::Array(ArrayType::Elements(elements))
3828 };
3829 if let Some(declaration) = retained {
3830 ty = ValueType::Declared {
3831 actual: Box::new(ty),
3832 declaration,
3833 };
3834 }
3835 push_metadata(&mut result, ty, budget, location)?;
3836 }
3837 Ok(result)
3838 }
3839 ValueExpressionKind::GroupBy { rows, field } => {
3840 let selector = Location::Query(field.range.clone());
3841 let mut result = Vec::new();
3842 for ty in self.walk(rows, budget)? {
3843 budget.charge(1, location.clone())?;
3844 let elements = match shape_type(ty, budget, location)? {
3845 ValueType::Array(
3846 ArrayType::Positions(elements) | ArrayType::Elements(elements),
3847 )
3848 | ValueType::ArrayKind(elements) => elements,
3849 ValueType::Unestablished => {
3850 push_metadata(&mut result, ValueType::Unestablished, budget, location)?;
3851 continue;
3852 }
3853 _ => return Err(error(location, "group_by needs a positional array")),
3854 };
3855 let mut key_type = None;
3856 for row in &elements {
3857 budget.charge(1, location.clone())?;
3858 let normalized = if matches!(row, ValueType::Declared { .. }) {
3859 Some(shape_type(
3860 copy_type(row, budget, location)?,
3861 budget,
3862 location,
3863 )?)
3864 } else {
3865 None
3866 };
3867 let fields = match normalized.as_ref().unwrap_or(row) {
3868 ValueType::Record(fields) => fields,
3869 ValueType::Unestablished | ValueType::RecordKind => continue,
3870 _ => return Err(error(location, "group_by needs record rows")),
3871 };
3872 for (label, ty) in fields {
3873 budget.charge(
3874 sum(1, label.len().min(field.value.len()), &selector)?,
3875 selector.clone(),
3876 )?;
3877 if label != &field.value || matches!(ty, ValueType::Unestablished) {
3878 continue;
3879 }
3880 if !matches!(
3881 ty,
3882 ValueType::Integer | ValueType::String | ValueType::Member(_)
3883 ) {
3884 return Err(error(
3885 &selector,
3886 "group_by keys need integers, strings or nominal members",
3887 ));
3888 }
3889 if key_type.as_ref().is_some_and(|previous| previous != ty) {
3890 return Err(error(
3891 &selector,
3892 "group_by needs homogeneous key types",
3893 ));
3894 }
3895 if key_type.is_none() {
3896 key_type = Some(copy_type(ty, budget, &selector)?);
3897 }
3898 }
3899 }
3900 let mut groups = Vec::new();
3901 if !elements.is_empty() {
3902 let mut fields = metadata_vec(2, budget, location)?;
3903 budget.charge("key".len() + "items".len(), location.clone())?;
3904 fields.push(("key".into(), key_type.unwrap_or(ValueType::Unestablished)));
3905 fields.push((
3906 "items".into(),
3907 ValueType::Array(ArrayType::Elements(elements)),
3908 ));
3909 push_metadata(&mut groups, ValueType::Record(fields), budget, location)?;
3910 }
3911 push_metadata(
3912 &mut result,
3913 ValueType::Array(ArrayType::Elements(groups)),
3914 budget,
3915 location,
3916 )?;
3917 }
3918 Ok(result)
3919 }
3920 ValueExpressionKind::Require {
3921 condition,
3922 value,
3923 message,
3924 } => {
3925 self.condition(condition, budget)?;
3926 let types = self.walk(value, budget)?;
3927 allocation::<u8>(message.value.len(), location)?;
3928 budget.charge(message.value.len(), Location::Query(message.range.clone()))?;
3929 Ok(types)
3930 }
3931 ValueExpressionKind::Range { lower, upper } => {
3932 for expression in [lower, upper] {
3933 for ty in self.walk(expression, budget)? {
3934 require_type(&ty, ScalarRequirement::Integer, location)?;
3935 }
3936 }
3937 one_type(
3938 ValueType::Set(Some(SetElementType::Integer)),
3939 budget,
3940 location,
3941 )
3942 }
3943 ValueExpressionKind::Conditional {
3944 branches,
3945 otherwise,
3946 } => {
3947 let mut types = Vec::new();
3948 for (condition, branch) in branches {
3949 self.condition(condition, budget)?;
3950 append_types(
3951 &mut types,
3952 self.walk_control(branch, budget, transfer)?,
3953 budget,
3954 location,
3955 )?;
3956 }
3957 append_types(
3958 &mut types,
3959 self.walk_control(otherwise, budget, transfer)?,
3960 budget,
3961 location,
3962 )?;
3963 Ok(types)
3964 }
3965 ValueExpressionKind::Loop { states, body } => {
3966 let mut initial = metadata_vec(states.len(), budget, location)?;
3967 for (_, value) in states {
3968 initial.push(self.walk(value, budget)?);
3969 }
3970 let saved = self.locals.len();
3971 self.queries.enter_scope(budget, &expression.range)?;
3972 let result = (|| {
3973 for ((name, value), facts) in states.iter().zip(initial) {
3974 function_local(name, &self.locals, budget)?;
3975 if self.global_exists(&name.value, name.range.clone(), budget)? {
3976 return Err(error(
3977 &Location::Query(name.range.clone()),
3978 "binding shadows an existing source or let",
3979 ));
3980 }
3981 self.queries.prepare_local(name, value, &facts, budget)?;
3982 push_metadata(
3983 &mut self.locals,
3984 (name.value.as_str(), facts),
3985 budget,
3986 location,
3987 )?;
3988 }
3989 self.queries.prepare_computation(expression, budget)?;
3990 self.walk_control(body, budget, Some(states.len()))
3991 })();
3992 self.locals.truncate(saved);
3993 self.queries.leave_scope();
3994 result
3995 }
3996 ValueExpressionKind::Break(value) => self.walk(value, budget),
3997 ValueExpressionKind::Continue(values) => {
3998 for value in values {
3999 self.walk(value, budget)?;
4000 }
4001 Ok(Vec::new())
4002 }
4003 ValueExpressionKind::Block { bindings, value } => {
4004 let saved = self.locals.len();
4005 self.queries.enter_scope(budget, &expression.range)?;
4006 let result = (|| {
4007 for (pattern, value) in bindings {
4008 let types = self.walk(value, budget)?;
4009 self.pattern(pattern, &types, false, budget)?;
4010 self.queries.prepare_pattern(pattern, value, budget)?;
4011 }
4012 self.walk_control(value, budget, transfer)
4013 })();
4014 self.locals.truncate(saved);
4015 self.queries.leave_scope();
4016 result
4017 }
4018 ValueExpressionKind::ValueMatch { subject, arms } => {
4019 if arms.is_empty()
4020 || !matches!(
4021 arms.last().map(|a| (&a.pattern.value, &a.guard)),
4022 Some((PatternKind::Wildcard, None))
4023 )
4024 {
4025 return Err(error(
4026 location,
4027 "value match needs a final unguarded wildcard",
4028 ));
4029 }
4030 let facts = self.walk(subject, budget)?;
4031 let mut types = Vec::new();
4032 for (index, arm) in arms.iter().enumerate() {
4033 if index + 1 < arms.len()
4034 && matches!(arm.pattern.value, PatternKind::Wildcard)
4035 && arm.guard.is_none()
4036 {
4037 return Err(error(
4038 &Location::Query(arm.pattern.range.clone()),
4039 "unguarded wildcard must be the final arm",
4040 ));
4041 }
4042 let saved = self.locals.len();
4043 self.queries.enter_scope(budget, &arm.pattern.range)?;
4044 let result = (|| {
4045 self.pattern(&arm.pattern, &facts, false, budget)?;
4046 self.queries
4047 .prepare_pattern(&arm.pattern, subject, budget)?;
4048 if let Some(guard) = &arm.guard {
4049 self.condition(guard, budget)?;
4050 }
4051 self.walk_control(&arm.value, budget, transfer)
4052 })();
4053 self.locals.truncate(saved);
4054 self.queries.leave_scope();
4055 append_types(&mut types, result?, budget, location)?;
4056 }
4057 Ok(types)
4058 }
4059 ValueExpressionKind::Comprehension {
4060 constructor,
4061 clauses,
4062 head,
4063 } => {
4064 let saved = self.locals.len();
4065 let result = (|| {
4066 self.clauses(clauses, budget)?;
4067 let types = self.walk(head, budget)?;
4068 let ty = match constructor {
4069 ValueConstructor::Array => ValueType::Array(ArrayType::Elements(types)),
4070 ValueConstructor::Set => {
4071 let mut element_type = None;
4072 merge_set_types(&mut element_type, &types, budget, location)?;
4073 ValueType::Set(element_type)
4074 }
4075 };
4076 one_type(ty, budget, location)
4077 })();
4078 self.locals.truncate(saved);
4079 result
4080 }
4081 }
4082 }
4083
4084 fn scoped_types(
4085 &mut self,
4086 predicate: &'a PredicateArgument<Q>,
4087 source: &'a ValueExpression<Q>,
4088 types: &[ValueType],
4089 element: bool,
4090 budget: &mut Budget,
4091 ) -> Result<Vec<ValueType>, QueryError> {
4092 let range = &predicate.body.range;
4093 let location = Location::Query(range.clone());
4094 let saved = self.locals.len();
4095 self.queries.enter_scope(budget, range)?;
4096 let result = (|| {
4097 push_metadata(
4098 &mut self.locals,
4099 (PREDICATE_SUBJECT, copy_types(types, budget, &location)?),
4100 budget,
4101 &location,
4102 )?;
4103 if let Some(pattern) = &predicate.argument {
4104 self.pattern(pattern, types, true, budget)?;
4105 }
4106 self.queries.prepare_predicate(
4107 predicate.argument.as_ref(),
4108 source,
4109 types,
4110 element,
4111 budget,
4112 )?;
4113 self.walk(&predicate.body, budget)
4114 })();
4115 self.locals.truncate(saved);
4116 self.queries.leave_scope();
4117 result
4118 }
4119
4120 fn pattern(
4121 &mut self,
4122 pattern: &'a Pattern,
4123 facts: &[ValueType],
4124 required: bool,
4125 budget: &mut Budget,
4126 ) -> Result<(), QueryError> {
4127 let names = if required {
4128 pattern::required_facts(pattern, facts, budget)?
4129 } else {
4130 pattern::facts(pattern, facts, budget)?
4131 };
4132 for (name, facts) in names {
4133 let location = Location::Query(name.range.clone());
4134 function_local(name, &self.locals, budget)?;
4135 if self.global_exists(&name.value, name.range.clone(), budget)? {
4136 return Err(error(
4137 &location,
4138 "binding shadows an existing source or let",
4139 ));
4140 }
4141 push_metadata(
4142 &mut self.locals,
4143 (name.value.as_str(), facts),
4144 budget,
4145 &location,
4146 )?;
4147 }
4148 Ok(())
4149 }
4150
4151 fn clauses(
4152 &mut self,
4153 clauses: &'a [Located<ValueGenerator<Q>>],
4154 budget: &mut Budget,
4155 ) -> Result<(), QueryError> {
4156 for clause in clauses {
4157 let clause_location = Location::Query(clause.range.clone());
4158 budget.charge(1, clause_location.clone())?;
4159 match &clause.value {
4160 ValueGenerator::In {
4161 binders,
4162 source,
4163 filter,
4164 } => {
4165 if binders.is_empty() {
4166 return Err(error(&clause_location, "in generator needs a binder"));
4167 }
4168 let source_types = self.walk(source, budget)?;
4169 let mut elements = Vec::new();
4170 for ty in source_types {
4171 match shape_type(ty, budget, &clause_location)? {
4172 ValueType::Array(
4173 ArrayType::Positions(entries) | ArrayType::Elements(entries),
4174 )
4175 | ValueType::ArrayKind(entries) => {
4176 append_types(&mut elements, entries, budget, &clause_location)?
4177 }
4178 ValueType::KeyedArray(keyed) => append_types(
4179 &mut elements,
4180 keyed.elements,
4181 budget,
4182 &clause_location,
4183 )?,
4184 ValueType::Set(element_type) => push_metadata(
4185 &mut elements,
4186 set_value_type(element_type),
4187 budget,
4188 &clause_location,
4189 )?,
4190 ValueType::Unestablished => push_metadata(
4191 &mut elements,
4192 ValueType::Unestablished,
4193 budget,
4194 &clause_location,
4195 )?,
4196 _ => {
4197 return Err(error(
4198 &Location::Query(source.range.clone()),
4199 "in source needs an array or supported set",
4200 ));
4201 }
4202 }
4203 }
4204 if elements.is_empty() {
4205 push_metadata(
4206 &mut elements,
4207 ValueType::Unestablished,
4208 budget,
4209 &clause_location,
4210 )?;
4211 }
4212 for binder in binders {
4213 self.pattern(binder, &elements, false, budget)?;
4214 self.queries
4215 .prepare_generator(binder, source, &elements, true, budget)?;
4216 }
4217 if let Some(filter) = filter {
4218 self.condition(filter, budget)?;
4219 }
4220 }
4221 ValueGenerator::Bind {
4222 binder,
4223 value,
4224 filter,
4225 } => {
4226 let types = self.walk(value, budget)?;
4227 self.pattern(binder, &types, false, budget)?;
4228 self.queries
4229 .prepare_generator(binder, value, &types, false, budget)?;
4230 if let Some(filter) = filter {
4231 self.condition(filter, budget)?;
4232 }
4233 }
4234 }
4235 }
4236 Ok(())
4237 }
4238
4239 fn condition(
4240 &mut self,
4241 condition: &'a ValueExpression<Q>,
4242 budget: &mut Budget,
4243 ) -> Result<(), QueryError> {
4244 let location = Location::Query(condition.range.clone());
4245 for ty in self.walk(condition, budget)? {
4246 budget.charge(1, location.clone())?;
4247 require_type(&ty, ScalarRequirement::Boolean, &location)?;
4248 }
4249 Ok(())
4250 }
4251
4252 fn axis_sources(
4253 &mut self,
4254 sources: &'a [ValueExpression<Q>],
4255 budget: &mut Budget,
4256 location: &Location,
4257 ) -> Result<Vec<Option<ValueKeyType>>, QueryError> {
4258 if sources.is_empty() {
4259 return Err(error(location, "axis sources need nonzero rank"));
4260 }
4261 let mut facts = metadata_vec(sources.len(), budget, location)?;
4262 for source in sources {
4263 let types = self.walk(source, budget)?;
4264 facts.push(source_key_type(
4265 &types,
4266 budget,
4267 &Location::Query(source.range.clone()),
4268 )?);
4269 }
4270 Ok(facts)
4271 }
4272
4273 fn positions(
4277 &mut self,
4278 children: impl Iterator<Item = &'a ValueExpression<Q>>,
4279 budget: &mut Budget,
4280 location: &Location,
4281 ) -> Result<Vec<Vec<ValueType>>, QueryError> {
4282 let mut positions = metadata_vec(1, budget, location)?;
4283 positions.push(Vec::new());
4284 for child in children {
4285 let types = self.walk(child, budget)?;
4286 positions = extend_type_positions(&positions, &types, budget, location)?;
4287 }
4288 Ok(positions)
4289 }
4290}
4291
4292fn zip_exact_type(
4293 left: &ValueType,
4294 right: &ValueType,
4295 budget: &mut Budget,
4296 location: &Location,
4297) -> Result<ValueType, QueryError> {
4298 if matches!(left, ValueType::Declared { .. }) || matches!(right, ValueType::Declared { .. }) {
4299 let left = shape_type(copy_type(left, budget, location)?, budget, location)?;
4300 let right = shape_type(copy_type(right, budget, location)?, budget, location)?;
4301 return zip_exact_type(&left, &right, budget, location);
4302 }
4303 let deferred = [ValueType::Unestablished];
4304 let [left, right] = [left, right].map(|ty| match ty {
4305 ValueType::KeyedArray(keyed) => Ok((keyed.axes.as_deref(), keyed.elements.as_slice())),
4306 ValueType::ArrayKind(elements) => Ok((None, elements.as_slice())),
4307 ValueType::Unestablished => Ok((None, deferred.as_slice())),
4308 _ => Err(error(location, "zip_exact needs keyed arrays")),
4309 });
4310 let (left_axes, a) = left?;
4311 let (right_axes, b) = right?;
4312 if let (Some(a), Some(b)) = (left_axes, right_axes)
4313 && !same_axis_types(a, b, budget, location)?
4314 {
4315 return Err(error(
4316 location,
4317 "zip_exact needs identical axis rank and types",
4318 ));
4319 }
4320 let axes = match left_axes.or(right_axes) {
4321 Some(axes) => Some(copy_axis_types(axes, budget, location)?),
4322 None => None,
4323 };
4324 let mut elements = Vec::new();
4325 for a in a {
4326 for b in b {
4327 let mut pair = metadata_vec(2, budget, location)?;
4328 pair.push(copy_type(a, budget, location)?);
4329 pair.push(copy_type(b, budget, location)?);
4330 push_metadata(&mut elements, ValueType::Tuple(pair), budget, location)?;
4331 }
4332 }
4333 Ok(ValueType::KeyedArray(KeyedArrayType { axes, elements }))
4334}
4335
4336fn key_component_type(
4339 ty: &ValueType,
4340 location: &Location,
4341) -> Result<Option<ValueKeyType>, QueryError> {
4342 match ty {
4343 ValueType::Declared {
4344 actual,
4345 declaration,
4346 } => {
4347 if !matches!(
4348 actual.as_ref(),
4349 ValueType::Unestablished | ValueType::ScalarKind
4350 ) {
4351 return key_component_type(actual, location);
4352 }
4353 match underlying(declaration) {
4354 DeclaredType::Integer => Ok(Some(ValueKeyType::Integer)),
4355 DeclaredType::Member(id) if !matches!(actual.as_ref(), ValueType::ScalarKind) => {
4356 Ok(Some(ValueKeyType::Member(*id)))
4357 }
4358 _ => Err(error(location, "key components need integers or members")),
4359 }
4360 }
4361 ValueType::Integer | ValueType::ScalarKind => Ok(Some(ValueKeyType::Integer)),
4364 ValueType::Member(id) => Ok(Some(ValueKeyType::Member(*id))),
4365 ValueType::Unestablished => Ok(None),
4366 _ => Err(error(location, "key components need integers or members")),
4367 }
4368}
4369
4370fn merge_key_facts(
4371 facts: &mut Option<Vec<Option<ValueKeyType>>>,
4372 types: &[ValueType],
4373 budget: &mut Budget,
4374 location: &Location,
4375) -> Result<(), QueryError> {
4376 for ty in types {
4377 budget.charge(1, location.clone())?;
4378 let normalized = if matches!(ty, ValueType::Declared { .. }) {
4379 Some(shape_type(
4380 copy_type(ty, budget, location)?,
4381 budget,
4382 location,
4383 )?)
4384 } else {
4385 None
4386 };
4387 let ty = normalized.as_ref().unwrap_or(ty);
4388 let components = match ty {
4389 ValueType::Unestablished | ValueType::TupleKind => continue,
4390 ValueType::Tuple(types) if !types.is_empty() => {
4391 let mut result = metadata_vec(types.len(), budget, location)?;
4392 for ty in types {
4393 budget.charge(1, location.clone())?;
4394 result.push(key_component_type(ty, location)?);
4395 }
4396 result
4397 }
4398 ValueType::Integer | ValueType::ScalarKind | ValueType::Member(_) => {
4399 let mut result = metadata_vec(1, budget, location)?;
4400 result.push(key_component_type(ty, location)?);
4401 result
4402 }
4403 _ => {
4404 return Err(error(
4405 location,
4406 "key needs an integer, member or nonempty flat tuple",
4407 ));
4408 }
4409 };
4410 match facts {
4411 Some(previous) => {
4412 if previous.len() != components.len() {
4413 return Err(error(location, "key rank mismatch"));
4414 }
4415 for (previous, ty) in previous.iter_mut().zip(components) {
4416 budget.charge(1, location.clone())?;
4417 if previous.is_some() && ty.is_some() && *previous != ty {
4418 return Err(error(location, "incompatible keyed dimension type"));
4419 }
4420 if previous.is_none() {
4421 *previous = ty;
4422 }
4423 }
4424 }
4425 None => *facts = Some(components),
4426 }
4427 }
4428 Ok(())
4429}
4430
4431fn check_key_facts(
4432 facts: &Option<Vec<Option<ValueKeyType>>>,
4433 axes: &[ValueKeyType],
4434 budget: &mut Budget,
4435 location: &Location,
4436) -> Result<(), QueryError> {
4437 if let Some(facts) = facts {
4438 if facts.len() != axes.len() {
4439 return Err(error(location, "key rank mismatch"));
4440 }
4441 for (fact, axis) in facts.iter().zip(axes) {
4442 budget.charge(1, location.clone())?;
4443 if fact.is_some_and(|fact| fact != *axis) {
4444 return Err(error(location, "incompatible keyed dimension type"));
4445 }
4446 }
4447 }
4448 Ok(())
4449}
4450
4451fn established_facts(
4452 facts: Option<Vec<Option<ValueKeyType>>>,
4453 budget: &mut Budget,
4454 location: &Location,
4455) -> Result<Option<Vec<ValueKeyType>>, QueryError> {
4456 let Some(facts) = facts else {
4457 return Ok(None);
4458 };
4459 let mut axes = metadata_vec(facts.len(), budget, location)?;
4460 for fact in facts {
4461 budget.charge(1, location.clone())?;
4462 let Some(fact) = fact else {
4463 return Ok(None);
4464 };
4465 axes.push(fact);
4466 }
4467 Ok(Some(axes))
4468}
4469
4470fn source_key_type(
4471 types: &[ValueType],
4472 budget: &mut Budget,
4473 location: &Location,
4474) -> Result<Option<ValueKeyType>, QueryError> {
4475 let mut result = None;
4476 for ty in types {
4477 budget.charge(1, location.clone())?;
4478 let normalized = if matches!(ty, ValueType::Declared { .. }) {
4479 Some(shape_type(
4480 copy_type(ty, budget, location)?,
4481 budget,
4482 location,
4483 )?)
4484 } else {
4485 None
4486 };
4487 let ty = normalized.as_ref().unwrap_or(ty);
4488 let keys = match ty {
4489 ValueType::Array(ArrayType::Positions(elements) | ArrayType::Elements(elements))
4490 | ValueType::ArrayKind(elements)
4491 | ValueType::KeyedArray(KeyedArrayType { elements, .. }) => {
4492 let mut key_type = None;
4493 for ty in elements {
4494 budget.charge(1, location.clone())?;
4495 let ty = key_component_type(ty, location)?;
4496 if key_type.is_some() && ty.is_some() && key_type != ty {
4497 return Err(error(location, "incompatible axis source type"));
4498 }
4499 if ty.is_some() {
4500 key_type = ty;
4501 }
4502 }
4503 key_type
4504 }
4505 ValueType::Set(Some(SetElementType::Integer)) => Some(ValueKeyType::Integer),
4506 ValueType::Set(Some(SetElementType::Member(id))) => Some(ValueKeyType::Member(*id)),
4507 ValueType::Set(None) | ValueType::Unestablished => None,
4508 _ => {
4509 return Err(error(
4510 location,
4511 "axis source needs an integer or member array/set",
4512 ));
4513 }
4514 };
4515 if result.is_some() && keys.is_some() && result != keys {
4516 return Err(error(location, "incompatible axis source type"));
4517 }
4518 if keys.is_some() {
4519 result = keys;
4520 }
4521 }
4522 Ok(result)
4523}
4524
4525fn check_source_facts(
4526 facts: &Option<Vec<Option<ValueKeyType>>>,
4527 sources: &[Option<ValueKeyType>],
4528 budget: &mut Budget,
4529 location: &Location,
4530) -> Result<(), QueryError> {
4531 if let Some(facts) = facts {
4532 if facts.len() != sources.len() {
4533 return Err(error(location, "axis source rank mismatch"));
4534 }
4535 for (fact, source) in facts.iter().zip(sources) {
4536 budget.charge(1, location.clone())?;
4537 if fact.is_some() && source.is_some() && *fact != *source {
4538 return Err(error(location, "incompatible axis source type"));
4539 }
4540 }
4542 }
4543 Ok(())
4544}
4545
4546#[derive(Clone, Copy)]
4547enum ScalarRequirement {
4548 String,
4549 Boolean,
4550 Integer,
4551 Numeric,
4552}
4553
4554pub(crate) fn predicate_types(
4555 types: &[ValueType],
4556 budget: &mut Budget,
4557 range: &std::ops::Range<usize>,
4558) -> Result<(), QueryError> {
4559 let location = Location::Query(range.clone());
4560 for ty in types {
4561 budget.charge(1, location.clone())?;
4562 require_type(ty, ScalarRequirement::Boolean, &location)?;
4563 }
4564 Ok(())
4565}
4566
4567fn require_type(
4568 ty: &ValueType,
4569 requirement: ScalarRequirement,
4570 location: &Location,
4571) -> Result<(), QueryError> {
4572 if let ValueType::Declared {
4573 actual,
4574 declaration,
4575 } = ty
4576 {
4577 if !matches!(
4578 actual.as_ref(),
4579 ValueType::Unestablished | ValueType::ScalarKind
4580 ) {
4581 return require_type(actual, requirement, location);
4582 }
4583 let expected = underlying(declaration);
4584 let accepted = match requirement {
4585 ScalarRequirement::String => matches!(expected, DeclaredType::String),
4586 ScalarRequirement::Boolean => matches!(expected, DeclaredType::Boolean),
4587 ScalarRequirement::Integer => matches!(expected, DeclaredType::Integer),
4588 ScalarRequirement::Numeric => {
4589 matches!(expected, DeclaredType::Integer | DeclaredType::Float)
4590 }
4591 };
4592 if accepted {
4593 return Ok(());
4594 }
4595 return Err(error(location, "incompatible declared operand type"));
4596 }
4597 let accepted = matches!(ty, ValueType::Unestablished | ValueType::ScalarKind)
4598 || match requirement {
4599 ScalarRequirement::String => matches!(ty, ValueType::String),
4600 ScalarRequirement::Boolean => matches!(ty, ValueType::Boolean),
4601 ScalarRequirement::Integer => matches!(ty, ValueType::Integer),
4602 ScalarRequirement::Numeric => matches!(ty, ValueType::Integer | ValueType::Float),
4603 };
4604 if !accepted {
4605 return Err(error(
4606 location,
4607 match requirement {
4608 ScalarRequirement::String => "dictionary key needs a present string",
4609 ScalarRequirement::Boolean => "condition needs a fixed Boolean",
4610 ScalarRequirement::Integer => "operation needs integers",
4611 ScalarRequirement::Numeric => "operation needs numeric operands",
4612 },
4613 ));
4614 }
4615 Ok(())
4616}
4617
4618fn set_value_type(ty: Option<SetElementType>) -> ValueType {
4619 match ty {
4620 Some(SetElementType::Boolean) => ValueType::Boolean,
4621 Some(SetElementType::Integer) => ValueType::Integer,
4622 Some(SetElementType::Float) => ValueType::Float,
4623 Some(SetElementType::Member(id)) => ValueType::Member(id),
4624 None => ValueType::Unestablished,
4625 }
4626}
4627
4628fn merge_set_types(
4629 element_type: &mut Option<SetElementType>,
4630 types: &[ValueType],
4631 budget: &mut Budget,
4632 location: &Location,
4633) -> Result<(), QueryError> {
4634 for ty in types {
4635 budget.charge(1, location.clone())?;
4636 let normalized = if matches!(ty, ValueType::Declared { .. }) {
4637 Some(shape_type(
4638 copy_type(ty, budget, location)?,
4639 budget,
4640 location,
4641 )?)
4642 } else {
4643 None
4644 };
4645 let ty = normalized.as_ref().unwrap_or(ty);
4646 let ty = match ty {
4647 ValueType::Boolean => SetElementType::Boolean,
4648 ValueType::Integer => SetElementType::Integer,
4649 ValueType::Float => SetElementType::Float,
4650 ValueType::Member(id) => SetElementType::Member(*id),
4651 ValueType::Unestablished => continue,
4652 _ => {
4653 return Err(error(
4654 location,
4655 "set elements must have one supported scalar type",
4656 ));
4657 }
4658 };
4659 if element_type.is_some_and(|previous| previous != ty) {
4660 return Err(error(
4661 location,
4662 "set elements must have one supported scalar type",
4663 ));
4664 }
4665 *element_type = Some(ty);
4666 }
4667 Ok(())
4668}
4669
4670fn compatible_types(
4671 left: &ValueType,
4672 right: &ValueType,
4673 budget: &mut Budget,
4674 location: &Location,
4675) -> Result<bool, QueryError> {
4676 budget.within_evaluation(1, location.clone(), |budget| {
4677 budget.charge(1, location.clone())?;
4678 if let ValueType::Declared { declaration, .. } = left {
4679 if let ValueType::Declared {
4680 declaration: expected,
4681 ..
4682 } = right
4683 {
4684 return compatible_declarations(declaration, expected, budget, location);
4685 }
4686 let expected = DeclaredType::Optional(Box::new(copy_declaration(
4687 underlying(declaration),
4688 budget,
4689 location,
4690 )?));
4691 check_known_type(right, &expected, budget, location)?;
4692 return Ok(true);
4693 }
4694 if matches!(right, ValueType::Declared { .. }) {
4695 return compatible_types(right, left, budget, location);
4696 }
4697 Ok(match (left, right) {
4698 (ValueType::Absent, _) | (_, ValueType::Absent) => true,
4699 (ValueType::Unestablished, _) | (_, ValueType::Unestablished) => true,
4700 (
4701 ValueType::ScalarKind,
4702 ValueType::ScalarKind
4703 | ValueType::Boolean
4704 | ValueType::Integer
4705 | ValueType::Float
4706 | ValueType::String,
4707 )
4708 | (
4709 ValueType::Boolean | ValueType::Integer | ValueType::Float | ValueType::String,
4710 ValueType::ScalarKind,
4711 ) => true,
4712 (ValueType::Boolean, ValueType::Boolean)
4713 | (ValueType::Integer, ValueType::Integer)
4714 | (ValueType::Float, ValueType::Float)
4715 | (ValueType::String, ValueType::String) => true,
4716 (ValueType::RecordKind, ValueType::RecordKind | ValueType::Record(_))
4717 | (ValueType::Record(_), ValueType::RecordKind)
4718 | (ValueType::TupleKind, ValueType::TupleKind | ValueType::Tuple(_))
4719 | (ValueType::Tuple(_), ValueType::TupleKind) => true,
4720 (ValueType::Member(a), ValueType::Member(b)) => a == b,
4721 (ValueType::ArrayKind(a), ValueType::ArrayKind(b))
4722 | (
4723 ValueType::ArrayKind(a),
4724 ValueType::Array(ArrayType::Positions(b) | ArrayType::Elements(b)),
4725 )
4726 | (
4727 ValueType::Array(ArrayType::Positions(a) | ArrayType::Elements(a)),
4728 ValueType::ArrayKind(b),
4729 ) => compatible_keyed_elements(a, b, budget, location)?,
4730 (ValueType::ArrayKind(a), ValueType::KeyedArray(b)) => {
4731 compatible_keyed_elements(a, &b.elements, budget, location)?
4732 }
4733 (ValueType::KeyedArray(a), ValueType::ArrayKind(b)) => {
4734 compatible_keyed_elements(&a.elements, b, budget, location)?
4735 }
4736 (ValueType::KeyedArray(a), ValueType::KeyedArray(b)) => {
4737 if let (Some(a), Some(b)) = (&a.axes, &b.axes)
4738 && !same_axis_types(a, b, budget, location)?
4739 {
4740 return Ok(false);
4741 }
4742 compatible_keyed_elements(&a.elements, &b.elements, budget, location)?
4743 }
4744 (ValueType::Set(a), ValueType::Set(b)) => a.is_none() || b.is_none() || a == b,
4745 (ValueType::Tuple(a), ValueType::Tuple(b)) => {
4746 if a.len() != b.len() {
4747 return Ok(false);
4748 }
4749 for (a, b) in a.iter().zip(b) {
4750 if !compatible_types(a, b, budget, location)? {
4751 return Ok(false);
4752 }
4753 }
4754 true
4755 }
4756 (ValueType::Array(a), ValueType::Array(b)) => {
4757 match (a, b) {
4758 (ArrayType::Positions(a), ArrayType::Positions(b)) => {
4759 for (a, b) in a.iter().zip(b) {
4760 if !compatible_types(a, b, budget, location)? {
4761 return Ok(false);
4762 }
4763 }
4764 }
4765 (
4766 ArrayType::Positions(a) | ArrayType::Elements(a),
4767 ArrayType::Positions(b) | ArrayType::Elements(b),
4768 ) => {
4769 for a in a {
4770 for b in b {
4771 if !compatible_types(a, b, budget, location)? {
4772 return Ok(false);
4773 }
4774 }
4775 }
4776 }
4777 }
4778 true
4779 }
4780 (ValueType::Record(a), ValueType::Record(b)) => {
4781 if a.len() != b.len() {
4782 return Ok(false);
4783 }
4784 for (label, ty) in a {
4785 let mut other = None;
4786 for (other_label, other_ty) in b {
4787 budget.charge(
4788 sum(1, label.len().min(other_label.len()), location)?,
4789 location.clone(),
4790 )?;
4791 if label == other_label {
4792 other = Some(other_ty);
4793 break;
4794 }
4795 }
4796 let Some(other) = other else {
4797 return Ok(false);
4798 };
4799 if !compatible_types(ty, other, budget, location)? {
4800 return Ok(false);
4801 }
4802 }
4803 true
4804 }
4805 _ => false,
4806 })
4807 })
4808}
4809
4810fn compatible_keyed_elements(
4813 left: &[ValueType],
4814 right: &[ValueType],
4815 budget: &mut Budget,
4816 location: &Location,
4817) -> Result<bool, QueryError> {
4818 if left.is_empty() || right.is_empty() {
4819 return Ok(true);
4820 }
4821 for (types, alternatives) in [(left, right), (right, left)] {
4822 for ty in types {
4823 let mut compatible = false;
4824 for alternative in alternatives {
4825 if compatible_types(ty, alternative, budget, location)? {
4826 compatible = true;
4827 break;
4828 }
4829 }
4830 if !compatible {
4831 return Ok(false);
4832 }
4833 }
4834 }
4835 Ok(true)
4836}
4837
4838fn binary_type(
4839 operator: ValueBinaryOperator,
4840 left: &ValueType,
4841 right: &ValueType,
4842 budget: &mut Budget,
4843 location: &Location,
4844) -> Result<ValueType, QueryError> {
4845 if !matches!(
4846 operator,
4847 ValueBinaryOperator::Equal | ValueBinaryOperator::NotEqual
4848 ) && (matches!(left, ValueType::Declared { .. })
4849 || matches!(right, ValueType::Declared { .. }))
4850 {
4851 let left = shape_type(copy_type(left, budget, location)?, budget, location)?;
4852 let right = shape_type(copy_type(right, budget, location)?, budget, location)?;
4853 return binary_type(operator, &left, &right, budget, location);
4854 }
4855 match operator {
4856 ValueBinaryOperator::Add
4857 | ValueBinaryOperator::Subtract
4858 | ValueBinaryOperator::Multiply
4859 | ValueBinaryOperator::Divide
4860 | ValueBinaryOperator::Less
4861 | ValueBinaryOperator::LessEqual
4862 | ValueBinaryOperator::Greater
4863 | ValueBinaryOperator::GreaterEqual => {
4864 require_type(left, ScalarRequirement::Numeric, location)?;
4865 require_type(right, ScalarRequirement::Numeric, location)?;
4866 Ok(match operator {
4867 ValueBinaryOperator::Less
4868 | ValueBinaryOperator::LessEqual
4869 | ValueBinaryOperator::Greater
4870 | ValueBinaryOperator::GreaterEqual => ValueType::Boolean,
4871 ValueBinaryOperator::Divide => ValueType::Float,
4872 _ if matches!(left, ValueType::Float) || matches!(right, ValueType::Float) => {
4873 ValueType::Float
4874 }
4875 _ if matches!(left, ValueType::ScalarKind)
4876 || matches!(right, ValueType::ScalarKind) =>
4877 {
4878 ValueType::ScalarKind
4879 }
4880 _ if matches!(left, ValueType::Unestablished)
4881 || matches!(right, ValueType::Unestablished) =>
4882 {
4883 ValueType::Unestablished
4884 }
4885 _ => ValueType::Integer,
4886 })
4887 }
4888 ValueBinaryOperator::IntegerDivide | ValueBinaryOperator::Modulo => {
4889 require_type(left, ScalarRequirement::Integer, location)?;
4890 require_type(right, ScalarRequirement::Integer, location)?;
4891 Ok(ValueType::Integer)
4892 }
4893 ValueBinaryOperator::Contains
4894 | ValueBinaryOperator::StartsWith
4895 | ValueBinaryOperator::EndsWith => {
4896 if !matches!(
4897 left,
4898 ValueType::String | ValueType::ScalarKind | ValueType::Unestablished
4899 ) || !matches!(
4900 right,
4901 ValueType::String | ValueType::ScalarKind | ValueType::Unestablished
4902 ) {
4903 return Err(string_operand_error(budget, location));
4904 }
4905 Ok(ValueType::Boolean)
4906 }
4907 ValueBinaryOperator::And | ValueBinaryOperator::Or => {
4908 require_type(left, ScalarRequirement::Boolean, location)?;
4909 require_type(right, ScalarRequirement::Boolean, location)?;
4910 Ok(ValueType::Boolean)
4911 }
4912 ValueBinaryOperator::Equal | ValueBinaryOperator::NotEqual => {
4913 if !compatible_types(left, right, budget, location)? {
4914 return Err(error(location, "equality needs compatible types"));
4915 }
4916 Ok(ValueType::Boolean)
4917 }
4918 ValueBinaryOperator::In => {
4919 let mut element_type = None;
4920 let deferred_primitive = matches!(left, ValueType::ScalarKind)
4921 && matches!(
4922 right,
4923 ValueType::Unestablished
4924 | ValueType::Set(
4925 None | Some(
4926 SetElementType::Boolean
4927 | SetElementType::Integer
4928 | SetElementType::Float
4929 )
4930 )
4931 );
4932 if deferred_primitive {
4933 budget.charge(1, location.clone())?;
4934 } else {
4935 merge_set_types(
4936 &mut element_type,
4937 std::slice::from_ref(left),
4938 budget,
4939 location,
4940 )?;
4941 }
4942 match right {
4943 ValueType::Set(ty)
4944 if ty.is_none() || element_type.is_none() || ty == &element_type =>
4945 {
4946 Ok(ValueType::Boolean)
4947 }
4948 ValueType::Unestablished => Ok(ValueType::Boolean),
4949 _ => Err(error(
4950 location,
4951 "membership needs a compatible supported set",
4952 )),
4953 }
4954 }
4955 ValueBinaryOperator::Concatenate => match (left, right) {
4956 (ValueType::String, ValueType::String)
4957 | (
4958 ValueType::ScalarKind,
4959 ValueType::String | ValueType::ScalarKind | ValueType::Unestablished,
4960 )
4961 | (ValueType::String | ValueType::Unestablished, ValueType::ScalarKind) => {
4962 Ok(ValueType::String)
4963 }
4964 (ValueType::Array(a), ValueType::Array(b)) => {
4965 let (ArrayType::Positions(a_entries) | ArrayType::Elements(a_entries)) = a;
4966 let (ArrayType::Positions(b_entries) | ArrayType::Elements(b_entries)) = b;
4967 let mut entries = copy_types(a_entries, budget, location)?;
4968 append_types(
4969 &mut entries,
4970 copy_types(b_entries, budget, location)?,
4971 budget,
4972 location,
4973 )?;
4974 Ok(ValueType::Array(
4975 if matches!((a, b), (ArrayType::Positions(_), ArrayType::Positions(_))) {
4976 ArrayType::Positions(entries)
4977 } else {
4978 ArrayType::Elements(entries)
4979 },
4980 ))
4981 }
4982 (ValueType::Unestablished, other) | (other, ValueType::Unestablished)
4983 if matches!(
4984 other,
4985 ValueType::Unestablished | ValueType::String | ValueType::Array(_)
4986 ) =>
4987 {
4988 Ok(ValueType::Unestablished)
4989 }
4990 _ => Err(error(
4991 location,
4992 "concatenation needs two strings or two positional arrays",
4993 )),
4994 },
4995 }
4996}
4997
4998pub(crate) fn boolean(value: ConstructedValue, location: &Location) -> Result<bool, QueryError> {
4999 if let ConstructedValue::Boolean(value) = value.into_data() {
5000 Ok(value)
5001 } else {
5002 Err(error(location, "condition needs a fixed Boolean"))
5003 }
5004}
5005
5006fn integer(value: ConstructedValue, location: &Location) -> Result<i64, QueryError> {
5007 if let ConstructedValue::Integer(value) = value.into_data() {
5008 Ok(value)
5009 } else {
5010 Err(error(location, "operation needs integers"))
5011 }
5012}
5013
5014fn scalar(
5015 value: ConstructedValue,
5016 budget: &mut Budget,
5017 location: &Location,
5018) -> Result<ConstructedValue, QueryError> {
5019 budget.charge_results(1, location.clone())?;
5020 Ok(value)
5021}
5022
5023fn exact_float(value: i64, location: &Location) -> Result<f64, QueryError> {
5024 let magnitude = value.unsigned_abs();
5025 let significant_bits = u64::BITS - magnitude.leading_zeros();
5026 if significant_bits > 53 && magnitude.trailing_zeros() < significant_bits - 53 {
5027 return Err(error(
5028 location,
5029 "integer cannot be represented exactly as binary64",
5030 ));
5031 }
5032 Ok(value as f64)
5035}
5036
5037fn numeric_float(value: ConstructedValue, location: &Location) -> Result<f64, QueryError> {
5038 match value.into_data() {
5039 ConstructedValue::Integer(value) => exact_float(value, location),
5040 ConstructedValue::Float(value) => {
5041 finite(value, location)?;
5042 Ok(value)
5043 }
5044 _ => Err(error(location, "operation needs numeric operands")),
5045 }
5046}
5047
5048fn unary(
5049 operator: ValueUnaryOperator,
5050 value: ConstructedValue,
5051 budget: &mut Budget,
5052 location: &Location,
5053) -> Result<ConstructedValue, QueryError> {
5054 let value = match (operator, value.into_data()) {
5055 (ValueUnaryOperator::Not, value) => ConstructedValue::Boolean(!boolean(value, location)?),
5056 (
5057 ValueUnaryOperator::Positive,
5058 value @ (ConstructedValue::Integer(_) | ConstructedValue::Float(_)),
5059 ) => value,
5060 (ValueUnaryOperator::Negative, ConstructedValue::Integer(value)) => {
5061 ConstructedValue::Integer(
5062 value
5063 .checked_neg()
5064 .ok_or_else(|| error(location, "integer overflow"))?,
5065 )
5066 }
5067 (ValueUnaryOperator::Negative, ConstructedValue::Float(value)) => {
5068 ConstructedValue::Float(-value)
5069 }
5070 _ => return Err(error(location, "operation needs numeric operands")),
5071 };
5072 scalar(value, budget, location)
5073}
5074
5075fn string_operand_error(budget: &mut Budget, location: &Location) -> QueryError {
5076 let message = "string matching needs two strings";
5077 match budget.charge(message.len(), location.clone()) {
5078 Ok(()) => error(location, message),
5079 Err(error) => error,
5080 }
5081}
5082
5083fn string_match_ref(
5084 operator: ValueBinaryOperator,
5085 left: &ConstructedValue,
5086 right: &ConstructedValue,
5087 budget: &mut Budget,
5088 location: &Location,
5089) -> Result<ConstructedValue, QueryError> {
5090 let (ConstructedValue::String(text), ConstructedValue::String(search)) =
5091 (left.data(), right.data())
5092 else {
5093 return Err(string_operand_error(budget, location));
5094 };
5095 let work = if search.is_empty() {
5098 0
5099 } else if operator == ValueBinaryOperator::Contains {
5100 sum(text.len(), search.len(), location)?
5101 } else {
5102 text.len().min(search.len())
5103 };
5104 budget.charge(work, location.clone())?;
5105 let matched = match operator {
5106 ValueBinaryOperator::Contains => text.contains(search.as_str()),
5107 ValueBinaryOperator::StartsWith => text.starts_with(search.as_str()),
5108 ValueBinaryOperator::EndsWith => text.ends_with(search.as_str()),
5109 _ => unreachable!("string matching operator"),
5110 };
5111 scalar(ConstructedValue::Boolean(matched), budget, location)
5112}
5113
5114fn binary(
5115 operator: ValueBinaryOperator,
5116 left: ConstructedValue,
5117 right: ConstructedValue,
5118 budget: &mut Budget,
5119 location: &Location,
5120) -> Result<ConstructedValue, QueryError> {
5121 let (left, right) = if matches!(
5122 operator,
5123 ValueBinaryOperator::Equal | ValueBinaryOperator::NotEqual
5124 ) {
5125 (left, right)
5126 } else {
5127 (
5128 expose(left, budget, location)?,
5129 expose(right, budget, location)?,
5130 )
5131 };
5132 match operator {
5133 ValueBinaryOperator::Contains
5134 | ValueBinaryOperator::StartsWith
5135 | ValueBinaryOperator::EndsWith => {
5136 string_match_ref(operator, &left, &right, budget, location)
5137 }
5138 ValueBinaryOperator::Concatenate => match (left, right) {
5139 (ConstructedValue::String(left), ConstructedValue::String(right)) => {
5140 let len = sum(left.len(), right.len(), location)?;
5141 allocation::<u8>(len, location)?;
5142 budget.charge(len, location.clone())?;
5143 budget.charge_results(1, location.clone())?;
5144 let mut value = String::with_capacity(len);
5145 value.push_str(&left);
5146 value.push_str(&right);
5147 Ok(ConstructedValue::String(value))
5148 }
5149 (ConstructedValue::Array(left), ConstructedValue::Array(right)) => {
5150 let len = sum(left.len(), right.len(), location)?;
5151 let mut values = admit_container(len, budget, location)?;
5152 values.extend(left);
5153 values.extend(right);
5154 Ok(ConstructedValue::Array(values))
5155 }
5156 _ => Err(error(
5157 location,
5158 "concatenation needs two strings or two positional arrays",
5159 )),
5160 },
5161 ValueBinaryOperator::Equal | ValueBinaryOperator::NotEqual => {
5162 let equal = equal_values(&left, &right, budget, location)?;
5163 scalar(
5164 ConstructedValue::Boolean(if operator == ValueBinaryOperator::Equal {
5165 equal
5166 } else {
5167 !equal
5168 }),
5169 budget,
5170 location,
5171 )
5172 }
5173 ValueBinaryOperator::In => {
5174 let ConstructedValue::Set {
5175 element_type,
5176 elements,
5177 } = right
5178 else {
5179 return Err(error(location, "membership needs a supported set"));
5180 };
5181 let ty = scalar_set_type(&left)
5182 .ok_or_else(|| error(location, "membership needs a supported scalar"))?;
5183 if element_type.is_some_and(|element_type| element_type != ty) {
5184 return Err(error(location, "membership element type mismatch"));
5185 }
5186 let mut found = false;
5187 for value in &elements {
5188 if compare_set_values(&left, value, budget, location)? == Ordering::Equal {
5189 found = true;
5190 break;
5191 }
5192 }
5193 scalar(ConstructedValue::Boolean(found), budget, location)
5194 }
5195 ValueBinaryOperator::And | ValueBinaryOperator::Or => {
5196 let a = boolean(left, location)?;
5197 let b = boolean(right, location)?;
5198 scalar(
5199 ConstructedValue::Boolean(if operator == ValueBinaryOperator::And {
5200 a && b
5201 } else {
5202 a || b
5203 }),
5204 budget,
5205 location,
5206 )
5207 }
5208 ValueBinaryOperator::IntegerDivide | ValueBinaryOperator::Modulo => {
5209 let a = integer(left, location)?;
5210 let b = integer(right, location)?;
5211 if b == 0 {
5212 return Err(error(location, "division by zero"));
5213 }
5214 let value = if operator == ValueBinaryOperator::IntegerDivide {
5215 a.checked_div(b)
5216 } else {
5217 a.checked_rem(b)
5218 }
5219 .ok_or_else(|| error(location, "integer overflow"))?;
5220 scalar(ConstructedValue::Integer(value), budget, location)
5221 }
5222 ValueBinaryOperator::Add
5223 | ValueBinaryOperator::Subtract
5224 | ValueBinaryOperator::Multiply => {
5225 if let (ConstructedValue::Integer(a), ConstructedValue::Integer(b)) = (&left, &right) {
5226 let value = match operator {
5227 ValueBinaryOperator::Add => a.checked_add(*b),
5228 ValueBinaryOperator::Subtract => a.checked_sub(*b),
5229 ValueBinaryOperator::Multiply => a.checked_mul(*b),
5230 _ => unreachable!("integer arithmetic"),
5231 }
5232 .ok_or_else(|| error(location, "integer overflow"))?;
5233 return scalar(ConstructedValue::Integer(value), budget, location);
5234 }
5235 float_operation(
5236 operator,
5237 numeric_float(left, location)?,
5238 numeric_float(right, location)?,
5239 budget,
5240 location,
5241 )
5242 }
5243 ValueBinaryOperator::Divide => float_operation(
5244 operator,
5245 numeric_float(left, location)?,
5246 numeric_float(right, location)?,
5247 budget,
5248 location,
5249 ),
5250 ValueBinaryOperator::Less
5251 | ValueBinaryOperator::LessEqual
5252 | ValueBinaryOperator::Greater
5253 | ValueBinaryOperator::GreaterEqual => {
5254 let order = if let (ConstructedValue::Integer(a), ConstructedValue::Integer(b)) =
5255 (&left, &right)
5256 {
5257 a.cmp(b)
5258 } else {
5259 numeric_float(left, location)?
5260 .partial_cmp(&numeric_float(right, location)?)
5261 .expect("finite numeric operands")
5262 };
5263 let value = match operator {
5264 ValueBinaryOperator::Less => order == Ordering::Less,
5265 ValueBinaryOperator::LessEqual => order != Ordering::Greater,
5266 ValueBinaryOperator::Greater => order == Ordering::Greater,
5267 ValueBinaryOperator::GreaterEqual => order != Ordering::Less,
5268 _ => unreachable!("comparison"),
5269 };
5270 scalar(ConstructedValue::Boolean(value), budget, location)
5271 }
5272 }
5273}
5274
5275fn float_operation(
5276 operator: ValueBinaryOperator,
5277 a: f64,
5278 b: f64,
5279 budget: &mut Budget,
5280 location: &Location,
5281) -> Result<ConstructedValue, QueryError> {
5282 let (value, mathematically_zero) = match operator {
5283 ValueBinaryOperator::Add => (a + b, a == -b),
5284 ValueBinaryOperator::Subtract => (a - b, a == b),
5285 ValueBinaryOperator::Multiply => (a * b, a == 0.0 || b == 0.0),
5286 ValueBinaryOperator::Divide => {
5287 if b == 0.0 {
5288 return Err(error(location, "division by zero"));
5289 }
5290 (a / b, a == 0.0)
5291 }
5292 _ => unreachable!("floating arithmetic"),
5293 };
5294 finite(value, location)?;
5295 if value == 0.0 && !mathematically_zero {
5296 return Err(error(location, "nonzero floating result rounded to zero"));
5297 }
5298 scalar(ConstructedValue::Float(value), budget, location)
5299}
5300
5301fn equal_values(
5302 left: &ConstructedValue,
5303 right: &ConstructedValue,
5304 budget: &mut Budget,
5305 location: &Location,
5306) -> Result<bool, QueryError> {
5307 budget.within_evaluation(1, location.clone(), |budget| {
5308 budget.charge(1, location.clone())?;
5309 if declaration(left).is_some() || declaration(right).is_some() {
5310 let a = constructed_value_type(left, budget, location.clone())?;
5311 let b = constructed_value_type(right, budget, location.clone())?;
5312 if !compatible_types(&a, &b, budget, location)? {
5313 return Err(error(
5314 location,
5315 "equality needs compatible underlying types",
5316 ));
5317 }
5318 }
5319 Ok(match (left.data(), right.data()) {
5320 (ConstructedValue::Absent, ConstructedValue::Absent) => true,
5321 (ConstructedValue::Absent, _) | (_, ConstructedValue::Absent) => false,
5322 (ConstructedValue::Boolean(a), ConstructedValue::Boolean(b)) => a == b,
5323 (ConstructedValue::Integer(a), ConstructedValue::Integer(b)) => a == b,
5324 (ConstructedValue::Float(a), ConstructedValue::Float(b)) => a == b,
5325 (ConstructedValue::String(a), ConstructedValue::String(b)) => {
5326 budget.charge(a.len().min(b.len()), location.clone())?;
5327 a == b
5328 }
5329 (ConstructedValue::Member(a), ConstructedValue::Member(b)) => {
5330 check_member_pair(a, b, budget, location)?;
5331 if a.type_id != b.type_id {
5332 return Err(error(location, "equality needs compatible nominal types"));
5333 }
5334 a.member_id == b.member_id
5335 }
5336 (
5337 ConstructedValue::KeyedArray {
5338 axes: a,
5339 entries: a_entries,
5340 },
5341 ConstructedValue::KeyedArray {
5342 axes: b,
5343 entries: b_entries,
5344 },
5345 ) => {
5346 if a.len() != b.len() || a_entries.len() != b_entries.len() {
5347 return Ok(false);
5348 }
5349 for (a, b) in a.iter().zip(b) {
5350 budget.charge(1, location.clone())?;
5351 if a.key_type != b.key_type {
5352 return Err(error(location, "equality needs compatible keyed types"));
5353 }
5354 if !equal_keys(&a.keys, &b.keys, budget, location)? {
5355 return Ok(false);
5356 }
5357 }
5358 for (a, b) in a_entries.iter().zip(b_entries) {
5359 budget.charge(1, location.clone())?;
5360 if !equal_keys(&a.key, &b.key, budget, location)?
5361 || !equal_values(&a.value, &b.value, budget, location)?
5362 {
5363 return Ok(false);
5364 }
5365 }
5366 true
5367 }
5368 (ConstructedValue::Array(a), ConstructedValue::Array(b))
5369 | (ConstructedValue::Tuple(a), ConstructedValue::Tuple(b)) => {
5370 if a.len() != b.len() {
5371 return Ok(false);
5372 }
5373 for (a, b) in a.iter().zip(b) {
5374 if !equal_values(a, b, budget, location)? {
5375 return Ok(false);
5376 }
5377 }
5378 true
5379 }
5380 (
5381 ConstructedValue::Set {
5382 element_type: a_type,
5383 elements: a,
5384 },
5385 ConstructedValue::Set {
5386 element_type: b_type,
5387 elements: b,
5388 },
5389 ) => {
5390 if matches!((a_type, b_type), (Some(a), Some(b)) if a != b) {
5391 return Err(error(location, "equality needs compatible set types"));
5392 }
5393 if a.len() != b.len() {
5394 return Ok(false);
5395 }
5396 for value in a {
5397 let mut found = false;
5398 for other in b {
5399 if equal_values(value, other, budget, location)? {
5400 found = true;
5401 break;
5402 }
5403 }
5404 if !found {
5405 return Ok(false);
5406 }
5407 }
5408 true
5409 }
5410 (ConstructedValue::Record(a), ConstructedValue::Record(b)) => {
5411 if a.len() != b.len() {
5412 return Ok(false);
5413 }
5414 for (label, value) in a {
5415 let mut other = None;
5416 for (other_label, other_value) in b {
5417 budget.charge(
5418 sum(1, label.len().min(other_label.len()), location)?,
5419 location.clone(),
5420 )?;
5421 if label == other_label {
5422 other = Some(other_value);
5423 break;
5424 }
5425 }
5426 let Some(other) = other else {
5427 return Ok(false);
5428 };
5429 if !equal_values(value, other, budget, location)? {
5430 return Ok(false);
5431 }
5432 }
5433 true
5434 }
5435 _ => return Err(error(location, "equality needs compatible types")),
5436 })
5437 })
5438}
5439
5440fn run<'a, Q, H: ValueQueryHost<Q> + ?Sized>(
5441 expression: &'a PreparedValue<'a, Q>,
5442 queries: &mut H,
5443 locals: &mut Frame<'a>,
5444 budget: &mut Budget,
5445 check_value: &mut impl FnMut(&ConstructedValue, &mut Budget, &Location) -> Result<(), QueryError>,
5446) -> Result<ConstructedValue, H::Error> {
5447 let value = run_value(expression, queries, locals, budget, check_value)?;
5448 let location = Location::Query(expression.range.clone());
5449 budget.within_evaluation(1, location.clone(), |budget| {
5450 Ok(value.materialize(budget, &location)?)
5451 })
5452}
5453
5454struct PreparedArguments<'a, 'f, Q, F> {
5455 arguments: &'a [PreparedArgument<'a, Q>],
5456 frames: Vec<Frame<'a>>,
5457 check_value: &'f mut F,
5458}
5459impl<Q, E, F> ValueArguments<Q, E> for PreparedArguments<'_, '_, Q, F>
5460where
5461 E: From<QueryError>,
5462 F: FnMut(&ConstructedValue, &mut Budget, &Location) -> Result<(), QueryError>,
5463{
5464 fn evaluate(
5465 &mut self,
5466 expression: &ValueExpression<Q>,
5467 queries: &mut dyn ValueQueryHost<Q, Error = E>,
5468 budget: &mut Budget,
5469 ) -> Result<ConstructedRead, E> {
5470 let index = self
5471 .arguments
5472 .iter()
5473 .position(|argument| std::ptr::eq(argument.source, expression))
5474 .ok_or_else(|| {
5475 QueryError::query(
5476 expression.range.clone(),
5477 "argument was not prepared in this invocation",
5478 )
5479 })?;
5480 let value = run_value(
5481 &self.arguments[index].expression,
5482 queries,
5483 &mut self.frames[index],
5484 budget,
5485 self.check_value,
5486 )?;
5487 Ok(ConstructedRead {
5488 value,
5489 location: Location::Query(expression.range.clone()),
5490 declaration: None,
5491 })
5492 }
5493}
5494
5495fn run_value<'a, Q, H: ValueQueryHost<Q> + ?Sized>(
5496 expression: &'a PreparedValue<'a, Q>,
5497 queries: &mut H,
5498 locals: &mut Frame<'a>,
5499 budget: &mut Budget,
5500 check_value: &mut impl FnMut(&ConstructedValue, &mut Budget, &Location) -> Result<(), QueryError>,
5501) -> Result<RuntimeValue, H::Error> {
5502 execution::run_scalar(expression, queries, locals, budget, check_value)
5503}
5504
5505fn entries(
5506 array: ConstructedValue,
5507 budget: &mut Budget,
5508 location: &Location,
5509) -> Result<ConstructedValue, QueryError> {
5510 let array = expose(array, budget, location)?;
5511 let ConstructedValue::KeyedArray { axes, entries } = array else {
5512 return Err(error(location, "entries needs a keyed array"));
5513 };
5514 check_keyed(&axes, &entries, budget, location)?;
5515 let mut records = admit_container(entries.len(), budget, location)?;
5516 for entry in entries {
5517 budget.within_evaluation(2, location.clone(), |budget| {
5519 copy_size(&entry.value, budget, location).map(|_| ())
5520 })?;
5521 let key = if entry.key.len() == 1 {
5522 budget.charge(1, location.clone())?;
5523 key_value(entry.key.into_iter().next().expect("rank one"))
5524 } else {
5525 let mut components = admit_container(entry.key.len(), budget, location)?;
5526 for key in entry.key {
5527 budget.charge(1, location.clone())?;
5528 components.push(key_value(key));
5529 }
5530 ConstructedValue::Tuple(components)
5531 };
5532 budget.within_evaluation(2, location.clone(), |budget| {
5533 copy_size(&key, budget, location).map(|_| ())
5534 })?;
5535 let mut fields = admit_container(2, budget, location)?;
5536 budget.charge("key".len() + "value".len(), location.clone())?;
5537 fields.push(("key".into(), key));
5538 fields.push(("value".into(), entry.value));
5539 records.push(ConstructedValue::Record(fields));
5540 }
5541 Ok(ConstructedValue::Array(records))
5542}
5543
5544fn zip_exact(
5545 left: ConstructedValue,
5546 right: ConstructedValue,
5547 budget: &mut Budget,
5548 location: &Location,
5549) -> Result<ConstructedValue, QueryError> {
5550 let left = expose(left, budget, location)?;
5551 let right = expose(right, budget, location)?;
5552 let (
5553 ConstructedValue::KeyedArray {
5554 axes,
5555 entries: left,
5556 },
5557 ConstructedValue::KeyedArray {
5558 axes: right_axes,
5559 entries: right,
5560 },
5561 ) = (left, right)
5562 else {
5563 return Err(error(location, "zip_exact needs keyed arrays"));
5564 };
5565 check_keyed(&axes, &left, budget, location)?;
5566 check_keyed(&right_axes, &right, budget, location)?;
5567 budget.charge(1, location.clone())?;
5568 if axes.len() != right_axes.len() {
5569 return Err(error(location, "zip_exact needs identical ordered axes"));
5570 }
5571 for (a, b) in axes.iter().zip(&right_axes) {
5572 budget.charge(1, location.clone())?;
5573 if a.key_type != b.key_type || !equal_keys(&a.keys, &b.keys, budget, location)? {
5574 return Err(error(location, "zip_exact needs identical ordered axes"));
5575 }
5576 }
5577 budget.charge(1, location.clone())?;
5578 if left.len() != right.len() {
5579 return Err(error(location, "zip_exact needs identical present keys"));
5580 }
5581 let mut entries = admit_container(left.len(), budget, location)?;
5582 for (a, b) in left.into_iter().zip(right) {
5583 if !equal_keys(&a.key, &b.key, budget, location)? {
5584 return Err(error(location, "zip_exact needs identical present keys"));
5585 }
5586 budget.within_evaluation(2, location.clone(), |budget| {
5588 copy_size(&a.value, budget, location)?;
5589 copy_size(&b.value, budget, location).map(|_| ())
5590 })?;
5591 let mut pair = admit_container(2, budget, location)?;
5592 pair.push(a.value);
5593 pair.push(b.value);
5594 entries.push(KeyedEntry {
5595 key: a.key,
5596 value: ConstructedValue::Tuple(pair),
5597 });
5598 }
5599 Ok(ConstructedValue::KeyedArray { axes, entries })
5600}
5601
5602fn group_by(
5603 rows: ConstructedValue,
5604 field: &Located<String>,
5605 budget: &mut Budget,
5606 location: &Location,
5607) -> Result<ConstructedValue, QueryError> {
5608 let rows = expose(rows, budget, location)?;
5609 let ConstructedValue::Array(rows) = rows else {
5610 return Err(error(location, "group_by needs a positional array"));
5611 };
5612 let selector = Location::Query(field.range.clone());
5613 let mut groups = admit_container(0, budget, location)?;
5614 let mut key_type = None;
5615 for row in rows {
5616 budget.charge(1, location.clone())?;
5617 let ConstructedValue::Record(fields) = row.data() else {
5618 return Err(error(location, "group_by needs record rows"));
5619 };
5620 budget.within_evaluation(2, location.clone(), |budget| {
5623 copy_size(&row, budget, location).map(|_| ())
5624 })?;
5625 let mut key = None;
5626 for (label, value) in fields {
5627 budget.charge(
5628 sum(1, label.len().min(field.value.len()), &selector)?,
5629 selector.clone(),
5630 )?;
5631 if label == &field.value {
5632 key = Some(value);
5633 break;
5634 }
5635 }
5636 let Some(key) = key else {
5637 admit_diagnostic("missing record field: ", &field.value, budget, &selector)?;
5638 return Err(error(
5639 &selector,
5640 format!("missing record field: {}", field.value),
5641 ));
5642 };
5643 let ty = match key.data() {
5644 ConstructedValue::Integer(_) => ValueType::Integer,
5645 ConstructedValue::String(_) => ValueType::String,
5646 ConstructedValue::Member(member) => ValueType::Member(member.type_id),
5647 _ => {
5648 return Err(error(
5649 &selector,
5650 "group_by keys need integers, strings or nominal members",
5651 ));
5652 }
5653 };
5654 budget.charge(1, selector.clone())?;
5655 if key_type.as_ref().is_some_and(|previous| previous != &ty) {
5656 return Err(error(&selector, "group_by needs homogeneous key types"));
5657 }
5658 key_type = Some(ty);
5659 let mut matched = None;
5660 for (index, group) in groups.iter().enumerate() {
5661 let ConstructedValue::Record(fields) = group else {
5662 unreachable!("group record")
5663 };
5664 if equal_values(key, &fields[0].1, budget, &selector)? {
5665 matched = Some(index);
5666 break;
5667 }
5668 }
5669 let index = match matched {
5670 Some(index) => index,
5671 None => {
5672 let key = copy_constructed_value(key, budget, selector.clone())?;
5673 let mut fields = admit_container(2, budget, location)?;
5674 budget.charge("key".len() + "items".len(), location.clone())?;
5675 fields.push(("key".into(), key));
5676 fields.push((
5677 "items".into(),
5678 ConstructedValue::Array(admit_container(0, budget, location)?),
5679 ));
5680 allocation::<ConstructedValue>(sum(groups.len(), 1, location)?, location)?;
5681 budget.charge(1, location.clone())?;
5682 budget.charge_results(1, location.clone())?;
5683 groups.push(ConstructedValue::Record(fields));
5684 groups.len() - 1
5685 }
5686 };
5687 let ConstructedValue::Record(fields) = &mut groups[index] else {
5688 unreachable!("group record")
5689 };
5690 let ConstructedValue::Array(items) = &mut fields[1].1 else {
5691 unreachable!("group items")
5692 };
5693 allocation::<ConstructedValue>(sum(items.len(), 1, location)?, location)?;
5694 budget.charge(1, location.clone())?;
5695 budget.charge_results(1, location.clone())?;
5696 items.push(row);
5697 }
5698 Ok(ConstructedValue::Array(groups))
5699}
5700
5701fn filter_elements(
5703 ty: ValueType,
5704 budget: &mut Budget,
5705 location: &Location,
5706) -> Result<Vec<ValueType>, QueryError> {
5707 match shape_type(ty, budget, location)? {
5708 ValueType::Array(ArrayType::Positions(elements) | ArrayType::Elements(elements))
5709 | ValueType::ArrayKind(elements) => Ok(elements),
5710 ValueType::Unestablished => one_type(ValueType::Unestablished, budget, location),
5711 _ => Err(error(location, "filter needs a positional array")),
5712 }
5713}
5714
5715fn scalar_pipeline_elements(
5717 ty: ValueType,
5718 tally: bool,
5719 budget: &mut Budget,
5720 location: &Location,
5721) -> Result<Vec<ValueType>, QueryError> {
5722 let elements = match shape_type(ty, budget, location)? {
5723 ValueType::Array(ArrayType::Positions(elements) | ArrayType::Elements(elements))
5724 | ValueType::ArrayKind(elements) => elements,
5725 ValueType::Unestablished => return one_type(ValueType::Unestablished, budget, location),
5726 _ => return Err(error(location, "collection stage needs a positional array")),
5727 };
5728 let mut element_type = None;
5729 for element in &elements {
5730 budget.charge(1, location.clone())?;
5731 let ty = shape_type(copy_type(element, budget, location)?, budget, location)?;
5732 if matches!(ty, ValueType::Unestablished) {
5733 continue;
5734 }
5735 if tally {
5736 if ty != ValueType::String {
5737 return Err(error(location, "tally needs strings"));
5738 }
5739 } else if !matches!(
5740 ty,
5741 ValueType::Boolean
5742 | ValueType::Integer
5743 | ValueType::Float
5744 | ValueType::String
5745 | ValueType::Member(_)
5746 ) {
5747 return Err(error(location, "unique needs homogeneous scalar elements"));
5748 }
5749 if element_type
5750 .as_ref()
5751 .is_some_and(|previous| previous != &ty)
5752 {
5753 return Err(error(location, "unique needs homogeneous scalar elements"));
5754 }
5755 element_type = Some(ty);
5756 }
5757 Ok(elements)
5758}
5759
5760fn unique_value(
5761 mut array: ConstructedValue,
5762 budget: &mut Budget,
5763 location: &Location,
5764) -> Result<ConstructedValue, QueryError> {
5765 if declaration(&array).is_some() {
5766 scalar_pipeline_elements(
5767 constructed_value_type(&array, budget, location.clone())?,
5768 false,
5769 budget,
5770 location,
5771 )?;
5772 }
5773 let mut data = &mut array;
5774 while let ConstructedValue::Declared { value, .. } = data {
5775 data = value;
5776 }
5777 let ConstructedValue::Array(rows) = data else {
5778 return Err(error(location, "unique needs a positional array"));
5779 };
5780 let mut element_type = None;
5781 let mut retained = 0;
5782 let mut strings = HashSet::new();
5783 for index in 0..rows.len() {
5784 budget.charge(1, location.clone())?;
5785 let ty = match rows[index].data() {
5786 ConstructedValue::Boolean(_) => ValueType::Boolean,
5787 ConstructedValue::Integer(_) => ValueType::Integer,
5788 ConstructedValue::Float(value) => {
5789 finite(*value, location)?;
5790 ValueType::Float
5791 }
5792 ConstructedValue::String(_) => ValueType::String,
5793 ConstructedValue::Member(member) => {
5794 member_bytes(member, budget, location)?;
5795 ValueType::Member(member.type_id)
5796 }
5797 _ => return Err(error(location, "unique needs homogeneous scalar elements")),
5798 };
5799 if element_type
5800 .as_ref()
5801 .is_some_and(|previous| previous != &ty)
5802 {
5803 return Err(error(location, "unique needs homogeneous scalar elements"));
5804 }
5805 element_type = Some(ty);
5806 let duplicate = if let ConstructedValue::String(key) = rows[index].data() {
5807 if declaration(&rows[index]).is_some() {
5808 constructed_value_type(&rows[index], budget, location.clone())?;
5809 }
5810 if index == 0 {
5811 allocation::<String>(rows.len(), location)?;
5813 budget.charge(rows.len() * size_of::<String>(), location.clone())?;
5814 strings
5815 .try_reserve(rows.len())
5816 .map_err(|_| error(location, "unique index allocation failed"))?;
5817 }
5818 budget.charge(sum(1, key.len(), location)?, location.clone())?;
5819 if strings.contains(key) {
5820 true
5821 } else {
5822 allocation::<u8>(key.len(), location)?;
5823 let bytes = sum(key.len(), key.len(), location)?;
5825 budget.charge(sum(2, bytes, location)?, location.clone())?;
5826 strings.insert(key.clone());
5827 false
5828 }
5829 } else {
5830 let mut duplicate = false;
5831 for previous in &rows[..retained] {
5832 if equal_values(previous, &rows[index], budget, location)? {
5833 duplicate = true;
5834 break;
5835 }
5836 }
5837 duplicate
5838 };
5839 if !duplicate {
5840 rows.swap(retained, index);
5841 retained += 1;
5842 }
5843 }
5844 rows.truncate(retained);
5845 Ok(array)
5846}
5847
5848fn tally_value(
5849 array: ConstructedValue,
5850 budget: &mut Budget,
5851 location: &Location,
5852) -> Result<ConstructedValue, QueryError> {
5853 if declaration(&array).is_some() {
5854 scalar_pipeline_elements(
5855 constructed_value_type(&array, budget, location.clone())?,
5856 true,
5857 budget,
5858 location,
5859 )?;
5860 }
5861 let ConstructedValue::Array(rows) = array.data() else {
5862 return Err(error(location, "tally needs a positional array"));
5863 };
5864 for row in rows {
5865 budget.charge(1, location.clone())?;
5866 if !matches!(row.data(), ConstructedValue::String(_)) {
5867 return Err(error(location, "tally needs strings"));
5868 }
5869 }
5870 let ConstructedValue::Array(rows) = expose(array, budget, location)? else {
5871 unreachable!("checked positional array")
5872 };
5873 let mut fields: Vec<(String, ConstructedValue)> = metadata_vec(rows.len(), budget, location)?;
5874 budget.charge(1, location.clone())?;
5875 budget.charge_results(1, location.clone())?;
5876 for row in rows {
5877 budget.charge(1, location.clone())?;
5878 let ConstructedValue::String(label) = expose(row, budget, location)? else {
5879 return Err(error(location, "tally needs strings"));
5880 };
5881 let mut existing = None;
5882 for (previous, count) in &mut fields {
5883 budget.charge(
5884 sum(1, previous.len().min(label.len()), location)?,
5885 location.clone(),
5886 )?;
5887 if *previous == label {
5888 existing = Some(count);
5889 break;
5890 }
5891 }
5892 if let Some(ConstructedValue::Integer(count)) = existing {
5893 *count = count
5894 .checked_add(1)
5895 .ok_or_else(|| error(location, "tally count overflow"))?;
5896 continue;
5897 }
5898 budget.charge(2, location.clone())?;
5899 budget.charge_results(2, location.clone())?;
5900 fields.push((label, ConstructedValue::Integer(1)));
5901 }
5902 Ok(ConstructedValue::Record(fields))
5903}
5904
5905fn sort_type(
5906 ty: ValueType,
5907 selector: Option<&Located<SortSelector>>,
5908 budget: &mut Budget,
5909 location: &Location,
5910) -> Result<ValueType, QueryError> {
5911 let retained = match &ty {
5912 ValueType::Declared { declaration, .. } => {
5913 Some(copy_declaration(declaration, budget, location)?)
5914 }
5915 _ => None,
5916 };
5917 let selected = selector.map_or_else(
5918 || location.clone(),
5919 |selector| Location::Query(selector.range.clone()),
5920 );
5921 let field = match selector {
5922 Some(Located {
5923 value: SortSelector::Field(field),
5924 range,
5925 }) => Some(Located::new(field.as_str(), range.clone())),
5926 _ => None,
5927 };
5928 let ty = match shape_type(ty, budget, location)? {
5929 ty @ (ValueType::Array(_) | ValueType::ArrayKind(_)) => {
5930 if matches!(
5931 selector.map(|selector| &selector.value),
5932 Some(SortSelector::Value)
5933 ) {
5934 return Err(error(&selected, "value ordering needs a dictionary"));
5935 }
5936 ValueType::Array(ArrayType::Elements(ordering_elements(
5937 ty, field, budget, location,
5938 )?))
5939 }
5940 ty @ ValueType::Set(_) => {
5941 if selector.is_some() {
5942 return Err(error(&selected, "set sorting uses its scalar values"));
5943 }
5944 ty
5945 }
5946 ValueType::Record(fields) => {
5947 if selector.is_some() {
5948 check_ordering_types(
5949 fields.iter().map(|(_, value)| value),
5950 field,
5951 budget,
5952 &selected,
5953 )?;
5954 }
5955 ValueType::Record(fields)
5956 }
5957 ty @ (ValueType::RecordKind | ValueType::Unestablished) => ty,
5958 _ => return Err(error(location, "sort needs an array, set or dictionary")),
5959 };
5960 Ok(if let Some(declaration) = retained {
5961 ValueType::Declared {
5962 actual: Box::new(ty),
5963 declaration,
5964 }
5965 } else {
5966 ty
5967 })
5968}
5969
5970fn ordering_elements(
5972 ty: ValueType,
5973 field: Option<Located<&str>>,
5974 budget: &mut Budget,
5975 location: &Location,
5976) -> Result<Vec<ValueType>, QueryError> {
5977 let elements = match shape_type(ty, budget, location)? {
5978 ValueType::Array(ArrayType::Positions(elements) | ArrayType::Elements(elements))
5979 | ValueType::ArrayKind(elements) => elements,
5980 ValueType::Unestablished => return one_type(ValueType::Unestablished, budget, location),
5981 _ => return Err(error(location, "ordering needs a positional array")),
5982 };
5983 let selector = field.as_ref().map_or_else(
5984 || location.clone(),
5985 |field| Location::Query(field.range.clone()),
5986 );
5987 check_ordering_types(elements.iter(), field, budget, &selector)?;
5988 Ok(elements)
5989}
5990
5991fn check_ordering_types<'a>(
5992 elements: impl IntoIterator<Item = &'a ValueType>,
5993 field: Option<Located<&str>>,
5994 budget: &mut Budget,
5995 selector: &Location,
5996) -> Result<(), QueryError> {
5997 let mut key_type = None;
5998 for element in elements {
5999 budget.charge(1, selector.clone())?;
6000 let ty = shape_type(copy_type(element, budget, selector)?, budget, selector)?;
6001 let ty = if let Some(field) = &field {
6002 match ty {
6003 ValueType::Record(fields) => {
6004 let mut selected = ValueType::Unestablished;
6005 for (label, ty) in fields {
6006 budget.charge(
6007 sum(1, label.len().min(field.value.len()), selector)?,
6008 selector.clone(),
6009 )?;
6010 if label == field.value {
6011 selected = ty;
6012 break;
6013 }
6014 }
6015 selected
6016 }
6017 ValueType::RecordKind | ValueType::Unestablished | ValueType::Absent => continue,
6018 _ => return Err(error(selector, "field ordering needs record rows")),
6019 }
6020 } else {
6021 ty
6022 };
6023 let ty = shape_type(ty, budget, selector)?;
6024 match ty {
6025 ValueType::Absent | ValueType::Unestablished => continue,
6028 ValueType::Integer | ValueType::Float | ValueType::String | ValueType::Member(_) => {}
6029 _ => {
6030 return Err(error(
6031 selector,
6032 "ordering keys need integers, finite floats, strings or nominal members",
6033 ));
6034 }
6035 }
6036 if key_type.as_ref().is_some_and(|previous| previous != &ty) {
6037 return Err(error(selector, "ordering needs homogeneous key types"));
6038 }
6039 key_type = Some(ty);
6040 }
6041 Ok(())
6042}
6043
6044#[derive(Clone, Copy, PartialEq, Eq)]
6045pub(crate) enum OrderingKeyType {
6046 Integer,
6047 Float,
6048 String,
6049 Member(NominalTypeId),
6050}
6051
6052pub(crate) fn ordering_key<'a>(
6053 row: &'a ConstructedValue,
6054 field: Option<&str>,
6055 budget: &mut Budget,
6056 location: &Location,
6057) -> Result<(&'a ConstructedValue, OrderingKeyType), QueryError> {
6058 budget.charge(1, location.clone())?;
6059 let key = if let Some(field) = field {
6060 let ConstructedValue::Record(fields) = row.data() else {
6061 return Err(error(location, "field ordering needs record rows"));
6062 };
6063 let mut key = None;
6064 for (label, value) in fields {
6065 budget.charge(
6066 sum(1, label.len().min(field.len()), location)?,
6067 location.clone(),
6068 )?;
6069 if label == field {
6070 key = Some(value);
6071 break;
6072 }
6073 }
6074 key.ok_or_else(|| error(location, "missing ordering field"))?
6075 } else {
6076 row
6077 };
6078 let key = key.data();
6079 let ty = match key {
6080 ConstructedValue::Integer(_) => OrderingKeyType::Integer,
6081 ConstructedValue::Float(value) => {
6082 finite(*value, location)?;
6083 OrderingKeyType::Float
6084 }
6085 ConstructedValue::String(_) => OrderingKeyType::String,
6086 ConstructedValue::Member(member) => {
6087 member_bytes(member, budget, location)?;
6088 OrderingKeyType::Member(member.type_id)
6089 }
6090 ConstructedValue::Absent => return Err(error(location, "ordering keys must be present")),
6091 _ => {
6092 return Err(error(
6093 location,
6094 "ordering keys need integers, finite floats, strings or nominal members",
6095 ));
6096 }
6097 };
6098 Ok((key, ty))
6099}
6100
6101pub(crate) fn compare_ordering_keys(
6102 left: &ConstructedValue,
6103 right: &ConstructedValue,
6104 budget: &mut Budget,
6105 location: &Location,
6106) -> Result<Ordering, QueryError> {
6107 budget.charge(1, location.clone())?;
6108 match (left, right) {
6109 (ConstructedValue::Integer(a), ConstructedValue::Integer(b)) => Ok(a.cmp(b)),
6110 (ConstructedValue::Float(a), ConstructedValue::Float(b)) => a
6111 .partial_cmp(b)
6112 .ok_or_else(|| error(location, "nonfinite float")),
6113 (ConstructedValue::String(a), ConstructedValue::String(b)) => {
6114 for (a, b) in a.bytes().zip(b.bytes()) {
6115 budget.charge(1, location.clone())?;
6116 let order = a.cmp(&b);
6117 if order != Ordering::Equal {
6118 return Ok(order);
6119 }
6120 }
6121 Ok(a.len().cmp(&b.len()))
6122 }
6123 (ConstructedValue::Member(a), ConstructedValue::Member(b)) if a.type_id == b.type_id => {
6124 check_member_pair(a, b, budget, location)?;
6125 Ok(a.declaration_order.cmp(&b.declaration_order))
6126 }
6127 _ => Err(error(location, "ordering needs homogeneous key types")),
6128 }
6129}
6130
6131#[derive(Clone, Copy)]
6132enum SortKey<'a> {
6133 Value(&'a ConstructedValue),
6134 Label(&'a str),
6135}
6136
6137#[derive(Clone, Copy)]
6138struct OrderingRow<'a> {
6139 index: usize,
6140 key: SortKey<'a>,
6141}
6142
6143fn sort_value(
6144 mut collection: ConstructedValue,
6145 selector: Option<&Located<SortSelector>>,
6146 descending: bool,
6147 budget: &mut Budget,
6148 location: &Location,
6149) -> Result<ConstructedValue, QueryError> {
6150 if declaration(&collection).is_some() {
6151 sort_type(
6152 constructed_value_type(&collection, budget, location.clone())?,
6153 selector,
6154 budget,
6155 location,
6156 )?;
6157 }
6158 let selected = selector.map_or_else(
6159 || location.clone(),
6160 |selector| Location::Query(selector.range.clone()),
6161 );
6162 let field = match selector.map(|selector| &selector.value) {
6163 Some(SortSelector::Field(field)) => Some(field.as_str()),
6164 _ => None,
6165 };
6166 let data = collection.data();
6167 let count = match data {
6168 ConstructedValue::Array(rows) => {
6169 if matches!(
6170 selector.map(|selector| &selector.value),
6171 Some(SortSelector::Value)
6172 ) {
6173 return Err(error(&selected, "value ordering needs a dictionary"));
6174 }
6175 rows.len()
6176 }
6177 ConstructedValue::Set { elements, .. } => {
6178 if selector.is_some() {
6179 return Err(error(&selected, "set sorting uses its scalar values"));
6180 }
6181 elements.len()
6182 }
6183 ConstructedValue::Record(fields) => fields.len(),
6184 _ => return Err(error(location, "sort needs an array, set or dictionary")),
6185 };
6186 let mut order: Vec<OrderingRow<'_>> = metadata_vec(count, budget, location)?;
6187 let mut key_type = None;
6188 for index in 0..count {
6189 let key = match data {
6190 ConstructedValue::Set { elements, .. } => {
6191 budget.charge(1, selected.clone())?;
6192 SortKey::Value(elements[index].data())
6193 }
6194 ConstructedValue::Record(fields) if selector.is_none() => {
6195 budget.charge(1, selected.clone())?;
6196 SortKey::Label(&fields[index].0)
6197 }
6198 _ => {
6199 let row = match data {
6200 ConstructedValue::Array(rows) => &rows[index],
6201 ConstructedValue::Record(fields) => &fields[index].1,
6202 _ => unreachable!("checked collection kind"),
6203 };
6204 let (key, ty) = ordering_key(row, field, budget, &selected)?;
6205 if key_type.is_some_and(|previous| previous != ty) {
6206 return Err(error(&selected, "ordering needs homogeneous key types"));
6207 }
6208 if let (Some(first), ConstructedValue::Member(member)) = (order.first(), key)
6209 && let SortKey::Value(ConstructedValue::Member(first)) = first.key
6210 {
6211 check_member_pair(first, member, budget, &selected)?;
6212 }
6213 key_type = Some(ty);
6214 SortKey::Value(key)
6215 }
6216 };
6217 order.push(OrderingRow { index, key });
6218 }
6219 let mut scratch = metadata_vec(order.len(), budget, location)?;
6220 scratch.extend_from_slice(&order);
6221 let mut width = 1;
6222 while width < order.len() {
6223 budget.charge(order.len(), location.clone())?;
6225 let mut start = 0;
6226 while start < order.len() {
6227 let middle = start.saturating_add(width).min(order.len());
6228 let end = middle.saturating_add(width).min(order.len());
6229 let (mut left, mut right) = (start, middle);
6230 for slot in &mut scratch[start..end] {
6231 let take_left = if right == end {
6232 true
6233 } else if left == middle {
6234 false
6235 } else {
6236 let order = match (order[left].key, order[right].key) {
6237 (SortKey::Label(left), SortKey::Label(right)) => {
6238 crate::ordering::compare_text(left, right, budget, &selected)?
6239 }
6240 (SortKey::Value(left), SortKey::Value(right))
6241 if matches!(data, ConstructedValue::Set { .. }) =>
6242 {
6243 compare_set_values(left, right, budget, &selected)?
6244 }
6245 (SortKey::Value(left), SortKey::Value(right)) => {
6246 compare_ordering_keys(left, right, budget, &selected)?
6247 }
6248 _ => unreachable!("one collection key kind"),
6249 };
6250 if descending {
6251 order != Ordering::Less
6252 } else {
6253 order != Ordering::Greater
6254 }
6255 };
6256 *slot = if take_left {
6257 let row = order[left];
6258 left += 1;
6259 row
6260 } else {
6261 let row = order[right];
6262 right += 1;
6263 row
6264 };
6265 }
6266 start = end;
6267 }
6268 std::mem::swap(&mut order, &mut scratch);
6269 width = width.saturating_mul(2);
6270 }
6271 let mut destinations = metadata_vec(order.len(), budget, location)?;
6272 destinations.resize(order.len(), 0);
6273 for (destination, row) in order.iter().enumerate() {
6274 budget.charge(1, location.clone())?;
6275 destinations[row.index] = destination;
6276 }
6277 drop(order);
6280 drop(scratch);
6281 let mut data = &mut collection;
6282 while let ConstructedValue::Declared { value, .. } = data {
6283 data = value;
6284 }
6285 for index in 0..count {
6286 while destinations[index] != index {
6287 budget.charge(1, location.clone())?;
6288 let destination = destinations[index];
6289 match data {
6290 ConstructedValue::Array(rows) | ConstructedValue::Set { elements: rows, .. } => {
6291 rows.swap(index, destination)
6292 }
6293 ConstructedValue::Record(fields) => fields.swap(index, destination),
6294 _ => unreachable!("checked collection kind"),
6295 }
6296 destinations.swap(index, destination);
6297 }
6298 }
6299 Ok(collection)
6300}
6301
6302fn extremum_position(
6303 operator: ValueExtremum,
6304 array: &ConstructedValue,
6305 field: Option<&Located<String>>,
6306 budget: &mut Budget,
6307 location: &Location,
6308) -> Result<Option<usize>, QueryError> {
6309 let ConstructedValue::Array(rows) = array.data() else {
6310 return Err(error(location, "ordering needs a positional array"));
6311 };
6312 let selector = field.map_or_else(
6313 || location.clone(),
6314 |field| Location::Query(field.range.clone()),
6315 );
6316 let mut selected: Option<(usize, &ConstructedValue)> = None;
6317 let mut key_type = None;
6318 for (index, row) in rows.iter().enumerate() {
6319 let (key, ty) = ordering_key(
6320 row,
6321 field.map(|field| field.value.as_str()),
6322 budget,
6323 &selector,
6324 )?;
6325 if key_type.is_some_and(|previous| previous != ty) {
6326 return Err(error(&selector, "ordering needs homogeneous key types"));
6327 }
6328 key_type = Some(ty);
6329 let replace = match selected {
6330 None => true,
6331 Some((_, previous)) => {
6332 let order = compare_ordering_keys(key, previous, budget, &selector)?;
6333 order
6334 == if operator == ValueExtremum::Min {
6335 Ordering::Less
6336 } else {
6337 Ordering::Greater
6338 }
6339 }
6340 };
6341 if replace {
6342 selected = Some((index, key));
6343 }
6344 }
6345 Ok(selected.map(|(index, _)| index))
6346}
6347
6348fn reduce_ref(
6349 operator: ValueReducer,
6350 array: &ConstructedValue,
6351 budget: &mut Budget,
6352 location: &Location,
6353) -> Result<ConstructedValue, QueryError> {
6354 let array = array.data();
6355 let (positional, keyed) = match &array {
6357 ConstructedValue::Array(values) => (values.as_slice(), &[][..]),
6358 ConstructedValue::KeyedArray { entries, .. } => (&[][..], entries.as_slice()),
6359 _ => return Err(error(location, "reducer needs an array")),
6360 };
6361 let len = positional.len().max(keyed.len());
6362 let values = positional
6363 .iter()
6364 .chain(keyed.iter().map(|entry| &entry.value));
6365 let value = match operator {
6366 ValueReducer::Length => {
6367 budget.charge(1, location.clone())?;
6368 ConstructedValue::Integer(
6369 i64::try_from(len).map_err(|_| error(location, "length overflow"))?,
6370 )
6371 }
6372 ValueReducer::Sum => {
6373 let mut total = 0_i64;
6374 for value in values {
6375 budget.charge(1, location.clone())?;
6376 let ConstructedValue::Integer(value) = value.data() else {
6377 return Err(error(location, "sum needs integer array elements"));
6378 };
6379 total = total
6380 .checked_add(*value)
6381 .ok_or_else(|| error(location, "integer sum overflow"))?;
6382 }
6383 ConstructedValue::Integer(total)
6384 }
6385 ValueReducer::Forall | ValueReducer::Exists => {
6386 let mut result = operator == ValueReducer::Forall;
6387 for value in values {
6388 budget.charge(1, location.clone())?;
6389 let ConstructedValue::Boolean(value) = value.data() else {
6390 return Err(error(
6391 location,
6392 "quantifier needs fixed Boolean array elements",
6393 ));
6394 };
6395 if operator == ValueReducer::Forall {
6397 result &= value;
6398 } else {
6399 result |= value;
6400 }
6401 }
6402 ConstructedValue::Boolean(result)
6403 }
6404 };
6405 scalar(value, budget, location)
6406}
6407
6408fn take_position(
6409 values: Vec<ConstructedValue>,
6410 position: usize,
6411 budget: &mut Budget,
6412 location: &Location,
6413) -> Result<ConstructedValue, QueryError> {
6414 let index = position
6415 .checked_sub(1)
6416 .filter(|index| *index < values.len())
6417 .ok_or_else(|| error(location, "missing collection position"))?;
6418 budget.charge(sum(index, 1, location)?, location.clone())?;
6421 Ok(values.into_iter().nth(index).expect("position checked"))
6422}
6423
6424fn integer_range(
6425 lower: i64,
6426 upper: i64,
6427 budget: &mut Budget,
6428 location: &Location,
6429) -> Result<ConstructedValue, QueryError> {
6430 let len = if upper < lower {
6431 0
6432 } else {
6433 usize::try_from(i128::from(upper) - i128::from(lower) + 1)
6434 .map_err(|_| error(location, "range cardinality overflow"))?
6435 };
6436 allocation::<ConstructedValue>(len, location)?;
6437 budget.charge(len, location.clone())?;
6438 let units = sum(
6439 1,
6440 len.checked_mul(2)
6441 .ok_or_else(|| error(location, "range allocation overflow"))?,
6442 location,
6443 )?;
6444 budget.charge_results(units, location.clone())?;
6445 let mut elements = Vec::with_capacity(len);
6446 for offset in 0..len {
6447 let value = i64::try_from(i128::from(lower) + offset as i128)
6448 .map_err(|_| error(location, "range value overflow"))?;
6449 elements.push(ConstructedValue::Integer(value));
6450 }
6451 Ok(ConstructedValue::Set {
6452 element_type: Some(SetElementType::Integer),
6453 elements,
6454 })
6455}
6456
6457fn insert_set(
6458 values: &mut Vec<ConstructedValue>,
6459 element_type: &mut Option<SetElementType>,
6460 value: ConstructedValue,
6461 admit_slot: bool,
6462 budget: &mut Budget,
6463 location: &Location,
6464) -> Result<(), QueryError> {
6465 let ty = scalar_set_type(&value)
6466 .ok_or_else(|| error(location, "set elements must have one supported scalar type"))?;
6467 if element_type.is_some_and(|previous| previous != ty) {
6468 return Err(error(location, "set element type mismatch"));
6469 }
6470 *element_type = Some(ty);
6471 match value.data() {
6472 ConstructedValue::Float(value) => finite(*value, location)?,
6473 ConstructedValue::Member(member) => {
6474 for previous in values.iter() {
6475 if let ConstructedValue::Member(previous) = previous.data() {
6476 check_member_pair(previous, member, budget, location)?;
6477 }
6478 }
6479 }
6480 _ => {}
6481 }
6482 for existing in values.iter() {
6483 if compare_set_values(&value, existing, budget, location)? == Ordering::Equal {
6484 return Ok(());
6485 }
6486 }
6487 allocation::<ConstructedValue>(sum(values.len(), 1, location)?, location)?;
6488 if admit_slot {
6489 budget.charge_results(1, location.clone())?;
6490 }
6491 values.push(value);
6492 Ok(())
6493}
6494
6495pub fn copy_value_types(
6500 types: &[ValueType],
6501 budget: &mut Budget,
6502 location: Location,
6503) -> Result<Vec<ValueType>, QueryError> {
6504 copy_types(types, budget, &location)
6505}
6506
6507pub(crate) fn extend_type_positions(
6509 positions: &[Vec<ValueType>],
6510 types: &[ValueType],
6511 budget: &mut Budget,
6512 location: &Location,
6513) -> Result<Vec<Vec<ValueType>>, QueryError> {
6514 let count = positions
6515 .len()
6516 .checked_mul(types.len())
6517 .ok_or_else(|| error(location, "type possibilities overflow"))?;
6518 let mut expanded = metadata_vec(count, budget, location)?;
6519 for position in positions {
6520 for ty in types {
6521 let mut entries = copy_types(position, budget, location)?;
6522 let ty = copy_type(ty, budget, location)?;
6523 push_metadata(&mut entries, ty, budget, location)?;
6524 expanded.push(entries);
6525 }
6526 }
6527 Ok(expanded)
6528}
6529
6530pub(crate) fn function_facts<K>(
6531 declaration: &DeclaredType<K>,
6532 budget: &mut Budget,
6533 location: &Location,
6534) -> Result<Vec<ValueType>, QueryError> {
6535 if crate::runtime_types::contains_native(declaration, budget, location)? {
6536 one_type(ValueType::Unestablished, budget, location)
6537 } else {
6538 let declaration =
6539 crate::runtime_types::constructed_declaration(declaration, budget, location)?;
6540 one_type(
6541 declared_fact(&declaration, ValueType::Unestablished, budget, location)?,
6542 budget,
6543 location,
6544 )
6545 }
6546}
6547
6548pub(crate) fn prepare_function_body<'a, Q, K, H: ValueQueryHost<Q>>(
6549 declaration: crate::functions::DeclarationRef<'a, Q, K>,
6550 queries: &mut H,
6551 budget: &mut Budget,
6552) -> Result<execution::Body<'a, Q, K>, QueryError> {
6553 let globals = BTreeMap::new();
6554 let mut analysis = Analysis::new(Globals::Facts(&globals), queries);
6555 let mut preparation = Preparation::new();
6556 for parameter in declaration.parameters.iter() {
6557 let types = function_facts(
6558 parameter.declaration,
6559 budget,
6560 &Location::Query(parameter.range.clone()),
6561 )?;
6562 match parameter.pattern {
6563 pattern::PatternRef::Name(name) => {
6564 function_local(name, &analysis.locals, budget)?;
6565 push_metadata(
6566 &mut analysis.locals,
6567 (name.value.as_str(), types),
6568 budget,
6569 &Location::Query(name.range.clone()),
6570 )?;
6571 push_metadata(
6572 &mut preparation.locals,
6573 name.value.as_str(),
6574 budget,
6575 &Location::Query(name.range.clone()),
6576 )?;
6577 }
6578 pattern::PatternRef::Pattern(pattern) => {
6579 analysis.pattern(pattern, &types, false, budget)?;
6580 pattern::names(pattern, &mut preparation.locals, budget)?;
6581 }
6582 }
6583 }
6584 let mut bindings = metadata_vec(
6585 declaration.bindings.len(),
6586 budget,
6587 &Location::Query(declaration.name.range.clone()),
6588 )?;
6589 for (name, value) in declaration.bindings {
6590 function_local(name, &analysis.locals, budget)?;
6591 let types = analysis.walk(value, budget)?;
6592 let expression = preparation.resolve(value, analysis.queries, budget)?;
6593 analysis
6594 .queries
6595 .prepare_local(name, value, &types, budget)?;
6596 push_metadata(
6597 &mut analysis.locals,
6598 (name.value.as_str(), types),
6599 budget,
6600 &Location::Query(name.range.clone()),
6601 )?;
6602 push_metadata(
6603 &mut preparation.locals,
6604 name.value.as_str(),
6605 budget,
6606 &Location::Query(name.range.clone()),
6607 )?;
6608 bindings.push((name.value.as_str(), expression));
6609 }
6610 analysis.walk(declaration.value, budget)?;
6611 let value = preparation.resolve(declaration.value, analysis.queries, budget)?;
6612 Ok(execution::Body {
6613 declaration,
6614 bindings,
6615 value,
6616 })
6617}
6618fn function_local(
6619 name: &Located<String>,
6620 locals: &[(&str, Vec<ValueType>)],
6621 budget: &mut Budget,
6622) -> Result<(), QueryError> {
6623 let location = Location::Query(name.range.clone());
6624 budget.charge(name.value.len() + 1, location.clone())?;
6625 if name.value == "_" {
6626 return Err(error(&location, "discard name cannot be bound"));
6627 }
6628 for (previous, _) in locals {
6629 budget.charge(1 + previous.len().min(name.value.len()), location.clone())?;
6630 if *previous == name.value {
6631 return Err(error(&location, "binding is already defined"));
6632 }
6633 }
6634 Ok(())
6635}
6636pub(crate) fn run_functions(
6637 declarations: &[crate::FunctionDeclaration],
6638 entry: &ValueExpression,
6639 bindings: &Bindings<ConstructedValue>,
6640 budget: &mut Budget,
6641 limits: crate::FunctionLimits,
6642) -> Result<ConstructedValue, crate::FunctionError<QueryError>> {
6643 let mut retained = Vec::new();
6644 for d in declarations {
6645 crate::projection::admit_slots::<crate::functions::DeclarationRef<'_, (), ()>>(
6646 1,
6647 budget,
6648 &d.name.range,
6649 )?;
6650 retained.push(d.as_borrowed().into());
6651 }
6652 run_function_refs(&retained, entry, bindings, budget, limits)
6653}
6654pub(crate) fn run_function_refs(
6655 declarations: &[crate::functions::DeclarationRef<'_, (), ()>],
6656 entry: &ValueExpression,
6657 bindings: &Bindings<ConstructedValue>,
6658 budget: &mut Budget,
6659 limits: crate::FunctionLimits,
6660) -> Result<ConstructedValue, crate::FunctionError<QueryError>> {
6661 let mut queries = NoQueries {
6662 bindings: Some(bindings),
6663 };
6664 let mut resolver = crate::functions::Resolver {
6665 queries: &mut queries,
6666 declarations,
6667 };
6668 let location = Location::Query(entry.range.clone());
6669 let mut bodies = metadata_vec(declarations.len(), budget, &location)?;
6670 for declaration in declarations {
6671 bodies.push(prepare_function_body(*declaration, &mut resolver, budget)?);
6672 }
6673 Analysis::new(Globals::Available(bindings), &mut resolver).walk(entry, budget)?;
6674 let mut preparation = Preparation::new();
6675 let entry = preparation.resolve(entry, &mut resolver, budget)?;
6676 let names = preparation.names;
6677 let mut frame = Frame::new(names.clone(), budget, &location)?;
6678 let mut calls = crate::functions::CallTrace::default();
6679 let mut check = |_: &ConstructedValue, _: &mut Budget, _: &Location| Ok(());
6680 let mut host = execution::ScalarHost {
6681 queries: &mut queries,
6682 frame: &mut frame,
6683 check: &mut check,
6684 query: std::marker::PhantomData,
6685 calls: &mut calls,
6686 };
6687 let result = execution::execute(
6688 &entry,
6689 &names,
6690 &bodies,
6691 &mut host,
6692 budget,
6693 limits.active_depth,
6694 0,
6695 )
6696 .and_then(|v| v.materialize(budget, &location));
6697 result.map_err(|error| crate::FunctionError {
6698 error,
6699 omitted_calls: calls.omitted,
6700 calls: calls
6701 .frames
6702 .into_iter()
6703 .map(|(id, range)| crate::FunctionCall {
6704 function: declarations[id].name.value.chars().take(64).collect(),
6705 range,
6706 })
6707 .collect(),
6708 })
6709}