diff options
-rw-r--r-- | src/parser/CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/parser/parse-1-decls.cpp | 23 | ||||
-rw-r--r-- | src/parser/parse-2-typedefs.cpp | 55 | ||||
-rw-r--r-- | src/parser/parse-3-implicit-types.cpp | 35 | ||||
-rw-r--r-- | src/parser/parse-4-module-types.cpp | 41 | ||||
-rw-r--r-- | src/parser/parse-5-defs.cpp | 95 | ||||
-rw-r--r-- | src/parser/parsers.h | 31 | ||||
-rw-r--r-- | src/parser/wat-parser-internal.h | 97 | ||||
-rw-r--r-- | src/parser/wat-parser.cpp | 154 |
9 files changed, 369 insertions, 167 deletions
diff --git a/src/parser/CMakeLists.txt b/src/parser/CMakeLists.txt index 9c54646e7..045948ba1 100644 --- a/src/parser/CMakeLists.txt +++ b/src/parser/CMakeLists.txt @@ -3,6 +3,11 @@ set(parser_SOURCES context-decls.cpp context-defs.cpp lexer.cpp + parse-1-decls.cpp + parse-2-typedefs.cpp + parse-3-implicit-types.cpp + parse-4-module-types.cpp + parse-5-defs.cpp wast-parser.cpp wat-parser.cpp ${parser_HEADERS} diff --git a/src/parser/parse-1-decls.cpp b/src/parser/parse-1-decls.cpp new file mode 100644 index 000000000..1c753cc61 --- /dev/null +++ b/src/parser/parse-1-decls.cpp @@ -0,0 +1,23 @@ +/* + * Copyright 2024 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wat-parser-internal.h" + +namespace wasm::WATParser { + +Result<> parseDecls(ParseDeclsCtx& decls) { return module(decls); } + +} // namespace wasm::WATParser diff --git a/src/parser/parse-2-typedefs.cpp b/src/parser/parse-2-typedefs.cpp new file mode 100644 index 000000000..90a84941d --- /dev/null +++ b/src/parser/parse-2-typedefs.cpp @@ -0,0 +1,55 @@ +/* + * Copyright 2024 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wat-parser-internal.h" + +namespace wasm::WATParser { + +Result<> parseTypeDefs( + ParseDeclsCtx& decls, + Lexer& input, + IndexMap& typeIndices, + std::vector<HeapType>& types, + std::unordered_map<HeapType, std::unordered_map<Name, Index>>& typeNames) { + TypeBuilder builder(decls.subtypeDefs.size()); + ParseTypeDefsCtx ctx(input, builder, typeIndices); + for (auto& typeDef : decls.typeDefs) { + WithPosition with(ctx, typeDef.pos); + CHECK_ERR(deftype(ctx)); + } + auto built = builder.build(); + if (auto* err = built.getError()) { + std::stringstream msg; + msg << "invalid type: " << err->reason; + return ctx.in.err(decls.typeDefs[err->index].pos, msg.str()); + } + types = *built; + // Record type names on the module and in typeNames. + for (size_t i = 0; i < types.size(); ++i) { + auto& names = ctx.names[i]; + auto& fieldNames = names.fieldNames; + if (names.name.is() || fieldNames.size()) { + decls.wasm.typeNames.insert({types[i], names}); + auto& fieldIdxMap = typeNames[types[i]]; + for (auto [idx, name] : fieldNames) { + fieldIdxMap.insert({name, idx}); + } + } + } + return Ok{}; +} + +} // namespace wasm::WATParser diff --git a/src/parser/parse-3-implicit-types.cpp b/src/parser/parse-3-implicit-types.cpp new file mode 100644 index 000000000..3a3a867e1 --- /dev/null +++ b/src/parser/parse-3-implicit-types.cpp @@ -0,0 +1,35 @@ +/* + * Copyright 2024 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wat-parser-internal.h" + +namespace wasm::WATParser { + +Result<> +parseImplicitTypeDefs(ParseDeclsCtx& decls, + Lexer& input, + IndexMap& typeIndices, + std::vector<HeapType>& types, + std::unordered_map<Index, HeapType>& implicitTypes) { + ParseImplicitTypeDefsCtx ctx(input, types, implicitTypes, typeIndices); + for (Index pos : decls.implicitTypeDefs) { + WithPosition with(ctx, pos); + CHECK_ERR(typeuse(ctx)); + } + return Ok{}; +} + +} // namespace wasm::WATParser diff --git a/src/parser/parse-4-module-types.cpp b/src/parser/parse-4-module-types.cpp new file mode 100644 index 000000000..04d8292d0 --- /dev/null +++ b/src/parser/parse-4-module-types.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2024 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wat-parser-internal.h" + +namespace wasm::WATParser { + +Result<> parseModuleTypes(ParseDeclsCtx& decls, + Lexer& input, + IndexMap& typeIndices, + std::vector<HeapType>& types, + std::unordered_map<Index, HeapType>& implicitTypes) { + ParseModuleTypesCtx ctx(input, + decls.wasm, + types, + implicitTypes, + decls.implicitElemIndices, + typeIndices); + CHECK_ERR(parseDefs(ctx, decls.funcDefs, func)); + CHECK_ERR(parseDefs(ctx, decls.tableDefs, table)); + CHECK_ERR(parseDefs(ctx, decls.memoryDefs, memory)); + CHECK_ERR(parseDefs(ctx, decls.globalDefs, global)); + CHECK_ERR(parseDefs(ctx, decls.elemDefs, elem)); + CHECK_ERR(parseDefs(ctx, decls.tagDefs, tag)); + return Ok{}; +} + +} // namespace wasm::WATParser diff --git a/src/parser/parse-5-defs.cpp b/src/parser/parse-5-defs.cpp new file mode 100644 index 000000000..acc81bb75 --- /dev/null +++ b/src/parser/parse-5-defs.cpp @@ -0,0 +1,95 @@ +/* + * Copyright 2024 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "wat-parser-internal.h" + +namespace wasm::WATParser { + +Result<> parseDefinitions( + ParseDeclsCtx& decls, + Lexer& input, + IndexMap& typeIndices, + std::vector<HeapType>& types, + std::unordered_map<Index, HeapType>& implicitTypes, + std::unordered_map<HeapType, std::unordered_map<Name, Index>>& typeNames) { + // Parse definitions. + // TODO: Parallelize this. + ParseDefsCtx ctx(input, + decls.wasm, + types, + implicitTypes, + typeNames, + decls.implicitElemIndices, + typeIndices); + CHECK_ERR(parseDefs(ctx, decls.tableDefs, table)); + CHECK_ERR(parseDefs(ctx, decls.globalDefs, global)); + CHECK_ERR(parseDefs(ctx, decls.startDefs, start)); + CHECK_ERR(parseDefs(ctx, decls.elemDefs, elem)); + CHECK_ERR(parseDefs(ctx, decls.dataDefs, data)); + + for (Index i = 0; i < decls.funcDefs.size(); ++i) { + ctx.index = i; + auto* f = decls.wasm.functions[i].get(); + WithPosition with(ctx, decls.funcDefs[i].pos); + ctx.setSrcLoc(decls.funcDefs[i].annotations); + if (!f->imported()) { + CHECK_ERR(ctx.visitFunctionStart(f)); + } + if (auto parsed = func(ctx)) { + CHECK_ERR(parsed); + } else { + auto im = import_(ctx); + assert(im); + CHECK_ERR(im); + } + if (!f->imported()) { + auto end = ctx.irBuilder.visitEnd(); + if (auto* err = end.getErr()) { + return ctx.in.err(decls.funcDefs[i].pos, err->msg); + } + } + } + + // Parse exports. + // TODO: It would be more technically correct to interleave these properly + // with the implicit inline exports in other module field definitions. + for (auto pos : decls.exportDefs) { + WithPosition with(ctx, pos); + auto parsed = export_(ctx); + CHECK_ERR(parsed); + assert(parsed); + } + return Ok{}; +} + +Result<Literal> parseConst(Lexer& lexer) { + Module wasm; + ParseDefsCtx ctx(lexer, wasm, {}, {}, {}, {}, {}); + auto inst = foldedinstr(ctx); + CHECK_ERR(inst); + auto expr = ctx.irBuilder.build(); + if (auto* err = expr.getErr()) { + return lexer.err(err->msg); + } + auto* e = *expr; + if (!e->is<Const>() && !e->is<RefNull>() && !e->is<RefI31>()) { + return lexer.err("expected constant"); + } + lexer = ctx.in; + return getLiteralFromConstExpression(e); +} + +} // namespace wasm::WATParser diff --git a/src/parser/parsers.h b/src/parser/parsers.h index ab990e7b0..c4eaf5fc6 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -20,6 +20,7 @@ #include "common.h" #include "contexts.h" #include "lexer.h" +#include "wat-parser-internal.h" namespace wasm::WATParser { @@ -350,32 +351,6 @@ template<typename Ctx> MaybeResult<> tag(Ctx&); template<typename Ctx> MaybeResult<> modulefield(Ctx&); template<typename Ctx> Result<> module(Ctx&); -// ========= -// Utilities -// ========= - -// RAII utility for temporarily changing the parsing position of a parsing -// context. -template<typename Ctx> struct WithPosition { - Ctx& ctx; - Index original; - std::vector<Annotation> annotations; - - WithPosition(Ctx& ctx, Index pos) - : ctx(ctx), original(ctx.in.getPos()), - annotations(ctx.in.takeAnnotations()) { - ctx.in.setPos(pos); - } - - ~WithPosition() { - ctx.in.setPos(original); - ctx.in.setAnnotations(std::move(annotations)); - } -}; - -// Deduction guide to satisfy -Wctad-maybe-unsupported. -template<typename Ctx> WithPosition(Ctx& ctx, Index) -> WithPosition<Ctx>; - // ===== // Types // ===== @@ -2699,7 +2674,7 @@ Result<typename Ctx::TypeUseT> typeuse(Ctx& ctx, bool allowNames) { } // ('(' 'import' mod:name nm:name ')')? -MaybeResult<ImportNames> inlineImport(Lexer& in) { +inline MaybeResult<ImportNames> inlineImport(Lexer& in) { if (!in.takeSExprStart("import"sv)) { return {}; } @@ -2719,7 +2694,7 @@ MaybeResult<ImportNames> inlineImport(Lexer& in) { } // ('(' 'export' name ')')* -Result<std::vector<Name>> inlineExports(Lexer& in) { +inline Result<std::vector<Name>> inlineExports(Lexer& in) { std::vector<Name> exports; while (in.takeSExprStart("export"sv)) { auto name = in.takeName(); diff --git a/src/parser/wat-parser-internal.h b/src/parser/wat-parser-internal.h new file mode 100644 index 000000000..00c96abd4 --- /dev/null +++ b/src/parser/wat-parser-internal.h @@ -0,0 +1,97 @@ +/* + * Copyright 2024 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "contexts.h" +#include "parsers.h" + +#ifndef parser_wat_parser_internal_h +#define parser_wat_parser_internal_h + +namespace wasm::WATParser { + +Result<> parseDecls(ParseDeclsCtx& decls); + +Result<> parseTypeDefs( + ParseDeclsCtx& decls, + Lexer& input, + IndexMap& typeIndices, + std::vector<HeapType>& types, + std::unordered_map<HeapType, std::unordered_map<Name, Index>>& typeNames); + +Result<> +parseImplicitTypeDefs(ParseDeclsCtx& decls, + Lexer& input, + IndexMap& typeIndices, + std::vector<HeapType>& types, + std::unordered_map<Index, HeapType>& implicitTypes); + +Result<> parseModuleTypes(ParseDeclsCtx& decls, + Lexer& input, + IndexMap& typeIndices, + std::vector<HeapType>& types, + std::unordered_map<Index, HeapType>& implicitTypes); + +Result<> parseDefinitions( + ParseDeclsCtx& decls, + Lexer& input, + IndexMap& typeIndices, + std::vector<HeapType>& types, + std::unordered_map<Index, HeapType>& implicitTypes, + std::unordered_map<HeapType, std::unordered_map<Name, Index>>& typeNames); + +// RAII utility for temporarily changing the parsing position of a parsing +// context. +template<typename Ctx> struct WithPosition { + Ctx& ctx; + Index original; + std::vector<Annotation> annotations; + + WithPosition(Ctx& ctx, Index pos) + : ctx(ctx), original(ctx.in.getPos()), + annotations(ctx.in.takeAnnotations()) { + ctx.in.setPos(pos); + } + + ~WithPosition() { + ctx.in.setPos(original); + ctx.in.setAnnotations(std::move(annotations)); + } +}; + +template<typename Ctx> +Result<> parseDefs(Ctx& ctx, + const std::vector<DefPos>& defs, + MaybeResult<> (*parser)(Ctx&)) { + for (auto& def : defs) { + ctx.index = def.index; + WithPosition with(ctx, def.pos); + if (auto parsed = parser(ctx)) { + CHECK_ERR(parsed); + } else { + auto im = import_(ctx); + assert(im); + CHECK_ERR(im); + } + } + return Ok{}; +} + +// Deduction guide to satisfy -Wctad-maybe-unsupported. +template<typename Ctx> WithPosition(Ctx& ctx, Index) -> WithPosition<Ctx>; + +} // namespace wasm::WATParser + +#endif // parser_wat_parser_internal_h diff --git a/src/parser/wat-parser.cpp b/src/parser/wat-parser.cpp index 4763c69ec..975cbd3c3 100644 --- a/src/parser/wat-parser.cpp +++ b/src/parser/wat-parser.cpp @@ -18,10 +18,10 @@ #include "contexts.h" #include "ir/names.h" #include "lexer.h" -#include "parsers.h" #include "pass.h" #include "wasm-type.h" #include "wasm.h" +#include "wat-parser-internal.h" // The WebAssembly text format is recursive in the sense that elements may be // referred to before they are declared. Furthermore, elements may be referred @@ -73,24 +73,6 @@ Result<IndexMap> createIndexMap(Lexer& in, const std::vector<DefPos>& defs) { return indices; } -template<typename Ctx> -Result<> parseDefs(Ctx& ctx, - const std::vector<DefPos>& defs, - MaybeResult<> (*parser)(Ctx&)) { - for (auto& def : defs) { - ctx.index = def.index; - WithPosition with(ctx, def.pos); - if (auto parsed = parser(ctx)) { - CHECK_ERR(parsed); - } else { - auto im = import_(ctx); - assert(im); - CHECK_ERR(im); - } - } - return Ok{}; -} - void propagateDebugLocations(Module& wasm) { // Copy debug locations from parents or previous siblings to expressions that // do not already have their own debug locations. @@ -101,10 +83,16 @@ void propagateDebugLocations(Module& wasm) { runner.run(); } +// Parse module-level declarations. + +// Parse type definitions. + +// Parse implicit type definitions and map typeuses without explicit types to +// the correct types. + Result<> doParseModule(Module& wasm, Lexer& input, bool allowExtra) { - // Parse module-level declarations. ParseDeclsCtx decls(input, wasm); - CHECK_ERR(module(decls)); + CHECK_ERR(parseDecls(decls)); if (!allowExtra && !decls.in.empty()) { return decls.in.err("Unexpected tokens after module"); } @@ -112,113 +100,18 @@ Result<> doParseModule(Module& wasm, Lexer& input, bool allowExtra) { auto typeIndices = createIndexMap(decls.in, decls.subtypeDefs); CHECK_ERR(typeIndices); - // Parse type definitions. std::vector<HeapType> types; std::unordered_map<HeapType, std::unordered_map<Name, Index>> typeNames; - { - TypeBuilder builder(decls.subtypeDefs.size()); - ParseTypeDefsCtx ctx(input, builder, *typeIndices); - for (auto& typeDef : decls.typeDefs) { - WithPosition with(ctx, typeDef.pos); - CHECK_ERR(deftype(ctx)); - } - auto built = builder.build(); - if (auto* err = built.getError()) { - std::stringstream msg; - msg << "invalid type: " << err->reason; - return ctx.in.err(decls.typeDefs[err->index].pos, msg.str()); - } - types = *built; - // Record type names on the module and in typeNames. - for (size_t i = 0; i < types.size(); ++i) { - auto& names = ctx.names[i]; - auto& fieldNames = names.fieldNames; - if (names.name.is() || fieldNames.size()) { - wasm.typeNames.insert({types[i], names}); - auto& fieldIdxMap = typeNames[types[i]]; - for (auto [idx, name] : fieldNames) { - fieldIdxMap.insert({name, idx}); - } - } - } - } + CHECK_ERR(parseTypeDefs(decls, input, *typeIndices, types, typeNames)); - // Parse implicit type definitions and map typeuses without explicit types to - // the correct types. std::unordered_map<Index, HeapType> implicitTypes; + CHECK_ERR( + parseImplicitTypeDefs(decls, input, *typeIndices, types, implicitTypes)); - { - ParseImplicitTypeDefsCtx ctx(input, types, implicitTypes, *typeIndices); - for (Index pos : decls.implicitTypeDefs) { - WithPosition with(ctx, pos); - CHECK_ERR(typeuse(ctx)); - } - } - - { - // Parse module-level types. - ParseModuleTypesCtx ctx(input, - wasm, - types, - implicitTypes, - decls.implicitElemIndices, - *typeIndices); - CHECK_ERR(parseDefs(ctx, decls.funcDefs, func)); - CHECK_ERR(parseDefs(ctx, decls.tableDefs, table)); - CHECK_ERR(parseDefs(ctx, decls.memoryDefs, memory)); - CHECK_ERR(parseDefs(ctx, decls.globalDefs, global)); - CHECK_ERR(parseDefs(ctx, decls.elemDefs, elem)); - CHECK_ERR(parseDefs(ctx, decls.tagDefs, tag)); - } - { - // Parse definitions. - // TODO: Parallelize this. - ParseDefsCtx ctx(input, - wasm, - types, - implicitTypes, - typeNames, - decls.implicitElemIndices, - *typeIndices); - CHECK_ERR(parseDefs(ctx, decls.tableDefs, table)); - CHECK_ERR(parseDefs(ctx, decls.globalDefs, global)); - CHECK_ERR(parseDefs(ctx, decls.startDefs, start)); - CHECK_ERR(parseDefs(ctx, decls.elemDefs, elem)); - CHECK_ERR(parseDefs(ctx, decls.dataDefs, data)); - - for (Index i = 0; i < decls.funcDefs.size(); ++i) { - ctx.index = i; - auto* f = wasm.functions[i].get(); - WithPosition with(ctx, decls.funcDefs[i].pos); - ctx.setSrcLoc(decls.funcDefs[i].annotations); - if (!f->imported()) { - CHECK_ERR(ctx.visitFunctionStart(f)); - } - if (auto parsed = func(ctx)) { - CHECK_ERR(parsed); - } else { - auto im = import_(ctx); - assert(im); - CHECK_ERR(im); - } - if (!f->imported()) { - auto end = ctx.irBuilder.visitEnd(); - if (auto* err = end.getErr()) { - return ctx.in.err(decls.funcDefs[i].pos, err->msg); - } - } - } + CHECK_ERR(parseModuleTypes(decls, input, *typeIndices, types, implicitTypes)); - // Parse exports. - // TODO: It would be more technically correct to interleave these properly - // with the implicit inline exports in other module field definitions. - for (auto pos : decls.exportDefs) { - WithPosition with(ctx, pos); - auto parsed = export_(ctx); - CHECK_ERR(parsed); - assert(parsed); - } - } + CHECK_ERR(parseDefinitions( + decls, input, *typeIndices, types, implicitTypes, typeNames)); propagateDebugLocations(wasm); input = decls.in; @@ -237,21 +130,4 @@ Result<> parseModule(Module& wasm, Lexer& lexer) { return doParseModule(wasm, lexer, true); } -Result<Literal> parseConst(Lexer& lexer) { - Module wasm; - ParseDefsCtx ctx(lexer, wasm, {}, {}, {}, {}, {}); - auto inst = foldedinstr(ctx); - CHECK_ERR(inst); - auto expr = ctx.irBuilder.build(); - if (auto* err = expr.getErr()) { - return lexer.err(err->msg); - } - auto* e = *expr; - if (!e->is<Const>() && !e->is<RefNull>() && !e->is<RefI31>()) { - return lexer.err("expected constant"); - } - lexer = ctx.in; - return getLiteralFromConstExpression(e); -} - } // namespace wasm::WATParser |