#!/usr/bin/env bash source $(dirname $0)/reader.sh source $(dirname $0)/printer.sh # read proc READ { test ${1} && setvar 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}" case{ symbol { local val="${ANON["${ast}"]}" eval r="\${${env}["${val}"]}" test ${r} || _error "'${val}' not found" } list { _map_with_type _list EVAL ${ast} ${env} } vector { _map_with_type _vector EVAL ${ast} ${env} } 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} } setvar r = "${new_hm}" } * { setvar r = "${ast}" } } } proc EVAL { local ast="${1}" env="${2}" setvar 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} && setvar 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 setvar r = ""Error: ${r}"" setvar __ERROR = '' } else { _pr_str ${1} yes } } # repl declare -A REPL_ENV proc REP { setvar r = '' READ ${1} EVAL ${r} REPL_ENV PRINT ${r} } proc plus { setvar r = $(( ${ANON["${1}"]} + ${ANON["${2}"]} )); _number ${r}; } proc minus { setvar r = $(( ${ANON["${1}"]} - ${ANON["${2}"]} )); _number ${r}; } proc multiply { setvar r = $(( ${ANON["${1}"]} * ${ANON["${2}"]} )); _number ${r}; } proc divide { setvar r = $(( ${ANON["${1}"]} / ${ANON["${2}"]} )); _number ${r}; } setvar REPL_ENV["+"]=plus setvar REPL_ENV["-"]=minus setvar REPL_ENV["__STAR__"]=multiply setvar REPL_ENV["/"]=divide # repl loop while true { READLINE "user> " || exit "$?" [[ "${r}" ]] && REP ${r} && echo ${r} }