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> * @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 { public static final class ExportEntry {
private final String exportName; private final IdentNode exportName;
private final String moduleRequest; private final IdentNode moduleRequest;
private final String importName; private final IdentNode importName;
private final String localName; 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.exportName = exportName;
this.moduleRequest = moduleRequest; this.moduleRequest = moduleRequest;
this.importName = importName; this.importName = importName;
this.localName = localName; this.localName = localName;
this.startPosition = startPosition;
this.endPosition = endPosition;
} }
/** /**
* Creates a {@code export *} export entry. * Creates a {@code export *} export entry.
* *
* @param starName the star name
* @param moduleRequest the module request * @param moduleRequest the module request
* @param startPosition the start position
* @param endPosition the end position
* @return the export entry * @return the export entry
*/ */
public static ExportEntry exportStarFrom(final String moduleRequest) { public static ExportEntry exportStarFrom(final IdentNode starName, final IdentNode moduleRequest, final int startPosition, final int endPosition) {
return new ExportEntry(null, moduleRequest, STAR_NAME, null); return new ExportEntry(null, moduleRequest, starName, null, startPosition, endPosition);
}
/**
* Creates a {@code export default} export entry.
*
* @return the export entry
*/
public static ExportEntry exportDefault() {
return exportDefault(DEFAULT_EXPORT_BINDING_NAME);
} }
/** /**
* Creates a {@code export default} export entry with a local name. * Creates a {@code export default} export entry with a local name.
* *
* @param defaultName the default name
* @param localName the local name * @param localName the local name
* @param startPosition the start position
* @param endPosition the end position
* @return the export entry * @return the export entry
*/ */
public static ExportEntry exportDefault(final String localName) { public static ExportEntry exportDefault(final IdentNode defaultName, final IdentNode localName, final int startPosition, final int endPosition) {
return new ExportEntry(DEFAULT_NAME, null, null, localName); return new ExportEntry(defaultName, null, null, localName, startPosition, endPosition);
} }
/** /**
@ -93,30 +96,37 @@ public final class Module {
* *
* @param exportName the export name * @param exportName the export name
* @param localName the local name * @param localName the local name
* @param startPosition the start position
* @param endPosition the end position
* @return the export entry * @return the export entry
*/ */
public static ExportEntry exportSpecifier(final String exportName, final String localName) { public static ExportEntry exportSpecifier(final IdentNode exportName, final IdentNode localName, final int startPosition, final int endPosition) {
return new ExportEntry(exportName, null, null, localName); return new ExportEntry(exportName, null, null, localName, startPosition, endPosition);
} }
/** /**
* Creates a export entry with an export name. * Creates a export entry with an export name.
* *
* @param exportName the export name * @param exportName the export name
* @param startPosition the start position
* @param endPosition the end position
* @return the export entry * @return the export entry
*/ */
public static ExportEntry exportSpecifier(final String exportName) { public static ExportEntry exportSpecifier(final IdentNode exportName, final int startPosition, final int endPosition) {
return exportSpecifier(exportName, exportName); return exportSpecifier(exportName, exportName, startPosition, endPosition);
} }
/** /**
* Create a copy of this entry with the specified {@code module request} string. * Create a copy of this entry with the specified {@code module request} string.
* *
* @param moduleRequest the module request * @param moduleRequest the module request
* @param endPosition the new endPosition
* @return the new export entry * @return the new export entry
*/ */
public ExportEntry withFrom(@SuppressWarnings("hiding") final String moduleRequest) { public ExportEntry withFrom(@SuppressWarnings("hiding") final IdentNode moduleRequest, final int endPosition) {
return new ExportEntry(exportName, moduleRequest, localName, null); // 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 * @return the export name
*/ */
public String getExportName() { public IdentNode getExportName() {
return exportName; return exportName;
} }
@ -133,7 +143,7 @@ public final class Module {
* *
* @return the module request * @return the module request
*/ */
public String getModuleRequest() { public IdentNode getModuleRequest() {
return moduleRequest; return moduleRequest;
} }
@ -142,7 +152,7 @@ public final class Module {
* *
* @return the import name * @return the import name
*/ */
public String getImportName() { public IdentNode getImportName() {
return importName; return importName;
} }
@ -151,10 +161,28 @@ public final class Module {
* *
* @return the local name * @return the local name
*/ */
public String getLocalName() { public IdentNode getLocalName() {
return localName; 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 @Override
public String toString() { public String toString() {
return "ExportEntry [exportName=" + exportName + ", moduleRequest=" + moduleRequest + ", importName=" + importName + ", localName=" + localName + "]"; 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> * @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 { public static final class ImportEntry {
private final String moduleRequest; private final IdentNode moduleRequest;
private final String importName; private final IdentNode importName;
private final String localName; 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.moduleRequest = moduleRequest;
this.importName = importName; this.importName = importName;
this.localName = localName; this.localName = localName;
} this.startPosition = startPosition;
this.endPosition = endPosition;
/**
* 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);
} }
/** /**
@ -202,30 +216,35 @@ public final class Module {
* *
* @param importName the import name * @param importName the import name
* @param localName the local name * @param localName the local name
* @param startPosition the start position
* @param endPosition the end position
* @return the import entry * @return the import entry
*/ */
public static ImportEntry importSpecifier(final String importName, final String localName) { public static ImportEntry importSpecifier(final IdentNode importName, final IdentNode localName, final int startPosition, final int endPosition) {
return new ImportEntry(null, importName, localName); return new ImportEntry(null, importName, localName, startPosition, endPosition);
} }
/** /**
* Creates a new import entry with the given import name. * Creates a new import entry with the given import name.
* *
* @param importName the import name * @param importName the import name
* @param startPosition the start position
* @param endPosition the end position
* @return the import entry * @return the import entry
*/ */
public static ImportEntry importSpecifier(final String importName) { public static ImportEntry importSpecifier(final IdentNode importName, final int startPosition, final int endPosition) {
return importSpecifier(importName, importName); 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 moduleRequest the module request
* @param endPosition the new end position
* @return the new import entry * @return the new import entry
*/ */
public ImportEntry withFrom(@SuppressWarnings("hiding") final String moduleRequest) { public ImportEntry withFrom(@SuppressWarnings("hiding") final IdentNode moduleRequest, final int endPosition) {
return new ImportEntry(moduleRequest, importName, localName); return new ImportEntry(moduleRequest, importName, localName, startPosition, endPosition);
} }
/** /**
@ -233,7 +252,7 @@ public final class Module {
* *
* @return the module request * @return the module request
*/ */
public String getModuleRequest() { public IdentNode getModuleRequest() {
return moduleRequest; return moduleRequest;
} }
@ -242,7 +261,7 @@ public final class Module {
* *
* @return the import name * @return the import name
*/ */
public String getImportName() { public IdentNode getImportName() {
return importName; return importName;
} }
@ -251,10 +270,28 @@ public final class Module {
* *
* @return the local name * @return the local name
*/ */
public String getLocalName() { public IdentNode getLocalName() {
return localName; 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 @Override
public String toString() { public String toString() {
return "ImportEntry [moduleRequest=" + moduleRequest + ", importName=" + importName + ", localName=" + localName + "]"; return "ImportEntry [moduleRequest=" + moduleRequest + ", importName=" + importName + ", localName=" + localName + "]";

View File

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

View File

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