summaryrefslogtreecommitdiff
path: root/source/compiler-core/slang-json-value.h
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2021-06-01 16:58:07 -0400
committerGitHub <noreply@github.com>2021-06-01 16:58:07 -0400
commit7a3c87b58de2683c077bd5341052c2e3cebeb048 (patch)
tree8641667ebcfecd728bfe8b572822751fae1c55bd /source/compiler-core/slang-json-value.h
parent67486ee516ddc33806003727682cbfc68ab1f726 (diff)
JSONValue / Container (#1864)
* #include an absolute path didn't work - because paths were taken to always be relative. * WIP JSONWriter/JSONParser. * Checking different Layout styles for JSON. * Add slang-json-parser.h/.cpp * WIP JSONValue. * Added JSONValue::destroy/Recursive. * Improvement to JSONValue. * Improve text double conversion precision. Testing. * Simplify double parsing (just use atof). JSON comparison More testing of conversions and start of JSONValue. * Add <math.h> for isnan, isinf etc. * Small improvement with object comparison. * Fix typo in getArgsByName. * Removed use of isnan and isinf as includes don't work on linux. * Improve JSON unit test. * Added asInteger/asFloat/asBool to JSONValue. * Change comment to trigger CI build.
Diffstat (limited to 'source/compiler-core/slang-json-value.h')
-rw-r--r--source/compiler-core/slang-json-value.h243
1 files changed, 243 insertions, 0 deletions
diff --git a/source/compiler-core/slang-json-value.h b/source/compiler-core/slang-json-value.h
new file mode 100644
index 000000000..48cde5750
--- /dev/null
+++ b/source/compiler-core/slang-json-value.h
@@ -0,0 +1,243 @@
+// slang-json-value.h
+#ifndef SLANG_JSON_VALUE_H
+#define SLANG_JSON_VALUE_H
+
+#include "../core/slang-basic.h"
+
+#include "slang-source-loc.h"
+#include "slang-diagnostic-sink.h"
+
+namespace Slang {
+
+typedef uint32_t JSONKey;
+
+struct JSONValue
+{
+ enum class Kind
+ {
+ Invalid,
+
+ Null,
+
+ Bool,
+ String,
+ Integer,
+ Float,
+
+ Array,
+ Object,
+
+ CountOf,
+ };
+
+ enum class Type
+ {
+ Invalid,
+
+ True,
+ False,
+ Null,
+
+ StringLexeme,
+ IntegerLexeme,
+ FloatLexeme,
+
+ IntegerValue,
+ FloatValue,
+ StringValue,
+
+ Array,
+ Object,
+
+ CountOf,
+ };
+
+ static bool isLexeme(Type type) { return Index(type) >= Index(Type::StringLexeme) && Index(type) <= Index(Type::FloatLexeme); }
+
+ static JSONValue makeInt(int64_t inValue, SourceLoc loc = SourceLoc()) { JSONValue value; value.type = Type::IntegerValue; value.loc = loc; value.intValue = inValue; return value; }
+ static JSONValue makeFloat(double inValue, SourceLoc loc = SourceLoc()) { JSONValue value; value.type = Type::FloatValue; value.loc = loc; value.floatValue = inValue; return value; }
+ static JSONValue makeNull(SourceLoc loc = SourceLoc()) { JSONValue value; value.type = Type::Null; value.loc = loc; return value; }
+ static JSONValue makeBool(bool inValue, SourceLoc loc = SourceLoc()) { JSONValue value; value.type = (inValue ? Type::True : Type::False); value.loc = loc; return value; }
+
+ static JSONValue makeLexeme(Type type, SourceLoc loc, Index length) { SLANG_ASSERT(isLexeme(type)); JSONValue value; value.type = type; value.loc = loc; value.length = length; return value; }
+
+ static JSONValue makeEmptyArray(SourceLoc loc = SourceLoc()) { JSONValue value; value.type = Type::Array; value.loc = loc; value.rangeIndex = 0; return value; }
+ static JSONValue makeEmptyObject(SourceLoc loc = SourceLoc()) { JSONValue value; value.type = Type::Object; value.loc = loc; value.rangeIndex = 0; return value; }
+
+ // The following functions only work if the value is stored directly NOT as a lexeme. Use the methods on the container
+ // to access values if it is potentially stored as a lexeme
+
+ /// As a boolean value
+ bool asBool() const;
+ /// As an integer value
+ int64_t asInteger() const;
+ /// As a float value
+ double asFloat() const;
+
+ /// True if this is a object like (array or object)
+ bool isObjectLike() const { return Index(type) >= Index(Type::Array); }
+
+ /// True if this appears to be a valid value
+ bool isValid() const { return type != JSONValue::Type::Invalid; }
+
+ /// True if needs destroy
+ bool needsDestroy() const { return isObjectLike() && rangeIndex != 0; }
+
+ /// Get the kind
+ SLANG_FORCE_INLINE Kind getKind() const { return getKindForType(type); }
+
+ /// Given a type return the associated kind
+ static Kind getKindForType(Type type) { return g_typeToKind[Index(type)]; }
+
+ Type type; ///< The type of value
+ SourceLoc loc; ///< The (optional) location in source of this value.
+
+ union
+ {
+ Index rangeIndex; ///< Used for Array/Object
+ Index length; ///< Length in bytes if it is a 'Lexeme'
+ double floatValue; ///< Float value
+ int64_t intValue; ///< Integer value
+ JSONKey stringKey; ///< The pool key if it's a string
+ };
+
+ static const Kind g_typeToKind[Index(Type::CountOf)];
+};
+
+struct JSONKeyValue
+{
+ /// True if it's valid
+ bool isValid() const { return value.type != JSONValue::Type::Invalid; }
+
+ JSONKey key;
+ SourceLoc keyLoc;
+ JSONValue value;
+
+ static JSONKeyValue g_invalid;
+};
+
+class JSONContainer : public RefObject
+{
+public:
+
+ /// Make a new array
+ JSONValue createArray(const JSONValue* values, Index valuesCount, SourceLoc loc = SourceLoc());
+ /// Make a new object
+ JSONValue createObject(const JSONKeyValue* keyValues, Index keyValueCount, SourceLoc loc = SourceLoc());
+ /// Make a string
+ JSONValue createString(const UnownedStringSlice& slice, SourceLoc loc = SourceLoc());
+
+ ConstArrayView<JSONValue> getArray(const JSONValue& in) const;
+ ConstArrayView<JSONKeyValue> getObject(const JSONValue& in) const;
+
+ ArrayView<JSONValue> getArray(const JSONValue& in);
+ ArrayView<JSONKeyValue> getObject(const JSONValue& in);
+
+ /// Add value to array.
+ void addToArray(JSONValue& array, const JSONValue& value);
+
+ /// Get the value at the index in the array
+ JSONValue& getAt(const JSONValue& array, Index index);
+
+ /// Returns the index
+ Index findKeyGlobalIndex(const JSONValue& obj, JSONKey key);
+ Index findKeyGlobalIndex(const JSONValue& obj, const UnownedStringSlice& slice);
+
+ /// Set a key value for the obj
+ void setKeyValue(JSONValue& obj, JSONKey key, const JSONValue& value, SourceLoc loc = SourceLoc());
+
+ /// Returns true if found
+ bool removeKey(JSONValue& obj, JSONKey key);
+ bool removeKey(JSONValue& obj, const UnownedStringSlice& slice);
+
+ /// As a boolean value
+ bool asBool(const JSONValue& value);
+ /// As an integer value
+ int64_t asInteger(const JSONValue& value);
+ /// As a float value
+ double asFloat(const JSONValue& value);
+
+ /// Returns string as a key
+ JSONKey getStringKey(const JSONValue& in);
+
+ /// Get as a string.
+ UnownedStringSlice getString(const JSONValue& in);
+
+ /// Gets the lexeme
+ UnownedStringSlice getLexeme(const JSONValue& in);
+
+ /// Get a key for a name
+ JSONKey getKey(const UnownedStringSlice& slice);
+ /// Get the string from the key
+ UnownedStringSlice getStringFromKey(JSONKey key) const { return m_slicePool.getSlice(StringSlicePool::Handle(key)); }
+
+ /// True if they are the same value
+ /// If object like type comparison is performed recursively.
+ /// NOTE! That Float and Integer values do not compare & source locations are ignored.
+ bool areEqual(const JSONValue& a, const JSONValue& b);
+ bool areEqual(const JSONValue* a, const JSONValue* b, Index count);
+ bool areEqual(const JSONKeyValue* a, const JSONKeyValue* b, Index count);
+
+ /// Destroy value
+ void destroy(JSONValue& value);
+ /// Destroy recursively from value
+ void destroyRecursively(JSONValue& value);
+
+ //
+ JSONContainer(SourceManager* sourceManger);
+
+ /// Returns true if all the keys are unique
+ static bool areKeysUnique(const JSONKeyValue* keyValues, Index keyValueCount);
+
+protected:
+ struct Range
+ {
+ // We want to record the underlying range, because we don't track JSONValue, and so we need to know what the range
+ // applies to if we want to reorder, flatten etc.
+ enum class Type
+ {
+ None,
+ Destroyed,
+ Object,
+ Array,
+ };
+
+ /// Is active if it consuming some part of a value list (even if zero count)
+ SLANG_FORCE_INLINE bool isActive() const { return Index(type) >= Index(Type::Object); }
+
+ Type type;
+ Index startIndex;
+ Index count;
+ Index capacity;
+ };
+
+ template <typename T>
+ static void _add(Range& range, List<T>& list, const T& value);
+
+ Index _addRange(Range::Type type, Index startIndex, Index count);
+ void _removeKey(JSONValue& obj, Index globalIndex);
+ /// Note does not destroy values in range.
+ void _destroyRange(Index rangeIndex);
+
+ static bool _sameKeyOrder(const JSONKeyValue* a, const JSONKeyValue* b, Index count);
+ /// True if the values are equal
+ bool _areEqualValues(const JSONKeyValue* a, const JSONKeyValue* b, Index count);
+ /// True if the key and value are equal
+ bool _areEqualOrderedKeys(const JSONKeyValue* a, const JSONKeyValue* b, Index count);
+
+ StringBuilder m_buf; ///< A temporary buffer used to hold unescaped strings
+
+ SourceView* m_currentView = nullptr;
+ SourceManager* m_sourceManager;
+
+ StringSlicePool m_slicePool;
+ List<Range> m_ranges;
+ List<Index> m_freeRangeIndices;
+ List<JSONValue> m_arrayValues;
+ List<JSONKeyValue> m_objectValues;
+
+};
+
+} // namespace Slang
+
+#endif