You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucenenet.apache.org by ni...@apache.org on 2016/12/06 15:11:45 UTC

[10/58] lucenenet git commit: WIP on QueryParsers.Flexible

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/PathQueryNode.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/PathQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/PathQueryNode.cs
new file mode 100644
index 0000000..264f9fd
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/PathQueryNode.cs
@@ -0,0 +1,233 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Parser;
+using Lucene.Net.Support;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
+{
+    /// <summary>
+    /// A {@link PathQueryNode} is used to store queries like
+    /// /company/USA/California /product/shoes/brown. QueryText are objects that
+    /// contain the text, begin position and end position in the query.
+    /// <para>
+    /// Example how the text parser creates these objects:
+    /// </para>
+    /// <code>
+    /// List values = new List();
+    /// values.add(new PathQueryNode.QueryText("company", 1, 7));
+    /// values.add(new PathQueryNode.QueryText("USA", 9, 12));
+    /// values.add(new PathQueryNode.QueryText("California", 14, 23));
+    /// QueryNode q = new PathQueryNode(values);
+    /// </code>
+    /// 
+    /// </summary>
+    public class PathQueryNode : QueryNodeImpl
+    {
+        /**
+   * Term text with a beginning and end position
+   */
+        public class QueryText : ICloneable
+        {
+            internal string value = null;
+            /**
+             * != null The term's begin position.
+             */
+            internal int begin;
+
+            /**
+             * The term's end position.
+             */
+            internal int end;
+
+            /**
+             * @param value
+             *          - text value
+             * @param begin
+             *          - position in the query string
+             * @param end
+             *          - position in the query string
+             */
+            public QueryText(string value, int begin, int end)
+                : base()
+            {
+                this.value = value;
+                this.begin = begin;
+                this.end = end;
+            }
+
+
+            public virtual /*QueryText*/ object Clone()
+            {
+                QueryText clone = (QueryText)this.MemberwiseClone();
+                clone.value = this.value;
+                clone.begin = this.begin;
+                clone.end = this.end;
+                return clone;
+            }
+
+            /**
+             * @return the value
+             */
+            public string GetValue()
+            {
+                return value;
+            }
+
+            /**
+             * @return the begin
+             */
+            public int GetBegin()
+            {
+                return begin;
+            }
+
+            /**
+             * @return the end
+             */
+            public int GetEnd()
+            {
+                return end;
+            }
+
+            public override string ToString()
+            {
+                return value + ", " + begin + ", " + end;
+            }
+        }
+
+        private IList<QueryText> values = null;
+
+        /**
+         * @param pathElements
+         *          - List of QueryText objects
+         */
+        public PathQueryNode(IList<QueryText> pathElements)
+        {
+            this.values = pathElements;
+            if (pathElements.Count <= 1)
+            {
+                // this should not happen
+                throw new Exception(
+                    "PathQuerynode requires more 2 or more path elements.");
+            }
+        }
+
+        /**
+         * Returns the a List with all QueryText elements
+         * 
+         * @return QueryText List size
+         */
+        public IList<QueryText> GetPathElements()
+        {
+            return values;
+        }
+
+        /**
+         * Returns the a List with all QueryText elements
+         */
+        public void SetPathElements(IList<QueryText> elements)
+        {
+            this.values = elements;
+        }
+
+        /**
+         * Returns the a specific QueryText element
+         * 
+         * @return QueryText List size
+         */
+        public QueryText GetPathElement(int index)
+        {
+            return values[index];
+        }
+
+        /**
+         * Returns the CharSequence value of a specific QueryText element
+         * 
+         * @return the CharSequence for a specific QueryText element
+         */
+        public string GetFirstPathElement()
+        {
+            return values[0].value;
+        }
+
+        /**
+         * Returns a List QueryText element from position startIndex
+         * 
+         * @return a List QueryText element from position startIndex
+         */
+        public IList<QueryText> GetPathElements(int startIndex)
+        {
+            List<PathQueryNode.QueryText> rValues = new List<PathQueryNode.QueryText>();
+            for (int i = startIndex; i < this.values.Count; i++)
+            {
+                //try
+                //{
+                rValues.Add((QueryText)this.values[i].Clone());
+                //}
+                //catch (CloneNotSupportedException e)
+                //{
+                //    // this will not happen
+                //}
+            }
+            return rValues;
+        }
+
+        private string GetPathString()
+        {
+            StringBuilder path = new StringBuilder();
+
+            foreach (QueryText pathelement in values)
+            {
+                path.Append("/").Append(pathelement.value);
+            }
+            return path.ToString();
+        }
+
+
+        public override string ToQueryString(IEscapeQuerySyntax escaper)
+        {
+            StringBuilder path = new StringBuilder();
+            path.Append("/").Append(GetFirstPathElement());
+
+            foreach (QueryText pathelement in GetPathElements(1))
+            {
+                string value = escaper.Escape(new StringCharSequenceWrapper(pathelement.value), 
+                    CultureInfo.InvariantCulture, EscapeQuerySyntax.Type.STRING).ToString();
+                path.Append("/\"").Append(value).Append("\"");
+            }
+            return path.ToString();
+        }
+
+
+        public override string ToString()
+        {
+            QueryText text = this.values[0];
+
+            return "<path start='" + text.begin + "' end='" + text.end + "' path='"
+                + GetPathString() + "'/>";
+        }
+
+
+        public override IQueryNode CloneTree()
+        {
+            PathQueryNode clone = (PathQueryNode)base.CloneTree();
+
+            // copy children
+            if (this.values != null)
+            {
+                List<QueryText> localValues = new List<QueryText>();
+                foreach (QueryText value in this.values)
+                {
+                    localValues.Add((QueryText)value.Clone());
+                }
+                clone.values = localValues;
+            }
+
+            return clone;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/PhraseSlopQueryNode.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/PhraseSlopQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/PhraseSlopQueryNode.cs
new file mode 100644
index 0000000..63b19c1
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/PhraseSlopQueryNode.cs
@@ -0,0 +1,106 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Messages;
+using Lucene.Net.QueryParsers.Flexible.Core.Parser;
+using Lucene.Net.QueryParsers.Flexible.Messages;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
+{
+    /// <summary>
+    /// Query node for <see cref="PhraseQuery"/>'s slop factor.
+    /// </summary>
+    public class PhraseSlopQueryNode : QueryNodeImpl, IFieldableNode
+    {
+        private int value = 0;
+
+        /**
+         * @exception QueryNodeError throw in overridden method to disallow
+         */
+        public PhraseSlopQueryNode(IQueryNode query, int value)
+        {
+            if (query == null)
+            {
+                throw new QueryNodeError(new MessageImpl(
+                    QueryParserMessages.NODE_ACTION_NOT_SUPPORTED, "query", "null"));
+            }
+
+            this.value = value;
+            SetLeaf(false);
+            Allocate();
+            Add(query);
+        }
+
+        public IQueryNode GetChild()
+        {
+            return GetChildren()[0];
+        }
+
+        public int GetValue()
+        {
+            return this.value;
+        }
+
+        private string GetValueString()
+        {
+            float f = this.value;
+            if (f == (long)f)
+                return "" + (long)f;
+            else
+                return "" + f;
+
+        }
+
+
+        public override string ToString()
+        {
+            return "<phraseslop value='" + GetValueString() + "'>" + "\n"
+                + GetChild().ToString() + "\n</phraseslop>";
+        }
+
+
+        public override string ToQueryString(IEscapeQuerySyntax escapeSyntaxParser)
+        {
+            if (GetChild() == null)
+                return "";
+            return GetChild().ToQueryString(escapeSyntaxParser) + "~"
+                + GetValueString();
+        }
+
+
+        public override IQueryNode CloneTree()
+        {
+            PhraseSlopQueryNode clone = (PhraseSlopQueryNode)base.CloneTree();
+
+            clone.value = this.value;
+
+            return clone;
+        }
+
+        public virtual string Field
+        {
+            get
+            {
+                IQueryNode child = GetChild();
+
+                if (child is IFieldableNode)
+                {
+                    return ((IFieldableNode)child).Field;
+                }
+
+                return null;
+            }
+            set
+            {
+                IQueryNode child = GetChild();
+
+                if (child is IFieldableNode)
+                {
+                    ((IFieldableNode)child).Field = value;
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ProximityQueryNode.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ProximityQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ProximityQueryNode.cs
new file mode 100644
index 0000000..da1bf0b
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ProximityQueryNode.cs
@@ -0,0 +1,288 @@
+\ufeff//using System;
+using Lucene.Net.QueryParsers.Flexible.Core.Messages;
+using Lucene.Net.QueryParsers.Flexible.Core.Parser;
+using Lucene.Net.QueryParsers.Flexible.Messages;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
+{
+    /// <summary>
+    /// A {@link ProximityQueryNode} represents a query where the terms should meet
+    /// specific distance conditions. (a b c) WITHIN [SENTENCE|PARAGRAPH|NUMBER]
+    /// [INORDER] ("a" "b" "c") WITHIN [SENTENCE|PARAGRAPH|NUMBER] [INORDER]
+    /// 
+    /// TODO: Add this to the future standard Lucene parser/processor/builder
+    /// </summary>
+    public class ProximityQueryNode : BooleanQueryNode
+    {
+        /**
+   * Distance condition: PARAGRAPH, SENTENCE, or NUMBER
+   */
+
+        public enum Type
+        {
+            PARAGRAPH,
+            SENTENCE,
+            NUMBER
+        }
+
+        //        public enum Type
+        //        {
+        //            PARAGRAPH /*{
+        //      @Override
+        //            CharSequence toQueryString() { return "WITHIN PARAGRAPH";
+        //        }
+        //    }*/,
+        //            SENTENCE  /*{ 
+        //      @Override
+        //      CharSequence toQueryString() { return "WITHIN SENTENCE"; }
+        //}*/,
+        //            NUMBER   /* {
+        //      @Override
+        //      CharSequence toQueryString() { return "WITHIN"; }
+        //    };*/
+        //        }
+
+        // LUCENENET TODO: Implement this on enum
+        //    internal abstract string ToQueryString();
+        //}
+
+        /** utility class containing the distance condition and number */
+        public class ProximityType
+        {
+            internal int pDistance = 0;
+
+            ProximityQueryNode.Type pType/* = null*/;
+
+            public ProximityType(ProximityQueryNode.Type type)
+                    : this(type, 0)
+            {
+            }
+
+            public ProximityType(ProximityQueryNode.Type type, int distance)
+            {
+                this.pType = type;
+                this.pDistance = distance;
+            }
+        }
+
+        private ProximityQueryNode.Type proximityType = ProximityQueryNode.Type.SENTENCE;
+        private int distance = -1;
+        private bool inorder = false;
+        private string field = null;
+
+        /**
+         * @param clauses
+         *          - QueryNode children
+         * @param field
+         *          - field name
+         * @param type
+         *          - type of proximity query
+         * @param distance
+         *          - positive integer that specifies the distance
+         * @param inorder
+         *          - true, if the tokens should be matched in the order of the
+         *          clauses
+         */
+        public ProximityQueryNode(IList<IQueryNode> clauses, string field,
+            ProximityQueryNode.Type type, int distance, bool inorder)
+            : base(clauses)
+        {
+
+            SetLeaf(false);
+            this.proximityType = type;
+            this.inorder = inorder;
+            this.field = field;
+            if (type == ProximityQueryNode.Type.NUMBER)
+            {
+                if (distance <= 0)
+                {
+                    throw new QueryNodeError(new MessageImpl(
+                        QueryParserMessages.PARAMETER_VALUE_NOT_SUPPORTED, "distance",
+                        distance));
+
+                }
+                else
+                {
+                    this.distance = distance;
+                }
+
+            }
+            ClearFields(clauses, field);
+        }
+
+        /**
+         * @param clauses
+         *          - QueryNode children
+         * @param field
+         *          - field name
+         * @param type
+         *          - type of proximity query
+         * @param inorder
+         *          - true, if the tokens should be matched in the order of the
+         *          clauses
+         */
+        public ProximityQueryNode(IList<IQueryNode> clauses, string field,
+            ProximityQueryNode.Type type, bool inorder)
+            : this(clauses, field, type, -1, inorder)
+        {
+
+        }
+
+        private static void ClearFields(IList<IQueryNode> nodes, string field)
+        {
+            if (nodes == null || nodes.Count == 0)
+                return;
+
+            foreach (IQueryNode clause in nodes)
+            {
+
+                if (clause is FieldQueryNode)
+                {
+                    ((FieldQueryNode)clause).toQueryStringIgnoreFields = true;
+                    ((FieldQueryNode)clause).Field = field;
+                }
+            }
+        }
+
+        public ProximityQueryNode.Type GetProximityType()
+        {
+            return this.proximityType;
+        }
+
+        public override string ToString()
+        {
+            string distanceSTR = ((this.distance == -1) ? ("")
+                : (" distance='" + this.distance) + "'");
+
+            if (GetChildren() == null || GetChildren().Count == 0)
+                return "<proximity field='" + this.field + "' inorder='" + this.inorder
+                    + "' type='" + this.proximityType.ToString() + "'" + distanceSTR
+                    + "/>";
+            StringBuilder sb = new StringBuilder();
+            sb.Append("<proximity field='" + this.field + "' inorder='" + this.inorder
+                + "' type='" + this.proximityType.ToString() + "'" + distanceSTR + ">");
+            foreach (IQueryNode child in GetChildren())
+            {
+                sb.Append("\n");
+                sb.Append(child.ToString());
+            }
+            sb.Append("\n</proximity>");
+            return sb.ToString();
+        }
+
+
+        public override string ToQueryString(IEscapeQuerySyntax escapeSyntaxParser)
+        {
+            string withinSTR = this.proximityType.ToQueryString()
+                + ((this.distance == -1) ? ("") : (" " + this.distance))
+                + ((this.inorder) ? (" INORDER") : (""));
+
+            StringBuilder sb = new StringBuilder();
+            if (GetChildren() == null || GetChildren().Count == 0)
+            {
+                // no children case
+            }
+            else
+            {
+                string filler = "";
+                foreach (IQueryNode child in GetChildren())
+                {
+                    sb.Append(filler).Append(child.ToQueryString(escapeSyntaxParser));
+                    filler = " ";
+                }
+            }
+
+            if (IsDefaultField(this.field))
+            {
+                return "( " + sb.ToString() + " ) " + withinSTR;
+            }
+            else
+            {
+                return this.field + ":(( " + sb.ToString() + " ) " + withinSTR + ")";
+            }
+        }
+
+
+        public override IQueryNode CloneTree()
+        {
+            ProximityQueryNode clone = (ProximityQueryNode)base.CloneTree();
+
+            clone.proximityType = this.proximityType;
+            clone.distance = this.distance;
+            clone.field = this.field;
+
+            return clone;
+        }
+
+        /**
+         * @return the distance
+         */
+        public int GetDistance()
+        {
+            return this.distance;
+        }
+
+        /**
+         * returns null if the field was not specified in the query string
+         * 
+         * @return the field
+         */
+        public string GetField()
+        {
+            return this.field;
+        }
+
+        /**
+         * returns null if the field was not specified in the query string
+         * 
+         * @return the field
+         */
+        public string GetFieldAsString()
+        {
+            if (this.field == null)
+                return null;
+            else
+                return this.field.ToString();
+        }
+
+        /**
+         * @param field
+         *          the field to set
+         */
+        public void SetField(string field)
+        {
+            this.field = field;
+        }
+
+        /**
+         * @return terms must be matched in the specified order
+         */
+        public bool IsInOrder()
+        {
+            return this.inorder;
+        }
+    }
+
+    public static class ProximityQueryNode_TypeExtensions
+    {
+        public static string ToQueryString(this ProximityQueryNode.Type type)
+        {
+            switch (type)
+            {
+                case ProximityQueryNode.Type.NUMBER:
+                    return "WITHIN";
+                case ProximityQueryNode.Type.PARAGRAPH:
+                    return "WITHIN PARAGRAPH";
+                case ProximityQueryNode.Type.SENTENCE:
+                    return "WITHIN SENTENCE";
+            }
+
+            throw new ArgumentException("Invalid ProximityQueryNode.Type");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNode.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNode.cs
new file mode 100644
index 0000000..ad641eb
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNode.cs
@@ -0,0 +1,84 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Parser;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Lucene.Net.Search;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
+{
+    /// <summary>
+    /// A {@link QueryNode} is a interface implemented by all nodes on a QueryNode
+    /// tree.
+    /// </summary>
+    public interface IQueryNode
+    {
+        /** convert to a query string understood by the query parser */
+        // TODO: this interface might be changed in the future
+        string ToQueryString(IEscapeQuerySyntax escapeSyntaxParser);
+
+        /** for printing */
+        
+  //public override string ToString();
+
+        /** get Children nodes */
+        IList<IQueryNode> GetChildren();
+
+        /** verify if a node is a Leaf node */
+        bool IsLeaf();
+
+        /** verify if a node contains a tag */
+        bool ContainsTag(string tagName);
+
+        /**
+         * Returns object stored under that tag name
+         */
+        object GetTag(string tagName);
+
+        IQueryNode GetParent();
+
+        /**
+         * Recursive clone the QueryNode tree The tags are not copied to the new tree
+         * when you call the cloneTree() method
+         * 
+         * @return the cloned tree
+         */
+        IQueryNode CloneTree();
+
+        // Below are the methods that can change state of a QueryNode
+        // Write Operations (not Thread Safe)
+
+        // add a new child to a non Leaf node
+        void Add(IQueryNode child);
+
+        void Add(IList<IQueryNode> children);
+
+        // reset the children of a node
+        void Set(IList<IQueryNode> children);
+
+        /**
+         * Associate the specified value with the specified tagName. If the tagName
+         * already exists, the old value is replaced. The tagName and value cannot be
+         * null. tagName will be converted to lowercase.
+         */
+        void SetTag(string tagName, object value);
+
+        /**
+         * Unset a tag. tagName will be converted to lowercase.
+         */
+        void UnsetTag(string tagName);
+
+        /**
+         * Returns a map containing all tags attached to this query node. 
+         * 
+         * @return a map containing all tags attached to this query node
+         */
+        IDictionary<string, object> GetTagMap();
+
+        /**
+         * Removes this query node from its parent.
+         */
+        void RemoveFromParent();
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNodeImpl.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNodeImpl.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNodeImpl.cs
new file mode 100644
index 0000000..31186de
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QueryNodeImpl.cs
@@ -0,0 +1,292 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Messages;
+using Lucene.Net.QueryParsers.Flexible.Core.Parser;
+using Lucene.Net.QueryParsers.Flexible.Core.Util;
+using Lucene.Net.QueryParsers.Flexible.Messages;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
+{
+    /// <summary>
+    /// A {@link QueryNodeImpl} is the default implementation of the interface
+    /// {@link QueryNode}
+    /// </summary>
+    public abstract class QueryNodeImpl : IQueryNode, ICloneable
+    {
+        /* index default field */
+        // TODO remove PLAINTEXT_FIELD_NAME replacing it with configuration APIs
+        public static readonly string PLAINTEXT_FIELD_NAME = "_plain";
+
+        private bool isLeaf = true;
+
+        private Dictionary<string, object> tags = new Dictionary<string, object>();
+
+        private List<IQueryNode> clauses = null;
+
+        protected virtual void Allocate()
+        {
+
+            if (this.clauses == null)
+            {
+                this.clauses = new List<IQueryNode>();
+
+            }
+            else
+            {
+                this.clauses.Clear();
+            }
+
+        }
+
+        public void Add(IQueryNode child)
+        {
+
+            if (IsLeaf() || this.clauses == null || child == null)
+            {
+                throw new ArgumentException(NLS
+                    .GetLocalizedMessage(QueryParserMessages.NODE_ACTION_NOT_SUPPORTED));
+            }
+
+            this.clauses.Add(child);
+            ((QueryNodeImpl)child).SetParent(this);
+
+        }
+
+
+        public void Add(IList<IQueryNode> children)
+        {
+
+            if (IsLeaf() || this.clauses == null)
+            {
+                throw new ArgumentException(NLS
+                    .GetLocalizedMessage(QueryParserMessages.NODE_ACTION_NOT_SUPPORTED));
+            }
+
+            foreach (IQueryNode child in children)
+            {
+                Add(child);
+            }
+
+        }
+
+
+        public virtual bool IsLeaf()
+        {
+            return this.isLeaf;
+        }
+
+
+        public void Set(IList<IQueryNode> children)
+        {
+
+            if (IsLeaf() || this.clauses == null)
+            {
+                //ResourceBundle bundle = ResourceBundle
+                //    .getBundle("org.apache.lucene.queryParser.messages.QueryParserMessages");
+                //String message = bundle.getObject("Q0008E.NODE_ACTION_NOT_SUPPORTED")
+                //    .toString();
+                string message = Lucene.Net.QueryParsers.Properties.Resources.NODE_ACTION_NOT_SUPPORTED;
+
+                throw new ArgumentException(message);
+
+            }
+
+            // reset parent value
+            foreach (IQueryNode child in children)
+            {
+                child.RemoveFromParent();
+            }
+
+            List<IQueryNode> existingChildren = new List<IQueryNode>(GetChildren());
+            foreach (IQueryNode existingChild in existingChildren)
+            {
+                existingChild.RemoveFromParent();
+            }
+
+            // allocate new children list
+            Allocate();
+
+            // add new children and set parent
+            Add(children);
+        }
+
+
+        public virtual IQueryNode CloneTree()
+        {
+            QueryNodeImpl clone = (QueryNodeImpl)this.MemberwiseClone();
+            clone.isLeaf = this.isLeaf;
+
+            // Reset all tags
+            clone.tags = new Dictionary<string, object>();
+
+            // copy children
+            if (this.clauses != null)
+            {
+                List<IQueryNode> localClauses = new List<IQueryNode>();
+                foreach (IQueryNode clause in this.clauses)
+                {
+                    localClauses.Add(clause.CloneTree());
+                }
+                clone.clauses = localClauses;
+            }
+
+            return clone;
+        }
+
+
+        public virtual /*IQueryNode*/ object Clone()
+        {
+            return CloneTree();
+        }
+
+        protected virtual void SetLeaf(bool isLeaf)
+        {
+            this.isLeaf = isLeaf;
+        }
+
+        /**
+         * @return a List for QueryNode object. Returns null, for nodes that do not
+         *         contain children. All leaf Nodes return null.
+         */
+
+        public IList<IQueryNode> GetChildren()
+        {
+            if (IsLeaf() || this.clauses == null)
+            {
+                return null;
+            }
+            return new List<IQueryNode>(this.clauses);
+        }
+
+
+        public virtual void SetTag(string tagName, object value)
+        {
+            this.tags[tagName.ToLower(CultureInfo.InvariantCulture)] = value;
+        }
+
+
+        public virtual void UnsetTag(string tagName)
+        {
+            this.tags.Remove(tagName.ToLower(CultureInfo.InvariantCulture));
+        }
+
+        /** verify if a node contains a tag */
+        public virtual bool ContainsTag(string tagName)
+        {
+            return this.tags.ContainsKey(tagName.ToLower(CultureInfo.InvariantCulture));
+        }
+
+        public virtual object GetTag(string tagName)
+        {
+            return this.tags[tagName.ToLower(CultureInfo.InvariantCulture)];
+        }
+
+        private IQueryNode parent = null;
+
+        private void SetParent(IQueryNode parent)
+        {
+            if (this.parent != parent)
+            {
+                this.RemoveFromParent();
+                this.parent = parent;
+            }
+        }
+
+
+        public virtual IQueryNode GetParent()
+        {
+            return this.parent;
+        }
+
+        protected bool IsRoot()
+        {
+            return GetParent() == null;
+        }
+
+        /**
+         * If set to true the the method toQueryString will not write field names
+         */
+        protected internal bool toQueryStringIgnoreFields = false;
+
+        /**
+         * This method is use toQueryString to detect if fld is the default field
+         * 
+         * @param fld - field name
+         * @return true if fld is the default field
+         */
+        // TODO: remove this method, it's commonly used by {@link
+        // #toQueryString(org.apache.lucene.queryParser.core.parser.EscapeQuerySyntax)}
+        // to figure out what is the default field, however, {@link
+        // #toQueryString(org.apache.lucene.queryParser.core.parser.EscapeQuerySyntax)}
+        // should receive the default field value directly by parameter
+        protected bool IsDefaultField(string fld)
+        {
+            if (this.toQueryStringIgnoreFields)
+                return true;
+            if (fld == null)
+                return true;
+            if (QueryNodeImpl.PLAINTEXT_FIELD_NAME.Equals(StringUtils.ToString(fld)))
+                return true;
+            return false;
+        }
+
+        /**
+         * Every implementation of this class should return pseudo xml like this:
+         * 
+         * For FieldQueryNode: &lt;field start='1' end='2' field='subject' text='foo'/&gt;
+         * 
+         * @see org.apache.lucene.queryparser.flexible.core.nodes.QueryNode#toString()
+         */
+
+        public override string ToString()
+        {
+            return base.ToString();
+        }
+
+        /**
+         * Returns a map containing all tags attached to this query node.
+         * 
+         * @return a map containing all tags attached to this query node
+         */
+        public virtual IDictionary<string, object> GetTagMap()
+        {
+            return new Dictionary<string, object>(this.tags);
+        }
+
+        public virtual void RemoveFromParent()
+        {
+            if (this.parent != null)
+            {
+                IList<IQueryNode> parentChildren = this.parent.GetChildren();
+                //IEnumerator<IQueryNode> it = parentChildren.GetEnumerator();
+
+                //while (it.MoveNext())
+                //{
+                //    if (it.Current == this)
+                //    {
+                //        it.Remove();
+                //    }
+                //}
+
+                // LUCENENET NOTE: Loop in reverse so we can remove items
+                // without screwing up our iterator.
+                for (int i = parentChildren.Count - 1; i >= 0; i--)
+                {
+                    if (parentChildren[i] == this)
+                    {
+                        parentChildren.RemoveAt(i);
+                    }
+                }
+
+                this.parent = null;
+            }
+        }
+
+        // LUCENENET specific - class must implement all members of IQueryNode
+        public abstract string ToQueryString(IEscapeQuerySyntax escapeSyntaxParser);
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QuotedFieldQueryNode.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QuotedFieldQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QuotedFieldQueryNode.cs
new file mode 100644
index 0000000..a60597b
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/QuotedFieldQueryNode.cs
@@ -0,0 +1,77 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Parser;
+using Lucene.Net.Support;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
+{
+    /// <summary>
+    /// A {@link QuotedFieldQueryNode} represents phrase query. Example:
+    /// "life is great"
+    /// </summary>
+    public class QuotedFieldQueryNode : FieldQueryNode
+    {
+        /**
+        * @param field
+        *          - field name
+        * @param text
+        *          - value
+        * @param begin
+        *          - position in the query string
+        * @param end
+        *          - position in the query string
+        */
+        // LUCENENET specific overload for text string
+        public QuotedFieldQueryNode(string field, string text, int begin,
+            int end)
+            : this(field, text.ToCharSequence(), begin, end)
+        {
+        }
+
+        /**
+        * @param field
+        *          - field name
+        * @param text
+        *          - value
+        * @param begin
+        *          - position in the query string
+        * @param end
+        *          - position in the query string
+        */
+        public QuotedFieldQueryNode(string field, ICharSequence text, int begin,
+            int end)
+            : base(field, text, begin, end)
+        {
+        }
+
+
+        public override string ToQueryString(IEscapeQuerySyntax escaper)
+        {
+            if (IsDefaultField(this.field))
+            {
+                return "\"" + GetTermEscapeQuoted(escaper) + "\"";
+            }
+            else
+            {
+                return this.field + ":" + "\"" + GetTermEscapeQuoted(escaper) + "\"";
+            }
+        }
+
+
+        public override string ToString()
+        {
+            return "<quotedfield start='" + this.begin + "' end='" + this.end
+                + "' field='" + this.field + "' term='" + this.text + "'/>";
+        }
+
+        public override IQueryNode CloneTree()
+        {
+            QuotedFieldQueryNode clone = (QuotedFieldQueryNode)base.CloneTree();
+            // nothing to do here
+            return clone;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/RangeQueryNode.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/RangeQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/RangeQueryNode.cs
new file mode 100644
index 0000000..6e64892
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/RangeQueryNode.cs
@@ -0,0 +1,32 @@
+\ufeffusing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
+{
+    /// <summary>
+    /// This interface should be implemented by a {@link QueryNode} that represents
+    /// some kind of range query.
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public interface IRangeQueryNode<T> : IRangeQueryNode, IFieldableNode
+        where T : IFieldableNode /*IFieldValuePairQueryNode<?>*/
+    {
+        T LowerBound { get; }
+
+        T UpperBound { get; }
+
+        bool IsLowerInclusive { get; }
+
+        bool IsUpperInclusive { get; }
+    }
+
+    /// <summary>
+    /// LUCENENET specific interface for identifying a
+    /// RangeQueryNode without specifying its generic closing type
+    /// </summary>
+    public interface IRangeQueryNode
+    { }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/SlopQueryNode.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/SlopQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/SlopQueryNode.cs
new file mode 100644
index 0000000..98fd5c1
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/SlopQueryNode.cs
@@ -0,0 +1,116 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Messages;
+using Lucene.Net.QueryParsers.Flexible.Core.Parser;
+using Lucene.Net.QueryParsers.Flexible.Messages;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
+{
+    /// <summary>
+    /// A {@link SlopQueryNode} represents phrase query with a slop.
+    /// 
+    /// From Lucene FAQ: Is there a way to use a proximity operator (like near or
+    /// within) with Lucene? There is a variable called slop that allows you to
+    /// perform NEAR/WITHIN-like queries. By default, slop is set to 0 so that only
+    /// exact phrases will match. When using TextParser you can use this syntax to
+    /// specify the slop: "doug cutting"~2 will find documents that contain
+    /// "doug cutting" as well as ones that contain "cutting doug".
+    /// </summary>
+    public class SlopQueryNode : QueryNodeImpl, IFieldableNode
+    {
+        private int value = 0;
+
+        /**
+         * @param query
+         *          - QueryNode Tree with the phrase
+         * @param value
+         *          - slop value
+         */
+        public SlopQueryNode(IQueryNode query, int value)
+        {
+            if (query == null)
+            {
+                throw new QueryNodeError(new MessageImpl(
+                    QueryParserMessages.NODE_ACTION_NOT_SUPPORTED, "query", "null"));
+            }
+
+            this.value = value;
+            SetLeaf(false);
+            Allocate();
+            Add(query);
+        }
+
+        public IQueryNode GetChild()
+        {
+            return GetChildren()[0];
+        }
+
+        public int GetValue()
+        {
+            return this.value;
+        }
+
+        private string GetValueString()
+        {
+            float f = this.value;
+            if (f == (long)f)
+                return "" + (long)f;
+            else
+                return "" + f;
+
+        }
+
+
+        public override string ToString()
+        {
+            return "<slop value='" + GetValueString() + "'>" + "\n"
+                + GetChild().ToString() + "\n</slop>";
+        }
+
+
+        public override string ToQueryString(IEscapeQuerySyntax escapeSyntaxParser)
+        {
+            if (GetChild() == null)
+                return "";
+            return GetChild().ToQueryString(escapeSyntaxParser) + "~"
+                + GetValueString();
+        }
+
+        public override IQueryNode CloneTree()
+        {
+            SlopQueryNode clone = (SlopQueryNode)base.CloneTree();
+
+            clone.value = this.value;
+
+            return clone;
+        }
+
+        public virtual string Field
+        {
+            get
+            {
+                IQueryNode child = GetChild();
+
+                if (child is IFieldableNode)
+                {
+                    return ((IFieldableNode)child).Field;
+                }
+
+                return null;
+            }
+            set
+            {
+                IQueryNode child = GetChild();
+
+                if (child is IFieldableNode)
+                {
+                    ((IFieldableNode)child).Field = value;
+                }
+            }
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/TextableQueryNode.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/TextableQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/TextableQueryNode.cs
new file mode 100644
index 0000000..317e060
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/TextableQueryNode.cs
@@ -0,0 +1,17 @@
+\ufeffusing Lucene.Net.Support;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
+{
+    /// <summary>
+    /// Interface for a node that has text as a {@link CharSequence}
+    /// </summary>
+    public interface ITextableQueryNode
+    {
+        ICharSequence Text { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/TokenizedPhraseQueryNode.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/TokenizedPhraseQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/TokenizedPhraseQueryNode.cs
new file mode 100644
index 0000000..4cb5452
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/TokenizedPhraseQueryNode.cs
@@ -0,0 +1,103 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Parser;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
+{
+    /// <summary>
+    /// A {@link TokenizedPhraseQueryNode} represents a node created by a code that
+    /// tokenizes/lemmatizes/analyzes.
+    /// </summary>
+    public class TokenizedPhraseQueryNode : QueryNodeImpl, IFieldableNode
+    {
+        public TokenizedPhraseQueryNode()
+        {
+            SetLeaf(false);
+            Allocate();
+        }
+
+
+        public override string ToString()
+        {
+            if (GetChildren() == null || GetChildren().Count == 0)
+                return "<tokenizedphrase/>";
+            StringBuilder sb = new StringBuilder();
+            sb.Append("<tokenizedtphrase>");
+            foreach (IQueryNode child in GetChildren())
+            {
+                sb.Append("\n");
+                sb.Append(child.ToString());
+            }
+            sb.Append("\n</tokenizedphrase>");
+            return sb.ToString();
+        }
+
+        // This text representation is not re-parseable
+
+        public override string ToQueryString(IEscapeQuerySyntax escapeSyntaxParser)
+        {
+            if (GetChildren() == null || GetChildren().Count == 0)
+                return "";
+
+            StringBuilder sb = new StringBuilder();
+            string filler = "";
+            foreach (IQueryNode child in GetChildren())
+            {
+                sb.Append(filler).Append(child.ToQueryString(escapeSyntaxParser));
+                filler = ",";
+            }
+
+            return "[TP[" + sb.ToString() + "]]";
+        }
+
+        public override IQueryNode CloneTree()
+        {
+            TokenizedPhraseQueryNode clone = (TokenizedPhraseQueryNode)base
+        .CloneTree();
+
+            // nothing to do
+
+            return clone;
+        }
+
+        public string Field
+        {
+            get
+            {
+                IList<IQueryNode> children = GetChildren();
+
+                if (children == null || children.Count == 0)
+                {
+                    return null;
+
+                }
+                else
+                {
+                    return ((IFieldableNode)children[0]).Field;
+                }
+            }
+            set
+            {
+                IList<IQueryNode> children = GetChildren();
+
+                if (children != null)
+                {
+
+                    foreach (IQueryNode child in GetChildren())
+                    {
+
+                        if (child is IFieldableNode)
+                        {
+                            ((IFieldableNode)child).Field = value;
+                        }
+
+                    }
+                }
+            }
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ValueQueryNode.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ValueQueryNode.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ValueQueryNode.cs
new file mode 100644
index 0000000..ee0dbd22
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Nodes/ValueQueryNode.cs
@@ -0,0 +1,18 @@
+\ufeffusing System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Nodes
+{
+    /// <summary>
+    /// This interface should be implemented by {@link QueryNode} that holds an
+    /// arbitrary value.
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public interface IValueQueryNode<T> : IQueryNode
+    {
+        T Value { get; set; }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Parser/EscapeQuerySyntax.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Parser/EscapeQuerySyntax.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Parser/EscapeQuerySyntax.cs
new file mode 100644
index 0000000..d0e6803
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Parser/EscapeQuerySyntax.cs
@@ -0,0 +1,39 @@
+\ufeffusing Lucene.Net.Support;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Parser
+{
+    /// <summary>
+    /// A parser needs to implement {@link EscapeQuerySyntax} to allow the QueryNode
+    /// to escape the queries, when the toQueryString method is called.
+    /// </summary>
+    public interface IEscapeQuerySyntax
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="text"> text to be escaped</param>
+        /// <param name="locale">locale for the current query</param>
+        /// <param name="type">select the type of escape operation to use</param>
+        /// <returns>escaped text</returns>
+        ICharSequence Escape(ICharSequence text, CultureInfo locale, EscapeQuerySyntax.Type type);
+    }
+
+    public static class EscapeQuerySyntax
+    {
+        /// <summary>
+        /// Type of escaping: String for escaping syntax,
+        /// NORMAL for escaping reserved words (like AND) in terms
+        /// </summary>
+        public enum Type
+        {
+            STRING,
+            NORMAL
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Parser/SyntaxParser.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Parser/SyntaxParser.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Parser/SyntaxParser.cs
new file mode 100644
index 0000000..387019d
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Parser/SyntaxParser.cs
@@ -0,0 +1,23 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Parser
+{
+    /// <summary>
+    /// A parser needs to implement {@link SyntaxParser} interface
+    /// </summary>
+    public interface ISyntaxParser
+    {
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="query">query data to be parsed</param>
+        /// <param name="field">default field name</param>
+        /// <returns>QueryNode tree</returns>
+        IQueryNode Parse(string query, string field);
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Processors/NoChildOptimizationQueryNodeProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Processors/NoChildOptimizationQueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Processors/NoChildOptimizationQueryNodeProcessor.cs
new file mode 100644
index 0000000..862ad1f
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Processors/NoChildOptimizationQueryNodeProcessor.cs
@@ -0,0 +1,73 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Processors
+{
+    /// <summary>
+    /// A {@link NoChildOptimizationQueryNodeProcessor} removes every
+    /// BooleanQueryNode, BoostQueryNode, TokenizedPhraseQueryNode or
+    /// ModifierQueryNode that do not have a valid children.
+    /// <para>
+    /// Example: When the children of these nodes are removed for any reason then the
+    /// nodes may become invalid.
+    /// </para>
+    /// </summary>
+    public class NoChildOptimizationQueryNodeProcessor : QueryNodeProcessorImpl
+    {
+        public NoChildOptimizationQueryNodeProcessor()
+        {
+            // empty constructor
+        }
+
+
+        protected override IQueryNode PostProcessNode(IQueryNode node)
+        {
+
+            if (node is BooleanQueryNode || node is BoostQueryNode
+                || node is TokenizedPhraseQueryNode
+                || node is ModifierQueryNode)
+            {
+
+                IList<IQueryNode> children = node.GetChildren();
+
+                if (children != null && children.Count > 0)
+                {
+
+                    foreach (IQueryNode child in children)
+                    {
+
+                        if (!(child is DeletedQueryNode))
+                        {
+                            return node;
+                        }
+
+                    }
+
+                }
+
+                return new MatchNoDocsQueryNode();
+
+            }
+
+            return node;
+
+        }
+
+
+        protected override IQueryNode PreProcessNode(IQueryNode node)
+        {
+
+            return node;
+
+        }
+
+        protected override IList<IQueryNode> SetChildrenOrder(IList<IQueryNode> children)
+        {
+            return children;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Processors/QueryNodeProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Processors/QueryNodeProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Processors/QueryNodeProcessor.cs
new file mode 100644
index 0000000..df3a851
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Processors/QueryNodeProcessor.cs
@@ -0,0 +1,61 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Config;
+using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Processors
+{
+    /// <summary>
+    /// A {@link QueryNodeProcessor} is an interface for classes that process a
+    /// {@link QueryNode} tree.
+    /// <para>
+    /// The implementor of this class should perform some operation on a query node
+    /// tree and return the same or another query node tree.
+    /// </para>
+    /// <para>
+    /// It also may carry a {@link QueryConfigHandler} object that contains
+    /// configuration about the query represented by the query tree or the
+    /// collection/index where it's intended to be executed.
+    /// </para>
+    /// <para>
+    /// In case there is any {@link QueryConfigHandler} associated to the query tree
+    /// to be processed, it should be set using
+    /// {@link QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler)} before
+    /// {@link QueryNodeProcessor#process(QueryNode)} is invoked.
+    /// </para>
+    /// </summary>
+    /// <seealso cref="IQueryNode"/>
+    /// <seealso cref="QueryNodeProcessor"/>
+    /// <seealso cref="QueryConfigHandler"/>
+    public interface IQueryNodeProcessor
+    {
+        /**
+        * Processes a query node tree. It may return the same or another query tree.
+        * I should never return <code>null</code>.
+        * 
+        * @param queryTree
+        *          tree root node
+        * 
+        * @return the processed query tree
+        */
+        IQueryNode Process(IQueryNode queryTree);
+
+        /**
+         * Sets the {@link QueryConfigHandler} associated to the query tree.
+         */
+        void SetQueryConfigHandler(QueryConfigHandler queryConfigHandler);
+
+        /**
+         * Returns the {@link QueryConfigHandler} associated to the query tree if any,
+         * otherwise it returns <code>null</code>
+         * 
+         * @return the {@link QueryConfigHandler} associated to the query tree if any,
+         *         otherwise it returns <code>null</code>
+         */
+        QueryConfigHandler GetQueryConfigHandler();
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Processors/QueryNodeProcessorImpl.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Processors/QueryNodeProcessorImpl.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Processors/QueryNodeProcessorImpl.cs
new file mode 100644
index 0000000..23aa179
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Processors/QueryNodeProcessorImpl.cs
@@ -0,0 +1,202 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Config;
+using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Processors
+{
+    public abstract class QueryNodeProcessorImpl : IQueryNodeProcessor
+    {
+        private List<ChildrenList> childrenListPool = new List<ChildrenList>();
+
+        private QueryConfigHandler queryConfig;
+
+        public QueryNodeProcessorImpl()
+        {
+            // empty constructor
+        }
+
+        public QueryNodeProcessorImpl(QueryConfigHandler queryConfigHandler)
+        {
+            this.queryConfig = queryConfigHandler;
+        }
+
+
+        public virtual IQueryNode Process(IQueryNode queryTree)
+        {
+            return ProcessIteration(queryTree);
+        }
+
+        private IQueryNode ProcessIteration(IQueryNode queryTree)
+        {
+            queryTree = PreProcessNode(queryTree);
+
+            ProcessChildren(queryTree);
+
+            queryTree = PostProcessNode(queryTree);
+
+            return queryTree;
+
+        }
+
+        /**
+         * This method is called every time a child is processed.
+         * 
+         * @param queryTree
+         *          the query node child to be processed
+         * @throws QueryNodeException
+         *           if something goes wrong during the query node processing
+         */
+        protected virtual void ProcessChildren(IQueryNode queryTree)
+        {
+
+            IList<IQueryNode> children = queryTree.GetChildren();
+            ChildrenList newChildren;
+
+            if (children != null && children.Count > 0)
+            {
+
+                newChildren = AllocateChildrenList();
+
+                try
+                {
+
+                    foreach (IQueryNode child in children)
+                    {
+                        var child2 = ProcessIteration(child);
+
+                        if (child2 == null)
+                        {
+                            throw new NullReferenceException();
+
+                        }
+
+                        newChildren.Add(child2);
+
+                    }
+
+                    IList<IQueryNode> orderedChildrenList = SetChildrenOrder(newChildren);
+
+                    queryTree.Set(orderedChildrenList);
+
+                }
+                finally
+                {
+                    newChildren.beingUsed = false;
+                }
+
+            }
+
+        }
+
+        private ChildrenList AllocateChildrenList()
+        {
+            ChildrenList list = null;
+
+            foreach (ChildrenList auxList in this.childrenListPool)
+            {
+
+                if (!auxList.beingUsed)
+                {
+                    list = auxList;
+                    list.Clear();
+
+                    break;
+
+                }
+
+            }
+
+            if (list == null)
+            {
+                list = new ChildrenList();
+                this.childrenListPool.Add(list);
+
+            }
+
+            list.beingUsed = true;
+
+            return list;
+
+        }
+
+        /**
+         * For reference about this method check:
+         * {@link QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler)}.
+         * 
+         * @param queryConfigHandler
+         *          the query configuration handler to be set.
+         * 
+         * @see QueryNodeProcessor#getQueryConfigHandler()
+         * @see QueryConfigHandler
+         */
+
+        public virtual void SetQueryConfigHandler(QueryConfigHandler queryConfigHandler)
+        {
+            this.queryConfig = queryConfigHandler;
+        }
+
+        /**
+         * For reference about this method check:
+         * {@link QueryNodeProcessor#getQueryConfigHandler()}.
+         * 
+         * @return QueryConfigHandler the query configuration handler to be set.
+         * 
+         * @see QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler)
+         * @see QueryConfigHandler
+         */
+        public virtual QueryConfigHandler GetQueryConfigHandler()
+        {
+            return this.queryConfig;
+        }
+
+        /**
+         * This method is invoked for every node when walking down the tree.
+         * 
+         * @param node
+         *          the query node to be pre-processed
+         * 
+         * @return a query node
+         * 
+         * @throws QueryNodeException
+         *           if something goes wrong during the query node processing
+         */
+        protected abstract IQueryNode PreProcessNode(IQueryNode node);
+
+        /**
+         * This method is invoked for every node when walking up the tree.
+         * 
+         * @param node
+         *          node the query node to be post-processed
+         * 
+         * @return a query node
+         * 
+         * @throws QueryNodeException
+         *           if something goes wrong during the query node processing
+         */
+        protected abstract IQueryNode PostProcessNode(IQueryNode node);
+
+        /**
+         * This method is invoked for every node that has at least on child. It's
+         * invoked right before {@link #postProcessNode(QueryNode)} is invoked.
+         * 
+         * @param children
+         *          the list containing all current node's children
+         * 
+         * @return a new list containing all children that should be set to the
+         *         current node
+         * 
+         * @throws QueryNodeException
+         *           if something goes wrong during the query node processing
+         */
+        protected abstract IList<IQueryNode> SetChildrenOrder(IList<IQueryNode> children);
+
+        private class ChildrenList : List<IQueryNode>
+        {
+            internal bool beingUsed;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Processors/QueryNodeProcessorPipeline.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Processors/QueryNodeProcessorPipeline.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Processors/QueryNodeProcessorPipeline.cs
new file mode 100644
index 0000000..7ffdd1e
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Processors/QueryNodeProcessorPipeline.cs
@@ -0,0 +1,425 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Config;
+using Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Collections;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Processors
+{
+    public class QueryNodeProcessorPipeline : IQueryNodeProcessor, IList<IQueryNodeProcessor>
+    {
+        //private LinkedList<IQueryNodeProcessor> processors = new LinkedList<IQueryNodeProcessor>();
+        private List<IQueryNodeProcessor> processors = new List<IQueryNodeProcessor>();
+
+        private QueryConfigHandler queryConfig;
+
+        /**
+         * Constructs an empty query node processor pipeline.
+         */
+        public QueryNodeProcessorPipeline()
+        {
+            // empty constructor
+        }
+
+        /**
+         * Constructs with a {@link QueryConfigHandler} object.
+         */
+        public QueryNodeProcessorPipeline(QueryConfigHandler queryConfigHandler)
+        {
+            this.queryConfig = queryConfigHandler;
+        }
+
+        /**
+         * For reference about this method check:
+         * {@link QueryNodeProcessor#getQueryConfigHandler()}.
+         * 
+         * @return QueryConfigHandler the query configuration handler to be set.
+         * 
+         * @see QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler)
+         * @see QueryConfigHandler
+         */
+        public virtual QueryConfigHandler GetQueryConfigHandler()
+        {
+            return this.queryConfig;
+        }
+
+        /**
+         * For reference about this method check:
+         * {@link QueryNodeProcessor#process(QueryNode)}.
+         * 
+         * @param queryTree the query node tree to be processed
+         * 
+         * @throws QueryNodeException if something goes wrong during the query node
+         *         processing
+         * 
+         * @see QueryNode
+         */
+
+        public virtual IQueryNode Process(IQueryNode queryTree)
+        {
+
+            foreach (IQueryNodeProcessor processor in this.processors)
+            {
+                queryTree = processor.Process(queryTree);
+            }
+
+            return queryTree;
+
+        }
+
+        /**
+         * For reference about this method check:
+         * {@link QueryNodeProcessor#setQueryConfigHandler(QueryConfigHandler)}.
+         * 
+         * @param queryConfigHandler the query configuration handler to be set.
+         * 
+         * @see QueryNodeProcessor#getQueryConfigHandler()
+         * @see QueryConfigHandler
+         */
+
+        public virtual void SetQueryConfigHandler(QueryConfigHandler queryConfigHandler)
+        {
+            this.queryConfig = queryConfigHandler;
+
+            foreach (IQueryNodeProcessor processor in this.processors)
+            {
+                processor.SetQueryConfigHandler(this.queryConfig);
+            }
+
+        }
+
+        /**
+         * @see List#add(Object)
+         */
+
+        public virtual bool Add(IQueryNodeProcessor processor)
+        {
+            this.processors.Add(processor);
+            bool added = processors.Contains(processor);
+
+            if (added)
+            {
+                processor.SetQueryConfigHandler(this.queryConfig);
+            }
+
+            return added;
+
+        }
+
+        /**
+         * @see List#add(int, Object)
+         */
+
+        public virtual void Add(int index, IQueryNodeProcessor processor)
+        {
+            this.processors.Insert(index, processor);
+            processor.SetQueryConfigHandler(this.queryConfig);
+
+        }
+
+        //      /**
+        //       * @see List#addAll(Collection)
+        //       */
+
+        //public virtual bool AddAll(Collection<? extends QueryNodeProcessor> c)
+        //      {
+        //          boolean anyAdded = this.processors.addAll(c);
+
+        //          for (QueryNodeProcessor processor : c)
+        //          {
+        //              processor.setQueryConfigHandler(this.queryConfig);
+        //          }
+
+        //          return anyAdded;
+
+        //      }
+
+        //      /**
+        //       * @see List#addAll(int, Collection)
+        //       */
+        //      @Override
+        //public boolean addAll(int index, Collection<? extends QueryNodeProcessor> c)
+        //      {
+        //          boolean anyAdded = this.processors.addAll(index, c);
+
+        //          for (QueryNodeProcessor processor : c)
+        //          {
+        //              processor.setQueryConfigHandler(this.queryConfig);
+        //          }
+
+        //          return anyAdded;
+
+        //      }
+
+        /**
+         * @see List#clear()
+         */
+
+        public virtual void Clear()
+        {
+            this.processors.Clear();
+        }
+
+        /**
+         * @see List#contains(Object)
+         */
+
+        public virtual bool Contains(object o)
+        {
+            return this.processors.Contains(o);
+        }
+
+        //      /**
+        //       * @see List#containsAll(Collection)
+        //       */
+        //      @Override
+        //public boolean containsAll(Collection<?> c)
+        //      {
+        //          return this.processors.containsAll(c);
+        //      }
+
+        //      /**
+        //       * @see List#get(int)
+        //       */
+        //      @Override
+        //public QueryNodeProcessor Get(int index)
+        //      {
+        //          return this.processors.get(index);
+        //      }
+
+        public virtual IQueryNodeProcessor this[int index]
+        {
+            get
+            {
+                return this.processors[index];
+            }
+            set
+            {
+                IQueryNodeProcessor oldProcessor = this.processors[index];
+                this.processors[index] = value;
+
+                if (oldProcessor != value)
+                {
+                    value.SetQueryConfigHandler(this.queryConfig);
+                }
+
+                //return oldProcessor;
+            }
+        }
+
+        /**
+         * @see List#indexOf(Object)
+         */
+
+        public virtual int IndexOf(object o)
+        {
+            return this.processors.IndexOf(o as IQueryNodeProcessor);
+        }
+
+        public virtual int IndexOf(IQueryNodeProcessor o)
+        {
+            return this.processors.IndexOf(o);
+        }
+
+        //      /**
+        //       * @see List#isEmpty()
+        //       */
+        //      @Override
+        //public boolean isEmpty()
+        //      {
+        //          return this.processors.isEmpty();
+        //      }
+
+        //      /**
+        //       * @see List#iterator()
+        //       */
+        //      @Override
+        //public Iterator<QueryNodeProcessor> iterator()
+        //      {
+        //          return this.processors.iterator();
+        //      }
+
+        public virtual IEnumerator<IQueryNodeProcessor> GetEnumerator()
+        {
+            return this.processors.GetEnumerator();
+        }
+
+        //      /**
+        //       * @see List#lastIndexOf(Object)
+        //       */
+        //      @Override
+        //public int lastIndexOf(Object o)
+        //      {
+        //          return this.processors.lastIndexOf(o);
+        //      }
+
+        //      /**
+        //       * @see List#listIterator()
+        //       */
+        //      @Override
+        //public ListIterator<QueryNodeProcessor> listIterator()
+        //      {
+        //          return this.processors.listIterator();
+        //      }
+
+        //      /**
+        //       * @see List#listIterator(int)
+        //       */
+        //      @Override
+        //public ListIterator<QueryNodeProcessor> listIterator(int index)
+        //      {
+        //          return this.processors.listIterator(index);
+        //      }
+
+        /**
+         * @see List#remove(Object)
+         */
+
+        public bool Remove(object o)
+        {
+            return this.processors.Remove(o as IQueryNodeProcessor);
+        }
+
+        public virtual bool Remove(IQueryNodeProcessor o)
+        {
+            return this.processors.Remove(o);
+        }
+
+        //      /**
+        //       * @see List#remove(int)
+        //       */
+        //      @Override
+        //public QueryNodeProcessor remove(int index)
+        //      {
+        //          return this.processors.remove(index);
+        //      }
+
+        public virtual void RemoveAt(int index)
+        {
+            this.processors.RemoveAt(index);
+        }
+
+        //      /**
+        //       * @see List#removeAll(Collection)
+        //       */
+        //      @Override
+        //public boolean removeAll(Collection<?> c)
+        //      {
+        //          return this.processors.removeAll(c);
+        //      }
+
+        public virtual void RemoveRange(int index, int count)
+        {
+            this.processors.RemoveRange(index, count);
+        }
+
+        //      /**
+        //       * @see List#retainAll(Collection)
+        //       */
+        //      @Override
+        //public boolean retainAll(Collection<?> c)
+        //      {
+        //          return this.processors.retainAll(c);
+        //      }
+
+        /**
+         * @see List#set(int, Object)
+         */
+
+        public virtual IQueryNodeProcessor Set(int index, IQueryNodeProcessor processor)
+        {
+            IQueryNodeProcessor oldProcessor = this.processors[index];
+            this.processors[index] = processor;
+
+            if (oldProcessor != processor)
+            {
+                processor.SetQueryConfigHandler(this.queryConfig);
+            }
+
+            return oldProcessor;
+
+        }
+
+        //      /**
+        //       * @see List#size()
+        //       */
+        //      @Override
+        //public int size()
+        //      {
+        //          return this.processors.size();
+        //      }
+
+        public int Count
+        {
+            get { return this.processors.Count; }
+        }
+
+        public bool IsReadOnly
+        {
+            get
+            {
+                return false;
+            }
+        }
+
+        //      /**
+        //       * @see List#subList(int, int)
+        //       */
+        //      @Override
+        //public List<QueryNodeProcessor> subList(int fromIndex, int toIndex)
+        //      {
+        //          return this.processors.subList(fromIndex, toIndex);
+        //      }
+
+        public virtual List<IQueryNodeProcessor> GetRange(int index, int count)
+        {
+            return this.processors.GetRange(index, count);
+        }
+
+        public void Insert(int index, IQueryNodeProcessor item)
+        {
+            this.processors.Insert(index, item);
+        }
+
+        void ICollection<IQueryNodeProcessor>.Add(IQueryNodeProcessor item)
+        {
+            this.processors.Add(item);
+        }
+
+        public bool Contains(IQueryNodeProcessor item)
+        {
+            return this.processors.Contains(item);
+        }
+
+        public void CopyTo(IQueryNodeProcessor[] array, int arrayIndex)
+        {
+            this.processors.CopyTo(array, arrayIndex);
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        //      /**
+        //       * @see List#toArray(Object[])
+        //       */
+        //      @Override
+        //public <T> T[] toArray(T[] array)
+        //      {
+        //          return this.processors.toArray(array);
+        //      }
+
+        //      /**
+        //       * @see List#toArray()
+        //       */
+        //      @Override
+        //public Object[] toArray()
+        //      {
+        //          return this.processors.toArray();
+        //      }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/Processors/RemoveDeletedQueryNodesProcessor.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/Processors/RemoveDeletedQueryNodesProcessor.cs b/src/Lucene.Net.QueryParser/Flexible/Core/Processors/RemoveDeletedQueryNodesProcessor.cs
new file mode 100644
index 0000000..95214f9
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/Processors/RemoveDeletedQueryNodesProcessor.cs
@@ -0,0 +1,102 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Nodes;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core.Processors
+{
+    /// <summary>
+    /// A {@link QueryNodeProcessorPipeline} class removes every instance of
+    /// {@link DeletedQueryNode} from a query node tree. If the resulting root node
+    /// is a {@link DeletedQueryNode}, {@link MatchNoDocsQueryNode} is returned.
+    /// </summary>
+    public class RemoveDeletedQueryNodesProcessor : QueryNodeProcessorImpl
+    {
+        public RemoveDeletedQueryNodesProcessor()
+        {
+            // empty constructor
+        }
+
+
+        public override IQueryNode Process(IQueryNode queryTree)
+        {
+            queryTree = base.Process(queryTree);
+
+            if (queryTree is DeletedQueryNode
+                && !(queryTree is MatchNoDocsQueryNode))
+            {
+
+                return new MatchNoDocsQueryNode();
+
+            }
+
+            return queryTree;
+
+        }
+
+
+        protected override IQueryNode PostProcessNode(IQueryNode node)
+        {
+
+            if (!node.IsLeaf())
+            {
+                IList<IQueryNode> children = node.GetChildren();
+                bool removeBoolean = false;
+
+                if (children == null || children.Count == 0)
+                {
+                    removeBoolean = true;
+
+                }
+                else
+                {
+                    removeBoolean = true;
+
+                    for (IEnumerator<IQueryNode> it = children.GetEnumerator(); it.MoveNext();)
+                    {
+
+                        if (!(it.Current is DeletedQueryNode))
+                        {
+                            removeBoolean = false;
+                            break;
+
+                        }
+
+                    }
+
+                }
+
+                if (removeBoolean)
+                {
+                    return new DeletedQueryNode();
+                }
+
+            }
+
+            return node;
+        }
+
+
+        protected override IList<IQueryNode> SetChildrenOrder(IList<IQueryNode> children)
+        {
+            for (int i = 0; i < children.Count; i++)
+            {
+
+                if (children[i] is DeletedQueryNode)
+                {
+                    children.RemoveAt(i--);
+                }
+
+            }
+
+            return children;
+        }
+
+        protected override IQueryNode PreProcessNode(IQueryNode node)
+        {
+            return node;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeError.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeError.cs b/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeError.cs
new file mode 100644
index 0000000..e92e399
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeError.cs
@@ -0,0 +1,64 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Messages;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core
+{
+    /// <summary>
+    /// Error class with NLS support
+    /// </summary>
+    /// <seealso cref="Messages.NLS"/>
+    /// <seealso cref="Messages.Message"/>
+    [Serializable]
+    public class QueryNodeError : Exception, INLSException
+    {
+        private IMessage message;
+
+        /**
+         * @param message
+         *          - NLS Message Object
+         */
+        public QueryNodeError(IMessage message)
+            : base(message.Key)
+        {
+            this.message = message;
+
+        }
+
+        /**
+         * @param throwable
+         *          - @see java.lang.Error
+         */
+        public QueryNodeError(Exception throwable)
+            : base(throwable.Message, throwable)
+        {
+        }
+
+        /**
+         * @param message
+         *          - NLS Message Object
+         * @param throwable
+         *          - @see java.lang.Error
+         */
+        public QueryNodeError(IMessage message, Exception throwable)
+            : base(message.Key, throwable)
+        {
+            this.message = message;
+
+        }
+
+        /*
+         * (non-Javadoc)
+         * 
+         * @see org.apache.lucene.messages.NLSException#getMessageObject()
+         */
+
+        public virtual IMessage MessageObject
+        {
+            get { return this.message; }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeException.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeException.cs b/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeException.cs
new file mode 100644
index 0000000..881f738
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeException.cs
@@ -0,0 +1,75 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Messages;
+using Lucene.Net.QueryParsers.Flexible.Messages;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core
+{
+    /// <summary>
+    /// This exception should be thrown if something wrong happens when dealing with
+    /// {@link QueryNode}s.
+    /// <para>
+    /// It also supports NLS messages.
+    /// </para>
+    /// </summary>
+    /// <seealso cref="Message"/>
+    /// <seealso cref="NLS"/>
+    /// <seealso cref="NLSException"/>
+    /// <seealso cref="IQueryNode"/>
+    [Serializable]
+    public class QueryNodeException : Exception, INLSException
+    {
+        protected IMessage message = new MessageImpl(QueryParserMessages.EMPTY_MESSAGE);
+
+        public QueryNodeException(IMessage message)
+            : base(message.Key)
+        {
+            this.message = message;
+
+        }
+
+        public QueryNodeException(Exception throwable)
+            : base(throwable.Message, throwable)
+        {
+        }
+
+        public QueryNodeException(IMessage message, Exception throwable)
+            : base(message.Key, throwable)
+        {
+            this.message = message;
+        }
+
+
+        public virtual IMessage MessageObject
+        {
+            get { return this.message; }
+        }
+
+
+        public override string Message
+        {
+            get { return GetLocalizedMessage(); }
+        }
+
+
+        public string GetLocalizedMessage()
+        {
+            return GetLocalizedMessage(CultureInfo.InvariantCulture);
+        }
+
+        public string GetLocalizedMessage(CultureInfo locale)
+        {
+            return this.message.GetLocalizedMessage(locale);
+        }
+
+
+        public override string ToString()
+        {
+            return this.message.Key + ": " + GetLocalizedMessage();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/c83be6be/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeParseException.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeParseException.cs b/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeParseException.cs
new file mode 100644
index 0000000..c6cd651
--- /dev/null
+++ b/src/Lucene.Net.QueryParser/Flexible/Core/QueryNodeParseException.cs
@@ -0,0 +1,117 @@
+\ufeffusing Lucene.Net.QueryParsers.Flexible.Core.Messages;
+using Lucene.Net.QueryParsers.Flexible.Messages;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Lucene.Net.QueryParsers.Flexible.Core
+{
+    /// <summary>
+    /// This should be thrown when an exception happens during the query parsing from
+    /// string to the query node tree.
+    /// </summary>
+    /// <seealso cref="QueryNodeException"/>
+    /// <seealso cref="ISyntaxParser"/>
+    /// <seealso cref="IQueryNode"/>
+    [Serializable]
+    public class QueryNodeParseException : QueryNodeException
+    {
+        private string query;
+
+        private int beginColumn = -1;
+
+        private int beginLine = -1;
+
+        private string errorToken = "";
+
+        public QueryNodeParseException(IMessage message)
+            : base(message)
+        {
+        }
+
+        public QueryNodeParseException(Exception throwable)
+            : base(throwable)
+        {
+        }
+
+        public QueryNodeParseException(IMessage message, Exception throwable)
+            : base(message, throwable)
+        {
+        }
+
+        public void SetQuery(string query)
+        {
+            this.query = query;
+            this.message = new MessageImpl(
+                QueryParserMessages.INVALID_SYNTAX_CANNOT_PARSE, query, "");
+        }
+
+        public string GetQuery()
+        {
+            return this.query;
+        }
+
+        /**
+         * @param errorToken
+         *          the errorToken in the query
+         */
+        protected void SetErrorToken(string errorToken)
+        {
+            this.errorToken = errorToken;
+        }
+
+        public string GetErrorToken()
+        {
+            return this.errorToken;
+        }
+
+        public void SetNonLocalizedMessage(IMessage message)
+        {
+            this.message = message;
+        }
+
+        /**
+         * For EndOfLine and EndOfFile ("&lt;EOF&gt;") parsing problems the last char in the
+         * string is returned For the case where the parser is not able to figure out
+         * the line and column number -1 will be returned
+         * 
+         * @return line where the problem was found
+         */
+        public int GetBeginLine()
+        {
+            return this.beginLine;
+        }
+
+        /**
+         * For EndOfLine and EndOfFile ("&lt;EOF&gt;") parsing problems the last char in the
+         * string is returned For the case where the parser is not able to figure out
+         * the line and column number -1 will be returned
+         * 
+         * @return column of the first char where the problem was found
+         */
+        public int GetBeginColumn()
+        {
+            return this.beginColumn;
+        }
+
+        /**
+         * @param beginLine
+         *          the beginLine to set
+         */
+        protected void SetBeginLine(int beginLine)
+        {
+            this.beginLine = beginLine;
+        }
+
+        /**
+         * @param beginColumn
+         *          the beginColumn to set
+         */
+        protected void SetBeginColumn(int beginColumn)
+        {
+            this.beginColumn = beginColumn;
+        }
+    }
+}