This commit is contained in:
norris%netscape.com 1999-04-19 20:43:53 +00:00
Родитель 48d88a6275
Коммит 3a188e59ad
144 изменённых файлов: 53133 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,109 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This class implements the "arguments" object.
*
* See ECMA 10.1.8
*
* @see org.mozilla.javascript.NativeCall
* @author Norris Boyd
*/
class Arguments extends ScriptableObject {
public Arguments(NativeCall activation) {
this.activation = activation;
Scriptable parent = activation.getParentScope();
setParentScope(parent);
setPrototype(ScriptableObject.getObjectPrototype(parent));
args = activation.getOriginalArguments();
int length = args.length;
Object callee = activation.funObj;
defineProperty("length", new Integer(length),
ScriptableObject.DONTENUM);
defineProperty("callee", callee, ScriptableObject.DONTENUM);
hasCaller = activation.funObj.version <= Context.VERSION_1_3;
}
public String getClassName() {
return "Arguments";
}
public boolean has(String name, Scriptable start) {
return (hasCaller && name.equals("caller")) || super.has(name, start);
}
public boolean has(int index, Scriptable start) {
Object[] args = activation.getOriginalArguments();
return (0 <= index && index < args.length) || super.has(index, start);
}
public Object get(String name, Scriptable start) {
if (hasCaller && name.equals("caller")) {
NativeCall caller = activation.caller;
if (caller == null || caller.originalArgs == null)
return null;
return caller.get("arguments", caller);
}
return super.get(name, start);
}
public Object get(int index, Scriptable start) {
if (0 <= index && index < args.length) {
NativeFunction f = activation.funObj;
if (index < f.argCount)
return activation.get(f.names[index+1], activation);
return args[index];
}
return super.get(index, start);
}
public void put(String name, Scriptable start, Object value) {
if (name.equals("caller"))
hasCaller = false;
super.put(name, start, value);
}
public void put(int index, Scriptable start, Object value) {
if (0 <= index && index < args.length) {
NativeFunction f = activation.funObj;
if (index < f.argCount)
activation.put(f.names[index+1], activation, value);
else
args[index] = value;
return;
}
super.put(index, start, value);
}
public void delete(String name) {
if (name.equals("caller"))
hasCaller = false;
super.delete(name);
}
private NativeCall activation;
private Object[] args;
private boolean hasCaller;
}

Просмотреть файл

@ -0,0 +1,58 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
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,32 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
/**
* Thrown if errors are detected while attempting to define a host object
* from a Java class.
*/
public class ClassDefinitionException extends Exception {
public ClassDefinitionException(String detail) {
super(detail);
}
}

Просмотреть файл

@ -0,0 +1,34 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
public interface ClassNameHelper {
public String getTargetClassFileName();
public void setTargetClassFileName(String classFileName);
public String getTargetPackage();
public void setTargetPackage(String targetPackage);
public String getTargetClassFileName(String className);
public String getGeneratingDirectory();
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,75 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This interface supports low-level per statement debug hooks
* <p>
* This interface can be implemented and used to do statement level
* interrupting and trapping of executing scripts.
* org.mozilla.javascript.debug.IDebugManager uses this system and provides
* a higher level abstraction more appropriate as a debugger API.
*
* @see org.mozilla.javascript.Context#setBytecodeHook
* @see org.mozilla.javascript.debug.IDebugManager
* @author John Bandhauer
*/
public interface DeepBytecodeHook
{
/**
* Possible hook return values.
*/
/**
* The executing script should continue.
*/
public static final int CONTINUE = 0;
/**
* The executing script should throw the object passed back in
* retVal[0]. This must be an object derived from java.lang.Throwable.
*/
public static final int THROW = 1;
/**
* The executing script should immediately return the object passed
* back in retVal[0].
*/
public static final int RETURN_VALUE = 2;
/**
* Handle trap.
*
* @param cx current context
* @param pc current program counter
* @param retVal single Object array to hold return value or exception
* @return one of {CONTINUE | THROW | RETURN_VALUE}
*/
public int trapped(Context cx, int pc, Object[] retVal);
/**
* Handle interrupt.
*
* @param cx current context
* @param pc current program counter
* @param retVal single Object array to hold return value or exception
* @return one of {CONTINUE | THROW | RETURN_VALUE}
*/
public int interrupted(Context cx, int pc, Object[] retVal);
}

Просмотреть файл

@ -0,0 +1,59 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This interface supports low-level call debug hooks
* <p>
* This interface can be implemented and used to hook JavaScript
* function calls. org.mozilla.javascript.debug.IDebugManager uses this
* system and provides a higher level abstraction more appropriate
* as a debugger API.
*
* @see org.mozilla.javascript.Context#setCallHook
* @see org.mozilla.javascript.debug.IDebugManager
* @author John Bandhauer
*/
public interface DeepCallHook
{
/**
* Notification that a function is about to be called.
*
* @param cx current context
* @param fun function to be called
* @param thisArg the 'this' of the object
* @param args constructor arguments array
* @return arbitrary object which is subsequently passed to postCall
* @see org.mozilla.javascript.debug.NativeDelegate#callDebug
*/
public Object preCall(Context cx, Object fun, Object thisArg, Object[] args);
/**
* Notification that a call returned.
*
* @param cx current context
* @param ref value returned from previous call to preCall
* @param retVal value returned by the callee (null if exception thrown)
* @param e exception thrown by callee (null if none thrown)
* @see org.mozilla.javascript.debug.NativeDelegate#callDebug
*/
public void postCall(Context cx, Object ref, Object retVal,
JavaScriptException e);
}

Просмотреть файл

@ -0,0 +1,53 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This interface supports low-level error reporter hooks.
* <p>
* This interface can be implemented and used to hook calls to the
* error reporter. org.mozilla.javascript.debug.IDebugManager uses this
* system and provides a higher level abstraction more appropriate
* as a debugger API.
*
* @see org.mozilla.javascript.Context#setErrorReporterHook
* @see org.mozilla.javascript.debug.IDebugManager
* @author John Bandhauer
*/
public interface DeepErrorReporterHook extends ErrorReporter
{
/**
* Change the current error reporter.
*
* @return the previous error reporter
* @see org.mozilla.javascript.ErrorReporter
* @see org.mozilla.javascript.Context#setErrorReporter
*/
public ErrorReporter setErrorReporter(ErrorReporter reporter);
/**
* Get the current error reporter.
*
* @see org.mozilla.javascript.ErrorReporter
* @see org.mozilla.javascript.Context#getErrorReporter
*/
public ErrorReporter getErrorReporter();
}

Просмотреть файл

@ -0,0 +1,58 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This interface supports low-level execute debug hooks.
* <p>
* This interface can be implemented and used to hook JavaScript
* script execution. org.mozilla.javascript.debug.IDebugManager uses this
* system and provides a higher level abstraction more appropriate
* as a debugger API.
*
* @see org.mozilla.javascript.Context#setExecuteHook
* @see org.mozilla.javascript.debug.IDebugManager
* @author John Bandhauer
*/
public interface DeepExecuteHook
{
/**
* Notification that a top-level script is about to be executed.
*
* @param cx current context
* @param fun script
* @param scope scope
* @return arbitrary object which is subsequently passed to postExecute
* @see org.mozilla.javascript.debug.NativeDelegate#executeDebug
*/
public Object preExecute(Context cx, NativeFunction fun, Scriptable scope);
/**
* Notification that a top-level script execution returned.
*
* @param cx current context
* @param ref value returned from previous call to preExecute
* @param retVal value returned by the script (null if exception thrown)
* @param e exception thrown by script (null if none thrown)
* @see org.mozilla.javascript.debug.NativeDelegate#executeDebug
*/
public void postExecute(Context cx, Object ref, Object retVal,
JavaScriptException e);
}

Просмотреть файл

@ -0,0 +1,59 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This interface supports low-level new object debug hooks.
* <p>
* This interface can be implemented and used to hook JavaScript
* object creation; i.e. calls for JavaScript constructor
* functions. org.mozilla.javascript.debug.IDebugManager uses this
* system and provides a higher level abstraction more appropriate
* as a debugger API.
*
* @see org.mozilla.javascript.Context#setNewObjectHook
* @see org.mozilla.javascript.debug.IDebugManager
* @author John Bandhauer
*/
public interface DeepNewObjectHook
{
/**
* Notification that a constructor is about to be called.
*
* @param cx current context
* @param fun constructor function
* @param args constructor arguments array
* @return arbitrary object which is subsequently passed to postNewObject
* @see org.mozilla.javascript.debug.NativeDelegate#newObjectDebug
*/
public Object preNewObject(Context cx, Object fun, Object[] args);
/**
* Notification that a constructor returned.
*
* @param cx current context
* @param ref value returned from previous call to preNewObject
* @param retVal value returned by the constructor (null if exception thrown)
* @param e exception thrown by constructor (null if none thrown)
* @see org.mozilla.javascript.debug.NativeDelegate#newObjectDebug
*/
public void postNewObject(Context cx, Object ref, Scriptable retVal,
Exception e);
}

Просмотреть файл

@ -0,0 +1,57 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This interface supports low-level script load/unload debug hooks.
* <p>
* This interface can be implemented and used to hook script loading
* and unloading. org.mozilla.javascript.debug.IDebugManager uses this
* system and provides a higher level abstraction more appropriate
* as a debugger API.
*
* @see org.mozilla.javascript.Context#setScriptHook
* @see org.mozilla.javascript.debug.IDebugManager
* @author John Bandhauer
*/
public interface DeepScriptHook
{
/**
* Notification that a script is being loaded.
*
* @param cx current context
* @param obj script or function being loaded
*/
public void loadingScript(Context cx, NativeFunction obj);
/**
* Notification that a script is being unloaded.
* <p>
* NOTE: this currently happens as part of the Java garbage
* collection process; i.e. it is called by the finalize method
* of the script and is thus likely to be called on a system
* thread. Also, this is thus not likely to be called if there are
* any outstanding references to the script.
*
* @param cx context which originally loaded the script
* @param obj script or function being unloaded
*/
public void unloadingScript(Context cx, NativeFunction obj);
}

Просмотреть файл

@ -0,0 +1,46 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This is the default error reporter for JavaScript.
*
* @author Norris Boyd
*/
class DefaultErrorReporter implements ErrorReporter {
public void warning(String message, String sourceName, int line,
String lineSource, int lineOffset)
{
// do nothing
}
public void error(String message, String sourceName, int line,
String lineSource, int lineOffset)
{
throw new EvaluatorException(message);
}
public EvaluatorException runtimeError(String message, String sourceName,
int line, String lineSource,
int lineOffset)
{
return new EvaluatorException(message);
}
}

Просмотреть файл

@ -0,0 +1,86 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
/**
* 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,38 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* 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,322 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
import java.util.Hashtable;
import java.util.Enumeration;
/**
* Manipulate a Scriptable object as if its prototype chain were flattened.
* <p>
* Compared to the Scriptable interface, FlattenedObject provides a view of
* Scriptable objects that is easier to use and more closely matches a script
* writer's view of a JavaScript object. <p>
*
* A FlattenedObject is "flattened" in the sense that multiple objects in a
* prototype chain appear to have their properties all appear in the
* FlattenedObject. <p>
*
* Another convenience provided by Flattened object is the ability to access
* properties by a single java.lang.Object id. This id is then converted into
* a String or an int before methods of the Scriptable object are called.
*
* @see org.mozilla.javascript.Scriptable
*
* @author Norris Boyd
*/
public class FlattenedObject {
/**
* Construct a new FlattenedObject.
*
* @param object the object to be viewed with flattened properties
*/
public FlattenedObject(Scriptable object) {
this.obj = object;
}
/**
* Get the associated Scriptable object.
*/
public Scriptable getObject() {
return obj;
}
/**
* Determine if a property exists in an object.
*
* This is a more convenient (and less efficient) form than
* <code>Scriptable.has()</code>.
* It returns true if and only if the property
* exists in this object or any of the objects in its prototype
* chain.
*
* @param id the property index, which may be either a String or a
* Number
* @return true if and only if the property exists in the prototype
* chain
* @see org.mozilla.javascript.Scriptable#has
*/
public boolean hasProperty(Object id) {
String stringId = ScriptRuntime.toString(id);
String s = ScriptRuntime.getStringId(stringId);
if (s == null)
return getBase(obj, ScriptRuntime.getIntId(stringId)) != null;
return getBase(obj, s) != null;
}
/**
* Get a property of an object.
* <p>
* This is a more convenient (and less efficient) form than
* <code>Scriptable.get()</code>. It corresponds exactly to the
* expression <code>obj[id]</code> in JavaScript. This method
* will traverse the prototype chain of an object to find the
* property.<p>
*
* If the property does not exist in the object or its prototype
* chain, the undefined value will be returned.
*
* @param id the property index; can be a String or a Number; the
* String may contain characters representing a number
* @return the value of the property or the undefined value
* @see org.mozilla.javascript.Scriptable#get
* @see org.mozilla.javascript.Context#getUndefinedValue
*/
public Object getProperty(Object id) {
String s = ScriptRuntime.getStringId(id);
int index = s == null ? ScriptRuntime.getIntId(id) : 0;
Scriptable m = obj;
Object result;
for(;;) {
result = s == null ? m.get(index, obj) : m.get(s, obj);
if (result != Scriptable.NOT_FOUND)
break;
m = m.getPrototype();
if (m == null)
return Undefined.instance;
}
if (result instanceof Scriptable)
return new FlattenedObject((Scriptable) result);
return result;
}
/**
* Set a property of an object.
*
* This is a more convenient (and less efficient) form than that
* provided in Scriptable. It corresponds exactly to the
* expression <code>obj[id] = val</code> in JavaScript.<p>
*
* @param id the property index, which may be either a String or
* a Number
* @param value the value of the property
* @see org.mozilla.javascript.Scriptable#put
*/
public void putProperty(Object id, Object value) {
String s = ScriptRuntime.getStringId(id);
if (value instanceof FlattenedObject)
value = ((FlattenedObject) value).getObject();
Scriptable x;
if (s == null) {
int index = ScriptRuntime.getIntId(id);
x = getBase(obj, index);
if (x == null)
x = obj;
x.put(index, obj, value);
return;
}
x = getBase(obj, s);
if (x == null)
x = obj;
x.put(s, obj, value);
}
/**
* Remove a property.
*
* This method provides the functionality of the <code>delete</code>
* operator in JavaScript.
*
* @param id the property index, which may be either a String or
* a Number
* @return true if the property didn't exist, or existed and was removed
* @see org.mozilla.javascript.Scriptable#delete
*/
public boolean deleteProperty(Object id) {
String s = ScriptRuntime.getStringId(id);
if (s == null) {
int index = ScriptRuntime.getIntId(id);
Scriptable base = getBase(obj, index);
if (base == null)
return true;
base.delete(index);
return !base.has(index, base);
}
Scriptable base = getBase(obj, s);
if (base == null)
return true;
base.delete(s);
return !base.has(s, base);
}
/**
* Return an array that contains the ids of the properties.
*
* <p>This method will walk the prototype chain and collect the
* ids of all objects in the prototype chain.<p>
*
* If an id appears in more than one object in the prototype chain,
* it will only be in the array once. (So all the entries in the
* array will be unique respective to equals().)
*
* @see org.mozilla.javascript.Scriptable#getIds
*/
public Object[] getIds() {
Hashtable h = new Hashtable(11);
Scriptable m = obj;
while (m != null) {
Object[] e = m.getIds();
for (int i=0; i < e.length; i++) {
h.put(e[i], Boolean.TRUE);
}
m = m.getPrototype();
}
Enumeration keys = h.keys();
Object elem;
Object[] result = new Object[h.size()];
int index = 0;
while (keys.hasMoreElements()) {
elem = keys.nextElement();
result[index++] = elem;
}
return result;
}
/**
* Consider this object to be a function, and call it.
*
* @param cx the current Context for this thread
* @param thisObj the JavaScript 'this' for the call
* @param args the arguments for the call
* @return the result of the JavaScript function call
* @exception NotAFunctionException if this object is not a function
* @exception JavaScriptException if an uncaught JavaScript exception
* occurred while executing the function
* @see org.mozilla.javascript.Function#call
*/
public Object call(Context cx, Scriptable thisObj, Object[] args)
throws NotAFunctionException,
JavaScriptException
{
if (!(obj instanceof Function)) {
throw new NotAFunctionException();
}
return ScriptRuntime.call(cx, obj, thisObj, args);
}
/**
* Consider this object to be a function, and invoke it as a
* constructor call.
*
* @param cx the current Context for this thread
* @param args the arguments for the constructor call
* @return the allocated object
* @exception NotAFunctionException if this object is not a function
* @exception JavaScriptException if an uncaught JavaScript exception
* occurred while executing the constructor
* @see org.mozilla.javascript.Function#construct
*/
public Scriptable construct(Context cx, Object[] args)
throws NotAFunctionException,
JavaScriptException
{
if (!(obj instanceof Function)) {
throw new NotAFunctionException();
}
return ScriptRuntime.newObject(cx, obj, args);
}
/**
* Get the property indicated by the id, and invoke it with the
* specified arguments.
* <p>
* For example, for a FlattenedObject <code>obj</code>,
* and a Java array <code>a</code> consisting of a single string
* <code>"hi"</code>, the call <pre>
* obj.callMethod("m", a)</pre>
* is equivalent to the JavaScript code <code>obj.m("hi")</code>.<p>
*
* If the property is not found or is not a function, an
* exception will be thrown.
*
* @param id the Number or String to use to find the function property
* to call
* @param args the arguments for the constructor call
* @return the result of the call
* @exception PropertyException if the designated property
* was not found
* @exception NotAFunctionException if this object is not a function
* @exception JavaScriptException if an uncaught JavaScript exception
* occurred while executing the method
* @see org.mozilla.javascript.Function#call
*/
public Object callMethod(Object id, Object[] args)
throws PropertyException,
NotAFunctionException,
JavaScriptException
{
if (!hasProperty(id)) {
throw new PropertyException(
Context.getMessage("msg.prop.not.found", null));
}
Object o = getProperty(id);
if (o instanceof FlattenedObject)
return ((FlattenedObject) o).call(Context.getContext(), obj, args);
throw new NotAFunctionException();
}
/****** End of API *******/
private static Scriptable getBase(Scriptable obj, String s) {
Scriptable m = obj;
while (m != null) {
if (m.has(s, obj))
return m;
m = m.getPrototype();
}
return null;
}
private static Scriptable getBase(Scriptable obj, int index) {
Scriptable m = obj;
while (m != null) {
if (m.has(index, obj))
return m;
m = m.getPrototype();
}
return null;
}
private Scriptable obj;
}

Просмотреть файл

@ -0,0 +1,70 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
/**
* This is interface that all functions in JavaScript must implement.
* The interface provides for calling functions and constructors.
*
* @see org.mozilla.javascript.Scriptable
* @author Norris Boyd
*/
public interface Function extends Scriptable {
/**
* Call the function.
*
* Note that the array of arguments is not guaranteed to have
* length greater than 0.
*
* @param cx the current Context for this thread
* @param scope the scope to execute the function relative to. This
* set to the value returned by getParentScope() except
* when the function is called from a closure.
* @param thisObj the JavaScript <code>this</code> object
* @param args the array of arguments
* @return the result of the call
* @exception JavaScriptException if an uncaught exception
* occurred while executing the function
*/
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException;
/**
* Call the function as a constructor.
*
* This method is invoked by the runtime in order to satisfy a use
* of the JavaScript <code>new</code> operator. This method is
* expected to create a new object and return it.
*
* @param cx the current Context for this thread
* @param scope the scope to execute the function relative to. This
* set to the value returned by getParentScope() except
* when the function is called from a closure.
* @param args the array of arguments
* @return the allocated object
* @exception JavaScriptException if an uncaught exception
* occurred while executing the constructor
*/
public Scriptable construct(Context cx, Scriptable scope, Object[] args)
throws JavaScriptException;
}

Просмотреть файл

@ -0,0 +1,48 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.util.*;
public class FunctionNode extends Node {
public FunctionNode(String name, Node left, Node right) {
super(TokenStream.FUNCTION, left, right, name);
itsVariableTable = new VariableTable();
}
public String getFunctionName() {
return getString();
}
public VariableTable getVariableTable() {
return itsVariableTable;
}
public boolean requiresActivation() {
return itsNeedsActivation;
}
public boolean setRequiresActivation(boolean b) {
return itsNeedsActivation = b;
}
protected VariableTable itsVariableTable;
protected boolean itsNeedsActivation;
}

Просмотреть файл

@ -0,0 +1,492 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
import java.util.Hashtable;
import java.util.Vector;
import java.lang.reflect.*;
public class FunctionObject extends NativeFunction {
/**
* Create a JavaScript function object from a Java method.
*
* <p>The <code>member</code> argument must be either a java.lang.reflect.Method
* or a java.lang.reflect.Constructor and must match one of two forms.<p>
*
* The first form is a member with zero or more parameters
* of the following types: Object, String, boolean, Scriptable,
* byte, short, int, long, float, or double. If the member is
* a Method, the return value must be void or one of the types
* allowed for parameters.<p>
*
* The runtime will perform appropriate conversions based
* upon the type of the parameter. A parameter type of
* Object specifies that no conversions are to be done. A parameter
* of type String will use Context.toString to convert arguments.
* Similarly, parameters of type double, boolean, and Scriptable
* will cause Context.toNumber, Context.toBoolean, and
* Context.toObject, respectively, to be called.<p>
*
* If the method is not static, the Java 'this' value will
* correspond to the JavaScript 'this' value. Any attempt
* to call the function with a 'this' value that is not
* of the right Java type will result in an error.<p>
*
* The second form is the variable arguments (or "varargs")
* form. If the FunctionObject will be used as a constructor,
* the member must have the following parameters
* <pre>
* (Context cx, Scriptable thisObj, Object[] args,
* Function funObj) </pre>
* and if it is a Method, be static and return an Object result.<p>
*
* Otherwise, if the FunctionObject will not be used to define a
* constructor, the member must be a static Method with parameters
* <pre>
* (Context cx, Object[] args, Function ctorObj,
* boolean inNewExpr)</pre>
* and an Object result.<p>
*
* When the function varargs form is called as part of a function call,
* the <code>args</code> parameter contains the
* arguments, with <code>thisObj</code>
* set to the JavaScript 'this' value. <code>funObj</code>
* is the function object for the invoked function.<p>
*
* When the constructor varargs form is called or invoked while evaluating
* a <code>new</code> expression, <code>args</code> contains the
* arguments, <code>ctorObj</code> refers to this FunctionObject, and
* <code>inNewExpr</code> is true if and only if a <code>new</code>
* expression caused the call. This supports defining a function that
* has different behavior when called as a constructor than when
* invoked as a normal function call. (For example, the Boolean
* constructor, when called as a function,
* will convert to boolean rather than creating a new object.)<p>
*
* @param name the name of the function
* @param methodOrConstructor a java.lang.reflect.Method or a java.lang.reflect.Constructor
* that defines the object
* @param scope enclosing scope of function
* @see org.mozilla.javascript.Scriptable
*/
public FunctionObject(String name, Member methodOrConstructor,
Scriptable scope)
{
String methodName;
if (methodOrConstructor instanceof Constructor) {
ctor = (Constructor) methodOrConstructor;
isStatic = true; // well, doesn't take a 'this'
types = ctor.getParameterTypes();
methodName = ctor.getName();
} else {
method = (Method) methodOrConstructor;
isStatic = Modifier.isStatic(method.getModifiers());
types = method.getParameterTypes();
methodName = method.getName();
}
String myNames[] = { name };
super.names = myNames;
int length;
if (types.length == 4 && (types[1].isArray() || types[2].isArray())) {
// Either variable args or an error.
if (types[1].isArray()) {
if (!isStatic ||
types[0] != Context.class ||
types[1].getComponentType() != ScriptRuntime.ObjectClass ||
types[2] != ScriptRuntime.FunctionClass ||
types[3] != Boolean.TYPE)
{
String message = Context.getMessage("msg.varargs.ctor",
null);
throw Context.reportRuntimeError(message);
}
} else {
if (!isStatic ||
types[0] != Context.class ||
types[1] != ScriptRuntime.ScriptableClass ||
types[2].getComponentType() != ScriptRuntime.ObjectClass ||
types[3] != ScriptRuntime.FunctionClass)
{
String message = Context.getMessage("msg.varargs.fun",
null);
throw Context.reportRuntimeError(message);
}
}
// XXX check return type
parmsLength = types[1].isArray() ? VARARGS_CTOR : VARARGS_METHOD;
length = 1;
} else {
parmsLength = (short) types.length;
boolean hasConversions = false;
for (int i=0; i < parmsLength; i++) {
Class type = types[i];
if (type == ScriptRuntime.ObjectClass) {
// may not need conversions
} else if (type == ScriptRuntime.StringClass ||
type == ScriptRuntime.BooleanClass ||
ScriptRuntime.NumberClass.isAssignableFrom(type) ||
Scriptable.class.isAssignableFrom(type))
{
hasConversions = true;
} else if (type == Boolean.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.BooleanClass;
} else if (type == Byte.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.ByteClass;
} else if (type == Short.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.ShortClass;
} else if (type == Integer.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.IntegerClass;
} else if (type == Float.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.FloatClass;
} else if (type == Double.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.DoubleClass;
} else {
Object[] errArgs = { methodName };
throw Context.reportRuntimeError(
Context.getMessage("msg.bad.parms", errArgs));
}
}
if (!hasConversions)
types = null;
length = parmsLength;
}
// Initialize length property
lengthPropertyValue = (short) length;
hasVoidReturn = method != null && method.getReturnType() == Void.TYPE;
this.argCount = (short) length;
setParentScope(scope);
setPrototype(getFunctionPrototype(scope));
}
/**
* Override ScriptableObject's has, get, and set in order to define
* the "length" property of the function. <p>
*
* We could also have defined the property using ScriptableObject's
* defineProperty method, but that would have consumed a slot in every
* FunctionObject. Most FunctionObjects typically don't have any
* properties anyway, so having the "length" property would cause us
* to allocate an array of slots. <p>
*
* In particular, this method will return true for
* <code>name.equals("length")</code>
* and will delegate to the superclass for all other
* values of <code>name</code>.
*/
public boolean has(String name, Scriptable start) {
return name.equals("length") || super.has(name, start);
}
/**
* Override ScriptableObject's has, get, and set in order to define
* the "length" property of the function. <p>
*
* In particular, this method will return the value defined by
* the method used to construct the object (number of parameters
* of the method, or 1 if the method is a "varargs" form), unless
* setLength has been called with a new value.
*
* @see org.mozilla.javascript.FunctionObject#setLength
*/
public Object get(String name, Scriptable start) {
if (name.equals("length"))
return new Integer(lengthPropertyValue);
return super.get(name, start);
}
/**
* Override ScriptableObject's has, get, and set in order to define
* the "length" property of the function. <p>
*
* In particular, this method will ignore all attempts to set the
* "length" property and forward all other requests to ScriptableObject.
*
* @see org.mozilla.javascript.FunctionObject#setLength
*/
public void put(String name, Scriptable start, Object value) {
if (!name.equals("length"))
super.put(name, start, value);
}
/**
* Set the value of the "length" property.
*
* <p>Changing the value of the "length" property of a FunctionObject only
* affects the value retrieved from get() and does not affect the way
* the method itself is called. <p>
*
* The "length" property will be defined by default as the number
* of parameters of the method used to construct the FunctionObject,
* unless the method is a "varargs" form, in which case the "length"
* property will be defined to 1.
*
* @param length the new length
*/
public void setLength(short length) {
lengthPropertyValue = length;
}
// TODO: Make not public
/**
* Finds methods of a given name in a given class.
*
* <p>Searches <code>clazz</code> for methods with name
* <code>name</code>. Maintains a cache so that multiple
* lookups on the same class are cheap.
*
* @param clazz the class to search
* @param name the name of the methods to find
* @return an array of the found methods, or null if no methods
* by that name were found.
* @see java.lang.Class#getMethods
*/
public static Method[] findMethods(Class clazz, String name) {
Vector v = new Vector(5);
Method[] methods = clazz.getMethods();
for (int i=0; i < methods.length; i++) {
if (methods[i].getDeclaringClass() == clazz &&
methods[i].getName().equals(name)){
v.addElement(methods[i]);
}
}
if (v.size() == 0) {
return null;
}
Method[] result = new Method[v.size()];
v.copyInto(result);
return result;
}
/**
* Define this function as a JavaScript constructor.
* <p>
* Sets up the "prototype" and "constructor" properties. Also
* calls setParent and setPrototype with appropriate values.
* Then adds the function object as a property of the given scope, using
* <code>prototype.getClassName()</code>
* as the name of the property.
*
* @param scope the scope in which to define the constructor (typically
* the global object)
* @param prototype the prototype object
* @see org.mozilla.javascript.Scriptable#setParentScope
* @see org.mozilla.javascript.Scriptable#setPrototype
* @see org.mozilla.javascript.Scriptable#getClassName
*/
public void addAsConstructor(Scriptable scope, Scriptable prototype) {
setParentScope(scope);
setPrototype(getFunctionPrototype(scope));
prototype.setParentScope(this);
final int attr = ScriptableObject.DONTENUM |
ScriptableObject.PERMANENT |
ScriptableObject.READONLY;
defineProperty("prototype", prototype, attr);
String name = prototype.getClassName();
if (!name.equals("With")) {
// A "With" object would delegate these calls to the prototype:
// not the right thing to do here!
if (prototype instanceof ScriptableObject) {
((ScriptableObject) prototype).defineProperty("constructor",
this, attr);
} else {
prototype.put("constructor", prototype, this);
}
}
if (scope instanceof ScriptableObject) {
((ScriptableObject) scope).defineProperty(name, this,
ScriptableObject.DONTENUM);
} else {
scope.put(name, scope, this);
}
setParentScope(scope);
}
/**
* Performs conversions on argument types if needed and
* invokes the underlying Java method or constructor.
* <p>
* Implements Function.call.
*
* @see org.mozilla.javascript.Function#call
* @exception JavaScriptException if the underlying Java method or constructor
* threw an exception
*/
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException
{
if (parmsLength < 0)
return callVarargs(cx, thisObj, args, false);
if (!isStatic) {
// OPT: cache "clazz"?
Class clazz = method != null ? method.getDeclaringClass()
: ctor.getDeclaringClass();
if (thisObj == null || !clazz.isInstance(thisObj)) {
Object[] errArgs = { names[0] };
throw Context.reportRuntimeError(
Context.getMessage("msg.incompat.call", errArgs));
}
}
Object[] invokeArgs;
int i;
if (parmsLength == args.length) {
invokeArgs = args;
// avoid copy loop if no conversions needed
i = (types == null) ? parmsLength : 0;
} else {
invokeArgs = new Object[parmsLength];
i = 0;
}
for (; i < parmsLength; i++) {
Object arg = (i < args.length)
? args[i]
: Undefined.instance;
if (types != null) {
Class desired = types[i];
if (desired == ScriptRuntime.BooleanClass
|| desired == Boolean.TYPE)
arg = ScriptRuntime.toBoolean(arg) ? Boolean.TRUE
: Boolean.FALSE;
else if (desired == ScriptRuntime.StringClass)
arg = ScriptRuntime.toString(arg);
else if (desired == ScriptRuntime.IntegerClass || desired == Integer.TYPE)
arg = new Integer(ScriptRuntime.toInt32(arg));
else if (desired == ScriptRuntime.DoubleClass || desired == Double.TYPE)
arg = new Double(ScriptRuntime.toNumber(arg));
else if (desired == ScriptRuntime.ScriptableClass)
arg = ScriptRuntime.toObject(this, arg);
else {
Object[] errArgs = { desired.getName() };
throw Context.reportRuntimeError(
Context.getMessage("msg.cant.convert", errArgs));
}
}
invokeArgs[i] = arg;
}
try {
Object result = (method != null)
? method.invoke(thisObj, invokeArgs)
: ctor.newInstance(invokeArgs);
return hasVoidReturn ? Undefined.instance : result;
}
catch (InvocationTargetException e) {
throw JavaScriptException.wrapException(scope, e);
}
catch (IllegalAccessException e) {
throw WrappedException.wrapException(e);
}
catch (InstantiationException e) {
throw WrappedException.wrapException(e);
}
}
/**
* Performs conversions on argument types if needed and
* invokes the underlying Java method or constructor
* to create a new Scriptable object.
* <p>
* Implements Function.construct.
*
* @param cx the current Context for this thread
* @param scope the scope to execute the function relative to. This
* set to the value returned by getParentScope() except
* when the function is called from a closure.
* @param args arguments to the constructor
* @see org.mozilla.javascript.Function#construct
* @exception JavaScriptException if the underlying Java method or constructor
* threw an exception
*/
public Scriptable construct(Context cx, Scriptable scope, Object[] args)
throws JavaScriptException
{
if (method == null || parmsLength == VARARGS_CTOR) {
Scriptable result = method != null
? (Scriptable) callVarargs(cx, null, args, true)
: (Scriptable) call(cx, scope, null, args);
if (result.getPrototype() == null)
result.setPrototype(getClassPrototype());
if (result.getParentScope() == null) {
Scriptable parent = getParentScope();
if (result != parent)
result.setParentScope(parent);
}
return result;
}
return super.construct(cx, scope, args);
}
private Object callVarargs(Context cx, Scriptable thisObj, Object[] args,
boolean inNewExpr)
throws JavaScriptException
{
try {
if (parmsLength == VARARGS_METHOD) {
Object[] invokeArgs = { cx, thisObj, args, this };
Object result = method.invoke(null, invokeArgs);
return hasVoidReturn ? Undefined.instance : result;
} else {
Boolean b = inNewExpr ? Boolean.TRUE : Boolean.FALSE;
Object[] invokeArgs = { cx, args, this, b };
return (method == null)
? ctor.newInstance(invokeArgs)
: method.invoke(null, invokeArgs);
}
}
catch (InvocationTargetException e) {
Throwable target = e.getTargetException();
if (target instanceof EvaluatorException)
throw (EvaluatorException) target;
Scriptable scope = thisObj == null ? this : thisObj;
throw JavaScriptException.wrapException(scope, target);
}
catch (IllegalAccessException e) {
throw WrappedException.wrapException(e);
}
catch (InstantiationException e) {
throw WrappedException.wrapException(e);
}
}
private static final short VARARGS_METHOD = -1;
private static final short VARARGS_CTOR = -2;
Method method;
Constructor ctor;
private Class[] types;
private short parmsLength;
private short lengthPropertyValue;
private boolean hasVoidReturn;
private boolean isStatic;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
class InterpretedFunction extends NativeFunction {
InterpretedFunction(InterpreterData theData, Context cx)
{
itsData = theData;
// probably too much copying going on from theData to the InterpretedFunction object
// should pass them as parameters - unless we need them in the data block anyway?
names = new String[itsData.itsVariableTable.size() + 1];
names[0] = itsData.itsName;
for (int i = 0; i < itsData.itsVariableTable.size(); i++)
names[i + 1] = itsData.itsVariableTable.getName(i);
argCount = (short)itsData.itsVariableTable.getParameterCount();
source = itsData.itsSource;
nestedFunctions = itsData.itsNestedFunctions;
version = (short)cx.getLanguageVersion();
}
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException
{
if (itsData.itsNeedsActivation)
scope = ScriptRuntime.initVarObj(cx, scope, this, thisObj, args);
itsData.itsCX = cx;
itsData.itsScope = scope;
itsData.itsThisObj = thisObj;
itsData.itsInArgs = args;
return Interpreter.interpret(itsData);
}
InterpreterData itsData;
}

Просмотреть файл

@ -0,0 +1,55 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
public class InterpretedScript extends NativeScript {
InterpretedScript(InterpreterData theData, Context cx)
{
itsData = theData;
names = new String[itsData.itsVariableTable.size() + 1];
names[0] = "";
for (int i = 0; i < itsData.itsVariableTable.size(); i++)
names[i + 1] = itsData.itsVariableTable.getName(i);
nestedFunctions = itsData.itsNestedFunctions;
version = (short)cx.getLanguageVersion();
}
public Object exec(Context cx, Scriptable scope)
throws JavaScriptException
{
return call(cx, scope, scope, null);
}
public Object call(Context cx, Scriptable scope,
Scriptable thisObj, Object[] args)
throws JavaScriptException
{
scope = ScriptRuntime.initScript(cx, scope, this, thisObj);
itsData.itsCX = cx;
itsData.itsScope = scope;
itsData.itsThisObj = thisObj;
itsData.itsInArgs = args;
return Interpreter.interpret(itsData);
}
InterpreterData itsData;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,80 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.util.Vector;
class InterpreterData {
static final int INITIAL_MAX_ICODE_LENGTH = 1024;
static final int INITIAL_STRINGTABLE_SIZE = 64;
static final int INITIAL_NUMBERTABLE_SIZE = 64;
InterpreterData(int lastICodeTop, int lastStringTableIndex,
int lastNumberTableIndex, Object securityDomain)
{
itsICodeTop = lastICodeTop == 0
? INITIAL_MAX_ICODE_LENGTH
: lastICodeTop * 2;
itsICode = new byte[itsICodeTop];
itsStringTable = new String[lastStringTableIndex == 0
? INITIAL_STRINGTABLE_SIZE
: lastStringTableIndex * 2];
itsNumberTable = new Number[lastNumberTableIndex == 0
? INITIAL_NUMBERTABLE_SIZE
: lastNumberTableIndex * 2];
if (securityDomain == null && Context.isSecurityDomainRequired())
throw new SecurityException("Required security context missing");
this.securityDomain = securityDomain;
}
VariableTable itsVariableTable;
String itsName;
String itsSource;
boolean itsNeedsActivation;
String[] itsStringTable;
int itsStringTableIndex;
Number[] itsNumberTable;
int itsNumberTableIndex;
InterpretedFunction[] itsNestedFunctions;
Object[] itsRegExpLiterals;
byte[] itsICode;
int itsICodeTop;
int itsMaxLocals;
int itsMaxArgs;
int itsMaxStack;
int itsMaxTryDepth;
Object securityDomain;
Context itsCX;
Scriptable itsScope;
Scriptable itsThisObj;
Object[] itsInArgs;
}

Просмотреть файл

@ -0,0 +1,305 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.lang.reflect.*;
import java.util.Hashtable;
import java.util.Enumeration;
/**
*
* @author Mike Shaver
* @author Norris Boyd
* @see NativeJavaObject
* @see NativeJavaClass
*/
class JavaMembers {
JavaMembers(Scriptable scope, Class cl) {
this.members = new Hashtable(23);
this.staticMembers = new Hashtable(7);
this.cl = cl;
reflect(scope, cl);
}
boolean has(String name, boolean isStatic) {
Hashtable ht = isStatic ? staticMembers : members;
return ht.get(name) != null;
}
Object get(Scriptable scope, String name, Object javaObject,
boolean isStatic)
{
Hashtable ht = isStatic ? staticMembers : members;
Object member = ht.get(name);
if (member == null)
return Scriptable.NOT_FOUND;
if (member instanceof Scriptable)
return member;
Field field = (Field) member;
Object rval;
try {
rval = field.get(isStatic ? null : javaObject);
} catch (IllegalAccessException accEx) {
throw new RuntimeException("unexpected IllegalAccessException "+
"accessing Java field");
}
// Need to wrap the object before we return it.
Class fieldType = field.getType();
scope = ScriptableObject.getTopLevelScope(scope);
return NativeJavaObject.wrap(scope, rval, fieldType);
}
public void put(String name, Object javaObject, Object value,
boolean isStatic)
{
Hashtable ht = isStatic ? staticMembers : members;
Object member = ht.get(name);
if (member == null)
throw reportMemberNotFound(name);
if (member instanceof FieldAndMethods) {
member = ((FieldAndMethods) ht.get(name)).getField();
}
Field field = null;
try {
field = (Field) member;
// XXX what was this for?
//if (obj instanceof Wrapper)
// obj = ((Wrapper)obj).unwrap();
field.set(javaObject, NativeJavaObject.coerceType(field.getType(),
value));
} catch (ClassCastException e) {
Object errArgs[] = { name };
throw Context.reportRuntimeError(Context.getMessage
("msg.java.method.assign",
errArgs));
} catch (IllegalAccessException accessEx) {
throw new RuntimeException("unexpected IllegalAccessException "+
"accessing Java field");
} catch (IllegalArgumentException argEx) {
Object errArgs[] = { value.getClass().getName(), field,
javaObject.getClass().getName() };
throw Context.reportRuntimeError(Context.getMessage(
"msg.java.internal.field.type", errArgs));
}
}
Object[] getIds(boolean isStatic) {
Hashtable ht = isStatic ? staticMembers : members;
int len = ht.size();
Object[] result = new Object[len];
Enumeration keys = ht.keys();
for (int i=0; i < len; i++)
result[i] = keys.nextElement();
return result;
}
Class getReflectedClass() {
return cl;
}
void reflectField(Field field) {
int mods = field.getModifiers();
if (!Modifier.isPublic(mods))
return;
boolean isStatic = Modifier.isStatic(mods);
Hashtable ht = isStatic ? staticMembers : members;
String name = field.getName();
Object member = ht.get(name);
if (member != null) {
if (member instanceof NativeJavaMethod) {
NativeJavaMethod method = (NativeJavaMethod) member;
Hashtable fmht = isStatic ? staticFieldAndMethods
: fieldAndMethods;
if (fmht == null) {
fmht = new Hashtable(11);
if (isStatic)
staticFieldAndMethods = fmht;
else
fieldAndMethods = fmht;
}
FieldAndMethods fam = new FieldAndMethods(method.getMethods(),
field);
fmht.put(name, fam);
ht.put(name, fam);
return;
}
if (member instanceof Field) {
Field oldField = (Field) member;
// beard:
// If an exception is thrown here, then JDirect classes on MRJ can't be used. JDirect
// classes implement multiple interfaces that each have a static "libraryInstance" field.
if (false) {
throw new RuntimeException("cannot have multiple Java " +
"fields with same name");
}
// If this newly reflected field shadows an inherited field, then replace it. Otherwise,
// since access to the field would be ambiguous from Java, no field should be reflected.
// For now, the first field found wins, unless another field explicitly shadows it.
if (oldField.getDeclaringClass().isAssignableFrom(field.getDeclaringClass()))
ht.put(name, field);
return;
}
throw new RuntimeException("unknown member type");
}
ht.put(name, field);
}
void reflectMethod(Scriptable scope, Method method) {
int mods = method.getModifiers();
if (!Modifier.isPublic(mods))
return;
boolean isStatic = Modifier.isStatic(mods);
Hashtable ht = isStatic ? staticMembers : members;
String name = method.getName();
NativeJavaMethod fun = (NativeJavaMethod) ht.get(name);
if (fun == null) {
fun = new NativeJavaMethod();
fun.setParentScope(scope);
fun.setPrototype(ScriptableObject.getFunctionPrototype(scope));
ht.put(name, fun);
fun.add(method);
}
else
fun.add(method);
}
void reflect(Scriptable scope, Class cl) {
// We reflect methods first, because we want overloaded field/method
// names to be allocated to the NativeJavaMethod before the field
// gets in the way.
Method[] methods = cl.getMethods();
for (int i = 0; i < methods.length; i++)
reflectMethod(scope, methods[i]);
Field[] fields = cl.getFields();
for (int i = 0; i < fields.length; i++)
reflectField(fields[i]);
ctors = cl.getConstructors();
}
Hashtable getFieldAndMethodsObjects(Object javaObject, boolean isStatic) {
Hashtable ht = isStatic ? staticFieldAndMethods : fieldAndMethods;
if (ht == null)
return null;
int len = ht.size();
Hashtable result = new Hashtable(len);
Enumeration e = ht.elements();
while (len-- > 0) {
FieldAndMethods fam = (FieldAndMethods) e.nextElement();
fam = (FieldAndMethods) fam.clone();
fam.setJavaObject(javaObject);
result.put(fam.getName(), fam);
}
return result;
}
Constructor[] getConstructors() {
return ctors;
}
static JavaMembers lookupClass(Scriptable scope, Class dynamicType,
Class staticType)
{
Class cl = dynamicType;
JavaMembers members = (JavaMembers) classTable.get(cl);
if (members != null)
return members;
if (staticType != null && staticType != dynamicType &&
!Modifier.isPublic(dynamicType.getModifiers()) &&
Modifier.isPublic(staticType.getModifiers()))
{
cl = staticType;
}
synchronized (classTable) {
members = (JavaMembers) classTable.get(cl);
if (members != null)
return members;
members = new JavaMembers(scope, cl);
classTable.put(cl, members);
return members;
}
}
RuntimeException reportMemberNotFound(String memberName) {
Object errArgs[] = { cl.getName(),
memberName };
return Context.reportRuntimeError(
Context.getMessage("msg.java.member.not.found",
errArgs));
}
private static Hashtable classTable = new Hashtable();
private Class cl;
private Hashtable members;
private Hashtable fieldAndMethods;
private Hashtable staticMembers;
private Hashtable staticFieldAndMethods;
private Constructor[] ctors;
}
class FieldAndMethods extends NativeJavaMethod {
FieldAndMethods(Method[] methods, Field field) {
super(methods);
this.field = field;
}
void setJavaObject(Object javaObject) {
this.javaObject = javaObject;
}
String getName() {
return field.getName();
}
Field getField() {
return field;
}
public Object getDefaultValue(Class hint) {
if (hint == ScriptRuntime.FunctionClass)
return this;
Object rval;
try {
rval = field.get(javaObject);
} catch (IllegalAccessException accEx) {
throw Context.reportRuntimeError(Context.getMessage
("msg.java.internal.private", null));
}
rval = NativeJavaObject.wrap(this, rval, field.getType());
if (rval instanceof Scriptable) {
((Scriptable)rval).setParentScope(this);
((Scriptable)rval).setPrototype(parent.getPrototype());
}
return rval;
}
public Object clone() {
FieldAndMethods result = new FieldAndMethods(methods, field);
result.javaObject = javaObject;
return result;
}
private Field field;
private Object javaObject;
}

Просмотреть файл

@ -0,0 +1,92 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
import java.lang.reflect.InvocationTargetException;
/**
* 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(ScriptRuntime.toString(value));
this.value = value;
}
/**
* Get the exception message.
*
* <p>Will just convert the wrapped exception to a string.
*/
public String getMessage() {
return ScriptRuntime.toString(value);
}
static JavaScriptException wrapException(Scriptable scope,
Throwable exn)
{
if (exn instanceof InvocationTargetException)
exn = ((InvocationTargetException)exn).getTargetException();
if (exn instanceof JavaScriptException)
return (JavaScriptException)exn;
Object wrapper = NativeJavaObject.wrap(scope, exn, Throwable.class);
return new JavaScriptException(wrapper);
}
/**
* 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() {
if (value != null && value instanceof Wrapper)
// this will also catch NativeStrings...
return ((Wrapper)value).unwrap();
else
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,87 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
public class Label {
private static final int FIXUPTABLE_SIZE = 8;
private static final boolean DEBUG = true;
public Label()
{
itsPC = -1;
}
public short getPC()
{
return itsPC;
}
public void fixGotos(byte theCodeBuffer[])
{
if (DEBUG) {
if ((itsPC == -1) && (itsFixupTable != null))
throw new RuntimeException("Unlocated label");
}
if (itsFixupTable != null) {
for (int i = 0; i < itsFixupTableTop; i++) {
int fixupSite = itsFixupTable[i];
// -1 to get delta from instruction start
short offset = (short)(itsPC - (fixupSite - 1));
theCodeBuffer[fixupSite++] = (byte)(offset >> 8);
theCodeBuffer[fixupSite] = (byte)offset;
}
}
itsFixupTable = null;
}
public void setPC(short thePC)
{
if (DEBUG) {
if ((itsPC != -1) && (itsPC != thePC))
throw new RuntimeException("Duplicate label");
}
itsPC = thePC;
}
public void addFixup(int fixupSite)
{
if (itsFixupTable == null) {
itsFixupTableTop = 1;
itsFixupTable = new int[FIXUPTABLE_SIZE];
itsFixupTable[0] = fixupSite;
}
else {
if (itsFixupTableTop == itsFixupTable.length) {
int oldLength = itsFixupTable.length;
int newTable[] = new int[oldLength + FIXUPTABLE_SIZE];
System.arraycopy(itsFixupTable, 0, newTable, 0, oldLength);
itsFixupTable = newTable;
}
itsFixupTable[itsFixupTableTop++] = fixupSite;
}
}
private short itsPC;
private int itsFixupTable[];
private int itsFixupTableTop;
}

Просмотреть файл

@ -0,0 +1,63 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
public class LabelTable {
private static final boolean DEBUGLABELS = false;
private static final int LabelTableSize = 32;
protected Label itsLabelTable[];
protected int itsLabelTableTop;
public int acquireLabel()
{
if (itsLabelTable == null) {
itsLabelTable = new Label[LabelTableSize];
itsLabelTable[0] = new Label();
itsLabelTableTop = 1;
return 0x80000000;
}
else {
if (itsLabelTableTop == itsLabelTable.length) {
Label oldTable[] = itsLabelTable;
itsLabelTable = new Label[itsLabelTableTop * 2];
System.arraycopy(oldTable, 0, itsLabelTable, 0, itsLabelTableTop);
}
itsLabelTable[itsLabelTableTop] = new Label();
int result = itsLabelTableTop++;
return result | 0x80000000;
}
}
public int markLabel(int theLabel, int pc)
{
if (DEBUGLABELS) {
if ((theLabel & 0x80000000) != 0x80000000)
throw new RuntimeException("Bad label, no biscuit");
}
theLabel &= 0x7FFFFFFF;
if (DEBUGLABELS) {
System.out.println("Marking label " + theLabel + " at " + pc);
}
itsLabelTable[theLabel].setPC((short)pc);
return theLabel | 0x80000000;
}
}

Просмотреть файл

@ -0,0 +1,348 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.io.Reader;
import java.io.IOException;
/**
* An input buffer that combines fast character-based access with
* (slower) support for retrieving the text of the current line. It
* also supports building strings directly out of the internal buffer
* to support fast scanning with minimal object creation.
*
* Note that it is customized in several ways to support the
* TokenStream class, and should not be considered general.
*
* Credits to Kipp Hickman and John Bandhauer.
*
* @author Mike McCabe
*/
final class LineBuffer {
/*
* for smooth operation of getLine(), this should be greater than
* the length of any expected line. Currently, 256 is 3% slower
* than 4096 for large compiles, but seems safer given evaluateString.
* Strings for the scanner are are built with StringBuffers
* instead of directly out of the buffer whenever a string crosses
* a buffer boundary, so small buffer sizes will mean that more
* objects are created.
*/
static final int BUFLEN = 256;
LineBuffer(Reader in, int lineno) {
this.in = in;
this.lineno = lineno;
}
int read() throws IOException {
if (end == offset && !fill())
return -1;
// Do only a bitmask + branch per character, at the cost of
// three branches per low-bits-only character.
if ((buffer[offset] & '\ufff0') == 0) {
if (buffer[offset] == '\r') {
// if the next character is a newline, skip past it.
if ((offset + 1) < end) {
if (buffer[offset + 1] == '\n')
offset++;
} else {
// set a flag for fill(), in case the first char of the
// next fill is a newline.
lastWasCR = true;
}
}
else if (buffer[offset] != '\n') {
return (int) buffer[offset++];
}
offset++;
prevStart = lineStart;
lineStart = offset;
lineno++;
return '\n';
}
return (int) buffer[offset++];
}
void unread() {
if (offset == 0)
// We can get here when we're asked to unread() an
// implicit EOF_CHAR.
// This would also 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. So we're OK.
return;
offset--;
if ((buffer[offset] & '\ufff0') == 0
&& (buffer[offset] == '\r' || buffer[offset] == '\n')) {
// back off from the line start we presumably just registered...
lineStart = prevStart;
lineno--;
}
}
int peek() throws IOException {
if (end == offset && !fill())
return -1;
if (buffer[offset] == '\r')
return '\n';
return buffer[offset];
}
boolean match(char c) throws IOException {
if (end == offset && !fill())
return false;
// This'd be a place where we'd need to map '\r' to '\n' and
// do other updates, but TokenStream never looks ahead for
// '\n', so we don't bother.
if (buffer[offset] == c) {
offset++;
return true;
}
return false;
}
// Reconstruct a source line from the buffers. This can be slow...
String getLine() {
StringBuffer result = new StringBuffer();
int start = lineStart;
if (start >= offset) {
// the line begins somewhere in the other buffer; get that first.
if (otherStart < otherEnd)
// if a line ending was seen in the other buffer... otherwise
// just ignore this strange case.
result.append(otherBuffer, otherStart,
otherEnd - otherStart);
start = 0;
}
// get the part of the line in the current buffer.
result.append(buffer, start, offset - start);
// Get the remainder of the line.
int i = offset;
while(true) {
if (i == buffer.length) {
// 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.
char[] newBuffer = new char[buffer.length * 2];
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
buffer = newBuffer;
int charsRead = 0;
try {
charsRead = in.read(buffer, end, buffer.length - end);
} catch (IOException ioe) {
// ignore it, we're already displaying an error...
}
if (charsRead < 0)
break;
end += charsRead;
}
if (buffer[i] == '\r' || buffer[i] == '\n')
break;
i++;
}
result.append(buffer, offset, i - offset);
return result.toString();
}
// Get the offset of the current character, relative to
// the line that getLine() returns.
int getOffset() {
if (lineStart >= offset)
// The line begins somewhere in the other buffer.
return offset + (otherEnd - otherStart);
else
return offset - lineStart;
}
// Set a mark to indicate that the reader should begin
// accumulating characters for getString(). The string begins
// with the last character read.
void startString() {
if (offset == 0) {
// We can get here if startString is called after a peek()
// or failed match() with offset past the end of the
// buffer.
// We're at the beginning of the buffer, and the previous character
// (which we want to include) is at the end of the last one, so
// we just go to StringBuffer mode.
stringSoFar = new StringBuffer();
stringSoFar.append(otherBuffer, otherEnd - 1, 1);
stringStart = -1; // Set sentinel value.
} else {
// Support restarting strings
stringSoFar = null;
stringStart = offset - 1;
}
}
// Get a string consisting of the characters seen since the last
// startString.
String getString() {
String result;
/*
* There's one strange case here: If the character offset currently
* points to (which we never want to include in the string) is
* a newline, then if the previous character is a carriage return,
* we probably want to exclude that as well. If the offset is 0,
* then we hope that fill() handled excluding it from stringSoFar.
*/
int loseCR = (offset > 0 &&
buffer[offset] == '\n' && buffer[offset - 1] == '\r') ?
1 : 0;
if (stringStart != -1) {
// String mark is valid, and in this buffer.
result = new String(buffer, stringStart,
offset - stringStart - loseCR);
} else {
// Exclude cr as well as nl of newline. If offset is 0, then
// hopefully fill() did the right thing.
result = (stringSoFar.append(buffer, 0, offset - loseCR)).toString();
}
stringStart = -1;
stringSoFar = null;
return result;
}
boolean fill() throws IOException {
// not sure I care...
if (end - offset != 0)
throw new IOException("fill of non-empty buffer");
// If there's a string currently being accumulated, save
// off the progress.
/*
* Exclude an end-of-buffer carriage return. NOTE this is not
* fully correct in the general case, because we really only
* want to exclude the carriage return if it's followed by a
* linefeed at the beginning of the next buffer. But we fudge
* because the scanner doesn't do this.
*/
int loseCR = (offset > 0 && lastWasCR) ? 1 : 0;
if (stringStart != -1) {
// The mark is in the current buffer, save off from the mark to the
// end.
stringSoFar = new StringBuffer();
stringSoFar.append(buffer, stringStart, end - stringStart - loseCR);
stringStart = -1;
} else if (stringSoFar != null) {
// the string began prior to the current buffer, so save the
// whole current buffer.
stringSoFar.append(buffer, 0, end - loseCR);
}
// 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.
otherStart = lineStart;
otherEnd = end;
// set lineStart to a sentinel value, unless this is the first
// time around.
prevStart = lineStart = (otherBuffer == null) ? 0 : buffer.length + 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 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;
private int stringStart = -1;
private StringBuffer stringSoFar = null;
}

Просмотреть файл

@ -0,0 +1,40 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
public class LocalVariable {
public LocalVariable(String name, boolean isParameter) {
itsName = name;
itsIsParameter = isParameter;
}
public void setIndex(int index){ itsIndex = index; }
public int getIndex() { return itsIndex; }
public void setIsParameter() { itsIsParameter = true; }
public boolean isParameter() { return itsIsParameter; }
public String getName() { return itsName; }
private String itsName;
private int itsIndex = -1;
private boolean itsIsParameter;
}

Просмотреть файл

@ -0,0 +1,919 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.util.Hashtable;
/**
* This class implements the Array native object.
* @author Norris Boyd
* @author Mike McCabe
*/
public class NativeArray extends ScriptableObject {
/*
* Optimization possibilities and open issues:
* - Long vs. double schizophrenia. I suspect it might be better
* to use double throughout.
* - Most array operations go through getElem or setElem (defined
* in this file) to handle the full 2^32 range; it might be faster
* to have versions of most of the loops in this file for the
* (infinitely more common) case of indices < 2^31.
* - Functions that need a new Array call "new Array" in the
* current scope rather than using a hardwired constructor;
* "Array" could be redefined. It turns out that js calls the
* equivalent of "new Array" in the current scope, except that it
* always gets at least an object back, even when Array == null.
*/
/**
* Zero-parameter constructor: just used to create Array.prototype
*/
public NativeArray() {
dense = null;
this.length = 0;
}
public NativeArray(long length) {
int intLength = (int) length;
if (intLength == length && intLength > 0) {
if (intLength > maximumDenseLength)
intLength = maximumDenseLength;
dense = new Object[intLength];
for (int i=0; i < intLength; i++)
dense[i] = NOT_FOUND;
}
this.length = length;
}
public NativeArray(Object[] array) {
dense = array;
this.length = array.length;
}
public static void finishInit(Scriptable scope, FunctionObject ctor,
Scriptable proto)
{
// Set some method length values.
// See comment for NativeString.finishInit()
String[] specialLengthNames = { "reverse",
"toString",
};
short[] specialLengthValues = { 0,
0,
};
for (int i=0; i < specialLengthNames.length; i++) {
Object obj = proto.get(specialLengthNames[i], proto);
((FunctionObject) obj).setLength(specialLengthValues[i]);
}
}
public String getClassName() {
return "Array";
}
public Object get(int index, Scriptable start) {
if (dense != null && 0 <= index && index < dense.length)
return dense[index];
return super.get(index, start);
}
public boolean has(int index, Scriptable start) {
if (dense != null && 0 <= index && index < dense.length)
return dense[index] != NOT_FOUND;
return super.has(index, start);
}
public void put(String id, Scriptable start, Object value) {
// only set the array length if given an array index (ECMA 15.4.0)
// try to get an array index from id
double d = ScriptRuntime.toNumber(id);
if (ScriptRuntime.toUint32(d) == d &&
ScriptRuntime.numberToString(d).equals(id) &&
this.length <= d && d != 4294967295.0)
this.length = (long)d + 1;
super.put(id, start, value);
}
public void put(int index, Scriptable start, Object value) {
// only set the array length if given an array index (ECMA 15.4.0)
if (this.length <= index) {
// avoid overflowing index!
this.length = (long)index + 1;
}
if (dense != null && 0 <= index && index < dense.length) {
dense[index] = value;
return;
}
super.put(index, start, value);
}
public void delete(int index) {
if (dense != null && 0 <= index && index < dense.length) {
dense[index] = NOT_FOUND;
return;
}
super.delete(index);
}
public Object[] getIds() {
Object[] superIds = super.getIds();
if (dense == null)
return superIds;
int count = 0;
int last = dense.length;
if (last > length)
last = (int) length;
for (int i=last-1; i >= 0; i--) {
if (dense[i] != NOT_FOUND)
count++;
}
count += superIds.length;
Object[] result = new Object[count];
System.arraycopy(superIds, 0, result, 0, superIds.length);
for (int i=last-1; i >= 0; i--) {
if (dense[i] != NOT_FOUND)
result[--count] = new Integer(i);
}
return result;
}
public Object getDefaultValue(Class hint) {
if (hint == ScriptRuntime.NumberClass) {
Context cx = Context.getContext();
if (cx.getLanguageVersion() == Context.VERSION_1_2)
return new Long(length);
}
return super.getDefaultValue(hint);
}
/**
* See ECMA 15.4.1,2
*/
public static Object js_Array(Context cx, Object[] args, Function ctorObj,
boolean inNewExpr)
throws JavaScriptException
{
if (!inNewExpr) {
// FunctionObject.construct will set up parent, proto
return ctorObj.construct(cx, ctorObj.getParentScope(), args);
}
if (args.length == 0)
return new NativeArray();
// Only use 1 arg as first element for version 1.2; for
// any other version (including 1.3) follow ECMA and use it as
// a length.
if (args.length == 1 && args[0] instanceof Number &&
cx.getLanguageVersion() != cx.VERSION_1_2)
{
return new NativeArray(ScriptRuntime.toUint32(args[0]));
}
// initialize array with arguments
return new NativeArray(args);
}
private static final int lengthAttr = ScriptableObject.DONTENUM |
ScriptableObject.PERMANENT;
public long js_getLength() {
return length;
}
public void js_setLength(Object val) {
/* XXX do we satisfy this?
* 15.4.5.1 [[Put]](P, V):
* 1. Call the [[CanPut]] method of A with name P.
* 2. If Result(1) is false, return.
* ?
*/
long longVal = ScriptRuntime.toUint32(val);
if (longVal < length) {
// remove all properties between longVal and length
if (length - longVal > 0x1000) {
// assume that the representation is sparse
Object[] e = getIds(); // will only find in object itself
for (int i=0; i < e.length; i++) {
if (e[i] instanceof String) {
// > MAXINT will appear as string
String id = (String) e[i];
double d = ScriptRuntime.toNumber(id);
if (d == d && d < length)
delete(id);
continue;
}
int index = ((Number) e[i]).intValue();
if (index >= longVal)
delete(index);
}
} else {
// assume a dense representation
for (long i=longVal; i < length; i++) {
// only delete if defined in the object itself
if (hasElem(this, i))
ScriptRuntime.delete(this, new Long(i));
}
}
}
length = longVal;
}
/* Support for generic Array-ish objects. Most of the Array
* functions try to be generic; anything that has a length
* property is assumed to be an array. hasLengthProperty is
* needed in addition to getLengthProperty, because
* getLengthProperty always succeeds - tries to convert strings, etc.
*/
static double getLengthProperty(Scriptable obj) {
// These will both give numeric lengths within Uint32 range.
if (obj instanceof NativeString)
return (double)((NativeString)obj).js_getLength();
if (obj instanceof NativeArray)
return (double)((NativeArray)obj).js_getLength();
return ScriptRuntime.toUint32(ScriptRuntime
.getProp(obj, "length", obj));
}
static boolean hasLengthProperty(Object obj) {
if (!(obj instanceof Scriptable) || obj == Context.getUndefinedValue())
return false;
if (obj instanceof NativeString || obj instanceof NativeArray)
return true;
Scriptable sobj = (Scriptable)obj;
// XXX some confusion as to whether or not to walk to get the length
// property. Pending review of js/[new ecma submission] treatment
// of 'arrayness'.
Object property = ScriptRuntime.getProp(sobj, "length", sobj);
return property instanceof Number;
}
/* Utility functions to encapsulate index > Integer.MAX_VALUE
* handling. Also avoids unnecessary object creation that would
* be necessary to use the general ScriptRuntime.get/setElem
* functions... though this is probably premature optimization.
*/
private static boolean hasElem(Scriptable target, long index) {
return index > Integer.MAX_VALUE
? target.has(Long.toString(index), target)
: target.has((int)index, target);
}
private static Object getElem(Scriptable target, long index) {
if (index > Integer.MAX_VALUE) {
String id = Long.toString(index);
return ScriptRuntime.getElem(target, id, target);
} else {
return ScriptRuntime.getElem(target, (int)index);
}
}
private static void setElem(Scriptable target, long index, Object value) {
if (index > Integer.MAX_VALUE) {
String id = Long.toString(index);
ScriptRuntime.setElem(target, id, value, target);
} else {
ScriptRuntime.setElem(target, (int)index, value);
}
}
public static String js_toString(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
return toStringHelper(cx, thisObj,
cx.getLanguageVersion() == cx.VERSION_1_2);
}
private static String toStringHelper(Context cx, Scriptable thisObj,
boolean toSource)
{
/* It's probably redundant to handle long lengths in this
* function; StringBuffers are limited to 2^31 in java.
*/
long length = (long)getLengthProperty(thisObj);
StringBuffer result = new StringBuffer();
if (cx.iterating == null)
cx.iterating = new Hashtable(31);
boolean iterating = cx.iterating.get(thisObj) == Boolean.TRUE;
// whether to return '4,unquoted,5' or '[4, "quoted", 5]'
String separator;
if (toSource) {
result.append("[");
separator = ", ";
} else {
separator = ",";
}
boolean haslast = false;
long i = 0;
if (!iterating) {
for (i = 0; i < length; i++) {
if (i > 0)
result.append(separator);
Object elem = getElem(thisObj, i);
if (elem == null || elem == Undefined.instance) {
haslast = false;
continue;
}
haslast = true;
if (elem instanceof String) {
if (toSource) {
result.append("\"");
result.append(ScriptRuntime.escapeString
(ScriptRuntime.toString(elem)));
result.append("\"");
} else {
result.append(ScriptRuntime.toString(elem));
}
} else {
/* wrap changes to cx.iterating in a try/finally
* so that the reference always gets removed, and
* we don't leak memory. Good place for weak
* references, if we had them. */
try {
// stop recursion.
cx.iterating.put(thisObj, Boolean.TRUE);
result.append(ScriptRuntime.toString(elem));
} finally {
cx.iterating.remove(thisObj);
}
}
}
}
if (toSource) {
//for [,,].length behavior; we want toString to be symmetric.
if (!haslast && i > 0)
result.append(", ]");
else
result.append("]");
}
return result.toString();
}
/**
* See ECMA 15.4.4.3
*/
public static String js_join(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
StringBuffer result = new StringBuffer();
String separator;
double length = getLengthProperty(thisObj);
// if no args, use "," as separator
if (args.length < 1) {
separator = ",";
} else {
separator = ScriptRuntime.toString(args[0]);
}
for (long i=0; i < length; i++) {
if (i > 0)
result.append(separator);
Object temp = getElem(thisObj, i);
if (temp == null || temp == Undefined.instance)
continue;
result.append(ScriptRuntime.toString(temp));
}
return result.toString();
}
/**
* See ECMA 15.4.4.4
*/
public static Scriptable js_reverse(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
long len = (long)getLengthProperty(thisObj);
long half = len / 2;
for(long i=0; i < half; i++) {
long j = len - i - 1;
Object temp1 = getElem(thisObj, i);
Object temp2 = getElem(thisObj, j);
setElem(thisObj, i, temp2);
setElem(thisObj, j, temp1);
}
return thisObj;
}
/**
* See ECMA 15.4.4.5
*/
public static Scriptable js_sort(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws JavaScriptException
{
long length = (long)getLengthProperty(thisObj);
Object compare;
if (args.length > 0 && Undefined.instance != args[0])
// sort with given compare function
compare = args[0];
else
// sort with default compare
compare = null;
// OPT: Would it make sense to use the extended sort for very small
// arrays?
// Should we use the extended sort function, or the faster one?
if (length >= Integer.MAX_VALUE) {
qsort_extended(cx, compare, thisObj, 0, length - 1);
} else {
// copy the JS array into a working array, so it can be
// sorted cheaply.
Object[] working = new Object[(int)length];
for (int i=0; i<length; i++) {
working[i] = getElem(thisObj, i);
}
qsort(cx, compare, working, 0, (int)length - 1);
// copy the working array back into thisObj
for (int i=0; i<length; i++) {
setElem(thisObj, i, working[i]);
}
}
return thisObj;
}
private static double qsortCompare(Context cx, Object jsCompare, Object x,
Object y)
throws JavaScriptException
{
Object undef = Undefined.instance;
// sort undefined to end
if (undef == x || undef == y) {
if (undef != x)
return -1;
if (undef != y)
return 1;
return 0;
}
if (jsCompare == null) {
// if no compare function supplied, sort lexicographically
String a = ScriptRuntime.toString(x);
String b = ScriptRuntime.toString(y);
return a.compareTo(b);
} else {
// assemble args and call supplied JS compare function
// OPT: put this argument creation in the caller and reuse it.
// XXX what to do when compare function returns NaN? ECMA states
// that it's then not a 'consistent compararison function'... but
// then what do we do? Back out and start over with the generic
// compare function when we see a NaN? Throw an error?
Object[] args = {x, y};
// return ScriptRuntime.toNumber(ScriptRuntime.call(jsCompare, null,
// args));
// for now, just ignore it:
double d = ScriptRuntime.
toNumber(ScriptRuntime.call(cx, jsCompare, null, args));
return (d == d) ? d : 0;
}
}
private static void qsort(Context cx, Object jsCompare, Object[] working,
int lo, int hi)
throws JavaScriptException
{
Object pivot;
int i, j;
int a, b;
while (lo < hi) {
i = lo;
j = hi;
a = i;
pivot = working[a];
while (i < j) {
for(;;) {
b = j;
if (qsortCompare(cx, jsCompare, working[j], pivot) <= 0)
break;
j--;
}
working[a] = working[b];
while (i < j && qsortCompare(cx, jsCompare, working[a],
pivot) <= 0)
{
i++;
a = i;
}
working[b] = working[a];
}
working[a] = pivot;
if (i - lo < hi - i) {
qsort(cx, jsCompare, working, lo, i - 1);
lo = i + 1;
} else {
qsort(cx, jsCompare, working, i + 1, hi);
hi = i - 1;
}
}
}
// A version that knows about long indices and doesn't use
// a working array. Probably will never be used.
private static void qsort_extended(Context cx, Object jsCompare,
Scriptable target, long lo, long hi)
throws JavaScriptException
{
Object pivot;
long i, j;
long a, b;
while (lo < hi) {
i = lo;
j = hi;
a = i;
pivot = getElem(target, a);
while (i < j) {
for(;;) {
b = j;
if (qsortCompare(cx, jsCompare, getElem(target, j),
pivot) <= 0)
break;
j--;
}
setElem(target, a, getElem(target, b));
while (i < j && qsortCompare(cx, jsCompare,
getElem(target, a), pivot) <= 0)
{
i++;
a = i;
}
setElem(target, b, getElem(target, a));
}
setElem(target, a, pivot);
if (i - lo < hi - i) {
qsort_extended(cx, jsCompare, target, lo, i - 1);
lo = i + 1;
} else {
qsort_extended(cx, jsCompare, target, i + 1, hi);
hi = i - 1;
}
}
}
/**
* Non-ECMA methods.
*/
public static Object js_push(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
double length = getLengthProperty(thisObj);
for (int i = 0; i < args.length; i++) {
setElem(thisObj, (long)length + i, args[i]);
}
length += args.length;
ScriptRuntime.setProp(thisObj, "length", new Double(length), thisObj);
/*
* If JS1.2, follow Perl4 by returning the last thing pushed.
* Otherwise, return the new array length.
*/
if (cx.getLanguageVersion() == Context.VERSION_1_2)
// if JS1.2 && no arguments, return undefined.
return args.length == 0
? Context.getUndefinedValue()
: args[args.length - 1];
else
return new Long((long)length);
}
public static Object js_pop(Context cx, Scriptable thisObj, Object[] args,
Function funObj)
{
Object result;
double length = getLengthProperty(thisObj);
if (length > 0) {
length--;
// Get the to-be-deleted property's value.
result = getElem(thisObj, (long)length);
// We don't need to delete the last property, because
// setLength does that for us.
} else {
result = Context.getUndefinedValue();
}
// necessary to match js even when length < 0; js pop will give a
// length property to any target it is called on.
ScriptRuntime.setProp(thisObj, "length", new Double(length), thisObj);
return result;
}
public static Object js_shift(Context cx, Scriptable thisObj, Object[] args,
Function funOjb)
{
Object result;
double length = getLengthProperty(thisObj);
if (length > 0) {
long i = 0;
length--;
// Get the to-be-deleted property's value.
result = getElem(thisObj, i);
/*
* Slide down the array above the first element. Leave i
* set to point to the last element.
*/
if (length > 0) {
for (i = 1; i <= length; i++) {
Object temp = getElem(thisObj, i);
setElem(thisObj, i - 1, temp);
}
}
// We don't need to delete the last property, because
// setLength does that for us.
} else {
result = Context.getUndefinedValue();
}
ScriptRuntime.setProp(thisObj, "length", new Double(length), thisObj);
return result;
}
public static Object js_unshift(Context cx, Scriptable thisObj,
Object[] args, Function funOjb)
{
Object result;
double length = (double)getLengthProperty(thisObj);
int argc = args.length;
if (args.length > 0) {
/* Slide up the array to make room for args at the bottom */
if (length > 0) {
for (long last = (long)length - 1; last >= 0; last--) {
Object temp = getElem(thisObj, last);
setElem(thisObj, last + argc, temp);
}
}
/* Copy from argv to the bottom of the array. */
for (int i = 0; i < args.length; i++) {
setElem(thisObj, i, args[i]);
}
/* Follow Perl by returning the new array length. */
length += args.length;
ScriptRuntime.setProp(thisObj, "length",
new Double(length), thisObj);
}
return new Long((long)length);
}
public static Object js_splice(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
/* create an empty Array to return. */
Scriptable scope = getTopLevelScope(funObj);
Object result = ScriptRuntime.newObject(cx, scope, "Array", null);
int argc = args.length;
if (argc == 0)
return result;
double length = getLengthProperty(thisObj);
/* Convert the first argument into a starting index. */
double begin = ScriptRuntime.toInteger(args[0]);
double end;
double delta;
double count;
if (begin < 0) {
begin += length;
if (begin < 0)
begin = 0;
} else if (begin > length) {
begin = length;
}
argc--;
/* Convert the second argument from a count into a fencepost index. */
delta = length - begin;
if (args.length == 1) {
count = delta;
end = length;
} else {
count = ScriptRuntime.toInteger(args[1]);
if (count < 0)
count = 0;
else if (count > delta)
count = delta;
end = begin + count;
argc--;
}
long lbegin = (long)begin;
long lend = (long)end;
/* If there are elements to remove, put them into the return value. */
if (count > 0) {
if (count == 1
&& (cx.getLanguageVersion() == Context.VERSION_1_2))
{
/*
* JS lacks "list context", whereby in Perl one turns the
* single scalar that's spliced out into an array just by
* assigning it to @single instead of $single, or by using it
* as Perl push's first argument, for instance.
*
* JS1.2 emulated Perl too closely and returned a non-Array for
* the single-splice-out case, requiring callers to test and
* wrap in [] if necessary. So JS1.3, default, and other
* versions all return an array of length 1 for uniformity.
*/
result = getElem(thisObj, lbegin);
} else {
for (long last = lbegin; last < lend; last++) {
Scriptable resultArray = (Scriptable)result;
Object temp = getElem(thisObj, last);
setElem(resultArray, last - lbegin, temp);
}
}
} else if (count == 0
&& cx.getLanguageVersion() == Context.VERSION_1_2)
{
/* Emulate C JS1.2; if no elements are removed, return undefined. */
result = Context.getUndefinedValue();
}
/* Find the direction (up or down) to copy and make way for argv. */
delta = argc - count;
if (delta > 0) {
for (long last = (long)length - 1; last >= lend; last--) {
Object temp = getElem(thisObj, last);
setElem(thisObj, last + (long)delta, temp);
}
} else if (delta < 0) {
for (long last = lend; last < length; last++) {
Object temp = getElem(thisObj, last);
setElem(thisObj, last + (long)delta, temp);
}
}
/* Copy from argv into the hole to complete the splice. */
int argoffset = args.length - argc;
for (int i = 0; i < argc; i++) {
setElem(thisObj, lbegin + i, args[i + argoffset]);
}
/* Update length in case we deleted elements from the end. */
ScriptRuntime.setProp(thisObj, "length",
new Double(length + delta), thisObj);
return result;
}
/*
* Python-esque sequence operations.
*/
public static Scriptable js_concat(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
/* Concat tries to keep the definition of an array as general
* as possible; if it finds that an object has a numeric
* 'length' property, then it treats that object as an array.
* This treats string atoms and string objects differently; as
* string objects have a length property and are accessible by
* index, they get exploded into arrays when added, while
* atomic strings are just added as strings.
*/
// create an empty Array to return.
Scriptable scope = getTopLevelScope(funObj);
Scriptable result = ScriptRuntime.newObject(cx, scope, "Array", null);
double length;
long slot = 0;
/* Put the target in the result array; only add it as an array
* if it looks like one.
*/
if (hasLengthProperty(thisObj)) {
length = getLengthProperty(thisObj);
// Copy from the target object into the result
for (slot = 0; slot < length; slot++) {
Object temp = getElem(thisObj, slot);
setElem(result, slot, temp);
}
} else {
setElem(result, slot++, thisObj);
}
/* Copy from the arguments into the result. If any argument
* has a numeric length property, treat it as an array and add
* elements separately; otherwise, just copy the argument.
*/
for (int i = 0; i < args.length; i++) {
if (hasLengthProperty(args[i])) {
// hasLengthProperty => instanceOf Scriptable.
Scriptable arg = (Scriptable)args[i];
length = getLengthProperty(arg);
for (long j = 0; j < length; j++, slot++) {
Object temp = getElem(arg, j);
setElem(result, slot, temp);
}
} else {
setElem(result, slot++, args[i]);
}
}
return result;
}
public static Scriptable js_slice(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
Scriptable scope = getTopLevelScope(funObj);
Scriptable result = ScriptRuntime.newObject(cx, scope, "Array", null);
double length = getLengthProperty(thisObj);
double begin = 0;
double end = length;
if (args.length > 0) {
begin = ScriptRuntime.toInteger(args[0]);
if (begin < 0) {
begin += length;
if (begin < 0)
begin = 0;
} else if (begin > length) {
begin = length;
}
if (args.length > 1) {
end = ScriptRuntime.toInteger(args[1]);
if (end < 0) {
end += length;
if (end < 0)
end = 0;
} else if (end > length) {
end = length;
}
}
}
long lbegin = (long)begin;
long lend = (long)end;
for (long slot = lbegin; slot < lend; slot++) {
Object temp = getElem(thisObj, slot);
setElem(result, slot - lbegin, temp);
}
return result;
}
private long length;
private Object[] dense;
private static final int maximumDenseLength = 10000;
}

Просмотреть файл

@ -0,0 +1,74 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This class implements the Boolean native object.
* See ECMA 15.6.
* @author Norris Boyd
*/
public class NativeBoolean extends ScriptableObject {
/**
* Zero-parameter constructor: just used to create Boolean.prototype
*/
public NativeBoolean() {
}
public NativeBoolean(boolean b) {
booleanValue = b;
}
public String getClassName() {
return "Boolean";
}
public Object getDefaultValue(Class typeHint) {
// This is actually non-ECMA, but will be proposed
// as a change in round 2.
if (typeHint == ScriptRuntime.BooleanClass)
return booleanValue ? Boolean.TRUE : Boolean.FALSE;
return super.getDefaultValue(typeHint);
}
public static Object Boolean(Context cx, Object[] args, Function ctorObj,
boolean inNewExpr)
{
boolean b = args.length >= 1
? ScriptRuntime.toBoolean(args[0])
: false;
if (inNewExpr) {
// new Boolean(val) creates a new boolean object.
return new NativeBoolean(b);
}
// Boolean(val) converts val to a boolean.
return b ? Boolean.TRUE : Boolean.FALSE;
}
public String toString() {
return booleanValue ? "true" : "false";
}
public boolean valueOf() {
return booleanValue;
}
private boolean booleanValue;
}

Просмотреть файл

@ -0,0 +1,128 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This class implements the activation object.
*
* See ECMA 10.1.6
*
* @see org.mozilla.javascript.Arguments
* @author Norris Boyd
*/
public final class NativeCall extends ScriptableObject {
NativeCall(Context cx, Scriptable scope, NativeFunction funObj,
Scriptable thisObj, Object[] args)
{
this(cx, scope, funObj, thisObj);
this.originalArgs = args;
// initialize references to nested functions
NativeFunction[] fns = funObj.nestedFunctions;
if (fns != null) {
for (int i=0; i < fns.length; i++) {
NativeFunction f = fns[i];
if (f.names != null)
super.put(f.names[0], this, f);
}
}
// initialize values of arguments
String[] names = funObj.names;
if (names != null) {
for (int i=0; i < funObj.argCount; i++) {
Object val = i < args.length ? args[i]
: Undefined.instance;
super.put(names[i+1], this, val);
}
}
// initialize "arguments" property
super.put("arguments", this, new Arguments(this));
}
NativeCall(Context cx, Scriptable scope, NativeFunction funObj,
Scriptable thisObj)
{
this.funObj = funObj;
this.thisObj = thisObj;
setParentScope(scope);
// leave prototype null
// save current activation
this.caller = cx.currentActivation;
cx.currentActivation = this;
}
// Needed in order to use this class with ScriptableObject.defineClass
public NativeCall() {
}
public String getClassName() {
return "Call";
}
public static Object js_Call(Context cx, Object[] args, Function ctorObj,
boolean inNewExpr)
{
if (!inNewExpr) {
Object[] errArgs = { "Call" };
throw Context.reportRuntimeError(Context.getMessage
("msg.only.from.new", errArgs));
}
ScriptRuntime.checkDeprecated(cx, "Call");
NativeCall result = new NativeCall();
result.setPrototype(getObjectPrototype(ctorObj));
return result;
}
NativeCall getActivation(NativeFunction f) {
NativeCall x = this;
do {
if (x.funObj == f)
return x;
x = x.caller;
} while (x != null);
return null;
}
public NativeFunction getFunctionObject() {
return funObj;
}
public Object[] getOriginalArguments() {
return originalArgs;
}
public NativeCall getCaller() {
return caller;
}
public Scriptable getThisObj() {
return thisObj;
}
NativeCall caller;
NativeFunction funObj;
Scriptable thisObj;
Object[] originalArgs;
public int debugPC;
}

Просмотреть файл

@ -0,0 +1,103 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This class implements the closure object.
*
* @author Norris Boyd
*/
public class NativeClosure extends ScriptableObject implements Function {
public NativeClosure() {
}
public NativeClosure(Context cx, Scriptable scope, NativeFunction f) {
setPrototype(f);
setParentScope(scope);
String name = f.names != null ? f.names[0] : "";
if (name != null && name.length() > 0) {
scope.put(name, scope, scope.getParentScope() == null
? (Object) f : this);
}
}
public String getClassName() {
return "Closure";
}
public Object getDefaultValue(Class typeHint) {
if (typeHint == ScriptRuntime.FunctionClass)
return prototype;
return super.getDefaultValue(typeHint);
}
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException
{
Function proto = checkProto();
return proto.call(cx, getParentScope(), thisObj, args);
}
public Scriptable construct(Context cx, Scriptable scope, Object[] args)
throws JavaScriptException
{
Function proto = checkProto();
return proto.construct(cx, getParentScope(), args);
}
public static Object js_Closure(Context cx, Object[] args,
Function ctorObj, boolean inNewExpr)
{
Object[] msgArgs = { "Closure" };
throw Context.reportRuntimeError(
Context.getMessage("msg.cant.call.indirect", msgArgs));
}
public static Object newClosureSpecial(Context cx, Scriptable varObj,
Object[] args, Function ctorObj)
{
ScriptRuntime.checkDeprecated(cx, "Closure");
NativeFunction f = args.length > 0 &&
args[0] instanceof NativeFunction
? (NativeFunction) args[0]
: null;
NativeClosure result = f != null
? new NativeClosure(cx, varObj, f)
: new NativeClosure();
Scriptable scope = getTopLevelScope(ctorObj);
result.setPrototype(args.length == 0
? getObjectPrototype(scope)
: ScriptRuntime.toObject(scope, args[0]));
result.setParentScope(varObj);
return result;
}
private Function checkProto() {
Scriptable proto = getPrototype();
if (!(proto instanceof Function)) {
throw Context.reportRuntimeError(Context.getMessage
("msg.closure.proto", null));
}
return (Function) proto;
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,997 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.util.Hashtable;
/**
* This class implements the Function native object.
* See ECMA 15.3.
* @author Norris Boyd
*/
public class NativeFunction extends ScriptableObject implements Function {
public static void finishInit(Scriptable scope, FunctionObject ctor,
Scriptable proto)
{
// Fix up bootstrapping problem: the prototype of the Function
// constructor was set to null because Function.prototype
// was not yet defined.
ctor.setPrototype(proto);
String[] noName = { "" };
((NativeFunction) proto).names = noName;
}
public String getClassName() {
return "Function";
}
public boolean has(String s, Scriptable start) {
return s.equals("prototype") || s.equals("arguments") ||
super.has(s, start);
}
public Object get(String s, Scriptable start) {
Object result = super.get(s, start);
if (result != NOT_FOUND)
return result;
if (s.equals("prototype")) {
NativeObject obj = new NativeObject();
obj.setPrototype(getObjectPrototype(this));
final int attr = ScriptableObject.DONTENUM |
ScriptableObject.READONLY |
ScriptableObject.PERMANENT;
obj.defineProperty("constructor", this, attr);
put(s, this, obj);
return obj;
}
if (s.equals("arguments")) {
// <Function name>.arguments is deprecated, so we use a slow
// way of getting it that doesn't add to the invocation cost.
// TODO: add warning, error based on version
NativeCall activation = getActivation(Context.getContext());
return activation == null
? null
: activation.get("arguments", activation);
}
return NOT_FOUND;
}
/**
* Implements the instanceof operator for JavaScript Function objects.
* <p>
* <code>
* foo = new Foo();<br>
* foo instanceof Foo; // true<br>
* </code>
*
* <p>This operator has been proposed to ECMA.
*
* @param instance The value that appeared on the LHS of the instanceof
* operator
* @return true if the "prototype" property of "this" appears in
* value's prototype chain
*
*/
public boolean hasInstance(Scriptable instance) {
FlattenedObject flat = new FlattenedObject(this);
Object protoProp = flat.getProperty("prototype");
try {
protoProp = ((FlattenedObject)protoProp).getObject();
} catch (ClassCastException e) {
Object[] args = { names[0] };
throw Context.reportRuntimeError(Context.getMessage
("msg.instanceof.bad.prototype", args));
}
return ScriptRuntime.jsDelegatesTo(instance, (Scriptable)protoProp);
}
/**
* Should be overridden.
*/
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException
{
return Undefined.instance;
}
protected Scriptable getClassPrototype() {
Object protoVal = get("prototype", this);
if (protoVal == null || !(protoVal instanceof Scriptable))
protoVal = getClassPrototype(this, "Object");
return (Scriptable) protoVal;
}
public Scriptable construct(Context cx, Scriptable scope, Object[] args)
throws JavaScriptException
{
Scriptable newInstance = new NativeObject();
newInstance.setPrototype(getClassPrototype());
newInstance.setParentScope(getParentScope());
Object val = call(cx, scope, newInstance, args);
if (val != null && val != Undefined.instance &&
val instanceof Scriptable)
{
return (Scriptable) val;
}
return newInstance;
}
private boolean nextIs(int i, int token) {
if (i + 1 < source.length())
return source.charAt(i + 1) == token;
return false;
}
// how much to indent
private final static int OFFSET = 4;
// less how much for case labels
private final static int SETBACK = 2;
// whether to do a debug print of the source information, when
// decompiling.
private static final boolean printSource = false;
/**
* Decompile the source information associated with this js
* function/script back into a string. For the most part, this
* just means translating tokens back to their string
* representations; there's a little bit of lookahead logic to
* decide the proper spacing/indentation. Most of the work in
* mapping the original source to the prettyprinted decompiled
* version is done by the parser.
*
* Note that support for Context.decompileFunctionBody is hacked
* on through special cases; I suspect that js makes a distinction
* between function header and function body that rhino
* decompilation does not.
*
* @param indent How much to indent the decompiled result
*
* @param toplevel Whether this is the first call or a recursive
* call of decompile. (Not whether the function is defined at the
* top level of script evaluation.)
*
* @param justbody Whether the decompilation should omit the
* function header and trailing brace.
*/
public String decompile(int indent, boolean toplevel, boolean justbody) {
if (source == null)
return "function " + js_getName() +
"() {\n\t[native code]\n}\n";
// Spew tokens in source, for debugging.
// as TYPE number char
if (printSource) {
System.err.println("length:" + source.length());
for (int i = 0; i < source.length(); i++) {
// Note that tokenToName will fail unless Context.printTrees
// is true.
String tokenname = TokenStream.tokenToName(source.charAt(i));
if (tokenname == null)
tokenname = "---";
String pad = tokenname.length() > 7
? "\t"
: "\t\t";
System.err.println
(tokenname
+ pad + (int)source.charAt(i)
+ "\t'" + ScriptRuntime.escapeString
(source.substring(i, i+1))
+ "'");
}
System.err.println();
}
StringBuffer result = new StringBuffer();
int i = 0;
if (source.length() > 0) {
/* special-case FUNCTION as the first token; if it is,
* (and it's not followed by a NAME or LP) then we're
* decompiling a function (and not the toplevel script.)
* FUNCTION appearing elsewhere is an escape that means we'll
* need to call toString of the given function (object).
* If not at the top level, don't add an initial indent;
* let the caller do it, so functions as expressions look
* reasonable. */
if (toplevel) {
// add an initial newline to exactly match js.
if (!justbody)
result.append('\n');
for (int j = 0; j < indent; j++)
result.append(' ');
}
if (source.charAt(0) == TokenStream.FUNCTION
// make sure it's not a script that begins with a
// reference to a function definition.
&& source.length() > 1
&& (source.charAt(1) == TokenStream.NAME
|| source.charAt(1) == TokenStream.LP))
{
if (!justbody) {
result.append("function ");
/* version < 1.2 Function constructor behavior - if
* there's no function name in the source info, and
* the names[0] entry is the empty string, then it must
* have been created by the Function constructor;
* print 'anonymous' as the function name if the
* version (under which the function was compiled) is
* less than 1.2... or if it's greater than 1.2, because
* we need to be closer to ECMA. (ToSource, please?)
*/
if (nextIs(i, TokenStream.LP)
&& this.version != Context.VERSION_1_2
&& this.names != null
&& this.names[0].length() == 0)
result.append("anonymous");
i++;
} else {
/* Skip past the entire function header to the next EOL.
* Depends on how NAMEs are encoded.
*/
while (i < source.length()
&& (source.charAt(i) != TokenStream.EOL
// the length char of a NAME sequence
// can look like an EOL.
|| (i > 0
&& source.charAt(i-1) == TokenStream.NAME)))
{
i++;
}
// Skip past the EOL, too.
i++;
}
}
}
while (i < source.length()) {
int stop;
switch(source.charAt(i)) {
case TokenStream.NAME:
case TokenStream.OBJECT: // re-wrapped in '/'s in parser...
/* NAMEs are encoded as NAME, (char) length, string...
* Note that lookahead for detecting labels depends on
* this encoding; change there if this changes.
* Also change function-header skipping code above,
* used when decompling under decompileFunctionBody.
*/
i++;
stop = i + (int)source.charAt(i);
result.append(source.substring(i + 1, stop + 1));
i = stop;
break;
case TokenStream.NUMBER:
i++;
long lbits = 0;
switch(source.charAt(i)) {
case 'S':
i++;
result.append((int)source.charAt(i));
break;
case 'J':
i++;
lbits |= (long)source.charAt(i++) << 48;
lbits |= (long)source.charAt(i++) << 32;
lbits |= (long)source.charAt(i++) << 16;
lbits |= (long)source.charAt(i);
result.append(lbits);
break;
case 'D':
i++;
lbits |= (long)source.charAt(i++) << 48;
lbits |= (long)source.charAt(i++) << 32;
lbits |= (long)source.charAt(i++) << 16;
lbits |= (long)source.charAt(i);
double dval = Double.longBitsToDouble(lbits);
result.append(ScriptRuntime.numberToString(dval));
break;
}
break;
case TokenStream.STRING:
i++;
stop = i + (int)source.charAt(i);
result.append('"');
result.append(ScriptRuntime.escapeString
(source.substring(i + 1, stop + 1)));
result.append('"');
i = stop;
break;
case TokenStream.PRIMARY:
i++;
switch(source.charAt(i)) {
case TokenStream.TRUE:
result.append("true");
break;
case TokenStream.FALSE:
result.append("false");
break;
case TokenStream.NULL:
result.append("null");
break;
case TokenStream.THIS:
result.append("this");
break;
case TokenStream.TYPEOF:
result.append("typeof");
break;
case TokenStream.VOID:
result.append("void");
break;
case TokenStream.UNDEFINED:
result.append("undefined");
break;
}
break;
case TokenStream.FUNCTION: {
/* decompile a FUNCTION token as an escape; call
* toString on the nth enclosed nested function,
* where n is given by the byte that follows.
*/
i++;
int functionNumber = source.charAt(i);
if (nestedFunctions == null
|| functionNumber > nestedFunctions.length)
{
String message;
if (names != null && names.length > 0
&& names[0].length() > 0)
{
Object[] errArgs = { new Integer((int)source.charAt(i)),
names[0] };
message = Context.getMessage
("msg.no.function.ref.found.in", errArgs);
} else {
Object[] errArgs
= { new Integer((int)source.charAt(i)) };
message = Context.getMessage
("msg.no.function.ref.found", errArgs);
}
throw Context.reportRuntimeError(message);
}
result.append(nestedFunctions[functionNumber].decompile(indent,
false,
false));
break;
}
case TokenStream.COMMA:
result.append(", ");
break;
case TokenStream.LC:
if (nextIs(i, TokenStream.EOL))
indent += OFFSET;
result.append("{");
break;
case TokenStream.RC:
/* don't print the closing RC if it closes the
* toplevel function and we're called from
* decompileFunctionBody.
*/
if (justbody && toplevel && i + 1 == source.length())
break;
if (nextIs(i, TokenStream.EOL))
indent -= OFFSET;
if (nextIs(i, TokenStream.WHILE)
|| nextIs(i, TokenStream.ELSE)) {
indent -= OFFSET;
result.append("} ");
}
else
result.append('}');
break;
case TokenStream.LP:
result.append('(');
break;
case TokenStream.RP:
if (nextIs(i, TokenStream.LC))
result.append(") ");
else
result.append(')');
break;
case TokenStream.LB:
result.append('[');
break;
case TokenStream.RB:
result.append(']');
break;
case TokenStream.EOL:
result.append('\n');
/* add indent if any tokens remain,
* less setback if next token is
* a label, case or default.
*/
if (i + 1 < source.length()) {
int less = 0;
if (nextIs(i, TokenStream.CASE)
|| nextIs(i, TokenStream.DEFAULT))
less = SETBACK;
else if (nextIs(i, TokenStream.RC))
less = OFFSET;
/* elaborate check against label... skip past a
* following inlined NAME and look for a COLON.
* Depends on how NAME is encoded.
*/
else if (nextIs(i, TokenStream.NAME)) {
int skip = source.charAt(i + 2);
if (source.charAt(i + skip + 3) == TokenStream.COLON)
less = OFFSET;
}
for (; less < indent; less++)
result.append(' ');
}
break;
case TokenStream.DOT:
result.append('.');
break;
case TokenStream.NEW:
result.append("new ");
break;
case TokenStream.DELPROP:
result.append("delete ");
break;
case TokenStream.IF:
result.append("if ");
break;
case TokenStream.ELSE:
result.append("else ");
break;
case TokenStream.FOR:
result.append("for ");
break;
case TokenStream.IN:
result.append(" in ");
break;
case TokenStream.WITH:
result.append("with ");
break;
case TokenStream.WHILE:
result.append("while ");
break;
case TokenStream.DO:
result.append("do ");
break;
case TokenStream.TRY:
result.append("try ");
break;
case TokenStream.CATCH:
result.append("catch ");
break;
case TokenStream.FINALLY:
result.append("finally ");
break;
case TokenStream.THROW:
result.append("throw ");
break;
case TokenStream.SWITCH:
result.append("switch ");
break;
case TokenStream.BREAK:
if (nextIs(i, TokenStream.NAME))
result.append("break ");
else
result.append("break");
break;
case TokenStream.CONTINUE:
if (nextIs(i, TokenStream.NAME))
result.append("continue ");
else
result.append("continue");
break;
case TokenStream.CASE:
result.append("case ");
break;
case TokenStream.DEFAULT:
result.append("default");
break;
case TokenStream.RETURN:
if (nextIs(i, TokenStream.SEMI))
result.append("return");
else
result.append("return ");
break;
case TokenStream.VAR:
result.append("var ");
break;
case TokenStream.SEMI:
if (nextIs(i, TokenStream.EOL))
// statement termination
result.append(";");
else
// separators in FOR
result.append("; ");
break;
case TokenStream.ASSIGN:
i++;
switch(source.charAt(i)) {
case TokenStream.NOP:
result.append(" = ");
break;
case TokenStream.ADD:
result.append(" += ");
break;
case TokenStream.SUB:
result.append(" -= ");
break;
case TokenStream.MUL:
result.append(" *= ");
break;
case TokenStream.DIV:
result.append(" /= ");
break;
case TokenStream.MOD:
result.append(" %= ");
break;
case TokenStream.BITOR:
result.append(" |= ");
break;
case TokenStream.BITXOR:
result.append(" ^= ");
break;
case TokenStream.BITAND:
result.append(" &= ");
break;
case TokenStream.LSH:
result.append(" <<= ");
break;
case TokenStream.RSH:
result.append(" >>= ");
break;
case TokenStream.URSH:
result.append(" >>>= ");
break;
}
break;
case TokenStream.HOOK:
result.append(" ? ");
break;
case TokenStream.OBJLIT:
// pun OBJLIT to mean colon in objlit property initialization.
// this needs to be distinct from COLON in the general case
// to distinguish from the colon in a ternary... which needs
// different spacing.
result.append(':');
break;
case TokenStream.COLON:
if (nextIs(i, TokenStream.EOL))
// it's the end of a label
result.append(":");
else
// it's the middle part of a ternary
result.append(" : ");
break;
case TokenStream.OR:
result.append(" || ");
break;
case TokenStream.AND:
result.append(" && ");
break;
case TokenStream.BITOR:
result.append(" | ");
break;
case TokenStream.BITXOR:
result.append(" ^ ");
break;
case TokenStream.BITAND:
result.append(" & ");
break;
case TokenStream.EQOP:
i++;
switch(source.charAt(i)) {
case TokenStream.SHEQ:
/*
* Emulate the C engine; if we're under version
* 1.2, then the == operator behaves like the ===
* operator (and the source is generated by
* decompiling a === opcode), so print the ===
* operator as ==.
*/
result.append(this.version == Context.VERSION_1_2 ? " == "
: " === ");
break;
case TokenStream.SHNE:
result.append(this.version == Context.VERSION_1_2 ? " != "
: " !== ");
break;
case TokenStream.EQ:
result.append(" == ");
break;
case TokenStream.NE:
result.append(" != ");
break;
}
break;
case TokenStream.RELOP:
i++;
switch(source.charAt(i)) {
case TokenStream.LE:
result.append(" <= ");
break;
case TokenStream.LT:
result.append(" < ");
break;
case TokenStream.GE:
result.append(" >= ");
break;
case TokenStream.GT:
result.append(" > ");
break;
case TokenStream.INSTANCEOF:
result.append(" instanceof ");
break;
}
break;
case TokenStream.SHOP:
i++;
switch(source.charAt(i)) {
case TokenStream.LSH:
result.append(" << ");
break;
case TokenStream.RSH:
result.append(" >> ");
break;
case TokenStream.URSH:
result.append(" >>> ");
break;
}
break;
case TokenStream.UNARYOP:
i++;
switch(source.charAt(i)) {
case TokenStream.TYPEOF:
result.append("typeof ");
break;
case TokenStream.VOID:
result.append("void ");
break;
case TokenStream.NOT:
result.append('!');
break;
case TokenStream.BITNOT:
result.append('~');
break;
case TokenStream.ADD:
result.append('+');
break;
case TokenStream.SUB:
result.append('-');
break;
}
break;
case TokenStream.INC:
result.append("++");
break;
case TokenStream.DEC:
result.append("--");
break;
case TokenStream.ADD:
result.append(" + ");
break;
case TokenStream.SUB:
result.append(" - ");
break;
case TokenStream.MUL:
result.append(" * ");
break;
case TokenStream.DIV:
result.append(" / ");
break;
case TokenStream.MOD:
result.append(" % ");
break;
default:
// If we don't know how to decompile it, raise an exception.
throw new RuntimeException("Unknown token " +
source.charAt(i));
}
i++;
}
// add that trailing newline if it's an outermost function.
if (toplevel && !justbody)
result.append('\n');
return result.toString();
}
public static Object js_toString(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
Object val = thisObj.getDefaultValue(ScriptRuntime.FunctionClass);
if (!(val instanceof NativeFunction)) {
Object[] errArgs = { "toString" };
String message = Context.getMessage("msg.incompat.call", errArgs);
throw Context.reportRuntimeError(message);
}
int indent = 0;
if (args.length > 0)
indent = (int)ScriptRuntime.toNumber(args[0]);
return ((NativeFunction) val).decompile(indent, true, false);
}
public static Scriptable js_Function(Context cx, Object[] args,
Function ctorObj, boolean inNewExpr)
{
int arglen = args.length;
StringBuffer funArgs = new StringBuffer();
/* Collect the arguments into a string. */
int i;
for (i = 0; i < arglen - 1; i++) {
if (i > 0)
funArgs.append(",");
funArgs.append(ScriptRuntime.toString(args[i]));
}
String funBody = arglen == 0 ? "" : ScriptRuntime.toString(args[i]);
String source = "function (" + funArgs.toString() + ") {" +
funBody + "}";
int[] linep = { 0 };
String filename = Context.getSourcePositionFromStack(linep);
if (filename == null) {
filename = "<eval'ed string>";
linep[0] = 1;
}
Object securityDomain = cx.getSecurityDomainForStackDepth(4);
Scriptable global = ScriptableObject.getTopLevelScope(ctorObj);
// Compile the function with opt level of -1 to force interpreter
// mode.
int oldOptLevel = cx.getOptimizationLevel();
cx.setOptimizationLevel(-1);
NativeFunction fn = (NativeFunction) cx.compileFunction(
global, source,
filename, linep[0],
securityDomain);
cx.setOptimizationLevel(oldOptLevel);
if (fn.names == null)
fn.names = new String[1];
fn.names[0] = "";
fn.setPrototype(getFunctionPrototype(global));
fn.setParentScope(global);
return fn;
}
/**
* Function.prototype.apply
*
* A proposed ECMA extension for round 2.
*/
public static Object js_apply(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws JavaScriptException
{
if (args.length != 2)
return js_call(cx, thisObj, args, funObj);
Object val = thisObj.getDefaultValue(ScriptRuntime.FunctionClass);
Scriptable newThis = args[0] == null
? null
: ScriptRuntime.toObject(funObj, args[0]);
Object[] newArgs = cx.getElements((Scriptable) args[1]);
return ScriptRuntime.call(cx, val, newThis, newArgs);
}
/**
* Function.prototype.call
*
* A proposed ECMA extension for round 2.
*/
public static Object js_call(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws JavaScriptException
{
Object val = thisObj.getDefaultValue(ScriptRuntime.FunctionClass);
if (args.length == 0) {
Scriptable s = ScriptRuntime.toObject(funObj, val);
return ScriptRuntime.call(cx, val, s.getParentScope(),
ScriptRuntime.emptyArgs);
} else {
Scriptable newThis = args[0] == null
? null
: ScriptRuntime.toObject(funObj, args[0]);
Object[] newArgs = new Object[args.length - 1];
System.arraycopy(args, 1, newArgs, 0, newArgs.length);
return ScriptRuntime.call(cx, val, newThis, newArgs);
}
}
public int js_getLength() {
Context cx = Context.getContext();
if (cx.getLanguageVersion() != Context.VERSION_1_2)
return argCount;
NativeCall activation = getActivation(cx);
if (activation == null)
return argCount;
return activation.getOriginalArguments().length;
}
public int js_getArity() {
return argCount;
}
public String js_getName() {
if (names != null && names[0].length() > 0)
return names[0];
Context cx = Context.getCurrentContext();
if (cx != null && cx.getLanguageVersion() == Context.VERSION_1_2) {
return "";
}
return "anonymous";
}
private NativeCall getActivation(Context cx) {
NativeCall activation = cx.currentActivation;
while (activation != null) {
if (activation.getFunctionObject() == this)
return activation;
activation = activation.caller;
}
return null;
}
/**
* The "names" array has the following information:
* names[0]: The name of the function
* names[1] through names[argCount]: the names of the parameters
* names[argCount+1] through names[names.length-1]: the names of the
* variables declared
* in var statements
*/
protected String[] names;
protected short argCount;
protected short version;
/**
* An encoded representation of the function source, for
* decompiling. Needs to be visible (only) to generated
* subclasses of NativeFunction.
*/
protected String source;
/**
* An array of NativeFunction values for each nested function.
* Used internally, and also for decompiling nested functions.
*/
public NativeFunction[] nestedFunctions;
// For all generated subclass objects debug_level is set to 0 or higher.
// So, if debug_level remains -1 in some object, then that object is
// known to have not been generated.
public int debug_level = -1;
public String debug_srcName;
}

Просмотреть файл

@ -0,0 +1,402 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.io.StringReader;
import java.io.IOException;
/**
* This class implements the global native object (function and value properties only).
* See ECMA 15.1.[12].
*
* @author Mike Shaver
*/
public class NativeGlobal {
public static void init(Scriptable scope)
throws PropertyException
{
String names[] = { "eval",
"parseInt",
"parseFloat",
"escape",
"unescape",
"isNaN",
"isFinite"
};
// We can downcast here because Context.initStandardObjects
// takes a ScriptableObject scope.
ScriptableObject global = (ScriptableObject) scope;
global.defineFunctionProperties(names, NativeGlobal.class,
ScriptableObject.DONTENUM);
global.defineProperty("NaN", ScriptRuntime.NaNobj,
ScriptableObject.DONTENUM);
global.defineProperty("Infinity", new Double(Double.POSITIVE_INFINITY),
ScriptableObject.DONTENUM);
global.defineProperty("undefined", Undefined.instance,
ScriptableObject.DONTENUM);
}
/**
* The global method parseInt, as per ECMA-262 15.1.2.2.
*/
public static Object parseInt(String s, int radix) {
int len = s.length();
if (len == 0)
return ScriptRuntime.NaNobj;
boolean negative = false;
int start = 0;
char c;
do {
c = s.charAt(start);
if (!Character.isWhitespace(c))
break;
start++;
} while (start < len);
if (c == '+' || (negative = (c == '-')))
start++;
final int NO_RADIX = -1;
if (radix == 0) {
radix = NO_RADIX;
} else if (radix < 2 || radix > 36) {
return ScriptRuntime.NaNobj;
} else if (radix == 16 && len - start > 1 &&
s.charAt(start) == '0')
{
c = s.charAt(start+1);
if (c == 'x' || c == 'X')
start += 2;
}
if (radix == NO_RADIX) {
radix = 10;
if (len - start > 1 && s.charAt(start) == '0') {
c = s.charAt(start+1);
if (c == 'x' || c == 'X') {
radix = 16;
start += 2;
} else if (c != '.') {
radix = 8;
start++;
}
}
}
double d = ScriptRuntime.stringToNumber(s, start, radix);
return new Double(negative ? -d : d);
}
/**
* The global method parseFloat, as per ECMA-262 15.1.2.3.
*
* @param cx unused
* @param thisObj unused
* @param args the arguments to parseFloat, ignoring args[>=1]
* @param funObj unused
*/
public static Object parseFloat(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
if (args.length < 1)
return ScriptRuntime.NaNobj;
String s = ScriptRuntime.toString(args[0]);
int len = s.length();
if (len == 0)
return ScriptRuntime.NaNobj;
int i;
char c;
// Scan forward to the first digit or .
for (i=0; TokenStream.isJSSpace(c = s.charAt(i)) && i+1 < len; i++)
/* empty */
;
int start = i;
if (c == '+' || c == '-')
c = s.charAt(++i);
if (c == 'I') {
// check for "Infinity"
double d;
if (i+8 <= len && s.substring(i, i+8).equals("Infinity"))
d = s.charAt(start) == '-' ? Double.NEGATIVE_INFINITY
: Double.POSITIVE_INFINITY;
else
return ScriptRuntime.NaNobj;
return new Double(d);
}
// Find the end of the legal bit
int decimal = -1;
int exponent = -1;
for (; i < len; i++) {
switch (s.charAt(i)) {
case '.':
if (decimal != -1) // Only allow a single decimal point.
break;
decimal = i;
continue;
case 'e':
case 'E':
if (exponent != -1)
break;
exponent = i;
continue;
case '+':
case '-':
// Only allow '+' or '-' after 'e' or 'E'
if (exponent != i-1)
break;
continue;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
continue;
default:
break;
}
break;
}
s = s.substring(start, i);
try {
return Double.valueOf(s);
}
catch (NumberFormatException ex) {
return ScriptRuntime.NaNobj;
}
}
/**
* The global method escape, as per ECMA-262 15.1.2.4.
* Includes code for the 'mask' argument supported by the C escape
* method, which used to be part of the browser imbedding. Blame
* for the strange constant names should be directed there.
*/
private static int
URL_XALPHAS = 1,
URL_XPALPHAS = 2,
URL_PATH = 4;
public static Object escape(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
if (args.length < 1)
args = ScriptRuntime.padArguments(args, 1);
String s = ScriptRuntime.toString(args[0]);
int mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
if (args.length > 1) { // the 'mask' argument. Non-ECMA.
double d = ScriptRuntime.toNumber(args[1]);
if (d != d || ((mask = (int) d) != d) ||
0 != (mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH)))
{
String message = Context.getMessage
("msg.bad.esc.mask", null);
cx.reportError(message);
// do the ecma thing, in case reportError returns.
mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
}
}
StringBuffer R = new StringBuffer();
for (int k = 0; k < s.length(); k++) {
char c = s.charAt(k);
if (mask != 0 &&
((c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
c == '@' || c == '*' || c == '_' ||
c == '-' || c == '.' ||
((c == '/' || c == '+') && mask > 3)))
R.append(c);
else if (c < 256) {
if (c == ' ' && mask == URL_XPALPHAS) {
R.append('+');
} else {
R.append('%');
R.append(digits[c >> 4]);
R.append(digits[c & 0xF]);
}
} else {
R.append('%');
R.append('u');
R.append(digits[c >> 12]);
R.append(digits[(c & 0xF00) >> 8]);
R.append(digits[(c & 0xF0) >> 4]);
R.append(digits[c & 0xF]);
}
}
return R.toString();
}
/**
* The global unescape method, as per ECMA-262 15.1.2.5.
*/
public static Object unescape(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
if (args.length < 1)
args = ScriptRuntime.padArguments(args, 1);
String s = ScriptRuntime.toString(args[0]);
StringBuffer R = new StringBuffer();
stringIter: for (int k = 0; k < s.length(); k++) {
char c = s.charAt(k);
if (c != '%' || k == s.length() -1) {
R.append(c);
continue;
}
String hex;
int end, start;
if (s.charAt(k+1) == 'u') {
start = k+2;
end = k+6;
} else {
start = k+1;
end = k+3;
}
if (end > s.length()) {
R.append('%');
continue;
}
hex = s.substring(start, end);
for (int i = 0; i < hex.length(); i++)
if (!TokenStream.isXDigit(hex.charAt(i))) {
R.append('%');
continue stringIter;
}
k = end - 1;
R.append((new Character((char) Integer.valueOf(hex, 16).intValue())));
}
return R.toString();
}
/**
* The global method isNaN, as per ECMA-262 15.1.2.6.
*/
public static Object isNaN(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
if (args.length < 1)
return Boolean.TRUE;
double d = ScriptRuntime.toNumber(args[0]);
return (d != d) ? Boolean.TRUE : Boolean.FALSE;
}
public static Object isFinite(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
if (args.length < 1)
return Boolean.FALSE;
double d = ScriptRuntime.toNumber(args[0]);
return (d != d || d == Double.POSITIVE_INFINITY ||
d == Double.NEGATIVE_INFINITY)
? Boolean.FALSE
: Boolean.TRUE;
}
public static Object eval(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws JavaScriptException
{
Object[] msgArgs = { "eval" };
throw Context.reportRuntimeError(
Context.getMessage("msg.cant.call.indirect", msgArgs));
}
/**
* The eval function property of the global object.
*
* See ECMA 15.1.2.1
*/
public static Object evalSpecial(Context cx, Scriptable scope,
Object thisArg, Object[] args,
String filename, int lineNumber)
throws JavaScriptException
{
if (args.length < 1)
return Undefined.instance;
Object x = args[0];
if (!(x instanceof String)) {
String message = Context.getMessage("msg.eval.nonstring", null);
Context.reportWarning(message);
return x;
}
int[] linep = { lineNumber };
if (filename == null) {
filename = Context.getSourcePositionFromStack(linep);
if (filename == null) {
filename = "<eval'ed string>";
linep[0] = 1;
}
}
try {
StringReader in = new StringReader((String) x);
Object securityDomain = cx.getSecurityDomainForStackDepth(3);
// Compile the reader with opt level of -1 to force interpreter
// mode.
int oldOptLevel = cx.getOptimizationLevel();
cx.setOptimizationLevel(-1);
Script script = cx.compileReader(null, in, filename, linep[0],
securityDomain);
cx.setOptimizationLevel(oldOptLevel);
// if the compile fails, an error has been reported by the
// compiler, but we need to stop execution to avoid
// infinite looping on while(true) { eval('foo bar') } -
// so we throw an EvaluatorException.
if (script == null) {
String message = Context.getMessage("msg.syntax", null);
throw new EvaluatorException(message);
}
InterpretedScript is = (InterpretedScript) script;
Object result = is.call(cx, scope, (Scriptable) thisArg, null);
return result;
}
catch (IOException ioe) {
// should never happen since we just made the Reader from a String
throw new RuntimeException("unexpected io exception");
}
}
}

Просмотреть файл

@ -0,0 +1,121 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.lang.reflect.Array;
/**
* This class reflects Java arrays into the JavaScript environment.
*
* @author Mike Shaver
* @see NativeJavaClass
* @see NativeJavaObject
* @see NativeJavaPackage
*/
public class NativeJavaArray extends NativeJavaObject {
public String getClassName() {
return "JavaArray";
}
public static NativeJavaArray wrap(Scriptable scope, Object array) {
return new NativeJavaArray(scope, array);
}
public Object unwrap() {
return array;
}
public NativeJavaArray(Scriptable scope, Object array) {
super(scope, null, ScriptRuntime.ObjectClass);
Class cl = array.getClass();
if (!cl.isArray()) {
throw new RuntimeException("Array expected");
}
this.array = array;
this.length = Array.getLength(array);
this.cls = cl.getComponentType();
}
public boolean has(String id, Scriptable start) {
return id.equals("length") || super.has(id, start);
}
public boolean has(int index, Scriptable start) {
return 0 <= index && index < length;
}
public Object get(String id, Scriptable start) {
if (id.equals("length"))
return new Integer(length);
return super.get(id, start);
}
public Object get(int index, Scriptable start) {
if (0 <= index && index < length)
return NativeJavaObject.wrap(this, Array.get(array, index), cls);
return Undefined.instance;
}
public void put(String id, Scriptable start, Object value) {
// Ignore assignments to "length"--it's readonly.
if (!id.equals("length"))
super.put(id, start, value);
}
public void put(int index, Scriptable start, Object value) {
if (0 <= index && index < length) {
if (value instanceof Wrapper)
value = ((Wrapper)value).unwrap();
Array.set(array, index, NativeJavaObject.coerceType(cls, value));
return;
}
super.put(index, start, value);
}
public Object getDefaultValue(Class hint) {
if (hint == null || hint == ScriptRuntime.StringClass)
return array.toString();
if (hint == ScriptRuntime.BooleanClass)
return Boolean.TRUE;
if (hint == ScriptRuntime.NumberClass)
return ScriptRuntime.NaNobj;
return this;
}
public Object[] getIds() {
Object[] result = new Object[length];
int i = length;
while (--i >= 0)
result[i] = new Integer(i);
return result;
}
public boolean hasInstance(Scriptable value) {
if (!(value instanceof NativeJavaObject))
return false;
Object instance = ((NativeJavaObject)value).unwrap();
return cls.isInstance(instance);
}
Object array;
int length;
Class cls;
}

Просмотреть файл

@ -0,0 +1,243 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.lang.reflect.*;
import java.util.Hashtable;
/**
* This class reflects Java classes into the JavaScript environment, mainly
* for constructors and static members. We lazily reflect properties,
* and currently do not guarantee that a single j.l.Class is only
* reflected once into the JS environment, although we should.
* The only known case where multiple reflections
* are possible occurs when a j.l.Class is wrapped as part of a
* method return or property access, rather than by walking the
* Packages/java tree.
*
* @author Mike Shaver
* @see NativeJavaArray
* @see NativeJavaObject
* @see NativeJavaPackage
*/
public class NativeJavaClass extends NativeJavaObject implements Function {
public NativeJavaClass(Scriptable scope, Class cl) {
super(cl, JavaMembers.lookupClass(scope, cl, cl));
fieldAndMethods = members.getFieldAndMethodsObjects(javaObject, false);
}
public String getClassName() {
return "JavaClass";
}
public boolean has(String name, Scriptable start) {
return members.has(name, true);
}
public Object get(String name, Scriptable start) {
// When used as a constructor, ScriptRuntime.newObject() asks
// for our prototype to create an object of the correct type.
// We don't really care what the object is, since we're returning
// one constructed out of whole cloth, so we return null.
if (name.equals("prototype"))
return null;
Object result = Scriptable.NOT_FOUND;
if (fieldAndMethods != null) {
result = fieldAndMethods.get(name);
if (result != null)
return result;
}
if (members.has(name, true)) {
result = members.get(this, name, javaObject, true);
} else {
// experimental: look for nested classes by appending $name to current class' name.
try {
String nestedName = getClassObject().getName() + '$' + name;
Class nestedClass = Class.forName(nestedName);
Scriptable nestedValue = wrap(ScriptableObject.getTopLevelScope(this), nestedClass);
nestedValue.setParentScope(this);
result = nestedValue;
} catch (ClassNotFoundException ex) {
throw members.reportMemberNotFound(name);
}
}
return result;
}
public void put(String name, Scriptable start, Object value) {
members.put(name, javaObject, value, true);
}
public Object[] getIds() {
return members.getIds(true);
}
public Class getClassObject() {
return (Class) super.unwrap();
}
// XXX ??
public static NativeJavaClass wrap(Scriptable scope, Class cls) {
return new NativeJavaClass(scope, cls);
}
public Object getDefaultValue(Class hint) {
if (hint == null || hint == ScriptRuntime.StringClass)
return this.toString();
if (hint == ScriptRuntime.BooleanClass)
return Boolean.TRUE;
if (hint == ScriptRuntime.NumberClass)
return ScriptRuntime.NaNobj;
return this;
}
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException
{
return construct(cx, scope, args);
}
public Scriptable construct(Context cx, Scriptable scope, Object[] args)
throws JavaScriptException
{
Class classObject = getClassObject();
Scriptable topLevel = ScriptableObject.getTopLevelScope(this);
int modifiers = classObject.getModifiers();
if (! (Modifier.isInterface(modifiers) ||
Modifier.isAbstract(modifiers)))
{
for (int i = 0; i < args.length; i++) {
if (args[i] instanceof Wrapper)
args[i] = ((Wrapper)args[i]).unwrap();
}
Constructor[] ctors = members.getConstructors();
Member member = NativeJavaMethod.findFunction(ctors, args);
Constructor ctor = (Constructor) member;
if (ctor == null) {
String sig = NativeJavaMethod.signature(args);
Object errArgs[] = { getClassObject().getName(), sig };
throw Context.reportRuntimeError(Context.getMessage(
"msg.no.java.ctor", errArgs));
}
// Found the constructor, so try invoking it.
Class[] paramTypes = ctor.getParameterTypes();
for (int i = 0; i < args.length; i++) {
args[i] = NativeJavaObject.coerceType(paramTypes[i], args[i]);
}
try {
/* we need to force this to be wrapped, because construct _has_
* to return a scriptable */
return (Scriptable) NativeJavaObject.wrap(
topLevel, ctor.newInstance(args),
getClassObject());
} catch (InstantiationException instEx) {
Object[] errArgs = { instEx.getMessage(),
getClassObject().getName() };
throw Context.reportRuntimeError(Context.getMessage
("msg.cant.instantiate",
errArgs));
} catch (IllegalArgumentException argEx) {
String signature = NativeJavaMethod.signature(args);
String ctorString = ctor.toString();
Object[] errArgs = { argEx.getMessage(),ctorString,signature };
throw Context.reportRuntimeError(Context.getMessage
("msg.bad.ctor.sig",
errArgs));
} catch (InvocationTargetException e) {
throw JavaScriptException.wrapException(scope, e);
} catch (IllegalAccessException accessEx) {
Object[] errArgs = { accessEx.getMessage() };
throw Context.reportRuntimeError(Context.getMessage
("msg.java.internal.private", errArgs));
}
} else {
String msg = "";
try {
// trying to construct an interface; use JavaAdapter to
// construct a new class on the fly that implements this
// interface.
Object v = topLevel.get("JavaAdapter", topLevel);
if (v != NOT_FOUND) {
Function f = (Function) v;
Object[] adapterArgs = { this, args[0] };
return (Scriptable) f.construct(cx, topLevel,
adapterArgs);
}
} catch (Exception ex) {
// fall through to error
msg = ex.getMessage();
}
Object[] errArgs = { msg, getClassObject().getName() };
throw Context.reportRuntimeError(Context.getMessage
("msg.cant.instantiate",
errArgs));
}
}
public String toString() {
return "[JavaClass " + getClassObject().getName() + "]";
}
/**
* Determines if prototype is a wrapped Java object and performs
* a Java "instanceof"
*/
public boolean hasInstance(Scriptable value) {
if (value instanceof NativeJavaObject) {
Object instance = ((NativeJavaObject)value).unwrap();
return getClassObject().isInstance(instance);
}
// value wasn't something we understand
return false;
}
public Scriptable getParentScope() {
return parent;
}
public void setParentScope(Scriptable scope) {
// beard:
// need at least the top-most scope, so JavaMembers.reflectMethod()
// will work. this fixes a bug where a static field of a class would get
// reflected by JavaMembers.reflect() in the scope of a NativeJavaClass,
// and calls to ScriptableObject.getFunctionPrototype() would return
// null because there was no top-level scope with "Function" defined.
// question: should the package hierarchy form the scope chain or is top-level sufficient?
parent = scope;
}
private Hashtable fieldAndMethods;
// beard: need a scope for finding top-level prototypes.
private Scriptable parent;
}

Просмотреть файл

@ -0,0 +1,260 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.lang.reflect.*;
/**
* This class reflects Java methods into the JavaScript environment. It
* handles overloading of methods, and method/field name conflicts.
* All NativeJavaMethods behave as JSRef `bound' methods, in that they
* always operate on the object underlying the original NativeJavaObject
* parent regardless of any reparenting that may occur.
*
* @author Mike Shaver
* @see NativeJavaArray
* @see NativeJavaPackage
* @see NativeJavaClass
*/
public class NativeJavaMethod extends NativeFunction implements Function {
public NativeJavaMethod() {
names = new String[1];
}
public NativeJavaMethod(Method[] methods) {
this.methods = methods;
names = new String[1];
names[0] = methods[0].getName();
}
public void add(Method method) {
if (names[0] == null) {
names[0] = method.getName();
} else if (!names[0].equals(method.getName())) {
throw new RuntimeException("internal method name mismatch");
}
// XXX a more intelligent growth algorithm would be nice
int len = methods == null ? 0 : methods.length;
Method[] newMeths = new Method[len + 1];
for (int i = 0; i < len; i++)
newMeths[i] = methods[i];
newMeths[len] = method;
methods = newMeths;
}
static String signature(Class type) {
if (type == null)
return "null";
if (type == ScriptRuntime.BooleanClass)
return "boolean";
if (type == ScriptRuntime.ByteClass)
return "byte";
if (type == ScriptRuntime.ShortClass)
return "short";
if (type == ScriptRuntime.IntegerClass)
return "int";
if (type == ScriptRuntime.LongClass)
return "long";
if (type == ScriptRuntime.FloatClass)
return "float";
if (type == ScriptRuntime.DoubleClass)
return "double";
if (type == ScriptRuntime.StringClass)
return "string";
if (ScriptRuntime.ScriptableClass.isAssignableFrom(type)) {
if (ScriptRuntime.FunctionClass.isAssignableFrom(type))
return "function";
if (type == ScriptRuntime.UndefinedClass)
return "undefined";
return "object";
}
return type.getName();
}
static String signature(Object[] values) {
StringBuffer sig = new StringBuffer();
for (int i = 0; i < values.length; i++) {
if (i != 0)
sig.append(',');
sig.append(values[i] == null ? "null"
: signature(values[i].getClass()));
}
return sig.toString();
}
static String signature(Class[] types) {
StringBuffer sig = new StringBuffer();
for (int i = 0; i < types.length; i++) {
if (i != 0)
sig.append(',');
sig.append(signature(types[i]));
}
return sig.toString();
}
static String signature(Member member) {
Class paramTypes[] = member instanceof Method
? ((Method) member).getParameterTypes()
: ((Constructor) member).getParameterTypes();
return member.getName() + "(" + signature(paramTypes) + ")";
}
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException
{
// Find a method that matches the types given.
if (methods.length == 0) {
throw new RuntimeException("No methods defined for call");
}
// Eliminate useless args[0] and unwrap if required
for (int i = 0; i < args.length; i++)
if (args[i] instanceof Wrapper)
args[i] = ((Wrapper)args[i]).unwrap();
Method meth = (Method) findFunction(methods, args);
if (meth == null) {
Class c = methods[0].getDeclaringClass();
String sig = c.getName() + "." + names[0] + "(" +
signature(args) + ")";
Object errArgs[] = { sig };
throw Context.reportRuntimeError(
Context.getMessage("msg.java.no_such_method", errArgs));
}
// OPT: already retrieved in findFunction, so we should inline that
// OPT: or pass it back somehow
Class paramTypes[] = meth.getParameterTypes();
// First, we kill the lawyers. Er, marshall the args.
for (int i = 0; i < args.length; i++) {
args[i] = NativeJavaObject.coerceType(paramTypes[i], args[i]);
}
Object javaObject;
try {
javaObject = ((NativeJavaObject) thisObj).unwrap();
}
catch (ClassCastException e) {
if (Modifier.isStatic(meth.getModifiers())) {
javaObject = null; // don't need it anyway
} else {
Object errArgs[] = { names[0] };
throw Context.reportRuntimeError(
Context.getMessage("msg.nonjava.method", errArgs));
}
}
try {
Object retval = meth.invoke(javaObject, args);
Class staticType = meth.getReturnType();
Object wrapped = NativeJavaObject.wrap(scope, retval, staticType);
// XXX set prototype && parent
if (wrapped == Undefined.instance)
return wrapped;
if (wrapped == null && staticType == Void.TYPE)
return Undefined.instance;
if (retval != wrapped && wrapped instanceof Scriptable) {
Scriptable s = (Scriptable)wrapped;
if (s.getPrototype() == null)
s.setPrototype(parent.getPrototype());
if (s.getParentScope() == null)
s.setParentScope(parent.getParentScope());
}
return wrapped;
} catch (IllegalAccessException accessEx) {
throw Context.reportRuntimeError(accessEx.getMessage());
} catch (InvocationTargetException e) {
throw JavaScriptException.wrapException(scope, e);
}
}
public Object getDefaultValue(Class hint) {
return this;
}
/**
* Find the correct function to call given the set of methods
* or constructors and the arguments.
* If no function can be found to call, return null.
*/
static Member findFunction(Member[] methodsOrCtors, Object[] args) {
if (methodsOrCtors.length == 0)
return null;
boolean hasMethods = methodsOrCtors[0] instanceof Method;
if (Context.useJSObject &&
NativeJavaObject.jsObjectClass != null)
{
try {
for (int i = 0; i < args.length; i++) {
if (NativeJavaObject.jsObjectClass.isInstance(args[i]))
args[i] = NativeJavaObject.jsObjectGetScriptable.invoke(
args[i], ScriptRuntime.emptyArgs);
}
}
catch (InvocationTargetException e) {
// Just abandon conversion from JSObject
}
catch (IllegalAccessException e) {
// Just abandon conversion from JSObject
}
}
methodSearch:
for (int i = 0; i < methodsOrCtors.length; i++) {
Member member = methodsOrCtors[i];
Class paramTypes[] = hasMethods
? ((Method) member).getParameterTypes()
: ((Constructor) member).getParameterTypes();
if (paramTypes.length != args.length) {
continue;
}
for (int j = 0; j < paramTypes.length; j++) {
if (!NativeJavaObject.canConvert(args[j], paramTypes[j])) {
if (debug) printDebug("Rejecting ", member, args);
continue methodSearch;
}
}
if (debug) {
printDebug("Found ", member, args);
while (++i < methodsOrCtors.length)
printDebug("Never considered ", methodsOrCtors[i], args);
}
return member;
}
return null;
}
Method[] getMethods() {
return methods;
}
private static final boolean debug = false;
private static void printDebug(String msg, Member member, Object[] args) {
if (debug) {
System.err.println(msg + member.getDeclaringClass().getName() +
"." + signature(member) +
" for arguments (" + signature(args) + ")");
}
}
Method methods[];
}

Просмотреть файл

@ -0,0 +1,384 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.lang.reflect.*;
import java.util.Hashtable;
import java.util.Enumeration;
/**
* This class reflects non-Array Java objects into the JavaScript environment. It
* reflect fields directly, and uses NativeJavaMethod objects to reflect (possibly
* overloaded) methods.<p>
*
* @author Mike Shaver
* @see NativeJavaArray
* @see NativeJavaPackage
* @see NativeJavaClass
*/
public class NativeJavaObject implements Scriptable, Wrapper {
public NativeJavaObject(Object javaObject, JavaMembers members) {
this.javaObject = javaObject;
this.members = members;
}
public NativeJavaObject(Scriptable scope, Object javaObject,
Class staticType)
{
this.javaObject = javaObject;
Class dynamicType = javaObject != null ? javaObject.getClass()
: staticType;
members = JavaMembers.lookupClass(scope, dynamicType, staticType);
fieldAndMethods = members.getFieldAndMethodsObjects(javaObject, false);
}
public boolean has(String name, Scriptable start) {
return members.has(name, false);
}
public boolean has(int index, Scriptable start) {
return false;
}
public Object get(String name, Scriptable start) {
if (fieldAndMethods != null) {
Object result = fieldAndMethods.get(name);
if (result != null)
return result;
}
// TODO: passing 'this' as the scope is bogus since it has
// no parent scope
return members.get(this, name, javaObject, false);
}
public Object get(int index, Scriptable start) {
throw members.reportMemberNotFound(Integer.toString(index));
}
public void put(String name, Scriptable start, Object value) {
members.put(name, javaObject, value, false);
}
public void put(int index, Scriptable start, Object value) {
throw members.reportMemberNotFound(Integer.toString(index));
}
public boolean hasInstance(Scriptable value) {
// This is an instance of a Java class, so always return false
return false;
}
public void delete(String name) {
}
public void delete(int index) {
}
public Scriptable getPrototype() {
return null;
}
public void setPrototype(Scriptable prototype) {
}
public Scriptable getParentScope() {
return null;
}
public void setParentScope(Scriptable parent) {
}
public Object[] getIds() {
return members.getIds(false);
}
public static Object wrap(Scriptable scope, Object obj, Class staticType)
{
if (obj == null)
return obj;
Class cls = obj.getClass();
if (staticType != null && staticType.isPrimitive()) {
if (staticType == Void.TYPE)
return Undefined.instance;
if (staticType == Character.TYPE)
return new Integer((int) ((Character) obj).charValue());
return obj;
}
if (cls.isArray())
return NativeJavaArray.wrap(scope, obj);
if (obj instanceof Scriptable)
return obj;
if (Context.useJSObject && jsObjectClass != null &&
staticType != jsObjectClass && jsObjectClass.isInstance(obj))
{
try {
return jsObjectGetScriptable.invoke(obj, ScriptRuntime.emptyArgs);
}
catch (InvocationTargetException e) {
// Just abandon conversion from JSObject
}
catch (IllegalAccessException e) {
// Just abandon conversion from JSObject
}
}
return new NativeJavaObject(scope, obj, staticType);
}
public Object unwrap() {
return javaObject;
}
public String getClassName() {
return "JavaObject";
}
Function getConverter(String converterName) {
Object converterFunction = get(converterName, this);
if (converterFunction instanceof Function) {
return (Function) converterFunction;
}
return null;
}
Object callConverter(Function converterFunction)
throws JavaScriptException
{
Function f = (Function) converterFunction;
return f.call(Context.getContext(), f.getParentScope(),
this, new Object[0]);
}
Object callConverter(String converterName)
throws JavaScriptException
{
Function converter = getConverter(converterName);
if (converter == null) {
Object[] errArgs = { converterName, javaObject.getClass().getName() };
throw Context.reportRuntimeError(
Context.getMessage("msg.java.conversion.implicit_method",
errArgs));
}
return callConverter(converter);
}
public Object getDefaultValue(Class hint) {
if (hint == null || hint == ScriptRuntime.StringClass)
return javaObject.toString();
try {
if (hint == ScriptRuntime.BooleanClass)
return callConverter("booleanValue");
if (hint == ScriptRuntime.NumberClass) {
return callConverter("doubleValue");
}
// fall through to error message
} catch (JavaScriptException jse) {
// fall through to error message
}
throw Context.reportRuntimeError(
Context.getMessage("msg.default.value", null));
}
/**
* Determine whether we can/should convert between the given type and the
* desired one. This should be superceded by a conversion-cost calculation
* function, but for now I'll hide behind precedent.
*/
public static boolean canConvert(Object fromObj, Class to) {
if (fromObj == null)
return true;
// XXX nontrivial conversions?
return getConversionWeight(fromObj, to) == CONVERSION_TRIVIAL;
}
public static final int CONVERSION_NONE = 0;
public static final int CONVERSION_TRIVIAL = 1;
public static final int CONVERSION_NONTRIVIAL = 2;
public static int getConversionWeight(Object fromObj, Class to) {
Class from = fromObj.getClass();
// if to is a primitive, from must be assignableFrom
// the wrapper class.
if (to.isPrimitive()) {
if (ScriptRuntime.NumberClass.isAssignableFrom(from))
return CONVERSION_TRIVIAL;
if (to == Boolean.TYPE)
return from == ScriptRuntime.BooleanClass
? CONVERSION_TRIVIAL
: CONVERSION_NONE;
// Allow String to convert to Character if length() == 1
if (to == Character.TYPE) {
if (from.isAssignableFrom(ScriptRuntime.CharacterClass) ||
(from == ScriptRuntime.StringClass &&
((String) fromObj).length() == 1))
{
return CONVERSION_TRIVIAL;
}
return CONVERSION_NONE;
}
return CONVERSION_NONTRIVIAL;
}
if (to == ScriptRuntime.CharacterClass) {
if (from.isAssignableFrom(ScriptRuntime.CharacterClass) ||
(from == ScriptRuntime.StringClass &&
((String) fromObj).length() == 1))
{
return CONVERSION_TRIVIAL;
}
return CONVERSION_NONE;
}
if (to == ScriptRuntime.StringClass) {
return CONVERSION_TRIVIAL;
}
if (Context.useJSObject && jsObjectClass != null &&
jsObjectClass.isAssignableFrom(to) &&
Scriptable.class.isAssignableFrom(from))
{
// Convert a Scriptable to a JSObject.
return CONVERSION_TRIVIAL;
}
return to.isAssignableFrom(from) ? CONVERSION_TRIVIAL : CONVERSION_NONE;
}
/**
* Type-munging for field setting and method invocation.
* This is traditionally the least fun part of getting LiveConnect right.
* I hope we've got good tests.... =/<p>
*
* Assumptions:<br>
* <ul>
* <li> we should convert fields very aggressively. e.g: a String sent to an
* int slot gets toInteger()ed and then assigned. Invalid strings
* become NaN and then 0.
* <li> we only get called when we <b>must</b> make this coercion. Don't
* use this unless you already know that the type conversion is really
* what you want.
* </ul>
*/
public static Object coerceType(Class type, Object value) {
// Don't coerce null to a string (or other object)
if (value == null)
return null;
// For final classes we can compare valueClass to a class object
// rather than using instanceof
Class valueClass = value.getClass();
// Is value already of the correct type?
if (valueClass == type)
return value;
// String
if (type == ScriptRuntime.StringClass)
return ScriptRuntime.toString(value);
if (type == Character.TYPE || type == ScriptRuntime.CharacterClass) {
// Special case for converting a single char string to a character
if (valueClass == ScriptRuntime.StringClass && ((String) value).length() == 1)
return new Character(((String) value).charAt(0));
return new Character((char)ScriptRuntime.toInteger(value));
}
// Integer, Long, Char, Byte
if (type == ScriptRuntime.IntegerClass || type == Integer.TYPE)
return new Integer((int)ScriptRuntime.toInteger(value));
if (type == ScriptRuntime.LongClass || type == Long.TYPE)
return new Long((long)ScriptRuntime.toInteger(value));
if (type == ScriptRuntime.ByteClass || type == Byte.TYPE)
return new Byte((byte)ScriptRuntime.toInteger(value));
if (type == ScriptRuntime.ShortClass || type == Short.TYPE)
return new Short((short)ScriptRuntime.toInteger(value));
// Double, Float
if (type == ScriptRuntime.DoubleClass || type == Double.TYPE) {
return valueClass == ScriptRuntime.DoubleClass
? value
: new Double(ScriptRuntime.toNumber(value));
}
if (type == ScriptRuntime.FloatClass || type == Float.TYPE) {
return valueClass == ScriptRuntime.FloatClass
? value
: new Float(ScriptRuntime.toNumber(value));
}
if (valueClass == ScriptRuntime.DoubleClass)
return value;
// If JSObject compatibility is enabled, and the method wants it,
// wrap the Scriptable value in a JSObject.
if (Context.useJSObject && jsObjectClass != null &&
value instanceof Scriptable)
{
if (Scriptable.class.isAssignableFrom(type))
return value;
try {
Object ctorArgs[] = { value };
return jsObjectCtor.newInstance(ctorArgs);
} catch (InstantiationException instEx) {
throw new EvaluatorException("error generating JSObject wrapper for " +
value);
} catch (IllegalArgumentException argEx) {
throw new EvaluatorException("JSObject constructor doesn't want [Scriptable]!");
} catch (InvocationTargetException e) {
throw WrappedException.wrapException(e);
} catch (IllegalAccessException accessEx) {
throw new EvaluatorException("JSObject constructor is protected/private!");
}
}
if (ScriptRuntime.NumberClass.isInstance(value))
return new Double(((Number) value).doubleValue());
return value;
}
public static void initJSObject() {
if (!Context.useJSObject)
return;
// if netscape.javascript.JSObject is in the CLASSPATH, enable JSObject
// compatability wrappers
jsObjectClass = null;
try {
jsObjectClass = Class.forName("netscape.javascript.JSObject");
Class ctorParms[] = { ScriptRuntime.ScriptableClass };
jsObjectCtor = jsObjectClass.getConstructor(ctorParms);
jsObjectGetScriptable = jsObjectClass.getMethod("getScriptable",
new Class[0]);
} catch (ClassNotFoundException classEx) {
// jsObjectClass already null
} catch (NoSuchMethodException methEx) {
// jsObjectClass already null
}
}
protected Object javaObject;
protected JavaMembers members;
private Hashtable fieldAndMethods;
static Class jsObjectClass;
static Constructor jsObjectCtor;
static Method jsObjectGetScriptable;
}

Просмотреть файл

@ -0,0 +1,201 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.lang.reflect.*;
/**
* This class reflects Java packages into the JavaScript environment. We
* lazily reflect classes and subpackages, and use a caching/sharing
* system to ensure that members reflected into one JavaPackage appear
* in all other references to the same package (as with Packages.java.lang
* and java.lang).
*
* @author Mike Shaver
* @see NativeJavaArray
* @see NativeJavaObject
* @see NativeJavaClass
*/
public class NativeJavaPackage extends ScriptableObject {
// we know these are packages so we can skip the class check
// note that this is ok even if the package isn't present.
static final String[] commonPackages = {
"java.lang",
"java.lang.reflect",
"java.io",
"java.math",
"java.util",
"java.util.zip",
"java.text",
"java.text.resources",
"java.applet",
"netscape.security",
"netscape.plugin",
"netscape.application",
};
public static Scriptable init(Scriptable scope)
throws PropertyException
{
NativeJavaPackage packages = new NativeJavaPackage("");
packages.setPrototype(getObjectPrototype(scope));
packages.setParentScope(scope);
// We want to get a real alias, and not a distinct JavaPackage
// with the same packageName, so that we share classes and packages
// that are underneath.
NativeJavaPackage javaAlias = (NativeJavaPackage)packages.get("java",
packages);
// It's safe to downcast here since initStandardObjects takes
// a ScriptableObject.
ScriptableObject global = (ScriptableObject) scope;
global.defineProperty("Packages", packages, ScriptableObject.DONTENUM);
global.defineProperty("java", javaAlias, ScriptableObject.DONTENUM);
for (int i = 0; i < commonPackages.length; i++)
packages.forcePackage(commonPackages[i]);
NativeJavaObject.initJSObject();
String[] methods = { "getClass" };
global.defineFunctionProperties(methods, NativeJavaPackage.class,
ScriptableObject.DONTENUM);
// I think I'm supposed to return the prototype, but I don't have one.
return packages;
}
// set up a name which is known to be a package so we don't
// need to look for a class by that name
void forcePackage(String name) {
NativeJavaPackage pkg;
int end = name.indexOf('.');
if (end == -1)
end = name.length();
String id = name.substring(0, end);
Object cached = super.get(id, this);
if (cached != null && cached instanceof NativeJavaPackage) {
pkg = (NativeJavaPackage) cached;
} else {
String newPackage = packageName.length() == 0
? id
: packageName + "." + id;
pkg = new NativeJavaPackage(newPackage);
pkg.setParentScope(this);
pkg.setPrototype(this.prototype);
super.put(id, this, pkg);
}
if (end < name.length())
pkg.forcePackage(name.substring(end+1));
}
public NativeJavaPackage(String packageName) {
this.packageName = packageName;
}
public String getClassName() {
return "JavaPackage";
}
public boolean has(String id, int index, Scriptable start) {
return true;
}
public void put(String id, Scriptable start, Object value) {
// Can't add properties to Java packages. Sorry.
}
public void put(int index, Scriptable start, Object value) {
// Can't add properties to Java packages. Sorry.
}
public synchronized Object get(String id, Scriptable start) {
Object cached = super.get(id, start);
if (cached != NOT_FOUND)
return cached;
String newPackage = packageName.length() == 0
? id
: packageName + "." + id;
Scriptable newValue;
try {
Class newClass = Class.forName(newPackage);
newValue = NativeJavaClass.wrap(getTopLevelScope(this), newClass);
newValue.setParentScope(this);
newValue.setPrototype(this.prototype);
} catch (ClassNotFoundException ex) {
newValue = new NativeJavaPackage(newPackage);
newValue.setParentScope(this);
newValue.setPrototype(this.prototype);
}
// Make it available for fast lookup and sharing of lazily-reflected
// constructors and static members.
super.put(id, start, newValue);
return newValue;
}
public synchronized Object get(int index, Scriptable start) {
return NOT_FOUND;
}
public Object getDefaultValue(Class ignored) {
return toString();
}
public String toString() {
return "[JavaPackage " + packageName + "]";
}
public static Scriptable getClass(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
if (args.length > 0 && args[0] instanceof NativeJavaObject) {
NativeJavaObject nativeJavaObj = (NativeJavaObject) args[0];
Scriptable result = getTopLevelScope(thisObj);
Class cl = nativeJavaObj.unwrap().getClass();
// Evaluate the class name by getting successive properties of
// the string to find the appropriate NativeJavaClass object
String name = "Packages." + cl.getName();
int offset = 0;
for (;;) {
int index = name.indexOf('.', offset);
String propName = index == -1
? name.substring(offset)
: name.substring(offset, index);
Object prop = result.get(propName, result);
if (!(prop instanceof Scriptable))
break; // fall through to error
result = (Scriptable) prop;
if (index == -1)
return result;
offset = index+1;
}
}
throw Context.reportRuntimeError(
Context.getMessage("msg.not.java.obj", null));
}
private String packageName;
}

Просмотреть файл

@ -0,0 +1,122 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This class implements the Math native object.
* See ECMA 15.8.
* @author Norris Boyd
*/
public class NativeMath extends ScriptableObject {
public static Scriptable init(Scriptable scope)
throws PropertyException
{
NativeMath m = new NativeMath();
m.setPrototype(getObjectPrototype(scope));
m.setParentScope(scope);
String[] names = { "acos", "asin", "atan", "atan2", "ceil",
"cos", "floor", "log", "random",
"sin", "sqrt", "tan" };
m.defineFunctionProperties(names, java.lang.Math.class,
ScriptableObject.DONTENUM);
// These functions exist in java.lang.Math, but
// are overloaded. Define our own wrappers.
String[] localNames = { "abs", "exp", "max", "min", "round", "pow" };
m.defineFunctionProperties(localNames, NativeMath.class,
ScriptableObject.DONTENUM);
final int attr = ScriptableObject.DONTENUM |
ScriptableObject.PERMANENT |
ScriptableObject.READONLY;
m.defineProperty("E", new Double(Math.E), attr);
m.defineProperty("PI", new Double(Math.PI), attr);
m.defineProperty("LN10", new Double(2.302585092994046), attr);
m.defineProperty("LN2", new Double(0.6931471805599453), attr);
m.defineProperty("LOG2E", new Double(1.4426950408889634), attr);
m.defineProperty("LOG10E", new Double(0.4342944819032518), attr);
m.defineProperty("SQRT1_2", new Double(0.7071067811865476), attr);
m.defineProperty("SQRT2", new Double(1.4142135623730951), attr);
// We know that scope is a Scriptable object since we
// constrained the type on initStandardObjects.
ScriptableObject global = (ScriptableObject) scope;
global.defineProperty("Math", m, ScriptableObject.DONTENUM);
return m;
}
public NativeMath() {
}
public String getClassName() {
return "Math";
}
public double abs(double d) {
if (d == 0.0)
return 0.0; // abs(-0.0) should be 0.0, but -0.0 < 0.0 == false
else if (d < 0.0)
return -d;
else
return d;
}
public double max(double x, double y) {
return Math.max(x, y);
}
public double min(double x, double y) {
return Math.min(x, y);
}
public double round(double d) {
if (d != d)
return d; // NaN
if (d == Double.POSITIVE_INFINITY || d == Double.NEGATIVE_INFINITY)
return d;
long l = Math.round(d);
if (l == 0) {
// We must propagate the sign of d into the result
if (d < 0.0)
return ScriptRuntime.negativeZero;
return d == 0.0 ? d : 0.0;
}
return (double) l;
}
public double pow(double x, double y) {
if (y == 0)
return 1.0; // Java's pow(NaN, 0) = NaN; we need 1
return Math.pow(x, y);
}
public double exp(double d) {
if (d == Double.POSITIVE_INFINITY)
return d;
if (d == Double.NEGATIVE_INFINITY)
return 0.0;
return Math.exp(d);
}
}

Просмотреть файл

@ -0,0 +1,86 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This class implements the Number native object.
*
* See ECMA 15.7.
*
* @author Norris Boyd
*/
public class NativeNumber extends ScriptableObject {
public static void finishInit(Scriptable scope,
FunctionObject ctor, Scriptable proto)
{
final int attr = ScriptableObject.DONTENUM |
ScriptableObject.PERMANENT |
ScriptableObject.READONLY;
String[] names = { "NaN", "POSITIVE_INFINITY", "NEGATIVE_INFINITY",
"MAX_VALUE", "MIN_VALUE" };
double[] values = { ScriptRuntime.NaN, Double.POSITIVE_INFINITY,
Double.NEGATIVE_INFINITY, Double.MAX_VALUE,
Double.MIN_VALUE };
for (int i=0; i < names.length; i++) {
ctor.defineProperty(names[i], new Double(values[i]), attr);
}
}
/**
* Zero-parameter constructor: just used to create Number.prototype
*/
public NativeNumber() {
doubleValue = defaultValue;
}
public NativeNumber(double number) {
doubleValue = number;
}
public String getClassName() {
return "Number";
}
public static Object Number(Context cx, Object[] args, Function funObj,
boolean inNewExpr)
{
double d = args.length >= 1
? ScriptRuntime.toNumber(args[0])
: defaultValue;
if (inNewExpr) {
// new Number(val) creates a new Number object.
return new NativeNumber(d);
}
// Number(val) converts val to a number value.
return new Double(d);
}
public String toString() {
return ScriptRuntime.numberToString(doubleValue);
}
public double valueOf() {
return doubleValue;
}
private static final double defaultValue = +0.0;
private double doubleValue;
}

Просмотреть файл

@ -0,0 +1,128 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.util.Hashtable;
/**
* This class implements the Object native object.
* See ECMA 15.2.
* @author Norris Boyd
*/
public class NativeObject extends ScriptableObject {
public static void finishInit(Scriptable scope, FunctionObject ctor,
Scriptable proto)
{
Object obj = proto.get("valueOf", proto);
((FunctionObject) obj).setLength((short) 0);
}
public String getClassName() {
return "Object";
}
public static Object js_Object(Context cx, Object[] args, Function ctorObj,
boolean inNewExpr)
throws JavaScriptException
{
if (!inNewExpr) {
// FunctionObject.construct will set up parent, proto
return ctorObj.construct(cx, ctorObj.getParentScope(), args);
}
if (args.length == 0 || args[0] == null ||
args[0] == Undefined.instance)
{
return new NativeObject();
}
return ScriptRuntime.toObject(ctorObj.getParentScope(), args[0]);
}
public String toString() {
Context cx = Context.getContext();
if (cx != null)
return js_toString(cx, this, null, null);
else
return "[object " + getClassName() + "]";
}
public static String js_toString(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
if (cx.getLanguageVersion() != cx.VERSION_1_2)
return "[object " + thisObj.getClassName() + "]";
return toSource(cx, thisObj, args, funObj);
}
public static String toSource(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
Scriptable m = thisObj;
if (cx.iterating == null)
cx.iterating = new Hashtable(31);
if (cx.iterating.get(m) == Boolean.TRUE) {
return "{}"; // stop recursion
} else {
StringBuffer result = new StringBuffer("{");
Object[] ids = m.getIds();
for(int i=0; i < ids.length; i++) {
if (i > 0)
result.append(", ");
Object id = ids[i];
String idString = ScriptRuntime.toString(id);
Object p = (id instanceof String)
? m.get((String) id, m)
: m.get(((Number) id).intValue(), m);
if (p instanceof String) {
result.append(idString + ":\""
+ ScriptRuntime
.escapeString(ScriptRuntime.toString(p))
+ "\"");
} else {
/* wrap changes to cx.iterating in a try/finally
* so that the reference always gets removed, and
* we don't leak memory. Good place for weak
* references, if we had them.
*/
try {
cx.iterating.put(m, Boolean.TRUE); // stop recursion.
result.append(idString + ":" + ScriptRuntime.toString(p));
} finally {
cx.iterating.remove(m);
}
}
}
result.append("}");
return result.toString();
}
}
public static Object js_valueOf(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
return thisObj;
}
}

Просмотреть файл

@ -0,0 +1,150 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.io.StringReader;
import java.io.IOException;
/**
* The JavaScript Script object.
*
* Note that the C version of the engine uses XDR as the format used
* by freeze and thaw. Since this depends on the internal format of
* structures in the C runtime, we cannot duplicate it.
*
* Since we cannot replace 'this' as a result of the compile method,
* this class has a dual nature. Generated scripts will have a null
* 'script' field and will override 'exec' and 'call'. Scripts created
* using the JavaScript constructor will forward requests to the
* nonnull 'script' field.
*
* @since 1.3
* @author Norris Boyd
*/
public class NativeScript extends NativeFunction implements Script {
public NativeScript() {
}
/**
* Returns the name of this JavaScript class, "Script".
*/
public String getClassName() {
return "Script";
}
/**
* Initialize script.
*
* Does nothing here, but scripts will override with code
* to initialize contained functions, regexp literals, etc.
*/
public void initScript(Scriptable scope) {
}
/**
* The Java method defining the JavaScript Script constructor.
*
*/
public static Object js_Script(Context cx, Object[] args,
Function ctorObj, boolean inNewExpr)
{
String source = args.length == 0
? ""
: ScriptRuntime.toString(args[0]);
return compile(ctorObj, source);
}
public static Script compile(Scriptable scope, String source) {
Context cx = Context.getContext();
StringReader reader = new StringReader(source);
try {
int[] linep = { 0 };
String filename = Context.getSourcePositionFromStack(linep);
if (filename == null) {
filename = "<Script object>";
linep[0] = 1;
}
Object securityDomain =
cx.getSecurityDomainForStackDepth(5);
return cx.compileReader(scope, reader, filename, linep[0],
securityDomain);
}
catch (IOException e) {
throw new RuntimeException("Unexpected IOException");
}
}
public Scriptable js_compile(String source) {
script = compile(null, source);
return this;
}
public Object js_exec() throws JavaScriptException {
Context cx = Context.getContext();
Scriptable scope = getTopLevelScope(getParentScope());
return exec(cx, scope);
}
public static Object js_toString(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
Script thisScript = ((NativeScript) thisObj).script;
if (thisScript == null)
thisScript = (Script) thisObj;
Scriptable scope = getTopLevelScope(thisObj);
return cx.decompileScript(thisScript, scope, 0);
}
/*
* Override method in NativeFunction to avoid ever returning "anonymous"
*/
public String js_getName() {
return "";
}
/**
* Execute the script.
*
* Will be overridden by generated scripts; needed to implement Script.
*/
public Object exec(Context cx, Scriptable scope)
throws JavaScriptException
{
return script == null ? Undefined.instance : script.exec(cx, scope);
}
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException
{
return exec(cx, scope);
}
public Scriptable construct(Context cx, Scriptable scope, Object[] args)
throws JavaScriptException
{
String message = Context.getMessage("msg.script.is.not.constructor", null);
throw Context.reportRuntimeError(message);
}
private Script script;
}

Просмотреть файл

@ -0,0 +1,711 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.lang.reflect.Method;
import java.util.Vector;
/**
* This class implements the String native object.
*
* See ECMA 15.5.
*
* String methods for dealing with regular expressions are
* ported directly from C. Latest port is from version 1.40.12.19
* in the JSFUN13_BRANCH.
*
* @author Mike McCabe
* @author Norris Boyd
*/
public class NativeString extends ScriptableObject implements Wrapper {
/**
* Zero-parameter constructor: just used to create String.prototype
*/
public NativeString() {
string = defaultValue;
}
public static void finishInit(Scriptable scope, FunctionObject ctor,
Scriptable proto)
{
// Most of the methods of String.prototype are "vararg" form
// so that they can convert the "this" value to string, rather
// than being restricted to just operating on NativeString
// objects. However, this means that the values of the "length"
// properties of these methods are set to 1 by the constructor
// for FunctionObject. We must therefore fetch the function
// objects and set the length to the appropriate value.
String[] specialLengthNames = { "indexOf",
"lastIndexOf",
"substring",
"toUpperCase",
"toLowerCase",
"toString",
};
short[] specialLengthValues = { 2,
2,
2,
0,
0,
0,
};
for (int i=0; i < specialLengthNames.length; i++) {
Object obj = proto.get(specialLengthNames[i], proto);
((FunctionObject) obj).setLength(specialLengthValues[i]);
}
}
public NativeString(String s) {
string = s;
}
public String getClassName() {
return "String";
}
public static String jsStaticFunction_fromCharCode(Context cx,
Scriptable thisObj,
Object[] args,
Function funObj)
{
StringBuffer s = new java.lang.StringBuffer();
if (args.length < 1)
return "";
for (int i=0; i < args.length; i++) {
s.append(ScriptRuntime.toUint16(args[i]));
}
return s.toString();
}
public static Object js_String(Context cx, Object[] args, Function ctorObj,
boolean inNewExpr)
{
String s = args.length >= 1
? ScriptRuntime.toString(args[0])
: defaultValue;
if (inNewExpr) {
// new String(val) creates a new String object.
return new NativeString(s);
}
// String(val) converts val to a string value.
return s;
}
public String toString() {
return string;
}
/* ECMA 15.5.4.2: 'the toString function is not generic.' */
public String js_toString() {
return string;
}
public String js_valueOf() {
return string;
}
/* Make array-style property lookup work for strings.
* XXX is this ECMA? A version check is probably needed. In js too.
*/
public Object get(int index, Scriptable start) {
if (index >= 0 && index < string.length())
return string.substring(index, index + 1);
return super.get(index, start);
}
public void put(int index, Scriptable start, Object value) {
if (index >= 0 && index < string.length())
return;
super.put(index, start, value);
}
/**
*
* See ECMA 15.5.4.[4,5]
*/
public static String js_charAt(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
if (args.length < 1)
args = ScriptRuntime.padArguments(args, 1);
// this'll return 0 if undefined... seems
// to be ECMA.
String target = ScriptRuntime.toString(thisObj);
double pos = ScriptRuntime.toInteger(args[0]);
if (pos < 0 || pos >= target.length())
return "";
return target.substring((int)pos, (int)pos + 1);
}
public static double js_charCodeAt(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
if (args.length < 1)
args = ScriptRuntime.padArguments(args, 1);
String target = ScriptRuntime.toString(thisObj);
double pos = ScriptRuntime.toInteger(args[0]);
if (pos < 0 || pos >= target.length()) {
return ScriptRuntime.NaN;
}
return target.charAt((int)pos);
}
/**
*
* See ECMA 15.5.4.6. Uses Java String.indexOf()
* OPT to add - BMH searching from jsstr.c.
*/
public static int js_indexOf(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
if (args.length < 2)
args = ScriptRuntime.padArguments(args, 2);
String target = ScriptRuntime.toString(thisObj);
String search = ScriptRuntime.toString(args[0]);
double begin = ScriptRuntime.toInteger(args[1]);
if (begin > target.length()) {
return -1;
} else {
if (begin < 0)
begin = 0;
return target.indexOf(search, (int)begin);
}
}
/**
*
* See ECMA 15.5.4.7
*
*/
public static int js_lastIndexOf(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
if (args.length < 2)
args = ScriptRuntime.padArguments(args, 2);
String target = ScriptRuntime.toString(thisObj);
String search = ScriptRuntime.toString(args[0]);
double end = ScriptRuntime.toNumber(args[1]);
if (end != end || end > target.length())
end = target.length();
else if (end < 0)
end = 0;
return target.lastIndexOf(search, (int)end);
}
/*
* Used by js_split to find the next split point in target,
* starting at offset ip and looking either for the given
* separator substring, or for the next re match. ip and
* matchlen must be reference variables (assumed to be arrays of
* length 1) so they can be updated in the leading whitespace or
* re case.
*
* Return -1 on end of string, >= 0 for a valid index of the next
* separator occurrence if found, or the string length if no
* separator is found.
*/
private static int find_split(Function funObj, String target,
String separator, Object re,
int[] ip, int[] matchlen, boolean[] matched,
String[][] parensp)
{
int i = ip[0];
int length = target.length();
Context cx = Context.getContext();
int version = cx.getLanguageVersion();
/*
* Perl4 special case for str.split(' '), only if the user has selected
* JavaScript1.2 explicitly. Split on whitespace, and skip leading w/s.
* Strange but true, apparently modeled after awk.
*/
if (version == Context.VERSION_1_2 &&
re == null && separator.length() == 1 && separator.charAt(0) == ' ')
{
/* Skip leading whitespace if at front of str. */
if (i == 0) {
while (i < length && Character.isWhitespace(target.charAt(i)))
i++;
ip[0] = i;
}
/* Don't delimit whitespace at end of string. */
if (i == length)
return -1;
/* Skip over the non-whitespace chars. */
while (i < length
&& !Character.isWhitespace(target.charAt(i)))
i++;
/* Now skip the next run of whitespace. */
int j = i;
while (j < length && Character.isWhitespace(target.charAt(j)))
j++;
/* Update matchlen to count delimiter chars. */
matchlen[0] = j - i;
return i;
}
/*
* Stop if past end of string. If at end of string, we will
* return target length, so that
*
* "ab,".split(',') => new Array("ab", "")
*
* and the resulting array converts back to the string "ab,"
* for symmetry. NB: This differs from perl, which drops the
* trailing empty substring if the LIMIT argument is omitted.
*/
if (i > length)
return -1;
/*
* Match a regular expression against the separator at or
* above index i. Return -1 at end of string instead of
* trying for a match, so we don't get stuck in a loop.
*/
if (re != null) {
return cx.getRegExpProxy().find_split(funObj, target,
separator, re,
ip, matchlen, matched,
parensp);
}
/*
* Deviate from ECMA by never splitting an empty string by any separator
* string into a non-empty array (an array of length 1 that contains the
* empty string).
*/
if (version != Context.VERSION_DEFAULT && version < Context.VERSION_1_3
&& length == 0)
return -1;
/*
* Special case: if sep is the empty string, split str into
* one character substrings. Let our caller worry about
* whether to split once at end of string into an empty
* substring.
*
* For 1.2 compatibility, at the end of the string, we return the length as
* the result, and set the separator length to 1 -- this allows the caller
* to include an additional null string at the end of the substring list.
*/
if (separator.length() == 0) {
if (version == Context.VERSION_1_2) {
if (i == length) {
matchlen[0] = 1;
return i;
}
return i + 1;
}
return (i == length) ? -1 : i + 1;
}
/* Punt to j.l.s.indexOf; return target length if seperator is
* not found.
*/
if (ip[0] >= length)
return length;
i = target.indexOf(separator, ip[0]);
return (i != -1) ? i : length;
}
/**
* See ECMA 15.5.4.8. Modified to match JS 1.2 - optionally takes
* a limit argument and accepts a regular expression as the split
* argument.
*/
public static Object js_split(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
String target = ScriptRuntime.toString(thisObj);
// create an empty Array to return;
Scriptable scope = getTopLevelScope(funObj);
Scriptable result = ScriptRuntime.newObject(cx, scope, "Array", null);
// return an array consisting of the target if no separator given
// don't check against undefined, because we want
// 'fooundefinedbar'.split(void 0) to split to ['foo', 'bar']
if (args.length < 1) {
result.put(0, result, target);
return result;
}
// Use the second argument as the split limit, if given.
boolean limited = (args.length > 1);
int limit = 0; // Initialize to avoid warning.
if (limited) {
/* Clamp limit between 0 and 1 + string length. */
double d = ScriptRuntime.toInteger(args[1]);
if (d < 0)
d = 0;
else if (d > target.length())
d = 1 + target.length();
limit = (int)d;
}
String separator = null;
int[] matchlen = { 0 };
Object re = null;
RegExpProxy reProxy = cx.getRegExpProxy();
if (reProxy != null && reProxy.isRegExp(args[0])) {
re = args[0];
} else {
separator = ScriptRuntime.toString(args[0]);
matchlen[0] = separator.length();
}
// split target with separator or re
int[] ip = { 0 };
int match;
int len = 0;
boolean[] matched = { false };
String[][] parens = { null };
while ((match = find_split(funObj, target, separator, re, ip,
matchlen, matched, parens)) >= 0)
{
if ((limited && len >= limit) || (match > target.length()))
break;
String substr;
if (target.length() == 0)
substr = target;
else
substr = target.substring(ip[0], match);
result.put(len, result, substr);
len++;
/*
* Imitate perl's feature of including parenthesized substrings
* that matched part of the delimiter in the new array, after the
* split substring that was delimited.
*/
if (re != null && matched[0] == true) {
int size = parens[0].length;
for (int num = 0; num < size; num++) {
if (limited && len >= limit)
break;
result.put(len, result, parens[0][num]);
len++;
}
matched[0] = false;
}
ip[0] = match + matchlen[0];
if (cx.getLanguageVersion() < Context.VERSION_1_3
&& cx.getLanguageVersion() != Context.VERSION_DEFAULT)
{
/*
* Deviate from ECMA to imitate Perl, which omits a final
* split unless a limit argument is given and big enough.
*/
if (!limited && ip[0] == target.length())
break;
}
}
return result;
}
/**
*
* See ECMA 15.5.4.[9,10]
*/
public static String js_substring(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
if (args.length < 1)
args = ScriptRuntime.padArguments(args, 1);
String target = ScriptRuntime.toString(thisObj);
int length = target.length();
double start = ScriptRuntime.toInteger(args[0]);
double end;
if (start < 0)
start = 0;
else if (start > length)
start = length;
if (args.length == 1) {
end = length;
} else {
end = ScriptRuntime.toInteger(args[1]);
if (end < 0)
end = 0;
else if (end > length)
end = length;
// swap if end < start
if (end < start) {
if (cx.getLanguageVersion() != Context.VERSION_1_2) {
double temp = start;
start = end;
end = temp;
} else {
// Emulate old JDK1.0 java.lang.String.substring()
end = start;
}
}
}
return target.substring((int)start, (int)end);
}
/**
*
* See ECMA 15.5.4.[11,12]
*/
public static String js_toLowerCase(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
String target = ScriptRuntime.toString(thisObj);
return target.toLowerCase();
}
public static String js_toUpperCase(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
String target = ScriptRuntime.toString(thisObj);
return target.toUpperCase();
}
public double js_getLength() {
return (double) string.length();
}
/**
* Non-ECMA methods.
*/
public static String js_substr(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
String target = ScriptRuntime.toString(thisObj);
if (args.length < 1)
return target;
double begin = ScriptRuntime.toInteger(args[0]);
double end;
int length = target.length();
if (begin < 0) {
begin += length;
if (begin < 0)
begin = 0;
} else if (begin > length) {
begin = length;
}
if (args.length == 1) {
end = length;
} else {
end = ScriptRuntime.toInteger(args[1]);
if (end < 0)
end = 0;
end += begin;
if (end > length)
end = length;
}
return target.substring((int)begin, (int)end);
}
/**
* Python-esque sequence operations.
*/
public static String js_concat(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
StringBuffer result = new StringBuffer();
result.append(ScriptRuntime.toString(thisObj));
for (int i = 0; i < args.length; i++)
result.append(ScriptRuntime.toString(args[i]));
return result.toString();
}
public static String js_slice(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
String target = ScriptRuntime.toString(thisObj);
if (args.length != 0) {
double begin = ScriptRuntime.toInteger(args[0]);
double end;
int length = target.length();
if (begin < 0) {
begin += length;
if (begin < 0)
begin = 0;
} else if (begin > length) {
begin = length;
}
if (args.length == 1) {
end = length;
} else {
end = ScriptRuntime.toInteger(args[1]);
if (end < 0) {
end += length;
if (end < 0)
end = 0;
} else if (end > length) {
end = length;
}
if (end < begin)
end = begin;
}
return target.substring((int)begin, (int)end);
}
return target;
}
/**
* HTML composition aids.
*/
private String tagify(String begin, String end, String value) {
StringBuffer result = new StringBuffer();
result.append('<');
result.append(begin);
if (value != null) {
result.append('=');
result.append(value);
}
result.append('>');
result.append(this.string);
result.append("</");
result.append((end == null) ? begin : end);
result.append('>');
return result.toString();
}
public String js_bold() {
return tagify("B", null, null);
}
public String js_italics() {
return tagify("I", null, null);
}
public String js_fixed() {
return tagify("TT", null, null);
}
public String js_strike() {
return tagify("STRIKE", null, null);
}
public String js_small() {
return tagify("SMALL", null, null);
}
public String js_big() {
return tagify("BIG", null, null);
}
public String js_blink() {
return tagify("BLINK", null, null);
}
public String js_sup() {
return tagify("SUP", null, null);
}
public String js_sub() {
return tagify("SUB", null, null);
}
public String js_fontsize(String value) {
return tagify("FONT SIZE", "FONT", value);
}
public String js_fontcolor(String value) {
return tagify("FONT COLOR", "FONT", value);
}
public String js_link(String value) {
return tagify("A HREF", "A", value);
}
public String js_anchor(String value) {
return tagify("A NAME", "A", value);
}
/**
* Unwrap this NativeString as a j.l.String for LiveConnect use.
*/
public Object unwrap() {
return string;
}
public static Object js_match(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws JavaScriptException
{
return checkReProxy(cx).match(cx, thisObj, args, funObj);
}
public static Object js_search(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws JavaScriptException
{
return checkReProxy(cx).search(cx, thisObj, args, funObj);
}
public static Object js_replace(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws JavaScriptException
{
return checkReProxy(cx).replace(cx, thisObj, args, funObj);
}
private static RegExpProxy checkReProxy(Context cx) {
RegExpProxy result = cx.getRegExpProxy();
if (result == null) {
throw cx.reportRuntimeError(cx.getMessage("msg.no.regexp", null));
}
return result;
}
private static final String defaultValue = "";
private String string;
}

Просмотреть файл

@ -0,0 +1,155 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.lang.reflect.Method;
/**
* This class implements the object lookup required for the
* <code>with</code> statement.
* It simply delegates every action to its prototype except
* for operations on its parent.
*/
public class NativeWith implements Scriptable {
public static void init(Scriptable scope) {
NativeWith w = new NativeWith();
w.setPrototype(ScriptableObject.getObjectPrototype(scope));
Method[] m = FunctionObject.findMethods(NativeWith.class, "With");
FunctionObject f = new FunctionObject("With", m[0], scope);
f.addAsConstructor(scope, w);
}
public NativeWith() {
}
public NativeWith(Scriptable parent, Scriptable prototype) {
this.parent = parent;
this.prototype = prototype;
}
public String getClassName() {
return "With";
}
public boolean has(String id, Scriptable start) {
if (start == this)
start = prototype;
return prototype.has(id, start);
}
public boolean has(int index, Scriptable start) {
if (start == this)
start = prototype;
return prototype.has(index, start);
}
public Object get(String id, Scriptable start) {
if (start == this)
start = prototype;
return prototype.get(id, start);
}
public Object get(int index, Scriptable start) {
if (start == this)
start = prototype;
return prototype.get(index, start);
}
public void put(String id, Scriptable start, Object value) {
if (start == this)
start = prototype;
prototype.put(id, start, value);
}
public void put(int index, Scriptable start, Object value) {
if (start == this)
start = prototype;
prototype.put(index, start, value);
}
public void delete(String id) {
prototype.delete(id);
}
public void delete(int index) {
prototype.delete(index);
}
public Scriptable getPrototype() {
return prototype;
}
public void setPrototype(Scriptable prototype) {
this.prototype = prototype;
}
public Scriptable getParentScope() {
return parent;
}
public void setParentScope(Scriptable parent) {
this.parent = parent;
}
public Object[] getIds() {
return prototype.getIds();
}
public Object getDefaultValue(Class typeHint) {
return prototype.getDefaultValue(typeHint);
}
public boolean hasInstance(Scriptable value) {
return prototype.hasInstance(value);
}
public static Object With(Context cx, Object[] args, Function ctorObj,
boolean inNewExpr)
{
Object[] msgArgs = { "With" };
throw Context.reportRuntimeError(
Context.getMessage("msg.cant.call.indirect", msgArgs));
}
public static Object newWithSpecial(Context cx, Object[] args,
Function ctorObj, boolean inNewExpr)
{
if (!inNewExpr) {
Object[] errArgs = { "With" };
throw Context.reportRuntimeError(Context.getMessage
("msg.only.from.new", errArgs));
}
ScriptRuntime.checkDeprecated(cx, "With");
Scriptable scope = ScriptableObject.getTopLevelScope(ctorObj);
NativeWith thisObj = new NativeWith();
thisObj.setPrototype(args.length == 0
? ScriptableObject.getClassPrototype(scope,
"Object")
: ScriptRuntime.toObject(scope, args[0]));
thisObj.setParentScope(scope);
return thisObj;
}
private Scriptable prototype;
private Scriptable parent;
private Scriptable constructor;
}

Просмотреть файл

@ -0,0 +1,450 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.util.*;
/**
* This class implements the root of the intermediate representation.
*
* @author Norris Boyd
* @author Mike McCabe
*/
public class Node implements Cloneable {
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, Object datum) {
type = nodeType;
this.datum = datum;
}
public Node(int nodeType, Node child, Object datum) {
this(nodeType, child);
this.datum = datum;
}
public Node(int nodeType, Node left, Node right, Object datum) {
this(nodeType, left, right);
this.datum = datum;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public boolean hasChildren() {
return first != null;
}
public Node getFirstChild() {
return first;
}
public Node getLastChild() {
return last;
}
public Node getNextSibling() {
return next;
}
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 ShallowNodeIterator getChildIterator() {
return new ShallowNodeIterator(first);
}
public PreorderNodeIterator getPreorderIterator() {
return new PreorderNodeIterator(this);
}
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 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;
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 String propNames[];
private static final String propToString(int propType) {
if (Context.printTrees && propNames == null) {
// If Context.printTrees is false, the compiler
// can remove all these strings.
String[] a = {
"TARGET",
"BREAK",
"CONTINUE",
"ENUM",
"FUNCTION",
"TEMP",
"LOCAL",
"CODEOFFSET",
"FIXUPS",
"VARS",
"USES",
"REGEXP",
"SWITCHES",
"CASES",
"DEFAULT",
"CASEARRAY",
"SOURCENAME",
"SOURCE",
"TYPE",
"SPECIAL_PROP",
"LABEL",
"FINALLY",
"LOCALCOUNT",
"TARGETBLOCK",
"VARIABLE",
"LASTUSE",
"ISNUMBER",
"DIRECTCALL",
"BASE_LINENO",
"END_LINENO",
"SPECIALCALL"
};
propNames = a;
}
return propNames[propType];
}
public Object getProp(int propType) {
if (props == null)
return null;
return props.get(new Integer(propType));
}
public void putProp(int propType, Object prop) {
if (props == null)
props = new Hashtable(2);
if (prop == null)
props.remove(new Integer(propType));
else
props.put(new Integer(propType), prop);
}
public Object getDatum() {
return datum;
}
public void setDatum(Object datum) {
this.datum = datum;
}
public int getInt() {
return ((Number) datum).intValue();
}
public double getDouble() {
return ((Number) datum).doubleValue();
}
public long getLong() {
return ((Number) datum).longValue();
}
public String getString() {
return (String) datum;
}
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 String toString() {
if (Context.printTrees) {
StringBuffer sb = new StringBuffer(TokenStream.tokenToName(type));
if (type == TokenStream.TARGET) {
sb.append(" ");
sb.append(hashCode());
}
if (datum != null) {
sb.append(' ');
sb.append(datum.toString());
}
if (props == null)
return sb.toString();
Enumeration keys = props.keys();
Enumeration elems = props.elements();
while (keys.hasMoreElements()) {
Integer key = (Integer) keys.nextElement();
Object elem = elems.nextElement();
sb.append(" [");
sb.append(propToString(key.intValue()));
sb.append(": ");
switch (key.intValue()) {
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 :
sb.append(elem.toString());
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');
ShallowNodeIterator iterator = getChildIterator();
if (iterator != null) {
while (iterator.hasMoreElements()) {
Node n = (Node) iterator.nextElement();
if (n.getType() == TokenStream.FUNCTION) {
Node p = (Node) n.getProp(Node.FUNCTION_PROP);
if (p != null)
n = p;
}
s.append(n.toStringTreeHelper(level+1));
}
}
return s.toString();
}
return "";
}
public Node getFirst() { return first; }
public Node getNext() { return next; }
protected int type; // type of the node; TokenStream.NAME for example
protected Node next; // next sibling
protected Node first; // first element of a linked list of children
protected Node last; // last element of a linked list of children
protected Hashtable props;
protected Object datum; // encapsulated data; depends on type
}

Просмотреть файл

@ -0,0 +1,659 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.util.Hashtable;
import java.util.Stack;
import java.util.Vector;
/**
* This class transforms a tree to a lower-level representation for codegen.
*
* @see Node
* @author Norris Boyd
*/
public class NodeTransformer {
/**
* Return new instance of this class. So that derived classes
* can override methods of the transformer.
*/
public NodeTransformer newInstance() {
return new NodeTransformer();
}
public IRFactory createIRFactory(TokenStream ts) {
return new IRFactory(ts);
}
public Node transform(Node tree, Node enclosing, TokenStream ts) {
loops = new Stack();
loopEnds = new Stack();
Context cx = Context.getContext();
inFunction = tree.getType() == TokenStream.FUNCTION;
if (!inFunction) {
addVariables(tree, getVariableTable(tree));
}
irFactory = createIRFactory(ts);
// to save against upchecks if no finally blocks are used.
boolean hasFinally = false;
PreorderNodeIterator iterator = tree.getPreorderIterator();
Node node;
while ((node = iterator.nextNode()) != null) {
int type = node.getType();
typeswitch:
switch (type) {
case TokenStream.FUNCTION:
if (node == tree) {
// Add the variables to variable table, the
// parameters were added earlier.
VariableTable vars = getVariableTable(tree);
addVariables(tree, vars);
// Add return to end if needed.
Node stmts = node.getLastChild();
Node lastStmt = stmts.getLastChild();
if (lastStmt == null ||
lastStmt.getType() != TokenStream.RETURN)
{
stmts.addChildToBack(new Node(TokenStream.RETURN));
}
} else {
if (inFunction) {
// Nested functions require activation objects.
((FunctionNode) tree).setRequiresActivation(true);
}
FunctionNode fnNode = (FunctionNode)
node.getProp(Node.FUNCTION_PROP);
addParameters(fnNode);
NodeTransformer inner = newInstance();
fnNode = (FunctionNode) inner.transform(fnNode, tree, ts);
node.putProp(Node.FUNCTION_PROP, fnNode);
Vector fns = (Vector) tree.getProp(Node.FUNCTION_PROP);
if (fns == null) {
fns = new Vector(7);
tree.putProp(Node.FUNCTION_PROP, fns);
}
fns.addElement(fnNode);
}
break;
case TokenStream.LABEL:
{
Node child = node.getFirstChild();
node.removeChild(child);
String id = child.getString();
// check against duplicate labels...
for (int i=loops.size()-1; i >= 0; i--) {
Node n = (Node) loops.elementAt(i);
if (n.getType() == TokenStream.LABEL) {
String otherId = (String)n.getProp(Node.LABEL_PROP);
if (id.equals(otherId)) {
Object[] errArgs = { id };
String message = Context.getMessage("msg.dup.label",
errArgs);
reportMessage(cx, message, node, tree, true);
break typeswitch;
}
}
}
node.putProp(Node.LABEL_PROP, id);
/* Make a target and put it _after_ the following
* node. And in the LABEL node, so breaks get the
* right target.
*/
Node breakTarget = new Node(TokenStream.TARGET);
Node parent = iterator.getCurrentParent();
Node next = node.getNextSibling();
while (next != null &&
(next.getType() == TokenStream.LABEL ||
next.getType() == TokenStream.TARGET))
next = next.getNextSibling();
if (next == null)
break;
parent.addChildAfter(breakTarget, next);
node.putProp(Node.BREAK_PROP, breakTarget);
if (next.getType() == TokenStream.LOOP) {
node.putProp(Node.CONTINUE_PROP,
next.getProp(Node.CONTINUE_PROP));
}
loops.push(node);
loopEnds.push(breakTarget);
break;
}
case TokenStream.SWITCH:
{
Node breakTarget = new Node(TokenStream.TARGET);
Node parent = iterator.getCurrentParent();
parent.addChildAfter(breakTarget, node);
// make all children siblings except for selector
Node sib = node;
Node child = node.getFirstChild().next;
while (child != null) {
Node next = child.next;
node.removeChild(child);
parent.addChildAfter(child, sib);
sib = child;
child = next;
}
node.putProp(Node.BREAK_PROP, breakTarget);
loops.push(node);
loopEnds.push(breakTarget);
node.putProp(Node.CASES_PROP, new Vector(13));
break;
}
case TokenStream.DEFAULT:
case TokenStream.CASE:
{
Node sw = (Node) loops.peek();
if (type == TokenStream.CASE) {
Vector cases = (Vector) sw.getProp(Node.CASES_PROP);
cases.addElement(node);
} else {
sw.putProp(Node.DEFAULT_PROP, node);
}
break;
}
case TokenStream.NEWLOCAL : {
Integer localCount
= (Integer)(tree.getProp(Node.LOCALCOUNT_PROP));
if (localCount == null) {
tree.putProp(Node.LOCALCOUNT_PROP, new Integer(1));
}
else {
tree.putProp(Node.LOCALCOUNT_PROP,
new Integer(localCount.intValue() + 1));
}
}
break;
case TokenStream.LOOP:
loops.push(node);
loopEnds.push(node.getProp(Node.BREAK_PROP));
break;
case TokenStream.WITH:
{
if (inFunction) {
// With statements require an activation object.
((FunctionNode) tree).setRequiresActivation(true);
}
loops.push(node);
Node leave = node.getNextSibling();
if (leave.getType() != TokenStream.LEAVEWITH) {
throw new RuntimeException("Unexpected tree");
}
loopEnds.push(leave);
break;
}
case TokenStream.TRY:
{
Node finallytarget = (Node)node.getProp(Node.FINALLY_PROP);
if (finallytarget != null) {
hasFinally = true;
loops.push(node);
loopEnds.push(finallytarget);
}
Integer localCount
= (Integer)(tree.getProp(Node.LOCALCOUNT_PROP));
if (localCount == null) {
tree.putProp(Node.LOCALCOUNT_PROP, new Integer(1));
}
else {
tree.putProp(Node.LOCALCOUNT_PROP,
new Integer(localCount.intValue() + 1));
}
break;
}
case TokenStream.TARGET:
case TokenStream.LEAVEWITH:
if (!loopEnds.empty() && loopEnds.peek() == node) {
loopEnds.pop();
loops.pop();
}
break;
case TokenStream.RETURN:
{
/* If we didn't support try/finally, it wouldn't be
* necessary to put LEAVEWITH nodes here... but as
* we do need a series of JSR FINALLY nodes before
* each RETURN, we need to ensure that each finally
* block gets the correct scope... which could mean
* that some LEAVEWITH nodes are necessary.
*/
if (!hasFinally)
break; // skip the whole mess.
Node parent = iterator.getCurrentParent();
for (int i=loops.size()-1; i >= 0; i--) {
Node n = (Node) loops.elementAt(i);
int elemtype = n.getType();
if (elemtype == TokenStream.TRY) {
Node jsrnode = new Node(TokenStream.JSR);
Object jsrtarget = n.getProp(Node.FINALLY_PROP);
jsrnode.putProp(Node.TARGET_PROP, jsrtarget);
parent.addChildBefore(jsrnode, node);
} else if (elemtype == TokenStream.WITH) {
parent.addChildBefore(new Node(TokenStream.LEAVEWITH),
node);
}
}
break;
}
case TokenStream.BREAK:
case TokenStream.CONTINUE:
{
Node loop = null;
boolean labelled = node.hasChildren();
String id = null;
if (labelled) {
/* get the label */
Node child = node.getFirstChild();
id = child.getString();
node.removeChild(child);
}
int i;
Node parent = iterator.getCurrentParent();
for (i=loops.size()-1; i >= 0; i--) {
Node n = (Node) loops.elementAt(i);
int elemtype = n.getType();
if (elemtype == TokenStream.WITH) {
parent.addChildBefore(new Node(TokenStream.LEAVEWITH),
node);
} else if (elemtype == TokenStream.TRY) {
Node jsrFinally = new Node(TokenStream.JSR);
Object jsrTarget = n.getProp(Node.FINALLY_PROP);
jsrFinally.putProp(Node.TARGET_PROP, jsrTarget);
parent.addChildBefore(jsrFinally, node);
} else if (!labelled &&
(elemtype == TokenStream.LOOP ||
(elemtype == TokenStream.SWITCH &&
type == TokenStream.BREAK)))
{
/* if it's a simple break/continue, break from the
* nearest enclosing loop or switch
*/
loop = n;
break;
} else if (labelled &&
elemtype == TokenStream.LABEL &&
id.equals((String)n.getProp(Node.LABEL_PROP)))
{
loop = n;
break;
}
}
int propType = type == TokenStream.BREAK
? Node.BREAK_PROP
: Node.CONTINUE_PROP;
Node target = loop == null
? null
: (Node) loop.getProp(propType);
if (loop == null || target == null) {
String message;
if (!labelled) {
// didn't find an appropriate target
if (type == TokenStream.CONTINUE) {
message = Context.getMessage
("msg.continue.outside", null);
} else {
message = Context.getMessage
("msg.bad.break", null);
}
} else if (loop != null) {
message = Context.getMessage("msg.continue.nonloop",
null);
} else {
Object[] errArgs = { id };
message = Context.getMessage
("msg.undef.label", errArgs);
}
reportMessage(cx, message, node, tree, true);
node.setType(TokenStream.NOP);
break;
}
node.setType(TokenStream.GOTO);
node.putProp(Node.TARGET_PROP, target);
break;
}
case TokenStream.CALL:
if (isSpecialCallName(cx, tree, node))
node.putProp(Node.SPECIALCALL_PROP, Boolean.TRUE);
visitCall(node, tree);
break;
case TokenStream.NEW:
if (isSpecialCallName(cx, tree, node))
node.putProp(Node.SPECIALCALL_PROP, Boolean.TRUE);
visitNew(node, tree);
break;
case TokenStream.DOT:
{
Node right = node.getLastChild();
right.setType(TokenStream.STRING);
break;
}
case TokenStream.EXPRSTMT:
node.setType(inFunction ? TokenStream.POP : TokenStream.POPV);
break;
case TokenStream.OBJECT:
{
Vector regexps = (Vector) tree.getProp(Node.REGEXP_PROP);
if (regexps == null) {
regexps = new Vector(3);
tree.putProp(Node.REGEXP_PROP, regexps);
}
regexps.addElement(node);
Node n = new Node(TokenStream.OBJECT);
iterator.replaceCurrent(n);
n.putProp(Node.REGEXP_PROP, node);
break;
}
case TokenStream.VAR:
{
ShallowNodeIterator i = node.getChildIterator();
Node result = new Node(TokenStream.BLOCK);
while (i.hasMoreElements()) {
Node n = i.nextNode();
if (!n.hasChildren())
continue;
Node init = n.getFirstChild();
n.removeChild(init);
Node asn = (Node) irFactory.createAssignment(
TokenStream.NOP, n, init, null,
false);
Node pop = new Node(TokenStream.POP, asn, node.getDatum());
result.addChildToBack(pop);
}
iterator.replaceCurrent(result);
break;
}
case TokenStream.DELPROP:
case TokenStream.SETNAME:
{
if (!inFunction || inWithStatement())
break;
Node bind = node.getFirstChild();
if (bind == null || bind.getType() != TokenStream.BINDNAME)
break;
String name = bind.getString();
if (name.equals("arguments")) {
// use of "arguments" requires an activation object.
((FunctionNode) tree).setRequiresActivation(true);
}
VariableTable vars = getVariableTable(tree);
if (vars.get(name) != null) {
if (type == TokenStream.SETNAME) {
node.setType(TokenStream.SETVAR);
bind.setType(TokenStream.STRING);
} else {
// Local variables are by definition permanent
Node n = new Node(TokenStream.PRIMARY,
new Integer(TokenStream.FALSE));
iterator.replaceCurrent(n);
}
}
break;
}
case TokenStream.GETPROP:
if (inFunction) {
Node n = node.getFirstChild().getNextSibling();
String name = n == null ? "" : n.getString();
if (name.equals("arguments") ||
(name.equals("length") &&
cx.getLanguageVersion() == Context.VERSION_1_2))
{
// Use of "arguments" or "length" in 1.2 requires
// an activation object.
((FunctionNode) tree).setRequiresActivation(true);
}
}
break;
case TokenStream.NAME:
{
if (!inFunction || inWithStatement())
break;
String name = node.getString();
if (name.equals("arguments")) {
// Use of "arguments" requires a an activation object.
((FunctionNode) tree).setRequiresActivation(true);
}
VariableTable vars = getVariableTable(tree);
if (vars.get(name) != null) {
node.setType(TokenStream.GETVAR);
}
break;
}
}
}
return tree;
}
protected void addVariables(Node tree, VariableTable vars) {
// OPT: a whole pass to collect variables seems expensive.
// Could special case to go into statements only.
PreorderNodeIterator iterator = tree.getPreorderIterator();
Node node;
while ((node = iterator.nextNode()) != null) {
if (node.getType() != TokenStream.VAR)
continue;
ShallowNodeIterator i = node.getChildIterator();
while (i.hasMoreElements()) {
Node n = i.nextNode();
vars.addLocal(n.getString());
}
}
}
protected void addParameters(FunctionNode fnNode) {
VariableTable vars = fnNode.getVariableTable();
Node args = fnNode.getFirstChild();
if (args.getType() == TokenStream.LP && vars.getParameterCount() == 0)
{
// Add parameters
ShallowNodeIterator i = args.getChildIterator();
while (i.hasMoreElements()) {
Node n = i.nextNode();
String arg = n.getString();
vars.addParameter(arg);
}
}
}
protected void visitNew(Node node, Node tree) {
}
protected void visitCall(Node node, Node tree) {
/*
* For
* Call(GetProp(a, b), c, d) // or GetElem...
* we wish to evaluate as
* Call(GetProp(tmp=a, b), tmp, c, d)
*
* for
* Call(Name("a"), b, c)
* we wish to evaluate as
* Call(GetProp(tmp=GetBase("a"), "a"), tmp, b, c)
*
* and for
* Call(a, b, c);
* we wish to evaluate as
* Call(tmp=a, Parent(tmp), c, d)
*/
Node left = node.getFirstChild();
// count the arguments
int argCount = 0;
Node arg = left.getNextSibling();
while (arg != null) {
arg = arg.getNextSibling();
argCount++;
}
boolean addGetThis = false;
if (left.getType() == TokenStream.NAME) {
VariableTable vars = getVariableTable(tree);
String name = left.getString();
if (inFunction && vars.get(name) != null) {
// call to a var. Transform to Call(GetVar("a"), b, c)
left.setType(TokenStream.GETVAR);
// fall through to code to add GetParent
} else {
// transform to Call(GetProp(GetBase("a"), "a"), b, c)
node.removeChild(left);
left.setType(TokenStream.GETBASE);
Node str = left.cloneNode();
str.setType(TokenStream.STRING);
Node getProp = new Node(TokenStream.GETPROP, left, str);
node.addChildToFront(getProp);
left = getProp;
// Conditionally set a flag to add a GETTHIS node.
// The getThis entry in the runtime will take a
// Scriptable object intended to be used as a 'this'
// and make sure that it is neither a With object or
// an activation object.
// Executing getThis requires at least two instanceof
// tests, so we only include it if we are currently
// inside a 'with' statement, or if we are executing
// a script (to protect against an eval inside a with).
addGetThis = inWithStatement() || !inFunction;
// fall through to GETPROP code
}
}
if (left.getType() != TokenStream.GETPROP &&
left.getType() != TokenStream.GETELEM)
{
node.removeChild(left);
Node tmp = irFactory.createNewTemp(left);
Node use = irFactory.createUseTemp(tmp);
use.putProp(Node.TEMP_PROP, tmp);
Node parent = new Node(TokenStream.PARENT, use);
node.addChildToFront(parent);
node.addChildToFront(tmp);
return;
}
Node leftLeft = left.getFirstChild();
left.removeChild(leftLeft);
Node tmp = irFactory.createNewTemp(leftLeft);
left.addChildToFront(tmp);
Node use = irFactory.createUseTemp(tmp);
use.putProp(Node.TEMP_PROP, tmp);
if (addGetThis)
use = new Node(TokenStream.GETTHIS, use);
node.addChildAfter(use, left);
}
protected boolean inWithStatement() {
for (int i=loops.size()-1; i >= 0; i--) {
Node n = (Node) loops.elementAt(i);
if (n.getType() == TokenStream.WITH)
return true;
}
return false;
}
/**
* Return true if the node is a call to a function that requires
* access to the enclosing activation object.
*/
private boolean isSpecialCallName(Context cx, Node tree, Node node) {
Node left = node.getFirstChild();
String name = "";
if (left.getType() == TokenStream.NAME)
name = left.getString();
if (name.equals("eval") || name.equals("Closure") ||
name.equals("With"))
{
// Calls to these functions require activation objects.
if (inFunction)
((FunctionNode) tree).setRequiresActivation(true);
return true;
}
return false;
}
protected VariableTable createVariableTable() {
return new VariableTable();
}
protected VariableTable getVariableTable(Node tree) {
if (inFunction) {
return ((FunctionNode)tree).getVariableTable();
}
VariableTable result = (VariableTable)(tree.getProp(Node.VARS_PROP));
if (result == null) {
result = createVariableTable();
tree.putProp(Node.VARS_PROP, result);
}
return result;
}
protected void reportMessage(Context cx, String msg, Node stmt,
Node tree, boolean isError)
{
Object obj = stmt.getDatum();
int lineno = 0;
if (obj != null && obj instanceof Integer)
lineno = ((Integer) obj).intValue();
Object prop = tree == null
? null
: tree.getProp(Node.SOURCENAME_PROP);
if (isError)
cx.reportError(msg, (String) prop, lineno, null, 0);
else
cx.reportWarning(msg, (String) prop, lineno, null, 0);
}
protected Stack loops;
protected Stack loopEnds;
protected boolean inFunction;
protected IRFactory irFactory;
}

Просмотреть файл

@ -0,0 +1,35 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
/**
* Thrown if call is attempted on an object that is not a function.
*/
public class NotAFunctionException extends Exception {
public NotAFunctionException() {
}
public NotAFunctionException(String detail) {
super(detail);
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,74 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.util.Stack;
/**
* This class implements a preorder tree iterator for the Node class.
*
* @see Node
* @author Norris Boyd
*/
public class PreorderNodeIterator {
public PreorderNodeIterator(Node n) {
start = n;
stack = new Stack();
}
public Node currentNode() {
return current;
}
public Node getCurrentParent() {
return currentParent;
}
public Node nextNode() {
if (current == null)
return current = start;
if (current.first != null) {
stack.push(current);
currentParent = current;
current = current.first;
} else {
current = current.next;
boolean isEmpty;
for (;;) {
isEmpty = stack.isEmpty();
if (isEmpty || current != null)
break;
current = (Node) stack.pop();
current = current.next;
}
currentParent = isEmpty ? null : (Node) stack.peek();
}
return current;
}
public void replaceCurrent(Node newNode) {
currentParent.replaceChild(current, newNode);
current = newNode;
}
private Node start;
private Node current;
private Node currentParent;
private Stack stack;
}

Просмотреть файл

@ -0,0 +1,33 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
/**
* Thrown if errors are detected while attempting to define a property of
* a host object from a Java class or method, or if a property is not found.
*/
public class PropertyException extends Exception {
public PropertyException(String detail) {
super(detail);
}
}

Просмотреть файл

@ -0,0 +1,49 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* A proxy for the regexp package, so that the regexp package can be
* loaded optionally.
*
* @author Norris Boyd
*/
public interface RegExpProxy {
public Object executeRegExp(Object regExp, Scriptable scopeObj,
String str, int indexp[], boolean test);
public boolean isRegExp(Object obj);
public Object match(Context cx, Scriptable thisObj, Object[] args,
Function funObj)
throws JavaScriptException;
public Object search(Context cx, Scriptable thisObj, Object[] args,
Function funObj)
throws JavaScriptException;
public Object replace(Context cx, Scriptable thisObj, Object[] args,
Function funObj)
throws JavaScriptException;
public int find_split(Function funObj, String target, String separator,
Object re, int[] ip, int[] matchlen,
boolean[] matched, String[][] parensp);
}

Просмотреть файл

@ -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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
/**
* All compiled scripts implement this interface.
* <p>
* This class encapsulates script execution relative to an
* object scope.
* @since 1.3
* @author Norris Boyd
*/
public interface Script {
/**
* Execute the script.
* <p>
* The script is executed in a particular runtime Context, which
* must be associated with the current thread.
* The script is executed relative to a scope--definitions and
* uses of global top-level variables and functions will access
* properties of the scope object. For compliant ECMA
* programs, the scope must be an object that has been initialized
* as a global object using <code>Context.initStandardObjects</code>.
* <p>
*
* @param cx the Context associated with the current thread
* @param scope the scope to execute relative to
* @return the result of executing the script
* @see org.mozilla.javascript.Context#initStandardObjects
* @exception JavaScriptException if an uncaught JavaScript exception
* occurred while executing the script
*/
public Object exec(Context cx, Scriptable scope)
throws JavaScriptException;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,308 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
/**
* This is interface that all objects in JavaScript must implement.
* The interface provides for the management of properties and for
* performing conversions.
* <p>
* Host system implementors may find it easier to extend the ScriptableObject
* class rather than implementing Scriptable when writing host objects.
* <p>
* There are many convenience methods defined in FlattenedObject that make
* accessing objects easier.
* <p>
*
* @see org.mozilla.javascript.ScriptableObject
* @see org.mozilla.javascript.FlattenedObject
* @author Norris Boyd
* @author Nick Thompson
* @author Brendan Eich
*/
public interface Scriptable {
/**
* Get the name of the set of objects implemented by this Java class.
* This corresponds to the [[Class]] operation in ECMA and is used
* by Object.prototype.toString() in ECMA.<p>
* See ECMA 8.6.2 and 15.2.4.2.
*/
public String getClassName();
/**
* Value returned from <code>get</code> if the property is not
* found.
*/
public static final Object NOT_FOUND = new Object();
/**
* Get a named property from the object.
*
* Looks property up in this object and returns the associated value
* if found. Returns NOT_FOUND if not found.
* Note that this method is not expected to traverse the prototype
* chain. This is different from the ECMA [[Get]] operation.
*
* Depending on the property selector, the runtime will call
* this method or the form of <code>get</code> that takes an
* integer:
* <table>
* <tr><th>JavaScript code</th><th>Java code</th></tr>
* <tr><td>a.b </td><td>a.get("b", a)</td></tr>
* <tr><td>a["foo"] </td><td>a.get("foo", a)</td></tr>
* <tr><td>a[3] </td><td>a.get(3, a)</td></tr>
* <tr><td>a["3"] </td><td>a.get(3, a)</td></tr>
* <tr><td>a[3.0] </td><td>a.get(3, a)</td></tr>
* <tr><td>a["3.0"] </td><td>a.get("3.0", a)</td></tr>
* <tr><td>a[1.1] </td><td>a.get("1.1", a)</td></tr>
* <tr><td>a[-4] </td><td>a.get(-4, a)</td></tr>
* </table>
* <p>
* The values that may be returned are limited to the following:
* <UL>
* <LI>java.lang.Boolean objects</LI>
* <LI>java.lang.String objects</LI>
* <LI>java.lang.Number objects</LI>
* <LI>org.mozilla.javascript.Scriptable objects</LI>
* <LI>null</LI>
* <LI>The value returned by Context.getUndefinedValue()</LI>
* <LI>NOT_FOUND</LI>
* </UL>
* @param name the name of the property
* @param start the object in which the lookup began
* @return the value of the property (may be null), or NOT_FOUND
* @see org.mozilla.javascript.Context#getUndefinedValue
*/
public Object get(String name, Scriptable start);
/**
* Get a property from the object selected by an integral index.
*
* Identical to <code>get(String, Scriptable)</code> except that
* an integral index is used to select the property.
*
* @param index the numeric index for the property
* @param start the object in which the lookup began
* @return the value of the property (may be null), or NOT_FOUND
* @see org.mozilla.javascript.Scriptable#get(String,Scriptable)
*/
public Object get(int index, Scriptable start);
/**
* Indicates whether or not a named property is defined in an object.
*
* Does not traverse the prototype chain.<p>
*
* The property is specified by a String name
* as defined for the <code>get</code> method.<p>
*
* @param name the name of the property
* @param start the object in which the lookup began
* @return true if and only if the named property is found in the object
* @see org.mozilla.javascript.Scriptable#get
* @see org.mozilla.javascript.FlattenedObject#hasProperty
*/
public boolean has(String name, Scriptable start);
/**
* Indicates whether or not an indexed property is defined in an object.
*
* Does not traverse the prototype chain.<p>
*
* The property is specified by an integral index
* as defined for the <code>get</code> method.<p>
*
* @param index the numeric index for the property
* @param start the object in which the lookup began
* @return true if and only if the indexed property is found in the object
* @see org.mozilla.javascript.Scriptable#get
* @see org.mozilla.javascript.FlattenedObject#hasProperty
*/
public boolean has(int index, Scriptable start);
/**
* Sets a named property in this object.
* <p>
* The property is specified by a string name
* as defined for <code>get</code>.
* <p>
* The possible values that may be passed in are as defined for
* <code>get</code>. A class that implements this method may choose
* to ignore calls to set certain properties, in which case those
* properties are effectively read-only.<p>
* For a more convenient (and less efficient) form of this method,
* see <code>putProperty</code> in FlattenedObject. <p>
* Note that if a property <i>a</i> is defined in the prototype <i>p</i>
* of an object <i>o</i>, then evaluating <code>o.a = 23</code> will cause
* <code>set</code> to be called on the prototype <i>p</i> with
* <i>o</i> as the <i>start</i> parameter.
* To preserve JavaScript semantics, it is the Scriptable
* object's responsibility to modify <i>o</i>. <p>
* This design allows properties to be defined in prototypes and implemented
* in terms of getters and setters of Java values without consuming slots
* in each instance.<p>
* Note that <code>has</code> will be called by the runtime first before
* <code>set</code> is called to determine in which object the
* property is defined.
* Note that this method is not expected to traverse the prototype chain,
* which is different from the ECMA [[Put]] operation.
* @param name the name of the property
* @param start the object whose property is being set
* @param value value to set the property to
* @see org.mozilla.javascript.Scriptable#has
* @see org.mozilla.javascript.Scriptable#get
* @see org.mozilla.javascript.FlattenedObject#putProperty
*/
public void put(String name, Scriptable start, Object value);
/**
* Sets an indexed property in this object.
* <p>
* The property is specified by an integral index
* as defined for <code>get</code>.<p>
*
* Identical to <code>put(String, Scriptable, Object)</code> except that
* an integral index is used to select the property.
*
* @param index the numeric index for the property
* @param start the object whose property is being set
* @param value value to set the property to
* @see org.mozilla.javascript.Scriptable#has
* @see org.mozilla.javascript.Scriptable#get
* @see org.mozilla.javascript.Scriptable#put(String,Scriptable,Object)
* @see org.mozilla.javascript.FlattenedObject#putProperty
*/
public void put(int index, Scriptable start, Object value);
/**
* Removes a property from this object.
* This operation corresponds to the ECMA [[Delete]] except that
* the no result is returned. The runtime will guarantee that this
* method is called only if the property exists. After this method
* is called, the runtime will call Scriptable.has to see if the
* property has been removed in order to determine the boolean
* result of the delete operator as defined by ECMA 11.4.1.
* <p>
* A property can be made permanent by ignoring calls to remove
* it.<p>
* The property is specified by a String name
* as defined for <code>get</code>.
* <p>
* For a more convenient form of this method,
* see deleteProperty in FlattenedObject.
* @param name the identifier for the property
* @see org.mozilla.javascript.Scriptable#get
* @see org.mozilla.javascript.FlattenedObject#deleteProperty
*/
public void delete(String name);
/**
* Removes a property from this object.
*
* The property is specified by an integral index
* as defined for <code>get</code>.
* <p>
* For a more convenient form of this method,
* see deleteProperty in FlattenedObject.
*
* Identical to <code>delete(String)</code> except that
* an integral index is used to select the property.
*
* @param index the numeric index for the property
* @see org.mozilla.javascript.Scriptable#get
* @see org.mozilla.javascript.FlattenedObject#deleteProperty
*/
public void delete(int index);
/**
* Get the prototype of the object.
* @return the prototype
*/
public Scriptable getPrototype();
/**
* Set the prototype of the object.
* @param prototype the prototype to set
*/
public void setPrototype(Scriptable prototype);
/**
* Get the parent scope of the object.
* @return the parent scope
*/
public Scriptable getParentScope();
/**
* Set the parent scope of the object.
* @param parent the parent scope to set
*/
public void setParentScope(Scriptable parent);
/**
* Get an array of property ids.
*
* Not all property ids need be returned. Those properties
* whose ids are not returned are considered non-enumerable.
*
* @return an array of Objects. Each entry in the array is either
* a java.lang.String or a java.lang.Number
*/
public Object[] getIds();
/**
* Get the default value of the object with a given hint.
* The hints are String.class for type String, Number.class for type
* Number, Scriptable.class for type Object, and Boolean.class for
* type Boolean. <p>
*
* A <code>hint</code> of null means "no hint".
*
* See ECMA 8.6.2.6.
*
* @param hint the type hint
* @return the default value
*/
public Object getDefaultValue(Class hint);
/**
* The instanceof operator.
*
* <p>
* The JavaScript code "lhs instanceof rhs" causes rhs.hasInstance(lhs) to
* be called.
*
* <p>
* The return value is implementation dependent so that embedded host objects can
* return an appropriate value. See the JS 1.3 language documentation for more
* detail.
*
* <p>This operator corresponds to the proposed EMCA [[HasInstance]] operator.
*
* @param instance The value that appeared on the LHS of the instanceof
* operator
*
* @return an implementation dependent value
*/
public boolean hasInstance(Scriptable instance);
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,93 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
/**
* This class describes the support needed to implement security.
* <p>
* Three main pieces of functionality are required to implement
* security for JavaScript. First, it must be possible to define
* classes with an associated security context. (This security
* context may be any object that has meaning to an embedding;
* for a client-side JavaScript embedding this would typically
* be an origin URL and/or a digital certificate.) Next it
* must be possible to get the current class context so that
* the implementation can determine securely which class is
* requesting a privileged action. And finally, it must be
* possible to map a class back into a security context so that
* additional classes may be defined with that security context.
* <p>
* These three pieces of functionality are encapsulated in the
* SecuritySupport class.
*
* @see org.mozilla.javascript.Context
* @see java.lang.ClassLoader
* @since 1.4 Release 2
* @author Norris Boyd
*/
public interface SecuritySupport {
/**
* Define and load a Java class.
* <p>
* In embeddings that care about security, the securityDomain
* must be associated with the defined class such that a call to
* getsecurityDomain with that class will return this security
* context.
* <p>
* @param name the name of the class
* @param data the bytecode of the class
* @param securityDomain some object specifying the security
* context of the code that is defining this class.
* Embeddings that don't care about security may allow
* null here. This value propagated from the values passed
* into methods of Context that evaluate scripts.
* @see java.lang.ClassLoader#defineClass
*/
public Class defineClass(String name, byte[] data,
Object securityDomain);
/**
* Get the current class Context.
* <p>
* This functionality is supplied by SecurityManager.getClassContext,
* but only one SecurityManager may be instantiated in a single JVM
* at any one time. So implementations that care about security must
* provide access to this functionality through this interface.
* <p>
* Note that the 0th entry of the returned array should be the class
* of the caller of this method. So if this method is implemented by
* calling SecurityManager.getClassContext, this method must allocate
* a new, shorter array to return.
*/
public Class[] getClassContext();
/**
* Return the security context associated with the given class.
* <p>
* If <code>cl</code> is a class defined through a call to
* SecuritySupport.defineClass, then return the security
* context from that call. Otherwise return null.
* @param cl a class potentially defined by defineClass
* @return a security context object previously passed to defineClass
*/
public Object getSecurityDomain(Class cl);
}

Просмотреть файл

@ -0,0 +1,51 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.util.Enumeration;
/**
* This class implements a child iterator for the Node class.
*
* @see Node
* @author Norris Boyd
*/
class ShallowNodeIterator implements Enumeration {
public ShallowNodeIterator(Node n) {
current = n;
}
public boolean hasMoreElements() {
return current != null;
}
public Object nextElement() {
return nextNode();
}
public Node nextNode() {
Node result = current;
current = current.next;
return result;
}
private Node current;
}

Просмотреть файл

@ -0,0 +1,205 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// DEBUG API class
package org.mozilla.javascript;
/**
* This interface supports managing incrementally updated source text items.
* <p>
* Items have immutable names. They can be valid or invalid. They can
* accumulate text, but existing text can not be overwritten. They can be
* marked as 'complete', 'aborted', etc. They can be cleared of all text.
* See status flags for details.
*
* @see org.mozilla.javascript.SourceTextManager
* @author John Bandhauer
*/
public interface SourceTextItem
{
/**
* Possible status values...
*/
/**
* Item just created, no text added yet.
*/
public static final int INITED = 0;
/**
* Item has some text, likely that more will be added.
*/
public static final int PARTIAL = 1;
/**
* Item has all the text it is going to get.
*/
public static final int COMPLETED = 2;
/**
* User aborted loading of text, some text may be in item.
*/
public static final int ABORTED = 3;
/**
* Loading of text failed, some text may be in item.
*/
public static final int FAILED = 4;
/**
* Whatever text was in item has been cleared by a consumer.
*/
public static final int CLEARED = 5;
/**
* Item has be marked as invalid and has no useful information.
*/
public static final int INVALID = 6;
/**
* Append some text.
* <p>
* This only succeeds if status is INITED or PARTIAL.
*
* @param text String to append
* @return true if succeeded, false if failed
*/
public boolean append(String text);
/**
* Append a char.
* <p>
* This only succeeds if status is INITED or PARTIAL.
*
* @param c char to append
* @return true if succeeded, false if failed
*/
public boolean append(char c);
/**
* Append a char from a char[].
* <p>
* This only succeeds if status is INITED or PARTIAL.
*
* @param buf char[] from which to append
* @param offset offset into char[] from which to append
* @param count count of chars to append
* @return true if succeeded, false if failed
*/
public boolean append(char[] buf, int offset, int count);
/**
* Set status to COMPLETED.
* <p>
* meaning: all the text is there, it is complete, no problems.
* This only succeeds if status is INITED or PARTIAL.
*
* @return true if succeeded, false if failed
*/
public boolean complete();
/**
* Set status to ABORTED.
* <p>
* meaning: some text might be there, but user aborted text loading.
* This only succeeds if status is INITED or PARTIAL.
*
* @return true if succeeded, false if failed
*/
public boolean abort();
/**
* Set status to FAILED.
* <p>
* meaning: some text might be there, but loading failed.
* This only succeeds if status is INITED or PARTIAL.
*
* @return true if succeeded, false if failed
*/
public boolean fail();
/**
* Clear the text and set status to CLEARED.
* <p>
* meaning: consumer of the text has what he wants, leave this
* as an emptly placeholder.
* This succeeds unless status is INVALID.
*
* @return true if succeeded, false if failed
*/
public boolean clear();
/**
* Clear the text and set status to INVALID.
* <p>
* meaning: This item is not to be used, likely the SourceTextManager
* has been asked to create a new item (with potentially different
* text) in its place.
* This succeeds unless status is INVALID.
*
* @return true if succeeded, false if failed
*/
public boolean invalidate();
/**
* Get the Current Text.
*
* @return the text, null if INVALID
*/
public String getText();
/**
* Get the name.
*
* @return the name (immutable).
*/
public String getName();
/**
* Get the status.
*
* @return the current status
*/
public int getStatus();
/**
* Get the validity status.
*
* @return true if item is valid, false if not
*/
public boolean isValid();
/**
* Get a counter representing the modification count of the item.
* <p>
* Any consumer of the item may look at this value and store it at one
* point in time and then later look at the value again. If the
* value has increased, then the consumer can know that the item has
* been modified in some way and can then take the appropriate action.
* If the count has not changed from one point in time to another,
* then the item is guarenteed to not have changed in any way.
*
* NOTE: this value is not guaranteed to start at 0;
*
* @return the alter count
*/
public int getAlterCount();
}

Просмотреть файл

@ -0,0 +1,65 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// DEBUG API class
package org.mozilla.javascript;
import java.util.Enumeration;
/**
* This interface supports managing incrementally updated source text.
*
* @see org.mozilla.javascript.SourceTextItem
* @see org.mozilla.javascript.Context#setSourceTextManager
* @author John Bandhauer
*/
public interface SourceTextManager
{
/**
* Create a new item.
* <p>
* A new item is always created. If an item with this name already exists,
* then that preexisting iten is is set as invalid.
*
* @param name item name - in most embedings this will be a URL or filename
* @return new item
*/
public SourceTextItem newItem(String name);
/**
* Get an existing item.
* <p>
* If an item with this name already exists, then return it. Otherwise,
* return null.
*
* @param name item name - in most embedings this will be a URL or filename
* @return existing item (or null if none)
*/
public SourceTextItem getItem(String name);
/**
* Get all items.
* <p>
* Takes a snapshot of the list of all items and returns an Enumeration.
*
* @return snapshot Enumeration of all items
*/
public Enumeration getAllItems();
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,122 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This class implements the Undefined value in JavaScript.
*/
public class Undefined implements Scriptable {
static final public Scriptable instance = new Undefined();
public String getClassName() {
return "undefined";
}
public boolean has(String id, Scriptable start) {
return false;
}
public boolean has(int index, Scriptable start) {
return false;
}
public Object get(String id, Scriptable start) {
throw reportError();
}
public Object get(int index, Scriptable start) {
throw reportError();
}
public void put(String id,Scriptable start, Object value) {
throw reportError();
}
public void put(int index, Scriptable start, Object value) {
throw reportError();
}
public void delete(String id) {
throw reportError();
}
public void delete(int index) {
throw reportError();
}
public short getAttributes(String id, Scriptable start) {
throw reportError();
}
public short getAttributes(int index, Scriptable start) {
throw reportError();
}
public void setAttributes(String id, Scriptable start, short attributes) {
throw reportError();
}
public void setAttributes(int index, Scriptable start, short attributes) {
throw reportError();
}
public Scriptable getPrototype() {
throw reportError();
}
public void setPrototype(Scriptable prototype) {
throw reportError();
}
public Scriptable getParentScope() {
throw reportError();
}
public void setParentScope(Scriptable parent) {
throw reportError();
}
public Object[] getIds() {
throw reportError();
}
public Object getDefaultValue(Class cl) {
if (cl == ScriptRuntime.StringClass)
return "undefined";
if (cl == ScriptRuntime.NumberClass)
return ScriptRuntime.NaNobj;
if (cl == ScriptRuntime.BooleanClass)
return Boolean.FALSE;
return this;
}
public boolean hasInstance(Scriptable value) {
throw reportError();
}
public boolean instanceOf(Scriptable prototype) {
return false;
}
private RuntimeException reportError() {
String message = Context.getMessage("msg.undefined", null);
return Context.reportRuntimeError(message);
}
}

Просмотреть файл

@ -0,0 +1,124 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.io.*;
import java.util.*;
public class VariableTable {
public int size()
{
return itsVariables.size();
}
public int getParameterCount()
{
return varStart;
}
public LocalVariable createLocalVariable(String name, boolean isParameter)
{
return new LocalVariable(name, isParameter);
}
public LocalVariable get(int index)
{
return (LocalVariable)(itsVariables.elementAt(index));
}
public LocalVariable get(String name)
{
Integer vIndex = (Integer)(itsVariableNames.get(name));
if (vIndex != null)
return (LocalVariable)(itsVariables.elementAt(vIndex.intValue()));
else
return null;
}
public int getOrdinal(String name) {
Integer vIndex = (Integer)(itsVariableNames.get(name));
if (vIndex != null)
return vIndex.intValue();
else
return -1;
}
public String getName(int index)
{
return ((LocalVariable)(itsVariables.elementAt(index))).getName();
}
public void establishIndices()
{
for (int i = 0; i < itsVariables.size(); i++) {
LocalVariable lVar = (LocalVariable)(itsVariables.elementAt(i));
lVar.setIndex(i);
}
}
public void addParameter(String pName)
{
Integer pIndex = (Integer)(itsVariableNames.get(pName));
if (pIndex != null) {
LocalVariable p = (LocalVariable)
(itsVariables.elementAt(pIndex.intValue()));
if (p.isParameter()) {
Object[] errorArgs = { pName };
String message = Context.getMessage("msg.dup.parms", errorArgs);
Context.reportWarning(message, null, 0, null, 0);
}
else { // there's a local variable with this name, blow it off
itsVariables.removeElementAt(pIndex.intValue());
}
}
int curIndex = varStart++;
LocalVariable lVar = createLocalVariable(pName, true);
itsVariables.insertElementAt(lVar, curIndex);
itsVariableNames.put(pName, new Integer(curIndex));
}
public void addLocal(String vName)
{
Integer vIndex = (Integer)(itsVariableNames.get(vName));
if (vIndex != null) {
LocalVariable v = (LocalVariable)
(itsVariables.elementAt(vIndex.intValue()));
if (v.isParameter()) {
// this is o.k. the parameter subsumes the variable def.
}
else {
return;
}
}
int index = itsVariables.size();
LocalVariable lVar = createLocalVariable(vName, false);
itsVariables.addElement(lVar);
itsVariableNames.put(vName, new Integer(index));
}
// a list of the formal parameters and local variables
protected Vector itsVariables = new Vector();
// mapping from name to index in list
protected Hashtable itsVariableNames = new Hashtable(11);
protected int varStart; // index in list of first variable
}

Просмотреть файл

@ -0,0 +1,98 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.lang.reflect.InvocationTargetException;
/**
* A wrapper for runtime exceptions.
*
* Used by the JavaScript runtime to wrap and propagate exceptions that occur
* during runtime.
*
* @author Norris Boyd
*/
public class WrappedException extends EvaluatorException implements Wrapper {
/**
* Create a new exception wrapped around an existing exception.
*
* @param exception the exception to wrap
*/
public WrappedException(Throwable exception) {
super(exception.getMessage());
this.exception = exception.fillInStackTrace();
}
/**
* Get the message for the exception.
*
* Delegates to the wrapped exception.
*/
public String getMessage() {
return "WrappedException of " + exception.toString();
}
/**
* Gets the localized message.
*
* Delegates to the wrapped exception.
*/
public String getLocalizedMessage() {
return "WrappedException of " + exception.getLocalizedMessage();
}
/**
* Get the wrapped exception.
*
* @return the exception that was presented as a argument to the
* constructor when this object was created
*/
public Throwable getWrappedException() {
return exception;
}
/**
* Get the wrapped exception.
*
* @return the exception that was presented as a argument to the
* constructor when this object was created
*/
public Object unwrap() {
return exception;
}
/**
* Wrap an exception.
*
* Provides special cases for EvaluatorExceptions (which are returned
* as-is), and InvocationTargetExceptions (which are unwrapped and
* passed to a recursive call to wrapException).<p>
*
* Otherwise the exception is simply wrapped in a WrappedException.
*/
public static EvaluatorException wrapException(Throwable e) {
if ((e instanceof InvocationTargetException))
e = ((InvocationTargetException) e).getTargetException();
if (e instanceof EvaluatorException)
return (EvaluatorException) e;
return new WrappedException(e);
}
private Throwable exception;
}

Просмотреть файл

@ -0,0 +1,28 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* Objects that can wrap other values for reflection in the JS environment.
*/
public interface Wrapper {
public Object unwrap();
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,174 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript.regexp;
import org.mozilla.javascript.*;
import java.lang.reflect.Method;
/**
* This class implements the RegExp constructor native object.
*
* Revision History:
* Implementation in C by Brendan Eich
* Initial port to Java by Norris Boyd from jsregexp.c version 1.36
* Merged up to version 1.38, which included Unicode support.
* Merged bug fixes in version 1.39.
* Merged JSFUN13_BRANCH changes up to 1.32.2.11
*
* @author Brendan Eich
* @author Norris Boyd
*/
public class NativeRegExpCtor extends NativeFunction {
public static Scriptable init(Scriptable scope)
throws PropertyException
{
NativeRegExpCtor ctor = new NativeRegExpCtor();
String[] names = { "RegExp" };
ctor.names = names;
ctor.setPrototype(getClassPrototype(scope, "Function"));
ctor.setParentScope(scope);
String[] propNames = { "multiline", "input", "lastMatch",
"lastParen", "leftContext", "rightContext" };
String[] aliases = { "$*", "$_", "$&",
"$+", "$`", "$'" };
for (int i=0; i < propNames.length; i++)
ctor.defineProperty(propNames[i], NativeRegExpCtor.class,
ScriptableObject.DONTENUM);
for (int i=0; i < aliases.length; i++) {
StringBuffer buf = new StringBuffer("get");
buf.append(propNames[i]);
buf.setCharAt(3, Character.toUpperCase(propNames[i].charAt(0)));
Method[] getter = FunctionObject.findMethods(
NativeRegExpCtor.class,
buf.toString());
buf.setCharAt(0, 's');
Method[] setter = FunctionObject.findMethods(
NativeRegExpCtor.class,
buf.toString());
Method m = setter == null ? null : setter[0];
ctor.defineProperty(aliases[i], null, getter[0], m,
ScriptableObject.DONTENUM);
}
// We know that scope is a Scriptable object since we
// constrained the type on initStandardObjects.
ScriptableObject global = (ScriptableObject) scope;
global.defineProperty("RegExp", ctor, ScriptableObject.DONTENUM);
return ctor;
}
public String getClassName() {
return "Function";
}
private int getDollarNumber(String s) {
// assumes s starts with '$'
if (s.length() != 2)
return 0;
char c = s.charAt(1);
if (c < '0' || '9' < c)
return 0;
return c - '0';
}
public boolean has(String id, Scriptable start) {
if (id != null && id.length() > 1 && id.charAt(0) == '$') {
if (getDollarNumber(id) != 0)
return true;
}
return super.has(id, start);
}
public Object get(String id, Scriptable start) {
if (id.length() > 1 && id.charAt(0) == '$') {
int dollar = getDollarNumber(id);
if (dollar != 0) {
dollar--;
RegExpImpl res = getImpl();
return res.getParenSubString(dollar).toString();
}
}
return super.get(id, start);
}
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
{
return construct(cx, parent, args);
}
public Scriptable construct(Context cx, Scriptable scope, Object[] args) {
NativeRegExp re = new NativeRegExp();
NativeRegExp.compile(cx, re, args, this);
re.setPrototype(getClassPrototype(scope, "RegExp"));
re.setParentScope(getParentScope());
return re;
}
public static boolean getMultiline(ScriptableObject obj) {
return getImpl().multiline;
}
public static void setMultiline(ScriptableObject obj, boolean b) {
getImpl().multiline = b;
}
public static String getInput(ScriptableObject obj) {
String s = getImpl().input;
return s == null ? "" : s;
}
public static void setInput(ScriptableObject obj, String s) {
getImpl().input = s;
}
public static String getLastMatch(ScriptableObject obj) {
SubString ss = getImpl().lastMatch;
return ss == null ? "" : ss.toString();
}
public static String getLastParen(ScriptableObject obj) {
SubString ss = getImpl().lastParen;
return ss == null ? "" : ss.toString();
}
public static String getLeftContext(ScriptableObject obj) {
SubString ss = getImpl().leftContext;
return ss == null ? "" : ss.toString();
}
public static String getRightContext(ScriptableObject obj) {
SubString ss = getImpl().rightContext;
return ss == null ? "" : ss.toString();
}
static RegExpImpl getImpl() {
Context cx = Context.getCurrentContext();
return (RegExpImpl) ScriptRuntime.getRegExpProxy(cx);
}
}

Просмотреть файл

@ -0,0 +1,524 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript.regexp;
import org.mozilla.javascript.*;
import java.util.Vector;
/**
*
*/
public class RegExpImpl implements RegExpProxy {
public RegExpImpl() {
parens = new Vector(9);
}
public boolean isRegExp(Object obj) {
return obj instanceof NativeRegExp;
}
public Object executeRegExp(Object regExp, Scriptable scopeObj,
String str, int indexp[], boolean test)
{
if (regExp instanceof NativeRegExp)
return ((NativeRegExp) regExp).executeRegExp(scopeObj, str,
indexp, test);
return null;
}
public Object match(Context cx, Scriptable thisObj, Object[] args,
Function funObj)
throws JavaScriptException
{
MatchData mdata = new MatchData();
mdata.optarg = 1;
mdata.mode = GlobData.GLOB_MATCH;
mdata.parent = ScriptableObject.getTopLevelScope(funObj);
Object rval = matchOrReplace(cx, thisObj, args, funObj, mdata);
return mdata.arrayobj == null ? rval : mdata.arrayobj;
}
public Object search(Context cx, Scriptable thisObj, Object[] args,
Function funObj)
throws JavaScriptException
{
MatchData mdata = new MatchData();
mdata.optarg = 1;
mdata.mode = GlobData.GLOB_SEARCH;
mdata.parent = ScriptableObject.getTopLevelScope(funObj);
return matchOrReplace(cx, thisObj, args, funObj, mdata);
}
public Object replace(Context cx, Scriptable thisObj, Object[] args,
Function funObj)
throws JavaScriptException
{
Object arg1 = args.length < 2 ? Undefined.instance : args[1];
String repstr = null;
Function lambda = null;
if (arg1 instanceof Function) {
lambda = (Function) arg1;
} else {
repstr = ScriptRuntime.toString(arg1);
}
ReplaceData rdata = new ReplaceData();
rdata.optarg = 2;
rdata.mode = GlobData.GLOB_REPLACE;
rdata.lambda = lambda;
rdata.repstr = repstr == null ? null : repstr.toCharArray();
rdata.dollar = repstr == null ? -1 : repstr.indexOf('$');
rdata.charArray = null;
rdata.length = 0;
rdata.index = 0;
rdata.leftIndex = 0;
Object val = matchOrReplace(cx, thisObj, args, funObj, rdata);
char[] charArray;
if (rdata.charArray == null) {
if (rdata.global || val == null || !val.equals(Boolean.TRUE)) {
/* Didn't match even once. */
return rdata.str;
}
int leftlen = this.leftContext.length;
int length = leftlen + rdata.findReplen(this);
charArray = new char[length];
SubString leftContext = this.leftContext;
System.arraycopy(leftContext.charArray, leftContext.index,
charArray, 0, leftlen);
rdata.doReplace(this, charArray, leftlen);
rdata.charArray = charArray;
rdata.length = length;
}
SubString rc = this.rightContext;
int rightlen = rc.length;
int length = rdata.length + rightlen;
charArray = new char[length];
System.arraycopy(rdata.charArray, 0,
charArray, 0, rdata.charArray.length);
System.arraycopy(rc.charArray, rc.index, charArray,
rdata.length, rightlen);
return new String(charArray, 0, length);
}
/**
* Analog of C match_or_replace.
*/
private static Object matchOrReplace(Context cx, Scriptable thisObj,
Object[] args, Function funObj,
GlobData data)
throws JavaScriptException
{
NativeRegExp re;
String str = ScriptRuntime.toString(thisObj);
data.str = str;
RegExpImpl reImpl = RegExpImpl.getRegExpImpl(cx);
if (args[0] instanceof NativeRegExp) {
re = (NativeRegExp) args[0];
} else {
String src = ScriptRuntime.toString(args[0]);
String opt;
if (data.optarg < args.length) {
args[0] = src;
opt = ScriptRuntime.toString(args[data.optarg]);
} else {
opt = null;
}
Scriptable scope = ScriptableObject.getTopLevelScope(funObj);
re = new NativeRegExp(scope, src, opt);
}
data.regexp = re;
data.global = (re.getFlags() & NativeRegExp.GLOB) != 0;
int[] indexp = { 0 };
Object result = null;
if (data.mode == GlobData.GLOB_SEARCH) {
result = re.executeRegExp(funObj, str, indexp, true);
if (result != null && result.equals(Boolean.TRUE))
result = new Integer(reImpl.leftContext.length);
else
result = new Integer(-1);
} else if (data.global) {
re.setLastIndex(0);
for (int count = 0; indexp[0] <= str.length(); count++) {
result = re.executeRegExp(funObj, str, indexp, true);
if (result == null || !result.equals(Boolean.TRUE))
break;
data.doGlobal(funObj, count);
if (reImpl.lastMatch.length == 0) {
if (indexp[0] == str.length())
break;
indexp[0]++;
}
}
} else {
result = re.executeRegExp(funObj, str, indexp,
data.mode == GlobData.GLOB_REPLACE);
}
return result;
}
public int find_split(Function funObj, String target, String separator,
Object reObj, int[] ip, int[] matchlen,
boolean[] matched, String[][] parensp)
{
int i = ip[0];
int length = target.length();
int result;
Context cx = Context.getCurrentContext();
int version = cx.getLanguageVersion();
NativeRegExp re = (NativeRegExp) reObj;
again:
while (true) { // imitating C label
/* JS1.2 deviated from Perl by never matching at end of string. */
int ipsave = ip[0]; // reuse ip to save object creation
ip[0] = i;
if (re.executeRegExp(funObj, target, ip, true) != Boolean.TRUE)
{
// Mismatch: ensure our caller advances i past end of string.
ip[0] = ipsave;
matchlen[0] = 1;
matched[0] = false;
return length;
}
i = ip[0];
ip[0] = ipsave;
matched[0] = true;
SubString sep = this.lastMatch;
matchlen[0] = sep.length;
if (matchlen[0] == 0) {
/*
* Empty string match: never split on an empty
* match at the start of a find_split cycle. Same
* rule as for an empty global match in
* match_or_replace.
*/
if (i == ip[0]) {
/*
* "Bump-along" to avoid sticking at an empty
* match, but don't bump past end of string --
* our caller must do that by adding
* sep->length to our return value.
*/
if (i == length) {
if (version == Context.VERSION_1_2) {
matchlen[0] = 1;
result = i;
}
else
result = -1;
break;
}
i++;
continue again; // imitating C goto
}
}
// PR_ASSERT((size_t)i >= sep->length);
result = i - matchlen[0];
break;
}
int size = parens.size();
parensp[0] = new String[size];
for (int num = 0; num < size; num++) {
SubString parsub = getParenSubString(num);
parensp[0][num] = parsub.toString();
}
return result;
}
static RegExpImpl getRegExpImpl(Context cx) {
return (RegExpImpl) ScriptRuntime.getRegExpProxy(cx);
}
/**
* Analog of REGEXP_PAREN_SUBSTRING in C jsregexp.h.
* Assumes zero-based; i.e., for $3, i==2
*/
SubString getParenSubString(int i) {
if (i >= parens.size())
return SubString.emptySubString;
return (SubString) parens.elementAt(i);
}
String input; /* input string to match (perl $_, GC root) */
boolean multiline; /* whether input contains newlines (perl $*) */
Vector parens; /* Vector of SubString; last set of parens
matched (perl $1, $2) */
SubString lastMatch; /* last string matched (perl $&) */
SubString lastParen; /* last paren matched (perl $+) */
SubString leftContext; /* input to left of last match (perl $`) */
SubString rightContext; /* input to right of last match (perl $') */
}
abstract class GlobData {
static final int GLOB_MATCH = 1;
static final int GLOB_REPLACE = 2;
static final int GLOB_SEARCH = 3;
abstract void doGlobal(Function funObj, int count)
throws JavaScriptException;
byte mode; /* input: return index, match object, or void */
int optarg; /* input: index of optional flags argument */
boolean global; /* output: whether regexp was global */
String str; /* output: 'this' parameter object as string */
NativeRegExp regexp;/* output: regexp parameter object private data */
Scriptable parent;
}
class MatchData extends GlobData {
/*
* Analog of match_glob() in jsstr.c
*/
void doGlobal(Function funObj, int count) throws JavaScriptException {
MatchData mdata;
Object v;
mdata = this;
Context cx = Context.getCurrentContext();
RegExpImpl reImpl = RegExpImpl.getRegExpImpl(cx);
if (arrayobj == null) {
Scriptable s = ScriptableObject.getTopLevelScope(funObj);
arrayobj = ScriptRuntime.newObject(cx, s, "Array", null);
}
SubString matchsub = reImpl.lastMatch;
String matchstr = matchsub.toString();
arrayobj.put(count, arrayobj, matchstr);
}
Scriptable arrayobj;
}
class ReplaceData extends GlobData {
ReplaceData() {
dollar = -1;
}
/*
* Analog of replace_glob() in jsstr.c
*/
void doGlobal(Function funObj, int count)
throws JavaScriptException
{
ReplaceData rdata = this;
Context cx = Context.getCurrentContext();
RegExpImpl reImpl = RegExpImpl.getRegExpImpl(cx);
SubString lc = reImpl.leftContext;
char[] leftArray = lc.charArray;
int leftIndex = rdata.leftIndex;
int leftlen = reImpl.lastMatch.index - leftIndex;
rdata.leftIndex = reImpl.lastMatch.index + reImpl.lastMatch.length;
int replen = findReplen(reImpl);
int growth = leftlen + replen;
char[] charArray;
if (rdata.charArray != null) {
charArray = new char[rdata.length + growth];
System.arraycopy(rdata.charArray, 0, charArray, 0, rdata.length);
} else {
charArray = new char[growth];
}
rdata.charArray = charArray;
rdata.length += growth;
int index = rdata.index;
rdata.index += growth;
System.arraycopy(leftArray, leftIndex, charArray, index, leftlen);
index += leftlen;
doReplace(reImpl, charArray, index);
}
static SubString interpretDollar(RegExpImpl res, char[] da, int dp,
int bp, int[] skip)
{
char[] ca;
int cp;
char dc;
int num, tmp;
/* Allow a real backslash (literal "\\") to escape "$1" etc. */
if (da[dp] != '$')
throw new RuntimeException();
if (dp > bp && da[dp-1] == '\\')
return null;
/* Interpret all Perl match-induced dollar variables. */
dc = da[dp+1];
if (NativeRegExp.isDigit(dc)) {
if (dc == '0')
return null;
/* Check for overflow to avoid gobbling arbitrary decimal digits. */
num = 0;
ca = da;
cp = dp;
while (++cp < ca.length && NativeRegExp.isDigit(dc = ca[cp])) {
tmp = 10 * num + NativeRegExp.unDigit(dc);
if (tmp < num)
break;
num = tmp;
}
/* Adjust num from 1 $n-origin to 0 array-index-origin. */
num--;
skip[0] = cp - dp;
return res.getParenSubString(num);
}
skip[0] = 2;
switch (dc) {
case '&':
return res.lastMatch;
case '+':
return res.lastParen;
case '`':
Context cx = Context.getCurrentContext();
if (cx.getLanguageVersion() == Context.VERSION_1_2) {
/*
* JS1.2 imitated the Perl4 bug where left context at each step
* in an iterative use of a global regexp started from last match,
* not from the start of the target string. But Perl4 does start
* $` at the beginning of the target string when it is used in a
* substitution, so we emulate that special case here.
*/
res.leftContext.index = 0;
res.leftContext.length = res.lastMatch.index;
}
return res.leftContext;
case '\'':
return res.rightContext;
}
return null;
}
/**
* Corresponds to find_replen in jsstr.c. rdata is 'this', and
* the result parameter sizep is the return value (errors are
* propagated with exceptions).
*/
int findReplen(RegExpImpl reImpl)
throws JavaScriptException
{
if (lambda != null) {
// invoke lambda function with args lastMatch, $1, $2, ... $n,
// leftContext.length, whole string.
Context cx = Context.getCurrentContext();
Vector parens = reImpl.parens;
int parenCount = parens.size();
Object[] args = new Object[parenCount + 3];
args[0] = reImpl.lastMatch.toString();
for (int i=0; i < parenCount; i++) {
SubString sub = (SubString) parens.elementAt(i);
args[i+1] = sub.toString();
}
args[parenCount+1] = new Integer(reImpl.leftContext.length);
args[parenCount+2] = str;
Scriptable parent = lambda.getParentScope();
Object result = lambda.call(cx, parent, parent, args);
this.repstr = ScriptRuntime.toString(result).toCharArray();
return this.repstr.length;
}
int replen = this.repstr.length;
if (dollar == -1)
return replen;
int bp = 0;
for (int dp = dollar; dp < this.repstr.length ; dp++) {
char c = this.repstr[dp];
if (c != '$')
continue;
int[] skip = { 0 };
SubString sub = interpretDollar(reImpl, this.repstr, dp,
bp, skip);
if (sub != null)
replen += sub.length - skip[0];
}
return replen;
}
/**
* Analog of do_replace in jsstr.c
*/
void doReplace(RegExpImpl regExpImpl, char[] charArray,
int arrayIndex)
{
int cp = 0;
char[] da = repstr;
int dp = this.dollar;
int bp = cp;
if (dp != -1) {
outer:
for (;;) {
int len = dp - cp;
System.arraycopy(repstr, cp, charArray, arrayIndex,
len);
arrayIndex += len;
cp = dp;
int[] skip = { 0 };
SubString sub = interpretDollar(regExpImpl, da,
dp, bp, skip);
if (sub != null) {
len = sub.length;
if (len > 0) {
System.arraycopy(sub.charArray, sub.index, charArray,
arrayIndex, len);
}
arrayIndex += len;
cp += skip[0];
}
dp++;
do {
if (dp >= charArray.length)
break outer;
} while (charArray[dp++] != '$');
}
}
if (repstr.length > cp) {
System.arraycopy(repstr, cp, charArray, arrayIndex,
repstr.length - cp);
}
}
Function lambda; /* replacement function object or null */
char[] repstr; /* replacement string */
int dollar; /* -1 or index of first $ in repstr */
char[] charArray; /* result characters, null initially */
int length; /* result length, 0 initially */
int index; /* index in result of next replacement */
int leftIndex; /* leftContext index, always 0 for JS1.2 */
}

Просмотреть файл

@ -0,0 +1,35 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript.regexp;
class SubString {
public String toString() {
return charArray == null
? ""
: new String(charArray, index, length);
}
static final SubString emptySubString = new SubString();
char[] charArray;
int index;
int length;
}

Просмотреть файл

@ -0,0 +1,458 @@
#
# Default JavaScript messages file.
#
# Copyright © 1998 Netscape Communications Corporation, All Rights Reserved.
#
#
# 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
# com.netscape.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 =\
Variable arguments signature must be \
(Context cx, Object[] args, Function ctorObj, boolean inNewExpr) \
to define a constructor.
msg.varargs.fun =\
Variable arguments signature must be \
(Context cx, Scriptable thisObj, Object[] args, Function funObj) \
to define a 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.del.nonref =\
Only variables and properties may be deleted.
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.
# NativeClosure
msg.closure.proto =\
Closure.__proto__ must be a function
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}
# 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.
# NativeRegExp
msg.bad.quant =\
Invalid quantifier {0}
msg.overlarge.max =\
Overly large maximum {0}
msg.overlarge.octal =\
Overly large octal escape {0}
msg.zero.quant =\
Zero quantifier {0}
msg.max.lt.min =\
Maximum {0} less than minimum
msg.re.empty =\
Regular expression before {0} could be empty.
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.
# 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.fn.retval =\
function does not always return a value
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.scanner.caught.error =\
scanner caught an error
msg.no.paren.catch =\
missing ( before catch-block condition
msg.bad.catchcond =\
invalid catch block condition
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.in.not.object = \
Can''t use the in operator on a non-object.
msg.instanceof.bad.prototype = \
''prototype'' property of {0} is not an object.
# 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.nested.comment =\
nested comment
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
# TokensStream warnings
msg.bad.octal.literal =\
illegal octal literal digit {0}; interpreting it as a decimal digit
# 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}".
java.construmsg.ctor.not.found =\
No constructor for {0} matching arguments ({1}).
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}".

Просмотреть файл

@ -0,0 +1 @@
security.requireSecurityDomain = false

Просмотреть файл

@ -0,0 +1,153 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript.tools;
import org.mozilla.javascript.*;
import java.text.MessageFormat;
import java.io.*;
import java.util.*;
/**
* Error reporter for tools.
*
* Currently used by both the shell and the compiler.
*/
public class ToolErrorReporter implements ErrorReporter {
public ToolErrorReporter(boolean reportWarnings) {
this.reportWarnings = reportWarnings;
}
/**
* Look up the message corresponding to messageId in the
* org.mozilla.javascript.tools.shell.resources.Messages property file.
* For internationalization support.
*/
public static String getMessage(String messageId) {
return getMessage(messageId, (Object []) null);
}
public static String getMessage(String messageId, String argument) {
Object[] args = { argument };
return getMessage(messageId, args);
}
public static String getMessage(String messageId, Object[] args) {
Context cx = Context.getCurrentContext();
Locale locale = cx == null ? Locale.getDefault() : cx.getLocale();
// ResourceBundle does cacheing.
ResourceBundle rb = ResourceBundle.getBundle
("org.mozilla.javascript.tools.resources.Messages", locale);
String formatString;
try {
formatString = rb.getString(messageId);
} catch (java.util.MissingResourceException mre) {
throw new RuntimeException("no message resource found for message property "
+ messageId);
}
if (args == null) {
return formatString;
} else {
MessageFormat formatter = new MessageFormat(formatString);
return formatter.format(args);
}
}
public void warning(String message, String sourceName, int line,
String lineSource, int lineOffset)
{
if (!reportWarnings)
return;
Object[] errArgs = { formatMessage(message, sourceName, line) };
message = getMessage("msg.warning", errArgs);
System.err.println(messagePrefix + message);
if (null != lineSource) {
System.err.println(messagePrefix + lineSource);
System.err.println(messagePrefix + buildIndicator(lineOffset));
}
}
public void error(String message, String sourceName, int line,
String lineSource, int lineOffset)
{
hasReportedErrorFlag = true;
message = formatMessage(message, sourceName, line);
System.err.println(messagePrefix + message);
if (null != lineSource) {
System.err.println(messagePrefix + lineSource);
System.err.println(messagePrefix + buildIndicator(lineOffset));
}
}
public EvaluatorException runtimeError(String message, String sourceName,
int line, String lineSource,
int lineOffset)
{
hasReportedErrorFlag = true;
message = formatMessage(message, sourceName, line);
System.err.println(messagePrefix + message);
if (null != lineSource) {
System.err.println(messagePrefix + lineSource);
System.err.println(messagePrefix + buildIndicator(lineOffset));
}
return new EvaluatorException(message);
}
public boolean hasReportedError() {
return hasReportedErrorFlag;
}
public boolean isReportingWarnings() {
return this.reportWarnings;
}
public void setIsReportingWarnings(boolean reportWarnings) {
this.reportWarnings = reportWarnings;
}
private String formatMessage(String message, String sourceName, int line) {
if (line > 0) {
if (sourceName != null) {
Object[] errArgs = { sourceName, new Integer(line), message };
return getMessage("msg.format3", errArgs);
} else {
Object[] errArgs = { new Integer(line), message };
return getMessage("msg.format2", errArgs);
}
} else {
Object[] errArgs = { message };
return getMessage("msg.format1", errArgs);
}
}
private String buildIndicator(int offset){
StringBuffer sb = new StringBuffer();
for (int i = 0; i < offset-1; i++)
sb.append(".");
sb.append("^");
return sb.toString();
}
private final String messagePrefix = "js: ";
private boolean hasReportedErrorFlag;
private boolean reportWarnings;
}

Просмотреть файл

@ -0,0 +1,127 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript.tools.shell;
import java.io.*;
import org.mozilla.javascript.*;
public class DebugReader extends BufferedReader {
private BufferedReader reader;
private SourceTextManager stm;
private SourceTextItem sti;
public DebugReader(Reader reader, SourceTextManager stm, String name) {
super(null);
this.reader = new BufferedReader(reader);
this.stm = stm;
this.sti = stm.newItem(name);
}
public int read() throws IOException {
int c = reader.read();
if(null != sti) {
if(-1 == c) {
sti.complete();
sti = null;
}
else
sti.append((char)c);
}
return c;
}
public int read(char cbuf[]) throws IOException {
int i = reader.read(cbuf);
if(null != sti) {
if(-1 == i) {
sti.complete();
sti = null;
}
else if(0 != i) {
sti.append(cbuf, 0, i);
}
}
return i;
}
public int read(char cbuf[], int off, int len) throws IOException {
int i = reader.read(cbuf, off, len);
if(null != sti) {
if(-1 == i) {
sti.complete();
sti = null;
}
else if(0 != i) {
sti.append(cbuf, off, i);
}
}
return i;
}
public String readLine() throws IOException {
String s = reader.readLine();
if(null != sti) {
if(null == s) {
sti.complete();
sti = null;
}
else {
sti.append(s+"\n");
}
}
return s;
}
public long skip(long n) throws IOException {
return reader.skip(n);
}
public boolean ready() throws IOException {
return reader.ready();
}
public boolean markSupported() {
return reader.markSupported();
}
public void mark(int readAheadLimit) throws IOException {
reader.mark(readAheadLimit);
}
public void reset() throws IOException {
reader.reset();
}
public void close() throws IOException {
reader.close();
if(null != sti) {
sti.complete();
sti = null;
}
}
protected void finalize() throws Throwable {
if(null != sti) {
sti.complete();
sti = null;
}
reader = null;
}
}

Просмотреть файл

@ -0,0 +1,614 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript.tools.shell;
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
import org.mozilla.javascript.*;
import java.text.MessageFormat;
import org.mozilla.javascript.tools.ToolErrorReporter;
/*
TODO: integrate debugger; make DebugProxy class so that debugger is
not required to run the shell.
import org.mozilla.javascript.debug.ILaunchableDebugger;
import org.mozilla.javascript.debug.DebugManager;
import org.mozilla.javascript.debug.SourceTextManagerImpl;
*/
/**
* The shell program.
*
* Can execute scripts interactively or in batch mode at the command line.
* An example of controlling the JavaScript engine.
*
* @author Norris Boyd
*/
public class Main extends ScriptableObject {
/**
* Main entry point.
*
* Process arguments as would a normal Java program. Also
* create a new Context and associate it with the current thread.
* Then set up the execution environment and begin to
* execute scripts.
*/
public static void main(String args[]) {
Context cx = Context.enter();
errorReporter = new ToolErrorReporter(false);
cx.setErrorReporter(errorReporter);
// A bit of shorthand: since Main extends ScriptableObject,
// we can make it the global object.
// We create a shared global with sealed properties that
// we can share with other threads (see spawn).
sharedGlobal = new Main();
// Initialize the standard objects (Object, Function, etc.)
// This must be done before scripts can be executed.
cx.initStandardObjects(sharedGlobal, true);
// Define some global functions particular to the shell. Note
// that these functions are not part of ECMA.
String[] names = { "print", "quit", "version", "load", "help",
"loadClass", "defineClass", "spawn" };
try {
sharedGlobal.defineFunctionProperties(names, Main.class,
ScriptableObject.DONTENUM);
} catch (PropertyException e) {
throw new Error(e.getMessage());
}
// Create the "global" object where top-level variables will live.
// Set its prototype to the sharedGlobal where all the standard
// functions and objects live.
global = new Main();
global.setPrototype(sharedGlobal);
args = processOptions(cx, args);
// Set up "arguments" in the global scope to contain the command
// line arguments after the name of the script to execute
Object[] array = args;
if (args.length > 0) {
int length = args.length - 1;
array = new Object[length];
System.arraycopy(args, 1, array, 0, length);
}
Scriptable argsObj = cx.newArray(global, array);
global.defineProperty("arguments", argsObj,
ScriptableObject.DONTENUM);
/*
TODO: enable debugger
if (global.debug) {
global.debug_dm = new DebugManager();
global.debug_stm = new SourceTextManagerImpl();
global.debug_dm.setSourceTextManager(global.debug_stm);
cx.setSourceTextManager(global.debug_stm);
global.debug_dm.createdContext(cx);
if (global.showDebuggerUI) {
System.out.println("Launching JSDebugger...");
try {
Class clazz = Class.forName(
"com.netscape.jsdebugging.ifcui.launcher.rhino.LaunchNetscapeJavaScriptDebugger");
ILaunchableDebugger debugger =
(ILaunchableDebugger) clazz.newInstance();
debugger.launch(global.debug_dm, global.debug_stm, false);
} catch (Exception e) {
// eat it...
System.out.println(e);
System.out.println("Failed to launch the JSDebugger");
}
}
System.out.println("Debug level set to "+cx.getDebugLevel());
}
*/
if (global.processStdin)
processSource(cx, args.length == 0 ? null : args[0]);
cx.exit();
}
/**
* Parse arguments.
*/
public static String[] processOptions(Context cx, String args[]) {
cx.setTargetPackage(""); // default to no package
for (int i=0; i < args.length; i++) {
String arg = args[i];
if (!arg.startsWith("-")) {
String[] result = new String[args.length - i];
for (int j=i; j < args.length; j++)
result[j-i] = args[j];
return result;
}
if (arg.equals("-version")) {
if (++i == args.length)
usage(arg);
double d = cx.toNumber(args[i]);
if (d != d)
usage(arg);
cx.setLanguageVersion((int) d);
continue;
}
if (arg.equals("-opt") || arg.equals("-O")) {
if (++i == args.length)
usage(arg);
double d = cx.toNumber(args[i]);
if (d != d)
usage(arg);
cx.setOptimizationLevel((int)d);
continue;
}
if (arg.equals("-e")) {
global.processStdin = false;
if (++i == args.length)
usage(arg);
try {
cx.evaluateString(global, args[i], "command line", 1,
null);
}
catch (EvaluatorException ee) {
break;
}
catch (JavaScriptException jse) {
Context.reportError(ToolErrorReporter.getMessage(
"msg.uncaughtJSException",
jse.getMessage()));
break;
}
continue;
}
if (arg.equals("-w")) {
errorReporter.setIsReportingWarnings(true);
continue;
}
if (arg.equals("-f")) {
if (++i == args.length)
usage(arg);
if (args[i].equals("-"))
global.processStdin = false;
processSource(cx, args[i]);
continue;
}
if (arg.startsWith("-debug")) {
int level = 9;
if (i+1 < args.length) {
double d = cx.toNumber(args[i+1]);
if (d == d) {
level = (int)d;
i++;
}
}
if (arg.equals("-debug"))
global.showDebuggerUI = true;
else if (arg.equals("-debugQ"))
global.showDebuggerUI = false;
else
usage(arg);
cx.setDebugLevel(level);
global.debug = true;
continue;
}
usage(arg);
}
return new String[0];
}
/**
* Return name of this class, the global object.
*
* This method must be implemented in all concrete classes
* extending ScriptableObject.
*
* @see org.mozilla.javascript.Scriptable#getClassName
*/
public String getClassName() {
return "global";
}
/**
* Print a usage message.
*/
public static void usage(String s) {
p(ToolErrorReporter.getMessage("msg.shell.usage", s));
System.exit(1);
}
/**
* Print a help message.
*
* This method is defined as a JavaScript function.
*/
public static void help(String s) {
p(ToolErrorReporter.getMessage("msg.help"));
}
/**
* Print the string values of its arguments.
*
* This method is defined as a JavaScript function.
* Note that its arguments are of the "varargs" form, which
* allows it to handle an arbitrary number of arguments
* supplied to the JavaScript function.
*
*/
public static Object print(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
for (int i=0; i < args.length; i++) {
if (i > 0)
System.out.print(" ");
// Convert the
// arbitrary JavaScript value into a string form.
String s = Context.toString(args[i]);
System.out.print(s);
}
System.out.println();
return Context.getUndefinedValue();
}
/**
* Quit the shell.
*
* This only affects the interactive mode.
*
* This method is defined as a JavaScript function.
*/
public static void quit() {
global.quitting = true;
}
/**
* Get and set the language version.
*
* This method is defined as a JavaScript function.
*/
public static double version(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
double result = (double) cx.getLanguageVersion();
if (args.length > 0) {
double d = cx.toNumber(args[0]);
cx.setLanguageVersion((int) d);
}
return result;
}
/**
* Load and execute a set of JavaScript source files.
*
* This method is defined as a JavaScript function.
*
*/
public static void load(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
for (int i=0; i < args.length; i++) {
processSource(cx, cx.toString(args[i]));
}
}
/**
* Load a Java class that defines a JavaScript object using the
* conventions outlined in ScriptableObject.defineClass.
* <p>
* This method is defined as a JavaScript function.
* @exception IllegalAccessException if access is not available
* to a reflected class member
* @exception InstantiationException if unable to instantiate
* the named class
* @exception InvocationTargetException if an exception is thrown
* during execution of methods of the named class
* @exception ClassDefinitionException if the format of the
* class causes this exception in ScriptableObject.defineClass
* @exception PropertyException if the format of the
* class causes this exception in ScriptableObject.defineClass
* @see org.mozilla.javascript.ScriptableObject#defineClass
*/
public static void defineClass(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws IllegalAccessException, InstantiationException,
InvocationTargetException, ClassDefinitionException,
PropertyException
{
Class clazz = getClass(args);
ScriptableObject.defineClass(global, clazz);
}
/**
* Load and execute a script compiled to a class file.
* <p>
* This method is defined as a JavaScript function.
* When called as a JavaScript function, a single argument is
* expected. This argument should be the name of a class that
* implements the Script interface, as will any script
* compiled by jsc.
*
* @exception IllegalAccessException if access is not available
* to the class
* @exception InstantiationException if unable to instantiate
* the named class
* @exception InvocationTargetException if an exception is thrown
* during execution of methods of the named class
* @exception JavaScriptException if a JavaScript exception is thrown
* during execution of the compiled script
* @see org.mozilla.javascript.ScriptableObject#defineClass
*/
public static void loadClass(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws IllegalAccessException, InstantiationException,
InvocationTargetException, JavaScriptException
{
Class clazz = getClass(args);
if (!Script.class.isAssignableFrom(clazz)) {
throw Context.reportRuntimeError(ToolErrorReporter.getMessage(
"msg.must.implement.Script"));
}
Script script = (Script) clazz.newInstance();
script.exec(cx, global);
}
private static Class getClass(Object[] args)
throws IllegalAccessException, InstantiationException,
InvocationTargetException
{
if (args.length == 0) {
throw Context.reportRuntimeError(ToolErrorReporter.getMessage(
"msg.expected.string.arg"));
}
String className = Context.toString(args[0]);
try {
return Class.forName(className);
}
catch (ClassNotFoundException cnfe) {
throw Context.reportRuntimeError(ToolErrorReporter.getMessage(
"msg.class.not.found",
className));
}
}
public static Object spawn(Context cx, Scriptable thisObj, Object[] args,
Function funObj)
{
Runner runner;
if (args.length != 0 && args[0] instanceof Function) {
Object[] newArgs = null;
if (args.length > 1 && args[1] instanceof Scriptable) {
newArgs = cx.getElements((Scriptable) args[1]);
}
runner = new Runner((Function) args[0], newArgs);
} else if (args.length != 0 && args[0] instanceof Script) {
runner = new Runner((Script) args[0]);
} else {
throw Context.reportRuntimeError(ToolErrorReporter.getMessage(
"msg.spawn.args"));
}
Thread thread = new Thread(runner);
thread.start();
return thread;
}
/**
* Evaluate JavaScript source.
*
* @param cx the current context
* @param filename the name of the file to compile, or null
* for interactive mode.
*/
public static void processSource(Context cx, String filename) {
SourceTextManager stm = cx.getSourceTextManager();
if (filename == null || filename.equals("-")) {
BufferedReader in = new BufferedReader
(new InputStreamReader(System.in));
if(null != stm)
in = new DebugReader(in, stm, "<stdin>");
int lineno = 1;
boolean hitEOF = false;
while (!hitEOF && !global.quitting) {
int startline = lineno;
if (filename == null)
System.err.print("js> ");
System.err.flush();
try {
String source = "";
// Collect lines of source to compile.
while(true) {
String newline;
newline = in.readLine();
if (newline == null) {
hitEOF = true;
break;
}
source = source + newline + "\n";
lineno++;
if (cx.stringIsCompilableUnit(source))
break;
}
Object result = cx.evaluateString(global, source,
"<stdin>", startline,
null);
if (result != cx.getUndefinedValue()) {
System.err.println(cx.toString(result));
}
}
catch (WrappedException we) {
// Some form of exception was caught by JavaScript and
// propagated up.
System.err.println(we.getWrappedException().toString());
we.printStackTrace();
}
catch (EvaluatorException ee) {
// Some form of JavaScript error.
// Already printed message, so just fall through.
}
catch (JavaScriptException jse) {
Context.reportError(ToolErrorReporter.getMessage(
"msg.uncaughtJSException",
jse.getMessage()));
}
catch (IOException ioe) {
System.err.println(ioe.toString());
}
if (global.quitting) {
// The user executed the quit() function.
break;
}
}
System.err.println();
} else {
Reader in = null;
try {
in = new PushbackReader(new FileReader(filename));
int c = in.read();
// Support the executable script #! syntax: If
// the first line begins with a '#', treat the whole
// line as a comment.
if (c == '#') {
while ((c = in.read()) != -1) {
if (c == '\n' || c == '\r')
break;
}
((PushbackReader) in).unread(c);
} else {
// No '#' line, just reopen the file and forget it
// ever happened. OPT closing and reopening
// undoubtedly carries some cost. Is this faster
// or slower than leaving the PushbackReader
// around?
in.close();
in = new FileReader(filename);
}
if(null != stm)
in = new DebugReader(in, stm, filename);
}
catch (FileNotFoundException ex) {
Context.reportError(ToolErrorReporter.getMessage(
"msg.couldnt.open",
filename));
return;
} catch (IOException ioe) {
System.err.println(ioe.toString());
}
try {
// Here we evalute the entire contents of the file as
// a script. Text is printed only if the print() function
// is called.
cx.evaluateReader(global, in, filename, 1, null);
}
catch (WrappedException we) {
System.err.println(we.getWrappedException().toString());
we.printStackTrace();
}
catch (EvaluatorException ee) {
// Already printed message, so just fall through.
}
catch (JavaScriptException jse) {
Context.reportError(ToolErrorReporter.getMessage(
"msg.uncaughtJSException",
jse.getMessage()));
}
catch (IOException ioe) {
System.err.println(ioe.toString());
}
finally {
try {
in.close();
}
catch (IOException ioe) {
System.err.println(ioe.toString());
}
}
}
System.gc();
}
private static void p(String s) {
System.out.println(s);
}
static ToolErrorReporter errorReporter;
static Main global;
static Main sharedGlobal;
boolean quitting;
SourceTextManager debug_stm;
//DebugManager debug_dm; // TODO: enable debugger
boolean debug = false;
boolean processStdin = true;
boolean showDebuggerUI = false;
}
class Runner implements Runnable {
Runner(Function func, Object[] args) {
f = func;
this.args = args;
}
Runner(Script script) {
s = script;
}
public void run() {
Context cx = Context.enter();
// Create a local scope for this thread to execute in, and use
// the shared global properties.
Main scope = new Main();
scope.setPrototype(Main.sharedGlobal);
try {
if (f != null)
f.call(cx, scope, scope, args);
else
s.exec(cx, scope);
} catch (JavaScriptException e) {
Context.reportError(ToolErrorReporter.getMessage(
"msg.uncaughtJSException",
e.getMessage()));
}
cx.exit();
}
private Function f;
private Script s;
private Object[] args;
}

Просмотреть файл

@ -0,0 +1,109 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This class implements the "arguments" object.
*
* See ECMA 10.1.8
*
* @see org.mozilla.javascript.NativeCall
* @author Norris Boyd
*/
class Arguments extends ScriptableObject {
public Arguments(NativeCall activation) {
this.activation = activation;
Scriptable parent = activation.getParentScope();
setParentScope(parent);
setPrototype(ScriptableObject.getObjectPrototype(parent));
args = activation.getOriginalArguments();
int length = args.length;
Object callee = activation.funObj;
defineProperty("length", new Integer(length),
ScriptableObject.DONTENUM);
defineProperty("callee", callee, ScriptableObject.DONTENUM);
hasCaller = activation.funObj.version <= Context.VERSION_1_3;
}
public String getClassName() {
return "Arguments";
}
public boolean has(String name, Scriptable start) {
return (hasCaller && name.equals("caller")) || super.has(name, start);
}
public boolean has(int index, Scriptable start) {
Object[] args = activation.getOriginalArguments();
return (0 <= index && index < args.length) || super.has(index, start);
}
public Object get(String name, Scriptable start) {
if (hasCaller && name.equals("caller")) {
NativeCall caller = activation.caller;
if (caller == null || caller.originalArgs == null)
return null;
return caller.get("arguments", caller);
}
return super.get(name, start);
}
public Object get(int index, Scriptable start) {
if (0 <= index && index < args.length) {
NativeFunction f = activation.funObj;
if (index < f.argCount)
return activation.get(f.names[index+1], activation);
return args[index];
}
return super.get(index, start);
}
public void put(String name, Scriptable start, Object value) {
if (name.equals("caller"))
hasCaller = false;
super.put(name, start, value);
}
public void put(int index, Scriptable start, Object value) {
if (0 <= index && index < args.length) {
NativeFunction f = activation.funObj;
if (index < f.argCount)
activation.put(f.names[index+1], activation, value);
else
args[index] = value;
return;
}
super.put(index, start, value);
}
public void delete(String name) {
if (name.equals("caller"))
hasCaller = false;
super.delete(name);
}
private NativeCall activation;
private Object[] args;
private boolean hasCaller;
}

Просмотреть файл

@ -0,0 +1,58 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
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,32 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
/**
* Thrown if errors are detected while attempting to define a host object
* from a Java class.
*/
public class ClassDefinitionException extends Exception {
public ClassDefinitionException(String detail) {
super(detail);
}
}

Просмотреть файл

@ -0,0 +1,34 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
public interface ClassNameHelper {
public String getTargetClassFileName();
public void setTargetClassFileName(String classFileName);
public String getTargetPackage();
public void setTargetPackage(String targetPackage);
public String getTargetClassFileName(String className);
public String getGeneratingDirectory();
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,46 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* This is the default error reporter for JavaScript.
*
* @author Norris Boyd
*/
class DefaultErrorReporter implements ErrorReporter {
public void warning(String message, String sourceName, int line,
String lineSource, int lineOffset)
{
// do nothing
}
public void error(String message, String sourceName, int line,
String lineSource, int lineOffset)
{
throw new EvaluatorException(message);
}
public EvaluatorException runtimeError(String message, String sourceName,
int line, String lineSource,
int lineOffset)
{
return new EvaluatorException(message);
}
}

Просмотреть файл

@ -0,0 +1,86 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
/**
* 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,38 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
/**
* 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,322 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
import java.util.Hashtable;
import java.util.Enumeration;
/**
* Manipulate a Scriptable object as if its prototype chain were flattened.
* <p>
* Compared to the Scriptable interface, FlattenedObject provides a view of
* Scriptable objects that is easier to use and more closely matches a script
* writer's view of a JavaScript object. <p>
*
* A FlattenedObject is "flattened" in the sense that multiple objects in a
* prototype chain appear to have their properties all appear in the
* FlattenedObject. <p>
*
* Another convenience provided by Flattened object is the ability to access
* properties by a single java.lang.Object id. This id is then converted into
* a String or an int before methods of the Scriptable object are called.
*
* @see org.mozilla.javascript.Scriptable
*
* @author Norris Boyd
*/
public class FlattenedObject {
/**
* Construct a new FlattenedObject.
*
* @param object the object to be viewed with flattened properties
*/
public FlattenedObject(Scriptable object) {
this.obj = object;
}
/**
* Get the associated Scriptable object.
*/
public Scriptable getObject() {
return obj;
}
/**
* Determine if a property exists in an object.
*
* This is a more convenient (and less efficient) form than
* <code>Scriptable.has()</code>.
* It returns true if and only if the property
* exists in this object or any of the objects in its prototype
* chain.
*
* @param id the property index, which may be either a String or a
* Number
* @return true if and only if the property exists in the prototype
* chain
* @see org.mozilla.javascript.Scriptable#has
*/
public boolean hasProperty(Object id) {
String stringId = ScriptRuntime.toString(id);
String s = ScriptRuntime.getStringId(stringId);
if (s == null)
return getBase(obj, ScriptRuntime.getIntId(stringId)) != null;
return getBase(obj, s) != null;
}
/**
* Get a property of an object.
* <p>
* This is a more convenient (and less efficient) form than
* <code>Scriptable.get()</code>. It corresponds exactly to the
* expression <code>obj[id]</code> in JavaScript. This method
* will traverse the prototype chain of an object to find the
* property.<p>
*
* If the property does not exist in the object or its prototype
* chain, the undefined value will be returned.
*
* @param id the property index; can be a String or a Number; the
* String may contain characters representing a number
* @return the value of the property or the undefined value
* @see org.mozilla.javascript.Scriptable#get
* @see org.mozilla.javascript.Context#getUndefinedValue
*/
public Object getProperty(Object id) {
String s = ScriptRuntime.getStringId(id);
int index = s == null ? ScriptRuntime.getIntId(id) : 0;
Scriptable m = obj;
Object result;
for(;;) {
result = s == null ? m.get(index, obj) : m.get(s, obj);
if (result != Scriptable.NOT_FOUND)
break;
m = m.getPrototype();
if (m == null)
return Undefined.instance;
}
if (result instanceof Scriptable)
return new FlattenedObject((Scriptable) result);
return result;
}
/**
* Set a property of an object.
*
* This is a more convenient (and less efficient) form than that
* provided in Scriptable. It corresponds exactly to the
* expression <code>obj[id] = val</code> in JavaScript.<p>
*
* @param id the property index, which may be either a String or
* a Number
* @param value the value of the property
* @see org.mozilla.javascript.Scriptable#put
*/
public void putProperty(Object id, Object value) {
String s = ScriptRuntime.getStringId(id);
if (value instanceof FlattenedObject)
value = ((FlattenedObject) value).getObject();
Scriptable x;
if (s == null) {
int index = ScriptRuntime.getIntId(id);
x = getBase(obj, index);
if (x == null)
x = obj;
x.put(index, obj, value);
return;
}
x = getBase(obj, s);
if (x == null)
x = obj;
x.put(s, obj, value);
}
/**
* Remove a property.
*
* This method provides the functionality of the <code>delete</code>
* operator in JavaScript.
*
* @param id the property index, which may be either a String or
* a Number
* @return true if the property didn't exist, or existed and was removed
* @see org.mozilla.javascript.Scriptable#delete
*/
public boolean deleteProperty(Object id) {
String s = ScriptRuntime.getStringId(id);
if (s == null) {
int index = ScriptRuntime.getIntId(id);
Scriptable base = getBase(obj, index);
if (base == null)
return true;
base.delete(index);
return !base.has(index, base);
}
Scriptable base = getBase(obj, s);
if (base == null)
return true;
base.delete(s);
return !base.has(s, base);
}
/**
* Return an array that contains the ids of the properties.
*
* <p>This method will walk the prototype chain and collect the
* ids of all objects in the prototype chain.<p>
*
* If an id appears in more than one object in the prototype chain,
* it will only be in the array once. (So all the entries in the
* array will be unique respective to equals().)
*
* @see org.mozilla.javascript.Scriptable#getIds
*/
public Object[] getIds() {
Hashtable h = new Hashtable(11);
Scriptable m = obj;
while (m != null) {
Object[] e = m.getIds();
for (int i=0; i < e.length; i++) {
h.put(e[i], Boolean.TRUE);
}
m = m.getPrototype();
}
Enumeration keys = h.keys();
Object elem;
Object[] result = new Object[h.size()];
int index = 0;
while (keys.hasMoreElements()) {
elem = keys.nextElement();
result[index++] = elem;
}
return result;
}
/**
* Consider this object to be a function, and call it.
*
* @param cx the current Context for this thread
* @param thisObj the JavaScript 'this' for the call
* @param args the arguments for the call
* @return the result of the JavaScript function call
* @exception NotAFunctionException if this object is not a function
* @exception JavaScriptException if an uncaught JavaScript exception
* occurred while executing the function
* @see org.mozilla.javascript.Function#call
*/
public Object call(Context cx, Scriptable thisObj, Object[] args)
throws NotAFunctionException,
JavaScriptException
{
if (!(obj instanceof Function)) {
throw new NotAFunctionException();
}
return ScriptRuntime.call(cx, obj, thisObj, args);
}
/**
* Consider this object to be a function, and invoke it as a
* constructor call.
*
* @param cx the current Context for this thread
* @param args the arguments for the constructor call
* @return the allocated object
* @exception NotAFunctionException if this object is not a function
* @exception JavaScriptException if an uncaught JavaScript exception
* occurred while executing the constructor
* @see org.mozilla.javascript.Function#construct
*/
public Scriptable construct(Context cx, Object[] args)
throws NotAFunctionException,
JavaScriptException
{
if (!(obj instanceof Function)) {
throw new NotAFunctionException();
}
return ScriptRuntime.newObject(cx, obj, args);
}
/**
* Get the property indicated by the id, and invoke it with the
* specified arguments.
* <p>
* For example, for a FlattenedObject <code>obj</code>,
* and a Java array <code>a</code> consisting of a single string
* <code>"hi"</code>, the call <pre>
* obj.callMethod("m", a)</pre>
* is equivalent to the JavaScript code <code>obj.m("hi")</code>.<p>
*
* If the property is not found or is not a function, an
* exception will be thrown.
*
* @param id the Number or String to use to find the function property
* to call
* @param args the arguments for the constructor call
* @return the result of the call
* @exception PropertyException if the designated property
* was not found
* @exception NotAFunctionException if this object is not a function
* @exception JavaScriptException if an uncaught JavaScript exception
* occurred while executing the method
* @see org.mozilla.javascript.Function#call
*/
public Object callMethod(Object id, Object[] args)
throws PropertyException,
NotAFunctionException,
JavaScriptException
{
if (!hasProperty(id)) {
throw new PropertyException(
Context.getMessage("msg.prop.not.found", null));
}
Object o = getProperty(id);
if (o instanceof FlattenedObject)
return ((FlattenedObject) o).call(Context.getContext(), obj, args);
throw new NotAFunctionException();
}
/****** End of API *******/
private static Scriptable getBase(Scriptable obj, String s) {
Scriptable m = obj;
while (m != null) {
if (m.has(s, obj))
return m;
m = m.getPrototype();
}
return null;
}
private static Scriptable getBase(Scriptable obj, int index) {
Scriptable m = obj;
while (m != null) {
if (m.has(index, obj))
return m;
m = m.getPrototype();
}
return null;
}
private Scriptable obj;
}

Просмотреть файл

@ -0,0 +1,70 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
/**
* This is interface that all functions in JavaScript must implement.
* The interface provides for calling functions and constructors.
*
* @see org.mozilla.javascript.Scriptable
* @author Norris Boyd
*/
public interface Function extends Scriptable {
/**
* Call the function.
*
* Note that the array of arguments is not guaranteed to have
* length greater than 0.
*
* @param cx the current Context for this thread
* @param scope the scope to execute the function relative to. This
* set to the value returned by getParentScope() except
* when the function is called from a closure.
* @param thisObj the JavaScript <code>this</code> object
* @param args the array of arguments
* @return the result of the call
* @exception JavaScriptException if an uncaught exception
* occurred while executing the function
*/
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException;
/**
* Call the function as a constructor.
*
* This method is invoked by the runtime in order to satisfy a use
* of the JavaScript <code>new</code> operator. This method is
* expected to create a new object and return it.
*
* @param cx the current Context for this thread
* @param scope the scope to execute the function relative to. This
* set to the value returned by getParentScope() except
* when the function is called from a closure.
* @param args the array of arguments
* @return the allocated object
* @exception JavaScriptException if an uncaught exception
* occurred while executing the constructor
*/
public Scriptable construct(Context cx, Scriptable scope, Object[] args)
throws JavaScriptException;
}

Просмотреть файл

@ -0,0 +1,48 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.util.*;
public class FunctionNode extends Node {
public FunctionNode(String name, Node left, Node right) {
super(TokenStream.FUNCTION, left, right, name);
itsVariableTable = new VariableTable();
}
public String getFunctionName() {
return getString();
}
public VariableTable getVariableTable() {
return itsVariableTable;
}
public boolean requiresActivation() {
return itsNeedsActivation;
}
public boolean setRequiresActivation(boolean b) {
return itsNeedsActivation = b;
}
protected VariableTable itsVariableTable;
protected boolean itsNeedsActivation;
}

Просмотреть файл

@ -0,0 +1,492 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
import java.util.Hashtable;
import java.util.Vector;
import java.lang.reflect.*;
public class FunctionObject extends NativeFunction {
/**
* Create a JavaScript function object from a Java method.
*
* <p>The <code>member</code> argument must be either a java.lang.reflect.Method
* or a java.lang.reflect.Constructor and must match one of two forms.<p>
*
* The first form is a member with zero or more parameters
* of the following types: Object, String, boolean, Scriptable,
* byte, short, int, long, float, or double. If the member is
* a Method, the return value must be void or one of the types
* allowed for parameters.<p>
*
* The runtime will perform appropriate conversions based
* upon the type of the parameter. A parameter type of
* Object specifies that no conversions are to be done. A parameter
* of type String will use Context.toString to convert arguments.
* Similarly, parameters of type double, boolean, and Scriptable
* will cause Context.toNumber, Context.toBoolean, and
* Context.toObject, respectively, to be called.<p>
*
* If the method is not static, the Java 'this' value will
* correspond to the JavaScript 'this' value. Any attempt
* to call the function with a 'this' value that is not
* of the right Java type will result in an error.<p>
*
* The second form is the variable arguments (or "varargs")
* form. If the FunctionObject will be used as a constructor,
* the member must have the following parameters
* <pre>
* (Context cx, Scriptable thisObj, Object[] args,
* Function funObj) </pre>
* and if it is a Method, be static and return an Object result.<p>
*
* Otherwise, if the FunctionObject will not be used to define a
* constructor, the member must be a static Method with parameters
* <pre>
* (Context cx, Object[] args, Function ctorObj,
* boolean inNewExpr)</pre>
* and an Object result.<p>
*
* When the function varargs form is called as part of a function call,
* the <code>args</code> parameter contains the
* arguments, with <code>thisObj</code>
* set to the JavaScript 'this' value. <code>funObj</code>
* is the function object for the invoked function.<p>
*
* When the constructor varargs form is called or invoked while evaluating
* a <code>new</code> expression, <code>args</code> contains the
* arguments, <code>ctorObj</code> refers to this FunctionObject, and
* <code>inNewExpr</code> is true if and only if a <code>new</code>
* expression caused the call. This supports defining a function that
* has different behavior when called as a constructor than when
* invoked as a normal function call. (For example, the Boolean
* constructor, when called as a function,
* will convert to boolean rather than creating a new object.)<p>
*
* @param name the name of the function
* @param methodOrConstructor a java.lang.reflect.Method or a java.lang.reflect.Constructor
* that defines the object
* @param scope enclosing scope of function
* @see org.mozilla.javascript.Scriptable
*/
public FunctionObject(String name, Member methodOrConstructor,
Scriptable scope)
{
String methodName;
if (methodOrConstructor instanceof Constructor) {
ctor = (Constructor) methodOrConstructor;
isStatic = true; // well, doesn't take a 'this'
types = ctor.getParameterTypes();
methodName = ctor.getName();
} else {
method = (Method) methodOrConstructor;
isStatic = Modifier.isStatic(method.getModifiers());
types = method.getParameterTypes();
methodName = method.getName();
}
String myNames[] = { name };
super.names = myNames;
int length;
if (types.length == 4 && (types[1].isArray() || types[2].isArray())) {
// Either variable args or an error.
if (types[1].isArray()) {
if (!isStatic ||
types[0] != Context.class ||
types[1].getComponentType() != ScriptRuntime.ObjectClass ||
types[2] != ScriptRuntime.FunctionClass ||
types[3] != Boolean.TYPE)
{
String message = Context.getMessage("msg.varargs.ctor",
null);
throw Context.reportRuntimeError(message);
}
} else {
if (!isStatic ||
types[0] != Context.class ||
types[1] != ScriptRuntime.ScriptableClass ||
types[2].getComponentType() != ScriptRuntime.ObjectClass ||
types[3] != ScriptRuntime.FunctionClass)
{
String message = Context.getMessage("msg.varargs.fun",
null);
throw Context.reportRuntimeError(message);
}
}
// XXX check return type
parmsLength = types[1].isArray() ? VARARGS_CTOR : VARARGS_METHOD;
length = 1;
} else {
parmsLength = (short) types.length;
boolean hasConversions = false;
for (int i=0; i < parmsLength; i++) {
Class type = types[i];
if (type == ScriptRuntime.ObjectClass) {
// may not need conversions
} else if (type == ScriptRuntime.StringClass ||
type == ScriptRuntime.BooleanClass ||
ScriptRuntime.NumberClass.isAssignableFrom(type) ||
Scriptable.class.isAssignableFrom(type))
{
hasConversions = true;
} else if (type == Boolean.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.BooleanClass;
} else if (type == Byte.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.ByteClass;
} else if (type == Short.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.ShortClass;
} else if (type == Integer.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.IntegerClass;
} else if (type == Float.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.FloatClass;
} else if (type == Double.TYPE) {
hasConversions = true;
types[i] = ScriptRuntime.DoubleClass;
} else {
Object[] errArgs = { methodName };
throw Context.reportRuntimeError(
Context.getMessage("msg.bad.parms", errArgs));
}
}
if (!hasConversions)
types = null;
length = parmsLength;
}
// Initialize length property
lengthPropertyValue = (short) length;
hasVoidReturn = method != null && method.getReturnType() == Void.TYPE;
this.argCount = (short) length;
setParentScope(scope);
setPrototype(getFunctionPrototype(scope));
}
/**
* Override ScriptableObject's has, get, and set in order to define
* the "length" property of the function. <p>
*
* We could also have defined the property using ScriptableObject's
* defineProperty method, but that would have consumed a slot in every
* FunctionObject. Most FunctionObjects typically don't have any
* properties anyway, so having the "length" property would cause us
* to allocate an array of slots. <p>
*
* In particular, this method will return true for
* <code>name.equals("length")</code>
* and will delegate to the superclass for all other
* values of <code>name</code>.
*/
public boolean has(String name, Scriptable start) {
return name.equals("length") || super.has(name, start);
}
/**
* Override ScriptableObject's has, get, and set in order to define
* the "length" property of the function. <p>
*
* In particular, this method will return the value defined by
* the method used to construct the object (number of parameters
* of the method, or 1 if the method is a "varargs" form), unless
* setLength has been called with a new value.
*
* @see org.mozilla.javascript.FunctionObject#setLength
*/
public Object get(String name, Scriptable start) {
if (name.equals("length"))
return new Integer(lengthPropertyValue);
return super.get(name, start);
}
/**
* Override ScriptableObject's has, get, and set in order to define
* the "length" property of the function. <p>
*
* In particular, this method will ignore all attempts to set the
* "length" property and forward all other requests to ScriptableObject.
*
* @see org.mozilla.javascript.FunctionObject#setLength
*/
public void put(String name, Scriptable start, Object value) {
if (!name.equals("length"))
super.put(name, start, value);
}
/**
* Set the value of the "length" property.
*
* <p>Changing the value of the "length" property of a FunctionObject only
* affects the value retrieved from get() and does not affect the way
* the method itself is called. <p>
*
* The "length" property will be defined by default as the number
* of parameters of the method used to construct the FunctionObject,
* unless the method is a "varargs" form, in which case the "length"
* property will be defined to 1.
*
* @param length the new length
*/
public void setLength(short length) {
lengthPropertyValue = length;
}
// TODO: Make not public
/**
* Finds methods of a given name in a given class.
*
* <p>Searches <code>clazz</code> for methods with name
* <code>name</code>. Maintains a cache so that multiple
* lookups on the same class are cheap.
*
* @param clazz the class to search
* @param name the name of the methods to find
* @return an array of the found methods, or null if no methods
* by that name were found.
* @see java.lang.Class#getMethods
*/
public static Method[] findMethods(Class clazz, String name) {
Vector v = new Vector(5);
Method[] methods = clazz.getMethods();
for (int i=0; i < methods.length; i++) {
if (methods[i].getDeclaringClass() == clazz &&
methods[i].getName().equals(name)){
v.addElement(methods[i]);
}
}
if (v.size() == 0) {
return null;
}
Method[] result = new Method[v.size()];
v.copyInto(result);
return result;
}
/**
* Define this function as a JavaScript constructor.
* <p>
* Sets up the "prototype" and "constructor" properties. Also
* calls setParent and setPrototype with appropriate values.
* Then adds the function object as a property of the given scope, using
* <code>prototype.getClassName()</code>
* as the name of the property.
*
* @param scope the scope in which to define the constructor (typically
* the global object)
* @param prototype the prototype object
* @see org.mozilla.javascript.Scriptable#setParentScope
* @see org.mozilla.javascript.Scriptable#setPrototype
* @see org.mozilla.javascript.Scriptable#getClassName
*/
public void addAsConstructor(Scriptable scope, Scriptable prototype) {
setParentScope(scope);
setPrototype(getFunctionPrototype(scope));
prototype.setParentScope(this);
final int attr = ScriptableObject.DONTENUM |
ScriptableObject.PERMANENT |
ScriptableObject.READONLY;
defineProperty("prototype", prototype, attr);
String name = prototype.getClassName();
if (!name.equals("With")) {
// A "With" object would delegate these calls to the prototype:
// not the right thing to do here!
if (prototype instanceof ScriptableObject) {
((ScriptableObject) prototype).defineProperty("constructor",
this, attr);
} else {
prototype.put("constructor", prototype, this);
}
}
if (scope instanceof ScriptableObject) {
((ScriptableObject) scope).defineProperty(name, this,
ScriptableObject.DONTENUM);
} else {
scope.put(name, scope, this);
}
setParentScope(scope);
}
/**
* Performs conversions on argument types if needed and
* invokes the underlying Java method or constructor.
* <p>
* Implements Function.call.
*
* @see org.mozilla.javascript.Function#call
* @exception JavaScriptException if the underlying Java method or constructor
* threw an exception
*/
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException
{
if (parmsLength < 0)
return callVarargs(cx, thisObj, args, false);
if (!isStatic) {
// OPT: cache "clazz"?
Class clazz = method != null ? method.getDeclaringClass()
: ctor.getDeclaringClass();
if (thisObj == null || !clazz.isInstance(thisObj)) {
Object[] errArgs = { names[0] };
throw Context.reportRuntimeError(
Context.getMessage("msg.incompat.call", errArgs));
}
}
Object[] invokeArgs;
int i;
if (parmsLength == args.length) {
invokeArgs = args;
// avoid copy loop if no conversions needed
i = (types == null) ? parmsLength : 0;
} else {
invokeArgs = new Object[parmsLength];
i = 0;
}
for (; i < parmsLength; i++) {
Object arg = (i < args.length)
? args[i]
: Undefined.instance;
if (types != null) {
Class desired = types[i];
if (desired == ScriptRuntime.BooleanClass
|| desired == Boolean.TYPE)
arg = ScriptRuntime.toBoolean(arg) ? Boolean.TRUE
: Boolean.FALSE;
else if (desired == ScriptRuntime.StringClass)
arg = ScriptRuntime.toString(arg);
else if (desired == ScriptRuntime.IntegerClass || desired == Integer.TYPE)
arg = new Integer(ScriptRuntime.toInt32(arg));
else if (desired == ScriptRuntime.DoubleClass || desired == Double.TYPE)
arg = new Double(ScriptRuntime.toNumber(arg));
else if (desired == ScriptRuntime.ScriptableClass)
arg = ScriptRuntime.toObject(this, arg);
else {
Object[] errArgs = { desired.getName() };
throw Context.reportRuntimeError(
Context.getMessage("msg.cant.convert", errArgs));
}
}
invokeArgs[i] = arg;
}
try {
Object result = (method != null)
? method.invoke(thisObj, invokeArgs)
: ctor.newInstance(invokeArgs);
return hasVoidReturn ? Undefined.instance : result;
}
catch (InvocationTargetException e) {
throw JavaScriptException.wrapException(scope, e);
}
catch (IllegalAccessException e) {
throw WrappedException.wrapException(e);
}
catch (InstantiationException e) {
throw WrappedException.wrapException(e);
}
}
/**
* Performs conversions on argument types if needed and
* invokes the underlying Java method or constructor
* to create a new Scriptable object.
* <p>
* Implements Function.construct.
*
* @param cx the current Context for this thread
* @param scope the scope to execute the function relative to. This
* set to the value returned by getParentScope() except
* when the function is called from a closure.
* @param args arguments to the constructor
* @see org.mozilla.javascript.Function#construct
* @exception JavaScriptException if the underlying Java method or constructor
* threw an exception
*/
public Scriptable construct(Context cx, Scriptable scope, Object[] args)
throws JavaScriptException
{
if (method == null || parmsLength == VARARGS_CTOR) {
Scriptable result = method != null
? (Scriptable) callVarargs(cx, null, args, true)
: (Scriptable) call(cx, scope, null, args);
if (result.getPrototype() == null)
result.setPrototype(getClassPrototype());
if (result.getParentScope() == null) {
Scriptable parent = getParentScope();
if (result != parent)
result.setParentScope(parent);
}
return result;
}
return super.construct(cx, scope, args);
}
private Object callVarargs(Context cx, Scriptable thisObj, Object[] args,
boolean inNewExpr)
throws JavaScriptException
{
try {
if (parmsLength == VARARGS_METHOD) {
Object[] invokeArgs = { cx, thisObj, args, this };
Object result = method.invoke(null, invokeArgs);
return hasVoidReturn ? Undefined.instance : result;
} else {
Boolean b = inNewExpr ? Boolean.TRUE : Boolean.FALSE;
Object[] invokeArgs = { cx, args, this, b };
return (method == null)
? ctor.newInstance(invokeArgs)
: method.invoke(null, invokeArgs);
}
}
catch (InvocationTargetException e) {
Throwable target = e.getTargetException();
if (target instanceof EvaluatorException)
throw (EvaluatorException) target;
Scriptable scope = thisObj == null ? this : thisObj;
throw JavaScriptException.wrapException(scope, target);
}
catch (IllegalAccessException e) {
throw WrappedException.wrapException(e);
}
catch (InstantiationException e) {
throw WrappedException.wrapException(e);
}
}
private static final short VARARGS_METHOD = -1;
private static final short VARARGS_CTOR = -2;
Method method;
Constructor ctor;
private Class[] types;
private short parmsLength;
private short lengthPropertyValue;
private boolean hasVoidReturn;
private boolean isStatic;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
class InterpretedFunction extends NativeFunction {
InterpretedFunction(InterpreterData theData, Context cx)
{
itsData = theData;
// probably too much copying going on from theData to the InterpretedFunction object
// should pass them as parameters - unless we need them in the data block anyway?
names = new String[itsData.itsVariableTable.size() + 1];
names[0] = itsData.itsName;
for (int i = 0; i < itsData.itsVariableTable.size(); i++)
names[i + 1] = itsData.itsVariableTable.getName(i);
argCount = (short)itsData.itsVariableTable.getParameterCount();
source = itsData.itsSource;
nestedFunctions = itsData.itsNestedFunctions;
version = (short)cx.getLanguageVersion();
}
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args)
throws JavaScriptException
{
if (itsData.itsNeedsActivation)
scope = ScriptRuntime.initVarObj(cx, scope, this, thisObj, args);
itsData.itsCX = cx;
itsData.itsScope = scope;
itsData.itsThisObj = thisObj;
itsData.itsInArgs = args;
return Interpreter.interpret(itsData);
}
InterpreterData itsData;
}

Просмотреть файл

@ -0,0 +1,55 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
public class InterpretedScript extends NativeScript {
InterpretedScript(InterpreterData theData, Context cx)
{
itsData = theData;
names = new String[itsData.itsVariableTable.size() + 1];
names[0] = "";
for (int i = 0; i < itsData.itsVariableTable.size(); i++)
names[i + 1] = itsData.itsVariableTable.getName(i);
nestedFunctions = itsData.itsNestedFunctions;
version = (short)cx.getLanguageVersion();
}
public Object exec(Context cx, Scriptable scope)
throws JavaScriptException
{
return call(cx, scope, scope, null);
}
public Object call(Context cx, Scriptable scope,
Scriptable thisObj, Object[] args)
throws JavaScriptException
{
scope = ScriptRuntime.initScript(cx, scope, this, thisObj);
itsData.itsCX = cx;
itsData.itsScope = scope;
itsData.itsThisObj = thisObj;
itsData.itsInArgs = args;
return Interpreter.interpret(itsData);
}
InterpreterData itsData;
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,80 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.util.Vector;
class InterpreterData {
static final int INITIAL_MAX_ICODE_LENGTH = 1024;
static final int INITIAL_STRINGTABLE_SIZE = 64;
static final int INITIAL_NUMBERTABLE_SIZE = 64;
InterpreterData(int lastICodeTop, int lastStringTableIndex,
int lastNumberTableIndex, Object securityDomain)
{
itsICodeTop = lastICodeTop == 0
? INITIAL_MAX_ICODE_LENGTH
: lastICodeTop * 2;
itsICode = new byte[itsICodeTop];
itsStringTable = new String[lastStringTableIndex == 0
? INITIAL_STRINGTABLE_SIZE
: lastStringTableIndex * 2];
itsNumberTable = new Number[lastNumberTableIndex == 0
? INITIAL_NUMBERTABLE_SIZE
: lastNumberTableIndex * 2];
if (securityDomain == null && Context.isSecurityDomainRequired())
throw new SecurityException("Required security context missing");
this.securityDomain = securityDomain;
}
VariableTable itsVariableTable;
String itsName;
String itsSource;
boolean itsNeedsActivation;
String[] itsStringTable;
int itsStringTableIndex;
Number[] itsNumberTable;
int itsNumberTableIndex;
InterpretedFunction[] itsNestedFunctions;
Object[] itsRegExpLiterals;
byte[] itsICode;
int itsICodeTop;
int itsMaxLocals;
int itsMaxArgs;
int itsMaxStack;
int itsMaxTryDepth;
Object securityDomain;
Context itsCX;
Scriptable itsScope;
Scriptable itsThisObj;
Object[] itsInArgs;
}

Просмотреть файл

@ -0,0 +1,305 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.lang.reflect.*;
import java.util.Hashtable;
import java.util.Enumeration;
/**
*
* @author Mike Shaver
* @author Norris Boyd
* @see NativeJavaObject
* @see NativeJavaClass
*/
class JavaMembers {
JavaMembers(Scriptable scope, Class cl) {
this.members = new Hashtable(23);
this.staticMembers = new Hashtable(7);
this.cl = cl;
reflect(scope, cl);
}
boolean has(String name, boolean isStatic) {
Hashtable ht = isStatic ? staticMembers : members;
return ht.get(name) != null;
}
Object get(Scriptable scope, String name, Object javaObject,
boolean isStatic)
{
Hashtable ht = isStatic ? staticMembers : members;
Object member = ht.get(name);
if (member == null)
return Scriptable.NOT_FOUND;
if (member instanceof Scriptable)
return member;
Field field = (Field) member;
Object rval;
try {
rval = field.get(isStatic ? null : javaObject);
} catch (IllegalAccessException accEx) {
throw new RuntimeException("unexpected IllegalAccessException "+
"accessing Java field");
}
// Need to wrap the object before we return it.
Class fieldType = field.getType();
scope = ScriptableObject.getTopLevelScope(scope);
return NativeJavaObject.wrap(scope, rval, fieldType);
}
public void put(String name, Object javaObject, Object value,
boolean isStatic)
{
Hashtable ht = isStatic ? staticMembers : members;
Object member = ht.get(name);
if (member == null)
throw reportMemberNotFound(name);
if (member instanceof FieldAndMethods) {
member = ((FieldAndMethods) ht.get(name)).getField();
}
Field field = null;
try {
field = (Field) member;
// XXX what was this for?
//if (obj instanceof Wrapper)
// obj = ((Wrapper)obj).unwrap();
field.set(javaObject, NativeJavaObject.coerceType(field.getType(),
value));
} catch (ClassCastException e) {
Object errArgs[] = { name };
throw Context.reportRuntimeError(Context.getMessage
("msg.java.method.assign",
errArgs));
} catch (IllegalAccessException accessEx) {
throw new RuntimeException("unexpected IllegalAccessException "+
"accessing Java field");
} catch (IllegalArgumentException argEx) {
Object errArgs[] = { value.getClass().getName(), field,
javaObject.getClass().getName() };
throw Context.reportRuntimeError(Context.getMessage(
"msg.java.internal.field.type", errArgs));
}
}
Object[] getIds(boolean isStatic) {
Hashtable ht = isStatic ? staticMembers : members;
int len = ht.size();
Object[] result = new Object[len];
Enumeration keys = ht.keys();
for (int i=0; i < len; i++)
result[i] = keys.nextElement();
return result;
}
Class getReflectedClass() {
return cl;
}
void reflectField(Field field) {
int mods = field.getModifiers();
if (!Modifier.isPublic(mods))
return;
boolean isStatic = Modifier.isStatic(mods);
Hashtable ht = isStatic ? staticMembers : members;
String name = field.getName();
Object member = ht.get(name);
if (member != null) {
if (member instanceof NativeJavaMethod) {
NativeJavaMethod method = (NativeJavaMethod) member;
Hashtable fmht = isStatic ? staticFieldAndMethods
: fieldAndMethods;
if (fmht == null) {
fmht = new Hashtable(11);
if (isStatic)
staticFieldAndMethods = fmht;
else
fieldAndMethods = fmht;
}
FieldAndMethods fam = new FieldAndMethods(method.getMethods(),
field);
fmht.put(name, fam);
ht.put(name, fam);
return;
}
if (member instanceof Field) {
Field oldField = (Field) member;
// beard:
// If an exception is thrown here, then JDirect classes on MRJ can't be used. JDirect
// classes implement multiple interfaces that each have a static "libraryInstance" field.
if (false) {
throw new RuntimeException("cannot have multiple Java " +
"fields with same name");
}
// If this newly reflected field shadows an inherited field, then replace it. Otherwise,
// since access to the field would be ambiguous from Java, no field should be reflected.
// For now, the first field found wins, unless another field explicitly shadows it.
if (oldField.getDeclaringClass().isAssignableFrom(field.getDeclaringClass()))
ht.put(name, field);
return;
}
throw new RuntimeException("unknown member type");
}
ht.put(name, field);
}
void reflectMethod(Scriptable scope, Method method) {
int mods = method.getModifiers();
if (!Modifier.isPublic(mods))
return;
boolean isStatic = Modifier.isStatic(mods);
Hashtable ht = isStatic ? staticMembers : members;
String name = method.getName();
NativeJavaMethod fun = (NativeJavaMethod) ht.get(name);
if (fun == null) {
fun = new NativeJavaMethod();
fun.setParentScope(scope);
fun.setPrototype(ScriptableObject.getFunctionPrototype(scope));
ht.put(name, fun);
fun.add(method);
}
else
fun.add(method);
}
void reflect(Scriptable scope, Class cl) {
// We reflect methods first, because we want overloaded field/method
// names to be allocated to the NativeJavaMethod before the field
// gets in the way.
Method[] methods = cl.getMethods();
for (int i = 0; i < methods.length; i++)
reflectMethod(scope, methods[i]);
Field[] fields = cl.getFields();
for (int i = 0; i < fields.length; i++)
reflectField(fields[i]);
ctors = cl.getConstructors();
}
Hashtable getFieldAndMethodsObjects(Object javaObject, boolean isStatic) {
Hashtable ht = isStatic ? staticFieldAndMethods : fieldAndMethods;
if (ht == null)
return null;
int len = ht.size();
Hashtable result = new Hashtable(len);
Enumeration e = ht.elements();
while (len-- > 0) {
FieldAndMethods fam = (FieldAndMethods) e.nextElement();
fam = (FieldAndMethods) fam.clone();
fam.setJavaObject(javaObject);
result.put(fam.getName(), fam);
}
return result;
}
Constructor[] getConstructors() {
return ctors;
}
static JavaMembers lookupClass(Scriptable scope, Class dynamicType,
Class staticType)
{
Class cl = dynamicType;
JavaMembers members = (JavaMembers) classTable.get(cl);
if (members != null)
return members;
if (staticType != null && staticType != dynamicType &&
!Modifier.isPublic(dynamicType.getModifiers()) &&
Modifier.isPublic(staticType.getModifiers()))
{
cl = staticType;
}
synchronized (classTable) {
members = (JavaMembers) classTable.get(cl);
if (members != null)
return members;
members = new JavaMembers(scope, cl);
classTable.put(cl, members);
return members;
}
}
RuntimeException reportMemberNotFound(String memberName) {
Object errArgs[] = { cl.getName(),
memberName };
return Context.reportRuntimeError(
Context.getMessage("msg.java.member.not.found",
errArgs));
}
private static Hashtable classTable = new Hashtable();
private Class cl;
private Hashtable members;
private Hashtable fieldAndMethods;
private Hashtable staticMembers;
private Hashtable staticFieldAndMethods;
private Constructor[] ctors;
}
class FieldAndMethods extends NativeJavaMethod {
FieldAndMethods(Method[] methods, Field field) {
super(methods);
this.field = field;
}
void setJavaObject(Object javaObject) {
this.javaObject = javaObject;
}
String getName() {
return field.getName();
}
Field getField() {
return field;
}
public Object getDefaultValue(Class hint) {
if (hint == ScriptRuntime.FunctionClass)
return this;
Object rval;
try {
rval = field.get(javaObject);
} catch (IllegalAccessException accEx) {
throw Context.reportRuntimeError(Context.getMessage
("msg.java.internal.private", null));
}
rval = NativeJavaObject.wrap(this, rval, field.getType());
if (rval instanceof Scriptable) {
((Scriptable)rval).setParentScope(this);
((Scriptable)rval).setPrototype(parent.getPrototype());
}
return rval;
}
public Object clone() {
FieldAndMethods result = new FieldAndMethods(methods, field);
result.javaObject = javaObject;
return result;
}
private Field field;
private Object javaObject;
}

Просмотреть файл

@ -0,0 +1,92 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
// API class
package org.mozilla.javascript;
import java.lang.reflect.InvocationTargetException;
/**
* 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(ScriptRuntime.toString(value));
this.value = value;
}
/**
* Get the exception message.
*
* <p>Will just convert the wrapped exception to a string.
*/
public String getMessage() {
return ScriptRuntime.toString(value);
}
static JavaScriptException wrapException(Scriptable scope,
Throwable exn)
{
if (exn instanceof InvocationTargetException)
exn = ((InvocationTargetException)exn).getTargetException();
if (exn instanceof JavaScriptException)
return (JavaScriptException)exn;
Object wrapper = NativeJavaObject.wrap(scope, exn, Throwable.class);
return new JavaScriptException(wrapper);
}
/**
* 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() {
if (value != null && value instanceof Wrapper)
// this will also catch NativeStrings...
return ((Wrapper)value).unwrap();
else
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,87 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
public class Label {
private static final int FIXUPTABLE_SIZE = 8;
private static final boolean DEBUG = true;
public Label()
{
itsPC = -1;
}
public short getPC()
{
return itsPC;
}
public void fixGotos(byte theCodeBuffer[])
{
if (DEBUG) {
if ((itsPC == -1) && (itsFixupTable != null))
throw new RuntimeException("Unlocated label");
}
if (itsFixupTable != null) {
for (int i = 0; i < itsFixupTableTop; i++) {
int fixupSite = itsFixupTable[i];
// -1 to get delta from instruction start
short offset = (short)(itsPC - (fixupSite - 1));
theCodeBuffer[fixupSite++] = (byte)(offset >> 8);
theCodeBuffer[fixupSite] = (byte)offset;
}
}
itsFixupTable = null;
}
public void setPC(short thePC)
{
if (DEBUG) {
if ((itsPC != -1) && (itsPC != thePC))
throw new RuntimeException("Duplicate label");
}
itsPC = thePC;
}
public void addFixup(int fixupSite)
{
if (itsFixupTable == null) {
itsFixupTableTop = 1;
itsFixupTable = new int[FIXUPTABLE_SIZE];
itsFixupTable[0] = fixupSite;
}
else {
if (itsFixupTableTop == itsFixupTable.length) {
int oldLength = itsFixupTable.length;
int newTable[] = new int[oldLength + FIXUPTABLE_SIZE];
System.arraycopy(itsFixupTable, 0, newTable, 0, oldLength);
itsFixupTable = newTable;
}
itsFixupTable[itsFixupTableTop++] = fixupSite;
}
}
private short itsPC;
private int itsFixupTable[];
private int itsFixupTableTop;
}

Просмотреть файл

@ -0,0 +1,63 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
public class LabelTable {
private static final boolean DEBUGLABELS = false;
private static final int LabelTableSize = 32;
protected Label itsLabelTable[];
protected int itsLabelTableTop;
public int acquireLabel()
{
if (itsLabelTable == null) {
itsLabelTable = new Label[LabelTableSize];
itsLabelTable[0] = new Label();
itsLabelTableTop = 1;
return 0x80000000;
}
else {
if (itsLabelTableTop == itsLabelTable.length) {
Label oldTable[] = itsLabelTable;
itsLabelTable = new Label[itsLabelTableTop * 2];
System.arraycopy(oldTable, 0, itsLabelTable, 0, itsLabelTableTop);
}
itsLabelTable[itsLabelTableTop] = new Label();
int result = itsLabelTableTop++;
return result | 0x80000000;
}
}
public int markLabel(int theLabel, int pc)
{
if (DEBUGLABELS) {
if ((theLabel & 0x80000000) != 0x80000000)
throw new RuntimeException("Bad label, no biscuit");
}
theLabel &= 0x7FFFFFFF;
if (DEBUGLABELS) {
System.out.println("Marking label " + theLabel + " at " + pc);
}
itsLabelTable[theLabel].setPC((short)pc);
return theLabel | 0x80000000;
}
}

Просмотреть файл

@ -0,0 +1,348 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.io.Reader;
import java.io.IOException;
/**
* An input buffer that combines fast character-based access with
* (slower) support for retrieving the text of the current line. It
* also supports building strings directly out of the internal buffer
* to support fast scanning with minimal object creation.
*
* Note that it is customized in several ways to support the
* TokenStream class, and should not be considered general.
*
* Credits to Kipp Hickman and John Bandhauer.
*
* @author Mike McCabe
*/
final class LineBuffer {
/*
* for smooth operation of getLine(), this should be greater than
* the length of any expected line. Currently, 256 is 3% slower
* than 4096 for large compiles, but seems safer given evaluateString.
* Strings for the scanner are are built with StringBuffers
* instead of directly out of the buffer whenever a string crosses
* a buffer boundary, so small buffer sizes will mean that more
* objects are created.
*/
static final int BUFLEN = 256;
LineBuffer(Reader in, int lineno) {
this.in = in;
this.lineno = lineno;
}
int read() throws IOException {
if (end == offset && !fill())
return -1;
// Do only a bitmask + branch per character, at the cost of
// three branches per low-bits-only character.
if ((buffer[offset] & '\ufff0') == 0) {
if (buffer[offset] == '\r') {
// if the next character is a newline, skip past it.
if ((offset + 1) < end) {
if (buffer[offset + 1] == '\n')
offset++;
} else {
// set a flag for fill(), in case the first char of the
// next fill is a newline.
lastWasCR = true;
}
}
else if (buffer[offset] != '\n') {
return (int) buffer[offset++];
}
offset++;
prevStart = lineStart;
lineStart = offset;
lineno++;
return '\n';
}
return (int) buffer[offset++];
}
void unread() {
if (offset == 0)
// We can get here when we're asked to unread() an
// implicit EOF_CHAR.
// This would also 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. So we're OK.
return;
offset--;
if ((buffer[offset] & '\ufff0') == 0
&& (buffer[offset] == '\r' || buffer[offset] == '\n')) {
// back off from the line start we presumably just registered...
lineStart = prevStart;
lineno--;
}
}
int peek() throws IOException {
if (end == offset && !fill())
return -1;
if (buffer[offset] == '\r')
return '\n';
return buffer[offset];
}
boolean match(char c) throws IOException {
if (end == offset && !fill())
return false;
// This'd be a place where we'd need to map '\r' to '\n' and
// do other updates, but TokenStream never looks ahead for
// '\n', so we don't bother.
if (buffer[offset] == c) {
offset++;
return true;
}
return false;
}
// Reconstruct a source line from the buffers. This can be slow...
String getLine() {
StringBuffer result = new StringBuffer();
int start = lineStart;
if (start >= offset) {
// the line begins somewhere in the other buffer; get that first.
if (otherStart < otherEnd)
// if a line ending was seen in the other buffer... otherwise
// just ignore this strange case.
result.append(otherBuffer, otherStart,
otherEnd - otherStart);
start = 0;
}
// get the part of the line in the current buffer.
result.append(buffer, start, offset - start);
// Get the remainder of the line.
int i = offset;
while(true) {
if (i == buffer.length) {
// 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.
char[] newBuffer = new char[buffer.length * 2];
System.arraycopy(buffer, 0, newBuffer, 0, buffer.length);
buffer = newBuffer;
int charsRead = 0;
try {
charsRead = in.read(buffer, end, buffer.length - end);
} catch (IOException ioe) {
// ignore it, we're already displaying an error...
}
if (charsRead < 0)
break;
end += charsRead;
}
if (buffer[i] == '\r' || buffer[i] == '\n')
break;
i++;
}
result.append(buffer, offset, i - offset);
return result.toString();
}
// Get the offset of the current character, relative to
// the line that getLine() returns.
int getOffset() {
if (lineStart >= offset)
// The line begins somewhere in the other buffer.
return offset + (otherEnd - otherStart);
else
return offset - lineStart;
}
// Set a mark to indicate that the reader should begin
// accumulating characters for getString(). The string begins
// with the last character read.
void startString() {
if (offset == 0) {
// We can get here if startString is called after a peek()
// or failed match() with offset past the end of the
// buffer.
// We're at the beginning of the buffer, and the previous character
// (which we want to include) is at the end of the last one, so
// we just go to StringBuffer mode.
stringSoFar = new StringBuffer();
stringSoFar.append(otherBuffer, otherEnd - 1, 1);
stringStart = -1; // Set sentinel value.
} else {
// Support restarting strings
stringSoFar = null;
stringStart = offset - 1;
}
}
// Get a string consisting of the characters seen since the last
// startString.
String getString() {
String result;
/*
* There's one strange case here: If the character offset currently
* points to (which we never want to include in the string) is
* a newline, then if the previous character is a carriage return,
* we probably want to exclude that as well. If the offset is 0,
* then we hope that fill() handled excluding it from stringSoFar.
*/
int loseCR = (offset > 0 &&
buffer[offset] == '\n' && buffer[offset - 1] == '\r') ?
1 : 0;
if (stringStart != -1) {
// String mark is valid, and in this buffer.
result = new String(buffer, stringStart,
offset - stringStart - loseCR);
} else {
// Exclude cr as well as nl of newline. If offset is 0, then
// hopefully fill() did the right thing.
result = (stringSoFar.append(buffer, 0, offset - loseCR)).toString();
}
stringStart = -1;
stringSoFar = null;
return result;
}
boolean fill() throws IOException {
// not sure I care...
if (end - offset != 0)
throw new IOException("fill of non-empty buffer");
// If there's a string currently being accumulated, save
// off the progress.
/*
* Exclude an end-of-buffer carriage return. NOTE this is not
* fully correct in the general case, because we really only
* want to exclude the carriage return if it's followed by a
* linefeed at the beginning of the next buffer. But we fudge
* because the scanner doesn't do this.
*/
int loseCR = (offset > 0 && lastWasCR) ? 1 : 0;
if (stringStart != -1) {
// The mark is in the current buffer, save off from the mark to the
// end.
stringSoFar = new StringBuffer();
stringSoFar.append(buffer, stringStart, end - stringStart - loseCR);
stringStart = -1;
} else if (stringSoFar != null) {
// the string began prior to the current buffer, so save the
// whole current buffer.
stringSoFar.append(buffer, 0, end - loseCR);
}
// 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.
otherStart = lineStart;
otherEnd = end;
// set lineStart to a sentinel value, unless this is the first
// time around.
prevStart = lineStart = (otherBuffer == null) ? 0 : buffer.length + 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 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;
private int stringStart = -1;
private StringBuffer stringSoFar = null;
}

Просмотреть файл

@ -0,0 +1,40 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
public class LocalVariable {
public LocalVariable(String name, boolean isParameter) {
itsName = name;
itsIsParameter = isParameter;
}
public void setIndex(int index){ itsIndex = index; }
public int getIndex() { return itsIndex; }
public void setIsParameter() { itsIsParameter = true; }
public boolean isParameter() { return itsIsParameter; }
public String getName() { return itsName; }
private String itsName;
private int itsIndex = -1;
private boolean itsIsParameter;
}

Просмотреть файл

@ -0,0 +1,919 @@
/* -*- 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.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All Rights
* Reserved.
*/
package org.mozilla.javascript;
import java.util.Hashtable;
/**
* This class implements the Array native object.
* @author Norris Boyd
* @author Mike McCabe
*/
public class NativeArray extends ScriptableObject {
/*
* Optimization possibilities and open issues:
* - Long vs. double schizophrenia. I suspect it might be better
* to use double throughout.
* - Most array operations go through getElem or setElem (defined
* in this file) to handle the full 2^32 range; it might be faster
* to have versions of most of the loops in this file for the
* (infinitely more common) case of indices < 2^31.
* - Functions that need a new Array call "new Array" in the
* current scope rather than using a hardwired constructor;
* "Array" could be redefined. It turns out that js calls the
* equivalent of "new Array" in the current scope, except that it
* always gets at least an object back, even when Array == null.
*/
/**
* Zero-parameter constructor: just used to create Array.prototype
*/
public NativeArray() {
dense = null;
this.length = 0;
}
public NativeArray(long length) {
int intLength = (int) length;
if (intLength == length && intLength > 0) {
if (intLength > maximumDenseLength)
intLength = maximumDenseLength;
dense = new Object[intLength];
for (int i=0; i < intLength; i++)
dense[i] = NOT_FOUND;
}
this.length = length;
}
public NativeArray(Object[] array) {
dense = array;
this.length = array.length;
}
public static void finishInit(Scriptable scope, FunctionObject ctor,
Scriptable proto)
{
// Set some method length values.
// See comment for NativeString.finishInit()
String[] specialLengthNames = { "reverse",
"toString",
};
short[] specialLengthValues = { 0,
0,
};
for (int i=0; i < specialLengthNames.length; i++) {
Object obj = proto.get(specialLengthNames[i], proto);
((FunctionObject) obj).setLength(specialLengthValues[i]);
}
}
public String getClassName() {
return "Array";
}
public Object get(int index, Scriptable start) {
if (dense != null && 0 <= index && index < dense.length)
return dense[index];
return super.get(index, start);
}
public boolean has(int index, Scriptable start) {
if (dense != null && 0 <= index && index < dense.length)
return dense[index] != NOT_FOUND;
return super.has(index, start);
}
public void put(String id, Scriptable start, Object value) {
// only set the array length if given an array index (ECMA 15.4.0)
// try to get an array index from id
double d = ScriptRuntime.toNumber(id);
if (ScriptRuntime.toUint32(d) == d &&
ScriptRuntime.numberToString(d).equals(id) &&
this.length <= d && d != 4294967295.0)
this.length = (long)d + 1;
super.put(id, start, value);
}
public void put(int index, Scriptable start, Object value) {
// only set the array length if given an array index (ECMA 15.4.0)
if (this.length <= index) {
// avoid overflowing index!
this.length = (long)index + 1;
}
if (dense != null && 0 <= index && index < dense.length) {
dense[index] = value;
return;
}
super.put(index, start, value);
}
public void delete(int index) {
if (dense != null && 0 <= index && index < dense.length) {
dense[index] = NOT_FOUND;
return;
}
super.delete(index);
}
public Object[] getIds() {
Object[] superIds = super.getIds();
if (dense == null)
return superIds;
int count = 0;
int last = dense.length;
if (last > length)
last = (int) length;
for (int i=last-1; i >= 0; i--) {
if (dense[i] != NOT_FOUND)
count++;
}
count += superIds.length;
Object[] result = new Object[count];
System.arraycopy(superIds, 0, result, 0, superIds.length);
for (int i=last-1; i >= 0; i--) {
if (dense[i] != NOT_FOUND)
result[--count] = new Integer(i);
}
return result;
}
public Object getDefaultValue(Class hint) {
if (hint == ScriptRuntime.NumberClass) {
Context cx = Context.getContext();
if (cx.getLanguageVersion() == Context.VERSION_1_2)
return new Long(length);
}
return super.getDefaultValue(hint);
}
/**
* See ECMA 15.4.1,2
*/
public static Object js_Array(Context cx, Object[] args, Function ctorObj,
boolean inNewExpr)
throws JavaScriptException
{
if (!inNewExpr) {
// FunctionObject.construct will set up parent, proto
return ctorObj.construct(cx, ctorObj.getParentScope(), args);
}
if (args.length == 0)
return new NativeArray();
// Only use 1 arg as first element for version 1.2; for
// any other version (including 1.3) follow ECMA and use it as
// a length.
if (args.length == 1 && args[0] instanceof Number &&
cx.getLanguageVersion() != cx.VERSION_1_2)
{
return new NativeArray(ScriptRuntime.toUint32(args[0]));
}
// initialize array with arguments
return new NativeArray(args);
}
private static final int lengthAttr = ScriptableObject.DONTENUM |
ScriptableObject.PERMANENT;
public long js_getLength() {
return length;
}
public void js_setLength(Object val) {
/* XXX do we satisfy this?
* 15.4.5.1 [[Put]](P, V):
* 1. Call the [[CanPut]] method of A with name P.
* 2. If Result(1) is false, return.
* ?
*/
long longVal = ScriptRuntime.toUint32(val);
if (longVal < length) {
// remove all properties between longVal and length
if (length - longVal > 0x1000) {
// assume that the representation is sparse
Object[] e = getIds(); // will only find in object itself
for (int i=0; i < e.length; i++) {
if (e[i] instanceof String) {
// > MAXINT will appear as string
String id = (String) e[i];
double d = ScriptRuntime.toNumber(id);
if (d == d && d < length)
delete(id);
continue;
}
int index = ((Number) e[i]).intValue();
if (index >= longVal)
delete(index);
}
} else {
// assume a dense representation
for (long i=longVal; i < length; i++) {
// only delete if defined in the object itself
if (hasElem(this, i))
ScriptRuntime.delete(this, new Long(i));
}
}
}
length = longVal;
}
/* Support for generic Array-ish objects. Most of the Array
* functions try to be generic; anything that has a length
* property is assumed to be an array. hasLengthProperty is
* needed in addition to getLengthProperty, because
* getLengthProperty always succeeds - tries to convert strings, etc.
*/
static double getLengthProperty(Scriptable obj) {
// These will both give numeric lengths within Uint32 range.
if (obj instanceof NativeString)
return (double)((NativeString)obj).js_getLength();
if (obj instanceof NativeArray)
return (double)((NativeArray)obj).js_getLength();
return ScriptRuntime.toUint32(ScriptRuntime
.getProp(obj, "length", obj));
}
static boolean hasLengthProperty(Object obj) {
if (!(obj instanceof Scriptable) || obj == Context.getUndefinedValue())
return false;
if (obj instanceof NativeString || obj instanceof NativeArray)
return true;
Scriptable sobj = (Scriptable)obj;
// XXX some confusion as to whether or not to walk to get the length
// property. Pending review of js/[new ecma submission] treatment
// of 'arrayness'.
Object property = ScriptRuntime.getProp(sobj, "length", sobj);
return property instanceof Number;
}
/* Utility functions to encapsulate index > Integer.MAX_VALUE
* handling. Also avoids unnecessary object creation that would
* be necessary to use the general ScriptRuntime.get/setElem
* functions... though this is probably premature optimization.
*/
private static boolean hasElem(Scriptable target, long index) {
return index > Integer.MAX_VALUE
? target.has(Long.toString(index), target)
: target.has((int)index, target);
}
private static Object getElem(Scriptable target, long index) {
if (index > Integer.MAX_VALUE) {
String id = Long.toString(index);
return ScriptRuntime.getElem(target, id, target);
} else {
return ScriptRuntime.getElem(target, (int)index);
}
}
private static void setElem(Scriptable target, long index, Object value) {
if (index > Integer.MAX_VALUE) {
String id = Long.toString(index);
ScriptRuntime.setElem(target, id, value, target);
} else {
ScriptRuntime.setElem(target, (int)index, value);
}
}
public static String js_toString(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
return toStringHelper(cx, thisObj,
cx.getLanguageVersion() == cx.VERSION_1_2);
}
private static String toStringHelper(Context cx, Scriptable thisObj,
boolean toSource)
{
/* It's probably redundant to handle long lengths in this
* function; StringBuffers are limited to 2^31 in java.
*/
long length = (long)getLengthProperty(thisObj);
StringBuffer result = new StringBuffer();
if (cx.iterating == null)
cx.iterating = new Hashtable(31);
boolean iterating = cx.iterating.get(thisObj) == Boolean.TRUE;
// whether to return '4,unquoted,5' or '[4, "quoted", 5]'
String separator;
if (toSource) {
result.append("[");
separator = ", ";
} else {
separator = ",";
}
boolean haslast = false;
long i = 0;
if (!iterating) {
for (i = 0; i < length; i++) {
if (i > 0)
result.append(separator);
Object elem = getElem(thisObj, i);
if (elem == null || elem == Undefined.instance) {
haslast = false;
continue;
}
haslast = true;
if (elem instanceof String) {
if (toSource) {
result.append("\"");
result.append(ScriptRuntime.escapeString
(ScriptRuntime.toString(elem)));
result.append("\"");
} else {
result.append(ScriptRuntime.toString(elem));
}
} else {
/* wrap changes to cx.iterating in a try/finally
* so that the reference always gets removed, and
* we don't leak memory. Good place for weak
* references, if we had them. */
try {
// stop recursion.
cx.iterating.put(thisObj, Boolean.TRUE);
result.append(ScriptRuntime.toString(elem));
} finally {
cx.iterating.remove(thisObj);
}
}
}
}
if (toSource) {
//for [,,].length behavior; we want toString to be symmetric.
if (!haslast && i > 0)
result.append(", ]");
else
result.append("]");
}
return result.toString();
}
/**
* See ECMA 15.4.4.3
*/
public static String js_join(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
StringBuffer result = new StringBuffer();
String separator;
double length = getLengthProperty(thisObj);
// if no args, use "," as separator
if (args.length < 1) {
separator = ",";
} else {
separator = ScriptRuntime.toString(args[0]);
}
for (long i=0; i < length; i++) {
if (i > 0)
result.append(separator);
Object temp = getElem(thisObj, i);
if (temp == null || temp == Undefined.instance)
continue;
result.append(ScriptRuntime.toString(temp));
}
return result.toString();
}
/**
* See ECMA 15.4.4.4
*/
public static Scriptable js_reverse(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
long len = (long)getLengthProperty(thisObj);
long half = len / 2;
for(long i=0; i < half; i++) {
long j = len - i - 1;
Object temp1 = getElem(thisObj, i);
Object temp2 = getElem(thisObj, j);
setElem(thisObj, i, temp2);
setElem(thisObj, j, temp1);
}
return thisObj;
}
/**
* See ECMA 15.4.4.5
*/
public static Scriptable js_sort(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
throws JavaScriptException
{
long length = (long)getLengthProperty(thisObj);
Object compare;
if (args.length > 0 && Undefined.instance != args[0])
// sort with given compare function
compare = args[0];
else
// sort with default compare
compare = null;
// OPT: Would it make sense to use the extended sort for very small
// arrays?
// Should we use the extended sort function, or the faster one?
if (length >= Integer.MAX_VALUE) {
qsort_extended(cx, compare, thisObj, 0, length - 1);
} else {
// copy the JS array into a working array, so it can be
// sorted cheaply.
Object[] working = new Object[(int)length];
for (int i=0; i<length; i++) {
working[i] = getElem(thisObj, i);
}
qsort(cx, compare, working, 0, (int)length - 1);
// copy the working array back into thisObj
for (int i=0; i<length; i++) {
setElem(thisObj, i, working[i]);
}
}
return thisObj;
}
private static double qsortCompare(Context cx, Object jsCompare, Object x,
Object y)
throws JavaScriptException
{
Object undef = Undefined.instance;
// sort undefined to end
if (undef == x || undef == y) {
if (undef != x)
return -1;
if (undef != y)
return 1;
return 0;
}
if (jsCompare == null) {
// if no compare function supplied, sort lexicographically
String a = ScriptRuntime.toString(x);
String b = ScriptRuntime.toString(y);
return a.compareTo(b);
} else {
// assemble args and call supplied JS compare function
// OPT: put this argument creation in the caller and reuse it.
// XXX what to do when compare function returns NaN? ECMA states
// that it's then not a 'consistent compararison function'... but
// then what do we do? Back out and start over with the generic
// compare function when we see a NaN? Throw an error?
Object[] args = {x, y};
// return ScriptRuntime.toNumber(ScriptRuntime.call(jsCompare, null,
// args));
// for now, just ignore it:
double d = ScriptRuntime.
toNumber(ScriptRuntime.call(cx, jsCompare, null, args));
return (d == d) ? d : 0;
}
}
private static void qsort(Context cx, Object jsCompare, Object[] working,
int lo, int hi)
throws JavaScriptException
{
Object pivot;
int i, j;
int a, b;
while (lo < hi) {
i = lo;
j = hi;
a = i;
pivot = working[a];
while (i < j) {
for(;;) {
b = j;
if (qsortCompare(cx, jsCompare, working[j], pivot) <= 0)
break;
j--;
}
working[a] = working[b];
while (i < j && qsortCompare(cx, jsCompare, working[a],
pivot) <= 0)
{
i++;
a = i;
}
working[b] = working[a];
}
working[a] = pivot;
if (i - lo < hi - i) {
qsort(cx, jsCompare, working, lo, i - 1);
lo = i + 1;
} else {
qsort(cx, jsCompare, working, i + 1, hi);
hi = i - 1;
}
}
}
// A version that knows about long indices and doesn't use
// a working array. Probably will never be used.
private static void qsort_extended(Context cx, Object jsCompare,
Scriptable target, long lo, long hi)
throws JavaScriptException
{
Object pivot;
long i, j;
long a, b;
while (lo < hi) {
i = lo;
j = hi;
a = i;
pivot = getElem(target, a);
while (i < j) {
for(;;) {
b = j;
if (qsortCompare(cx, jsCompare, getElem(target, j),
pivot) <= 0)
break;
j--;
}
setElem(target, a, getElem(target, b));
while (i < j && qsortCompare(cx, jsCompare,
getElem(target, a), pivot) <= 0)
{
i++;
a = i;
}
setElem(target, b, getElem(target, a));
}
setElem(target, a, pivot);
if (i - lo < hi - i) {
qsort_extended(cx, jsCompare, target, lo, i - 1);
lo = i + 1;
} else {
qsort_extended(cx, jsCompare, target, i + 1, hi);
hi = i - 1;
}
}
}
/**
* Non-ECMA methods.
*/
public static Object js_push(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
double length = getLengthProperty(thisObj);
for (int i = 0; i < args.length; i++) {
setElem(thisObj, (long)length + i, args[i]);
}
length += args.length;
ScriptRuntime.setProp(thisObj, "length", new Double(length), thisObj);
/*
* If JS1.2, follow Perl4 by returning the last thing pushed.
* Otherwise, return the new array length.
*/
if (cx.getLanguageVersion() == Context.VERSION_1_2)
// if JS1.2 && no arguments, return undefined.
return args.length == 0
? Context.getUndefinedValue()
: args[args.length - 1];
else
return new Long((long)length);
}
public static Object js_pop(Context cx, Scriptable thisObj, Object[] args,
Function funObj)
{
Object result;
double length = getLengthProperty(thisObj);
if (length > 0) {
length--;
// Get the to-be-deleted property's value.
result = getElem(thisObj, (long)length);
// We don't need to delete the last property, because
// setLength does that for us.
} else {
result = Context.getUndefinedValue();
}
// necessary to match js even when length < 0; js pop will give a
// length property to any target it is called on.
ScriptRuntime.setProp(thisObj, "length", new Double(length), thisObj);
return result;
}
public static Object js_shift(Context cx, Scriptable thisObj, Object[] args,
Function funOjb)
{
Object result;
double length = getLengthProperty(thisObj);
if (length > 0) {
long i = 0;
length--;
// Get the to-be-deleted property's value.
result = getElem(thisObj, i);
/*
* Slide down the array above the first element. Leave i
* set to point to the last element.
*/
if (length > 0) {
for (i = 1; i <= length; i++) {
Object temp = getElem(thisObj, i);
setElem(thisObj, i - 1, temp);
}
}
// We don't need to delete the last property, because
// setLength does that for us.
} else {
result = Context.getUndefinedValue();
}
ScriptRuntime.setProp(thisObj, "length", new Double(length), thisObj);
return result;
}
public static Object js_unshift(Context cx, Scriptable thisObj,
Object[] args, Function funOjb)
{
Object result;
double length = (double)getLengthProperty(thisObj);
int argc = args.length;
if (args.length > 0) {
/* Slide up the array to make room for args at the bottom */
if (length > 0) {
for (long last = (long)length - 1; last >= 0; last--) {
Object temp = getElem(thisObj, last);
setElem(thisObj, last + argc, temp);
}
}
/* Copy from argv to the bottom of the array. */
for (int i = 0; i < args.length; i++) {
setElem(thisObj, i, args[i]);
}
/* Follow Perl by returning the new array length. */
length += args.length;
ScriptRuntime.setProp(thisObj, "length",
new Double(length), thisObj);
}
return new Long((long)length);
}
public static Object js_splice(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
/* create an empty Array to return. */
Scriptable scope = getTopLevelScope(funObj);
Object result = ScriptRuntime.newObject(cx, scope, "Array", null);
int argc = args.length;
if (argc == 0)
return result;
double length = getLengthProperty(thisObj);
/* Convert the first argument into a starting index. */
double begin = ScriptRuntime.toInteger(args[0]);
double end;
double delta;
double count;
if (begin < 0) {
begin += length;
if (begin < 0)
begin = 0;
} else if (begin > length) {
begin = length;
}
argc--;
/* Convert the second argument from a count into a fencepost index. */
delta = length - begin;
if (args.length == 1) {
count = delta;
end = length;
} else {
count = ScriptRuntime.toInteger(args[1]);
if (count < 0)
count = 0;
else if (count > delta)
count = delta;
end = begin + count;
argc--;
}
long lbegin = (long)begin;
long lend = (long)end;
/* If there are elements to remove, put them into the return value. */
if (count > 0) {
if (count == 1
&& (cx.getLanguageVersion() == Context.VERSION_1_2))
{
/*
* JS lacks "list context", whereby in Perl one turns the
* single scalar that's spliced out into an array just by
* assigning it to @single instead of $single, or by using it
* as Perl push's first argument, for instance.
*
* JS1.2 emulated Perl too closely and returned a non-Array for
* the single-splice-out case, requiring callers to test and
* wrap in [] if necessary. So JS1.3, default, and other
* versions all return an array of length 1 for uniformity.
*/
result = getElem(thisObj, lbegin);
} else {
for (long last = lbegin; last < lend; last++) {
Scriptable resultArray = (Scriptable)result;
Object temp = getElem(thisObj, last);
setElem(resultArray, last - lbegin, temp);
}
}
} else if (count == 0
&& cx.getLanguageVersion() == Context.VERSION_1_2)
{
/* Emulate C JS1.2; if no elements are removed, return undefined. */
result = Context.getUndefinedValue();
}
/* Find the direction (up or down) to copy and make way for argv. */
delta = argc - count;
if (delta > 0) {
for (long last = (long)length - 1; last >= lend; last--) {
Object temp = getElem(thisObj, last);
setElem(thisObj, last + (long)delta, temp);
}
} else if (delta < 0) {
for (long last = lend; last < length; last++) {
Object temp = getElem(thisObj, last);
setElem(thisObj, last + (long)delta, temp);
}
}
/* Copy from argv into the hole to complete the splice. */
int argoffset = args.length - argc;
for (int i = 0; i < argc; i++) {
setElem(thisObj, lbegin + i, args[i + argoffset]);
}
/* Update length in case we deleted elements from the end. */
ScriptRuntime.setProp(thisObj, "length",
new Double(length + delta), thisObj);
return result;
}
/*
* Python-esque sequence operations.
*/
public static Scriptable js_concat(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
/* Concat tries to keep the definition of an array as general
* as possible; if it finds that an object has a numeric
* 'length' property, then it treats that object as an array.
* This treats string atoms and string objects differently; as
* string objects have a length property and are accessible by
* index, they get exploded into arrays when added, while
* atomic strings are just added as strings.
*/
// create an empty Array to return.
Scriptable scope = getTopLevelScope(funObj);
Scriptable result = ScriptRuntime.newObject(cx, scope, "Array", null);
double length;
long slot = 0;
/* Put the target in the result array; only add it as an array
* if it looks like one.
*/
if (hasLengthProperty(thisObj)) {
length = getLengthProperty(thisObj);
// Copy from the target object into the result
for (slot = 0; slot < length; slot++) {
Object temp = getElem(thisObj, slot);
setElem(result, slot, temp);
}
} else {
setElem(result, slot++, thisObj);
}
/* Copy from the arguments into the result. If any argument
* has a numeric length property, treat it as an array and add
* elements separately; otherwise, just copy the argument.
*/
for (int i = 0; i < args.length; i++) {
if (hasLengthProperty(args[i])) {
// hasLengthProperty => instanceOf Scriptable.
Scriptable arg = (Scriptable)args[i];
length = getLengthProperty(arg);
for (long j = 0; j < length; j++, slot++) {
Object temp = getElem(arg, j);
setElem(result, slot, temp);
}
} else {
setElem(result, slot++, args[i]);
}
}
return result;
}
public static Scriptable js_slice(Context cx, Scriptable thisObj,
Object[] args, Function funObj)
{
Scriptable scope = getTopLevelScope(funObj);
Scriptable result = ScriptRuntime.newObject(cx, scope, "Array", null);
double length = getLengthProperty(thisObj);
double begin = 0;
double end = length;
if (args.length > 0) {
begin = ScriptRuntime.toInteger(args[0]);
if (begin < 0) {
begin += length;
if (begin < 0)
begin = 0;
} else if (begin > length) {
begin = length;
}
if (args.length > 1) {
end = ScriptRuntime.toInteger(args[1]);
if (end < 0) {
end += length;
if (end < 0)
end = 0;
} else if (end > length) {
end = length;
}
}
}
long lbegin = (long)begin;
long lend = (long)end;
for (long slot = lbegin; slot < lend; slot++) {
Object temp = getElem(thisObj, slot);
setElem(result, slot - lbegin, temp);
}
return result;
}
private long length;
private Object[] dense;
private static final int maximumDenseLength = 10000;
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше