Bladeren bron

Add typing syntax

George Marques 7 jaren geleden
bovenliggende
commit
8aab9a06d4

+ 2 - 0
modules/gdscript/gdscript.cpp

@@ -1735,7 +1735,9 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
 		"NAN",
 		"self",
 		"true",
+		"void",
 		// functions
+		"as",
 		"assert",
 		"breakpoint",
 		"class",

+ 4 - 0
modules/gdscript/gdscript_compiler.cpp

@@ -430,6 +430,10 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
 			return dst_addr;
 
 		} break;
+		case GDScriptParser::Node::TYPE_CAST: {
+			const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression);
+			return _parse_expression(codegen, cn->source_node, p_stack_level);
+		} break;
 		case GDScriptParser::Node::TYPE_OPERATOR: {
 			//hell breaks loose
 

+ 87 - 2
modules/gdscript/gdscript_parser.cpp

@@ -1087,6 +1087,27 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
 				break;
 		}
 
+		/*****************/
+		/* Parse Casting */
+		/*****************/
+
+		bool has_casting = expr->type == Node::TYPE_CAST;
+		if (tokenizer->get_token() == GDScriptTokenizer::TK_PR_AS) {
+			if (has_casting) {
+				_set_error("Unexpected 'as'.");
+				return NULL;
+			}
+			CastNode *cn = alloc_node<CastNode>();
+			DataType casttype;
+			if (!_parse_type(casttype)) {
+				_set_error("Expected type after 'as'.");
+				return NULL;
+			}
+			has_casting = true;
+			cn->source_node = expr;
+			expr = cn;
+		}
+
 		/******************/
 		/* Parse Operator */
 		/******************/
@@ -1110,7 +1131,7 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
 
 //assign, if allowed is only allowed on the first operator
 #define _VALIDATE_ASSIGN                  \
-	if (!p_allow_assign) {                \
+	if (!p_allow_assign || has_casting) { \
 		_set_error("Unexpected assign."); \
 		return NULL;                      \
 	}                                     \
@@ -2488,6 +2509,14 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
 
 				Node *assigned = NULL;
 
+				if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) {
+					DataType vartype;
+					if (!_parse_type(vartype)) {
+						_set_error("Expected type for variable.");
+						return;
+					}
+				}
+
 				if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) {
 
 					tokenizer->advance();
@@ -3150,7 +3179,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
 				//class inside class :D
 
 				StringName name;
-				StringName extends;
 
 				if (tokenizer->get_token(1) != GDScriptTokenizer::TK_IDENTIFIER) {
 
@@ -3279,6 +3307,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
 
 						tokenizer->advance();
 
+						if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) {
+							DataType argtype;
+							if (!_parse_type(argtype)) {
+								_set_error("Expected type for argument.");
+								return;
+							}
+						}
+
 						if (defaulting && tokenizer->get_token() != GDScriptTokenizer::TK_OP_ASSIGN) {
 
 							_set_error("Default parameter expected.");
@@ -3386,6 +3422,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
 					}
 				}
 
+				if (tokenizer->get_token() == GDScriptTokenizer::TK_FORWARD_ARROW) {
+					DataType rettype;
+					if (!_parse_type(rettype, true)) {
+						_set_error("Expected return type for function.");
+						return;
+					}
+				}
+
 				if (!_enter_indent_block(block)) {
 
 					_set_error("Indented block expected.");
@@ -4113,6 +4157,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
 
 				rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
 
+				if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) {
+					DataType vartype;
+					if (!_parse_type(vartype)) {
+						_set_error("Expected type for class variable.");
+						return;
+					}
+				}
+
 				if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) {
 
 #ifdef DEBUG_ENABLED
@@ -4272,6 +4324,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
 				constant.identifier = tokenizer->get_token_literal();
 				tokenizer->advance();
 
+				if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) {
+					DataType consttype;
+					if (!_parse_type(consttype)) {
+						_set_error("Expected type for class constant.");
+						return;
+					}
+				}
+
 				if (tokenizer->get_token() != GDScriptTokenizer::TK_OP_ASSIGN) {
 					_set_error("Constant expects assignment.");
 					return;
@@ -4423,6 +4483,31 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
 	}
 }
 
+bool GDScriptParser::_parse_type(DataType &r_type, bool p_can_be_void) {
+	tokenizer->advance();
+
+	r_type.has_type = true;
+
+	switch (tokenizer->get_token()) {
+		case GDScriptTokenizer::TK_IDENTIFIER: {
+			StringName id = tokenizer->get_token_identifier();
+		} break;
+		case GDScriptTokenizer::TK_BUILT_IN_TYPE: {
+		} break;
+		case GDScriptTokenizer::TK_PR_VOID: {
+			if (!p_can_be_void) {
+				return false;
+			}
+		} break;
+		default: {
+			return false;
+		}
+	}
+
+	tokenizer->advance();
+	return true;
+}
+
 void GDScriptParser::_set_error(const String &p_error, int p_line, int p_column) {
 
 	if (error_set)

+ 44 - 70
modules/gdscript/gdscript_parser.h

@@ -39,6 +39,39 @@
 
 class GDScriptParser {
 public:
+	struct ClassNode;
+
+	struct DataType {
+		enum {
+			BUILTIN,
+			NATIVE,
+			SCRIPT,
+			GDSCRIPT,
+			CLASS
+		} kind;
+
+		bool has_type;
+
+		Variant::Type builtin_type;
+		StringName native_type;
+		Ref<Script> script_type;
+		ClassNode *class_type;
+
+		DataType *meta_type;
+
+		DataType() :
+				has_type(false),
+				meta_type(NULL),
+				builtin_type(Variant::NIL),
+				class_type(NULL) {}
+
+		~DataType() {
+			if (meta_type) {
+				memdelete(meta_type);
+			}
+		}
+	};
+
 	struct Node {
 
 		enum Type {
@@ -55,6 +88,7 @@ public:
 			TYPE_OPERATOR,
 			TYPE_CONTROL_FLOW,
 			TYPE_LOCAL_VAR,
+			TYPE_CAST,
 			TYPE_ASSERT,
 			TYPE_BREAKPOINT,
 			TYPE_NEWLINE,
@@ -65,6 +99,9 @@ public:
 		int column;
 		Type type;
 
+		virtual DataType get_datatype() const { return DataType(); }
+		virtual void set_datatype(DataType p_datatype) {}
+
 		virtual ~Node() {}
 	};
 
@@ -340,6 +377,11 @@ public:
 		}
 	};
 
+	struct CastNode : public Node {
+		Node *source_node;
+		CastNode() { type = TYPE_CAST; }
+	};
+
 	struct AssertNode : public Node {
 		Node *condition;
 		AssertNode() { type = TYPE_ASSERT; }
@@ -362,76 +404,6 @@ public:
 		};
 	};
 
-	/*
-	struct OperatorNode : public Node {
-
-		DataType return_cache;
-		Operator op;
-		Vector<Node*> arguments;
-		virtual DataType get_datatype() const { return return_cache; }
-
-		OperatorNode() { type=TYPE_OPERATOR; return_cache=TYPE_VOID; }
-	};
-
-	struct VariableNode : public Node {
-
-		DataType datatype_cache;
-		StringName name;
-		virtual DataType get_datatype() const { return datatype_cache; }
-
-		VariableNode() { type=TYPE_VARIABLE; datatype_cache=TYPE_VOID; }
-	};
-
-	struct ConstantNode : public Node {
-
-		DataType datatype;
-		Variant value;
-		virtual DataType get_datatype() const { return datatype; }
-
-		ConstantNode() { type=TYPE_CONSTANT; }
-	};
-
-	struct BlockNode : public Node {
-
-		Map<StringName,DataType> variables;
-		List<Node*> statements;
-		BlockNode() { type=TYPE_BLOCK; }
-	};
-
-	struct ControlFlowNode : public Node {
-
-		FlowOperation flow_op;
-		Vector<Node*> statements;
-		ControlFlowNode() { type=TYPE_CONTROL_FLOW; flow_op=FLOW_OP_IF;}
-	};
-
-	struct MemberNode : public Node {
-
-		DataType datatype;
-		StringName name;
-		Node* owner;
-		virtual DataType get_datatype() const { return datatype; }
-		MemberNode() { type=TYPE_MEMBER; }
-	};
-
-
-	struct ProgramNode : public Node {
-
-		struct Function {
-			StringName name;
-			FunctionNode*function;
-		};
-
-		Map<StringName,DataType> builtin_variables;
-		Map<StringName,DataType> preexisting_variables;
-
-		Vector<Function> functions;
-		BlockNode *body;
-
-		ProgramNode() { type=TYPE_PROGRAM; }
-	};
-*/
-
 	enum CompletionType {
 		COMPLETION_NONE,
 		COMPLETION_BUILT_IN_TYPE_CONSTANT,
@@ -515,6 +487,8 @@ private:
 	void _parse_class(ClassNode *p_class);
 	bool _end_statement();
 
+	bool _parse_type(DataType &r_type, bool p_can_be_void = false);
+
 	Error _parse(const String &p_base_path);
 
 public:

+ 7 - 4
modules/gdscript/gdscript_tokenizer.cpp

@@ -101,6 +101,8 @@ const char *GDScriptTokenizer::token_names[TK_MAX] = {
 	"setget",
 	"const",
 	"var",
+	"as",
+	"void",
 	"enum",
 	"preload",
 	"assert",
@@ -125,6 +127,7 @@ const char *GDScriptTokenizer::token_names[TK_MAX] = {
 	"'.'",
 	"'?'",
 	"':'",
+	"'->'",
 	"'$'",
 	"'\\n'",
 	"PI",
@@ -197,6 +200,8 @@ static const _kws _keyword_list[] = {
 	{ GDScriptTokenizer::TK_PR_EXPORT, "export" },
 	{ GDScriptTokenizer::TK_PR_SETGET, "setget" },
 	{ GDScriptTokenizer::TK_PR_VAR, "var" },
+	{ GDScriptTokenizer::TK_PR_AS, "as" },
+	{ GDScriptTokenizer::TK_PR_VOID, "void" },
 	{ GDScriptTokenizer::TK_PR_PRELOAD, "preload" },
 	{ GDScriptTokenizer::TK_PR_ASSERT, "assert" },
 	{ GDScriptTokenizer::TK_PR_YIELD, "yield" },
@@ -707,11 +712,9 @@ void GDScriptTokenizerText::_advance() {
 				if (GETCHAR(1) == '=') {
 					_make_token(TK_OP_ASSIGN_SUB);
 					INCPOS(1);
-					/*
-				}  else if (GETCHAR(1)=='-') {
-					_make_token(TK_OP_MINUS_MINUS);
+				} else if (GETCHAR(1) == '>') {
+					_make_token(TK_FORWARD_ARROW);
 					INCPOS(1);
-				*/
 				} else {
 					_make_token(TK_OP_SUB);
 				}

+ 3 - 0
modules/gdscript/gdscript_tokenizer.h

@@ -106,6 +106,8 @@ public:
 		TK_PR_SETGET,
 		TK_PR_CONST,
 		TK_PR_VAR,
+		TK_PR_AS,
+		TK_PR_VOID,
 		TK_PR_ENUM,
 		TK_PR_PRELOAD,
 		TK_PR_ASSERT,
@@ -131,6 +133,7 @@ public:
 		TK_QUESTION_MARK,
 		TK_COLON,
 		TK_DOLLAR,
+		TK_FORWARD_ARROW,
 		TK_NEWLINE,
 		TK_CONST_PI,
 		TK_CONST_TAU,