#!/usr/bin/env bash source $[dirname $0]/reader.sh source $[dirname $0]/printer.sh # read proc READ { test $(1) && setglobal r = $(1) || READLINE READ_STR $(r) } # eval proc EVAL_AST { local ast="$(1)" env="$(2)" #_pr_str "${ast}"; echo "EVAL_AST '${ast}:${r} / ${env}'" _obj_type $(ast); local ot="$(r)" match $(ot) { with symbol local val="$(ANON["${ast}"])" eval r="\${$(env)["$(val)"]}" test $(r) || _error "'$(val)' not found" with list _map_with_type _list EVAL $(ast) $(env) with vector _map_with_type _vector EVAL $(ast) $(env) with hash_map local res="" key= val="" hm="$(ANON["${ast}"])" _hash_map; local new_hm="$(r)" eval local keys="\${!$(hm)[@]}" for key in [$(keys)] { eval val="\${$(hm)[\"$(key)\"]}" EVAL $(val) $(env) _assoc! $(new_hm) $(key) $(r) } setglobal r = $(new_hm) with * setglobal r = $(ast) } } proc EVAL { local ast="$(1)" env="$(2)" setglobal r = '' [[ "${__ERROR}" ]] && return 1 #_pr_str "${ast}"; echo "EVAL '${r} / ${env}'" _obj_type $(ast); local ot="$(r)" if [[ "${ot}" != "list" ]] { EVAL_AST $(ast) $(env) return } _empty? $(ast) && setglobal r = $(ast) && return # apply list EVAL_AST $(ast) $(env) [[ "${__ERROR}" ]] && return 1 local el="$(r)" _first $(el); local f="$(r)" _rest $(el); local args="$(ANON["${r}"])" #echo "invoke: ${f} ${args}" eval $(f) $(args) } # print proc PRINT { if [[ "${__ERROR}" ]] { _pr_str $(__ERROR) yes setglobal r = ""Error: $(r)"" setglobal __ERROR = '' } else { _pr_str $(1) yes } } # repl declare -A REPL_ENV proc REP { setglobal r = '' READ $(1) EVAL $(r) REPL_ENV PRINT $(r) } proc plus { setglobal r = $shExpr(' ${ANON["${1}"]} + ${ANON["${2}"]} '); _number $(r); } proc minus { setglobal r = $shExpr(' ${ANON["${1}"]} - ${ANON["${2}"]} '); _number $(r); } proc multiply { setglobal r = $shExpr(' ${ANON["${1}"]} * ${ANON["${2}"]} '); _number $(r); } proc divide { setglobal r = $shExpr(' ${ANON["${1}"]} / ${ANON["${2}"]} '); _number $(r); } compat array-assign REPL_ENV '"+"' 'plus' compat array-assign REPL_ENV '"-"' 'minus' compat array-assign REPL_ENV '"__STAR__"' 'multiply' compat array-assign REPL_ENV '"/"' 'divide' # repl loop while true { READLINE "user> " || exit "$?" [[ "${r}" ]] && REP $(r) && echo $(r) }