| /****************************************************************************  | 
| **  | 
| ** Copyright (C) 2019 The Qt Company Ltd.  | 
| ** Contact: https://www.qt.io/licensing/  | 
| **  | 
| ** This file is part of the Qt VS Tools.  | 
| **  | 
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$  | 
| ** Commercial License Usage  | 
| ** Licensees holding valid commercial Qt licenses may use this file in  | 
| ** accordance with the commercial license agreement provided with the  | 
| ** Software or, alternatively, in accordance with the terms contained in  | 
| ** a written agreement between you and The Qt Company. For licensing terms  | 
| ** and conditions see https://www.qt.io/terms-conditions. For further  | 
| ** information use the contact form at https://www.qt.io/contact-us.  | 
| **  | 
| ** GNU General Public License Usage  | 
| ** Alternatively, this file may be used under the terms of the GNU  | 
| ** General Public License version 3 as published by the Free Software  | 
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT  | 
| ** included in the packaging of this file. Please review the following  | 
| ** information to ensure the GNU General Public License requirements will  | 
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html.  | 
| **  | 
| ** $QT_END_LICENSE$  | 
| **  | 
| ****************************************************************************/  | 
|   | 
| using System;  | 
| using System.Collections;  | 
| using System.Collections.Generic;  | 
| using System.Linq;  | 
| using System.Text;  | 
|   | 
| namespace QtVsTools.SyntaxAnalysis  | 
| {  | 
|     using static CharClassSet;  | 
|     using static CharClass.CharSetExprBuilder;  | 
|   | 
|     ////////////////////////////////////////////////////////////////////////////////////////////////  | 
|     ///  | 
|     /// CharClassSet ( -> CharClass -> RegExpr )  | 
|     ///  | 
|     ////////////////////////////////////////////////////////////////////////////////////////////////  | 
|     /// <summary>  | 
|     /// Represents a complex class defined by a combination of elementary character classes.  | 
|     /// </summary>  | 
|     ///  | 
|     public partial class CharClassSet : CharClass, IEnumerable<IEnumerable<Element>>  | 
|     {  | 
|         public IEnumerable<Element> Positives { get; set; }  | 
|         public IEnumerable<Element> Negatives { get; set; }  | 
|   | 
|         bool IsSubSet { get; set; }  | 
|         bool HasPositive { get { return Positives != null && Positives.Any(); } }  | 
|         bool HasNegative { get { return Negatives != null && Negatives.Any(); } }  | 
|   | 
|         protected override IEnumerable<RegExpr> OnRender(RegExpr defaultTokenWs, RegExpr parent,  | 
|             StringBuilder pattern, ref RenderMode mode, Stack<Token> tokenStack)  | 
|         {  | 
|             base.OnRender(defaultTokenWs, parent, pattern, ref mode, tokenStack);  | 
|   | 
|             if (!HasPositive && !HasNegative)  | 
|                 return null;  | 
|   | 
|             if (!IsSubSet) {  | 
|                 if (HasPositive)  | 
|                     pattern.Append("[");  | 
|                 else  | 
|                     pattern.Append("[^");  | 
|             }  | 
|   | 
|             IEnumerable<RegExpr> children = null;  | 
|             if (HasPositive && HasNegative) {  | 
|                 children = Items(  | 
|                     new CharClassSet(positives: Positives) { IsSubSet = true },  | 
|                     new CharClassSet(negatives: Negatives) { IsSubSet = true });  | 
|             } else {  | 
|                 if (HasPositive)  | 
|                     children = Positives;  | 
|                 else if (HasNegative)  | 
|                     children = Negatives;  | 
|             }  | 
|   | 
|             return children;  | 
|         }  | 
|   | 
|         protected override void OnRenderNext(RegExpr defaultTokenWs, RegExpr parent,  | 
|             StringBuilder pattern, ref RenderMode mode, Stack<Token> tokenStack)  | 
|         {  | 
|             base.OnRenderNext(defaultTokenWs, parent, pattern, ref mode, tokenStack);  | 
|             if (!IsSubSet && HasPositive && HasNegative)  | 
|                 pattern.Append("-[");  | 
|         }  | 
|   | 
|         protected override void OnRenderEnd(RegExpr defaultTokenWs, RegExpr parent,  | 
|             StringBuilder pattern, ref RenderMode mode, Stack<Token> tokenStack)  | 
|         {  | 
|             base.OnRenderEnd(defaultTokenWs, parent, pattern, ref mode, tokenStack);  | 
|             if (!IsSubSet) {  | 
|                 if (HasPositive && HasNegative)  | 
|                     pattern.Append("]]");  | 
|                 else  | 
|                     pattern.Append("]");  | 
|             }  | 
|         }  | 
|   | 
|         public const bool Invert = true;  | 
|         public const bool Positive = true;  | 
|   | 
|         public CharClassSet(  | 
|             IEnumerable<Element> positives = null,  | 
|             IEnumerable<Element> negatives = null)  | 
|         {  | 
|             Positives = positives != null ? positives : Empty<Element>();  | 
|             Negatives = negatives != null ? negatives : Empty<Element>();  | 
|         }  | 
|   | 
|         public CharClassSet(Element element, bool negative = false) : this()  | 
|         {  | 
|             if (negative)  | 
|                 Negatives = Items(element);  | 
|             else  | 
|                 Positives = Items(element);  | 
|         }  | 
|   | 
|         public CharClassSet(CharClassSet set, bool invert = false) : this()  | 
|         {  | 
|             Add(set, invert);  | 
|         }  | 
|   | 
|         public void Add(Element element, bool negative = false)  | 
|         {  | 
|             if (negative)  | 
|                 Negatives = Negatives.Concat(Items(element));  | 
|             else  | 
|                 Positives = Positives.Concat(Items(element));  | 
|         }  | 
|   | 
|         public void Add(CharClassSet set, bool invert = false)  | 
|         {  | 
|             Positives = Positives.Concat(!invert ? set.Positives : set.Negatives);  | 
|             Negatives = Negatives.Concat(!invert ? set.Negatives : set.Positives);  | 
|         }  | 
|   | 
|         public IEnumerator<IEnumerable<Element>> GetEnumerator()  | 
|         {  | 
|             return (new[] { Positives, Negatives }).AsEnumerable().GetEnumerator();  | 
|         }  | 
|   | 
|         IEnumerator IEnumerable.GetEnumerator()  | 
|         {  | 
|             return GetEnumerator();  | 
|         }  | 
|   | 
|         public abstract class Element : CharClass  | 
|         {  | 
|             public static CharClassSet operator ~(Element x)  | 
|             { return new CharClassSet(x, negative: true); }  | 
|   | 
|             public static PositiveSet operator +(Element x, Element y)  | 
|             { return new PositiveSet(Op.Plus, x, y); }  | 
|   | 
|             public static PositiveSet operator +(Element x, PositiveSet y)  | 
|             { return new PositiveSet(Op.Plus, x, y); }  | 
|   | 
|             public static PositiveSet operator +(PositiveSet x, Element y)  | 
|             { return new PositiveSet(Op.Plus, x, y); }  | 
|   | 
|             public static Expr operator -(Element x, Element y)  | 
|             { return new Expr(Op.Minus, x, y); }  | 
|   | 
|             public static Expr operator -(Element x, PositiveSet y)  | 
|             { return new Expr(Op.Minus, x, y); }  | 
|   | 
|             public static Expr operator -(PositiveSet x, Element y)  | 
|             { return new Expr(Op.Minus, x, y); }  | 
|         }  | 
|   | 
|         public static CharClassSet operator ~(CharClassSet x)  | 
|         { return new CharClassSet(x, invert: true); }  | 
|   | 
|         public static Expr operator +(Element x, CharClassSet y)  | 
|         { return new Expr(Op.Plus, x, y); }  | 
|   | 
|         public static Expr operator +(CharClassSet x, Element y)  | 
|         { return new Expr(Op.Plus, x, y); }  | 
|   | 
|         public static Expr operator +(PositiveSet x, CharClassSet y)  | 
|         { return new Expr(Op.Plus, x, y); }  | 
|   | 
|         public static Expr operator +(CharClassSet x, PositiveSet y)  | 
|         { return new Expr(Op.Plus, x, y); }  | 
|   | 
|         public static Expr operator +(CharClassSet x, CharClassSet y)  | 
|         { return new Expr(Op.Plus, x, y); }  | 
|   | 
|         public static Expr operator -(CharClassSet x, Element y)  | 
|         { return new Expr(Op.Minus, x, y); }  | 
|   | 
|         public static Expr operator -(CharClassSet x, PositiveSet y)  | 
|         { return new Expr(Op.Minus, x, y); }  | 
|     }  | 
|   | 
|     public abstract partial class CharClass : RegExpr  | 
|     {  | 
|         public partial class CharSetExprBuilder  | 
|         {  | 
|             public enum Op { Term, Tilde, Plus, Minus }  | 
|   | 
|             public class Expr  | 
|             {  | 
|                 public Op Operator { get; private set; }  | 
|   | 
|                 public List<Expr> Factors { get; private set; }  | 
|                 public Expr(Op op, List<Expr> factors) { Operator = op; Factors = factors; }  | 
|                 public Expr(Op op, params Expr[] factors) : this(op, factors.ToList()) { }  | 
|   | 
|                 public CharClass Term { get; private set; }  | 
|                 public Expr(CharClass c) { Operator = Op.Term; Term = c; }  | 
|                 public static implicit operator Expr(CharClass c) { return new Expr(c); }  | 
|                 public static implicit operator Expr(string s) { return Char[s]; }  | 
|                 public static implicit operator Expr(char c) { return Char[c]; }  | 
|                 public static Expr operator ~(Expr x)  | 
|                 { return new Expr(Op.Tilde, x); }  | 
|             }  | 
|   | 
|             public class PositiveSet : Expr  | 
|             {  | 
|                 public PositiveSet(Op op, params Expr[] factors) : base(op, factors) { }  | 
|   | 
|                 public static PositiveSet operator +(PositiveSet x, PositiveSet y)  | 
|                 { return new PositiveSet(Op.Plus, x, y); }  | 
|   | 
|                 public static Expr operator -(PositiveSet x, PositiveSet y)  | 
|                 { return new Expr(Op.Minus, x, y); }  | 
|             }  | 
|   | 
|             public CharClassSet this[params Expr[] exprs]  | 
|             {  | 
|                 get  | 
|                 {  | 
|                     return this[new PositiveSet(Op.Plus, exprs)];  | 
|                 }  | 
|             }  | 
|   | 
|             public CharClassSet this[Expr expr]  | 
|             {  | 
|                 get  | 
|                 {  | 
|                     var stack = new Stack<StackFrame>();  | 
|                     stack.Push(expr);  | 
|                     CharClassSet classSet = null;  | 
|   | 
|                     while (stack.Any()) {  | 
|                         var context = stack.Pop();  | 
|                         expr = context.Expr;  | 
|                         if (context == null || expr == null) {  | 
|                             continue;  | 
|                         } else if (context.Children == null) {  | 
|                             context.Children = new Queue<Expr>();  | 
|                             if (expr.Factors != null && expr.Factors.Any())  | 
|                                 expr.Factors.ForEach(x => context.Children.Enqueue(x));  | 
|                             stack.Push(context);  | 
|                             continue;  | 
|                         } else if (context.Children.Any()) {  | 
|                             expr = context.Children.Dequeue();  | 
|                             stack.Push(context);  | 
|                             stack.Push(expr);  | 
|                             continue;  | 
|                         }  | 
|   | 
|                         classSet = null;  | 
|                         if (expr.Operator == Op.Term) {  | 
|                             if (expr.Term is CharClassSet)  | 
|                                 classSet = expr.Term as CharClassSet;  | 
|                             else  | 
|                                 classSet = new CharClassSet(expr.Term as Element);  | 
|                         } else if (context.SubSets != null && context.SubSets.Any()) {  | 
|                             switch (expr.Operator) {  | 
|                             case Op.Tilde:  | 
|                                 classSet = new CharClassSet  | 
|                                     {  | 
|                                         { context.SubSets.First(), Invert }  | 
|                                     };  | 
|                                 break;  | 
|                             case Op.Plus:  | 
|                                 classSet = new CharClassSet  | 
|                                     {  | 
|                                         { context.SubSets.First() },  | 
|                                         { context.SubSets.Last() }  | 
|                                     };  | 
|                                 break;  | 
|                             case Op.Minus:  | 
|                                 classSet = new CharClassSet  | 
|                                     {  | 
|                                         { context.SubSets.First() },  | 
|                                         { context.SubSets.Last(), Invert }  | 
|                                     };  | 
|                                 break;  | 
|                             }  | 
|                         }  | 
|   | 
|                         var parentContext = stack.Any() ? stack.Peek() : null;  | 
|                         if (classSet != null && parentContext != null)  | 
|                             parentContext.SubSets.Add(classSet);  | 
|                     }  | 
|   | 
|                     if (classSet == null)  | 
|                         throw new CharClassEvalException();  | 
|   | 
|                     return classSet;  | 
|                 }  | 
|             }  | 
|   | 
|             public CharClassSet this[IEnumerable<char> chars]  | 
|             {  | 
|                 get  | 
|                 {  | 
|                     return this[chars.Select(c => (Expr)c).ToArray()];  | 
|                 }  | 
|             }  | 
|   | 
|             class StackFrame  | 
|             {  | 
|                 public Expr Expr { get; set; }  | 
|                 public Queue<Expr> Children { get; set; }  | 
|                 public List<CharClassSet> SubSets { get; set; }  | 
|                 public StackFrame()  | 
|                 {  | 
|                     Expr = null;  | 
|                     Children = null;  | 
|                     SubSets = new List<CharClassSet>();  | 
|                 }  | 
|                 public static implicit operator StackFrame(Expr e)  | 
|                 {  | 
|                     return new StackFrame { Expr = e };  | 
|                 }  | 
|             }  | 
|         }  | 
|   | 
|         public partial class CharSetRawExprBuilder  | 
|         {  | 
|             public CharClassLiteral this[string s] { get { return CharRawLiteral(s); } }  | 
|         }  | 
|   | 
|         public class CharClassEvalException : RegExprException  | 
|         {  | 
|             public CharClassEvalException(string message = null) : base(message) { }  | 
|         }  | 
|     }  | 
| }  |