diff --git a/mozilla/js/js2/java/BinaryDigitReader.java b/mozilla/js/js2/java/BinaryDigitReader.java
new file mode 100644
index 00000000000..882fde202b3
--- /dev/null
+++ b/mozilla/js/js2/java/BinaryDigitReader.java
@@ -0,0 +1,43 @@
+/* -*- 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;
+ }
+}
diff --git a/mozilla/js/js2/java/Context.java b/mozilla/js/js2/java/Context.java
new file mode 100644
index 00000000000..cb32c9e7f18
--- /dev/null
+++ b/mozilla/js/js2/java/Context.java
@@ -0,0 +1,79 @@
+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);
+};
+
\ No newline at end of file
diff --git a/mozilla/js/js2/java/FunctionNode.java b/mozilla/js/js2/java/FunctionNode.java
new file mode 100644
index 00000000000..9ffad550aa5
--- /dev/null
+++ b/mozilla/js/js2/java/FunctionNode.java
@@ -0,0 +1,18 @@
+/* -*- 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();
+ }
+
+}
diff --git a/mozilla/js/js2/java/IRFactory.java b/mozilla/js/js2/java/IRFactory.java
new file mode 100644
index 00000000000..1b6997519fd
--- /dev/null
+++ b/mozilla/js/js2/java/IRFactory.java
@@ -0,0 +1,994 @@
+/* -*- 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
+ *
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
+ *
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;
+}
+
diff --git a/mozilla/js/js2/java/Interpreter.java b/mozilla/js/js2/java/Interpreter.java
new file mode 100644
index 00000000000..df7a26ceac7
--- /dev/null
+++ b/mozilla/js/js2/java/Interpreter.java
@@ -0,0 +1,31 @@
+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();
+ }
+
+
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/mozilla/js/js2/java/JSStack.java b/mozilla/js/js2/java/JSStack.java
new file mode 100644
index 00000000000..f99d6731674
--- /dev/null
+++ b/mozilla/js/js2/java/JSStack.java
@@ -0,0 +1,18 @@
+
+import java.util.Stack;
+
+class JSStack {
+
+ Stack stack = new Stack();
+
+ void push(StackValue value)
+ {
+ stack.push(value);
+ }
+
+ StackValue pop()
+ {
+ return (StackValue)stack.pop();
+ }
+
+}
\ No newline at end of file
diff --git a/mozilla/js/js2/java/LineBuffer.java b/mozilla/js/js2/java/LineBuffer.java
new file mode 100644
index 00000000000..f3b73cea8fb
--- /dev/null
+++ b/mozilla/js/js2/java/LineBuffer.java
@@ -0,0 +1,333 @@
+/* -*- 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;
+}
+
+
diff --git a/mozilla/js/js2/java/Node.java b/mozilla/js/js2/java/Node.java
new file mode 100644
index 00000000000..259aaee1045
--- /dev/null
+++ b/mozilla/js/js2/java/Node.java
@@ -0,0 +1,473 @@
+/* -*- 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 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());
+ return ni;
+
+ case TokenStream.SETNAME :
+ System.out.println("setname");
+ return ni;
+
+ case TokenStream.BINDNAME :
+ System.out.println("name " + getString());
+ return ni;
+
+ case TokenStream.ADD :
+ rhs = theStack.pop();
+ lhs = theStack.pop();
+ theStack.push(new StackValue(lhs.dbl + rhs.dbl));
+ 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
+}
+
diff --git a/mozilla/js/js2/java/PostorderNodeIterator.java b/mozilla/js/js2/java/PostorderNodeIterator.java
new file mode 100644
index 00000000000..b75e816dd14
--- /dev/null
+++ b/mozilla/js/js2/java/PostorderNodeIterator.java
@@ -0,0 +1,41 @@
+
+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 nextNode()
+ {
+ if (current == null)
+ return current = start;
+
+ if (stack.isEmpty())
+ return 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;
+}
\ No newline at end of file
diff --git a/mozilla/js/js2/java/PreorderNodeIterator.java b/mozilla/js/js2/java/PreorderNodeIterator.java
new file mode 100644
index 00000000000..bc5fc623b38
--- /dev/null
+++ b/mozilla/js/js2/java/PreorderNodeIterator.java
@@ -0,0 +1,58 @@
+/* -*- 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;
+}
diff --git a/mozilla/js/js2/java/ScriptRuntime.java b/mozilla/js/js2/java/ScriptRuntime.java
new file mode 100644
index 00000000000..336a51a2ab2
--- /dev/null
+++ b/mozilla/js/js2/java/ScriptRuntime.java
@@ -0,0 +1,128 @@
+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;
+ }
+
+}
\ No newline at end of file
diff --git a/mozilla/js/js2/java/ShallowNodeIterator.java b/mozilla/js/js2/java/ShallowNodeIterator.java
new file mode 100644
index 00000000000..991df032264
--- /dev/null
+++ b/mozilla/js/js2/java/ShallowNodeIterator.java
@@ -0,0 +1,35 @@
+/* -*- 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;
+}
+
diff --git a/mozilla/js/js2/java/StackValue.java b/mozilla/js/js2/java/StackValue.java
new file mode 100644
index 00000000000..ca84ae8cce7
--- /dev/null
+++ b/mozilla/js/js2/java/StackValue.java
@@ -0,0 +1,11 @@
+class StackValue {
+
+ StackValue(double d)
+ {
+ dbl = d;
+ }
+
+ double dbl;
+
+
+}
\ No newline at end of file
diff --git a/mozilla/js/js2/java/ThreadLinkException.java b/mozilla/js/js2/java/ThreadLinkException.java
new file mode 100644
index 00000000000..f854577e98e
--- /dev/null
+++ b/mozilla/js/js2/java/ThreadLinkException.java
@@ -0,0 +1,26 @@
+/* -*- Mode: java; tab-width: 8 -*-
+ * Copyright © 1998 Netscape Communications Corporation,
+ * All Rights Reserved.
+ */
+
+// API class
+/**
+ * Thrown if the thread association cannot be made.
+ *
+ * Thrown by Context.enter() if the context
+ * is already associated with a thread, or if the
+ * current thread is already associated with a context.
+ *
+ * Thrown by Context.exit() if the context is not
+ * associated with the current thread.
+ *
+ * @see com.netscape.javascript.Context#enter
+ * @see com.netscape.javascript.Context#exit
+ */
+public class ThreadLinkException extends Exception {
+
+ public ThreadLinkException(String detail) {
+ super(detail);
+ }
+}
+
diff --git a/mozilla/js/js2/java/TokenStream.java b/mozilla/js/js2/java/TokenStream.java
new file mode 100644
index 00000000000..a8764526562
--- /dev/null
+++ b/mozilla/js/js2/java/TokenStream.java
@@ -0,0 +1,1299 @@
+/* -*- Mode: Java; tab-width: 8 -*-
+ * Copyright © 1997, 1998 Netscape Communications Corporation,
+ * All Rights Reserved.
+ */
+
+import java.io.*;
+
+/**
+ * This class implements the JavaScript scanner.
+ *
+ * It is based on the C source files jsscan.c and jsscan.h
+ * in the jsref package.
+ *
+ * @see com.netscape.javascript.Parser
+ *
+ * @author Mike McCabe
+ * @author Brendan Eich
+ */
+
+public class TokenStream {
+ /*
+ * JSTokenStream flags, mirroring those in jsscan.h. These are used
+ * by the parser to change/check the state of the scanner.
+ */
+
+ public final static int
+ TSF_ERROR = 0x0001, // fatal error while scanning
+// TSF_EOF = 0x0002, // hit end of file
+ TSF_NEWLINES = 0x0004, // tokenize newlines
+ TSF_FUNCTION = 0x0008, // scanning inside function body
+ TSF_RETURN_EXPR = 0x0010, // function has 'return expr;'
+ TSF_RETURN_VOID = 0x0020, // function has 'return;'
+// TSF_INTERACTIVE = 0x0040, // interactive parsing mode
+// TSF_COMMAND = 0x0080, // command parsing mode
+// TSF_LOOKAHEAD = 0x0100, // looking ahead for a token
+ TSF_REGEXP = 0x0200; // looking for a regular expression
+
+ /*
+ * For chars - because we need something out-of-range
+ * to check. (And checking EOF by exception is annoying.)
+ * Note distinction from EOF token type!
+ */
+ private final static int
+ EOF_CHAR = -1;
+
+ /**
+ * Token types. These values correspond to JSTokenType values in
+ * jsscan.c.
+ */
+
+ public final static int
+ // start enum
+ ERROR = -1, // well-known as the only code < EOF
+ EOF = 0, // end of file token - (not EOF_CHAR)
+ EOL = 1, // end of line
+ // Beginning here are interpreter bytecodes. Their values
+ // must not exceed 127.
+ POPV = 2,
+ ENTERWITH = 3,
+ LEAVEWITH = 4,
+ RETURN = 5,
+ GOTO = 6,
+ IFEQ = 7,
+ IFNE = 8,
+ DUP = 9,
+ SETNAME = 10,
+ BITOR = 11,
+ BITXOR = 12,
+ BITAND = 13,
+ EQ = 14,
+ NE = 15,
+ LT = 16,
+ LE = 17,
+ GT = 18,
+ GE = 19,
+ LSH = 20,
+ RSH = 21,
+ URSH = 22,
+ ADD = 23,
+ SUB = 24,
+ MUL = 25,
+ DIV = 26,
+ MOD = 27,
+ BITNOT = 28,
+ NEG = 29,
+ NEW = 30,
+ DELPROP = 31,
+ TYPEOF = 32,
+ NAMEINC = 33,
+ PROPINC = 34,
+ ELEMINC = 35,
+ NAMEDEC = 36,
+ PROPDEC = 37,
+ ELEMDEC = 38,
+ GETPROP = 39,
+ SETPROP = 40,
+ GETELEM = 41,
+ SETELEM = 42,
+ CALL = 43,
+ NAME = 44,
+ NUMBER = 45,
+ STRING = 46,
+ ZERO = 47,
+ ONE = 48,
+ NULL = 49,
+ THIS = 50,
+ FALSE = 51,
+ TRUE = 52,
+ SHEQ = 53, // shallow equality (===)
+ SHNE = 54, // shallow inequality (!==)
+ CLOSURE = 55,
+ OBJECT = 56,
+ POP = 57,
+ POS = 58,
+ VARINC = 59,
+ VARDEC = 60,
+ BINDNAME = 61,
+ THROW = 62,
+ IN = 63,
+ INSTANCEOF = 64,
+ GOSUB = 65,
+ RETSUB = 66,
+ CALLSPECIAL = 67,
+ GETTHIS = 68,
+ NEWTEMP = 69,
+ USETEMP = 70,
+ GETBASE = 71,
+ GETVAR = 72,
+ SETVAR = 73,
+ UNDEFINED = 74,
+ TRY = 75,
+ ENDTRY = 76,
+ NEWSCOPE = 77,
+ TYPEOFNAME = 78,
+ ENUMINIT = 79,
+ ENUMNEXT = 80,
+ GETPROTO = 81,
+ GETPARENT = 82,
+ SETPROTO = 83,
+ SETPARENT = 84,
+ SCOPE = 85,
+ GETSCOPEPARENT = 86,
+ JTHROW = 87,
+ // End of interpreter bytecodes
+ SEMI = 88, // semicolon
+ LB = 89, // left and right brackets
+ RB = 90,
+ LC = 91, // left and right curlies (braces)
+ RC = 92,
+ LP = 93, // left and right parentheses
+ RP = 94,
+ COMMA = 95, // comma operator
+ ASSIGN = 96, // assignment ops (= += -= etc.)
+ HOOK = 97, // conditional (?:)
+ COLON = 98,
+ OR = 99, // logical or (||)
+ AND = 100, // logical and (&&)
+ EQOP = 101, // equality ops (== !=)
+ RELOP = 102, // relational ops (< <= > >=)
+ SHOP = 103, // shift ops (<< >> >>>)
+ UNARYOP = 104, // unary prefix operator
+ INC = 105, // increment/decrement (++ --)
+ DEC = 106,
+ DOT = 107, // member operator (.)
+ PRIMARY = 108, // true, false, null, this, super
+ FUNCTION = 109, // function keyword
+ EXPORT = 110, // export keyword
+ IMPORT = 111, // import keyword
+ IF = 112, // if keyword
+ ELSE = 113, // else keyword
+ SWITCH = 114, // switch keyword
+ CASE = 115, // case keyword
+ DEFAULT = 116, // default keyword
+ WHILE = 117, // while keyword
+ DO = 118, // do keyword
+ FOR = 119, // for keyword
+ BREAK = 120, // break keyword
+ CONTINUE = 121, // continue keyword
+ VAR = 122, // var keyword
+ WITH = 123, // with keyword
+ CATCH = 124, // catch keyword
+ FINALLY = 125, // finally keyword
+ RESERVED = 126, // reserved keywords
+
+ /** Added by Mike - these are JSOPs in the jsref, but I
+ * don't have them yet in the java implementation...
+ * so they go here. Also whatever I needed.
+
+ * Most of these go in the 'op' field when returning
+ * more general token types, eg. 'DIV' as the op of 'ASSIGN'.
+ */
+ NOP = 127, // NOP
+ NOT = 128, // etc.
+ PRE = 129, // for INC, DEC nodes.
+ POST = 130,
+
+ /**
+ * For JSOPs associated with keywords...
+ * eg. op = THIS; token = PRIMARY
+ */
+
+ VOID = 131,
+
+ /* types used for the parse tree - these never get returned
+ * by the scanner.
+ */
+ BLOCK = 132, // statement block
+ ARRAYLIT = 133, // array literal
+ OBJLIT = 134, // object literal
+ LABEL = 135, // label
+ TARGET = 136,
+ LOOP = 137,
+ ENUMDONE = 138,
+ EXPRSTMT = 139,
+ PARENT = 140,
+ CONVERT = 141,
+ JSR = 142,
+ NEWLOCAL = 143,
+ USELOCAL = 144,
+ SCRIPT = 145; // top-level node for entire script
+ // end enum
+
+
+ /* for mapping int token types to printable strings.
+ * make sure to add 1 to index before using these!
+ */
+ private static String names[];
+ private static void checkNames() {
+ if (Context.printTrees && names == null) {
+ String[] a = {
+ "error",
+ "eof",
+ "eol",
+ "popv",
+ "enterwith",
+ "leavewith",
+ "return",
+ "goto",
+ "ifeq",
+ "ifne",
+ "dup",
+ "setname",
+ "bitor",
+ "bitxor",
+ "bitand",
+ "eq",
+ "ne",
+ "lt",
+ "le",
+ "gt",
+ "ge",
+ "lsh",
+ "rsh",
+ "ursh",
+ "add",
+ "sub",
+ "mul",
+ "div",
+ "mod",
+ "bitnot",
+ "neg",
+ "new",
+ "delprop",
+ "typeof",
+ "nameinc",
+ "propinc",
+ "eleminc",
+ "namedec",
+ "propdec",
+ "elemdec",
+ "getprop",
+ "setprop",
+ "getelem",
+ "setelem",
+ "call",
+ "name",
+ "number",
+ "string",
+ "zero",
+ "one",
+ "null",
+ "this",
+ "false",
+ "true",
+ "sheq",
+ "shne",
+ "closure",
+ "object",
+ "pop",
+ "pos",
+ "varinc",
+ "vardec",
+ "bindname",
+ "throw",
+ "in",
+ "instanceof",
+ "gosub",
+ "retsub",
+ "callspecial",
+ "getthis",
+ "newtemp",
+ "usetemp",
+ "getbase",
+ "getvar",
+ "setvar",
+ "undefined",
+ "try",
+ "endtry",
+ "newscope",
+ "typeofname",
+ "enuminit",
+ "enumnext",
+ "getproto",
+ "getparent",
+ "setproto",
+ "setparent",
+ "scope",
+ "getscopeparent",
+ "jthrow",
+ "semi",
+ "lb",
+ "rb",
+ "lc",
+ "rc",
+ "lp",
+ "rp",
+ "comma",
+ "assign",
+ "hook",
+ "colon",
+ "or",
+ "and",
+ "eqop",
+ "relop",
+ "shop",
+ "unaryop",
+ "inc",
+ "dec",
+ "dot",
+ "primary",
+ "function",
+ "export",
+ "import",
+ "if",
+ "else",
+ "switch",
+ "case",
+ "default",
+ "while",
+ "do",
+ "for",
+ "break",
+ "continue",
+ "var",
+ "with",
+ "catch",
+ "finally",
+ "reserved",
+ "nop",
+ "not",
+ "pre",
+ "post",
+ "void",
+ "block",
+ "arraylit",
+ "objlit",
+ "label",
+ "target",
+ "loop",
+ "enumdone",
+ "exprstmt",
+ "parent",
+ "convert",
+ "jsr",
+ "newlocal",
+ "uselocal",
+ "script"
+ };
+ names = a;
+ }
+ }
+
+ /* This function uses the cached op, string and number fields in
+ * TokenStream; if getToken has been called since the passed token
+ * was scanned, the op or string printed may be incorrect.
+ */
+ public String tokenToString(int token) {
+ if (Context.printTrees) {
+ checkNames();
+ if (token + 1 >= names.length)
+ return null;
+
+ if (token == UNARYOP ||
+ token == ASSIGN ||
+ token == PRIMARY ||
+ token == EQOP ||
+ token == SHOP ||
+ token == RELOP) {
+ return names[token + 1] + " " + names[this.op + 1];
+ }
+
+ if (token == STRING || token == OBJECT || token == NAME)
+ return names[token + 1] + " `" + this.string + "'";
+
+ if (token == NUMBER)
+ return "NUMBER " + this.number;
+
+ return names[token + 1];
+ }
+ return "";
+ }
+
+ public static String tokenToName(int type) {
+ checkNames();
+ return names == null ? "" : names[type + 1];
+ }
+
+ private static java.util.Hashtable keywords;
+
+ static {
+ String[] strings = {
+ "break",
+ "case",
+ "continue",
+ "default",
+ "delete",
+ "do",
+ "else",
+ "export",
+ "false",
+ "for",
+ "function",
+ "if",
+ "in",
+ "new",
+ "null",
+ "return",
+ "switch",
+ "this",
+ "true",
+ "typeof",
+ "var",
+ "void",
+ "while",
+ "with",
+
+ // the following are #ifdef RESERVE_JAVA_KEYWORDS in jsscan.c
+ "abstract",
+ "boolean",
+ "byte",
+ "catch",
+ "char",
+ "class",
+ "const",
+ "debugger",
+ "double",
+ "enum",
+ "extends",
+ "final",
+ "finally",
+ "float",
+ "goto",
+ "implements",
+ "import",
+ "instanceof",
+ "int",
+ "interface",
+ "long",
+ "native",
+ "package",
+ "private",
+ "protected",
+ "public",
+ "short",
+ "static",
+ "super",
+ "synchronized",
+ "throw",
+ "throws",
+ "transient",
+ "try",
+ "volatile"
+ };
+ int[] values = {
+ BREAK, // break
+ CASE, // case
+ CONTINUE, // continue
+ DEFAULT, // default
+ DELPROP, // delete
+ DO, // do
+ ELSE, // else
+ EXPORT, // export
+ PRIMARY | (FALSE << 8), // false
+ FOR, // for
+ FUNCTION, // function
+ IF, // if
+ RELOP | (IN << 8), // in
+ NEW, // new
+ PRIMARY | (NULL << 8), // null
+ RETURN, // return
+ SWITCH, // switch
+ PRIMARY | (THIS << 8), // this
+ PRIMARY | (TRUE << 8), // true
+ UNARYOP | (TYPEOF << 8), // typeof
+ VAR, // var
+ UNARYOP | (VOID << 8), // void
+ WHILE, // while
+ WITH, // with
+ RESERVED, // abstract
+ RESERVED, // boolean
+ RESERVED, // byte
+ CATCH, // catch
+ RESERVED, // char
+ RESERVED, // class
+ RESERVED, // const
+ RESERVED, // debugger
+ RESERVED, // double
+ RESERVED, // enum
+ RESERVED, // extends
+ RESERVED, // final
+ FINALLY, // finally
+ RESERVED, // float
+ RESERVED, // goto
+ RESERVED, // implements
+ IMPORT, // import
+ RELOP | (INSTANCEOF << 8), // instanceof
+ RESERVED, // int
+ RESERVED, // interface
+ RESERVED, // long
+ RESERVED, // native
+ RESERVED, // package
+ RESERVED, // private
+ RESERVED, // protected
+ RESERVED, // public
+ RESERVED, // short
+ RESERVED, // static
+ PRIMARY | (NOP << 8), // super
+ RESERVED, // synchronized
+ THROW, // throw
+ RESERVED, // throws
+ RESERVED, // transient
+ TRY, // try
+ RESERVED // volatile
+ };
+ keywords = new java.util.Hashtable(strings.length);
+ Integer res = new Integer(RESERVED);
+ for (int i=0; i < strings.length; i++)
+ keywords.put(strings[i], values[i] == RESERVED
+ ? res
+ : new Integer(values[i]));
+ }
+
+ private int stringToKeyword(String name) {
+ Integer result = (Integer) keywords.get(name);
+ if (result == null)
+ return EOF;
+ int x = result.intValue();
+ this.op = x >> 8;
+ return x & 0xff;
+ }
+
+ public TokenStream(Reader in,
+ String sourceName, int lineno)
+ {
+ this.in = new LineBuffer(in, lineno);
+
+ this.pushbackToken = EOF;
+ this.sourceName = sourceName;
+ flags = 0;
+ }
+
+ /* return and pop the token from the stream if it matches...
+ * otherwise return null
+ */
+ public boolean matchToken(int toMatch) throws IOException {
+ int token = getToken();
+ if (token == toMatch)
+ return true;
+
+ // didn't match, push back token
+ tokenno--;
+ this.pushbackToken = token;
+ return false;
+ }
+
+ public void clearPushback() {
+ this.pushbackToken = EOF;
+ }
+
+ public void ungetToken(int tt) {
+ if (this.pushbackToken != EOF && tt != ERROR) {
+ Object[] errArgs = { tokenToString(tt),
+ tokenToString(this.pushbackToken) };
+ String message = Context.getMessage("msg.token.replaces.pushback",
+ errArgs);
+ throw new RuntimeException(message);
+ }
+ this.pushbackToken = tt;
+ tokenno--;
+ }
+
+ public int peekToken() throws IOException {
+ int result = getToken();
+
+ this.pushbackToken = result;
+ tokenno--;
+ return result;
+ }
+
+ public int peekTokenSameLine() throws IOException {
+ int result;
+
+ flags |= TSF_NEWLINES; // SCAN_NEWLINES from jsscan.h
+ result = peekToken();
+ flags &= ~TSF_NEWLINES; // HIDE_NEWLINES from jsscan.h
+ if (this.pushbackToken == EOL)
+ this.pushbackToken = EOF;
+ return result;
+ }
+
+ /* helper functions... these might be better inlined.
+ * These are needed because the java.lang.Character.isWhatever
+ * functions accept unicode, and we want to limit
+ * identifiers to ASCII.
+ */
+ protected static boolean isJSIdentifier(String s) {
+ int length = s.length();
+
+ if (length == 0 || !isJSIdentifierStart(s.charAt(0)))
+ return false;
+
+ for (int i=1; i