| /* | |
| * Copyright 2023 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.h" | |
| #include "contexts.h" | |
| #include "ir/names.h" | |
| #include "lexer.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 | |
| // to by index or by name. As a result, we need to parse text modules in | |
| // multiple phases. | |
| // | |
| // In the first phase, we find all of the module element declarations and | |
| // record, but do not interpret, the input spans of their corresponding | |
| // definitions. This phase establishes the indices and names of each module | |
| // element so that subsequent phases can look them up. | |
| // | |
| // The second phase parses type definitions to construct the types used in the | |
| // module. This has to be its own phase because we have no way to refer to a | |
| // type before it has been built along with all the other types, unlike for | |
| // other module elements that can be referred to by name before their | |
| // definitions have been parsed. | |
| // | |
| // The third phase further parses and constructs types implicitly defined by | |
| // type uses in functions, blocks, and call_indirect instructions. These | |
| // implicitly defined types may be referred to by index elsewhere. | |
| // | |
| // The fourth phase parses and sets the types of globals, functions, and other | |
| // top-level module elements. These types need to be set before we parse | |
| // instructions because they determine the types of instructions such as | |
| // global.get and ref.func. | |
| // | |
| // The fifth and final phase parses the remaining contents of all module | |
| // elements, including instructions. | |
| // | |
| // Each phase of parsing gets its own context type that is passed to the | |
| // individual parsing functions. There is a parsing function for each element of | |
| // the grammar given in the spec. Parsing functions are templatized so that they | |
| // may be passed the appropriate context type and return the correct result type | |
| // for each phase. | |
| namespace wasm::WATParser { | |
| namespace { | |
| Result<IndexMap> createIndexMap(Lexer& in, const std::vector<DefPos>& defs) { | |
| IndexMap indices; | |
| for (auto& def : defs) { | |
| if (def.name.is()) { | |
| if (!indices.insert({def.name, def.index}).second) { | |
| return in.err(def.pos, "duplicate element name"); | |
| } | |
| } | |
| } | |
| return indices; | |
| } | |
| void propagateDebugLocations(Module& wasm) { | |
| // Copy debug locations from parents or previous siblings to expressions that | |
| // do not already have their own debug locations. | |
| PassRunner runner(&wasm); | |
| runner.add("propagate-debug-locs"); | |
| // The parser should not be responsible for validation. | |
| runner.setIsNested(true); | |
| runner.run(); | |
| } | |
| // After doing the initial pass, parse types, imports, etc. | |
| Result<> parseModuleWithDecls(ParseDeclsCtx& decls) { | |
| auto typeIndices = createIndexMap(decls.in, decls.typeDefs); | |
| CHECK_ERR(typeIndices); | |
| std::vector<HeapType> types; | |
| std::unordered_map<HeapType, std::unordered_map<Name, Index>> typeNames; | |
| CHECK_ERR(parseTypeDefs(decls, decls.in, *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, decls.in, *typeIndices, types, implicitTypes)); | |
| CHECK_ERR( | |
| parseModuleTypes(decls, decls.in, *typeIndices, types, implicitTypes)); | |
| CHECK_ERR(parseDefinitions( | |
| decls, decls.in, *typeIndices, types, implicitTypes, typeNames)); | |
| propagateDebugLocations(decls.wasm); | |
| return Ok{}; | |
| } | |
| Result<> doParseModule(Module& wasm, Lexer& input, bool allowExtra) { | |
| ParseDeclsCtx decls(input, wasm); | |
| CHECK_ERR(parseModule(decls)); | |
| if (!allowExtra && !decls.in.empty()) { | |
| return decls.in.err("Unexpected tokens after module"); | |
| } | |
| CHECK_ERR(parseModuleWithDecls(decls)); | |
| // decls / parseModule made a copy of `input`. Advance `input` past the parsed | |
| // module. | |
| input = decls.in; | |
| return Ok{}; | |
| } | |
| } // anonymous namespace | |
| Result<> parseModule(Module& wasm, | |
| std::string_view in, | |
| std::optional<std::string> filename) { | |
| Lexer lexer(in, filename); | |
| return doParseModule(wasm, lexer, /*allowExtra=*/false); | |
| } | |
| Result<> parseModule(Module& wasm, std::string_view in) { | |
| Lexer lexer(in); | |
| return doParseModule(wasm, lexer, /*allowExtra=*/false); | |
| } | |
| Result<> parseModule(Module& wasm, Lexer& lexer) { | |
| return doParseModule(wasm, lexer, /*allowExtra=*/true); | |
| } | |
| Result<> parseModuleBody(Module& wasm, Lexer& lexer) { | |
| ParseDeclsCtx decls(lexer, wasm); | |
| CHECK_ERR(parseModuleBody(decls)); | |
| CHECK_ERR(parseModuleWithDecls(decls)); | |
| // decls / parseModuleBody made a copy of `input`. Advance `input` past the | |
| // parsed module. | |
| lexer = decls.in; | |
| return Ok{}; | |
| } | |
| } // namespace wasm::WATParser |