Add typing syntax
This commit is contained in:
parent
cfcb6e11f2
commit
8aab9a06d4
6 changed files with 147 additions and 76 deletions
|
@ -1735,7 +1735,9 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
|
||||||
"NAN",
|
"NAN",
|
||||||
"self",
|
"self",
|
||||||
"true",
|
"true",
|
||||||
|
"void",
|
||||||
// functions
|
// functions
|
||||||
|
"as",
|
||||||
"assert",
|
"assert",
|
||||||
"breakpoint",
|
"breakpoint",
|
||||||
"class",
|
"class",
|
||||||
|
|
|
@ -430,6 +430,10 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
|
||||||
return dst_addr;
|
return dst_addr;
|
||||||
|
|
||||||
} break;
|
} 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: {
|
case GDScriptParser::Node::TYPE_OPERATOR: {
|
||||||
//hell breaks loose
|
//hell breaks loose
|
||||||
|
|
||||||
|
|
|
@ -1087,6 +1087,27 @@ GDScriptParser::Node *GDScriptParser::_parse_expression(Node *p_parent, bool p_s
|
||||||
break;
|
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 */
|
/* 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
|
//assign, if allowed is only allowed on the first operator
|
||||||
#define _VALIDATE_ASSIGN \
|
#define _VALIDATE_ASSIGN \
|
||||||
if (!p_allow_assign) { \
|
if (!p_allow_assign || has_casting) { \
|
||||||
_set_error("Unexpected assign."); \
|
_set_error("Unexpected assign."); \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
|
@ -2488,6 +2509,14 @@ void GDScriptParser::_parse_block(BlockNode *p_block, bool p_static) {
|
||||||
|
|
||||||
Node *assigned = NULL;
|
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) {
|
if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) {
|
||||||
|
|
||||||
tokenizer->advance();
|
tokenizer->advance();
|
||||||
|
@ -3150,7 +3179,6 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
|
||||||
//class inside class :D
|
//class inside class :D
|
||||||
|
|
||||||
StringName name;
|
StringName name;
|
||||||
StringName extends;
|
|
||||||
|
|
||||||
if (tokenizer->get_token(1) != GDScriptTokenizer::TK_IDENTIFIER) {
|
if (tokenizer->get_token(1) != GDScriptTokenizer::TK_IDENTIFIER) {
|
||||||
|
|
||||||
|
@ -3279,6 +3307,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
|
||||||
|
|
||||||
tokenizer->advance();
|
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) {
|
if (defaulting && tokenizer->get_token() != GDScriptTokenizer::TK_OP_ASSIGN) {
|
||||||
|
|
||||||
_set_error("Default parameter expected.");
|
_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)) {
|
if (!_enter_indent_block(block)) {
|
||||||
|
|
||||||
_set_error("Indented block expected.");
|
_set_error("Indented block expected.");
|
||||||
|
@ -4113,6 +4157,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
|
||||||
|
|
||||||
rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
|
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) {
|
if (tokenizer->get_token() == GDScriptTokenizer::TK_OP_ASSIGN) {
|
||||||
|
|
||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
@ -4272,6 +4324,14 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
|
||||||
constant.identifier = tokenizer->get_token_literal();
|
constant.identifier = tokenizer->get_token_literal();
|
||||||
tokenizer->advance();
|
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) {
|
if (tokenizer->get_token() != GDScriptTokenizer::TK_OP_ASSIGN) {
|
||||||
_set_error("Constant expects assignment.");
|
_set_error("Constant expects assignment.");
|
||||||
return;
|
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) {
|
void GDScriptParser::_set_error(const String &p_error, int p_line, int p_column) {
|
||||||
|
|
||||||
if (error_set)
|
if (error_set)
|
||||||
|
|
|
@ -39,6 +39,39 @@
|
||||||
|
|
||||||
class GDScriptParser {
|
class GDScriptParser {
|
||||||
public:
|
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 {
|
struct Node {
|
||||||
|
|
||||||
enum Type {
|
enum Type {
|
||||||
|
@ -55,6 +88,7 @@ public:
|
||||||
TYPE_OPERATOR,
|
TYPE_OPERATOR,
|
||||||
TYPE_CONTROL_FLOW,
|
TYPE_CONTROL_FLOW,
|
||||||
TYPE_LOCAL_VAR,
|
TYPE_LOCAL_VAR,
|
||||||
|
TYPE_CAST,
|
||||||
TYPE_ASSERT,
|
TYPE_ASSERT,
|
||||||
TYPE_BREAKPOINT,
|
TYPE_BREAKPOINT,
|
||||||
TYPE_NEWLINE,
|
TYPE_NEWLINE,
|
||||||
|
@ -65,6 +99,9 @@ public:
|
||||||
int column;
|
int column;
|
||||||
Type type;
|
Type type;
|
||||||
|
|
||||||
|
virtual DataType get_datatype() const { return DataType(); }
|
||||||
|
virtual void set_datatype(DataType p_datatype) {}
|
||||||
|
|
||||||
virtual ~Node() {}
|
virtual ~Node() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -340,6 +377,11 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CastNode : public Node {
|
||||||
|
Node *source_node;
|
||||||
|
CastNode() { type = TYPE_CAST; }
|
||||||
|
};
|
||||||
|
|
||||||
struct AssertNode : public Node {
|
struct AssertNode : public Node {
|
||||||
Node *condition;
|
Node *condition;
|
||||||
AssertNode() { type = TYPE_ASSERT; }
|
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 {
|
enum CompletionType {
|
||||||
COMPLETION_NONE,
|
COMPLETION_NONE,
|
||||||
COMPLETION_BUILT_IN_TYPE_CONSTANT,
|
COMPLETION_BUILT_IN_TYPE_CONSTANT,
|
||||||
|
@ -515,6 +487,8 @@ private:
|
||||||
void _parse_class(ClassNode *p_class);
|
void _parse_class(ClassNode *p_class);
|
||||||
bool _end_statement();
|
bool _end_statement();
|
||||||
|
|
||||||
|
bool _parse_type(DataType &r_type, bool p_can_be_void = false);
|
||||||
|
|
||||||
Error _parse(const String &p_base_path);
|
Error _parse(const String &p_base_path);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -101,6 +101,8 @@ const char *GDScriptTokenizer::token_names[TK_MAX] = {
|
||||||
"setget",
|
"setget",
|
||||||
"const",
|
"const",
|
||||||
"var",
|
"var",
|
||||||
|
"as",
|
||||||
|
"void",
|
||||||
"enum",
|
"enum",
|
||||||
"preload",
|
"preload",
|
||||||
"assert",
|
"assert",
|
||||||
|
@ -125,6 +127,7 @@ const char *GDScriptTokenizer::token_names[TK_MAX] = {
|
||||||
"'.'",
|
"'.'",
|
||||||
"'?'",
|
"'?'",
|
||||||
"':'",
|
"':'",
|
||||||
|
"'->'",
|
||||||
"'$'",
|
"'$'",
|
||||||
"'\\n'",
|
"'\\n'",
|
||||||
"PI",
|
"PI",
|
||||||
|
@ -197,6 +200,8 @@ static const _kws _keyword_list[] = {
|
||||||
{ GDScriptTokenizer::TK_PR_EXPORT, "export" },
|
{ GDScriptTokenizer::TK_PR_EXPORT, "export" },
|
||||||
{ GDScriptTokenizer::TK_PR_SETGET, "setget" },
|
{ GDScriptTokenizer::TK_PR_SETGET, "setget" },
|
||||||
{ GDScriptTokenizer::TK_PR_VAR, "var" },
|
{ GDScriptTokenizer::TK_PR_VAR, "var" },
|
||||||
|
{ GDScriptTokenizer::TK_PR_AS, "as" },
|
||||||
|
{ GDScriptTokenizer::TK_PR_VOID, "void" },
|
||||||
{ GDScriptTokenizer::TK_PR_PRELOAD, "preload" },
|
{ GDScriptTokenizer::TK_PR_PRELOAD, "preload" },
|
||||||
{ GDScriptTokenizer::TK_PR_ASSERT, "assert" },
|
{ GDScriptTokenizer::TK_PR_ASSERT, "assert" },
|
||||||
{ GDScriptTokenizer::TK_PR_YIELD, "yield" },
|
{ GDScriptTokenizer::TK_PR_YIELD, "yield" },
|
||||||
|
@ -707,11 +712,9 @@ void GDScriptTokenizerText::_advance() {
|
||||||
if (GETCHAR(1) == '=') {
|
if (GETCHAR(1) == '=') {
|
||||||
_make_token(TK_OP_ASSIGN_SUB);
|
_make_token(TK_OP_ASSIGN_SUB);
|
||||||
INCPOS(1);
|
INCPOS(1);
|
||||||
/*
|
} else if (GETCHAR(1) == '>') {
|
||||||
} else if (GETCHAR(1)=='-') {
|
_make_token(TK_FORWARD_ARROW);
|
||||||
_make_token(TK_OP_MINUS_MINUS);
|
|
||||||
INCPOS(1);
|
INCPOS(1);
|
||||||
*/
|
|
||||||
} else {
|
} else {
|
||||||
_make_token(TK_OP_SUB);
|
_make_token(TK_OP_SUB);
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,8 @@ public:
|
||||||
TK_PR_SETGET,
|
TK_PR_SETGET,
|
||||||
TK_PR_CONST,
|
TK_PR_CONST,
|
||||||
TK_PR_VAR,
|
TK_PR_VAR,
|
||||||
|
TK_PR_AS,
|
||||||
|
TK_PR_VOID,
|
||||||
TK_PR_ENUM,
|
TK_PR_ENUM,
|
||||||
TK_PR_PRELOAD,
|
TK_PR_PRELOAD,
|
||||||
TK_PR_ASSERT,
|
TK_PR_ASSERT,
|
||||||
|
@ -131,6 +133,7 @@ public:
|
||||||
TK_QUESTION_MARK,
|
TK_QUESTION_MARK,
|
||||||
TK_COLON,
|
TK_COLON,
|
||||||
TK_DOLLAR,
|
TK_DOLLAR,
|
||||||
|
TK_FORWARD_ARROW,
|
||||||
TK_NEWLINE,
|
TK_NEWLINE,
|
||||||
TK_CONST_PI,
|
TK_CONST_PI,
|
||||||
TK_CONST_TAU,
|
TK_CONST_TAU,
|
||||||
|
|
Loading…
Reference in a new issue