protected CompositeStatement(int startOffset, BytecodeToken token, StatementList children, int endOffset)
     : base(startOffset, token)
 {
     _children        = children;
     _children.Parent = this;
     EndOffset        = endOffset;
 }
        /// <summary>
        /// ME3Explorer intercepting function to build the token list. As tokens are read the tokens list will be updated.
        /// This method is used to prevent significant modifications to ReadNextInternal() (originally ReadNext)
        /// </summary>
        /// <returns></returns>
        public BytecodeToken ReadNext(bool dontAddToken = false)
        {
            ME1OpCodes b = (ME1OpCodes)_reader.ReadByte();

            _reader.BaseStream.Position--;

            if (OpCodesThatReturnNextToken.Contains(b))
            {
                BytecodeToken t = new BytecodeToken("", (int)_reader.BaseStream.Position);

                t.OpCode = b;
                ReadTokens.Add(t);
            }

            //if (b == ME1OpCodes.EX_Skip)
            //{
            //    Debugger.Break();
            //}

            //Debug.WriteLine("Read bytecode " + ((byte)b).ToString("X2") + " " + b + " at " + _reader.BaseStream.Position.ToString("X8"));
            BytecodeToken bct = ReadNextInternal();

            //Debug.WriteLine("Bytecode finished: " + ((byte)b).ToString("X2") + " " + b + " from " + _reader.BaseStream.Position.ToString("X8"));

            if (!OpCodesThatReturnNextToken.Contains(b))
            {
                bct.OpCode = b;
                ReadTokens.Add(bct);
            }
            return(bct);
        }
 public Statement(int startOffset, int endOffset, BytecodeToken token, BytecodeReader Reader)
 {
     StartOffset = startOffset;
     EndOffset   = endOffset;
     Token       = token;
     this.Reader = Reader;
 }
        private BytecodeToken WrapNextBytecode(Func <BytecodeToken, BytecodeToken> func)
        {
            BytecodeToken operand = ReadNext();

            if (IsInvalid(operand))
            {
                return(operand);
            }
            return(func(operand));
        }
        internal BytecodeToken WrapErrToken(string text, BytecodeToken token)
        {
            int pos = (int)_reader.BaseStream.Position;
            var errorBytecodeToken = token as ErrorBytecodeToken;

            if (errorBytecodeToken != null)
            {
                return(new ErrorBytecodeToken(text, errorBytecodeToken.UnknownBytecode,
                                              errorBytecodeToken.SubsequentBytes, pos));
            }
            return(ErrToken(text));
        }
 public SwitchToken(string text, BytecodeToken expr, int offset) : base("switch (" + text + ")", offset)
 {
     Expr = expr;
 }
 public ReturnToken(BytecodeToken returnValue, int offset)
     : base(returnValue.ToString().Length > 0 ? "return " + returnValue : "return", offset)
 {
     _returnValue = returnValue;
 }
        private BytecodeToken ReadNextInternal()
        {
            int        readerpos = (int)_reader.BaseStream.Position;
            ME1OpCodes b         = (ME1OpCodes)_reader.ReadByte();

            switch (b)
            {
            case ME1OpCodes.EX_LocalVariable:
            case ME1OpCodes.EX_InstanceVariable:
            case ME1OpCodes.EX_NativeParm:
                return(ReadRef(r => r.ObjectName.Instanced));

            case ME1OpCodes.EX_DefaultVariable:
                return(ReadRef(r => $"Default.{r.ObjectName.Instanced}"));

            case ME1OpCodes.EX_Return:
            {
                BytecodeToken returnValue = ReadNext();
                return(new ReturnToken(returnValue, readerpos));
            }

            case ME1OpCodes.EX_Assert:
            {
                _reader.ReadInt16();
                _reader.ReadByte();
                return(WrapNextBytecode(c => new BytecodeToken($"assert({c})", readerpos)));
            }

            case ME1OpCodes.EX_Switch:
            {
                byte          b1         = _reader.ReadByte();
                BytecodeToken switchExpr = ReadNext();
                return(new SwitchToken(switchExpr.ToString(), switchExpr, readerpos));
            }

            case ME1OpCodes.EX_Case:
            {
                short offset = _reader.ReadInt16();
                if (offset == -1)
                {
                    return(new DefaultToken(readerpos));
                }
                BytecodeToken caseExpr = ReadNext();
                return(new CaseToken(caseExpr.ToString(), readerpos));
            }

            case ME1OpCodes.EX_Jump:
            {
                int offset = _reader.ReadInt16();
                return(new UncondJumpToken(offset, readerpos));
            }

            case ME1OpCodes.EX_JumpIfNot:
            {
                short         offset    = _reader.ReadInt16();
                BytecodeToken condition = ReadNext();
                if (IsInvalid(condition))
                {
                    return(WrapErrToken("if (!" + condition, condition));
                }
                return(new JumpIfNotToken(offset, condition, readerpos));
            }

            case ME1OpCodes.EX_LabelTable:
            {
                var token = new LabelTableToken(readerpos);
                while (true)
                {
                    string labelName = ReadName();
                    if (labelName == "None")
                    {
                        break;
                    }
                    int offset = _reader.ReadInt32();
                    token.AddLabel(labelName, offset);
                }
                return(token);
            }

            case ME1OpCodes.EX_GotoLabel:
                return(WrapNextBytecode(op => Token("goto " + op, readerpos)));

            case ME1OpCodes.EX_Self:
                return(Token("self", readerpos));

            case ME1OpCodes.EX_Skip:
                _reader.ReadInt16();
                //Returning readnext causes a new token to be read
                return(ReadNext());

            case ME1OpCodes.EX_EatReturnValue:
                _reader.ReadInt32();
                return(ReadNext());

            case ME1OpCodes.EX_Nothing:
                return(new NothingToken(readerpos));

            case ME1OpCodes.EX_Stop:
                _reader.ReadInt16();
                return(new NothingToken(readerpos));

            case ME1OpCodes.EX_IntZero:
                return(Token("0", readerpos));

            case ME1OpCodes.EX_IntOne:
                return(Token("1", readerpos));

            case ME1OpCodes.EX_True:
                return(Token("true", readerpos));

            case ME1OpCodes.EX_False:
                return(Token("false", readerpos));

            case ME1OpCodes.EX_NoObject:
            case ME1OpCodes.EX_EmptyDelegate:
                return(Token("None", readerpos));

            case ME1OpCodes.EX_Let:
            case ME1OpCodes.EX_LetBool:
            case ME1OpCodes.EX_LetDelegate:
                BytecodeToken lhs = ReadNext();
                if (IsInvalid(lhs))
                {
                    return(lhs);
                }
                BytecodeToken rhs = ReadNext();
                if (IsInvalid(rhs))
                {
                    return(WrapErrToken(lhs + " = " + rhs, rhs));
                }
                return(Token(lhs + " = " + rhs, readerpos));

            case ME1OpCodes.EX_IntConst:
                return(Token(_reader.ReadInt32().ToString(), readerpos));

            case ME1OpCodes.EX_FloatConst:
                return(Token(_reader.ReadSingle().ToString(), readerpos));

            case ME1OpCodes.EX_StringConst:
            {
                var s = ReadAsciiz().Replace("\n", "\\n").Replace("\t", "\\t");
                return(Token($"\"{s}\"", readerpos));
            }

            case ME1OpCodes.EX_ByteConst:
            case ME1OpCodes.EX_IntConstByte:
                return(Token(_reader.ReadByte().ToString(), readerpos));

            case ME1OpCodes.EX_ObjectConst:
            {
                int objectIndex = _reader.ReadInt32();
                var item        = _package.GetEntry(objectIndex);
                if (item == null)
                {
                    return(ErrToken("Unresolved class item " + objectIndex));
                }
                return(Token($"{item.ClassName}'{item.ObjectName.Instanced}'", readerpos));
            }

            case ME1OpCodes.EX_NameConst:
                return(Token($"'{ReadName()}'", readerpos));

            case ME1OpCodes.EX_EndFunctionParms:
                return(new EndParmsToken(")", readerpos));

            case ME1OpCodes.EX_ClassContext:
            case ME1OpCodes.EX_Context:
            {
                var context = ReadNext();
                if (IsInvalid(context))
                {
                    return(context);
                }
                int exprSize = _reader.ReadInt16();
                int bSize    = _reader.ReadByte();
                var value    = ReadNext();
                if (IsInvalid(value))
                {
                    return(WrapErrToken($"{context}.{value}", value));
                }
                return(Token($"{context}.{value}", readerpos));
            }

            case ME1OpCodes.EX_InterfaceContext:
                return(ReadNext());

            case ME1OpCodes.EX_FinalFunction:
            {
                int functionIndex = _reader.ReadInt32();
                var item          = _package.GetEntry(functionIndex);
                if (item == null)
                {
                    return(ErrToken("Unresolved function item " + item));
                }
                string functionName = item.ObjectName.Instanced;
                return(ReadCall(functionName));
            }

            case ME1OpCodes.EX_PrimitiveCast:
            {
                var prefix = _reader.ReadByte();
                var v      = ReadNext();
                return(v);
            }

            case ME1OpCodes.EX_VirtualFunction:
                return(ReadCall(ReadName()));

            case ME1OpCodes.EX_GlobalFunction:
                return(ReadCall("Global." + ReadName()));

            case ME1OpCodes.EX_BoolVariable:
                return(ReadNext());

            case ME1OpCodes.EX_ByteToInt:
                int objectRefIdx = _reader.ReadInt32();
                if (_package.IsEntry(objectRefIdx))
                {
                    return(Token($"ByteToInt({_package.getObjectName(objectRefIdx)})", readerpos));
                }
                else
                {
                    return(Token($"ByteToInt(Unknown reference {objectRefIdx})", readerpos));
                }

            case ME1OpCodes.EX_DynamicCast:
            {
                int typeIndex = _reader.ReadInt32();
                var item      = _package.GetEntry(typeIndex);
                return(WrapNextBytecode(op => Token($"{item.ObjectName.Instanced}({op})", readerpos)));
            }

            case ME1OpCodes.EX_Metacast:
            {
                int typeIndex = _reader.ReadInt32();
                var item      = _package.GetEntry(typeIndex);
                if (item == null)
                {
                    return(ErrToken("Unresolved class item " + typeIndex));
                }
                return(WrapNextBytecode(op => Token($"Class<{item.ObjectName.Instanced}>({op})", readerpos)));
            }

            case ME1OpCodes.EX_StructMember:
            {
                var field      = ReadRef();
                var structType = ReadRef();
                int wSkip      = _reader.ReadInt16();
                var token      = ReadNext();
                if (IsInvalid(token))
                {
                    return(token);
                }
                return(Token($"{token}.{field.ObjectName.Instanced}", readerpos));
            }

            case ME1OpCodes.EX_ArrayElement:
            case ME1OpCodes.EX_DynArrayElement:
            {
                var index = ReadNext();
                if (IsInvalid(index))
                {
                    return(index);
                }
                var array = ReadNext();
                if (IsInvalid(array))
                {
                    return(array);
                }
                return(Token($"{array}[{index}]", readerpos));
            }

            case ME1OpCodes.EX_DynArrayLength:
                return(WrapNextBytecode(op => Token($"{op}.Length", readerpos)));

            case ME1OpCodes.EX_StructCmpEq:
                return(CompareStructs("=="));

            case ME1OpCodes.EX_StructCmpNe:
                return(CompareStructs("!="));

            case ME1OpCodes.EX_EndOfScript:
                return(new EndOfScriptToken(readerpos));

            case ME1OpCodes.EX_EmptyParmValue:
            case ME1OpCodes.EX_GoW_DefaultValue:
                return(new DefaultValueToken("", readerpos));

            case ME1OpCodes.EX_DefaultParmValue:
            {
                var size             = _reader.ReadInt16();
                var offset           = _reader.BaseStream.Position;
                var defaultValueExpr = ReadNext();
                _reader.BaseStream.Position = offset + size;
                return(new DefaultParamValueToken(defaultValueExpr.ToString(), readerpos));
            }

            case ME1OpCodes.EX_LocalOutVariable:
                int valueIndex  = _reader.ReadInt32();
                var packageItem = _package.GetEntry(valueIndex);
                if (packageItem == null)
                {
                    return(ErrToken("Unresolved package item " + packageItem));
                }
                return(Token(packageItem.ObjectName.Instanced, readerpos));

            case ME1OpCodes.EX_Iterator:
                var expr    = ReadNext();
                int loopEnd = _reader.ReadInt16();
                if (IsInvalid(expr))
                {
                    return(WrapErrToken("foreach " + expr, expr));
                }
                return(new ForeachToken(loopEnd, expr, readerpos));

            case ME1OpCodes.EX_IteratorPop:
                return(new IteratorPopToken(readerpos));

            case ME1OpCodes.EX_IteratorNext:
                return(new IteratorNextToken(readerpos));

            case ME1OpCodes.EX_New:
                var outer = ReadNext();
                if (IsInvalid(outer))
                {
                    return(outer);
                }
                var name = ReadNext();
                if (IsInvalid(name))
                {
                    return(name);
                }
                var flags = ReadNext();
                if (IsInvalid(flags))
                {
                    return(flags);
                }
                var cls = ReadNext();
                if (IsInvalid(cls))
                {
                    return(cls);
                }
                return(Token($"new({JoinTokens(outer, name, flags, cls)})", readerpos));

            case ME1OpCodes.EX_VectorConst:
                var f1 = _reader.ReadSingle();
                var f2 = _reader.ReadSingle();
                var f3 = _reader.ReadSingle();
                return(Token($"vect({f1},{f2},{f3})", readerpos));

            case ME1OpCodes.EX_RotationConst:
                var i1 = _reader.ReadInt32();
                var i2 = _reader.ReadInt32();
                var i3 = _reader.ReadInt32();
                return(Token($"rot({i1},{i2},{i3})", readerpos));

            case ME1OpCodes.EX_InterfaceCast:
            {
                var interfaceName = ReadRef();
                return(WrapNextBytecode(op => Token($"{interfaceName.ObjectName.Instanced}({op})", readerpos)));
            }

            case ME1OpCodes.EX_Conditional:
            {
                var condition = ReadNext();
                if (IsInvalid(condition))
                {
                    return(condition);
                }
                var trueSize = _reader.ReadInt16();
                var pos      = _reader.BaseStream.Position;
                var truePart = ReadNext();
                if (IsInvalid(truePart))
                {
                    return(WrapErrToken($"{condition} ? {truePart}", truePart));
                }
                if (_reader.BaseStream.Position != pos + trueSize)
                {
                    return(ErrToken("conditional true part size mismatch"));
                }
                var falseSize = _reader.ReadInt16();
                pos = _reader.BaseStream.Position;
                var falsePart = ReadNext();
                if (IsInvalid(truePart))
                {
                    return(WrapErrToken($"{condition} ? {truePart} : {falsePart}", falsePart));
                }
                Debug.Assert(_reader.BaseStream.Position == pos + falseSize);
                return(Token($"{condition} ? {truePart} : {falsePart}", readerpos));
            }

            case ME1OpCodes.EX_DynArrayFind:
                return(ReadDynArray1ArgMethod("Find"));

            case ME1OpCodes.EX_DynArrayFindStruct:
                return(ReadDynArray2ArgMethod("Find", true));

            case ME1OpCodes.EX_DynArrayRemove:
                return(ReadDynArray2ArgMethod("Remove", false));

            case ME1OpCodes.EX_DynArrayInsert:
                return(ReadDynArray2ArgMethod("Insert", false));

            case ME1OpCodes.EX_DynArrayAddItem:
                return(ReadDynArray1ArgMethod("AddItem"));

            case ME1OpCodes.EX_DynArrayRemoveItem:
                return(ReadDynArray1ArgMethod("RemoveItem"));

            case ME1OpCodes.EX_DynArrayInsertItem:
                return(ReadDynArray2ArgMethod("InsertItem", true));

            case ME1OpCodes.EX_DynArrayIterator:
            {
                var array = ReadNext();
                if (IsInvalid(array))
                {
                    return(array);
                }
                var iteratorVar = ReadNext();
                if (IsInvalid(iteratorVar))
                {
                    return(iteratorVar);
                }
                _reader.ReadInt16();
                var endOffset = _reader.ReadInt16();
                return(new ForeachToken(endOffset, array, iteratorVar, readerpos));
            }

            case ME1OpCodes.EX_DelegateProperty:
            case ME1OpCodes.EX_InstanceDelegate:
                return(Token(ReadName(), readerpos));

            case ME1OpCodes.EX_DelegateFunction:
            {
                var receiver = ReadNext();
                if (IsInvalid(receiver))
                {
                    return(receiver);
                }
                var methodName = ReadName();
                if (receiver.ToString().StartsWith("__") && receiver.ToString().EndsWith("__Delegate"))
                {
                    return(ReadCall(methodName));
                }
                return(ReadCall(receiver + "." + methodName));
            }

            case ME1OpCodes.EX_EqualEqual_DelDel:
            case ME1OpCodes.EX_EqualEqual_DelFunc:
                return(CompareDelegates("=="));

            case ME1OpCodes.EX_NotEqual_DelDel:
                return(CompareDelegates("!="));

            default:
                if ((int)b >= 0x60)
                {
                    return(ReadNativeCall((byte)b));
                }
                return(ErrToken("// unknown bytecode " + ((byte)b).ToString("X2"), (int)b));
            }
        }
 internal ForeachToken(int targetOffset, BytecodeToken expr, BytecodeToken iteratorExpr, int offset)
     : base("foreach (" + expr + ") end " + targetOffset, targetOffset, offset)
 {
     Expr         = expr;
     IteratorExpr = iteratorExpr;
 }
 internal ForeachToken(int targetOffset, BytecodeToken expr, int offset) : this(targetOffset, expr, null, offset)
 {
 }
 public JumpIfNotToken(int targetOffset, BytecodeToken condition, int offset)
     : base("if (!" + condition + ") jump to 0x" + targetOffset.ToString("X"), targetOffset, offset)
 {
     _condition = condition;
 }
 private static bool IsInvalid(BytecodeToken token)
 {
     return(token == null || token is ErrorBytecodeToken);
 }
 public BreakContinueStatement(int startOffset, BytecodeToken token, string text)
     : base(startOffset, token)
 {
     _text = text;
 }
 public SwitchStatement(int startOffset, BytecodeToken token, StatementList children, int endOffset)
     : base(startOffset, token, children, endOffset)
 {
 }
 public Statement(int startOffset, BytecodeToken token)
 {
     StartOffset = startOffset;
     EndOffset   = -1;
     Token       = token;
 }
 public JumpIfNotToken(int targetOffset, BytecodeToken condition, int offset)
     : base("if (!" + condition + ") jump " + targetOffset, targetOffset, offset)
 {
     _condition = condition;
 }