diff options
-rw-r--r-- | defs.sh | 179 |
1 files changed, 155 insertions, 24 deletions
@@ -18,7 +18,7 @@ function bos_list_new_funcs() { while read -r _ _ name; do new_function="$(declare -pf "$name")" if [[ "$new_function" != "${bos_saved_funcs["$name"]}" ]]; then - echo -n "${name}"$'\0' + echo "${name}" fi done < <( declare -pF ) @@ -99,49 +99,172 @@ 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) + readarray -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 - # +function bos_find_class_for_method() { # 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 class invoked us + local start_from_class="$2" # - what method invoked us (same) - local caller="${FUNCNAME[1]}" - local caller_class="${caller%.*}" - local caller_method="${caller##*.}" + local method="$3" local -n mro="${class}__bos_mro" - local next_class idx + local next_class + local idx=0 + + 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 + echo "${mro[$idx]}" + return 0 + fi + done + + >&2 echo "method $method not found" +} + +function bos_id_from_self() { + local -a parts=( $1 ) + echo "${parts[2]}" +} + +# objects are values, so they're stored in variables! +# +# the shape of that value is… a call to _invoke curry-ed on class and +# id, so that `$my_obj the-method 1 2` is equivalent to `_invoke +# TheClass $the_obj_id the-method 1 2` +function bos_self_from_class_id() { + local class="$1" + local self_id="$2" + echo "bos_invoke $class $self_id" +} + +function bos_storage_var_for_object() { + local self_id="$(bos_id_from_self "$1")" + local var="bos_obj_storage_${self_id}" + echo "$var" +} + +function bos_set_attribute_value() { + local self="$1";shift + local field="$1";shift + local -n storage="$(bos_storage_var_for_object "$self")" + storage[$field]="$*" +} - for (( idx=0 ; idx < "${#mro}" ; ++idx )); do - if [[ "${mro[$idx]}" == "$caller_class" ]]; then - next_class="${mro[ (( $idx + 1 )) ]}" - break +function bos_get_attribute_value() { + local self="$1";shift + local field="$1";shift + local -n storage="$(bos_storage_var_for_object "$self")" + echo "${storage[$field]}" +} + +function bos_add_attribute() { + local name="$1" + + eval " +function get_${name}() { + bos_get_attribute_value \"\$self\" $name +} +function set_${name}() { + bos_set_attribute_value \"\$self\" $name \"\$@\" +} +" +} + +function bos_find_methods() { + local class="$1" + local method="$2" + local -n dest="$3" + + local -n mro="${class}__bos_mro" + + dest=() + + for class in "${mro[@]}"; do + local full_name="${class}.${method}" + if declare -F "$full_name" >/dev/null; then + dest+=( "$full_name" ) fi done - "${next_class}.${caller_method}" "$@" + return 0 +} + +function bos_caller() { + local idx + for caller in "${FUNCNAME[@]}"; do + if [[ ! $caller =~ ^bos_ ]]; then + echo "$caller" + return 0 + fi + done +} + +# the method dispatcher +function bos_invoke() { + local class="$1";shift + local self_id="$1";shift + local method="$1";shift + local self="$(bos_self_from_class_id $class $self_id)" + + local start_from_class='' + + if [[ "$method" == 'next.method' ]]; then + local caller="$(bos_caller)" + method="${caller##*.}" + start_from_class="${caller%.*}" + fi + + class="$(bos_find_class_for_method "$class" "$start_from_class" "$method")" + + "${class}.${method}" "$@" +} + +bos_object_id=0 +function bos_create_object() { + local -n dest="$1";shift + local class="$1";shift + (( ++bos_object_id )) + local self="$(bos_self_from_class_id $class $bos_object_id)" + declare -gA "$(bos_storage_var_for_object "$self")" + + $self BUILD "$@" + + dest="$self" } # ---- test ---- bos_begin_class one +bos_add_attribute first + +BUILD() { + echo "building one" + $self set_first "$1" +} + function doit() { - echo "one method" + echo "one method ($*) first=$( $self get_first )" } bos_end_class @@ -150,14 +273,22 @@ bos_begin_class two bos_set_superclasses one +bos_add_attribute second + +BUILD() { + echo "building two" + $self set_second "$1" + $self next.method "$2" +} + function doit() { - echo "two method" - bos_next_method two + echo "two method ($*) second=$( $self get_second )" + + $self next.method "$@" } bos_end_class +bos_create_object A two 16 23 - -one.doit -two.doit +$A doit 1 2 3 |