You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-04 12:00:25 +00:00
-moved script to modules
This commit is contained in:
7
modules/gdscript/SCsub
Normal file
7
modules/gdscript/SCsub
Normal file
@@ -0,0 +1,7 @@
|
||||
Import('env')
|
||||
|
||||
env.add_source_files(env.modules_sources,"*.cpp")
|
||||
|
||||
Export('env')
|
||||
|
||||
|
||||
11
modules/gdscript/config.py
Normal file
11
modules/gdscript/config.py
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
def can_build(platform):
|
||||
return True
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
1531
modules/gdscript/gd_compiler.cpp
Normal file
1531
modules/gdscript/gd_compiler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
181
modules/gdscript/gd_compiler.h
Normal file
181
modules/gdscript/gd_compiler.h
Normal file
@@ -0,0 +1,181 @@
|
||||
/*************************************************************************/
|
||||
/* gd_compiler.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#ifndef GD_COMPILER_H
|
||||
#define GD_COMPILER_H
|
||||
|
||||
#include "gd_parser.h"
|
||||
#include "gd_script.h"
|
||||
|
||||
|
||||
class GDCompiler {
|
||||
|
||||
const GDParser *parser;
|
||||
struct CodeGen {
|
||||
|
||||
|
||||
GDScript *script;
|
||||
const GDParser::ClassNode *class_node;
|
||||
const GDParser::FunctionNode *function_node;
|
||||
|
||||
|
||||
bool debug_stack;
|
||||
|
||||
|
||||
List< Map<StringName,int> > stack_id_stack;
|
||||
Map<StringName,int> stack_identifiers;
|
||||
|
||||
List<GDFunction::StackDebug> stack_debug;
|
||||
List< Map<StringName,int> > block_identifier_stack;
|
||||
Map<StringName,int> block_identifiers;
|
||||
|
||||
|
||||
void add_stack_identifier(const StringName& p_id,int p_stackpos) {
|
||||
|
||||
stack_identifiers[p_id]=p_stackpos;
|
||||
if (debug_stack) {
|
||||
|
||||
block_identifiers[p_id]=p_stackpos;
|
||||
GDFunction::StackDebug sd;
|
||||
sd.added=true;
|
||||
sd.line=current_line;
|
||||
sd.identifier=p_id;
|
||||
sd.pos=p_stackpos;
|
||||
stack_debug.push_back(sd);
|
||||
}
|
||||
}
|
||||
|
||||
void push_stack_identifiers() {
|
||||
|
||||
stack_id_stack.push_back( stack_identifiers );
|
||||
if (debug_stack) {
|
||||
|
||||
block_identifier_stack.push_back(block_identifiers);
|
||||
block_identifiers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void pop_stack_identifiers() {
|
||||
|
||||
stack_identifiers = stack_id_stack.back()->get();
|
||||
stack_id_stack.pop_back();
|
||||
|
||||
if (debug_stack) {
|
||||
for (Map<StringName,int>::Element *E=block_identifiers.front();E;E=E->next()) {
|
||||
|
||||
GDFunction::StackDebug sd;
|
||||
sd.added=false;
|
||||
sd.identifier=E->key();
|
||||
sd.line=current_line;
|
||||
sd.pos=E->get();
|
||||
stack_debug.push_back(sd);
|
||||
}
|
||||
block_identifiers=block_identifier_stack.back()->get();
|
||||
block_identifier_stack.pop_back();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// int get_identifier_pos(const StringName& p_dentifier) const;
|
||||
HashMap<Variant,int,VariantHasher> constant_map;
|
||||
Map<StringName,int> name_map;
|
||||
|
||||
int get_name_map_pos(const StringName& p_identifier) {
|
||||
|
||||
int ret;
|
||||
if (!name_map.has(p_identifier)) {
|
||||
ret=name_map.size();
|
||||
name_map[p_identifier]=ret;
|
||||
} else {
|
||||
ret=name_map[p_identifier];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int get_constant_pos(const Variant& p_constant) {
|
||||
|
||||
|
||||
if (constant_map.has(p_constant))
|
||||
return constant_map[p_constant];
|
||||
int pos = constant_map.size();
|
||||
constant_map[p_constant]=pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
Vector<int> opcodes;
|
||||
void alloc_stack(int p_level) { if (p_level >= stack_max) stack_max=p_level+1; }
|
||||
void alloc_call(int p_params) { if (p_params >= call_max) call_max=p_params; }
|
||||
|
||||
int current_line;
|
||||
int stack_max;
|
||||
int call_max;
|
||||
};
|
||||
|
||||
#if 0
|
||||
void _create_index(const GDParser::OperatorNode *on);
|
||||
void _create_call(const GDParser::OperatorNode *on);
|
||||
|
||||
|
||||
int _parse_expression(const GDParser::Node *p_expr,CodeGen& codegen);
|
||||
void _parse_block(GDParser::BlockNode *p_block);
|
||||
void _parse_function(GDParser::FunctionNode *p_func);
|
||||
Ref<GDScript> _parse_class(GDParser::ClassNode *p_class);
|
||||
#endif
|
||||
|
||||
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);
|
||||
bool _create_binary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level);
|
||||
|
||||
//int _parse_subexpression(CodeGen& codegen,const GDParser::BlockNode *p_block,const GDParser::Node *p_expression);
|
||||
int _parse_assign_right_expression(CodeGen& codegen,const GDParser::OperatorNode *p_expression, int p_stack_level);
|
||||
int _parse_expression(CodeGen& codegen,const GDParser::Node *p_expression, int p_stack_level,bool p_root=false);
|
||||
Error _parse_block(CodeGen& codegen,const GDParser::BlockNode *p_block,int p_stack_level=0,int p_break_addr=-1,int p_continue_addr=-1);
|
||||
Error _parse_function(GDScript *p_script,const GDParser::ClassNode *p_class,const GDParser::FunctionNode *p_func);
|
||||
Error _parse_class(GDScript *p_script,GDScript *p_owner,const GDParser::ClassNode *p_class);
|
||||
int err_line;
|
||||
int err_column;
|
||||
StringName source;
|
||||
String error;
|
||||
|
||||
public:
|
||||
|
||||
Error compile(const GDParser *p_parser,GDScript *p_script);
|
||||
|
||||
String get_error() const;
|
||||
int get_error_line() const;
|
||||
int get_error_column() const;
|
||||
|
||||
GDCompiler();
|
||||
};
|
||||
|
||||
|
||||
#endif // COMPILER_H
|
||||
789
modules/gdscript/gd_editor.cpp
Normal file
789
modules/gdscript/gd_editor.cpp
Normal file
@@ -0,0 +1,789 @@
|
||||
/*************************************************************************/
|
||||
/* gd_editor.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#include "gd_script.h"
|
||||
#include "gd_compiler.h"
|
||||
|
||||
|
||||
void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
|
||||
|
||||
p_delimiters->push_back("#");
|
||||
|
||||
}
|
||||
void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
|
||||
|
||||
p_delimiters->push_back("\" \"");
|
||||
p_delimiters->push_back("' '");
|
||||
|
||||
|
||||
}
|
||||
String GDScriptLanguage::get_template(const String& p_class_name, const String& p_base_class_name) const {
|
||||
|
||||
String _template = String()+
|
||||
"\nextends %BASE%\n\n"+
|
||||
"# member variables here, example:\n"+
|
||||
"# var a=2\n"+
|
||||
"# var b=\"textvar\"\n\n"+
|
||||
"func _ready():\n"+
|
||||
"\t# Initalization here\n"+
|
||||
"\tpass\n"+
|
||||
"\n"+
|
||||
"\n";
|
||||
|
||||
return _template.replace("%BASE%",p_base_class_name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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());
|
||||
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;
|
||||
}
|
||||
|
||||
bool GDScriptLanguage::has_named_classes() const {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int GDScriptLanguage::find_function(const String& p_function,const String& p_code) const {
|
||||
|
||||
GDTokenizer 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;
|
||||
}
|
||||
|
||||
Script *GDScriptLanguage::create_script() const {
|
||||
|
||||
return memnew( GDScript );
|
||||
}
|
||||
|
||||
/* DEBUGGER FUNCTIONS */
|
||||
|
||||
|
||||
bool GDScriptLanguage::debug_break_parse(const String& p_file, int p_line,const String& p_error) {
|
||||
//break because of parse error
|
||||
|
||||
if (ScriptDebugger::get_singleton() && Thread::get_caller_ID()==Thread::get_main_ID()) {
|
||||
|
||||
_debug_parse_err_line=p_line;
|
||||
_debug_parse_err_file=p_file;
|
||||
_debug_error=p_error;
|
||||
ScriptDebugger::get_singleton()->debug(this,false);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool GDScriptLanguage::debug_break(const String& p_error,bool p_allow_continue) {
|
||||
|
||||
if (ScriptDebugger::get_singleton() && Thread::get_caller_ID()==Thread::get_main_ID()) {
|
||||
|
||||
_debug_parse_err_line=-1;
|
||||
_debug_parse_err_file="";
|
||||
_debug_error=p_error;
|
||||
ScriptDebugger::get_singleton()->debug(this,p_allow_continue);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
String GDScriptLanguage::debug_get_error() const {
|
||||
|
||||
return _debug_error;
|
||||
}
|
||||
|
||||
int GDScriptLanguage::debug_get_stack_level_count() const {
|
||||
|
||||
if (_debug_parse_err_line>=0)
|
||||
return 1;
|
||||
|
||||
|
||||
return _debug_call_stack_pos;
|
||||
}
|
||||
int GDScriptLanguage::debug_get_stack_level_line(int p_level) const {
|
||||
|
||||
if (_debug_parse_err_line>=0)
|
||||
return _debug_parse_err_line;
|
||||
|
||||
ERR_FAIL_INDEX_V(p_level,_debug_call_stack_pos,-1);
|
||||
|
||||
int l = _debug_call_stack_pos - p_level -1;
|
||||
|
||||
return *(_call_stack[l].line);
|
||||
|
||||
}
|
||||
String GDScriptLanguage::debug_get_stack_level_function(int p_level) const {
|
||||
|
||||
if (_debug_parse_err_line>=0)
|
||||
return "";
|
||||
|
||||
ERR_FAIL_INDEX_V(p_level,_debug_call_stack_pos,"");
|
||||
int l = _debug_call_stack_pos - p_level -1;
|
||||
return _call_stack[l].function->get_name();
|
||||
}
|
||||
String GDScriptLanguage::debug_get_stack_level_source(int p_level) const {
|
||||
|
||||
if (_debug_parse_err_line>=0)
|
||||
return _debug_parse_err_file;
|
||||
|
||||
ERR_FAIL_INDEX_V(p_level,_debug_call_stack_pos,"");
|
||||
int l = _debug_call_stack_pos - p_level -1;
|
||||
return _call_stack[l].function->get_script()->get_path();
|
||||
|
||||
}
|
||||
void GDScriptLanguage::debug_get_stack_level_locals(int p_level,List<String> *p_locals, List<Variant> *p_values, int p_max_subitems,int p_max_depth) {
|
||||
|
||||
if (_debug_parse_err_line>=0)
|
||||
return;
|
||||
|
||||
ERR_FAIL_INDEX(p_level,_debug_call_stack_pos);
|
||||
int l = _debug_call_stack_pos - p_level -1;
|
||||
|
||||
GDFunction *f = _call_stack[l].function;
|
||||
|
||||
List<Pair<StringName,int> > locals;
|
||||
|
||||
f->debug_get_stack_member_state(*_call_stack[l].line,&locals);
|
||||
for( List<Pair<StringName,int> >::Element *E = locals.front();E;E=E->next() ) {
|
||||
|
||||
p_locals->push_back(E->get().first);
|
||||
p_values->push_back(_call_stack[l].stack[E->get().second]);
|
||||
}
|
||||
|
||||
}
|
||||
void GDScriptLanguage::debug_get_stack_level_members(int p_level,List<String> *p_members, List<Variant> *p_values, int p_max_subitems,int p_max_depth) {
|
||||
|
||||
if (_debug_parse_err_line>=0)
|
||||
return;
|
||||
|
||||
ERR_FAIL_INDEX(p_level,_debug_call_stack_pos);
|
||||
int l = _debug_call_stack_pos - p_level -1;
|
||||
|
||||
|
||||
GDInstance *instance = _call_stack[l].instance;
|
||||
|
||||
if (!instance)
|
||||
return;
|
||||
|
||||
Ref<GDScript> script = instance->get_script();
|
||||
ERR_FAIL_COND( script.is_null() );
|
||||
|
||||
|
||||
const Map<StringName,int>& mi = script->debug_get_member_indices();
|
||||
|
||||
for(const Map<StringName,int>::Element *E=mi.front();E;E=E->next()) {
|
||||
|
||||
p_members->push_back(E->key());
|
||||
p_values->push_back( instance->debug_get_member_by_index(E->get()));
|
||||
}
|
||||
|
||||
}
|
||||
void GDScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems,int p_max_depth) {
|
||||
|
||||
//no globals are really reachable in gdscript
|
||||
}
|
||||
String GDScriptLanguage::debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems,int p_max_depth) {
|
||||
|
||||
if (_debug_parse_err_line>=0)
|
||||
return "";
|
||||
return "";
|
||||
}
|
||||
|
||||
void GDScriptLanguage::get_recognized_extensions(List<String> *p_extensions) const {
|
||||
|
||||
p_extensions->push_back("gd");
|
||||
}
|
||||
|
||||
|
||||
void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const {
|
||||
|
||||
|
||||
for(int i=0;i<GDFunctions::FUNC_MAX;i++) {
|
||||
|
||||
p_functions->push_back(GDFunctions::get_info(GDFunctions::Function(i)));
|
||||
}
|
||||
}
|
||||
|
||||
void GDScriptLanguage::get_public_constants(List<Pair<String,Variant> > *p_constants) const {
|
||||
|
||||
Pair<String,Variant> pi;
|
||||
pi.first="PI";
|
||||
pi.second=Math_PI;
|
||||
p_constants->push_back(pi);
|
||||
}
|
||||
|
||||
String GDScriptLanguage::make_function(const String& p_class,const String& p_name,const StringArray& p_args) const {
|
||||
|
||||
String s="func "+p_name+"(";
|
||||
if (p_args.size()) {
|
||||
s+=" ";
|
||||
for(int i=0;i<p_args.size();i++) {
|
||||
if (i>0)
|
||||
s+=", ";
|
||||
s+=p_args[i];
|
||||
}
|
||||
s+=" ";
|
||||
}
|
||||
s+="):\n\tpass # replace with function body\n";
|
||||
|
||||
return s;
|
||||
|
||||
}
|
||||
|
||||
static void _parse_native_symbols(const StringName& p_native,bool p_static,List<String>* r_options) {
|
||||
|
||||
if (!p_static) {
|
||||
List<MethodInfo> methods;
|
||||
ObjectTypeDB::get_method_list(p_native,&methods);
|
||||
for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
|
||||
if (!E->get().name.begins_with("_")) {
|
||||
r_options->push_back(E->get().name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<String> constants;
|
||||
ObjectTypeDB::get_integer_constant_list(p_native,&constants);
|
||||
|
||||
for(List<String>::Element *E=constants.front();E;E=E->next()) {
|
||||
r_options->push_back(E->get());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static bool _parse_script_symbols(const Ref<GDScript>& p_script,bool p_static,List<String>* r_options,List<String>::Element *p_indices);
|
||||
|
||||
|
||||
static bool _parse_completion_variant(const Variant& p_var,List<String>* r_options,List<String>::Element *p_indices) {
|
||||
|
||||
if (p_indices) {
|
||||
|
||||
bool ok;
|
||||
Variant si = p_var.get(p_indices->get(),&ok);
|
||||
if (!ok)
|
||||
return false;
|
||||
return _parse_completion_variant(si,r_options,p_indices->next());
|
||||
} else {
|
||||
|
||||
switch(p_var.get_type()) {
|
||||
|
||||
|
||||
case Variant::DICTIONARY: {
|
||||
|
||||
Dictionary d=p_var;
|
||||
List<Variant> vl;
|
||||
d.get_key_list(&vl);
|
||||
for (List<Variant>::Element *E=vl.front();E;E=E->next()) {
|
||||
|
||||
if (E->get().get_type()==Variant::STRING)
|
||||
r_options->push_back(E->get());
|
||||
}
|
||||
|
||||
|
||||
List<MethodInfo> ml;
|
||||
p_var.get_method_list(&ml);
|
||||
for(List<MethodInfo>::Element *E=ml.front();E;E=E->next()) {
|
||||
r_options->push_back(E->get().name);
|
||||
}
|
||||
|
||||
} break;
|
||||
case Variant::OBJECT: {
|
||||
|
||||
|
||||
Object *o=p_var;
|
||||
if (o) {
|
||||
print_line("OBJECT: "+o->get_type());
|
||||
if (p_var.is_ref() && o->cast_to<GDScript>()) {
|
||||
|
||||
Ref<GDScript> gds = p_var;
|
||||
_parse_script_symbols(gds,true,r_options,NULL);
|
||||
} else if (o->is_type("GDNativeClass")){
|
||||
|
||||
GDNativeClass *gnc = o->cast_to<GDNativeClass>();
|
||||
_parse_native_symbols(gnc->get_name(),false,r_options);
|
||||
} else {
|
||||
|
||||
print_line("REGULAR BLEND");
|
||||
_parse_native_symbols(o->get_type(),false,r_options);
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
default: {
|
||||
|
||||
List<PropertyInfo> pi;
|
||||
p_var.get_property_list(&pi);
|
||||
for(List<PropertyInfo>::Element *E=pi.front();E;E=E->next()) {
|
||||
r_options->push_back(E->get().name);
|
||||
}
|
||||
List<StringName> cl;
|
||||
|
||||
p_var.get_numeric_constants_for_type(p_var.get_type(),&cl);
|
||||
for(List<StringName>::Element *E=cl.front();E;E=E->next()) {
|
||||
r_options->push_back(E->get());
|
||||
}
|
||||
|
||||
List<MethodInfo> ml;
|
||||
p_var.get_method_list(&ml);
|
||||
for(List<MethodInfo>::Element *E=ml.front();E;E=E->next()) {
|
||||
r_options->push_back(E->get().name);
|
||||
}
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void _parse_expression_node(const GDParser::Node *p_node,List<String>* r_options,List<String>::Element *p_indices) {
|
||||
|
||||
|
||||
|
||||
if (p_node->type==GDParser::Node::TYPE_CONSTANT) {
|
||||
|
||||
const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(p_node);
|
||||
_parse_completion_variant(cn->value,r_options,p_indices?p_indices->next():NULL);
|
||||
} else if (p_node->type==GDParser::Node::TYPE_DICTIONARY) {
|
||||
|
||||
const GDParser::DictionaryNode *dn=static_cast<const GDParser::DictionaryNode*>(p_node);
|
||||
for(int i=0;i<dn->elements.size();i++) {
|
||||
|
||||
if (dn->elements[i].key->type==GDParser::Node::TYPE_CONSTANT) {
|
||||
|
||||
const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(dn->elements[i].key);
|
||||
if (cn->value.get_type()==Variant::STRING) {
|
||||
|
||||
String str=cn->value;
|
||||
if (p_indices) {
|
||||
|
||||
if (str==p_indices->get()) {
|
||||
_parse_expression_node(dn->elements[i].value,r_options,p_indices->next());
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
r_options->push_back(str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool _parse_completion_block(const GDParser::BlockNode *p_block,int p_line,List<String>* r_options,List<String>::Element *p_indices) {
|
||||
|
||||
for(int i=0;i<p_block->sub_blocks.size();i++) {
|
||||
//parse inner first
|
||||
if (p_line>=p_block->sub_blocks[i]->line && (p_line<=p_block->sub_blocks[i]->end_line || p_block->sub_blocks[i]->end_line==-1)) {
|
||||
if (_parse_completion_block(p_block->sub_blocks[i],p_line,r_options,p_indices))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_indices) {
|
||||
|
||||
//parse indices in expressions :|
|
||||
for (int i=0;i<p_block->statements.size();i++) {
|
||||
|
||||
if (p_block->statements[i]->line>p_line)
|
||||
break;
|
||||
|
||||
if (p_block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) {
|
||||
|
||||
const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(p_block->statements[i]);
|
||||
if (lv->assign && String(lv->name)==p_indices->get()) {
|
||||
|
||||
_parse_expression_node(lv->assign,r_options,p_indices->next());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
for(int i=0;i<p_block->variables.size();i++) {
|
||||
//parse variables second
|
||||
if (p_line>=p_block->variable_lines[i]) {
|
||||
r_options->push_back(p_block->variables[i]);
|
||||
}
|
||||
else break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool _parse_script_symbols(const Ref<GDScript>& p_script,bool p_static,List<String>* r_options,List<String>::Element *p_indices) {
|
||||
|
||||
//for (Map<StringName,Ref<GDScript> >::Element ?
|
||||
|
||||
if (!p_static && !p_indices) {
|
||||
for(const Set<StringName>::Element *E=p_script->get_members().front();E;E=E->next()) {
|
||||
|
||||
r_options->push_back(E->get());
|
||||
}
|
||||
}
|
||||
|
||||
for (const Map<StringName,Variant >::Element *E=p_script->get_constants().front();E;E=E->next()) {
|
||||
|
||||
if( p_indices) {
|
||||
if (p_indices->get()==String(E->get())) {
|
||||
_parse_completion_variant(E->get(),r_options,p_indices->next());
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
r_options->push_back(E->key());
|
||||
}
|
||||
}
|
||||
|
||||
if (!p_indices){
|
||||
for (const Map<StringName,GDFunction>::Element *E=p_script->get_member_functions().front();E;E=E->next()) {
|
||||
|
||||
if (E->get().is_static() || !p_static)
|
||||
r_options->push_back(E->key());
|
||||
}
|
||||
}
|
||||
|
||||
if (p_script->get_base().is_valid()){
|
||||
if (_parse_script_symbols(p_script->get_base(),p_static,r_options,p_indices))
|
||||
return true;
|
||||
} else if (p_script->get_native().is_valid() && !p_indices) {
|
||||
_parse_native_symbols(p_script->get_native()->get_name(),p_static,r_options);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool _parse_completion_class(const String& p_base_path,const GDParser::ClassNode *p_class,int p_line,List<String>* r_options,List<String>::Element *p_indices) {
|
||||
|
||||
|
||||
static const char*_type_names[Variant::VARIANT_MAX]={
|
||||
"null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Trasnform",
|
||||
"Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray",
|
||||
"Vector2Array","Vector3Array","ColorArray"};
|
||||
|
||||
if (p_indices && !p_indices->next()) {
|
||||
for(int i=0;i<Variant::VARIANT_MAX;i++) {
|
||||
|
||||
if (p_indices->get()==_type_names[i]) {
|
||||
|
||||
List<StringName> ic;
|
||||
|
||||
Variant::get_numeric_constants_for_type(Variant::Type(i),&ic);
|
||||
for(List<StringName>::Element *E=ic.front();E;E=E->next()) {
|
||||
r_options->push_back(E->get());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
for(int i=0;i<p_class->subclasses.size();i++) {
|
||||
|
||||
if (p_line>=p_class->subclasses[i]->line && (p_line<=p_class->subclasses[i]->end_line || p_class->subclasses[i]->end_line==-1)) {
|
||||
|
||||
if (_parse_completion_class(p_base_path,p_class->subclasses[i],p_line,r_options,p_indices))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool in_static_func=false;
|
||||
|
||||
for(int i=0;i<p_class->functions.size();i++) {
|
||||
|
||||
const GDParser::FunctionNode *fu = p_class->functions[i];
|
||||
|
||||
if (p_line>=fu->body->line && (p_line<=fu->body->end_line || fu->body->end_line==-1)) {
|
||||
//if in function, first block stuff from outer to inner
|
||||
if (_parse_completion_block(fu->body,p_line,r_options,p_indices))
|
||||
return true;
|
||||
//then function arguments
|
||||
if (!p_indices) {
|
||||
for(int j=0;j<fu->arguments.size();j++) {
|
||||
|
||||
r_options->push_back(fu->arguments[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for(int i=0;i<p_class->static_functions.size();i++) {
|
||||
|
||||
const GDParser::FunctionNode *fu = p_class->static_functions[i];
|
||||
|
||||
if (p_line>=fu->body->line && (p_line<=fu->body->end_line || fu->body->end_line==-1)) {
|
||||
|
||||
//if in function, first block stuff from outer to inne
|
||||
if (_parse_completion_block(fu->body,p_line,r_options,p_indices))
|
||||
return true;
|
||||
//then function arguments
|
||||
if (!p_indices) {
|
||||
for(int j=0;j<fu->arguments.size();j++) {
|
||||
|
||||
r_options->push_back(fu->arguments[j]);
|
||||
}
|
||||
}
|
||||
|
||||
in_static_func=true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//add all local names
|
||||
if (!p_indices) {
|
||||
|
||||
if (!in_static_func) {
|
||||
|
||||
for(int i=0;i<p_class->variables.size();i++) {
|
||||
|
||||
r_options->push_back(p_class->variables[i].identifier);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0;i<p_class->constant_expressions.size();i++) {
|
||||
|
||||
r_options->push_back(p_class->constant_expressions[i].identifier);
|
||||
}
|
||||
|
||||
if (!in_static_func) {
|
||||
for(int i=0;i<p_class->functions.size();i++) {
|
||||
|
||||
r_options->push_back(p_class->functions[i]->name);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0;i<p_class->static_functions.size();i++) {
|
||||
|
||||
r_options->push_back(p_class->static_functions[i]->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (p_class->extends_used) {
|
||||
//do inheritance
|
||||
String path = p_class->extends_file;
|
||||
|
||||
Ref<GDScript> script;
|
||||
Ref<GDNativeClass> native;
|
||||
|
||||
if (path!="") {
|
||||
//path (and optionally subclasses)
|
||||
|
||||
script = ResourceLoader::load(path);
|
||||
if (script.is_null()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p_class->extends_class.size()) {
|
||||
|
||||
for(int i=0;i<p_class->extends_class.size();i++) {
|
||||
|
||||
String sub = p_class->extends_class[i];
|
||||
if (script->get_subclasses().has(sub)) {
|
||||
|
||||
script=script->get_subclasses()[sub];
|
||||
} else {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
ERR_FAIL_COND_V(p_class->extends_class.size()==0,false);
|
||||
//look around for the subclasses
|
||||
|
||||
String base=p_class->extends_class[0];
|
||||
Ref<GDScript> base_class;
|
||||
#if 0
|
||||
while(p) {
|
||||
|
||||
if (p->subclasses.has(base)) {
|
||||
|
||||
base_class=p->subclasses[base];
|
||||
break;
|
||||
}
|
||||
p=p->_owner;
|
||||
}
|
||||
|
||||
if (base_class.is_valid()) {
|
||||
|
||||
for(int i=1;i<p_class->extends_class.size();i++) {
|
||||
|
||||
String subclass=p_class->extends_class[i];
|
||||
|
||||
if (base_class->subclasses.has(subclass)) {
|
||||
|
||||
base_class=base_class->subclasses[subclass];
|
||||
} else {
|
||||
|
||||
_set_error("Could not find subclass: "+subclass,p_class);
|
||||
return ERR_FILE_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
#endif
|
||||
if (p_class->extends_class.size()>1) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
//if not found, try engine classes
|
||||
if (!GDScriptLanguage::get_singleton()->get_global_map().has(base)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int base_idx = GDScriptLanguage::get_singleton()->get_global_map()[base];
|
||||
native = GDScriptLanguage::get_singleton()->get_global_array()[base_idx];
|
||||
if (!native.is_valid()) {
|
||||
return false;
|
||||
}
|
||||
#if 0
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if (script.is_valid()) {
|
||||
if (_parse_script_symbols(script,in_static_func,r_options,p_indices))
|
||||
return true;
|
||||
|
||||
} else if (native.is_valid() && !p_indices) {
|
||||
|
||||
_parse_native_symbols(native->get_name(),in_static_func,r_options);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
1218
modules/gdscript/gd_functions.cpp
Normal file
1218
modules/gdscript/gd_functions.cpp
Normal file
File diff suppressed because it is too large
Load Diff
103
modules/gdscript/gd_functions.h
Normal file
103
modules/gdscript/gd_functions.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*************************************************************************/
|
||||
/* gd_functions.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#ifndef GD_FUNCTIONS_H
|
||||
#define GD_FUNCTIONS_H
|
||||
|
||||
#include "variant.h"
|
||||
|
||||
class GDFunctions {
|
||||
public:
|
||||
|
||||
enum Function {
|
||||
MATH_SIN,
|
||||
MATH_COS,
|
||||
MATH_TAN,
|
||||
MATH_SINH,
|
||||
MATH_COSH,
|
||||
MATH_TANH,
|
||||
MATH_ASIN,
|
||||
MATH_ACOS,
|
||||
MATH_ATAN,
|
||||
MATH_ATAN2,
|
||||
MATH_SQRT,
|
||||
MATH_FMOD,
|
||||
MATH_FPOSMOD,
|
||||
MATH_FLOOR,
|
||||
MATH_CEIL,
|
||||
MATH_ROUND,
|
||||
MATH_ABS,
|
||||
MATH_SIGN,
|
||||
MATH_POW,
|
||||
MATH_LOG,
|
||||
MATH_EXP,
|
||||
MATH_ISNAN,
|
||||
MATH_ISINF,
|
||||
MATH_EASE,
|
||||
MATH_DECIMALS,
|
||||
MATH_STEPIFY,
|
||||
MATH_LERP,
|
||||
MATH_DECTIME,
|
||||
MATH_RANDOMIZE,
|
||||
MATH_RAND,
|
||||
MATH_RANDF,
|
||||
MATH_RANDOM,
|
||||
MATH_RANDSEED,
|
||||
MATH_DEG2RAD,
|
||||
MATH_RAD2DEG,
|
||||
MATH_LINEAR2DB,
|
||||
MATH_DB2LINEAR,
|
||||
LOGIC_MAX,
|
||||
LOGIC_MIN,
|
||||
LOGIC_CLAMP,
|
||||
LOGIC_NEAREST_PO2,
|
||||
OBJ_WEAKREF,
|
||||
TYPE_CONVERT,
|
||||
TYPE_OF,
|
||||
TEXT_STR,
|
||||
TEXT_PRINT,
|
||||
TEXT_PRINT_TABBED,
|
||||
TEXT_PRINTERR,
|
||||
TEXT_PRINTRAW,
|
||||
GEN_RANGE,
|
||||
RESOURCE_LOAD,
|
||||
INST2DICT,
|
||||
DICT2INST,
|
||||
PRINT_STACK,
|
||||
FUNC_MAX
|
||||
|
||||
};
|
||||
|
||||
static const char *get_func_name(Function p_func);
|
||||
static void call(Function p_func,const Variant **p_args,int p_arg_count,Variant &r_ret,Variant::CallError &r_error);
|
||||
static bool is_deterministic(Function p_func);
|
||||
static MethodInfo get_info(Function p_func);
|
||||
|
||||
};
|
||||
|
||||
#endif // GD_FUNCTIONS_H
|
||||
2469
modules/gdscript/gd_parser.cpp
Normal file
2469
modules/gdscript/gd_parser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
397
modules/gdscript/gd_parser.h
Normal file
397
modules/gdscript/gd_parser.h
Normal file
@@ -0,0 +1,397 @@
|
||||
/*************************************************************************/
|
||||
/* gd_parser.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#ifndef GD_PARSER_H
|
||||
#define GD_PARSER_H
|
||||
|
||||
#include "gd_tokenizer.h"
|
||||
#include "gd_functions.h"
|
||||
#include "map.h"
|
||||
#include "object.h"
|
||||
|
||||
class GDParser {
|
||||
public:
|
||||
|
||||
struct Node {
|
||||
|
||||
enum Type {
|
||||
TYPE_CLASS,
|
||||
TYPE_FUNCTION,
|
||||
TYPE_BUILT_IN_FUNCTION,
|
||||
TYPE_BLOCK,
|
||||
TYPE_IDENTIFIER,
|
||||
TYPE_TYPE,
|
||||
TYPE_CONSTANT,
|
||||
TYPE_ARRAY,
|
||||
TYPE_DICTIONARY,
|
||||
TYPE_SELF,
|
||||
TYPE_OPERATOR,
|
||||
TYPE_CONTROL_FLOW,
|
||||
TYPE_LOCAL_VAR,
|
||||
TYPE_ASSERT,
|
||||
TYPE_NEWLINE,
|
||||
};
|
||||
|
||||
Node * next;
|
||||
int line;
|
||||
int column;
|
||||
Type type;
|
||||
|
||||
virtual ~Node() {}
|
||||
};
|
||||
|
||||
struct FunctionNode;
|
||||
struct BlockNode;
|
||||
|
||||
struct ClassNode : public Node {
|
||||
|
||||
bool tool;
|
||||
StringName name;
|
||||
bool extends_used;
|
||||
StringName extends_file;
|
||||
Vector<StringName> extends_class;
|
||||
|
||||
struct Member {
|
||||
PropertyInfo _export;
|
||||
#ifdef TOOLS_ENABLED
|
||||
Variant default_value;
|
||||
#endif
|
||||
StringName identifier;
|
||||
};
|
||||
struct Constant {
|
||||
StringName identifier;
|
||||
Node *expression;
|
||||
};
|
||||
|
||||
Vector<ClassNode*> subclasses;
|
||||
Vector<Member> variables;
|
||||
Vector<Constant> constant_expressions;
|
||||
Vector<FunctionNode*> functions;
|
||||
Vector<FunctionNode*> static_functions;
|
||||
BlockNode *initializer;
|
||||
//Vector<Node*> initializers;
|
||||
int end_line;
|
||||
|
||||
ClassNode() { tool=false; type=TYPE_CLASS; extends_used=false; end_line=-1;}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct FunctionNode : public Node {
|
||||
|
||||
bool _static;
|
||||
StringName name;
|
||||
Vector<StringName> arguments;
|
||||
Vector<Node*> default_values;
|
||||
BlockNode *body;
|
||||
|
||||
FunctionNode() { type=TYPE_FUNCTION; _static=false; }
|
||||
|
||||
};
|
||||
|
||||
struct BlockNode : public Node {
|
||||
|
||||
Map<StringName,int> locals;
|
||||
List<Node*> statements;
|
||||
Vector<StringName> variables;
|
||||
Vector<int> variable_lines;
|
||||
|
||||
//the following is useful for code completion
|
||||
List<BlockNode*> sub_blocks;
|
||||
int end_line;
|
||||
BlockNode() { type=TYPE_BLOCK; end_line=-1;}
|
||||
};
|
||||
|
||||
struct TypeNode : public Node {
|
||||
|
||||
Variant::Type vtype;
|
||||
TypeNode() { type=TYPE_TYPE; }
|
||||
};
|
||||
struct BuiltInFunctionNode : public Node {
|
||||
GDFunctions::Function function;
|
||||
BuiltInFunctionNode() { type=TYPE_BUILT_IN_FUNCTION; }
|
||||
};
|
||||
|
||||
struct IdentifierNode : public Node {
|
||||
|
||||
StringName name;
|
||||
IdentifierNode() { type=TYPE_IDENTIFIER; }
|
||||
};
|
||||
|
||||
struct LocalVarNode : public Node {
|
||||
|
||||
StringName name;
|
||||
Node *assign;
|
||||
LocalVarNode() { type=TYPE_LOCAL_VAR; assign=NULL;}
|
||||
};
|
||||
|
||||
struct ConstantNode : public Node {
|
||||
Variant value;
|
||||
ConstantNode() { type=TYPE_CONSTANT; }
|
||||
};
|
||||
|
||||
struct ArrayNode : public Node {
|
||||
|
||||
Vector<Node*> elements;
|
||||
ArrayNode() { type=TYPE_ARRAY; }
|
||||
};
|
||||
|
||||
|
||||
struct DictionaryNode : public Node {
|
||||
|
||||
struct Pair {
|
||||
|
||||
Node *key;
|
||||
Node *value;
|
||||
};
|
||||
|
||||
Vector<Pair> elements;
|
||||
DictionaryNode() { type=TYPE_DICTIONARY; }
|
||||
};
|
||||
|
||||
struct SelfNode : public Node {
|
||||
SelfNode() { type=TYPE_SELF; }
|
||||
};
|
||||
|
||||
struct OperatorNode : public Node {
|
||||
enum Operator {
|
||||
//call/constructor operator
|
||||
OP_CALL,
|
||||
OP_PARENT_CALL,
|
||||
OP_EXTENDS,
|
||||
//indexing operator
|
||||
OP_INDEX,
|
||||
OP_INDEX_NAMED,
|
||||
//unary operators
|
||||
OP_NEG,
|
||||
OP_NOT,
|
||||
OP_BIT_INVERT,
|
||||
OP_PREINC,
|
||||
OP_PREDEC,
|
||||
OP_INC,
|
||||
OP_DEC,
|
||||
//binary operators (in precedence order)
|
||||
OP_IN,
|
||||
OP_EQUAL,
|
||||
OP_NOT_EQUAL,
|
||||
OP_LESS,
|
||||
OP_LESS_EQUAL,
|
||||
OP_GREATER,
|
||||
OP_GREATER_EQUAL,
|
||||
OP_AND,
|
||||
OP_OR,
|
||||
OP_ADD,
|
||||
OP_SUB,
|
||||
OP_MUL,
|
||||
OP_DIV,
|
||||
OP_MOD,
|
||||
OP_SHIFT_LEFT,
|
||||
OP_SHIFT_RIGHT,
|
||||
OP_ASSIGN,
|
||||
OP_ASSIGN_ADD,
|
||||
OP_ASSIGN_SUB,
|
||||
OP_ASSIGN_MUL,
|
||||
OP_ASSIGN_DIV,
|
||||
OP_ASSIGN_MOD,
|
||||
OP_ASSIGN_SHIFT_LEFT,
|
||||
OP_ASSIGN_SHIFT_RIGHT,
|
||||
OP_ASSIGN_BIT_AND,
|
||||
OP_ASSIGN_BIT_OR,
|
||||
OP_ASSIGN_BIT_XOR,
|
||||
OP_BIT_AND,
|
||||
OP_BIT_OR,
|
||||
OP_BIT_XOR
|
||||
};
|
||||
|
||||
Operator op;
|
||||
|
||||
Vector<Node*> arguments;
|
||||
OperatorNode() { type=TYPE_OPERATOR; }
|
||||
};
|
||||
|
||||
struct ControlFlowNode : public Node {
|
||||
enum CFType {
|
||||
CF_IF,
|
||||
CF_FOR,
|
||||
CF_WHILE,
|
||||
CF_SWITCH,
|
||||
CF_BREAK,
|
||||
CF_CONTINUE,
|
||||
CF_RETURN
|
||||
};
|
||||
|
||||
CFType cf_type;
|
||||
Vector<Node*> arguments;
|
||||
BlockNode *body;
|
||||
BlockNode *body_else;
|
||||
|
||||
ControlFlowNode *_else; //used for if
|
||||
ControlFlowNode() { type=TYPE_CONTROL_FLOW; cf_type=CF_IF; body=NULL; body_else=NULL;}
|
||||
};
|
||||
|
||||
struct AssertNode : public Node {
|
||||
Node* condition;
|
||||
AssertNode() { type=TYPE_ASSERT; }
|
||||
};
|
||||
struct NewLineNode : public Node {
|
||||
int line;
|
||||
NewLineNode() { type=TYPE_NEWLINE; }
|
||||
};
|
||||
|
||||
|
||||
struct Expression {
|
||||
|
||||
bool is_op;
|
||||
union {
|
||||
OperatorNode::Operator op;
|
||||
Node *node;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
struct OperatorNode : public Node {
|
||||
|
||||
DataType return_cache;
|
||||
Operator op;
|
||||
Vector<Node*> arguments;
|
||||
virtual DataType get_datatype() const { return return_cache; }
|
||||
|
||||
OperatorNode() { type=TYPE_OPERATOR; return_cache=TYPE_VOID; }
|
||||
};
|
||||
|
||||
struct VariableNode : public Node {
|
||||
|
||||
DataType datatype_cache;
|
||||
StringName name;
|
||||
virtual DataType get_datatype() const { return datatype_cache; }
|
||||
|
||||
VariableNode() { type=TYPE_VARIABLE; datatype_cache=TYPE_VOID; }
|
||||
};
|
||||
|
||||
struct ConstantNode : public Node {
|
||||
|
||||
DataType datatype;
|
||||
Variant value;
|
||||
virtual DataType get_datatype() const { return datatype; }
|
||||
|
||||
ConstantNode() { type=TYPE_CONSTANT; }
|
||||
};
|
||||
|
||||
struct BlockNode : public Node {
|
||||
|
||||
Map<StringName,DataType> variables;
|
||||
List<Node*> statements;
|
||||
BlockNode() { type=TYPE_BLOCK; }
|
||||
};
|
||||
|
||||
struct ControlFlowNode : public Node {
|
||||
|
||||
FlowOperation flow_op;
|
||||
Vector<Node*> statements;
|
||||
ControlFlowNode() { type=TYPE_CONTROL_FLOW; flow_op=FLOW_OP_IF;}
|
||||
};
|
||||
|
||||
struct MemberNode : public Node {
|
||||
|
||||
DataType datatype;
|
||||
StringName name;
|
||||
Node* owner;
|
||||
virtual DataType get_datatype() const { return datatype; }
|
||||
MemberNode() { type=TYPE_MEMBER; }
|
||||
};
|
||||
|
||||
|
||||
struct ProgramNode : public Node {
|
||||
|
||||
struct Function {
|
||||
StringName name;
|
||||
FunctionNode*function;
|
||||
};
|
||||
|
||||
Map<StringName,DataType> builtin_variables;
|
||||
Map<StringName,DataType> preexisting_variables;
|
||||
|
||||
Vector<Function> functions;
|
||||
BlockNode *body;
|
||||
|
||||
ProgramNode() { type=TYPE_PROGRAM; }
|
||||
};
|
||||
*/
|
||||
private:
|
||||
|
||||
|
||||
GDTokenizer tokenizer;
|
||||
|
||||
|
||||
Node *head;
|
||||
Node *list;
|
||||
template<class T>
|
||||
T* alloc_node();
|
||||
|
||||
bool error_set;
|
||||
String error;
|
||||
int error_line;
|
||||
int error_column;
|
||||
|
||||
List<int> tab_level;
|
||||
|
||||
String base_path;
|
||||
|
||||
PropertyInfo current_export;
|
||||
|
||||
void _set_error(const String& p_error, int p_line=-1, int p_column=-1);
|
||||
|
||||
|
||||
bool _parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_static);
|
||||
bool _enter_indent_block(BlockNode *p_block=NULL);
|
||||
bool _parse_newline();
|
||||
Node* _parse_expression(Node *p_parent,bool p_static,bool p_allow_assign=false);
|
||||
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);
|
||||
|
||||
void _parse_block(BlockNode *p_block,bool p_static);
|
||||
void _parse_extends(ClassNode *p_class);
|
||||
void _parse_class(ClassNode *p_class);
|
||||
bool _end_statement();
|
||||
|
||||
public:
|
||||
|
||||
String get_error() const;
|
||||
int get_error_line() const;
|
||||
int get_error_column() const;
|
||||
Error parse(const String& p_code,const String& p_base_path="");
|
||||
|
||||
const Node *get_parse_tree() const;
|
||||
|
||||
void clear();
|
||||
GDParser();
|
||||
~GDParser();
|
||||
};
|
||||
|
||||
#endif // PARSER_H
|
||||
34
modules/gdscript/gd_pretty_print.cpp
Normal file
34
modules/gdscript/gd_pretty_print.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/*************************************************************************/
|
||||
/* gd_pretty_print.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#include "gd_pretty_print.h"
|
||||
|
||||
GDPrettyPrint::GDPrettyPrint() {
|
||||
|
||||
|
||||
}
|
||||
40
modules/gdscript/gd_pretty_print.h
Normal file
40
modules/gdscript/gd_pretty_print.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*************************************************************************/
|
||||
/* gd_pretty_print.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#ifndef GD_PRETTY_PRINT_H
|
||||
#define GD_PRETTY_PRINT_H
|
||||
|
||||
|
||||
|
||||
|
||||
class GDPrettyPrint {
|
||||
public:
|
||||
GDPrettyPrint();
|
||||
};
|
||||
|
||||
#endif // GD_PRETTY_PRINT_H
|
||||
2222
modules/gdscript/gd_script.cpp
Normal file
2222
modules/gdscript/gd_script.cpp
Normal file
File diff suppressed because it is too large
Load Diff
473
modules/gdscript/gd_script.h
Normal file
473
modules/gdscript/gd_script.h
Normal file
@@ -0,0 +1,473 @@
|
||||
/*************************************************************************/
|
||||
/* gd_script.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#ifndef GD_SCRIPT_H
|
||||
#define GD_SCRIPT_H
|
||||
|
||||
#include "script_language.h"
|
||||
#include "io/resource_loader.h"
|
||||
#include "io/resource_saver.h"
|
||||
#include "os/thread.h"
|
||||
#include "pair.h"
|
||||
class GDInstance;
|
||||
class GDScript;
|
||||
|
||||
class GDFunction {
|
||||
public:
|
||||
|
||||
enum Opcode {
|
||||
OPCODE_OPERATOR,
|
||||
OPCODE_EXTENDS_TEST,
|
||||
OPCODE_SET,
|
||||
OPCODE_GET,
|
||||
OPCODE_SET_NAMED,
|
||||
OPCODE_GET_NAMED,
|
||||
OPCODE_ASSIGN,
|
||||
OPCODE_ASSIGN_TRUE,
|
||||
OPCODE_ASSIGN_FALSE,
|
||||
OPCODE_CONSTRUCT, //only for basic types!!
|
||||
OPCODE_CONSTRUCT_ARRAY,
|
||||
OPCODE_CONSTRUCT_DICTIONARY,
|
||||
OPCODE_CALL,
|
||||
OPCODE_CALL_RETURN,
|
||||
OPCODE_CALL_BUILT_IN,
|
||||
OPCODE_CALL_SELF,
|
||||
OPCODE_CALL_SELF_BASE,
|
||||
OPCODE_JUMP,
|
||||
OPCODE_JUMP_IF,
|
||||
OPCODE_JUMP_IF_NOT,
|
||||
OPCODE_JUMP_TO_DEF_ARGUMENT,
|
||||
OPCODE_RETURN,
|
||||
OPCODE_ITERATE_BEGIN,
|
||||
OPCODE_ITERATE,
|
||||
OPCODE_ASSERT,
|
||||
OPCODE_LINE,
|
||||
OPCODE_END
|
||||
};
|
||||
|
||||
enum Address {
|
||||
ADDR_BITS=24,
|
||||
ADDR_MASK=((1<<ADDR_BITS)-1),
|
||||
ADDR_TYPE_MASK=~ADDR_MASK,
|
||||
ADDR_TYPE_SELF=0,
|
||||
ADDR_TYPE_MEMBER=1,
|
||||
ADDR_TYPE_CLASS_CONSTANT=2,
|
||||
ADDR_TYPE_LOCAL_CONSTANT=3,
|
||||
ADDR_TYPE_STACK=4,
|
||||
ADDR_TYPE_STACK_VARIABLE=5,
|
||||
ADDR_TYPE_GLOBAL=6,
|
||||
ADDR_TYPE_NIL=7
|
||||
};
|
||||
|
||||
struct StackDebug {
|
||||
|
||||
int line;
|
||||
int pos;
|
||||
bool added;
|
||||
StringName identifier;
|
||||
};
|
||||
|
||||
private:
|
||||
friend class GDCompiler;
|
||||
|
||||
StringName source;
|
||||
|
||||
mutable Variant nil;
|
||||
mutable Variant *_constants_ptr;
|
||||
int _constant_count;
|
||||
const StringName *_global_names_ptr;
|
||||
int _global_names_count;
|
||||
const int *_default_arg_ptr;
|
||||
int _default_arg_count;
|
||||
const int *_code_ptr;
|
||||
int _code_size;
|
||||
int _argument_count;
|
||||
int _stack_size;
|
||||
int _call_size;
|
||||
int _initial_line;
|
||||
bool _static;
|
||||
GDScript *_script;
|
||||
|
||||
StringName name;
|
||||
Vector<Variant> constants;
|
||||
Vector<StringName> global_names;
|
||||
Vector<int> default_arguments;
|
||||
|
||||
Vector<int> code;
|
||||
|
||||
List<StackDebug> stack_debug;
|
||||
|
||||
_FORCE_INLINE_ Variant *_get_variant(int p_address,GDInstance *p_instance,GDScript *p_script,Variant &self,Variant *p_stack,String& r_error) const;
|
||||
_FORCE_INLINE_ String _get_call_error(const Variant::CallError& p_err, const String& p_where,const Variant**argptrs) const;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
_FORCE_INLINE_ bool is_static() const { return _static; }
|
||||
|
||||
const int* get_code() const; //used for debug
|
||||
int get_code_size() const;
|
||||
Variant get_constant(int p_idx) const;
|
||||
StringName get_global_name(int p_idx) const;
|
||||
StringName get_name() const;
|
||||
int get_max_stack_size() const;
|
||||
int get_default_argument_count() const;
|
||||
int get_default_argument_addr(int p_idx) const;
|
||||
GDScript *get_script() const { return _script; }
|
||||
|
||||
void debug_get_stack_member_state(int p_line,List<Pair<StringName,int> > *r_stackvars) const;
|
||||
|
||||
_FORCE_INLINE_ bool is_empty() const { return _code_size==0; }
|
||||
|
||||
int get_argument_count() const { return _argument_count; }
|
||||
Variant call(GDInstance *p_instance,const Variant **p_args, int p_argcount,Variant::CallError& r_err);
|
||||
|
||||
GDFunction();
|
||||
};
|
||||
|
||||
|
||||
class GDNativeClass : public Reference {
|
||||
|
||||
OBJ_TYPE(GDNativeClass,Reference);
|
||||
|
||||
StringName name;
|
||||
protected:
|
||||
|
||||
bool _get(const StringName& p_name,Variant &r_ret) const;
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
|
||||
_FORCE_INLINE_ const StringName& get_name() const { return name; }
|
||||
Variant _new();
|
||||
Object *instance();
|
||||
GDNativeClass(const StringName& p_name);
|
||||
};
|
||||
|
||||
|
||||
class GDScript : public Script {
|
||||
|
||||
|
||||
OBJ_TYPE(GDScript,Script);
|
||||
bool tool;
|
||||
bool valid;
|
||||
|
||||
|
||||
friend class GDInstance;
|
||||
friend class GDFunction;
|
||||
friend class GDCompiler;
|
||||
friend class GDFunctions;
|
||||
Ref<GDNativeClass> native;
|
||||
Ref<GDScript> base;
|
||||
GDScript *_base; //fast pointer access
|
||||
GDScript *_owner; //for subclasses
|
||||
|
||||
Set<StringName> members; //members are just indices to the instanced script.
|
||||
Map<StringName,Variant> constants;
|
||||
Map<StringName,GDFunction> member_functions;
|
||||
Map<StringName,int> member_indices; //members are just indices to the instanced script.
|
||||
Map<StringName,Ref<GDScript> > subclasses;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
Map<StringName,Variant> member_default_values;
|
||||
#endif
|
||||
Map<StringName,PropertyInfo> member_info;
|
||||
|
||||
GDFunction *initializer; //direct pointer to _init , faster to locate
|
||||
|
||||
int subclass_count;
|
||||
Set<Object*> instances;
|
||||
//exported members
|
||||
String source;
|
||||
String path;
|
||||
String name;
|
||||
|
||||
|
||||
GDInstance* _create_instance(const Variant** p_args,int p_argcount,Object *p_owner,bool p_isref);
|
||||
|
||||
void _set_subclass_path(Ref<GDScript>& p_sc,const String& p_path);
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
Set<PlaceHolderScriptInstance*> placeholders;
|
||||
void _update_placeholder(PlaceHolderScriptInstance *p_placeholder);
|
||||
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder);
|
||||
#endif
|
||||
|
||||
|
||||
protected:
|
||||
bool _get(const StringName& p_name,Variant &r_ret) const;
|
||||
bool _set(const StringName& p_name, const Variant& p_value);
|
||||
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);
|
||||
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
|
||||
const Map<StringName,Ref<GDScript> >& get_subclasses() const { return subclasses; }
|
||||
const Map<StringName,Variant >& get_constants() const { return constants; }
|
||||
const Set<StringName>& get_members() const { return members; }
|
||||
const Map<StringName,GDFunction>& get_member_functions() const { return member_functions; }
|
||||
const Ref<GDNativeClass>& get_native() const { return native; }
|
||||
|
||||
|
||||
bool is_tool() const { return tool; }
|
||||
Ref<GDScript> get_base() const;
|
||||
|
||||
const Map<StringName,int>& debug_get_member_indices() const { return member_indices; }
|
||||
const Map<StringName,GDFunction>& debug_get_member_functions() const; //this is debug only
|
||||
StringName debug_get_member_by_index(int p_idx) const;
|
||||
|
||||
Variant _new(const Variant** p_args,int p_argcount,Variant::CallError& r_error);
|
||||
virtual bool can_instance() const;
|
||||
|
||||
virtual StringName get_instance_base_type() const; // this may not work in all scripts, will return empty if so
|
||||
virtual ScriptInstance* instance_create(Object *p_this);
|
||||
virtual bool instance_has(const Object *p_this) const;
|
||||
|
||||
virtual bool has_source_code() const;
|
||||
virtual String get_source_code() const;
|
||||
virtual void set_source_code(const String& p_code);
|
||||
virtual Error reload();
|
||||
|
||||
virtual String get_node_type() const;
|
||||
void set_script_path(const String& p_path) { path=p_path; } //because subclasses need a path too...
|
||||
Error load_source_code(const String& p_path);
|
||||
|
||||
virtual ScriptLanguage *get_language() const;
|
||||
|
||||
GDScript();
|
||||
};
|
||||
|
||||
class GDInstance : public ScriptInstance {
|
||||
friend class GDScript;
|
||||
friend class GDFunction;
|
||||
friend class GDFunctions;
|
||||
|
||||
Object *owner;
|
||||
Ref<GDScript> script;
|
||||
Vector<Variant> members;
|
||||
bool base_ref;
|
||||
|
||||
void _ml_call_reversed(GDScript *sptr,const StringName& p_method,const Variant** p_args,int p_argcount);
|
||||
|
||||
public:
|
||||
|
||||
virtual bool set(const StringName& p_name, const Variant& p_value);
|
||||
virtual bool get(const StringName& p_name, Variant &r_ret) const;
|
||||
virtual void get_property_list(List<PropertyInfo> *p_properties) const;
|
||||
|
||||
virtual void get_method_list(List<MethodInfo> *p_list) const;
|
||||
virtual bool has_method(const StringName& p_method) const;
|
||||
virtual Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error);
|
||||
virtual void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount);
|
||||
virtual void call_multilevel_reversed(const StringName& p_method,const Variant** p_args,int p_argcount);
|
||||
|
||||
Variant debug_get_member_by_index(int p_idx) const { return members[p_idx]; }
|
||||
|
||||
virtual void notification(int p_notification);
|
||||
|
||||
virtual Ref<Script> get_script() const;
|
||||
|
||||
virtual ScriptLanguage *get_language();
|
||||
|
||||
void set_path(const String& p_path);
|
||||
|
||||
|
||||
GDInstance();
|
||||
~GDInstance();
|
||||
|
||||
};
|
||||
|
||||
class GDScriptLanguage : public ScriptLanguage {
|
||||
|
||||
static GDScriptLanguage *singleton;
|
||||
|
||||
Variant* _global_array;
|
||||
Vector<Variant> global_array;
|
||||
Map<StringName,int> globals;
|
||||
|
||||
|
||||
struct CallLevel {
|
||||
|
||||
Variant *stack;
|
||||
GDFunction *function;
|
||||
GDInstance *instance;
|
||||
int *ip;
|
||||
int *line;
|
||||
|
||||
};
|
||||
|
||||
|
||||
int _debug_parse_err_line;
|
||||
String _debug_parse_err_file;
|
||||
String _debug_error;
|
||||
int _debug_call_stack_pos;
|
||||
int _debug_max_call_stack;
|
||||
CallLevel *_call_stack;
|
||||
|
||||
void _add_global(const StringName& p_name,const Variant& p_value);
|
||||
|
||||
|
||||
public:
|
||||
|
||||
int calls;
|
||||
|
||||
bool debug_break(const String& p_error,bool p_allow_continue=true);
|
||||
bool debug_break_parse(const String& p_file, int p_line,const String& p_error);
|
||||
|
||||
_FORCE_INLINE_ void enter_function(GDInstance *p_instance,GDFunction *p_function, Variant *p_stack, int *p_ip, int *p_line) {
|
||||
|
||||
if (Thread::get_main_ID()!=Thread::get_caller_ID())
|
||||
return; //no support for other threads than main for now
|
||||
|
||||
if (ScriptDebugger::get_singleton()->get_lines_left()>0 && ScriptDebugger::get_singleton()->get_depth()>=0)
|
||||
ScriptDebugger::get_singleton()->set_depth( ScriptDebugger::get_singleton()->get_depth() +1 );
|
||||
|
||||
if (_debug_call_stack_pos >= _debug_max_call_stack) {
|
||||
//stack overflow
|
||||
_debug_error="Stack Overflow (Stack Size: "+itos(_debug_max_call_stack)+")";
|
||||
ScriptDebugger::get_singleton()->debug(this);
|
||||
return;
|
||||
}
|
||||
|
||||
_call_stack[_debug_call_stack_pos].stack=p_stack;
|
||||
_call_stack[_debug_call_stack_pos].instance=p_instance;
|
||||
_call_stack[_debug_call_stack_pos].function=p_function;
|
||||
_call_stack[_debug_call_stack_pos].ip=p_ip;
|
||||
_call_stack[_debug_call_stack_pos].line=p_line;
|
||||
_debug_call_stack_pos++;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void exit_function() {
|
||||
|
||||
if (Thread::get_main_ID()!=Thread::get_caller_ID())
|
||||
return; //no support for other threads than main for now
|
||||
|
||||
if (ScriptDebugger::get_singleton()->get_lines_left()>0 && ScriptDebugger::get_singleton()->get_depth()>=0)
|
||||
ScriptDebugger::get_singleton()->set_depth( ScriptDebugger::get_singleton()->get_depth() -1 );
|
||||
|
||||
if (_debug_call_stack_pos==0) {
|
||||
|
||||
_debug_error="Stack Underflow (Engine Bug)";
|
||||
ScriptDebugger::get_singleton()->debug(this);
|
||||
return;
|
||||
}
|
||||
|
||||
_debug_call_stack_pos--;
|
||||
}
|
||||
|
||||
|
||||
struct {
|
||||
|
||||
StringName _init;
|
||||
StringName _notification;
|
||||
StringName _set;
|
||||
StringName _get;
|
||||
StringName _get_property_list;
|
||||
StringName _script_source;
|
||||
|
||||
} strings;
|
||||
|
||||
|
||||
_FORCE_INLINE_ int get_global_array_size() const { return global_array.size(); }
|
||||
_FORCE_INLINE_ Variant* get_global_array() { return _global_array; }
|
||||
_FORCE_INLINE_ const Map<StringName,int>& get_global_map() { return globals; }
|
||||
|
||||
_FORCE_INLINE_ static GDScriptLanguage *get_singleton() { return singleton; }
|
||||
|
||||
virtual String get_name() const;
|
||||
|
||||
/* LANGUAGE FUNCTIONS */
|
||||
virtual void init();
|
||||
virtual String get_type() const;
|
||||
virtual String get_extension() const;
|
||||
virtual Error execute_file(const String& p_path) ;
|
||||
virtual void finish();
|
||||
|
||||
/* EDITOR FUNCTIONS */
|
||||
virtual void get_reserved_words(List<String> *p_words) const;
|
||||
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
|
||||
virtual void get_string_delimiters(List<String> *p_delimiters) const;
|
||||
virtual String get_template(const String& p_class_name, const String& p_base_class_name) const;
|
||||
virtual bool 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=NULL) const;
|
||||
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 Error complete_keyword(const String& p_code, int p_line, const String& p_base_path,const String& p_keyword, List<String>* r_options);
|
||||
|
||||
/* DEBUGGER FUNCTIONS */
|
||||
|
||||
virtual String debug_get_error() const;
|
||||
virtual int debug_get_stack_level_count() const;
|
||||
virtual int debug_get_stack_level_line(int p_level) const;
|
||||
virtual String debug_get_stack_level_function(int p_level) const;
|
||||
virtual String debug_get_stack_level_source(int p_level) const;
|
||||
virtual void debug_get_stack_level_locals(int p_level,List<String> *p_locals, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1);
|
||||
virtual void debug_get_stack_level_members(int p_level,List<String> *p_members, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1);
|
||||
virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1);
|
||||
virtual String debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems=-1,int p_max_depth=-1);
|
||||
|
||||
virtual void frame();
|
||||
|
||||
virtual void get_public_functions(List<MethodInfo> *p_functions) const;
|
||||
virtual void get_public_constants(List<Pair<String,Variant> > *p_constants) const;
|
||||
|
||||
/* LOADER FUNCTIONS */
|
||||
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const;
|
||||
|
||||
GDScriptLanguage();
|
||||
~GDScriptLanguage();
|
||||
};
|
||||
|
||||
|
||||
class ResourceFormatLoaderGDScript : public ResourceFormatLoader {
|
||||
public:
|
||||
|
||||
virtual RES load(const String &p_path,const String& p_original_path="");
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const;
|
||||
virtual bool handles_type(const String& p_type) const;
|
||||
virtual String get_resource_type(const String &p_path) const;
|
||||
|
||||
};
|
||||
|
||||
class ResourceFormatSaverGDScript : public ResourceFormatSaver {
|
||||
public:
|
||||
|
||||
virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
|
||||
virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const;
|
||||
virtual bool recognize(const RES& p_resource) const;
|
||||
|
||||
};
|
||||
|
||||
#endif // GD_SCRIPT_H
|
||||
973
modules/gdscript/gd_tokenizer.cpp
Normal file
973
modules/gdscript/gd_tokenizer.cpp
Normal file
@@ -0,0 +1,973 @@
|
||||
/*************************************************************************/
|
||||
/* gd_tokenizer.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#include "gd_tokenizer.h"
|
||||
#include "print_string.h"
|
||||
#include "gd_functions.h"
|
||||
const char* GDTokenizer::token_names[TK_MAX]={
|
||||
"Empty",
|
||||
"Identifier",
|
||||
"Constant",
|
||||
"Self",
|
||||
"Built-In Type",
|
||||
"Built-In Func",
|
||||
"In",
|
||||
"'=='",
|
||||
"'!='",
|
||||
"'<'",
|
||||
"'<='",
|
||||
"'>'",
|
||||
"'>='",
|
||||
"'and'",
|
||||
"'or'",
|
||||
"'not'",
|
||||
"'+'",
|
||||
"'-'",
|
||||
"'*'",
|
||||
"'/'",
|
||||
"'%'",
|
||||
"'<<'",
|
||||
"'>>'",
|
||||
"'='",
|
||||
"'+='",
|
||||
"'-='",
|
||||
"'*='",
|
||||
"'/='",
|
||||
"'%='",
|
||||
"'<<='",
|
||||
"'>>='",
|
||||
"'&='",
|
||||
"'|='",
|
||||
"'^='",
|
||||
"'&'",
|
||||
"'|'",
|
||||
"'^'",
|
||||
"'~'",
|
||||
//"Plus Plus",
|
||||
//"Minus Minus",
|
||||
"if",
|
||||
"elif",
|
||||
"else",
|
||||
"for",
|
||||
"do",
|
||||
"while",
|
||||
"switch",
|
||||
"case",
|
||||
"break",
|
||||
"continue",
|
||||
"pass",
|
||||
"return",
|
||||
"func",
|
||||
"class",
|
||||
"extends",
|
||||
"tool",
|
||||
"static",
|
||||
"export",
|
||||
"const",
|
||||
"var",
|
||||
"preload",
|
||||
"assert",
|
||||
"'['",
|
||||
"']'",
|
||||
"'{'",
|
||||
"'}'",
|
||||
"'('",
|
||||
"')'",
|
||||
"','",
|
||||
"';'",
|
||||
"'.'",
|
||||
"'?'",
|
||||
"':'",
|
||||
"'\\n'",
|
||||
"Error",
|
||||
"EOF"};
|
||||
|
||||
const char *GDTokenizer::get_token_name(Token p_token) {
|
||||
|
||||
ERR_FAIL_INDEX_V(p_token,TK_MAX,"<error>");
|
||||
return token_names[p_token];
|
||||
}
|
||||
|
||||
static bool _is_text_char(CharType c) {
|
||||
|
||||
return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_';
|
||||
}
|
||||
|
||||
static bool _is_number(CharType c) {
|
||||
|
||||
return (c>='0' && c<='9');
|
||||
}
|
||||
|
||||
static bool _is_hex(CharType c) {
|
||||
|
||||
return (c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F');
|
||||
}
|
||||
|
||||
void GDTokenizer::_make_token(Token p_type) {
|
||||
|
||||
TokenData &tk=tk_rb[tk_rb_pos];
|
||||
|
||||
tk.type=p_type;
|
||||
tk.line=line;
|
||||
tk.col=column;
|
||||
|
||||
tk_rb_pos=(tk_rb_pos+1)%TK_RB_SIZE;
|
||||
}
|
||||
void GDTokenizer::_make_identifier(const StringName& p_identifier) {
|
||||
|
||||
TokenData &tk=tk_rb[tk_rb_pos];
|
||||
|
||||
tk.type=TK_IDENTIFIER;
|
||||
tk.identifier=p_identifier;
|
||||
tk.line=line;
|
||||
tk.col=column;
|
||||
|
||||
tk_rb_pos=(tk_rb_pos+1)%TK_RB_SIZE;
|
||||
|
||||
}
|
||||
|
||||
void GDTokenizer::_make_built_in_func(GDFunctions::Function p_func) {
|
||||
|
||||
TokenData &tk=tk_rb[tk_rb_pos];
|
||||
|
||||
tk.type=TK_BUILT_IN_FUNC;
|
||||
tk.func=p_func;
|
||||
tk.line=line;
|
||||
tk.col=column;
|
||||
|
||||
tk_rb_pos=(tk_rb_pos+1)%TK_RB_SIZE;
|
||||
|
||||
}
|
||||
void GDTokenizer::_make_constant(const Variant& p_constant) {
|
||||
|
||||
TokenData &tk=tk_rb[tk_rb_pos];
|
||||
|
||||
tk.type=TK_CONSTANT;
|
||||
tk.constant=p_constant;
|
||||
tk.line=line;
|
||||
tk.col=column;
|
||||
|
||||
tk_rb_pos=(tk_rb_pos+1)%TK_RB_SIZE;
|
||||
|
||||
}
|
||||
|
||||
void GDTokenizer::_make_type(const Variant::Type& p_type) {
|
||||
|
||||
|
||||
TokenData &tk=tk_rb[tk_rb_pos];
|
||||
|
||||
tk.type=TK_BUILT_IN_TYPE;
|
||||
tk.vtype=p_type;
|
||||
tk.line=line;
|
||||
tk.col=column;
|
||||
|
||||
tk_rb_pos=(tk_rb_pos+1)%TK_RB_SIZE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void GDTokenizer::_make_error(const String& p_error) {
|
||||
|
||||
error_flag=true;
|
||||
last_error=p_error;
|
||||
|
||||
TokenData &tk=tk_rb[tk_rb_pos];
|
||||
tk.type=TK_ERROR;
|
||||
tk.constant=p_error;
|
||||
tk.line=line;
|
||||
tk.col=column;
|
||||
tk_rb_pos=(tk_rb_pos+1)%TK_RB_SIZE;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void GDTokenizer::_make_newline(int p_spaces) {
|
||||
|
||||
TokenData &tk=tk_rb[tk_rb_pos];
|
||||
tk.type=TK_NEWLINE;
|
||||
tk.constant=p_spaces;
|
||||
tk.line=line;
|
||||
tk.col=column;
|
||||
tk_rb_pos=(tk_rb_pos+1)%TK_RB_SIZE;
|
||||
}
|
||||
|
||||
void GDTokenizer::_advance() {
|
||||
|
||||
if (error_flag) {
|
||||
//parser broke
|
||||
_make_error(last_error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (code_pos>=len) {
|
||||
_make_token(TK_EOF);
|
||||
return;
|
||||
}
|
||||
#define GETCHAR(m_ofs) ((m_ofs+code_pos)>=len?0:_code[m_ofs+code_pos])
|
||||
#define INCPOS(m_amount) { code_pos+=m_amount; column+=m_amount; }
|
||||
while (true) {
|
||||
|
||||
|
||||
bool is_node_path=false;
|
||||
|
||||
switch(GETCHAR(0)) {
|
||||
case 0:
|
||||
_make_token(TK_EOF);
|
||||
break;
|
||||
case '\t':
|
||||
case '\r':
|
||||
case ' ':
|
||||
INCPOS(1);
|
||||
continue;
|
||||
case '\n': {
|
||||
line++;
|
||||
INCPOS(1);
|
||||
column=0;
|
||||
int i=0;
|
||||
while(GETCHAR(i)==' ' || GETCHAR(i)=='\t') {
|
||||
i++;
|
||||
}
|
||||
|
||||
_make_newline(i);
|
||||
return;
|
||||
}
|
||||
#if 1 //py style tokenizer
|
||||
case '#': { // line comment skip
|
||||
|
||||
while(GETCHAR(0)!='\n') {
|
||||
code_pos++;
|
||||
if (GETCHAR(0)==0) { //end of file
|
||||
_make_error("Unterminated Comment");
|
||||
return;
|
||||
}
|
||||
}
|
||||
INCPOS(1);
|
||||
column=0;
|
||||
line++;
|
||||
int i=0;
|
||||
while(GETCHAR(i)==' ' || GETCHAR(i)=='\t') {
|
||||
i++;
|
||||
}
|
||||
_make_newline(i);
|
||||
return;
|
||||
|
||||
} break;
|
||||
#endif
|
||||
case '/': {
|
||||
|
||||
switch(GETCHAR(1)) {
|
||||
#if 0 // c style tokenizer
|
||||
case '*': { // block comment
|
||||
int pos = code_pos+2;
|
||||
int new_line=line;
|
||||
int new_col=column+2;
|
||||
|
||||
while(true) {
|
||||
if (_code[pos]=='0') {
|
||||
_make_error("Unterminated Comment");
|
||||
code_pos=pos;
|
||||
return;
|
||||
}
|
||||
if (_code[pos]=='*' && _code[pos+1]=='/') {
|
||||
new_col+=2;
|
||||
pos+=2; //compensate
|
||||
break;
|
||||
} else if (_code[pos]=='\n') {
|
||||
new_line++;
|
||||
new_col=0;
|
||||
} else {
|
||||
new_col++;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
|
||||
column=new_col;
|
||||
line=new_line;
|
||||
code_pos=pos;
|
||||
continue;
|
||||
|
||||
} break;
|
||||
case '/': { // line comment skip
|
||||
|
||||
while(GETCHAR(0)!='\n') {
|
||||
code_pos++;
|
||||
if (GETCHAR(0)==0) { //end of file
|
||||
_make_error("Unterminated Comment");
|
||||
return;
|
||||
}
|
||||
}
|
||||
INCPOS(1);
|
||||
column=0;
|
||||
line++;
|
||||
continue;
|
||||
|
||||
} break;
|
||||
#endif
|
||||
case '=': { // diveq
|
||||
|
||||
_make_token(TK_OP_ASSIGN_DIV);
|
||||
INCPOS(1);
|
||||
|
||||
} break;
|
||||
default:
|
||||
_make_token(TK_OP_DIV);
|
||||
|
||||
}
|
||||
} break;
|
||||
case '=': {
|
||||
if (GETCHAR(1)=='=') {
|
||||
_make_token(TK_OP_EQUAL);
|
||||
INCPOS(1);
|
||||
|
||||
} else
|
||||
_make_token(TK_OP_ASSIGN);
|
||||
|
||||
} break;
|
||||
case '<': {
|
||||
if (GETCHAR(1)=='=') {
|
||||
|
||||
_make_token(TK_OP_LESS_EQUAL);
|
||||
INCPOS(1);
|
||||
} else if (GETCHAR(1)=='<') {
|
||||
if (GETCHAR(2)=='=') {
|
||||
_make_token(TK_OP_ASSIGN_SHIFT_LEFT);
|
||||
INCPOS(1);
|
||||
} else {
|
||||
_make_token(TK_OP_SHIFT_LEFT);
|
||||
}
|
||||
INCPOS(1);
|
||||
} else
|
||||
_make_token(TK_OP_LESS);
|
||||
|
||||
} break;
|
||||
case '>': {
|
||||
if (GETCHAR(1)=='=') {
|
||||
_make_token(TK_OP_GREATER_EQUAL);
|
||||
INCPOS(1);
|
||||
} else if (GETCHAR(1)=='>') {
|
||||
if (GETCHAR(2)=='=') {
|
||||
_make_token(TK_OP_ASSIGN_SHIFT_RIGHT);
|
||||
INCPOS(1);
|
||||
|
||||
} else {
|
||||
_make_token(TK_OP_SHIFT_RIGHT);
|
||||
}
|
||||
INCPOS(1);
|
||||
} else {
|
||||
_make_token(TK_OP_GREATER);
|
||||
}
|
||||
|
||||
} break;
|
||||
case '!': {
|
||||
if (GETCHAR(1)=='=') {
|
||||
_make_token(TK_OP_NOT_EQUAL);
|
||||
INCPOS(1);
|
||||
} else {
|
||||
_make_token(TK_OP_NOT);
|
||||
}
|
||||
|
||||
} break;
|
||||
//case '"' //string - no strings in shader
|
||||
//case '\'' //string - no strings in shader
|
||||
case '{':
|
||||
_make_token(TK_CURLY_BRACKET_OPEN);
|
||||
break;
|
||||
case '}':
|
||||
_make_token(TK_CURLY_BRACKET_CLOSE);
|
||||
break;
|
||||
case '[':
|
||||
_make_token(TK_BRACKET_OPEN);
|
||||
break;
|
||||
case ']':
|
||||
_make_token(TK_BRACKET_CLOSE);
|
||||
break;
|
||||
case '(':
|
||||
_make_token(TK_PARENTHESIS_OPEN);
|
||||
break;
|
||||
case ')':
|
||||
_make_token(TK_PARENTHESIS_CLOSE);
|
||||
break;
|
||||
case ',':
|
||||
_make_token(TK_COMMA);
|
||||
break;
|
||||
case ';':
|
||||
_make_token(TK_SEMICOLON);
|
||||
break;
|
||||
case '?':
|
||||
_make_token(TK_QUESTION_MARK);
|
||||
break;
|
||||
case ':':
|
||||
_make_token(TK_COLON); //for methods maybe but now useless.
|
||||
break;
|
||||
case '^': {
|
||||
if (GETCHAR(1)=='=') {
|
||||
_make_token(TK_OP_ASSIGN_BIT_XOR);
|
||||
INCPOS(1);
|
||||
} else {
|
||||
_make_token(TK_OP_BIT_XOR);
|
||||
}
|
||||
|
||||
} break;
|
||||
case '~':
|
||||
_make_token(TK_OP_BIT_INVERT);
|
||||
break;
|
||||
case '&': {
|
||||
if (GETCHAR(1)=='&') {
|
||||
|
||||
_make_token(TK_OP_AND);
|
||||
INCPOS(1);
|
||||
} else if (GETCHAR(1)=='=') {
|
||||
_make_token(TK_OP_ASSIGN_BIT_AND);
|
||||
INCPOS(1);
|
||||
} else {
|
||||
_make_token(TK_OP_BIT_AND);
|
||||
}
|
||||
} break;
|
||||
case '|': {
|
||||
if (GETCHAR(1)=='|') {
|
||||
|
||||
_make_token(TK_OP_OR);
|
||||
INCPOS(1);
|
||||
} else if (GETCHAR(1)=='=') {
|
||||
_make_token(TK_OP_ASSIGN_BIT_OR);
|
||||
INCPOS(1);
|
||||
} else {
|
||||
_make_token(TK_OP_BIT_OR);
|
||||
}
|
||||
} break;
|
||||
case '*': {
|
||||
|
||||
if (GETCHAR(1)=='=') {
|
||||
_make_token(TK_OP_ASSIGN_MUL);
|
||||
INCPOS(1);
|
||||
} else {
|
||||
_make_token(TK_OP_MUL);
|
||||
}
|
||||
} break;
|
||||
case '+': {
|
||||
|
||||
if (GETCHAR(1)=='=') {
|
||||
_make_token(TK_OP_ASSIGN_ADD);
|
||||
INCPOS(1);
|
||||
//} else if (GETCHAR(1)=='+') {
|
||||
// _make_token(TK_OP_PLUS_PLUS);
|
||||
// INCPOS(1);
|
||||
} else {
|
||||
_make_token(TK_OP_ADD);
|
||||
}
|
||||
|
||||
} break;
|
||||
case '-': {
|
||||
|
||||
if (GETCHAR(1)=='=') {
|
||||
_make_token(TK_OP_ASSIGN_SUB);
|
||||
INCPOS(1);
|
||||
//} else if (GETCHAR(1)=='-') {
|
||||
// _make_token(TK_OP_MINUS_MINUS);
|
||||
// INCPOS(1);
|
||||
} else {
|
||||
_make_token(TK_OP_SUB);
|
||||
}
|
||||
} break;
|
||||
case '%': {
|
||||
|
||||
if (GETCHAR(1)=='=') {
|
||||
_make_token(TK_OP_ASSIGN_MOD);
|
||||
INCPOS(1);
|
||||
} else {
|
||||
_make_token(TK_OP_MOD);
|
||||
}
|
||||
} break;
|
||||
case '@':
|
||||
if (CharType(GETCHAR(1))!='"') {
|
||||
_make_error("Unexpected '@'");
|
||||
return;
|
||||
}
|
||||
INCPOS(1);
|
||||
is_node_path=true;
|
||||
case '"': {
|
||||
|
||||
int i=1;
|
||||
String str;
|
||||
while(true) {
|
||||
if (CharType(GETCHAR(i)==0)) {
|
||||
|
||||
_make_error("Unterminated String");
|
||||
return;
|
||||
} else if (CharType(GETCHAR(i)=='"')) {
|
||||
break;
|
||||
} else if (CharType(GETCHAR(i)=='\\')) {
|
||||
//escaped characters...
|
||||
i++;
|
||||
CharType next = GETCHAR(i);
|
||||
if (next==0) {
|
||||
_make_error("Unterminated String");
|
||||
return;
|
||||
}
|
||||
CharType res=0;
|
||||
|
||||
switch(next) {
|
||||
|
||||
case 'a': res=7; break;
|
||||
case 'b': res=8; break;
|
||||
case 't': res=9; break;
|
||||
case 'n': res=10; break;
|
||||
case 'v': res=11; break;
|
||||
case 'f': res=12; break;
|
||||
case 'r': res=13; break;
|
||||
case '\'': res='\''; break;
|
||||
case '\"': res='\"'; break;
|
||||
case '\\': res='\\'; break;
|
||||
case 'x': {
|
||||
//hexnumbarh - oct is deprecated
|
||||
|
||||
int read=0;
|
||||
for(int j=0;j<4;j++) {
|
||||
CharType c = GETCHAR(i+j);
|
||||
if (c==0) {
|
||||
_make_error("Unterminated String");
|
||||
return;
|
||||
}
|
||||
if (!_is_hex(c)) {
|
||||
if (j==0 || !(j&1)) {
|
||||
_make_error("Malformed hex constant in string");
|
||||
return;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
CharType v;
|
||||
if (c>='0' && c<='9') {
|
||||
v=c-'0';
|
||||
} else if (c>='a' && c<='f') {
|
||||
v=c-'a';
|
||||
v+=10;
|
||||
} else if (c>='A' && c<='F') {
|
||||
v=c-'A';
|
||||
v+=10;
|
||||
} else {
|
||||
ERR_PRINT("BUG");
|
||||
v=0;
|
||||
}
|
||||
|
||||
res<<=4;
|
||||
res|=v;
|
||||
|
||||
read++;
|
||||
}
|
||||
i+=read-1;
|
||||
|
||||
|
||||
} break;
|
||||
default: {
|
||||
|
||||
_make_error("Invalid escape sequence");
|
||||
return;
|
||||
} break;
|
||||
}
|
||||
|
||||
str+=res;
|
||||
|
||||
} else {
|
||||
str+=CharType(GETCHAR(i));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
INCPOS(i);
|
||||
|
||||
if (is_node_path) {
|
||||
_make_constant(NodePath(str));
|
||||
} else {
|
||||
_make_constant(str);
|
||||
}
|
||||
|
||||
} break;
|
||||
default: {
|
||||
|
||||
if (_is_number(GETCHAR(0)) || (GETCHAR(0)=='.' && _is_number(GETCHAR(1)))) {
|
||||
// parse number
|
||||
bool period_found=false;
|
||||
bool exponent_found=false;
|
||||
bool hexa_found=false;
|
||||
bool sign_found=false;
|
||||
|
||||
String str;
|
||||
int i=0;
|
||||
|
||||
while(true) {
|
||||
if (GETCHAR(i)=='.') {
|
||||
if (period_found || exponent_found) {
|
||||
_make_error("Invalid numeric constant at '.'");
|
||||
return;
|
||||
}
|
||||
period_found=true;
|
||||
} else if (GETCHAR(i)=='x') {
|
||||
if (hexa_found || str.length()!=1 || !( (i==1 && str[0]=='0') || (i==2 && str[1]=='0' && str[0]=='-') ) ) {
|
||||
_make_error("Invalid numeric constant at 'x'");
|
||||
return;
|
||||
}
|
||||
hexa_found=true;
|
||||
} else if (!hexa_found && GETCHAR(i)=='e') {
|
||||
if (hexa_found || exponent_found) {
|
||||
_make_error("Invalid numeric constant at 'e'");
|
||||
return;
|
||||
}
|
||||
exponent_found=true;
|
||||
} else if (_is_number(GETCHAR(i))) {
|
||||
//all ok
|
||||
} else if (hexa_found && _is_hex(GETCHAR(i))) {
|
||||
|
||||
} else if ((GETCHAR(i)=='-' || GETCHAR(i)=='+') && exponent_found) {
|
||||
if (sign_found) {
|
||||
_make_error("Invalid numeric constant at '-'");
|
||||
return;
|
||||
}
|
||||
sign_found=true;
|
||||
} else
|
||||
break;
|
||||
|
||||
str+=CharType(GETCHAR(i));
|
||||
i++;
|
||||
}
|
||||
|
||||
if (!( _is_number(str[str.length()-1]) || (hexa_found && _is_hex(str[str.length()-1])))) {
|
||||
_make_error("Invalid numeric constant: "+str);
|
||||
return;
|
||||
}
|
||||
|
||||
INCPOS(str.length());
|
||||
if (hexa_found) {
|
||||
int val = str.hex_to_int();
|
||||
_make_constant(val);
|
||||
} else if (period_found) {
|
||||
real_t val = str.to_double();
|
||||
//print_line("*%*%*%*% to convert: "+str+" result: "+rtos(val));
|
||||
_make_constant(val);
|
||||
} else {
|
||||
int val = str.to_int();
|
||||
_make_constant(val);
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (GETCHAR(0)=='.') {
|
||||
//parse period
|
||||
_make_token(TK_PERIOD);
|
||||
break;
|
||||
}
|
||||
|
||||
if (_is_text_char(GETCHAR(0))) {
|
||||
// parse identifier
|
||||
String str;
|
||||
str+=CharType(GETCHAR(0));
|
||||
|
||||
int i=1;
|
||||
while(_is_text_char(GETCHAR(i))) {
|
||||
str+=CharType(GETCHAR(i));
|
||||
i++;
|
||||
}
|
||||
|
||||
bool identifier=false;
|
||||
|
||||
if (str=="null") {
|
||||
_make_constant(Variant());
|
||||
|
||||
} else if (str=="true") {
|
||||
_make_constant(true);
|
||||
|
||||
} else if (str=="false") {
|
||||
_make_constant(false);
|
||||
} else {
|
||||
|
||||
bool found=false;
|
||||
|
||||
struct _bit { Variant::Type type; const char *text;};
|
||||
//built in types
|
||||
|
||||
static const _bit type_list[]={
|
||||
//types
|
||||
{Variant::BOOL,"bool"},
|
||||
{Variant::INT,"int"},
|
||||
{Variant::REAL,"float"},
|
||||
{Variant::STRING,"String"},
|
||||
{Variant::VECTOR2,"vec2"},
|
||||
{Variant::VECTOR2,"Vector2"},
|
||||
{Variant::RECT2,"Rect2"},
|
||||
{Variant::MATRIX32,"Matrix32"},
|
||||
{Variant::MATRIX32,"mat32"},
|
||||
{Variant::VECTOR3,"vec3"},
|
||||
{Variant::VECTOR3,"Vector3"},
|
||||
{Variant::_AABB,"AABB"},
|
||||
{Variant::_AABB,"Rect3"},
|
||||
{Variant::PLANE,"Plane"},
|
||||
{Variant::QUAT,"Quat"},
|
||||
{Variant::MATRIX3,"mat3"},
|
||||
{Variant::MATRIX3,"Matrix3"},
|
||||
{Variant::TRANSFORM,"trn"},
|
||||
{Variant::TRANSFORM,"Transform"},
|
||||
{Variant::COLOR,"Color"},
|
||||
{Variant::IMAGE,"Image"},
|
||||
{Variant::_RID,"RID"},
|
||||
{Variant::OBJECT,"Object"},
|
||||
{Variant::INPUT_EVENT,"InputEvent"},
|
||||
{Variant::DICTIONARY,"dict"},
|
||||
{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::VARIANT_MAX,NULL},
|
||||
};
|
||||
|
||||
{
|
||||
|
||||
|
||||
int idx=0;
|
||||
|
||||
while(type_list[idx].text) {
|
||||
|
||||
if (str==type_list[idx].text) {
|
||||
_make_type(type_list[idx].type);
|
||||
found=true;
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
|
||||
//built in func?
|
||||
|
||||
for(int i=0;i<GDFunctions::FUNC_MAX;i++) {
|
||||
|
||||
if (str==GDFunctions::get_func_name(GDFunctions::Function(i))) {
|
||||
|
||||
_make_built_in_func(GDFunctions::Function(i));
|
||||
found=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//keywor
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
|
||||
|
||||
struct _kws { Token token; const char *text;};
|
||||
|
||||
static const _kws keyword_list[]={
|
||||
//ops
|
||||
{TK_OP_IN,"in"},
|
||||
{TK_OP_NOT,"not"},
|
||||
{TK_OP_OR,"or"},
|
||||
{TK_OP_AND,"and"},
|
||||
//func
|
||||
{TK_PR_FUNCTION,"func"},
|
||||
{TK_PR_FUNCTION,"function"},
|
||||
{TK_PR_CLASS,"class"},
|
||||
{TK_PR_EXTENDS,"extends"},
|
||||
{TK_PR_TOOL,"tool"},
|
||||
{TK_PR_STATIC,"static"},
|
||||
{TK_PR_EXPORT,"export"},
|
||||
{TK_PR_VAR,"var"},
|
||||
{TK_PR_PRELOAD,"preload"},
|
||||
{TK_PR_ASSERT,"assert"},
|
||||
{TK_PR_CONST,"const"},
|
||||
//controlflow
|
||||
{TK_CF_IF,"if"},
|
||||
{TK_CF_ELIF,"elif"},
|
||||
{TK_CF_ELSE,"else"},
|
||||
{TK_CF_FOR,"for"},
|
||||
{TK_CF_WHILE,"while"},
|
||||
{TK_CF_DO,"do"},
|
||||
{TK_CF_SWITCH,"switch"},
|
||||
{TK_CF_BREAK,"break"},
|
||||
{TK_CF_CONTINUE,"continue"},
|
||||
{TK_CF_RETURN,"return"},
|
||||
{TK_CF_PASS,"pass"},
|
||||
{TK_SELF,"self"},
|
||||
{TK_ERROR,NULL}
|
||||
};
|
||||
|
||||
int idx=0;
|
||||
found=false;
|
||||
|
||||
while(keyword_list[idx].text) {
|
||||
|
||||
if (str==keyword_list[idx].text) {
|
||||
_make_token(keyword_list[idx].token);
|
||||
found=true;
|
||||
break;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
identifier=true;
|
||||
}
|
||||
|
||||
|
||||
if (identifier) {
|
||||
_make_identifier(str);
|
||||
}
|
||||
INCPOS(str.length());
|
||||
return;
|
||||
}
|
||||
|
||||
_make_error("Unknown character");
|
||||
return;
|
||||
|
||||
} break;
|
||||
}
|
||||
|
||||
INCPOS(1);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GDTokenizer::set_code(const String& p_code) {
|
||||
|
||||
code=p_code;
|
||||
len = p_code.length();
|
||||
if (len) {
|
||||
_code=&code[0];
|
||||
} else {
|
||||
_code=NULL;
|
||||
}
|
||||
code_pos=0;
|
||||
line=1; //it is stand-ar-ized that lines begin in 1 in code..
|
||||
column=0;
|
||||
tk_rb_pos=0;
|
||||
error_flag=false;
|
||||
last_error="";
|
||||
for(int i=0;i<MAX_LOOKAHEAD+1;i++)
|
||||
_advance();
|
||||
}
|
||||
|
||||
GDTokenizer::Token GDTokenizer::get_token(int p_offset) const {
|
||||
ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, TK_ERROR);
|
||||
ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, TK_ERROR);
|
||||
|
||||
int ofs = (TK_RB_SIZE + tk_rb_pos + p_offset - MAX_LOOKAHEAD -1)%TK_RB_SIZE;
|
||||
return tk_rb[ofs].type;
|
||||
}
|
||||
|
||||
int GDTokenizer::get_token_line(int p_offset) const {
|
||||
ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, -1);
|
||||
ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, -1);
|
||||
|
||||
int ofs = (TK_RB_SIZE + tk_rb_pos + p_offset - MAX_LOOKAHEAD -1)%TK_RB_SIZE;
|
||||
return tk_rb[ofs].line;
|
||||
}
|
||||
|
||||
int GDTokenizer::get_token_column(int p_offset) const {
|
||||
ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, -1);
|
||||
ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, -1);
|
||||
|
||||
int ofs = (TK_RB_SIZE + tk_rb_pos + p_offset - MAX_LOOKAHEAD -1)%TK_RB_SIZE;
|
||||
return tk_rb[ofs].col;
|
||||
}
|
||||
|
||||
const Variant& GDTokenizer::get_token_constant(int p_offset) const {
|
||||
ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, tk_rb[0].constant);
|
||||
ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, tk_rb[0].constant);
|
||||
|
||||
int ofs = (TK_RB_SIZE + tk_rb_pos + p_offset - MAX_LOOKAHEAD -1)%TK_RB_SIZE;
|
||||
ERR_FAIL_COND_V(tk_rb[ofs].type!=TK_CONSTANT,tk_rb[0].constant);
|
||||
return tk_rb[ofs].constant;
|
||||
}
|
||||
StringName GDTokenizer::get_token_identifier(int p_offset) const {
|
||||
|
||||
ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, StringName());
|
||||
ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, StringName());
|
||||
|
||||
int ofs = (TK_RB_SIZE + tk_rb_pos + p_offset - MAX_LOOKAHEAD -1)%TK_RB_SIZE;
|
||||
ERR_FAIL_COND_V(tk_rb[ofs].type!=TK_IDENTIFIER,StringName());
|
||||
return tk_rb[ofs].identifier;
|
||||
|
||||
}
|
||||
|
||||
GDFunctions::Function GDTokenizer::get_token_built_in_func(int p_offset) const {
|
||||
|
||||
ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, GDFunctions::FUNC_MAX);
|
||||
ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, GDFunctions::FUNC_MAX);
|
||||
|
||||
int ofs = (TK_RB_SIZE + tk_rb_pos + p_offset - MAX_LOOKAHEAD -1)%TK_RB_SIZE;
|
||||
ERR_FAIL_COND_V(tk_rb[ofs].type!=TK_BUILT_IN_FUNC,GDFunctions::FUNC_MAX);
|
||||
return tk_rb[ofs].func;
|
||||
|
||||
}
|
||||
|
||||
Variant::Type GDTokenizer::get_token_type(int p_offset) const {
|
||||
|
||||
ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, Variant::NIL);
|
||||
ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, Variant::NIL);
|
||||
|
||||
int ofs = (TK_RB_SIZE + tk_rb_pos + p_offset - MAX_LOOKAHEAD -1)%TK_RB_SIZE;
|
||||
ERR_FAIL_COND_V(tk_rb[ofs].type!=TK_BUILT_IN_TYPE,Variant::NIL);
|
||||
return tk_rb[ofs].vtype;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int GDTokenizer::get_token_line_indent(int p_offset) const {
|
||||
|
||||
ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, 0);
|
||||
ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, 0);
|
||||
|
||||
int ofs = (TK_RB_SIZE + tk_rb_pos + p_offset - MAX_LOOKAHEAD -1)%TK_RB_SIZE;
|
||||
ERR_FAIL_COND_V(tk_rb[ofs].type!=TK_NEWLINE,0);
|
||||
return tk_rb[ofs].constant;
|
||||
|
||||
}
|
||||
|
||||
String GDTokenizer::get_token_error(int p_offset) const {
|
||||
|
||||
ERR_FAIL_COND_V( p_offset <= -MAX_LOOKAHEAD, String());
|
||||
ERR_FAIL_COND_V( p_offset >= MAX_LOOKAHEAD, String());
|
||||
|
||||
int ofs = (TK_RB_SIZE + tk_rb_pos + p_offset - MAX_LOOKAHEAD -1)%TK_RB_SIZE;
|
||||
ERR_FAIL_COND_V(tk_rb[ofs].type!=TK_ERROR,String());
|
||||
return tk_rb[ofs].constant;
|
||||
}
|
||||
|
||||
void GDTokenizer::advance(int p_amount) {
|
||||
|
||||
ERR_FAIL_COND( p_amount <=0 );
|
||||
for(int i=0;i<p_amount;i++)
|
||||
_advance();
|
||||
}
|
||||
181
modules/gdscript/gd_tokenizer.h
Normal file
181
modules/gdscript/gd_tokenizer.h
Normal file
@@ -0,0 +1,181 @@
|
||||
/*************************************************************************/
|
||||
/* gd_tokenizer.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#ifndef GD_TOKENIZER_H
|
||||
#define GD_TOKENIZER_H
|
||||
|
||||
#include "ustring.h"
|
||||
#include "variant.h"
|
||||
#include "string_db.h"
|
||||
#include "gd_functions.h"
|
||||
class GDTokenizer {
|
||||
public:
|
||||
|
||||
enum Token {
|
||||
|
||||
TK_EMPTY,
|
||||
TK_IDENTIFIER,
|
||||
TK_CONSTANT,
|
||||
TK_SELF,
|
||||
TK_BUILT_IN_TYPE,
|
||||
TK_BUILT_IN_FUNC,
|
||||
TK_OP_IN,
|
||||
TK_OP_EQUAL,
|
||||
TK_OP_NOT_EQUAL,
|
||||
TK_OP_LESS,
|
||||
TK_OP_LESS_EQUAL,
|
||||
TK_OP_GREATER,
|
||||
TK_OP_GREATER_EQUAL,
|
||||
TK_OP_AND,
|
||||
TK_OP_OR,
|
||||
TK_OP_NOT,
|
||||
TK_OP_ADD,
|
||||
TK_OP_SUB,
|
||||
TK_OP_MUL,
|
||||
TK_OP_DIV,
|
||||
TK_OP_MOD,
|
||||
TK_OP_SHIFT_LEFT,
|
||||
TK_OP_SHIFT_RIGHT,
|
||||
TK_OP_ASSIGN,
|
||||
TK_OP_ASSIGN_ADD,
|
||||
TK_OP_ASSIGN_SUB,
|
||||
TK_OP_ASSIGN_MUL,
|
||||
TK_OP_ASSIGN_DIV,
|
||||
TK_OP_ASSIGN_MOD,
|
||||
TK_OP_ASSIGN_SHIFT_LEFT,
|
||||
TK_OP_ASSIGN_SHIFT_RIGHT,
|
||||
TK_OP_ASSIGN_BIT_AND,
|
||||
TK_OP_ASSIGN_BIT_OR,
|
||||
TK_OP_ASSIGN_BIT_XOR,
|
||||
TK_OP_BIT_AND,
|
||||
TK_OP_BIT_OR,
|
||||
TK_OP_BIT_XOR,
|
||||
TK_OP_BIT_INVERT,
|
||||
//TK_OP_PLUS_PLUS,
|
||||
//TK_OP_MINUS_MINUS,
|
||||
TK_CF_IF,
|
||||
TK_CF_ELIF,
|
||||
TK_CF_ELSE,
|
||||
TK_CF_FOR,
|
||||
TK_CF_DO,
|
||||
TK_CF_WHILE,
|
||||
TK_CF_SWITCH,
|
||||
TK_CF_CASE,
|
||||
TK_CF_BREAK,
|
||||
TK_CF_CONTINUE,
|
||||
TK_CF_PASS,
|
||||
TK_CF_RETURN,
|
||||
TK_PR_FUNCTION,
|
||||
TK_PR_CLASS,
|
||||
TK_PR_EXTENDS,
|
||||
TK_PR_TOOL,
|
||||
TK_PR_STATIC,
|
||||
TK_PR_EXPORT,
|
||||
TK_PR_CONST,
|
||||
TK_PR_VAR,
|
||||
TK_PR_PRELOAD,
|
||||
TK_PR_ASSERT,
|
||||
TK_BRACKET_OPEN,
|
||||
TK_BRACKET_CLOSE,
|
||||
TK_CURLY_BRACKET_OPEN,
|
||||
TK_CURLY_BRACKET_CLOSE,
|
||||
TK_PARENTHESIS_OPEN,
|
||||
TK_PARENTHESIS_CLOSE,
|
||||
TK_COMMA,
|
||||
TK_SEMICOLON,
|
||||
TK_PERIOD,
|
||||
TK_QUESTION_MARK,
|
||||
TK_COLON,
|
||||
TK_NEWLINE,
|
||||
TK_ERROR,
|
||||
TK_EOF,
|
||||
TK_MAX
|
||||
};
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
static const char* token_names[TK_MAX];
|
||||
enum {
|
||||
MAX_LOOKAHEAD=4,
|
||||
TK_RB_SIZE=MAX_LOOKAHEAD*2+1
|
||||
|
||||
};
|
||||
|
||||
struct TokenData {
|
||||
Token type;
|
||||
StringName identifier; //for identifier types
|
||||
Variant constant; //for constant types
|
||||
union {
|
||||
Variant::Type vtype; //for type types
|
||||
GDFunctions::Function func; //function for built in functions
|
||||
};
|
||||
int line,col;
|
||||
TokenData() { type = TK_EMPTY; line=col=0; vtype=Variant::NIL; }
|
||||
};
|
||||
|
||||
void _make_token(Token p_type);
|
||||
void _make_newline(int p_spaces=0);
|
||||
void _make_identifier(const StringName& p_identifier);
|
||||
void _make_built_in_func(GDFunctions::Function p_func);
|
||||
void _make_constant(const Variant& p_constant);
|
||||
void _make_type(const Variant::Type& p_type);
|
||||
void _make_error(const String& p_error);
|
||||
|
||||
String code;
|
||||
int len;
|
||||
int code_pos;
|
||||
const CharType *_code;
|
||||
int line;
|
||||
int column;
|
||||
TokenData tk_rb[TK_RB_SIZE*2+1];
|
||||
int tk_rb_pos;
|
||||
String last_error;
|
||||
bool error_flag;
|
||||
|
||||
void _advance();
|
||||
public:
|
||||
|
||||
static const char *get_token_name(Token p_token);
|
||||
|
||||
void set_code(const String& p_code);
|
||||
Token get_token(int p_offset=0) const;
|
||||
const Variant& get_token_constant(int p_offset=0) const;
|
||||
StringName get_token_identifier(int p_offset=0) const;
|
||||
GDFunctions::Function get_token_built_in_func(int p_offset=0) const;
|
||||
Variant::Type get_token_type(int p_offset=0) const;
|
||||
int get_token_line(int p_offset=0) const;
|
||||
int get_token_column(int p_offset=0) const;
|
||||
int get_token_line_indent(int p_offset=0) const;
|
||||
|
||||
String get_token_error(int p_offset=0) const;
|
||||
void advance(int p_amount=1);
|
||||
};
|
||||
|
||||
#endif // TOKENIZER_H
|
||||
46
modules/gdscript/register_types.cpp
Normal file
46
modules/gdscript/register_types.cpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*************************************************/
|
||||
/* register_script_types.cpp */
|
||||
/*************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/*************************************************/
|
||||
/* Source code within this file is: */
|
||||
/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
|
||||
/* All Rights Reserved. */
|
||||
/*************************************************/
|
||||
|
||||
#include "register_types.h"
|
||||
|
||||
#include "gd_script.h"
|
||||
#include "io/resource_loader.h"
|
||||
|
||||
GDScriptLanguage *script_language_gd=NULL;
|
||||
ResourceFormatLoaderGDScript *resource_loader_gd=NULL;
|
||||
ResourceFormatSaverGDScript *resource_saver_gd=NULL;
|
||||
|
||||
void register_gdscript_types() {
|
||||
|
||||
|
||||
script_language_gd=memnew( GDScriptLanguage );
|
||||
script_language_gd->init();
|
||||
ScriptServer::register_language(script_language_gd);
|
||||
ObjectTypeDB::register_type<GDScript>();
|
||||
resource_loader_gd=memnew( ResourceFormatLoaderGDScript );
|
||||
ResourceLoader::add_resource_format_loader(resource_loader_gd);
|
||||
resource_saver_gd=memnew( ResourceFormatSaverGDScript );
|
||||
ResourceSaver::add_resource_format_saver(resource_saver_gd);
|
||||
|
||||
}
|
||||
void unregister_gdscript_types() {
|
||||
|
||||
|
||||
|
||||
|
||||
if (script_language_gd)
|
||||
memdelete( script_language_gd );
|
||||
if (resource_loader_gd)
|
||||
memdelete( resource_loader_gd );
|
||||
if (resource_saver_gd)
|
||||
memdelete( resource_saver_gd );
|
||||
|
||||
}
|
||||
30
modules/gdscript/register_types.h
Normal file
30
modules/gdscript/register_types.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
void register_gdscript_types();
|
||||
void unregister_gdscript_types();
|
||||
7
modules/multiscript/SCsub
Normal file
7
modules/multiscript/SCsub
Normal file
@@ -0,0 +1,7 @@
|
||||
Import('env')
|
||||
|
||||
env.add_source_files(env.modules_sources,"*.cpp")
|
||||
|
||||
Export('env')
|
||||
|
||||
|
||||
11
modules/multiscript/config.py
Normal file
11
modules/multiscript/config.py
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
|
||||
def can_build(platform):
|
||||
return True
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
498
modules/multiscript/multi_script.cpp
Normal file
498
modules/multiscript/multi_script.cpp
Normal file
@@ -0,0 +1,498 @@
|
||||
/*************************************************************************/
|
||||
/* multi_script.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#include "multi_script.h"
|
||||
|
||||
bool MultiScriptInstance::set(const StringName& p_name, const Variant& p_value) {
|
||||
|
||||
ScriptInstance **sarr = instances.ptr();
|
||||
int sc = instances.size();
|
||||
|
||||
for(int i=0;i<sc;i++) {
|
||||
|
||||
if (!sarr[i])
|
||||
continue;
|
||||
|
||||
bool found = sarr[i]->set(p_name,p_value);
|
||||
if (found)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (String(p_name).begins_with("script_")) {
|
||||
bool valid;
|
||||
owner->set(p_name,p_value,&valid);
|
||||
return valid;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool MultiScriptInstance::get(const StringName& p_name, Variant &r_ret) const{
|
||||
|
||||
ScriptInstance **sarr = instances.ptr();
|
||||
int sc = instances.size();
|
||||
|
||||
for(int i=0;i<sc;i++) {
|
||||
|
||||
if (!sarr[i])
|
||||
continue;
|
||||
|
||||
bool found = sarr[i]->get(p_name,r_ret);
|
||||
if (found)
|
||||
return true;
|
||||
}
|
||||
if (String(p_name).begins_with("script_")) {
|
||||
bool valid;
|
||||
r_ret=owner->get(p_name,&valid);
|
||||
return valid;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
void MultiScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const{
|
||||
|
||||
ScriptInstance **sarr = instances.ptr();
|
||||
int sc = instances.size();
|
||||
|
||||
|
||||
Set<String> existing;
|
||||
|
||||
for(int i=0;i<sc;i++) {
|
||||
|
||||
if (!sarr[i])
|
||||
continue;
|
||||
|
||||
List<PropertyInfo> pl;
|
||||
sarr[i]->get_property_list(&pl);
|
||||
|
||||
for(List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
|
||||
|
||||
if (existing.has(E->get().name))
|
||||
continue;
|
||||
|
||||
p_properties->push_back(E->get());
|
||||
existing.insert(E->get().name);
|
||||
}
|
||||
}
|
||||
|
||||
p_properties->push_back( PropertyInfo(Variant::NIL,"Scripts",PROPERTY_HINT_NONE,String(),PROPERTY_USAGE_CATEGORY) );
|
||||
|
||||
for(int i=0;i<owner->scripts.size();i++) {
|
||||
|
||||
p_properties->push_back( PropertyInfo(Variant::OBJECT,"script_"+String::chr('a'+i),PROPERTY_HINT_RESOURCE_TYPE,"Script",PROPERTY_USAGE_EDITOR) );
|
||||
|
||||
}
|
||||
|
||||
if (owner->scripts.size()<25) {
|
||||
|
||||
p_properties->push_back( PropertyInfo(Variant::OBJECT,"script_"+String::chr('a'+(owner->scripts.size())),PROPERTY_HINT_RESOURCE_TYPE,"Script",PROPERTY_USAGE_EDITOR) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MultiScriptInstance::get_method_list(List<MethodInfo> *p_list) const{
|
||||
|
||||
ScriptInstance **sarr = instances.ptr();
|
||||
int sc = instances.size();
|
||||
|
||||
|
||||
Set<StringName> existing;
|
||||
|
||||
for(int i=0;i<sc;i++) {
|
||||
|
||||
if (!sarr[i])
|
||||
continue;
|
||||
|
||||
List<MethodInfo> ml;
|
||||
sarr[i]->get_method_list(&ml);
|
||||
|
||||
for(List<MethodInfo>::Element *E=ml.front();E;E=E->next()) {
|
||||
|
||||
if (existing.has(E->get().name))
|
||||
continue;
|
||||
|
||||
p_list->push_back(E->get());
|
||||
existing.insert(E->get().name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
bool MultiScriptInstance::has_method(const StringName& p_method) const{
|
||||
|
||||
ScriptInstance **sarr = instances.ptr();
|
||||
int sc = instances.size();
|
||||
|
||||
for(int i=0;i<sc;i++) {
|
||||
|
||||
if (!sarr[i])
|
||||
continue;
|
||||
|
||||
if (sarr[i]->has_method(p_method))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
Variant MultiScriptInstance::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) {
|
||||
|
||||
ScriptInstance **sarr = instances.ptr();
|
||||
int sc = instances.size();
|
||||
|
||||
for(int i=0;i<sc;i++) {
|
||||
|
||||
if (!sarr[i])
|
||||
continue;
|
||||
|
||||
Variant r = sarr[i]->call(p_method,p_args,p_argcount,r_error);
|
||||
if (r_error.error==Variant::CallError::CALL_OK)
|
||||
return r;
|
||||
else if (r_error.error!=Variant::CallError::CALL_ERROR_INVALID_METHOD)
|
||||
return r;
|
||||
}
|
||||
|
||||
r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
|
||||
return Variant();
|
||||
|
||||
}
|
||||
|
||||
void MultiScriptInstance::call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount){
|
||||
|
||||
ScriptInstance **sarr = instances.ptr();
|
||||
int sc = instances.size();
|
||||
|
||||
for(int i=0;i<sc;i++) {
|
||||
|
||||
if (!sarr[i])
|
||||
continue;
|
||||
|
||||
sarr[i]->call_multilevel(p_method,p_args,p_argcount);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
void MultiScriptInstance::notification(int p_notification){
|
||||
|
||||
ScriptInstance **sarr = instances.ptr();
|
||||
int sc = instances.size();
|
||||
|
||||
for(int i=0;i<sc;i++) {
|
||||
|
||||
if (!sarr[i])
|
||||
continue;
|
||||
|
||||
sarr[i]->notification(p_notification);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
Ref<Script> MultiScriptInstance::get_script() const {
|
||||
|
||||
return owner;
|
||||
}
|
||||
|
||||
ScriptLanguage *MultiScriptInstance::get_language() {
|
||||
|
||||
return MultiScriptLanguage::get_singleton();
|
||||
}
|
||||
|
||||
MultiScriptInstance::~MultiScriptInstance() {
|
||||
|
||||
owner->remove_instance(object);
|
||||
}
|
||||
|
||||
|
||||
///////////////////
|
||||
|
||||
|
||||
bool MultiScript::is_tool() const {
|
||||
|
||||
for(int i=0;i<scripts.size();i++) {
|
||||
|
||||
if (scripts[i]->is_tool())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MultiScript::_set(const StringName& p_name, const Variant& p_value) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
String s = String(p_name);
|
||||
if (s.begins_with("script_")) {
|
||||
|
||||
int idx = s[7];
|
||||
if (idx==0)
|
||||
return false;
|
||||
idx-='a';
|
||||
|
||||
ERR_FAIL_COND_V(idx<0,false);
|
||||
|
||||
Ref<Script> s = p_value;
|
||||
|
||||
if (idx<scripts.size()) {
|
||||
|
||||
|
||||
if (s.is_null())
|
||||
remove_script(idx);
|
||||
else
|
||||
set_script(idx,s);
|
||||
} else if (idx==scripts.size()) {
|
||||
if (s.is_null())
|
||||
return false;
|
||||
add_script(s);
|
||||
} else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MultiScript::_get(const StringName& p_name,Variant &r_ret) const{
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
String s = String(p_name);
|
||||
if (s.begins_with("script_")) {
|
||||
|
||||
int idx = s[7];
|
||||
if (idx==0)
|
||||
return false;
|
||||
idx-='a';
|
||||
|
||||
ERR_FAIL_COND_V(idx<0,false);
|
||||
|
||||
if (idx<scripts.size()) {
|
||||
|
||||
r_ret=get_script(idx);
|
||||
return true;
|
||||
} else if (idx==scripts.size()) {
|
||||
r_ret=Ref<Script>();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
void MultiScript::_get_property_list( List<PropertyInfo> *p_list) const{
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
for(int i=0;i<scripts.size();i++) {
|
||||
|
||||
p_list->push_back( PropertyInfo(Variant::OBJECT,"script_"+String::chr('a'+i),PROPERTY_HINT_RESOURCE_TYPE,"Script") );
|
||||
|
||||
}
|
||||
|
||||
if (scripts.size()<25) {
|
||||
|
||||
p_list->push_back( PropertyInfo(Variant::OBJECT,"script_"+String::chr('a'+(scripts.size())),PROPERTY_HINT_RESOURCE_TYPE,"Script") );
|
||||
}
|
||||
}
|
||||
|
||||
void MultiScript::set_script(int p_idx,const Ref<Script>& p_script ) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
ERR_FAIL_INDEX(p_idx,scripts.size());
|
||||
ERR_FAIL_COND( p_script.is_null() );
|
||||
|
||||
scripts[p_idx]=p_script;
|
||||
Ref<Script> s=p_script;
|
||||
|
||||
for (Map<Object*,MultiScriptInstance*>::Element *E=instances.front();E;E=E->next()) {
|
||||
|
||||
|
||||
MultiScriptInstance*msi=E->get();
|
||||
ScriptInstance *si = msi->instances[p_idx];
|
||||
if (si) {
|
||||
msi->instances[p_idx]=NULL;
|
||||
memdelete(si);
|
||||
}
|
||||
|
||||
if (p_script->can_instance())
|
||||
msi->instances[p_idx]=s->instance_create(msi->object);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
Ref<Script> MultiScript::get_script(int p_idx) const{
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
ERR_FAIL_INDEX_V(p_idx,scripts.size(),Ref<Script>());
|
||||
|
||||
return scripts[p_idx];
|
||||
|
||||
}
|
||||
void MultiScript::add_script(const Ref<Script>& p_script){
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
ERR_FAIL_COND( p_script.is_null() );
|
||||
scripts.push_back(p_script);
|
||||
Ref<Script> s=p_script;
|
||||
|
||||
for (Map<Object*,MultiScriptInstance*>::Element *E=instances.front();E;E=E->next()) {
|
||||
|
||||
|
||||
MultiScriptInstance*msi=E->get();
|
||||
|
||||
if (p_script->can_instance())
|
||||
msi->instances.push_back( s->instance_create(msi->object) );
|
||||
else
|
||||
msi->instances.push_back(NULL);
|
||||
|
||||
msi->object->_change_notify();
|
||||
|
||||
}
|
||||
|
||||
|
||||
_change_notify();
|
||||
}
|
||||
|
||||
|
||||
void MultiScript::remove_script(int p_idx) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
|
||||
ERR_FAIL_INDEX(p_idx,scripts.size());
|
||||
|
||||
scripts.remove(p_idx);
|
||||
|
||||
for (Map<Object*,MultiScriptInstance*>::Element *E=instances.front();E;E=E->next()) {
|
||||
|
||||
|
||||
MultiScriptInstance*msi=E->get();
|
||||
ScriptInstance *si = msi->instances[p_idx];
|
||||
msi->instances.remove(p_idx);
|
||||
if (si) {
|
||||
memdelete(si);
|
||||
}
|
||||
|
||||
msi->object->_change_notify();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void MultiScript::remove_instance(Object *p_object) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
instances.erase(p_object);
|
||||
}
|
||||
|
||||
bool MultiScript::can_instance() const {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
StringName MultiScript::get_instance_base_type() const {
|
||||
|
||||
return StringName();
|
||||
}
|
||||
ScriptInstance* MultiScript::instance_create(Object *p_this) {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
MultiScriptInstance *msi = memnew( MultiScriptInstance );
|
||||
msi->object=p_this;
|
||||
msi->owner=this;
|
||||
for(int i=0;i<scripts.size();i++) {
|
||||
|
||||
ScriptInstance *si;
|
||||
|
||||
if (scripts[i]->can_instance())
|
||||
si = scripts[i]->instance_create(p_this);
|
||||
else
|
||||
si=NULL;
|
||||
|
||||
msi->instances.push_back(si);
|
||||
}
|
||||
|
||||
instances[p_this]=msi;
|
||||
p_this->_change_notify();
|
||||
return msi;
|
||||
}
|
||||
bool MultiScript::instance_has(const Object *p_this) const {
|
||||
|
||||
_THREAD_SAFE_METHOD_
|
||||
return instances.has((Object*)p_this);
|
||||
}
|
||||
|
||||
bool MultiScript::has_source_code() const {
|
||||
|
||||
return false;
|
||||
}
|
||||
String MultiScript::get_source_code() const {
|
||||
|
||||
return "";
|
||||
}
|
||||
void MultiScript::set_source_code(const String& p_code) {
|
||||
|
||||
|
||||
}
|
||||
Error MultiScript::reload() {
|
||||
|
||||
for(int i=0;i<scripts.size();i++)
|
||||
scripts[i]->reload();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
String MultiScript::get_node_type() const {
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void MultiScript::_bind_methods() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
ScriptLanguage *MultiScript::get_language() const {
|
||||
|
||||
return MultiScriptLanguage::get_singleton();
|
||||
}
|
||||
|
||||
|
||||
///////////////
|
||||
|
||||
MultiScript::MultiScript() {
|
||||
}
|
||||
|
||||
|
||||
MultiScriptLanguage *MultiScriptLanguage::singleton=NULL;
|
||||
158
modules/multiscript/multi_script.h
Normal file
158
modules/multiscript/multi_script.h
Normal file
@@ -0,0 +1,158 @@
|
||||
/*************************************************************************/
|
||||
/* multi_script.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
#ifndef MULTI_SCRIPT_H
|
||||
#define MULTI_SCRIPT_H
|
||||
|
||||
#include "script_language.h"
|
||||
#include "os/thread_safe.h"
|
||||
|
||||
class MultiScript;
|
||||
|
||||
class MultiScriptInstance : public ScriptInstance {
|
||||
friend class MultiScript;
|
||||
mutable Vector<ScriptInstance*> instances;
|
||||
Object *object;
|
||||
mutable MultiScript *owner;
|
||||
|
||||
public:
|
||||
virtual bool set(const StringName& p_name, const Variant& p_value);
|
||||
virtual bool get(const StringName& p_name, Variant &r_ret) const;
|
||||
virtual void get_property_list(List<PropertyInfo> *p_properties) const;
|
||||
|
||||
virtual void get_method_list(List<MethodInfo> *p_list) const;
|
||||
virtual bool has_method(const StringName& p_method) const;
|
||||
virtual Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error);
|
||||
virtual void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount);
|
||||
virtual void notification(int p_notification);
|
||||
|
||||
|
||||
virtual Ref<Script> get_script() const;
|
||||
|
||||
virtual ScriptLanguage *get_language();
|
||||
virtual ~MultiScriptInstance();
|
||||
};
|
||||
|
||||
|
||||
class MultiScript : public Script {
|
||||
|
||||
_THREAD_SAFE_CLASS_
|
||||
friend class MultiScriptInstance;
|
||||
OBJ_TYPE( MultiScript,Script);
|
||||
|
||||
Vector<Ref<Script> > scripts;
|
||||
|
||||
Map<Object*,MultiScriptInstance*> instances;
|
||||
protected:
|
||||
|
||||
bool _set(const StringName& p_name, const Variant& p_value);
|
||||
bool _get(const StringName& p_name,Variant &r_ret) const;
|
||||
void _get_property_list( List<PropertyInfo> *p_list) const;
|
||||
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
|
||||
void remove_instance(Object *p_object);
|
||||
virtual bool can_instance() const;
|
||||
|
||||
virtual StringName get_instance_base_type() const;
|
||||
virtual ScriptInstance* instance_create(Object *p_this);
|
||||
virtual bool instance_has(const Object *p_this) const;
|
||||
|
||||
virtual bool has_source_code() const;
|
||||
virtual String get_source_code() const;
|
||||
virtual void set_source_code(const String& p_code);
|
||||
virtual Error reload();
|
||||
|
||||
virtual bool is_tool() const;
|
||||
|
||||
virtual String get_node_type() const;
|
||||
|
||||
|
||||
void set_script(int p_idx,const Ref<Script>& p_script );
|
||||
Ref<Script> get_script(int p_idx) const;
|
||||
void remove_script(int p_idx);
|
||||
void add_script(const Ref<Script>& p_script);
|
||||
|
||||
virtual ScriptLanguage *get_language() const;
|
||||
|
||||
MultiScript();
|
||||
};
|
||||
|
||||
|
||||
class MultiScriptLanguage : public ScriptLanguage {
|
||||
|
||||
static MultiScriptLanguage *singleton;
|
||||
public:
|
||||
|
||||
static _FORCE_INLINE_ MultiScriptLanguage *get_singleton() { return singleton; }
|
||||
virtual String get_name() const { return "MultiScript"; }
|
||||
|
||||
/* LANGUAGE FUNCTIONS */
|
||||
virtual void init() {}
|
||||
virtual String get_type() const { return "MultiScript"; }
|
||||
virtual String get_extension() const { return ""; }
|
||||
virtual Error execute_file(const String& p_path) { return OK; }
|
||||
virtual void finish() {}
|
||||
|
||||
/* EDITOR FUNCTIONS */
|
||||
virtual void get_reserved_words(List<String> *p_words) const {}
|
||||
virtual void get_comment_delimiters(List<String> *p_delimiters) const {}
|
||||
virtual void get_string_delimiters(List<String> *p_delimiters) const {}
|
||||
virtual String get_template(const String& p_class_name, const String& p_base_class_name) const { return ""; }
|
||||
virtual bool validate(const String& p_script, int &r_line_error,int &r_col_error,String& r_test_error,const String& p_path="",List<String>* r_fn=NULL) const { return true; }
|
||||
virtual Script *create_script() const { return memnew( MultiScript ); }
|
||||
virtual bool has_named_classes() const { return false; }
|
||||
virtual int find_function(const String& p_function,const String& p_code) const { return -1; }
|
||||
virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const { return ""; }
|
||||
|
||||
/* DEBUGGER FUNCTIONS */
|
||||
|
||||
virtual String debug_get_error() const { return ""; }
|
||||
virtual int debug_get_stack_level_count() const { return 0; }
|
||||
virtual int debug_get_stack_level_line(int p_level) const { return 0; }
|
||||
virtual String debug_get_stack_level_function(int p_level) const { return ""; }
|
||||
virtual String debug_get_stack_level_source(int p_level) const { return ""; }
|
||||
virtual void debug_get_stack_level_locals(int p_level,List<String> *p_locals, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1) {}
|
||||
virtual void debug_get_stack_level_members(int p_level,List<String> *p_members, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1) {}
|
||||
virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1) {}
|
||||
virtual String debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems=-1,int p_max_depth=-1) { return ""; }
|
||||
|
||||
/* LOADER FUNCTIONS */
|
||||
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const {}
|
||||
virtual void get_public_functions(List<MethodInfo> *p_functions) const {}
|
||||
virtual void get_public_constants(List<Pair<String,Variant> > *p_constants) const {}
|
||||
|
||||
MultiScriptLanguage() { singleton=this; }
|
||||
virtual ~MultiScriptLanguage() {};
|
||||
};
|
||||
|
||||
|
||||
#endif // MULTI_SCRIPT_H
|
||||
32
modules/multiscript/register_types.cpp
Normal file
32
modules/multiscript/register_types.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/*************************************************/
|
||||
/* register_script_types.cpp */
|
||||
/*************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/*************************************************/
|
||||
/* Source code within this file is: */
|
||||
/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
|
||||
/* All Rights Reserved. */
|
||||
/*************************************************/
|
||||
|
||||
#include "register_types.h"
|
||||
|
||||
#include "multi_script.h"
|
||||
#include "io/resource_loader.h"
|
||||
|
||||
static MultiScriptLanguage *script_multi_script=NULL;
|
||||
|
||||
void register_multiscript_types() {
|
||||
|
||||
|
||||
script_multi_script = memnew( MultiScriptLanguage );
|
||||
ScriptServer::register_language(script_multi_script);
|
||||
ObjectTypeDB::register_type<MultiScript>();
|
||||
|
||||
|
||||
}
|
||||
void unregister_multiscript_types() {
|
||||
|
||||
if (script_multi_script);
|
||||
memdelete(script_multi_script);
|
||||
}
|
||||
30
modules/multiscript/register_types.h
Normal file
30
modules/multiscript/register_types.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*************************************************************************/
|
||||
/* register_types.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2014 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 */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
void register_multiscript_types();
|
||||
void unregister_multiscript_types();
|
||||
Reference in New Issue
Block a user