Skip to main content

hydroper_razen/verifier/
verifier.rs

1use crate::ns::*;
2
3/// Directive or binding phase.
4#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
5pub enum VerifierPhase {
6    Alpha = 0,
7    Beta = 1,
8    Delta = 2,
9    Epsilon = 3,
10    Eta = 4,
11    Theta = 5,
12    Omega = 6,
13    Finished = 7,
14}
15
16/// ActionScript 3 and MXML verifier.
17///
18/// `Verifier` performs type checking and maps nodes to something in
19/// the semantic model.
20///
21/// # Verifying
22/// 
23/// A set of programs can be verified by invoking `verify_programs()`:
24/// 
25/// ```ignore
26/// verifier.verify_programs(program_list, mxml_list);
27/// ```
28/// 
29/// A single expression can be verified by invoking `verify_expression()`:
30/// 
31/// ```ignore
32/// verifier.verify_expression(&expression, Some(context_type));
33/// ```
34/// 
35/// # Scopes
36/// 
37/// Enter and exit scopes by invoking `enter_scope()` and `exit_scope()` respectively.
38/// Such methods may alter the `parent()` field of the scope to use the enclosing
39/// scope as the parent.
40///
41/// ```
42/// verifier.enter_scope(&scope);
43/// verifier.exit_scope();
44/// ```
45///
46/// # Symbol solving
47///
48/// As programs are verified, the `host.node_mapping()` object is filled
49/// with mappings from program nodes to something in the semantic model.
50/// 
51/// ```ignore
52/// // expression: Rc<Expression>
53/// let thingy: Option<Thingy> = host.node_mapping().get(&expression);
54/// ```
55pub struct Verifier {
56    verifier: Subverifier,
57}
58
59impl Verifier {
60    pub(crate) const MAX_CYCLES: usize = 512;
61
62    pub fn new(host: &Rc<SemanticHost>) -> Self {
63        Self {
64            verifier: Subverifier {
65                host: host.clone(),
66                cached_var_init: HashMap::new(),
67                phase_of_thingy: HashMap::new(),
68                phase_of_drtv: HashMap::new(),
69                phase_of_block: HashMap::new(),
70                deferred_function_exp: SharedMap::new(),
71                definition_conflicts: SharedArray::new(),
72                invalidated: false,
73                external: false,
74                // deferred_counter: 0,
75                scope: None,
76            },
77        }
78    }
79
80    /// Indicates whether an error was found while verifying the program.
81    pub fn invalidated(&self) -> bool {
82        self.verifier.invalidated
83    }
84
85    /// # Panics
86    ///
87    /// Panics if the verifier is already invalidated before verifying.
88    pub fn verify_programs(&mut self, programs: Vec<Rc<Program>>, mxml_list: Vec<Rc<Mxml>>) {
89        if self.verifier.invalidated {
90            panic!("Verifier already invalidated.");
91        }
92
93        // Collect package definitions, including these from top-level include directives.
94        let mut packages: Vec<Rc<PackageDefinition>> = vec![];
95        for program in programs.iter() {
96            packages.extend(Self::collect_package_definitions(program));
97        }
98        let mut rem_pckg_list = packages.clone();
99
100        // Do a first pass in every package to declare them.
101        todo_here();
102
103        // Verify directives across packages ("rem_pckg_list")
104        //
105        // * [ ] Eliminate packages from "rem_pckg_list" that were fully solved from directive verification,
106        //       but still visit them later for statement verification.
107        todo_here();
108
109        // Verify statements across packages
110        todo_here();
111
112        // Verify directives and then statements in the top-level of all programs.
113        todo_here();
114
115        // * [ ] Handle deferred function commons for lambdas.
116        for _ in 0..Verifier::MAX_CYCLES {
117            let mut any_defer = false;
118            for (common, partials) in self.verifier.deferred_function_exp.clone().borrow().iter() {
119                let common = (**common).clone();
120                any_defer = any_defer || FunctionCommonSubverifier::verify_function_exp_common(&mut self.verifier, &common, partials).is_err();
121            }
122            if !any_defer {
123                break;
124            }
125        }
126        for (common, _) in self.verifier.deferred_function_exp.clone().borrow().iter() {
127            let loc = (*common).location.clone();
128            self.verifier.add_verify_error(&loc, FxDiagnosticKind::ReachedMaximumCycles, diagarg![]);
129        }
130
131        for (old, new) in self.verifier.definition_conflicts.clone().iter() {
132            self.verifier.finish_definition_conflict(&old, &new);
133        }
134
135        self.verifier.reset_state();
136    }
137
138    /// Verifies an expression. Returns `None` if verification failed.
139    ///
140    /// # Panics
141    ///
142    /// Panics if the verifier is already invalidated before verifying.
143    pub fn verify_expression(&mut self, exp: &Rc<Expression>, context: &VerifierExpressionContext) -> Option<Thingy> {
144        if self.verifier.invalidated {
145            panic!("Verifier already invalidated.");
146        }
147
148        let v = self.verifier.verify_expression(exp, context);
149        if let Ok(v) = v {
150            for _ in 0..Verifier::MAX_CYCLES {
151                let mut any_defer = false;
152                for (common, partials) in self.verifier.deferred_function_exp.clone().borrow().iter() {
153                    let common = (**common).clone();
154                    any_defer = any_defer || FunctionCommonSubverifier::verify_function_exp_common(&mut self.verifier, &common, partials).is_err();
155                }
156                if !any_defer {
157                    break;
158                }
159            }
160            for (common, _) in self.verifier.deferred_function_exp.clone().borrow().iter() {
161                let loc = (*common).location.clone();
162                self.verifier.add_verify_error(&loc, FxDiagnosticKind::ReachedMaximumCycles, diagarg![]);
163            }
164            for (old, new) in self.verifier.definition_conflicts.clone().iter() {
165                self.verifier.finish_definition_conflict(&old, &new);
166            }
167            self.verifier.reset_state();
168            return v;
169        }
170
171        self.verifier.add_verify_error(&exp.location(), FxDiagnosticKind::ReachedMaximumCycles, diagarg![]);
172        self.verifier.reset_state();
173        None
174    }
175
176    fn collect_package_definitions(program: &Rc<Program>) -> Vec<Rc<PackageDefinition>> {
177        let mut r = program.packages.clone();
178        for drtv in &program.directives {
179            if let Directive::IncludeDirective(drtv) = drtv.as_ref() {
180                r.extend(Self::collect_package_definitions_from_include(drtv));
181            }
182        }
183        r
184    }
185
186    fn collect_package_definitions_from_include(drtv: &IncludeDirective) -> Vec<Rc<PackageDefinition>> {
187        let mut r = drtv.nested_packages.clone();
188        for drtv in &drtv.nested_directives {
189            if let Directive::IncludeDirective(drtv) = drtv.as_ref() {
190                r.extend(Self::collect_package_definitions_from_include(drtv));
191            }
192        }
193        r
194    }
195
196    #[inline(always)]
197    pub fn set_scope(&mut self, scope: &Thingy) {
198        self.verifier.set_scope(scope);
199    }
200
201    #[inline(always)]
202    pub fn inherit_and_enter_scope(&mut self, scope: &Thingy) {
203        self.verifier.inherit_and_enter_scope(scope);
204    }
205
206    pub fn exit_scope(&mut self) {
207        self.verifier.exit_scope();
208    }
209
210    pub fn external(&self) -> bool {
211        self.verifier.external
212    }
213
214    pub fn set_external(&mut self, value: bool) {
215        self.verifier.external = value;
216    }
217}
218
219pub(crate) struct Subverifier {
220    pub host: Rc<SemanticHost>,
221    /// Temporary cache of variable binding initializers.
222    pub cached_var_init: HashMap<NodeAsKey<Rc<Expression>>, Thingy>,
223
224    pub phase_of_thingy: HashMap<Thingy, VerifierPhase>,
225    pub phase_of_drtv: HashMap<NodeAsKey<Rc<Directive>>, VerifierPhase>,
226    pub phase_of_block: HashMap<NodeAsKey<Rc<Block>>, VerifierPhase>,
227
228    pub deferred_function_exp: SharedMap<NodeAsKey<Rc<FunctionCommon>>, VerifierFunctionPartials>,
229
230    pub definition_conflicts: SharedArray<(Thingy, Thingy)>,
231
232    invalidated: bool,
233    // pub deferred_counter: usize,
234    pub scope: Option<Thingy>,
235    pub external: bool,
236}
237
238impl Subverifier {
239    #[inline(always)]
240    pub fn node_mapping(&self) -> &TreeSemantics<Thingy> {
241        &self.host.node_mapping()
242    }
243
244    /// Indicates whether an error was found in the program while
245    /// verifying.
246    pub fn invalidated(&self) -> bool {
247        self.invalidated
248    }
249
250    pub fn reset_state(&mut self) {
251        self.cached_var_init.clear();
252        self.phase_of_thingy.clear();
253        self.phase_of_drtv.clear();
254        self.phase_of_block.clear();
255        self.deferred_function_exp.clear();
256    }
257
258    pub fn lazy_init_drtv_phase(&mut self, drtv: &Rc<Directive>, initial_phase: VerifierPhase) -> VerifierPhase {
259        if let Some(k) = self.phase_of_drtv.get(&NodeAsKey(drtv.clone())) {
260            *k
261        } else {
262            self.phase_of_drtv.insert(NodeAsKey(drtv.clone()), initial_phase);
263            initial_phase
264        }
265    }
266
267    pub fn lazy_init_block_phase(&mut self, block: &Rc<Block>, initial_phase: VerifierPhase) -> VerifierPhase {
268        if let Some(k) = self.phase_of_block.get(&NodeAsKey(block.clone())) {
269            *k
270        } else {
271            self.phase_of_block.insert(NodeAsKey(block.clone()), initial_phase);
272            initial_phase
273        }
274    }
275
276    pub fn set_drtv_phase(&mut self, drtv: &Rc<Directive>, phase: VerifierPhase) {
277        self.phase_of_drtv.insert(NodeAsKey(drtv.clone()), phase);
278    }
279
280    pub fn set_block_phase(&mut self, block: &Rc<Block>, phase: VerifierPhase) {
281        self.phase_of_block.insert(NodeAsKey(block.clone()), phase);
282    }
283
284    pub fn add_syntax_error(&mut self, location: &Location, kind: FxDiagnosticKind, arguments: Vec<Rc<dyn DiagnosticArgument>>) {
285        let cu = location.compilation_unit();
286        if cu.prevent_equal_offset_error(location) {
287            return;
288        }
289        cu.add_diagnostic(FxDiagnostic::new_syntax_error(location, kind, arguments));
290        self.invalidated = true;
291    }
292
293    pub fn add_verify_error(&mut self, location: &Location, kind: FxDiagnosticKind, arguments: Vec<Rc<dyn DiagnosticArgument>>) {
294        let cu = location.compilation_unit();
295        if cu.prevent_equal_offset_error(location) {
296            return;
297        }
298        cu.add_diagnostic(FxDiagnostic::new_verify_error(location, kind, arguments));
299        self.invalidated = true;
300    }
301
302    pub fn add_warning(&mut self, location: &Location, kind: FxDiagnosticKind, arguments: Vec<Rc<dyn DiagnosticArgument>>) {
303        let cu = location.compilation_unit();
304        if cu.prevent_equal_offset_warning(location) {
305            return;
306        }
307        cu.add_diagnostic(FxDiagnostic::new_warning(location, kind, arguments));
308    }
309
310    pub fn set_scope(&mut self, scope: &Thingy) {
311        self.scope = Some(scope.clone());
312    }
313
314    pub fn inherit_and_enter_scope(&mut self, scope: &Thingy) {
315        let k = self.scope.clone();
316        self.scope = Some(scope.clone());
317        if scope.parent().is_none() {
318            scope.set_parent(k);
319        }
320    }
321
322    pub fn exit_scope(&mut self) {
323        self.scope = self.scope.as_ref().and_then(|scope| scope.parent());
324    }
325
326    pub fn scope(&self) -> Thingy {
327        self.scope.as_ref().unwrap().clone()
328    }
329
330    pub fn verify_expression(&mut self, exp: &Rc<Expression>, context: &VerifierExpressionContext) -> Result<Option<Thingy>, DeferError> {
331        // Cache-result - prevents diagnostic duplication
332        if self.host.node_mapping().has(exp) {
333            return Ok(self.host.node_mapping().get(exp));
334        }
335
336        let mut result: Option<Thingy>;
337        match exp.as_ref() {
338            Expression::QualifiedIdentifier(id) => {
339                result = ExpSubverifier::verify_qualified_identifier_as_exp(self, id, context)?;
340            },
341            Expression::Member(e) => {
342                result = ExpSubverifier::verify_member_exp(self, exp, e, context)?;
343            },
344            Expression::ComputedMember(e) => {
345                result = ExpSubverifier::verify_computed_member_exp(self, e, context)?;
346            },
347            Expression::NumericLiteral(e) => {
348                result = ExpSubverifier::verify_numeric_literal(self, e, context)?;
349            },
350            Expression::StringLiteral(e) => {
351                result = ExpSubverifier::verify_string_literal(self, e, context)?;
352            },
353            Expression::Paren(e) => {
354                result = self.verify_expression(&e.expression, context)?;
355            },
356            Expression::NullLiteral(e) => {
357                result = ExpSubverifier::verify_null_literal(self, e, context)?;
358            },
359            Expression::BooleanLiteral(e) => {
360                result = ExpSubverifier::verify_boolean_literal(self, e, context)?;
361            },
362            Expression::ThisLiteral(e) => {
363                result = ExpSubverifier::verify_this_literal(self, e)?;
364            },
365            Expression::RegExpLiteral(e) => {
366                result = ExpSubverifier::verify_reg_exp_literal(self, e, context)?;
367            },
368            Expression::Xml(e) => {
369                result = ExpSubverifier::verify_xml_exp(self, e, context)?;
370            },
371            Expression::XmlList(e) => {
372                result = ExpSubverifier::verify_xml_list_exp(self, e, context)?;
373            },
374            Expression::XmlMarkup(_) => {
375                result = Some(self.host.factory().create_value(&self.host.xml_type().defer()?));
376            },
377            Expression::ArrayLiteral(e) => {
378                result = ArraySubverifier::verify_array_literal(self, e, context)?;
379            },
380            Expression::VectorLiteral(e) => {
381                result = ArraySubverifier::verify_vector_literal(self, e, context)?;
382            },
383            Expression::ObjectInitializer(e) => {
384                result = ObjectLiteralSubverifier::verify_object_initializer(self, e, context)?;
385            },
386            Expression::Invalidated(_) => {
387                result = None;
388            },
389            Expression::ImportMeta(_) => {
390                result = Some(self.host.meta_property());
391            },
392            Expression::New(e) => {
393                result = ExpSubverifier::verify_new_exp(self, e)?;
394            },
395            Expression::Descendants(e) => {
396                result = ExpSubverifier::verify_descendants_exp(self, e)?;
397            },
398            Expression::Filter(e) => {
399                result = ExpSubverifier::verify_filter_exp(self, e)?;
400            },
401            Expression::Super(e) => {
402                result = ExpSubverifier::verify_super_exp(self, e)?;
403            },
404            Expression::Call(e) => {
405                result = ExpSubverifier::verify_call_exp(self, e)?;
406            },
407            Expression::WithTypeArguments(e) => {
408                result = ExpSubverifier::verify_apply_types_exp(self, e)?;
409            },
410            Expression::Unary(e) => {
411                result = ExpSubverifier::verify_unary_exp(self, e)?;
412            },
413            Expression::OptionalChaining(e) => {
414                result = ExpSubverifier::verify_opt_chaining_exp(self, e)?;
415            },
416            Expression::OptionalChainingPlaceholder(_) => {
417                // The optional chaining placeholder is assumed to be already
418                // cached by the optional chaining operation.
419                panic!();
420            },
421            Expression::Binary(e) => {
422                result = ExpSubverifier::verify_binary_exp(self, e)?;
423            },
424            Expression::Conditional(e) => {
425                result = ExpSubverifier::verify_conditional_exp(self, e, context)?;
426            },
427            Expression::Sequence(e) => {
428                result = ExpSubverifier::verify_seq_exp(self, e)?;
429            },
430            Expression::ReservedNamespace(e) => {
431                result = ExpSubverifier::verify_reserved_ns_exp(self, e)?;
432            },
433            Expression::NullableType(e) => {
434                result = ExpSubverifier::verify_nullable_type_exp(self, e)?;
435            },
436            Expression::NonNullableType(e) => {
437                result = ExpSubverifier::verify_non_nullable_type_exp(self, e)?;
438            },
439            Expression::AnyType(_) => {
440                result = Some(self.host.any_type().wrap_property_reference(&self.host)?);
441            },
442            Expression::VoidType(_) => {
443                result = Some(self.host.void_type().wrap_property_reference(&self.host)?);
444            },
445            Expression::ArrayType(e) => {
446                result = ExpSubverifier::verify_array_type_exp(self, e)?;
447            },
448            Expression::TupleType(e) => {
449                result = ExpSubverifier::verify_tuple_type_exp(self, e)?;
450            },
451            Expression::FunctionType(e) => {
452                result = ExpSubverifier::verify_function_type_exp(self, e)?;
453            },
454            Expression::Assignment(e) => {
455                result = ExpSubverifier::verify_assignment_exp(self, e)?;
456            },
457            Expression::Function(e) => {
458                result = ExpSubverifier::verify_function_exp(self, e)?;
459            },
460        }
461
462        if let Some(r1) = result.as_ref() {
463            if r1.is::<InvalidationThingy>() {
464                result = None;
465            } else if r1.static_type(&self.host).is::<InvalidationThingy>() {
466                result = None;
467            }
468        }
469
470        self.host.node_mapping().set(exp, result.clone());
471
472        if result.is_none() {
473            return Ok(result);
474        }
475        let result = result.unwrap();
476
477        match context.mode {
478            VerifyMode::Read => {
479                if result.write_only(&self.host) {
480                    self.add_verify_error(&exp.location(), FxDiagnosticKind::EntityIsWriteOnly, diagarg![]);
481                }
482            },
483            VerifyMode::Write => {
484                if result.read_only(&self.host) {
485                    self.add_verify_error(&exp.location(), FxDiagnosticKind::EntityIsReadOnly, diagarg![]);
486                }
487            },
488            VerifyMode::Delete => {
489                if !result.deletable(&self.host) {
490                    self.add_verify_error(&exp.location(), FxDiagnosticKind::EntityMustNotBeDeleted, diagarg![]);
491                }
492            },
493        }
494
495        Ok(Some(result))
496    }
497
498    pub fn verify_type_expression(&mut self, exp: &Rc<Expression>) -> Result<Option<Thingy>, DeferError> {
499        // Cache-result - prevents diagnostic duplication
500        if self.host.node_invalidation_mapping().has(exp) {
501            return Ok(None);
502        }
503        if self.host.node_mapping().has(exp) {
504            return Ok(self.host.node_mapping().get(exp));
505        }
506
507        let v = self.verify_expression(exp, &VerifierExpressionContext { ..default() })?;
508        if v.is_none() {
509            return Ok(None);
510        }
511        let v = v.unwrap();
512        let v = v.expect_type();
513        if v.is_err() {
514            self.add_verify_error(&exp.location(), FxDiagnosticKind::EntityIsNotAType, diagarg![]);
515            self.host.node_invalidation_mapping().set(exp, Some(()));
516            return Ok(None);
517        }
518        let v = v.unwrap();
519        self.host.node_mapping().set(exp, Some(v.clone()));
520        Ok(Some(v))
521    }
522
523    /// Implicitly coerce expression to a type.
524    pub fn imp_coerce_exp(&mut self, exp: &Rc<Expression>, target_type: &Thingy) -> Result<Option<Thingy>, DeferError> {
525        // Cache-result - prevents diagnostic duplication
526        if self.host.node_invalidation_mapping().has(exp) {
527            return Ok(None);
528        }
529        if self.host.node_mapping().has(exp) {
530            return Ok(self.host.node_mapping().get(exp));
531        }
532
533        let v = self.verify_expression(exp, &VerifierExpressionContext {
534            context_type: Some(target_type.clone()),
535            ..default()
536        })?;
537        if v.is_none() {
538            return Ok(None);
539        }
540        let v = v.unwrap();
541        let got_type = v.static_type(&self.host);
542        let v = TypeConversions(&self.host).implicit(&v, target_type, false)?;
543        if v.is_none() {
544            self.add_verify_error(&exp.location(), FxDiagnosticKind::ImplicitCoercionToUnrelatedType, diagarg![got_type, target_type.clone()]);
545            self.host.node_invalidation_mapping().set(exp, Some(()));
546            return Ok(None);
547        }
548        let v = v.unwrap();
549        self.host.node_mapping().set(exp, Some(v.clone()));
550        Ok(Some(v))
551    }
552    
553    pub fn detect_local_capture(&self, reference: &Thingy) {
554        if reference.is::<ScopeReferenceValue>() {
555            let r_act = reference.base().search_activation();
556            let cur_act = self.scope().search_activation();
557            if let (Some(r_act), Some(cur_act)) = (r_act, cur_act) {
558                if r_act != cur_act {
559                    r_act.set_property_has_capture(&reference.property(), true);
560                }
561            }
562        }
563    }
564
565    /// Post-processes an already resolved reference. Auto applies
566    /// type parameters and auto expands constant.
567    pub fn reference_post_processing(&mut self, r: Thingy, context: &VerifierExpressionContext) -> Result<Option<Thingy>, DeferError> {
568        if r.is::<FixtureReferenceValue>() {
569            let p = r.property();
570
571            // Auto apply parameterized types
572            if (p.is::<ClassType>() || p.is::<InterfaceType>()) && p.type_params().is_some() && !context.followed_by_type_arguments {
573                let mut subst = SharedArray::<Thingy>::new();
574                for _ in 0..p.type_params().unwrap().length() {
575                    subst.push(self.host.any_type());
576                }
577                return Ok(Some(self.host.factory().create_type_after_substitution(&p, &subst)));
578            }
579
580            // Compile-time constant
581            if p.is::<OriginalVariableSlot>() && p.read_only(&self.host) && p.var_constant().is_some() {
582                let r = p.var_constant().unwrap();
583                return Ok(Some(r));
584            }
585        }
586        Ok(Some(r))
587    }
588
589    /// Handles definition conflict, returning any equivalent variable or method slot back, or invalidation.
590    pub fn handle_definition_conflict(&mut self, prev: &Thingy, new: &Thingy) -> Thingy {
591        self.definition_conflicts.push((prev.clone(), new.clone()));
592        let parent = new.parent().unwrap();
593        if new.is::<VariableSlot>() && !parent.is::<FixtureScope>() && prev.is::<VariableSlot>() {
594            return prev.clone();
595        } else if prev.is::<VariableSlot>() && !parent.is::<FixtureScope>() && new.is::<MethodSlot>() {
596            return prev.clone();
597        }
598        self.host.invalidation_thingy()
599    }
600
601    pub fn finish_definition_conflict(&mut self, prev: &Thingy, new: &Thingy) {
602        let name = new.name();
603        let parent = new.parent().unwrap();
604        let host = self.host.clone();
605        if new.is::<VariableSlot>() && !parent.is::<FixtureScope>() {
606            if prev.is::<VariableSlot>() && TypeConversions(&host).implicit(&host.factory().create_value(&new.static_type(&host)), &prev.static_type(&host), false).unwrap().is_some() {
607                self.add_warning(&new.location().unwrap(), FxDiagnosticKind::DuplicateVariableDefinition, diagarg![name.local_name()]);
608                return;
609            }
610        } else if prev.is::<VariableSlot>() && !parent.is::<FixtureScope>() {
611            if new.is::<MethodSlot>() && TypeConversions(&host).implicit(&host.factory().create_value(&host.function_type()), &prev.static_type(&host), false).unwrap().is_some() {
612                self.add_warning(&new.location().unwrap(), FxDiagnosticKind::DuplicateVariableDefinition, diagarg![name.local_name()]);
613                return;
614            }
615        }
616        self.report_definition_conflict_for_thingy(prev);
617        self.report_definition_conflict_for_thingy(new);
618    }
619
620    fn report_definition_conflict_for_thingy(&mut self, thingy: &Thingy) {
621        let Some(loc) = thingy.location() else {
622            return;
623        };
624        let name = thingy.name();
625        if thingy.is::<ClassType>() || thingy.is::<EnumType>() {
626            self.add_verify_error(&loc, FxDiagnosticKind::DuplicateClassDefinition, diagarg![name.local_name()]);
627        } else if thingy.is::<InterfaceType>() {
628            self.add_verify_error(&loc, FxDiagnosticKind::DuplicateInterfaceDefinition, diagarg![name.local_name()]);
629        } else if thingy.is::<MethodSlot>() {
630            self.add_verify_error(&loc, FxDiagnosticKind::DuplicateFunctionDefinition, diagarg![name.local_name()]);
631        } else {
632            self.add_verify_error(&loc, FxDiagnosticKind::AConflictExistsWithDefinition, diagarg![name.local_name(), name.namespace()]);
633        }
634    }
635
636    pub fn cache_var_init(&mut self, pattern: &Rc<Expression>, callback: impl FnOnce() -> Thingy) -> Thingy {
637        if let Some(init) = self.cached_var_init.get(&NodeAsKey(pattern.clone())) {
638            init.clone()
639        } else {
640            let init = callback();
641            self.cached_var_init.insert(NodeAsKey(pattern.clone()), init.clone());
642            init
643        }
644    }
645}
646
647#[derive(Clone, Copy, PartialEq, Eq)]
648pub enum VerifyMode {
649    Read,
650    Write,
651    Delete,
652}
653
654#[derive(Clone)]
655pub struct VerifierExpressionContext {
656    pub context_type: Option<Thingy>,
657    pub followed_by_type_arguments: bool,
658    pub mode: VerifyMode,
659    pub preceded_by_negative: bool,
660}
661
662impl Default for VerifierExpressionContext {
663    fn default() -> Self {
664        Self {
665            context_type: None,
666            followed_by_type_arguments: false,
667            mode: VerifyMode::Read,
668            preceded_by_negative: false,
669        }
670    }
671}
672
673#[cfg(test)]
674mod tests {
675    use crate::ns::*;
676
677    #[test]
678    fn test_exp() {
679        // Prepare the host
680        let host = Rc::new(SemanticHost::new(SemanticHostOptions::default()));
681        host.config_constants().set("FOO::X".into(), "true".into());
682        
683        /*
684        let boolean_class = host.factory().create_class_type(
685            host.factory().create_qname(&host.top_level_package().public_ns().unwrap(), "Boolean".into()),
686            &host.top_level_package().public_ns().unwrap());
687        host.top_level_package().properties(&host).set(boolean_class.name(), boolean_class);
688        */
689
690        let cu = CompilationUnit::new(None, "FOO::X".into());
691
692        // Parsing
693        let exp = ParserFacade(&cu, ParserOptions::default()).parse_expression();
694
695        // Verification
696        let mut verifier = Verifier::new(&host);
697        let scope = host.factory().create_scope();
698        scope.import_list().push(host.factory().create_package_wildcard_import(&host.top_level_package(), None));
699        verifier.set_scope(&scope);
700        let _ = verifier.verify_expression(&exp, &VerifierExpressionContext {
701            ..default()
702        });
703        /*
704        assert!(cv.is_some());
705        let Some(cv) = cv else { panic!(); };
706        assert!(cv.is::<BooleanConstant>());
707        assert!(cv.boolean_value());
708        */
709
710        // Report diagnostics
711        cu.sort_diagnostics();
712        for diag in cu.nested_diagnostics() {
713            println!("{}", FxDiagnostic(&diag).format_english());
714        }
715    }
716}