chaiscript_parser.hpp 86 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596
  1. // This file is distributed under the BSD License.
  2. // See "license.txt" for details.
  3. // Copyright 2009-2012, Jonathan Turner ([email protected])
  4. // Copyright 2009-2017, Jason Turner ([email protected])
  5. // http://www.chaiscript.com
  6. // This is an open source non-commercial project. Dear PVS-Studio, please check it.
  7. // PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
  8. #ifndef CHAISCRIPT_PARSER_HPP_
  9. #define CHAISCRIPT_PARSER_HPP_
  10. #include <exception>
  11. #include <iostream>
  12. #include <memory>
  13. #include <sstream>
  14. #include <string>
  15. #include <vector>
  16. #include <cctype>
  17. #include <cstring>
  18. #include "../dispatchkit/boxed_value.hpp"
  19. #include "chaiscript_common.hpp"
  20. #include "chaiscript_optimizer.hpp"
  21. #include "chaiscript_tracer.hpp"
  22. #include "../utility/fnv1a.hpp"
  23. #include "../utility/static_string.hpp"
  24. #if defined(CHAISCRIPT_UTF16_UTF32)
  25. #include <locale>
  26. #include <codecvt>
  27. #endif
  28. #if defined(CHAISCRIPT_MSVC) && defined(max) && defined(min)
  29. #define CHAISCRIPT_PUSHED_MIN_MAX
  30. #pragma push_macro("max") // Why Microsoft? why? This is worse than bad
  31. #undef max
  32. #pragma push_macro("min")
  33. #undef min
  34. #endif
  35. namespace chaiscript
  36. {
  37. /// \brief Classes and functions used during the parsing process.
  38. namespace parser
  39. {
  40. /// \brief Classes and functions internal to the parsing process. Not supported for the end user.
  41. namespace detail
  42. {
  43. enum Alphabet
  44. { symbol_alphabet = 0
  45. , keyword_alphabet
  46. , int_alphabet
  47. , float_alphabet
  48. , x_alphabet
  49. , hex_alphabet
  50. , b_alphabet
  51. , bin_alphabet
  52. , id_alphabet
  53. , white_alphabet
  54. , int_suffix_alphabet
  55. , float_suffix_alphabet
  56. , max_alphabet
  57. , lengthof_alphabet = 256
  58. };
  59. // Generic for u16, u32 and wchar
  60. template<typename string_type>
  61. struct Char_Parser_Helper
  62. {
  63. // common for all implementations
  64. static std::string u8str_from_ll(long long val)
  65. {
  66. typedef std::string::value_type char_type;
  67. char_type c[2];
  68. c[1] = char_type(val);
  69. c[0] = char_type(val >> 8);
  70. if (c[0] == 0)
  71. {
  72. return std::string(1, c[1]); // size, character
  73. }
  74. return std::string(c, 2); // char buffer, size
  75. }
  76. static string_type str_from_ll(long long val)
  77. {
  78. typedef typename string_type::value_type target_char_type;
  79. #if defined (CHAISCRIPT_UTF16_UTF32)
  80. // prepare converter
  81. std::wstring_convert<std::codecvt_utf8<target_char_type>, target_char_type> converter;
  82. // convert
  83. return converter.from_bytes(u8str_from_ll(val));
  84. #else
  85. // no conversion available, just put value as character
  86. return string_type(1, target_char_type(val)); // size, character
  87. #endif
  88. }
  89. };
  90. // Specialization for char AKA UTF-8
  91. template<>
  92. struct Char_Parser_Helper<std::string>
  93. {
  94. static std::string str_from_ll(long long val)
  95. {
  96. // little SFINAE trick to avoid base class
  97. return Char_Parser_Helper<std::true_type>::u8str_from_ll(val);
  98. }
  99. };
  100. }
  101. template<typename Tracer, typename Optimizer>
  102. class ChaiScript_Parser final : public ChaiScript_Parser_Base {
  103. void *get_tracer_ptr() override {
  104. return &m_tracer;
  105. }
  106. static std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> build_alphabet()
  107. {
  108. std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> alphabet;
  109. for (auto &alpha : alphabet) {
  110. alpha.fill(false);
  111. }
  112. alphabet[detail::symbol_alphabet][static_cast<size_t>('?')]=true;
  113. alphabet[detail::symbol_alphabet][static_cast<size_t>('+')]=true;
  114. alphabet[detail::symbol_alphabet][static_cast<size_t>('-')]=true;
  115. alphabet[detail::symbol_alphabet][static_cast<size_t>('*')]=true;
  116. alphabet[detail::symbol_alphabet][static_cast<size_t>('/')]=true;
  117. alphabet[detail::symbol_alphabet][static_cast<size_t>('|')]=true;
  118. alphabet[detail::symbol_alphabet][static_cast<size_t>('&')]=true;
  119. alphabet[detail::symbol_alphabet][static_cast<size_t>('^')]=true;
  120. alphabet[detail::symbol_alphabet][static_cast<size_t>('=')]=true;
  121. alphabet[detail::symbol_alphabet][static_cast<size_t>('.')]=true;
  122. alphabet[detail::symbol_alphabet][static_cast<size_t>('<')]=true;
  123. alphabet[detail::symbol_alphabet][static_cast<size_t>('>')]=true;
  124. for ( size_t c = 'a' ; c <= 'z' ; ++c ) { alphabet[detail::keyword_alphabet][c]=true; }
  125. for ( size_t c = 'A' ; c <= 'Z' ; ++c ) { alphabet[detail::keyword_alphabet][c]=true; }
  126. for ( size_t c = '0' ; c <= '9' ; ++c ) { alphabet[detail::keyword_alphabet][c]=true; }
  127. alphabet[detail::keyword_alphabet][static_cast<size_t>('_')]=true;
  128. for ( size_t c = '0' ; c <= '9' ; ++c ) { alphabet[detail::int_alphabet][c]=true; }
  129. for ( size_t c = '0' ; c <= '9' ; ++c ) { alphabet[detail::float_alphabet][c]=true; }
  130. alphabet[detail::float_alphabet][static_cast<size_t>('.')]=true;
  131. for ( size_t c = '0' ; c <= '9' ; ++c ) { alphabet[detail::hex_alphabet][c]=true; }
  132. for ( size_t c = 'a' ; c <= 'f' ; ++c ) { alphabet[detail::hex_alphabet][c]=true; }
  133. for ( size_t c = 'A' ; c <= 'F' ; ++c ) { alphabet[detail::hex_alphabet][c]=true; }
  134. alphabet[detail::x_alphabet][static_cast<size_t>('x')]=true;
  135. alphabet[detail::x_alphabet][static_cast<size_t>('X')]=true;
  136. for ( size_t c = '0' ; c <= '1' ; ++c ) { alphabet[detail::bin_alphabet][c]=true; }
  137. alphabet[detail::b_alphabet][static_cast<size_t>('b')]=true;
  138. alphabet[detail::b_alphabet][static_cast<size_t>('B')]=true;
  139. for ( size_t c = 'a' ; c <= 'z' ; ++c ) { alphabet[detail::id_alphabet][c]=true; }
  140. for ( size_t c = 'A' ; c <= 'Z' ; ++c ) { alphabet[detail::id_alphabet][c]=true; }
  141. alphabet[detail::id_alphabet][static_cast<size_t>('_')] = true;
  142. alphabet[detail::white_alphabet][static_cast<size_t>(' ')]=true;
  143. alphabet[detail::white_alphabet][static_cast<size_t>('\t')]=true;
  144. alphabet[detail::int_suffix_alphabet][static_cast<size_t>('l')] = true;
  145. alphabet[detail::int_suffix_alphabet][static_cast<size_t>('L')] = true;
  146. alphabet[detail::int_suffix_alphabet][static_cast<size_t>('u')] = true;
  147. alphabet[detail::int_suffix_alphabet][static_cast<size_t>('U')] = true;
  148. alphabet[detail::float_suffix_alphabet][static_cast<size_t>('l')] = true;
  149. alphabet[detail::float_suffix_alphabet][static_cast<size_t>('L')] = true;
  150. alphabet[detail::float_suffix_alphabet][static_cast<size_t>('f')] = true;
  151. alphabet[detail::float_suffix_alphabet][static_cast<size_t>('F')] = true;
  152. return alphabet;
  153. }
  154. static const std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> &create_alphabet()
  155. {
  156. static const auto alpha = build_alphabet();
  157. return alpha;
  158. }
  159. static const std::vector<std::vector<utility::Static_String>> &create_operator_matches() {
  160. static const std::vector<std::vector<utility::Static_String>> operator_matches {
  161. {"?"},
  162. {"||"},
  163. {"&&"},
  164. {"|"},
  165. {"^"},
  166. {"&"},
  167. {"==", "!="},
  168. {"<", "<=", ">", ">="},
  169. {"<<", ">>"},
  170. //We share precedence here but then separate them later
  171. {"+", "-"},
  172. {"*", "/", "%"},
  173. {"++", "--", "-", "+", "!", "~"}
  174. };
  175. return operator_matches;
  176. }
  177. static const std::array<Operator_Precidence, 12> &create_operators() {
  178. static const std::array<Operator_Precidence, 12> operators = { {
  179. Operator_Precidence::Ternary_Cond,
  180. Operator_Precidence::Logical_Or,
  181. Operator_Precidence::Logical_And,
  182. Operator_Precidence::Bitwise_Or,
  183. Operator_Precidence::Bitwise_Xor,
  184. Operator_Precidence::Bitwise_And,
  185. Operator_Precidence::Equality,
  186. Operator_Precidence::Comparison,
  187. Operator_Precidence::Shift,
  188. Operator_Precidence::Addition,
  189. Operator_Precidence::Multiplication,
  190. Operator_Precidence::Prefix
  191. } };
  192. return operators;
  193. }
  194. static const utility::Static_String &multiline_comment_end()
  195. {
  196. static const utility::Static_String s("*/");
  197. return s;
  198. }
  199. static const utility::Static_String &multiline_comment_begin()
  200. {
  201. static const utility::Static_String s("/*");
  202. return s;
  203. }
  204. static const utility::Static_String &singleline_comment()
  205. {
  206. static const utility::Static_String s("//");
  207. return s;
  208. }
  209. static const utility::Static_String &annotation()
  210. {
  211. static const utility::Static_String s("#");
  212. return s;
  213. }
  214. static const utility::Static_String &cr_lf()
  215. {
  216. static const utility::Static_String s("\r\n");
  217. return s;
  218. }
  219. const std::array<std::array<bool, detail::lengthof_alphabet>, detail::max_alphabet> &m_alphabet = create_alphabet();
  220. const std::vector<std::vector<utility::Static_String>> &m_operator_matches = create_operator_matches();
  221. const std::array<Operator_Precidence, 12> &m_operators = create_operators();
  222. std::shared_ptr<std::string> m_filename;
  223. std::vector<eval::AST_Node_Impl_Ptr<Tracer>> m_match_stack;
  224. struct Position
  225. {
  226. Position() = default;
  227. Position(std::string::const_iterator t_pos, std::string::const_iterator t_end)
  228. : line(1), col(1), m_pos(t_pos), m_end(t_end), m_last_col(1)
  229. {
  230. }
  231. static std::string str(const Position &t_begin, const Position &t_end) {
  232. return std::string(t_begin.m_pos, t_end.m_pos);
  233. }
  234. Position &operator++() {
  235. if (m_pos != m_end) {
  236. if (*m_pos == '\n') {
  237. ++line;
  238. m_last_col = std::exchange(col, 1);
  239. } else {
  240. ++col;
  241. }
  242. ++m_pos;
  243. }
  244. return *this;
  245. }
  246. Position &operator--() {
  247. --m_pos;
  248. if (*m_pos == '\n') {
  249. --line;
  250. col = m_last_col;
  251. } else {
  252. --col;
  253. }
  254. return *this;
  255. }
  256. Position &operator+=(size_t t_distance) {
  257. *this = (*this) + t_distance;
  258. return *this;
  259. }
  260. Position operator+(size_t t_distance) const {
  261. Position ret(*this);
  262. for (size_t i = 0; i < t_distance; ++i) {
  263. ++ret;
  264. }
  265. return ret;
  266. }
  267. Position &operator-=(size_t t_distance) {
  268. *this = (*this) - t_distance;
  269. return *this;
  270. }
  271. Position operator-(size_t t_distance) const {
  272. Position ret(*this);
  273. for (size_t i = 0; i < t_distance; ++i) {
  274. --ret;
  275. }
  276. return ret;
  277. }
  278. bool operator==(const Position &t_rhs) const {
  279. return m_pos == t_rhs.m_pos;
  280. }
  281. bool operator!=(const Position &t_rhs) const {
  282. return m_pos != t_rhs.m_pos;
  283. }
  284. bool has_more() const {
  285. return m_pos != m_end;
  286. }
  287. size_t remaining() const {
  288. return static_cast<size_t>(std::distance(m_pos, m_end));
  289. }
  290. const char& operator*() const {
  291. if (m_pos == m_end) {
  292. static const char ktmp ='\0';
  293. return ktmp;
  294. } else {
  295. return *m_pos;
  296. }
  297. }
  298. int line = -1;
  299. int col = -1;
  300. private:
  301. std::string::const_iterator m_pos;
  302. std::string::const_iterator m_end;
  303. int m_last_col = -1;
  304. };
  305. Position m_position;
  306. Tracer m_tracer;
  307. Optimizer m_optimizer;
  308. void validate_object_name(const std::string &name) const
  309. {
  310. if (!Name_Validator::valid_object_name(name)) {
  311. throw exception::eval_error("Invalid Object Name: " + name, File_Position(m_position.line, m_position.col), *m_filename);
  312. }
  313. }
  314. public:
  315. explicit ChaiScript_Parser(Tracer tracer = Tracer(), Optimizer optimizer=Optimizer())
  316. : m_tracer(std::move(tracer)),
  317. m_optimizer(std::move(optimizer))
  318. {
  319. m_match_stack.reserve(2);
  320. }
  321. Tracer &get_tracer()
  322. {
  323. return m_tracer;
  324. }
  325. Optimizer &get_optimizer()
  326. {
  327. return m_optimizer;
  328. }
  329. ChaiScript_Parser(const ChaiScript_Parser &) = delete;
  330. ChaiScript_Parser &operator=(const ChaiScript_Parser &) = delete;
  331. ChaiScript_Parser(ChaiScript_Parser &&) = default;
  332. ChaiScript_Parser &operator=(ChaiScript_Parser &&) = delete;
  333. /// test a char in an m_alphabet
  334. bool char_in_alphabet(char c, detail::Alphabet a) const { return m_alphabet[a][static_cast<uint8_t>(c)]; }
  335. /// Prints the parsed ast_nodes as a tree
  336. void debug_print(const AST_Node &t, std::string prepend = "") const override {
  337. std::cout << prepend << "(" << ast_node_type_to_string(t.identifier) << ") " << t.text << " : " << t.start().line << ", " << t.start().column << '\n';
  338. for (const auto &node : t.get_children()) {
  339. debug_print(node.get(), prepend + " ");
  340. }
  341. }
  342. /// Helper function that collects ast_nodes from a starting position to the top of the stack into a new AST node
  343. template<typename NodeType>
  344. void build_match(size_t t_match_start, std::string t_text = "") {
  345. bool is_deep = false;
  346. Parse_Location filepos = [&]()->Parse_Location{
  347. //so we want to take everything to the right of this and make them children
  348. if (t_match_start != m_match_stack.size()) {
  349. is_deep = true;
  350. return Parse_Location(
  351. m_filename,
  352. m_match_stack[t_match_start]->location.start.line,
  353. m_match_stack[t_match_start]->location.start.column,
  354. m_position.line,
  355. m_position.col
  356. );
  357. } else {
  358. return Parse_Location(
  359. m_filename,
  360. m_position.line,
  361. m_position.col,
  362. m_position.line,
  363. m_position.col
  364. );
  365. }
  366. }();
  367. std::vector<eval::AST_Node_Impl_Ptr<Tracer>> new_children;
  368. if (is_deep) {
  369. new_children.assign(std::make_move_iterator(m_match_stack.begin() + static_cast<int>(t_match_start)),
  370. std::make_move_iterator(m_match_stack.end()));
  371. m_match_stack.erase(m_match_stack.begin() + static_cast<int>(t_match_start), m_match_stack.end());
  372. }
  373. /// \todo fix the fact that a successful match that captured no ast_nodes doesn't have any real start position
  374. m_match_stack.push_back(
  375. m_optimizer.optimize(
  376. chaiscript::make_unique<chaiscript::eval::AST_Node_Impl<Tracer>, NodeType>(
  377. std::move(t_text),
  378. std::move(filepos),
  379. std::move(new_children)))
  380. );
  381. }
  382. /// Reads a symbol group from input if it matches the parameter, without skipping initial whitespace
  383. inline auto Symbol_(const utility::Static_String &sym)
  384. {
  385. const auto len = sym.size();
  386. if (m_position.remaining() >= len) {
  387. const char *file_pos = &(*m_position);
  388. for (size_t pos = 0; pos < len; ++pos)
  389. {
  390. if (sym.c_str()[pos] != file_pos[pos]) { return false; }
  391. }
  392. m_position += len;
  393. return true;
  394. }
  395. return false;
  396. }
  397. /// Skips any multi-line or single-line comment
  398. bool SkipComment() {
  399. if (Symbol_(multiline_comment_begin())) {
  400. while (m_position.has_more()) {
  401. if (Symbol_(multiline_comment_end())) {
  402. break;
  403. } else if (!Eol_()) {
  404. ++m_position;
  405. }
  406. }
  407. return true;
  408. } else if (Symbol_(singleline_comment())) {
  409. while (m_position.has_more()) {
  410. if (Symbol_(cr_lf())) {
  411. m_position -= 2;
  412. break;
  413. } else if (Char_('\n')) {
  414. --m_position;
  415. break;
  416. } else {
  417. ++m_position;
  418. }
  419. }
  420. return true;
  421. } else if (Symbol_(annotation())) {
  422. while (m_position.has_more()) {
  423. if (Symbol_(cr_lf())) {
  424. m_position -= 2;
  425. break;
  426. } else if (Char_('\n')) {
  427. --m_position;
  428. break;
  429. } else {
  430. ++m_position;
  431. }
  432. }
  433. return true;
  434. }
  435. return false;
  436. }
  437. /// Skips ChaiScript whitespace, which means space and tab, but not cr/lf
  438. /// jespada: Modified SkipWS to skip optionally CR ('\n') and/or LF+CR ("\r\n")
  439. bool SkipWS(bool skip_cr=false) {
  440. bool retval = false;
  441. while (m_position.has_more()) {
  442. auto end_line = (*m_position != 0) && ((*m_position == '\n') || (*m_position == '\r' && *(m_position+1) == '\n'));
  443. if ( char_in_alphabet(*m_position,detail::white_alphabet) || (skip_cr && end_line)) {
  444. if(end_line) {
  445. if(*m_position == '\r') {
  446. // discards lf
  447. ++m_position;
  448. }
  449. }
  450. ++m_position;
  451. retval = true;
  452. }
  453. else if (SkipComment()) {
  454. retval = true;
  455. } else {
  456. break;
  457. }
  458. }
  459. return retval;
  460. }
  461. /// Reads the optional exponent (scientific notation) and suffix for a Float
  462. bool read_exponent_and_suffix() {
  463. // Support a form of scientific notation: 1e-5, 35.5E+8, 0.01e19
  464. if (m_position.has_more() && (std::tolower(*m_position) == 'e')) {
  465. ++m_position;
  466. if (m_position.has_more() && ((*m_position == '-') || (*m_position == '+'))) {
  467. ++m_position;
  468. }
  469. auto exponent_pos = m_position;
  470. while (m_position.has_more() && char_in_alphabet(*m_position,detail::int_alphabet) ) {
  471. ++m_position;
  472. }
  473. if (m_position == exponent_pos) {
  474. // Require at least one digit after the exponent
  475. return false;
  476. }
  477. }
  478. // Parse optional float suffix
  479. while (m_position.has_more() && char_in_alphabet(*m_position, detail::float_suffix_alphabet))
  480. {
  481. ++m_position;
  482. }
  483. return true;
  484. }
  485. /// Reads a floating point value from input, without skipping initial whitespace
  486. bool Float_() {
  487. if (m_position.has_more() && char_in_alphabet(*m_position,detail::float_alphabet) ) {
  488. while (m_position.has_more() && char_in_alphabet(*m_position,detail::int_alphabet) ) {
  489. ++m_position;
  490. }
  491. if (m_position.has_more() && (std::tolower(*m_position) == 'e')) {
  492. // The exponent is valid even without any decimal in the Float (1e8, 3e-15)
  493. return read_exponent_and_suffix();
  494. }
  495. else if (m_position.has_more() && (*m_position == '.')) {
  496. ++m_position;
  497. if (m_position.has_more() && char_in_alphabet(*m_position,detail::int_alphabet)) {
  498. while (m_position.has_more() && char_in_alphabet(*m_position,detail::int_alphabet) ) {
  499. ++m_position;
  500. }
  501. // After any decimal digits, support an optional exponent (3.7e3)
  502. return read_exponent_and_suffix();
  503. } else {
  504. --m_position;
  505. }
  506. }
  507. }
  508. return false;
  509. }
  510. /// Reads a hex value from input, without skipping initial whitespace
  511. bool Hex_() {
  512. if (m_position.has_more() && (*m_position == '0')) {
  513. ++m_position;
  514. if (m_position.has_more() && char_in_alphabet(*m_position, detail::x_alphabet) ) {
  515. ++m_position;
  516. if (m_position.has_more() && char_in_alphabet(*m_position, detail::hex_alphabet)) {
  517. while (m_position.has_more() && char_in_alphabet(*m_position, detail::hex_alphabet) ) {
  518. ++m_position;
  519. }
  520. while (m_position.has_more() && char_in_alphabet(*m_position, detail::int_suffix_alphabet))
  521. {
  522. ++m_position;
  523. }
  524. return true;
  525. }
  526. else {
  527. --m_position;
  528. }
  529. }
  530. else {
  531. --m_position;
  532. }
  533. }
  534. return false;
  535. }
  536. /// Reads an integer suffix
  537. void IntSuffix_() {
  538. while (m_position.has_more() && char_in_alphabet(*m_position, detail::int_suffix_alphabet))
  539. {
  540. ++m_position;
  541. }
  542. }
  543. /// Reads a binary value from input, without skipping initial whitespace
  544. bool Binary_() {
  545. if (m_position.has_more() && (*m_position == '0')) {
  546. ++m_position;
  547. if (m_position.has_more() && char_in_alphabet(*m_position, detail::b_alphabet) ) {
  548. ++m_position;
  549. if (m_position.has_more() && char_in_alphabet(*m_position, detail::bin_alphabet) ) {
  550. while (m_position.has_more() && char_in_alphabet(*m_position, detail::bin_alphabet) ) {
  551. ++m_position;
  552. }
  553. return true;
  554. } else {
  555. --m_position;
  556. }
  557. } else {
  558. --m_position;
  559. }
  560. }
  561. return false;
  562. }
  563. /// Parses a floating point value and returns a Boxed_Value representation of it
  564. static Boxed_Value buildFloat(const std::string &t_val)
  565. {
  566. bool float_ = false;
  567. bool long_ = false;
  568. auto i = t_val.size();
  569. for (; i > 0; --i)
  570. {
  571. char val = t_val[i-1];
  572. if (val == 'f' || val == 'F')
  573. {
  574. float_ = true;
  575. } else if (val == 'l' || val == 'L') {
  576. long_ = true;
  577. } else {
  578. break;
  579. }
  580. }
  581. if (float_)
  582. {
  583. return const_var(parse_num<float>(t_val.substr(0,i)));
  584. } else if (long_) {
  585. return const_var(parse_num<long double>(t_val.substr(0,i)));
  586. } else {
  587. return const_var(parse_num<double>(t_val.substr(0,i)));
  588. }
  589. }
  590. static Boxed_Value buildInt(const int base, const std::string &t_val, const bool prefixed)
  591. {
  592. bool unsigned_ = false;
  593. bool long_ = false;
  594. bool longlong_ = false;
  595. auto i = t_val.size();
  596. for (; i > 0; --i)
  597. {
  598. const char val = t_val[i-1];
  599. if (val == 'u' || val == 'U')
  600. {
  601. unsigned_ = true;
  602. } else if (val == 'l' || val == 'L') {
  603. if (long_)
  604. {
  605. longlong_ = true;
  606. }
  607. long_ = true;
  608. } else {
  609. break;
  610. }
  611. }
  612. const auto val = prefixed?std::string(t_val.begin()+2,t_val.end()):t_val;
  613. #ifdef __GNUC__
  614. #pragma GCC diagnostic push
  615. #pragma GCC diagnostic ignored "-Wsign-compare"
  616. #ifdef CHAISCRIPT_CLANG
  617. #pragma GCC diagnostic ignored "-Wtautological-compare"
  618. #endif
  619. #endif
  620. try {
  621. auto u = std::stoll(val,nullptr,base);
  622. if (!unsigned_ && !long_ && u >= std::numeric_limits<int>::min() && u <= std::numeric_limits<int>::max()) {
  623. return const_var(static_cast<int>(u));
  624. } else if ((unsigned_ || base != 10) && !long_ && u >= std::numeric_limits<unsigned int>::min() && u <= std::numeric_limits<unsigned int>::max()) {
  625. return const_var(static_cast<unsigned int>(u));
  626. } else if (!unsigned_ && !longlong_ && u >= std::numeric_limits<long>::min() && u <= std::numeric_limits<long>::max()) {
  627. return const_var(static_cast<long>(u));
  628. } else if ((unsigned_ || base != 10) && !longlong_ && u >= std::numeric_limits<unsigned long>::min() && u <= std::numeric_limits<unsigned long>::max()) {
  629. return const_var(static_cast<unsigned long>(u));
  630. } else if (!unsigned_ && u >= std::numeric_limits<long long>::min() && u <= std::numeric_limits<long long>::max()) {
  631. return const_var(static_cast<long long>(u));
  632. } else {
  633. return const_var(static_cast<unsigned long long>(u));
  634. }
  635. } catch (const std::out_of_range &) {
  636. // too big to be signed
  637. try {
  638. auto u = std::stoull(val,nullptr,base);
  639. if (!longlong_ && u >= std::numeric_limits<unsigned long>::min() && u <= std::numeric_limits<unsigned long>::max()) {
  640. return const_var(static_cast<unsigned long>(u));
  641. } else {
  642. return const_var(static_cast<unsigned long long>(u));
  643. }
  644. } catch (const std::out_of_range &) {
  645. // it's just simply too big
  646. return const_var(std::numeric_limits<long long>::max());
  647. }
  648. }
  649. #ifdef __GNUC__
  650. #pragma GCC diagnostic pop
  651. #endif
  652. }
  653. template<typename T, typename ... Param>
  654. std::unique_ptr<eval::AST_Node_Impl<Tracer>> make_node(std::string t_match, const int t_prev_line, const int t_prev_col, Param && ...param)
  655. {
  656. return chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, T>(std::move(t_match), Parse_Location(m_filename, t_prev_line, t_prev_col, m_position.line, m_position.col), std::forward<Param>(param)...);
  657. }
  658. /// Reads a number from the input, detecting if it's an integer or floating point
  659. bool Num() {
  660. SkipWS();
  661. const auto start = m_position;
  662. if (m_position.has_more() && char_in_alphabet(*m_position, detail::float_alphabet) ) {
  663. try {
  664. if (Hex_()) {
  665. auto match = Position::str(start, m_position);
  666. auto bv = buildInt(16, match, true);
  667. m_match_stack.emplace_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
  668. return true;
  669. }
  670. if (Binary_()) {
  671. auto match = Position::str(start, m_position);
  672. auto bv = buildInt(2, match, true);
  673. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
  674. return true;
  675. }
  676. if (Float_()) {
  677. auto match = Position::str(start, m_position);
  678. auto bv = buildFloat(match);
  679. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
  680. return true;
  681. }
  682. else {
  683. IntSuffix_();
  684. auto match = Position::str(start, m_position);
  685. if (!match.empty() && (match[0] == '0')) {
  686. auto bv = buildInt(8, match, false);
  687. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
  688. }
  689. else if (!match.empty()) {
  690. auto bv = buildInt(10, match, false);
  691. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(match), start.line, start.col, std::move(bv)));
  692. } else {
  693. return false;
  694. }
  695. return true;
  696. }
  697. } catch (const std::invalid_argument &) {
  698. // error parsing number passed in to buildFloat/buildInt
  699. return false;
  700. }
  701. }
  702. else {
  703. return false;
  704. }
  705. }
  706. /// Reads an identifier from input which conforms to C's identifier naming conventions, without skipping initial whitespace
  707. bool Id_() {
  708. if (m_position.has_more() && char_in_alphabet(*m_position, detail::id_alphabet)) {
  709. while (m_position.has_more() && char_in_alphabet(*m_position, detail::keyword_alphabet) ) {
  710. ++m_position;
  711. }
  712. return true;
  713. } else if (m_position.has_more() && (*m_position == '`')) {
  714. ++m_position;
  715. const auto start = m_position;
  716. while (m_position.has_more() && (*m_position != '`')) {
  717. if (Eol()) {
  718. throw exception::eval_error("Carriage return in identifier literal", File_Position(m_position.line, m_position.col), *m_filename);
  719. }
  720. else {
  721. ++m_position;
  722. }
  723. }
  724. if (start == m_position) {
  725. throw exception::eval_error("Missing contents of identifier literal", File_Position(m_position.line, m_position.col), *m_filename);
  726. }
  727. else if (!m_position.has_more()) {
  728. throw exception::eval_error("Incomplete identifier literal", File_Position(m_position.line, m_position.col), *m_filename);
  729. }
  730. ++m_position;
  731. return true;
  732. }
  733. return false;
  734. }
  735. /// Reads (and potentially captures) an identifier from input
  736. bool Id(const bool validate) {
  737. SkipWS();
  738. const auto start = m_position;
  739. if (Id_()) {
  740. auto text = Position::str(start, m_position);
  741. const auto text_hash = utility::fnv1a_32(text.c_str());
  742. if (validate) {
  743. validate_object_name(text);
  744. }
  745. #ifdef CHAISCRIPT_MSVC
  746. #pragma warning(push)
  747. #pragma warning(disable : 4307)
  748. #endif
  749. switch (text_hash) {
  750. case utility::fnv1a_32("true"): {
  751. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col, const_var(true)));
  752. } break;
  753. case utility::fnv1a_32("false"): {
  754. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col, const_var(false)));
  755. } break;
  756. case utility::fnv1a_32("Infinity"): {
  757. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
  758. const_var(std::numeric_limits<double>::infinity())));
  759. } break;
  760. case utility::fnv1a_32("NaN"): {
  761. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
  762. const_var(std::numeric_limits<double>::quiet_NaN())));
  763. } break;
  764. case utility::fnv1a_32("__LINE__"): {
  765. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
  766. const_var(start.line)));
  767. } break;
  768. case utility::fnv1a_32("__FILE__"): {
  769. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
  770. const_var(m_filename)));
  771. } break;
  772. case utility::fnv1a_32("__FUNC__"): {
  773. std::string fun_name = "NOT_IN_FUNCTION";
  774. for (size_t idx = m_match_stack.size() - 1; idx > 0; --idx)
  775. {
  776. if (m_match_stack[idx-1]->identifier == AST_Node_Type::Id
  777. && m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) {
  778. fun_name = m_match_stack[idx-1]->text;
  779. }
  780. }
  781. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
  782. const_var(fun_name)));
  783. } break;
  784. case utility::fnv1a_32("__CLASS__"): {
  785. std::string fun_name = "NOT_IN_CLASS";
  786. for (size_t idx = m_match_stack.size() - 1; idx > 1; --idx)
  787. {
  788. if (m_match_stack[idx-2]->identifier == AST_Node_Type::Id
  789. && m_match_stack[idx-1]->identifier == AST_Node_Type::Id
  790. && m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) {
  791. fun_name = m_match_stack[idx-2]->text;
  792. }
  793. }
  794. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
  795. const_var(fun_name)));
  796. } break;
  797. case utility::fnv1a_32("_"): {
  798. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(std::move(text), start.line, start.col,
  799. Boxed_Value(std::make_shared<dispatch::Placeholder_Object>())));
  800. } break;
  801. default: {
  802. std::string val = std::move(text);
  803. if (*start == '`') {
  804. // 'escaped' literal, like an operator name
  805. val = Position::str(start+1, m_position-1);
  806. }
  807. m_match_stack.push_back(make_node<eval::Id_AST_Node<Tracer>>(val, start.line, start.col));
  808. } break;
  809. }
  810. #ifdef CHAISCRIPT_MSVC
  811. #pragma warning(pop)
  812. #endif
  813. return true;
  814. } else {
  815. return false;
  816. }
  817. }
  818. /// Reads an argument from input
  819. bool Arg(const bool t_type_allowed = true) {
  820. const auto prev_stack_top = m_match_stack.size();
  821. SkipWS();
  822. if (!Id(true)) {
  823. return false;
  824. }
  825. SkipWS();
  826. if (t_type_allowed) {
  827. Id(true);
  828. }
  829. build_match<eval::Arg_AST_Node<Tracer>>(prev_stack_top);
  830. return true;
  831. }
  832. /// Reads a quoted string from input, without skipping initial whitespace
  833. bool Quoted_String_() {
  834. if (m_position.has_more() && (*m_position == '\"')) {
  835. char prev_char = *m_position;
  836. ++m_position;
  837. int in_interpolation = 0;
  838. bool in_quote = false;
  839. while (m_position.has_more() && ((*m_position != '\"') || ((*m_position == '\"') && (in_interpolation > 0)) || ((*m_position == '\"') && (prev_char == '\\')))) {
  840. if (!Eol_()) {
  841. if (prev_char == '$' && *m_position == '{') {
  842. ++in_interpolation;
  843. } else if (prev_char != '\\' && *m_position == '"') {
  844. in_quote = !in_quote;
  845. } else if (*m_position == '}' && !in_quote) {
  846. --in_interpolation;
  847. }
  848. if (prev_char == '\\') {
  849. prev_char = 0;
  850. } else {
  851. prev_char = *m_position;
  852. }
  853. ++m_position;
  854. }
  855. }
  856. if (m_position.has_more()) {
  857. ++m_position;
  858. } else {
  859. throw exception::eval_error("Unclosed quoted string", File_Position(m_position.line, m_position.col), *m_filename);
  860. }
  861. return true;
  862. }
  863. return false;
  864. }
  865. template<typename string_type>
  866. struct Char_Parser
  867. {
  868. string_type &match;
  869. typedef typename string_type::value_type char_type;
  870. bool is_escaped = false;
  871. bool is_interpolated = false;
  872. bool saw_interpolation_marker = false;
  873. bool is_octal = false;
  874. bool is_hex = false;
  875. bool is_unicode = false;
  876. const bool interpolation_allowed;
  877. string_type octal_matches;
  878. string_type hex_matches;
  879. Char_Parser(string_type &t_match, const bool t_interpolation_allowed)
  880. : match(t_match),
  881. interpolation_allowed(t_interpolation_allowed)
  882. {
  883. }
  884. Char_Parser &operator=(const Char_Parser &) = delete;
  885. ~Char_Parser(){
  886. try {
  887. if (is_octal) {
  888. process_octal();
  889. }
  890. if (is_hex) {
  891. process_hex();
  892. }
  893. if (is_unicode) {
  894. process_unicode();
  895. }
  896. } catch (const std::invalid_argument &) {
  897. // escape sequence was invalid somehow, we'll pick this
  898. // up in the next part of parsing
  899. }
  900. }
  901. void process_hex()
  902. {
  903. if (!hex_matches.empty()) {
  904. auto val = stoll(hex_matches, nullptr, 16);
  905. match.push_back(char_type(val));
  906. }
  907. hex_matches.clear();
  908. is_escaped = false;
  909. is_hex = false;
  910. }
  911. void process_octal()
  912. {
  913. if (!octal_matches.empty()) {
  914. auto val = stoll(octal_matches, nullptr, 8);
  915. match.push_back(char_type(val));
  916. }
  917. octal_matches.clear();
  918. is_escaped = false;
  919. is_octal = false;
  920. }
  921. void process_unicode()
  922. {
  923. if (!hex_matches.empty()) {
  924. auto val = stoll(hex_matches, nullptr, 16);
  925. hex_matches.clear();
  926. match += detail::Char_Parser_Helper<string_type>::str_from_ll(val);
  927. }
  928. is_escaped = false;
  929. is_unicode = false;
  930. }
  931. void parse(const char_type t_char, const int line, const int col, const std::string &filename) {
  932. const bool is_octal_char = t_char >= '0' && t_char <= '7';
  933. const bool is_hex_char = (t_char >= '0' && t_char <= '9')
  934. || (t_char >= 'a' && t_char <= 'f')
  935. || (t_char >= 'A' && t_char <= 'F');
  936. if (is_octal) {
  937. if (is_octal_char) {
  938. octal_matches.push_back(t_char);
  939. if (octal_matches.size() == 3) {
  940. process_octal();
  941. }
  942. return;
  943. } else {
  944. process_octal();
  945. }
  946. } else if (is_hex) {
  947. if (is_hex_char) {
  948. hex_matches.push_back(t_char);
  949. if (hex_matches.size() == 2*sizeof(char_type)) {
  950. // This rule differs from the C/C++ standard, but ChaiScript
  951. // does not offer the same workaround options, and having
  952. // hexadecimal sequences longer than can fit into the char
  953. // type is undefined behavior anyway.
  954. process_hex();
  955. }
  956. return;
  957. } else {
  958. process_hex();
  959. }
  960. } else if (is_unicode) {
  961. if (is_hex_char) {
  962. hex_matches.push_back(t_char);
  963. if(hex_matches.size() == 4) {
  964. // Format is specified to be 'slash'uABCD
  965. // on collecting from A to D do parsing
  966. process_unicode();
  967. }
  968. return;
  969. } else {
  970. // Not a unicode anymore, try parsing any way
  971. // May be someone used 'slash'uAA only
  972. process_unicode();
  973. }
  974. }
  975. if (t_char == '\\') {
  976. if (is_escaped) {
  977. match.push_back('\\');
  978. is_escaped = false;
  979. } else {
  980. is_escaped = true;
  981. }
  982. } else {
  983. if (is_escaped) {
  984. if (is_octal_char) {
  985. is_octal = true;
  986. octal_matches.push_back(t_char);
  987. } else if (t_char == 'x') {
  988. is_hex = true;
  989. } else if (t_char == 'u') {
  990. is_unicode = true;
  991. } else {
  992. switch (t_char) {
  993. case ('\'') : match.push_back('\''); break;
  994. case ('\"') : match.push_back('\"'); break;
  995. case ('?') : match.push_back('?'); break;
  996. case ('a') : match.push_back('\a'); break;
  997. case ('b') : match.push_back('\b'); break;
  998. case ('f') : match.push_back('\f'); break;
  999. case ('n') : match.push_back('\n'); break;
  1000. case ('r') : match.push_back('\r'); break;
  1001. case ('t') : match.push_back('\t'); break;
  1002. case ('v') : match.push_back('\v'); break;
  1003. case ('$') : match.push_back('$'); break;
  1004. default: throw exception::eval_error("Unknown escaped sequence in string", File_Position(line, col), filename);
  1005. }
  1006. is_escaped = false;
  1007. }
  1008. } else if (interpolation_allowed && t_char == '$') {
  1009. saw_interpolation_marker = true;
  1010. } else {
  1011. match.push_back(t_char);
  1012. }
  1013. }
  1014. }
  1015. };
  1016. /// Reads (and potentially captures) a quoted string from input. Translates escaped sequences.
  1017. bool Quoted_String() {
  1018. SkipWS();
  1019. const auto start = m_position;
  1020. if (Quoted_String_()) {
  1021. std::string match;
  1022. const auto prev_stack_top = m_match_stack.size();
  1023. bool is_interpolated = [&]()->bool {
  1024. Char_Parser<std::string> cparser(match, true);
  1025. auto s = start + 1, end = m_position - 1;
  1026. while (s != end) {
  1027. if (cparser.saw_interpolation_marker) {
  1028. if (*s == '{') {
  1029. //We've found an interpolation point
  1030. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, const_var(match)));
  1031. if (cparser.is_interpolated) {
  1032. //If we've seen previous interpolation, add on instead of making a new one
  1033. build_match<eval::Binary_Operator_AST_Node<Tracer>>(prev_stack_top, "+");
  1034. }
  1035. //We've finished with the part of the string up to this point, so clear it
  1036. match.clear();
  1037. std::string eval_match;
  1038. ++s;
  1039. while ((s != end) && (*s != '}')) {
  1040. eval_match.push_back(*s);
  1041. ++s;
  1042. }
  1043. if (*s == '}') {
  1044. cparser.is_interpolated = true;
  1045. ++s;
  1046. const auto tostr_stack_top = m_match_stack.size();
  1047. m_match_stack.push_back(make_node<eval::Id_AST_Node<Tracer>>("to_string", start.line, start.col));
  1048. const auto ev_stack_top = m_match_stack.size();
  1049. try {
  1050. m_match_stack.push_back(parse_instr_eval(eval_match));
  1051. } catch (const exception::eval_error &e) {
  1052. throw exception::eval_error(e.what(), File_Position(start.line, start.col), *m_filename);
  1053. }
  1054. build_match<eval::Arg_List_AST_Node<Tracer>>(ev_stack_top);
  1055. build_match<eval::Fun_Call_AST_Node<Tracer>>(tostr_stack_top);
  1056. build_match<eval::Binary_Operator_AST_Node<Tracer>>(prev_stack_top, "+");
  1057. } else {
  1058. throw exception::eval_error("Unclosed in-string eval", File_Position(start.line, start.col), *m_filename);
  1059. }
  1060. } else {
  1061. match.push_back('$');
  1062. }
  1063. cparser.saw_interpolation_marker = false;
  1064. } else {
  1065. cparser.parse(*s, start.line, start.col, *m_filename);
  1066. ++s;
  1067. }
  1068. }
  1069. return cparser.is_interpolated;
  1070. }();
  1071. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, const_var(match)));
  1072. if (is_interpolated) {
  1073. build_match<eval::Binary_Operator_AST_Node<Tracer>>(prev_stack_top, "+");
  1074. }
  1075. return true;
  1076. } else {
  1077. return false;
  1078. }
  1079. }
  1080. /// Reads a character group from input, without skipping initial whitespace
  1081. bool Single_Quoted_String_() {
  1082. bool retval = false;
  1083. if (m_position.has_more() && (*m_position == '\'')) {
  1084. retval = true;
  1085. char prev_char = *m_position;
  1086. ++m_position;
  1087. while (m_position.has_more() && ((*m_position != '\'') || ((*m_position == '\'') && (prev_char == '\\')))) {
  1088. if (!Eol_()) {
  1089. if (prev_char == '\\') {
  1090. prev_char = 0;
  1091. } else {
  1092. prev_char = *m_position;
  1093. }
  1094. ++m_position;
  1095. }
  1096. }
  1097. if (m_position.has_more()) {
  1098. ++m_position;
  1099. } else {
  1100. throw exception::eval_error("Unclosed single-quoted string", File_Position(m_position.line, m_position.col), *m_filename);
  1101. }
  1102. }
  1103. return retval;
  1104. }
  1105. /// Reads (and potentially captures) a char group from input. Translates escaped sequences.
  1106. bool Single_Quoted_String() {
  1107. SkipWS();
  1108. const auto start = m_position;
  1109. if (Single_Quoted_String_()) {
  1110. std::string match;
  1111. {
  1112. // scope for cparser destructor
  1113. Char_Parser<std::string> cparser(match, false);
  1114. for (auto s = start + 1, end = m_position - 1; s != end; ++s) {
  1115. cparser.parse(*s, start.line, start.col, *m_filename);
  1116. }
  1117. }
  1118. if (match.size() != 1) {
  1119. throw exception::eval_error("Single-quoted strings must be 1 character long", File_Position(m_position.line, m_position.col), *m_filename);
  1120. }
  1121. m_match_stack.push_back(make_node<eval::Constant_AST_Node<Tracer>>(match, start.line, start.col, const_var(char(match.at(0)))));
  1122. return true;
  1123. }
  1124. else {
  1125. return false;
  1126. }
  1127. }
  1128. /// Reads a char from input if it matches the parameter, without skipping initial whitespace
  1129. bool Char_(const char c) {
  1130. if (m_position.has_more() && (*m_position == c)) {
  1131. ++m_position;
  1132. return true;
  1133. } else {
  1134. return false;
  1135. }
  1136. }
  1137. /// Reads (and potentially captures) a char from input if it matches the parameter
  1138. bool Char(const char t_c) {
  1139. SkipWS();
  1140. return Char_(t_c);
  1141. }
  1142. /// Reads a string from input if it matches the parameter, without skipping initial whitespace
  1143. bool Keyword_(const utility::Static_String &t_s) {
  1144. const auto len = t_s.size();
  1145. if (m_position.remaining() >= len) {
  1146. auto tmp = m_position;
  1147. for (size_t i = 0; tmp.has_more() && i < len; ++i) {
  1148. if (*tmp != t_s.c_str()[i]) {
  1149. return false;
  1150. }
  1151. ++tmp;
  1152. }
  1153. m_position = tmp;
  1154. return true;
  1155. }
  1156. return false;
  1157. }
  1158. /// Reads (and potentially captures) a string from input if it matches the parameter
  1159. bool Keyword(const utility::Static_String &t_s) {
  1160. SkipWS();
  1161. const auto start = m_position;
  1162. bool retval = Keyword_(t_s);
  1163. // ignore substring matches
  1164. if ( retval && m_position.has_more() && char_in_alphabet(*m_position, detail::keyword_alphabet) ) {
  1165. m_position = start;
  1166. retval = false;
  1167. }
  1168. return retval;
  1169. }
  1170. bool is_operator(const std::string &t_s) const {
  1171. return std::any_of(m_operator_matches.begin(), m_operator_matches.end(),
  1172. [t_s](const std::vector<utility::Static_String> &opers) {
  1173. return std::any_of(opers.begin(), opers.end(),
  1174. [t_s](const utility::Static_String &s) {
  1175. return t_s == s.c_str();
  1176. });
  1177. });
  1178. }
  1179. /// Reads (and potentially captures) a symbol group from input if it matches the parameter
  1180. bool Symbol(const utility::Static_String &t_s, const bool t_disallow_prevention=false) {
  1181. SkipWS();
  1182. const auto start = m_position;
  1183. bool retval = Symbol_(t_s);
  1184. // ignore substring matches
  1185. if (retval && m_position.has_more() && (t_disallow_prevention == false) && char_in_alphabet(*m_position,detail::symbol_alphabet)) {
  1186. if (*m_position != '=' && is_operator(Position::str(start, m_position)) && !is_operator(Position::str(start, m_position+1))) {
  1187. // don't throw this away, it's a good match and the next is not
  1188. } else {
  1189. m_position = start;
  1190. retval = false;
  1191. }
  1192. }
  1193. return retval;
  1194. }
  1195. /// Reads an end-of-line group from input, without skipping initial whitespace
  1196. bool Eol_(const bool t_eos = false) {
  1197. bool retval = false;
  1198. if (m_position.has_more() && (Symbol_(cr_lf()) || Char_('\n'))) {
  1199. retval = true;
  1200. //++m_position.line;
  1201. m_position.col = 1;
  1202. } else if (m_position.has_more() && !t_eos && Char_(';')) {
  1203. retval = true;
  1204. }
  1205. return retval;
  1206. }
  1207. /// Reads until the end of the current statement
  1208. bool Eos() {
  1209. SkipWS();
  1210. return Eol_(true);
  1211. }
  1212. /// Reads (and potentially captures) an end-of-line group from input
  1213. bool Eol() {
  1214. SkipWS();
  1215. return Eol_();
  1216. }
  1217. /// Reads a comma-separated list of values from input. Id's only, no types allowed
  1218. bool Id_Arg_List() {
  1219. SkipWS(true);
  1220. bool retval = false;
  1221. const auto prev_stack_top = m_match_stack.size();
  1222. if (Arg(false)) {
  1223. retval = true;
  1224. while (Eol()) {}
  1225. while (Char(',')) {
  1226. while (Eol()) {}
  1227. if (!Arg(false)) {
  1228. throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename);
  1229. }
  1230. }
  1231. }
  1232. build_match<eval::Arg_List_AST_Node<Tracer>>(prev_stack_top);
  1233. SkipWS(true);
  1234. return retval;
  1235. }
  1236. /// Reads a comma-separated list of values from input, for function declarations
  1237. bool Decl_Arg_List() {
  1238. SkipWS(true);
  1239. bool retval = false;
  1240. const auto prev_stack_top = m_match_stack.size();
  1241. if (Arg()) {
  1242. retval = true;
  1243. while (Eol()) {}
  1244. while (Char(',')) {
  1245. while (Eol()) {}
  1246. if (!Arg()) {
  1247. throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename);
  1248. }
  1249. }
  1250. }
  1251. build_match<eval::Arg_List_AST_Node<Tracer>>(prev_stack_top);
  1252. SkipWS(true);
  1253. return retval;
  1254. }
  1255. /// Reads a comma-separated list of values from input
  1256. bool Arg_List() {
  1257. SkipWS(true);
  1258. bool retval = false;
  1259. const auto prev_stack_top = m_match_stack.size();
  1260. if (Equation()) {
  1261. retval = true;
  1262. while (Eol()) {}
  1263. while (Char(',')) {
  1264. while (Eol()) {}
  1265. if (!Equation()) {
  1266. throw exception::eval_error("Unexpected value in parameter list", File_Position(m_position.line, m_position.col), *m_filename);
  1267. }
  1268. }
  1269. }
  1270. build_match<eval::Arg_List_AST_Node<Tracer>>(prev_stack_top);
  1271. SkipWS(true);
  1272. return retval;
  1273. }
  1274. /// Reads possible special container values, including ranges and map_pairs
  1275. bool Container_Arg_List() {
  1276. bool retval = false;
  1277. SkipWS(true);
  1278. const auto prev_stack_top = m_match_stack.size();
  1279. if (Value_Range()) {
  1280. retval = true;
  1281. build_match<eval::Arg_List_AST_Node<Tracer>>(prev_stack_top);
  1282. } else if (Map_Pair()) {
  1283. retval = true;
  1284. while (Eol()) {}
  1285. while (Char(',')) {
  1286. while (Eol()) {}
  1287. if (!Map_Pair()) {
  1288. throw exception::eval_error("Unexpected value in container", File_Position(m_position.line, m_position.col), *m_filename);
  1289. }
  1290. }
  1291. build_match<eval::Arg_List_AST_Node<Tracer>>(prev_stack_top);
  1292. } else if (Operator()) {
  1293. retval = true;
  1294. while (Eol()) {}
  1295. while (Char(',')) {
  1296. while (Eol()) {}
  1297. if (!Operator()) {
  1298. throw exception::eval_error("Unexpected value in container", File_Position(m_position.line, m_position.col), *m_filename);
  1299. }
  1300. }
  1301. build_match<eval::Arg_List_AST_Node<Tracer>>(prev_stack_top);
  1302. }
  1303. SkipWS(true);
  1304. return retval;
  1305. }
  1306. /// Reads a lambda (anonymous function) from input
  1307. bool Lambda() {
  1308. bool retval = false;
  1309. const auto prev_stack_top = m_match_stack.size();
  1310. if (Keyword("fun")) {
  1311. retval = true;
  1312. if (Char('[')) {
  1313. Id_Arg_List();
  1314. if (!Char(']')) {
  1315. throw exception::eval_error("Incomplete anonymous function bind", File_Position(m_position.line, m_position.col), *m_filename);
  1316. }
  1317. } else {
  1318. // make sure we always have the same number of nodes
  1319. build_match<eval::Arg_List_AST_Node<Tracer>>(prev_stack_top);
  1320. }
  1321. if (Char('(')) {
  1322. Decl_Arg_List();
  1323. if (!Char(')')) {
  1324. throw exception::eval_error("Incomplete anonymous function", File_Position(m_position.line, m_position.col), *m_filename);
  1325. }
  1326. } else {
  1327. throw exception::eval_error("Incomplete anonymous function", File_Position(m_position.line, m_position.col), *m_filename);
  1328. }
  1329. while (Eol()) {}
  1330. if (!Block()) {
  1331. throw exception::eval_error("Incomplete anonymous function", File_Position(m_position.line, m_position.col), *m_filename);
  1332. }
  1333. build_match<eval::Lambda_AST_Node<Tracer>>(prev_stack_top);
  1334. }
  1335. return retval;
  1336. }
  1337. /// Reads a function definition from input
  1338. bool Def(const bool t_class_context = false, const std::string &t_class_name = "") {
  1339. bool retval = false;
  1340. const auto prev_stack_top = m_match_stack.size();
  1341. if (Keyword("def")) {
  1342. retval = true;
  1343. if (t_class_context) {
  1344. m_match_stack.push_back(make_node<eval::Id_AST_Node<Tracer>>(t_class_name, m_position.line, m_position.col));
  1345. }
  1346. if (!Id(true)) {
  1347. throw exception::eval_error("Missing function name in definition", File_Position(m_position.line, m_position.col), *m_filename);
  1348. }
  1349. bool is_method = false;
  1350. if (Symbol("::")) {
  1351. //We're now a method
  1352. is_method = true;
  1353. if (!Id(true)) {
  1354. throw exception::eval_error("Missing method name in definition", File_Position(m_position.line, m_position.col), *m_filename);
  1355. }
  1356. }
  1357. if (Char('(')) {
  1358. Decl_Arg_List();
  1359. if (!Char(')')) {
  1360. throw exception::eval_error("Incomplete function definition", File_Position(m_position.line, m_position.col), *m_filename);
  1361. }
  1362. }
  1363. while (Eos()) {}
  1364. if (Char(':')) {
  1365. if (!Operator()) {
  1366. throw exception::eval_error("Missing guard expression for function", File_Position(m_position.line, m_position.col), *m_filename);
  1367. }
  1368. }
  1369. while (Eol()) {}
  1370. if (!Block()) {
  1371. throw exception::eval_error("Incomplete function definition", File_Position(m_position.line, m_position.col), *m_filename);
  1372. }
  1373. if (is_method || t_class_context) {
  1374. build_match<eval::Method_AST_Node<Tracer>>(prev_stack_top);
  1375. } else {
  1376. build_match<eval::Def_AST_Node<Tracer>>(prev_stack_top);
  1377. }
  1378. }
  1379. return retval;
  1380. }
  1381. /// Reads a function definition from input
  1382. bool Try() {
  1383. bool retval = false;
  1384. const auto prev_stack_top = m_match_stack.size();
  1385. if (Keyword("try")) {
  1386. retval = true;
  1387. while (Eol()) {}
  1388. if (!Block()) {
  1389. throw exception::eval_error("Incomplete 'try' block", File_Position(m_position.line, m_position.col), *m_filename);
  1390. }
  1391. bool has_matches = true;
  1392. while (has_matches) {
  1393. while (Eol()) {}
  1394. has_matches = false;
  1395. if (Keyword("catch")) {
  1396. const auto catch_stack_top = m_match_stack.size();
  1397. if (Char('(')) {
  1398. if (!(Arg() && Char(')'))) {
  1399. throw exception::eval_error("Incomplete 'catch' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1400. }
  1401. if (Char(':')) {
  1402. if (!Operator()) {
  1403. throw exception::eval_error("Missing guard expression for catch", File_Position(m_position.line, m_position.col), *m_filename);
  1404. }
  1405. }
  1406. }
  1407. while (Eol()) {}
  1408. if (!Block()) {
  1409. throw exception::eval_error("Incomplete 'catch' block", File_Position(m_position.line, m_position.col), *m_filename);
  1410. }
  1411. build_match<eval::Catch_AST_Node<Tracer>>(catch_stack_top);
  1412. has_matches = true;
  1413. }
  1414. }
  1415. while (Eol()) {}
  1416. if (Keyword("finally")) {
  1417. const auto finally_stack_top = m_match_stack.size();
  1418. while (Eol()) {}
  1419. if (!Block()) {
  1420. throw exception::eval_error("Incomplete 'finally' block", File_Position(m_position.line, m_position.col), *m_filename);
  1421. }
  1422. build_match<eval::Finally_AST_Node<Tracer>>(finally_stack_top);
  1423. }
  1424. build_match<eval::Try_AST_Node<Tracer>>(prev_stack_top);
  1425. }
  1426. return retval;
  1427. }
  1428. /// Reads an if/else if/else block from input
  1429. bool If() {
  1430. bool retval = false;
  1431. const auto prev_stack_top = m_match_stack.size();
  1432. if (Keyword("if")) {
  1433. retval = true;
  1434. if (!Char('(')) {
  1435. throw exception::eval_error("Incomplete 'if' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1436. }
  1437. if (!Equation()) {
  1438. throw exception::eval_error("Incomplete 'if' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1439. }
  1440. const bool is_if_init = Eol() && Equation();
  1441. if (!Char(')')) {
  1442. throw exception::eval_error("Incomplete 'if' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1443. }
  1444. while (Eol()) {}
  1445. if (!Block()) {
  1446. throw exception::eval_error("Incomplete 'if' block", File_Position(m_position.line, m_position.col), *m_filename);
  1447. }
  1448. bool has_matches = true;
  1449. while (has_matches) {
  1450. while (Eol()) {}
  1451. has_matches = false;
  1452. if (Keyword("else")) {
  1453. if (If()) {
  1454. has_matches = true;
  1455. } else {
  1456. while (Eol()) {}
  1457. if (!Block()) {
  1458. throw exception::eval_error("Incomplete 'else' block", File_Position(m_position.line, m_position.col), *m_filename);
  1459. }
  1460. has_matches = true;
  1461. }
  1462. }
  1463. }
  1464. const auto num_children = m_match_stack.size() - prev_stack_top;
  1465. if ((is_if_init && num_children == 3)
  1466. || (!is_if_init && num_children == 2)) {
  1467. m_match_stack.push_back(chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
  1468. }
  1469. if (!is_if_init) {
  1470. build_match<eval::If_AST_Node<Tracer>>(prev_stack_top);
  1471. } else {
  1472. build_match<eval::If_AST_Node<Tracer>>(prev_stack_top+1);
  1473. build_match<eval::Block_AST_Node<Tracer>>(prev_stack_top);
  1474. }
  1475. }
  1476. return retval;
  1477. }
  1478. /// Reads a class block from input
  1479. bool Class(const bool t_class_allowed) {
  1480. bool retval = false;
  1481. size_t prev_stack_top = m_match_stack.size();
  1482. if (Keyword("class")) {
  1483. if (!t_class_allowed) {
  1484. throw exception::eval_error("Class definitions only allowed at top scope", File_Position(m_position.line, m_position.col), *m_filename);
  1485. }
  1486. retval = true;
  1487. if (!Id(true)) {
  1488. throw exception::eval_error("Missing class name in definition", File_Position(m_position.line, m_position.col), *m_filename);
  1489. }
  1490. const auto class_name = m_match_stack.back()->text;
  1491. while (Eol()) {}
  1492. if (!Class_Block(class_name)) {
  1493. throw exception::eval_error("Incomplete 'class' block", File_Position(m_position.line, m_position.col), *m_filename);
  1494. }
  1495. build_match<eval::Class_AST_Node<Tracer>>(prev_stack_top);
  1496. }
  1497. return retval;
  1498. }
  1499. /// Reads a while block from input
  1500. bool While() {
  1501. bool retval = false;
  1502. const auto prev_stack_top = m_match_stack.size();
  1503. if (Keyword("while")) {
  1504. retval = true;
  1505. if (!Char('(')) {
  1506. throw exception::eval_error("Incomplete 'while' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1507. }
  1508. if (!(Operator() && Char(')'))) {
  1509. throw exception::eval_error("Incomplete 'while' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1510. }
  1511. while (Eol()) {}
  1512. if (!Block()) {
  1513. throw exception::eval_error("Incomplete 'while' block", File_Position(m_position.line, m_position.col), *m_filename);
  1514. }
  1515. build_match<eval::While_AST_Node<Tracer>>(prev_stack_top);
  1516. }
  1517. return retval;
  1518. }
  1519. /// Reads the ranged `for` conditions from input
  1520. bool Range_Expression() {
  1521. // the first element will have already been captured by the For_Guards() call that preceeds it
  1522. return Char(':') && Equation();
  1523. }
  1524. /// Reads the C-style `for` conditions from input
  1525. bool For_Guards() {
  1526. if (!(Equation() && Eol()))
  1527. {
  1528. if (!Eol())
  1529. {
  1530. return false;
  1531. } else {
  1532. m_match_stack.push_back(chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
  1533. }
  1534. }
  1535. if (!(Equation() && Eol()))
  1536. {
  1537. if (!Eol())
  1538. {
  1539. return false;
  1540. } else {
  1541. m_match_stack.push_back(chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, eval::Constant_AST_Node<Tracer>>(Boxed_Value(true)));
  1542. }
  1543. }
  1544. if (!Equation())
  1545. {
  1546. m_match_stack.push_back(chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
  1547. }
  1548. return true;
  1549. }
  1550. /// Reads a for block from input
  1551. bool For() {
  1552. bool retval = false;
  1553. const auto prev_stack_top = m_match_stack.size();
  1554. if (Keyword("for")) {
  1555. retval = true;
  1556. if (!Char('(')) {
  1557. throw exception::eval_error("Incomplete 'for' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1558. }
  1559. const bool classic_for = For_Guards() && Char(')');
  1560. if (!classic_for && !(Range_Expression() && Char(')'))) {
  1561. throw exception::eval_error("Incomplete 'for' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1562. }
  1563. while (Eol()) {}
  1564. if (!Block()) {
  1565. throw exception::eval_error("Incomplete 'for' block", File_Position(m_position.line, m_position.col), *m_filename);
  1566. }
  1567. const auto num_children = m_match_stack.size() - prev_stack_top;
  1568. if (classic_for) {
  1569. if (num_children != 4) {
  1570. throw exception::eval_error("Incomplete 'for' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1571. }
  1572. build_match<eval::For_AST_Node<Tracer>>(prev_stack_top);
  1573. } else {
  1574. if (num_children != 3) {
  1575. throw exception::eval_error("Incomplete ranged-for expression", File_Position(m_position.line, m_position.col), *m_filename);
  1576. }
  1577. build_match<eval::Ranged_For_AST_Node<Tracer>>(prev_stack_top);
  1578. }
  1579. }
  1580. return retval;
  1581. }
  1582. /// Reads a case block from input
  1583. bool Case() {
  1584. bool retval = false;
  1585. const auto prev_stack_top = m_match_stack.size();
  1586. if (Keyword("case")) {
  1587. retval = true;
  1588. if (!Char('(')) {
  1589. throw exception::eval_error("Incomplete 'case' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1590. }
  1591. if (!(Operator() && Char(')'))) {
  1592. throw exception::eval_error("Incomplete 'case' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1593. }
  1594. while (Eol()) {}
  1595. if (!Block()) {
  1596. throw exception::eval_error("Incomplete 'case' block", File_Position(m_position.line, m_position.col), *m_filename);
  1597. }
  1598. build_match<eval::Case_AST_Node<Tracer>>(prev_stack_top);
  1599. } else if (Keyword("default")) {
  1600. retval = true;
  1601. while (Eol()) {}
  1602. if (!Block()) {
  1603. throw exception::eval_error("Incomplete 'default' block", File_Position(m_position.line, m_position.col), *m_filename);
  1604. }
  1605. build_match<eval::Default_AST_Node<Tracer>>(prev_stack_top);
  1606. }
  1607. return retval;
  1608. }
  1609. /// Reads a switch statement from input
  1610. bool Switch() {
  1611. const auto prev_stack_top = m_match_stack.size();
  1612. if (Keyword("switch")) {
  1613. if (!Char('(')) {
  1614. throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1615. }
  1616. if (!(Operator() && Char(')'))) {
  1617. throw exception::eval_error("Incomplete 'switch' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1618. }
  1619. while (Eol()) {}
  1620. if (Char('{')) {
  1621. while (Eol()) {}
  1622. while (Case()) {
  1623. while (Eol()) { } // eat
  1624. }
  1625. while (Eol()) { } // eat
  1626. if (!Char('}')) {
  1627. throw exception::eval_error("Incomplete block", File_Position(m_position.line, m_position.col), *m_filename);
  1628. }
  1629. }
  1630. else {
  1631. throw exception::eval_error("Incomplete block", File_Position(m_position.line, m_position.col), *m_filename);
  1632. }
  1633. build_match<eval::Switch_AST_Node<Tracer>>(prev_stack_top);
  1634. return true;
  1635. } else {
  1636. return false;
  1637. }
  1638. }
  1639. /// Reads a curly-brace C-style class block from input
  1640. bool Class_Block(const std::string &t_class_name) {
  1641. bool retval = false;
  1642. const auto prev_stack_top = m_match_stack.size();
  1643. if (Char('{')) {
  1644. retval = true;
  1645. Class_Statements(t_class_name);
  1646. if (!Char('}')) {
  1647. throw exception::eval_error("Incomplete class block", File_Position(m_position.line, m_position.col), *m_filename);
  1648. }
  1649. if (m_match_stack.size() == prev_stack_top) {
  1650. m_match_stack.push_back(chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
  1651. }
  1652. build_match<eval::Block_AST_Node<Tracer>>(prev_stack_top);
  1653. }
  1654. return retval;
  1655. }
  1656. /// Reads a curly-brace C-style block from input
  1657. bool Block() {
  1658. bool retval = false;
  1659. const auto prev_stack_top = m_match_stack.size();
  1660. if (Char('{')) {
  1661. retval = true;
  1662. Statements();
  1663. if (!Char('}')) {
  1664. throw exception::eval_error("Incomplete block", File_Position(m_position.line, m_position.col), *m_filename);
  1665. }
  1666. if (m_match_stack.size() == prev_stack_top) {
  1667. m_match_stack.push_back(chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
  1668. }
  1669. build_match<eval::Block_AST_Node<Tracer>>(prev_stack_top);
  1670. }
  1671. return retval;
  1672. }
  1673. /// Reads a return statement from input
  1674. bool Return() {
  1675. const auto prev_stack_top = m_match_stack.size();
  1676. if (Keyword("return")) {
  1677. Operator();
  1678. build_match<eval::Return_AST_Node<Tracer>>(prev_stack_top);
  1679. return true;
  1680. } else {
  1681. return false;
  1682. }
  1683. }
  1684. /// Reads a break statement from input
  1685. bool Break() {
  1686. const auto prev_stack_top = m_match_stack.size();
  1687. if (Keyword("break")) {
  1688. build_match<eval::Break_AST_Node<Tracer>>(prev_stack_top);
  1689. return true;
  1690. } else {
  1691. return false;
  1692. }
  1693. }
  1694. /// Reads a continue statement from input
  1695. bool Continue() {
  1696. const auto prev_stack_top = m_match_stack.size();
  1697. if (Keyword("continue")) {
  1698. build_match<eval::Continue_AST_Node<Tracer>>(prev_stack_top);
  1699. return true;
  1700. } else {
  1701. return false;
  1702. }
  1703. }
  1704. /// Reads a dot expression(member access), then proceeds to check if it's a function or array call
  1705. bool Dot_Fun_Array() {
  1706. bool retval = false;
  1707. const auto prev_stack_top = m_match_stack.size();
  1708. if (Lambda() || Num() || Quoted_String() || Single_Quoted_String() ||
  1709. Paren_Expression() || Inline_Container() || Id(false))
  1710. {
  1711. retval = true;
  1712. bool has_more = true;
  1713. while (has_more) {
  1714. has_more = false;
  1715. if (Char('(')) {
  1716. has_more = true;
  1717. Arg_List();
  1718. if (!Char(')')) {
  1719. throw exception::eval_error("Incomplete function call", File_Position(m_position.line, m_position.col), *m_filename);
  1720. }
  1721. build_match<eval::Fun_Call_AST_Node<Tracer>>(prev_stack_top);
  1722. /// \todo Work around for method calls until we have a better solution
  1723. if (!m_match_stack.back()->children.empty()) {
  1724. if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Dot_Access) {
  1725. if (m_match_stack.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
  1726. }
  1727. if (m_match_stack.back()->children.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
  1728. }
  1729. auto dot_access = std::move(m_match_stack.back()->children[0]);
  1730. auto func_call = std::move(m_match_stack.back());
  1731. m_match_stack.pop_back();
  1732. func_call->children.erase(func_call->children.begin());
  1733. if (dot_access->children.empty()) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
  1734. }
  1735. func_call->children.insert(func_call->children.begin(), std::move(dot_access->children.back()));
  1736. dot_access->children.pop_back();
  1737. dot_access->children.push_back(std::move(func_call));
  1738. if (dot_access->children.size() != 2) { throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
  1739. }
  1740. m_match_stack.push_back(std::move(dot_access));
  1741. }
  1742. }
  1743. } else if (Char('[')) {
  1744. has_more = true;
  1745. if (!(Operator() && Char(']'))) {
  1746. throw exception::eval_error("Incomplete array access", File_Position(m_position.line, m_position.col), *m_filename);
  1747. }
  1748. build_match<eval::Array_Call_AST_Node<Tracer>>(prev_stack_top);
  1749. }
  1750. else if (Symbol(".")) {
  1751. has_more = true;
  1752. if (!(Id(true))) {
  1753. throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
  1754. }
  1755. if ( std::distance(m_match_stack.begin() + static_cast<int>(prev_stack_top), m_match_stack.end()) != 2) {
  1756. throw exception::eval_error("Incomplete dot access fun call", File_Position(m_position.line, m_position.col), *m_filename);
  1757. }
  1758. build_match<eval::Dot_Access_AST_Node<Tracer>>(prev_stack_top);
  1759. }
  1760. }
  1761. }
  1762. return retval;
  1763. }
  1764. /// Reads a variable declaration from input
  1765. bool Var_Decl(const bool t_class_context = false, const std::string &t_class_name = "") {
  1766. bool retval = false;
  1767. const auto prev_stack_top = m_match_stack.size();
  1768. if (t_class_context && (Keyword("attr") || Keyword("auto") || Keyword("var"))) {
  1769. retval = true;
  1770. m_match_stack.push_back(make_node<eval::Id_AST_Node<Tracer>>(t_class_name, m_position.line, m_position.col));
  1771. if (!Id(true)) {
  1772. throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename);
  1773. }
  1774. build_match<eval::Attr_Decl_AST_Node<Tracer>>(prev_stack_top);
  1775. } else if (Keyword("auto") || Keyword("var") ) {
  1776. retval = true;
  1777. if (Reference()) {
  1778. // we built a reference node - continue
  1779. } else if (Id(true)) {
  1780. build_match<eval::Var_Decl_AST_Node<Tracer>>(prev_stack_top);
  1781. } else {
  1782. throw exception::eval_error("Incomplete variable declaration", File_Position(m_position.line, m_position.col), *m_filename);
  1783. }
  1784. } else if (Keyword("global")) {
  1785. retval = true;
  1786. if (!(Reference() || Id(true))) {
  1787. throw exception::eval_error("Incomplete global declaration", File_Position(m_position.line, m_position.col), *m_filename);
  1788. }
  1789. build_match<eval::Global_Decl_AST_Node<Tracer>>(prev_stack_top);
  1790. } else if (Keyword("attr")) {
  1791. retval = true;
  1792. if (!Id(true)) {
  1793. throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename);
  1794. }
  1795. if (!Symbol("::")) {
  1796. throw exception::eval_error("Incomplete attribute declaration", File_Position(m_position.line, m_position.col), *m_filename);
  1797. }
  1798. if (!Id(true)) {
  1799. throw exception::eval_error("Missing attribute name in definition", File_Position(m_position.line, m_position.col), *m_filename);
  1800. }
  1801. build_match<eval::Attr_Decl_AST_Node<Tracer>>(prev_stack_top);
  1802. }
  1803. return retval;
  1804. }
  1805. /// Reads an expression surrounded by parentheses from input
  1806. bool Paren_Expression() {
  1807. if (Char('(')) {
  1808. if (!Operator()) {
  1809. throw exception::eval_error("Incomplete expression", File_Position(m_position.line, m_position.col), *m_filename);
  1810. }
  1811. if (!Char(')')) {
  1812. throw exception::eval_error("Missing closing parenthesis ')'", File_Position(m_position.line, m_position.col), *m_filename);
  1813. }
  1814. return true;
  1815. } else {
  1816. return false;
  1817. }
  1818. }
  1819. /// Reads, and identifies, a short-form container initialization from input
  1820. bool Inline_Container() {
  1821. const auto prev_stack_top = m_match_stack.size();
  1822. if (Char('[')) {
  1823. Container_Arg_List();
  1824. if (!Char(']')) {
  1825. throw exception::eval_error("Missing closing square bracket ']' in container initializer", File_Position(m_position.line, m_position.col), *m_filename);
  1826. }
  1827. if ((prev_stack_top != m_match_stack.size()) && (!m_match_stack.back()->children.empty())) {
  1828. if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Value_Range) {
  1829. build_match<eval::Inline_Range_AST_Node<Tracer>>(prev_stack_top);
  1830. }
  1831. else if (m_match_stack.back()->children[0]->identifier == AST_Node_Type::Map_Pair) {
  1832. build_match<eval::Inline_Map_AST_Node<Tracer>>(prev_stack_top);
  1833. }
  1834. else {
  1835. build_match<eval::Inline_Array_AST_Node<Tracer>>(prev_stack_top);
  1836. }
  1837. }
  1838. else {
  1839. build_match<eval::Inline_Array_AST_Node<Tracer>>(prev_stack_top);
  1840. }
  1841. return true;
  1842. } else {
  1843. return false;
  1844. }
  1845. }
  1846. /// Parses a variable specified with a & aka reference
  1847. bool Reference() {
  1848. const auto prev_stack_top = m_match_stack.size();
  1849. if (Symbol("&")) {
  1850. if (!Id(true)) {
  1851. throw exception::eval_error("Incomplete '&' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1852. }
  1853. build_match<eval::Reference_AST_Node<Tracer>>(prev_stack_top);
  1854. return true;
  1855. } else {
  1856. return false;
  1857. }
  1858. }
  1859. /// Reads a unary prefixed expression from input
  1860. bool Prefix() {
  1861. const auto prev_stack_top = m_match_stack.size();
  1862. using SS = utility::Static_String;
  1863. constexpr const std::array<utility::Static_String, 6> prefix_opers{{
  1864. SS{"++"},
  1865. SS{"--"},
  1866. SS{"-"},
  1867. SS{"+"},
  1868. SS{"!"},
  1869. SS{"~"}
  1870. }};
  1871. for (const auto &oper : prefix_opers)
  1872. {
  1873. const bool is_char = oper.size() == 1;
  1874. if ((is_char && Char(oper.c_str()[0])) || (!is_char && Symbol(oper)))
  1875. {
  1876. if (!Operator(m_operators.size()-1)) {
  1877. throw exception::eval_error("Incomplete prefix '" + std::string(oper.c_str()) + "' expression", File_Position(m_position.line, m_position.col), *m_filename);
  1878. }
  1879. build_match<eval::Prefix_AST_Node<Tracer>>(prev_stack_top, oper.c_str());
  1880. return true;
  1881. }
  1882. }
  1883. return false;
  1884. }
  1885. /// Parses any of a group of 'value' style ast_node groups from input
  1886. bool Value() {
  1887. return Var_Decl() || Dot_Fun_Array() || Prefix();
  1888. }
  1889. bool Operator_Helper(const size_t t_precedence, std::string &oper) {
  1890. for (auto & elem : m_operator_matches[t_precedence]) {
  1891. if (Symbol(elem)) {
  1892. oper = elem.c_str();
  1893. return true;
  1894. }
  1895. }
  1896. return false;
  1897. }
  1898. bool Operator(const size_t t_precedence = 0) {
  1899. bool retval = false;
  1900. const auto prev_stack_top = m_match_stack.size();
  1901. if (m_operators[t_precedence] != Operator_Precidence::Prefix) {
  1902. if (Operator(t_precedence+1)) {
  1903. retval = true;
  1904. std::string oper;
  1905. while (Operator_Helper(t_precedence, oper)) {
  1906. while (Eol()) {}
  1907. if (!Operator(t_precedence+1)) {
  1908. throw exception::eval_error("Incomplete '" + oper + "' expression",
  1909. File_Position(m_position.line, m_position.col), *m_filename);
  1910. }
  1911. switch (m_operators[t_precedence]) {
  1912. case(Operator_Precidence::Ternary_Cond) :
  1913. if (Symbol(":")) {
  1914. if (!Operator(t_precedence+1)) {
  1915. throw exception::eval_error("Incomplete '" + oper + "' expression",
  1916. File_Position(m_position.line, m_position.col), *m_filename);
  1917. }
  1918. build_match<eval::If_AST_Node<Tracer>>(prev_stack_top);
  1919. }
  1920. else {
  1921. throw exception::eval_error("Incomplete '" + oper + "' expression",
  1922. File_Position(m_position.line, m_position.col), *m_filename);
  1923. }
  1924. break;
  1925. case(Operator_Precidence::Addition) :
  1926. case(Operator_Precidence::Multiplication) :
  1927. case(Operator_Precidence::Shift) :
  1928. case(Operator_Precidence::Equality) :
  1929. case(Operator_Precidence::Bitwise_And) :
  1930. case(Operator_Precidence::Bitwise_Xor) :
  1931. case(Operator_Precidence::Bitwise_Or) :
  1932. case(Operator_Precidence::Comparison) :
  1933. build_match<eval::Binary_Operator_AST_Node<Tracer>>(prev_stack_top, oper);
  1934. break;
  1935. case(Operator_Precidence::Logical_And) :
  1936. build_match<eval::Logical_And_AST_Node<Tracer>>(prev_stack_top, oper);
  1937. break;
  1938. case(Operator_Precidence::Logical_Or) :
  1939. build_match<eval::Logical_Or_AST_Node<Tracer>>(prev_stack_top, oper);
  1940. break;
  1941. case(Operator_Precidence::Prefix) :
  1942. assert(false); // cannot reach here because of if() statement at the top
  1943. break;
  1944. // default:
  1945. // throw exception::eval_error("Internal error: unhandled ast_node", File_Position(m_position.line, m_position.col), *m_filename);
  1946. }
  1947. }
  1948. }
  1949. } else {
  1950. return Value();
  1951. }
  1952. return retval;
  1953. }
  1954. /// Reads a pair of values used to create a map initialization from input
  1955. bool Map_Pair() {
  1956. bool retval = false;
  1957. const auto prev_stack_top = m_match_stack.size();
  1958. const auto prev_pos = m_position;
  1959. if (Operator()) {
  1960. if (Symbol(":")) {
  1961. retval = true;
  1962. if (!Operator()) {
  1963. throw exception::eval_error("Incomplete map pair", File_Position(m_position.line, m_position.col), *m_filename);
  1964. }
  1965. build_match<eval::Map_Pair_AST_Node<Tracer>>(prev_stack_top);
  1966. }
  1967. else {
  1968. m_position = prev_pos;
  1969. while (prev_stack_top != m_match_stack.size()) {
  1970. m_match_stack.pop_back();
  1971. }
  1972. }
  1973. }
  1974. return retval;
  1975. }
  1976. /// Reads a pair of values used to create a range initialization from input
  1977. bool Value_Range() {
  1978. bool retval = false;
  1979. const auto prev_stack_top = m_match_stack.size();
  1980. const auto prev_pos = m_position;
  1981. if (Operator()) {
  1982. if (Symbol("..")) {
  1983. retval = true;
  1984. if (!Operator()) {
  1985. throw exception::eval_error("Incomplete value range", File_Position(m_position.line, m_position.col), *m_filename);
  1986. }
  1987. build_match<eval::Value_Range_AST_Node<Tracer>>(prev_stack_top);
  1988. }
  1989. else {
  1990. m_position = prev_pos;
  1991. while (prev_stack_top != m_match_stack.size()) {
  1992. m_match_stack.pop_back();
  1993. }
  1994. }
  1995. }
  1996. return retval;
  1997. }
  1998. /// Parses a string of binary equation operators
  1999. bool Equation() {
  2000. const auto prev_stack_top = m_match_stack.size();
  2001. using SS = utility::Static_String;
  2002. if (Operator()) {
  2003. for (const auto &sym : {SS{"="}, SS{":="}, SS{"+="}, SS{"-="}, SS{"*="}, SS{"/="}, SS{"%="}, SS{"<<="}, SS{">>="}, SS{"&="}, SS{"^="}, SS{"|="}})
  2004. {
  2005. if (Symbol(sym, true)) {
  2006. SkipWS(true);
  2007. if (!Equation()) {
  2008. throw exception::eval_error("Incomplete equation", File_Position(m_position.line, m_position.col), *m_filename);
  2009. }
  2010. build_match<eval::Equation_AST_Node<Tracer>>(prev_stack_top, sym.c_str());
  2011. return true;
  2012. }
  2013. }
  2014. return true;
  2015. }
  2016. return false;
  2017. }
  2018. /// Parses statements allowed inside of a class block
  2019. bool Class_Statements(const std::string &t_class_name) {
  2020. bool retval = false;
  2021. bool has_more = true;
  2022. bool saw_eol = true;
  2023. while (has_more) {
  2024. const auto start = m_position;
  2025. if (Def(true, t_class_name) || Var_Decl(true, t_class_name)) {
  2026. if (!saw_eol) {
  2027. throw exception::eval_error("Two function definitions missing line separator", File_Position(start.line, start.col), *m_filename);
  2028. }
  2029. has_more = true;
  2030. retval = true;
  2031. saw_eol = true;
  2032. } else if (Eol()) {
  2033. has_more = true;
  2034. retval = true;
  2035. saw_eol = true;
  2036. } else {
  2037. has_more = false;
  2038. }
  2039. }
  2040. return retval;
  2041. }
  2042. /// Top level parser, starts parsing of all known parses
  2043. bool Statements(const bool t_class_allowed = false) {
  2044. bool retval = false;
  2045. bool has_more = true;
  2046. bool saw_eol = true;
  2047. while (has_more) {
  2048. const auto start = m_position;
  2049. if (Def() || Try() || If() || While() || Class(t_class_allowed) || For() || Switch()) {
  2050. if (!saw_eol) {
  2051. throw exception::eval_error("Two function definitions missing line separator", File_Position(start.line, start.col), *m_filename);
  2052. }
  2053. has_more = true;
  2054. retval = true;
  2055. saw_eol = true;
  2056. }
  2057. else if (Return() || Break() || Continue() || Equation()) {
  2058. if (!saw_eol) {
  2059. throw exception::eval_error("Two expressions missing line separator", File_Position(start.line, start.col), *m_filename);
  2060. }
  2061. has_more = true;
  2062. retval = true;
  2063. saw_eol = false;
  2064. }
  2065. else if (Block() || Eol()) {
  2066. has_more = true;
  2067. retval = true;
  2068. saw_eol = true;
  2069. }
  2070. else {
  2071. has_more = false;
  2072. }
  2073. }
  2074. return retval;
  2075. }
  2076. AST_NodePtr parse(const std::string &t_input, const std::string &t_fname) override
  2077. {
  2078. ChaiScript_Parser<Tracer, Optimizer> parser(m_tracer, m_optimizer);
  2079. return parser.parse_internal(t_input, t_fname);
  2080. }
  2081. eval::AST_Node_Impl_Ptr<Tracer> parse_instr_eval(const std::string &t_input)
  2082. {
  2083. auto last_position = m_position;
  2084. auto last_filename = m_filename;
  2085. auto last_match_stack = std::exchange(m_match_stack, decltype(m_match_stack){});
  2086. auto retval = parse_internal(t_input, "instr eval");
  2087. m_position = std::move(last_position);
  2088. m_filename = std::move(last_filename);
  2089. m_match_stack = std::move(last_match_stack);
  2090. return eval::AST_Node_Impl_Ptr<Tracer>(dynamic_cast<eval::AST_Node_Impl<Tracer>*>(retval.release()));
  2091. }
  2092. /// Parses the given input string, tagging parsed ast_nodes with the given m_filename.
  2093. AST_NodePtr parse_internal(const std::string &t_input, std::string t_fname) {
  2094. m_position = Position(t_input.begin(), t_input.end());
  2095. m_filename = std::make_shared<std::string>(std::move(t_fname));
  2096. if ((t_input.size() > 1) && (t_input[0] == '#') && (t_input[1] == '!')) {
  2097. while (m_position.has_more() && (!Eol())) {
  2098. ++m_position;
  2099. }
  2100. }
  2101. if (Statements(true)) {
  2102. if (m_position.has_more()) {
  2103. throw exception::eval_error("Unparsed input", File_Position(m_position.line, m_position.col), *m_filename);
  2104. } else {
  2105. build_match<eval::File_AST_Node<Tracer>>(0);
  2106. }
  2107. } else {
  2108. m_match_stack.push_back(chaiscript::make_unique<eval::AST_Node_Impl<Tracer>, eval::Noop_AST_Node<Tracer>>());
  2109. }
  2110. AST_NodePtr retval(std::move(m_match_stack.front()));
  2111. m_match_stack.clear();
  2112. return retval;
  2113. }
  2114. };
  2115. }
  2116. }
  2117. #if defined(CHAISCRIPT_MSVC) && defined(CHAISCRIPT_PUSHED_MIN_MAX)
  2118. #undef CHAISCRIPT_PUSHED_MIN_MAX
  2119. #pragma pop_macro("min")
  2120. #pragma pop_macro("max")
  2121. #endif
  2122. #endif /* CHAISCRIPT_PARSER_HPP_ */