yum-mirror/slang

Making it easier to work with shaders

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

Yong HeMisc language server improvements. (#7569)eb7f3357a

master
42.1 KiB1611 linesraw
1// slang-json-value.cpp
2#include "slang-json-value.h"
3
4#include "../core/slang-string-escape-util.h"
5#include "../core/slang-string-util.h"
6
7namespace Slang
8{
9
10/* static */ const JSONValue::Kind JSONValue::g_typeToKind[] = {
11    JSONValue::Kind::Invalid, // Invalid
12
13    JSONValue::Kind::Bool, // True,
14    JSONValue::Kind::Bool, // False
15    JSONValue::Kind::Null, // Null,
16
17    JSONValue::Kind::String,  // StringLexeme,
18    JSONValue::Kind::Integer, // IntegerLexeme,
19    JSONValue::Kind::Float,   // FloatLexeme,
20
21    JSONValue::Kind::Integer, // IntegerValue,
22    JSONValue::Kind::Float,   // FloatValue,
23    JSONValue::Kind::String,  // StringValue,
24
25    JSONValue::Kind::String, // StringRepresentation
26
27    JSONValue::Kind::Array,  // Array,
28    JSONValue::Kind::Object, // Object,
29};
30
31static bool _isDefault(const RttiInfo* type, const void* in)
32{
33    SLANG_UNUSED(type)
34    const JSONValue& value = *(const JSONValue*)in;
35    return value.getKind() == JSONValue::Kind::Invalid;
36}
37
38static OtherRttiInfo _getJSONValueRttiInfo()
39{
40    OtherRttiInfo info;
41    info.init<JSONValue>(RttiInfo::Kind::Other);
42    info.m_name = "JSONValue";
43    info.m_isDefaultFunc = _isDefault;
44    info.m_typeFuncs = GetRttiTypeFuncs<JSONValue>::getFuncs();
45    return info;
46}
47/* static */ const OtherRttiInfo JSONValue::g_rttiInfo = _getJSONValueRttiInfo();
48
49static JSONKeyValue _makeInvalidKeyValue()
50{
51    JSONKeyValue keyValue;
52    keyValue.key = JSONKey(0);
53    keyValue.value.type = JSONValue::Type::Invalid;
54    return keyValue;
55}
56
57/* static */ JSONKeyValue g_invalid = _makeInvalidKeyValue();
58
59/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
60
61                             JSONValue
62
63!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
64
65bool JSONValue::asBool() const
66{
67    switch (type)
68    {
69    case JSONValue::Type::True:
70        return true;
71    case JSONValue::Type::False:
72    case JSONValue::Type::Null:
73        {
74            return false;
75        }
76    case JSONValue::Type::IntegerValue:
77        return intValue != 0;
78    case JSONValue::Type::FloatValue:
79        return floatValue != 0;
80    default:
81        break;
82    }
83
84    if (isLexeme(type))
85    {
86        SLANG_ASSERT(!"Lexeme values can only be accessed through container");
87    }
88    else
89    {
90        SLANG_ASSERT(!"Not bool convertable");
91    }
92
93    return false;
94}
95
96int64_t JSONValue::asInteger() const
97{
98    switch (type)
99    {
100    case JSONValue::Type::True:
101        return 1;
102    case JSONValue::Type::False:
103    case JSONValue::Type::Null:
104        {
105            return 0;
106        }
107    case JSONValue::Type::IntegerValue:
108        return intValue;
109    case JSONValue::Type::FloatValue:
110        return int64_t(floatValue);
111        break;
112    }
113
114    if (isLexeme(type))
115    {
116        SLANG_ASSERT(!"Lexeme values can only be accessed through container");
117    }
118    else
119    {
120        SLANG_ASSERT(!"Not int convertable");
121    }
122
123    return 0;
124}
125
126double JSONValue::asFloat() const
127{
128    switch (type)
129    {
130    case JSONValue::Type::True:
131        return 1.0;
132    case JSONValue::Type::False:
133    case JSONValue::Type::Null:
134        {
135            return 0.0;
136        }
137    case JSONValue::Type::IntegerValue:
138        return double(intValue);
139    case JSONValue::Type::FloatValue:
140        return floatValue;
141    default:
142        break;
143    }
144
145    if (isLexeme(type))
146    {
147        SLANG_ASSERT(!"Lexeme values can only be accessed through container");
148    }
149    else
150    {
151        SLANG_ASSERT(!"Not float convertable");
152    }
153
154    return 0;
155}
156
157/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
158
159                             PersistentJSONValue
160
161!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
162
163PersistentJSONValue::PersistentJSONValue(const ThisType& rhs)
164{
165    *(JSONValue*)this = rhs;
166
167    if (type == Type::StringRepresentation && stringRep)
168    {
169        stringRep->addReference();
170    }
171}
172
173void PersistentJSONValue::operator=(const ThisType& rhs)
174{
175    if (this != &rhs)
176    {
177        if (rhs.type == Type::StringRepresentation && rhs.stringRep)
178        {
179            rhs.stringRep->addReference();
180        }
181        if (type == Type::StringRepresentation && stringRep)
182        {
183            stringRep->releaseReference();
184        }
185        *(JSONValue*)this = rhs;
186    }
187}
188
189String PersistentJSONValue::getString() const
190{
191    if (type == Type::StringRepresentation)
192    {
193        return String(stringRep);
194    }
195    SLANG_ASSERT(!"Not a string type");
196    return String();
197}
198
199UnownedStringSlice PersistentJSONValue::getSlice() const
200{
201    if (type == Type::StringRepresentation)
202    {
203        return StringRepresentation::asSlice(stringRep);
204    }
205    SLANG_ASSERT(!"Not a string type");
206    return UnownedStringSlice();
207}
208
209void PersistentJSONValue::set(const UnownedStringSlice& slice, SourceLoc inLoc)
210{
211    StringRepresentation* oldRep =
212        (type == JSONValue::Type::StringRepresentation) ? stringRep : nullptr;
213
214    type = Type::StringRepresentation;
215    loc = inLoc;
216
217    StringRepresentation* newRep = nullptr;
218
219    const auto sliceLength = slice.getLength();
220
221    // If we have an oldRep that is unique and large enough reuse it
222    if (sliceLength)
223    {
224        if (oldRep && oldRep->isUniquelyReferenced() && sliceLength <= oldRep->capacity)
225        {
226            oldRep->setContents(slice);
227            newRep = oldRep;
228            // We are reusing so make null so not freed
229            oldRep = nullptr;
230        }
231        else
232        {
233            newRep = StringRepresentation::createWithReference(slice);
234        }
235
236        SLANG_ASSERT(newRep->debugGetReferenceCount() >= 1);
237    }
238
239    stringRep = newRep;
240
241    if (oldRep)
242    {
243        oldRep->releaseReference();
244    }
245}
246
247void PersistentJSONValue::_init(const UnownedStringSlice& slice, SourceLoc inLoc)
248{
249    loc = inLoc;
250    type = Type::StringRepresentation;
251    stringRep = StringRepresentation::createWithReference(slice);
252}
253
254bool PersistentJSONValue::operator==(const ThisType& rhs) const
255{
256    if (this == &rhs)
257    {
258        return true;
259    }
260
261    if (type != rhs.type || loc != rhs.loc)
262    {
263        return false;
264    }
265
266    switch (type)
267    {
268    case Type::Invalid:
269    case Type::True:
270    case Type::False:
271    case Type::Null:
272        {
273            // The type is all that needs to be checked
274            return true;
275        }
276    case Type::IntegerValue:
277        return intValue == rhs.intValue;
278    case Type::FloatValue:
279        return floatValue == rhs.floatValue;
280    case Type::StringRepresentation:
281        {
282            if (stringRep == rhs.stringRep)
283            {
284                return true;
285            }
286            auto thisSlice = StringRepresentation::asSlice(stringRep);
287            auto rhsSlice = StringRepresentation::asSlice(rhs.stringRep);
288            return thisSlice == rhsSlice;
289        }
290    default:
291        break;
292    }
293
294    SLANG_ASSERT(!"Not valid Persistent type");
295    return false;
296}
297
298void PersistentJSONValue::_init(const JSONValue& in, JSONContainer* container)
299{
300    // We are assuming this is invalid, so it can't be the same as in
301    SLANG_ASSERT(&in != this);
302
303    switch (in.type)
304    {
305    case Type::StringValue:
306    case Type::StringLexeme:
307        {
308            if (!container)
309            {
310                SLANG_ASSERT(!"Requires container");
311                return;
312            }
313            _init(container->getTransientString(in), in.loc);
314            break;
315        }
316    case Type::StringRepresentation:
317        {
318            *(JSONValue*)this = in;
319            if (stringRep)
320            {
321                stringRep->addReference();
322            }
323            break;
324        }
325    case Type::IntegerLexeme:
326        {
327            type = JSONValue::Type::IntegerValue;
328            intValue = container->asInteger(in);
329            loc = in.loc;
330            break;
331        }
332    case Type::FloatLexeme:
333        {
334            type = JSONValue::Type::FloatValue;
335            floatValue = container->asFloat(in);
336            loc = in.loc;
337            break;
338        }
339    case Type::Array:
340    case Type::Object:
341        {
342            SLANG_ASSERT(!"Not a simple JSON type");
343            break;
344        }
345    default:
346        {
347            *(JSONValue*)this = in;
348            break;
349        }
350    }
351}
352
353void PersistentJSONValue::set(const JSONValue& in, JSONContainer* container)
354{
355    if (&in != this)
356    {
357        if (type == Type::StringRepresentation)
358        {
359            StringRepresentation* oldStringRep = stringRep;
360            _init(in, container);
361            if (oldStringRep)
362            {
363                oldStringRep->releaseReference();
364            }
365        }
366        else
367        {
368            _init(in, container);
369        }
370    }
371}
372
373/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
374
375                             JSONContainer
376
377!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
378
379JSONContainer::JSONContainer(SourceManager* sourceManager)
380    : m_slicePool(StringSlicePool::Style::Default), m_sourceManager(sourceManager)
381{
382    // Index 0 is the empty array or object
383    _addRange(Range::Type::None, 0, 0);
384}
385
386void JSONContainer::reset()
387{
388    m_slicePool.clear();
389
390    m_freeRangeIndices.clear();
391    m_arrayValues.clear();
392    m_objectValues.clear();
393
394    _addRange(Range::Type::None, 0, 0);
395
396    m_currentView = nullptr;
397}
398
399/* static */ bool JSONContainer::areKeysUnique(const JSONKeyValue* keyValues, Index keyValueCount)
400{
401    for (Index i = 1; i < keyValueCount; ++i)
402    {
403        const JSONKey key = keyValues[i].key;
404
405        for (Int j = 0; j < i - 1; j++)
406        {
407            if (keyValues[j].key == key)
408            {
409                return false;
410            }
411        }
412    }
413
414    return true;
415}
416
417Index JSONContainer::_addRange(Range::Type type, Index startIndex, Index count)
418{
419    if (m_freeRangeIndices.getCount() > 0)
420    {
421        const Index rangeIndex = m_freeRangeIndices.getLast();
422        m_freeRangeIndices.removeLast();
423
424        auto& range = m_ranges[rangeIndex];
425        range.type = type;
426        range.startIndex = startIndex;
427        range.count = count;
428        range.capacity = count;
429
430        return rangeIndex;
431    }
432    else
433    {
434        Range range;
435        range.type = type;
436        range.startIndex = startIndex;
437        range.count = count;
438        range.capacity = count;
439
440        m_ranges.add(range);
441        return m_ranges.getCount() - 1;
442    }
443}
444
445JSONValue JSONContainer::createArray(const JSONValue* values, Index valuesCount, SourceLoc loc)
446{
447    if (valuesCount <= 0)
448    {
449        return JSONValue::makeEmptyArray(loc);
450    }
451
452    JSONValue value;
453    value.type = JSONValue::Type::Array;
454    value.loc = loc;
455    value.rangeIndex = _addRange(Range::Type::Array, m_arrayValues.getCount(), valuesCount);
456
457    m_arrayValues.addRange(values, valuesCount);
458    return value;
459}
460
461JSONValue JSONContainer::createObject(
462    const JSONKeyValue* keyValues,
463    Index keyValueCount,
464    SourceLoc loc)
465{
466    if (keyValueCount <= 0)
467    {
468        return JSONValue::makeEmptyObject(loc);
469    }
470
471    JSONValue value;
472    value.type = JSONValue::Type::Object;
473    value.loc = loc;
474    value.rangeIndex = _addRange(Range::Type::Object, m_objectValues.getCount(), keyValueCount);
475
476    m_objectValues.addRange(keyValues, keyValueCount);
477    return value;
478}
479
480JSONValue JSONContainer::createString(const UnownedStringSlice& slice, SourceLoc loc)
481{
482    JSONValue value;
483    value.type = JSONValue::Type::StringValue;
484    value.loc = loc;
485    value.stringKey = getKey(slice);
486    return value;
487}
488
489JSONKey JSONContainer::getKey(const UnownedStringSlice& slice)
490{
491    return JSONKey(m_slicePool.add(slice));
492}
493
494JSONKey JSONContainer::findKey(const UnownedStringSlice& slice) const
495{
496    const Index index = m_slicePool.findIndex(slice);
497    return (index < 0) ? JSONKey(0) : JSONKey(index);
498}
499
500ConstArrayView<JSONValue> JSONContainer::getArray(const JSONValue& in) const
501{
502    SLANG_ASSERT(in.type == JSONValue::Type::Array);
503    if (in.type != JSONValue::Type::Array || in.rangeIndex == 0)
504    {
505        return ConstArrayView<JSONValue>((const JSONValue*)nullptr, 0);
506    }
507    const Range& range = m_ranges[in.rangeIndex];
508    return ConstArrayView<JSONValue>(m_arrayValues.getBuffer() + range.startIndex, range.count);
509}
510
511ConstArrayView<JSONKeyValue> JSONContainer::getObject(const JSONValue& in) const
512{
513    SLANG_ASSERT(in.type == JSONValue::Type::Object);
514    if (in.type != JSONValue::Type::Object || in.rangeIndex == 0)
515    {
516        return ConstArrayView<JSONKeyValue>((const JSONKeyValue*)nullptr, 0);
517    }
518
519    const Range& range = m_ranges[in.rangeIndex];
520    return ConstArrayView<JSONKeyValue>(m_objectValues.getBuffer() + range.startIndex, range.count);
521}
522
523ArrayView<JSONValue> JSONContainer::getArray(const JSONValue& in)
524{
525    SLANG_ASSERT(in.type == JSONValue::Type::Array);
526    if (in.type != JSONValue::Type::Array || in.rangeIndex == 0)
527    {
528        return ArrayView<JSONValue>((JSONValue*)nullptr, 0);
529    }
530    const Range& range = m_ranges[in.rangeIndex];
531    SLANG_ASSERT(
532        range.startIndex <= m_arrayValues.getCount() &&
533        range.startIndex + range.count <= m_arrayValues.getCount());
534
535    return ArrayView<JSONValue>(m_arrayValues.getBuffer() + range.startIndex, range.count);
536}
537
538ArrayView<JSONKeyValue> JSONContainer::getObject(const JSONValue& in)
539{
540    SLANG_ASSERT(in.type == JSONValue::Type::Object);
541    if (in.type != JSONValue::Type::Object || in.rangeIndex == 0)
542    {
543        return ArrayView<JSONKeyValue>((JSONKeyValue*)nullptr, 0);
544    }
545
546    const Range& range = m_ranges[in.rangeIndex];
547    return ArrayView<JSONKeyValue>(m_objectValues.getBuffer() + range.startIndex, range.count);
548}
549
550UnownedStringSlice JSONContainer::getLexeme(const JSONValue& in)
551{
552    SLANG_ASSERT(JSONValue::isLexeme(in.type));
553    if (!JSONValue::isLexeme(in.type))
554    {
555        return UnownedStringSlice();
556    }
557
558    if (!(m_currentView && m_currentView->getRange().contains(in.loc)))
559    {
560        m_currentView = m_sourceManager->findSourceView(in.loc);
561        if (!m_currentView)
562        {
563            return UnownedStringSlice();
564        }
565    }
566
567    const auto offset = m_currentView->getRange().getOffset(in.loc);
568    SourceFile* sourceFile = m_currentView->getSourceFile();
569
570    return UnownedStringSlice(sourceFile->getContent().begin() + offset, in.length);
571}
572
573UnownedStringSlice JSONContainer::getString(const JSONValue& in)
574{
575    switch (in.type)
576    {
577    case JSONValue::Type::StringValue:
578        {
579            return getStringFromKey(in.stringKey);
580        }
581    case JSONValue::Type::StringLexeme:
582        {
583            auto slice = getTransientString(in);
584            auto handle = m_slicePool.add(slice);
585            return m_slicePool.getSlice(handle);
586        }
587    case JSONValue::Type::StringRepresentation:
588        {
589            return StringRepresentation::asSlice(in.stringRep);
590        }
591    case JSONValue::Type::Null:
592        {
593            return UnownedStringSlice();
594        }
595    default:
596        break;
597    }
598
599    SLANG_ASSERT(!"Not a string type");
600    return UnownedStringSlice();
601}
602
603UnownedStringSlice JSONContainer::getTransientString(const JSONValue& in)
604{
605    switch (in.type)
606    {
607    case JSONValue::Type::StringRepresentation:
608        {
609            return StringRepresentation::asSlice(in.stringRep);
610        }
611    case JSONValue::Type::StringValue:
612        {
613            return getStringFromKey(in.stringKey);
614        }
615    case JSONValue::Type::StringLexeme:
616        {
617            StringEscapeHandler* handler =
618                StringEscapeUtil::getHandler(StringEscapeUtil::Style::JSON);
619
620            UnownedStringSlice lexeme = getLexeme(in);
621            UnownedStringSlice unquoted = StringEscapeUtil::unquote(handler, lexeme);
622
623            if (handler->isUnescapingNeeeded(unquoted))
624            {
625                m_buf.clear();
626                handler->appendUnescaped(unquoted, m_buf);
627                return m_buf.getUnownedSlice();
628            }
629            else
630            {
631                return unquoted;
632            }
633        }
634    case JSONValue::Type::Null:
635        {
636            return UnownedStringSlice();
637        }
638    }
639
640    SLANG_ASSERT(!"Not a string type");
641    return UnownedStringSlice();
642}
643
644JSONKey JSONContainer::getStringKey(const JSONValue& in)
645{
646    return (in.type == JSONValue::Type::StringValue) ? in.stringKey
647                                                     : getKey(getTransientString(in));
648}
649
650bool JSONContainer::asBool(const JSONValue& value)
651{
652    switch (value.type)
653    {
654    case JSONValue::Type::IntegerLexeme:
655        return asInteger(value) != 0;
656    case JSONValue::Type::FloatLexeme:
657        return asFloat(value) != 0.0;
658    case JSONValue::Type::StringLexeme:
659        return getTransientString(value).caseInsensitiveEquals(toSlice("true")) ||
660               getTransientString(value).caseInsensitiveEquals(toSlice("1"));
661    default:
662        return value.asBool();
663    }
664}
665
666JSONValue JSONContainer::asValue(const JSONValue& inValue)
667{
668    JSONValue value = inValue;
669    switch (value.type)
670    {
671    case JSONValue::Type::StringLexeme:
672        {
673            const UnownedStringSlice slice = getTransientString(inValue);
674            value.stringKey = getKey(slice);
675            value.type = JSONValue::Type::StringValue;
676            break;
677        }
678    case JSONValue::Type::IntegerLexeme:
679        {
680            value.floatValue = value.asFloat();
681            value.type = JSONValue::Type::IntegerValue;
682            break;
683        }
684    case JSONValue::Type::FloatLexeme:
685        {
686            value.floatValue = value.asFloat();
687            value.type = JSONValue::Type::FloatValue;
688            break;
689        }
690    default:
691        break;
692    }
693
694    return value;
695}
696
697void JSONContainer::_clearSourceManagerDependency(JSONValue* ioValues, Index count)
698{
699    for (Index i = 0; i < count; ++i)
700    {
701        auto& value = ioValues[i];
702        value = asValue(value);
703        value.loc = SourceLoc();
704    }
705}
706
707void JSONContainer::clearSourceManagerDependency(JSONValue* ioValues, Index valuesCount)
708{
709    _clearSourceManagerDependency(ioValues, valuesCount);
710
711    // We need to find ranges that are available
712    for (auto& range : m_ranges)
713    {
714        switch (range.type)
715        {
716        case Range::Type::Array:
717            {
718                _clearSourceManagerDependency(
719                    m_arrayValues.getBuffer() + range.startIndex,
720                    range.count);
721                break;
722            }
723        case Range::Type::Object:
724            {
725                const Index count = range.count;
726                auto pairs = m_objectValues.getBuffer() + range.startIndex;
727
728                for (Index i = 0; i < count; ++i)
729                {
730                    auto& pair = pairs[i];
731                    pair.keyLoc = SourceLoc();
732                    pair.value = asValue(pair.value);
733                    pair.value.loc = SourceLoc();
734                }
735                break;
736            }
737        default:
738            break;
739        }
740    }
741
742    // Remove the source manager
743    m_sourceManager = nullptr;
744}
745
746int64_t JSONContainer::asInteger(const JSONValue& value)
747{
748    switch (value.type)
749    {
750    case JSONValue::Type::IntegerLexeme:
751        {
752            UnownedStringSlice slice = getLexeme(value);
753            int64_t intValue;
754            if (SLANG_SUCCEEDED(StringUtil::parseInt64(slice, intValue)))
755            {
756                return intValue;
757            }
758            SLANG_ASSERT(!"Couldn't convert int");
759            return 0;
760        }
761    case JSONValue::Type::FloatLexeme:
762        return int64_t(asFloat(value));
763    default:
764        return value.asInteger();
765    }
766}
767
768double JSONContainer::asFloat(const JSONValue& value)
769{
770    switch (value.type)
771    {
772    case JSONValue::Type::IntegerLexeme:
773        return double(asInteger(value));
774    case JSONValue::Type::FloatLexeme:
775        {
776            UnownedStringSlice slice = getLexeme(value);
777            double floatValue;
778            if (SLANG_SUCCEEDED(StringUtil::parseDouble(slice, floatValue)))
779            {
780                return floatValue;
781            }
782            SLANG_ASSERT(!"Couldn't convert double");
783            return 0.0;
784        }
785    default:
786        return value.asFloat();
787    }
788}
789
790Index JSONContainer::findObjectIndex(const JSONValue& obj, JSONKey key) const
791{
792    auto pairs = getObject(obj);
793    return pairs.findFirstIndex(
794        [key](const JSONKeyValue& pair) -> bool { return pair.key == key; });
795}
796
797JSONValue JSONContainer::findObjectValue(const JSONValue& obj, JSONKey key) const
798{
799    auto pairs = getObject(obj);
800    const Index index =
801        pairs.findFirstIndex([key](const JSONKeyValue& pair) -> bool { return pair.key == key; });
802    return (index >= 0) ? pairs[index].value : JSONValue::makeInvalid();
803}
804
805JSONValue& JSONContainer::getAt(const JSONValue& array, Index index)
806{
807    SLANG_ASSERT(array.type == JSONValue::Type::Array);
808    const Range& range = m_ranges[array.rangeIndex];
809
810    SLANG_ASSERT(index >= 0 && index < range.count);
811    return m_arrayValues[range.startIndex + index];
812}
813
814void JSONContainer::addToArray(JSONValue& array, const JSONValue& value)
815{
816    SLANG_ASSERT(array.type == JSONValue::Type::Array);
817    if (array.type == JSONValue::Type::Array)
818    {
819        // If it's empty
820        if (array.rangeIndex == 0)
821        {
822            // We can just add to the end
823            array.rangeIndex = _addRange(Range::Type::Array, m_arrayValues.getCount(), 1);
824            m_arrayValues.add(value);
825        }
826        else
827        {
828            _add(m_ranges[array.rangeIndex], m_arrayValues, value);
829        }
830    }
831}
832
833Index JSONContainer::findKeyGlobalIndex(const JSONValue& obj, JSONKey key)
834{
835    SLANG_ASSERT(obj.type == JSONValue::Type::Object);
836    if (obj.type != JSONValue::Type::Object)
837    {
838        return -1;
839    }
840
841    auto buf = m_objectValues.getBuffer();
842
843    const Range& range = m_ranges[obj.rangeIndex];
844    for (Index i = range.startIndex; i < range.startIndex + range.count; ++i)
845    {
846        if (buf[i].key == key)
847        {
848            return i;
849        }
850    }
851
852    return -1;
853}
854
855Index JSONContainer::findKeyGlobalIndex(const JSONValue& obj, const UnownedStringSlice& slice)
856{
857    Index keyIndex = m_slicePool.findIndex(slice);
858    if (keyIndex < 0)
859    {
860        return -1;
861    }
862
863    return findKeyGlobalIndex(obj, JSONKey(keyIndex));
864}
865
866void JSONContainer::_removeKey(JSONValue& obj, Index globalIndex)
867{
868    Range& range = m_ranges[obj.rangeIndex];
869    const auto localIndex = globalIndex + range.startIndex;
870
871    if (localIndex < range.count - 1)
872    {
873        auto localBuf = m_objectValues.getBuffer() + range.startIndex;
874        ::memmove(
875            (void*)(localBuf + localIndex),
876            (void*)(localBuf + localIndex + 1),
877            sizeof(*localBuf) * (range.count - (localIndex + 1)));
878    }
879
880    --range.count;
881}
882
883bool JSONContainer::removeKey(JSONValue& obj, JSONKey key)
884{
885    const Index globalIndex = findKeyGlobalIndex(obj, key);
886    if (globalIndex >= 0)
887    {
888        _removeKey(obj, globalIndex);
889        return true;
890    }
891    return false;
892}
893
894bool JSONContainer::removeKey(JSONValue& obj, const UnownedStringSlice& slice)
895{
896    const Index globalIndex = findKeyGlobalIndex(obj, slice);
897    if (globalIndex >= 0)
898    {
899        _removeKey(obj, globalIndex);
900        return true;
901    }
902    return false;
903}
904
905template<typename T>
906/* static */ void JSONContainer::_add(Range& ioRange, List<T>& ioList, const T& value)
907{
908    // If we have capacity, we can add to the end
909    if (ioRange.count < ioRange.capacity)
910    {
911        ioList[ioRange.startIndex + ioRange.count++] = value;
912        return;
913    }
914
915    // If we are at the end, we can just add
916    if (ioRange.startIndex + ioRange.capacity == ioList.getCount())
917    {
918        ioList.add(value);
919        ioRange.capacity++;
920        ioRange.count++;
921        return;
922    }
923
924    // Okay we have no choice but to make new space at the end
925    // So there's no place to add. We want to move to the end with an extra space.
926
927    const Index newStartIndex = ioList.getCount();
928    ioList.growToCount(newStartIndex + ioRange.count + 1);
929
930    auto buffer = ioList.getBuffer();
931    ::memmove(
932        (void*)(buffer + newStartIndex),
933        (void*)(buffer + ioRange.startIndex),
934        sizeof(*buffer) * ioRange.count);
935
936    buffer[newStartIndex + ioRange.count] = value;
937
938    ioRange.startIndex = newStartIndex;
939    ioRange.count++;
940    ioRange.capacity++;
941}
942
943
944void JSONContainer::setKeyValue(JSONValue& obj, JSONKey key, const JSONValue& value, SourceLoc loc)
945{
946    SLANG_ASSERT(obj.type == JSONValue::Type::Object);
947    if (obj.type != JSONValue::Type::Object)
948    {
949        return;
950    }
951
952    const JSONKeyValue keyValue{key, loc, value};
953    if (obj.rangeIndex == 0)
954    {
955        // We need a new range and add to the end
956        obj.rangeIndex = _addRange(Range::Type::Object, m_objectValues.getCount(), 1);
957        m_objectValues.add(keyValue);
958        return;
959    }
960
961    const Index globalIndex = findKeyGlobalIndex(obj, key);
962    if (globalIndex >= 0)
963    {
964        auto& dst = m_objectValues[globalIndex];
965        SLANG_ASSERT(dst.key == key);
966        dst = keyValue;
967        return;
968    }
969
970    Range& range = m_ranges[obj.rangeIndex];
971    _add(range, m_objectValues, keyValue);
972}
973
974void JSONContainer::_destroyRange(Index rangeIndex)
975{
976    auto& range = m_ranges[rangeIndex];
977
978    // If the range is at the end, shrink it
979    switch (range.type)
980    {
981    case Range::Type::Array:
982        {
983            if (range.startIndex + range.capacity == m_arrayValues.getCount())
984            {
985                m_arrayValues.setCount(range.startIndex);
986            }
987            break;
988        }
989    case Range::Type::Object:
990        {
991            if (range.startIndex + range.capacity == m_objectValues.getCount())
992            {
993                m_objectValues.setCount(range.startIndex);
994            }
995            break;
996        }
997    default:
998        break;
999    }
1000
1001    range.type = Range::Type::Destroyed;
1002    m_freeRangeIndices.add(rangeIndex);
1003}
1004
1005void JSONContainer::destroy(JSONValue& value)
1006{
1007    if (value.needsDestroy())
1008    {
1009        _destroyRange(value.rangeIndex);
1010    }
1011    value.type = JSONValue::Type::Invalid;
1012}
1013
1014void JSONContainer::destroyRecursively(JSONValue& inValue)
1015{
1016    if (!(inValue.needsDestroy() && m_ranges[inValue.rangeIndex].isActive()))
1017    {
1018        inValue.type = JSONValue::Type::Invalid;
1019        return;
1020    }
1021
1022    inValue.type = JSONValue::Type::Invalid;
1023
1024    List<Range> activeRanges;
1025
1026    activeRanges.add(m_ranges[inValue.rangeIndex]);
1027    _destroyRange(inValue.rangeIndex);
1028
1029    while (activeRanges.getCount())
1030    {
1031        const Range range = activeRanges.getLast();
1032        activeRanges.removeLast();
1033
1034        auto type = range.type;
1035        const Index count = range.count;
1036
1037        if (type == Range::Type::Array)
1038        {
1039            auto* buf = m_arrayValues.getBuffer() + range.startIndex;
1040
1041            for (Index i = 0; i < count; ++i)
1042            {
1043                auto& value = buf[i];
1044                // If we have an active range, add to work list, and destroy
1045                if (value.needsDestroy() && m_ranges[value.rangeIndex].isActive())
1046                {
1047                    activeRanges.add(m_ranges[value.rangeIndex]);
1048                    _destroyRange(value.rangeIndex);
1049                }
1050                value.type = JSONValue::Type::Invalid;
1051            }
1052        }
1053        else
1054        {
1055            SLANG_ASSERT(type == Range::Type::Object);
1056
1057            auto* buf = m_objectValues.getBuffer() + range.startIndex;
1058
1059            for (Index i = 0; i < count; ++i)
1060            {
1061                auto& keyValue = buf[i];
1062                auto& value = keyValue.value;
1063                // We want to mark that it's in the list so that if we have a badly formed tree we
1064                // don't read
1065                if (value.needsDestroy() && m_ranges[value.rangeIndex].isActive())
1066                {
1067                    activeRanges.add(m_ranges[value.rangeIndex]);
1068                    _destroyRange(value.rangeIndex);
1069                }
1070                value.type = JSONValue::Type::Invalid;
1071            }
1072        }
1073    }
1074}
1075
1076bool JSONContainer::areEqual(const JSONValue* a, const JSONValue* b, Index count)
1077{
1078    for (Index i = 0; i < count; ++i)
1079    {
1080        if (!areEqual(a[i], b[i]))
1081        {
1082            return false;
1083        }
1084    }
1085
1086    return true;
1087}
1088
1089
1090/* static */ bool JSONContainer::_sameKeyOrder(
1091    const JSONKeyValue* a,
1092    const JSONKeyValue* b,
1093    Index count)
1094{
1095    for (Index i = 0; i < count; ++i)
1096    {
1097        if (a[i].key != b[i].key)
1098        {
1099            return false;
1100        }
1101    }
1102    return true;
1103}
1104
1105bool JSONContainer::_areEqualOrderedKeys(const JSONKeyValue* a, const JSONKeyValue* b, Index count)
1106{
1107    for (Index i = 0; i < count; ++i)
1108    {
1109        const auto& curA = a[i];
1110        const auto& curB = b[i];
1111
1112        if (curA.key != curB.key || !areEqual(curA.value, curB.value))
1113        {
1114            return false;
1115        }
1116    }
1117    return true;
1118}
1119
1120bool JSONContainer::_areEqualValues(const JSONKeyValue* a, const JSONKeyValue* b, Index count)
1121{
1122    for (Index i = 0; i < count; ++i)
1123    {
1124        if (!areEqual(a[i].value, b[i].value))
1125        {
1126            return false;
1127        }
1128    }
1129    return true;
1130}
1131
1132bool JSONContainer::areEqual(const JSONKeyValue* a, const JSONKeyValue* b, Index count)
1133{
1134    if (count == 0)
1135    {
1136        return true;
1137    }
1138
1139    if (count == 1)
1140    {
1141        return _areEqualOrderedKeys(a, b, count);
1142    }
1143    else if (_sameKeyOrder(a, b, count))
1144    {
1145        return _areEqualValues(a, b, count);
1146    }
1147    else
1148    {
1149        // We need to compare with keys in the same order
1150        List<JSONKeyValue> sortedAs;
1151        sortedAs.addRange(a, count);
1152
1153        List<JSONKeyValue> sortedBs;
1154        sortedBs.addRange(b, count);
1155
1156        sortedAs.sort(
1157            [](const JSONKeyValue& a, const JSONKeyValue& b) -> bool { return a.key < b.key; });
1158        sortedBs.sort(
1159            [](const JSONKeyValue& a, const JSONKeyValue& b) -> bool { return a.key < b.key; });
1160
1161        return _areEqualOrderedKeys(sortedAs.getBuffer(), sortedBs.getBuffer(), count);
1162    }
1163}
1164
1165bool JSONContainer::areEqual(const JSONValue& a, const UnownedStringSlice& slice)
1166{
1167    return a.getKind() == JSONValue::Kind::String && getTransientString(a) == slice;
1168}
1169
1170bool JSONContainer::areEqual(const JSONValue& a, const JSONValue& b)
1171{
1172    if (&a == &b)
1173    {
1174        return true;
1175    }
1176
1177    if (a.type == b.type)
1178    {
1179        switch (a.type)
1180        {
1181        default:
1182        // Invalid are never equal
1183        case JSONValue::Type::Invalid:
1184            return false;
1185        case JSONValue::Type::True:
1186        case JSONValue::Type::False:
1187        case JSONValue::Type::Null:
1188            {
1189                return true;
1190            }
1191        case JSONValue::Type::IntegerLexeme:
1192            return asInteger(a) == asInteger(b);
1193        case JSONValue::Type::FloatLexeme:
1194            return asFloat(a) == asFloat(b);
1195        case JSONValue::Type::StringLexeme:
1196            {
1197                // If the lexemes are equal they are equal
1198                UnownedStringSlice lexemeA = getLexeme(a);
1199                UnownedStringSlice lexemeB = getLexeme(b);
1200                // Else we want to decode the string to be sure if they are equal.
1201                return lexemeA == lexemeB || getStringKey(a) == getStringKey(b);
1202            }
1203        case JSONValue::Type::IntegerValue:
1204            return a.intValue == b.intValue;
1205        case JSONValue::Type::FloatValue:
1206            return a.floatValue == b.floatValue;
1207        case JSONValue::Type::StringValue:
1208            return a.stringKey == b.stringKey;
1209        case JSONValue::Type::StringRepresentation:
1210            {
1211                return a.stringRep == b.stringRep || StringRepresentation::asSlice(a.stringRep) ==
1212                                                         StringRepresentation::asSlice(b.stringRep);
1213            }
1214        case JSONValue::Type::Array:
1215            {
1216                if (a.rangeIndex == b.rangeIndex)
1217                {
1218                    return true;
1219                }
1220                auto arrayA = getArray(a);
1221                auto arrayB = getArray(b);
1222
1223                const Index count = arrayA.getCount();
1224                return (count == arrayB.getCount()) &&
1225                       areEqual(arrayA.getBuffer(), arrayB.getBuffer(), count);
1226            }
1227        case JSONValue::Type::Object:
1228            {
1229                if (a.rangeIndex == b.rangeIndex)
1230                {
1231                    return true;
1232                }
1233                const auto aValues = getObject(a);
1234                const auto bValues = getObject(b);
1235
1236                const Index count = aValues.getCount();
1237                return (count == bValues.getCount()) &&
1238                       areEqual(aValues.getBuffer(), bValues.getBuffer(), count);
1239            }
1240        }
1241    }
1242
1243    // If they are the same kind, and float/int/string we can convert to compare
1244    const JSONValue::Kind kind = a.getKind();
1245    if (kind == b.getKind())
1246    {
1247        switch (kind)
1248        {
1249        case JSONValue::Kind::String:
1250            return getStringKey(a) == getStringKey(b);
1251        case JSONValue::Kind::Integer:
1252            return asInteger(a) == asInteger(b);
1253        case JSONValue::Kind::Float:
1254            return asFloat(a) == asFloat(b);
1255        default:
1256            break;
1257        }
1258    }
1259
1260    return false;
1261}
1262
1263void JSONContainer::traverseRecursively(const JSONValue& value, JSONListener* listener)
1264{
1265    typedef JSONValue::Type Type;
1266
1267    switch (value.type)
1268    {
1269    case Type::True:
1270        return listener->addBoolValue(true, value.loc);
1271    case Type::False:
1272        return listener->addBoolValue(false, value.loc);
1273    case Type::Null:
1274        return listener->addNullValue(value.loc);
1275
1276    case Type::StringLexeme:
1277        return listener->addLexemeValue(JSONTokenType::StringLiteral, getLexeme(value), value.loc);
1278    case Type::IntegerLexeme:
1279        return listener->addLexemeValue(JSONTokenType::IntegerLiteral, getLexeme(value), value.loc);
1280    case Type::FloatLexeme:
1281        return listener->addLexemeValue(JSONTokenType::FloatLiteral, getLexeme(value), value.loc);
1282
1283    case Type::IntegerValue:
1284        return listener->addIntegerValue(value.intValue, value.loc);
1285    case Type::FloatValue:
1286        return listener->addFloatValue(value.floatValue, value.loc);
1287    case Type::StringValue:
1288        {
1289            const auto slice = getStringFromKey(value.stringKey);
1290            return listener->addStringValue(slice, value.loc);
1291        }
1292    case Type::StringRepresentation:
1293        {
1294            return listener->addStringValue(getTransientString(value), value.loc);
1295        }
1296    case Type::Array:
1297        {
1298            listener->startArray(value.loc);
1299
1300            const auto arr = getArray(value);
1301
1302            for (const auto& arrayValue : arr)
1303            {
1304                traverseRecursively(arrayValue, listener);
1305            }
1306
1307            listener->endArray(SourceLoc());
1308            break;
1309        }
1310    case Type::Object:
1311        {
1312            listener->startObject(value.loc);
1313
1314            const auto obj = getObject(value);
1315
1316            for (const auto& objKeyValue : obj)
1317            {
1318                // Emit the key
1319                const auto keyString = getStringFromKey(objKeyValue.key);
1320                listener->addUnquotedKey(keyString, objKeyValue.keyLoc);
1321
1322                // Emit the value associated with the key
1323                traverseRecursively(objKeyValue.value, listener);
1324            }
1325
1326            listener->endObject(SourceLoc());
1327            break;
1328        }
1329    default:
1330        {
1331            SLANG_ASSERT(!"Invalid type");
1332            return;
1333        }
1334    }
1335}
1336
1337/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
1338
1339                          JSONBuilder
1340
1341!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
1342
1343JSONBuilder::JSONBuilder(JSONContainer* container, Flags flags)
1344    : m_container(container), m_flags(flags)
1345{
1346    m_state.m_kind = State::Kind::Root;
1347    m_state.m_startIndex = 0;
1348    m_state.resetKey();
1349
1350    m_rootValue.reset();
1351}
1352
1353void JSONBuilder::reset()
1354{
1355    // Reset the state
1356    m_state.m_kind = State::Kind::Root;
1357    m_state.m_startIndex = 0;
1358    m_state.resetKey();
1359
1360    // Clear the work values
1361    m_rootValue.reset();
1362
1363    // Clear the lists
1364    m_stateStack.clear();
1365    m_values.clear();
1366    m_keyValues.clear();
1367}
1368
1369void JSONBuilder::_popState()
1370{
1371    SLANG_ASSERT(m_stateStack.getCount() > 0);
1372
1373    // Reset the end depending on typpe
1374    switch (m_state.m_kind)
1375    {
1376    case State::Kind::Array:
1377        {
1378            m_values.setCount(m_state.m_startIndex);
1379            break;
1380        }
1381    case State::Kind::Object:
1382        {
1383            m_keyValues.setCount(m_state.m_startIndex);
1384            break;
1385        }
1386    }
1387
1388    // Pop from the stack
1389    m_state = m_stateStack.getLast();
1390    m_stateStack.removeLast();
1391}
1392
1393Index JSONBuilder::_findKeyIndex(JSONKey key) const
1394{
1395    SLANG_ASSERT(m_state.m_kind == State::Kind::Object);
1396    const Index count = m_keyValues.getCount();
1397    for (Index i = m_state.m_startIndex; i < count; ++i)
1398    {
1399        auto& keyValue = m_keyValues[i];
1400        // If we find the key return it's index
1401        if (keyValue.key == key)
1402        {
1403            return i;
1404        }
1405    }
1406    return -1;
1407}
1408
1409void JSONBuilder::_add(const JSONValue& value)
1410{
1411    SLANG_ASSERT(value.isValid());
1412    switch (m_state.m_kind)
1413    {
1414    case State::Kind::Root:
1415        {
1416            SLANG_ASSERT(!m_rootValue.isValid());
1417            m_rootValue = value;
1418            break;
1419        }
1420    case State::Kind::Array:
1421        {
1422            m_values.add(value);
1423            break;
1424        }
1425    case State::Kind::Object:
1426        {
1427            SLANG_ASSERT(m_state.hasKey());
1428
1429            JSONKeyValue keyValue;
1430            keyValue.key = m_state.m_key;
1431            keyValue.keyLoc = m_state.m_keyLoc;
1432            keyValue.value = value;
1433
1434            const Index index = _findKeyIndex(keyValue.key);
1435            if (index >= 0)
1436            {
1437                m_keyValues[index] = keyValue;
1438            }
1439            else
1440            {
1441                m_keyValues.add(keyValue);
1442            }
1443
1444            m_state.resetKey();
1445            break;
1446        }
1447    }
1448}
1449
1450void JSONBuilder::startObject(SourceLoc loc)
1451{
1452    m_stateStack.add(m_state);
1453    m_state.m_kind = State::Kind::Object;
1454    m_state.m_startIndex = m_keyValues.getCount();
1455    m_state.m_loc = loc;
1456    m_state.resetKey();
1457}
1458
1459void JSONBuilder::endObject(SourceLoc loc)
1460{
1461    SLANG_UNUSED(loc);
1462
1463    SLANG_ASSERT(m_state.m_kind == State::Kind::Object);
1464
1465    const Index count = m_keyValues.getCount() - m_state.m_startIndex;
1466    const JSONValue value = m_container->createObject(
1467        m_keyValues.getBuffer() + m_state.m_startIndex,
1468        count,
1469        m_state.m_loc);
1470
1471    // Pop current state
1472    _popState();
1473    // Add the value to the current state
1474    _add(value);
1475}
1476
1477void JSONBuilder::startArray(SourceLoc loc)
1478{
1479    m_stateStack.add(m_state);
1480    m_state.m_kind = State::Kind::Array;
1481    m_state.m_startIndex = m_values.getCount();
1482    m_state.m_loc = loc;
1483    m_state.resetKey();
1484}
1485
1486void JSONBuilder::endArray(SourceLoc loc)
1487{
1488    SLANG_UNUSED(loc);
1489
1490    SLANG_ASSERT(m_state.m_kind == State::Kind::Array);
1491
1492    const Index count = m_values.getCount() - m_state.m_startIndex;
1493    const JSONValue value =
1494        m_container->createArray(m_values.getBuffer() + m_state.m_startIndex, count, m_state.m_loc);
1495
1496    // Pop current state
1497    _popState();
1498    // Add the value to the current state
1499    _add(value);
1500}
1501
1502void JSONBuilder::addQuotedKey(const UnownedStringSlice& key, SourceLoc loc)
1503{
1504    // We need to decode
1505    m_work.clear();
1506    StringEscapeHandler* handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::JSON);
1507    StringEscapeUtil::appendUnquoted(handler, key, m_work);
1508    addUnquotedKey(m_work.getUnownedSlice(), loc);
1509}
1510
1511void JSONBuilder::addUnquotedKey(const UnownedStringSlice& key, SourceLoc loc)
1512{
1513    SLANG_ASSERT(!m_state.hasKey());
1514    m_state.setKey(m_container->getKey(key), loc);
1515}
1516
1517void JSONBuilder::addLexemeValue(JSONTokenType type, const UnownedStringSlice& value, SourceLoc loc)
1518{
1519    switch (type)
1520    {
1521    case JSONTokenType::True:
1522        return _add(JSONValue::makeBool(true, loc));
1523    case JSONTokenType::False:
1524        return _add(JSONValue::makeBool(false, loc));
1525    case JSONTokenType::Null:
1526        return _add(JSONValue::makeNull(loc));
1527
1528    case JSONTokenType::IntegerLiteral:
1529        {
1530            if (m_flags & Flag::ConvertLexemes)
1531            {
1532                int64_t intValue = -1;
1533                auto res = StringUtil::parseInt64(value, intValue);
1534                SLANG_UNUSED(res);
1535                SLANG_ASSERT(SLANG_SUCCEEDED(res));
1536                _add(JSONValue::makeInt(intValue, loc));
1537            }
1538            else
1539            {
1540                SLANG_ASSERT(loc.isValid());
1541                _add(JSONValue::makeLexeme(JSONValue::Type::IntegerLexeme, loc, value.getLength()));
1542            }
1543            break;
1544        }
1545    case JSONTokenType::FloatLiteral:
1546        {
1547            if (m_flags & Flag::ConvertLexemes)
1548            {
1549                double floatValue = 0;
1550                auto res = StringUtil::parseDouble(value, floatValue);
1551                SLANG_UNUSED(res);
1552                SLANG_ASSERT(SLANG_SUCCEEDED(res));
1553                _add(JSONValue::makeFloat(floatValue, loc));
1554            }
1555            else
1556            {
1557                SLANG_ASSERT(loc.isValid());
1558                _add(JSONValue::makeLexeme(JSONValue::Type::FloatLexeme, loc, value.getLength()));
1559            }
1560            break;
1561        }
1562    case JSONTokenType::StringLiteral:
1563        {
1564            if (m_flags & Flag::ConvertLexemes)
1565            {
1566                auto handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::JSON);
1567                StringBuilder buf;
1568                StringEscapeUtil::appendUnquoted(handler, value, buf);
1569
1570                _add(m_container->createString(buf.getUnownedSlice(), loc));
1571            }
1572            else
1573            {
1574                SLANG_ASSERT(loc.isValid());
1575                _add(JSONValue::makeLexeme(JSONValue::Type::StringLexeme, loc, value.getLength()));
1576            }
1577            break;
1578        }
1579    default:
1580        {
1581            SLANG_ASSERT(!"Unhandled type");
1582        }
1583    }
1584}
1585
1586void JSONBuilder::addIntegerValue(int64_t value, SourceLoc loc)
1587{
1588    _add(JSONValue::makeInt(value, loc));
1589}
1590
1591void JSONBuilder::addFloatValue(double value, SourceLoc loc)
1592{
1593    _add(JSONValue::makeFloat(value, loc));
1594}
1595
1596void JSONBuilder::addBoolValue(bool value, SourceLoc loc)
1597{
1598    _add(JSONValue::makeBool(value, loc));
1599}
1600
1601void JSONBuilder::addStringValue(const UnownedStringSlice& slice, SourceLoc loc)
1602{
1603    _add(m_container->createString(slice, loc));
1604}
1605
1606void JSONBuilder::addNullValue(SourceLoc loc)
1607{
1608    _add(JSONValue::makeNull(loc));
1609}
1610
1611} // namespace Slang