1use crate::ns::*;
2
3#[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
16pub 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 scope: None,
76 },
77 }
78 }
79
80 pub fn invalidated(&self) -> bool {
82 self.verifier.invalidated
83 }
84
85 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 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 todo_here();
102
103 todo_here();
108
109 todo_here();
111
112 todo_here();
114
115 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 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 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 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 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 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 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 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 pub fn imp_coerce_exp(&mut self, exp: &Rc<Expression>, target_type: &Thingy) -> Result<Option<Thingy>, DeferError> {
525 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 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 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 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 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 let host = Rc::new(SemanticHost::new(SemanticHostOptions::default()));
681 host.config_constants().set("FOO::X".into(), "true".into());
682
683 let cu = CompilationUnit::new(None, "FOO::X".into());
691
692 let exp = ParserFacade(&cu, ParserOptions::default()).parse_expression();
694
695 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 cu.sort_diagnostics();
712 for diag in cu.nested_diagnostics() {
713 println!("{}", FxDiagnostic(&diag).format_english());
714 }
715 }
716}