GDevelop Core
Core library for developing platforms and tools compatible with GDevelop.
ExpressionLeftSideTypeFinder.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_EXPRESSIONLEFTSIDETYPEFINDER_H
7 #define GDCORE_EXPRESSIONLEFTSIDETYPEFINDER_H
8 
9 #include <memory>
10 #include <vector>
11 #include "GDCore/Events/Parsers/ExpressionParser2Node.h"
12 #include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
13 #include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
14 #include "GDCore/Extensions/Metadata/MetadataProvider.h"
15 #include "GDCore/Extensions/Metadata/ObjectMetadata.h"
16 #include "GDCore/Extensions/Metadata/ParameterMetadata.h"
17 #include "GDCore/Project/ProjectScopedContainers.h"
19 
20 namespace gd {
21 class Expression;
22 class ObjectsContainer;
23 class Platform;
24 class ParameterMetadata;
25 class ExpressionMetadata;
26 } // namespace gd
27 
28 namespace gd {
29 
36  public:
37 
42  static const gd::String GetType(const gd::Platform &platform,
43  const gd::ProjectScopedContainers &projectScopedContainers,
44  gd::ExpressionNode& node) {
46  platform, projectScopedContainers);
47  node.Visit(typeFinder);
48  return typeFinder.GetType();
49  }
50 
51  virtual ~ExpressionLeftSideTypeFinder(){};
52 
53  protected:
54  ExpressionLeftSideTypeFinder(const gd::Platform &platform_,
55  const gd::ProjectScopedContainers &projectScopedContainers_)
56  : platform(platform_),
57  projectScopedContainers(projectScopedContainers_),
58  type("unknown") {};
59 
60  const gd::String &GetType() {
61  return type;
62  };
63 
64  void OnVisitSubExpressionNode(SubExpressionNode& node) override {
65  node.expression->Visit(*this);
66  }
67  void OnVisitOperatorNode(OperatorNode& node) override {
68  node.leftHandSide->Visit(*this);
69 
70  // The type is decided by the first operand, unless it can (`number|string`)
71  // or should (`unknown`) be refined, in which case we go for the right
72  // operand (which got visited knowing the type of the first operand, so it's
73  // equal or strictly more precise than the left operand).
74  if (type == "unknown" || type == "number|string") {
75  node.rightHandSide->Visit(*this);
76  }
77  }
78  void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {
79  node.factor->Visit(*this);
80  }
81  void OnVisitVariableBracketAccessorNode(
82  VariableBracketAccessorNode& node) override {
83  node.expression->Visit(*this);
84  }
85  void OnVisitNumberNode(NumberNode& node) override {
86  type = "number";
87  }
88  void OnVisitTextNode(TextNode& node) override {
89  type = "string";
90  }
91  void OnVisitFunctionCallNode(FunctionCallNode& node) override {
92  const gd::ExpressionMetadata &metadata = MetadataProvider::GetFunctionCallMetadata(
93  platform, projectScopedContainers.GetObjectsContainersList(), node);
94  if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
95  type = "unknown";
96  }
97  else {
98  type = metadata.GetReturnType();
99  }
100  }
101  void OnVisitVariableNode(VariableNode& node) override {
102  type = "unknown";
103 
104  projectScopedContainers.MatchIdentifierWithName<void>(node.name,
105  [&]() {
106  // This represents an object.
107  // We could store it to explore the type of the variable, but in practice this
108  // is only called for structures/arrays with 2 levels, and we don't support structure
109  // type identification for now.
110  },
111  [&]() {
112  // This is a variable.
113  // We could store it to explore the type of the variable, but in practice this
114  // is only called for structures/arrays with 2 levels, and we don't support structure
115  // type identification for now.
116  }, [&]() {
117  // This is a property with more than one child - this is unsupported.
118  }, [&]() {
119  // This is a parameter with more than one child - this is unsupported.
120  }, [&]() {
121  // This is something else.
122  type = "unknown";
123  });
124  }
125  void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
126  type = "unknown";
127  }
128  void OnVisitIdentifierNode(IdentifierNode& node) override {
129  type = "unknown";
130  projectScopedContainers.MatchIdentifierWithName<void>(node.identifierName,
131  [&]() {
132  // It's an object variable.
133  if (projectScopedContainers.GetObjectsContainersList()
134  .HasObjectOrGroupWithVariableNamed(
135  node.identifierName, node.childIdentifierName)
136  == ObjectsContainersList::VariableExistence::DoesNotExist) {
137  type = "unknown";
138  return;
139  }
140 
141  auto variableType =
142  projectScopedContainers.GetObjectsContainersList()
143  .GetTypeOfObjectOrGroupVariable(node.identifierName,
144  node.childIdentifierName);
145  ReadTypeFromVariable(variableType);
146  },
147  [&]() {
148  // It's a variable.
149  const auto& variable =
150  projectScopedContainers.GetVariablesContainersList().Get(
151  node.identifierName);
152 
153  if (node.childIdentifierName.empty()) {
154  ReadTypeFromVariable(variable.GetType());
155  } else {
156  if (!variable.HasChild(node.childIdentifierName)) {
157  type = "unknown";
158  return;
159  }
160 
161  ReadTypeFromVariable(
162  variable.GetChild(node.childIdentifierName).GetType());
163  }
164  }, [&]() {
165  // This is a property.
166  const gd::NamedPropertyDescriptor& property = projectScopedContainers
167  .GetPropertiesContainersList().Get(node.identifierName).second;
168 
169  if (property.GetType() == "Number") {
170  type = "number";
171  } else if (property.GetType() == "Boolean") {
172  // Nothing - we don't know the precise type (this could be used a string or as a number)
173  } else {
174  // Assume type is String or equivalent.
175  type = "string";
176  }
177  }, [&]() {
178  // It's a parameter.
179 
180  const auto& parametersVectorsList = projectScopedContainers.GetParametersVectorsList();
181  const auto& parameter = gd::ParameterMetadataTools::Get(parametersVectorsList, node.identifierName);
182  const auto& valueTypeMetadata = parameter.GetValueTypeMetadata();
183  if (valueTypeMetadata.IsNumber()) {
184  type = "number";
185  } else if (valueTypeMetadata.IsString()) {
186  type = "string";
187  } else if (valueTypeMetadata.IsBoolean()) {
188  // Nothing - we don't know the precise type (this could be used as a string or as a number).
189  } else {
190  type = "unknown";
191  }
192  }, [&]() {
193  // This is something else.
194  type = "unknown";
195  });
196  }
197  void OnVisitEmptyNode(EmptyNode& node) override {
198  type = "unknown";
199  }
200  void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {
201  type = "unknown";
202  }
203 
204  private:
205  void ReadTypeFromVariable(gd::Variable::Type variableType) {
206  if (variableType == gd::Variable::Number) {
207  type = "number";
208  } else if (variableType == gd::Variable::String) {
209  type = "string";
210  }
211  }
212 
213  gd::String type;
214 
215  const gd::Platform &platform;
216  const gd::ProjectScopedContainers &projectScopedContainers;
217  const gd::String rootType;
218 };
219 
220 } // namespace gd
221 
222 #endif // GDCORE_EXPRESSIONLEFTSIDETYPEFINDER_H
Find the type of the node at the left side of operations.
Definition: ExpressionLeftSideTypeFinder.h:35
static const gd::String GetType(const gd::Platform &platform, const gd::ProjectScopedContainers &projectScopedContainers, gd::ExpressionNode &node)
Helper function to find the type of the node at the left side of operations.
Definition: ExpressionLeftSideTypeFinder.h:42
Describe user-friendly information about an expression, its parameters and the function name as well ...
Definition: ExpressionMetadata.h:47
The interface for any worker class ("visitor" pattern) that want to interact with the nodes of a pars...
Definition: ExpressionParser2NodeWorker.h:36
Used to describe a property shown in a property grid.
Definition: NamedPropertyDescriptor.h:21
Base class for implementing a platform.
Definition: Platform.h:42
Holds references to variables, objects, properties and other containers.
Definition: ProjectScopedContainers.h:30
String represents an UTF8 encoded string.
Definition: String.h:31
Definition: CommonTools.h:24
The base node, from which all nodes in the tree of an expression inherits from.
Definition: ExpressionParser2Node.h:93