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/emitter/exports.tpz

Topaz · 3721 B · Original file

1import emitter.ir { Table, children, child, fieldOf, opAt, refusal }
2import stage1_types { Stage1Operation }
4// Target-neutral export facts of the entry module, projected from the IR.
5// This is the Topaz form of the export half of the Rust shell's adapter-fact
6// projection: value exports of the entry module sorted by name, with the
7// declared parameter names and defaults of exported functions. An export
8// that is not a function declaration carries no parameter names.
9export record ExportFact {
10 name: string,
11 namesKnown: bool,
12 parameterNames: Array<string>,
13 parameterDefaults: Array<bool>,
16function signatureParameterCount(declaration: Stage1Operation) -> int {
17 let mut count = 0
18 for atom in declaration.declaredTypeAtoms {
19 if atom.parent == 0 && atom.field == "parameters" {
20 count += 1
21 }
22 }
23 count
26function functionFact(table: Table, declaration: Stage1Operation) -> Result<ExportFact, string> {
27 let mut names: Array<string> = []
28 let mut defaults: Array<bool> = []
29 for parameter in children(table, declaration, "parameters")? {
30 names.push(parameter.bindingName)
31 defaults.push(false)
32 }
33 // A default expression hangs off the function with the parameter's path.
34 let mut position = 0
35 for label in declaration.operandLabels {
36 if fieldOf(label) == "default" {
37 let mut index = 0
38 while index < names.length {
39 if label.contains("/parameters:{index}/") {
40 defaults[index] = true
41 }
42 index += 1
43 }
44 }
45 position += 1
46 }
47 if declaration.declaredTypeAtoms.length == 0 || declaration.declaredTypeAtoms[0].kind != "function" {
48 return Err(refusal("export {declaration.bindingName} is declared as a function but has a non-function type", declaration))
49 }
50 if signatureParameterCount(declaration) != names.length {
51 return Err(refusal("export {declaration.bindingName} parameter facts disagree with its checked type", declaration))
52 }
53 Ok(ExportFact {
54 name: declaration.bindingName,
55 namesKnown: true,
56 parameterNames: names,
57 parameterDefaults: defaults,
58 })
61function insertSorted(facts: Array<ExportFact>, fact: ExportFact) -> Array<ExportFact> {
62 let mut out: Array<ExportFact> = []
63 let mut placed = false
64 for existing in facts {
65 if !placed && fact.name < existing.name {
66 out.push(fact)
67 placed = true
68 }
69 out.push(existing)
70 }
71 if !placed {
72 out.push(fact)
73 }
74 out
77export function projectExports(table: Table, entryRoot: Stage1Operation) -> Result<Array<ExportFact>, string> {
78 let mut facts: Array<ExportFact> = []
79 for id in entryRoot.operands {
80 let item = opAt(table, id)?
81 if item.kind != "export" {
82 continue
83 }
84 let declaration = child(table, item, "item")?
85 let fact = match declaration.kind {
86 case "function" => Some(functionFact(table, declaration)?)
87 case "let" => {
88 let pattern = child(table, declaration, "pattern")?
89 Some(ExportFact {
90 name: pattern.bindingName,
91 namesKnown: false,
92 parameterNames: [],
93 parameterDefaults: [],
94 })
95 }
96 case "constant" => Some(ExportFact {
97 name: declaration.bindingName,
98 namesKnown: false,
99 parameterNames: [],
100 parameterDefaults: [],
101 })
102 case _ => None
103 }
104 match fact {
105 case Some(found) => {
106 facts = insertSorted(facts, found)
107 }
108 case None => ()
109 }
110 }
111 Ok(facts)
114// The one entry-point judgement: `export function main` in the entry module.
115export function hasExplicitMain(facts: Array<ExportFact>) -> bool {
116 for fact in facts {
117 if fact.namesKnown && fact.name == "main" {
118 return true
119 }
120 }
121 false

SHA256 4ad549adba331dd178aa05570a129c07c7e010be3f64c505afc32eceed1865fd