started implementing real lexing

This commit is contained in:
Valerie Wolfe 2024-04-02 21:05:08 -04:00
parent a0286194b2
commit ff05782056
4 changed files with 190 additions and 98 deletions

14
src/Error.cs Normal file
View 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
View 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); }
}
}

View file

@ -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 ""; }
}*/
}

View file

@ -65,8 +65,8 @@ namespace Dungeoneer {
if(dieCheck.Success) { if(dieCheck.Success) {
var token = new DiceToken(dieCheck); var token = new DiceToken(dieCheck);
this.Print += $"{token.Format()} "; this.Print += $"{token} ";
this.Expression += $"{token.Expression()} "; this.Expression += $"{token.Value} ";
} else { } else {
var part = $"{piece} "; var part = $"{piece} ";
this.Expression += part; this.Expression += part;
@ -100,7 +100,7 @@ namespace Dungeoneer {
break; break;
} }
var result = RollResult.Wrap(success); var result = RollResult.Wrap(success);
Console.WriteLine($"{dice.Format()}\n => {result}"); Console.WriteLine($"{dice}\n => {result}");
} }
} }