提交 a6b98e01 编写于 作者: S sundar

8032068: implement @sourceURL and #sourceURL directives

Reviewed-by: hannesw, lagergren
上级 c379c785
...@@ -85,6 +85,8 @@ public final class Compiler { ...@@ -85,6 +85,8 @@ public final class Compiler {
private Source source; private Source source;
private String sourceName;
private final Map<String, byte[]> bytecode; private final Map<String, byte[]> bytecode;
private final Set<CompileUnit> compileUnits; private final Set<CompileUnit> compileUnits;
...@@ -267,6 +269,7 @@ public final class Compiler { ...@@ -267,6 +269,7 @@ public final class Compiler {
append('$'). append('$').
append(safeSourceName(functionNode.getSource())); append(safeSourceName(functionNode.getSource()));
this.source = functionNode.getSource(); this.source = functionNode.getSource();
this.sourceName = functionNode.getSourceName();
this.scriptName = sb.toString(); this.scriptName = sb.toString();
} }
...@@ -573,7 +576,7 @@ public final class Compiler { ...@@ -573,7 +576,7 @@ public final class Compiler {
} }
private CompileUnit initCompileUnit(final String unitClassName, final long initialWeight) { 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); final CompileUnit compileUnit = new CompileUnit(unitClassName, classEmitter, initialWeight);
classEmitter.begin(); classEmitter.begin();
......
...@@ -29,6 +29,7 @@ import java.util.Collections; ...@@ -29,6 +29,7 @@ import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import jdk.nashorn.internal.codegen.CompileUnit; import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.Compiler; import jdk.nashorn.internal.codegen.Compiler;
...@@ -138,6 +139,9 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -138,6 +139,9 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
/** Function flags. */ /** Function flags. */
private final int flags; private final int flags;
/** //@ sourceURL or //# sourceURL for program function nodes */
private final String sourceURL;
private final int lineNumber; private final int lineNumber;
/** Is anonymous function flag. */ /** Is anonymous function flag. */
...@@ -223,6 +227,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -223,6 +227,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
* @param parameters parameter list * @param parameters parameter list
* @param kind kind of function as in {@link FunctionNode.Kind} * @param kind kind of function as in {@link FunctionNode.Kind}
* @param flags initial flags * @param flags initial flags
* @param sourceURL sourceURL specified in script (optional)
*/ */
public FunctionNode( public FunctionNode(
final Source source, final Source source,
...@@ -235,7 +240,8 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -235,7 +240,8 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
final String name, final String name,
final List<IdentNode> parameters, final List<IdentNode> parameters,
final FunctionNode.Kind kind, final FunctionNode.Kind kind,
final int flags) { final int flags,
final String sourceURL) {
super(token, finish); super(token, finish);
this.source = source; this.source = source;
...@@ -250,6 +256,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -250,6 +256,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
this.compilationState = EnumSet.of(CompilationState.INITIALIZED); this.compilationState = EnumSet.of(CompilationState.INITIALIZED);
this.declaredSymbols = new HashSet<>(); this.declaredSymbols = new HashSet<>();
this.flags = flags; this.flags = flags;
this.sourceURL = sourceURL;
this.compileUnit = null; this.compileUnit = null;
this.body = null; this.body = null;
this.snapshot = null; this.snapshot = null;
...@@ -260,6 +267,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -260,6 +267,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
final FunctionNode functionNode, final FunctionNode functionNode,
final long lastToken, final long lastToken,
final int flags, final int flags,
final String sourceURL,
final String name, final String name,
final Type returnType, final Type returnType,
final CompileUnit compileUnit, final CompileUnit compileUnit,
...@@ -271,6 +279,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -271,6 +279,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
super(functionNode); super(functionNode);
this.lineNumber = functionNode.lineNumber; this.lineNumber = functionNode.lineNumber;
this.flags = flags; this.flags = flags;
this.sourceURL = sourceURL;
this.name = name; this.name = name;
this.returnType = returnType; this.returnType = returnType;
this.compileUnit = compileUnit; this.compileUnit = compileUnit;
...@@ -307,6 +316,38 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -307,6 +316,38 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
return source; 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. * Returns the line number.
* @return the line number. * @return the line number.
...@@ -335,7 +376,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -335,7 +376,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
if (this.snapshot == null) { if (this.snapshot == null) {
return this; 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 ...@@ -351,7 +392,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
if (isProgram() || parameters.isEmpty()) { if (isProgram() || parameters.isEmpty()) {
return this; //never specialize anything that won't be recompiled 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 ...@@ -409,7 +450,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
} }
final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState); final EnumSet<CompilationState> newState = EnumSet.copyOf(this.compilationState);
newState.add(state); 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 ...@@ -430,7 +471,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
if (this.hints == hints) { if (this.hints == hints) {
return this; 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 ...@@ -483,7 +524,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
if (this.flags == flags) { if (this.flags == flags) {
return this; 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 @Override
...@@ -593,7 +634,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -593,7 +634,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
if(this.body == body) { if(this.body == body) {
return this; 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 ...@@ -688,7 +729,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
if (this.lastToken == lastToken) { if (this.lastToken == lastToken) {
return this; 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 ...@@ -710,7 +751,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
if (this.name.equals(name)) { if (this.name.equals(name)) {
return this; 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 ...@@ -760,7 +801,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
if (this.parameters == parameters) { if (this.parameters == parameters) {
return this; 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 ...@@ -825,6 +866,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
this, this,
lastToken, lastToken,
flags, flags,
sourceURL,
name, name,
type, type,
compileUnit, compileUnit,
...@@ -863,7 +905,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag ...@@ -863,7 +905,7 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
if (this.compileUnit == compileUnit) { if (this.compileUnit == compileUnit) {
return this; 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 @@ ...@@ -26,6 +26,7 @@
package jdk.nashorn.internal.parser; package jdk.nashorn.internal.parser;
import static jdk.nashorn.internal.parser.TokenType.COMMENT; 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.EOF;
import static jdk.nashorn.internal.parser.TokenType.EOL; import static jdk.nashorn.internal.parser.TokenType.EOL;
import static jdk.nashorn.internal.parser.TokenType.IDENT; import static jdk.nashorn.internal.parser.TokenType.IDENT;
...@@ -84,6 +85,9 @@ public abstract class AbstractParser { ...@@ -84,6 +85,9 @@ public abstract class AbstractParser {
/** Is this parser running under strict mode? */ /** Is this parser running under strict mode? */
protected boolean isStrictMode; protected boolean isStrictMode;
/** //@ sourceURL or //# sourceURL */
protected String sourceURL;
/** /**
* Construct a parser. * Construct a parser.
* *
...@@ -156,17 +160,38 @@ public abstract class AbstractParser { ...@@ -156,17 +160,38 @@ public abstract class AbstractParser {
protected final TokenType nextOrEOL() { protected final TokenType nextOrEOL() {
do { do {
nextToken(); nextToken();
} while (type == COMMENT); if (type == DIRECTIVE_COMMENT) {
checkDirectiveComment();
}
} while (type == COMMENT || type == DIRECTIVE_COMMENT);
return type; 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. * Seek next token.
* *
* @return tokenType of next token. * @return tokenType of next token.
*/ */
private final TokenType nextToken() { private TokenType nextToken() {
// Capture last token tokenType. // Capture last token tokenType.
last = type; last = type;
if (type != EOF) { if (type != EOF) {
......
...@@ -27,6 +27,7 @@ package jdk.nashorn.internal.parser; ...@@ -27,6 +27,7 @@ package jdk.nashorn.internal.parser;
import static jdk.nashorn.internal.parser.TokenType.ADD; import static jdk.nashorn.internal.parser.TokenType.ADD;
import static jdk.nashorn.internal.parser.TokenType.COMMENT; 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.DECIMAL;
import static jdk.nashorn.internal.parser.TokenType.EOF; import static jdk.nashorn.internal.parser.TokenType.EOF;
import static jdk.nashorn.internal.parser.TokenType.EOL; import static jdk.nashorn.internal.parser.TokenType.EOL;
...@@ -434,12 +435,18 @@ public class Lexer extends Scanner { ...@@ -434,12 +435,18 @@ public class Lexer extends Scanner {
if (ch1 == '/') { if (ch1 == '/') {
// Skip over //. // Skip over //.
skip(2); skip(2);
boolean directiveComment = false;
if ((ch0 == '#' || ch0 == '@') && (ch1 == ' ')) {
directiveComment = true;
}
// Scan for EOL. // Scan for EOL.
while (!atEOF() && !isEOL(ch0)) { while (!atEOF() && !isEOL(ch0)) {
skip(1); skip(1);
} }
// Did detect a comment. // Did detect a comment.
add(COMMENT, start); add(directiveComment? DIRECTIVE_COMMENT : COMMENT, start);
return true; return true;
} else if (ch1 == '*') { } else if (ch1 == '*') {
// Skip over /*. // Skip over /*.
...@@ -1623,6 +1630,8 @@ public class Lexer extends Scanner { ...@@ -1623,6 +1630,8 @@ public class Lexer extends Scanner {
return valueOfPattern(start, len); // RegexToken::LexerToken return valueOfPattern(start, len); // RegexToken::LexerToken
case XML: case XML:
return valueOfXML(start, len); // XMLToken::LexerToken return valueOfXML(start, len); // XMLToken::LexerToken
case DIRECTIVE_COMMENT:
return source.getString(start, len);
default: default:
break; break;
} }
......
...@@ -421,7 +421,8 @@ loop: ...@@ -421,7 +421,8 @@ loop:
name, name,
parameters, parameters,
kind, kind,
flags); flags,
sourceURL);
lc.push(functionNode); lc.push(functionNode);
// Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the // Create new block, and just put it on the context stack, restoreFunctionNode() will associate it with the
...@@ -640,6 +641,10 @@ loop: ...@@ -640,6 +641,10 @@ loop:
script = restoreFunctionNode(script, token); //commit code script = restoreFunctionNode(script, token); //commit code
script = script.setBody(lc, script.getBody().setNeedsScope(lc)); 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; return script;
} }
......
...@@ -41,10 +41,14 @@ import static jdk.nashorn.internal.parser.TokenKind.UNARY; ...@@ -41,10 +41,14 @@ import static jdk.nashorn.internal.parser.TokenKind.UNARY;
*/ */
@SuppressWarnings("javadoc") @SuppressWarnings("javadoc")
public enum TokenType { public enum TokenType {
ERROR (SPECIAL, null), ERROR (SPECIAL, null),
EOF (SPECIAL, null), EOF (SPECIAL, null),
EOL (SPECIAL, null), EOL (SPECIAL, null),
COMMENT (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), NOT (UNARY, "!", 14, false),
NE (BINARY, "!=", 9, true), 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.
先完成此消息的编辑!
想要评论请 注册