#include "wat-parser.h"
#include "contexts.h"
#include "ir/names.h"
#include "lexer.h"
#include "parsers.h"
#include "pass.h"
#include "wasm-type.h"
#include "wasm.h"
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;
}
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) {
struct Propagator : WalkerPass<ExpressionStackWalker<Propagator>> {
using Super = WalkerPass<ExpressionStackWalker<Propagator>>;
bool isFunctionParallel() override { return true; }
bool modifiesBinaryenIR() override { return false; }
bool requiresNonNullableLocalFixups() override { return false; }
void runOnFunction(Module* module, Function* func) override {
if (!func->debugLocations.empty()) {
Super::runOnFunction(module, func);
}
}
std::unordered_map<Expression*, Function::DebugLocation> parentDefaults;
static void doPreVisit(Propagator* self, Expression** currp) {
Super::doPreVisit(self, currp);
auto* curr = *currp;
auto& locs = self->getFunction()->debugLocations;
auto& parentDefaults = self->parentDefaults;
if (auto it = locs.find(curr); it != locs.end()) {
parentDefaults[curr] = it->second;
if (auto* parent = self->getParent()) {
parentDefaults[parent] = it->second;
}
} else {
if (auto* parent = self->getParent()) {
if (auto defaultIt = parentDefaults.find(parent);
defaultIt != parentDefaults.end()) {
locs[curr] = parentDefaults[curr] = defaultIt->second;
}
}
}
}
std::unique_ptr<Pass> create() override {
return std::make_unique<Propagator>();
}
};
PassRunner runner(&wasm);
runner.add(std::make_unique<Propagator>());
runner.run();
}
}
Result<> parseModule(Module& wasm, std::string_view input) {
ParseDeclsCtx decls(input, wasm);
CHECK_ERR(module(decls));
if (!decls.in.empty()) {
return decls.in.err("Unexpected tokens after module");
}
auto typeIndices = createIndexMap(decls.in, decls.subtypeDefs);
CHECK_ERR(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;
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});
}
}
}
}
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));
}
}
{
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));
}
{
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()) {
CHECK_ERR(ctx.irBuilder.visitEnd());
}
}
for (auto pos : decls.exportDefs) {
WithPosition with(ctx, pos);
auto parsed = export_(ctx);
CHECK_ERR(parsed);
assert(parsed);
}
}
propagateDebugLocations(wasm);
return Ok{};
}
}