diff --git a/packages/ast/src/definitions.js b/packages/ast/src/definitions.js index 171db7dfc..6cca5f587 100644 --- a/packages/ast/src/definitions.js +++ b/packages/ast/src/definitions.js @@ -272,7 +272,8 @@ defineType("Elem", { unionType: ["Node"], fields: { table: { - type: "Index" + type: "Index", + assertNodeType: true, }, offset: { array: true, @@ -280,7 +281,8 @@ defineType("Elem", { }, funcs: { array: true, - type: "Index" + type: "Index", + assertNodeType: true, } } }); @@ -289,7 +291,8 @@ defineType("IndexInFuncSection", { unionType: ["Node"], fields: { index: { - type: "Index" + type: "Index", + assertNodeType: true, } } }); @@ -308,7 +311,8 @@ defineType("TypeInstruction", { fields: { id: { maybe: true, - type: "Index" + type: "Index", + assertNodeType: true, }, functype: { type: "Signature" @@ -320,7 +324,9 @@ defineType("Start", { unionType: ["Node"], fields: { index: { - type: "Index" + assertNodeType: true, + type: "Index", + assertNodeType: true, } } }); @@ -404,7 +410,8 @@ defineType("Table", { elements: { array: true, optional: true, - type: "Index" + type: "Index", + assertNodeType: true, } } }); @@ -417,7 +424,8 @@ defineType("Memory", { }, id: { maybe: true, - type: "Index" + type: "Index", + assertNodeType: true, } } }); @@ -456,7 +464,8 @@ defineType("ModuleExportDescr", { type: "ExportDescrType" }, id: { - type: "Index" + type: "Index", + assertNodeType: true, } } }); @@ -555,6 +564,7 @@ defineType("CallInstruction", { value: "call" }, index: { + assertNodeType: true, type: "Index" }, instrArgs: { @@ -599,7 +609,8 @@ defineType("Func", { fields: { name: { maybe: true, - type: "Index" + type: "Index", + assertNodeType: true, }, signature: { type: "SignatureOrTypeRef" @@ -620,4 +631,19 @@ defineType("Func", { } }); +defineType("Index", { + unionType: ["Node"], + fields: { + index: { + maybe: true, + type: "Idx" + }, + identifier: { + assertNodeType: true, + maybe: true, + type: "Identifier" + } + } +}); + module.exports = definitions; diff --git a/packages/ast/src/index.js b/packages/ast/src/index.js index 5e646e296..bf860a5c8 100644 --- a/packages/ast/src/index.js +++ b/packages/ast/src/index.js @@ -10,7 +10,9 @@ export { indexLiteral, memIndexLiteral, instruction, - objectInstruction + objectInstruction, + indexOfIndex, + indexOfIdentifier } from "./node-helpers.js"; export { traverse } from "./traverse"; diff --git a/packages/ast/src/node-helpers.js b/packages/ast/src/node-helpers.js index 1093c7275..1ab94ce09 100644 --- a/packages/ast/src/node-helpers.js +++ b/packages/ast/src/node-helpers.js @@ -1,5 +1,7 @@ // @flow +import { assert } from "mamacro"; + const { parse32F, parse64F, @@ -10,7 +12,15 @@ const { isInfLiteral } = require("@webassemblyjs/wast-parser/lib/number-literals"); -import { longNumberLiteral, floatLiteral, numberLiteral, instr } from "./nodes"; +import { + assertNumberLiteral, + assertIdentifier, + longNumberLiteral, + floatLiteral, + numberLiteral, + instr, + index +} from "./nodes"; export function numberLiteralFromRaw( rawValue: number | string, @@ -113,3 +123,17 @@ export function memIndexLiteral(value: number): Memidx { const x: U32Literal = numberLiteralFromRaw(value, "u32"); return x; } + +export function indexOfIndex(n: NumberLiteral) { + console.log(n.type); + assertNumberLiteral(n); + + return index(n, null); +} + +export function indexOfIdentifier(n: Identifer) { + console.log(n.type); + assertIdentifier(n); + + return index(null, n); +} diff --git a/packages/ast/src/nodes.js b/packages/ast/src/nodes.js index fa03d45ce..b225d7cf1 100644 --- a/packages/ast/src/nodes.js +++ b/packages/ast/src/nodes.js @@ -384,6 +384,10 @@ export function elem( offset: Array, funcs: Array ): Elem { + assert( + table.type === "Index", + "Argument table must be of type Index, given: " + table.type + ); assert(typeof offset === "object" && typeof offset.length !== "undefined"); assert(typeof funcs === "object" && typeof funcs.length !== "undefined"); @@ -399,6 +403,11 @@ export function elem( } export function indexInFuncSection(index: Index): IndexInFuncSection { + assert( + index.type === "Index", + "Argument index must be of type Index, given: " + index.type + ); + const node: IndexInFuncSection = { type: "IndexInFuncSection", index @@ -420,6 +429,13 @@ export function typeInstruction( id: ?Index, functype: Signature ): TypeInstruction { + if (id !== null && id !== undefined) { + assert( + id.type === "Index", + "Argument id must be of type Index, given: " + id.type + ); + } + const node: TypeInstruction = { type: "TypeInstruction", id, @@ -430,6 +446,11 @@ export function typeInstruction( } export function start(index: Index): Start { + assert( + index.type === "Index", + "Argument index must be of type Index, given: " + index.type + ); + const node: Start = { type: "Start", index @@ -543,6 +564,13 @@ export function table( } export function memory(limits: Limit, id: ?Index): Memory { + if (id !== null && id !== undefined) { + assert( + id.type === "Index", + "Argument id must be of type Index, given: " + id.type + ); + } + const node: Memory = { type: "Memory", limits, @@ -593,6 +621,11 @@ export function moduleExportDescr( exportType: ExportDescrType, id: Index ): ModuleExportDescr { + assert( + id.type === "Index", + "Argument id must be of type Index, given: " + id.type + ); + const node: ModuleExportDescr = { type: "ModuleExportDescr", exportType, @@ -720,6 +753,11 @@ export function callInstruction( index: Index, instrArgs?: Array ): CallInstruction { + assert( + index.type === "Index", + "Argument index must be of type Index, given: " + index.type + ); + if (instrArgs !== null && instrArgs !== undefined) { assert( typeof instrArgs === "object" && typeof instrArgs.length !== "undefined" @@ -778,6 +816,13 @@ export function func( isExternal?: boolean, metadata?: FuncMetadata ): Func { + if (name !== null && name !== undefined) { + assert( + name.type === "Index", + "Argument name must be of type Index, given: " + name.type + ); + } + assert(typeof body === "object" && typeof body.length !== "undefined"); if (isExternal !== null && isExternal !== undefined) { @@ -805,6 +850,24 @@ export function func( return node; } +export function index(index: ?Idx, identifier: ?Identifier): Index { + if (identifier !== null && identifier !== undefined) { + assert( + identifier.type === "Identifier", + "Argument identifier must be of type Identifier, given: " + + identifier.type + ); + } + + const node: Index = { + type: "Index", + index, + identifier + }; + + return node; +} + export const isModule = isTypeOf("Module"); export const isModuleMetadata = isTypeOf("ModuleMetadata"); @@ -885,6 +948,8 @@ export const isByteArray = isTypeOf("ByteArray"); export const isFunc = isTypeOf("Func"); +export const isIndex = isTypeOf("Index"); + export const isNode = (node: Node) => isModule(node) || isModuleMetadata(node) || @@ -925,7 +990,8 @@ export const isNode = (node: Node) => isCallInstruction(node) || isCallIndirectInstruction(node) || isByteArray(node) || - isFunc(node); + isFunc(node) || + isIndex(node); export const isBlock = (node: Node) => isLoopInstruction(node) || isBlockInstruction(node) || isFunc(node); @@ -1039,6 +1105,8 @@ export const assertByteArray = assertTypeOf("ByteArray"); export const assertFunc = assertTypeOf("Func"); +export const assertIndex = assertTypeOf("Index"); + export const unionTypesMap = { Module: ["Node"], ModuleMetadata: ["Node"], @@ -1079,7 +1147,8 @@ export const unionTypesMap = { CallInstruction: ["Node", "Instruction"], CallIndirectInstruction: ["Node", "Instruction"], ByteArray: ["Node"], - Func: ["Node", "Block"] + Func: ["Node", "Block"], + Index: ["Node"] }; export const nodeAndUnionTypes = [ @@ -1123,6 +1192,7 @@ export const nodeAndUnionTypes = [ "CallIndirectInstruction", "ByteArray", "Func", + "Index", "Node", "Block", "Instruction", diff --git a/packages/ast/src/types/basic.js b/packages/ast/src/types/basic.js index 8b7a2f92d..8cb19b8b0 100644 --- a/packages/ast/src/types/basic.js +++ b/packages/ast/src/types/basic.js @@ -25,16 +25,14 @@ type Memidx = U32Literal; type Globalidx = U32Literal; type Localidx = U32Literal; type Labelidx = U32Literal; - -type Index = +type Idx = | Typeidx | Funcidx | Tableidx | Memidx | Globalidx | Localidx - | Labelidx - | Identifier; // WAST shorthand + | Labelidx; type SignatureOrTypeRef = Index | Signature; diff --git a/packages/ast/src/types/nodes.js b/packages/ast/src/types/nodes.js index 7eb4e4057..8242e0c5e 100644 --- a/packages/ast/src/types/nodes.js +++ b/packages/ast/src/types/nodes.js @@ -43,7 +43,8 @@ type Node = | CallInstruction | CallIndirectInstruction | ByteArray - | Func; + | Func + | Index; type Block = LoopInstruction | BlockInstruction | Func; @@ -367,3 +368,10 @@ type Func = { isExternal?: boolean, metadata?: FuncMetadata }; + +type Index = { + ...BaseNode, + type: "Index", + index: ?Idx, + identifier: ?Identifier +}; diff --git a/packages/ast/test/traverse.js b/packages/ast/test/traverse.js index e8bd8ac9d..b8e5a4b33 100644 --- a/packages/ast/test/traverse.js +++ b/packages/ast/test/traverse.js @@ -292,7 +292,7 @@ describe("AST traverse", () => { it("should remove export in module", () => { const root = t.module("test", [ - t.moduleExport("a", t.moduleExportDescr("Func", t.indexLiteral(0))) + t.moduleExport("a", t.moduleExportDescr("Func", t.indexOfIndex(t.indexLiteral(0)))) ]); traverse(root, { diff --git a/packages/helper-code-frame/test/index.js b/packages/helper-code-frame/test/index.js index 4a8316493..bd3f112b5 100644 --- a/packages/helper-code-frame/test/index.js +++ b/packages/helper-code-frame/test/index.js @@ -8,7 +8,9 @@ const codeFrame = require("../lib").codeFrameFromAst; describe("code frame", () => { const m = t.program([ - t.module(null, [t.func(t.identifier("foo"), t.signature([], []), [])]) + t.module(null, [ + t.func(t.indexOfIdentifier(t.identifier("foo")), t.signature([], []), []) + ]) ]); it("should point to a location", () => { diff --git a/packages/wasm-edit/test/insert-node.js b/packages/wasm-edit/test/insert-node.js index 4f484ce7c..65ad8d671 100644 --- a/packages/wasm-edit/test/insert-node.js +++ b/packages/wasm-edit/test/insert-node.js @@ -195,7 +195,7 @@ describe("insert a node", () => { undefined, t.signature(func.signature.params, func.signature.results) ); - const funcindex = t.indexInFuncSection(t.indexLiteral(0)); + const funcindex = t.indexInFuncSection(t.indexOfIndex(t.indexLiteral(0))); it("should insert the node in existing sections", () => { const actual = makeBuffer( diff --git a/packages/wasm-gen/test/index.js b/packages/wasm-gen/test/index.js index fdd38cf4b..0924be67e 100644 --- a/packages/wasm-gen/test/index.js +++ b/packages/wasm-gen/test/index.js @@ -92,19 +92,19 @@ const fixtures = [ { name: "(call 0)", - node: t.callInstruction(t.indexLiteral(0)), + node: t.callInstruction(t.indexOfIndex(t.indexLiteral(0))), expected: [0x10, 0x00] }, { name: "a CallIndirectInstruction", - node: callIndirectInstructionIndex(t.indexLiteral(10)), + node: callIndirectInstructionIndex(t.indexOfIndex(t.indexLiteral(10))), expected: [0x11, 0x0a, 0x00] }, { name: '(export "a" (func 1))', - node: t.moduleExport("a", t.moduleExportDescr("Func", t.indexLiteral(1))), + node: t.moduleExport("a", t.moduleExportDescr("Func", t.indexOfIndex(t.indexLiteral(1)))), expected: [0x01, 0x61, 0x00, 0x01] }, @@ -208,7 +208,7 @@ const fixtures = [ { name: "(elem 1 (i32.const 2) 3 4)", node: t.elem( - t.numberLiteralFromRaw(1), + t.indexOfIndex(t.numberLiteralFromRaw(1)), [t.objectInstruction("const", "i32", [t.numberLiteralFromRaw(2)])], [t.numberLiteralFromRaw(3), t.numberLiteralFromRaw(4)] ), diff --git a/packages/wasm-parser/src/decoder.js b/packages/wasm-parser/src/decoder.js index 11e6e044c..37805c69e 100644 --- a/packages/wasm-parser/src/decoder.js +++ b/packages/wasm-parser/src/decoder.js @@ -1315,7 +1315,9 @@ export function decode(ab: ArrayBuffer, opts: DecoderOpts): Program { const endLoc = getPosition(); - return t.withLoc(t.start(t.indexLiteral(startFuncIndex)), endLoc, startLoc); + const index = t.indexOfIndex(t.numberLiteralFromRaw(startFuncIndex)); + + return t.withLoc(t.start(index), endLoc, startLoc); } // https://webassembly.github.io/spec/binary/modules.html#data-section diff --git a/packages/wast-parser/src/grammar.js b/packages/wast-parser/src/grammar.js index 48a8eb81e..62ecc68f1 100644 --- a/packages/wast-parser/src/grammar.js +++ b/packages/wast-parser/src/grammar.js @@ -1291,7 +1291,7 @@ export function parse(tokensList: Array, source: string): Program { } return t.func( - fnName, + t.indexOfIdentifier(fnName), typeRef !== undefined ? typeRef : t.signature(fnParams, fnResult), fnBody ); @@ -1655,14 +1655,14 @@ export function parse(tokensList: Array, source: string): Program { */ function parseStart(): Start { if (token.type === tokens.identifier) { - const index = identifierFromToken(token); + const index = t.indexOfIdentifier(identifierFromToken(token)); eatToken(); return t.start(index); } if (token.type === tokens.number) { - const index = t.indexLiteral(token.value); + const index = t.indexOfIndex(t.numberLiteralFromRaw(token.value)); eatToken(); return t.start(index); diff --git a/packages/wast-parser/test/fixtures/start/expected.json b/packages/wast-parser/test/fixtures/start/expected.json index 9c3444027..c56773878 100644 --- a/packages/wast-parser/test/fixtures/start/expected.json +++ b/packages/wast-parser/test/fixtures/start/expected.json @@ -41,16 +41,20 @@ { "type": "Start", "index": { - "type": "Identifier", - "value": "fn", - "loc": { - "start": { - "line": 3, - "column": 9 - }, - "end": { - "line": 3, - "column": 12 + "type": "Index", + "index": null, + "identifier": { + "type": "Identifier", + "value": "fn", + "loc": { + "start": { + "line": 3, + "column": 9 + }, + "end": { + "line": 3, + "column": 12 + } } } }, diff --git a/packages/wast-printer/src/index.js b/packages/wast-printer/src/index.js index 5543e32cb..6bc93ce0f 100644 --- a/packages/wast-printer/src/index.js +++ b/packages/wast-printer/src/index.js @@ -2,6 +2,8 @@ import Long from "long"; import { isAnonymous, isInstruction } from "@webassemblyjs/ast"; +import { printIndex } from "./nodes/Index"; + const compact = false; const space = " "; const quote = str => `"${str}"`; @@ -942,16 +944,6 @@ function printIdentifier(n: Identifier): string { return "$" + n.value; } -function printIndex(n: Index): string { - if (n.type === "Identifier") { - return printIdentifier(n); - } else if (n.type === "NumberLiteral") { - return printNumberLiteral(n); - } else { - throw new Error("Unsupported index: " + n.type); - } -} - function printMemory(n: Memory): string { let out = ""; out += "("; diff --git a/packages/wast-printer/src/nodes/Index.js b/packages/wast-printer/src/nodes/Index.js new file mode 100644 index 000000000..c74e285cb --- /dev/null +++ b/packages/wast-printer/src/nodes/Index.js @@ -0,0 +1,13 @@ +// @flow + +export function printIndex(n: Index): string { + if (typeof n.identifier === "object") { + return printIdentifier(n.identifier); + } + + if (typeof n.index === "object") { + return printNumberLiteral(n.index); + } + + throw new Error("Unsupported index: " + n.type); +} diff --git a/packages/webassemblyjs/test/interpreter/runtime/values.js b/packages/webassemblyjs/test/interpreter/runtime/values.js index 9ff69c2eb..a9b4c08af 100644 --- a/packages/webassemblyjs/test/interpreter/runtime/values.js +++ b/packages/webassemblyjs/test/interpreter/runtime/values.js @@ -34,10 +34,14 @@ describe("module create interface", () => { const exportName = "foo"; const node = t.module(null, [ - t.func(t.identifier(exportName), t.signature([], []), []), + t.func( + t.indexOfIdentifier(t.identifier(exportName)), + t.signature([], []), + [] + ), t.moduleExport( exportName, - t.moduleExportDescr("Func", t.identifier(exportName)) + t.moduleExportDescr("Func", t.indexOfIdentifier(t.identifier(exportName))) ) ]);