Пример #1
0
        public VAL Run(int breakPoint)
        {
L1:

            Instruction I = CS[IP];
            Operand operand = I.operand;

            position.line  = I.line;
            position.col   = I.col;
            position.cur   = I.cur;
            position.block = I.block;

            if (I.line == breakPoint)
            {
                return(null);
            }

            switch (I.cmd)
            {
                //----------------------------------------------------------------------------

                #region  MOV, STO,STO1, RMT. RCP

            case INSTYPE.MOV:
                if (operand.ty == OPRTYPE.identcon)         // MOV [v]
                {
                    if (CS[IP + 1].cmd == INSTYPE.OFS)      // if this is offset of a struct, keep variable name
                    {
                        REG.Push(new VAL(operand));
                    }
                    else
                    {
                        REG.Push(GetVAL(operand.Str, false));
                    }
                }
                else if (operand.ty == OPRTYPE.addrcon)         // MOV [BP-3]
                {
                    //VAL opr = Register.BPAddr(BP, operand);

                    VAL opr = new VAL();
                    opr.ty    = VALTYPE.addrcon;
                    opr.value = BP + operand.Addr;
                    opr.name  = operand.name;

                    REG.Push(opr);
                }
                else
                {
                    VAL x = new VAL(operand);
                    if (operand.ty == OPRTYPE.funccon)
                    {
                        if (ES.SP > -1)
                        {
                            x.temp = new ContextInstance(this.context, ES.Top());
                        }
                        else
                        {
                            x.temp = new ContextInstance(this.context, new VAL());
                        }
                    }

                    REG.Push(VAL.Clone(x));     // MOV 3
                }
                break;



            //----------------------------------------------------------------------------


            case INSTYPE.STO1:
            case INSTYPE.STO:
                R0 = REG.Pop();
                R1 = REG.pop();
                if (R1.ty == VALTYPE.addrcon)
                {
                    SS[R1.Address] = R0;
                }
                else
                {
                    HostOperation.Assign(R1, R0);
                }

                if (I.cmd == INSTYPE.STO)
                {
                    REG.Push(R1);
                }
                break;

            case INSTYPE.RMT:
                if (CS[IP + 1].cmd != INSTYPE.HALT)      //used for expression decoding,keep last value
                {
                    REG.Pop();
                }
                break;

            case INSTYPE.RCP:
                REG.Push(VAL.Clone(REG.Top()));
                break;

                #endregion


                //----------------------------------------------------------------------------

                #region PUSH/POP/SP/ESI/ESO
            case INSTYPE.ESI:
                R0 = REG.Pop();
                ES.Push(R0);
                break;

            case INSTYPE.ESO:
                ES.Pop();
                break;

            case INSTYPE.PUSH:
                if (operand != null && operand.ty == OPRTYPE.regcon)
                {
                    switch (operand.SEG)
                    {
                    case SEGREG.BP: SS.Push(new VAL(BP)); break;

                    case SEGREG.SP: SS.Push(new VAL(SS.SP)); break;

                    case SEGREG.SI: SS.Push(new VAL(SI)); break;

                    case SEGREG.IP: SS.Push(new VAL(IP + 2)); break;

                    case SEGREG.EX: EX.Push((int)operand.value); break;
                    }
                }
                else
                {
                    R0 = REG.Pop();
                    SS.Push(R0);
                }
                break;

            case INSTYPE.POP:
                if (operand.ty == OPRTYPE.regcon)
                {
                    switch (operand.SEG)
                    {
                    case SEGREG.BP: BP = (SS.Pop()).Address; break;

                    case SEGREG.SI: SI = (SS.Pop()).Address; break;

                    case SEGREG.SP: SS.SP = (SS.Pop()).Address; break;

                    case SEGREG.EX: EX.Pop(); break;
                    }
                }
                else
                {
                    R0 = SS.Pop();
                    REG.Push(R0);
                }
                break;

            case INSTYPE.SP:
                SS.SP += operand.Addr;
                break;

                #endregion


                //----------------------------------------------------------------------------

                #region OFS, ARR
            //----------------------------------------------------------------------------
            // Associative List
            // Mike={{"street", "3620 Street"},{"zip", 20201},{"phone","111-222-333},{"apt",1111}}
            // Mike.street = "3620 Street";
            // Mike.zip = 40802;
            case INSTYPE.OFS:
                R0 = REG.Pop();
                R1 = REG.pop();
                {
                    VAL v = new VAL();
                    switch (R1.ty)
                    {
                    case VALTYPE.hostcon:
                        v = R1.getter(R0, true, OffsetType.STRUCT);
                        goto LOFS;

                    case VALTYPE.addrcon:
                        v = SS[R1.Address];
                        if (v.Undefined || v.IsNull)
                        {
                            v.ty    = VALTYPE.listcon;
                            v.value = new VALL();
                        }
                        break;

                    case VALTYPE.listcon:
                        v = R1;
                        break;

                    default:           // if assoicative arrary is empty or not list
                        R1.ty    = VALTYPE.listcon;
                        R1.value = new VALL();
                        v        = R1;
                        break;
                    }

                    switch (v.ty)
                    {
                    case VALTYPE.listcon:
                        VALL L = v.List;
                        v = L[R0.Str];

                        // if property is not found in the associative array
                        if (!v.Defined)
                        {
                            L[R0.Str] = v;
                        }

                        break;

                    case VALTYPE.hostcon:
                        //VAL.Assign(v, VAL.HostTypeOffset(v.value, R0.value));
                        v = HostOperation.HostTypeOffset(v, R0, OffsetType.STRUCT);
                        break;
                    }

LOFS:
                    if ((object)v == null)
                    {
                        v = new VAL();
                    }

                    v.name = R1.name + "." + R0.name;
                    REG.Push(v);
                }
                break;

            case INSTYPE.ARR:
                R0 = REG.Pop();
                R1 = REG.pop();
                {
                    VAL v = new VAL();
                    switch (R1.ty)
                    {
                    case VALTYPE.addrcon:
                        v = SS[R1.Address];           //indirect addressing
                        if (v.Undefined || v.IsNull)
                        {
                            v.ty    = VALTYPE.listcon;
                            v.value = new VALL();
                            v       = v.getter(R0, true, OffsetType.ARRAY);
                        }
                        else
                        {
                            v = v.getter(R0, true, OffsetType.ARRAY);
                        }
                        break;

                    case VALTYPE.listcon:                       //push reference
                        v = R1.getter(R0, true, OffsetType.ARRAY);
                        break;

                    case VALTYPE.hostcon:
                        v = R1.getter(R0, true, OffsetType.ARRAY);
                        if (!v.Defined)
                        {
                            throw new RuntimeException(position, "{0} does not have property {1}.", R1, R0);
                        }
                        break;

                    default:
                        //refer: public VAL this[VAL arr], when R1 == null, dynamically allocate a list
                        R1.ty    = VALTYPE.listcon;
                        R1.value = new VALL();
                        v        = R1.getter(R0, true, OffsetType.ARRAY);

                        //JError.OnRuntime(0);
                        break;
                    }

                    v.name = R1.name + "[" + R0.ToString() + "]";
                    REG.Push(v);
                }
                break;

                #endregion


                //----------------------------------------------------------------------------

                #region  CALL, NEW, ENDP, RET, GNRC
            case  INSTYPE.GNRC:
                R0 = REG.Pop();         // R0 = new Type[] { string, int }
                R1 = REG.Pop();         // R1 = System.Collection.Generic
                {
                    Operand opr = I.operand;
                    VAL     R2  = R1[opr.Str];    // I.val.Str == Dictionary`2
                    if (R2.Undefined)             // Type is not registered
                    {
                        object t = HostType.GetType(R1.name + "." + opr.Str);
                        if (t != null)
                        {
                            R2 = VAL.NewHostType(t);
                        }
                        else
                        {
                            throw new RuntimeException(position, "Type {0}.{1} is not registered.", R1.name, opr.Str);
                        }
                    }

                    object A = R0.HostValue;
                    if (A is object[] && ((object[])A).Length == 0)         //case: typeof(Dictionary<,>)
                    {
                        if (R2.value is Type)
                        {
                            REG.Push(VAL.NewHostType(R2.value));
                        }
                        else
                        {
                            throw new RuntimeException(position, "{0} is not System.Type.", R1);
                        }
                    }
                    else
                    {
                        if (!(A is Type[]))
                        {
                            throw new RuntimeException(position, "<{0}> is not System.Type[].", R0.ToString2());
                        }

                        if (R2.value is Type)
                        {
                            Type t = (Type)R2.value;
                            REG.Push(VAL.NewHostType(t.MakeGenericType((Type[])A)));
                        }
                        else if (R2.value is MethodInfo)
                        {
                            MethodInfo t = (MethodInfo)R2.value;
                            VAL        m = VAL.NewHostType(t.MakeGenericMethod((Type[])A));
                            m.temp = R2.temp;
                            REG.Push(m);
                        }
                        else if (R2.value is MethodInfo[])
                        {
                            MethodInfo[] T = (MethodInfo[])R2.value;
                            for (int i = 0; i < T.Length; i++)
                            {
                                T[i] = T[i].MakeGenericMethod((Type[])A);
                            }
                            VAL m = VAL.NewHostType(T);
                            m.temp = R2.temp;
                            REG.Push(m);
                        }
                        else
                        {
                            throw new RuntimeException(position, "{0} is not System.Type.", R1);
                        }
                    }
                }

                break;

            case INSTYPE.CALL:
                if (operand.ty == OPRTYPE.intcon)
                {
                    IP = operand.Addr;
                }
                else if (operand.ty == OPRTYPE.addrcon)      // high-level programming
                {
                    SysFuncCallByAddr(SS[operand.Addr + BP]);
                }
                else if (operand.ty == OPRTYPE.regcon)
                {
                    SysFuncCallByAddr(SS[operand.Addr + SS.SP]);
                }
                else if (operand.ty == OPRTYPE.none)       //used for Generic method
                {
                    if (ES.IsEmpty())
                    {
                        R0 = REG.Pop();
                    }
                    else
                    {
                        R0 = ES.Top();
                    }

                    SysFuncCallByName(R0);
                }
                else
                {
                    SysFuncCallByName(new VAL(operand));
                }
                goto L1;

            case INSTYPE.NEW:
                if (operand.ty == OPRTYPE.funccon)
                {
                    NewInstance(new VAL(operand));         //system predifined class & user-defined class
                }
                else if (operand.ty == OPRTYPE.none)       //used for Generic class
                {
                    if (ES.IsEmpty())
                    {
                        R0 = REG.Pop();
                    }
                    else
                    {
                        R0 = ES.Top();
                    }

                    NewInstance(R0);
                }
                else if (operand.ty == OPRTYPE.intcon)
                {
                    int opr = (int)operand.value;
                    if (opr > 1)
                    {
                        R0 = REG.Pop();
                        R1 = REG.Pop();
                    }
                    else
                    {
                        R1 = REG.Pop();
                    }

                    if (R1.value is Type)
                    {
                        Type ty = (Type)R1.value;

                        if (opr == 1)
                        {
                            if (ty.IsArray)
                            {
                                R0 = VAL.Array();
                            }
                            else
                            {
                                R0 = new VAL();
                            }
                        }

                        if (R0.ty == VALTYPE.listcon)
                        {
                            if (ty.IsArray)
                            {
                                R0.List.ty = ty;
                            }
                            else
                            {
                                throw new RuntimeException(position, "new object failed. {0} is not Array Type", R1);
                            }
                        }

                        R0.Class = ty.FullName;
                        REG.Push(R0);
                    }
                    else
                    {
                        throw new RuntimeException(position, "new object failed. {0} is not System.Type", R1);
                    }

                    IP++;
                }

                goto L1;

            case INSTYPE.ENDP:
                if ((OPRTYPE)operand.Intcon == OPRTYPE.classcon)
                {
                    REG.Push(ES.Top());                 //return this;
                }
                else
                {
                    REG.Push(VAL.VOID);        //return void;
                }
                SS.SP = BP;                    //PUSH BP; POP SP;
                BP    = (SS.Pop()).Address;    //POP BP;

                R0 = SS.Top();                 //EXEC RET
                IP = R0.Address;
                goto L1;

            case INSTYPE.RET:
                if (!SS.IsEmpty())
                {
                    R0 = SS.Top();
                    IP = R0.Address;                        //goto V.i
                }
                else
                {
                    if (REG.IsEmpty())
                    {
                        return(VAL.VOID);
                    }
                    else
                    {
                        return(REG.Top());
                    }
                }

                goto L1;

                #endregion


                //----------------------------------------------------------------------------

                #region  +,-,*,/,%,>,<,!=,==,<=,>=, ++, --
            //----------------------------------------------------------------------------
            case INSTYPE.NEG:
                R0 = REG.Pop();
                if (operand.Intcon == -1)
                {
                    R0 = -R0;       //call VAL.operator -(VAL)
                }
                else
                {
                    R0 = +R0;       //call VAL.operator +(VAL)
                }
                REG.Push(R0);
                break;

            case INSTYPE.ADD: R0 = REG.Pop(); R1 = REG.Pop(); R1 += R0; REG.Push(R1); break;

            case INSTYPE.SUB: R0 = REG.Pop(); R1 = REG.Pop(); R1 -= R0; REG.Push(R1); break;

            case INSTYPE.MUL: R0 = REG.Pop(); R1 = REG.Pop(); R1 *= R0; REG.Push(R1); break;

            case INSTYPE.DIV: R0 = REG.Pop(); R1 = REG.Pop(); R1 /= R0; REG.Push(R1); break;

            case INSTYPE.MOD: R0 = REG.Pop(); R1 = REG.Pop(); R1 %= R0; REG.Push(R1); break;

            case INSTYPE.GTR: R0 = REG.Pop(); R1 = REG.Pop(); REG.Push(new VAL(R1 > R0)); break;

            case INSTYPE.LSS: R0 = REG.Pop(); R1 = REG.Pop(); REG.Push(new VAL(R1 < R0)); break;

            case INSTYPE.GEQ: R0 = REG.Pop(); R1 = REG.Pop(); REG.Push(new VAL(R1 >= R0)); break;

            case INSTYPE.LEQ: R0 = REG.Pop(); R1 = REG.Pop(); REG.Push(new VAL(R1 <= R0)); break;

            case INSTYPE.EQL: R0 = REG.Pop(); R1 = REG.Pop(); REG.Push(new VAL(R1 == R0)); break;

            case INSTYPE.NEQ: R0 = REG.Pop(); R1 = REG.Pop(); REG.Push(new VAL(R1 != R0)); break;

            case INSTYPE.INC:
                R0 = REG.pop();
                R1 = VAL.Clone(R0);
                if (R0.ty == VALTYPE.addrcon)
                {
                    SS[R0.Address] += new VAL(1);
                }
                else     //global varible
                {
                    HostOperation.Assign(R0, R0 + new VAL(1));
                }
                REG.Push(R1);
                break;

            case INSTYPE.DEC:
                R0 = REG.pop();
                R1 = VAL.Clone(R0);
                if (R0.ty == VALTYPE.addrcon)
                {
                    SS[R0.Address] -= new VAL(1);
                }
                else     //global varible
                {
                    HostOperation.Assign(R0, R0 - new VAL(1));
                }
                REG.Push(R1);
                break;

                #endregion


                //----------------------------------------------------------------------------

                #region MARK, END, EACH, CAS, DIRC

            case INSTYPE.MARK: REG.Push(Mark); break;

            case INSTYPE.END:
            {
                VAL L = new VAL(new VALL());
                while (REG.Top() != Mark)
                {
                    L.List.Insert(REG.Pop());
                }
                REG.Pop();                      // pop mark
                REG.Push(L);
            } break;

            case INSTYPE.EACH:
                R0 = REG.Pop();             //Collection
                R1 = REG.pop();             //address of element [BP+addr]
                REG.Push(ForEach(R0, SS[R1.Intcon], SS[R1.Intcon + 1]));
                break;

            case INSTYPE.CAS:
                R0 = REG.Pop(); R1 = REG.Top();
                if (R1 == R0)
                {
                    REG.Pop(); IP = operand.Addr; goto L1;
                }                                                            //goto V.i
                break;

            case INSTYPE.DIRC:          //directive command
                switch (operand.mod)
                {
                case Constant.SCOPE:
                    this.scope = (string)operand.value;
                    break;
                }
                break;

                #endregion


                //----------------------------------------------------------------------------

                #region &&, ||, ~, &, |, >>, <<
            //----------------------------------------------------------------------------
            case INSTYPE.NOTNOT:
                R0 = REG.Pop();
                if (R0.ty == VALTYPE.stringcon)
                {
                    REG.Push(Computer.Run(scope, R0.Str, CodeType.statements, context));
                }
                else
                {
                    REG.Push(new VAL(!R0));         //call VAL.operator !(VAL)
                }
                break;

            case INSTYPE.ANDAND: R0 = REG.pop(); R1 = REG.Pop();
                REG.Push(new VAL(R0.ty == VALTYPE.boolcon && R1.ty == VALTYPE.boolcon? R0.Boolcon && R1.Boolcon: false));
                break;

            case INSTYPE.OROR: R0 = REG.pop(); R1 = REG.Pop();
                REG.Push(new VAL(R0.ty == VALTYPE.boolcon && R1.ty == VALTYPE.boolcon ? R0.Boolcon || R1.Boolcon : false));
                break;


            //----------------------------------------------------------------------------
            case INSTYPE.NOT: R0 = REG.Pop();
                REG.Push(~R0);      //call VAL.operator ~(VAL)
                break;

            case INSTYPE.AND: R0 = REG.pop(); R1 = REG.Pop();
                REG.Push(R1 & R0);
                break;

            case INSTYPE.OR: R0 = REG.pop(); R1 = REG.Pop();
                REG.Push(R1 | R0);
                break;

            case INSTYPE.XOR: R0 = REG.pop(); R1 = REG.Pop();
                REG.Push(R1 ^ R0);
                break;

            //----------------------------------------------------------------------------
            case INSTYPE.SHL: R0 = REG.pop(); R1 = REG.Pop();
                if (!(R0.value is int))
                {
                    throw new RuntimeException(position, "the 2nd operand {0} in << operation must be integer", R0);
                }
                REG.Push(R1 << (int)R0.value);
                break;

            case INSTYPE.SHR: R0 = REG.pop(); R1 = REG.Pop();
                if (!(R0.value is int))
                {
                    throw new RuntimeException(position, "the 2nd operand {0} in >> operation must be integer", R0);
                }
                REG.Push(R1 >> (int)R0.value);
                break;
                #endregion


                //----------------------------------------------------------------------------

                #region JUMP, ADR, VLU

            case INSTYPE.JMP: IP = operand.Addr; goto L1;

            case INSTYPE.LJMP: IP += operand.Addr; goto L1;

            case INSTYPE.JNZ:
                if (REG.Pop() == new VAL(true))
                {
                    IP = operand.Addr; goto L1;
                }
                else
                {
                    break;
                }

            case INSTYPE.JZ:
                if (REG.Pop() != new VAL(true))
                {
                    IP = operand.Addr; goto L1;
                }
                else
                {
                    break;
                }

            case INSTYPE.LJZ:
                if (REG.Pop() != new VAL(true))
                {
                    IP += operand.Addr; goto L1;
                }
                else
                {
                    break;
                }

            case INSTYPE.ADR:
                R0 = REG.Pop();
                REG.Push(new VAL(R0.name));
                break;

            case INSTYPE.VLU:
                R0 = REG.Pop();
                if (R0.ty == VALTYPE.stringcon)
                {
                    REG.Push(Computer.Run(scope, R0.Str, CodeType.expression, context));
                }
                else
                {
                    throw new RuntimeException(position, "Invalid address type:" + R0.ToString());
                }
                break;

                #endregion


                //----------------------------------------------------------------------------


                #region  THIS,BASE
            case INSTYPE.THIS:                                           //this.x
                if (ES.SP > -1)
                {
                    if (this.scope != "")
                    {
                        VAL NS = GetScopeVAL(this.scope);
                        if (NS != ES.Top())
                        {
                            REG.Push(NS);
                        }
                    }
                    else
                    {
                        REG.Push(ES.Top());
                    }
                }
                else if (this.scope != "")
                {
                    if (operand.ty == OPRTYPE.intcon)                         //this.x=100;
                    {
                        REG.Push(GetScopeVAL(this.scope));
                    }
                    else
                    {
                        REG.Push(new VAL(this.scope));             //p=&this.x;
                    }
                }
                else
                {
                    if (CS[IP + 2].cmd == INSTYPE.OFS)
                    {
                        CS[IP + 2].cmd = INSTYPE.NOP;
                    }
                    else
                    {
                        throw new RuntimeException(position, "Operator[this] is invalid since namespace is empty.");
                    }
                }
                break;

            case INSTYPE.BASE:           //base.x
                //if (ES.SP > -1)
                //{
                //    VAL BS = ES.Top()[JExpression.BASE_INSTANCE];
                //    if((object)BS!=null)
                //        REG.Push(BS);
                //    else
                //        throw new RuntimeException(string.Format("Operator[base] is invalid since class {0} does not have base class.",ES.Top()));
                //}
                if (this.scope != "")
                {
                    string bv = "";
                    int    n  = 1;
                    if (operand.ty == OPRTYPE.intcon)          //base.base.x=10;
                    {
                        n = operand.Intcon;

                        bv = GetBaseScope(this.scope, n);

                        if (bv != "")
                        {
                            REG.Push(GetScopeVAL(bv));
                        }
                        else
                        {
                            if (CS[IP + 2].cmd == INSTYPE.OFS)
                            {
                                CS[IP + 2].cmd = INSTYPE.NOP;
                            }
                        }
                    }
                    else
                    {
                        n  = operand.Addr;                 // p = &base.base.x;
                        bv = GetBaseScope(this.scope, n);
                        REG.Push(new VAL(bv));
                    }
                }
                else
                {
                    throw new RuntimeException(position, "Operator[base] is invalid since scope is root.");
                }
                break;

                #endregion


                //----------------------------------------------------------------------------

                #region THRW, DDT, HALT

            case INSTYPE.THRW:
                R0 = REG.Top();
                if (!(R0.HostValue is Exception))
                {
                    throw new RuntimeException(position, "{0} is not type of System.Exception.", R0.HostValue);
                }

                if (EX.IsEmpty())
                {
                    throw (Exception)R0.HostValue;
                }
                IP = EX.Pop();

                if (IP == -1)
                {
                    throw (Exception)R0.HostValue;
                }
                break;

            case INSTYPE.DDT:
                Logger.WriteLine(DebugInfo());
                break;

            case INSTYPE.HALT:
                if (REG.IsEmpty())
                {
                    return(VAL.VOID);
                }
                else
                {
                    return(REG.Top());
                }

                #endregion
            }

            IP++;
            goto L1;
        }