8032068: implement @sourceURL and #sourceURL directives
Reviewed-by: hannesw, lagergren
This commit is contained in:
parent
961103778f
commit
86a64a99fd
@ -85,6 +85,8 @@ public final class Compiler {
|
||||
|
||||
private Source source;
|
||||
|
||||
private String sourceName;
|
||||
|
||||
private final Map<String, byte[]> bytecode;
|
||||
|
||||
private final Set<CompileUnit> compileUnits;
|
||||
@ -267,6 +269,7 @@ public final class Compiler {
|
||||
append('$').
|
||||
append(safeSourceName(functionNode.getSource()));
|
||||
this.source = functionNode.getSource();
|
||||
this.sourceName = functionNode.getSourceName();
|
||||
this.scriptName = sb.toString();
|
||||
}
|
||||
|
||||
@ -573,7 +576,7 @@ public final class Compiler {
|
||||
}
|
||||
|
||||
private CompileUnit initCompileUnit(final String unitClassName, final long initialWeight) {
|
||||
final ClassEmitter classEmitter = new ClassEmitter(env, source.getName(), unitClassName, strict);
|
||||
final ClassEmitter classEmitter = new ClassEmitter(env, sourceName, unitClassName, strict);
|
||||
final CompileUnit compileUnit = new CompileUnit(unitClassName, classEmitter, initialWeight);
|
||||
|
||||
classEmitter.begin();
|
||||
|
@ -29,6 +29,7 @@ import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import jdk.nashorn.internal.codegen.CompileUnit;
|
||||
import jdk.nashorn.internal.codegen.Compiler;
|
||||
@ -138,6 +139,9 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
/** Function flags. */
|
||||
private final int flags;
|
||||
|
||||
/** //@ sourceURL or //# sourceURL for program function nodes */
|
||||
private final String sourceURL;
|
||||
|
||||
private final int lineNumber;
|
||||
|
||||
/** Is anonymous function flag. */
|
||||
@ -223,6 +227,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
* @param parameters parameter list
|
||||
* @param kind kind of function as in {@link FunctionNode.Kind}
|
||||
* @param flags initial flags
|
||||
* @param sourceURL sourceURL specified in script (optional)
|
||||
*/
|
||||
public FunctionNode(
|
||||
final Source source,
|
||||
@ -235,7 +240,8 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
final String name,
|
||||
final List<IdentNode> parameters,
|
||||
final FunctionNode.Kind kind,
|
||||
final int flags) {
|
||||
final int flags,
|
||||
final String sourceURL) {
|
||||
super(token, finish);
|
||||
|
||||
this.source = source;
|
||||
@ -250,6 +256,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
|
||||
this.declaredSymbols = new HashSet<>();
|
||||
this.flags = flags;
|
||||
this.sourceURL = sourceURL;
|
||||
this.compileUnit = null;
|
||||
this.body = null;
|
||||
this.snapshot = null;
|
||||
@ -260,6 +267,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
final FunctionNode functionNode,
|
||||
final long lastToken,
|
||||
final int flags,
|
||||
final String sourceURL,
|
||||
final String name,
|
||||
final Type returnType,
|
||||
final CompileUnit compileUnit,
|
||||
@ -271,6 +279,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
super(functionNode);
|
||||
this.lineNumber = functionNode.lineNumber;
|
||||
this.flags = flags;
|
||||
this.sourceURL = sourceURL;
|
||||
this.name = name;
|
||||
this.returnType = returnType;
|
||||
this.compileUnit = compileUnit;
|
||||
@ -307,6 +316,38 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
return source;
|
||||
}
|
||||
|
||||
/**
|
||||
* get source name - sourceURL or name derived from Source.
|
||||
*
|
||||
* @return name for the script source
|
||||
*/
|
||||
public String getSourceName() {
|
||||
return (sourceURL != null)? sourceURL : source.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* get the sourceURL
|
||||
* @return the sourceURL
|
||||
*/
|
||||
public String getSourceURL() {
|
||||
return sourceURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sourceURL
|
||||
*
|
||||
* @param lc lexical context
|
||||
* @param newSourceURL source url string to set
|
||||
* @return function node or a new one if state was changed
|
||||
*/
|
||||
public FunctionNode setSourceURL(final LexicalContext lc, final String newSourceURL) {
|
||||
if (Objects.equals(sourceURL, newSourceURL)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, newSourceURL, name, returnType, compileUnit, compilationState, body, parameters, null, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the line number.
|
||||
* @return the line number.
|
||||
@ -335,7 +376,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
if (this.snapshot == null) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, null, hints));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, null, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -351,7 +392,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
if (isProgram() || parameters.isEmpty()) {
|
||||
return this; //never specialize anything that won't be recompiled
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, this, hints));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, this, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -409,7 +450,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
}
|
||||
final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
|
||||
newState.add(state);
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, newState, body, parameters, snapshot, hints));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, newState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -430,7 +471,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
if (this.hints == hints) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -483,7 +524,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
if (this.flags == flags) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -593,7 +634,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
if(this.body == body) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags | (body.needsScope() ? FunctionNode.HAS_SCOPE_BLOCK : 0), name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags | (body.needsScope() ? FunctionNode.HAS_SCOPE_BLOCK : 0), sourceURL, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -688,7 +729,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
if (this.lastToken == lastToken) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -710,7 +751,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
if (this.name.equals(name)) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -760,7 +801,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
if (this.parameters == parameters) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -825,6 +866,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
this,
|
||||
lastToken,
|
||||
flags,
|
||||
sourceURL,
|
||||
name,
|
||||
type,
|
||||
compileUnit,
|
||||
@ -863,7 +905,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
|
||||
if (this.compileUnit == compileUnit) {
|
||||
return this;
|
||||
}
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
return Node.replaceInLexicalContext(lc, this, new FunctionNode(this, lastToken, flags, sourceURL, name, returnType, compileUnit, compilationState, body, parameters, snapshot, hints));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,6 +26,7 @@
|
||||
package jdk.nashorn.internal.parser;
|
||||
|
||||
import static jdk.nashorn.internal.parser.TokenType.COMMENT;
|
||||
import static jdk.nashorn.internal.parser.TokenType.DIRECTIVE_COMMENT;
|
||||
import static jdk.nashorn.internal.parser.TokenType.EOF;
|
||||
import static jdk.nashorn.internal.parser.TokenType.EOL;
|
||||
import static jdk.nashorn.internal.parser.TokenType.IDENT;
|
||||
@ -84,6 +85,9 @@ public abstract class AbstractParser {
|
||||
/** Is this parser running under strict mode? */
|
||||
protected boolean isStrictMode;
|
||||
|
||||
/** //@ sourceURL or //# sourceURL */
|
||||
protected String sourceURL;
|
||||
|
||||
/**
|
||||
* Construct a parser.
|
||||
*
|
||||
@ -156,17 +160,38 @@ public abstract class AbstractParser {
|
||||
protected final TokenType nextOrEOL() {
|
||||
do {
|
||||
nextToken();
|
||||
} while (type == COMMENT);
|
||||
if (type == DIRECTIVE_COMMENT) {
|
||||
checkDirectiveComment();
|
||||
}
|
||||
} while (type == COMMENT || type == DIRECTIVE_COMMENT);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
// sourceURL= after directive comment
|
||||
private static final String SOURCE_URL_PREFIX = "sourceURL=";
|
||||
|
||||
// currently only @sourceURL=foo supported
|
||||
private void checkDirectiveComment() {
|
||||
// if already set, ignore this one
|
||||
if (sourceURL != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String comment = (String) lexer.getValueOf(token, isStrictMode);
|
||||
final int len = comment.length();
|
||||
// 4 characters for directive comment marker //@\s or //#\s
|
||||
if (len > 4 && comment.substring(4).startsWith(SOURCE_URL_PREFIX)) {
|
||||
sourceURL = comment.substring(4 + SOURCE_URL_PREFIX.length());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek next token.
|
||||
*
|
||||
* @return tokenType of next token.
|
||||
*/
|
||||
private final TokenType nextToken() {
|
||||
private TokenType nextToken() {
|
||||
// Capture last token tokenType.
|
||||
last = type;
|
||||
if (type != EOF) {
|
||||
|
@ -27,6 +27,7 @@ package jdk.nashorn.internal.parser;
|
||||
|
||||
import static jdk.nashorn.internal.parser.TokenType.ADD;
|
||||
import static jdk.nashorn.internal.parser.TokenType.COMMENT;
|
||||
import static jdk.nashorn.internal.parser.TokenType.DIRECTIVE_COMMENT;
|
||||
import static jdk.nashorn.internal.parser.TokenType.DECIMAL;
|
||||
import static jdk.nashorn.internal.parser.TokenType.EOF;
|
||||
import static jdk.nashorn.internal.parser.TokenType.EOL;
|
||||
@ -434,12 +435,18 @@ public class Lexer extends Scanner {
|
||||
if (ch1 == '/') {
|
||||
// Skip over //.
|
||||
skip(2);
|
||||
|
||||
boolean directiveComment = false;
|
||||
if ((ch0 == '#' || ch0 == '@') && (ch1 == ' ')) {
|
||||
directiveComment = true;
|
||||
}
|
||||
|
||||
// Scan for EOL.
|
||||
while (!atEOF() && !isEOL(ch0)) {
|
||||
skip(1);
|
||||
}
|
||||
// Did detect a comment.
|
||||
add(COMMENT, start);
|
||||
add(directiveComment? DIRECTIVE_COMMENT : COMMENT, start);
|
||||
return true;
|
||||
} else if (ch1 == '*') {
|
||||
// Skip over /*.
|
||||
@ -1623,6 +1630,8 @@ public class Lexer extends Scanner {
|
||||
return valueOfPattern(start, len); // RegexToken::LexerToken
|
||||
case XML:
|
||||
return valueOfXML(start, len); // XMLToken::LexerToken
|
||||
case DIRECTIVE_COMMENT:
|
||||
return source.getString(start, len);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -421,7 +421,8 @@ loop:
|
||||
name,
|
||||
parameters,
|
||||
kind,
|
||||
flags);
|
||||
flags,
|
||||
sourceURL);
|
||||
|
||||
lc.push(functionNode);
|
||||
// Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
|
||||
@ -640,6 +641,10 @@ loop:
|
||||
|
||||
script = restoreFunctionNode(script, token); //commit code
|
||||
script = script.setBody(lc, script.getBody().setNeedsScope(lc));
|
||||
// user may have directive comment to set sourceURL
|
||||
if (sourceURL != null) {
|
||||
script = script.setSourceURL(lc, sourceURL);
|
||||
}
|
||||
|
||||
return script;
|
||||
}
|
||||
|
@ -41,10 +41,14 @@ import static jdk.nashorn.internal.parser.TokenKind.UNARY;
|
||||
*/
|
||||
@SuppressWarnings("javadoc")
|
||||
public enum TokenType {
|
||||
ERROR (SPECIAL, null),
|
||||
EOF (SPECIAL, null),
|
||||
EOL (SPECIAL, null),
|
||||
COMMENT (SPECIAL, null),
|
||||
ERROR (SPECIAL, null),
|
||||
EOF (SPECIAL, null),
|
||||
EOL (SPECIAL, null),
|
||||
COMMENT (SPECIAL, null),
|
||||
// comments of the form //@ foo=bar or //# foo=bar
|
||||
// These comments are treated as special instructions
|
||||
// to the lexer, parser or codegenerator.
|
||||
DIRECTIVE_COMMENT (SPECIAL, null),
|
||||
|
||||
NOT (UNARY, "!", 14, false),
|
||||
NE (BINARY, "!=", 9, true),
|
||||
|
56
nashorn/test/script/basic/JDK-8032068.js
Normal file
56
nashorn/test/script/basic/JDK-8032068.js
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* JDK-8032068: implement @sourceURL and #sourceURL directives.
|
||||
*
|
||||
* @test
|
||||
* @run
|
||||
*/
|
||||
|
||||
|
||||
try {
|
||||
Function("throw new Error();\n//# sourceURL=foo.js")();
|
||||
} catch (e) {
|
||||
print(e.stack.replace(/\\/g, '/'));
|
||||
}
|
||||
|
||||
try {
|
||||
eval("function g() { throw Error('x');\n } g();\n//# sourceURL=bar.js");
|
||||
} catch (e) {
|
||||
print(e.stack.replace(/\\/g, '/'));
|
||||
}
|
||||
|
||||
// check @sourceURL for compatibility
|
||||
try {
|
||||
Function("throw new Error();\n//@ sourceURL=foo2.js")();
|
||||
} catch (e) {
|
||||
print(e.stack.replace(/\\/g, '/'));
|
||||
}
|
||||
|
||||
try {
|
||||
eval("function g() { throw Error('x');\n } g();\n//@ sourceURL=bar2.js");
|
||||
} catch (e) {
|
||||
print(e.stack.replace(/\\/g, '/'));
|
||||
}
|
||||
|
14
nashorn/test/script/basic/JDK-8032068.js.EXPECTED
Normal file
14
nashorn/test/script/basic/JDK-8032068.js.EXPECTED
Normal file
@ -0,0 +1,14 @@
|
||||
Error
|
||||
at <anonymous> (foo.js:2)
|
||||
at <program> (test/script/basic/JDK-8032068.js:33)
|
||||
Error: x
|
||||
at g (bar.js:1)
|
||||
at <program> (bar.js:2)
|
||||
at <program> (test/script/basic/JDK-8032068.js:39)
|
||||
Error
|
||||
at <anonymous> (foo2.js:2)
|
||||
at <program> (test/script/basic/JDK-8032068.js:46)
|
||||
Error: x
|
||||
at g (bar2.js:1)
|
||||
at <program> (bar2.js:2)
|
||||
at <program> (test/script/basic/JDK-8032068.js:52)
|
Loading…
Reference in New Issue
Block a user