package com.oracle.js.parser;
import java.util.ArrayList;
import java.util.List;
import org.graalvm.collections.EconomicMap;
import org.graalvm.collections.EconomicSet;
import com.oracle.js.parser.ir.ExportNode;
import com.oracle.js.parser.ir.ExportSpecifierNode;
import com.oracle.js.parser.ir.ImportNode;
import com.oracle.js.parser.ir.Module;
import com.oracle.js.parser.ir.Module.ExportEntry;
import com.oracle.js.parser.ir.Module.ImportEntry;
import com.oracle.js.parser.ir.Scope;
class ParserContextModuleNode extends ParserContextBaseNode {
private final String name;
private final Scope moduleScope;
private final AbstractParser parser;
private List<String> requestedModules = new ArrayList<>();
private List<ImportEntry> importEntries = new ArrayList<>();
private List<ExportEntry> localExportEntries = new ArrayList<>();
private List<ExportEntry> indirectExportEntries = new ArrayList<>();
private List<ExportEntry> starExportEntries = new ArrayList<>();
private List<ImportNode> imports = new ArrayList<>();
private List<ExportNode> exports = new ArrayList<>();
private EconomicMap<String, ImportEntry> importedLocalNames = EconomicMap.create();
private EconomicSet<String> exportedNames = EconomicSet.create();
ParserContextModuleNode(final String name, Scope moduleScope, AbstractParser parser) {
this.name = name;
this.moduleScope = moduleScope;
this.parser = parser;
}
public String getModuleName() {
return name;
}
public void addImport(ImportNode importNode) {
imports.add(importNode);
}
public void addExport(ExportNode exportNode) {
exports.add(exportNode);
}
public void addModuleRequest(String moduleRequest) {
requestedModules.add(moduleRequest);
}
public void addImportEntry(ImportEntry importEntry) {
importEntries.add(importEntry);
importedLocalNames.put(importEntry.getLocalName(), importEntry);
}
public void addLocalExportEntry(long exportToken, ExportEntry exportEntry) {
localExportEntries.add(exportEntry);
addExportedName(exportToken, exportEntry);
if (!moduleScope.hasSymbol(exportEntry.getLocalName())) {
throw parser.error(AbstractParser.message("export.not.defined", exportEntry.getLocalName()), exportToken);
}
}
public void addIndirectExportEntry(long exportToken, ExportEntry exportEntry) {
indirectExportEntries.add(exportEntry);
addExportedName(exportToken, exportEntry);
}
public void addStarExportEntry(ExportEntry exportEntry) {
starExportEntries.add(exportEntry);
}
private void addExportedName(long exportToken, ExportEntry exportEntry) {
if (!exportedNames.add(exportEntry.getExportName())) {
throw parser.error(AbstractParser.message("duplicate.export", exportEntry.getExportName()), exportToken);
}
}
private void resolveExports() {
for (ExportNode export : exports) {
long exportToken = export.getToken();
if (export.getNamedExports() != null) {
assert export.getExportIdentifier() == null;
for (ExportSpecifierNode s : export.getNamedExports().getExportSpecifiers()) {
String localName = s.getIdentifier().getName();
ExportEntry ee;
if (s.getExportIdentifier() != null) {
ee = ExportEntry.exportSpecifier(s.getExportIdentifier().getName(), localName);
} else {
ee = ExportEntry.exportSpecifier(localName);
}
if (export.getFrom() == null) {
ImportEntry ie = importedLocalNames.get(localName);
if (ie == null) {
addLocalExportEntry(exportToken, ee);
} else if (ie.getImportName().equals(Module.STAR_NAME)) {
addLocalExportEntry(exportToken, ee);
} else {
addIndirectExportEntry(exportToken, ExportEntry.exportIndirect(ee.getExportName(), ie.getModuleRequest(), ie.getImportName()));
}
} else {
addIndirectExportEntry(exportToken, ee.withFrom(export.getFrom().getModuleSpecifier().getValue()));
}
}
} else if (export.getFrom() != null) {
String moduleRequest = export.getFrom().getModuleSpecifier().getValue();
if (export.getExportIdentifier() == null) {
addStarExportEntry(ExportEntry.exportStarFrom(moduleRequest));
} else {
addIndirectExportEntry(exportToken, ExportEntry.exportStarAsNamespaceFrom(export.getExportIdentifier().getName(), moduleRequest));
}
} else if (export.isDefault()) {
addLocalExportEntry(exportToken, ExportEntry.exportDefault(export.getExportIdentifier().getName()));
} else {
addLocalExportEntry(exportToken, ExportEntry.exportSpecifier(export.getExportIdentifier().getName()));
}
}
}
public Module createModule() {
resolveExports();
return new Module(requestedModules, importEntries, localExportEntries, indirectExportEntries, starExportEntries, imports, exports);
}
}