wasm-idle 0.3.0 → 0.3.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/dist/clang/app.js +50 -9
- package/dist/clang/index.js +22 -10
- package/dist/debug/expression.js +89 -9
- package/dist/playground/options.d.ts +1 -0
- package/package.json +1 -1
package/dist/clang/app.js
CHANGED
|
@@ -198,18 +198,59 @@ export default class App {
|
|
|
198
198
|
if (variable.kind === 'array') {
|
|
199
199
|
this.mem?.check?.();
|
|
200
200
|
const address = Number(frame?.values.get(variable.slot) ?? Number.NaN);
|
|
201
|
-
|
|
201
|
+
const dimensions = variable.dimensions?.length
|
|
202
|
+
? variable.dimensions
|
|
203
|
+
: variable.length
|
|
204
|
+
? [variable.length]
|
|
205
|
+
: [];
|
|
206
|
+
if (!Number.isFinite(address) || address <= 0 || !dimensions.length || !variable.elementKind) {
|
|
202
207
|
return [{ name: variable.name, value: '?' }];
|
|
203
208
|
}
|
|
204
|
-
const
|
|
209
|
+
const elementStride = variable.elementKind === 'double'
|
|
210
|
+
? 8
|
|
211
|
+
: variable.elementKind === 'bool' || variable.elementKind === 'char'
|
|
212
|
+
? 1
|
|
213
|
+
: 4;
|
|
214
|
+
if (dimensions.length === 2) {
|
|
215
|
+
const previewRows = Math.min(dimensions[0], 4);
|
|
216
|
+
const previewCols = Math.min(dimensions[1], 8);
|
|
217
|
+
const rows = [];
|
|
218
|
+
for (let row = 0; row < previewRows; row += 1) {
|
|
219
|
+
const values = [];
|
|
220
|
+
for (let col = 0; col < previewCols; col += 1) {
|
|
221
|
+
const offset = address + (row * dimensions[1] + col) * elementStride;
|
|
222
|
+
if (variable.elementKind === 'bool') {
|
|
223
|
+
values.push(this.mem.read8(offset) ? 'true' : 'false');
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (variable.elementKind === 'char') {
|
|
227
|
+
const charCode = this.mem.read8(offset);
|
|
228
|
+
values.push(charCode >= 0x20 && charCode <= 0x7e ? `'${String.fromCharCode(charCode)}'` : `${charCode}`);
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (variable.elementKind === 'float') {
|
|
232
|
+
values.push(`${this.mem.readFloat32(offset)}`);
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
if (variable.elementKind === 'double') {
|
|
236
|
+
values.push(`${this.mem.readFloat64(offset)}`);
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
values.push(`${this.mem.readInt32(offset)}`);
|
|
240
|
+
}
|
|
241
|
+
rows.push(`[${values.join(', ')}${dimensions[1] > previewCols ? ', ...' : ''}]`);
|
|
242
|
+
}
|
|
243
|
+
return [
|
|
244
|
+
{
|
|
245
|
+
name: variable.name,
|
|
246
|
+
value: `[${rows.join(', ')}${dimensions[0] > previewRows ? ', ...' : ''}]`
|
|
247
|
+
}
|
|
248
|
+
];
|
|
249
|
+
}
|
|
250
|
+
const previewLength = Math.min(dimensions[0], 8);
|
|
205
251
|
const values = [];
|
|
206
252
|
for (let index = 0; index < previewLength; index += 1) {
|
|
207
|
-
const offset = address +
|
|
208
|
-
(variable.elementKind === 'double'
|
|
209
|
-
? index * 8
|
|
210
|
-
: variable.elementKind === 'bool' || variable.elementKind === 'char'
|
|
211
|
-
? index
|
|
212
|
-
: index * 4);
|
|
253
|
+
const offset = address + index * elementStride;
|
|
213
254
|
if (variable.elementKind === 'bool') {
|
|
214
255
|
values.push(this.mem.read8(offset) ? 'true' : 'false');
|
|
215
256
|
continue;
|
|
@@ -232,7 +273,7 @@ export default class App {
|
|
|
232
273
|
return [
|
|
233
274
|
{
|
|
234
275
|
name: variable.name,
|
|
235
|
-
value: `[${values.join(', ')}${
|
|
276
|
+
value: `[${values.join(', ')}${dimensions[0] > previewLength ? ', ...' : ''}]`
|
|
236
277
|
}
|
|
237
278
|
];
|
|
238
279
|
}
|
package/dist/clang/index.js
CHANGED
|
@@ -306,22 +306,27 @@ export default class Clang {
|
|
|
306
306
|
for (const declaration of declarations) {
|
|
307
307
|
const [left] = declaration.split('=');
|
|
308
308
|
const declarator = left?.trim() || '';
|
|
309
|
-
const
|
|
310
|
-
|
|
309
|
+
const arrayDimensions = [];
|
|
310
|
+
for (const match of declarator.matchAll(/\[(\d+)\]/g)) {
|
|
311
|
+
arrayDimensions.push(Number(match[1]));
|
|
312
|
+
}
|
|
313
|
+
const arrayName = declarator.match(/([A-Za-z_]\w*)\s*(?=\[\d+\])/);
|
|
314
|
+
if (arrayDimensions.length && arrayName) {
|
|
311
315
|
const slot = nextVariableSlot++;
|
|
312
316
|
this.debugVariableMetadata[currentFunctionId] = [
|
|
313
317
|
...(this.debugVariableMetadata[currentFunctionId] || []),
|
|
314
318
|
{
|
|
315
319
|
slot,
|
|
316
|
-
name:
|
|
320
|
+
name: arrayName[1],
|
|
317
321
|
kind: 'array',
|
|
318
322
|
elementKind: declarationMatch[1],
|
|
319
|
-
length:
|
|
323
|
+
length: arrayDimensions[0],
|
|
324
|
+
dimensions: arrayDimensions,
|
|
320
325
|
fromLine: index + 1,
|
|
321
326
|
toLine: Number.MAX_SAFE_INTEGER
|
|
322
327
|
}
|
|
323
328
|
];
|
|
324
|
-
trailingInstrumentation.push(`${indent}__wasm_idle_debug_value_addr(${currentFunctionId}, ${slot}, (int)((unsigned long long)(${
|
|
329
|
+
trailingInstrumentation.push(`${indent}__wasm_idle_debug_value_addr(${currentFunctionId}, ${slot}, (int)((unsigned long long)(${arrayName[1]})));`);
|
|
325
330
|
continue;
|
|
326
331
|
}
|
|
327
332
|
if (/[*&]/.test(declarator))
|
|
@@ -544,22 +549,29 @@ export default class Clang {
|
|
|
544
549
|
instrumented.push(`${indent} __wasm_idle_debug_emit_${container}(${currentFunctionId}, ${slot}, ${name});`);
|
|
545
550
|
continue;
|
|
546
551
|
}
|
|
547
|
-
const
|
|
548
|
-
|
|
552
|
+
const parameterArrayDimensions = [];
|
|
553
|
+
for (const match of cleaned.matchAll(/\[(\d+)\]/g)) {
|
|
554
|
+
parameterArrayDimensions.push(Number(match[1]));
|
|
555
|
+
}
|
|
556
|
+
const parameterArrayName = cleaned.match(/([A-Za-z_]\w*)\s*(?=\[\d+\])/);
|
|
557
|
+
if (parameterArrayDimensions.length &&
|
|
558
|
+
parameterArrayName &&
|
|
559
|
+
/\b(int|float|double|bool|char)\b/.test(cleaned)) {
|
|
549
560
|
const slot = nextVariableSlot++;
|
|
550
561
|
this.debugVariableMetadata[currentFunctionId] = [
|
|
551
562
|
...(this.debugVariableMetadata[currentFunctionId] || []),
|
|
552
563
|
{
|
|
553
564
|
slot,
|
|
554
|
-
name:
|
|
565
|
+
name: parameterArrayName[1],
|
|
555
566
|
kind: 'array',
|
|
556
567
|
elementKind: (cleaned.match(/\b(int|float|double|bool|char)\b/)?.[1] || 'int'),
|
|
557
|
-
length:
|
|
568
|
+
length: parameterArrayDimensions[0],
|
|
569
|
+
dimensions: parameterArrayDimensions,
|
|
558
570
|
fromLine: index + 1,
|
|
559
571
|
toLine: Number.MAX_SAFE_INTEGER
|
|
560
572
|
}
|
|
561
573
|
];
|
|
562
|
-
instrumented.push(`${indent} __wasm_idle_debug_value_addr(${currentFunctionId}, ${slot}, (int)((unsigned long long)(${
|
|
574
|
+
instrumented.push(`${indent} __wasm_idle_debug_value_addr(${currentFunctionId}, ${slot}, (int)((unsigned long long)(${parameterArrayName[1]})));`);
|
|
563
575
|
continue;
|
|
564
576
|
}
|
|
565
577
|
if (/[*&\[]/.test(cleaned))
|
package/dist/debug/expression.js
CHANGED
|
@@ -6,6 +6,7 @@ export function evaluateDebugExpression(expression, variables) {
|
|
|
6
6
|
const values = new Map();
|
|
7
7
|
for (const variable of variables)
|
|
8
8
|
values.set(variable.name, variable.value);
|
|
9
|
+
const parsedValues = new Map();
|
|
9
10
|
const tokens = [];
|
|
10
11
|
for (let index = 0; index < source.length;) {
|
|
11
12
|
const character = source[index];
|
|
@@ -20,6 +21,11 @@ export function evaluateDebugExpression(expression, variables) {
|
|
|
20
21
|
index += 1;
|
|
21
22
|
continue;
|
|
22
23
|
}
|
|
24
|
+
if (character === '[' || character === ']') {
|
|
25
|
+
tokens.push({ type: 'bracket', value: character });
|
|
26
|
+
index += 1;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
23
29
|
const operator = operators.find((candidate) => source.startsWith(candidate, index));
|
|
24
30
|
if (operator) {
|
|
25
31
|
tokens.push({ type: 'operator', value: operator });
|
|
@@ -46,6 +52,73 @@ export function evaluateDebugExpression(expression, variables) {
|
|
|
46
52
|
throw new Error(`unsupported token near "${source.slice(index)}"`);
|
|
47
53
|
}
|
|
48
54
|
let cursor = 0;
|
|
55
|
+
const parsePreviewValue = (text, start = 0) => {
|
|
56
|
+
let index = start;
|
|
57
|
+
while (/\s/.test(text[index] || ''))
|
|
58
|
+
index += 1;
|
|
59
|
+
const character = text[index];
|
|
60
|
+
if (character === '[') {
|
|
61
|
+
index += 1;
|
|
62
|
+
const items = [];
|
|
63
|
+
while (true) {
|
|
64
|
+
while (/\s/.test(text[index] || ''))
|
|
65
|
+
index += 1;
|
|
66
|
+
if (text[index] === ']')
|
|
67
|
+
return { value: items, next: index + 1 };
|
|
68
|
+
if (text.startsWith('...', index))
|
|
69
|
+
throw new Error('unavailable');
|
|
70
|
+
const item = parsePreviewValue(text, index);
|
|
71
|
+
items.push(item.value);
|
|
72
|
+
index = item.next;
|
|
73
|
+
while (/\s/.test(text[index] || ''))
|
|
74
|
+
index += 1;
|
|
75
|
+
if (text[index] === ',') {
|
|
76
|
+
index += 1;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (text[index] === ']')
|
|
80
|
+
return { value: items, next: index + 1 };
|
|
81
|
+
throw new Error('unsupported array preview');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (character === "'") {
|
|
85
|
+
const end = text.indexOf("'", index + 1);
|
|
86
|
+
if (end === -1)
|
|
87
|
+
throw new Error('unsupported char preview');
|
|
88
|
+
return { value: text.slice(index + 1, end), next: end + 1 };
|
|
89
|
+
}
|
|
90
|
+
if (text.startsWith('true', index))
|
|
91
|
+
return { value: true, next: index + 4 };
|
|
92
|
+
if (text.startsWith('false', index))
|
|
93
|
+
return { value: false, next: index + 5 };
|
|
94
|
+
const number = text.slice(index).match(/^-?\d+(?:\.\d+)?/);
|
|
95
|
+
if (number?.[0])
|
|
96
|
+
return { value: Number(number[0]), next: index + number[0].length };
|
|
97
|
+
throw new Error('unsupported preview');
|
|
98
|
+
};
|
|
99
|
+
const resolveIdentifierValue = (name) => {
|
|
100
|
+
if (parsedValues.has(name))
|
|
101
|
+
return parsedValues.get(name);
|
|
102
|
+
const value = values.get(name);
|
|
103
|
+
if (value == null || value === '?')
|
|
104
|
+
throw new Error('unavailable');
|
|
105
|
+
if (value === 'true' || value === 'false') {
|
|
106
|
+
const parsed = value === 'true';
|
|
107
|
+
parsedValues.set(name, parsed);
|
|
108
|
+
return parsed;
|
|
109
|
+
}
|
|
110
|
+
const numeric = Number(value);
|
|
111
|
+
if (!Number.isNaN(numeric)) {
|
|
112
|
+
parsedValues.set(name, numeric);
|
|
113
|
+
return numeric;
|
|
114
|
+
}
|
|
115
|
+
if (value.startsWith('[')) {
|
|
116
|
+
const parsed = parsePreviewValue(value).value;
|
|
117
|
+
parsedValues.set(name, parsed);
|
|
118
|
+
return parsed;
|
|
119
|
+
}
|
|
120
|
+
throw new Error(`unsupported value for ${name}`);
|
|
121
|
+
};
|
|
49
122
|
const parsePrimary = () => {
|
|
50
123
|
const token = tokens[cursor];
|
|
51
124
|
if (!token)
|
|
@@ -60,15 +133,22 @@ export function evaluateDebugExpression(expression, variables) {
|
|
|
60
133
|
}
|
|
61
134
|
if (token.type === 'identifier') {
|
|
62
135
|
cursor += 1;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
136
|
+
let resolved = resolveIdentifierValue(token.value);
|
|
137
|
+
while (tokens[cursor]?.type === 'bracket' && tokens[cursor]?.value === '[') {
|
|
138
|
+
cursor += 1;
|
|
139
|
+
const index = Number(parseOr());
|
|
140
|
+
const closing = tokens[cursor];
|
|
141
|
+
if (!closing || closing.type !== 'bracket' || closing.value !== ']')
|
|
142
|
+
throw new Error('missing closing bracket');
|
|
143
|
+
cursor += 1;
|
|
144
|
+
if (!Array.isArray(resolved) || !Number.isInteger(index))
|
|
145
|
+
throw new Error('unsupported index access');
|
|
146
|
+
const next = resolved[index];
|
|
147
|
+
if (next == null)
|
|
148
|
+
throw new Error('unavailable');
|
|
149
|
+
resolved = next;
|
|
150
|
+
}
|
|
151
|
+
return resolved;
|
|
72
152
|
}
|
|
73
153
|
if (token.type === 'paren' && token.value === '(') {
|
|
74
154
|
cursor += 1;
|