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 childType = parentType;
209 CheckVariableExistence(node.location, node.name);
211 node.child->Visit(*
this);
213 }
else if (parentType == Type::LegacyVariable) {
214 childType = parentType;
217 node.child->Visit(*
this);
219 }
else if (parentType == Type::String || parentType == Type::Number || parentType == Type::NumberOrString) {
221 childType = parentType;
223 const auto& variablesContainersList = projectScopedContainers.GetVariablesContainersList();
224 const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
225 const auto& propertiesContainerList = projectScopedContainers.GetPropertiesContainersList();
227 forbidsUsageOfBracketsBecauseParentIsObject =
false;
228 projectScopedContainers.MatchIdentifierWithName<
void>(node.name,
231 variableObjectName = node.name;
232 variableObjectNameLocation = node.nameLocation;
235 forbidsUsageOfBracketsBecauseParentIsObject =
true;
241 RaiseTypeError(_(
"Accessing a child variable of a property is not possible - just write the property name."),
246 RaiseTypeError(_(
"Accessing a child variable of a parameter is not possible - just write the parameter name."),
250 RaiseTypeError(_(
"No object, variable or property with this name found."),
255 node.child->Visit(*
this);
258 forbidsUsageOfBracketsBecauseParentIsObject =
false;
260 RaiseTypeError(_(
"You entered a variable, but this type was expected:") +
261 " " + TypeToString(parentType),
265 node.child->Visit(*
this);
269 void OnVisitVariableAccessorNode(VariableAccessorNode& node)
override {
270 ReportAnyError(node);
272 if (!variableObjectName.empty()) {
273 ValidateObjectVariableOrVariableOrProperty(variableObjectName,
274 variableObjectNameLocation,
275 node.name, node.nameLocation);
276 variableObjectName =
"";
280 forbidsUsageOfBracketsBecauseParentIsObject =
false;
283 node.child->Visit(*
this);
286 void OnVisitVariableBracketAccessorNode(
287 VariableBracketAccessorNode& node)
override {
288 ReportAnyError(node);
290 variableObjectName =
"";
291 if (forbidsUsageOfBracketsBecauseParentIsObject) {
292 RaiseError(gd::ExpressionParserError::ErrorType::BracketsNotAllowedForObjects,
293 _(
"You can't use the brackets to access an object variable. "
294 "Use a dot followed by the variable name, like this: "
295 "`MyObject.MyVariable`."),
298 forbidsUsageOfBracketsBecauseParentIsObject =
false;
300 Type currentParentType = parentType;
301 Type currentChildType = childType;
302 parentType = Type::NumberOrString;
303 auto parentParameterExtraInfo = currentParameterExtraInfo;
304 currentParameterExtraInfo =
nullptr;
305 node.expression->Visit(*
this);
306 currentParameterExtraInfo = parentParameterExtraInfo;
307 parentType = currentParentType;
308 childType = currentChildType;
311 node.child->Visit(*
this);
314 void OnVisitIdentifierNode(IdentifierNode& node)
override {
315 ReportAnyError(node);
316 if (parentType == Type::String) {
317 if (!ValidateObjectVariableOrVariableOrProperty(node)) {
320 RaiseUnknownIdentifierError(_(
"You must wrap your text inside double quotes "
321 "(example: \"Hello world\")."),
325 else if (parentType == Type::Number) {
326 if (!ValidateObjectVariableOrVariableOrProperty(node)) {
328 RaiseUnknownIdentifierError(_(
"You must enter a number."), node.location);
331 else if (parentType == Type::NumberOrString) {
332 if (!ValidateObjectVariableOrVariableOrProperty(node)) {
335 RaiseUnknownIdentifierError(
336 _(
"You must enter a number or a text, wrapped inside double quotes (example: \"Hello world\"), or a variable name."),
340 else if (parentType == Type::Variable) {
341 CheckVariableExistence(node.location, node.identifierName);
343 else if (parentType != Type::Object && parentType != Type::LegacyVariable) {
346 _(
"You've entered a name, but this type was expected:") +
" " + TypeToString(parentType),
348 childType = parentType;
350 childType = parentType;
353 void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node)
override {
354 ReportAnyError(node);
356 void OnVisitFunctionCallNode(FunctionCallNode& node)
override {
357 childType = ValidateFunction(node);
359 void OnVisitEmptyNode(EmptyNode& node)
override {
360 ReportAnyError(node);
362 if (parentType == Type::Number) {
363 message = _(
"You must enter a number or a valid expression call.");
364 }
else if (parentType == Type::String) {
366 "You must enter a text (between quotes) or a valid expression call.");
367 }
else if (parentType == Type::Variable || parentType == Type::LegacyVariable) {
368 message = _(
"You must enter a variable name.");
369 }
else if (parentType == Type::Object) {
370 message = _(
"You must enter a valid object name.");
373 message = _(
"You must enter a valid expression.");
375 RaiseTypeError(message, node.location);
376 childType = Type::Empty;
380 enum Type {Unknown = 0, Number, String, NumberOrString, Variable, LegacyVariable, Object, Empty};
382 bool ValidateObjectVariableOrVariableOrProperty(
const gd::IdentifierNode& identifier);
383 bool ValidateObjectVariableOrVariableOrProperty(
389 void CheckVariableExistence(
const ExpressionParserLocation &location,
const gd::String& name) {
390 if (!currentParameterExtraInfo || *currentParameterExtraInfo !=
"AllowUndeclaredVariable") {
391 projectScopedContainers.MatchIdentifierWithName<
void>(
395 RaiseVariableNameCollisionError(
396 _(
"This variable has the same name as an object. Consider "
397 "renaming one or the other."),
406 RaiseVariableNameCollisionError(
407 _(
"This variable has the same name as a property. Consider "
408 "renaming one or the other."),
414 RaiseVariableNameCollisionError(
415 _(
"This variable has the same name as a parameter. Consider "
416 "renaming one or the other."),
421 RaiseUndeclaredVariableError(
422 _(
"No variable with this name found."), location,
428 void ReportAnyError(
const ExpressionNode& node,
bool isFatal =
true) {
429 if (node.diagnostic) {
433 allErrors.push_back(node.diagnostic.get());
435 fatalErrors.push_back(node.diagnostic.get());
440 void RaiseError(gd::ExpressionParserError::ErrorType type,
442 const ExpressionParserLocation &location,
bool isFatal =
true,
445 auto diagnostic = gd::make_unique<ExpressionParserError>(
446 type, message, location, actualValue, objectName);
447 allErrors.push_back(diagnostic.get());
449 fatalErrors.push_back(diagnostic.get());
454 supplementalErrors.push_back(std::move(diagnostic));
457 void RaiseUnknownIdentifierError(
const gd::String &message,
458 const ExpressionParserLocation &location) {
459 RaiseError(gd::ExpressionParserError::ErrorType::UnknownIdentifier, message,
463 void RaiseUndeclaredVariableError(
const gd::String &message,
464 const ExpressionParserLocation &location,
467 RaiseError(gd::ExpressionParserError::ErrorType::UndeclaredVariable,
468 message, location,
true, variableName, objectName);
471 void RaiseVariableNameCollisionError(
const gd::String &message,
472 const ExpressionParserLocation &location,
475 RaiseError(gd::ExpressionParserError::ErrorType::VariableNameCollision,
476 message, location,
false, variableName, objectName);
479 void RaiseTypeError(
const gd::String &message,
480 const ExpressionParserLocation &location,
481 bool isFatal =
true) {
482 RaiseError(gd::ExpressionParserError::ErrorType::MismatchedType, message,
486 void RaiseOperatorError(
const gd::String &message,
487 const ExpressionParserLocation &location) {
488 RaiseError(gd::ExpressionParserError::ErrorType::InvalidOperator, message,
493 if (variableType == gd::Variable::Number) {
494 childType = Type::Number;
495 }
else if (variableType == gd::Variable::String) {
496 childType = Type::String;
502 static bool ShouldTypeBeRefined(
Type type) {
503 return (type == Type::Unknown || type == Type::NumberOrString);
511 static const gd::String numberOrStringTypeString;
513 static const gd::String legacyVariableTypeString;
518 std::vector<ExpressionParserError*> fatalErrors;
519 std::vector<ExpressionParserError*> allErrors;
520 std::vector<std::unique_ptr<ExpressionParserError>> supplementalErrors;
523 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