提交 a6b98e01 编写于 作者: S sundar

8032068: implement @sourceURL and #sourceURL directives

Reviewed-by: hannesw, lagergren
上级 c379c785
......@@ -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),
......
/*
* 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, '/'));
}
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)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册