JS parser: GWT parser copied
This commit is contained in:
Generated
+1
@@ -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" />
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -15,5 +15,4 @@
|
||||
<orderEntry type="module" module-name="js.frontend" exported="" />
|
||||
<orderEntry type="module" module-name="js.inliner" exported="" />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
</module>
|
||||
Reference in New Issue
Block a user