This commit is contained in:
nora 2023-07-25 16:42:10 +02:00
parent 05eacea56b
commit 74af407e47
2 changed files with 368 additions and 13 deletions

View file

@ -82,9 +82,9 @@ export type NumericInstr =
| { kind: `f${BitWidth}.${FUnOp}` } | { kind: `f${BitWidth}.${FUnOp}` }
| { kind: `i${BitWidth}.${IBinOp}` } | { kind: `i${BitWidth}.${IBinOp}` }
| { kind: `f${BitWidth}.${FBinOp}` } | { kind: `f${BitWidth}.${FBinOp}` }
| { kind: ITestOp } | { kind: `i${BitWidth}.${ITestOp}` }
| { kind: IRelOp } | { kind: `i${BitWidth}.${IRelOp}` }
| { kind: FRelOp } | { kind: `f${BitWidth}.${FRelOp}` }
| { kind: `i${BitWidth}.extend8_s` } | { kind: `i${BitWidth}.extend8_s` }
| { kind: `i${BitWidth}.extend16_s` } | { kind: `i${BitWidth}.extend16_s` }
| { kind: `i64.extend32_s` } | { kind: `i64.extend32_s` }
@ -191,8 +191,8 @@ export type TableInstr =
// . memory // . memory
export type MemArg = { export type MemArg = {
offset: u32; offset?: u32;
align: u32; align?: u32;
}; };
export type MemoryInstr = export type MemoryInstr =
@ -289,7 +289,7 @@ export type Module = {
start?: Start; start?: Start;
imports: Vec<Import>; imports: Vec<Import>;
exports: Vec<Export>; exports: Vec<Export>;
_name?: string, _name?: string;
}; };
export type TypeIdx = u32; export type TypeIdx = u32;
@ -306,20 +306,23 @@ export type Func = {
type: TypeIdx; type: TypeIdx;
locals: Vec<Valtype>; locals: Vec<Valtype>;
body: Expr; body: Expr;
_name?: string, _name?: string;
}; };
export type Table = { export type Table = {
type: TableType; type: TableType;
_name?: string;
}; };
export type Mem = { export type Mem = {
type: MemType; type: MemType;
_name?: string;
}; };
export type GLobal = { export type Global = {
type: GlobalType; type: GlobalType;
init: Expr; init: Expr;
_name?: string;
}; };
export type Elem = unknown; export type Elem = unknown;
@ -327,6 +330,7 @@ export type Elem = unknown;
export type Data = { export type Data = {
init: VecByte; init: VecByte;
mode: Datamode; mode: Datamode;
_name?: string;
}; };
export type Datamode = export type Datamode =
@ -348,7 +352,8 @@ export type ExportDesc =
idx: FuncIdx; idx: FuncIdx;
} }
| { kind: "table"; idx: TableIdx } | { kind: "table"; idx: TableIdx }
| { kind: "mem"; idx: MemIdx | { kind: "global"; idx: GlobalIdx } }; | { kind: "mem"; idx: MemIdx }
| { kind: "global"; idx: GlobalIdx };
export type Import = { export type Import = {
module: Name; module: Name;

View file

@ -2,18 +2,28 @@
// WebAssembly text format for easier debugging and inspection. // WebAssembly text format for easier debugging and inspection.
import { import {
Blocktype,
Data,
Elem,
Export,
Func, Func,
Functype as FuncType, Functype as FuncType,
Global,
GlobalType, GlobalType,
Import, Import,
Instr, Instr,
Limits, Limits,
Mem,
MemArg,
Module, Module,
Start,
Table,
TableType as TableType, TableType as TableType,
Valtype as ValType, Valtype as ValType,
} from "./defs"; } from "./defs";
const INLINE_SYM = Symbol.for("inline"); const INLINE_SYM = Symbol.for("inline");
const INLINE_OWN_LINE = Symbol.for("inline_own_line");
type Sexpr = string | number | Sexpr[] | { inline: Symbol; items: Sexpr[] }; type Sexpr = string | number | Sexpr[] | { inline: Symbol; items: Sexpr[] };
@ -22,6 +32,14 @@ export function writeModuleWat(module: Module) {
console.dir(sexprs, { depth: 100 }); console.dir(sexprs, { depth: 100 });
} }
function inline(items: Sexpr[]): Sexpr {
return { inline: INLINE_SYM, items };
}
function inlineOwnLine(items: Sexpr[]): Sexpr {
return { inline: INLINE_OWN_LINE, items };
}
// base // base
function sexprString(s: string): Sexpr { function sexprString(s: string): Sexpr {
@ -29,6 +47,14 @@ function sexprString(s: string): Sexpr {
return `"$${s}"`; return `"$${s}"`;
} }
function sexprBinaryString(buf: Uint8Array): Sexpr {
todo();
}
function optArr<T>(elem?: T): T[] {
return elem !== undefined ? [elem] : [];
}
// types // types
function sexprValtype(type: ValType): Sexpr { function sexprValtype(type: ValType): Sexpr {
@ -40,7 +66,7 @@ function sexprFuncType(type: FuncType): Sexpr {
} }
function sexprLimits(limits: Limits): Sexpr { function sexprLimits(limits: Limits): Sexpr {
return { inline: INLINE_SYM, items: [limits.min, limits.max] }; return inline([limits.min, limits.max]);
} }
function sexprTableType(type: TableType): Sexpr { function sexprTableType(type: TableType): Sexpr {
@ -55,8 +81,268 @@ function sexprGlobalType(type: GlobalType): Sexpr {
// instrs // instrs
function sexprBlockType(type: Blocktype): Sexpr {
return type.kind === "typeidx"
? type.idx
: type.type
? sexprValtype(type.type)
: inline([]);
}
function sexprMemarg(arg: MemArg): Sexpr {
const align = arg.align !== undefined ? `align=${arg.align}` : "";
const offset = arg.offset /*0->false*/ ? `offset=${arg.offset}` : "";
return inline([offset, align]);
}
function sexprInstr(instr: Instr): Sexpr { function sexprInstr(instr: Instr): Sexpr {
todo(); switch (instr.kind) {
case "block":
case "loop":
return inlineOwnLine([
instr.kind,
sexprBlockType(instr.type),
...instr.instr.map(sexprInstr),
"end",
]);
case "if":
if (instr.else.length === 0) {
return inlineOwnLine([
instr.kind,
sexprBlockType(instr.type),
...instr.then.map(sexprInstr),
"end",
]);
} else {
return inlineOwnLine([
instr.kind,
sexprBlockType(instr.type),
...instr.then.map(sexprInstr),
"else",
...instr.else.map(sexprInstr),
"end",
]);
}
case "unreachable":
case "nop":
case "return":
case "ref.is_null":
case "drop":
case "memory.size":
case "memory.grow":
case "memory.fill":
case "memory.copy":
// numeric i32
case "i32.clz":
case "i32.ctz":
case "i32.popcnt":
case "i32.add":
case "i32.sub":
case "i32.mul":
case "i32.div_s":
case "i32.div_u":
case "i32.rem_s":
case "i32.rem_u":
case "i32.and":
case "i32.or":
case "i32.xor":
case "i32.shl":
case "i32.shr_s":
case "i32.shr_u":
case "i32.rotl":
case "i32.rotr":
// numeric i64
case "i64.clz":
case "i64.ctz":
case "i64.popcnt":
case "i64.add":
case "i64.sub":
case "i64.mul":
case "i64.div_s":
case "i64.div_u":
case "i64.rem_s":
case "i64.rem_u":
case "i64.and":
case "i64.or":
case "i64.xor":
case "i64.shl":
case "i64.shr_s":
case "i64.shr_u":
case "i64.rotl":
case "i64.rotr":
// numeric f32
case "f32.abs":
case "f32.neg":
case "f32.ceil":
case "f32.floor":
case "f32.trunc":
case "f32.nearest":
case "f32.sqrt":
case "f32.add":
case "f32.sub":
case "f32.mul":
case "f32.div":
case "f32.min":
case "f32.max":
case "f32.copysign":
// numeric f64
case "f64.abs":
case "f64.neg":
case "f64.ceil":
case "f64.floor":
case "f64.trunc":
case "f64.nearest":
case "f64.sqrt":
case "f64.add":
case "f64.sub":
case "f64.mul":
case "f64.div":
case "f64.min":
case "f64.max":
case "f64.copysign":
// more numeric i32
case "i32.eqz":
case "i32.eq":
case "i32.ne":
case "i32.lt_s":
case "i32.lt_u":
case "i32.gt_s":
case "i32.gt_u":
case "i32.le_s":
case "i32.le_u":
case "i32.ge_s":
case "i32.ge_u":
// more numeric i64
case "i64.eqz":
case "i64.eq":
case "i64.ne":
case "i64.lt_s":
case "i64.lt_u":
case "i64.gt_s":
case "i64.gt_u":
case "i64.le_s":
case "i64.le_u":
case "i64.ge_s":
case "i64.ge_u":
// more numeric f32
case "f32.eq":
case "f32.ne":
case "f32.lt":
case "f32.gt":
case "f32.le":
case "f32.ge":
// more numeric f64
case "f64.eq":
case "f64.ne":
case "f64.lt":
case "f64.gt":
case "f64.le":
case "f64.ge":
// more numeric
case "i32.wrap_i64":
case "i32.trunc_f32_s":
case "i32.trunc_f32_u":
case "i32.trunc_f64_u":
case "i32.trunc_f64_s":
case "i32.trunc_sat_f32_s":
case "i32.trunc_sat_f32_u":
case "i32.trunc_sat_f64_u":
case "i32.trunc_sat_f64_s":
case "i64.extend_i32_s":
case "i64.extend_i32_u":
case "i64.trunc_f32_s":
case "i64.trunc_f32_u":
case "i64.trunc_f64_u":
case "i64.trunc_f64_s":
case "i64.trunc_sat_f32_s":
case "i64.trunc_sat_f32_u":
case "i64.trunc_sat_f64_u":
case "i64.trunc_sat_f64_s":
case "f32.convert_i32_s":
case "f32.convert_i32_u":
case "f32.convert_i64_s":
case "f32.convert_i64_u":
case "f32.demote_f64":
case "f64.convert_i32_s":
case "f64.convert_i32_u":
case "f64.convert_i64_s":
case "f64.convert_i64_u":
case "f64.promote_f32":
case "i32.reinterpret_f32":
case "i64.reinterpret_f64":
case "f32.reinterpret_i32":
case "f64.reinterpret_i64":
// int extend
case "i32.extend8_s":
case "i32.extend16_s":
case "i64.extend8_s":
case "i64.extend16_s":
case "i64.extend32_s":
return instr.kind;
case "br":
case "br_if":
return inlineOwnLine([instr.kind, instr.label]);
case "br_table":
return inlineOwnLine([instr.kind, ...instr.labels, instr.label]);
case "call":
return inlineOwnLine([instr.kind, instr.func]);
case "call_indirect":
return inlineOwnLine([instr.kind, instr.table, instr.type]);
case "i32.const":
case "i64.const":
case "f32.const":
case "f64.const":
case "ref.null":
case "ref.func":
case "local.get":
case "local.set":
case "local.tee":
case "global.get":
case "global.set":
case "table.get":
case "table.set":
case "table.size":
case "table.grow":
case "table.fill":
case "elem.drop":
case "memory.init":
case "data.drop":
return inlineOwnLine([instr.kind, instr.imm]);
case "select":
return inlineOwnLine([
instr.kind,
...optArr(instr.type?.map(sexprValtype)),
]);
case "table.copy":
case "table.init":
return inlineOwnLine([instr.kind, instr.imm1, instr.imm2]);
case "i32.load":
case "i64.load":
case "f32.load":
case "f64.load":
case "i32.load8_s":
case "i32.load8_u":
case "i32.load16_s":
case "i32.load16_u":
case "i64.load8_s":
case "i64.load8_u":
case "i64.load16_s":
case "i64.load16_u":
case "i64.load32_s":
case "i64.load32_u":
case "i32.store":
case "i64.store":
case "f32.store":
case "f64.store":
case "i32.store8":
case "i32.store16":
case "i64.store8":
case "i64.store16":
case "i64.store32":
case "v128.load":
case "v128.store":
return inlineOwnLine([instr.kind, sexprMemarg(instr.imm)]);
}
} }
// modules // modules
@ -94,20 +380,84 @@ function sexprImport(import_: Import): Sexpr {
function sexprFunction(func: Func): Sexpr { function sexprFunction(func: Func): Sexpr {
return [ return [
"func", "func",
...(func._name ? [func._name] : []), ...optArr(func._name),
["type", func.type], ["type", func.type],
...func.locals.map((local) => ["local", sexprValtype(local)]), ...func.locals.map((local) => ["local", sexprValtype(local)]),
...func.body.map((instr) => sexprInstr(instr)), ...func.body.map((instr) => sexprInstr(instr)),
]; ];
} }
function sexprTable(table: Table): Sexpr {
return ["table", ...optArr(table._name), sexprTableType(table.type)];
}
function sexprMem(mem: Mem): Sexpr {
return ["memory", ...optArr(mem._name), sexprLimits(mem.type)];
}
function sexprGlobal(global: Global): Sexpr {
return [
"global",
...optArr(global._name),
sexprGlobalType(global.type),
...global.init.map(sexprInstr),
];
}
function sexprExport(export_: Export): Sexpr {
const desc = export_.desc;
let exportDesc;
switch (desc.kind) {
case "func":
exportDesc = ["func", desc.idx];
break;
case "table":
exportDesc = ["table", desc.idx];
break;
case "mem":
exportDesc = ["memory", desc.idx];
break;
case "global":
exportDesc = ["global", desc.idx];
break;
}
return ["export", export_.name, exportDesc];
}
function sexprStart(start: Start): Sexpr {
return ["start", start.func];
}
function sexprElem(_elem: Elem): Sexpr {
todo();
}
function sexprData(data: Data): Sexpr {
let mode = data.mode;
if (mode.kind === "passive") {
return ["data", ...optArr(data._name), sexprBinaryString(data.init)];
} else {
return [
"data",
...optArr(data._name),
...optArr(mode.memory === 0 ? undefined : ["memory", mode.memory]),
["offset", ...mode.offset.map(sexprInstr)],
sexprBinaryString(data.init),
];
}
}
function sexprModule(module: Module): Sexpr { function sexprModule(module: Module): Sexpr {
return [ return [
"module", "module",
...(module._name ? [module._name] : []), ...optArr(module._name),
...module.types.map(sexprType), ...module.types.map(sexprType),
...module.imports.map(sexprImport), ...module.imports.map(sexprImport),
...module.funcs.map(sexprFunction), ...module.funcs.map(sexprFunction),
...module.tables.map(sexprTable),
...module.mems.map(sexprMem),
...module.globals.map(sexprGlobal),
...module.exports.map(sexprExport),
...optArr(module.start && sexprStart(module.start)),
...module.elems.map(sexprElem),
...module.datas.map(sexprData),
]; ];
} }