1use source_map::SpanWithSource;
4
5use super::LocalInformation;
6use crate::{
7 context::information::merge_info, events::ApplicationResult, types::TypeStore, Environment,
8 FunctionId, TypeId,
9};
10
11pub trait CallCheckingBehavior {
13 const CHECK_PARAMETERS: bool;
15
16 fn get_latest_info<'a>(
17 &'a mut self,
18 environment: &'a mut Environment,
19 ) -> &'a mut LocalInformation;
20
21 fn in_recursive_cycle(&self, function_id: FunctionId) -> bool;
22
23 fn new_function_context<T>(
24 &mut self,
25 function_id: FunctionId,
26 cb: impl for<'a> FnOnce(&'a mut InvocationContext) -> T,
27 ) -> T;
28
29 fn debug_types(&self) -> bool {
30 false
31 }
32}
33
34pub struct CheckThings {
36 pub debug_types: bool,
37}
38
39impl CallCheckingBehavior for CheckThings {
40 const CHECK_PARAMETERS: bool = true;
41
42 fn get_latest_info<'a>(
43 &'a mut self,
44 environment: &'a mut Environment,
45 ) -> &'a mut LocalInformation {
46 &mut environment.info
47 }
48
49 fn in_recursive_cycle(&self, _function_id: FunctionId) -> bool {
50 false
52 }
53
54 fn new_function_context<T>(
55 &mut self,
56 function_id: FunctionId,
57 cb: impl for<'a> FnOnce(&'a mut InvocationContext) -> T,
58 ) -> T {
59 let mut target = InvocationContext(vec![InvocationKind::Function(function_id)]);
60 cb(&mut target)
61 }
62
63 fn debug_types(&self) -> bool {
64 self.debug_types
65 }
66}
67
68pub struct InvocationContext(Vec<InvocationKind>);
69
70pub(crate) enum InvocationKind {
72 Conditional(Box<LocalInformation>),
73 AlwaysTrue,
77 Function(FunctionId),
78 LoopIteration,
79 Unknown,
80}
81
82impl CallCheckingBehavior for InvocationContext {
83 const CHECK_PARAMETERS: bool = false;
84
85 fn get_latest_info<'b>(
86 &'b mut self,
87 environment: &'b mut Environment,
88 ) -> &'b mut LocalInformation {
89 self.0
90 .iter_mut()
91 .rev()
92 .find_map(|kind| -> Option<&mut LocalInformation> {
93 if let InvocationKind::Conditional(info) = kind {
94 Some(&mut *info)
95 } else {
96 None
97 }
98 })
99 .unwrap_or(&mut environment.info)
100 }
101
102 fn in_recursive_cycle(&self, function_id: FunctionId) -> bool {
103 self.0.iter().any(|kind| matches!(kind, InvocationKind::Function(id) if function_id == *id))
104 }
105
106 fn new_function_context<T>(
107 &mut self,
108 function_id: FunctionId,
109 cb: impl for<'a> FnOnce(&'a mut InvocationContext) -> T,
110 ) -> T {
111 self.0.push(InvocationKind::Function(function_id));
112 let value = cb(self);
113 self.0.pop();
114 value
115 }
116}
117
118impl InvocationContext {
119 pub(crate) fn new_empty() -> Self {
121 InvocationContext(Vec::new())
122 }
123
124 pub(crate) fn in_unknown(&self) -> bool {
125 self.0.iter().any(|c| matches!(c, InvocationKind::Unknown))
126 }
127
128 pub(crate) fn new_unknown_target<T>(
130 &mut self,
131 cb: impl for<'a> FnOnce(&'a mut InvocationContext) -> T,
132 ) -> T {
133 self.0.push(InvocationKind::Unknown);
134 let result = cb(self);
135 self.0.pop();
136 result
137 }
138
139 fn new_conditional_target<T>(
140 &mut self,
141 cb: impl for<'a> FnOnce(&'a mut InvocationContext) -> T,
142 ) -> (LocalInformation, T) {
143 self.0.push(InvocationKind::Conditional(Box::default()));
144 let result = cb(self);
145 if let Some(InvocationKind::Conditional(info)) = self.0.pop() {
146 (*info, result)
147 } else {
148 unreachable!()
149 }
150 }
151
152 pub(crate) fn new_unconditional_target(
153 &mut self,
154 cb: impl for<'a> FnOnce(&'a mut InvocationContext) -> Option<ApplicationResult>,
155 ) -> Option<ApplicationResult> {
156 self.0.push(InvocationKind::AlwaysTrue);
157 let result = cb(self);
158 self.0.pop();
159 result
160 }
161
162 pub(crate) fn new_loop_iteration<T>(
163 &mut self,
164 cb: impl for<'a> FnOnce(&'a mut InvocationContext) -> T,
165 ) -> T {
166 self.0.push(InvocationKind::LoopIteration);
167 let value = cb(self);
168 self.0.pop();
169 value
170 }
171
172 pub(crate) fn get_iteration_depth(&self) -> u8 {
173 let depth =
174 self.0.iter().filter(|p| matches!(p, InvocationKind::LoopIteration)).count() as u8;
175 crate::utilities::notify!("Iteration depth {}", depth);
177 depth
178 }
179
180 pub(crate) fn in_unconditional(&self) -> bool {
181 self.0.iter().any(|mem| matches!(mem, InvocationKind::AlwaysTrue))
182 }
183
184 pub(crate) fn evaluate_conditionally<I, T, R>(
187 &mut self,
188 top_environment: &mut Environment,
189 types: &mut TypeStore,
190 (condition, condition_position): (TypeId, SpanWithSource),
191 (input_left, input_right): (T, T),
192 mut data: I,
193 cb: impl for<'a> Fn(
194 &'a mut Environment,
195 &'a mut TypeStore,
196 &'a mut InvocationContext,
197 T,
198 &'a mut I,
199 ) -> R,
200 ) -> (I, (R, R)) {
201 let (truthy_info, truthy_result) =
202 self.new_conditional_target(|target: &mut InvocationContext| {
203 cb(top_environment, types, target, input_left, &mut data)
204 });
205
206 let (otherwise_info, otherwise_result) =
207 self.new_conditional_target(|target: &mut InvocationContext| {
208 cb(top_environment, types, target, input_right, &mut data)
209 });
210
211 if self.0.iter().any(|x| matches!(x, InvocationKind::Conditional(_))) {
217 todo!("nested, get latest")
218 } else {
234 let local_information = &mut top_environment.info;
235 match top_environment.context_type.parent {
236 crate::GeneralContext::Syntax(env) => {
237 merge_info(
238 env,
239 local_information,
240 condition,
241 truthy_info,
242 Some(otherwise_info),
243 types,
244 condition_position,
245 );
246 }
247 crate::GeneralContext::Root(_) => {
248 crate::utilities::notify!("Top environment is root?");
249 }
250 }
251 }
252
253 (data, (truthy_result, otherwise_result))
254 }
255}