value.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512
  1. // SExp - A S-Expression Parser for C++
  2. // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
  3. // 2015 Ingo Ruhnke <grumbel@gmail.com>
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. #ifndef HEADER_SEXP_VALUE_HPP
  18. #define HEADER_SEXP_VALUE_HPP
  19. #include <assert.h>
  20. #include <memory>
  21. #include <string>
  22. #include <vector>
  23. #include <sexp/error.hpp>
  24. #include <stdint.h>
  25. namespace sexp {
  26. class Value
  27. {
  28. public:
  29. enum class Type : unsigned char
  30. {
  31. NIL,
  32. BOOLEAN,
  33. INTEGER,
  34. REAL,
  35. STRING,
  36. SYMBOL,
  37. CONS,
  38. ARRAY
  39. };
  40. private:
  41. struct Cons;
  42. #if INTPTR_MAX == INT32_MAX
  43. unsigned m_line : 24;
  44. #else
  45. int m_line;
  46. #endif
  47. Value::Type m_type;
  48. union Data
  49. {
  50. inline Data() {}
  51. inline Data(bool v) : m_bool(v) {}
  52. inline Data(int v) : m_int(v) {}
  53. inline Data(float v) : m_float(v) {}
  54. inline Data(std::string* v) : m_string(v) {}
  55. inline Data(Cons* v) : m_cons(v) {}
  56. inline Data(std::vector<Value>* v) : m_array(v) {}
  57. bool m_bool;
  58. int m_int;
  59. float m_float;
  60. std::string* m_string;
  61. Cons* m_cons;
  62. std::vector<Value>* m_array;
  63. } m_data;
  64. struct BooleanTag {};
  65. struct IntegerTag {};
  66. struct RealTag {};
  67. struct StringTag {};
  68. struct SymbolTag {};
  69. struct ConsTag {};
  70. struct ArrayTag {};
  71. public:
  72. /** Returns a reference to a nil value for use in functions that
  73. return a reference and need to return a nil value */
  74. static Value const& nil_ref() { static Value const s_nil; return s_nil; }
  75. static Value nil() { return Value(); }
  76. static Value boolean(bool v) { return Value(BooleanTag(), v); }
  77. static Value integer(int v) { return Value(IntegerTag(), v); }
  78. static Value real(float v) { return Value(RealTag(), v); }
  79. static Value string(std::string const& v) { return Value(StringTag(), v); }
  80. static Value symbol(std::string const& v) { return Value(SymbolTag(), v); }
  81. static Value cons(Value&& car, Value&& cdr) { return Value(ConsTag(), std::move(car), std::move(cdr)); }
  82. static Value cons() { return Value(ConsTag(), Value::nil(), Value::nil()); }
  83. static Value array(std::vector<Value> arr) { return Value(ArrayTag(), std::move(arr)); }
  84. template<typename... Args>
  85. static Value array(Args&&... args) { return Value(ArrayTag(), std::move(args)...); }
  86. static Value list()
  87. {
  88. return Value::nil();
  89. }
  90. template<typename... Args>
  91. static Value list(Value&& head, Args&&... rest)
  92. {
  93. return Value::cons(std::move(head), list(std::move(rest)...));
  94. }
  95. int get_line() const { return static_cast<int>(m_line); }
  96. void set_line(int line)
  97. {
  98. #if INTPTR_MAX == INT32_MAX
  99. m_line = static_cast<unsigned int>(line) & 0xffffff;
  100. #else
  101. m_line = line;
  102. #endif
  103. }
  104. private:
  105. inline explicit Value(BooleanTag, bool value) : m_line(0), m_type(Type::BOOLEAN), m_data(value) {}
  106. inline explicit Value(IntegerTag, int value) : m_line(0), m_type(Type::INTEGER), m_data(value) {}
  107. inline explicit Value(RealTag, float value) : m_line(0), m_type(Type::REAL), m_data(value) {}
  108. inline Value(StringTag, std::string const& value) :
  109. m_line(0),
  110. m_type(Type::STRING),
  111. m_data(new std::string(value))
  112. {}
  113. inline Value(SymbolTag, std::string const& value) :
  114. m_line(0),
  115. m_type(Type::SYMBOL),
  116. m_data(new std::string(value))
  117. {}
  118. inline Value(ConsTag, Value&& car, Value&& cdr);
  119. inline Value(ArrayTag, std::vector<Value> arr) :
  120. m_line(0),
  121. m_type(Type::ARRAY),
  122. m_data(new std::vector<Value>(std::move(arr)))
  123. {}
  124. template<typename... Args>
  125. inline Value(ArrayTag, Args&&... args) :
  126. m_line(0),
  127. m_type(Type::ARRAY),
  128. m_data(new std::vector<Value>{std::move(args)...})
  129. {}
  130. void destroy();
  131. [[noreturn]]
  132. void type_error(const char* msg) const
  133. {
  134. throw TypeError(m_line, msg);
  135. }
  136. public:
  137. Value(Value const& other);
  138. inline Value(Value&& other) :
  139. m_line(other.m_line),
  140. m_type(other.m_type),
  141. m_data(other.m_data)
  142. {
  143. other.m_type = Type::NIL;
  144. }
  145. inline Value() :
  146. m_line(0),
  147. m_type(Type::NIL),
  148. m_data()
  149. {}
  150. inline ~Value()
  151. {
  152. destroy();
  153. }
  154. inline Value& operator=(Value&& other)
  155. {
  156. destroy();
  157. m_line = other.m_line;
  158. m_type = other.m_type;
  159. m_data = other.m_data;
  160. other.m_type = Type::NIL;
  161. return *this;
  162. }
  163. inline Value& operator=(Value const& other)
  164. {
  165. destroy();
  166. new (this) Value(other);
  167. return *this;
  168. }
  169. inline Type get_type() const { return m_type; }
  170. inline explicit operator bool() const { return m_type != Type::NIL; }
  171. inline bool is_nil() const { return m_type == Type::NIL; }
  172. inline bool is_boolean() const { return m_type == Type::BOOLEAN; }
  173. inline bool is_integer() const { return m_type == Type::INTEGER; }
  174. inline bool is_real() const { return (m_type == Type::REAL || m_type == Type::INTEGER); }
  175. inline bool is_string() const { return m_type == Type::STRING; }
  176. inline bool is_translatable_string() const;
  177. inline bool is_symbol() const { return m_type == Type::SYMBOL; }
  178. inline bool is_cons() const { return m_type == Type::CONS; }
  179. inline bool is_array() const { return m_type == Type::ARRAY; }
  180. Value const& get_car() const;
  181. Value const& get_cdr() const;
  182. Value& get_car();
  183. Value& get_cdr();
  184. void set_car(Value&& sexpr);
  185. void set_cdr(Value&& sexpr);
  186. void append(Value&& sexpr);
  187. bool as_bool() const;
  188. int as_int() const;
  189. float as_float() const;
  190. std::string const& as_string() const;
  191. std::vector<Value> const& as_array() const;
  192. bool operator==(Value const& other) const;
  193. std::string str() const;
  194. };
  195. struct Value::Cons
  196. {
  197. Value car;
  198. Value cdr;
  199. };
  200. inline
  201. Value::Value(ConsTag, Value&& car, Value&& cdr) :
  202. m_line(0),
  203. m_type(Type::CONS),
  204. m_data(new Cons{std::move(car), std::move(cdr)})
  205. {}
  206. inline void
  207. Value::destroy()
  208. {
  209. switch(m_type)
  210. {
  211. case Value::Type::STRING:
  212. case Value::Type::SYMBOL:
  213. delete m_data.m_string;
  214. break;
  215. case Value::Type::CONS:
  216. delete m_data.m_cons;
  217. break;
  218. case Value::Type::ARRAY:
  219. delete m_data.m_array;
  220. break;
  221. default:
  222. // atoms don't need deletion
  223. break;
  224. }
  225. }
  226. inline
  227. Value::Value(Value const& other) :
  228. m_line(other.m_line),
  229. m_type(other.m_type)
  230. {
  231. switch(m_type)
  232. {
  233. case Type::NIL:
  234. break;
  235. case Type::BOOLEAN:
  236. m_data.m_bool = other.m_data.m_bool;
  237. break;
  238. case Type::INTEGER:
  239. m_data.m_int = other.m_data.m_int;
  240. break;
  241. case Type::REAL:
  242. m_data.m_float = other.m_data.m_float;
  243. break;
  244. case Type::STRING:
  245. case Type::SYMBOL:
  246. m_data.m_string = new std::string(*other.m_data.m_string);
  247. break;
  248. case Type::CONS:
  249. m_data.m_cons = new Cons(*other.m_data.m_cons);
  250. break;
  251. case Type::ARRAY:
  252. m_data.m_array = new std::vector<Value>(*other.m_data.m_array);
  253. break;
  254. }
  255. }
  256. inline bool
  257. Value::operator==(Value const& rhs) const
  258. {
  259. if (m_type == rhs.m_type)
  260. {
  261. switch(m_type)
  262. {
  263. case Type::NIL:
  264. return true;
  265. case Value::Type::BOOLEAN:
  266. return m_data.m_bool == rhs.m_data.m_bool;
  267. case Value::Type::INTEGER:
  268. return m_data.m_int == rhs.m_data.m_int;
  269. case Value::Type::REAL:
  270. return m_data.m_float == rhs.m_data.m_float;
  271. case Value::Type::STRING:
  272. case Value::Type::SYMBOL:
  273. return *m_data.m_string == *rhs.m_data.m_string;
  274. case Value::Type::CONS:
  275. return (m_data.m_cons->car == rhs.m_data.m_cons->car &&
  276. m_data.m_cons->cdr == rhs.m_data.m_cons->cdr);
  277. case Value::Type::ARRAY:
  278. return *m_data.m_array == *rhs.m_data.m_array;
  279. }
  280. assert(false && "should never be reached");
  281. return false;
  282. }
  283. else
  284. {
  285. return false;
  286. }
  287. }
  288. inline bool
  289. Value::is_translatable_string() const
  290. {
  291. if (m_type != Type::ARRAY)
  292. return false;
  293. const std::vector<Value>& array = *m_data.m_array;
  294. return array.size() == 2 &&
  295. array[0].is_symbol() &&
  296. array[0].as_string() == "_" &&
  297. array[1].is_string();
  298. }
  299. inline Value const&
  300. Value::get_car() const
  301. {
  302. if (m_type == Type::CONS)
  303. {
  304. return m_data.m_cons->car;
  305. }
  306. else
  307. {
  308. type_error("sexp::Value::get_car(): wrong type, expected Type::CONS");
  309. }
  310. }
  311. inline Value const&
  312. Value::get_cdr() const
  313. {
  314. if (m_type == Type::CONS)
  315. {
  316. return m_data.m_cons->cdr;
  317. }
  318. else
  319. {
  320. type_error("sexp::Value::get_cdr(): wrong type, expected Type::CONS");
  321. }
  322. }
  323. inline Value&
  324. Value::get_car()
  325. {
  326. return const_cast<Value&>(static_cast<Value const&>(*this).get_car());
  327. }
  328. inline Value&
  329. Value::get_cdr()
  330. {
  331. return const_cast<Value&>(static_cast<Value const&>(*this).get_cdr());
  332. }
  333. inline void
  334. Value::set_car(Value&& sexpr)
  335. {
  336. if (m_type == Type::CONS)
  337. {
  338. m_data.m_cons->car = std::move(sexpr);
  339. }
  340. else
  341. {
  342. type_error("sexp::Value::set_car(): wrong type, expected Type::CONS");
  343. }
  344. }
  345. inline void
  346. Value::set_cdr(Value&& sexpr)
  347. {
  348. if (m_type == Type::CONS)
  349. {
  350. m_data.m_cons->cdr = std::move(sexpr);
  351. }
  352. else
  353. {
  354. type_error("sexp::Value::set_cdr(): wrong type, expected Type::CONS");
  355. }
  356. }
  357. inline void
  358. Value::append(Value&& sexpr)
  359. {
  360. if (m_type == Type::ARRAY)
  361. {
  362. m_data.m_array->push_back(std::move(sexpr));
  363. }
  364. else
  365. {
  366. type_error("sexp::Value::append(): wrong type, expected Type::ARRAY");
  367. }
  368. }
  369. inline bool
  370. Value::as_bool() const
  371. {
  372. if (m_type == Type::BOOLEAN)
  373. {
  374. return m_data.m_bool;
  375. }
  376. else
  377. {
  378. type_error("sexp::Value::as_bool(): wrong type, expected Type::BOOLEAN");
  379. }
  380. }
  381. inline int
  382. Value::as_int() const
  383. {
  384. if (m_type == Type::INTEGER)
  385. {
  386. return m_data.m_int;
  387. }
  388. else
  389. {
  390. type_error("sexp::Value::as_int(): wrong type, expected Type::INTEGER");
  391. }
  392. }
  393. inline float
  394. Value::as_float() const
  395. {
  396. if (m_type == Type::REAL)
  397. {
  398. return m_data.m_float;
  399. }
  400. else if (m_type == Type::INTEGER)
  401. {
  402. return static_cast<float>(m_data.m_int);
  403. }
  404. else
  405. {
  406. type_error("sexp::Value::as_float(): wrong type, expected Type::INTEGER or Type::REAL");
  407. }
  408. }
  409. inline std::string const&
  410. Value::as_string() const
  411. {
  412. if (m_type == Type::SYMBOL || m_type == Type::STRING)
  413. {
  414. return *m_data.m_string;
  415. }
  416. else
  417. {
  418. type_error("sexp::Value::as_float(): wrong type, expected Type::SYMBOL or Type::STRING");
  419. }
  420. }
  421. inline std::vector<Value> const&
  422. Value::as_array() const
  423. {
  424. if (m_type == Type::ARRAY)
  425. {
  426. return *m_data.m_array;
  427. }
  428. else
  429. {
  430. type_error("sexp::Value::as_array(): wrong type, expected Type::ARRAY");
  431. }
  432. }
  433. } // namespace sexp
  434. #endif
  435. /* EOF */