aboutsummaryrefslogtreecommitdiff
path: root/bash/env.sh
diff options
context:
space:
mode:
Diffstat (limited to 'bash/env.sh')
-rw-r--r--bash/env.sh78
1 files changed, 78 insertions, 0 deletions
diff --git a/bash/env.sh b/bash/env.sh
new file mode 100644
index 0000000..2eabe8b
--- /dev/null
+++ b/bash/env.sh
@@ -0,0 +1,78 @@
+#
+# mal (Make a Lisp) environment definition
+#
+
+if [ -z "${__mal_env_included__}" ]; then
+__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)
+ENV () {
+ r=
+ _hash_map
+ local env="${r}"
+ if [[ "${1}" ]]; then
+ outer="${1}"; shift
+ _assoc! "${env}" "__outer__" "${outer}"
+ else
+ _assoc! "${env}" "__outer__" "${__nil}"
+ fi
+ r="${env}"
+
+ if [[ "${1}" && "${@}" ]]; then
+ local binds=(${ANON["${1}"]}); shift
+ local idx=0
+ while [[ "${binds["${idx}"]}" ]]; do
+ local fp="${ANON["${binds["${idx}"]}"]}"
+ if [[ "${fp}" == "&" ]]; then
+ idx=$(( idx + 1 ))
+ fp="${ANON["${binds["${idx}"]}"]}"
+ _list "${@}"
+ _assoc! "${env}" "${fp}" "${r}"
+ break
+ else
+ _assoc! "${env}" "${fp}" "${1}"
+ shift
+ idx=$(( idx + 1 ))
+ fi
+ done
+ fi
+ r="${env}"
+}
+
+# Find the environment with the key set and return the environment
+ENV_FIND () {
+ if _contains? "${1}" "${2}"; then
+ r="${1}"
+ else
+ local obj="${ANON["${1}"]}"
+ eval local outer="\${${obj}["__outer__"]}"
+ if [[ "${outer}" && "${outer}" != "${__nil}" ]]; then
+ ENV_FIND "${outer}" "${2}"
+ else
+ r=
+ fi
+ fi
+}
+
+# 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
+ENV_GET () {
+ ENV_FIND "${1}" "${2}"
+ local env="${r}"
+ if [[ "${r}" ]]; then
+ local obj="${ANON["${env}"]}"
+ eval r="\${${obj}["${2}"]}"
+ else
+ _error "'${2}' not found"
+ fi
+}
+
+ENV_SET () {
+ _assoc! "${1}" "${2}" "${3}"
+}
+
+fi