GDevelop Core
Core library for developing platforms and tools compatible with GDevelop.
ExpressionParser2.h
1 /*
2  * GDevelop Core
3  * Copyright 2008-present Florian Rival ([email protected]). All rights
4  * reserved. This project is released under the MIT License.
5  */
6 #ifndef GDCORE_EXPRESSIONPARSER2_H
7 #define GDCORE_EXPRESSIONPARSER2_H
8 
9 #include <memory>
10 #include <utility>
11 #include <vector>
12 
13 #include "ExpressionParser2Node.h"
14 #include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
15 #include "GDCore/Extensions/Metadata/MetadataProvider.h"
16 #include "GDCore/Extensions/Metadata/ObjectMetadata.h"
17 #include "GDCore/Project/Layout.h" // For GetTypeOfObject and GetTypeOfBehavior
18 #include "GDCore/String.h"
20 #include "GDCore/Tools/MakeUnique.h"
21 #include "GrammarTerminals.h"
22 namespace gd {
23 class Expression;
24 class ObjectsContainer;
25 class Platform;
26 class ParameterMetadata;
27 class ExpressionMetadata;
28 } // namespace gd
29 
30 namespace gd {
31 
32 using namespace gd::GrammarTerminals;
33 
44 class GD_CORE_API ExpressionParser2 {
45  public:
47  virtual ~ExpressionParser2(){};
48 
56  std::unique_ptr<ExpressionNode> ParseExpression(
57  const gd::String &expression) {
58  // Parse over a UTF-32 (fixed-width) copy of the expression: gd::String is
59  // UTF-8, so indexing it by character position (operator[]) and computing
60  // its size() are both O(position)/O(length). Doing that for every
61  // character would make parsing O(N^2) in the expression length (which is
62  // catastrophic for very large expressions). std::u32string gives O(1)
63  // random access and size, while keeping the same character indices (and so
64  // the same node locations) as gd::String.
65  expressionUtf32 = expression.ToUTF32();
66 
67  currentPosition = 0;
68  return Start();
69  }
70 
80  static size_t WrittenParametersFirstIndex(const gd::String &objectName,
81  const gd::String &behaviorName) {
82  // By convention, object is always the first parameter, and behavior the
83  // second one.
84  return !behaviorName.empty() ? 2 : (!objectName.empty() ? 1 : 0);
85  }
86 
87  private:
92  std::unique_ptr<ExpressionNode> Start() {
93  size_t expressionStartPosition = GetCurrentPosition();
94  auto expression = Expression();
95 
96  // Check for extra characters at the end of the expression
97  if (!IsEndReached()) {
98  auto op = gd::make_unique<OperatorNode>(' ');
99  op->leftHandSide = std::move(expression);
100  op->rightHandSide = ReadUntilEnd();
101  op->rightHandSide->parent = op.get();
102 
103  op->rightHandSide->diagnostic = RaiseSyntaxError(
104  _("The expression has extra character at the end that should be "
105  "removed (or completed if your expression is not finished)."));
106 
107  op->location = ExpressionParserLocation(expressionStartPosition,
108  GetCurrentPosition());
109  return std::move(op);
110  }
111 
112  return expression;
113  }
114 
115  std::unique_ptr<ExpressionNode> Expression() {
116  SkipAllWhitespaces();
117 
118  size_t expressionStartPosition = GetCurrentPosition();
119  std::unique_ptr<ExpressionNode> leftHandSide = Term();
120 
121  SkipAllWhitespaces();
122 
123  if (IsEndReached()) return leftHandSide;
124  if (CheckIfChar(IsExpressionEndingChar)) return leftHandSide;
125  if (CheckIfChar(IsExpressionOperator)) {
126  auto op = gd::make_unique<OperatorNode>(GetCurrentChar());
127  op->leftHandSide = std::move(leftHandSide);
128  op->leftHandSide->parent = op.get();
129  op->diagnostic = ValidateOperator(GetCurrentChar());
130  SkipChar();
131  op->rightHandSide = Expression();
132  op->rightHandSide->parent = op.get();
133 
134  op->location = ExpressionParserLocation(expressionStartPosition,
135  GetCurrentPosition());
136  return std::move(op);
137  }
138 
139  leftHandSide->diagnostic = RaiseSyntaxError(
140  "More than one term was found. Verify that your expression is "
141  "properly written.");
142 
143  auto op = gd::make_unique<OperatorNode>(' ');
144  op->leftHandSide = std::move(leftHandSide);
145  op->leftHandSide->parent = op.get();
146  op->rightHandSide = Expression();
147  op->rightHandSide->parent = op.get();
148  op->location =
149  ExpressionParserLocation(expressionStartPosition, GetCurrentPosition());
150  return std::move(op);
151  }
152 
153  std::unique_ptr<ExpressionNode> Term() {
154  SkipAllWhitespaces();
155 
156  size_t expressionStartPosition = GetCurrentPosition();
157  std::unique_ptr<ExpressionNode> factor = Factor();
158 
159  SkipAllWhitespaces();
160 
161  // This while loop is used instead of a recursion (like in Expression)
162  // to guarantee the proper operator precedence. (Expression could also
163  // be reworked to use a while loop).
164  while (CheckIfChar(IsTermOperator)) {
165  auto op = gd::make_unique<OperatorNode>(GetCurrentChar());
166  op->leftHandSide = std::move(factor);
167  op->leftHandSide->parent = op.get();
168  op->diagnostic = ValidateOperator(GetCurrentChar());
169  SkipChar();
170  op->rightHandSide = Factor();
171  op->rightHandSide->parent = op.get();
172  op->location = ExpressionParserLocation(expressionStartPosition,
173  GetCurrentPosition());
174  SkipAllWhitespaces();
175 
176  factor = std::move(op);
177  }
178 
179  return factor;
180  };
181 
182  std::unique_ptr<ExpressionNode> Factor() {
183  SkipAllWhitespaces();
184  size_t expressionStartPosition = GetCurrentPosition();
185 
186  if (CheckIfChar(IsQuote)) {
187  std::unique_ptr<ExpressionNode> factor = ReadText();
188  return factor;
189  } else if (CheckIfChar(IsUnaryOperator)) {
190  auto unaryOperatorCharacter = GetCurrentChar();
191 
192  bool isNumberSign = CheckIfChar(IsNumberSign);
193  SkipChar();
194  if (isNumberSign && CheckIfChar(IsNumberFirstChar)) {
195  std::unique_ptr<ExpressionNode> numberNode =
196  ReadNumber(expressionStartPosition);
197  return numberNode;
198  }
199  auto operatorOperand = Factor();
200 
201  auto unaryOperator = gd::make_unique<UnaryOperatorNode>(
202  unaryOperatorCharacter);
203  unaryOperator->diagnostic = ValidateUnaryOperator(
204  unaryOperatorCharacter, expressionStartPosition);
205  unaryOperator->factor = std::move(operatorOperand);
206  unaryOperator->factor->parent = unaryOperator.get();
207  unaryOperator->location = ExpressionParserLocation(
208  expressionStartPosition, GetCurrentPosition());
209 
210  return std::move(unaryOperator);
211  } else if (CheckIfChar(IsNumberFirstChar)) {
212  std::unique_ptr<ExpressionNode> factor = ReadNumber();
213  return factor;
214  } else if (CheckIfChar(IsOpeningParenthesis)) {
215  size_t expressionStartPosition = GetCurrentPosition();
216  SkipChar();
217 
218  // The expression inside the parentheses excluding them.
219  auto expression = Expression();
220 
221  // The expression and its parentheses.
222  auto factor = gd::make_unique<SubExpressionNode>(std::move(expression));
223 
224  if (!CheckIfChar(IsClosingParenthesis)) {
225  factor->diagnostic =
226  RaiseSyntaxError(_("Missing a closing parenthesis. Add a closing "
227  "parenthesis for each opening parenthesis."));
228  }
229  SkipIfChar(IsClosingParenthesis);
230  factor->location = ExpressionParserLocation(expressionStartPosition,
231  GetCurrentPosition());
232 
233  return std::move(factor);
234  } else if (CheckIfChar(IsAllowedInIdentifier)) {
235  return Identifier();
236  }
237 
238  std::unique_ptr<ExpressionNode> factor = ReadUntilWhitespace();
239  return factor;
240  }
241 
242  std::unique_ptr<IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode>
243  Identifier() {
244  auto identifierAndLocation = ReadIdentifierName();
245  gd::String name = identifierAndLocation.name;
246  auto nameLocation = identifierAndLocation.location;
247 
248  SkipAllWhitespaces();
249 
250  // We consider a namespace separator to be allowed here and be part of the
251  // function name (or object name, but object names are not allowed to
252  // contain a ":"). This is because functions from extensions have their
253  // extension name prefix, and separated by the namespace separator. This
254  // could maybe be refactored to create different nodes in the future.
255  if (IsNamespaceSeparator()) {
256  SkipNamespaceSeparator();
257  SkipAllWhitespaces();
258 
259  auto postNamespaceIdentifierAndLocation = ReadIdentifierName();
260  name += NAMESPACE_SEPARATOR;
261  name += postNamespaceIdentifierAndLocation.name;
262  ExpressionParserLocation completeNameLocation(
263  nameLocation.GetStartPosition(),
264  postNamespaceIdentifierAndLocation.location.GetEndPosition());
265  nameLocation = completeNameLocation;
266  }
267 
268  if (CheckIfChar(IsOpeningParenthesis)) {
269  ExpressionParserLocation openingParenthesisLocation = SkipChar();
270  return FreeFunction(name, nameLocation, openingParenthesisLocation);
271  } else if (CheckIfChar(IsDot)) {
272  ExpressionParserLocation dotLocation = SkipChar();
273  SkipAllWhitespaces();
274  return ObjectFunctionOrBehaviorFunctionOrVariable(
275  name, nameLocation, dotLocation);
276  } else if (CheckIfChar(IsOpeningSquareBracket)) {
277  return Variable(name, nameLocation);
278  } else {
279  auto identifier = gd::make_unique<IdentifierNode>(name);
280  identifier->location = ExpressionParserLocation(
281  nameLocation.GetStartPosition(), GetCurrentPosition());
282  identifier->identifierNameLocation = identifier->location;
283  return std::move(identifier);
284  }
285  }
286 
287  std::unique_ptr<VariableNode> Variable(const gd::String &name, gd::ExpressionParserLocation nameLocation) {
288  auto variable = gd::make_unique<VariableNode>(name);
289 
290  if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
291  variable->child = VariableAccessorOrVariableBracketAccessor();
292  variable->child->parent = variable.get();
293  }
294 
295  variable->location = ExpressionParserLocation(
296  nameLocation.GetStartPosition(), GetCurrentPosition());
297  variable->nameLocation = nameLocation;
298  return std::move(variable);
299  }
300 
301  std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>
302  VariableAccessorOrVariableBracketAccessor() {
303  size_t childStartPosition = GetCurrentPosition();
304 
305  SkipAllWhitespaces();
306  if (CheckIfChar(IsOpeningSquareBracket)) {
307  SkipChar();
308  auto child = gd::make_unique<VariableBracketAccessorNode>(Expression());
309  child->expression->parent = child.get();
310 
311  if (!CheckIfChar(IsClosingSquareBracket)) {
312  child->diagnostic =
313  RaiseSyntaxError(_("Missing a closing bracket. Add a closing "
314  "bracket for each opening bracket."));
315  }
316  SkipIfChar(IsClosingSquareBracket);
317 
318  SkipAllWhitespaces();
319  if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
320  child->child = VariableAccessorOrVariableBracketAccessor();
321  child->child->parent = child.get();
322  }
323  child->location =
324  ExpressionParserLocation(childStartPosition, GetCurrentPosition());
325 
326  return std::move(child);
327  } else if (CheckIfChar(IsDot)) {
328  auto dotLocation = SkipChar();
329  SkipAllWhitespaces();
330 
331  auto identifierAndLocation = ReadIdentifierName(/*allowDeprecatedSpacesInName=*/ false);
332  auto child =
333  gd::make_unique<VariableAccessorNode>(identifierAndLocation.name);
334  if (identifierAndLocation.name.empty()) {
335  child->diagnostic = RaiseSyntaxError(_("A name should be entered after the dot."));
336  }
337 
338  SkipAllWhitespaces();
339  if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
340  child->child = VariableAccessorOrVariableBracketAccessor();
341  child->child->parent = child.get();
342  }
343  child->nameLocation = identifierAndLocation.location;
344  child->dotLocation = dotLocation;
345  child->location =
346  ExpressionParserLocation(childStartPosition, GetCurrentPosition());
347 
348  return std::move(child);
349  }
350 
351  // Should never happen, unless a node called this function without checking if the current character
352  // was a dot or an opening bracket - this means there is an error in the grammar.
353  auto unrecognisedNode = gd::make_unique<VariableAccessorOrVariableBracketAccessorNode>();
354  unrecognisedNode->diagnostic = RaiseSyntaxError(_("A dot or bracket was expected here."));
355  return std::move(unrecognisedNode);
356  }
357 
358  std::unique_ptr<FunctionCallNode> FreeFunction(
359  const gd::String &functionFullName,
360  const ExpressionParserLocation &identifierLocation,
361  const ExpressionParserLocation &openingParenthesisLocation) {
362  // TODO: error if trying to use function for type != "number" && != "string"
363  // + Test for it
364 
365  auto function =
366  gd::make_unique<FunctionCallNode>(functionFullName);
367  auto parametersNode = Parameters(function.get());
368  function->parameters = std::move(parametersNode.parameters);
369  function->diagnostic = std::move(parametersNode.diagnostic);
370 
371  function->location = ExpressionParserLocation(
372  identifierLocation.GetStartPosition(), GetCurrentPosition());
373  function->functionNameLocation = identifierLocation;
374  function->openingParenthesisLocation = openingParenthesisLocation;
375  function->closingParenthesisLocation =
376  parametersNode.closingParenthesisLocation;
377 
378  return std::move(function);
379  }
380 
381  std::unique_ptr<IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode>
382  ObjectFunctionOrBehaviorFunctionOrVariable(
383  const gd::String &parentIdentifier,
384  const ExpressionParserLocation &parentIdentifierLocation,
385  const ExpressionParserLocation &parentIdentifierDotLocation) {
386  auto childIdentifierAndLocation = ReadIdentifierName(/*allowDeprecatedSpacesInName=*/ false);
387  const gd::String &childIdentifierName = childIdentifierAndLocation.name;
388  const auto &childIdentifierNameLocation =
389  childIdentifierAndLocation.location;
390 
391  std::unique_ptr<gd::ExpressionParserError> emptyNameError = childIdentifierName.empty() ?
392  RaiseSyntaxError(_("A name should be entered after the dot.")) : nullptr;
393 
394  SkipAllWhitespaces();
395 
396  if (IsNamespaceSeparator()) {
397  ExpressionParserLocation namespaceSeparatorLocation =
398  SkipNamespaceSeparator();
399  SkipAllWhitespaces();
400  auto behaviorFunction = BehaviorFunction(parentIdentifier,
401  childIdentifierName,
402  parentIdentifierLocation,
403  parentIdentifierDotLocation,
404  childIdentifierNameLocation,
405  namespaceSeparatorLocation);
406 
407  if (emptyNameError) behaviorFunction->diagnostic = std::move(emptyNameError);
408  return std::move(behaviorFunction);
409  } else if (CheckIfChar(IsOpeningParenthesis)) {
410  ExpressionParserLocation openingParenthesisLocation = SkipChar();
411 
412  auto function = gd::make_unique<FunctionCallNode>(
413  parentIdentifier,
414  childIdentifierName);
415  auto parametersNode = Parameters(function.get(), parentIdentifier);
416  function->parameters = std::move(parametersNode.parameters),
417  function->diagnostic = emptyNameError ? std::move(emptyNameError) : std::move(parametersNode.diagnostic);
418 
419  function->location = ExpressionParserLocation(
420  parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
421  function->objectNameLocation = parentIdentifierLocation;
422  function->objectNameDotLocation = parentIdentifierDotLocation;
423  function->functionNameLocation = childIdentifierNameLocation;
424  function->openingParenthesisLocation = openingParenthesisLocation;
425  function->closingParenthesisLocation =
426  parametersNode.closingParenthesisLocation;
427  return std::move(function);
428  } else if (CheckIfChar(IsDot) || CheckIfChar(IsOpeningSquareBracket)) {
429  auto variable = gd::make_unique<VariableNode>(parentIdentifier);
430  variable->diagnostic = std::move(emptyNameError);
431 
432  auto child =
433  gd::make_unique<VariableAccessorNode>(childIdentifierName);
434  child->child = VariableAccessorOrVariableBracketAccessor();
435  child->child->parent = child.get();
436  child->nameLocation = childIdentifierNameLocation;
437  child->dotLocation = parentIdentifierDotLocation;
438  child->location = ExpressionParserLocation(
439  parentIdentifierDotLocation.GetStartPosition(), GetCurrentPosition());
440  variable->child = std::move(child);
441  variable->child->parent = variable.get();
442 
443  variable->location = ExpressionParserLocation(
444  parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
445  variable->nameLocation = parentIdentifierLocation;
446 
447  return std::move(variable);
448  }
449 
450  auto node = gd::make_unique<IdentifierNode>(
451  parentIdentifier, childIdentifierName);
452  node->location = ExpressionParserLocation(
453  parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
454  node->identifierNameLocation = parentIdentifierLocation;
455  node->identifierNameDotLocation = parentIdentifierDotLocation;
456  node->childIdentifierNameLocation = childIdentifierNameLocation;
457  node->diagnostic = std::move(emptyNameError);
458  return std::move(node);
459  }
460 
461  std::unique_ptr<FunctionCallOrObjectFunctionNameOrEmptyNode> BehaviorFunction(
462  const gd::String &objectName,
463  const gd::String &behaviorName,
464  const ExpressionParserLocation &objectNameLocation,
465  const ExpressionParserLocation &objectNameDotLocation,
466  const ExpressionParserLocation &behaviorNameLocation,
467  const ExpressionParserLocation &behaviorNameNamespaceSeparatorLocation) {
468  auto identifierAndLocation = ReadIdentifierName();
469  const gd::String &functionName = identifierAndLocation.name;
470  const auto &functionNameLocation = identifierAndLocation.location;
471 
472  SkipAllWhitespaces();
473 
474  if (CheckIfChar(IsOpeningParenthesis)) {
475  ExpressionParserLocation openingParenthesisLocation = SkipChar();
476 
477  auto function = gd::make_unique<FunctionCallNode>(
478  objectName,
479  behaviorName,
480  functionName);
481  auto parametersNode =
482  Parameters(function.get(), objectName, behaviorName);
483  function->parameters = std::move(parametersNode.parameters);
484  function->diagnostic = std::move(parametersNode.diagnostic);
485 
486  function->location = ExpressionParserLocation(
487  objectNameLocation.GetStartPosition(), GetCurrentPosition());
488  function->objectNameLocation = objectNameLocation;
489  function->objectNameDotLocation = objectNameDotLocation;
490  function->behaviorNameLocation = behaviorNameLocation;
491  function->behaviorNameNamespaceSeparatorLocation =
492  behaviorNameNamespaceSeparatorLocation;
493  function->openingParenthesisLocation = openingParenthesisLocation;
494  function->closingParenthesisLocation =
495  parametersNode.closingParenthesisLocation;
496  function->functionNameLocation = functionNameLocation;
497  return std::move(function);
498  } else {
499  auto node = gd::make_unique<ObjectFunctionNameNode>(
500  objectName, behaviorName, functionName);
501  node->diagnostic = RaiseSyntaxError(
502  _("An opening parenthesis was expected here to call a function."));
503 
504  node->location = ExpressionParserLocation(
505  objectNameLocation.GetStartPosition(), GetCurrentPosition());
506  node->objectNameLocation = objectNameLocation;
507  node->objectNameDotLocation = objectNameDotLocation;
508  node->objectFunctionOrBehaviorNameLocation = behaviorNameLocation;
509  node->behaviorNameNamespaceSeparatorLocation =
510  behaviorNameNamespaceSeparatorLocation;
511  node->behaviorFunctionNameLocation = functionNameLocation;
512  return std::move(node);
513  }
514  }
515 
516  // A temporary node that will be integrated into function nodes.
517  struct ParametersNode {
518  std::vector<std::unique_ptr<ExpressionNode>> parameters;
519  std::unique_ptr<gd::ExpressionParserError> diagnostic;
520  ExpressionParserLocation closingParenthesisLocation;
521  };
522 
523  ParametersNode Parameters(
524  FunctionCallNode *functionCallNode,
525  const gd::String &objectName = "",
526  const gd::String &behaviorName = "") {
527  std::vector<std::unique_ptr<ExpressionNode>> parameters;
528  gd::String lastObjectName = "";
529 
530  bool previousCharacterIsParameterSeparator = false;
531  while (!IsEndReached()) {
532  SkipAllWhitespaces();
533 
534  if (CheckIfChar(IsClosingParenthesis) && !previousCharacterIsParameterSeparator) {
535  auto closingParenthesisLocation = SkipChar();
536  return ParametersNode{
537  std::move(parameters), nullptr, closingParenthesisLocation};
538  }
539  bool isEmptyParameter = CheckIfChar(IsParameterSeparator)
540  || (CheckIfChar(IsClosingParenthesis) && previousCharacterIsParameterSeparator);
541  auto parameter = isEmptyParameter ? gd::make_unique<EmptyNode>() : Expression();
542  parameter->parent = functionCallNode;
543  parameters.push_back(std::move(parameter));
544 
545  SkipAllWhitespaces();
546  previousCharacterIsParameterSeparator = CheckIfChar(IsParameterSeparator);
547  SkipIfChar(IsParameterSeparator);
548  }
549 
550  ExpressionParserLocation invalidClosingParenthesisLocation;
551  return ParametersNode{
552  std::move(parameters),
553  RaiseSyntaxError(_("The list of parameters is not terminated. Add a "
554  "closing parenthesis to end the parameters.")),
555  invalidClosingParenthesisLocation};
556  }
558 
559  std::unique_ptr<ExpressionParserError> ValidateOperator(
560  gd::String::value_type operatorChar) {
561  if (operatorChar == '+' || operatorChar == '-' || operatorChar == '/' ||
562  operatorChar == '*') {
563  return std::unique_ptr<ExpressionParserError>(nullptr);
564  }
565  return gd::make_unique<ExpressionParserError>(
566  gd::ExpressionParserError::ErrorType::InvalidOperator,
567  _("You've used an operator that is not supported. Operator should be "
568  "either +, -, / or *."),
569  GetCurrentPosition());
570  }
571 
572  std::unique_ptr<ExpressionParserError> ValidateUnaryOperator(
573  gd::String::value_type operatorChar,
574  size_t position) {
575  if (operatorChar == '+' || operatorChar == '-') {
576  return std::unique_ptr<ExpressionParserError>(nullptr);
577  }
578 
579  return gd::make_unique<ExpressionParserError>(
580  gd::ExpressionParserError::ErrorType::InvalidOperator,
581  _("You've used an \"unary\" operator that is not supported. Operator "
582  "should be "
583  "either + or -."),
584  position);
585  }
587 
592  ExpressionParserLocation SkipChar() {
593  size_t startPosition = currentPosition;
594  return ExpressionParserLocation(startPosition, ++currentPosition);
595  }
596 
597  void SkipAllWhitespaces() {
598  while (currentPosition < expressionUtf32.size() &&
599  IsWhitespace(expressionUtf32[currentPosition])) {
600  currentPosition++;
601  }
602  }
603 
604  void SkipIfChar(
605  const std::function<bool(gd::String::value_type)> &predicate) {
606  if (CheckIfChar(predicate)) {
607  currentPosition++;
608  }
609  }
610 
611  ExpressionParserLocation SkipNamespaceSeparator() {
612  size_t startPosition = currentPosition;
613  // Namespace separator is a special kind of delimiter as it is 2 characters
614  // long
615  if (IsNamespaceSeparator()) {
616  currentPosition += NAMESPACE_SEPARATOR.size();
617  }
618 
619  return ExpressionParserLocation(startPosition, currentPosition);
620  }
621 
622  bool CheckIfChar(
623  const std::function<bool(gd::String::value_type)> &predicate) {
624  if (currentPosition >= expressionUtf32.size()) return false;
625  gd::String::value_type character = expressionUtf32[currentPosition];
626 
627  return predicate(character);
628  }
629 
630  bool IsNamespaceSeparator() {
631  // Namespace separator is a special kind of delimiter as it is 2 characters
632  // long. Computed once as the separator is a compile-time constant ("::").
633  static const std::u32string separator = NAMESPACE_SEPARATOR.ToUTF32();
634  return (currentPosition + separator.size() <= expressionUtf32.size() &&
635  expressionUtf32.compare(
636  currentPosition, separator.size(), separator) == 0);
637  }
638 
639  bool IsEndReached() { return currentPosition >= expressionUtf32.size(); }
640 
641  // A temporary node used when reading an identifier
642  struct IdentifierAndLocation {
643  gd::String name;
644  ExpressionParserLocation location;
645  };
646 
647  IdentifierAndLocation ReadIdentifierName(bool allowDeprecatedSpacesInName = true) {
648  gd::String name;
649  size_t startPosition = currentPosition;
650  while (currentPosition < expressionUtf32.size() &&
651  (CheckIfChar(IsAllowedInIdentifier)
652  // Allow whitespace in identifier name for compatibility
653  || (allowDeprecatedSpacesInName && expressionUtf32[currentPosition] == ' '))) {
654  name += expressionUtf32[currentPosition];
655  currentPosition++;
656  }
657 
658  // Trim whitespace at the end (we allow them for compatibility inside
659  // the name, but after the last character that is not whitespace, they
660  // should be ignore again).
661  if (!name.empty() && IsWhitespace(name[name.size() - 1])) {
662  size_t lastCharacterPos = name.size() - 1;
663  while (lastCharacterPos < name.size() &&
664  IsWhitespace(name[lastCharacterPos])) {
665  lastCharacterPos--;
666  }
667  if ((lastCharacterPos + 1) < name.size()) {
668  name.erase(lastCharacterPos + 1);
669  }
670  }
671 
672  IdentifierAndLocation identifierAndLocation{
673  name,
674  // The location is ignoring the trailing whitespace (only whitespace
675  // inside the identifier are allowed for compatibility).
676  ExpressionParserLocation(startPosition, startPosition + name.size())};
677  return identifierAndLocation;
678  }
679 
680  std::unique_ptr<TextNode> ReadText();
681 
682  std::unique_ptr<NumberNode> ReadNumber(size_t minusSignPosition = -1);
683 
684  std::unique_ptr<EmptyNode> ReadUntilWhitespace() {
685  size_t startPosition = GetCurrentPosition();
686  gd::String text;
687  while (currentPosition < expressionUtf32.size() &&
688  !IsWhitespace(expressionUtf32[currentPosition])) {
689  text += expressionUtf32[currentPosition];
690  currentPosition++;
691  }
692 
693  auto node = gd::make_unique<EmptyNode>(text);
694  node->location =
695  ExpressionParserLocation(startPosition, GetCurrentPosition());
696  return node;
697  }
698 
699  std::unique_ptr<EmptyNode> ReadUntilEnd() {
700  size_t startPosition = GetCurrentPosition();
701  gd::String text;
702  while (currentPosition < expressionUtf32.size()) {
703  text += expressionUtf32[currentPosition];
704  currentPosition++;
705  }
706 
707  auto node = gd::make_unique<EmptyNode>(text);
708  node->location =
709  ExpressionParserLocation(startPosition, GetCurrentPosition());
710  return node;
711  }
712 
713  size_t GetCurrentPosition() { return currentPosition; }
714 
715  gd::String::value_type GetCurrentChar() {
716  if (currentPosition < expressionUtf32.size()) {
717  return expressionUtf32[currentPosition];
718  }
719 
720  return '\n'; // Should not arise, unless GetCurrentChar was called when
721  // IsEndReached() is true (which is a logical error).
722  }
724 
729  std::unique_ptr<ExpressionParserError> RaiseSyntaxError(
730  const gd::String &message) {
731  return std::move(gd::make_unique<ExpressionParserError>(
732  gd::ExpressionParserError::ErrorType::SyntaxError, message,
733  GetCurrentPosition()));
734  }
735 
736  std::unique_ptr<ExpressionParserError> RaiseTypeError(
737  const gd::String &message, size_t beginningPosition) {
738  return std::move(gd::make_unique<ExpressionParserError>(
739  gd::ExpressionParserError::ErrorType::MismatchedType, message,
740  beginningPosition, GetCurrentPosition()));
741  }
743 
744  // The expression being parsed, stored as UTF-32 (fixed-width) so that
745  // character access (operator[]) and size() are O(1). See ParseExpression for
746  // the rationale.
747  std::u32string expressionUtf32;
748  std::size_t currentPosition;
749 
750  static gd::String NAMESPACE_SEPARATOR;
751 };
752 
753 } // namespace gd
754 
755 #endif // GDCORE_EXPRESSIONPARSER2_H
Class representing an expression used as a parameter of a gd::Instruction. This class is nothing more...
Definition: Expression.h:30
Parse an expression, returning a tree of node corresponding to the parsed expression.
Definition: ExpressionParser2.h:44
static size_t WrittenParametersFirstIndex(const gd::String &objectName, const gd::String &behaviorName)
Definition: ExpressionParser2.h:80
std::unique_ptr< ExpressionNode > ParseExpression(const gd::String &expression)
Definition: ExpressionParser2.h:56
String represents an UTF8 encoded string.
Definition: String.h:33
std::u32string ToUTF32() const
Definition: String.cpp:154
bool empty() const
Returns true if the string is empty.
Definition: String.h:157
iterator erase(iterator first, iterator last)
Erase the characters between first and last (last not included).
Definition: String.cpp:333
size_type size() const
Returns the string's length.
Definition: String.cpp:63
Definition: GrammarTerminals.h:9
bool IsAllowedInIdentifier(gd::String::value_type character)
Definition: GrammarTerminals.h:103
Definition: CommonTools.h:24
Definition: ExpressionParser2Node.h:25