Esempio n. 1
0
		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;
				}
			}
		}
Esempio n. 2
0
		private Node TransformObjectLiteral(ObjectLiteral node)
		{
			if (node.IsDestructuring())
			{
				return node;
			}
			// createObjectLiteral rewrites its argument as object
			// creation plus object property entries, so later compiler
			// stages don't need to know about object literals.
			decompiler.AddToken(Token.LC);
			IList<ObjectProperty> elems = node.GetElements();
			Node @object = new Node(Token.OBJECTLIT);
			object[] properties;
			if (elems.IsEmpty())
			{
				properties = ScriptRuntime.emptyArgs;
			}
			else
			{
				int size = elems.Count;
				int i = 0;
				properties = new object[size];
				foreach (ObjectProperty prop in elems)
				{
					if (prop.IsGetter())
					{
						decompiler.AddToken(Token.GET);
					}
					else
					{
						if (prop.IsSetter())
						{
							decompiler.AddToken(Token.SET);
						}
					}
					properties[i++] = GetPropKey(prop.GetLeft());
					// OBJECTLIT is used as ':' in object literal for
					// decompilation to solve spacing ambiguity.
					if (!(prop.IsGetter() || prop.IsSetter()))
					{
						decompiler.AddToken(Token.OBJECTLIT);
					}
					Node right = Transform(prop.GetRight());
					if (prop.IsGetter())
					{
						right = CreateUnary(Token.GET, right);
					}
					else
					{
						if (prop.IsSetter())
						{
							right = CreateUnary(Token.SET, right);
						}
					}
					@object.AddChildToBack(right);
					if (i < size)
					{
						decompiler.AddToken(Token.COMMA);
					}
				}
			}
			decompiler.AddToken(Token.RC);
			@object.PutProp(Node.OBJECT_IDS_PROP, properties);
			return @object;
		}
Esempio n. 3
0
		private void RewriteAsObjectChildren(Node n, Node child)
		{
			// Force optimized children to be objects
			while (child != null)
			{
				Node nextChild = child.GetNext();
				int type = RewriteForNumberVariables(child, NoType);
				if (type == NumberType)
				{
					if (!ConvertParameter(child))
					{
						n.RemoveChild(child);
						Node nuChild = new Node(Token.TO_OBJECT, child);
						if (nextChild == null)
						{
							n.AddChildToBack(nuChild);
						}
						else
						{
							n.AddChildBefore(nuChild, nextChild);
						}
					}
				}
				child = nextChild;
			}
		}
Esempio n. 4
0
		private Node TransformArrayComp(ArrayComprehension node)
		{
			// An array comprehension expression such as
			//
			//   [expr for (x in foo) for each ([y, z] in bar) if (cond)]
			//
			// is rewritten approximately as
			//
			// new Scope(ARRAYCOMP) {
			//   new Node(BLOCK) {
			//     let tmp1 = new Array;
			//     for (let x in foo) {
			//       for each (let tmp2 in bar) {
			//         if (cond) {
			//           tmp1.push([y, z] = tmp2, expr);
			//         }
			//       }
			//     }
			//   }
			//   createName(tmp1)
			// }
			int lineno = node.GetLineno();
			Scope scopeNode = CreateScopeNode(Token.ARRAYCOMP, lineno);
			string arrayName = currentScriptOrFn.GetNextTempName();
			PushScope(scopeNode);
			try
			{
				DefineSymbol(Token.LET, arrayName, false);
				Node block = new Node(Token.BLOCK, lineno);
				Node newArray = CreateCallOrNew(Token.NEW, CreateName("Array"));
				Node init = new Node(Token.EXPR_VOID, CreateAssignment(Token.ASSIGN, CreateName(arrayName), newArray), lineno);
				block.AddChildToBack(init);
				block.AddChildToBack(ArrayCompTransformHelper(node, arrayName));
				scopeNode.AddChildToBack(block);
				scopeNode.AddChildToBack(CreateName(arrayName));
				return scopeNode;
			}
			finally
			{
				PopScope();
			}
		}
Esempio n. 5
0
		private Node TransformArrayLiteral(ArrayLiteral node)
		{
			if (node.IsDestructuring())
			{
				return node;
			}
			decompiler.AddToken(Token.LB);
			IList<AstNode> elems = node.GetElements();
			Node array = new Node(Token.ARRAYLIT);
			IList<int> skipIndexes = null;
			for (int i = 0; i < elems.Count; ++i)
			{
				AstNode elem = elems[i];
				if (elem.GetType() != Token.EMPTY)
				{
					array.AddChildToBack(Transform(elem));
				}
				else
				{
					if (skipIndexes == null)
					{
						skipIndexes = new List<int>();
					}
					skipIndexes.Add(i);
				}
				if (i < elems.Count - 1)
				{
					decompiler.AddToken(Token.COMMA);
				}
			}
			decompiler.AddToken(Token.RB);
			array.PutIntProp(Node.DESTRUCTURING_ARRAY_LENGTH, node.GetDestructuringLength());
			if (skipIndexes != null)
			{
				int[] skips = new int[skipIndexes.Count];
				for (int i_1 = 0; i_1 < skipIndexes.Count; i_1++)
				{
					skips[i_1] = skipIndexes[i_1];
				}
				array.PutProp(Node.SKIP_INDEXES_PROP, skips);
			}
			return array;
		}
Esempio n. 6
0
		private Node CreateWith(Node obj, Node body, int lineno)
		{
			SetRequiresActivation();
			Node result = new Node(Token.BLOCK, lineno);
			result.AddChildToBack(new Node(Token.ENTERWITH, obj));
			Node bodyNode = new Node(Token.WITH, body, lineno);
			result.AddChildrenToBack(bodyNode);
			result.AddChildToBack(new Node(Token.LEAVEWITH));
			return result;
		}
Esempio n. 7
0
		private Node CreateIf(Node cond, Node ifTrue, Node ifFalse, int lineno)
		{
			int condStatus = IsAlwaysDefinedBoolean(cond);
			if (condStatus == ALWAYS_TRUE_BOOLEAN)
			{
				return ifTrue;
			}
			else
			{
				if (condStatus == ALWAYS_FALSE_BOOLEAN)
				{
					if (ifFalse != null)
					{
						return ifFalse;
					}
					// Replace if (false) xxx by empty block
					return new Node(Token.BLOCK, lineno);
				}
			}
			Node result = new Node(Token.BLOCK, lineno);
			Node ifNotTarget = Node.NewTarget();
			Jump IFNE = new Jump(Token.IFNE, cond);
			IFNE.target = ifNotTarget;
			result.AddChildToBack(IFNE);
			result.AddChildrenToBack(ifTrue);
			if (ifFalse != null)
			{
				Node endTarget = Node.NewTarget();
				result.AddChildToBack(MakeJump(Token.GOTO, endTarget));
				result.AddChildToBack(ifNotTarget);
				result.AddChildrenToBack(ifFalse);
				result.AddChildToBack(endTarget);
			}
			else
			{
				result.AddChildToBack(ifNotTarget);
			}
			return result;
		}
Esempio n. 8
0
		/// <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;
		}
Esempio n. 9
0
		/// <summary>
		/// 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
		/// - a finally handler
		/// ...
		/// </summary>
		/// <remarks>
		/// 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
		/// - a finally handler
		/// ... and a goto to GOTO around these handlers.
		/// </remarks>
		private Node CreateTryCatchFinally(Node tryBlock, Node catchBlocks, Node finallyBlock, int lineno)
		{
			bool hasFinally = (finallyBlock != null) && (finallyBlock.GetType() != Token.BLOCK || finallyBlock.HasChildren());
			// short circuit
			if (tryBlock.GetType() == Token.BLOCK && !tryBlock.HasChildren() && !hasFinally)
			{
				return tryBlock;
			}
			bool hasCatch = catchBlocks.HasChildren();
			// short circuit
			if (!hasFinally && !hasCatch)
			{
				// bc finally might be an empty block...
				return tryBlock;
			}
			Node handlerBlock = new Node(Token.LOCAL_BLOCK);
			Jump pn = new Jump(Token.TRY, tryBlock, lineno);
			pn.PutProp(Node.LOCAL_BLOCK_PROP, handlerBlock);
			if (hasCatch)
			{
				// jump around catch code
				Node endCatch = Node.NewTarget();
				pn.AddChildToBack(MakeJump(Token.GOTO, endCatch));
				// make a TARGET for the catch that the tcf node knows about
				Node catchTarget = Node.NewTarget();
				pn.target = catchTarget;
				// mark it
				pn.AddChildToBack(catchTarget);
				//
				//  Given
				//
				//   try {
				//       tryBlock;
				//   } catch (e if condition1) {
				//       something1;
				//   ...
				//
				//   } catch (e if conditionN) {
				//       somethingN;
				//   } catch (e) {
				//       somethingDefault;
				//   }
				//
				//  rewrite as
				//
				//   try {
				//       tryBlock;
				//       goto after_catch:
				//   } catch (x) {
				//       with (newCatchScope(e, x)) {
				//           if (condition1) {
				//               something1;
				//               goto after_catch;
				//           }
				//       }
				//   ...
				//       with (newCatchScope(e, x)) {
				//           if (conditionN) {
				//               somethingN;
				//               goto after_catch;
				//           }
				//       }
				//       with (newCatchScope(e, x)) {
				//           somethingDefault;
				//           goto after_catch;
				//       }
				//   }
				// after_catch:
				//
				// If there is no default catch, then the last with block
				// arround  "somethingDefault;" is replaced by "rethrow;"
				// It is assumed that catch handler generation will store
				// exeception object in handlerBlock register
				// Block with local for exception scope objects
				Node catchScopeBlock = new Node(Token.LOCAL_BLOCK);
				// expects catchblocks children to be (cond block) pairs.
				Node cb = catchBlocks.GetFirstChild();
				bool hasDefault = false;
				int scopeIndex = 0;
				while (cb != null)
				{
					int catchLineNo = cb.GetLineno();
					Node name = cb.GetFirstChild();
					Node cond = name.GetNext();
					Node catchStatement = cond.GetNext();
					cb.RemoveChild(name);
					cb.RemoveChild(cond);
					cb.RemoveChild(catchStatement);
					// Add goto to the catch statement to jump out of catch
					// but prefix it with LEAVEWITH since try..catch produces
					// "with"code in order to limit the scope of the exception
					// object.
					catchStatement.AddChildToBack(new Node(Token.LEAVEWITH));
					catchStatement.AddChildToBack(MakeJump(Token.GOTO, endCatch));
					// Create condition "if" when present
					Node condStmt;
					if (cond.GetType() == Token.EMPTY)
					{
						condStmt = catchStatement;
						hasDefault = true;
					}
					else
					{
						condStmt = CreateIf(cond, catchStatement, null, catchLineNo);
					}
					// Generate code to create the scope object and store
					// it in catchScopeBlock register
					Node catchScope = new Node(Token.CATCH_SCOPE, name, CreateUseLocal(handlerBlock));
					catchScope.PutProp(Node.LOCAL_BLOCK_PROP, catchScopeBlock);
					catchScope.PutIntProp(Node.CATCH_SCOPE_PROP, scopeIndex);
					catchScopeBlock.AddChildToBack(catchScope);
					// Add with statement based on catch scope object
					catchScopeBlock.AddChildToBack(CreateWith(CreateUseLocal(catchScopeBlock), condStmt, catchLineNo));
					// move to next cb
					cb = cb.GetNext();
					++scopeIndex;
				}
				pn.AddChildToBack(catchScopeBlock);
				if (!hasDefault)
				{
					// Generate code to rethrow if no catch clause was executed
					Node rethrow = new Node(Token.RETHROW);
					rethrow.PutProp(Node.LOCAL_BLOCK_PROP, handlerBlock);
					pn.AddChildToBack(rethrow);
				}
				pn.AddChildToBack(endCatch);
			}
			if (hasFinally)
			{
				Node finallyTarget = Node.NewTarget();
				pn.SetFinally(finallyTarget);
				// add jsr finally to the try block
				pn.AddChildToBack(MakeJump(Token.JSR, finallyTarget));
				// jump around finally code
				Node finallyEnd = Node.NewTarget();
				pn.AddChildToBack(MakeJump(Token.GOTO, finallyEnd));
				pn.AddChildToBack(finallyTarget);
				Node fBlock = new Node(Token.FINALLY, finallyBlock);
				fBlock.PutProp(Node.LOCAL_BLOCK_PROP, handlerBlock);
				pn.AddChildToBack(fBlock);
				pn.AddChildToBack(finallyEnd);
			}
			handlerBlock.AddChildToBack(pn);
			return handlerBlock;
		}
Esempio n. 10
0
		private void CloseSwitch(Node switchBlock)
		{
			if (switchBlock.GetType() != Token.BLOCK)
			{
				throw Kit.CodeBug();
			}
			Jump switchNode = (Jump)switchBlock.GetFirstChild();
			if (switchNode.GetType() != Token.SWITCH)
			{
				throw Kit.CodeBug();
			}
			Node switchBreakTarget = Node.NewTarget();
			// switchNode.target is only used by NodeTransformer
			// to detect switch end
			switchNode.target = switchBreakTarget;
			Node defaultTarget = switchNode.GetDefault();
			if (defaultTarget == null)
			{
				defaultTarget = switchBreakTarget;
			}
			switchBlock.AddChildAfter(MakeJump(Token.GOTO, defaultTarget), switchNode);
			switchBlock.AddChildToBack(switchBreakTarget);
		}
Esempio n. 11
0
		private Node InitFunction(FunctionNode fnNode, int functionIndex, Node statements, int functionType)
		{
			fnNode.SetFunctionType(functionType);
			fnNode.AddChildToBack(statements);
			int functionCount = fnNode.GetFunctionCount();
			if (functionCount != 0)
			{
				// Functions containing other functions require activation objects
				fnNode.SetRequiresActivation();
			}
			if (functionType == FunctionNode.FUNCTION_EXPRESSION)
			{
				Name name = fnNode.GetFunctionName();
				if (name != null && name.Length() != 0 && fnNode.GetSymbol(name.GetIdentifier()) == null)
				{
					// A function expression needs to have its name as a
					// variable (if it isn't already allocated as a variable).
					// See ECMA Ch. 13.  We add code to the beginning of the
					// function to initialize a local variable of the
					// function's name to the function value, but only if the
					// function doesn't already define a formal parameter, var,
					// or nested function with the same name.
					fnNode.PutSymbol(new Symbol(Token.FUNCTION, name.GetIdentifier()));
					Node setFn = new Node(Token.EXPR_VOID, new Node(Token.SETNAME, Node.NewString(Token.BINDNAME, name.GetIdentifier()), new Node(Token.THISFN)));
					statements.AddChildrenToFront(setFn);
				}
			}
			// Add return to end if needed.
			Node lastStmt = statements.GetLastChild();
			if (lastStmt == null || lastStmt.GetType() != Token.RETURN)
			{
				statements.AddChildToBack(new Node(Token.RETURN));
			}
			Node result = Node.NewString(Token.FUNCTION, fnNode.GetName());
			result.PutIntProp(Node.FUNCTION_PROP, functionIndex);
			return result;
		}
Esempio n. 12
0
		/// <summary>If caseExpression argument is null it indicates a default label.</summary>
		/// <remarks>If caseExpression argument is null it indicates a default label.</remarks>
		private void AddSwitchCase(Node switchBlock, Node caseExpression, Node statements)
		{
			if (switchBlock.GetType() != Token.BLOCK)
			{
				throw Kit.CodeBug();
			}
			Jump switchNode = (Jump)switchBlock.GetFirstChild();
			if (switchNode.GetType() != Token.SWITCH)
			{
				throw Kit.CodeBug();
			}
			Node gotoTarget = Node.NewTarget();
			if (caseExpression != null)
			{
				Jump caseNode = new Jump(Token.CASE, caseExpression);
				caseNode.target = gotoTarget;
				switchNode.AddChildToBack(caseNode);
			}
			else
			{
				switchNode.SetDefault(gotoTarget);
			}
			switchBlock.AddChildToBack(gotoTarget);
			switchBlock.AddChildToBack(statements);
		}
Esempio n. 13
0
		private Node TransformXmlLiteral(XmlLiteral node)
		{
			// a literal like <foo>{bar}</foo> is rewritten as
			//   new XML("<foo>" + bar + "</foo>");
			Node pnXML = new Node(Token.NEW, node.GetLineno());
			IList<XmlFragment> frags = node.GetFragments();
			XmlString first = (XmlString)frags[0];
			bool anon = first.GetXml().Trim().StartsWith("<>");
			pnXML.AddChildToBack(CreateName(anon ? "XMLList" : "XML"));
			Node pn = null;
			foreach (XmlFragment frag in frags)
			{
				if (frag is XmlString)
				{
					string xml = ((XmlString)frag).GetXml();
					decompiler.AddName(xml);
					if (pn == null)
					{
						pn = CreateString(xml);
					}
					else
					{
						pn = CreateBinary(Token.ADD, pn, CreateString(xml));
					}
				}
				else
				{
					XmlExpression xexpr = (XmlExpression)frag;
					bool isXmlAttr = xexpr.IsXmlAttribute();
					Node expr;
					decompiler.AddToken(Token.LC);
					if (xexpr.GetExpression() is EmptyExpression)
					{
						expr = CreateString(string.Empty);
					}
					else
					{
						expr = Transform(xexpr.GetExpression());
					}
					decompiler.AddToken(Token.RC);
					if (isXmlAttr)
					{
						// Need to put the result in double quotes
						expr = CreateUnary(Token.ESCXMLATTR, expr);
						Node prepend = CreateBinary(Token.ADD, CreateString("\""), expr);
						expr = CreateBinary(Token.ADD, prepend, CreateString("\""));
					}
					else
					{
						expr = CreateUnary(Token.ESCXMLTEXT, expr);
					}
					pn = CreateBinary(Token.ADD, pn, expr);
				}
			}
			pnXML.AddChildToBack(pn);
			return pnXML;
		}
Esempio n. 14
0
		private Node TransformScript(ScriptNode node)
		{
			decompiler.AddToken(Token.SCRIPT);
			if (currentScope != null)
			{
				Kit.CodeBug();
			}
			currentScope = node;
			Node body = new Node(Token.BLOCK);
			foreach (Node kid in node)
			{
				body.AddChildToBack(Transform((AstNode)kid));
			}
			node.RemoveChildren();
			Node children = body.GetFirstChild();
			if (children != null)
			{
				node.AddChildrenToBack(children);
			}
			return node;
		}
Esempio n. 15
0
		private void TransformCompilationUnit_r(ScriptNode tree, Node parent, Scope scope, bool createScopeObjects, bool inStrictMode)
		{
			Node node = null;
			for (; ; )
			{
				Node previous = null;
				if (node == null)
				{
					node = parent.GetFirstChild();
				}
				else
				{
					previous = node;
					node = node.GetNext();
				}
				if (node == null)
				{
					break;
				}
				int type = node.GetType();
				if (createScopeObjects && (type == Token.BLOCK || type == Token.LOOP || type == Token.ARRAYCOMP) && (node is Scope))
				{
					Scope newScope = (Scope)node;
					if (newScope.GetSymbolTable() != null)
					{
						// transform to let statement so we get a with statement
						// created to contain scoped let variables
						Node let = new Node(type == Token.ARRAYCOMP ? Token.LETEXPR : Token.LET);
						Node innerLet = new Node(Token.LET);
						let.AddChildToBack(innerLet);
						foreach (string name in newScope.GetSymbolTable().Keys)
						{
							innerLet.AddChildToBack(Node.NewString(Token.NAME, name));
						}
						newScope.SetSymbolTable(null);
						// so we don't transform again
						Node oldNode = node;
						node = ReplaceCurrent(parent, previous, node, let);
						type = node.GetType();
						let.AddChildToBack(oldNode);
					}
				}
				switch (type)
				{
					case Token.LABEL:
					case Token.SWITCH:
					case Token.LOOP:
					{
						loops.Push(node);
						loopEnds.Push(((Jump)node).target);
						break;
					}

					case Token.WITH:
					{
						loops.Push(node);
						Node leave = node.GetNext();
						if (leave.GetType() != Token.LEAVEWITH)
						{
							Kit.CodeBug();
						}
						loopEnds.Push(leave);
						break;
					}

					case Token.TRY:
					{
						Jump jump = (Jump)node;
						Node finallytarget = jump.GetFinally();
						if (finallytarget != null)
						{
							hasFinally = true;
							loops.Push(node);
							loopEnds.Push(finallytarget);
						}
						break;
					}

					case Token.TARGET:
					case Token.LEAVEWITH:
					{
						if (!loopEnds.IsEmpty() && loopEnds.Peek() == node)
						{
							loopEnds.Pop();
							loops.Pop();
						}
						break;
					}

					case Token.YIELD:
					{
						((FunctionNode)tree).AddResumptionPoint(node);
						break;
					}

					case Token.RETURN:
					{
						bool isGenerator = tree.GetType() == Token.FUNCTION && ((FunctionNode)tree).IsGenerator();
						if (isGenerator)
						{
							node.PutIntProp(Node.GENERATOR_END_PROP, 1);
						}
						if (!hasFinally)
						{
							break;
						}
						// skip the whole mess.
						Node unwindBlock = null;
						for (int i = loops.Size() - 1; i >= 0; i--)
						{
							Node n = (Node)loops.Get(i);
							int elemtype = n.GetType();
							if (elemtype == Token.TRY || elemtype == Token.WITH)
							{
								Node unwind;
								if (elemtype == Token.TRY)
								{
									Jump jsrnode = new Jump(Token.JSR);
									Node jsrtarget = ((Jump)n).GetFinally();
									jsrnode.target = jsrtarget;
									unwind = jsrnode;
								}
								else
								{
									unwind = new Node(Token.LEAVEWITH);
								}
								if (unwindBlock == null)
								{
									unwindBlock = new Node(Token.BLOCK, node.GetLineno());
								}
								unwindBlock.AddChildToBack(unwind);
							}
						}
						if (unwindBlock != null)
						{
							Node returnNode = node;
							Node returnExpr = returnNode.GetFirstChild();
							node = ReplaceCurrent(parent, previous, node, unwindBlock);
							if (returnExpr == null || isGenerator)
							{
								unwindBlock.AddChildToBack(returnNode);
							}
							else
							{
								Node store = new Node(Token.EXPR_RESULT, returnExpr);
								unwindBlock.AddChildToFront(store);
								returnNode = new Node(Token.RETURN_RESULT);
								unwindBlock.AddChildToBack(returnNode);
								// transform return expression
								TransformCompilationUnit_r(tree, store, scope, createScopeObjects, inStrictMode);
							}
							// skip transformCompilationUnit_r to avoid infinite loop
							goto siblingLoop_continue;
						}
						break;
					}

					case Token.BREAK:
					case Token.CONTINUE:
					{
						Jump jump = (Jump)node;
						Jump jumpStatement = jump.GetJumpStatement();
						if (jumpStatement == null)
						{
							Kit.CodeBug();
						}
						for (int i = loops.Size(); ; )
						{
							if (i == 0)
							{
								// Parser/IRFactory ensure that break/continue
								// always has a jump statement associated with it
								// which should be found
								throw Kit.CodeBug();
							}
							--i;
							Node n = (Node)loops.Get(i);
							if (n == jumpStatement)
							{
								break;
							}
							int elemtype = n.GetType();
							if (elemtype == Token.WITH)
							{
								Node leave = new Node(Token.LEAVEWITH);
								previous = AddBeforeCurrent(parent, previous, node, leave);
							}
							else
							{
								if (elemtype == Token.TRY)
								{
									Jump tryNode = (Jump)n;
									Jump jsrFinally = new Jump(Token.JSR);
									jsrFinally.target = tryNode.GetFinally();
									previous = AddBeforeCurrent(parent, previous, node, jsrFinally);
								}
							}
						}
						if (type == Token.BREAK)
						{
							jump.target = jumpStatement.target;
						}
						else
						{
							jump.target = jumpStatement.GetContinue();
						}
						jump.SetType(Token.GOTO);
						break;
					}

					case Token.CALL:
					{
						VisitCall(node, tree);
						break;
					}

					case Token.NEW:
					{
						VisitNew(node, tree);
						break;
					}

					case Token.LETEXPR:
					case Token.LET:
					{
						Node child = node.GetFirstChild();
						if (child.GetType() == Token.LET)
						{
							// We have a let statement or expression rather than a
							// let declaration
							bool createWith = tree.GetType() != Token.FUNCTION || ((FunctionNode)tree).RequiresActivation();
							node = VisitLet(createWith, parent, previous, node);
							break;
						}
						goto case Token.CONST;
					}

					case Token.CONST:
					case Token.VAR:
					{
						// fall through to process let declaration...
						Node result = new Node(Token.BLOCK);
						for (Node cursor = node.GetFirstChild(); cursor != null; )
						{
							// Move cursor to next before createAssignment gets chance
							// to change n.next
							Node n = cursor;
							cursor = cursor.GetNext();
							if (n.GetType() == Token.NAME)
							{
								if (!n.HasChildren())
								{
									continue;
								}
								Node init = n.GetFirstChild();
								n.RemoveChild(init);
								n.SetType(Token.BINDNAME);
								n = new Node(type == Token.CONST ? Token.SETCONST : Token.SETNAME, n, init);
							}
							else
							{
								// May be a destructuring assignment already transformed
								// to a LETEXPR
								if (n.GetType() != Token.LETEXPR)
								{
									throw Kit.CodeBug();
								}
							}
							Node pop = new Node(Token.EXPR_VOID, n, node.GetLineno());
							result.AddChildToBack(pop);
						}
						node = ReplaceCurrent(parent, previous, node, result);
						break;
					}

					case Token.TYPEOFNAME:
					{
						Scope defining = scope.GetDefiningScope(node.GetString());
						if (defining != null)
						{
							node.SetScope(defining);
						}
						break;
					}

					case Token.TYPEOF:
					case Token.IFNE:
					{
						Node child = node.GetFirstChild();
						if (type == Token.IFNE)
						{
							while (child.GetType() == Token.NOT)
							{
								child = child.GetFirstChild();
							}
							if (child.GetType() == Token.EQ || child.GetType() == Token.NE)
							{
								Node first = child.GetFirstChild();
								Node last = child.GetLastChild();
								if (first.GetType() == Token.NAME && first.GetString().Equals("undefined"))
								{
									child = last;
								}
								else
								{
									if (last.GetType() == Token.NAME && last.GetString().Equals("undefined"))
									{
										child = first;
									}
								}
							}
						}
						if (child.GetType() == Token.GETPROP)
						{
							child.SetType(Token.GETPROPNOWARN);
						}
						break;
					}

					case Token.SETNAME:
					{
						if (inStrictMode)
						{
							node.SetType(Token.STRICT_SETNAME);
						}
						goto case Token.NAME;
					}

					case Token.NAME:
					case Token.SETCONST:
					case Token.DELPROP:
					{
						// Turn name to var for faster access if possible
						if (createScopeObjects)
						{
							break;
						}
						Node nameSource;
						if (type == Token.NAME)
						{
							nameSource = node;
						}
						else
						{
							nameSource = node.GetFirstChild();
							if (nameSource.GetType() != Token.BINDNAME)
							{
								if (type == Token.DELPROP)
								{
									break;
								}
								throw Kit.CodeBug();
							}
						}
						if (nameSource.GetScope() != null)
						{
							break;
						}
						// already have a scope set
						string name = nameSource.GetString();
						Scope defining = scope.GetDefiningScope(name);
						if (defining != null)
						{
							nameSource.SetScope(defining);
							if (type == Token.NAME)
							{
								node.SetType(Token.GETVAR);
							}
							else
							{
								if (type == Token.SETNAME || type == Token.STRICT_SETNAME)
								{
									node.SetType(Token.SETVAR);
									nameSource.SetType(Token.STRING);
								}
								else
								{
									if (type == Token.SETCONST)
									{
										node.SetType(Token.SETCONSTVAR);
										nameSource.SetType(Token.STRING);
									}
									else
									{
										if (type == Token.DELPROP)
										{
											// Local variables are by definition permanent
											Node n = new Node(Token.FALSE);
											node = ReplaceCurrent(parent, previous, node, n);
										}
										else
										{
											throw Kit.CodeBug();
										}
									}
								}
							}
						}
						break;
					}
				}
				TransformCompilationUnit_r(tree, node, node is Scope ? (Scope)node : scope, createScopeObjects, inStrictMode);
siblingLoop_continue: ;
			}
siblingLoop_break: ;
		}
Esempio n. 16
0
		protected internal virtual Node VisitLet(bool createWith, Node parent, Node previous, Node scopeNode)
		{
			Node vars = scopeNode.GetFirstChild();
			Node body = vars.GetNext();
			scopeNode.RemoveChild(vars);
			scopeNode.RemoveChild(body);
			bool isExpression = scopeNode.GetType() == Token.LETEXPR;
			Node result;
			Node newVars;
			if (createWith)
			{
				result = new Node(isExpression ? Token.WITHEXPR : Token.BLOCK);
				result = ReplaceCurrent(parent, previous, scopeNode, result);
				List<object> list = new List<object>();
				Node objectLiteral = new Node(Token.OBJECTLIT);
				for (Node v = vars.GetFirstChild(); v != null; v = v.GetNext())
				{
					Node current = v;
					if (current.GetType() == Token.LETEXPR)
					{
						// destructuring in let expr, e.g. let ([x, y] = [3, 4]) {}
						IList<object> destructuringNames = (IList<object>)current.GetProp(Node.DESTRUCTURING_NAMES);
						Node c = current.GetFirstChild();
						if (c.GetType() != Token.LET)
						{
							throw Kit.CodeBug();
						}
						// Add initialization code to front of body
						if (isExpression)
						{
							body = new Node(Token.COMMA, c.GetNext(), body);
						}
						else
						{
							body = new Node(Token.BLOCK, new Node(Token.EXPR_VOID, c.GetNext()), body);
						}
						// Update "list" and "objectLiteral" for the variables
						// defined in the destructuring assignment
						if (destructuringNames != null)
						{
							Sharpen.Collections.AddAll(list, destructuringNames);
							for (int i = 0; i < destructuringNames.Count; i++)
							{
								objectLiteral.AddChildToBack(new Node(Token.VOID, Node.NewNumber(0.0)));
							}
						}
						current = c.GetFirstChild();
					}
					// should be a NAME, checked below
					if (current.GetType() != Token.NAME)
					{
						throw Kit.CodeBug();
					}
					list.Add(ScriptRuntime.GetIndexObject(current.GetString()));
					Node init = current.GetFirstChild();
					if (init == null)
					{
						init = new Node(Token.VOID, Node.NewNumber(0.0));
					}
					objectLiteral.AddChildToBack(init);
				}
				objectLiteral.PutProp(Node.OBJECT_IDS_PROP, Sharpen.Collections.ToArray(list));
				newVars = new Node(Token.ENTERWITH, objectLiteral);
				result.AddChildToBack(newVars);
				result.AddChildToBack(new Node(Token.WITH, body));
				result.AddChildToBack(new Node(Token.LEAVEWITH));
			}
			else
			{
				result = new Node(isExpression ? Token.COMMA : Token.BLOCK);
				result = ReplaceCurrent(parent, previous, scopeNode, result);
				newVars = new Node(Token.COMMA);
				for (Node v = vars.GetFirstChild(); v != null; v = v.GetNext())
				{
					Node current = v;
					if (current.GetType() == Token.LETEXPR)
					{
						// destructuring in let expr, e.g. let ([x, y] = [3, 4]) {}
						Node c = current.GetFirstChild();
						if (c.GetType() != Token.LET)
						{
							throw Kit.CodeBug();
						}
						// Add initialization code to front of body
						if (isExpression)
						{
							body = new Node(Token.COMMA, c.GetNext(), body);
						}
						else
						{
							body = new Node(Token.BLOCK, new Node(Token.EXPR_VOID, c.GetNext()), body);
						}
						// We're removing the LETEXPR, so move the symbols
						Scope.JoinScopes((Scope)current, (Scope)scopeNode);
						current = c.GetFirstChild();
					}
					// should be a NAME, checked below
					if (current.GetType() != Token.NAME)
					{
						throw Kit.CodeBug();
					}
					Node stringNode = Node.NewString(current.GetString());
					stringNode.SetScope((Scope)scopeNode);
					Node init = current.GetFirstChild();
					if (init == null)
					{
						init = new Node(Token.VOID, Node.NewNumber(0.0));
					}
					newVars.AddChildToBack(new Node(Token.SETVAR, stringNode, init));
				}
				if (isExpression)
				{
					result.AddChildToBack(newVars);
					scopeNode.SetType(Token.COMMA);
					result.AddChildToBack(scopeNode);
					scopeNode.AddChildToBack(body);
					if (body is Scope)
					{
						Scope scopeParent = ((Scope)body).GetParentScope();
						((Scope)body).SetParentScope((Scope)scopeNode);
						((Scope)scopeNode).SetParentScope(scopeParent);
					}
				}
				else
				{
					result.AddChildToBack(new Node(Token.EXPR_VOID, newVars));
					scopeNode.SetType(Token.BLOCK);
					result.AddChildToBack(scopeNode);
					scopeNode.AddChildrenToBack(body);
					if (body is Scope)
					{
						Scope scopeParent = ((Scope)body).GetParentScope();
						((Scope)body).SetParentScope((Scope)scopeNode);
						((Scope)scopeNode).SetParentScope(scopeParent);
					}
				}
			}
			return result;
		}