summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/config.py7
-rw-r--r--modules/gdscript/gd_compiler.cpp207
-rw-r--r--modules/gdscript/gd_compiler.h6
-rw-r--r--modules/gdscript/gd_editor.cpp211
-rw-r--r--modules/gdscript/gd_function.cpp167
-rw-r--r--modules/gdscript/gd_function.h4
-rw-r--r--modules/gdscript/gd_functions.cpp213
-rw-r--r--modules/gdscript/gd_functions.h6
-rw-r--r--modules/gdscript/gd_parser.cpp845
-rw-r--r--modules/gdscript/gd_parser.h56
-rw-r--r--modules/gdscript/gd_script.cpp95
-rw-r--r--modules/gdscript/gd_script.h12
-rw-r--r--modules/gdscript/gd_tokenizer.cpp54
-rw-r--r--modules/gdscript/gd_tokenizer.h5
-rw-r--r--modules/gdscript/register_types.cpp12
-rw-r--r--modules/gdscript/register_types.h2
16 files changed, 1628 insertions, 274 deletions
diff --git a/modules/gdscript/config.py b/modules/gdscript/config.py
index ea7e83378a..5698a37295 100644
--- a/modules/gdscript/config.py
+++ b/modules/gdscript/config.py
@@ -1,11 +1,8 @@
def can_build(platform):
- return True
+ return True
def configure(env):
- pass
-
-
-
+ pass
diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp
index b75b13551e..398c2cf82a 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;
@@ -1019,7 +1099,72 @@ Error GDCompiler::_parse_block(CodeGen& codegen,const GDParser::BlockNode *p_blo
switch(cf->cf_type) {
-
+ case GDParser::ControlFlowNode::CF_MATCH: {
+ GDParser::MatchNode *match = cf->match;
+
+ GDParser::IdentifierNode *id = memnew(GDParser::IdentifierNode);
+ id->name = "#match_value";
+
+ // var #match_value
+ // copied because there is no _parse_statement :(
+ codegen.add_stack_identifier(id->name, p_stack_level++);
+ codegen.alloc_stack(p_stack_level);
+ new_identifiers++;
+
+ GDParser::OperatorNode *op = memnew(GDParser::OperatorNode);
+ op->op=GDParser::OperatorNode::OP_ASSIGN;
+ op->arguments.push_back(id);
+ op->arguments.push_back(match->val_to_match);
+
+ int ret = _parse_expression(codegen, op, p_stack_level);
+ if (ret < 0) {
+ return ERR_PARSE_ERROR;
+ }
+
+ // break address
+ codegen.opcodes.push_back(GDFunction::OPCODE_JUMP);
+ codegen.opcodes.push_back(codegen.opcodes.size() + 3);
+ int break_addr = codegen.opcodes.size();
+ codegen.opcodes.push_back(GDFunction::OPCODE_JUMP);
+ codegen.opcodes.push_back(0); // break addr
+
+ for (int j = 0; j < match->compiled_pattern_branches.size(); j++) {
+ GDParser::MatchNode::CompiledPatternBranch branch = match->compiled_pattern_branches[j];
+
+ // jump over continue
+ // jump unconditionally
+ // continue address
+ // compile the condition
+ int ret = _parse_expression(codegen, branch.compiled_pattern, p_stack_level);
+ if (ret < 0) {
+ return ERR_PARSE_ERROR;
+ }
+
+ codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF);
+ codegen.opcodes.push_back(ret);
+ codegen.opcodes.push_back(codegen.opcodes.size() + 3);
+ int continue_addr = codegen.opcodes.size();
+ codegen.opcodes.push_back(GDFunction::OPCODE_JUMP);
+ codegen.opcodes.push_back(0);
+
+
+
+ Error err = _parse_block(codegen, branch.body, p_stack_level, p_break_addr, continue_addr);
+ if (err) {
+ return ERR_PARSE_ERROR;
+ }
+
+ codegen.opcodes.push_back(GDFunction::OPCODE_JUMP);
+ codegen.opcodes.push_back(break_addr);
+
+ codegen.opcodes[continue_addr + 1] = codegen.opcodes.size();
+ }
+
+ codegen.opcodes[break_addr + 1] = codegen.opcodes.size();
+
+
+ } break;
+
case GDParser::ControlFlowNode::CF_IF: {
#ifdef DEBUG_ENABLED
@@ -1211,6 +1356,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 +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]);
@@ -1331,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];
@@ -1421,7 +1576,7 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
//funciton and class
if (p_class->name) {
- signature+="::"+String(p_class->name)+"."+String(func_name);;
+ signature+="::"+String(p_class->name)+"."+String(func_name);
} else {
signature+="::"+String(func_name);
}
@@ -1640,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()));
@@ -1653,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) {
@@ -1691,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);
@@ -1723,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;
}
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..114a25feeb 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()) {
@@ -364,11 +364,13 @@ static GDCompletionIdentifier _get_type_from_variant(const Variant& p_variant) {
if (p_variant.get_type()==Variant::OBJECT) {
Object *obj = p_variant;
if (obj) {
- //if (obj->cast_to<GDNativeClass>()) {
- // t.obj_type=obj->cast_to<GDNativeClass>()->get_name();
- // t.value=Variant();
- //} else {
- t.obj_type=obj->get_type();
+ /*
+ if (obj->cast_to<GDNativeClass>()) {
+ t.obj_type=obj->cast_to<GDNativeClass>()->get_name();
+ t.value=Variant();
+ } else {
+ */
+ t.obj_type=obj->get_class();
//}
}
}
@@ -614,10 +616,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 +645,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 +664,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;
@@ -671,7 +673,7 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
if (!script.ends_with(".gd")) {
//not a script, try find the script anyway,
//may have some success
- script=script.basename()+".gd";
+ script=script.get_basename()+".gd";
}
if (FileAccess::exists(script)) {
@@ -940,6 +942,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 +1079,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 +1153,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,14 +1163,14 @@ 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());
if (!script.ends_with(".gd")) {
//not a script, try find the script anyway,
//may have some success
- script=script.basename()+".gd";
+ script=script.get_basename()+".gd";
}
if (FileAccess::exists(script)) {
@@ -1298,26 +1309,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 +1395,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 +1405,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 +1413,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 +1498,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 +1514,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 +1727,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,17 +1763,17 @@ 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()) {
String s = E->get().name;
if (!s.begins_with("autoload/"))
continue;
- // print_line("found "+s);
+ //print_line("found "+s);
String name = s.get_slice("/",1);
result.insert("\"/root/"+name+"\"");
}
@@ -1970,12 +1998,12 @@ 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+"(");
- //else
- // result.insert(E->get().name+"()");
+ if (E->get().arguments.size())
+ result.insert(E->get().name+"(");
+ else
+ result.insert(E->get().name+"()");
}*/
}
break;
@@ -2063,13 +2091,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 +2157,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 +2198,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 +2348,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 +2393,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 +2470,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 +2506,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 +2604,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 +2685,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 +2726,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 +2736,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 +2817,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,14 +2827,14 @@ 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());
if (!script.ends_with(".gd")) {
//not a script, try find the script anyway,
//may have some success
- script=script.basename()+".gd";
+ script=script.get_basename()+".gd";
}
if (FileAccess::exists(script)) {
@@ -2777,7 +2863,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;
}
@@ -2828,7 +2914,7 @@ Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol
Ref<GDNativeClass> gdn = t.value;
if (gdn.is_valid()) {
r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
- r_result.class_name=gdn->get_name();;
+ r_result.class_name=gdn->get_name();
r_result.class_member=p_symbol;
return OK;
@@ -2858,7 +2944,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 +2954,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 +2962,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 +3023,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..51e2c1e2be 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";
}
@@ -331,8 +331,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
#endif
ip+=5;
-
- } continue;
+ continue;
+ }
case OPCODE_EXTENDS_TEST: {
CHECK_SPACE(4);
@@ -395,17 +395,17 @@ 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;
ip+=4;
-
- } continue;
+ continue;
+ }
case OPCODE_SET: {
CHECK_SPACE(3);
@@ -429,7 +429,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
ip+=4;
- } continue;
+ continue;
+ }
case OPCODE_GET: {
CHECK_SPACE(3);
@@ -460,7 +461,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst=ret;
#endif
ip+=4;
- } continue;
+ continue;
+ }
case OPCODE_SET_NAMED: {
CHECK_SPACE(3);
@@ -483,11 +485,12 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
ip+=4;
- } continue;
+ continue;
+ }
case OPCODE_GET_NAMED: {
- CHECK_SPACE(3);
+ CHECK_SPACE(4);
GET_VARIANT_PTR(src,1);
GET_VARIANT_PTR(dst,3);
@@ -518,7 +521,49 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst=ret;
#endif
ip+=4;
- } continue;
+ 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);
@@ -528,8 +573,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = *src;
ip+=3;
-
- } continue;
+ continue;
+ }
case OPCODE_ASSIGN_TRUE: {
CHECK_SPACE(2);
@@ -538,7 +583,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = true;
ip+=2;
- } continue;
+ continue;
+ }
case OPCODE_ASSIGN_FALSE: {
CHECK_SPACE(2);
@@ -547,7 +593,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst = false;
ip+=2;
- } continue;
+ continue;
+ }
case OPCODE_CONSTRUCT: {
CHECK_SPACE(2);
@@ -572,12 +619,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
ip+=4+argc;
//construct a basic type
- } continue;
+ continue;
+ }
case OPCODE_CONSTRUCT_ARRAY: {
CHECK_SPACE(1);
int argc=_code_ptr[ip+1];
- Array array(true); //arrays are always shared
+ Array array; //arrays are always shared
array.resize(argc);
CHECK_SPACE(argc+2);
@@ -592,13 +640,13 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst=array;
ip+=3+argc;
-
- } continue;
+ continue;
+ }
case OPCODE_CONSTRUCT_DICTIONARY: {
CHECK_SPACE(1);
int argc=_code_ptr[ip+1];
- Dictionary dict(true); //arrays are always shared
+ Dictionary dict; //arrays are always shared
CHECK_SPACE(argc*2+2);
@@ -615,8 +663,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
*dst=dict;
ip+=3+argc*2;
-
- } continue;
+ continue;
+ }
case OPCODE_CALL_RETURN:
case OPCODE_CALL: {
@@ -697,8 +745,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
//_call_func(NULL,base,*methodname,ip,argc,p_instance,stack);
ip+=argc+1;
-
- } continue;
+ continue;
+ }
case OPCODE_CALL_BUILT_IN: {
CHECK_SPACE(4);
@@ -735,12 +783,12 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
break;
}
ip+=argc+1;
-
- } continue;
+ continue;
+ }
case OPCODE_CALL_SELF: {
-
- } break;
+ break;
+ }
case OPCODE_CALL_SELF_BASE: {
CHECK_SPACE(2);
@@ -788,7 +836,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 {
@@ -817,8 +865,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
ip+=4+argc;
-
- } continue;
+ continue;
+ }
case OPCODE_YIELD:
case OPCODE_YIELD_SIGNAL: {
@@ -898,8 +946,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
exit_ok=true;
-
- } break;
+ break;
+ }
case OPCODE_YIELD_RESUME: {
CHECK_SPACE(2);
@@ -910,8 +958,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
GET_VARIANT_PTR(result,1);
*result=p_state->result;
ip+=2;
-
- } continue;
+ continue;
+ }
case OPCODE_JUMP: {
CHECK_SPACE(2);
@@ -919,8 +967,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
ERR_BREAK(to<0 || to>_code_size);
ip=to;
-
- } continue;
+ continue;
+ }
case OPCODE_JUMP_IF: {
CHECK_SPACE(3);
@@ -943,7 +991,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
continue;
}
ip+=3;
- } continue;
+ continue;
+ }
case OPCODE_JUMP_IF_NOT: {
CHECK_SPACE(3);
@@ -966,21 +1015,22 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
continue;
}
ip+=3;
- } continue;
+ continue;
+ }
case OPCODE_JUMP_TO_DEF_ARGUMENT: {
CHECK_SPACE(2);
ip=_default_arg_ptr[defarg];
-
- } continue;
+ continue;
+ }
case OPCODE_RETURN: {
CHECK_SPACE(2);
GET_VARIANT_PTR(r,1);
retvalue=*r;
exit_ok=true;
-
- } break;
+ break;
+ }
case OPCODE_ITERATE_BEGIN: {
CHECK_SPACE(8); //space for this an regular iterate
@@ -1010,8 +1060,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
ip+=5; //skip regular iterate which is always next
-
- } continue;
+ continue;
+ }
case OPCODE_ITERATE: {
CHECK_SPACE(4);
@@ -1039,7 +1089,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
ip+=5; //loop again
- } continue;
+ continue;
+ }
case OPCODE_ASSERT: {
CHECK_SPACE(2);
GET_VARIANT_PTR(test,1);
@@ -1065,7 +1116,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
#endif
ip+=2;
- } continue;
+ continue;
+ }
case OPCODE_BREAKPOINT: {
#ifdef DEBUG_ENABLED
if (ScriptDebugger::get_singleton()) {
@@ -1073,7 +1125,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
}
#endif
ip+=1;
- } continue;
+ continue;
+ }
case OPCODE_LINE: {
CHECK_SPACE(2);
@@ -1102,17 +1155,19 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
ScriptDebugger::get_singleton()->line_poll();
}
- } continue;
+ continue;
+ }
case OPCODE_END: {
exit_ok=true;
break;
- } break;
+ }
default: {
err_text="Illegal opcode "+itos(_code_ptr[ip])+" at address "+itos(ip);
- } break;
+ break;
+ }
}
@@ -1435,9 +1490,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 d3f7dcd35f..d0fc241734 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 */
@@ -28,13 +28,14 @@
/*************************************************************************/
#include "gd_functions.h"
#include "math_funcs.h"
-#include "object_type_db.h"
+#include "class_db.h"
#include "reference.h"
#include "gd_script.h"
#include "func_ref.h"
#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,8 +104,12 @@ const char *GDFunctions::get_func_name(Function p_func) {
"load",
"inst2dict",
"dict2inst",
+ "validate_json",
+ "parse_json",
+ "to_json",
"hash",
"Color8",
+ "ColorN",
"print_stack",
"instance_from_id",
};
@@ -154,85 +159,85 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
case MATH_SIN: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::sin(*p_args[0]);
+ r_ret=Math::sin((double)*p_args[0]);
} break;
case MATH_COS: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::cos(*p_args[0]);
+ r_ret=Math::cos((double)*p_args[0]);
} break;
case MATH_TAN: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::tan(*p_args[0]);
+ r_ret=Math::tan((double)*p_args[0]);
} break;
case MATH_SINH: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::sinh(*p_args[0]);
+ r_ret=Math::sinh((double)*p_args[0]);
} break;
case MATH_COSH: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::cosh(*p_args[0]);
+ r_ret=Math::cosh((double)*p_args[0]);
} break;
case MATH_TANH: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::tanh(*p_args[0]);
+ r_ret=Math::tanh((double)*p_args[0]);
} break;
case MATH_ASIN: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::asin(*p_args[0]);
+ r_ret=Math::asin((double)*p_args[0]);
} break;
case MATH_ACOS: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::acos(*p_args[0]);
+ r_ret=Math::acos((double)*p_args[0]);
} break;
case MATH_ATAN: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::atan(*p_args[0]);
+ r_ret=Math::atan((double)*p_args[0]);
} break;
case MATH_ATAN2: {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- r_ret=Math::atan2(*p_args[0],*p_args[1]);
+ r_ret=Math::atan2((double)*p_args[0],(double)*p_args[1]);
} break;
case MATH_SQRT: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::sqrt(*p_args[0]);
+ r_ret=Math::sqrt((double)*p_args[0]);
} break;
case MATH_FMOD: {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- r_ret=Math::fmod(*p_args[0],*p_args[1]);
+ r_ret=Math::fmod((double)*p_args[0],(double)*p_args[1]);
} break;
case MATH_FPOSMOD: {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- r_ret=Math::fposmod(*p_args[0],*p_args[1]);
+ r_ret=Math::fposmod((double)*p_args[0],(double)*p_args[1]);
} break;
case MATH_FLOOR: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::floor(*p_args[0]);
+ r_ret=Math::floor((double)*p_args[0]);
} break;
case MATH_CEIL: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::ceil(*p_args[0]);
+ r_ret=Math::ceil((double)*p_args[0]);
} break;
case MATH_ROUND: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::round(*p_args[0]);
+ r_ret=Math::round((double)*p_args[0]);
} break;
case MATH_ABS: {
VALIDATE_ARG_COUNT(1);
@@ -242,7 +247,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_ret=ABS(i);
} else if (p_args[0]->get_type()==Variant::REAL) {
- real_t r = *p_args[0];
+ double r = *p_args[0];
r_ret=Math::abs(r);
} else {
@@ -274,58 +279,58 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- r_ret=Math::pow(*p_args[0],*p_args[1]);
+ r_ret=Math::pow((double)*p_args[0],(double)*p_args[1]);
} break;
case MATH_LOG: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::log(*p_args[0]);
+ r_ret=Math::log((double)*p_args[0]);
} break;
case MATH_EXP: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::exp(*p_args[0]);
+ r_ret=Math::exp((double)*p_args[0]);
} break;
case MATH_ISNAN: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::is_nan(*p_args[0]);
+ r_ret=Math::is_nan((double)*p_args[0]);
} break;
case MATH_ISINF: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::is_inf(*p_args[0]);
+ r_ret=Math::is_inf((double)*p_args[0]);
} break;
case MATH_EASE: {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- r_ret=Math::ease(*p_args[0],*p_args[1]);
+ r_ret=Math::ease((double)*p_args[0],(double)*p_args[1]);
} break;
case MATH_DECIMALS: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::step_decimals(*p_args[0]);
+ r_ret=Math::step_decimals((double)*p_args[0]);
} break;
case MATH_STEPIFY: {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- r_ret=Math::stepify(*p_args[0],*p_args[1]);
+ r_ret=Math::stepify((double)*p_args[0],(double)*p_args[1]);
} break;
case MATH_LERP: {
VALIDATE_ARG_COUNT(3);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
VALIDATE_ARG_NUM(2);
- r_ret=Math::lerp(*p_args[0],*p_args[1],*p_args[2]);
+ r_ret=Math::lerp((double)*p_args[0],(double)*p_args[1],(double)*p_args[2]);
} break;
case MATH_DECTIME: {
VALIDATE_ARG_COUNT(3);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
VALIDATE_ARG_NUM(2);
- r_ret=Math::dectime(*p_args[0],*p_args[1],*p_args[2]);
+ r_ret=Math::dectime((double)*p_args[0],(double)*p_args[1],(double)*p_args[2]);
} break;
case MATH_RANDOMIZE: {
Math::randomize();
@@ -341,19 +346,19 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
- r_ret=Math::random(*p_args[0],*p_args[1]);
+ r_ret=Math::random((double)*p_args[0],(double)*p_args[1]);
} break;
case MATH_SEED: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- uint32_t seed=*p_args[0];
+ uint64_t seed=*p_args[0];
Math::seed(seed);
r_ret=Variant();
} break;
case MATH_RANDSEED: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- uint32_t seed=*p_args[0];
+ uint64_t seed=*p_args[0];
int ret = Math::rand_from_seed(&seed);
Array reta;
reta.push_back(ret);
@@ -364,22 +369,22 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
case MATH_DEG2RAD: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::deg2rad(*p_args[0]);
+ r_ret=Math::deg2rad((double)*p_args[0]);
} break;
case MATH_RAD2DEG: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::rad2deg(*p_args[0]);
+ r_ret=Math::rad2deg((double)*p_args[0]);
} break;
case MATH_LINEAR2DB: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::linear2db(*p_args[0]);
+ r_ret=Math::linear2db((double)*p_args[0]);
} break;
case MATH_DB2LINEAR: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
- r_ret=Math::db2linear(*p_args[0]);
+ r_ret=Math::db2linear((double)*p_args[0]);
} break;
case LOGIC_MAX: {
VALIDATE_ARG_COUNT(2);
@@ -536,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: {
@@ -550,7 +555,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
String str;
for(int i=0;i<p_arg_count;i++) {
- String os = p_args[i]->operator String();;
+ String os = p_args[i]->operator String();
if (i==0)
str=os;
@@ -668,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) {
@@ -681,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);
}
@@ -689,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;
}
@@ -730,7 +735,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
VALIDATE_ARG_NUM(0);
int count=*p_args[0];
- Array arr(true);
+ Array arr;
if (count<=0) {
r_ret=arr;
return;
@@ -756,7 +761,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
int from=*p_args[0];
int to=*p_args[1];
- Array arr(true);
+ Array arr;
if (from>=to) {
r_ret=arr;
return;
@@ -787,7 +792,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
return;
}
- Array arr(true);
+ Array arr;
if (from>=to && incr>0) {
r_ret=arr;
return;
@@ -846,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]);
@@ -915,7 +921,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
NodePath cp(sname,Vector<StringName>(),false);
- Dictionary d(true);
+ Dictionary d;
d["@subpath"]=cp;
d["@path"]=p->path;
@@ -1024,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);
@@ -1061,6 +1118,36 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_ret=color;
} break;
+ case COLORN: {
+
+ if (p_arg_count<1) {
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=1;
+ r_ret=Variant();
+ return;
+ }
+
+ if (p_arg_count>2) {
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument=2;
+ r_ret=Variant();
+ return;
+ }
+
+ if (p_args[0]->get_type()!=Variant::STRING) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_ret=Variant();
+ } else {
+ Color color = Color::named(*p_args[0]);
+ if (p_arg_count==2) {
+ VALIDATE_ARG_NUM(1);
+ color.a=*p_args[1];
+ }
+ r_ret=color;
+ }
+
+ } break;
case PRINT_STACK: {
@@ -1475,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;
@@ -1510,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"));
@@ -1522,6 +1627,12 @@ MethodInfo GDFunctions::get_info(Function p_func) {
mi.return_val.type=Variant::COLOR;
return mi;
} break;
+ case COLORN: {
+
+ MethodInfo mi("ColorN",PropertyInfo(Variant::STRING,"name"),PropertyInfo(Variant::REAL,"alpha"));
+ mi.return_val.type=Variant::COLOR;
+ return mi;
+ } break;
case PRINT_STACK: {
MethodInfo mi("print_stack");
diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h
index f444bb3b5b..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,8 +97,12 @@ public:
RESOURCE_LOAD,
INST2DICT,
DICT2INST,
+ VALIDATE_JSON,
+ PARSE_JSON,
+ TO_JSON,
HASH,
COLOR8,
+ COLORN,
PRINT_STACK,
INSTANCE_FROM_ID,
FUNC_MAX
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp
index 434f918355..34c39c8024 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 */
@@ -225,8 +225,8 @@ bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& ide
GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_allow_assign,bool p_parsing_constant) {
-// Vector<Node*> expressions;
-// Vector<OperatorNode::Operator> operators;
+ //Vector<Node*> expressions;
+ //Vector<OperatorNode::Operator> operators;
Vector<Expression> expression;
@@ -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,17 +632,18 @@ 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;
+ case GDTokenizer::TK_OP_BIT_INVERT: e.op=OperatorNode::OP_BIT_INVERT; break;
default: {}
}
@@ -631,6 +724,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
};
Node *key=NULL;
+ Set<Variant> keys;
DictExpect expecting=DICT_EXPECT_KEY;
@@ -726,6 +820,16 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
return NULL;
expecting=DICT_EXPECT_COMMA;
+ if (key->type == GDParser::Node::TYPE_CONSTANT) {
+ Variant const& keyName = static_cast<const GDParser::ConstantNode*>(key)->value;
+
+ if (keys.has(keyName)) {
+ _set_error("Duplicate key found in Dictionary literal");
+ return NULL;
+ }
+ keys.insert(keyName);
+ }
+
DictionaryNode::Pair pair;
pair.key=key;
pair.value=value;
@@ -939,8 +1043,8 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
case GDTokenizer::TK_OP_ASSIGN_MUL: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_MUL ; break;
case GDTokenizer::TK_OP_ASSIGN_DIV: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_DIV ; break;
case GDTokenizer::TK_OP_ASSIGN_MOD: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_MOD ; break;
- case GDTokenizer::TK_OP_ASSIGN_SHIFT_LEFT: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_SHIFT_LEFT; ; break;
- case GDTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_SHIFT_RIGHT; ; break;
+ case GDTokenizer::TK_OP_ASSIGN_SHIFT_LEFT: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_SHIFT_LEFT; break;
+ case GDTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_SHIFT_RIGHT; break;
case GDTokenizer::TK_OP_ASSIGN_BIT_AND: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_BIT_AND ; break;
case GDTokenizer::TK_OP_ASSIGN_BIT_OR: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_BIT_OR ; break;
case GDTokenizer::TK_OP_ASSIGN_BIT_XOR: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_BIT_XOR ; break;
@@ -995,6 +1099,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;
@@ -1223,7 +1328,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) {
//reduce constant array expression
ConstantNode *cn = alloc_node<ConstantNode>();
- Array arr(!p_to_const);
+ Array arr;
//print_line("mk array "+itos(!p_to_const));
arr.resize(an->elements.size());
for(int i=0;i<an->elements.size();i++) {
@@ -1258,7 +1363,7 @@ GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) {
//reduce constant array expression
ConstantNode *cn = alloc_node<ConstantNode>();
- Dictionary dict(!p_to_const);
+ Dictionary dict;
for(int i=0;i<dn->elements.size();i++) {
ConstantNode *key_c = static_cast<ConstantNode*>(dn->elements[i].key);
ConstantNode *value_c = static_cast<ConstantNode*>(dn->elements[i].value);
@@ -1476,6 +1581,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 +1626,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)
@@ -1575,6 +1690,541 @@ bool GDParser::_recover_from_completion() {
return true;
}
+GDParser::PatternNode *GDParser::_parse_pattern(bool p_static)
+{
+
+ PatternNode *pattern = alloc_node<PatternNode>();
+
+ GDTokenizer::Token token = tokenizer->get_token();
+ if (error_set)
+ return NULL;
+
+ if (token == GDTokenizer::TK_EOF) {
+ return NULL;
+ }
+
+ switch (token) {
+ // array
+ case GDTokenizer::TK_BRACKET_OPEN: {
+ tokenizer->advance();
+ pattern->pt_type = GDParser::PatternNode::PT_ARRAY;
+ while (true) {
+
+ if (tokenizer->get_token() == GDTokenizer::TK_BRACKET_CLOSE) {
+ tokenizer->advance();
+ break;
+ }
+
+ if (tokenizer->get_token() == GDTokenizer::TK_PERIOD && tokenizer->get_token(1) == GDTokenizer::TK_PERIOD) {
+ // match everything
+ tokenizer->advance(2);
+ PatternNode *sub_pattern = alloc_node<PatternNode>();
+ sub_pattern->pt_type = GDParser::PatternNode::PT_IGNORE_REST;
+ pattern->array.push_back(sub_pattern);
+ if (tokenizer->get_token() == GDTokenizer::TK_COMMA && tokenizer->get_token(1) == GDTokenizer::TK_BRACKET_CLOSE) {
+ tokenizer->advance(2);
+ break;
+ } else if (tokenizer->get_token() == GDTokenizer::TK_BRACKET_CLOSE) {
+ tokenizer->advance(1);
+ break;
+ } else {
+ _set_error("'..' pattern only allowed at the end of an array pattern");
+ return NULL;
+ }
+ }
+
+ PatternNode *sub_pattern = _parse_pattern(p_static);
+ if (!sub_pattern) {
+ return NULL;
+ }
+
+ pattern->array.push_back(sub_pattern);
+
+ if (tokenizer->get_token() == GDTokenizer::TK_COMMA) {
+ tokenizer->advance();
+ continue;
+ } else if (tokenizer->get_token() == GDTokenizer::TK_BRACKET_CLOSE) {
+ tokenizer->advance();
+ break;
+ } else {
+ _set_error("Not a valid pattern");
+ return NULL;
+ }
+ }
+ } break;
+ // bind
+ case GDTokenizer::TK_PR_VAR: {
+ tokenizer->advance();
+ pattern->pt_type = GDParser::PatternNode::PT_BIND;
+ pattern->bind = tokenizer->get_token_identifier();
+ tokenizer->advance();
+ } break;
+ // dictionary
+ case GDTokenizer::TK_CURLY_BRACKET_OPEN: {
+ tokenizer->advance();
+ pattern->pt_type = GDParser::PatternNode::PT_DICTIONARY;
+ while (true) {
+
+ if (tokenizer->get_token() == GDTokenizer::TK_CURLY_BRACKET_CLOSE) {
+ tokenizer->advance();
+ break;
+ }
+
+ if (tokenizer->get_token() == GDTokenizer::TK_PERIOD && tokenizer->get_token(1) == GDTokenizer::TK_PERIOD) {
+ // match everything
+ tokenizer->advance(2);
+ PatternNode *sub_pattern = alloc_node<PatternNode>();
+ sub_pattern->pt_type = PatternNode::PT_IGNORE_REST;
+ pattern->array.push_back(sub_pattern);
+ if (tokenizer->get_token() == GDTokenizer::TK_COMMA && tokenizer->get_token(1) == GDTokenizer::TK_CURLY_BRACKET_CLOSE) {
+ tokenizer->advance(2);
+ break;
+ } else if (tokenizer->get_token() == GDTokenizer::TK_CURLY_BRACKET_CLOSE) {
+ tokenizer->advance(1);
+ break;
+ } else {
+ _set_error("'..' pattern only allowed at the end of an dictionary pattern");
+ return NULL;
+ }
+ }
+
+ Node *key = _parse_and_reduce_expression(pattern, p_static);
+ if (!key) {
+ _set_error("Not a valid key in pattern");
+ return NULL;
+ }
+
+ if (key->type != GDParser::Node::TYPE_CONSTANT) {
+ _set_error("Not a constant expression as key");
+ return NULL;
+ }
+
+ if (tokenizer->get_token() == GDTokenizer::TK_COLON) {
+ tokenizer->advance();
+
+ PatternNode *value = _parse_pattern(p_static);
+ if (!value) {
+ _set_error("Expected pattern in dictionary value");
+ return NULL;
+ }
+
+ pattern->dictionary.insert(static_cast<ConstantNode*>(key), value);
+ } else {
+ pattern->dictionary.insert(static_cast<ConstantNode*>(key), NULL);
+ }
+
+
+ if (tokenizer->get_token() == GDTokenizer::TK_COMMA) {
+ tokenizer->advance();
+ continue;
+ } else if (tokenizer->get_token() == GDTokenizer::TK_CURLY_BRACKET_CLOSE) {
+ tokenizer->advance();
+ break;
+ } else {
+ _set_error("Not a valid pattern");
+ return NULL;
+ }
+ }
+ } break;
+ case GDTokenizer::TK_WILDCARD: {
+ tokenizer->advance();
+ pattern->pt_type = PatternNode::PT_WILDCARD;
+ } break;
+ // all the constants like strings and numbers
+ default: {
+ Node *value = _parse_and_reduce_expression(pattern, p_static);
+ if (error_set) {
+ return NULL;
+ }
+
+ if (value->type != Node::TYPE_IDENTIFIER && value->type != Node::TYPE_CONSTANT) {
+ _set_error("Only constant expressions or variables allowed in a pattern");
+ return NULL;
+ }
+
+ pattern->pt_type = PatternNode::PT_CONSTANT;
+ pattern->constant = value;
+ } break;
+ }
+
+ return pattern;
+}
+
+void GDParser::_parse_pattern_block(BlockNode *p_block, Vector<PatternBranchNode*> &p_branches, bool p_static)
+{
+ int indent_level = tab_level.back()->get();
+
+ while (true) {
+
+ while (tokenizer->get_token() == GDTokenizer::TK_NEWLINE && _parse_newline());
+
+ // GDTokenizer::Token token = tokenizer->get_token();
+ if (error_set)
+ return;
+
+ if (indent_level > tab_level.back()->get()) {
+ return; // go back a level
+ }
+
+ if (pending_newline!=-1) {
+ pending_newline=-1;
+ }
+
+ PatternBranchNode *branch = alloc_node<PatternBranchNode>();
+
+ branch->patterns.push_back(_parse_pattern(p_static));
+ if (!branch->patterns[0]) {
+ return;
+ }
+
+ while (tokenizer->get_token() == GDTokenizer::TK_COMMA) {
+ tokenizer->advance();
+ branch->patterns.push_back(_parse_pattern(p_static));
+ if (!branch->patterns[branch->patterns.size() - 1]) {
+ return;
+ }
+ }
+
+ if(!_enter_indent_block()) {
+ _set_error("Expected block in pattern branch");
+ return;
+ }
+
+ branch->body = alloc_node<BlockNode>();
+ branch->body->parent_block = p_block;
+ p_block->sub_blocks.push_back(branch->body);
+ current_block = branch->body;
+
+ _parse_block(branch->body, p_static);
+
+ current_block = p_block;
+
+ p_branches.push_back(branch);
+ }
+}
+
+
+void GDParser::_generate_pattern(PatternNode *p_pattern, Node *p_node_to_match, Node *&p_resulting_node, Map<StringName, Node*> &p_bindings)
+{
+ switch (p_pattern->pt_type) {
+ case PatternNode::PT_CONSTANT: {
+
+ // typecheck
+ BuiltInFunctionNode *typeof_node = alloc_node<BuiltInFunctionNode>();
+ typeof_node->function = GDFunctions::TYPE_OF;
+
+ OperatorNode *typeof_match_value = alloc_node<OperatorNode>();
+ typeof_match_value->op = OperatorNode::OP_CALL;
+ typeof_match_value->arguments.push_back(typeof_node);
+ typeof_match_value->arguments.push_back(p_node_to_match);
+
+ OperatorNode *typeof_pattern_value = alloc_node<OperatorNode>();
+ typeof_pattern_value->op = OperatorNode::OP_CALL;
+ typeof_pattern_value->arguments.push_back(typeof_node);
+ typeof_pattern_value->arguments.push_back(p_pattern->constant);
+
+ OperatorNode *type_comp = alloc_node<OperatorNode>();
+ type_comp->op = OperatorNode::OP_EQUAL;
+ type_comp->arguments.push_back(typeof_match_value);
+ type_comp->arguments.push_back(typeof_pattern_value);
+
+
+ // comare the actual values
+ OperatorNode *value_comp = alloc_node<OperatorNode>();
+ value_comp->op = OperatorNode::OP_EQUAL;
+ value_comp->arguments.push_back(p_pattern->constant);
+ value_comp->arguments.push_back(p_node_to_match);
+
+
+ OperatorNode *comparison = alloc_node<OperatorNode>();
+ comparison->op = OperatorNode::OP_AND;
+ comparison->arguments.push_back(type_comp);
+ comparison->arguments.push_back(value_comp);
+
+ p_resulting_node = comparison;
+
+ } break;
+ case PatternNode::PT_BIND: {
+ p_bindings[p_pattern->bind] = p_node_to_match;
+
+ // a bind always matches
+ ConstantNode *true_value = alloc_node<ConstantNode>();
+ true_value->value = Variant(true);
+ p_resulting_node = true_value;
+ } break;
+ case PatternNode::PT_ARRAY: {
+
+ bool open_ended = false;
+
+ if (p_pattern->array.size() > 0) {
+ if (p_pattern->array[p_pattern->array.size() - 1]->pt_type == PatternNode::PT_IGNORE_REST) {
+ open_ended = true;
+ }
+ }
+
+ // typeof(value_to_match) == TYPE_ARRAY && value_to_match.size() >= length
+ // typeof(value_to_match) == TYPE_ARRAY && value_to_match.size() == length
+
+ {
+ // typecheck
+ BuiltInFunctionNode *typeof_node = alloc_node<BuiltInFunctionNode>();
+ typeof_node->function = GDFunctions::TYPE_OF;
+
+ OperatorNode *typeof_match_value = alloc_node<OperatorNode>();
+ typeof_match_value->op = OperatorNode::OP_CALL;
+ typeof_match_value->arguments.push_back(typeof_node);
+ typeof_match_value->arguments.push_back(p_node_to_match);
+
+ IdentifierNode *typeof_array = alloc_node<IdentifierNode>();
+ typeof_array->name = "TYPE_ARRAY";
+
+ OperatorNode *type_comp = alloc_node<OperatorNode>();
+ type_comp->op = OperatorNode::OP_EQUAL;
+ type_comp->arguments.push_back(typeof_match_value);
+ type_comp->arguments.push_back(typeof_array);
+
+
+ // size
+ ConstantNode *length = alloc_node<ConstantNode>();
+ length->value = Variant(open_ended ? p_pattern->array.size() - 1 : p_pattern->array.size());
+
+ OperatorNode *call = alloc_node<OperatorNode>();
+ call->op = OperatorNode::OP_CALL;
+ call->arguments.push_back(p_node_to_match);
+
+ IdentifierNode *size = alloc_node<IdentifierNode>();
+ size->name = "size";
+ call->arguments.push_back(size);
+
+ OperatorNode *length_comparison = alloc_node<OperatorNode>();
+ length_comparison->op = open_ended ? OperatorNode::OP_GREATER_EQUAL : OperatorNode::OP_EQUAL;
+ length_comparison->arguments.push_back(call);
+ length_comparison->arguments.push_back(length);
+
+ OperatorNode *type_and_length_comparison = alloc_node<OperatorNode>();
+ type_and_length_comparison->op = OperatorNode::OP_AND;
+ type_and_length_comparison->arguments.push_back(type_comp);
+ type_and_length_comparison->arguments.push_back(length_comparison);
+
+ p_resulting_node = type_and_length_comparison;
+ }
+
+
+
+ for (int i = 0; i < p_pattern->array.size(); i++) {
+ PatternNode *pattern = p_pattern->array[i];
+
+ Node *condition = NULL;
+
+ ConstantNode *index = alloc_node<ConstantNode>();
+ index->value = Variant(i);
+
+ OperatorNode *indexed_value = alloc_node<OperatorNode>();
+ indexed_value->op = OperatorNode::OP_INDEX;
+ indexed_value->arguments.push_back(p_node_to_match);
+ indexed_value->arguments.push_back(index);
+
+ _generate_pattern(pattern, indexed_value, condition, p_bindings);
+
+ // concatenate all the patterns with &&
+ OperatorNode *and_node = alloc_node<OperatorNode>();
+ and_node->op = OperatorNode::OP_AND;
+ and_node->arguments.push_back(p_resulting_node);
+ and_node->arguments.push_back(condition);
+
+ p_resulting_node = and_node;
+ }
+
+
+ } break;
+ case PatternNode::PT_DICTIONARY: {
+
+ bool open_ended = false;
+
+ if (p_pattern->array.size() > 0) {
+ open_ended = true;
+ }
+
+ // typeof(value_to_match) == TYPE_DICTIONARY && value_to_match.size() >= length
+ // typeof(value_to_match) == TYPE_DICTIONARY && value_to_match.size() == length
+
+
+ {
+ // typecheck
+ BuiltInFunctionNode *typeof_node = alloc_node<BuiltInFunctionNode>();
+ typeof_node->function = GDFunctions::TYPE_OF;
+
+ OperatorNode *typeof_match_value = alloc_node<OperatorNode>();
+ typeof_match_value->op = OperatorNode::OP_CALL;
+ typeof_match_value->arguments.push_back(typeof_node);
+ typeof_match_value->arguments.push_back(p_node_to_match);
+
+ IdentifierNode *typeof_dictionary = alloc_node<IdentifierNode>();
+ typeof_dictionary->name = "TYPE_DICTIONARY";
+
+ OperatorNode *type_comp = alloc_node<OperatorNode>();
+ type_comp->op = OperatorNode::OP_EQUAL;
+ type_comp->arguments.push_back(typeof_match_value);
+ type_comp->arguments.push_back(typeof_dictionary);
+
+ // size
+ ConstantNode *length = alloc_node<ConstantNode>();
+ length->value = Variant(open_ended ? p_pattern->dictionary.size() - 1 : p_pattern->dictionary.size());
+
+ OperatorNode *call = alloc_node<OperatorNode>();
+ call->op = OperatorNode::OP_CALL;
+ call->arguments.push_back(p_node_to_match);
+
+ IdentifierNode *size = alloc_node<IdentifierNode>();
+ size->name = "size";
+ call->arguments.push_back(size);
+
+ OperatorNode *length_comparison = alloc_node<OperatorNode>();
+ length_comparison->op = open_ended ? OperatorNode::OP_GREATER_EQUAL : OperatorNode::OP_EQUAL;
+ length_comparison->arguments.push_back(call);
+ length_comparison->arguments.push_back(length);
+
+ OperatorNode *type_and_length_comparison = alloc_node<OperatorNode>();
+ type_and_length_comparison->op = OperatorNode::OP_AND;
+ type_and_length_comparison->arguments.push_back(type_comp);
+ type_and_length_comparison->arguments.push_back(length_comparison);
+
+ p_resulting_node = type_and_length_comparison;
+ }
+
+
+
+ for (Map<ConstantNode*, PatternNode*>::Element *e = p_pattern->dictionary.front(); e; e = e->next()) {
+
+ Node *condition = NULL;
+
+ // chech for has, then for pattern
+
+ IdentifierNode *has = alloc_node<IdentifierNode>();
+ has->name = "has";
+
+ OperatorNode *has_call = alloc_node<OperatorNode>();
+ has_call->op = OperatorNode::OP_CALL;
+ has_call->arguments.push_back(p_node_to_match);
+ has_call->arguments.push_back(has);
+ has_call->arguments.push_back(e->key());
+
+
+ if (e->value()) {
+
+ OperatorNode *indexed_value = alloc_node<OperatorNode>();
+ indexed_value->op = OperatorNode::OP_INDEX;
+ indexed_value->arguments.push_back(p_node_to_match);
+ indexed_value->arguments.push_back(e->key());
+
+ _generate_pattern(e->value(), indexed_value, condition, p_bindings);
+
+ OperatorNode *has_and_pattern = alloc_node<OperatorNode>();
+ has_and_pattern->op = OperatorNode::OP_AND;
+ has_and_pattern->arguments.push_back(has_call);
+ has_and_pattern->arguments.push_back(condition);
+
+ condition = has_and_pattern;
+
+ } else {
+ condition = has_call;
+ }
+
+
+
+ // concatenate all the patterns with &&
+ OperatorNode *and_node = alloc_node<OperatorNode>();
+ and_node->op = OperatorNode::OP_AND;
+ and_node->arguments.push_back(p_resulting_node);
+ and_node->arguments.push_back(condition);
+
+ p_resulting_node = and_node;
+ }
+
+ } break;
+ case PatternNode::PT_IGNORE_REST:
+ case PatternNode::PT_WILDCARD: {
+ // simply generate a `true`
+ ConstantNode *true_value = alloc_node<ConstantNode>();
+ true_value->value = Variant(true);
+ p_resulting_node = true_value;
+ } break;
+ default: {
+
+ } break;
+ }
+}
+
+void GDParser::_transform_match_statment(BlockNode *p_block, MatchNode *p_match_statement)
+{
+ IdentifierNode *id = alloc_node<IdentifierNode>();
+ id->name = "#match_value";
+
+ for (int i = 0; i < p_match_statement->branches.size(); i++) {
+
+ PatternBranchNode *branch = p_match_statement->branches[i];
+
+ MatchNode::CompiledPatternBranch compiled_branch;
+ compiled_branch.compiled_pattern = NULL;
+
+ Map<StringName, Node*> binding;
+
+ for (int j = 0; j < branch->patterns.size(); j++) {
+ PatternNode *pattern = branch->patterns[j];
+
+ Map<StringName, Node*> bindings;
+ Node *resulting_node;
+ _generate_pattern(pattern, id, resulting_node, bindings);
+
+ if (!binding.empty() && !bindings.empty()) {
+ _set_error("Multipatterns can't contain bindings");
+ return;
+ } else {
+ binding = bindings;
+ }
+
+ if (compiled_branch.compiled_pattern) {
+ OperatorNode *or_node = alloc_node<OperatorNode>();
+ or_node->op = OperatorNode::OP_OR;
+ or_node->arguments.push_back(compiled_branch.compiled_pattern);
+ or_node->arguments.push_back(resulting_node);
+
+ compiled_branch.compiled_pattern = or_node;
+ } else {
+ // single pattern | first one
+ compiled_branch.compiled_pattern = resulting_node;
+ }
+
+ }
+
+
+ // prepare the body ...hehe
+ for (Map<StringName, Node*>::Element *e = binding.front(); e; e = e->next()) {
+ LocalVarNode *local_var = alloc_node<LocalVarNode>();
+ local_var->name = e->key();
+ local_var->assign = e->value();
+
+
+ IdentifierNode *id = alloc_node<IdentifierNode>();
+ id->name = local_var->name;
+
+ OperatorNode *op = alloc_node<OperatorNode>();
+ op->op=OperatorNode::OP_ASSIGN;
+ op->arguments.push_back(id);
+ op->arguments.push_back(local_var->assign);
+
+ branch->body->statements.push_front(op);
+ branch->body->statements.push_front(local_var);
+ }
+
+ compiled_branch.body = branch->body;
+
+
+ p_match_statement->compiled_pattern_branches.push_back(compiled_branch);
+ }
+
+}
+
void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
int indent_level = tab_level.back()->get();
@@ -1658,6 +2308,24 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
}
StringName n = tokenizer->get_token_identifier();
tokenizer->advance();
+ if (current_function){
+ for (int i=0;i<current_function->arguments.size();i++){
+ if (n == current_function->arguments[i]){
+ _set_error("Variable '"+String(n)+"' already defined in the scope (at line: "+itos(current_function->line)+").");
+ return;
+ }
+ }
+ }
+ BlockNode *check_block = p_block;
+ while (check_block){
+ for (int i=0;i<check_block->variables.size();i++){
+ if (n == check_block->variables[i]){
+ _set_error("Variable '"+String(n)+"' already defined in the scope (at line: "+itos(check_block->variable_lines[i])+").");
+ return;
+ }
+ }
+ check_block = check_block->parent_block;
+ }
p_block->variables.push_back(n); //line?
p_block->variable_lines.push_back(tokenizer->get_token_line());
@@ -1900,6 +2568,64 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
return;
}
+ if (container->type==Node::TYPE_OPERATOR) {
+
+ OperatorNode* op = static_cast<OperatorNode*>(container);
+ if (op->op==OperatorNode::OP_CALL && op->arguments[0]->type==Node::TYPE_BUILT_IN_FUNCTION && static_cast<BuiltInFunctionNode*>(op->arguments[0])->function==GDFunctions::GEN_RANGE) {
+ //iterating a range, so see if range() can be optimized without allocating memory, by replacing it by vectors (which can work as iterable too!)
+
+ Vector<Node*> args;
+ Vector<double> constants;
+
+ bool constant=true;
+
+ for(int i=1;i<op->arguments.size();i++) {
+ args.push_back(op->arguments[i]);
+ if (constant && op->arguments[i]->type==Node::TYPE_CONSTANT) {
+ ConstantNode *c = static_cast<ConstantNode*>(op->arguments[i]);
+ if (c->value.get_type()==Variant::REAL || c->value.get_type()==Variant::INT) {
+ constants.push_back(c->value);
+ } else {
+ constant=false;
+ }
+ }
+ }
+
+ if (args.size()>0 || args.size()<4) {
+
+ if (constant) {
+
+ ConstantNode *cn = alloc_node<ConstantNode>();
+ switch(args.size()) {
+ case 1: cn->value=constants[0]; break;
+ case 2: cn->value=Vector2(constants[0],constants[1]); break;
+ case 3: cn->value=Vector3(constants[0],constants[1],constants[2]); break;
+ }
+ container=cn;
+ } else {
+ OperatorNode *on = alloc_node<OperatorNode>();
+ on->op=OperatorNode::OP_CALL;
+
+ TypeNode *tn = alloc_node<TypeNode>();
+ on->arguments.push_back(tn);
+
+ switch(args.size()) {
+ case 1: tn->vtype=Variant::REAL; break;
+ case 2: tn->vtype=Variant::VECTOR2; break;
+ case 3: tn->vtype=Variant::VECTOR3; break;
+ }
+
+ for(int i=0;i<args.size();i++) {
+ on->arguments.push_back(args[i]);
+ }
+
+ container=on;
+ }
+ }
+ }
+
+ }
+
ControlFlowNode *cf_for = alloc_node<ControlFlowNode>();
cf_for->cf_type=ControlFlowNode::CF_FOR;
@@ -1917,7 +2643,14 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
}
current_block=cf_for->body;
+
+ // this is for checking variable for redefining
+ // inside this _parse_block
+ cf_for->body->variables.push_back(id->name);
+ cf_for->body->variable_lines.push_back(id->line);
_parse_block(cf_for->body,p_static);
+ cf_for->body->variables.remove(0);
+ cf_for->body->variable_lines.remove(0);
current_block=p_block;
if (error_set)
@@ -1979,6 +2712,46 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
} break;
+ case GDTokenizer::TK_CF_MATCH: {
+
+ tokenizer->advance();
+
+ MatchNode *match_node = alloc_node<MatchNode>();
+
+ Node *val_to_match = _parse_and_reduce_expression(p_block, p_static);
+
+ if (!val_to_match) {
+ if (_recover_from_completion()) {
+ break;
+ }
+ return;
+ }
+
+ match_node->val_to_match = val_to_match;
+
+ if (!_enter_indent_block()) {
+ _set_error("Expected indented pattern matching block after 'match'");
+ return;
+ }
+
+ BlockNode *compiled_branches = alloc_node<BlockNode>();
+ compiled_branches->parent_block = p_block;
+ compiled_branches->parent_class = p_block->parent_class;
+
+ p_block->sub_blocks.push_back(compiled_branches);
+
+ _parse_pattern_block(compiled_branches, match_node->branches, p_static);
+
+ _transform_match_statment(compiled_branches, match_node);
+
+ ControlFlowNode *match_cf_node = alloc_node<ControlFlowNode>();
+ match_cf_node->cf_type = ControlFlowNode::CF_MATCH;
+ match_cf_node->match = match_node;
+
+ p_block->statements.push_back(match_cf_node);
+
+ _end_statement();
+ } break;
case GDTokenizer::TK_PR_ASSERT: {
tokenizer->advance();
@@ -2554,17 +3327,41 @@ void GDParser::_parse_class(ClassNode *p_class) {
current_export.type=type;
current_export.usage|=PROPERTY_USAGE_SCRIPT_VARIABLE;
tokenizer->advance();
+
+ String hint_prefix ="";
+
+ if(type == Variant::ARRAY && tokenizer->get_token()==GDTokenizer::TK_COMMA) {
+ tokenizer->advance();
+
+ while(tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_TYPE) {
+ type = tokenizer->get_token_type();
+
+ tokenizer->advance();
+
+ if(type == Variant::ARRAY) {
+ hint_prefix += itos(Variant::ARRAY)+":";
+ if (tokenizer->get_token()==GDTokenizer::TK_COMMA) {
+ tokenizer->advance();
+ }
+ } else {
+ hint_prefix += itos(type);
+ break;
+ }
+ }
+ }
+
if (tokenizer->get_token()==GDTokenizer::TK_COMMA) {
// hint expected next!
tokenizer->advance();
- switch(current_export.type) {
+
+ switch(type) {
case Variant::INT: {
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) {
@@ -2913,13 +3710,20 @@ void GDParser::_parse_class(ClassNode *p_class) {
return;
} break;
}
-
+
+ }
+ if(current_export.type == Variant::ARRAY && !hint_prefix.empty()) {
+ if(current_export.hint) {
+ hint_prefix += "/"+itos(current_export.hint);
+ }
+ current_export.hint_string=hint_prefix+":"+current_export.hint_string;
+ current_export.hint=PROPERTY_HINT_NONE;
}
} 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 +3941,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();
}
}
}
@@ -3375,7 +4179,16 @@ void GDParser::_parse_class(ClassNode *p_class) {
} break;
-
+
+ case GDTokenizer::TK_CONSTANT: {
+ if(tokenizer->get_token_constant().get_type() == Variant::STRING) {
+ tokenizer->advance();
+ // Ignore
+ } else {
+ _set_error(String()+"Unexpected constant of type: "+Variant::get_type_name(tokenizer->get_token_constant().get_type()));
+ return;
+ }
+ } break;
default: {
diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h
index 75653e0916..7968bf85df 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,
@@ -257,6 +258,44 @@ public:
Vector<Node*> arguments;
OperatorNode() { type=TYPE_OPERATOR; }
};
+
+
+ struct PatternNode : public Node {
+
+ enum PatternType {
+ PT_CONSTANT,
+ PT_BIND,
+ PT_DICTIONARY,
+ PT_ARRAY,
+ PT_IGNORE_REST,
+ PT_WILDCARD
+ };
+
+ PatternType pt_type;
+
+ Node *constant;
+ StringName bind;
+ Map<ConstantNode*, PatternNode*> dictionary;
+ Vector<PatternNode*> array;
+
+ };
+
+ struct PatternBranchNode : public Node {
+ Vector<PatternNode*> patterns;
+ BlockNode *body;
+ };
+
+ struct MatchNode : public Node {
+ Node *val_to_match;
+ Vector<PatternBranchNode*> branches;
+
+ struct CompiledPatternBranch {
+ Node *compiled_pattern;
+ BlockNode *body;
+ };
+
+ Vector<CompiledPatternBranch> compiled_pattern_branches;
+ };
struct ControlFlowNode : public Node {
enum CFType {
@@ -266,13 +305,16 @@ public:
CF_SWITCH,
CF_BREAK,
CF_CONTINUE,
- CF_RETURN
+ CF_RETURN,
+ CF_MATCH
};
CFType cf_type;
Vector<Node*> arguments;
BlockNode *body;
BlockNode *body_else;
+
+ MatchNode *match;
ControlFlowNode *_else; //used for if
ControlFlowNode() { type=TYPE_CONTROL_FLOW; cf_type=CF_IF; body=NULL; body_else=NULL;}
@@ -375,6 +417,7 @@ public:
enum CompletionType {
COMPLETION_NONE,
COMPLETION_BUILT_IN_TYPE_CONSTANT,
+ COMPLETION_GET_NODE,
COMPLETION_FUNCTION,
COMPLETION_IDENTIFIER,
COMPLETION_PARENT_FUNCTION,
@@ -450,6 +493,15 @@ private:
Node* _reduce_expression(Node *p_node,bool p_to_const=false);
Node* _parse_and_reduce_expression(Node *p_parent,bool p_static,bool p_reduce_const=false,bool p_allow_assign=false);
+
+
+
+ PatternNode *_parse_pattern(bool p_static);
+ void _parse_pattern_block(BlockNode *p_block, Vector<PatternBranchNode*> &p_branches, bool p_static);
+ void _transform_match_statment(BlockNode *p_block, MatchNode *p_match_statement);
+ void _generate_pattern(PatternNode *p_pattern, Node *p_node_to_match, Node *&p_resulting_node, Map<StringName, Node*> &p_bindings);
+
+
void _parse_block(BlockNode *p_block,bool p_static);
void _parse_extends(ClassNode *p_class);
void _parse_class(ClassNode *p_class);
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp
index 0ea10950df..89df7e962a 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
}
@@ -145,6 +160,8 @@ Variant GDScript::_new(const Variant** p_args,int p_argcount,Variant::CallError&
_baseptr=_baseptr->_base;
}
+ ERR_FAIL_COND_V(_baseptr->native.is_null(), Variant());
+
if (_baseptr->native.ptr()) {
owner=_baseptr->native->instance();
} else {
@@ -341,9 +358,11 @@ bool GDScript::get_property_default_value(const StringName& p_property, Variant
#ifdef TOOLS_ENABLED
- //for (const Map<StringName,Variant>::Element *I=member_default_values.front();I;I=I->next()) {
- // print_line("\t"+String(String(I->key())+":"+String(I->get())));
- //}
+ /*
+ for (const Map<StringName,Variant>::Element *I=member_default_values.front();I;I=I->next()) {
+ print_line("\t"+String(String(I->key())+":"+String(I->get())));
+ }
+ */
const Map<StringName,Variant>::Element *E=member_default_values_cache.find(p_property);
if (E) {
r_value=E->get();
@@ -388,12 +407,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 +424,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 {
@@ -513,7 +541,7 @@ bool GDScript::_update_exports() {
}
}
- members_cache.clear();;
+ members_cache.clear();
member_default_values_cache.clear();
for(int i=0;i<c->variables.size();i++) {
@@ -596,8 +624,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 +787,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 +866,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 +876,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 +1459,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 +1521,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 +1537,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);
}
@@ -1820,7 +1864,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script>& p_script,bool p_sof
void GDScriptLanguage::frame() {
- // print_line("calls: "+itos(calls));
+ //print_line("calls: "+itos(calls));
calls=0;
#ifdef DEBUG_ENABLED
@@ -1894,6 +1938,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"for",
"pass",
"return",
+ "match",
"while",
"remote",
"sync",
@@ -1940,7 +1985,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!
@@ -2026,7 +2071,7 @@ bool ResourceFormatLoaderGDScript::handles_type(const String& p_type) const {
String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const {
- String el = p_path.extension().to_lower();
+ String el = p_path.get_extension().to_lower();
if (el=="gd" || el=="gdc" || el=="gde")
return "GDScript";
return "";
diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h
index 051e80634f..4d3baa5bc0 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;
@@ -139,7 +139,7 @@ protected:
void _get_property_list(List<PropertyInfo> *p_properties) const;
Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error);
-// void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount);
+ //void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount);
static void _bind_methods();
public:
@@ -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..5be2a2beae 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 */
@@ -85,6 +85,7 @@ const char* GDTokenizer::token_names[TK_MAX]={
"continue",
"pass",
"return",
+"match",
"func",
"class",
"extends",
@@ -118,6 +119,7 @@ const char* GDTokenizer::token_names[TK_MAX]={
"':'",
"'\\n'",
"PI",
+"_",
"Error",
"EOF",
"Cursor"};
@@ -460,6 +462,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);
@@ -510,9 +515,11 @@ void GDTokenizerText::_advance() {
if (GETCHAR(1)=='=') {
_make_token(TK_OP_ASSIGN_ADD);
INCPOS(1);
- //} else if (GETCHAR(1)=='+') {
- // _make_token(TK_OP_PLUS_PLUS);
- // INCPOS(1);
+ /*
+ } else if (GETCHAR(1)=='+') {
+ _make_token(TK_OP_PLUS_PLUS);
+ INCPOS(1);
+ */
} else {
_make_token(TK_OP_ADD);
}
@@ -523,9 +530,11 @@ void GDTokenizerText::_advance() {
if (GETCHAR(1)=='=') {
_make_token(TK_OP_ASSIGN_SUB);
INCPOS(1);
- //} else if (GETCHAR(1)=='-') {
- // _make_token(TK_OP_MINUS_MINUS);
- // INCPOS(1);
+ /*
+ } else if (GETCHAR(1)=='-') {
+ _make_token(TK_OP_MINUS_MINUS);
+ INCPOS(1);
+ */
} else {
_make_token(TK_OP_SUB);
}
@@ -728,14 +737,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 +794,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 +809,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},
};
@@ -888,9 +896,11 @@ void GDTokenizerText::_advance() {
{TK_CF_BREAK,"break"},
{TK_CF_CONTINUE,"continue"},
{TK_CF_RETURN,"return"},
+ {TK_CF_MATCH, "match"},
{TK_CF_PASS,"pass"},
{TK_SELF,"self"},
{TK_CONST_PI,"PI"},
+ {TK_WILDCARD,"_"},
{TK_ERROR,NULL}
};
@@ -1057,7 +1067,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..5d955ff1ae 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 */
@@ -92,6 +92,7 @@ public:
TK_CF_CONTINUE,
TK_CF_PASS,
TK_CF_RETURN,
+ TK_CF_MATCH,
TK_PR_FUNCTION,
TK_PR_CLASS,
TK_PR_EXTENDS,
@@ -123,8 +124,10 @@ public:
TK_PERIOD,
TK_QUESTION_MARK,
TK_COLON,
+ TK_DOLLAR,
TK_NEWLINE,
TK_CONST_PI,
+ TK_WILDCARD,
TK_ERROR,
TK_EOF,
TK_CURSOR, //used for code completion
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index 95b18cae4d..051d1d85cd 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:
@@ -100,7 +100,7 @@ public:
if (err==OK) {
fae->store_buffer(file.ptr(),file.size());
- p_path=p_path.basename()+".gde";
+ p_path=p_path.get_basename()+".gde";
}
memdelete(fae);
@@ -111,7 +111,7 @@ public:
} else {
- p_path=p_path.basename()+".gdc";
+ p_path=p_path.get_basename()+".gdc";
return file;
}
}
@@ -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 */