LibrePCB Developers Documentation
sexpression.h
Go to the documentation of this file.
1 /*
2  * LibrePCB - Professional EDA for everyone!
3  * Copyright (C) 2013 LibrePCB Developers, see AUTHORS.md for contributors.
4  * https://librepcb.org/
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef LIBREPCB_SEXPRESSION_H
21 #define LIBREPCB_SEXPRESSION_H
22 
23 /*******************************************************************************
24  * Includes
25  ******************************************************************************/
26 #include "../exceptions.h"
27 #include "filepath.h"
28 
29 #include <QtCore>
30 #include <QtWidgets>
31 
32 /*******************************************************************************
33  * Namespace / Forward Declarations
34  ******************************************************************************/
35 namespace librepcb {
36 
37 class SExpression;
38 class Version;
39 
48 template <typename T>
49 SExpression serialize(const T& obj);
50 
62 template <typename T>
63 T deserialize(const SExpression& sexpr, const Version& fileFormat);
64 
65 /*******************************************************************************
66  * Class SExpression
67  ******************************************************************************/
68 
72 class SExpression final {
73  Q_DECLARE_TR_FUNCTIONS(SExpression)
74 
75 public:
76  // Types
77  enum class Type {
78  List,
79  Token,
80  String,
81  LineBreak,
82  };
83 
84  // Constructors / Destructor
85  SExpression() noexcept;
86  SExpression(const SExpression& other) noexcept;
87  ~SExpression() noexcept;
88 
89  // Getters
90  const FilePath& getFilePath() const noexcept { return mFilePath; }
91  Type getType() const noexcept { return mType; }
92  bool isList() const noexcept { return mType == Type::List; }
93  bool isToken() const noexcept { return mType == Type::Token; }
94  bool isString() const noexcept { return mType == Type::String; }
95  bool isLineBreak() const noexcept { return mType == Type::LineBreak; }
96  bool isMultiLineList() const noexcept;
97  const QString& getName() const;
98  const QString& getValue() const;
99  const QList<SExpression>& getChildren() const noexcept { return mChildren; }
100  QList<SExpression> getChildren(const QString& name) const noexcept;
101 
135  const SExpression& getChild(const QString& path) const;
136 
148  const SExpression* tryGetChild(const QString& path) const noexcept;
149 
150  // General Methods
152  SExpression& appendList(const QString& name, bool linebreak);
153  SExpression& appendChild(const SExpression& child, bool linebreak);
154  template <typename T>
155  SExpression& appendChild(const T& obj) {
156  appendChild(serialize(obj), false);
157  return *this;
158  }
159  template <typename T>
160  SExpression& appendChild(const QString& child, const T& obj, bool linebreak) {
161  return appendList(child, linebreak).appendChild(obj);
162  }
163  void removeLineBreaks() noexcept;
164  QByteArray toByteArray() const;
165 
166  // Operator Overloadings
167  SExpression& operator=(const SExpression& rhs) noexcept;
168 
169  // Static Methods
170  static SExpression createList(const QString& name);
171  static SExpression createToken(const QString& token);
172  static SExpression createString(const QString& string);
173  static SExpression createLineBreak();
174  static SExpression parse(const QByteArray& content, const FilePath& filePath);
175 
176 private: // Methods
177  SExpression(Type type, const QString& value);
178 
179  static SExpression parse(const QString& content, int& index,
180  const FilePath& filePath);
181  static SExpression parseList(const QString& content, int& index,
182  const FilePath& filePath);
183  static QString parseToken(const QString& content, int& index,
184  const FilePath& filePath);
185  static QString parseString(const QString& content, int& index,
186  const FilePath& filePath);
187  static void skipWhitespaceAndComments(const QString& content, int& index);
188  static QString escapeString(const QString& string) noexcept;
189  static bool isValidToken(const QString& token) noexcept;
190  static bool isValidTokenChar(const QChar& c) noexcept;
191  QString toString(int indent) const;
192 
193 private: // Data
195  QString mValue;
196  QList<SExpression> mChildren;
198 };
199 
200 /*******************************************************************************
201  * Serialization Methods
202  ******************************************************************************/
203 
204 template <>
205 inline SExpression serialize(const QString& obj) {
206  return SExpression::createString(obj);
207 }
208 
209 template <>
210 inline SExpression serialize(const bool& obj) {
211  return SExpression::createToken(obj ? "true" : "false");
212 }
213 
214 template <>
215 inline SExpression serialize(const int& obj) {
216  return SExpression::createToken(QString::number(obj));
217 }
218 
219 template <>
220 inline SExpression serialize(const uint& obj) {
221  return SExpression::createToken(QString::number(obj));
222 }
223 
224 template <>
225 inline SExpression serialize(const QColor& obj) {
226  return SExpression::createString(obj.isValid() ? obj.name(QColor::HexArgb)
227  : "");
228 }
229 
230 template <>
231 inline SExpression serialize(const QUrl& obj) {
233  obj.isValid() ? obj.toString(QUrl::PrettyDecoded) : "");
234 }
235 
236 template <>
237 inline SExpression serialize(const QDateTime& obj) {
238  return SExpression::createToken(obj.toUTC().toString(Qt::ISODate));
239 }
240 
241 template <>
242 inline SExpression serialize(const SExpression& obj) {
243  return obj;
244 }
245 
246 /*******************************************************************************
247  * Deserialization Methods
248  ******************************************************************************/
249 
250 template <>
251 inline QString deserialize(const SExpression& sexpr,
252  const Version& fileFormat) {
253  Q_UNUSED(fileFormat);
254  return sexpr.getValue(); // can throw
255 }
256 
257 template <>
258 inline bool deserialize(const SExpression& sexpr, const Version& fileFormat) {
259  Q_UNUSED(fileFormat);
260  if (sexpr.getValue() == "true") {
261  return true;
262  } else if (sexpr.getValue() == "false") {
263  return false;
264  } else
265  throw RuntimeError(__FILE__, __LINE__,
266  SExpression::tr("Not a valid boolean."));
267 }
268 
269 template <>
270 inline int deserialize(const SExpression& sexpr, const Version& fileFormat) {
271  Q_UNUSED(fileFormat);
272  bool ok = false;
273  int value = sexpr.getValue().toInt(&ok);
274  if (ok) {
275  return value;
276  } else
277  throw RuntimeError(__FILE__, __LINE__,
278  SExpression::tr("Not a valid integer."));
279 }
280 
281 template <>
282 inline uint deserialize(const SExpression& sexpr, const Version& fileFormat) {
283  Q_UNUSED(fileFormat);
284  bool ok = false;
285  uint value = sexpr.getValue().toUInt(&ok);
286  if (ok) {
287  return value;
288  } else
289  throw RuntimeError(__FILE__, __LINE__,
290  SExpression::tr("Not a valid unsigned integer."));
291 }
292 
293 template <>
294 inline QDateTime deserialize(const SExpression& sexpr,
295  const Version& fileFormat) {
296  Q_UNUSED(fileFormat);
297  QDateTime obj =
298  QDateTime::fromString(sexpr.getValue(), Qt::ISODate).toLocalTime();
299  if (obj.isValid())
300  return obj;
301  else
302  throw RuntimeError(__FILE__, __LINE__,
303  SExpression::tr("Not a valid datetime."));
304 }
305 
306 template <>
307 inline QColor deserialize(const SExpression& sexpr, const Version& fileFormat) {
308  Q_UNUSED(fileFormat);
309  QColor obj(sexpr.getValue());
310  if (obj.isValid()) {
311  return obj;
312  } else
313  throw RuntimeError(__FILE__, __LINE__,
314  SExpression::tr("Not a valid color."));
315 }
316 
317 template <>
318 inline QUrl deserialize(const SExpression& sexpr, const Version& fileFormat) {
319  Q_UNUSED(fileFormat);
320  QUrl obj(sexpr.getValue(), QUrl::StrictMode);
321  if (obj.isValid()) {
322  return obj;
323  } else
324  throw RuntimeError(__FILE__, __LINE__, SExpression::tr("Not a valid URL."));
325 }
326 
327 /*******************************************************************************
328  * End of File
329  ******************************************************************************/
330 
331 } // namespace librepcb
332 
333 #endif // LIBREPCB_SEXPRESSION_H
const QString & getName() const
Definition: sexpression.cpp:68
The Version class represents a version number in the format "1.42.7".
Definition: version.h:60
const SExpression * tryGetChild(const QString &path) const noexcept
Try get a child by path.
Definition: sexpression.cpp:106
bool isString() const noexcept
Definition: sexpression.h:94
const QList< SExpression > & getChildren() const noexcept
Definition: sexpression.h:99
static SExpression createLineBreak()
Definition: sexpression.cpp:298
QByteArray toByteArray() const
Definition: sexpression.cpp:167
SExpression & appendLineBreak()
Definition: sexpression.cpp:139
SExpression & appendChild(const SExpression &child, bool linebreak)
Definition: sexpression.cpp:148
SExpression serialize(const HAlign &obj)
Definition: alignment.h:76
static bool isValidToken(const QString &token) noexcept
Definition: sexpression.cpp:220
Definition: airwiresbuilder.cpp:32
Type
Definition: sexpression.h:77
HAlign deserialize(const SExpression &sexpr, const Version &fileFormat)
Definition: alignment.h:90
static QString parseString(const QString &content, int &index, const FilePath &filePath)
Definition: sexpression.cpp:378
Type getType() const noexcept
Definition: sexpression.h:91
static SExpression createList(const QString &name)
Definition: sexpression.cpp:286
bool isToken() const noexcept
Definition: sexpression.h:93
FilePath mFilePath
Definition: sexpression.h:197
bool isList() const noexcept
Definition: sexpression.h:92
Type mType
Definition: sexpression.h:194
values without quotes (e.g. -12.34)
SExpression & appendChild(const T &obj)
Definition: sexpression.h:155
static SExpression createToken(const QString &token)
Definition: sexpression.cpp:290
QList< SExpression > mChildren
Definition: sexpression.h:196
static SExpression parseList(const QString &content, int &index, const FilePath &filePath)
Definition: sexpression.cpp:336
QString mValue
either a list name, a token or a string
Definition: sexpression.h:195
static void skipWhitespaceAndComments(const QString &content, int &index)
Definition: sexpression.cpp:432
static SExpression createString(const QString &string)
Definition: sexpression.cpp:294
SExpression & appendList(const QString &name, bool linebreak)
Definition: sexpression.cpp:144
SExpression & operator=(const SExpression &rhs) noexcept
Definition: sexpression.cpp:177
has a tag name and an arbitrary number of children
void removeLineBreaks() noexcept
Definition: sexpression.cpp:159
manual line break inside a List
static QString parseToken(const QString &content, int &index, const FilePath &filePath)
Definition: sexpression.cpp:361
bool isMultiLineList() const noexcept
Definition: sexpression.cpp:59
bool isLineBreak() const noexcept
Definition: sexpression.h:95
SExpression & appendChild(const QString &child, const T &obj, bool linebreak)
Definition: sexpression.h:160
The RuntimeError class.
Definition: exceptions.h:216
This class represents absolute, well-formatted paths to files or directories.
Definition: filepath.h:127
SExpression() noexcept
Definition: sexpression.cpp:38
QString toString(int indent) const
Definition: sexpression.cpp:238
values with double quotes (e.g. "Foo!")
const SExpression & getChild(const QString &path) const
Get a child by path.
Definition: sexpression.cpp:96
static QString escapeString(const QString &string) noexcept
Definition: sexpression.cpp:189
static bool isValidTokenChar(const QChar &c) noexcept
Definition: sexpression.cpp:232
~SExpression() noexcept
Definition: sexpression.cpp:52
const QString & getValue() const
Definition: sexpression.cpp:77
The SExpression class.
Definition: sexpression.h:72
static SExpression parse(const QByteArray &content, const FilePath &filePath)
Definition: sexpression.cpp:302
const FilePath & getFilePath() const noexcept
Definition: sexpression.h:90