@thi.ng/wasm-api 0.4.0 → 0.7.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/cli.js ADDED
@@ -0,0 +1,142 @@
1
+ import { flag, oneOfMulti, parse, ParseError, string, strings, usage, } from "@thi.ng/args";
2
+ import { isArray, isPlainObject } from "@thi.ng/checks";
3
+ import { illegalArgs } from "@thi.ng/errors";
4
+ import { readJSON, writeText } from "@thi.ng/file-io";
5
+ import { ConsoleLogger } from "@thi.ng/logger";
6
+ import { resolve } from "path";
7
+ import { generateTypes } from "./codegen.js";
8
+ import { TYPESCRIPT } from "./codegen/typescript.js";
9
+ import { isPrim } from "./codegen/utils.js";
10
+ import { ZIG } from "./codegen/zig.js";
11
+ const GENERATORS = { ts: TYPESCRIPT, zig: ZIG };
12
+ const argOpts = {
13
+ config: string({
14
+ alias: "c",
15
+ hint: "FILE",
16
+ desc: "JSON config file with codegen options",
17
+ }),
18
+ debug: flag({ alias: "d", default: false, desc: "enable debug output" }),
19
+ dryRun: flag({
20
+ default: false,
21
+ desc: "enable dry run (don't overwrite files)",
22
+ }),
23
+ lang: oneOfMulti(Object.keys(GENERATORS), {
24
+ alias: "l",
25
+ desc: "target language",
26
+ default: ["ts", "zig"],
27
+ delim: ",",
28
+ }),
29
+ out: strings({ alias: "o", hint: "FILE", desc: "output file path" }),
30
+ };
31
+ export const INSTALL_DIR = resolve(`${process.argv[2]}/..`);
32
+ export const PKG = readJSON(`${INSTALL_DIR}/package.json`);
33
+ export const APP_NAME = PKG.name.split("/")[1];
34
+ export const HEADER = `
35
+ █ █ █ │
36
+ ██ █ │
37
+ █ █ █ █ █ █ █ █ │ ${PKG.name} ${PKG.version}
38
+ █ █ █ █ █ █ █ █ █ │ Multi-language data bindings code generator
39
+ █ │
40
+ █ █ │
41
+ `;
42
+ const usageOpts = {
43
+ lineWidth: process.stdout.columns,
44
+ prefix: `${HEADER}
45
+ usage: ${APP_NAME} [OPTS] JSON-INPUT-FILE(S) ...
46
+ ${APP_NAME} --help
47
+
48
+ `,
49
+ showGroupNames: true,
50
+ paramWidth: 32,
51
+ };
52
+ const showUsage = () => {
53
+ process.stderr.write(usage(argOpts, usageOpts));
54
+ process.exit(1);
55
+ };
56
+ const invalidSpec = (path, msg) => {
57
+ throw new Error(`invalid typedef: ${path}${msg ? ` (${msg})` : ""}`);
58
+ };
59
+ const addTypeSpec = (ctx, path, coll, spec) => {
60
+ if (!(spec.name && spec.type))
61
+ invalidSpec(path);
62
+ if (!(spec.type === "enum" || spec.type === "struct"))
63
+ invalidSpec(path, `${spec.name} type: ${spec.type}`);
64
+ if (coll[spec.name])
65
+ invalidSpec(path, `duplicate name: ${spec.name}`);
66
+ ctx.logger.debug(`registering ${spec.type}: ${spec.name}`);
67
+ coll[spec.name] = spec;
68
+ spec.__path = path;
69
+ };
70
+ const validateTypeRefs = (coll) => {
71
+ for (let spec of Object.values(coll)) {
72
+ if (spec.type !== "struct")
73
+ continue;
74
+ for (let f of spec.fields) {
75
+ if (!(isPrim(f.type) || coll[f.type])) {
76
+ invalidSpec(spec.__path, `structfield ${spec.name}.${f.name} of unknown type: ${f.type}`);
77
+ }
78
+ }
79
+ }
80
+ };
81
+ const parseTypeSpecs = (ctx, inputs) => {
82
+ const coll = {};
83
+ for (let path of inputs) {
84
+ try {
85
+ const spec = readJSON(resolve(path), ctx.logger);
86
+ if (isArray(spec)) {
87
+ for (let s of spec)
88
+ addTypeSpec(ctx, path, coll, s);
89
+ }
90
+ else if (isPlainObject(spec)) {
91
+ addTypeSpec(ctx, path, coll, spec);
92
+ }
93
+ else {
94
+ invalidSpec(path);
95
+ }
96
+ }
97
+ catch (e) {
98
+ process.stderr.write(e.message);
99
+ process.exit(1);
100
+ }
101
+ }
102
+ validateTypeRefs(coll);
103
+ return coll;
104
+ };
105
+ const generateOutputs = ({ config, logger, opts }, coll) => {
106
+ for (let i = 0; i < opts.lang.length; i++) {
107
+ const lang = opts.lang[i];
108
+ logger.debug(`generating ${lang.toUpperCase()} output...`);
109
+ const src = generateTypes(coll, GENERATORS[lang](config[lang]), config.global);
110
+ if (opts.out) {
111
+ writeText(resolve(opts.out[i]), src, logger, opts.dryRun);
112
+ }
113
+ else {
114
+ process.stdout.write(src + "\n");
115
+ }
116
+ }
117
+ };
118
+ try {
119
+ const result = parse(argOpts, process.argv, { start: 3, usageOpts });
120
+ if (!result)
121
+ process.exit(1);
122
+ const { result: opts, rest } = result;
123
+ if (!rest.length)
124
+ showUsage();
125
+ if (opts.out && opts.lang.length != opts.out.length) {
126
+ illegalArgs(`expected ${opts.lang.length} outputs, but got ${opts.out.length}`);
127
+ }
128
+ const ctx = {
129
+ logger: new ConsoleLogger("wasm-api", opts.debug ? "DEBUG" : "INFO"),
130
+ config: {},
131
+ opts,
132
+ };
133
+ if (opts.config) {
134
+ ctx.config = readJSON(resolve(opts.config), ctx.logger);
135
+ }
136
+ generateOutputs(ctx, parseTypeSpecs(ctx, rest));
137
+ }
138
+ catch (e) {
139
+ if (!(e instanceof ParseError))
140
+ process.stderr.write(e.message);
141
+ process.exit(1);
142
+ }
@@ -0,0 +1,26 @@
1
+ import { ICodeGen } from "../api.js";
2
+ export interface TSOpts {
3
+ /**
4
+ * Indentation string
5
+ *
6
+ * @defaultValue "\t"
7
+ */
8
+ indent: string;
9
+ /**
10
+ * If true (default), forces uppercase enums
11
+ */
12
+ uppercaseEnums: boolean;
13
+ }
14
+ /**
15
+ * TypeScript code generator. Call with options and then pass to
16
+ * {@link generateTypes} (see its docs for further usage).
17
+ *
18
+ * @remarks
19
+ * This codegen generates interface and enum definitions for a {@link TypeColl}
20
+ * given to {@link generateTypes}. For structs it will also generate memory
21
+ * mapped wrappers with fully typed accessors.
22
+ *
23
+ * @param opts
24
+ */
25
+ export declare const TYPESCRIPT: (opts?: Partial<TSOpts>) => ICodeGen;
26
+ //# sourceMappingURL=typescript.d.ts.map
@@ -0,0 +1,153 @@
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, USIZE, } from "../api.js";
4
+ import { isBigNumeric, isNumeric, isPrim, prefixLines } from "./utils.js";
5
+ /**
6
+ * TypeScript code generator. Call with options and then pass to
7
+ * {@link generateTypes} (see its docs for further usage).
8
+ *
9
+ * @remarks
10
+ * This codegen generates interface and enum definitions for a {@link TypeColl}
11
+ * given to {@link generateTypes}. For structs it will also generate memory
12
+ * mapped wrappers with fully typed accessors.
13
+ *
14
+ * @param opts
15
+ */
16
+ export const TYPESCRIPT = (opts) => {
17
+ const { indent, uppercaseEnums } = {
18
+ indent: "\t",
19
+ uppercaseEnums: true,
20
+ ...opts,
21
+ };
22
+ const I = indent;
23
+ const I2 = I + I;
24
+ const I3 = I2 + I;
25
+ const gen = {
26
+ pre: `import type { WasmTypeBase, WasmTypeConstructor } from "${PKG_NAME}";`,
27
+ doc: (doc, indent, acc) => {
28
+ if (doc.indexOf("\n") !== -1) {
29
+ acc.push(indent + "/**", prefixLines(indent + " * ", doc), indent + " */");
30
+ }
31
+ else {
32
+ acc.push(`${indent}/** ${doc} */`);
33
+ }
34
+ },
35
+ enum: (type, _, acc) => {
36
+ const e = type;
37
+ acc.push(`export enum ${e.name} {`);
38
+ for (let v of e.values) {
39
+ var line = indent;
40
+ if (!isString(v)) {
41
+ v.doc && gen.doc(v.doc, indent, acc);
42
+ line += uppercaseEnums ? v.name.toUpperCase() : v.name;
43
+ if (v.value != null)
44
+ line += ` = ${v.value}`;
45
+ }
46
+ else {
47
+ line += uppercaseEnums ? v.toUpperCase() : v;
48
+ }
49
+ acc.push(line + ",");
50
+ }
51
+ acc.push("}\n");
52
+ return acc;
53
+ },
54
+ struct: (type, types, acc) => {
55
+ const struct = type;
56
+ const returnTypes = {};
57
+ // interface definition
58
+ acc.push(`export interface ${struct.name} extends WasmTypeBase {`);
59
+ for (let f of struct.fields) {
60
+ f.doc && gen.doc(f.doc, indent, acc);
61
+ let line = `${indent}${f.name}: `;
62
+ let rtype = "";
63
+ if (f.tag == "array" || f.tag == "slice" || f.tag === "vec") {
64
+ rtype = isNumeric(f.type)
65
+ ? TYPEDARRAY_CTORS[f.type].name
66
+ : isBigNumeric(f.type)
67
+ ? BIGINT_ARRAY_CTORS[f.type].name
68
+ : f.type + "[]";
69
+ }
70
+ else if (!f.tag || f.tag === "scalar" || f.tag === "ptr") {
71
+ rtype = isBigNumeric(f.type)
72
+ ? "bigint"
73
+ : isNumeric(f.type)
74
+ ? "number"
75
+ : f.type;
76
+ }
77
+ returnTypes[f.name] = rtype;
78
+ acc.push(line + rtype + ";");
79
+ }
80
+ acc.push("}\n");
81
+ // type implementation
82
+ acc.push(`export const $${struct.name}: WasmTypeConstructor<${struct.name}> = (mem) => ({`, `${I}get align() { return ${struct.__align}; },`, `${I}get size() { return ${struct.__size}; },`, `${I}instance: (base) => ({`, `${I2}get __base() { return base; },`, `${I2}get __bytes() { return mem.u8.subarray(base, base + ${struct.__size}); },`);
83
+ for (let f of struct.fields) {
84
+ const offset = f.__offset || 0;
85
+ acc.push(`${I2}get ${f.name}(): ${returnTypes[f.name]} {`);
86
+ const prim = isPrim(f.type);
87
+ if (f.tag === "ptr") {
88
+ acc.push(prim
89
+ ? `${I3}return mem.${f.type}[${__ptrShift(offset, f.type)}];`
90
+ : `${I3}return $${f.type}.instance(${__ptr(offset)});`);
91
+ }
92
+ else if (f.tag === "slice") {
93
+ acc.push(`${I3}const len = ${__ptr(offset + 4)};`, prim
94
+ ? `${I3}const addr = ${__ptrShift(offset, f.type)};
95
+ ${I3}return mem.${f.type}.subarray(addr, addr + len);`
96
+ : `${I3}const addr = ${__ptr(offset)};\n${__mapArray(f, I3)}`);
97
+ }
98
+ else if (f.tag === "array" || f.tag === "vec") {
99
+ acc.push(prim
100
+ ? `${I3}const addr = ${__addrShift(offset, f.type)};
101
+ ${I3}return mem.${f.type}.subarray(addr, addr + ${f.len});`
102
+ : `${I3}const addr = ${__addr(offset)};\n${__mapArray(f, I3, f.len)}`);
103
+ }
104
+ else {
105
+ let setter;
106
+ if (prim) {
107
+ const addr = __mem(f.type, f.__offset);
108
+ acc.push(`${I3}return ${addr};`);
109
+ setter = `${addr} = x`;
110
+ }
111
+ else if (types[f.type].type === "enum") {
112
+ const tag = types[f.type].tag;
113
+ const addr = __mem(tag, f.__offset);
114
+ acc.push(`${I3}return ${addr};`);
115
+ setter = `${addr} = x`;
116
+ }
117
+ else {
118
+ acc.push(`${I3}return $${f.type}(mem).instance(${__addr(offset)});`);
119
+ setter = `mem.u8.set(x.__bytes, ${__addr(offset)})`;
120
+ }
121
+ // close getter
122
+ acc.push(`${I2}},`);
123
+ // setter
124
+ acc.push(`${I2}set ${f.name}(x: ${returnTypes[f.name]}) {`, `${I3}${setter};`);
125
+ }
126
+ // close field accessor
127
+ acc.push(`${I2}},`);
128
+ }
129
+ acc.push(`${I}})\n});\n`);
130
+ return acc;
131
+ },
132
+ };
133
+ return gen;
134
+ };
135
+ /** @internal */
136
+ const __shift = (type) => BIT_SHIFTS[type];
137
+ /** @internal */
138
+ const __addr = (offset) => (offset > 0 ? `(base + ${offset})` : "base");
139
+ /** @internal */
140
+ const __addrShift = (offset, shift) => {
141
+ const bits = __shift(shift);
142
+ return __addr(offset) + (bits ? " >>> " + bits : "");
143
+ };
144
+ /** @internal */
145
+ const __ptr = (offset) => `mem.${USIZE}[${__addrShift(offset, USIZE)}]`;
146
+ /** @internal */
147
+ const __ptrShift = (offset, shift) => __ptr(offset) + " >>> " + __shift(shift);
148
+ const __mem = (type, offset) => `mem.${type}[${__addrShift(offset, type)}]`;
149
+ /** @internal */
150
+ const __mapArray = (f, indent, len = "len") => prefixLines(indent, `const inst = $${f.type}(mem);
151
+ const slice: ${f.type}[] = [];
152
+ for(let i = 0; i < ${len}; i++) slice.push(inst.instance(addr + i * ${f.__size}));
153
+ return slice;`);
@@ -0,0 +1,29 @@
1
+ import type { BigType } from "@thi.ng/api";
2
+ import type { 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 isPrim: (x: string) => x is WasmPrim;
21
+ /**
22
+ * Splits given string into lines, prefixes each with given `prefix` and then
23
+ * returns rejoined result.
24
+ *
25
+ * @param prefix
26
+ * @param str
27
+ */
28
+ export declare const prefixLines: (prefix: string, str: string) => string;
29
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Returns true iff `x` is a {@link WasmPrim32}.
3
+ *
4
+ * @param x
5
+ */
6
+ export const isNumeric = (x) => /^(([iu](8|16|32))|(f(32|64)))$/.test(x);
7
+ /**
8
+ * Returns true iff `x` is a `i64` or `u64`.
9
+ *
10
+ * @param x
11
+ */
12
+ export const isBigNumeric = (x) => /^[iu]64$/.test(x);
13
+ /**
14
+ * Returns true iff `x` is a {@link WasmPrim}.
15
+ *
16
+ * @param x
17
+ */
18
+ export const isPrim = (x) => isNumeric(x) || isBigNumeric(x);
19
+ /**
20
+ * Splits given string into lines, prefixes each with given `prefix` and then
21
+ * returns rejoined result.
22
+ *
23
+ * @param prefix
24
+ * @param str
25
+ */
26
+ export const prefixLines = (prefix, str) => str
27
+ .split("\n")
28
+ .map((line) => prefix + line)
29
+ .join("\n");
@@ -0,0 +1,22 @@
1
+ import type { ICodeGen } from "../api.js";
2
+ export interface ZigOpts {
3
+ /**
4
+ * If true, generates various struct & struct field analysis functions
5
+ * (sizes, alignment, offsets etc.).
6
+ *
7
+ * @defaultValue false
8
+ */
9
+ debug: boolean;
10
+ }
11
+ /**
12
+ * Zig code generator. Call with options and then pass to {@link generateTypes}
13
+ * (see its docs for further usage).
14
+ *
15
+ * @remarks
16
+ * This codegen generates struct and enum definitions for a {@link TypeColl}
17
+ * given to {@link generateTypes}.
18
+ *
19
+ * @param opts
20
+ */
21
+ export declare const ZIG: (opts?: Partial<ZigOpts>) => ICodeGen;
22
+ //# sourceMappingURL=zig.d.ts.map
package/codegen/zig.js ADDED
@@ -0,0 +1,75 @@
1
+ import { isString } from "@thi.ng/checks/is-string";
2
+ import { prefixLines } from "./utils.js";
3
+ /**
4
+ * Zig code generator. Call with options and then pass to {@link generateTypes}
5
+ * (see its docs for further usage).
6
+ *
7
+ * @remarks
8
+ * This codegen generates struct and enum definitions for a {@link TypeColl}
9
+ * given to {@link generateTypes}.
10
+ *
11
+ * @param opts
12
+ */
13
+ export const ZIG = (opts) => {
14
+ const { debug } = { debug: false, ...opts };
15
+ const gen = {
16
+ doc: (doc, indent, acc, topLevel = false) => {
17
+ acc.push(prefixLines(topLevel ? "//! " : indent + "/// ", doc));
18
+ },
19
+ enum: (e, _, acc) => {
20
+ acc.push(`pub const ${e.name} = enum(${e.tag}) {`);
21
+ for (let v of e.values) {
22
+ let line = ` `;
23
+ if (!isString(v)) {
24
+ v.doc && gen.doc(v.doc, " ", acc);
25
+ line += v.name;
26
+ if (v.value != null)
27
+ line += ` = ${v.value}`;
28
+ }
29
+ else {
30
+ line += v;
31
+ }
32
+ acc.push(line + ",");
33
+ }
34
+ acc.push("};\n");
35
+ },
36
+ struct: (struct, _, acc) => {
37
+ const name = struct.name;
38
+ acc.push(`pub const ${name} = struct {`);
39
+ const ftypes = {};
40
+ for (let f of struct.fields) {
41
+ f.doc && gen.doc(f.doc, " ", acc);
42
+ var ftype;
43
+ switch (f.tag) {
44
+ case "array":
45
+ ftype = `[${f.len}]${f.type}`;
46
+ break;
47
+ case "slice":
48
+ ftype = `[]${f.type}`;
49
+ break;
50
+ case "vec":
51
+ ftype = `@Vector(${f.len}, ${f.type})`;
52
+ break;
53
+ case "ptr":
54
+ ftype = `*${f.len ? `[${f.len}]` : ""}${f.type}`;
55
+ break;
56
+ case "scalar":
57
+ default:
58
+ ftype = f.type;
59
+ }
60
+ ftypes[f.name] = ftype;
61
+ acc.push(` ${f.name}: ${ftype},`);
62
+ }
63
+ acc.push("};\n");
64
+ if (!debug)
65
+ return;
66
+ const fn = (fname, body) => `export fn ${name}_${fname}() usize { return ${body}; }`;
67
+ acc.push(fn("align", `@alignOf(${name})`), fn("size", `@sizeOf(${name})`));
68
+ for (let f of struct.fields) {
69
+ acc.push(fn(f.name + "_align", `@alignOf(${ftypes[f.name]})`), fn(f.name + "_offset", `@offsetOf(${name}, "${f.name}")`), fn(f.name + "_size", `@sizeOf(${ftypes[f.name]})`));
70
+ }
71
+ acc.push("");
72
+ },
73
+ };
74
+ return gen;
75
+ };
package/codegen.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { ICodeGen, TypeColl } from "./api.js";
2
+ export interface CodeGenOpts {
3
+ /**
4
+ * Optional string to be injected before generated type defs (but after
5
+ * codegen's own prelude, if any)
6
+ */
7
+ pre: string;
8
+ /**
9
+ * Optional string to be injected after generated type defs (but before
10
+ * codegen's own epilogue, if any)
11
+ */
12
+ post: string;
13
+ }
14
+ export declare const prepareTypes: (types: TypeColl) => void;
15
+ export declare const generateTypes: (types: TypeColl, codegen: ICodeGen, opts?: Partial<CodeGenOpts>) => string;
16
+ //# sourceMappingURL=codegen.d.ts.map
package/codegen.js ADDED
@@ -0,0 +1,116 @@
1
+ import { SIZEOF } from "@thi.ng/api/typedarray";
2
+ import { align } from "@thi.ng/binary/align";
3
+ import { ceilPow2 } from "@thi.ng/binary/pow";
4
+ import { compareByKey } from "@thi.ng/compare/keys";
5
+ import { compareNumDesc } from "@thi.ng/compare/numeric";
6
+ import { DEFAULT, defmulti } from "@thi.ng/defmulti/defmulti";
7
+ import { PKG_NAME, USIZE_SIZE, } from "./api.js";
8
+ import { isNumeric } from "./codegen/utils.js";
9
+ const sizeOf = defmulti((x) => x.type, {}, {
10
+ [DEFAULT]: (field, types) => {
11
+ if (field.__size)
12
+ return field.__size;
13
+ let size = 0;
14
+ if (field.tag === "ptr") {
15
+ size = USIZE_SIZE;
16
+ }
17
+ else if (field.tag === "slice") {
18
+ size = USIZE_SIZE * 2;
19
+ }
20
+ else {
21
+ size = isNumeric(field.type)
22
+ ? SIZEOF[field.type]
23
+ : sizeOf(types[field.type], types);
24
+ if (field.tag == "array" || field.tag === "vec") {
25
+ size *= field.len;
26
+ }
27
+ }
28
+ return (field.__size = align(size, field.__align));
29
+ },
30
+ enum: (type) => {
31
+ if (type.__size)
32
+ return type.__size;
33
+ return (type.__size = SIZEOF[type.tag]);
34
+ },
35
+ struct: (type, types) => {
36
+ if (type.__size)
37
+ return type.__size;
38
+ const struct = type;
39
+ let size = 0;
40
+ for (let f of struct.fields) {
41
+ size = align(size, f.__align);
42
+ f.__offset = size;
43
+ size += sizeOf(f, types);
44
+ }
45
+ return (type.__size = align(size, type.__align));
46
+ },
47
+ });
48
+ const alignOf = defmulti((x) => x.type, {}, {
49
+ [DEFAULT]: (field, types) => {
50
+ if (field.__align)
51
+ return field.__align;
52
+ let align = isNumeric(field.type)
53
+ ? SIZEOF[field.type]
54
+ : alignOf(types[field.type], types);
55
+ if (field.tag === "vec") {
56
+ align *= ceilPow2(field.len);
57
+ }
58
+ field.__align = align;
59
+ return align;
60
+ },
61
+ enum: (e) => {
62
+ return (e.__align = SIZEOF[e.tag]);
63
+ },
64
+ struct: (type, types) => {
65
+ const struct = type;
66
+ let maxAlign = 0;
67
+ for (let f of struct.fields) {
68
+ maxAlign = Math.max(maxAlign, alignOf(f, types));
69
+ }
70
+ return (type.__align = maxAlign);
71
+ },
72
+ });
73
+ const prepareType = defmulti((x) => x.type, {}, {
74
+ [DEFAULT]: (x, types) => {
75
+ if (x.__align && x.__size)
76
+ return;
77
+ alignOf(x, types);
78
+ sizeOf(x, types);
79
+ },
80
+ struct: (x, types) => {
81
+ if (x.__align && x.__size)
82
+ return;
83
+ const struct = x;
84
+ alignOf(struct, types);
85
+ if (struct.auto) {
86
+ struct.fields.sort(compareByKey("__align", compareNumDesc));
87
+ }
88
+ for (let f of struct.fields) {
89
+ if (types[f.type]) {
90
+ prepareType(types[f.type], types);
91
+ }
92
+ }
93
+ sizeOf(struct, types);
94
+ },
95
+ });
96
+ export const prepareTypes = (types) => {
97
+ for (let id in types) {
98
+ prepareType(types[id], types);
99
+ }
100
+ };
101
+ export const generateTypes = (types, codegen, opts = {}) => {
102
+ prepareTypes(types);
103
+ const res = [];
104
+ codegen.doc(`Generated by ${PKG_NAME} at ${new Date().toISOString()} - DO NOT EDIT!`, "", res, true);
105
+ res.push("");
106
+ codegen.pre && res.push(codegen.pre, "");
107
+ opts.pre && res.push(opts.pre, "");
108
+ for (let id in types) {
109
+ const type = types[id];
110
+ type.doc && codegen.doc(type.doc, "", res);
111
+ codegen[type.type](type, types, res);
112
+ }
113
+ opts.post && res.push("", opts.post);
114
+ codegen.post && res.push("", codegen.post);
115
+ return res.join("\n");
116
+ };
@@ -0,0 +1,60 @@
1
+ #pragma once
2
+
3
+ #ifdef __cplusplus
4
+ extern "C" {
5
+ #endif
6
+
7
+ #include <stddef.h>
8
+ #include <stdint.h>
9
+
10
+ #define WASM_IMPORT(MODULE, TYPE, NAME, PREFIX) \
11
+ extern __attribute__((import_module(MODULE), import_name(#NAME))) \
12
+ TYPE PREFIX##NAME
13
+ #define WASM_KEEP __attribute__((used))
14
+
15
+ // Generate stubs only if explicitly disabled by defining this symbol
16
+ #ifdef WASMAPI_NO_MALLOC
17
+ size_t WASM_KEEP _wasm_allocate(size_t num_bytes) { return 0; }
18
+ void WASM_KEEP _wasm_free(size_t addr) {}
19
+ #else
20
+ #include <stdlib.h>
21
+ size_t WASM_KEEP _wasm_allocate(size_t numBytes) {
22
+ return (size_t)malloc(numBytes);
23
+ }
24
+ void WASM_KEEP _wasm_free(size_t addr) { free((void*)addr); }
25
+ #endif
26
+
27
+ WASM_IMPORT("wasmapi", void, printI8, wasm_)(int8_t x);
28
+ WASM_IMPORT("wasmapi", void, printU8, wasm_)(uint8_t x);
29
+ WASM_IMPORT("wasmapi", void, printU8Hex, wasm_)(uint8_t x);
30
+ WASM_IMPORT("wasmapi", void, printI16, wasm_)(int16_t x);
31
+ WASM_IMPORT("wasmapi", void, printU16, wasm_)(uint16_t x);
32
+ WASM_IMPORT("wasmapi", void, printU16Hex, wasm_)(uint16_t x);
33
+ WASM_IMPORT("wasmapi", void, printI32, wasm_)(int32_t x);
34
+ WASM_IMPORT("wasmapi", void, printU32, wasm_)(uint32_t x);
35
+ WASM_IMPORT("wasmapi", void, printU32Hex, wasm_)(uint32_t x);
36
+ WASM_IMPORT("wasmapi", void, printI64, wasm_)(int64_t x);
37
+ WASM_IMPORT("wasmapi", void, printU64, wasm_)(uint64_t x);
38
+ WASM_IMPORT("wasmapi", void, printU64Hex, wasm_)(uint64_t x);
39
+ WASM_IMPORT("wasmapi", void, printF32, wasm_)(float x);
40
+ WASM_IMPORT("wasmapi", void, printF64, wasm_)(double x);
41
+
42
+ WASM_IMPORT("wasmapi", void, _printI8Array, wasm)(void* addr, size_t len);
43
+ WASM_IMPORT("wasmapi", void, _printU8Array, wasm)(void* addr, size_t len);
44
+ WASM_IMPORT("wasmapi", void, _printI16Array, wasm)(void* addr, size_t len);
45
+ WASM_IMPORT("wasmapi", void, _printU16Array, wasm)(void* addr, size_t len);
46
+ WASM_IMPORT("wasmapi", void, _printI32Array, wasm)(void* addr, size_t len);
47
+ WASM_IMPORT("wasmapi", void, _printU32Array, wasm)(void* addr, size_t len);
48
+ WASM_IMPORT("wasmapi", void, _printI64Array, wasm)(void* addr, size_t len);
49
+ WASM_IMPORT("wasmapi", void, _printU64Array, wasm)(void* addr, size_t len);
50
+ WASM_IMPORT("wasmapi", void, _printF32Array, wasm)(void* addr, size_t len);
51
+ WASM_IMPORT("wasmapi", void, _printF64Array, wasm)(void* addr, size_t len);
52
+
53
+ WASM_IMPORT("wasmapi", void, _printStr0, wasm)(void* addr);
54
+ WASM_IMPORT("wasmapi", void, _printStr, wasm)(void* addr, size_t len);
55
+
56
+ void wasm_printPtr(void* ptr) { wasm_printU32Hex((size_t)ptr); }
57
+
58
+ #ifdef __cplusplus
59
+ }
60
+ #endif