8159220: Preserve position info in module import and export entries

Reviewed-by: sundar, lagergren
This commit is contained in:
Hannes Wallnöfer 2016-06-13 12:39:28 +02:00
parent 607cd7698d
commit cace72a5ad
3 changed files with 136 additions and 92 deletions

View File

@ -47,45 +47,48 @@ public final class Module {
* @see <a href="http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records">es6 modules</a>
*/
public static final class ExportEntry {
private final String exportName;
private final String moduleRequest;
private final String importName;
private final String localName;
private final IdentNode exportName;
private final IdentNode moduleRequest;
private final IdentNode importName;
private final IdentNode localName;
private ExportEntry(final String exportName, final String moduleRequest, final String importName, final String localName) {
private final int startPosition;
private final int endPosition;
private ExportEntry(final IdentNode exportName, final IdentNode moduleRequest, final IdentNode importName,
final IdentNode localName, final int startPosition, final int endPosition) {
this.exportName = exportName;
this.moduleRequest = moduleRequest;
this.importName = importName;
this.localName = localName;
this.startPosition = startPosition;
this.endPosition = endPosition;
}
/**
* Creates a {@code export *} export entry.
*
* @param starName the star name
* @param moduleRequest the module request
* @param startPosition the start position
* @param endPosition the end position
* @return the export entry
*/
public static ExportEntry exportStarFrom(final String moduleRequest) {
return new ExportEntry(null, moduleRequest, STAR_NAME, null);
}
/**
* Creates a {@code export default} export entry.
*
* @return the export entry
*/
public static ExportEntry exportDefault() {
return exportDefault(DEFAULT_EXPORT_BINDING_NAME);
public static ExportEntry exportStarFrom(final IdentNode starName, final IdentNode moduleRequest, final int startPosition, final int endPosition) {
return new ExportEntry(null, moduleRequest, starName, null, startPosition, endPosition);
}
/**
* Creates a {@code export default} export entry with a local name.
*
* @param defaultName the default name
* @param localName the local name
* @param startPosition the start position
* @param endPosition the end position
* @return the export entry
*/
public static ExportEntry exportDefault(final String localName) {
return new ExportEntry(DEFAULT_NAME, null, null, localName);
public static ExportEntry exportDefault(final IdentNode defaultName, final IdentNode localName, final int startPosition, final int endPosition) {
return new ExportEntry(defaultName, null, null, localName, startPosition, endPosition);
}
/**
@ -93,30 +96,37 @@ public final class Module {
*
* @param exportName the export name
* @param localName the local name
* @param startPosition the start position
* @param endPosition the end position
* @return the export entry
*/
public static ExportEntry exportSpecifier(final String exportName, final String localName) {
return new ExportEntry(exportName, null, null, localName);
public static ExportEntry exportSpecifier(final IdentNode exportName, final IdentNode localName, final int startPosition, final int endPosition) {
return new ExportEntry(exportName, null, null, localName, startPosition, endPosition);
}
/**
* Creates a export entry with an export name.
*
* @param exportName the export name
* @param startPosition the start position
* @param endPosition the end position
* @return the export entry
*/
public static ExportEntry exportSpecifier(final String exportName) {
return exportSpecifier(exportName, exportName);
public static ExportEntry exportSpecifier(final IdentNode exportName, final int startPosition, final int endPosition) {
return exportSpecifier(exportName, exportName, startPosition, endPosition);
}
/**
* Create a copy of this entry with the specified {@code module request} string.
*
* @param moduleRequest the module request
* @param endPosition the new endPosition
* @return the new export entry
*/
public ExportEntry withFrom(@SuppressWarnings("hiding") final String moduleRequest) {
return new ExportEntry(exportName, moduleRequest, localName, null);
public ExportEntry withFrom(@SuppressWarnings("hiding") final IdentNode moduleRequest, final int endPosition) {
// Note that "from" moves localName to inputName, and localName becomes null
return new ExportEntry(exportName, moduleRequest, localName, null, startPosition, endPosition);
}
/**
@ -124,7 +134,7 @@ public final class Module {
*
* @return the export name
*/
public String getExportName() {
public IdentNode getExportName() {
return exportName;
}
@ -133,7 +143,7 @@ public final class Module {
*
* @return the module request
*/
public String getModuleRequest() {
public IdentNode getModuleRequest() {
return moduleRequest;
}
@ -142,7 +152,7 @@ public final class Module {
*
* @return the import name
*/
public String getImportName() {
public IdentNode getImportName() {
return importName;
}
@ -151,10 +161,28 @@ public final class Module {
*
* @return the local name
*/
public String getLocalName() {
public IdentNode getLocalName() {
return localName;
}
/**
* Returns the entry's start position.
*
* @return the start position
*/
public int getStartPosition() {
return startPosition;
}
/**
* Returns the entry's end position.
*
* @return the end position
*/
public int getEndPosition() {
return endPosition;
}
@Override
public String toString() {
return "ExportEntry [exportName=" + exportName + ", moduleRequest=" + moduleRequest + ", importName=" + importName + ", localName=" + localName + "]";
@ -167,34 +195,20 @@ public final class Module {
* @see <a href="http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records">es6 modules</a>
*/
public static final class ImportEntry {
private final String moduleRequest;
private final String importName;
private final String localName;
private final IdentNode moduleRequest;
private final IdentNode importName;
private final IdentNode localName;
private ImportEntry(final String moduleRequest, final String importName, final String localName) {
private final int startPosition;
private final int endPosition;
private ImportEntry(final IdentNode moduleRequest, final IdentNode importName, final IdentNode localName,
final int startPosition, final int endPosition) {
this.moduleRequest = moduleRequest;
this.importName = importName;
this.localName = localName;
}
/**
* Creates an import entry with default name.
*
* @param localName the local name
* @return the import entry
*/
public static ImportEntry importDefault(final String localName) {
return new ImportEntry(null, DEFAULT_NAME, localName);
}
/**
* Creates an import entry with {@code *} import name.
*
* @param localName the local name
* @return the import entry
*/
public static ImportEntry importStarAsNameSpaceFrom(final String localName) {
return new ImportEntry(null, STAR_NAME, localName);
this.startPosition = startPosition;
this.endPosition = endPosition;
}
/**
@ -202,30 +216,35 @@ public final class Module {
*
* @param importName the import name
* @param localName the local name
* @param startPosition the start position
* @param endPosition the end position
* @return the import entry
*/
public static ImportEntry importSpecifier(final String importName, final String localName) {
return new ImportEntry(null, importName, localName);
public static ImportEntry importSpecifier(final IdentNode importName, final IdentNode localName, final int startPosition, final int endPosition) {
return new ImportEntry(null, importName, localName, startPosition, endPosition);
}
/**
* Creates a new import entry with the given import name.
*
* @param importName the import name
* @param startPosition the start position
* @param endPosition the end position
* @return the import entry
*/
public static ImportEntry importSpecifier(final String importName) {
return importSpecifier(importName, importName);
public static ImportEntry importSpecifier(final IdentNode importName, final int startPosition, final int endPosition) {
return importSpecifier(importName, importName, startPosition, endPosition);
}
/**
* Returns a copy of this import entry with the given module request.
* Returns a copy of this import entry with the given module request and end position.
*
* @param moduleRequest the module request
* @param endPosition the new end position
* @return the new import entry
*/
public ImportEntry withFrom(@SuppressWarnings("hiding") final String moduleRequest) {
return new ImportEntry(moduleRequest, importName, localName);
public ImportEntry withFrom(@SuppressWarnings("hiding") final IdentNode moduleRequest, final int endPosition) {
return new ImportEntry(moduleRequest, importName, localName, startPosition, endPosition);
}
/**
@ -233,7 +252,7 @@ public final class Module {
*
* @return the module request
*/
public String getModuleRequest() {
public IdentNode getModuleRequest() {
return moduleRequest;
}
@ -242,7 +261,7 @@ public final class Module {
*
* @return the import name
*/
public String getImportName() {
public IdentNode getImportName() {
return importName;
}
@ -251,10 +270,28 @@ public final class Module {
*
* @return the local name
*/
public String getLocalName() {
public IdentNode getLocalName() {
return localName;
}
/**
* Returns the entry's start position.
*
* @return the start position
*/
public int getStartPosition() {
return startPosition;
}
/**
* Returns the entry's end position.
*
* @return the end position
*/
public int getEndPosition() {
return endPosition;
}
@Override
public String toString() {
return "ImportEntry [moduleRequest=" + moduleRequest + ", importName=" + importName + ", localName=" + localName + "]";

View File

@ -5138,32 +5138,33 @@ public class Parser extends AbstractParser implements Loggable {
* BindingIdentifier
*/
private void importDeclaration() {
final int startPosition = start;
expect(IMPORT);
final ParserContextModuleNode module = lc.getCurrentModule();
if (type == STRING || type == ESCSTRING) {
// import ModuleSpecifier ;
final String moduleSpecifier = (String) getValue();
final IdentNode moduleSpecifier = createIdentNode(token, finish, (String) getValue());
next();
module.addModuleRequest(moduleSpecifier);
} else {
// import ImportClause FromClause ;
List<Module.ImportEntry> importEntries;
if (type == MUL) {
importEntries = Collections.singletonList(nameSpaceImport());
importEntries = Collections.singletonList(nameSpaceImport(startPosition));
} else if (type == LBRACE) {
importEntries = namedImports();
importEntries = namedImports(startPosition);
} else if (isBindingIdentifier()) {
// ImportedDefaultBinding
final IdentNode importedDefaultBinding = bindingIdentifier("ImportedBinding");
Module.ImportEntry defaultImport = Module.ImportEntry.importDefault(importedDefaultBinding.getName());
Module.ImportEntry defaultImport = Module.ImportEntry.importSpecifier(importedDefaultBinding, startPosition, finish);
if (type == COMMARIGHT) {
next();
importEntries = new ArrayList<>();
if (type == MUL) {
importEntries.add(nameSpaceImport());
importEntries.add(nameSpaceImport(startPosition));
} else if (type == LBRACE) {
importEntries.addAll(namedImports());
importEntries.addAll(namedImports(startPosition));
} else {
throw error(AbstractParser.message("expected.named.import"));
}
@ -5174,10 +5175,10 @@ public class Parser extends AbstractParser implements Loggable {
throw error(AbstractParser.message("expected.import"));
}
final String moduleSpecifier = fromClause();
final IdentNode moduleSpecifier = fromClause();
module.addModuleRequest(moduleSpecifier);
for (int i = 0; i < importEntries.size(); i++) {
module.addImportEntry(importEntries.get(i).withFrom(moduleSpecifier));
module.addImportEntry(importEntries.get(i).withFrom(moduleSpecifier, finish));
}
}
expect(SEMICOLON);
@ -5187,10 +5188,12 @@ public class Parser extends AbstractParser implements Loggable {
* NameSpaceImport :
* * as ImportedBinding
*
* @param startPosition the start of the import declaration
* @return imported binding identifier
*/
private Module.ImportEntry nameSpaceImport() {
private Module.ImportEntry nameSpaceImport(final int startPosition) {
assert type == MUL;
final IdentNode starName = createIdentNode(Token.recast(token, IDENT), finish, Module.STAR_NAME);
next();
final long asToken = token;
final String as = (String) expectValue(IDENT);
@ -5198,7 +5201,7 @@ public class Parser extends AbstractParser implements Loggable {
throw error(AbstractParser.message("expected.as"), asToken);
}
final IdentNode localNameSpace = bindingIdentifier("ImportedBinding");
return Module.ImportEntry.importStarAsNameSpaceFrom(localNameSpace.getName());
return Module.ImportEntry.importSpecifier(starName, localNameSpace, startPosition, finish);
}
/**
@ -5215,7 +5218,7 @@ public class Parser extends AbstractParser implements Loggable {
* ImportedBinding :
* BindingIdentifier
*/
private List<Module.ImportEntry> namedImports() {
private List<Module.ImportEntry> namedImports(final int startPosition) {
assert type == LBRACE;
next();
List<Module.ImportEntry> importEntries = new ArrayList<>();
@ -5226,11 +5229,11 @@ public class Parser extends AbstractParser implements Loggable {
if (type == IDENT && "as".equals(getValue())) {
next();
final IdentNode localName = bindingIdentifier("ImportedBinding");
importEntries.add(Module.ImportEntry.importSpecifier(importName.getName(), localName.getName()));
importEntries.add(Module.ImportEntry.importSpecifier(importName, localName, startPosition, finish));
} else if (!bindingIdentifier) {
throw error(AbstractParser.message("expected.binding.identifier"), nameToken);
} else {
importEntries.add(Module.ImportEntry.importSpecifier(importName.getName()));
importEntries.add(Module.ImportEntry.importSpecifier(importName, startPosition, finish));
}
if (type == COMMARIGHT) {
next();
@ -5246,14 +5249,14 @@ public class Parser extends AbstractParser implements Loggable {
* FromClause :
* from ModuleSpecifier
*/
private String fromClause() {
private IdentNode fromClause() {
final long fromToken = token;
final String name = (String) expectValue(IDENT);
if (!"from".equals(name)) {
throw error(AbstractParser.message("expected.from"), fromToken);
}
if (type == STRING || type == ESCSTRING) {
final String moduleSpecifier = (String) getValue();
final IdentNode moduleSpecifier = createIdentNode(Token.recast(token, IDENT), finish, (String) getValue());
next();
return moduleSpecifier;
} else {
@ -5276,23 +5279,25 @@ public class Parser extends AbstractParser implements Loggable {
*/
private void exportDeclaration() {
expect(EXPORT);
final int startPosition = start;
final ParserContextModuleNode module = lc.getCurrentModule();
switch (type) {
case MUL: {
final IdentNode starName = createIdentNode(Token.recast(token, IDENT), finish, Module.STAR_NAME);
next();
final String moduleRequest = fromClause();
final IdentNode moduleRequest = fromClause();
expect(SEMICOLON);
module.addModuleRequest(moduleRequest);
module.addStarExportEntry(Module.ExportEntry.exportStarFrom(moduleRequest));
module.addStarExportEntry(Module.ExportEntry.exportStarFrom(starName, moduleRequest, startPosition, finish));
break;
}
case LBRACE: {
final List<Module.ExportEntry> exportEntries = exportClause();
final List<Module.ExportEntry> exportEntries = exportClause(startPosition);
if (type == IDENT && "from".equals(getValue())) {
final String moduleRequest = fromClause();
final IdentNode moduleRequest = fromClause();
module.addModuleRequest(moduleRequest);
for (Module.ExportEntry exportEntry : exportEntries) {
module.addIndirectExportEntry(exportEntry.withFrom(moduleRequest));
module.addIndirectExportEntry(exportEntry.withFrom(moduleRequest, finish));
}
} else {
for (Module.ExportEntry exportEntry : exportEntries) {
@ -5303,6 +5308,7 @@ public class Parser extends AbstractParser implements Loggable {
break;
}
case DEFAULT:
final IdentNode defaultName = createIdentNode(Token.recast(token, IDENT), finish, Module.DEFAULT_NAME);
next();
final Expression assignmentExpression;
IdentNode ident;
@ -5327,14 +5333,14 @@ public class Parser extends AbstractParser implements Loggable {
break;
}
if (ident != null) {
module.addLocalExportEntry(Module.ExportEntry.exportDefault(ident.getName()));
module.addLocalExportEntry(Module.ExportEntry.exportDefault(defaultName, ident, startPosition, finish));
} else {
ident = createIdentNode(Token.recast(rhsToken, IDENT), finish, Module.DEFAULT_EXPORT_BINDING_NAME);
lc.appendStatementToCurrentNode(new VarNode(lineNumber, Token.recast(rhsToken, LET), finish, ident, assignmentExpression));
if (!declaration) {
expect(SEMICOLON);
}
module.addLocalExportEntry(Module.ExportEntry.exportDefault());
module.addLocalExportEntry(Module.ExportEntry.exportDefault(defaultName, ident, startPosition, finish));
}
break;
case VAR:
@ -5345,18 +5351,18 @@ public class Parser extends AbstractParser implements Loggable {
variableStatement(type);
for (final Statement statement : statements.subList(previousEnd, statements.size())) {
if (statement instanceof VarNode) {
module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(((VarNode) statement).getName().getName()));
module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(((VarNode) statement).getName(), startPosition, finish));
}
}
break;
case CLASS: {
final ClassNode classDeclaration = classDeclaration(false);
module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(classDeclaration.getIdent().getName()));
module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(classDeclaration.getIdent(), startPosition, finish));
break;
}
case FUNCTION: {
final FunctionNode functionDeclaration = (FunctionNode) functionExpression(true, true);
module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(functionDeclaration.getIdent().getName()));
module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(functionDeclaration.getIdent(), startPosition, finish));
break;
}
default:
@ -5378,7 +5384,7 @@ public class Parser extends AbstractParser implements Loggable {
*
* @return a list of ExportSpecifiers
*/
private List<Module.ExportEntry> exportClause() {
private List<Module.ExportEntry> exportClause(final int startPosition) {
assert type == LBRACE;
next();
List<Module.ExportEntry> exports = new ArrayList<>();
@ -5387,9 +5393,9 @@ public class Parser extends AbstractParser implements Loggable {
if (type == IDENT && "as".equals(getValue())) {
next();
final IdentNode exportName = getIdentifierName();
exports.add(Module.ExportEntry.exportSpecifier(exportName.getName(), localName.getName()));
exports.add(Module.ExportEntry.exportSpecifier(exportName, localName, startPosition, finish));
} else {
exports.add(Module.ExportEntry.exportSpecifier(localName.getName()));
exports.add(Module.ExportEntry.exportSpecifier(localName, startPosition, finish));
}
if (type == COMMARIGHT) {
next();

View File

@ -28,6 +28,7 @@ package jdk.nashorn.internal.parser;
import java.util.ArrayList;
import java.util.List;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.Module;
import jdk.nashorn.internal.ir.Module.ExportEntry;
import jdk.nashorn.internal.ir.Module.ImportEntry;
@ -64,8 +65,8 @@ class ParserContextModuleNode extends ParserContextBaseNode {
return name;
}
public void addModuleRequest(final String moduleRequest) {
requestedModules.add(moduleRequest);
public void addModuleRequest(final IdentNode moduleRequest) {
requestedModules.add(moduleRequest.getName());
}
public void addImportEntry(final ImportEntry importEntry) {