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  size_t expressionStartPosition = GetCurrentPosition();
203  SkipChar();
204 
205  // The expression inside the parentheses excluding them.
206  auto expression = Expression();
207 
208  // The expression and its parentheses.
209  auto factor = gd::make_unique<SubExpressionNode>(std::move(expression));
210 
211  if (!CheckIfChar(IsClosingParenthesis)) {
212  factor->diagnostic =
213  RaiseSyntaxError(_("Missing a closing parenthesis. Add a closing "
214  "parenthesis for each opening parenthesis."));
215  }
216  SkipIfChar(IsClosingParenthesis);
217  factor->location = ExpressionParserLocation(expressionStartPosition,
218  GetCurrentPosition());
219 
220  return std::move(factor);
221  } else if (CheckIfChar(IsAllowedInIdentifier)) {
222  return Identifier();
223  }
224 
225  std::unique_ptr<ExpressionNode> factor = ReadUntilWhitespace();
226  return factor;
227  }
228 
229  std::unique_ptr<IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode>
230  Identifier() {
231  auto identifierAndLocation = ReadIdentifierName();
232  gd::String name = identifierAndLocation.name;
233  auto nameLocation = identifierAndLocation.location;
234 
235  SkipAllWhitespaces();
236 
237  // We consider a namespace separator to be allowed here and be part of the
238  // function name (or object name, but object names are not allowed to
239  // contain a ":"). This is because functions from extensions have their
240  // extension name prefix, and separated by the namespace separator. This
241  // could maybe be refactored to create different nodes in the future.
242  if (IsNamespaceSeparator()) {
243  SkipNamespaceSeparator();
244  SkipAllWhitespaces();
245 
246  auto postNamespaceIdentifierAndLocation = ReadIdentifierName();
247  name += NAMESPACE_SEPARATOR;
248  name += postNamespaceIdentifierAndLocation.name;
249  ExpressionParserLocation completeNameLocation(
250  nameLocation.GetStartPosition(),
251  postNamespaceIdentifierAndLocation.location.GetEndPosition());
252  nameLocation = completeNameLocation;
253  }
254 
255  if (CheckIfChar(IsOpeningParenthesis)) {
256  ExpressionParserLocation openingParenthesisLocation = SkipChar();
257  return FreeFunction(name, nameLocation, openingParenthesisLocation);
258  } else if (CheckIfChar(IsDot)) {
259  ExpressionParserLocation dotLocation = SkipChar();
260  SkipAllWhitespaces();
261  return ObjectFunctionOrBehaviorFunctionOrVariable(
262  name, nameLocation, dotLocation);
263  } else if (CheckIfChar(IsOpeningSquareBracket)) {
264  return Variable(name, nameLocation);
265  } else {
266  auto identifier = gd::make_unique<IdentifierNode>(name);
267  identifier->location = ExpressionParserLocation(
268  nameLocation.GetStartPosition(), GetCurrentPosition());
269  identifier->identifierNameLocation = identifier->location;
270  return std::move(identifier);
271  }
272  }
273 
274  std::unique_ptr<VariableNode> Variable(const gd::String &name, gd::ExpressionParserLocation nameLocation) {
275  auto variable = gd::make_unique<VariableNode>(name);
276 
277  if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
278  variable->child = VariableAccessorOrVariableBracketAccessor();
279  variable->child->parent = variable.get();
280  }
281 
282  variable->location = ExpressionParserLocation(
283  nameLocation.GetStartPosition(), GetCurrentPosition());
284  variable->nameLocation = nameLocation;
285  return std::move(variable);
286  }
287 
288  std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>
289  VariableAccessorOrVariableBracketAccessor() {
290  size_t childStartPosition = GetCurrentPosition();
291 
292  SkipAllWhitespaces();
293  if (CheckIfChar(IsOpeningSquareBracket)) {
294  SkipChar();
295  auto child = gd::make_unique<VariableBracketAccessorNode>(Expression());
296  child->expression->parent = child.get();
297 
298  if (!CheckIfChar(IsClosingSquareBracket)) {
299  child->diagnostic =
300  RaiseSyntaxError(_("Missing a closing bracket. Add a closing "
301  "bracket for each opening bracket."));
302  }
303  SkipIfChar(IsClosingSquareBracket);
304 
305  SkipAllWhitespaces();
306  if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
307  child->child = VariableAccessorOrVariableBracketAccessor();
308  child->child->parent = child.get();
309  }
310  child->location =
311  ExpressionParserLocation(childStartPosition, GetCurrentPosition());
312 
313  return std::move(child);
314  } else if (CheckIfChar(IsDot)) {
315  auto dotLocation = SkipChar();
316  SkipAllWhitespaces();
317 
318  auto identifierAndLocation = ReadIdentifierName(/*allowDeprecatedSpacesInName=*/ false);
319  auto child =
320  gd::make_unique<VariableAccessorNode>(identifierAndLocation.name);
321  if (identifierAndLocation.name.empty()) {
322  child->diagnostic = RaiseSyntaxError(_("A name should be entered after the dot."));
323  }
324 
325  SkipAllWhitespaces();
326  if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
327  child->child = VariableAccessorOrVariableBracketAccessor();
328  child->child->parent = child.get();
329  }
330  child->nameLocation = identifierAndLocation.location;
331  child->dotLocation = dotLocation;
332  child->location =
333  ExpressionParserLocation(childStartPosition, GetCurrentPosition());
334 
335  return std::move(child);
336  }
337 
338  // Should never happen, unless a node called this function without checking if the current character
339  // was a dot or an opening bracket - this means there is an error in the grammar.
340  auto unrecognisedNode = gd::make_unique<VariableAccessorOrVariableBracketAccessorNode>();
341  unrecognisedNode->diagnostic = RaiseSyntaxError(_("A dot or bracket was expected here."));
342  return std::move(unrecognisedNode);
343  }
344 
345  std::unique_ptr<FunctionCallNode> FreeFunction(
346  const gd::String &functionFullName,
347  const ExpressionParserLocation &identifierLocation,
348  const ExpressionParserLocation &openingParenthesisLocation) {
349  // TODO: error if trying to use function for type != "number" && != "string"
350  // + Test for it
351 
352  auto function =
353  gd::make_unique<FunctionCallNode>(functionFullName);
354  auto parametersNode = Parameters(function.get());
355  function->parameters = std::move(parametersNode.parameters);
356  function->diagnostic = std::move(parametersNode.diagnostic);
357 
358  function->location = ExpressionParserLocation(
359  identifierLocation.GetStartPosition(), GetCurrentPosition());
360  function->functionNameLocation = identifierLocation;
361  function->openingParenthesisLocation = openingParenthesisLocation;
362  function->closingParenthesisLocation =
363  parametersNode.closingParenthesisLocation;
364 
365  return std::move(function);
366  }
367 
368  std::unique_ptr<IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode>
369  ObjectFunctionOrBehaviorFunctionOrVariable(
370  const gd::String &parentIdentifier,
371  const ExpressionParserLocation &parentIdentifierLocation,
372  const ExpressionParserLocation &parentIdentifierDotLocation) {
373  auto childIdentifierAndLocation = ReadIdentifierName(/*allowDeprecatedSpacesInName=*/ false);
374  const gd::String &childIdentifierName = childIdentifierAndLocation.name;
375  const auto &childIdentifierNameLocation =
376  childIdentifierAndLocation.location;
377 
378  std::unique_ptr<gd::ExpressionParserError> emptyNameError = childIdentifierName.empty() ?
379  RaiseSyntaxError(_("A name should be entered after the dot.")) : nullptr;
380 
381  SkipAllWhitespaces();
382 
383  if (IsNamespaceSeparator()) {
384  ExpressionParserLocation namespaceSeparatorLocation =
385  SkipNamespaceSeparator();
386  SkipAllWhitespaces();
387  auto behaviorFunction = BehaviorFunction(parentIdentifier,
388  childIdentifierName,
389  parentIdentifierLocation,
390  parentIdentifierDotLocation,
391  childIdentifierNameLocation,
392  namespaceSeparatorLocation);
393 
394  if (emptyNameError) behaviorFunction->diagnostic = std::move(emptyNameError);
395  return std::move(behaviorFunction);
396  } else if (CheckIfChar(IsOpeningParenthesis)) {
397  ExpressionParserLocation openingParenthesisLocation = SkipChar();
398 
399  auto function = gd::make_unique<FunctionCallNode>(
400  parentIdentifier,
401  childIdentifierName);
402  auto parametersNode = Parameters(function.get(), parentIdentifier);
403  function->parameters = std::move(parametersNode.parameters),
404  function->diagnostic = emptyNameError ? std::move(emptyNameError) : std::move(parametersNode.diagnostic);
405 
406  function->location = ExpressionParserLocation(
407  parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
408  function->objectNameLocation = parentIdentifierLocation;
409  function->objectNameDotLocation = parentIdentifierDotLocation;
410  function->functionNameLocation = childIdentifierNameLocation;
411  function->openingParenthesisLocation = openingParenthesisLocation;
412  function->closingParenthesisLocation =
413  parametersNode.closingParenthesisLocation;
414  return std::move(function);
415  } else if (CheckIfChar(IsDot) || CheckIfChar(IsOpeningSquareBracket)) {
416  auto variable = gd::make_unique<VariableNode>(parentIdentifier);
417  variable->diagnostic = std::move(emptyNameError);
418 
419  auto child =
420  gd::make_unique<VariableAccessorNode>(childIdentifierName);
421  child->child = VariableAccessorOrVariableBracketAccessor();
422  child->child->parent = child.get();
423  child->nameLocation = childIdentifierNameLocation;
424  child->dotLocation = parentIdentifierDotLocation;
425  child->location = ExpressionParserLocation(
426  parentIdentifierDotLocation.GetStartPosition(), GetCurrentPosition());
427  variable->child = std::move(child);
428  variable->child->parent = variable.get();
429 
430  variable->location = ExpressionParserLocation(
431  parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
432  variable->nameLocation = parentIdentifierLocation;
433 
434  return std::move(variable);
435  }
436 
437  auto node = gd::make_unique<IdentifierNode>(
438  parentIdentifier, childIdentifierName);
439  node->location = ExpressionParserLocation(
440  parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
441  node->identifierNameLocation = parentIdentifierLocation;
442  node->identifierNameDotLocation = parentIdentifierDotLocation;
443  node->childIdentifierNameLocation = childIdentifierNameLocation;
444  node->diagnostic = std::move(emptyNameError);
445  return std::move(node);
446  }
447 
448  std::unique_ptr<FunctionCallOrObjectFunctionNameOrEmptyNode> BehaviorFunction(
449  const gd::String &objectName,
450  const gd::String &behaviorName,
451  const ExpressionParserLocation &objectNameLocation,
452  const ExpressionParserLocation &objectNameDotLocation,
453  const ExpressionParserLocation &behaviorNameLocation,
454  const ExpressionParserLocation &behaviorNameNamespaceSeparatorLocation) {
455  auto identifierAndLocation = ReadIdentifierName();
456  const gd::String &functionName = identifierAndLocation.name;
457  const auto &functionNameLocation = identifierAndLocation.location;
458 
459  SkipAllWhitespaces();
460 
461  if (CheckIfChar(IsOpeningParenthesis)) {
462  ExpressionParserLocation openingParenthesisLocation = SkipChar();
463 
464  auto function = gd::make_unique<FunctionCallNode>(
465  objectName,
466  behaviorName,
467  functionName);
468  auto parametersNode =
469  Parameters(function.get(), objectName, behaviorName);
470  function->parameters = std::move(parametersNode.parameters);
471  function->diagnostic = std::move(parametersNode.diagnostic);
472 
473  function->location = ExpressionParserLocation(
474  objectNameLocation.GetStartPosition(), GetCurrentPosition());
475  function->objectNameLocation = objectNameLocation;
476  function->objectNameDotLocation = objectNameDotLocation;
477  function->behaviorNameLocation = behaviorNameLocation;
478  function->behaviorNameNamespaceSeparatorLocation =
479  behaviorNameNamespaceSeparatorLocation;
480  function->openingParenthesisLocation = openingParenthesisLocation;
481  function->closingParenthesisLocation =
482  parametersNode.closingParenthesisLocation;
483  function->functionNameLocation = functionNameLocation;
484  return std::move(function);
485  } else {
486  auto node = gd::make_unique<ObjectFunctionNameNode>(
487  objectName, behaviorName, functionName);
488  node->diagnostic = RaiseSyntaxError(
489  _("An opening parenthesis was expected here to call a function."));
490 
491  node->location = ExpressionParserLocation(
492  objectNameLocation.GetStartPosition(), GetCurrentPosition());
493  node->objectNameLocation = objectNameLocation;
494  node->objectNameDotLocation = objectNameDotLocation;
495  node->objectFunctionOrBehaviorNameLocation = behaviorNameLocation;
496  node->behaviorNameNamespaceSeparatorLocation =
497  behaviorNameNamespaceSeparatorLocation;
498  node->behaviorFunctionNameLocation = functionNameLocation;
499  return std::move(node);
500  }
501  }
502 
503  // A temporary node that will be integrated into function nodes.
504  struct ParametersNode {
505  std::vector<std::unique_ptr<ExpressionNode>> parameters;
506  std::unique_ptr<gd::ExpressionParserError> diagnostic;
507  ExpressionParserLocation closingParenthesisLocation;
508  };
509 
510  ParametersNode Parameters(
511  FunctionCallNode *functionCallNode,
512  const gd::String &objectName = "",
513  const gd::String &behaviorName = "") {
514  std::vector<std::unique_ptr<ExpressionNode>> parameters;
515  gd::String lastObjectName = "";
516 
517  bool previousCharacterIsParameterSeparator = false;
518  while (!IsEndReached()) {
519  SkipAllWhitespaces();
520 
521  if (CheckIfChar(IsClosingParenthesis) && !previousCharacterIsParameterSeparator) {
522  auto closingParenthesisLocation = SkipChar();
523  return ParametersNode{
524  std::move(parameters), nullptr, closingParenthesisLocation};
525  }
526  bool isEmptyParameter = CheckIfChar(IsParameterSeparator)
527  || (CheckIfChar(IsClosingParenthesis) && previousCharacterIsParameterSeparator);
528  auto parameter = isEmptyParameter ? gd::make_unique<EmptyNode>() : Expression();
529  parameter->parent = functionCallNode;
530  parameters.push_back(std::move(parameter));
531 
532  SkipAllWhitespaces();
533  previousCharacterIsParameterSeparator = CheckIfChar(IsParameterSeparator);
534  SkipIfChar(IsParameterSeparator);
535  }
536 
537  ExpressionParserLocation invalidClosingParenthesisLocation;
538  return ParametersNode{
539  std::move(parameters),
540  RaiseSyntaxError(_("The list of parameters is not terminated. Add a "
541  "closing parenthesis to end the parameters.")),
542  invalidClosingParenthesisLocation};
543  }
545 
546  std::unique_ptr<ExpressionParserError> ValidateOperator(
547  gd::String::value_type operatorChar) {
548  if (operatorChar == '+' || operatorChar == '-' || operatorChar == '/' ||
549  operatorChar == '*') {
550  return std::unique_ptr<ExpressionParserError>(nullptr);
551  }
552  return gd::make_unique<ExpressionParserError>(
553  gd::ExpressionParserError::ErrorType::InvalidOperator,
554  _("You've used an operator that is not supported. Operator should be "
555  "either +, -, / or *."),
556  GetCurrentPosition());
557  }
558 
559  std::unique_ptr<ExpressionParserError> ValidateUnaryOperator(
560  gd::String::value_type operatorChar,
561  size_t position) {
562  if (operatorChar == '+' || operatorChar == '-') {
563  return std::unique_ptr<ExpressionParserError>(nullptr);
564  }
565 
566  return gd::make_unique<ExpressionParserError>(
567  gd::ExpressionParserError::ErrorType::InvalidOperator,
568  _("You've used an \"unary\" operator that is not supported. Operator "
569  "should be "
570  "either + or -."),
571  position);
572  }
574 
579  ExpressionParserLocation SkipChar() {
580  size_t startPosition = currentPosition;
581  return ExpressionParserLocation(startPosition, ++currentPosition);
582  }
583 
584  void SkipAllWhitespaces() {
585  while (currentPosition < expression.size() &&
586  IsWhitespace(expression[currentPosition])) {
587  currentPosition++;
588  }
589  }
590 
591  void SkipIfChar(
592  const std::function<bool(gd::String::value_type)> &predicate) {
593  if (CheckIfChar(predicate)) {
594  currentPosition++;
595  }
596  }
597 
598  ExpressionParserLocation SkipNamespaceSeparator() {
599  size_t startPosition = currentPosition;
600  // Namespace separator is a special kind of delimiter as it is 2 characters
601  // long
602  if (IsNamespaceSeparator()) {
603  currentPosition += NAMESPACE_SEPARATOR.size();
604  }
605 
606  return ExpressionParserLocation(startPosition, currentPosition);
607  }
608 
609  bool CheckIfChar(
610  const std::function<bool(gd::String::value_type)> &predicate) {
611  if (currentPosition >= expression.size()) return false;
612  gd::String::value_type character = expression[currentPosition];
613 
614  return predicate(character);
615  }
616 
617  bool IsNamespaceSeparator() {
618  // Namespace separator is a special kind of delimiter as it is 2 characters
619  // long
620  return (currentPosition + NAMESPACE_SEPARATOR.size() <= expression.size() &&
621  expression.substr(currentPosition, NAMESPACE_SEPARATOR.size()) ==
622  NAMESPACE_SEPARATOR);
623  }
624 
625  bool IsEndReached() { return currentPosition >= expression.size(); }
626 
627  // A temporary node used when reading an identifier
628  struct IdentifierAndLocation {
629  gd::String name;
630  ExpressionParserLocation location;
631  };
632 
633  IdentifierAndLocation ReadIdentifierName(bool allowDeprecatedSpacesInName = true) {
634  gd::String name;
635  size_t startPosition = currentPosition;
636  while (currentPosition < expression.size() &&
637  (CheckIfChar(IsAllowedInIdentifier)
638  // Allow whitespace in identifier name for compatibility
639  || (allowDeprecatedSpacesInName && expression[currentPosition] == ' '))) {
640  name += expression[currentPosition];
641  currentPosition++;
642  }
643 
644  // Trim whitespace at the end (we allow them for compatibility inside
645  // the name, but after the last character that is not whitespace, they
646  // should be ignore again).
647  if (!name.empty() && IsWhitespace(name[name.size() - 1])) {
648  size_t lastCharacterPos = name.size() - 1;
649  while (lastCharacterPos < name.size() &&
650  IsWhitespace(name[lastCharacterPos])) {
651  lastCharacterPos--;
652  }
653  if ((lastCharacterPos + 1) < name.size()) {
654  name.erase(lastCharacterPos + 1);
655  }
656  }
657 
658  IdentifierAndLocation identifierAndLocation{
659  name,
660  // The location is ignoring the trailing whitespace (only whitespace
661  // inside the identifier are allowed for compatibility).
662  ExpressionParserLocation(startPosition, startPosition + name.size())};
663  return identifierAndLocation;
664  }
665 
666  std::unique_ptr<TextNode> ReadText();
667 
668  std::unique_ptr<NumberNode> ReadNumber();
669 
670  std::unique_ptr<EmptyNode> ReadUntilWhitespace() {
671  size_t startPosition = GetCurrentPosition();
672  gd::String text;
673  while (currentPosition < expression.size() &&
674  !IsWhitespace(expression[currentPosition])) {
675  text += expression[currentPosition];
676  currentPosition++;
677  }
678 
679  auto node = gd::make_unique<EmptyNode>(text);
680  node->location =
681  ExpressionParserLocation(startPosition, GetCurrentPosition());
682  return node;
683  }
684 
685  std::unique_ptr<EmptyNode> ReadUntilEnd() {
686  size_t startPosition = GetCurrentPosition();
687  gd::String text;
688  while (currentPosition < expression.size()) {
689  text += expression[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  size_t GetCurrentPosition() { return currentPosition; }
700 
701  gd::String::value_type GetCurrentChar() {
702  if (currentPosition < expression.size()) {
703  return expression[currentPosition];
704  }
705 
706  return '\n'; // Should not arise, unless GetCurrentChar was called when
707  // IsEndReached() is true (which is a logical error).
708  }
710 
715  std::unique_ptr<ExpressionParserError> RaiseSyntaxError(
716  const gd::String &message) {
717  return std::move(gd::make_unique<ExpressionParserError>(
718  gd::ExpressionParserError::ErrorType::SyntaxError, message,
719  GetCurrentPosition()));
720  }
721 
722  std::unique_ptr<ExpressionParserError> RaiseTypeError(
723  const gd::String &message, size_t beginningPosition) {
724  return std::move(gd::make_unique<ExpressionParserError>(
725  gd::ExpressionParserError::ErrorType::MismatchedType, message,
726  beginningPosition, GetCurrentPosition()));
727  }
729 
730  gd::String expression;
731  std::size_t currentPosition;
732 
733  static gd::String NAMESPACE_SEPARATOR;
734 };
735 
736 } // namespace gd
737 
738 #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