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.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.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.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.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$/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" />
|
<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.translator/src"/>
|
||||||
<include name="js/js.frontend/src"/>
|
<include name="js/js.frontend/src"/>
|
||||||
<include name="js/js.inliner/src"/>
|
<include name="js/js.inliner/src"/>
|
||||||
|
<include name="js/js.parser/src"/>
|
||||||
</dirset>
|
</dirset>
|
||||||
|
|
||||||
<property name="idea.out" value="${basedir}/out/production"/>
|
<property name="idea.out" value="${basedir}/out/production"/>
|
||||||
@@ -100,6 +101,7 @@
|
|||||||
<include name="js.translator/**"/>
|
<include name="js.translator/**"/>
|
||||||
<include name="js.frontend/**"/>
|
<include name="js.frontend/**"/>
|
||||||
<include name="js.inliner/**"/>
|
<include name="js.inliner/**"/>
|
||||||
|
<include name="js.parser/**"/>
|
||||||
</patternset>
|
</patternset>
|
||||||
|
|
||||||
<path id="compilerSources.path">
|
<path id="compilerSources.path">
|
||||||
@@ -165,6 +167,7 @@
|
|||||||
<fileset dir="js/js.translator/src"/>
|
<fileset dir="js/js.translator/src"/>
|
||||||
<fileset dir="js/js.frontend/src"/>
|
<fileset dir="js/js.frontend/src"/>
|
||||||
<fileset dir="js/js.inliner/src"/>
|
<fileset dir="js/js.inliner/src"/>
|
||||||
|
<fileset dir="js/js.parser/src"/>
|
||||||
<zipfileset file="${kotlin-home}/build.txt" prefix="META-INF"/>
|
<zipfileset file="${kotlin-home}/build.txt" prefix="META-INF"/>
|
||||||
|
|
||||||
<manifest>
|
<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;
|
||||||
|
}
|
||||||
@@ -16,4 +16,3 @@
|
|||||||
<orderEntry type="module" module-name="js.inliner" exported="" />
|
<orderEntry type="module" module-name="js.inliner" exported="" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user