str-scanner.hpp str-scanner.cpp \
parse-json.hpp \
make-unique.hpp \
- json-val.hpp json-val.cpp
+ json-val.hpp json-val.cpp \
+ parse-json-as-val.hpp parse-json-as-val.cpp
EXTRA_DIST = bt2
--- /dev/null
+/*
+ * Copyright (c) 2016-2022 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#define BT_CLOG_CFG _mLogCfg
+#define BT_LOG_TAG "PARSE-JSON-AS-VAL"
+#include "cpp-common/cfg-logging-error-reporting-throw.hpp"
+
+#include "common/common.h"
+#include "common/assert.h"
+#include "parse-json-as-val.hpp"
+
+namespace bt2_common {
+namespace {
+
+/*
+ * Listener for the listener version of parseJson() which iteratively
+ * builds a "root" JSON value.
+ */
+class JsonValBuilder final
+{
+public:
+ explicit JsonValBuilder(const std::size_t baseOffset) : _mBaseOffset {baseOffset}
+ {
+ }
+
+ void onNull(const TextLoc& loc)
+ {
+ this->_handleVal(loc);
+ }
+
+ template <typename ValT>
+ void onScalarVal(const ValT& val, const TextLoc& loc)
+ {
+ this->_handleVal(loc, val);
+ }
+
+ void onArrayBegin(const TextLoc&)
+ {
+ _mStack.push_back(_StackFrame {_State::IN_ARRAY});
+ }
+
+ void onArrayEnd(const TextLoc& loc)
+ {
+ auto arrayValCont = std::move(this->_stackTop().arrayValCont);
+
+ _mStack.pop_back();
+ this->_handleVal(loc, std::move(arrayValCont));
+ }
+
+ void onObjBegin(const TextLoc&)
+ {
+ _mStack.push_back(_StackFrame {_State::IN_OBJ});
+ }
+
+ void onObjKey(const std::string& key, const TextLoc&)
+ {
+ this->_stackTop().lastObjKey = key;
+ }
+
+ void onObjEnd(const TextLoc& loc)
+ {
+ auto objValCont = std::move(this->_stackTop().objValCont);
+
+ _mStack.pop_back();
+ this->_handleVal(loc, std::move(objValCont));
+ }
+
+ JsonVal::UP releaseVal() noexcept
+ {
+ return std::move(_mJsonVal);
+ }
+
+private:
+ /* The state of a stack frame */
+ enum class _State
+ {
+ IN_ARRAY,
+ IN_OBJ,
+ };
+
+ /* A entry of `_mStack` */
+ struct _StackFrame
+ {
+ explicit _StackFrame(const _State stateParam) : state {stateParam}
+ {
+ }
+
+ _State state;
+ JsonArrayVal::Container arrayValCont;
+ JsonObjVal::Container objValCont;
+ std::string lastObjKey;
+ };
+
+private:
+ /*
+ * Top frame of the stack.
+ */
+ _StackFrame& _stackTop() noexcept
+ {
+ BT_ASSERT_DBG(!_mStack.empty());
+ return _mStack.back();
+ }
+
+ template <typename... ArgTs>
+ void _handleVal(const TextLoc& loc, ArgTs&&...args)
+ {
+ /* Create a JSON value from custom arguments and `loc` */
+ auto jsonVal =
+ createJsonVal(std::forward<ArgTs>(args)...,
+ TextLoc {loc.offset() + _mBaseOffset, loc.lineNo(), loc.colNo()});
+
+ if (_mStack.empty()) {
+ /* Assign as root */
+ _mJsonVal = std::move(jsonVal);
+ return;
+ }
+
+ switch (_mStack.back().state) {
+ case _State::IN_ARRAY:
+ /* Append to current JSON array value container */
+ this->_stackTop().arrayValCont.push_back(std::move(jsonVal));
+ break;
+
+ case _State::IN_OBJ:
+ /*
+ * Insert into current JSON object value container
+ *
+ * It's safe to move `this->_stackTop().lastObjKey` as it's
+ * only used once.
+ */
+ this->_stackTop().objValCont.insert(
+ std::make_pair(std::move(this->_stackTop().lastObjKey), std::move(jsonVal)));
+ break;
+
+ default:
+ bt_common_abort();
+ }
+ }
+
+private:
+ std::size_t _mBaseOffset;
+ std::vector<_StackFrame> _mStack;
+ JsonVal::UP _mJsonVal;
+};
+
+} /* namespace */
+
+JsonVal::UP parseJson(const char * const begin, const char * const end,
+ const std::size_t baseOffset, const LogCfg& logCfg,
+ const TextLocStrFmt textLocStrFmt)
+{
+ JsonValBuilder builder {baseOffset};
+
+ parseJson(begin, end, builder, baseOffset, logCfg, textLocStrFmt);
+ return builder.releaseVal();
+}
+
+} /* namespace bt2_common */
--- /dev/null
+/*
+ * Copyright (c) 2022 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#ifndef BABELTRACE_CPP_COMMON_PARSE_JSON_AS_VAL_HPP
+#define BABELTRACE_CPP_COMMON_PARSE_JSON_AS_VAL_HPP
+
+#include <cstdlib>
+#include <string>
+
+#include "parse-json.hpp"
+#include "json-val.hpp"
+#include "text-loc.hpp"
+#include "text-loc-str.hpp"
+#include "log-cfg.hpp"
+
+namespace bt2_common {
+
+/*
+ * Parses the JSON text between `begin` and `end` (excluded) and returns
+ * the resulting JSON value, adding `baseOffset` to the text location
+ * offset of all the created JSON values.
+ *
+ * When this function logs or appends a cause to the error of the
+ * current thread, it uses `baseOffset` and `textLocStrFmt` to format
+ * the text location part of the message.
+ */
+JsonVal::UP parseJson(const char *begin, const char *end, std::size_t baseOffset,
+ const LogCfg& logCfg,
+ TextLocStrFmt textLocStrFmt = TextLocStrFmt::LINE_COL_NOS_AND_OFFSET);
+
+static inline JsonVal::UP
+parseJson(const char *begin, const char *end, const LogCfg& logCfg,
+ const TextLocStrFmt textLocStrFmt = TextLocStrFmt::LINE_COL_NOS_AND_OFFSET)
+{
+ return parseJson(begin, end, 0, logCfg, textLocStrFmt);
+}
+
+/*
+ * Parses the null-terminated JSON text `str` and returns the resulting
+ * JSON value, adding `baseOffset` to the text location offset of all
+ * the created JSON values.
+ *
+ * When this function logs or appends a cause to the error of the
+ * current thread, it uses `baseOffset` and `textLocStrFmt` to format
+ * the text location part of the message.
+ */
+static inline JsonVal::UP
+parseJson(const char * const str, const std::size_t baseOffset, const LogCfg& logCfg,
+ const TextLocStrFmt textLocStrFmt = TextLocStrFmt::LINE_COL_NOS_AND_OFFSET)
+{
+ return parseJson(str, str + std::strlen(str), baseOffset, logCfg, textLocStrFmt);
+}
+
+static inline JsonVal::UP
+parseJson(const char * const str, const LogCfg& logCfg,
+ const TextLocStrFmt textLocStrFmt = TextLocStrFmt::LINE_COL_NOS_AND_OFFSET)
+{
+ return parseJson(str, static_cast<std::size_t>(0), logCfg, textLocStrFmt);
+}
+
+/*
+ * Parses the JSON string `str` and returns the resulting JSON value,
+ * adding `baseOffset` to the text location offset of all the created
+ * JSON values.
+ *
+ * When this function logs or appends a cause to the error of the
+ * current thread, it uses `baseOffset` and `textLocStrFmt` to format
+ * the text location part of the message.
+ */
+static inline JsonVal::UP
+parseJson(const std::string& str, const std::size_t baseOffset, const LogCfg& logCfg,
+ const TextLocStrFmt textLocStrFmt = TextLocStrFmt::LINE_COL_NOS_AND_OFFSET)
+{
+ return parseJson(str.data(), str.data() + str.size(), baseOffset, logCfg, textLocStrFmt);
+}
+
+static inline JsonVal::UP
+parseJson(const std::string& str, const LogCfg& logCfg,
+ const TextLocStrFmt textLocStrFmt = TextLocStrFmt::LINE_COL_NOS_AND_OFFSET)
+{
+ return parseJson(str, 0, logCfg, textLocStrFmt);
+}
+
+} /* namespace bt2_common */
+
+#endif /* BABELTRACE_CPP_COMMON_PARSE_JSON_AS_VAL_HPP */