/****************************************************************************
|
**
|
** 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) { }
|
}
|
}
|
}
|