diff options
Diffstat (limited to 'modules/gdscript')
| -rw-r--r-- | modules/gdscript/config.py | 7 | ||||
| -rw-r--r-- | modules/gdscript/gd_compiler.cpp | 207 | ||||
| -rw-r--r-- | modules/gdscript/gd_compiler.h | 6 | ||||
| -rw-r--r-- | modules/gdscript/gd_editor.cpp | 211 | ||||
| -rw-r--r-- | modules/gdscript/gd_function.cpp | 167 | ||||
| -rw-r--r-- | modules/gdscript/gd_function.h | 4 | ||||
| -rw-r--r-- | modules/gdscript/gd_functions.cpp | 213 | ||||
| -rw-r--r-- | modules/gdscript/gd_functions.h | 6 | ||||
| -rw-r--r-- | modules/gdscript/gd_parser.cpp | 845 | ||||
| -rw-r--r-- | modules/gdscript/gd_parser.h | 56 | ||||
| -rw-r--r-- | modules/gdscript/gd_script.cpp | 95 | ||||
| -rw-r--r-- | modules/gdscript/gd_script.h | 12 | ||||
| -rw-r--r-- | modules/gdscript/gd_tokenizer.cpp | 54 | ||||
| -rw-r--r-- | modules/gdscript/gd_tokenizer.h | 5 | ||||
| -rw-r--r-- | modules/gdscript/register_types.cpp | 12 | ||||
| -rw-r--r-- | modules/gdscript/register_types.h | 2 |
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 */ |