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/checker/syntax_index.tpz

Topaz · 21372 B · Original file

1// Syntax lookup and module indexes shared by checker phases.
2// It translates resolved preview rows into stable node and source views without
3// making type decisions or emitting diagnostics on its own.
5import types {
6 PreviewAstAttribute,
7 PreviewCheckDiagnostic,
8 PreviewModuleResult,
9 PreviewResolvedDeclaration,
10 PreviewResolvedReference,
11 PreviewResolvedScope,
12 PreviewTypedNode,
13 ResolveResult,
14 SyntaxNode,
16import checker_types { TypeValue }
17import checker.model {
18 CheckerState,
19 EnumDefinition,
20 FunctionBound,
21 FunctionDefinition,
22 ModuleSyntax,
23 NamedNominalTarget,
24 NewtypeDefinition,
25 ProtocolDefinition,
26 ProtocolMethodDefinition,
27 RecordDefinition,
28 SymbolType,
29 TYPE_BOUND_INDEX_STRIDE,
30 TypeParameterFact,
31 nominal,
32 rigid,
34import checker.type_algebra {
35 flattenType,
36 hasHole,
39export function text(source: Bytes, node: SyntaxNode) -> string {
40 match source.slice(node.lo, node.hi).decodeUtf8() {
41 case Ok(value) => value
42 case Err(_) => ""
43 }
46export function child(value: SyntaxNode, field: string) -> Option<SyntaxNode> {
47 for found in value.children {
48 if found.field == field {
49 return Some(found)
50 }
51 }
52 None
55export function children(value: SyntaxNode, field: string) -> Array<SyntaxNode> {
56 let mut output: Array<SyntaxNode> = []
57 for found in value.children {
58 if found.field == field {
59 output.push(found)
60 }
61 }
62 output
65export function attribute(value: SyntaxNode, name: string) -> string {
66 for found in value.attributes {
67 if found.name == name {
68 return found.value
69 }
70 }
71 ""
74export function boolAttribute(value: SyntaxNode, name: string) -> bool {
75 attribute(value, name) == "true"
78export function unwrapExport(value: SyntaxNode) -> SyntaxNode {
79 if value.kind == "statement/export" {
80 match child(value, "item") {
81 case Some(item) => item
82 case None => value
83 }
84 } else {
85 value
86 }
89export function spanKey(moduleIndex: int, lo: int, hi: int) -> string {
90 "{moduleIndex}:{lo}:{hi}"
93function nodeKey(moduleIndex: int, kind: string, lo: int, hi: int) -> string {
94 "{moduleIndex}:{kind}:{lo}:{hi}"
97export function typedNodeIndex(
98 state: CheckerState,
99 moduleIndex: int,
100 kind: string,
101 lo: int,
102 hi: int,
103) -> int {
104 match state.nodeIndexes.get(nodeKey(moduleIndex, kind, lo, hi)) {
105 case Some(index) => index
106 case None => -1
107 }
110export function scopeKey(moduleIndex: int, ordinal: int) -> string {
111 "{moduleIndex}:{ordinal}"
114export function definitionNameKey(moduleIndex: int, name: string) -> string {
115 "{moduleIndex}:{name}"
118export function emptyStringIntMap() -> Map<string, int> {
119 let mut value = map { "": 0 }
120 value.remove("")
121 value
124export function declarationFor(
125 state: CheckerState,
126 moduleIndex: int,
127 lo: int,
128 hi: int,
129) -> Option<PreviewResolvedDeclaration> {
130 match state.declarationIndexes.get(spanKey(moduleIndex, lo, hi)) {
131 case Some(index) => match state.resolved.declarations.get(index) {
132 case Some(declaration) => Some(declaration)
133 case None => None
134 }
135 case None => None
136 }
139export function referenceFor(
140 state: CheckerState,
141 moduleIndex: int,
142 lo: int,
143 hi: int,
144) -> Option<PreviewResolvedReference> {
145 match state.referenceIndexes.get(spanKey(moduleIndex, lo, hi)) {
146 case Some(index) => match state.resolved.references.get(index) {
147 case Some(reference) => Some(reference)
148 case None => None
149 }
150 case None => None
151 }
154export function symbolAt(
155 state: CheckerState,
156 moduleIndex: int,
157 lo: int,
158 hi: int,
159) -> Option<SymbolType> {
160 match state.symbolIndexes.get(spanKey(moduleIndex, lo, hi)) {
161 case Some(index) => match state.symbols.get(index) {
162 case Some(symbol) => Some(symbol)
163 case None => None
164 }
165 case None => None
166 }
169export function symbolTypeAt(
170 state: CheckerState,
171 moduleIndex: int,
172 lo: int,
173 hi: int,
174) -> Option<TypeValue> {
175 match symbolAt(state, moduleIndex, lo, hi) {
176 case Some(symbol) => Some(symbol.typeValue)
177 case None => None
178 }
181export function moduleIndexByIdentity(
182 state: CheckerState,
183 identity: string,
184) -> int {
185 for module in state.modules {
186 if module.identity == identity {
187 return module.moduleIndex
188 }
189 }
190 -1
193export function symbolTypeByName(
194 state: CheckerState,
195 moduleIndex: int,
196 name: string,
197 namespace: string,
198) -> Option<TypeValue> {
199 for declaration in state.resolved.declarations {
200 if declaration.moduleIndex == moduleIndex &&
201 declaration.name == name &&
202 declaration.namespace == namespace {
203 match symbolTypeAt(
204 state,
205 moduleIndex,
206 declaration.lo,
207 declaration.hi,
208 ) {
209 case Some(found) => return Some(found)
210 case None => ()
211 }
212 }
213 }
214 None
217export function bindSymbol(
218 state: CheckerState,
219 moduleIndex: int,
220 lo: int,
221 hi: int,
222 name: string,
223 typeValue: TypeValue,
224 mutable: bool,
225) -> () {
226 let mut target = state.symbols
227 let key = spanKey(moduleIndex, lo, hi)
228 match state.symbolIndexes.get(key) {
229 case Some(index) => match target.get(index) {
230 case Some(symbol) => {
231 target[index] = SymbolType {
232 moduleIndex: symbol.moduleIndex,
233 lo: symbol.lo,
234 hi: symbol.hi,
235 name: symbol.name,
236 typeValue: typeValue,
237 mutable: mutable,
238 }
239 }
240 case None => ()
241 }
242 case None => {
243 let mut indexes = state.symbolIndexes
244 indexes.insert(key, target.length)
245 target.push(SymbolType {
246 moduleIndex: moduleIndex,
247 lo: lo,
248 hi: hi,
249 name: name,
250 typeValue: typeValue,
251 mutable: mutable,
252 })
253 }
254 }
257export function resolvedTypeOfReference(
258 state: CheckerState,
259 moduleIndex: int,
260 node: SyntaxNode,
261) -> Option<TypeValue> {
262 match referenceFor(state, moduleIndex, node.lo, node.hi) {
263 case Some(reference) => resolvedTypeFromFact(state, reference)
264 case None => None
265 }
268export function resolvedTypeFromFact(
269 state: CheckerState,
270 reference: PreviewResolvedReference,
271) -> Option<TypeValue> {
272 if reference.targetModuleIndex < 0 {
273 return None
274 }
275 match symbolTypeAt(
276 state,
277 reference.targetModuleIndex,
278 reference.targetLo,
279 reference.targetHi,
280 ) {
281 case Some(found) => return Some(found)
282 case None => ()
283 }
284 match declarationFor(
285 state,
286 reference.targetModuleIndex,
287 reference.targetLo,
288 reference.targetHi,
289 ) {
290 case Some(declaration) => {
291 if declaration.targetModule == "" {
292 return None
293 }
294 let targetModule = moduleIndexByIdentity(
295 state,
296 declaration.targetModule,
297 )
298 symbolTypeByName(
299 state,
300 targetModule,
301 declaration.targetName,
302 reference.targetNamespace,
303 )
304 }
305 case None => None
306 }
309export function addNode(
310 state: CheckerState,
311 moduleIndex: int,
312 kind: string,
313 node: SyntaxNode,
314 typeValue: TypeValue,
315) -> () {
316 let mut target = state.nodes
317 let key = nodeKey(moduleIndex, kind, node.lo, node.hi)
318 match state.nodeIndexes.get(key) {
319 case Some(_) => return ()
320 case None => ()
321 }
322 let mut indexes = state.nodeIndexes
323 indexes.insert(key, target.length)
324 target.push(PreviewTypedNode {
325 moduleIndex: moduleIndex,
326 nodeKind: kind,
327 lo: node.lo,
328 hi: node.hi,
329 typeValue: flattenType(typeValue),
330 ambient: hasHole(typeValue),
331 })
334export function replaceNodeType(
335 state: CheckerState,
336 moduleIndex: int,
337 kind: string,
338 node: SyntaxNode,
339 typeValue: TypeValue,
340) -> () {
341 if typeValue.kind == "unknown" {
342 return ()
343 }
344 let mut target = state.nodes
345 let key = nodeKey(moduleIndex, kind, node.lo, node.hi)
346 match state.nodeIndexes.get(key) {
347 case Some(index) => {
348 match target.get(index) {
349 case Some(_) => {
350 target[index] = PreviewTypedNode {
351 moduleIndex: moduleIndex,
352 nodeKind: kind,
353 lo: node.lo,
354 hi: node.hi,
355 typeValue: flattenType(typeValue),
356 ambient: hasHole(typeValue),
357 }
358 return ()
359 }
360 case None => ()
361 }
362 }
363 case None => ()
364 }
365 addNode(state, moduleIndex, kind, node, typeValue)
368export function addDiagnostic(
369 state: CheckerState,
370 moduleIndex: int,
371 code: string,
372 message: string,
373 primaryMessage: string,
374 node: SyntaxNode,
375) -> () {
376 let mut target = state.diagnostics
377 target.push(PreviewCheckDiagnostic {
378 moduleIndex: moduleIndex,
379 code: code,
380 message: message,
381 primaryMessage: primaryMessage,
382 lo: node.lo,
383 hi: node.hi,
384 secondary: [],
385 notes: [],
386 profileRule: "",
387 })
390function syntaxFromFlat(
391 module: PreviewModuleResult,
392 maxAstNodes: int,
393 maxAstDepth: int,
394) -> Result<SyntaxNode, string> {
395 if module.ast.length == 0 {
396 return Err("checker received a module without an AST")
397 }
398 if module.ast.length > maxAstNodes {
399 return Err("front-end preview AST node count exceeds {maxAstNodes}")
400 }
401 let mut rows: Array<SyntaxNode> = []
402 let mut depths: Array<int> = []
403 let mut ordinal = 0
404 for flat in module.ast {
405 let mut attributes: Array<PreviewAstAttribute> = []
406 if flat.attributeNames.length != flat.attributeKinds.length ||
407 flat.attributeNames.length != flat.attributeValues.length {
408 return Err("checker received malformed AST attributes")
409 }
410 let mut attributeIndex = 0
411 while attributeIndex < flat.attributeNames.length {
412 attributes.push(PreviewAstAttribute {
413 name: match flat.attributeNames.get(attributeIndex) {
414 case Some(value) => value
415 case None => ""
416 },
417 kind: match flat.attributeKinds.get(attributeIndex) {
418 case Some(value) => value
419 case None => ""
420 },
421 value: match flat.attributeValues.get(attributeIndex) {
422 case Some(value) => value
423 case None => ""
424 },
425 })
426 attributeIndex += 1
427 }
428 let depth = if ordinal == 0 {
429 if flat.parent != -1 {
430 return Err("checker received an AST root with a parent")
431 }
432 0
433 } else {
434 if flat.parent < 0 || flat.parent >= ordinal {
435 return Err("checker received a non-preorder AST parent")
436 }
437 match depths.get(flat.parent) {
438 case Some(parentDepth) => parentDepth + 1
439 case None => return Err("checker received a missing AST parent")
440 }
441 }
442 if depth > maxAstDepth {
443 return Err("front-end preview AST depth exceeds {maxAstDepth}")
444 }
445 let rebuilt = SyntaxNode {
446 kind: flat.kind,
447 lo: flat.lo,
448 hi: flat.hi,
449 field: flat.field,
450 index: flat.index,
451 attributes: attributes,
452 children: [],
453 }
454 rows.push(rebuilt)
455 depths.push(depth)
456 if flat.parent >= 0 {
457 match rows.get(flat.parent) {
458 case Some(parent) => {
459 let mut children = parent.children
460 children.push(rebuilt)
461 }
462 case None => return Err("checker received a missing AST parent")
463 }
464 }
465 ordinal += 1
466 }
467 match rows.get(0) {
468 case Some(root) => Ok(root)
469 case None => Err("checker received a module without an AST")
470 }
473export function moduleSyntax(
474 resolved: ResolveResult,
475 maxAstNodes: int,
476 maxAstDepth: int,
477) -> Result<Array<ModuleSyntax>, string> {
478 let mut modules: Array<ModuleSyntax> = []
479 let mut index = 0
480 for module in resolved.modules {
481 let source = Bytes.encodeUtf8(module.source)
482 modules.push(ModuleSyntax {
483 moduleIndex: index,
484 sourceOrdinal: module.sourceOrdinal,
485 identity: module.identity,
486 source: source,
487 root: syntaxFromFlat(module, maxAstNodes, maxAstDepth)?,
488 generatedStd: module.generatedStd,
489 })
490 index += 1
491 }
492 Ok(modules)
495export function moduleAt(state: CheckerState, moduleIndex: int) -> Option<ModuleSyntax> {
496 state.modules.get(moduleIndex)
499export function typeParameterNames(source: Bytes, node: SyntaxNode) -> Array<string> {
500 let mut output: Array<string> = []
501 for parameter in children(node, "typeParameters") {
502 output.push(text(source, parameter))
503 }
504 output
507export function functionBounds(source: Bytes, node: SyntaxNode) -> Array<FunctionBound> {
508 let parameters = typeParameterNames(source, node)
509 let mut output: Array<FunctionBound> = []
510 for bound in children(node, "typeParameterBounds") {
511 let mut parameterIndex = 0
512 let mut encoded = bound.index
513 while encoded >= TYPE_BOUND_INDEX_STRIDE {
514 encoded -= TYPE_BOUND_INDEX_STRIDE
515 parameterIndex += 1
516 }
517 match parameters.get(parameterIndex) {
518 case Some(parameterName) => output.push(FunctionBound {
519 parameterName: parameterName,
520 protocol: text(source, bound),
521 })
522 case None => ()
523 }
524 }
525 output
528export function registerTypeParameters(
529 state: CheckerState,
530 moduleIndex: int,
531 source: Bytes,
532 node: SyntaxNode,
533) -> () {
534 let mut facts = state.typeParameters
535 let sourceOrdinal = match moduleAt(state, moduleIndex) {
536 case Some(found) => found.sourceOrdinal
537 case None => moduleIndex
538 }
539 let owner = "source:{sourceOrdinal}:{node.lo}:{node.hi}"
540 for parameter in children(node, "typeParameters") {
541 facts.push(TypeParameterFact {
542 moduleIndex: moduleIndex,
543 owner: owner,
544 name: text(source, parameter),
545 origin: "source:{sourceOrdinal}:{parameter.lo}:{parameter.hi}",
546 })
547 }
548 ()
551export function typeParameterOrigin(
552 state: CheckerState,
553 moduleIndex: int,
554 name: string,
555 fallback: string,
556) -> string {
557 let mut result = fallback
558 for fact in state.typeParameters {
559 if fact.moduleIndex == moduleIndex && fact.owner == fallback &&
560 fact.name == name {
561 result = fact.origin
562 }
563 }
564 result
567export function activeTypeParameter(
568 state: CheckerState,
569 moduleIndex: int,
570 name: string,
571) -> Option<TypeValue> {
572 let mut activeIndex = state.activeFunctions.length
573 while activeIndex > 0 {
574 activeIndex -= 1
575 match state.activeFunctions.get(activeIndex) {
576 case Some(functionIndex) => match state.functions.get(functionIndex) {
577 case Some(definition) => if definition.moduleIndex == moduleIndex {
578 let mut parameterIndex = 0
579 for parameterName in definition.typeParameters {
580 if parameterName == name {
581 return match definition.typeParameterOrigins.get(parameterIndex) {
582 case Some(origin) => Some(rigid(name, origin))
583 case None => None
584 }
585 }
586 parameterIndex += 1
587 }
588 }
589 case None => ()
590 }
591 case None => ()
592 }
593 }
594 None
597export function containsString(values: Array<string>, needle: string) -> bool {
598 for value in values {
599 if value == needle {
600 return true
601 }
602 }
603 false
606export function recordDefinitionIndex(
607 state: CheckerState,
608 moduleIndex: int,
609 name: string,
610) -> int {
611 match state.recordIndexes.get(definitionNameKey(moduleIndex, name)) {
612 case Some(index) => index
613 case None => -1
614 }
617export function enumDefinitionIndex(
618 state: CheckerState,
619 moduleIndex: int,
620 name: string,
621) -> int {
622 match state.enumIndexes.get(definitionNameKey(moduleIndex, name)) {
623 case Some(index) => index
624 case None => -1
625 }
628export function newtypeDefinitionIndex(
629 state: CheckerState,
630 moduleIndex: int,
631 name: string,
632) -> int {
633 match state.newtypeIndexes.get(definitionNameKey(moduleIndex, name)) {
634 case Some(index) => index
635 case None => -1
636 }
639export function aliasDefinitionIndex(
640 state: CheckerState,
641 moduleIndex: int,
642 name: string,
643) -> int {
644 match state.aliasIndexes.get(definitionNameKey(moduleIndex, name)) {
645 case Some(index) => index
646 case None => -1
647 }
650export function namedNominalTarget(
651 state: CheckerState,
652 moduleIndex: int,
653 name: string,
654) -> Option<NamedNominalTarget> {
655 let recordIndex = recordDefinitionIndex(state, moduleIndex, name)
656 if recordIndex >= 0 {
657 return match state.records.get(recordIndex) {
658 case Some(definition) => Some(NamedNominalTarget {
659 semanticKind: "nominal-record",
660 diagnosticKind: "record",
661 typeArgumentCount: definition.typeParameters.length,
662 })
663 case None => None
664 }
665 }
666 let enumIndex = enumDefinitionIndex(state, moduleIndex, name)
667 if enumIndex >= 0 {
668 return match state.enums.get(enumIndex) {
669 case Some(definition) => Some(NamedNominalTarget {
670 semanticKind: "enum",
671 diagnosticKind: "enum",
672 typeArgumentCount: definition.typeParameters.length,
673 })
674 case None => None
675 }
676 }
677 let newtypeIndex = newtypeDefinitionIndex(state, moduleIndex, name)
678 if newtypeIndex >= 0 {
679 return match state.newtypes.get(newtypeIndex) {
680 case Some(definition) => Some(NamedNominalTarget {
681 semanticKind: "newtype",
682 diagnosticKind: "newtype",
683 typeArgumentCount: definition.typeParameters.length,
684 })
685 case None => None
686 }
687 }
688 None
691export function protocolDefinitionIndex(
692 state: CheckerState,
693 moduleIndex: int,
694 name: string,
695) -> int {
696 match state.protocolIndexes.get(definitionNameKey(moduleIndex, name)) {
697 case Some(index) => index
698 case None => -1
699 }
702export function protocolDefinition(
703 state: CheckerState,
704 moduleIndex: int,
705 name: string,
706) -> Option<ProtocolDefinition> {
707 state.protocols.get(protocolDefinitionIndex(state, moduleIndex, name))
710export function protocolMethodDefinition(
711 definition: ProtocolDefinition,
712 name: string,
713) -> Option<ProtocolMethodDefinition> {
714 for method in definition.methods {
715 if method.name == name {
716 return Some(method)
717 }
718 }
719 None
722export function functionDefinitionForReference(
723 state: CheckerState,
724 reference: PreviewResolvedReference,
725) -> Option<FunctionDefinition> {
726 let key = spanKey(
727 reference.targetModuleIndex,
728 reference.targetLo,
729 reference.targetHi,
730 )
731 match state.functionIndexes.get(key) {
732 case Some(index) => return state.functions.get(index)
733 case None => ()
734 }
735 match state.functionAliases.get(key) {
736 case Some(index) => return state.functions.get(index)
737 case None => ()
738 }
739 let declaration = match declarationFor(
740 state,
741 reference.targetModuleIndex,
742 reference.targetLo,
743 reference.targetHi,
744 ) {
745 case Some(found) => found
746 case None => return None
747 }
748 if declaration.targetModule == "" {
749 return None
750 }
751 let targetModule = moduleIndexByIdentity(state, declaration.targetModule)
752 match state.functionNameIndexes.get(definitionNameKey(
753 targetModule,
754 declaration.targetName,
755 )) {
756 case Some(index) => state.functions.get(index)
757 case None => None
758 }
761export function functionIndexForReference(
762 state: CheckerState,
763 reference: PreviewResolvedReference,
764) -> int {
765 let key = spanKey(
766 reference.targetModuleIndex,
767 reference.targetLo,
768 reference.targetHi,
769 )
770 match state.functionIndexes.get(key) {
771 case Some(index) => return index
772 case None => ()
773 }
774 match state.functionAliases.get(key) {
775 case Some(index) => return index
776 case None => ()
777 }
778 match functionDefinitionForReference(state, reference) {
779 case Some(definition) => match state.functionNameIndexes.get(
780 definitionNameKey(definition.moduleIndex, definition.name),
781 ) {
782 case Some(index) => index
783 case None => -1
784 }
785 case None => -1
786 }
789export function referenceTargetsPendingFunction(
790 state: CheckerState,
791 reference: PreviewResolvedReference,
792) -> bool {
793 let index = functionIndexForReference(state, reference)
794 if index < 0 {
795 return false
796 }
797 match state.pendingFunctions.get(index) {
798 case Some(found) => found
799 case None => false
800 }
803export function replaceRecordDefinition(
804 state: CheckerState,
805 index: int,
806 value: RecordDefinition,
807) -> () {
808 let mut target = state.records
809 target[index] = value
810 ()
813export function replaceEnumDefinition(
814 state: CheckerState,
815 index: int,
816 value: EnumDefinition,
817) -> () {
818 let mut target = state.enums
819 target[index] = value
820 ()
823export function replaceNewtypeDefinition(
824 state: CheckerState,
825 index: int,
826 value: NewtypeDefinition,
827) -> () {
828 let mut target = state.newtypes
829 target[index] = value
830 ()
833export function scopeFor(
834 state: CheckerState,
835 moduleIndex: int,
836 ordinal: int,
837) -> Option<PreviewResolvedScope> {
838 match state.scopeIndexes.get(scopeKey(moduleIndex, ordinal)) {
839 case Some(index) => match state.resolved.scopes.get(index) {
840 case Some(scope) => Some(scope)
841 case None => None
842 }
843 case None => None
844 }
847export function scopeIsWithin(
848 state: CheckerState,
849 moduleIndex: int,
850 candidateOrdinal: int,
851 ancestorOrdinal: int,
852) -> bool {
853 let mut current = candidateOrdinal
854 while current >= 0 {
855 if current == ancestorOrdinal {
856 return true
857 }
858 match scopeFor(state, moduleIndex, current) {
859 case Some(scope) => {
860 current = scope.parentOrdinal
861 }
862 case None => return false
863 }
864 }
865 false
868export function moduleIdentityAt(state: CheckerState, moduleIndex: int) -> string {
869 match moduleAt(state, moduleIndex) {
870 case Some(module) => module.identity
871 case None => "<unknown>"
872 }

SHA256 b05fd16ec17a8edfd75a1355e42e31e5cf41ec136a0f626977ab4397949de2c1