Error GDScriptLanguage::complete_keyword(const String& p_code, int p_line, const String& p_base_path, const String& p_base, List<String>* r_options) { GDParser p; Error err = p.parse(p_code,p_base_path); // don't care much about error I guess const GDParser::Node* root = p.get_parse_tree(); ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,ERR_INVALID_DATA); const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root); List<String> indices; Vector<String> spl = p_base.split("."); for(int i=0;i<spl.size()-1;i++) { indices.push_back(spl[i]); } if (_parse_completion_class(p_base,cl,p_line,r_options,indices.front())) return OK; //and the globals x_x? for(Map<StringName,int>::Element *E=globals.front();E;E=E->next()) { if (!indices.empty()) { if (String(E->key())==indices.front()->get()) { _parse_completion_variant(global_array[E->get()],r_options,indices.front()->next()); return OK; } } else { r_options->push_back(E->key()); } } return OK; }
bool GDScriptLanguage::validate(const String& p_script, int &r_line_error,int &r_col_error,String& r_test_error, const String& p_path,List<String> *r_functions) const { GDParser parser; Error err = parser.parse(p_script,p_path.get_base_dir(),true); if (err) { r_line_error=parser.get_error_line(); r_col_error=parser.get_error_column(); r_test_error=parser.get_error(); return false; } else { const GDParser::Node *root = parser.get_parse_tree(); ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,false); const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root); Map<int,String> funcs; for(int i=0;i<cl->functions.size();i++) { funcs[cl->functions[i]->line]=cl->functions[i]->name; } for(int i=0;i<cl->static_functions.size();i++) { funcs[cl->static_functions[i]->line]=cl->static_functions[i]->name; } for (Map<int,String>::Element *E=funcs.front();E;E=E->next()) { r_functions->push_back(E->get()+":"+itos(E->key())); } } return true; }
MainLoop* test(TestType p_test) { List<String> cmdlargs = OS::get_singleton()->get_cmdline_args(); if (cmdlargs.empty()) { //try editor! return NULL; } String test = cmdlargs.back()->get(); FileAccess *fa = FileAccess::open(test,FileAccess::READ); if (!fa) { ERR_EXPLAIN("Could not open file: "+test); ERR_FAIL_V(NULL); } Vector<uint8_t> buf; int flen = fa->get_len(); buf.resize(fa->get_len()+1); fa->get_buffer(&buf[0],flen); buf[flen]=0; String code; code.parse_utf8((const char*)&buf[0]); Vector<String> lines; int last=0; for(int i=0;i<=code.length();i++) { if (code[i]=='\n' || code[i]==0) { lines.push_back(code.substr(last,i-last)); last=i+1; } } if (p_test==TEST_TOKENIZER) { GDTokenizerText tk; tk.set_code(code); int line=-1; while(tk.get_token()!=GDTokenizer::TK_EOF) { String text; if (tk.get_token()==GDTokenizer::TK_IDENTIFIER) text="'"+tk.get_token_identifier()+"' (identifier)"; else if (tk.get_token()==GDTokenizer::TK_CONSTANT) { Variant c= tk.get_token_constant(); if (c.get_type()==Variant::STRING) text="\""+String(c)+"\""; else text=c; text=text+" ("+Variant::get_type_name(c.get_type())+" constant)"; } else if (tk.get_token()==GDTokenizer::TK_ERROR) text="ERROR: "+tk.get_token_error(); else if (tk.get_token()==GDTokenizer::TK_NEWLINE) text="newline ("+itos(tk.get_token_line())+") + indent: "+itos(tk.get_token_line_indent()); else if (tk.get_token()==GDTokenizer::TK_BUILT_IN_FUNC) text="'"+String(GDFunctions::get_func_name(tk.get_token_built_in_func()))+"' (built-in function)"; else text=tk.get_token_name(tk.get_token()); if (tk.get_token_line()!=line) { int from=line+1; line = tk.get_token_line();; for(int i=from;i<=line;i++) { int l=i-1; if (l>=0 && l<lines.size()) { print_line("\n"+itos(i)+": "+lines[l]+"\n"); } } } print_line("\t("+itos(tk.get_token_column())+"): "+text); tk.advance(); } } if (p_test==TEST_PARSER) { GDParser parser; Error err = parser.parse(code); if (err) { print_line("Parse Error:\n"+itos(parser.get_error_line())+":"+itos(parser.get_error_column())+":"+parser.get_error()); memdelete(fa); return NULL; } const GDParser::Node* root = parser.get_parse_tree(); ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,NULL); const GDParser::ClassNode *cnode=static_cast<const GDParser::ClassNode*>(root); _parser_show_class(cnode,0,lines); } if (p_test==TEST_COMPILER) { GDParser parser; Error err = parser.parse(code); if (err) { print_line("Parse Error:\n"+itos(parser.get_error_line())+":"+itos(parser.get_error_column())+":"+parser.get_error()); memdelete(fa); return NULL; } GDScript *script = memnew( GDScript ); GDCompiler gdc; err = gdc.compile(&parser,script); if (err) { print_line("Compile Error:\n"+itos(gdc.get_error_line())+":"+itos(gdc.get_error_column())+":"+gdc.get_error()); memdelete(script); return NULL; } Ref<GDScript> gds =Ref<GDScript>( script ); Ref<GDScript> current=gds; while(current.is_valid()) { print_line("** CLASS **"); _disassemble_class(current,lines); current=current->get_base(); } } else if (p_test==TEST_BYTECODE) { Vector<uint8_t> buf = GDTokenizerBuffer::parse_code_string(code); String dst = test.basename()+".gdc"; FileAccess *fw = FileAccess::open(dst,FileAccess::WRITE); fw->store_buffer(buf.ptr(),buf.size()); memdelete(fw); } #if 0 Parser parser; Error err = parser.parse(code); if (err) { print_line("error:"+itos(parser.get_error_line())+":"+itos(parser.get_error_column())+":"+parser.get_error()); } else { print_line("Parse O-K!"); } #endif memdelete(fa); return NULL; }
Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base_path, Object*p_owner, List<String>* r_options, String &r_call_hint) { /* bugs: a[0].<complete> does not work functions should end in ( when completing virtuals, ask for full back */ //print_line( p_code.replace(String::chr(0xFFFF),"<cursor>")); GDParser p; Error err = p.parse(p_code,p_base_path); bool isfunction=false; Set<String> options; GDCompletionContext context; context._class=p.get_completion_class(); context.block=p.get_completion_block(); context.function=p.get_completion_function(); context.base=p_owner; context.base_path=p_base_path; switch(p.get_completion_type()) { case GDParser::COMPLETION_NONE: { print_line("No completion"); } break; case GDParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: { print_line("Built in type constant"); List<StringName> constants; Variant::get_numeric_constants_for_type(p.get_completion_built_in_constant(),&constants); for(List<StringName>::Element *E=constants.front();E;E=E->next()) { options.insert(E->get().operator String()); } } break; case GDParser::COMPLETION_FUNCTION: isfunction=true; case GDParser::COMPLETION_IDENTIFIER: { _find_identifiers(context,p.get_completion_line(),isfunction,options); } break; case GDParser::COMPLETION_PARENT_FUNCTION: { print_line("parent function"); } break; case GDParser::COMPLETION_METHOD: isfunction=true; case GDParser::COMPLETION_INDEX: { const GDParser::Node *node = p.get_completion_node(); if (node->type!=GDParser::Node::TYPE_OPERATOR) break; GDCompletionIdentifier t; if (_guess_expression_type(context,static_cast<const GDParser::OperatorNode *>(node)->arguments[0],p.get_completion_line(),t)) { if (t.type==Variant::OBJECT && t.obj_type!=StringName()) { if (t.value.get_type()) { Object *obj=t.value; if (obj) { GDScript *scr = obj->cast_to<GDScript>(); while (scr) { if (!isfunction) { for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) { options.insert(E->key()); } } for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) { options.insert(E->key()); } if (scr->get_base().is_valid()) scr=scr->get_base().ptr(); else scr=NULL; } } } if (!isfunction) { ObjectTypeDB::get_integer_constant_list(t.obj_type,r_options); } List<MethodInfo> mi; ObjectTypeDB::get_method_list(t.obj_type,&mi); for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) { if (E->get().name.begins_with("_")) continue; if (E->get().arguments.size()) options.insert(E->get().name+"("); else options.insert(E->get().name+"()"); } } else { if (t.value.get_type()==Variant::NIL) { Variant::CallError ce; t.value=Variant::construct(t.type,NULL,0,ce); } if (!isfunction) { List<PropertyInfo> pl; t.value.get_property_list(&pl); for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) { if (E->get().name.find("/")==-1) options.insert(E->get().name); } } List<MethodInfo> mi; t.value.get_method_list(&mi); for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) { if (E->get().arguments.size()) options.insert(E->get().name+"("); else options.insert(E->get().name+"()"); } } } } break; case GDParser::COMPLETION_CALL_ARGUMENTS: { _find_call_arguments(context,p.get_completion_node(),p.get_completion_line(),p.get_completion_argument_index(),options,r_call_hint); } break; } for(Set<String>::Element *E=options.front();E;E=E->next()) { r_options->push_back(E->get()); } return OK; }