/// <summary>Generate IR for a for..in loop.</summary> /// <remarks>Generate IR for a for..in loop.</remarks> private Node CreateForIn(int declType, Node loop, Node lhs, Node obj, Node body, bool isForEach) { int destructuring = -1; int destructuringLen = 0; Node lvalue; int type = lhs.GetType(); if (type == Token.VAR || type == Token.LET) { Node kid = lhs.GetLastChild(); int kidType = kid.GetType(); if (kidType == Token.ARRAYLIT || kidType == Token.OBJECTLIT) { type = destructuring = kidType; lvalue = kid; destructuringLen = 0; if (kid is ArrayLiteral) { destructuringLen = ((ArrayLiteral)kid).GetDestructuringLength(); } } else { if (kidType == Token.NAME) { lvalue = Node.NewString(Token.NAME, kid.GetString()); } else { ReportError("msg.bad.for.in.lhs"); return null; } } } else { if (type == Token.ARRAYLIT || type == Token.OBJECTLIT) { destructuring = type; lvalue = lhs; destructuringLen = 0; if (lhs is ArrayLiteral) { destructuringLen = ((ArrayLiteral)lhs).GetDestructuringLength(); } } else { lvalue = MakeReference(lhs); if (lvalue == null) { ReportError("msg.bad.for.in.lhs"); return null; } } } Node localBlock = new Node(Token.LOCAL_BLOCK); int initType = isForEach ? Token.ENUM_INIT_VALUES : (destructuring != -1 ? Token.ENUM_INIT_ARRAY : Token.ENUM_INIT_KEYS); Node init = new Node(initType, obj); init.PutProp(Node.LOCAL_BLOCK_PROP, localBlock); Node cond = new Node(Token.ENUM_NEXT); cond.PutProp(Node.LOCAL_BLOCK_PROP, localBlock); Node id = new Node(Token.ENUM_ID); id.PutProp(Node.LOCAL_BLOCK_PROP, localBlock); Node newBody = new Node(Token.BLOCK); Node assign; if (destructuring != -1) { assign = CreateDestructuringAssignment(declType, lvalue, id); if (!isForEach && (destructuring == Token.OBJECTLIT || destructuringLen != 2)) { // destructuring assignment is only allowed in for..each or // with an array type of length 2 (to hold key and value) ReportError("msg.bad.for.in.destruct"); } } else { assign = SimpleAssignment(lvalue, id); } newBody.AddChildToBack(new Node(Token.EXPR_VOID, assign)); newBody.AddChildToBack(body); loop = CreateLoop((Jump)loop, LOOP_WHILE, newBody, cond, null, null); loop.AddChildToFront(init); if (type == Token.VAR || type == Token.LET) { loop.AddChildToFront(lhs); } localBlock.AddChildToBack(loop); return localBlock; }
private int RewriteForNumberVariables(Node n, int desired) { switch (n.GetType()) { case Token.EXPR_VOID: { Node child = n.GetFirstChild(); int type = RewriteForNumberVariables(child, NumberType); if (type == NumberType) { n.PutIntProp(Node.ISNUMBER_PROP, Node.BOTH); } return NoType; } case Token.NUMBER: { n.PutIntProp(Node.ISNUMBER_PROP, Node.BOTH); return NumberType; } case Token.GETVAR: { int varIndex = theFunction.GetVarIndex(n); if (inDirectCallFunction && theFunction.IsParameter(varIndex) && desired == NumberType) { n.PutIntProp(Node.ISNUMBER_PROP, Node.BOTH); return NumberType; } else { if (theFunction.IsNumberVar(varIndex)) { n.PutIntProp(Node.ISNUMBER_PROP, Node.BOTH); return NumberType; } } return NoType; } case Token.INC: case Token.DEC: { Node child = n.GetFirstChild(); int type = RewriteForNumberVariables(child, NumberType); if (child.GetType() == Token.GETVAR) { if (type == NumberType && !ConvertParameter(child)) { n.PutIntProp(Node.ISNUMBER_PROP, Node.BOTH); MarkDCPNumberContext(child); return NumberType; } return NoType; } else { if (child.GetType() == Token.GETELEM || child.GetType() == Token.GETPROP) { return type; } } return NoType; } case Token.SETVAR: { Node lChild = n.GetFirstChild(); Node rChild = lChild.GetNext(); int rType = RewriteForNumberVariables(rChild, NumberType); int varIndex = theFunction.GetVarIndex(n); if (inDirectCallFunction && theFunction.IsParameter(varIndex)) { if (rType == NumberType) { if (!ConvertParameter(rChild)) { n.PutIntProp(Node.ISNUMBER_PROP, Node.BOTH); return NumberType; } MarkDCPNumberContext(rChild); return NoType; } else { return rType; } } else { if (theFunction.IsNumberVar(varIndex)) { if (rType != NumberType) { n.RemoveChild(rChild); n.AddChildToBack(new Node(Token.TO_DOUBLE, rChild)); } n.PutIntProp(Node.ISNUMBER_PROP, Node.BOTH); MarkDCPNumberContext(rChild); return NumberType; } else { if (rType == NumberType) { if (!ConvertParameter(rChild)) { n.RemoveChild(rChild); n.AddChildToBack(new Node(Token.TO_OBJECT, rChild)); } } return NoType; } } goto case Token.LE; } case Token.LE: case Token.LT: case Token.GE: case Token.GT: { Node lChild = n.GetFirstChild(); Node rChild = lChild.GetNext(); int lType = RewriteForNumberVariables(lChild, NumberType); int rType = RewriteForNumberVariables(rChild, NumberType); MarkDCPNumberContext(lChild); MarkDCPNumberContext(rChild); if (ConvertParameter(lChild)) { if (ConvertParameter(rChild)) { return NoType; } else { if (rType == NumberType) { n.PutIntProp(Node.ISNUMBER_PROP, Node.RIGHT); } } } else { if (ConvertParameter(rChild)) { if (lType == NumberType) { n.PutIntProp(Node.ISNUMBER_PROP, Node.LEFT); } } else { if (lType == NumberType) { if (rType == NumberType) { n.PutIntProp(Node.ISNUMBER_PROP, Node.BOTH); } else { n.PutIntProp(Node.ISNUMBER_PROP, Node.LEFT); } } else { if (rType == NumberType) { n.PutIntProp(Node.ISNUMBER_PROP, Node.RIGHT); } } } } // we actually build a boolean value return NoType; } case Token.ADD: { Node lChild = n.GetFirstChild(); Node rChild = lChild.GetNext(); int lType = RewriteForNumberVariables(lChild, NumberType); int rType = RewriteForNumberVariables(rChild, NumberType); if (ConvertParameter(lChild)) { if (ConvertParameter(rChild)) { return NoType; } else { if (rType == NumberType) { n.PutIntProp(Node.ISNUMBER_PROP, Node.RIGHT); } } } else { if (ConvertParameter(rChild)) { if (lType == NumberType) { n.PutIntProp(Node.ISNUMBER_PROP, Node.LEFT); } } else { if (lType == NumberType) { if (rType == NumberType) { n.PutIntProp(Node.ISNUMBER_PROP, Node.BOTH); return NumberType; } else { n.PutIntProp(Node.ISNUMBER_PROP, Node.LEFT); } } else { if (rType == NumberType) { n.PutIntProp(Node.ISNUMBER_PROP, Node.RIGHT); } } } } return NoType; } case Token.BITXOR: case Token.BITOR: case Token.BITAND: case Token.RSH: case Token.LSH: case Token.SUB: case Token.MUL: case Token.DIV: case Token.MOD: { Node lChild = n.GetFirstChild(); Node rChild = lChild.GetNext(); int lType = RewriteForNumberVariables(lChild, NumberType); int rType = RewriteForNumberVariables(rChild, NumberType); MarkDCPNumberContext(lChild); MarkDCPNumberContext(rChild); if (lType == NumberType) { if (rType == NumberType) { n.PutIntProp(Node.ISNUMBER_PROP, Node.BOTH); return NumberType; } else { if (!ConvertParameter(rChild)) { n.RemoveChild(rChild); n.AddChildToBack(new Node(Token.TO_DOUBLE, rChild)); n.PutIntProp(Node.ISNUMBER_PROP, Node.BOTH); } return NumberType; } } else { if (rType == NumberType) { if (!ConvertParameter(lChild)) { n.RemoveChild(lChild); n.AddChildToFront(new Node(Token.TO_DOUBLE, lChild)); n.PutIntProp(Node.ISNUMBER_PROP, Node.BOTH); } return NumberType; } else { if (!ConvertParameter(lChild)) { n.RemoveChild(lChild); n.AddChildToFront(new Node(Token.TO_DOUBLE, lChild)); } if (!ConvertParameter(rChild)) { n.RemoveChild(rChild); n.AddChildToBack(new Node(Token.TO_DOUBLE, rChild)); } n.PutIntProp(Node.ISNUMBER_PROP, Node.BOTH); return NumberType; } } goto case Token.SETELEM; } case Token.SETELEM: case Token.SETELEM_OP: { Node arrayBase = n.GetFirstChild(); Node arrayIndex = arrayBase.GetNext(); Node rValue = arrayIndex.GetNext(); int baseType = RewriteForNumberVariables(arrayBase, NumberType); if (baseType == NumberType) { if (!ConvertParameter(arrayBase)) { n.RemoveChild(arrayBase); n.AddChildToFront(new Node(Token.TO_OBJECT, arrayBase)); } } int indexType = RewriteForNumberVariables(arrayIndex, NumberType); if (indexType == NumberType) { if (!ConvertParameter(arrayIndex)) { // setting the ISNUMBER_PROP signals the codegen // to use the OptRuntime.setObjectIndex that takes // a double index n.PutIntProp(Node.ISNUMBER_PROP, Node.LEFT); } } int rValueType = RewriteForNumberVariables(rValue, NumberType); if (rValueType == NumberType) { if (!ConvertParameter(rValue)) { n.RemoveChild(rValue); n.AddChildToBack(new Node(Token.TO_OBJECT, rValue)); } } return NoType; } case Token.GETELEM: { Node arrayBase = n.GetFirstChild(); Node arrayIndex = arrayBase.GetNext(); int baseType = RewriteForNumberVariables(arrayBase, NumberType); if (baseType == NumberType) { if (!ConvertParameter(arrayBase)) { n.RemoveChild(arrayBase); n.AddChildToFront(new Node(Token.TO_OBJECT, arrayBase)); } } int indexType = RewriteForNumberVariables(arrayIndex, NumberType); if (indexType == NumberType) { if (!ConvertParameter(arrayIndex)) { // setting the ISNUMBER_PROP signals the codegen // to use the OptRuntime.getObjectIndex that takes // a double index n.PutIntProp(Node.ISNUMBER_PROP, Node.RIGHT); } } return NoType; } case Token.CALL: { Node child = n.GetFirstChild(); // the function node // must be an object RewriteAsObjectChildren(child, child.GetFirstChild()); child = child.GetNext(); // the first arg OptFunctionNode target = (OptFunctionNode)n.GetProp(Node.DIRECTCALL_PROP); if (target != null) { while (child != null) { int type = RewriteForNumberVariables(child, NumberType); if (type == NumberType) { MarkDCPNumberContext(child); } child = child.GetNext(); } } else { RewriteAsObjectChildren(n, child); } return NoType; } default: { RewriteAsObjectChildren(n, n.GetFirstChild()); return NoType; } } }
private static Node AddBeforeCurrent(Node parent, Node previous, Node current, Node toAdd) { if (previous == null) { if (!(current == parent.GetFirstChild())) { Kit.CodeBug(); } parent.AddChildToFront(toAdd); } else { if (!(current == previous.GetNext())) { Kit.CodeBug(); } parent.AddChildAfter(toAdd, previous); } return toAdd; }