diff options
author | dakkar <dakkar@thenautilus.net> | 2023-07-22 15:57:30 +0100 |
---|---|---|
committer | dakkar <dakkar@thenautilus.net> | 2023-07-22 15:57:30 +0100 |
commit | 81a723086f99f8270563dbab28f6a70866dde02d (patch) | |
tree | 4b382a1098a33195121d8db3f2bf294ef3743cec /bos-meta-class.sh | |
parent | factor namespace open/close (diff) | |
download | bash-object-system-81a723086f99f8270563dbab28f6a70866dde02d.tar.gz bash-object-system-81a723086f99f8270563dbab28f6a70866dde02d.tar.bz2 bash-object-system-81a723086f99f8270563dbab28f6a70866dde02d.zip |
single meta class
Diffstat (limited to 'bos-meta-class.sh')
-rw-r--r-- | bos-meta-class.sh | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/bos-meta-class.sh b/bos-meta-class.sh new file mode 100644 index 0000000..4d701b5 --- /dev/null +++ b/bos-meta-class.sh @@ -0,0 +1,152 @@ +#!bash + +# this encoding must match bos-namespaces/encode-into +bos_5fbos_2fmeta_2fclass_5fmeta="bos-dipatch/invoke bos/meta/class 0" +declare -a bos_5fbos_2fmeta_2fclass_5fmro=( "bos/meta/class" ) + +# these are instance methods of the base metaclass + +function bos/meta/class/isa-for-into() { + bos-namespaces/store-array-for-into "$1" isa "$2" +} + +function bos/meta/class/set-superclasses-for() { + local isa_name; $self isa-for-into isa_name "$1" + local -n isa="$isa_name" + shift + + isa=( "$@" ) + + return 0 +} + +function bos/meta/class/get-superclasses-for-into() { + local -n dest="$1" + local isa_name; $self isa-for-into isa_name "$2" + local -n isa="$isa_name" + + dest=( "${isa[@]}" ) + + return 0 +} + +function bos/meta/class/mro-for-into() { + bos-namespaces/store-array-for-into "$1" mro "$2" +} + +# given a class and an array, sets the array to the list of clasess to +# look into when resolving a method call for the given class, in order +function bos/meta/class/make-mro-for() { + local class="$1" + local mro_name; $self mro-for-into mro_name "$class" + local -n mro="$mro_name" + + # TODO: use C3 and support multiple inheritance + + mro=( "$class" ) + local -a nextclasses + $self get-superclasses-for-into nextclasses "$class" + + while [[ "${#nextclasses}" -gt 0 ]]; do + mro+=( "${nextclasses[0]}" ) + class="${nextclasses[0]}" + $self get-superclasses-for-into nextclasses "$class" + done + + return 0 +} + +# find the first class (in MRO) that defines a given method +function bos/meta/class/find-method-into() { + local -n bos_meta_class_find_method_result="$1" + # the class that started the method dispatch (the class of $self, + # usually) + local class="$2" + # what class invoked next/method (if we're doing next/method) + local start_from_class="$3" + # the method to look for + local method="$4" + + local mro_store; $self mro-for-into mro_store "$class" + local -n mro="$mro_store" + + # minimal MRO: the class itself + if [[ "${#mro[@]}" -eq 0 ]]; then + mro=( "$class" ) + fi + + local idx=0 + + # if we don't have a $start_from_class, it means we're doing the + # initial method resolution, so don't skip any class in $mro + if [[ -n "$start_from_class" ]]; then + for (( ; idx < "${#mro[@]}" ; ++idx )); do + if [[ "${mro[$idx]}" == "$start_from_class" ]]; then + (( ++idx )) + break + fi + done + fi + + for (( ; idx < "${#mro[@]}" ; ++idx )); do + local full_name="${mro[$idx]}/${method}" + if declare -F "$full_name" >/dev/null; then + bos_meta_class_find_method_result="${full_name}" + return 0 + fi + done + + # TODO: better error / failure + >&2 echo "method $method not found via class $class" + return 1 +} + +# the method dispatcher +function bos/meta/class/invoke() { + local class="$1";shift + local object_id="$1";shift + local method="$1";shift + + local start_from_class='' + + if [[ "$method" == 'next/method' ]]; then + # get the method and the calling class, so + # bos_find_class_for_method will return the *next* class to + # use + local caller; bos-dispatch/caller-into caller + method="${caller##*/}" + start_from_class="${caller%/*}" + fi + + # get the first class that defines the method + + # there is some fuckery going on with namerefs, recursion, and + # local; this is a probably-bad-but-works workaround: use a + # different variable name in different recursive calls + local ffsname="to_invoke_${#FUNCNAME[*]}" + $self find-method-into "$ffsname" "$class" "$start_from_class" "$method" + + # TODO: make the fields accessible! + + local self + bos-object-id/pack-self-into self "$class" "$object_id" + + # call it + eval "\"\$$ffsname\" \"\$@\"" + return $? +} + +function bos/meta/class/create-object-into() { + local -n bos_meta_class_create_object_result="$1";shift + local class="$1";shift + + local object_id_store; bos-namespaces/store-scalar-for-into object_id_store object_id "$class" + local -n object_id="$object_id_store" + (( ++object_id )) + + bos-object-id/pack-self-into bos_meta_class_create_object_result "$class" "$object_id" + + # TODO invoke BUILD/BUILDALL? + + return 0 +} |