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/lowering.tpz

Topaz · 86763 B · Original file

1import stage1_types {
2 LoweringOutput,
3 STAGE1_EXCHANGE_SCHEMA,
4 STAGE1_IR_SCHEMA,
5 Stage1Module,
6 Stage1Operation,
7 Stage1Response,
8 compilerProvenance,
9}
10import types {
11 LowerBridgeRequest,
12 decodeLowerBridgeRequest,
13 PreviewAstNode,
14 PreviewImportEdge,
15 PreviewCallArgument,
16 PreviewCallEvaluation,
17 PreviewModuleResult,
18 PreviewResolvedDeclaration,
19 PreviewResolvedReference,
20 PreviewTypeAtom,
21 PreviewTypedCall,
22 PreviewTypedCapture,
23 PreviewTypedNode,
26// Prepared Lispex rules are runtime handles, so lowering preserves their resolved identity.
27const LISPEX_RULE_HANDLE_PREFIX = "topaz.lispex-rule-handle/v1:"
29record LowerKindPlan {
30 name: string,
31 tag: string,
32 roleName: string,
33 runtimeLeaf: string,
36function lowerKind(
37 name: string,
38 tagName: string,
39 roleName: string,
40 runtimeLeaf: string,
41) -> LowerKindPlan {
42 LowerKindPlan {
43 name: name,
44 tag: tagName,
45 roleName: roleName,
46 runtimeLeaf: runtimeLeaf,
47 }
50function statementKind(name: string, tagName: string) -> LowerKindPlan {
51 lowerKind(name, tagName, "statement", "")
54function expressionKind(name: string, tagName: string) -> LowerKindPlan {
55 lowerKind(name, tagName, "expression", "")
58function runtimeExpressionKind(
59 name: string,
60 tagName: string,
61 runtimeLeaf: string,
62) -> LowerKindPlan {
63 lowerKind(name, tagName, "expression", runtimeLeaf)
66function patternKind(name: string, tagName: string) -> LowerKindPlan {
67 lowerKind(name, tagName, "pattern", "pattern")
70function lowerKindPlan(kind: string) -> LowerKindPlan {
71 match kind {
72 case "program" => lowerKind("module", "module", "module-initialization", "")
73 case "block" => expressionKind("expression/block", "block")
74 case "string-part/text" => runtimeExpressionKind("expression/string-text", "string-text", "string")
75 case "parameter" => lowerKind("binding/parameter", "parameter", "binding", "")
76 case "lambda-parameter" => lowerKind("binding/parameter", "parameter", "binding", "")
77 case "function-declaration" => lowerKind("function", "function", "declaration", "")
78 case "statement/import" => statementKind("import", "import")
79 case "statement/export" => statementKind("export", "export")
80 case "statement/function" => statementKind("function", "function")
81 case "statement/type-alias" => statementKind("type-alias", "type-alias")
82 case "statement/enum" => statementKind("enum", "enum")
83 case "statement/record" => statementKind("record", "record")
84 case "statement/newtype" => statementKind("newtype", "newtype")
85 case "statement/impl" => statementKind("implementation", "implementation")
86 case "statement/protocol" => statementKind("protocol", "protocol")
87 case "statement/let" => statementKind("let", "let")
88 case "statement/const" => statementKind("constant", "constant")
89 case "statement/assign" => statementKind("assignment", "assignment")
90 case "statement/return" => statementKind("return", "return")
91 case "statement/defer" => lowerKind("defer", "defer", "cleanup", "")
92 case "statement/using" => statementKind("using", "using")
93 case "statement/while" => statementKind("while", "while")
94 case "statement/break" => statementKind("break", "break")
95 case "statement/continue" => statementKind("continue", "continue")
96 case "statement/expression" => statementKind("expression/block", "expression-statement")
97 case "expression/integer" => expressionKind("expression/integer", "integer")
98 case "expression/float" => expressionKind("expression/float", "float")
99 case "expression/duration" => expressionKind("expression/duration", "duration")
100 case "expression/boolean" => expressionKind("expression/boolean", "boolean")
101 case "expression/null" => expressionKind("expression/null", "null")
102 case "expression/unit" => expressionKind("expression/unit", "unit")
103 case "expression/string" => runtimeExpressionKind("expression/string", "string", "string")
104 case "expression/template" => runtimeExpressionKind("expression/string", "string", "template")
105 case "expression/identifier" => expressionKind("expression/identifier", "identifier")
106 case "expression/placeholder" => expressionKind("expression/placeholder", "placeholder")
107 case "expression/parenthesized" => expressionKind("expression/parenthesized", "parenthesized")
108 case "expression/block" => expressionKind("expression/block", "block-expression")
109 case "expression/if" => expressionKind("expression/if", "if")
110 case "expression/match" => expressionKind("expression/match", "match")
111 case "expression/for" => expressionKind("expression/for", "for")
112 case "expression/loop" => expressionKind("expression/loop", "loop")
113 case "expression/concurrent" => runtimeExpressionKind("expression/concurrent", "concurrent", "concurrent")
114 case "expression/call" => runtimeExpressionKind("expression/call", "call", "call")
115 case "expression/member" => runtimeExpressionKind("expression/member", "member", "member")
116 case "expression/index" => runtimeExpressionKind("expression/index", "index", "collection")
117 case "expression/optional-access" => runtimeExpressionKind("expression/optional-member", "optional-member", "member")
118 case "expression/try" => runtimeExpressionKind("expression/result-propagation", "result-propagation", "result")
119 case "expression/unary" => runtimeExpressionKind("expression/unary", "unary", "unary")
120 case "expression/binary" => runtimeExpressionKind("expression/binary", "binary", "binary")
121 case "expression/range" => runtimeExpressionKind("expression/range", "range", "range")
122 case "expression/compose" => runtimeExpressionKind("expression/compose", "compose", "callable")
123 case "expression/pipe" => runtimeExpressionKind("expression/pipeline", "pipeline", "callable")
124 case "expression/lambda" => runtimeExpressionKind("expression/lambda", "lambda", "callable")
125 case "expression/record-literal" => runtimeExpressionKind("expression/record-literal", "record-literal", "record")
126 case "expression/record-update" => runtimeExpressionKind("expression/record-update", "record-update", "record")
127 case "expression/array" => runtimeExpressionKind("expression/array", "array", "array")
128 case "expression/set" => runtimeExpressionKind("expression/set", "set", "set")
129 case "expression/map" => runtimeExpressionKind("expression/map", "map", "map")
130 case "expression/comprehension" => runtimeExpressionKind("expression/comprehension", "comprehension", "collection")
131 case "pattern/or" => patternKind("pattern/alternatives", "alternatives")
132 case "pattern/binding" => patternKind("pattern/binding", "binding")
133 case "pattern/wildcard" => patternKind("pattern/wildcard", "wildcard")
134 case "pattern/literal" => patternKind("pattern/literal", "literal")
135 case "pattern/range" => patternKind("pattern/range", "range")
136 case "pattern/typed" => patternKind("pattern/typed-binding", "typed-binding")
137 case "pattern/constructor" => patternKind("pattern/constructor", "constructor")
138 case "pattern/list" => patternKind("pattern/list", "list")
139 case "pattern/record" => patternKind("pattern/record", "record")
140 case "pattern/nominal-record" => patternKind("pattern/nominal-record", "nominal-record")
141 case _ => lowerKind("", "", "", "")
142 }
145function admittedRole(
146 plan: LowerKindPlan,
147 sourceKind: string,
148 insideProtocol: bool,
149 parentKind: string,
150) -> string {
151 if insideProtocol && sourceKind != "statement/protocol" {
152 return ""
153 }
154 if sourceKind == "function-declaration" && parentKind != "impl-method" {
155 return ""
156 }
157 plan.roleName
160function roleIdentity(roleName: string) -> string {
161 match roleName {
162 case "module-initialization" => "ModuleInitialization"
163 case "statement" => "Statement"
164 case "expression" => "Expression"
165 case "pattern" => "Pattern"
166 case "binding" => "Binding"
167 case "declaration" => "Declaration"
168 case "cleanup" => "Cleanup"
169 case _ => "Unknown"
170 }
173function operationId(
174 module: string,
175 sourceOrdinal: int,
176 roleName: string,
177 tagName: string,
178 lo: int,
179 hi: int,
180) -> string {
181 "op:{module}:{sourceOrdinal}:{lo}:{hi}:{roleIdentity(roleName)}:{tagName}"
184function sourceText(source: Bytes, lo: int, hi: int) -> string {
185 match source.slice(lo, hi).decodeUtf8() {
186 case Ok(value) => value
187 case Err(_) => ""
188 }
191function attribute(
192 names: Array<string>,
193 values: Array<string>,
194 wanted: string,
195) -> string {
196 let mut index = 0
197 while index < names.length {
198 match names.get(index) {
199 case Some(name) => if name == wanted {
200 return match values.get(index) {
201 case Some(value) => value
202 case None => ""
203 }
204 }
205 case None => ()
206 }
207 index += 1
208 }
209 ""
212function childText(
213 nodes: Array<PreviewAstNode>,
214 childIndexes: Map<string, int>,
215 parent: int,
216 field: string,
217 source: Bytes,
218) -> string {
219 match childIndexes.get("{parent}:{field}") {
220 case Some(index) => match nodes.get(index) {
221 case Some(node) => return sourceText(source, node.lo, node.hi)
222 case None => ()
223 }
224 case None => ()
225 }
226 ""
229function detail(
230 nodes: Array<PreviewAstNode>,
231 childIndexes: Map<string, int>,
232 nodeIndex: int,
233 node: PreviewAstNode,
234 source: Bytes,
235) -> string {
236 match node.kind {
237 case "expression/integer" => attribute(
238 node.attributeNames,
239 node.attributeValues,
240 "valueDecimal",
241 )
242 case "expression/float" => sourceText(source, node.lo, node.hi)
243 case "expression/duration" => sourceText(source, node.lo, node.hi)
244 case "expression/boolean" => attribute(
245 node.attributeNames,
246 node.attributeValues,
247 "value",
248 )
249 case "expression/identifier" => sourceText(source, node.lo, node.hi)
250 case "string-part/text" => sourceText(source, node.lo, node.hi)
251 case "statement/assign" => attribute(
252 node.attributeNames,
253 node.attributeValues,
254 "operator",
255 )
256 case "expression/string" => if sourceText(
257 source,
258 node.lo,
259 node.hi,
260 ).startsWith("\"\"\"") {
261 "multiline"
262 } else {
263 "single-line"
264 }
265 case "expression/template" => {
266 let tag = childText(nodes, childIndexes, nodeIndex, "tag", source)
267 if sourceText(source, node.lo, node.hi).startsWith("{tag}\"\"\"") {
268 "{tag}|multiline"
269 } else {
270 "{tag}|single-line"
271 }
272 }
273 case "parameter" => childText(nodes, childIndexes, nodeIndex, "name", source)
274 case "lambda-parameter" => childText(nodes, childIndexes, nodeIndex, "name", source)
275 case "function-declaration" => childText(nodes, childIndexes, nodeIndex, "name", source)
276 case "statement/impl" => {
277 let name = childText(nodes, childIndexes, nodeIndex, "name", source)
278 let target = childText(nodes, childIndexes, nodeIndex, "target", source)
279 if target == "" { name } else { "{name}<{target}>" }
280 }
281 case "statement/protocol" => childText(
282 nodes,
283 childIndexes,
284 nodeIndex,
285 "name",
286 source,
287 )
288 case "expression/member" => childText(nodes, childIndexes, nodeIndex, "field", source)
289 case "expression/pipe" => childText(nodes, childIndexes, nodeIndex, "field", source)
290 case "expression/optional-access" => childText(
291 nodes,
292 childIndexes,
293 nodeIndex,
294 "field",
295 source,
296 )
297 case "pattern/binding" => sourceText(source, node.lo, node.hi)
298 case "pattern/typed" => childText(nodes, childIndexes, nodeIndex, "name", source)
299 case "pattern/constructor" => childText(nodes, childIndexes, nodeIndex, "name", source)
300 case "pattern/nominal-record" => childText(nodes, childIndexes, nodeIndex, "name", source)
301 case "expression/range" => attribute(
302 node.attributeNames,
303 node.attributeValues,
304 "inclusive",
305 )
306 case "pattern/range" => attribute(
307 node.attributeNames,
308 node.attributeValues,
309 "inclusive",
310 )
311 case "expression/comprehension" => attribute(
312 node.attributeNames,
313 node.attributeValues,
314 "collection",
315 )
316 case "expression/unary" => attribute(
317 node.attributeNames,
318 node.attributeValues,
319 "operator",
320 )
321 case "expression/binary" => attribute(
322 node.attributeNames,
323 node.attributeValues,
324 "operator",
325 )
326 case _ => ""
327 }
330function representationForType(value: string) -> string {
331 match value {
332 case "int" => "i64"
333 case "float" => "f64"
334 case "bool" => "bool"
335 case "unit" => "unit"
336 case "Bytes" => "bytes-handle"
337 case "ByteBuffer" => "byte-buffer-handle"
338 case _ => if value == "" { "" } else { "boxed" }
339 }
342function spanKey(moduleIndex: int, lo: int, hi: int) -> string {
343 "{moduleIndex}:{lo}:{hi}"
346function projectReferenceIdentity(reference: PreviewResolvedReference) -> string {
347 if reference.targetModule != "" && reference.targetName != "" {
348 return "{reference.targetModule}::{reference.targetName}"
349 }
350 if reference.targetModuleIndex >= 0 &&
351 reference.targetLo >= 0 &&
352 reference.targetHi >= reference.targetLo {
353 return "source:{reference.targetModuleIndex}:{reference.targetLo}:{reference.targetHi}"
354 }
355 "builtin::{reference.name}"
358// References by span. Operations project their reference identity from it,
359// and the type fills and defer captures follow a reference to its declaration.
360function indexReferences(
361 values: Array<PreviewResolvedReference>,
362) -> Map<string, PreviewResolvedReference> {
363 let mut references: Map<string, PreviewResolvedReference> = Map.new()
364 for value in values {
365 references.insert(spanKey(value.moduleIndex, value.lo, value.hi), value)
366 }
367 references
370// The reference at a span when it names a declaration in the program.
371function referenceTargetAt(
372 references: Map<string, PreviewResolvedReference>,
373 moduleIndex: int,
374 lo: int,
375 hi: int,
376) -> Option<PreviewResolvedReference> {
377 match references.get(spanKey(moduleIndex, lo, hi)) {
378 case Some(found) => if found.targetModuleIndex >= 0 { Some(found) } else { None }
379 case None => None
380 }
383// Resolver import edges grouped by importing module, each group in edge order.
384function indexImportEdges(values: Array<PreviewImportEdge>) -> Map<string, Array<string>> {
385 let mut edges: Map<string, Array<string>> = Map.new()
386 for value in values {
387 match edges.get(value.from) {
388 case Some(group) => {
389 let mut target = group
390 target.push(value.to)
391 }
392 case None => edges.insert(value.from, [value.to])
393 }
394 }
395 edges
398function indexModuleIdentities(values: Array<PreviewModuleResult>) -> Map<string, int> {
399 let mut indexes: Map<string, int> = Map.new()
400 let mut index = 0
401 for value in values {
402 indexes.insert(value.identity, index)
403 index += 1
404 }
405 indexes
408function indexDeclarationsBySpan(
409 values: Array<PreviewResolvedDeclaration>,
410) -> Map<string, PreviewResolvedDeclaration> {
411 let mut declarations: Map<string, PreviewResolvedDeclaration> = Map.new()
412 for value in values {
413 declarations.insert(spanKey(value.moduleIndex, value.lo, value.hi), value)
414 }
415 declarations
418function declarationNameKey(moduleIndex: int, namespace: string, name: string) -> string {
419 "{moduleIndex}:{namespace}:{name}"
422function indexDeclarationsByName(
423 values: Array<PreviewResolvedDeclaration>,
424) -> Map<string, PreviewResolvedDeclaration> {
425 let mut declarations: Map<string, PreviewResolvedDeclaration> = Map.new()
426 for value in values {
427 declarations.insert(declarationNameKey(value.moduleIndex, value.namespace, value.name), value)
428 }
429 declarations
432function importEdgesOf(edges: Map<string, Array<string>>, identity: string) -> Array<string> {
433 match edges.get(identity) {
434 case Some(found) => found
435 case None => []
436 }
439function referenceIdentity(
440 references: Map<string, PreviewResolvedReference>,
441 moduleIndex: int,
442 lo: int,
443 hi: int,
444) -> string {
445 match references.get(spanKey(moduleIndex, lo, hi)) {
446 case Some(found) => projectReferenceIdentity(found)
447 case None => ""
448 }
451function mutableBinding(
452 nodes: Array<PreviewAstNode>,
453 node: PreviewAstNode,
454) -> bool {
455 if node.kind != "pattern/binding" || node.parent < 0 {
456 return false
457 }
458 match nodes.get(node.parent) {
459 case Some(parent) => parent.kind == "statement/let" && attribute(
460 parent.attributeNames,
461 parent.attributeValues,
462 "mutable",
463 ) == "true"
464 case None => false
465 }
468function bindingStorage(kind: string) -> string {
469 if kind == "parameter" || kind == "lambda-parameter" {
470 return "parameter"
471 }
472 if kind == "statement/const" ||
473 kind == "statement/function" ||
474 kind == "function-declaration" {
475 return "module"
476 }
477 if kind == "pattern/binding" || kind == "pattern/typed" {
478 return "local"
479 }
480 if kind == "statement/using" {
481 return "local"
482 }
483 ""
486record LowerBindingSource {
487 name: string,
488 lo: int,
489 hi: int,
492function emptyBindingSource() -> LowerBindingSource {
493 LowerBindingSource {
494 name: "",
495 lo: 0,
496 hi: 0,
497 }
500function bindingSourceAt(
501 nodes: Array<PreviewAstNode>,
502 index: int,
503 source: Bytes,
504) -> LowerBindingSource {
505 match nodes.get(index) {
506 case Some(node) => LowerBindingSource {
507 name: sourceText(source, node.lo, node.hi),
508 lo: node.lo,
509 hi: node.hi,
510 }
511 case None => emptyBindingSource()
512 }
515function bindingSourceFor(
516 nodes: Array<PreviewAstNode>,
517 childIndexes: Map<string, int>,
518 nodeIndex: int,
519 node: PreviewAstNode,
520 effectiveKind: string,
521 source: Bytes,
522) -> LowerBindingSource {
523 if effectiveKind == "pattern/binding" && node.kind == "identifier" {
524 return bindingSourceAt(nodes, nodeIndex, source)
525 }
526 if node.kind == "pattern/binding" {
527 return LowerBindingSource {
528 name: sourceText(source, node.lo, node.hi),
529 lo: node.lo,
530 hi: node.hi,
531 }
532 }
533 let nameParent = if node.kind == "pattern/typed" ||
534 node.kind == "parameter" ||
535 node.kind == "lambda-parameter" ||
536 node.kind == "function-declaration" ||
537 node.kind == "statement/const" ||
538 node.kind == "statement/using" {
539 nodeIndex
540 } else if node.kind == "statement/function" {
541 match childIndexes.get("{nodeIndex}:declaration") {
542 case Some(index) => index
543 case None => return emptyBindingSource()
544 }
545 } else {
546 return emptyBindingSource()
547 }
548 match childIndexes.get("{nameParent}:name") {
549 case Some(index) => bindingSourceAt(nodes, index, source)
550 case None => emptyBindingSource()
551 }
554record LowerControlPlan {
555 kind: string,
556 ownsTarget: bool,
559function lowerControl(kind: string, ownsTarget: bool) -> LowerControlPlan {
560 LowerControlPlan {
561 kind: kind,
562 ownsTarget: ownsTarget,
563 }
566function controlPlan(kind: string) -> LowerControlPlan {
567 match kind {
568 case "expression/if" => lowerControl("branch", true)
569 case "expression/match" => lowerControl("match", true)
570 case "expression/for" => lowerControl("loop", true)
571 case "expression/loop" => lowerControl("loop", true)
572 case "statement/while" => lowerControl("loop", true)
573 case "statement/break" => lowerControl("break", false)
574 case "statement/continue" => lowerControl("continue", false)
575 case "statement/return" => lowerControl("return", false)
576 case "statement/defer" => lowerControl("cleanup", false)
577 case "expression/try" => lowerControl("propagate", false)
578 case "expression/concurrent" => lowerControl("concurrent", true)
579 case _ => lowerControl("", false)
580 }
583function loopControlTarget(
584 context: ModuleLoweringContext,
585 node: PreviewAstNode,
586 astIndex: int,
587) -> string {
588 if node.kind != "statement/break" && node.kind != "statement/continue" {
589 return ""
590 }
591 let label = childText(
592 context.module.ast,
593 context.state.childIndexes,
594 astIndex,
595 "label",
596 context.state.source,
597 )
598 let mut ancestorIndex = node.parent
599 while ancestorIndex >= 0 {
600 match context.module.ast.get(ancestorIndex) {
601 case Some(ancestor) => {
602 let loopKind = ancestor.kind == "expression/loop" ||
603 ancestor.kind == "expression/for" ||
604 ancestor.kind == "statement/while"
605 let target = if label == "" {
606 loopKind
607 } else {
608 ancestor.kind == "expression/loop" && childText(
609 context.module.ast,
610 context.state.childIndexes,
611 ancestorIndex,
612 "label",
613 context.state.source,
614 ) == label
615 }
616 if target {
617 match context.state.operationIndexByAst.get(ancestorIndex) {
618 case Some(operationIndex) => return operationParentId(
619 context,
620 operationIndex,
621 )
622 case None => return ""
623 }
624 }
625 ancestorIndex = ancestor.parent
626 }
627 case None => return ""
628 }
629 }
630 ""
633function runtimeLeaf(kindLeaf: string, callTarget: string) -> string {
634 if callTarget.startsWith("builtin::") || callTarget.startsWith("std.") ||
635 callTarget.startsWith(LISPEX_RULE_HANDLE_PREFIX) {
636 return callTarget
637 }
638 kindLeaf
641record LowerCallPlan {
642 targetIdentity: string,
643 calleeKind: string,
644 method: string,
645 methodClass: string,
646 optional: bool,
647 shadowFirst: bool,
648 stageMethod: string,
649 arguments: Array<string>,
650 evaluations: Array<string>,
653function callArgumentRows(values: Array<PreviewCallArgument>) -> Array<string> {
654 let mut rows: Array<string> = []
655 for argument in values {
656 let sourceIndex = match argument.sourceIndex {
657 case Some(index) => index
658 case None => -1
659 }
660 rows.push(
661 "{argument.bindingKind}|{argument.bindingName}|{sourceIndex}|{argument.lo}|{argument.hi}",
662 )
663 }
664 rows
667function callEvaluationRows(values: Array<PreviewCallEvaluation>) -> Array<string> {
668 let mut rows: Array<string> = []
669 for evaluation in values {
670 rows.push("{evaluation.kind}|{evaluation.argumentIndex}")
671 }
672 rows
675function projectCall(value: PreviewTypedCall) -> LowerCallPlan {
676 LowerCallPlan {
677 targetIdentity: value.targetIdentity,
678 calleeKind: value.calleeKind,
679 method: value.method,
680 methodClass: value.methodClass,
681 optional: value.optional,
682 shadowFirst: value.shadowFirst,
683 stageMethod: value.stageMethod,
684 arguments: callArgumentRows(value.arguments),
685 evaluations: callEvaluationRows(value.evaluations),
686 }
689function emptyCallPlan() -> LowerCallPlan {
690 LowerCallPlan {
691 targetIdentity: "",
692 calleeKind: "",
693 method: "",
694 methodClass: "",
695 optional: false,
696 shadowFirst: false,
697 stageMethod: "",
698 arguments: [],
699 evaluations: [],
700 }
703function indexCallPlans(values: Array<PreviewTypedCall>) -> Map<string, LowerCallPlan> {
704 let mut plans: Map<string, LowerCallPlan> = Map.new()
705 for value in values {
706 plans.insert(spanKey(value.moduleIndex, value.lo, value.hi), projectCall(value))
707 }
708 plans
711function callPlanFor(
712 plans: Map<string, LowerCallPlan>,
713 moduleIndex: int,
714 lo: int,
715 hi: int,
716) -> LowerCallPlan {
717 match plans.get(spanKey(moduleIndex, lo, hi)) {
718 case Some(found) => found
719 case None => emptyCallPlan()
720 }
723record LowerTypePlan {
724 semanticType: string,
725 representation: string,
726 runtimeType: string,
727 atoms: Array<PreviewTypeAtom>,
730function projectLowerType(value: Array<PreviewTypeAtom>) -> LowerTypePlan {
731 let semanticType = match value.get(0) {
732 case Some(found) => if found.name != "" { found.name } else { found.kind }
733 case None => ""
734 }
735 let runtimeType = if value.length == 0 {
736 ""
737 } else {
738 match JSON.stringify(value) {
739 case Ok(found) => found
740 case Err(_) => ""
741 }
742 }
743 LowerTypePlan {
744 semanticType: semanticType,
745 representation: representationForType(semanticType),
746 runtimeType: runtimeType,
747 atoms: value,
748 }
751record LowerTypedNodePlan {
752 nodeKind: string,
753 typePlan: LowerTypePlan,
756function projectTypedNode(value: PreviewTypedNode) -> LowerTypedNodePlan {
757 LowerTypedNodePlan {
758 nodeKind: value.nodeKind,
759 typePlan: projectLowerType(value.typeValue),
760 }
763function emptyTypedNodePlan() -> LowerTypedNodePlan {
764 LowerTypedNodePlan {
765 nodeKind: "",
766 typePlan: projectLowerType([]),
767 }
770function unitTypeAtom() -> PreviewTypeAtom {
771 PreviewTypeAtom {
772 parent: -1,
773 field: "root",
774 index: 0,
775 edgeName: "",
776 kind: "primitive",
777 name: "unit",
778 value: "",
779 identity: "",
780 origin: "",
781 }
784function contextualLowerTypePlan(
785 kind: string,
786 parentKind: string,
787 observed: LowerTypePlan,
788) -> LowerTypePlan {
789 if kind == "expression/for" && parentKind == "statement/expression" {
790 return LowerTypePlan {
791 semanticType: "unit",
792 representation: representationForType("unit"),
793 runtimeType: observed.runtimeType,
794 atoms: [unitTypeAtom()],
795 }
796 }
797 observed
800function typedPatternLowerTypePlan(
801 context: ModuleLoweringContext,
802 node: PreviewAstNode,
803 astIndex: int,
804 observed: LowerTypePlan,
805) -> LowerTypePlan {
806 if node.kind != "pattern/typed" {
807 return observed
808 }
809 let nameIndex = match context.state.childIndexes.get("{astIndex}:name") {
810 case Some(found) => found
811 case None => return observed
812 }
813 let nameNode = match context.module.ast.get(nameIndex) {
814 case Some(found) => found
815 case None => return observed
816 }
817 let binding = typedNodePlanFor(
818 context.input.typedNodePlans,
819 context.moduleIndex,
820 nameNode.lo,
821 nameNode.hi,
822 )
823 if binding.nodeKind != "binding" || binding.typePlan.runtimeType == "" {
824 return observed
825 }
826 LowerTypePlan {
827 semanticType: binding.typePlan.runtimeType,
828 representation: binding.typePlan.representation,
829 runtimeType: binding.typePlan.runtimeType,
830 atoms: binding.typePlan.atoms,
831 }
834function unknownTypeAtom() -> PreviewTypeAtom {
835 PreviewTypeAtom {
836 parent: -1,
837 field: "root",
838 index: 0,
839 edgeName: "",
840 kind: "unknown",
841 name: "",
842 value: "",
843 identity: "",
844 origin: "",
845 }
848record LowerDeclarationSite {
849 moduleIndex: int,
850 lo: int,
851 hi: int,
854// A reference names its declaration; a selected import is followed to the
855// module-scope declaration it imports, through re-exporting imports too.
856function declarationSite(
857 input: LoweringInput,
858 reference: PreviewResolvedReference,
859 namespace: string,
860) -> LowerDeclarationSite {
861 let mut site = LowerDeclarationSite {
862 moduleIndex: reference.targetModuleIndex,
863 lo: reference.targetLo,
864 hi: reference.targetHi,
865 }
866 let mut hops = 0
867 while hops < input.modules.length {
868 let declaration = match input.declarationsBySpan.get(spanKey(site.moduleIndex, site.lo, site.hi)) {
869 case Some(found) => found
870 case None => return site
871 }
872 if declaration.declarationKind != "selected-import" {
873 return site
874 }
875 let moduleIndex = match input.moduleIndexes.get(declaration.targetModule) {
876 case Some(found) => found
877 case None => return site
878 }
879 match input.declarationsByName.get(
880 declarationNameKey(moduleIndex, namespace, declaration.targetName),
881 ) {
882 case Some(found) => {
883 site = LowerDeclarationSite { moduleIndex: moduleIndex, lo: found.lo, hi: found.hi }
884 }
885 case None => return site
886 }
887 hops += 1
888 }
889 site
892// The checker's binding type of a declaration, else its declaration type.
893function declaredTypeEntry(
894 context: ModuleLoweringContext,
895 moduleIndex: int,
896 lo: int,
897 hi: int,
898) -> Option<Array<PreviewTypeAtom>> {
899 match context.input.declaredTypes.get(declaredTypeKey("binding", moduleIndex, lo, hi)) {
900 case Some(found) => return Some(found)
901 case None => ()
902 }
903 context.input.declaredTypes.get(declaredTypeKey("declaration", moduleIndex, lo, hi))
906// Appends the subtree of `atoms` rooted at `root` to `output`, re-rooted under
907// `parent`. Preorder keeps a subtree contiguous: it ends at the first atom
908// whose parent precedes the root.
909function appendTypeAtomSubtree(
910 output: Array<PreviewTypeAtom>,
911 atoms: Array<PreviewTypeAtom>,
912 root: int,
913 parent: int,
914 field: string,
915 index: int,
916 edgeName: string,
917) -> () {
918 let base = output.length
919 let mut target = output
920 let mut position = root
921 let mut scanning = true
922 while scanning {
923 match atoms.get(position) {
924 case Some(atom) => if position == root {
925 target.push(PreviewTypeAtom {
926 ...atom,
927 parent: parent,
928 field: field,
929 index: index,
930 edgeName: edgeName,
931 })
932 position += 1
933 } else if atom.parent < root {
934 scanning = false
935 } else {
936 target.push(PreviewTypeAtom { ...atom, parent: atom.parent - root + base })
937 position += 1
938 }
939 case None => {
940 scanning = false
941 }
942 }
943 }
946// A structural record type's field, as its own atom list.
947function recordFieldAtoms(
948 atoms: Array<PreviewTypeAtom>,
949 fieldName: string,
950) -> Array<PreviewTypeAtom> {
951 let output: Array<PreviewTypeAtom> = []
952 match atoms.get(0) {
953 case Some(root) => if root.kind != "record" {
954 return output
955 }
956 case None => return output
957 }
958 let mut position = 0
959 for atom in atoms {
960 if atom.parent == 0 && atom.field == "fields" && atom.edgeName == fieldName {
961 appendTypeAtomSubtree(output, atoms, position, -1, "root", 0, "")
962 return output
963 }
964 position += 1
965 }
966 output
969function stringIndex(values: Array<string>, wanted: string) -> int {
970 let mut index = 0
971 for value in values {
972 if value == wanted {
973 return index
974 }
975 index += 1
976 }
977 -1
980// A generic record's declared field type with its type parameters replaced by
981// the arguments of the nominal type the pattern matched.
982function substituteRecordArguments(
983 declared: Array<PreviewTypeAtom>,
984 typeParameters: Array<string>,
985 nominal: Array<PreviewTypeAtom>,
986) -> Array<PreviewTypeAtom> {
987 if typeParameters.length == 0 {
988 return declared
989 }
990 let mut argumentRoots: Array<int> = []
991 let mut position = 0
992 for atom in nominal {
993 if atom.parent == 0 && atom.field == "arguments" {
994 argumentRoots.push(position)
995 }
996 position += 1
997 }
998 let output: Array<PreviewTypeAtom> = []
999 let mut mapped: Array<int> = []
1000 for atom in declared {

SHA256 0bef60580a8fc4374bc6a62ffcc9f8bcb11e66059727761fb4f7e1adceea585a