diff --git a/js/rhino/src/org/mozilla/javascript/Context.java b/js/rhino/src/org/mozilla/javascript/Context.java index b57e3e277aa2..112bf19250f8 100644 --- a/js/rhino/src/org/mozilla/javascript/Context.java +++ b/js/rhino/src/org/mozilla/javascript/Context.java @@ -779,14 +779,12 @@ public class Context { Object securityDomain) throws JavaScriptException { - try { - Reader in = new StringReader(source); - return evaluateReader(scope, in, sourceName, lineno, - securityDomain); - } - catch (IOException ioe) { - // Should never occur because we just made the reader from a String - throw new RuntimeException(); + Script script = compileString(scope, source, sourceName, lineno, + securityDomain); + if (script != null) { + return script.exec(this, scope); + } else { + return null; } } @@ -816,10 +814,11 @@ public class Context { { Script script = compileReader(scope, in, sourceName, lineno, securityDomain); - if (script != null) + if (script != null) { return script.exec(this, scope); - else + } else { return null; + } } /** @@ -840,10 +839,9 @@ public class Context { */ synchronized public boolean stringIsCompilableUnit(String source) { - Reader in = new StringReader(source); // no source name or source text manager, because we're just // going to throw away the result. - TokenStream ts = new TokenStream(in, null, null, 1); + TokenStream ts = new TokenStream(null, source, null, null, 1); // Temporarily set error reporter to always be the exception-throwing // DefaultErrorReporter. (This is why the method is synchronized...) @@ -896,10 +894,41 @@ public class Context { int lineno, Object securityDomain) throws IOException { - return (Script) compile(scope, in, sourceName, lineno, securityDomain, - false); + return (Script) compile(scope, in, null, sourceName, lineno, + securityDomain, false); } + /** + * Compiles the source in the given string. + *
+ * Returns a script that may later be executed.
+ *
+ * @param scope if nonnull, will be the scope in which the script object
+ * is created. The script object will be a valid JavaScript object
+ * as if it were created using the JavaScript1.3 Script constructor
+ * @param source the source string
+ * @param sourceName a string describing the source, such as a filename
+ * @param lineno the starting line number for reporting errors
+ * @param securityDomain an arbitrary object that specifies security
+ * information about the origin or owner of the script. For
+ * implementations that don't care about security, this value
+ * may be null.
+ * @return a script that may later be executed
+ * @see org.mozilla.javascript.Script#exec
+ * @exception IOException if an IOException was generated by the Reader
+ */
+ public Script compileString(Scriptable scope, String source,
+ String sourceName, int lineno,
+ Object securityDomain)
+ {
+ try {
+ return (Script) compile(scope, null, source, sourceName, lineno,
+ securityDomain, false);
+ } catch (IOException ex) {
+ // Should not happen when dealing with source as string
+ throw new RuntimeException();
+ }
+ }
/**
* Compile a JavaScript function.
@@ -922,9 +951,8 @@ public class Context {
String sourceName, int lineno,
Object securityDomain)
{
- Reader in = new StringReader(source);
try {
- return (Function) compile(scope, in, sourceName, lineno,
+ return (Function) compile(scope, null, source, sourceName, lineno,
securityDomain, true);
}
catch (IOException ioe) {
@@ -1904,6 +1932,24 @@ public class Context {
return formatter.format(arguments);
}
+ private static String readReader(Reader r)
+ throws IOException
+ {
+ char[] buffer = new char[512];
+ int cursor = 0;
+ for (;;) {
+ int n = r.read(buffer, cursor, buffer.length - cursor);
+ if (n < 0) { break; }
+ cursor += n;
+ if (cursor == buffer.length) {
+ char[] tmp = new char[buffer.length];
+ System.arraycopy(buffer, 0, tmp, 0, cursor);
+ buffer = tmp;
+ }
+ }
+ return new String(buffer, 0, cursor);
+ }
+
// debug flags
static final boolean printTrees = false;
static final boolean printICode = false;
@@ -1930,22 +1976,30 @@ public class Context {
* @return a class for the script or function
* @see org.mozilla.javascript.Context#compileReader
*/
- private Object compile(Scriptable scope, Reader in, String sourceName,
- int lineno, Object securityDomain,
- boolean returnFunction)
+ private Object compile(Scriptable scope,
+ Reader sourceReader, String sourceString,
+ String sourceName, int lineno,
+ Object securityDomain, boolean returnFunction)
throws IOException
{
+ // One of sourceReader or sourceString has to be null
+ if (!(sourceReader == null ^ sourceString == null)) Context.codeBug();
+
Object dynamicDoamin = null;
if (securityController != null) {
dynamicDoamin = securityController.
getDynamicSecurityDomain(securityDomain);
}
- if (debugger != null && in != null) {
- in = new DebugReader(in);
+ if (debugger != null) {
+ if (sourceReader != null) {
+ sourceString = readReader(sourceReader);
+ sourceReader = null;
+ }
}
- TokenStream ts = new TokenStream(in, scope, sourceName, lineno);
- return compile(scope, ts, dynamicDoamin, in, returnFunction);
+ TokenStream ts = new TokenStream(sourceReader, sourceString,
+ scope, sourceName, lineno);
+ return compile(scope, ts, dynamicDoamin, sourceString, returnFunction);
}
private static Class codegenClass;
@@ -1978,7 +2032,7 @@ public class Context {
}
private Object compile(Scriptable scope, TokenStream ts,
- Object dynamicSecurityDomain, Reader in,
+ Object dynamicSecurityDomain, String sourceString,
boolean returnFunction)
throws IOException
{
@@ -2010,9 +2064,9 @@ public class Context {
return null;
}
- if (in instanceof DebugReader) {
- DebugReader dr = (DebugReader) in;
- tree.putProp(Node.DEBUGSOURCE_PROP, dr.getSaved());
+ if (debugger != null) {
+ if (sourceString == null) Context.codeBug();
+ tree.putProp(Node.DEBUGSOURCE_PROP, sourceString);
}
Object result = compiler.compile(this, scope, tree,
diff --git a/js/rhino/src/org/mozilla/javascript/LineBuffer.java b/js/rhino/src/org/mozilla/javascript/LineBuffer.java
deleted file mode 100644
index e545758cf3f2..000000000000
--- a/js/rhino/src/org/mozilla/javascript/LineBuffer.java
+++ /dev/null
@@ -1,343 +0,0 @@
-/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * The contents of this file are subject to the Netscape Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/NPL/
- *
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- *
- * The Original Code is Rhino code, released
- * May 6, 1999.
- *
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation. Portions created by Netscape are
- * Copyright (C) 1997-1999 Netscape Communications Corporation. All
- * Rights Reserved.
- *
- * Contributor(s):
- * Mike McCabe
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU Public License (the "GPL"), in which case the
- * provisions of the GPL are applicable instead of those above.
- * If you wish to allow use of your version of this file only
- * under the terms of the GPL and not to allow others to use your
- * version of this file under the NPL, indicate your decision by
- * deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL. If you do not delete
- * the provisions above, a recipient may use your version of this
- * file under either the NPL or the GPL.
- */
-
-package org.mozilla.javascript;
-
-import java.io.Reader;
-import java.io.IOException;
-
-/**
- * An input buffer that combines fast character-based access with
- * (slower) support for retrieving the text of the current line. It
- * also supports building strings directly out of the internal buffer
- * to support fast scanning with minimal object creation.
- *
- * Note that it is customized in several ways to support the
- * TokenStream class, and should not be considered general.
- *
- * Credits to Kipp Hickman and John Bandhauer.
- *
- * @author Mike McCabe
- */
-final class LineBuffer {
- /*
- * for smooth operation of getLine(), this should be greater than
- * the length of any expected line. Currently, 256 is 3% slower
- * than 4096 for large compiles, but seems safer given evaluateString.
- * Strings for the scanner are are built with StringBuffers
- * instead of directly out of the buffer whenever a string crosses
- * a buffer boundary, so small buffer sizes will mean that more
- * objects are created.
- */
- static final int BUFLEN = 256;
-
- LineBuffer(Reader in, int lineno) {
- this.in = in;
- this.lineno = lineno;
- }
-
- int read() throws IOException {
- for(;;) {
- if (end == offset && !fill())
- return -1;
-
- int c = buffer[offset];
- ++offset;
-
- if ((c & EOL_HINT_MASK) == 0) {
- switch (c) {
- case '\r':
- // if the next character is a newline, skip past it.
- if (offset != end) {
- if (buffer[offset] == '\n')
- ++offset;
- } else {
- // set a flag for fill(), in case the first char
- // of the next fill is a newline.
- lastWasCR = true;
- }
- // NO break here!
- case '\n': case '\u2028': case '\u2029':
- prevStart = lineStart;
- lineStart = offset;
- lineno++;
- return '\n';
- }
- }
-
- if (c < 128 || !formatChar(c)) {
- return c;
- }
- }
- }
-
- void unread() {
- // offset can only be 0 when we're asked to unread() an implicit
- // EOF_CHAR.
-
- // This would be wrong behavior in the general case,
- // because a peek() could map a buffer.length offset to 0
- // in the process of a fill(), and leave it there. But
- // the scanner never calls peek() or a failed match()
- // followed by unread()... this would violate 1-character
- // lookahead.
- if (Context.check && offset == 0 && !hitEOF) Context.codeBug();
-
- if (offset == 0) // Same as if (hitEOF)
- return;
- offset--;
- int c = buffer[offset];
- if ((c & EOL_HINT_MASK) == 0 && eolChar(c)) {
- lineStart = prevStart;
- lineno--;
- }
- }
-
- private void skipFormatChar() {
- if (checkSelf && !formatChar(buffer[offset])) Context.codeBug();
-
- // swap prev character with format one so possible call to
- // startString can assume that previous non-format char is at
- // offset - 1. Note it causes getLine to return not exactly the
- // source LineBuffer read, but it is used only in error reporting
- // and should not be a problem.
- if (offset != 0) {
- char tmp = buffer[offset];
- buffer[offset] = buffer[offset - 1];
- buffer[offset - 1] = tmp;
- }
- else if (otherEnd != 0) {
- char tmp = buffer[offset];
- buffer[offset] = otherBuffer[otherEnd - 1];
- otherBuffer[otherEnd - 1] = tmp;
- }
-
- ++offset;
- }
-
- int peek() throws IOException {
- for (;;) {
- if (end == offset && !fill()) {
- return -1;
- }
-
- int c = buffer[offset];
- if ((c & EOL_HINT_MASK) == 0 && eolChar(c)) {
- return '\n';
- }
- if (c < 128 || !formatChar(c)) {
- return c;
- }
-
- skipFormatChar();
- }
- }
-
- boolean match(int test) throws IOException {
- if (Context.check) {
- // TokenStream never looks ahead for '\n', which allows simple code
- if ((test & EOL_HINT_MASK) == 0 && eolChar(test))
- Context.codeBug();
- // Format chars are not allowed either
- if (test >= 128 && formatChar(test))
- Context.codeBug();
- }
-
- for (;;) {
- if (end == offset && !fill())
- return false;
-
- int c = buffer[offset];
- if (test == c) {
- ++offset;
- return true;
- }
- if (c < 128 || !formatChar(c)) {
- return false;
- }
- skipFormatChar();
- }
- }
-
- // Reconstruct a source line from the buffers. This can be slow...
- String getLine() {
- // Look for line end in the unprocessed buffer
- int i = offset;
- while(true) {
- if (i == end) {
- // if we're out of buffer, let's just expand it. We do
- // this instead of reading into a StringBuffer to
- // preserve the stream for later reads.
- if (end == buffer.length) {
- char[] tmp = new char[buffer.length * 2];
- System.arraycopy(buffer, 0, tmp, 0, end);
- buffer = tmp;
- }
- int charsRead = 0;
- try {
- charsRead = in.read(buffer, end, buffer.length - end);
- } catch (IOException ioe) {
- // ignore it, we're already displaying an error...
- break;
- }
- if (charsRead < 0)
- break;
- end += charsRead;
- }
- int c = buffer[i];
- if ((c & EOL_HINT_MASK) == 0 && eolChar(c))
- break;
- i++;
- }
-
- int start = lineStart;
- if (lineStart < 0) {
- // the line begins somewhere in the other buffer; get that first.
- StringBuffer sb = new StringBuffer(otherEnd - otherStart + i);
- sb.append(otherBuffer, otherStart, otherEnd - otherStart);
- sb.append(buffer, 0, i);
- return sb.toString();
- } else {
- return new String(buffer, lineStart, i - lineStart);
- }
- }
-
- // Get the offset of the current character, relative to
- // the line that getLine() returns.
- int getOffset() {
- if (lineStart < 0)
- // The line begins somewhere in the other buffer.
- return offset + (otherEnd - otherStart);
- else
- return offset - lineStart;
- }
-
- private boolean fill() throws IOException {
- // fill should be caled only for emty buffer
- if (checkSelf && !(end == offset)) Context.codeBug();
-
- // swap buffers
- char[] tempBuffer = buffer;
- buffer = otherBuffer;
- otherBuffer = tempBuffer;
-
- // allocate the buffers lazily, in case we're handed a short string.
- if (buffer == null) {
- buffer = new char[BUFLEN];
- }
-
- // buffers have switched, so move the newline marker.
- if (lineStart >= 0) {
- otherStart = lineStart;
- } else {
- // discard beging of the old line
- otherStart = 0;
- }
-
- otherEnd = end;
-
- // set lineStart to a sentinel value, unless this is the first
- // time around.
- prevStart = lineStart = (otherBuffer == null) ? 0 : -1;
-
- offset = 0;
- end = in.read(buffer, 0, buffer.length);
- if (end < 0) {
- end = 0;
-
- // can't null buffers here, because a string might be retrieved
- // out of the other buffer, and a 0-length string might be
- // retrieved out of this one.
-
- hitEOF = true;
- return false;
- }
-
- // If the last character of the previous fill was a carriage return,
- // then ignore a newline.
-
- // There's another bizzare special case here. If lastWasCR is
- // true, and we see a newline, and the buffer length is
- // 1... then we probably just read the last character of the
- // file, and returning after advancing offset is not the right
- // thing to do. Instead, we try to ignore the newline (and
- // likely get to EOF for real) by doing yet another fill().
- if (lastWasCR) {
- if (buffer[0] == '\n') {
- offset++;
- if (end == 1)
- return fill();
- }
- lineStart = offset;
- lastWasCR = false;
- }
- return true;
- }
-
- int getLineno() { return lineno; }
- boolean eof() { return hitEOF; }
-
- private static boolean formatChar(int c) {
- return Character.getType((char)c) == Character.FORMAT;
- }
-
- private static boolean eolChar(int c) {
- return c == '\r' || c == '\n' || c == '\u2028' || c == '\u2029';
- }
-
- // Optimization for faster check for eol character: eolChar(c) returns
- // true only when (c & EOL_HINT_MASK) == 0
- private static final int EOL_HINT_MASK = 0xdfd0;
-
- private Reader in;
- private char[] otherBuffer = null;
- private char[] buffer = null;
-
- // Yes, there are too too many of these.
- private int offset = 0;
- private int end = 0;
- private int otherEnd;
- private int lineno;
-
- private int lineStart = 0;
- private int otherStart = 0;
- private int prevStart = 0;
-
- private boolean lastWasCR = false;
- private boolean hitEOF = false;
-
-// Rudimentary support for Design-by-Contract
- private static final boolean checkSelf = Context.check && true;
-}
diff --git a/js/rhino/src/org/mozilla/javascript/TokenStream.java b/js/rhino/src/org/mozilla/javascript/TokenStream.java
index 2037769e8164..9365e8cc0202 100644
--- a/js/rhino/src/org/mozilla/javascript/TokenStream.java
+++ b/js/rhino/src/org/mozilla/javascript/TokenStream.java
@@ -21,6 +21,7 @@
* Contributor(s):
* Roger Lawrence
* Mike McCabe
+ * Igor Bukanov
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
@@ -613,20 +614,45 @@ public class TokenStream {
return id & 0xff;
}
- public TokenStream(Reader in, Scriptable scope,
- String sourceName, int lineno)
+ public TokenStream(Reader sourceReader, String sourceString,
+ Scriptable scope, String sourceName, int lineno)
{
- this.in = new LineBuffer(in, lineno);
this.scope = scope;
this.pushbackToken = EOF;
this.sourceName = sourceName;
- flags = 0;
+ this.lineno = lineno;
+ this.flags = 0;
+ if (sourceReader != null) {
+ if (sourceString != null) Context.codeBug();
+ this.sourceReader = sourceReader;
+ this.sourceBuffer = new char[512];
+ this.sourceEnd = 0;
+ } else {
+ if (sourceString == null) Context.codeBug();
+ this.sourceString = sourceString;
+ this.sourceEnd = sourceString.length();
+ }
+ this.sourceCursor = 0;
}
public Scriptable getScope() {
return scope;
}
+ public String getSourceName() { return sourceName; }
+
+ public int getLineno() { return lineno; }
+
+ public int getOp() { return op; }
+
+ public String getString() { return string; }
+
+ public double getNumber() { return number; }
+
+ public int getTokenno() { return tokenno; }
+
+ public boolean eof() { return hitEOF; }
+
/* return and pop the token from the stream if it matches...
* otherwise return null
*/
@@ -646,11 +672,8 @@ public class TokenStream {
}
public void ungetToken(int tt) {
- if (this.pushbackToken != EOF && tt != ERROR) {
- String message = Context.getMessage2("msg.token.replaces.pushback",
- tokenToString(tt), tokenToString(this.pushbackToken));
- throw new RuntimeException(message);
- }
+ // Can not unread more then one token
+ if (this.pushbackToken != EOF && tt != ERROR) Context.codeBug();
this.pushbackToken = tt;
tokenno--;
}
@@ -674,68 +697,6 @@ public class TokenStream {
return result;
}
- protected static boolean isJSIdentifier(String s) {
- int length = s.length();
-
- if (length == 0 || !Character.isJavaIdentifierStart(s.charAt(0)))
- return false;
-
- for (int i=1; i