Represents a syntax matching node. Thie node is used to build a Trie representing possible matching. Each node contians children and matching syntax nodes.
        /// <summary>
        /// Visits a member.
        /// </summary>
        /// <typeparam name="T">The syntax node type to visit.</typeparam>
        /// <param name="node">The node to visit.</param>
        /// <param name="exctractName">Extract the node name.</param>
        /// <param name="typeParameterList">The type parameter list.</param>
        /// <param name="targetNode">Resolved the target node.</param>
        /// <param name="visit">Visit sub nodes.</param>
        private void Visit <T>(T node, Func <T, string> exctractName, TypeParameterListSyntax typeParameterList, Func <T, SyntaxNode> targetNode, Action <T> visit) where T : CSharpSyntaxNode
        {
            // Retrieve the accessor name
            string name = exctractName(node);

            // Compute suffix for representing generics
            if (null != typeParameterList)
            {
                name = string.Format(
                    "{0}{{{1}}}",
                    name,
                    string.Join(",", typeParameterList.Parameters.Select(x => x.ToString())));
            }

            // Keep track of the initial node the restore the root after the visit
            CSharpSyntaxMatchingNode initialNode = this.Root;

            // Create and add the node
            this.Root = this.Root.EnsureNode(name);
            this.Root.AddSyntaxNode(targetNode(node));

            // Trigger member visiting
            visit(node);

            // Copy the class sub tree to the Trie root
            this.Root.CopyTo(this.internalInvariantRoot, name);

            // Restore the initial root
            this.Root = initialNode;
        }
        /// <summary>
        /// Visits a namespace declaration.
        /// A namespace may be composed with different segment dot separated, each segment has to be represented by a different node.
        /// However the syntax node is attached to the last node only.
        /// </summary>
        /// <param name="node">The namespace declaration node to visit.</param>
        public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node)
        {
            // Retrieve the namespace name and split segments
            string name = node.Name.ToString();

            string[] namespaces = name.Split('.');

            // Keep track of the initial node the restore the root after the visit
            CSharpSyntaxMatchingNode initialNode = this.Root;

            // Browse all namespaces and generate intermediate node for each segment for the copy to the root
            CSharpSyntaxMatchingNode firstNamespaceNode = null;

            foreach (string currentNamespace in namespaces)
            {
                // Create the node and keep track of the first one
                this.Root = this.Root.EnsureNode(currentNamespace);
                if (null == firstNamespaceNode)
                {
                    firstNamespaceNode = this.Root;
                }
            }

            // Add the syntax node the last segment
            this.Root.AddSyntaxNode(node);

            // Triger member visiting
            base.VisitNamespaceDeclaration(node);

            // Copy the generated sub tree to the Trie root
            firstNamespaceNode.CopyTo(this.internalInvariantRoot, namespaces[0]);

            // Restore the initial root
            this.Root = initialNode;
        }
        /// <summary>
        /// Copies to a given node.
        /// </summary>
        /// <param name="targetNode">The node wherer to copy.</param>
        /// <param name="name">The node name.</param>
        public void CopyTo(CSharpSyntaxMatchingNode targetNode, string name)
        {
            // Data validation
            Ensure.That(() => name).IsNotNullOrWhiteSpace();
            Ensure.That(() => targetNode).IsNotNull();

            // Ensure and retrieve a node the the copy
            CSharpSyntaxMatchingNode newNode = targetNode.EnsureNode(name);

            // Add syntax node to the created node
            if (null != this.matchingSyntaxNodes)
            {
                // Lazy create the syntax nodes
                if (null == newNode.matchingSyntaxNodes)
                {
                    newNode.matchingSyntaxNodes = new List <SyntaxNode>();
                }

                // Merge syntax nodes
                int[] indexes = newNode.matchingSyntaxNodes.Select(x => x.Span.Start).ToArray();
                newNode.matchingSyntaxNodes.AddRange(this.matchingSyntaxNodes.Where(x => !indexes.Contains(x.Span.Start)));
            }

            // Recurse for applying copy to the children
            if (null != this.children && this.children.Count > 0)
            {
                string[] childrenName = this.children.Keys.ToArray();
                foreach (string childName in childrenName)
                {
                    this.children[childName].CopyTo(newNode, childName);
                }
            }
        }
        /// <summary>
        /// Copies to a given node.
        /// </summary>
        /// <param name="targetNode">The node wherer to copy.</param>
        /// <param name="name">The node name.</param>
        public void CopyTo(CSharpSyntaxMatchingNode targetNode, string name)
        {
            // Data validation
            Ensure.That(() => name).IsNotNullOrWhiteSpace();
            Ensure.That(() => targetNode).IsNotNull();

            // Ensure and retrieve a node the the copy
            CSharpSyntaxMatchingNode newNode = targetNode.EnsureNode(name);

            // Add syntax node to the created node
            if (null != this.matchingSyntaxNodes)
            {
                // Lazy create the syntax nodes
                if (null == newNode.matchingSyntaxNodes)
                {
                    newNode.matchingSyntaxNodes = new List<SyntaxNode>();
                }

                // Merge syntax nodes
                int[] indexes = newNode.matchingSyntaxNodes.Select(x => x.Span.Start).ToArray();
                newNode.matchingSyntaxNodes.AddRange(this.matchingSyntaxNodes.Where(x => !indexes.Contains(x.Span.Start)));
            }

            // Recurse for applying copy to the children
            if (null != this.children && this.children.Count > 0)
            {
                string[] childrenName = this.children.Keys.ToArray();
                foreach (string childName in childrenName)
                {
                    this.children[childName].CopyTo(newNode, childName);
                }
            }
        }
        /// <summary>
        /// Finds a node from syntax chunk.
        /// </summary>
        /// <param name="chunks">The chunks to match.</param>
        /// <returns></returns>
        public CSharpSyntaxMatchingNode Match(string[] chunks)
        {
            // Data validation
            Ensure.That(() => chunks).IsNotNull();

            // Browse the Trie until finding a matching
            CSharpSyntaxMatchingNode matchingNode = this;

            foreach (string fragment in chunks)
            {
                // Could not find any matching
                if (null == matchingNode.children || !matchingNode.children.TryGetValue(fragment, out matchingNode))
                {
                    return(null);
                }
            }

            // Return the matching node
            return(matchingNode);
        }
        /// <summary>
        /// Finds a node from syntax chunk.
        /// </summary>
        /// <param name="chunks">The chunks to match.</param>
        /// <returns></returns>
        public CSharpSyntaxMatchingNode Match(string[] chunks)
        {
            if (chunks == null)
            {
                throw new ArgumentNullException(nameof(chunks));
            }
            // Browse the Trie until finding a matching
            CSharpSyntaxMatchingNode matchingNode = this;

            foreach (string fragment in chunks)
            {
                // Could not find any matching
                if (null == matchingNode.children || !matchingNode.children.TryGetValue(fragment, out matchingNode))
                {
                    return(null);
                }
            }

            // Return the matching node
            return(matchingNode);
        }
Beispiel #7
0
        /// <summary>
        /// Extracts a snippet from a given rule pattern.
        /// </summary>
        /// <param name="fullFilename">The full filename (with path) to load and to extract the snippet from.</param>
        /// <param name="memberPattern">The member pattern to extract.</param>
        /// <returns>The extracted snippet.</returns>
        public override string Extract(string fullFilename, string memberPattern)
        {
            // Return the entire code if no member is specified
            if (string.IsNullOrWhiteSpace(memberPattern))
            {
                return(base.Extract(fullFilename, memberPattern));
            }

            // Parse the matching rule from the pattern
            CSharpMatchingRule rule = CSharpMatchingRule.Parse(memberPattern);

            // Load the trie for pattern matching
            if (null == this.syntaxTrie)
            {
                // Load file content
                string sourceCode = this.LoadFile(fullFilename);

                // Build a syntax tree from the source code
                SyntaxTree tree = CSharpSyntaxTree.ParseText(sourceCode);
                SyntaxNode root = tree.GetRoot();

                // Visit the syntax tree for generating a Trie for pattern matching
                CSharpSyntaxWalkerMatchingBuilder syntaxMatchingBuilder = new CSharpSyntaxWalkerMatchingBuilder();
                syntaxMatchingBuilder.Visit(root);

                // Retrieve the Trie root
                this.syntaxTrie = syntaxMatchingBuilder.Root;
            }

            // Match the rule from the syntax matching Trie
            CSharpSyntaxMatchingNode matchingTrie = syntaxTrie.Match(rule.MatchingChunks);

            if (null == matchingTrie)
            {
                throw new SnippetExtractionException("Cannot find member", memberPattern);
            }

            // Build a snippet for extracted syntax nodes
            return(this.BuildSnippet(matchingTrie.MatchingSyntaxNodes, rule.ExtractionMode));
        }
        /// <summary>
        /// Extracts a snippet from a given rule pattern.
        /// </summary>
        /// <param name="fullFilename">The full filename (with path) to load and to extract the snippet from.</param>
        /// <param name="memberPattern">The member pattern to extract.</param>
        /// <returns>The extracted snippet.</returns>
        public override string Extract(string fullFilename, string memberPattern)
        {
            // Return the entire code if no member is specified
            if (string.IsNullOrWhiteSpace(memberPattern))
            {
                return base.Extract(fullFilename, memberPattern);
            }

            // Parse the matching rule from the pattern
            CSharpMatchingRule rule = CSharpMatchingRule.Parse(memberPattern);

            // Load the trie for pattern matching
            if (null == this.syntaxTrie)
            {
                // Load file content
                string sourceCode = this.LoadFile(fullFilename);

                // Build a syntax tree from the source code
                SyntaxTree tree = CSharpSyntaxTree.ParseText(sourceCode);
                SyntaxNode root = tree.GetRoot();

                // Visit the syntax tree for generating a Trie for pattern matching
                CSharpSyntaxWalkerMatchingBuilder syntaxMatchingBuilder = new CSharpSyntaxWalkerMatchingBuilder();
                syntaxMatchingBuilder.Visit(root);

                // Retrieve the Trie root
                this.syntaxTrie = syntaxMatchingBuilder.Root;
            }

            // Match the rule from the syntax matching Trie
            CSharpSyntaxMatchingNode matchingTrie = syntaxTrie.Match(rule.MatchingChunks);
            if (null == matchingTrie)
            {
                throw new SnippetExtractionException("Cannot find member", memberPattern);
            }

            // Build a snippet for extracted syntax nodes
            return this.BuildSnippet(matchingTrie.MatchingSyntaxNodes, rule.ExtractionMode);
        }
        /// <summary>
        /// Copies to a given node.
        /// </summary>
        /// <param name="targetNode">The node wherer to copy.</param>
        /// <param name="name">The node name.</param>
        public void CopyTo(CSharpSyntaxMatchingNode targetNode, string name)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentException($"'{nameof(name)}' is null or whitespace");
            }
            if (targetNode == null)
            {
                throw new ArgumentNullException(nameof(targetNode));
            }

            // Ensure and retrieve a node the the copy
            CSharpSyntaxMatchingNode newNode = targetNode.EnsureNode(name);

            // Add syntax node to the created node
            if (null != this.matchingSyntaxNodes)
            {
                // Lazy create the syntax nodes
                if (null == newNode.matchingSyntaxNodes)
                {
                    newNode.matchingSyntaxNodes = new List <SyntaxNode>();
                }

                // Merge syntax nodes
                int[] indexes = newNode.matchingSyntaxNodes.Select(x => x.Span.Start).ToArray();
                newNode.matchingSyntaxNodes.AddRange(this.matchingSyntaxNodes.Where(x => !indexes.Contains(x.Span.Start)));
            }

            // Recurse for applying copy to the children
            if (null != this.children && this.children.Count > 0)
            {
                string[] childrenName = this.children.Keys.ToArray();
                foreach (string childName in childrenName)
                {
                    this.children[childName].CopyTo(newNode, childName);
                }
            }
        }
        /// <summary>
        /// Copies to a given node.
        /// </summary>
        /// <param name="targetNode">The node wherer to copy.</param>
        /// <param name="name">The node name.</param>
        public void CopyTo(CSharpSyntaxMatchingNode targetNode, string name)
        {
            if(string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentException($"'{nameof(name)}' is null or whitespace");
            }
            if(targetNode == null)
            {
                throw new ArgumentNullException(nameof(targetNode));
            }

            // Ensure and retrieve a node the the copy
            CSharpSyntaxMatchingNode newNode = targetNode.EnsureNode(name);

            // Add syntax node to the created node
            if (null != this.matchingSyntaxNodes)
            {
                // Lazy create the syntax nodes
                if (null == newNode.matchingSyntaxNodes)
                {
                    newNode.matchingSyntaxNodes = new List<SyntaxNode>();
                }

                // Merge syntax nodes
                int[] indexes = newNode.matchingSyntaxNodes.Select(x => x.Span.Start).ToArray();
                newNode.matchingSyntaxNodes.AddRange(this.matchingSyntaxNodes.Where(x => !indexes.Contains(x.Span.Start)));
            }

            // Recurse for applying copy to the children
            if (null != this.children && this.children.Count > 0)
            {
                string[] childrenName = this.children.Keys.ToArray();
                foreach (string childName in childrenName)
                {
                    this.children[childName].CopyTo(newNode, childName);
                }
            }
        }
 /// <summary>
 /// Initializes a new instance of <see cref="CSharpSyntaxWalkerMatchingBuilder"/>.
 /// </summary>
 public CSharpSyntaxWalkerMatchingBuilder()
 {
     this.internalInvariantRoot = new CSharpSyntaxMatchingNode();
     this.Root = this.internalInvariantRoot;
 }