File indexing completed on 2024-05-12 05:51:07
0001 /* 0002 SPDX-FileCopyrightText: 2022 Héctor Mesa Jiménez <wmj.py@gmx.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #pragma once 0008 0009 #include <QJsonArray> 0010 #include <QJsonDocument> 0011 #include <QJsonObject> 0012 #include <QJsonValue> 0013 #include <QMetaType> 0014 #include <QString> 0015 #include <optional> 0016 0017 #include "records.h" 0018 0019 namespace gdbmi 0020 { 0021 0022 template<typename T> 0023 struct Item { 0024 // head position 0025 int position; 0026 // parsed value 0027 std::optional<T> value; 0028 // error message 0029 std::optional<QString> error; 0030 0031 bool isEmpty() const 0032 { 0033 return !value.has_value(); 0034 } 0035 0036 bool hasError() const 0037 { 0038 return isEmpty() && error.has_value(); 0039 } 0040 }; 0041 0042 /** 0043 * make an empty item (no value) 0044 */ 0045 template<typename T> 0046 Item<T> make_empty_item(int position) 0047 { 0048 return Item<T>{position, std::nullopt, std::nullopt}; 0049 } 0050 0051 /** 0052 * make an empty item with an error message 0053 */ 0054 template<typename T> 0055 Item<T> make_error_item(int position, const QString &error) 0056 { 0057 return Item<T>{position, std::nullopt, error}; 0058 } 0059 0060 /** 0061 * make an item with value 0062 */ 0063 template<typename T> 0064 Item<T> make_item(int position, const T &&value) 0065 { 0066 return Item<T>{position, std::move(value), std::nullopt}; 0067 } 0068 0069 /** 0070 * convert an empty item from type Told to type Tnew 0071 */ 0072 template<typename Tnew, typename Told> 0073 Item<Tnew> relay_item(const Item<Told> &item, const int pos = -1) 0074 { 0075 return Item<Tnew>{pos >= 0 ? pos : item.position, std::nullopt, item.error}; 0076 } 0077 0078 struct Result { 0079 QString name; 0080 QJsonValue value; 0081 }; 0082 0083 /** 0084 * unescape a string 0085 */ 0086 QString unescapeString(const QByteArray &escapedString, QJsonParseError *error); 0087 /** 0088 * escape quotes in a string 0089 */ 0090 QString quotedString(const QString &message); 0091 0092 int advanceBlanks(const QByteArray &buffer, int position); 0093 int advanceNewlines(const QByteArray &buffer, int position); 0094 int indexOfNewline(const QByteArray &buffer, const int offset); 0095 0096 /** 0097 * extract a prompt separator 0098 */ 0099 Item<int> tryPrompt(const QByteArray &buffer, const int start); 0100 /** 0101 * extract sequence token 0102 * 0103 * token → any sequence of digits. 0104 */ 0105 Item<int> tryToken(const QByteArray &buffer, const int start); 0106 /** 0107 * extract c-string 0108 */ 0109 Item<QString> tryString(const QByteArray &buffer, int start); 0110 /** 0111 * extract classname 0112 * 0113 * result-record → [ token ] "^" result-class ( "," result )* nl 0114 */ 0115 Item<QString> tryClassName(const QByteArray &buffer, const int start); 0116 /** 0117 * extract variable 0118 * 0119 * result → variable "=" value 0120 */ 0121 Item<QString> tryVariable(const QByteArray &message, const int start, const char sep = '='); 0122 /** 0123 * extract stream output 0124 * 0125 * console-stream-output → "~" c-string nl 0126 * target-stream-output → "@" c-string nl 0127 * log-stream-output → "&" c-string nl 0128 */ 0129 Item<StreamOutput> tryStreamOutput(const char prefix, const QByteArray &buffer, int position); 0130 0131 /** 0132 * extract result 0133 * 0134 * result → variable "=" value 0135 */ 0136 Item<Result> tryResult(const QByteArray &message, const int start); 0137 /** 0138 * result ( "," result )* 0139 * 0140 * @return {key1=value1, ..., keyN=valueN} 0141 */ 0142 Item<QJsonObject> tryResults(const QByteArray &message, const int start); 0143 /** 0144 * result ( "," result )* 0145 * 0146 * @return [{key1=value1}, ..., {keyN=valueN}] 0147 */ 0148 Item<QJsonArray> tryResultList(const QByteArray &message, const int start); 0149 /** 0150 * value → const | tuple | list 0151 */ 0152 Item<QJsonValue> tryValue(const QByteArray &message, const int start); 0153 /** 0154 * value ( "," value )* 0155 */ 0156 Item<QJsonArray> tryValueList(const QByteArray &message, const int start); 0157 /** 0158 * tuple → "{}" | "{" result ( "," result )* "}" 0159 */ 0160 Item<QJsonObject> tryTuple(const QByteArray &message, const int start); 0161 /** 0162 * tuple → "[]" | "[" result ( "," result )* "]" 0163 */ 0164 Item<QJsonArray> tryTupleList(const QByteArray &message, const int start); 0165 /** 0166 * list → "[]" | "[" value ( "," value )* "]" | "[" result ( "," result )* "]" 0167 */ 0168 Item<QJsonValue> tryList(const QByteArray &message, const int start); 0169 /** 0170 * exec-async-output → [ token ] "*" async-output nl 0171 * status-async-output → [ token ] "+" async-output nl 0172 * notify-async-output → [ token ] "=" async-output nl 0173 * async-output → async-class ( "," result )* 0174 * 0175 * result-record → [ token ] "^" result-class ( "," result )* nl 0176 */ 0177 Item<Record> tryRecord(const char prefix, const QByteArray &message, const int start, int token = -1); 0178 } 0179 0180 Q_DECLARE_METATYPE(gdbmi::StreamOutput) 0181 Q_DECLARE_METATYPE(gdbmi::Record)