using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Text; using ICSharpCode.NRefactory.PatternMatching; namespace ICSharpCode.NRefactory.CSharp { public class QueryExpressionExpansionResult { public AstNode AstNode { get; private set; } /// /// Maps original range variables to some node in the new tree that represents them. /// public IDictionary RangeVariables { get; private set; } /// /// Maps clauses to method calls. The keys will always be either a or a /// public IDictionary Expressions { get; private set; } public QueryExpressionExpansionResult(AstNode astNode, IDictionary rangeVariables, IDictionary expressions) { AstNode = astNode; RangeVariables = rangeVariables; Expressions = expressions; } } public class QueryExpressionExpander { class Visitor : IAstVisitor { int currentTransparentParameter; const string TransparentParameterNameTemplate = "<>x{0}"; AstNode Default(AstNode node) { List newChildren = null; int i = 0; foreach (var child in node.Children) { var newChild = child.AcceptVisitor(this); if (newChild != null) { newChildren = newChildren ?? Enumerable.Repeat((AstNode)null, i).ToList(); newChildren.Add(newChild); } else if (newChildren != null) { newChildren.Add(null); } i++; } if (newChildren == null) return null; var result = node.Clone(); i = 0; foreach (var children in result.Children) { if (newChildren[i] != null) children.ReplaceWith(newChildren[i]); i++; } return result; } Expression MakeNestedMemberAccess(Expression target, IEnumerable members) { return members.Aggregate(target, (current, m) => current.Member(m)); } Expression VisitNested(Expression node, ParameterDeclaration transparentParameter) { var oldRangeVariableSubstitutions = activeRangeVariableSubstitutions; try { if (transparentParameter != null && currentTransparentType.Count > 1) { activeRangeVariableSubstitutions = new Dictionary(activeRangeVariableSubstitutions); foreach (var t in currentTransparentType) activeRangeVariableSubstitutions[t.Item1.Name] = MakeNestedMemberAccess(new IdentifierExpression(transparentParameter.Name), t.Item2); } var result = node.AcceptVisitor(this); return (Expression)(result ?? node.Clone()); } finally { activeRangeVariableSubstitutions = oldRangeVariableSubstitutions; } } QueryClause GetNextQueryClause(QueryClause clause) { for (AstNode node = clause.NextSibling; node != null; node = node.NextSibling) { if (node.Role == QueryExpression.ClauseRole) return (QueryClause)node; } return null; } public IDictionary rangeVariables = new Dictionary(); public IDictionary expressions = new Dictionary(); Dictionary activeRangeVariableSubstitutions = new Dictionary(); List>> currentTransparentType = new List>>(); Expression currentResult; bool eatSelect; void MapExpression(AstNode orig, Expression newExpr) { Debug.Assert(orig is QueryClause || orig is QueryOrdering); expressions[orig] = newExpr; } ParameterDeclaration CreateParameterForCurrentRangeVariable() { var param = new ParameterDeclaration(); if (currentTransparentType.Count == 1) { var clonedRangeVariable = (Identifier)currentTransparentType[0].Item1.Clone(); if (!rangeVariables.ContainsKey(currentTransparentType[0].Item1)) rangeVariables[currentTransparentType[0].Item1] = clonedRangeVariable; param.AddChild(clonedRangeVariable, Roles.Identifier); } else { param.AddChild(Identifier.Create(string.Format(CultureInfo.InvariantCulture, TransparentParameterNameTemplate, currentTransparentParameter++)), Roles.Identifier); } return param; } LambdaExpression CreateLambda(IList parameters, Expression body) { var result = new LambdaExpression(); if (parameters.Count > 1) result.AddChild(new CSharpTokenNode(TextLocation.Empty), Roles.LPar); result.AddChild(parameters[0], Roles.Parameter); for (int i = 1; i < parameters.Count; i++) { result.AddChild(new CSharpTokenNode(TextLocation.Empty), Roles.Comma); result.AddChild(parameters[i], Roles.Parameter); } if (parameters.Count > 1) result.AddChild(new CSharpTokenNode(TextLocation.Empty), Roles.RPar); result.AddChild(body, LambdaExpression.BodyRole); return result; } ParameterDeclaration CreateParameter(Identifier identifier) { var result = new ParameterDeclaration(); result.AddChild(identifier, Roles.Identifier); return result; } Expression AddMemberToCurrentTransparentType(ParameterDeclaration param, Identifier name, Expression value, bool namedExpression) { Expression newAssignment = VisitNested(value, param); if (namedExpression) { newAssignment = new NamedExpression(name.Name, VisitNested(value, param)); if (!rangeVariables.ContainsKey(name) ) rangeVariables[name] = ((NamedExpression)newAssignment).NameToken; } foreach (var t in currentTransparentType) t.Item2.Insert(0, param.Name); currentTransparentType.Add(Tuple.Create(name, new List { name.Name })); return new AnonymousTypeCreateExpression(new[] { new IdentifierExpression(param.Name), newAssignment }); } void AddFirstMemberToCurrentTransparentType(Identifier identifier) { Debug.Assert(currentTransparentType.Count == 0); currentTransparentType.Add(Tuple.Create(identifier, new List())); } AstNode IAstVisitor.VisitQueryExpression(QueryExpression queryExpression) { var oldTransparentType = currentTransparentType; var oldResult = currentResult; var oldEatSelect = eatSelect; try { currentTransparentType = new List>>(); currentResult = null; eatSelect = false; foreach (var clause in queryExpression.Clauses) { var result = (Expression)clause.AcceptVisitor(this); MapExpression(clause, result ?? currentResult); currentResult = result; } return currentResult; } finally { currentTransparentType = oldTransparentType; currentResult = oldResult; eatSelect = oldEatSelect; } } AstNode IAstVisitor.VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause) { var prev = VisitNested(queryContinuationClause.PrecedingQuery, null); AddFirstMemberToCurrentTransparentType(queryContinuationClause.IdentifierToken); return prev; } AstNode IAstVisitor.VisitQueryFromClause(QueryFromClause queryFromClause) { if (currentResult == null) { AddFirstMemberToCurrentTransparentType(queryFromClause.IdentifierToken); if (queryFromClause.Type.IsNull) { return VisitNested(queryFromClause.Expression, null); } else { return VisitNested(queryFromClause.Expression, null).Invoke("Cast", new[] { queryFromClause.Type.Clone() }, new Expression[0]); } } else { var innerSelectorParam = CreateParameterForCurrentRangeVariable(); var innerSelector = CreateLambda(new[] { innerSelectorParam }, VisitNested(queryFromClause.Expression, innerSelectorParam)); var clonedIdentifier = (Identifier)queryFromClause.IdentifierToken.Clone(); var resultParam = CreateParameterForCurrentRangeVariable(); Expression body; // Second from clause - SelectMany var select = GetNextQueryClause(queryFromClause) as QuerySelectClause; if (select != null) { body = VisitNested(select.Expression, resultParam); eatSelect = true; } else { body = AddMemberToCurrentTransparentType(resultParam, queryFromClause.IdentifierToken, new IdentifierExpression(queryFromClause.Identifier), false); } var resultSelector = CreateLambda(new[] { resultParam, CreateParameter(clonedIdentifier) }, body); rangeVariables[queryFromClause.IdentifierToken] = clonedIdentifier; return currentResult.Invoke("SelectMany", innerSelector, resultSelector); } } AstNode IAstVisitor.VisitQueryLetClause(QueryLetClause queryLetClause) { var param = CreateParameterForCurrentRangeVariable(); var body = AddMemberToCurrentTransparentType(param, queryLetClause.IdentifierToken, queryLetClause.Expression, true); var lambda = CreateLambda(new[] { param }, body); return currentResult.Invoke("Select", lambda); } AstNode IAstVisitor.VisitQueryWhereClause(QueryWhereClause queryWhereClause) { var param = CreateParameterForCurrentRangeVariable(); return currentResult.Invoke("Where", CreateLambda(new[] { param }, VisitNested(queryWhereClause.Condition, param))); } AstNode IAstVisitor.VisitQueryJoinClause(QueryJoinClause queryJoinClause) { Expression resultSelectorBody = null; var inExpression = VisitNested(queryJoinClause.InExpression, null); var key1SelectorFirstParam = CreateParameterForCurrentRangeVariable(); var key1Selector = CreateLambda(new[] { key1SelectorFirstParam }, VisitNested(queryJoinClause.OnExpression, key1SelectorFirstParam)); var key2Param = Identifier.Create(queryJoinClause.JoinIdentifier); var key2Selector = CreateLambda(new[] { CreateParameter(key2Param) }, VisitNested(queryJoinClause.EqualsExpression, null)); var resultSelectorFirstParam = CreateParameterForCurrentRangeVariable(); var select = GetNextQueryClause(queryJoinClause) as QuerySelectClause; if (select != null) { resultSelectorBody = VisitNested(select.Expression, resultSelectorFirstParam); eatSelect = true; } if (queryJoinClause.IntoKeyword.IsNull) { // Normal join if (resultSelectorBody == null) resultSelectorBody = AddMemberToCurrentTransparentType(resultSelectorFirstParam, queryJoinClause.JoinIdentifierToken, new IdentifierExpression(queryJoinClause.JoinIdentifier), false); var resultSelector = CreateLambda(new[] { resultSelectorFirstParam, CreateParameter(Identifier.Create(queryJoinClause.JoinIdentifier)) }, resultSelectorBody); rangeVariables[queryJoinClause.JoinIdentifierToken] = key2Param; return currentResult.Invoke("Join", inExpression, key1Selector, key2Selector, resultSelector); } else { // Group join if (resultSelectorBody == null) resultSelectorBody = AddMemberToCurrentTransparentType(resultSelectorFirstParam, queryJoinClause.IntoIdentifierToken, new IdentifierExpression(queryJoinClause.IntoIdentifier), false); var intoParam = Identifier.Create(queryJoinClause.IntoIdentifier); var resultSelector = CreateLambda(new[] { resultSelectorFirstParam, CreateParameter(intoParam) }, resultSelectorBody); rangeVariables[queryJoinClause.IntoIdentifierToken] = intoParam; return currentResult.Invoke("GroupJoin", inExpression, key1Selector, key2Selector, resultSelector); } } AstNode IAstVisitor.VisitQueryOrderClause(QueryOrderClause queryOrderClause) { var current = currentResult; bool first = true; foreach (var o in queryOrderClause.Orderings) { string methodName = first ? (o.Direction == QueryOrderingDirection.Descending ? "OrderByDescending" : "OrderBy") : (o.Direction == QueryOrderingDirection.Descending ? "ThenByDescending" : "ThenBy"); var param = CreateParameterForCurrentRangeVariable(); current = current.Invoke(methodName, CreateLambda(new[] { param }, VisitNested(o.Expression, param))); MapExpression(o, current); first = false; } return current; } AstNode IAstVisitor.VisitQueryOrdering(QueryOrdering queryOrdering) { return null; } AstNode IAstVisitor.VisitQuerySelectClause(QuerySelectClause querySelectClause) { if (eatSelect) { eatSelect = false; return currentResult; } else if (currentTransparentType.Count == 1 && ((QueryExpression)querySelectClause.Parent).Clauses.Count > 2 && querySelectClause.Expression is IdentifierExpression && ((IdentifierExpression)querySelectClause.Expression).Identifier == currentTransparentType[0].Item1.Name) { // A simple query that ends with a trivial select should be removed. return currentResult; } var param = CreateParameterForCurrentRangeVariable(); var lambda = CreateLambda(new[] { param }, VisitNested(querySelectClause.Expression, param)); return currentResult.Invoke("Select", lambda); } AstNode IAstVisitor.VisitQueryGroupClause(QueryGroupClause queryGroupClause) { var param = CreateParameterForCurrentRangeVariable(); var keyLambda = CreateLambda(new[] { param }, VisitNested(queryGroupClause.Key, param)); if (currentTransparentType.Count == 1 && queryGroupClause.Projection is IdentifierExpression && ((IdentifierExpression)queryGroupClause.Projection).Identifier == currentTransparentType[0].Item1.Name) { // We are grouping by the single active range variable, so we can use the single argument form of GroupBy return currentResult.Invoke("GroupBy", keyLambda); } else { var projectionParam = CreateParameterForCurrentRangeVariable(); var projectionLambda = CreateLambda(new[] { projectionParam }, VisitNested(queryGroupClause.Projection, projectionParam)); return currentResult.Invoke("GroupBy", keyLambda, projectionLambda); } } AstNode IAstVisitor.VisitIdentifierExpression(IdentifierExpression identifierExpression) { Expression subst; activeRangeVariableSubstitutions.TryGetValue(identifierExpression.Identifier, out subst); return subst != null ? subst.Clone() : null; } #region Uninteresting methods AstNode IAstVisitor.VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression) { return Default(anonymousMethodExpression); } AstNode IAstVisitor.VisitUndocumentedExpression(UndocumentedExpression undocumentedExpression) { return Default(undocumentedExpression); } AstNode IAstVisitor.VisitArrayCreateExpression(ArrayCreateExpression arrayCreateExpression) { return Default(arrayCreateExpression); } AstNode IAstVisitor.VisitArrayInitializerExpression(ArrayInitializerExpression arrayInitializerExpression) { return Default(arrayInitializerExpression); } AstNode IAstVisitor.VisitAsExpression(AsExpression asExpression) { return Default(asExpression); } AstNode IAstVisitor.VisitAssignmentExpression(AssignmentExpression assignmentExpression) { return Default(assignmentExpression); } AstNode IAstVisitor.VisitBaseReferenceExpression(BaseReferenceExpression baseReferenceExpression) { return Default(baseReferenceExpression); } AstNode IAstVisitor.VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression) { return Default(binaryOperatorExpression); } AstNode IAstVisitor.VisitCastExpression(CastExpression castExpression) { return Default(castExpression); } AstNode IAstVisitor.VisitCheckedExpression(CheckedExpression checkedExpression) { return Default(checkedExpression); } AstNode IAstVisitor.VisitConditionalExpression(ConditionalExpression conditionalExpression) { return Default(conditionalExpression); } AstNode IAstVisitor.VisitDefaultValueExpression(DefaultValueExpression defaultValueExpression) { return Default(defaultValueExpression); } AstNode IAstVisitor.VisitDirectionExpression(DirectionExpression directionExpression) { return Default(directionExpression); } AstNode IAstVisitor.VisitIndexerExpression(IndexerExpression indexerExpression) { return Default(indexerExpression); } AstNode IAstVisitor.VisitInvocationExpression(InvocationExpression invocationExpression) { return Default(invocationExpression); } AstNode IAstVisitor.VisitIsExpression(IsExpression isExpression) { return Default(isExpression); } AstNode IAstVisitor.VisitLambdaExpression(LambdaExpression lambdaExpression) { return Default(lambdaExpression); } AstNode IAstVisitor.VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression) { return Default(memberReferenceExpression); } AstNode IAstVisitor.VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression) { return Default(namedArgumentExpression); } AstNode IAstVisitor.VisitNamedExpression(NamedExpression namedExpression) { return Default(namedExpression); } AstNode IAstVisitor.VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression) { return Default(nullReferenceExpression); } AstNode IAstVisitor.VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression) { return Default(objectCreateExpression); } AstNode IAstVisitor.VisitAnonymousTypeCreateExpression(AnonymousTypeCreateExpression anonymousTypeCreateExpression) { return Default(anonymousTypeCreateExpression); } AstNode IAstVisitor.VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression) { return Default(parenthesizedExpression); } AstNode IAstVisitor.VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression) { return Default(pointerReferenceExpression); } AstNode IAstVisitor.VisitPrimitiveExpression(PrimitiveExpression primitiveExpression) { return Default(primitiveExpression); } AstNode IAstVisitor.VisitSizeOfExpression(SizeOfExpression sizeOfExpression) { return Default(sizeOfExpression); } AstNode IAstVisitor.VisitStackAllocExpression(StackAllocExpression stackAllocExpression) { return Default(stackAllocExpression); } AstNode IAstVisitor.VisitThisReferenceExpression(ThisReferenceExpression thisReferenceExpression) { return Default(thisReferenceExpression); } AstNode IAstVisitor.VisitTypeOfExpression(TypeOfExpression typeOfExpression) { return Default(typeOfExpression); } AstNode IAstVisitor.VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression) { return Default(typeReferenceExpression); } AstNode IAstVisitor.VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression) { return Default(unaryOperatorExpression); } AstNode IAstVisitor.VisitUncheckedExpression(UncheckedExpression uncheckedExpression) { return Default(uncheckedExpression); } AstNode IAstVisitor.VisitEmptyExpression(EmptyExpression emptyExpression) { return Default(emptyExpression); } AstNode IAstVisitor.VisitAttribute(Attribute attribute) { return Default(attribute); } AstNode IAstVisitor.VisitAttributeSection(AttributeSection attributeSection) { return Default(attributeSection); } AstNode IAstVisitor.VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration) { return Default(delegateDeclaration); } AstNode IAstVisitor.VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration) { return Default(namespaceDeclaration); } AstNode IAstVisitor.VisitTypeDeclaration(TypeDeclaration typeDeclaration) { return Default(typeDeclaration); } AstNode IAstVisitor.VisitUsingAliasDeclaration(UsingAliasDeclaration usingAliasDeclaration) { return Default(usingAliasDeclaration); } AstNode IAstVisitor.VisitUsingDeclaration(UsingDeclaration usingDeclaration) { return Default(usingDeclaration); } AstNode IAstVisitor.VisitExternAliasDeclaration(ExternAliasDeclaration externAliasDeclaration) { return Default(externAliasDeclaration); } AstNode IAstVisitor.VisitBlockStatement(BlockStatement blockStatement) { return Default(blockStatement); } AstNode IAstVisitor.VisitBreakStatement(BreakStatement breakStatement) { return Default(breakStatement); } AstNode IAstVisitor.VisitCheckedStatement(CheckedStatement checkedStatement) { return Default(checkedStatement); } AstNode IAstVisitor.VisitContinueStatement(ContinueStatement continueStatement) { return Default(continueStatement); } AstNode IAstVisitor.VisitDoWhileStatement(DoWhileStatement doWhileStatement) { return Default(doWhileStatement); } AstNode IAstVisitor.VisitEmptyStatement(EmptyStatement emptyStatement) { return Default(emptyStatement); } AstNode IAstVisitor.VisitExpressionStatement(ExpressionStatement expressionStatement) { return Default(expressionStatement); } AstNode IAstVisitor.VisitFixedStatement(FixedStatement fixedStatement) { return Default(fixedStatement); } AstNode IAstVisitor.VisitForeachStatement(ForeachStatement foreachStatement) { return Default(foreachStatement); } AstNode IAstVisitor.VisitForStatement(ForStatement forStatement) { return Default(forStatement); } AstNode IAstVisitor.VisitGotoCaseStatement(GotoCaseStatement gotoCaseStatement) { return Default(gotoCaseStatement); } AstNode IAstVisitor.VisitGotoDefaultStatement(GotoDefaultStatement gotoDefaultStatement) { return Default(gotoDefaultStatement); } AstNode IAstVisitor.VisitGotoStatement(GotoStatement gotoStatement) { return Default(gotoStatement); } AstNode IAstVisitor.VisitIfElseStatement(IfElseStatement ifElseStatement) { return Default(ifElseStatement); } AstNode IAstVisitor.VisitLabelStatement(LabelStatement labelStatement) { return Default(labelStatement); } AstNode IAstVisitor.VisitLockStatement(LockStatement lockStatement) { return Default(lockStatement); } AstNode IAstVisitor.VisitReturnStatement(ReturnStatement returnStatement) { return Default(returnStatement); } AstNode IAstVisitor.VisitSwitchStatement(SwitchStatement switchStatement) { return Default(switchStatement); } AstNode IAstVisitor.VisitSwitchSection(SwitchSection switchSection) { return Default(switchSection); } AstNode IAstVisitor.VisitCaseLabel(CaseLabel caseLabel) { return Default(caseLabel); } AstNode IAstVisitor.VisitThrowStatement(ThrowStatement throwStatement) { return Default(throwStatement); } AstNode IAstVisitor.VisitTryCatchStatement(TryCatchStatement tryCatchStatement) { return Default(tryCatchStatement); } AstNode IAstVisitor.VisitCatchClause(CatchClause catchClause) { return Default(catchClause); } AstNode IAstVisitor.VisitUncheckedStatement(UncheckedStatement uncheckedStatement) { return Default(uncheckedStatement); } AstNode IAstVisitor.VisitUnsafeStatement(UnsafeStatement unsafeStatement) { return Default(unsafeStatement); } AstNode IAstVisitor.VisitUsingStatement(UsingStatement usingStatement) { return Default(usingStatement); } AstNode IAstVisitor.VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement) { return Default(variableDeclarationStatement); } AstNode IAstVisitor.VisitWhileStatement(WhileStatement whileStatement) { return Default(whileStatement); } AstNode IAstVisitor.VisitYieldBreakStatement(YieldBreakStatement yieldBreakStatement) { return Default(yieldBreakStatement); } AstNode IAstVisitor.VisitYieldReturnStatement(YieldReturnStatement yieldReturnStatement) { return Default(yieldReturnStatement); } AstNode IAstVisitor.VisitAccessor(Accessor accessor) { return Default(accessor); } AstNode IAstVisitor.VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration) { return Default(constructorDeclaration); } AstNode IAstVisitor.VisitConstructorInitializer(ConstructorInitializer constructorInitializer) { return Default(constructorInitializer); } AstNode IAstVisitor.VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration) { return Default(destructorDeclaration); } AstNode IAstVisitor.VisitEnumMemberDeclaration(EnumMemberDeclaration enumMemberDeclaration) { return Default(enumMemberDeclaration); } AstNode IAstVisitor.VisitEventDeclaration(EventDeclaration eventDeclaration) { return Default(eventDeclaration); } AstNode IAstVisitor.VisitCustomEventDeclaration(CustomEventDeclaration customEventDeclaration) { return Default(customEventDeclaration); } AstNode IAstVisitor.VisitFieldDeclaration(FieldDeclaration fieldDeclaration) { return Default(fieldDeclaration); } AstNode IAstVisitor.VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration) { return Default(indexerDeclaration); } AstNode IAstVisitor.VisitMethodDeclaration(MethodDeclaration methodDeclaration) { return Default(methodDeclaration); } AstNode IAstVisitor.VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration) { return Default(operatorDeclaration); } AstNode IAstVisitor.VisitParameterDeclaration(ParameterDeclaration parameterDeclaration) { return Default(parameterDeclaration); } AstNode IAstVisitor.VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration) { return Default(propertyDeclaration); } AstNode IAstVisitor.VisitVariableInitializer(VariableInitializer variableInitializer) { return Default(variableInitializer); } AstNode IAstVisitor.VisitFixedFieldDeclaration(FixedFieldDeclaration fixedFieldDeclaration) { return Default(fixedFieldDeclaration); } AstNode IAstVisitor.VisitFixedVariableInitializer(FixedVariableInitializer fixedVariableInitializer) { return Default(fixedVariableInitializer); } AstNode IAstVisitor.VisitCompilationUnit(CompilationUnit compilationUnit) { return Default(compilationUnit); } AstNode IAstVisitor.VisitSimpleType(SimpleType simpleType) { return Default(simpleType); } AstNode IAstVisitor.VisitMemberType(MemberType memberType) { return Default(memberType); } AstNode IAstVisitor.VisitComposedType(ComposedType composedType) { return Default(composedType); } AstNode IAstVisitor.VisitArraySpecifier(ArraySpecifier arraySpecifier) { return Default(arraySpecifier); } AstNode IAstVisitor.VisitPrimitiveType(PrimitiveType primitiveType) { return Default(primitiveType); } AstNode IAstVisitor.VisitComment(Comment comment) { return Default(comment); } AstNode IAstVisitor.VisitWhitespace(WhitespaceNode whitespaceNode) { return Default(whitespaceNode); } AstNode IAstVisitor.VisitText(TextNode textNode) { return Default(textNode); } AstNode IAstVisitor.VisitNewLine(NewLineNode newLineNode) { return Default(newLineNode); } AstNode IAstVisitor.VisitPreProcessorDirective(PreProcessorDirective preProcessorDirective) { return Default(preProcessorDirective); } AstNode IAstVisitor.VisitDocumentationReference(DocumentationReference documentationReference) { return Default(documentationReference); } AstNode IAstVisitor.VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration) { return Default(typeParameterDeclaration); } AstNode IAstVisitor.VisitConstraint(Constraint constraint) { return Default(constraint); } AstNode IAstVisitor.VisitCSharpTokenNode(CSharpTokenNode cSharpTokenNode) { return Default(cSharpTokenNode); } AstNode IAstVisitor.VisitIdentifier(Identifier identifier) { return Default(identifier); } AstNode IAstVisitor.VisitPatternPlaceholder(AstNode placeholder, Pattern pattern) { return Default(pattern); } #endregion } /// /// Expands all occurances of query patterns in the specified node. Returns a clone of the node with all query patterns expanded, or null if there was no query pattern to expand. /// /// /// public QueryExpressionExpansionResult ExpandQueryPattern(AstNode node) { var visitor = new Visitor(); var astNode = node.AcceptVisitor(visitor); if (astNode != null) { astNode.Freeze(); return new QueryExpressionExpansionResult(astNode, visitor.rangeVariables, visitor.expressions); } else { return null; } } } }