Merge remote-tracking branch 'dubek/fix-negative' into fix-negative
[jackhill/mal.git] / bash / step3_env.sh
1 #!/usr/bin/env bash
2
3 source $(dirname $0)/reader.sh
4 source $(dirname $0)/printer.sh
5 source $(dirname $0)/env.sh
6
7 # read
8 READ () {
9 [ "${1}" ] && r="${1}" || READLINE
10 READ_STR "${r}"
11 }
12
13 # eval
14 EVAL_AST () {
15 local ast="${1}" env="${2}"
16 #_pr_str "${ast}"; echo "EVAL_AST '${ast}:${r} / ${env}'"
17 _obj_type "${ast}"; local ot="${r}"
18 case "${ot}" in
19 symbol)
20 ENV_GET "${env}" "${ast}"
21 return ;;
22 list)
23 _map_with_type _list EVAL "${ast}" "${env}" ;;
24 vector)
25 _map_with_type _vector EVAL "${ast}" "${env}" ;;
26 hash_map)
27 local res="" key= val="" hm="${ANON["${ast}"]}"
28 _hash_map; local new_hm="${r}"
29 eval local keys="\${!${hm}[@]}"
30 for key in ${keys}; do
31 eval val="\${${hm}[\"${key}\"]}"
32 EVAL "${val}" "${env}"
33 _assoc! "${new_hm}" "${key}" "${r}"
34 done
35 r="${new_hm}" ;;
36 *)
37 r="${ast}" ;;
38 esac
39 }
40
41 EVAL () {
42 local ast="${1}" env="${2}"
43 r=
44 [[ "${__ERROR}" ]] && return 1
45 #_pr_str "${ast}"; echo "EVAL '${r} / ${env}'"
46 _obj_type "${ast}"; local ot="${r}"
47 if [[ "${ot}" != "list" ]]; then
48 EVAL_AST "${ast}" "${env}"
49 return
50 fi
51
52 # apply list
53 _nth "${ast}" 0; local a0="${r}"
54 _nth "${ast}" 1; local a1="${r}"
55 _nth "${ast}" 2; local a2="${r}"
56 case "${ANON["${a0}"]}" in
57 def!) EVAL "${a2}" "${env}"
58 [[ "${__ERROR}" ]] && return 1
59 ENV_SET "${env}" "${a1}" "${r}"
60 return ;;
61 let*) ENV "${env}"; local let_env="${r}"
62 local let_pairs=(${ANON["${a1}"]})
63 local idx=0
64 #echo "let: [${let_pairs[*]}] for ${a2}"
65 while [[ "${let_pairs["${idx}"]}" ]]; do
66 EVAL "${let_pairs[$(( idx + 1))]}" "${let_env}"
67 ENV_SET "${let_env}" "${let_pairs[${idx}]}" "${r}"
68 idx=$(( idx + 2))
69 done
70 EVAL "${a2}" "${let_env}"
71 return ;;
72 *) EVAL_AST "${ast}" "${env}"
73 [[ "${__ERROR}" ]] && r= && return 1
74 local el="${r}"
75 _first "${el}"; local f="${r}"
76 _rest "${el}"; local args="${ANON["${r}"]}"
77 #echo "invoke: ${f} ${args}"
78 eval ${f} ${args}
79 return ;;
80 esac
81 }
82
83 # print
84 PRINT () {
85 if [[ "${__ERROR}" ]]; then
86 _pr_str "${__ERROR}" yes
87 r="Error: ${r}"
88 __ERROR=
89 else
90 _pr_str "${1}" yes
91 fi
92 }
93
94 # repl
95 ENV; REPL_ENV="${r}"
96 REP () {
97 r=
98 READ "${1}"
99 EVAL "${r}" "${REPL_ENV}"
100 PRINT "${r}"
101 }
102
103 plus () { r=$(( ${ANON["${1}"]} + ${ANON["${2}"]} )); _number "${r}"; }
104 minus () { r=$(( ${ANON["${1}"]} - ${ANON["${2}"]} )); _number "${r}"; }
105 multiply () { r=$(( ${ANON["${1}"]} * ${ANON["${2}"]} )); _number "${r}"; }
106 divide () { r=$(( ${ANON["${1}"]} / ${ANON["${2}"]} )); _number "${r}"; }
107
108 _symbol "+"; ENV_SET "${REPL_ENV}" "${r}" plus
109 _symbol "-"; ENV_SET "${REPL_ENV}" "${r}" minus
110 _symbol "__STAR__"; ENV_SET "${REPL_ENV}" "${r}" multiply
111 _symbol "/"; ENV_SET "${REPL_ENV}" "${r}" divide
112
113 # repl loop
114 while true; do
115 READLINE "user> " || exit "$?"
116 [[ "${r}" ]] && REP "${r}" && echo "${r}"
117 done