You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public ParseException(string message, string @string, int position, Pattern pattern)
: base(message)
{
Pattern = pattern;
String = @string;
Position = position;
}
public Pattern Pattern { get; }
public int Position { get; }
public string String { get; }
}
public class Symbol : IEnumerable<Symbol>
{
public static readonly Symbol[] EmptySymbols = new Symbol[0];
public Symbol(Pattern pattern)
{
Pattern = pattern;
}
public Pattern Pattern { get; }
public virtual IEnumerator<Symbol> GetEnumerator()
{
yield return this;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public class TerminalSymbol : Symbol
{
public TerminalSymbol(Pattern pattern, string value)
: base(pattern)
{
Value = value;
}
public string Value { get; }
public override string ToString()
{
return Value;
}
}
public class CompositeSymbol : Symbol
{
public CompositeSymbol(Pattern pattern, IEnumerable<Symbol> symbols)
: base(pattern)
{
Symbols = symbols;
}
private IEnumerable<Symbol> Symbols { get; }
public override string ToString()
{
var builder = new StringBuilder();
foreach (var symbol in Symbols)
{
builder.Append(symbol);
}
return builder.ToString();
}
public override IEnumerator<Symbol> GetEnumerator()
{
return GraphHelper.ExploreBreadthFirstGraph(this, symbol => symbol is CompositeSymbol compositeSymbol ? compositeSymbol.Symbols : EmptySymbols, EqualityComparer<Symbol>.Default).GetEnumerator();
}
}
public sealed class Pattern
{
private Func<StringProcessor, Symbol> _parse;
private Pattern(string name)
{
Name = name;
_parse = _ => new CompositeSymbol(this, Symbol.EmptySymbols);
}
public string Name { get; }
public static Pattern Conjunction(params Pattern[] patterns)
{
return Conjunction("(" + string.Join(" + ", from subPattern in patterns select subPattern.Name) + ")", patterns);
}
public static Pattern Conjunction(string name, params Pattern[] patterns)
{
var pattern = new Pattern(name);
pattern._parse = processor => new CompositeSymbol(pattern, (from subPattern in patterns select subPattern.Parse(processor)).ToArray());
return pattern;
}
public static Pattern Custom(string name, Func<StringProcessor, string> callback)
{
if (callback == null)
{
throw new ArgumentNullException(nameof(callback));
}
var pattern = new Pattern(name);
pattern._parse = processor =>
{
var position = processor.Position;
var greedy = processor.Greedy;
string? result = null;
try
{
result = callback(processor);
}
finally
{
if (result == null)
{
processor.Position = position;
processor.Greedy = greedy;
throw new ParseException($"Expected {name}", processor.String, processor.Position, pattern);
}
}
return new TerminalSymbol(pattern, result);
};
return pattern;
}
public static Pattern Disjunction(params Pattern[] patterns)
{
return Disjunction("(" + string.Join(" | ", from subPattern in patterns select subPattern.Name) + ")", patterns);
}
public static Pattern Disjunction(string name, params Pattern[] patterns)
{
var pattern = new Pattern(name);
pattern._parse = processor =>
{
var position = processor.Position;
var greedy = processor.Greedy;
foreach (var subPattern in patterns)
{
Symbol? result = null;
try
{
result = subPattern.Parse(processor);
}
catch (ParseException exception)
{
// swallow
Theraot.No.Op(exception);
}
finally
{
if (result == null)
{
processor.Position = position;
processor.Greedy = greedy;
}
}
if (result != null)
{
return new CompositeSymbol(pattern, new[] { result });
}
}
throw new ParseException($"Expected {name}", processor.String, processor.Position, pattern);