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()); }
/// <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); } }
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); }
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); }
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); } }
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); } }
/// <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); }
/// <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); }
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]); }
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); }