static CodeExpression GetReturnExpression(XPathSequenceType sequenceType, CodeVariableReferenceExpression varExpr) { if (sequenceType.ClrType == typeof(void)) { return(new CodePropertyReferenceExpression { PropertyName = "EmptyIterator", TargetObject = new CodeTypeReferenceExpression(typeof(ExtensionObjectConvert)) }); } string convertMethod = "ToInput"; if (sequenceType.ItemType.KindIsNode) { convertMethod += "Node"; } if (sequenceType.Cardinality == XPathSequenceCardinality.ZeroOrMore || sequenceType.Cardinality == XPathSequenceCardinality.ZeroOrOne) { convertMethod += "OrEmpty"; } CodeExpression returnExpr = new CodeMethodInvokeExpression { Method = new CodeMethodReferenceExpression { MethodName = convertMethod, TargetObject = new CodeTypeReferenceExpression(typeof(ExtensionObjectConvert)) }, Parameters = { varExpr } }; if (sequenceType.ItemType.Kind == XPathItemKind.Element || sequenceType.ItemType.Kind == XPathItemKind.SchemaElement) { returnExpr = new CodeMethodInvokeExpression { Method = new CodeMethodReferenceExpression { MethodName = "FirstElementOrSelf", TargetObject = new CodeTypeReferenceExpression(typeof(ExtensionObjectConvert)) }, Parameters = { returnExpr } }; } return(returnExpr); }
static Type GetReturnType(XPathSequenceType returnTypeInfo) { switch (returnTypeInfo.Cardinality) { default: case XPathSequenceCardinality.One: if (returnTypeInfo.ItemType.KindIsNode) { return(typeof(XPathNavigator)); } return(typeof(object)); case XPathSequenceCardinality.ZeroOrOne: case XPathSequenceCardinality.ZeroOrMore: return(typeof(object)); case XPathSequenceCardinality.OneOrMore: return(typeof(XPathNavigator[])); } }
static CodeExpression TransformOutput(CodeExpression functionResultRef, XPathSequenceType sequenceType, CodeExpression processorRef) { CodeExpression itemFactoryRef = GetItemFactoryReference(processorRef); CodeExpression expr = new CodeMethodInvokeExpression { Method = new CodeMethodReferenceExpression { MethodName = "ToXdmValue", TargetObject = new CodeTypeReferenceExpression(typeof(SaxonExtensions)) }, Parameters = { functionResultRef, itemFactoryRef } }; if (sequenceType.ItemType.Kind == XPathItemKind.Element || sequenceType.ItemType.Kind == XPathItemKind.SchemaElement) { expr = new CodeMethodInvokeExpression { Method = new CodeMethodReferenceExpression { MethodName = "FirstElementOrSelf", TargetObject = new CodeTypeReferenceExpression(typeof(SaxonExtensions)) }, Parameters = { expr } }; } return(new CodeMethodInvokeExpression { Method = new CodeMethodReferenceExpression { MethodName = "GetXdmEnumerator", TargetObject = new CodeTypeReferenceExpression(typeof(SaxonExtensions)) }, Parameters = { expr } }); }
static CodeExpression GetArgumentExpression(XPathSequenceType paramTypeInfo, Type varType, CodeVariableReferenceExpression varExpr) { var convertTypeExpr = new CodeTypeReferenceExpression(typeof(ExtensionObjectConvert)); CodeExpression argExpr = varExpr; if (paramTypeInfo.ClrType.IsAssignableFrom(varType)) { return(argExpr); } MethodInfo convertMethod = typeof(ExtensionObjectConvert) .GetMethod("To" + paramTypeInfo.ClrType.Name, BindingFlags.Public | BindingFlags.Static, null, new[] { varType }, null); if (convertMethod != null) { return(new CodeMethodInvokeExpression { Method = new CodeMethodReferenceExpression { MethodName = convertMethod.Name, TargetObject = convertTypeExpr, }, Parameters = { argExpr } }); } MethodInfo convertItemMethod = typeof(ExtensionObjectConvert) .GetMethod("To" + paramTypeInfo.ItemType.ClrType.Name, BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(XPathItem) }, null); CodeExpression convertItemExpr = (convertItemMethod != null) ? new CodeMethodReferenceExpression(convertTypeExpr, convertItemMethod.Name) : null; if (paramTypeInfo.ClrTypeIsEnumerable) { CodeMethodInvokeExpression methodExpr; argExpr = methodExpr = new CodeMethodInvokeExpression { Method = new CodeMethodReferenceExpression { MethodName = "ToEnumerable", TypeArguments = { paramTypeInfo.ItemType.ClrType }, TargetObject = convertTypeExpr }, Parameters = { argExpr } }; if (convertItemExpr != null) { methodExpr.Parameters.Add(convertItemExpr); } if (paramTypeInfo.ClrType.IsArray) { argExpr = new CodeMethodInvokeExpression { Method = new CodeMethodReferenceExpression { MethodName = "ToArray", TypeArguments = { paramTypeInfo.ItemType.ClrType }, TargetObject = new CodeTypeReferenceExpression(typeof(Enumerable)) }, Parameters = { argExpr } }; } } else if (paramTypeInfo.ClrTypeIsNullableValueType) { CodeMethodInvokeExpression methodExpr; argExpr = methodExpr = new CodeMethodInvokeExpression { Method = new CodeMethodReferenceExpression { MethodName = "ToNullableValueType", TypeArguments = { paramTypeInfo.ItemType.ClrType }, TargetObject = convertTypeExpr }, Parameters = { argExpr } }; if (convertItemExpr != null) { methodExpr.Parameters.Add(convertItemExpr); } } else { CodeMethodInvokeExpression methodExpr; argExpr = methodExpr = new CodeMethodInvokeExpression { Method = new CodeMethodReferenceExpression { MethodName = "ToOutput", TypeArguments = { paramTypeInfo.ClrType }, TargetObject = convertTypeExpr }, Parameters = { argExpr } }; if (convertItemExpr != null && paramTypeInfo.ClrType == paramTypeInfo.ItemType.ClrType) { methodExpr.Parameters.Add(convertItemExpr); } } return(argExpr); }
static Type GetParameterType(XPathSequenceType paramTypeInfo) { switch (paramTypeInfo.Cardinality) { case XPathSequenceCardinality.One: if (paramTypeInfo.ItemType.Kind == XPathItemKind.AnyItem) { return(typeof(object)); } if (paramTypeInfo.ItemType.KindIsNode) { return(typeof(XPathNavigator)); } switch (Type.GetTypeCode(paramTypeInfo.ItemType.ClrType)) { default: case TypeCode.String: case TypeCode.Char: case TypeCode.Object: return(typeof(string)); case TypeCode.Boolean: return(typeof(bool)); case TypeCode.Byte: return(typeof(byte)); case TypeCode.DateTime: return(typeof(DateTime)); case TypeCode.Decimal: return(typeof(decimal)); case TypeCode.Double: return(typeof(double)); case TypeCode.Int16: return(typeof(Int16)); case TypeCode.Int32: return(typeof(Int32)); case TypeCode.Int64: return(typeof(Int64)); case TypeCode.SByte: return(typeof(SByte)); case TypeCode.Single: return(typeof(Single)); case TypeCode.UInt16: return(typeof(UInt16)); case TypeCode.UInt32: return(typeof(UInt32)); case TypeCode.UInt64: return(typeof(UInt64)); } default: return(typeof(XPathNodeIterator)); } }
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); }
CodeExpression TransformInput(CodeVariableReferenceExpression argumentsRef, int position, XPathSequenceType sequenceType) { var codeBuilder = new StringBuilder() .Append(argumentsRef.VariableName) .AppendFormatInvariant("[{0}]", position - 1); bool isAtomic = sequenceType.ItemType.Kind == XPathItemKind.Atomic; bool isNode = sequenceType.ItemType.KindIsNode; if (isAtomic) { codeBuilder.Append(".AsAtomicValues()"); } else if (isNode) { codeBuilder.Append(".AsNodes()"); } else { codeBuilder.Append(".AsItems()"); } var itemExpr = new StringBuilder("x"); if (isAtomic) { itemExpr.Append(".Value"); QName atomicSchemaType = GetAtomicSchemaType(sequenceType.ItemType); Type expectedType = sequenceType.ItemType.ClrType; Type actualType = (atomicSchemaType.Uri == XMLSchemaNamespace) ? SaxonAtomicMapping(atomicSchemaType.LocalName) : typeof(object); string expectedTypeName = GetCSharpFullName(expectedType); if (expectedType.IsAssignableFrom(actualType)) { itemExpr.Insert(0, "({0})".FormatInvariant(expectedTypeName)); } else { if (actualType == typeof(QName) && expectedType == typeof(XmlQualifiedName)) { itemExpr.Insert(0, "(({0})".FormatInvariant(GetCSharpFullName(actualType))); itemExpr.Append(").ToXmlQualifiedName()"); } else { itemExpr.Insert(0, "({0}){1}.ChangeType(".FormatInvariant(expectedTypeName, typeof(Convert).FullName)); itemExpr.AppendFormatInvariant(", typeof({0}))", expectedTypeName); } } } else if (isNode) { itemExpr.Append(".ToXPathNavigator()"); } else { itemExpr.Append(".ToXPathItem()"); } if (itemExpr.Length > 1) { codeBuilder.Append(".Select(x => "); codeBuilder.Append(itemExpr.ToString()); codeBuilder.Append(")"); } switch (sequenceType.Cardinality) { case XPathSequenceCardinality.One: codeBuilder.Append(".Single()"); break; case XPathSequenceCardinality.ZeroOrOne: if (sequenceType.ClrTypeIsNullableValueType) { codeBuilder.Insert(0, typeof(SaxonExtensions).FullName + ".SingleOrNull("); codeBuilder.Append(")"); } else { codeBuilder.Append(".SingleOrDefault()"); } break; case XPathSequenceCardinality.OneOrMore: case XPathSequenceCardinality.ZeroOrMore: if (sequenceType.ClrType.IsArray) { codeBuilder.Append(".ToArray()"); } break; } return(new CodeSnippetExpression(codeBuilder.ToString())); }
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); }
internal XPathVariableInfo(string name, XPathSequenceType type) { this._Name = name; this._Type = type; }