Fixed formatting with ByteArray and LongArray

This commit is contained in:
ForeverZer0 2021-08-31 19:33:57 -04:00
parent 16369b68e3
commit 31aac628b6
5 changed files with 161 additions and 37 deletions

View File

@ -1,3 +1,6 @@
using System.IO;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using SharpNBT.SNBT;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
@ -26,5 +29,27 @@ namespace SharpNBT.Tests
var tag = TestHelper.GetTag("hello_world.nbt", CompressionType.None); var tag = TestHelper.GetTag("hello_world.nbt", CompressionType.None);
output.WriteLine(tag.Stringify(true)); output.WriteLine(tag.Stringify(true));
} }
[Fact]
public void ParseSmall()
{
const string testString = "{name1:123,name2:\"sometext1\",name3:{subname1:456,subname2:\"sometext2\"}}";
var lexer = new Lexer();
foreach (var token in lexer.Tokenize(testString))
{
output.WriteLine($"{token.Type}: \"{token.Match.Trim()}\"");
}
}
[Fact]
public void ParseBig()
{
var testString = File.ReadAllText("/code/ruby/craftbook-nbt/test/bigtest.snbt");
var lexer = new Lexer();
foreach (var token in lexer.Tokenize(testString))
{
output.WriteLine($"{token.Type}: \"{token.Match.Trim()}\"");
}
}
} }
} }

View File

@ -1,7 +1,10 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection.Emit;
using System.Security;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using JetBrains.Annotations;
namespace SharpNBT.SNBT namespace SharpNBT.SNBT
{ {
@ -26,70 +29,152 @@ namespace SharpNBT.SNBT
Long, Long,
Int, Int,
WhiteSpace, WhiteSpace,
Char Char,
EscapedChar
} }
internal sealed class LexerRule internal sealed class LexerRule
{ {
internal delegate string PostProcessHandler(string input);
private readonly Regex regex; internal delegate string PostProcessHandler(Match match);
public Regex Matcher { get; }
public TokenType Type { get; } public TokenType Type { get; }
public LexerRule(TokenType type, string pattern) : this(type, new Regex(pattern, RegexOptions.Multiline | RegexOptions.CultureInvariant)) public string Description { get; }
{
}
public LexerRule(TokenType type, Regex regex) public string PostProcess(Match match) => handler?.Invoke(match) ?? match.Value;
private readonly PostProcessHandler handler;
public LexerRule(TokenType type, string description, string pattern, [CanBeNull] PostProcessHandler process)
{ {
Type = type; Type = type;
this.regex = regex ?? throw new ArgumentNullException(nameof(regex)); Description = description;
Matcher = new Regex(pattern, RegexOptions.Multiline | RegexOptions.CultureInvariant);
handler = process;
} }
public LexerRule(TokenType type, Regex regex, PostProcessHandler handler) // public LexerRule(TokenType type, string description, Regex regex)
{ // {
// Description = description;
// Type = type;
//
// }
}
internal sealed class Token
{
public TokenType Type { get; }
public string Match { get; }
public Token(TokenType type, string match)
{
Type = type;
Type = type;
Match = match;
} }
} }
internal class Lexer internal class Lexer
{ {
private static readonly string DoubleQuoteIdentifier = "\"(.*?)\"\\s*(?=:)";
private static readonly List<LexerRule> rules; private static readonly List<LexerRule> rules;
private const string IDENTIFIER_DOUBLE_QUOTES = "\".*?\"\\s*(?>:)";
private const string IDENTIFIER_SINGLE_QUOTES = "'.*?'\\s*(?>:)";
private const string IDENTIFIER_NO_QUOTES = @"[A-Za-z0-9_-]+\s*(?=:)";
private const string STRING_DOUBLE_QUOTED = "^\\s*\".*?\"";
private const string STRING_SINGLE_QUOTED = "^\\s*'.*?'";
private const string COMPOUND_START = "\\s*{\\s*";
private const string COMPOUND_END = @"\}";
private const string SEPARATOR = "^\\s*:\\s*";
private const string COMMA = "^\\s*,\\s*";
static Lexer() static Lexer()
{ {
rules = new List<LexerRule> rules = new List<LexerRule>
{ {
new LexerRule(TokenType.CompoundBegin, @"\{[\s]*"), new LexerRule(TokenType.CompoundBegin, "Opening Compound brace", "^{", null),
new LexerRule(TokenType.CompoundEnd, @"[\s]*\}"), new LexerRule(TokenType.WhiteSpace, "Useless whitespace", @"^[\s]+", null),
new LexerRule(TokenType.Identifier, "\".+?\"(?=:)"),
new LexerRule(TokenType.Identifier, "'.+?'(?=:) "), new LexerRule(TokenType.Identifier, "Single-quoted name", "^\\s*'(.*?)'\\s*(?=:)", m => m.Groups[1].Value),
new LexerRule(TokenType.Identifier, "A-Za-z0-9_-]+?(?=:) "), new LexerRule(TokenType.Identifier, "Double-quoted name", "^\\s*\"(.*?)\"\\s*(?=:)", m => m.Groups[1].Value),
new LexerRule(TokenType.String, "\".*?\""), new LexerRule(TokenType.Identifier, "Unquoted name", "^\\s*([A-Za-z0-9_-]+)\\s*(?=:)", m => m.Groups[1].Value),
new LexerRule(TokenType.String, "'.*?'"),
new LexerRule(TokenType.Separator, @"[\s]*:[\s]*"),
new LexerRule(TokenType.Comma, @"[\s]*,[\s]*"), new LexerRule(TokenType.String, "Double-quoted string value", "^\"(.*?)\"", null),
new LexerRule(TokenType.ByteArray, @"\[B;[\s]*?"), new LexerRule(TokenType.String, "Single-quoted string value", "^'(.*?)'", null)
new LexerRule(TokenType.IntArray, @"\[I;[\s]*?"),
new LexerRule(TokenType.LongArray, @"\[L;[\s]*?"), // new LexerRule(TokenType.CompoundBegin, COMPOUND_START),
new LexerRule(TokenType.ListArray, @"\[[\s]*?"), // new LexerRule(TokenType.CompoundEnd, COMPOUND_END),
new LexerRule(TokenType.EndArray, @"[\s]*\]"), // new LexerRule(TokenType.Identifier, IDENTIFIER_DOUBLE_QUOTES),
new LexerRule(TokenType.Float, @"-?[0-9]*\.[0-9]+[Ff]"), // new LexerRule(TokenType.Identifier, IDENTIFIER_SINGLE_QUOTES),
new LexerRule(TokenType.Double, @"-?[0-9]*\.[0-9]+[Dd]?"), // new LexerRule(TokenType.Identifier, IDENTIFIER_NO_QUOTES),
new LexerRule(TokenType.Byte, "-?([0-9]+)[Bb]"), // new LexerRule(TokenType.String, STRING_DOUBLE_QUOTED),
new LexerRule(TokenType.Short, "-?([0-9]+)[Ss]"), // new LexerRule(TokenType.String, STRING_SINGLE_QUOTED),
new LexerRule(TokenType.Long, "-?([0-9]+)[Ll]"), // new LexerRule(TokenType.Separator, SEPARATOR),
new LexerRule(TokenType.Int, "-?([0-9]+)"), // new LexerRule(TokenType.Comma, COMMA),
new LexerRule(TokenType.WhiteSpace, @"[\s]+"), // new LexerRule(TokenType.ByteArray, @"\[B;[\s]*?"),
new LexerRule(TokenType.String, @"[\S]+"), // new LexerRule(TokenType.IntArray, @"\[I;[\s]*?"),
new LexerRule(TokenType.Char, ".") // new LexerRule(TokenType.LongArray, @"\[L;[\s]*?"),
// new LexerRule(TokenType.ListArray, @"\[[\s]*?"),
// new LexerRule(TokenType.EndArray, @"[\s]*\]"),
// new LexerRule(TokenType.Float, @"-?[0-9]*\.[0-9]+[Ff]"),
// new LexerRule(TokenType.Double, @"-?[0-9]*\.[0-9]+[Dd]?"),
// new LexerRule(TokenType.Byte, "-?([0-9]+)[Bb]"),
// new LexerRule(TokenType.Short, "-?([0-9]+)[Ss]"),
// new LexerRule(TokenType.Long, "-?([0-9]+)[Ll]"),
// new LexerRule(TokenType.Int, "-?([0-9]+)"),
// new LexerRule(TokenType.WhiteSpace, @"[\s]+"),
// new LexerRule(TokenType.String, @"[\S]+"),
// new LexerRule(TokenType.Char, ".")
}; };
} }
private static string Process(Match match)
{
throw new NotImplementedException();
}
public Lexer() public Lexer()
{ {
} }
public IEnumerable<Token> Tokenize(string input)
{
string.Create(input.Length, input, (span, i) =>
{
});
var pos = 0;
do
{
Label:
foreach (var rule in rules)
{
var match = rule.Matcher.Match(input, pos);
if (match.Success)
{
yield return new Token(rule.Type, rule.PostProcess(match));
pos = match.Index + match.Length - 1;
break;
}
}
} while (++pos < input.Length);
}
} }
} }

View File

@ -63,6 +63,12 @@ namespace SharpNBT
/// </summary> /// </summary>
/// <returns>This NBT tag in SNBT format.</returns> /// <returns>This NBT tag in SNBT format.</returns>
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/> /// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
public override string Stringify() => $"{StringifyName}[B;{string.Join(',', this)}]"; public override string Stringify()
{
var values = new string[Count];
for (var i = 0; i < Count; i++)
values[i] = $"{this[i]}b";
return $"{StringifyName}[B;{string.Join(',', values)}]";
}
} }
} }

View File

@ -66,6 +66,12 @@ namespace SharpNBT
/// </summary> /// </summary>
/// <returns>This NBT tag in SNBT format.</returns> /// <returns>This NBT tag in SNBT format.</returns>
/// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/> /// <seealso href="https://minecraft.fandom.com/wiki/NBT_format#SNBT_format"/>
public override string Stringify() => $"{StringifyName}[L;{string.Join(',', this)}]"; public override string Stringify()
{
var values = new string[Count];
for (var i = 0; i < Count; i++)
values[i] = $"{this[i]}l";
return $"{StringifyName}[L;{string.Join(',', values)}]";
}
} }
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization; using System.Runtime.Serialization;
using System.Runtime.Serialization.Json; using System.Runtime.Serialization.Json;
using System.Text; using System.Text;
@ -8,6 +9,7 @@ using System.Text.RegularExpressions;
using JetBrains.Annotations; using JetBrains.Annotations;
[assembly: CLSCompliant(true)] [assembly: CLSCompliant(true)]
[assembly: InternalsVisibleTo("SharpNBT.Tests")]
namespace SharpNBT namespace SharpNBT
{ {