operators.hpp
Go to the documentation of this file.
1 /* Copyright (C) 2022 Davide Faconti - All Rights Reserved
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
4 * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
5 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
10 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11 */
12 
13 #pragma once
14 
15 #include <cmath>
16 #include <memory>
17 #include <string>
18 #include <vector>
19 
22 
23 // Naive implementation of an AST with simple evaluation function.
24 namespace BT::Ast
25 {
27 
28 using expr_ptr = std::shared_ptr<struct ExprBase>;
29 
30 // extended strin to number that consider enums and booleans
31 inline double StringToDouble(const Any& value, const Environment& env)
32 {
33  const auto str = value.cast<std::string>();
34  if(str == "true")
35  {
36  return 1.0;
37  }
38  if(str == "false")
39  {
40  return 0.0;
41  }
42  if(env.enums)
43  {
44  auto it = env.enums->find(str);
45  if(it != env.enums->end())
46  {
47  return it->second;
48  }
49  }
50  return value.cast<double>();
51 }
52 
53 struct ExprBase
54 {
55  using Ptr = std::shared_ptr<ExprBase>;
56 
57  virtual ~ExprBase() = default;
58  virtual Any evaluate(Environment& env) const = 0;
59 };
60 
61 inline std::string ErrorNotInit(const char* side, const char* op_str)
62 {
63  return StrCat("The ", side, " operand of the operator [", op_str,
64  "] is not initialized");
65 }
66 
68 {
70 
72  {}
73 
74  Any evaluate(Environment&) const override
75  {
76  return value;
77  }
78 };
79 
81 {
82  std::string name;
83 
84  explicit ExprName(std::string n) : name(LEXY_MOV(n))
85  {}
86 
87  Any evaluate(Environment& env) const override
88  {
89  //search first in the enums table
90  if(env.enums)
91  {
92  auto enum_ptr = env.enums->find(name);
93  if(enum_ptr != env.enums->end())
94  {
95  return Any(double(enum_ptr->second));
96  }
97  }
98  // search now in the variables table
99  auto any_ref = env.vars->getAnyLocked(name);
100  if(!any_ref)
101  {
102  throw RuntimeError(StrCat("Variable not found: ", name));
103  }
104  return *any_ref.get();
105  }
106 };
107 
109 {
110  enum op_t
111  {
115  } op;
117 
119  {}
120 
121  Any evaluate(Environment& env) const override
122  {
123  auto rhs_v = rhs->evaluate(env);
124  if(rhs_v.isNumber())
125  {
126  const double rv = rhs_v.cast<double>();
127  switch(op)
128  {
129  case negate:
130  return Any(-rv);
131  case complement:
132  if(rv > static_cast<double>(std::numeric_limits<int64_t>::max()) ||
133  rv < static_cast<double>(std::numeric_limits<int64_t>::min()))
134  {
135  throw RuntimeError("Number out of range for bitwise operation");
136  }
137  return Any(static_cast<double>(~static_cast<int64_t>(rv)));
138  case logical_not:
139  return Any(static_cast<double>(!static_cast<bool>(rv)));
140  }
141  }
142  else if(rhs_v.isString())
143  {
144  throw RuntimeError("Invalid operator for std::string");
145  }
146  throw RuntimeError("ExprUnaryArithmetic: undefined");
147  }
148 };
149 
151 {
152  enum op_t
153  {
159 
163 
166  } op;
167 
168  const char* opStr() const
169  {
170  switch(op)
171  {
172  case plus:
173  return "+";
174  case minus:
175  return "-";
176  case times:
177  return "*";
178  case div:
179  return "/";
180  case concat:
181  return "..";
182  case bit_and:
183  return "&";
184  case bit_or:
185  return "|";
186  case bit_xor:
187  return "^";
188  case logic_and:
189  return "&&";
190  case logic_or:
191  return "||";
192  }
193  return "";
194  }
195 
197 
199  : op(op), lhs(LEXY_MOV(lhs)), rhs(LEXY_MOV(rhs))
200  {}
201 
202  Any evaluate(Environment& env) const override
203  {
204  auto lhs_v = lhs->evaluate(env);
205  auto rhs_v = rhs->evaluate(env);
206 
207  if(lhs_v.empty())
208  {
209  throw RuntimeError(ErrorNotInit("left", opStr()));
210  }
211  if(rhs_v.empty())
212  {
213  throw RuntimeError(ErrorNotInit("right", opStr()));
214  }
215 
216  if(rhs_v.isNumber() && lhs_v.isNumber())
217  {
218  auto lv = lhs_v.cast<double>();
219  auto rv = rhs_v.cast<double>();
220 
221  switch(op)
222  {
223  case plus:
224  return Any(lv + rv);
225  case minus:
226  return Any(lv - rv);
227  case times:
228  return Any(lv * rv);
229  case div:
230  return Any(lv / rv);
231  default: {
232  }
233  }
234 
235  if(op == bit_and || op == bit_or || op == bit_xor)
236  {
237  try
238  {
239  int64_t li = lhs_v.cast<int64_t>();
240  int64_t ri = rhs_v.cast<int64_t>();
241  switch(op)
242  {
243  case bit_and:
244  return Any(static_cast<double>(li & ri));
245  case bit_or:
246  return Any(static_cast<double>(li | ri));
247  case bit_xor:
248  return Any(static_cast<double>(li ^ ri));
249  default: {
250  }
251  }
252  }
253  catch(...)
254  {
255  throw RuntimeError("Binary operators are not allowed if "
256  "one of the operands is not an integer");
257  }
258  }
259 
260  if(op == logic_or || op == logic_and)
261  {
262  try
263  {
264  auto lb = lhs_v.cast<bool>();
265  auto rb = rhs_v.cast<bool>();
266  switch(op)
267  {
268  case logic_or:
269  return Any(static_cast<double>(lb || rb));
270  case logic_and:
271  return Any(static_cast<double>(lb && rb));
272  default: {
273  }
274  }
275  }
276  catch(...)
277  {
278  throw RuntimeError("Logic operators are not allowed if "
279  "one of the operands is not castable to bool");
280  }
281  }
282  }
283  else if(rhs_v.isString() && lhs_v.isString() && op == plus)
284  {
285  return Any(lhs_v.cast<std::string>() + rhs_v.cast<std::string>());
286  }
287  else if(op == concat && ((rhs_v.isString() && lhs_v.isString()) ||
288  (rhs_v.isString() && lhs_v.isNumber()) ||
289  (rhs_v.isNumber() && lhs_v.isString())))
290  {
291  return Any(lhs_v.cast<std::string>() + rhs_v.cast<std::string>());
292  }
293  else
294  {
295  throw RuntimeError("Operation not permitted");
296  }
297 
298  return {}; // unreachable
299  }
300 };
301 
302 template <typename T>
303 bool IsSame(const T& lv, const T& rv)
304 {
305  if constexpr(std::is_same_v<double, T>)
306  {
307  constexpr double EPS = static_cast<double>(std::numeric_limits<float>::epsilon());
308  return std::abs(lv - rv) <= EPS;
309  }
310  else
311  {
312  return (lv == rv);
313  }
314 }
315 
317 {
318  enum op_t
319  {
326  };
327 
328  const char* opStr(op_t op) const
329  {
330  switch(op)
331  {
332  case equal:
333  return "==";
334  case not_equal:
335  return "!=";
336  case less:
337  return "<";
338  case greater:
339  return ">";
340  case less_equal:
341  return "<=";
342  case greater_equal:
343  return ">=";
344  }
345  return "";
346  }
347 
348  std::vector<op_t> ops;
349  std::vector<expr_ptr> operands;
350 
351  Any evaluate(Environment& env) const override
352  {
353  auto SwitchImpl = [&](const auto& lv, const auto& rv, op_t op) {
354  switch(op)
355  {
356  case equal:
357  if(!IsSame(lv, rv))
358  return false;
359  break;
360  case not_equal:
361  if(IsSame(lv, rv))
362  return false;
363  break;
364  case less:
365  if(lv >= rv)
366  return false;
367  break;
368  case greater:
369  if(lv <= rv)
370  return false;
371  break;
372  case less_equal:
373  if(lv > rv)
374  return false;
375  break;
376  case greater_equal:
377  if(lv < rv)
378  return false;
379  break;
380  }
381  return true;
382  };
383 
384  auto lhs_v = operands[0]->evaluate(env);
385  for(auto i = 0u; i != ops.size(); ++i)
386  {
387  auto rhs_v = operands[i + 1]->evaluate(env);
388 
389  if(lhs_v.empty())
390  {
391  throw RuntimeError(ErrorNotInit("left", opStr(ops[i])));
392  }
393  if(rhs_v.empty())
394  {
395  throw RuntimeError(ErrorNotInit("right", opStr(ops[i])));
396  }
397  const Any False(0.0);
398 
399  if(lhs_v.isNumber() && rhs_v.isNumber())
400  {
401  auto lv = lhs_v.cast<double>();
402  auto rv = rhs_v.cast<double>();
403  if(!SwitchImpl(lv, rv, ops[i]))
404  {
405  return False;
406  }
407  }
408  else if(lhs_v.isString() && rhs_v.isString())
409  {
410  auto lv = lhs_v.cast<SimpleString>();
411  auto rv = rhs_v.cast<SimpleString>();
412  if(!SwitchImpl(lv, rv, ops[i]))
413  {
414  return False;
415  }
416  }
417  else if(lhs_v.isString() && rhs_v.isNumber())
418  {
419  auto lv = StringToDouble(lhs_v, env);
420  auto rv = rhs_v.cast<double>();
421  if(!SwitchImpl(lv, rv, ops[i]))
422  {
423  return False;
424  }
425  }
426  else if(lhs_v.isNumber() && rhs_v.isString())
427  {
428  auto lv = lhs_v.cast<double>();
429  auto rv = StringToDouble(rhs_v, env);
430  if(!SwitchImpl(lv, rv, ops[i]))
431  {
432  return False;
433  }
434  }
435  else
436  {
437  throw RuntimeError(StrCat("Can't mix different types in Comparison. "
438  "Left operand [",
439  BT::demangle(lhs_v.type()), "] right operand [",
440  BT::demangle(rhs_v.type()), "]"));
441  }
442  lhs_v = rhs_v;
443  }
444  return Any(1.0);
445  }
446 };
447 
448 struct ExprIf : ExprBase
449 {
451 
454  {}
455 
456  Any evaluate(Environment& env) const override
457  {
458  const auto& v = condition->evaluate(env);
459  bool valid = (v.isType<SimpleString>() && v.cast<SimpleString>().size() > 0) ||
460  (v.cast<double>() != 0.0);
461  if(valid)
462  {
463  return then->evaluate(env);
464  }
465  else
466  {
467  return else_->evaluate(env);
468  }
469  }
470 };
471 
473 {
474  enum op_t
475  {
482  } op;
483 
484  const char* opStr() const
485  {
486  switch(op)
487  {
488  case assign_create:
489  return ":=";
490  case assign_existing:
491  return "=";
492  case assign_plus:
493  return "+=";
494  case assign_minus:
495  return "-=";
496  case assign_times:
497  return "*=";
498  case assign_div:
499  return "/=";
500  }
501  return "";
502  }
503 
505 
506  explicit ExprAssignment(expr_ptr _lhs, op_t op, expr_ptr _rhs)
507  : op(op), lhs(LEXY_MOV(_lhs)), rhs(LEXY_MOV(_rhs))
508  {}
509 
510  Any evaluate(Environment& env) const override
511  {
512  auto varname = dynamic_cast<ExprName*>(lhs.get());
513  if(!varname)
514  {
515  throw RuntimeError("Assignment left operand not a blackboard entry");
516  }
517  const auto& key = varname->name;
518 
519  auto entry = env.vars->getEntry(key);
520  if(!entry)
521  {
522  // variable doesn't exist, create it if using operator assign_create
523  if(op == assign_create)
524  {
525  env.vars->createEntry(key, PortInfo());
526  entry = env.vars->getEntry(key);
527  if(!entry)
528  {
529  throw LogicError("Bug: report");
530  }
531  }
532  else
533  {
534  // fail otherwise
535  auto msg = StrCat("The blackboard entry [", key,
536  "] doesn't exist, yet.\n"
537  "If you want to create a new one, "
538  "use the operator "
539  "[:=] instead of [=]");
540  throw RuntimeError(msg);
541  }
542  }
543  auto value = rhs->evaluate(env);
544 
545  std::scoped_lock lock(entry->entry_mutex);
546  auto* dst_ptr = &entry->value;
547 
548  auto errorPrefix = [dst_ptr, &key]() {
549  return StrCat("Error assigning a value to entry [", key, "] with type [",
550  BT::demangle(dst_ptr->type()), "]. ");
551  };
552 
553  if(value.empty())
554  {
555  throw RuntimeError(ErrorNotInit("right", opStr()));
556  }
557 
558  if(op == assign_create || op == assign_existing)
559  {
560  // the very fist assignment can come from any type.
561  // In the future, type check will be done by Any::copyInto
562  if(dst_ptr->empty() && entry->info.type() == typeid(AnyTypeAllowed))
563  {
564  *dst_ptr = value;
565  }
566  else if(value.isString() && !dst_ptr->isString())
567  {
568  // special case: string to other type.
569  // Check if we can use the StringConverter
570  auto const str = value.cast<std::string>();
571  const auto* entry_info = env.vars->entryInfo(key);
572 
573  if(auto converter = entry_info->converter())
574  {
575  *dst_ptr = converter(str);
576  }
577  else if(dst_ptr->isNumber())
578  {
579  auto num_value = StringToDouble(value, env);
580  *dst_ptr = Any(num_value);
581  }
582  else
583  {
584  auto msg = StrCat(errorPrefix(),
585  "\nThe right operand is a string, "
586  "can't convert to ",
587  demangle(dst_ptr->type()));
588  throw RuntimeError(msg);
589  }
590  }
591  else
592  {
593  try
594  {
595  value.copyInto(*dst_ptr);
596  }
597  catch(std::exception&)
598  {
599  auto msg = StrCat(errorPrefix(), "\nThe right operand has type [",
600  BT::demangle(value.type()), "] and can't be converted to [",
601  BT::demangle(dst_ptr->type()), "]");
602  throw RuntimeError(msg);
603  }
604  }
605  entry->sequence_id++;
606  entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
607  return *dst_ptr;
608  }
609 
610  if(dst_ptr->empty())
611  {
612  throw RuntimeError(ErrorNotInit("left", opStr()));
613  }
614 
615  // temporary use
616  Any temp_variable = *dst_ptr;
617 
618  if(value.isNumber())
619  {
620  if(!temp_variable.isNumber())
621  {
622  throw RuntimeError("This Assignment operator can't be used "
623  "with a non-numeric type");
624  }
625 
626  auto lv = temp_variable.cast<double>();
627  auto rv = value.cast<double>();
628  switch(op)
629  {
630  case assign_plus:
631  temp_variable = Any(lv + rv);
632  break;
633  case assign_minus:
634  temp_variable = Any(lv - rv);
635  break;
636  case assign_times:
637  temp_variable = Any(lv * rv);
638  break;
639  case assign_div:
640  temp_variable = Any(lv / rv);
641  break;
642  default: {
643  }
644  }
645  }
646  else if(value.isString())
647  {
648  if(op == assign_plus)
649  {
650  auto lv = temp_variable.cast<std::string>();
651  auto rv = value.cast<std::string>();
652  temp_variable = Any(lv + rv);
653  }
654  else
655  {
656  throw RuntimeError("Operator not supported for strings");
657  }
658  }
659 
660  temp_variable.copyInto(*dst_ptr);
661  entry->sequence_id++;
662  entry->stamp = std::chrono::steady_clock::now().time_since_epoch();
663  return *dst_ptr;
664  }
665 };
666 } // namespace BT::Ast
667 
668 namespace BT::Grammar
669 {
670 namespace dsl = lexy::dsl;
671 
672 constexpr auto escaped_newline = dsl::backslash >> dsl::newline;
673 
674 // An expression that is nested inside another expression.
676 {
677  // We change the whitespace rule to allow newlines:
678  // as it's nested, the REPL can properly handle continuation lines.
679  static constexpr auto whitespace = dsl::ascii::space | escaped_newline;
680  // The rule itself just recurses back to expression, but with the adjusted whitespace now.
681  static constexpr auto rule = dsl::recurse<struct Expression>;
682 
683  static constexpr auto value = lexy::forward<Ast::expr_ptr>;
684 };
685 
686 // An arbitrary expression.
687 // It uses lexy's built-in support for operator precedence parsing to automatically generate a
688 // proper rule. This is done by inheriting from expression_production.
690 {
692  {
693  static constexpr auto name = "expected operand";
694  };
695 
696  // We need to specify the atomic part of an expression.
697  static constexpr auto atom = [] {
698  auto paren_expr = dsl::parenthesized(dsl::p<nested_expr>);
699  auto boolean = dsl::p<BooleanLiteral>;
700  auto var = dsl::p<Name>;
701  auto literal = dsl::p<AnyValue>;
702 
703  return paren_expr | boolean | var | literal | dsl::error<expected_operand>;
704  }();
705 
706  // Each of the nested classes defines one operation.
707  // They inherit from a tag type that specify the kind of operation (prefix, infix, postfix),
708  // and associativity (left, right, single (non-associative)),
709  // and specify the operator rule and operand.
710 
711  // -x
712  struct math_prefix : dsl::prefix_op
713  {
714  static constexpr auto op = dsl::op<Ast::ExprUnaryArithmetic::negate>(LEXY_LIT("-"));
715  using operand = dsl::atom;
716  };
717  // x * x, x / x
718  struct math_product : dsl::infix_op_left
719  {
720  static constexpr auto op = [] {
721  // Don't confuse with *= or /=
722  auto times = dsl::not_followed_by(LEXY_LIT("*"), dsl::lit_c<'='>);
723  auto div = dsl::not_followed_by(LEXY_LIT("/"), dsl::lit_c<'='>);
724  return dsl::op<Ast::ExprBinaryArithmetic::times>(times) /
725  dsl::op<Ast::ExprBinaryArithmetic::div>(div);
726  }();
728  };
729  // x + x, x - x
730  struct math_sum : dsl::infix_op_left
731  {
732  static constexpr auto op = [] {
733  // Don't confuse with += or -=
734  auto plus = dsl::not_followed_by(LEXY_LIT("+"), dsl::lit_c<'='>);
735  auto minus = dsl::not_followed_by(LEXY_LIT("-"), dsl::lit_c<'='>);
736  return dsl::op<Ast::ExprBinaryArithmetic::plus>(plus) /
737  dsl::op<Ast::ExprBinaryArithmetic::minus>(minus);
738  }();
739 
741  };
742 
743  // x .. y
744  struct string_concat : dsl::infix_op_left
745  {
746  static constexpr auto op = [] {
747  return dsl::op<Ast::ExprBinaryArithmetic::concat>(LEXY_LIT(".."));
748  }();
749 
750  using operand = math_sum;
751  };
752 
753  // ~x
754  struct bit_prefix : dsl::prefix_op
755  {
756  static constexpr auto op = [] {
757  auto complement = LEXY_LIT("~");
758  auto logical_not = dsl::not_followed_by(LEXY_LIT("!"), dsl::lit_c<'='>);
759 
760  return dsl::op<Ast::ExprUnaryArithmetic::complement>(complement) /
761  dsl::op<Ast::ExprUnaryArithmetic::logical_not>(logical_not);
762  }();
763  using operand = dsl::atom;
764  };
765 
766  // x & x
767  struct bit_and : dsl::infix_op_left
768  {
769  static constexpr auto op = [] {
770  // Don't confuse with &&
771  auto bit_and = dsl::not_followed_by(LEXY_LIT("&"), dsl::lit_c<'&'>);
772  return dsl::op<Ast::ExprBinaryArithmetic::bit_and>(bit_and);
773  }();
774 
776  };
777 
778  // x | x, x ^ x
779  struct bit_or : dsl::infix_op_left
780  {
781  static constexpr auto op = [] {
782  // Don't confuse with ||
783  auto bit_or = dsl::not_followed_by(LEXY_LIT("|"), dsl::lit_c<'|'>);
784  return dsl::op<Ast::ExprBinaryArithmetic::bit_or>(bit_or) /
785  dsl::op<Ast::ExprBinaryArithmetic::bit_xor>(LEXY_LIT("^"));
786  }();
787 
788  using operand = bit_and;
789  };
790 
791  // Comparisons are list operators, which allows implementation of chaining.
792  // x == y < z
793  struct comparison : dsl::infix_op_list
794  {
795  // Other comparison operators omitted for simplicity.
796  static constexpr auto op = dsl::op<Ast::ExprComparison::equal>(LEXY_LIT("==")) /
797  dsl::op<Ast::ExprComparison::not_equal>(LEXY_LIT("!=")) /
798  dsl::op<Ast::ExprComparison::less>(LEXY_LIT("<")) /
799  dsl::op<Ast::ExprComparison::greater>(LEXY_LIT(">")) /
800  dsl::op<Ast::ExprComparison::less_equal>(LEXY_LIT("<=")) /
801  dsl::op<Ast::ExprComparison::greater_equal>(LEXY_LIT(">"
802  "="));
803 
804  // The use of dsl::groups ensures that an expression can either contain math or bit or string
805  // operators. Mixing requires parenthesis.
806  using operand = dsl::groups<math_sum, bit_or, string_concat>;
807  };
808 
809  // Logical operators, || and &&
810  struct logical : dsl::infix_op_left
811  {
812  static constexpr auto op =
813  dsl::op<Ast::ExprBinaryArithmetic::logic_or>(LEXY_LIT("||")) /
814  dsl::op<Ast::ExprBinaryArithmetic::logic_and>(LEXY_LIT("&&"));
815 
817  };
818 
819  // x ? y : z
820  struct conditional : dsl::infix_op_single
821  {
822  // We treat a conditional operator, which has three operands,
823  // as a binary operator where the operator consists of ?, the inner operator, and :.
824  // The <void> ensures that `dsl::op` does not produce a value.
825  static constexpr auto op =
826  dsl::op<void>(LEXY_LIT("?") >> (dsl::p<nested_expr> + dsl::lit_c<':'>));
827  using operand = logical;
828  };
829 
830  struct assignment : dsl::infix_op_single
831  {
832  // We need to prevent `=` from matching `==`.
833  static constexpr auto op =
834  dsl::op<Ast::ExprAssignment::assign_create>(LEXY_LIT(":=")) /
835  dsl::op<Ast::ExprAssignment::assign_existing>(
836  dsl::not_followed_by(LEXY_LIT("="), dsl::lit_c<'='>)) /
837  dsl::op<Ast::ExprAssignment::assign_plus>(LEXY_LIT("+=")) /
838  dsl::op<Ast::ExprAssignment::assign_minus>(LEXY_LIT("-=")) /
839  dsl::op<Ast::ExprAssignment::assign_times>(LEXY_LIT("*=")) /
840  dsl::op<Ast::ExprAssignment::assign_div>(LEXY_LIT("/="));
841 
843  };
844 
845  // An expression also needs to specify the operation with the lowest binding power.
846  // The operation of everything else is determined by following the `::operand` member.
848 
849  static constexpr auto value =
850  // We need a sink as the comparison expression generates a list.
851  lexy::fold_inplace<std::unique_ptr<Ast::ExprComparison>>(
852  [] { return std::make_unique<Ast::ExprComparison>(); },
853  [](auto& node, Ast::expr_ptr opr) { node->operands.push_back(LEXY_MOV(opr)); },
854  [](auto& node, Ast::ExprComparison::op_t op) { node->ops.push_back(op); })
855  // The result of the list feeds into a callback that handles all other cases.
856  >> lexy::callback(
857  // atoms
858  lexy::forward<Ast::expr_ptr>, lexy::new_<Ast::ExprLiteral, Ast::expr_ptr>,
859  lexy::new_<Ast::ExprName, Ast::expr_ptr>,
860  // unary/binary operators
861  lexy::new_<Ast::ExprUnaryArithmetic, Ast::expr_ptr>,
862  lexy::new_<Ast::ExprBinaryArithmetic, Ast::expr_ptr>,
863  // conditional and assignment
864  lexy::new_<Ast::ExprIf, Ast::expr_ptr>,
865  lexy::new_<Ast::ExprAssignment, Ast::expr_ptr>);
866 };
867 
868 // A statement, which is a list of expressions separated by semicolons.
869 struct stmt
870 {
871  // We don't allow newlines as whitespace at the top-level.
872  // This is because we can't easily know whether we need to request more input when seeing a
873  // newline or not. Once we're having a e.g. parenthesized expression, we know that we need more
874  // input until we've reached ), so then change the whitespace rule.
876 
877  static constexpr auto rule = [] {
878  // We can't use `dsl::eol` as our terminator directly,
879  // since that would try and skip whitespace, which requests more input on the REPL.
880  auto at_eol = dsl::peek(dsl::eol);
881  return dsl::terminator(at_eol).opt_list(dsl::p<Expression>, dsl::sep(dsl::semicolon));
882  }();
883 
884  static constexpr auto value = lexy::as_list<std::vector<Ast::expr_ptr>>;
885 };
886 
887 } // namespace BT::Grammar
BT::Grammar::Expression
Definition: operators.hpp:689
BT::Grammar::Expression::assignment
Definition: operators.hpp:830
BT::PortInfo
Definition: basic_types.h:394
BT::Ast::ExprBinaryArithmetic::lhs
expr_ptr lhs
Definition: operators.hpp:196
BT::Ast::ExprAssignment::assign_div
@ assign_div
Definition: operators.hpp:481
LEXY_MOV
#define LEXY_MOV(...)
Definition: config.hpp:29
BT::Ast::ExprComparison::greater
@ greater
Definition: operators.hpp:323
BT::demangle
std::string demangle(char const *name)
Definition: demangle_util.h:74
BT::Ast::ExprAssignment::assign_times
@ assign_times
Definition: operators.hpp:480
BT::Ast::ExprComparison::not_equal
@ not_equal
Definition: operators.hpp:321
lexyd::peek
constexpr auto peek(Rule)
Definition: peek.hpp:166
BT::Ast::ExprAssignment::lhs
expr_ptr lhs
Definition: operators.hpp:504
BT::Ast::ExprBinaryArithmetic::div
@ div
Definition: operators.hpp:157
BT::Ast::ExprAssignment
Definition: operators.hpp:472
BT::Ast::ExprLiteral::ExprLiteral
ExprLiteral(Any v)
Definition: operators.hpp:71
BT::Any
Definition: safe_any.hpp:36
BT::Ast::ExprUnaryArithmetic::ExprUnaryArithmetic
ExprUnaryArithmetic(op_t op, expr_ptr e)
Definition: operators.hpp:118
BT::Grammar::Expression::comparison::operand
dsl::groups< math_sum, bit_or, string_concat > operand
Definition: operators.hpp:806
LEXY_LIT
#define LEXY_LIT(Str)
Definition: literal.hpp:392
BT::Ast::ExprIf
Definition: operators.hpp:448
BT::Grammar::Expression::assignment::op
static constexpr auto op
Definition: operators.hpp:833
lexyd::sep
constexpr auto sep(Branch)
Defines a separator for a list.
Definition: separator.hpp:91
BT::Grammar::Expression::string_concat::op
static constexpr auto op
Definition: operators.hpp:746
BT::Ast::Environment::enums
EnumsTablePtr enums
Definition: script_parser.hpp:34
BT::Ast::ExprUnaryArithmetic::complement
@ complement
Definition: operators.hpp:113
lexyd::terminator
constexpr auto terminator(Branch)
Creates a terminator using the given branch.
Definition: terminator.hpp:106
SafeAny::SimpleString::size
std::size_t size() const
Definition: simple_string.hpp:88
BT::Ast::ExprBinaryArithmetic::logic_or
@ logic_or
Definition: operators.hpp:165
BT::Ast::ExprName
Definition: operators.hpp:80
BT::Grammar::Expression::bit_or::op
static constexpr auto op
Definition: operators.hpp:781
BT::Ast::ExprBase::evaluate
virtual Any evaluate(Environment &env) const =0
BT::Ast::ExprUnaryArithmetic::op_t
op_t
Definition: operators.hpp:110
BT::Ast::ExprComparison::opStr
const char * opStr(op_t op) const
Definition: operators.hpp:328
BT::Ast::ExprComparison::op_t
op_t
Definition: operators.hpp:318
BT::Ast::ExprName::evaluate
Any evaluate(Environment &env) const override
Definition: operators.hpp:87
BT::Grammar::Expression::string_concat
Definition: operators.hpp:744
BT::Ast::ExprBinaryArithmetic::logic_and
@ logic_and
Definition: operators.hpp:164
BT::Ast::ExprIf::evaluate
Any evaluate(Environment &env) const override
Definition: operators.hpp:456
BT::Ast::ExprBinaryArithmetic::bit_xor
@ bit_xor
Definition: operators.hpp:162
BT::Ast::ExprAssignment::assign_minus
@ assign_minus
Definition: operators.hpp:479
BT::Grammar::Expression::math_sum
Definition: operators.hpp:730
BT::Ast::ExprUnaryArithmetic::negate
@ negate
Definition: operators.hpp:112
BT::Ast::Environment::vars
BT::Blackboard::Ptr vars
Definition: script_parser.hpp:33
BT::Grammar::Expression::math_prefix::op
static constexpr auto op
Definition: operators.hpp:714
BT::Grammar::Expression::value
static constexpr auto value
Definition: operators.hpp:849
BT::Ast::ExprIf::then
expr_ptr then
Definition: operators.hpp:450
lexyd::parenthesized
constexpr auto parenthesized
Definition: brackets.hpp:113
BT::Grammar::Expression::comparison
Definition: operators.hpp:793
lexyd::ascii::newline
constexpr auto newline
Definition: ascii.hpp:77
BT::Ast::ExprLiteral::value
Any value
Definition: operators.hpp:69
BT::Grammar::Expression::conditional::op
static constexpr auto op
Definition: operators.hpp:825
BT::Grammar::Expression::comparison::op
static constexpr auto op
Definition: operators.hpp:796
BT::Ast::ExprComparison::greater_equal
@ greater_equal
Definition: operators.hpp:325
BT::Ast::ExprUnaryArithmetic::rhs
expr_ptr rhs
Definition: operators.hpp:116
BT::Ast::ExprBinaryArithmetic::ExprBinaryArithmetic
ExprBinaryArithmetic(expr_ptr lhs, op_t op, expr_ptr rhs)
Definition: operators.hpp:198
BT::Grammar::Expression::bit_and::op
static constexpr auto op
Definition: operators.hpp:769
BT::Grammar::Expression::atom
static constexpr auto atom
Definition: operators.hpp:697
BT::Any::isNumber
bool isNumber() const
Definition: safe_any.hpp:338
BT::Grammar::Expression::expected_operand::name
static constexpr auto name
Definition: operators.hpp:693
BT::Ast::ExprBinaryArithmetic::evaluate
Any evaluate(Environment &env) const override
Definition: operators.hpp:202
BT::Ast::ExprName::name
std::string name
Definition: operators.hpp:82
lexy::_detail::any_ref
any_base * any_ref
Definition: any_ref.hpp:43
BT::LogicError
Definition: exceptions.h:45
BT::Ast::ExprIf::ExprIf
ExprIf(expr_ptr condition, expr_ptr then, expr_ptr else_)
Definition: operators.hpp:452
BT::Ast::ExprComparison::operands
std::vector< expr_ptr > operands
Definition: operators.hpp:349
any_types.hpp
BT::Ast::ExprBinaryArithmetic::opStr
const char * opStr() const
Definition: operators.hpp:168
BT::Grammar::Expression::math_prefix
Definition: operators.hpp:712
lexyd::eol
constexpr auto eol
Matches the end of line (EOF or newline).
Definition: newline.hpp:82
BT::Ast::ExprComparison::ops
std::vector< op_t > ops
Definition: operators.hpp:348
BT::Grammar::Expression::math_product::op
static constexpr auto op
Definition: operators.hpp:720
BT::Ast::ExprBinaryArithmetic::bit_and
@ bit_and
Definition: operators.hpp:160
BT::Grammar::nested_expr
Definition: operators.hpp:675
BT::Grammar::stmt::whitespace
static constexpr auto whitespace
Definition: operators.hpp:875
BT::Ast::SimpleString
SafeAny::SimpleString SimpleString
Definition: operators.hpp:26
lexy::callback
constexpr auto callback(Fns &&... fns)
Creates a callback.
Definition: adapter.hpp:48
BT::Grammar::stmt::rule
static constexpr auto rule
Definition: operators.hpp:877
BT::Grammar::Expression::bit_prefix
Definition: operators.hpp:754
BT::Ast::ExprAssignment::op
enum BT::Ast::ExprAssignment::op_t op
BT::Ast::ExprBinaryArithmetic::op
enum BT::Ast::ExprBinaryArithmetic::op_t op
BT::Ast::expr_ptr
std::shared_ptr< struct ExprBase > expr_ptr
Definition: operators.hpp:28
BT::Ast::ExprComparison::less
@ less
Definition: operators.hpp:322
BT::Grammar::stmt::value
static constexpr auto value
Definition: operators.hpp:884
BT::Grammar::Expression::logical
Definition: operators.hpp:810
lexyd::not_followed_by
constexpr auto not_followed_by(Literal, CharClass cc)
Match a literal but only if not followed by the given char class.
Definition: follow.hpp:101
BT::Ast::ExprBinaryArithmetic::plus
@ plus
Definition: operators.hpp:154
BT::Ast::ExprBinaryArithmetic::op_t
op_t
Definition: operators.hpp:152
BT::Ast::ErrorNotInit
std::string ErrorNotInit(const char *side, const char *op_str)
Definition: operators.hpp:61
BT::Ast::ExprUnaryArithmetic::logical_not
@ logical_not
Definition: operators.hpp:114
BT::Ast::ExprLiteral::evaluate
Any evaluate(Environment &) const override
Definition: operators.hpp:74
BT::RuntimeError
Definition: exceptions.h:58
BT::Ast::ExprName::ExprName
ExprName(std::string n)
Definition: operators.hpp:84
BT::Grammar::Expression::bit_and
Definition: operators.hpp:767
SafeAny::SimpleString
Definition: simple_string.hpp:18
BT::Ast::ExprBase::~ExprBase
virtual ~ExprBase()=default
BT::Ast::ExprComparison::evaluate
Any evaluate(Environment &env) const override
Definition: operators.hpp:351
BT::Ast::ExprComparison::less_equal
@ less_equal
Definition: operators.hpp:324
BT::Any::cast
T cast() const
Definition: safe_any.hpp:146
BT::Ast::ExprBinaryArithmetic::concat
@ concat
Definition: operators.hpp:158
magic_enum::detail::n
constexpr auto n() noexcept
Definition: magic_enum.hpp:417
BT::Ast::ExprComparison
Definition: operators.hpp:316
BT::StrCat
std::string StrCat()
Definition: strcat.hpp:46
BT::Ast::ExprAssignment::rhs
expr_ptr rhs
Definition: operators.hpp:504
BT::Grammar::Expression::bit_prefix::op
static constexpr auto op
Definition: operators.hpp:756
lexy::op
typename LEXY_DECAY_DECLTYPE(Operator)::op_tag_type op
Definition: operator.hpp:41
BT::Grammar::Expression::math_sum::op
static constexpr auto op
Definition: operators.hpp:732
BT::Ast::ExprUnaryArithmetic
Definition: operators.hpp:108
BT::AnyTypeAllowed
Definition: basic_types.h:87
BT::Grammar::nested_expr::rule
static constexpr auto rule
Definition: operators.hpp:681
BT::Ast::ExprAssignment::assign_plus
@ assign_plus
Definition: operators.hpp:478
BT::Ast::ExprLiteral
Definition: operators.hpp:67
lexy::transparent_production
Definition: grammar.hpp:165
BT::Grammar::Expression::conditional
Definition: operators.hpp:820
BT::Ast::ExprAssignment::op_t
op_t
Definition: operators.hpp:474
BT::Ast::ExprAssignment::opStr
const char * opStr() const
Definition: operators.hpp:484
BT::Ast::ExprBinaryArithmetic::bit_or
@ bit_or
Definition: operators.hpp:161
BT::Grammar
Definition: any_types.hpp:22
BT::Ast::ExprBinaryArithmetic::times
@ times
Definition: operators.hpp:156
BT::Grammar::Expression::bit_or
Definition: operators.hpp:779
BT::Any::copyInto
void copyInto(Any &dst)
Definition: safe_any.hpp:349
BT::Ast::StringToDouble
double StringToDouble(const Any &value, const Environment &env)
Definition: operators.hpp:31
lexyd::ascii::space
constexpr auto space
Definition: ascii.hpp:112
BT::Grammar::Expression::bit_prefix::operand
dsl::atom operand
Definition: operators.hpp:763
BT::Grammar::Expression::logical::op
static constexpr auto op
Definition: operators.hpp:812
lexy::expression_production
Definition: expression.hpp:582
BT::Ast::ExprBinaryArithmetic::rhs
expr_ptr rhs
Definition: operators.hpp:196
BT::Grammar::escaped_newline
constexpr auto escaped_newline
Definition: operators.hpp:672
BT::Grammar::Expression::math_product
Definition: operators.hpp:718
BT::Ast::ExprIf::else_
expr_ptr else_
Definition: operators.hpp:450
BT::Ast::ExprIf::condition
expr_ptr condition
Definition: operators.hpp:450
lexyd::ascii::blank
constexpr auto blank
Definition: ascii.hpp:60
BT::Ast::ExprBinaryArithmetic
Definition: operators.hpp:150
BT::Grammar::nested_expr::value
static constexpr auto value
Definition: operators.hpp:683
lexyd::times
constexpr auto times(Rule)
Repeats the rule N times in sequence.
Definition: times.hpp:40
BT::Ast::ExprBase
Definition: operators.hpp:53
BT::Ast::ExprBinaryArithmetic::minus
@ minus
Definition: operators.hpp:155
BT::Ast::ExprAssignment::ExprAssignment
ExprAssignment(expr_ptr _lhs, op_t op, expr_ptr _rhs)
Definition: operators.hpp:506
BT::Grammar::stmt
Definition: operators.hpp:869
script_parser.hpp
lexy::_detail::any_base::get
constexpr T & get() noexcept
Definition: any_ref.hpp:25
BT::Ast::ExprUnaryArithmetic::evaluate
Any evaluate(Environment &env) const override
Definition: operators.hpp:121
BT::Ast::IsSame
bool IsSame(const T &lv, const T &rv)
Definition: operators.hpp:303
BT::Grammar::Expression::expected_operand
Definition: operators.hpp:691
BT::Ast::ExprAssignment::assign_create
@ assign_create
Definition: operators.hpp:476
BT::Grammar::Expression::math_prefix::operand
dsl::atom operand
Definition: operators.hpp:715
BT::Ast::ExprBase::Ptr
std::shared_ptr< ExprBase > Ptr
Definition: operators.hpp:55
BT::Grammar::nested_expr::whitespace
static constexpr auto whitespace
Definition: operators.hpp:679
BT::Ast::ExprAssignment::assign_existing
@ assign_existing
Definition: operators.hpp:477
BT::Ast::ExprUnaryArithmetic::op
enum BT::Ast::ExprUnaryArithmetic::op_t op
BT::Ast::ExprComparison::equal
@ equal
Definition: operators.hpp:320
BT::Ast::ExprAssignment::evaluate
Any evaluate(Environment &env) const override
Definition: operators.hpp:510
BT::Ast
Definition: operators.hpp:24
BT::Ast::Environment
The Environment class is used to encapsulate the information and states needed by the scripting langu...
Definition: script_parser.hpp:31


behaviortree_cpp_v4
Author(s): Davide Faconti
autogenerated on Fri Feb 28 2025 03:19:19