6 #ifndef GDCORE_EXPRESSIONPARSER2_H
7 #define GDCORE_EXPRESSIONPARSER2_H
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"
18 #include "GDCore/String.h"
20 #include "GDCore/Tools/MakeUnique.h"
21 #include "GrammarTerminals.h"
24 class ObjectsContainer;
26 class ParameterMetadata;
27 class ExpressionMetadata;
65 expressionUtf32 = expression.
ToUTF32();
84 return !behaviorName.
empty() ? 2 : (!objectName.
empty() ? 1 : 0);
92 std::unique_ptr<ExpressionNode> Start() {
93 size_t expressionStartPosition = GetCurrentPosition();
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();
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)."));
108 GetCurrentPosition());
109 return std::move(op);
115 std::unique_ptr<ExpressionNode> Expression() {
116 SkipAllWhitespaces();
118 size_t expressionStartPosition = GetCurrentPosition();
119 std::unique_ptr<ExpressionNode> leftHandSide = Term();
121 SkipAllWhitespaces();
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());
131 op->rightHandSide = Expression();
132 op->rightHandSide->parent = op.get();
134 op->location = ExpressionParserLocation(expressionStartPosition,
135 GetCurrentPosition());
136 return std::move(op);
139 leftHandSide->diagnostic = RaiseSyntaxError(
140 "More than one term was found. Verify that your expression is "
141 "properly written.");
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();
149 ExpressionParserLocation(expressionStartPosition, GetCurrentPosition());
150 return std::move(op);
153 std::unique_ptr<ExpressionNode> Term() {
154 SkipAllWhitespaces();
156 size_t expressionStartPosition = GetCurrentPosition();
157 std::unique_ptr<ExpressionNode> factor = Factor();
159 SkipAllWhitespaces();
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());
170 op->rightHandSide = Factor();
171 op->rightHandSide->parent = op.get();
172 op->location = ExpressionParserLocation(expressionStartPosition,
173 GetCurrentPosition());
174 SkipAllWhitespaces();
176 factor = std::move(op);
182 std::unique_ptr<ExpressionNode> Factor() {
183 SkipAllWhitespaces();
184 size_t expressionStartPosition = GetCurrentPosition();
186 if (CheckIfChar(IsQuote)) {
187 std::unique_ptr<ExpressionNode> factor = ReadText();
189 }
else if (CheckIfChar(IsUnaryOperator)) {
190 auto unaryOperatorCharacter = GetCurrentChar();
192 bool isNumberSign = CheckIfChar(IsNumberSign);
194 if (isNumberSign && CheckIfChar(IsNumberFirstChar)) {
195 std::unique_ptr<ExpressionNode> numberNode =
196 ReadNumber(expressionStartPosition);
199 auto operatorOperand = Factor();
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());
210 return std::move(unaryOperator);
211 }
else if (CheckIfChar(IsNumberFirstChar)) {
212 std::unique_ptr<ExpressionNode> factor = ReadNumber();
214 }
else if (CheckIfChar(IsOpeningParenthesis)) {
215 size_t expressionStartPosition = GetCurrentPosition();
219 auto expression = Expression();
222 auto factor = gd::make_unique<SubExpressionNode>(std::move(expression));
224 if (!CheckIfChar(IsClosingParenthesis)) {
226 RaiseSyntaxError(_(
"Missing a closing parenthesis. Add a closing "
227 "parenthesis for each opening parenthesis."));
229 SkipIfChar(IsClosingParenthesis);
230 factor->location = ExpressionParserLocation(expressionStartPosition,
231 GetCurrentPosition());
233 return std::move(factor);
238 std::unique_ptr<ExpressionNode> factor = ReadUntilWhitespace();
242 std::unique_ptr<IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode>
244 auto identifierAndLocation = ReadIdentifierName();
246 auto nameLocation = identifierAndLocation.location;
248 SkipAllWhitespaces();
255 if (IsNamespaceSeparator()) {
256 SkipNamespaceSeparator();
257 SkipAllWhitespaces();
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;
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);
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);
288 auto variable = gd::make_unique<VariableNode>(name);
290 if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
291 variable->child = VariableAccessorOrVariableBracketAccessor();
292 variable->child->parent = variable.get();
295 variable->location = ExpressionParserLocation(
296 nameLocation.GetStartPosition(), GetCurrentPosition());
297 variable->nameLocation = nameLocation;
298 return std::move(variable);
301 std::unique_ptr<VariableAccessorOrVariableBracketAccessorNode>
302 VariableAccessorOrVariableBracketAccessor() {
303 size_t childStartPosition = GetCurrentPosition();
305 SkipAllWhitespaces();
306 if (CheckIfChar(IsOpeningSquareBracket)) {
309 SkipAllWhitespaces();
310 bool isEmptyBrackets = CheckIfChar(IsClosingSquareBracket);
312 auto child = gd::make_unique<VariableBracketAccessorNode>(Expression());
313 child->expression->parent = child.get();
315 if (!CheckIfChar(IsClosingSquareBracket) && !isEmptyBrackets) {
317 RaiseSyntaxError(_(
"Missing a closing bracket. Add a closing "
318 "bracket for each opening bracket."));
320 SkipIfChar(IsClosingSquareBracket);
322 SkipAllWhitespaces();
323 if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
324 child->child = VariableAccessorOrVariableBracketAccessor();
325 child->child->parent = child.get();
328 ExpressionParserLocation(childStartPosition, GetCurrentPosition());
330 return std::move(child);
331 }
else if (CheckIfChar(IsDot)) {
332 auto dotLocation = SkipChar();
333 SkipAllWhitespaces();
335 auto identifierAndLocation = ReadIdentifierName(
false);
337 gd::make_unique<VariableAccessorNode>(identifierAndLocation.name);
338 if (identifierAndLocation.name.empty()) {
339 child->diagnostic = RaiseSyntaxError(_(
"A name should be entered after the dot."));
342 SkipAllWhitespaces();
343 if (CheckIfChar(IsOpeningSquareBracket) || CheckIfChar(IsDot)) {
344 child->child = VariableAccessorOrVariableBracketAccessor();
345 child->child->parent = child.get();
347 child->nameLocation = identifierAndLocation.location;
348 child->dotLocation = dotLocation;
350 ExpressionParserLocation(childStartPosition, GetCurrentPosition());
352 return std::move(child);
357 auto unrecognisedNode = gd::make_unique<VariableAccessorOrVariableBracketAccessorNode>();
358 unrecognisedNode->diagnostic = RaiseSyntaxError(_(
"A dot or bracket was expected here."));
359 return std::move(unrecognisedNode);
362 std::unique_ptr<FunctionCallNode> FreeFunction(
364 const ExpressionParserLocation &identifierLocation,
365 const ExpressionParserLocation &openingParenthesisLocation) {
370 gd::make_unique<FunctionCallNode>(functionFullName);
371 auto parametersNode = Parameters(
function.get());
372 function->parameters = std::move(parametersNode.parameters);
373 function->diagnostic = std::move(parametersNode.diagnostic);
375 function->location = ExpressionParserLocation(
376 identifierLocation.GetStartPosition(), GetCurrentPosition());
377 function->functionNameLocation = identifierLocation;
378 function->openingParenthesisLocation = openingParenthesisLocation;
379 function->closingParenthesisLocation =
380 parametersNode.closingParenthesisLocation;
382 return std::move(
function);
385 std::unique_ptr<IdentifierOrFunctionCallOrObjectFunctionNameOrEmptyNode>
386 ObjectFunctionOrBehaviorFunctionOrVariable(
388 const ExpressionParserLocation &parentIdentifierLocation,
389 const ExpressionParserLocation &parentIdentifierDotLocation) {
390 auto childIdentifierAndLocation = ReadIdentifierName(
false);
391 const gd::String &childIdentifierName = childIdentifierAndLocation.name;
392 const auto &childIdentifierNameLocation =
393 childIdentifierAndLocation.location;
395 std::unique_ptr<gd::ExpressionParserError> emptyNameError = childIdentifierName.
empty() ?
396 RaiseSyntaxError(_(
"A name should be entered after the dot.")) : nullptr;
398 SkipAllWhitespaces();
400 if (IsNamespaceSeparator()) {
401 ExpressionParserLocation namespaceSeparatorLocation =
402 SkipNamespaceSeparator();
403 SkipAllWhitespaces();
404 auto behaviorFunction = BehaviorFunction(parentIdentifier,
406 parentIdentifierLocation,
407 parentIdentifierDotLocation,
408 childIdentifierNameLocation,
409 namespaceSeparatorLocation);
411 if (emptyNameError) behaviorFunction->diagnostic = std::move(emptyNameError);
412 return std::move(behaviorFunction);
413 }
else if (CheckIfChar(IsOpeningParenthesis)) {
414 ExpressionParserLocation openingParenthesisLocation = SkipChar();
416 auto function = gd::make_unique<FunctionCallNode>(
418 childIdentifierName);
419 auto parametersNode = Parameters(
function.get(), parentIdentifier);
420 function->parameters = std::move(parametersNode.parameters),
421 function->diagnostic = emptyNameError ? std::move(emptyNameError) : std::move(parametersNode.diagnostic);
423 function->location = ExpressionParserLocation(
424 parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
425 function->objectNameLocation = parentIdentifierLocation;
426 function->objectNameDotLocation = parentIdentifierDotLocation;
427 function->functionNameLocation = childIdentifierNameLocation;
428 function->openingParenthesisLocation = openingParenthesisLocation;
429 function->closingParenthesisLocation =
430 parametersNode.closingParenthesisLocation;
431 return std::move(
function);
432 }
else if (CheckIfChar(IsDot) || CheckIfChar(IsOpeningSquareBracket)) {
433 auto variable = gd::make_unique<VariableNode>(parentIdentifier);
434 variable->diagnostic = std::move(emptyNameError);
437 gd::make_unique<VariableAccessorNode>(childIdentifierName);
438 child->child = VariableAccessorOrVariableBracketAccessor();
439 child->child->parent = child.get();
440 child->nameLocation = childIdentifierNameLocation;
441 child->dotLocation = parentIdentifierDotLocation;
442 child->location = ExpressionParserLocation(
443 parentIdentifierDotLocation.GetStartPosition(), GetCurrentPosition());
444 variable->child = std::move(child);
445 variable->child->parent = variable.get();
447 variable->location = ExpressionParserLocation(
448 parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
449 variable->nameLocation = parentIdentifierLocation;
451 return std::move(variable);
454 auto node = gd::make_unique<IdentifierNode>(
455 parentIdentifier, childIdentifierName);
456 node->location = ExpressionParserLocation(
457 parentIdentifierLocation.GetStartPosition(), GetCurrentPosition());
458 node->identifierNameLocation = parentIdentifierLocation;
459 node->identifierNameDotLocation = parentIdentifierDotLocation;
460 node->childIdentifierNameLocation = childIdentifierNameLocation;
461 node->diagnostic = std::move(emptyNameError);
462 return std::move(node);
465 std::unique_ptr<FunctionCallOrObjectFunctionNameOrEmptyNode> BehaviorFunction(
468 const ExpressionParserLocation &objectNameLocation,
469 const ExpressionParserLocation &objectNameDotLocation,
470 const ExpressionParserLocation &behaviorNameLocation,
471 const ExpressionParserLocation &behaviorNameNamespaceSeparatorLocation) {
472 auto identifierAndLocation = ReadIdentifierName();
473 const gd::String &functionName = identifierAndLocation.name;
474 const auto &functionNameLocation = identifierAndLocation.location;
476 SkipAllWhitespaces();
478 if (CheckIfChar(IsOpeningParenthesis)) {
479 ExpressionParserLocation openingParenthesisLocation = SkipChar();
481 auto function = gd::make_unique<FunctionCallNode>(
485 auto parametersNode =
486 Parameters(
function.get(), objectName, behaviorName);
487 function->parameters = std::move(parametersNode.parameters);
488 function->diagnostic = std::move(parametersNode.diagnostic);
490 function->location = ExpressionParserLocation(
491 objectNameLocation.GetStartPosition(), GetCurrentPosition());
492 function->objectNameLocation = objectNameLocation;
493 function->objectNameDotLocation = objectNameDotLocation;
494 function->behaviorNameLocation = behaviorNameLocation;
495 function->behaviorNameNamespaceSeparatorLocation =
496 behaviorNameNamespaceSeparatorLocation;
497 function->openingParenthesisLocation = openingParenthesisLocation;
498 function->closingParenthesisLocation =
499 parametersNode.closingParenthesisLocation;
500 function->functionNameLocation = functionNameLocation;
501 return std::move(
function);
503 auto node = gd::make_unique<ObjectFunctionNameNode>(
504 objectName, behaviorName, functionName);
505 node->diagnostic = RaiseSyntaxError(
506 _(
"An opening parenthesis was expected here to call a function."));
508 node->location = ExpressionParserLocation(
509 objectNameLocation.GetStartPosition(), GetCurrentPosition());
510 node->objectNameLocation = objectNameLocation;
511 node->objectNameDotLocation = objectNameDotLocation;
512 node->objectFunctionOrBehaviorNameLocation = behaviorNameLocation;
513 node->behaviorNameNamespaceSeparatorLocation =
514 behaviorNameNamespaceSeparatorLocation;
515 node->behaviorFunctionNameLocation = functionNameLocation;
516 return std::move(node);
521 struct ParametersNode {
522 std::vector<std::unique_ptr<ExpressionNode>> parameters;
523 std::unique_ptr<gd::ExpressionParserError> diagnostic;
524 ExpressionParserLocation closingParenthesisLocation;
527 ParametersNode Parameters(
528 FunctionCallNode *functionCallNode,
531 std::vector<std::unique_ptr<ExpressionNode>> parameters;
534 bool previousCharacterIsParameterSeparator =
false;
535 while (!IsEndReached()) {
536 SkipAllWhitespaces();
538 if (CheckIfChar(IsClosingParenthesis) && !previousCharacterIsParameterSeparator) {
539 auto closingParenthesisLocation = SkipChar();
540 return ParametersNode{
541 std::move(parameters),
nullptr, closingParenthesisLocation};
543 bool isEmptyParameter = CheckIfChar(IsParameterSeparator)
544 || (CheckIfChar(IsClosingParenthesis) && previousCharacterIsParameterSeparator);
545 auto parameter = isEmptyParameter ? gd::make_unique<EmptyNode>() : Expression();
546 parameter->parent = functionCallNode;
547 parameters.push_back(std::move(parameter));
549 SkipAllWhitespaces();
550 previousCharacterIsParameterSeparator = CheckIfChar(IsParameterSeparator);
551 SkipIfChar(IsParameterSeparator);
554 ExpressionParserLocation invalidClosingParenthesisLocation;
555 return ParametersNode{
556 std::move(parameters),
557 RaiseSyntaxError(_(
"The list of parameters is not terminated. Add a "
558 "closing parenthesis to end the parameters.")),
559 invalidClosingParenthesisLocation};
563 std::unique_ptr<ExpressionParserError> ValidateOperator(
564 gd::String::value_type operatorChar) {
565 if (operatorChar ==
'+' || operatorChar ==
'-' || operatorChar ==
'/' ||
566 operatorChar ==
'*') {
567 return std::unique_ptr<ExpressionParserError>(
nullptr);
569 return gd::make_unique<ExpressionParserError>(
570 gd::ExpressionParserError::ErrorType::InvalidOperator,
571 _(
"You've used an operator that is not supported. Operator should be "
572 "either +, -, / or *."),
573 GetCurrentPosition());
576 std::unique_ptr<ExpressionParserError> ValidateUnaryOperator(
577 gd::String::value_type operatorChar,
579 if (operatorChar ==
'+' || operatorChar ==
'-') {
580 return std::unique_ptr<ExpressionParserError>(
nullptr);
583 return gd::make_unique<ExpressionParserError>(
584 gd::ExpressionParserError::ErrorType::InvalidOperator,
585 _(
"You've used an \"unary\" operator that is not supported. Operator "
596 ExpressionParserLocation SkipChar() {
597 size_t startPosition = currentPosition;
598 return ExpressionParserLocation(startPosition, ++currentPosition);
601 void SkipAllWhitespaces() {
602 while (currentPosition < expressionUtf32.size() &&
603 IsWhitespace(expressionUtf32[currentPosition])) {
609 const std::function<
bool(gd::String::value_type)> &predicate) {
610 if (CheckIfChar(predicate)) {
615 ExpressionParserLocation SkipNamespaceSeparator() {
616 size_t startPosition = currentPosition;
619 if (IsNamespaceSeparator()) {
620 currentPosition += NAMESPACE_SEPARATOR.size();
623 return ExpressionParserLocation(startPosition, currentPosition);
627 const std::function<
bool(gd::String::value_type)> &predicate) {
628 if (currentPosition >= expressionUtf32.size())
return false;
629 gd::String::value_type character = expressionUtf32[currentPosition];
631 return predicate(character);
634 bool IsNamespaceSeparator() {
637 static const std::u32string separator = NAMESPACE_SEPARATOR.ToUTF32();
638 return (currentPosition + separator.size() <= expressionUtf32.size() &&
639 expressionUtf32.compare(
640 currentPosition, separator.size(), separator) == 0);
643 bool IsEndReached() {
return currentPosition >= expressionUtf32.size(); }
646 struct IdentifierAndLocation {
648 ExpressionParserLocation location;
651 IdentifierAndLocation ReadIdentifierName(
bool allowDeprecatedSpacesInName =
true) {
653 size_t startPosition = currentPosition;
654 while (currentPosition < expressionUtf32.size() &&
657 || (allowDeprecatedSpacesInName && expressionUtf32[currentPosition] ==
' '))) {
658 name += expressionUtf32[currentPosition];
665 if (!name.
empty() && IsWhitespace(name[name.
size() - 1])) {
666 size_t lastCharacterPos = name.
size() - 1;
667 while (lastCharacterPos < name.
size() &&
668 IsWhitespace(name[lastCharacterPos])) {
671 if ((lastCharacterPos + 1) < name.
size()) {
672 name.
erase(lastCharacterPos + 1);
676 IdentifierAndLocation identifierAndLocation{
680 ExpressionParserLocation(startPosition, startPosition + name.
size())};
681 return identifierAndLocation;
684 std::unique_ptr<TextNode> ReadText();
686 std::unique_ptr<NumberNode> ReadNumber(
size_t minusSignPosition = -1);
688 std::unique_ptr<EmptyNode> ReadUntilWhitespace() {
689 size_t startPosition = GetCurrentPosition();
691 while (currentPosition < expressionUtf32.size() &&
692 !IsWhitespace(expressionUtf32[currentPosition])) {
693 text += expressionUtf32[currentPosition];
697 auto node = gd::make_unique<EmptyNode>(text);
699 ExpressionParserLocation(startPosition, GetCurrentPosition());
703 std::unique_ptr<EmptyNode> ReadUntilEnd() {
704 size_t startPosition = GetCurrentPosition();
706 while (currentPosition < expressionUtf32.size()) {
707 text += expressionUtf32[currentPosition];
711 auto node = gd::make_unique<EmptyNode>(text);
713 ExpressionParserLocation(startPosition, GetCurrentPosition());
717 size_t GetCurrentPosition() {
return currentPosition; }
719 gd::String::value_type GetCurrentChar() {
720 if (currentPosition < expressionUtf32.size()) {
721 return expressionUtf32[currentPosition];
733 std::unique_ptr<ExpressionParserError> RaiseSyntaxError(
735 return std::move(gd::make_unique<ExpressionParserError>(
736 gd::ExpressionParserError::ErrorType::SyntaxError, message,
737 GetCurrentPosition()));
740 std::unique_ptr<ExpressionParserError> RaiseTypeError(
741 const gd::String &message,
size_t beginningPosition) {
742 return std::move(gd::make_unique<ExpressionParserError>(
743 gd::ExpressionParserError::ErrorType::MismatchedType, message,
744 beginningPosition, GetCurrentPosition()));
751 std::u32string expressionUtf32;
752 std::size_t currentPosition;
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:16
bool IsAllowedInIdentifier(gd::String::value_type character)
Definition: GrammarTerminals.h:110
Definition: CommonTools.h:24
Definition: ExpressionParser2Node.h:25