first enemy test
This commit is contained in:
315
addons/gut/script_parser.gd
Normal file
315
addons/gut/script_parser.gd
Normal file
@ -0,0 +1,315 @@
|
||||
# These methods didn't have flags that would exclude them from being used
|
||||
# in a double and they appear to break things if they are included.
|
||||
const BLACKLIST = [
|
||||
'get_script',
|
||||
'has_method',
|
||||
]
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Combins the meta for the method with additional information.
|
||||
# * flag for whether the method is local
|
||||
# * adds a 'default' property to all parameters that can be easily checked per
|
||||
# parameter
|
||||
# ------------------------------------------------------------------------------
|
||||
class ParsedMethod:
|
||||
const NO_DEFAULT = '__no__default__'
|
||||
|
||||
var _meta = {}
|
||||
var meta = _meta :
|
||||
get: return _meta
|
||||
set(val): return;
|
||||
|
||||
var is_local = false
|
||||
var _parameters = []
|
||||
|
||||
func _init(metadata):
|
||||
_meta = metadata
|
||||
var start_default = _meta.args.size() - _meta.default_args.size()
|
||||
for i in range(_meta.args.size()):
|
||||
var arg = _meta.args[i]
|
||||
# Add a "default" property to the metadata so we don't have to do
|
||||
# weird default paramter position math again.
|
||||
if(i >= start_default):
|
||||
arg['default'] = _meta.default_args[start_default - i]
|
||||
else:
|
||||
arg['default'] = NO_DEFAULT
|
||||
_parameters.append(arg)
|
||||
|
||||
|
||||
func is_eligible_for_doubling():
|
||||
var has_bad_flag = _meta.flags & \
|
||||
(METHOD_FLAG_OBJECT_CORE | METHOD_FLAG_VIRTUAL | METHOD_FLAG_STATIC)
|
||||
return !has_bad_flag and BLACKLIST.find(_meta.name) == -1
|
||||
|
||||
|
||||
func is_accessor():
|
||||
return _meta.name.begins_with('@') and \
|
||||
(_meta.name.ends_with('_getter') or _meta.name.ends_with('_setter'))
|
||||
|
||||
|
||||
func to_s():
|
||||
var s = _meta.name + "("
|
||||
|
||||
for i in range(_meta.args.size()):
|
||||
var arg = _meta.args[i]
|
||||
if(str(arg.default) != NO_DEFAULT):
|
||||
var val = str(arg.default)
|
||||
if(val == ''):
|
||||
val = '""'
|
||||
s += str(arg.name, ' = ', val)
|
||||
else:
|
||||
s += str(arg.name)
|
||||
|
||||
if(i != _meta.args.size() -1):
|
||||
s += ', '
|
||||
|
||||
s += ")"
|
||||
return s
|
||||
|
||||
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
class ParsedScript:
|
||||
# All methods indexed by name.
|
||||
var _methods_by_name = {}
|
||||
|
||||
var _script_path = null
|
||||
var script_path = _script_path :
|
||||
get: return _script_path
|
||||
set(val): return;
|
||||
|
||||
var _subpath = null
|
||||
var subpath = null :
|
||||
get: return _subpath
|
||||
set(val): return;
|
||||
|
||||
var _resource = null
|
||||
var resource = null :
|
||||
get: return _resource
|
||||
set(val): return;
|
||||
|
||||
|
||||
var _is_native = false
|
||||
var is_native = _is_native:
|
||||
get: return _is_native
|
||||
set(val): return;
|
||||
|
||||
var _native_methods = {}
|
||||
var _native_class_name = ""
|
||||
|
||||
|
||||
|
||||
func _init(script_or_inst, inner_class=null):
|
||||
var to_load = script_or_inst
|
||||
|
||||
if(GutUtils.is_native_class(to_load)):
|
||||
_resource = to_load
|
||||
_is_native = true
|
||||
var inst = to_load.new()
|
||||
_native_class_name = inst.get_class()
|
||||
_native_methods = inst.get_method_list()
|
||||
if(!inst is RefCounted):
|
||||
inst.free()
|
||||
else:
|
||||
if(!script_or_inst is Resource):
|
||||
to_load = load(script_or_inst.get_script().get_path())
|
||||
|
||||
_script_path = to_load.resource_path
|
||||
if(inner_class != null):
|
||||
_subpath = _find_subpath(to_load, inner_class)
|
||||
|
||||
if(inner_class == null):
|
||||
_resource = to_load
|
||||
else:
|
||||
_resource = inner_class
|
||||
to_load = inner_class
|
||||
|
||||
_parse_methods(to_load)
|
||||
|
||||
|
||||
func _print_flags(meta):
|
||||
print(str(meta.name, ':').rpad(30), str(meta.flags).rpad(4), ' = ', GutUtils.dec2bistr(meta.flags, 10))
|
||||
|
||||
|
||||
func _get_native_methods(base_type):
|
||||
var to_return = []
|
||||
if(base_type != null):
|
||||
var source = str('extends ', base_type)
|
||||
var inst = GutUtils.create_script_from_source(source).new()
|
||||
to_return = inst.get_method_list()
|
||||
if(! inst is RefCounted):
|
||||
inst.free()
|
||||
return to_return
|
||||
|
||||
|
||||
func _parse_methods(thing):
|
||||
var methods = []
|
||||
if(is_native):
|
||||
methods = _native_methods.duplicate()
|
||||
else:
|
||||
var base_type = thing.get_instance_base_type()
|
||||
methods = _get_native_methods(base_type)
|
||||
|
||||
for m in methods:
|
||||
var parsed = ParsedMethod.new(m)
|
||||
_methods_by_name[m.name] = parsed
|
||||
# _init must always be included so that we can initialize
|
||||
# double_tools
|
||||
if(m.name == '_init'):
|
||||
parsed.is_local = true
|
||||
|
||||
|
||||
# This loop will overwrite all entries in _methods_by_name with the local
|
||||
# method object so there is only ever one listing for a function with
|
||||
# the right "is_local" flag.
|
||||
if(!is_native):
|
||||
methods = thing.get_script_method_list()
|
||||
for m in methods:
|
||||
var parsed_method = ParsedMethod.new(m)
|
||||
parsed_method.is_local = true
|
||||
_methods_by_name[m.name] = parsed_method
|
||||
|
||||
|
||||
func _find_subpath(parent_script, inner):
|
||||
var const_map = parent_script.get_script_constant_map()
|
||||
var consts = const_map.keys()
|
||||
var const_idx = 0
|
||||
var found = false
|
||||
var to_return = null
|
||||
|
||||
while(const_idx < consts.size() and !found):
|
||||
var key = consts[const_idx]
|
||||
var const_val = const_map[key]
|
||||
if(typeof(const_val) == TYPE_OBJECT):
|
||||
if(const_val == inner):
|
||||
found = true
|
||||
to_return = key
|
||||
else:
|
||||
to_return = _find_subpath(const_val, inner)
|
||||
if(to_return != null):
|
||||
to_return = str(key, '.', to_return)
|
||||
found = true
|
||||
|
||||
const_idx += 1
|
||||
|
||||
return to_return
|
||||
|
||||
|
||||
func get_method(name):
|
||||
return _methods_by_name[name]
|
||||
|
||||
|
||||
func get_super_method(name):
|
||||
var to_return = get_method(name)
|
||||
if(to_return.is_local):
|
||||
to_return = null
|
||||
|
||||
return to_return
|
||||
|
||||
func get_local_method(name):
|
||||
var to_return = get_method(name)
|
||||
if(!to_return.is_local):
|
||||
to_return = null
|
||||
|
||||
return to_return
|
||||
|
||||
|
||||
func get_sorted_method_names():
|
||||
var keys = _methods_by_name.keys()
|
||||
keys.sort()
|
||||
return keys
|
||||
|
||||
|
||||
func get_local_method_names():
|
||||
var names = []
|
||||
for method in _methods_by_name:
|
||||
if(_methods_by_name[method].is_local):
|
||||
names.append(method)
|
||||
|
||||
return names
|
||||
|
||||
|
||||
func get_super_method_names():
|
||||
var names = []
|
||||
for method in _methods_by_name:
|
||||
if(!_methods_by_name[method].is_local):
|
||||
names.append(method)
|
||||
|
||||
return names
|
||||
|
||||
|
||||
func get_local_methods():
|
||||
var to_return = []
|
||||
for key in _methods_by_name:
|
||||
var method = _methods_by_name[key]
|
||||
if(method.is_local):
|
||||
to_return.append(method)
|
||||
return to_return
|
||||
|
||||
|
||||
func get_super_methods():
|
||||
var to_return = []
|
||||
for key in _methods_by_name:
|
||||
var method = _methods_by_name[key]
|
||||
if(!method.is_local):
|
||||
to_return.append(method)
|
||||
return to_return
|
||||
|
||||
|
||||
func get_extends_text():
|
||||
var text = null
|
||||
if(is_native):
|
||||
text = str("extends ", _native_class_name)
|
||||
else:
|
||||
text = str("extends '", _script_path, "'")
|
||||
if(_subpath != null):
|
||||
text += '.' + _subpath
|
||||
return text
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
var scripts = {}
|
||||
|
||||
func _get_instance_id(thing):
|
||||
var inst_id = null
|
||||
|
||||
if(GutUtils.is_native_class(thing)):
|
||||
var id_str = str(thing).replace("<", '').replace(">", '').split('#')[1]
|
||||
inst_id = id_str.to_int()
|
||||
elif(typeof(thing) == TYPE_STRING):
|
||||
if(FileAccess.file_exists(thing)):
|
||||
inst_id = load(thing).get_instance_id()
|
||||
else:
|
||||
inst_id = thing.get_instance_id()
|
||||
|
||||
return inst_id
|
||||
|
||||
|
||||
func parse(thing, inner_thing=null):
|
||||
var key = -1
|
||||
if(inner_thing == null):
|
||||
key = _get_instance_id(thing)
|
||||
else:
|
||||
key = _get_instance_id(inner_thing)
|
||||
|
||||
var parsed = null
|
||||
|
||||
if(key != null):
|
||||
if(scripts.has(key)):
|
||||
parsed = scripts[key]
|
||||
else:
|
||||
var obj = instance_from_id(_get_instance_id(thing))
|
||||
var inner = null
|
||||
if(inner_thing != null):
|
||||
inner = instance_from_id(_get_instance_id(inner_thing))
|
||||
|
||||
if(obj is Resource or GutUtils.is_native_class(obj)):
|
||||
parsed = ParsedScript.new(obj, inner)
|
||||
scripts[key] = parsed
|
||||
|
||||
return parsed
|
||||
|
Reference in New Issue
Block a user