Skip to content

Commit

Permalink
Improved parser implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
kekyo committed Sep 15, 2024
1 parent b423e2e commit 099a7d9
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 44 deletions.
110 changes: 66 additions & 44 deletions NamingFormatter/Internal/Formatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ internal static class Formatter
private enum States
{
Normal,
EnterKey
EnterKey,
Closing,
}

private static bool TryGetPropertyValue(this Type type, object instance, string name, out object? value)
Expand Down Expand Up @@ -149,53 +150,74 @@ public static (string format, object?[] args) PreFormat(
var currentIndex = 0;
while (currentIndex < format.Length)
{
if (state == States.Normal)
switch (state)
{
var bracketIndex = format.IndexOf('{', currentIndex);
if (bracketIndex == -1)
{
cooked.Append(format.Substring(currentIndex));
case States.Normal:
var bracketIndex = format.IndexOf('{', currentIndex);
if (bracketIndex == -1)
{
cooked.Append(format.Substring(currentIndex));
currentIndex = format.Length;
}
else
{
var nextIndex = bracketIndex + 1;
cooked.Append(format.Substring(currentIndex, nextIndex - currentIndex));
currentIndex = nextIndex;
state = States.EnterKey;
}
break;
}

var nextIndex = bracketIndex + 1;
cooked.Append(format.Substring(currentIndex, nextIndex - currentIndex));
currentIndex = nextIndex;

state = States.EnterKey;
continue;
}

if (format[currentIndex] == '{')
{
cooked.Append('{');
currentIndex++;

state = States.Normal;
continue;
}

var finishIndex = format.IndexOfAny(finishFormatChars_, currentIndex);
if (finishIndex == -1)
{
throw new FormatException("Couldn't find close bracket.");
}

var key = format.Substring(currentIndex, finishIndex - currentIndex);
switch (TryGetValueBySelector(selector, key, out var value))
{
case Results.InvalidPropertyPath when
(options & PreFormatOptions.IgnoreInvalidPropertyPath) != PreFormatOptions.IgnoreInvalidPropertyPath:
case Results.Terminated when
(options & PreFormatOptions.IgnoreIfTerminated) != PreFormatOptions.IgnoreIfTerminated:
throw new ArgumentException($"Couldn't find a key: {key}");
case States.EnterKey:
// '{{'
if (format[currentIndex] == '{')
{
cooked.Append('{');
currentIndex++;

state = States.Normal;
continue;
}

var finishIndex = format.IndexOfAny(finishFormatChars_, currentIndex);
if (finishIndex == -1)
{
throw new FormatException("Couldn't find close bracket.");
}

var key = format.Substring(currentIndex, finishIndex - currentIndex);
switch (TryGetValueBySelector(selector, key, out var value))
{
case Results.InvalidPropertyPath when
(options & PreFormatOptions.IgnoreInvalidPropertyPath) != PreFormatOptions.IgnoreInvalidPropertyPath:
case Results.Terminated when
(options & PreFormatOptions.IgnoreIfTerminated) != PreFormatOptions.IgnoreIfTerminated:
throw new ArgumentException($"Couldn't find a key: {key}");
}

cooked.Append(args.Count);
args.Add(value);
currentIndex = finishIndex;

state = States.Closing;
break;

case States.Closing:
var bracketIndex2 = format.IndexOf('}', currentIndex);
if (bracketIndex2 == -1)
{
cooked.Append(format.Substring(currentIndex));
currentIndex = format.Length;
}
else
{
var nextIndex = bracketIndex2 + 1;
cooked.Append(format.Substring(currentIndex, nextIndex - currentIndex));
currentIndex = nextIndex;
}
state = States.Normal;
break;
}

cooked.Append(args.Count);
args.Add(value);
currentIndex = finishIndex;

state = States.Normal;
}

return (cooked.ToString(), args.ToArray());
Expand Down
19 changes: 19 additions & 0 deletions NamingFormatterTests/WriteFormatTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ namespace NamingFormatter.Tests
[TestFixture]
public class WriteFormatTests
{
[Test]
public void ParameterTest()
{
var now = DateTime.Now;
IDictionary<string, object?> keyValues = new Dictionary<string, object?>()
{
{ "abc", 123 },
{ "defgh", now },
{ "ijkl", "XYZ" }
};

var tw = new StringWriter();
tw.WriteFormat(
"AAA{defgh:yyyMMdd}BBB{abc:X}CCC{ijkl}DDD",
keyValues);

Assert.AreEqual("AAA" + now.ToString("yyyyMMdd") + "BBB" + 123.ToString("X") + "CCCXYZDDD", tw.ToString());
}

[Test]
public void DictionaryOverloadTest()
{
Expand Down

0 comments on commit 099a7d9

Please sign in to comment.