| /****************************************************************************  | 
| **  | 
| ** 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.IO;  | 
| using System.Linq;  | 
| using System.Text;  | 
|   | 
| namespace QtVsTools.SyntaxAnalysis  | 
| {  | 
|     public abstract partial class RegExpr  | 
|     {  | 
|         public enum SkipWhitespace { Disable, Enable }  | 
|   | 
|         ////////////////////////////////////////////////////////////////////////////////////////////  | 
|         ///  | 
|         /// RegExpr.Token  | 
|         ///  | 
|         ////////////////////////////////////////////////////////////////////////////////////////////  | 
|         /// <summary>  | 
|         /// A token of the syntax under analysis.  | 
|         /// </summary>  | 
|         /// <remarks>  | 
|         /// Token objects contain an encapsulated <see cref="RegExpr"/> that defines the pattern  | 
|         /// of the token's syntax, rendered as a named capture group. The name of the capture group  | 
|         /// corresponds to the identifier of the token. A Token may also include production rules  | 
|         /// defining the actions to take when content is matched by the associated capture group.  | 
|         /// </remarks>  | 
|         public partial class Token : RegExpr, IEnumerable<IProductionRule>  | 
|         {  | 
|             public string Id { get; set; }  | 
|   | 
|             public bool SkipLeadingWhitespace { get; set; }  | 
|             public RegExpr LeadingWhitespace { get; set; }  | 
|   | 
|             public RegExpr Expr { get; set; }  | 
|   | 
|             public HashSet<Token> Children { get; set; }  | 
|             public Dictionary<string, Token> Parents { get; set; }  | 
|             public IEnumerable<string> CaptureIds => Parents.Keys;  | 
|   | 
|             public Token(string id, RegExpr skipWs, RegExpr expr)  | 
|             {  | 
|                 Id = id;  | 
|                 SkipLeadingWhitespace = true;  | 
|                 LeadingWhitespace = skipWs;  | 
|                 Expr = expr;  | 
|                 Rules = new TokenRules();  | 
|                 Children = new HashSet<Token>();  | 
|                 Parents = new Dictionary<string, Token>();  | 
|             }  | 
|   | 
|             public Token(string id, SkipWhitespace skipWs, RegExpr expr)  | 
|             {  | 
|                 Id = id;  | 
|                 SkipLeadingWhitespace = (skipWs == SkipWhitespace.Enable);  | 
|                 Expr = expr;  | 
|                 Rules = new TokenRules();  | 
|                 Children = new HashSet<Token>();  | 
|                 Parents = new Dictionary<string, Token>();  | 
|             }  | 
|   | 
|             public Token(Enum id, RegExpr expr)  | 
|                 : this(id.ToString(), SkipWhitespace.Enable, expr)  | 
|             { }  | 
|   | 
|             public Token(string id, RegExpr expr)  | 
|                 : this(id, SkipWhitespace.Enable, expr)  | 
|             { }  | 
|   | 
|             public Token(Enum id, SkipWhitespace skipWs, RegExpr expr)  | 
|                 : this(id.ToString(), skipWs, expr)  | 
|             { }  | 
|   | 
|             public Token(Enum id, RegExpr skipWs, RegExpr expr)  | 
|                 : this(id.ToString(), skipWs, expr)  | 
|             { }  | 
|   | 
|             public Token(RegExpr skipWs, RegExpr expr)  | 
|                 : this(string.Empty, skipWs, expr)  | 
|             { }  | 
|   | 
|             public Token(RegExpr expr)  | 
|                 : this(string.Empty, SkipWhitespace.Enable, expr)  | 
|             { }  | 
|   | 
|             public Token()  | 
|                 : this(string.Empty, SkipWhitespace.Enable, null)  | 
|             { }  | 
|   | 
|             public static Token CreateRoot()  | 
|             {  | 
|                 var rootToken = new Token();  | 
|                 rootToken.Parents[ParseTree.KeyRoot] = rootToken;  | 
|                 return rootToken;  | 
|             }  | 
|   | 
|             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);  | 
|   | 
|                 var tokenWs = GetTokenWhitespace(defaultTokenWs);  | 
|                 if (tokenWs != null)  | 
|                     pattern.Append("(?:");  | 
|                 if (NeedsWhitespaceGroup(tokenWs, mode))  | 
|                     pattern.Append("(?:");  | 
|                 return Items(tokenWs, Expr);  | 
|             }  | 
|   | 
|             protected override void OnRenderNext(RegExpr defaultTokenWs, RegExpr parent,  | 
|                 StringBuilder pattern, ref RenderMode mode, Stack<Token> tokenStack)  | 
|             {  | 
|                 base.OnRenderNext(defaultTokenWs, parent, pattern, ref mode, tokenStack);  | 
|                 var tokenWs = GetTokenWhitespace(defaultTokenWs);  | 
|                 if (NeedsWhitespaceGroup(tokenWs, mode))  | 
|                     pattern.Append(")");  | 
|                 if (Expr != null) {  | 
|                     if (!mode.HasFlag(RenderMode.Assert) && !string.IsNullOrEmpty(Id)) {  | 
|                         string captureId = GenerateCaptureId(Id);  | 
|                         Parents.Add(captureId, tokenStack.Peek());  | 
|                         tokenStack.Peek().Children.Add(this);  | 
|                         pattern.AppendFormat("(?<{0}>", captureId);  | 
|                     } else {  | 
|                         pattern.Append("(?:");  | 
|                     }  | 
|                 }  | 
|                 tokenStack.Push(this);  | 
|             }  | 
|   | 
|             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 (Expr != null)  | 
|                     pattern.Append(")");  | 
|                 var tokenWs = GetTokenWhitespace(defaultTokenWs);  | 
|                 if (tokenWs != null)  | 
|                     pattern.Append(")");  | 
|                 tokenStack.Pop();  | 
|             }  | 
|   | 
|             /// <summary>  | 
|             /// Set of rules that can be applied to the token.  | 
|             /// </summary>  | 
|             TokenRules Rules { get; set; }  | 
|   | 
|             public void Add(IProductionRule rule)  | 
|             {  | 
|                 Rules.Add(rule);  | 
|                 rule.Token = this;  | 
|             }  | 
|   | 
|             public IProductionRule SelectRule(ITokenCapture tokenCapture)  | 
|             {  | 
|                 return Rules.Select(tokenCapture);  | 
|             }  | 
|   | 
|             const string TokenUniqueIdTemplate = "TOKEN_{0}_{1}";  | 
|   | 
|             protected static string GenerateCaptureId(string Id)  | 
|             {  | 
|                 return string.Concat(string.Format(TokenUniqueIdTemplate,  | 
|                     Path.GetRandomFileName().Replace(".", ""), Id)  | 
|                     .Take(32));  | 
|             }  | 
|   | 
|             RegExpr GetTokenWhitespace(RegExpr defaultTokenWs)  | 
|             {  | 
|                 if (!SkipLeadingWhitespace)  | 
|                     return null;  | 
|                 var tokenWs = LeadingWhitespace;  | 
|                 if (tokenWs == null)  | 
|                     tokenWs = defaultTokenWs;  | 
|                 return tokenWs;  | 
|             }  | 
|   | 
|             bool NeedsWhitespaceGroup(RegExpr tokenWs, RenderMode mode)  | 
|             {  | 
|                 return tokenWs != null && !mode.HasFlag(RenderMode.Assert)  | 
|                     && (tokenWs is RegExprLiteral || tokenWs is RegExprSequence);  | 
|             }  | 
|   | 
|             public IEnumerator<IProductionRule> GetEnumerator()  | 
|             {  | 
|                 return ((IEnumerable<IProductionRule>)Rules).GetEnumerator();  | 
|             }  | 
|   | 
|             IEnumerator IEnumerable.GetEnumerator()  | 
|             {  | 
|                 return ((IEnumerable<IProductionRule>)Rules).GetEnumerator();  | 
|             }  | 
|         }  | 
|   | 
|         public class TokenGroup : IEnumerable<string>  | 
|         {  | 
|             HashSet<string> TokenIds { get; set; }  | 
|   | 
|             public TokenGroup(params string[] tokenIds)  | 
|             {  | 
|                 TokenIds = new HashSet<string>(tokenIds);  | 
|             }  | 
|   | 
|             public void Add(string tokenId)  | 
|             {  | 
|                 TokenIds.Add(tokenId);  | 
|             }  | 
|   | 
|             public void Add(IEnumerable<string> tokenIds)  | 
|             {  | 
|                 TokenIds.UnionWith(tokenIds);  | 
|             }  | 
|   | 
|             public void Add(Token token)  | 
|             {  | 
|                 Add(token.Id);  | 
|             }  | 
|   | 
|             public static implicit operator TokenGroup(string tokenId)  | 
|             {  | 
|                 return new TokenGroup(tokenId);  | 
|             }  | 
|   | 
|             public IEnumerator<string> GetEnumerator()  | 
|             {  | 
|                 return TokenIds.GetEnumerator();  | 
|             }  | 
|   | 
|             IEnumerator IEnumerable.GetEnumerator()  | 
|             {  | 
|                 return TokenIds.GetEnumerator();  | 
|             }  | 
|         }  | 
|   | 
|         public class TokenRules : IEnumerable<IProductionRule>  | 
|         {  | 
|             Dictionary<RuleCallback.Selector, IProductionRule> Rules { get; set; }  | 
|             IProductionRule DefaultRule { get; set; }  | 
|   | 
|             public TokenRules()  | 
|             {  | 
|                 Rules = new Dictionary<RuleCallback.Selector, IProductionRule>();  | 
|             }  | 
|   | 
|             public void Add(IProductionRule item)  | 
|             {  | 
|                 if (item.Selector == Default)  | 
|                     DefaultRule = item;  | 
|                 else  | 
|                     Rules[item.Selector] = item;  | 
|             }  | 
|   | 
|             bool TestSelector(  | 
|                 KeyValuePair<RuleCallback.Selector, IProductionRule> pairSelectorRule,  | 
|                 ITokenCapture tokenCapture)  | 
|             {  | 
|                 var selector = pairSelectorRule.Key;  | 
|                 var rule = pairSelectorRule.Value;  | 
|                 if (rule == null)  | 
|                     return false;  | 
|                 if (selector != null && !selector(tokenCapture))  | 
|                     return false;  | 
|                 return true;  | 
|             }  | 
|   | 
|             public IProductionRule Select(ITokenCapture tokenCapture)  | 
|             {  | 
|                 var selectedRules = Rules  | 
|                     .Where(rule => TestSelector(rule, tokenCapture))  | 
|                     .Select(rule => rule.Value);  | 
|                 return selectedRules.Any() ? selectedRules.First() : DefaultRule;  | 
|             }  | 
|   | 
|             public IEnumerator<IProductionRule> GetEnumerator()  | 
|             {  | 
|                 return Rules.Values.GetEnumerator();  | 
|             }  | 
|   | 
|             IEnumerator IEnumerable.GetEnumerator()  | 
|             {  | 
|                 return Rules.Values.GetEnumerator();  | 
|             }  | 
|         }  | 
|   | 
|         public interface ITokenCapture  | 
|         {  | 
|             string TokenId { get; }  | 
|             string Value { get; }  | 
|             bool IsFirst { get; }  | 
|             bool IsLast { get; }  | 
|             IEnumerable<ITokenCapture> LookAhead(params TokenGroup[] tokenIds);  | 
|             IEnumerable<ITokenCapture> LookBehind(params TokenGroup[] tokenIds);  | 
|             bool Is(params TokenGroup[] tokenIds);  | 
|             bool IsNot(params TokenGroup[] tokenIds);  | 
|         }  | 
|   | 
|         public interface IOperatorCapture : ITokenCapture  | 
|         {  | 
|             IOperandCapture Operand { get; }  | 
|             IOperandCapture LeftOperand { get; }  | 
|             IOperandCapture RightOperand { get; }  | 
|             bool HasOperand { get; }  | 
|             bool HasLeftOperand { get; }  | 
|             bool HasRightOperand { get; }  | 
|         }  | 
|   | 
|         public interface IOperandCapture : ITokenCapture  | 
|         {  | 
|             object Production { get; }  | 
|         }  | 
|   | 
|         public class TokenEndOfList : IOperatorCapture, IOperandCapture  | 
|         {  | 
|             public string TokenId { get; }  | 
|             public string Value { get; }  | 
|             public bool IsFirst { get; }  | 
|             public bool IsLast { get; }  | 
|             public IEnumerable<ITokenCapture> LookAhead(params TokenGroup[] tokenIds)  | 
|             {  | 
|                 return Items(this);  | 
|             }  | 
|   | 
|             public IEnumerable<ITokenCapture> LookBehind(params TokenGroup[] tokenIds)  | 
|             {  | 
|                 return Items(this);  | 
|             }  | 
|   | 
|             public bool Is(params TokenGroup[] tokenIds)  | 
|             {  | 
|                 return false;  | 
|             }  | 
|   | 
|             public bool IsNot(params TokenGroup[] tokenIds)  | 
|             {  | 
|                 return true;  | 
|             }  | 
|   | 
|             public IOperandCapture Operand  | 
|             {  | 
|                 get { return this; }  | 
|             }  | 
|   | 
|             public IOperandCapture LeftOperand  | 
|             {  | 
|                 get { return this; }  | 
|             }  | 
|   | 
|             public IOperandCapture RightOperand  | 
|             {  | 
|                 get { return this; }  | 
|             }  | 
|   | 
|             public bool HasOperand { get; }  | 
|             public bool HasLeftOperand { get; }  | 
|             public bool HasRightOperand { get; }  | 
|             public object Production { get; }  | 
|         }  | 
|   | 
|         static TokenEndOfList EndOfList = new TokenEndOfList();  | 
|     }  | 
| }  |