int GDScriptLanguage::find_function(const String& p_function,const String& p_code) const { GDTokenizerText tokenizer; tokenizer.set_code(p_code); int indent=0; while(tokenizer.get_token()!=GDTokenizer::TK_EOF && tokenizer.get_token()!=GDTokenizer::TK_ERROR) { if (tokenizer.get_token()==GDTokenizer::TK_NEWLINE) { indent=tokenizer.get_token_line_indent(); } if (indent==0 && tokenizer.get_token()==GDTokenizer::TK_PR_FUNCTION && tokenizer.get_token(1)==GDTokenizer::TK_IDENTIFIER) { String identifier = tokenizer.get_token_identifier(1); if (identifier==p_function) { return tokenizer.get_token_line(); } } tokenizer.advance(); } return -1; }
Vector<uint8_t> GDTokenizerBuffer::parse_code_string(const String& p_code) { Vector<uint8_t> buf; Map<StringName,int> identifier_map; HashMap<Variant,int,VariantHasher> constant_map; Map<uint32_t,int> line_map; Vector<uint32_t> token_array; GDTokenizerText tt; tt.set_code(p_code); int line=-1; int col=0; while(true) { if (tt.get_token_line()!=line) { line=tt.get_token_line(); line_map[line]=token_array.size(); } uint32_t token=tt.get_token(); switch(tt.get_token()) { case TK_IDENTIFIER: { StringName id = tt.get_token_identifier(); if (!identifier_map.has(id)) { int idx = identifier_map.size(); identifier_map[id]=idx; } token|=identifier_map[id]<<TOKEN_BITS; } break; case TK_CONSTANT: { Variant c = tt.get_token_constant(); if (!constant_map.has(c)) { int idx = constant_map.size(); constant_map[c]=idx; } token|=constant_map[c]<<TOKEN_BITS; } break; case TK_BUILT_IN_TYPE: { token|=tt.get_token_type()<<TOKEN_BITS; } break; case TK_BUILT_IN_FUNC: { token|=tt.get_token_built_in_func()<<TOKEN_BITS; } break; case TK_NEWLINE: { token|=tt.get_token_line_indent()<<TOKEN_BITS; } break; case TK_ERROR: { ERR_FAIL_V(Vector<uint8_t>()); } break; default: {} }; token_array.push_back(token); if (tt.get_token()==TK_EOF) break; tt.advance(); } //reverse maps Map<int,StringName> rev_identifier_map; for(Map<StringName,int>::Element *E=identifier_map.front();E;E=E->next()) { rev_identifier_map[E->get()]=E->key(); } Map<int,Variant> rev_constant_map; const Variant *K =NULL; while((K=constant_map.next(K))) { rev_constant_map[constant_map[*K]]=*K; } Map<int,uint32_t> rev_line_map; for(Map<uint32_t,int>::Element *E=line_map.front();E;E=E->next()) { rev_line_map[E->get()]=E->key(); } //save header buf.resize(24); buf[0]='G'; buf[1]='D'; buf[2]='S'; buf[3]='C'; encode_uint32(BYTECODE_VERSION,&buf[4]); encode_uint32(identifier_map.size(),&buf[8]); encode_uint32(constant_map.size(),&buf[12]); encode_uint32(line_map.size(),&buf[16]); encode_uint32(token_array.size(),&buf[20]); //save identifiers for(Map<int,StringName>::Element *E=rev_identifier_map.front();E;E=E->next()) { CharString cs = String(E->get()).utf8(); int len = cs.length()+1; int extra = 4-(len%4); if (extra==4) extra=0; uint8_t ibuf[4]; encode_uint32(len+extra,ibuf); for(int i=0;i<4;i++) { buf.push_back(ibuf[i]); } for(int i=0;i<len;i++) { buf.push_back(cs[i]^0xb6); } for(int i=0;i<extra;i++) { buf.push_back(0^0xb6); } } for(Map<int,Variant>::Element *E=rev_constant_map.front();E;E=E->next()) { int len; Error err = encode_variant(E->get(),NULL,len); ERR_FAIL_COND_V(err!=OK,Vector<uint8_t>()); int pos=buf.size(); buf.resize(pos+len); encode_variant(E->get(),&buf[pos],len); } for(Map<int,uint32_t>::Element *E=rev_line_map.front();E;E=E->next()) { uint8_t ibuf[8]; encode_uint32(E->key(),&ibuf[0]); encode_uint32(E->get(),&ibuf[4]); for(int i=0;i<8;i++) buf.push_back(ibuf[i]); } for(int i=0;i<token_array.size();i++) { uint32_t token = token_array[i]; if (token&~TOKEN_MASK) { uint8_t buf4[4]; encode_uint32(token_array[i]|TOKEN_BYTE_MASK,&buf4[0]); for(int j=0;j<4;j++) { buf.push_back(buf4[j]); } } else { buf.push_back(token); } } return buf; }
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; }