# # 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 var env = $(r) if [[ "${1}" ]] { setglobal outer = $(1); shift _assoc! $(env) "__outer__" $(outer) } else { _assoc! $(env) "__outer__" $(__nil) } setglobal r = $(env) if [[ "${1}" && "${@}" ]] { var binds = '('${ANON["${1}"]}); shift var idx = '0' { var fp = $(ANON["${binds["${idx}"]}"]) if [[ "${fp}" == "&" ]] { set idx = $shExpr(' idx + 1 ') set fp = $(ANON["${binds["${idx}"]}"]) _list $(@) _assoc! $(env) $(fp) $(r) break } else { _assoc! $(env) $(fp) $(1) shift set 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 { var 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) var env = $(r) var key = $(ANON["${2}"]) if [[ "${r}" ]] { var obj = $(ANON["${env}"]) eval r="\${$(obj)["$(key)"]}" } else { _error "'$(key)' not found" } } proc ENV_SET { var key = $(ANON["${2}"]) _assoc! $(1) $(key) $(3) } }