static Expression GetArgument(Expression Expression, int n) { if (Expression.Type == typeof(LuaArguments)) return Expression.Property(Expression, "Item", Expression.Constant(n)); else return Expression.ArrayAccess(Expression, Expression.Constant(n)); }
static GlyphRunFormatter() { var refType = typeof(CharacterBufferReference); _textFormattingMode = typeof(GlyphRun).GetField("_textFormattingMode", BindingFlags.NonPublic | BindingFlags.Instance); { var property = refType.GetProperty("CharacterBuffer", BindingFlags.NonPublic | BindingFlags.Instance); var param0 = Expr.Parameter(refType); var expr = Expr.Convert(Expr.Property(param0, property), typeof(IList <char>)); var lambda = Expr.Lambda <Func <CharacterBufferReference, IList <char> > >(expr, param0); getCharBuf = lambda.Compile(); } { var property = refType.GetProperty("OffsetToFirstChar", BindingFlags.NonPublic | BindingFlags.Instance); var param0 = Expr.Parameter(refType); var expr = Expr.Property(param0, property); var lambda = Expr.Lambda <Func <CharacterBufferReference, int> >(expr, param0); getCharOffset = lambda.Compile(); } { var ctor = typeof(TextBounds).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0]; var param0 = Expr.Parameter(typeof(Rect)); var expr = Expr.New(ctor, param0, Expr.Constant(FlowDirection.LeftToRight), Expr.Constant(null, typeof(IList <TextRunBounds>))); var lambda = Expr.Lambda <Func <Rect, TextBounds> >(expr, param0); makeBounds = lambda.Compile(); } }
public void BinaryExpression_OrAssign() => UnsupportedBinaryExpr(Property.Id, id => Expr.OrAssign(id, Expr.Constant(3)), ExpressionType.OrAssign);
private static LinqExpression Compile(ElementExpression value, CompilationData data) { data.Cache ??= new Dictionary <CachedExpression, ParameterExpression>(); data.GroupCache ??= new Dictionary <ExpressionGroup, LinqExpression[]>(); switch (value) { case ICLRExpression s: return(s.Compile(e => Compile(e, data))); case Constant c: return(LinqExpression.Constant(c.Value)); case Binary b: var ea = Compile(b.OpA, data); var eb = Compile(b.OpB, data); if (b.Operation == Binary.Op.Pow) { var o = LinqExpression.Call(typeof(Math).GetMethod(nameof(Math.Pow)), LinqExpression.Convert(ea, typeof(double)), LinqExpression.Convert(eb, typeof(double))); return(LinqExpression.Convert(o, typeof(float))); } if (b.Operation == Binary.Op.Atan2) { var o = LinqExpression.Call(typeof(Math).GetMethod(nameof(Math.Atan2)), LinqExpression.Convert(ea, typeof(double)), LinqExpression.Convert(eb, typeof(double))); return(LinqExpression.Convert(o, typeof(float))); } return(BinaryOps[b.Operation](ea, eb)); case Unary u: var input = Compile(u.Operand, data); var output = LinqExpression.Call(MethodOps[u.Operation], LinqExpression.Convert(input, typeof(double))); return(LinqExpression.Convert(output, typeof(float))); case CachedExpression v: if (!data.Cache.TryGetValue(v, out var varExpr)) { var result = Compile(v.Value, data); data.Cache.Add(v, varExpr = LinqExpression.Parameter(result.Type)); data.Statements.Add(LinqExpression.Assign(varExpr, result)); data.Variables.Add(varExpr); } return(varExpr); case Mux m: if (m.Operands.Count == 2) { return(LinqExpression.Condition( LinqExpression.LessThan(Compile(m.Selector, data), LinqExpression.Constant(1f)), Compile(m.Operands[0], data), Compile(m.Operands[1], data))); } var sel = LinqExpression.Convert(Compile(m.Selector, data), typeof(int)); var clampedSel = LinqExpression.Condition( LinqExpression.GreaterThanOrEqual(sel, LinqExpression.Constant(m.Operands.Count)), LinqExpression.Constant(m.Operands.Count - 1), sel); var cases = m.Operands.Select( (c, i) => LinqExpression.SwitchCase(Compile(c, data), LinqExpression.Constant(i))) .ToArray(); return(LinqExpression.Switch(clampedSel, cases[0].Body, cases)); case State s: if (data.ResolveState == null) { throw new Exception("Tried to compile a State expression outside of an ExpressionGroup"); } return(data.ResolveState(s)); case ExpressionGroupElement groupElement: if (!data.GroupCache.TryGetValue(groupElement.Group, out var groupList)) { data.GroupCache.Add(groupElement.Group, groupList = CompileGroup(groupElement.Group, data)); } return(groupList[groupElement.Index]); } throw new Exception("Unknown expression " + value); }
private static LinqExpression[] CompileGroup(ExpressionGroup group, CompilationData data) { switch (group) { case Persist p: foreach (var s in p.State) { if (!(s.InitialValue is Constant)) { throw new Exception("Persist initial value is not constant"); } data.StateValues.Add(((Constant)s.InitialValue).Value); } var assigns = new List <LinqExpression>(); // TODO: Resolve parent scopes data.ResolveState = s => LinqExpression.ArrayAccess(data.StateArray, LinqExpression.Constant(s.Id)); for (var i = 0; i < p.NewValue.Count; i++) { var newValueExpr = Compile(p.NewValue[i], data); assigns.Add(LinqExpression.Assign( LinqExpression.ArrayAccess(data.StateArray, LinqExpression.Constant(i)), newValueExpr)); } data.Statements.AddRange(assigns); return(Enumerable.Range(0, p.Size) .Select(i => LinqExpression.ArrayAccess(data.StateArray, LinqExpression.Constant(i))) .ToArray()); case Loop l: var stateList = new List <ParameterExpression>(); foreach (var s in l.State) { var initial = Compile(s.InitialValue, data); var variable = LinqExpression.Variable(initial.Type); data.Statements.Add(LinqExpression.Assign(variable, initial)); data.Variables.Add(variable); stateList.Add(variable); } // TODO: Resolve parent scopes data.ResolveState = s => stateList[s.Id]; var parentStatements = data.Statements; // Make a new cache that copies in the old one, but won't leak State expressions data.Cache = new Dictionary <CachedExpression, ParameterExpression>(data.Cache); // Create a new statements list to put in the loop body var s1 = data.Statements = new List <LinqExpression>(); var condition = Compile(l.Condition, data); var s2 = data.Statements = new List <LinqExpression>(); var newState = l.Body.Select(e => Compile(e, data)).ToArray(); // Ensure that the entire state is only set at the end of the loop for (var i = 0; i < newState.Length; i++) { var s = newState[i]; if (!(s is ParameterExpression)) { var tmpVar = LinqExpression.Variable(s.Type); data.Variables.Add(tmpVar); s2.Add(LinqExpression.Assign(tmpVar, s)); newState[i] = tmpVar; } } var breakLabel = LinqExpression.Label(); var body = LinqExpression.Block(s1 .Concat(new[] { LinqExpression.IfThen( LinqExpression.LessThan(condition, LinqExpression.Constant(1f)), LinqExpression.Break(breakLabel)) }) .Concat(s2) .Concat(newState.Select((e, i) => LinqExpression.Assign(stateList[i], e)))); parentStatements.Add(LinqExpression.Loop(body, breakLabel)); return(stateList.ToArray()); default: throw new NotSupportedException(); } }
public LambdaExpression CreateLambda(Type from, Type to) { var input = Ex.Parameter(from, "input"); var eType = to.GetElementType(); var res = Ex.Parameter(typeof(ConversionResult <>).MakeGenericType(eType).MakeArrayType(), "res"); var end = Ex.Label(typeof(ConversionResult <>).MakeGenericType(to), "end"); var fromParameters = from.GetTypeInfo().GenericTypeArguments; var converters = fromParameters.Select(t => new { Lambda = Ref.GetLambda(t, eType), Input = t }).ToArray(); var block = Ex.Block(new[] { res }, Ex.Assign(res, Ex.NewArrayBounds(typeof(ConversionResult <>).MakeGenericType(eType), Ex.Constant(fromParameters.Length))), Ex.Block(converters.Select((con, i) => Ex.Block( Ex.Assign(Ex.ArrayAccess(res, Ex.Constant(i)), con.Lambda.ApplyTo(Ex.PropertyOrField(input, $"Item{i + 1}"))), Ex.IfThen(Ex.Not(Ex.Property(Ex.ArrayIndex(res, Ex.Constant(i)), nameof(IConversionResult.IsSuccessful))), Ex.Goto(end, NoResult(to)))))), Ex.Label(end, Result(to, Ex.NewArrayInit(eType, Enumerable.Range(0, fromParameters.Length) .Select(idx => Ex.Property(Ex.ArrayIndex(res, Ex.Constant(idx)), nameof(IConversionResult.Result))))))); var lambda = Ex.Lambda(block, input); return(lambda); }
public virtual Expr ToExpression() { var blockBody = new List <Expr>(); #if EXPERIMENTAL_GENERATOR var variables = new HashSet <ParameterExpression>(); #endif // AccessExpression is null on the root node (It's a dummy node) // ReadExpression.Count > 1 can only happen if we decided to roll a loop, in which case all elements are identical. // ReadExpression.Count = 0 can happen if the type is a value type. Otherwise this is new T[...] or new T(). if (AccessExpression != null) { if (ReadExpression.Count > 0) { blockBody.Add(Expr.Assign(AccessExpression, ReadExpression[0])); } else if (TypeToken.IsArray) { blockBody.Add(Expr.Assign(AccessExpression, TypeToken.GetElementTypeToken().NewArrayBounds(Expr.Constant(MemberToken.Cardinality)))); } else if (TypeToken.IsClass) { if (!TypeToken.HasDefaultConstructor) { throw new InvalidOperationException("Missing default constructor for " + TypeToken.Name); } blockBody.Add(Expr.Assign(AccessExpression, TypeToken.NewExpression())); } } if (Children.Count > 0) { // Produce children if there are any foreach (var child in Children) { var subExpression = child.ToExpression(); #if EXPERIMENTAL_GENERATOR if (subExpression is BlockExpression subBlockExpression) { blockBody.AddRange(subBlockExpression.Expressions); foreach (var subBlockVariable in subBlockExpression.Variables) { variables.Add(subBlockVariable); } } else { blockBody.Add(subExpression); } #else blockBody.Add(subExpression); #endif } // Assert that there is at least one node in the block emitted. if (blockBody.Count == 0) { throw new InvalidOperationException("Empty block"); } } // We allow empty blocks if there are no children for primitive types if (blockBody.Count == 0) { return(Expr.Empty()); } // If there's only one expression, just return it. #if EXPERIMENTAL_GENERATOR if (blockBody.Count == 1 && variables.Count == 0) { return(blockBody[0]); } return(Expression.Block(variables, blockBody)); #else if (blockBody.Count == 1) { return(blockBody[0]); } return(Expr.Block(blockBody)); #endif }
public override TreeNode TryUnroll() { if (!MustUnroll) { return(this); } // Reduce begins now var bodyExpression = new TreeNode() { TypeToken = Array.TypeToken.GetElementTypeToken(), MemberToken = Array.MemberToken, AccessExpression = Array.AccessExpression }; // Array initializer added now and only now bodyExpression.ReadExpression.Add(bodyExpression.TypeToken.NewArrayBounds(Expr.Constant(IterationCount - InitialValue))); // Create N blocks of body for (var i = 0; i < IterationCount - InitialValue; ++i) { var invocationNode = new TreeNode() { // Can't reuse this.AccessExpression because it's bound on the iterator. AccessExpression = Expr.ArrayAccess(Array.AccessExpression, Expr.Constant(i)), MemberToken = Array.MemberToken, TypeToken = Array.TypeToken.GetElementTypeToken() }; // Insert ctor if class if (invocationNode.TypeToken.IsClass) { invocationNode.ReadExpression.Add(invocationNode.TypeToken.NewExpression()); } // Insert all children foreach (var childNode in Children) { var newChildNode = new TreeNode() { AccessExpression = Expr.MakeMemberAccess(invocationNode.AccessExpression, childNode.MemberToken.MemberInfo), MemberToken = childNode.MemberToken, TypeToken = childNode.TypeToken }; // Now that we created a new block we must try to unroll it if it needs to foreach (var subChildNode in childNode.Children) { newChildNode.AddChild(subChildNode.TryUnroll()); } // If deserialization calls were found select the one corresponding to the currently unrolling iteration. if (childNode.ReadExpression.Count > 0) { newChildNode.ReadExpression.Add(childNode.ReadExpression[i]); } invocationNode.AddChild(newChildNode); } bodyExpression.AddChild(invocationNode); } return(bodyExpression); }