summaryrefslogtreecommitdiff
path: root/bos-mop.sh
diff options
context:
space:
mode:
Diffstat (limited to 'bos-mop.sh')
-rw-r--r--bos-mop.sh81
1 files changed, 81 insertions, 0 deletions
diff --git a/bos-mop.sh b/bos-mop.sh
new file mode 100644
index 0000000..f9faef2
--- /dev/null
+++ b/bos-mop.sh
@@ -0,0 +1,81 @@
+#!bash
+
+bos_class__bos__mop__base__meta="bos-dipatch/invoke bos/mop/base 0"
+
+# these are instance methods of the base metaclass
+
+function bos/mop/base/mro-for-into() {
+ local name="bos_mop__mro__${1//\//__}"
+ local -n result="$2"
+ declare -ga "$name"
+ result="$name"
+}
+
+# find the first class (in MRO) that defines a given method
+function bos/mop/base/find-method-into() {
+ # the class that started the method dispatch (the class of $self,
+ # usually)
+ local class="$1"
+ # what class invoked next/method (if we're doing next/method)
+ local start_from_class="$2"
+ # the method to look for
+ local method="$3"
+ local -n result="$4"
+
+ local mro_store; $self mro-for-into mro_store
+ local -n mro="$mro_store"
+ local idx=0
+
+ # if we don't have a $start_from_class, it means we're doing the
+ # initial method resolution, so don't skip any class in $mro
+ 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
+ result="${full_name}"
+ return 0
+ fi
+ done
+
+ # TODO: better error / failure
+ >&2 echo "method $method not found"
+ return 1
+}
+
+# the method dispatcher
+function bos/mop/base/invoke() {
+ local class="$1";shift
+ local object_id="$1";shift
+ local method="$1";shift
+
+ local start_from_class=''
+
+ if [[ "$method" == 'next/method' ]]; then
+ # get the method and the calling class, so
+ # bos_find_class_for_method will return the *next* class to
+ # use
+ local caller; bos-dispatch/caller-into caller
+ method="${caller##*/}"
+ start_from_class="${caller%/*}"
+ fi
+
+ # get the first class that defines the method
+ local to_invoke
+ $self find-method-into "$class" "$start_from_class" "$method" to_invoke
+
+ # TODO: make the fields accessible!
+
+ local self
+ bos-object-id/pack-self-into "$class" "$object_id" self
+
+ # call it
+ "$to_invoke" "$@"
+}