// General version in terms of CompileToDoubleOrNan. // Should be overridden in CGNumberConst, CGTextConst, CGError, CGComposite ... /// <summary> /// Compile expression that is expected to evaluate to a proper (finite /// and non-NaN) number; generate code to test whether it is actually a /// proper number and then execute the code generated by ifProper, or /// else execute the code generated by ifOther. /// </summary> /// <param name="ifProper">Generates code for the case where the expression /// evaluates to a proper number; the generated code expects to find the value as /// an unwrapped proper float64 on the stack top.</param> /// <param name="ifOther"></param> public virtual void CompileToDoubleProper(Gen ifProper, Gen ifOther) { CompileToDoubleOrNan(); ilg.Emit(OpCodes.Stloc, testDouble); ilg.Emit(OpCodes.Ldloc, testDouble); ilg.Emit(OpCodes.Call, isInfinityMethod); ilg.Emit(OpCodes.Brtrue, ifOther.GetLabel(ilg)); ilg.Emit(OpCodes.Ldloc, testDouble); ilg.Emit(OpCodes.Call, isNaNMethod); ilg.Emit(OpCodes.Brtrue, ifOther.GetLabel(ilg)); ilg.Emit(OpCodes.Ldloc, testDouble); ifProper.Generate(ilg); if (!ifOther.Generated) { Label endLabel = ilg.DefineLabel(); ilg.Emit(OpCodes.Br, endLabel); ifOther.Generate(ilg); ilg.MarkLabel(endLabel); } }
/// <summary> /// Generate code to check the type of the stack top value, and leave it /// there if it is of the expected type t followed by success code; else /// jump to failure code. /// </summary> /// <param name="t">The expected type of the stack top value.</param> /// <param name="ifType">Generate success code -- the value is of the expected type.</param> /// <param name="ifOther">Generate failure code -- the value is not of the expected type.</param> protected void CheckType(Type t, Gen ifType, Gen ifOther) { ilg.Emit(OpCodes.Stloc, testValue); ilg.Emit(OpCodes.Ldloc, testValue); ilg.Emit(OpCodes.Isinst, t); ilg.Emit(OpCodes.Brfalse, ifOther.GetLabel(ilg)); ilg.Emit(OpCodes.Ldloc, testValue); ifType.Generate(ilg); if (!ifOther.Generated) { Label endLabel = ilg.DefineLabel(); ilg.Emit(OpCodes.Br, endLabel); ifOther.Generate(ilg); ilg.MarkLabel(endLabel); } }
/// <summary> /// Compiles an expression as a condition, that can be true (if non-zero) or /// false (if zero) or other (if +/-infinity or NaN). If possible, avoids /// computing and pushing a value and then testing it, instead performing /// comparisons directly on arguments, or even statically. This implementation /// is a general version in terms of CompileToDoubleProper. Should be overridden /// in CGNumberConst, CGTextConst, CGError, CGIf, CGComparison, ... /// </summary> /// <param name="ifTrue">Generates code for the true branch</param> /// <param name="ifFalse">Generates code for the false branch</param> /// <param name="ifOther">Generates code for the other (neither true nor /// false) branch</param> public virtual void CompileCondition(Gen ifTrue, Gen ifFalse, Gen ifOther) { CompileToDoubleProper( new Gen(delegate { ilg.Emit(OpCodes.Ldc_R8, 0.0); ilg.Emit(OpCodes.Beq, ifFalse.GetLabel(ilg)); ifTrue.Generate(ilg); if (!ifFalse.Generated) { Label endLabel = ilg.DefineLabel(); ilg.Emit(OpCodes.Br, endLabel); ifFalse.Generate(ilg); ilg.MarkLabel(endLabel); } }), ifOther); }
// This override combines the ordering predicate and the conditional jump public override void CompileCondition(Gen ifTrue, Gen ifFalse, Gen ifOther) { es[0].CompileToDoubleProper( new Gen(delegate { es[1].CompileToDoubleProper( new Gen(delegate { GenDoubleFalseJump(ifFalse.GetLabel(ilg)); ifTrue.Generate(ilg); if (!ifFalse.Generated) { Label endLabel = ilg.DefineLabel(); ilg.Emit(OpCodes.Br, endLabel); ifFalse.Generate(ilg); ilg.MarkLabel(endLabel); } }), new Gen(delegate { ilg.Emit(OpCodes.Pop); ifOther.Generate(ilg); })); }), ifOther); }