jz 0.0.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +373 -0
- package/cli.js +163 -0
- package/index.js +247 -0
- package/module/array.js +1322 -0
- package/module/collection.js +793 -0
- package/module/console.js +192 -0
- package/module/core.js +644 -0
- package/module/function.js +181 -0
- package/module/index.js +15 -0
- package/module/json.js +506 -0
- package/module/math.js +390 -0
- package/module/number.js +601 -0
- package/module/object.js +359 -0
- package/module/regex.js +914 -0
- package/module/schema.js +106 -0
- package/module/string.js +985 -0
- package/module/symbol.js +55 -0
- package/module/timer.js +253 -0
- package/module/typedarray.js +713 -0
- package/package.json +56 -5
- package/src/analyze.js +1927 -0
- package/src/autoload.js +175 -0
- package/src/compile.js +1211 -0
- package/src/ctx.js +244 -0
- package/src/emit.js +2105 -0
- package/src/host.js +536 -0
- package/src/ir.js +649 -0
- package/src/jzify.js +418 -0
- package/src/key.js +73 -0
- package/src/narrow.js +928 -0
- package/src/optimize.js +1352 -0
- package/src/plan.js +105 -0
- package/src/prepare.js +1534 -0
- package/src/source.js +76 -0
- package/wasi.js +80 -0
package/module/object.js
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Object module — literals and property access.
|
|
3
|
+
*
|
|
4
|
+
* Type=6 (OBJECT): schemaId in aux, properties as sequential f64 in memory.
|
|
5
|
+
* Schema = compile-time known property names. Access by index via ptr module.
|
|
6
|
+
*
|
|
7
|
+
* @module object
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { typed, asF64, temp, tempI32, allocPtr, needsDynShadow, mkPtrIR, extractF64Bits, appendStaticSlots, slotAddr } from '../src/ir.js'
|
|
11
|
+
import { emit } from '../src/emit.js'
|
|
12
|
+
import { valTypeOf, lookupValType, VAL, repOf, updateRep } from '../src/analyze.js'
|
|
13
|
+
import { ctx, err, inc, PTR } from '../src/ctx.js'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
export default (ctx) => {
|
|
17
|
+
inc('__mkptr', '__alloc', '__alloc_hdr', '__ptr_offset', '__len', '__ptr_type')
|
|
18
|
+
|
|
19
|
+
// Object literal: {x: 1, y: 2} → allocate, fill, return pointer with schemaId
|
|
20
|
+
ctx.core.emit['{}'] = (...rawProps) => {
|
|
21
|
+
if (rawProps.length === 0)
|
|
22
|
+
return mkPtrIR(PTR.OBJECT, 0, ['call', '$__alloc', ['i32.const', 8]])
|
|
23
|
+
|
|
24
|
+
// Flatten comma-grouped props: [',', p1, p2] → [p1, p2]
|
|
25
|
+
const props = rawProps.length === 1 && Array.isArray(rawProps[0]) && rawProps[0][0] === ','
|
|
26
|
+
? rawProps[0].slice(1) : rawProps
|
|
27
|
+
|
|
28
|
+
// Object spread: {...a, x: 1, ...b} — merge schemas, copy props from sources
|
|
29
|
+
const hasSpreads = props.some(p => Array.isArray(p) && p[0] === '...')
|
|
30
|
+
if (hasSpreads) return emitObjectSpread(props)
|
|
31
|
+
|
|
32
|
+
const names = [], values = []
|
|
33
|
+
for (const p of props) {
|
|
34
|
+
if (Array.isArray(p) && p[0] === ':') { names.push(p[1]); values.push(p[2]) }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Use variable's merged schema if available (from Object.assign inference), else register literal schema
|
|
38
|
+
let schemaId = ctx.schema.register(names)
|
|
39
|
+
const target = ctx.schema.targetStack.at(-1)
|
|
40
|
+
if (target) {
|
|
41
|
+
const merged = ctx.schema.resolve(target)
|
|
42
|
+
if (merged) schemaId = ctx.schema.idOf(target)
|
|
43
|
+
}
|
|
44
|
+
const schema = ctx.schema.list[schemaId]
|
|
45
|
+
const t = tempI32('obj')
|
|
46
|
+
const ptr = temp('objp')
|
|
47
|
+
|
|
48
|
+
// R: Static data segment for objects of pure-literal property values (own-memory only).
|
|
49
|
+
// Even with shadow needed, we can skip alloc + N stores; just feed literal values to __dyn_set.
|
|
50
|
+
const shadow = needsDynShadow(target)
|
|
51
|
+
if (values.length >= 2 && !ctx.memory.shared) {
|
|
52
|
+
const emitted = values.map(emit)
|
|
53
|
+
// asF64 folds i32.const → f64.const so int-literal values also qualify.
|
|
54
|
+
const slots = emitted.map(v => extractF64Bits(asF64(v)))
|
|
55
|
+
if (slots.every(b => b !== null)) {
|
|
56
|
+
const off = appendStaticSlots(slots)
|
|
57
|
+
const staticPtr = mkPtrIR(PTR.OBJECT, schemaId, off)
|
|
58
|
+
if (!shadow) return staticPtr
|
|
59
|
+
inc('__dyn_set')
|
|
60
|
+
const body = [['local.set', `$${ptr}`, staticPtr]]
|
|
61
|
+
for (let i = 0; i < schema.length; i++)
|
|
62
|
+
body.push(['drop', ['call', '$__dyn_set', ['local.get', `$${ptr}`],
|
|
63
|
+
emit(['str', String(schema[i])]), asF64(emitted[i])]])
|
|
64
|
+
body.push(['local.get', `$${ptr}`])
|
|
65
|
+
return typed(['block', ['result', 'f64'], ...body], 'f64')
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const body = [
|
|
70
|
+
['local.set', `$${t}`, ['call', '$__alloc', ['i32.const', schema.length * 8]]],
|
|
71
|
+
]
|
|
72
|
+
for (let i = 0; i < values.length; i++)
|
|
73
|
+
body.push(['f64.store', slotAddr(t, i), asF64(emit(values[i]))])
|
|
74
|
+
body.push(['local.set', `$${ptr}`, mkPtrIR(PTR.OBJECT, schemaId, ['local.get', `$${t}`])])
|
|
75
|
+
if (shadow) {
|
|
76
|
+
inc('__dyn_set')
|
|
77
|
+
for (let i = 0; i < schema.length; i++)
|
|
78
|
+
body.push(['drop', ['call', '$__dyn_set', ['local.get', `$${ptr}`], emit(['str', String(schema[i])]),
|
|
79
|
+
['f64.load', slotAddr(t, i)]]])
|
|
80
|
+
}
|
|
81
|
+
body.push(['local.get', `$${ptr}`])
|
|
82
|
+
|
|
83
|
+
return typed(['block', ['result', 'f64'], ...body], 'f64')
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// === Object static methods ===
|
|
87
|
+
|
|
88
|
+
ctx.core.emit['Object.keys'] = (obj) => {
|
|
89
|
+
const schema = resolveSchema(obj)
|
|
90
|
+
if (!schema) err('Object.keys requires object with known schema')
|
|
91
|
+
return emitStringArray(schema)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
ctx.core.emit['Object.values'] = (obj) => {
|
|
95
|
+
const schema = resolveSchema(obj)
|
|
96
|
+
if (!schema) err('Object.values requires object with known schema')
|
|
97
|
+
const va = asF64(emit(obj))
|
|
98
|
+
const n = schema.length
|
|
99
|
+
const t = temp('ov'), base = tempI32('vb')
|
|
100
|
+
const out = allocPtr({ type: PTR.ARRAY, len: n, tag: 'oa' })
|
|
101
|
+
const body = [['local.set', `$${t}`, va], out.init,
|
|
102
|
+
['local.set', `$${base}`, ['call', '$__ptr_offset', ['local.get', `$${t}`]]]]
|
|
103
|
+
for (let i = 0; i < n; i++)
|
|
104
|
+
body.push(['f64.store', slotAddr(out.local, i), ['f64.load', slotAddr(base, i)]])
|
|
105
|
+
body.push(out.ptr)
|
|
106
|
+
return typed(['block', ['result', 'f64'], ...body], 'f64')
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
ctx.core.emit['Object.entries'] = (obj) => {
|
|
110
|
+
const schema = resolveSchema(obj)
|
|
111
|
+
if (!schema) err('Object.entries requires object with known schema')
|
|
112
|
+
const va = asF64(emit(obj))
|
|
113
|
+
const n = schema.length
|
|
114
|
+
const t = temp('oe'), pair = tempI32('op'), base = tempI32('eb')
|
|
115
|
+
const out = allocPtr({ type: PTR.ARRAY, len: n, tag: 'oa' })
|
|
116
|
+
const body = [['local.set', `$${t}`, va], out.init,
|
|
117
|
+
['local.set', `$${base}`, ['call', '$__ptr_offset', ['local.get', `$${t}`]]]]
|
|
118
|
+
for (let i = 0; i < n; i++) {
|
|
119
|
+
body.push(
|
|
120
|
+
['local.set', `$${pair}`, ['call', '$__alloc_hdr', ['i32.const', 2], ['i32.const', 2], ['i32.const', 8]]],
|
|
121
|
+
['f64.store', slotAddr(pair, 0), emit(['str', schema[i]])],
|
|
122
|
+
['f64.store', slotAddr(pair, 1), ['f64.load', slotAddr(base, i)]],
|
|
123
|
+
['f64.store', slotAddr(out.local, i), mkPtrIR(PTR.ARRAY, 0, ['local.get', `$${pair}`])])
|
|
124
|
+
}
|
|
125
|
+
body.push(out.ptr)
|
|
126
|
+
return typed(['block', ['result', 'f64'], ...body], 'f64')
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
ctx.core.emit['Object.assign'] = (target, ...sources) => {
|
|
130
|
+
if (typeof target === 'string') {
|
|
131
|
+
const vt = repOf(target)?.val
|
|
132
|
+
if (vt && vt !== VAL.OBJECT) {
|
|
133
|
+
const allProps = []
|
|
134
|
+
for (const src of sources) {
|
|
135
|
+
const s = resolveSchema(src)
|
|
136
|
+
if (!s) err('Object.assign: source needs known schema')
|
|
137
|
+
for (const p of s) if (!allProps.includes(p)) allProps.push(p)
|
|
138
|
+
}
|
|
139
|
+
const boxedSchema = ['__inner__', ...allProps]
|
|
140
|
+
const schemaId = ctx.schema.register(boxedSchema)
|
|
141
|
+
ctx.schema.vars.set(target, schemaId)
|
|
142
|
+
updateRep(target, { schemaId })
|
|
143
|
+
const t = tempI32('bx'), s = temp('bs')
|
|
144
|
+
const body = [
|
|
145
|
+
['local.set', `$${t}`, ['call', '$__alloc', ['i32.const', boxedSchema.length * 8]]],
|
|
146
|
+
['f64.store', ['local.get', `$${t}`], asF64(emit(target))],
|
|
147
|
+
]
|
|
148
|
+
const sBase = tempI32('sb')
|
|
149
|
+
for (const source of sources) {
|
|
150
|
+
const sSchema = resolveSchema(source)
|
|
151
|
+
body.push(['local.set', `$${s}`, asF64(emit(source))])
|
|
152
|
+
body.push(['local.set', `$${sBase}`, ['call', '$__ptr_offset', ['local.get', `$${s}`]]])
|
|
153
|
+
for (let si = 0; si < sSchema.length; si++) {
|
|
154
|
+
const ti = boxedSchema.indexOf(sSchema[si])
|
|
155
|
+
if (ti < 0) continue
|
|
156
|
+
body.push(['f64.store', slotAddr(t, ti), ['f64.load', slotAddr(sBase, si)]])
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
body.push(['local.set', `$${target}`,
|
|
160
|
+
mkPtrIR(PTR.OBJECT, schemaId, ['local.get', `$${t}`])])
|
|
161
|
+
body.push(['local.get', `$${target}`])
|
|
162
|
+
return typed(['block', ['result', 'f64'], ...body], 'f64')
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const tSchema = resolveSchema(target)
|
|
166
|
+
if (!tSchema) err('Object.assign: target needs known schema')
|
|
167
|
+
const t = temp('at'), s = temp('as')
|
|
168
|
+
const tBase = tempI32('tb'), sBase2 = tempI32('sb')
|
|
169
|
+
const body = [['local.set', `$${t}`, asF64(emit(target))],
|
|
170
|
+
['local.set', `$${tBase}`, ['call', '$__ptr_offset', ['local.get', `$${t}`]]]]
|
|
171
|
+
for (const source of sources) {
|
|
172
|
+
const sSchema = resolveSchema(source)
|
|
173
|
+
if (!sSchema) err('Object.assign: source needs known schema')
|
|
174
|
+
body.push(['local.set', `$${s}`, asF64(emit(source))])
|
|
175
|
+
body.push(['local.set', `$${sBase2}`, ['call', '$__ptr_offset', ['local.get', `$${s}`]]])
|
|
176
|
+
for (let si = 0; si < sSchema.length; si++) {
|
|
177
|
+
const ti = tSchema.indexOf(sSchema[si])
|
|
178
|
+
if (ti < 0) continue
|
|
179
|
+
body.push(['f64.store', slotAddr(tBase, ti), ['f64.load', slotAddr(sBase2, si)]])
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
body.push(['local.get', `$${t}`])
|
|
183
|
+
return typed(['block', ['result', 'f64'], ...body], 'f64')
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Object.fromEntries(arr) → creates HASH from array of [key, value] pairs
|
|
187
|
+
ctx.core.emit['Object.fromEntries'] = (arr) => {
|
|
188
|
+
inc('__hash_new', '__hash_set')
|
|
189
|
+
inc('__str_hash', '__str_eq')
|
|
190
|
+
const va = asF64(emit(arr))
|
|
191
|
+
const t = temp('fe'), ptr = tempI32('fp'), len = tempI32('fl')
|
|
192
|
+
const i = tempI32('fi'), pair = tempI32('fv')
|
|
193
|
+
const id = ctx.func.uniq++
|
|
194
|
+
return typed(['block', ['result', 'f64'],
|
|
195
|
+
['local.set', `$${t}`, ['call', '$__hash_new']],
|
|
196
|
+
['local.set', `$${ptr}`, ['call', '$__ptr_offset', va]],
|
|
197
|
+
['local.set', `$${len}`, ['call', '$__len', va]],
|
|
198
|
+
['local.set', `$${i}`, ['i32.const', 0]],
|
|
199
|
+
['block', `$brk${id}`, ['loop', `$loop${id}`,
|
|
200
|
+
['br_if', `$brk${id}`, ['i32.ge_s', ['local.get', `$${i}`], ['local.get', `$${len}`]]],
|
|
201
|
+
// Load pair (array of 2): pair = ptr_offset(arr[i])
|
|
202
|
+
['local.set', `$${pair}`, ['call', '$__ptr_offset',
|
|
203
|
+
['f64.load', ['i32.add', ['local.get', `$${ptr}`], ['i32.shl', ['local.get', `$${i}`], ['i32.const', 3]]]]]],
|
|
204
|
+
// hash_set(result, pair[0], pair[1])
|
|
205
|
+
['local.set', `$${t}`, ['call', '$__hash_set', ['local.get', `$${t}`],
|
|
206
|
+
['f64.load', ['local.get', `$${pair}`]],
|
|
207
|
+
['f64.load', ['i32.add', ['local.get', `$${pair}`], ['i32.const', 8]]]]],
|
|
208
|
+
['local.set', `$${i}`, ['i32.add', ['local.get', `$${i}`], ['i32.const', 1]]],
|
|
209
|
+
['br', `$loop${id}`]]],
|
|
210
|
+
['local.get', `$${t}`]], 'f64')
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Object.create(proto) → shallow copy of object (same schema, copied properties)
|
|
214
|
+
ctx.core.emit['Object.create'] = (proto) => {
|
|
215
|
+
const protoType = typeof proto === 'string' ? lookupValType(proto) : valTypeOf(proto)
|
|
216
|
+
if (protoType === VAL.ARRAY) {
|
|
217
|
+
// Clone array data + link named-prop sidecar so for-in/bracket-name lookups
|
|
218
|
+
// keep working after Object.create (watr's ctx.local = Object.create(param) pattern).
|
|
219
|
+
inc('__arr_from', '__dyn_move', '__ptr_offset')
|
|
220
|
+
const src = temp('ocs')
|
|
221
|
+
const dst = temp('ocd')
|
|
222
|
+
return typed(['block', ['result', 'f64'],
|
|
223
|
+
['local.set', `$${src}`, asF64(emit(proto))],
|
|
224
|
+
['local.set', `$${dst}`, ['call', '$__arr_from', ['local.get', `$${src}`]]],
|
|
225
|
+
['call', '$__dyn_move',
|
|
226
|
+
['call', '$__ptr_offset', ['local.get', `$${src}`]],
|
|
227
|
+
['call', '$__ptr_offset', ['local.get', `$${dst}`]]],
|
|
228
|
+
['local.get', `$${dst}`]], 'f64')
|
|
229
|
+
}
|
|
230
|
+
const schema = resolveSchema(proto)
|
|
231
|
+
if (!schema) {
|
|
232
|
+
if (protoType == null) {
|
|
233
|
+
const value = temp('ocr')
|
|
234
|
+
inc('__arr_from', '__dyn_move', '__ptr_offset')
|
|
235
|
+
const dst2 = temp('ocd')
|
|
236
|
+
return typed(['block', ['result', 'f64'],
|
|
237
|
+
['local.set', `$${value}`, asF64(emit(proto))],
|
|
238
|
+
['if', ['result', 'f64'],
|
|
239
|
+
['i32.eq', ['call', '$__ptr_type', ['local.get', `$${value}`]], ['i32.const', PTR.ARRAY]],
|
|
240
|
+
['then', ['block', ['result', 'f64'],
|
|
241
|
+
['local.set', `$${dst2}`, ['call', '$__arr_from', ['local.get', `$${value}`]]],
|
|
242
|
+
['call', '$__dyn_move',
|
|
243
|
+
['call', '$__ptr_offset', ['local.get', `$${value}`]],
|
|
244
|
+
['call', '$__ptr_offset', ['local.get', `$${dst2}`]]],
|
|
245
|
+
['local.get', `$${dst2}`]]],
|
|
246
|
+
['else', ['local.get', `$${value}`]]]] , 'f64')
|
|
247
|
+
}
|
|
248
|
+
err('Object.create requires object with known schema')
|
|
249
|
+
}
|
|
250
|
+
const n = schema.length
|
|
251
|
+
const schemaId = ctx.schema.register(schema)
|
|
252
|
+
const t = tempI32('oc'), s = temp('os')
|
|
253
|
+
const srcBase = tempI32('cb')
|
|
254
|
+
const body = [
|
|
255
|
+
['local.set', `$${s}`, asF64(emit(proto))],
|
|
256
|
+
['local.set', `$${t}`, ['call', '$__alloc', ['i32.const', n * 8]]],
|
|
257
|
+
['local.set', `$${srcBase}`, ['call', '$__ptr_offset', ['local.get', `$${s}`]]],
|
|
258
|
+
]
|
|
259
|
+
// Copy all properties from proto
|
|
260
|
+
for (let i = 0; i < n; i++)
|
|
261
|
+
body.push(['f64.store', slotAddr(t, i), ['f64.load', slotAddr(srcBase, i)]])
|
|
262
|
+
body.push(mkPtrIR(PTR.OBJECT, schemaId, ['local.get', `$${t}`]))
|
|
263
|
+
return typed(['block', ['result', 'f64'], ...body], 'f64')
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// --- Helpers ---
|
|
268
|
+
|
|
269
|
+
function resolveSchema(obj) {
|
|
270
|
+
if (typeof obj === 'string') return ctx.schema.resolve(obj)
|
|
271
|
+
if (Array.isArray(obj) && obj[0] === '{}')
|
|
272
|
+
return obj.slice(1).filter(p => Array.isArray(p) && p[0] === ':').map(p => p[1])
|
|
273
|
+
return null
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Emit object literal with spread: {...a, x: 1, ...b, y: 2}
|
|
278
|
+
* Merges schemas from all sources, allocates result, copies in order.
|
|
279
|
+
*/
|
|
280
|
+
function emitObjectSpread(props) {
|
|
281
|
+
// Collect merged schema: union of all spread source schemas + explicit props
|
|
282
|
+
const allNames = []
|
|
283
|
+
const addName = n => { if (!allNames.includes(n)) allNames.push(n) }
|
|
284
|
+
for (const p of props) {
|
|
285
|
+
if (Array.isArray(p) && p[0] === '...') {
|
|
286
|
+
const s = resolveSchema(p[1])
|
|
287
|
+
if (s) for (const n of s) addName(n)
|
|
288
|
+
} else if (Array.isArray(p) && p[0] === ':') addName(p[1])
|
|
289
|
+
}
|
|
290
|
+
// Pragmatic fallback: single spread source with no resolvable schema
|
|
291
|
+
// (e.g. `{ ...opts }` where opts is a parameter). Emit source directly.
|
|
292
|
+
// Alias rather than clone — safe for read-only use; mutation would affect source.
|
|
293
|
+
if (!allNames.length && props.length === 1 && Array.isArray(props[0]) && props[0][0] === '...') {
|
|
294
|
+
return typed(asF64(emit(props[0][1])), 'f64')
|
|
295
|
+
}
|
|
296
|
+
if (!allNames.length) err('Object spread: cannot resolve source schema')
|
|
297
|
+
|
|
298
|
+
const schemaId = ctx.schema.register(allNames)
|
|
299
|
+
const schema = ctx.schema.list[schemaId]
|
|
300
|
+
const t = tempI32('obj')
|
|
301
|
+
const ptr = temp('objp')
|
|
302
|
+
const src = tempI32('osp')
|
|
303
|
+
|
|
304
|
+
const body = [['local.set', `$${t}`, ['call', '$__alloc', ['i32.const', schema.length * 8]]]]
|
|
305
|
+
|
|
306
|
+
// Process props in order — later props override earlier (JS semantics)
|
|
307
|
+
let srcF
|
|
308
|
+
for (const p of props) {
|
|
309
|
+
if (Array.isArray(p) && p[0] === '...') {
|
|
310
|
+
const sSchema = resolveSchema(p[1])
|
|
311
|
+
if (!sSchema) {
|
|
312
|
+
// Unknown-schema source (e.g. parameter). Override each slot via runtime
|
|
313
|
+
// __dyn_get_or using existing value as fallback. Requires collection module.
|
|
314
|
+
if (!ctx.module.modules.collection) err('Object spread: source needs known schema')
|
|
315
|
+
inc('__dyn_get_or')
|
|
316
|
+
srcF ??= temp('ospf')
|
|
317
|
+
body.push(['local.set', `$${srcF}`, asF64(emit(p[1]))])
|
|
318
|
+
for (let i = 0; i < schema.length; i++) {
|
|
319
|
+
const slot = slotAddr(t, i)
|
|
320
|
+
body.push(['f64.store', slot,
|
|
321
|
+
['call', '$__dyn_get_or', ['local.get', `$${srcF}`],
|
|
322
|
+
emit(['str', String(schema[i])]),
|
|
323
|
+
['f64.load', slot]]])
|
|
324
|
+
}
|
|
325
|
+
continue
|
|
326
|
+
}
|
|
327
|
+
body.push(['local.set', `$${src}`, ['call', '$__ptr_offset', asF64(emit(p[1]))]])
|
|
328
|
+
for (let si = 0; si < sSchema.length; si++) {
|
|
329
|
+
const ti = schema.indexOf(sSchema[si])
|
|
330
|
+
if (ti < 0) continue
|
|
331
|
+
body.push(['f64.store', slotAddr(t, ti), ['f64.load', slotAddr(src, si)]])
|
|
332
|
+
}
|
|
333
|
+
} else if (Array.isArray(p) && p[0] === ':') {
|
|
334
|
+
const ti = schema.indexOf(p[1])
|
|
335
|
+
if (ti >= 0) body.push(['f64.store', slotAddr(t, ti), asF64(emit(p[2]))])
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
body.push(['local.set', `$${ptr}`, mkPtrIR(PTR.OBJECT, schemaId, ['local.get', `$${t}`])])
|
|
340
|
+
const spreadTarget = ctx.schema.targetStack.at(-1)
|
|
341
|
+
if (needsDynShadow(spreadTarget)) {
|
|
342
|
+
inc('__dyn_set')
|
|
343
|
+
for (let i = 0; i < schema.length; i++)
|
|
344
|
+
body.push(['drop', ['call', '$__dyn_set', ['local.get', `$${ptr}`], emit(['str', String(schema[i])]),
|
|
345
|
+
['f64.load', slotAddr(t, i)]]])
|
|
346
|
+
}
|
|
347
|
+
body.push(['local.get', `$${ptr}`])
|
|
348
|
+
return typed(['block', ['result', 'f64'], ...body], 'f64')
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function emitStringArray(names) {
|
|
352
|
+
const n = names.length
|
|
353
|
+
const out = allocPtr({ type: PTR.ARRAY, len: n, tag: 'sa' })
|
|
354
|
+
const body = [out.init]
|
|
355
|
+
for (let i = 0; i < n; i++)
|
|
356
|
+
body.push(['f64.store', slotAddr(out.local, i), emit(['str', names[i]])])
|
|
357
|
+
body.push(out.ptr)
|
|
358
|
+
return typed(['block', ['result', 'f64'], ...body], 'f64')
|
|
359
|
+
}
|