aboutsummaryrefslogtreecommitdiff
path: root/bash
diff options
context:
space:
mode:
Diffstat (limited to 'bash')
-rw-r--r--bash/core.sh52
-rwxr-xr-xbash/step2_eval.sh22
-rwxr-xr-xbash/step3_env.sh25
-rwxr-xr-xbash/step4_if_fn_do.sh21
-rwxr-xr-xbash/step5_tco.sh19
-rwxr-xr-xbash/step6_file.sh29
-rwxr-xr-xbash/step7_quote.sh31
-rwxr-xr-xbash/step8_macros.sh35
-rwxr-xr-xbash/step9_interop.sh35
-rwxr-xr-xbash/stepA_more.sh39
-rw-r--r--bash/types.sh29
11 files changed, 154 insertions, 183 deletions
diff --git a/bash/core.sh b/bash/core.sh
index d5750e6..e0cba38 100644
--- a/bash/core.sh
+++ b/bash/core.sh
@@ -6,6 +6,7 @@ if [ -z "${__mal_core_included__}" ]; then
__mal_core_included=true
source $(dirname $0)/types.sh
+source $(dirname $0)/reader.sh
source $(dirname $0)/printer.sh
# Exceptions/Errors
@@ -87,6 +88,21 @@ println () {
r="${__nil}";
}
+readline () {
+ READLINE "${ANON["${1}"]}" && _string "${r}" || r="${__nil}"
+}
+
+read_string () {
+ READ_STR "${ANON["${1}"]}"
+}
+
+slurp () {
+ local lines
+ mapfile lines < "${ANON["${1}"]}"
+ local text="${lines[*]}"; text=${text//$'\n' /$'\n'}
+ _string "${text}"
+}
+
# Function functions
function? () { _function? "${1}" && r="${__true}" || r="${__false}"; }
@@ -155,11 +171,6 @@ get () {
[[ "${r}" ]] || r="${__nil}"
}
-_contains? () {
- local obj="${ANON["${1}"]}"
- #echo "_contains? ${1} ${2} -> \${${obj}[\"${2}\"]+isset}"
- eval [[ "\${${obj}[\"${2}\"]+isset}" ]]
-}
contains? () { _contains? "${1}" "${ANON["${2}"]}" && r="${__true}" || r="${__false}"; }
keys () {
@@ -215,29 +226,6 @@ nth () {
_nth "${1}" "${ANON["${2}"]}"
}
-first () {
- local temp="${ANON["${1}"]}"
- r="${temp%% *}"
- [ "${r}" ] || r="${__nil}"
-}
-
-# Creates a new vector/list of the everything after but the first
-# element
-rest () {
- local temp="${ANON["${1}"]}"
- _list
- if [[ "${temp#* }" == "${temp}" ]]; then
- ANON["${r}"]=
- else
- ANON["${r}"]="${temp#* }"
- fi
-}
-
-last () {
- local temp="${ANON["${1}"]}"
- r="${temp##* }"
-}
-
empty? () { _empty? "${1}" && r="${__true}" || r="${__false}"; }
count () {
@@ -323,10 +311,14 @@ declare -A core_ns=(
[true?]=true?
[false?]=false?
[symbol?]=symbol?
+
[pr-str]=pr_str
[str]=str
[prn]=prn
[println]=println
+ [readline]=readline
+ [read-string]=read_string
+ [slurp]=slurp
[<]=num_lt
[<=]=num_lte
[>]=num_gt
@@ -353,8 +345,8 @@ declare -A core_ns=(
[cons]=cons
[concat]=concat
[nth]=nth
- [first]=first
- [rest]=rest
+ [first]=_first
+ [rest]=_rest
[empty?]=empty?
[count]=count
[conj]=conj
diff --git a/bash/step2_eval.sh b/bash/step2_eval.sh
index 0f03a79..4572223 100755
--- a/bash/step2_eval.sh
+++ b/bash/step2_eval.sh
@@ -4,11 +4,10 @@ INTERACTIVE=${INTERACTIVE-yes}
source $(dirname $0)/reader.sh
source $(dirname $0)/printer.sh
-source $(dirname $0)/core.sh
# READ: read and parse input
READ () {
- READLINE
+ [ "${1}" ] && r="${1}" || READLINE
READ_STR "${r}"
}
@@ -56,8 +55,8 @@ EVAL () {
EVAL_AST "${ast}" "${env}"
[[ "${__ERROR}" ]] && return 1
local el="${r}"
- first "${el}"; local f="${r}"
- rest "${el}"; local args="${ANON["${r}"]}"
+ _first "${el}"; local f="${r}"
+ _rest "${el}"; local args="${ANON["${r}"]}"
#echo "invoke: ${f} ${args}"
eval ${f} ${args}
}
@@ -76,15 +75,20 @@ PRINT () {
# REPL: read, eval, print, loop
declare -A REPL_ENV
REP () {
- READ_STR "${1}"
+ READ "${1}" || return 1
EVAL "${r}" REPL_ENV
PRINT "${r}"
}
-REPL_ENV["+"]=num_plus
-REPL_ENV["-"]=num_minus
-REPL_ENV["__STAR__"]=num_multiply
-REPL_ENV["/"]=num_divide
+plus () { r=$(( ${ANON["${1}"]} + ${ANON["${2}"]} )); _number "${r}"; }
+minus () { r=$(( ${ANON["${1}"]} - ${ANON["${2}"]} )); _number "${r}"; }
+multiply () { r=$(( ${ANON["${1}"]} * ${ANON["${2}"]} )); _number "${r}"; }
+divide () { r=$(( ${ANON["${1}"]} / ${ANON["${2}"]} )); _number "${r}"; }
+
+REPL_ENV["+"]=plus
+REPL_ENV["-"]=minus
+REPL_ENV["__STAR__"]=multiply
+REPL_ENV["/"]=divide
if [[ -n "${INTERACTIVE}" ]]; then
while true; do
diff --git a/bash/step3_env.sh b/bash/step3_env.sh
index 28106ee..f7a9e42 100755
--- a/bash/step3_env.sh
+++ b/bash/step3_env.sh
@@ -4,12 +4,11 @@ INTERACTIVE=${INTERACTIVE-yes}
source $(dirname $0)/reader.sh
source $(dirname $0)/printer.sh
-source $(dirname $0)/core.sh
source $(dirname $0)/env.sh
# READ: read and parse input
READ () {
- READLINE
+ [ "${1}" ] && r="${1}" || READLINE
READ_STR "${r}"
}
@@ -77,8 +76,8 @@ EVAL () {
*) EVAL_AST "${ast}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
local el="${r}"
- first "${el}"; local f="${r}"
- rest "${el}"; local args="${ANON["${r}"]}"
+ _first "${el}"; local f="${r}"
+ _rest "${el}"; local args="${ANON["${r}"]}"
#echo "invoke: ${f} ${args}"
eval ${f} ${args}
return ;;
@@ -100,16 +99,20 @@ PRINT () {
ENV; REPL_ENV="${r}"
REP () {
r=
- READ_STR "${1}"
- EVAL "${r}" ${REPL_ENV}
+ READ "${1}" || return 1
+ EVAL "${r}" "${REPL_ENV}"
PRINT "${r}"
}
-_ref () { ENV_SET "${REPL_ENV}" "${1}" "${2}"; }
-_ref "+" num_plus
-_ref "-" num_minus
-_ref "__STAR__" num_multiply
-_ref "/" num_divide
+plus () { r=$(( ${ANON["${1}"]} + ${ANON["${2}"]} )); _number "${r}"; }
+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
if [[ -n "${INTERACTIVE}" ]]; then
while true; do
diff --git a/bash/step4_if_fn_do.sh b/bash/step4_if_fn_do.sh
index d22ade6..a1b27ed 100755
--- a/bash/step4_if_fn_do.sh
+++ b/bash/step4_if_fn_do.sh
@@ -4,12 +4,12 @@ INTERACTIVE=${INTERACTIVE-yes}
source $(dirname $0)/reader.sh
source $(dirname $0)/printer.sh
-source $(dirname $0)/core.sh
source $(dirname $0)/env.sh
+source $(dirname $0)/core.sh
# READ: read and parse input
READ () {
- READLINE
+ [ "${1}" ] && r="${1}" || READLINE
READ_STR "${r}"
}
@@ -74,10 +74,10 @@ EVAL () {
done
EVAL "${a2}" "${let_env}"
return ;;
- do) rest "${ast}"
+ do) _rest "${ast}"
EVAL_AST "${r}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
- last "${r}"
+ _last "${r}"
return ;;
if) EVAL "${a1}" "${env}"
if [[ "${r}" == "${__false}" || "${r}" == "${__nil}" ]]; then
@@ -99,8 +99,8 @@ EVAL () {
*) EVAL_AST "${ast}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
local el="${r}"
- first "${el}"; local f="${ANON["${r}"]}"
- rest "${el}"; local args="${ANON["${r}"]}"
+ _first "${el}"; local f="${ANON["${r}"]}"
+ _rest "${el}"; local args="${ANON["${r}"]}"
#echo "invoke: ${f} ${args}"
eval ${f} ${args}
return ;;
@@ -122,17 +122,16 @@ PRINT () {
ENV; REPL_ENV="${r}"
REP () {
r=
- READ_STR "${1}"
- EVAL "${r}" ${REPL_ENV}
+ READ "${1}" || return 1
+ EVAL "${r}" "${REPL_ENV}"
PRINT "${r}"
}
+# core.sh: defined using bash
_fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
-
-# Import types functions
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
-# Defined using the language itself
+# core.mal: defined using the language itself
REP "(def! not (fn* (a) (if a false true)))"
if [[ -n "${INTERACTIVE}" ]]; then
diff --git a/bash/step5_tco.sh b/bash/step5_tco.sh
index 2d81d84..62446a7 100755
--- a/bash/step5_tco.sh
+++ b/bash/step5_tco.sh
@@ -4,12 +4,12 @@ INTERACTIVE=${INTERACTIVE-yes}
source $(dirname $0)/reader.sh
source $(dirname $0)/printer.sh
-source $(dirname $0)/core.sh
source $(dirname $0)/env.sh
+source $(dirname $0)/core.sh
# READ: read and parse input
READ () {
- READLINE
+ [ "${1}" ] && r="${1}" || READLINE
READ_STR "${r}"
}
@@ -79,7 +79,7 @@ EVAL () {
_slice "${ast}" 1 $(( ${r} - 2 ))
EVAL_AST "${r}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
- last "${ast}"
+ _last "${ast}"
ast="${r}"
# Continue loop
;;
@@ -106,8 +106,8 @@ EVAL () {
*) EVAL_AST "${ast}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
local el="${r}"
- first "${el}"; local f="${ANON["${r}"]}"
- rest "${el}"; local args="${ANON["${r}"]}"
+ _first "${el}"; local f="${ANON["${r}"]}"
+ _rest "${el}"; local args="${ANON["${r}"]}"
#echo "invoke: [${f}] ${args}"
if [[ "${f//@/ }" != "${f}" ]]; then
set -- ${f//@/ }
@@ -139,17 +139,16 @@ PRINT () {
ENV; REPL_ENV="${r}"
REP () {
r=
- READ_STR "${1}"
- EVAL "${r}" ${REPL_ENV}
+ READ "${1}" || return 1
+ EVAL "${r}" "${REPL_ENV}"
PRINT "${r}"
}
+# core.sh: defined using bash
_fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
-
-# Import types functions
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
-# Defined using the language itself
+# core.mal: defined using the language itself
REP "(def! not (fn* (a) (if a false true)))"
if [[ -n "${INTERACTIVE}" ]]; then
diff --git a/bash/step6_file.sh b/bash/step6_file.sh
index 1ebba64..b2a3dc8 100755
--- a/bash/step6_file.sh
+++ b/bash/step6_file.sh
@@ -4,12 +4,12 @@ INTERACTIVE=${INTERACTIVE-yes}
source $(dirname $0)/reader.sh
source $(dirname $0)/printer.sh
-source $(dirname $0)/core.sh
source $(dirname $0)/env.sh
+source $(dirname $0)/core.sh
# READ: read and parse input
READ () {
- READLINE
+ [ "${1}" ] && r="${1}" || READLINE
READ_STR "${r}"
}
@@ -79,7 +79,7 @@ EVAL () {
_slice "${ast}" 1 $(( ${r} - 2 ))
EVAL_AST "${r}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
- last "${ast}"
+ _last "${ast}"
ast="${r}"
# Continue loop
;;
@@ -106,8 +106,8 @@ EVAL () {
*) EVAL_AST "${ast}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
local el="${r}"
- first "${el}"; local f="${ANON["${r}"]}"
- rest "${el}"; local args="${ANON["${r}"]}"
+ _first "${el}"; local f="${ANON["${r}"]}"
+ _rest "${el}"; local args="${ANON["${r}"]}"
#echo "invoke: [${f}] ${args}"
if [[ "${f//@/ }" != "${f}" ]]; then
set -- ${f//@/ }
@@ -139,29 +139,18 @@ PRINT () {
ENV; REPL_ENV="${r}"
REP () {
r=
- READ_STR "${1}"
- EVAL "${r}" ${REPL_ENV}
+ READ "${1}" || return 1
+ EVAL "${r}" "${REPL_ENV}"
PRINT "${r}"
}
+# core.sh: defined using bash
_fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
-
-# Import types functions
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
-
-read_string () { READ_STR "${ANON["${1}"]}"; }
-_fref "read-string" read_string
_eval () { EVAL "${1}" "${REPL_ENV}"; }
_fref "eval" _eval
-slurp () {
- local lines
- mapfile lines < "${ANON["${1}"]}"
- local text="${lines[*]}"; text=${text//$'\n' /$'\n'}
- _string "${text}"
-}
-_fref "slurp" slurp
-# Defined using the language itself
+# core.mal: defined using the language itself
REP "(def! not (fn* (a) (if a false true)))"
REP "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"
diff --git a/bash/step7_quote.sh b/bash/step7_quote.sh
index 5aa2991..b541d67 100755
--- a/bash/step7_quote.sh
+++ b/bash/step7_quote.sh
@@ -4,12 +4,12 @@ INTERACTIVE=${INTERACTIVE-yes}
source $(dirname $0)/reader.sh
source $(dirname $0)/printer.sh
-source $(dirname $0)/core.sh
source $(dirname $0)/env.sh
+source $(dirname $0)/core.sh
# READ: read and parse input
READ () {
- READLINE
+ [ "${1}" ] && r="${1}" || READLINE
READ_STR "${r}"
}
@@ -36,7 +36,7 @@ QUASIQUOTE () {
if [[ "${ANON["${a00}"]}" == "splice-unquote" ]]; then
_symbol concat; local a="${r}"
_nth "${a0}" 1; local b="${r}"
- rest "${1}"
+ _rest "${1}"
QUASIQUOTE "${r}"; local c="${r}"
_list "${a}" "${b}" "${c}"
return
@@ -45,7 +45,7 @@ QUASIQUOTE () {
fi
_symbol cons; local a="${r}"
QUASIQUOTE "${a0}"; local b="${r}"
- rest "${1}"
+ _rest "${1}"
QUASIQUOTE "${r}"; local c="${r}"
_list "${a}" "${b}" "${c}"
return
@@ -124,7 +124,7 @@ EVAL () {
_slice "${ast}" 1 $(( ${r} - 2 ))
EVAL_AST "${r}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
- last "${ast}"
+ _last "${ast}"
ast="${r}"
# Continue loop
;;
@@ -151,8 +151,8 @@ EVAL () {
*) EVAL_AST "${ast}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
local el="${r}"
- first "${el}"; local f="${ANON["${r}"]}"
- rest "${el}"; local args="${ANON["${r}"]}"
+ _first "${el}"; local f="${ANON["${r}"]}"
+ _rest "${el}"; local args="${ANON["${r}"]}"
#echo "invoke: [${f}] ${args}"
if [[ "${f//@/ }" != "${f}" ]]; then
set -- ${f//@/ }
@@ -184,29 +184,18 @@ PRINT () {
ENV; REPL_ENV="${r}"
REP () {
r=
- READ_STR "${1}"
+ READ "${1}" || return 1
EVAL "${r}" "${REPL_ENV}"
PRINT "${r}"
}
+# core.sh: defined using bash
_fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
-
-# Import types functions
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
-
-read_string () { READ_STR "${ANON["${1}"]}"; }
-_fref "read-string" read_string
_eval () { EVAL "${1}" "${REPL_ENV}"; }
_fref "eval" _eval
-slurp () {
- local lines
- mapfile lines < "${ANON["${1}"]}"
- local text="${lines[*]}"; text=${text//$'\n' /$'\n'}
- _string "${text}"
-}
-_fref "slurp" slurp
-# Defined using the language itself
+# core.mal: defined using the language itself
REP "(def! not (fn* (a) (if a false true)))"
REP "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"
diff --git a/bash/step8_macros.sh b/bash/step8_macros.sh
index a32e7f9..0e58404 100755
--- a/bash/step8_macros.sh
+++ b/bash/step8_macros.sh
@@ -4,12 +4,12 @@ INTERACTIVE=${INTERACTIVE-yes}
source $(dirname $0)/reader.sh
source $(dirname $0)/printer.sh
-source $(dirname $0)/core.sh
source $(dirname $0)/env.sh
+source $(dirname $0)/core.sh
# READ: read and parse input
READ () {
- READLINE
+ [ "${1}" ] && r="${1}" || READLINE
READ_STR "${r}"
}
@@ -36,7 +36,7 @@ QUASIQUOTE () {
if [[ "${ANON["${a00}"]}" == "splice-unquote" ]]; then
_symbol concat; local a="${r}"
_nth "${a0}" 1; local b="${r}"
- rest "${1}"
+ _rest "${1}"
QUASIQUOTE "${r}"; local c="${r}"
_list "${a}" "${b}" "${c}"
return
@@ -45,7 +45,7 @@ QUASIQUOTE () {
fi
_symbol cons; local a="${r}"
QUASIQUOTE "${a0}"; local b="${r}"
- rest "${1}"
+ _rest "${1}"
QUASIQUOTE "${r}"; local c="${r}"
_list "${a}" "${b}" "${c}"
return
@@ -68,7 +68,7 @@ MACROEXPAND () {
while IS_MACRO_CALL "${ast}" "${env}"; do
_nth "${ast}" 0; local a0="${r}"
ENV_GET "${env}" "${ANON["${a0}"]}"; local mac="${ANON["${r}"]}"
- rest "${ast}"
+ _rest "${ast}"
${mac%%@*} ${ANON["${r}"]}
ast="${r}"
done
@@ -160,7 +160,7 @@ EVAL () {
_slice "${ast}" 1 $(( ${r} - 2 ))
EVAL_AST "${r}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
- last "${ast}"
+ _last "${ast}"
ast="${r}"
# Continue loop
;;
@@ -187,8 +187,8 @@ EVAL () {
*) EVAL_AST "${ast}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
local el="${r}"
- first "${el}"; local f="${ANON["${r}"]}"
- rest "${el}"; local args="${ANON["${r}"]}"
+ _first "${el}"; local f="${ANON["${r}"]}"
+ _rest "${el}"; local args="${ANON["${r}"]}"
#echo "invoke: [${f}] ${args}"
if [[ "${f//@/ }" != "${f}" ]]; then
set -- ${f//@/ }
@@ -220,31 +220,22 @@ PRINT () {
ENV; REPL_ENV="${r}"
REP () {
r=
- READ_STR "${1}"
+ READ "${1}" || return 1
EVAL "${r}" "${REPL_ENV}"
PRINT "${r}"
}
+# core.sh: defined using bash
_fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
-
-# Import types functions
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
-
-read_string () { READ_STR "${ANON["${1}"]}"; }
-_fref "read-string" read_string
_eval () { EVAL "${1}" "${REPL_ENV}"; }
_fref "eval" _eval
-slurp () {
- local lines
- mapfile lines < "${ANON["${1}"]}"
- local text="${lines[*]}"; text=${text//$'\n' /$'\n'}
- _string "${text}"
-}
-_fref "slurp" slurp
-# Defined using the language itself
+# core.mal: defined using the language itself
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)))))))"
+REP "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) \`(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))"
if [[ "${1}" ]]; then
echo "${@}"
diff --git a/bash/step9_interop.sh b/bash/step9_interop.sh
index dfa1e2c..c2b0931 100755
--- a/bash/step9_interop.sh
+++ b/bash/step9_interop.sh
@@ -4,12 +4,12 @@ INTERACTIVE=${INTERACTIVE-yes}
source $(dirname $0)/reader.sh
source $(dirname $0)/printer.sh
-source $(dirname $0)/core.sh
source $(dirname $0)/env.sh
+source $(dirname $0)/core.sh
# READ: read and parse input
READ () {
- READLINE
+ [ "${1}" ] && r="${1}" || READLINE
READ_STR "${r}"
}
@@ -36,7 +36,7 @@ QUASIQUOTE () {
if [[ "${ANON["${a00}"]}" == "splice-unquote" ]]; then
_symbol concat; local a="${r}"
_nth "${a0}" 1; local b="${r}"
- rest "${1}"
+ _rest "${1}"
QUASIQUOTE "${r}"; local c="${r}"
_list "${a}" "${b}" "${c}"
return
@@ -45,7 +45,7 @@ QUASIQUOTE () {
fi
_symbol cons; local a="${r}"
QUASIQUOTE "${a0}"; local b="${r}"
- rest "${1}"
+ _rest "${1}"
QUASIQUOTE "${r}"; local c="${r}"
_list "${a}" "${b}" "${c}"
return
@@ -68,7 +68,7 @@ MACROEXPAND () {
while IS_MACRO_CALL "${ast}" "${env}"; do
_nth "${ast}" 0; local a0="${r}"
ENV_GET "${env}" "${ANON["${a0}"]}"; local mac="${ANON["${r}"]}"
- rest "${ast}"
+ _rest "${ast}"
${mac%%@*} ${ANON["${r}"]}
ast="${r}"
done
@@ -169,7 +169,7 @@ EVAL () {
_slice "${ast}" 1 $(( ${r} - 2 ))
EVAL_AST "${r}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
- last "${ast}"
+ _last "${ast}"
ast="${r}"
# Continue loop
;;
@@ -196,8 +196,8 @@ EVAL () {
*) EVAL_AST "${ast}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
local el="${r}"
- first "${el}"; local f="${ANON["${r}"]}"
- rest "${el}"; local args="${ANON["${r}"]}"
+ _first "${el}"; local f="${ANON["${r}"]}"
+ _rest "${el}"; local args="${ANON["${r}"]}"
#echo "invoke: [${f}] ${args}"
if [[ "${f//@/ }" != "${f}" ]]; then
set -- ${f//@/ }
@@ -229,31 +229,22 @@ PRINT () {
ENV; REPL_ENV="${r}"
REP () {
r=
- READ_STR "${1}"
+ READ "${1}" || return 1
EVAL "${r}" "${REPL_ENV}"
PRINT "${r}"
}
+# core.sh: defined using bash
_fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
-
-# Import types functions
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
-
-read_string () { READ_STR "${ANON["${1}"]}"; }
-_fref "read-string" read_string
_eval () { EVAL "${1}" "${REPL_ENV}"; }
_fref "eval" _eval
-slurp () {
- local lines
- mapfile lines < "${ANON["${1}"]}"
- local text="${lines[*]}"; text=${text//$'\n' /$'\n'}
- _string "${text}"
-}
-_fref "slurp" slurp
-# Defined using the language itself
+# core.mal: defined using the language itself
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)))))))"
+REP "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) \`(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))"
if [[ "${1}" ]]; then
echo "${@}"
diff --git a/bash/stepA_more.sh b/bash/stepA_more.sh
index 605ca7f..d968942 100755
--- a/bash/stepA_more.sh
+++ b/bash/stepA_more.sh
@@ -4,12 +4,12 @@ INTERACTIVE=${INTERACTIVE-yes}
source $(dirname $0)/reader.sh
source $(dirname $0)/printer.sh
-source $(dirname $0)/core.sh
source $(dirname $0)/env.sh
+source $(dirname $0)/core.sh
# READ: read and parse input
READ () {
- READLINE
+ [ "${1}" ] && r="${1}" || READLINE
READ_STR "${r}"
}
@@ -36,7 +36,7 @@ QUASIQUOTE () {
if [[ "${ANON["${a00}"]}" == "splice-unquote" ]]; then
_symbol concat; local a="${r}"
_nth "${a0}" 1; local b="${r}"
- rest "${1}"
+ _rest "${1}"
QUASIQUOTE "${r}"; local c="${r}"
_list "${a}" "${b}" "${c}"
return
@@ -45,7 +45,7 @@ QUASIQUOTE () {
fi
_symbol cons; local a="${r}"
QUASIQUOTE "${a0}"; local b="${r}"
- rest "${1}"
+ _rest "${1}"
QUASIQUOTE "${r}"; local c="${r}"
_list "${a}" "${b}" "${c}"
return
@@ -68,7 +68,7 @@ MACROEXPAND () {
while IS_MACRO_CALL "${ast}" "${env}"; do
_nth "${ast}" 0; local a0="${r}"
ENV_GET "${env}" "${ANON["${a0}"]}"; local mac="${ANON["${r}"]}"
- rest "${ast}"
+ _rest "${ast}"
${mac%%@*} ${ANON["${r}"]}
ast="${r}"
done
@@ -184,7 +184,7 @@ EVAL () {
_slice "${ast}" 1 $(( ${r} - 2 ))
EVAL_AST "${r}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
- last "${ast}"
+ _last "${ast}"
ast="${r}"
# Continue loop
;;
@@ -211,8 +211,8 @@ EVAL () {
*) EVAL_AST "${ast}" "${env}"
[[ "${__ERROR}" ]] && r= && return 1
local el="${r}"
- first "${el}"; local f="${ANON["${r}"]}"
- rest "${el}"; local args="${ANON["${r}"]}"
+ _first "${el}"; local f="${ANON["${r}"]}"
+ _rest "${el}"; local args="${ANON["${r}"]}"
#echo "invoke: [${f}] ${args}"
if [[ "${f//@/ }" != "${f}" ]]; then
set -- ${f//@/ }
@@ -244,37 +244,22 @@ PRINT () {
ENV; REPL_ENV="${r}"
REP () {
r=
- READ_STR "${1}"
+ READ "${1}" || return 1
EVAL "${r}" "${REPL_ENV}"
PRINT "${r}"
}
+# core.sh: defined using bash
_fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
-
-# Import types functions
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
-
-readline () {
- READLINE "${ANON["${1}"]}" && _string "${r}" || r="${__nil}";
-}
-_fref "readline" readline
-read_string () { READ_STR "${ANON["${1}"]}"; }
-_fref "read-string" read_string
_eval () { EVAL "${1}" "${REPL_ENV}"; }
_fref "eval" _eval
-slurp () {
- local lines
- mapfile lines < "${ANON["${1}"]}"
- local text="${lines[*]}"; text=${text//$'\n' /$'\n'}
- _string "${text}"
-}
-_fref "slurp" slurp
-# Defined using the language itself
+# core.mal: defined using the language itself
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)))))))"
REP "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) \`(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))"
-REP "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"
if [[ "${1}" ]]; then
echo "${@}"
diff --git a/bash/types.sh b/bash/types.sh
index 8e256be..6781492 100644
--- a/bash/types.sh
+++ b/bash/types.sh
@@ -185,6 +185,11 @@ _hash_map () {
}
_hash_map? () { [[ ${1} =~ ^hmap_ ]]; }
+_contains? () {
+ local obj="${ANON["${1}"]}"
+ eval [[ "\${${obj}[\"${2}\"]+isset}" ]]
+}
+
_copy_hash_map () {
local orig_obj="${ANON["${1}"]}"
_hash_map
@@ -243,6 +248,30 @@ _nth () {
r=${temp[${2}]}
}
+_first () {
+ local temp="${ANON["${1}"]}"
+ r="${temp%% *}"
+ [ "${r}" ] || r="${__nil}"
+}
+
+_last () {
+ local temp="${ANON["${1}"]}"
+ r="${temp##* }"
+}
+
+# Creates a new vector/list of the everything after but the first
+# element
+_rest () {
+ local temp="${ANON["${1}"]}"
+ _list
+ if [[ "${temp#* }" == "${temp}" ]]; then
+ ANON["${r}"]=
+ else
+ ANON["${r}"]="${temp#* }"
+ fi
+}
+
+
_empty? () { [[ -z "${ANON["${1}"]}" ]]; }
# conj that mutates in place (and always appends)