summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGianni Ceccarelli <gianni.ceccarelli@broadbean.com>2023-07-06 16:37:32 +0100
committerGianni Ceccarelli <gianni.ceccarelli@broadbean.com>2023-07-06 16:37:32 +0100
commit20c782acc71e1de6599ba55e2dc0443415c24bca (patch)
tree7a108e3b0b3ae441cf8b471761c5aa5a1d4682dc
parentstarting (diff)
downloadbash-object-system-20c782acc71e1de6599ba55e2dc0443415c24bca.tar.gz
bash-object-system-20c782acc71e1de6599ba55e2dc0443415c24bca.tar.bz2
bash-object-system-20c782acc71e1de6599ba55e2dc0443415c24bca.zip
might work?
-rw-r--r--defs.sh179
1 files changed, 155 insertions, 24 deletions
diff --git a/defs.sh b/defs.sh
index 805b7a0..dc711ec 100644
--- a/defs.sh
+++ b/defs.sh
@@ -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