public override void CompileToDoubleOrNan() { if (IsCacheNeeded) { EmitCacheAccess(); } else { expr.CompileToDoubleOrNan(); } }
/// <summary> /// Generate code to compute the expression's value and storing it in the IL /// local variable; possibly to unwrap to a number variable; and possibly under /// the control of an evaluation condition evalCond. /// </summary> public virtual void Compile() { EvalCondCompile(delegate { if (var != null && var.Type == Typ.Number) { expr.CompileToDoubleOrNan(); } else { expr.Compile(); } if (var != null) { var.EmitStore(ilg); } if (numberVar != null) { Debug.Assert(var.Type == Typ.Value); var.EmitLoad(ilg); UnwrapToDoubleOrNan(); numberVar.EmitStore(ilg); } }); }
// Generate code to evaluate all argument expressions, including the receiver es[1] // if the method is an instance method, and convert their values to .NET types. private void CompileArgumentsAndApply(CGExpr[] es, Gen ifSuccess, Gen ifOther) { int argCount = es.Length; // The error continuations must pop the arguments computed so far. Gen[] errorCont = new Gen[argCount]; if (argCount > 0) { errorCont[0] = ifOther; } for (int i = 1; i < argCount; i++) { int ii = i; // Capture lvalue -- do NOT inline! errorCont[ii] = new Gen(delegate { ilg.Emit(OpCodes.Pop); errorCont[ii - 1].Generate(ilg); }); } // Generate code, backwards, to evaluate argument expressions and // convert to the .NET method's argument types for (int i = argCount - 1; i >= 0; i--) { // These local vars capture rvalue rather than lvalue -- do NOT inline them! CGExpr ei = es[i]; Gen localSuccess = ifSuccess; Typ argType = functionInfo.signature.argTypes[i]; Gen ifError = errorCont[i]; if (argType == Typ.Number) { ifSuccess = new Gen(delegate { ei.CompileToDoubleOrNan(); localSuccess.Generate(ilg); }); } else if (argType == Typ.Function) { ifSuccess = new Gen(delegate { ei.Compile(); CheckType(FunctionValue.type, localSuccess, ifError); }); } else if (argType == Typ.Array) { ifSuccess = new Gen(delegate { ei.Compile(); CheckType(ArrayValue.type, localSuccess, ifError); }); } else if (argType == Typ.Text) { ifSuccess = new Gen(delegate { ei.Compile(); CheckType(TextValue.type, localSuccess, ifError); }); } else // argType.Value -- TODO: neglects to propagate ErrorValue from argument { ifSuccess = new Gen(delegate { ei.Compile(); localSuccess.Generate(ilg); }); } } ifSuccess.Generate(ilg); }
// Generate code to evaluate all argument expressions, including the receiver es[1] // if the method is an instance method, and convert their values to .NET types. private void CompileArgumentsAndApply(CGExpr[] es, Gen ifSuccess, Gen ifOther) { int argCount = es.Length - 1; // The error continuations must pop the arguments computed so far: Gen[] errorCont = new Gen[argCount]; if (argCount > 0) { errorCont[0] = ifOther; } for (int i = 1; i < argCount; i++) { int ii = i; // Capture lvalue -- do NOT inline! errorCont[ii] = new Gen(delegate { ilg.Emit(OpCodes.Pop); errorCont[ii - 1].Generate(ilg); }); } // Generate code, backwards, to evaluate argument expressions and // convert to external method's argument types for (int i = argCount - 1; i >= 0; i--) { // These local vars capture rvalue rather than lvalue -- do NOT inline them! CGExpr ei = es[i + 1]; Gen localSuccess = ifSuccess; int argIndex = i; Type argType = ef.ArgType(i); Gen ifError = errorCont[i]; // First some special cases to avoid boxing: if (argType == typeof(System.Double)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleOrNan(); localSuccess.Generate(ilg); }); } else if (argType == typeof(System.Single)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleOrNan(); ilg.Emit(OpCodes.Conv_R4); localSuccess.Generate(ilg); }); } else if (signed32.Contains(argType)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Conv_I4); localSuccess.Generate(ilg); }), ifError); }); } else if (unsigned32.Contains(argType)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Conv_U4); localSuccess.Generate(ilg); }), ifError); }); } else if (argType == typeof(System.Int64)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Conv_I8); localSuccess.Generate(ilg); }), ifError); }); } else if (argType == typeof(System.UInt64)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Conv_U8); localSuccess.Generate(ilg); }), ifError); }); } else if (argType == typeof(System.Boolean)) { ifSuccess = new Gen( delegate { ei.CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Ldc_R8, 0.0); ilg.Emit(OpCodes.Ceq); localSuccess.Generate(ilg); }), ifError); }); } else if (argType == typeof(System.Char)) { ifSuccess = new Gen( delegate { ei.Compile(); ilg.Emit(OpCodes.Call, TextValue.toNakedCharMethod); localSuccess.Generate(ilg); }); } else if (argType == typeof(System.String)) { ifSuccess = new Gen( delegate { ei.Compile(); UnwrapToString(localSuccess, ifError); }); } else // General cases: String[], double[], double[,], ... { ifSuccess = new Gen( delegate { ei.Compile(); ilg.Emit(OpCodes.Call, ef.ArgConverter(argIndex).Method); if (argType.IsValueType) // must unbox wrapped value type, but this is too simple-minded { ilg.Emit(OpCodes.Unbox, argType); } localSuccess.Generate(ilg); }); } } ifSuccess.Generate(ilg); }