[rust][sema] For statements and JSX
Adds semantic analysis support for normal `for` statements and for JSX. The main catch with JSX is that there are a bunch of identifiers that we have to ignore since they aren't variable references: jsx attribute names, namespace names, jsx member expression properties, and closing elements.
Joe Savona committed
Aug 4, 2023 at 12:02 UTC
3df04725bd58d37e834dee071d6cd6257f6d3516
7 files changed
+1457
-82
compiler/forget/crates/forget_estree/src/generated_extensions.rs
+23
-1
@@ -1,5 +1,8 @@
1
// Manual extensions to generated types
2
-use crate::{Pattern, SourceRange, SourceType};
2
+use crate::{
3
+ JSXElementName, JSXMemberExpression, JSXMemberExpressionOrIdentifier, Pattern, SourceRange,
4
+ SourceType,
5
+};
6
7
/// Sentinel trait to distinguish AST *node* types
8
pub trait ESTreeNode {}
@@ -21,3 +24,22 @@ impl Pattern {
24
}
25
}
26
}
27
+
28
+impl JSXElementName {
29
+ pub fn root_name(&self) -> &str {
30
+ match self {
31
+ Self::JSXIdentifier(name) => &name.name,
32
+ Self::JSXMemberExpression(name) => name.root_name(),
33
+ Self::JSXNamespacedName(name) => &name.namespace.name,
34
+ }
35
+ }
36
+}
37
+
38
+impl JSXMemberExpression {
39
+ pub fn root_name(&self) -> &str {
40
+ match &self.object {
41
+ JSXMemberExpressionOrIdentifier::JSXMemberExpression(object) => object.root_name(),
42
+ JSXMemberExpressionOrIdentifier::JSXIdentifier(object) => &object.name,
43
+ }
44
+ }
45
+}
compiler/forget/crates/forget_semantic_analysis/src/analyzer.rs
+104
-12
@@ -1,8 +1,8 @@
1
use forget_diagnostics::Diagnostic;
2
use forget_estree::{
3
AssignmentOperator, AssignmentPropertyOrRestElement, AssignmentTarget, Expression,
4
- ExpressionOrSuper, ForInInit, Function, FunctionBody, Identifier, Pattern, Program,
5
- SourceRange, SourceType, Statement, VariableDeclarationKind, Visitor2,
4
+ ExpressionOrSuper, ForInInit, ForInit, Function, FunctionBody, Identifier, JSXElementName,
5
+ Pattern, Program, SourceRange, SourceType, Statement, VariableDeclarationKind, Visitor2,
6
};
7
8
use crate::{AstNode, DeclarationKind, LabelKind, ReferenceKind, ScopeId, ScopeKind, ScopeManager};
@@ -190,7 +190,7 @@ impl Analyzer {
190
left: &ForInInit,
191
right: &Expression,
192
body: &Statement,
193
- range: Option<SourceRange>,
193
+ _range: Option<SourceRange>,
194
) {
195
// Record an anonymous label for the statement to resolve unlabeled break/continue
196
let label = self
@@ -455,17 +455,31 @@ impl Visitor2 for Analyzer {
455
);
456
}
457
458
- fn visit_identifier(&mut self, ast: &forget_estree::Identifier) {
459
- Analyzer::visit_reference_identifier(
460
- self,
461
- &ast.name,
462
- AstNode::from(ast),
463
- ReferenceKind::Read,
464
- ast.range,
465
- );
458
+ fn visit_for_statement(&mut self, ast: &forget_estree::ForStatement) {
459
+ let mut for_scope: Option<ScopeId> = None;
460
+ if let Some(init) = &ast.init {
461
+ if let ForInit::VariableDeclaration(init) = init {
462
+ if init.kind != VariableDeclarationKind::Var {
463
+ for_scope = Some(self.enter_scope(ScopeKind::For));
464
+ }
465
+ }
466
+ }
467
+ if let Some(init) = &ast.init {
468
+ self.visit_for_init(init);
469
+ }
470
+ if let Some(test) = &ast.test {
471
+ self.visit_expression(test);
472
+ }
473
+ if let Some(update) = &ast.update {
474
+ self.visit_expression(update);
475
+ }
476
+ self.visit_statement(&ast.body);
477
+ if let Some(for_scope) = for_scope {
478
+ self.close_scope(for_scope);
479
+ }
480
}
481
468
- fn visit_jsxidentifier(&mut self, ast: &forget_estree::JSXIdentifier) {
482
+ fn visit_identifier(&mut self, ast: &forget_estree::Identifier) {
483
Analyzer::visit_reference_identifier(
484
self,
485
&ast.name,
@@ -561,4 +575,82 @@ impl Visitor2 for Analyzer {
575
}
576
}
577
}
578
+
579
+ fn visit_jsxattribute(&mut self, ast: &forget_estree::JSXAttribute) {
580
+ // NOTE: skip visiting the attribute name, attributes are like non-computed
581
+ // object properties where the identifier is not a variable reference
582
+ if let Some(value) = &ast.value {
583
+ self.visit_jsxattribute_value(value);
584
+ }
585
+ }
586
+
587
+ fn visit_jsxclosing_element(&mut self, _ast: &forget_estree::JSXClosingElement) {
588
+ // no-op, should not be counted as a reference
589
+ }
590
+
591
+ fn visit_jsxidentifier(&mut self, ast: &forget_estree::JSXIdentifier) {
592
+ Analyzer::visit_reference_identifier(
593
+ self,
594
+ &ast.name,
595
+ AstNode::from(ast),
596
+ ReferenceKind::Read,
597
+ ast.range,
598
+ );
599
+ }
600
+
601
+ fn visit_jsxfragment(&mut self, ast: &forget_estree::JSXFragment) {
602
+ // TODO: record the pragmas
603
+ for child in &ast.children {
604
+ self.visit_jsxchild_item(child);
605
+ }
606
+ }
607
+
608
+ fn visit_jsxmember_expression(&mut self, ast: &forget_estree::JSXMemberExpression) {
609
+ // NOTE: ignore the 'property' since JSX doesn't support computed properties
610
+ self.visit_jsxmember_expression_or_identifier(&ast.object);
611
+ }
612
+
613
+ fn visit_jsxnamespaced_name(&mut self, ast: &forget_estree::JSXNamespacedName) {
614
+ // NOTE: ignore the 'name' since it doesn't refer to a variable
615
+ self.visit_jsxidentifier(&ast.namespace);
616
+ }
617
+
618
+ fn visit_jsxopening_element(&mut self, ast: &forget_estree::JSXOpeningElement) {
619
+ // TODO: record jsx pragma if root_name is not an FBT name
620
+ let root_name = ast.name.root_name();
621
+
622
+ match &ast.name {
623
+ JSXElementName::JSXIdentifier(name) => {
624
+ // lowercase names are builtins, only visit if this is a user-defined
625
+ // component
626
+ if let Some(first) = root_name.chars().next() {
627
+ if first == first.to_ascii_uppercase() {
628
+ self.visit_jsxidentifier(name);
629
+ }
630
+ } else {
631
+ // TODO: this likely indicates a parse error, since a valid parse
632
+ // should never result in an empty JSXIdentifier node. but just in
633
+ // case we report this rather than silently fail
634
+ self.manager.diagnostics.push(Diagnostic::invalid_syntax(
635
+ "Expected JSXOpenintElement.name to be non-empty",
636
+ name.range,
637
+ ));
638
+ }
639
+ }
640
+ JSXElementName::JSXMemberExpression(name) => {
641
+ if root_name != "this" {
642
+ self.visit_jsxmember_expression(name);
643
+ }
644
+ }
645
+ JSXElementName::JSXNamespacedName(name) => {
646
+ if root_name != "this" {
647
+ self.visit_jsxnamespaced_name(name);
648
+ }
649
+ }
650
+ }
651
+
652
+ for attribute in &ast.attributes {
653
+ self.visit_jsxattribute_or_spread(attribute);
654
+ }
655
+ }
656
}
compiler/forget/crates/forget_semantic_analysis/src/scope_manager.rs
+4
@@ -65,6 +65,10 @@ impl ScopeManager {
65
}
66
}
67
68
+ pub fn diagnostics(&mut self) -> Vec<Diagnostic> {
69
+ std::mem::take(&mut self.diagnostics)
70
+ }
71
+
72
pub fn root(&self) -> &Scope {
73
&self.scopes[self.root.0]
74
}
compiler/forget/crates/forget_semantic_analysis/tests/analysis_test.rs
+10
-3
@@ -1,3 +1,5 @@
1
+use std::fmt::Write;
2
+
3
use forget_hermes_parser::parse;
4
use forget_semantic_analysis::analyze;
5
use insta::{assert_snapshot, glob};
@@ -8,12 +10,17 @@ fn fixtures() {
10
println!("fixture {}", path.to_str().unwrap());
11
let input = std::fs::read_to_string(path).unwrap();
12
let ast = parse(&input, path.to_str().unwrap()).unwrap();
11
- let analysis = analyze(&ast);
13
+ let mut analysis = analyze(&ast);
14
15
let ast_output = serde_json::to_string_pretty(&ast).unwrap();
14
- let analysis_output = format!("{:#?}", analysis.debug());
16
+ let mut output = String::new();
17
+ writeln!(&mut output, "{:#?}", analysis.debug()).unwrap();
18
+ let diagnostics = analysis.diagnostics();
19
+ for diagnostic in diagnostics {
20
+ writeln!(&mut output, "{:#?}", diagnostic).unwrap();
21
+ }
22
assert_snapshot!(format!(
16
- "Input:\n{input}\n\nAST:\n{ast_output}\n\nAnalysis:\n{analysis_output}"
23
+ "Input:\n{input}\n\nAST:\n{ast_output}\n\nAnalysis:\n{output}"
24
));
25
});
26
}
compiler/forget/crates/forget_semantic_analysis/tests/fixtures/globals-and-imports.js
new
+17
@@ -0,0 +1,17 @@
1
+import Foo from "foo";
2
+import * as Bar from "bar";
3
+import { Baz } from "baz";
4
+
5
+function Component(props) {
6
+ let g = global;
7
+ let y = new Array(props.count);
8
+ let s = String("hello");
9
+ let b = Boolean(true);
10
+ let n = Number(0);
11
+ let x = Math.min(props.x, props.y);
12
+ setTimeout(() => {}, 0);
13
+ setInterval(() => {}, 0);
14
+ Foo;
15
+ Bar;
16
+ Baz;
17
+}
compiler/forget/crates/forget_semantic_analysis/tests/snapshots/analysis_test__fixtures@globals-and-imports.js.snap
new
+1219
@@ -0,0 +1,1219 @@
1
+---
2
+source: crates/forget_semantic_analysis/tests/analysis_test.rs
3
+expression: "format!(\"Input:\\n{input}\\n\\nAST:\\n{ast_output}\\n\\nAnalysis:\\n{output}\")"
4
+input_file: crates/forget_semantic_analysis/tests/fixtures/globals-and-imports.js
5
+---
6
+Input:
7
+import Foo from "foo";
8
+import * as Bar from "bar";
9
+import { Baz } from "baz";
10
+
11
+function Component(props) {
12
+ let g = global;
13
+ let y = new Array(props.count);
14
+ let s = String("hello");
15
+ let b = Boolean(true);
16
+ let n = Number(0);
17
+ let x = Math.min(props.x, props.y);
18
+ setTimeout(() => {}, 0);
19
+ setInterval(() => {}, 0);
20
+ Foo;
21
+ Bar;
22
+ Baz;
23
+}
24
+
25
+
26
+AST:
27
+{
28
+ "type": "Program",
29
+ "body": [
30
+ {
31
+ "type": "ImportDeclaration",
32
+ "specifiers": [
33
+ {
34
+ "type": "ImportDefaultSpecifier",
35
+ "local": {
36
+ "type": "Identifier",
37
+ "name": "Foo",
38
+ "typeAnnotation": null,
39
+ "loc": null,
40
+ "range": {
41
+ "start": 0,
42
+ "end": 1
43
+ }
44
+ },
45
+ "loc": null,
46
+ "range": {
47
+ "start": 0,
48
+ "end": 1
49
+ }
50
+ }
51
+ ],
52
+ "source": {
53
+ "type": "StringLiteral",
54
+ "value": "foo",
55
+ "loc": null,
56
+ "range": {
57
+ "start": 0,
58
+ "end": 1
59
+ }
60
+ },
61
+ "loc": null,
62
+ "range": {
63
+ "start": 0,
64
+ "end": 1
65
+ }
66
+ },
67
+ {
68
+ "type": "ImportDeclaration",
69
+ "specifiers": [
70
+ {
71
+ "type": "ImportNamespaceSpecifier",
72
+ "local": {
73
+ "type": "Identifier",
74
+ "name": "Bar",
75
+ "typeAnnotation": null,
76
+ "loc": null,
77
+ "range": {
78
+ "start": 0,
79
+ "end": 1
80
+ }
81
+ },
82
+ "loc": null,
83
+ "range": {
84
+ "start": 0,
85
+ "end": 1
86
+ }
87
+ }
88
+ ],
89
+ "source": {
90
+ "type": "StringLiteral",
91
+ "value": "bar",
92
+ "loc": null,
93
+ "range": {
94
+ "start": 0,
95
+ "end": 1
96
+ }
97
+ },
98
+ "loc": null,
99
+ "range": {
100
+ "start": 0,
101
+ "end": 1
102
+ }
103
+ },
104
+ {
105
+ "type": "ImportDeclaration",
106
+ "specifiers": [
107
+ {
108
+ "type": "ImportSpecifier",
109
+ "imported": {
110
+ "type": "Identifier",
111
+ "name": "Baz",
112
+ "typeAnnotation": null,
113
+ "loc": null,
114
+ "range": {
115
+ "start": 0,
116
+ "end": 1
117
+ }
118
+ },
119
+ "local": {
120
+ "type": "Identifier",
121
+ "name": "Baz",
122
+ "typeAnnotation": null,
123
+ "loc": null,
124
+ "range": {
125
+ "start": 0,
126
+ "end": 1
127
+ }
128
+ },
129
+ "loc": null,
130
+ "range": {
131
+ "start": 0,
132
+ "end": 1
133
+ }
134
+ }
135
+ ],
136
+ "source": {
137
+ "type": "StringLiteral",
138
+ "value": "baz",
139
+ "loc": null,
140
+ "range": {
141
+ "start": 0,
142
+ "end": 1
143
+ }
144
+ },
145
+ "loc": null,
146
+ "range": {
147
+ "start": 0,
148
+ "end": 1
149
+ }
150
+ },
151
+ {
152
+ "type": "FunctionDeclaration",
153
+ "id": {
154
+ "type": "Identifier",
155
+ "name": "Component",
156
+ "typeAnnotation": null,
157
+ "loc": null,
158
+ "range": {
159
+ "start": 0,
160
+ "end": 1
161
+ }
162
+ },
163
+ "params": [
164
+ {
165
+ "type": "Identifier",
166
+ "name": "props",
167
+ "typeAnnotation": null,
168
+ "loc": null,
169
+ "range": {
170
+ "start": 0,
171
+ "end": 1
172
+ }
173
+ }
174
+ ],
175
+ "body": {
176
+ "type": "BlockStatement",
177
+ "body": [
178
+ {
179
+ "type": "VariableDeclaration",
180
+ "kind": "let",
181
+ "declarations": [
182
+ {
183
+ "type": "VariableDeclarator",
184
+ "id": {
185
+ "type": "Identifier",
186
+ "name": "g",
187
+ "typeAnnotation": null,
188
+ "loc": null,
189
+ "range": {
190
+ "start": 0,
191
+ "end": 1
192
+ }
193
+ },
194
+ "init": {
195
+ "type": "Identifier",
196
+ "name": "global",
197
+ "typeAnnotation": null,
198
+ "loc": null,
199
+ "range": {
200
+ "start": 0,
201
+ "end": 1
202
+ }
203
+ },
204
+ "loc": null,
205
+ "range": {
206
+ "start": 0,
207
+ "end": 1
208
+ }
209
+ }
210
+ ],
211
+ "loc": null,
212
+ "range": {
213
+ "start": 0,
214
+ "end": 1
215
+ }
216
+ },
217
+ {
218
+ "type": "VariableDeclaration",
219
+ "kind": "let",
220
+ "declarations": [
221
+ {
222
+ "type": "VariableDeclarator",
223
+ "id": {
224
+ "type": "Identifier",
225
+ "name": "y",
226
+ "typeAnnotation": null,
227
+ "loc": null,
228
+ "range": {
229
+ "start": 0,
230
+ "end": 1
231
+ }
232
+ },
233
+ "init": {
234
+ "type": "NewExpression",
235
+ "callee": {
236
+ "type": "Identifier",
237
+ "name": "Array",
238
+ "typeAnnotation": null,
239
+ "loc": null,
240
+ "range": {
241
+ "start": 0,
242
+ "end": 1
243
+ }
244
+ },
245
+ "arguments": [
246
+ {
247
+ "type": "MemberExpression",
248
+ "object": {
249
+ "type": "Identifier",
250
+ "name": "props",
251
+ "typeAnnotation": null,
252
+ "loc": null,
253
+ "range": {
254
+ "start": 0,
255
+ "end": 1
256
+ }
257
+ },
258
+ "property": {
259
+ "type": "Identifier",
260
+ "name": "count",
261
+ "typeAnnotation": null,
262
+ "loc": null,
263
+ "range": {
264
+ "start": 0,
265
+ "end": 1
266
+ }
267
+ },
268
+ "computed": false,
269
+ "loc": null,
270
+ "range": {
271
+ "start": 0,
272
+ "end": 1
273
+ }
274
+ }
275
+ ],
276
+ "loc": null,
277
+ "range": {
278
+ "start": 0,
279
+ "end": 1
280
+ }
281
+ },
282
+ "loc": null,
283
+ "range": {
284
+ "start": 0,
285
+ "end": 1
286
+ }
287
+ }
288
+ ],
289
+ "loc": null,
290
+ "range": {
291
+ "start": 0,
292
+ "end": 1
293
+ }
294
+ },
295
+ {
296
+ "type": "VariableDeclaration",
297
+ "kind": "let",
298
+ "declarations": [
299
+ {
300
+ "type": "VariableDeclarator",
301
+ "id": {
302
+ "type": "Identifier",
303
+ "name": "s",
304
+ "typeAnnotation": null,
305
+ "loc": null,
306
+ "range": {
307
+ "start": 0,
308
+ "end": 1
309
+ }
310
+ },
311
+ "init": {
312
+ "type": "CallExpression",
313
+ "callee": {
314
+ "type": "Identifier",
315
+ "name": "String",
316
+ "typeAnnotation": null,
317
+ "loc": null,
318
+ "range": {
319
+ "start": 0,
320
+ "end": 1
321
+ }
322
+ },
323
+ "arguments": [
324
+ {
325
+ "type": "StringLiteral",
326
+ "value": "hello",
327
+ "loc": null,
328
+ "range": {
329
+ "start": 0,
330
+ "end": 1
331
+ }
332
+ }
333
+ ],
334
+ "loc": null,
335
+ "range": {
336
+ "start": 0,
337
+ "end": 1
338
+ }
339
+ },
340
+ "loc": null,
341
+ "range": {
342
+ "start": 0,
343
+ "end": 1
344
+ }
345
+ }
346
+ ],
347
+ "loc": null,
348
+ "range": {
349
+ "start": 0,
350
+ "end": 1
351
+ }
352
+ },
353
+ {
354
+ "type": "VariableDeclaration",
355
+ "kind": "let",
356
+ "declarations": [
357
+ {
358
+ "type": "VariableDeclarator",
359
+ "id": {
360
+ "type": "Identifier",
361
+ "name": "b",
362
+ "typeAnnotation": null,
363
+ "loc": null,
364
+ "range": {
365
+ "start": 0,
366
+ "end": 1
367
+ }
368
+ },
369
+ "init": {
370
+ "type": "CallExpression",
371
+ "callee": {
372
+ "type": "Identifier",
373
+ "name": "Boolean",
374
+ "typeAnnotation": null,
375
+ "loc": null,
376
+ "range": {
377
+ "start": 0,
378
+ "end": 1
379
+ }
380
+ },
381
+ "arguments": [
382
+ {
383
+ "type": "BooleanLiteral",
384
+ "value": true,
385
+ "loc": null,
386
+ "range": {
387
+ "start": 0,
388
+ "end": 1
389
+ }
390
+ }
391
+ ],
392
+ "loc": null,
393
+ "range": {
394
+ "start": 0,
395
+ "end": 1
396
+ }
397
+ },
398
+ "loc": null,
399
+ "range": {
400
+ "start": 0,
401
+ "end": 1
402
+ }
403
+ }
404
+ ],
405
+ "loc": null,
406
+ "range": {
407
+ "start": 0,
408
+ "end": 1
409
+ }
410
+ },
411
+ {
412
+ "type": "VariableDeclaration",
413
+ "kind": "let",
414
+ "declarations": [
415
+ {
416
+ "type": "VariableDeclarator",
417
+ "id": {
418
+ "type": "Identifier",
419
+ "name": "n",
420
+ "typeAnnotation": null,
421
+ "loc": null,
422
+ "range": {
423
+ "start": 0,
424
+ "end": 1
425
+ }
426
+ },
427
+ "init": {
428
+ "type": "CallExpression",
429
+ "callee": {
430
+ "type": "Identifier",
431
+ "name": "Number",
432
+ "typeAnnotation": null,
433
+ "loc": null,
434
+ "range": {
435
+ "start": 0,
436
+ "end": 1
437
+ }
438
+ },
439
+ "arguments": [
440
+ {
441
+ "type": "NumericLiteral",
442
+ "value": 0,
443
+ "loc": null,
444
+ "range": {
445
+ "start": 0,
446
+ "end": 1
447
+ }
448
+ }
449
+ ],
450
+ "loc": null,
451
+ "range": {
452
+ "start": 0,
453
+ "end": 1
454
+ }
455
+ },
456
+ "loc": null,
457
+ "range": {
458
+ "start": 0,
459
+ "end": 1
460
+ }
461
+ }
462
+ ],
463
+ "loc": null,
464
+ "range": {
465
+ "start": 0,
466
+ "end": 1
467
+ }
468
+ },
469
+ {
470
+ "type": "VariableDeclaration",
471
+ "kind": "let",
472
+ "declarations": [
473
+ {
474
+ "type": "VariableDeclarator",
475
+ "id": {
476
+ "type": "Identifier",
477
+ "name": "x",
478
+ "typeAnnotation": null,
479
+ "loc": null,
480
+ "range": {
481
+ "start": 0,
482
+ "end": 1
483
+ }
484
+ },
485
+ "init": {
486
+ "type": "CallExpression",
487
+ "callee": {
488
+ "type": "MemberExpression",
489
+ "object": {
490
+ "type": "Identifier",
491
+ "name": "Math",
492
+ "typeAnnotation": null,
493
+ "loc": null,
494
+ "range": {
495
+ "start": 0,
496
+ "end": 1
497
+ }
498
+ },
499
+ "property": {
500
+ "type": "Identifier",
501
+ "name": "min",
502
+ "typeAnnotation": null,
503
+ "loc": null,
504
+ "range": {
505
+ "start": 0,
506
+ "end": 1
507
+ }
508
+ },
509
+ "computed": false,
510
+ "loc": null,
511
+ "range": {
512
+ "start": 0,
513
+ "end": 1
514
+ }
515
+ },
516
+ "arguments": [
517
+ {
518
+ "type": "MemberExpression",
519
+ "object": {
520
+ "type": "Identifier",
521
+ "name": "props",
522
+ "typeAnnotation": null,
523
+ "loc": null,
524
+ "range": {
525
+ "start": 0,
526
+ "end": 1
527
+ }
528
+ },
529
+ "property": {
530
+ "type": "Identifier",
531
+ "name": "x",
532
+ "typeAnnotation": null,
533
+ "loc": null,
534
+ "range": {
535
+ "start": 0,
536
+ "end": 1
537
+ }
538
+ },
539
+ "computed": false,
540
+ "loc": null,
541
+ "range": {
542
+ "start": 0,
543
+ "end": 1
544
+ }
545
+ },
546
+ {
547
+ "type": "MemberExpression",
548
+ "object": {
549
+ "type": "Identifier",
550
+ "name": "props",
551
+ "typeAnnotation": null,
552
+ "loc": null,
553
+ "range": {
554
+ "start": 0,
555
+ "end": 1
556
+ }
557
+ },
558
+ "property": {
559
+ "type": "Identifier",
560
+ "name": "y",
561
+ "typeAnnotation": null,
562
+ "loc": null,
563
+ "range": {
564
+ "start": 0,
565
+ "end": 1
566
+ }
567
+ },
568
+ "computed": false,
569
+ "loc": null,
570
+ "range": {
571
+ "start": 0,
572
+ "end": 1
573
+ }
574
+ }
575
+ ],
576
+ "loc": null,
577
+ "range": {
578
+ "start": 0,
579
+ "end": 1
580
+ }
581
+ },
582
+ "loc": null,
583
+ "range": {
584
+ "start": 0,
585
+ "end": 1
586
+ }
587
+ }
588
+ ],
589
+ "loc": null,
590
+ "range": {
591
+ "start": 0,
592
+ "end": 1
593
+ }
594
+ },
595
+ {
596
+ "type": "ExpressionStatement",
597
+ "expression": {
598
+ "type": "CallExpression",
599
+ "callee": {
600
+ "type": "Identifier",
601
+ "name": "setTimeout",
602
+ "typeAnnotation": null,
603
+ "loc": null,
604
+ "range": {
605
+ "start": 0,
606
+ "end": 1
607
+ }
608
+ },
609
+ "arguments": [
610
+ {
611
+ "type": "ArrowFunctionExpression",
612
+ "id": null,
613
+ "params": [],
614
+ "body": {
615
+ "type": "BlockStatement",
616
+ "body": [],
617
+ "loc": null,
618
+ "range": {
619
+ "start": 0,
620
+ "end": 1
621
+ }
622
+ },
623
+ "generator": false,
624
+ "async": false,
625
+ "loc": null,
626
+ "range": {
627
+ "start": 0,
628
+ "end": 1
629
+ },
630
+ "expression": false,
631
+ "loc": null,
632
+ "range": {
633
+ "start": 0,
634
+ "end": 1
635
+ }
636
+ },
637
+ {
638
+ "type": "NumericLiteral",
639
+ "value": 0,
640
+ "loc": null,
641
+ "range": {
642
+ "start": 0,
643
+ "end": 1
644
+ }
645
+ }
646
+ ],
647
+ "loc": null,
648
+ "range": {
649
+ "start": 0,
650
+ "end": 1
651
+ }
652
+ },
653
+ "directive": null,
654
+ "loc": null,
655
+ "range": {
656
+ "start": 0,
657
+ "end": 1
658
+ }
659
+ },
660
+ {
661
+ "type": "ExpressionStatement",
662
+ "expression": {
663
+ "type": "CallExpression",
664
+ "callee": {
665
+ "type": "Identifier",
666
+ "name": "setInterval",
667
+ "typeAnnotation": null,
668
+ "loc": null,
669
+ "range": {
670
+ "start": 0,
671
+ "end": 1
672
+ }
673
+ },
674
+ "arguments": [
675
+ {
676
+ "type": "ArrowFunctionExpression",
677
+ "id": null,
678
+ "params": [],
679
+ "body": {
680
+ "type": "BlockStatement",
681
+ "body": [],
682
+ "loc": null,
683
+ "range": {
684
+ "start": 0,
685
+ "end": 1
686
+ }
687
+ },
688
+ "generator": false,
689
+ "async": false,
690
+ "loc": null,
691
+ "range": {
692
+ "start": 0,
693
+ "end": 1
694
+ },
695
+ "expression": false,
696
+ "loc": null,
697
+ "range": {
698
+ "start": 0,
699
+ "end": 1
700
+ }
701
+ },
702
+ {
703
+ "type": "NumericLiteral",
704
+ "value": 0,
705
+ "loc": null,
706
+ "range": {
707
+ "start": 0,
708
+ "end": 1
709
+ }
710
+ }
711
+ ],
712
+ "loc": null,
713
+ "range": {
714
+ "start": 0,
715
+ "end": 1
716
+ }
717
+ },
718
+ "directive": null,
719
+ "loc": null,
720
+ "range": {
721
+ "start": 0,
722
+ "end": 1
723
+ }
724
+ },
725
+ {
726
+ "type": "ExpressionStatement",
727
+ "expression": {
728
+ "type": "Identifier",
729
+ "name": "Foo",
730
+ "typeAnnotation": null,
731
+ "loc": null,
732
+ "range": {
733
+ "start": 0,
734
+ "end": 1
735
+ }
736
+ },
737
+ "directive": null,
738
+ "loc": null,
739
+ "range": {
740
+ "start": 0,
741
+ "end": 1
742
+ }
743
+ },
744
+ {
745
+ "type": "ExpressionStatement",
746
+ "expression": {
747
+ "type": "Identifier",
748
+ "name": "Bar",
749
+ "typeAnnotation": null,
750
+ "loc": null,
751
+ "range": {
752
+ "start": 0,
753
+ "end": 1
754
+ }
755
+ },
756
+ "directive": null,
757
+ "loc": null,
758
+ "range": {
759
+ "start": 0,
760
+ "end": 1
761
+ }
762
+ },
763
+ {
764
+ "type": "ExpressionStatement",
765
+ "expression": {
766
+ "type": "Identifier",
767
+ "name": "Baz",
768
+ "typeAnnotation": null,
769
+ "loc": null,
770
+ "range": {
771
+ "start": 0,
772
+ "end": 1
773
+ }
774
+ },
775
+ "directive": null,
776
+ "loc": null,
777
+ "range": {
778
+ "start": 0,
779
+ "end": 1
780
+ }
781
+ }
782
+ ],
783
+ "loc": null,
784
+ "range": {
785
+ "start": 0,
786
+ "end": 1
787
+ }
788
+ },
789
+ "generator": false,
790
+ "async": false,
791
+ "loc": null,
792
+ "range": {
793
+ "start": 0,
794
+ "end": 1
795
+ },
796
+ "loc": null,
797
+ "range": {
798
+ "start": 0,
799
+ "end": 1
800
+ }
801
+ }
802
+ ],
803
+ "sourceType": "module",
804
+ "loc": null,
805
+ "range": {
806
+ "start": 0,
807
+ "end": 1
808
+ }
809
+}
810
+
811
+Analysis:
812
+Scope {
813
+ id: ScopeId(
814
+ 0,
815
+ ),
816
+ kind: Global,
817
+ labels: {},
818
+ declarations: {},
819
+ references: [],
820
+ children: [
821
+ Scope {
822
+ id: ScopeId(
823
+ 1,
824
+ ),
825
+ kind: Module,
826
+ labels: {},
827
+ declarations: {
828
+ "Component": Declaration {
829
+ id: DeclarationId(
830
+ 0,
831
+ ),
832
+ kind: FunctionDeclaration,
833
+ scope: ScopeId(
834
+ 1,
835
+ ),
836
+ },
837
+ },
838
+ references: [],
839
+ children: [
840
+ Scope {
841
+ id: ScopeId(
842
+ 2,
843
+ ),
844
+ kind: Function,
845
+ labels: {},
846
+ declarations: {
847
+ "props": Declaration {
848
+ id: DeclarationId(
849
+ 1,
850
+ ),
851
+ kind: FunctionDeclaration,
852
+ scope: ScopeId(
853
+ 2,
854
+ ),
855
+ },
856
+ "g": Declaration {
857
+ id: DeclarationId(
858
+ 2,
859
+ ),
860
+ kind: Let,
861
+ scope: ScopeId(
862
+ 2,
863
+ ),
864
+ },
865
+ "y": Declaration {
866
+ id: DeclarationId(
867
+ 3,
868
+ ),
869
+ kind: Let,
870
+ scope: ScopeId(
871
+ 2,
872
+ ),
873
+ },
874
+ "s": Declaration {
875
+ id: DeclarationId(
876
+ 4,
877
+ ),
878
+ kind: Let,
879
+ scope: ScopeId(
880
+ 2,
881
+ ),
882
+ },
883
+ "b": Declaration {
884
+ id: DeclarationId(
885
+ 5,
886
+ ),
887
+ kind: Let,
888
+ scope: ScopeId(
889
+ 2,
890
+ ),
891
+ },
892
+ "n": Declaration {
893
+ id: DeclarationId(
894
+ 6,
895
+ ),
896
+ kind: Let,
897
+ scope: ScopeId(
898
+ 2,
899
+ ),
900
+ },
901
+ "x": Declaration {
902
+ id: DeclarationId(
903
+ 7,
904
+ ),
905
+ kind: Let,
906
+ scope: ScopeId(
907
+ 2,
908
+ ),
909
+ },
910
+ },
911
+ references: [
912
+ Reference {
913
+ id: ReferenceId(
914
+ 0,
915
+ ),
916
+ kind: Read,
917
+ declaration: DeclarationId(
918
+ 1,
919
+ ),
920
+ declaration (name): "props",
921
+ scope: ScopeId(
922
+ 2,
923
+ ),
924
+ },
925
+ Reference {
926
+ id: ReferenceId(
927
+ 1,
928
+ ),
929
+ kind: Read,
930
+ declaration: DeclarationId(
931
+ 1,
932
+ ),
933
+ declaration (name): "props",
934
+ scope: ScopeId(
935
+ 2,
936
+ ),
937
+ },
938
+ Reference {
939
+ id: ReferenceId(
940
+ 2,
941
+ ),
942
+ kind: Read,
943
+ declaration: DeclarationId(
944
+ 1,
945
+ ),
946
+ declaration (name): "props",
947
+ scope: ScopeId(
948
+ 2,
949
+ ),
950
+ },
951
+ ],
952
+ children: [
953
+ Scope {
954
+ id: ScopeId(
955
+ 3,
956
+ ),
957
+ kind: Function,
958
+ labels: {},
959
+ declarations: {},
960
+ references: [],
961
+ children: [],
962
+ },
963
+ Scope {
964
+ id: ScopeId(
965
+ 4,
966
+ ),
967
+ kind: Function,
968
+ labels: {},
969
+ declarations: {},
970
+ references: [],
971
+ children: [],
972
+ },
973
+ ],
974
+ },
975
+ ],
976
+ },
977
+ ],
978
+}
979
+Diagnostic(
980
+ DiagnosticData {
981
+ message: "Undefined variable",
982
+ span: Some(
983
+ SourceSpan {
984
+ offset: SourceOffset(
985
+ 0,
986
+ ),
987
+ length: 1,
988
+ },
989
+ ),
990
+ related_information: [],
991
+ severity: InvalidSyntax,
992
+ data: [],
993
+ },
994
+)
995
+Diagnostic(
996
+ DiagnosticData {
997
+ message: "Undefined variable",
998
+ span: Some(
999
+ SourceSpan {
1000
+ offset: SourceOffset(
1001
+ 0,
1002
+ ),
1003
+ length: 1,
1004
+ },
1005
+ ),
1006
+ related_information: [],
1007
+ severity: InvalidSyntax,
1008
+ data: [],
1009
+ },
1010
+)
1011
+Diagnostic(
1012
+ DiagnosticData {
1013
+ message: "Undefined variable",
1014
+ span: Some(
1015
+ SourceSpan {
1016
+ offset: SourceOffset(
1017
+ 0,
1018
+ ),
1019
+ length: 1,
1020
+ },
1021
+ ),
1022
+ related_information: [],
1023
+ severity: InvalidSyntax,
1024
+ data: [],
1025
+ },
1026
+)
1027
+Diagnostic(
1028
+ DiagnosticData {
1029
+ message: "Undefined variable",
1030
+ span: Some(
1031
+ SourceSpan {
1032
+ offset: SourceOffset(
1033
+ 0,
1034
+ ),
1035
+ length: 1,
1036
+ },
1037
+ ),
1038
+ related_information: [],
1039
+ severity: InvalidSyntax,
1040
+ data: [],
1041
+ },
1042
+)
1043
+Diagnostic(
1044
+ DiagnosticData {
1045
+ message: "Undefined variable",
1046
+ span: Some(
1047
+ SourceSpan {
1048
+ offset: SourceOffset(
1049
+ 0,
1050
+ ),
1051
+ length: 1,
1052
+ },
1053
+ ),
1054
+ related_information: [],
1055
+ severity: InvalidSyntax,
1056
+ data: [],
1057
+ },
1058
+)
1059
+Diagnostic(
1060
+ DiagnosticData {
1061
+ message: "Undefined variable",
1062
+ span: Some(
1063
+ SourceSpan {
1064
+ offset: SourceOffset(
1065
+ 0,
1066
+ ),
1067
+ length: 1,
1068
+ },
1069
+ ),
1070
+ related_information: [],
1071
+ severity: InvalidSyntax,
1072
+ data: [],
1073
+ },
1074
+)
1075
+Diagnostic(
1076
+ DiagnosticData {
1077
+ message: "Undefined variable",
1078
+ span: Some(
1079
+ SourceSpan {
1080
+ offset: SourceOffset(
1081
+ 0,
1082
+ ),
1083
+ length: 1,
1084
+ },
1085
+ ),
1086
+ related_information: [],
1087
+ severity: InvalidSyntax,
1088
+ data: [],
1089
+ },
1090
+)
1091
+Diagnostic(
1092
+ DiagnosticData {
1093
+ message: "Undefined variable",
1094
+ span: Some(
1095
+ SourceSpan {
1096
+ offset: SourceOffset(
1097
+ 0,
1098
+ ),
1099
+ length: 1,
1100
+ },
1101
+ ),
1102
+ related_information: [],
1103
+ severity: InvalidSyntax,
1104
+ data: [],
1105
+ },
1106
+)
1107
+Diagnostic(
1108
+ DiagnosticData {
1109
+ message: "Undefined variable",
1110
+ span: Some(
1111
+ SourceSpan {
1112
+ offset: SourceOffset(
1113
+ 0,
1114
+ ),
1115
+ length: 1,
1116
+ },
1117
+ ),
1118
+ related_information: [],
1119
+ severity: InvalidSyntax,
1120
+ data: [],
1121
+ },
1122
+)
1123
+Diagnostic(
1124
+ DiagnosticData {
1125
+ message: "Undefined variable",
1126
+ span: Some(
1127
+ SourceSpan {
1128
+ offset: SourceOffset(
1129
+ 0,
1130
+ ),
1131
+ length: 1,
1132
+ },
1133
+ ),
1134
+ related_information: [],
1135
+ severity: InvalidSyntax,
1136
+ data: [],
1137
+ },
1138
+)
1139
+Diagnostic(
1140
+ DiagnosticData {
1141
+ message: "Undefined variable",
1142
+ span: Some(
1143
+ SourceSpan {
1144
+ offset: SourceOffset(
1145
+ 0,
1146
+ ),
1147
+ length: 1,
1148
+ },
1149
+ ),
1150
+ related_information: [],
1151
+ severity: InvalidSyntax,
1152
+ data: [],
1153
+ },
1154
+)
1155
+Diagnostic(
1156
+ DiagnosticData {
1157
+ message: "Undefined variable",
1158
+ span: Some(
1159
+ SourceSpan {
1160
+ offset: SourceOffset(
1161
+ 0,
1162
+ ),
1163
+ length: 1,
1164
+ },
1165
+ ),
1166
+ related_information: [],
1167
+ severity: InvalidSyntax,
1168
+ data: [],
1169
+ },
1170
+)
1171
+Diagnostic(
1172
+ DiagnosticData {
1173
+ message: "Undefined variable",
1174
+ span: Some(
1175
+ SourceSpan {
1176
+ offset: SourceOffset(
1177
+ 0,
1178
+ ),
1179
+ length: 1,
1180
+ },
1181
+ ),
1182
+ related_information: [],
1183
+ severity: InvalidSyntax,
1184
+ data: [],
1185
+ },
1186
+)
1187
+Diagnostic(
1188
+ DiagnosticData {
1189
+ message: "Undefined variable",
1190
+ span: Some(
1191
+ SourceSpan {
1192
+ offset: SourceOffset(
1193
+ 0,
1194
+ ),
1195
+ length: 1,
1196
+ },
1197
+ ),
1198
+ related_information: [],
1199
+ severity: InvalidSyntax,
1200
+ data: [],
1201
+ },
1202
+)
1203
+Diagnostic(
1204
+ DiagnosticData {
1205
+ message: "Undefined variable",
1206
+ span: Some(
1207
+ SourceSpan {
1208
+ offset: SourceOffset(
1209
+ 0,
1210
+ ),
1211
+ length: 1,
1212
+ },
1213
+ ),
1214
+ related_information: [],
1215
+ severity: InvalidSyntax,
1216
+ data: [],
1217
+ },
1218
+)
1219
+
compiler/forget/crates/forget_semantic_analysis/tests/snapshots/analysis_test__fixtures@labels.js.snap
renamed
+80
-66
@@ -1,6 +1,6 @@
1
---
2
source: crates/forget_semantic_analysis/tests/analysis_test.rs
3
-expression: "format!(\"Input:\\n{input}\\n\\nAST:\\n{ast_output}\\n\\nAnalysis:\\n{analysis_output}\")"
3
+expression: "format!(\"Input:\\n{input}\\n\\nAST:\\n{ast_output}\\n\\nAnalysis:\\n{output}\")"
4
input_file: crates/forget_semantic_analysis/tests/fixtures/labels.js
5
---
6
Input:
@@ -517,43 +517,8 @@ Scope {
517
2,
518
),
519
},
520
- "x": Declaration {
521
- id: DeclarationId(
522
- 3,
523
- ),
524
- kind: Let,
525
- scope: ScopeId(
526
- 2,
527
- ),
528
- },
520
},
521
references: [
531
- Reference {
532
- id: ReferenceId(
533
- 0,
534
- ),
535
- kind: Read,
536
- declaration: DeclarationId(
537
- 3,
538
- ),
539
- declaration (name): "x",
540
- scope: ScopeId(
541
- 2,
542
- ),
543
- },
544
- Reference {
545
- id: ReferenceId(
546
- 1,
547
- ),
548
- kind: Read,
549
- declaration: DeclarationId(
550
- 3,
551
- ),
552
- declaration (name): "x",
553
- scope: ScopeId(
554
- 2,
555
- ),
556
- },
522
Reference {
523
id: ReferenceId(
524
6,
@@ -573,39 +538,23 @@ Scope {
538
id: ScopeId(
539
3,
540
),
576
- kind: Block,
541
+ kind: For,
542
labels: {},
578
- declarations: {},
579
- references: [
580
- Reference {
581
- id: ReferenceId(
582
- 2,
583
- ),
584
- kind: Read,
585
- declaration: DeclarationId(
586
- 3,
587
- ),
588
- declaration (name): "x",
589
- scope: ScopeId(
543
+ declarations: {
544
+ "x": Declaration {
545
+ id: DeclarationId(
546
3,
547
),
592
- },
593
- Reference {
594
- id: ReferenceId(
595
- 3,
596
- ),
597
- kind: ReadWrite,
598
- declaration: DeclarationId(
599
- 2,
600
- ),
601
- declaration (name): "y",
548
+ kind: Let,
549
scope: ScopeId(
550
3,
551
),
552
},
553
+ },
554
+ references: [
555
Reference {
556
id: ReferenceId(
608
- 4,
557
+ 0,
558
),
559
kind: Read,
560
declaration: DeclarationId(
@@ -618,13 +567,13 @@ Scope {
567
},
568
Reference {
569
id: ReferenceId(
621
- 5,
570
+ 1,
571
),
572
kind: Read,
573
declaration: DeclarationId(
625
- 2,
574
+ 3,
575
),
627
- declaration (name): "y",
576
+ declaration (name): "x",
577
scope: ScopeId(
578
3,
579
),
@@ -638,14 +587,78 @@ Scope {
587
kind: Block,
588
labels: {},
589
declarations: {},
641
- references: [],
642
- children: [],
590
+ references: [
591
+ Reference {
592
+ id: ReferenceId(
593
+ 2,
594
+ ),
595
+ kind: Read,
596
+ declaration: DeclarationId(
597
+ 3,
598
+ ),
599
+ declaration (name): "x",
600
+ scope: ScopeId(
601
+ 4,
602
+ ),
603
+ },
604
+ Reference {
605
+ id: ReferenceId(
606
+ 3,
607
+ ),
608
+ kind: ReadWrite,
609
+ declaration: DeclarationId(
610
+ 2,
611
+ ),
612
+ declaration (name): "y",
613
+ scope: ScopeId(
614
+ 4,
615
+ ),
616
+ },
617
+ Reference {
618
+ id: ReferenceId(
619
+ 4,
620
+ ),
621
+ kind: Read,
622
+ declaration: DeclarationId(
623
+ 3,
624
+ ),
625
+ declaration (name): "x",
626
+ scope: ScopeId(
627
+ 4,
628
+ ),
629
+ },
630
+ Reference {
631
+ id: ReferenceId(
632
+ 5,
633
+ ),
634
+ kind: Read,
635
+ declaration: DeclarationId(
636
+ 2,
637
+ ),
638
+ declaration (name): "y",
639
+ scope: ScopeId(
640
+ 4,
641
+ ),
642
+ },
643
+ ],
644
+ children: [
645
+ Scope {
646
+ id: ScopeId(
647
+ 5,
648
+ ),
649
+ kind: Block,
650
+ labels: {},
651
+ declarations: {},
652
+ references: [],
653
+ children: [],
654
+ },
655
+ ],
656
},
657
],
658
},
659
Scope {
660
id: ScopeId(
648
- 5,
661
+ 6,
662
),
663
kind: Block,
664
labels: {},
@@ -659,3 +672,4 @@ Scope {
672
},
673
],
674
}
675
+