static CodeMemberMethod GenerateInitialize(XPathModuleInfo module, CodeExpression moduleExpr) { var initializeMethod = new CodeMemberMethod { Name = "Initialize", Attributes = MemberAttributes.Public | MemberAttributes.Final }; for (int i = 0; i < module.Dependencies.Count; i++) { XPathDependencyInfo dependency = module.Dependencies[i]; initializeMethod.Parameters.Add(new CodeParameterDeclarationExpression { Type = new CodeTypeReference(dependency.Type), Name = "d" + (i + 1).ToStringInvariant() }); var paramRef = new CodeVariableReferenceExpression(initializeMethod.Parameters[i].Name); initializeMethod.Statements.Add(new CodeAssignStatement { Left = new CodePropertyReferenceExpression(moduleExpr, dependency.Property.Name), Right = paramRef }); } return(initializeMethod); }
object InitializeExtensionObject(Tuple <XPathModuleInfo, Type> info, XmlResolver resolver) { object instance = Activator.CreateInstance(info.Item2); XPathModuleInfo moduleInfo = info.Item1; if (moduleInfo == null) { var xpathFn = instance as extensions.XPathFunctions; if (xpathFn != null) { xpathFn.resolver = resolver; } } else if (moduleInfo.Dependencies.Count > 0) { object[] args = new object[info.Item1.Dependencies.Count]; for (int i = 0; i < info.Item1.Dependencies.Count; i++) { XPathDependencyInfo dependency = info.Item1.Dependencies[i]; if (dependency.Type == typeof(XPathItemFactory)) { args[i] = this.Processor.ItemFactory; continue; } if (dependency.Type == typeof(XmlResolver)) { args[i] = resolver; continue; } if (dependency.Type == typeof(IXsltProcessor)) { args[i] = this.Processor; continue; } args[i] = dependency.Type.IsValueType ? Activator.CreateInstance(dependency.Type) : null; } info.Item2.GetMethod("Initialize").Invoke(instance, args); } return(instance); }
static CodeTypeDeclaration GenerateType(XPathModuleInfo module) { var type = new CodeTypeDeclaration { Name = module.Type.FullName.Replace('.', '_') + "_extobj", IsClass = true, TypeAttributes = TypeAttributes.Public, CustomAttributes = { new CodeAttributeDeclaration( new CodeTypeReference(typeof(DebuggerNonUserCodeAttribute)) ) } }; CodeExpression moduleExpr; if (module.TypeIsStatic) { moduleExpr = new CodeTypeReferenceExpression(module.Type); } else { var moduleField = new CodeMemberField { Name = "module", Type = new CodeTypeReference(module.Type), InitExpression = new CodeObjectCreateExpression(module.Type) }; type.Members.Add(moduleField); moduleExpr = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), moduleField.Name); if (module.Dependencies.Count > 0) { type.Members.Add(GenerateInitialize(module, moduleExpr)); } } foreach (XPathFunctionInfo function in module.Functions) { type.Members.Add(GenerateFunction(function, moduleExpr)); } return(type); }
CodeMemberMethod GenerateInitialize(XPathModuleInfo module, CodeExpression processorRef, CodeExpression staticBaseUriExpr) { var initializeMethod = new CodeMemberMethod { Name = "Initialize", Attributes = MemberAttributes.Private | MemberAttributes.Final, Parameters = { new CodeParameterDeclarationExpression(module.Type, "module") } }; for (int i = 0; i < module.Dependencies.Count; i++) { XPathDependencyInfo dependency = module.Dependencies[i]; CodeExpression expr = null; if (dependency.Type == typeof(IXsltProcessor) || dependency.Type == typeof(IXQueryProcessor)) { expr = processorRef; } else if (dependency.Type == typeof(XPathItemFactory)) { expr = GetItemFactoryReference(processorRef); } else if (dependency.Type == typeof(XmlResolver)) { expr = new CodeObjectCreateExpression(typeof(XmlDynamicResolver), staticBaseUriExpr); } if (expr != null) { initializeMethod.Statements.Add(new CodeAssignStatement { Left = new CodePropertyReferenceExpression( new CodeVariableReferenceExpression(initializeMethod.Parameters[0].Name), dependency.Property.Name ), Right = expr }); } } return(initializeMethod); }
CodeNamespace GenerateModuleTypes(XPathModuleInfo module, out string[] functionDefTypeNames) { var namespaceBuilder = new StringBuilder() .Append(typeof(IntegratedExtensionFunctionGenerator).Namespace) .Append(".modules.") .Append(module.Type.FullName.Replace('.', '_')) .Append("_functions"); var nspace = new CodeNamespace { Name = namespaceBuilder.ToString(), Imports = { new CodeNamespaceImport(typeof(Enumerable).Namespace), new CodeNamespaceImport(typeof(SaxonExtensions).Namespace) } }; var groupedByName = from f in module.Functions group f by f.Name; var functionDefNames = new List <string>(); foreach (var functions in groupedByName) { Tuple <CodeTypeDeclaration, CodeTypeDeclaration> funcDefAndCall = GenerateFunctionType(functions.ToArray()); nspace.Types.Add(funcDefAndCall.Item1); nspace.Types.Add(funcDefAndCall.Item2); functionDefNames.Add(nspace.Name + "." + funcDefAndCall.Item1.Name); } functionDefTypeNames = functionDefNames.ToArray(); return(nspace); }
CodeMemberMethod GenerateCallMethod(XPathFunctionInfo[] functions, int minArgs, int maxArgs, CodeExpression processorRef, CodeMemberMethod initializeMethod) { XPathFunctionInfo mostParameters = functions.OrderByDescending(f => f.Parameters.Count).First(); XPathModuleInfo module = mostParameters.Module; var argsParam = new CodeParameterDeclarationExpression(typeof(IXdmEnumerator[]), "arguments"); var callMethod = new CodeMemberMethod { Name = "Call", Attributes = MemberAttributes.Public | MemberAttributes.Override, ReturnType = new CodeTypeReference(typeof(IXdmEnumerator)), Parameters = { argsParam, new CodeParameterDeclarationExpression(typeof(DynamicContext), "context") } }; var argumentsRef = new CodeVariableReferenceExpression(callMethod.Parameters[0].Name); CodeExpression moduleRef; if (module.TypeIsStatic) { moduleRef = new CodeTypeReferenceExpression(module.Type); } else { var moduleVar = new CodeVariableDeclarationStatement { Name = "module", Type = new CodeTypeReference(module.Type), InitExpression = new CodeObjectCreateExpression(module.Type) }; callMethod.Statements.Add(moduleVar); moduleRef = new CodeVariableReferenceExpression(moduleVar.Name); if (initializeMethod != null) { callMethod.Statements.Add(new CodeMethodInvokeExpression { Method = new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), initializeMethod.Name), Parameters = { moduleRef } }); } } CodeStatementCollection currentBlock = callMethod.Statements; var paramRef = new List <CodeExpression>(); for (int pos = 0; pos <= maxArgs; pos++) { if (pos > 0) { XPathSequenceType paramInfo = mostParameters.Parameters[pos - 1].Type; var paramVar = new CodeVariableDeclarationStatement { Name = "p" + pos, Type = new CodeTypeReference(paramInfo.ClrType), InitExpression = TransformInput(argumentsRef, pos, paramInfo) }; currentBlock.Add(paramVar); paramRef.Add(new CodeVariableReferenceExpression(paramVar.Name)); } if (pos >= minArgs) { XPathFunctionInfo fn = functions[pos - minArgs]; CodeConditionStatement ifElse = null; if (minArgs != maxArgs && pos < maxArgs) { ifElse = new CodeConditionStatement { Condition = new CodeBinaryOperatorExpression { Left = new CodePropertyReferenceExpression(argumentsRef, "Length"), Operator = CodeBinaryOperatorType.ValueEquality, Right = new CodePrimitiveExpression(pos) } }; currentBlock.Add(ifElse); currentBlock = ifElse.TrueStatements; } var functionInvoke = new CodeMethodInvokeExpression { Method = new CodeMethodReferenceExpression(moduleRef, fn.Method.Name) }; functionInvoke.Parameters.AddRange(paramRef.ToArray()); CodeExpression returnExpr; if (!fn.ReturnType.IsEmptySequence) { returnExpr = TransformOutput(functionInvoke, fn.ReturnType, processorRef); } else { currentBlock.Add(functionInvoke); returnExpr = new CodePropertyReferenceExpression { PropertyName = "INSTANCE", TargetObject = new CodeTypeReferenceExpression(typeof(EmptyEnumerator)) }; } currentBlock.Add(new CodeMethodReturnStatement(returnExpr)); if (ifElse != null) { currentBlock = ifElse.FalseStatements; } } } return(callMethod); }
Tuple <CodeTypeDeclaration, CodeTypeDeclaration> GenerateFunctionType(XPathFunctionInfo[] functions) { XPathFunctionInfo first = functions.First(); XPathFunctionInfo leastParameters = functions.OrderBy(f => f.Parameters.Count).First(); XPathFunctionInfo mostParameters = functions.OrderByDescending(f => f.Parameters.Count).First(); XPathModuleInfo module = first.Module; int minArgs = leastParameters.Parameters.Count; int maxArgs = mostParameters.Parameters.Count; CodeExpression thisRef = new CodeThisReferenceExpression(); var processorField = new CodeMemberField { Name = "_processor", Type = new CodeTypeReference(typeof(SaxonProcessor)) }; var funcNameField = new CodeMemberField { Name = "_FunctionName", Type = new CodeTypeReference(typeof(QName)), InitExpression = new CodeObjectCreateExpression( typeof(QName), new CodePrimitiveExpression(module.Namespace), new CodePrimitiveExpression(first.Name) ) }; var argTypesField = new CodeMemberField { Name = "_ArgumentTypes", Type = new CodeTypeReference(typeof(XdmSequenceType[])), InitExpression = new CodeArrayCreateExpression( typeof(XdmSequenceType), mostParameters.Parameters.Select(p => new CodeObjectCreateExpression( typeof(XdmSequenceType), GetXdmItemTypeExpression(p.Type.ItemType), new CodePrimitiveExpression(GetOcurrenceIndicator(p.Type.Cardinality)) )).ToArray() ) }; var resultTypesField = new CodeMemberField { Name = "_resultTypes", Type = new CodeTypeReference(typeof(XdmSequenceType[])) }; var resultTypesFieldInit = new CodeArrayCreateExpression { CreateType = resultTypesField.Type, Size = functions.Length }; for (int i = 0; i < functions.Length; i++) { XPathFunctionInfo function = functions[i]; resultTypesFieldInit.Initializers.Add( // Using item()? instead of empty-sequence() (function.ReturnType.IsEmptySequence) ? new CodeObjectCreateExpression( typeof(XdmSequenceType), new CodeFieldReferenceExpression( new CodeTypeReferenceExpression(typeof(XdmAnyItemType)), "Instance" ), new CodePrimitiveExpression(GetOcurrenceIndicator(XPathSequenceCardinality.ZeroOrOne)) ) : new CodeObjectCreateExpression( typeof(XdmSequenceType), GetXdmItemTypeExpression(function.ReturnType.ItemType), new CodePrimitiveExpression(GetOcurrenceIndicator(function.ReturnType.Cardinality)) ) ); } resultTypesField.InitExpression = resultTypesFieldInit; var defClass = new CodeTypeDeclaration { Name = first.Method.Name + "Function", Attributes = MemberAttributes.Public, BaseTypes = { typeof(ExtensionFunctionDefinition) }, Members = { processorField, funcNameField, argTypesField, resultTypesField, new CodeConstructor { Attributes = MemberAttributes.Public, Parameters = { new CodeParameterDeclarationExpression(processorField.Type, "processor") }, Statements = { new CodeAssignStatement( new CodeFieldReferenceExpression(thisRef, processorField.Name), new CodeVariableReferenceExpression("processor") ) } }, new CodeMemberProperty { Name = "FunctionName", Type = funcNameField.Type, Attributes = MemberAttributes.Public | MemberAttributes.Override, HasGet = true, GetStatements = { new CodeMethodReturnStatement(new CodeFieldReferenceExpression(thisRef,funcNameField.Name)) } }, new CodeMemberProperty { Name = "ArgumentTypes", Type = argTypesField.Type, Attributes = MemberAttributes.Public | MemberAttributes.Override, HasGet = true, GetStatements = { new CodeMethodReturnStatement(new CodeFieldReferenceExpression(thisRef,argTypesField.Name)) } }, new CodeMemberProperty { Name = "MaximumNumberOfArguments", Type = new CodeTypeReference(typeof(int)), Attributes = MemberAttributes.Public | MemberAttributes.Override, HasGet = true, GetStatements = { new CodeMethodReturnStatement(new CodePrimitiveExpression(maxArgs)) } }, new CodeMemberProperty { Name = "MinimumNumberOfArguments", Type = new CodeTypeReference(typeof(int)), Attributes = MemberAttributes.Public | MemberAttributes.Override, HasGet = true, GetStatements = { new CodeMethodReturnStatement(new CodePrimitiveExpression(minArgs)) } }, GenerateResultTypeMethod(thisRef, resultTypesField) } }; if (first.HasSideEffects) { defClass.Members.Add(new CodeMemberProperty { Name = "HasSideEffects", Type = new CodeTypeReference(typeof(bool)), Attributes = MemberAttributes.Public | MemberAttributes.Override, HasGet = true, GetStatements = { new CodeMethodReturnStatement(new CodePrimitiveExpression(true)) } }); } var callClass = new CodeTypeDeclaration { Name = defClass.Name + "Call", Attributes = MemberAttributes.Assembly, BaseTypes = { new CodeTypeReference(typeof(ExtensionFunctionCall)) }, Members = { processorField, new CodeConstructor { Attributes = MemberAttributes.Public, Parameters = { new CodeParameterDeclarationExpression(processorField.Type,"processor") }, Statements = { new CodeAssignStatement( new CodeFieldReferenceExpression(thisRef, processorField.Name), new CodeVariableReferenceExpression("processor") ) } } } }; CodeMemberMethod initializeMethod = null; if (!module.TypeIsStatic && module.Dependencies.Count > 0) { CodeExpression staticBaseUriExpr = null; if (module.Dependencies.Any(d => d.Type == typeof(XmlResolver))) { var staticBaseUriField = new CodeMemberField { Name = "_staticBaseUri", Type = new CodeTypeReference(typeof(Uri)) }; callClass.Members.Add(staticBaseUriField); var staticContextParam = new CodeParameterDeclarationExpression(typeof(StaticContext), "context"); staticBaseUriExpr = new CodeFieldReferenceExpression(thisRef, staticBaseUriField.Name); callClass.Members.Add(new CodeMemberMethod { Name = "SupplyStaticContext", Attributes = MemberAttributes.Public | MemberAttributes.Override, Parameters = { staticContextParam }, Statements = { new CodeAssignStatement { Left = staticBaseUriExpr, Right = new CodePropertyReferenceExpression{ PropertyName = "BaseUri", TargetObject = new CodeVariableReferenceExpression(staticContextParam.Name) } } } }); } initializeMethod = GenerateInitialize(module, new CodeFieldReferenceExpression(thisRef, processorField.Name), staticBaseUriExpr); callClass.Members.Add(initializeMethod); } callClass.Members.Add(GenerateCallMethod(functions, minArgs, maxArgs, new CodeFieldReferenceExpression(thisRef, processorField.Name), initializeMethod)); defClass.Members.Add( new CodeMemberMethod { Name = "MakeFunctionCall", Attributes = MemberAttributes.Public | MemberAttributes.Override, ReturnType = new CodeTypeReference(typeof(ExtensionFunctionCall)), Statements = { new CodeMethodReturnStatement( new CodeObjectCreateExpression( callClass.Name, new CodeFieldReferenceExpression(thisRef, processorField.Name) ) ) } } ); return(Tuple.Create(defClass, callClass)); }