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