summaryrefslogtreecommitdiff
path: root/modules/gdscript/gd_parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gd_parser.cpp')
-rw-r--r--modules/gdscript/gd_parser.cpp474
1 files changed, 380 insertions, 94 deletions
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp
index 46eade0b7c..aa2878f9e1 100644
--- a/modules/gdscript/gd_parser.cpp
+++ b/modules/gdscript/gd_parser.cpp
@@ -30,19 +30,6 @@
#include "print_string.h"
#include "io/resource_loader.h"
#include "os/file_access.h"
-/* TODO:
-
- *Property reduce constant expressions
- *Implement missing operators in variant?
- *constructor
- */
-
-/*
- todo:
- fix post ++,--
- make sure ++,-- don't work on constant expressions
- seems passing parent node as param is not needed
- */
template<class T>
T* GDParser::alloc_node() {
@@ -116,14 +103,20 @@ bool GDParser::_enter_indent_block(BlockNode* p_block) {
}
}
-bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_static) {
+bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_static,bool p_can_codecomplete) {
if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) {
tokenizer->advance();
} else {
+ int argidx=0;
+
while(true) {
+ if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
+ _make_completable_call(argidx);
+ completion_node=p_parent;
+ }
Node*arg = _parse_expression(p_parent,p_static);
if (!arg)
@@ -144,6 +137,7 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat
}
tokenizer->advance();
+ argidx++;
} else {
// something is broken
_set_error("Expected ',' or ')'");
@@ -158,6 +152,48 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat
}
+void GDParser::_make_completable_call(int p_arg) {
+
+ completion_cursor=StringName();
+ completion_type=COMPLETION_CALL_ARGUMENTS;
+ completion_class=current_class;
+ completion_function=current_function;
+ completion_line=tokenizer->get_token_line();
+ completion_argument=p_arg;
+ completion_block=current_block;
+ tokenizer->advance();
+
+}
+
+
+bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& identifier) {
+
+ identifier=StringName();
+ if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
+ identifier=tokenizer->get_token_identifier();
+ tokenizer->advance();
+ }
+ if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
+
+ completion_cursor=identifier;
+ completion_type=p_type;
+ completion_class=current_class;
+ completion_function=current_function;
+ completion_line=tokenizer->get_token_line();
+ completion_block=current_block;
+ tokenizer->advance();
+
+ if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
+ identifier=identifier.operator String() + tokenizer->get_token_identifier().operator String();
+ tokenizer->advance();
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_allow_assign) {
@@ -199,6 +235,9 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
tokenizer->advance();
expr=subexpr;
+ } else if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
+ tokenizer->advance();
+ continue; //no point in cursor in the middle of expression
} else if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT) {
@@ -225,7 +264,14 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
String path = tokenizer->get_token_constant();
if (!path.is_abs_path() && base_path!="")
path=base_path+"/"+path;
- path = path.replace("///","//");
+ path = path.replace("///","//").simplify_path();
+ if (path==self_path) {
+
+ _set_error("Can't preload itself (use 'get_script()').");
+ return NULL;
+
+ }
+
Ref<Resource> res;
if (!validating) {
@@ -320,12 +366,19 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
Variant::Type bi_type = tokenizer->get_token_type();
tokenizer->advance(2);
- if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
+
+ StringName identifier;
+
+ if (_get_completable_identifier(COMPLETION_BUILT_IN_TYPE_CONSTANT,identifier)) {
+
+ completion_built_in_constant=bi_type;
+ }
+
+ if (identifier==StringName()) {
_set_error("Built-in type constant expected after '.'");
return NULL;
}
- StringName identifier = tokenizer->get_token_identifier();
if (!Variant::has_numeric_constant(bi_type,identifier)) {
_set_error("Static constant '"+identifier.operator String()+"' not present in built-in type "+Variant::get_type_name(bi_type)+".");
@@ -335,7 +388,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
ConstantNode *cn = alloc_node<ConstantNode>();
cn->value=Variant::get_numeric_constant_value(bi_type,identifier);
expr=cn;
- tokenizer->advance();
+
} else if (tokenizer->get_token(1)==GDTokenizer::TK_PARENTHESIS_OPEN && (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_TYPE || tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER || tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_FUNC)) {
//function or constructor
@@ -348,23 +401,35 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
TypeNode *tn = alloc_node<TypeNode>();
tn->vtype=tokenizer->get_token_type();
op->arguments.push_back(tn);
+ tokenizer->advance(2);
} else if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_FUNC) {
BuiltInFunctionNode *bn = alloc_node<BuiltInFunctionNode>();
bn->function=tokenizer->get_token_built_in_func();
op->arguments.push_back(bn);
+ tokenizer->advance(2);
} else {
SelfNode *self = alloc_node<SelfNode>();
op->arguments.push_back(self);
+ StringName identifier;
+ if (_get_completable_identifier(COMPLETION_FUNCTION,identifier)) {
+
+ }
+
IdentifierNode* id = alloc_node<IdentifierNode>();
- id->name=tokenizer->get_token_identifier();
+ id->name=identifier;
op->arguments.push_back(id);
+ tokenizer->advance(1);
}
- tokenizer->advance(2);
- if (!_parse_arguments(op,op->arguments,p_static))
+ if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
+ _make_completable_call(0);
+ completion_node=op;
+
+ }
+ if (!_parse_arguments(op,op->arguments,p_static,true))
return NULL;
expr=op;
@@ -372,10 +437,28 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
} else if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
//identifier (reference)
- IdentifierNode *id = alloc_node<IdentifierNode>();
- id->name=tokenizer->get_token_identifier();
- tokenizer->advance();
- expr=id;
+ const ClassNode* cln = static_cast<const ClassNode*>(get_parse_tree());
+ bool bfn = false;
+ StringName identifier;
+ if (_get_completable_identifier(COMPLETION_IDENTIFIER,identifier)) {
+
+ }
+
+ for( int i=0; i<cln->constant_expressions.size(); ++i ) {
+
+ if( cln->constant_expressions[i].identifier == identifier ) {
+
+ expr = cln->constant_expressions[i].expression;
+ bfn = true;
+ break;
+ }
+ }
+
+ if ( !bfn ) {
+ IdentifierNode *id = alloc_node<IdentifierNode>();
+ id->name = identifier;
+ expr = id;
+ }
} else if (/*tokenizer->get_token()==GDTokenizer::TK_OP_ADD ||*/ tokenizer->get_token()==GDTokenizer::TK_OP_SUB || tokenizer->get_token()==GDTokenizer::TK_OP_NOT || tokenizer->get_token()==GDTokenizer::TK_OP_BIT_INVERT) {
@@ -577,7 +660,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
expr=dict;
- } else if (tokenizer->get_token()==GDTokenizer::TK_PERIOD && tokenizer->get_token(1)==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) {
+ } else if (tokenizer->get_token()==GDTokenizer::TK_PERIOD && (tokenizer->get_token(1)==GDTokenizer::TK_IDENTIFIER || tokenizer->get_token(1)==GDTokenizer::TK_CURSOR) && tokenizer->get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) {
// parent call
tokenizer->advance(); //goto identifier
@@ -588,12 +671,16 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
/*SelfNode *self = alloc_node<SelfNode>();
op->arguments.push_back(self);
forbidden for now */
+ StringName identifier;
+ if (_get_completable_identifier(COMPLETION_PARENT_FUNCTION,identifier)) {
+ //indexing stuff
+ }
- IdentifierNode* id = alloc_node<IdentifierNode>();
- id->name=tokenizer->get_token_identifier();
+ IdentifierNode *id = alloc_node<IdentifierNode>();
+ id->name=identifier;
op->arguments.push_back(id);
- tokenizer->advance(2);
+ tokenizer->advance(1);
if (!_parse_arguments(op,op->arguments,p_static))
return NULL;
@@ -628,7 +715,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
//indexing using "."
- if (tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1)!=GDTokenizer::TK_BUILT_IN_FUNC ) {
+ if (tokenizer->get_token(1)!=GDTokenizer::TK_CURSOR && tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1)!=GDTokenizer::TK_BUILT_IN_FUNC ) {
_set_error("Expected identifier as member");
return NULL;
} else if (tokenizer->get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) {
@@ -636,37 +723,67 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
OperatorNode * op = alloc_node<OperatorNode>();
op->op=OperatorNode::OP_CALL;
+ tokenizer->advance();
+
IdentifierNode * id = alloc_node<IdentifierNode>();
- if (tokenizer->get_token(1)==GDTokenizer::TK_BUILT_IN_FUNC ) {
+ if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_FUNC ) {
//small hack so built in funcs don't obfuscate methods
- id->name=GDFunctions::get_func_name(tokenizer->get_token_built_in_func(1));
+ id->name=GDFunctions::get_func_name(tokenizer->get_token_built_in_func());
+ tokenizer->advance();
+
} else {
- id->name=tokenizer->get_token_identifier(1);
+ StringName identifier;
+ if (_get_completable_identifier(COMPLETION_METHOD,identifier)) {
+ completion_node=op;
+ //indexing stuff
+ }
+
+ id->name=identifier;
}
op->arguments.push_back(expr); // call what
op->arguments.push_back(id); // call func
//get arguments
- tokenizer->advance(3);
- if (!_parse_arguments(op,op->arguments,p_static))
+ tokenizer->advance(1);
+ if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
+ _make_completable_call(0);
+ completion_node=op;
+
+ }
+ if (!_parse_arguments(op,op->arguments,p_static,true))
return NULL;
expr=op;
} else {
//simple indexing!
+
+
OperatorNode * op = alloc_node<OperatorNode>();
op->op=OperatorNode::OP_INDEX_NAMED;
+ tokenizer->advance();
+
+
+ StringName identifier;
+ if (_get_completable_identifier(COMPLETION_INDEX,identifier)) {
+
+ if (identifier==StringName()) {
+ identifier="@temp"; //so it parses allright
+ }
+ completion_node=op;
+
+ //indexing stuff
+ }
IdentifierNode * id = alloc_node<IdentifierNode>();
- id->name=tokenizer->get_token_identifier(1);
+ id->name=identifier;
op->arguments.push_back(expr);
op->arguments.push_back(id);
expr=op;
- tokenizer->advance(2);
+
}
} else if (tokenizer->get_token()==GDTokenizer::TK_BRACKET_OPEN) {
@@ -1142,7 +1259,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) {
cn->value=v;
return cn;
- } else if (op->arguments[0]->type==Node::TYPE_CONSTANT && op->arguments[1]->type==Node::TYPE_IDENTIFIER) {
+ } /*else if (op->arguments[0]->type==Node::TYPE_CONSTANT && op->arguments[1]->type==Node::TYPE_IDENTIFIER) {
ConstantNode *ca = static_cast<ConstantNode*>(op->arguments[0]);
IdentifierNode *ib = static_cast<IdentifierNode*>(op->arguments[1]);
@@ -1157,10 +1274,31 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) {
ConstantNode *cn = alloc_node<ConstantNode>();
cn->value=v;
return cn;
+ }*/
+
+ return op;
+
+ } else if (op->op==OperatorNode::OP_INDEX_NAMED) {
+ if (op->arguments[0]->type==Node::TYPE_CONSTANT && op->arguments[1]->type==Node::TYPE_IDENTIFIER) {
+
+ ConstantNode *ca = static_cast<ConstantNode*>(op->arguments[0]);
+ IdentifierNode *ib = static_cast<IdentifierNode*>(op->arguments[1]);
+
+ bool valid;
+ Variant v = ca->value.get_named(ib->name,&valid);
+ if (!valid) {
+ _set_error("invalid index '"+String(ib->name)+"' in constant expression");
+ return op;
+ }
+
+ ConstantNode *cn = alloc_node<ConstantNode>();
+ cn->value=v;
+ return cn;
}
return op;
+
}
//validate assignment (don't assign to cosntant expression
@@ -1179,7 +1317,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) {
case OperatorNode::OP_ASSIGN_BIT_XOR: {
if (op->arguments[0]->type==Node::TYPE_CONSTANT) {
- _set_error("Can't assign to constant");
+ _set_error("Can't assign to constant",tokenizer->get_token_line()-1);
return op;
}
@@ -1398,6 +1536,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
cf_if->arguments.push_back(condition);
cf_if->body = alloc_node<BlockNode>();
+ cf_if->body->parent_block=p_block;
p_block->sub_blocks.push_back(cf_if->body);
if (!_enter_indent_block(cf_if->body)) {
@@ -1405,7 +1544,10 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
return;
}
+ current_block=cf_if->body;
_parse_block(cf_if->body,p_static);
+ current_block=p_block;
+
if (error_set)
return;
p_block->statements.push_back(cf_if);
@@ -1432,6 +1574,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
tokenizer->advance();
cf_if->body_else=alloc_node<BlockNode>();
+ cf_if->body_else->parent_block=p_block;
p_block->sub_blocks.push_back(cf_if->body_else);
ControlFlowNode *cf_else = alloc_node<ControlFlowNode>();
@@ -1447,6 +1590,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
cf_if->body_else->statements.push_back(cf_else);
cf_if=cf_else;
cf_if->body=alloc_node<BlockNode>();
+ cf_if->body->parent_block=p_block;
p_block->sub_blocks.push_back(cf_if->body);
@@ -1455,7 +1599,9 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
return;
}
+ current_block=cf_else->body;
_parse_block(cf_else->body,p_static);
+ current_block=p_block;
if (error_set)
return;
@@ -1471,13 +1617,16 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
tokenizer->advance();
cf_if->body_else=alloc_node<BlockNode>();
+ cf_if->body_else->parent_block=p_block;
p_block->sub_blocks.push_back(cf_if->body_else);
if (!_enter_indent_block(cf_if->body_else)) {
p_block->end_line=tokenizer->get_token_line();
return;
}
+ current_block=cf_if->body_else;
_parse_block(cf_if->body_else,p_static);
+ current_block=p_block;
if (error_set)
return;
@@ -1504,6 +1653,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
cf_while->arguments.push_back(condition);
cf_while->body = alloc_node<BlockNode>();
+ cf_while->body->parent_block=p_block;
p_block->sub_blocks.push_back(cf_while->body);
if (!_enter_indent_block(cf_while->body)) {
@@ -1511,7 +1661,9 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
return;
}
+ current_block=cf_while->body;
_parse_block(cf_while->body,p_static);
+ current_block=p_block;
if (error_set)
return;
p_block->statements.push_back(cf_while);
@@ -1548,6 +1700,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
cf_for->arguments.push_back(container);
cf_for->body = alloc_node<BlockNode>();
+ cf_for->body->parent_block=p_block;
p_block->sub_blocks.push_back(cf_for->body);
if (!_enter_indent_block(cf_for->body)) {
@@ -1555,7 +1708,10 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
return;
}
+ current_block=cf_for->body;
_parse_block(cf_for->body,p_static);
+ current_block=p_block;
+
if (error_set)
return;
p_block->statements.push_back(cf_for);
@@ -1821,7 +1977,9 @@ void GDParser::_parse_class(ClassNode *p_class) {
ClassNode *newclass = alloc_node<ClassNode>();
newclass->initializer = alloc_node<BlockNode>();
+ newclass->initializer->parent_class=newclass;
newclass->name=name;
+ newclass->owner=p_class;
p_class->subclasses.push_back(newclass);
@@ -1838,7 +1996,9 @@ void GDParser::_parse_class(ClassNode *p_class) {
_set_error("Indented block expected.");
return;
}
+ current_class=newclass;
_parse_class(newclass);
+ current_class=p_class;
} break;
/* this is for functions....
@@ -1867,14 +2027,20 @@ void GDParser::_parse_class(ClassNode *p_class) {
}
- if (tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER) {
+ tokenizer->advance();
+ StringName name;
+
+ if (_get_completable_identifier(COMPLETION_VIRTUAL_FUNC,name)) {
+
+ }
+
+
+ if (name==StringName()) {
_set_error("Expected identifier after 'func' (syntax: 'func <identifier>([arguments]):' ).");
return;
}
- StringName name = tokenizer->get_token_identifier(1);
-
for(int i=0;i<p_class->functions.size();i++) {
if (p_class->functions[i]->name==name) {
_set_error("Function '"+String(name)+"' already exists in this class (at line: "+itos(p_class->functions[i]->line)+").");
@@ -1885,7 +2051,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
_set_error("Function '"+String(name)+"' already exists in this class (at line: "+itos(p_class->static_functions[i]->line)+").");
}
}
- tokenizer->advance(2);
+
if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) {
@@ -1976,6 +2142,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
tokenizer->advance();
BlockNode *block = alloc_node<BlockNode>();
+ block->parent_class=p_class;
if (name=="_init") {
@@ -2051,8 +2218,12 @@ void GDParser::_parse_class(ClassNode *p_class) {
p_class->functions.push_back(function);
- _parse_block(block,_static);
+ current_function=function;
function->body=block;
+ current_block=block;
+ _parse_block(block,_static);
+ current_block=NULL;
+
//arguments
} break;
case GDTokenizer::TK_PR_EXPORT: {
@@ -2357,83 +2528,120 @@ void GDParser::_parse_class(ClassNode *p_class) {
}
member.identifier=tokenizer->get_token_identifier();
+ member.expression=NULL;
member._export.name=member.identifier;
+ member.line=tokenizer->get_token_line();
tokenizer->advance();
- p_class->variables.push_back(member);
+ if (tokenizer->get_token()==GDTokenizer::TK_OP_ASSIGN) {
- if (tokenizer->get_token()!=GDTokenizer::TK_OP_ASSIGN) {
+#ifdef DEBUG_ENABLED
+ int line = tokenizer->get_token_line();
+#endif
+ tokenizer->advance();
- if (autoexport) {
+ Node *subexpr=NULL;
- _set_error("Type-less export needs a constant expression assigned to infer type.");
+ subexpr = _parse_and_reduce_expression(p_class,false);
+ if (!subexpr)
return;
- }
- break;
- }
-#ifdef DEBUG_ENABLED
- int line = tokenizer->get_token_line();
-#endif
- tokenizer->advance();
- Node *subexpr=NULL;
+ member.expression=subexpr;
- subexpr = _parse_and_reduce_expression(p_class,false);
- if (!subexpr)
- return;
+ if (autoexport) {
+ if (subexpr->type==Node::TYPE_ARRAY) {
- if (autoexport) {
- if (subexpr->type==Node::TYPE_ARRAY) {
+ member._export.type=Variant::ARRAY;
- p_class->variables[p_class->variables.size()-1]._export.type=Variant::ARRAY;
+ } else if (subexpr->type==Node::TYPE_DICTIONARY) {
- } else if (subexpr->type==Node::TYPE_DICTIONARY) {
+ member._export.type=Variant::DICTIONARY;
- p_class->variables[p_class->variables.size()-1]._export.type=Variant::DICTIONARY;
+ } else {
- } else {
+ if (subexpr->type!=Node::TYPE_CONSTANT) {
- if (subexpr->type!=Node::TYPE_CONSTANT) {
+ _set_error("Type-less export needs a constant expression assigned to infer type.");
+ return;
+ }
- _set_error("Type-less export needs a constant expression assigned to infer type.");
- return;
+ ConstantNode *cn = static_cast<ConstantNode*>(subexpr);
+ if (cn->value.get_type()==Variant::NIL) {
+
+ _set_error("Can't accept a null constant expression for infering export type.");
+ return;
+ }
+ member._export.type=cn->value.get_type();
}
+ }
+#ifdef TOOLS_ENABLED
+ if (subexpr->type==Node::TYPE_CONSTANT && member._export.type!=Variant::NIL) {
ConstantNode *cn = static_cast<ConstantNode*>(subexpr);
- if (cn->value.get_type()==Variant::NIL) {
-
- _set_error("Can't accept a null constant expression for infering export type.");
- return;
+ if (cn->value.get_type()!=Variant::NIL) {
+ member.default_value=cn->value;
}
- p_class->variables[p_class->variables.size()-1]._export.type=cn->value.get_type();
}
- }
-#ifdef TOOLS_ENABLED
- if (subexpr->type==Node::TYPE_CONSTANT && p_class->variables[p_class->variables.size()-1]._export.type!=Variant::NIL) {
+#endif
+
+ IdentifierNode *id = alloc_node<IdentifierNode>();
+ id->name=member.identifier;
+
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op=OperatorNode::OP_INIT_ASSIGN;
+ op->arguments.push_back(id);
+ op->arguments.push_back(subexpr);
+
+#ifdef DEBUG_ENABLED
+ NewLineNode *nl = alloc_node<NewLineNode>();
+ nl->line=line;
+ p_class->initializer->statements.push_back(nl);
+#endif
+ p_class->initializer->statements.push_back(op);
+
+
+
+ } else {
+
+ if (autoexport) {
- ConstantNode *cn = static_cast<ConstantNode*>(subexpr);
- if (cn->value.get_type()!=Variant::NIL) {
- p_class->variables[p_class->variables.size()-1].default_value=cn->value;
+ _set_error("Type-less export needs a constant expression assigned to infer type.");
+ return;
}
+
}
-#endif
+ if (tokenizer->get_token()==GDTokenizer::TK_PR_SETGET) {
- IdentifierNode *id = alloc_node<IdentifierNode>();
- id->name=member.identifier;
+ tokenizer->advance();
- OperatorNode *op = alloc_node<OperatorNode>();
- op->op=OperatorNode::OP_ASSIGN;
- op->arguments.push_back(id);
- op->arguments.push_back(subexpr);
+ if (tokenizer->get_token()!=GDTokenizer::TK_COMMA) {
+ //just comma means using only getter
+ if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
+ _set_error("Expected identifier for setter function after 'notify'.");
+ }
-#ifdef DEBUG_ENABLED
- NewLineNode *nl = alloc_node<NewLineNode>();
- nl->line=line;
- p_class->initializer->statements.push_back(nl);
-#endif
- p_class->initializer->statements.push_back(op);
+ member.setter=tokenizer->get_token_identifier();
+
+ tokenizer->advance();
+ }
+
+ if (tokenizer->get_token()==GDTokenizer::TK_COMMA) {
+ //there is a getter
+ tokenizer->advance();
+
+ if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
+ _set_error("Expected identifier for getter function after ','.");
+ }
+
+ member.getter=tokenizer->get_token_identifier();
+ tokenizer->advance();
+
+ }
+ }
+
+ p_class->variables.push_back(member);
_end_statement();
@@ -2531,6 +2739,8 @@ Error GDParser::_parse(const String& p_base_path) {
//assume class
ClassNode *main_class = alloc_node<ClassNode>();
main_class->initializer = alloc_node<BlockNode>();
+ main_class->initializer->parent_class=main_class;
+ current_class=main_class;
_parse_class(main_class);
@@ -2546,8 +2756,18 @@ Error GDParser::_parse(const String& p_base_path) {
return OK;
}
-Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path) {
+Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path, const String &p_self_path) {
+
+ completion_type=COMPLETION_NONE;
+ completion_node=NULL;
+ completion_class=NULL;
+ completion_function=NULL;
+ completion_block=NULL;
+ current_block=NULL;
+ current_class=NULL;
+ current_function=NULL;
+ self_path=p_self_path;
GDTokenizerBuffer *tb = memnew( GDTokenizerBuffer );
tb->set_code_buffer(p_bytecode);
tokenizer=tb;
@@ -2558,9 +2778,19 @@ Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p
}
-Error GDParser::parse(const String& p_code,const String& p_base_path,bool p_just_validate) {
+Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_just_validate, const String &p_self_path) {
+ completion_type=COMPLETION_NONE;
+ completion_node=NULL;
+ completion_class=NULL;
+ completion_function=NULL;
+ completion_block=NULL;
+ current_block=NULL;
+ current_class=NULL;
+ current_function=NULL;
+
+ self_path=p_self_path;
GDTokenizerText *tt = memnew( GDTokenizerText );
tt->set_code(p_code);
@@ -2589,6 +2819,16 @@ void GDParser::clear() {
head=NULL;
list=NULL;
+ completion_type=COMPLETION_NONE;
+ completion_node=NULL;
+ completion_class=NULL;
+ completion_function=NULL;
+ completion_block=NULL;
+ current_block=NULL;
+ current_class=NULL;
+
+ current_function=NULL;
+
validating=false;
error_set=false;
tab_level.clear();
@@ -2602,6 +2842,52 @@ void GDParser::clear() {
}
+
+GDParser::CompletionType GDParser::get_completion_type() {
+
+ return completion_type;
+}
+
+StringName GDParser::get_completion_cursor() {
+
+ return completion_cursor;
+}
+
+int GDParser::get_completion_line() {
+
+ return completion_line;
+}
+
+Variant::Type GDParser::get_completion_built_in_constant(){
+
+ return completion_built_in_constant;
+}
+
+GDParser::Node *GDParser::get_completion_node(){
+
+ return completion_node;
+}
+
+GDParser::BlockNode *GDParser::get_completion_block() {
+
+ return completion_block;
+}
+
+GDParser::ClassNode *GDParser::get_completion_class(){
+
+ return completion_class;
+}
+
+GDParser::FunctionNode *GDParser::get_completion_function(){
+
+ return completion_function;
+}
+
+int GDParser::get_completion_argument_index() {
+
+ return completion_argument;
+}
+
GDParser::GDParser() {
head=NULL;