mirror of
https://github.com/Noratrieb/riverdelta.git
synced 2026-01-16 17:35:02 +01:00
wat
This commit is contained in:
parent
87b8b8eb28
commit
8b424c0add
5 changed files with 501 additions and 202 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
||||||
/node_modules
|
/node_modules
|
||||||
/target
|
/target
|
||||||
*.tsbuildinfo
|
*.tsbuildinfo
|
||||||
|
/*-example.wat
|
||||||
13
flake.nix
13
flake.nix
|
|
@ -1,15 +1,10 @@
|
||||||
{
|
{
|
||||||
description = "Example JavaScript development environment for Zero to Nix";
|
description = "Programming language written in TypeScript compiling to Wasm";
|
||||||
|
|
||||||
# Flake inputs
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs"; # also valid: "nixpkgs"
|
nixpkgs.url = "github:NixOS/nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Flake outputs
|
|
||||||
outputs = { self, nixpkgs }:
|
outputs = { self, nixpkgs }:
|
||||||
let
|
let
|
||||||
# Systems supported
|
|
||||||
allSystems = [
|
allSystems = [
|
||||||
"x86_64-linux" # 64-bit Intel/AMD Linux
|
"x86_64-linux" # 64-bit Intel/AMD Linux
|
||||||
"aarch64-linux" # 64-bit ARM Linux
|
"aarch64-linux" # 64-bit ARM Linux
|
||||||
|
|
@ -23,12 +18,12 @@
|
||||||
});
|
});
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
# Development environment output
|
|
||||||
devShells = forAllSystems ({ pkgs }: {
|
devShells = forAllSystems ({ pkgs }: {
|
||||||
default = pkgs.mkShell {
|
default = pkgs.mkShell {
|
||||||
# The Nix packages provided in the environment
|
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
nodejs-18_x # Node.js 18, plus npm, npx, and corepack
|
nodejs-18_x # Node.js 18, plus npm, npx, and corepack
|
||||||
|
wasmtime
|
||||||
|
wasm-tools
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,11 @@ export type Vectype = "v128";
|
||||||
|
|
||||||
export type Reftype = "funcref" | "externref";
|
export type Reftype = "funcref" | "externref";
|
||||||
|
|
||||||
export type Valtype = Numtype | Vectype | Reftype;
|
export type ValType = Numtype | Vectype | Reftype;
|
||||||
|
|
||||||
export type ResultType = Vec<Valtype>;
|
export type ResultType = Vec<ValType>;
|
||||||
|
|
||||||
export type Functype = {
|
export type FuncType = {
|
||||||
params: ResultType;
|
params: ResultType;
|
||||||
returns: ResultType;
|
returns: ResultType;
|
||||||
};
|
};
|
||||||
|
|
@ -42,7 +42,7 @@ export type TableType = {
|
||||||
|
|
||||||
export type GlobalType = {
|
export type GlobalType = {
|
||||||
mut: Mut;
|
mut: Mut;
|
||||||
type: Valtype;
|
type: ValType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Mut = "const" | "var";
|
export type Mut = "const" | "var";
|
||||||
|
|
@ -50,7 +50,7 @@ export type Mut = "const" | "var";
|
||||||
export type Externtype =
|
export type Externtype =
|
||||||
| {
|
| {
|
||||||
kind: "func";
|
kind: "func";
|
||||||
type: Functype;
|
type: FuncType;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
kind: "table";
|
kind: "table";
|
||||||
|
|
@ -152,7 +152,7 @@ export type ReferenceInstr =
|
||||||
|
|
||||||
export type ParametricInstr =
|
export type ParametricInstr =
|
||||||
| { kind: "drop" }
|
| { kind: "drop" }
|
||||||
| { kind: "select"; type?: Valtype[] };
|
| { kind: "select"; type?: ValType[] };
|
||||||
|
|
||||||
// . variable
|
// . variable
|
||||||
|
|
||||||
|
|
@ -223,7 +223,7 @@ export type MemoryInstr =
|
||||||
|
|
||||||
export type Blocktype =
|
export type Blocktype =
|
||||||
| { kind: "typeidx"; idx: TypeIdx }
|
| { kind: "typeidx"; idx: TypeIdx }
|
||||||
| { kind: "valtype"; type?: Valtype };
|
| { kind: "valtype"; type?: ValType };
|
||||||
|
|
||||||
export type ControlInstr =
|
export type ControlInstr =
|
||||||
| {
|
| {
|
||||||
|
|
@ -232,7 +232,7 @@ export type ControlInstr =
|
||||||
| {
|
| {
|
||||||
kind: "block" | "loop";
|
kind: "block" | "loop";
|
||||||
type: Blocktype;
|
type: Blocktype;
|
||||||
instr: Instr[];
|
instrs: Instr[];
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
kind: "if";
|
kind: "if";
|
||||||
|
|
@ -279,7 +279,7 @@ export type Expr = Instr[];
|
||||||
// Modules
|
// Modules
|
||||||
|
|
||||||
export type Module = {
|
export type Module = {
|
||||||
types: Vec<Functype>;
|
types: Vec<FuncType>;
|
||||||
funcs: Vec<Func>;
|
funcs: Vec<Func>;
|
||||||
tables: Vec<Table>;
|
tables: Vec<Table>;
|
||||||
mems: Vec<Mem>;
|
mems: Vec<Mem>;
|
||||||
|
|
@ -304,7 +304,7 @@ export type LabelIdx = u32;
|
||||||
|
|
||||||
export type Func = {
|
export type Func = {
|
||||||
type: TypeIdx;
|
type: TypeIdx;
|
||||||
locals: Vec<Valtype>;
|
locals: Vec<ValType>;
|
||||||
body: Expr;
|
body: Expr;
|
||||||
_name?: string;
|
_name?: string;
|
||||||
};
|
};
|
||||||
|
|
@ -333,9 +333,8 @@ export type Data = {
|
||||||
_name?: string;
|
_name?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Datamode =
|
export type DatamodeActive = { kind: "active"; memory: MemIdx; offset: Expr };
|
||||||
| { kind: "passive" }
|
export type Datamode = { kind: "passive" } | DatamodeActive;
|
||||||
| { kind: "active"; memory: MemIdx; offset: Expr };
|
|
||||||
|
|
||||||
export type Start = {
|
export type Start = {
|
||||||
func: FuncIdx;
|
func: FuncIdx;
|
||||||
|
|
@ -352,7 +351,7 @@ export type ExportDesc =
|
||||||
idx: FuncIdx;
|
idx: FuncIdx;
|
||||||
}
|
}
|
||||||
| { kind: "table"; idx: TableIdx }
|
| { kind: "table"; idx: TableIdx }
|
||||||
| { kind: "mem"; idx: MemIdx }
|
| { kind: "memory"; idx: MemIdx }
|
||||||
| { kind: "global"; idx: GlobalIdx };
|
| { kind: "global"; idx: GlobalIdx };
|
||||||
|
|
||||||
export type Import = {
|
export type Import = {
|
||||||
|
|
|
||||||
109
src/wasm/wat.test.ts
Normal file
109
src/wasm/wat.test.ts
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
import { Module } from "./defs";
|
||||||
|
import { writeModuleWatToString } from "./wat";
|
||||||
|
|
||||||
|
const EXAMPLE_MODULE: Module = {
|
||||||
|
_name: "example",
|
||||||
|
types: [
|
||||||
|
{ params: ["i32"], returns: ["i32"] },
|
||||||
|
{ params: [], returns: ["i32"] },
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
{
|
||||||
|
module: "left-pad",
|
||||||
|
name: "padLeft",
|
||||||
|
desc: {
|
||||||
|
kind: "func",
|
||||||
|
type: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
funcs: [
|
||||||
|
{
|
||||||
|
_name: "addOne",
|
||||||
|
type: 0,
|
||||||
|
locals: ["i32", "i32"],
|
||||||
|
body: [
|
||||||
|
{ kind: "local.set", imm: 0 },
|
||||||
|
{
|
||||||
|
kind: "block",
|
||||||
|
type: { kind: "typeidx", idx: 1 },
|
||||||
|
instrs: [{ kind: "local.get", imm: 0 }],
|
||||||
|
},
|
||||||
|
{ kind: "i32.const", imm: 1 },
|
||||||
|
{ kind: "i32.add" },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
tables: [
|
||||||
|
{
|
||||||
|
type: { reftype: "funcref", limits: { min: 10, max: 20 } },
|
||||||
|
_name: "cool-table",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
mems: [
|
||||||
|
{
|
||||||
|
type: { min: 100, max: 1000 },
|
||||||
|
_name: "the_memory",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
globals: [
|
||||||
|
{
|
||||||
|
type: { mut: "const", type: "i32" },
|
||||||
|
init: [{ kind: "i32.const", imm: 0 }],
|
||||||
|
_name: "globalling",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
elems: [],
|
||||||
|
exports: [
|
||||||
|
{
|
||||||
|
name: "addOne",
|
||||||
|
desc: { kind: "func", idx: 0 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
datas: [
|
||||||
|
{
|
||||||
|
mode: { kind: "passive" },
|
||||||
|
init: new Uint8Array(),
|
||||||
|
_name: "meow",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
mode: {
|
||||||
|
kind: "active",
|
||||||
|
memory: 0,
|
||||||
|
offset: [{ kind: "i32.const", imm: 0 }],
|
||||||
|
},
|
||||||
|
init: new Uint8Array(),
|
||||||
|
_name: "very-active-data",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
it("should print a Wasm module with the correct formatting", () => {
|
||||||
|
const wat = writeModuleWatToString(EXAMPLE_MODULE);
|
||||||
|
|
||||||
|
expect(wat).toMatchInlineSnapshot(`
|
||||||
|
"(module $example
|
||||||
|
(type (func (param i32) (result i32)))
|
||||||
|
(type (func (param) (result i32)))
|
||||||
|
(import "left-pad" "padLeft" (func (type 0)))
|
||||||
|
(func $addOne (type 0)
|
||||||
|
(local i32 i32)
|
||||||
|
local.set 0
|
||||||
|
block (type 1)
|
||||||
|
local.get 0
|
||||||
|
end
|
||||||
|
i32.const 1
|
||||||
|
i32.add
|
||||||
|
)
|
||||||
|
(table $cool-table 10 20 funcref)
|
||||||
|
(memory $the_memory 100 1000)
|
||||||
|
(global $globalling i32
|
||||||
|
i32.const 0
|
||||||
|
)
|
||||||
|
(export "addOne" (func 0))
|
||||||
|
(data $meow "")
|
||||||
|
(data $very-active-data (i32.const 0) "")
|
||||||
|
)
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
});
|
||||||
551
src/wasm/wat.ts
551
src/wasm/wat.ts
|
|
@ -4,10 +4,11 @@
|
||||||
import {
|
import {
|
||||||
Blocktype,
|
Blocktype,
|
||||||
Data,
|
Data,
|
||||||
|
DatamodeActive,
|
||||||
Elem,
|
Elem,
|
||||||
Export,
|
Export,
|
||||||
Func,
|
Func,
|
||||||
Functype as FuncType,
|
FuncType,
|
||||||
Global,
|
Global,
|
||||||
GlobalType,
|
GlobalType,
|
||||||
Import,
|
Import,
|
||||||
|
|
@ -18,125 +19,198 @@ import {
|
||||||
Module,
|
Module,
|
||||||
Start,
|
Start,
|
||||||
Table,
|
Table,
|
||||||
TableType as TableType,
|
TableType,
|
||||||
Valtype as ValType,
|
ValType,
|
||||||
} from "./defs";
|
} from "./defs";
|
||||||
|
|
||||||
const INLINE_SYM = Symbol.for("inline");
|
class Formatter {
|
||||||
const INLINE_OWN_LINE = Symbol.for("inline_own_line");
|
print: (chunk: string) => void;
|
||||||
|
indentation: number;
|
||||||
|
wordsInSexpr: number[];
|
||||||
|
freshLinebreak: boolean;
|
||||||
|
|
||||||
type Sexpr = string | number | Sexpr[] | { inline: Symbol; items: Sexpr[] };
|
constructor(print: (chunk: string) => void) {
|
||||||
|
this.print = print;
|
||||||
|
this.indentation = 0;
|
||||||
|
this.wordsInSexpr = [];
|
||||||
|
this.freshLinebreak = false;
|
||||||
|
}
|
||||||
|
|
||||||
export function writeModuleWat(module: Module) {
|
linebreak() {
|
||||||
const sexprs = sexprModule(module);
|
this.print("\n");
|
||||||
console.dir(sexprs, { depth: 100 });
|
this.print(" ".repeat(this.indentation));
|
||||||
console.log(printSexpr(sexprs));
|
this.freshLinebreak = true;
|
||||||
}
|
}
|
||||||
|
breakIndent() {
|
||||||
|
this.indentation++;
|
||||||
|
this.linebreak();
|
||||||
|
}
|
||||||
|
breakDedent() {
|
||||||
|
this.indentation--;
|
||||||
|
this.linebreak();
|
||||||
|
}
|
||||||
|
|
||||||
function printSexpr(sexpr: Sexpr): string {
|
sexpr(f: () => void) {
|
||||||
if (typeof sexpr === "string") {
|
this.startSexpr();
|
||||||
return sexpr;
|
f();
|
||||||
} else if (typeof sexpr === "number") {
|
this.endSexpr();
|
||||||
return String(sexpr);
|
}
|
||||||
} else if (typeof sexpr === "object" && "inline" in sexpr) {
|
|
||||||
return sexpr.items.map(printSexpr).join(" ");
|
word(word: string | number) {
|
||||||
} else {
|
const last = this.wordsInSexpr.length - 1;
|
||||||
const all = sexpr.map(printSexpr).join(" ");
|
if (this.wordsInSexpr[last] > 0 && !this.freshLinebreak) {
|
||||||
return `(${all})`;
|
// The first word hugs the left parenthesis.
|
||||||
|
this.print(" ");
|
||||||
|
}
|
||||||
|
this.freshLinebreak = false;
|
||||||
|
this.print(String(word));
|
||||||
|
this.wordsInSexpr[last]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
startSexpr() {
|
||||||
|
this.word("(");
|
||||||
|
this.wordsInSexpr.push(0);
|
||||||
|
}
|
||||||
|
endSexpr() {
|
||||||
|
this.print(")");
|
||||||
|
this.freshLinebreak = false;
|
||||||
|
this.wordsInSexpr.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function inline(items: Sexpr[]): Sexpr {
|
export function writeModuleWatToString(module: Module): string {
|
||||||
return { inline: INLINE_SYM, items };
|
const parts: string[] = [];
|
||||||
|
const writer = (s: string) => parts.push(s);
|
||||||
|
printModule(module, new Formatter(writer));
|
||||||
|
return parts.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
function inlineOwnLine(items: Sexpr[]): Sexpr {
|
export function writeModuleWat(module: Module, f: Formatter) {
|
||||||
return { inline: INLINE_OWN_LINE, items };
|
printModule(module, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// base
|
// base
|
||||||
|
|
||||||
function sexprString(s: string): Sexpr {
|
function printString(s: string, f: Formatter) {
|
||||||
// TODO: escaping
|
// TODO: escaping
|
||||||
return `"$${s}"`;
|
f.word(`"${s}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexprBinaryString(buf: Uint8Array): Sexpr {
|
function printBinaryString(buf: Uint8Array, f: Formatter) {
|
||||||
todo();
|
f.word(`"${buf.toString()}"`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function optArr<T>(elem?: T): T[] {
|
function printId(id: string | undefined, f: Formatter) {
|
||||||
return elem !== undefined ? [elem] : [];
|
if (id) {
|
||||||
|
f.word(`$${id}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// types
|
// types
|
||||||
|
|
||||||
function sexprValtype(type: ValType): Sexpr {
|
function printValType(type: ValType, f: Formatter) {
|
||||||
return type;
|
f.word(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexprFuncType(type: FuncType): Sexpr {
|
function printFuncType(type: FuncType, f: Formatter) {
|
||||||
return ["func", ["param", ...type.params], ["result", ...type.returns]];
|
f.sexpr(() => {
|
||||||
|
f.word("func");
|
||||||
|
f.sexpr(() => {
|
||||||
|
f.word("param");
|
||||||
|
type.params.forEach(f.word.bind(f));
|
||||||
|
});
|
||||||
|
f.sexpr(() => {
|
||||||
|
f.word("result");
|
||||||
|
type.returns.forEach(f.word.bind(f));
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexprLimits(limits: Limits): Sexpr {
|
function printLimits(limits: Limits, f: Formatter) {
|
||||||
return inline([limits.min, limits.max]);
|
f.word(limits.min);
|
||||||
|
f.word(limits.max);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexprTableType(type: TableType): Sexpr {
|
function printTableType(type: TableType, f: Formatter) {
|
||||||
todo();
|
printLimits(type.limits, f);
|
||||||
|
f.word(type.reftype);
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexprGlobalType(type: GlobalType): Sexpr {
|
function printGlobalType(type: GlobalType, f: Formatter) {
|
||||||
return type.mut === "const"
|
if (type.mut === "const") {
|
||||||
? sexprValtype(type.type)
|
printValType(type.type, f);
|
||||||
: ["mut", sexprValtype(type.type)];
|
} else {
|
||||||
|
f.sexpr(() => {
|
||||||
|
f.word("mut");
|
||||||
|
printValType(type.type, f);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// instrs
|
// instrs
|
||||||
|
|
||||||
function sexprBlockType(type: Blocktype): Sexpr {
|
function printBlockType(type: Blocktype, f: Formatter) {
|
||||||
return type.kind === "typeidx"
|
f.sexpr(() => {
|
||||||
? type.idx
|
f.word("type");
|
||||||
: type.type
|
if (type.kind === "typeidx") {
|
||||||
? sexprValtype(type.type)
|
f.word(type.idx);
|
||||||
: inline([]);
|
} else if (type.type !== undefined) {
|
||||||
|
printValType(type.type, f);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexprMemarg(arg: MemArg): Sexpr {
|
function printMemarg(arg: MemArg, f: Formatter) {
|
||||||
const align = arg.align !== undefined ? `align=${arg.align}` : "";
|
if (arg.align !== undefined) {
|
||||||
const offset = arg.offset /*0->false*/ ? `offset=${arg.offset}` : "";
|
f.word(`align=${arg.align}`);
|
||||||
return inline([offset, align]);
|
}
|
||||||
|
if (arg.offset /*0->false*/) {
|
||||||
|
`offset=${arg.offset}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexprInstr(instr: Instr): Sexpr {
|
/**
|
||||||
|
* Print a list of instructions with one extra indentation.
|
||||||
|
* Start: indented start of first instr
|
||||||
|
* End: start of next line
|
||||||
|
*/
|
||||||
|
function printInstrBlock(instrs: Instr[], f: Formatter) {
|
||||||
|
instrs.forEach((nested, i) => {
|
||||||
|
printInstr(nested, f);
|
||||||
|
if (i !== instrs.length - 1) {
|
||||||
|
f.linebreak();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
f.breakDedent();
|
||||||
|
}
|
||||||
|
|
||||||
|
function printInstr(instr: Instr, f: Formatter) {
|
||||||
switch (instr.kind) {
|
switch (instr.kind) {
|
||||||
case "block":
|
case "block":
|
||||||
case "loop":
|
case "loop":
|
||||||
return inlineOwnLine([
|
f.word(instr.kind);
|
||||||
instr.kind,
|
printBlockType(instr.type, f);
|
||||||
sexprBlockType(instr.type),
|
f.breakIndent();
|
||||||
...instr.instr.map(sexprInstr),
|
printInstrBlock(instr.instrs, f);
|
||||||
"end",
|
f.word("end");
|
||||||
]);
|
break;
|
||||||
case "if":
|
case "if":
|
||||||
if (instr.else.length === 0) {
|
if (instr.else.length === 0) {
|
||||||
return inlineOwnLine([
|
f.word(instr.kind);
|
||||||
instr.kind,
|
printBlockType(instr.type, f);
|
||||||
sexprBlockType(instr.type),
|
f.breakIndent();
|
||||||
...instr.then.map(sexprInstr),
|
printInstrBlock(instr.then, f);
|
||||||
"end",
|
f.word("end");
|
||||||
]);
|
|
||||||
} else {
|
} else {
|
||||||
return inlineOwnLine([
|
f.word(instr.kind);
|
||||||
instr.kind,
|
printBlockType(instr.type, f);
|
||||||
sexprBlockType(instr.type),
|
f.breakIndent();
|
||||||
...instr.then.map(sexprInstr),
|
printInstrBlock(instr.then, f);
|
||||||
"else",
|
f.word("else");
|
||||||
...instr.else.map(sexprInstr),
|
f.breakIndent();
|
||||||
"end",
|
printInstrBlock(instr.else, f);
|
||||||
]);
|
f.word("end");
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
case "unreachable":
|
case "unreachable":
|
||||||
case "nop":
|
case "nop":
|
||||||
case "return":
|
case "return":
|
||||||
|
|
@ -292,16 +366,27 @@ function sexprInstr(instr: Instr): Sexpr {
|
||||||
case "i64.extend8_s":
|
case "i64.extend8_s":
|
||||||
case "i64.extend16_s":
|
case "i64.extend16_s":
|
||||||
case "i64.extend32_s":
|
case "i64.extend32_s":
|
||||||
return instr.kind;
|
f.word(instr.kind);
|
||||||
|
break;
|
||||||
case "br":
|
case "br":
|
||||||
case "br_if":
|
case "br_if":
|
||||||
return inlineOwnLine([instr.kind, instr.label]);
|
f.word(instr.kind);
|
||||||
|
f.word(instr.label);
|
||||||
|
break;
|
||||||
case "br_table":
|
case "br_table":
|
||||||
return inlineOwnLine([instr.kind, ...instr.labels, instr.label]);
|
f.word(instr.kind);
|
||||||
|
instr.labels.forEach(f.word.bind(f));
|
||||||
|
f.word(instr.label);
|
||||||
|
break;
|
||||||
case "call":
|
case "call":
|
||||||
return inlineOwnLine([instr.kind, instr.func]);
|
f.word(instr.kind);
|
||||||
|
f.word(instr.func);
|
||||||
|
break;
|
||||||
case "call_indirect":
|
case "call_indirect":
|
||||||
return inlineOwnLine([instr.kind, instr.table, instr.type]);
|
f.word(instr.kind);
|
||||||
|
f.word(instr.table);
|
||||||
|
f.word(instr.type);
|
||||||
|
break;
|
||||||
case "i32.const":
|
case "i32.const":
|
||||||
case "i64.const":
|
case "i64.const":
|
||||||
case "f32.const":
|
case "f32.const":
|
||||||
|
|
@ -321,15 +406,19 @@ function sexprInstr(instr: Instr): Sexpr {
|
||||||
case "elem.drop":
|
case "elem.drop":
|
||||||
case "memory.init":
|
case "memory.init":
|
||||||
case "data.drop":
|
case "data.drop":
|
||||||
return inlineOwnLine([instr.kind, instr.imm]);
|
f.word(instr.kind);
|
||||||
|
f.word(instr.imm);
|
||||||
|
break;
|
||||||
case "select":
|
case "select":
|
||||||
return inlineOwnLine([
|
f.word(instr.kind);
|
||||||
instr.kind,
|
instr.type?.forEach((type) => printValType(type, f));
|
||||||
...optArr(instr.type?.map(sexprValtype)),
|
break;
|
||||||
]);
|
|
||||||
case "table.copy":
|
case "table.copy":
|
||||||
case "table.init":
|
case "table.init":
|
||||||
return inlineOwnLine([instr.kind, instr.imm1, instr.imm2]);
|
f.word(instr.kind);
|
||||||
|
f.word(instr.imm1);
|
||||||
|
f.word(instr.imm2);
|
||||||
|
break;
|
||||||
case "i32.load":
|
case "i32.load":
|
||||||
case "i64.load":
|
case "i64.load":
|
||||||
case "f32.load":
|
case "f32.load":
|
||||||
|
|
@ -355,124 +444,230 @@ function sexprInstr(instr: Instr): Sexpr {
|
||||||
case "i64.store32":
|
case "i64.store32":
|
||||||
case "v128.load":
|
case "v128.load":
|
||||||
case "v128.store":
|
case "v128.store":
|
||||||
return inlineOwnLine([instr.kind, sexprMemarg(instr.imm)]);
|
f.word(instr.kind);
|
||||||
|
printMemarg(instr.imm, f);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// modules
|
// modules
|
||||||
|
|
||||||
function sexprType(type: FuncType): Sexpr {
|
function printType(type: FuncType, f: Formatter) {
|
||||||
return ["type", sexprFuncType(type)];
|
f.sexpr(() => {
|
||||||
|
f.word("type");
|
||||||
|
printFuncType(type, f);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexprImport(import_: Import): Sexpr {
|
function printImport(import_: Import, f: Formatter) {
|
||||||
const desc = import_.desc;
|
f.sexpr(() => {
|
||||||
let importDesc: Sexpr;
|
f.word("import");
|
||||||
switch (desc.kind) {
|
printString(import_.module, f);
|
||||||
case "func":
|
printString(import_.name, f);
|
||||||
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 [
|
const desc = import_.desc;
|
||||||
"import",
|
f.sexpr(() => {
|
||||||
sexprString(import_.module),
|
f.word(desc.kind);
|
||||||
sexprString(import_.name),
|
switch (desc.kind) {
|
||||||
[desc.kind, importDesc],
|
case "func":
|
||||||
];
|
f.sexpr(() => {
|
||||||
|
f.word("type");
|
||||||
|
f.word(desc.type);
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case "table":
|
||||||
|
printTableType(desc.type, f);
|
||||||
|
break;
|
||||||
|
case "memory":
|
||||||
|
printLimits(desc.type, f);
|
||||||
|
break;
|
||||||
|
case "global":
|
||||||
|
printGlobalType(desc.type, f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexprFunction(func: Func): Sexpr {
|
function printFunction(func: Func, f: Formatter) {
|
||||||
return [
|
f.sexpr(() => {
|
||||||
"func",
|
f.word("func");
|
||||||
...optArr(func._name),
|
printId(func._name, f);
|
||||||
["type", func.type],
|
|
||||||
...func.locals.map((local) => ["local", sexprValtype(local)]),
|
f.sexpr(() => {
|
||||||
...func.body.map((instr) => sexprInstr(instr)),
|
f.word("type");
|
||||||
];
|
f.word(func.type);
|
||||||
|
});
|
||||||
|
|
||||||
|
f.breakIndent();
|
||||||
|
|
||||||
|
if (func.locals.length > 0) {
|
||||||
|
f.sexpr(() => {
|
||||||
|
f.word("local");
|
||||||
|
|
||||||
|
func.locals.forEach((local) => printValType(local, f));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
f.linebreak();
|
||||||
|
|
||||||
|
printInstrBlock(func.body, f);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexprTable(table: Table): Sexpr {
|
function printTable(table: Table, f: Formatter) {
|
||||||
return ["table", ...optArr(table._name), sexprTableType(table.type)];
|
f.sexpr(() => {
|
||||||
|
f.word("table");
|
||||||
|
printId(table._name, f);
|
||||||
|
printTableType(table.type, f);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexprMem(mem: Mem): Sexpr {
|
function printMem(mem: Mem, f: Formatter) {
|
||||||
return ["memory", ...optArr(mem._name), sexprLimits(mem.type)];
|
f.sexpr(() => {
|
||||||
|
f.word("memory");
|
||||||
|
printId(mem._name, f);
|
||||||
|
|
||||||
|
printLimits(mem.type, f);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexprGlobal(global: Global): Sexpr {
|
function printGlobal(global: Global, f: Formatter) {
|
||||||
return [
|
f.sexpr(() => {
|
||||||
"global",
|
f.word("global");
|
||||||
...optArr(global._name),
|
printId(global._name, f);
|
||||||
sexprGlobalType(global.type),
|
|
||||||
...global.init.map(sexprInstr),
|
printGlobalType(global.type, f);
|
||||||
];
|
|
||||||
|
f.breakIndent();
|
||||||
|
printInstrBlock(global.init, f);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
function sexprExport(export_: Export): Sexpr {
|
|
||||||
|
function printExport(export_: Export, f: Formatter) {
|
||||||
const desc = export_.desc;
|
const desc = export_.desc;
|
||||||
let exportDesc;
|
|
||||||
switch (desc.kind) {
|
f.sexpr(() => {
|
||||||
case "func":
|
f.word("export");
|
||||||
exportDesc = ["func", desc.idx];
|
printString(export_.name, f);
|
||||||
break;
|
|
||||||
case "table":
|
f.sexpr(() => {
|
||||||
exportDesc = ["table", desc.idx];
|
f.word(desc.kind);
|
||||||
break;
|
f.word(desc.idx);
|
||||||
case "mem":
|
});
|
||||||
exportDesc = ["memory", desc.idx];
|
});
|
||||||
break;
|
|
||||||
case "global":
|
|
||||||
exportDesc = ["global", desc.idx];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ["export", export_.name, exportDesc];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexprStart(start: Start): Sexpr {
|
function printStart(start: Start, f: Formatter) {
|
||||||
return ["start", start.func];
|
f.sexpr(() => {
|
||||||
|
f.word("start");
|
||||||
|
f.word(start.func);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
function sexprElem(_elem: Elem): Sexpr {
|
|
||||||
|
function printElem(_elem: Elem, f: Formatter) {
|
||||||
todo();
|
todo();
|
||||||
}
|
}
|
||||||
function sexprData(data: Data): Sexpr {
|
|
||||||
|
function printData(data: Data, f: Formatter) {
|
||||||
let mode = data.mode;
|
let mode = data.mode;
|
||||||
if (mode.kind === "passive") {
|
|
||||||
return ["data", ...optArr(data._name), sexprBinaryString(data.init)];
|
f.sexpr(() => {
|
||||||
} else {
|
f.word("data");
|
||||||
return [
|
printId(data._name, f);
|
||||||
"data",
|
|
||||||
...optArr(data._name),
|
if (mode.kind === "active") {
|
||||||
...optArr(mode.memory === 0 ? undefined : ["memory", mode.memory]),
|
const active: DatamodeActive = mode;
|
||||||
["offset", ...mode.offset.map(sexprInstr)],
|
if (active.memory !== 0) {
|
||||||
sexprBinaryString(data.init),
|
f.sexpr(() => {
|
||||||
];
|
f.word("memory");
|
||||||
}
|
f.word(active.memory);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
f.sexpr(() => {
|
||||||
|
if (active.offset.length === 1) {
|
||||||
|
printInstr(active.offset[0], f);
|
||||||
|
} else {
|
||||||
|
f.word("offset");
|
||||||
|
f.linebreak();
|
||||||
|
printInstrBlock(active.offset, f);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
printBinaryString(data.init, f);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function sexprModule(module: Module): Sexpr {
|
function printModule(module: Module, f: Formatter) {
|
||||||
return [
|
f.sexpr(() => {
|
||||||
"module",
|
f.word("module");
|
||||||
...optArr(module._name),
|
printId(module._name, f);
|
||||||
...module.types.map(sexprType),
|
f.breakIndent();
|
||||||
...module.imports.map(sexprImport),
|
|
||||||
...module.funcs.map(sexprFunction),
|
let hasAnything = false;
|
||||||
...module.tables.map(sexprTable),
|
const breakIfAny = () => {
|
||||||
...module.mems.map(sexprMem),
|
if (hasAnything) {
|
||||||
...module.globals.map(sexprGlobal),
|
f.linebreak();
|
||||||
...module.exports.map(sexprExport),
|
}
|
||||||
...optArr(module.start && sexprStart(module.start)),
|
hasAnything = true;
|
||||||
...module.elems.map(sexprElem),
|
};
|
||||||
...module.datas.map(sexprData),
|
|
||||||
];
|
module.types.forEach((type) => {
|
||||||
|
breakIfAny();
|
||||||
|
printType(type, f);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.imports.forEach((import_) => {
|
||||||
|
breakIfAny();
|
||||||
|
printImport(import_, f);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.funcs.forEach((func) => {
|
||||||
|
breakIfAny();
|
||||||
|
printFunction(func, f);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.tables.forEach((table) => {
|
||||||
|
breakIfAny();
|
||||||
|
printTable(table, f);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.mems.forEach((mem) => {
|
||||||
|
breakIfAny();
|
||||||
|
printMem(mem, f);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.globals.forEach((global) => {
|
||||||
|
breakIfAny();
|
||||||
|
printGlobal(global, f);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports.forEach((export_) => {
|
||||||
|
breakIfAny();
|
||||||
|
printExport(export_, f);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (module.start) {
|
||||||
|
breakIfAny();
|
||||||
|
printStart(module.start, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.elems.forEach((elem) => {
|
||||||
|
breakIfAny();
|
||||||
|
printElem(elem, f);
|
||||||
|
});
|
||||||
|
|
||||||
|
module.datas.forEach((data) => {
|
||||||
|
breakIfAny();
|
||||||
|
printData(data, f);
|
||||||
|
});
|
||||||
|
|
||||||
|
f.breakDedent();
|
||||||
|
});
|
||||||
|
|
||||||
|
f.linebreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
function todo(): never {
|
function todo(): never {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue