📄 node.java
字号:
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 <tt>getType() == Token.NUMBER</tt> */ 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 <value>" * 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -