diff options
Diffstat (limited to 'modules/gdscript')
| -rw-r--r-- | modules/gdscript/gd_compiler.cpp | 81 | ||||
| -rw-r--r-- | modules/gdscript/gd_compiler.h | 2 | ||||
| -rw-r--r-- | modules/gdscript/gd_editor.cpp | 41 | ||||
| -rw-r--r-- | modules/gdscript/gd_function.cpp | 119 | ||||
| -rw-r--r-- | modules/gdscript/gd_functions.cpp | 72 | ||||
| -rw-r--r-- | modules/gdscript/gd_parser.cpp | 675 | ||||
| -rw-r--r-- | modules/gdscript/gd_parser.h | 52 | ||||
| -rw-r--r-- | modules/gdscript/gd_script.cpp | 27 | ||||
| -rw-r--r-- | modules/gdscript/gd_script.h | 2 | ||||
| -rw-r--r-- | modules/gdscript/gd_tokenizer.cpp | 26 | ||||
| -rw-r--r-- | modules/gdscript/gd_tokenizer.h | 4 | ||||
| -rw-r--r-- | modules/gdscript/register_types.cpp | 11 |
12 files changed, 968 insertions, 144 deletions
diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp index 7483af298..398c2cf82 100644 --- a/modules/gdscript/gd_compiler.cpp +++ b/modules/gdscript/gd_compiler.cpp @@ -1099,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 @@ -1420,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]; @@ -1510,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); } @@ -1729,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())); diff --git a/modules/gdscript/gd_compiler.h b/modules/gdscript/gd_compiler.h index dd211a852..eb6079e8e 100644 --- a/modules/gdscript/gd_compiler.h +++ b/modules/gdscript/gd_compiler.h @@ -93,7 +93,7 @@ class GDCompiler { //int get_identifier_pos(const StringName& p_dentifier) const; - HashMap<Variant,int,VariantHasher> constant_map; + HashMap<Variant,int,VariantHasher,VariantComparator> constant_map; Map<StringName,int> name_map; int get_name_map_pos(const StringName& p_identifier) { diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp index 00b080190..9dd41847d 100644 --- a/modules/gdscript/gd_editor.cpp +++ b/modules/gdscript/gd_editor.cpp @@ -28,7 +28,7 @@ /*************************************************************************/ #include "gd_script.h" #include "gd_compiler.h" -#include "globals.h" +#include "global_config.h" #include "os/file_access.h" void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const { @@ -323,6 +323,16 @@ void GDScriptLanguage::get_public_constants(List<Pair<String,Variant> > *p_const pi.first="PI"; pi.second=Math_PI; p_constants->push_back(pi); + + Pair<String, Variant> infinity; + infinity.first = "INF"; + infinity.second = Math_INF; + p_constants->push_back(infinity); + + Pair<String, Variant> nan; + nan.first = "NAN"; + nan.second = Math_NAN; + p_constants->push_back(nan); } String GDScriptLanguage::make_function(const String& p_class,const String& p_name,const PoolStringArray& p_args) const { @@ -364,10 +374,12 @@ 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 { + /* + if (obj->cast_to<GDNativeClass>()) { + t.obj_type=obj->cast_to<GDNativeClass>()->get_name(); + t.value=Variant(); + } else { + */ t.obj_type=obj->get_class(); //} } @@ -671,7 +683,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)) { @@ -1168,7 +1180,7 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const 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)) { @@ -1771,7 +1783,7 @@ static void _find_type_arguments(GDCompletionContext& context,const GDParser::No 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+"\""); } @@ -1998,10 +2010,10 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No List<MethodInfo> 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; @@ -2643,6 +2655,7 @@ Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol switch(p.get_completion_type()) { + case GDParser::COMPLETION_GET_NODE: case GDParser::COMPLETION_NONE: { } break; case GDParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: { @@ -2832,7 +2845,7 @@ Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol 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)) { @@ -2912,7 +2925,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; diff --git a/modules/gdscript/gd_function.cpp b/modules/gdscript/gd_function.cpp index 665998860..0c72f6d18 100644 --- a/modules/gdscript/gd_function.cpp +++ b/modules/gdscript/gd_function.cpp @@ -171,7 +171,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a if (p_state) { //use existing (supplied) state (yielded) stack=(Variant*)p_state->stack.ptr(); - call_args=(Variant**)&p_state->stack[sizeof(Variant)*p_state->stack_size]; + call_args=(Variant**)stack + sizeof(Variant)*p_state->stack_size; line=p_state->line; ip=p_state->ip; alloca_size=p_state->stack.size(); @@ -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); @@ -404,8 +404,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a *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,7 +485,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } ip+=4; - } continue; + continue; + } case OPCODE_GET_NAMED: { @@ -518,7 +521,8 @@ 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); @@ -540,7 +544,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } #endif ip+=3; - } continue; + continue; + } case OPCODE_GET_MEMBER: { CHECK_SPACE(3); @@ -557,8 +562,8 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a } #endif ip+=3; - - } continue; + continue; + } case OPCODE_ASSIGN: { CHECK_SPACE(3); @@ -568,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); @@ -578,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); @@ -587,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); @@ -612,7 +619,8 @@ 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); @@ -632,8 +640,8 @@ 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); @@ -655,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: { @@ -717,7 +725,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a err.argument-=1; } } - } if (methodstr=="free") { + } else if (methodstr=="free") { if (err.error==Variant::CallError::CALL_ERROR_INVALID_METHOD) { @@ -737,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); @@ -775,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); @@ -857,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: { @@ -938,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); @@ -950,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); @@ -959,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); @@ -983,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); @@ -1006,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 @@ -1050,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); @@ -1079,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); @@ -1105,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()) { @@ -1113,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); @@ -1142,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; + } } @@ -1475,8 +1490,8 @@ Variant GDFunctionState::resume(const Variant& p_arg) { void GDFunctionState::_bind_methods() { - ClassDB::bind_method(_MD("resume:Variant","arg"),&GDFunctionState::resume,DEFVAL(Variant())); - ClassDB::bind_method(_MD("is_valid"),&GDFunctionState::is_valid); + ClassDB::bind_method(D_METHOD("resume:Variant","arg"),&GDFunctionState::resume,DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("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_functions.cpp b/modules/gdscript/gd_functions.cpp index 1c41b2e73..d0fc24173 100644 --- a/modules/gdscript/gd_functions.cpp +++ b/modules/gdscript/gd_functions.cpp @@ -28,7 +28,7 @@ /*************************************************************************/ #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" @@ -159,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); @@ -247,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 { @@ -279,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(); @@ -346,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); @@ -369,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); @@ -555,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; diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp index 6aed7c949..5147ccd63 100644 --- a/modules/gdscript/gd_parser.cpp +++ b/modules/gdscript/gd_parser.cpp @@ -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; @@ -375,6 +375,22 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ constant->value=Math_PI; tokenizer->advance(); expr=constant; + } + else if (tokenizer->get_token() == GDTokenizer::TK_CONST_INF) { + + //constant defined by tokenizer + ConstantNode *constant = alloc_node<ConstantNode>(); + constant->value = Math_INF; + tokenizer->advance(); + expr = constant; + } + else if (tokenizer->get_token() == GDTokenizer::TK_CONST_NAN) { + + //constant defined by tokenizer + ConstantNode *constant = alloc_node<ConstantNode>(); + constant->value = Math_NAN; + tokenizer->advance(); + expr = constant; } else if (tokenizer->get_token()==GDTokenizer::TK_PR_PRELOAD) { //constant defined by tokenizer @@ -386,21 +402,42 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ tokenizer->advance(); String path; + bool found_constant = false; bool valid = false; + ConstantNode *cn; + Node *subexpr = _parse_and_reduce_expression(p_parent, p_static); if (subexpr) { if (subexpr->type == Node::TYPE_CONSTANT) { - ConstantNode *cn = static_cast<ConstantNode*>(subexpr); - if (cn->value.get_type() == Variant::STRING) { - valid = true; - path = (String) cn->value; + cn = static_cast<ConstantNode*>(subexpr); + found_constant = true; + } + if (subexpr->type == Node::TYPE_IDENTIFIER) { + IdentifierNode *in = static_cast<IdentifierNode*>(subexpr); + Vector<ClassNode::Constant> ce = current_class->constant_expressions; + + // Try to find the constant expression by the identifier + for(int i=0; i < ce.size(); ++i){ + if(ce[i].identifier == in->name) { + if(ce[i].expression->type == Node::TYPE_CONSTANT) { + cn = static_cast<ConstantNode*>(ce[i].expression); + found_constant = true; + } + } } } + + if (found_constant && cn->value.get_type() == Variant::STRING) { + valid = true; + path = (String) cn->value; + } } + if (!valid) { _set_error("expected string constant as 'preload' argument."); return NULL; } + if (!path.is_abs_path() && base_path!="") path=base_path+"/"+path; path = path.replace("///","//").simplify_path(); @@ -643,7 +680,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_ 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: {} } @@ -724,6 +761,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; @@ -819,6 +857,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; @@ -1032,8 +1080,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; @@ -1679,6 +1727,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(); @@ -1762,6 +2345,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()); @@ -2013,7 +2614,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { Vector<Node*> args; Vector<double> constants; - bool constant=true; + bool constant=false; for(int i=1;i<op->arguments.size();i++) { args.push_back(op->arguments[i]); @@ -2021,13 +2622,14 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) { 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; + constant=true; } + } else { + constant=false; } } - if (args.size()>0 || args.size()<4) { + if (args.size()>0 && args.size()<4) { if (constant) { @@ -2079,7 +2681,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) @@ -2141,6 +2750,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(); diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h index e8f5f0f98..7968bf85d 100644 --- a/modules/gdscript/gd_parser.h +++ b/modules/gdscript/gd_parser.h @@ -258,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 { @@ -267,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;} @@ -452,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 0b81780b0..4e72bc39a 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -27,7 +27,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "gd_script.h" -#include "globals.h" +#include "global_config.h" #include "global_constants.h" #include "gd_compiler.h" #include "os/file_access.h" @@ -63,7 +63,7 @@ bool GDNativeClass::_get(const StringName& p_name,Variant &r_ret) const { void GDNativeClass::_bind_methods() { - ClassDB::bind_method(_MD("new"),&GDNativeClass::_new); + ClassDB::bind_method(D_METHOD("new"),&GDNativeClass::_new); } @@ -160,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 { @@ -356,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(); @@ -537,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++) { @@ -785,7 +789,7 @@ void GDScript::_bind_methods() { ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo(Variant::OBJECT,"new")); - ClassDB::bind_method(_MD("get_as_byte_code"),&GDScript::get_as_byte_code); + ClassDB::bind_method(D_METHOD("get_as_byte_code"),&GDScript::get_as_byte_code); } @@ -1513,6 +1517,8 @@ void GDScriptLanguage::init() { } _add_global(StaticCString::create("PI"),Math_PI); + _add_global(StaticCString::create("INF"),Math_INF); + _add_global(StaticCString::create("NAN"),Math_NAN); //populate native classes @@ -1860,7 +1866,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 @@ -1905,6 +1911,8 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "bool", "null", "PI", + "INF", + "NAN", "self", "true", // functions @@ -1934,6 +1942,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { "for", "pass", "return", + "match", "while", "remote", "sync", @@ -2066,7 +2075,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 960b06f3f..4d3baa5bc 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -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: diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp index 30ac98829..54b9624e8 100644 --- a/modules/gdscript/gd_tokenizer.cpp +++ b/modules/gdscript/gd_tokenizer.cpp @@ -85,6 +85,7 @@ const char* GDTokenizer::token_names[TK_MAX]={ "continue", "pass", "return", +"match", "func", "class", "extends", @@ -118,6 +119,9 @@ const char* GDTokenizer::token_names[TK_MAX]={ "':'", "'\\n'", "PI", +"_", +"INF", +"NAN", "Error", "EOF", "Cursor"}; @@ -513,9 +517,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); } @@ -526,9 +532,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); } @@ -890,9 +898,13 @@ 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_CONST_INF,"INF"}, + {TK_CONST_NAN,"NAN"}, {TK_ERROR,NULL} }; @@ -1161,7 +1173,7 @@ Vector<uint8_t> GDTokenizerBuffer::parse_code_string(const String& p_code) { Map<StringName,int> identifier_map; - HashMap<Variant,int,VariantHasher> constant_map; + HashMap<Variant,int,VariantHasher,VariantComparator> constant_map; Map<uint32_t,int> line_map; Vector<uint32_t> token_array; diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h index 18e5547d3..1e9eda794 100644 --- a/modules/gdscript/gd_tokenizer.h +++ b/modules/gdscript/gd_tokenizer.h @@ -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, @@ -126,6 +127,9 @@ public: TK_DOLLAR, TK_NEWLINE, TK_CONST_PI, + TK_WILDCARD, + TK_CONST_INF, + TK_CONST_NAN, 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 11bdf783f..db47ee43c 100644 --- a/modules/gdscript/register_types.cpp +++ b/modules/gdscript/register_types.cpp @@ -38,7 +38,7 @@ GDScriptLanguage *script_language_gd=NULL; ResourceFormatLoaderGDScript *resource_loader_gd=NULL; ResourceFormatSaverGDScript *resource_saver_gd=NULL; - +#if 0 #ifdef TOOLS_ENABLED #include "tools/editor/editor_import_export.h" @@ -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; } } @@ -135,7 +135,7 @@ static void register_editor_plugin() { #endif - +#endif void register_gdscript_types() { ClassDB::register_class<GDScript>(); @@ -148,11 +148,12 @@ void register_gdscript_types() { ResourceLoader::add_resource_format_loader(resource_loader_gd); resource_saver_gd=memnew( ResourceFormatSaverGDScript ); ResourceSaver::add_resource_format_saver(resource_saver_gd); - +#if 0 #ifdef TOOLS_ENABLED EditorNode::add_init_callback(register_editor_plugin); #endif +#endif } void unregister_gdscript_types() { |
