Commit | Line | Data |
---|---|---|
7838e339 | 1 | #!/usr/bin/env bash |
31690700 | 2 | |
31690700 | 3 | source $(dirname $0)/reader.sh |
ea81a808 | 4 | source $(dirname $0)/printer.sh |
ea81a808 | 5 | source $(dirname $0)/env.sh |
8cb5cda4 | 6 | source $(dirname $0)/core.sh |
31690700 | 7 | |
86b689f3 | 8 | # read |
31690700 | 9 | READ () { |
8cb5cda4 | 10 | [ "${1}" ] && r="${1}" || READLINE |
31690700 JM |
11 | READ_STR "${r}" |
12 | } | |
13 | ||
86b689f3 | 14 | # eval |
31690700 JM |
15 | EVAL_AST () { |
16 | local ast="${1}" env="${2}" | |
17 | #_pr_str "${ast}"; echo "EVAL_AST '${ast}:${r} / ${env}'" | |
18 | _obj_type "${ast}"; local ot="${r}" | |
19 | case "${ot}" in | |
20 | symbol) | |
b8ee29b2 | 21 | ENV_GET "${env}" "${ast}" |
31690700 JM |
22 | return ;; |
23 | list) | |
ea81a808 | 24 | _map_with_type _list EVAL "${ast}" "${env}" ;; |
31690700 | 25 | vector) |
ea81a808 | 26 | _map_with_type _vector EVAL "${ast}" "${env}" ;; |
31690700 | 27 | hash_map) |
33d33bb3 | 28 | local res="" key= val="" hm="${ANON["${ast}"]}" |
ea81a808 | 29 | _hash_map; local new_hm="${r}" |
31690700 JM |
30 | eval local keys="\${!${hm}[@]}" |
31 | for key in ${keys}; do | |
32 | eval val="\${${hm}[\"${key}\"]}" | |
33 | EVAL "${val}" "${env}" | |
ea81a808 | 34 | _assoc! "${new_hm}" "${key}" "${r}" |
31690700 JM |
35 | done |
36 | r="${new_hm}" ;; | |
37 | *) | |
38 | r="${ast}" ;; | |
39 | esac | |
40 | } | |
41 | ||
31690700 JM |
42 | EVAL () { |
43 | local ast="${1}" env="${2}" | |
44 | r= | |
45 | [[ "${__ERROR}" ]] && return 1 | |
46 | #_pr_str "${ast}"; echo "EVAL '${r} / ${env}'" | |
47 | _obj_type "${ast}"; local ot="${r}" | |
48 | if [[ "${ot}" != "list" ]]; then | |
49 | EVAL_AST "${ast}" "${env}" | |
50 | return | |
51 | fi | |
52 | ||
53 | # apply list | |
5bbc7a1f JM |
54 | _empty? "${ast}" && r="${ast}" && return |
55 | ||
31690700 JM |
56 | _nth "${ast}" 0; local a0="${r}" |
57 | _nth "${ast}" 1; local a1="${r}" | |
58 | _nth "${ast}" 2; local a2="${r}" | |
59 | case "${ANON["${a0}"]}" in | |
b8ee29b2 JM |
60 | def!) EVAL "${a2}" "${env}" |
61 | [[ "${__ERROR}" ]] && return 1 | |
62 | ENV_SET "${env}" "${a1}" "${r}" | |
31690700 | 63 | return ;; |
5bbc7a1f | 64 | let__STAR__) ENV "${env}"; local let_env="${r}" |
31690700 JM |
65 | local let_pairs=(${ANON["${a1}"]}) |
66 | local idx=0 | |
67 | #echo "let: [${let_pairs[*]}] for ${a2}" | |
68 | while [[ "${let_pairs["${idx}"]}" ]]; do | |
69 | EVAL "${let_pairs[$(( idx + 1))]}" "${let_env}" | |
b8ee29b2 | 70 | ENV_SET "${let_env}" "${let_pairs[${idx}]}" "${r}" |
31690700 JM |
71 | idx=$(( idx + 2)) |
72 | done | |
73 | EVAL "${a2}" "${let_env}" | |
74 | return ;; | |
8cb5cda4 | 75 | do) _rest "${ast}" |
31690700 JM |
76 | EVAL_AST "${r}" "${env}" |
77 | [[ "${__ERROR}" ]] && r= && return 1 | |
8cb5cda4 | 78 | _last "${r}" |
31690700 JM |
79 | return ;; |
80 | if) EVAL "${a1}" "${env}" | |
b8ee29b2 | 81 | [[ "${__ERROR}" ]] && return 1 |
31690700 JM |
82 | if [[ "${r}" == "${__false}" || "${r}" == "${__nil}" ]]; then |
83 | # eval false form | |
84 | _nth "${ast}" 3; local a3="${r}" | |
85 | if [[ "${a3}" ]]; then | |
86 | EVAL "${a3}" "${env}" | |
87 | else | |
88 | r="${__nil}" | |
89 | fi | |
90 | else | |
91 | # eval true condition | |
92 | EVAL "${a2}" "${env}" | |
93 | fi | |
94 | return ;; | |
5bbc7a1f | 95 | fn__STAR__) _function "ENV \"${env}\" \"${a1}\" \"\${@}\"; \ |
ea81a808 | 96 | EVAL \"${a2}\" \"\${r}\"" |
31690700 JM |
97 | return ;; |
98 | *) EVAL_AST "${ast}" "${env}" | |
99 | [[ "${__ERROR}" ]] && r= && return 1 | |
100 | local el="${r}" | |
8cb5cda4 JM |
101 | _first "${el}"; local f="${ANON["${r}"]}" |
102 | _rest "${el}"; local args="${ANON["${r}"]}" | |
31690700 JM |
103 | #echo "invoke: ${f} ${args}" |
104 | eval ${f} ${args} | |
105 | return ;; | |
106 | esac | |
107 | } | |
108 | ||
86b689f3 | 109 | |
31690700 JM |
110 | PRINT () { |
111 | if [[ "${__ERROR}" ]]; then | |
112 | _pr_str "${__ERROR}" yes | |
113 | r="Error: ${r}" | |
114 | __ERROR= | |
115 | else | |
116 | _pr_str "${1}" yes | |
117 | fi | |
118 | } | |
119 | ||
86b689f3 | 120 | # repl |
31690700 JM |
121 | ENV; REPL_ENV="${r}" |
122 | REP () { | |
123 | r= | |
70aff0c1 | 124 | READ "${1}" |
8cb5cda4 | 125 | EVAL "${r}" "${REPL_ENV}" |
31690700 JM |
126 | PRINT "${r}" |
127 | } | |
128 | ||
8cb5cda4 | 129 | # core.sh: defined using bash |
b8ee29b2 JM |
130 | _fref () { |
131 | _symbol "${1}"; local sym="${r}" | |
132 | _function "${2} \"\${@}\"" | |
133 | ENV_SET "${REPL_ENV}" "${sym}" "${r}" | |
134 | } | |
ea81a808 | 135 | for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done |
31690700 | 136 | |
8cb5cda4 | 137 | # core.mal: defined using the language itself |
31690700 JM |
138 | REP "(def! not (fn* (a) (if a false true)))" |
139 | ||
86b689f3 JM |
140 | # repl loop |
141 | while true; do | |
142 | READLINE "user> " || exit "$?" | |
143 | [[ "${r}" ]] && REP "${r}" && echo "${r}" | |
144 | done |