graceful error handling and StringToken class implementation
This commit is contained in:
parent
2349fb743f
commit
e8a8bdde85
6 changed files with 47 additions and 93 deletions
|
@ -9,6 +9,14 @@ namespace Dungeoneer.Error {
|
|||
|
||||
}
|
||||
|
||||
public sealed class SyntaxException : Exception {
|
||||
|
||||
public SyntaxException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
30
src/Lex.cs
30
src/Lex.cs
|
@ -96,18 +96,34 @@ namespace Dungeoneer.Interpreter {
|
|||
|
||||
}
|
||||
|
||||
public abstract class MetadataToken<T> : Token {
|
||||
public abstract class DataToken<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 abstract class MetadataToken<T> : DataToken<T> {
|
||||
public T Value { get; protected set; }
|
||||
}
|
||||
|
||||
public class OperatorToken : Token {
|
||||
public char Value;
|
||||
public abstract class ValueToken : DataToken<int> {
|
||||
|
||||
public override string ToString() { return Value.ToString(); }
|
||||
|
||||
}
|
||||
|
||||
public abstract class StringToken : DataToken<string> {
|
||||
|
||||
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<char> {
|
||||
|
||||
public OperatorToken(char op) { Value = op; }
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@ using System.Dynamic;
|
|||
|
||||
namespace Dungeoneer.Objects {
|
||||
|
||||
|
||||
|
||||
public class Character {
|
||||
public string Name;
|
||||
|
||||
|
|
12
src/Parse.cs
12
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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!");
|
||||
}
|
||||
|
|
84
src/Roll.cs
84
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<string> 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<string> 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)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Reference in a new issue