2 # mal (Make a Lisp) object types
5 if [ -z "${__mal_core_included__}" ]; then
6 __mal_core_included
=true
8 source $
(dirname $0)/types.sh
9 source $
(dirname $0)/reader.sh
10 source $
(dirname $0)/printer.sh
28 _equal?
"${1}" "${2}" && r="${__true}" || r="${__false}"
34 nil?
() { _nil?
"${1}" && r="${__true}" || r="${__false}"; }
35 true? () { _true? "${1}" && r="${__true}" || r="${__false}"; }
36 false?
() { _false?
"${1}" && r="${__true}" || r="${__false}"; }
41 symbol? () { _symbol? "${1}" && r="${__true}" || r="${__false}"; }
46 number?
() { _number?
"${1}" && r="${__true}" || r="${__false}"; }
48 num_plus () { r=$(( ${ANON["${1}"]} + ${ANON["${2}"]} )); _number "${r}"; }
49 num_minus () { r=$(( ${ANON["${1}"]} - ${ANON["${2}"]} )); _number "${r}"; }
50 num_multiply () { r=$(( ${ANON["${1}"]} * ${ANON["${2}"]} )); _number "${r}"; }
51 num_divide () { r=$(( ${ANON["${1}"]} / ${ANON["${2}"]} )); _number "${r}"; }
53 _num_bool () { [[ "${1}" = "1" ]] && r="${__true}" || r="${__false}"; }
54 num_gt
() { r
=$
(( ${ANON["${1}"]} > ${ANON["${2}"]} )); _num_bool "${r}"; }
55 num_gte
() { r
=$
(( ${ANON["${1}"]} >= ${ANON["${2}"]} )); _num_bool "${r}"; }
56 num_lt
() { r
=$
(( ${ANON["${1}"]} < ${ANON["${2}"]} )); _num_bool "${r}"; }
57 num_lte
() { r
=$
(( ${ANON["${1}"]} <= ${ANON["${2}"]} )); _num_bool "${r}"; }
62 string?
() { _string?
"${1}" && r="${__true}" || r="${__false}"; }
66 for x in "${@}"; do _pr_str "${x}" yes; res="${res} ${r}"; done
72 for x in "${@}"; do _pr_str "${x}"; res="${res}${r}"; done
78 for x in "${@}"; do _pr_str "${x}" yes; res="${res} ${r}"; done
85 for x in "${@}"; do _pr_str "${x}"; res="${res} ${r}"; done
86 res="${res//\\n/$'\n'}"
92 READLINE "${ANON["${1}"]}" && _string "${r}" || r="${__nil}"
96 READ_STR "${ANON["${1}"]}"
101 mapfile lines < "${ANON["${1}"]}"
102 local text="${lines[*]}"; text=${text//$'\n' /$'\n'}
108 function? () { _function? "${1}" && r="${__true}" || r="${__false}"; }
112 list?
() { _list?
"${1}" && r="${__true}" || r="${__false}"; }
115 # Vector functions (same as lists for now)
116 vector? () { _vector? "${1}" && r="${__true}" || r="${__false}"; }
119 # Hash map (associative array) functions
120 hash_map?
() { _hash_map?
"${1}" && r="${__true}" || r="${__false}"; }
122 # Return new hash map with keys/values updated
124 if ! _hash_map? "${1}"; then
125 _error "assoc onto non-hash-map
"
128 _copy_hash_map "${1}"; shift
130 local obj=${ANON["${name}"]}
133 while [[ "${1}" ]]; do
134 eval ${obj}[\"${ANON["${1}"]}\"]=\"${2}\"
141 if ! _hash_map? "${1}"; then
142 _error "dissoc from non-hash-map
"
145 _copy_hash_map "${1}"; shift
147 local obj=${ANON["${name}"]}
150 while [[ "${1}" ]]; do
151 eval unset ${obj}[\"${ANON["${1}"]}\"]
158 _obj_type "${1}"; local ot="${r}"
161 local obj="${ANON["${1}"]}"
162 eval r="\
${${obj}[\"${2}\"]}" ;;
164 _nth "${1}" "${2}" ;;
170 _get "${1}" "${ANON["${2}"]}"
171 [[ "${r}" ]] || r="${__nil}"
174 contains? () { _contains? "${1}" "${ANON["${2}"]}" && r="${__true}" || r="${__false}"; }
177 local obj
="${ANON["${1}"]}"
179 eval local keys
="\${!${obj}[@]}"
182 kstrs
="${kstrs} ${r}"
187 ANON
["${r}"]="${kstrs:1}"
191 local obj
="${ANON["${1}"]}"
194 eval local keys
="\${!${obj}[@]}"
196 eval val
="\${${obj}["\${k}"]}"
197 kvals
="${kvals} ${val}"
202 ANON
["${r}"]="${kvals:1}"
206 # sequence operations
209 _sequential?
"${1}" && r="${__true}" || r="${__false}"
213 _list
${1} ${ANON["${2}"]}
219 for item
in "${@}"; do
220 acc
="${acc} ${ANON["${item}"]}"
222 ANON
["${r}"]="${acc:1}"
226 _nth
"${1}" "${ANON["${2}"]}"
229 empty?
() { _empty?
"${1}" && r="${__true}" || r="${__false}"; }
237 local obj="${1}"; shift
238 local obj_data="${ANON["${obj}"]}"
239 __new_obj_like "${obj}"
240 if _list? "${obj}"; then
241 ANON["${r}"]="${obj_data:+${obj_data}}"
243 ANON["${r}"]="${elem} ${ANON["${r}"]}"
247 ANON["${r}"]="${obj_data:+${obj_data} }${*}"
252 local f="${ANON["${1}"]}"; shift
253 local items="${@:1:$(( ${#@} -1 ))} ${ANON["${!#}"]}"
254 eval ${f%%@*} ${items}
257 # Takes a function object and an list object and invokes the function
258 # on each element of the list, returning a new list of the results.
260 local f="${ANON["${1}"]}"; shift
261 #echo _map "${f}" "${@}"
269 local obj="${1}"; shift
270 local meta_data="${1}"; shift
271 __new_obj_like "${obj}"
272 ANON["${r}"]="${ANON["${obj}"]}"
273 local meta_obj="meta_
${r#*_}"
274 ANON["${meta_obj}"]="${meta_data}"
278 r="${ANON["meta_${1#*_}"]}"
279 [[ "${r}" ]] || r="${__nil}"
285 atom? () { _atom? "${1}" && r="${__true}" || r="${__false}"; }
287 # TODO: double-check atom type
291 local atm
="${1}"; shift
292 ANON
["${atm}"]="${*}"
296 local atm
="${1}"; shift
297 local f
="${ANON["${1}"]}"; shift
298 ${f%%@*} "${ANON["${atm}"]}" "${@}"
299 ANON["${atm}"]="${r}"
304 # Namespace of core functions
320 [read-string]=read_string
328 [__STAR__]=num_multiply
340 [contains?]=contains?
344 [sequential?]=sequential?
356 [with-meta]=with_meta