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

Topaz · 7389 B · Original file

1import types { PreviewTypeAtom }
3// The single representation table. Every emission decision about how a
4// value is carried in Rust goes through `reprOfAtom`; later batches add rows
5// here (string, arrays, records ...) instead of branching per operation.
6//
7// primitive int -> i64
8// primitive float -> f64
9// primitive bool -> bool
10// primitive unit -> ()
11// literal int / float / bool -> the primitive's row (a literal type is a
12// value of its primitive at runtime)
13// constructor Range<int> -> (i64, i64, bool, i64), endpoints/inclusive/step
14// variadic parameter T -> Vec<representation(T)> at the function ABI;
15// the body owns one shared Value array until B7
16// 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)
22export 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 }
36export 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)
49// `none` marks an operation that carries no checked type at all.
50export function reprOf(atoms: Array<PreviewTypeAtom>) -> string {
51 if atoms.length == 0 {
52 "none"
53 } else {
54 reprAt(atoms, 0)
55 }
58// The representation of a signature slot below a `function` atom root:
59// `parameters[i]` or `result[0]`.
60export function slotRepr(atoms: Array<PreviewTypeAtom>, field: string, index: int) -> string {
61 let mut found = "none"
62 let mut position = 0
63 for atom in atoms {
64 if atom.parent == 0 && atom.field == field && atom.index == index {
65 found = reprAt(atoms, position)
66 }
67 position += 1
68 }
69 found
72export function variadicRepr(element: string) -> string { "vec:{element}" }
74export 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 }
86export function isCopyRepr(repr: string) -> bool {
87 repr == "i64" || repr == "f64" || repr == "bool" || repr == "unit" || repr == "range"
90// Code without one pair of outer parentheses when they enclose all of it
91// (string literals inside are skipped), for positions where Rust needs none.
92export function bare(code: string) -> string {
93 if code == "()" || !code.startsWith("(") || !code.endsWith(")") {
94 return code
95 }
96 let mut depth = 0
97 let mut inString = false
98 let mut escaped = false
99 let mut index = 0
100 let last = code.scalars().length - 1
101 for scalar in code.scalars() {
102 if inString {
103 if escaped {
104 escaped = false
105 } else if scalar == "\\" {
106 escaped = true
107 } else if scalar == "\"" {
108 inString = false
109 }
110 } else if scalar == "\"" {
111 inString = true
112 } else if scalar == "(" {
113 depth += 1
114 } else if scalar == ")" {
115 depth -= 1
116 if depth == 0 && index != last {
117 return code
118 }
119 }
120 index += 1
121 }
122 code.slice(1, last)
125// Box boundary: a typed value entering a `Value` slot.
126export 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 _ => code
135 }
138// Unbox boundary: a `Value` entering a typed slot. The checker proves the
139// runtime kind; the shared leaf still faults (never panics) if it differs.
140export 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 _ => code
148 }
151export 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 }
167// A captured mutable local shares storage with every closure and defer.
168// Scalar cells retain their Rust type; boxed cells retain Value sharing.
169export 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 }
177export 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 \}" }
182export 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; \}" }
186export 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 _ => value
195 }

SHA256 634fff7a669bfb6896ce65b4024835f980589347bdf7a62faec43aa1abdad195