Skip to main content

ezno_checker/context/
invocation.rs

1//! When a function is called (or a group of events like function such as a iteration block) it creates a mini-environment for which events are applied into
2
3use source_map::SpanWithSource;
4
5use super::LocalInformation;
6use crate::{
7	context::information::merge_info, events::ApplicationResult, types::TypeStore, Environment,
8	FunctionId, TypeId,
9};
10
11/// For anything that might involve a call, including gets, sets and actual calls
12pub trait CallCheckingBehavior {
13	// TODO
14	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
34/// Top level. Evaluating directly, rather than deep in event application
35pub 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		// cannot get in a loop from checking
51		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
70/// TODO want to have type arguments on each of these
71pub(crate) enum InvocationKind {
72	Conditional(Box<LocalInformation>),
73	/// *Unconditional*
74	///
75	/// TODO does this need [`LocalInformation`]??
76	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	/// TODO temp for loop unrolling
120	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	/// WIP
129	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		// TODO can this every go > 1
176		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	/// TODO maybe take result -> R
185	/// TODO move to trait
186	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		// TODO all things that are
212		// - variable and property values (these aren't read from events)
213		// - immutable, mutable, prototypes etc
214		// let info = self.get_latest_info(top_environment);
215
216		if self.0.iter().any(|x| matches!(x, InvocationKind::Conditional(_))) {
217			todo!("nested, get latest")
218		// let local_information = &mut top_environment.info;
219		// match top_environment.context_type.parent {
220		// 	crate::GeneralContext::Syntax(env) => {
221		// 		merge_info(
222		// 			env,
223		// 			local_information,
224		// 			condition,
225		// 			truthy_info,
226		// 			Some(otherwise_info),
227		// 			types,
228		// 			condition_position,
229		// 		);
230		// 	}
231		// 	crate::GeneralContext::Root(_) => todo!(),
232		// }
233		} 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}