Exemple #1
0
 public static string ToString(ValueType value)
 {
     Debug.Assert(value != null);
     if (value is NumericalType)
     {
         throw SchemeError.ErrorWithName("to-string", "can't inspect number-class", value);
     }
     return(value.ToString());
 }
Exemple #2
0
        /// <summary>
        /// Set value from the C# value type as the argument
        /// is object reference then value is in the box.
        /// </summary>
        /// <param name="value"></param>
        private void SetFromValueType(object value)
        {
            // the quick check

            if (value is Value)
            {
                this = (Value)value;
            }

            // core types first

            else if (value is bool)
            {
                Set((bool)value);
            }
            else if (value is int)
            {
                Set((int)value);
            }
            else if (value is double)
            {
                Set((double)value);
            }

            //and now all the odd cases (note the leading else!)

            else if (value is uint)
            {
                Set((double)(uint)value);
            }
            else if (value is float)
            {
                Set((double)(float)value);
            }
            else if (value is sbyte)
            {
                Set((double)(sbyte)value);
            }
            else if (value is byte)
            {
                Set((double)(byte)value);
            }
            else if (value is short)
            {
                Set((double)(short)value);
            }
            else if (value is ushort)
            {
                Set((double)(ushort)value);
            }
            else
            {
                throw SchemeError.ErrorWithName("value-set", "can't assign the C# value-type", value);
            }
        }
Exemple #3
0
        public static double GetDouble(string value)
        {
            double val = 0;

            if (double.TryParse(value, out val))
            {
                return(val);
            }

            throw SchemeError.ErrorWithName("get-double", "improperly formed float value", value);
        }
Exemple #4
0
        public static float GetFloat(string value)
        {
            float val = 0;

            if (float.TryParse(value, out val))
            {
                return(val);
            }

            throw SchemeError.ErrorWithName("get-float", "improperly formed float value", value);
        }
Exemple #5
0
 public static int GetInteger(string value)
 {
     try
     {
         var val = int.Parse(value, NumberStyles.AllowLeadingSign);
         return(val);
     }
     catch (System.Exception ex)
     {
         throw SchemeError.ErrorWithName("get-integer", "improperly formed int value", value);
     }
 }
Exemple #6
0
 public static int GetHexadecimal(string value)
 {
     try
     {
         Debug.Assert(value.Length > 2, "Error in hex literal");
         var hval = int.Parse(value.Substring(2), NumberStyles.AllowHexSpecifier);
         return(hval);
     }
     catch (System.Exception ex)
     {
         throw SchemeError.ErrorWithName("get-hexadecimal", "improperly formed int value", value);
     }
 }
Exemple #7
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="ast"></param>
        /// <param name="template"></param>
        /// <returns>return dummy value</returns>
        private int Generate(AST ast)
        {
            if (ast is AstLiteral)
            {
                return(GenerateLiteral(ast as AstLiteral));
            }

            if (ast is AstReference)
            {
                return(GenerateReference(ast as AstReference));
            }

            if (ast is AstSet)
            {
                return(GenerateSet(ast as AstSet));
            }

            if (ast is AstLambda)
            {
                return(GenerateLambda(ast as AstLambda));
            }

            if (ast is AstConditionIf)
            {
                return(GenerateConditionIf(ast as AstConditionIf));
            }

            if (ast is AstCondition)
            {
                return(GenerateCondition(ast as AstCondition));
            }

            if (ast is AstPrimitive)
            {
                return(GeneratePrimitive(ast as AstPrimitive));
            }

            if (ast is AstApplication)
            {
                return(GenerateApplication(ast as AstApplication));
            }

            if (ast is AstSequence)
            {
                return(GenerateSequence(ast as AstSequence));
            }

            throw SchemeError.ErrorWithName("codegen-generate", "unexpected ast", ast);
        }
Exemple #8
0
        /// <summary>
        /// Return double value from any type of string
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static double GetNumerical(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                throw SchemeError.ErrorWithName("get-double", "unexpected empty string", value);
            }
            if (char.IsDigit(value[0]))
            {
                return(GetDouble(value));
            }

            if (value[0] == '#')
            {
                return(GetHexadecimal(value));
            }

            throw SchemeError.ErrorWithName("get-numerical", "improperly formed numerical value", value);
        }
Exemple #9
0
        public Value RunClosure(Frame frame, Template template, params System.ValueType[] args)
        {
            var environment = frame.environment;
            var literals    = template.Literals;
            var values      = frame.Values;
            var sp          = frame.SP;

#if PROFILER
            _profiler.EnterFunction(null, TEMPLATE);
#endif
            try
            {
                for (var pc = frame.PC; pc < template.Code.Length; frame.PC = ++pc)
                {
                    var op = template.Code[pc];
                    switch (op.OpCode)
                    {
                    case OpCode.NOP:
                        break;

                    case OpCode.MOVE:
                        values[op.A] = values[op.B];
                        break;

                    case OpCode.LOADK:
                        values[op.A] = literals[op.Bx];
                        break;

                    case OpCode.LOADBOOL:
                    {
                        values[op.A].Set(op.B != 0);
                        if (op.C != 0)
                        {
                            pc++;
                        }
                    }
                    break;

                    case OpCode.LOADNIL:
                    {
                        var a = op.A;
                        var b = op.B;
                        while (b-- != 0)
                        {
                            values[a++].SetNil();
                        }
                    }
                    break;

                    case OpCode.GETUPVAL:
                    {
                        // R(A) := U[B]
                        var idx = op.B;
                        var uv  = values[idx];
                        if (uv.RefVal is Frame)
                        {
                            var uframe = uv.RefVal as Frame;
                            var varnum = (int)uv.NumVal;
                            values[op.A] = uframe.Values[varnum];
                        }
                        else
                        {
                            int franum = 0;
                            int varnum = 0;
                            template.GetUpValue(idx, ref franum, ref varnum);
                            uv.NumVal = varnum;
                            uv.RefVal = frame.GetFrame(franum);
                            var uframe = uv.RefVal as Frame;
                            values[op.A] = uframe.Values[varnum];
                        }
                    }
                    break;

                    case OpCode.GETGLOBAL:
                    {
                        // R(A) = G[K(Bx)]
                        var literal = literals[op.Bx].AsSymbol();
                        var binding = environment.LookupRecursively(literal);
                        if (binding == null)
                        {
                            //    throw SchemeError.Error("vm-set-gloabal", "undefined variable", upVal.AsSymbol());
                            values[op.A] = Value.Nil;
                        }
                        else
                        {
                            values[op.A] = environment[literal];
                        }

                        //Value upVal;
                        //frame.environment.LookupRecursively(frame, ref literals[op.B], out upVal);

                        //var c = op.C;
                        //var key = (c & Instruction.BitK) != 0 ?
                        //    literals[c & Instruction.BitKNeg] :
                        //    values[c];
                        //Value upVal;
                        //frame.environment.LookupRecursively(frame, ref upvalues[op.B], out upVal);
                        //Binding bind = environment.LookupRecursively(upVal.AsSymbol());
                        //if (bind != null)
                        //    values[op.A].Set(bind.value);
                        //else
                        //    throw SchemeError.Error("vm-get-gloabal", "undefined variable", upVal.AsSymbol());
                    }
                    break;

                    case OpCode.GETTABLE:
                        // RA = R(B)[Rk(C)]
                        break;

                    case OpCode.SETGLOBAL:
                    {
                        // G[Bx] = R(A)
                        var varIdx = op.Bx;

                        if (values[varIdx].RefVal == null)
                        {
                            var litIdx  = template.GetVariable(varIdx).LitIdx;
                            var literal = literals[litIdx].AsSymbol();
                            var binding = environment.LookupRecursively(literal);
                            if (binding == null)
                            {
                                values[varIdx].RefVal = environment.DefineOrUpdate(literal, values[op.A]);
                            }
                            else
                            {
                                binding.value         = values[op.A];
                                values[varIdx].RefVal = binding;
                            }
                        }
                        else if (values[varIdx].RefVal is Binding)
                        {
                            var binding = values[varIdx].RefVal as Binding;
                            binding.value = values[op.A];
                        }
                        else
                        {
                            throw new System.Exception();
                        }
                    }
                    break;

                    case OpCode.SETUPVAL:
                    {
                        // U[B] := R(A)
                        var uv     = values[op.B];
                        var varNum = (int)uv.NumVal;
                        var uframe = uv.RefVal as Frame;
                        if (uframe == null)
                        {
                            throw SchemeError.ErrorWithName("vm", "can't write up value");
                        }
                        uframe.Values[varNum] = values[op.A];
                    }
                    break;

                    case OpCode.SETTABLE:
                        //{
                        //    int b = op.B;
                        //    var key = (b & Instruction.BitKB) != 0 ?
                        //        literals[b & ~Instruction.BitK] :
                        //        values[b];
                        //
                        //    int c = op.C;
                        //    var value = (c & Instruction.BitKC) != 0 ?
                        //        literals[c & ~Instruction.BitK] :
                        //        values[c];
                        //
                        //    //SetTable(variables[ op.A], ref key, ref value);
                        //}
                        break;

                    case OpCode.NEWTABLE:
                    {
                        var nArr = FbToInt(op.B);           // array size
                        var nNod = FbToInt(op.C);           // hash size
                        values[op.A].Set(new Table(nNod));
                    }
                    break;

                    case OpCode.SELF:
                    {
                        // TODO!
                        var table = values[op.B];
                        values[op.A + 1] = table;

                        var c   = op.C;
                        var key = (c & Instruction.BitK) != 0 ?
                                  literals[c & Instruction.BitKNeg] :
                                  values[c];

                        //GetTable(table, ref key, stackBase + op.A);
                    }
                    break;

                    case OpCode.ADD:
                    case OpCode.SUB:
                    case OpCode.MUL:
                    case OpCode.DIV:
                    case OpCode.MOD:
                    case OpCode.POW:
                    {
                        var ib = op.B;
                        var b  = (ib & Instruction.BitK) != 0 ?
                                 literals[ib & Instruction.BMask] :
                                 values[ib];

                        var ic = op.C;
                        var c  = (ic & Instruction.BitK) != 0 ?
                                 literals[ic & Instruction.BitKNeg] :
                                 values[ic];

                        if (b.RefVal is INumeric &&
                            c.RefVal is INumeric)
                        {
                            double rv, bv = b.NumVal, cv = c.NumVal;
                            switch (op.OpCode)
                            {
                            case OpCode.ADD: rv = bv + cv; break;

                            case OpCode.SUB: rv = bv - cv; break;

                            case OpCode.MUL: rv = bv * cv; break;

                            case OpCode.DIV: rv = bv / cv; break;

                            case OpCode.MOD: rv = bv % cv; break;

                            case OpCode.POW: rv = Math.Pow(bv, cv); break;

                            default: throw new NotImplementedException();
                            }
                            if (c.RefVal is FixnumType && c.RefVal is FixnumType)
                            {
                                values[op.A].Set((int)rv);
                            }
                            else
                            {
                                values[op.A].Set(rv);
                            }
                        }
                        else
                        {
                            DoArith(op.OpCode, b, c, ref values[op.A]);
                        }
                    }
                    break;

                    case OpCode.NEG:
                    {
                        var ib = op.B;
                        var b  = (ib & Instruction.BitK) != 0 ?
                                 literals[ib & Instruction.BMask] :
                                 values[ib];

                        if (b.RefVal is FloatType)
                        {
                            values[op.A].Set(-b.NumVal);
                        }
                        else if (b.RefVal is FixnumType)
                        {
                            values[op.A].Set(-(int)b.NumVal);
                        }
                        else
                        {
                            DoArith(op.OpCode, b, b, ref values[op.A]);
                        }
                    }
                    break;

                    case OpCode.NOT:
                    {
                        values[op.A].Set(!values[op.B].AsBool());
                    }
                    break;

                    case OpCode.LEN:
                    {
                        var ib = op.B;
                        var b  = (ib & Instruction.BitK) != 0 ?
                                 literals[ib & Instruction.BMask] :
                                 values[ib];
                        DoGetLen(ref b, out values[op.A]);
                    }
                    break;

                    case OpCode.CONCAT:
                    {
                        var end = op.C + 1;
                        var sb  = new StringBuilder();
                        for (var n = op.B; n < end; n++)
                        {
                            sb.Append(values[n].ToString());
                        }
                        values[op.A].Set(sb.ToString());
                    }
                    break;

                    case OpCode.JMP:
                    {
                        pc += op.SBx;
                    }
                    break;

                    case OpCode.EQ:
                    case OpCode.LT:
                    case OpCode.LE:
                    case OpCode.NE:
                    case OpCode.GT:
                    case OpCode.GE:
                    {
                        var b  = op.B;
                        var bv = (b & Instruction.BitK) != 0 ?
                                 literals[b & Instruction.BitKNeg] :
                                 values[b];

                        var c  = op.C;
                        var cv = (c & Instruction.BitK) != 0 ?
                                 literals[c & Instruction.BitKNeg] :
                                 values[c];

                        bool test;

                        switch (op.OpCode)
                        {
                        case OpCode.EQ:
                            test = bv.RefVal == cv.RefVal ?
                                   bv.RefVal is NumericalType && bv.NumVal == cv.NumVal :
                                   Equal(ref bv, ref cv);
                            break;

                        case OpCode.LT:
                            test = (bv.RefVal is NumericalType && cv.RefVal is NumericalType) ?
                                   bv.NumVal < cv.NumVal :
                                   Less(ref bv, ref cv);
                            break;

                        case OpCode.LE:
                            test = (bv.RefVal is NumericalType && cv.RefVal is NumericalType) ?
                                   bv.NumVal <= cv.NumVal :
                                   LessEqual(ref bv, ref cv);
                            break;

                        case OpCode.NE:
                            test = bv.RefVal != cv.RefVal ?
                                   bv.RefVal is NumericalType && bv.NumVal == cv.NumVal :
                                   !Equal(ref bv, ref cv);
                            break;

                        case OpCode.GT:
                            test = (bv.RefVal is NumericalType && cv.RefVal is NumericalType) ?
                                   bv.NumVal > cv.NumVal :
                                   !LessEqual(ref bv, ref cv);
                            break;

                        case OpCode.GE:
                            test = (bv.RefVal is NumericalType && cv.RefVal is NumericalType) ?
                                   bv.NumVal >= cv.NumVal :
                                   !Less(ref bv, ref cv);
                            break;

                        default: Debug.Assert(false); test = false; break;
                        }
                        values[op.A].Set(test);
                    }
                    break;


                    case OpCode.TEST:
                    {
                        // if ((bool)R(A) != (bool)C) then {skip next instruction}
                        var a       = values[op.A].RefVal;
                        var isfalse = a == null || a == BoolType.False;

                        if ((op.C == 0) == isfalse)
                        {
                            op = template.Code[++pc];
                            Debug.Assert(op.OpCode == OpCode.JMP);
                            goto case OpCode.JMP;
                        }
                        else
                        {
                            pc++;
                        }
                    }
                    break;

                    case OpCode.TESTSET:
                    {
                        var b    = values[op.B].RefVal;
                        var test = b == null || b == BoolType.False;

                        if ((op.C != 0) == test)
                        {
                            pc++;
                        }
                        else
                        {
                            values[op.A] = values[op.B];

                            op = template.Code[++pc];
                            Debug.Assert(op.OpCode == OpCode.JMP);
                            goto case OpCode.JMP;
                        }
                    }
                    break;

                    case OpCode.CALL:
                    {
                        // A - has the closure to call
                        // B - has quantity of the arguments
                        // C - has quantity of results

                        var func = values[op.A];
                        if (func.RefVal is Frame)
                        {
                            var closure     = func.As <Frame>();
                            var closureTemp = closure.template;

                            var numArgs    = op.B;
                            var numRetVals = op.C;

                            //pc++; /// return to the next instruction

                            if (numArgs < closureTemp.ReqArgsNumber)
                            {
                                throw SchemeError.ErrorWithName("vm", "not enough arguments");
                            }


                            {
                                /// -------------------------------
                                /// required and optional arguments
                                /// -------------------------------
                                var reqnum = closureTemp.ReqArgsNumber;
                                var keynum = closureTemp.KeyArgsNumber;
                                var optnum = closureTemp.OptArgsNumber;
                                var src    = op.A + 1;
                                var dst    = 0;

                                while (reqnum > 0 && dst < numArgs)
                                {
                                    closure.Values[dst++] = values[src++]; reqnum--;
                                }

                                // now initialize optional values
                                while (optnum > 0 && dst < numArgs)
                                {
                                    closure.Values[dst++] = values[src++]; optnum--;
                                }

                                src--;          // because argument 0 is method we minus 1
                                                // to make index address in template's
                                                // value array

                                while (optnum > 0)
                                {
                                    var lidx = closureTemp.Variables[src++].LitIdx;

                                    if (lidx >= 0)
                                    {
                                        var initval = closureTemp.Literals[lidx];
                                        if (initval.Is <Template>())
                                        {
                                            var ovtinit = closureTemp.Literals[lidx].As <Template>();
                                            closure.Values[dst++] = RunClosure(frame, ovtinit);
                                        }
                                        else
                                        {
                                            closure.Values[dst++] = initval;
                                        }
                                    }
                                    else
                                    {
                                        closure.Values[dst++].Set(false);
                                    }
                                    optnum--;
                                }

                                /// -------------------------------
                                /// key arguments
                                /// -------------------------------

                                dst += keynum;

                                /// -------------------------------
                                /// rest arguments
                                /// -------------------------------
                            }

                            values[op.A] = RunClosure(closure, closure.template);
                        }
                        else if (func.RefVal is Function)
                        {
                            // CALL A.B.C
                            // <A> result register
                            // <B> quantity of arguments
                            // 0: () no arguments
                            // 1: R(A+2)
                            // 2: R(A+3)
                            // <C> quantity of results
                            // 0: NILL 0 no result
                            // 1: R(A)
                            // 2: R(A..B)

                            var function = func.As <Function>();
                            if (function != null)
                            {
                                function.Call(frame, op.A, op.B, op.C);
                            }
                            else
                            {
                                throw SchemeError.ErrorWithName("vm", "expected function found", func);
                            }
                        }
                    }
                    break;

                    case OpCode.TAILCALL:
                        break;

                    case OpCode.RETURN:
                        // return R(A) quantity of RB
                        if (op.B <= 0)
                        {
                            frame = frame.parent;
                            return(Value.Void);
                        }
                        else
                        {
                            var res = values[op.A];
                            frame = frame.parent;
                            return(res);
                        }
                        break;

                    case OpCode.RESULT:
                        // return R(A) quantity of RB
                        if (op.B <= 0)
                        {
                            return(Value.Void);
                        }
                        else
                        {
                            return(values[op.A]);
                        }
                        break;

                    case OpCode.FORLOOP:
                        break;

                    case OpCode.FORPREP:
                        break;

                    case OpCode.TFORLOOP:
                        break;

                    case OpCode.SETLIST:
                        break;

                    case OpCode.CLOSE:
                        break;

                    case OpCode.CLOSURE:
                    {
                        /// R(A) := closure(KPROTO[Bx], R(A), ... , R(A + n))
                        var ntempl = literals[op.Bx].As <Template>();
                        var nfram  = new Frame(frame, ntempl);
                        values[op.A].RefVal = nfram;
                    }
                    break;

                    case OpCode.VARARG:
                    {
                        //// R(A), R(A+1), ..., R(A+B-1) = varargs
                        //int max = frame.ValuesCount;
                        //int idx = frame.VarArgsIndex + frame.VarArgsCount;
                        //int cnt = op.B; // argc
                        //while (cnt>0)
                        //{
                        //    values[destIdx + i].RefVal = null;
                        //}
                        //
                        //
                        //
                        //if (VarArgsCount + Va)
                        //int qunatity = op.A
                        //if (frame.argc)
                        //int srcIdx = call.VarArgsIndex;
                        //int destIdx = stackBase + op.A;
                        //
                        //int numVarArgs = call.StackBase - srcIdx;
                        //int numWanted = op.B - 1;
                        //
                        //if (numWanted == -1)
                        //{
                        //    numWanted = numVarArgs;
                        //    stackTop = destIdx + numWanted;
                        //}
                        //
                        //int numHad = numWanted < numVarArgs ? numWanted : numVarArgs;
                        //for (int i = 0; i < numHad; i++)
                        //    values[destIdx + i] = values[srcIdx + i];
                        //
                        //for (int i = numHad; i < numWanted; i++)
                        //    values[destIdx + i].RefVal = null;
                    }
                    break;


                    default:
                        throw new InvalidOperationException("Invalid instruction");
                    }
                }
            }
            catch (SchemeError ex)
            {
                //return VALUE;
            }
            finally
            {
                // CONT = PREV_CONT;
                // ENVT = PREV_ENVT;
                // EVAL_STACK = PREV_EVAL_STACK;
                // TEMPLATE = PREV_TEMPLATE;
                // PC = PREV_PC;
            }


#if PROFILER
            _profiler.EnterFunction(null, TEMPLATE);
#endif
            return(values[frame.SP]);
        }
Exemple #10
0
        private short GenerateSet(AstSet ast)
        {
            var value  = ast.Value;
            int target = Generate(value);


            if (ast.IsGlobal)
            {
                // G[K(Bx)] := R(A)
                var varIdx = new Value(ast.Identifier);
                var litIdx = DefineLiteral(varIdx);

                if (litIdx > Instruction.BxMask)
                {
                    throw SchemeError.ErrorWithName("GenerateSet", "the index is too large for Bx", ast);
                }

                var litIdxCur = Variables[ast.VarIdx].LitIdx;
                if (litIdxCur < 0)
                {
                    var var = Variables[ast.VarIdx];
                    var.LitIdx            = litIdx;
                    Variables[ast.VarIdx] = var;
                }
                else if (litIdxCur != litIdx)
                {
                    throw new System.Exception();
                }

                AddABX(OpCode.SETGLOBAL, (short)target, ast.VarIdx);
            }
            else
            {
                var envIdx = ast.UpEnvIdx;
                var varIdx = ast.UpVarIdx;

                if (envIdx > 0)
                {
                    // UpValue case
                    // U[B] := R(A)
                    if (varIdx > Instruction.BMask)
                    {
                        throw SchemeError.ErrorWithName("GenerateSet", "the index is too large for RB", ast);
                    }
                    if (target > Instruction.AMask)
                    {
                        throw SchemeError.ErrorWithName("GenerateSet", "the index is too large for RA", ast);
                    }
                    //  AddAB(OpCode.SETUPVAL, (short)varIdx, (short)target);
                }
                else
                {
                    // Local case
                    // R(A) = R(B)
                    if (varIdx > Instruction.AMask)
                    {
                        throw SchemeError.ErrorWithName("GenerateSet", "the index is too large for RA", ast);
                    }
                    if (target > Instruction.BMask)
                    {
                        throw SchemeError.ErrorWithName("GenerateSet", "the index is too large for RB", ast);
                    }

                    AddAB(OpCode.MOVE, (short)varIdx, (short)target);
                }
            }
            return(-1);
        }