Skip to content

Commit 587b5a1

Browse files
committed
Add LToken.Load/Parse for parsing Lua table expression.
1 parent e59f058 commit 587b5a1

File tree

6 files changed

+171
-27
lines changed

6 files changed

+171
-27
lines changed

Luaon.NET/Linq/LField.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,26 @@ namespace Luaon.Linq
77
{
88
public class LField : LToken
99
{
10+
1011
private LToken _Value;
1112

13+
public new static LField Load(LuaTableTextReader reader)
14+
{
15+
if (reader == null) throw new ArgumentNullException(nameof(reader));
16+
if (reader.CurrentToken == LuaTableReaderToken.None)
17+
reader.Read();
18+
SkipComments(reader);
19+
LValue key = null;
20+
if (reader.CurrentToken == LuaTableReaderToken.Key)
21+
{
22+
key = new LValue(reader.CurrentValue);
23+
reader.Read();
24+
SkipComments(reader);
25+
}
26+
LToken value = LToken.Load(reader);
27+
return new LField(key, value);
28+
}
29+
1230
/// <summary>
1331
/// Initializes a new positional Lua table field with the specified name and value.
1432
/// </summary>

Luaon.NET/Linq/LTable.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,29 @@ public class LTable : LToken, ICollection<LField>
1616

1717
private readonly LTableStore store = new LTableStore();
1818

19+
public new static LTable Load(LuaTableTextReader reader)
20+
{
21+
if (reader == null) throw new ArgumentNullException(nameof(reader));
22+
if (reader.CurrentToken == LuaTableReaderToken.None)
23+
reader.Read();
24+
SkipComments(reader);
25+
AssertReaderToken(reader, LuaTableReaderToken.TableStart);
26+
// Read fields.
27+
reader.Read();
28+
SkipComments(reader);
29+
var table = new LTable();
30+
while (true)
31+
{
32+
if (reader.CurrentToken == LuaTableReaderToken.TableEnd)
33+
{
34+
reader.Read();
35+
break;
36+
}
37+
table.Add(LField.Load(reader));
38+
}
39+
return table;
40+
}
41+
1942
public LTable()
2043
{
2144

Luaon.NET/Linq/LToken.cs

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,63 @@ namespace Luaon.Linq
88
public abstract class LToken
99
{
1010

11+
public static LToken Load(LuaTableTextReader reader)
12+
{
13+
if (reader == null) throw new ArgumentNullException(nameof(reader));
14+
if (reader.CurrentToken == LuaTableReaderToken.None)
15+
reader.Read();
16+
SkipComments(reader);
17+
switch (reader.CurrentToken)
18+
{
19+
case LuaTableReaderToken.None:
20+
case LuaTableReaderToken.TableStart:
21+
return LTable.Load(reader);
22+
case LuaTableReaderToken.Key:
23+
return LField.Load(reader);
24+
case LuaTableReaderToken.Value:
25+
return LValue.Load(reader);
26+
default:
27+
throw MakeUnexpectedTokenException(reader);
28+
}
29+
}
30+
31+
public static LToken Parse(string expression)
32+
{
33+
using (var reader = new StringReader(expression))
34+
using (var lreader = new LuaTableTextReader(reader))
35+
{
36+
var token = Load(lreader);
37+
SkipComments(lreader);
38+
if (lreader.CurrentToken != LuaTableReaderToken.None)
39+
throw new LuaTableReaderException($"Detected extra content after parsing complete: {lreader.CurrentToken}.",
40+
lreader.CurrentPath);
41+
return token;
42+
}
43+
}
44+
45+
protected static void SkipComments(LuaTableTextReader reader)
46+
{
47+
while (reader.CurrentToken == LuaTableReaderToken.Comment)
48+
reader.Read();
49+
}
50+
51+
protected static void AssertReaderToken(LuaTableTextReader reader, LuaTableReaderToken expectedToken)
52+
{
53+
if (reader.CurrentToken != expectedToken)
54+
throw MakeUnexpectedTokenException(reader, expectedToken);
55+
}
56+
57+
protected static LuaTableReaderException MakeUnexpectedTokenException(LuaTableTextReader reader,
58+
LuaTableReaderToken expectedToken = LuaTableReaderToken.None)
59+
{
60+
if (reader.CurrentToken == LuaTableReaderToken.None)
61+
return new LuaTableReaderException("Unexpected end of input.", reader.CurrentPath);
62+
var message = $"Unexpected Lua token: {reader.CurrentToken}.";
63+
if (expectedToken != LuaTableReaderToken.None)
64+
message += $" Expected: {expectedToken}.";
65+
return new LuaTableReaderException(message, reader.CurrentPath);
66+
}
67+
1168
/// <summary>
1269
/// Gets the token node type.
1370
/// </summary>
@@ -33,7 +90,7 @@ public string ToString(Formatting formatting)
3390
{
3491
using (var writer = new StringWriter())
3592
{
36-
using (var lw = new LuaTableTextWriter(writer) { CloseWriter = false, Formatting = formatting})
93+
using (var lw = new LuaTableTextWriter(writer) { CloseWriter = false, Formatting = formatting })
3794
{
3895
WriteTo(lw);
3996
}
@@ -55,60 +112,60 @@ public override string ToString()
55112

56113
public static explicit operator double(LToken value)
57114
{
58-
return (double)(LValue)value;
115+
return (double) (LValue) value;
59116
}
60117

61118
public static explicit operator double?(LToken value)
62119
{
63120
if (value == null || value.TokenType == LTokenType.Nil) return null;
64-
return (double)(LValue)value;
121+
return (double) (LValue) value;
65122
}
66123

67124
public static explicit operator float(LToken value)
68125
{
69-
return (float)(double)(LValue)value;
126+
return (float) (double) (LValue) value;
70127
}
71128

72129
public static explicit operator float?(LToken value)
73130
{
74-
return (float?)(double?)value;
131+
return (float?) (double?) value;
75132
}
76133

77134
public static explicit operator long(LToken value)
78135
{
79-
return (long)(LValue)value;
136+
return (long) (LValue) value;
80137
}
81138

82139
public static explicit operator long?(LToken value)
83140
{
84141
if (value.TokenType == LTokenType.Nil) return null;
85-
return (long)(LValue)value;
142+
return (long) (LValue) value;
86143
}
87144

88145
public static explicit operator int(LToken value)
89146
{
90-
return (int)(long)value;
147+
return (int) (long) value;
91148
}
92149

93150
public static explicit operator int?(LToken value)
94151
{
95-
return (int?)(long?)value;
152+
return (int?) (long?) value;
96153
}
97154

98155
public static explicit operator bool(LToken value)
99156
{
100-
return (bool)(LValue)value;
157+
return (bool) (LValue) value;
101158
}
102159

103160
public static explicit operator bool?(LToken value)
104161
{
105162
if (value.TokenType == LTokenType.Nil) return null;
106-
return (bool)value;
163+
return (bool) value;
107164
}
108165

109166
public static explicit operator string(LToken value)
110167
{
111-
return (string)(LValue)value;
168+
return (string) (LValue) value;
112169
}
113170

114171
public static implicit operator LToken(bool value)

Luaon.NET/Linq/LValue.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ public class LValue : LToken, IEquatable<LValue>
2929
/// </summary>
3030
public static LValue False { get; } = new LValue(false);
3131

32+
public new static LValue Load(LuaTableTextReader reader)
33+
{
34+
if (reader == null) throw new ArgumentNullException(nameof(reader));
35+
if (reader.CurrentToken == LuaTableReaderToken.None)
36+
reader.Read();
37+
SkipComments(reader);
38+
AssertReaderToken(reader, LuaTableReaderToken.Value);
39+
var v = new LValue(reader.CurrentValue);
40+
reader.Read();
41+
return v;
42+
}
43+
3244
public LValue(LValue other)
3345
{
3446
if (other == null) throw new ArgumentNullException(nameof(other));
@@ -97,19 +109,19 @@ public LValue(object value)
97109
TokenType = LTokenType.Boolean;
98110
break;
99111
case byte v:
100-
this.Value = (int)v;
112+
this.Value = (int) v;
101113
TokenType = LTokenType.Integer;
102114
break;
103115
case sbyte v:
104-
this.Value = (int)v;
116+
this.Value = (int) v;
105117
TokenType = LTokenType.Integer;
106118
break;
107119
case short v:
108-
this.Value = (int)v;
120+
this.Value = (int) v;
109121
TokenType = LTokenType.Integer;
110122
break;
111123
case ushort v:
112-
this.Value = (int)v;
124+
this.Value = (int) v;
113125
TokenType = LTokenType.Integer;
114126
break;
115127
case int v:
@@ -283,7 +295,7 @@ public override bool Equals(object obj)
283295
if (ReferenceEquals(null, obj)) return false;
284296
if (ReferenceEquals(this, obj)) return true;
285297
if (obj.GetType() != this.GetType()) return false;
286-
return Equals((LValue)obj);
298+
return Equals((LValue) obj);
287299
}
288300

289301
/// <inheritdoc />

Luaon.NET/LuaTableTextReader.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public class LuaTableTextReader : IDisposable
3939

4040
private readonly List<LuaContainerContext> contextStack;
4141
private LuaContainerContext currentContext;
42-
private char[] buffer;
42+
private readonly char[] buffer;
4343
private int bufferLength;
4444
private int bufferPos;
4545
private bool readerEof;
@@ -146,7 +146,7 @@ private LuaContainerType Pop()
146146
return context.ContainerType;
147147
}
148148

149-
private string CurrentPath => LuaContainerContext.ToString(contextStack, currentContext);
149+
public string CurrentPath => LuaContainerContext.ToString(contextStack, currentContext);
150150

151151
private void AssertContainerType(LuaContainerType type)
152152
{

XUnitTestProject1/Tests/LinqTests.cs

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public LinqTests(ITestOutputHelper output) : base(output)
1717
}
1818

1919
[Fact]
20-
public void LTableTest()
20+
public void LTableToStringTest()
2121
{
2222
var table = new LTable
2323
{
@@ -36,13 +36,13 @@ public void LTableTest()
3636
Assert.Equal(4.5, table[2]);
3737
Assert.Equal(5, table[20]);
3838
Assert.Equal("6", table[true]);
39-
Assert.Equal(1, (int)table["Test1"]);
40-
Assert.Equal(2, (int)table[1]);
41-
Assert.Equal(3, (int)table["Test2"]);
42-
Assert.Equal(4, (int)table[2]);
43-
Assert.Equal("5", (string)table[20]);
44-
Assert.Equal(6, (int)table[true]);
45-
var childTable = (LTable)table["Child"];
39+
Assert.Equal(1, (int) table["Test1"]);
40+
Assert.Equal(2, (int) table[1]);
41+
Assert.Equal(3, (int) table["Test2"]);
42+
Assert.Equal(4, (int) table[2]);
43+
Assert.Equal("5", (string) table[20]);
44+
Assert.Equal(6, (int) table[true]);
45+
var childTable = (LTable) table["Child"];
4646
Assert.Equal(5, childTable.Count);
4747
Assert.Equal(1, table["Child"][1]);
4848
Assert.Equal(2, table["Child"][2]);
@@ -66,5 +66,39 @@ public void LTableTest()
6666
}", table.ToString());
6767
}
6868

69+
[Fact]
70+
public void LTokenParseTest()
71+
{
72+
Assert.Equal(LValue.True, LToken.Parse("true"));
73+
Assert.Equal(LValue.False, LToken.Parse("--content\nfalse\n--content"));
74+
Assert.Equal(LValue.Nil, LToken.Parse("nil"));
75+
Assert.Equal(new LTable { 10, 20, 30 }, LToken.Parse("{10, 20, 30}"));
76+
Assert.Equal(new LTable { 10, 20, 30, new LTable { 40, 50 } }, LToken.Parse("{10, 20, 30, {40, 50}}"));
77+
Assert.Equal(new LTable
78+
{
79+
{"Test1", 1},
80+
2,
81+
{"Test2", 3},
82+
4.5,
83+
{20, 5},
84+
{true, "6"},
85+
{"Child", new LTable(1, 2, 3, 4, 5)}
86+
}, LToken.Parse(@"{
87+
Test1 = 1,
88+
2,
89+
Test2 = 3,
90+
4.5,
91+
[20] = 5,
92+
[true] = ""6"",
93+
Child = {
94+
1,
95+
2,
96+
3,
97+
4,
98+
5
99+
}
100+
}"));
101+
}
102+
69103
}
70104
}

0 commit comments

Comments
 (0)