summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/gd_compiler.cpp124
-rw-r--r--modules/gdscript/gd_compiler.h6
-rw-r--r--modules/gdscript/gd_editor.cpp183
-rw-r--r--modules/gdscript/gd_function.cpp58
-rw-r--r--modules/gdscript/gd_function.h4
-rw-r--r--modules/gdscript/gd_functions.cpp96
-rw-r--r--modules/gdscript/gd_functions.h5
-rw-r--r--modules/gdscript/gd_parser.cpp116
-rw-r--r--modules/gdscript/gd_parser.h4
-rw-r--r--modules/gdscript/gd_script.cpp78
-rw-r--r--modules/gdscript/gd_script.h10
-rw-r--r--modules/gdscript/gd_tokenizer.cpp34
-rw-r--r--modules/gdscript/gd_tokenizer.h3
-rw-r--r--modules/gdscript/register_types.cpp8
-rw-r--r--modules/gdscript/register_types.h2
15 files changed, 594 insertions, 137 deletions
diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp
index b75b13551e..7483af298c 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;
@@ -1211,6 +1291,11 @@ Error GDCompiler::_parse_block(CodeGen& codegen,const GDParser::BlockNode *p_blo
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++;
@@ -1249,6 +1334,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]);
@@ -1653,6 +1742,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) {
@@ -1691,6 +1784,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);
@@ -1723,7 +1821,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;
}
diff --git a/modules/gdscript/gd_compiler.h b/modules/gdscript/gd_compiler.h
index 7cf575e3d6..dd211a852c 100644
--- a/modules/gdscript/gd_compiler.h
+++ b/modules/gdscript/gd_compiler.h
@@ -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 */
@@ -37,6 +37,7 @@ class GDCompiler {
const GDParser *parser;
struct CodeGen {
+
GDScript *script;
const GDParser::ClassNode *class_node;
const GDParser::FunctionNode *function_node;
@@ -134,6 +135,9 @@ class GDCompiler {
Ref<GDScript> _parse_class(GDParser::ClassNode *p_class);
#endif
+ bool _is_class_member_property(CodeGen & codegen, const StringName & p_name);
+ bool _is_class_member_property(GDScript *owner, const StringName & p_name);
+
void _set_error(const String& p_error,const GDParser::Node *p_node);
bool _create_unary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level);
diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp
index c3e59836a2..00b080190f 100644
--- a/modules/gdscript/gd_editor.cpp
+++ b/modules/gdscript/gd_editor.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 */
@@ -325,7 +325,7 @@ void GDScriptLanguage::get_public_constants(List<Pair<String,Variant> > *p_const
p_constants->push_back(pi);
}
-String GDScriptLanguage::make_function(const String& p_class,const String& p_name,const StringArray& p_args) const {
+String GDScriptLanguage::make_function(const String& p_class,const String& p_name,const PoolStringArray& p_args) const {
String s="func "+p_name+"(";
if (p_args.size()) {
@@ -368,7 +368,7 @@ static GDCompletionIdentifier _get_type_from_variant(const Variant& p_variant) {
// t.obj_type=obj->cast_to<GDNativeClass>()->get_name();
// t.value=Variant();
//} else {
- t.obj_type=obj->get_type();
+ t.obj_type=obj->get_class();
//}
}
}
@@ -614,10 +614,10 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
}
}
- if (ObjectTypeDB::has_method(base.obj_type,id)) {
+ if (ClassDB::has_method(base.obj_type,id)) {
#ifdef TOOLS_ENABLED
- MethodBind *mb = ObjectTypeDB::get_method(base.obj_type,id);
+ MethodBind *mb = ClassDB::get_method(base.obj_type,id);
PropertyInfo pi = mb->get_argument_info(-1);
//try calling the function if constant and all args are constant, should not crash..
@@ -643,14 +643,14 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
}
}
- if (all_valid && String(id)=="get_node" && ObjectTypeDB::is_type(base.obj_type,"Node") && args.size()) {
+ if (all_valid && String(id)=="get_node" && ClassDB::is_parent_class(base.obj_type,"Node") && args.size()) {
String arg1=args[0];
if (arg1.begins_with("/root/")) {
String which = arg1.get_slice("/",2);
if (which!="") {
List<PropertyInfo> props;
- Globals::get_singleton()->get_property_list(&props);
+ GlobalConfig::get_singleton()->get_property_list(&props);
//print_line("find singleton");
for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
@@ -662,7 +662,7 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
String name = s.get_slice("/",1);
//print_line("name: "+name+", which: "+which);
if (name==which) {
- String script = Globals::get_singleton()->get(s);
+ String script = GlobalConfig::get_singleton()->get(s);
if (!script.begins_with("res://")) {
script="res://"+script;
@@ -940,6 +940,15 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
static bool _guess_identifier_type_in_block(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) {
+ GDCompletionIdentifier gdi = _get_native_class(context);
+ if (gdi.obj_type!=StringName()) {
+ bool valid;
+ Variant::Type t = ClassDB::get_property_type(gdi.obj_type,p_identifier,&valid);
+ if (t!=Variant::NIL && valid) {
+ r_type.type=t;
+ return true;
+ }
+ }
const GDParser::Node *last_assign=NULL;
int last_assign_line=-1;
@@ -1068,7 +1077,7 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const
//this kinda sucks but meh
List<MethodInfo> vmethods;
- ObjectTypeDB::get_virtual_methods(id.obj_type,&vmethods);
+ ClassDB::get_virtual_methods(id.obj_type,&vmethods);
for (List<MethodInfo>::Element *E=vmethods.front();E;E=E->next()) {
@@ -1142,7 +1151,7 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const
//autoloads as singletons
List<PropertyInfo> props;
- Globals::get_singleton()->get_property_list(&props);
+ GlobalConfig::get_singleton()->get_property_list(&props);
for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
@@ -1152,7 +1161,7 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const
String name = s.get_slice("/",1);
if (name==String(p_identifier)) {
- String path = Globals::get_singleton()->get(s);
+ String path = GlobalConfig::get_singleton()->get(s);
if (path.begins_with("*")) {
String script =path.substr(1,path.length());
@@ -1298,26 +1307,43 @@ static void _find_identifiers_in_class(GDCompletionContext& context,bool p_stati
base=script->get_native();
} else if (nc.is_valid()) {
+ StringName type = nc->get_name();
+
if (!p_only_functions) {
- StringName type = nc->get_name();
+
List<String> constants;
- ObjectTypeDB::get_integer_constant_list(type,&constants);
+ ClassDB::get_integer_constant_list(type,&constants);
for(List<String>::Element *E=constants.front();E;E=E->next()) {
result.insert(E->get());
}
- List<MethodInfo> methods;
- ObjectTypeDB::get_method_list(type,&methods);
- for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
- if (E->get().name.begins_with("_"))
+ List<PropertyInfo> pinfo;
+
+ ClassDB::get_property_list(type,&pinfo);
+
+ for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+ if (E->get().usage&(PROPERTY_USAGE_GROUP|PROPERTY_USAGE_CATEGORY))
continue;
- if (E->get().arguments.size())
- result.insert(E->get().name+"(");
- else
- result.insert(E->get().name+"()");
+ if (E->get().name.find("/")!=-1)
+ continue;
+ result.insert(E->get().name);
}
+
}
+ List<MethodInfo> methods;
+ ClassDB::get_method_list(type,&methods);
+ for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
+ if (E->get().name.begins_with("_"))
+ continue;
+ if (E->get().arguments.size())
+ result.insert(E->get().name+"(");
+ else
+ result.insert(E->get().name+"()");
+ }
+
+
+
break;
} else
break;
@@ -1367,7 +1393,7 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl
}
static const char*_type_names[Variant::VARIANT_MAX]={
- "null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Transform",
+ "null","bool","int","float","String","Vector2","Rect2","Vector3","Transform2D","Plane","Quat","AABB","Basis","Transform",
"Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray",
"Vector2Array","Vector3Array","ColorArray"};
@@ -1377,7 +1403,7 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl
//autoload singletons
List<PropertyInfo> props;
- Globals::get_singleton()->get_property_list(&props);
+ GlobalConfig::get_singleton()->get_property_list(&props);
for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
@@ -1385,7 +1411,7 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl
if (!s.begins_with("autoload/"))
continue;
String name = s.get_slice("/",1);
- String path = Globals::get_singleton()->get(s);
+ String path = GlobalConfig::get_singleton()->get(s);
if (path.begins_with("*")) {
result.insert(name);
}
@@ -1470,7 +1496,7 @@ static void _find_type_arguments(GDCompletionContext& context,const GDParser::No
if (id.type==Variant::INPUT_EVENT && String(p_method)=="is_action" && p_argidx==0) {
List<PropertyInfo> pinfo;
- Globals::get_singleton()->get_property_list(&pinfo);
+ GlobalConfig::get_singleton()->get_property_list(&pinfo);
for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
const PropertyInfo &pi=E->get();
@@ -1486,7 +1512,7 @@ static void _find_type_arguments(GDCompletionContext& context,const GDParser::No
} else if (id.type==Variant::OBJECT && id.obj_type!=StringName()) {
- MethodBind *m = ObjectTypeDB::get_method(id.obj_type,p_method);
+ MethodBind *m = ClassDB::get_method(id.obj_type,p_method);
if (!m) {
//not in static method, see script
@@ -1699,7 +1725,7 @@ static void _find_type_arguments(GDCompletionContext& context,const GDParser::No
if (p_argidx==0) {
List<MethodInfo> sigs;
- ObjectTypeDB::get_signal_list(id.obj_type,&sigs);
+ ClassDB::get_signal_list(id.obj_type,&sigs);
if (id.script.is_valid()) {
id.script->get_script_signal_list(&sigs);
@@ -1735,10 +1761,10 @@ static void _find_type_arguments(GDCompletionContext& context,const GDParser::No
}*/
} else {
- if (p_argidx==0 && (String(p_method)=="get_node" || String(p_method)=="has_node") && ObjectTypeDB::is_type(id.obj_type,"Node")) {
+ if (p_argidx==0 && (String(p_method)=="get_node" || String(p_method)=="has_node") && ClassDB::is_parent_class(id.obj_type,"Node")) {
List<PropertyInfo> props;
- Globals::get_singleton()->get_property_list(&props);
+ GlobalConfig::get_singleton()->get_property_list(&props);
for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
@@ -1970,7 +1996,7 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No
//guess type..
/*
List<MethodInfo> methods;
- ObjectTypeDB::get_method_list(type,&methods);
+ ClassDB::get_method_list(type,&methods);
for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
//if (E->get().arguments.size())
// result.insert(E->get().name+"(");
@@ -2063,13 +2089,13 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No
StringName type = nc->get_name();
List<String> constants;
- ObjectTypeDB::get_integer_constant_list(type,&constants);
+ ClassDB::get_integer_constant_list(type,&constants);
for(List<String>::Element *E=constants.front();E;E=E->next()) {
result.insert(E->get());
}
List<MethodInfo> methods;
- ObjectTypeDB::get_method_list(type,&methods);
+ ClassDB::get_method_list(type,&methods);
for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
if (E->get().arguments.size())
result.insert(E->get().name+"(");
@@ -2129,6 +2155,27 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
case GDParser::COMPLETION_PARENT_FUNCTION: {
} break;
+ case GDParser::COMPLETION_GET_NODE: {
+
+ if (p_owner) {
+ List<String> opts;
+ p_owner->get_argument_options("get_node",0,&opts);
+
+ for (List<String>::Element *E=opts.front();E;E=E->next()) {
+
+ String opt = E->get().strip_edges();
+ if (opt.begins_with("\"") && opt.ends_with("\"")) {
+ String idopt=opt.substr(1,opt.length()-2);
+ if (idopt.replace("/","_").is_valid_identifier()) {
+ options.insert(idopt);
+ } else {
+ options.insert(opt);
+ }
+ }
+ }
+
+ }
+ } break;
case GDParser::COMPLETION_METHOD:
isfunction=true;
case GDParser::COMPLETION_INDEX: {
@@ -2149,10 +2196,21 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
if (gdn.is_valid()) {
StringName cn = gdn->get_name();
List<String> cnames;
- ObjectTypeDB::get_integer_constant_list(cn,&cnames);
+ ClassDB::get_integer_constant_list(cn,&cnames);
for (List<String>::Element *E=cnames.front();E;E=E->next()) {
options.insert(E->get());
}
+
+ List<PropertyInfo> pinfo;
+ ClassDB::get_property_list(cn,&pinfo);
+
+ for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+ if (E->get().usage&(PROPERTY_USAGE_GROUP|PROPERTY_USAGE_CATEGORY))
+ continue;
+ if (E->get().name.find("/")!=-1)
+ continue;
+ options.insert(E->get().name);
+ }
}
} else if (t.type==Variant::OBJECT && t.obj_type!=StringName()) {
@@ -2288,10 +2346,23 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
if (!isfunction) {
- ObjectTypeDB::get_integer_constant_list(t.obj_type,r_options);
+ ClassDB::get_integer_constant_list(t.obj_type,r_options);
+
+ List<PropertyInfo> pinfo;
+ ClassDB::get_property_list(t.obj_type,&pinfo);
+
+ for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+ if (E->get().usage&(PROPERTY_USAGE_GROUP|PROPERTY_USAGE_CATEGORY))
+ continue;
+ if (E->get().name.find("/")!=-1)
+ continue;
+ r_options->push_back(E->get().name);
+ }
}
+
+
List<MethodInfo> mi;
- ObjectTypeDB::get_method_list(t.obj_type,&mi);
+ ClassDB::get_method_list(t.obj_type,&mi);
for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) {
if (E->get().name.begins_with("_"))
@@ -2320,8 +2391,8 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
"# Key",
"# MouseMotion",
"# MouseButton",
- "# JoystickMotion",
- "# JoystickButton",
+ "# JoypadMotion",
+ "# JoypadButton",
"# ScreenTouch",
"# ScreenDrag",
"# Action"
@@ -2397,7 +2468,7 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
if (cid.obj_type!=StringName()) {
List<MethodInfo> vm;
- ObjectTypeDB::get_virtual_methods(cid.obj_type,&vm);
+ ClassDB::get_virtual_methods(cid.obj_type,&vm);
for(List<MethodInfo>::Element *E=vm.front();E;E=E->next()) {
MethodInfo &mi=E->get();
@@ -2433,7 +2504,7 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
if (t.type==Variant::OBJECT && t.obj_type!=StringName()) {
List<MethodInfo> sigs;
- ObjectTypeDB::get_signal_list(t.obj_type,&sigs);
+ ClassDB::get_signal_list(t.obj_type,&sigs);
for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) {
options.insert("\""+E->get().name+"\"");
}
@@ -2531,7 +2602,7 @@ Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol
//before parsing, try the usual stuff
- if (ObjectTypeDB::type_exists(p_symbol)) {
+ if (ClassDB::class_exists(p_symbol)) {
r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS;
r_result.class_name=p_symbol;
return OK;
@@ -2612,7 +2683,7 @@ Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol
GDCompletionIdentifier identifier = _get_native_class(context);
print_line("identifier: "+String(identifier.obj_type));
- if (ObjectTypeDB::has_method(identifier.obj_type,p_symbol)) {
+ if (ClassDB::has_method(identifier.obj_type,p_symbol)) {
r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
r_result.class_name=identifier.obj_type;
@@ -2653,7 +2724,7 @@ Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol
GDCompletionIdentifier identifier = _get_native_class(context);
- if (ObjectTypeDB::has_method(identifier.obj_type,p_symbol)) {
+ if (ClassDB::has_method(identifier.obj_type,p_symbol)) {
r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
r_result.class_name=identifier.obj_type;
@@ -2663,6 +2734,19 @@ Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol
} else {
+ GDCompletionIdentifier gdi = _get_native_class(context);
+ if (gdi.obj_type!=StringName()) {
+ bool valid;
+ Variant::Type t = ClassDB::get_property_type(gdi.obj_type,p_symbol,&valid);
+ if (t!=Variant::NIL && valid) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY;
+ r_result.class_name=gdi.obj_type;
+ r_result.class_member=p_symbol;
+ return OK;
+
+ }
+ }
+
const GDParser::BlockNode *block=context.block;
//search in blocks going up (local var?)
while(block) {
@@ -2731,7 +2815,7 @@ Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol
//guess in autoloads as singletons
List<PropertyInfo> props;
- Globals::get_singleton()->get_property_list(&props);
+ GlobalConfig::get_singleton()->get_property_list(&props);
for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
@@ -2741,7 +2825,7 @@ Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol
String name = s.get_slice("/",1);
if (name==String(p_symbol)) {
- String path = Globals::get_singleton()->get(s);
+ String path = GlobalConfig::get_singleton()->get(s);
if (path.begins_with("*")) {
String script =path.substr(1,path.length());
@@ -2777,7 +2861,7 @@ Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol
} else {
r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS;
- r_result.class_name=obj->get_type();
+ r_result.class_name=obj->get_class();
}
return OK;
}
@@ -2858,7 +2942,7 @@ Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol
}
}
- if (ObjectTypeDB::has_method(t.obj_type,p_symbol)) {
+ if (ClassDB::has_method(t.obj_type,p_symbol)) {
r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
r_result.class_name=t.obj_type;
@@ -2868,7 +2952,7 @@ Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol
}
bool success;
- ObjectTypeDB::get_integer_constant(t.obj_type,p_symbol,&success);
+ ClassDB::get_integer_constant(t.obj_type,p_symbol,&success);
if (success) {
r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
r_result.class_name=t.obj_type;
@@ -2876,7 +2960,8 @@ Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol
return OK;
}
- ObjectTypeDB::get_property_type(t.obj_type,p_symbol,&success);
+
+ ClassDB::get_property_type(t.obj_type,p_symbol,&success);
if (success) {
r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY;
@@ -2936,7 +3021,7 @@ Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol
if (cid.obj_type!=StringName()) {
List<MethodInfo> vm;
- ObjectTypeDB::get_virtual_methods(cid.obj_type,&vm);
+ ClassDB::get_virtual_methods(cid.obj_type,&vm);
for(List<MethodInfo>::Element *E=vm.front();E;E=E->next()) {
if (p_symbol==E->get().name) {
diff --git a/modules/gdscript/gd_function.cpp b/modules/gdscript/gd_function.cpp
index 094e21bb4f..e3217e9218 100644
--- a/modules/gdscript/gd_function.cpp
+++ b/modules/gdscript/gd_function.cpp
@@ -119,9 +119,9 @@ static String _get_var_type(const Variant* p_type) {
#ifdef DEBUG_ENABLED
if (ObjectDB::instance_validate(bobj)) {
if (bobj->get_script_instance())
- basestr= bobj->get_type()+" ("+bobj->get_script_instance()->get_script()->get_path().get_file()+")";
+ basestr= bobj->get_class()+" ("+bobj->get_script_instance()->get_script()->get_path().get_file()+")";
else
- basestr = bobj->get_type();
+ basestr = bobj->get_class();
} else {
basestr="previously freed instance";
}
@@ -395,11 +395,11 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
if (!nc) {
- err_text="Right operand of 'extends' is not a class (type: '"+obj_B->get_type()+"').";
+ err_text="Right operand of 'extends' is not a class (type: '"+obj_B->get_class()+"').";
break;
}
- extends_ok=ObjectTypeDB::is_type(obj_A->get_type_name(),nc->get_name());
+ extends_ok=ClassDB::is_parent_class(obj_A->get_class_name(),nc->get_name());
}
*dst=extends_ok;
@@ -487,7 +487,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
case OPCODE_GET_NAMED: {
- CHECK_SPACE(3);
+ CHECK_SPACE(4);
GET_VARIANT_PTR(src,1);
GET_VARIANT_PTR(dst,3);
@@ -519,6 +519,46 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
#endif
ip+=4;
} continue;
+ case OPCODE_SET_MEMBER: {
+
+ CHECK_SPACE(3);
+ int indexname = _code_ptr[ip+1];
+ ERR_BREAK(indexname<0 || indexname>=_global_names_count);
+ const StringName *index = &_global_names_ptr[indexname];
+ GET_VARIANT_PTR(src,2);
+
+ bool valid;
+ bool ok = ClassDB::set_property(p_instance->owner,*index,*src,&valid);
+#ifdef DEBUG_ENABLED
+ if (!ok) {
+ err_text="Internal error setting property: "+String(*index);
+ break;
+ } else if (!valid) {
+ err_text="Error setting property '"+String(*index)+"' with value of type "+Variant::get_type_name(src->get_type())+".";
+ break;
+
+ }
+#endif
+ ip+=3;
+ } continue;
+ case OPCODE_GET_MEMBER: {
+
+ CHECK_SPACE(3);
+ int indexname = _code_ptr[ip+1];
+ ERR_BREAK(indexname<0 || indexname>=_global_names_count);
+ const StringName *index = &_global_names_ptr[indexname];
+ GET_VARIANT_PTR(dst,2);
+ bool ok = ClassDB::get_property(p_instance->owner,*index,*dst);
+
+#ifdef DEBUG_ENABLED
+ if (!ok) {
+ err_text="Internal error getting property: "+String(*index);
+ break;
+ }
+#endif
+ ip+=3;
+
+ } continue;
case OPCODE_ASSIGN: {
CHECK_SPACE(3);
@@ -788,7 +828,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
if (*methodname!=GDScriptLanguage::get_singleton()->strings._init) {
- MethodBind *mb = ObjectTypeDB::get_method(gds->native->get_name(),*methodname);
+ MethodBind *mb = ClassDB::get_method(gds->native->get_name(),*methodname);
if (!mb) {
err.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
} else {
@@ -1435,9 +1475,9 @@ Variant GDFunctionState::resume(const Variant& p_arg) {
void GDFunctionState::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("resume:Variant","arg"),&GDFunctionState::resume,DEFVAL(Variant()));
- ObjectTypeDB::bind_method(_MD("is_valid"),&GDFunctionState::is_valid);
- ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&GDFunctionState::_signal_callback,MethodInfo("_signal_callback"));
+ ClassDB::bind_method(_MD("resume:Variant","arg"),&GDFunctionState::resume,DEFVAL(Variant()));
+ ClassDB::bind_method(_MD("is_valid"),&GDFunctionState::is_valid);
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&GDFunctionState::_signal_callback,MethodInfo("_signal_callback"));
}
diff --git a/modules/gdscript/gd_function.h b/modules/gdscript/gd_function.h
index f1c5b13ca1..e5262e8ad7 100644
--- a/modules/gdscript/gd_function.h
+++ b/modules/gdscript/gd_function.h
@@ -23,6 +23,8 @@ public:
OPCODE_GET,
OPCODE_SET_NAMED,
OPCODE_GET_NAMED,
+ OPCODE_SET_MEMBER,
+ OPCODE_GET_MEMBER,
OPCODE_ASSIGN,
OPCODE_ASSIGN_TRUE,
OPCODE_ASSIGN_FALSE,
@@ -204,7 +206,7 @@ public:
class GDFunctionState : public Reference {
- OBJ_TYPE(GDFunctionState,Reference);
+ GDCLASS(GDFunctionState,Reference);
friend class GDFunction;
GDFunction *function;
GDFunction::CallState state;
diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp
index e4add4e574..35ceeeb1aa 100644
--- a/modules/gdscript/gd_functions.cpp
+++ b/modules/gdscript/gd_functions.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 */
@@ -35,6 +35,7 @@
#include "os/os.h"
#include "variant_parser.h"
#include "io/marshalls.h"
+#include "io/json.h"
const char *GDFunctions::get_func_name(Function p_func) {
@@ -103,6 +104,9 @@ const char *GDFunctions::get_func_name(Function p_func) {
"load",
"inst2dict",
"dict2inst",
+ "validate_json",
+ "parse_json",
+ "to_json",
"hash",
"Color8",
"ColorN",
@@ -537,7 +541,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
case TYPE_EXISTS: {
VALIDATE_ARG_COUNT(1);
- r_ret = ObjectTypeDB::type_exists(*p_args[0]);
+ r_ret = ClassDB::class_exists(*p_args[0]);
} break;
case TEXT_CHAR: {
@@ -669,7 +673,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
case VAR_TO_BYTES: {
VALIDATE_ARG_COUNT(1);
- ByteArray barr;
+ PoolByteArray barr;
int len;
Error err = encode_variant(*p_args[0],NULL,len);
if (err) {
@@ -682,7 +686,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
barr.resize(len);
{
- ByteArray::Write w = barr.write();
+ PoolByteArray::Write w = barr.write();
encode_variant(*p_args[0],w.ptr(),len);
}
@@ -690,24 +694,24 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
} break;
case BYTES_TO_VAR: {
VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type()!=Variant::RAW_ARRAY) {
+ if (p_args[0]->get_type()!=Variant::POOL_BYTE_ARRAY) {
r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument=0;
- r_error.expected=Variant::RAW_ARRAY;
+ r_error.expected=Variant::POOL_BYTE_ARRAY;
r_ret=Variant();
return;
}
- ByteArray varr=*p_args[0];
+ PoolByteArray varr=*p_args[0];
Variant ret;
{
- ByteArray::Read r=varr.read();
+ PoolByteArray::Read r=varr.read();
Error err = decode_variant(ret,r.ptr(),varr.size(),NULL);
if (err!=OK) {
r_ret=RTR("Not enough bytes for decoding bytes, or invalid format.");
r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument=0;
- r_error.expected=Variant::RAW_ARRAY;
+ r_error.expected=Variant::POOL_BYTE_ARRAY;
return;
}
@@ -847,6 +851,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
if (p_args[0]->get_type()!=Variant::STRING) {
r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument=0;
+ r_error.expected=Variant::STRING;
r_ret=Variant();
} else {
r_ret=ResourceLoader::load(*p_args[0]);
@@ -1025,6 +1030,57 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
}
} break;
+ case VALIDATE_JSON: {
+
+ VALIDATE_ARG_COUNT(1);
+
+ if (p_args[0]->get_type()!=Variant::STRING) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::STRING;
+ r_ret=Variant();
+ return;
+ }
+
+ String errs;
+ int errl;
+
+ Error err = JSON::parse(*p_args[0],r_ret,errs,errl);
+
+ if (err!=OK) {
+ r_ret=itos(errl)+":"+errs;
+ } else {
+ r_ret="";
+ }
+
+ } break;
+ case PARSE_JSON: {
+
+ VALIDATE_ARG_COUNT(1);
+
+ if (p_args[0]->get_type()!=Variant::STRING) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::STRING;
+ r_ret=Variant();
+ return;
+ }
+
+ String errs;
+ int errl;
+
+ Error err = JSON::parse(*p_args[0],r_ret,errs,errl);
+
+ if (err!=OK) {
+ r_ret=Variant();
+ }
+
+ } break;
+ case TO_JSON: {
+ VALIDATE_ARG_COUNT(1);
+
+ r_ret = JSON::print(*p_args[0]);
+ } break;
case HASH: {
VALIDATE_ARG_COUNT(1);
@@ -1506,13 +1562,13 @@ MethodInfo GDFunctions::get_info(Function p_func) {
} break;
case VAR_TO_BYTES: {
MethodInfo mi("var2bytes",PropertyInfo(Variant::NIL,"var"));
- mi.return_val.type=Variant::RAW_ARRAY;
+ mi.return_val.type=Variant::POOL_BYTE_ARRAY;
return mi;
} break;
case BYTES_TO_VAR: {
- MethodInfo mi("bytes2var:Variant",PropertyInfo(Variant::RAW_ARRAY,"bytes"));
+ MethodInfo mi("bytes2var:Variant",PropertyInfo(Variant::POOL_BYTE_ARRAY,"bytes"));
mi.return_val.type=Variant::NIL;
return mi;
} break;
@@ -1541,6 +1597,24 @@ MethodInfo GDFunctions::get_info(Function p_func) {
mi.return_val.type=Variant::OBJECT;
return mi;
} break;
+ case VALIDATE_JSON: {
+
+ MethodInfo mi("validate_json:Variant",PropertyInfo(Variant::STRING,"json"));
+ mi.return_val.type=Variant::STRING;
+ return mi;
+ } break;
+ case PARSE_JSON: {
+
+ MethodInfo mi("parse_json:Variant",PropertyInfo(Variant::STRING,"json"));
+ mi.return_val.type=Variant::NIL;
+ return mi;
+ } break;
+ case TO_JSON: {
+
+ MethodInfo mi("to_json",PropertyInfo(Variant::NIL,"var:Variant"));
+ mi.return_val.type=Variant::STRING;
+ return mi;
+ } break;
case HASH: {
MethodInfo mi("hash",PropertyInfo(Variant::NIL,"var:Variant"));
diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h
index 5c8b61db37..6e30b4dbb5 100644
--- a/modules/gdscript/gd_functions.h
+++ b/modules/gdscript/gd_functions.h
@@ -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 */
@@ -97,6 +97,9 @@ public:
RESOURCE_LOAD,
INST2DICT,
DICT2INST,
+ VALIDATE_JSON,
+ PARSE_JSON,
+ TO_JSON,
HASH,
COLOR8,
COLORN,
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp
index 131b9a0853..adf13e0a3b 100644
--- a/modules/gdscript/gd_parser.cpp
+++ b/modules/gdscript/gd_parser.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 */
@@ -265,6 +265,98 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
tokenizer->advance();
expr=subexpr;
+ } else if (tokenizer->get_token()==GDTokenizer::TK_DOLLAR) {
+ tokenizer->advance();
+
+ String path;
+
+ bool need_identifier=true;
+ bool done=false;
+
+ while(!done) {
+
+ switch(tokenizer->get_token()) {
+ case GDTokenizer::TK_CURSOR: {
+ completion_cursor=StringName();
+ completion_type=COMPLETION_GET_NODE;
+ completion_class=current_class;
+ completion_function=current_function;
+ completion_line=tokenizer->get_token_line();
+ completion_cursor=path;
+ completion_argument=0;
+ completion_block=current_block;
+ completion_found=true;
+ tokenizer->advance();
+ } break;
+ case GDTokenizer::TK_CONSTANT: {
+
+ if (!need_identifier) {
+ done=true;
+ break;
+ }
+
+ if (tokenizer->get_token_constant().get_type()!=Variant::STRING) {
+ _set_error("Expected string constant or identifier after '$' or '/'.");
+ return NULL;
+ }
+
+ path+=String(tokenizer->get_token_constant());
+ tokenizer->advance();
+ need_identifier=false;
+
+ } break;
+ case GDTokenizer::TK_IDENTIFIER: {
+ if (!need_identifier) {
+ done=true;
+ break;
+ }
+
+ path+=String(tokenizer->get_token_identifier());
+ tokenizer->advance();
+ need_identifier=false;
+
+ } break;
+ case GDTokenizer::TK_OP_DIV: {
+
+ if (need_identifier) {
+ done=true;
+ break;
+ }
+
+ path+="/";
+ tokenizer->advance();
+ need_identifier=true;
+
+ } break;
+ default: {
+ done=true;
+ break;
+ }
+ }
+ }
+
+ if (path=="") {
+ _set_error("Path expected after $.");
+ return NULL;
+
+ }
+
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op=OperatorNode::OP_CALL;
+
+ op->arguments.push_back(alloc_node<SelfNode>());
+
+ IdentifierNode *funcname = alloc_node<IdentifierNode>();
+ funcname->name="get_node";
+
+ op->arguments.push_back(funcname);
+
+ ConstantNode *nodepath = alloc_node<ConstantNode>();
+ nodepath->value = NodePath(StringName(path));
+ op->arguments.push_back(nodepath);
+
+ expr=op;
+
} else if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
tokenizer->advance();
continue; //no point in cursor in the middle of expression
@@ -540,14 +632,15 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
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) {
+ } 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) {
- //single prefix operators like !expr -expr ++expr --expr
+ //single prefix operators like !expr +expr -expr ++expr --expr
alloc_node<OperatorNode>();
Expression e;
e.is_op=true;
switch(tokenizer->get_token()) {
+ case GDTokenizer::TK_OP_ADD: e.op=OperatorNode::OP_POS; break;
case GDTokenizer::TK_OP_SUB: e.op=OperatorNode::OP_NEG; break;
case GDTokenizer::TK_OP_NOT: e.op=OperatorNode::OP_NOT; break;
case GDTokenizer::TK_OP_BIT_INVERT: e.op=OperatorNode::OP_BIT_INVERT;; break;
@@ -995,6 +1088,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
case OperatorNode::OP_BIT_INVERT: priority=0; unary=true; break;
case OperatorNode::OP_NEG: priority=1; unary=true; break;
+ case OperatorNode::OP_POS: priority=1; unary=true; break;
case OperatorNode::OP_MUL: priority=2; break;
case OperatorNode::OP_DIV: priority=2; break;
@@ -1476,6 +1570,15 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) {
return op;
}
+ if (op->arguments[0]->type==Node::TYPE_OPERATOR) {
+ OperatorNode *on = static_cast<OperatorNode*>(op->arguments[0]);
+ if (on->op != OperatorNode::OP_INDEX && on->op != OperatorNode::OP_INDEX_NAMED) {
+ _set_error("Can't assign to an expression",tokenizer->get_token_line()-1);
+ error_line=op->line;
+ return op;
+ }
+ }
+
} break;
default: { break; }
}
@@ -1512,6 +1615,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) {
//unary operators
case OperatorNode::OP_NEG: { _REDUCE_UNARY(Variant::OP_NEGATE); } break;
+ case OperatorNode::OP_POS: { _REDUCE_UNARY(Variant::OP_POSITIVE); } break;
case OperatorNode::OP_NOT: { _REDUCE_UNARY(Variant::OP_NOT); } break;
case OperatorNode::OP_BIT_INVERT: { _REDUCE_UNARY(Variant::OP_BIT_NEGATE); } break;
//binary operators (in precedence order)
@@ -2564,7 +2668,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="FLAGS") {
- current_export.hint=PROPERTY_HINT_ALL_FLAGS;
+ //current_export.hint=PROPERTY_HINT_ALL_FLAGS;
tokenizer->advance();
if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) {
@@ -2919,7 +3023,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
} else if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
String identifier = tokenizer->get_token_identifier();
- if (!ObjectTypeDB::is_type(identifier,"Resource")) {
+ if (!ClassDB::is_parent_class(identifier,"Resource")) {
current_export=PropertyInfo();
_set_error("Export hint not a type or resource.");
@@ -3137,7 +3241,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
return;
}
member._export.hint=PROPERTY_HINT_RESOURCE_TYPE;
- member._export.hint_string=res->get_type();
+ member._export.hint_string=res->get_class();
}
}
}
diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h
index 75653e0916..e8f5f0f981 100644
--- a/modules/gdscript/gd_parser.h
+++ b/modules/gdscript/gd_parser.h
@@ -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 */
@@ -209,6 +209,7 @@ public:
OP_INDEX_NAMED,
//unary operators
OP_NEG,
+ OP_POS,
OP_NOT,
OP_BIT_INVERT,
OP_PREINC,
@@ -375,6 +376,7 @@ public:
enum CompletionType {
COMPLETION_NONE,
COMPLETION_BUILT_IN_TYPE_CONSTANT,
+ COMPLETION_GET_NODE,
COMPLETION_FUNCTION,
COMPLETION_IDENTIFIER,
COMPLETION_PARENT_FUNCTION,
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp
index 0ea10950df..0b81780b0c 100644
--- a/modules/gdscript/gd_script.cpp
+++ b/modules/gdscript/gd_script.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 */
@@ -50,7 +50,7 @@ GDNativeClass::GDNativeClass(const StringName& p_name) {
bool GDNativeClass::_get(const StringName& p_name,Variant &r_ret) const {
bool ok;
- int v = ObjectTypeDB::get_integer_constant(name, p_name, &ok);
+ int v = ClassDB::get_integer_constant(name, p_name, &ok);
if (ok) {
r_ret=v;
@@ -63,7 +63,7 @@ bool GDNativeClass::_get(const StringName& p_name,Variant &r_ret) const {
void GDNativeClass::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("new"),&GDNativeClass::_new);
+ ClassDB::bind_method(_MD("new"),&GDNativeClass::_new);
}
@@ -86,7 +86,7 @@ Variant GDNativeClass::_new() {
Object *GDNativeClass::instance() {
- return ObjectTypeDB::instance(name);
+ return ClassDB::instance(name);
}
@@ -111,14 +111,29 @@ GDInstance* GDScript::_create_instance(const Variant** p_args,int p_argcount,Obj
/* STEP 2, INITIALIZE AND CONSRTUCT */
+#ifndef NO_THREADS
+ GDScriptLanguage::singleton->lock->lock();
+#endif
+
instances.insert(instance->owner);
+#ifndef NO_THREADS
+ GDScriptLanguage::singleton->lock->unlock();
+#endif
+
initializer->call(instance,p_args,p_argcount,r_error);
if (r_error.error!=Variant::CallError::CALL_OK) {
instance->script=Ref<GDScript>();
instance->owner->set_script_instance(NULL);
+#ifndef NO_THREADS
+ GDScriptLanguage::singleton->lock->lock();
+#endif
instances.erase(p_owner);
+#ifndef NO_THREADS
+ GDScriptLanguage::singleton->lock->unlock();
+#endif
+
ERR_FAIL_COND_V(r_error.error!=Variant::CallError::CALL_OK, NULL); //error constructing
}
@@ -388,12 +403,12 @@ ScriptInstance* GDScript::instance_create(Object *p_this) {
top=top->_base;
if (top->native.is_valid()) {
- if (!ObjectTypeDB::is_type(p_this->get_type_name(),top->native->get_name())) {
+ if (!ClassDB::is_parent_class(p_this->get_class_name(),top->native->get_name())) {
if (ScriptDebugger::get_singleton()) {
- GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),0,"Script inherits from native type '"+String(top->native->get_name())+"', so it can't be instanced in object of type: '"+p_this->get_type()+"'");
+ GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),0,"Script inherits from native type '"+String(top->native->get_name())+"', so it can't be instanced in object of type: '"+p_this->get_class()+"'");
}
- ERR_EXPLAIN("Script inherits from native type '"+String(top->native->get_name())+"', so it can't be instanced in object of type: '"+p_this->get_type()+"'");
+ ERR_EXPLAIN("Script inherits from native type '"+String(top->native->get_name())+"', so it can't be instanced in object of type: '"+p_this->get_class()+"'");
ERR_FAIL_V(NULL);
}
@@ -405,7 +420,16 @@ ScriptInstance* GDScript::instance_create(Object *p_this) {
}
bool GDScript::instance_has(const Object *p_this) const {
- return instances.has((Object*)p_this);
+#ifndef NO_THREADS
+ GDScriptLanguage::singleton->lock->lock();
+#endif
+ bool hasit = instances.has((Object*)p_this);
+
+#ifndef NO_THREADS
+ GDScriptLanguage::singleton->lock->unlock();
+#endif
+
+ return hasit;
}
bool GDScript::has_source_code() const {
@@ -596,8 +620,16 @@ void GDScript::_set_subclass_path(Ref<GDScript>& p_sc,const String& p_path) {
Error GDScript::reload(bool p_keep_state) {
+#ifndef NO_THREADS
+ GDScriptLanguage::singleton->lock->lock();
+#endif
+ bool has_instances = instances.size();
+
+#ifndef NO_THREADS
+ GDScriptLanguage::singleton->lock->unlock();
+#endif
- ERR_FAIL_COND_V(!p_keep_state && instances.size(),ERR_ALREADY_IN_USE);
+ ERR_FAIL_COND_V(!p_keep_state && has_instances,ERR_ALREADY_IN_USE);
String basedir=path;
@@ -751,9 +783,9 @@ void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const {
void GDScript::_bind_methods() {
- ObjectTypeDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo(Variant::OBJECT,"new"));
+ ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo(Variant::OBJECT,"new"));
- ObjectTypeDB::bind_method(_MD("get_as_byte_code"),&GDScript::get_as_byte_code);
+ ClassDB::bind_method(_MD("get_as_byte_code"),&GDScript::get_as_byte_code);
}
@@ -830,7 +862,7 @@ Error GDScript::load_byte_code(const String& p_path) {
Error GDScript::load_source_code(const String& p_path) {
- DVector<uint8_t> sourcef;
+ PoolVector<uint8_t> sourcef;
Error err;
FileAccess *f=FileAccess::open(p_path,FileAccess::READ,&err);
if (err) {
@@ -840,7 +872,7 @@ Error GDScript::load_source_code(const String& p_path) {
int len = f->get_len();
sourcef.resize(len+1);
- DVector<uint8_t>::Write w = sourcef.write();
+ PoolVector<uint8_t>::Write w = sourcef.write();
int r = f->get_buffer(w.ptr(),len);
f->close();
memdelete(f);
@@ -1423,7 +1455,15 @@ GDInstance::GDInstance() {
GDInstance::~GDInstance() {
if (script.is_valid() && owner) {
- script->instances.erase(owner);
+#ifndef NO_THREADS
+ GDScriptLanguage::singleton->lock->lock();
+#endif
+
+ script->instances.erase(owner);
+#ifndef NO_THREADS
+ GDScriptLanguage::singleton->lock->unlock();
+#endif
+
}
}
@@ -1477,7 +1517,7 @@ void GDScriptLanguage::init() {
//populate native classes
List<StringName> class_list;
- ObjectTypeDB::get_type_list(&class_list);
+ ClassDB::get_class_list(&class_list);
for(List<StringName>::Element *E=class_list.front();E;E=E->next()) {
StringName n = E->get();
@@ -1493,9 +1533,9 @@ void GDScriptLanguage::init() {
//populate singletons
- List<Globals::Singleton> singletons;
- Globals::get_singleton()->get_singletons(&singletons);
- for(List<Globals::Singleton>::Element *E=singletons.front();E;E=E->next()) {
+ List<GlobalConfig::Singleton> singletons;
+ GlobalConfig::get_singleton()->get_singletons(&singletons);
+ for(List<GlobalConfig::Singleton>::Element *E=singletons.front();E;E=E->next()) {
_add_global(E->get().name,E->get().ptr);
}
@@ -1940,7 +1980,7 @@ GDScriptLanguage::GDScriptLanguage() {
script_frame_time=0;
_debug_call_stack_pos=0;
- int dmcs=GLOBAL_DEF("debug/script_max_call_stack",1024);
+ int dmcs=GLOBAL_DEF("debug/script/max_call_stack",1024);
if (ScriptDebugger::get_singleton()) {
//debugging enabled!
diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h
index 051e80634f..960b06f3ff 100644
--- a/modules/gdscript/gd_script.h
+++ b/modules/gdscript/gd_script.h
@@ -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 */
@@ -35,7 +35,7 @@
#include "gd_function.h"
class GDNativeClass : public Reference {
- OBJ_TYPE(GDNativeClass,Reference);
+ GDCLASS(GDNativeClass,Reference);
StringName name;
protected:
@@ -55,7 +55,7 @@ public:
class GDScript : public Script {
- OBJ_TYPE(GDScript,Script);
+ GDCLASS(GDScript,Script);
bool tool;
bool valid;
@@ -294,11 +294,13 @@ class GDScriptLanguage : public ScriptLanguage {
void _add_global(const StringName& p_name,const Variant& p_value);
+friend class GDInstance;
Mutex *lock;
+
friend class GDScript;
SelfList<GDScript>::List script_list;
@@ -406,7 +408,7 @@ public:
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual int find_function(const String& p_function,const String& p_code) const;
- virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const;
+ virtual String make_function(const String& p_class,const String& p_name,const PoolStringArray& p_args) const;
virtual Error complete_code(const String& p_code, const String& p_base_path, Object*p_owner,List<String>* r_options,String& r_call_hint);
#ifdef TOOLS_ENABLED
virtual Error lookup_code(const String& p_code, const String& p_symbol, const String& p_base_path, Object*p_owner, LookupResult& r_result);
diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp
index 39c4530d96..30ac988295 100644
--- a/modules/gdscript/gd_tokenizer.cpp
+++ b/modules/gdscript/gd_tokenizer.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 */
@@ -460,6 +460,9 @@ void GDTokenizerText::_advance() {
case ':':
_make_token(TK_COLON); //for methods maybe but now useless.
break;
+ case '$':
+ _make_token(TK_DOLLAR); //for the get_node() shortener
+ break;
case '^': {
if (GETCHAR(1)=='=') {
_make_token(TK_OP_ASSIGN_BIT_XOR);
@@ -728,14 +731,14 @@ void GDTokenizerText::_advance() {
INCPOS(str.length());
if (hexa_found) {
- int val = str.hex_to_int();
+ int64_t val = str.hex_to_int64();
_make_constant(val);
} else if (period_found || exponent_found) {
- real_t val = str.to_double();
+ double val = str.to_double();
//print_line("*%*%*%*% to convert: "+str+" result: "+rtos(val));
_make_constant(val);
} else {
- int val = str.to_int();
+ int64_t val = str.to_int64();
_make_constant(val);
}
@@ -785,13 +788,12 @@ void GDTokenizerText::_advance() {
{Variant::STRING,"String"},
{Variant::VECTOR2,"Vector2"},
{Variant::RECT2,"Rect2"},
- {Variant::MATRIX32,"Matrix32"},
+ {Variant::TRANSFORM2D,"Transform2D"},
{Variant::VECTOR3,"Vector3"},
- {Variant::_AABB,"AABB"},
- {Variant::_AABB,"Rect3"},
+ {Variant::RECT3,"Rect3"},
{Variant::PLANE,"Plane"},
{Variant::QUAT,"Quat"},
- {Variant::MATRIX3,"Matrix3"},
+ {Variant::BASIS,"Basis"},
{Variant::TRANSFORM,"Transform"},
{Variant::COLOR,"Color"},
{Variant::IMAGE,"Image"},
@@ -801,13 +803,13 @@ void GDTokenizerText::_advance() {
{Variant::NODE_PATH,"NodePath"},
{Variant::DICTIONARY,"Dictionary"},
{Variant::ARRAY,"Array"},
- {Variant::RAW_ARRAY,"RawArray"},
- {Variant::INT_ARRAY,"IntArray"},
- {Variant::REAL_ARRAY,"FloatArray"},
- {Variant::STRING_ARRAY,"StringArray"},
- {Variant::VECTOR2_ARRAY,"Vector2Array"},
- {Variant::VECTOR3_ARRAY,"Vector3Array"},
- {Variant::COLOR_ARRAY,"ColorArray"},
+ {Variant::POOL_BYTE_ARRAY,"PoolByteArray"},
+ {Variant::POOL_INT_ARRAY,"PoolIntArray"},
+ {Variant::POOL_REAL_ARRAY,"PoolFloatArray"},
+ {Variant::POOL_STRING_ARRAY,"PoolStringArray"},
+ {Variant::POOL_VECTOR2_ARRAY,"PoolVector2Array"},
+ {Variant::POOL_VECTOR3_ARRAY,"PoolVector3Array"},
+ {Variant::POOL_COLOR_ARRAY,"PoolColorArray"},
{Variant::VARIANT_MAX,NULL},
};
@@ -1057,7 +1059,7 @@ void GDTokenizerText::advance(int p_amount) {
//////////////////////////////////////////////////////////////////////////////////////////////////////
-#define BYTECODE_VERSION 11
+#define BYTECODE_VERSION 12
Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) {
diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h
index b91229ab1e..18e5547d36 100644
--- a/modules/gdscript/gd_tokenizer.h
+++ b/modules/gdscript/gd_tokenizer.h
@@ -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 */
@@ -123,6 +123,7 @@ public:
TK_PERIOD,
TK_QUESTION_MARK,
TK_COLON,
+ TK_DOLLAR,
TK_NEWLINE,
TK_CONST_PI,
TK_ERROR,
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index 95b18cae4d..11bdf783f8 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.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 */
@@ -48,7 +48,7 @@ ResourceFormatSaverGDScript *resource_saver_gd=NULL;
class EditorExportGDScript : public EditorExportPlugin {
- OBJ_TYPE(EditorExportGDScript,EditorExportPlugin);
+ GDCLASS(EditorExportGDScript,EditorExportPlugin);
public:
@@ -138,8 +138,8 @@ static void register_editor_plugin() {
void register_gdscript_types() {
- ObjectTypeDB::register_type<GDScript>();
- ObjectTypeDB::register_virtual_type<GDFunctionState>();
+ ClassDB::register_class<GDScript>();
+ ClassDB::register_virtual_class<GDFunctionState>();
script_language_gd=memnew( GDScriptLanguage );
//script_language_gd->init();
diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h
index aed11cd1d4..5778dfcadc 100644
--- a/modules/gdscript/register_types.h
+++ b/modules/gdscript/register_types.h
@@ -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 */