diff options
Diffstat (limited to 'source/compiler-core/slang-json-value.cpp')
| -rw-r--r-- | source/compiler-core/slang-json-value.cpp | 318 |
1 files changed, 316 insertions, 2 deletions
diff --git a/source/compiler-core/slang-json-value.cpp b/source/compiler-core/slang-json-value.cpp index 3b74c00dd..5b1ee0047 100644 --- a/source/compiler-core/slang-json-value.cpp +++ b/source/compiler-core/slang-json-value.cpp @@ -350,7 +350,7 @@ int64_t JSONContainer::asInteger(const JSONValue& value) { UnownedStringSlice slice = getLexeme(value); int64_t intValue; - if (SLANG_SUCCEEDED(StringUtil::parseInt64(slice, intValue)) && slice.getLength() == 0) + if (SLANG_SUCCEEDED(StringUtil::parseInt64(slice, intValue))) { return intValue; } @@ -371,7 +371,7 @@ double JSONContainer::asFloat(const JSONValue& value) { UnownedStringSlice slice = getLexeme(value); double floatValue; - if (SLANG_SUCCEEDED(StringUtil::parseDouble(slice, floatValue)) && slice.getLength() == 0) + if (SLANG_SUCCEEDED(StringUtil::parseDouble(slice, floatValue))) { return floatValue; } @@ -808,4 +808,318 @@ bool JSONContainer::areEqual(const JSONValue& a, const JSONValue& b) return false; } +void JSONContainer::traverseRecursively(const JSONValue& value, JSONListener* listener) +{ + typedef JSONValue::Type Type; + + switch (value.type) + { + case Type::True: return listener->addBoolValue(true, value.loc); + case Type::False: return listener->addBoolValue(false, value.loc); + case Type::Null: return listener->addNullValue(value.loc); + + case Type::StringLexeme: return listener->addLexemeValue(JSONTokenType::StringLiteral, getLexeme(value), value.loc); + case Type::IntegerLexeme: return listener->addLexemeValue(JSONTokenType::IntegerLiteral, getLexeme(value), value.loc); + case Type::FloatLexeme: return listener->addLexemeValue(JSONTokenType::FloatLiteral, getLexeme(value), value.loc); + + case Type::IntegerValue: return listener->addIntegerValue(value.intValue, value.loc); + case Type::FloatValue: return listener->addFloatValue(value.floatValue, value.loc); + case Type::StringValue: + { + const auto slice = getStringFromKey(value.stringKey); + return listener->addStringValue(slice, value.loc); + } + case Type::Array: + { + listener->startArray(value.loc); + + const auto arr = getArray(value); + + for (const auto& arrayValue : arr) + { + traverseRecursively(arrayValue, listener); + } + + listener->endArray(SourceLoc()); + break; + } + case Type::Object: + { + listener->startObject(value.loc); + + const auto obj = getObject(value); + + for (const auto& objKeyValue : obj) + { + // Emit the key + const auto keyString = getStringFromKey(objKeyValue.key); + listener->addKey(keyString, objKeyValue.keyLoc); + + // Emit the value associated with the key + traverseRecursively(objKeyValue.value, listener); + } + + listener->endObject(SourceLoc()); + break; + } + default: + { + SLANG_ASSERT(!"Invalid type"); + return; + } + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + JSONBuilder + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +JSONBuilder::JSONBuilder(JSONContainer* container, Flags flags): + m_container(container), + m_flags(flags) +{ + m_state.m_kind = State::Kind::Root; + m_state.m_startIndex = 0; + + m_keyValue.reset(); + + m_rootValue.reset(); +} + +void JSONBuilder::reset() +{ + // Reset the state + m_state.m_kind = State::Kind::Root; + m_state.m_startIndex = 0; + + // Clear the work values + m_keyValue.reset(); + m_rootValue.reset(); + + // Clear the lists + m_stateStack.clear(); + m_values.clear(); + m_keyValues.clear(); +} + +void JSONBuilder::_popState() +{ + SLANG_ASSERT(m_stateStack.getCount() > 0); + + // Reset the end depending on typpe + switch (m_state.m_kind) + { + case State::Kind::Array: + { + m_values.setCount(m_state.m_startIndex); + break; + } + case State::Kind::Object: + { + m_keyValues.setCount(m_state.m_startIndex); + break; + } + } + + // Pop from the stack + m_state = m_stateStack.getLast(); + m_stateStack.removeLast(); +} + +Index JSONBuilder::_findKeyIndex(JSONKey key) const +{ + SLANG_ASSERT(m_state.m_kind == State::Kind::Object); + const Index count = m_keyValues.getCount(); + for (Index i = m_state.m_startIndex; i < count; ++i) + { + auto& keyValue = m_keyValues[i]; + // If we find the key return it's index + if (keyValue.key == key) + { + return i; + } + } + return -1; +} + +void JSONBuilder::_add(const JSONValue& value) +{ + SLANG_ASSERT(value.isValid()); + switch (m_state.m_kind) + { + case State::Kind::Root: + { + SLANG_ASSERT(!m_rootValue.isValid()); + m_rootValue = value; + break; + } + case State::Kind::Array: + { + m_values.add(value); + break; + } + case State::Kind::Object: + { + m_keyValue.value = value; + const Index index = _findKeyIndex(m_keyValue.key); + if (index >= 0) + { + m_keyValues[index] = m_keyValue; + } + else + { + m_keyValues.add(m_keyValue); + } + m_keyValue.reset(); + break; + } + } +} + +void JSONBuilder::startObject(SourceLoc loc) +{ + m_stateStack.add(m_state); + m_state.m_kind = State::Kind::Object; + m_state.m_startIndex = m_keyValues.getCount(); + m_state.m_loc = loc; +} + +void JSONBuilder::endObject(SourceLoc loc) +{ + SLANG_UNUSED(loc); + + SLANG_ASSERT(m_state.m_kind == State::Kind::Object); + + const Index count = m_keyValues.getCount() - m_state.m_startIndex; + const JSONValue value = m_container->createObject(m_keyValues.getBuffer() + m_state.m_startIndex, count, m_state.m_loc); + + // Pop current state + _popState(); + // Add the value to the current state + _add(value); +} + +void JSONBuilder::startArray(SourceLoc loc) +{ + m_stateStack.add(m_state); + m_state.m_kind = State::Kind::Array; + m_state.m_startIndex = m_values.getCount(); + m_state.m_loc = loc; +} + +void JSONBuilder::endArray(SourceLoc loc) +{ + SLANG_UNUSED(loc); + + SLANG_ASSERT(m_state.m_kind == State::Kind::Array); + + const Index count = m_values.getCount() - m_state.m_startIndex; + const JSONValue value = m_container->createArray(m_values.getBuffer() + m_state.m_startIndex, count, m_state.m_loc); + + // Pop current state + _popState(); + // Add the value to the current state + _add(value); +} + +void JSONBuilder::addKey(const UnownedStringSlice& key, SourceLoc loc) +{ + SLANG_ASSERT(m_keyValue.key == JSONKey(0)); + m_keyValue.key = m_container->getKey(key); + m_keyValue.keyLoc = loc; +} + +void JSONBuilder::addLexemeValue(JSONTokenType type, const UnownedStringSlice& value, SourceLoc loc) +{ + switch (type) + { + case JSONTokenType::True: return _add(JSONValue::makeBool(true, loc)); + case JSONTokenType::False: return _add(JSONValue::makeBool(false, loc)); + case JSONTokenType::Null: return _add(JSONValue::makeNull(loc)); + + case JSONTokenType::IntegerLiteral: + { + if (m_flags & Flag::ConvertLexemes) + { + int64_t intValue = -1; + auto res = StringUtil::parseInt64(value, intValue); + SLANG_UNUSED(res); + SLANG_ASSERT(SLANG_SUCCEEDED(res)); + _add(JSONValue::makeInt(intValue, loc)); + } + else + { + SLANG_ASSERT(loc.isValid()); + _add(JSONValue::makeLexeme(JSONValue::Type::IntegerLexeme, loc, value.getLength())); + } + break; + } + case JSONTokenType::FloatLiteral: + { + if (m_flags & Flag::ConvertLexemes) + { + double floatValue = 0; + auto res = StringUtil::parseDouble(value, floatValue); + SLANG_UNUSED(res); + SLANG_ASSERT(SLANG_SUCCEEDED(res)); + _add(JSONValue::makeFloat(floatValue, loc)); + } + else + { + SLANG_ASSERT(loc.isValid()); + _add(JSONValue::makeLexeme(JSONValue::Type::FloatLexeme, loc, value.getLength())); + } + break; + } + case JSONTokenType::StringLiteral: + { + if (m_flags & Flag::ConvertLexemes) + { + auto handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::JSON); + StringBuilder buf; + StringEscapeUtil::appendUnquoted(handler, value, buf); + + _add(m_container->createString(buf.getUnownedSlice(), loc)); + } + else + { + SLANG_ASSERT(loc.isValid()); + _add(JSONValue::makeLexeme(JSONValue::Type::StringLexeme, loc, value.getLength())); + } + break; + } + default: + { + SLANG_ASSERT(!"Unhandled type"); + } + } +} + +void JSONBuilder::addIntegerValue(int64_t value, SourceLoc loc) +{ + _add(JSONValue::makeInt(value, loc)); +} + +void JSONBuilder::addFloatValue(double value, SourceLoc loc) +{ + _add(JSONValue::makeFloat(value, loc)); +} + +void JSONBuilder::addBoolValue(bool value, SourceLoc loc) +{ + _add(JSONValue::makeBool(value, loc)); +} + +void JSONBuilder::addStringValue(const UnownedStringSlice& slice, SourceLoc loc) +{ + _add(m_container->createString(slice, loc)); +} + +void JSONBuilder::addNullValue(SourceLoc loc) +{ + _add(JSONValue::makeNull(loc)); +} + } // namespace Slang |
