Example #1
0
		public override void CompileToDoubleProper(Gen ifProper, Gen ifOther) {
			if (IsCacheNeeded) {
				// Call CompileToDoubleOrNan via base class CompileToDoubleProper
				base.CompileToDoubleProper(ifProper, ifOther);
			}
			else {
				expr.CompileToDoubleProper(ifProper, ifOther);
			}
		}
Example #2
0
		// Special case for the argumentless and always-proper 
		// functions RAND and NOW, often used in conditions
		public override void CompileToDoubleProper(Gen ifProper, Gen ifOther) {
			if (es.Length == 0 && (functionInfo.name == "RAND" || functionInfo.name == "NOW")) {
				ilg.Emit(OpCodes.Call, functionInfo.methodInfo);
				ifProper.Generate(ilg);
			}
			else {
				base.CompileToDoubleProper(ifProper, ifOther);
			}
		}
Example #3
0
		public override void CompileCondition(Gen ifTrue, Gen ifFalse, Gen ifOther) {
			if (IsCacheNeeded) {
				// Call CompileToDoubleProper via base class CompileCondition
				base.CompileCondition(ifTrue, ifFalse, ifOther);
			}
			else {
				expr.CompileCondition(ifTrue, ifFalse, ifOther);
			}
		}
Example #4
0
		public override void CompileCondition(Gen ifTrue, Gen ifFalse, Gen ifOther) {
			for (int i = es.Length - 1; i >= 0; i--) {
				// These declarations are needed to capture rvalues rather than lvalues:
				CGExpr ei = es[i];
				Gen localIfFalse = ifFalse;
				ifFalse = new Gen(delegate { ei.CompileCondition(ifTrue, localIfFalse, ifOther); });
			}
			ifFalse.Generate(ilg);
		}
Example #5
0
		public override void CompileToDoubleProper(Gen ifProper, Gen ifOther) {
			if (double.IsInfinity(number.value) || double.IsNaN(number.value)) {
				ilg.Emit(OpCodes.Ldc_R8, number.value);
				ilg.Emit(OpCodes.Stloc, testDouble);
				ifOther.Generate(ilg);
			}
			else {
				ilg.Emit(OpCodes.Ldc_R8, number.value);
				ifProper.Generate(ilg);
			}
		}
Example #6
0
		// This handles compilation of IF(IF(e00,e01,e02), e1, e2) and such
		public override void CompileCondition(Gen ifTrue, Gen ifFalse, Gen ifOther) {
			if (es.Length != 3) {
				SetArgCountErrorNan();
				ifOther.Generate(ilg);
			}
			else {
				es[0].CompileCondition(
									   new Gen(delegate { es[1].CompileCondition(ifTrue, ifFalse, ifOther); }),
									   new Gen(delegate { es[2].CompileCondition(ifTrue, ifFalse, ifOther); }),
									   ifOther);
			}
		}
Example #7
0
		public override void CompileToDoubleProper(Gen ifProper, Gen ifOther) {
			CompileCondition(
							 new Gen(delegate {
										 ilg.Emit(OpCodes.Ldc_R8, 1.0);
										 ifProper.Generate(ilg);
									 }),
							 new Gen(delegate {
										 ilg.Emit(OpCodes.Ldc_R8, 0.0);
										 ifProper.Generate(ilg);
									 }),
							 ifOther);
		}
Example #8
0
		public override void CompileCondition(Gen ifTrue, Gen ifFalse, Gen ifOther) {
			if (Double.IsInfinity(number.value) || Double.IsNaN(number.value)) {
				ilg.Emit(OpCodes.Ldc_R8, number.value);
				ilg.Emit(OpCodes.Stloc, testDouble);
				ifOther.Generate(ilg);
			}
			else if (number.value != 0) {
				ifTrue.Generate(ilg);
			}
			else {
				ifFalse.Generate(ilg);
			}
		}
Example #9
0
		public override void CompileToDoubleProper(Gen ifProper, Gen ifOther) {
			if (es.Length != Arity) {
				SetArgCountErrorNan();
				ifOther.Generate(ilg);
			}
			else {
				es[0].CompileToDoubleProper(
										    new Gen(delegate {
														ilg.Emit(OpCodes.Neg);
														ifProper.Generate(ilg);
													}),
											ifOther);
			}
		}
Example #10
0
		// A comparison evaluates to a proper double only if both operands do
		public override void CompileToDoubleProper(Gen ifProper, Gen ifOther) {
			es[0].CompileToDoubleProper(
									    new Gen(delegate {
													es[1].CompileToDoubleProper(
																			    new Gen(delegate {
																							GenCompareDouble();
																							ilg.Emit(OpCodes.Conv_R8);
																							ifProper.Generate(ilg);
																						}),
																				new Gen(delegate {
																							ilg.Emit(OpCodes.Pop);
																							ifOther.Generate(ilg);
																						}));
												}),
										ifOther);
		}
Example #11
0
		// 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);
			}
		}
Example #12
0
		// 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);
		}
Example #13
0
		public override void CompileToDoubleOrNan() {
			Gen success =
				new Gen(delegate {
							ilg.Emit(OpCodes.Call, functionInfo.methodInfo);
							if (functionInfo.signature.retType != Typ.Number) {
								UnwrapToDoubleOrNan();
							}
						});
			if (Arity < 0) { // Variable arity 
				CompileToValueArray(es.Length, 0, es);
				success.Generate(ilg);
			}
			else if (es.Length != Arity) {
				LoadErrorNan(ErrorValue.argCountError);
			}
			else {
				// TODO: ifOther should probably load error from testValue instead?
				Gen ifOther = GenLoadErrorNan(ErrorValue.argTypeError);
				CompileArgumentsAndApply(es, success, ifOther);
			}
		}
Example #14
0
		// 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);
		}
Example #15
0
		// 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);
		}
Example #16
0
		/// <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);
			}
		}
Example #17
0
		public override void CompileToDoubleProper(Gen ifProper, Gen ifOther) { ifOther.Generate(ilg); }
Example #18
0
		// In Excel, a text used in a conditional produces the error #VALUE! -- mostly
		public override void CompileCondition(Gen ifTrue, Gen ifFalse, Gen ifOther) { ifOther.Generate(ilg); }
Example #19
0
		protected void UnwrapToString(Gen ifString, Gen ifError) {
			CheckType(TextValue.type,
					  new Gen(delegate {
								  ilg.Emit(OpCodes.Ldfld, TextValue.valueField);
								  ifString.Generate(ilg);
							  }),
					  ifError);
		}
Example #20
0
		public override void CompileToDoubleOrNan() {
			if (ef == null) {
				ilg.Emit(OpCodes.Ldc_R8, errorValue.ErrorNan);
			}
			else {
				// sestoft: This is maybe correct
				Gen ifOther = GenLoadErrorNan(ErrorValue.argTypeError);
				if (ef.ResType == typeof (System.Double)) {
					// If argument evaluation is successful, call external function 
					// and continue with ifDouble; otherwise continue with ifOther
					Gen success = new Gen(delegate { ef.EmitCall(ilg); });
					CompileArgumentsAndApply(es, success, ifOther);
				}
				else if (numeric.Contains(ef.ResType)) {
					// If argument evaluation is successful, call external function, convert 
					// to float64
					Gen success =
						new Gen(delegate {
									ef.EmitCall(ilg);
									ilg.Emit(OpCodes.Conv_R8);
								});
					CompileArgumentsAndApply(es, success, ifOther);
				}
				else // Result type cannot be converted to a float64
				{
					ifOther.Generate(ilg);
				}
			}
		}
Example #21
0
		public override void CompileCondition(Gen ifTrue, Gen ifFalse, Gen ifOther) { es[0].CompileCondition(ifFalse, ifTrue, ifOther); }
Example #22
0
		public override void Compile() {
			if (ef == null) {
				LoadErrorValue(errorValue);
			}
			else {
				// If argument evaluation is successful, call the external function 
				// and convert its result to Value; if unsuccessful, return ArgTypeError
				Gen success;
				// First some return type special cases, avoid boxing:
				if (ef.ResType == typeof (System.Double)) {
					success = new Gen(delegate {
										  ef.EmitCall(ilg);
										  ilg.Emit(OpCodes.Call, NumberValue.makeMethod);
									  });
				}
				else if (numeric.Contains(ef.ResType)) {
					success = new Gen(delegate {
										  ef.EmitCall(ilg);
										  ilg.Emit(OpCodes.Conv_R8);
										  ilg.Emit(OpCodes.Call, NumberValue.makeMethod);
									  });
				}
				else if (ef.ResType == typeof (char)) {
					success = new Gen(delegate {
										  ef.EmitCall(ilg);
										  ilg.Emit(OpCodes.Call, TextValue.fromNakedCharMethod);
									  });
				}
				else if (ef.ResType == typeof (void)) {
					success = new Gen(delegate {
										  ef.EmitCall(ilg);
										  ilg.Emit(OpCodes.Ldsfld, TextValue.voidField);
									  });
				}
				else {
					success = new Gen(delegate {
										  ef.EmitCall(ilg);
										  if (ef.ResType.IsValueType) {
											  ilg.Emit(OpCodes.Box, ef.ResType);
										  }
										  ilg.Emit(OpCodes.Call, ef.ResConverter.Method);
									  });
				}
				Gen ifOther = GenLoadErrorValue(ErrorValue.argTypeError);
				CompileArgumentsAndApply(es, success, ifOther);
			}
		}
Example #23
0
		/// <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);
		}