summaryrefslogtreecommitdiff
path: root/source/compiler-core/slang-json-parser.h
diff options
context:
space:
mode:
Diffstat (limited to 'source/compiler-core/slang-json-parser.h')
-rw-r--r--source/compiler-core/slang-json-parser.h188
1 files changed, 188 insertions, 0 deletions
diff --git a/source/compiler-core/slang-json-parser.h b/source/compiler-core/slang-json-parser.h
new file mode 100644
index 000000000..2e907abb2
--- /dev/null
+++ b/source/compiler-core/slang-json-parser.h
@@ -0,0 +1,188 @@
+// slang-json-parser.h
+#ifndef SLANG_JSON_PARSER_H
+#define SLANG_JSON_PARSER_H
+
+#include "slang-json-lexer.h"
+
+
+namespace Slang {
+
+class JSONListener
+{
+public:
+ /// Start an object
+ virtual void startObject() = 0;
+ /// End an object
+ virtual void endObject() = 0;
+ /// Start an array
+ virtual void startArray() = 0;
+ /// End and array
+ virtual void endArray() = 0;
+
+ /// Add the key lexeme. Must be followed by addLexemeValue.
+ virtual void addLexemeKey(const UnownedStringSlice& key) = 0;
+ /// Can be performed in an array or after an addLexemeKey in an object
+ virtual void addLexemeValue(JSONTokenType type, const UnownedStringSlice& value) = 0;
+};
+
+class JSONWriter : public JSONListener
+{
+public:
+ /*
+ https://en.wikipedia.org/wiki/Indentation_style
+ */
+ enum class IndentationStyle
+ {
+ Allman, ///< After every value, and opening, closing all other types
+ KNR, ///< K&R like. Fields have CR.
+ };
+
+ enum class LocationType : uint8_t
+ {
+ Object,
+ Array,
+ Comma,
+ };
+
+ // NOTE! Order must be kept the same without fixing is functions below
+ enum class Location
+ {
+ BeforeOpenObject,
+ BeforeCloseObject,
+ AfterOpenObject,
+ AfterCloseObject,
+
+ BeforeOpenArray,
+ BeforeCloseArray,
+ AfterOpenArray,
+ AfterCloseArray,
+
+ FieldComma,
+ Comma,
+
+ CountOf,
+ };
+
+ static LocationType getLocationType(Location loc) { return isObject(loc) ? LocationType::Object : (isComma(loc) ? LocationType::Comma : LocationType::Array); }
+
+ static bool isObjectLike(Location loc) { return Index(loc) <= Index(Location::AfterCloseArray); }
+ static bool isObject(Location loc) { return Index(loc) <= Index(Location::AfterCloseObject); }
+ static bool isArray(Location loc) { return Index(loc) >= Index(Location::BeforeOpenArray) && Index(loc) <= Index(Location::AfterCloseArray); }
+ static bool isComma(Location loc) { return Index(loc) >= Index(Location::FieldComma); }
+ static bool isOpen(Location loc) { return isObjectLike(loc) && (Index(loc) & 1) == 0; }
+ static bool isClose(Location loc) { return isObjectLike(loc) && (Index(loc) & 1) != 0; }
+ static bool isBefore(Location loc) { return isObjectLike(loc) && (Index(loc) & 2) == 0; }
+ static bool isAfter(Location loc) { return isObjectLike(loc) && (Index(loc) & 2) != 0; }
+
+ // Implement JSONListener
+ virtual void startObject() SLANG_OVERRIDE;
+ virtual void endObject() SLANG_OVERRIDE;
+ virtual void startArray() SLANG_OVERRIDE;
+ virtual void endArray() SLANG_OVERRIDE;
+ virtual void addLexemeKey(const UnownedStringSlice& key) SLANG_OVERRIDE;
+ virtual void addLexemeValue(JSONTokenType type, const UnownedStringSlice& value) SLANG_OVERRIDE;
+
+ /// Get the builder
+ StringBuilder& getBuilder() { return m_builder; }
+
+ JSONWriter(IndentationStyle format, Index lineLengthLimit = -1)
+ {
+ m_format = format;
+ m_lineLengthLimit = lineLengthLimit;
+
+ m_state.m_kind = State::Kind::Root;
+ m_state.m_flags = 0;
+ }
+
+protected:
+ struct State
+ {
+ enum class Kind : uint8_t
+ {
+ Root,
+ Object,
+ Array,
+ };
+
+ typedef uint8_t Flags;
+ struct Flag
+ {
+ enum Enum : Flags
+ {
+ HasPrevious = 0x01,
+ HasKey = 0x02,
+ };
+ };
+
+ bool canEmitValue() const
+ {
+ switch (m_kind)
+ {
+ case Kind::Root: return (m_flags & Flag::HasPrevious) == 0;
+ case Kind::Array: return true;
+ case Kind::Object: return (m_flags & Flag::HasKey) != 0;
+ default: return false;
+ }
+ }
+
+ Kind m_kind;
+ Flags m_flags;
+ };
+
+ void _maybeNextLine();
+ void _nextLine();
+ void _handleFormat(Location loc);
+
+ Index _getLineLengthAfterIndent();
+
+ /// Only emits the indent if at start of line
+ void _maybeEmitIndent();
+ void _emitIndent();
+
+ void _maybeEmitComma();
+ void _maybeEmitFieldComma();
+
+ void _indent() { m_currentIndent++; }
+ void _dedent() { --m_currentIndent; SLANG_ASSERT(m_currentIndent >= 0); }
+
+ /// True if the line is indented at the required level
+ bool _hasIndent() { return m_emittedIndent >= 0 && m_emittedIndent == m_currentIndent; }
+
+ Index m_currentIndent = 0;
+ char m_indentChar = ' ';
+ Index m_indentCharCount = 4;
+
+ Index m_lineIndex = 0;
+ Index m_lineStart = 0;
+ Index m_emittedIndent = -1; /// If -1 for current line there is no indent emitted
+
+ Index m_lineLengthLimit = -1; /// The limit is only applied *AFTER* indentation
+
+ IndentationStyle m_format;
+
+ StringBuilder m_builder;
+ List<State> m_stack;
+ State m_state;
+};
+
+class JSONParser
+{
+public:
+ SlangResult parse(JSONLexer* lexer, SourceView* sourceView, JSONListener* listener, DiagnosticSink* sink);
+
+protected:
+ SlangResult _parseValue();
+ SlangResult _parseObject();
+ SlangResult _parseArray();
+
+ SourceView* m_sourceView;
+ DiagnosticSink* m_sink;
+ JSONListener* m_listener;
+ JSONLexer* m_lexer;
+};
+
+
+
+} // namespace Slang
+
+#endif