mirror of
https://github.com/Noratrieb/riverdelta.git
synced 2026-01-15 08:55:04 +01:00
start WAT
This commit is contained in:
parent
1448edc164
commit
05eacea56b
2 changed files with 128 additions and 9 deletions
366
src/wasm/defs.ts
Normal file
366
src/wasm/defs.ts
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
// Type definitions and encoding of Wasm.
|
||||
// See https://webassembly.github.io/spec/core.
|
||||
|
||||
// Base types.
|
||||
|
||||
export type Vec<T> = T[];
|
||||
export type u32 = number;
|
||||
export type u64 = number;
|
||||
export type f32 = number;
|
||||
export type f64 = number;
|
||||
export type VecByte = Uint8Array;
|
||||
export type Name = string;
|
||||
|
||||
// types
|
||||
|
||||
export type Numtype = "i32" | "i64" | "f32" | "f64";
|
||||
|
||||
export type Vectype = "v128";
|
||||
|
||||
export type Reftype = "funcref" | "externref";
|
||||
|
||||
export type Valtype = Numtype | Vectype | Reftype;
|
||||
|
||||
export type ResultType = Vec<Valtype>;
|
||||
|
||||
export type Functype = {
|
||||
params: ResultType;
|
||||
returns: ResultType;
|
||||
};
|
||||
|
||||
export type Limits = {
|
||||
min: u32;
|
||||
max: u32;
|
||||
};
|
||||
|
||||
export type MemType = Limits;
|
||||
|
||||
export type TableType = {
|
||||
limits: Limits;
|
||||
reftype: Reftype;
|
||||
};
|
||||
|
||||
export type GlobalType = {
|
||||
mut: Mut;
|
||||
type: Valtype;
|
||||
};
|
||||
|
||||
export type Mut = "const" | "var";
|
||||
|
||||
export type Externtype =
|
||||
| {
|
||||
kind: "func";
|
||||
type: Functype;
|
||||
}
|
||||
| {
|
||||
kind: "table";
|
||||
type: TableType;
|
||||
}
|
||||
| {
|
||||
kind: "mem";
|
||||
type: MemType;
|
||||
}
|
||||
| {
|
||||
kind: "global";
|
||||
type: GlobalType;
|
||||
};
|
||||
|
||||
// instructions
|
||||
|
||||
// . numeric
|
||||
|
||||
export type BitWidth = "32" | "64";
|
||||
|
||||
export type Sign = "u" | "s";
|
||||
|
||||
export type NumericInstr =
|
||||
| { kind: "i32.const"; imm: u32 }
|
||||
| { kind: "i64.const"; imm: u64 }
|
||||
| { kind: "f32.const"; imm: f32 }
|
||||
| { kind: "f64.const"; imm: f64 }
|
||||
| { kind: `i${BitWidth}.${IUnOp}` }
|
||||
| { kind: `f${BitWidth}.${FUnOp}` }
|
||||
| { kind: `i${BitWidth}.${IBinOp}` }
|
||||
| { kind: `f${BitWidth}.${FBinOp}` }
|
||||
| { kind: ITestOp }
|
||||
| { kind: IRelOp }
|
||||
| { kind: FRelOp }
|
||||
| { kind: `i${BitWidth}.extend8_s` }
|
||||
| { kind: `i${BitWidth}.extend16_s` }
|
||||
| { kind: `i64.extend32_s` }
|
||||
| { kind: "i32.wrap_i64" }
|
||||
| { kind: `i64.extend_i32_${Sign}` }
|
||||
| { kind: `i${BitWidth}.trunc_f${BitWidth}_${Sign}` }
|
||||
| { kind: `i${BitWidth}.trunc_sat_f${BitWidth}_${Sign}` }
|
||||
| { kind: "f32.demote_f64" }
|
||||
| { kind: "f64.promote_f32" }
|
||||
| { kind: `f${BitWidth}.convert_i${BitWidth}_${Sign}` }
|
||||
| { kind: "i32.reinterpret_f32" | "i64.reinterpret_f64" }
|
||||
| { kind: "f32.reinterpret_i32" | "f64.reinterpret_i64" };
|
||||
|
||||
export type IUnOp = "clz" | "ctz" | "popcnt";
|
||||
|
||||
export type IBinOp =
|
||||
| "add"
|
||||
| "sub"
|
||||
| "mul"
|
||||
| `div_${Sign}`
|
||||
| `rem_${Sign}`
|
||||
| "and"
|
||||
| "or"
|
||||
| "xor"
|
||||
| "shl"
|
||||
| `shr_${Sign}`
|
||||
| "rotl"
|
||||
| "rotr";
|
||||
|
||||
export type FUnOp =
|
||||
| "abs"
|
||||
| "neg"
|
||||
| "sqrt"
|
||||
| "ceil"
|
||||
| "floor"
|
||||
| "trunc"
|
||||
| "nearest";
|
||||
|
||||
export type FBinOp = "add" | "sub" | "mul" | "div" | "min" | "max" | "copysign";
|
||||
|
||||
export type ITestOp = "eqz";
|
||||
|
||||
export type IRelOp =
|
||||
| "eq"
|
||||
| "ne"
|
||||
| `lt_${Sign}`
|
||||
| `gt_${Sign}`
|
||||
| `le_${Sign}`
|
||||
| `ge_${Sign}`;
|
||||
|
||||
export type FRelOp = "eq" | "ne" | "lt" | "gt" | "le" | "ge";
|
||||
|
||||
// . vectors
|
||||
|
||||
export type VectorInstr = never;
|
||||
|
||||
// . reference
|
||||
|
||||
export type ReferenceInstr =
|
||||
| { kind: "ref.null"; imm: Reftype }
|
||||
| { kind: "ref.is_null" }
|
||||
| { kind: "ref.func"; imm: FuncIdx };
|
||||
|
||||
// . parametric
|
||||
|
||||
export type ParametricInstr =
|
||||
| { kind: "drop" }
|
||||
| { kind: "select"; type?: Valtype[] };
|
||||
|
||||
// . variable
|
||||
|
||||
export type VariableInstr =
|
||||
| {
|
||||
kind: `local.${"get" | "set" | "tee"}`;
|
||||
imm: LocalIdx;
|
||||
}
|
||||
| {
|
||||
kind: `global.${"get" | "set"}`;
|
||||
imm: LocalIdx;
|
||||
};
|
||||
|
||||
// . table
|
||||
|
||||
export type TableInstr =
|
||||
| {
|
||||
kind: `table.${"get" | "set" | "size" | "grow" | "fill"}`;
|
||||
imm: TableIdx;
|
||||
}
|
||||
| {
|
||||
kind: "table.copy";
|
||||
imm1: TableIdx;
|
||||
imm2: TableIdx;
|
||||
}
|
||||
| {
|
||||
kind: "table.init";
|
||||
imm1: TableIdx;
|
||||
imm2: ElemIdx;
|
||||
}
|
||||
| {
|
||||
kind: "elem.drop";
|
||||
imm: ElemIdx;
|
||||
};
|
||||
|
||||
// . memory
|
||||
|
||||
export type MemArg = {
|
||||
offset: u32;
|
||||
align: u32;
|
||||
};
|
||||
|
||||
export type MemoryInstr =
|
||||
| {
|
||||
kind: `${`${"i" | "f"}${BitWidth}` | "v128"}.${"load" | "store"}`;
|
||||
imm: MemArg;
|
||||
}
|
||||
| {
|
||||
kind: `i${BitWidth}.load${"8" | "16"}_${Sign}`;
|
||||
imm: MemArg;
|
||||
}
|
||||
| { kind: `i64.load32_${Sign}`; imm: MemArg }
|
||||
| {
|
||||
kind: `i${BitWidth}.store${"8" | "16"}`;
|
||||
imm: MemArg;
|
||||
}
|
||||
| { kind: "i64.store32"; imm: MemArg }
|
||||
| {
|
||||
kind: `memory.${"size" | "grow" | "fill" | "copy"}`;
|
||||
}
|
||||
| {
|
||||
kind: "memory.init";
|
||||
imm: DataIdx;
|
||||
}
|
||||
| { kind: "data.drop"; imm: DataIdx };
|
||||
|
||||
// . control
|
||||
|
||||
export type Blocktype =
|
||||
| { kind: "typeidx"; idx: TypeIdx }
|
||||
| { kind: "valtype"; type?: Valtype };
|
||||
|
||||
export type ControlInstr =
|
||||
| {
|
||||
kind: "nop" | "unreachable";
|
||||
}
|
||||
| {
|
||||
kind: "block" | "loop";
|
||||
type: Blocktype;
|
||||
instr: Instr[];
|
||||
}
|
||||
| {
|
||||
kind: "if";
|
||||
type: Blocktype;
|
||||
then: Instr[];
|
||||
else: Instr[];
|
||||
}
|
||||
| {
|
||||
kind: "br" | "br_if";
|
||||
label: LabelIdx;
|
||||
}
|
||||
| {
|
||||
kind: "br_table";
|
||||
labels: LabelIdx[];
|
||||
label: LabelIdx;
|
||||
}
|
||||
| {
|
||||
kind: "return";
|
||||
}
|
||||
| {
|
||||
kind: "call";
|
||||
func: FuncIdx;
|
||||
}
|
||||
| {
|
||||
kind: "call_indirect";
|
||||
table: TableIdx;
|
||||
type: TypeIdx;
|
||||
};
|
||||
|
||||
// . final
|
||||
|
||||
export type Instr =
|
||||
| NumericInstr
|
||||
| VectorInstr
|
||||
| ReferenceInstr
|
||||
| ParametricInstr
|
||||
| VariableInstr
|
||||
| TableInstr
|
||||
| MemoryInstr
|
||||
| ControlInstr;
|
||||
|
||||
export type Expr = Instr[];
|
||||
|
||||
// Modules
|
||||
|
||||
export type Module = {
|
||||
types: Vec<Functype>;
|
||||
funcs: Vec<Func>;
|
||||
tables: Vec<Table>;
|
||||
mems: Vec<Mem>;
|
||||
globals: Vec<Global>;
|
||||
elems: Vec<Elem>;
|
||||
datas: Vec<Data>;
|
||||
start?: Start;
|
||||
imports: Vec<Import>;
|
||||
exports: Vec<Export>;
|
||||
_name?: string,
|
||||
};
|
||||
|
||||
export type TypeIdx = u32;
|
||||
export type FuncIdx = u32;
|
||||
export type TableIdx = u32;
|
||||
export type MemIdx = u32;
|
||||
export type GlobalIdx = u32;
|
||||
export type ElemIdx = u32;
|
||||
export type DataIdx = u32;
|
||||
export type LocalIdx = u32;
|
||||
export type LabelIdx = u32;
|
||||
|
||||
export type Func = {
|
||||
type: TypeIdx;
|
||||
locals: Vec<Valtype>;
|
||||
body: Expr;
|
||||
_name?: string,
|
||||
};
|
||||
|
||||
export type Table = {
|
||||
type: TableType;
|
||||
};
|
||||
|
||||
export type Mem = {
|
||||
type: MemType;
|
||||
};
|
||||
|
||||
export type GLobal = {
|
||||
type: GlobalType;
|
||||
init: Expr;
|
||||
};
|
||||
|
||||
export type Elem = unknown;
|
||||
|
||||
export type Data = {
|
||||
init: VecByte;
|
||||
mode: Datamode;
|
||||
};
|
||||
|
||||
export type Datamode =
|
||||
| { kind: "passive" }
|
||||
| { kind: "active"; memory: MemIdx; offset: Expr };
|
||||
|
||||
export type Start = {
|
||||
func: FuncIdx;
|
||||
};
|
||||
|
||||
export type Export = {
|
||||
name: Name;
|
||||
desc: ExportDesc;
|
||||
};
|
||||
|
||||
export type ExportDesc =
|
||||
| {
|
||||
kind: "func";
|
||||
idx: FuncIdx;
|
||||
}
|
||||
| { kind: "table"; idx: TableIdx }
|
||||
| { kind: "mem"; idx: MemIdx | { kind: "global"; idx: GlobalIdx } };
|
||||
|
||||
export type Import = {
|
||||
module: Name;
|
||||
name: Name;
|
||||
desc: ImportDesc;
|
||||
};
|
||||
|
||||
export type ImportDesc =
|
||||
| {
|
||||
kind: "func";
|
||||
type: TypeIdx;
|
||||
}
|
||||
| { kind: "table"; type: TableType }
|
||||
| { kind: "memory"; type: MemType }
|
||||
| { kind: "global"; type: GlobalType };
|
||||
116
src/wasm/wat.ts
Normal file
116
src/wasm/wat.ts
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
// This module converts the Wasm definitions to the WAT
|
||||
// WebAssembly text format for easier debugging and inspection.
|
||||
|
||||
import {
|
||||
Func,
|
||||
Functype as FuncType,
|
||||
GlobalType,
|
||||
Import,
|
||||
Instr,
|
||||
Limits,
|
||||
Module,
|
||||
TableType as TableType,
|
||||
Valtype as ValType,
|
||||
} from "./defs";
|
||||
|
||||
const INLINE_SYM = Symbol.for("inline");
|
||||
|
||||
type Sexpr = string | number | Sexpr[] | { inline: Symbol; items: Sexpr[] };
|
||||
|
||||
export function writeModuleWat(module: Module) {
|
||||
const sexprs = sexprModule(module);
|
||||
console.dir(sexprs, { depth: 100 });
|
||||
}
|
||||
|
||||
// base
|
||||
|
||||
function sexprString(s: string): Sexpr {
|
||||
// TODO: escaping
|
||||
return `"$${s}"`;
|
||||
}
|
||||
|
||||
// types
|
||||
|
||||
function sexprValtype(type: ValType): Sexpr {
|
||||
return type;
|
||||
}
|
||||
|
||||
function sexprFuncType(type: FuncType): Sexpr {
|
||||
return ["func", ["param", ...type.params], ["result", ...type.returns]];
|
||||
}
|
||||
|
||||
function sexprLimits(limits: Limits): Sexpr {
|
||||
return { inline: INLINE_SYM, items: [limits.min, limits.max] };
|
||||
}
|
||||
|
||||
function sexprTableType(type: TableType): Sexpr {
|
||||
todo();
|
||||
}
|
||||
|
||||
function sexprGlobalType(type: GlobalType): Sexpr {
|
||||
return type.mut === "const"
|
||||
? sexprValtype(type.type)
|
||||
: ["mut", sexprValtype(type.type)];
|
||||
}
|
||||
|
||||
// instrs
|
||||
|
||||
function sexprInstr(instr: Instr): Sexpr {
|
||||
todo();
|
||||
}
|
||||
|
||||
// modules
|
||||
|
||||
function sexprType(type: FuncType): Sexpr {
|
||||
return ["type", sexprFuncType(type)];
|
||||
}
|
||||
|
||||
function sexprImport(import_: Import): Sexpr {
|
||||
const desc = import_.desc;
|
||||
let importDesc: Sexpr;
|
||||
switch (desc.kind) {
|
||||
case "func":
|
||||
importDesc = ["type", desc.type];
|
||||
break;
|
||||
case "table":
|
||||
importDesc = sexprTableType(desc.type);
|
||||
break;
|
||||
case "memory":
|
||||
importDesc = sexprLimits(desc.type);
|
||||
break;
|
||||
case "global":
|
||||
importDesc = sexprGlobalType(desc.type);
|
||||
break;
|
||||
}
|
||||
|
||||
return [
|
||||
"import",
|
||||
sexprString(import_.module),
|
||||
sexprString(import_.name),
|
||||
[desc.kind, importDesc],
|
||||
];
|
||||
}
|
||||
|
||||
function sexprFunction(func: Func): Sexpr {
|
||||
return [
|
||||
"func",
|
||||
...(func._name ? [func._name] : []),
|
||||
["type", func.type],
|
||||
...func.locals.map((local) => ["local", sexprValtype(local)]),
|
||||
...func.body.map((instr) => sexprInstr(instr)),
|
||||
];
|
||||
}
|
||||
|
||||
function sexprModule(module: Module): Sexpr {
|
||||
return [
|
||||
"module",
|
||||
...(module._name ? [module._name] : []),
|
||||
...module.types.map(sexprType),
|
||||
...module.imports.map(sexprImport),
|
||||
...module.funcs.map(sexprFunction),
|
||||
];
|
||||
}
|
||||
|
||||
function todo(): never {
|
||||
throw new Error("todo");
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue