Removing copies of Rhino code

git-svn-id: svn://10.0.0.236/trunk@29406 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
rogerl%netscape.com 1999-04-27 06:23:48 +00:00
parent aed1ccc028
commit dda3ccddad
14 changed files with 0 additions and 3698 deletions

View File

@ -1,43 +0,0 @@
/* -*- Mode: java; tab-width: 8 -*-
* Copyright © 1997, 1998 Netscape Communications Corporation,
* All Rights Reserved.
*/
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;
}
}

View File

@ -1,79 +0,0 @@
import java.util.Hashtable;
class Context {
static boolean printTrees = true;
public static final int VERSION_DEFAULT = 0;
public static final int VERSION_1_2 = 120;
public Context() {
setLanguageVersion(VERSION_DEFAULT);
}
public synchronized void enter() throws ThreadLinkException,
InterruptedException
{
Thread t = Thread.currentThread();
while (currentThread != null) {
// Check to avoid deadlock
if (t == currentThread) {
throw new ThreadLinkException(
"Context already associated with a Thread");
}
wait();
}
currentThread = t;
synchronized (threadContexts) {
Context cx = (Context) threadContexts.get(t);
if (cx != null) {
currentThread = null;
throw new ThreadLinkException(
"Thread already associated with a Context");
}
threadContexts.put(t, this);
}
}
static Context getContext() {
Thread t = Thread.currentThread();
Context cx = (Context) threadContexts.get(t);
if (cx == null) {
throw new WrappedException(new ThreadLinkException(
"No Context associated with current Thread"));
}
return cx;
}
public void setLanguageVersion(int version) {
this.version = version;
}
public int getLanguageVersion() {
return version;
}
int version;
static String getMessage(String messageId, Object[] arguments)
{
return messageId;
}
static void reportError(String message, String sourceName,
int lineno, String lineSource,
int lineOffset)
{
}
static void reportWarning(String message, String sourceName,
int lineno, String lineSource,
int lineOffset)
{
}
private Thread currentThread;
private static Hashtable threadContexts = new Hashtable(11);
};

View File

@ -1,18 +0,0 @@
/* -*- Mode: java; tab-width: 8 -*-
* Copyright © 1998 Netscape Communications Corporation,
* All Rights Reserved.
*/
import java.util.*;
public class FunctionNode extends Node {
public FunctionNode(String name, Node left, Node right) {
super(TokenStream.FUNCTION, left, right, name);
}
public String getFunctionName() {
return getString();
}
}

View File

@ -1,994 +0,0 @@
/* -*- Mode: java; tab-width: 8 -*-
* Copyright © 1997, 1998 Netscape Communications Corporation,
* All Rights Reserved.
*/
/**
* This class allows the creation of nodes, and follows the Factory pattern.
*
* @see Node
* @see NodeFactory
* @see ASTFactory
* @author Mike McCabe
* @author Norris Boyd
*/
public class IRFactory {
public IRFactory(TokenStream ts) {
this.ts = ts;
}
/**
* Script (for associating file/url names with toplevel scripts.)
*/
public Object createScript(Object body, String sourceName,
int baseLineno, int endLineno, Object source)
{
Node result = new Node(TokenStream.SCRIPT, sourceName);
Node children = ((Node) body).getFirstChild();
if (children != null)
result.addChildrenToBack(children);
result.putProp(Node.SOURCENAME_PROP, sourceName);
result.putProp(Node.BASE_LINENO_PROP, new Integer(baseLineno));
result.putProp(Node.END_LINENO_PROP, new Integer(endLineno));
if (source != null)
result.putProp(Node.SOURCE_PROP, source);
return result;
}
/**
* Leaf
*/
public Object createLeaf(int nodeType) {
return new Node(nodeType);
}
public Object createLeaf(int nodeType, String id) {
return new Node(nodeType, id);
}
public Object createLeaf(int nodeType, int nodeOp) {
return new Node(nodeType, new Integer(nodeOp));
}
/**
* Statement leaf nodes.
*/
public Object createSwitch(int lineno) {
return new Node(TokenStream.SWITCH, new Integer(lineno));
}
public Object createVariables(int lineno) {
return new Node(TokenStream.VAR, new Integer(lineno));
}
public Object createExprStatement(Object expr, int lineno) {
return new Node(TokenStream.EXPRSTMT, (Node) expr, new Integer(lineno));
}
/**
* Name
*/
public Object createName(String name) {
return new Node(TokenStream.NAME, name);
}
/**
* String (for literals)
*/
public Object createString(String string) {
return new Node(TokenStream.STRING, string);
}
/**
* Number (for literals)
*/
public Object createNumber(Number number) {
return new Node(TokenStream.NUMBER, number);
}
/**
* Catch clause of try/catch/finally
* @param varName the name of the variable to bind to the exception
* @param catchCond the condition under which to catch the exception.
* May be null if no condition is given.
* @param stmts the statements in the catch clause
* @param lineno the starting line number of the catch clause
*/
public Object createCatch(String varName, Object catchCond, Object stmts,
int lineno)
{
if (catchCond == null)
catchCond = new Node(TokenStream.PRIMARY,
new Integer(TokenStream.TRUE));
Node result = new Node(TokenStream.CATCH, (Node)createName(varName),
(Node)catchCond, (Node)stmts);
result.setDatum(new Integer(lineno));
return result;
}
/**
* Throw
*/
public Object createThrow(Object expr, int lineno) {
return new Node(TokenStream.THROW, (Node)expr, new Integer(lineno));
}
/**
* Return
*/
public Object createReturn(Object expr, int lineno) {
return expr == null
? new Node(TokenStream.RETURN, new Integer(lineno))
: new Node(TokenStream.RETURN, (Node)expr, new Integer(lineno));
}
/**
* Label
*/
public Object createLabel(String label, int lineno) {
Node result = new Node(TokenStream.LABEL, new Integer(lineno));
Node name = new Node(TokenStream.NAME, label);
result.addChildToBack(name);
return result;
}
/**
* Break (possibly labeled)
*/
public Object createBreak(String label, int lineno) {
Node result = new Node(TokenStream.BREAK, new Integer(lineno));
if (label == null) {
return result;
} else {
Node name = new Node(TokenStream.NAME, label);
result.addChildToBack(name);
return result;
}
}
/**
* Continue (possibly labeled)
*/
public Object createContinue(String label, int lineno) {
Node result = new Node(TokenStream.CONTINUE, new Integer(lineno));
if (label == null) {
return result;
} else {
Node name = new Node(TokenStream.NAME, label);
result.addChildToBack(name);
return result;
}
}
/**
* Statement block
* Creates the empty statement block
* Must make subsequent calls to add statements to the node
*/
public Object createBlock(int lineno) {
return new Node(TokenStream.BLOCK, new Integer(lineno));
}
public Object createFunctionNode(String name, Object args,
Object statements)
{
if (name == null)
name = "";
return new FunctionNode(name, (Node) args, (Node) statements);
}
public Object createFunction(String name, Object args, Object statements,
String sourceName, int baseLineno,
int endLineno, Object source)
{
Node f = (Node) createFunctionNode(name, args, statements);
f.putProp(Node.SOURCENAME_PROP, sourceName);
f.putProp(Node.BASE_LINENO_PROP, new Integer(baseLineno));
f.putProp(Node.END_LINENO_PROP, new Integer(endLineno));
if (source != null)
f.putProp(Node.SOURCE_PROP, source);
Node result = new Node(TokenStream.FUNCTION, name);
result.putProp(Node.FUNCTION_PROP, f);
return result;
}
/**
* Add a child to the back of the given node. This function
* breaks the Factory abstraction, but it removes a requirement
* from implementors of Node.
*/
public void addChildToBack(Object parent, Object child) {
((Node)parent).addChildToBack((Node)child);
}
/**
* While
*/
public Object createWhile(Object cond, Object body, int lineno) {
// Just add a GOTO to the condition in the do..while
Node result = (Node) createDoWhile(body, cond, lineno);
Node condTarget = (Node) result.getProp(Node.CONTINUE_PROP);
Node GOTO = new Node(TokenStream.GOTO);
GOTO.putProp(Node.TARGET_PROP, condTarget);
result.addChildToFront(GOTO);
return result;
}
/**
* DoWhile
*/
public Object createDoWhile(Object body, Object cond, int lineno) {
Node result = new Node(TokenStream.LOOP, new Integer(lineno));
Node bodyTarget = new Node(TokenStream.TARGET);
Node condTarget = new Node(TokenStream.TARGET);
Node IFEQ = new Node(TokenStream.IFEQ, (Node)cond);
IFEQ.putProp(Node.TARGET_PROP, bodyTarget);
Node breakTarget = new Node(TokenStream.TARGET);
result.addChildToBack(bodyTarget);
result.addChildrenToBack((Node)body);
result.addChildToBack(condTarget);
result.addChildToBack(IFEQ);
result.addChildToBack(breakTarget);
result.putProp(Node.BREAK_PROP, breakTarget);
result.putProp(Node.CONTINUE_PROP, condTarget);
return result;
}
/**
* For
*/
public Object createFor(Object init, Object test, Object incr,
Object body, int lineno)
{
if (((Node) test).getType() == TokenStream.VOID) {
test = new Node(TokenStream.PRIMARY,
new Integer(TokenStream.TRUE));
}
Node result = (Node)createWhile(test, body, lineno);
Node initNode = (Node) init;
if (initNode.getType() != TokenStream.VOID) {
if (initNode.getType() != TokenStream.VAR)
initNode = new Node(TokenStream.POP, initNode);
result.addChildToFront(initNode);
}
Node condTarget = (Node)result.getProp(Node.CONTINUE_PROP);
Node incrTarget = new Node(TokenStream.TARGET);
result.addChildBefore(incrTarget, condTarget);
if (((Node) incr).getType() != TokenStream.VOID) {
incr = createUnary(TokenStream.POP, incr);
result.addChildAfter((Node)incr, incrTarget);
}
result.putProp(Node.CONTINUE_PROP, incrTarget);
return result;
}
/**
* For .. In
*
*/
public Object createForIn(Object lhs, Object obj, Object body, int lineno) {
String name;
Node lhsNode = (Node) lhs;
Node objNode = (Node) obj;
int type = lhsNode.getType();
Node lvalue = lhsNode;
switch (type) {
case TokenStream.NAME:
case TokenStream.GETPROP:
case TokenStream.GETELEM:
break;
case TokenStream.VAR:
/*
* check that there was only one variable given.
* we can't do this in the parser, because then the
* parser would have to know something about the
* 'init' node of the for-in loop.
*/
Node lastChild = lhsNode.getLastChild();
if (lhsNode.getFirstChild() != lastChild) {
reportError("msg.mult.index");
}
lvalue = new Node(TokenStream.NAME, lastChild.getString());
break;
default:
reportError("msg.bad.for.in.lhs");
return objNode;
}
Node init = new Node(TokenStream.ENUMINIT, objNode);
Node next = new Node(TokenStream.ENUMNEXT);
next.putProp(Node.ENUM_PROP, init);
Node temp = createNewTemp(next);
Node cond = new Node(TokenStream.EQOP, new Integer(TokenStream.NE));
cond.addChildToBack(temp);
cond.addChildToBack(new Node(TokenStream.PRIMARY,
new Integer(TokenStream.NULL)));
Node newBody = new Node(TokenStream.BLOCK);
Node assign = (Node) createAssignment(TokenStream.NOP, lvalue,
createUseTemp(temp), null,
false);
newBody.addChildToBack(new Node(TokenStream.POP, assign));
newBody.addChildToBack((Node) body);
Node result = (Node) createWhile(cond, newBody, lineno);
result.addChildToFront(init);
if (type == TokenStream.VAR)
result.addChildToFront(lhsNode);
Node done = new Node(TokenStream.ENUMDONE);
done.putProp(Node.ENUM_PROP, init);
result.addChildToBack(done);
return result;
}
/**
* Try/Catch/Finally
*
* The IRFactory tries to express as much as possible in the tree;
* the responsibilities remaining for Codegen are to add the Java
* handlers: (Either (but not both) of TARGET and FINALLY might not
* be defined)
* - a catch handler for javascript exceptions that unwraps the
* exception onto the stack and GOTOes to the catch target -
* TARGET_PROP in the try node.
* - a finally handler that catches any exception, stores it to a
* temporary, and JSRs to the finally target - FINALLY_PROP in the
* try node - before re-throwing the exception.
* ... and a goto to GOTO around these handlers.
*/
public Object createTryCatchFinally(Object tryblock, Object catchblocks,
Object finallyblock, int lineno)
{
Node trynode = (Node)tryblock;
// short circuit
if (trynode.getType() == TokenStream.BLOCK && !trynode.hasChildren())
return trynode;
Node pn = new Node(TokenStream.TRY, trynode, new Integer(lineno));
Node catchNodes = (Node)catchblocks;
boolean hasCatch = catchNodes.hasChildren();
boolean hasFinally = false;
Node finallyNode = null;
Node finallyTarget = null;
if (finallyblock != null) {
finallyNode = (Node)finallyblock;
hasFinally = (finallyNode.getType() != TokenStream.BLOCK
|| finallyNode.hasChildren());
if (hasFinally) {
// make a TARGET for the finally that the tcf node knows about
finallyTarget = new Node(TokenStream.TARGET);
pn.putProp(Node.FINALLY_PROP, finallyTarget);
// add jsr finally to the try block
Node jsrFinally = new Node(TokenStream.JSR);
jsrFinally.putProp(Node.TARGET_PROP, finallyTarget);
pn.addChildToBack(jsrFinally);
}
}
// short circuit
if (!hasFinally && !hasCatch) // bc finally might be an empty block...
return trynode;
Node endTarget = new Node(TokenStream.TARGET);
Node GOTOToEnd = new Node(TokenStream.GOTO);
GOTOToEnd.putProp(Node.TARGET_PROP, endTarget);
pn.addChildToBack(GOTOToEnd);
if (hasCatch) {
/*
*
Given
try {
throw 3;
} catch (e: e instanceof Object) {
print("object");
} catch (e2) {
print(e2);
}
rewrite as
try {
throw 3;
} catch (x) {
o = newScope();
o.e = x;
with (o) {
if (e instanceof Object) {
print("object");
}
}
o2 = newScope();
o2.e2 = x;
with (o2) {
if (true) {
print(e2);
}
}
}
*/
// make a TARGET for the catch that the tcf node knows about
Node catchTarget = new Node(TokenStream.TARGET);
pn.putProp(Node.TARGET_PROP, catchTarget);
// mark it
pn.addChildToBack(catchTarget);
// get the exception object and store it in a temp
Node exn = createNewLocal(new Node(TokenStream.VOID));
pn.addChildToBack(new Node(TokenStream.POP, exn));
Node endCatch = new Node(TokenStream.TARGET);
// add [jsr finally?] goto end to each catch block
// expects catchNode children to be (cond block) pairs.
Node cb = catchNodes.getFirstChild();
while (cb != null) {
Node catchStmt = new Node(TokenStream.BLOCK);
int catchLineNo = ((Integer)cb.getDatum()).intValue();
Node name = cb.getFirstChild();
Node cond = name.getNextSibling();
Node catchBlock = cond.getNextSibling();
cb.removeChild(name);
cb.removeChild(cond);
cb.removeChild(catchBlock);
Node newScope = createNewLocal(new Node(TokenStream.NEWSCOPE));
Node initScope = new Node(TokenStream.SETPROP, newScope,
new Node(TokenStream.STRING,
name.getString()),
createUseLocal(exn));
catchStmt.addChildToBack(new Node(TokenStream.POP, initScope));
catchBlock.addChildToBack(new Node(TokenStream.LEAVEWITH));
Node GOTOToEndCatch = new Node(TokenStream.GOTO);
GOTOToEndCatch.putProp(Node.TARGET_PROP, endCatch);
catchBlock.addChildToBack(GOTOToEndCatch);
Node ifStmt = (Node) createIf(cond, catchBlock, null, catchLineNo);
// Try..catch produces "with" code in order to limit
// the scope of the exception object.
// OPT: We should be able to figure out the correct
// scoping at compile-time and avoid the
// runtime overhead.
Node withStmt = (Node) createWith(createUseLocal(newScope),
ifStmt, catchLineNo);
catchStmt.addChildToBack(withStmt);
pn.addChildToBack(catchStmt);
// move to next cb
cb = cb.getNextSibling();
}
// Generate code to rethrow if no catch clause was executed
Node rethrow = new Node(TokenStream.THROW, createUseLocal(exn));
pn.addChildToBack(rethrow);
pn.addChildToBack(endCatch);
// add a JSR finally if needed
if (hasFinally) {
Node jsrFinally = new Node(TokenStream.JSR);
jsrFinally.putProp(Node.TARGET_PROP, finallyTarget);
pn.addChildToBack(jsrFinally);
Node GOTO = new Node(TokenStream.GOTO);
GOTO.putProp(Node.TARGET_PROP, endTarget);
pn.addChildToBack(GOTO);
}
}
if (hasFinally) {
pn.addChildToBack(finallyTarget);
Node returnTemp = createNewLocal(new Node(TokenStream.VOID));
Node popAndMake = new Node(TokenStream.POP, returnTemp);
pn.addChildToBack(popAndMake);
pn.addChildToBack(finallyNode);
Node ret = createUseLocal(returnTemp);
// add the magic prop that makes it output a RET
ret.putProp(Node.TARGET_PROP, Boolean.TRUE);
pn.addChildToBack(ret);
}
pn.addChildToBack(endTarget);
return pn;
}
/**
* Throw, Return, Label, Break and Continue are defined in ASTFactory.
*/
/**
* With
*/
public Object createWith(Object obj, Object body, int lineno) {
Node result = new Node(TokenStream.BLOCK, new Integer(lineno));
result.addChildToBack(new Node(TokenStream.ENTERWITH, (Node)obj));
Node bodyNode = new Node(TokenStream.WITH, (Node) body,
new Integer(lineno));
result.addChildrenToBack(bodyNode);
result.addChildToBack(new Node(TokenStream.LEAVEWITH));
return result;
}
/**
* Array Literal
* <BR>createArrayLiteral rewrites its argument as array creation
* plus a series of array element entries, so later compiler
* stages don't need to know about array literals.
*/
public Object createArrayLiteral(Object obj) {
Node array;
Node result;
array = result = new Node(TokenStream.NEW,
new Node(TokenStream.NAME, "Array"));
Node temp = createNewTemp(result);
result = temp;
java.util.Enumeration children = ((Node) obj).getChildIterator();
Node elem = null;
int i = 0;
while (children.hasMoreElements()) {
elem = (Node) children.nextElement();
if (elem.getType() == TokenStream.PRIMARY &&
elem.getInt() == TokenStream.UNDEFINED)
{
i++;
continue;
}
Node addelem = new Node(TokenStream.SETELEM, createUseTemp(temp),
new Node(TokenStream.NUMBER,
new Integer(i)),
elem);
i++;
result = new Node(TokenStream.COMMA, result, addelem);
}
/*
* If the version is 120, then new Array(4) means create a new
* array with 4 as the first element. In this case, we might
* need to explicitly check against trailing undefined
* elements in the array literal, and set the length manually
* if these occur. Otherwise, we can add an argument to the
* node specifying new Array() to provide the array length.
* (Which will make Array optimizations involving allocating a
* Java array to back the javascript array work better.)
*/
if (Context.getContext().getLanguageVersion() == Context.VERSION_1_2) {
/* When last array element is empty, we need to set the
* length explicitly, because we can't depend on SETELEM
* to do it for us - because empty [,,] array elements
* never set anything at all. */
if (elem != null &&
elem.getType() == TokenStream.PRIMARY &&
elem.getInt() == TokenStream.UNDEFINED)
{
Node setlength = new Node(TokenStream.SETPROP,
createUseTemp(temp),
new Node(TokenStream.STRING,
"length"),
new Node(TokenStream.NUMBER,
new Integer(i)));
result = new Node(TokenStream.COMMA, result, setlength);
}
} else {
array.addChildToBack(new Node(TokenStream.NUMBER,
new Integer(i)));
}
return new Node(TokenStream.COMMA, result, createUseTemp(temp));
}
/**
* Object Literals
* <BR> createObjectLiteral rewrites its argument as object
* creation plus object property entries, so later compiler
* stages don't need to know about object literals.
*/
public Object createObjectLiteral(Object obj) {
Node result = new Node(TokenStream.NEW, new Node(TokenStream.NAME,
"Object"));
Node temp = createNewTemp(result);
result = temp;
java.util.Enumeration children = ((Node) obj).getChildIterator();
while (children.hasMoreElements()) {
Node elem = (Node)children.nextElement();
int op = (elem.getType() == TokenStream.NAME)
? TokenStream.SETPROP
: TokenStream.SETELEM;
Node addelem = new Node(op, createUseTemp(temp),
elem, (Node)children.nextElement());
result = new Node(TokenStream.COMMA, result, addelem);
}
return new Node(TokenStream.COMMA, result, createUseTemp(temp));
}
/**
* Regular expressions
*/
public Object createRegExp(String string, String flags) {
return flags.length() == 0
? new Node(TokenStream.OBJECT,
new Node(TokenStream.STRING, string))
: new Node(TokenStream.OBJECT,
new Node(TokenStream.STRING, string),
new Node(TokenStream.STRING, flags));
}
/**
* If statement
*/
public Object createIf(Object cond, Object ifTrue, Object ifFalse,
int lineno)
{
Node result = new Node(TokenStream.BLOCK, new Integer(lineno));
Node ifNotTarget = new Node(TokenStream.TARGET);
Node IFNE = new Node(TokenStream.IFNE, (Node) cond);
IFNE.putProp(Node.TARGET_PROP, ifNotTarget);
result.addChildToBack(IFNE);
result.addChildrenToBack((Node)ifTrue);
if (ifFalse != null) {
Node GOTOToEnd = new Node(TokenStream.GOTO);
Node endTarget = new Node(TokenStream.TARGET);
GOTOToEnd.putProp(Node.TARGET_PROP, endTarget);
result.addChildToBack(GOTOToEnd);
result.addChildToBack(ifNotTarget);
result.addChildrenToBack((Node)ifFalse);
result.addChildToBack(endTarget);
} else {
result.addChildToBack(ifNotTarget);
}
return result;
}
public Object createTernary(Object cond, Object ifTrue, Object ifFalse) {
return createIf(cond, ifTrue, ifFalse, -1);
}
/**
* Unary
*/
public Object createUnary(int nodeType, Object child) {
Node childNode = (Node) child;
if (nodeType == TokenStream.DELPROP) {
int childType = childNode.getType();
Node left;
Node right;
if (childType == TokenStream.NAME) {
// Transform Delete(Name "a")
// to Delete(Bind("a"), String("a"))
childNode.setType(TokenStream.BINDNAME);
left = childNode;
right = childNode.cloneNode();
right.setType(TokenStream.STRING);
} else if (childType == TokenStream.GETPROP ||
childType == TokenStream.GETELEM)
{
left = childNode.getFirstChild();
right = childNode.getLastChild();
childNode.removeChild(left);
childNode.removeChild(right);
} else {
reportError("msg.del.nonref");
return new Node(TokenStream.PRIMARY,
new Integer(TokenStream.TRUE));
}
return new Node(nodeType, left, right);
}
return new Node(nodeType, childNode);
}
public Object createUnary(int nodeType, int nodeOp, Object child) {
Node childNode = (Node) child;
int childType = childNode.getType();
if (nodeOp == TokenStream.TYPEOF &&
childType == TokenStream.NAME)
{
childNode.setType(TokenStream.TYPEOF);
return childNode;
}
if (nodeType == TokenStream.INC || nodeType == TokenStream.DEC) {
if (!hasSideEffects(childNode)
&& (nodeOp == TokenStream.POST)
&& (childType == TokenStream.NAME
|| childType == TokenStream.GETPROP
|| childType == TokenStream.GETELEM))
{
// if it's not a LHS type, createAssignment (below) will throw
// an exception.
return new Node(nodeType, childNode);
}
/*
* Transform INC/DEC ops to +=1, -=1,
* expecting later optimization of all +/-=1 cases to INC, DEC.
*/
// we have to use Double for now, because
// 0.0 and 1.0 are stored as dconst_[01],
// and using a Float creates a stack mismatch.
Node rhs = (Node) createNumber(new Double(1.0));
return createAssignment(nodeType == TokenStream.INC
? TokenStream.ADD
: TokenStream.SUB,
childNode,
rhs,
ScriptRuntime.NumberClass,
nodeOp == TokenStream.POST);
}
Node result = new Node(nodeType, new Integer(nodeOp));
result.addChildToBack((Node)child);
return result;
}
/**
* Binary
*/
public Object createBinary(int nodeType, Object left, Object right) {
Node temp;
switch (nodeType) {
case TokenStream.DOT:
nodeType = TokenStream.GETPROP;
Node idNode = (Node) right;
idNode.setType(TokenStream.STRING);
String id = idNode.getString();
if (id.equals("__proto__") || id.equals("__parent__")) {
Node result = new Node(nodeType, (Node) left);
result.putProp(Node.SPECIAL_PROP_PROP, id);
return result;
}
break;
case TokenStream.LB:
// OPT: could optimize to GETPROP iff string can't be a number
nodeType = TokenStream.GETELEM;
break;
/*
case TokenStream.AND:
temp = createNewTemp((Node) left);
return createTernary(temp, right, createUseTemp(temp));
case TokenStream.OR:
temp = createNewTemp((Node) left);
return createTernary(temp, createUseTemp(temp), right);
*/
}
return new Node(nodeType, (Node)left, (Node)right);
}
public Object createBinary(int nodeType, int nodeOp, Object left,
Object right)
{
if (nodeType == TokenStream.ASSIGN) {
return createAssignment(nodeOp, (Node) left, (Node) right,
null, false);
}
return new Node(nodeType, (Node) left, (Node) right,
new Integer(nodeOp));
}
public Object createAssignment(int nodeOp, Node left, Node right,
Class convert, boolean postfix)
{
int nodeType = left.getType();
String idString;
Node id = null;
switch (nodeType) {
case TokenStream.NAME:
return createSetName(nodeOp, left, right, convert, postfix);
case TokenStream.GETPROP:
idString = (String) left.getProp(Node.SPECIAL_PROP_PROP);
if (idString != null)
id = new Node(TokenStream.STRING, idString);
/* fall through */
case TokenStream.GETELEM:
if (id == null)
id = left.getLastChild();
return createSetProp(nodeType, nodeOp, left.getFirstChild(),
id, right, convert, postfix);
default:
reportError("msg.bad.lhs.assign");
return left;
}
}
private Node createConvert(Class toType, Node expr) {
if (toType == null)
return expr;
Node result = new Node(TokenStream.CONVERT, expr);
result.putProp(Node.TYPE_PROP, ScriptRuntime.NumberClass);
return result;
}
private Object createSetName(int nodeOp, Node left, Node right,
Class convert, boolean postfix)
{
if (nodeOp == TokenStream.NOP) {
left.setType(TokenStream.BINDNAME);
return new Node(TokenStream.SETNAME, left, right);
}
String s = left.getString();
if (s.equals("__proto__") || s.equals("__parent__")) {
Node result = new Node(TokenStream.SETPROP, left, right);
result.putProp(Node.SPECIAL_PROP_PROP, s);
return result;
}
Node opLeft = new Node(TokenStream.NAME, s);
if (convert != null)
opLeft = createConvert(convert, opLeft);
if (postfix)
opLeft = createNewTemp(opLeft);
Node op = new Node(nodeOp, opLeft, right);
Node lvalueLeft = new Node(TokenStream.BINDNAME, s);
Node result = new Node(TokenStream.SETNAME, lvalueLeft, op);
if (postfix) {
result = new Node(TokenStream.COMMA, result,
createUseTemp(opLeft));
}
return result;
}
public Node createNewTemp(Node n) {
int type = n.getType();
if (type == TokenStream.STRING || type == TokenStream.NUMBER) {
// Optimization: clone these values rather than storing
// and loading from a temp
return n;
}
Node result = new Node(TokenStream.NEWTEMP, n);
return result;
}
public Node createUseTemp(Node newTemp) {
int type = newTemp.getType();
if (type == TokenStream.NEWTEMP) {
Node result = new Node(TokenStream.USETEMP);
result.putProp(Node.TEMP_PROP, newTemp);
Integer n = (Integer) newTemp.getProp(Node.USES_PROP);
if (n == null) {
n = new Integer(1);
} else {
if (n.intValue() < Integer.MAX_VALUE)
n = new Integer(n.intValue() + 1);
}
newTemp.putProp(Node.USES_PROP, n);
return result;
}
return newTemp.cloneNode();
}
public Node createNewLocal(Node n) {
Node result = new Node(TokenStream.NEWLOCAL, n);
return result;
}
public Node createUseLocal(Node newLocal) {
int type = newLocal.getType();
if (type == TokenStream.NEWLOCAL) {
Node result = new Node(TokenStream.USELOCAL);
result.putProp(Node.LOCAL_PROP, newLocal);
return result;
}
return newLocal.cloneNode(); // what's this path for ?
}
public static boolean hasSideEffects(Node exprTree) {
switch (exprTree.getType()) {
case TokenStream.SETPROP:
case TokenStream.SETELEM:
case TokenStream.CALL:
case TokenStream.NEW:
return true;
default:
Node child = exprTree.getFirstChild();
while (child != null) {
if (hasSideEffects(child))
return true;
else
child = child.getNextSibling();
}
break;
}
return false;
}
private Node createSetProp(int nodeType, int nodeOp, Node obj, Node id,
Node expr, Class convert, boolean postfix)
{
int type = nodeType == TokenStream.GETPROP
? TokenStream.SETPROP
: TokenStream.SETELEM;
Object datum = id.getDatum();
if (type == TokenStream.SETPROP && datum != null &&
datum instanceof String)
{
String s = (String) datum;
if (s.equals("__proto__") || s.equals("__parent__")) {
Node result = new Node(type, obj, expr);
result.putProp(Node.SPECIAL_PROP_PROP, s);
return result;
}
}
if (nodeOp == TokenStream.NOP)
return new Node(type, obj, id, expr);
/*
if the RHS expression could modify the LHS we have
to construct a temporary to hold the LHS context
prior to running the expression
*/
Node tmp1, tmp2, opLeft;
if (hasSideEffects(expr) || (obj.getType() != TokenStream.NAME)) {
tmp1 = createNewTemp(obj);
Node useTmp1 = createUseTemp(tmp1);
tmp2 = createNewTemp(id);
Node useTmp2 = createUseTemp(tmp2);
opLeft = new Node(nodeType, useTmp1, useTmp2);
} else {
tmp1 = obj.cloneNode();
tmp2 = id.cloneNode();
opLeft = new Node(nodeType, obj, id);
}
if (convert != null)
opLeft = createConvert(convert, opLeft);
if (postfix)
opLeft = createNewTemp(opLeft);
Node op = new Node(nodeOp, opLeft, expr);
Node result = new Node(type, tmp1, tmp2, op);
if (postfix) {
result = new Node(TokenStream.COMMA, result,
createUseTemp(opLeft));
}
return result;
}
private void reportError(String msgResource) {
String message = Context.getMessage(msgResource, null);
Context.reportError(message, ts.getSourceName(), ts.getLineno(),
ts.getLine(), ts.getOffset());
}
// Only needed to get file/line information. Could create an interface
// that TokenStream implements if we want to make the connection less
// direct.
private TokenStream ts;
}

View File

@ -1,35 +0,0 @@
public class Interpreter {
void executeScript(Node node)
{
Node child = node.getFirstChild();
while (child != null) {
if (child.getType() != TokenStream.FUNCTION)
executeCode(child);
child = child.getNextSibling();
}
}
void executeCode(Node top)
{
PostorderNodeIterator ni = new PostorderNodeIterator(top);
JSStack theStack = new JSStack();
Node n = ni.nextNode();
while (n != null) {
ni = n.execute(theStack, ni);
n = ni.nextNode();
}
while (!theStack.isEmpty()) {
System.out.println("Stack Slot contains " + theStack.pop());
}
}
}

View File

@ -1,39 +0,0 @@
import java.util.Stack;
class JSStack {
Stack stack = new Stack();
int frameTop;
void newFrame(StackValue returnAddress)
{
stack.push(returnAddress);
stack.push(new StackValue(frameTop));
frameTop = stack.size();
}
StackValue popFrame()
{
stack.setSize(frameTop);
StackValue oldFrame = (StackValue)(stack.pop());
frameTop = oldFrame.i;
return (StackValue)stack.pop();
}
void push(StackValue v)
{
stack.push(v);
}
boolean isEmpty()
{
return stack.isEmpty();
}
StackValue pop()
{
return (StackValue)stack.pop();
}
}

View File

@ -1,333 +0,0 @@
/* -*- Mode: Java; tab-width: 8 -*-
* Copyright © 1998 Netscape Communications Corporation,
* All Rights Reserved.
*/
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;
}

View File

@ -1,524 +0,0 @@
/* -*- Mode: java; tab-width: 8 -*-
* Copyright © 1997, 1998 Netscape Communications Corporation,
* All Rights Reserved.
*/
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 "";
}
/************************************************************************************************/
PostorderNodeIterator findTryNode(JSStack theStack, PostorderNodeIterator ni)
{
while (true) {
Node p = ni.peekParent();
if (p == null) {
StackValue ret = theStack.popFrame();
ni = ret.p;
if (ni == null) return null;
}
else {
if (p.type == TokenStream.TRY)
return ni;
ni.pop();
}
}
}
PostorderNodeIterator execute(JSStack theStack, PostorderNodeIterator ni)
{
StackValue lhs;
StackValue rhs;
Number num;
switch (type) {
case TokenStream.NUMBER :
num = (Number)getDatum();
System.out.println("number " + num.doubleValue());
theStack.push(new StackValue(num.doubleValue()));
return ni;
case TokenStream.SETNAME :
rhs = theStack.pop(); // the new value
lhs = theStack.pop(); // the target lvalue
System.out.println("setname " + lhs.s + " to " + rhs.d);
return ni;
case TokenStream.BINDNAME :
System.out.println("bindname " + getString());
theStack.push(new StackValue(getString()));
return ni;
case TokenStream.NAME :
System.out.println("name " + getString());
theStack.push(new StackValue(22.0));
return ni;
case TokenStream.CALL :
System.out.println("call");
lhs = theStack.pop(); // the function object
/*
here we look up the first arg, find that it's a known function
and return the nodeIterator for it's tree. Also, begin execution
for that function by constructing a frame on the stack.
*/
theStack.newFrame(new StackValue(ni));
ni = new PostorderNodeIterator(Brenda.tf);
return ni;
case TokenStream.RETURN :
lhs = theStack.pop(); // the return value
rhs = theStack.pop(); // the return address
ni = rhs.p;
theStack.push(lhs);
return ni;
case TokenStream.ADD :
rhs = theStack.pop();
lhs = theStack.pop();
theStack.push(new StackValue(lhs.d + rhs.d));
return ni;
case TokenStream.THROW :
lhs = theStack.pop(); // the exception object
ni = findTryNode(theStack, ni);
return ni;
}
return ni;
}
/************************************************************************************************/
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
}

View File

@ -1,57 +0,0 @@
import java.util.Stack;
class PostorderNodeIterator {
PostorderNodeIterator(Node n)
{
stack = new Stack();
while (n.first != null) {
stack.push(n);
n = n.first;
}
start = n;
}
Node peekParent()
{
if (stack.isEmpty())
return null;
else
return (Node)stack.peek();
}
void pop()
{
if (stack.isEmpty())
current = null;
else
current = (Node)stack.pop();
}
Node nextNode()
{
if (current == null)
return current = start;
if (stack.isEmpty())
return current = null;
else {
current = current.next;
if (current != null) {
while (current.first != null) {
stack.push(current);
current = current.first;
}
}
else
current = (Node)stack.pop();
}
return current;
}
Node start;
Node current;
Stack stack;
}

View File

@ -1,58 +0,0 @@
/* -*- Mode: java; tab-width: 8 -*-
* Copyright © 1997, 1998 Netscape Communications Corporation, All Rights Reserved.
*/
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;
}

View File

@ -1,128 +0,0 @@
class ScriptRuntime {
/*
* There's such a huge space (and some time) waste for the Foo.class
* syntax: the compiler sticks in a test of a static field in the
* enclosing class for null and the code for creating the class value.
* It has to do this since the reference has to get pushed off til
* executiontime (i.e. can't force an early load), but for the
* 'standard' classes - especially those in java.lang, we can trust
* that they won't cause problems by being loaded early.
*/
public final static Class StringClass = String.class;
public final static Class NumberClass = Number.class;
public final static Class BooleanClass = Boolean.class;
public final static Class ByteClass = Byte.class;
public final static Class ShortClass = Short.class;
public final static Class IntegerClass = Integer.class;
public final static Class LongClass = Long.class;
public final static Class FloatClass = Float.class;
public final static Class DoubleClass = Double.class;
public final static Class CharacterClass = Character.class;
public final static Class ObjectClass = Object.class;
// This definition of NaN is identical to that in java.lang.Double
// except that it is not final. This is a workaround for a bug in
// the Microsoft VM, versions 2.01 and 3.0P1, that causes some uses
// (returns at least) of Double.NaN to be converted to 1.0.
// So we use ScriptRuntime.NaN instead of Double.NaN.
public static double NaN = 0.0d / 0.0;
/*
* Helper function for toNumber, parseInt, and TokenStream.getToken.
*/
static double stringToNumber(String s, int start, int radix) {
char digitMax = '9';
char lowerCaseBound = 'a';
char upperCaseBound = 'A';
int len = s.length();
if (radix < 10) {
digitMax = (char) ('0' + radix - 1);
}
if (radix > 10) {
lowerCaseBound = (char) ('a' + radix - 10);
upperCaseBound = (char) ('A' + radix - 10);
}
int end;
double sum = 0.0;
for (end=start; end < len; end++) {
char c = s.charAt(end);
int newDigit;
if ('0' <= c && c <= digitMax)
newDigit = c - '0';
else if ('a' <= c && c < lowerCaseBound)
newDigit = c - 'a' + 10;
else if ('A' <= c && c < upperCaseBound)
newDigit = c - 'A' + 10;
else
break;
sum = sum*radix + newDigit;
}
if (start == end) {
return NaN;
}
if (sum >= 9007199254740992.0) {
if (radix == 10) {
/* If we're accumulating a decimal number and the number
* is >= 2^53, then the result from the repeated multiply-add
* above may be inaccurate. Call Java to get the correct
* answer.
*/
try {
return Double.valueOf(s.substring(start, end)).doubleValue();
} catch (NumberFormatException nfe) {
return NaN;
}
} else if (radix == 2 || radix == 4 || radix == 8 ||
radix == 16 || radix == 32)
{
/* The number may also be inaccurate for one of these bases.
* This happens if the addition in value*radix + digit causes
* a round-down to an even least significant mantissa bit
* when the first dropped bit is a one. If any of the
* following digits in the number (which haven't been added
* in yet) are nonzero then the correct action would have
* been to round up instead of down. An example of this
* occurs when reading the number 0x1000000000000081, which
* rounds to 0x1000000000000000 instead of 0x1000000000000100.
*/
BinaryDigitReader bdr = new BinaryDigitReader(radix, s, start, end);
int bit;
sum = 0.0;
/* Skip leading zeros. */
do {
bit = bdr.getNextBinaryDigit();
} while (bit == 0);
if (bit == 1) {
/* Gather the 53 significant bits (including the leading 1) */
sum = 1.0;
for (int j = 52; j != 0; j--) {
bit = bdr.getNextBinaryDigit();
if (bit < 0)
return sum;
sum = sum*2 + bit;
}
/* bit54 is the 54th bit (the first dropped from the mantissa) */
int bit54 = bdr.getNextBinaryDigit();
if (bit54 >= 0) {
double factor = 2.0;
int sticky = 0; /* sticky is 1 if any bit beyond the 54th is 1 */
int bit3;
while ((bit3 = bdr.getNextBinaryDigit()) >= 0) {
sticky |= bit3;
factor *= 2;
}
sum += bit54 & (bit | sticky);
sum *= factor;
}
}
}
/* We don't worry about inaccurate numbers for any other base. */
}
return sum;
}
}

View File

@ -1,35 +0,0 @@
/* -*- Mode: java; tab-width: 8 -*-
* Copyright © 1997, 1998 Netscape Communications Corporation, All Rights Reserved.
*/
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;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,56 +0,0 @@
/* -*- Mode: java; tab-width: 8 -*-
* Copyright © 1997, 1998 Netscape Communications Corporation,
* All Rights Reserved.
*/
/**
* 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 RuntimeException {
/**
* 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();
}
/**
* 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;
}
private Throwable exception;
}