protected override LExpression GetExpressionTreeIfPossible(LExpression contextExpression, LExpression evalContext) { AST node = getFirstChild(); var conditionExpression = GetExpressionTreeIfPossible((BaseNode)node, contextExpression, evalContext); if (conditionExpression == null) { return(null); } node = node.getNextSibling(); var trueExpression = GetExpressionTreeIfPossible((BaseNode)node, contextExpression, evalContext); if (trueExpression == null) { return(null); } node = node.getNextSibling(); var falseExpression = GetExpressionTreeIfPossible((BaseNode)node, contextExpression, evalContext); if (falseExpression == null) { return(null); } return(LExpression.Condition(conditionExpression, trueExpression, falseExpression)); }
/// <summary>Helper to produce the rule for converting T to Nullable of T</summary> private static MSAst MakeConvertingToTToNullableOfTTarget(Type toType, ConversionResultKind kind, MSAst arg) { var valueType = toType.GetGenericArguments()[0]; // ConvertSelfToT -> Nullable<T> if (kind == ConversionResultKind.ExplicitCast) { // if the conversion to T fails we just throw var conversion = ConvertExpression(arg, valueType); return(MSAst.New( toType.GetConstructor(new[] { valueType }), conversion)); } else { var conversion = ConvertExpression(arg, valueType); // if the conversion to T succeeds then produce the nullable<T>, otherwise return default(retType) return(MSAst.Condition( MSAst.NotEqual( conversion, AstUtils.Constant(null)), MSAst.New( toType.GetConstructor(new[] { valueType }), MSAst.Convert( conversion, valueType)), GetTryConvertReturnValue(toType))); } }
/// <summary> /// Periodize a value, /// "bouncing off" the endpoint instead of wrapping around. /// </summary> /// <example> /// <c> /// FSoftMod(X(), 4)(3.95) = 3.95 /// FSoftMod(X(), 4)(4.05) = 3.95 /// FSoftMod(X(), 4)(4.15) = 3.85 /// </c> /// </example> /// <param name="by">Period</param> /// <param name="x">Value</param> /// <returns></returns> public static tfloat SoftMod(efloat by, efloat x) => EEx.Resolve(by, _by => { var vd = VFloat(); return(Ex.Block(new[] { vd }, vd.Is(Mod(E2.Mul(_by), x)), Ex.Condition(vd.LT(_by), vd, E2.Mul(_by).Sub(vd)) )); });
/// <summary> /// Use this to draw "wings" where both go in opposite directions. /// <br/>Odd by: 0 is the center, [1,by/2-0.5] are one wing, and [by/2+0.5,by) are the other. /// <br/>Even by: [0, by/2) are one wing, [by/2, by) are the other. /// </summary> /// <example> /// <c> /// HNMod(X(), 9)(0) = HNMod(X(), 9)(9) = 0 /// HNMod(X(), 9)(1) = 1 /// HNMod(X(), 9)(5) = -1 /// HNMod(X(), 9)(8) = -4 /// HNMod(X(), 8)(0) = HNMod(X(), 8)(8) = 0.5 /// HNMod(X(), 8)(3) = 3.5 /// HNMod(X(), 8)(4) = -0.5 /// </c> /// </example> /// <param name="by">Period</param> /// <param name="x">Target function</param> /// <returns></returns> public static tfloat HNMod(tfloat by, tfloat x) => EEx.Resolve <float>(by.Div(E2), h => { var y = VFloat(); return(Ex.Block(new[] { y }, y.Is(Mod(h.Mul(E2), x)), Ex.Condition(y.LT(h), y.Add(Floor(h)).Add(E05).Sub(h), h.Sub(E05).Sub(y)) )); });
public override MSAst TransformCore(ScriptGenerator generator) { return(MSAst.Condition( Test.Transform(generator), IfTrue.Transform(generator), IfFalse.Transform(generator))); }
/// <summary> /// Samples an invokee exactly once. /// </summary> /// <param name="p">Target function</param> /// <returns></returns> public static Func <TExArgCtx, TEx <T> > SS0 <T>(Func <TExArgCtx, TEx <T> > p) => bpi => { var key = bpi.Ctx.NameWithSuffix("_SampleIfKey"); return(Ex.Condition(Ex.Not(bpi.FCtxHas <T>(key)), bpi.FCtxSet <T>(key, p(bpi)), bpi.FCtxGet <T>(key) )); };
/// <summary> /// Normalize a vector. /// </summary> public static tv3 Norm3(ev3 v3) => EEx.ResolveV3(v3, xyz => { var mag = VFloat(); return(Ex.Block(new[] { mag }, mag.Is(v3Mag(xyz)), Ex.Condition(mag.GT(ExC(M.MAG_ERR)), xyz.Mul(E1.Div(mag)), xyz ) )); });
/// <summary> /// Normalize a vector. /// </summary> public static tv2 Norm(ev2 v2) => EEx.ResolveV2(v2, xy => { var mag = VFloat(); return(Ex.Block(new[] { mag }, mag.Is(Mag(xy)), Ex.Condition(mag.GT(ExC(M.MAG_ERR)), xy.Mul(E1.Div(mag)), xy ) )); });
private static tfloat _ModWithPause(tfloat by, tfloat pauseAt, tfloat pauseLen, tfloat x) { var val = VFloat(); return(Ex.Block(new[] { val }, val.Is(Mod(pauseLen.Add(by), x)), Ex.Condition(val.LT(pauseAt), val, Ex.Condition(ExUtils.SubAssign(val, pauseLen).LT(pauseAt), pauseAt, val)) )); }
/// <summary> /// Nest a predicate such that it only returns True once for a single bullet. /// </summary> /// <param name="pred"></param> /// <returns></returns> public static ExPred OnlyOnce(ExPred pred) => bpi => { var b = V <bool>(); var key = bpi.Ctx.NameWithSuffix("_OnlyOnce_Set"); return(Ex.Condition(FiringCtx.Contains <int>(bpi, key), ExC(false), Ex.Block(new[] { b }, Ex.IfThen(b.Is(pred(bpi)), FiringCtx.SetValue <int>(bpi, key, ExC(1))), b ) )); };
/// <summary>Generates a method similar to this: /// <code> /// void Write(IO.BitStream s, TEnum v, int bitCount) /// { /// s.Write((TStreamType)v, bitCount); /// } /// </code> /// </summary> /// <returns>The generated method.</returns> /// <param name="args"></param> /// <param name="writeMethodInfo"></param> /// <param name="bitSwapMethod"></param> /// <remarks> /// If <see cref="args.UnderlyingType"/> is the same as <typeparamref name="TStreamType"/>, no conversion code is generated /// </remarks> static Action <IO.BitStream, TEnum, int> GenerateWriteMethod(MethodGenerationArgs args, MethodInfo writeMethodInfo, MethodInfo bitSwapMethod) { ////////////////////////////////////////////////////////////////////////// // Define the generated method's parameters var param_s = Expr.Parameter(kBitStreamType, "s"); // BitStream s var param_v = Expr.Parameter(args.EnumType, "v"); // TEnum v var param_bc = Expr.Parameter(typeof(int), "bitCount"); // int bitCount ////////////////////////////////////////////////////////////////////////// // Define the member access var param_v_member = Expr.PropertyOrField(param_v, EnumUtils.kMemberName); // i.e., 'v.value__' var write_param = args.UnderlyingTypeNeedsConversion ? // If the underlying type is different from the type we're writing, Expr.Convert(param_v_member, args.StreamType) : // we need to cast the Write param from UnderlyingType to TStreamType (Expr)param_v_member; if (args.Options.UseNoneSentinelEncoding) { write_param = Expr.Increment(write_param); } #region options.BitSwap if (args.Options.BitSwap) { // i.e., Bits.BitSwap( value, bitCount-1 ); var start_bit_index = Expr.Decrement(param_bc); Expr swap_call = Expr.Call(null, bitSwapMethod, write_param, start_bit_index); // i.e., bitCount-1 ? Bits.BitSwap( value, bitCount-1 ) : value ; if (args.Options.BitSwapGuardAgainstOneBit) { var start_bit_index_is_not_zero = Expr.NotEqual(start_bit_index, Expr.Constant(0, typeof(int))); swap_call = Expr.Condition(start_bit_index_is_not_zero, swap_call, write_param); } write_param = swap_call; } #endregion ////////////////////////////////////////////////////////////////////////// // Define the Write call // i.e., 's.Write(v.value__, bitCount)' or 's.Write((TStreamType)v.value__, bitCount)' var call_write = Expr.Call(param_s, writeMethodInfo, write_param, param_bc); ////////////////////////////////////////////////////////////////////////// // Generate a method based on the expression tree we've built var lambda = Expr.Lambda <Action <IO.BitStream, TEnum, int> >(call_write, param_s, param_v, param_bc); return(lambda.Compile()); }
public static Expr ConvertToNumberAndCheck(Context context, Expr expression, string format, params object[] args) { var numberVar = Expr.Variable(typeof(double)); var assignNumber = Expr.Assign(numberVar, ConvertToNumber(context, expression)); return(Expr.Block( new[] { numberVar }, assignNumber, Expr.Condition( Expr.Invoke( Expr.Constant((Func <double, bool>)Double.IsNaN), numberVar), Expr.Block( Expr.Throw(Expr.New(MemberInfos.NewRuntimeException, Expr.Constant(format), Expr.Constant(args))), Expr.Constant(Double.NaN)), numberVar))); }
public IFunction ToInput(LExpression parameter, ICLRBoundaryMap rootTypeMap, CompilationContext context) { var arg = parameter; if (arg.Type != typeof(float)) { if (arg.Type == typeof(bool)) { arg = LExpression.Condition(arg, LExpression.Constant(1f), LExpression.Constant(0f)); } else { arg = LExpression.Convert(arg, typeof(float)); } } return(new SingleInputExpr(arg)); }
public override DynamicMetaObject BindGetIndex(GetIndexBinder binder, DynamicMetaObject[] indexes) { var valueVar = Expr.Variable(typeof(object)); var getValue = Expr.Call( Expr.Convert(Expression, typeof(LuaTable)), MemberInfos.LuaTableGetValue, Expr.Convert(indexes[0].Expression, typeof(object))); var valueAssign = Expr.Assign(valueVar, getValue); var expression = Expr.Block( valueVar, Expr.Condition( Expr.Equal(valueVar, Expr.Constant(null)), MetamethodFallbacks.Index(null, this, indexes), valueVar)); return(new DynamicMetaObject(expression, RuntimeHelpers.MergeTypeRestrictions(this))); }
public override DynamicMetaObject BindSetIndex(SetIndexBinder binder, DynamicMetaObject[] indexes, DynamicMetaObject value) { var getValue = Expr.Call( Expr.Convert(Expression, typeof(LuaTable)), MemberInfos.LuaTableGetValue, Expr.Convert(indexes[0].Expression, typeof(object))); var setValue = Expr.Call( Expr.Convert(Expression, typeof(LuaTable)), MemberInfos.LuaTableSetValue, Expr.Convert(indexes[0].Expression, typeof(object)), Expr.Convert(value.Expression, typeof(object))); var expression = Expr.Condition( Expr.Equal(getValue, Expr.Constant(null)), MetamethodFallbacks.NewIndex(null, this, indexes, value), setValue); return(new DynamicMetaObject(expression, RuntimeHelpers.MergeTypeRestrictions(this))); }
Expr FallbackIfNumberIsNan(Expr conversionResult, DynamicMetaObject left, DynamicMetaObject right) { // If we have performed a string to number conversion check that conversion went well by checking // number for NaN. If conversion failed do metatable fallback. Also assign to temp variable for single evaluation. var conversionVar = Expr.Variable(typeof(double)); var expr = Expr.Condition( Expr.Invoke(Expr.Constant((Func <double, bool>)Double.IsNaN), conversionVar), Expr.Invoke( Expr.Constant((Func <Context, ExprType, object, object, object>)LuaOps.NumericMetamethod), Expr.Constant(context), Expr.Constant(Operation), Expr.Convert(left.Expression, typeof(object)), Expr.Convert(right.Expression, typeof(object))), Expr.Convert(conversionVar, typeof(object))); return(Expr.Block( new[] { conversionVar }, Expr.Assign(conversionVar, conversionResult), expr)); }
/// <summary> /// Of two numbers, return the one with the larger absolute value. /// Not well-defined when x1 = -x2. /// </summary> public static tfloat MaxA(efloat x1, efloat x2) => EEx.Resolve(x1, x2, (a, b) => Ex.Condition(Abs(a).GT(Abs(b)), a, b));
/// <summary> /// If the switcher is 1, return the result, otherwise the default value. /// </summary> public static TEx <T> If1 <T>(tfloat switcher, TEx <T> result) => Ex.Condition(Ex.Equal(switcher, E1), result, Ex.Default(typeof(T)));
/// <summary> /// If the predicate is true, return the true branch, otherwise the false branch. /// </summary> public static TEx <T> If <T>(tbool pred, TEx <T> iftrue, TEx <T> iffalse) => Ex.Condition(pred, iftrue, iffalse);
static Expr GenerateModifyFlagsGuts(ExprParam paramV, ExprParam paramF, ExprParam paramCond) { return(Expr.Condition(paramCond, GenerateAddFlagsGuts(paramV, paramF), GenerateRemoveFlagsGuts(paramV, paramF))); }
/// <summary> /// Return either -1 or 1 based on the parametric ID. /// </summary> /// <returns></returns> public static ExBPY BRandpm1() => bpi => Ex.Condition(bpi.id.GT(ExC(uint.MaxValue / (uint)2)), EN1, E1);
/// <summary> /// Returns -1 if x lt 0 and 1 otherwise. (Note: Sign(0) = 1) /// </summary> public static tfloat Sign(efloat x) => EEx.Resolve(x, y => Ex.Condition(y.LT0(), EN1, E1));
/// <summary>Generates a method similar to this: /// <code> /// void Read(IO.BitStream s, out TEnum v, int bitCount) /// { /// v = (UnderlyingType)s.Read[TStreamType](bitCount); /// } /// </code> /// </summary> /// <param name="args"></param> /// <param name="readMethodInfo"></param> /// <param name="bitSwapMethod"></param> /// <returns>The generated method.</returns> /// <remarks> /// If <see cref="args.UnderlyingType"/> is the same as <typeparamref name="TStreamType"/>, no conversion code is generated /// </remarks> static ReadDelegate GenerateReadMethod(MethodGenerationArgs args, MethodInfo readMethodInfo, MethodInfo bitSwapMethod) { // Get a "ref type" of the enum we're dealing with so we can define the enum value as an 'out' parameter var enum_ref = args.EnumType.MakeByRefType(); ////////////////////////////////////////////////////////////////////////// // Define the generated method's parameters var param_s = Expr.Parameter(kBitStreamType, "s"); // BitStream s var param_v = Expr.Parameter(enum_ref, "v"); // ref TEnum v var param_bc = Expr.Parameter(typeof(int), "bitCount"); // int bitCount ////////////////////////////////////////////////////////////////////////// // Define the Read call Expr call_read; if (args.StreamTypeIsSigned) { call_read = Expr.Call(param_s, readMethodInfo, param_bc, Expr.Constant(args.Options.SignExtend)); } else { call_read = Expr.Call(param_s, readMethodInfo, param_bc); // i.e., 's.Read<Type>(bitCount)' } if (args.Options.UseNoneSentinelEncoding) { call_read = Expr.Decrement(call_read); } #region options.BitSwap if (args.Options.BitSwap) { // i.e., Bits.BitSwap( Read(), bitCount-1 ); var start_bit_index = Expr.Decrement(param_bc); Expr swap_call = Expr.Call(null, bitSwapMethod, call_read, start_bit_index); // i.e., bitCount-1 ? Bits.BitSwap( Read(), bitCount-1 ) : Read() ; if (args.Options.BitSwapGuardAgainstOneBit) { var start_bit_index_is_not_zero = Expr.NotEqual(start_bit_index, Expr.Constant(0, typeof(int))); swap_call = Expr.Condition(start_bit_index_is_not_zero, swap_call, call_read); } call_read = swap_call; } #endregion var read_result = args.UnderlyingTypeNeedsConversion ? // If the underlying type is different from the type we're reading, Expr.Convert(call_read, args.UnderlyingType) : // we need to cast the Read result from TStreamType to UnderlyingType (Expr)call_read; ////////////////////////////////////////////////////////////////////////// // Define the member assignment var param_v_member = Expr.PropertyOrField(param_v, EnumUtils.kMemberName); // i.e., 'v.value__' // i.e., 'v.value__ = s.Read<Type>()' or 'v.value__ = (UnderlyingType)s.Read<Type>()' var assign = Expr.Assign(param_v_member, read_result); ////////////////////////////////////////////////////////////////////////// // Generate a method based on the expression tree we've built var lambda = Expr.Lambda <ReadDelegate>(assign, param_s, param_v, param_bc); return(lambda.Compile()); }
/// <summary> /// Move a value in the range [-540, 540] to the range [-180, 180] by adding or subtracting 360. /// </summary> /// <param name="ang_rad"></param> /// <returns></returns> public static tfloat DegIntoRange(efloat ang_rad) => EEx.Resolve(ang_rad, a => Ex.Condition(a.GT(ExC(180f)), a.Sub(ExC(360f)), Ex.Condition(a.LT(ExC(-180f)), a.Add(ExC(360f)), a)));
public static tfloat NPow(efloat bas, efloat exp) => EEx.Resolve(bas, exp, (x, y) => Ex.Condition(Ex.LessThan(x, E0), Ex.Negate(Pow(Ex.Negate(x), y)), Pow(x, y)));
/// <summary> /// Move a value in the range [-2pi, 2pi] to the range [0,2pi] by adding tau. /// </summary> /// <param name="ang_rad"></param> /// <returns></returns> public static tfloat RadToPos(efloat ang_rad) => EEx.Resolve(ang_rad, a => Ex.Condition(a.LT0(), a.Add(tau), a));
/// <summary> /// Move a value in the range [-2pi, 2pi] to the range [-2pi, 0] by subtracting tau. /// </summary> /// <param name="ang_rad"></param> /// <returns></returns> public static tfloat RadToNeg(efloat ang_rad) => EEx.Resolve(ang_rad, a => Ex.Condition(a.GT0(), a.Sub(tau), a));
/// <summary> /// Move a value in the range [-3pi, 3pi] to the range [-pi, pi] by adding or subtracting tau. /// </summary> /// <param name="ang_rad"></param> /// <returns></returns> public static tfloat RadIntoRange(efloat ang_rad) => EEx.Resolve(ang_rad, a => Ex.Condition(a.GT(pi), a.Sub(tau), Ex.Condition(a.LT(npi), a.Add(tau), a)));
/// <summary> /// If x's absolute value is greater than by, then return 0 instead. /// </summary> public static tfloat HighCut(tfloat by, efloat x) => EEx.Resolve(x, _x => Ex.Condition(Abs(_x).GT(by), E0, _x));
/// <summary> /// Limit a value x to have absolute value leq by. /// </summary> /// <param name="by">Positive number for absolute value comparison</param> /// <param name="x">Number to be limited</param> /// <returns></returns> public static tfloat Limit(efloat by, efloat x) => EEx.Resolve(by, x, (_by, _x) => Ex.Condition(_x.GT0(), Min(_x, _by), Max(_x, Ex.Negate(_by))));