aboutsummaryrefslogtreecommitdiff
path: root/bash/env.sh
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-04-02 22:23:37 -0500
committerJoel Martin <github@martintribe.org>2014-04-02 22:23:37 -0500
commitea81a8087bcd7953b083a2be9db447f75e7ebf56 (patch)
tree6cf47a2dbd55d42efc4a901eaabdec952f40ce89 /bash/env.sh
parent1617910ad342a55762f3ddabb975849d843cff85 (diff)
downloadmal-ea81a8087bcd7953b083a2be9db447f75e7ebf56.tar.gz
mal-ea81a8087bcd7953b083a2be9db447f75e7ebf56.zip
All: split types into types, env, printer, core.
- types: low-level mapping to the implementation language. - core: functions on types that are exposed directly to mal. - printer: implementation called by pr-str, str, prn, println. - env: the environment implementation - Also, unindent all TCO while loops so that the diff of step4 and step5 are minimized.
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