diff options
-rw-r--r-- | defs.sh | 163 |
1 files changed, 163 insertions, 0 deletions
@@ -0,0 +1,163 @@ +#!bash + +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" + + # TODO: use C3 and support multiple inheritance + + _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() { + # very TODO + # + # we need to know: + # + # - what class started the method dispatch (we need a class name + # or an object instance) + local class="$1" + + # - what class invoked us (${FUNCNAME[...]} and split on the + # *last* `.`) + # + # - what method invoked us (same) + 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}" "$@" +} + +# ---- test ---- + +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 |