1use source_map::SpanWithSource;
2use std::collections::HashMap;
3
4use crate::{
5 events::{Event, RootReference},
6 features::functions::ClosureId,
7 types::{
8 calling::ThisValue,
9 properties::{Properties, PropertyKey, Publicity},
10 TypeStore,
11 },
12 PropertyValue, Type, TypeId, VariableId,
13};
14
15#[derive(Debug, Default, binary_serialize_derive::BinarySerializable)]
17pub struct LocalInformation {
18 pub(crate) events: Vec<Event>,
19 pub(crate) queued_events: Vec<Event>,
21
22 pub(crate) variable_current_value: HashMap<VariableId, TypeId>,
24
25 pub(crate) current_properties: HashMap<TypeId, Properties>,
28
29 pub(crate) prototypes: HashMap<TypeId, TypeId>,
31
32 pub(crate) closure_current_values: HashMap<(ClosureId, RootReference), TypeId>,
34
35 pub(crate) frozen: HashMap<TypeId, ObjectProtectionState>,
37
38 pub(crate) object_constraints: HashMap<TypeId, TypeId>,
42
43 pub(crate) narrowed_values: crate::Map<TypeId, TypeId>,
46
47 pub(crate) state: ReturnState,
48
49 pub(crate) value_of_this: ThisValue,
53}
54
55#[derive(Debug, Clone, Copy, binary_serialize_derive::BinarySerializable)]
56pub enum ObjectProtectionState {
57 Frozen,
58 Sealed,
59 NoExtensions,
60}
61
62#[derive(Debug, Default, binary_serialize_derive::BinarySerializable, Clone)]
63pub(crate) enum ReturnState {
64 #[default]
65 Continued,
66 Rolling {
67 under: TypeId,
68 returned: TypeId,
69 },
70 Finished(TypeId),
71}
72
73impl ReturnState {
74 pub(crate) fn is_finished(&self) -> bool {
75 matches!(self, ReturnState::Finished(..))
76 }
77
78 pub(crate) fn get_returned(self, types: &mut TypeStore) -> TypeId {
79 match self {
80 ReturnState::Continued => TypeId::UNDEFINED_TYPE,
81 ReturnState::Rolling { under, returned } => {
82 types.new_conditional_type(under, returned, TypeId::UNDEFINED_TYPE)
83 }
84 ReturnState::Finished(ty) => ty,
85 }
86 }
87
88 pub(crate) fn append(&mut self, new: ReturnState) {
89 match self {
90 ReturnState::Continued => *self = new,
91 ReturnState::Rolling { .. } => match new {
92 ReturnState::Continued => {}
93 ReturnState::Rolling { .. } => {
94 crate::utilities::notify!("Warning not accepting second rolling");
95 }
96 new @ ReturnState::Finished(_) => {
97 crate::utilities::notify!("Warning overwriting conditional");
98 *self = new;
99 }
100 },
101 ReturnState::Finished(_) => todo!(),
102 }
103 }
104}
105
106impl LocalInformation {
107 pub fn register_property_on_type(
109 &mut self,
110 on: TypeId,
111 publicity: Publicity,
112 under: PropertyKey<'static>,
113 to: PropertyValue,
114 ) {
115 self.current_properties.entry(on).or_default().push((publicity, under, to));
116 }
117 pub fn register_property(
118 &mut self,
119 on: TypeId,
120 publicity: Publicity,
121 under: PropertyKey<'static>,
122 value: PropertyValue,
123 position: SpanWithSource,
124 ) {
125 self.current_properties.entry(on).or_default().push((
126 publicity,
127 under.clone(),
128 value.clone(),
129 ));
130 self.events.push(Event::Miscellaneous(
131 crate::events::MiscellaneousEvents::RegisterProperty {
132 on,
133 under,
134 value,
135 publicity,
136 position,
137 },
138 ));
139 }
140
141 #[must_use]
147 pub fn get_events(&self) -> &[Event] {
148 &self.events
149 }
150
151 pub(crate) fn delete_property(
153 &mut self,
154 on: TypeId,
155 (publicity, key): (Publicity, PropertyKey<'static>),
156 position: SpanWithSource,
157 option: Option<TypeId>,
158 ) {
159 self.current_properties.entry(on).or_default().push((
162 publicity,
163 key.clone(),
164 PropertyValue::Deleted,
165 ));
166
167 self.events.push(Event::Miscellaneous(crate::events::MiscellaneousEvents::Delete {
168 on,
169 publicity,
170 under: key,
171 into: option,
172 position,
173 }));
174 }
175
176 pub(crate) fn new_object(
177 &mut self,
178 prototype: Option<TypeId>,
179 types: &mut crate::types::TypeStore,
180 position: SpanWithSource,
181 is_under_dyn: bool,
183 ) -> TypeId {
184 let ty = types.register_type(Type::Object(crate::types::ObjectNature::RealDeal));
185 if let Some(prototype) = prototype {
188 self.prototypes.insert(ty, prototype);
189 }
190
191 if is_under_dyn {
192 let prototype = match prototype {
193 Some(id) => crate::events::PrototypeArgument::Yeah(id),
194 None => crate::events::PrototypeArgument::None,
195 };
196 let value = Event::CreateObject { referenced_in_scope_as: ty, prototype, position };
199 self.events.push(value);
200 }
201
202 ty
203 }
204
205 #[must_use]
206 pub fn get_properties_on_type_for_this_level(
207 &self,
208 ty: TypeId,
209 ) -> Option<&Vec<(Publicity, PropertyKey, PropertyValue)>> {
210 self.current_properties.get(&ty)
211 }
212
213 pub(crate) fn extend(&mut self, other: LocalInformation, condition: Option<TypeId>) {
214 if condition.is_some() {
215 todo!()
216 }
217 self.events.extend(other.events);
218 self.queued_events.extend(other.queued_events);
219 self.variable_current_value.extend(other.variable_current_value);
220 self.current_properties.extend(other.current_properties);
221 self.prototypes.extend(other.prototypes);
222 self.closure_current_values.extend(other.closure_current_values);
223 self.frozen.extend(other.frozen);
224 self.narrowed_values.extend(other.narrowed_values);
225 self.state = other.state;
226 }
227
228 pub(crate) fn extend_ref(&mut self, other: &LocalInformation) {
230 self.events.extend(other.events.iter().cloned());
231 self.queued_events.extend(other.queued_events.iter().cloned());
232 self.variable_current_value.extend(other.variable_current_value.iter().clone());
233 self.prototypes.extend(other.prototypes.iter().clone());
234 self.current_properties
235 .extend(other.current_properties.iter().map(|(l, r)| (*l, r.clone())));
236 self.closure_current_values
237 .extend(other.closure_current_values.iter().map(|(l, r)| (l.clone(), *r)));
238 self.frozen.extend(other.frozen.clone());
239 self.narrowed_values.extend(other.narrowed_values.iter().copied());
240 self.state = other.state.clone();
241 }
242
243 #[must_use]
244 pub fn is_finished(&self) -> bool {
245 self.state.is_finished()
246 }
247}
248
249pub trait InformationChain {
250 fn get_chain_of_info(&self) -> impl Iterator<Item = &'_ LocalInformation>;
251
252 fn get_narrowed(&self, for_ty: TypeId) -> Option<TypeId> {
253 self.get_chain_of_info().find_map(|info| info.narrowed_values.get(&for_ty).copied())
254 }
255
256 fn get_narrowed_or_object(&self, for_ty: TypeId, types: &TypeStore) -> Option<TypeId> {
257 let value = self.get_narrowed(for_ty);
258 if let Some(value) = value {
259 Some(value)
260 } else if let Type::Constructor(crate::types::Constructor::ConditionalResult {
261 condition,
262 truthy_result,
263 otherwise_result,
264 result_union: _,
265 }) = types.get_type_by_id(for_ty)
266 {
267 let narrowed_condition = self.get_narrowed(*condition)?;
268 if let crate::Decidable::Known(condition) =
269 crate::types::is_type_truthy_falsy(narrowed_condition, types)
270 {
271 let value = if condition { truthy_result } else { otherwise_result };
272 Some(*value)
273 } else {
274 None
275 }
276 } else {
277 value
278 }
279 }
280}
281
282pub struct ModuleInformation<'a> {
283 pub top: &'a LocalInformation,
284 pub module: &'a LocalInformation,
285}
286
287impl<'a> InformationChain for ModuleInformation<'a> {
288 fn get_chain_of_info(&self) -> impl Iterator<Item = &'_ LocalInformation> {
289 IntoIterator::into_iter([self.top, self.module])
290 }
291}
292
293pub(crate) fn get_value_of_constant_import_variable(
294 variable: VariableId,
295 info: &impl InformationChain,
296) -> TypeId {
297 info.get_chain_of_info()
298 .find_map(|info| info.variable_current_value.get(&variable).copied())
299 .unwrap()
300}
301
302pub fn merge_info(
303 parents: &impl InformationChain,
304 onto: &mut LocalInformation,
305 condition: TypeId,
306 mut truthy: LocalInformation,
307 mut otherwise: Option<LocalInformation>,
308 types: &mut TypeStore,
309 position: SpanWithSource,
310) {
311 let (new_state, carry_information_from) = match (
314 truthy.state.clone(),
315 otherwise.as_ref().map_or(ReturnState::Continued, |o| o.state.clone()),
316 ) {
317 (ReturnState::Continued, ReturnState::Continued) => (ReturnState::Continued, None),
318 (ReturnState::Finished(returned), ReturnState::Continued) => {
319 (ReturnState::Rolling { under: condition, returned }, Some(false))
320 }
321 (ReturnState::Continued, ReturnState::Finished(returned)) => (
322 ReturnState::Rolling { under: types.new_logical_negation_type(condition), returned },
323 Some(true),
324 ),
325 (ReturnState::Continued, rhs @ ReturnState::Rolling { .. }) => (rhs, None),
326 (ReturnState::Rolling { under, returned }, ReturnState::Continued) => (
327 ReturnState::Rolling { under: types.new_logical_and_type(condition, under), returned },
328 None,
329 ),
330 (
331 ReturnState::Rolling { under: truthy_under, returned: truthy_returned },
332 ReturnState::Rolling { under: otherwise_under, returned: otherwise_returned },
333 ) => {
334 let under = types.new_logical_or_type(truthy_under, otherwise_under);
335 let returned =
336 types.new_conditional_type(condition, truthy_returned, otherwise_returned);
337 (ReturnState::Rolling { under, returned }, None)
338 }
339 (lhs @ ReturnState::Rolling { .. }, ReturnState::Finished(_)) => (lhs, Some(true)),
340 (ReturnState::Finished(_), rhs @ ReturnState::Rolling { .. }) => (rhs, Some(false)),
341 (ReturnState::Finished(truthy_return), ReturnState::Finished(otherwise_return)) => (
342 ReturnState::Finished(types.new_conditional_type(
343 condition,
344 truthy_return,
345 otherwise_return,
346 )),
347 None,
348 ),
349 };
350
351 let truthy_events = truthy.events.len() as u32;
352 let otherwise_events = otherwise.as_ref().map_or(0, |f| f.events.len() as u32);
353
354 if truthy_events + otherwise_events != 0 {
355 onto.events.push(Event::Conditionally {
356 condition,
357 truthy_events,
358 otherwise_events,
359 position,
360 });
361
362 onto.events.append(&mut truthy.events);
363 if let Some(ref mut otherwise) = otherwise {
364 onto.events.append(&mut otherwise.events);
366 }
367
368 onto.events.push(Event::EndOfControlFlow(truthy_events + otherwise_events));
369 }
370
371 if new_state.is_finished() {
372 onto.state = new_state;
373 return;
374 }
375
376 if let Some(carry_information_from) = carry_information_from {
377 #[allow(clippy::match_bool)]
378 match carry_information_from {
379 true => {
380 onto.extend(truthy, None);
381 }
382 false => {
383 if let Some(otherwise) = otherwise {
384 onto.extend(otherwise, None);
385 } else {
386 let values = crate::features::narrowing::narrow_based_on_expression_into_vec(
388 condition, true, parents, types,
389 );
390
391 onto.narrowed_values = values;
392 onto.state = new_state;
393 }
394 }
395 }
396 } else {
397 onto.state = new_state;
398
399 for (var, true_value) in truthy.variable_current_value {
401 crate::utilities::notify!("{:?} {:?}", var, true_value);
402 let otherwise_value = otherwise
404 .as_mut()
405 .and_then(|otherwise| otherwise.variable_current_value.remove(&var))
407 .or_else(|| onto.variable_current_value.get(&var).copied())
408 .or_else(|| {
409 parents
410 .get_chain_of_info()
411 .find_map(|info| info.variable_current_value.get(&var))
412 .copied()
413 })
414 .unwrap_or(TypeId::ERROR_TYPE);
415
416 let new = types.new_conditional_type(condition, true_value, otherwise_value);
417
418 onto.variable_current_value.insert(var, new);
419 }
420
421 for (on, properties) in truthy.current_properties {
424 if let Some(existing) = onto.current_properties.get_mut(&on) {
443 existing.extend(properties);
444 } else {
445 onto.current_properties.insert(on, properties);
446 }
447 }
448
449 if let Some(otherwise) = otherwise {
450 for (on, properties) in otherwise.current_properties {
451 if let Some(existing) = onto.current_properties.get_mut(&on) {
452 existing.extend(properties);
453 } else {
454 onto.current_properties.insert(on, properties);
455 }
456 }
457 }
458
459 }
461}
462
463fn _pick_out_property(
466 from: &mut Properties,
467 (want_publicity, want_key): (Publicity, &PropertyKey<'static>),
468 info_chain: &impl InformationChain,
469 types: &TypeStore,
470) -> Option<(Publicity, PropertyKey<'static>, PropertyValue)> {
471 from.iter()
472 .position(|(publicity, key, _)| {
473 *publicity == want_publicity
474 && crate::types::key_matches((key, None), (want_key, None), info_chain, types).0
475 })
476 .map(|idx| from.remove(idx))
478}