diff options
Diffstat (limited to 'script')
-rw-r--r-- | script/SCsub | 16 | ||||
-rw-r--r-- | script/gdscript/SCsub | 7 | ||||
-rw-r--r-- | script/gdscript/gd_compiler.cpp | 1531 | ||||
-rw-r--r-- | script/gdscript/gd_compiler.h | 181 | ||||
-rw-r--r-- | script/gdscript/gd_editor.cpp | 781 | ||||
-rw-r--r-- | script/gdscript/gd_functions.cpp | 1218 | ||||
-rw-r--r-- | script/gdscript/gd_functions.h | 103 | ||||
-rw-r--r-- | script/gdscript/gd_parser.cpp | 2469 | ||||
-rw-r--r-- | script/gdscript/gd_parser.h | 397 | ||||
-rw-r--r-- | script/gdscript/gd_pretty_print.cpp | 34 | ||||
-rw-r--r-- | script/gdscript/gd_pretty_print.h | 40 | ||||
-rw-r--r-- | script/gdscript/gd_script.cpp | 2222 | ||||
-rw-r--r-- | script/gdscript/gd_script.h | 471 | ||||
-rw-r--r-- | script/gdscript/gd_tokenizer.cpp | 973 | ||||
-rw-r--r-- | script/gdscript/gd_tokenizer.h | 181 | ||||
-rw-r--r-- | script/multiscript/SCsub | 7 | ||||
-rw-r--r-- | script/multiscript/multi_script.cpp | 498 | ||||
-rw-r--r-- | script/multiscript/multi_script.h | 157 | ||||
-rw-r--r-- | script/register_script_types.cpp | 66 | ||||
-rw-r--r-- | script/register_script_types.h | 38 | ||||
-rw-r--r-- | script/script_binder.cpp | 13 | ||||
-rw-r--r-- | script/script_binder.h | 15 |
22 files changed, 0 insertions, 11418 deletions
diff --git a/script/SCsub b/script/SCsub deleted file mode 100644 index 7093dee36d..0000000000 --- a/script/SCsub +++ /dev/null @@ -1,16 +0,0 @@ -Import('env') - -env.script_sources=[] -env.add_source_files(env.script_sources,"*.cpp") - -Export('env') - -if (env["gdscript"]=="yes"): - SConscript('gdscript/SCsub'); -SConscript('multiscript/SCsub'); - -lib = env.Library("script",env.script_sources, LIBSUFFIX=env['platform_libsuffix']) - -env.Prepend(LIBS=[lib]) - - diff --git a/script/gdscript/SCsub b/script/gdscript/SCsub deleted file mode 100644 index dd812edec5..0000000000 --- a/script/gdscript/SCsub +++ /dev/null @@ -1,7 +0,0 @@ -Import('env') - -env.add_source_files(env.script_sources,"*.cpp") - -Export('env') - - diff --git a/script/gdscript/gd_compiler.cpp b/script/gdscript/gd_compiler.cpp deleted file mode 100644 index dd2834bf34..0000000000 --- a/script/gdscript/gd_compiler.cpp +++ /dev/null @@ -1,1531 +0,0 @@ -/*************************************************************************/ -/* gd_compiler.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_compiler.h" -#include "gd_script.h" -/* TODO: - - *AND and OR need early abort - -Inheritance properly process (done?) - *create built in initializer and constructor - *assign operators - *build arrays and dictionaries - *call parent constructor - */ - - -void GDCompiler::_set_error(const String& p_error,const GDParser::Node *p_node) { - - if (error!="") - return; - - error=p_error; - err_line=p_node->line; - err_column=p_node->column; -} - -bool GDCompiler::_create_unary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level) { - - ERR_FAIL_COND_V(on->arguments.size()!=1,false); - - int src_address_a = _parse_expression(codegen,on->arguments[0],p_stack_level); - if (src_address_a<0) - return false; - - codegen.opcodes.push_back(GDFunction::OPCODE_OPERATOR); // perform operator - codegen.opcodes.push_back(op); //which operator - codegen.opcodes.push_back(src_address_a); // argument 1 - codegen.opcodes.push_back(GDFunction::ADDR_TYPE_NIL); // argument 2 (unary only takes one parameter) - return true; -} - -bool GDCompiler::_create_binary_operator(CodeGen& codegen,const GDParser::OperatorNode *on,Variant::Operator op, int p_stack_level) { - - ERR_FAIL_COND_V(on->arguments.size()!=2,false); - - - int src_address_a = _parse_expression(codegen,on->arguments[0],p_stack_level); - if (src_address_a<0) - return false; - if (src_address_a&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) - p_stack_level++; //uses stack for return, increase stack - - int src_address_b = _parse_expression(codegen,on->arguments[1],p_stack_level); - if (src_address_b<0) - return false; - - - codegen.opcodes.push_back(GDFunction::OPCODE_OPERATOR); // perform operator - codegen.opcodes.push_back(op); //which operator - codegen.opcodes.push_back(src_address_a); // argument 1 - codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter) - return true; -} - - -/* -int GDCompiler::_parse_subexpression(CodeGen& codegen,const GDParser::Node *p_expression) { - - - int ret = _parse_expression(codegen,p_expression); - if (ret<0) - return ret; - - if (ret&(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS)) { - codegen.stack_level++; - codegen.check_max_stack_level(); - //stack was used, keep value - } - - return ret; -} -*/ - -int GDCompiler::_parse_assign_right_expression(CodeGen& codegen,const GDParser::OperatorNode *p_expression, int p_stack_level) { - - Variant::Operator var_op=Variant::OP_MAX; - - switch(p_expression->op) { - - case GDParser::OperatorNode::OP_ASSIGN_ADD: var_op=Variant::OP_ADD; break; - case GDParser::OperatorNode::OP_ASSIGN_SUB: var_op=Variant::OP_SUBSTRACT; break; - case GDParser::OperatorNode::OP_ASSIGN_MUL: var_op=Variant::OP_MULTIPLY; break; - case GDParser::OperatorNode::OP_ASSIGN_DIV: var_op=Variant::OP_DIVIDE; break; - case GDParser::OperatorNode::OP_ASSIGN_MOD: var_op=Variant::OP_MODULE; break; - case GDParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT: var_op=Variant::OP_SHIFT_LEFT; break; - case GDParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: var_op=Variant::OP_SHIFT_RIGHT; break; - case GDParser::OperatorNode::OP_ASSIGN_BIT_AND: var_op=Variant::OP_BIT_AND; break; - case GDParser::OperatorNode::OP_ASSIGN_BIT_OR: var_op=Variant::OP_BIT_OR; break; - case GDParser::OperatorNode::OP_ASSIGN_BIT_XOR: var_op=Variant::OP_BIT_XOR; break; - case GDParser::OperatorNode::OP_ASSIGN: { - - //none - } break; - default: { - - ERR_FAIL_V(-1); - } - } - - if (var_op==Variant::OP_MAX) { - - return _parse_expression(codegen,p_expression->arguments[1],p_stack_level); - } - - if (!_create_binary_operator(codegen,p_expression,var_op,p_stack_level)) - return -1; - - int dst_addr=(p_stack_level)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); - codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode - codegen.alloc_stack(p_stack_level); - return dst_addr; - -} - -int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expression, int p_stack_level,bool p_root) { - - - switch(p_expression->type) { - //should parse variable declaration and adjust stack accordingly... - case GDParser::Node::TYPE_IDENTIFIER: { - //return identifier - //wait, identifier could be a local variable or something else... careful here, must reference properly - //as stack may be more interesting to work with - - //This could be made much simpler by just indexing "self", but done this way (with custom self-addressing modes) increases peformance a lot. - - const GDParser::IdentifierNode *in = static_cast<const GDParser::IdentifierNode*>(p_expression); - - StringName identifier = in->name; - - // TRY STACK! - if (codegen.stack_identifiers.has(identifier)) { - - int pos = codegen.stack_identifiers[identifier]; - return pos|(GDFunction::ADDR_TYPE_STACK_VARIABLE<<GDFunction::ADDR_BITS); - - } - //TRY ARGUMENTS! - if (!codegen.function_node || !codegen.function_node->_static) { - - // TRY MEMBER VARIABLES! - - //static function - if (codegen.script->member_indices.has(identifier)) { - - int idx = codegen.script->member_indices[identifier]; - return idx|(GDFunction::ADDR_TYPE_MEMBER<<GDFunction::ADDR_BITS); //argument (stack root) - } - } - - //TRY CLASS CONSTANTS - - GDScript *scr = codegen.script; - GDNativeClass *nc=NULL; - while(scr) { - - if (scr->constants.has(identifier)) { - - //int idx=scr->constants[identifier]; - int idx = codegen.get_name_map_pos(identifier); - return idx|(GDFunction::ADDR_TYPE_CLASS_CONSTANT<<GDFunction::ADDR_BITS); //argument (stack root) - } - if (scr->native.is_valid()) - nc=scr->native.ptr(); - scr=scr->_base; - } - - // CLASS C++ Integer Constant - - if (nc) { - - bool success=false; - int constant = ObjectTypeDB::get_integer_constant(nc->get_name(),identifier,&success); - if (success) { - Variant key=constant; - int idx; - - if (!codegen.constant_map.has(key)) { - - idx=codegen.constant_map.size(); - codegen.constant_map[key]=idx; - - } else { - idx=codegen.constant_map[key]; - } - - return idx|(GDFunction::ADDR_TYPE_LOCAL_CONSTANT<<GDFunction::ADDR_BITS); //make it a local constant (faster access) - } - - } - - if (codegen.script->subclasses.has(identifier)) { - //same with a subclass, make it a local constant. - int idx = codegen.get_constant_pos(codegen.script->subclasses[identifier]); - return idx|(GDFunction::ADDR_TYPE_LOCAL_CONSTANT<<GDFunction::ADDR_BITS); //make it a local constant (faster access) - - } - - if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) { - - int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier]; - return idx|(GDFunction::ADDR_TYPE_GLOBAL<<GDFunction::ADDR_BITS); //argument (stack root) - } - - //not found, error - - _set_error("Identifier not found: "+String(identifier),p_expression); - - return -1; - - - } break; - case GDParser::Node::TYPE_CONSTANT: { - //return constant - const GDParser::ConstantNode *cn = static_cast<const GDParser::ConstantNode*>(p_expression); - - - int idx; - - if (!codegen.constant_map.has(cn->value)) { - - idx=codegen.constant_map.size(); - codegen.constant_map[cn->value]=idx; - - } else { - idx=codegen.constant_map[cn->value]; - } - - - return idx|(GDFunction::ADDR_TYPE_LOCAL_CONSTANT<<GDFunction::ADDR_BITS); //argument (stack root) - - } break; - case GDParser::Node::TYPE_SELF: { - //return constant - if (codegen.function_node && codegen.function_node->_static) { - _set_error("'self' not present in static function!",p_expression); - return -1; - } - return (GDFunction::ADDR_TYPE_SELF<<GDFunction::ADDR_BITS); - } break; - case GDParser::Node::TYPE_ARRAY: { - - const GDParser::ArrayNode *an = static_cast<const GDParser::ArrayNode*>(p_expression); - Vector<int> values; - - int slevel=p_stack_level; - - for(int i=0;i<an->elements.size();i++) { - - int ret = _parse_expression(codegen,an->elements[i],slevel); - if (ret<0) - return ret; - if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { - slevel++; - codegen.alloc_stack(slevel); - } - - values.push_back(ret); - } - - codegen.opcodes.push_back(GDFunction::OPCODE_CONSTRUCT_ARRAY); - codegen.opcodes.push_back(values.size()); - for(int i=0;i<values.size();i++) - codegen.opcodes.push_back(values[i]); - - int dst_addr=(p_stack_level)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); - codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode - codegen.alloc_stack(p_stack_level); - return dst_addr; - - } break; - case GDParser::Node::TYPE_DICTIONARY: { - - const GDParser::DictionaryNode *dn = static_cast<const GDParser::DictionaryNode*>(p_expression); - Vector<int> values; - - int slevel=p_stack_level; - - for(int i=0;i<dn->elements.size();i++) { - - int ret = _parse_expression(codegen,dn->elements[i].key,slevel); - if (ret<0) - return ret; - if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { - slevel++; - codegen.alloc_stack(slevel); - } - - values.push_back(ret); - - ret = _parse_expression(codegen,dn->elements[i].value,slevel); - if (ret<0) - return ret; - if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { - slevel++; - codegen.alloc_stack(slevel); - } - - values.push_back(ret); - } - - codegen.opcodes.push_back(GDFunction::OPCODE_CONSTRUCT_DICTIONARY); - codegen.opcodes.push_back(dn->elements.size()); - for(int i=0;i<values.size();i++) - codegen.opcodes.push_back(values[i]); - - int dst_addr=(p_stack_level)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); - codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode - codegen.alloc_stack(p_stack_level); - return dst_addr; - - } break; - case GDParser::Node::TYPE_OPERATOR: { - //hell breaks loose - - const GDParser::OperatorNode *on = static_cast<const GDParser::OperatorNode*>(p_expression); - switch(on->op) { - - - //call/constructor operator - case GDParser::OperatorNode::OP_PARENT_CALL: { - - - ERR_FAIL_COND_V(on->arguments.size()<1,-1); - - const GDParser::IdentifierNode *in = (const GDParser::IdentifierNode *)on->arguments[0]; - - - Vector<int> arguments; - int slevel = p_stack_level; - for(int i=1;i<on->arguments.size();i++) { - - int ret = _parse_expression(codegen,on->arguments[i],slevel); - if (ret<0) - return ret; - if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { - slevel++; - codegen.alloc_stack(slevel); - } - arguments.push_back(ret); - } - - //push call bytecode - codegen.opcodes.push_back(GDFunction::OPCODE_CALL_SELF_BASE); // basic type constructor - - codegen.opcodes.push_back(codegen.get_name_map_pos(in->name)); //instance - codegen.opcodes.push_back(arguments.size()); //argument count - codegen.alloc_call(arguments.size()); - for(int i=0;i<arguments.size();i++) - codegen.opcodes.push_back(arguments[i]); //arguments - - } break; - case GDParser::OperatorNode::OP_CALL: { - - if (on->arguments[0]->type==GDParser::Node::TYPE_TYPE) { - //construct a basic type - ERR_FAIL_COND_V(on->arguments.size()<1,-1); - - const GDParser::TypeNode *tn = (const GDParser::TypeNode *)on->arguments[0]; - int vtype = tn->vtype; - - Vector<int> arguments; - int slevel = p_stack_level; - for(int i=1;i<on->arguments.size();i++) { - - int ret = _parse_expression(codegen,on->arguments[i],slevel); - if (ret<0) - return ret; - if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { - slevel++; - codegen.alloc_stack(slevel); - } - arguments.push_back(ret); - } - - //push call bytecode - codegen.opcodes.push_back(GDFunction::OPCODE_CONSTRUCT); // basic type constructor - codegen.opcodes.push_back(vtype); //instance - codegen.opcodes.push_back(arguments.size()); //argument count - codegen.alloc_call(arguments.size()); - for(int i=0;i<arguments.size();i++) - codegen.opcodes.push_back(arguments[i]); //arguments - - } else if (on->arguments[0]->type==GDParser::Node::TYPE_BUILT_IN_FUNCTION) { - //built in function - - ERR_FAIL_COND_V(on->arguments.size()<1,-1); - - - Vector<int> arguments; - int slevel = p_stack_level; - for(int i=1;i<on->arguments.size();i++) { - - int ret = _parse_expression(codegen,on->arguments[i],slevel); - if (ret<0) - return ret; - - if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { - slevel++; - codegen.alloc_stack(slevel); - } - - arguments.push_back(ret); - } - - - codegen.opcodes.push_back(GDFunction::OPCODE_CALL_BUILT_IN); - codegen.opcodes.push_back(static_cast<const GDParser::BuiltInFunctionNode*>(on->arguments[0])->function); - codegen.opcodes.push_back(on->arguments.size()-1); - codegen.alloc_call(on->arguments.size()-1); - for(int i=0;i<arguments.size();i++) - codegen.opcodes.push_back(arguments[i]); - - } else { - //regular function - ERR_FAIL_COND_V(on->arguments.size()<2,-1); - - const GDParser::Node *instance = on->arguments[0]; - - if (instance->type==GDParser::Node::TYPE_SELF) { - //room for optimization - - } - - - Vector<int> arguments; - int slevel = p_stack_level; - - for(int i=0;i<on->arguments.size();i++) { - - int ret; - - if (i==1) { - - if (on->arguments[i]->type!=GDParser::Node::TYPE_IDENTIFIER) { - _set_error("Attempt to call a non-identifier.",on); - return -1; - } - GDParser::IdentifierNode *id = static_cast<GDParser::IdentifierNode*>(on->arguments[i]); - ret=codegen.get_name_map_pos(id->name); - - } else { - ret = _parse_expression(codegen,on->arguments[i],slevel); - if (ret<0) - return ret; - if (ret&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { - slevel++; - codegen.alloc_stack(slevel); - } - } - arguments.push_back(ret); - - } - - codegen.opcodes.push_back(p_root?GDFunction::OPCODE_CALL:GDFunction::OPCODE_CALL_RETURN); // perform operator - codegen.opcodes.push_back(on->arguments.size()-2); - codegen.alloc_call(on->arguments.size()-2); - for(int i=0;i<arguments.size();i++) - codegen.opcodes.push_back(arguments[i]); - } - } break; - //indexing operator - case GDParser::OperatorNode::OP_INDEX: - case GDParser::OperatorNode::OP_INDEX_NAMED: { - - ERR_FAIL_COND_V(on->arguments.size()!=2,-1); - - int slevel = p_stack_level; - bool named=(on->op==GDParser::OperatorNode::OP_INDEX_NAMED); - - int from = _parse_expression(codegen,on->arguments[0],slevel); - if (from<0) - return from; - - int index; - if (named) { - - index=codegen.get_name_map_pos(static_cast<GDParser::IdentifierNode*>(on->arguments[1])->name); - - } else { - - if (on->arguments[1]->type==GDParser::Node::TYPE_CONSTANT && static_cast<const GDParser::ConstantNode*>(on->arguments[1])->value.get_type()==Variant::STRING) { - //also, somehow, named (speed up anyway) - StringName name = static_cast<const GDParser::ConstantNode*>(on->arguments[1])->value; - index=codegen.get_name_map_pos(name); - named=true; - - } else { - //regular indexing - if (from&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { - slevel++; - codegen.alloc_stack(slevel); - } - - index = _parse_expression(codegen,on->arguments[1],slevel); - if (index<0) - return index; - } - } - - codegen.opcodes.push_back(named?GDFunction::OPCODE_GET_NAMED:GDFunction::OPCODE_GET); // perform operator - codegen.opcodes.push_back(from); // argument 1 - codegen.opcodes.push_back(index); // argument 2 (unary only takes one parameter) - - } break; - case GDParser::OperatorNode::OP_AND: { - - // AND operator with early out on failure - - int res = _parse_expression(codegen,on->arguments[0],p_stack_level); - if (res<0) - return res; - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF_NOT); - codegen.opcodes.push_back(res); - int jump_fail_pos=codegen.opcodes.size(); - codegen.opcodes.push_back(0); - - res = _parse_expression(codegen,on->arguments[1],p_stack_level); - if (res<0) - return res; - - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF_NOT); - codegen.opcodes.push_back(res); - int jump_fail_pos2=codegen.opcodes.size(); - codegen.opcodes.push_back(0); - - codegen.alloc_stack(p_stack_level); //it will be used.. - codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN_TRUE); - codegen.opcodes.push_back(p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); - codegen.opcodes.push_back(codegen.opcodes.size()+3); - codegen.opcodes[jump_fail_pos]=codegen.opcodes.size(); - codegen.opcodes[jump_fail_pos2]=codegen.opcodes.size(); - codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN_FALSE); - codegen.opcodes.push_back(p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); - return p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS; - - } break; - case GDParser::OperatorNode::OP_OR: { - - // OR operator with early out on success - - int res = _parse_expression(codegen,on->arguments[0],p_stack_level); - if (res<0) - return res; - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF); - codegen.opcodes.push_back(res); - int jump_success_pos=codegen.opcodes.size(); - codegen.opcodes.push_back(0); - - res = _parse_expression(codegen,on->arguments[1],p_stack_level); - if (res<0) - return res; - - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF); - codegen.opcodes.push_back(res); - int jump_success_pos2=codegen.opcodes.size(); - codegen.opcodes.push_back(0); - - codegen.alloc_stack(p_stack_level); //it will be used.. - codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN_FALSE); - codegen.opcodes.push_back(p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); - codegen.opcodes.push_back(codegen.opcodes.size()+3); - codegen.opcodes[jump_success_pos]=codegen.opcodes.size(); - codegen.opcodes[jump_success_pos2]=codegen.opcodes.size(); - codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN_TRUE); - codegen.opcodes.push_back(p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); - return p_stack_level|GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS; - - } break; - //unary operators - case GDParser::OperatorNode::OP_NEG: { if (!_create_unary_operator(codegen,on,Variant::OP_NEGATE,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_NOT: { if (!_create_unary_operator(codegen,on,Variant::OP_NOT,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_BIT_INVERT: { if (!_create_unary_operator(codegen,on,Variant::OP_BIT_NEGATE,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_PREINC: { } break; //? - case GDParser::OperatorNode::OP_PREDEC: { } break; - case GDParser::OperatorNode::OP_INC: { } break; - case GDParser::OperatorNode::OP_DEC: { } break; - //binary operators (in precedence order) - case GDParser::OperatorNode::OP_IN: { if (!_create_binary_operator(codegen,on,Variant::OP_IN,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_EQUAL: { if (!_create_binary_operator(codegen,on,Variant::OP_EQUAL,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_NOT_EQUAL: { if (!_create_binary_operator(codegen,on,Variant::OP_NOT_EQUAL,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_LESS: { if (!_create_binary_operator(codegen,on,Variant::OP_LESS,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_LESS_EQUAL: { if (!_create_binary_operator(codegen,on,Variant::OP_LESS_EQUAL,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_GREATER: { if (!_create_binary_operator(codegen,on,Variant::OP_GREATER,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_GREATER_EQUAL: { if (!_create_binary_operator(codegen,on,Variant::OP_GREATER_EQUAL,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_ADD: { if (!_create_binary_operator(codegen,on,Variant::OP_ADD,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_SUB: { if (!_create_binary_operator(codegen,on,Variant::OP_SUBSTRACT,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_MUL: { if (!_create_binary_operator(codegen,on,Variant::OP_MULTIPLY,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_DIV: { if (!_create_binary_operator(codegen,on,Variant::OP_DIVIDE,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_MOD: { if (!_create_binary_operator(codegen,on,Variant::OP_MODULE,p_stack_level)) return -1;} break; - //case GDParser::OperatorNode::OP_SHIFT_LEFT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_LEFT,p_stack_level)) return -1;} break; - //case GDParser::OperatorNode::OP_SHIFT_RIGHT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_RIGHT,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_BIT_AND: { if (!_create_binary_operator(codegen,on,Variant::OP_BIT_AND,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_BIT_OR: { if (!_create_binary_operator(codegen,on,Variant::OP_BIT_OR,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_BIT_XOR: { if (!_create_binary_operator(codegen,on,Variant::OP_BIT_XOR,p_stack_level)) return -1;} break; - //shift - case GDParser::OperatorNode::OP_SHIFT_LEFT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_LEFT,p_stack_level)) return -1;} break; - case GDParser::OperatorNode::OP_SHIFT_RIGHT: { if (!_create_binary_operator(codegen,on,Variant::OP_SHIFT_RIGHT,p_stack_level)) return -1;} break; - //assignment operators - case GDParser::OperatorNode::OP_ASSIGN_ADD: - case GDParser::OperatorNode::OP_ASSIGN_SUB: - case GDParser::OperatorNode::OP_ASSIGN_MUL: - case GDParser::OperatorNode::OP_ASSIGN_DIV: - case GDParser::OperatorNode::OP_ASSIGN_MOD: - case GDParser::OperatorNode::OP_ASSIGN_SHIFT_LEFT: - case GDParser::OperatorNode::OP_ASSIGN_SHIFT_RIGHT: - case GDParser::OperatorNode::OP_ASSIGN_BIT_AND: - case GDParser::OperatorNode::OP_ASSIGN_BIT_OR: - case GDParser::OperatorNode::OP_ASSIGN_BIT_XOR: - case GDParser::OperatorNode::OP_ASSIGN: { - - ERR_FAIL_COND_V(on->arguments.size()!=2,-1); - - - if (on->arguments[0]->type==GDParser::Node::TYPE_OPERATOR && (static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX || static_cast<GDParser::OperatorNode*>(on->arguments[0])->op==GDParser::OperatorNode::OP_INDEX_NAMED)) { - //SET (chained) MODE!! - - int slevel=p_stack_level; - - GDParser::OperatorNode* op = static_cast<GDParser::OperatorNode*>(on->arguments[0]); - - /* Find chain of sets */ - - List<GDParser::OperatorNode*> chain; - - { - //create get/set chain - GDParser::OperatorNode* n=op; - while(true) { - - chain.push_back(n); - if (n->arguments[0]->type!=GDParser::Node::TYPE_OPERATOR) - break; - n = static_cast<GDParser::OperatorNode*>(n->arguments[0]); - if (n->op!=GDParser::OperatorNode::OP_INDEX && n->op!=GDParser::OperatorNode::OP_INDEX_NAMED) - break; - } - } - - /* Chain of gets */ - - //get at (potential) root stack pos, so it can be returned - int prev_pos = _parse_expression(codegen,chain.back()->get()->arguments[0],slevel); - if (prev_pos<0) - return prev_pos; - int retval=prev_pos; - - if (retval&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { - slevel++; - codegen.alloc_stack(slevel); - } - - - Vector<int> setchain; - - for(List<GDParser::OperatorNode*>::Element *E=chain.back();E;E=E->prev()) { - - - if (E==chain.front()) //ignore first - break; - - bool named = E->get()->op==GDParser::OperatorNode::OP_INDEX_NAMED; - int key_idx; - - if (named) { - - key_idx = codegen.get_name_map_pos(static_cast<const GDParser::IdentifierNode*>(E->get()->arguments[1])->name); - } else { - - GDParser::Node *key = E->get()->arguments[1]; - key_idx = _parse_expression(codegen,key,slevel); - if (retval&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { - slevel++; - codegen.alloc_stack(slevel); - } - - } - - if (key_idx<0) - return key_idx; - - codegen.opcodes.push_back(named ? GDFunction::OPCODE_GET_NAMED : GDFunction::OPCODE_GET); - codegen.opcodes.push_back(prev_pos); - codegen.opcodes.push_back(key_idx); - slevel++; - codegen.alloc_stack(slevel); - int dst_pos = (GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS)|slevel; - codegen.opcodes.push_back(dst_pos); - - //add in reverse order, since it will be reverted - setchain.push_back(dst_pos); - setchain.push_back(key_idx); - setchain.push_back(prev_pos); - setchain.push_back(named ? GDFunction::OPCODE_SET_NAMED : GDFunction::OPCODE_SET); - - prev_pos=dst_pos; - - } - - setchain.invert(); - - - int set_index; - bool named=false; - - - if (static_cast<const GDParser::OperatorNode*>(op)->op==GDParser::OperatorNode::OP_INDEX_NAMED) { - - - set_index=codegen.get_name_map_pos(static_cast<const GDParser::IdentifierNode*>(op->arguments[1])->name); - named=true; - } else { - - set_index = _parse_expression(codegen,op->arguments[1],slevel+1); - named=false; - } - - - if (set_index<0) - return set_index; - - if (set_index&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { - slevel++; - codegen.alloc_stack(slevel); - } - - - int set_value = _parse_assign_right_expression(codegen,on,slevel+1); - if (set_value<0) - return set_value; - - codegen.opcodes.push_back(named?GDFunction::OPCODE_SET_NAMED:GDFunction::OPCODE_SET); - codegen.opcodes.push_back(prev_pos); - codegen.opcodes.push_back(set_index); - codegen.opcodes.push_back(set_value); - - for(int i=0;i<setchain.size();i+=4) { - - - codegen.opcodes.push_back(setchain[i+0]); - codegen.opcodes.push_back(setchain[i+1]); - codegen.opcodes.push_back(setchain[i+2]); - codegen.opcodes.push_back(setchain[i+3]); - } - - return retval; - - - } else { - //ASSIGNMENT MODE!! - - int slevel = p_stack_level; - - int dst_address_a = _parse_expression(codegen,on->arguments[0],slevel); - if (dst_address_a<0) - return -1; - - if (dst_address_a&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) { - slevel++; - codegen.alloc_stack(slevel); - } - - int src_address_b = _parse_assign_right_expression(codegen,on,slevel); - if (src_address_b<0) - return -1; - - - - - codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN); // perform operator - codegen.opcodes.push_back(dst_address_a); // argument 1 - codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter) - return dst_address_a; //if anything, returns wathever was assigned or correct stack position - - } - - - } break; - case GDParser::OperatorNode::OP_EXTENDS: { - - ERR_FAIL_COND_V(on->arguments.size()!=2,false); - - - int slevel = p_stack_level; - - int src_address_a = _parse_expression(codegen,on->arguments[0],slevel); - if (src_address_a<0) - return -1; - - if (src_address_a&GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS) - slevel++; //uses stack for return, increase stack - - int src_address_b = _parse_expression(codegen,on->arguments[1],slevel); - if (src_address_b<0) - return -1; - - codegen.opcodes.push_back(GDFunction::OPCODE_EXTENDS_TEST); // perform operator - codegen.opcodes.push_back(src_address_a); // argument 1 - codegen.opcodes.push_back(src_address_b); // argument 2 (unary only takes one parameter) - - } break; - default: { - - - ERR_EXPLAIN("Bug in bytecode compiler, unexpected operator #"+itos(on->op)+" in parse tree while parsing expression."); - ERR_FAIL_V(0); //unreachable code - - } break; - } - - int dst_addr=(p_stack_level)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); - codegen.opcodes.push_back(dst_addr); // append the stack level as destination address of the opcode - codegen.alloc_stack(p_stack_level); - return dst_addr; - } break; - //TYPE_TYPE, - default: { - - ERR_EXPLAIN("Bug in bytecode compiler, unexpected node in parse tree while parsing expression."); - ERR_FAIL_V(-1); //unreachable code - } break; - - - } - - ERR_FAIL_V(-1); //unreachable code -} - - -Error GDCompiler::_parse_block(CodeGen& codegen,const GDParser::BlockNode *p_block,int p_stack_level,int p_break_addr,int p_continue_addr) { - - codegen.push_stack_identifiers(); - int new_identifiers=0; - codegen.current_line=p_block->line; - - for(int i=0;i<p_block->statements.size();i++) { - - const GDParser::Node *s = p_block->statements[i]; - - - switch(s->type) { - case GDParser::Node::TYPE_NEWLINE: { - - const GDParser::NewLineNode *nl = static_cast<const GDParser::NewLineNode*>(s); - codegen.opcodes.push_back(GDFunction::OPCODE_LINE); - codegen.opcodes.push_back(nl->line); - codegen.current_line=nl->line; - - } break; - case GDParser::Node::TYPE_CONTROL_FLOW: { - // try subblocks - - const GDParser::ControlFlowNode *cf = static_cast<const GDParser::ControlFlowNode*>(s); - - switch(cf->cf_type) { - - - case GDParser::ControlFlowNode::CF_IF: { - -#ifdef DEBUG_ENABLED - codegen.opcodes.push_back(GDFunction::OPCODE_LINE); - codegen.opcodes.push_back(cf->line); - codegen.current_line=cf->line; -#endif - int ret = _parse_expression(codegen,cf->arguments[0],p_stack_level,false); - if (ret<0) - return ERR_PARSE_ERROR; - - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF_NOT); - codegen.opcodes.push_back(ret); - int else_addr=codegen.opcodes.size(); - codegen.opcodes.push_back(0); //temporary - - Error err = _parse_block(codegen,cf->body,p_stack_level,p_break_addr,p_continue_addr); - if (err) - return err; - - if (cf->body_else) { - - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); - int end_addr=codegen.opcodes.size(); - codegen.opcodes.push_back(0); - codegen.opcodes[else_addr]=codegen.opcodes.size(); - - Error err = _parse_block(codegen,cf->body_else,p_stack_level,p_break_addr,p_continue_addr); - if (err) - return err; - - codegen.opcodes[end_addr]=codegen.opcodes.size(); - } else { - //end without else - codegen.opcodes[else_addr]=codegen.opcodes.size(); - - } - - } break; - case GDParser::ControlFlowNode::CF_FOR: { - - - - int slevel=p_stack_level; - int iter_stack_pos=slevel; - int iterator_pos = (slevel++)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); - int counter_pos = (slevel++)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); - int container_pos = (slevel++)|(GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS); - codegen.alloc_stack(slevel); - - codegen.push_stack_identifiers(); - codegen.add_stack_identifier(static_cast<const GDParser::IdentifierNode*>(cf->arguments[0])->name,iter_stack_pos); - - int ret = _parse_expression(codegen,cf->arguments[1],slevel,false); - if (ret<0) - return ERR_COMPILATION_FAILED; - - //assign container - codegen.opcodes.push_back(GDFunction::OPCODE_ASSIGN); - codegen.opcodes.push_back(container_pos); - codegen.opcodes.push_back(ret); - - //begin loop - codegen.opcodes.push_back(GDFunction::OPCODE_ITERATE_BEGIN); - codegen.opcodes.push_back(counter_pos); - codegen.opcodes.push_back(container_pos); - codegen.opcodes.push_back(codegen.opcodes.size()+4); - codegen.opcodes.push_back(iterator_pos); - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); //skip code for next - codegen.opcodes.push_back(codegen.opcodes.size()+8); - //break loop - int break_pos=codegen.opcodes.size(); - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); //skip code for next - codegen.opcodes.push_back(0); //skip code for next - //next loop - int continue_pos=codegen.opcodes.size(); - codegen.opcodes.push_back(GDFunction::OPCODE_ITERATE); - codegen.opcodes.push_back(counter_pos); - codegen.opcodes.push_back(container_pos); - codegen.opcodes.push_back(break_pos); - codegen.opcodes.push_back(iterator_pos); - - - Error err = _parse_block(codegen,cf->body,slevel,break_pos,continue_pos); - if (err) - return err; - - - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); - codegen.opcodes.push_back(continue_pos); - codegen.opcodes[break_pos+1]=codegen.opcodes.size(); - - - codegen.pop_stack_identifiers(); - - } break; - case GDParser::ControlFlowNode::CF_WHILE: { - - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); - codegen.opcodes.push_back(codegen.opcodes.size()+3); - int break_addr=codegen.opcodes.size(); - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); - codegen.opcodes.push_back(0); - int continue_addr=codegen.opcodes.size(); - - int ret = _parse_expression(codegen,cf->arguments[0],p_stack_level,false); - if (ret<0) - return ERR_PARSE_ERROR; - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_IF_NOT); - codegen.opcodes.push_back(ret); - codegen.opcodes.push_back(break_addr); - Error err = _parse_block(codegen,cf->body,p_stack_level,break_addr,continue_addr); - if (err) - return err; - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); - codegen.opcodes.push_back(continue_addr); - - codegen.opcodes[break_addr+1]=codegen.opcodes.size(); - - } break; - case GDParser::ControlFlowNode::CF_SWITCH: { - - } break; - case GDParser::ControlFlowNode::CF_BREAK: { - - if (p_break_addr<0) { - - _set_error("'break'' not within loop",cf); - return ERR_COMPILATION_FAILED; - } - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); - codegen.opcodes.push_back(p_break_addr); - - } break; - case GDParser::ControlFlowNode::CF_CONTINUE: { - - if (p_continue_addr<0) { - - _set_error("'continue' not within loop",cf); - return ERR_COMPILATION_FAILED; - } - - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP); - codegen.opcodes.push_back(p_continue_addr); - - } break; - case GDParser::ControlFlowNode::CF_RETURN: { - - int ret; - - if (cf->arguments.size()) { - - ret = _parse_expression(codegen,cf->arguments[0],p_stack_level,false); - if (ret<0) - return ERR_PARSE_ERROR; - - } else { - - ret=GDFunction::ADDR_TYPE_NIL << GDFunction::ADDR_BITS; - } - - codegen.opcodes.push_back(GDFunction::OPCODE_RETURN); - codegen.opcodes.push_back(ret); - - } break; - - } - } break; - case GDParser::Node::TYPE_ASSERT: { - // try subblocks - - const GDParser::AssertNode *as = static_cast<const GDParser::AssertNode*>(s); - - int ret = _parse_expression(codegen,as->condition,p_stack_level,false); - if (ret<0) - return ERR_PARSE_ERROR; - - codegen.opcodes.push_back(GDFunction::OPCODE_ASSERT); - codegen.opcodes.push_back(ret); - } break; - case GDParser::Node::TYPE_LOCAL_VAR: { - - - const GDParser::LocalVarNode *lv = static_cast<const GDParser::LocalVarNode*>(s); - - codegen.add_stack_identifier(lv->name,p_stack_level++); - codegen.alloc_stack(p_stack_level); - new_identifiers++; - - } break; - default: { - //expression - int ret = _parse_expression(codegen,s,p_stack_level,true); - if (ret<0) - return ERR_PARSE_ERROR; - } break; - - } - - } - codegen.pop_stack_identifiers(); - return OK; -} - - -Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *p_class,const GDParser::FunctionNode *p_func) { - - Vector<int> bytecode; - CodeGen codegen; - - codegen.class_node=p_class; - codegen.script=p_script; - codegen.function_node=p_func; - codegen.stack_max=0; - codegen.current_line=0; - codegen.call_max=0; - codegen.debug_stack=ScriptDebugger::get_singleton()!=NULL; - - int stack_level=0; - - if (p_func) { - for(int i=0;i<p_func->arguments.size();i++) { - int idx = i; - codegen.add_stack_identifier(p_func->arguments[i],i); - } - stack_level=p_func->arguments.size(); - } - - codegen.alloc_stack(stack_level); - - /* Parse initializer -if applies- */ - - bool is_initializer=false || !p_func; - - if (!p_func || String(p_func->name)=="_init") { - //parse initializer for class members - if (!p_func && p_class->extends_used && p_script->native.is_null()){ - - //call implicit parent constructor - codegen.opcodes.push_back(GDFunction::OPCODE_CALL_SELF_BASE); - codegen.opcodes.push_back(codegen.get_name_map_pos("_init")); - codegen.opcodes.push_back(0); - codegen.opcodes.push_back((GDFunction::ADDR_TYPE_STACK<<GDFunction::ADDR_BITS)|0); - - } - Error err = _parse_block(codegen,p_class->initializer,stack_level); - if (err) - return err; - is_initializer=true; - - } - - /* Parse default argument code -if applies- */ - - Vector<int> defarg_addr; - StringName func_name; - - if (p_func) { - if (p_func->default_values.size()) { - - codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_TO_DEF_ARGUMENT); - defarg_addr.push_back(codegen.opcodes.size()); - for(int i=0;i<p_func->default_values.size();i++) { - - _parse_expression(codegen,p_func->default_values[i],stack_level,true); - defarg_addr.push_back(codegen.opcodes.size()); - } - - - defarg_addr.invert(); - } - - - - Error err = _parse_block(codegen,p_func->body,stack_level); - if (err) - return err; - - func_name=p_func->name; - } else { - func_name="_init"; - } - - codegen.opcodes.push_back(GDFunction::OPCODE_END); - - GDFunction *gdfunc=NULL; - - //if (String(p_func->name)=="") { //initializer func - // gdfunc = &p_script->initializer; - - //} else { //regular func - p_script->member_functions[func_name]=GDFunction(); - gdfunc = &p_script->member_functions[func_name]; - //} - - if (p_func) - gdfunc->_static=p_func->_static; - - //constants - if (codegen.constant_map.size()) { - gdfunc->_constant_count=codegen.constant_map.size(); - gdfunc->constants.resize(codegen.constant_map.size()); - gdfunc->_constants_ptr=&gdfunc->constants[0]; - const Variant *K=NULL; - while((K=codegen.constant_map.next(K))) { - int idx = codegen.constant_map[*K]; - gdfunc->constants[idx]=*K; - } - } else { - - gdfunc->_constants_ptr=NULL; - gdfunc->_constant_count=0; - } - //global names - if (codegen.name_map.size()) { - - gdfunc->global_names.resize(codegen.name_map.size()); - gdfunc->_global_names_ptr = &gdfunc->global_names[0]; - for(Map<StringName,int>::Element *E=codegen.name_map.front();E;E=E->next()) { - - gdfunc->global_names[E->get()]=E->key(); - } - gdfunc->_global_names_count=gdfunc->global_names.size(); - - } else { - gdfunc->_global_names_ptr = NULL; - gdfunc->_global_names_count =0; - } - - - if (codegen.opcodes.size()) { - - gdfunc->code=codegen.opcodes; - gdfunc->_code_ptr=&gdfunc->code[0]; - gdfunc->_code_size=codegen.opcodes.size(); - - } else { - - gdfunc->_code_ptr=NULL; - gdfunc->_code_size=0; - } - - if (defarg_addr.size()) { - - gdfunc->default_arguments=defarg_addr; - gdfunc->_default_arg_count=defarg_addr.size(); - gdfunc->_default_arg_ptr=&gdfunc->default_arguments[0]; - } else { - gdfunc->_default_arg_count=0; - gdfunc->_default_arg_ptr=NULL; - } - - gdfunc->_argument_count=p_func ? p_func->arguments.size() : 0; - gdfunc->_stack_size=codegen.stack_max; - gdfunc->_call_size=codegen.call_max; - gdfunc->name=func_name; - gdfunc->_script=p_script; - gdfunc->source=source; - if (p_func) { - gdfunc->_initial_line=p_func->line; - } else { - gdfunc->_initial_line=0; - } - - if (codegen.debug_stack) - gdfunc->stack_debug=codegen.stack_debug; - - if (is_initializer) - p_script->initializer=gdfunc; - - - return OK; -} - - - -Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDParser::ClassNode *p_class) { - - - p_script->native=Ref<GDNativeClass>(); - p_script->base=Ref<GDScript>(); - p_script->_base=NULL; - p_script->members.clear(); - p_script->constants.clear(); - p_script->member_functions.clear(); - p_script->member_indices.clear(); - p_script->member_info.clear(); - p_script->initializer=NULL; - p_script->subclasses.clear(); - p_script->_owner=p_owner; - p_script->tool=p_class->tool; - p_script->name=p_class->name; - - - int index_from=0; - - 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()) { - _set_error("Could not load base class: "+path,p_class); - return ERR_FILE_NOT_FOUND; - } - - 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->subclasses.has(sub)) { - - script=script->subclasses[sub]; - } else { - - _set_error("Could not find subclass: "+sub,p_class); - return ERR_FILE_NOT_FOUND; - } - } - } - - } else { - - ERR_FAIL_COND_V(p_class->extends_class.size()==0,ERR_BUG); - //look around for the subclasses - - String base=p_class->extends_class[0]; - GDScript *p = p_owner; - Ref<GDScript> base_class; - - 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; - } - } - - script=base_class; - - - } else { - - if (p_class->extends_class.size()>1) { - - _set_error("Invalid inheritance (unknown class+subclasses)",p_class); - return ERR_FILE_NOT_FOUND; - - } - //if not found, try engine classes - if (!GDScriptLanguage::get_singleton()->get_global_map().has(base)) { - - _set_error("Unknown class: '"+base+"'",p_class); - return ERR_FILE_NOT_FOUND; - } - - int base_idx = GDScriptLanguage::get_singleton()->get_global_map()[base]; - native = GDScriptLanguage::get_singleton()->get_global_array()[base_idx]; - if (!native.is_valid()) { - - _set_error("Global not a class: '"+base+"'",p_class); - - return ERR_FILE_NOT_FOUND; - } - } - - - } - - if (script.is_valid()) { - - p_script->base=script; - p_script->_base=p_script->base.ptr(); - p_script->member_indices=script->member_indices; - - } else if (native.is_valid()) { - - p_script->native=native; - } else { - - _set_error("Could not determine inheritance",p_class); - return ERR_FILE_NOT_FOUND; - } - - - } - - - for(int i=0;i<p_class->variables.size();i++) { - - StringName name = p_class->variables[i].identifier; - if (p_script->member_indices.has(name)) { - _set_error("Member '"+name+"' already exists (in current or parent class)",p_class); - return ERR_ALREADY_EXISTS; - } - - if (p_class->variables[i]._export.type!=Variant::NIL) { - - p_script->member_info[name]=p_class->variables[i]._export; -#ifdef TOOLS_ENABLED - if (p_class->variables[i].default_value.get_type()!=Variant::NIL) { - - p_script->member_default_values[name]=p_class->variables[i].default_value; - } -#endif - } - - int new_idx = p_script->member_indices.size(); - p_script->member_indices[name]=new_idx; - p_script->members.insert(name); - - } - - for(int i=0;i<p_class->constant_expressions.size();i++) { - - StringName name = p_class->constant_expressions[i].identifier; - ERR_CONTINUE( p_class->constant_expressions[i].expression->type!=GDParser::Node::TYPE_CONSTANT ); - - GDParser::ConstantNode *constant = static_cast<GDParser::ConstantNode*>(p_class->constant_expressions[i].expression); - - p_script->constants.insert(name,constant->value); - //p_script->constants[constant->value].make_const(); - } - - - //parse sub-classes - - for(int i=0;i<p_class->subclasses.size();i++) { - StringName name = p_class->subclasses[i]->name; - - Ref<GDScript> subclass = memnew( GDScript ); - - Error err = _parse_class(subclass.ptr(),p_script,p_class->subclasses[i]); - if (err) - return err; - p_script->subclasses.insert(name,subclass); - - } - - - //parse methods - - bool has_initializer=false; - for(int i=0;i<p_class->functions.size();i++) { - - if (!has_initializer && p_class->functions[i]->name=="_init") - has_initializer=true; - Error err = _parse_function(p_script,p_class,p_class->functions[i]); - if (err) - return err; - } - - //parse static methods - - for(int i=0;i<p_class->static_functions.size();i++) { - - Error err = _parse_function(p_script,p_class,p_class->static_functions[i]); - if (err) - return err; - } - - - if (!has_initializer) { - //create a constructor - Error err = _parse_function(p_script,p_class,NULL); - if (err) - return err; - } - - return OK; -} - -Error GDCompiler::compile(const GDParser *p_parser,GDScript *p_script) { - - err_line=-1; - err_column=-1; - error=""; - parser=p_parser; - const GDParser::Node* root = parser->get_parse_tree(); - ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,ERR_INVALID_DATA); - - source=p_script->get_path(); - - - - Error err = _parse_class(p_script,NULL,static_cast<const GDParser::ClassNode*>(root)); - - if (err) - return err; - - return OK; - -} - -String GDCompiler::get_error() const { - - return error; -} -int GDCompiler::get_error_line() const{ - - return err_line; -} -int GDCompiler::get_error_column() const{ - - return err_column; -} - -GDCompiler::GDCompiler() -{ -} - - diff --git a/script/gdscript/gd_compiler.h b/script/gdscript/gd_compiler.h deleted file mode 100644 index cda221dab0..0000000000 --- a/script/gdscript/gd_compiler.h +++ /dev/null @@ -1,181 +0,0 @@ -/*************************************************************************/ -/* 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 diff --git a/script/gdscript/gd_editor.cpp b/script/gdscript/gd_editor.cpp deleted file mode 100644 index 4bb5d3206c..0000000000 --- a/script/gdscript/gd_editor.cpp +++ /dev/null @@ -1,781 +0,0 @@ -/*************************************************************************/ -/* 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))); - } -} - -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; -} - diff --git a/script/gdscript/gd_functions.cpp b/script/gdscript/gd_functions.cpp deleted file mode 100644 index 2930d9322c..0000000000 --- a/script/gdscript/gd_functions.cpp +++ /dev/null @@ -1,1218 +0,0 @@ -/*************************************************************************/ -/* gd_functions.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_functions.h" -#include "math_funcs.h" -#include "object_type_db.h" -#include "reference.h" -#include "gd_script.h" -#include "os/os.h" - -const char *GDFunctions::get_func_name(Function p_func) { - - ERR_FAIL_INDEX_V(p_func,FUNC_MAX,""); - - static const char *_names[FUNC_MAX]={ - "sin", - "cos", - "tan", - "sinh", - "cosh", - "tanh", - "asin", - "acos", - "atan", - "atan2", - "sqrt", - "fmod", - "fposmod", - "floor", - "ceil", - "round", - "abs", - "sign", - "pow", - "log", - "exp", - "is_nan", - "is_inf", - "ease", - "decimals", - "stepify", - "lerp", - "dectime", - "randomize", - "randi", - "randf", - "rand_range", - "rand_seed", - "deg2rad", - "rad2deg", - "linear2db", - "db2linear", - "max", - "min", - "clamp", - "nearest_po2", - "weakref", - "convert", - "typeof", - "str", - "print", - "printt", - "printerr", - "printraw", - "range", - "load", - "inst2dict", - "dict2inst", - "print_stack", - }; - - return _names[p_func]; - -} - -void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Variant &r_ret,Variant::CallError &r_error) { - - r_error.error=Variant::CallError::CALL_OK; -#ifdef DEBUG_ENABLED - -#define VALIDATE_ARG_COUNT(m_count) \ - if (p_arg_count<m_count) {\ - r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;\ - r_error.argument=m_count;\ - return;\ - }\ - if (p_arg_count>m_count) {\ - r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;\ - r_error.argument=m_count;\ - return;\ - } - -#define VALIDATE_ARG_NUM(m_arg) \ - if (!p_args[m_arg]->is_num()) {\ - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;\ - r_error.argument=m_arg;\ - r_error.expected=Variant::REAL;\ - return;\ - } - -#else - -#define VALIDATE_ARG_COUNT(m_count) -#define VALIDATE_ARG_NUM(m_arg) -#endif - - //using a switch, so the compiler generates a jumptable - - switch(p_func) { - - case MATH_SIN: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::sin(*p_args[0]); - } break; - case MATH_COS: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::cos(*p_args[0]); - } break; - case MATH_TAN: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::tan(*p_args[0]); - } break; - case MATH_SINH: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::sinh(*p_args[0]); - } break; - case MATH_COSH: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::cosh(*p_args[0]); - } break; - case MATH_TANH: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::tanh(*p_args[0]); - } break; - case MATH_ASIN: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::asin(*p_args[0]); - } break; - case MATH_ACOS: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::acos(*p_args[0]); - } break; - case MATH_ATAN: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::atan(*p_args[0]); - } break; - case MATH_ATAN2: { - VALIDATE_ARG_COUNT(2); - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - r_ret=Math::atan2(*p_args[0],*p_args[1]); - } break; - case MATH_SQRT: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::sqrt(*p_args[0]); - } break; - case MATH_FMOD: { - VALIDATE_ARG_COUNT(2); - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - r_ret=Math::fmod(*p_args[0],*p_args[1]); - } break; - case MATH_FPOSMOD: { - VALIDATE_ARG_COUNT(2); - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - r_ret=Math::fposmod(*p_args[0],*p_args[1]); - } break; - case MATH_FLOOR: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::floor(*p_args[0]); - } break; - case MATH_CEIL: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::ceil(*p_args[0]); - } break; - case MATH_ROUND: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::round(*p_args[0]); - } break; - case MATH_ABS: { - VALIDATE_ARG_COUNT(1); - if (p_args[0]->get_type()==Variant::INT) { - - int64_t i = *p_args[0]; - r_ret=ABS(i); - } else if (p_args[0]->get_type()==Variant::REAL) { - - real_t r = *p_args[0]; - r_ret=Math::abs(r); - } else { - - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::REAL; - } - } break; - case MATH_SIGN: { - VALIDATE_ARG_COUNT(1); - if (p_args[0]->get_type()==Variant::INT) { - - int64_t i = *p_args[0]; - r_ret= i < 0 ? -1 : ( i > 0 ? +1 : 0); - } else if (p_args[0]->get_type()==Variant::REAL) { - - real_t r = *p_args[0]; - r_ret= r < 0.0 ? -1.0 : ( r > 0.0 ? +1.0 : 0.0); - } else { - - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::REAL; - } - } break; - case MATH_POW: { - VALIDATE_ARG_COUNT(2); - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - r_ret=Math::pow(*p_args[0],*p_args[1]); - } break; - case MATH_LOG: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::log(*p_args[0]); - } break; - case MATH_EXP: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::exp(*p_args[0]); - } break; - case MATH_ISNAN: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::is_nan(*p_args[0]); - } break; - case MATH_ISINF: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::is_inf(*p_args[0]); - } break; - case MATH_EASE: { - VALIDATE_ARG_COUNT(2); - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - r_ret=Math::ease(*p_args[0],*p_args[1]); - } break; - case MATH_DECIMALS: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::decimals(*p_args[0]); - } break; - case MATH_STEPIFY: { - VALIDATE_ARG_COUNT(2); - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - r_ret=Math::stepify(*p_args[0],*p_args[1]); - } break; - case MATH_LERP: { - VALIDATE_ARG_COUNT(3); - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - r_ret=Math::lerp(*p_args[0],*p_args[1],*p_args[2]); - } break; - case MATH_DECTIME: { - VALIDATE_ARG_COUNT(3); - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - r_ret=Math::dectime(*p_args[0],*p_args[1],*p_args[2]); - } break; - case MATH_RANDOMIZE: { - Math::randomize(); - r_ret=Variant(); - } break; - case MATH_RAND: { - r_ret=Math::rand(); - } break; - case MATH_RANDF: { - r_ret=Math::randf(); - } break; - case MATH_RANDOM: { - VALIDATE_ARG_COUNT(2); - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - r_ret=Math::random(*p_args[0],*p_args[1]); - } break; - case MATH_RANDSEED: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - uint32_t seed=*p_args[0]; - int ret = Math::rand_from_seed(&seed); - Array reta; - reta.push_back(ret); - reta.push_back(seed); - r_ret=reta; - - } break; - case MATH_DEG2RAD: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::deg2rad(*p_args[0]); - } break; - case MATH_RAD2DEG: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::rad2deg(*p_args[0]); - } break; - case MATH_LINEAR2DB: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::linear2db(*p_args[0]); - } break; - case MATH_DB2LINEAR: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - r_ret=Math::db2linear(*p_args[0]); - } break; - case LOGIC_MAX: { - VALIDATE_ARG_COUNT(2); - if (p_args[0]->get_type()==Variant::INT && p_args[1]->get_type()==Variant::INT) { - - int64_t a = *p_args[0]; - int64_t b = *p_args[1]; - r_ret=MAX(a,b); - } else { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - - real_t a = *p_args[0]; - real_t b = *p_args[1]; - - r_ret=MAX(a,b); - } - - } break; - case LOGIC_MIN: { - VALIDATE_ARG_COUNT(2); - if (p_args[0]->get_type()==Variant::INT && p_args[1]->get_type()==Variant::INT) { - - int64_t a = *p_args[0]; - int64_t b = *p_args[1]; - r_ret=MIN(a,b); - } else { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - - real_t a = *p_args[0]; - real_t b = *p_args[1]; - - r_ret=MIN(a,b); - } - } break; - case LOGIC_CLAMP: { - VALIDATE_ARG_COUNT(3); - if (p_args[0]->get_type()==Variant::INT && p_args[1]->get_type()==Variant::INT && p_args[2]->get_type()==Variant::INT) { - - int64_t a = *p_args[0]; - int64_t b = *p_args[1]; - int64_t c = *p_args[2]; - r_ret=CLAMP(a,b,c); - } else { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - - real_t a = *p_args[0]; - real_t b = *p_args[1]; - real_t c = *p_args[2]; - - r_ret=CLAMP(a,b,c); - } - } break; - case LOGIC_NEAREST_PO2: { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_NUM(0); - int64_t num = *p_args[0]; - r_ret = nearest_power_of_2(num); - } break; - case OBJ_WEAKREF: { - VALIDATE_ARG_COUNT(1); - if (p_args[0]->get_type()!=Variant::OBJECT) { - - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::OBJECT; - return; - - } - - if (p_args[0]->is_ref()) { - - REF r = *p_args[0]; - if (!r.is_valid()) { - r_ret=Variant(); - return; - } - - Ref<WeakRef> wref = memnew( WeakRef ); - wref->set_ref(r); - r_ret=wref; - } else { - Object *obj = *p_args[0]; - if (!obj) { - r_ret=Variant(); - return; - } - Ref<WeakRef> wref = memnew( WeakRef ); - wref->set_obj(obj); - r_ret=wref; - } - - - - - } break; - case TYPE_CONVERT: { - VALIDATE_ARG_COUNT(2); - VALIDATE_ARG_NUM(1); - int type=*p_args[1]; - if (type<0 || type>=Variant::VARIANT_MAX) { - - ERR_PRINT("Invalid type argument to convert()"); - r_ret=Variant::NIL; - - } else { - - - r_ret=Variant::construct(Variant::Type(type),p_args,1,r_error); - } - } break; - case TYPE_OF: { - - VALIDATE_ARG_COUNT(1); - r_ret = p_args[0]->get_type(); - - } break; - case TEXT_STR: { - - String str; - for(int i=0;i<p_arg_count;i++) { - - String os = p_args[i]->operator String();; - if (i==0) - str=os; - else - str+=os; - } - - r_ret=str; - - } break; - case TEXT_PRINT: { - - String str; - for(int i=0;i<p_arg_count;i++) { - - str+=p_args[i]->operator String(); - } - - //str+="\n"; - print_line(str); - r_ret=Variant(); - - - } break; - case TEXT_PRINT_TABBED: { - - String str; - for(int i=0;i<p_arg_count;i++) { - - if (i) - str+="\t"; - str+=p_args[i]->operator String(); - } - - //str+="\n"; - print_line(str); - r_ret=Variant(); - - - } break; - - case TEXT_PRINTERR: { - - String str; - for(int i=0;i<p_arg_count;i++) { - - str+=p_args[i]->operator String(); - } - - //str+="\n"; - OS::get_singleton()->printerr("%s\n",str.utf8().get_data()); - r_ret=Variant(); - - } break; - case TEXT_PRINTRAW: { - String str; - for(int i=0;i<p_arg_count;i++) { - - str+=p_args[i]->operator String(); - } - - //str+="\n"; - OS::get_singleton()->print("%s\n",str.utf8().get_data()); - r_ret=Variant(); - - } break; - case GEN_RANGE: { - - - - switch(p_arg_count) { - - case 0: { - - r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.argument=1; - - } break; - case 1: { - - VALIDATE_ARG_NUM(0); - int count=*p_args[0]; - Array arr(true); - if (count<=0) { - r_ret=arr; - return; - } - Error err = arr.resize(count); - if (err!=OK) { - r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; - r_ret=Variant(); - return; - } - - for(int i=0;i<count;i++) { - arr[i]=i; - } - - r_ret=arr; - } break; - case 2: { - - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - - int from=*p_args[0]; - int to=*p_args[1]; - - Array arr(true); - if (from>=to) { - r_ret=arr; - return; - } - Error err = arr.resize(to-from); - if (err!=OK) { - r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; - r_ret=Variant(); - return; - } - for(int i=from;i<to;i++) - arr[i-from]=i; - r_ret=arr; - } break; - case 3: { - - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); - - int from=*p_args[0]; - int to=*p_args[1]; - int incr=*p_args[2]; - if (incr==0) { - - ERR_EXPLAIN("step argument is zero!"); - r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; - ERR_FAIL(); - } - - Array arr(true); - if (from>=to && incr>0) { - r_ret=arr; - return; - } - if (from<=to && incr<0) { - r_ret=arr; - return; - } - - //calculate how many - int count=0; - if (incr>0) { - - count=((to-from-1)/incr)+1; - } else { - - count=((from-to-1)/-incr)+1; - } - - - Error err = arr.resize(count); - - if (err!=OK) { - r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; - r_ret=Variant(); - return; - } - - if (incr>0) { - int idx=0; - for(int i=from;i<to;i+=incr) { - arr[idx++]=i; - } - } else { - - int idx=0; - for(int i=from;i>to;i+=incr) { - arr[idx++]=i; - } - } - - r_ret=arr; - } break; - default: { - - r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.argument=3; - } break; - } - - } break; - case RESOURCE_LOAD: { - VALIDATE_ARG_COUNT(1); - if (p_args[0]->get_type()!=Variant::STRING) { - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_ret=Variant(); - } - r_ret=ResourceLoader::load(*p_args[0]); - - } - case INST2DICT: { - - VALIDATE_ARG_COUNT(1); - - if (p_args[0]->get_type()==Variant::NIL) { - r_ret=Variant(); - } else if (p_args[0]->get_type()!=Variant::OBJECT) { - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_ret=Variant(); - } else { - - Object *obj = *p_args[0]; - if (!obj) { - r_ret=Variant(); - - } else if (!obj->get_script_instance() || obj->get_script_instance()->get_language()!=GDScriptLanguage::get_singleton()) { - - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::DICTIONARY; - ERR_PRINT("Not a script with an instance"); - - } else { - - GDInstance *ins = static_cast<GDInstance*>(obj->get_script_instance()); - Ref<GDScript> base = ins->get_script(); - if (base.is_null()) { - - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::DICTIONARY; - ERR_PRINT("Not based on a script"); - return; - - } - - - GDScript *p = base.ptr(); - Vector<StringName> sname; - - while(p->_owner) { - - sname.push_back(p->name); - p=p->_owner; - } - sname.invert(); - - - if (!p->path.is_resource_file()) { - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::DICTIONARY; - print_line("PATH: "+p->path); - ERR_PRINT("Not based on a resource file"); - - return; - } - - NodePath cp(sname,Vector<StringName>(),false); - - Dictionary d(true); - d["@subpath"]=cp; - d["@path"]=p->path; - - - p = base.ptr(); - - while(p) { - - for(Set<StringName>::Element *E=p->members.front();E;E=E->next()) { - - Variant value; - if (ins->get(E->get(),value)) { - - String k = E->get(); - if (!d.has(k)) { - d[k]=value; - } - } - } - - p=p->_base; - } - - r_ret=d; - - } - } - - } break; - case DICT2INST: { - - VALIDATE_ARG_COUNT(1); - - if (p_args[0]->get_type()!=Variant::DICTIONARY) { - - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::DICTIONARY; - return; - } - - Dictionary d = *p_args[0]; - - if (!d.has("@path")) { - - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::OBJECT; - return; - } - - Ref<Script> scr = ResourceLoader::load(d["@path"]); - if (!scr.is_valid()) { - - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::OBJECT; - return; - } - - Ref<GDScript> gdscr = scr; - - if (!gdscr.is_valid()) { - - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::OBJECT; - return; - } - - NodePath sub; - if (d.has("@subpath")) { - sub=d["@subpath"]; - } - - for(int i=0;i<sub.get_name_count();i++) { - - gdscr = gdscr->subclasses[ sub.get_name(i)]; - if (!gdscr.is_valid()) { - - r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument=0; - r_error.expected=Variant::OBJECT; - return; - } - } - - - r_ret = gdscr->_new(NULL,0,r_error); - - } break; - - case PRINT_STACK: { - - ScriptLanguage* script = GDScriptLanguage::get_singleton(); - for (int i=0; i < script->debug_get_stack_level_count(); i++) { - - print_line("Frame "+itos(i)+" - "+script->debug_get_stack_level_source(i)+":"+itos(script->debug_get_stack_level_line(i))+" in function '"+script->debug_get_stack_level_function(i)+"'"); - }; - } break; - - case FUNC_MAX: { - - ERR_FAIL_V(); - } break; - - } - -} - -bool GDFunctions::is_deterministic(Function p_func) { - - //man i couldn't have chosen a worse function name, - //way too controversial.. - - switch(p_func) { - - case MATH_SIN: - case MATH_COS: - case MATH_TAN: - case MATH_SINH: - case MATH_COSH: - case MATH_TANH: - case MATH_ASIN: - case MATH_ACOS: - case MATH_ATAN: - case MATH_ATAN2: - case MATH_SQRT: - case MATH_FMOD: - case MATH_FPOSMOD: - case MATH_FLOOR: - case MATH_CEIL: - case MATH_ROUND: - case MATH_ABS: - case MATH_SIGN: - case MATH_POW: - case MATH_LOG: - case MATH_EXP: - case MATH_ISNAN: - case MATH_ISINF: - case MATH_EASE: - case MATH_DECIMALS: - case MATH_STEPIFY: - case MATH_LERP: - case MATH_DECTIME: - case MATH_DEG2RAD: - case MATH_RAD2DEG: - case MATH_LINEAR2DB: - case MATH_DB2LINEAR: - case LOGIC_MAX: - case LOGIC_MIN: - case LOGIC_CLAMP: - case LOGIC_NEAREST_PO2: - case TYPE_CONVERT: - case TYPE_OF: - case TEXT_STR: -// enable for debug only, otherwise not desirable - case GEN_RANGE: - return true; - default: - return false; - - } - - return false; - - -} - -MethodInfo GDFunctions::get_info(Function p_func) { - -#ifdef TOOLS_ENABLED - //using a switch, so the compiler generates a jumptable - - switch(p_func) { - - case MATH_SIN: { - MethodInfo mi("sin",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - - } break; - case MATH_COS: { - MethodInfo mi("cos",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_TAN: { - MethodInfo mi("tan",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_SINH: { - MethodInfo mi("sinh",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_COSH: { - MethodInfo mi("cosh",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_TANH: { - MethodInfo mi("tanh",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_ASIN: { - MethodInfo mi("asin",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_ACOS: { - MethodInfo mi("acos",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_ATAN: { - MethodInfo mi("atan",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_ATAN2: { - MethodInfo mi("atan2",PropertyInfo(Variant::REAL,"x"),PropertyInfo(Variant::REAL,"y")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_SQRT: { - MethodInfo mi("sqrt",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_FMOD: { - MethodInfo mi("fmod",PropertyInfo(Variant::REAL,"x"),PropertyInfo(Variant::REAL,"y")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_FPOSMOD: { - MethodInfo mi("fposmod",PropertyInfo(Variant::REAL,"x"),PropertyInfo(Variant::REAL,"y")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_FLOOR: { - MethodInfo mi("floor",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_CEIL: { - MethodInfo mi("ceil",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_ROUND: { - MethodInfo mi("round",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_ABS: { - MethodInfo mi("abs",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_SIGN: { - MethodInfo mi("sign",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_POW: { - MethodInfo mi("pow",PropertyInfo(Variant::REAL,"x"),PropertyInfo(Variant::REAL,"y")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_LOG: { - MethodInfo mi("log",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_EXP: { - MethodInfo mi("exp",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_ISNAN: { - MethodInfo mi("isnan",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_ISINF: { - MethodInfo mi("isinf",PropertyInfo(Variant::REAL,"s")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_EASE: { - MethodInfo mi("ease",PropertyInfo(Variant::REAL,"s"),PropertyInfo(Variant::REAL,"curve")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_DECIMALS: { - MethodInfo mi("decimals",PropertyInfo(Variant::REAL,"step")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_STEPIFY: { - MethodInfo mi("stepify",PropertyInfo(Variant::REAL,"s"),PropertyInfo(Variant::REAL,"step")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_LERP: { - MethodInfo mi("lerp",PropertyInfo(Variant::REAL,"a"),PropertyInfo(Variant::REAL,"b"), PropertyInfo(Variant::REAL,"c")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_DECTIME: { - MethodInfo mi("dectime",PropertyInfo(Variant::REAL,"value"),PropertyInfo(Variant::REAL,"amount"),PropertyInfo(Variant::REAL,"step")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_RANDOMIZE: { - MethodInfo mi("randomize"); - mi.return_val.type=Variant::NIL; - return mi; - } break; - case MATH_RAND: { - MethodInfo mi("rand"); - mi.return_val.type=Variant::INT; - return mi; - } break; - case MATH_RANDF: { - MethodInfo mi("randf"); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_RANDOM: { - MethodInfo mi("rand_range",PropertyInfo(Variant::REAL,"from"),PropertyInfo(Variant::REAL,"to")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_RANDSEED: { - MethodInfo mi("rand_seed",PropertyInfo(Variant::REAL,"seed")); - mi.return_val.type=Variant::ARRAY; - return mi; - } break; - case MATH_DEG2RAD: { - MethodInfo mi("deg2rad",PropertyInfo(Variant::REAL,"deg")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_RAD2DEG: { - MethodInfo mi("rad2deg",PropertyInfo(Variant::REAL,"rad")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_LINEAR2DB: { - MethodInfo mi("linear2db",PropertyInfo(Variant::REAL,"nrg")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case MATH_DB2LINEAR: { - MethodInfo mi("db2linear",PropertyInfo(Variant::REAL,"db")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case LOGIC_MAX: { - MethodInfo mi("max",PropertyInfo(Variant::REAL,"a"),PropertyInfo(Variant::REAL,"b")); - mi.return_val.type=Variant::REAL; - return mi; - - } break; - case LOGIC_MIN: { - MethodInfo mi("min",PropertyInfo(Variant::REAL,"a"),PropertyInfo(Variant::REAL,"b")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case LOGIC_CLAMP: { - MethodInfo mi("clamp",PropertyInfo(Variant::REAL,"val"),PropertyInfo(Variant::REAL,"min"),PropertyInfo(Variant::REAL,"max")); - mi.return_val.type=Variant::REAL; - return mi; - } break; - case LOGIC_NEAREST_PO2: { - MethodInfo mi("nearest_po2",PropertyInfo(Variant::INT,"val")); - mi.return_val.type=Variant::INT; - return mi; - } break; - case OBJ_WEAKREF: { - - MethodInfo mi("weakref",PropertyInfo(Variant::OBJECT,"obj")); - mi.return_val.type=Variant::OBJECT; - return mi; - - } break; - case TYPE_CONVERT: { - - MethodInfo mi("convert",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::INT,"type")); - mi.return_val.type=Variant::OBJECT; - return mi; - } break; - case TYPE_OF: { - MethodInfo mi("typeof",PropertyInfo(Variant::NIL,"what")); - mi.return_val.type=Variant::INT; - }; - case TEXT_STR: { - - MethodInfo mi("str",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"...")); - mi.return_val.type=Variant::STRING; - return mi; - - } break; - case TEXT_PRINT: { - - MethodInfo mi("print",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"...")); - mi.return_val.type=Variant::NIL; - return mi; - - } break; - case TEXT_PRINT_TABBED: { - - MethodInfo mi("printt",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"...")); - mi.return_val.type=Variant::NIL; - return mi; - - } break; - case TEXT_PRINTERR: { - - MethodInfo mi("printerr",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"...")); - mi.return_val.type=Variant::NIL; - return mi; - - } break; - case TEXT_PRINTRAW: { - - MethodInfo mi("printraw",PropertyInfo(Variant::NIL,"what"),PropertyInfo(Variant::NIL,"...")); - mi.return_val.type=Variant::NIL; - return mi; - - } break; - case GEN_RANGE: { - - MethodInfo mi("range",PropertyInfo(Variant::NIL,"...")); - mi.return_val.type=Variant::ARRAY; - return mi; - } break; - case RESOURCE_LOAD: { - - MethodInfo mi("load",PropertyInfo(Variant::STRING,"path")); - mi.return_val.type=Variant::OBJECT; - return mi; - } break; - case INST2DICT: { - - MethodInfo mi("inst2dict",PropertyInfo(Variant::OBJECT,"inst")); - mi.return_val.type=Variant::DICTIONARY; - return mi; - } break; - case DICT2INST: { - - MethodInfo mi("dict2inst",PropertyInfo(Variant::DICTIONARY,"dict")); - mi.return_val.type=Variant::OBJECT; - return mi; - } break; - - case PRINT_STACK: { - MethodInfo mi("print_stack"); - mi.return_val.type=Variant::NIL; - return mi; - } break; - - case FUNC_MAX: { - - ERR_FAIL_V(MethodInfo()); - } break; - - } -#endif - - return MethodInfo(); -} diff --git a/script/gdscript/gd_functions.h b/script/gdscript/gd_functions.h deleted file mode 100644 index 2ab397d18a..0000000000 --- a/script/gdscript/gd_functions.h +++ /dev/null @@ -1,103 +0,0 @@ -/*************************************************************************/ -/* 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 diff --git a/script/gdscript/gd_parser.cpp b/script/gdscript/gd_parser.cpp deleted file mode 100644 index e558ceb416..0000000000 --- a/script/gdscript/gd_parser.cpp +++ /dev/null @@ -1,2469 +0,0 @@ -/*************************************************************************/ -/* gd_parser.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_parser.h" -#include "print_string.h" -#include "io/resource_loader.h" -/* TODO: - - *Property reduce constant expressions - *Implement missing operators in variant? - *constructor - */ - -/* - todo: - fix post ++,-- - make sure ++,-- don't work on constant expressions - seems passing parent node as param is not needed - */ - -template<class T> -T* GDParser::alloc_node() { - - T *t = memnew( T); - - t->next=list; - list=t; - - if (!head) - head=t; - - t->line=tokenizer.get_token_line(); - t->column=tokenizer.get_token_column(); - return t; - -} - -bool GDParser::_end_statement() { - - if (tokenizer.get_token()==GDTokenizer::TK_SEMICOLON) { - tokenizer.advance(); - return true; //handle next - } else if (tokenizer.get_token()==GDTokenizer::TK_NEWLINE || tokenizer.get_token()==GDTokenizer::TK_EOF) { - return true; //will be handled properly - } - - return false; -} - -bool GDParser::_enter_indent_block(BlockNode* p_block) { - - - if (tokenizer.get_token()!=GDTokenizer::TK_COLON) { - - _set_error("':' expected at end of line."); - return false; - } - tokenizer.advance(); - - if (tokenizer.get_token()!=GDTokenizer::TK_NEWLINE) { - - _set_error("newline expected after ':'."); - return false; - } - - while(true) { - - if (tokenizer.get_token()!=GDTokenizer::TK_NEWLINE) { - return false; //wtf - } else if (tokenizer.get_token(1)!=GDTokenizer::TK_NEWLINE) { - - int indent = tokenizer.get_token_line_indent(); - int current = tab_level.back()->get(); - if (indent<=current) - return false; - - tab_level.push_back(indent); - tokenizer.advance(); - return true; - - } else if (p_block) { - - NewLineNode *nl = alloc_node<NewLineNode>(); - nl->line=tokenizer.get_token_line(); - p_block->statements.push_back(nl); - - } - - tokenizer.advance(); // go to next newline - } -} - -bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_static) { - - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { - tokenizer.advance(); - } else { - - while(true) { - - - Node*arg = _parse_expression(p_parent,p_static); - if (!arg) - return false; - - p_args.push_back(arg); - - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { - tokenizer.advance(); - break; - - } else if (tokenizer.get_token()==GDTokenizer::TK_COMMA) { - - if (tokenizer.get_token(1)==GDTokenizer::TK_PARENTHESIS_CLOSE) { - - _set_error("Expression expected"); - return false; - } - - tokenizer.advance(); - } else { - // something is broken - _set_error("Expected ',' or ')'"); - return false; - } - - } - } - - return true; - -} - - - -GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_allow_assign) { - -// Vector<Node*> expressions; -// Vector<OperatorNode::Operator> operators; - - Vector<Expression> expression; - - Node *expr=NULL; - - while(true) { - - - /*****************/ - /* Parse Operand */ - /*****************/ - - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) { - //subexpression () - tokenizer.advance(); - Node* subexpr = _parse_expression(p_parent,p_static); - if (!subexpr) - return NULL; - - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { - - _set_error("Expected ')' in expression"); - return NULL; - } - - tokenizer.advance(); - expr=subexpr; - - } else if (tokenizer.get_token()==GDTokenizer::TK_CONSTANT) { - - //constant defined by tokenizer - ConstantNode *constant = alloc_node<ConstantNode>(); - constant->value=tokenizer.get_token_constant(); - tokenizer.advance(); - expr=constant; - } else if (tokenizer.get_token()==GDTokenizer::TK_PR_PRELOAD) { - - //constant defined by tokenizer - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) { - _set_error("Expected '(' after 'preload'"); - return NULL; - } - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_CONSTANT || tokenizer.get_token_constant().get_type()!=Variant::STRING) { - _set_error("Expected string constant as 'preload' argument."); - return NULL; - } - - - String path = tokenizer.get_token_constant(); - if (!path.is_abs_path() && base_path!="") - path=base_path+"/"+path; - - Ref<Resource> res = ResourceLoader::load(path); - if (!res.is_valid()) { - _set_error("Can't preload resource at path: "+path); - return NULL; - } - - tokenizer.advance(); - - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')' after 'preload' path"); - return NULL; - } - - ConstantNode *constant = alloc_node<ConstantNode>(); - constant->value=res; - tokenizer.advance(); - - expr=constant; - - } else if (tokenizer.get_token()==GDTokenizer::TK_SELF) { - - if (p_static) { - _set_error("'self'' not allowed in static function or constant expression"); - return NULL; - } - //constant defined by tokenizer - SelfNode *self = alloc_node<SelfNode>(); - tokenizer.advance(); - expr=self; - } else if (tokenizer.get_token()==GDTokenizer::TK_BUILT_IN_TYPE && tokenizer.get_token(1)==GDTokenizer::TK_PERIOD) { - - Variant::Type bi_type = tokenizer.get_token_type(); - tokenizer.advance(2); - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER) { - - _set_error("Built-in type constant expected after '.'"); - return NULL; - } - StringName identifier = tokenizer.get_token_identifier(); - if (!Variant::has_numeric_constant(bi_type,identifier)) { - - _set_error("Static constant '"+identifier.operator String()+"' not present in built-in type "+Variant::get_type_name(bi_type)+"."); - return NULL; - } - - ConstantNode *cn = alloc_node<ConstantNode>(); - cn->value=Variant::get_numeric_constant_value(bi_type,identifier); - expr=cn; - tokenizer.advance(); - - } else if (tokenizer.get_token(1)==GDTokenizer::TK_PARENTHESIS_OPEN && (tokenizer.get_token()==GDTokenizer::TK_BUILT_IN_TYPE || tokenizer.get_token()==GDTokenizer::TK_IDENTIFIER || tokenizer.get_token()==GDTokenizer::TK_BUILT_IN_FUNC)) { - //function or constructor - - OperatorNode *op = alloc_node<OperatorNode>(); - op->op=OperatorNode::OP_CALL; - - if (tokenizer.get_token()==GDTokenizer::TK_BUILT_IN_TYPE) { - - TypeNode *tn = alloc_node<TypeNode>(); - tn->vtype=tokenizer.get_token_type(); - op->arguments.push_back(tn); - } else if (tokenizer.get_token()==GDTokenizer::TK_BUILT_IN_FUNC) { - - BuiltInFunctionNode *bn = alloc_node<BuiltInFunctionNode>(); - bn->function=tokenizer.get_token_built_in_func(); - op->arguments.push_back(bn); - } else { - - SelfNode *self = alloc_node<SelfNode>(); - op->arguments.push_back(self); - - IdentifierNode* id = alloc_node<IdentifierNode>(); - id->name=tokenizer.get_token_identifier(); - op->arguments.push_back(id); - } - - tokenizer.advance(2); - if (!_parse_arguments(op,op->arguments,p_static)) - return NULL; - - expr=op; - - } else if (tokenizer.get_token()==GDTokenizer::TK_IDENTIFIER) { - //identifier (reference) - - IdentifierNode *id = alloc_node<IdentifierNode>(); - id->name=tokenizer.get_token_identifier(); - tokenizer.advance(); - expr=id; - - } else if (/*tokenizer.get_token()==GDTokenizer::TK_OP_ADD ||*/ tokenizer.get_token()==GDTokenizer::TK_OP_SUB || tokenizer.get_token()==GDTokenizer::TK_OP_NOT || tokenizer.get_token()==GDTokenizer::TK_OP_BIT_INVERT) { - - //single prefix operators like !expr -expr ++expr --expr - OperatorNode *op = alloc_node<OperatorNode>(); - - Expression e; - e.is_op=true; - - switch(tokenizer.get_token()) { - case GDTokenizer::TK_OP_SUB: e.op=OperatorNode::OP_NEG; break; - case GDTokenizer::TK_OP_NOT: e.op=OperatorNode::OP_NOT; break; - case GDTokenizer::TK_OP_BIT_INVERT: e.op=OperatorNode::OP_BIT_INVERT;; break; - default: {} - } - - - tokenizer.advance(); - - if (e.op!=OperatorNode::OP_NOT && tokenizer.get_token()==GDTokenizer::TK_OP_NOT) { - _set_error("Misplaced 'not'."); - return NULL; - } - - expression.push_back(e); - continue; //only exception, must continue... - - /* - Node *subexpr=_parse_expression(op,p_static); - if (!subexpr) - return NULL; - op->arguments.push_back(subexpr); - expr=op;*/ - - } else if (tokenizer.get_token()==GDTokenizer::TK_BRACKET_OPEN) { - // array - tokenizer.advance(); - - ArrayNode *arr = alloc_node<ArrayNode>(); - bool expecting_comma=false; - - while(true) { - - if (tokenizer.get_token()==GDTokenizer::TK_EOF) { - - _set_error("Unterminated array"); - return NULL; - - } else if (tokenizer.get_token()==GDTokenizer::TK_BRACKET_CLOSE) { - tokenizer.advance(); - break; - } else if (tokenizer.get_token()==GDTokenizer::TK_NEWLINE) { - - tokenizer.advance(); //ignore newline - } else if (tokenizer.get_token()==GDTokenizer::TK_COMMA) { - if (!expecting_comma) { - _set_error("expression or ']' expected"); - return NULL; - } - - expecting_comma=false; - tokenizer.advance(); //ignore newline - } else { - //parse expression - if (expecting_comma) { - _set_error("',' or ']' expected"); - return NULL; - } - Node *n = _parse_expression(arr,p_static); - if (!n) - return NULL; - arr->elements.push_back(n); - expecting_comma=true; - } - } - - expr=arr; - } else if (tokenizer.get_token()==GDTokenizer::TK_CURLY_BRACKET_OPEN) { - // array - tokenizer.advance(); - - DictionaryNode *dict = alloc_node<DictionaryNode>(); - - enum DictExpect { - - DICT_EXPECT_KEY, - DICT_EXPECT_COLON, - DICT_EXPECT_VALUE, - DICT_EXPECT_COMMA - - }; - - Node *key=NULL; - - DictExpect expecting=DICT_EXPECT_KEY; - - while(true) { - - if (tokenizer.get_token()==GDTokenizer::TK_EOF) { - - _set_error("Unterminated dictionary"); - return NULL; - - } else if (tokenizer.get_token()==GDTokenizer::TK_CURLY_BRACKET_CLOSE) { - - if (expecting==DICT_EXPECT_COLON) { - _set_error("':' expected"); - return NULL; - } - if (expecting==DICT_EXPECT_VALUE) { - _set_error("value expected"); - return NULL; - } - tokenizer.advance(); - break; - } else if (tokenizer.get_token()==GDTokenizer::TK_NEWLINE) { - - tokenizer.advance(); //ignore newline - } else if (tokenizer.get_token()==GDTokenizer::TK_COMMA) { - - if (expecting==DICT_EXPECT_KEY) { - _set_error("key or '}' expected"); - return NULL; - } - if (expecting==DICT_EXPECT_VALUE) { - _set_error("value expected"); - return NULL; - } - if (expecting==DICT_EXPECT_COLON) { - _set_error("':' expected"); - return NULL; - } - - expecting=DICT_EXPECT_KEY; - tokenizer.advance(); //ignore newline - - } else if (tokenizer.get_token()==GDTokenizer::TK_COLON) { - - if (expecting==DICT_EXPECT_KEY) { - _set_error("key or '}' expected"); - return NULL; - } - if (expecting==DICT_EXPECT_VALUE) { - _set_error("value expected"); - return NULL; - } - if (expecting==DICT_EXPECT_COMMA) { - _set_error("',' or '}' expected"); - return NULL; - } - - expecting=DICT_EXPECT_VALUE; - tokenizer.advance(); //ignore newline - } else { - - if (expecting==DICT_EXPECT_COMMA) { - _set_error("',' or '}' expected"); - return NULL; - } - if (expecting==DICT_EXPECT_COLON) { - _set_error("':' expected"); - return NULL; - } - - if (expecting==DICT_EXPECT_KEY) { - - if (tokenizer.get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer.get_token(1)==GDTokenizer::TK_OP_ASSIGN) { - //lua style identifier, easier to write - ConstantNode *cn = alloc_node<ConstantNode>(); - cn->value = tokenizer.get_token_identifier(); - key = cn; - tokenizer.advance(2); - expecting=DICT_EXPECT_VALUE; - } else { - //python/js style more flexible - key = _parse_expression(dict,p_static); - if (!key) - return NULL; - expecting=DICT_EXPECT_COLON; - } - } - - if (expecting==DICT_EXPECT_VALUE) { - Node *value = _parse_expression(dict,p_static); - if (!value) - return NULL; - expecting=DICT_EXPECT_COMMA; - - DictionaryNode::Pair pair; - pair.key=key; - pair.value=value; - dict->elements.push_back(pair); - key=NULL; - - } - - } - } - - expr=dict; - - } else if (tokenizer.get_token()==GDTokenizer::TK_PERIOD && tokenizer.get_token(1)==GDTokenizer::TK_IDENTIFIER && tokenizer.get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) { - // parent call - - tokenizer.advance(); //goto identifier - OperatorNode *op = alloc_node<OperatorNode>(); - op->op=OperatorNode::OP_PARENT_CALL; - - - /*SelfNode *self = alloc_node<SelfNode>(); - op->arguments.push_back(self); - forbidden for now */ - - IdentifierNode* id = alloc_node<IdentifierNode>(); - id->name=tokenizer.get_token_identifier(); - op->arguments.push_back(id); - - tokenizer.advance(2); - if (!_parse_arguments(op,op->arguments,p_static)) - return NULL; - - expr=op; - - } else { - - //find list [ or find dictionary { - - print_line("found bug?"); - - _set_error("Error parsing expression, misplaced: "+String(tokenizer.get_token_name(tokenizer.get_token()))); - return NULL; //nothing - } - - if (!expr) { - ERR_EXPLAIN("GDParser bug, couldn't figure out what expression is.."); - ERR_FAIL_COND_V(!expr,NULL); - } - - - /******************/ - /* Parse Indexing */ - /******************/ - - - while (true) { - - //expressions can be indexed any number of times - - if (tokenizer.get_token()==GDTokenizer::TK_PERIOD) { - - //indexing using "." - - if (tokenizer.get_token(1)!=GDTokenizer::TK_IDENTIFIER && tokenizer.get_token(1)!=GDTokenizer::TK_BUILT_IN_FUNC ) { - _set_error("Expected identifier as member"); - return NULL; - } else if (tokenizer.get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) { - //call!! - OperatorNode * op = alloc_node<OperatorNode>(); - op->op=OperatorNode::OP_CALL; - - IdentifierNode * id = alloc_node<IdentifierNode>(); - if (tokenizer.get_token(1)==GDTokenizer::TK_BUILT_IN_FUNC ) { - //small hack so built in funcs don't obfuscate methods - - id->name=GDFunctions::get_func_name(tokenizer.get_token_built_in_func(1)); - } else { - id->name=tokenizer.get_token_identifier(1); - } - - op->arguments.push_back(expr); // call what - op->arguments.push_back(id); // call func - //get arguments - tokenizer.advance(3); - if (!_parse_arguments(op,op->arguments,p_static)) - return NULL; - expr=op; - - } else { - //simple indexing! - OperatorNode * op = alloc_node<OperatorNode>(); - op->op=OperatorNode::OP_INDEX_NAMED; - - IdentifierNode * id = alloc_node<IdentifierNode>(); - id->name=tokenizer.get_token_identifier(1); - - op->arguments.push_back(expr); - op->arguments.push_back(id); - - expr=op; - - tokenizer.advance(2); - } - - } else if (tokenizer.get_token()==GDTokenizer::TK_BRACKET_OPEN) { - //indexing using "[]" - OperatorNode * op = alloc_node<OperatorNode>(); - op->op=OperatorNode::OP_INDEX; - - tokenizer.advance(1); - - Node *subexpr = _parse_expression(op,p_static); - if (!subexpr) { - return NULL; - } - - if (tokenizer.get_token()!=GDTokenizer::TK_BRACKET_CLOSE) { - _set_error("Expected ']'"); - return NULL; - } - - op->arguments.push_back(expr); - op->arguments.push_back(subexpr); - tokenizer.advance(1); - expr=op; - - } else - break; - } - - /******************/ - /* Parse Operator */ - /******************/ - - - Expression e; - e.is_op=false; - e.node=expr; - expression.push_back(e); - - // determine which operator is next - - OperatorNode::Operator op; - bool valid=true; - -//assign, if allowed is only alowed on the first operator -#define _VALIDATE_ASSIGN if (!p_allow_assign) { _set_error("Unexpected assign."); return NULL; } p_allow_assign=false; - switch(tokenizer.get_token()) { //see operator - - case GDTokenizer::TK_OP_IN: op=OperatorNode::OP_IN; break; - case GDTokenizer::TK_OP_EQUAL: op=OperatorNode::OP_EQUAL ; break; - case GDTokenizer::TK_OP_NOT_EQUAL: op=OperatorNode::OP_NOT_EQUAL ; break; - case GDTokenizer::TK_OP_LESS: op=OperatorNode::OP_LESS ; break; - case GDTokenizer::TK_OP_LESS_EQUAL: op=OperatorNode::OP_LESS_EQUAL ; break; - case GDTokenizer::TK_OP_GREATER: op=OperatorNode::OP_GREATER ; break; - case GDTokenizer::TK_OP_GREATER_EQUAL: op=OperatorNode::OP_GREATER_EQUAL ; break; - case GDTokenizer::TK_OP_AND: op=OperatorNode::OP_AND ; break; - case GDTokenizer::TK_OP_OR: op=OperatorNode::OP_OR ; break; - case GDTokenizer::TK_OP_ADD: op=OperatorNode::OP_ADD ; break; - case GDTokenizer::TK_OP_SUB: op=OperatorNode::OP_SUB ; break; - case GDTokenizer::TK_OP_MUL: op=OperatorNode::OP_MUL ; break; - case GDTokenizer::TK_OP_DIV: op=OperatorNode::OP_DIV ; break; - case GDTokenizer::TK_OP_MOD: op=OperatorNode::OP_MOD ; break; - //case GDTokenizer::TK_OP_NEG: op=OperatorNode::OP_NEG ; break; - case GDTokenizer::TK_OP_SHIFT_LEFT: op=OperatorNode::OP_SHIFT_LEFT ; break; - case GDTokenizer::TK_OP_SHIFT_RIGHT: op=OperatorNode::OP_SHIFT_RIGHT ; break; - case GDTokenizer::TK_OP_ASSIGN: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN ; break; - case GDTokenizer::TK_OP_ASSIGN_ADD: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_ADD ; break; - case GDTokenizer::TK_OP_ASSIGN_SUB: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_SUB ; break; - case GDTokenizer::TK_OP_ASSIGN_MUL: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_MUL ; break; - case GDTokenizer::TK_OP_ASSIGN_DIV: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_DIV ; break; - case GDTokenizer::TK_OP_ASSIGN_MOD: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_MOD ; break; - case GDTokenizer::TK_OP_ASSIGN_SHIFT_LEFT: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_SHIFT_LEFT; ; break; - case GDTokenizer::TK_OP_ASSIGN_SHIFT_RIGHT: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_SHIFT_RIGHT; ; break; - case GDTokenizer::TK_OP_ASSIGN_BIT_AND: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_BIT_AND ; break; - case GDTokenizer::TK_OP_ASSIGN_BIT_OR: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_BIT_OR ; break; - case GDTokenizer::TK_OP_ASSIGN_BIT_XOR: _VALIDATE_ASSIGN op=OperatorNode::OP_ASSIGN_BIT_XOR ; break; - case GDTokenizer::TK_OP_BIT_AND: op=OperatorNode::OP_BIT_AND ; break; - case GDTokenizer::TK_OP_BIT_OR: op=OperatorNode::OP_BIT_OR ; break; - case GDTokenizer::TK_OP_BIT_XOR: op=OperatorNode::OP_BIT_XOR ; break; - case GDTokenizer::TK_PR_EXTENDS: op=OperatorNode::OP_EXTENDS; break; - default: valid=false; break; - } - - if (valid) { - e.is_op=true; - e.op=op; - expression.push_back(e); - tokenizer.advance(); - } else { - break; - } - - } - - /* Reduce the set set of expressions and place them in an operator tree, respecting precedence */ - - - while(expression.size()>1) { - - int next_op=-1; - int min_priority=0xFFFFF; - bool is_unary=false; - - for(int i=0;i<expression.size();i++) { - - - - if (!expression[i].is_op) { - - continue; - } - - int priority; - - bool unary=false; - - switch(expression[i].op) { - - case OperatorNode::OP_EXTENDS: priority=-1; break; //before anything - - case OperatorNode::OP_BIT_INVERT: priority=0; unary=true; break; - case OperatorNode::OP_NEG: priority=1; unary=true; break; - - case OperatorNode::OP_MUL: priority=2; break; - case OperatorNode::OP_DIV: priority=2; break; - case OperatorNode::OP_MOD: priority=2; break; - - case OperatorNode::OP_ADD: priority=3; break; - case OperatorNode::OP_SUB: priority=3; break; - - case OperatorNode::OP_SHIFT_LEFT: priority=4; break; - case OperatorNode::OP_SHIFT_RIGHT: priority=4; break; - - case OperatorNode::OP_BIT_AND: priority=5; break; - case OperatorNode::OP_BIT_XOR: priority=6; break; - case OperatorNode::OP_BIT_OR: priority=7; break; - - case OperatorNode::OP_LESS: priority=8; break; - case OperatorNode::OP_LESS_EQUAL: priority=8; break; - case OperatorNode::OP_GREATER: priority=8; break; - case OperatorNode::OP_GREATER_EQUAL: priority=8; break; - - case OperatorNode::OP_EQUAL: priority=8; break; - case OperatorNode::OP_NOT_EQUAL: priority=8; break; - - case OperatorNode::OP_IN: priority=10; break; - - case OperatorNode::OP_NOT: priority=11; unary=true; break; - case OperatorNode::OP_AND: priority=12; break; - case OperatorNode::OP_OR: priority=13; break; - - // ?: = 10 - - case OperatorNode::OP_ASSIGN: priority=14; break; - case OperatorNode::OP_ASSIGN_ADD: priority=14; break; - case OperatorNode::OP_ASSIGN_SUB: priority=14; break; - case OperatorNode::OP_ASSIGN_MUL: priority=14; break; - case OperatorNode::OP_ASSIGN_DIV: priority=14; break; - case OperatorNode::OP_ASSIGN_MOD: priority=14; break; - case OperatorNode::OP_ASSIGN_SHIFT_LEFT: priority=14; break; - case OperatorNode::OP_ASSIGN_SHIFT_RIGHT: priority=14; break; - case OperatorNode::OP_ASSIGN_BIT_AND: priority=14; break; - case OperatorNode::OP_ASSIGN_BIT_OR: priority=14; break; - case OperatorNode::OP_ASSIGN_BIT_XOR: priority=14; break; - - - default: { - _set_error("GDParser bug, invalid operator in expression: "+itos(expression[i].op)); - return NULL; - } - - } - - if (priority<min_priority) { - // < is used for left to right (default) - // <= is used for right to left - next_op=i; - min_priority=priority; - is_unary=unary; - } - - } - - - if (next_op==-1) { - - - _set_error("Yet another parser bug...."); - ERR_FAIL_COND_V(next_op==-1,NULL); - } - - - // OK! create operator.. - if (is_unary) { - - int expr_pos=next_op; - while(expression[expr_pos].is_op) { - - expr_pos++; - if (expr_pos==expression.size()) { - //can happen.. - _set_error("Unexpected end of expression.."); - return NULL; - } - } - - //consecutively do unary opeators - for(int i=expr_pos-1;i>=next_op;i--) { - - OperatorNode *op = alloc_node<OperatorNode>(); - op->op=expression[i].op; - op->arguments.push_back(expression[i+1].node); - expression[i].is_op=false; - expression[i].node=op; - expression.remove(i+1); - } - - - } else { - - if (next_op <1 || next_op>=(expression.size()-1)) { - _set_error("Parser bug.."); - ERR_FAIL_V(NULL); - } - - OperatorNode *op = alloc_node<OperatorNode>(); - op->op=expression[next_op].op; - - if (expression[next_op-1].is_op) { - - _set_error("Parser bug.."); - ERR_FAIL_V(NULL); - } - - if (expression[next_op+1].is_op) { - // this is not invalid and can really appear - // but it becomes invalid anyway because no binary op - // can be followed by an unary op in a valid combination, - // due to how precedence works, unaries will always dissapear first - - _set_error("Parser bug.."); - - } - - - op->arguments.push_back(expression[next_op-1].node); //expression goes as left - op->arguments.push_back(expression[next_op+1].node); //next expression goes as right - - //replace all 3 nodes by this operator and make it an expression - expression[next_op-1].node=op; - expression.remove(next_op); - expression.remove(next_op); - } - - } - - return expression[0].node; - -} - - -GDParser::Node* GDParser::_reduce_expression(Node *p_node,bool p_to_const) { - - switch(p_node->type) { - - case Node::TYPE_BUILT_IN_FUNCTION: { - //many may probably be optimizable - return p_node; - } break; - case Node::TYPE_ARRAY: { - - ArrayNode *an = static_cast<ArrayNode*>(p_node); - bool all_constants=true; - - for(int i=0;i<an->elements.size();i++) { - - an->elements[i]=_reduce_expression(an->elements[i],p_to_const); - if (an->elements[i]->type!=Node::TYPE_CONSTANT) - all_constants=false; - } - - if (all_constants && p_to_const) { - //reduce constant array expression - - ConstantNode *cn = alloc_node<ConstantNode>(); - Array arr(!p_to_const); - arr.resize(an->elements.size()); - for(int i=0;i<an->elements.size();i++) { - ConstantNode *acn = static_cast<ConstantNode*>(an->elements[i]); - arr[i]=acn->value; - - } - cn->value=arr; - return cn; - } - - return an; - - } break; - case Node::TYPE_DICTIONARY: { - - DictionaryNode *dn = static_cast<DictionaryNode*>(p_node); - bool all_constants=true; - - for(int i=0;i<dn->elements.size();i++) { - - dn->elements[i].key=_reduce_expression(dn->elements[i].key,p_to_const); - if (dn->elements[i].key->type!=Node::TYPE_CONSTANT) - all_constants=false; - dn->elements[i].value=_reduce_expression(dn->elements[i].value,p_to_const); - if (dn->elements[i].value->type!=Node::TYPE_CONSTANT) - all_constants=false; - - } - - if (all_constants && p_to_const) { - //reduce constant array expression - - ConstantNode *cn = alloc_node<ConstantNode>(); - Dictionary dict(!p_to_const); - for(int i=0;i<dn->elements.size();i++) { - ConstantNode *key_c = static_cast<ConstantNode*>(dn->elements[i].key); - ConstantNode *value_c = static_cast<ConstantNode*>(dn->elements[i].value); - - dict[key_c->value]=value_c->value; - - } - cn->value=dict; - return cn; - } - - return dn; - - - } break; - case Node::TYPE_OPERATOR: { - - OperatorNode *op=static_cast<OperatorNode*>(p_node); - - bool all_constants=true; - int last_not_constant=-1; - - for(int i=0;i<op->arguments.size();i++) { - - op->arguments[i]=_reduce_expression(op->arguments[i],p_to_const); - if (op->arguments[i]->type!=Node::TYPE_CONSTANT) { - all_constants=false; - last_not_constant=i; - } - } - - if (op->op==OperatorNode::OP_EXTENDS) { - //nothing much - return op; - - } if (op->op==OperatorNode::OP_PARENT_CALL) { - //nothing much - return op; - - } else if (op->op==OperatorNode::OP_CALL) { - //can reduce base type constructors - if ((op->arguments[0]->type==Node::TYPE_TYPE || (op->arguments[0]->type==Node::TYPE_BUILT_IN_FUNCTION && GDFunctions::is_deterministic( static_cast<BuiltInFunctionNode*>(op->arguments[0])->function))) && last_not_constant==0) { - - //native type constructor or intrinsic function - const Variant **vptr=NULL; - Vector<Variant*> ptrs; - if (op->arguments.size()>1) { - - ptrs.resize(op->arguments.size()-1); - for(int i=0;i<ptrs.size();i++) { - - - ConstantNode *cn = static_cast<ConstantNode*>(op->arguments[i+1]); - ptrs[i]=&cn->value; - } - - vptr=(const Variant**)&ptrs[0]; - - - } - - Variant::CallError ce; - Variant v; - - if (op->arguments[0]->type==Node::TYPE_TYPE) { - TypeNode *tn = static_cast<TypeNode*>(op->arguments[0]); - v = Variant::construct(tn->vtype,vptr,ptrs.size(),ce); - - } else { - GDFunctions::Function func = static_cast<BuiltInFunctionNode*>(op->arguments[0])->function; - GDFunctions::call(func,vptr,ptrs.size(),v,ce); - } - - - if (ce.error!=Variant::CallError::CALL_OK) { - - String errwhere; - if (op->arguments[0]->type==Node::TYPE_TYPE) { - TypeNode *tn = static_cast<TypeNode*>(op->arguments[0]); - errwhere="'"+Variant::get_type_name(tn->vtype)+"'' constructor"; - - } else { - GDFunctions::Function func = static_cast<BuiltInFunctionNode*>(op->arguments[0])->function; - errwhere=String("'")+GDFunctions::get_func_name(func)+"'' intrinsic function"; - - } - - switch(ce.error) { - - case Variant::CallError::CALL_ERROR_INVALID_ARGUMENT: { - - _set_error("Invalid argument (#"+itos(ce.argument+1)+") for "+errwhere+"."); - - } break; - case Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS: { - - _set_error("Too many arguments for "+errwhere+"."); - } break; - case Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS: { - - _set_error("Too few arguments for "+errwhere+"."); - } break; - default: { - _set_error("Invalid arguments for "+errwhere+"."); - - } break; - } - - return p_node; - } - - ConstantNode *cn = alloc_node<ConstantNode>(); - cn->value=v; - return cn; - - } else if (op->arguments[0]->type==Node::TYPE_BUILT_IN_FUNCTION && last_not_constant==0) { - - - - - - } - - return op; //don't reduce yet - } else if (op->op==OperatorNode::OP_INDEX) { - //can reduce indices into constant arrays or dictionaries - - if (all_constants) { - - ConstantNode *ca = static_cast<ConstantNode*>(op->arguments[0]); - ConstantNode *cb = static_cast<ConstantNode*>(op->arguments[1]); - - - - bool valid; - - Variant v = ca->value.get(cb->value,&valid); - if (!valid) { - _set_error("invalid index in constant expression"); - return op; - } - - ConstantNode *cn = alloc_node<ConstantNode>(); - cn->value=v; - return cn; - - } else if (op->arguments[0]->type==Node::TYPE_CONSTANT && op->arguments[1]->type==Node::TYPE_IDENTIFIER) { - - ConstantNode *ca = static_cast<ConstantNode*>(op->arguments[0]); - IdentifierNode *ib = static_cast<IdentifierNode*>(op->arguments[1]); - - bool valid; - Variant v = ca->value.get_named(ib->name,&valid); - if (!valid) { - _set_error("invalid index '"+String(ib->name)+"' in constant expression"); - return op; - } - - ConstantNode *cn = alloc_node<ConstantNode>(); - cn->value=v; - return cn; - - } - - return op; - } - - //validate assignment (don't assign to cosntant expression - switch(op->op) { - - case OperatorNode::OP_ASSIGN: - case OperatorNode::OP_ASSIGN_ADD: - case OperatorNode::OP_ASSIGN_SUB: - case OperatorNode::OP_ASSIGN_MUL: - case OperatorNode::OP_ASSIGN_DIV: - case OperatorNode::OP_ASSIGN_MOD: - case OperatorNode::OP_ASSIGN_SHIFT_LEFT: - case OperatorNode::OP_ASSIGN_SHIFT_RIGHT: - case OperatorNode::OP_ASSIGN_BIT_AND: - case OperatorNode::OP_ASSIGN_BIT_OR: - case OperatorNode::OP_ASSIGN_BIT_XOR: { - - if (op->arguments[0]->type==Node::TYPE_CONSTANT) { - _set_error("Can't assign to constant"); - return op; - } - - } break; - default: { break; } - } - //now se if all are constants - if (!all_constants) - return op; //nothing to reduce from here on -#define _REDUCE_UNARY(m_vop)\ - bool valid=false;\ - Variant res;\ - Variant::evaluate(m_vop,static_cast<ConstantNode*>(op->arguments[0])->value,Variant(),res,valid);\ - if (!valid) {\ - _set_error("Invalid operand for unary operator");\ - return p_node;\ - }\ - ConstantNode *cn = alloc_node<ConstantNode>();\ - cn->value=res;\ - return cn; - -#define _REDUCE_BINARY(m_vop)\ - bool valid=false;\ - Variant res;\ - Variant::evaluate(m_vop,static_cast<ConstantNode*>(op->arguments[0])->value,static_cast<ConstantNode*>(op->arguments[1])->value,res,valid);\ - if (!valid) {\ - _set_error("Invalid operands for operator");\ - return p_node;\ - }\ - ConstantNode *cn = alloc_node<ConstantNode>();\ - cn->value=res;\ - return cn; - - switch(op->op) { - - //unary operators - case OperatorNode::OP_NEG: { _REDUCE_UNARY(Variant::OP_NEGATE); } break; - case OperatorNode::OP_NOT: { _REDUCE_UNARY(Variant::OP_NOT); } break; - case OperatorNode::OP_BIT_INVERT: { _REDUCE_UNARY(Variant::OP_BIT_NEGATE); } break; - //binary operators (in precedence order) - case OperatorNode::OP_IN: { _REDUCE_BINARY(Variant::OP_IN); } break; - case OperatorNode::OP_EQUAL: { _REDUCE_BINARY(Variant::OP_EQUAL); } break; - case OperatorNode::OP_NOT_EQUAL: { _REDUCE_BINARY(Variant::OP_NOT_EQUAL); } break; - case OperatorNode::OP_LESS: { _REDUCE_BINARY(Variant::OP_LESS); } break; - case OperatorNode::OP_LESS_EQUAL: { _REDUCE_BINARY(Variant::OP_LESS_EQUAL); } break; - case OperatorNode::OP_GREATER: { _REDUCE_BINARY(Variant::OP_GREATER); } break; - case OperatorNode::OP_GREATER_EQUAL: { _REDUCE_BINARY(Variant::OP_GREATER_EQUAL); } break; - case OperatorNode::OP_AND: { _REDUCE_BINARY(Variant::OP_AND); } break; - case OperatorNode::OP_OR: { _REDUCE_BINARY(Variant::OP_OR); } break; - case OperatorNode::OP_ADD: { _REDUCE_BINARY(Variant::OP_ADD); } break; - case OperatorNode::OP_SUB: { _REDUCE_BINARY(Variant::OP_SUBSTRACT); } break; - case OperatorNode::OP_MUL: { _REDUCE_BINARY(Variant::OP_MULTIPLY); } break; - case OperatorNode::OP_DIV: { _REDUCE_BINARY(Variant::OP_DIVIDE); } break; - case OperatorNode::OP_MOD: { _REDUCE_BINARY(Variant::OP_MODULE); } break; - case OperatorNode::OP_SHIFT_LEFT: { _REDUCE_BINARY(Variant::OP_SHIFT_LEFT); } break; - case OperatorNode::OP_SHIFT_RIGHT: { _REDUCE_BINARY(Variant::OP_SHIFT_RIGHT); } break; - case OperatorNode::OP_BIT_AND: { _REDUCE_BINARY(Variant::OP_BIT_AND); } break; - case OperatorNode::OP_BIT_OR: { _REDUCE_BINARY(Variant::OP_BIT_OR); } break; - case OperatorNode::OP_BIT_XOR: { _REDUCE_BINARY(Variant::OP_BIT_XOR); } break; - default: { ERR_FAIL_V(op); } - } - - ERR_FAIL_V(op); - } break; - default: { - return p_node; - } break; - - } -} - -GDParser::Node* GDParser::_parse_and_reduce_expression(Node *p_parent,bool p_static,bool p_reduce_const,bool p_allow_assign) { - - Node* expr=_parse_expression(p_parent,p_static,p_allow_assign); - if (!expr || error_set) - return NULL; - expr = _reduce_expression(expr,p_reduce_const); - if (!expr || error_set) - return NULL; - return expr; -} - -void GDParser::_parse_block(BlockNode *p_block,bool p_static) { - - int indent_level = tab_level.back()->get(); - - -#ifdef DEBUG_ENABLED - - NewLineNode *nl = alloc_node<NewLineNode>(); - - nl->line=tokenizer.get_token_line(); - p_block->statements.push_back(nl); -#endif - - while(true) { - - GDTokenizer::Token token = tokenizer.get_token(); - if (error_set) - return; - - if (indent_level>tab_level.back()->get()) { - p_block->end_line=tokenizer.get_token_line(); - return; //go back a level - } - - switch(token) { - - - case GDTokenizer::TK_EOF: - p_block->end_line=tokenizer.get_token_line(); - case GDTokenizer::TK_ERROR: { - return; //go back - - //end of file! - - } break; - case GDTokenizer::TK_NEWLINE: { - - NewLineNode *nl = alloc_node<NewLineNode>(); - nl->line=tokenizer.get_token_line(); - p_block->statements.push_back(nl); - - if (!_parse_newline()) { - if (!error_set) { - p_block->end_line=tokenizer.get_token_line(); - } - return; - } - } break; - case GDTokenizer::TK_CF_PASS: { - if (tokenizer.get_token(1)!=GDTokenizer::TK_SEMICOLON && tokenizer.get_token(1)!=GDTokenizer::TK_NEWLINE ) { - - _set_error("Expected ';' or <NewLine>."); - return; - } - tokenizer.advance(); - } break; - case GDTokenizer::TK_PR_VAR: { - //variale declaration and (eventual) initialization - - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER) { - - _set_error("Expected identifier for local variable name."); - return; - } - StringName n = tokenizer.get_token_identifier(); - tokenizer.advance(); - - p_block->variables.push_back(n); //line? - p_block->variable_lines.push_back(tokenizer.get_token_line()); - - - //must know when the local variable is declared - LocalVarNode *lv = alloc_node<LocalVarNode>(); - lv->name=n; - p_block->statements.push_back(lv); - - Node *assigned=NULL; - - if (tokenizer.get_token()==GDTokenizer::TK_OP_ASSIGN) { - - tokenizer.advance(); - Node *subexpr=NULL; - - subexpr = _parse_and_reduce_expression(p_block,p_static); - if (!subexpr) - return; - - lv->assign=subexpr; - assigned=subexpr; - } else { - - ConstantNode *c = alloc_node<ConstantNode>(); - c->value=Variant(); - assigned = c; - - } - IdentifierNode *id = alloc_node<IdentifierNode>(); - id->name=n; - - - OperatorNode *op = alloc_node<OperatorNode>(); - op->op=OperatorNode::OP_ASSIGN; - op->arguments.push_back(id); - op->arguments.push_back(assigned); - p_block->statements.push_back(op); - - _end_statement(); - - - } break; - case GDTokenizer::TK_CF_IF: { - - tokenizer.advance(); - Node *condition = _parse_and_reduce_expression(p_block,p_static); - if (!condition) - return; - - ControlFlowNode *cf_if = alloc_node<ControlFlowNode>(); - - cf_if->cf_type=ControlFlowNode::CF_IF; - cf_if->arguments.push_back(condition); - - cf_if->body = alloc_node<BlockNode>(); - p_block->sub_blocks.push_back(cf_if->body); - - if (!_enter_indent_block(cf_if->body)) { - p_block->end_line=tokenizer.get_token_line(); - return; - } - - _parse_block(cf_if->body,p_static); - if (error_set) - return; - p_block->statements.push_back(cf_if); - - while(true) { - - while(tokenizer.get_token()==GDTokenizer::TK_NEWLINE) { - tokenizer.advance(); - } - - if (tab_level.back()->get() < indent_level) { //not at current indent level - p_block->end_line=tokenizer.get_token_line(); - return; - } - - if (tokenizer.get_token()==GDTokenizer::TK_CF_ELIF) { - - if (tab_level.back()->get() > indent_level) { - - _set_error("Invalid indent"); - return; - } - - tokenizer.advance(); - - cf_if->body_else=alloc_node<BlockNode>(); - p_block->sub_blocks.push_back(cf_if->body_else); - - ControlFlowNode *cf_else = alloc_node<ControlFlowNode>(); - cf_else->cf_type=ControlFlowNode::CF_IF; - - //condition - Node *condition = _parse_and_reduce_expression(p_block,p_static); - if (!condition) - return; - cf_else->arguments.push_back(condition); - cf_else->cf_type=ControlFlowNode::CF_IF; - - cf_if->body_else->statements.push_back(cf_else); - cf_if=cf_else; - cf_if->body=alloc_node<BlockNode>(); - p_block->sub_blocks.push_back(cf_if->body); - - - if (!_enter_indent_block(cf_if->body)) { - p_block->end_line=tokenizer.get_token_line(); - return; - } - - _parse_block(cf_else->body,p_static); - if (error_set) - return; - - - } else if (tokenizer.get_token()==GDTokenizer::TK_CF_ELSE) { - - if (tab_level.back()->get() > indent_level) { - - _set_error("Invalid indent"); - return; - } - - - tokenizer.advance(); - cf_if->body_else=alloc_node<BlockNode>(); - p_block->sub_blocks.push_back(cf_if->body_else); - - if (!_enter_indent_block(cf_if->body_else)) { - p_block->end_line=tokenizer.get_token_line(); - return; - } - _parse_block(cf_if->body_else,p_static); - if (error_set) - return; - - - break; //after else, exit - - } else - break; - - } - - - } break; - case GDTokenizer::TK_CF_WHILE: { - - tokenizer.advance(); - Node *condition = _parse_and_reduce_expression(p_block,p_static); - if (!condition) - return; - - ControlFlowNode *cf_while = alloc_node<ControlFlowNode>(); - - cf_while->cf_type=ControlFlowNode::CF_WHILE; - cf_while->arguments.push_back(condition); - - cf_while->body = alloc_node<BlockNode>(); - p_block->sub_blocks.push_back(cf_while->body); - - if (!_enter_indent_block(cf_while->body)) { - p_block->end_line=tokenizer.get_token_line(); - return; - } - - _parse_block(cf_while->body,p_static); - if (error_set) - return; - p_block->statements.push_back(cf_while); - } break; - case GDTokenizer::TK_CF_FOR: { - - tokenizer.advance(); - - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER) { - - _set_error("identifier expected after 'for'"); - } - - IdentifierNode *id = alloc_node<IdentifierNode>(); - id->name=tokenizer.get_token_identifier(); - - tokenizer.advance(); - - if (tokenizer.get_token()!=GDTokenizer::TK_OP_IN) { - _set_error("'in' expected after identifier"); - return; - } - - tokenizer.advance(); - - Node *container = _parse_and_reduce_expression(p_block,p_static); - if (!container) - return; - - ControlFlowNode *cf_for = alloc_node<ControlFlowNode>(); - - cf_for->cf_type=ControlFlowNode::CF_FOR; - cf_for->arguments.push_back(id); - cf_for->arguments.push_back(container); - - cf_for->body = alloc_node<BlockNode>(); - p_block->sub_blocks.push_back(cf_for->body); - - if (!_enter_indent_block(cf_for->body)) { - p_block->end_line=tokenizer.get_token_line(); - return; - } - - _parse_block(cf_for->body,p_static); - if (error_set) - return; - p_block->statements.push_back(cf_for); - } break; - case GDTokenizer::TK_CF_CONTINUE: { - - tokenizer.advance(); - ControlFlowNode *cf_continue = alloc_node<ControlFlowNode>(); - cf_continue->cf_type=ControlFlowNode::CF_CONTINUE; - p_block->statements.push_back(cf_continue); - if (!_end_statement()) { - _set_error("Expected end of statement (continue)"); - return; - } - } break; - case GDTokenizer::TK_CF_BREAK: { - - tokenizer.advance(); - ControlFlowNode *cf_break = alloc_node<ControlFlowNode>(); - cf_break->cf_type=ControlFlowNode::CF_BREAK; - p_block->statements.push_back(cf_break); - if (!_end_statement()) { - _set_error("Expected end of statement (break)"); - return; - } - } break; - case GDTokenizer::TK_CF_RETURN: { - - tokenizer.advance(); - ControlFlowNode *cf_return = alloc_node<ControlFlowNode>(); - cf_return->cf_type=ControlFlowNode::CF_RETURN; - - - - if (tokenizer.get_token()==GDTokenizer::TK_SEMICOLON || tokenizer.get_token()==GDTokenizer::TK_NEWLINE || tokenizer.get_token()==GDTokenizer::TK_EOF) { - //expect end of statement - p_block->statements.push_back(cf_return); - if (!_end_statement()) { - return; - } - } else { - //expect expression - Node *retexpr = _parse_and_reduce_expression(p_block,p_static); - if (!retexpr) - return; - cf_return->arguments.push_back(retexpr); - p_block->statements.push_back(cf_return); - if (!_end_statement()) { - _set_error("Expected end of statement after return expression."); - return; - } - } - - - } break; - case GDTokenizer::TK_PR_ASSERT: { - - tokenizer.advance(); - Node *condition = _parse_and_reduce_expression(p_block,p_static); - if (!condition) - return; - AssertNode *an = alloc_node<AssertNode>(); - an->condition=condition; - p_block->statements.push_back(an); - - if (!_end_statement()) { - _set_error("Expected end of statement after assert."); - return; - } - } break; - default: { - - Node *expression = _parse_and_reduce_expression(p_block,p_static,false,true); - if (!expression) - return; - p_block->statements.push_back(expression); - if (!_end_statement()) { - _set_error("Expected end of statement after expression."); - return; - } - - } break; - /* - case GDTokenizer::TK_CF_LOCAL: { - - if (tokenizer.get_token(1)!=GDTokenizer::TK_SEMICOLON && tokenizer.get_token(1)!=GDTokenizer::TK_NEWLINE ) { - - _set_error("Expected ';' or <NewLine>."); - } - tokenizer.advance(); - } break; - */ - - } - } - -} - -bool GDParser::_parse_newline() { - - if (tokenizer.get_token(1)!=GDTokenizer::TK_EOF && tokenizer.get_token(1)!=GDTokenizer::TK_NEWLINE) { - - int indent = tokenizer.get_token_line_indent(); - int current_indent = tab_level.back()->get(); - - if (indent>current_indent) { - _set_error("Unexpected indent."); - return false; - } - - if (indent<current_indent) { - - while(indent<current_indent) { - - //exit block - if (tab_level.size()==1) { - _set_error("Invalid indent. BUG?"); - return false; - } - - tab_level.pop_back(); - - if (tab_level.back()->get()<indent) { - - _set_error("Unindent does not match any outer indentation level."); - return false; - } - current_indent = tab_level.back()->get(); - } - - tokenizer.advance(); - return false; - } - } - - tokenizer.advance(); - return true; - -} - - -void GDParser::_parse_extends(ClassNode *p_class) { - - - if (p_class->extends_used) { - - _set_error("'extends' already used for this class."); - return; - } - - if (!p_class->constant_expressions.empty() || !p_class->subclasses.empty() || !p_class->functions.empty() || !p_class->variables.empty()) { - - _set_error("'extends' must be used before anything else."); - return; - } - - p_class->extends_used=true; - - //see if inheritance happens from a file - tokenizer.advance(); - - if (tokenizer.get_token()==GDTokenizer::TK_CONSTANT) { - - Variant constant = tokenizer.get_token_constant(); - if (constant.get_type()!=Variant::STRING) { - - _set_error("'extends' constant must be a string."); - return; - } - - p_class->extends_file=constant; - tokenizer.advance(); - - if (tokenizer.get_token()!=GDTokenizer::TK_PERIOD) { - return; - } else - tokenizer.advance(); - - } - - while(true) { - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER) { - - _set_error("Invalid 'extends' syntax, expected string constant (path) and/or identifier (parent class)."); - return; - } - - StringName identifier=tokenizer.get_token_identifier(); - p_class->extends_class.push_back(identifier); - - tokenizer.advance(1); - if (tokenizer.get_token()!=GDTokenizer::TK_PERIOD) - return; - } - -} - -void GDParser::_parse_class(ClassNode *p_class) { - - int indent_level = tab_level.back()->get(); - - while(true) { - - GDTokenizer::Token token = tokenizer.get_token(); - if (error_set) - return; - - if (indent_level>tab_level.back()->get()) { - p_class->end_line=tokenizer.get_token_line(); - return; //go back a level - } - - switch(token) { - - case GDTokenizer::TK_EOF: - p_class->end_line=tokenizer.get_token_line(); - case GDTokenizer::TK_ERROR: { - return; //go back - //end of file! - } break; - case GDTokenizer::TK_NEWLINE: { - if (!_parse_newline()) { - if (!error_set) { - p_class->end_line=tokenizer.get_token_line(); - } - return; - } - } break; - case GDTokenizer::TK_PR_EXTENDS: { - - _parse_extends(p_class); - if (error_set) - return; - _end_statement(); - - - } break; - case GDTokenizer::TK_PR_TOOL: { - - if (p_class->tool) { - - _set_error("tool used more than once"); - return; - } - - p_class->tool=true; - tokenizer.advance(); - - } break; - case GDTokenizer::TK_PR_CLASS: { - //class inside class :D - - StringName name; - StringName extends; - - if (tokenizer.get_token(1)!=GDTokenizer::TK_IDENTIFIER) { - - _set_error("'class' syntax: 'class <Name>:' or 'class <Name> extends <BaseClass>:'"); - return; - } - name = tokenizer.get_token_identifier(1); - tokenizer.advance(2); - - ClassNode *newclass = alloc_node<ClassNode>(); - newclass->initializer = alloc_node<BlockNode>(); - newclass->name=name; - - p_class->subclasses.push_back(newclass); - - - if (tokenizer.get_token()==GDTokenizer::TK_PR_EXTENDS) { - - _parse_extends(newclass); - if (error_set) - return; - } - - if (!_enter_indent_block()) { - - _set_error("Indented block expected."); - return; - } - _parse_class(newclass); - - } break; - /* this is for functions.... - case GDTokenizer::TK_CF_PASS: { - - tokenizer.advance(1); - } break; - */ - case GDTokenizer::TK_PR_STATIC: { - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_PR_FUNCTION) { - - _set_error("Expected 'func'."); - return; - } - - }; //fallthrough to function - case GDTokenizer::TK_PR_FUNCTION: { - - bool _static=false; - - if (tokenizer.get_token(-1)==GDTokenizer::TK_PR_STATIC) { - - _static=true; - } - - - if (tokenizer.get_token(1)!=GDTokenizer::TK_IDENTIFIER) { - - _set_error("Expected identifier after 'func' (syntax: 'func <identifier>([arguments]):' )."); - return; - } - - StringName name = tokenizer.get_token_identifier(1); - - for(int i=0;i<p_class->functions.size();i++) { - if (p_class->functions[i]->name==name) { - _set_error("Function '"+String(name)+"' already exists in this class (at line: "+itos(p_class->functions[i]->line)+")."); - } - } - for(int i=0;i<p_class->static_functions.size();i++) { - if (p_class->static_functions[i]->name==name) { - _set_error("Function '"+String(name)+"' already exists in this class (at line: "+itos(p_class->static_functions[i]->line)+")."); - } - } - tokenizer.advance(2); - - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) { - - _set_error("Expected '(' after identifier (syntax: 'func <identifier>([arguments]):' )."); - return; - } - - tokenizer.advance(); - - Vector<StringName> arguments; - Vector<Node*> default_values; - - int fnline = tokenizer.get_token_line(); - - - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { - //has arguments - bool defaulting=false; - while(true) { - - if (tokenizer.get_token()==GDTokenizer::TK_PR_VAR) { - - tokenizer.advance(); //var before the identifier is allowed - } - - - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER) { - - _set_error("Expected identifier for argument."); - return; - } - - StringName argname=tokenizer.get_token_identifier(); - arguments.push_back(argname); - - tokenizer.advance(); - - if (defaulting && tokenizer.get_token()!=GDTokenizer::TK_OP_ASSIGN) { - - _set_error("Default parameter expected."); - return; - } - - //tokenizer.advance(); - - - if (tokenizer.get_token()==GDTokenizer::TK_OP_ASSIGN) { - defaulting=true; - tokenizer.advance(1); - Node *defval=NULL; - - defval=_parse_and_reduce_expression(p_class,_static); - if (!defval || error_set) - return; - - OperatorNode *on = alloc_node<OperatorNode>(); - on->op=OperatorNode::OP_ASSIGN; - - IdentifierNode *in = alloc_node<IdentifierNode>(); - in->name=argname; - - on->arguments.push_back(in); - on->arguments.push_back(defval); - /* no .. - if (defval->type!=Node::TYPE_CONSTANT) { - - _set_error("default argument must be constant"); - } - */ - default_values.push_back(on); - } - - if (tokenizer.get_token()==GDTokenizer::TK_COMMA) { - tokenizer.advance(); - continue; - } else if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { - - _set_error("Expected ',' or ')'."); - return; - } - - break; - } - - - } - - tokenizer.advance(); - - BlockNode *block = alloc_node<BlockNode>(); - - if (name=="_init") { - - if (p_class->extends_used) { - - OperatorNode *cparent = alloc_node<OperatorNode>(); - cparent->op=OperatorNode::OP_PARENT_CALL; - block->statements.push_back(cparent); - - IdentifierNode *id = alloc_node<IdentifierNode>(); - id->name="_init"; - cparent->arguments.push_back(id); - - if (tokenizer.get_token()==GDTokenizer::TK_PERIOD) { - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_OPEN) { - _set_error("expected '(' for parent constructor arguments."); - } - tokenizer.advance(); - - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { - //has arguments - while(true) { - - Node *arg = _parse_and_reduce_expression(p_class,_static); - cparent->arguments.push_back(arg); - - if (tokenizer.get_token()==GDTokenizer::TK_COMMA) { - tokenizer.advance(); - continue; - } else if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { - - _set_error("Expected ',' or ')'."); - return; - } - - break; - - } - } - - tokenizer.advance(); - } - } else { - - - if (tokenizer.get_token()==GDTokenizer::TK_PERIOD) { - - _set_error("Parent constructor call found for a class without inheritance."); - return; - } - - } - } - - if (!_enter_indent_block(block)) { - - _set_error("Indented block expected."); - return; - } - - FunctionNode *function = alloc_node<FunctionNode>(); - function->name=name; - function->arguments=arguments; - function->default_values=default_values; - function->_static=_static; - function->line=fnline; - - - if (_static) - p_class->static_functions.push_back(function); - else - p_class->functions.push_back(function); - - - _parse_block(block,_static); - function->body=block; - //arguments - } break; - case GDTokenizer::TK_PR_EXPORT: { - - tokenizer.advance(); - - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_OPEN) { - - tokenizer.advance(); - if (tokenizer.get_token()==GDTokenizer::TK_BUILT_IN_TYPE) { - - Variant::Type type = tokenizer.get_token_type(); - if (type==Variant::NIL) { - _set_error("Can't export null type."); - return; - } - current_export.type=type; - tokenizer.advance(); - if (tokenizer.get_token()==GDTokenizer::TK_COMMA) { - // hint expected next! - tokenizer.advance(); - switch(current_export.type) { - - - case Variant::INT: { - - if (tokenizer.get_token()==GDTokenizer::TK_CONSTANT && tokenizer.get_token_constant().get_type()==Variant::STRING) { - //enumeration - current_export.hint=PROPERTY_HINT_ENUM; - bool first=true; - while(true) { - - if (tokenizer.get_token()!=GDTokenizer::TK_CONSTANT || tokenizer.get_token_constant().get_type()!=Variant::STRING) { - - current_export=PropertyInfo(); - _set_error("Expected a string constant in enumeration hint."); - } - - String c = tokenizer.get_token_constant(); - if (!first) - current_export.hint_string+=","; - else - first=false; - - current_export.hint_string+=c.xml_escape(); - - tokenizer.advance(); - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) - break; - - if (tokenizer.get_token()!=GDTokenizer::TK_COMMA) { - current_export=PropertyInfo(); - _set_error("Expected ')' or ',' in enumeration hint."); - } - - tokenizer.advance(); - - } - - break; - } - - }; - case Variant::REAL: { - - if (tokenizer.get_token()!=GDTokenizer::TK_CONSTANT || !tokenizer.get_token_constant().is_num()) { - - current_export=PropertyInfo(); - _set_error("Expected a range in numeric hint."); - - } - //enumeration - current_export.hint=PROPERTY_HINT_RANGE; - - current_export.hint_string=tokenizer.get_token_constant().operator String(); - tokenizer.advance(); - - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) { - current_export.hint_string="0,"+current_export.hint_string; - break; - } - - if (tokenizer.get_token()!=GDTokenizer::TK_COMMA) { - - current_export=PropertyInfo(); - _set_error("Expected ',' or ')' in numeric range hint."); - } - - tokenizer.advance(); - - if (tokenizer.get_token()!=GDTokenizer::TK_CONSTANT || !tokenizer.get_token_constant().is_num()) { - - current_export=PropertyInfo(); - _set_error("Expected a number as upper bound in numeric range hint."); - } - - current_export.hint_string+=","+tokenizer.get_token_constant().operator String(); - tokenizer.advance(); - - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) - break; - - if (tokenizer.get_token()!=GDTokenizer::TK_COMMA) { - - current_export=PropertyInfo(); - _set_error("Expected ',' or ')' in numeric range hint."); - } - - tokenizer.advance(); - - if (tokenizer.get_token()!=GDTokenizer::TK_CONSTANT || !tokenizer.get_token_constant().is_num()) { - - current_export=PropertyInfo(); - _set_error("Expected a number as step in numeric range hint."); - } - - current_export.hint_string+=","+tokenizer.get_token_constant().operator String(); - tokenizer.advance(); - - } break; - case Variant::STRING: { - - if (tokenizer.get_token()==GDTokenizer::TK_CONSTANT && tokenizer.get_token_constant().get_type()==Variant::STRING) { - //enumeration - current_export.hint=PROPERTY_HINT_ENUM; - bool first=true; - while(true) { - - if (tokenizer.get_token()!=GDTokenizer::TK_CONSTANT || tokenizer.get_token_constant().get_type()!=Variant::STRING) { - - current_export=PropertyInfo(); - _set_error("Expected a string constant in enumeration hint."); - } - - String c = tokenizer.get_token_constant(); - if (!first) - current_export.hint_string+=","; - else - first=false; - - current_export.hint_string+=c.xml_escape(); - tokenizer.advance(); - if (tokenizer.get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) - break; - - if (tokenizer.get_token()!=GDTokenizer::TK_COMMA) { - current_export=PropertyInfo(); - _set_error("Expected ')' or ',' in enumeration hint."); - return; - } - tokenizer.advance(); - - } - - break; - } - - if (tokenizer.get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer.get_token_identifier()=="DIR") { - - current_export.hint=PROPERTY_HINT_DIR; - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')' in hint."); - return; - } - break; - } - - if (tokenizer.get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer.get_token_identifier()=="FILE") { - - current_export.hint=PROPERTY_HINT_FILE; - tokenizer.advance(); - - if (tokenizer.get_token()==GDTokenizer::TK_COMMA) { - - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_CONSTANT || tokenizer.get_token_constant().get_type()!=Variant::STRING) { - - _set_error("Expected string constant with filter"); - return; - } - current_export.hint_string=tokenizer.get_token_constant(); - tokenizer.advance(); - - } - - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { - _set_error("Expected ')' in hint."); - return; - } - break; - } - } break; - case Variant::COLOR: { - - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER ) { - - current_export=PropertyInfo(); - _set_error("Color type hint expects RGB or RGBA as hints"); - return; - } - - String identifier = tokenizer.get_token_identifier(); - if (identifier=="RGB") { - current_export.hint=PROPERTY_HINT_COLOR_NO_ALPHA; - } else if (identifier=="RGBA") { - //none - } else { - current_export=PropertyInfo(); - _set_error("Color type hint expects RGB or RGBA as hints"); - return; - } - tokenizer.advance(); - - } break; - default: { - - current_export=PropertyInfo(); - _set_error("Type '"+Variant::get_type_name(type)+"' can't take hints."); - return; - } break; - } - - } - - } else if (tokenizer.get_token()==GDTokenizer::TK_IDENTIFIER) { - - String identifier = tokenizer.get_token_identifier(); - if (!ObjectTypeDB::is_type(identifier,"Resource")) { - - current_export=PropertyInfo(); - _set_error("Export hint not a type or resource."); - } - - current_export.type=Variant::OBJECT; - current_export.hint=PROPERTY_HINT_RESOURCE_TYPE; - current_export.hint_string=identifier; - - tokenizer.advance(); - } - - if (tokenizer.get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) { - - current_export=PropertyInfo(); - _set_error("Expected ')' or ',' after export hint."); - return; - - } - - tokenizer.advance(); - - } - - if (tokenizer.get_token()!=GDTokenizer::TK_PR_VAR) { - - current_export=PropertyInfo(); - _set_error("Expected 'var'."); - return; - } - - }; //fallthrough to var - case GDTokenizer::TK_PR_VAR: { - //variale declaration and (eventual) initialization - - ClassNode::Member member; - bool autoexport = tokenizer.get_token(-1)==GDTokenizer::TK_PR_EXPORT; - if (current_export.type!=Variant::NIL) { - member._export=current_export; - current_export=PropertyInfo(); - } - - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER) { - - _set_error("Expected identifier for member variable name."); - return; - } - - member.identifier=tokenizer.get_token_identifier(); - member._export.name=member.identifier; - tokenizer.advance(); - - p_class->variables.push_back(member); - - if (tokenizer.get_token()!=GDTokenizer::TK_OP_ASSIGN) { - - if (autoexport) { - - _set_error("Type-less export needs a constant expression assigned to infer type."); - return; - } - break; - } -#ifdef DEBUG_ENABLED - int line = tokenizer.get_token_line(); -#endif - tokenizer.advance(); - - Node *subexpr=NULL; - - subexpr = _parse_and_reduce_expression(p_class,false); - if (!subexpr) - return; - - if (autoexport) { - if (subexpr->type==Node::TYPE_ARRAY) { - - p_class->variables[p_class->variables.size()-1]._export.type=Variant::ARRAY; - - } else if (subexpr->type==Node::TYPE_DICTIONARY) { - - p_class->variables[p_class->variables.size()-1]._export.type=Variant::DICTIONARY; - - } else { - - if (subexpr->type!=Node::TYPE_CONSTANT) { - - _set_error("Type-less export needs a constant expression assigned to infer type."); - return; - } - - ConstantNode *cn = static_cast<ConstantNode*>(subexpr); - if (cn->value.get_type()==Variant::NIL) { - - _set_error("Can't accept a null constant expression for infering export type."); - return; - } - p_class->variables[p_class->variables.size()-1]._export.type=cn->value.get_type(); - } - } -#ifdef TOOLS_ENABLED - if (subexpr->type==Node::TYPE_CONSTANT && p_class->variables[p_class->variables.size()-1]._export.type!=Variant::NIL) { - - ConstantNode *cn = static_cast<ConstantNode*>(subexpr); - if (cn->value.get_type()!=Variant::NIL) { - p_class->variables[p_class->variables.size()-1].default_value=cn->value; - } - } -#endif - - - - IdentifierNode *id = alloc_node<IdentifierNode>(); - id->name=member.identifier; - - OperatorNode *op = alloc_node<OperatorNode>(); - op->op=OperatorNode::OP_ASSIGN; - op->arguments.push_back(id); - op->arguments.push_back(subexpr); - -#ifdef DEBUG_ENABLED - NewLineNode *nl = alloc_node<NewLineNode>(); - nl->line=line; - p_class->initializer->statements.push_back(nl); -#endif - p_class->initializer->statements.push_back(op); - - _end_statement(); - - } break; - case GDTokenizer::TK_PR_CONST: { - //variale declaration and (eventual) initialization - - ClassNode::Constant constant; - - tokenizer.advance(); - if (tokenizer.get_token()!=GDTokenizer::TK_IDENTIFIER) { - - _set_error("Expected name (identifier) for constant."); - return; - } - - constant.identifier=tokenizer.get_token_identifier(); - tokenizer.advance(); - - if (tokenizer.get_token()!=GDTokenizer::TK_OP_ASSIGN) { - _set_error("Constant expects assignment."); - return; - } - - tokenizer.advance(); - - Node *subexpr=NULL; - - subexpr = _parse_and_reduce_expression(p_class,true,true); - if (!subexpr) - return; - - if (subexpr->type!=Node::TYPE_CONSTANT) { - _set_error("Expected constant expression"); - } - constant.expression=subexpr; - - p_class->constant_expressions.push_back(constant); - - _end_statement(); - - - } break; - - - default: { - - _set_error(String()+"Unexpected token: "+tokenizer.get_token_name(tokenizer.get_token())+":"+tokenizer.get_token_identifier()); - return; - - } break; - - } - - } - - -} - - -void GDParser::_set_error(const String& p_error, int p_line, int p_column) { - - - if (error_set) - return; //allow no further errors - - error=p_error; - error_line=p_line<0?tokenizer.get_token_line():p_line; - error_column=p_column<0?tokenizer.get_token_column():p_column; - error_set=true; -} - -String GDParser::get_error() const { - - return error; -} - -int GDParser::get_error_line() const { - - return error_line; -} -int GDParser::get_error_column() const { - - return error_column; -} - - -Error GDParser::parse(const String& p_code,const String& p_base_path) { - - base_path=p_base_path; - - tokenizer.set_code(p_code); - - clear(); - - //assume class - ClassNode *main_class = alloc_node<ClassNode>(); - main_class->initializer = alloc_node<BlockNode>(); - - _parse_class(main_class); - - if (tokenizer.get_token()==GDTokenizer::TK_ERROR) { - error_set=false; - _set_error("Parse Error: "+tokenizer.get_token_error()); - } - - if (error_set) { - - return ERR_PARSE_ERROR; - } - return OK; -} - -const GDParser::Node *GDParser::get_parse_tree() const { - - return head; -} - -void GDParser::clear() { - - while(list) { - - Node *l=list; - list=list->next; - memdelete(l); - } - - head=NULL; - list=NULL; - - error_set=false; - tab_level.clear(); - tab_level.push_back(0); - error_line=0; - error_column=0; - current_export.type=Variant::NIL; - error=""; - -} - -GDParser::GDParser() { - - head=NULL; - list=NULL; - clear(); - -} - -GDParser::~GDParser() { - - clear(); -} diff --git a/script/gdscript/gd_parser.h b/script/gdscript/gd_parser.h deleted file mode 100644 index 8011495340..0000000000 --- a/script/gdscript/gd_parser.h +++ /dev/null @@ -1,397 +0,0 @@ -/*************************************************************************/ -/* 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 diff --git a/script/gdscript/gd_pretty_print.cpp b/script/gdscript/gd_pretty_print.cpp deleted file mode 100644 index a5a993bb3a..0000000000 --- a/script/gdscript/gd_pretty_print.cpp +++ /dev/null @@ -1,34 +0,0 @@ -/*************************************************************************/ -/* 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() { - - -} diff --git a/script/gdscript/gd_pretty_print.h b/script/gdscript/gd_pretty_print.h deleted file mode 100644 index fbf002295b..0000000000 --- a/script/gdscript/gd_pretty_print.h +++ /dev/null @@ -1,40 +0,0 @@ -/*************************************************************************/ -/* 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 diff --git a/script/gdscript/gd_script.cpp b/script/gdscript/gd_script.cpp deleted file mode 100644 index 5679e1e066..0000000000 --- a/script/gdscript/gd_script.cpp +++ /dev/null @@ -1,2222 +0,0 @@ -/*************************************************************************/ -/* gd_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 "gd_script.h" -#include "globals.h" -#include "global_constants.h" -#include "gd_compiler.h" -#include "os/file_access.h" - -/* TODO: - - *populate globals - *do checks as close to debugger as possible (but don't do debugger) - *const check plz - *check arguments and default arguments in GDFunction - -get property list in instance? - *missing opcodes - -const checks - -make thread safe - */ - - - -Variant *GDFunction::_get_variant(int p_address,GDInstance *p_instance,GDScript *p_script,Variant &self, Variant *p_stack,String& r_error) const{ - - int address = p_address&ADDR_MASK; - - //sequential table (jump table generated by compiler) - switch((p_address&ADDR_TYPE_MASK)>>ADDR_BITS) { - - case ADDR_TYPE_SELF: { - - if (!p_instance) { - r_error="Cannot access self without instance."; - return NULL; - } - return &self; - } break; - case ADDR_TYPE_MEMBER: { - //member indexing is O(1) - if (!p_instance) { - r_error="Cannot access member without instance."; - return NULL; - } - return &p_instance->members[address]; - } break; - case ADDR_TYPE_CLASS_CONSTANT: { - - //todo change to index! - GDScript *s=p_script; - ERR_FAIL_INDEX_V(address,_global_names_count,NULL); - const StringName *sn = &_global_names_ptr[address]; - - while(s) { - Map<StringName,Variant>::Element *E=s->constants.find(*sn); - if (E) { - return &E->get(); - } - s=s->_base; - } - - - ERR_EXPLAIN("GDCompiler bug.."); - ERR_FAIL_V(NULL); - } break; - case ADDR_TYPE_LOCAL_CONSTANT: { - ERR_FAIL_INDEX_V(address,_constant_count,NULL); - return &_constants_ptr[address]; - } break; - case ADDR_TYPE_STACK: - case ADDR_TYPE_STACK_VARIABLE: { - ERR_FAIL_INDEX_V(address,_stack_size,NULL); - return &p_stack[address]; - } break; - case ADDR_TYPE_GLOBAL: { - - - ERR_FAIL_INDEX_V(address,GDScriptLanguage::get_singleton()->get_global_array_size(),NULL); - - - return &GDScriptLanguage::get_singleton()->get_global_array()[address]; - } break; - case ADDR_TYPE_NIL: { - return &nil; - } break; - } - - ERR_EXPLAIN("Bad Code! (Addressing Mode)"); - ERR_FAIL_V(NULL); - return NULL; -} - - -String GDFunction::_get_call_error(const Variant::CallError& p_err, const String& p_where,const Variant**argptrs) const { - - - - String err_text; - - if (p_err.error==Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) { - int errorarg=p_err.argument; - err_text="Invalid type in "+p_where+". Cannot convert argument "+itos(errorarg+1)+" from "+Variant::get_type_name(argptrs[errorarg]->get_type())+" to "+Variant::get_type_name(p_err.expected)+"."; - } else if (p_err.error==Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) { - err_text="Invalid call to "+p_where+". Expected "+itos(p_err.argument)+" arguments."; - } else if (p_err.error==Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) { - err_text="Invalid call to "+p_where+". Expected "+itos(p_err.argument)+" arguments."; - } else if (p_err.error==Variant::CallError::CALL_ERROR_INVALID_METHOD) { - err_text="Invalid call. Unexisting "+p_where+"."; - } else if (p_err.error==Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) { - err_text="Attempt to call "+p_where+" on a null instance."; - } else { - err_text="Bug, call error: #"+itos(p_err.error); - } - - return err_text; - -} - -static String _get_var_type(const Variant* p_type) { - - String basestr; - - if (p_type->get_type()==Variant::OBJECT) { - Object *bobj = *p_type; - if (!bobj) { - basestr = "null instance"; - } else { -#ifdef DEBUG_ENABLED - if (ObjectDB::instance_validate(bobj)) { - if (bobj->get_script_instance()) - basestr= bobj->get_type()+" ("+bobj->get_script_instance()->get_script()->get_path().get_file()+")"; - else - basestr = bobj->get_type(); - } else { - basestr="previously freed instance"; - } - -#else - basestr="Object"; -#endif - } - - } else { - basestr = Variant::get_type_name(p_type->get_type()); - } - - return basestr; - -} - -Variant GDFunction::call(GDInstance *p_instance,const Variant **p_args, int p_argcount,Variant::CallError& r_err) { - - - if (!_code_ptr) { - - return Variant(); - } - - r_err.error=Variant::CallError::CALL_OK; - - Variant self; - Variant retvalue; - Variant *stack = NULL; - Variant **call_args; - int defarg=0; - -#ifdef DEBUG_ENABLED - - //GDScriptLanguage::get_singleton()->calls++; - -#endif - - if (p_argcount!=_argument_count) { - - if (p_argcount>_argument_count) { - - r_err.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; - r_err.argument=_argument_count; - - return Variant(); - } else if (p_argcount < _argument_count - _default_arg_count) { - - r_err.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_err.argument=_argument_count - _default_arg_count; - return Variant(); - } else { - - defarg=_argument_count-p_argcount; - } - } - - uint32_t alloca_size = sizeof(Variant*)*_call_size + sizeof(Variant)*_stack_size; - - if (alloca_size) { - - uint8_t *aptr = (uint8_t*)alloca(alloca_size); - - if (_stack_size) { - - stack=(Variant*)aptr; - for(int i=0;i<p_argcount;i++) - memnew_placement(&stack[i],Variant(*p_args[i])); - for(int i=p_argcount;i<_stack_size;i++) - memnew_placement(&stack[i],Variant); - } else { - stack=NULL; - } - - if (_call_size) { - - call_args = (Variant**)&aptr[sizeof(Variant)*_stack_size]; - } else { - - call_args=NULL; - } - - - } else { - stack=NULL; - call_args=NULL; - } - - - GDScript *_class; - - if (p_instance) { - if (p_instance->base_ref && static_cast<Reference*>(p_instance->owner)->is_referenced()) { - - self=REF(static_cast<Reference*>(p_instance->owner)); - } else { - self=p_instance->owner; - } - _class=p_instance->script.ptr(); - } else { - _class=_script; - } - - int ip=0; - int line=_initial_line; - String err_text; - - - -#ifdef DEBUG_ENABLED - - if (ScriptDebugger::get_singleton()) - GDScriptLanguage::get_singleton()->enter_function(p_instance,this,stack,&ip,&line); - -#define CHECK_SPACE(m_space)\ - ERR_BREAK((ip+m_space)>_code_size) - -#define GET_VARIANT_PTR(m_v,m_code_ofs) \ - Variant *m_v; \ - m_v = _get_variant(_code_ptr[ip+m_code_ofs],p_instance,_class,self,stack,err_text);\ - if (!m_v)\ - break; - - -#else -#define CHECK_SPACE(m_space) -#define GET_VARIANT_PTR(m_v,m_code_ofs) \ - Variant *m_v; \ - m_v = _get_variant(_code_ptr[ip+m_code_ofs],p_instance,_class,self,stack,err_text); - -#endif - - - - bool exit_ok=false; - - while(ip<_code_size) { - - - int last_opcode=_code_ptr[ip]; - switch(_code_ptr[ip]) { - - case OPCODE_OPERATOR: { - - CHECK_SPACE(5); - - bool valid; - Variant::Operator op = (Variant::Operator)_code_ptr[ip+1]; - ERR_BREAK(op>=Variant::OP_MAX); - - GET_VARIANT_PTR(a,2); - GET_VARIANT_PTR(b,3); - GET_VARIANT_PTR(dst,4); - - Variant::evaluate(op,*a,*b,*dst,valid); - if (!valid) { - if (false && dst->get_type()==Variant::STRING) { - //return a string when invalid with the error - err_text=*dst; - } else { - err_text="Invalid operands '"+Variant::get_type_name(a->get_type())+"' and '"+Variant::get_type_name(b->get_type())+"' in operator '"+Variant::get_operator_name(op)+"'."; - } - break; - } - - ip+=5; - - } continue; - case OPCODE_EXTENDS_TEST: { - - CHECK_SPACE(4); - - GET_VARIANT_PTR(a,1); - GET_VARIANT_PTR(b,2); - GET_VARIANT_PTR(dst,3); - -#ifdef DEBUG_ENABLED - - if (a->get_type()!=Variant::OBJECT || a->operator Object*()==NULL) { - - err_text="Left operand of 'extends' is not an instance of anything."; - break; - - } - if (b->get_type()!=Variant::OBJECT || b->operator Object*()==NULL) { - - err_text="Right operand of 'extends' is not a class."; - break; - - } -#endif - - - Object *obj_A = *a; - Object *obj_B = *b; - - - GDScript *scr_B = obj_B->cast_to<GDScript>(); - - bool extends_ok=false; - - if (scr_B) { - //if B is a script, the only valid condition is that A has an instance which inherits from the script - //in other situation, this shoul return false. - - if (obj_A->get_script_instance() && obj_A->get_script_instance()->get_language()==GDScriptLanguage::get_singleton()) { - - GDInstance *ins = static_cast<GDInstance*>(obj_A->get_script_instance()); - GDScript *cmp = ins->script.ptr(); - //bool found=false; - while(cmp) { - - if (cmp==scr_B) { - //inherits from script, all ok - extends_ok=true; - break; - - } - - cmp=cmp->_base; - } - - } - } else { - - GDNativeClass *nc= obj_B->cast_to<GDNativeClass>(); - - if (!nc) { - - err_text="Right operand of 'extends' is not a class (type: '"+obj_B->get_type()+"')."; - break; - } - - extends_ok=ObjectTypeDB::is_type(obj_A->get_type_name(),nc->get_name()); - } - - *dst=extends_ok; - ip+=4; - - } continue; - case OPCODE_SET: { - - CHECK_SPACE(3); - - GET_VARIANT_PTR(dst,1); - GET_VARIANT_PTR(index,2); - GET_VARIANT_PTR(value,3); - - bool valid; - dst->set(*index,*value,&valid); - - if (!valid) { - String v = index->operator String(); - if (v!="") { - v="'"+v+"'"; - } else { - v="of type '"+_get_var_type(index)+"'"; - } - err_text="Invalid set index "+v+" (on base: '"+_get_var_type(dst)+"')."; - break; - } - - ip+=4; - } continue; - case OPCODE_GET: { - - CHECK_SPACE(3); - - GET_VARIANT_PTR(src,1); - GET_VARIANT_PTR(index,2); - GET_VARIANT_PTR(dst,3); - - bool valid; - *dst = src->get(*index,&valid); - - if (!valid) { - String v = index->operator String(); - if (v!="") { - v="'"+v+"'"; - } else { - v="of type '"+_get_var_type(index)+"'"; - } - err_text="Invalid get index "+v+" (on base: '"+_get_var_type(src)+"')."; - break; - } - ip+=4; - } continue; - case OPCODE_SET_NAMED: { - - CHECK_SPACE(3); - - GET_VARIANT_PTR(dst,1); - GET_VARIANT_PTR(value,3); - - int indexname = _code_ptr[ip+2]; - - ERR_BREAK(indexname<0 || indexname>=_global_names_count); - const StringName *index = &_global_names_ptr[indexname]; - - bool valid; - dst->set_named(*index,*value,&valid); - - if (!valid) { - String err_type; - err_text="Invalid set index '"+String(*index)+"' (on base: '"+_get_var_type(dst)+"')."; - break; - } - - ip+=4; - } continue; - case OPCODE_GET_NAMED: { - - - CHECK_SPACE(3); - - GET_VARIANT_PTR(src,1); - GET_VARIANT_PTR(dst,3); - - int indexname = _code_ptr[ip+2]; - - ERR_BREAK(indexname<0 || indexname>=_global_names_count); - const StringName *index = &_global_names_ptr[indexname]; - - bool valid; - *dst = src->get_named(*index,&valid); - - if (!valid) { - err_text="Invalid get index '"+index->operator String()+"' (on base: '"+_get_var_type(src)+"')."; - break; - } - - ip+=4; - } continue; - case OPCODE_ASSIGN: { - - CHECK_SPACE(3); - GET_VARIANT_PTR(dst,1); - GET_VARIANT_PTR(src,2); - - *dst = *src; - - ip+=3; - - } continue; - case OPCODE_ASSIGN_TRUE: { - - CHECK_SPACE(2); - GET_VARIANT_PTR(dst,1); - - *dst = true; - - ip+=2; - } continue; - case OPCODE_ASSIGN_FALSE: { - - CHECK_SPACE(2); - GET_VARIANT_PTR(dst,1); - - *dst = false; - - ip+=2; - } continue; - case OPCODE_CONSTRUCT: { - - CHECK_SPACE(2); - Variant::Type t=Variant::Type(_code_ptr[ip+1]); - int argc=_code_ptr[ip+2]; - CHECK_SPACE(argc+2); - Variant **argptrs = call_args; - for(int i=0;i<argc;i++) { - GET_VARIANT_PTR(v,3+i); - argptrs[i]=v; - } - - GET_VARIANT_PTR(dst,3+argc); - Variant::CallError err; - *dst = Variant::construct(t,(const Variant**)argptrs,argc,err); - - if (err.error!=Variant::CallError::CALL_OK) { - - err_text=_get_call_error(err,"'"+Variant::get_type_name(t)+"' constructor",(const Variant**)argptrs); - break; - } - - ip+=4+argc; - //construct a basic type - } continue; - case OPCODE_CONSTRUCT_ARRAY: { - - CHECK_SPACE(1); - int argc=_code_ptr[ip+1]; - Array array(true); //arrays are always shared - array.resize(argc); - CHECK_SPACE(argc+2); - - for(int i=0;i<argc;i++) { - GET_VARIANT_PTR(v,2+i); - array[i]=*v; - - } - - GET_VARIANT_PTR(dst,2+argc); - - *dst=array; - - ip+=3+argc; - - } continue; - case OPCODE_CONSTRUCT_DICTIONARY: { - - CHECK_SPACE(1); - int argc=_code_ptr[ip+1]; - Dictionary dict(true); //arrays are always shared - - CHECK_SPACE(argc*2+2); - - for(int i=0;i<argc;i++) { - - GET_VARIANT_PTR(k,2+i*2+0); - GET_VARIANT_PTR(v,2+i*2+1); - dict[*k]=*v; - - } - - GET_VARIANT_PTR(dst,2+argc*2); - - *dst=dict; - - ip+=3+argc*2; - - } continue; - case OPCODE_CALL_RETURN: - case OPCODE_CALL: { - - - CHECK_SPACE(4); - bool call_ret = _code_ptr[ip]==OPCODE_CALL_RETURN; - - int argc=_code_ptr[ip+1]; - GET_VARIANT_PTR(base,2); - int nameg=_code_ptr[ip+3]; - - ERR_BREAK(nameg<0 || nameg>=_global_names_count); - const StringName *methodname = &_global_names_ptr[nameg]; - - ERR_BREAK(argc<0); - ip+=4; - CHECK_SPACE(argc+1); - Variant **argptrs = call_args; - - for(int i=0;i<argc;i++) { - GET_VARIANT_PTR(v,i); - argptrs[i]=v; - } - - Variant::CallError err; - if (call_ret) { - - GET_VARIANT_PTR(ret,argc); - *ret = base->call(*methodname,(const Variant**)argptrs,argc,err); - } else { - - base->call(*methodname,(const Variant**)argptrs,argc,err); - } - - if (err.error!=Variant::CallError::CALL_OK) { - - - String methodstr = *methodname; - String basestr = _get_var_type(base); - - if (methodstr=="call") { - if (argc>=1) { - methodstr=String(*argptrs[0])+" (via call)"; - if (err.error==Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) { - err.argument-=1; - } - } - } - err_text=_get_call_error(err,"function '"+methodstr+"' in base '"+basestr+"'",(const Variant**)argptrs); - break; - } - - //_call_func(NULL,base,*methodname,ip,argc,p_instance,stack); - ip+=argc+1; - - } continue; - case OPCODE_CALL_BUILT_IN: { - - CHECK_SPACE(4); - - GDFunctions::Function func = GDFunctions::Function(_code_ptr[ip+1]); - int argc=_code_ptr[ip+2]; - ERR_BREAK(argc<0); - - ip+=3; - CHECK_SPACE(argc+1); - Variant **argptrs = call_args; - - for(int i=0;i<argc;i++) { - GET_VARIANT_PTR(v,i); - argptrs[i]=v; - } - - GET_VARIANT_PTR(dst,argc); - - Variant::CallError err; - - GDFunctions::call(func,(const Variant**)argptrs,argc,*dst,err); - - if (err.error!=Variant::CallError::CALL_OK) { - - - String methodstr = GDFunctions::get_func_name(func); - err_text=_get_call_error(err,"built-in function '"+methodstr+"'",(const Variant**)argptrs); - break; - } - ip+=argc+1; - - } continue; - case OPCODE_CALL_SELF: { - - - } break; - case OPCODE_CALL_SELF_BASE: { - - CHECK_SPACE(2); - int self_fun = _code_ptr[ip+1]; -#ifdef DEBUG_ENABLED - - if (self_fun<0 || self_fun>=_global_names_count) { - - err_text="compiler bug, function name not found"; - break; - } -#endif - const StringName *methodname = &_global_names_ptr[self_fun]; - - int argc=_code_ptr[ip+2]; - - CHECK_SPACE(2+argc+1); - - Variant **argptrs = call_args; - - for(int i=0;i<argc;i++) { - GET_VARIANT_PTR(v,i+3); - argptrs[i]=v; - } - - GET_VARIANT_PTR(dst,argc+3); - - const GDScript *gds = _script; - - - const Map<StringName,GDFunction>::Element *E=NULL; - while (gds->base.ptr()) { - gds=gds->base.ptr(); - E=gds->member_functions.find(*methodname); - if (E) - break; - } - - Variant::CallError err; - - if (E) { - - *dst=((GDFunction*)&E->get())->call(p_instance,(const Variant**)argptrs,argc,err); - } else if (gds->native.ptr()) { - - if (*methodname!=GDScriptLanguage::get_singleton()->strings._init) { - - MethodBind *mb = ObjectTypeDB::get_method(gds->native->get_name(),*methodname); - if (!mb) { - err.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; - } else { - *dst=mb->call(p_instance->owner,(const Variant**)argptrs,argc,err); - } - } else { - err.error=Variant::CallError::CALL_OK; - } - } else { - - if (*methodname!=GDScriptLanguage::get_singleton()->strings._init) { - err.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; - } else { - err.error=Variant::CallError::CALL_OK; - } - } - - - if (err.error!=Variant::CallError::CALL_OK) { - - - String methodstr = *methodname; - err_text=_get_call_error(err,"function '"+methodstr+"'",(const Variant**)argptrs); - - break; - } - - ip+=4+argc; - - } continue; - case OPCODE_JUMP: { - - CHECK_SPACE(2); - int to = _code_ptr[ip+1]; - - ERR_BREAK(to<0 || to>_code_size); - ip=to; - - } continue; - case OPCODE_JUMP_IF: { - - CHECK_SPACE(3); - - GET_VARIANT_PTR(test,1); - - bool valid; - bool result = test->booleanize(valid); -#ifdef DEBUG_ENABLED - if (!valid) { - - err_text="cannot evaluate conditional expression of type: "+Variant::get_type_name(test->get_type()); - break; - } -#endif - if (result) { - int to = _code_ptr[ip+2]; - ERR_BREAK(to<0 || to>_code_size); - ip=to; - continue; - } - ip+=3; - } continue; - case OPCODE_JUMP_IF_NOT: { - - CHECK_SPACE(3); - - GET_VARIANT_PTR(test,1); - - bool valid; - bool result = test->booleanize(valid); -#ifdef DEBUG_ENABLED - if (!valid) { - - err_text="cannot evaluate conditional expression of type: "+Variant::get_type_name(test->get_type()); - break; - } -#endif - if (!result) { - int to = _code_ptr[ip+2]; - ERR_BREAK(to<0 || to>_code_size); - ip=to; - continue; - } - ip+=3; - } continue; - case OPCODE_JUMP_TO_DEF_ARGUMENT: { - - CHECK_SPACE(2); - ip=_default_arg_ptr[defarg]; - - } continue; - case OPCODE_RETURN: { - - CHECK_SPACE(2); - GET_VARIANT_PTR(r,1); - retvalue=*r; - exit_ok=true; - - } break; - case OPCODE_ITERATE_BEGIN: { - - CHECK_SPACE(8); //space for this an regular iterate - - GET_VARIANT_PTR(counter,1); - GET_VARIANT_PTR(container,2); - - bool valid; - if (!container->iter_init(*counter,valid)) { - if (!valid) { - err_text="Unable to iterate on object of type "+Variant::get_type_name(container->get_type())+"'."; - break; - } - int jumpto=_code_ptr[ip+3]; - ERR_BREAK(jumpto<0 || jumpto>_code_size); - ip=jumpto; - continue; - } - GET_VARIANT_PTR(iterator,4); - - - *iterator=container->iter_get(*counter,valid); - if (!valid) { - err_text="Unable to obtain iterator object of type "+Variant::get_type_name(container->get_type())+"'."; - break; - } - - - ip+=5; //skip regular iterate which is always next - - } continue; - case OPCODE_ITERATE: { - - CHECK_SPACE(4); - - GET_VARIANT_PTR(counter,1); - GET_VARIANT_PTR(container,2); - - bool valid; - if (!container->iter_next(*counter,valid)) { - if (!valid) { - err_text="Unable to iterate on object of type "+Variant::get_type_name(container->get_type())+"' (type changed since first iteration?)."; - break; - } - int jumpto=_code_ptr[ip+3]; - ERR_BREAK(jumpto<0 || jumpto>_code_size); - ip=jumpto; - continue; - } - GET_VARIANT_PTR(iterator,4); - - *iterator=container->iter_get(*counter,valid); - if (!valid) { - err_text="Unable to obtain iterator object of type "+Variant::get_type_name(container->get_type())+"' (but was obtained on first iteration?)."; - break; - } - - ip+=5; //loop again - } continue; - case OPCODE_ASSERT: { - CHECK_SPACE(2); - GET_VARIANT_PTR(test,1); - -#ifdef DEBUG_ENABLED - bool valid; - bool result = test->booleanize(valid); - - - if (!valid) { - - err_text="cannot evaluate conditional expression of type: "+Variant::get_type_name(test->get_type()); - break; - } - - - if (!result) { - - err_text="Assertion failed."; - break; - } - -#endif - - ip+=2; - } continue; - case OPCODE_LINE: { - CHECK_SPACE(2); - - line=_code_ptr[ip+1]; - ip+=2; - - if (ScriptDebugger::get_singleton()) { - // line - bool do_break=false; - - if (ScriptDebugger::get_singleton()->get_lines_left()>0) { - - if (ScriptDebugger::get_singleton()->get_depth()<=0) - ScriptDebugger::get_singleton()->set_lines_left( ScriptDebugger::get_singleton()->get_lines_left() -1 ); - if (ScriptDebugger::get_singleton()->get_lines_left()<=0) - do_break=true; - } - - if (ScriptDebugger::get_singleton()->is_breakpoint(line,source)) - do_break=true; - - if (do_break) { - GDScriptLanguage::get_singleton()->debug_break("Breakpoint",true); - } - - ScriptDebugger::get_singleton()->line_poll(); - - } - } continue; - case OPCODE_END: { - - exit_ok=true; - break; - - } break; - default: { - - err_text="Illegal opcode "+itos(_code_ptr[ip])+" at address "+itos(ip); - } break; - - } - - if (exit_ok) - break; - //error - // function, file, line, error, explanation - String err_file; - if (p_instance) - err_file=p_instance->script->path; - else if (_class) - err_file=_class->path; - if (err_file=="") - err_file="<built-in>"; - String err_func = name; - if (p_instance && p_instance->script->name!="") - err_func=p_instance->script->name+"."+err_func; - int err_line=line; - if (err_text=="") { - err_text="Internal Script Error! - opcode #"+itos(last_opcode)+" (report please)."; - } - - if (!GDScriptLanguage::get_singleton()->debug_break(err_text,false)) { - // debugger break did not happen - - _err_print_error(err_func.utf8().get_data(),err_file.utf8().get_data(),err_line,err_text.utf8().get_data()); - } - - - break; - } - - if (ScriptDebugger::get_singleton()) - GDScriptLanguage::get_singleton()->exit_function(); - - - if (_stack_size) { - //free stack - for(int i=0;i<_stack_size;i++) - stack[i].~Variant(); - } - - return retvalue; - -} - -const int* GDFunction::get_code() const { - - return _code_ptr; -} -int GDFunction::get_code_size() const{ - - return _code_size; -} - -Variant GDFunction::get_constant(int p_idx) const { - - ERR_FAIL_INDEX_V(p_idx,constants.size(),"<errconst>"); - return constants[p_idx]; -} - -StringName GDFunction::get_global_name(int p_idx) const { - - ERR_FAIL_INDEX_V(p_idx,global_names.size(),"<errgname>"); - return global_names[p_idx]; -} - -int GDFunction::get_default_argument_count() const { - - return default_arguments.size(); -} -int GDFunction::get_default_argument_addr(int p_arg) const{ - - ERR_FAIL_INDEX_V(p_arg,default_arguments.size(),-1); - return default_arguments[p_arg]; -} - - -StringName GDFunction::get_name() const { - - return name; -} - -int GDFunction::get_max_stack_size() const { - - return _stack_size; -} - -struct _GDFKC { - - int order; - List<int> pos; -}; - -struct _GDFKCS { - - int order; - StringName id; - int pos; - - bool operator<(const _GDFKCS &p_r) const { - - return order<p_r.order; - } -}; - -void GDFunction::debug_get_stack_member_state(int p_line,List<Pair<StringName,int> > *r_stackvars) const { - - - int oc=0; - Map<StringName,_GDFKC> sdmap; - for( const List<StackDebug>::Element *E=stack_debug.front();E;E=E->next()) { - - const StackDebug &sd=E->get(); - if (sd.line>p_line) - break; - - if (sd.added) { - - if (!sdmap.has(sd.identifier)) { - _GDFKC d; - d.order=oc++; - d.pos.push_back(sd.pos); - sdmap[sd.identifier]=d; - - } else { - sdmap[sd.identifier].pos.push_back(sd.pos); - } - } else { - - - ERR_CONTINUE(!sdmap.has(sd.identifier)); - - sdmap[sd.identifier].pos.pop_back(); - if (sdmap[sd.identifier].pos.empty()) - sdmap.erase(sd.identifier); - } - - } - - - List<_GDFKCS> stackpositions; - for(Map<StringName,_GDFKC>::Element *E=sdmap.front();E;E=E->next() ) { - - _GDFKCS spp; - spp.id=E->key(); - spp.order=E->get().order; - spp.pos=E->get().pos.back()->get(); - stackpositions.push_back(spp); - } - - stackpositions.sort(); - - for(List<_GDFKCS>::Element *E=stackpositions.front();E;E=E->next()) { - - Pair<StringName,int> p; - p.first=E->get().id; - p.second=E->get().pos; - r_stackvars->push_back(p); - } - - -} - -#if 0 -void GDFunction::clear() { - - name=StringName(); - constants.clear(); - _stack_size=0; - code.clear(); - _constants_ptr=NULL; - _constant_count=0; - _global_names_ptr=NULL; - _global_names_count=0; - _code_ptr=NULL; - _code_size=0; - -} -#endif -GDFunction::GDFunction() { - - _stack_size=0; - _call_size=0; - name="<anonymous>"; - -} - -GDNativeClass::GDNativeClass(const StringName& p_name) { - - name=p_name; -} - -/*void GDNativeClass::call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount){ - - -}*/ - - -bool GDNativeClass::_get(const StringName& p_name,Variant &r_ret) const { - - bool ok; - int v = ObjectTypeDB::get_integer_constant(name, p_name, &ok); - - if (ok) { - r_ret=v; - return true; - } else { - return false; - } -} - - -void GDNativeClass::_bind_methods() { - - ObjectTypeDB::bind_method(_MD("new"),&GDNativeClass::_new); - -} - -Variant GDNativeClass::_new() { - - Object *o = instance(); - if (!o) { - ERR_EXPLAIN("Class type: '"+String(name)+"' is not instantiable."); - ERR_FAIL_COND_V(!o,Variant()); - } - - Reference *ref = o->cast_to<Reference>(); - if (ref) { - return REF(ref); - } else { - return o; - } - -} - -Object *GDNativeClass::instance() { - - return ObjectTypeDB::instance(name); -} - - - -GDInstance* GDScript::_create_instance(const Variant** p_args,int p_argcount,Object *p_owner,bool p_isref) { - - - /* STEP 1, CREATE */ - - GDInstance* instance = memnew( GDInstance ); - instance->base_ref=p_isref; - instance->members.resize(member_indices.size()); - instance->script=Ref<GDScript>(this); - instance->owner=p_owner; - instance->owner->set_script_instance(instance); - - /* STEP 2, INITIALIZE AND CONSRTUCT */ - - instances.insert(instance->owner); - - Variant::CallError err; - initializer->call(instance,p_args,p_argcount,err); - - if (err.error!=Variant::CallError::CALL_OK) { - instance->script=Ref<GDScript>(); - instances.erase(p_owner); - memdelete(instance); - ERR_FAIL_COND_V(err.error!=Variant::CallError::CALL_OK, NULL); //error consrtucting - } - - //@TODO make thread safe - return instance; - -} - -Variant GDScript::_new(const Variant** p_args,int p_argcount,Variant::CallError& r_error) { - - /* STEP 1, CREATE */ - - r_error.error=Variant::CallError::CALL_OK; - REF ref; - Object *owner=NULL; - - GDScript *_baseptr=this; - while (_baseptr->_base) { - _baseptr=_baseptr->_base; - } - - if (_baseptr->native.ptr()) { - owner=_baseptr->native->instance(); - } else { - owner=memnew( Reference ); //by default, no base means use reference - } - - Reference *r=owner->cast_to<Reference>(); - if (r) { - ref=REF(r); - } - - - GDInstance* instance = _create_instance(p_args,p_argcount,owner,r!=NULL); - if (!instance) { - if (ref.is_null()) { - memdelete(owner); //no owner, sorry - } - return Variant(); - } - - if (ref.is_valid()) { - return ref; - } else { - return owner; - } -} - -bool GDScript::can_instance() const { - - return valid; //any script in GDscript can instance -} - -StringName GDScript::get_instance_base_type() const { - - if (native.is_valid()) - return native->get_name(); - if (base.is_valid()) - return base->get_instance_base_type(); - return StringName(); -} - -struct _GDScriptMemberSort { - - int index; - StringName name; - _FORCE_INLINE_ bool operator<(const _GDScriptMemberSort& p_member) const { return index < p_member.index; } - -}; - - -#ifdef TOOLS_ENABLED - - -void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) { - - placeholders.erase(p_placeholder); -} - -void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) { - - - List<PropertyInfo> plist; - GDScript *scr=this; - - Map<StringName,Variant> default_values; - while(scr) { - - Vector<_GDScriptMemberSort> msort; - for(Map<StringName,PropertyInfo>::Element *E=scr->member_info.front();E;E=E->next()) { - - _GDScriptMemberSort ms; - ERR_CONTINUE(!scr->member_indices.has(E->key())); - ms.index=scr->member_indices[E->key()]; - ms.name=E->key(); - - msort.push_back(ms); - - } - - msort.sort(); - msort.invert(); - for(int i=0;i<msort.size();i++) { - - plist.push_front(scr->member_info[msort[i].name]); - if (scr->member_default_values.has(msort[i].name)) - default_values[msort[i].name]=scr->member_default_values[msort[i].name]; - else { - Variant::CallError err; - default_values[msort[i].name]=Variant::construct(scr->member_info[msort[i].name].type,NULL,0,err); - } - } - - scr=scr->_base; - } - - - p_placeholder->update(plist,default_values); - -} -#endif -ScriptInstance* GDScript::instance_create(Object *p_this) { - - if (!tool && !ScriptServer::is_scripting_enabled()) { - -#ifdef TOOLS_ENABLED - - //instance a fake script for editing the values - //plist.invert(); - - /*print_line("CREATING PLACEHOLDER"); - for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) { - print_line(E->get().name); - }*/ - PlaceHolderScriptInstance *si = memnew( PlaceHolderScriptInstance(GDScriptLanguage::get_singleton(),Ref<Script>(this),p_this) ); - placeholders.insert(si); - _update_placeholder(si); - return si; -#else - return NULL; -#endif - } - - GDScript *top=this; - while(top->_base) - top=top->_base; - - if (top->native.is_valid()) { - if (!ObjectTypeDB::is_type(p_this->get_type_name(),top->native->get_name())) { - - if (ScriptDebugger::get_singleton()) { - GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),0,"Script inherits from native type '"+String(top->native->get_name())+"', so it can't be instanced in object of type: '"+p_this->get_type()+"'"); - } - ERR_EXPLAIN("Script inherits from native type '"+String(top->native->get_name())+"', so it can't be instanced in object of type: '"+p_this->get_type()+"'"); - ERR_FAIL_V(NULL); - - } - } - - return _create_instance(NULL,0,p_this,p_this->cast_to<Reference>()); - -} -bool GDScript::instance_has(const Object *p_this) const { - - return instances.has((Object*)p_this); -} - -bool GDScript::has_source_code() const { - - return source!=""; -} -String GDScript::get_source_code() const { - - return source; -} -void GDScript::set_source_code(const String& p_code) { - - source=p_code; - -} - -void GDScript::_set_subclass_path(Ref<GDScript>& p_sc,const String& p_path) { - - p_sc->path=p_path; - for(Map<StringName,Ref<GDScript> >::Element *E=p_sc->subclasses.front();E;E=E->next()) { - - _set_subclass_path(E->get(),p_path); - } -} - -Error GDScript::reload() { - - - ERR_FAIL_COND_V(instances.size(),ERR_ALREADY_IN_USE); - - String basedir=path; - - if (basedir=="") - basedir==get_path(); - - if (basedir!="") - basedir=basedir.get_base_dir(); - - - - valid=false; - GDParser parser; - Error err = parser.parse(source,basedir); - if (err) { - if (ScriptDebugger::get_singleton()) { - GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),parser.get_error_line(),"Parser Error: "+parser.get_error()); - } - _err_print_error("GDScript::reload",path.empty()?"built-in":(const char*)path.utf8().get_data(),parser.get_error_line(),("Parse Error: "+parser.get_error()).utf8().get_data()); - ERR_FAIL_V(ERR_PARSE_ERROR); - } - - GDCompiler compiler; - err = compiler.compile(&parser,this); - - if (err) { - if (ScriptDebugger::get_singleton()) { - GDScriptLanguage::get_singleton()->debug_break_parse(get_path(),compiler.get_error_line(),"Parser Error: "+compiler.get_error()); - } - _err_print_error("GDScript::reload",path.empty()?"built-in":(const char*)path.utf8().get_data(),compiler.get_error_line(),("Compile Error: "+compiler.get_error()).utf8().get_data()); - ERR_FAIL_V(ERR_COMPILATION_FAILED); - } - - valid=true; - - for(Map<StringName,Ref<GDScript> >::Element *E=subclasses.front();E;E=E->next()) { - - _set_subclass_path(E->get(),path); - } - -#ifdef TOOLS_ENABLED - for (Set<PlaceHolderScriptInstance*>::Element *E=placeholders.front();E;E=E->next()) { - - _update_placeholder(E->get()); - } -#endif - return OK; -} - -String GDScript::get_node_type() const { - - return ""; // ? -} - -ScriptLanguage *GDScript::get_language() const { - - return GDScriptLanguage::get_singleton(); -} - - -Variant GDScript::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) { - - - GDScript *top=this; - while(top) { - - Map<StringName,GDFunction>::Element *E=top->member_functions.find(p_method); - if (E) { - - if (!E->get().is_static()) { - WARN_PRINT(String("Can't call non-static function: '"+String(p_method)+"' in script.").utf8().get_data()); - } - - return E->get().call(NULL,p_args,p_argcount,r_error); - } - top=top->_base; - } - - //none found, regular - - return Script::call(p_method,p_args,p_argcount,r_error); - -} - -bool GDScript::_get(const StringName& p_name,Variant &r_ret) const { - - { - - - const GDScript *top=this; - while(top) { - - { - const Map<StringName,Variant>::Element *E=top->constants.find(p_name); - if (E) { - - r_ret= E->get(); - return true; - } - } - - { - const Map<StringName,Ref<GDScript> >::Element *E=subclasses.find(p_name); - if (E) { - - r_ret=E->get(); - return true; - } - } - top=top->_base; - } - - if (p_name==GDScriptLanguage::get_singleton()->strings._script_source) { - - r_ret=get_source_code(); - return true; - } - } - - - - return false; - -} -bool GDScript::_set(const StringName& p_name, const Variant& p_value) { - - if (p_name==GDScriptLanguage::get_singleton()->strings._script_source) { - - set_source_code(p_value); - reload(); - } else - return false; - - return true; -} - -void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const { - - p_properties->push_back( PropertyInfo(Variant::STRING,"script/source",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR) ); -} - - -void GDScript::_bind_methods() { - - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo("new")); - -} - -Error GDScript::load_source_code(const String& p_path) { - - - DVector<uint8_t> sourcef; - Error err; - FileAccess *f=FileAccess::open(p_path,FileAccess::READ,&err); - if (err) { - - ERR_FAIL_COND_V(err,err); - } - - int len = f->get_len(); - sourcef.resize(len+1); - DVector<uint8_t>::Write w = sourcef.write(); - int r = f->get_buffer(w.ptr(),len); - f->close(); - memdelete(f); - ERR_FAIL_COND_V(r!=len,ERR_CANT_OPEN); - w[len]=0; - - String s; - if (s.parse_utf8((const char*)w.ptr())) { - - ERR_EXPLAIN("Script '"+p_path+"' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode."); - ERR_FAIL_V(ERR_INVALID_DATA); - } - - source=s; - path=p_path; - return OK; - -} - - -const Map<StringName,GDFunction>& GDScript::debug_get_member_functions() const { - - return member_functions; -} - - - -StringName GDScript::debug_get_member_by_index(int p_idx) const { - - - for(const Map<StringName,int>::Element *E=member_indices.front();E;E=E->next()) { - - if (E->get()==p_idx) - return E->key(); - } - - return "<error>"; -} - - -Ref<GDScript> GDScript::get_base() const { - - return base; -} - -GDScript::GDScript() { - - - valid=false; - subclass_count=0; - initializer=NULL; - _base=NULL; - _owner=NULL; - tool=false; -} - - - - - -////////////////////////////// -// INSTANCE // -////////////////////////////// - - -bool GDInstance::set(const StringName& p_name, const Variant& p_value) { - - //member - { - const Map<StringName,int>::Element *E = script->member_indices.find(p_name); - if (E) { - members[E->get()]=p_value; - return true; - - } - } - - GDScript *sptr=script.ptr(); - while(sptr) { - - - Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set); - if (E) { - - Variant name=p_name; - const Variant *args[2]={&name,&p_value}; - - Variant::CallError err; - Variant ret = E->get().call(this,(const Variant**)args,2,err); - if (err.error==Variant::CallError::CALL_OK && ret.get_type()==Variant::BOOL && ret.operator bool()) - return true; - } - sptr = sptr->_base; - } - - return false; -} - -bool GDInstance::get(const StringName& p_name, Variant &r_ret) const { - - - - const GDScript *sptr=script.ptr(); - while(sptr) { - - { - const Map<StringName,int>::Element *E = script->member_indices.find(p_name); - if (E) { - r_ret=members[E->get()]; - return true; //index found - - } - } - - { - const Map<StringName,Variant>::Element *E = script->constants.find(p_name); - if (E) { - r_ret=E->get(); - return true; //index found - - } - } - - { - const Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get); - if (E) { - - Variant name=p_name; - const Variant *args[1]={&name}; - - Variant::CallError err; - Variant ret = const_cast<GDFunction*>(&E->get())->call(const_cast<GDInstance*>(this),(const Variant**)args,1,err); - if (err.error==Variant::CallError::CALL_OK && ret.get_type()!=Variant::NIL) { - r_ret=ret; - return true; - } - } - } - sptr = sptr->_base; - } - - return false; - -} -void GDInstance::get_property_list(List<PropertyInfo> *p_properties) const { - // exported members, not doen yet! - - const GDScript *sptr=script.ptr(); - List<PropertyInfo> props; - - while(sptr) { - - - const Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list); - if (E) { - - - Variant::CallError err; - Variant ret = const_cast<GDFunction*>(&E->get())->call(const_cast<GDInstance*>(this),NULL,0,err); - if (err.error==Variant::CallError::CALL_OK) { - - if (ret.get_type()!=Variant::ARRAY) { - - ERR_EXPLAIN("Wrong type for _get_property list, must be an array of dictionaries."); - ERR_FAIL(); - } - Array arr = ret; - for(int i=0;i<arr.size();i++) { - - Dictionary d = arr[i]; - ERR_CONTINUE(!d.has("name")); - ERR_CONTINUE(!d.has("type")); - PropertyInfo pinfo; - pinfo.type = Variant::Type( d["type"].operator int()); - ERR_CONTINUE(pinfo.type<0 || pinfo.type>=Variant::VARIANT_MAX ); - pinfo.name = d["name"]; - ERR_CONTINUE(pinfo.name==""); - if (d.has("hint")) - pinfo.hint=PropertyHint(d["hint"].operator int()); - if (d.has("hint_string")) - pinfo.hint_string=d["hint_string"]; - if (d.has("usage")) - pinfo.usage=d["usage"]; - - props.push_back(pinfo); - - } - - } - } - - //instance a fake script for editing the values - - Vector<_GDScriptMemberSort> msort; - for(Map<StringName,PropertyInfo>::Element *E=sptr->member_info.front();E;E=E->next()) { - - _GDScriptMemberSort ms; - ERR_CONTINUE(!sptr->member_indices.has(E->key())); - ms.index=sptr->member_indices[E->key()]; - ms.name=E->key(); - msort.push_back(ms); - - } - - msort.sort(); - msort.invert(); - for(int i=0;i<msort.size();i++) { - - props.push_front(sptr->member_info[msort[i].name]); - - } -#if 0 - if (sptr->member_functions.has("_get_property_list")) { - - Variant::CallError err; - GDFunction *f = const_cast<GDFunction*>(&sptr->member_functions["_get_property_list"]); - Variant plv = f->call(const_cast<GDInstance*>(this),NULL,0,err); - - if (plv.get_type()!=Variant::ARRAY) { - - ERR_PRINT("_get_property_list: expected array returned"); - } else { - - Array pl=plv; - - for(int i=0;i<pl.size();i++) { - - Dictionary p = pl[i]; - PropertyInfo pinfo; - if (!p.has("name")) { - ERR_PRINT("_get_property_list: expected 'name' key of type string.") - continue; - } - if (!p.has("type")) { - ERR_PRINT("_get_property_list: expected 'type' key of type integer.") - continue; - } - pinfo.name=p["name"]; - pinfo.type=Variant::Type(int(p["type"])); - if (p.has("hint")) - pinfo.hint=PropertyHint(int(p["hint"])); - if (p.has("hint_string")) - pinfo.hint_string=p["hint_string"]; - if (p.has("usage")) - pinfo.usage=p["usage"]; - - - props.push_back(pinfo); - } - } - } -#endif - - sptr = sptr->_base; - } - - //props.invert(); - - for (List<PropertyInfo>::Element *E=props.front();E;E=E->next()) { - - p_properties->push_back(E->get()); - } -} - -void GDInstance::get_method_list(List<MethodInfo> *p_list) const { - - const GDScript *sptr=script.ptr(); - while(sptr) { - - for (Map<StringName,GDFunction>::Element *E = sptr->member_functions.front();E;E=E->next()) { - - MethodInfo mi; - mi.name=E->key(); - for(int i=0;i<E->get().get_argument_count();i++) - mi.arguments.push_back(PropertyInfo(Variant::NIL,"arg"+itos(i))); - p_list->push_back(mi); - } - sptr = sptr->_base; - } - -} - -bool GDInstance::has_method(const StringName& p_method) const { - - const GDScript *sptr=script.ptr(); - while(sptr) { - const Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(p_method); - if (E) - return true; - sptr = sptr->_base; - } - - return false; -} -Variant GDInstance::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) { - - //printf("calling %ls:%i method %ls\n", script->get_path().c_str(), -1, String(p_method).c_str()); - - GDScript *sptr=script.ptr(); - while(sptr) { - Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(p_method); - if (E) { - return E->get().call(this,p_args,p_argcount,r_error); - } - sptr = sptr->_base; - } - r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD; - return Variant(); -} - -void GDInstance::call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount) { - - GDScript *sptr=script.ptr(); - Variant::CallError ce; - - while(sptr) { - Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(p_method); - if (E) { - E->get().call(this,p_args,p_argcount,ce); - } - sptr = sptr->_base; - } - -} - - -void GDInstance::_ml_call_reversed(GDScript *sptr,const StringName& p_method,const Variant** p_args,int p_argcount) { - - if (sptr->_base) - _ml_call_reversed(sptr->_base,p_method,p_args,p_argcount); - - Variant::CallError ce; - - Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(p_method); - if (E) { - E->get().call(this,p_args,p_argcount,ce); - } - -} - -void GDInstance::call_multilevel_reversed(const StringName& p_method,const Variant** p_args,int p_argcount) { - - if (script.ptr()) { - _ml_call_reversed(script.ptr(),p_method,p_args,p_argcount); - } -} - -void GDInstance::notification(int p_notification) { - - //notification is not virutal, it gets called at ALL levels just like in C. - Variant value=p_notification; - const Variant *args[1]={&value }; - - GDScript *sptr=script.ptr(); - while(sptr) { - Map<StringName,GDFunction>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification); - if (E) { - Variant::CallError err; - E->get().call(this,args,1,err); - if (err.error!=Variant::CallError::CALL_OK) { - //print error about notification call - - } - } - sptr = sptr->_base; - } - -} - -Ref<Script> GDInstance::get_script() const { - - return script; -} - -ScriptLanguage *GDInstance::get_language() { - - return GDScriptLanguage::get_singleton(); -} - - -GDInstance::GDInstance() { - owner=NULL; - base_ref=false; -} - -GDInstance::~GDInstance() { - if (script.is_valid() && owner) { - script->instances.erase(owner); - } -} - -/************* SCRIPT LANGUAGE **************/ -/************* SCRIPT LANGUAGE **************/ -/************* SCRIPT LANGUAGE **************/ -/************* SCRIPT LANGUAGE **************/ -/************* SCRIPT LANGUAGE **************/ - -GDScriptLanguage *GDScriptLanguage::singleton=NULL; - - -String GDScriptLanguage::get_name() const { - - return "GDScript"; -} - -/* LANGUAGE FUNCTIONS */ - -void GDScriptLanguage::_add_global(const StringName& p_name,const Variant& p_value) { - - - if (globals.has(p_name)) { - //overwrite existing - global_array[globals[p_name]]=p_value; - return; - } - globals[p_name]=global_array.size(); - global_array.push_back(p_value); - _global_array=global_array.ptr(); -} - -void GDScriptLanguage::init() { - - - //populate global constants - int gcc=GlobalConstants::get_global_constant_count(); - for(int i=0;i<gcc;i++) { - - _add_global(StaticCString::create(GlobalConstants::get_global_constant_name(i)),GlobalConstants::get_global_constant_value(i)); - } - - _add_global(StaticCString::create("PI"),Math_PI); - - //populate native classes - - List<String> class_list; - ObjectTypeDB::get_type_list(&class_list); - for(List<String>::Element *E=class_list.front();E;E=E->next()) { - - StringName n = E->get(); - String s = String(n); - if (s.begins_with("_")) - n=s.substr(1,s.length()); - - if (globals.has(n)) - continue; - Ref<GDNativeClass> nc = memnew( GDNativeClass(E->get()) ); - _add_global(n,nc); - } - - //populate singletons - - List<Globals::Singleton> singletons; - Globals::get_singleton()->get_singletons(&singletons); - for(List<Globals::Singleton>::Element *E=singletons.front();E;E=E->next()) { - - _add_global(E->get().name,E->get().ptr); - } -} - -String GDScriptLanguage::get_type() const { - - return "GDScript"; -} -String GDScriptLanguage::get_extension() const { - - return "gd"; -} -Error GDScriptLanguage::execute_file(const String& p_path) { - - // ?? - return OK; -} -void GDScriptLanguage::finish() { - - -} - - -void GDScriptLanguage::frame() { - -// print_line("calls: "+itos(calls)); - calls=0; -} - -/* EDITOR FUNCTIONS */ -void GDScriptLanguage::get_reserved_words(List<String> *p_words) const { - - static const char *_reserved_words[]={ - "break", - "class", - "continue", - "const", - "else", - "elif", - "enum", - "extends" , - "for" , - "func" , - "if" , - "in" , - "varl", - "null" , - "return" , - "self" , - "while" , - "true" , - "false" , - "tool", - "var", - "pass", - "and", - "or", - "export", - 0}; - - - const char **w=_reserved_words; - - - while (*w) { - - p_words->push_back(*w); - w++; - } - - for(int i=0;i<GDFunctions::FUNC_MAX;i++) { - p_words->push_back(GDFunctions::get_func_name(GDFunctions::Function(i))); - } - -} - -GDScriptLanguage::GDScriptLanguage() { - - calls=0; - ERR_FAIL_COND(singleton); - singleton=this; - strings._init = StaticCString::create("_init"); - strings._notification = StaticCString::create("_notification"); - strings._set= StaticCString::create("_set"); - strings._get= StaticCString::create("_get"); - strings._get_property_list= StaticCString::create("_get_property_list"); - strings._script_source=StaticCString::create("script/source"); - _debug_parse_err_line=-1; - _debug_parse_err_file=""; - - _debug_call_stack_pos=0; - int dmcs=GLOBAL_DEF("debug/script_max_call_stack",1024); - if (ScriptDebugger::get_singleton()) { - //debugging enabled! - - _debug_max_call_stack = dmcs; - if (_debug_max_call_stack<1024) - _debug_max_call_stack=1024; - _call_stack = memnew_arr( CallLevel, _debug_max_call_stack+1 ); - - } else { - _debug_max_call_stack=0; - _call_stack=NULL; - } - -} - - -GDScriptLanguage::~GDScriptLanguage() { - - if (_call_stack) { - memdelete_arr(_call_stack); - } - singleton=NULL; -} - -/*************** RESOURCE ***************/ - -RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_original_path) { - - GDScript *script = memnew( GDScript ); - - Ref<GDScript> scriptres(script); - - Error err = script->load_source_code(p_path); - - if (err!=OK) { - - ERR_FAIL_COND_V(err!=OK, RES()); - } - - script->set_script_path(p_original_path); // script needs this. - script->set_path(p_original_path); - //script->set_name(p_path.get_file()); - - script->reload(); - - return scriptres; -} -void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const { - - p_extensions->push_back("gd"); -} - -bool ResourceFormatLoaderGDScript::handles_type(const String& p_type) const { - - return (p_type=="Script" || p_type=="GDScript"); -} - -String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const { - - if (p_path.extension().to_lower()=="gd") - return "GDScript"; - return ""; -} - - -Error ResourceFormatSaverGDScript::save(const String &p_path,const RES& p_resource,uint32_t p_flags) { - - Ref<GDScript> sqscr = p_resource; - ERR_FAIL_COND_V(sqscr.is_null(),ERR_INVALID_PARAMETER); - - String source = sqscr->get_source_code(); - - Error err; - FileAccess *file = FileAccess::open(p_path,FileAccess::WRITE,&err); - - - if (err) { - - ERR_FAIL_COND_V(err,err); - } - - file->store_string(source); - - file->close(); - memdelete(file); - return OK; -} - -void ResourceFormatSaverGDScript::get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const { - - if (p_resource->cast_to<GDScript>()) { - p_extensions->push_back("gd"); - } - -} -bool ResourceFormatSaverGDScript::recognize(const RES& p_resource) const { - - return p_resource->cast_to<GDScript>()!=NULL; -} diff --git a/script/gdscript/gd_script.h b/script/gdscript/gd_script.h deleted file mode 100644 index bb9beaaf56..0000000000 --- a/script/gdscript/gd_script.h +++ /dev/null @@ -1,471 +0,0 @@ -/*************************************************************************/ -/* 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; - /* 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 diff --git a/script/gdscript/gd_tokenizer.cpp b/script/gdscript/gd_tokenizer.cpp deleted file mode 100644 index f7320799a5..0000000000 --- a/script/gdscript/gd_tokenizer.cpp +++ /dev/null @@ -1,973 +0,0 @@ -/*************************************************************************/ -/* 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(); -} diff --git a/script/gdscript/gd_tokenizer.h b/script/gdscript/gd_tokenizer.h deleted file mode 100644 index 24ee2be7ad..0000000000 --- a/script/gdscript/gd_tokenizer.h +++ /dev/null @@ -1,181 +0,0 @@ -/*************************************************************************/ -/* 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 diff --git a/script/multiscript/SCsub b/script/multiscript/SCsub deleted file mode 100644 index dd812edec5..0000000000 --- a/script/multiscript/SCsub +++ /dev/null @@ -1,7 +0,0 @@ -Import('env') - -env.add_source_files(env.script_sources,"*.cpp") - -Export('env') - - diff --git a/script/multiscript/multi_script.cpp b/script/multiscript/multi_script.cpp deleted file mode 100644 index 1924cf2a6e..0000000000 --- a/script/multiscript/multi_script.cpp +++ /dev/null @@ -1,498 +0,0 @@ -/*************************************************************************/ -/* 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; diff --git a/script/multiscript/multi_script.h b/script/multiscript/multi_script.h deleted file mode 100644 index a67cedc56b..0000000000 --- a/script/multiscript/multi_script.h +++ /dev/null @@ -1,157 +0,0 @@ -/*************************************************************************/ -/* 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 {} - - MultiScriptLanguage() { singleton=this; } - virtual ~MultiScriptLanguage() {}; -}; - - -#endif // MULTI_SCRIPT_H diff --git a/script/register_script_types.cpp b/script/register_script_types.cpp deleted file mode 100644 index 1927cd5c1f..0000000000 --- a/script/register_script_types.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/*************************************************/ -/* 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_script_types.h" - -#include "script/gdscript/gd_script.h" -#include "script/multiscript/multi_script.h" -#include "io/resource_loader.h" - - - -#ifdef GDSCRIPT_ENABLED -GDScriptLanguage *script_language_gd=NULL; -ResourceFormatLoaderGDScript *resource_loader_gd=NULL; -ResourceFormatSaverGDScript *resource_saver_gd=NULL; -#endif - -static MultiScriptLanguage *script_multi_script=NULL; - -void register_script_types() { - -#ifdef GDSCRIPT_ENABLED - - 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); -#endif - - - script_multi_script = memnew( MultiScriptLanguage ); - ScriptServer::register_language(script_multi_script); - ObjectTypeDB::register_type<MultiScript>(); - - -} -void unregister_script_types() { - - - - -#ifdef GDSCRIPT_ENABLED - if (script_language_gd) - memdelete( script_language_gd ); - if (resource_loader_gd) - memdelete( resource_loader_gd ); - if (resource_saver_gd) - memdelete( resource_saver_gd ); - -#endif - - if (script_multi_script); - memdelete(script_multi_script); -} diff --git a/script/register_script_types.h b/script/register_script_types.h deleted file mode 100644 index eec0cfe539..0000000000 --- a/script/register_script_types.h +++ /dev/null @@ -1,38 +0,0 @@ -/*************************************************************************/ -/* register_script_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. */ -/*************************************************************************/ -#ifndef REGISTER_SCRIPT_TYPES_H -#define REGISTER_SCRIPT_TYPES_H - -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ -void register_script_types(); -void unregister_script_types(); - -#endif diff --git a/script/script_binder.cpp b/script/script_binder.cpp deleted file mode 100644 index 63c6d1d050..0000000000 --- a/script/script_binder.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/*************************************************/ -/* script_binder.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 "script_binder.h" - diff --git a/script/script_binder.h b/script/script_binder.h deleted file mode 100644 index c3167a901d..0000000000 --- a/script/script_binder.h +++ /dev/null @@ -1,15 +0,0 @@ -/*************************************************/ -/* script_binder.h */ -/*************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/*************************************************/ -/* Source code within this file is: */ -/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */ -/* All Rights Reserved. */ -/*************************************************/ - -#ifndef SCRIPT_BINDER_H -#define SCRIPT_BINDER_H - -#endif // SCRIPT_BINDER_H |