From 6297ec2ae4263c346a9f7cf036055ca8cdb72c78 Mon Sep 17 00:00:00 2001 From: Gianni Ceccarelli Date: Fri, 14 Jul 2023 15:22:38 +0100 Subject: inheritance via MOP *probably*, I'm still not completely certain I've found all the weirdness --- bos-dispatch.sh | 6 +++--- bos-mop-inheritance.sh | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ bos-mop.sh | 18 ++++++++++++++---- test.sh | 12 ++++++++---- 4 files changed, 76 insertions(+), 11 deletions(-) create mode 100644 bos-mop-inheritance.sh diff --git a/bos-dispatch.sh b/bos-dispatch.sh index cb883d8..afefb5e 100644 --- a/bos-dispatch.sh +++ b/bos-dispatch.sh @@ -6,10 +6,9 @@ function bos-dispatch/invoke() { local self_id="$1";shift local method="$1";shift - local self - bos-object-id/pack-self-into "$class" "$self_id" self - if declare -F "$class/$method" >/dev/null; then + local self + bos-object-id/pack-self-into "$class" "$self_id" self "$class/$method" "$@" return $? fi @@ -19,4 +18,5 @@ function bos-dispatch/invoke() { local -n metaclass_object="$metaclass_ref" $metaclass_object invoke "$class" "$self_id" "$method" "$@" + return $? } diff --git a/bos-mop-inheritance.sh b/bos-mop-inheritance.sh new file mode 100644 index 0000000..551dd18 --- /dev/null +++ b/bos-mop-inheritance.sh @@ -0,0 +1,51 @@ +#!bash + +# this encoding must match bos-namespaces/encode-into +bos_5fbos_2fmop_2finheritance_5fmeta="bos-dispatch/invoke bos/mop/base 0" +declare -a bos_5fbos_2fmop_2finheritance_5fmro=( "bos/mop/inheritance" "bos/mop/base" ) + +function bos/mop/inheritance/isa-for-into() { + bos-namespaces/store-array-for-into isa "$1" "$2" +} + +function bos/mop/inheritance/set-superclasses-for() { + local isa_name; $self isa-for-into "$1" isa_name + local -n isa="$isa_name" + shift + + isa=( "$@" ) + + return 0 +} + +function bos/mop/inheritance/get-superclasses-for-into() { + local isa_name; $self isa-for-into "$1" isa_name + local -n isa="$isa_name" + local -n dest="$2" + + dest=( "${isa[@]}" ) + + return 0 +} + +# given a class and an array, sets the array to the list of clasess to +# look into when resolving a method call for the given class, in order +function bos/mop/inheritance/make-mro-for() { + local class="$1" + local mro_name; $self mro-for-into "$class" mro_name + local -n mro="$mro_name" + + # TODO: use C3 and support multiple inheritance + + mro=( "$class" ) + local -a nextclasses + $self get-superclasses-for-into "$class" nextclasses + + while [[ "${#nextclasses}" -gt 0 ]]; do + mro+=( "${nextclasses[0]}" ) + class="${nextclasses[0]}" + $self get-superclasses-for-into "$class" nextclasses + done + + return 0 +} diff --git a/bos-mop.sh b/bos-mop.sh index 3b06216..b3b03f0 100644 --- a/bos-mop.sh +++ b/bos-mop.sh @@ -23,6 +23,12 @@ function bos/mop/base/find-method-into() { local mro_store; $self mro-for-into "$class" mro_store local -n mro="$mro_store" + + # minimal MRO: the class itself + if [[ "${#mro[@]}" -eq 0 ]]; then + mro=( "$class" ) + fi + local idx=0 # if we don't have a $start_from_class, it means we're doing the @@ -67,14 +73,18 @@ function bos/mop/base/invoke() { fi # get the first class that defines the method - local to_invoke - $self find-method-into "$class" "$start_from_class" "$method" to_invoke + + # there is some fuckery going on with namerefs, recursion, and + # local; this is a probably-bad-but-works workaround: use a + # different variable name in different recursive calls + local ffsname="to_invoke_${#FUNCNAME[*]}" + $self find-method-into "$class" "$start_from_class" "$method" "$ffsname" # TODO: make the fields accessible! - local self bos-object-id/pack-self-into "$class" "$object_id" self # call it - "$to_invoke" "$@" + eval "\"\$$ffsname\" \"\$@\"" + return $? } diff --git a/test.sh b/test.sh index 1a4ed6d..4a3e02c 100644 --- a/test.sh +++ b/test.sh @@ -1,19 +1,23 @@ #!/bin/bash +PS4='[${#FUNCNAME[*]}] ${BASH_SOURCE[0]}:${LINENO} (${FUNCNAME[0]}) +' + . bos-namespaces.sh . bos-object-id.sh . bos-mop.sh . bos-dispatch.sh +. bos-mop-inheritance.sh -bos_5fA_5fmeta="bos-dispatch/invoke bos/mop/base 0" -bos_5fA_5fmro=( "A" ) +bos_5fA_5fmeta="bos-dispatch/invoke bos/mop/inheritance 0" function A/thing() { echo "<$self> A/thing ($*)" } -bos_5fB_5fmeta="bos-dispatch/invoke bos/mop/base 0" -bos_5fB_5fmro=( "B" "A" ) + +bos_5fB_5fmeta="bos-dispatch/invoke bos/mop/inheritance 0" +$bos_5fB_5fmeta set-superclasses-for B A +$bos_5fB_5fmeta make-mro-for B function B/other() { echo "<$self> B/other ($*)" -- cgit v1.2.3