aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsundar <none@none>2014-01-20 19:51:54 +0530
committersundar <none@none>2014-01-20 19:51:54 +0530
commit298f7560533712017dcc90229db1f7323f31619e (patch)
treee44f16f8e09645c764b823bd5b82eb51888bec03
parent798250cf4d3447691959ff5fad39373296786f4f (diff)
downloadnashorn-298f7560533712017dcc90229db1f7323f31619e.tar.gz
8032068: implement @sourceURL and #sourceURL directives
Reviewed-by: hannesw, lagergren
-rw-r--r--src/jdk/nashorn/internal/codegen/Compiler.java5
-rw-r--r--src/jdk/nashorn/internal/ir/FunctionNode.java64
-rw-r--r--src/jdk/nashorn/internal/parser/AbstractParser.java29
-rw-r--r--src/jdk/nashorn/internal/parser/Lexer.java11
-rw-r--r--src/jdk/nashorn/internal/parser/Parser.java7
-rw-r--r--src/jdk/nashorn/internal/parser/TokenType.java12
-rw-r--r--test/script/basic/JDK-8032068.js56
-rw-r--r--test/script/basic/JDK-8032068.js.EXPECTED14
8 files changed, 178 insertions, 20 deletions
diff --git a/src/jdk/nashorn/internal/codegen/Compiler.java b/src/jdk/nashorn/internal/codegen/Compiler.java
index 24173c3e..b53b8fdf 100644
--- a/src/jdk/nashorn/internal/codegen/Compiler.java
+++ b/src/jdk/nashorn/internal/codegen/Compiler.java
@@ -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();
diff --git a/src/jdk/nashorn/internal/ir/FunctionNode.java b/src/jdk/nashorn/internal/ir/FunctionNode.java
index b0998ae1..1437eb40 100644
--- a/src/jdk/nashorn/internal/ir/FunctionNode.java
+++ b/src/jdk/nashorn/internal/ir/FunctionNode.java
@@ -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;
@@ -308,6 +317,38 @@ public final class FunctionNode extends LexicalContextExpression implements Flag
}
/**
+ * 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));
}
/**
diff --git a/src/jdk/nashorn/internal/parser/AbstractParser.java b/src/jdk/nashorn/internal/parser/AbstractParser.java
index 587ae869..d4a42ba4 100644
--- a/src/jdk/nashorn/internal/parser/AbstractParser.java
+++ b/src/jdk/nashorn/internal/parser/AbstractParser.java
@@ -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) {
diff --git a/src/jdk/nashorn/internal/parser/Lexer.java b/src/jdk/nashorn/internal/parser/Lexer.java
index a01705dd..653f04c0 100644
--- a/src/jdk/nashorn/internal/parser/Lexer.java
+++ b/src/jdk/nashorn/internal/parser/Lexer.java
@@ -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;
}
diff --git a/src/jdk/nashorn/internal/parser/Parser.java b/src/jdk/nashorn/internal/parser/Parser.java
index 6ac18d09..60cbaccb 100644
--- a/src/jdk/nashorn/internal/parser/Parser.java
+++ b/src/jdk/nashorn/internal/parser/Parser.java
@@ -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;
}
diff --git a/src/jdk/nashorn/internal/parser/TokenType.java b/src/jdk/nashorn/internal/parser/TokenType.java
index 6287a234..5c696cb9 100644
--- a/src/jdk/nashorn/internal/parser/TokenType.java
+++ b/src/jdk/nashorn/internal/parser/TokenType.java
@@ -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),
diff --git a/test/script/basic/JDK-8032068.js b/test/script/basic/JDK-8032068.js
new file mode 100644
index 00000000..570789d7
--- /dev/null
+++ b/test/script/basic/JDK-8032068.js
@@ -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, '/'));
+}
+
diff --git a/test/script/basic/JDK-8032068.js.EXPECTED b/test/script/basic/JDK-8032068.js.EXPECTED
new file mode 100644
index 00000000..b8891eee
--- /dev/null
+++ b/test/script/basic/JDK-8032068.js.EXPECTED
@@ -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)