/* * When naming an anonymous function, the process works loosely by walking * up the AST and then translating that to a string. The stringification * happens from some far-up assignment and then going back down the parse * tree to the function definition point. * * This function will walk up the parse tree, gathering relevant nodes used * for naming, and return the assignment node if there is one. The provided * array and size will be filled in, and the returned node could be NULL if * no assignment is found. The first element of the array will be the * innermost node relevant to naming, and the last element will be the * outermost node. */ ParseNode *gatherNameable(ParseNode **nameable, size_t *size) { *size = 0; for (int pos = nparents - 1; pos >= 0; pos--) { ParseNode *cur = parents[pos]; if (cur->isAssignment()) return cur; switch (cur->getKind()) { case PNK_NAME: return cur; /* found the initialized declaration */ case PNK_FUNCTION: return NULL; /* won't find an assignment or declaration */ case PNK_RETURN: /* * Normally the relevant parent of a node is its direct parent, but * sometimes with code like: * * var foo = (function() { return function() {}; })(); * * the outer function is just a helper to create a scope for the * returned function. Hence the name of the returned function should * actually be 'foo'. This loop sees if the current node is a * PNK_RETURN, and if there is a direct function call we skip to * that. */ for (int tmp = pos - 1; tmp > 0; tmp--) { if (isDirectCall(tmp, cur)) { pos = tmp; break; } else if (call(cur)) { /* Don't skip too high in the tree */ break; } cur = parents[tmp]; } break; case PNK_COLON: /* * If this is a PNK_COLON, but our parent is not a PNK_OBJECT, * then this is a label and we're done naming. Otherwise we * record the PNK_COLON but skip the PNK_OBJECT so we're not * flagged as a contributor. */ if (pos == 0 || !parents[pos - 1]->isKind(PNK_OBJECT)) return NULL; pos--; /* fallthrough */ /* Save any other nodes we encounter on the way up. */ default: JS_ASSERT(*size < MaxParents); nameable[(*size)++] = cur; break; } } return NULL; }
bool ModuleBuilder::processExport(frontend::ParseNode* pn) { MOZ_ASSERT(pn->isArity(PN_UNARY)); ParseNode* kid = pn->pn_kid; bool isDefault = pn->getKind() == PNK_EXPORT_DEFAULT; switch (kid->getKind()) { case PNK_EXPORT_SPEC_LIST: MOZ_ASSERT(!isDefault); for (ParseNode* spec = kid->pn_head; spec; spec = spec->pn_next) { MOZ_ASSERT(spec->isKind(PNK_EXPORT_SPEC)); RootedAtom localName(cx_, spec->pn_left->pn_atom); RootedAtom exportName(cx_, spec->pn_right->pn_atom); if (!appendLocalExportEntry(exportName, localName)) return false; } break; case PNK_FUNCTION: { RootedFunction func(cx_, kid->pn_funbox->function()); RootedAtom localName(cx_, func->atom()); RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get()); if (!appendLocalExportEntry(exportName, localName)) return false; break; } case PNK_CLASS: { const ClassNode& cls = kid->as<ClassNode>(); MOZ_ASSERT(cls.names()); RootedAtom localName(cx_, cls.names()->innerBinding()->pn_atom); RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get()); if (!appendLocalExportEntry(exportName, localName)) return false; break; } case PNK_VAR: case PNK_CONST: case PNK_GLOBALCONST: case PNK_LET: { MOZ_ASSERT(kid->isArity(PN_LIST)); for (ParseNode* var = kid->pn_head; var; var = var->pn_next) { if (var->isKind(PNK_ASSIGN)) var = var->pn_left; MOZ_ASSERT(var->isKind(PNK_NAME)); RootedAtom localName(cx_, var->pn_atom); RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get()); if (!appendLocalExportEntry(exportName, localName)) return false; } break; } default: MOZ_ASSERT(isDefault); RootedAtom localName(cx_, cx_->names().starDefaultStar); RootedAtom exportName(cx_, cx_->names().default_); if (!appendLocalExportEntry(exportName, localName)) return false; break; } return true; }
bool ModuleBuilder::buildAndInit(frontend::ParseNode* moduleNode, HandleModuleObject module) { MOZ_ASSERT(moduleNode->isKind(PNK_MODULE)); ParseNode* stmtsNode = moduleNode->pn_expr; MOZ_ASSERT(stmtsNode->isKind(PNK_STATEMENTLIST)); MOZ_ASSERT(stmtsNode->isArity(PN_LIST)); for (ParseNode* pn = stmtsNode->pn_head; pn; pn = pn->pn_next) { switch (pn->getKind()) { case PNK_IMPORT: if (!processImport(pn)) return false; break; case PNK_EXPORT: case PNK_EXPORT_DEFAULT: if (!processExport(pn)) return false; break; case PNK_EXPORT_FROM: if (!processExportFrom(pn)) return false; break; default: break; } } for (const auto& e : exportEntries_) { RootedExportEntry exp(cx_, e); if (!exp->moduleRequest()) { RootedImportEntry importEntry(cx_, importEntryFor(exp->localName())); if (!importEntry) { if (!localExportEntries_.append(exp)) return false; } else { if (importEntry->importName() == cx_->names().star) { if (!localExportEntries_.append(exp)) return false; } else { RootedAtom exportName(cx_, exp->exportName()); RootedAtom moduleRequest(cx_, importEntry->moduleRequest()); RootedAtom importName(cx_, importEntry->importName()); RootedExportEntry exportEntry(cx_); exportEntry = ExportEntryObject::create(cx_, exportName, moduleRequest, importName, nullptr); if (!exportEntry || !indirectExportEntries_.append(exportEntry)) return false; } } } else if (exp->importName() == cx_->names().star) { if (!starExportEntries_.append(exp)) return false; } else { if (!indirectExportEntries_.append(exp)) return false; } } RootedArrayObject requestedModules(cx_, createArray<JSAtom*>(requestedModules_)); if (!requestedModules) return false; RootedArrayObject importEntries(cx_, createArray<ImportEntryObject*>(importEntries_)); if (!importEntries) return false; RootedArrayObject localExportEntries(cx_, createArray<ExportEntryObject*>(localExportEntries_)); if (!localExportEntries) return false; RootedArrayObject indirectExportEntries(cx_); indirectExportEntries = createArray<ExportEntryObject*>(indirectExportEntries_); if (!indirectExportEntries) return false; RootedArrayObject starExportEntries(cx_, createArray<ExportEntryObject*>(starExportEntries_)); if (!starExportEntries) return false; module->initImportExportData(requestedModules, importEntries, localExportEntries, indirectExportEntries, starExportEntries); return true; }