/* * 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 "contexts.h" namespace wasm::WATParser { namespace { void applyImportNames(Importable& item, ImportNames* names) { if (names) { item.module = names->mod; item.base = names->nm; } } Result<> addExports(Lexer& in, Module& wasm, const Named* item, const std::vector& exports, ExternalKind kind) { for (auto name : exports) { if (wasm.getExportOrNull(name)) { // TODO: Fix error location return in.err("repeated export name"); } wasm.addExport(Builder(wasm).makeExport(name, item->name, kind)); } return Ok{}; } } // anonymous namespace Result ParseDeclsCtx::addFuncDecl(Index pos, Name name, ImportNames* importNames) { auto f = std::make_unique(); if (name.is()) { if (wasm.getFunctionOrNull(name)) { // TDOO: if the existing function is not explicitly named, fix its name // and continue. return in.err(pos, "repeated function name"); } f->setExplicitName(name); } else { name = (importNames ? "fimport$" : "") + std::to_string(funcCounter++); name = Names::getValidFunctionName(wasm, name); f->name = name; } applyImportNames(*f, importNames); return wasm.addFunction(std::move(f)); } Result<> ParseDeclsCtx::addFunc(Name name, const std::vector& exports, ImportNames* import, TypeUseT type, std::optional, std::vector&& annotations, Index pos) { CHECK_ERR(checkImport(pos, import)); auto f = addFuncDecl(pos, name, import); CHECK_ERR(f); CHECK_ERR(addExports(in, wasm, *f, exports, ExternalKind::Function)); funcDefs.push_back( {name, pos, Index(funcDefs.size()), std::move(annotations)}); return Ok{}; } Result ParseDeclsCtx::addTableDecl(Index pos, Name name, ImportNames* importNames, TableType type) { auto t = std::make_unique(); t->addressType = type.addressType; t->initial = type.limits.initial; t->max = type.limits.max ? *type.limits.max : Table::kUnlimitedSize; if (name.is()) { if (wasm.getTableOrNull(name)) { // TODO: if the existing table is not explicitly named, fix its name and // continue. return in.err(pos, "repeated table name"); } t->setExplicitName(name); } else { name = (importNames ? "timport$" : "") + std::to_string(tableCounter++); name = Names::getValidTableName(wasm, name); t->name = name; } applyImportNames(*t, importNames); return wasm.addTable(std::move(t)); } Result<> ParseDeclsCtx::addTable(Name name, const std::vector& exports, ImportNames* import, TableType type, Index pos) { CHECK_ERR(checkImport(pos, import)); auto t = addTableDecl(pos, name, import, type); CHECK_ERR(t); CHECK_ERR(addExports(in, wasm, *t, exports, ExternalKind::Table)); // TODO: table annotations tableDefs.push_back({name, pos, Index(tableDefs.size()), {}}); return Ok{}; } Result<> ParseDeclsCtx::addImplicitElems(TypeT, ElemListT&& elems) { auto& table = *wasm.tables.back(); auto e = std::make_unique(); e->table = table.name; e->offset = Builder(wasm).makeConstPtr(0, Type::i32); e->name = Names::getValidElementSegmentName(wasm, "implicit-elem"); wasm.addElementSegment(std::move(e)); // Record the index mapping so we can find this segment again to set its type // and elements in later phases. Index tableIndex = wasm.tables.size() - 1; Index elemIndex = wasm.elementSegments.size() - 1; implicitElemIndices[tableIndex] = elemIndex; return Ok{}; } Result ParseDeclsCtx::addMemoryDecl(Index pos, Name name, ImportNames* importNames, MemType type) { auto m = std::make_unique(); m->addressType = type.addressType; m->initial = type.limits.initial; m->max = type.limits.max ? *type.limits.max : Memory::kUnlimitedSize; m->shared = type.shared; if (name) { // TODO: if the existing memory is not explicitly named, fix its name // and continue. if (wasm.getMemoryOrNull(name)) { return in.err(pos, "repeated memory name"); } m->setExplicitName(name); } else { name = (importNames ? "mimport$" : "") + std::to_string(memoryCounter++); name = Names::getValidMemoryName(wasm, name); m->name = name; } applyImportNames(*m, importNames); return wasm.addMemory(std::move(m)); } Result<> ParseDeclsCtx::addMemory(Name name, const std::vector& exports, ImportNames* import, MemType type, Index pos) { CHECK_ERR(checkImport(pos, import)); auto m = addMemoryDecl(pos, name, import, type); CHECK_ERR(m); CHECK_ERR(addExports(in, wasm, *m, exports, ExternalKind::Memory)); // TODO: memory annotations memoryDefs.push_back({name, pos, Index(memoryDefs.size()), {}}); return Ok{}; } Result<> ParseDeclsCtx::addImplicitData(DataStringT&& data) { auto& mem = *wasm.memories.back(); auto d = std::make_unique(); d->memory = mem.name; d->isPassive = false; d->offset = Builder(wasm).makeConstPtr(0, mem.addressType); d->data = std::move(data); d->name = Names::getValidDataSegmentName(wasm, "implicit-data"); wasm.addDataSegment(std::move(d)); return Ok{}; } Result ParseDeclsCtx::addGlobalDecl(Index pos, Name name, ImportNames* importNames) { auto g = std::make_unique(); if (name) { if (wasm.getGlobalOrNull(name)) { // TODO: if the existing global is not explicitly named, fix its name // and continue. return in.err(pos, "repeated global name"); } g->setExplicitName(name); } else { name = (importNames ? "gimport$" : "global$") + std::to_string(globalCounter++); name = Names::getValidGlobalName(wasm, name); g->name = name; } applyImportNames(*g, importNames); return wasm.addGlobal(std::move(g)); } Result<> ParseDeclsCtx::addGlobal(Name name, const std::vector& exports, ImportNames* import, GlobalTypeT, std::optional, Index pos) { CHECK_ERR(checkImport(pos, import)); auto g = addGlobalDecl(pos, name, import); CHECK_ERR(g); CHECK_ERR(addExports(in, wasm, *g, exports, ExternalKind::Global)); // TODO: global annotations globalDefs.push_back({name, pos, Index(globalDefs.size()), {}}); return Ok{}; } Result<> ParseDeclsCtx::addElem( Name name, TableIdxT*, std::optional, ElemListT&&, Index pos) { auto e = std::make_unique(); if (name) { if (wasm.getElementSegmentOrNull(name)) { // TDOO: if the existing segment is not explicitly named, fix its name and // continue. return in.err(pos, "repeated element segment name"); } e->setExplicitName(name); } else { name = std::to_string(elemCounter++); name = Names::getValidElementSegmentName(wasm, name); e->name = name; } // TODO: element segment annotations elemDefs.push_back({name, pos, Index(wasm.elementSegments.size()), {}}); wasm.addElementSegment(std::move(e)); return Ok{}; } Result<> ParseDeclsCtx::addData(Name name, MemoryIdxT*, std::optional, std::vector&& data, Index pos) { auto d = std::make_unique(); if (name) { if (wasm.getDataSegmentOrNull(name)) { // TODO: if the existing segment is not explicitly named, fix its name // and continue. return in.err(pos, "repeated data segment name"); } d->setExplicitName(name); } else { name = std::to_string(dataCounter++); name = Names::getValidDataSegmentName(wasm, name); d->name = name; } d->data = std::move(data); // TODO: data segment annotations dataDefs.push_back({name, pos, Index(wasm.dataSegments.size()), {}}); wasm.addDataSegment(std::move(d)); return Ok{}; } Result ParseDeclsCtx::addTagDecl(Index pos, Name name, ImportNames* importNames) { auto t = std::make_unique(); if (name) { if (wasm.getTagOrNull(name)) { // TODO: if the existing tag is not explicitly named, fix its name and // continue. return in.err(pos, "repeated tag name"); } t->setExplicitName(name); } else { name = (importNames ? "eimport$" : "tag$") + std::to_string(tagCounter++); name = Names::getValidTagName(wasm, name); t->name = name; } applyImportNames(*t, importNames); return wasm.addTag(std::move(t)); } Result<> ParseDeclsCtx::addTag(Name name, const std::vector& exports, ImportNames* import, TypeUseT type, Index pos) { CHECK_ERR(checkImport(pos, import)); auto t = addTagDecl(pos, name, import); CHECK_ERR(t); CHECK_ERR(addExports(in, wasm, *t, exports, ExternalKind::Tag)); // TODO: tag annotations tagDefs.push_back({name, pos, Index(tagDefs.size()), {}}); return Ok{}; } } // namespace wasm::WATParser