10 #include "GDCore/Events/Parsers/ExpressionParser2Node.h" 
   11 #include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h" 
   12 #include "GDCore/Tools/MakeUnique.h" 
   14 #include "GDCore/Extensions/Metadata/ExpressionMetadata.h" 
   15 #include "GDCore/Project/ProjectScopedContainers.h" 
   16 #include "GDCore/Project/VariablesContainersList.h" 
   17 #include "GDCore/Project/VariablesContainer.h" 
   21 class ObjectsContainer;
 
   22 class VariablesContainer;
 
   24 class ParameterMetadata;
 
   25 class ExpressionMetadata;
 
   26 class VariablesContainersList;
 
   27 class ProjectScopedContainers;
 
   44       : platform(platform_),
 
   45         projectScopedContainers(projectScopedContainers_),
 
   47         childType(Type::Unknown),
 
   48         forbidsUsageOfBracketsBecauseParentIsObject(
false),
 
   49         currentParameterExtraInfo(&extraInfo_),
 
   51         variableObjectNameLocation() {};
 
   63     node.Visit(validator);
 
   88     node.expression->Visit(*
this);
 
   90   void OnVisitOperatorNode(OperatorNode& node)
 override {
 
   95     node.leftHandSide->Visit(*
this);
 
   96     const Type leftType = childType; 
 
   98     if (leftType == Type::Number) {
 
  100         RaiseError(gd::ExpressionParserError::ErrorType::SyntaxError,
 
  101             "No operator found. Did you forget to enter an operator (like +, -, " 
  102             "* or /) between numbers or expressions?", node.rightHandSide->location);
 
  105     else if (leftType == Type::String) {
 
  106       if (node.op == 
' ') {
 
  107         RaiseError(gd::ExpressionParserError::ErrorType::SyntaxError,
 
  108             "You must add the operator + between texts or expressions. For " 
  109             "example: \"Your name: \" + VariableString(PlayerName).", node.rightHandSide->location);
 
  111       else if (node.op != 
'+') {
 
  113             _(
"You've used an operator that is not supported. Only + can be used " 
  114               "to concatenate texts."),
 
  115             ExpressionParserLocation(node.leftHandSide->location.GetEndPosition() + 1, node.location.GetEndPosition()));
 
  117     } 
else if (leftType == Type::Object) {
 
  119           _(
"Operators (+, -, /, *) can't be used with an object name. Remove " 
  121             node.rightHandSide->location);
 
  122     } 
else if (leftType == Type::Variable || leftType == Type::LegacyVariable) {
 
  124           _(
"Operators (+, -, /, *) can't be used in variable names. Remove " 
  125             "the operator from the variable name."),
 
  126             node.rightHandSide->location);
 
  132     parentType = ShouldTypeBeRefined(parentType) ? leftType : parentType;
 
  133     node.rightHandSide->Visit(*
this);
 
  134     const Type rightType = childType;
 
  141     childType = ShouldTypeBeRefined(parentType) ? (ShouldTypeBeRefined(leftType) ? leftType : rightType) : parentType;
 
  143   void OnVisitUnaryOperatorNode(UnaryOperatorNode& node)
 override {
 
  144     ReportAnyError(node);
 
  145     node.factor->Visit(*
this);
 
  146     const Type rightType = childType;
 
  148     if (rightType == Type::Number) {
 
  149       if (node.op != 
'+' && node.op != 
'-') {
 
  153           _(
"You've used an \"unary\" operator that is not supported. Operator " 
  158     } 
else if (rightType == Type::String) {
 
  160           _(
"You've used an operator that is not supported. Only + can be used " 
  161             "to concatenate texts, and must be placed between two texts (or " 
  164     } 
else if (rightType == Type::Object) {
 
  166           _(
"Operators (+, -) can't be used with an object name. Remove the " 
  169     } 
else if (rightType == Type::Variable || rightType == Type::LegacyVariable) {
 
  171           _(
"Operators (+, -) can't be used in variable names. Remove " 
  172             "the operator from the variable name."),
 
  176   void OnVisitNumberNode(NumberNode& node)
 override {
 
  177     ReportAnyError(node);
 
  178     childType = Type::Number;
 
  179     if (parentType == Type::String) {
 
  181           _(
"You entered a number, but a text was expected (in quotes)."),
 
  183     } 
else if (parentType != Type::Number &&
 
  184                parentType != Type::NumberOrString) {
 
  185       RaiseTypeError(_(
"You entered a number, but this type was expected:") +
 
  186                          " " + TypeToString(parentType),
 
  190   void OnVisitTextNode(TextNode& node)
 override {
 
  191     ReportAnyError(node);
 
  192     childType = Type::String;
 
  193     if (parentType == Type::Number) {
 
  194       RaiseTypeError(_(
"You entered a text, but a number was expected."),
 
  196     } 
else if (parentType != Type::String &&
 
  197                parentType != Type::NumberOrString) {
 
  198       RaiseTypeError(_(
"You entered a text, but this type was expected:") +
 
  199                          " " + TypeToString(parentType),
 
  203   void OnVisitVariableNode(VariableNode& node)
 override {
 
  204     ReportAnyError(node);
 
  206     if (parentType == Type::Variable ||
 
  207         parentType == Type::VariableOrProperty ||
 
  208         parentType == Type::VariableOrPropertyOrParameter) {
 
  209       childType = parentType;
 
  211       CheckVariableExistence(node.location, node.name, node.child != 
nullptr);
 
  213         node.child->Visit(*
this);
 
  215     } 
else if (parentType == Type::LegacyVariable) {
 
  216       childType = parentType;
 
  219         node.child->Visit(*
this);
 
  221     } 
else if (parentType == Type::String || parentType == Type::Number ||
 
  222                parentType == Type::NumberOrString) {
 
  224       childType = parentType;
 
  226       const auto& variablesContainersList = projectScopedContainers.GetVariablesContainersList();
 
  227       const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
 
  228       const auto& propertiesContainerList = projectScopedContainers.GetPropertiesContainersList();
 
  230       forbidsUsageOfBracketsBecauseParentIsObject = 
false;
 
  231       projectScopedContainers.MatchIdentifierWithName<
void>(node.name,
 
  234           variableObjectName = node.name;
 
  235           variableObjectNameLocation = node.nameLocation;
 
  238           forbidsUsageOfBracketsBecauseParentIsObject = 
true;
 
  244           RaiseTypeError(_(
"Accessing a child variable of a property is not possible - just write the property name."),
 
  249           RaiseTypeError(_(
"Accessing a child variable of a parameter is not possible - just write the parameter name."),
 
  253           RaiseTypeError(_(
"No object, variable or property with this name found."),
 
  258         node.child->Visit(*
this);
 
  261       forbidsUsageOfBracketsBecauseParentIsObject = 
false;
 
  263       RaiseTypeError(_(
"You entered a variable, but this type was expected:") +
 
  264                          " " + TypeToString(parentType),
 
  268         node.child->Visit(*
this);
 
  272   void OnVisitVariableAccessorNode(VariableAccessorNode& node)
 override {
 
  273     ReportAnyError(node);
 
  275     if (!variableObjectName.empty()) {
 
  276       ValidateObjectVariableOrVariableOrProperty(variableObjectName,
 
  277                                                  variableObjectNameLocation,
 
  278                                                  node.name, node.nameLocation);
 
  279       variableObjectName = 
"";
 
  283     forbidsUsageOfBracketsBecauseParentIsObject = 
false;
 
  286       node.child->Visit(*
this);
 
  289   void OnVisitVariableBracketAccessorNode(
 
  290       VariableBracketAccessorNode& node)
 override {
 
  291     ReportAnyError(node);
 
  293     variableObjectName = 
"";
 
  294     if (forbidsUsageOfBracketsBecauseParentIsObject) {
 
  295       RaiseError(gd::ExpressionParserError::ErrorType::BracketsNotAllowedForObjects,
 
  296                  _(
"You can't use the brackets to access an object variable. " 
  297                    "Use a dot followed by the variable name, like this: " 
  298                    "`MyObject.MyVariable`."),
 
  301     forbidsUsageOfBracketsBecauseParentIsObject = 
false;
 
  303     Type currentParentType = parentType;
 
  304     Type currentChildType = childType;
 
  305     parentType = Type::NumberOrString;
 
  306     auto parentParameterExtraInfo = currentParameterExtraInfo;
 
  307     currentParameterExtraInfo = 
nullptr;
 
  308     node.expression->Visit(*
this);
 
  309     currentParameterExtraInfo = parentParameterExtraInfo;
 
  310     parentType = currentParentType;
 
  311     childType = currentChildType;
 
  314       node.child->Visit(*
this);
 
  317   void OnVisitIdentifierNode(IdentifierNode& node)
 override {
 
  318     ReportAnyError(node);
 
  319     if (parentType == Type::String) {
 
  320       if (!ValidateObjectVariableOrVariableOrProperty(node)) {
 
  323         RaiseUnknownIdentifierError(_(
"You must wrap your text inside double quotes " 
  324                               "(example: \"Hello world\")."),
 
  328     else if (parentType == Type::Number) {
 
  329       if (!ValidateObjectVariableOrVariableOrProperty(node)) {
 
  331         RaiseUnknownIdentifierError(_(
"You must enter a number."), node.location);
 
  334     else if (parentType == Type::NumberOrString) {
 
  335       if (!ValidateObjectVariableOrVariableOrProperty(node)) {
 
  338         RaiseUnknownIdentifierError(
 
  339             _(
"You must enter a number or a text, wrapped inside double quotes (example: \"Hello world\"), or a variable name."),
 
  342     } 
else if (parentType == Type::Variable ||
 
  343                parentType == Type::VariableOrProperty ||
 
  344                parentType == Type::VariableOrPropertyOrParameter) {
 
  345       CheckVariableExistence(node.location, node.identifierName, !node.childIdentifierName.empty());
 
  346     } 
else if (parentType != Type::Object &&
 
  347                parentType != Type::LegacyVariable) {
 
  350           _(
"You've entered a name, but this type was expected:") + 
" " + TypeToString(parentType),
 
  352       childType = parentType;
 
  354       childType = parentType;
 
  357   void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node)
 override {
 
  358     ReportAnyError(node);
 
  360   void OnVisitFunctionCallNode(FunctionCallNode& node)
 override {
 
  361     childType = ValidateFunction(node);
 
  363   void OnVisitEmptyNode(EmptyNode& node)
 override {
 
  364     ReportAnyError(node);
 
  366     if (parentType == Type::Number) {
 
  367       message = _(
"You must enter a number or a valid expression call.");
 
  368     } 
else if (parentType == Type::String) {
 
  370           "You must enter a text (between quotes) or a valid expression call.");
 
  371     } 
else if (parentType == Type::Variable || parentType == Type::LegacyVariable) {
 
  372       message = _(
"You must enter a variable name.");
 
  373     } 
else if (parentType == Type::Object) {
 
  374       message = _(
"You must enter a valid object name.");
 
  377       message = _(
"You must enter a valid expression.");
 
  379     RaiseTypeError(message, node.location);
 
  380     childType = Type::Empty;
 
  394     VariableOrPropertyOrParameter
 
  397   bool ValidateObjectVariableOrVariableOrProperty(
const gd::IdentifierNode& identifier);
 
  398   bool ValidateObjectVariableOrVariableOrProperty(
 
  404   void CheckVariableExistence(
const ExpressionParserLocation &location,
 
  406     if (!currentParameterExtraInfo ||
 
  407         *currentParameterExtraInfo != 
"AllowUndeclaredVariable") {
 
  408       projectScopedContainers.MatchIdentifierWithName<
void>(
 
  412             RaiseVariableNameCollisionError(
 
  413                 _(
"This variable has the same name as an object. Consider " 
  414                   "renaming one or the other."),
 
  422             if (parentType != Type::VariableOrProperty &&
 
  423                 parentType != Type::VariableOrPropertyOrParameter) {
 
  424               RaiseVariableNameCollisionError(
 
  425                   _(
"This variable has the same name as a property. Consider " 
  426                     "renaming one or the other."),
 
  428             } 
else if (hasChild) {
 
  429               RaiseMalformedVariableParameter(
 
  430                   _(
"Properties can't have children."), location, name);
 
  435             if (parentType != Type::VariableOrPropertyOrParameter) {
 
  436               RaiseVariableNameCollisionError(
 
  437                   _(
"This variable has the same name as a parameter. Consider " 
  438                     "renaming one or the other."),
 
  440             } 
else if (hasChild) {
 
  441               RaiseMalformedVariableParameter(
 
  442                   _(
"Properties can't have children."), location, name);
 
  447             RaiseUndeclaredVariableError(
 
  448                 _(
"No variable with this name found."), location,
 
  454   void ReportAnyError(
const ExpressionNode& node, 
bool isFatal = 
true) {
 
  455     if (node.diagnostic) {
 
  459       allErrors.push_back(node.diagnostic.get());
 
  461         fatalErrors.push_back(node.diagnostic.get());
 
  466   void RaiseError(gd::ExpressionParserError::ErrorType type,
 
  468                   const ExpressionParserLocation &location, 
bool isFatal = 
true,
 
  471     auto diagnostic = gd::make_unique<ExpressionParserError>(
 
  472         type, message, location, actualValue, objectName);
 
  473     allErrors.push_back(diagnostic.get());
 
  475       fatalErrors.push_back(diagnostic.get());
 
  480     supplementalErrors.push_back(std::move(diagnostic));
 
  483   void RaiseUnknownIdentifierError(
const gd::String &message,
 
  484                                    const ExpressionParserLocation &location) {
 
  485     RaiseError(gd::ExpressionParserError::ErrorType::UnknownIdentifier, message,
 
  489   void RaiseUndeclaredVariableError(
const gd::String &message,
 
  490                                     const ExpressionParserLocation &location,
 
  493     RaiseError(gd::ExpressionParserError::ErrorType::UndeclaredVariable,
 
  494                message, location, 
true, variableName, objectName);
 
  497   void RaiseVariableNameCollisionError(
const gd::String &message,
 
  498                                     const ExpressionParserLocation &location,
 
  501     RaiseError(gd::ExpressionParserError::ErrorType::VariableNameCollision,
 
  502                message, location, 
false, variableName, objectName);
 
  505   void RaiseMalformedVariableParameter(
const gd::String &message,
 
  506                                    const ExpressionParserLocation &location,
 
  508     RaiseError(gd::ExpressionParserError::ErrorType::MalformedVariableParameter,
 
  509                message, location, 
true, variableName, 
"");
 
  512   void RaiseTypeError(
const gd::String &message,
 
  513                       const ExpressionParserLocation &location,
 
  514                       bool isFatal = 
true) {
 
  515     RaiseError(gd::ExpressionParserError::ErrorType::MismatchedType, message,
 
  519   void RaiseOperatorError(
const gd::String &message,
 
  520                           const ExpressionParserLocation &location) {
 
  521     RaiseError(gd::ExpressionParserError::ErrorType::InvalidOperator, message,
 
  526     if (variableType == gd::Variable::Number) {
 
  527       childType = Type::Number;
 
  528     } 
else if (variableType == gd::Variable::String) {
 
  529       childType = Type::String;
 
  535   static bool ShouldTypeBeRefined(
Type type) {
 
  536     return (type == Type::Unknown || type == Type::NumberOrString);
 
  544   static const gd::String numberOrStringTypeString;
 
  546   static const gd::String legacyVariableTypeString;
 
  551   std::vector<ExpressionParserError*> fatalErrors;
 
  552   std::vector<ExpressionParserError*> allErrors;
 
  553   std::vector<std::unique_ptr<ExpressionParserError>> supplementalErrors;
 
  556   bool forbidsUsageOfBracketsBecauseParentIsObject;
 
The interface for any worker class ("visitor" pattern) that want to interact with the nodes of a pars...
Definition: ExpressionParser2NodeWorker.h:36
Validate that an expression is properly written by returning any error attached to the nodes during p...
Definition: ExpressionValidator.h:38
const std::vector< ExpressionParserError * > & GetFatalErrors()
Get only the fatal errors.
Definition: ExpressionValidator.h:72
const std::vector< ExpressionParserError * > & GetAllErrors()
Get all the errors.
Definition: ExpressionValidator.h:81
static bool HasNoErrors(const gd::Platform &platform, const gd::ProjectScopedContainers &projectScopedContainers, const gd::String &rootType, gd::ExpressionNode &node)
Helper function to check if a given node does not contain any error including non-fatal ones.
Definition: ExpressionValidator.h:58
Holds references to variables, objects, properties and other containers.
Definition: ProjectScopedContainers.h:34
String represents an UTF8 encoded string.
Definition: String.h:33
Type
Definition: Variable.h:32
Definition: CommonTools.h:24
Type
Type of JSON value.
Definition: rapidjson.h:603
The base node, from which all nodes in the tree of an expression inherits from.
Definition: ExpressionParser2Node.h:100
Definition: ExpressionParser2Node.h:25
A function call node (either free function, object function or object behavior function)....
Definition: ExpressionParser2Node.h:371
An identifier node, usually representing an object or a variable with an optional function name or ch...
Definition: ExpressionParser2Node.h:204
Definition: ExpressionParser2Node.h:115