# # mal (Make a Lisp) environment definition # if test -z $(__mal_env_included__) { setglobal __mal_env_included = 'true' source $[dirname $0]/types.sh # Any environment is a hash_map with an __outer__ key that refers to # a parent environment (or nil) proc ENV { setglobal r = '' _hash_map local env="$(r)" if [[ "${1}" ]] { setglobal outer = $(1); shift _assoc! $(env) "__outer__" $(outer) } else { _assoc! $(env) "__outer__" $(__nil) } setglobal r = $(env) if [[ "${1}" && "${@}" ]] { local binds=(${ANON["${1}"]}); shift local idx=0 { local fp="$(ANON["${binds["${idx}"]}"])" if [[ "${fp}" == "&" ]] { setglobal idx = $shExpr(' idx + 1 ') setglobal fp = $(ANON["${binds["${idx}"]}"]) _list $(@) _assoc! $(env) $(fp) $(r) break } else { _assoc! $(env) $(fp) $(1) shift setglobal idx = $shExpr(' idx + 1 ') } } } setglobal r = $(env) } # Find the environment with the key set and return the environment proc ENV_FIND { if _contains? $(1) $(ANON["${2}"]) { setglobal r = $(1) } else { local obj="$(ANON["${1}"])" eval local outer="\${$(obj)["__outer__"]}" if [[ "${outer}" && "${outer}" != "${__nil}" ]] { ENV_FIND $(outer) $(2) } else { setglobal r = '' } } } # Find the environment with the key set and return the value of the # key in that environment. If no environment contains the key then # return an error proc ENV_GET { ENV_FIND $(1) $(2) local env="$(r)" local key="$(ANON["${2}"])" if [[ "${r}" ]] { local obj="$(ANON["${env}"])" eval r="\${$(obj)["$(key)"]}" } else { _error "'$(key)' not found" } } proc ENV_SET { local key="$(ANON["${2}"])" _assoc! $(1) $(key) $(3) } }