declare -A bos_saved_funcs
function bos_save_funcs() {
local _ name
while read -r _ _ name; do
bos_saved_funcs+=( ["$name"]="$(declare -pf "$name")" )
done < <( declare -pF )
return 0
}
function bos_list_new_funcs() {
local _ name new_function
while read -r _ _ name; do
new_function="$(declare -pf "$name")"
if [[ "$new_function" != "${bos_saved_funcs["$name"]}" ]]; then
echo -n "${name}"$'\0'
fi
done < <( declare -pF )
return 0
}
function bos_qualify_funcs() {
local prefix="$1"
shift
local _ name new_function
for name in "$@"; do
new_function="$(declare -pf "$name")"
eval "${prefix}.${new_function}"
if [[ -n "${bos_saved_funcs["$name"]}" ]]; then
eval "${bos_saved_funcs["$name"]}"
else
unset -f "$name"
fi
done
return 0
}
function bos_set_superclasses() {
local isa_name="${bos_current_class}__bos_isa"
declare -ga "$isa_name"
local -n isa="$isa_name"
isa=( "$@" )
return 0
}
function bos_get_superclasses_for() {
local class="$1"
local -n dest="$2"
local isa_name="${class}__bos_isa"
local -n isa="$isa_name"
dest=( "${isa[@]}" )
return 0
}
function bos_linearised_isa() {
local class="$1"
local -n _linearised_isa="$2"
_linearised_isa=( "$class" )
local -a nextclasses
bos_get_superclasses_for "$class" nextclasses
while [[ "${#nextclasses}" -gt 0 ]]; do
_linearised_isa+=( "${nextclasses[0]}" )
class="${nextclasses[0]}"
bos_get_superclasses_for "$class" nextclasses
done
return 0
}
bos_current_class=''
function bos_begin_class() {
bos_current_class="$1"
bos_save_funcs
return 0
}
function bos_end_class() {
local mro_name="${bos_current_class}__bos_mro"
declare -ga "$mro_name"
readarray -d $'\0' -t method_names < <(bos_list_new_funcs)
bos_qualify_funcs "$bos_current_class" "${method_names[@]}"
bos_linearised_isa "$bos_current_class" "$mro_name"
return 0
}
function bos_next_method() {
local class="$1"
local caller="${FUNCNAME[1]}"
local caller_class="${caller%.*}"
local caller_method="${caller##*.}"
local -n mro="${class}__bos_mro"
local next_class idx
for (( idx=0 ; idx < "${#mro}" ; ++idx )); do
if [[ "${mro[$idx]}" == "$caller_class" ]]; then
next_class="${mro[ (( $idx + 1 )) ]}"
break
fi
done
"${next_class}.${caller_method}" "$@"
}
bos_begin_class one
function doit() {
echo "one method"
}
bos_end_class
bos_begin_class two
bos_set_superclasses one
function doit() {
echo "two method"
bos_next_method two
}
bos_end_class
one.doit
two.doit