/// <summary> /// Creates a field that holds <see cref="QueryTypeProperties{T}"/> for the module. /// </summary> protected FieldDeclarationSyntax CreatePropertiesField( Module module, string resultClassName, FieldDeclarationSyntax propsField, SortType?sortType) { var queryTypePropertiesType = SyntaxEx.GenericName("QueryTypeProperties", resultClassName); var propertiesInitializer = SyntaxEx.ObjectCreation( queryTypePropertiesType, SyntaxEx.Literal(module.Name), SyntaxEx.Literal(module.Prefix), module.QueryType == null ? (ExpressionSyntax)SyntaxEx.NullLiteral() : SyntaxEx.MemberAccess("QueryType", module.QueryType.ToString()), sortType == null ? (ExpressionSyntax)SyntaxEx.NullLiteral() : SyntaxEx.MemberAccess("SortType", sortType.ToString()), CreateTupleListExpression(GetBaseParameters(module)), propsField == null ? (ExpressionSyntax)SyntaxEx.NullLiteral() : (NamedNode)propsField, resultClassName == "object" ? (ExpressionSyntax)SyntaxEx.LambdaExpression("_", SyntaxEx.NullLiteral()) : SyntaxEx.MemberAccess(resultClassName, "Parse")); return(SyntaxEx.FieldDeclaration( new[] { SyntaxKind.PrivateKeyword, SyntaxKind.StaticKeyword, SyntaxKind.ReadOnlyKeyword }, queryTypePropertiesType, ClassNameBase + "Properties", propertiesInitializer)); }
protected override void GenerateInternal(Module module) { ResultClassName = ClassNameBase + "Result"; var resultType = GenerateResultClass(GetPropertyGroups(module)); if (resultType == null) { ResultClassName = "object"; m_voidResult = true; } else { var codeUnit = SyntaxEx.CompilationUnit( SyntaxEx.NamespaceDeclaration(Wiki.EntitiesNamespace, resultType), "System", "System.Linq", "System.Globalization", "System.Xml.Linq", "LinqToWiki", "LinqToWiki.Internals"); Wiki.Files.Add(ClassNameBase, codeUnit); } m_listResult = module.ListResult; GenerateMethod(module); }
/// <summary> /// Creates class that is used in the <c>where</c> clause. /// </summary> private ClassDeclarationSyntax GenerateWhere(IEnumerable <Parameter> parameters) { var propertyDeclarations = parameters.Select(p => GenerateProperty(p.Name, p.Type, multi: p.Multi, description: p.Description)); return(SyntaxEx.ClassDeclaration(m_whereClassName, propertyDeclarations) .AddPrivateConstructor()); }
/// <summary> /// Creates the property that can used to access the information from the given module. /// </summary> private PropertyDeclarationSyntax CreateProperty(Module module) { var summary = SyntaxEx.DocumentationSummary(module.Description); return(SyntaxEx.AutoPropertyDeclaration( new[] { SyntaxKind.PublicKeyword, SyntaxKind.AbstractKeyword }, GenerateMethodResultType(), ClassNameBase, isAbstract: true, setModifier: SyntaxKind.PrivateKeyword) .WithLeadingTrivia(Syntax.Trivia(SyntaxEx.DocumentationComment(summary)))); }
/// <summary> /// Creates a class for a set of properties. /// </summary> protected ClassDeclarationSyntax GenerateClassForProperties(string className, IEnumerable <Property> properties, string baseType = null) { var propertiesArray = properties.ToArray(); return(SyntaxEx.ClassDeclaration( className, baseType == null ? null : SyntaxFactory.ParseTypeName(baseType), propertiesArray.Select(p => GenerateProperty(p.Name, p.Type, p.Nullable))) .AddPrivateConstructor() .AddMembers( GenerateParseMethod(className, propertiesArray), GenerateToStringMethod(propertiesArray))); }
protected override IList <StatementSyntax> GenerateMethodBody( ExpressionSyntax queryProcessor, ExpressionSyntax queryParameters, IList <StatementSyntax> statements) { var invocation = SyntaxEx.Invocation( SyntaxEx.MemberAccess(queryProcessor, m_listResult ? "ExecuteList" : "ExecuteSingle"), queryParameters); var statement = m_voidResult ? (StatementSyntax)Syntax.ExpressionStatement(invocation) : SyntaxEx.Return(invocation); statements.Add(statement); return(statements); }
/// <summary> /// Generates a single property. /// </summary> protected PropertyDeclarationSyntax GenerateProperty( string name, ParameterType type, bool nullable = false, string description = null, bool multi = false) { var result = SyntaxEx.AutoPropertyDeclaration( new[] { SyntaxKind.PublicKeyword }, Wiki.TypeManager.GetTypeName(type, FixPropertyName(name), ClassNameBase, multi, nullable), GetPropertyName(name), SyntaxKind.PrivateKeyword); if (description != null) { result = result.WithDocumentationSummary(description); } return(result); }
protected override TypeSyntax GenerateMethodResultType() { if (m_voidResult) { return(Syntax.ParseTypeName("void")); } var resultType = Syntax.ParseTypeName(ResultClassName); if (m_listResult) { resultType = SyntaxEx.GenericName("IEnumerable", resultType); } return(resultType); }
/// <summary> /// Creates an overide of the <see cref="object.ToString"/> method for given properties. /// </summary> private static MethodDeclarationSyntax GenerateToStringMethod(IEnumerable <Property> properties) { var formatString = string.Join( "; ", properties.Select((p, i) => string.Format("{0}: {{{1}}}", GetPropertyName(p.Name, false), i))); var parameters = new List <ExpressionSyntax> { SyntaxEx.Literal(formatString) }; parameters.AddRange(properties.Select(p => SyntaxFactory.IdentifierName(GetPropertyName(p.Name)))); var returnStatement = SyntaxEx.Return(SyntaxEx.Invocation(SyntaxEx.MemberAccess("string", "Format"), parameters)); return(SyntaxEx.MethodDeclaration( new[] { SyntaxKind.PublicKeyword, SyntaxKind.OverrideKeyword }, "string", "ToString", null, returnStatement)); }
/// <summary> /// Creates a field that holds information about property groups for the given module. /// </summary> protected FieldDeclarationSyntax CreatePropsField(IEnumerable <PropertyGroup> propertyGroups) { var initializers = from pg in propertyGroups from p in pg.Properties group pg.Name by p.Name into g select new[] { SyntaxEx.Literal(g.Key), SyntaxEx.ArrayCreation(null, g.Select(SyntaxEx.Literal)) }; var propsInitializer = SyntaxEx.ObjectCreation("Dictionary<string, string[]>", null, initializers); var propsField = SyntaxEx.FieldDeclaration( new[] { SyntaxKind.PrivateKeyword, SyntaxKind.StaticKeyword, SyntaxKind.ReadOnlyKeyword }, "IDictionary<string, string[]>", ClassNameBase + "Props", propsInitializer); return(propsField); }
/// <summary> /// Creates class that is ised in the <c>orderby</c> clause. /// Returns <c>null</c>, if the module doesn't support sorting. /// </summary> private ClassDeclarationSyntax GenerateOrderBy(IEnumerable <Parameter> parameters, IEnumerable <Property> properties) { var propertyTypes = properties.Distinct().ToDictionary(p => p.Name, p => p.Type); var sortParameter = parameters.SingleOrDefault(p => p.Name == "sort"); if (!parameters.Any(p => p.Name == "dir")) { return(null); } IEnumerable <PropertyDeclarationSyntax> propertyDeclarations = null; if (sortParameter != null) { propertyDeclarations = ((EnumParameterType)sortParameter.Type).Values.Select(v => GenerateProperty(v, propertyTypes[v])); } return(SyntaxEx.ClassDeclaration(m_orderByClassName, propertyDeclarations) .AddPrivateConstructor()); }
protected override ClassDeclarationSyntax GenerateResultClass(IEnumerable <PropertyGroup> propertyGroups) { var resultClass = GenerateClassForProperties(ResultClassName, propertyGroups.SelectMany(g => g.Properties)); var parseMethodBody = resultClass.DescendantNodes() .OfType <MethodDeclarationSyntax>() .Single(m => m.Identifier.ValueText == "Parse") .Body; var statements = parseMethodBody.Statements; var newStatement = SyntaxEx.Assignment( SyntaxFactory.IdentifierName("element"), SyntaxEx.Invocation( SyntaxEx.MemberAccess(SyntaxEx.Invocation(SyntaxEx.MemberAccess("element", "Elements")), "Single"))); var newStatements = new[] { newStatement }.Concat(statements); var newBody = SyntaxEx.Block(newStatements); return(resultClass.ReplaceNode(parseMethodBody, newBody)); }
/// <summary> /// Creates an expression that creates the <see cref="LinqToWiki.Collections.TupleList{T1,T2}"/> /// that is passed as a parameter. /// </summary> private static ObjectCreationExpressionSyntax CreateTupleListExpression(IEnumerable <Tuple <string, string> > tupleList) { return(SyntaxEx.ObjectCreation( "TupleList<string, string>", null, tupleList.Select(t => new[] { t.Item1, t.Item2 }.Select(SyntaxEx.Literal)))); }
protected override IList <StatementSyntax> GenerateMethodBody( ExpressionSyntax queryProcessor, ExpressionSyntax queryParameters, IList <StatementSyntax> statements) { statements.Add(SyntaxEx.Return(SyntaxEx.ObjectCreation(m_queryType, queryProcessor, queryParameters))); return(statements); }
/// <summary> /// Creates an entry method, that is used to execute query for normal modules /// or that can be used as a base for a query for query modules. /// </summary> protected void GenerateMethod( Module module, IEnumerable <Parameter> methodParameters, string resultClassName, FieldDeclarationSyntax propsField, string fileName, bool nullableParameters, SortType?sortType) { var propertiesField = CreatePropertiesField(module, resultClassName, propsField, sortType); ExpressionSyntax queryParameters = SyntaxEx.Invocation( SyntaxEx.MemberAccess("QueryParameters", SyntaxEx.GenericName("Create", resultClassName))); var queryParametersLocal = SyntaxEx.LocalDeclaration("var", "queryParameters", queryParameters); var documentationElements = new List <XmlElementSyntax>(); var summary = SyntaxEx.DocumentationSummary(module.Description); documentationElements.Add(summary); var parameters = new List <ParameterSyntax>(); IList <StatementSyntax> statements = new List <StatementSyntax>(); statements.Add(queryParametersLocal); methodParameters = methodParameters .Where(p => !p.Deprecated) .Where(p => p.Name != "continue") .OrderByDescending(p => p.Required); foreach (var methodParameter in methodParameters) { var nullable = nullableParameters && !methodParameter.Required; var typeName = Wiki.TypeManager.GetTypeName(methodParameter, ClassNameBase, nullable, false); var parameterName = GetPropertyName(methodParameter.Name); // this type cannot be processed if (typeName == null) { continue; } var parameter = SyntaxEx.Parameter(typeName, parameterName, nullable ? SyntaxEx.NullLiteral() : null); parameters.Add(parameter); ExpressionSyntax valueExpression = (NamedNode)parameter; if (nullable && typeName.EndsWith("?")) { valueExpression = SyntaxEx.MemberAccess(valueExpression, "Value"); } ExpressionSyntax newQueryParameters; if (typeName == "System.IO.Stream") { newQueryParameters = SyntaxEx.Invocation( SyntaxEx.MemberAccess(queryParametersLocal, "AddFile"), SyntaxEx.Literal(methodParameter.Name), valueExpression); } else { newQueryParameters = SyntaxEx.Invocation( SyntaxEx.MemberAccess(queryParametersLocal, "AddSingleValue"), SyntaxEx.Literal(methodParameter.Name), SyntaxEx.Invocation(SyntaxEx.MemberAccess(valueExpression, "ToQueryString"))); } var queryParametersAssignment = SyntaxEx.Assignment(queryParametersLocal, newQueryParameters); if (nullable) { var assignmentWithCheck = SyntaxEx.If( SyntaxEx.NotEquals((NamedNode)parameter, SyntaxEx.NullLiteral()), queryParametersAssignment); statements.Add(assignmentWithCheck); } else { statements.Add(queryParametersAssignment); } var parameterDocumentation = SyntaxEx.DocumentationParameter(parameterName, methodParameter.Description); documentationElements.Add(parameterDocumentation); } statements = GenerateMethodBody( SyntaxEx.ObjectCreation( SyntaxEx.GenericName("QueryProcessor", resultClassName), SyntaxFactory.IdentifierName("m_wiki"), (NamedNode)propertiesField), (NamedNode)queryParametersLocal, statements); var modifiers = new List <SyntaxKind> { SyntaxKind.PublicKeyword }; if (statements == null) { modifiers.Add(SyntaxKind.AbstractKeyword); } var method = SyntaxEx.MethodDeclaration( modifiers, GenerateMethodResultType(), ClassNameBase, parameters, statements) .WithLeadingTrivia(SyntaxFactory.Trivia(SyntaxEx.DocumentationComment(documentationElements))); AddMembersToClass(fileName, propertiesField, method); }
protected override void GenerateInternal(Module module) { m_selectClassName = ClassNameBase + "Select"; m_whereClassName = ClassNameBase + "Where"; m_orderByClassName = ClassNameBase + "OrderBy"; var parameters = module.Parameters.ToList(); var sortParameters = RemoveAndReturnByNames(parameters, "sort", "dir"); var methodParameters = parameters.RemoveAndReturn(p => p.Required); // don't belong anywhere, are used in a special way RemoveAndReturnByNames(parameters, "continue", "offset", "limit", "prop"); var whereParameters = parameters; var selectClass = GenerateSelect(module.PropertyGroups, module.Name == "revisions"); var whereClass = GenerateWhere(whereParameters); var orderByClass = GenerateOrderBy(sortParameters, module.PropertyGroups.SelectMany(g => g.Properties)); var codeUnit = SyntaxEx.CompilationUnit( SyntaxEx.NamespaceDeclaration(Wiki.EntitiesNamespace, selectClass, whereClass, orderByClass), "System", "System.Globalization", "System.Xml.Linq", "LinqToWiki", "LinqToWiki.Collections", "LinqToWiki.Internals"); Wiki.Files.Add(ClassNameBase, codeUnit); string queryTypeName = "WikiQuery"; var queryTypeGenericParameters = new List <string> { m_whereClassName, m_selectClassName }; if (orderByClass != null) { queryTypeName += "Sortable"; queryTypeGenericParameters.Insert(1, m_orderByClassName); } if (module.Generator) { queryTypeName += "Generator"; queryTypeGenericParameters.Insert(0, Wiki.Names.Page); } m_queryType = SyntaxEx.GenericName(queryTypeName, queryTypeGenericParameters); SortType?sortType = null; var dirParameter = sortParameters.SingleOrDefault(p => p.Name == "dir"); if (dirParameter != null) { var type = (EnumParameterType)dirParameter.Type; if (type.Values.Any(x => x == "ascending")) { sortType = SortType.Ascending; } else if (type.Values.Any(x => x == "newer")) { sortType = SortType.Newer; } } GenerateMethod(module, methodParameters, m_selectClassName, m_selectProps, MethodClassName, false, sortType); }
/// <summary> /// Creates a method that parses an XML element returned from the API by setting creating an instance /// of the given class and setting its properties. /// </summary> private MethodDeclarationSyntax GenerateParseMethod(string className, IEnumerable <Property> properties) { var elementParameter = SyntaxEx.Parameter("XElement", "element"); var wikiParameter = SyntaxEx.Parameter("WikiInfo", "wiki"); var statements = new List <StatementSyntax>(); var resultLocal = SyntaxEx.LocalDeclaration("var", "result", SyntaxEx.ObjectCreation(className)); statements.Add(resultLocal); foreach (var property in properties) { ExpressionSyntax propertyValueAccess; bool checkForNull; if (property.Name == "*") { propertyValueAccess = (NamedNode)elementParameter; checkForNull = false; } else { propertyValueAccess = SyntaxEx.Invocation( SyntaxEx.MemberAccess(elementParameter, "Attribute"), SyntaxEx.Literal(property.Name)); checkForNull = true; } var propertyValueLocal = SyntaxEx.LocalDeclaration( "var", GetPropertyName(property.Name, false) + "Value", propertyValueAccess); statements.Add(propertyValueLocal); var valueValue = SyntaxEx.MemberAccess(propertyValueLocal, "Value"); var assignment = SyntaxEx.Assignment( SyntaxEx.MemberAccess(resultLocal, GetPropertyName(property.Name)), Wiki.TypeManager.CreateConverter( property, ClassNameBase, valueValue, (NamedNode)wikiParameter)); if (checkForNull) { ExpressionSyntax condition = SyntaxEx.NotEquals((NamedNode)propertyValueLocal, SyntaxEx.NullLiteral()); var simpleType = property.Type as SimpleParameterType; if (simpleType == null || (simpleType.Name != "string" && simpleType.Name != "boolean")) { condition = SyntaxEx.And( condition, SyntaxEx.NotEquals(valueValue, SyntaxEx.Literal(""))); } var ifStatement = SyntaxEx.If(condition, assignment); statements.Add(ifStatement); } else { statements.Add(assignment); } } statements.Add(SyntaxEx.Return(resultLocal)); return(SyntaxEx.MethodDeclaration( new[] { SyntaxKind.PublicKeyword, SyntaxKind.StaticKeyword }, className, "Parse", new[] { elementParameter, wikiParameter }, statements)); }