DataExpression.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218
  1. #include "DataExpression.h"
  2. #include "../../Include/RmlUi/Core/DataModelHandle.h"
  3. #include "../../Include/RmlUi/Core/Event.h"
  4. #include "../../Include/RmlUi/Core/Variant.h"
  5. #include "DataModel.h"
  6. #include <stack>
  7. #ifdef _MSC_VER
  8. #pragma warning(default : 4061)
  9. #pragma warning(default : 4062)
  10. #endif
  11. namespace Rml {
  12. class DataParser;
  13. /*
  14. The abstract machine for RmlUi data expressions.
  15. The machine can execute a program which contains a list of instructions listed below.
  16. The abstract machine has three registers:
  17. R Typically results and right-hand side arguments.
  18. L Typically left-hand side arguments.
  19. And a stack:
  20. S The program stack.
  21. In addition, each instruction has an optional payload:
  22. D Instruction data (payload).
  23. Notation used in the instruction list below:
  24. S+ Push to stack S.
  25. S- Pop stack S (returns the popped value).
  26. */
  27. enum class Instruction {
  28. // clang-format off
  29. // Assignment (register/stack) = Read (register R/L, instruction data D, or stack)
  30. Push = 'P', // S+ = R
  31. Pop = 'o', // <R/L> = S- (D determines R/L)
  32. Literal = 'D', // R = D
  33. Variable = 'V', // R = DataModel.GetVariable(D) (D is an index into the variable address list)
  34. Add = '+', // R = L + R
  35. Subtract = '-', // R = L - R
  36. Multiply = '*', // R = L * R
  37. Divide = '/', // R = L / R
  38. Not = '!', // R = !R
  39. And = '&', // R = L && R
  40. Or = '|', // R = L || R
  41. Less = '<', // R = L < R
  42. LessEq = 'L', // R = L <= R
  43. Greater = '>', // R = L > R
  44. GreaterEq = 'G', // R = L >= R
  45. Equal = '=', // R = L == R
  46. NotEqual = 'N', // R = L != R
  47. NumArguments = '#', // R = D (Contains the num. arguments currently on the stack, immediately followed by a 'T' or 'E' instruction)
  48. TransformFnc = 'T', // R = DataModel.Execute(D, A) where A = S[TOP - R, TOP]; S -= R; (D determines function name, input R the num. arguments, A the arguments)
  49. EventFnc = 'E', // DataModel.EventCallback(D, A); S -= R;
  50. Assign = 'A', // DataModel.SetVariable(D, R)
  51. DynamicVariable = 'Y', // DataModel.GetVariable(DataModel.ParseAddress(R)) (Looks up a variable by path in R)
  52. CastToInt = 'I', // R = (int)R
  53. Jump = 'J', // Jumps to instruction index D
  54. JumpIfZero = 'Z', // If R is false, jumps to instruction index D
  55. // clang-format on
  56. };
  57. enum class Register {
  58. R,
  59. L,
  60. };
  61. struct InstructionData {
  62. Instruction instruction;
  63. Variant data;
  64. };
  65. struct ProgramState {
  66. size_t program_length;
  67. int stack_size;
  68. };
  69. namespace Parse {
  70. static void Assignment(DataParser& parser);
  71. static void Expression(DataParser& parser);
  72. } // namespace Parse
  73. class DataParser {
  74. public:
  75. DataParser(String expression, DataExpressionInterface expression_interface) :
  76. expression(std::move(expression)), expression_interface(expression_interface)
  77. {}
  78. char Look()
  79. {
  80. if (reached_end)
  81. return '\0';
  82. return expression[index];
  83. }
  84. bool Match(char c, bool skip_whitespace = true)
  85. {
  86. if (c == Look())
  87. {
  88. Next();
  89. if (skip_whitespace)
  90. SkipWhitespace();
  91. return true;
  92. }
  93. Expected(c);
  94. return false;
  95. }
  96. char Next()
  97. {
  98. ++index;
  99. if (index >= expression.size())
  100. reached_end = true;
  101. return Look();
  102. }
  103. void SkipWhitespace()
  104. {
  105. char c = Look();
  106. while (StringUtilities::IsWhitespace(c))
  107. c = Next();
  108. }
  109. void Error(const String& message)
  110. {
  111. parse_error = true;
  112. Log::Message(Log::LT_WARNING, "Error in data expression at %zu. %s", index, message.c_str());
  113. Log::Message(Log::LT_WARNING, " \"%s\"", expression.c_str());
  114. const size_t cursor_offset = size_t(index) + 3;
  115. const String cursor_string = String(cursor_offset, ' ') + '^';
  116. Log::Message(Log::LT_WARNING, "%s", cursor_string.c_str());
  117. }
  118. void Expected(const String& expected_symbols)
  119. {
  120. const char c = Look();
  121. if (c == '\0')
  122. Error(CreateString("Expected %s but found end of string.", expected_symbols.c_str()));
  123. else
  124. Error(CreateString("Expected %s but found character '%c'.", expected_symbols.c_str(), c));
  125. }
  126. void Expected(char expected) { Expected(String(1, '\'') + expected + '\''); }
  127. bool Parse(bool is_assignment_expression)
  128. {
  129. program.clear();
  130. variable_addresses.clear();
  131. index = 0;
  132. reached_end = false;
  133. parse_error = false;
  134. if (expression.empty())
  135. reached_end = true;
  136. SkipWhitespace();
  137. if (is_assignment_expression)
  138. Parse::Assignment(*this);
  139. else
  140. Parse::Expression(*this);
  141. if (!reached_end)
  142. {
  143. parse_error = true;
  144. Error(CreateString("Unexpected character '%c' encountered.", Look()));
  145. }
  146. if (!parse_error && program_stack_size != 0)
  147. {
  148. parse_error = true;
  149. Error(CreateString("Internal parser error, inconsistent stack operations. Stack size is %d at parse end.", program_stack_size));
  150. }
  151. return !parse_error;
  152. }
  153. Program ReleaseProgram()
  154. {
  155. RMLUI_ASSERT(!parse_error);
  156. return std::move(program);
  157. }
  158. AddressList ReleaseAddresses()
  159. {
  160. RMLUI_ASSERT(!parse_error);
  161. return std::move(variable_addresses);
  162. }
  163. void Emit(Instruction instruction, Variant data = Variant())
  164. {
  165. RMLUI_ASSERTMSG(instruction != Instruction::Push && instruction != Instruction::Pop && instruction != Instruction::NumArguments &&
  166. instruction != Instruction::TransformFnc && instruction != Instruction::EventFnc && instruction != Instruction::Variable &&
  167. instruction != Instruction::Assign,
  168. "Use Push(), Pop(), Function(), Variable(), and Assign() procedures for stack manipulation and variable instructions.");
  169. program.push_back(InstructionData{instruction, std::move(data)});
  170. }
  171. void Push()
  172. {
  173. program_stack_size += 1;
  174. program.push_back(InstructionData{Instruction::Push, Variant()});
  175. }
  176. void Pop(Register destination)
  177. {
  178. if (program_stack_size <= 0)
  179. {
  180. Error("Internal parser error: Tried to pop an empty stack.");
  181. return;
  182. }
  183. program_stack_size -= 1;
  184. program.push_back(InstructionData{Instruction::Pop, Variant(int(destination))});
  185. }
  186. void Function(Instruction instruction, int num_arguments, String&& name)
  187. {
  188. RMLUI_ASSERT(instruction == Instruction::TransformFnc || instruction == Instruction::EventFnc);
  189. RMLUI_ASSERT(num_arguments >= 0);
  190. if (program_stack_size < num_arguments)
  191. {
  192. Error(CreateString("Internal parser error: Popping %d arguments, but the stack contains only %d elements.", num_arguments,
  193. program_stack_size));
  194. return;
  195. }
  196. program_stack_size -= num_arguments;
  197. program.push_back(InstructionData{Instruction::NumArguments, Variant(int(num_arguments))});
  198. program.push_back(InstructionData{instruction, Variant(std::move(name))});
  199. }
  200. void Variable(const String& data_address) { VariableGetSet(data_address, false); }
  201. void Assign(const String& data_address) { VariableGetSet(data_address, true); }
  202. size_t InstructionIndex() const { return program.size(); }
  203. void PatchInstruction(size_t index, InstructionData data) { program[index] = data; }
  204. ProgramState GetProgramState() { return ProgramState{program.size(), program_stack_size}; }
  205. void SetProgramState(const ProgramState& state)
  206. {
  207. RMLUI_ASSERT(state.program_length <= program.size());
  208. program.resize(state.program_length);
  209. program_stack_size = state.stack_size;
  210. }
  211. bool AddVariableAddress(const String& name)
  212. {
  213. DataAddress address = expression_interface.ParseAddress(name);
  214. if (address.empty())
  215. {
  216. return false;
  217. }
  218. variable_addresses.push_back(std::move(address));
  219. return true;
  220. }
  221. private:
  222. void VariableGetSet(const String& name, bool is_assignment)
  223. {
  224. DataAddress address = expression_interface.ParseAddress(name);
  225. if (address.empty())
  226. {
  227. Error(CreateString("Could not find data variable with name '%s'.", name.c_str()));
  228. return;
  229. }
  230. int index = int(variable_addresses.size());
  231. variable_addresses.push_back(std::move(address));
  232. program.push_back(InstructionData{is_assignment ? Instruction::Assign : Instruction::Variable, Variant(int(index))});
  233. }
  234. const String expression;
  235. DataExpressionInterface expression_interface;
  236. size_t index = 0;
  237. bool reached_end = false;
  238. bool parse_error = true;
  239. int program_stack_size = 0;
  240. Program program;
  241. AddressList variable_addresses;
  242. };
  243. namespace Parse {
  244. // Forward declare all parse functions.
  245. static void Assignment(DataParser& parser);
  246. // The following in order of precedence.
  247. static void Expression(DataParser& parser);
  248. static void Relational(DataParser& parser);
  249. static void Additive(DataParser& parser);
  250. static void Term(DataParser& parser);
  251. static void Factor(DataParser& parser);
  252. static void NumberLiteral(DataParser& parser);
  253. static void StringLiteral(DataParser& parser);
  254. static String VariableExpression(DataParser& parser, const String& address_prefix);
  255. static void VariableOrFunction(DataParser& parser);
  256. static void Add(DataParser& parser);
  257. static void Subtract(DataParser& parser);
  258. static void Multiply(DataParser& parser);
  259. static void Divide(DataParser& parser);
  260. static void Not(DataParser& parser);
  261. static void And(DataParser& parser);
  262. static void Or(DataParser& parser);
  263. static void Less(DataParser& parser);
  264. static void Greater(DataParser& parser);
  265. static void Equal(DataParser& parser);
  266. static void NotEqual(DataParser& parser);
  267. static void Ternary(DataParser& parser);
  268. static void Function(DataParser& parser, Instruction function_type, String&& name, bool first_argument_piped);
  269. // Helper functions
  270. static bool IsVariableCharacter(char c, bool is_first_character)
  271. {
  272. const bool is_alpha = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
  273. if (is_first_character)
  274. return is_alpha;
  275. if (is_alpha || (c >= '0' && c <= '9'))
  276. return true;
  277. for (char valid_char : "_.")
  278. {
  279. if (c == valid_char && valid_char != '\0')
  280. return true;
  281. }
  282. return false;
  283. }
  284. static String VariableOrFunctionName(DataParser& parser, bool* out_valid_function_name)
  285. {
  286. String name;
  287. bool is_first_character = true;
  288. char c = parser.Look();
  289. while (IsVariableCharacter(c, is_first_character))
  290. {
  291. name += c;
  292. c = parser.Next();
  293. is_first_character = false;
  294. }
  295. if (out_valid_function_name)
  296. *out_valid_function_name = (name.find_first_of(". ") == String::npos);
  297. return name;
  298. }
  299. static String FindNumberLiteral(DataParser& parser, bool silent)
  300. {
  301. String str;
  302. bool first_match = false;
  303. bool has_dot = false;
  304. char c = parser.Look();
  305. if (c == '-')
  306. {
  307. str += c;
  308. c = parser.Next();
  309. }
  310. while ((c >= '0' && c <= '9') || (c == '.' && !has_dot))
  311. {
  312. first_match = true;
  313. str += c;
  314. if (c == '.')
  315. has_dot = true;
  316. c = parser.Next();
  317. }
  318. if (!first_match)
  319. {
  320. if (!silent)
  321. parser.Error(CreateString("Invalid number literal. Expected '0-9' or '.' but found '%c'.", c));
  322. return String();
  323. }
  324. return str;
  325. }
  326. // Parser functions
  327. static void Assignment(DataParser& parser)
  328. {
  329. bool looping = true;
  330. while (looping)
  331. {
  332. if (parser.Look() != '\0')
  333. {
  334. String variable_name = VariableOrFunctionName(parser, nullptr);
  335. if (variable_name.empty())
  336. {
  337. parser.Error("Expected a variable for assignment but got an empty name.");
  338. return;
  339. }
  340. parser.SkipWhitespace();
  341. const char c = parser.Look();
  342. if (c == '=')
  343. {
  344. parser.Match('=');
  345. Expression(parser);
  346. parser.Assign(variable_name);
  347. }
  348. else if (c == '(' || c == ';' || c == '\0')
  349. {
  350. Function(parser, Instruction::EventFnc, std::move(variable_name), false);
  351. }
  352. else
  353. {
  354. parser.Expected("one of = ; ( or end of string");
  355. return;
  356. }
  357. }
  358. const char c = parser.Look();
  359. if (c == ';')
  360. parser.Match(';');
  361. else if (c == '\0')
  362. looping = false;
  363. else
  364. {
  365. parser.Expected("';' or end of string");
  366. looping = false;
  367. }
  368. }
  369. }
  370. static void Expression(DataParser& parser)
  371. {
  372. Relational(parser);
  373. bool looping = true;
  374. while (looping)
  375. {
  376. switch (parser.Look())
  377. {
  378. case '&': And(parser); break;
  379. case '|':
  380. {
  381. parser.Match('|', false);
  382. if (parser.Look() == '|')
  383. Or(parser);
  384. else
  385. {
  386. parser.Push();
  387. parser.SkipWhitespace();
  388. bool valid_function_name = true;
  389. String name = VariableOrFunctionName(parser, &valid_function_name);
  390. if (name.empty())
  391. {
  392. parser.Error("Expected a transform function name but got an empty name.");
  393. return;
  394. }
  395. if (!valid_function_name)
  396. {
  397. parser.Error("Expected a transform function name but got an invalid name '" + name + "'.");
  398. return;
  399. }
  400. Function(parser, Instruction::TransformFnc, std::move(name), true);
  401. }
  402. }
  403. break;
  404. case '?': Ternary(parser); break;
  405. default: looping = false;
  406. }
  407. }
  408. }
  409. static void Relational(DataParser& parser)
  410. {
  411. Additive(parser);
  412. bool looping = true;
  413. while (looping)
  414. {
  415. switch (parser.Look())
  416. {
  417. case '=': Equal(parser); break;
  418. case '!': NotEqual(parser); break;
  419. case '<': Less(parser); break;
  420. case '>': Greater(parser); break;
  421. default: looping = false;
  422. }
  423. }
  424. }
  425. static void Additive(DataParser& parser)
  426. {
  427. Term(parser);
  428. bool looping = true;
  429. while (looping)
  430. {
  431. switch (parser.Look())
  432. {
  433. case '+': Add(parser); break;
  434. case '-': Subtract(parser); break;
  435. default: looping = false;
  436. }
  437. }
  438. }
  439. static void Term(DataParser& parser)
  440. {
  441. Factor(parser);
  442. bool looping = true;
  443. while (looping)
  444. {
  445. switch (parser.Look())
  446. {
  447. case '*': Multiply(parser); break;
  448. case '/': Divide(parser); break;
  449. default: looping = false;
  450. }
  451. }
  452. }
  453. static void Factor(DataParser& parser)
  454. {
  455. const char c = parser.Look();
  456. if (c == '(')
  457. {
  458. parser.Match('(');
  459. Expression(parser);
  460. parser.Match(')');
  461. }
  462. else if (c == '\'')
  463. {
  464. parser.Match('\'', false);
  465. StringLiteral(parser);
  466. parser.Match('\'');
  467. }
  468. else if (c == '!')
  469. {
  470. Not(parser);
  471. parser.SkipWhitespace();
  472. }
  473. else if (c == '-' || (c >= '0' && c <= '9'))
  474. {
  475. NumberLiteral(parser);
  476. parser.SkipWhitespace();
  477. }
  478. else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
  479. {
  480. VariableOrFunction(parser);
  481. parser.SkipWhitespace();
  482. }
  483. else
  484. parser.Expected("literal, variable name, function name, parenthesis, or '!'");
  485. }
  486. static void NumberLiteral(DataParser& parser)
  487. {
  488. String str = FindNumberLiteral(parser, false);
  489. if (str.empty())
  490. return;
  491. const double number = FromString(str, 0.0);
  492. parser.Emit(Instruction::Literal, Variant(number));
  493. }
  494. static void StringLiteral(DataParser& parser)
  495. {
  496. String str;
  497. char c = parser.Look();
  498. char c_prev = '\0';
  499. while (c != '\0' && (c != '\'' || c_prev == '\\'))
  500. {
  501. if (c_prev == '\\' && (c == '\\' || c == '\''))
  502. {
  503. str.pop_back();
  504. c_prev = '\0';
  505. }
  506. else
  507. {
  508. c_prev = c;
  509. }
  510. str += c;
  511. c = parser.Next();
  512. }
  513. parser.Emit(Instruction::Literal, Variant(str));
  514. }
  515. static String VariableExpression(DataParser& parser, const String& address_prefix)
  516. {
  517. if (parser.Look() == '[')
  518. {
  519. parser.Next();
  520. String prefix = address_prefix;
  521. prefix.push_back('[');
  522. // Backup program state before trying to parse number inside brackets.
  523. // Could turn out to be expression and needs reparsing
  524. auto backup_state = parser.GetProgramState();
  525. String index = FindNumberLiteral(parser, true);
  526. if (!index.empty() && parser.Look() == ']')
  527. {
  528. parser.Next();
  529. prefix.append(index);
  530. prefix.push_back(']');
  531. return VariableExpression(parser, prefix);
  532. }
  533. else
  534. {
  535. parser.SetProgramState(backup_state);
  536. parser.Emit(Instruction::Literal, Variant(prefix));
  537. parser.Push();
  538. Expression(parser);
  539. parser.Emit(Instruction::CastToInt);
  540. parser.Push();
  541. parser.Match(']');
  542. VariableExpression(parser, "]");
  543. parser.Pop(Register::L);
  544. parser.Emit(Instruction::Add, Variant());
  545. parser.Pop(Register::L);
  546. parser.Emit(Instruction::Add, Variant());
  547. return "";
  548. }
  549. }
  550. else if (parser.Look() == '.')
  551. {
  552. parser.Next();
  553. return VariableExpression(parser, address_prefix + ".");
  554. }
  555. else
  556. {
  557. String next = VariableOrFunctionName(parser, nullptr);
  558. if (next.empty())
  559. {
  560. if (!address_prefix.empty())
  561. parser.Emit(Instruction::Literal, Variant(address_prefix));
  562. return address_prefix;
  563. }
  564. return VariableExpression(parser, address_prefix + next);
  565. }
  566. }
  567. static void VariableOrFunction(DataParser& parser)
  568. {
  569. bool valid_function_name = true;
  570. String name = VariableOrFunctionName(parser, &valid_function_name);
  571. if (name.empty())
  572. {
  573. parser.Error("Expected a variable or function name but got an empty name.");
  574. return;
  575. }
  576. // Keywords are parsed like variables, but are really literals. Check for them here.
  577. if (name == "true")
  578. parser.Emit(Instruction::Literal, Variant(true));
  579. else if (name == "false")
  580. parser.Emit(Instruction::Literal, Variant(false));
  581. else if (parser.Look() == '(')
  582. {
  583. if (!valid_function_name)
  584. {
  585. parser.Error("Invalid function name '" + name + "'.");
  586. return;
  587. }
  588. Function(parser, Instruction::TransformFnc, std::move(name), false);
  589. }
  590. else if (parser.Look() == '[')
  591. {
  592. // Backup program state before trying to parse part inside brackets.
  593. // Could turn out to be expression and needs reparsing
  594. auto backup_state = parser.GetProgramState();
  595. String full_address = VariableExpression(parser, name);
  596. if (!full_address.empty())
  597. {
  598. parser.SetProgramState(backup_state);
  599. parser.Variable(full_address);
  600. }
  601. else
  602. {
  603. // add the root of a variable expression as dependency into the address list
  604. parser.AddVariableAddress(name);
  605. parser.Emit(Instruction::DynamicVariable, Variant());
  606. }
  607. }
  608. else
  609. parser.Variable(name);
  610. }
  611. static void Add(DataParser& parser)
  612. {
  613. parser.Match('+');
  614. parser.Push();
  615. Term(parser);
  616. parser.Pop(Register::L);
  617. parser.Emit(Instruction::Add);
  618. }
  619. static void Subtract(DataParser& parser)
  620. {
  621. parser.Match('-');
  622. parser.Push();
  623. Term(parser);
  624. parser.Pop(Register::L);
  625. parser.Emit(Instruction::Subtract);
  626. }
  627. static void Multiply(DataParser& parser)
  628. {
  629. parser.Match('*');
  630. parser.Push();
  631. Factor(parser);
  632. parser.Pop(Register::L);
  633. parser.Emit(Instruction::Multiply);
  634. }
  635. static void Divide(DataParser& parser)
  636. {
  637. parser.Match('/');
  638. parser.Push();
  639. Factor(parser);
  640. parser.Pop(Register::L);
  641. parser.Emit(Instruction::Divide);
  642. }
  643. static void Not(DataParser& parser)
  644. {
  645. parser.Match('!');
  646. Factor(parser);
  647. parser.Emit(Instruction::Not);
  648. }
  649. static void Or(DataParser& parser)
  650. {
  651. // We already skipped the first '|' during expression
  652. parser.Match('|');
  653. parser.Push();
  654. Relational(parser);
  655. parser.Pop(Register::L);
  656. parser.Emit(Instruction::Or);
  657. }
  658. static void And(DataParser& parser)
  659. {
  660. parser.Match('&', false);
  661. parser.Match('&');
  662. parser.Push();
  663. Relational(parser);
  664. parser.Pop(Register::L);
  665. parser.Emit(Instruction::And);
  666. }
  667. static void Less(DataParser& parser)
  668. {
  669. Instruction instruction = Instruction::Less;
  670. parser.Match('<', false);
  671. if (parser.Look() == '=')
  672. {
  673. parser.Match('=');
  674. instruction = Instruction::LessEq;
  675. }
  676. else
  677. {
  678. parser.SkipWhitespace();
  679. }
  680. parser.Push();
  681. Additive(parser);
  682. parser.Pop(Register::L);
  683. parser.Emit(instruction);
  684. }
  685. static void Greater(DataParser& parser)
  686. {
  687. Instruction instruction = Instruction::Greater;
  688. parser.Match('>', false);
  689. if (parser.Look() == '=')
  690. {
  691. parser.Match('=');
  692. instruction = Instruction::GreaterEq;
  693. }
  694. else
  695. {
  696. parser.SkipWhitespace();
  697. }
  698. parser.Push();
  699. Additive(parser);
  700. parser.Pop(Register::L);
  701. parser.Emit(instruction);
  702. }
  703. static void Equal(DataParser& parser)
  704. {
  705. parser.Match('=', false);
  706. parser.Match('=');
  707. parser.Push();
  708. Additive(parser);
  709. parser.Pop(Register::L);
  710. parser.Emit(Instruction::Equal);
  711. }
  712. static void NotEqual(DataParser& parser)
  713. {
  714. parser.Match('!', false);
  715. parser.Match('=');
  716. parser.Push();
  717. Additive(parser);
  718. parser.Pop(Register::L);
  719. parser.Emit(Instruction::NotEqual);
  720. }
  721. static void Ternary(DataParser& parser)
  722. {
  723. size_t jump_false_branch = parser.InstructionIndex();
  724. parser.Emit(Instruction::JumpIfZero);
  725. parser.Match('?');
  726. Expression(parser);
  727. size_t jump_end = parser.InstructionIndex();
  728. parser.Emit(Instruction::Jump);
  729. parser.Match(':');
  730. size_t false_branch = parser.InstructionIndex();
  731. Expression(parser);
  732. size_t end = parser.InstructionIndex();
  733. parser.PatchInstruction(jump_false_branch, InstructionData{Instruction::JumpIfZero, Variant((uint64_t)false_branch)});
  734. parser.PatchInstruction(jump_end, InstructionData{Instruction::Jump, Variant((uint64_t)end)});
  735. }
  736. static void Function(DataParser& parser, Instruction function_type, String&& func_name, bool first_argument_piped)
  737. {
  738. RMLUI_ASSERT(function_type == Instruction::TransformFnc || function_type == Instruction::EventFnc);
  739. // We already matched the variable name, and also pushed the first argument to the stack if it was piped using '|'.
  740. int num_arguments = first_argument_piped ? 1 : 0;
  741. if (parser.Look() == '(')
  742. {
  743. bool looping = true;
  744. parser.Match('(');
  745. if (parser.Look() == ')')
  746. {
  747. parser.Match(')');
  748. looping = false;
  749. }
  750. while (looping)
  751. {
  752. num_arguments += 1;
  753. Expression(parser);
  754. parser.Push();
  755. switch (parser.Look())
  756. {
  757. case ')':
  758. parser.Match(')');
  759. looping = false;
  760. break;
  761. case ',': parser.Match(','); break;
  762. default:
  763. parser.Expected("one of ')' or ','");
  764. looping = false;
  765. break;
  766. }
  767. }
  768. }
  769. else
  770. {
  771. parser.SkipWhitespace();
  772. }
  773. parser.Function(function_type, num_arguments, std::move(func_name));
  774. }
  775. } // namespace Parse
  776. static String DumpProgram(const Program& program)
  777. {
  778. String str;
  779. for (size_t i = 0; i < program.size(); i++)
  780. {
  781. String instruction_str = program[i].data.Get<String>();
  782. str += CreateString(" %4zu '%c' %s\n", i, char(program[i].instruction), instruction_str.c_str());
  783. }
  784. return str;
  785. }
  786. class DataInterpreter {
  787. public:
  788. DataInterpreter(const Program& program, const AddressList& addresses, DataExpressionInterface expression_interface) :
  789. program(program), addresses(addresses), expression_interface(expression_interface)
  790. {}
  791. bool Error(const String& message) const
  792. {
  793. Log::Message(Log::LT_WARNING, "Error during execution. %s", message.c_str());
  794. RMLUI_ERROR;
  795. return false;
  796. }
  797. bool Run()
  798. {
  799. bool success = true;
  800. size_t i = 0;
  801. while (i < program.size())
  802. {
  803. size_t next_instruction = i + 1;
  804. if (!Execute(program[i].instruction, program[i].data, next_instruction))
  805. {
  806. success = false;
  807. break;
  808. }
  809. i = next_instruction;
  810. }
  811. if (success && !stack.empty())
  812. Log::Message(Log::LT_WARNING, "Possible data interpreter stack corruption. Stack size is %zu at end of execution (should be zero).",
  813. stack.size());
  814. if (!success)
  815. {
  816. String program_str = DumpProgram(program);
  817. Log::Message(Log::LT_WARNING, "Failed to execute program with %zu instructions:", program.size());
  818. Log::Message(Log::LT_WARNING, "%s", program_str.c_str());
  819. }
  820. return success;
  821. }
  822. Variant Result() const { return R; }
  823. private:
  824. Variant R, L;
  825. Vector<Variant> stack;
  826. const Program& program;
  827. const AddressList& addresses;
  828. DataExpressionInterface expression_interface;
  829. bool Execute(const Instruction instruction, const Variant& data, size_t& next_instruction)
  830. {
  831. auto AnyString = [](const Variant& v1, const Variant& v2) { return v1.GetType() == Variant::STRING || v2.GetType() == Variant::STRING; };
  832. switch (instruction)
  833. {
  834. case Instruction::Push:
  835. {
  836. stack.push_back(std::move(R));
  837. R.Clear();
  838. }
  839. break;
  840. case Instruction::Pop:
  841. {
  842. if (stack.empty())
  843. return Error("Cannot pop stack, it is empty.");
  844. Register reg = Register(data.Get<int>(-1));
  845. switch (reg)
  846. {
  847. // clang-format off
  848. case Register::R: R = stack.back(); stack.pop_back(); break;
  849. case Register::L: L = stack.back(); stack.pop_back(); break;
  850. // clang-format on
  851. default: return Error(CreateString("Invalid register %d.", int(reg)));
  852. }
  853. }
  854. break;
  855. case Instruction::Literal:
  856. {
  857. R = data;
  858. }
  859. break;
  860. case Instruction::DynamicVariable:
  861. {
  862. auto str = R.Get<String>();
  863. auto address = expression_interface.ParseAddress(str);
  864. if (address.empty())
  865. return Error("Variable address not found.");
  866. R = expression_interface.GetValue(address);
  867. }
  868. break;
  869. case Instruction::Variable:
  870. {
  871. size_t variable_index = size_t(data.Get<int>(-1));
  872. if (variable_index < addresses.size())
  873. R = expression_interface.GetValue(addresses[variable_index]);
  874. else
  875. return Error("Variable address not found.");
  876. }
  877. break;
  878. case Instruction::Add:
  879. {
  880. if (AnyString(L, R))
  881. R = Variant(L.Get<String>() + R.Get<String>());
  882. else
  883. R = Variant(L.Get<double>() + R.Get<double>());
  884. }
  885. break;
  886. // clang-format off
  887. case Instruction::Subtract: R = Variant(L.Get<double>() - R.Get<double>()); break;
  888. case Instruction::Multiply: R = Variant(L.Get<double>() * R.Get<double>()); break;
  889. case Instruction::Divide: R = Variant(L.Get<double>() / R.Get<double>()); break;
  890. case Instruction::Not: R = Variant(!R.Get<bool>()); break;
  891. case Instruction::And: R = Variant(L.Get<bool>() && R.Get<bool>()); break;
  892. case Instruction::Or: R = Variant(L.Get<bool>() || R.Get<bool>()); break;
  893. case Instruction::Less: R = Variant(L.Get<double>() < R.Get<double>()); break;
  894. case Instruction::LessEq: R = Variant(L.Get<double>() <= R.Get<double>()); break;
  895. case Instruction::Greater: R = Variant(L.Get<double>() > R.Get<double>()); break;
  896. case Instruction::GreaterEq: R = Variant(L.Get<double>() >= R.Get<double>()); break;
  897. // clang-format on
  898. case Instruction::Equal:
  899. {
  900. if (AnyString(L, R))
  901. R = Variant(L.Get<String>() == R.Get<String>());
  902. else
  903. R = Variant(L.Get<double>() == R.Get<double>());
  904. }
  905. break;
  906. case Instruction::NotEqual:
  907. {
  908. if (AnyString(L, R))
  909. R = Variant(L.Get<String>() != R.Get<String>());
  910. else
  911. R = Variant(L.Get<double>() != R.Get<double>());
  912. }
  913. break;
  914. case Instruction::NumArguments:
  915. {
  916. const int num_arguments = data.Get<int>(-1);
  917. R = num_arguments;
  918. }
  919. break;
  920. case Instruction::TransformFnc:
  921. case Instruction::EventFnc:
  922. {
  923. Vector<Variant> arguments;
  924. if (!ExtractArgumentsFromStack(arguments))
  925. return false;
  926. const String function_name = data.Get<String>();
  927. const bool result = (instruction == Instruction::TransformFnc ? expression_interface.CallTransform(function_name, arguments, R)
  928. : expression_interface.EventCallback(function_name, arguments));
  929. if (!result)
  930. {
  931. String arguments_str;
  932. for (size_t i = 0; i < arguments.size(); i++)
  933. {
  934. arguments_str += arguments[i].Get<String>();
  935. if (i < arguments.size() - 1)
  936. arguments_str += ", ";
  937. }
  938. return Error(
  939. CreateString("Failed to execute %s: %s(%s)", instruction == Instruction::TransformFnc ? "transform function" : "event callback",
  940. function_name.c_str(), arguments_str.c_str()));
  941. }
  942. }
  943. break;
  944. case Instruction::Assign:
  945. {
  946. size_t variable_index = size_t(data.Get<int>(-1));
  947. if (variable_index < addresses.size())
  948. {
  949. if (!expression_interface.SetValue(addresses[variable_index], R))
  950. return Error("Could not assign to variable.");
  951. }
  952. else
  953. return Error("Variable address not found.");
  954. }
  955. break;
  956. case Instruction::CastToInt:
  957. {
  958. int tmp;
  959. if (!R.GetInto(tmp))
  960. return Error("Could not cast value to int.");
  961. else
  962. R = tmp;
  963. }
  964. break;
  965. case Instruction::JumpIfZero:
  966. {
  967. if (!R.Get<bool>())
  968. next_instruction = data.Get<size_t>(0);
  969. }
  970. break;
  971. case Instruction::Jump:
  972. {
  973. next_instruction = data.Get<size_t>(0);
  974. }
  975. break;
  976. default: RMLUI_ERRORMSG("Instruction not implemented."); break;
  977. }
  978. return true;
  979. }
  980. bool ExtractArgumentsFromStack(Vector<Variant>& out_arguments)
  981. {
  982. int num_arguments = R.Get<int>(-1);
  983. if (num_arguments < 0)
  984. return Error("Invalid number of arguments.");
  985. if (stack.size() < size_t(num_arguments))
  986. return Error(CreateString("Cannot pop %d arguments, stack contains only %zu elements.", num_arguments, stack.size()));
  987. const auto it_stack_begin_arguments = stack.end() - num_arguments;
  988. out_arguments.insert(out_arguments.end(), std::make_move_iterator(it_stack_begin_arguments), std::make_move_iterator(stack.end()));
  989. stack.erase(it_stack_begin_arguments, stack.end());
  990. return true;
  991. }
  992. };
  993. DataExpression::DataExpression(String expression) : expression(std::move(expression)) {}
  994. DataExpression::~DataExpression() {}
  995. bool DataExpression::Parse(const DataExpressionInterface& expression_interface, bool is_assignment_expression)
  996. {
  997. DataParser parser(expression, expression_interface);
  998. if (!parser.Parse(is_assignment_expression))
  999. return false;
  1000. program = parser.ReleaseProgram();
  1001. addresses = parser.ReleaseAddresses();
  1002. return true;
  1003. }
  1004. bool DataExpression::Run(const DataExpressionInterface& expression_interface, Variant& out_value)
  1005. {
  1006. DataInterpreter interpreter(program, addresses, expression_interface);
  1007. if (!interpreter.Run())
  1008. return false;
  1009. out_value = interpreter.Result();
  1010. return true;
  1011. }
  1012. StringList DataExpression::GetVariableNameList() const
  1013. {
  1014. StringList list;
  1015. list.reserve(addresses.size());
  1016. for (const DataAddress& address : addresses)
  1017. {
  1018. if (!address.empty())
  1019. list.push_back(address[0].name);
  1020. }
  1021. return list;
  1022. }
  1023. DataExpressionInterface::DataExpressionInterface(DataModel* data_model, Element* element, Event* event) :
  1024. data_model(data_model), element(element), event(event)
  1025. {}
  1026. DataAddress DataExpressionInterface::ParseAddress(const String& address_str) const
  1027. {
  1028. if (address_str.size() >= 4 && address_str[0] == 'e' && address_str[1] == 'v' && address_str[2] == '.')
  1029. return DataAddress{DataAddressEntry("ev"), DataAddressEntry(address_str.substr(3))};
  1030. return data_model ? data_model->ResolveAddress(address_str, element) : DataAddress();
  1031. }
  1032. Variant DataExpressionInterface::GetValue(const DataAddress& address) const
  1033. {
  1034. Variant result;
  1035. if (event && address.size() == 2 && address.front().name == "ev")
  1036. {
  1037. auto& parameters = event->GetParameters();
  1038. auto it = parameters.find(address.back().name);
  1039. if (it != parameters.end())
  1040. result = it->second;
  1041. }
  1042. else if (data_model)
  1043. {
  1044. data_model->GetVariableInto(address, result);
  1045. }
  1046. return result;
  1047. }
  1048. bool DataExpressionInterface::SetValue(const DataAddress& address, const Variant& value) const
  1049. {
  1050. bool result = false;
  1051. if (data_model && !address.empty())
  1052. {
  1053. if (DataVariable variable = data_model->GetVariable(address))
  1054. result = variable.Set(value);
  1055. if (result)
  1056. data_model->DirtyVariable(address.front().name);
  1057. }
  1058. return result;
  1059. }
  1060. bool DataExpressionInterface::CallTransform(const String& name, const VariantList& arguments, Variant& out_result)
  1061. {
  1062. return data_model ? data_model->CallTransform(name, arguments, out_result) : false;
  1063. }
  1064. bool DataExpressionInterface::EventCallback(const String& name, const VariantList& arguments)
  1065. {
  1066. if (!data_model || !event)
  1067. return false;
  1068. const DataEventFunc* func = data_model->GetEventCallback(name);
  1069. if (!func || !*func)
  1070. return false;
  1071. DataModelHandle handle(data_model);
  1072. func->operator()(handle, *event, arguments);
  1073. return true;
  1074. }
  1075. } // namespace Rml