summaryrefslogtreecommitdiff
path: root/defs.sh
blob: 805b7a01950a17eb6480b6b5d177ba1b759fc6fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
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