diff options
Diffstat (limited to 'bash')
| -rw-r--r-- | bash/core.sh | 52 | ||||
| -rwxr-xr-x | bash/step2_eval.sh | 22 | ||||
| -rwxr-xr-x | bash/step3_env.sh | 25 | ||||
| -rwxr-xr-x | bash/step4_if_fn_do.sh | 21 | ||||
| -rwxr-xr-x | bash/step5_tco.sh | 19 | ||||
| -rwxr-xr-x | bash/step6_file.sh | 29 | ||||
| -rwxr-xr-x | bash/step7_quote.sh | 31 | ||||
| -rwxr-xr-x | bash/step8_macros.sh | 35 | ||||
| -rwxr-xr-x | bash/step9_interop.sh | 35 | ||||
| -rwxr-xr-x | bash/stepA_more.sh | 39 | ||||
| -rw-r--r-- | bash/types.sh | 29 |
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) |
