public Delegate Generate(RootNode root) { var ctx = new DeserializerTypeContext { Type = root.Type }; InitializeVars(ctx); var @switch = GetSwitchStatement(ctx, root.Children); ctx.BlockInsideLoop = GetInnerLoopTemplate(ctx, @switch); var lambda = GetTemplate(ctx); var del = CompileExpression(root.Type, lambda); _treeBuilder.AddKnownType(root.Type, del); return del; }
private SwitchCase ProcessNode(DeserializerTypeContext ctx, IntCollectionNode node) { return ProcessCollectionNode(ctx, node, _extractIntCollection); }
private SwitchCase ProcessNode(DeserializerTypeContext ctx, DoubleNode node) { var bodyExpressions = new List<Expression>(); var callExtractInt = Expression.Call(null, _extractDouble, ctx.IteratorVar, ctx.StringParam); var accessMember = Expression.MakeMemberAccess(ctx.InstanceVar, node.Member); var assignMember = Expression.Assign(accessMember, callExtractInt); bodyExpressions.Add(assignMember); bodyExpressions.Add(Expression.Empty()); var body = Expression.Block(bodyExpressions); var @case = Expression.SwitchCase(body, GetSwitchConstant(ctx, node)); return @case; }
private SwitchCase ProcessNode(DeserializerTypeContext ctx, RecursionNode node) { var accessFunction = Expression.MakeMemberAccess(null, typeof(DeserializerStore<>) .MakeGenericType(node.Type).GetField("Function")); var invokeReturnValue = Expression.Invoke(accessFunction, ctx.IteratorVar, ctx.StringParam); var accessMember = Expression.MakeMemberAccess(ctx.InstanceVar, node.Member); var assignMember = Expression.Assign(accessMember, invokeReturnValue); var bodyExpressions = new List<Expression>(); bodyExpressions.Add(assignMember); bodyExpressions.Add(Expression.Empty()); var body = Expression.Block(bodyExpressions); var @case = Expression.SwitchCase(body, GetSwitchConstant(ctx, node)); return @case; }
private SwitchCase ProcessNode(DeserializerTypeContext parentCtx, UnknownTypeNode node) { var ctx = new DeserializerTypeContext { Type = node.Member.PropertyOrFieldType }; InitializeVars(ctx); var @switch = GetSwitchStatement(ctx, node.Children); ctx.BlockInsideLoop = GetInnerLoopTemplate(ctx, @switch); var lambda = GetTemplate(ctx); var del = CompileExpression(node.Type, lambda); _treeBuilder.AddKnownType(node.Type, del); return GetKnownTypeSwitchCase(parentCtx, del.Method, node); }
private SwitchCase ProcessCollectionNode(DeserializerTypeContext ctx, MemberNode node, MethodInfo method) { var bodyExpressions = new List<Expression>(); var collectionType = GetNewCollectionType(node.Member.PropertyOrFieldType); method = method.MakeGenericMethod(collectionType); var createNewCollection = Expression.New(collectionType); var callExtractItems = Expression.Call(null, method, ctx.IteratorVar, ctx.StringParam, createNewCollection); var accessMember = Expression.MakeMemberAccess(ctx.InstanceVar, node.Member); if (node.Member.PropertyOrFieldType.IsArray) { var callToArray = Expression.Call(null, _toArray.MakeGenericMethod(node.Member.PropertyOrFieldType.GetElementType()), callExtractItems); callExtractItems = callToArray; } var assignMember = Expression.Assign(accessMember, callExtractItems); bodyExpressions.Add(assignMember); bodyExpressions.Add(Expression.Empty()); var body = Expression.Block(bodyExpressions); var @case = Expression.SwitchCase(body, GetSwitchConstant(ctx, node)); return @case; }
private SwitchCase ProcessNode(DeserializerTypeContext ctx, KnownTypeNode node) { return GetKnownTypeSwitchCase(ctx, node.Method, node); }
private LambdaExpression GetTemplate(DeserializerTypeContext ctx) { var newInstance = Expression.New(ctx.Type); var assignInstance = Expression.Assign(ctx.InstanceVar, newInstance); var terminationCondition = Expression.LessThan(ctx.IteratorVar, ctx.StringLengthVar); var initializeIterationVar = Expression.Assign(ctx.IteratorVar, ctx.StartParam); var assignLen = Expression.Assign(ctx.StringLengthVar, Expression.Property(ctx.StringParam, "Length")); var @for = Expression.Loop( Expression.IfThenElse( terminationCondition, ctx.BlockInsideLoop , Expression.Break(ctx.BreakLabel)), ctx.BreakLabel); var bodyExpressions = new List<Expression>(); bodyExpressions.Add(assignInstance); bodyExpressions.Add(initializeIterationVar); bodyExpressions.Add(assignLen); bodyExpressions.Add(@for); bodyExpressions.Add(Expression.Label(ctx.ReturnLabel)); bodyExpressions.Add(ctx.InstanceVar); var body = Expression.Block(new[] // the variables { ctx.InstanceVar, ctx.EndVar, ctx.IteratorVar, ctx.StringLengthVar, ctx.CharVar, ctx.WhiteSpaceCounter, ctx.PropertyHashValue ?? ctx.SubStringVar }, // the body bodyExpressions); var lambdaType = typeof(DeserializeHandler<>).MakeGenericType(ctx.Type); var lambda = Expression.Lambda(lambdaType, body, ctx.StartParam, ctx.StringParam); return lambda; }
private void InitializeVars(DeserializerTypeContext ctx) { ctx.InstanceVar = Expression.Variable(ctx.Type, "new" + ctx.Type.Name); ctx.EndVar = Expression.Variable(typeof(int), "end"); ctx.StartParam = Expression.Parameter(typeof(int).MakeByRefType(), "start"); ctx.IteratorVar = Expression.Variable(typeof(int), "i"); ctx.StringParam = Expression.Parameter(typeof(string), "str"); ctx.StringLengthVar = Expression.Variable(typeof(int), "len"); ctx.CharVar = Expression.Variable(typeof(char), "c"); ctx.BreakLabel = Expression.Label("break"); ctx.ContinueLabel = Expression.Label("continue"); ctx.ReturnLabel = Expression.Label("return"); ctx.WhiteSpaceCounter = Expression.Variable(typeof(int), "whitespace"); ctx.SubStringVar = Expression.Variable(typeof(string), "subStr"); }
private Expression GetSwitchConstant(DeserializerTypeContext ctx, MemberNode node) { if (ctx.HashingMethod == null) return Expression.Constant(node.Member.Name); var hash = ctx.HashingMethod.Values.FirstOrDefault(kv => kv.Value == node.Member.Name); if (hash.Value == null) throw new InvalidOperationException("Unknown hash for member " + node.Member); return Expression.Constant(hash.Key); }
private Expression GetSwitchStatement(DeserializerTypeContext ctx, IList<Node> members) { var switchCases = new List<SwitchCase>(); ctx.HashingMethod = MemberHashHelper.CanUseHashLookup(members.Cast<MemberNode>().Select(m => m.Member.Name)); foreach (var c in members) { var caseStatement = ProcessNode(ctx, c as dynamic) as SwitchCase; if (caseStatement != null) { switchCases.Add(caseStatement); } } if (!switchCases.Any()) { return Expression.Empty(); } Expression switchValue; if (ctx.HashingMethod == null) { switchValue = ctx.SubStringVar; } else { ctx.PropertyHashValue = Expression.Variable(typeof(int), "hashValue"); switchValue = ctx.PropertyHashValue; } var @switch = Expression.Switch(switchValue, GetDefaultCase(ctx), switchCases.ToArray()); return @switch; }
private Expression GetPropertyFinderLoop(DeserializerTypeContext ctx) { var outerLoopExpressions = new List<Expression>(); var jParam = Expression.Variable(typeof(int), "j"); var terminationCondition = Expression.LessThan(jParam, ctx.StringLengthVar); var @break = Expression.Label(); var assignItoJ = Expression.Assign(jParam, ctx.IteratorVar); var increment = Expression.PostIncrementAssign(jParam); var accessStringIndex = Expression.MakeIndex(ctx.StringParam, _stringIndexMethod, new[] { jParam }); var assignToChar = Expression.Assign(ctx.CharVar, accessStringIndex); var invokeIgnoreFunc = Expression.Call(null, _ignoreFunc, ctx.CharVar); var assignJtoEnd = Expression.Assign(ctx.EndVar, jParam); var exitLoopBlock = Expression.Block(assignJtoEnd, Expression.Break(@break)); var ifWhiteSpace = Expression.IfThenElse(invokeIgnoreFunc, Expression.PostIncrementAssign(ctx.WhiteSpaceCounter), Expression.IfThen(Expression.Equal(ctx.CharVar, Expression.Constant(':')), exitLoopBlock)); var innerLoopExpressions = new List<Expression>(); innerLoopExpressions.Add(assignToChar); innerLoopExpressions.Add(ifWhiteSpace); innerLoopExpressions.Add(increment); var innerLoopBlock = Expression.Block(innerLoopExpressions); var @for = Expression.Loop( Expression.IfThenElse( terminationCondition, innerLoopBlock , Expression.Break(@break)), @break); outerLoopExpressions.Add(assignItoJ); outerLoopExpressions.Add(@for); var outerLoopBlock = Expression.Block(new[] { jParam }, outerLoopExpressions); return outerLoopBlock; }
private SwitchCase GetKnownTypeSwitchCaseForRecursion(DeserializerTypeContext ctx, RecursionNode node) { //var return null; }
private SwitchCase GetKnownTypeSwitchCase(DeserializerTypeContext ctx, MethodInfo method, MemberNode node) { var bodyExpressions = new List<Expression>(); var callExtractString = Expression.Call(null, method, ctx.IteratorVar, ctx.StringParam); var accessMember = Expression.MakeMemberAccess(ctx.InstanceVar, node.Member); var assignMember = Expression.Assign(accessMember, callExtractString); bodyExpressions.Add(assignMember); bodyExpressions.Add(Expression.Empty()); var body = Expression.Block(bodyExpressions); var @case = Expression.SwitchCase(body, GetSwitchConstant(ctx, node)); return @case; }
private Expression GetInnerLoopTemplate(DeserializerTypeContext ctx, Expression propertySwitch) { var accessStringIndex = Expression.MakeIndex(ctx.StringParam, _stringIndexMethod, new[] { ctx.IteratorVar }); var assignToChar = Expression.Assign(ctx.CharVar, accessStringIndex); var invokeIgnoreFunc = Expression.Call(null, _ignoreFunc, ctx.CharVar); var increment = Expression.PreIncrementAssign(ctx.IteratorVar); var ifIgnore = Expression.IfThen(invokeIgnoreFunc, Expression.Block(increment, Expression.Continue(ctx.ContinueLabel))); var bodyExpressions = new List<Expression>(); var ifCommaOrBrace = Expression.SwitchCase(Expression.Block(increment, Expression.Continue(ctx.ContinueLabel)), Expression.Constant(','), Expression.Constant('{')); var ifClosingBrace = Expression.SwitchCase(Expression.Block(Expression.Assign(ctx.StartParam, increment), Expression.Return(ctx.ReturnLabel)), Expression.Constant('}')); var @switch = Expression.Switch(ctx.CharVar, ifCommaOrBrace, ifClosingBrace); var resetEndVar = Expression.Assign(ctx.EndVar, Expression.Constant(-1)); var resetWhiteSpaceVar = Expression.Assign(ctx.WhiteSpaceCounter, Expression.Constant(0)); var throwIfEndIsNegative = Expression.IfThen(Expression.LessThan(ctx.EndVar, Expression.Constant(0)), Expression.Throw(Expression.New(typeof(InvalidOperationException).GetConstructor(new[] { typeof(string) }) , Expression.Constant("Expected a property, but encountered none.")))); Expression assignToSwitchValue; if (ctx.HashingMethod == null) { var callSubString = Expression.Call(ctx.StringParam, _subStringMethod, ctx.IteratorVar, Expression.Subtract(Expression.Subtract(ctx.EndVar, ctx.IteratorVar), ctx.WhiteSpaceCounter)); assignToSwitchValue = Expression.Assign(ctx.SubStringVar, callSubString); } else { var callHash = Expression.Call(null, ctx.HashingMethod.Method.Method, ctx.StringParam, ctx.IteratorVar, Expression.Subtract(ctx.EndVar, ctx.WhiteSpaceCounter)); assignToSwitchValue = Expression.Assign(ctx.PropertyHashValue, callHash); } var assignI = Expression.Assign(ctx.IteratorVar, Expression.Add(ctx.EndVar, Expression.Constant(1))); bodyExpressions.Add(assignToChar); bodyExpressions.Add(ifIgnore); bodyExpressions.Add(@switch); bodyExpressions.Add(resetEndVar); bodyExpressions.Add(resetWhiteSpaceVar); bodyExpressions.Add(GetPropertyFinderLoop(ctx)); bodyExpressions.Add(throwIfEndIsNegative); bodyExpressions.Add(assignToSwitchValue); bodyExpressions.Add(assignI); bodyExpressions.Add(propertySwitch); bodyExpressions.Add(Expression.Label(ctx.ContinueLabel)); return Expression.Block(bodyExpressions); }
private Expression GetDefaultCase(DeserializerTypeContext ctx) { var skipMethod = typeof(StandardFunctions).GetMethod("Skip"); var callSkip = Expression.Call(null, skipMethod, ctx.IteratorVar, ctx.StringParam); return callSkip; }