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/repr.tpz
Topaz · 7389 B · Original file
1
import types { PreviewTypeAtom }3
// The single representation table. Every emission decision about how a4
// value is carried in Rust goes through `reprOfAtom`; later batches add rows5
// here (string, arrays, records ...) instead of branching per operation.6
//7
// primitive int -> i648
// primitive float -> f649
// primitive bool -> bool10
// primitive unit -> ()11
// literal int / float / bool -> the primitive's row (a literal type is a12
// value of its primitive at runtime)13
// constructor Range<int> -> (i64, i64, bool, i64), endpoints/inclusive/step14
// variadic parameter T -> Vec<representation(T)> at the function ABI;15
// the body owns one shared Value array until B716
// captured mutable copy value T -> Rc<Cell<representation(T)>>17
// captured mutable boxed value -> Rc<RefCell<Value>>18
// nominal-record -> Value::NominalRecord (immutable shared fields; shallow update)19
// enum -> Value::Enum (declaration identity, variant ordinal and payloads)20
// newtype -> Value::Newtype (declaration identity and wrapped value)21
// anything else -> Value (the boxed carrier)22
export function reprOfAtom(atom: PreviewTypeAtom) -> string {23
if atom.kind == "primitive" || (atom.kind == "literal" && atom.name != "string" && atom.name != "null") {24
match atom.name {25
case "int" => "i64"26
case "float" => "f64"27
case "bool" => "bool"28
case "unit" => "unit"29
case _ => "value"30
}31
} else {32
"value"33
}34
}36
export function reprAt(atoms: Array<PreviewTypeAtom>, position: int) -> string {37
let atom = atoms[position]38
if atom.kind == "constructor" && atom.name == "Range" {39
for child in atoms {40
if child.parent == position && child.field == "arguments" && child.index == 0 &&41
child.kind == "primitive" && child.name == "int" {42
return "range"43
}44
}45
}46
reprOfAtom(atom)47
}49
// `none` marks an operation that carries no checked type at all.50
export function reprOf(atoms: Array<PreviewTypeAtom>) -> string {51
if atoms.length == 0 {52
"none"53
} else {54
reprAt(atoms, 0)55
}56
}58
// The representation of a signature slot below a `function` atom root:59
// `parameters[i]` or `result[0]`.60
export function slotRepr(atoms: Array<PreviewTypeAtom>, field: string, index: int) -> string {61
let mut found = "none"62
let mut position = 063
for atom in atoms {64
if atom.parent == 0 && atom.field == field && atom.index == index {65
found = reprAt(atoms, position)66
}67
position += 168
}69
found70
}72
export function variadicRepr(element: string) -> string { "vec:{element}" }74
export function rustType(repr: string) -> string {75
if repr.startsWith("vec:") { return "Vec<{rustType(repr.slice(4, repr.scalars().length))}>" }76
match repr {77
case "i64" => "i64"78
case "f64" => "f64"79
case "bool" => "bool"80
case "unit" => "()"81
case "range" => "(i64, i64, bool, i64)"82
case _ => "Value"83
}84
}86
export function isCopyRepr(repr: string) -> bool {87
repr == "i64" || repr == "f64" || repr == "bool" || repr == "unit" || repr == "range"88
}90
// Code without one pair of outer parentheses when they enclose all of it91
// (string literals inside are skipped), for positions where Rust needs none.92
export function bare(code: string) -> string {93
if code == "()" || !code.startsWith("(") || !code.endsWith(")") {94
return code95
}96
let mut depth = 097
let mut inString = false98
let mut escaped = false99
let mut index = 0100
let last = code.scalars().length - 1101
for scalar in code.scalars() {102
if inString {103
if escaped {104
escaped = false105
} else if scalar == "\\" {106
escaped = true107
} else if scalar == "\"" {108
inString = false109
}110
} else if scalar == "\"" {111
inString = true112
} else if scalar == "(" {113
depth += 1114
} else if scalar == ")" {115
depth -= 1116
if depth == 0 && index != last {117
return code118
}119
}120
index += 1121
}122
code.slice(1, last)123
}125
// Box boundary: a typed value entering a `Value` slot.126
export function boxed(code: string, repr: string) -> string {127
if repr.startsWith("vec:") { return "Value::array(({code}).into_iter().map(|__v| {boxed("__v", repr.slice(4, repr.scalars().length))}).collect())" }128
match repr {129
case "i64" => "Value::Int({bare(code)})"130
case "f64" => "Value::Float({bare(code)})"131
case "bool" => "Value::Bool({bare(code)})"132
case "unit" => "\{ let _: () = {code}; Value::Unit \}"133
case "range" => "\{ let (lo, hi, inclusive, step) = {code}; Value::Range \{ lo, hi, inclusive, step \} \}"134
case _ => code135
}136
}138
// Unbox boundary: a `Value` entering a typed slot. The checker proves the139
// runtime kind; the shared leaf still faults (never panics) if it differs.140
export function unboxed(code: string, repr: string, span: string) -> string {141
match repr {142
case "i64" => "native_unbox_int({bare(code)}, {span})?"143
case "f64" => "native_unbox_float({bare(code)}, {span})?"144
case "bool" => "native_unbox_bool({bare(code)}, {span})?"145
case "unit" => "\{ let _: Value = {code}; \}"146
case "range" => "match {code} \{ Value::Range \{ lo, hi, inclusive, step \} => (lo, hi, inclusive, step), __other => return Err(fault(codes::GUARD_TYPE, format!(\"native array element expected `Range<int>`, found `\{\}` (internal: unreachable on a checked build)\", __other.kind()), {span})) \}"147
case _ => code148
}149
}151
export function coerce(code: string, from: string, to: string, span: string) -> Result<string, string> {152
if from == to || to == "none" {153
Ok(code)154
} else if from == "none" {155
Err("unsupported: type untyped value into {to}")156
} else if to == "value" {157
Ok(boxed(code, from))158
} else if from == "value" {159
Ok(unboxed(code, to, span))160
} else if to == "unit" {161
Ok("\{ let _ = {code}; \}")162
} else {163
Err("unsupported: type representation {from} as {to}")164
}165
}167
// A captured mutable local shares storage with every closure and defer.168
// Scalar cells retain their Rust type; boxed cells retain Value sharing.169
export function sharedInit(code: string, repr: string) -> string {170
if isCopyRepr(repr) {171
"Rc::new(std::cell::Cell::new({bare(code)}))"172
} else {173
"Rc::new(std::cell::RefCell::new({bare(code)}))"174
}175
}177
export function sharedRead(name: string, repr: string) -> string {178
// End the borrow before surrounding code calls another closure or writes.179
if isCopyRepr(repr) { "{name}.get()" } else { "\{ let __value = {name}.borrow().clone(); __value \}" }180
}182
export function sharedWrite(name: string, code: string, repr: string) -> string {183
if isCopyRepr(repr) { "{name}.set({bare(code)});" } else { "\{ let __value = {bare(code)}; *{name}.borrow_mut() = __value; \}" }184
}186
export function parameterGuard(value: string, repr: string, span: string) -> string {187
let fault = "return Err(fault(codes::GUARD_TYPE, \"argument does not match parameter type (§6)\", {span}))"188
match repr {189
case "i64" => "match {value} \{ Value::Int(__v) => __v, _ => {fault} \}"190
case "f64" => "match {value} \{ Value::Float(__v) => __v, _ => {fault} \}"191
case "bool" => "match {value} \{ Value::Bool(__v) => __v, _ => {fault} \}"192
case "unit" => "match {value} \{ Value::Unit => (), _ => {fault} \}"193
case "range" => "match {value} \{ Value::Range \{ lo, hi, inclusive, step \} => (lo, hi, inclusive, step), _ => {fault} \}"194
case _ => value195
}196
}SHA256 634fff7a669bfb6896ce65b4024835f980589347bdf7a62faec43aa1abdad195