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
1
import emitter.ir { Table, children, child, fieldOf, opAt, refusal }2
import 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-fact6
// projection: value exports of the entry module sorted by name, with the7
// declared parameter names and defaults of exported functions. An export8
// that is not a function declaration carries no parameter names.9
export record ExportFact {10
name: string,11
namesKnown: bool,12
parameterNames: Array<string>,13
parameterDefaults: Array<bool>,14
}16
function signatureParameterCount(declaration: Stage1Operation) -> int {17
let mut count = 018
for atom in declaration.declaredTypeAtoms {19
if atom.parent == 0 && atom.field == "parameters" {20
count += 121
}22
}23
count24
}26
function 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 = 035
for label in declaration.operandLabels {36
if fieldOf(label) == "default" {37
let mut index = 038
while index < names.length {39
if label.contains("/parameters:{index}/") {40
defaults[index] = true41
}42
index += 143
}44
}45
position += 146
}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
})59
}61
function insertSorted(facts: Array<ExportFact>, fact: ExportFact) -> Array<ExportFact> {62
let mut out: Array<ExportFact> = []63
let mut placed = false64
for existing in facts {65
if !placed && fact.name < existing.name {66
out.push(fact)67
placed = true68
}69
out.push(existing)70
}71
if !placed {72
out.push(fact)73
}74
out75
}77
export 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
continue83
}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 _ => None103
}104
match fact {105
case Some(found) => {106
facts = insertSorted(facts, found)107
}108
case None => ()109
}110
}111
Ok(facts)112
}114
// The one entry-point judgement: `export function main` in the entry module.115
export function hasExplicitMain(facts: Array<ExportFact>) -> bool {116
for fact in facts {117
if fact.namesKnown && fact.name == "main" {118
return true119
}120
}121
false122
}SHA256 4ad549adba331dd178aa05570a129c07c7e010be3f64c505afc32eceed1865fd