private IEnumerable <ParamActionDefinition> GenerateParameter(CommandDeclaration command, MethodDefinition newMethod, ParamDeclaration parameter, int parameterIndex, bool isEnumeratePattern, bool isLastParamArray, bool lastParamReturns, List <MethodAction> marshalFromActions, List <MethodAction> marshalMidActions, List <MethodAction> marshalToActions, List <Action <ExpressionBuilder> > marshalledValues, Func <string, Action <ExpressionBuilder> > getHandle, Dictionary <string, Action <ExpressionBuilder> > handleLookup) { string paramName = parameter.Name; var paramType = typeData[parameter.Type.VkName]; string GetMarshalledName(string baseName) { return("marshalled" + baseName.TrimStart('@').FirstToUpper()); } List <ParamActionDefinition> result = new List <ParamActionDefinition>(); if (parameterIndex >= command.HandleParamsCount) { if (lastParamReturns && parameterIndex == command.Params.Count() - 2 && isEnumeratePattern) { newMethod.MemberActions.Add(new DeclarationAction { MemberType = paramType.Name, MemberName = paramName }); marshalledValues.Add(AddressOf(Variable(paramName))); var patternInfo = new MemberPatternInfo(); this.memberPatternRules.ApplyFirst(command.Params, command.Params.Last(), new MemberPatternContext(command.Verb, true, command.Extension, getHandle, command.VkName), patternInfo); string marshalledName = GetMarshalledName(patternInfo.Interop.Name); marshalMidActions.Add(new AssignAction { Type = AssignActionType.Alloc, MemberType = patternInfo.InteropFullType.TrimEnd('*'), TargetExpression = Variable(marshalledName), LengthExpression = Cast("uint", Variable(paramName)) }); } else if (lastParamReturns && parameterIndex == command.Params.Count() - 1) { if (isLastParamArray) { var patternInfo = new MemberPatternInfo(); this.memberPatternRules.ApplyFirst(command.Params, parameter, new MemberPatternContext(command.Verb, true, command.Extension, getHandle, command.VkName), patternInfo); string marshalledName = GetMarshalledName(patternInfo.Interop.Name); marshalToActions.Add(new DeclarationAction { MemberType = patternInfo.InteropFullType, MemberName = marshalledName }); var newMarshalFrom = patternInfo.MarshalFrom.Select(action => action(targetName => Variable("result"), valueName => Variable(GetMarshalledName(valueName)))).ToArray(); if (!isEnumeratePattern) { var lengthExpression = newMarshalFrom.OfType <AssignAction>().First(x => x.IsLoop).LengthExpression; marshalToActions.Add(new AssignAction { Type = AssignActionType.Alloc, MemberType = patternInfo.InteropFullType.TrimEnd('*'), TargetExpression = Variable(marshalledName), LengthExpression = lengthExpression }); } marshalFromActions.AddRange(newMarshalFrom); marshalledValues.Add(Variable(marshalledName)); newMethod.ReturnType = patternInfo.ReturnType ?? patternInfo.Public.Single().Type; } else { var patternInfo = new MemberPatternInfo(); var effectiveParam = new ParamDeclaration { Name = parameter.Name, Type = parameter.Type.Deref(), Dimensions = parameter.Dimensions, VkName = parameter.VkName }; this.memberPatternRules.ApplyFirst(command.Params, effectiveParam, new MemberPatternContext(command.Verb, true, command.Extension, getHandle, command.VkName), patternInfo); string marshalledName = GetMarshalledName(patternInfo.Interop.Name); marshalToActions.Add(new DeclarationAction { MemberType = patternInfo.InteropFullType, MemberName = marshalledName }); marshalFromActions.AddRange(patternInfo.MarshalFrom.Select(action => action(targetName => Variable("result"), valueName => Variable(GetMarshalledName(valueName))))); marshalledValues.Add(AddressOf(Variable(marshalledName))); newMethod.ReturnType = patternInfo.Public.Single().Type; } } else { var patternInfo = new MemberPatternInfo(); this.memberPatternRules.ApplyFirst(command.Params, parameter, new MemberPatternContext(command.Verb, true, command.Extension, getHandle, command.VkName), patternInfo); var actionList = marshalToActions; Func <string, Action <ExpressionBuilder> > getValue = valueName => Variable(valueName); foreach (var publicMember in patternInfo.Public) { result.Add(new ParamActionDefinition { Param = new ParamDefinition { Name = publicMember.Name, Comment = publicMember.Comment, Type = publicMember.Type, DefaultValue = publicMember.DefaultValue } }); } if (patternInfo.MarshalTo.Any()) { string marshalledName = patternInfo.Interop.Name; if (patternInfo.Public.Any()) { marshalledName = GetMarshalledName(patternInfo.Interop.Name); } var newMarshalToActions = patternInfo.MarshalTo.Select(action => action(targetName => Variable(marshalledName), getValue)); var lastParam = command.Params.Last(); bool isLenForLastParam = lastParamReturns && lastParam.Dimensions != null && lastParam.Dimensions.Any(dimension => dimension.Type == LenType.Expression && this.tokenCheck.Check(dimension.Value, parameter.VkName)); if (!isLenForLastParam && newMarshalToActions.Count() == 1 && newMarshalToActions.First() is AssignAction newAssignAction && newAssignAction.Type == AssignActionType.Assign && !newAssignAction.IsLoop) { marshalledValues.Add(newAssignAction.ValueExpression); } else { marshalToActions.Add(new DeclarationAction { MemberType = patternInfo.InteropFullType, MemberName = marshalledName }); marshalledValues.Add(Variable(marshalledName)); actionList.AddRange(newMarshalToActions); } } foreach (var lookup in patternInfo.HandleLookup) { handleLookup[lookup.Item1] = lookup.Item2(getValue); } } }
public void Execute(IServiceCollection services) { foreach (var typeItem in this.typeData.Where(x => x.Value.Pattern == TypePattern.MarshalledStruct)) { var type = typeItem.Value; var typeNamespace = new List <string>(); if (type.Extension != null) { typeNamespace.AddRange(this.namespaceMap.Map(type.Extension)); } var publicStruct = new StructDefinition { Name = type.Name, Namespace = typeNamespace.ToArray(), Comment = this.commentGenerator.Lookup(typeItem.Key), Methods = new List <MethodDefinition>(), Properties = new List <MemberDefinition>() }; var marshalToMethod = new MethodDefinition { Name = "MarshalTo", IsUnsafe = true, ParamActions = new List <ParamActionDefinition> { new ParamActionDefinition { Param = new ParamDefinition { Name = "pointer", Type = this.nameLookup.Lookup(new TypeReference { VkName = typeItem.Key, PointerType = PointerType.Pointer }, true) } } }, MemberActions = new List <MethodAction>() }; var marshalFromMethod = new MethodDefinition { Name = "MarshalFrom", ReturnType = type.Name, IsUnsafe = true, IsStatic = true, ParamActions = new List <ParamActionDefinition> { new ParamActionDefinition { Param = new ParamDefinition { Name = "pointer", Type = this.nameLookup.Lookup(new TypeReference { VkName = typeItem.Key, PointerType = PointerType.Pointer }, true) } } }, MemberActions = new List <MethodAction>() }; if (!type.IsOutputOnly || (type.Extends?.Any(x => !this.typeData[x].IsOutputOnly) ?? false)) { publicStruct.Methods.Add(marshalToMethod); } if (type.IsOutputOnly || (!type.Name.EndsWith("Info") && type.Members.All(this.CanMarshalFrom))) { publicStruct.Methods.Add(marshalFromMethod); } typeNamespace.Insert(0, "Interop"); var interopStruct = new StructDefinition { Name = type.Name, Namespace = typeNamespace.ToArray(), IsUnsafe = true, Fields = new List <MemberDefinition>() }; foreach (var member in type.Members) { var patternInfo = new MemberPatternInfo { }; this.patternRules.ApplyFirst(type.Members, member, new MemberPatternContext(null, false, false, false, type.Extension, x => Default(this.nameLookup.Lookup(new TypeReference { VkName = x }, false)), typeItem.Key), patternInfo); marshalToMethod.MemberActions.AddRange(patternInfo.MarshalTo.Select(action => action(targetName => DerefMember(Variable("pointer"), targetName), valueName => Member(This, valueName)))); marshalFromMethod.MemberActions.AddRange(patternInfo.MarshalFrom.Select(action => action(targetName => Member(Variable("result"), targetName), valueName => DerefMember(Variable("pointer"), valueName)))); foreach (var publicMember in patternInfo.Public) { publicStruct.Properties.Add(new MemberDefinition { Name = publicMember.Name, Type = publicMember.Type, Comment = this.commentGenerator.Lookup(typeItem.Key, member.VkName) }); } if (patternInfo.Interop.Repeats.HasValue) { for (int index = 0; index < patternInfo.Interop.Repeats.Value; index++) { interopStruct.Fields.Add(new MemberDefinition { Name = patternInfo.Interop.Name + "_" + index, Type = patternInfo.Interop.Type }); } } else { interopStruct.Fields.Add(new MemberDefinition { Name = patternInfo.Interop.Name, Type = patternInfo.Interop.Type, Comment = this.commentGenerator.Lookup(typeItem.Key, member.VkName) }); } } services.AddSingleton(publicStruct); services.AddSingleton(interopStruct); } }