yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie HermaszewskaCorrect include dir for libslang (#5539)7b570feed

master
11.1 KiB369 linesraw
1
2#include "../../source/compiler-core/slang-json-lexer.h"
3#include "../../source/compiler-core/slang-json-parser.h"
4#include "../../source/compiler-core/slang-json-value.h"
5#include "../../source/core/slang-string-escape-util.h"
6#include "unit-test/slang-unit-test.h"
7
8using namespace Slang;
9
10namespace
11{ // anonymous
12
13struct Element
14{
15    JSONTokenType type;
16    const char* value;
17};
18
19} // namespace
20
21static SlangResult _lex(const char* in, DiagnosticSink* sink, List<JSONToken>& toks)
22{
23    SourceManager* sourceManager = sink->getSourceManager();
24
25    String contents(in);
26    SourceFile* sourceFile =
27        sourceManager->createSourceFileWithString(PathInfo::makeUnknown(), contents);
28    SourceView* sourceView = sourceManager->createSourceView(sourceFile, nullptr, SourceLoc());
29
30    JSONLexer lexer;
31
32    lexer.init(sourceView, sink);
33
34    while (lexer.peekType() != JSONTokenType::EndOfFile)
35    {
36        if (lexer.peekType() == JSONTokenType::Invalid)
37        {
38            toks.add(lexer.peekToken());
39            return SLANG_FAIL;
40        }
41
42        toks.add(lexer.peekToken());
43        lexer.advance();
44    }
45
46    toks.add(lexer.peekToken());
47
48    // If we advance from end of file we should still be at EndOfFile
49    SLANG_ASSERT(lexer.advance() == JSONTokenType::EndOfFile);
50
51    return SLANG_OK;
52}
53
54static SlangResult _parse(const char* in, DiagnosticSink* sink, JSONListener* listener)
55{
56    SourceManager* sourceManager = sink->getSourceManager();
57
58    String contents(in);
59    SourceFile* sourceFile =
60        sourceManager->createSourceFileWithString(PathInfo::makeUnknown(), contents);
61    SourceView* sourceView = sourceManager->createSourceView(sourceFile, nullptr, SourceLoc());
62
63    JSONLexer lexer;
64    lexer.init(sourceView, sink);
65
66    JSONParser parser;
67    SLANG_RETURN_ON_FAIL(parser.parse(&lexer, sourceView, listener, sink));
68    return SLANG_OK;
69}
70
71static bool _areEqual(
72    SourceManager* sourceManager,
73    const List<JSONToken>& toks,
74    const Element* eles,
75    Index elesCount)
76{
77    if (toks.getCount() != elesCount)
78    {
79        return false;
80    }
81
82    SourceView* sourceView = toks.getCount() ? sourceManager->findSourceView(toks[0].loc) : nullptr;
83    const char* const content = sourceView ? sourceView->getContent().begin() : nullptr;
84
85    for (Index i = 0; i < toks.getCount(); ++i)
86    {
87        const JSONToken& tok = toks[i];
88        const auto& ele = eles[i];
89
90        if (tok.type != ele.type)
91        {
92            return false;
93        }
94
95        SLANG_ASSERT(sourceView->getRange().contains(tok.loc));
96
97        const char* start = content + sourceView->getRange().getOffset(tok.loc);
98
99        UnownedStringSlice lexeme(start, tok.length);
100
101        if (lexeme != ele.value)
102        {
103            return false;
104        }
105    }
106
107    return true;
108}
109
110SLANG_UNIT_TEST(json)
111{
112    SourceManager sourceManager;
113    sourceManager.initialize(nullptr, nullptr);
114    DiagnosticSink sink(&sourceManager, nullptr);
115
116    {
117        const char text[] =
118            " { \"Hello\" : [ \"World\", 1, 2.0, -3.0, -435.5345435, 45e-10, 421.00e+20, 17e1] }";
119
120        const Element eles[] = {
121            {JSONTokenType::LBrace, "{"},
122            {JSONTokenType::StringLiteral, "\"Hello\""},
123            {JSONTokenType::Colon, ":"},
124            {JSONTokenType::LBracket, "["},
125            {JSONTokenType::StringLiteral, "\"World\""},
126            {JSONTokenType::Comma, ","},
127            {JSONTokenType::IntegerLiteral, "1"},
128            {JSONTokenType::Comma, ","},
129            {JSONTokenType::FloatLiteral, "2.0"},
130            {JSONTokenType::Comma, ","},
131            {JSONTokenType::FloatLiteral, "-3.0"},
132            {JSONTokenType::Comma, ","},
133            {JSONTokenType::FloatLiteral, "-435.5345435"},
134            {JSONTokenType::Comma, ","},
135            {JSONTokenType::FloatLiteral, "45e-10"},
136            {JSONTokenType::Comma, ","},
137            {JSONTokenType::FloatLiteral, "421.00e+20"},
138            {JSONTokenType::Comma, ","},
139            {JSONTokenType::FloatLiteral, "17e1"},
140            {JSONTokenType::RBracket, "]"},
141            {JSONTokenType::RBrace, "}"},
142            {JSONTokenType::EndOfFile, ""},
143        };
144
145        List<JSONToken> toks;
146        SLANG_CHECK(SLANG_SUCCEEDED(_lex(text, &sink, toks)));
147
148        SLANG_CHECK(_areEqual(&sourceManager, toks, eles, SLANG_COUNT_OF(eles)));
149    }
150
151    {
152        StringEscapeHandler* handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::JSON);
153
154
155        {
156            const auto slice = UnownedStringSlice::fromLiteral("\n\r\b\f\t \"\\/ Some text...");
157
158            SLANG_CHECK(handler->isEscapingNeeded(slice));
159            SLANG_CHECK(!handler->isEscapingNeeded(UnownedStringSlice::fromLiteral("Hello!")));
160
161            StringBuilder escaped;
162            handler->appendEscaped(slice, escaped);
163
164            StringBuilder unescaped;
165            handler->appendUnescaped(escaped.getUnownedSlice(), unescaped);
166
167            SLANG_CHECK(unescaped == slice);
168        }
169
170        {
171            uint32_t v = 0x7f;
172
173            StringBuilder buf;
174            while (v < 0x10000)
175            {
176                char work[10] = "\\u";
177
178                for (Int i = 0; i < 4; ++i)
179                {
180                    const uint32_t digitValue = (v >> ((3 - i) * 4)) & 0xf;
181
182                    char digitC =
183                        (digitValue > 9) ? char(digitValue - 10 + 'a') : char(digitValue + '0');
184                    work[i + 2] = digitC;
185                }
186
187                buf << UnownedStringSlice(work, 6);
188
189                v += v;
190            }
191
192            // Decode it
193            StringBuilder unescaped;
194            handler->appendUnescaped(buf.getUnownedSlice(), unescaped);
195
196            // Encode it
197            StringBuilder escaped;
198            handler->appendEscaped(unescaped.getUnownedSlice(), escaped);
199
200            SLANG_CHECK(escaped == buf);
201        }
202    }
203
204    {
205        const char in[] = "{ \"Hello\" : \"Json\", \"!\" : 10, \"array\" : [1, 2, 3.0] }";
206
207        {
208            auto style = JSONWriter::IndentationStyle::Allman;
209
210            JSONWriter writer(style);
211            _parse(in, &sink, &writer);
212
213            JSONWriter writerCheck(style);
214            _parse(writer.getBuilder().getBuffer(), &sink, &writerCheck);
215
216            SLANG_CHECK(writerCheck.getBuilder() == writer.getBuilder());
217        }
218
219        {
220            auto style = JSONWriter::IndentationStyle::KNR;
221
222            JSONWriter writer(style, 80);
223            _parse(in, &sink, &writer);
224
225            JSONWriter writerCheck(style);
226            _parse(writer.getBuilder().getBuffer(), &sink, &writerCheck);
227
228            SLANG_CHECK(writerCheck.getBuilder() == writer.getBuilder());
229        }
230
231        {
232            // Let's parse into a Value
233            RefPtr<JSONContainer> container = new JSONContainer(&sourceManager);
234
235            JSONValue value;
236            {
237                JSONBuilder builder(container);
238
239                SLANG_CHECK(SLANG_SUCCEEDED(_parse(in, &sink, &builder)));
240                value = builder.getRootValue();
241            }
242            // Let's recreate
243            JSONValue copy;
244            {
245                JSONBuilder builder(container);
246                container->traverseRecursively(value, &builder);
247                copy = builder.getRootValue();
248            }
249
250            SLANG_CHECK(container->areEqual(value, copy));
251        }
252    }
253
254    {
255        // Only need a SourceManager if we are going to store lexemes
256        RefPtr<JSONContainer> container = new JSONContainer(nullptr);
257
258        {
259            List<JSONValue> values;
260
261            for (Int i = 0; i < 100; ++i)
262            {
263
264                values.add(JSONValue::makeInt(i));
265                values.add(JSONValue::makeFloat(-double(i)));
266            }
267
268            JSONValue array = container->createArray(values.getBuffer(), values.getCount());
269
270            auto arrayView = container->getArray(array);
271
272            SLANG_CHECK(arrayView.getCount() == values.getCount());
273
274            // Check the values are the same
275            SLANG_CHECK(container->areEqual(
276                arrayView.getBuffer(),
277                values.getBuffer(),
278                arrayView.getCount()));
279
280            {
281                JSONWriter writer(JSONWriter::IndentationStyle::KNR, 80);
282
283                container->traverseRecursively(array, &writer);
284            }
285        }
286        {
287            JSONValue obj = JSONValue::makeEmptyObject();
288
289            JSONKey key = container->getKey(UnownedStringSlice::fromLiteral("Hello"));
290
291            container->setKeyValue(obj, key, JSONValue::makeNull());
292            container->setKeyValue(obj, key, JSONValue::makeInt(10));
293
294            auto objView = container->getObject(obj);
295
296            SLANG_CHECK(objView.getCount() == 1);
297
298            SLANG_CHECK(objView[0].value.asInteger() == 10);
299        }
300    }
301
302    // Check repeated keys works out
303    // Check out comparison works with different key orders
304    {
305        RefPtr<JSONContainer> container = new JSONContainer(&sourceManager);
306        const char aText[] = "{ \"a\" : 10, \"b\" : 20.0, \"a\" : \"Hello\" }";
307
308
309        JSONBuilder builder(container);
310        SLANG_CHECK(SLANG_SUCCEEDED(_parse(aText, &sink, &builder)));
311        const JSONValue a = builder.getRootValue();
312
313        builder.reset();
314
315        const char bText[] = "{ \"b\" : 20.0, \"a\" : \"Hello\"}";
316        SLANG_CHECK(SLANG_SUCCEEDED(_parse(bText, &sink, &builder)));
317        const JSONValue b = builder.getRootValue();
318
319        SLANG_CHECK(container->areEqual(a, b));
320
321        JSONBuilder convertBuilder(container, JSONBuilder::Flag::ConvertLexemes);
322
323        SLANG_CHECK(SLANG_SUCCEEDED(_parse(aText, &sink, &convertBuilder)));
324        const JSONValue c = builder.getRootValue();
325
326        SLANG_CHECK(container->areEqual(a, c));
327    }
328
329    {
330        RefPtr<JSONContainer> container = new JSONContainer(&sourceManager);
331        const char aText[] = "{ \"a\" : \"Hi!\", \"b\" : 20.0, \"c\" : \"Hello\", \"d\" : 30, "
332                             "\"e\": null, \"f\": true }";
333
334        JSONBuilder builder(container);
335        SLANG_CHECK(SLANG_SUCCEEDED(_parse(aText, &sink, &builder)));
336        const JSONValue rootValue = builder.getRootValue();
337
338        List<PersistentJSONValue> values;
339
340        for (char c = 'a'; c <= 'f'; c++)
341        {
342            const char name[] = {c, 0};
343            JSONKey key = container->getKey(UnownedStringSlice(name, 1));
344            auto value = container->findObjectValue(rootValue, key);
345
346            SLANG_CHECK(value.type != JSONValue::Type::Invalid);
347
348            PersistentJSONValue persistentValue(value, container);
349            values.add(persistentValue);
350
351            PersistentJSONValue copyValue(persistentValue);
352            PersistentJSONValue assignValue;
353            assignValue = persistentValue;
354
355            SLANG_CHECK(copyValue == persistentValue);
356            SLANG_CHECK(assignValue == persistentValue);
357        }
358
359        // Destroy the container
360        container.setNull();
361
362        SLANG_CHECK(values[0].getSlice() == "Hi!");
363        SLANG_CHECK(values[1].asFloat() == 20.0f);
364        SLANG_CHECK(values[2].getSlice() == "Hello");
365        SLANG_CHECK(values[3].asInteger() == 30);
366        SLANG_CHECK(values[4].type == JSONValue::Type::Null);
367        SLANG_CHECK(values[5].asBool() == true);
368    }
369}