Exemple #1
0
        protected override void PrintChildren(TextBuilder result, LabelTableToken labelTable, bool showStartOffsets)
        {
            result.PushIndent();
            bool indented = false;

            for (int i = 0; i < Children.Count; i++)
            {
                var stmt = Children[i];
                if (stmt.Token is CaseToken || stmt.Token is DefaultToken)
                {
                    if (indented)
                    {
                        result.PopIndent();
                        indented = false;
                    }
                    result.Indent().Append(stmt.Token.ToString()).Append(":").NewLine();
                }
                else
                {
                    if (!indented)
                    {
                        indented = true;
                        result.PushIndent();
                    }
                    stmt.Print(result, labelTable, showStartOffsets);
                }
            }
            if (indented)
            {
                result.PopIndent();
            }
            result.PopIndent();
        }
Exemple #2
0
 protected void PrintLabel(LabelTableToken labelTable, TextBuilder result)
 {
     if (labelTable != null)
     {
         var label = labelTable.GetLabel(StartOffset);
         if (label != null)
         {
             result.Append(label).Append(":").NewLine();
         }
     }
 }
Exemple #3
0
 public override void Print(TextBuilder result, LabelTableToken labelTable, bool showStartOffsets)
 {
     PrintLabel(labelTable, result);
     result.Indent();
     PrintHead(result);
     result.Append("\n");
     result.Indent().Append("{\n");
     PrintChildren(result, labelTable, showStartOffsets);
     result.Indent().Append("}");
     //            result.Append("   // ").Append(_endOffset.ToString());
     result.NewLine();
 }
Exemple #4
0
 public virtual void Print(TextBuilder result, LabelTableToken labelTable, bool showStartOffset)
 {
     if (Token.ToString() == "")
     {
         return;
     }
     PrintLabel(labelTable, result);
     result.Indent();
     if (showStartOffset)
     {
         result.Append("/* ").Append(StartOffset).Append(" */ ");
     }
     result.Append(Token.ToString(), StartOffset, EndOffset).Append(";");
     result.Append("\n");
 }
 protected void PrintLabel(LabelTableToken labelTable, TextBuilder result)
 {
     if (labelTable != null)
     {
         var label = labelTable.GetLabel(StartOffset);
         if (label != null)
         {
             result.Append(label).Append(":").NewLine();
         }
     }
 }
 public virtual void Print(TextBuilder result, LabelTableToken labelTable, bool showStartOffset)
 {
     if (Token.ToString() == "") return;
     PrintLabel(labelTable, result);
     result.Indent();
     if (showStartOffset)
     {
         result.Append("/* ").Append(StartOffset).Append(" */ ");
     }
     result.Append(Token.ToString(), StartOffset, EndOffset).Append(";");
     result.Append("\n");
 }
 protected override void PrintChildren(TextBuilder result, LabelTableToken labelTable, bool showStartOffsets)
 {
     result.PushIndent();
     bool indented = false;
     for (int i = 0; i < Children.Count; i++)
     {
         var stmt = Children[i];
         if (stmt.Token is CaseToken || stmt.Token is DefaultToken)
         {
             if (indented)
             {
                 result.PopIndent();
                 indented = false;
             }
             result.Indent().Append(stmt.Token.ToString()).Append(":").NewLine();
         }
         else
         {
             if (!indented)
             {
                 indented = true;
                 result.PushIndent();
             }
             stmt.Print(result, labelTable, showStartOffsets);
         }
     }
     if (indented) result.PopIndent();
     result.PopIndent();
 }
 protected virtual void PrintChildren(TextBuilder result, LabelTableToken labelTable, bool showStartOffsets)
 {
     _children.Print(result, labelTable, showStartOffsets);
 }
 public override void Print(TextBuilder result, LabelTableToken labelTable, bool showStartOffsets)
 {
     PrintLabel(labelTable, result);
     result.Indent();
     PrintHead(result);
     result.Append("\n");
     result.Indent().Append("{\n");
     PrintChildren(result, labelTable, showStartOffsets);
     result.Indent().Append("}");
     //            result.Append("   // ").Append(_endOffset.ToString());
     result.NewLine();
 }
Exemple #10
0
 public override void Print(TextBuilder result, LabelTableToken labelTable, bool offset)
 {
     result.Indent().Append(_text).Append(";").NewLine();
 }
Exemple #11
0
 public void Print(TextBuilder result, LabelTableToken labelTable, bool showStartOffset)
 {
     result.PushIndent();
     _statements.ForEach(s => s.Print(result, labelTable, showStartOffset));
     result.PopIndent();
 }
Exemple #12
0
 public override void Print(TextBuilder result, LabelTableToken labelTable, bool offset)
 {
     result.Indent().Append(_text).Append(";").NewLine();
 }
Exemple #13
0
 public void Print(TextBuilder result, LabelTableToken labelTable, bool showStartOffset)
 {
     result.PushIndent();
     _statements.ForEach(s => s.Print(result, labelTable, showStartOffset));
     result.PopIndent();
 }
Exemple #14
0
 protected virtual void PrintChildren(TextBuilder result, LabelTableToken labelTable, bool showStartOffsets)
 {
     _children.Print(result, labelTable, showStartOffsets);
 }
Exemple #15
0
        internal BytecodeToken ReadNext()
        {
            byte b = _reader.ReadByte();

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

            case EX_DefaultVariable:
                return(ReadRef(r => "Default." + r.ObjectName));

            case EX_Return:
                BytecodeToken returnValue = ReadNext();
                return(new ReturnToken(returnValue));

            case EX_Assert:
                _reader.ReadInt16();
                _reader.ReadByte();
                return(WrapNextBytecode(c => new BytecodeToken("assert(" + c + ")")));

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


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

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

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

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

            case EX_GotoLabel:
                return(WrapNextBytecode(op => Token("goto " + op)));

            case EX_Self:
                return(Token("self"));

            case EX_Skip:
                _reader.ReadInt16();
                return(ReadNext());

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

            case EX_Nothing:
                return(new NothingToken());

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

            case EX_IntZero:
                return(Token("0"));

            case EX_IntOne:
                return(Token("1"));

            case EX_True:
                return(Token("true"));

            case EX_False:
                return(Token("false"));

            case EX_NoObject:
            case EX_EmptyDelegate:
                return(Token("None"));

            case EX_Let:
            case EX_LetBool:
            case 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));

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

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

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

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

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

            case EX_NameConst:
                return(Token("'" + _package.Names[(int)_reader.ReadInt64()].Name + "'"));

            case EX_EndFunctionParms:
                return(new EndParmsToken(")"));

            case EX_ClassContext:
            case 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));
            }

            case EX_InterfaceContext:
                return(ReadNext());

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

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

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

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

            case EX_BoolVariable:
            case EX_ByteToInt:
                return(ReadNext());

            case EX_DynamicCast:
            {
                int typeIndex = _reader.ReadInt32();
                var item      = _package.ResolveClassItem(typeIndex);
                return(WrapNextBytecode(op => Token(item.ObjectName + "(" + op + ")")));
            }

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

            case 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));
            }

            case EX_ArrayElement:
            case EX_DynArrayElement:
            {
                var index = ReadNext();
                if (IsInvalid(index))
                {
                    return(index);
                }
                var array = ReadNext();
                if (IsInvalid(array))
                {
                    return(array);
                }
                return(Token(array + "[" + index + "]"));
            }

            case EX_DynArrayLength:
                return(WrapNextBytecode(op => Token(op + ".Length")));

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

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

            case EX_EndOfScript:
                return(new EndOfScriptToken());

            case EX_EmptyParmValue:
            case EX_GoW_DefaultValue:
                return(new DefaultValueToken(""));

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

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

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

            case EX_IteratorPop:
                return(new IteratorPopToken());

            case EX_IteratorNext:
                return(new IteratorNextToken());

            case 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) + ")"));

            case EX_VectorConst:
                var f1 = _reader.ReadSingle();
                var f2 = _reader.ReadSingle();
                var f3 = _reader.ReadSingle();
                return(Token("vect(" + f1 + "," + f2 + "," + f3 + ")"));

            case EX_RotationConst:
                var i1 = _reader.ReadInt32();
                var i2 = _reader.ReadInt32();
                var i3 = _reader.ReadInt32();
                return(Token("rot(" + i1 + "," + i2 + "," + i3 + ")"));

            case EX_InterfaceCast:
            {
                var interfaceName = ReadRef();
                return(WrapNextBytecode(op => Token(interfaceName.ObjectName + "(" + op + ")")));
            }

            case 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));
            }

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

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

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

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

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

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

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

            case 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));
            }

            case EX_DelegateProperty:
            case EX_InstanceDelegate:
                return(Token(ReadName()));

            case 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 EX_EqualEqual_DelDel:
            case EX_EqualEqual_DelFunc:
                return(CompareDelegates("=="));

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

            default:
                if (b >= 0x60)
                {
                    return(ReadNativeCall(b));
                }
                return(ErrToken("// unknown bytecode " + b.ToString("X2"), b));
            }
        }
        internal BytecodeToken ReadNext()
        {
            byte b = _reader.ReadByte();
            switch(b)
            {
                case EX_LocalVariable:
                case EX_InstanceVariable:
                case EX_NativeParm:
                    return ReadRef(r => r.ObjectName);

                case EX_DefaultVariable:
                    return ReadRef(r => "Default." + r.ObjectName);

                case EX_Return:
                    BytecodeToken returnValue = ReadNext();
                    return new ReturnToken(returnValue);

                case EX_Assert:
                    _reader.ReadInt16();
                    _reader.ReadByte();
                    return WrapNextBytecode(c => new BytecodeToken("assert(" + c + ")"));

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

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

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

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

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

                case EX_GotoLabel:
                    return WrapNextBytecode(op => Token("goto " + op));

                case EX_Self:
                    return Token("self");

                case EX_Skip:
                    _reader.ReadInt16();
                    return ReadNext();

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

                case EX_Nothing:
                    return new NothingToken();

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

                case EX_IntZero:
                    return Token("0");

                case EX_IntOne:
                    return Token("1");

                case EX_True:
                    return Token("true");

                case EX_False:
                    return Token("false");

                case EX_NoObject:
                case EX_EmptyDelegate:
                    return Token("None");

                case EX_Let:
                case EX_LetBool:
                case 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);

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

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

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

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

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

                case EX_NameConst:
                    return Token("'" + _package.Names[(int) _reader.ReadInt64()].Name + "'");

                case EX_EndFunctionParms:
                    return new EndParmsToken(")");

                case EX_ClassContext:
                case 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);
                    }

                case EX_InterfaceContext:
                    return ReadNext();

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

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

                case EX_VirtualFunction:
                    return ReadCall(ReadName());

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

                case EX_BoolVariable:
                case EX_ByteToInt:
                    return ReadNext();

                case EX_DynamicCast:
                    {
                        int typeIndex = _reader.ReadInt32();
                        var item = _package.ResolveClassItem(typeIndex);
                        return WrapNextBytecode(op => Token(item.ObjectName + "(" + op + ")"));
                    }

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

                case 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);
                    }

                case EX_ArrayElement:
                case EX_DynArrayElement:
                    {
                        var index = ReadNext();
                        if (IsInvalid(index)) return index;
                        var array = ReadNext();
                        if (IsInvalid(array)) return array;
                        return Token(array + "[" + index + "]");
                    }

                case EX_DynArrayLength:
                    return WrapNextBytecode(op => Token(op + ".Length"));

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

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

                case EX_EndOfScript:
                    return new EndOfScriptToken();

                case EX_EmptyParmValue:
                case EX_GoW_DefaultValue:
                    return new DefaultValueToken("");

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

                case EX_LocalOutVariable:
                    int valueIndex = _reader.ReadInt32();
                    var packageItem = _package.ResolveClassItem(valueIndex);
                    if (packageItem == null) return ErrToken("Unresolved package item " + packageItem);
                    return Token(packageItem.ObjectName);

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

                case EX_IteratorPop:
                    return new IteratorPopToken();

                case EX_IteratorNext:
                    return new IteratorNextToken();

                case 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) + ")");

                case EX_VectorConst:
                    var f1 = _reader.ReadSingle();
                    var f2 = _reader.ReadSingle();
                    var f3 = _reader.ReadSingle();
                    return Token("vect(" + f1 + "," + f2 + "," + f3 + ")");

                case EX_RotationConst:
                    var i1 = _reader.ReadInt32();
                    var i2 = _reader.ReadInt32();
                    var i3 = _reader.ReadInt32();
                    return Token("rot(" + i1 + "," + i2 + "," + i3 + ")");

                case EX_InterfaceCast:
                    {
                        var interfaceName = ReadRef();
                        return WrapNextBytecode(op => Token(interfaceName.ObjectName + "(" + op + ")"));
                    }

                case 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);
                    }

                case EX_DynArrayFind:
                    return ReadDynArray1ArgMethod("Find");

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

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

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

                case EX_DynArrayAddItem:
                    return ReadDynArray1ArgMethod("AddItem");

                case EX_DynArrayRemoveItem:
                    return ReadDynArray1ArgMethod("RemoveItem");

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

                case 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);
                    }

                case EX_DelegateProperty:
                case EX_InstanceDelegate:
                    return Token(ReadName());

                case 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 EX_EqualEqual_DelDel:
                case EX_EqualEqual_DelFunc:
                    return CompareDelegates("==");

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

                default:
                    if (b >= 0x60)
                    {
                        return ReadNativeCall(b);
                    }
                    return ErrToken("// unknown bytecode " + b.ToString("X2"), b);
            }
        }