summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/gd_compiler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gd_compiler.cpp')
-rw-r--r--modules/gdscript/gd_compiler.cpp144
1 files changed, 125 insertions, 19 deletions
diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp
index 139fdaad0d..a5351a584b 100644
--- a/modules/gdscript/gd_compiler.cpp
+++ b/modules/gdscript/gd_compiler.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,6 +29,31 @@
#include "gd_compiler.h"
#include "gd_script.h"
+bool GDCompiler::_is_class_member_property(CodeGen & codegen, const StringName & p_name) {
+
+ if (!codegen.function_node || codegen.function_node->_static)
+ return false;
+
+ return _is_class_member_property(codegen.script,p_name);
+}
+
+bool GDCompiler::_is_class_member_property(GDScript *owner, const StringName & p_name) {
+
+
+ GDScript *scr = owner;
+ GDNativeClass *nc=NULL;
+ while(scr) {
+
+ if (scr->native.is_valid())
+ nc=scr->native.ptr();
+ scr=scr->_base;
+ }
+
+ ERR_FAIL_COND_V(!nc,false);
+
+ return ClassDB::has_property(nc->get_name(),p_name);
+}
+
void GDCompiler::_set_error(const String& p_error,const GDParser::Node *p_node) {
@@ -164,6 +189,17 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
StringName identifier = in->name;
+
+ if (_is_class_member_property(codegen,identifier)) {
+ //get property
+ codegen.opcodes.push_back(GDFunction::OPCODE_GET_MEMBER); // perform operator
+ codegen.opcodes.push_back(codegen.get_name_map_pos(identifier)); // argument 2 (unary only takes one parameter)
+ int dst_addr=(p_stack_level)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS);
+ codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode
+ codegen.alloc_stack(p_stack_level);
+ return dst_addr;
+ }
+
// TRY STACK!
if (!p_initializer && codegen.stack_identifiers.has(identifier)) {
@@ -208,7 +244,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
if (nc) {
bool success=false;
- int constant = ObjectTypeDB::get_integer_constant(nc->get_name(),identifier,&success);
+ int constant = ClassDB::get_integer_constant(nc->get_name(),identifier,&success);
if (success) {
Variant key=constant;
int idx;
@@ -776,6 +812,8 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
/* Find chain of sets */
+ StringName assign_property;
+
List<GDParser::OperatorNode*> chain;
{
@@ -784,8 +822,20 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
while(true) {
chain.push_back(n);
- if (n->arguments[0]->type!=GDParser::Node::TYPE_OPERATOR)
+ if (n->arguments[0]->type!=GDParser::Node::TYPE_OPERATOR) {
+
+ //check for a built-in property
+ if (n->arguments[0]->type==GDParser::Node::TYPE_IDENTIFIER) {
+
+ GDParser::IdentifierNode *identifier = static_cast<GDParser::IdentifierNode*>(n->arguments[0]);
+ if (_is_class_member_property(codegen,identifier->name)) {
+ assign_property = identifier->name;
+
+ }
+
+ }
break;
+ }
n = static_cast<GDParser::OperatorNode*>(n->arguments[0]);
if (n->op!=GDParser::OperatorNode::OP_INDEX && n->op!=GDParser::OperatorNode::OP_INDEX_NAMED)
break;
@@ -810,6 +860,17 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
Vector<int> setchain;
+
+ if (assign_property!=StringName()) {
+
+ // recover and assign at the end, this allows stuff like
+ // position.x+=2.0
+ // in Node2D
+ setchain.push_back(prev_pos);
+ setchain.push_back(codegen.get_name_map_pos(assign_property));
+ setchain.push_back(GDFunction::OPCODE_SET_MEMBER);
+ }
+
for(List<GDParser::OperatorNode*>::Element *E=chain.back();E;E=E->prev()) {
@@ -840,7 +901,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
}
- if (key_idx<0)
+ if (key_idx<0) //error
return key_idx;
codegen.opcodes.push_back(named ? GDFunction::OPCODE_GET_NAMED : GDFunction::OPCODE_GET);
@@ -852,7 +913,10 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
codegen.opcodes.push_back(dst_pos);
+
//add in reverse order, since it will be reverted
+
+
setchain.push_back(dst_pos);
setchain.push_back(key_idx);
setchain.push_back(prev_pos);
@@ -881,7 +945,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
}
- if (set_index<0)
+ if (set_index<0) //error
return set_index;
if (set_index&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) {
@@ -891,7 +955,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
int set_value = _parse_assign_right_expression(codegen,on,slevel+1);
- if (set_value<0)
+ if (set_value<0) //error
return set_value;
codegen.opcodes.push_back(named?GDFunction::OPCODE_SET_NAMED:GDFunction::OPCODE_SET);
@@ -899,20 +963,36 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
codegen.opcodes.push_back(set_index);
codegen.opcodes.push_back(set_value);
- for(int i=0;i<setchain.size();i+=4) {
+ for(int i=0;i<setchain.size();i++) {
- codegen.opcodes.push_back(setchain[i+0]);
- codegen.opcodes.push_back(setchain[i+1]);
- codegen.opcodes.push_back(setchain[i+2]);
- codegen.opcodes.push_back(setchain[i+3]);
+ codegen.opcodes.push_back(setchain[i]);
}
return retval;
+ } else if (on->arguments[0]->type==GDParser::Node::TYPE_IDENTIFIER && _is_class_member_property(codegen,static_cast<GDParser::IdentifierNode*>(on->arguments[0])->name)) {
+ //assignment to member property
+
+ int slevel = p_stack_level;
+
+ int src_address = _parse_assign_right_expression(codegen,on,slevel);
+ if (src_address<0)
+ return -1;
+
+ StringName name = static_cast<GDParser::IdentifierNode*>(on->arguments[0])->name;
+
+ codegen.opcodes.push_back(GDFunction::OPCODE_SET_MEMBER);
+ codegen.opcodes.push_back(codegen.get_name_map_pos(name));
+ codegen.opcodes.push_back(src_address);
+
+ return GDFunction::ADDR_TYPE_NIL<<GDFunction::ADDR_BITS;
} else {
- //ASSIGNMENT MODE!!
+
+
+
+ //REGULAR ASSIGNMENT MODE!!
int slevel = p_stack_level;
@@ -1005,12 +1085,12 @@ Error GDCompiler::_parse_block(CodeGen& codegen,const GDParser::BlockNode *p_blo
switch(s->type) {
case GDParser::Node::TYPE_NEWLINE: {
-
+#ifdef DEBUG_ENABLED
const GDParser::NewLineNode *nl = static_cast<const GDParser::NewLineNode*>(s);
codegen.opcodes.push_back(GDFunction::OPCODE_LINE);
codegen.opcodes.push_back(nl->line);
codegen.current_line=nl->line;
-
+#endif
} break;
case GDParser::Node::TYPE_CONTROL_FLOW: {
// try subblocks
@@ -1266,14 +1346,21 @@ Error GDCompiler::_parse_block(CodeGen& codegen,const GDParser::BlockNode *p_blo
codegen.opcodes.push_back(ret);
} break;
case GDParser::Node::TYPE_BREAKPOINT: {
+#ifdef DEBUG_ENABLED
// try subblocks
codegen.opcodes.push_back(GDFunction::OPCODE_BREAKPOINT);
+#endif
} break;
case GDParser::Node::TYPE_LOCAL_VAR: {
const GDParser::LocalVarNode *lv = static_cast<const GDParser::LocalVarNode*>(s);
+ if (_is_class_member_property(codegen,lv->name)) {
+ _set_error("Name for local variable '"+String(lv->name)+"' can't shadow class property of the same name.",lv);
+ return ERR_ALREADY_EXISTS;
+ }
+
codegen.add_stack_identifier(lv->name,p_stack_level++);
codegen.alloc_stack(p_stack_level);
new_identifiers++;
@@ -1312,6 +1399,10 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
if (p_func) {
for(int i=0;i<p_func->arguments.size();i++) {
+ if (_is_class_member_property(p_script,p_func->arguments[i])) {
+ _set_error("Name for argument '"+String(p_func->arguments[i])+"' can't shadow class property of the same name.",p_func);
+ return ERR_ALREADY_EXISTS;
+ }
codegen.add_stack_identifier(p_func->arguments[i],i);
#ifdef TOOLS_ENABLED
argnames.push_back(p_func->arguments[i]);
@@ -1394,9 +1485,10 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
GDFunction *gdfunc=NULL;
- //if (String(p_func->name)=="") { //initializer func
- // gdfunc = &p_script->initializer;
-
+ /*
+ if (String(p_func->name)=="") { //initializer func
+ gdfunc = &p_script->initializer;
+ */
//} else { //regular func
p_script->member_functions[func_name]=memnew(GDFunction);
gdfunc = p_script->member_functions[func_name];
@@ -1703,9 +1795,14 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa
}
+ }else {
+ // without extends, implicitly extend Reference
+ int native_idx = GDScriptLanguage::get_singleton()->get_global_map()["Reference"];
+ native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx];
+ ERR_FAIL_COND_V(native.is_null(), ERR_BUG);
+ p_script->native=native;
}
-
//print_line("Script: "+p_script->get_path()+" indices: "+itos(p_script->member_indices.size()));
@@ -1716,6 +1813,10 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa
_set_error("Member '"+name+"' already exists (in current or parent class)",p_class);
return ERR_ALREADY_EXISTS;
}
+ if (_is_class_member_property(p_script,name)) {
+ _set_error("Member '"+name+"' already exists as a class property.",p_class);
+ return ERR_ALREADY_EXISTS;
+ }
if (p_class->variables[i]._export.type!=Variant::NIL) {
@@ -1754,6 +1855,11 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa
StringName name = p_class->constant_expressions[i].identifier;
ERR_CONTINUE( p_class->constant_expressions[i].expression->type!=GDParser::Node::TYPE_CONSTANT );
+ if (_is_class_member_property(p_script,name)) {
+ _set_error("Member '"+name+"' already exists as a class property.",p_class);
+ return ERR_ALREADY_EXISTS;
+ }
+
GDParser::ConstantNode *constant = static_cast<GDParser::ConstantNode*>(p_class->constant_expressions[i].expression);
p_script->constants.insert(name,constant->value);
@@ -1786,7 +1892,7 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa
}
if (native.is_valid()) {
- if (ObjectTypeDB::has_signal(native->get_name(),name)) {
+ if (ClassDB::has_signal(native->get_name(),name)) {
_set_error("Signal '"+name+"' redefined (original in native class '"+String(native->get_name())+"')",p_class);
return ERR_ALREADY_EXISTS;
}