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)