| /****************************************************************************  | 
| **  | 
| ** 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.Linq.Expressions;  | 
| using System.Reflection;  | 
| using System.Text;  | 
|   | 
| namespace QtVsTools.SyntaxAnalysis  | 
| {  | 
|     public abstract partial class RegExpr  | 
|     {  | 
|         [Flags]  | 
|         public enum Delimiter { None, Left, Right }  | 
|   | 
|         [Flags]  | 
|         public enum Operand { None, Left, Right }  | 
|   | 
|         public interface IProductionRule  | 
|         {  | 
|             int Priority { get; }  | 
|             RuleCallback.Selector Selector { get; }  | 
|             RuleCallback.PreCondition PreCondition { get; }  | 
|             Token Token { get; set; }  | 
|             Delimiter Delimiters { get; }  | 
|             Operand Operands { get; }  | 
|             object Execute(ParseTree.Node node);  | 
|         }  | 
|   | 
|         public abstract class ProductionRule<T> : IProductionRule, IEnumerable  | 
|         {  | 
|             public int Priority { get; protected set; }  | 
|             public RuleCallback.Selector Selector { get; set; }  | 
|             public RuleCallback.PreCondition PreCondition { get; set; }  | 
|   | 
|             public Token Token { get; set; }  | 
|             public virtual Delimiter Delimiters { get { return Delimiter.None; } }  | 
|             public virtual Operand Operands { get { return Operand.None; } }  | 
|   | 
|             protected List<IRuleAction<T>> Actions = new List<IRuleAction<T>>();  | 
|   | 
|             protected void Init(  | 
|                 int priority, RuleCallback.Selector select, RuleCallback.PreCondition pre)  | 
|             {  | 
|                 Priority = priority;  | 
|                 Selector = select;  | 
|                 PreCondition = pre;  | 
|             }  | 
|   | 
|             public void Add(IRuleAction<T> action)  | 
|             {  | 
|                 Actions.Add(action);  | 
|             }  | 
|   | 
|             protected abstract object[] FetchOperands(Stack<ParseTree.Node> operandStack);  | 
|   | 
|             protected virtual T DefaultProduction(  | 
|                 string capturedValue,  | 
|                 Stack<ParseTree.Node> operandStack,  | 
|                 ProductionObjects productions)  | 
|             {  | 
|                 return CreateInstance();  | 
|             }  | 
|   | 
|             protected virtual bool TestPreCondition(  | 
|                 ParseTree.Node node,  | 
|                 string capturedValue,  | 
|                 Stack<ParseTree.Node> operandStack,  | 
|                 ProductionObjects productions)  | 
|             {  | 
|                 if (PreCondition == null)  | 
|                     return true;  | 
|                 return PreCondition(node);  | 
|             }  | 
|   | 
|             public object Execute(ParseTree.Node node)  | 
|             {  | 
|                 if (PreCondition != null && !PreCondition(node))  | 
|                     throw new ParseErrorException();  | 
|   | 
|                 if (node.Parent == null)  | 
|                     return null;  | 
|   | 
|                 var operandStack = node.Parent.OperandStack;  | 
|                 var capturedValue = node.Value;  | 
|                 var productions = node.ChildProductions;  | 
|   | 
|                 // pop-out rule operands from operand stack  | 
|                 object[] ruleOperands = FetchOperands(operandStack);  | 
|   | 
|                 // calculate order of actions taking child productions into account  | 
|                 var actionScheduling = ScheduleActions(productions);  | 
|   | 
|                 // run actions in the calculated order  | 
|                 T production = default(T);  | 
|                 foreach (var actionSchedule in actionScheduling) {  | 
|                     var a = actionSchedule.Action;  | 
|                     var childProduction = actionSchedule.Production;  | 
|   | 
|                     // if production is null and action is update, init with default production  | 
|                     if (production == null && a.ActionInfo.ReturnType == typeof(void))  | 
|                         production = DefaultProduction(capturedValue, operandStack, productions);  | 
|   | 
|                     // if action uses child production, use it as input instead of the rule operands  | 
|                     if (childProduction != null)  | 
|                         a.Execute(ref production, capturedValue, childProduction);  | 
|                     else  | 
|                         a.Execute(ref production, capturedValue, ruleOperands);  | 
|                 }  | 
|   | 
|                 // if no production was created by rule actions, create default production  | 
|                 if (production == null)  | 
|                     production = DefaultProduction(capturedValue, operandStack, productions);  | 
|   | 
|                 return production;  | 
|             }  | 
|   | 
|             class ActionSchedule  | 
|             {  | 
|                 public IRuleAction<T> Action { get; set; }  | 
|                 public int ActionIndex { get; set; }  | 
|                 public object Production { get; set; }  | 
|                 public int ProductionIndex { get; set; }  | 
|             }  | 
|   | 
|             IEnumerable<ActionSchedule> ScheduleActions(ProductionObjects childProductions)  | 
|             {  | 
|                 // actions with order of definition  | 
|                 var actionsOrder = Actions  | 
|                     .Select((a, aIdx) => new  | 
|                     {  | 
|                         Self = a,  | 
|                         Index = aIdx,  | 
|                         a.SourceTokenId  | 
|                     });  | 
|                 var dependentActions = actionsOrder  | 
|                     .Where(a => !string.IsNullOrEmpty(a.SourceTokenId));  | 
|                 var independentActions = actionsOrder  | 
|                     .Where(a => string.IsNullOrEmpty(a.SourceTokenId));  | 
|   | 
|                 // child productions with order of creation  | 
|                 var productionsOrder = childProductions  | 
|                     .Select((p, pIdx) => new  | 
|                     {  | 
|                         Self = p.Value,  | 
|                         Index = pIdx,  | 
|                         TokenId = p.Key  | 
|                     });  | 
|   | 
|                 // schedule actions that depend on child production:  | 
|                 //  * actions x productions  | 
|                 //  * sorted by production creation order (inverted)  | 
|                 //  * and then by action definition order (inverted)  | 
|                 var dependentActionSchedules = dependentActions  | 
|                     .Join(productionsOrder,  | 
|                     a => a.SourceTokenId, p => p.TokenId,  | 
|                     (a, p) => new ActionSchedule  | 
|                     {  | 
|                         Action = a.Self,  | 
|                         ActionIndex = a.Index,  | 
|                         Production = p.Self,  | 
|                         ProductionIndex = p.Index,  | 
|                     })  | 
|                     .OrderByDescending(ap => ap.ProductionIndex)  | 
|                     .ThenByDescending(ap => ap.ActionIndex);  | 
|   | 
|                 // insert independent actions in the right order  | 
|                 var scheduled = new Stack<ActionSchedule>();  | 
|                 IEnumerable<ActionSchedule> toSchedule = dependentActionSchedules;  | 
|                 foreach (var a in independentActions.OrderByDescending(a => a.Index)) {  | 
|                     var scheduleAfter = toSchedule  | 
|                         .TakeWhile(ap => ap.ActionIndex > a.Index);  | 
|                     foreach (var ap in scheduleAfter)  | 
|                         scheduled.Push(ap);  | 
|                     scheduled.Push(new ActionSchedule { Action = a.Self });  | 
|   | 
|                     toSchedule = toSchedule.Skip(scheduleAfter.Count());  | 
|                 }  | 
|                 if (toSchedule.Any()) {  | 
|                     foreach (var ap in toSchedule)  | 
|                         scheduled.Push(ap);  | 
|                 }  | 
|   | 
|                 return scheduled;  | 
|             }  | 
|   | 
|             public IEnumerator GetEnumerator()  | 
|             {  | 
|                 return Actions.GetEnumerator();  | 
|             }  | 
|   | 
|             protected T CreateInstance()  | 
|             {  | 
|                 var type = typeof(T);  | 
|   | 
|                 if (type.IsValueType)  | 
|                     return default(T);  | 
|   | 
|                 if (type == typeof(string))  | 
|                     return (T)(object)string.Empty;  | 
|   | 
|                 if (!type.IsClass)  | 
|                     throw new InvalidOperationException("Not a class: " + type.Name);  | 
|   | 
|                 if (type.IsAbstract)  | 
|                     throw new InvalidOperationException("Abstract class: " + type.Name);  | 
|   | 
|                 if (type.ContainsGenericParameters)  | 
|                     throw new InvalidOperationException("Generic class: " + type.Name);  | 
|   | 
|                 var ctorInfo = ((TypeInfo)type).DeclaredConstructors  | 
|                     .Where(x => x.GetParameters().Length == 0)  | 
|                     .FirstOrDefault();  | 
|   | 
|                 if (ctorInfo == null)  | 
|                     throw new InvalidOperationException("No default constructor: " + type.Name);  | 
|   | 
|                 return (T)ctorInfo.Invoke(new object[0]);  | 
|             }  | 
|         }  | 
|   | 
|         public class Rule<T> : ProductionRule<T>  | 
|         {  | 
|             public Rule(  | 
|                 int priority = int.MaxValue,  | 
|                 RuleCallback.Selector select = null,  | 
|                 RuleCallback.PreCondition pre = null)  | 
|             {  | 
|                 Init(priority, select, pre);  | 
|             }  | 
|   | 
|             protected override object[] FetchOperands(Stack<ParseTree.Node> operandStack)  | 
|             {  | 
|                 return new object[] { };  | 
|             }  | 
|         }  | 
|   | 
|         public class PrefixRule<TOperand, T> : ProductionRule<T>  | 
|         {  | 
|             public override Operand Operands { get { return Operand.Right; } }  | 
|   | 
|             public PrefixRule(  | 
|                 int priority = 0,  | 
|                 RuleCallback.Selector select = null,  | 
|                 RuleCallback.PreCondition pre = null)  | 
|             {  | 
|                 Init(priority, select, pre);  | 
|             }  | 
|   | 
|             protected override object[] FetchOperands(Stack<ParseTree.Node> operandStack)  | 
|             {  | 
|                 if (operandStack.Count < 1)  | 
|                     throw new ParseErrorException();  | 
|   | 
|                 var operand = operandStack.Pop();  | 
|                 if (!(operand.Production is TOperand))  | 
|                     throw new ParseErrorException();  | 
|   | 
|                 return new object[] { operand.Production };  | 
|             }  | 
|         }  | 
|   | 
|         public class PostfixRule<TOperand, T> : ProductionRule<T>  | 
|         {  | 
|             public override Operand Operands { get { return Operand.Left; } }  | 
|   | 
|             public PostfixRule(  | 
|                 int priority = 0,  | 
|                 RuleCallback.Selector select = null,  | 
|                 RuleCallback.PreCondition pre = null)  | 
|             {  | 
|                 Init(priority, select, pre);  | 
|             }  | 
|   | 
|             protected override object[] FetchOperands(Stack<ParseTree.Node> operandStack)  | 
|             {  | 
|                 if (operandStack.Count < 1)  | 
|                     throw new ParseErrorException();  | 
|   | 
|                 var operand = operandStack.Pop();  | 
|                 if (!(operand.Production is TOperand))  | 
|                     throw new ParseErrorException();  | 
|   | 
|                 return new object[] { operand.Production };  | 
|             }  | 
|         }  | 
|   | 
|         public class InfixRule<TLeftOperand, TRightOperand, T> : ProductionRule<T>  | 
|         {  | 
|             public override Operand Operands { get { return Operand.Left | Operand.Right; } }  | 
|   | 
|             public InfixRule(  | 
|                 int priority = 0,  | 
|                 RuleCallback.Selector select = null,  | 
|                 RuleCallback.PreCondition pre = null)  | 
|             {  | 
|                 Init(priority, select, pre);  | 
|             }  | 
|   | 
|             protected override object[] FetchOperands(Stack<ParseTree.Node> operandStack)  | 
|             {  | 
|                 if (operandStack.Count < 2)  | 
|                     throw new ParseErrorException();  | 
|   | 
|                 var rightOperand = operandStack.Pop();  | 
|                 if (!(rightOperand.Production is TRightOperand))  | 
|                     throw new ParseErrorException();  | 
|   | 
|                 var leftOperand = operandStack.Pop();  | 
|                 if (!(leftOperand.Production is TLeftOperand))  | 
|                     throw new ParseErrorException();  | 
|   | 
|                 return new object[] { leftOperand.Production, rightOperand.Production };  | 
|             }  | 
|         }  | 
|   | 
|         public class LeftDelimiterRule<T> : ProductionRule<T>  | 
|         {  | 
|             public override Delimiter Delimiters { get { return Delimiter.Left; } }  | 
|   | 
|             public LeftDelimiterRule(  | 
|                 int priority = int.MinValue,  | 
|                 RuleCallback.Selector select = null,  | 
|                 RuleCallback.PreCondition pre = null)  | 
|             {  | 
|                 Init(priority, select, pre);  | 
|             }  | 
|   | 
|             protected override object[] FetchOperands(Stack<ParseTree.Node> operandStack)  | 
|             {  | 
|                 return new object[] { };  | 
|             }  | 
|         }  | 
|   | 
|         public class RightDelimiterRule<TLeftDelim, TExpr, T> : ProductionRule<T>  | 
|         {  | 
|             public override Delimiter Delimiters { get { return Delimiter.Right; } }  | 
|   | 
|             public RightDelimiterRule(  | 
|                 int priority = int.MaxValue,  | 
|                 RuleCallback.Selector select = null,  | 
|                 RuleCallback.PreCondition pre = null)  | 
|             {  | 
|                 Init(priority, select, pre);  | 
|             }  | 
|   | 
|             protected override T DefaultProduction(  | 
|                 string capturedValue,  | 
|                 Stack<ParseTree.Node> operandStack,  | 
|                 ProductionObjects productions)  | 
|             {  | 
|                 throw new ParseErrorException();  | 
|             }  | 
|   | 
|             protected override object[] FetchOperands(Stack<ParseTree.Node> operandStack)  | 
|             {  | 
|                 if (operandStack.Count < 2)  | 
|                     throw new ParseErrorException();  | 
|   | 
|                 var delimitedExpr = operandStack.Pop();  | 
|                 if (!(delimitedExpr.Production is TExpr))  | 
|                     throw new ParseErrorException();  | 
|   | 
|                 var leftDelimiter = operandStack.Pop();  | 
|                 if (!(leftDelimiter.Production is TLeftDelim))  | 
|                     throw new ParseErrorException();  | 
|   | 
|                 return new object[] { leftDelimiter.Production, delimitedExpr.Production };  | 
|             }  | 
|         }  | 
|   | 
|         public static class RuleCallback  | 
|         {  | 
|             public delegate bool Selector(ITokenCapture token);  | 
|             public delegate bool PreCondition(IOperatorCapture capture);  | 
|         }  | 
|   | 
|         public const RuleCallback.Selector Default = null;  | 
|     }  | 
| }  |