From 89bda83e0570ab87c6e449f5955613d5385e90b3 Mon Sep 17 00:00:00 2001 From: "alexanders@b2ef00c0-3703-41da-baef-cfe82387ac0c" Date: Wed, 3 Feb 2010 00:50:41 +0000 Subject: removed obsolete svn folder from hg tree --HG-- extra : convert_revision : svn%3Ab2ef00c0-3703-41da-baef-cfe82387ac0c/trunk%408 --- .../src/org/mozilla/javascript/Node.java | 1394 -------------------- 1 file changed, 1394 deletions(-) delete mode 100644 trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Node.java (limited to 'trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Node.java') diff --git a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Node.java b/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Node.java deleted file mode 100644 index 4298388..0000000 --- a/trunk/infrastructure/rhino1_7R1/src/org/mozilla/javascript/Node.java +++ /dev/null @@ -1,1394 +0,0 @@ -/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Rhino code, released - * May 6, 1999. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1997-1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Norris Boyd - * Roshan James - * Roger Lawrence - * Mike McCabe - * - * Alternatively, the contents of this file may be used under the terms of - * the GNU General Public License Version 2 or later (the "GPL"), in which - * case the provisions of the GPL are applicable instead of those above. If - * you wish to allow use of your version of this file only under the terms of - * the GPL and not to allow others to use your version of this file under the - * MPL, indicate your decision by deleting the provisions above and replacing - * them with the notice and other provisions required by the GPL. If you do - * not delete the provisions above, a recipient may use your version of this - * file under either the MPL or the GPL. - * - * ***** END LICENSE BLOCK ***** */ - -package org.mozilla.javascript; - -import java.util.Map; -import java.util.LinkedHashMap; -import java.util.Iterator; -import java.util.Collections; - -/** - * This class implements the root of the intermediate representation. - * - * @author Norris Boyd - * @author Mike McCabe - */ - -public class Node -{ - public static final int - FUNCTION_PROP = 1, - LOCAL_PROP = 2, - LOCAL_BLOCK_PROP = 3, - REGEXP_PROP = 4, - CASEARRAY_PROP = 5, - /* - 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 - 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 = 6, - VARIABLE_PROP = 7, - ISNUMBER_PROP = 8, - DIRECTCALL_PROP = 9, - SPECIALCALL_PROP = 10, - SKIP_INDEXES_PROP = 11, // array of skipped indexes of array literal - OBJECT_IDS_PROP = 12, // array of properties for object literal - INCRDECR_PROP = 13, // pre or post type of increment/decerement - CATCH_SCOPE_PROP = 14, // index of catch scope block in catch - LABEL_ID_PROP = 15, // label id: code generation uses it - MEMBER_TYPE_PROP = 16, // type of element access operation - NAME_PROP = 17, // property name - CONTROL_BLOCK_PROP = 18, // flags a control block that can drop off - PARENTHESIZED_PROP = 19, // expression is parenthesized - GENERATOR_END_PROP = 20, - DESTRUCTURING_ARRAY_LENGTH = 21, - DESTRUCTURING_NAMES= 22, - LAST_PROP = 22; - - // values of ISNUMBER_PROP to specify - // which of the children are Number types - public static final int - BOTH = 0, - LEFT = 1, - RIGHT = 2; - - public static final int // values for SPECIALCALL_PROP - NON_SPECIALCALL = 0, - SPECIALCALL_EVAL = 1, - SPECIALCALL_WITH = 2; - - public static final int // flags for INCRDECR_PROP - DECR_FLAG = 0x1, - POST_FLAG = 0x2; - - public static final int // flags for MEMBER_TYPE_PROP - PROPERTY_FLAG = 0x1, // property access: element is valid name - ATTRIBUTE_FLAG = 0x2, // x.@y or x..@y - DESCENDANTS_FLAG = 0x4; // x..y or x..@i - - private static class NumberNode extends Node - { - NumberNode(double number) - { - super(Token.NUMBER); - this.number = number; - } - - double number; - } - - private static class StringNode extends Node - { - StringNode(int type, String str) { - super(type); - this.str = str; - } - - String str; - Node.Scope scope; - } - - public static class Jump extends Node - { - public Jump(int type) - { - super(type); - } - - Jump(int type, int lineno) - { - super(type, lineno); - } - - Jump(int type, Node child) - { - super(type, child); - } - - Jump(int type, Node child, int lineno) - { - super(type, child, lineno); - } - - public final Jump getJumpStatement() - { - if (!(type == Token.BREAK || type == Token.CONTINUE)) Kit.codeBug(); - return jumpNode; - } - - public final void setJumpStatement(Jump jumpStatement) - { - if (!(type == Token.BREAK || type == Token.CONTINUE)) Kit.codeBug(); - if (jumpStatement == null) Kit.codeBug(); - if (this.jumpNode != null) Kit.codeBug(); //only once - this.jumpNode = jumpStatement; - } - - public final Node getDefault() - { - if (!(type == Token.SWITCH)) Kit.codeBug(); - return target2; - } - - public final void setDefault(Node defaultTarget) - { - if (!(type == Token.SWITCH)) Kit.codeBug(); - if (defaultTarget.type != Token.TARGET) Kit.codeBug(); - if (target2 != null) Kit.codeBug(); //only once - target2 = defaultTarget; - } - - public final Node getFinally() - { - if (!(type == Token.TRY)) Kit.codeBug(); - return target2; - } - - public final void setFinally(Node finallyTarget) - { - if (!(type == Token.TRY)) Kit.codeBug(); - if (finallyTarget.type != Token.TARGET) Kit.codeBug(); - if (target2 != null) Kit.codeBug(); //only once - target2 = finallyTarget; - } - - public final Jump getLoop() - { - if (!(type == Token.LABEL)) Kit.codeBug(); - return jumpNode; - } - - public final void setLoop(Jump loop) - { - if (!(type == Token.LABEL)) Kit.codeBug(); - if (loop == null) Kit.codeBug(); - if (jumpNode != null) Kit.codeBug(); //only once - jumpNode = loop; - } - - public final Node getContinue() - { - if (type != Token.LOOP) Kit.codeBug(); - return target2; - } - - public final void setContinue(Node continueTarget) - { - if (type != Token.LOOP) Kit.codeBug(); - if (continueTarget.type != Token.TARGET) Kit.codeBug(); - if (target2 != null) Kit.codeBug(); //only once - target2 = continueTarget; - } - - public Node target; - private Node target2; - private Jump jumpNode; - } - - static class Symbol { - Symbol(int declType, String name) { - this.declType = declType; - this.name = name; - this.index = -1; - } - /** - * One of Token.FUNCTION, Token.LP (for parameters), Token.VAR, - * Token.LET, or Token.CONST - */ - int declType; - int index; - String name; - Node.Scope containingTable; - } - - static class Scope extends Jump { - public Scope(int nodeType) { - super(nodeType); - } - - public Scope(int nodeType, int lineno) { - super(nodeType, lineno); - } - - public Scope(int nodeType, Node n, int lineno) { - super(nodeType, n, lineno); - } - - /* - * Creates a new scope node, moving symbol table information - * from "scope" to the new node, and making "scope" a nested - * scope contained by the new node. - * Useful for injecting a new scope in a scope chain. - */ - public static Scope splitScope(Scope scope) { - Scope result = new Scope(scope.getType()); - result.symbolTable = scope.symbolTable; - scope.symbolTable = null; - result.parent = scope.parent; - scope.parent = result; - result.top = scope.top; - return result; - } - - public static void joinScopes(Scope source, Scope dest) { - source.ensureSymbolTable(); - dest.ensureSymbolTable(); - if (!Collections.disjoint(source.symbolTable.keySet(), - dest.symbolTable.keySet())) - { - throw Kit.codeBug(); - } - dest.symbolTable.putAll(source.symbolTable); - } - - public void setParent(Scope parent) { - this.parent = parent; - this.top = parent == null ? (ScriptOrFnNode)this : parent.top; - } - - public Scope getParentScope() { - return parent; - } - - public Scope getDefiningScope(String name) { - for (Scope sn=this; sn != null; sn = sn.parent) { - if (sn.symbolTable == null) - continue; - if (sn.symbolTable.containsKey(name)) - return sn; - } - return null; - } - - public Symbol getSymbol(String name) { - return symbolTable == null ? null : symbolTable.get(name); - } - - public void putSymbol(String name, Symbol symbol) { - ensureSymbolTable(); - symbolTable.put(name, symbol); - symbol.containingTable = this; - top.addSymbol(symbol); - } - - public Map getSymbolTable() { - return symbolTable; - } - - private void ensureSymbolTable() { - if (symbolTable == null) { - symbolTable = new LinkedHashMap(5); - } - } - - // Use LinkedHashMap so that the iteration order is the insertion order - protected LinkedHashMap symbolTable; - private Scope parent; - private ScriptOrFnNode top; - } - - private static class PropListItem - { - PropListItem next; - int type; - int intValue; - Object objectValue; - } - - - 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, int line) { - type = nodeType; - lineno = line; - } - - public Node(int nodeType, Node child, int line) { - this(nodeType, child); - lineno = line; - } - - public Node(int nodeType, Node left, Node right, int line) { - this(nodeType, left, right); - lineno = line; - } - - public Node(int nodeType, Node left, Node mid, Node right, int line) { - this(nodeType, left, mid, right); - lineno = line; - } - - public static Node newNumber(double number) { - return new NumberNode(number); - } - - public static Node newString(String str) { - return new StringNode(Token.STRING, str); - } - - public static Node newString(int type, String str) { - return new StringNode(type, str); - } - - public int getType() { - return type; - } - - public void setType(int type) { - this.type = type; - } - - public boolean hasChildren() { - return first != null; - } - - public Node getFirstChild() { - return first; - } - - public Node getLastChild() { - return last; - } - - public Node getNext() { - 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 void addChildToFront(Node child) { - child.next = first; - first = child; - if (last == null) { - last = child; - } - } - - public void addChildToBack(Node child) { - child.next = null; - if (last == null) { - first = last = child; - return; - } - last.next = child; - last = child; - } - - public void addChildrenToFront(Node children) { - Node lastSib = children.getLastSibling(); - lastSib.next = first; - first = children; - if (last == null) { - last = lastSib; - } - } - - public void addChildrenToBack(Node children) { - if (last != null) { - last.next = children; - } - last = children.getLastSibling(); - if (first == null) { - first = children; - } - } - - /** - * Add 'child' before 'node'. - */ - public void addChildBefore(Node newChild, Node node) { - if (newChild.next != null) - throw new RuntimeException( - "newChild had siblings in addChildBefore"); - if (first == node) { - newChild.next = first; - first = newChild; - return; - } - Node prev = getChildBefore(node); - addChildAfter(newChild, prev); - } - - /** - * Add 'child' after 'node'. - */ - public void addChildAfter(Node newChild, Node node) { - if (newChild.next != null) - throw new RuntimeException( - "newChild had siblings in addChildAfter"); - newChild.next = node.next; - node.next = newChild; - if (last == node) - last = newChild; - } - - public void removeChild(Node child) { - Node prev = getChildBefore(child); - if (prev == null) - first = first.next; - else - prev.next = child.next; - if (child == last) last = prev; - child.next = null; - } - - public void replaceChild(Node child, Node newChild) { - newChild.next = child.next; - if (child == first) { - first = newChild; - } else { - Node prev = getChildBefore(child); - prev.next = newChild; - } - if (child == last) - last = newChild; - child.next = null; - } - - public void replaceChildAfter(Node prevChild, Node newChild) { - Node child = prevChild.next; - newChild.next = child.next; - prevChild.next = newChild; - if (child == last) - last = newChild; - child.next = null; - } - - private static final String propToString(int propType) - { - if (Token.printTrees) { - // If Context.printTrees is false, the compiler - // can remove all these strings. - switch (propType) { - case FUNCTION_PROP: return "function"; - case LOCAL_PROP: return "local"; - case LOCAL_BLOCK_PROP: return "local_block"; - case REGEXP_PROP: return "regexp"; - case CASEARRAY_PROP: return "casearray"; - - case TARGETBLOCK_PROP: return "targetblock"; - case VARIABLE_PROP: return "variable"; - case ISNUMBER_PROP: return "isnumber"; - case DIRECTCALL_PROP: return "directcall"; - - case SPECIALCALL_PROP: return "specialcall"; - case SKIP_INDEXES_PROP: return "skip_indexes"; - case OBJECT_IDS_PROP: return "object_ids_prop"; - case INCRDECR_PROP: return "incrdecr_prop"; - case CATCH_SCOPE_PROP: return "catch_scope_prop"; - case LABEL_ID_PROP: return "label_id_prop"; - case MEMBER_TYPE_PROP: return "member_type_prop"; - case NAME_PROP: return "name_prop"; - case CONTROL_BLOCK_PROP: return "control_block_prop"; - case PARENTHESIZED_PROP: return "parenthesized_prop"; - case GENERATOR_END_PROP: return "generator_end"; - case DESTRUCTURING_ARRAY_LENGTH: - return "destructuring_array_length"; - case DESTRUCTURING_NAMES:return "destructuring_names"; - - default: Kit.codeBug(); - } - } - return null; - } - - private PropListItem lookupProperty(int propType) - { - PropListItem x = propListHead; - while (x != null && propType != x.type) { - x = x.next; - } - return x; - } - - private PropListItem ensureProperty(int propType) - { - PropListItem item = lookupProperty(propType); - if (item == null) { - item = new PropListItem(); - item.type = propType; - item.next = propListHead; - propListHead = item; - } - return item; - } - - public void removeProp(int propType) - { - PropListItem x = propListHead; - if (x != null) { - PropListItem prev = null; - while (x.type != propType) { - prev = x; - x = x.next; - if (x == null) { return; } - } - if (prev == null) { - propListHead = x.next; - } else { - prev.next = x.next; - } - } - } - - public Object getProp(int propType) - { - PropListItem item = lookupProperty(propType); - if (item == null) { return null; } - return item.objectValue; - } - - public int getIntProp(int propType, int defaultValue) - { - PropListItem item = lookupProperty(propType); - if (item == null) { return defaultValue; } - return item.intValue; - } - - public int getExistingIntProp(int propType) - { - PropListItem item = lookupProperty(propType); - if (item == null) { Kit.codeBug(); } - return item.intValue; - } - - public void putProp(int propType, Object prop) - { - if (prop == null) { - removeProp(propType); - } else { - PropListItem item = ensureProperty(propType); - item.objectValue = prop; - } - } - - public void putIntProp(int propType, int prop) - { - PropListItem item = ensureProperty(propType); - item.intValue = prop; - } - - public int getLineno() { - return lineno; - } - - /** Can only be called when getType() == Token.NUMBER */ - public final double getDouble() { - return ((NumberNode)this).number; - } - - public final void setDouble(double number) { - ((NumberNode)this).number = number; - } - - /** Can only be called when node has String context. */ - public final String getString() { - return ((StringNode)this).str; - } - - /** Can only be called when node has String context. */ - public final void setString(String s) { - if (s == null) Kit.codeBug(); - ((StringNode)this).str = s; - } - - /** Can only be called when node has String context. */ - public final Scope getScope() { - return ((StringNode)this).scope; - } - - /** Can only be called when node has String context. */ - public final void setScope(Scope s) { - if (s == null) Kit.codeBug(); - if (!(this instanceof StringNode)) { - throw Kit.codeBug(); - } - ((StringNode)this).scope = s; - } - - public static Node newTarget() - { - return new Node(Token.TARGET); - } - - public final int labelId() - { - if (type != Token.TARGET && type != Token.YIELD) Kit.codeBug(); - return getIntProp(LABEL_ID_PROP, -1); - } - - public void labelId(int labelId) - { - if (type != Token.TARGET && type != Token.YIELD) Kit.codeBug(); - putIntProp(LABEL_ID_PROP, labelId); - } - - - /** - * Does consistent-return analysis on the function body when strict mode is - * enabled. - * - * function (x) { return (x+1) } - * is ok, but - * function (x) { if (x < 0) return (x+1); } - * is not becuase the function can potentially return a value when the - * condition is satisfied and if not, the function does not explicitly - * return value. - * - * This extends to checking mismatches such as "return" and "return " - * used in the same function. Warnings are not emitted if inconsistent - * returns exist in code that can be statically shown to be unreachable. - * Ex. - * function (x) { while (true) { ... if (..) { return value } ... } } - * emits no warning. However if the loop had a break statement, then a - * warning would be emitted. - * - * The consistency analysis looks at control structures such as loops, ifs, - * switch, try-catch-finally blocks, examines the reachable code paths and - * warns the user about an inconsistent set of termination possibilities. - * - * Caveat: Since the parser flattens many control structures into almost - * straight-line code with gotos, it makes such analysis hard. Hence this - * analyser is written to taken advantage of patterns of code generated by - * the parser (for loops, try blocks and such) and does not do a full - * control flow analysis of the gotos and break/continue statements. - * Future changes to the parser will affect this analysis. - */ - - /** - * These flags enumerate the possible ways a statement/function can - * terminate. These flags are used by endCheck() and by the Parser to - * detect inconsistent return usage. - * - * END_UNREACHED is reserved for code paths that are assumed to always be - * able to execute (example: throw, continue) - * - * END_DROPS_OFF indicates if the statement can transfer control to the - * next one. Statement such as return dont. A compound statement may have - * some branch that drops off control to the next statement. - * - * END_RETURNS indicates that the statement can return (without arguments) - * END_RETURNS_VALUE indicates that the statement can return a value. - * - * A compound statement such as - * if (condition) { - * return value; - * } - * Will be detected as (END_DROPS_OFF | END_RETURN_VALUE) by endCheck() - */ - static final int END_UNREACHED = 0; - static final int END_DROPS_OFF = 1; - static final int END_RETURNS = 2; - static final int END_RETURNS_VALUE = 4; - static final int END_YIELDS = 8; - - /** - * Checks that every return usage in a function body is consistent with the - * requirements of strict-mode. - * @return true if the function satisfies strict mode requirement. - */ - public boolean hasConsistentReturnUsage() - { - int n = endCheck(); - return (n & END_RETURNS_VALUE) == 0 || - (n & (END_DROPS_OFF|END_RETURNS|END_YIELDS)) == 0; - } - - /** - * Returns in the then and else blocks must be consistent with each other. - * If there is no else block, then the return statement can fall through. - * @return logical OR of END_* flags - */ - private int endCheckIf() - { - Node th, el; - int rv = END_UNREACHED; - - th = next; - el = ((Jump)this).target; - - rv = th.endCheck(); - - if (el != null) - rv |= el.endCheck(); - else - rv |= END_DROPS_OFF; - - return rv; - } - - /** - * Consistency of return statements is checked between the case statements. - * If there is no default, then the switch can fall through. If there is a - * default,we check to see if all code paths in the default return or if - * there is a code path that can fall through. - * @return logical OR of END_* flags - */ - private int endCheckSwitch() - { - Node n; - int rv = END_UNREACHED; - - // examine the cases - for (n = first.next; n != null; n = n.next) - { - if (n.type == Token.CASE) { - rv |= ((Jump)n).target.endCheck(); - } else - break; - } - - // we don't care how the cases drop into each other - rv &= ~END_DROPS_OFF; - - // examine the default - n = ((Jump)this).getDefault(); - if (n != null) - rv |= n.endCheck(); - else - rv |= END_DROPS_OFF; - - // remove the switch block - rv |= getIntProp(CONTROL_BLOCK_PROP, END_UNREACHED); - - return rv; - } - - /** - * If the block has a finally, return consistency is checked in the - * finally block. If all code paths in the finally returns, then the - * returns in the try-catch blocks don't matter. If there is a code path - * that does not return or if there is no finally block, the returns - * of the try and catch blocks are checked for mismatch. - * @return logical OR of END_* flags - */ - private int endCheckTry() - { - Node n; - int rv = END_UNREACHED; - - // check the finally if it exists - n = ((Jump)this).getFinally(); - if(n != null) { - rv = n.next.first.endCheck(); - } else { - rv = END_DROPS_OFF; - } - - // if the finally block always returns, then none of the returns - // in the try or catch blocks matter - if ((rv & END_DROPS_OFF) != 0) { - rv &= ~END_DROPS_OFF; - - // examine the try block - rv |= first.endCheck(); - - // check each catch block - n = ((Jump)this).target; - if (n != null) - { - // point to the first catch_scope - for (n = n.next.first; n != null; n = n.next.next) - { - // check the block of user code in the catch_scope - rv |= n.next.first.next.first.endCheck(); - } - } - } - - return rv; - } - - /** - * Return statement in the loop body must be consistent. The default - * assumption for any kind of a loop is that it will eventually terminate. - * The only exception is a loop with a constant true condition. Code that - * follows such a loop is examined only if one can statically determine - * that there is a break out of the loop. - * for(<> ; <>; <>) {} - * for(<> in <> ) {} - * while(<>) { } - * do { } while(<>) - * @return logical OR of END_* flags - */ - private int endCheckLoop() - { - Node n; - int rv = END_UNREACHED; - - // To find the loop body, we look at the second to last node of the - // loop node, which should be the predicate that the loop should - // satisfy. - // The target of the predicate is the loop-body for all 4 kinds of - // loops. - for (n = first; n.next != last; n = n.next) { - /* skip */ - } - if (n.type != Token.IFEQ) - return END_DROPS_OFF; - - // The target's next is the loop body block - rv = ((Jump)n).target.next.endCheck(); - - // check to see if the loop condition is true - if (n.first.type == Token.TRUE) - rv &= ~END_DROPS_OFF; - - // look for effect of breaks - rv |= getIntProp(CONTROL_BLOCK_PROP, END_UNREACHED); - - return rv; - } - - - /** - * A general block of code is examined statement by statement. If any - * statement (even compound ones) returns in all branches, then subsequent - * statements are not examined. - * @return logical OR of END_* flags - */ - private int endCheckBlock() - { - Node n; - int rv = END_DROPS_OFF; - - // check each statment and if the statement can continue onto the next - // one, then check the next statement - for (n=first; ((rv & END_DROPS_OFF) != 0) && n != null; n = n.next) - { - rv &= ~END_DROPS_OFF; - rv |= n.endCheck(); - } - return rv; - } - - /** - * A labelled statement implies that there maybe a break to the label. The - * function processes the labelled statement and then checks the - * CONTROL_BLOCK_PROP property to see if there is ever a break to the - * particular label. - * @return logical OR of END_* flags - */ - private int endCheckLabel() - { - int rv = END_UNREACHED; - - rv = next.endCheck(); - rv |= getIntProp(CONTROL_BLOCK_PROP, END_UNREACHED); - - return rv; - } - - /** - * When a break is encountered annotate the statement being broken - * out of by setting its CONTROL_BLOCK_PROP property. - * @return logical OR of END_* flags - */ - private int endCheckBreak() - { - Node n = ((Jump) this).jumpNode; - n.putIntProp(CONTROL_BLOCK_PROP, END_DROPS_OFF); - return END_UNREACHED; - } - - /** - * endCheck() examines the body of a function, doing a basic reachability - * analysis and returns a combination of flags END_* flags that indicate - * how the function execution can terminate. These constitute only the - * pessimistic set of termination conditions. It is possible that at - * runtime certain code paths will never be actually taken. Hence this - * analysis will flag errors in cases where there may not be errors. - * @return logical OR of END_* flags - */ - private int endCheck() - { - switch(type) - { - case Token.BREAK: - return endCheckBreak(); - - case Token.EXPR_VOID: - if (this.first != null) - return first.endCheck(); - return END_DROPS_OFF; - - case Token.YIELD: - return END_YIELDS; - - case Token.CONTINUE: - case Token.THROW: - return END_UNREACHED; - - case Token.RETURN: - if (this.first != null) - return END_RETURNS_VALUE; - else - return END_RETURNS; - - case Token.TARGET: - if (next != null) - return next.endCheck(); - else - return END_DROPS_OFF; - - case Token.LOOP: - return endCheckLoop(); - - case Token.LOCAL_BLOCK: - case Token.BLOCK: - // there are several special kinds of blocks - if (first == null) - return END_DROPS_OFF; - - switch(first.type) { - case Token.LABEL: - return first.endCheckLabel(); - - case Token.IFNE: - return first.endCheckIf(); - - case Token.SWITCH: - return first.endCheckSwitch(); - - case Token.TRY: - return first.endCheckTry(); - - default: - return endCheckBlock(); - } - - default: - return END_DROPS_OFF; - } - } - - public boolean hasSideEffects() - { - switch (type) { - case Token.EXPR_VOID: - case Token.COMMA: - if (last != null) - return last.hasSideEffects(); - else - return true; - - case Token.HOOK: - if (first == null || - first.next == null || - first.next.next == null) - Kit.codeBug(); - return first.next.hasSideEffects() && - first.next.next.hasSideEffects(); - - case Token.ERROR: // Avoid cascaded error messages - case Token.EXPR_RESULT: - case Token.ASSIGN: - case Token.ASSIGN_ADD: - case Token.ASSIGN_SUB: - case Token.ASSIGN_MUL: - case Token.ASSIGN_DIV: - case Token.ASSIGN_MOD: - case Token.ASSIGN_BITOR: - case Token.ASSIGN_BITXOR: - case Token.ASSIGN_BITAND: - case Token.ASSIGN_LSH: - case Token.ASSIGN_RSH: - case Token.ASSIGN_URSH: - case Token.ENTERWITH: - case Token.LEAVEWITH: - case Token.RETURN: - case Token.GOTO: - case Token.IFEQ: - case Token.IFNE: - case Token.NEW: - case Token.DELPROP: - case Token.SETNAME: - case Token.SETPROP: - case Token.SETELEM: - case Token.CALL: - case Token.THROW: - case Token.RETHROW: - case Token.SETVAR: - case Token.CATCH_SCOPE: - case Token.RETURN_RESULT: - case Token.SET_REF: - case Token.DEL_REF: - case Token.REF_CALL: - case Token.TRY: - case Token.SEMI: - case Token.INC: - case Token.DEC: - case Token.EXPORT: - case Token.IMPORT: - case Token.IF: - case Token.ELSE: - case Token.SWITCH: - case Token.WHILE: - case Token.DO: - case Token.FOR: - case Token.BREAK: - case Token.CONTINUE: - case Token.VAR: - case Token.CONST: - case Token.LET: - case Token.LETEXPR: - case Token.WITH: - case Token.WITHEXPR: - case Token.CATCH: - case Token.FINALLY: - case Token.BLOCK: - case Token.LABEL: - case Token.TARGET: - case Token.LOOP: - case Token.JSR: - case Token.SETPROP_OP: - case Token.SETELEM_OP: - case Token.LOCAL_BLOCK: - case Token.SET_REF_OP: - case Token.YIELD: - return true; - - default: - return false; - } - } - - public String toString() - { - if (Token.printTrees) { - StringBuffer sb = new StringBuffer(); - toString(new ObjToIntMap(), sb); - return sb.toString(); - } - return String.valueOf(type); - } - - private void toString(ObjToIntMap printIds, StringBuffer sb) - { - if (Token.printTrees) { - sb.append(Token.name(type)); - if (this instanceof StringNode) { - sb.append(' '); - sb.append(getString()); - Scope scope = getScope(); - if (scope != null) { - sb.append("[scope: "); - appendPrintId(scope, printIds, sb); - sb.append("]"); - } - } else if (this instanceof Node.Scope) { - if (this instanceof ScriptOrFnNode) { - ScriptOrFnNode sof = (ScriptOrFnNode)this; - if (this instanceof FunctionNode) { - FunctionNode fn = (FunctionNode)this; - sb.append(' '); - sb.append(fn.getFunctionName()); - } - sb.append(" [source name: "); - sb.append(sof.getSourceName()); - sb.append("] [encoded source length: "); - sb.append(sof.getEncodedSourceEnd() - - sof.getEncodedSourceStart()); - sb.append("] [base line: "); - sb.append(sof.getBaseLineno()); - sb.append("] [end line: "); - sb.append(sof.getEndLineno()); - sb.append(']'); - } - if (((Node.Scope)this).symbolTable != null) { - sb.append(" [scope "); - appendPrintId(this, printIds, sb); - sb.append(": "); - Iterator iter = ((Node.Scope) this).symbolTable.keySet() - .iterator(); - while (iter.hasNext()) { - sb.append(iter.next()); - sb.append(" "); - } - sb.append("]"); - } - } else if (this instanceof Jump) { - Jump jump = (Jump)this; - if (type == Token.BREAK || type == Token.CONTINUE) { - sb.append(" [label: "); - appendPrintId(jump.getJumpStatement(), printIds, sb); - sb.append(']'); - } else if (type == Token.TRY) { - Node catchNode = jump.target; - Node finallyTarget = jump.getFinally(); - if (catchNode != null) { - sb.append(" [catch: "); - appendPrintId(catchNode, printIds, sb); - sb.append(']'); - } - if (finallyTarget != null) { - sb.append(" [finally: "); - appendPrintId(finallyTarget, printIds, sb); - sb.append(']'); - } - } else if (type == Token.LABEL || type == Token.LOOP - || type == Token.SWITCH) - { - sb.append(" [break: "); - appendPrintId(jump.target, printIds, sb); - sb.append(']'); - if (type == Token.LOOP) { - sb.append(" [continue: "); - appendPrintId(jump.getContinue(), printIds, sb); - sb.append(']'); - } - } else { - sb.append(" [target: "); - appendPrintId(jump.target, printIds, sb); - sb.append(']'); - } - } else if (type == Token.NUMBER) { - sb.append(' '); - sb.append(getDouble()); - } else if (type == Token.TARGET) { - sb.append(' '); - appendPrintId(this, printIds, sb); - } - if (lineno != -1) { - sb.append(' '); - sb.append(lineno); - } - - for (PropListItem x = propListHead; x != null; x = x.next) { - int type = x.type; - sb.append(" ["); - sb.append(propToString(type)); - sb.append(": "); - String value; - switch (type) { - case TARGETBLOCK_PROP : // can't add this as it recurses - value = "target block property"; - break; - case LOCAL_BLOCK_PROP : // can't add this as it is dull - value = "last local block"; - break; - case ISNUMBER_PROP: - switch (x.intValue) { - case BOTH: - value = "both"; - break; - case RIGHT: - value = "right"; - break; - case LEFT: - value = "left"; - break; - default: - throw Kit.codeBug(); - } - break; - case SPECIALCALL_PROP: - switch (x.intValue) { - case SPECIALCALL_EVAL: - value = "eval"; - break; - case SPECIALCALL_WITH: - value = "with"; - break; - default: - // NON_SPECIALCALL should not be stored - throw Kit.codeBug(); - } - break; - case OBJECT_IDS_PROP: { - Object[] a = (Object[]) x.objectValue; - value = "["; - for (int i=0; i < a.length; i++) { - value += a[i].toString(); - if (i+1 < a.length) - value += ", "; - } - value += "]"; - break; - } - default : - Object obj = x.objectValue; - if (obj != null) { - value = obj.toString(); - } else { - value = String.valueOf(x.intValue); - } - break; - } - sb.append(value); - sb.append(']'); - } - } - } - - public String toStringTree(ScriptOrFnNode treeTop) { - if (Token.printTrees) { - StringBuffer sb = new StringBuffer(); - toStringTreeHelper(treeTop, this, null, 0, sb); - return sb.toString(); - } - return null; - } - - private static void toStringTreeHelper(ScriptOrFnNode treeTop, Node n, - ObjToIntMap printIds, - int level, StringBuffer sb) - { - if (Token.printTrees) { - if (printIds == null) { - printIds = new ObjToIntMap(); - generatePrintIds(treeTop, printIds); - } - for (int i = 0; i != level; ++i) { - sb.append(" "); - } - n.toString(printIds, sb); - sb.append('\n'); - for (Node cursor = n.getFirstChild(); cursor != null; - cursor = cursor.getNext()) - { - if (cursor.getType() == Token.FUNCTION) { - int fnIndex = cursor.getExistingIntProp(Node.FUNCTION_PROP); - FunctionNode fn = treeTop.getFunctionNode(fnIndex); - toStringTreeHelper(fn, fn, null, level + 1, sb); - } else { - toStringTreeHelper(treeTop, cursor, printIds, level + 1, sb); - } - } - } - } - - private static void generatePrintIds(Node n, ObjToIntMap map) - { - if (Token.printTrees) { - map.put(n, map.size()); - for (Node cursor = n.getFirstChild(); cursor != null; - cursor = cursor.getNext()) - { - generatePrintIds(cursor, map); - } - } - } - - private static void appendPrintId(Node n, ObjToIntMap printIds, - StringBuffer sb) - { - if (Token.printTrees) { - if (n != null) { - int id = printIds.get(n, -1); - sb.append('#'); - if (id != -1) { - sb.append(id + 1); - } else { - sb.append(""); - } - } - } - } - - int type; // type of the node; Token.NAME for example - Node next; // next sibling - private Node first; // first element of a linked list of children - private Node last; // last element of a linked list of children - protected int lineno = -1; - - /*APPJET*/public int statementEndLineNum = -1; - - /** - * Linked list of properties. Since vast majority of nodes would have - * no more then 2 properties, linked list saves memory and provides - * fast lookup. If this does not holds, propListHead can be replaced - * by UintMap. - */ - private PropListItem propListHead; -} -- cgit v1.2.3