summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--defs.sh163
1 files changed, 163 insertions, 0 deletions
diff --git a/defs.sh b/defs.sh
new file mode 100644
index 0000000..805b7a0
--- /dev/null
+++ b/defs.sh
@@ -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