From e8a8bdde8579b20406bf3000eea06ffdd9348327 Mon Sep 17 00:00:00 2001 From: Valerie Date: Wed, 3 Apr 2024 13:46:23 -0400 Subject: [PATCH] graceful error handling and StringToken class implementation --- src/Error.cs | 8 +++++ src/Lex.cs | 30 +++++++++++++----- src/Object.cs | 2 ++ src/Parse.cs | 12 +++++--- src/Program.cs | 4 ++- src/Roll.cs | 84 +++----------------------------------------------- 6 files changed, 47 insertions(+), 93 deletions(-) diff --git a/src/Error.cs b/src/Error.cs index e681af1..efc5d10 100644 --- a/src/Error.cs +++ b/src/Error.cs @@ -9,6 +9,14 @@ namespace Dungeoneer.Error { } + public sealed class SyntaxException : Exception { + + public SyntaxException(string message) + : base(message) + { } + + } + } diff --git a/src/Lex.cs b/src/Lex.cs index a67181e..3e26b5b 100644 --- a/src/Lex.cs +++ b/src/Lex.cs @@ -96,18 +96,34 @@ namespace Dungeoneer.Interpreter { } - public abstract class MetadataToken : Token { + public abstract class DataToken : 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 abstract class MetadataToken : DataToken { + public T Value { get; protected set; } } - public class OperatorToken : Token { - public char Value; + public abstract class ValueToken : DataToken { + + public override string ToString() { return Value.ToString(); } + + } + + public abstract class StringToken : DataToken { + + private const string Style = "\x1b[92m"; + internal static readonly Regex Pattern = new Regex(@"^'(.+)'$"); + + public StringToken(Match match) { Value = 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 OperatorToken : DataToken { public OperatorToken(char op) { Value = op; } diff --git a/src/Object.cs b/src/Object.cs index 6db54e5..1b70358 100644 --- a/src/Object.cs +++ b/src/Object.cs @@ -2,6 +2,8 @@ using System.Dynamic; namespace Dungeoneer.Objects { + + public class Character { public string Name; diff --git a/src/Parse.cs b/src/Parse.cs index 1d8b7d4..e4e3141 100644 --- a/src/Parse.cs +++ b/src/Parse.cs @@ -1,5 +1,7 @@ using System; +using Dungeoneer.Error; + namespace Dungeoneer.Interpreter { public static class Parser { @@ -14,23 +16,23 @@ namespace Dungeoneer.Interpreter { switch(token) { case ValueToken value: if(wasValue) - throw new Exception("value -> value"); + throw new SyntaxException("Value followed by value"); result = Operate(result, value.Value, operation); wasValue = true; break; case OperatorToken op: if(!wasValue) - throw new Exception("operator -> operator"); + throw new SyntaxException("Operator followed by operator"); operation = op.Value; wasValue = false; break; case DcToken dc: if(rollDc.HasValue) - throw new Exception("two DC elements"); + throw new SyntaxException("Duplicate element: DC"); rollDc = dc.Value; break; default: - throw new Exception($"invalid token: {token.GetType()}"); + throw new SyntaxException($"invalid token: {token.GetType()}"); } } return result; @@ -44,7 +46,7 @@ namespace Dungeoneer.Interpreter { case '/': return (a / b); case '%': return (a % b); case '^': return (int)Math.Pow(a, b); - default: throw new Exception("unmatched operator"); + default: throw new SyntaxException("unmatched operator"); } } diff --git a/src/Program.cs b/src/Program.cs index 3b14430..214da8a 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -35,7 +35,9 @@ namespace Dungeoneer { tokens.RemoveAt(0); if(first is NameToken) { var command = (first as NameToken).Value; - ReplCommands[command](tokens); + if(ReplCommands.ContainsKey(command)) + try { ReplCommands[command](tokens); } + catch(Exception e) { Console.WriteLine($"error: {e.Message}"); } } else { Console.WriteLine($"no command '{raw}' found!"); } diff --git a/src/Roll.cs b/src/Roll.cs index 340204a..7477084 100644 --- a/src/Roll.cs +++ b/src/Roll.cs @@ -5,89 +5,13 @@ using Dungeoneer.Interpreter; namespace Dungeoneer { - public class RollResult { - public dynamic Value { get; private set; } - - private RollResult() { Value = null; } - public RollResult(string expression) { - Value = Scripting.Expr($"eval('{expression}')"); - } - - internal static class Style { - internal const string Default = "\x1b[1m"; - - internal const string BoolTrue = "\x1b[32;1m"; - internal const string BoolFalse = "\x1b[31;1m"; - } - - public override string ToString() { - string style; - switch(Value) { - case bool boolValue: - style = boolValue ? Style.BoolTrue : Style.BoolFalse; - break; - default: - style = Style.Default; - break; - } - - return $"{style}{Value}{Format.Reset}"; - } - - public static RollResult Wrap(dynamic value) { - var output = new RollResult(); - output.Value = value; - return output; - } - - } - - public class RollExpression { - private IList Parts; - public string Print { get; private set; } - public string Expression { get; private set; } - public RollResult Result { - get { - try { return new RollResult(Expression); } - catch { return null; } - } - } - - public RollExpression(IList parts) { - this.Parts = parts; - this.Print = ""; - this.Expression = ""; - - // build expression from string parts - foreach(string piece in Parts) { - // die expression substitution - var dieCheck = DiceToken.Match(piece); - if(dieCheck.Success) { - var token = new DiceToken(dieCheck); - - this.Print += $"{token} "; - this.Expression += $"{token.Value} "; - } else { - var part = $"{piece} "; - this.Expression += part; - this.Print += part; - } - } - } - - } - public static class RollMacro { public static void Pool(TokenSet input) { - /* - foreach(var roll in rolls) - if(roll > dc.Value) { - success = true; - break; - } - var result = RollResult.Wrap(success); - Console.WriteLine($"{dice}\n => {result}");*/ + if(input.Count != 2) + + foreach(var token in input) + ); } }