slow.monster

STUDIO HAZE · topaz

Topaz source

Open by house policy. Topaz is our own language.

Topaz 5.20 · 56 files

compiler/crates/topaz_self_frontend/topaz/resolver/scopes_walk.tpz

Topaz · 29101 B · Original file

1// Lexical scope construction and resolved-reference traversal.
2// Module tables define cross-file bindings, while this leaf owns local scopes,
3// declarations, captures, and reference observations.
5import raw { keywordKind }
6import types {
7 PreviewResolvedDeclaration,
8 PreviewResolvedExport,
9 PreviewResolvedReference,
10 PreviewResolvedScope,
11 SyntaxNode,
13import unicode { didYouMean }
14import resolver.model_facts {
15 Binding,
16 LocalScope,
17 ModuleTable,
18 ReferenceResolution,
19 ResolverWalkContext,
20 boolAttribute,
21 child,
22 children,
23 diagnostic,
24 isNone,
25 text,
27import resolver.modules_tables {
28 bindingForStatement,
29 catalogTable,
30 collectPatternBindings,
31 effectiveNamespace,
32 exportedBinding,
33 exportedNames,
34 tableBinding,
37function localBinding(scopes: Array<LocalScope>, name: string, namespace: string) -> Option<Binding> {
38 let mut index = scopes.length
39 while index > 0 {
40 index -= 1
41 let scope = scopes[index]
42 let bindings = if namespace == "type" { scope.types } else { scope.values }
43 match bindings.get(name) {
44 case Some(binding) => return Some(binding)
45 case None => ()
46 }
47 }
48 None
51function currentScope(scopes: Array<LocalScope>) -> int {
52 if scopes.length == 0 {
53 return 0
54 }
55 scopes[scopes.length - 1].ordinal
58export function addDeclaration(
59 output: Array<PreviewResolvedDeclaration>,
60 binding: Binding,
61 namespace: string,
62 exported: bool,
63) -> () {
64 let mut target = output
65 target.push(PreviewResolvedDeclaration {
66 moduleIndex: binding.moduleIndex,
67 scopeOrdinal: binding.scopeOrdinal,
68 name: binding.name,
69 namespace: namespace,
70 declarationKind: binding.declarationKind,
71 lo: binding.lo,
72 hi: binding.hi,
73 exported: exported,
74 targetModule: binding.targetModule,
75 targetName: binding.targetName,
76 })
79function addLocalBinding(
80 scopes: Array<LocalScope>,
81 declarations: Array<PreviewResolvedDeclaration>,
82 binding: Binding,
83) -> () {
84 let mut activeScopes = scopes
85 let scope = activeScopes[activeScopes.length - 1]
86 if binding.namespace == "type" {
87 let mut types = scope.types
88 types.insert(binding.name, binding)
89 } else {
90 let mut values = scope.values
91 values.insert(binding.name, binding)
92 }
93 addDeclaration(
94 declarations,
95 binding,
96 binding.namespace,
97 binding.exported,
98 )
101export function appendModuleExports(
102 output: Array<PreviewResolvedExport>,
103 moduleIndexValue: int,
104 table: ModuleTable,
105) -> () {
106 let mut target = output
107 for name in exportedNames(table, "") {
108 match exportedBinding(table, name) {
109 case Some(exported) => {
110 let binding = table.bindings[exported.bindingIndex]
111 target.push(PreviewResolvedExport {
112 moduleIndex: moduleIndexValue,
113 name: name,
114 namespace: exported.namespace,
115 declarationLo: binding.lo,
116 declarationHi: binding.hi,
117 })
118 }
119 case None => ()
120 }
121 }
122 ()
125function unresolvedReference(namespace: string) -> ReferenceResolution {
126 ReferenceResolution {
127 referenceNamespace: namespace,
128 targetModuleIndex: -1,
129 targetLo: 0,
130 targetHi: 0,
131 targetNamespace: "",
132 targetModule: "",
133 targetName: "",
134 }
137function appendReference(
138 context: ResolverWalkContext,
139 scopes: Array<LocalScope>,
140 name: string,
141 role: string,
142 lo: int,
143 hi: int,
144 resolved: ReferenceResolution,
145) -> () {
146 let mut output = context.referenceOutput
147 output.push(PreviewResolvedReference {
148 moduleIndex: context.moduleIndex,
149 scopeOrdinal: currentScope(scopes),
150 name: name,
151 namespace: resolved.referenceNamespace,
152 role: role,
153 lo: lo,
154 hi: hi,
155 targetModuleIndex: resolved.targetModuleIndex,
156 targetLo: resolved.targetLo,
157 targetHi: resolved.targetHi,
158 targetNamespace: resolved.targetNamespace,
159 targetModule: resolved.targetModule,
160 targetName: resolved.targetName,
161 })
164function localReferenceResolution(
165 context: ResolverWalkContext,
166 scopes: Array<LocalScope>,
167 name: string,
168 namespace: string,
169) -> Option<ReferenceResolution> {
170 match localBinding(scopes, name, namespace) {
171 case Some(target) => Some(ReferenceResolution {
172 referenceNamespace: namespace,
173 targetModuleIndex: context.moduleIndex,
174 targetLo: target.lo,
175 targetHi: target.hi,
176 targetNamespace: target.namespace,
177 targetModule: context.table.identity,
178 targetName: name,
179 })
180 case None => None
181 }
184function moduleReferenceResolution(
185 context: ResolverWalkContext,
186 found: Binding,
187 name: string,
188 namespace: string,
189 role: string,
190) -> ReferenceResolution {
191 if found.declarationKind == "selected-import" {
192 return ReferenceResolution {
193 referenceNamespace: namespace,
194 targetModuleIndex: context.moduleIndex,
195 targetLo: found.lo,
196 targetHi: found.hi,
197 targetNamespace: if role == "type" {
198 namespace
199 } else {
200 effectiveNamespace(found, context.tables)
201 },
202 targetModule: if role == "type" {
203 context.table.identity
204 } else {
205 found.targetModule
206 },
207 targetName: if role == "type" { name } else { found.targetName },
208 }
209 } else if found.declarationKind == "namespace-import" {
210 return ReferenceResolution {
211 referenceNamespace: "module",
212 targetModuleIndex: context.moduleIndex,
213 targetLo: found.lo,
214 targetHi: found.hi,
215 targetNamespace: found.namespace,
216 targetModule: found.targetModule,
217 targetName: "",
218 }
219 }
220 ReferenceResolution {
221 referenceNamespace: namespace,
222 targetModuleIndex: context.moduleIndex,
223 targetLo: found.lo,
224 targetHi: found.hi,
225 targetNamespace: found.namespace,
226 targetModule: context.table.identity,
227 targetName: name,
228 }
231function reference(
232 context: ResolverWalkContext,
233 scopes: Array<LocalScope>,
234 name: string,
235 namespace: string,
236 role: string,
237 lo: int,
238 hi: int,
239) -> Option<Binding> {
240 let mut moduleBinding: Option<Binding> = None
241 let resolved = match localReferenceResolution(
242 context,
243 scopes,
244 name,
245 namespace,
246 ) {
247 case Some(value) => value
248 case None => match tableBinding(context.table, name) {
249 case Some(binding) => {
250 moduleBinding = Some(binding)
251 moduleReferenceResolution(
252 context,
253 binding,
254 name,
255 namespace,
256 role,
257 )
258 }
259 case None => unresolvedReference(namespace)
260 }
261 }
262 appendReference(context, scopes, name, role, lo, hi, resolved)
263 moduleBinding
266function namespaceMemberResolution(
267 context: ResolverWalkContext,
268 binding: Binding,
269 member: string,
270 namespace: string,
271 field: SyntaxNode,
272) -> ReferenceResolution {
273 let targetTable = match catalogTable(context.tables, binding.targetModule) {
274 case Some(found) => found
275 case None => return unresolvedReference(namespace)
276 }
277 let targetBinding = tableBinding(targetTable, member)
278 let targetExport = exportedBinding(targetTable, member)
279 let targetNamespace = match targetExport {
280 case Some(exported) => exported.namespace
281 case None => ""
282 }
283 let memberExported = !isNone(targetExport)
284 let keywordNamed = namespace == "value" &&
285 keywordKind(member).startsWith("keyword/")
286 if keywordNamed {
287 diagnostic(
288 context.diagnostics,
289 context.moduleIndex,
290 "TPZ3013",
291 "namespace members are exported declarations and cannot be keyword-named (`{binding.name}.{member}`)",
292 field.lo,
293 field.hi,
294 )
295 } else if !memberExported {
296 let mut recordDefaultPrivateValue = false
297 if namespace == "value" && context.recordDefaultStack.length > 0 {
298 match targetBinding {
299 case Some(privateBinding) => if privateBinding.declarationKind == "let" &&
300 !privateBinding.mutable && !privateBinding.exported {
301 recordDefaultPrivateValue = true
302 }
303 case None => ()
304 }
305 }
306 if !recordDefaultPrivateValue {
307 let hint = didYouMean(
308 member,
309 exportedNames(targetTable, namespace),
310 )
311 diagnostic(
312 context.diagnostics,
313 context.moduleIndex,
314 "TPZ3009",
315 "`{member}` is not exported by `{binding.targetModule}`{hint}",
316 field.lo,
317 field.hi,
318 )
319 }
320 }
321 let target = match targetBinding {
322 case Some(found) => found
323 case None => return unresolvedReference(namespace)
324 }
325 if !keywordNamed && memberExported && namespace == "value" &&
326 targetNamespace == "type" {
327 diagnostic(
328 context.diagnostics,
329 context.moduleIndex,
330 "TPZ3013",
331 "`{member}` is an exported type alias of `{binding.targetModule}`, not a value; use it in type position",
332 field.lo,
333 field.hi,
334 )
335 } else if !keywordNamed && memberExported && namespace == "type" &&
336 targetNamespace != "type" {
337 diagnostic(
338 context.diagnostics,
339 context.moduleIndex,
340 "TPZ3013",
341 "`{member}` is exported by `{binding.targetModule}` but is not a type alias",
342 field.lo,
343 field.hi,
344 )
345 }
346 ReferenceResolution {
347 referenceNamespace: namespace,
348 targetModuleIndex: target.moduleIndex,
349 targetLo: target.lo,
350 targetHi: target.hi,
351 targetNamespace: if namespace == "type" || targetNamespace == "type" {
352 "type"
353 } else {
354 "value"
355 },
356 targetModule: binding.targetModule,
357 targetName: member,
358 }
361function namespaceMember(
362 context: ResolverWalkContext,
363 scopes: Array<LocalScope>,
364 object: SyntaxNode,
365 field: SyntaxNode,
366 namespace: string,
367 role: string,
368) -> bool {
369 let head = text(context.source, object)
370 if match localBinding(scopes, head, "value") {
371 case Some(_) => true
372 case None => false
373 } {
374 return false
375 }
376 let binding = match tableBinding(context.table, head) {
377 case Some(found) => found
378 case None => return false
379 }
380 if binding.declarationKind != "namespace-import" {
381 return false
382 }
383 let member = text(context.source, field)
384 let resolved = namespaceMemberResolution(
385 context,
386 binding,
387 member,
388 namespace,
389 field,
390 )
391 appendReference(
392 context,
393 scopes,
394 "{head}.{member}",
395 role,
396 field.lo,
397 field.hi,
398 resolved,
399 )
400 true
403function pushScope(
404 moduleIndexValue: int,
405 owner: SyntaxNode,
406 kind: string,
407 scopes: Array<LocalScope>,
408 nextScope: Array<int>,
409 output: Array<PreviewResolvedScope>,
410) -> int {
411 let ordinal = nextScope[0]
412 let mut nextScopeBox = nextScope
413 nextScopeBox[0] = ordinal + 1
414 let mut rows = output
415 rows.push(PreviewResolvedScope {
416 moduleIndex: moduleIndexValue,
417 ordinal: ordinal,
418 parentOrdinal: currentScope(scopes),
419 kind: kind,
420 lo: owner.lo,
421 hi: owner.hi,
422 })
423 let mut active = scopes
424 active.push(LocalScope {
425 ordinal: ordinal,
426 values: Map.new(),
427 types: Map.new(),
428 })
429 ordinal
432function popScope(scopes: Array<LocalScope>) -> () {
433 let mut activeScopes = scopes
434 match activeScopes.pop() {
435 case Some(_) => ()
436 case None => ()
437 }
440function bindPattern(
441 moduleIndexValue: int,
442 pattern: SyntaxNode,
443 source: Bytes,
444 declarationKind: string,
445 scopes: Array<LocalScope>,
446 declarations: Array<PreviewResolvedDeclaration>,
447) -> () {
448 let mut names: Array<SyntaxNode> = []
449 collectPatternBindings(pattern, source, names)
450 for name in names {
451 addLocalBinding(scopes, declarations, Binding {
452 moduleIndex: moduleIndexValue,
453 scopeOrdinal: currentScope(scopes),
454 name: text(source, name),
455 namespace: "value",
456 declarationKind: declarationKind,
457 lo: name.lo,
458 hi: name.hi,
459 exported: false,
460 targetModule: "",
461 targetName: "",
462 mutable: false,
463 })
464 }
465 ()
468function walkProtocolStatement(
469 context: ResolverWalkContext,
470 node: SyntaxNode,
471 scopes: Array<LocalScope>,
472) -> () {
473 match child(node, "name") {
474 case Some(name) => {
475 let protocolName = text(context.source, name)
476 let alreadyBound = match localBinding(scopes, protocolName, "type") {
477 case Some(binding) => binding.scopeOrdinal == currentScope(scopes) &&
478 binding.lo == name.lo && binding.hi == name.hi
479 case None => false
480 }
481 if !alreadyBound {
482 let mut declarations = context.declarationOutput
483 declarations.push(PreviewResolvedDeclaration {
484 moduleIndex: context.moduleIndex,
485 scopeOrdinal: currentScope(scopes),
486 name: protocolName,
487 namespace: "type",
488 declarationKind: "protocol",
489 lo: name.lo,
490 hi: name.hi,
491 exported: false,
492 targetModule: "",
493 targetName: "",
494 })
495 }
496 }
497 case None => ()
498 }
499 for method in children(node, "methods") {
500 for parameter in children(method, "parameters") {
501 match child(parameter, "type") {
502 case Some(parameterType) => walkNode(context, parameterType, scopes)
503 case None => ()
504 }
505 }
506 match child(method, "returnType") {
507 case Some(returnType) => walkNode(context, returnType, scopes)
508 case None => ()
509 }
510 }
511 ()
514function walkUsingStatement(
515 context: ResolverWalkContext,
516 node: SyntaxNode,
517 scopes: Array<LocalScope>,
518) -> () {
519 match child(node, "value") {
520 case Some(value) => walkNode(context, value, scopes)
521 case None => ()
522 }
523 match child(node, "body") {
524 case Some(body) => {
525 pushScope(
526 context.moduleIndex,
527 body,
528 "using",
529 scopes,
530 context.nextScope,
531 context.scopeOutput,
532 )
533 match child(node, "name") {
534 case Some(name) => addLocalBinding(
535 scopes,
536 context.declarationOutput,
537 Binding {
538 moduleIndex: context.moduleIndex,
539 scopeOrdinal: currentScope(scopes),
540 name: text(context.source, name),
541 namespace: "value",
542 declarationKind: "using",
543 lo: name.lo,
544 hi: name.hi,
545 exported: false,
546 targetModule: "",
547 targetName: "",
548 mutable: false,
549 },
550 )
551 case None => ()
552 }
553 walkNode(context, body, scopes)
554 popScope(scopes)
555 }
556 case None => ()
557 }
558 ()
561function walkComprehensionExpression(
562 context: ResolverWalkContext,
563 node: SyntaxNode,
564 scopes: Array<LocalScope>,
565) -> () {
566 let mut opened = 0
567 for clause in children(node, "clauses") {
568 if clause.kind == "comprehension-clause/for" {
569 match child(clause, "iterator") {
570 case Some(iterator) => walkNode(context, iterator, scopes)
571 case None => ()
572 }
573 match child(clause, "pattern") {
574 case Some(pattern) => {
575 pushScope(
576 context.moduleIndex,
577 pattern,
578 "comprehension",
579 scopes,
580 context.nextScope,
581 context.scopeOutput,
582 )
583 bindPattern(
584 context.moduleIndex,
585 pattern,
586 context.source,
587 "pattern",
588 scopes,
589 context.declarationOutput,
590 )
591 walkNode(context, pattern, scopes)
592 opened += 1
593 }
594 case None => ()
595 }
596 } else {
597 for part in clause.children {
598 walkNode(context, part, scopes)
599 }
600 }
601 }
602 for found in node.children {
603 if found.field == "body" || found.field == "bodyKey" ||
604 found.field == "bodyValue" {
605 walkNode(context, found, scopes)
606 }
607 }
608 while opened > 0 {
609 popScope(scopes)
610 opened -= 1
611 }
612 ()
615function openPatternScope(
616 context: ResolverWalkContext,
617 pattern: SyntaxNode,
618 scopes: Array<LocalScope>,
619) -> () {
620 walkNode(context, pattern, scopes)
621 pushScope(
622 context.moduleIndex,
623 pattern,
624 "pattern",
625 scopes,
626 context.nextScope,
627 context.scopeOutput,
628 )
629 bindPattern(
630 context.moduleIndex,
631 pattern,
632 context.source,
633 "pattern",
634 scopes,
635 context.declarationOutput,
636 )
637 ()
640function walkMatchCase(
641 context: ResolverWalkContext,
642 node: SyntaxNode,
643 scopes: Array<LocalScope>,
644) -> () {
645 let mut opened = false
646 match child(node, "pattern") {
647 case Some(pattern) => {
648 openPatternScope(context, pattern, scopes)
649 opened = true
650 }
651 case None => ()
652 }
653 for found in node.children {
654 if found.field != "pattern" {
655 walkNode(context, found, scopes)
656 }
657 }
658 if opened {
659 popScope(scopes)
660 }
661 ()
664function walkForExpression(
665 context: ResolverWalkContext,
666 node: SyntaxNode,
667 scopes: Array<LocalScope>,
668) -> () {
669 match child(node, "iterator") {
670 case Some(iterator) => walkNode(context, iterator, scopes)
671 case None => ()
672 }
673 let mut opened = false
674 match child(node, "pattern") {
675 case Some(pattern) => {
676 openPatternScope(context, pattern, scopes)
677 opened = true
678 }
679 case None => ()
680 }
681 for found in node.children {
682 if found.field != "iterator" && found.field != "pattern" {
683 walkNode(context, found, scopes)
684 }
685 }
686 if opened {
687 popScope(scopes)
688 }
689 ()
692function resolveAssignmentIdentifier(
693 context: ResolverWalkContext,
694 target: SyntaxNode,
695 scopes: Array<LocalScope>,
696) -> () {
697 let name = text(context.source, target)
698 let binding = match reference(
699 context,
700 scopes,
701 name,
702 "value",
703 "write",
704 target.lo,
705 target.hi,
706 ) {
707 case Some(found) => found
708 case None => return ()
709 }
710 if binding.declarationKind == "selected-import" {
711 diagnostic(
712 context.diagnostics,
713 context.moduleIndex,
714 "TPZ3015",
715 "`{name}` is an imported binding and cannot be assigned",
716 target.lo,
717 target.hi,
718 )
719 } else if binding.declarationKind == "namespace-import" {
720 diagnostic(
721 context.diagnostics,
722 context.moduleIndex,
723 "TPZ3012",
724 "`{name}` is a namespace, not a value; it may appear only as `{name}.member`",
725 target.lo,
726 target.hi,
727 )
728 }
729 ()
732function rejectNamespaceAssignment(
733 context: ResolverWalkContext,
734 target: SyntaxNode,
735 scopes: Array<LocalScope>,
736) -> bool {
737 if target.kind != "expression/member" {
738 return false
739 }
740 let object = match child(target, "object") {
741 case Some(found) => found
742 case None => return false
743 }
744 if object.kind != "expression/identifier" {
745 return false
746 }
747 let name = text(context.source, object)
748 if !isNone(localBinding(scopes, name, "value")) {
749 return false
750 }
751 let binding = match tableBinding(context.table, name) {
752 case Some(found) => found
753 case None => return false
754 }
755 if binding.declarationKind != "namespace-import" {
756 return false
757 }
758 let member = match child(target, "field") {
759 case Some(field) => text(context.source, field)
760 case None => ""
761 }
762 diagnostic(
763 context.diagnostics,
764 context.moduleIndex,
765 "TPZ3015",
766 "`{name}.{member}` is an exported binding viewed through a namespace and cannot be assigned",
767 target.lo,
768 target.hi,
769 )
770 true
773function walkAssignmentStatement(
774 context: ResolverWalkContext,
775 node: SyntaxNode,
776 scopes: Array<LocalScope>,
777) -> () {
778 match child(node, "target") {
779 case Some(target) => if target.kind == "expression/identifier" {
780 resolveAssignmentIdentifier(context, target, scopes)
781 } else if !rejectNamespaceAssignment(context, target, scopes) {
782 walkNode(context, target, scopes)
783 }
784 case None => ()
785 }
786 match child(node, "value") {
787 case Some(value) => walkNode(context, value, scopes)
788 case None => ()
789 }
790 ()
793function resolveNamedTypeReference(
794 context: ResolverWalkContext,
795 node: SyntaxNode,
796 scopes: Array<LocalScope>,
797) -> () {
798 match child(node, "name") {
799 case Some(name) => {
800 reference(
801 context,
802 scopes,
803 text(context.source, name),
804 "type",
805 "type",
806 name.lo,
807 name.hi,
808 )
809 ()
810 }
811 case None => ()
812 }
813 ()
816function resolveQualifiedTypeReference(
817 context: ResolverWalkContext,
818 node: SyntaxNode,
819 scopes: Array<LocalScope>,
820) -> () {
821 match child(node, "namespace") {
822 case Some(namespaceNode) => match child(node, "name") {
823 case Some(name) => if !namespaceMember(
824 context,
825 scopes,
826 namespaceNode,
827 name,
828 "type",
829 "type",
830 ) {
831 diagnostic(
832 context.diagnostics,
833 context.moduleIndex,
834 "TPZ3013",
835 "the head of a qualified type must be a namespace binding; `{text(context.source, namespaceNode)}` is not one here",
836 namespaceNode.lo,
837 namespaceNode.hi,
838 )
839 }
840 case None => ()
841 }
842 case None => ()
843 }
844 ()
847function resolveValueIdentifier(
848 context: ResolverWalkContext,
849 node: SyntaxNode,
850 scopes: Array<LocalScope>,
851) -> () {
852 let name = text(context.source, node)
853 let binding = match reference(
854 context,
855 scopes,
856 name,
857 "value",
858 "read",
859 node.lo,
860 node.hi,
861 ) {
862 case Some(found) => found
863 case None => return ()
864 }
865 if binding.declarationKind == "namespace-import" {
866 diagnostic(
867 context.diagnostics,
868 context.moduleIndex,
869 "TPZ3012",
870 "`{name}` is a namespace, not a value; it may appear only as `{name}.member`",
871 node.lo,
872 node.hi,
873 )
874 }
875 ()
878function resolveNamespaceMemberReference(
879 context: ResolverWalkContext,
880 node: SyntaxNode,
881 scopes: Array<LocalScope>,
882) -> bool {
883 if node.kind != "expression/member" {
884 return false
885 }
886 match child(node, "object") {
887 case Some(object) => match child(node, "field") {
888 case Some(field) => object.kind == "expression/identifier" &&
889 namespaceMember(
890 context,
891 scopes,
892 object,
893 field,
894 "value",
895 "namespace-member",
896 )
897 case None => false
898 }
899 case None => false
900 }
903function walkCallableSignature(
904 context: ResolverWalkContext,
905 node: SyntaxNode,
906 scopes: Array<LocalScope>,
907) -> () {
908 if node.kind != "function-declaration" &&
909 node.kind != "expression/lambda" {
910 return ()
911 }
912 for parameter in children(node, "parameters") {
913 for part in parameter.children {
914 if part.field == "type" || part.field == "default" {
915 walkNode(context, part, scopes)
916 }
917 }
918 }
919 match child(node, "returnType") {
920 case Some(returnType) => walkNode(context, returnType, scopes)
921 case None => ()
922 }
923 ()
926function openNodeScope(
927 context: ResolverWalkContext,
928 node: SyntaxNode,
929 scopes: Array<LocalScope>,
930) -> bool {
931 let kind = match node.kind {
932 case "function-declaration" => "function"
933 case "expression/lambda" => "lambda"
934 case "block" => "block"
935 case _ => ""
936 }
937 if kind == "" {
938 return false
939 }
940 let ordinal = pushScope(
941 context.moduleIndex,
942 node,
943 kind,
944 scopes,
945 context.nextScope,
946 context.scopeOutput,
947 )
948 if node.kind == "function-declaration" ||
949 node.kind == "expression/lambda" {
950 for parameter in children(node, "parameters") {
951 match child(parameter, "name") {
952 case Some(name) => addLocalBinding(
953 scopes,
954 context.declarationOutput,
955 Binding {
956 moduleIndex: context.moduleIndex,
957 scopeOrdinal: ordinal,
958 name: text(context.source, name),
959 namespace: "value",
960 declarationKind: "parameter",
961 lo: name.lo,
962 hi: name.hi,
963 exported: false,
964 targetModule: "",
965 targetName: "",
966 mutable: false,
967 },
968 )
969 case None => ()
970 }
971 }
972 }
973 true
976function prebindChildDeclaration(
977 context: ResolverWalkContext,
978 childNode: SyntaxNode,
979 scopes: Array<LocalScope>,
980) -> () {
981 if scopes.length == 0 {
982 return ()
983 }
984 for candidate in bindingForStatement(
985 context.moduleIndex,
986 childNode,
987 context.source,
988 false,
989 ) {
990 if candidate.declarationKind != "let" &&
991 candidate.declarationKind != "const" &&
992 candidate.declarationKind != "namespace-import" &&
993 candidate.declarationKind != "selected-import" {
994 addLocalBinding(
995 scopes,
996 context.declarationOutput,
997 Binding {
998 moduleIndex: context.moduleIndex,
999 scopeOrdinal: currentScope(scopes),
1000 name: candidate.name,
1001 namespace: candidate.namespace,
1002 declarationKind: candidate.declarationKind,
1003 lo: candidate.lo,
1004 hi: candidate.hi,
1005 exported: false,
1006 targetModule: "",
1007 targetName: "",
1008 mutable: candidate.mutable,
1009 },
1013 ()
1016function bindStatementAfterWalk(
1017 context: ResolverWalkContext,
1018 node: SyntaxNode,
1019 scopes: Array<LocalScope>,
1020) -> () {
1021 if node.kind == "statement/let" {
1022 match child(node, "pattern") {
1023 case Some(pattern) => {
1024 let mut names: Array<SyntaxNode> = []
1025 collectPatternBindings(pattern, context.source, names)
1026 for name in names {
1027 addLocalBinding(
1028 scopes,
1029 context.declarationOutput,
1030 Binding {
1031 moduleIndex: context.moduleIndex,
1032 scopeOrdinal: currentScope(scopes),
1033 name: text(context.source, name),
1034 namespace: "value",
1035 declarationKind: "let",
1036 lo: name.lo,
1037 hi: name.hi,
1038 exported: false,
1039 targetModule: "",
1040 targetName: "",
1041 mutable: boolAttribute(node, "mutable"),
1042 },
1046 case None => ()
1048 } else if node.kind == "statement/const" && scopes.length > 0 {
1049 match child(node, "name") {
1050 case Some(name) => addLocalBinding(
1051 scopes,
1052 context.declarationOutput,
1053 Binding {
1054 moduleIndex: context.moduleIndex,
1055 scopeOrdinal: currentScope(scopes),
1056 name: text(context.source, name),
1057 namespace: "value",
1058 declarationKind: "const",
1059 lo: name.lo,
1060 hi: name.hi,
1061 exported: false,
1062 targetModule: "",
1063 targetName: "",
1064 mutable: false,
1065 },
1067 case None => ()
1070 ()
1073function walkNodeChildren(
1074 context: ResolverWalkContext,
1075 node: SyntaxNode,
1076 scopes: Array<LocalScope>,
1077) -> () {
1078 if node.kind == "block" {
1079 for statement in children(node, "statements") {
1080 if statement.kind == "statement/function" {
1081 prebindChildDeclaration(context, statement, scopes)
1085 for found in node.children {
1086 if found.kind == "identifier" {
1087 continue
1089 if node.kind == "expression/call" && found.field == "typeArguments" {
1090 continue
1092 if (node.kind == "function-declaration" ||
1093 node.kind == "expression/lambda") &&
1094 (found.field == "parameters" || found.field == "returnType") {
1095 continue
1097 if !(node.kind == "block" && found.kind == "statement/function") {
1098 prebindChildDeclaration(context, found, scopes)
1100 let recordDefault = node.kind == "record-field-declaration" &&
1101 found.field == "default"
1102 if recordDefault {
1103 let mut stack = context.recordDefaultStack
1104 stack.push(true)
1106 walkNode(context, found, scopes)
1107 if recordDefault {
1108 let mut stack = context.recordDefaultStack
1109 stack.pop()
1111 bindStatementAfterWalk(context, found, scopes)
1113 ()
1116export function walkNode(
1117 context: ResolverWalkContext,
1118 nodeValue: SyntaxNode,
1119 scopes: Array<LocalScope>,
1120) -> () {
1121 let mut activeScopes = scopes
1122 if nodeValue.kind == "identifier" {
1123 return ()
1125 if nodeValue.kind == "statement/protocol" {
1126 walkProtocolStatement(context, nodeValue, activeScopes)
1127 return ()
1129 if nodeValue.kind == "statement/using" {
1130 walkUsingStatement(context, nodeValue, activeScopes)
1131 return ()
1133 if nodeValue.kind == "expression/comprehension" {
1134 walkComprehensionExpression(context, nodeValue, activeScopes)
1135 return ()
1137 if nodeValue.kind == "match-case" {
1138 walkMatchCase(context, nodeValue, activeScopes)
1139 return ()
1141 if nodeValue.kind == "expression/for" {
1142 walkForExpression(context, nodeValue, activeScopes)
1143 return ()
1145 if nodeValue.kind == "statement/assign" {
1146 walkAssignmentStatement(context, nodeValue, scopes)
1147 return ()
1149 if nodeValue.kind == "type/named" {
1150 resolveNamedTypeReference(context, nodeValue, scopes)
1151 } else if nodeValue.kind == "pattern/nominal-record" {
1152 resolveNamedTypeReference(context, nodeValue, scopes)
1153 } else if nodeValue.kind == "type/qualified" {
1154 resolveQualifiedTypeReference(context, nodeValue, scopes)
1155 } else if nodeValue.kind == "expression/identifier" {
1156 resolveValueIdentifier(context, nodeValue, scopes)
1157 } else if resolveNamespaceMemberReference(context, nodeValue, scopes) {
1158 return ()
1161 walkCallableSignature(context, nodeValue, scopes)
1162 let opened = openNodeScope(context, nodeValue, activeScopes)
1163 walkNodeChildren(context, nodeValue, activeScopes)
1164 if opened {
1165 popScope(activeScopes)

SHA256 7ca10a9b0f96e19e723d3450a616420820c562e6d646013090ddf508622a59fb