summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/gdscript.cpp2
-rw-r--r--modules/gdscript/gdscript_compiler.cpp4
-rw-r--r--modules/gdscript/gdscript_parser.cpp89
-rw-r--r--modules/gdscript/gdscript_parser.h114
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp11
-rw-r--r--modules/gdscript/gdscript_tokenizer.h3
6 files changed, 147 insertions, 76 deletions
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index b3ebd4fe4b..f221aac5fe 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/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",
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 70f3d704ae..69a0575efe 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/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
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index d62112d3f1..37781cb934 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/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)
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index b88a59537c..a71bd96ded 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/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:
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 1d30871e3f..940bdcbc8d 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/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);
}
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index c1f611fe73..5bd303224c 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/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,