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