yum-mirror/slang

Making it easier to work with shaders

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

Ellie Hermaszewskaformatf65d756bf

master
11.3 KiB494 linesraw
1// slang-json-parser.cpp
2#include "slang-json-parser.h"
3
4#include "../core/slang-string-escape-util.h"
5#include "slang-json-diagnostics.h"
6
7/*
8https://www.json.org/json-en.html
9*/
10
11namespace Slang
12{
13
14SlangResult JSONParser::_parseObject()
15{
16    {
17        const SourceLoc loc = m_lexer->peekLoc();
18        SLANG_RETURN_ON_FAIL(m_lexer->expect(JSONTokenType::LBrace));
19        m_listener->startObject(loc);
20    }
21
22    {
23        const SourceLoc loc = m_lexer->peekLoc();
24        if (m_lexer->advanceIf(JSONTokenType::RBrace))
25        {
26            m_listener->endObject(loc);
27            return SLANG_OK;
28        }
29    }
30
31    while (true)
32    {
33        JSONToken keyToken;
34        SLANG_RETURN_ON_FAIL(m_lexer->expect(JSONTokenType::StringLiteral, keyToken));
35        m_listener->addQuotedKey(m_lexer->getLexeme(keyToken), keyToken.loc);
36
37        SLANG_RETURN_ON_FAIL(m_lexer->expect(JSONTokenType::Colon));
38
39        SLANG_RETURN_ON_FAIL(_parseValue());
40        if (m_lexer->advanceIf(JSONTokenType::Comma))
41        {
42            continue;
43        }
44
45        break;
46    }
47
48    {
49        const SourceLoc loc = m_lexer->peekLoc();
50        SLANG_RETURN_ON_FAIL(m_lexer->expect(JSONTokenType::RBrace));
51        m_listener->endObject(loc);
52    }
53    return SLANG_OK;
54}
55
56SlangResult JSONParser::_parseArray()
57{
58    {
59        const SourceLoc loc = m_lexer->peekLoc();
60        SLANG_RETURN_ON_FAIL(m_lexer->expect(JSONTokenType::LBracket));
61        m_listener->startArray(loc);
62    }
63
64    {
65        const SourceLoc loc = m_lexer->peekLoc();
66        if (m_lexer->advanceIf(JSONTokenType::RBracket))
67        {
68            m_listener->endArray(loc);
69            return SLANG_OK;
70        }
71    }
72
73    while (true)
74    {
75        SLANG_RETURN_ON_FAIL(_parseValue());
76        if (m_lexer->advanceIf(JSONTokenType::Comma))
77        {
78            continue;
79        }
80        break;
81    }
82
83    {
84        const SourceLoc loc = m_lexer->peekLoc();
85        SLANG_RETURN_ON_FAIL(m_lexer->expect(JSONTokenType::RBracket));
86        m_listener->endArray(loc);
87    }
88    return SLANG_OK;
89}
90
91SlangResult JSONParser::_parseValue()
92{
93    switch (m_lexer->peekType())
94    {
95    case JSONTokenType::True:
96    case JSONTokenType::False:
97    case JSONTokenType::Null:
98    case JSONTokenType::IntegerLiteral:
99    case JSONTokenType::FloatLiteral:
100    case JSONTokenType::StringLiteral:
101        {
102            const JSONToken& tok = m_lexer->peekToken();
103            m_listener->addLexemeValue(tok.type, m_lexer->peekLexeme(), tok.loc);
104            m_lexer->advance();
105            return SLANG_OK;
106        }
107    case JSONTokenType::LBracket:
108        {
109            return _parseArray();
110        }
111    case JSONTokenType::LBrace:
112        {
113            return _parseObject();
114        }
115    default:
116        {
117            m_sink->diagnose(
118                m_lexer->peekLoc(),
119                JSONDiagnostics::unexpectedToken,
120                getJSONTokenAsText(m_lexer->peekType()));
121            return SLANG_FAIL;
122        }
123    case JSONTokenType::Invalid:
124        {
125            // It's a lex error, so just fail
126            return SLANG_FAIL;
127        }
128    }
129}
130
131SlangResult JSONParser::parse(
132    JSONLexer* lexer,
133    SourceView* sourceView,
134    JSONListener* listener,
135    DiagnosticSink* sink)
136{
137    m_sourceView = sourceView;
138    m_lexer = lexer;
139    m_listener = listener;
140    m_sink = sink;
141
142    SLANG_RETURN_ON_FAIL(_parseValue());
143
144    return m_lexer->expect(JSONTokenType::EndOfFile);
145}
146
147/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
148
149                               JSONWriter
150
151!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
152
153Index JSONWriter::_getLineLengthAfterIndent()
154{
155    if (m_emittedIndent < 0)
156    {
157        return 0;
158    }
159
160    Index lineLength = m_builder.getLength() - m_lineStart;
161    return lineLength - m_emittedIndent * m_indentCharCount;
162}
163
164
165void JSONWriter::_emitIndent()
166{
167    m_builder.appendRepeatedChar(m_indentChar, m_currentIndent * m_indentCharCount);
168    m_emittedIndent = m_currentIndent;
169    SLANG_ASSERT(m_emittedIndent >= 0);
170}
171
172void JSONWriter::_maybeEmitIndent()
173{
174    if (m_emittedIndent < 0)
175    {
176        _emitIndent();
177    }
178}
179
180void JSONWriter::_nextLine()
181{
182    m_builder << "\n";
183    m_lineStart = m_builder.getLength();
184    m_lineIndex++;
185    m_emittedIndent = -1;
186}
187
188void JSONWriter::_maybeNextLine()
189{
190    // Nothing has been emitted, because nothing has been indented, and we must indent before an
191    // emit
192    if (m_emittedIndent < 0)
193    {
194    }
195    else
196    {
197        _nextLine();
198    }
199}
200
201void JSONWriter::_handleFormat(Location loc)
202{
203    switch (m_format)
204    {
205    case IndentationStyle::Allman:
206        {
207            if (isComma(loc))
208            {
209                _maybeNextLine();
210            }
211            else
212            {
213                if (isBefore(loc))
214                {
215                    _maybeNextLine();
216                    if (isClose(loc))
217                    {
218                        _dedent();
219                    }
220                }
221                else
222                {
223                    _maybeNextLine();
224                    if (isOpen(loc))
225                    {
226                        _indent();
227                    }
228                }
229            }
230            break;
231        }
232    case IndentationStyle::KNR:
233        {
234            if (isComma(loc))
235            {
236                if (loc == Location::FieldComma ||
237                    (m_lineLengthLimit > 0 && _getLineLengthAfterIndent() > m_lineLengthLimit))
238                {
239                    _maybeNextLine();
240                }
241            }
242            else
243            {
244                if (isBefore(loc))
245                {
246                    if (isClose(loc))
247                    {
248                        _maybeNextLine();
249                        _dedent();
250                    }
251                }
252                else
253                {
254                    _maybeNextLine();
255                    if (isOpen(loc))
256                    {
257                        _indent();
258                    }
259                }
260            }
261            break;
262        }
263    }
264}
265
266void JSONWriter::_maybeEmitComma()
267{
268    if (m_state.m_flags & State::Flag::HasPrevious)
269    {
270        _maybeEmitIndent();
271        m_builder << ", ";
272        _handleFormat(Location::Comma);
273    }
274}
275
276void JSONWriter::_maybeEmitFieldComma()
277{
278    if (m_state.m_flags & State::Flag::HasPrevious)
279    {
280        _maybeEmitIndent();
281        m_builder << ", ";
282        _handleFormat(Location::FieldComma);
283    }
284}
285
286void JSONWriter::startObject(SourceLoc loc)
287{
288    SLANG_UNUSED(loc);
289    SLANG_ASSERT(m_state.canEmitValue());
290
291    _maybeEmitComma();
292
293    _handleFormat(Location::BeforeOpenObject);
294    _maybeEmitIndent();
295    m_builder << "{";
296    _handleFormat(Location::AfterOpenObject);
297
298    m_state.m_flags |= State::Flag::HasPrevious;
299    m_state.m_flags &= State::Flag::HasKey;
300
301    m_stack.add(m_state);
302
303    m_state.m_kind = State::Kind::Object;
304    m_state.m_flags = 0;
305}
306
307void JSONWriter::endObject(SourceLoc loc)
308{
309    SLANG_UNUSED(loc);
310    SLANG_ASSERT(m_state.m_kind == State::Kind::Object);
311
312    _handleFormat(Location::BeforeCloseObject);
313    _maybeEmitIndent();
314    m_builder << "}";
315    _handleFormat(Location::AfterCloseObject);
316
317    m_state = m_stack.getLast();
318    m_stack.removeLast();
319
320    _postValue();
321}
322
323void JSONWriter::startArray(SourceLoc loc)
324{
325    SLANG_UNUSED(loc);
326    SLANG_ASSERT(m_state.canEmitValue());
327
328    _maybeEmitComma();
329
330    _handleFormat(Location::BeforeOpenArray);
331    _maybeEmitIndent();
332    m_builder << "[";
333    _handleFormat(Location::AfterOpenArray);
334
335    m_state.m_flags |= State::Flag::HasPrevious;
336    m_state.m_flags &= State::Flag::HasKey;
337
338    m_stack.add(m_state);
339
340    m_state.m_kind = State::Kind::Array;
341    m_state.m_flags = 0;
342}
343
344void JSONWriter::endArray(SourceLoc loc)
345{
346    SLANG_UNUSED(loc);
347    SLANG_ASSERT(m_state.m_kind == State::Kind::Array);
348
349    _handleFormat(Location::BeforeCloseArray);
350    _maybeEmitIndent();
351    m_builder << "]";
352    _handleFormat(Location::AfterCloseArray);
353
354    m_state = m_stack.getLast();
355    m_stack.removeLast();
356
357    _postValue();
358}
359
360void JSONWriter::addUnquotedKey(const UnownedStringSlice& key, SourceLoc loc)
361{
362    SLANG_UNUSED(loc);
363    SLANG_ASSERT(
364        m_state.m_kind == State::Kind::Object && (m_state.m_flags & State::Flag::HasKey) == 0);
365
366    _maybeEmitFieldComma();
367    _maybeEmitIndent();
368
369    // Output the key quoted
370    StringEscapeHandler* handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::JSON);
371    StringEscapeUtil::appendQuoted(handler, key, m_builder);
372
373    m_builder << " : ";
374
375    m_state.m_flags |= State::Flag::HasKey;
376    // We don't want it to emit a , after the :
377    m_state.m_flags &= ~State::Flag::HasPrevious;
378}
379
380void JSONWriter::addQuotedKey(const UnownedStringSlice& key, SourceLoc loc)
381{
382    SLANG_UNUSED(loc);
383    SLANG_ASSERT(
384        m_state.m_kind == State::Kind::Object && (m_state.m_flags & State::Flag::HasKey) == 0);
385
386    // It should be quoted
387    SLANG_ASSERT(key.getLength() >= 2 && key[0] == '"' && key[key.getLength() - 1] == '"');
388
389    _maybeEmitFieldComma();
390    _maybeEmitIndent();
391
392    m_builder << key;
393
394    m_builder << " : ";
395
396    m_state.m_flags |= State::Flag::HasKey;
397    // We don't want it to emit a , after the :
398    m_state.m_flags &= ~State::Flag::HasPrevious;
399}
400
401void JSONWriter::_preValue(SourceLoc loc)
402{
403    SLANG_UNUSED(loc);
404    SLANG_ASSERT(m_state.canEmitValue());
405
406    _maybeEmitComma();
407    _maybeEmitIndent();
408}
409
410void JSONWriter::_postValue()
411{
412    // We have a previous
413    m_state.m_flags |= State::Flag::HasPrevious;
414    // We don't have a key
415    m_state.m_flags &= ~State::Flag::HasKey;
416}
417
418
419void JSONWriter::addLexemeValue(JSONTokenType type, const UnownedStringSlice& value, SourceLoc loc)
420{
421    _preValue(loc);
422
423    switch (type)
424    {
425    case JSONTokenType::IntegerLiteral:
426    case JSONTokenType::FloatLiteral:
427    case JSONTokenType::StringLiteral:
428        {
429            m_builder << value;
430            break;
431        }
432    case JSONTokenType::True:
433        {
434            m_builder << UnownedStringSlice::fromLiteral("true");
435            break;
436        }
437    case JSONTokenType::False:
438        {
439            m_builder << UnownedStringSlice::fromLiteral("false");
440            break;
441        }
442    case JSONTokenType::Null:
443        {
444            m_builder << UnownedStringSlice::fromLiteral("null");
445            break;
446        }
447    default:
448        {
449            SLANG_ASSERT(!"Can only emit values");
450        }
451    }
452
453    _postValue();
454}
455
456void JSONWriter::addIntegerValue(int64_t value, SourceLoc loc)
457{
458    _preValue(loc);
459    m_builder << value;
460    _postValue();
461}
462
463void JSONWriter::addFloatValue(double value, SourceLoc loc)
464{
465    _preValue(loc);
466    m_builder << value;
467    _postValue();
468}
469
470void JSONWriter::addBoolValue(bool inValue, SourceLoc loc)
471{
472    _preValue(loc);
473    const UnownedStringSlice slice = inValue ? UnownedStringSlice::fromLiteral("true")
474                                             : UnownedStringSlice::fromLiteral("false");
475    m_builder << slice;
476    _postValue();
477}
478
479void JSONWriter::addNullValue(SourceLoc loc)
480{
481    _preValue(loc);
482    m_builder << UnownedStringSlice::fromLiteral("null");
483    _postValue();
484}
485
486void JSONWriter::addStringValue(const UnownedStringSlice& slice, SourceLoc loc)
487{
488    _preValue(loc);
489    StringEscapeHandler* handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::JSON);
490    StringEscapeUtil::appendQuoted(handler, slice, m_builder);
491    _postValue();
492}
493
494} // namespace Slang