started implementing real lexing
This commit is contained in:
parent
a0286194b2
commit
ff05782056
4 changed files with 190 additions and 98 deletions
14
src/Error.cs
Normal file
14
src/Error.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
namespace Dungeoneer.Error {
|
||||
|
||||
public sealed class UnmatchedTokenException : Exception {
|
||||
|
||||
public UnmatchedTokenException(string text)
|
||||
: base($"'{text}' is not a valid token!")
|
||||
{ }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
173
src/Lex.cs
Normal file
173
src/Lex.cs
Normal file
|
@ -0,0 +1,173 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
using Dungeoneer.Error;
|
||||
|
||||
namespace Dungeoneer.Lexing {
|
||||
|
||||
public static class Lexer {
|
||||
|
||||
public static TokenSet Tokenize(string text) {
|
||||
var output = new TokenSet();
|
||||
var parts = text.Trim().Split(" ", 0x11);
|
||||
foreach(string part in parts) {
|
||||
|
||||
var diceMatch = DiceToken.Match(part);
|
||||
if(diceMatch.Success) {
|
||||
output.Add(new DiceToken(diceMatch));
|
||||
continue;
|
||||
}
|
||||
|
||||
var numberMatch = NumberToken.Match(part);
|
||||
if(numberMatch.Success) {
|
||||
output.Add(new NumberToken(numberMatch));
|
||||
continue;
|
||||
}
|
||||
|
||||
var dcMatch = DcToken.Match(part);
|
||||
if(dcMatch.Success) {
|
||||
output.Add(new DcToken(dcMatch));
|
||||
continue;
|
||||
}
|
||||
|
||||
var operatorMatch = OperatorToken.Match(part);
|
||||
if(operatorMatch.Success) {
|
||||
output.Add(new OperatorToken(operatorMatch));
|
||||
continue;
|
||||
}
|
||||
|
||||
var varMatch = VarToken.Match(part);
|
||||
if(varMatch.Success) {
|
||||
output.Add(new VarToken(varMatch));
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new UnmatchedTokenException(part);
|
||||
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class TokenSet : List<Token> {
|
||||
|
||||
public TokenSet() : base() { }
|
||||
|
||||
public override string ToString() {
|
||||
var output = "";
|
||||
foreach(Token token in this)
|
||||
output += $"{token} ";
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract class Token {
|
||||
|
||||
public override string ToString() { return "<token>"; }
|
||||
|
||||
}
|
||||
|
||||
public abstract class MetadataToken<T> : Token {
|
||||
public T Value { get; protected set; }
|
||||
}
|
||||
|
||||
public abstract class ValueToken : Token {
|
||||
public int Value { get; protected set; }
|
||||
|
||||
public override string ToString() { return Value.ToString(); }
|
||||
}
|
||||
|
||||
public class OperatorToken : Token {
|
||||
public string dummy;
|
||||
|
||||
internal static readonly Regex Pattern = new Regex(@"([\+\-\*\/])");
|
||||
|
||||
public OperatorToken(Match match) {
|
||||
dummy = match.Groups[1].Value;
|
||||
}
|
||||
|
||||
public override string ToString() { return dummy; }
|
||||
|
||||
public static Match Match(string text) { return Pattern.Match(text); }
|
||||
|
||||
}
|
||||
|
||||
public class NumberToken : ValueToken {
|
||||
|
||||
internal static readonly Regex Pattern = new Regex(@"^(\d+)$");
|
||||
|
||||
public NumberToken(Match match) { Value = int.Parse(match.Groups[1].Value); }
|
||||
|
||||
public static Match Match(string text) { return Pattern.Match(text); }
|
||||
|
||||
}
|
||||
|
||||
public class VarToken : ValueToken {
|
||||
|
||||
private const string Style = "\x1b[33;1m";
|
||||
internal static readonly Regex Pattern = new Regex(@"^\$(.+)");
|
||||
|
||||
public VarToken(Match match) { Value = Scripting.Scope.GetVariable(match.Groups[1].Value); }
|
||||
|
||||
public override string ToString() { return $"{Style}{Value}{Format.Reset}"; }
|
||||
|
||||
public static Match Match(string text) { return Pattern.Match(text); }
|
||||
|
||||
}
|
||||
|
||||
public class DiceToken : ValueToken {
|
||||
public int Count { get; private set; }
|
||||
public int Sides { get; private set; }
|
||||
public List<int> Result { get; internal set; }
|
||||
|
||||
public DiceToken(Match match) {
|
||||
// parse captured values
|
||||
Count = int.Parse(match.Groups[1].Value);
|
||||
Sides = int.Parse(match.Groups[2].Value);
|
||||
|
||||
// get calculated fields
|
||||
Result = Roll();
|
||||
Value = Result.Sum();
|
||||
}
|
||||
|
||||
private const string Style = "\x1b[34;1m";
|
||||
internal static readonly Regex Pattern = new Regex(@"(\d+)d(\d+)");
|
||||
|
||||
public List<int> Roll() {
|
||||
var output = new List<int>();
|
||||
for(int i = 0; i < Count; i++)
|
||||
output.Add(Util.Roll(Sides));
|
||||
return output;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
var output = $"{Style}( ";
|
||||
var result = Result;
|
||||
for(int i = 0; i < Count; i++)
|
||||
if(i < Count - 1)
|
||||
output += $"{result[i]}, ";
|
||||
else
|
||||
output += $"{result[i]} ){Dungeoneer.Format.Reset}";
|
||||
return output;
|
||||
}
|
||||
|
||||
public static Match Match(string text) { return Pattern.Match(text); }
|
||||
|
||||
}
|
||||
|
||||
public class DcToken : MetadataToken<int> {
|
||||
|
||||
private const string Style = "\x1b[31m";
|
||||
internal static readonly Regex Pattern = new Regex(@"[Dd][Cc]\:(\d+)");
|
||||
|
||||
public DcToken(Match match) { Value = int.Parse(match.Groups[1].Value); }
|
||||
|
||||
public override string ToString() { return $"{Style}DC: {Value}{Format.Reset}"; }
|
||||
|
||||
public static Match Match(string text) { return Pattern.Match(text); }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
95
src/Lexer.cs
95
src/Lexer.cs
|
@ -1,95 +0,0 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Dungeoneer.Lexing {
|
||||
|
||||
public abstract class Token {
|
||||
|
||||
public virtual string Format() { return Expression(); }
|
||||
public abstract string Expression();
|
||||
|
||||
}
|
||||
|
||||
public class LiteralToken : Token {
|
||||
public string Content { get; private set; }
|
||||
|
||||
public LiteralToken(string text) { Content = text; }
|
||||
|
||||
public override string Expression() { return Content; }
|
||||
|
||||
}
|
||||
|
||||
public class DiceToken : Token {
|
||||
public int Count { get; private set; }
|
||||
public int Sides { get; private set; }
|
||||
private List<int> _result = null;
|
||||
public List<int> Result {
|
||||
get {
|
||||
if(_result == null) {
|
||||
_result = new List<int>();
|
||||
for(int i = 0; i < Count; i++)
|
||||
_result.Add(Util.Roll(Sides));
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
}
|
||||
public int? _sum = null;
|
||||
public int Sum {
|
||||
get {
|
||||
if(!_sum.HasValue) {
|
||||
_sum = 0;
|
||||
foreach(var roll in Result)
|
||||
_sum += roll;
|
||||
}
|
||||
return _sum.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public DiceToken(int count, int sides) {
|
||||
Count = count;
|
||||
Sides = sides;
|
||||
}
|
||||
public DiceToken(Match match) {
|
||||
Count = int.Parse(match.Groups[1].Value);
|
||||
Sides = int.Parse(match.Groups[2].Value);
|
||||
}
|
||||
public DiceToken(string text) {
|
||||
var match = Match(text);
|
||||
if(match.Success) {
|
||||
Count = int.Parse(match.Groups[1].Value);
|
||||
Sides = int.Parse(match.Groups[2].Value);
|
||||
} else
|
||||
throw new Exception("fuck you");
|
||||
}
|
||||
|
||||
private const string Style = "\x1b[34;1m";
|
||||
private static readonly Regex Pattern = new Regex(@"(\d+)d(\d+)");
|
||||
|
||||
public override string Format() {
|
||||
var output = $"{Style}( ";
|
||||
var result = Result;
|
||||
for(int i = 0; i < Count; i++)
|
||||
if(i < Count - 1)
|
||||
output += $"{result[i]}, ";
|
||||
else
|
||||
output += $"{result[i]} ){Dungeoneer.Format.Reset}";
|
||||
return output;
|
||||
}
|
||||
public override string Expression() { return Sum.ToString(); }
|
||||
|
||||
public static Match Match(string text) { return Pattern.Match(text); }
|
||||
|
||||
}
|
||||
|
||||
/*public class DcToken : Token {
|
||||
|
||||
private const string Style = "\x1b[31m";
|
||||
private static readonly Regex Pattern = new Regex(@"dc\:(\d+)");
|
||||
|
||||
public static Match Match(string text) { return Pattern.Match(text); }
|
||||
|
||||
public override string Expression() { return ""; }
|
||||
|
||||
}*/
|
||||
|
||||
}
|
||||
|
|
@ -65,8 +65,8 @@ namespace Dungeoneer {
|
|||
if(dieCheck.Success) {
|
||||
var token = new DiceToken(dieCheck);
|
||||
|
||||
this.Print += $"{token.Format()} ";
|
||||
this.Expression += $"{token.Expression()} ";
|
||||
this.Print += $"{token} ";
|
||||
this.Expression += $"{token.Value} ";
|
||||
} else {
|
||||
var part = $"{piece} ";
|
||||
this.Expression += part;
|
||||
|
@ -100,7 +100,7 @@ namespace Dungeoneer {
|
|||
break;
|
||||
}
|
||||
var result = RollResult.Wrap(success);
|
||||
Console.WriteLine($"{dice.Format()}\n => {result}");
|
||||
Console.WriteLine($"{dice}\n => {result}");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Reference in a new issue