JS parser: GWT parser copied

This commit is contained in:
Alexey Tsvetkov
2014-03-24 06:08:27 +04:00
parent 85b2df8c61
commit b1c005dccf
24 changed files with 10968 additions and 2 deletions
+1
View File
@@ -35,6 +35,7 @@
<module fileurl="file://$PROJECT_DIR$/js/js.dart-ast/js.dart-ast.iml" filepath="$PROJECT_DIR$/js/js.dart-ast/js.dart-ast.iml" group="compiler/js" />
<module fileurl="file://$PROJECT_DIR$/js/js.frontend/js.frontend.iml" filepath="$PROJECT_DIR$/js/js.frontend/js.frontend.iml" group="compiler/js" />
<module fileurl="file://$PROJECT_DIR$/js/js.inliner/js.inliner.iml" filepath="$PROJECT_DIR$/js/js.inliner/js.inliner.iml" group="compiler/js" />
<module fileurl="file://$PROJECT_DIR$/js/js.parser/js.parser.iml" filepath="$PROJECT_DIR$/js/js.parser/js.parser.iml" group="compiler/js" />
<module fileurl="file://$PROJECT_DIR$/js/js.tests/js.tests.iml" filepath="$PROJECT_DIR$/js/js.tests/js.tests.iml" group="compiler/js" />
<module fileurl="file://$PROJECT_DIR$/js/js.translator/js.translator.iml" filepath="$PROJECT_DIR$/js/js.translator/js.translator.iml" group="compiler/js" />
<module fileurl="file://$PROJECT_DIR$/jps-plugin/kannotator-jps-plugin-test/kannotator-jps-plugin-test.iml" filepath="$PROJECT_DIR$/jps-plugin/kannotator-jps-plugin-test/kannotator-jps-plugin-test.iml" group="ide/jps" />
+3
View File
@@ -78,6 +78,7 @@
<include name="js/js.translator/src"/>
<include name="js/js.frontend/src"/>
<include name="js/js.inliner/src"/>
<include name="js/js.parser/src"/>
</dirset>
<property name="idea.out" value="${basedir}/out/production"/>
@@ -100,6 +101,7 @@
<include name="js.translator/**"/>
<include name="js.frontend/**"/>
<include name="js.inliner/**"/>
<include name="js.parser/**"/>
</patternset>
<path id="compilerSources.path">
@@ -165,6 +167,7 @@
<fileset dir="js/js.translator/src"/>
<fileset dir="js/js.frontend/src"/>
<fileset dir="js/js.inliner/src"/>
<fileset dir="js/js.parser/src"/>
<zipfileset file="${kotlin-home}/build.txt" prefix="META-INF"/>
<manifest>
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="js.dart-ast" />
<orderEntry type="library" name="kotlin-runtime" level="project" />
</component>
</module>
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,106 @@
/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.js;
/**
* Indicates inability to parse JavaScript source.
*/
public class JsParserException extends Exception {
/**
* Represents the location of a parser exception.
*/
public static class SourceDetail {
private final String fileName;
private final int line;
private final int lineOffset;
private final String lineSource;
public SourceDetail(int line, String lineSource, int lineOffset,
String fileName) {
this.line = line;
this.lineSource = lineSource;
this.lineOffset = lineOffset;
this.fileName = fileName;
}
public String getFileName() {
return fileName;
}
public int getLine() {
return line;
}
public int getLineOffset() {
return lineOffset;
}
public String getLineSource() {
return lineSource;
}
}
private static String createMessageWithDetail(String msg,
SourceDetail sourceDetail) {
if (sourceDetail == null) {
return msg;
}
StringBuffer sb = new StringBuffer();
sb.append(sourceDetail.getFileName());
sb.append('(');
sb.append(sourceDetail.getLine());
sb.append(')');
sb.append(": ");
sb.append(msg);
if (sourceDetail.getLineSource() != null) {
sb.append("\n> ");
sb.append(sourceDetail.getLineSource());
sb.append("\n> ");
for (int i = 0, n = sourceDetail.getLineOffset(); i < n; ++i) {
sb.append('-');
}
sb.append('^');
}
return sb.toString();
}
private final SourceDetail sourceDetail;
public JsParserException(String msg) {
this(msg, null);
}
public JsParserException(String msg, int line, String lineSource,
int lineOffset, String fileName) {
this(msg, new SourceDetail(line, lineSource, lineOffset, fileName));
}
public JsParserException(String msg, SourceDetail sourceDetail) {
super(createMessageWithDetail(msg, sourceDetail));
this.sourceDetail = sourceDetail;
}
/**
* Provides additional source detail in some cases.
*
* @return additional detail regarding the error, or <code>null</code> if no
* additional detail is available
*/
public SourceDetail getSourceDetail() {
return sourceDetail;
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.js;
// An unchecked wrapper exception to interop with Rhino.
class UncheckedJsParserException extends RuntimeException {
private final JsParserException parserException;
public UncheckedJsParserException(JsParserException parserException) {
this.parserException = parserException;
}
public JsParserException getParserException() {
return parserException;
}
}
@@ -0,0 +1,76 @@
/* -*- 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):
* Waldemar Horwat
*
* 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.
*/
// Modified by Google
package com.google.gwt.dev.js.rhino;
final class BinaryDigitReader {
int lgBase; // Logarithm of base of number
int digit; // Current digit value in radix given by base
int digitPos; // Bit position of last bit extracted from digit
String digits; // String containing the digits
int start; // Index of the first remaining digit
int end; // Index past the last remaining digit
BinaryDigitReader(int base, String digits, int start, int end) {
lgBase = 0;
while (base != 1) {
lgBase++;
base >>= 1;
}
digitPos = 0;
this.digits = digits;
this.start = start;
this.end = end;
}
/* Return the next binary digit from the number or -1 if done */
int getNextBinaryDigit()
{
if (digitPos == 0) {
if (start == end)
return -1;
char c = digits.charAt(start++);
if ('0' <= c && c <= '9')
digit = c - '0';
else if ('a' <= c && c <= 'z')
digit = c - 'a' + 10;
else digit = c - 'A' + 10;
digitPos = lgBase;
}
return digit >> --digitPos & 1;
}
}
@@ -0,0 +1,36 @@
The files in this package are taken from mozilla's Rhino project.
See http://www.mozilla.org/rhino/
The files modified from Rhino 1.5R3
(ftp://ftp.mozilla.org/pub/js/rhino15R3.zip).
--
The contents of this package 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-2000 Netscape Communications Corporation. All
Rights Reserved.
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.
@@ -0,0 +1,802 @@
/* -*- 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-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*
* Patrick Beard
* Norris Boyd
* Igor Bukanov
* Brendan Eich
* Roger Lawrence
* Mike McCabe
* Ian D. Stewart
* Andi Vajda
* Andrew Wason
* Kemal Bayram
*
* 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.
*/
// Modified by Google
// API class
package com.google.gwt.dev.js.rhino;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Hashtable;
import java.util.Locale;
import java.util.ResourceBundle;
/**
* This class represents the runtime context of an executing script.
*
* Before executing a script, an instance of Context must be created
* and associated with the thread that will be executing the script.
* The Context will be used to store information about the executing
* of the script such as the call stack. Contexts are associated with
* the current thread using the <a href="#enter()">enter()</a> method.<p>
*
* The behavior of the execution engine may be altered through methods
* such as <a href="#setLanguageVersion>setLanguageVersion</a> and
* <a href="#setErrorReporter>setErrorReporter</a>.<p>
*
* Different forms of script execution are supported. Scripts may be
* evaluated from the source directly, or first compiled and then later
* executed. Interactive execution is also supported.<p>
*
* Some aspects of script execution, such as type conversions and
* object creation, may be accessed directly through methods of
* Context.
*
* @see Scriptable
* @author Norris Boyd
* @author Brendan Eich
*/
public class Context {
public static final String languageVersionProperty = "language version";
public static final String errorReporterProperty = "error reporter";
/**
* Create a new Context.
*
* Note that the Context must be associated with a thread before
* it can be used to execute a script.
*
* @see org.mozilla.javascript.Context#enter
*/
public Context() {
setLanguageVersion(VERSION_DEFAULT);
}
/**
* Get a context associated with the current thread, creating
* one if need be.
*
* The Context stores the execution state of the JavaScript
* engine, so it is required that the context be entered
* before execution may begin. Once a thread has entered
* a Context, then getCurrentContext() may be called to find
* the context that is associated with the current thread.
* <p>
* Calling <code>enter()</code> will
* return either the Context currently associated with the
* thread, or will create a new context and associate it
* with the current thread. Each call to <code>enter()</code>
* must have a matching call to <code>exit()</code>. For example,
* <pre>
* Context cx = Context.enter();
* try {
* ...
* cx.evaluateString(...);
* }
* finally { Context.exit(); }
* </pre>
* @return a Context associated with the current thread
* @see org.mozilla.javascript.Context#getCurrentContext
* @see org.mozilla.javascript.Context#exit
*/
public static Context enter() {
return enter(null);
}
/**
* Get a Context associated with the current thread, using
* the given Context if need be.
* <p>
* The same as <code>enter()</code> except that <code>cx</code>
* is associated with the current thread and returned if
* the current thread has no associated context and <code>cx</code>
* is not associated with any other thread.
* @param cx a Context to associate with the thread if possible
* @return a Context associated with the current thread
*/
public static Context enter(Context cx) {
Context old = getCurrentContext();
if (cx == null) {
if (old != null) {
cx = old;
} else {
cx = new Context();
setThreadContext(cx);
}
} else {
if (cx.enterCount != 0) {
// The suplied context must be the context for
// the current thread if it is already entered
if (cx != old) {
throw new RuntimeException
("Cannot enter Context active on another thread");
}
} else {
if (old != null) {
cx = old;
} else {
setThreadContext(cx);
}
}
}
++cx.enterCount;
return cx;
}
/**
* Exit a block of code requiring a Context.
*
* Calling <code>exit()</code> will remove the association between
* the current thread and a Context if the prior call to
* <code>enter()</code> on this thread newly associated a Context
* with this thread.
* Once the current thread no longer has an associated Context,
* it cannot be used to execute JavaScript until it is again associated
* with a Context.
*
* @see org.mozilla.javascript.Context#enter
*/
public static void exit() {
boolean released = false;
Context cx = getCurrentContext();
if (cx == null) {
throw new RuntimeException
("Calling Context.exit without previous Context.enter");
}
if (Context.check && cx.enterCount < 1) Context.codeBug();
--cx.enterCount;
if (cx.enterCount == 0) {
released = true;
setThreadContext(null);
}
}
/**
* Get the current Context.
*
* The current Context is per-thread; this method looks up
* the Context associated with the current thread. <p>
*
* @return the Context associated with the current thread, or
* null if no context is associated with the current
* thread.
* @see org.mozilla.javascript.Context#enter
* @see org.mozilla.javascript.Context#exit
*/
public static Context getCurrentContext() {
if (threadLocalCx != null) {
try {
return (Context)threadLocalGet.invoke(threadLocalCx, (Object[]) null);
} catch (Exception ex) { }
}
Thread t = Thread.currentThread();
return (Context) threadContexts.get(t);
}
private static void setThreadContext(Context cx) {
if (threadLocalCx != null) {
try {
threadLocalSet.invoke(threadLocalCx, new Object[] { cx });
return;
} catch (Exception ex) { }
}
Thread t = Thread.currentThread();
if (cx != null) {
threadContexts.put(t, cx);
} else {
threadContexts.remove(t);
}
}
/**
* Language versions
*
* All integral values are reserved for future version numbers.
*/
/**
* The unknown version.
*/
public static final int VERSION_UNKNOWN = -1;
/**
* The default version.
*/
public static final int VERSION_DEFAULT = 0;
/**
* JavaScript 1.0
*/
public static final int VERSION_1_0 = 100;
/**
* JavaScript 1.1
*/
public static final int VERSION_1_1 = 110;
/**
* JavaScript 1.2
*/
public static final int VERSION_1_2 = 120;
/**
* JavaScript 1.3
*/
public static final int VERSION_1_3 = 130;
/**
* JavaScript 1.4
*/
public static final int VERSION_1_4 = 140;
/**
* JavaScript 1.5
*/
public static final int VERSION_1_5 = 150;
/**
* Get the current language version.
* <p>
* The language version number affects JavaScript semantics as detailed
* in the overview documentation.
*
* @return an integer that is one of VERSION_1_0, VERSION_1_1, etc.
*/
public int getLanguageVersion() {
return version;
}
/**
* Set the language version.
*
* <p>
* Setting the language version will affect functions and scripts compiled
* subsequently. See the overview documentation for version-specific
* behavior.
*
* @param version the version as specified by VERSION_1_0, VERSION_1_1, etc.
*/
public void setLanguageVersion(int version) {
this.version = version;
}
/**
* Get the implementation version.
*
* <p>
* The implementation version is of the form
* <pre>
* "<i>name langVer</i> <code>release</code> <i>relNum date</i>"
* </pre>
* where <i>name</i> is the name of the product, <i>langVer</i> is
* the language version, <i>relNum</i> is the release number, and
* <i>date</i> is the release date for that specific
* release in the form "yyyy mm dd".
*
* @return a string that encodes the product, language version, release
* number, and date.
*/
public String getImplementationVersion() {
return "Rhino 1.5 release 4.1 2003 04 21";
}
/**
* Get the current error reporter.
*
* @see org.mozilla.javascript.ErrorReporter
*/
public ErrorReporter getErrorReporter() {
return errorReporter;
}
/**
* Change the current error reporter.
*
* @return the previous error reporter
* @see org.mozilla.javascript.ErrorReporter
*/
public ErrorReporter setErrorReporter(ErrorReporter reporter) {
errorReporter = reporter;
return reporter;
}
/**
* Get the current locale. Returns the default locale if none has
* been set.
*
* @see java.util.Locale
*/
public Locale getLocale() {
if (locale == null)
locale = Locale.getDefault();
return locale;
}
/**
* Set the current locale.
*
* @see java.util.Locale
*/
public Locale setLocale(Locale loc) {
Locale result = locale;
locale = loc;
return result;
}
/**
* Notify any registered listeners that a bounded property has changed
* @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
* @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
* @see java.beans.PropertyChangeListener
* @see java.beans.PropertyChangeEvent
* @param property the bound property
* @param oldValue the old value
* @param newVale the new value
*/
void firePropertyChange(String property, Object oldValue,
Object newValue)
{
Object[] array = listeners;
if (array != null) {
firePropertyChangeImpl(array, property, oldValue, newValue);
}
}
private void firePropertyChangeImpl(Object[] array, String property,
Object oldValue, Object newValue)
{
for (int i = array.length; i-- != 0;) {
Object obj = array[i];
if (obj instanceof PropertyChangeListener) {
PropertyChangeListener l = (PropertyChangeListener)obj;
l.propertyChange(new PropertyChangeEvent(
this, property, oldValue, newValue));
}
}
}
/**
* Report a warning using the error reporter for the current thread.
*
* @param message the warning message to report
* @param sourceName a string describing the source, such as a filename
* @param lineno the starting line number
* @param lineSource the text of the line (may be null)
* @param lineOffset the offset into lineSource where problem was detected
* @see org.mozilla.javascript.ErrorReporter
*/
public static void reportWarning(String message, String sourceName,
int lineno, String lineSource,
int lineOffset)
{
Context cx = Context.getContext();
cx.getErrorReporter().warning(message, sourceName, lineno,
lineSource, lineOffset);
}
/**
* Report a warning using the error reporter for the current thread.
*
* @param message the warning message to report
* @see org.mozilla.javascript.ErrorReporter
*/
/*
public static void reportWarning(String message) {
int[] linep = { 0 };
String filename = getSourcePositionFromStack(linep);
Context.reportWarning(message, filename, linep[0], null, 0);
}
*/
/**
* Report an error using the error reporter for the current thread.
*
* @param message the error message to report
* @param sourceName a string describing the source, such as a filename
* @param lineno the starting line number
* @param lineSource the text of the line (may be null)
* @param lineOffset the offset into lineSource where problem was detected
* @see org.mozilla.javascript.ErrorReporter
*/
public static void reportError(String message, String sourceName,
int lineno, String lineSource,
int lineOffset)
{
Context cx = getCurrentContext();
if (cx != null) {
cx.errorCount++;
cx.getErrorReporter().error(message, sourceName, lineno,
lineSource, lineOffset);
} else {
throw new EvaluatorException(message);
}
}
/**
* Report an error using the error reporter for the current thread.
*
* @param message the error message to report
* @see org.mozilla.javascript.ErrorReporter
*/
/*
public static void reportError(String message) {
int[] linep = { 0 };
String filename = getSourcePositionFromStack(linep);
Context.reportError(message, filename, linep[0], null, 0);
}
*/
/**
* Report a runtime error using the error reporter for the current thread.
*
* @param message the error message to report
* @param sourceName a string describing the source, such as a filename
* @param lineno the starting line number
* @param lineSource the text of the line (may be null)
* @param lineOffset the offset into lineSource where problem was detected
* @return a runtime exception that will be thrown to terminate the
* execution of the script
* @see org.mozilla.javascript.ErrorReporter
*/
/*
public static EvaluatorException reportRuntimeError(String message,
String sourceName,
int lineno,
String lineSource,
int lineOffset)
{
Context cx = getCurrentContext();
if (cx != null) {
cx.errorCount++;
return cx.getErrorReporter().
runtimeError(message, sourceName, lineno,
lineSource, lineOffset);
} else {
throw new EvaluatorException(message);
}
}
static EvaluatorException reportRuntimeError0(String messageId) {
return reportRuntimeError(getMessage0(messageId));
}
static EvaluatorException reportRuntimeError1
(String messageId, Object arg1)
{
return reportRuntimeError(getMessage1(messageId, arg1));
}
static EvaluatorException reportRuntimeError2
(String messageId, Object arg1, Object arg2)
{
return reportRuntimeError(getMessage2(messageId, arg1, arg2));
}
static EvaluatorException reportRuntimeError3
(String messageId, Object arg1, Object arg2, Object arg3)
{
return reportRuntimeError(getMessage3(messageId, arg1, arg2, arg3));
}
*/
/**
* Report a runtime error using the error reporter for the current thread.
*
* @param message the error message to report
* @see org.mozilla.javascript.ErrorReporter
*/
/*
public static EvaluatorException reportRuntimeError(String message) {
int[] linep = { 0 };
String filename = getSourcePositionFromStack(linep);
return Context.reportRuntimeError(message, filename, linep[0], null, 0);
}
*/
/**
* Get a value corresponding to a key.
* <p>
* Since the Context is associated with a thread it can be
* used to maintain values that can be later retrieved using
* the current thread.
* <p>
* Note that the values are maintained with the Context, so
* if the Context is disassociated from the thread the values
* cannot be retreived. Also, if private data is to be maintained
* in this manner the key should be a java.lang.Object
* whose reference is not divulged to untrusted code.
* @param key the key used to lookup the value
* @return a value previously stored using putThreadLocal.
*/
public final Object getThreadLocal(Object key) {
if (hashtable == null)
return null;
return hashtable.get(key);
}
/**
* Put a value that can later be retrieved using a given key.
* <p>
* @param key the key used to index the value
* @param value the value to save
*/
public void putThreadLocal(Object key, Object value) {
if (hashtable == null)
hashtable = new Hashtable();
hashtable.put(key, value);
}
/**
* Remove values from thread-local storage.
* @param key the key for the entry to remove.
* @since 1.5 release 2
*/
public void removeThreadLocal(Object key) {
if (hashtable == null)
return;
hashtable.remove(key);
}
/**
* Return whether functions are compiled by this context using
* dynamic scope.
* <p>
* If functions are compiled with dynamic scope, then they execute
* in the scope of their caller, rather than in their parent scope.
* This is useful for sharing functions across multiple scopes.
* @since 1.5 Release 1
*/
public final boolean hasCompileFunctionsWithDynamicScope() {
return compileFunctionsWithDynamicScopeFlag;
}
/**
* Set whether functions compiled by this context should use
* dynamic scope.
* <p>
* @param flag if true, compile functions with dynamic scope
* @since 1.5 Release 1
*/
public void setCompileFunctionsWithDynamicScope(boolean flag) {
compileFunctionsWithDynamicScopeFlag = flag;
}
/**
* if hasFeature(FEATURE_NON_ECMA_GET_YEAR) returns true,
* Date.prototype.getYear subtructs 1900 only if 1900 <= date < 2000
* in deviation with Ecma B.2.4
*/
public static final int FEATURE_NON_ECMA_GET_YEAR = 1;
/**
* if hasFeature(FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME) returns true,
* allow 'function <MemberExpression>(...) { ... }' to be syntax sugar for
* '<MemberExpression> = function(...) { ... }', when <MemberExpression>
* is not simply identifier.
* See Ecma-262, section 11.2 for definition of <MemberExpression>
*/
public static final int FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME = 2;
/**
* if hasFeature(RESERVED_KEYWORD_AS_IDENTIFIER) returns true,
* treat future reserved keyword (see Ecma-262, section 7.5.3) as ordinary
* identifiers but warn about this usage
*/
public static final int FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER = 3;
/**
* if hasFeature(FEATURE_TO_STRING_AS_SOURCE) returns true,
* calling toString on JS objects gives JS source with code to create an
* object with all enumeratable fields of the original object instead of
* printing "[object <object-type>]".
* By default {@link #hasFeature(int)} returns true only if
* the current JS version is set to {@link #VERSION_1_2}.
*/
public static final int FEATURE_TO_STRING_AS_SOURCE = 4;
/**
* Controls certain aspects of script semantics.
* Should be overwritten to alter default behavior.
* @param featureIndex feature index to check
* @return true if the <code>featureIndex</code> feature is turned on
* @see #FEATURE_NON_ECMA_GET_YEAR
* @see #FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME
* @see #FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER
* @see #FEATURE_TO_STRING_AS_SOURCE
*/
public boolean hasFeature(int featureIndex) {
switch (featureIndex) {
case FEATURE_NON_ECMA_GET_YEAR:
/*
* During the great date rewrite of 1.3, we tried to track the
* evolving ECMA standard, which then had a definition of
* getYear which always subtracted 1900. Which we
* implemented, not realizing that it was incompatible with
* the old behavior... now, rather than thrash the behavior
* yet again, we've decided to leave it with the - 1900
* behavior and point people to the getFullYear method. But
* we try to protect existing scripts that have specified a
* version...
*/
return (version == Context.VERSION_1_0
|| version == Context.VERSION_1_1
|| version == Context.VERSION_1_2);
case FEATURE_MEMBER_EXPR_AS_FUNCTION_NAME:
return false;
case FEATURE_RESERVED_KEYWORD_AS_IDENTIFIER:
return false;
case FEATURE_TO_STRING_AS_SOURCE:
return version == VERSION_1_2;
}
// It is a bug to call the method with unknown featureIndex
throw new IllegalArgumentException();
}
/********** end of API **********/
static String getMessage0(String messageId) {
return getMessage(messageId, null);
}
static String getMessage1(String messageId, Object arg1) {
Object[] arguments = {arg1};
return getMessage(messageId, arguments);
}
static String getMessage2(String messageId, Object arg1, Object arg2) {
Object[] arguments = {arg1, arg2};
return getMessage(messageId, arguments);
}
static String getMessage3
(String messageId, Object arg1, Object arg2, Object arg3) {
Object[] arguments = {arg1, arg2, arg3};
return getMessage(messageId, arguments);
}
/**
* Internal method that reports an error for missing calls to
* enter().
*/
static Context getContext() {
Context cx = getCurrentContext();
if (cx == null) {
throw new RuntimeException(
"No Context associated with current Thread");
}
return cx;
}
/* OPT there's a noticable delay for the first error! Maybe it'd
* make sense to use a ListResourceBundle instead of a properties
* file to avoid (synchronized) text parsing.
*/
// bruce: removed referenced to the initial "java" package name
// that used to be there due to a build artifact
static final String defaultResource =
"com.google.gwt.dev.js.rhino.Messages";
static String getMessage(String messageId, Object[] arguments) {
Context cx = getCurrentContext();
Locale locale = cx != null ? cx.getLocale() : Locale.getDefault();
// ResourceBundle does cacheing.
ResourceBundle rb = ResourceBundle.getBundle(defaultResource, locale);
String formatString;
try {
formatString = rb.getString(messageId);
} catch (java.util.MissingResourceException mre) {
throw new RuntimeException
("no message resource found for message property "+ messageId);
}
/*
* It's OK to format the string, even if 'arguments' is null;
* we need to format it anyway, to make double ''s collapse to
* single 's.
*/
// TODO: MessageFormat is not available on pJava
MessageFormat formatter = new MessageFormat(formatString);
return formatter.format(arguments);
}
// debug flags
static final boolean printTrees = true;
static final boolean printICode = true;
final boolean isVersionECMA1() {
return version == VERSION_DEFAULT || version >= VERSION_1_3;
}
// Rudimentary support for Design-by-Contract
static void codeBug() {
throw new RuntimeException("FAILED ASSERTION");
}
static final boolean check = true;
private static Hashtable threadContexts = new Hashtable(11);
private static Object threadLocalCx;
private static Method threadLocalGet;
private static Method threadLocalSet;
int version;
int errorCount;
private ErrorReporter errorReporter;
private Locale locale;
private boolean generatingDebug;
private boolean generatingDebugChanged;
private boolean generatingSource=true;
private boolean compileFunctionsWithDynamicScopeFlag;
private int enterCount;
private Object[] listeners;
private Hashtable hashtable;
private ClassLoader applicationClassLoader;
/**
* This is the list of names of objects forcing the creation of
* function activation records.
*/
private Hashtable activationNames;
// For instruction counting (interpreter only)
int instructionCount;
int instructionThreshold;
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,104 @@
/* -*- 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):
* Norris Boyd
*
* 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.
*/
// Modified by Google
// API class
package com.google.gwt.dev.js.rhino;
/**
* This is interface defines a protocol for the reporting of
* errors during JavaScript translation or execution.
*
* @author Norris Boyd
*/
public interface ErrorReporter {
/**
* Report a warning.
*
* The implementing class may choose to ignore the warning
* if it desires.
*
* @param message a String describing the warning
* @param sourceName a String describing the JavaScript source
* where the warning occured; typically a filename or URL
* @param line the line number associated with the warning
* @param lineSource the text of the line (may be null)
* @param lineOffset the offset into lineSource where problem was detected
*/
void warning(String message, String sourceName, int line,
String lineSource, int lineOffset);
/**
* Report an error.
*
* The implementing class is free to throw an exception if
* it desires.
*
* If execution has not yet begun, the JavaScript engine is
* free to find additional errors rather than terminating
* the translation. It will not execute a script that had
* errors, however.
*
* @param message a String describing the error
* @param sourceName a String describing the JavaScript source
* where the error occured; typically a filename or URL
* @param line the line number associated with the error
* @param lineSource the text of the line (may be null)
* @param lineOffset the offset into lineSource where problem was detected
*/
void error(String message, String sourceName, int line,
String lineSource, int lineOffset);
/**
* Creates an EvaluatorException that may be thrown.
*
* runtimeErrors, unlike errors, will always terminate the
* current script.
*
* @param message a String describing the error
* @param sourceName a String describing the JavaScript source
* where the error occured; typically a filename or URL
* @param line the line number associated with the error
* @param lineSource the text of the line (may be null)
* @param lineOffset the offset into lineSource where problem was detected
* @return an EvaluatorException that will be thrown.
*/
EvaluatorException runtimeError(String message, String sourceName,
int line, String lineSource,
int lineOffset);
}
@@ -0,0 +1,56 @@
/* -*- 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):
* Norris Boyd
*
* 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.
*/
// Modified by Google
package com.google.gwt.dev.js.rhino;
/**
* The class of exceptions thrown by the JavaScript engine.
*/
public class EvaluatorException extends RuntimeException {
/**
* Create an exception with the specified detail message.
*
* Errors internal to the JavaScript engine will simply throw a
* RuntimeException.
*
* @param detail a message with detail about the exception
*/
public EvaluatorException(String detail) {
super(detail);
}
}
@@ -0,0 +1,448 @@
/* -*- 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):
* Norris Boyd
*
* 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 com.google.gwt.dev.js.rhino;
/**
* This class allows the creation of nodes, and follows the Factory pattern.
*
* @see Node
* @author Mike McCabe
* @author Norris Boyd
*/
public class IRFactory {
public IRFactory(TokenStream ts) {
this.ts = ts;
}
/**
* Script (for associating file/url names with toplevel scripts.)
*/
public Object createScript(Object body, String sourceName,
int baseLineno, int endLineno, Object source)
{
Node result = new Node(TokenStream.SCRIPT);
Node children = ((Node) body).getFirstChild();
if (children != null)
result.addChildrenToBack(children);
result.putProp(Node.SOURCENAME_PROP, sourceName);
result.putIntProp(Node.BASE_LINENO_PROP, baseLineno);
result.putIntProp(Node.END_LINENO_PROP, endLineno);
if (source != null)
result.putProp(Node.SOURCE_PROP, source);
return result;
}
/**
* Leaf
*/
public Object createLeaf(int nodeType) {
return new Node(nodeType);
}
public Object createLeaf(int nodeType, int nodeOp) {
return new Node(nodeType, nodeOp);
}
public int getLeafType(Object leaf) {
Node n = (Node) leaf;
return n.getType();
}
/**
* Statement leaf nodes.
*/
public Object createSwitch(int lineno) {
return new Node(TokenStream.SWITCH, lineno);
}
public Object createVariables(int lineno) {
return new Node(TokenStream.VAR, lineno);
}
public Object createExprStatement(Object expr, int lineno) {
return new Node(TokenStream.EXPRSTMT, (Node) expr, lineno);
}
/**
* Name
*/
public Object createName(String name) {
return Node.newString(TokenStream.NAME, name);
}
/**
* String (for literals)
*/
public Object createString(String string) {
return Node.newString(string);
}
/**
* Number (for literals)
*/
public Object createNumber(double number) {
return Node.newNumber(number);
}
/**
* Catch clause of try/catch/finally
* @param varName the name of the variable to bind to the exception
* @param catchCond the condition under which to catch the exception.
* May be null if no condition is given.
* @param stmts the statements in the catch clause
* @param lineno the starting line number of the catch clause
*/
public Object createCatch(String varName, Object catchCond, Object stmts,
int lineno)
{
if (catchCond == null) {
catchCond = new Node(TokenStream.PRIMARY, TokenStream.TRUE);
}
return new Node(TokenStream.CATCH, (Node)createName(varName),
(Node)catchCond, (Node)stmts, lineno);
}
/**
* Throw
*/
public Object createThrow(Object expr, int lineno) {
return new Node(TokenStream.THROW, (Node)expr, lineno);
}
/**
* Return
*/
public Object createReturn(Object expr, int lineno) {
return expr == null
? new Node(TokenStream.RETURN, lineno)
: new Node(TokenStream.RETURN, (Node)expr, lineno);
}
/**
* Label
*/
public Object createLabel(String label, int lineno) {
Node result = new Node(TokenStream.LABEL, lineno);
Node name = Node.newString(TokenStream.NAME, label);
result.addChildToBack(name);
return result;
}
/**
* Break (possibly labeled)
*/
public Object createBreak(String label, int lineno) {
Node result = new Node(TokenStream.BREAK, lineno);
if (label == null) {
return result;
} else {
Node name = Node.newString(TokenStream.NAME, label);
result.addChildToBack(name);
return result;
}
}
/**
* Continue (possibly labeled)
*/
public Object createContinue(String label, int lineno) {
Node result = new Node(TokenStream.CONTINUE, lineno);
if (label == null) {
return result;
} else {
Node name = Node.newString(TokenStream.NAME, label);
result.addChildToBack(name);
return result;
}
}
/**
* debugger
*/
public Object createDebugger(int lineno) {
Node result = new Node(TokenStream.DEBUGGER, lineno);
return result;
}
/**
* Statement block
* Creates the empty statement block
* Must make subsequent calls to add statements to the node
*/
public Object createBlock(int lineno) {
return new Node(TokenStream.BLOCK, lineno);
}
public Object createFunction(String name, Object args, Object statements,
String sourceName, int baseLineno,
int endLineno, Object source,
boolean isExpr)
{
Node f = new Node(TokenStream.FUNCTION,
Node.newString(TokenStream.NAME,
name == null ? "" : name),
(Node)args, (Node)statements, baseLineno);
f.putProp(Node.SOURCENAME_PROP, sourceName);
f.putIntProp(Node.BASE_LINENO_PROP, baseLineno);
f.putIntProp(Node.END_LINENO_PROP, endLineno);
if (source != null)
f.putProp(Node.SOURCE_PROP, source);
return f;
}
/**
* Add a child to the back of the given node. This function
* breaks the Factory abstraction, but it removes a requirement
* from implementors of Node.
*/
public void addChildToBack(Object parent, Object child) {
((Node)parent).addChildToBack((Node)child);
}
/**
* While
*/
public Object createWhile(Object cond, Object body, int lineno) {
return new Node(TokenStream.WHILE, (Node)cond, (Node)body, lineno);
}
/**
* DoWhile
*/
public Object createDoWhile(Object body, Object cond, int lineno) {
return new Node(TokenStream.DO, (Node)body, (Node)cond, lineno);
}
/**
* For
*/
public Object createFor(Object init, Object test, Object incr,
Object body, int lineno)
{
return new Node(TokenStream.FOR, (Node)init, (Node)test, (Node)incr,
(Node)body);
}
/**
* For .. In
*
*/
public Object createForIn(Object lhs, Object obj, Object body, int lineno) {
return new Node(TokenStream.FOR, (Node)lhs, (Node)obj, (Node)body);
}
/**
* Try/Catch/Finally
*/
public Object createTryCatchFinally(Object tryblock, Object catchblocks,
Object finallyblock, int lineno)
{
if (finallyblock == null) {
return new Node(TokenStream.TRY, (Node)tryblock, (Node)catchblocks);
}
return new Node(TokenStream.TRY, (Node)tryblock,
(Node)catchblocks, (Node)finallyblock);
}
/**
* Throw, Return, Label, Break and Continue are defined in ASTFactory.
*/
/**
* With
*/
public Object createWith(Object obj, Object body, int lineno) {
return new Node(TokenStream.WITH, (Node)obj, (Node)body, lineno);
}
/**
* Array Literal
*/
public Object createArrayLiteral(Object obj) {
return obj;
}
/**
* Object Literals
*/
public Object createObjectLiteral(Object obj) {
return obj;
}
/**
* Regular expressions
*/
public Object createRegExp(String string, String flags) {
return flags.length() == 0
? new Node(TokenStream.REGEXP,
Node.newString(string))
: new Node(TokenStream.REGEXP,
Node.newString(string),
Node.newString(flags));
}
/**
* If statement
*/
public Object createIf(Object cond, Object ifTrue, Object ifFalse,
int lineno)
{
if (ifFalse == null)
return new Node(TokenStream.IF, (Node)cond, (Node)ifTrue);
return new Node(TokenStream.IF, (Node)cond, (Node)ifTrue, (Node)ifFalse);
}
public Object createTernary(Object cond, Object ifTrue, Object ifFalse) {
return new Node(TokenStream.HOOK,
(Node)cond, (Node)ifTrue, (Node)ifFalse);
}
/**
* Unary
*/
public Object createUnary(int nodeType, Object child) {
Node childNode = (Node) child;
return new Node(nodeType, childNode);
}
public Object createUnary(int nodeType, int nodeOp, Object child) {
return new Node(nodeType, (Node)child, nodeOp);
}
/**
* Binary
*/
public Object createBinary(int nodeType, Object left, Object right) {
Node temp;
switch (nodeType) {
case TokenStream.DOT:
nodeType = TokenStream.GETPROP;
Node idNode = (Node) right;
idNode.setType(TokenStream.STRING);
String id = idNode.getString();
if (id.equals("__proto__") || id.equals("__parent__")) {
Node result = new Node(nodeType, (Node) left);
result.putProp(Node.SPECIAL_PROP_PROP, id);
return result;
}
break;
case TokenStream.LB:
// OPT: could optimize to GETPROP iff string can't be a number
nodeType = TokenStream.GETELEM;
break;
}
return new Node(nodeType, (Node)left, (Node)right);
}
public Object createBinary(int nodeType, int nodeOp, Object left,
Object right)
{
if (nodeType == TokenStream.ASSIGN) {
return createAssignment(nodeOp, (Node) left, (Node) right,
null, false);
}
return new Node(nodeType, (Node) left, (Node) right, nodeOp);
}
public Object createAssignment(int nodeOp, Node left, Node right,
Class convert, boolean postfix)
{
int nodeType = left.getType();
switch (nodeType) {
case TokenStream.NAME:
case TokenStream.GETPROP:
case TokenStream.GETELEM:
break;
default:
// TODO: This should be a ReferenceError--but that's a runtime
// exception. Should we compile an exception into the code?
reportError("msg.bad.lhs.assign");
}
return new Node(TokenStream.ASSIGN, left, right, nodeOp);
}
private Node createConvert(Class toType, Node expr) {
if (toType == null)
return expr;
Node result = new Node(TokenStream.CONVERT, expr);
result.putProp(Node.TYPE_PROP, Number.class);
return result;
}
public static boolean hasSideEffects(Node exprTree) {
switch (exprTree.getType()) {
case TokenStream.INC:
case TokenStream.DEC:
case TokenStream.SETPROP:
case TokenStream.SETELEM:
case TokenStream.SETNAME:
case TokenStream.CALL:
case TokenStream.NEW:
return true;
default:
Node child = exprTree.getFirstChild();
while (child != null) {
if (hasSideEffects(child))
return true;
else
child = child.getNext();
}
break;
}
return false;
}
private void reportError(String msgResource) {
String message = Context.getMessage0(msgResource);
Context.reportError(
message, ts.getSourceName(), ts.getLineno(),
ts.getLine(), ts.getOffset());
}
// Only needed to get file/line information. Could create an interface
// that TokenStream implements if we want to make the connection less
// direct.
private TokenStream ts;
}
@@ -0,0 +1,85 @@
/* -*- 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):
* Norris Boyd
*
* 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.
*/
// Modified by Google
// API class
package com.google.gwt.dev.js.rhino;
/**
* Java reflection of JavaScript exceptions. (Possibly wrapping a Java exception.)
*
* @author Mike McCabe
*/
public class JavaScriptException extends Exception {
/**
* Create a JavaScript exception wrapping the given JavaScript value.
*
* Instances of this class are thrown by the JavaScript 'throw' keyword.
*
* @param value the JavaScript value thrown.
*/
public JavaScriptException(Object value) {
super(value.toString());
this.value = value;
}
/**
* Get the exception value originally thrown. This may be a
* JavaScript value (null, undefined, Boolean, Number, String,
* Scriptable or Function) or a Java exception value thrown from a
* host object or from Java called through LiveConnect.
*
* @return the value wrapped by this exception
*/
public Object getValue() {
return value;
}
/**
* The JavaScript exception value. This value is not
* intended for general use; if the JavaScriptException wraps a
* Java exception, getScriptableValue may return a Scriptable
* wrapping the original Java exception object.
*
* We would prefer to go through a getter to encapsulate the value,
* however that causes the bizarre error "nanosecond timeout value
* out of range" on the MS JVM.
* @serial
*/
Object value;
}
@@ -0,0 +1,342 @@
/* -*- 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.
*/
// Modified by Google
package com.google.gwt.dev.js.rhino;
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 (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 {
// 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 = true;
}
@@ -0,0 +1,533 @@
#
# Default JavaScript messages file.
#
# 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 oqr
# 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):
# Norris Boyd
#
# 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.
#
# To add JavaScript error messages for a particular locale, create a
# new Messages_[locale].properties file, where [locale] is the Java
# string abbreviation for that locale. For example, JavaScript
# messages for the Polish locale should be located in
# Messages_pl.properties, and messages for the Italian Swiss locale
# should be located in Messages_it_CH.properties. Message properties
# files should be accessible through the classpath under
# org.mozilla.javascript.resources
#
# See:
# java.util.ResourceBundle
# java.text.MessageFormat
#
# SomeJavaClassWhereUsed
# Codegen
msg.dup.parms =\
Duplicate parameter name "{0}".
# Context
msg.ctor.not.found =\
Constructor for "{0}" not found.
msg.not.ctor =\
"{0}" is not a constructor.
# FunctionObject
msg.varargs.ctor =\
Method or constructor "{0}" must be static with the signature \
"(Context cx, Object[] args, Function ctorObj, boolean inNewExpr)" \
to define a variable arguments constructor.
msg.varargs.fun =\
Method "{0}" must be static with the signature \
"(Context cx, Scriptable thisObj, Object[] args, Function funObj)" \
to define a variable arguments function.
msg.incompat.call =\
Method "{0}" called on incompatible object.
msg.bad.parms =\
Bad method parameters for "{0}".
msg.no.overload =\
Method "{0}" occurs multiple times in class "{1}".
msg.method.not.found =\
Method "{0}" not found in "{1}".
# IRFactory
msg.bad.for.in.lhs =\
Invalid left-hand side of for..in loop.
msg.bad.lhs.assign =\
Invalid assignment left-hand side.
msg.mult.index =\
Only one variable allowed in for..in loop.
msg.cant.convert =\
Can''t convert to type "{0}".
# NativeGlobal
msg.cant.call.indirect =\
Function "{0}" must be called directly, and not by way of a \
function of another name.
msg.eval.nonstring =\
Calling eval() with anything other than a primitive string value will \
simply return the value. Is this what you intended?
# NativeCall
msg.only.from.new =\
"{0}" may only be invoked from a "new" expression.
msg.deprec.ctor =\
The "{0}" constructor is deprecated.
# NativeFunction
msg.no.function.ref.found.in =\
no source found in {1} to decompile function reference {0}
msg.no.function.ref.found =\
no source found to decompile function reference {0}
msg.arg.isnt.array =\
second argument to Function.prototype.apply must be an array
# NativeGlobal
msg.bad.esc.mask =\
invalid string escape mask
# NativeJavaClass
msg.cant.instantiate =\
error instantiating ({0}): class {1} is interface or abstract
msg.bad.ctor.sig =\
Found constructor with wrong signature: \
{0} calling {1} with signature {2}
msg.not.java.obj =\
Expected argument to getClass() to be a Java object.
msg.no.java.ctor =\
Java constructor for "{0}" with arguments "{1}" not found.
# NativeJavaMethod
msg.method.ambiguous =\
The choice of Java method {0}.{1} matching JavaScript argument types ({2}) is ambiguous; \
candidate methods are: {3}
msg.constructor.ambiguous =\
The choice of Java constructor {0} matching JavaScript argument types ({1}) is ambiguous; \
candidate constructors are: {2}
# NativeJavaObject
msg.conversion.not.allowed =\
Cannot convert {0} to {1}
# NativeRegExp
msg.bad.quant =\
Invalid quantifier {0}
msg.overlarge.max =\
Overly large maximum {0}
msg.zero.quant =\
Zero quantifier {0}
msg.max.lt.min =\
Maximum {0} less than minimum
msg.unterm.quant =\
Unterminated quantifier {0}
msg.unterm.paren =\
Unterminated parenthetical {0}
msg.unterm.class =\
Unterminated character class {0}
msg.bad.range =\
Invalid range in character class.
msg.trail.backslash =\
Trailing \\ in regular expression.
msg.no.regexp =\
Regular expressions are not available.
msg.bad.backref =\
back-reference exceeds number of capturing parentheses.
# NodeTransformer
msg.dup.label =\
Duplicate label {0}.
msg.undef.label =\
Undefined label {0}.
msg.bad.break =\
Unlabelled break must be inside loop or switch.
msg.continue.outside =\
continue must be inside loop.
msg.continue.nonloop =\
Can only continue to labeled iteration statement.
msg.fn.redecl =\
Function "{0}" redeclared; prior definition will be ignored.
# Parser
msg.no.paren.parms =\
missing ( before function parameters
msg.no.parm =\
missing formal parameter
msg.no.paren.after.parms =\
missing ) after formal parameters
msg.no.brace.body =\
missing '{' before function body
msg.no.brace.after.body =\
missing } after function body
msg.no.paren.cond =\
missing ( before condition
msg.no.paren.after.cond =\
missing ) after condition
msg.no.semi.stmt =\
missing ; before statement
msg.no.name.after.dot =\
missing name after . operator
msg.no.bracket.index =\
missing ] in index expression
msg.no.paren.switch =\
missing ( before switch expression
msg.no.paren.after.switch =\
missing ) after switch expression
msg.no.brace.switch =\
missing '{' before switch body
msg.bad.switch =\
invalid switch statement
msg.no.colon.case =\
missing : after case expression
msg.no.while.do =\
missing while after do-loop body
msg.no.paren.for =\
missing ( after for
msg.no.semi.for =\
missing ; after for-loop initializer
msg.no.semi.for.cond =\
missing ; after for-loop condition
msg.no.paren.for.ctrl =\
missing ) after for-loop control
msg.no.paren.with =\
missing ( before with-statement object
msg.no.paren.after.with =\
missing ) after with-statement object
msg.bad.return =\
invalid return
msg.no.brace.block =\
missing } in compound statement
msg.bad.label =\
invalid label
msg.bad.var =\
missing variable name
msg.bad.var.init =\
invalid variable initialization
msg.no.colon.cond =\
missing : in conditional expression
msg.no.paren.arg =\
missing ) after argument list
msg.no.bracket.arg =\
missing ] after element list
msg.bad.prop =\
invalid property id
msg.no.colon.prop =\
missing : after property id
msg.no.brace.prop =\
missing } after property list
msg.no.paren =\
missing ) in parenthetical
msg.reserved.id =\
identifier is a reserved word
msg.no.paren.catch =\
missing ( before catch-block condition
msg.bad.catchcond =\
invalid catch block condition
msg.catch.unreachable =\
any catch clauses following an unqualified catch are unreachable
msg.no.brace.catchblock =\
missing '{' before catch-block body
msg.try.no.catchfinally =\
''try'' without ''catch'' or ''finally''
msg.syntax =\
syntax error
# ScriptRuntime
msg.assn.create =\
Assignment to undefined "{0}" will create a new variable. \
Add a variable statement at the top level scope to remove this warning.
msg.prop.not.found =\
Property not found.
msg.invalid.type =\
Invalid JavaScript value of type {0}
msg.primitive.expected =\
Primitive type expected (had {0} instead)
msg.null.to.object =\
Cannot convert null to an object.
msg.undef.to.object =\
Cannot convert undefined to an object.
msg.cyclic.value =\
Cyclic {0} value not allowed.
msg.is.not.defined =\
"{0}" is not defined.
msg.isnt.function =\
{0} is not a function.
msg.bad.default.value =\
Object''s getDefaultValue() method returned an object.
msg.instanceof.not.object = \
Can''t use instanceof on a non-object.
msg.instanceof.bad.prototype = \
''prototype'' property of {0} is not an object.
msg.bad.radix = \
illegal radix {0}.
# ScriptableObject
msg.default.value =\
Cannot find default value for object.
msg.zero.arg.ctor =\
Cannot load class "{0}" which has no zero-parameter constructor.
msg.multiple.ctors =\
Cannot have more than one constructor method, but found both {0} and {1}.
msg.ctor.multiple.parms =\
Can''t define constructor or class {0} since more than one \
constructor has multiple parameters.
msg.extend.scriptable =\
{0} must extend ScriptableObject in order to define property {1}.
msg.bad.getter.parms =\
In order to define a property, getter {0} must have zero parameters \
or a single ScriptableObject parameter.
msg.obj.getter.parms =\
Expected static or delegated getter {0} to take a ScriptableObject parameter.
msg.getter.static =\
Getter and setter must both be static or neither be static.
msg.setter2.parms =\
Two-parameter setter must take a ScriptableObject as its first parameter.
msg.setter1.parms =\
Expected single parameter setter for {0}
msg.setter2.expected =\
Expected static or delegated setter {0} to take two parameters.
msg.setter.parms =\
Expected either one or two parameters for setter.
msg.add.sealed =\
Cannot add a property to a sealed object.
msg.remove.sealed =\
Cannot remove a property from a sealed object.
# TokenStream
msg.token.replaces.pushback =\
ungot token {0} replaces pushback token {1}
msg.missing.exponent =\
missing exponent
msg.caught.nfe =\
number format error: {0}
msg.unterminated.string.lit =\
unterminated string literal
msg.oct.esc.too.large =\
octal escape too large
msg.unterminated.comment =\
unterminated comment
msg.unterminated.re.lit =\
unterminated regular expression literal
msg.invalid.re.flag =\
invalid flag after regular expression
msg.no.re.input.for =\
no input for {0}
msg.illegal.character =\
illegal character
msg.invalid.escape =\
invalid Unicode escape sequence
# TokensStream warnings
msg.bad.octal.literal =\
illegal octal literal digit {0}; interpreting it as a decimal digit
msg.reserved.keyword =\
illegal usage of future reserved keyword {0}; interpreting it as ordinary identifier
# Undefined
msg.undefined =\
The undefined value has no properties.
# LiveConnect errors
msg.java.internal.field.type =\
Internal error: type conversion of {0} to assign to {1} on {2} failed.
msg.java.conversion.implicit_method =\
Can''t find converter method "{0}" on class {1}.
msg.java.method.assign =\
Java method "{0}" cannot be assigned to.
msg.java.internal.private =\
Internal error: attempt to access private/protected field "{0}".
msg.java.no_such_method =\
Can''t find method {0}.
msg.script.is.not.constructor =\
Script objects are not constructors.
msg.nonjava.method =\
Java method "{0}" was invoked with a ''this'' value that was not a Java object.
msg.java.member.not.found =\
Java class "{0}" has no public instance field or method named "{1}".
msg.pkg.int =\
Java package names may not be numbers.
# ImporterTopLevel
msg.ambig.import =\
Ambiguous import: "{0}" and and "{1}".
msg.not.pkg =\
Function importPackage must be called with a package; had "{0}" instead.
msg.not.class =\
Function importClass must be called with a class; had "{0}" instead.
msg.prop.defined =\
Cannot import "{0}" since a property by that name is already defined.
# Arrays
msg.arraylength.bad =\
Inappropriate array length.
# URI
msg.bad.uri =\
Malformed URI sequence.
# Number
msg.bad.precision =\
Precision {0} out of range.
# JSNI
msg.jsni.expected.char =\
Expected "{0}" in JSNI reference
msg.jsni.expected.identifier =\
Expected an identifier in JSNI reference
msg.jsni.unexpected.identifier =\
Unexpected character in JSNI reference
msg.jsni.expected.param.type =\
Expected a valid parameter type signature in JSNI method reference
msg.jsni.unsupported.with =\
The ''with'' statement is unsupported in JSNI blocks (perhaps you could use a local variable instead?)
@@ -0,0 +1,725 @@
/* -*- 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):
* Norris Boyd
* Roger Lawrence
* 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.
*/
// Modified by Google
package com.google.gwt.dev.js.rhino;
/**
* This class implements the root of the intermediate representation.
*
* @author Norris Boyd
* @author Mike McCabe
*/
public class Node implements Cloneable {
private static class NumberNode extends Node {
NumberNode(double number) {
super(TokenStream.NUMBER);
this.number = number;
}
@Override
public double getDouble() {
return this.number;
}
@Override
public boolean equals(Object o) {
return o instanceof NumberNode
&& getDouble() == ((NumberNode) o).getDouble();
}
private double number;
}
private static class StringNode extends Node {
StringNode(int type, String str) {
super(type);
if (null == str) {
throw new IllegalArgumentException("StringNode: str is null");
}
this.str = str;
}
/** returns the string content.
* @return non null.
*/
@Override
public String getString() {
return this.str;
}
/** sets the string content.
* @param str the new value. Non null.
*/
@Override
public void setString(String str) {
if (null == str) {
throw new IllegalArgumentException("StringNode: str is null");
}
this.str = str;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof StringNode)) { return false; }
return o instanceof StringNode
&& this.str.equals(((StringNode) o).str);
}
private String str;
}
public Node(int nodeType) {
type = nodeType;
}
public Node(int nodeType, Node child) {
type = nodeType;
first = last = child;
child.next = null;
}
public Node(int nodeType, Node left, Node right) {
type = nodeType;
first = left;
last = right;
left.next = right;
right.next = null;
}
public Node(int nodeType, Node left, Node mid, Node right) {
type = nodeType;
first = left;
last = right;
left.next = mid;
mid.next = right;
right.next = null;
}
public Node(int nodeType, Node left, Node mid, Node mid2, Node right) {
type = nodeType;
first = left;
last = right;
left.next = mid;
mid.next = mid2;
mid2.next = right;
right.next = null;
}
public Node(int nodeType, Node[] children) {
this.type = nodeType;
if (children.length != 0) {
this.first = children[0];
this.last = children[children.length - 1];
for (int i = 1; i < children.length; i++) {
if (null != children[i - 1].next) {
// fail early on loops. implies same node in array twice
throw new IllegalArgumentException("duplicate child");
}
children[i - 1].next = children[i];
}
if (null != this.last.next) {
// fail early on loops. implies same node in array twice
throw new IllegalArgumentException("duplicate child");
}
}
}
public Node(int nodeType, int value) {
type = nodeType;
intDatum = value;
}
public Node(int nodeType, Node child, int value) {
this(nodeType, child);
intDatum = value;
}
public Node(int nodeType, Node left, Node right, int value) {
this(nodeType, left, right);
intDatum = value;
}
public Node(int nodeType, Node left, Node mid, Node right, int value) {
this(nodeType, left, mid, right);
intDatum = value;
}
public static Node newNumber(double number) {
return new NumberNode(number);
}
public static Node newString(String str) {
return new StringNode(TokenStream.STRING, str);
}
public static Node newString(int type, String str) {
return new StringNode(type, str);
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public int getIntDatum() {
return this.intDatum;
}
public boolean hasChildren() {
return first != null;
}
public Node getFirstChild() {
return first;
}
public Node getLastChild() {
return last;
}
public Node getNext() {
return next;
}
public int getChildCount() {
int c = 0;
for (Node n = first; n != null; n = n.next)
c++;
return c;
}
public Node getChildBefore(Node child) {
if (child == first)
return null;
Node n = first;
while (n.next != child) {
n = n.next;
if (n == null)
throw new RuntimeException("node is not a child");
}
return n;
}
public Node getLastSibling() {
Node n = this;
while (n.next != null) {
n = n.next;
}
return n;
}
public void addChildToFront(Node child) {
child.next = first;
first = child;
if (last == null) {
last = child;
}
}
public void addChildToBack(Node child) {
child.next = null;
if (last == null) {
first = last = child;
return;
}
last.next = child;
last = child;
}
public void addChildrenToFront(Node children) {
Node lastSib = children.getLastSibling();
lastSib.next = first;
first = children;
if (last == null) {
last = lastSib;
}
}
public void addChildrenToBack(Node children) {
if (last != null) {
last.next = children;
}
last = children.getLastSibling();
if (first == null) {
first = children;
}
}
/**
* Add 'child' before 'node'.
*/
public void addChildBefore(Node newChild, Node node) {
if (newChild.next != null)
throw new RuntimeException(
"newChild had siblings in addChildBefore");
if (first == node) {
newChild.next = first;
first = newChild;
return;
}
Node prev = getChildBefore(node);
addChildAfter(newChild, prev);
}
/**
* Add 'child' after 'node'.
*/
public void addChildAfter(Node newChild, Node node) {
if (newChild.next != null)
throw new RuntimeException(
"newChild had siblings in addChildAfter");
newChild.next = node.next;
node.next = newChild;
if (last == node)
last = newChild;
}
public void removeChild(Node child) {
Node prev = getChildBefore(child);
if (prev == null)
first = first.next;
else
prev.next = child.next;
if (child == last) last = prev;
child.next = null;
}
public void replaceChild(Node child, Node newChild) {
newChild.next = child.next;
if (child == first) {
first = newChild;
} else {
Node prev = getChildBefore(child);
prev.next = newChild;
}
if (child == last)
last = newChild;
child.next = null;
}
public void replaceChildAfter(Node prevChild, Node newChild) {
Node child = prevChild.next;
newChild.next = child.next;
prevChild.next = newChild;
if (child == last)
last = newChild;
child.next = null;
}
public static final int
TARGET_PROP = 1,
BREAK_PROP = 2,
CONTINUE_PROP = 3,
ENUM_PROP = 4,
FUNCTION_PROP = 5,
TEMP_PROP = 6,
LOCAL_PROP = 7,
CODEOFFSET_PROP = 8,
FIXUPS_PROP = 9,
VARS_PROP = 10,
USES_PROP = 11,
REGEXP_PROP = 12,
CASES_PROP = 13,
DEFAULT_PROP = 14,
CASEARRAY_PROP = 15,
SOURCENAME_PROP = 16,
SOURCE_PROP = 17,
TYPE_PROP = 18,
SPECIAL_PROP_PROP = 19,
LABEL_PROP = 20,
FINALLY_PROP = 21,
LOCALCOUNT_PROP = 22,
/*
the following properties are defined and manipulated by the
optimizer -
TARGETBLOCK_PROP - the block referenced by a branch node
VARIABLE_PROP - the variable referenced by a BIND or NAME node
LASTUSE_PROP - that variable node is the last reference before
a new def or the end of the block
ISNUMBER_PROP - this node generates code on Number children and
delivers a Number result (as opposed to Objects)
DIRECTCALL_PROP - this call node should emit code to test the function
object against the known class and call diret if it
matches.
*/
TARGETBLOCK_PROP = 23,
VARIABLE_PROP = 24,
LASTUSE_PROP = 25,
ISNUMBER_PROP = 26,
DIRECTCALL_PROP = 27,
BASE_LINENO_PROP = 28,
END_LINENO_PROP = 29,
SPECIALCALL_PROP = 30,
DEBUGSOURCE_PROP = 31;
public static final int // this value of the ISNUMBER_PROP specifies
BOTH = 0, // which of the children are Number types
LEFT = 1,
RIGHT = 2;
private static final String propToString(int propType) {
switch (propType) {
case TARGET_PROP: return "target";
case BREAK_PROP: return "break";
case CONTINUE_PROP: return "continue";
case ENUM_PROP: return "enum";
case FUNCTION_PROP: return "function";
case TEMP_PROP: return "temp";
case LOCAL_PROP: return "local";
case CODEOFFSET_PROP: return "codeoffset";
case FIXUPS_PROP: return "fixups";
case VARS_PROP: return "vars";
case USES_PROP: return "uses";
case REGEXP_PROP: return "regexp";
case CASES_PROP: return "cases";
case DEFAULT_PROP: return "default";
case CASEARRAY_PROP: return "casearray";
case SOURCENAME_PROP: return "sourcename";
case SOURCE_PROP: return "source";
case TYPE_PROP: return "type";
case SPECIAL_PROP_PROP: return "special_prop";
case LABEL_PROP: return "label";
case FINALLY_PROP: return "finally";
case LOCALCOUNT_PROP: return "localcount";
case TARGETBLOCK_PROP: return "targetblock";
case VARIABLE_PROP: return "variable";
case LASTUSE_PROP: return "lastuse";
case ISNUMBER_PROP: return "isnumber";
case DIRECTCALL_PROP: return "directcall";
case BASE_LINENO_PROP: return "base_lineno";
case END_LINENO_PROP: return "end_lineno";
case SPECIALCALL_PROP: return "specialcall";
case DEBUGSOURCE_PROP: return "debugsource";
default: Context.codeBug();
}
return null;
}
public Object getProp(int propType) {
if (props == null)
return null;
return props.getObject(propType);
}
public int getIntProp(int propType, int defaultValue) {
if (props == null)
return defaultValue;
return props.getInt(propType, defaultValue);
}
public int getExistingIntProp(int propType) {
return props.getExistingInt(propType);
}
public void putProp(int propType, Object prop) {
if (prop == null) {
removeProp(propType);
}
else {
if (props == null) {
props = new UintMap(2);
}
props.put(propType, prop);
}
}
public void putIntProp(int propType, int prop) {
if (props == null)
props = new UintMap(2);
props.put(propType, prop);
}
public void removeProp(int propType) {
if (props != null) {
props.remove(propType);
}
}
public int getOperation() {
switch (type) {
case TokenStream.EQOP:
case TokenStream.RELOP:
case TokenStream.UNARYOP:
case TokenStream.PRIMARY:
return intDatum;
}
Context.codeBug();
return 0;
}
public int getLineno() {
if (hasLineno()) {
return intDatum;
}
return -1;
}
private boolean hasLineno() {
switch (type) {
case TokenStream.EXPRSTMT:
case TokenStream.BLOCK:
case TokenStream.VAR:
case TokenStream.WHILE:
case TokenStream.DO:
case TokenStream.SWITCH:
case TokenStream.CATCH:
case TokenStream.THROW:
case TokenStream.RETURN:
case TokenStream.BREAK:
case TokenStream.CONTINUE:
case TokenStream.WITH:
return true;
}
return false;
}
/** Can only be called when <tt>getType() == TokenStream.NUMBER</tt> */
public double getDouble() throws UnsupportedOperationException {
throw new UnsupportedOperationException(this + " is not a number node");
}
/** Can only be called when node has String context. */
public String getString() throws UnsupportedOperationException {
throw new UnsupportedOperationException(this + " is not a string node");
}
/** Can only be called when node has String context. */
public void setString(String s) throws UnsupportedOperationException {
throw new UnsupportedOperationException(this + " is not a string node");
}
/**
* Not usefully implemented.
*/
@Override
public final int hashCode() {
assert false : "hashCode not designed";
return 42; // any arbitrary constant will do
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Node)) { return false; }
return hasLineno()
|| this.getIntDatum() == ((Node) o).getIntDatum();
}
public Node cloneNode() {
Node result;
try {
result = (Node) super.clone();
result.next = null;
result.first = null;
result.last = null;
}
catch (CloneNotSupportedException e) {
throw new RuntimeException(e.getMessage());
}
return result;
}
public Node cloneTree() {
Node result = cloneNode();
for (Node n2 = getFirstChild(); n2 != null; n2 = n2.getNext()) {
Node n2clone = n2.cloneTree();
if (result.last != null) {
result.last.next = n2clone;
}
if (result.first == null) {
result.first = n2clone;
}
result.last = n2clone;
}
return result;
}
@Override
public String toString() {
if (Context.printTrees) {
StringBuffer sb = new StringBuffer(TokenStream.tokenToName(type));
if (this instanceof StringNode) {
sb.append(' ');
sb.append(getString());
} else {
switch (type) {
case TokenStream.TARGET:
sb.append(' ');
sb.append(hashCode());
break;
case TokenStream.NUMBER:
sb.append(' ');
sb.append(getDouble());
break;
case TokenStream.FUNCTION:
sb.append(' ');
sb.append(first.getString());
break;
}
}
if (intDatum != -1) {
sb.append(' ');
sb.append(intDatum);
}
if (props == null)
return sb.toString();
int[] keys = props.getKeys();
for (int i = 0; i != keys.length; ++i) {
int key = keys[i];
sb.append(" [");
sb.append(propToString(key));
sb.append(": ");
switch (key) {
case FIXUPS_PROP : // can't add this as it recurses
sb.append("fixups property");
break;
case SOURCE_PROP : // can't add this as it has unprintables
sb.append("source property");
break;
case TARGETBLOCK_PROP : // can't add this as it recurses
sb.append("target block property");
break;
case LASTUSE_PROP : // can't add this as it is dull
sb.append("last use property");
break;
default :
Object obj = props.getObject(key);
if (obj != null) {
sb.append(obj.toString());
} else {
sb.append(props.getExistingInt(key));
}
break;
}
sb.append(']');
}
return sb.toString();
}
return null;
}
public String toStringTree() {
return toStringTreeHelper(0);
}
private String toStringTreeHelper(int level) {
if (Context.printTrees) {
StringBuffer s = new StringBuffer();
for (int i=0; i < level; i++) {
s.append(" ");
}
s.append(toString());
s.append('\n');
for (Node cursor = getFirstChild(); cursor != null;
cursor = cursor.getNext())
{
Node n = cursor;
s.append(n.toStringTreeHelper(level+1));
}
return s.toString();
}
return "";
}
/**
* Checks if the subtree under this node is the same as another subtree.
* Returns null if it's equal, or a message describing the differences.
*/
public String checkTreeEquals(Node node2) {
boolean eq = false;
if (type == node2.getType() &&
getChildCount() == node2.getChildCount() &&
getClass() == node2.getClass()) {
eq = this.equals(node2);
}
if (!eq) {
return "Node tree inequality:\nTree1:\n" + toStringTreeHelper(1) +
"\n\nTree2:\n" + node2.toStringTreeHelper(1);
}
String res = null;
Node n, n2;
for (n = first, n2 = node2.first;
res == null && n != null;
n = n.next, n2 = n2.next) {
res = n.checkTreeEquals(n2);
if (res != null) {
return res;
}
}
return res;
}
public void setIsSyntheticBlock(boolean val) {
isSyntheticBlock = val;
}
public boolean isSyntheticBlock() {
return isSyntheticBlock;
}
int type; // type of the node; TokenStream.NAME for example
Node next; // next sibling
private Node first; // first element of a linked list of children
private Node last; // last element of a linked list of children
private int intDatum = -1; // encapsulated int data; depends on type
private UintMap props;
private boolean isSyntheticBlock = false;
}
@@ -0,0 +1,697 @@
/* -*- 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 oqr
* 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-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* 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
* 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.
*/
// Modified by Google
package com.google.gwt.dev.js.rhino;
import java.io.Serializable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* Map to associate objects to integers.
* The map does not synchronize any of its operation, so either use
* it from a single thread or do own synchronization or perform all mutation
* operations on one thread before passing the map to others
*
* @author Igor Bukanov
*
*/
public class ObjToIntMap implements Serializable {
public static final Object NULL_VALUE = new String("");
// Map implementation via hashtable,
// follows "The Art of Computer Programming" by Donald E. Knuth
// ObjToIntMap is a copy cat of ObjToIntMap with API adjusted to object keys
public static class Iterator {
Iterator(ObjToIntMap master) {
this.master = master;
}
final void init(Object[] keys, int[] values, int keyCount) {
this.keys = keys;
this.values = values;
this.cursor = -1;
this.remaining = keyCount;
}
public void start() {
master.initIterator(this);
next();
}
public boolean done() {
return remaining < 0;
}
public void next() {
if (remaining == -1) Context.codeBug();
if (remaining == 0) {
remaining = -1;
cursor = -1;
}else {
for (++cursor; ; ++cursor) {
Object key = keys[cursor];
if (key != null && key != DELETED) {
--remaining;
break;
}
}
}
}
public Object getKey() {
Object key = keys[cursor];
if (key == NULL_VALUE) { key = null; }
return key;
}
public int getValue() {
return values[cursor];
}
public void setValue(int value) {
values[cursor] = value;
}
ObjToIntMap master;
private int cursor;
private int remaining;
private Object[] keys;
private int[] values;
}
public ObjToIntMap() {
this(4);
}
public ObjToIntMap(int keyCountHint) {
if (keyCountHint < 0) Context.codeBug();
// Table grow when number of stored keys >= 3/4 of max capacity
int minimalCapacity = keyCountHint * 4 / 3;
int i;
for (i = 2; (1 << i) < minimalCapacity; ++i) { }
power = i;
if (check && power < 2) Context.codeBug();
}
public boolean isEmpty() {
return keyCount == 0;
}
public int size() {
return keyCount;
}
public boolean has(Object key) {
if (key == null) { key = NULL_VALUE; }
return 0 <= findIndex(key);
}
/**
* Get integer value assigned with key.
* @return key integer value or defaultValue if key is absent
*/
public int get(Object key, int defaultValue) {
if (key == null) { key = NULL_VALUE; }
int index = findIndex(key);
if (0 <= index) {
return values[index];
}
return defaultValue;
}
/**
* Get integer value assigned with key.
* @return key integer value
* @throws RuntimeException if key does not exist
*/
public int getExisting(Object key) {
if (key == null) { key = NULL_VALUE; }
int index = findIndex(key);
if (0 <= index) {
return values[index];
}
// Key must exist
Context.codeBug();
return 0;
}
public void put(Object key, int value) {
if (key == null) { key = NULL_VALUE; }
int index = ensureIndex(key);
values[index] = value;
}
/**
* If table already contains a key that equals to keyArg, return that key
* while setting its value to zero, otherwise add keyArg with 0 value to
* the table and return it.
*/
public Object intern(Object keyArg) {
boolean nullKey = false;
if (keyArg == null) {
nullKey = true;
keyArg = NULL_VALUE;
}
int index = ensureIndex(keyArg);
values[index] = 0;
return (nullKey) ? null : keys[index];
}
public void remove(Object key) {
if (key == null) { key = NULL_VALUE; }
int index = findIndex(key);
if (0 <= index) {
keys[index] = DELETED;
--keyCount;
}
}
public void clear() {
int i = keys.length;
while (i != 0) {
keys[--i] = null;
}
keyCount = 0;
occupiedCount = 0;
}
public Iterator newIterator() {
return new Iterator(this);
}
// The sole purpose of the method is to avoid accessing private fields
// from the Iterator inner class to workaround JDK 1.1 compiler bug which
// generates code triggering VerifierError on recent JVMs
final void initIterator(Iterator i) {
i.init(keys, values, keyCount);
}
/** Return array of present keys */
public Object[] getKeys() {
Object[] array = new Object[keyCount];
getKeys(array, 0);
return array;
}
public void getKeys(Object[] array, int offset) {
int count = keyCount;
for (int i = 0; count != 0; ++i) {
Object key = keys[i];
if (key != null && key != DELETED) {
if (key == NULL_VALUE) { key = null; }
array[offset] = key;
++offset;
--count;
}
}
}
private static int tableLookupStep(int fraction, int mask, int power) {
int shift = 32 - 2 * power;
if (shift >= 0) {
return ((fraction >>> shift) & mask) | 1;
}
else {
return (fraction & (mask >>> -shift)) | 1;
}
}
private int findIndex(Object key) {
if (keys != null) {
int hash = key.hashCode();
int fraction = hash * A;
int index = fraction >>> (32 - power);
Object test = keys[index];
if (test != null) {
int N = 1 << power;
if (test == key
|| (values[N + index] == hash && test.equals(key)))
{
return index;
}
// Search in table after first failed attempt
int mask = N - 1;
int step = tableLookupStep(fraction, mask, power);
int n = 0;
for (;;) {
if (check) {
if (n >= occupiedCount) Context.codeBug();
++n;
}
index = (index + step) & mask;
test = keys[index];
if (test == null) {
break;
}
if (test == key
|| (values[N + index] == hash && test.equals(key)))
{
return index;
}
}
}
}
return -1;
}
// Insert key that is not present to table without deleted entries
// and enough free space
private int insertNewKey(Object key, int hash) {
if (check && occupiedCount != keyCount) Context.codeBug();
if (check && keyCount == 1 << power) Context.codeBug();
int fraction = hash * A;
int index = fraction >>> (32 - power);
int N = 1 << power;
if (keys[index] != null) {
int mask = N - 1;
int step = tableLookupStep(fraction, mask, power);
int firstIndex = index;
do {
if (check && keys[index] == DELETED) Context.codeBug();
index = (index + step) & mask;
if (check && firstIndex == index) Context.codeBug();
} while (keys[index] != null);
}
keys[index] = key;
values[N + index] = hash;
++occupiedCount;
++keyCount;
return index;
}
private void rehashTable() {
if (keys == null) {
if (check && keyCount != 0) Context.codeBug();
if (check && occupiedCount != 0) Context.codeBug();
int N = 1 << power;
keys = new Object[N];
values = new int[2 * N];
}
else {
// Check if removing deleted entries would free enough space
if (keyCount * 2 >= occupiedCount) {
// Need to grow: less then half of deleted entries
++power;
}
int N = 1 << power;
Object[] oldKeys = keys;
int[] oldValues = values;
int oldN = oldKeys.length;
keys = new Object[N];
values = new int[2 * N];
int remaining = keyCount;
occupiedCount = keyCount = 0;
for (int i = 0; remaining != 0; ++i) {
Object key = oldKeys[i];
if (key != null && key != DELETED) {
int keyHash = oldValues[oldN + i];
int index = insertNewKey(key, keyHash);
values[index] = oldValues[i];
--remaining;
}
}
}
}
// Ensure key index creating one if necessary
private int ensureIndex(Object key) {
int hash = key.hashCode();
int index = -1;
int firstDeleted = -1;
if (keys != null) {
int fraction = hash * A;
index = fraction >>> (32 - power);
Object test = keys[index];
if (test != null) {
int N = 1 << power;
if (test == key
|| (values[N + index] == hash && test.equals(key)))
{
return index;
}
if (test == DELETED) {
firstDeleted = index;
}
// Search in table after first failed attempt
int mask = N - 1;
int step = tableLookupStep(fraction, mask, power);
int n = 0;
for (;;) {
if (check) {
if (n >= occupiedCount) Context.codeBug();
++n;
}
index = (index + step) & mask;
test = keys[index];
if (test == null) {
break;
}
if (test == key
|| (values[N + index] == hash && test.equals(key)))
{
return index;
}
if (test == DELETED && firstDeleted < 0) {
firstDeleted = index;
}
}
}
}
// Inserting of new key
if (check && keys != null && keys[index] != null)
Context.codeBug();
if (firstDeleted >= 0) {
index = firstDeleted;
}
else {
// Need to consume empty entry: check occupation level
if (keys == null || occupiedCount * 4 >= (1 << power) * 3) {
// Too litle unused entries: rehash
rehashTable();
return insertNewKey(key, hash);
}
++occupiedCount;
}
keys[index] = key;
values[(1 << power) + index] = hash;
++keyCount;
return index;
}
private void writeObject(ObjectOutputStream out)
throws IOException
{
out.defaultWriteObject();
int count = keyCount;
for (int i = 0; count != 0; ++i) {
Object key = keys[i];
if (key != null && key != DELETED) {
--count;
out.writeObject(key);
out.writeInt(values[i]);
}
}
}
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
int writtenKeyCount = keyCount;
if (writtenKeyCount != 0) {
keyCount = 0;
int N = 1 << power;
keys = new Object[N];
values = new int[2 * N];
for (int i = 0; i != writtenKeyCount; ++i) {
Object key = in.readObject();
int hash = key.hashCode();
int index = insertNewKey(key, hash);
values[index] = in.readInt();
}
}
}
static final long serialVersionUID = 3396438333234169727L;
// A == golden_ratio * (1 << 32) = ((sqrt(5) - 1) / 2) * (1 << 32)
// See Knuth etc.
private static final int A = 0x9e3779b9;
private static final Object DELETED = new Object();
// Structure of kyes and values arrays (N == 1 << power):
// keys[0 <= i < N]: key value or null or DELETED mark
// values[0 <= i < N]: value of key at keys[i]
// values[N <= i < 2*N]: hash code of key at keys[i-N]
private transient Object[] keys;
private transient int[] values;
private int power;
private int keyCount;
private transient int occupiedCount; // == keyCount + deleted_count
// If true, enables consitency checks
private static final boolean check = false;
/* TEST START
public static void main(String[] args) {
if (!check) {
System.err.println("Set check to true and re-run");
throw new RuntimeException("Set check to true and re-run");
}
ObjToIntMap map;
map = new ObjToIntMap(0);
testHash(map, 3);
map = new ObjToIntMap(0);
testHash(map, 10 * 1000);
map = new ObjToIntMap();
testHash(map, 10 * 1000);
map = new ObjToIntMap(30 * 1000);
testHash(map, 10 * 100);
map.clear();
testHash(map, 4);
map = new ObjToIntMap(0);
testHash(map, 10 * 100);
}
private static void testHash(ObjToIntMap map, int N) {
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
Object key = testKey(i);
check(-1 == map.get(key, -1));
map.put(key, i);
check(i == map.get(key, -1));
}
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
Object key = testKey(i);
map.put(key, i);
check(i == map.get(key, -1));
}
check(map.size() == N);
System.out.print("."); System.out.flush();
Object[] keys = map.getKeys();
check(keys.length == N);
for (int i = 0; i != N; ++i) {
Object key = keys[i];
check(map.has(key));
}
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
Object key = testKey(i);
check(i == map.get(key, -1));
}
int Nsqrt = -1;
for (int i = 0; ; ++i) {
if (i * i >= N) {
Nsqrt = i;
break;
}
}
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
Object key = testKey(i * i);
map.put(key, i);
check(i == map.get(key, -1));
}
check(map.size() == 2 * N - Nsqrt);
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
Object key = testKey(i * i);
check(i == map.get(key, -1));
}
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
Object key = testKey(-1 - i * i);
map.put(key, i);
check(i == map.get(key, -1));
}
check(map.size() == 3 * N - Nsqrt);
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
Object key = testKey(-1 - i * i);
map.remove(key);
check(!map.has(key));
}
check(map.size() == 2 * N - Nsqrt);
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
Object key = testKey(i * i);
check(i == map.get(key, -1));
}
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
Object key = testKey(i);
int j = intSqrt(i);
if (j * j == i) {
check(j == map.get(key, -1));
}else {
check(i == map.get(key, -1));
}
}
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
Object key = testKey(i * i);
map.remove(key);
check(-2 == map.get(key, -2));
}
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
Object key = testKey(i);
map.put(key, i);
check(i == map.get(key, -2));
}
check(map.size() == N);
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
Object key = testKey(i);
check(i == map.get(key, -1));
}
System.out.print("."); System.out.flush();
ObjToIntMap copy = (ObjToIntMap)writeAndRead(map);
check(copy.size() == N);
for (int i = 0; i != N; ++i) {
Object key = testKey(i);
check(i == copy.get(key, -1));
}
System.out.print("."); System.out.flush();
checkSameMaps(copy, map);
System.out.println(); System.out.flush();
}
private static void checkSameMaps(ObjToIntMap map1, ObjToIntMap map2) {
check(map1.size() == map2.size());
Object[] keys = map1.getKeys();
check(keys.length == map1.size());
for (int i = 0; i != keys.length; ++i) {
check(map1.get(keys[i], -1) == map2.get(keys[i], -1));
}
}
private static void check(boolean condition) {
if (!condition) Context.codeBug();
}
private static Object[] testPool;
private static Object testKey(int i) {
int MAX_POOL = 100;
if (0 <= i && i < MAX_POOL) {
if (testPool != null && testPool[i] != null) {
return testPool[i];
}
}
Object x = new Double(i + 0.5);
if (0 <= i && i < MAX_POOL) {
if (testPool == null) {
testPool = new Object[MAX_POOL];
}
testPool[i] = x;
}
return x;
}
private static int intSqrt(int i) {
int approx = (int)Math.sqrt(i) + 1;
while (approx * approx > i) {
--approx;
}
return approx;
}
private static Object writeAndRead(Object obj) {
try {
java.io.ByteArrayOutputStream
bos = new java.io.ByteArrayOutputStream();
java.io.ObjectOutputStream
out = new java.io.ObjectOutputStream(bos);
out.writeObject(obj);
out.close();
byte[] data = bos.toByteArray();
java.io.ByteArrayInputStream
bis = new java.io.ByteArrayInputStream(data);
java.io.ObjectInputStream
in = new java.io.ObjectInputStream(bis);
Object result = in.readObject();
in.close();
return result;
}catch (Exception ex) {
throw new RuntimeException("Unexpected");
}
}
// TEST END */
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,240 @@
/* -*- 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-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Patrick Beard
* Norris Boyd
* Igor Bukanov
* Roger Lawrence
* Frank Mitchell
* Andrew Wason
*
* 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.
*/
// Modified by Google
package com.google.gwt.dev.js.rhino;
/**
* This is the class that implements the runtime.
*
* @author Norris Boyd
*/
public class ScriptRuntime {
public static double NaN = 0.0d / 0.0;
public static String numberToString(double d, int base) {
if (Double.isNaN(d))
return "NaN";
if (d == Double.POSITIVE_INFINITY)
return "Infinity";
if (d == Double.NEGATIVE_INFINITY)
return "-Infinity";
if (d == 0.0)
return "0";
if ((base < 2) || (base > 36)) {
throw new Error(Context.getMessage1("msg.bad.radix",
Integer.toString(base)));
}
if (base != 10) {
return DToA.JS_dtobasestr(base, d);
} else {
StringBuffer result = new StringBuffer();
DToA.JS_dtostr(result, DToA.DTOSTR_STANDARD, 0, d);
return result.toString();
}
}
/*
* Helper function for toNumber, parseInt, and TokenStream.getToken.
*/
static double stringToNumber(String s, int start, int radix) {
char digitMax = '9';
char lowerCaseBound = 'a';
char upperCaseBound = 'A';
int len = s.length();
if (radix < 10) {
digitMax = (char) ('0' + radix - 1);
}
if (radix > 10) {
lowerCaseBound = (char) ('a' + radix - 10);
upperCaseBound = (char) ('A' + radix - 10);
}
int end;
double sum = 0.0;
for (end=start; end < len; end++) {
char c = s.charAt(end);
int newDigit;
if ('0' <= c && c <= digitMax)
newDigit = c - '0';
else if ('a' <= c && c < lowerCaseBound)
newDigit = c - 'a' + 10;
else if ('A' <= c && c < upperCaseBound)
newDigit = c - 'A' + 10;
else
break;
sum = sum*radix + newDigit;
}
if (start == end) {
return NaN;
}
if (sum >= 9007199254740992.0) {
if (radix == 10) {
/* If we're accumulating a decimal number and the number
* is >= 2^53, then the result from the repeated multiply-add
* above may be inaccurate. Call Java to get the correct
* answer.
*/
try {
return Double.valueOf(s.substring(start, end)).doubleValue();
} catch (NumberFormatException nfe) {
return NaN;
}
} else if (radix == 2 || radix == 4 || radix == 8 ||
radix == 16 || radix == 32)
{
/* The number may also be inaccurate for one of these bases.
* This happens if the addition in value*radix + digit causes
* a round-down to an even least significant mantissa bit
* when the first dropped bit is a one. If any of the
* following digits in the number (which haven't been added
* in yet) are nonzero then the correct action would have
* been to round up instead of down. An example of this
* occurs when reading the number 0x1000000000000081, which
* rounds to 0x1000000000000000 instead of 0x1000000000000100.
*/
BinaryDigitReader bdr = new BinaryDigitReader(radix, s, start, end);
int bit;
sum = 0.0;
/* Skip leading zeros. */
do {
bit = bdr.getNextBinaryDigit();
} while (bit == 0);
if (bit == 1) {
/* Gather the 53 significant bits (including the leading 1) */
sum = 1.0;
for (int j = 52; j != 0; j--) {
bit = bdr.getNextBinaryDigit();
if (bit < 0)
return sum;
sum = sum*2 + bit;
}
/* bit54 is the 54th bit (the first dropped from the mantissa) */
int bit54 = bdr.getNextBinaryDigit();
if (bit54 >= 0) {
double factor = 2.0;
int sticky = 0; /* sticky is 1 if any bit beyond the 54th is 1 */
int bit3;
while ((bit3 = bdr.getNextBinaryDigit()) >= 0) {
sticky |= bit3;
factor *= 2;
}
sum += bit54 & (bit | sticky);
sum *= factor;
}
}
}
/* We don't worry about inaccurate numbers for any other base. */
}
return sum;
}
/**
* For escaping strings printed by object and array literals; not quite
* the same as 'escape.'
*/
public static String escapeString(String s) {
StringBuffer sb = null;
for(int i = 0, L = s.length(); i != L; ++i) {
int c = s.charAt(i);
if (' ' <= c && c <= '~' && c != '"' && c != '\\') {
// an ordinary print character (like C isprint()) and not "
// or \ . Note single quote ' is not escaped
if (sb != null) {
sb.append((char)c);
}
continue;
}
if (sb == null) {
sb = new StringBuffer(L + 3);
sb.append(s);
sb.setLength(i);
}
int escape = -1;
switch (c) {
case '\b': escape = 'b'; break;
case '\f': escape = 'f'; break;
case '\n': escape = 'n'; break;
case '\r': escape = 'r'; break;
case '\t': escape = 't'; break;
case 0xb: escape = 'v'; break; // Java lacks \v.
case '"': escape = '"'; break;
case ' ': escape = ' '; break;
case '\\': escape = '\\'; break;
}
if (escape >= 0) {
// an \escaped sort of character
sb.append('\\');
sb.append((char)escape);
} else {
int hexSize;
if (c < 256) {
// 2-digit hex
sb.append("\\x");
hexSize = 2;
} else {
// Unicode.
sb.append("\\u");
hexSize = 4;
}
// append hexadecimal form of c left-padded with 0
for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) {
int digit = 0xf & (c >> shift);
int hc = (digit < 10) ? '0' + digit : 'a' - 10 + digit;
sb.append((char)hc);
}
}
}
return (sb == null) ? s : sb.toString();
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,657 @@
/* -*- 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-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* 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
* 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.
*/
// Modified by Google
package com.google.gwt.dev.js.rhino;
import java.io.Serializable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* Map to associate non-negative integers to objects or integers.
* The map does not synchronize any of its operation, so either use
* it from a single thread or do own synchronization or perform all mutation
* operations on one thread before passing the map to others
*
* @author Igor Bukanov
*
*/
class UintMap implements Serializable {
// Map implementation via hashtable,
// follows "The Art of Computer Programming" by Donald E. Knuth
public UintMap() {
this(4);
}
public UintMap(int initialCapacity) {
if (initialCapacity < 0) Context.codeBug();
// Table grow when number of stored keys >= 3/4 of max capacity
int minimalCapacity = initialCapacity * 4 / 3;
int i;
for (i = 2; (1 << i) < minimalCapacity; ++i) { }
power = i;
if (check && power < 2) Context.codeBug();
}
public boolean isEmpty() {
return keyCount == 0;
}
public int size() {
return keyCount;
}
public boolean has(int key) {
if (key < 0) Context.codeBug();
return 0 <= findIndex(key);
}
/**
* Get object value assigned with key.
* @return key object value or null if key is absent
*/
public Object getObject(int key) {
if (key < 0) Context.codeBug();
if (values != null) {
int index = findIndex(key);
if (0 <= index) {
return values[index];
}
}
return null;
}
/**
* Get integer value assigned with key.
* @return key integer value or defaultValue if key is absent
*/
public int getInt(int key, int defaultValue) {
if (key < 0) Context.codeBug();
int index = findIndex(key);
if (0 <= index) {
if (ivaluesShift != 0) {
return keys[ivaluesShift + index];
}
return 0;
}
return defaultValue;
}
/**
* Get integer value assigned with key.
* @return key integer value or defaultValue if key does not exist or does
* not have int value
* @throws RuntimeException if key does not exist
*/
public int getExistingInt(int key) {
if (key < 0) Context.codeBug();
int index = findIndex(key);
if (0 <= index) {
if (ivaluesShift != 0) {
return keys[ivaluesShift + index];
}
return 0;
}
// Key must exist
Context.codeBug();
return 0;
}
/**
* Set object value of the key.
* If key does not exist, also set its int value to 0.
*/
public void put(int key, Object value) {
if (key < 0) Context.codeBug();
int index = ensureIndex(key, false);
if (values == null) {
values = new Object[1 << power];
}
values[index] = value;
}
/**
* Set int value of the key.
* If key does not exist, also set its object value to null.
*/
public void put(int key, int value) {
if (key < 0) Context.codeBug();
int index = ensureIndex(key, true);
if (ivaluesShift == 0) {
int N = 1 << power;
// keys.length can be N * 2 after clear which set ivaluesShift to 0
if (keys.length != N * 2) {
int[] tmp = new int[N * 2];
System.arraycopy(keys, 0, tmp, 0, N);
keys = tmp;
}
ivaluesShift = N;
}
keys[ivaluesShift + index] = value;
}
public void remove(int key) {
if (key < 0) Context.codeBug();
int index = findIndex(key);
if (0 <= index) {
keys[index] = DELETED;
--keyCount;
// Allow to GC value and make sure that new key with the deleted
// slot shall get proper default values
if (values != null) { values[index] = null; }
if (ivaluesShift != 0) { keys[ivaluesShift + index] = 0; }
}
}
public void clear() {
int N = 1 << power;
if (keys != null) {
for (int i = 0; i != N; ++i) {
keys[i] = EMPTY;
}
if (values != null) {
for (int i = 0; i != N; ++i) {
values[i] = null;
}
}
}
ivaluesShift = 0;
keyCount = 0;
occupiedCount = 0;
}
/** Return array of present keys */
public int[] getKeys() {
int[] keys = this.keys;
int n = keyCount;
int[] result = new int[n];
for (int i = 0; n != 0; ++i) {
int entry = keys[i];
if (entry != EMPTY && entry != DELETED) {
result[--n] = entry;
}
}
return result;
}
private static int tableLookupStep(int fraction, int mask, int power) {
int shift = 32 - 2 * power;
if (shift >= 0) {
return ((fraction >>> shift) & mask) | 1;
}
else {
return (fraction & (mask >>> -shift)) | 1;
}
}
private int findIndex(int key) {
int[] keys = this.keys;
if (keys != null) {
int fraction = key * A;
int index = fraction >>> (32 - power);
int entry = keys[index];
if (entry == key) { return index; }
if (entry != EMPTY) {
// Search in table after first failed attempt
int mask = (1 << power) - 1;
int step = tableLookupStep(fraction, mask, power);
int n = 0;
do {
if (check) {
if (n >= occupiedCount) Context.codeBug();
++n;
}
index = (index + step) & mask;
entry = keys[index];
if (entry == key) { return index; }
} while (entry != EMPTY);
}
}
return -1;
}
// Insert key that is not present to table without deleted entries
// and enough free space
private int insertNewKey(int key) {
if (check && occupiedCount != keyCount) Context.codeBug();
if (check && keyCount == 1 << power) Context.codeBug();
int[] keys = this.keys;
int fraction = key * A;
int index = fraction >>> (32 - power);
if (keys[index] != EMPTY) {
int mask = (1 << power) - 1;
int step = tableLookupStep(fraction, mask, power);
int firstIndex = index;
do {
if (check && keys[index] == DELETED) Context.codeBug();
index = (index + step) & mask;
if (check && firstIndex == index) Context.codeBug();
} while (keys[index] != EMPTY);
}
keys[index] = key;
++occupiedCount;
++keyCount;
return index;
}
private void rehashTable(boolean ensureIntSpace) {
if (keys != null) {
// Check if removing deleted entries would free enough space
if (keyCount * 2 >= occupiedCount) {
// Need to grow: less then half of deleted entries
++power;
}
}
int N = 1 << power;
int[] old = keys;
int oldShift = ivaluesShift;
if (oldShift == 0 && !ensureIntSpace) {
keys = new int[N];
}
else {
ivaluesShift = N; keys = new int[N * 2];
}
for (int i = 0; i != N; ++i) { keys[i] = EMPTY; }
Object[] oldValues = values;
if (oldValues != null) { values = new Object[N]; }
int oldCount = keyCount;
occupiedCount = 0;
if (oldCount != 0) {
keyCount = 0;
for (int i = 0, remaining = oldCount; remaining != 0; ++i) {
int key = old[i];
if (key != EMPTY && key != DELETED) {
int index = insertNewKey(key);
if (oldValues != null) {
values[index] = oldValues[i];
}
if (oldShift != 0) {
keys[ivaluesShift + index] = old[oldShift + i];
}
--remaining;
}
}
}
}
// Ensure key index creating one if necessary
private int ensureIndex(int key, boolean intType) {
int index = -1;
int firstDeleted = -1;
int[] keys = this.keys;
if (keys != null) {
int fraction = key * A;
index = fraction >>> (32 - power);
int entry = keys[index];
if (entry == key) { return index; }
if (entry != EMPTY) {
if (entry == DELETED) { firstDeleted = index; }
// Search in table after first failed attempt
int mask = (1 << power) - 1;
int step = tableLookupStep(fraction, mask, power);
int n = 0;
do {
if (check) {
if (n >= occupiedCount) Context.codeBug();
++n;
}
index = (index + step) & mask;
entry = keys[index];
if (entry == key) { return index; }
if (entry == DELETED && firstDeleted < 0) {
firstDeleted = index;
}
} while (entry != EMPTY);
}
}
// Inserting of new key
if (check && keys != null && keys[index] != EMPTY)
Context.codeBug();
if (firstDeleted >= 0) {
index = firstDeleted;
}
else {
// Need to consume empty entry: check occupation level
if (keys == null || occupiedCount * 4 >= (1 << power) * 3) {
// Too few unused entries: rehash
rehashTable(intType);
return insertNewKey(key);
}
++occupiedCount;
}
keys[index] = key;
++keyCount;
return index;
}
private void writeObject(ObjectOutputStream out)
throws IOException
{
out.defaultWriteObject();
int count = keyCount;
if (count != 0) {
boolean hasIntValues = (ivaluesShift != 0);
boolean hasObjectValues = (values != null);
out.writeBoolean(hasIntValues);
out.writeBoolean(hasObjectValues);
for (int i = 0; count != 0; ++i) {
int key = keys[i];
if (key != EMPTY && key != DELETED) {
--count;
out.writeInt(key);
if (hasIntValues) {
out.writeInt(keys[ivaluesShift + i]);
}
if (hasObjectValues) {
out.writeObject(values[i]);
}
}
}
}
}
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
int writtenKeyCount = keyCount;
if (writtenKeyCount != 0) {
keyCount = 0;
boolean hasIntValues = in.readBoolean();
boolean hasObjectValues = in.readBoolean();
int N = 1 << power;
if (hasIntValues) {
keys = new int[2 * N];
ivaluesShift = N;
}else {
keys = new int[N];
}
for (int i = 0; i != N; ++i) {
keys[i] = EMPTY;
}
if (hasObjectValues) {
values = new Object[N];
}
for (int i = 0; i != writtenKeyCount; ++i) {
int key = in.readInt();
int index = insertNewKey(key);
if (hasIntValues) {
int ivalue = in.readInt();
keys[ivaluesShift + index] = ivalue;
}
if (hasObjectValues) {
values[index] = in.readObject();
}
}
}
}
static final long serialVersionUID = -6916326879143724506L;
// A == golden_ratio * (1 << 32) = ((sqrt(5) - 1) / 2) * (1 << 32)
// See Knuth etc.
private static final int A = 0x9e3779b9;
private static final int EMPTY = -1;
private static final int DELETED = -2;
// Structure of kyes and values arrays (N == 1 << power):
// keys[0 <= i < N]: key value or EMPTY or DELETED mark
// values[0 <= i < N]: value of key at keys[i]
// keys[N <= i < 2N]: int values of keys at keys[i - N]
private transient int[] keys;
private transient Object[] values;
private int power;
private int keyCount;
private transient int occupiedCount; // == keyCount + deleted_count
// If ivaluesShift != 0, keys[ivaluesShift + index] contains integer
// values associated with keys
private transient int ivaluesShift;
// If true, enables consitency checks
private static final boolean check = false;
/* TEST START
public static void main(String[] args) {
if (!check) {
System.err.println("Set check to true and re-run");
throw new RuntimeException("Set check to true and re-run");
}
UintMap map;
map = new UintMap();
testHash(map, 2);
map = new UintMap();
testHash(map, 10 * 1000);
map = new UintMap(30 * 1000);
testHash(map, 10 * 100);
map.clear();
testHash(map, 4);
map = new UintMap(0);
testHash(map, 10 * 100);
}
private static void testHash(UintMap map, int N) {
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
map.put(i, i);
check(i == map.getInt(i, -1));
}
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
map.put(i, i);
check(i == map.getInt(i, -1));
}
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
map.put(i, new Integer(i));
check(-1 == map.getInt(i, -1));
Integer obj = (Integer)map.getObject(i);
check(obj != null && i == obj.intValue());
}
check(map.size() == N);
System.out.print("."); System.out.flush();
int[] keys = map.getKeys();
check(keys.length == N);
for (int i = 0; i != N; ++i) {
int key = keys[i];
check(map.has(key));
check(!map.isIntType(key));
check(map.isObjectType(key));
Integer obj = (Integer) map.getObject(key);
check(obj != null && key == obj.intValue());
}
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
check(-1 == map.getInt(i, -1));
}
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
map.put(i * i, i);
check(i == map.getInt(i * i, -1));
}
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
check(i == map.getInt(i * i, -1));
}
System.out.print("."); System.out.flush();
for (int i = 0; i != N; ++i) {
map.put(i * i, new Integer(i));
check(-1 == map.getInt(i * i, -1));
map.remove(i * i);
check(!map.has(i * i));
map.put(i * i, i);
check(map.isIntType(i * i));
check(null == map.getObject(i * i));
map.remove(i * i);
check(!map.isObjectType(i * i));
check(!map.isIntType(i * i));
}
int old_size = map.size();
for (int i = 0; i != N; ++i) {
map.remove(i * i);
check(map.size() == old_size);
}
System.out.print("."); System.out.flush();
map.clear();
check(map.size() == 0);
for (int i = 0; i != N; ++i) {
map.put(i * i, i);
map.put(i * i + 1, new Double(i+0.5));
}
checkSameMaps(map, (UintMap)writeAndRead(map));
System.out.print("."); System.out.flush();
map = new UintMap(0);
checkSameMaps(map, (UintMap)writeAndRead(map));
map = new UintMap(1);
checkSameMaps(map, (UintMap)writeAndRead(map));
map = new UintMap(1000);
checkSameMaps(map, (UintMap)writeAndRead(map));
System.out.print("."); System.out.flush();
map = new UintMap(N / 10);
for (int i = 0; i != N; ++i) {
map.put(2*i+1, i);
}
checkSameMaps(map, (UintMap)writeAndRead(map));
System.out.print("."); System.out.flush();
map = new UintMap(N / 10);
for (int i = 0; i != N; ++i) {
map.put(2*i+1, i);
}
for (int i = 0; i != N / 2; ++i) {
map.remove(2*i+1);
}
checkSameMaps(map, (UintMap)writeAndRead(map));
System.out.print("."); System.out.flush();
map = new UintMap();
for (int i = 0; i != N; ++i) {
map.put(2*i+1, new Double(i + 10));
}
for (int i = 0; i != N / 2; ++i) {
map.remove(2*i+1);
}
checkSameMaps(map, (UintMap)writeAndRead(map));
System.out.println(); System.out.flush();
}
private static void checkSameMaps(UintMap map1, UintMap map2) {
check(map1.size() == map2.size());
int[] keys = map1.getKeys();
check(keys.length == map1.size());
for (int i = 0; i != keys.length; ++i) {
int key = keys[i];
check(map2.has(key));
check(map1.isObjectType(key) == map2.isObjectType(key));
check(map1.isIntType(key) == map2.isIntType(key));
Object o1 = map1.getObject(key);
Object o2 = map2.getObject(key);
if (map1.isObjectType(key)) {
check(o1.equals(o2));
}else {
check(map1.getObject(key) == null);
check(map2.getObject(key) == null);
}
if (map1.isIntType(key)) {
check(map1.getExistingInt(key) == map2.getExistingInt(key));
}else {
check(map1.getInt(key, -10) == -10);
check(map1.getInt(key, -11) == -11);
check(map2.getInt(key, -10) == -10);
check(map2.getInt(key, -11) == -11);
}
}
}
private static void check(boolean condition) {
if (!condition) Context.codeBug();
}
private static Object writeAndRead(Object obj) {
try {
java.io.ByteArrayOutputStream
bos = new java.io.ByteArrayOutputStream();
java.io.ObjectOutputStream
out = new java.io.ObjectOutputStream(bos);
out.writeObject(obj);
out.close();
byte[] data = bos.toByteArray();
java.io.ByteArrayInputStream
bis = new java.io.ByteArrayInputStream(data);
java.io.ObjectInputStream
in = new java.io.ObjectInputStream(bis);
Object result = in.readObject();
in.close();
return result;
}catch (Exception ex) {
ex.printStackTrace();
throw new RuntimeException("Unexpected");
}
}
// TEST END */
}
@@ -0,0 +1,356 @@
/* -*- 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 oqr
* 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-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* 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
* 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.
*/
// Modified by Google
package com.google.gwt.dev.js.rhino;
import java.io.Serializable;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
Implementation of resizable array with focus on minimizing memory usage by storing few initial array elements in object fields. Can also be used as a stack.
*/
public class ObjArray implements Serializable {
public ObjArray() { }
public ObjArray(int capacityHint) {
if (capacityHint < 0) throw new IllegalArgumentException();
if (capacityHint > FIELDS_STORE_SIZE) {
data = new Object[capacityHint - FIELDS_STORE_SIZE];
}
}
public final boolean isEmpty() {
return size == 0;
}
public final int size() {
return size;
}
public final void setSize(int newSize) {
if (newSize < 0) throw new IllegalArgumentException();
int N = size;
if (newSize < N) {
for (int i = newSize; i != N; ++i) {
setImpl(i, null);
}
}else if (newSize > N) {
if (newSize > FIELDS_STORE_SIZE) {
ensureCapacity(newSize);
}
}
size = newSize;
}
public final Object get(int index) {
if (!(0 <= index && index < size)) throw invalidIndex(index, size);
return getImpl(index);
}
public final void set(int index, Object value) {
if (!(0 <= index && index < size)) throw invalidIndex(index, size);
setImpl(index, value);
}
private Object getImpl(int index) {
switch (index) {
case 0: return f0;
case 1: return f1;
case 2: return f2;
case 3: return f3;
case 4: return f4;
case 5: return f5;
}
return data[index - FIELDS_STORE_SIZE];
}
private void setImpl(int index, Object value) {
switch (index) {
case 0: f0 = value; break;
case 1: f1 = value; break;
case 2: f2 = value; break;
case 3: f3 = value; break;
case 4: f4 = value; break;
case 5: f5 = value; break;
default: data[index - FIELDS_STORE_SIZE] = value;
}
}
public int indexOf(Object obj) {
int N = size;
for (int i = 0; i != N; ++i) {
Object current = getImpl(i);
if (current == obj || (current != null && current.equals(obj))) {
return i;
}
}
return -1;
}
public int lastIndexOf(Object obj) {
for (int i = size; i != 0;) {
--i;
Object current = getImpl(i);
if (current == obj || (current != null && current.equals(obj))) {
return i;
}
}
return -1;
}
public final Object peek() {
int N = size;
if (N == 0) throw invalidEmptyStackAccess();
return getImpl(N - 1);
}
public final Object pop() {
int N = size;
--N;
Object top;
switch (N) {
case -1: throw invalidEmptyStackAccess();
case 0: top = f0; f0 = null; break;
case 1: top = f1; f1 = null; break;
case 2: top = f2; f2 = null; break;
case 3: top = f3; f3 = null; break;
case 4: top = f4; f4 = null; break;
case 5: top = f5; f5 = null; break;
default:
top = data[N - FIELDS_STORE_SIZE];
data[N - FIELDS_STORE_SIZE] = null;
}
size = N;
return top;
}
public final void push(Object value) {
add(value);
}
public final void add(Object value) {
int N = size;
if (N >= FIELDS_STORE_SIZE) {
ensureCapacity(N + 1);
}
size = N + 1;
setImpl(N, value);
}
public final void add(int index, Object value) {
Object tmp;
int N = size;
if (!(0 <= index && index <= N)) throw invalidIndex(index, N + 1);
switch (index) {
case 0:
if (N == 0) { f0 = value; break; }
tmp = f0; f0 = value; value = tmp;
case 1:
if (N == 1) { f1 = value; break; }
tmp = f1; f1 = value; value = tmp;
case 2:
if (N == 2) { f2 = value; break; }
tmp = f2; f2 = value; value = tmp;
case 3:
if (N == 3) { f3 = value; break; }
tmp = f3; f3 = value; value = tmp;
case 4:
if (N == 4) { f4 = value; break; }
tmp = f4; f4 = value; value = tmp;
case 5:
if (N == 5) { f5 = value; break; }
tmp = f5; f5 = value; value = tmp;
index = FIELDS_STORE_SIZE;
default:
ensureCapacity(N + 1);
if (index != N) {
System.arraycopy(data, index - FIELDS_STORE_SIZE,
data, index - FIELDS_STORE_SIZE + 1,
N - index);
}
data[index - FIELDS_STORE_SIZE] = value;
}
size = N + 1;
}
public final void remove(int index) {
int N = size;
if (!(0 <= index && index < N)) throw invalidIndex(index, N);
--N;
switch (index) {
case 0:
if (N == 0) { f0 = null; break; }
f0 = f1;
case 1:
if (N == 1) { f1 = null; break; }
f1 = f2;
case 2:
if (N == 2) { f2 = null; break; }
f2 = f3;
case 3:
if (N == 3) { f3 = null; break; }
f3 = f4;
case 4:
if (N == 4) { f4 = null; break; }
f4 = f5;
case 5:
if (N == 5) { f5 = null; break; }
f5 = data[0];
index = FIELDS_STORE_SIZE;
default:
if (index != N) {
System.arraycopy(data, index - FIELDS_STORE_SIZE + 1,
data, index - FIELDS_STORE_SIZE,
N - index);
}
data[N - FIELDS_STORE_SIZE] = null;
}
size = N;
}
public final void clear() {
int N = size;
for (int i = 0; i != N; ++i) {
setImpl(i, null);
}
size = 0;
}
public final Object[] toArray() {
Object[] array = new Object[size];
toArray(array, 0);
return array;
}
public final void toArray(Object[] array) {
toArray(array, 0);
}
public final void toArray(Object[] array, int offset) {
int N = size;
switch (N) {
default:
System.arraycopy(data, 0, array, offset + FIELDS_STORE_SIZE,
N - FIELDS_STORE_SIZE);
case 6: array[offset + 5] = f5;
case 5: array[offset + 4] = f4;
case 4: array[offset + 3] = f3;
case 3: array[offset + 2] = f2;
case 2: array[offset + 1] = f1;
case 1: array[offset + 0] = f0;
case 0: break;
}
}
private void ensureCapacity(int minimalCapacity) {
int required = minimalCapacity - FIELDS_STORE_SIZE;
if (required <= 0) throw new IllegalArgumentException();
if (data == null) {
int alloc = FIELDS_STORE_SIZE * 2;
if (alloc < required) {
alloc = required;
}
data = new Object[alloc];
} else {
int alloc = data.length;
if (alloc < required) {
if (alloc <= FIELDS_STORE_SIZE) {
alloc = FIELDS_STORE_SIZE * 2;
} else {
alloc *= 2;
}
if (alloc < required) {
alloc = required;
}
Object[] tmp = new Object[alloc];
if (size > FIELDS_STORE_SIZE) {
System.arraycopy(data, 0, tmp, 0,
size - FIELDS_STORE_SIZE);
}
data = tmp;
}
}
}
private static RuntimeException invalidIndex(int index, int upperBound) {
// \u2209 is "NOT ELEMENT OF"
String msg = index+" \u2209 [0, "+upperBound+')';
return new IndexOutOfBoundsException(msg);
}
private static RuntimeException invalidEmptyStackAccess() {
throw new RuntimeException("Empty stack");
}
private void writeObject(ObjectOutputStream os) throws IOException {
os.defaultWriteObject();
int N = size;
for (int i = 0; i != N; ++i) {
Object obj = getImpl(i);
os.writeObject(obj);
}
}
private void readObject(ObjectInputStream is)
throws IOException, ClassNotFoundException
{
is.defaultReadObject(); // It reads size
int N = size;
if (N > FIELDS_STORE_SIZE) {
data = new Object[N - FIELDS_STORE_SIZE];
}
for (int i = 0; i != N; ++i) {
Object obj = is.readObject();
setImpl(i, obj);
}
}
static final long serialVersionUID = 7448768847663119705L;
// Number of data elements
private int size;
private static final int FIELDS_STORE_SIZE = 6;
private transient Object f0, f1, f2, f3, f4, f5;
private transient Object[] data;
}
+1 -2
View File
@@ -15,5 +15,4 @@
<orderEntry type="module" module-name="js.frontend" exported="" />
<orderEntry type="module" module-name="js.inliner" exported="" />
</component>
</module>
</module>