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);
        }
Exemplo n.º 2
0
        static CodeMemberMethod GenerateFunction(XPathFunctionInfo function, CodeExpression moduleExpr)
        {
            string name = function.Name;

             MemberAttributes methodAttributes = MemberAttributes.Public;

             if (name.Contains('-')) {
            name = name.Replace('-', '_');
            methodAttributes = MemberAttributes.Family;
             }

             methodAttributes |= MemberAttributes.Final;

             Type procReturnType = GetReturnType(function.ReturnType);

             var codeMethod = new CodeMemberMethod {
            Name = name,
            Attributes = methodAttributes,
            ReturnType = new CodeTypeReference(procReturnType),
             };

             var methodInvoke = new CodeMethodInvokeExpression {
            Method = new CodeMethodReferenceExpression {
               MethodName = function.Method.Name,
               TargetObject = moduleExpr
            }
             };

             for (int i = 0; i < function.Parameters.Count; i++) {

            XPathSequenceType paramTypeInfo = function.Parameters[i].Type;

            Type procParamType = GetParameterType(paramTypeInfo);

            var paramDecl = new CodeParameterDeclarationExpression {
               Name = "p" + i.ToStringInvariant(),
               Type = new CodeTypeReference(procParamType)
            };

            codeMethod.Parameters.Add(paramDecl);

            var paramVarExpr = new CodeVariableReferenceExpression(paramDecl.Name);
            CodeExpression argExpr = GetArgumentExpression(paramTypeInfo, procParamType, paramVarExpr);

            methodInvoke.Parameters.Add(argExpr);
             }

             CodeVariableReferenceExpression resultVarExpr = null;

             if (function.ReturnType.ClrType == typeof(void)) {
            codeMethod.Statements.Add(new CodeExpressionStatement(methodInvoke));

             } else {

            var resultVarDecl = new CodeVariableDeclarationStatement {
               Name = "result",
               InitExpression = methodInvoke,
               Type = new CodeTypeReference(function.Method.ReturnType)
            };

            codeMethod.Statements.Add(resultVarDecl);

            resultVarExpr = new CodeVariableReferenceExpression(resultVarDecl.Name);
             }

             CodeExpression returnExpr = GetReturnExpression(function.ReturnType, resultVarExpr);

             codeMethod.Statements.Add(new CodeMethodReturnStatement(returnExpr));

             return codeMethod;
        }
        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;
        }