aboutsummaryrefslogtreecommitdiff
path: root/bash
diff options
context:
space:
mode:
Diffstat (limited to 'bash')
-rw-r--r--bash/core.sh12
-rw-r--r--bash/env.sh10
-rw-r--r--bash/printer.sh26
-rw-r--r--bash/reader.sh3
-rwxr-xr-xbash/step3_env.sh20
-rwxr-xr-xbash/step4_if_fn_do.sh19
-rwxr-xr-xbash/step5_tco.sh19
-rwxr-xr-xbash/step6_file.sh22
-rwxr-xr-xbash/step7_quote.sh25
-rwxr-xr-xbash/step8_macros.sh36
-rwxr-xr-xbash/step9_try.sh44
-rwxr-xr-xbash/stepA_interop.sh45
-rw-r--r--bash/types.sh33
13 files changed, 194 insertions, 120 deletions
diff --git a/bash/core.sh b/bash/core.sh
index c8a0261..ca53c43 100644
--- a/bash/core.sh
+++ b/bash/core.sh
@@ -41,6 +41,11 @@ false? () { _false? "${1}" && r="${__true}" || r="${__false}"; }
symbol? () { _symbol? "${1}" && r="${__true}" || r="${__false}"; }
+# Keyword functions
+
+keyword? () { _keyword? "${1}" && r="${__true}" || r="${__false}"; }
+
+
# Number functions
number? () { _number? "${1}" && r="${__true}" || r="${__false}"; }
@@ -230,6 +235,10 @@ concat () {
nth () {
_nth "${1}" "${ANON["${2}"]}"
+ if [ -z "${r}" ]; then
+ _error "nth: index out of bounds"
+ return
+ fi
}
empty? () { _empty? "${1}" && r="${__true}" || r="${__false}"; }
@@ -316,7 +325,10 @@ declare -A core_ns=(
[nil?]=nil?
[true?]=true?
[false?]=false?
+ [symbol]=_symbol
[symbol?]=symbol?
+ [keyword]=_keyword
+ [keyword?]=keyword?
[pr-str]=pr_str
[str]=str
diff --git a/bash/env.sh b/bash/env.sh
index 2eabe8b..9595aa2 100644
--- a/bash/env.sh
+++ b/bash/env.sh
@@ -44,7 +44,7 @@ ENV () {
# Find the environment with the key set and return the environment
ENV_FIND () {
- if _contains? "${1}" "${2}"; then
+ if _contains? "${1}" "${ANON["${2}"]}"; then
r="${1}"
else
local obj="${ANON["${1}"]}"
@@ -63,16 +63,18 @@ ENV_FIND () {
ENV_GET () {
ENV_FIND "${1}" "${2}"
local env="${r}"
+ local key="${ANON["${2}"]}"
if [[ "${r}" ]]; then
local obj="${ANON["${env}"]}"
- eval r="\${${obj}["${2}"]}"
+ eval r="\${${obj}["${key}"]}"
else
- _error "'${2}' not found"
+ _error "'${key}' not found"
fi
}
ENV_SET () {
- _assoc! "${1}" "${2}" "${3}"
+ local key="${ANON["${2}"]}"
+ _assoc! "${1}" "${key}" "${3}"
}
fi
diff --git a/bash/printer.sh b/bash/printer.sh
index 911db17..0d23028 100644
--- a/bash/printer.sh
+++ b/bash/printer.sh
@@ -29,28 +29,42 @@ symbol_pr_str () {
r="${r//__STAR__/*}"
}
-string_pr_str () {
+keyword_pr_str () {
+ string_pr_str "${1}"
+}
+
+_raw_string_pr_str () {
+ local s="${1}"
local print_readably="${2}"
- if [ "${print_readably}" == "yes" ]; then
- local s="${ANON["${1}"]}"
+ if [[ "${s:0:1}" = "${__keyw}" ]]; then
+ r=":${s:1}"
+ elif [ "${print_readably}" == "yes" ]; then
s="${s//\\/\\\\}"
r="\"${s//\"/\\\"}\""
else
- r="${ANON["${1}"]}"
+ r="${s}"
fi
r="${r//__STAR__/$'*'}"
}
+string_pr_str () {
+ _raw_string_pr_str "${ANON["${1}"]}" "${2}"
+}
+
function_pr_str () { r="${ANON["${1}"]}"; }
+bash_pr_str () {
+ r="$(declare -f -p ${1})"
+}
+
hash_map_pr_str () {
local print_readably="${2}"
local res=""; local val=""
local hm="${ANON["${1}"]}"
eval local keys="\${!${hm}[@]}"
for key in ${keys}; do
- #res="${res} \"${ANON["${key}"]}\""
- res="${res} \"${key//__STAR__/$'*'}\""
+ _raw_string_pr_str "${key}" "${print_readably}"
+ res="${res} ${r}"
eval val="\${${hm}[\"${key}\"]}"
_pr_str "${val}" "${print_readably}"
res="${res} ${r}"
diff --git a/bash/reader.sh b/bash/reader.sh
index ee7e505..a00e7a1 100644
--- a/bash/reader.sh
+++ b/bash/reader.sh
@@ -15,6 +15,7 @@ READ_ATOM () {
\"*) token="${token:1:-1}"
token="${token//\\\"/\"}"
_string "${token}" ;;
+ :*) _keyword "${token:1}" ;;
nil) r="${__nil}" ;;
true) r="${__true}" ;;
false) r="${__false}" ;;
@@ -135,7 +136,7 @@ READ_STR () {
declare -a __reader_tokens
TOKENIZE "${*}" || return 1 # sets __reader_tokens
#set | grep ^__reader_tokens
- if [ -z "${__reader_tokens[k]}" ]; then
+ if [ -z "${__reader_tokens[0]}" ]; then
r=
return 1 # No tokens
fi
diff --git a/bash/step3_env.sh b/bash/step3_env.sh
index a837e00..d924b03 100755
--- a/bash/step3_env.sh
+++ b/bash/step3_env.sh
@@ -17,8 +17,7 @@ EVAL_AST () {
_obj_type "${ast}"; local ot="${r}"
case "${ot}" in
symbol)
- local val="${ANON["${ast}"]}"
- ENV_GET "${env}" "${val}"
+ ENV_GET "${env}" "${ast}"
return ;;
list)
_map_with_type _list EVAL "${ast}" "${env}" ;;
@@ -55,10 +54,9 @@ EVAL () {
_nth "${ast}" 1; local a1="${r}"
_nth "${ast}" 2; local a2="${r}"
case "${ANON["${a0}"]}" in
- def!) local k="${ANON["${a1}"]}"
- #echo "def! ${k} to ${a2} in ${env}"
- EVAL "${a2}" "${env}"
- ENV_SET "${env}" "${k}" "${r}"
+ def!) EVAL "${a2}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
+ ENV_SET "${env}" "${a1}" "${r}"
return ;;
let*) ENV "${env}"; local let_env="${r}"
local let_pairs=(${ANON["${a1}"]})
@@ -66,7 +64,7 @@ EVAL () {
#echo "let: [${let_pairs[*]}] for ${a2}"
while [[ "${let_pairs["${idx}"]}" ]]; do
EVAL "${let_pairs[$(( idx + 1))]}" "${let_env}"
- ENV_SET "${let_env}" "${ANON["${let_pairs[${idx}]}"]}" "${r}"
+ ENV_SET "${let_env}" "${let_pairs[${idx}]}" "${r}"
idx=$(( idx + 2))
done
EVAL "${a2}" "${let_env}"
@@ -107,10 +105,10 @@ minus () { r=$(( ${ANON["${1}"]} - ${ANON["${2}"]} )); _number "${r}"; }
multiply () { r=$(( ${ANON["${1}"]} * ${ANON["${2}"]} )); _number "${r}"; }
divide () { r=$(( ${ANON["${1}"]} / ${ANON["${2}"]} )); _number "${r}"; }
-ENV_SET "${REPL_ENV}" "+" plus
-ENV_SET "${REPL_ENV}" "-" minus
-ENV_SET "${REPL_ENV}" "__STAR__" multiply
-ENV_SET "${REPL_ENV}" "/" divide
+_symbol "+"; ENV_SET "${REPL_ENV}" "${r}" plus
+_symbol "-"; ENV_SET "${REPL_ENV}" "${r}" minus
+_symbol "__STAR__"; ENV_SET "${REPL_ENV}" "${r}" multiply
+_symbol "/"; ENV_SET "${REPL_ENV}" "${r}" divide
# repl loop
while true; do
diff --git a/bash/step4_if_fn_do.sh b/bash/step4_if_fn_do.sh
index 6fd7301..dd0db03 100755
--- a/bash/step4_if_fn_do.sh
+++ b/bash/step4_if_fn_do.sh
@@ -18,8 +18,7 @@ EVAL_AST () {
_obj_type "${ast}"; local ot="${r}"
case "${ot}" in
symbol)
- local val="${ANON["${ast}"]}"
- ENV_GET "${env}" "${val}"
+ ENV_GET "${env}" "${ast}"
return ;;
list)
_map_with_type _list EVAL "${ast}" "${env}" ;;
@@ -56,10 +55,9 @@ EVAL () {
_nth "${ast}" 1; local a1="${r}"
_nth "${ast}" 2; local a2="${r}"
case "${ANON["${a0}"]}" in
- def!) local k="${ANON["${a1}"]}"
- #echo "def! ${k} to ${a2} in ${env}"
- EVAL "${a2}" "${env}"
- ENV_SET "${env}" "${k}" "${r}"
+ def!) EVAL "${a2}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
+ ENV_SET "${env}" "${a1}" "${r}"
return ;;
let*) ENV "${env}"; local let_env="${r}"
local let_pairs=(${ANON["${a1}"]})
@@ -67,7 +65,7 @@ EVAL () {
#echo "let: [${let_pairs[*]}] for ${a2}"
while [[ "${let_pairs["${idx}"]}" ]]; do
EVAL "${let_pairs[$(( idx + 1))]}" "${let_env}"
- ENV_SET "${let_env}" "${ANON["${let_pairs[${idx}]}"]}" "${r}"
+ ENV_SET "${let_env}" "${let_pairs[${idx}]}" "${r}"
idx=$(( idx + 2))
done
EVAL "${a2}" "${let_env}"
@@ -78,6 +76,7 @@ EVAL () {
_last "${r}"
return ;;
if) EVAL "${a1}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
if [[ "${r}" == "${__false}" || "${r}" == "${__nil}" ]]; then
# eval false form
_nth "${ast}" 3; local a3="${r}"
@@ -126,7 +125,11 @@ REP () {
}
# core.sh: defined using bash
-_fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
+_fref () {
+ _symbol "${1}"; local sym="${r}"
+ _function "${2} \"\${@}\""
+ ENV_SET "${REPL_ENV}" "${sym}" "${r}"
+}
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
# core.mal: defined using the language itself
diff --git a/bash/step5_tco.sh b/bash/step5_tco.sh
index fc36b46..f282e44 100755
--- a/bash/step5_tco.sh
+++ b/bash/step5_tco.sh
@@ -18,8 +18,7 @@ EVAL_AST () {
_obj_type "${ast}"; local ot="${r}"
case "${ot}" in
symbol)
- local val="${ANON["${ast}"]}"
- ENV_GET "${env}" "${val}"
+ ENV_GET "${env}" "${ast}"
return ;;
list)
_map_with_type _list EVAL "${ast}" "${env}" ;;
@@ -57,10 +56,9 @@ EVAL () {
_nth "${ast}" 1; local a1="${r}"
_nth "${ast}" 2; local a2="${r}"
case "${ANON["${a0}"]}" in
- def!) local k="${ANON["${a1}"]}"
- #echo "def! ${k} to ${a2} in ${env}"
- EVAL "${a2}" "${env}"
- ENV_SET "${env}" "${k}" "${r}"
+ def!) EVAL "${a2}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
+ ENV_SET "${env}" "${a1}" "${r}"
return ;;
let*) ENV "${env}"; local let_env="${r}"
local let_pairs=(${ANON["${a1}"]})
@@ -68,7 +66,7 @@ EVAL () {
#echo "let: [${let_pairs[*]}] for ${a2}"
while [[ "${let_pairs["${idx}"]}" ]]; do
EVAL "${let_pairs[$(( idx + 1))]}" "${let_env}"
- ENV_SET "${let_env}" "${ANON["${let_pairs[${idx}]}"]}" "${r}"
+ ENV_SET "${let_env}" "${let_pairs[${idx}]}" "${r}"
idx=$(( idx + 2))
done
ast="${a2}"
@@ -84,6 +82,7 @@ EVAL () {
# Continue loop
;;
if) EVAL "${a1}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
if [[ "${r}" == "${__false}" || "${r}" == "${__nil}" ]]; then
# eval false form
_nth "${ast}" 3; local a3="${r}"
@@ -145,7 +144,11 @@ REP () {
}
# core.sh: defined using bash
-_fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
+_fref () {
+ _symbol "${1}"; local sym="${r}"
+ _function "${2} \"\${@}\""
+ ENV_SET "${REPL_ENV}" "${sym}" "${r}"
+}
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
# core.mal: defined using the language itself
diff --git a/bash/step6_file.sh b/bash/step6_file.sh
index e6ee571..c655853 100755
--- a/bash/step6_file.sh
+++ b/bash/step6_file.sh
@@ -18,8 +18,7 @@ EVAL_AST () {
_obj_type "${ast}"; local ot="${r}"
case "${ot}" in
symbol)
- local val="${ANON["${ast}"]}"
- ENV_GET "${env}" "${val}"
+ ENV_GET "${env}" "${ast}"
return ;;
list)
_map_with_type _list EVAL "${ast}" "${env}" ;;
@@ -57,10 +56,9 @@ EVAL () {
_nth "${ast}" 1; local a1="${r}"
_nth "${ast}" 2; local a2="${r}"
case "${ANON["${a0}"]}" in
- def!) local k="${ANON["${a1}"]}"
- #echo "def! ${k} to ${a2} in ${env}"
- EVAL "${a2}" "${env}"
- ENV_SET "${env}" "${k}" "${r}"
+ def!) EVAL "${a2}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
+ ENV_SET "${env}" "${a1}" "${r}"
return ;;
let*) ENV "${env}"; local let_env="${r}"
local let_pairs=(${ANON["${a1}"]})
@@ -68,7 +66,7 @@ EVAL () {
#echo "let: [${let_pairs[*]}] for ${a2}"
while [[ "${let_pairs["${idx}"]}" ]]; do
EVAL "${let_pairs[$(( idx + 1))]}" "${let_env}"
- ENV_SET "${let_env}" "${ANON["${let_pairs[${idx}]}"]}" "${r}"
+ ENV_SET "${let_env}" "${let_pairs[${idx}]}" "${r}"
idx=$(( idx + 2))
done
ast="${a2}"
@@ -84,6 +82,7 @@ EVAL () {
# Continue loop
;;
if) EVAL "${a1}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
if [[ "${r}" == "${__false}" || "${r}" == "${__nil}" ]]; then
# eval false form
_nth "${ast}" 3; local a3="${r}"
@@ -145,13 +144,18 @@ REP () {
}
# core.sh: defined using bash
-_fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
+_fref () {
+ _symbol "${1}"; local sym="${r}"
+ _function "${2} \"\${@}\""
+ ENV_SET "${REPL_ENV}" "${sym}" "${r}"
+}
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
_eval () { EVAL "${1}" "${REPL_ENV}"; }
_fref "eval" _eval
_list; argv="${r}"
for _arg in "${@:2}"; do _string "${_arg}"; _conj! "${argv}" "${r}"; done
-ENV_SET "${REPL_ENV}" "__STAR__ARGV__STAR__" "${argv}";
+_symbol "__STAR__ARGV__STAR__"
+ENV_SET "${REPL_ENV}" "${r}" "${argv}";
# core.mal: defined using the language itself
REP "(def! not (fn* (a) (if a false true)))"
diff --git a/bash/step7_quote.sh b/bash/step7_quote.sh
index d71e24b..2f2e67e 100755
--- a/bash/step7_quote.sh
+++ b/bash/step7_quote.sh
@@ -56,8 +56,7 @@ EVAL_AST () {
_obj_type "${ast}"; local ot="${r}"
case "${ot}" in
symbol)
- local val="${ANON["${ast}"]}"
- ENV_GET "${env}" "${val}"
+ ENV_GET "${env}" "${ast}"
return ;;
list)
_map_with_type _list EVAL "${ast}" "${env}" ;;
@@ -84,8 +83,7 @@ EVAL () {
r=
[[ "${__ERROR}" ]] && return 1
#_pr_str "${ast}"; echo "EVAL '${r} / ${env}'"
- _obj_type "${ast}"; local ot="${r}"
- if [[ "${ot}" != "list" ]]; then
+ if ! _list? "${ast}"; then
EVAL_AST "${ast}" "${env}"
return
fi
@@ -95,10 +93,9 @@ EVAL () {
_nth "${ast}" 1; local a1="${r}"
_nth "${ast}" 2; local a2="${r}"
case "${ANON["${a0}"]}" in
- def!) local k="${ANON["${a1}"]}"
- #echo "def! ${k} to ${a2} in ${env}"
- EVAL "${a2}" "${env}"
- ENV_SET "${env}" "${k}" "${r}"
+ def!) EVAL "${a2}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
+ ENV_SET "${env}" "${a1}" "${r}"
return ;;
let*) ENV "${env}"; local let_env="${r}"
local let_pairs=(${ANON["${a1}"]})
@@ -106,7 +103,7 @@ EVAL () {
#echo "let: [${let_pairs[*]}] for ${a2}"
while [[ "${let_pairs["${idx}"]}" ]]; do
EVAL "${let_pairs[$(( idx + 1))]}" "${let_env}"
- ENV_SET "${let_env}" "${ANON["${let_pairs[${idx}]}"]}" "${r}"
+ ENV_SET "${let_env}" "${let_pairs[${idx}]}" "${r}"
idx=$(( idx + 2))
done
ast="${a2}"
@@ -130,6 +127,7 @@ EVAL () {
# Continue loop
;;
if) EVAL "${a1}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
if [[ "${r}" == "${__false}" || "${r}" == "${__nil}" ]]; then
# eval false form
_nth "${ast}" 3; local a3="${r}"
@@ -191,13 +189,18 @@ REP () {
}
# core.sh: defined using bash
-_fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
+_fref () {
+ _symbol "${1}"; local sym="${r}"
+ _function "${2} \"\${@}\""
+ ENV_SET "${REPL_ENV}" "${sym}" "${r}"
+}
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
_eval () { EVAL "${1}" "${REPL_ENV}"; }
_fref "eval" _eval
_list; argv="${r}"
for _arg in "${@:2}"; do _string "${_arg}"; _conj! "${argv}" "${r}"; done
-ENV_SET "${REPL_ENV}" "__STAR__ARGV__STAR__" "${argv}";
+_symbol "__STAR__ARGV__STAR__"
+ENV_SET "${REPL_ENV}" "${r}" "${argv}";
# core.mal: defined using the language itself
REP "(def! not (fn* (a) (if a false true)))"
diff --git a/bash/step8_macros.sh b/bash/step8_macros.sh
index 3be3651..51d83bd 100755
--- a/bash/step8_macros.sh
+++ b/bash/step8_macros.sh
@@ -54,9 +54,11 @@ IS_MACRO_CALL () {
if ! _list? "${1}"; then return 1; fi
_nth "${1}" 0; local a0="${r}"
if _symbol? "${a0}"; then
- ENV_FIND "${2}" "${ANON["${a0}"]}_ismacro_"
+ ENV_FIND "${2}" "${a0}"
if [[ "${r}" ]]; then
- return 0
+ ENV_GET "${2}" "${a0}"
+ [ "${ANON["${r}_ismacro_"]}" ]
+ return $?
fi
fi
return 1
@@ -66,7 +68,7 @@ MACROEXPAND () {
local ast="${1}" env="${2}"
while IS_MACRO_CALL "${ast}" "${env}"; do
_nth "${ast}" 0; local a0="${r}"
- ENV_GET "${env}" "${ANON["${a0}"]}"; local mac="${ANON["${r}"]}"
+ ENV_GET "${env}" "${a0}"; local mac="${ANON["${r}"]}"
_rest "${ast}"
${mac%%@*} ${ANON["${r}"]}
ast="${r}"
@@ -81,8 +83,7 @@ EVAL_AST () {
_obj_type "${ast}"; local ot="${r}"
case "${ot}" in
symbol)
- local val="${ANON["${ast}"]}"
- ENV_GET "${env}" "${val}"
+ ENV_GET "${env}" "${ast}"
return ;;
list)
_map_with_type _list EVAL "${ast}" "${env}" ;;
@@ -122,10 +123,9 @@ EVAL () {
_nth "${ast}" 1; local a1="${r}"
_nth "${ast}" 2; local a2="${r}"
case "${ANON["${a0}"]}" in
- def!) local k="${ANON["${a1}"]}"
- #echo "def! ${k} to ${a2} in ${env}"
- EVAL "${a2}" "${env}"
- ENV_SET "${env}" "${k}" "${r}"
+ def!) EVAL "${a2}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
+ ENV_SET "${env}" "${a1}" "${r}"
return ;;
let*) ENV "${env}"; local let_env="${r}"
local let_pairs=(${ANON["${a1}"]})
@@ -133,7 +133,7 @@ EVAL () {
#echo "let: [${let_pairs[*]}] for ${a2}"
while [[ "${let_pairs["${idx}"]}" ]]; do
EVAL "${let_pairs[$(( idx + 1))]}" "${let_env}"
- ENV_SET "${let_env}" "${ANON["${let_pairs[${idx}]}"]}" "${r}"
+ ENV_SET "${let_env}" "${let_pairs[${idx}]}" "${r}"
idx=$(( idx + 2))
done
ast="${a2}"
@@ -149,10 +149,10 @@ EVAL () {
# Continue loop
;;
defmacro!)
- local k="${ANON["${a1}"]}"
EVAL "${a2}" "${env}"
- ENV_SET "${env}" "${k}" "${r}"
- ENV_SET "${env}" "${k}_ismacro_" "yes"
+ [[ "${__ERROR}" ]] && return 1
+ ANON["${r}_ismacro_"]="yes"
+ ENV_SET "${env}" "${a1}" "${r}"
return ;;
macroexpand)
MACROEXPAND "${a1}" "${env}"
@@ -166,6 +166,7 @@ EVAL () {
# Continue loop
;;
if) EVAL "${a1}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
if [[ "${r}" == "${__false}" || "${r}" == "${__nil}" ]]; then
# eval false form
_nth "${ast}" 3; local a3="${r}"
@@ -227,13 +228,18 @@ REP () {
}
# core.sh: defined using bash
-_fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
+_fref () {
+ _symbol "${1}"; local sym="${r}"
+ _function "${2} \"\${@}\""
+ ENV_SET "${REPL_ENV}" "${sym}" "${r}"
+}
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
_eval () { EVAL "${1}" "${REPL_ENV}"; }
_fref "eval" _eval
_list; argv="${r}"
for _arg in "${@:2}"; do _string "${_arg}"; _conj! "${argv}" "${r}"; done
-ENV_SET "${REPL_ENV}" "__STAR__ARGV__STAR__" "${argv}";
+_symbol "__STAR__ARGV__STAR__"
+ENV_SET "${REPL_ENV}" "${r}" "${argv}";
# core.mal: defined using the language itself
REP "(def! not (fn* (a) (if a false true)))"
diff --git a/bash/step9_try.sh b/bash/step9_try.sh
index db0b5a7..85698b4 100755
--- a/bash/step9_try.sh
+++ b/bash/step9_try.sh
@@ -54,9 +54,11 @@ IS_MACRO_CALL () {
if ! _list? "${1}"; then return 1; fi
_nth "${1}" 0; local a0="${r}"
if _symbol? "${a0}"; then
- ENV_FIND "${2}" "${ANON["${a0}"]}_ismacro_"
+ ENV_FIND "${2}" "${a0}"
if [[ "${r}" ]]; then
- return 0
+ ENV_GET "${2}" "${a0}"
+ [ "${ANON["${r}_ismacro_"]}" ]
+ return $?
fi
fi
return 1
@@ -66,7 +68,7 @@ MACROEXPAND () {
local ast="${1}" env="${2}"
while IS_MACRO_CALL "${ast}" "${env}"; do
_nth "${ast}" 0; local a0="${r}"
- ENV_GET "${env}" "${ANON["${a0}"]}"; local mac="${ANON["${r}"]}"
+ ENV_GET "${env}" "${a0}"; local mac="${ANON["${r}"]}"
_rest "${ast}"
${mac%%@*} ${ANON["${r}"]}
ast="${r}"
@@ -81,8 +83,7 @@ EVAL_AST () {
_obj_type "${ast}"; local ot="${r}"
case "${ot}" in
symbol)
- local val="${ANON["${ast}"]}"
- ENV_GET "${env}" "${val}"
+ ENV_GET "${env}" "${ast}"
return ;;
list)
_map_with_type _list EVAL "${ast}" "${env}" ;;
@@ -122,10 +123,9 @@ EVAL () {
_nth "${ast}" 1; local a1="${r}"
_nth "${ast}" 2; local a2="${r}"
case "${ANON["${a0}"]}" in
- def!) local k="${ANON["${a1}"]}"
- #echo "def! ${k} to ${a2} in ${env}"
- EVAL "${a2}" "${env}"
- ENV_SET "${env}" "${k}" "${r}"
+ def!) EVAL "${a2}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
+ ENV_SET "${env}" "${a1}" "${r}"
return ;;
let*) ENV "${env}"; local let_env="${r}"
local let_pairs=(${ANON["${a1}"]})
@@ -133,7 +133,7 @@ EVAL () {
#echo "let: [${let_pairs[*]}] for ${a2}"
while [[ "${let_pairs["${idx}"]}" ]]; do
EVAL "${let_pairs[$(( idx + 1))]}" "${let_env}"
- ENV_SET "${let_env}" "${ANON["${let_pairs[${idx}]}"]}" "${r}"
+ ENV_SET "${let_env}" "${let_pairs[${idx}]}" "${r}"
idx=$(( idx + 2))
done
ast="${a2}"
@@ -149,16 +149,15 @@ EVAL () {
# Continue loop
;;
defmacro!)
- local k="${ANON["${a1}"]}"
EVAL "${a2}" "${env}"
- ENV_SET "${env}" "${k}" "${r}"
- ENV_SET "${env}" "${k}_ismacro_" "yes"
+ [[ "${__ERROR}" ]] && return 1
+ ANON["${r}_ismacro_"]="yes"
+ ENV_SET "${env}" "${a1}" "${r}"
return ;;
macroexpand)
MACROEXPAND "${a1}" "${env}"
return ;;
- try*) MACROEXPAND "${a1}" "${env}"
- EVAL "${r}" "${env}"
+ try*) EVAL "${a1}" "${env}"
[[ -z "${__ERROR}" ]] && return
_nth "${a2}" 0; local a20="${r}"
if [ "${ANON["${a20}"]}" == "catch__STAR__" ]; then
@@ -168,8 +167,7 @@ EVAL () {
ENV "${env}" "${binds}" "${__ERROR}"
local try_env="${r}"
__ERROR=
- MACROEXPAND "${a22}" "${try_env}"
- EVAL "${r}" "${try_env}"
+ EVAL "${a22}" "${try_env}"
fi # if no catch* clause, just propagate __ERROR
return ;;
do) _count "${ast}"
@@ -181,6 +179,7 @@ EVAL () {
# Continue loop
;;
if) EVAL "${a1}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
if [[ "${r}" == "${__false}" || "${r}" == "${__nil}" ]]; then
# eval false form
_nth "${ast}" 3; local a3="${r}"
@@ -242,16 +241,20 @@ REP () {
}
# core.sh: defined using bash
-_fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
+_fref () {
+ _symbol "${1}"; local sym="${r}"
+ _function "${2} \"\${@}\""
+ ENV_SET "${REPL_ENV}" "${sym}" "${r}"
+}
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
_eval () { EVAL "${1}" "${REPL_ENV}"; }
_fref "eval" _eval
_list; argv="${r}"
for _arg in "${@:2}"; do _string "${_arg}"; _conj! "${argv}" "${r}"; done
-ENV_SET "${REPL_ENV}" "__STAR__ARGV__STAR__" "${argv}";
+_symbol "__STAR__ARGV__STAR__"
+ENV_SET "${REPL_ENV}" "${r}" "${argv}";
# core.mal: defined using the language itself
-REP "(def! *host-language* \"bash\")"
REP "(def! not (fn* (a) (if a false true)))"
REP "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"
REP "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))"
@@ -264,7 +267,6 @@ if [[ "${1}" ]]; then
fi
# repl loop
-REP "(println (str \"Mal [\" *host-language* \"]\"))"
while true; do
READLINE "user> " || exit "$?"
[[ "${r}" ]] && REP "${r}" && echo "${r}"
diff --git a/bash/stepA_interop.sh b/bash/stepA_interop.sh
index 2422643..9a760e4 100755
--- a/bash/stepA_interop.sh
+++ b/bash/stepA_interop.sh
@@ -54,9 +54,11 @@ IS_MACRO_CALL () {
if ! _list? "${1}"; then return 1; fi
_nth "${1}" 0; local a0="${r}"
if _symbol? "${a0}"; then
- ENV_FIND "${2}" "${ANON["${a0}"]}_ismacro_"
+ ENV_FIND "${2}" "${a0}"
if [[ "${r}" ]]; then
- return 0
+ ENV_GET "${2}" "${a0}"
+ [ "${ANON["${r}_ismacro_"]}" ]
+ return $?
fi
fi
return 1
@@ -66,7 +68,7 @@ MACROEXPAND () {
local ast="${1}" env="${2}"
while IS_MACRO_CALL "${ast}" "${env}"; do
_nth "${ast}" 0; local a0="${r}"
- ENV_GET "${env}" "${ANON["${a0}"]}"; local mac="${ANON["${r}"]}"
+ ENV_GET "${env}" "${a0}"; local mac="${ANON["${r}"]}"
_rest "${ast}"
${mac%%@*} ${ANON["${r}"]}
ast="${r}"
@@ -81,8 +83,7 @@ EVAL_AST () {
_obj_type "${ast}"; local ot="${r}"
case "${ot}" in
symbol)
- local val="${ANON["${ast}"]}"
- ENV_GET "${env}" "${val}"
+ ENV_GET "${env}" "${ast}"
return ;;
list)
_map_with_type _list EVAL "${ast}" "${env}" ;;
@@ -122,10 +123,9 @@ EVAL () {
_nth "${ast}" 1; local a1="${r}"
_nth "${ast}" 2; local a2="${r}"
case "${ANON["${a0}"]}" in
- def!) local k="${ANON["${a1}"]}"
- #echo "def! ${k} to ${a2} in ${env}"
- EVAL "${a2}" "${env}"
- ENV_SET "${env}" "${k}" "${r}"
+ def!) EVAL "${a2}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
+ ENV_SET "${env}" "${a1}" "${r}"
return ;;
let*) ENV "${env}"; local let_env="${r}"
local let_pairs=(${ANON["${a1}"]})
@@ -133,7 +133,7 @@ EVAL () {
#echo "let: [${let_pairs[*]}] for ${a2}"
while [[ "${let_pairs["${idx}"]}" ]]; do
EVAL "${let_pairs[$(( idx + 1))]}" "${let_env}"
- ENV_SET "${let_env}" "${ANON["${let_pairs[${idx}]}"]}" "${r}"
+ ENV_SET "${let_env}" "${let_pairs[${idx}]}" "${r}"
idx=$(( idx + 2))
done
ast="${a2}"
@@ -149,16 +149,15 @@ EVAL () {
# Continue loop
;;
defmacro!)
- local k="${ANON["${a1}"]}"
EVAL "${a2}" "${env}"
- ENV_SET "${env}" "${k}" "${r}"
- ENV_SET "${env}" "${k}_ismacro_" "yes"
+ [[ "${__ERROR}" ]] && return 1
+ ANON["${r}_ismacro_"]="yes"
+ ENV_SET "${env}" "${a1}" "${r}"
return ;;
macroexpand)
MACROEXPAND "${a1}" "${env}"
return ;;
- sh*) MACROEXPAND "${a1}" "${env}"
- EVAL "${r}" "${env}"
+ sh*) EVAL "${a1}" "${env}"
local output=""
local line=""
while read line; do
@@ -166,8 +165,7 @@ EVAL () {
done < <(eval ${ANON["${r}"]})
_string "${output%\\n}"
return ;;
- try*) MACROEXPAND "${a1}" "${env}"
- EVAL "${r}" "${env}"
+ try*) EVAL "${a1}" "${env}"
[[ -z "${__ERROR}" ]] && return
_nth "${a2}" 0; local a20="${r}"
if [ "${ANON["${a20}"]}" == "catch__STAR__" ]; then
@@ -177,8 +175,7 @@ EVAL () {
ENV "${env}" "${binds}" "${__ERROR}"
local try_env="${r}"
__ERROR=
- MACROEXPAND "${a22}" "${try_env}"
- EVAL "${r}" "${try_env}"
+ EVAL "${a22}" "${try_env}"
fi # if no catch* clause, just propagate __ERROR
return ;;
do) _count "${ast}"
@@ -190,6 +187,7 @@ EVAL () {
# Continue loop
;;
if) EVAL "${a1}" "${env}"
+ [[ "${__ERROR}" ]] && return 1
if [[ "${r}" == "${__false}" || "${r}" == "${__nil}" ]]; then
# eval false form
_nth "${ast}" 3; local a3="${r}"
@@ -251,13 +249,18 @@ REP () {
}
# core.sh: defined using bash
-_fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
+_fref () {
+ _symbol "${1}"; local sym="${r}"
+ _function "${2} \"\${@}\""
+ ENV_SET "${REPL_ENV}" "${sym}" "${r}"
+}
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
_eval () { EVAL "${1}" "${REPL_ENV}"; }
_fref "eval" _eval
_list; argv="${r}"
for _arg in "${@:2}"; do _string "${_arg}"; _conj! "${argv}" "${r}"; done
-ENV_SET "${REPL_ENV}" "__STAR__ARGV__STAR__" "${argv}";
+_symbol "__STAR__ARGV__STAR__"
+ENV_SET "${REPL_ENV}" "${r}" "${argv}";
# core.mal: defined using the language itself
REP "(def! *host-language* \"bash\")"
diff --git a/bash/types.sh b/bash/types.sh
index 5cdc14a..4c2c824 100644
--- a/bash/types.sh
+++ b/bash/types.sh
@@ -8,6 +8,7 @@ __mal_types_included=true
declare -A ANON
__obj_magic=__5bal7
+__keyw=$(echo -en "\u029e")
__obj_hash_code=${__obj_hash_code:-0}
__new_obj_hash_code () {
@@ -50,7 +51,9 @@ _obj_type () {
list) r="list" ;;
numb) r="number" ;;
func) r="function" ;;
- strn) r="string" ;;
+ strn)
+ local s="${ANON["${1}"]}"
+ [[ "${s:0:1}" = "${__keyw}" ]] && r="keyword" || r="string" ;;
_nil) r="nil" ;;
true) r="true" ;;
fals) r="false" ;;
@@ -71,7 +74,7 @@ _equal? () {
fi
fi
case "${ot1}" in
- string|symbol|number)
+ string|symbol|keyword|number)
[[ "${ANON["${1}"]}" == "${ANON["${2}"]}" ]] ;;
list|vector|hash_map)
_count "${1}"; local sz1="${r}"
@@ -109,6 +112,22 @@ _symbol () {
_symbol? () { [[ ${1} =~ ^symb_ ]]; }
+# Keywords
+
+_keyword () {
+ local k="${1}"
+ __new_obj_hash_code
+ r="strn_${r}"
+ [[ "${1:1:1}" = "${__keyw}" ]] || k="${__keyw}${1}"
+ ANON["${r}"]="${k//\*/__STAR__}"
+}
+_keyword? () {
+ [[ ${1} =~ ^strn_ ]] || return 1
+ local s="${ANON["${1}"]}"
+ [[ "${s:0:1}" = "${__keyw}" ]]
+}
+
+
# Numbers
_number () {
@@ -245,7 +264,7 @@ _sequential? () {
_nth () {
local temp=(${ANON["${1}"]})
- r=${temp[${2}]}
+ r="${temp[${2}]}"
}
_first () {
@@ -285,8 +304,12 @@ _conj! () {
_count () {
- local temp=(${ANON["${1}"]})
- r=${#temp[*]}
+ if _nil? "${1}"; then
+ r="0"
+ else
+ local temp=(${ANON["${1}"]})
+ r=${#temp[*]}
+ fi
}
# Slice a sequence object $1 starting at $2 of length $3