@thi.ng/wasm-api 0.18.0 → 1.0.0
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/CHANGELOG.md +190 -102
- package/README.md +96 -468
- package/api.d.ts +24 -329
- package/api.js +0 -15
- package/bridge.d.ts +0 -31
- package/bridge.js +8 -33
- package/include/wasmapi.h +46 -42
- package/include/wasmapi_types.h +35 -0
- package/index.d.ts +0 -5
- package/index.js +0 -5
- package/package.json +15 -47
- package/pointer.d.ts +20 -0
- package/pointer.js +27 -0
- package/string.d.ts +48 -15
- package/string.js +67 -17
- package/zig/lib.zig +6 -31
- package/zig/types.zig +52 -0
- package/bin/wasm-api +0 -12
- package/bin/wasm-api.mjs_ +0 -17
- package/cli.d.ts +0 -5
- package/cli.js +0 -188
- package/codegen/align.d.ts +0 -14
- package/codegen/align.js +0 -35
- package/codegen/c.d.ts +0 -33
- package/codegen/c.js +0 -100
- package/codegen/c11.d.ts +0 -22
- package/codegen/c11.js +0 -145
- package/codegen/typescript.d.ts +0 -25
- package/codegen/typescript.js +0 -240
- package/codegen/utils.d.ts +0 -96
- package/codegen/utils.js +0 -120
- package/codegen/zig.d.ts +0 -23
- package/codegen/zig.js +0 -149
- package/codegen.d.ts +0 -32
- package/codegen.js +0 -198
package/codegen/typescript.js
DELETED
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
import { BIGINT_ARRAY_CTORS, BIT_SHIFTS, TYPEDARRAY_CTORS, } from "@thi.ng/api/typedarray";
|
|
2
|
-
import { isString } from "@thi.ng/checks/is-string";
|
|
3
|
-
import { PKG_NAME, } from "../api.js";
|
|
4
|
-
import { ensureLines, enumName, isBigNumeric, isNumeric, isPadding, isStringSlice, isWasmPrim, isWasmString, pointerFields, prefixLines, stringFields, withIndentation, } from "./utils.js";
|
|
5
|
-
import { fieldType as zigFieldType } from "./zig.js";
|
|
6
|
-
/**
|
|
7
|
-
* TypeScript code generator. Call with options and then pass to
|
|
8
|
-
* {@link generateTypes} (see its docs for further usage).
|
|
9
|
-
*
|
|
10
|
-
* @remarks
|
|
11
|
-
* This codegen generates interface and enum definitions for a {@link TypeColl}
|
|
12
|
-
* given to {@link generateTypes}. For structs it will also generate memory
|
|
13
|
-
* mapped wrappers with fully typed accessors.
|
|
14
|
-
*
|
|
15
|
-
* @param opts
|
|
16
|
-
*/
|
|
17
|
-
export const TYPESCRIPT = (opts = {}) => {
|
|
18
|
-
const { indent } = {
|
|
19
|
-
indent: "\t",
|
|
20
|
-
stringType: "slice",
|
|
21
|
-
...opts,
|
|
22
|
-
};
|
|
23
|
-
const SCOPES = [/\{$/, /\}\)?[;,]?$/];
|
|
24
|
-
const gen = {
|
|
25
|
-
pre: (opts) => `// @ts-ignore possibly includes unused imports
|
|
26
|
-
import { MemorySlice, Pointer, ${__stringImpl(opts)}, WasmTypeBase, WasmTypeConstructor } from "${PKG_NAME}";${opts.pre ? `\n${opts.pre}` : ""}`,
|
|
27
|
-
post: () => opts.post || "",
|
|
28
|
-
doc: (doc, acc, opts) => {
|
|
29
|
-
acc.push("/**", ...prefixLines(" * ", doc, opts.lineWidth), " */");
|
|
30
|
-
},
|
|
31
|
-
enum: (e, _, acc, opts) => {
|
|
32
|
-
const res = [];
|
|
33
|
-
res.push(`export enum ${e.name} {`);
|
|
34
|
-
for (let v of e.values) {
|
|
35
|
-
let line;
|
|
36
|
-
if (!isString(v)) {
|
|
37
|
-
v.doc && gen.doc(v.doc, res, opts);
|
|
38
|
-
line = enumName(opts, v.name);
|
|
39
|
-
if (v.value != null)
|
|
40
|
-
line += ` = ${v.value}`;
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
line = enumName(opts, v);
|
|
44
|
-
}
|
|
45
|
-
res.push(line + ",");
|
|
46
|
-
}
|
|
47
|
-
res.push("}", "");
|
|
48
|
-
acc.push(...withIndentation(res, indent, ...SCOPES));
|
|
49
|
-
},
|
|
50
|
-
struct: (struct, types, acc, opts) => {
|
|
51
|
-
const fieldTypes = {};
|
|
52
|
-
const $stringImpl = __stringImpl(opts);
|
|
53
|
-
const lines = [];
|
|
54
|
-
// interface definition
|
|
55
|
-
lines.push(`export interface ${struct.name} extends WasmTypeBase {`);
|
|
56
|
-
for (let f of struct.fields) {
|
|
57
|
-
if (isPadding(f))
|
|
58
|
-
continue;
|
|
59
|
-
const doc = __docType(struct, f, opts);
|
|
60
|
-
doc && gen.doc(doc, lines, opts);
|
|
61
|
-
const ftype = __fieldType(f, opts);
|
|
62
|
-
fieldTypes[f.name] = ftype;
|
|
63
|
-
lines.push(`${f.name}: ${ftype};`);
|
|
64
|
-
}
|
|
65
|
-
if (struct.body?.ts) {
|
|
66
|
-
lines.push("", ...ensureLines(struct.body.ts, "decl"));
|
|
67
|
-
}
|
|
68
|
-
lines.push("}", "");
|
|
69
|
-
const pointerDecls = pointerFields(struct.fields).map((x) => {
|
|
70
|
-
return `let $${x.name}: ${fieldTypes[x.name]} | null = null;`;
|
|
71
|
-
});
|
|
72
|
-
const stringDecls = stringFields(struct.fields).map((x) => {
|
|
73
|
-
const suffix = x.tag === "array" || x.tag === "slice" ? "[]" : "";
|
|
74
|
-
return `let $${x.name}: ${$stringImpl}${suffix} | null = null;`;
|
|
75
|
-
});
|
|
76
|
-
// type implementation
|
|
77
|
-
lines.push(`export const $${struct.name}: WasmTypeConstructor<${struct.name}> = (mem) => ({`, `get align() {`, `return ${struct.__align};`, `},`, `get size() {`, `return ${struct.__size};`, `},`, `instance: (base) => {`, ...pointerDecls, ...stringDecls, `return {`, `get __base() {`, `return base;`, `},`, `get __bytes() {`, `return mem.u8.subarray(base, base + ${struct.__size});`, `},`);
|
|
78
|
-
for (let f of struct.fields) {
|
|
79
|
-
// skip explicit padding fields
|
|
80
|
-
if (isPadding(f))
|
|
81
|
-
continue;
|
|
82
|
-
const ftype = fieldTypes[f.name];
|
|
83
|
-
const offset = f.__offset || 0;
|
|
84
|
-
lines.push(`get ${f.name}(): ${ftype} {`);
|
|
85
|
-
const isPrim = isWasmPrim(f.type);
|
|
86
|
-
const isStr = isWasmString(f.type);
|
|
87
|
-
const isConst = isStr ? f.const !== false : !!f.const;
|
|
88
|
-
if (f.tag === "ptr") {
|
|
89
|
-
if (isPrim) {
|
|
90
|
-
const fn = f.len
|
|
91
|
-
? `(base) => mem.${f.type}.subarray(${__addrShift(0, f.type)}, (${__addrShift(0, f.type)}) + ${f.len})`
|
|
92
|
-
: `(base) => mem.${f.type}[${__addrShift(0, f.type)}]`;
|
|
93
|
-
lines.push(`return $${f.name} || ($${f.name} = new ${ftype}(mem, ${__addr(offset)}, ${fn}));`);
|
|
94
|
-
}
|
|
95
|
-
else if (isStr) {
|
|
96
|
-
const fn = f.len
|
|
97
|
-
? [
|
|
98
|
-
`(addr) => {`,
|
|
99
|
-
...__mapStringArray(opts.target, "buf", $stringImpl, f.len, isConst, true),
|
|
100
|
-
`}`,
|
|
101
|
-
]
|
|
102
|
-
: [
|
|
103
|
-
`(addr) => new ${$stringImpl}(mem, addr, ${isConst})`,
|
|
104
|
-
];
|
|
105
|
-
lines.push(`return $${f.name} || ($${f.name} = new ${ftype}(mem, ${__addr(offset)},`, ...fn, `));`);
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
const fn = f.len
|
|
109
|
-
? [`(addr) => {`, ...__mapArray(f, f.len), `}`]
|
|
110
|
-
: [`(addr) => new $${f.type}.instance(addr)`];
|
|
111
|
-
lines.push(`return $${f.name} || ($${f.name} = new ${ftype}(mem, ${__addr(offset)},`, ...fn, `));`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
else if (f.tag === "slice") {
|
|
115
|
-
lines.push(`const len = ${__ptr(opts.target, offset + 4)};`);
|
|
116
|
-
if (isPrim) {
|
|
117
|
-
lines.push(`const addr = ${__ptrShift(opts.target, offset, f.type)};`, `return mem.${f.type}.subarray(addr, addr + len);`);
|
|
118
|
-
}
|
|
119
|
-
else if (isStr) {
|
|
120
|
-
lines.push(`const addr = ${__ptr(opts.target, offset)};`, ...__mapStringArray(opts.target, "buf", $stringImpl, "len", isConst));
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
lines.push(`const addr = ${__ptr(opts.target, offset)};`, ...__mapArray(f));
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
else if (f.tag === "array" || f.tag === "vec") {
|
|
127
|
-
if (isPrim) {
|
|
128
|
-
lines.push(`const addr = ${__addrShift(offset, f.type)};`, `return mem.${f.type}.subarray(addr, addr + ${f.len});`);
|
|
129
|
-
}
|
|
130
|
-
else if (isStr) {
|
|
131
|
-
lines.push(`if ($${f.name}) return $${f.name};`, `const addr = ${__addr(offset)};`, ...__mapStringArray(opts.target, f.name, $stringImpl, f.len, isConst));
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
lines.push(`const addr = ${__addr(offset)};`, ...__mapArray(f, f.len));
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
else {
|
|
138
|
-
let setter;
|
|
139
|
-
if (isPrim) {
|
|
140
|
-
const addr = __mem(f.type, f.__offset);
|
|
141
|
-
lines.push(`return ${addr};`);
|
|
142
|
-
setter = `${addr} = x`;
|
|
143
|
-
}
|
|
144
|
-
else if (isStr) {
|
|
145
|
-
lines.push(`return $${f.name} || ($${f.name} = new ${$stringImpl}(mem, ${__addr(offset)}, ${isConst}));`);
|
|
146
|
-
}
|
|
147
|
-
else if (types[f.type].type === "enum") {
|
|
148
|
-
const tag = types[f.type].tag;
|
|
149
|
-
const addr = __mem(tag, f.__offset);
|
|
150
|
-
lines.push(`return ${addr};`);
|
|
151
|
-
setter = `${addr} = x`;
|
|
152
|
-
}
|
|
153
|
-
else {
|
|
154
|
-
lines.push(`return $${f.type}(mem).instance(${__addr(offset)});`);
|
|
155
|
-
setter = `mem.u8.set(x.__bytes, ${__addr(offset)})`;
|
|
156
|
-
}
|
|
157
|
-
// setter
|
|
158
|
-
if (setter) {
|
|
159
|
-
lines.push(
|
|
160
|
-
// close getter
|
|
161
|
-
`},`, `set ${f.name}(x: ${fieldTypes[f.name]}) {`, `${setter};`);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
// close field accessor
|
|
165
|
-
lines.push(`},`);
|
|
166
|
-
}
|
|
167
|
-
if (struct.body?.ts) {
|
|
168
|
-
lines.push("", ...ensureLines(struct.body.ts, "impl"), "");
|
|
169
|
-
}
|
|
170
|
-
lines.push("};", "}", "});", "");
|
|
171
|
-
acc.push(...withIndentation(lines, indent, ...SCOPES));
|
|
172
|
-
},
|
|
173
|
-
union: (type, coll, acc, opts) => {
|
|
174
|
-
gen.struct(type, coll, acc, opts);
|
|
175
|
-
},
|
|
176
|
-
};
|
|
177
|
-
return gen;
|
|
178
|
-
};
|
|
179
|
-
/** @internal */
|
|
180
|
-
const __stringImpl = (opts) => isStringSlice(opts.stringType) ? "WasmStringSlice" : "WasmStringPtr";
|
|
181
|
-
/** @internal */
|
|
182
|
-
const __fieldType = (f, opts) => {
|
|
183
|
-
const ftype = f.tag == "array" ||
|
|
184
|
-
f.tag == "slice" ||
|
|
185
|
-
f.tag === "vec" ||
|
|
186
|
-
(f.tag === "ptr" && f.len)
|
|
187
|
-
? isNumeric(f.type)
|
|
188
|
-
? TYPEDARRAY_CTORS[f.type].name
|
|
189
|
-
: isBigNumeric(f.type)
|
|
190
|
-
? BIGINT_ARRAY_CTORS[f.type].name
|
|
191
|
-
: isWasmString(f.type)
|
|
192
|
-
? __stringImpl(opts) + "[]"
|
|
193
|
-
: f.type + "[]"
|
|
194
|
-
: !f.tag || f.tag === "scalar" || f.tag === "ptr"
|
|
195
|
-
? isBigNumeric(f.type)
|
|
196
|
-
? "bigint"
|
|
197
|
-
: isNumeric(f.type)
|
|
198
|
-
? "number"
|
|
199
|
-
: isWasmString(f.type)
|
|
200
|
-
? __stringImpl(opts)
|
|
201
|
-
: f.type
|
|
202
|
-
: f.type;
|
|
203
|
-
return f.tag === "ptr" ? `Pointer<${ftype}>` : ftype;
|
|
204
|
-
};
|
|
205
|
-
/** @internal */
|
|
206
|
-
const __shift = (type) => BIT_SHIFTS[type];
|
|
207
|
-
/** @internal */
|
|
208
|
-
const __addr = (offset) => (offset > 0 ? `(base + ${offset})` : "base");
|
|
209
|
-
/** @internal */
|
|
210
|
-
const __addrShift = (offset, shift) => {
|
|
211
|
-
const bits = __shift(shift);
|
|
212
|
-
return __addr(offset) + (bits ? " >>> " + bits : "");
|
|
213
|
-
};
|
|
214
|
-
/** @internal */
|
|
215
|
-
const __ptr = (target, offset) => `mem.${target.usize}[${__addrShift(offset, target.usize)}]`;
|
|
216
|
-
/** @internal */
|
|
217
|
-
const __ptrShift = (target, offset, shift) => __ptr(target, offset) + " >>> " + __shift(shift);
|
|
218
|
-
const __mem = (type, offset) => `mem.${type}[${__addrShift(offset, type)}]`;
|
|
219
|
-
/** @internal */
|
|
220
|
-
const __mapArray = (f, len = "len") => [
|
|
221
|
-
`const inst = $${f.type}(mem);`,
|
|
222
|
-
`const slice: ${f.type}[] = [];`,
|
|
223
|
-
`for(let i = 0; i < ${len}; i++) slice.push(inst.instance(addr + i * ${f.__size}));`,
|
|
224
|
-
`return slice;`,
|
|
225
|
-
];
|
|
226
|
-
/** @internal */
|
|
227
|
-
const __mapStringArray = (target, name, type, len, isConst, isLocal = false) => [
|
|
228
|
-
isLocal ? `const $${name}: ${type}[] = [];` : `$${name} = [];`,
|
|
229
|
-
`for(let i = 0; i < ${len}; i++) $${name}.push(new ${type}(mem, addr + i * ${target.usizeBytes * (type === "WasmStringSlice" ? 2 : 1)}, ${isConst}));`,
|
|
230
|
-
`return $${name};`,
|
|
231
|
-
];
|
|
232
|
-
const __docType = (parent, f, opts) => {
|
|
233
|
-
const doc = [...ensureLines(f.doc || [])];
|
|
234
|
-
if (isWasmPrim(f.type)) {
|
|
235
|
-
if (doc.length)
|
|
236
|
-
doc.push("");
|
|
237
|
-
doc.push(`WASM type: ${zigFieldType(parent, f, opts).type}`);
|
|
238
|
-
}
|
|
239
|
-
return doc.length ? doc : undefined;
|
|
240
|
-
};
|
package/codegen/utils.d.ts
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import type { BigType } from "@thi.ng/api";
|
|
2
|
-
import type { CodeGenOpts, Field, InjectedBody, WasmPrim, WasmPrim32 } from "../api.js";
|
|
3
|
-
/**
|
|
4
|
-
* Returns true iff `x` is a {@link WasmPrim32}.
|
|
5
|
-
*
|
|
6
|
-
* @param x
|
|
7
|
-
*/
|
|
8
|
-
export declare const isNumeric: (x: string) => x is WasmPrim32;
|
|
9
|
-
/**
|
|
10
|
-
* Returns true iff `x` is a `i64` or `u64`.
|
|
11
|
-
*
|
|
12
|
-
* @param x
|
|
13
|
-
*/
|
|
14
|
-
export declare const isBigNumeric: (x: string) => x is BigType;
|
|
15
|
-
/**
|
|
16
|
-
* Returns true iff `x` is a {@link WasmPrim}.
|
|
17
|
-
*
|
|
18
|
-
* @param x
|
|
19
|
-
*/
|
|
20
|
-
export declare const isWasmPrim: (x: string) => x is WasmPrim;
|
|
21
|
-
export declare const isWasmString: (x: string) => x is "string";
|
|
22
|
-
export declare const isPadding: (f: Field) => boolean;
|
|
23
|
-
export declare const isPointer: (f: Field) => boolean;
|
|
24
|
-
export declare const isSlice: (f: Field) => boolean;
|
|
25
|
-
/**
|
|
26
|
-
* Returns true iff the struct field is a pointer, slice or "string" type
|
|
27
|
-
*
|
|
28
|
-
* @param f
|
|
29
|
-
*/
|
|
30
|
-
export declare const isPointerLike: (f: Field) => boolean;
|
|
31
|
-
/**
|
|
32
|
-
* Returns true if `type` is "slice".
|
|
33
|
-
*
|
|
34
|
-
* @param type
|
|
35
|
-
*/
|
|
36
|
-
export declare const isStringSlice: (type: CodeGenOpts["stringType"]) => type is "slice";
|
|
37
|
-
/**
|
|
38
|
-
* Returns filtered array of struct fields of with "ptr" tag.
|
|
39
|
-
*
|
|
40
|
-
* @param fields
|
|
41
|
-
*
|
|
42
|
-
* @internal
|
|
43
|
-
*/
|
|
44
|
-
export declare const pointerFields: (fields: Field[]) => Field[];
|
|
45
|
-
/**
|
|
46
|
-
* Returns filtered array of struct fields of only "string" fields.
|
|
47
|
-
*
|
|
48
|
-
* @param fields
|
|
49
|
-
*
|
|
50
|
-
* @internal
|
|
51
|
-
*/
|
|
52
|
-
export declare const stringFields: (fields: Field[]) => Field[];
|
|
53
|
-
/**
|
|
54
|
-
* Returns enum identifier formatted according to given opts.
|
|
55
|
-
*
|
|
56
|
-
* @param opts
|
|
57
|
-
* @param name
|
|
58
|
-
*
|
|
59
|
-
* @internal
|
|
60
|
-
*/
|
|
61
|
-
export declare const enumName: (opts: CodeGenOpts, name: string) => string;
|
|
62
|
-
/**
|
|
63
|
-
* Returns given field's default value (or undefined). The `lang` ID is required
|
|
64
|
-
* to obtain the language specific value if the default is given as object.
|
|
65
|
-
*
|
|
66
|
-
* @param f
|
|
67
|
-
* @param lang
|
|
68
|
-
*/
|
|
69
|
-
export declare const defaultValue: (f: Field, lang: string) => import("@thi.ng/api").NumOrString | undefined;
|
|
70
|
-
/**
|
|
71
|
-
* Takes an array of strings or splits given string into lines, word wraps and
|
|
72
|
-
* then prefixes each line with given `width` and `prefix`. Returns array of new
|
|
73
|
-
* lines.
|
|
74
|
-
*
|
|
75
|
-
* @param prefix
|
|
76
|
-
* @param str
|
|
77
|
-
* @param width
|
|
78
|
-
*/
|
|
79
|
-
export declare const prefixLines: (prefix: string, str: string | string[], width: number) => string[];
|
|
80
|
-
export declare const ensureLines: (src: string | string[] | InjectedBody, key?: keyof InjectedBody) => Iterable<string>;
|
|
81
|
-
/**
|
|
82
|
-
* Yields iterator of given lines, each with applied indentation based on given
|
|
83
|
-
* scope regexp's which are applied to each line to increase or decrease
|
|
84
|
-
* indentation level (the initial indentation level can be specified via
|
|
85
|
-
* optional `level` arg, default 0). If `scopeStart` succeeds, the indent is
|
|
86
|
-
* increased for the _next_ line. If `scopeEnd` succeeds the level is decreased
|
|
87
|
-
* for the _current_ line. ...
|
|
88
|
-
*
|
|
89
|
-
* @param lines
|
|
90
|
-
* @param indent
|
|
91
|
-
* @param scopeStart
|
|
92
|
-
* @param scopeEnd
|
|
93
|
-
* @param level
|
|
94
|
-
*/
|
|
95
|
-
export declare function withIndentation(lines: string[], indent: string, scopeStart: RegExp, scopeEnd: RegExp, level?: number): Generator<string, void, unknown>;
|
|
96
|
-
//# sourceMappingURL=utils.d.ts.map
|
package/codegen/utils.js
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { isArray } from "@thi.ng/checks/is-array";
|
|
2
|
-
import { isPlainObject } from "@thi.ng/checks/is-plain-object";
|
|
3
|
-
import { isString } from "@thi.ng/checks/is-string";
|
|
4
|
-
import { split } from "@thi.ng/strings/split";
|
|
5
|
-
import { wordWrapLine, wordWrapLines } from "@thi.ng/strings/word-wrap";
|
|
6
|
-
/**
|
|
7
|
-
* Returns true iff `x` is a {@link WasmPrim32}.
|
|
8
|
-
*
|
|
9
|
-
* @param x
|
|
10
|
-
*/
|
|
11
|
-
export const isNumeric = (x) => /^(([iu](8|16|32))|(f(32|64)))$/.test(x);
|
|
12
|
-
/**
|
|
13
|
-
* Returns true iff `x` is a `i64` or `u64`.
|
|
14
|
-
*
|
|
15
|
-
* @param x
|
|
16
|
-
*/
|
|
17
|
-
export const isBigNumeric = (x) => /^[iu]64$/.test(x);
|
|
18
|
-
/**
|
|
19
|
-
* Returns true iff `x` is a {@link WasmPrim}.
|
|
20
|
-
*
|
|
21
|
-
* @param x
|
|
22
|
-
*/
|
|
23
|
-
export const isWasmPrim = (x) => isNumeric(x) || isBigNumeric(x);
|
|
24
|
-
export const isWasmString = (x) => x === "string";
|
|
25
|
-
export const isPadding = (f) => f.pad != null && f.pad > 0;
|
|
26
|
-
export const isPointer = (f) => f.tag === "ptr";
|
|
27
|
-
export const isSlice = (f) => f.tag === "slice";
|
|
28
|
-
/**
|
|
29
|
-
* Returns true iff the struct field is a pointer, slice or "string" type
|
|
30
|
-
*
|
|
31
|
-
* @param f
|
|
32
|
-
*/
|
|
33
|
-
export const isPointerLike = (f) => isPointer(f) || isSlice(f) || isWasmString(f.type);
|
|
34
|
-
/**
|
|
35
|
-
* Returns true if `type` is "slice".
|
|
36
|
-
*
|
|
37
|
-
* @param type
|
|
38
|
-
*/
|
|
39
|
-
export const isStringSlice = (type) => type === "slice";
|
|
40
|
-
/**
|
|
41
|
-
* Returns filtered array of struct fields of with "ptr" tag.
|
|
42
|
-
*
|
|
43
|
-
* @param fields
|
|
44
|
-
*
|
|
45
|
-
* @internal
|
|
46
|
-
*/
|
|
47
|
-
export const pointerFields = (fields) => fields.filter((f) => f.tag === "ptr");
|
|
48
|
-
/**
|
|
49
|
-
* Returns filtered array of struct fields of only "string" fields.
|
|
50
|
-
*
|
|
51
|
-
* @param fields
|
|
52
|
-
*
|
|
53
|
-
* @internal
|
|
54
|
-
*/
|
|
55
|
-
export const stringFields = (fields) => fields.filter((f) => isWasmString(f.type) && f.tag !== "ptr");
|
|
56
|
-
/**
|
|
57
|
-
* Returns enum identifier formatted according to given opts.
|
|
58
|
-
*
|
|
59
|
-
* @param opts
|
|
60
|
-
* @param name
|
|
61
|
-
*
|
|
62
|
-
* @internal
|
|
63
|
-
*/
|
|
64
|
-
export const enumName = (opts, name) => opts.uppercaseEnums ? name.toUpperCase() : name;
|
|
65
|
-
/**
|
|
66
|
-
* Returns given field's default value (or undefined). The `lang` ID is required
|
|
67
|
-
* to obtain the language specific value if the default is given as object.
|
|
68
|
-
*
|
|
69
|
-
* @param f
|
|
70
|
-
* @param lang
|
|
71
|
-
*/
|
|
72
|
-
export const defaultValue = (f, lang) => f.default !== undefined
|
|
73
|
-
? isPlainObject(f.default)
|
|
74
|
-
? f.default[lang]
|
|
75
|
-
: f.default
|
|
76
|
-
: undefined;
|
|
77
|
-
/**
|
|
78
|
-
* Takes an array of strings or splits given string into lines, word wraps and
|
|
79
|
-
* then prefixes each line with given `width` and `prefix`. Returns array of new
|
|
80
|
-
* lines.
|
|
81
|
-
*
|
|
82
|
-
* @param prefix
|
|
83
|
-
* @param str
|
|
84
|
-
* @param width
|
|
85
|
-
*/
|
|
86
|
-
export const prefixLines = (prefix, str, width) => (isString(str)
|
|
87
|
-
? wordWrapLines(str, { width: width - prefix.length })
|
|
88
|
-
: str.flatMap((x) => wordWrapLine(x, { width: width - prefix.length }))).map((line) => prefix + line);
|
|
89
|
-
export const ensureLines = (src, key) => isString(src)
|
|
90
|
-
? split(src)
|
|
91
|
-
: isArray(src)
|
|
92
|
-
? src
|
|
93
|
-
: key
|
|
94
|
-
? src[key]
|
|
95
|
-
? ensureLines(src[key], key)
|
|
96
|
-
: []
|
|
97
|
-
: [];
|
|
98
|
-
/**
|
|
99
|
-
* Yields iterator of given lines, each with applied indentation based on given
|
|
100
|
-
* scope regexp's which are applied to each line to increase or decrease
|
|
101
|
-
* indentation level (the initial indentation level can be specified via
|
|
102
|
-
* optional `level` arg, default 0). If `scopeStart` succeeds, the indent is
|
|
103
|
-
* increased for the _next_ line. If `scopeEnd` succeeds the level is decreased
|
|
104
|
-
* for the _current_ line. ...
|
|
105
|
-
*
|
|
106
|
-
* @param lines
|
|
107
|
-
* @param indent
|
|
108
|
-
* @param scopeStart
|
|
109
|
-
* @param scopeEnd
|
|
110
|
-
* @param level
|
|
111
|
-
*/
|
|
112
|
-
export function* withIndentation(lines, indent, scopeStart, scopeEnd, level = 0) {
|
|
113
|
-
const stack = new Array(level).fill(indent);
|
|
114
|
-
for (let l of lines) {
|
|
115
|
-
scopeEnd.test(l) && stack.pop();
|
|
116
|
-
const curr = stack.length ? stack[stack.length - 1] : "";
|
|
117
|
-
yield curr + l;
|
|
118
|
-
scopeStart.test(l) && stack.push(curr + indent);
|
|
119
|
-
}
|
|
120
|
-
}
|
package/codegen/zig.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { CodeGenOpts, CodeGenOptsBase, Field, ICodeGen, Struct, Union } from "../api.js";
|
|
2
|
-
/**
|
|
3
|
-
* Zig code generator options.
|
|
4
|
-
*/
|
|
5
|
-
export interface ZigOpts extends CodeGenOptsBase {
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Zig code generator. Call with options and then pass to {@link generateTypes}
|
|
9
|
-
* (see its docs for further usage).
|
|
10
|
-
*
|
|
11
|
-
* @remarks
|
|
12
|
-
* This codegen generates struct and enum definitions for a {@link TypeColl}
|
|
13
|
-
* given to {@link generateTypes}.
|
|
14
|
-
*
|
|
15
|
-
* @param opts
|
|
16
|
-
*/
|
|
17
|
-
export declare const ZIG: (opts?: Partial<ZigOpts>) => ICodeGen;
|
|
18
|
-
/** @internal */
|
|
19
|
-
export declare const fieldType: (parent: Struct | Union, f: Field, opts: CodeGenOpts) => {
|
|
20
|
-
type: string;
|
|
21
|
-
defaultVal: string;
|
|
22
|
-
};
|
|
23
|
-
//# sourceMappingURL=zig.d.ts.map
|
package/codegen/zig.js
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { isNumber } from "@thi.ng/checks";
|
|
2
|
-
import { isString } from "@thi.ng/checks/is-string";
|
|
3
|
-
import { unsupported } from "@thi.ng/errors/unsupported";
|
|
4
|
-
import { defaultValue, ensureLines, isPadding, isStringSlice, isWasmString, prefixLines, withIndentation, } from "./utils.js";
|
|
5
|
-
/**
|
|
6
|
-
* Zig code generator. Call with options and then pass to {@link generateTypes}
|
|
7
|
-
* (see its docs for further usage).
|
|
8
|
-
*
|
|
9
|
-
* @remarks
|
|
10
|
-
* This codegen generates struct and enum definitions for a {@link TypeColl}
|
|
11
|
-
* given to {@link generateTypes}.
|
|
12
|
-
*
|
|
13
|
-
* @param opts
|
|
14
|
-
*/
|
|
15
|
-
export const ZIG = (opts = {}) => {
|
|
16
|
-
const INDENT = " ";
|
|
17
|
-
const SCOPES = [/\{$/, /\}\)?[;,]?$/];
|
|
18
|
-
const gen = {
|
|
19
|
-
pre: () => `const std = @import("std");${opts.pre ? `\n${opts.pre}` : ""}`,
|
|
20
|
-
post: () => opts.post || "",
|
|
21
|
-
doc: (doc, acc, opts, topLevel = false) => {
|
|
22
|
-
acc.push(...prefixLines(topLevel ? "//! " : "/// ", doc, opts.lineWidth));
|
|
23
|
-
},
|
|
24
|
-
enum: (e, _, acc, opts) => {
|
|
25
|
-
const lines = [];
|
|
26
|
-
lines.push(`pub const ${e.name} = enum(${e.tag}) {`);
|
|
27
|
-
for (let v of e.values) {
|
|
28
|
-
let line;
|
|
29
|
-
if (!isString(v)) {
|
|
30
|
-
v.doc && gen.doc(v.doc, lines, opts);
|
|
31
|
-
line = v.name;
|
|
32
|
-
if (v.value != null)
|
|
33
|
-
line += ` = ${v.value}`;
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
line = v;
|
|
37
|
-
}
|
|
38
|
-
lines.push(line + ",");
|
|
39
|
-
}
|
|
40
|
-
if (e.body?.zig) {
|
|
41
|
-
lines.push("", ...ensureLines(e.body.zig, "impl"), "");
|
|
42
|
-
}
|
|
43
|
-
lines.push("};", "");
|
|
44
|
-
acc.push(...withIndentation(lines, INDENT, ...SCOPES));
|
|
45
|
-
},
|
|
46
|
-
struct: (struct, _, acc, opts) => {
|
|
47
|
-
acc.push(...withIndentation([
|
|
48
|
-
`pub const ${struct.name} = ${struct.tag ? struct.tag + " " : ""}struct {`,
|
|
49
|
-
...__generateFields(gen, struct, opts),
|
|
50
|
-
], INDENT, ...SCOPES));
|
|
51
|
-
},
|
|
52
|
-
union: (union, _, acc, opts) => {
|
|
53
|
-
acc.push(...withIndentation([
|
|
54
|
-
`pub const ${union.name} = ${union.tag ? union.tag + " " : ""}union {`,
|
|
55
|
-
...__generateFields(gen, union, opts),
|
|
56
|
-
], INDENT, ...SCOPES));
|
|
57
|
-
},
|
|
58
|
-
};
|
|
59
|
-
return gen;
|
|
60
|
-
};
|
|
61
|
-
const __generateFields = (gen, parent, opts) => {
|
|
62
|
-
const res = [];
|
|
63
|
-
const ftypes = {};
|
|
64
|
-
const isUnion = parent.type === "union";
|
|
65
|
-
const name = parent.name;
|
|
66
|
-
let padID = 0;
|
|
67
|
-
for (let f of parent.fields) {
|
|
68
|
-
// autolabel explicit padding fields
|
|
69
|
-
if (isPadding(f)) {
|
|
70
|
-
parent.tag === "packed"
|
|
71
|
-
? __packedPadding(padID, f.pad, res)
|
|
72
|
-
: res.push(`__pad${padID}: [${f.pad}]u8,`);
|
|
73
|
-
padID++;
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
f.doc && gen.doc(f.doc, res, opts);
|
|
77
|
-
const { type, defaultVal } = fieldType(parent, f, opts);
|
|
78
|
-
ftypes[f.name] = type;
|
|
79
|
-
res.push(`${f.name}: ${type}${defaultVal},`);
|
|
80
|
-
}
|
|
81
|
-
if (parent.body?.zig) {
|
|
82
|
-
res.push("", ...ensureLines(parent.body.zig, "impl"), "");
|
|
83
|
-
}
|
|
84
|
-
res.push("};");
|
|
85
|
-
if (opts.debug) {
|
|
86
|
-
const fn = (fname, body) => res.push("", `export fn ${name}_${fname}() usize {`, `return ${body};`, `}`);
|
|
87
|
-
fn("align", `@alignOf(${name})`);
|
|
88
|
-
fn("size", `@sizeOf(${name})`);
|
|
89
|
-
for (let f of parent.fields) {
|
|
90
|
-
if (isPadding(f))
|
|
91
|
-
continue;
|
|
92
|
-
fn(f.name + "_align", `@alignOf(${ftypes[f.name]})`);
|
|
93
|
-
!isUnion &&
|
|
94
|
-
fn(f.name + "_offset", `@offsetOf(${name}, "${f.name}")`);
|
|
95
|
-
fn(f.name + "_size", `@sizeOf(${ftypes[f.name]})`);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
res.push("");
|
|
99
|
-
return res;
|
|
100
|
-
};
|
|
101
|
-
/** @internal */
|
|
102
|
-
export const fieldType = (parent, f, opts) => {
|
|
103
|
-
let type = isWasmString(f.type)
|
|
104
|
-
? isStringSlice(opts.stringType)
|
|
105
|
-
? f.const !== false
|
|
106
|
-
? "[]const u8"
|
|
107
|
-
: "[]u8"
|
|
108
|
-
: f.const !== false
|
|
109
|
-
? "[*:0]const u8"
|
|
110
|
-
: "[*:0]u8"
|
|
111
|
-
: f.type;
|
|
112
|
-
let defaultVal = defaultValue(f, "zig");
|
|
113
|
-
switch (f.tag) {
|
|
114
|
-
case "array":
|
|
115
|
-
type =
|
|
116
|
-
f.sentinel !== undefined
|
|
117
|
-
? `[${f.len}:${f.sentinel}]${type}`
|
|
118
|
-
: `[${f.len}]${type}`;
|
|
119
|
-
break;
|
|
120
|
-
case "slice":
|
|
121
|
-
type = `[${f.sentinel !== undefined ? ":" + f.sentinel : ""}]${f.const ? "const " : ""}${type}`;
|
|
122
|
-
break;
|
|
123
|
-
case "vec":
|
|
124
|
-
type = `@Vector(${f.len}, ${type})`;
|
|
125
|
-
break;
|
|
126
|
-
case "ptr":
|
|
127
|
-
type = `*${f.const ? "const " : ""}${f.len ? `[${f.len}]` : ""}${type}`;
|
|
128
|
-
break;
|
|
129
|
-
case "scalar":
|
|
130
|
-
default:
|
|
131
|
-
if (defaultVal != undefined) {
|
|
132
|
-
if (!(isString(defaultVal) || isNumber(defaultVal))) {
|
|
133
|
-
unsupported(`wrong default value for ${parent.name}.${f.name} (${defaultVal})`);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return {
|
|
138
|
-
type,
|
|
139
|
-
defaultVal: defaultVal != undefined ? ` = ${defaultVal}` : "",
|
|
140
|
-
};
|
|
141
|
-
};
|
|
142
|
-
const __packedPadding = (id, n, res) => {
|
|
143
|
-
let i = 0;
|
|
144
|
-
n <<= 3;
|
|
145
|
-
for (; n >= 128; n -= 128, i++) {
|
|
146
|
-
res.push(`__pad${id}_${i}: u128,`);
|
|
147
|
-
}
|
|
148
|
-
res.push(`__pad${id}_${i}: u${n},`);
|
|
149
|
-
};
|
package/codegen.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import { CodeGenOpts, ICodeGen, TypeColl } from "./api.js";
|
|
2
|
-
export declare const DEFAULT_CODEGEN_OPTS: CodeGenOpts;
|
|
3
|
-
/**
|
|
4
|
-
* Takes a type collection and analyzes each analyzed to compute individual
|
|
5
|
-
* alignments and sizes.
|
|
6
|
-
*
|
|
7
|
-
* @remarks
|
|
8
|
-
* This function is idempotent and called automatically by
|
|
9
|
-
* {@link generateTypes}. Only exported for dev/debug purposes.
|
|
10
|
-
*
|
|
11
|
-
* @param types
|
|
12
|
-
*
|
|
13
|
-
* @internal
|
|
14
|
-
*/
|
|
15
|
-
export declare const prepareTypes: (types: TypeColl, opts: CodeGenOpts) => TypeColl;
|
|
16
|
-
/**
|
|
17
|
-
* Code generator main entry point. Takes an object of {@link TopLevelType}
|
|
18
|
-
* definitions, an actual code generator implementation for a single target
|
|
19
|
-
* language and (optional) global codegen options. Returns generated source code
|
|
20
|
-
* for all given types as a single string.
|
|
21
|
-
*
|
|
22
|
-
* @remarks
|
|
23
|
-
* Before actual code generation the types are first analyzed to compute their
|
|
24
|
-
* alignments and sizes. This is only ever done once (idempotent), even if
|
|
25
|
-
* `generateTypes()` is called multiple times for different target langs.
|
|
26
|
-
*
|
|
27
|
-
* @param types
|
|
28
|
-
* @param codegen
|
|
29
|
-
* @param opts
|
|
30
|
-
*/
|
|
31
|
-
export declare const generateTypes: (types: TypeColl, codegen: ICodeGen, opts?: Partial<CodeGenOpts>) => string;
|
|
32
|
-
//# sourceMappingURL=codegen.d.ts.map
|