// TODO: replace this ugly-ass hack with proper AST support. public Expression DecompileNew() { PopByte(); var parameters = new List<Expression>(); for (int n = 0; n < 5; n++) { if (CurrentIs(StandardByteCodes.Nothing)) { parameters.Add(null); continue; } var param = DecompileExpression(); if (param == null) return null; // ERROR parameters.Add(param); } Expression first = null; if ((parameters[0] ?? parameters[1] ?? parameters[2]) != null) { var innerParms = new List<Expression>(); if (parameters[0] != null) innerParms.Add(parameters[0]); if (parameters[1] != null) innerParms.Add(parameters[1]); if (parameters[2] != null) innerParms.Add(parameters[2]); first = new FunctionCall(new SymbolReference(null, null, null, "new"), innerParms, null, null); } else { first = new SymbolReference(null, null, null, "new"); } var second = parameters[3] ?? new SymbolReference(null, null, null, "NoClass??"); var op = new InOpDeclaration("", 0, true, null, null, null, null, null, null, null); var firstHalf = new InOpReference(op, first, second, null, null); StartPositions.Pop(); if (parameters[4] != null) return new InOpReference(op, firstHalf, parameters[4], null, null); else return firstHalf; }
public Expression DecompileNativeFunction(UInt16 index) { var parameters = new List<Expression>(); while (!CurrentIs(StandardByteCodes.EndFunctionParms)) { var param = DecompileExpression(); if (param == null) return null; // ERROR parameters.Add(param); } PopByte(); var entry = NativeTable[index]; Expression call = null; switch (entry.Type) { case NativeType.Function: var func = new SymbolReference(null, null, null, entry.Name); call = new FunctionCall(func, parameters, null, null); break; case NativeType.Operator: // TODO: table should hold precedence, currently all have 0 and it'll be a mess. var op = new InOpDeclaration(entry.Name, entry.Precedence, false, null, null, null, null, null, null, null); call = new InOpReference(op, parameters[0], parameters[1], null, null); break; case NativeType.PreOperator: // TODO: table should hold precedence, currently all have 0 and it'll be a mess. var preOp = new PreOpDeclaration(entry.Name, false, null, null, null, null, null, null); call = new PreOpReference(preOp, parameters[0], null, null); break; case NativeType.PostOperator: // TODO: table should hold precedence, currently all have 0 and it'll be a mess. var postOp = new PostOpDeclaration(entry.Name, false, null, null, null, null, null, null); call = new PostOpReference(postOp, parameters[0], null, null); break; } StartPositions.Pop(); return call; }
public bool VisitNode(FunctionCall node) { throw new NotImplementedException(); }
public bool VisitNode(FunctionCall node) { ExpressionPrescedence.Push(NOPRESCEDENCE); // functionName( parameter1, parameter2.. ) Append("{0}(", node.Function.Name); foreach(Expression expr in node.Parameters) { expr.AcceptVisitor(this); if (node.Parameters.IndexOf(expr) != node.Parameters.Count - 1) Append(", "); } Append(")"); ExpressionPrescedence.Pop(); return true; }
public Statement DecompileStatement() { StartPositions.Push((UInt16)Position); var token = CurrentByte; switch (token) { // return [expression]; case (byte)StandardByteCodes.Return: return DecompileReturn(); // switch (expression) case (byte)StandardByteCodes.Switch: return DecompileSwitch(); // case expression : case (byte)StandardByteCodes.Case: return DecompileCase(); // if (expression) // while / for / do until case (byte)StandardByteCodes.JumpIfNot: return DecompileConditionalJump(); // continue case (byte)StandardByteCodes.Jump: // TODO: UDK seems to compile this from break when inside ForEach, handle? return DecompileJump(); // continue (iterator) case (byte)StandardByteCodes.IteratorNext: PopByte(); // pop iteratornext token return DecompileJump(); // break; case (byte)StandardByteCodes.IteratorPop: return DecompileIteratorPop(); // stop; case (byte)StandardByteCodes.Stop: PopByte(); var stopStatement = new StopStatement(null, null); StatementLocations.Add(StartPositions.Pop(), stopStatement); return stopStatement; // Goto label case (byte)StandardByteCodes.GotoLabel: PopByte(); var labelExpr = DecompileExpression(); var func = new SymbolReference(null, null, null, "goto"); var call = new FunctionCall(func, new List<Expression>() { labelExpr }, null, null); var gotoLabel = new ExpressionOnlyStatement(null, null, call); StatementLocations.Add(StartPositions.Pop(), gotoLabel); return gotoLabel; // assignable expression = expression; case (byte)StandardByteCodes.Let: case (byte)StandardByteCodes.LetBool: case (byte)StandardByteCodes.LetDelegate: return DecompileAssign(); // [skip x bytes] case (byte)StandardByteCodes.Skip: // TODO: this should never occur as statement, possibly remove? PopByte(); ReadUInt16(); StartPositions.Pop(); return DecompileStatement(); case (byte)StandardByteCodes.Nothing: PopByte(); StartPositions.Pop(); return DecompileStatement(); // TODO, should probably have a nothing expression or statement, this is ugly // foreach IteratorFunction(...) case (byte)StandardByteCodes.Iterator: return DecompileForEach(); // foreach arrayName(valuevariable[, indexvariable]) case (byte)StandardByteCodes.DynArrayIterator: return DecompileForEach(isDynArray: true); case (byte)StandardByteCodes.LabelTable: DecompileLabelTable(); StartPositions.Pop(); return DecompileStatement(); #region unsupported case (byte)StandardByteCodes.OptIfLocal: // TODO: verify, handle syntax return DecompileConditionalJump(isOpt: true); case (byte)StandardByteCodes.OptIfInstance: // TODO: verify, handle syntax return DecompileConditionalJump(isOpt: true); #endregion default: var expr = DecompileExpression(); if (expr != null) { var statement = new ExpressionOnlyStatement(null, null, expr); StatementLocations.Add(StartPositions.Pop(), statement); return statement; } // ERROR! break; } return null; }
// TODO: guess for loop, probably requires a large restructure public Statement DecompileForEach(bool isDynArray = false) { PopByte(); var scopeStatements = new List<Statement>(); var iteratorFunc = DecompileExpression(); if (iteratorFunc == null) return null; Expression dynArrVar = null; Expression dynArrIndex = null; bool unknByte = false; if (isDynArray) { dynArrVar = DecompileExpression(); unknByte = Convert.ToBoolean(ReadByte()); dynArrIndex = DecompileExpression(); } var scopeEnd = ReadUInt16(); // MemOff ForEachScopes.Push(scopeEnd); Scopes.Add(scopeStatements); CurrentScope.Push(Scopes.Count - 1); while (Position < Size) { if (CurrentIs(StandardByteCodes.IteratorNext) && PeekByte == (byte)StandardByteCodes.IteratorPop) { PopByte(); // IteratorNext PopByte(); // IteratorPop break; } var current = DecompileStatement(); if (current == null) return null; // ERROR ? scopeStatements.Add(current); } CurrentScope.Pop(); ForEachScopes.Pop(); if (isDynArray) { var builder = new CodeBuilderVisitor(); // what a wonderful hack, TODO. iteratorFunc.AcceptVisitor(builder); var arrayName = new SymbolReference(null, null, null, builder.GetCodeString()); var parameters = new List<Expression>() { dynArrVar, dynArrIndex }; iteratorFunc = new FunctionCall(arrayName, parameters, null, null); } var statement = new ForEachLoop(iteratorFunc, new CodeBody(scopeStatements, null, null), null, null); StatementLocations.Add(StartPositions.Pop(), statement); return statement; }