summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/gdscript_parser.h
diff options
context:
space:
mode:
authorGeorge Marques <george@gmarqu.es>2020-06-10 18:18:10 -0300
committerGeorge Marques <george@gmarqu.es>2020-07-20 11:38:39 -0300
commit17cd6347ba96d4e64cba475854e842e0a490a465 (patch)
treea2c9120433ae80fa09425089b8bdd242e1e54846 /modules/gdscript/gdscript_parser.h
parent7adb0d77cc5dbe0beaa05c9aac0f5c16f2b79775 (diff)
downloadredot-engine-17cd6347ba96d4e64cba475854e842e0a490a465.tar.gz
Add better local variable detection in GDScript parser
Also store Variant operator to avoid needing to do it repeatedly in later compiling stages.
Diffstat (limited to 'modules/gdscript/gdscript_parser.h')
-rw-r--r--modules/gdscript/gdscript_parser.h144
1 files changed, 128 insertions, 16 deletions
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 0d775915cf..ec5e78bd4f 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -99,7 +99,9 @@ public:
NATIVE,
SCRIPT,
CLASS, // GDScript.
+ VARIANT, // Can be any type.
UNRESOLVED,
+ // TODO: Enum, Signal, Callable
};
Kind kind = UNRESOLVED;
@@ -113,14 +115,18 @@ public:
bool is_constant = false;
bool is_meta_type = false;
- bool infer_type = false;
+ bool is_coroutine = false; // For function calls.
Variant::Type builtin_type = Variant::NIL;
StringName native_type;
Ref<Script> script_type;
- ClassNode *gdscript_type = nullptr;
+ ClassNode *class_type = nullptr;
- _FORCE_INLINE_ bool is_set() const { return type_source != UNDETECTED; }
+ MethodInfo method_info; // For callable/signals.
+
+ _FORCE_INLINE_ bool is_set() const { return kind != UNRESOLVED; }
+ _FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; }
+ _FORCE_INLINE_ bool is_variant() const { return kind == VARIANT; }
String to_string() const;
bool operator==(const DataType &p_other) const {
@@ -137,6 +143,8 @@ public:
}
switch (kind) {
+ case VARIANT:
+ return true; // All variants are the same.
case BUILTIN:
return builtin_type == p_other.builtin_type;
case NATIVE:
@@ -144,13 +152,17 @@ public:
case SCRIPT:
return script_type == p_other.script_type;
case CLASS:
- return gdscript_type == p_other.gdscript_type;
+ return class_type == p_other.class_type;
case UNRESOLVED:
break;
}
return false;
}
+
+ bool operator!=(const DataType &p_other) const {
+ return !(this->operator==(p_other));
+ }
};
struct ParserError {
@@ -215,8 +227,10 @@ public:
Node *next = nullptr;
List<AnnotationNode *> annotations;
- virtual DataType get_datatype() const { return DataType(); }
- virtual void set_datatype(const DataType &p_datatype) {}
+ DataType datatype;
+
+ virtual DataType get_datatype() const { return datatype; }
+ virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; }
virtual bool is_expression() const { return false; }
@@ -225,6 +239,10 @@ public:
struct ExpressionNode : public Node {
// Base type for all expression kinds.
+ bool reduced = false;
+ bool is_constant = false;
+ Variant reduced_value;
+
virtual bool is_expression() const { return true; }
virtual ~ExpressionNode() {}
@@ -281,6 +299,7 @@ public:
};
Operation operation = OP_NONE;
+ Variant::Operator variant_op = Variant::OP_MAX;
ExpressionNode *assignee = nullptr;
ExpressionNode *assigned_value = nullptr;
@@ -322,6 +341,7 @@ public:
};
OpType operation;
+ Variant::Operator variant_op = Variant::OP_MAX;
ExpressionNode *left_operand = nullptr;
ExpressionNode *right_operand = nullptr;
@@ -345,6 +365,7 @@ public:
struct CallNode : public ExpressionNode {
ExpressionNode *callee = nullptr;
Vector<ExpressionNode *> arguments;
+ StringName function_name; // TODO: Set this.
bool is_super = false;
CallNode() {
@@ -422,6 +443,34 @@ public:
return "";
}
+ DataType get_datatype() const {
+ switch (type) {
+ case CLASS:
+ return m_class->get_datatype();
+ case CONSTANT:
+ return constant->get_datatype();
+ case FUNCTION:
+ return function->get_datatype();
+ case VARIABLE:
+ return variable->get_datatype();
+ case ENUM_VALUE: {
+ // Always integer.
+ DataType type;
+ type.type_source = DataType::ANNOTATED_EXPLICIT;
+ type.kind = DataType::BUILTIN;
+ type.builtin_type = Variant::INT;
+ return type;
+ }
+ case ENUM:
+ case SIGNAL:
+ // TODO: Use special datatype kinds for these.
+ return DataType();
+ case UNDEFINED:
+ return DataType();
+ }
+ ERR_FAIL_V_MSG(DataType(), "Reaching unhandled type.");
+ }
+
Member() {}
Member(ClassNode *p_class) {
@@ -464,10 +513,17 @@ public:
String extends_path;
Vector<StringName> extends; // List for indexing: extends A.B.C
DataType base_type;
+ String fqcn; // Fully-qualified class name. Identifies uniquely any class in the project.
+
+ bool resolved_interface = false;
+ bool resolved_body = false;
Member get_member(const StringName &p_name) const {
return members[members_indices[p_name]];
}
+ bool has_member(const StringName &p_name) const {
+ return members_indices.has(p_name);
+ }
template <class T>
void add_member(T *p_member_node) {
members_indices[p_member_node->identifier->name] = members.size();
@@ -477,12 +533,6 @@ public:
members_indices[p_enum_value.identifier->name] = members.size();
members.push_back(Member(p_enum_value));
}
- virtual DataType get_datatype() const {
- return base_type;
- }
- virtual void set_datatype(const DataType &p_datatype) {
- base_type = p_datatype;
- }
ClassNode() {
type = CLASS;
@@ -543,6 +593,9 @@ public:
bool is_static = false;
MultiplayerAPI::RPCMode rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
+ bool resolved_signature = false;
+ bool resolved_body = false;
+
FunctionNode() {
type = FUNCTION;
}
@@ -560,6 +613,24 @@ public:
struct IdentifierNode : public ExpressionNode {
StringName name;
+ enum Source {
+ UNDEFINED_SOURCE,
+ FUNCTION_PARAMETER,
+ LOCAL_CONSTANT,
+ LOCAL_VARIABLE,
+ LOCAL_ITERATOR, // `for` loop iterator.
+ LOCAL_BIND, // Pattern bind.
+ // TODO: Add higher sources to help compiling?
+ };
+ Source source = UNDEFINED_SOURCE;
+
+ union {
+ ParameterNode *parameter_source = nullptr;
+ ConstantNode *constant_source;
+ VariableNode *variable_source;
+ IdentifierNode *bind_source;
+ };
+
IdentifierNode() {
type = IDENTIFIER;
}
@@ -644,6 +715,11 @@ public:
};
Vector<Pair> dictionary;
+ HashMap<StringName, IdentifierNode *> binds;
+
+ bool has_bind(const StringName &p_name);
+ IdentifierNode *get_bind(const StringName &p_name);
+
PatternNode() {
type = PATTERN;
}
@@ -706,27 +782,57 @@ public:
UNDEFINED,
CONSTANT,
VARIABLE,
+ PARAMETER,
+ FOR_VARIABLE,
+ PATTERN_BIND,
};
Type type = UNDEFINED;
union {
ConstantNode *constant = nullptr;
VariableNode *variable;
+ ParameterNode *parameter;
+ IdentifierNode *bind;
};
+ StringName name;
+
+ int start_line = 0, end_line = 0;
+ int start_column = 0, end_column = 0;
+ int leftmost_column = 0, rightmost_column = 0;
+
+ DataType get_datatype() const;
+ String get_name() const;
Local() {}
Local(ConstantNode *p_constant) {
type = CONSTANT;
constant = p_constant;
+ name = p_constant->identifier->name;
}
Local(VariableNode *p_variable) {
type = VARIABLE;
variable = p_variable;
+ name = p_variable->identifier->name;
+ }
+ Local(ParameterNode *p_parameter) {
+ type = PARAMETER;
+ parameter = p_parameter;
+ name = p_parameter->identifier->name;
+ }
+ Local(IdentifierNode *p_identifier) {
+ type = FOR_VARIABLE;
+ bind = p_identifier;
+ name = p_identifier->name;
}
};
Local empty;
Vector<Local> locals;
HashMap<StringName, int> locals_indices;
+ FunctionNode *parent_function = nullptr;
+ ForNode *parent_for = nullptr;
+ IfNode *parent_if = nullptr;
+ PatternNode *parent_pattern = nullptr;
+
bool has_local(const StringName &p_name) const;
const Local &get_local(const StringName &p_name) const;
template <class T>
@@ -734,6 +840,10 @@ public:
locals_indices[p_local->identifier->name] = locals.size();
locals.push_back(Local(p_local));
}
+ void add_local(const Local &p_local) {
+ locals_indices[p_local.name] = locals.size();
+ locals.push_back(p_local);
+ }
SuiteNode() {
type = SUITE;
@@ -752,8 +862,7 @@ public:
};
struct TypeNode : public Node {
- IdentifierNode *type_base = nullptr;
- SubscriptNode *type_specifier = nullptr;
+ Vector<IdentifierNode *> type_chain;
TypeNode() {
type = TYPE;
@@ -769,6 +878,7 @@ public:
};
OpType operation;
+ Variant::Operator variant_op = Variant::OP_MAX;
ExpressionNode *operand = nullptr;
UnaryOpNode() {
@@ -861,6 +971,8 @@ private:
HashMap<StringName, AnnotationInfo> valid_annotations;
List<AnnotationNode *> annotation_stack;
+ Set<int> unsafe_lines;
+
typedef ExpressionNode *(GDScriptParser::*ParseFunction)(ExpressionNode *p_previous_operand, bool p_can_assign);
// Higher value means higher precedence (i.e. is evaluated first).
enum Precedence {
@@ -924,7 +1036,7 @@ private:
EnumNode *parse_enum();
ParameterNode *parse_parameter();
FunctionNode *parse_function();
- SuiteNode *parse_suite(const String &p_context);
+ SuiteNode *parse_suite(const String &p_context, SuiteNode *p_suite = nullptr);
// Annotations
AnnotationNode *parse_annotation(uint32_t p_valid_targets);
bool register_annotation(const MethodInfo &p_info, uint32_t p_target_kinds, AnnotationAction p_apply, int p_optional_arguments = 0, bool p_is_vararg = false);
@@ -953,7 +1065,7 @@ private:
IfNode *parse_if(const String &p_token = "if");
MatchNode *parse_match();
MatchBranchNode *parse_match_branch();
- PatternNode *parse_match_pattern();
+ PatternNode *parse_match_pattern(PatternNode *p_root_pattern = nullptr);
WhileNode *parse_while();
// Expressions.
ExpressionNode *parse_expression(bool p_can_assign, bool p_stop_on_assign = false);