aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-04-16 23:57:50 -0500
committerJoel Martin <github@martintribe.org>2014-04-16 23:57:50 -0500
commit8cb5cda46cf3aef847ae3926dc53a5e5f87fe261 (patch)
tree13e5b2878f19ee24272ead8a92a9cb84b33ad0e5
parenta05f7822b10ed4cdd61ed8384299a003baf1c1c6 (diff)
downloadmal-8cb5cda46cf3aef847ae3926dc53a5e5f87fe261.tar.gz
mal-8cb5cda46cf3aef847ae3926dc53a5e5f87fe261.zip
All: move some fns to core. Major cleanup.
- Don't import/require core until step4. - Define cond/or macros from step8
-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
-rw-r--r--c/core.c96
-rw-r--r--c/core.h16
-rw-r--r--c/step1_read_print.c1
-rw-r--r--c/step2_eval.c14
-rw-r--r--c/step3_env.c13
-rw-r--r--c/step4_if_fn_do.c23
-rw-r--r--c/step5_tco.c177
-rw-r--r--c/step6_file.c249
-rw-r--r--c/step7_quote.c271
-rw-r--r--c/step8_macros.c311
-rw-r--r--c/step9_interop.c320
-rw-r--r--c/stepA_more.c368
-rw-r--r--c/types.c30
-rw-r--r--c/types.h16
-rw-r--r--clojure/src/core.clj7
-rw-r--r--clojure/src/step3_env.clj9
-rw-r--r--clojure/src/step4_if_fn_do.clj9
-rw-r--r--clojure/src/step5_tco.clj9
-rw-r--r--clojure/src/step6_file.clj13
-rw-r--r--clojure/src/step7_quote.clj13
-rw-r--r--clojure/src/step8_macros.clj15
-rw-r--r--clojure/src/step9_interop.clj15
-rw-r--r--clojure/src/stepA_more.clj16
-rw-r--r--cs/core.cs20
-rw-r--r--cs/step1_read_print.cs8
-rw-r--r--cs/step2_eval.cs13
-rw-r--r--cs/step3_env.cs34
-rw-r--r--cs/step4_if_fn_do.cs46
-rw-r--r--cs/step5_tco.cs44
-rw-r--r--cs/step6_file.cs54
-rw-r--r--cs/step7_quote.cs28
-rw-r--r--cs/step8_macros.cs30
-rw-r--r--cs/stepA_more.cs44
-rw-r--r--cs/types.cs3
-rw-r--r--docs/TODO3
-rw-r--r--java/src/main/java/mal/core.java45
-rw-r--r--java/src/main/java/mal/step2_eval.java54
-rw-r--r--java/src/main/java/mal/step3_env.java40
-rw-r--r--java/src/main/java/mal/step4_if_fn_do.java8
-rw-r--r--java/src/main/java/mal/step5_tco.java8
-rw-r--r--java/src/main/java/mal/step6_file.java36
-rw-r--r--java/src/main/java/mal/step7_quote.java36
-rw-r--r--java/src/main/java/mal/step8_macros.java38
-rw-r--r--java/src/main/java/mal/stepA_more.java50
-rw-r--r--js/core.js10
-rw-r--r--js/step3_env.js9
-rw-r--r--js/step4_if_fn_do.js6
-rw-r--r--js/step5_tco.js6
-rw-r--r--js/step6_file.js12
-rw-r--r--js/step7_quote.js12
-rw-r--r--js/step8_macros.js14
-rw-r--r--js/step9_interop.js14
-rw-r--r--js/stepA_more.js15
-rw-r--r--make/core.mk12
-rw-r--r--make/step3_env.mk9
-rw-r--r--make/step4_if_fn_do.mk6
-rw-r--r--make/step6_file.mk14
-rw-r--r--make/step7_quote.mk14
-rw-r--r--make/step8_macros.mk16
-rw-r--r--make/step9_interop.mk16
-rw-r--r--make/stepA_more.mk17
-rw-r--r--mal/core.mal4
-rw-r--r--mal/step3_env.mal9
-rw-r--r--mal/step4_if_fn_do.mal10
-rw-r--r--mal/step6_file.mal13
-rw-r--r--mal/step7_quote.mal13
-rw-r--r--mal/step8_macros.mal15
-rw-r--r--mal/stepA_more.mal16
-rw-r--r--php/core.php6
-rw-r--r--php/step2_eval.php1
-rw-r--r--php/step3_env.php9
-rw-r--r--php/step4_if_fn_do.php10
-rw-r--r--php/step5_tco.php9
-rw-r--r--php/step6_file.php49
-rw-r--r--php/step7_quote.php49
-rw-r--r--php/step8_macros.php51
-rw-r--r--php/step9_interop.php51
-rw-r--r--php/stepA_more.php52
-rw-r--r--ps/core.ps4
-rw-r--r--ps/step3_env.ps2
-rw-r--r--ps/step4_if_fn_do.ps4
-rw-r--r--ps/step5_tco.ps4
-rw-r--r--ps/step6_file.ps8
-rw-r--r--ps/step7_quote.ps8
-rw-r--r--ps/step8_macros.ps10
-rw-r--r--ps/step9_interop.ps10
-rw-r--r--ps/stepA_more.ps11
-rw-r--r--python/core.py6
-rw-r--r--python/step3_env.py9
-rw-r--r--python/step4_if_fn_do.py7
-rw-r--r--python/step5_tco.py7
-rw-r--r--python/step6_file.py12
-rw-r--r--python/step7_quote.py12
-rw-r--r--python/step8_macros.py14
-rw-r--r--python/step9_interop.py14
-rw-r--r--python/stepA_more.py15
-rw-r--r--ruby/core.rb14
-rw-r--r--ruby/step3_env.rb9
-rw-r--r--ruby/step4_if_fn_do.rb8
-rw-r--r--ruby/step5_tco.rb8
-rw-r--r--ruby/step6_file.rb12
-rw-r--r--ruby/step7_quote.rb12
-rw-r--r--ruby/step8_macros.rb14
-rw-r--r--ruby/step9_interop.rb14
-rw-r--r--ruby/stepA_more.rb15
-rw-r--r--tests/step8_macros.mal2
-rw-r--r--tests/stepA_more.mal18
118 files changed, 1706 insertions, 2136 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)
diff --git a/c/core.c b/c/core.c
index 33bb991..2c76a95 100644
--- a/c/core.c
+++ b/c/core.c
@@ -2,9 +2,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include "types.h"
#include "core.h"
+#include "reader.h"
#include "printer.h"
// Errors/Exceptions
@@ -80,17 +83,49 @@ MalVal *println(MalVal *args) {
return &mal_nil;
}
+MalVal *mal_readline(MalVal *str) {
+ assert_type(str, MAL_STRING, "readline of non-string");
+ char * line = _readline(str->val.string);
+ if (line) { return malval_new_string(line); }
+ else { return &mal_nil; }
+}
-// Number functions
+MalVal *read_string(MalVal *str) {
+ assert_type(str, MAL_STRING, "read_string of non-string");
+ return read_str(str->val.string);
+}
-#define WRAP_INTEGER_OP(name, op) \
- MalVal *int_ ## name(MalVal *a, MalVal *b) { \
- return malval_new_integer(a->val.intnum op b->val.intnum); \
+char *slurp_raw(char *path) {
+ char *data;
+ struct stat fst;
+ int fd = open(path, O_RDONLY),
+ sz;
+ if (fd < 0) {
+ abort("slurp failed to open '%s'", path);
+ }
+ if (fstat(fd, &fst) < 0) {
+ abort("slurp failed to stat '%s'", path);
}
-#define WRAP_INTEGER_CMP_OP(name, op) \
- MalVal *int_ ## name(MalVal *a, MalVal *b) { \
- return a->val.intnum op b->val.intnum ? &mal_true : &mal_false; \
+ data = malloc(fst.st_size+1);
+ sz = read(fd, data, fst.st_size);
+ if (sz < fst.st_size) {
+ abort("slurp failed to read '%s'", path);
}
+ data[sz] = '\0';
+ return data;
+}
+MalVal *slurp(MalVal *path) {
+ assert_type(path, MAL_STRING, "slurp of non-string");
+ char *data = slurp_raw(path->val.string);
+ if (!data || mal_error) { return NULL; }
+ return malval_new_string(data);
+}
+
+
+
+
+// Number functions
+
WRAP_INTEGER_OP(plus,+)
WRAP_INTEGER_OP(minus,-)
WRAP_INTEGER_OP(multiply,*)
@@ -115,7 +150,6 @@ MalVal *vector_Q(MalVal *seq) { return _vector_Q(seq) ? &mal_true : &mal_false;
// Hash map functions
-MalVal *hash_map(MalVal *args) { return _hash_map(args); }
MalVal *hash_map_Q(MalVal *seq) { return _hash_map_Q(seq) ? &mal_true : &mal_false; }
MalVal *assoc(MalVal *args) {
@@ -123,15 +157,15 @@ MalVal *assoc(MalVal *args) {
"assoc called with non-sequential arguments");
assert(_count(args) >= 2,
"assoc needs at least 2 arguments");
- GHashTable *htable = g_hash_table_copy(first(args)->val.hash_table);
+ GHashTable *htable = g_hash_table_copy(_first(args)->val.hash_table);
MalVal *hm = malval_new_hash_map(htable);
- return _assoc_BANG(hm, rest(args));
+ return _assoc_BANG(hm, _rest(args));
}
MalVal *dissoc(MalVal* args) {
- GHashTable *htable = g_hash_table_copy(first(args)->val.hash_table);
+ GHashTable *htable = g_hash_table_copy(_first(args)->val.hash_table);
MalVal *hm = malval_new_hash_map(htable);
- return _dissoc_BANG(hm, rest(args));
+ return _dissoc_BANG(hm, _rest(args));
}
MalVal *keys(MalVal *obj) {
@@ -249,19 +283,6 @@ MalVal *nth(MalVal *seq, MalVal *idx) {
return _nth(seq, idx->val.intnum);
}
-MalVal *first(MalVal *seq) {
- assert_type(seq, MAL_LIST|MAL_VECTOR,
- "first called with non-sequential");
- if (_count(seq) == 0) {
- return &mal_nil;
- }
- return g_array_index(seq->val.array, MalVal*, 0);
-}
-
-MalVal *rest(MalVal *seq) {
- return _slice(seq, 1, _count(seq));
-}
-
MalVal *empty_Q(MalVal *seq) {
assert_type(seq, MAL_LIST|MAL_VECTOR,
"empty? called with non-sequential");
@@ -296,20 +317,11 @@ MalVal *sconj(MalVal *args) {
return malval_new_list(src_lst->type, new_arr);
}
-MalVal *last(MalVal *seq) {
- assert_type(seq, MAL_LIST|MAL_VECTOR,
- "last called with non-sequential");
- if (_count(seq) == 0) {
- return &mal_nil;
- }
- return g_array_index(seq->val.array, MalVal*, _count(seq)-1);
-}
-
MalVal *apply(MalVal *args) {
assert_type(args, MAL_LIST|MAL_VECTOR,
"apply called with non-sequential");
MalVal *f = _nth(args, 0);
- MalVal *last_arg = last(args);
+ MalVal *last_arg = _last(args);
assert_type(last_arg, MAL_LIST|MAL_VECTOR,
"last argument to apply is non-sequential");
int i, len = _count(args) - 2 + _count(last_arg);
@@ -410,7 +422,7 @@ MalVal *swap_BANG(MalVal *args) {
-core_ns_entry core_ns[50] = {
+core_ns_entry core_ns[53] = {
{"=", (void*(*)(void*))equal_Q, 2},
{"throw", (void*(*)(void*))throw, 1},
{"nil?", (void*(*)(void*))nil_Q, 1},
@@ -418,10 +430,14 @@ core_ns_entry core_ns[50] = {
{"false?", (void*(*)(void*))false_Q, 1},
{"symbol", (void*(*)(void*))symbol, 1},
{"symbol?", (void*(*)(void*))symbol_Q, 1},
+
{"pr-str", (void*(*)(void*))pr_str, -1},
{"str", (void*(*)(void*))str, -1},
{"prn", (void*(*)(void*))prn, -1},
{"println", (void*(*)(void*))println, -1},
+ {"readline", (void*(*)(void*))mal_readline, 1},
+ {"read-string", (void*(*)(void*))read_string, 1},
+ {"slurp", (void*(*)(void*))slurp, 1},
{"<", (void*(*)(void*))int_lt, 2},
{"<=", (void*(*)(void*))int_lte, 2},
{">", (void*(*)(void*))int_gt, 2},
@@ -435,7 +451,7 @@ core_ns_entry core_ns[50] = {
{"list?", (void*(*)(void*))list_Q, 1},
{"vector", (void*(*)(void*))vector, -1},
{"vector?", (void*(*)(void*))vector_Q, 1},
- {"hash-map", (void*(*)(void*))hash_map, -1},
+ {"hash-map", (void*(*)(void*))_hash_map, -1},
{"map?", (void*(*)(void*))hash_map_Q, 1},
{"assoc", (void*(*)(void*))assoc, -1},
{"dissoc", (void*(*)(void*))dissoc, -1},
@@ -448,9 +464,9 @@ core_ns_entry core_ns[50] = {
{"cons", (void*(*)(void*))cons, 2},
{"concat", (void*(*)(void*))concat, -1},
{"nth", (void*(*)(void*))nth, 2},
- {"first", (void*(*)(void*))first, 1},
- {"rest", (void*(*)(void*))rest, 1},
- {"last", (void*(*)(void*))last, 1},
+ {"first", (void*(*)(void*))_first, 1},
+ {"rest", (void*(*)(void*))_rest, 1},
+ {"last", (void*(*)(void*))_last, 1},
{"empty?", (void*(*)(void*))empty_Q, 1},
{"count", (void*(*)(void*))count, 1},
{"conj", (void*(*)(void*))sconj, -1},
diff --git a/c/core.h b/c/core.h
index 6668c53..a8b7a5f 100644
--- a/c/core.h
+++ b/c/core.h
@@ -3,20 +3,6 @@
#include <glib.h>
-// These are just used by step2 and step3 before then core_ns environment is
-// imported
-
-MalVal *int_plus(MalVal *a, MalVal *b);
-MalVal *int_minus(MalVal *a, MalVal *b);
-MalVal *int_multiply(MalVal *a, MalVal *b);
-MalVal *int_divide(MalVal *a, MalVal *b);
-
-// Useful for step implementation
-MalVal *first(MalVal *seq);
-MalVal *rest(MalVal *seq);
-MalVal *last(MalVal *seq);
-MalVal *hash_map(MalVal *args);
-
// namespace of type functions
typedef struct {
char *name;
@@ -24,6 +10,6 @@ typedef struct {
int arg_cnt;
} core_ns_entry;
-extern core_ns_entry core_ns[50];
+extern core_ns_entry core_ns[53];
#endif
diff --git a/c/step1_read_print.c b/c/step1_read_print.c
index 77c75b9..d28439e 100644
--- a/c/step1_read_print.c
+++ b/c/step1_read_print.c
@@ -1,6 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
+
#include "types.h"
#include "readline.h"
#include "reader.h"
diff --git a/c/step2_eval.c b/c/step2_eval.c
index 85746f8..5d24ff0 100644
--- a/c/step2_eval.c
+++ b/c/step2_eval.c
@@ -1,10 +1,10 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
+
#include "types.h"
#include "readline.h"
#include "reader.h"
-#include "core.h"
// Declarations
MalVal *EVAL(MalVal *ast, GHashTable *env);
@@ -54,7 +54,7 @@ MalVal *eval_ast(MalVal *ast, GHashTable *env) {
MalVal *new_val = EVAL((MalVal *)value, env);
g_array_append_val(seq->val.array, new_val);
}
- return hash_map(seq);
+ return _hash_map(seq);
} else {
//g_print("EVAL scalar: %s\n", _pr_str(ast,1));
return ast;
@@ -62,8 +62,8 @@ MalVal *eval_ast(MalVal *ast, GHashTable *env) {
}
MalVal *EVAL(MalVal *ast, GHashTable *env) {
- //g_print("EVAL: %s\n", _pr_str(ast,1));
if (!ast || mal_error) return NULL;
+ //g_print("EVAL: %s\n", _pr_str(ast,1));
if (ast->type != MAL_LIST) {
return eval_ast(ast, env);
}
@@ -76,7 +76,7 @@ MalVal *EVAL(MalVal *ast, GHashTable *env) {
assert_type(a0, MAL_SYMBOL, "Cannot invoke %s", _pr_str(a0,1));
MalVal *el = eval_ast(ast, env);
if (!el || mal_error) { return NULL; }
- MalVal *(*f)(void *, void*) = (MalVal *(*)(void*, void*))first(el);
+ MalVal *(*f)(void *, void*) = (MalVal *(*)(void*, void*))_first(el);
//g_print("eval_invoke el: %s\n", _pr_str(el,1));
return f(_nth(el, 1), _nth(el, 2));
}
@@ -109,9 +109,15 @@ MalVal *RE(GHashTable *env, char *prompt, char *str) {
// Setup the initial REPL environment
GHashTable *repl_env;
+
void init_repl_env() {
repl_env = g_hash_table_new(g_str_hash, g_str_equal);
+ WRAP_INTEGER_OP(plus,+)
+ WRAP_INTEGER_OP(minus,-)
+ WRAP_INTEGER_OP(multiply,*)
+ WRAP_INTEGER_OP(divide,/)
+
g_hash_table_insert(repl_env, "+", int_plus);
g_hash_table_insert(repl_env, "-", int_minus);
g_hash_table_insert(repl_env, "*", int_multiply);
diff --git a/c/step3_env.c b/c/step3_env.c
index 4abf4d6..7c36b38 100644
--- a/c/step3_env.c
+++ b/c/step3_env.c
@@ -1,10 +1,10 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
+
#include "types.h"
#include "readline.h"
#include "reader.h"
-#include "core.h"
// Declarations
MalVal *EVAL(MalVal *ast, Env *env);
@@ -53,7 +53,7 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
MalVal *new_val = EVAL((MalVal *)value, env);
g_array_append_val(seq->val.array, new_val);
}
- return hash_map(seq);
+ return _hash_map(seq);
} else {
//g_print("EVAL scalar: %s\n", _pr_str(ast,1));
return ast;
@@ -61,8 +61,8 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
}
MalVal *EVAL(MalVal *ast, Env *env) {
- //g_print("EVAL: %s\n", _pr_str(ast,1));
if (!ast || mal_error) return NULL;
+ //g_print("EVAL: %s\n", _pr_str(ast,1));
if (ast->type != MAL_LIST) {
return eval_ast(ast, env);
}
@@ -102,7 +102,7 @@ MalVal *EVAL(MalVal *ast, Env *env) {
//g_print("eval apply\n");
MalVal *el = eval_ast(ast, env);
if (!el || mal_error) { return NULL; }
- MalVal *(*f)(void *, void*) = (MalVal *(*)(void*, void*))first(el);
+ MalVal *(*f)(void *, void*) = (MalVal *(*)(void*, void*))_first(el);
return f(_nth(el, 1), _nth(el, 2));
}
}
@@ -138,6 +138,11 @@ Env *repl_env;
void init_repl_env() {
repl_env = new_env(NULL, NULL, NULL);
+ WRAP_INTEGER_OP(plus,+)
+ WRAP_INTEGER_OP(minus,-)
+ WRAP_INTEGER_OP(multiply,*)
+ WRAP_INTEGER_OP(divide,/)
+
env_set(repl_env, "+", (MalVal *)int_plus);
env_set(repl_env, "-", (MalVal *)int_minus);
env_set(repl_env, "*", (MalVal *)int_multiply);
diff --git a/c/step4_if_fn_do.c b/c/step4_if_fn_do.c
index 3662816..87e1241 100644
--- a/c/step4_if_fn_do.c
+++ b/c/step4_if_fn_do.c
@@ -1,6 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
+
#include "types.h"
#include "readline.h"
#include "reader.h"
@@ -53,7 +54,7 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
MalVal *new_val = EVAL((MalVal *)value, env);
g_array_append_val(seq->val.array, new_val);
}
- return hash_map(seq);
+ return _hash_map(seq);
} else {
//g_print("EVAL scalar: %s\n", _pr_str(ast,1));
return ast;
@@ -61,8 +62,8 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
}
MalVal *EVAL(MalVal *ast, Env *env) {
- //g_print("EVAL: %s\n", _pr_str(ast,1));
if (!ast || mal_error) return NULL;
+ //g_print("EVAL: %s\n", _pr_str(ast,1));
if (ast->type != MAL_LIST) {
return eval_ast(ast, env);
}
@@ -102,8 +103,8 @@ MalVal *EVAL(MalVal *ast, Env *env) {
} else if ((a0->type & MAL_SYMBOL) &&
strcmp("do", a0->val.string) == 0) {
//g_print("eval apply do\n");
- MalVal *el = eval_ast(rest(ast), env);
- return last(el);
+ MalVal *el = eval_ast(_rest(ast), env);
+ return _last(el);
} else if ((a0->type & MAL_SYMBOL) &&
strcmp("if", a0->val.string) == 0) {
//g_print("eval apply if\n");
@@ -136,8 +137,8 @@ MalVal *EVAL(MalVal *ast, Env *env) {
//g_print("eval apply\n");
MalVal *el = eval_ast(ast, env);
if (!el || mal_error) { return NULL; }
- MalVal *f = first(el),
- *args = rest(el);
+ MalVal *f = _first(el),
+ *args = _rest(el);
assert_type(f, MAL_FUNCTION_C|MAL_FUNCTION_MAL,
"cannot apply '%s'", _pr_str(f,1));
return _apply(f, args);
@@ -173,18 +174,16 @@ MalVal *RE(Env *env, char *prompt, char *str) {
Env *repl_env;
void init_repl_env() {
- void _ref(char *name, MalVal*(*func)(MalVal*), int arg_cnt) {
- void *(*f)(void *) = (void*(*)(void*))func;
- env_set(repl_env, name, malval_new_function(f, arg_cnt, NULL));
- }
repl_env = new_env(NULL, NULL, NULL);
+ // core.c: defined using C
int i;
for(i=0; i< (sizeof(core_ns) / sizeof(core_ns[0])); i++) {
- MalVal *(*f)(MalVal *) = (MalVal*(*)(MalVal*))core_ns[i].func;
- _ref(core_ns[i].name, f, core_ns[i].arg_cnt);
+ env_set(repl_env, core_ns[i].name,
+ malval_new_function(core_ns[i].func, core_ns[i].arg_cnt));
}
+ // core.mal: defined using the language itself
RE(repl_env, "", "(def! not (fn* (a) (if a false true)))");
}
diff --git a/c/step5_tco.c b/c/step5_tco.c
index 99d6826..6938e47 100644
--- a/c/step5_tco.c
+++ b/c/step5_tco.c
@@ -1,6 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
+
#include "types.h"
#include "readline.h"
#include "reader.h"
@@ -53,7 +54,7 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
MalVal *new_val = EVAL((MalVal *)value, env);
g_array_append_val(seq->val.array, new_val);
}
- return hash_map(seq);
+ return _hash_map(seq);
} else {
//g_print("EVAL scalar: %s\n", _pr_str(ast,1));
return ast;
@@ -62,93 +63,95 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
MalVal *EVAL(MalVal *ast, Env *env) {
while (TRUE) {
- //g_print("EVAL: %s\n", _pr_str(ast,1));
- if (!ast || mal_error) return NULL;
- if (ast->type != MAL_LIST) {
- return eval_ast(ast, env);
+
+ if (!ast || mal_error) return NULL;
+ //g_print("EVAL: %s\n", _pr_str(ast,1));
+ if (ast->type != MAL_LIST) {
+ return eval_ast(ast, env);
+ }
+ if (!ast || mal_error) return NULL;
+
+ // apply list
+ //g_print("EVAL apply list: %s\n", _pr_str(ast,1));
+ int i, len;
+ if (_count(ast) == 0) { return ast; }
+ MalVal *a0 = _nth(ast, 0);
+ if ((a0->type & MAL_SYMBOL) &&
+ strcmp("def!", a0->val.string) == 0) {
+ //g_print("eval apply def!\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2);
+ MalVal *res = EVAL(a2, env);
+ env_set(env, a1->val.string, res);
+ return res;
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("let*", a0->val.string) == 0) {
+ //g_print("eval apply let*\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2),
+ *key, *val;
+ assert_type(a1, MAL_LIST|MAL_VECTOR,
+ "let* bindings must be list or vector");
+ len = _count(a1);
+ assert((len % 2) == 0, "odd number of let* bindings forms");
+ Env *let_env = new_env(env, NULL, NULL);
+ for(i=0; i<len; i+=2) {
+ key = g_array_index(a1->val.array, MalVal*, i);
+ val = g_array_index(a1->val.array, MalVal*, i+1);
+ assert_type(key, MAL_SYMBOL, "let* bind to non-symbol");
+ env_set(let_env, key->val.string, EVAL(val, let_env));
}
- if (!ast || mal_error) return NULL;
-
- // apply list
- //g_print("EVAL apply list: %s\n", _pr_str(ast,1));
- int i, len;
- if (_count(ast) == 0) { return ast; }
- MalVal *a0 = _nth(ast, 0);
- if ((a0->type & MAL_SYMBOL) &&
- strcmp("def!", a0->val.string) == 0) {
- //g_print("eval apply def!\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2);
- MalVal *res = EVAL(a2, env);
- env_set(env, a1->val.string, res);
- return res;
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("let*", a0->val.string) == 0) {
- //g_print("eval apply let*\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2),
- *key, *val;
- assert_type(a1, MAL_LIST|MAL_VECTOR,
- "let* bindings must be list or vector");
- len = _count(a1);
- assert((len % 2) == 0, "odd number of let* bindings forms");
- Env *let_env = new_env(env, NULL, NULL);
- for(i=0; i<len; i+=2) {
- key = g_array_index(a1->val.array, MalVal*, i);
- val = g_array_index(a1->val.array, MalVal*, i+1);
- assert_type(key, MAL_SYMBOL, "let* bind to non-symbol");
- env_set(let_env, key->val.string, EVAL(val, let_env));
- }
- return EVAL(a2, let_env);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("do", a0->val.string) == 0) {
- //g_print("eval apply do\n");
- eval_ast(_slice(ast, 1, _count(ast)-1), env);
- ast = last(ast);
- // Continue loop
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("if", a0->val.string) == 0) {
- //g_print("eval apply if\n");
- MalVal *a1 = _nth(ast, 1);
- MalVal *cond = EVAL(a1, env);
- if (!cond || mal_error) return NULL;
- if (cond->type & (MAL_FALSE|MAL_NIL)) {
- // eval false slot form
- ast = _nth(ast, 3);
- if (!ast) {
- return &mal_nil;
- }
- } else {
- // eval true slot form
- ast = _nth(ast, 2);
+ return EVAL(a2, let_env);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("do", a0->val.string) == 0) {
+ //g_print("eval apply do\n");
+ eval_ast(_slice(ast, 1, _count(ast)-1), env);
+ ast = _last(ast);
+ // Continue loop
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("if", a0->val.string) == 0) {
+ //g_print("eval apply if\n");
+ MalVal *a1 = _nth(ast, 1);
+ MalVal *cond = EVAL(a1, env);
+ if (!cond || mal_error) return NULL;
+ if (cond->type & (MAL_FALSE|MAL_NIL)) {
+ // eval false slot form
+ ast = _nth(ast, 3);
+ if (!ast) {
+ return &mal_nil;
}
+ } else {
+ // eval true slot form
+ ast = _nth(ast, 2);
+ }
+ // Continue loop
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("fn*", a0->val.string) == 0) {
+ //g_print("eval apply fn*\n");
+ MalVal *mf = malval_new(MAL_FUNCTION_MAL, NULL);
+ mf->val.func.evaluator = EVAL;
+ mf->val.func.args = _nth(ast, 1);
+ mf->val.func.body = _nth(ast, 2);
+ mf->val.func.env = env;
+ return mf;
+ } else {
+ //g_print("eval apply\n");
+ MalVal *el = eval_ast(ast, env);
+ if (!el || mal_error) { return NULL; }
+ MalVal *f = _first(el),
+ *args = _rest(el);
+ assert_type(f, MAL_FUNCTION_C|MAL_FUNCTION_MAL,
+ "cannot apply '%s'", _pr_str(f,1));
+ if (f->type & MAL_FUNCTION_MAL) {
+ ast = f->val.func.body;
+ env = new_env(f->val.func.env, f->val.func.args, args);
// Continue loop
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("fn*", a0->val.string) == 0) {
- //g_print("eval apply fn*\n");
- MalVal *mf = malval_new(MAL_FUNCTION_MAL, NULL);
- mf->val.func.evaluator = EVAL;
- mf->val.func.args = _nth(ast, 1);
- mf->val.func.body = _nth(ast, 2);
- mf->val.func.env = env;
- return mf;
} else {
- //g_print("eval apply\n");
- MalVal *el = eval_ast(ast, env);
- if (!el || mal_error) { return NULL; }
- MalVal *f = first(el),
- *args = rest(el);
- assert_type(f, MAL_FUNCTION_C|MAL_FUNCTION_MAL,
- "cannot invoke '%s'", _pr_str(f,1));
- if (f->type & MAL_FUNCTION_MAL) {
- ast = f->val.func.body;
- env = new_env(f->val.func.env, f->val.func.args, args);
- // Continue loop
- } else {
- return _apply(f, args);
- }
+ return _apply(f, args);
}
}
+
+ } // TCO while loop
}
// print
@@ -180,18 +183,16 @@ MalVal *RE(Env *env, char *prompt, char *str) {
Env *repl_env;
void init_repl_env() {
- void _ref(char *name, MalVal*(*func)(MalVal*), int arg_cnt) {
- void *(*f)(void *) = (void*(*)(void*))func;
- env_set(repl_env, name, malval_new_function(f, arg_cnt, NULL));
- }
repl_env = new_env(NULL, NULL, NULL);
+ // core.c: defined using C
int i;
for(i=0; i< (sizeof(core_ns) / sizeof(core_ns[0])); i++) {
- MalVal *(*f)(MalVal *) = (MalVal*(*)(MalVal*))core_ns[i].func;
- _ref(core_ns[i].name, f, core_ns[i].arg_cnt);
+ env_set(repl_env, core_ns[i].name,
+ malval_new_function(core_ns[i].func, core_ns[i].arg_cnt));
}
+ // core.mal: defined using the language itself
RE(repl_env, "", "(def! not (fn* (a) (if a false true)))");
}
diff --git a/c/step6_file.c b/c/step6_file.c
index acde758..ae48693 100644
--- a/c/step6_file.c
+++ b/c/step6_file.c
@@ -1,13 +1,11 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
-#include <sys/stat.h>
-#include <fcntl.h>
+
#include "types.h"
#include "readline.h"
#include "reader.h"
#include "core.h"
-#include "interop.h"
// Declarations
MalVal *EVAL(MalVal *ast, Env *env);
@@ -56,7 +54,7 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
MalVal *new_val = EVAL((MalVal *)value, env);
g_array_append_val(seq->val.array, new_val);
}
- return hash_map(seq);
+ return _hash_map(seq);
} else {
//g_print("EVAL scalar: %s\n", _pr_str(ast,1));
return ast;
@@ -65,93 +63,95 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
MalVal *EVAL(MalVal *ast, Env *env) {
while (TRUE) {
- //g_print("EVAL: %s\n", _pr_str(ast,1));
- if (!ast || mal_error) return NULL;
- if (ast->type != MAL_LIST) {
- return eval_ast(ast, env);
- }
- if (!ast || mal_error) return NULL;
- // apply list
- //g_print("EVAL apply list: %s\n", _pr_str(ast,1));
- int i, len;
- if (_count(ast) == 0) { return ast; }
- MalVal *a0 = _nth(ast, 0);
- if ((a0->type & MAL_SYMBOL) &&
- strcmp("def!", a0->val.string) == 0) {
- //g_print("eval apply def!\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2);
- MalVal *res = EVAL(a2, env);
- env_set(env, a1->val.string, res);
- return res;
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("let*", a0->val.string) == 0) {
- //g_print("eval apply let*\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2),
- *key, *val;
- assert_type(a1, MAL_LIST|MAL_VECTOR,
- "let* bindings must be list or vector");
- len = _count(a1);
- assert((len % 2) == 0, "odd number of let* bindings forms");
- Env *let_env = new_env(env, NULL, NULL);
- for(i=0; i<len; i+=2) {
- key = g_array_index(a1->val.array, MalVal*, i);
- val = g_array_index(a1->val.array, MalVal*, i+1);
- assert_type(key, MAL_SYMBOL, "let* bind to non-symbol");
- env_set(let_env, key->val.string, EVAL(val, let_env));
- }
- return EVAL(a2, let_env);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("do", a0->val.string) == 0) {
- //g_print("eval apply do\n");
- eval_ast(_slice(ast, 1, _count(ast)-1), env);
- ast = last(ast);
- // Continue loop
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("if", a0->val.string) == 0) {
- //g_print("eval apply if\n");
- MalVal *a1 = _nth(ast, 1);
- MalVal *cond = EVAL(a1, env);
- if (!cond || mal_error) return NULL;
- if (cond->type & (MAL_FALSE|MAL_NIL)) {
- // eval false slot form
- ast = _nth(ast, 3);
- if (!ast) {
- return &mal_nil;
- }
- } else {
- // eval true slot form
- ast = _nth(ast, 2);
+ if (!ast || mal_error) return NULL;
+ //g_print("EVAL: %s\n", _pr_str(ast,1));
+ if (ast->type != MAL_LIST) {
+ return eval_ast(ast, env);
+ }
+ if (!ast || mal_error) return NULL;
+
+ // apply list
+ //g_print("EVAL apply list: %s\n", _pr_str(ast,1));
+ int i, len;
+ if (_count(ast) == 0) { return ast; }
+ MalVal *a0 = _nth(ast, 0);
+ if ((a0->type & MAL_SYMBOL) &&
+ strcmp("def!", a0->val.string) == 0) {
+ //g_print("eval apply def!\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2);
+ MalVal *res = EVAL(a2, env);
+ env_set(env, a1->val.string, res);
+ return res;
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("let*", a0->val.string) == 0) {
+ //g_print("eval apply let*\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2),
+ *key, *val;
+ assert_type(a1, MAL_LIST|MAL_VECTOR,
+ "let* bindings must be list or vector");
+ len = _count(a1);
+ assert((len % 2) == 0, "odd number of let* bindings forms");
+ Env *let_env = new_env(env, NULL, NULL);
+ for(i=0; i<len; i+=2) {
+ key = g_array_index(a1->val.array, MalVal*, i);
+ val = g_array_index(a1->val.array, MalVal*, i+1);
+ assert_type(key, MAL_SYMBOL, "let* bind to non-symbol");
+ env_set(let_env, key->val.string, EVAL(val, let_env));
+ }
+ return EVAL(a2, let_env);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("do", a0->val.string) == 0) {
+ //g_print("eval apply do\n");
+ eval_ast(_slice(ast, 1, _count(ast)-1), env);
+ ast = _last(ast);
+ // Continue loop
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("if", a0->val.string) == 0) {
+ //g_print("eval apply if\n");
+ MalVal *a1 = _nth(ast, 1);
+ MalVal *cond = EVAL(a1, env);
+ if (!cond || mal_error) return NULL;
+ if (cond->type & (MAL_FALSE|MAL_NIL)) {
+ // eval false slot form
+ ast = _nth(ast, 3);
+ if (!ast) {
+ return &mal_nil;
}
+ } else {
+ // eval true slot form
+ ast = _nth(ast, 2);
+ }
+ // Continue loop
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("fn*", a0->val.string) == 0) {
+ //g_print("eval apply fn*\n");
+ MalVal *mf = malval_new(MAL_FUNCTION_MAL, NULL);
+ mf->val.func.evaluator = EVAL;
+ mf->val.func.args = _nth(ast, 1);
+ mf->val.func.body = _nth(ast, 2);
+ mf->val.func.env = env;
+ return mf;
+ } else {
+ //g_print("eval apply\n");
+ MalVal *el = eval_ast(ast, env);
+ if (!el || mal_error) { return NULL; }
+ MalVal *f = _first(el),
+ *args = _rest(el);
+ assert_type(f, MAL_FUNCTION_C|MAL_FUNCTION_MAL,
+ "cannot apply '%s'", _pr_str(f,1));
+ if (f->type & MAL_FUNCTION_MAL) {
+ ast = f->val.func.body;
+ env = new_env(f->val.func.env, f->val.func.args, args);
// Continue loop
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("fn*", a0->val.string) == 0) {
- //g_print("eval apply fn*\n");
- MalVal *mf = malval_new(MAL_FUNCTION_MAL, NULL);
- mf->val.func.evaluator = EVAL;
- mf->val.func.args = _nth(ast, 1);
- mf->val.func.body = _nth(ast, 2);
- mf->val.func.env = env;
- return mf;
} else {
- //g_print("eval apply\n");
- MalVal *el = eval_ast(ast, env);
- if (!el || mal_error) { return NULL; }
- MalVal *f = first(el),
- *args = rest(el);
- assert_type(f, MAL_FUNCTION_C|MAL_FUNCTION_MAL,
- "cannot invoke '%s'", _pr_str(f,1));
- if (f->type & MAL_FUNCTION_MAL) {
- ast = f->val.func.body;
- env = new_env(f->val.func.env, f->val.func.args, args);
- // Continue loop
- } else {
- return _apply(f, args);
- }
+ return _apply(f, args);
}
}
+
+ } // TCO while loop
}
// print
@@ -182,58 +182,20 @@ MalVal *RE(Env *env, char *prompt, char *str) {
// Setup the initial REPL environment
Env *repl_env;
-char *slurp_raw(char *path) {
- char *data;
- struct stat fst;
- int fd = open(path, O_RDONLY),
- sz;
- if (fd < 0) {
- abort("slurp failed to open '%s'", path);
- }
- if (fstat(fd, &fst) < 0) {
- abort("slurp failed to stat '%s'", path);
- }
- data = malloc(fst.st_size+1);
- sz = read(fd, data, fst.st_size);
- if (sz < fst.st_size) {
- abort("slurp failed to read '%s'", path);
- }
- data[sz] = '\0';
- return data;
-}
-
void init_repl_env() {
- void _ref(char *name, MalVal*(*func)(MalVal*), int arg_cnt) {
- void *(*f)(void *) = (void*(*)(void*))func;
- env_set(repl_env, name, malval_new_function(f, arg_cnt, NULL));
- }
repl_env = new_env(NULL, NULL, NULL);
+ // core.c: defined using C
int i;
for(i=0; i< (sizeof(core_ns) / sizeof(core_ns[0])); i++) {
- MalVal *(*f)(MalVal *) = (MalVal*(*)(MalVal*))core_ns[i].func;
- _ref(core_ns[i].name, f, core_ns[i].arg_cnt);
- }
-
- MalVal *read_string(MalVal *str) {
- assert_type(str, MAL_STRING, "read_string of non-string");
- return read_str(str->val.string);
- }
- _ref("read-string", read_string, 1);
-
- MalVal *do_eval(MalVal *ast) {
- return EVAL(ast, repl_env);
+ env_set(repl_env, core_ns[i].name,
+ malval_new_function(core_ns[i].func, core_ns[i].arg_cnt));
}
- _ref("eval", do_eval, 1);
-
- MalVal *slurp(MalVal *path) {
- assert_type(path, MAL_STRING, "slurp of non-string");
- char *data = slurp_raw(path->val.string);
- if (!data || mal_error) { return NULL; }
- return malval_new_string(data);
- }
- _ref("slurp", slurp, 1);
+ MalVal *do_eval(MalVal *ast) { return EVAL(ast, repl_env); }
+ env_set(repl_env, "eval",
+ malval_new_function((void*(*)(void *))do_eval, 1));
+ // core.mal: defined using the language itself
RE(repl_env, "", "(def! not (fn* (a) (if a false true)))");
RE(repl_env, "",
"(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
@@ -252,21 +214,22 @@ int main(int argc, char *argv[])
if (argc > 1) {
char *cmd = g_strdup_printf("(load-file \"%s\")", argv[1]);
RE(repl_env, "", cmd);
- } else {
- // REPL loop
- for(;;) {
- exp = RE(repl_env, prompt, NULL);
- if (mal_error && strcmp("EOF", mal_error->val.string) == 0) {
- return 0;
- }
- output = PRINT(exp);
+ return 0;
+ }
- if (output) {
- g_print("%s\n", output);
- free(output); // Free output string
- }
+ // REPL loop
+ for(;;) {
+ exp = RE(repl_env, prompt, NULL);
+ if (mal_error && strcmp("EOF", mal_error->val.string) == 0) {
+ return 0;
+ }
+ output = PRINT(exp);
- //malval_free(exp); // Free evaluated expression
+ if (output) {
+ g_print("%s\n", output);
+ free(output); // Free output string
}
+
+ //malval_free(exp); // Free evaluated expression
}
}
diff --git a/c/step7_quote.c b/c/step7_quote.c
index 7da47ee..ac17955 100644
--- a/c/step7_quote.c
+++ b/c/step7_quote.c
@@ -1,13 +1,11 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
-#include <sys/stat.h>
-#include <fcntl.h>
+
#include "types.h"
#include "readline.h"
#include "reader.h"
#include "core.h"
-#include "interop.h"
// Declarations
MalVal *EVAL(MalVal *ast, Env *env);
@@ -49,12 +47,12 @@ MalVal *quasiquote(MalVal *ast) {
strcmp("splice-unquote", a00->val.string) == 0) {
return _listX(3, malval_new_symbol("concat"),
_nth(a0, 1),
- quasiquote(rest(ast)));
+ quasiquote(_rest(ast)));
}
}
return _listX(3, malval_new_symbol("cons"),
quasiquote(a0),
- quasiquote(rest(ast)));
+ quasiquote(_rest(ast)));
}
}
@@ -83,7 +81,7 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
MalVal *new_val = EVAL((MalVal *)value, env);
g_array_append_val(seq->val.array, new_val);
}
- return hash_map(seq);
+ return _hash_map(seq);
} else {
//g_print("EVAL scalar: %s\n", _pr_str(ast,1));
return ast;
@@ -92,102 +90,104 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
MalVal *EVAL(MalVal *ast, Env *env) {
while (TRUE) {
- if (!ast || mal_error) return NULL;
- //g_print("EVAL: %s\n", _pr_str(ast,1));
- if (ast->type != MAL_LIST) {
- return eval_ast(ast, env);
- }
- if (!ast || mal_error) return NULL;
- // apply list
- //g_print("EVAL apply list: %s\n", _pr_str(ast,1));
- int i, len;
- if (_count(ast) == 0) { return ast; }
- MalVal *a0 = _nth(ast, 0);
- if ((a0->type & MAL_SYMBOL) &&
- strcmp("def!", a0->val.string) == 0) {
- //g_print("eval apply def!\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2);
- MalVal *res = EVAL(a2, env);
- env_set(env, a1->val.string, res);
- return res;
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("let*", a0->val.string) == 0) {
- //g_print("eval apply let*\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2),
- *key, *val;
- assert_type(a1, MAL_LIST|MAL_VECTOR,
- "let* bindings must be list or vector");
- len = _count(a1);
- assert((len % 2) == 0, "odd number of let* bindings forms");
- Env *let_env = new_env(env, NULL, NULL);
- for(i=0; i<len; i+=2) {
- key = g_array_index(a1->val.array, MalVal*, i);
- val = g_array_index(a1->val.array, MalVal*, i+1);
- assert_type(key, MAL_SYMBOL, "let* bind to non-symbol");
- env_set(let_env, key->val.string, EVAL(val, let_env));
- }
- return EVAL(a2, let_env);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("quote", a0->val.string) == 0) {
- //g_print("eval apply quote\n");
- return _nth(ast, 1);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("quasiquote", a0->val.string) == 0) {
- //g_print("eval apply quasiquote\n");
- MalVal *a1 = _nth(ast, 1);
- return EVAL(quasiquote(a1), env);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("do", a0->val.string) == 0) {
- //g_print("eval apply do\n");
- eval_ast(_slice(ast, 1, _count(ast)-1), env);
- ast = last(ast);
- // Continue loop
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("if", a0->val.string) == 0) {
- //g_print("eval apply if\n");
- MalVal *a1 = _nth(ast, 1);
- MalVal *cond = EVAL(a1, env);
- if (!cond || mal_error) return NULL;
- if (cond->type & (MAL_FALSE|MAL_NIL)) {
- // eval false slot form
- ast = _nth(ast, 3);
- if (!ast) {
- return &mal_nil;
- }
- } else {
- // eval true slot form
- ast = _nth(ast, 2);
+ if (!ast || mal_error) return NULL;
+ //g_print("EVAL: %s\n", _pr_str(ast,1));
+ if (ast->type != MAL_LIST) {
+ return eval_ast(ast, env);
+ }
+ if (!ast || mal_error) return NULL;
+
+ // apply list
+ //g_print("EVAL apply list: %s\n", _pr_str(ast,1));
+ int i, len;
+ if (_count(ast) == 0) { return ast; }
+ MalVal *a0 = _nth(ast, 0);
+ if ((a0->type & MAL_SYMBOL) &&
+ strcmp("def!", a0->val.string) == 0) {
+ //g_print("eval apply def!\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2);
+ MalVal *res = EVAL(a2, env);
+ env_set(env, a1->val.string, res);
+ return res;
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("let*", a0->val.string) == 0) {
+ //g_print("eval apply let*\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2),
+ *key, *val;
+ assert_type(a1, MAL_LIST|MAL_VECTOR,
+ "let* bindings must be list or vector");
+ len = _count(a1);
+ assert((len % 2) == 0, "odd number of let* bindings forms");
+ Env *let_env = new_env(env, NULL, NULL);
+ for(i=0; i<len; i+=2) {
+ key = g_array_index(a1->val.array, MalVal*, i);
+ val = g_array_index(a1->val.array, MalVal*, i+1);
+ assert_type(key, MAL_SYMBOL, "let* bind to non-symbol");
+ env_set(let_env, key->val.string, EVAL(val, let_env));
+ }
+ return EVAL(a2, let_env);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("quote", a0->val.string) == 0) {
+ //g_print("eval apply quote\n");
+ return _nth(ast, 1);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("quasiquote", a0->val.string) == 0) {
+ //g_print("eval apply quasiquote\n");
+ MalVal *a1 = _nth(ast, 1);
+ return EVAL(quasiquote(a1), env);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("do", a0->val.string) == 0) {
+ //g_print("eval apply do\n");
+ eval_ast(_slice(ast, 1, _count(ast)-1), env);
+ ast = _last(ast);
+ // Continue loop
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("if", a0->val.string) == 0) {
+ //g_print("eval apply if\n");
+ MalVal *a1 = _nth(ast, 1);
+ MalVal *cond = EVAL(a1, env);
+ if (!cond || mal_error) return NULL;
+ if (cond->type & (MAL_FALSE|MAL_NIL)) {
+ // eval false slot form
+ ast = _nth(ast, 3);
+ if (!ast) {
+ return &mal_nil;
}
+ } else {
+ // eval true slot form
+ ast = _nth(ast, 2);
+ }
+ // Continue loop
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("fn*", a0->val.string) == 0) {
+ //g_print("eval apply fn*\n");
+ MalVal *mf = malval_new(MAL_FUNCTION_MAL, NULL);
+ mf->val.func.evaluator = EVAL;
+ mf->val.func.args = _nth(ast, 1);
+ mf->val.func.body = _nth(ast, 2);
+ mf->val.func.env = env;
+ return mf;
+ } else {
+ //g_print("eval apply\n");
+ MalVal *el = eval_ast(ast, env);
+ if (!el || mal_error) { return NULL; }
+ MalVal *f = _first(el),
+ *args = _rest(el);
+ assert_type(f, MAL_FUNCTION_C|MAL_FUNCTION_MAL,
+ "cannot apply '%s'", _pr_str(f,1));
+ if (f->type & MAL_FUNCTION_MAL) {
+ ast = f->val.func.body;
+ env = new_env(f->val.func.env, f->val.func.args, args);
// Continue loop
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("fn*", a0->val.string) == 0) {
- //g_print("eval apply fn*\n");
- MalVal *mf = malval_new(MAL_FUNCTION_MAL, NULL);
- mf->val.func.evaluator = EVAL;
- mf->val.func.args = _nth(ast, 1);
- mf->val.func.body = _nth(ast, 2);
- mf->val.func.env = env;
- return mf;
} else {
- //g_print("eval apply\n");
- MalVal *el = eval_ast(ast, env);
- if (!el || mal_error) { return NULL; }
- MalVal *f = first(el),
- *args = rest(el);
- assert_type(f, MAL_FUNCTION_C|MAL_FUNCTION_MAL,
- "cannot invoke '%s'", _pr_str(f,1));
- if (f->type & MAL_FUNCTION_MAL) {
- ast = f->val.func.body;
- env = new_env(f->val.func.env, f->val.func.args, args);
- // Continue loop
- } else {
- return _apply(f, args);
- }
+ return _apply(f, args);
}
}
+
+ } // TCO while loop
}
// print
@@ -218,58 +218,20 @@ MalVal *RE(Env *env, char *prompt, char *str) {
// Setup the initial REPL environment
Env *repl_env;
-char *slurp_raw(char *path) {
- char *data;
- struct stat fst;
- int fd = open(path, O_RDONLY),
- sz;
- if (fd < 0) {
- abort("slurp failed to open '%s'", path);
- }
- if (fstat(fd, &fst) < 0) {
- abort("slurp failed to stat '%s'", path);
- }
- data = malloc(fst.st_size+1);
- sz = read(fd, data, fst.st_size);
- if (sz < fst.st_size) {
- abort("slurp failed to read '%s'", path);
- }
- data[sz] = '\0';
- return data;
-}
-
void init_repl_env() {
- void _ref(char *name, MalVal*(*func)(MalVal*), int arg_cnt) {
- void *(*f)(void *) = (void*(*)(void*))func;
- env_set(repl_env, name, malval_new_function(f, arg_cnt, NULL));
- }
repl_env = new_env(NULL, NULL, NULL);
+ // core.c: defined using C
int i;
for(i=0; i< (sizeof(core_ns) / sizeof(core_ns[0])); i++) {
- MalVal *(*f)(MalVal *) = (MalVal*(*)(MalVal*))core_ns[i].func;
- _ref(core_ns[i].name, f, core_ns[i].arg_cnt);
- }
-
- MalVal *read_string(MalVal *str) {
- assert_type(str, MAL_STRING, "read_string of non-string");
- return read_str(str->val.string);
- }
- _ref("read-string", read_string, 1);
-
- MalVal *do_eval(MalVal *ast) {
- return EVAL(ast, repl_env);
+ env_set(repl_env, core_ns[i].name,
+ malval_new_function(core_ns[i].func, core_ns[i].arg_cnt));
}
- _ref("eval", do_eval, 1);
-
- MalVal *slurp(MalVal *path) {
- assert_type(path, MAL_STRING, "slurp of non-string");
- char *data = slurp_raw(path->val.string);
- if (!data || mal_error) { return NULL; }
- return malval_new_string(data);
- }
- _ref("slurp", slurp, 1);
+ MalVal *do_eval(MalVal *ast) { return EVAL(ast, repl_env); }
+ env_set(repl_env, "eval",
+ malval_new_function((void*(*)(void *))do_eval, 1));
+ // core.mal: defined using the language itself
RE(repl_env, "", "(def! not (fn* (a) (if a false true)))");
RE(repl_env, "",
"(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
@@ -288,21 +250,22 @@ int main(int argc, char *argv[])
if (argc > 1) {
char *cmd = g_strdup_printf("(load-file \"%s\")", argv[1]);
RE(repl_env, "", cmd);
- } else {
- // REPL loop
- for(;;) {
- exp = RE(repl_env, prompt, NULL);
- if (mal_error && strcmp("EOF", mal_error->val.string) == 0) {
- return 0;
- }
- output = PRINT(exp);
+ return 0;
+ }
- if (output) {
- g_print("%s\n", output);
- free(output); // Free output string
- }
+ // REPL loop
+ for(;;) {
+ exp = RE(repl_env, prompt, NULL);
+ if (mal_error && strcmp("EOF", mal_error->val.string) == 0) {
+ return 0;
+ }
+ output = PRINT(exp);
- //malval_free(exp); // Free evaluated expression
+ if (output) {
+ g_print("%s\n", output);
+ free(output); // Free output string
}
+
+ //malval_free(exp); // Free evaluated expression
}
}
diff --git a/c/step8_macros.c b/c/step8_macros.c
index eb715b1..93c83fa 100644
--- a/c/step8_macros.c
+++ b/c/step8_macros.c
@@ -1,13 +1,11 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
-#include <sys/stat.h>
-#include <fcntl.h>
+
#include "types.h"
#include "readline.h"
#include "reader.h"
#include "core.h"
-#include "interop.h"
// Declarations
MalVal *EVAL(MalVal *ast, Env *env);
@@ -50,12 +48,12 @@ MalVal *quasiquote(MalVal *ast) {
strcmp("splice-unquote", a00->val.string) == 0) {
return _listX(3, malval_new_symbol("concat"),
_nth(a0, 1),
- quasiquote(rest(ast)));
+ quasiquote(_rest(ast)));
}
}
return _listX(3, malval_new_symbol("cons"),
quasiquote(a0),
- quasiquote(rest(ast)));
+ quasiquote(_rest(ast)));
}
}
@@ -73,7 +71,7 @@ MalVal *macroexpand(MalVal *ast, Env *env) {
MalVal *a0 = _nth(ast, 0);
MalVal *mac = env_get(env, a0->val.string);
// TODO: this is weird and limits it to 20. FIXME
- ast = _apply(mac, rest(ast));
+ ast = _apply(mac, _rest(ast));
}
return ast;
}
@@ -103,7 +101,7 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
MalVal *new_val = EVAL((MalVal *)value, env);
g_array_append_val(seq->val.array, new_val);
}
- return hash_map(seq);
+ return _hash_map(seq);
} else {
//g_print("EVAL scalar: %s\n", _pr_str(ast,1));
return ast;
@@ -112,121 +110,123 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
MalVal *EVAL(MalVal *ast, Env *env) {
while (TRUE) {
- if (!ast || mal_error) return NULL;
- //g_print("EVAL: %s\n", _pr_str(ast,1));
- if (ast->type != MAL_LIST) {
- return eval_ast(ast, env);
- }
- if (!ast || mal_error) return NULL;
- // apply list
- //g_print("EVAL apply list: %s\n", _pr_str(ast,1));
- ast = macroexpand(ast, env);
- if (!ast || mal_error) return NULL;
- if (ast->type != MAL_LIST) { return ast; }
- if (_count(ast) == 0) { return ast; }
+ if (!ast || mal_error) return NULL;
+ //g_print("EVAL: %s\n", _pr_str(ast,1));
+ if (ast->type != MAL_LIST) {
+ return eval_ast(ast, env);
+ }
+ if (!ast || mal_error) return NULL;
- int i, len;
- MalVal *a0 = _nth(ast, 0);
- if ((a0->type & MAL_SYMBOL) &&
- strcmp("def!", a0->val.string) == 0) {
- //g_print("eval apply def!\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2);
- MalVal *res = EVAL(a2, env);
- env_set(env, a1->val.string, res);
- return res;
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("let*", a0->val.string) == 0) {
- //g_print("eval apply let*\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2),
- *key, *val;
- assert_type(a1, MAL_LIST|MAL_VECTOR,
- "let* bindings must be list or vector");
- len = _count(a1);
- assert((len % 2) == 0, "odd number of let* bindings forms");
- Env *let_env = new_env(env, NULL, NULL);
- for(i=0; i<len; i+=2) {
- key = g_array_index(a1->val.array, MalVal*, i);
- val = g_array_index(a1->val.array, MalVal*, i+1);
- assert_type(key, MAL_SYMBOL, "let* bind to non-symbol");
- env_set(let_env, key->val.string, EVAL(val, let_env));
- }
- return EVAL(a2, let_env);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("quote", a0->val.string) == 0) {
- //g_print("eval apply quote\n");
- return _nth(ast, 1);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("quasiquote", a0->val.string) == 0) {
- //g_print("eval apply quasiquote\n");
- MalVal *a1 = _nth(ast, 1);
- return EVAL(quasiquote(a1), env);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("defmacro!", a0->val.string) == 0) {
- //g_print("eval apply defmacro!\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2);
- MalVal *res = EVAL(a2, env);
- res->ismacro = TRUE;
- env_set(env, a1->val.string, res);
- return res;
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("macroexpand", a0->val.string) == 0) {
- //g_print("eval apply macroexpand\n");
- MalVal *a1 = _nth(ast, 1);
- return macroexpand(a1, env);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("do", a0->val.string) == 0) {
- //g_print("eval apply do\n");
- eval_ast(_slice(ast, 1, _count(ast)-1), env);
- ast = last(ast);
- // Continue loop
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("if", a0->val.string) == 0) {
- //g_print("eval apply if\n");
- MalVal *a1 = _nth(ast, 1);
- MalVal *cond = EVAL(a1, env);
- if (!cond || mal_error) return NULL;
- if (cond->type & (MAL_FALSE|MAL_NIL)) {
- // eval false slot form
- ast = _nth(ast, 3);
- if (!ast) {
- return &mal_nil;
- }
- } else {
- // eval true slot form
- ast = _nth(ast, 2);
+ // apply list
+ //g_print("EVAL apply list: %s\n", _pr_str(ast,1));
+ ast = macroexpand(ast, env);
+ if (!ast || mal_error) return NULL;
+ if (ast->type != MAL_LIST) { return ast; }
+ if (_count(ast) == 0) { return ast; }
+
+ int i, len;
+ MalVal *a0 = _nth(ast, 0);
+ if ((a0->type & MAL_SYMBOL) &&
+ strcmp("def!", a0->val.string) == 0) {
+ //g_print("eval apply def!\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2);
+ MalVal *res = EVAL(a2, env);
+ env_set(env, a1->val.string, res);
+ return res;
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("let*", a0->val.string) == 0) {
+ //g_print("eval apply let*\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2),
+ *key, *val;
+ assert_type(a1, MAL_LIST|MAL_VECTOR,
+ "let* bindings must be list or vector");
+ len = _count(a1);
+ assert((len % 2) == 0, "odd number of let* bindings forms");
+ Env *let_env = new_env(env, NULL, NULL);
+ for(i=0; i<len; i+=2) {
+ key = g_array_index(a1->val.array, MalVal*, i);
+ val = g_array_index(a1->val.array, MalVal*, i+1);
+ assert_type(key, MAL_SYMBOL, "let* bind to non-symbol");
+ env_set(let_env, key->val.string, EVAL(val, let_env));
+ }
+ return EVAL(a2, let_env);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("quote", a0->val.string) == 0) {
+ //g_print("eval apply quote\n");
+ return _nth(ast, 1);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("quasiquote", a0->val.string) == 0) {
+ //g_print("eval apply quasiquote\n");
+ MalVal *a1 = _nth(ast, 1);
+ return EVAL(quasiquote(a1), env);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("defmacro!", a0->val.string) == 0) {
+ //g_print("eval apply defmacro!\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2);
+ MalVal *res = EVAL(a2, env);
+ res->ismacro = TRUE;
+ env_set(env, a1->val.string, res);
+ return res;
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("macroexpand", a0->val.string) == 0) {
+ //g_print("eval apply macroexpand\n");
+ MalVal *a1 = _nth(ast, 1);
+ return macroexpand(a1, env);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("do", a0->val.string) == 0) {
+ //g_print("eval apply do\n");
+ eval_ast(_slice(ast, 1, _count(ast)-1), env);
+ ast = _last(ast);
+ // Continue loop
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("if", a0->val.string) == 0) {
+ //g_print("eval apply if\n");
+ MalVal *a1 = _nth(ast, 1);
+ MalVal *cond = EVAL(a1, env);
+ if (!cond || mal_error) return NULL;
+ if (cond->type & (MAL_FALSE|MAL_NIL)) {
+ // eval false slot form
+ ast = _nth(ast, 3);
+ if (!ast) {
+ return &mal_nil;
}
+ } else {
+ // eval true slot form
+ ast = _nth(ast, 2);
+ }
+ // Continue loop
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("fn*", a0->val.string) == 0) {
+ //g_print("eval apply fn*\n");
+ MalVal *mf = malval_new(MAL_FUNCTION_MAL, NULL);
+ mf->ismacro = FALSE;
+ mf->val.func.evaluator = EVAL;
+ mf->val.func.args = _nth(ast, 1);
+ mf->val.func.body = _nth(ast, 2);
+ mf->val.func.env = env;
+ return mf;
+ } else {
+ //g_print("eval apply\n");
+ MalVal *el = eval_ast(ast, env);
+ if (!el || mal_error) { return NULL; }
+ MalVal *f = _first(el),
+ *args = _rest(el);
+ assert_type(f, MAL_FUNCTION_C|MAL_FUNCTION_MAL,
+ "cannot apply '%s'", _pr_str(f,1));
+ if (f->type & MAL_FUNCTION_MAL) {
+ ast = f->val.func.body;
+ env = new_env(f->val.func.env, f->val.func.args, args);
// Continue loop
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("fn*", a0->val.string) == 0) {
- //g_print("eval apply fn*\n");
- MalVal *mf = malval_new(MAL_FUNCTION_MAL, NULL);
- mf->ismacro = FALSE;
- mf->val.func.evaluator = EVAL;
- mf->val.func.args = _nth(ast, 1);
- mf->val.func.body = _nth(ast, 2);
- mf->val.func.env = env;
- return mf;
} else {
- //g_print("eval apply\n");
- MalVal *el = eval_ast(ast, env);
- if (!el || mal_error) { return NULL; }
- MalVal *f = first(el),
- *args = rest(el);
- assert_type(f, MAL_FUNCTION_C|MAL_FUNCTION_MAL,
- "cannot invoke '%s'", _pr_str(f,1));
- if (f->type & MAL_FUNCTION_MAL) {
- ast = f->val.func.body;
- env = new_env(f->val.func.env, f->val.func.args, args);
- // Continue loop
- } else {
- return _apply(f, args);
- }
+ return _apply(f, args);
}
}
+
+ } // TCO while loop
}
// print
@@ -257,61 +257,25 @@ MalVal *RE(Env *env, char *prompt, char *str) {
// Setup the initial REPL environment
Env *repl_env;
-char *slurp_raw(char *path) {
- char *data;
- struct stat fst;
- int fd = open(path, O_RDONLY),
- sz;
- if (fd < 0) {
- abort("slurp failed to open '%s'", path);
- }
- if (fstat(fd, &fst) < 0) {
- abort("slurp failed to stat '%s'", path);
- }
- data = malloc(fst.st_size+1);
- sz = read(fd, data, fst.st_size);
- if (sz < fst.st_size) {
- abort("slurp failed to read '%s'", path);
- }
- data[sz] = '\0';
- return data;
-}
-
void init_repl_env() {
- void _ref(char *name, MalVal*(*func)(MalVal*), int arg_cnt) {
- void *(*f)(void *) = (void*(*)(void*))func;
- env_set(repl_env, name, malval_new_function(f, arg_cnt, NULL));
- }
repl_env = new_env(NULL, NULL, NULL);
+ // core.c: defined using C
int i;
for(i=0; i< (sizeof(core_ns) / sizeof(core_ns[0])); i++) {
- MalVal *(*f)(MalVal *) = (MalVal*(*)(MalVal*))core_ns[i].func;
- _ref(core_ns[i].name, f, core_ns[i].arg_cnt);
- }
-
- MalVal *read_string(MalVal *str) {
- assert_type(str, MAL_STRING, "read_string of non-string");
- return read_str(str->val.string);
- }
- _ref("read-string", read_string, 1);
-
- MalVal *do_eval(MalVal *ast) {
- return EVAL(ast, repl_env);
- }
- _ref("eval", do_eval, 1);
-
- MalVal *slurp(MalVal *path) {
- assert_type(path, MAL_STRING, "slurp of non-string");
- char *data = slurp_raw(path->val.string);
- if (!data || mal_error) { return NULL; }
- return malval_new_string(data);
+ env_set(repl_env, core_ns[i].name,
+ malval_new_function(core_ns[i].func, core_ns[i].arg_cnt));
}
- _ref("slurp", slurp, 1);
+ MalVal *do_eval(MalVal *ast) { return EVAL(ast, repl_env); }
+ env_set(repl_env, "eval",
+ malval_new_function((void*(*)(void *))do_eval, 1));
+ // core.mal: defined using the language itself
RE(repl_env, "", "(def! not (fn* (a) (if a false true)))");
RE(repl_env, "",
"(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
+ RE(repl_env, "", "(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)))))))");
+ RE(repl_env, "", "(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))))))))");
}
int main(int argc, char *argv[])
@@ -327,21 +291,22 @@ int main(int argc, char *argv[])
if (argc > 1) {
char *cmd = g_strdup_printf("(load-file \"%s\")", argv[1]);
RE(repl_env, "", cmd);
- } else {
- // REPL loop
- for(;;) {
- exp = RE(repl_env, prompt, NULL);
- if (mal_error && strcmp("EOF", mal_error->val.string) == 0) {
- return 0;
- }
- output = PRINT(exp);
+ return 0;
+ }
- if (output) {
- g_print("%s\n", output);
- free(output); // Free output string
- }
+ // REPL loop
+ for(;;) {
+ exp = RE(repl_env, prompt, NULL);
+ if (mal_error && strcmp("EOF", mal_error->val.string) == 0) {
+ return 0;
+ }
+ output = PRINT(exp);
- //malval_free(exp); // Free evaluated expression
+ if (output) {
+ g_print("%s\n", output);
+ free(output); // Free output string
}
+
+ //malval_free(exp); // Free evaluated expression
}
}
diff --git a/c/step9_interop.c b/c/step9_interop.c
index dcd1526..743fb22 100644
--- a/c/step9_interop.c
+++ b/c/step9_interop.c
@@ -1,8 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
-#include <sys/stat.h>
-#include <fcntl.h>
+
#include "types.h"
#include "readline.h"
#include "reader.h"
@@ -50,12 +49,12 @@ MalVal *quasiquote(MalVal *ast) {
strcmp("splice-unquote", a00->val.string) == 0) {
return _listX(3, malval_new_symbol("concat"),
_nth(a0, 1),
- quasiquote(rest(ast)));
+ quasiquote(_rest(ast)));
}
}
return _listX(3, malval_new_symbol("cons"),
quasiquote(a0),
- quasiquote(rest(ast)));
+ quasiquote(_rest(ast)));
}
}
@@ -73,7 +72,7 @@ MalVal *macroexpand(MalVal *ast, Env *env) {
MalVal *a0 = _nth(ast, 0);
MalVal *mac = env_get(env, a0->val.string);
// TODO: this is weird and limits it to 20. FIXME
- ast = _apply(mac, rest(ast));
+ ast = _apply(mac, _rest(ast));
}
return ast;
}
@@ -103,7 +102,7 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
MalVal *new_val = EVAL((MalVal *)value, env);
g_array_append_val(seq->val.array, new_val);
}
- return hash_map(seq);
+ return _hash_map(seq);
} else {
//g_print("EVAL scalar: %s\n", _pr_str(ast,1));
return ast;
@@ -112,126 +111,128 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
MalVal *EVAL(MalVal *ast, Env *env) {
while (TRUE) {
- if (!ast || mal_error) return NULL;
- //g_print("EVAL: %s\n", _pr_str(ast,1));
- if (ast->type != MAL_LIST) {
- return eval_ast(ast, env);
- }
- if (!ast || mal_error) return NULL;
- // apply list
- //g_print("EVAL apply list: %s\n", _pr_str(ast,1));
- ast = macroexpand(ast, env);
- if (!ast || mal_error) return NULL;
- if (ast->type != MAL_LIST) { return ast; }
- if (_count(ast) == 0) { return ast; }
+ if (!ast || mal_error) return NULL;
+ //g_print("EVAL: %s\n", _pr_str(ast,1));
+ if (ast->type != MAL_LIST) {
+ return eval_ast(ast, env);
+ }
+ if (!ast || mal_error) return NULL;
- int i, len;
- MalVal *a0 = _nth(ast, 0);
- if ((a0->type & MAL_SYMBOL) &&
- strcmp("def!", a0->val.string) == 0) {
- //g_print("eval apply def!\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2);
- MalVal *res = EVAL(a2, env);
- env_set(env, a1->val.string, res);
- return res;
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("let*", a0->val.string) == 0) {
- //g_print("eval apply let*\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2),
- *key, *val;
- assert_type(a1, MAL_LIST|MAL_VECTOR,
- "let* bindings must be list or vector");
- len = _count(a1);
- assert((len % 2) == 0, "odd number of let* bindings forms");
- Env *let_env = new_env(env, NULL, NULL);
- for(i=0; i<len; i+=2) {
- key = g_array_index(a1->val.array, MalVal*, i);
- val = g_array_index(a1->val.array, MalVal*, i+1);
- assert_type(key, MAL_SYMBOL, "let* bind to non-symbol");
- env_set(let_env, key->val.string, EVAL(val, let_env));
- }
- return EVAL(a2, let_env);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("quote", a0->val.string) == 0) {
- //g_print("eval apply quote\n");
- return _nth(ast, 1);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("quasiquote", a0->val.string) == 0) {
- //g_print("eval apply quasiquote\n");
- MalVal *a1 = _nth(ast, 1);
- return EVAL(quasiquote(a1), env);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("defmacro!", a0->val.string) == 0) {
- //g_print("eval apply defmacro!\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2);
- MalVal *res = EVAL(a2, env);
- res->ismacro = TRUE;
- env_set(env, a1->val.string, res);
- return res;
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("macroexpand", a0->val.string) == 0) {
- //g_print("eval apply macroexpand\n");
- MalVal *a1 = _nth(ast, 1);
- return macroexpand(a1, env);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp(".", a0->val.string) == 0) {
- //g_print("eval apply .\n");
- MalVal *el = eval_ast(_slice(ast, 1, _count(ast)), env);
- return invoke_native(el);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("do", a0->val.string) == 0) {
- //g_print("eval apply do\n");
- eval_ast(_slice(ast, 1, _count(ast)-1), env);
- ast = last(ast);
- // Continue loop
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("if", a0->val.string) == 0) {
- //g_print("eval apply if\n");
- MalVal *a1 = _nth(ast, 1);
- MalVal *cond = EVAL(a1, env);
- if (!cond || mal_error) return NULL;
- if (cond->type & (MAL_FALSE|MAL_NIL)) {
- // eval false slot form
- ast = _nth(ast, 3);
- if (!ast) {
- return &mal_nil;
- }
- } else {
- // eval true slot form
- ast = _nth(ast, 2);
+ // apply list
+ //g_print("EVAL apply list: %s\n", _pr_str(ast,1));
+ ast = macroexpand(ast, env);
+ if (!ast || mal_error) return NULL;
+ if (ast->type != MAL_LIST) { return ast; }
+ if (_count(ast) == 0) { return ast; }
+
+ int i, len;
+ MalVal *a0 = _nth(ast, 0);
+ if ((a0->type & MAL_SYMBOL) &&
+ strcmp("def!", a0->val.string) == 0) {
+ //g_print("eval apply def!\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2);
+ MalVal *res = EVAL(a2, env);
+ env_set(env, a1->val.string, res);
+ return res;
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("let*", a0->val.string) == 0) {
+ //g_print("eval apply let*\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2),
+ *key, *val;
+ assert_type(a1, MAL_LIST|MAL_VECTOR,
+ "let* bindings must be list or vector");
+ len = _count(a1);
+ assert((len % 2) == 0, "odd number of let* bindings forms");
+ Env *let_env = new_env(env, NULL, NULL);
+ for(i=0; i<len; i+=2) {
+ key = g_array_index(a1->val.array, MalVal*, i);
+ val = g_array_index(a1->val.array, MalVal*, i+1);
+ assert_type(key, MAL_SYMBOL, "let* bind to non-symbol");
+ env_set(let_env, key->val.string, EVAL(val, let_env));
+ }
+ return EVAL(a2, let_env);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("quote", a0->val.string) == 0) {
+ //g_print("eval apply quote\n");
+ return _nth(ast, 1);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("quasiquote", a0->val.string) == 0) {
+ //g_print("eval apply quasiquote\n");
+ MalVal *a1 = _nth(ast, 1);
+ return EVAL(quasiquote(a1), env);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("defmacro!", a0->val.string) == 0) {
+ //g_print("eval apply defmacro!\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2);
+ MalVal *res = EVAL(a2, env);
+ res->ismacro = TRUE;
+ env_set(env, a1->val.string, res);
+ return res;
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("macroexpand", a0->val.string) == 0) {
+ //g_print("eval apply macroexpand\n");
+ MalVal *a1 = _nth(ast, 1);
+ return macroexpand(a1, env);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp(".", a0->val.string) == 0) {
+ //g_print("eval apply .\n");
+ MalVal *el = eval_ast(_slice(ast, 1, _count(ast)), env);
+ return invoke_native(el);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("do", a0->val.string) == 0) {
+ //g_print("eval apply do\n");
+ eval_ast(_slice(ast, 1, _count(ast)-1), env);
+ ast = _last(ast);
+ // Continue loop
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("if", a0->val.string) == 0) {
+ //g_print("eval apply if\n");
+ MalVal *a1 = _nth(ast, 1);
+ MalVal *cond = EVAL(a1, env);
+ if (!cond || mal_error) return NULL;
+ if (cond->type & (MAL_FALSE|MAL_NIL)) {
+ // eval false slot form
+ ast = _nth(ast, 3);
+ if (!ast) {
+ return &mal_nil;
}
+ } else {
+ // eval true slot form
+ ast = _nth(ast, 2);
+ }
+ // Continue loop
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("fn*", a0->val.string) == 0) {
+ //g_print("eval apply fn*\n");
+ MalVal *mf = malval_new(MAL_FUNCTION_MAL, NULL);
+ mf->ismacro = FALSE;
+ mf->val.func.evaluator = EVAL;
+ mf->val.func.args = _nth(ast, 1);
+ mf->val.func.body = _nth(ast, 2);
+ mf->val.func.env = env;
+ return mf;
+ } else {
+ //g_print("eval apply\n");
+ MalVal *el = eval_ast(ast, env);
+ if (!el || mal_error) { return NULL; }
+ MalVal *f = _first(el),
+ *args = _rest(el);
+ assert_type(f, MAL_FUNCTION_C|MAL_FUNCTION_MAL,
+ "cannot apply '%s'", _pr_str(f,1));
+ if (f->type & MAL_FUNCTION_MAL) {
+ ast = f->val.func.body;
+ env = new_env(f->val.func.env, f->val.func.args, args);
// Continue loop
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("fn*", a0->val.string) == 0) {
- //g_print("eval apply fn*\n");
- MalVal *mf = malval_new(MAL_FUNCTION_MAL, NULL);
- mf->ismacro = FALSE;
- mf->val.func.evaluator = EVAL;
- mf->val.func.args = _nth(ast, 1);
- mf->val.func.body = _nth(ast, 2);
- mf->val.func.env = env;
- return mf;
} else {
- //g_print("eval apply\n");
- MalVal *el = eval_ast(ast, env);
- if (!el || mal_error) { return NULL; }
- MalVal *f = first(el),
- *args = rest(el);
- assert_type(f, MAL_FUNCTION_C|MAL_FUNCTION_MAL,
- "cannot invoke '%s'", _pr_str(f,1));
- if (f->type & MAL_FUNCTION_MAL) {
- ast = f->val.func.body;
- env = new_env(f->val.func.env, f->val.func.args, args);
- // Continue loop
- } else {
- return _apply(f, args);
- }
+ return _apply(f, args);
}
}
+
+ } // TCO while loop
}
// print
@@ -262,61 +263,25 @@ MalVal *RE(Env *env, char *prompt, char *str) {
// Setup the initial REPL environment
Env *repl_env;
-char *slurp_raw(char *path) {
- char *data;
- struct stat fst;
- int fd = open(path, O_RDONLY),
- sz;
- if (fd < 0) {
- abort("slurp failed to open '%s'", path);
- }
- if (fstat(fd, &fst) < 0) {
- abort("slurp failed to stat '%s'", path);
- }
- data = malloc(fst.st_size+1);
- sz = read(fd, data, fst.st_size);
- if (sz < fst.st_size) {
- abort("slurp failed to read '%s'", path);
- }
- data[sz] = '\0';
- return data;
-}
-
void init_repl_env() {
- void _ref(char *name, MalVal*(*func)(MalVal*), int arg_cnt) {
- void *(*f)(void *) = (void*(*)(void*))func;
- env_set(repl_env, name, malval_new_function(f, arg_cnt, NULL));
- }
repl_env = new_env(NULL, NULL, NULL);
+ // core.c: defined using C
int i;
for(i=0; i< (sizeof(core_ns) / sizeof(core_ns[0])); i++) {
- MalVal *(*f)(MalVal *) = (MalVal*(*)(MalVal*))core_ns[i].func;
- _ref(core_ns[i].name, f, core_ns[i].arg_cnt);
- }
-
- MalVal *read_string(MalVal *str) {
- assert_type(str, MAL_STRING, "read_string of non-string");
- return read_str(str->val.string);
- }
- _ref("read-string", read_string, 1);
-
- MalVal *do_eval(MalVal *ast) {
- return EVAL(ast, repl_env);
- }
- _ref("eval", do_eval, 1);
-
- MalVal *slurp(MalVal *path) {
- assert_type(path, MAL_STRING, "slurp of non-string");
- char *data = slurp_raw(path->val.string);
- if (!data || mal_error) { return NULL; }
- return malval_new_string(data);
+ env_set(repl_env, core_ns[i].name,
+ malval_new_function(core_ns[i].func, core_ns[i].arg_cnt));
}
- _ref("slurp", slurp, 1);
+ MalVal *do_eval(MalVal *ast) { return EVAL(ast, repl_env); }
+ env_set(repl_env, "eval",
+ malval_new_function((void*(*)(void *))do_eval, 1));
+ // core.mal: defined using the language itself
RE(repl_env, "", "(def! not (fn* (a) (if a false true)))");
RE(repl_env, "",
"(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
+ RE(repl_env, "", "(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)))))))");
+ RE(repl_env, "", "(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))))))))");
}
int main(int argc, char *argv[])
@@ -332,21 +297,22 @@ int main(int argc, char *argv[])
if (argc > 1) {
char *cmd = g_strdup_printf("(load-file \"%s\")", argv[1]);
RE(repl_env, "", cmd);
- } else {
- // REPL loop
- for(;;) {
- exp = RE(repl_env, prompt, NULL);
- if (mal_error && strcmp("EOF", mal_error->val.string) == 0) {
- return 0;
- }
- output = PRINT(exp);
+ return 0;
+ }
- if (output) {
- g_print("%s\n", output);
- free(output); // Free output string
- }
+ // REPL loop
+ for(;;) {
+ exp = RE(repl_env, prompt, NULL);
+ if (mal_error && strcmp("EOF", mal_error->val.string) == 0) {
+ return 0;
+ }
+ output = PRINT(exp);
- //malval_free(exp); // Free evaluated expression
+ if (output) {
+ g_print("%s\n", output);
+ free(output); // Free output string
}
+
+ //malval_free(exp); // Free evaluated expression
}
}
diff --git a/c/stepA_more.c b/c/stepA_more.c
index 4e4152c..82bf3db 100644
--- a/c/stepA_more.c
+++ b/c/stepA_more.c
@@ -1,8 +1,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
-#include <sys/stat.h>
-#include <fcntl.h>
+
#include "types.h"
#include "readline.h"
#include "reader.h"
@@ -50,12 +49,12 @@ MalVal *quasiquote(MalVal *ast) {
strcmp("splice-unquote", a00->val.string) == 0) {
return _listX(3, malval_new_symbol("concat"),
_nth(a0, 1),
- quasiquote(rest(ast)));
+ quasiquote(_rest(ast)));
}
}
return _listX(3, malval_new_symbol("cons"),
quasiquote(a0),
- quasiquote(rest(ast)));
+ quasiquote(_rest(ast)));
}
}
@@ -73,7 +72,7 @@ MalVal *macroexpand(MalVal *ast, Env *env) {
MalVal *a0 = _nth(ast, 0);
MalVal *mac = env_get(env, a0->val.string);
// TODO: this is weird and limits it to 20. FIXME
- ast = _apply(mac, rest(ast));
+ ast = _apply(mac, _rest(ast));
}
return ast;
}
@@ -103,7 +102,7 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
MalVal *new_val = EVAL((MalVal *)value, env);
g_array_append_val(seq->val.array, new_val);
}
- return hash_map(seq);
+ return _hash_map(seq);
} else {
//g_print("EVAL scalar: %s\n", _pr_str(ast,1));
return ast;
@@ -112,147 +111,149 @@ MalVal *eval_ast(MalVal *ast, Env *env) {
MalVal *EVAL(MalVal *ast, Env *env) {
while (TRUE) {
- if (!ast || mal_error) return NULL;
- //g_print("EVAL: %s\n", _pr_str(ast,1));
- if (ast->type != MAL_LIST) {
- return eval_ast(ast, env);
- }
- if (!ast || mal_error) return NULL;
- // apply list
- //g_print("EVAL apply list: %s\n", _pr_str(ast,1));
- ast = macroexpand(ast, env);
- if (!ast || mal_error) return NULL;
- if (ast->type != MAL_LIST) { return ast; }
- if (_count(ast) == 0) { return ast; }
+ if (!ast || mal_error) return NULL;
+ //g_print("EVAL: %s\n", _pr_str(ast,1));
+ if (ast->type != MAL_LIST) {
+ return eval_ast(ast, env);
+ }
+ if (!ast || mal_error) return NULL;
- int i, len;
- MalVal *a0 = _nth(ast, 0);
- if ((a0->type & MAL_SYMBOL) &&
- strcmp("def!", a0->val.string) == 0) {
- //g_print("eval apply def!\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2);
- MalVal *res = EVAL(a2, env);
- env_set(env, a1->val.string, res);
- return res;
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("let*", a0->val.string) == 0) {
- //g_print("eval apply let*\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2),
- *key, *val;
- assert_type(a1, MAL_LIST|MAL_VECTOR,
- "let* bindings must be list or vector");
- len = _count(a1);
- assert((len % 2) == 0, "odd number of let* bindings forms");
- Env *let_env = new_env(env, NULL, NULL);
- for(i=0; i<len; i+=2) {
- key = g_array_index(a1->val.array, MalVal*, i);
- val = g_array_index(a1->val.array, MalVal*, i+1);
- assert_type(key, MAL_SYMBOL, "let* bind to non-symbol");
- env_set(let_env, key->val.string, EVAL(val, let_env));
- }
- return EVAL(a2, let_env);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("quote", a0->val.string) == 0) {
- //g_print("eval apply quote\n");
- return _nth(ast, 1);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("quasiquote", a0->val.string) == 0) {
- //g_print("eval apply quasiquote\n");
- MalVal *a1 = _nth(ast, 1);
- return EVAL(quasiquote(a1), env);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("defmacro!", a0->val.string) == 0) {
- //g_print("eval apply defmacro!\n");
- MalVal *a1 = _nth(ast, 1),
- *a2 = _nth(ast, 2);
- MalVal *res = EVAL(a2, env);
- res->ismacro = TRUE;
- env_set(env, a1->val.string, res);
+ // apply list
+ //g_print("EVAL apply list: %s\n", _pr_str(ast,1));
+ ast = macroexpand(ast, env);
+ if (!ast || mal_error) return NULL;
+ if (ast->type != MAL_LIST) { return ast; }
+ if (_count(ast) == 0) { return ast; }
+
+ int i, len;
+ MalVal *a0 = _nth(ast, 0);
+ if ((a0->type & MAL_SYMBOL) &&
+ strcmp("def!", a0->val.string) == 0) {
+ //g_print("eval apply def!\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2);
+ MalVal *res = EVAL(a2, env);
+ env_set(env, a1->val.string, res);
+ return res;
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("let*", a0->val.string) == 0) {
+ //g_print("eval apply let*\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2),
+ *key, *val;
+ assert_type(a1, MAL_LIST|MAL_VECTOR,
+ "let* bindings must be list or vector");
+ len = _count(a1);
+ assert((len % 2) == 0, "odd number of let* bindings forms");
+ Env *let_env = new_env(env, NULL, NULL);
+ for(i=0; i<len; i+=2) {
+ key = g_array_index(a1->val.array, MalVal*, i);
+ val = g_array_index(a1->val.array, MalVal*, i+1);
+ assert_type(key, MAL_SYMBOL, "let* bind to non-symbol");
+ env_set(let_env, key->val.string, EVAL(val, let_env));
+ }
+ return EVAL(a2, let_env);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("quote", a0->val.string) == 0) {
+ //g_print("eval apply quote\n");
+ return _nth(ast, 1);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("quasiquote", a0->val.string) == 0) {
+ //g_print("eval apply quasiquote\n");
+ MalVal *a1 = _nth(ast, 1);
+ return EVAL(quasiquote(a1), env);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("defmacro!", a0->val.string) == 0) {
+ //g_print("eval apply defmacro!\n");
+ MalVal *a1 = _nth(ast, 1),
+ *a2 = _nth(ast, 2);
+ MalVal *res = EVAL(a2, env);
+ res->ismacro = TRUE;
+ env_set(env, a1->val.string, res);
+ return res;
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("macroexpand", a0->val.string) == 0) {
+ //g_print("eval apply macroexpand\n");
+ MalVal *a1 = _nth(ast, 1);
+ return macroexpand(a1, env);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp(".", a0->val.string) == 0) {
+ //g_print("eval apply .\n");
+ MalVal *el = eval_ast(_slice(ast, 1, _count(ast)), env);
+ return invoke_native(el);
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("try*", a0->val.string) == 0) {
+ //g_print("eval apply try*\n");
+ MalVal *a1 = _nth(ast, 1);
+ MalVal *a2 = _nth(ast, 2);
+ MalVal *res = EVAL(a1, env);
+ if (!mal_error) { return res; }
+ MalVal *a20 = _nth(a2, 0);
+ if (strcmp("catch*", a20->val.string) == 0) {
+ MalVal *a21 = _nth(a2, 1);
+ MalVal *a22 = _nth(a2, 2);
+ Env *catch_env = new_env(env,
+ _listX(1, a21),
+ _listX(1, mal_error));
+ //malval_free(mal_error);
+ mal_error = NULL;
+ res = EVAL(a22, catch_env);
return res;
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("macroexpand", a0->val.string) == 0) {
- //g_print("eval apply macroexpand\n");
- MalVal *a1 = _nth(ast, 1);
- return macroexpand(a1, env);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp(".", a0->val.string) == 0) {
- //g_print("eval apply .\n");
- MalVal *el = eval_ast(_slice(ast, 1, _count(ast)), env);
- return invoke_native(el);
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("try*", a0->val.string) == 0) {
- //g_print("eval apply try*\n");
- MalVal *a1 = _nth(ast, 1);
- MalVal *a2 = _nth(ast, 2);
- MalVal *res = EVAL(a1, env);
- if (!mal_error) { return res; }
- MalVal *a20 = _nth(a2, 0);
- if (strcmp("catch*", a20->val.string) == 0) {
- MalVal *a21 = _nth(a2, 1);
- MalVal *a22 = _nth(a2, 2);
- Env *catch_env = new_env(env,
- _listX(1, a21),
- _listX(1, mal_error));
- //malval_free(mal_error);
- mal_error = NULL;
- res = EVAL(a22, catch_env);
- return res;
- } else {
+ } else {
+ return &mal_nil;
+ }
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("do", a0->val.string) == 0) {
+ //g_print("eval apply do\n");
+ eval_ast(_slice(ast, 1, _count(ast)-1), env);
+ ast = _last(ast);
+ // Continue loop
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("if", a0->val.string) == 0) {
+ //g_print("eval apply if\n");
+ MalVal *a1 = _nth(ast, 1);
+ MalVal *cond = EVAL(a1, env);
+ if (!cond || mal_error) return NULL;
+ if (cond->type & (MAL_FALSE|MAL_NIL)) {
+ // eval false slot form
+ ast = _nth(ast, 3);
+ if (!ast) {
return &mal_nil;
}
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("do", a0->val.string) == 0) {
- //g_print("eval apply do\n");
- eval_ast(_slice(ast, 1, _count(ast)-1), env);
- ast = last(ast);
- // Continue loop
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("if", a0->val.string) == 0) {
- //g_print("eval apply if\n");
- MalVal *a1 = _nth(ast, 1);
- MalVal *cond = EVAL(a1, env);
- if (!cond || mal_error) return NULL;
- if (cond->type & (MAL_FALSE|MAL_NIL)) {
- // eval false slot form
- ast = _nth(ast, 3);
- if (!ast) {
- return &mal_nil;
- }
- } else {
- // eval true slot form
- ast = _nth(ast, 2);
- }
+ } else {
+ // eval true slot form
+ ast = _nth(ast, 2);
+ }
+ // Continue loop
+ } else if ((a0->type & MAL_SYMBOL) &&
+ strcmp("fn*", a0->val.string) == 0) {
+ //g_print("eval apply fn*\n");
+ MalVal *mf = malval_new(MAL_FUNCTION_MAL, NULL);
+ mf->ismacro = FALSE;
+ mf->val.func.evaluator = EVAL;
+ mf->val.func.args = _nth(ast, 1);
+ mf->val.func.body = _nth(ast, 2);
+ mf->val.func.env = env;
+ return mf;
+ } else {
+ //g_print("eval apply\n");
+ MalVal *el = eval_ast(ast, env);
+ if (!el || mal_error) { return NULL; }
+ MalVal *f = _first(el),
+ *args = _rest(el);
+ assert_type(f, MAL_FUNCTION_C|MAL_FUNCTION_MAL,
+ "cannot apply '%s'", _pr_str(f,1));
+ if (f->type & MAL_FUNCTION_MAL) {
+ ast = f->val.func.body;
+ env = new_env(f->val.func.env, f->val.func.args, args);
// Continue loop
- } else if ((a0->type & MAL_SYMBOL) &&
- strcmp("fn*", a0->val.string) == 0) {
- //g_print("eval apply fn*\n");
- MalVal *mf = malval_new(MAL_FUNCTION_MAL, NULL);
- mf->ismacro = FALSE;
- mf->val.func.evaluator = EVAL;
- mf->val.func.args = _nth(ast, 1);
- mf->val.func.body = _nth(ast, 2);
- mf->val.func.env = env;
- return mf;
} else {
- //g_print("eval apply\n");
- MalVal *el = eval_ast(ast, env);
- if (!el || mal_error) { return NULL; }
- MalVal *f = first(el),
- *args = rest(el);
- assert_type(f, MAL_FUNCTION_C|MAL_FUNCTION_MAL,
- "cannot invoke '%s'", _pr_str(f,1));
- if (f->type & MAL_FUNCTION_MAL) {
- ast = f->val.func.body;
- env = new_env(f->val.func.env, f->val.func.args, args);
- // Continue loop
- } else {
- return _apply(f, args);
- }
+ return _apply(f, args);
}
}
+
+ } // TCO while loop
}
// print
@@ -283,71 +284,25 @@ MalVal *RE(Env *env, char *prompt, char *str) {
// Setup the initial REPL environment
Env *repl_env;
-char *slurp_raw(char *path) {
- char *data;
- struct stat fst;
- int fd = open(path, O_RDONLY),
- sz;
- if (fd < 0) {
- abort("slurp failed to open '%s'", path);
- }
- if (fstat(fd, &fst) < 0) {
- abort("slurp failed to stat '%s'", path);
- }
- data = malloc(fst.st_size+1);
- sz = read(fd, data, fst.st_size);
- if (sz < fst.st_size) {
- abort("slurp failed to read '%s'", path);
- }
- data[sz] = '\0';
- return data;
-}
-
void init_repl_env() {
- void _ref(char *name, MalVal*(*func)(MalVal*), int arg_cnt) {
- void *(*f)(void *) = (void*(*)(void*))func;
- env_set(repl_env, name, malval_new_function(f, arg_cnt, NULL));
- }
repl_env = new_env(NULL, NULL, NULL);
+ // core.c: defined using C
int i;
for(i=0; i< (sizeof(core_ns) / sizeof(core_ns[0])); i++) {
- MalVal *(*f)(MalVal *) = (MalVal*(*)(MalVal*))core_ns[i].func;
- _ref(core_ns[i].name, f, core_ns[i].arg_cnt);
- }
-
- MalVal *readline(MalVal *str) {
- assert_type(str, MAL_STRING, "readline of non-string");
- char * line = _readline(str->val.string);
- if (line) { return malval_new_string(line); }
- else { return &mal_nil; }
- }
- _ref("readline", readline, 1);
-
- MalVal *read_string(MalVal *str) {
- assert_type(str, MAL_STRING, "read_string of non-string");
- return read_str(str->val.string);
+ env_set(repl_env, core_ns[i].name,
+ malval_new_function(core_ns[i].func, core_ns[i].arg_cnt));
}
- _ref("read-string", read_string, 1);
-
- MalVal *do_eval(MalVal *ast) {
- return EVAL(ast, repl_env);
- }
- _ref("eval", do_eval, 1);
-
- MalVal *slurp(MalVal *path) {
- assert_type(path, MAL_STRING, "slurp of non-string");
- char *data = slurp_raw(path->val.string);
- if (!data || mal_error) { return NULL; }
- return malval_new_string(data);
- }
- _ref("slurp", slurp, 1);
+ MalVal *do_eval(MalVal *ast) { return EVAL(ast, repl_env); }
+ env_set(repl_env, "eval",
+ malval_new_function((void*(*)(void *))do_eval, 1));
+ // core.mal: defined using the language itself
RE(repl_env, "", "(def! not (fn* (a) (if a false true)))");
- RE(repl_env, "", "(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)))))))");
- RE(repl_env, "", "(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))))))))");
RE(repl_env, "",
"(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
+ RE(repl_env, "", "(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)))))))");
+ RE(repl_env, "", "(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))))))))");
}
int main(int argc, char *argv[])
@@ -363,21 +318,22 @@ int main(int argc, char *argv[])
if (argc > 1) {
char *cmd = g_strdup_printf("(load-file \"%s\")", argv[1]);
RE(repl_env, "", cmd);
- } else {
- // REPL loop
- for(;;) {
- exp = RE(repl_env, prompt, NULL);
- if (mal_error && strcmp("EOF", mal_error->val.string) == 0) {
- return 0;
- }
- output = PRINT(exp);
+ return 0;
+ }
- if (output) {
- g_print("%s\n", output);
- free(output); // Free output string
- }
+ // REPL loop
+ for(;;) {
+ exp = RE(repl_env, prompt, NULL);
+ if (mal_error && strcmp("EOF", mal_error->val.string) == 0) {
+ return 0;
+ }
+ output = PRINT(exp);
- //malval_free(exp); // Free evaluated expression
+ if (output) {
+ g_print("%s\n", output);
+ free(output); // Free output string
}
+
+ //malval_free(exp); // Free evaluated expression
}
}
diff --git a/c/types.c b/c/types.c
index 5c06d9d..3f1771b 100644
--- a/c/types.c
+++ b/c/types.c
@@ -124,8 +124,8 @@ MalVal *malval_new_atom(MalVal *val) {
}
-MalVal *malval_new_function(void *(*func)(void *), int arg_cnt, MalVal* metadata) {
- MalVal *mv = malval_new(MAL_FUNCTION_C, metadata);
+MalVal *malval_new_function(void *(*func)(void *), int arg_cnt) {
+ MalVal *mv = malval_new(MAL_FUNCTION_C, NULL);
mv->func_arg_cnt = arg_cnt;
assert(mv->func_arg_cnt <= 20,
"native function restricted to 20 args (%d given)",
@@ -420,13 +420,37 @@ int _sequential_Q(MalVal *seq) {
MalVal *_nth(MalVal *seq, int idx) {
assert_type(seq, MAL_LIST|MAL_VECTOR,
- "nth called with non-sequential");
+ "_nth called with non-sequential");
if (idx >= _count(seq)) {
return &mal_nil;
}
return g_array_index(seq->val.array, MalVal*, idx);
}
+MalVal *_first(MalVal *seq) {
+ assert_type(seq, MAL_LIST|MAL_VECTOR,
+ "_first called with non-sequential");
+ if (_count(seq) == 0) {
+ return &mal_nil;
+ }
+ return g_array_index(seq->val.array, MalVal*, 0);
+}
+
+MalVal *_last(MalVal *seq) {
+ assert_type(seq, MAL_LIST|MAL_VECTOR,
+ "_last called with non-sequential");
+ if (_count(seq) == 0) {
+ return &mal_nil;
+ }
+ return g_array_index(seq->val.array, MalVal*, _count(seq)-1);
+}
+
+
+MalVal *_rest(MalVal *seq) {
+ return _slice(seq, 1, _count(seq));
+}
+
+
MalVal *_map2(MalVal *(*func)(void*, void*), MalVal *lst, void *arg2) {
MalVal *e, *el;
assert_type(lst, MAL_LIST|MAL_VECTOR,
diff --git a/c/types.h b/c/types.h
index d65e4ef..aa6c5e3 100644
--- a/c/types.h
+++ b/c/types.h
@@ -133,8 +133,19 @@ MalVal *malval_new_symbol(char *val);
MalVal *malval_new_list(MalType type, GArray *val);
MalVal *malval_new_hash_map(GHashTable *val);
MalVal *malval_new_atom(MalVal *val);
-MalVal *malval_new_function(void *(*func)(void *), int arg_cnt, MalVal* metadata);
+MalVal *malval_new_function(void *(*func)(void *), int arg_cnt);
+// Numbers
+#define WRAP_INTEGER_OP(name, op) \
+ MalVal *int_ ## name(MalVal *a, MalVal *b) { \
+ return malval_new_integer(a->val.intnum op b->val.intnum); \
+ }
+#define WRAP_INTEGER_CMP_OP(name, op) \
+ MalVal *int_ ## name(MalVal *a, MalVal *b) { \
+ return a->val.intnum op b->val.intnum ? &mal_true : &mal_false; \
+ }
+
+// Collections
MalVal *_listX(int count, ...);
MalVal *_list(MalVal *args);
MalVal *_vector(MalVal *args);
@@ -148,6 +159,9 @@ char *_pr_str(MalVal *args, int print_readably);
MalVal *_slice(MalVal *seq, int start, int end);
MalVal *_nth(MalVal *seq, int idx);
+MalVal *_first(MalVal *seq);
+MalVal *_rest(MalVal *seq);
+MalVal *_last(MalVal *seq);
MalVal *_map2(MalVal *(*func)(void*, void*), MalVal *lst, void *arg2);
diff --git a/clojure/src/core.clj b/clojure/src/core.clj
index 27599c0..73d8fb4 100644
--- a/clojure/src/core.clj
+++ b/clojure/src/core.clj
@@ -1,4 +1,5 @@
-(ns core)
+(ns core
+ (:require [readline]))
;; Errors/exceptions
(defn mal_throw [obj]
@@ -26,10 +27,14 @@
['true? true?]
['false? false?]
['symbol? symbol?]
+
['pr-str pr-str]
['str str]
['prn prn]
['println println]
+ ['readline readline/readline]
+ ['read-string reader/read-string]
+ ['slurp slurp]
['< <]
['<= <=]
['> >]
diff --git a/clojure/src/step3_env.clj b/clojure/src/step3_env.clj
index 7358b49..cb634ff 100644
--- a/clojure/src/step3_env.clj
+++ b/clojure/src/step3_env.clj
@@ -57,11 +57,10 @@
[strng]
(PRINT (EVAL (READ strng) repl-env)))
-(defn _ref [k,v] (env/env-set repl-env k v))
-(_ref '+ +)
-(_ref '- -)
-(_ref '* *)
-(_ref '/ /)
+(env/env-set repl-env '+ +)
+(env/env-set repl-env '- -)
+(env/env-set repl-env '* *)
+(env/env-set repl-env '/ /)
(defn -main [& args]
diff --git a/clojure/src/step4_if_fn_do.clj b/clojure/src/step4_if_fn_do.clj
index d332a14..49c8b03 100644
--- a/clojure/src/step4_if_fn_do.clj
+++ b/clojure/src/step4_if_fn_do.clj
@@ -73,12 +73,11 @@
[strng]
(PRINT (EVAL (READ strng) repl-env)))
-(defn _ref [k,v] (env/env-set repl-env k v))
+;; core.clj: defined using Clojure
+(doseq [[k v] core/core_ns] (env/env-set repl-env k v))
+(env/env-set repl-env 'eval (fn [ast] (EVAL ast repl-env)))
-;; Import types related functions
-(doseq [[k v] core/core_ns] (_ref k v))
-
-;; Defined using the language itself
+;; core.mal: defined using the language itself
(rep "(def! not (fn* [a] (if a false true)))")
(defn -main [& args]
diff --git a/clojure/src/step5_tco.clj b/clojure/src/step5_tco.clj
index f4f0107..69e09bf 100644
--- a/clojure/src/step5_tco.clj
+++ b/clojure/src/step5_tco.clj
@@ -83,12 +83,11 @@
[strng]
(PRINT (EVAL (READ strng) repl-env)))
-(defn _ref [k,v] (env/env-set repl-env k v))
+;; core.clj: defined using Clojure
+(doseq [[k v] core/core_ns] (env/env-set repl-env k v))
+(env/env-set repl-env 'eval (fn [ast] (EVAL ast repl-env)))
-;; Import types related functions
-(doseq [[k v] core/core_ns] (_ref k v))
-
-;; Defined using the language itself
+;; core.mal: defined using the language itself
(rep "(def! not (fn* [a] (if a false true)))")
(defn -main [& args]
diff --git a/clojure/src/step6_file.clj b/clojure/src/step6_file.clj
index 46bab16..2aeb1be 100644
--- a/clojure/src/step6_file.clj
+++ b/clojure/src/step6_file.clj
@@ -83,16 +83,11 @@
[strng]
(PRINT (EVAL (READ strng) repl-env)))
-(defn _ref [k,v] (env/env-set repl-env k v))
-
-;; Import types related functions
-(doseq [[k v] core/core_ns] (_ref k v))
-
-;; Defined using the language itself
-(_ref 'read-string reader/read-string)
-(_ref 'eval (fn [ast] (EVAL ast repl-env)))
-(_ref 'slurp slurp)
+;; core.clj: defined using Clojure
+(doseq [[k v] core/core_ns] (env/env-set repl-env k v))
+(env/env-set repl-env 'eval (fn [ast] (EVAL ast repl-env)))
+;; 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/clojure/src/step7_quote.clj b/clojure/src/step7_quote.clj
index 5e58e42..774c61f 100644
--- a/clojure/src/step7_quote.clj
+++ b/clojure/src/step7_quote.clj
@@ -106,16 +106,11 @@
[strng]
(PRINT (EVAL (READ strng) repl-env)))
-(defn _ref [k,v] (env/env-set repl-env k v))
-
-;; Import types related functions
-(doseq [[k v] core/core_ns] (_ref k v))
-
-;; Defined using the language itself
-(_ref 'read-string reader/read-string)
-(_ref 'eval (fn [ast] (EVAL ast repl-env)))
-(_ref 'slurp slurp)
+;; core.clj: defined using Clojure
+(doseq [[k v] core/core_ns] (env/env-set repl-env k v))
+(env/env-set repl-env 'eval (fn [ast] (EVAL ast repl-env)))
+;; 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/clojure/src/step8_macros.clj b/clojure/src/step8_macros.clj
index 605e9d6..723be17 100644
--- a/clojure/src/step8_macros.clj
+++ b/clojure/src/step8_macros.clj
@@ -132,18 +132,15 @@
[strng]
(PRINT (EVAL (READ strng) repl-env)))
-(defn _ref [k,v] (env/env-set repl-env k v))
-
-;; Import types related functions
-(doseq [[k v] core/core_ns] (_ref k v))
-
-;; Defined using the language itself
-(_ref 'read-string reader/read-string)
-(_ref 'eval (fn [ast] (EVAL ast repl-env)))
-(_ref 'slurp slurp)
+;; core.clj: defined using Clojure
+(doseq [[k v] core/core_ns] (env/env-set repl-env k v))
+(env/env-set repl-env 'eval (fn [ast] (EVAL ast repl-env)))
+;; 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))))))))")
(defn -main [& args]
(if args
diff --git a/clojure/src/step9_interop.clj b/clojure/src/step9_interop.clj
index 2fae3ca..40f2b5c 100644
--- a/clojure/src/step9_interop.clj
+++ b/clojure/src/step9_interop.clj
@@ -135,18 +135,15 @@
[strng]
(PRINT (EVAL (READ strng) repl-env)))
-(defn _ref [k,v] (env/env-set repl-env k v))
-
-;; Import types related functions
-(doseq [[k v] core/core_ns] (_ref k v))
-
-;; Defined using the language itself
-(_ref 'read-string reader/read-string)
-(_ref 'eval (fn [ast] (EVAL ast repl-env)))
-(_ref 'slurp slurp)
+;; core.clj: defined using Clojure
+(doseq [[k v] core/core_ns] (env/env-set repl-env k v))
+(env/env-set repl-env 'eval (fn [ast] (EVAL ast repl-env)))
+;; 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))))))))")
(defn -main [& args]
(if args
diff --git a/clojure/src/stepA_more.clj b/clojure/src/stepA_more.clj
index 30eb8a6..d45d86a 100644
--- a/clojure/src/stepA_more.clj
+++ b/clojure/src/stepA_more.clj
@@ -149,21 +149,15 @@
[strng]
(PRINT (EVAL (READ strng) repl-env)))
-(defn _ref [k,v] (env/env-set repl-env k v))
-
-;; Import types related functions
-(doseq [[k v] core/core_ns] (_ref k v))
-
-;; Defined using the language itself
-(_ref 'readline readline/readline)
-(_ref 'read-string reader/read-string)
-(_ref 'eval (fn [ast] (EVAL ast repl-env)))
-(_ref 'slurp slurp)
+;; core.clj: defined using Clojure
+(doseq [[k v] core/core_ns] (env/env-set repl-env k v))
+(env/env-set repl-env 'eval (fn [ast] (EVAL ast repl-env)))
+;; 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) \")\")))))")
(defn -main [& args]
(if args
diff --git a/cs/core.cs b/cs/core.cs
index 13f082e..62a121c 100644
--- a/cs/core.cs
+++ b/cs/core.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
using System.Collections.Generic;
using MalVal = Mal.types.MalVal;
using MalConstant = Mal.types.MalConstant;
@@ -54,6 +55,21 @@ namespace Mal {
return Nil;
} );
+ static public MalFunction mal_readline = new MalFunction(
+ a => {
+ var line = readline.Readline(((MalString)a[0]).getValue());
+ if (line == null) { return types.Nil; }
+ else { return new MalString(line); }
+ } );
+
+ static public MalFunction read_string = new MalFunction(
+ a => reader.read_str(((MalString)a[0]).getValue()));
+
+ static public MalFunction slurp = new MalFunction(
+ a => new MalString(File.ReadAllText(
+ ((MalString)a[0]).getValue())));
+
+
// List/Vector functions
static public MalFunction list_Q = new MalFunction(
a => a[0].GetType() == typeof(MalList) ? True : False);
@@ -233,10 +249,14 @@ namespace Mal {
{"true?", true_Q},
{"false?", false_Q},
{"symbol?", symbol_Q},
+
{"pr-str", pr_str},
{"str", str},
{"prn", prn},
{"println", println},
+ {"readline", mal_readline},
+ {"read-string", read_string},
+ {"slurp", slurp},
{"<", new MalFunction(a => (MalInteger)a[0] < (MalInteger)a[1])},
{"<=", new MalFunction(a => (MalInteger)a[0] <= (MalInteger)a[1])},
{">", new MalFunction(a => (MalInteger)a[0] > (MalInteger)a[1])},
diff --git a/cs/step1_read_print.cs b/cs/step1_read_print.cs
index 92a8b65..62cd7ad 100644
--- a/cs/step1_read_print.cs
+++ b/cs/step1_read_print.cs
@@ -31,7 +31,6 @@ namespace Mal {
if (args.Length > 0 && args[0] == "--raw") {
Mal.readline.mode = Mal.readline.Mode.Raw;
}
-
while (true) {
string line;
try {
@@ -45,13 +44,10 @@ namespace Mal {
Console.WriteLine(PRINT(RE(null, line)));
} catch (Mal.types.MalContinue) {
continue;
- } catch (Mal.types.MalError e) {
+ } catch (Exception e) {
Console.WriteLine("Error: " + e.Message);
+ Console.WriteLine(e.StackTrace);
continue;
- } catch (Mal.reader.ParseError e) {
- Console.WriteLine(e.Message);
- continue;
-
}
}
}
diff --git a/cs/step2_eval.cs b/cs/step2_eval.cs
index 09bf36d..dc467de 100644
--- a/cs/step2_eval.cs
+++ b/cs/step2_eval.cs
@@ -53,13 +53,13 @@ namespace Mal {
// apply list
MalList ast = (MalList)orig_ast;
if (ast.size() == 0) { return ast; }
- a0 = ast.nth(0);
+ a0 = ast[0];
if (!(a0 is MalSymbol)) {
throw new Mal.types.MalError("attempt to apply on non-symbol '"
+ Mal.printer._pr_str(a0,true) + "'");
}
var el = (MalList)eval_ast(ast, env);
- var f = (MalFunction)el.nth(0);
+ var f = (MalFunction)el[0];
return f.apply(el.rest());
}
@@ -92,10 +92,10 @@ namespace Mal {
{"*", multiply},
{"/", divide},
};
+
if (args.Length > 0 && args[0] == "--raw") {
Mal.readline.mode = Mal.readline.Mode.Raw;
}
-
while (true) {
string line;
try {
@@ -109,14 +109,9 @@ namespace Mal {
Console.WriteLine(PRINT(RE(repl_env, line)));
} catch (Mal.types.MalContinue) {
continue;
- } catch (Mal.reader.ParseError e) {
- Console.WriteLine(e.Message);
- continue;
- } catch (Mal.types.MalError e) {
- Console.WriteLine("Error: " + e.Message);
- continue;
} catch (Exception e) {
Console.WriteLine("Error: " + e.Message);
+ Console.WriteLine(e.StackTrace);
continue;
}
}
diff --git a/cs/step3_env.cs b/cs/step3_env.cs
index 032fadd..ba859eb 100644
--- a/cs/step3_env.cs
+++ b/cs/step3_env.cs
@@ -55,7 +55,7 @@ namespace Mal {
// apply list
MalList ast = (MalList)orig_ast;
if (ast.size() == 0) { return ast; }
- a0 = ast.nth(0);
+ a0 = ast[0];
if (!(a0 is MalSymbol)) {
throw new Mal.types.MalError("attempt to apply on non-symbol '"
+ Mal.printer._pr_str(a0,true) + "'");
@@ -63,26 +63,26 @@ namespace Mal {
switch (((MalSymbol)a0).getName()) {
case "def!":
- a1 = ast.nth(1);
- a2 = ast.nth(2);
+ a1 = ast[1];
+ a2 = ast[2];
res = EVAL(a2, env);
env.set(((MalSymbol)a1).getName(), res);
return res;
case "let*":
- a1 = ast.nth(1);
- a2 = ast.nth(2);
+ a1 = ast[1];
+ a2 = ast[2];
MalSymbol key;
MalVal val;
Env let_env = new Env(env);
for(int i=0; i<((MalList)a1).size(); i+=2) {
- key = (MalSymbol)((MalList)a1).nth(i);
- val = ((MalList)a1).nth(i+1);
+ key = (MalSymbol)((MalList)a1)[i];
+ val = ((MalList)a1)[i+1];
let_env.set(key.getName(), EVAL(val, let_env));
}
return EVAL(a2, let_env);
default:
el = (MalList)eval_ast(ast, env);
- var f = (MalFunction)el.nth(0);
+ var f = (MalFunction)el[0];
return f.apply(el.rest());
}
}
@@ -96,9 +96,6 @@ namespace Mal {
static MalVal RE(Env env, string str) {
return EVAL(READ(str), env);
}
- public static Env _ref(Env env, string name, MalVal mv) {
- return env.set(name, mv);
- }
static public MalFunction plus = new MalFunction(
a => (MalInteger)a[0] + (MalInteger)a[1] );
@@ -114,10 +111,10 @@ namespace Mal {
string prompt = "user> ";
var repl_env = new Mal.env.Env(null);
- _ref(repl_env, "+", plus);
- _ref(repl_env, "-", minus);
- _ref(repl_env, "*", multiply);
- _ref(repl_env, "/", divide);
+ repl_env.set("+", plus);
+ repl_env.set("-", minus);
+ repl_env.set("*", multiply);
+ repl_env.set("/", divide);
if (args.Length > 0 && args[0] == "--raw") {
Mal.readline.mode = Mal.readline.Mode.Raw;
@@ -135,14 +132,9 @@ namespace Mal {
Console.WriteLine(PRINT(RE(repl_env, line)));
} catch (Mal.types.MalContinue) {
continue;
- } catch (Mal.reader.ParseError e) {
- Console.WriteLine(e.Message);
- continue;
- } catch (Mal.types.MalException e) {
- Console.WriteLine("Error: " + e.getValue());
- continue;
} catch (Exception e) {
Console.WriteLine("Error: " + e.Message);
+ Console.WriteLine(e.StackTrace);
continue;
}
}
diff --git a/cs/step4_if_fn_do.cs b/cs/step4_if_fn_do.cs
index d0ca882..2383c31 100644
--- a/cs/step4_if_fn_do.cs
+++ b/cs/step4_if_fn_do.cs
@@ -55,58 +55,58 @@ namespace Mal {
// apply list
MalList ast = (MalList)orig_ast;
if (ast.size() == 0) { return ast; }
- a0 = ast.nth(0);
+ a0 = ast[0];
String a0sym = a0 is MalSymbol ? ((MalSymbol)a0).getName()
: "__<*fn*>__";
switch (a0sym) {
case "def!":
- a1 = ast.nth(1);
- a2 = ast.nth(2);
+ a1 = ast[1];
+ a2 = ast[2];
res = EVAL(a2, env);
env.set(((MalSymbol)a1).getName(), res);
return res;
case "let*":
- a1 = ast.nth(1);
- a2 = ast.nth(2);
+ a1 = ast[1];
+ a2 = ast[2];
MalSymbol key;
MalVal val;
Env let_env = new Env(env);
for(int i=0; i<((MalList)a1).size(); i+=2) {
- key = (MalSymbol)((MalList)a1).nth(i);
- val = ((MalList)a1).nth(i+1);
+ key = (MalSymbol)((MalList)a1)[i];
+ val = ((MalList)a1)[i+1];
let_env.set(key.getName(), EVAL(val, let_env));
}
return EVAL(a2, let_env);
case "do":
el = (MalList)eval_ast(ast.rest(), env);
- return el.nth(el.size()-1);
+ return el[el.size()-1];
case "if":
- a1 = ast.nth(1);
+ a1 = ast[1];
MalVal cond = EVAL(a1, env);
if (cond == Mal.types.Nil || cond == Mal.types.False) {
// eval false slot form
if (ast.size() > 3) {
- a3 = ast.nth(3);
+ a3 = ast[3];
return EVAL(a3, env);
} else {
return Mal.types.Nil;
}
} else {
// eval true slot form
- a2 = ast.nth(2);
+ a2 = ast[2];
return EVAL(a2, env);
}
case "fn*":
- MalList a1f = (MalList)ast.nth(1);
- MalVal a2f = ast.nth(2);
+ MalList a1f = (MalList)ast[1];
+ MalVal a2f = ast[2];
Env cur_env = env;
return new MalFunction(
args => EVAL(a2f, new Env(cur_env, a1f, args)) );
default:
el = (MalList)eval_ast(ast, env);
- var f = (MalFunction)el.nth(0);
+ var f = (MalFunction)el[0];
return f.apply(el.rest());
}
}
@@ -120,18 +120,17 @@ namespace Mal {
static MalVal RE(Env env, string str) {
return EVAL(READ(str), env);
}
- public static Env _ref(Env env, string name, MalVal mv) {
- return env.set(name, mv);
- }
static void Main(string[] args) {
string prompt = "user> ";
- var repl_env = new Mal.env.Env(null);
- foreach (var entry in Mal.core.ns) {
- _ref(repl_env, entry.Key, entry.Value);
+ // core.cs: defined using C#
+ var repl_env = new env.Env(null);
+ foreach (var entry in core.ns) {
+ repl_env.set(entry.Key, entry.Value);
}
+ // core.mal: defined using the language itself
RE(repl_env, "(def! not (fn* (a) (if a false true)))");
if (args.Length > 0 && args[0] == "--raw") {
@@ -150,14 +149,9 @@ namespace Mal {
Console.WriteLine(PRINT(RE(repl_env, line)));
} catch (Mal.types.MalContinue) {
continue;
- } catch (Mal.reader.ParseError e) {
- Console.WriteLine(e.Message);
- continue;
- } catch (Mal.types.MalException e) {
- Console.WriteLine("Error: " + e.getValue());
- continue;
} catch (Exception e) {
Console.WriteLine("Error: " + e.Message);
+ Console.WriteLine(e.StackTrace);
continue;
}
}
diff --git a/cs/step5_tco.cs b/cs/step5_tco.cs
index 18b2fc9..b04d16e 100644
--- a/cs/step5_tco.cs
+++ b/cs/step5_tco.cs
@@ -13,7 +13,7 @@ using MalFunction = Mal.types.MalFunction;
using Env = Mal.env.Env;
namespace Mal {
- class step4_if_fn_do {
+ class step5_tco {
// read
static MalVal READ(string str) {
return reader.read_str(str);
@@ -58,36 +58,36 @@ namespace Mal {
// apply list
MalList ast = (MalList)orig_ast;
if (ast.size() == 0) { return ast; }
- a0 = ast.nth(0);
+ a0 = ast[0];
String a0sym = a0 is MalSymbol ? ((MalSymbol)a0).getName()
: "__<*fn*>__";
switch (a0sym) {
case "def!":
- a1 = ast.nth(1);
- a2 = ast.nth(2);
+ a1 = ast[1];
+ a2 = ast[2];
res = EVAL(a2, env);
env.set(((MalSymbol)a1).getName(), res);
return res;
case "let*":
- a1 = ast.nth(1);
- a2 = ast.nth(2);
+ a1 = ast[1];
+ a2 = ast[2];
MalSymbol key;
MalVal val;
Env let_env = new Env(env);
for(int i=0; i<((MalList)a1).size(); i+=2) {
- key = (MalSymbol)((MalList)a1).nth(i);
- val = ((MalList)a1).nth(i+1);
+ key = (MalSymbol)((MalList)a1)[i];
+ val = ((MalList)a1)[i+1];
let_env.set(key.getName(), EVAL(val, let_env));
}
return EVAL(a2, let_env);
case "do":
eval_ast(ast.slice(1, ast.size()-1), env);
- orig_ast = ast.nth(ast.size()-1);
+ orig_ast = ast[ast.size()-1];
break;
case "if":
- a1 = ast.nth(1);
+ a1 = ast[1];
MalVal cond = EVAL(a1, env);
if (cond == Mal.types.Nil || cond == Mal.types.False) {
// eval false slot form
@@ -102,14 +102,14 @@ namespace Mal {
}
break;
case "fn*":
- MalList a1f = (MalList)ast.nth(1);
- MalVal a2f = ast.nth(2);
+ MalList a1f = (MalList)ast[1];
+ MalVal a2f = ast[2];
Env cur_env = env;
return new MalFunction(a2f, env, a1f,
args => EVAL(a2f, new Env(cur_env, a1f, args)) );
default:
el = (MalList)eval_ast(ast, env);
- var f = (MalFunction)el.nth(0);
+ var f = (MalFunction)el[0];
MalVal fnast = f.getAst();
if (fnast != null) {
orig_ast = fnast;
@@ -132,18 +132,17 @@ namespace Mal {
static MalVal RE(Env env, string str) {
return EVAL(READ(str), env);
}
- public static Env _ref(Env env, string name, MalVal mv) {
- return env.set(name, mv);
- }
static void Main(string[] args) {
string prompt = "user> ";
- var repl_env = new Mal.env.Env(null);
- foreach (var entry in Mal.core.ns) {
- _ref(repl_env, entry.Key, entry.Value);
+ // core.cs: defined using C#
+ var repl_env = new env.Env(null);
+ foreach (var entry in core.ns) {
+ repl_env.set(entry.Key, entry.Value);
}
+ // core.mal: defined using the language itself
RE(repl_env, "(def! not (fn* (a) (if a false true)))");
if (args.Length > 0 && args[0] == "--raw") {
@@ -162,14 +161,9 @@ namespace Mal {
Console.WriteLine(PRINT(RE(repl_env, line)));
} catch (Mal.types.MalContinue) {
continue;
- } catch (Mal.reader.ParseError e) {
- Console.WriteLine(e.Message);
- continue;
- } catch (Mal.types.MalException e) {
- Console.WriteLine("Error: " + e.getValue());
- continue;
} catch (Exception e) {
Console.WriteLine("Error: " + e.Message);
+ Console.WriteLine(e.StackTrace);
continue;
}
}
diff --git a/cs/step6_file.cs b/cs/step6_file.cs
index b02cedb..cb2157e 100644
--- a/cs/step6_file.cs
+++ b/cs/step6_file.cs
@@ -4,7 +4,6 @@ using System.Collections;
using System.Collections.Generic;
using Mal;
using MalVal = Mal.types.MalVal;
-using MalString = Mal.types.MalString;
using MalSymbol = Mal.types.MalSymbol;
using MalInteger = Mal.types.MalInteger;
using MalList = Mal.types.MalList;
@@ -14,7 +13,7 @@ using MalFunction = Mal.types.MalFunction;
using Env = Mal.env.Env;
namespace Mal {
- class step4_if_fn_do {
+ class step6_file {
// read
static MalVal READ(string str) {
return reader.read_str(str);
@@ -59,36 +58,36 @@ namespace Mal {
// apply list
MalList ast = (MalList)orig_ast;
if (ast.size() == 0) { return ast; }
- a0 = ast.nth(0);
+ a0 = ast[0];
String a0sym = a0 is MalSymbol ? ((MalSymbol)a0).getName()
: "__<*fn*>__";
switch (a0sym) {
case "def!":
- a1 = ast.nth(1);
- a2 = ast.nth(2);
+ a1 = ast[1];
+ a2 = ast[2];
res = EVAL(a2, env);
env.set(((MalSymbol)a1).getName(), res);
return res;
case "let*":
- a1 = ast.nth(1);
- a2 = ast.nth(2);
+ a1 = ast[1];
+ a2 = ast[2];
MalSymbol key;
MalVal val;
Env let_env = new Env(env);
for(int i=0; i<((MalList)a1).size(); i+=2) {
- key = (MalSymbol)((MalList)a1).nth(i);
- val = ((MalList)a1).nth(i+1);
+ key = (MalSymbol)((MalList)a1)[i];
+ val = ((MalList)a1)[i+1];
let_env.set(key.getName(), EVAL(val, let_env));
}
return EVAL(a2, let_env);
case "do":
eval_ast(ast.slice(1, ast.size()-1), env);
- orig_ast = ast.nth(ast.size()-1);
+ orig_ast = ast[ast.size()-1];
break;
case "if":
- a1 = ast.nth(1);
+ a1 = ast[1];
MalVal cond = EVAL(a1, env);
if (cond == Mal.types.Nil || cond == Mal.types.False) {
// eval false slot form
@@ -103,14 +102,14 @@ namespace Mal {
}
break;
case "fn*":
- MalList a1f = (MalList)ast.nth(1);
- MalVal a2f = ast.nth(2);
+ MalList a1f = (MalList)ast[1];
+ MalVal a2f = ast[2];
Env cur_env = env;
return new MalFunction(a2f, env, a1f,
args => EVAL(a2f, new Env(cur_env, a1f, args)) );
default:
el = (MalList)eval_ast(ast, env);
- var f = (MalFunction)el.nth(0);
+ var f = (MalFunction)el[0];
MalVal fnast = f.getAst();
if (fnast != null) {
orig_ast = fnast;
@@ -133,26 +132,18 @@ namespace Mal {
static MalVal RE(Env env, string str) {
return EVAL(READ(str), env);
}
- public static Env _ref(Env env, string name, MalVal mv) {
- return env.set(name, mv);
- }
-
static void Main(string[] args) {
string prompt = "user> ";
- var repl_env = new Mal.env.Env(null);
- foreach (var entry in Mal.core.ns) {
- _ref(repl_env, entry.Key, entry.Value);
+ // core.cs: defined using C#
+ var repl_env = new env.Env(null);
+ foreach (var entry in core.ns) {
+ repl_env.set(entry.Key, entry.Value);
}
- _ref(repl_env, "read-string", new MalFunction(
- a => reader.read_str(((MalString)a[0]).getValue())));
- _ref(repl_env, "eval", new MalFunction(
- a => EVAL(a[0], repl_env)));
- _ref(repl_env, "slurp", new MalFunction(
- a => new MalString(File.ReadAllText(
- ((MalString)a[0]).getValue()))));
+ repl_env.set("eval", new MalFunction(a => EVAL(a[0], repl_env)));
+ // core.mal: defined using the language itself
RE(repl_env, "(def! not (fn* (a) (if a false true)))");
RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
@@ -180,14 +171,9 @@ namespace Mal {
Console.WriteLine(PRINT(RE(repl_env, line)));
} catch (Mal.types.MalContinue) {
continue;
- } catch (Mal.reader.ParseError e) {
- Console.WriteLine(e.Message);
- continue;
- } catch (Mal.types.MalException e) {
- Console.WriteLine("Error: " + e.getValue());
- continue;
} catch (Exception e) {
Console.WriteLine("Error: " + e.Message);
+ Console.WriteLine(e.StackTrace);
continue;
}
}
diff --git a/cs/step7_quote.cs b/cs/step7_quote.cs
index 61f638f..6f08abb 100644
--- a/cs/step7_quote.cs
+++ b/cs/step7_quote.cs
@@ -14,7 +14,7 @@ using MalFunction = Mal.types.MalFunction;
using Env = Mal.env.Env;
namespace Mal {
- class step4_if_fn_do {
+ class step7_quote {
// read
static MalVal READ(string str) {
return reader.read_str(str);
@@ -164,26 +164,18 @@ namespace Mal {
static MalVal RE(Env env, string str) {
return EVAL(READ(str), env);
}
- public static Env _ref(Env env, string name, MalVal mv) {
- return env.set(name, mv);
- }
-
static void Main(string[] args) {
string prompt = "user> ";
- var repl_env = new Mal.env.Env(null);
- foreach (var entry in Mal.core.ns) {
- _ref(repl_env, entry.Key, entry.Value);
+ // core.cs: defined using C#
+ var repl_env = new env.Env(null);
+ foreach (var entry in core.ns) {
+ repl_env.set(entry.Key, entry.Value);
}
- _ref(repl_env, "read-string", new MalFunction(
- a => reader.read_str(((MalString)a[0]).getValue())));
- _ref(repl_env, "eval", new MalFunction(
- a => EVAL(a[0], repl_env)));
- _ref(repl_env, "slurp", new MalFunction(
- a => new MalString(File.ReadAllText(
- ((MalString)a[0]).getValue()))));
+ repl_env.set("eval", new MalFunction(a => EVAL(a[0], repl_env)));
+ // core.mal: defined using the language itself
RE(repl_env, "(def! not (fn* (a) (if a false true)))");
RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
@@ -211,12 +203,6 @@ namespace Mal {
Console.WriteLine(PRINT(RE(repl_env, line)));
} catch (Mal.types.MalContinue) {
continue;
- } catch (Mal.reader.ParseError e) {
- Console.WriteLine(e.Message);
- continue;
- } catch (Mal.types.MalException e) {
- Console.WriteLine("Error: " + e.getValue());
- continue;
} catch (Exception e) {
Console.WriteLine("Error: " + e.Message);
Console.WriteLine(e.StackTrace);
diff --git a/cs/step8_macros.cs b/cs/step8_macros.cs
index fe085f9..caa8f0a 100644
--- a/cs/step8_macros.cs
+++ b/cs/step8_macros.cs
@@ -14,7 +14,7 @@ using MalFunction = Mal.types.MalFunction;
using Env = Mal.env.Env;
namespace Mal {
- class step4_if_fn_do {
+ class step8_macros {
// read
static MalVal READ(string str) {
return reader.read_str(str);
@@ -201,28 +201,22 @@ namespace Mal {
static MalVal RE(Env env, string str) {
return EVAL(READ(str), env);
}
- public static Env _ref(Env env, string name, MalVal mv) {
- return env.set(name, mv);
- }
-
static void Main(string[] args) {
string prompt = "user> ";
- var repl_env = new Mal.env.Env(null);
- foreach (var entry in Mal.core.ns) {
- _ref(repl_env, entry.Key, entry.Value);
+ // core.cs: defined using C#
+ var repl_env = new env.Env(null);
+ foreach (var entry in core.ns) {
+ repl_env.set(entry.Key, entry.Value);
}
- _ref(repl_env, "read-string", new MalFunction(
- a => reader.read_str(((MalString)a[0]).getValue())));
- _ref(repl_env, "eval", new MalFunction(
- a => EVAL(a[0], repl_env)));
- _ref(repl_env, "slurp", new MalFunction(
- a => new MalString(File.ReadAllText(
- ((MalString)a[0]).getValue()))));
+ repl_env.set("eval", new MalFunction(a => EVAL(a[0], repl_env)));
+ // core.mal: defined using the language itself
RE(repl_env, "(def! not (fn* (a) (if a false true)))");
RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
+ RE(repl_env, "(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)))))))");
+ RE(repl_env, "(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))))))))");
int fileIdx = 0;
if (args.Length > 0 && args[0] == "--raw") {
@@ -248,12 +242,6 @@ namespace Mal {
Console.WriteLine(PRINT(RE(repl_env, line)));
} catch (Mal.types.MalContinue) {
continue;
- } catch (Mal.reader.ParseError e) {
- Console.WriteLine(e.Message);
- continue;
- } catch (Mal.types.MalException e) {
- Console.WriteLine("Error: " + e.getValue());
- continue;
} catch (Exception e) {
Console.WriteLine("Error: " + e.Message);
Console.WriteLine(e.StackTrace);
diff --git a/cs/stepA_more.cs b/cs/stepA_more.cs
index 97b1e84..cbbc91f 100644
--- a/cs/stepA_more.cs
+++ b/cs/stepA_more.cs
@@ -3,7 +3,6 @@ using System.IO;
using System.Collections;
using System.Collections.Generic;
using Mal;
-using MalException = Mal.types.MalException;
using MalVal = Mal.types.MalVal;
using MalString = Mal.types.MalString;
using MalSymbol = Mal.types.MalSymbol;
@@ -161,8 +160,8 @@ namespace Mal {
a2 = ast[2];
MalVal a20 = ((MalList)a2)[0];
if (((MalSymbol)a20).getName() == "catch*") {
- if (e is MalException) {
- exc = ((MalException)e).getValue();
+ if (e is Mal.types.MalException) {
+ exc = ((Mal.types.MalException)e).getValue();
} else {
exc = new MalString(e.StackTrace);
}
@@ -180,12 +179,12 @@ namespace Mal {
case "if":
a1 = ast[1];
MalVal cond = EVAL(a1, env);
- if (cond == types.Nil || cond == types.False) {
+ if (cond == Mal.types.Nil || cond == Mal.types.False) {
// eval false slot form
if (ast.size() > 3) {
orig_ast = ast[3];
} else {
- return types.Nil;
+ return Mal.types.Nil;
}
} else {
// eval true slot form
@@ -223,40 +222,26 @@ namespace Mal {
static MalVal RE(Env env, string str) {
return EVAL(READ(str), env);
}
- public static Env _ref(Env env, string name, MalVal mv) {
- return env.set(name, mv);
- }
-
static void Main(string[] args) {
string prompt = "user> ";
+ // core.cs: defined using C#
var repl_env = new env.Env(null);
foreach (var entry in core.ns) {
- _ref(repl_env, entry.Key, entry.Value);
+ repl_env.set(entry.Key, entry.Value);
}
- _ref(repl_env, "readline", new MalFunction(
- a => {
- var line = readline.Readline(((MalString)a[0]).getValue());
- if (line == null) { return types.Nil; }
- else { return new MalString(line); }
- }));
- _ref(repl_env, "read-string", new MalFunction(
- a => reader.read_str(((MalString)a[0]).getValue())));
- _ref(repl_env, "eval", new MalFunction(
- a => EVAL(a[0], repl_env)));
- _ref(repl_env, "slurp", new MalFunction(
- a => new MalString(File.ReadAllText(
- ((MalString)a[0]).getValue()))));
+ repl_env.set("eval", new MalFunction(a => EVAL(a[0], repl_env)));
+ // core.mal: defined using the language itself
RE(repl_env, "(def! not (fn* (a) (if a false true)))");
+ RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
RE(repl_env, "(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)))))))");
RE(repl_env, "(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))))))))");
- RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
int fileIdx = 0;
if (args.Length > 0 && args[0] == "--raw") {
- readline.mode = readline.Mode.Raw;
+ Mal.readline.mode = Mal.readline.Mode.Raw;
fileIdx = 1;
}
if (args.Length > fileIdx) {
@@ -268,7 +253,7 @@ namespace Mal {
while (true) {
string line;
try {
- line = readline.Readline(prompt);
+ line = Mal.readline.Readline(prompt);
if (line == null) { break; }
} catch (IOException e) {
Console.WriteLine("IOException: " + e.Message);
@@ -276,12 +261,9 @@ namespace Mal {
}
try {
Console.WriteLine(PRINT(RE(repl_env, line)));
- } catch (types.MalContinue) {
- continue;
- } catch (reader.ParseError e) {
- Console.WriteLine(e.Message);
+ } catch (Mal.types.MalContinue) {
continue;
- } catch (MalException e) {
+ } catch (Mal.types.MalException e) {
Console.WriteLine("Error: " +
printer._pr_str(e.getValue(), false));
continue;
diff --git a/cs/types.cs b/cs/types.cs
index 34985ad..b49adb6 100644
--- a/cs/types.cs
+++ b/cs/types.cs
@@ -19,10 +19,11 @@ namespace Mal {
// Thrown by throw function
public class MalException : MalThrowable {
MalVal value;
+ //string Message;
public MalException(MalVal value) {
this.value = value;
}
- public MalException(string value) {
+ public MalException(string value) :base(value) {
this.value = new MalString(value);
}
public MalVal getValue() { return value; }
diff --git a/docs/TODO b/docs/TODO
index 5c82d2b..43c11a2 100644
--- a/docs/TODO
+++ b/docs/TODO
@@ -7,8 +7,7 @@ All:
- gensym reader inside quasiquote
- can let* and quasiquote be TCO'd ?
- - more interop tests
- - test metadata on builtin functions (i.e. +)
+ - per impl tests for step5_tco, step9_interop (if possible)
- regular expression matching in runtest
- Print full exception when test gets EOF from expect
diff --git a/java/src/main/java/mal/core.java b/java/src/main/java/mal/core.java
index 6ac4f8e..ea6787d 100644
--- a/java/src/main/java/mal/core.java
+++ b/java/src/main/java/mal/core.java
@@ -7,8 +7,14 @@ import java.util.Map;
import java.util.HashMap;
import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.util.Scanner;
+import java.io.File;
+
import mal.types.*;
import mal.printer;
+import mal.readline;
public class core {
// Local references for convenience
@@ -84,6 +90,41 @@ public class core {
}
};
+ static MalFunction mal_readline = new MalFunction() {
+ public MalVal apply(MalList args) throws MalThrowable {
+ String prompt = ((MalString)args.nth(0)).getValue();
+ try {
+ return new MalString(readline.readline(prompt));
+ } catch (IOException e) {
+ throw new MalException(new MalString(e.getMessage()));
+ } catch (readline.EOFException e) {
+ throw new MalException(new MalString(e.getMessage()));
+ }
+ }
+ };
+
+ static MalFunction read_string = new MalFunction() {
+ public MalVal apply(MalList args) throws MalThrowable {
+ try {
+ return reader.read_str(((MalString)args.nth(0)).getValue());
+ } catch (MalContinue c) {
+ return types.Nil;
+ }
+ }
+ };
+
+ static MalFunction slurp = new MalFunction() {
+ public MalVal apply(MalList args) throws MalThrowable {
+ String fname = ((MalString)args.nth(0)).getValue();
+ try {
+ return new MalString(
+ new Scanner(new File(fname)).useDelimiter("\\Z").next());
+ } catch (FileNotFoundException e) {
+ throw new MalError(e.getMessage());
+ }
+ }
+ };
+
// Number functions
static MalFunction add = new MalFunction() {
@@ -423,10 +464,14 @@ public class core {
.put("true?", true_Q)
.put("false?", false_Q)
.put("symbol?", symbol_Q)
+
.put("pr-str", pr_str)
.put("str", str)
.put("prn", prn)
.put("println", println)
+ .put("readline", mal_readline)
+ .put("read-string", read_string)
+ .put("slurp", slurp)
.put("<", lt)
.put("<=", lte)
.put(">", gt)
diff --git a/java/src/main/java/mal/step2_eval.java b/java/src/main/java/mal/step2_eval.java
index 3d425db..cc2b785 100644
--- a/java/src/main/java/mal/step2_eval.java
+++ b/java/src/main/java/mal/step2_eval.java
@@ -77,42 +77,36 @@ public class step2_eval {
return EVAL(READ(str), env);
}
- static interface ILambda {
- public MalVal apply(MalList args);
- }
- static class plus implements ILambda {
- public MalVal apply(MalList args) {
- return ((MalInteger)args.nth(0)).add(
- ((MalInteger)args.nth(1)));
+ static MalFunction add = new MalFunction() {
+ public MalVal apply(MalList a) throws MalThrowable {
+ return ((MalInteger)a.nth(0)).add((MalInteger)a.nth(1));
}
- }
- static class minus implements ILambda {
- public MalVal apply(MalList args) {
- return ((MalInteger)args.nth(0)).subtract(
- ((MalInteger)args.nth(1)));
+ };
+ static MalFunction subtract = new MalFunction() {
+ public MalVal apply(MalList a) throws MalThrowable {
+ return ((MalInteger)a.nth(0)).subtract((MalInteger)a.nth(1));
}
- }
- static class multiply implements ILambda {
- public MalVal apply(MalList args) {
- return ((MalInteger)args.nth(0)).multiply(
- ((MalInteger)args.nth(1)));
+ };
+ static MalFunction multiply = new MalFunction() {
+ public MalVal apply(MalList a) throws MalThrowable {
+ return ((MalInteger)a.nth(0)).multiply((MalInteger)a.nth(1));
}
- }
- static class divide implements ILambda {
- public MalVal apply(MalList args) {
- return ((MalInteger)args.nth(0)).divide(
- ((MalInteger)args.nth(1)));
+ };
+ static MalFunction divide = new MalFunction() {
+ public MalVal apply(MalList a) throws MalThrowable {
+ return ((MalInteger)a.nth(0)).divide((MalInteger)a.nth(1));
}
- }
+ };
+
public static void main(String[] args) throws MalThrowable {
String prompt = "user> ";
HashMap repl_env = new HashMap();
- repl_env.put("+", new plus());
- repl_env.put("-", new minus());
- repl_env.put("*", new multiply());
- repl_env.put("/", new divide());
+ repl_env.put("+", add);
+ repl_env.put("-", subtract);
+ repl_env.put("*", multiply);
+ repl_env.put("/", divide);
if (args.length > 0 && args[0].equals("--raw")) {
readline.mode = readline.Mode.JAVA;
@@ -132,12 +126,12 @@ public class step2_eval {
System.out.println(PRINT(RE(repl_env, line)));
} catch (MalContinue e) {
continue;
- } catch (MalError e) {
- System.out.println("Error: " + e.getMessage());
- continue;
} catch (reader.ParseError e) {
System.out.println(e.getMessage());
continue;
+ } catch (MalError e) {
+ System.out.println("Error: " + e.getMessage());
+ continue;
}
}
}
diff --git a/java/src/main/java/mal/step3_env.java b/java/src/main/java/mal/step3_env.java
index 690469e..297453c 100644
--- a/java/src/main/java/mal/step3_env.java
+++ b/java/src/main/java/mal/step3_env.java
@@ -11,7 +11,6 @@ import mal.readline;
import mal.reader;
import mal.printer;
import mal.env.Env;
-import mal.core;
public class step3_env {
// read
@@ -97,18 +96,37 @@ public class step3_env {
public static MalVal RE(Env env, String str) throws MalThrowable {
return EVAL(READ(str), env);
}
- public static Env _ref(Env env, String name, MalVal mv) {
- return env.set(name, mv);
- }
+
+ static MalFunction add = new MalFunction() {
+ public MalVal apply(MalList a) throws MalThrowable {
+ return ((MalInteger)a.nth(0)).add((MalInteger)a.nth(1));
+ }
+ };
+ static MalFunction subtract = new MalFunction() {
+ public MalVal apply(MalList a) throws MalThrowable {
+ return ((MalInteger)a.nth(0)).subtract((MalInteger)a.nth(1));
+ }
+ };
+ static MalFunction multiply = new MalFunction() {
+ public MalVal apply(MalList a) throws MalThrowable {
+ return ((MalInteger)a.nth(0)).multiply((MalInteger)a.nth(1));
+ }
+ };
+ static MalFunction divide = new MalFunction() {
+ public MalVal apply(MalList a) throws MalThrowable {
+ return ((MalInteger)a.nth(0)).divide((MalInteger)a.nth(1));
+ }
+ };
+
public static void main(String[] args) throws MalThrowable {
String prompt = "user> ";
Env repl_env = new Env(null);
- _ref(repl_env, "+", core.add);
- _ref(repl_env, "-", core.subtract);
- _ref(repl_env, "*", core.multiply);
- _ref(repl_env, "/", core.divide);
+ repl_env.set("+", add);
+ repl_env.set("-", subtract);
+ repl_env.set("*", multiply);
+ repl_env.set("/", divide);
if (args.length > 0 && args[0].equals("--raw")) {
readline.mode = readline.Mode.JAVA;
@@ -128,12 +146,12 @@ public class step3_env {
System.out.println(PRINT(RE(repl_env, line)));
} catch (MalContinue e) {
continue;
- } catch (MalError e) {
- System.out.println("Error: " + e.getMessage());
- continue;
} catch (reader.ParseError e) {
System.out.println(e.getMessage());
continue;
+ } catch (MalError e) {
+ System.out.println("Error: " + e.getMessage());
+ continue;
}
}
}
diff --git a/java/src/main/java/mal/step4_if_fn_do.java b/java/src/main/java/mal/step4_if_fn_do.java
index 4d064cf..6e7997a 100644
--- a/java/src/main/java/mal/step4_if_fn_do.java
+++ b/java/src/main/java/mal/step4_if_fn_do.java
@@ -122,18 +122,18 @@ public class step4_if_fn_do {
public static MalVal RE(Env env, String str) throws MalThrowable {
return EVAL(READ(str), env);
}
- public static Env _ref(Env env, String name, MalVal mv) {
- return env.set(name, mv);
- }
public static void main(String[] args) throws MalThrowable {
String prompt = "user> ";
Env repl_env = new Env(null);
+
+ // core.java: defined using Java
for (String key : core.ns.keySet()) {
- _ref(repl_env, key, core.ns.get(key));
+ repl_env.set(key, core.ns.get(key));
}
+ // core.mal: defined using the language itself
RE(repl_env, "(def! not (fn* (a) (if a false true)))");
if (args.length > 0 && args[0].equals("--raw")) {
diff --git a/java/src/main/java/mal/step5_tco.java b/java/src/main/java/mal/step5_tco.java
index 9cd42d5..ad15d74 100644
--- a/java/src/main/java/mal/step5_tco.java
+++ b/java/src/main/java/mal/step5_tco.java
@@ -133,18 +133,18 @@ public class step5_tco {
public static MalVal RE(Env env, String str) throws MalThrowable {
return EVAL(READ(str), env);
}
- public static Env _ref(Env env, String name, MalVal mv) {
- return env.set(name, mv);
- }
public static void main(String[] args) throws MalThrowable {
String prompt = "user> ";
Env repl_env = new Env(null);
+
+ // core.java: defined using Java
for (String key : core.ns.keySet()) {
- _ref(repl_env, key, core.ns.get(key));
+ repl_env.set(key, core.ns.get(key));
}
+ // core.mal: defined using the language itself
RE(repl_env, "(def! not (fn* (a) (if a false true)))");
if (args.length > 0 && args[0].equals("--raw")) {
diff --git a/java/src/main/java/mal/step6_file.java b/java/src/main/java/mal/step6_file.java
index 6a4c981..446ffa0 100644
--- a/java/src/main/java/mal/step6_file.java
+++ b/java/src/main/java/mal/step6_file.java
@@ -1,10 +1,7 @@
package mal;
import java.io.IOException;
-import java.io.FileNotFoundException;
-import java.util.Scanner;
-import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
@@ -136,46 +133,23 @@ public class step6_file {
public static MalVal RE(Env env, String str) throws MalThrowable {
return EVAL(READ(str), env);
}
- public static Env _ref(Env env, String name, MalVal mv) {
- return env.set(name, mv);
- }
- public static String slurp(String fname) throws MalThrowable {
- try {
- return new Scanner(new File(fname))
- .useDelimiter("\\Z").next();
- } catch (FileNotFoundException e) {
- throw new MalError(e.getMessage());
- }
- }
public static void main(String[] args) throws MalThrowable {
String prompt = "user> ";
final Env repl_env = new Env(null);
+
+ // core.java: defined using Java
for (String key : core.ns.keySet()) {
- _ref(repl_env, key, core.ns.get(key));
+ repl_env.set(key, core.ns.get(key));
}
- _ref(repl_env, "read-string", new MalFunction() {
- public MalVal apply(MalList args) throws MalThrowable {
- try {
- return reader.read_str(((MalString)args.nth(0)).getValue());
- } catch (MalContinue c) {
- return types.Nil;
- }
- }
- });
- _ref(repl_env, "eval", new MalFunction() {
+ repl_env.set("eval", new MalFunction() {
public MalVal apply(MalList args) throws MalThrowable {
return EVAL(args.nth(0), repl_env);
}
});
- _ref(repl_env, "slurp", new MalFunction() {
- public MalVal apply(MalList args) throws MalThrowable {
- String fname = ((MalString)args.nth(0)).getValue();
- return new MalString(slurp(fname));
- }
- });
+ // core.mal: defined using the language itself
RE(repl_env, "(def! not (fn* (a) (if a false true)))");
RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
diff --git a/java/src/main/java/mal/step7_quote.java b/java/src/main/java/mal/step7_quote.java
index c46b4f0..2f5a638 100644
--- a/java/src/main/java/mal/step7_quote.java
+++ b/java/src/main/java/mal/step7_quote.java
@@ -1,10 +1,7 @@
package mal;
import java.io.IOException;
-import java.io.FileNotFoundException;
-import java.util.Scanner;
-import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
@@ -167,46 +164,23 @@ public class step7_quote {
public static MalVal RE(Env env, String str) throws MalThrowable {
return EVAL(READ(str), env);
}
- public static Env _ref(Env env, String name, MalVal mv) {
- return env.set(name, mv);
- }
- public static String slurp(String fname) throws MalThrowable {
- try {
- return new Scanner(new File(fname))
- .useDelimiter("\\Z").next();
- } catch (FileNotFoundException e) {
- throw new MalError(e.getMessage());
- }
- }
public static void main(String[] args) throws MalThrowable {
String prompt = "user> ";
final Env repl_env = new Env(null);
+
+ // core.java: defined using Java
for (String key : core.ns.keySet()) {
- _ref(repl_env, key, core.ns.get(key));
+ repl_env.set(key, core.ns.get(key));
}
- _ref(repl_env, "read-string", new MalFunction() {
- public MalVal apply(MalList args) throws MalThrowable {
- try {
- return reader.read_str(((MalString)args.nth(0)).getValue());
- } catch (MalContinue c) {
- return types.Nil;
- }
- }
- });
- _ref(repl_env, "eval", new MalFunction() {
+ repl_env.set("eval", new MalFunction() {
public MalVal apply(MalList args) throws MalThrowable {
return EVAL(args.nth(0), repl_env);
}
});
- _ref(repl_env, "slurp", new MalFunction() {
- public MalVal apply(MalList args) throws MalThrowable {
- String fname = ((MalString)args.nth(0)).getValue();
- return new MalString(slurp(fname));
- }
- });
+ // core.mal: defined using the language itself
RE(repl_env, "(def! not (fn* (a) (if a false true)))");
RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
diff --git a/java/src/main/java/mal/step8_macros.java b/java/src/main/java/mal/step8_macros.java
index bb99818..914c7d3 100644
--- a/java/src/main/java/mal/step8_macros.java
+++ b/java/src/main/java/mal/step8_macros.java
@@ -1,10 +1,7 @@
package mal;
import java.io.IOException;
-import java.io.FileNotFoundException;
-import java.util.Scanner;
-import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
@@ -205,48 +202,27 @@ public class step8_macros {
public static MalVal RE(Env env, String str) throws MalThrowable {
return EVAL(READ(str), env);
}
- public static Env _ref(Env env, String name, MalVal mv) {
- return env.set(name, mv);
- }
- public static String slurp(String fname) throws MalThrowable {
- try {
- return new Scanner(new File(fname))
- .useDelimiter("\\Z").next();
- } catch (FileNotFoundException e) {
- throw new MalError(e.getMessage());
- }
- }
public static void main(String[] args) throws MalThrowable {
String prompt = "user> ";
final Env repl_env = new Env(null);
+
+ // core.java: defined using Java
for (String key : core.ns.keySet()) {
- _ref(repl_env, key, core.ns.get(key));
+ repl_env.set(key, core.ns.get(key));
}
- _ref(repl_env, "read-string", new MalFunction() {
- public MalVal apply(MalList args) throws MalThrowable {
- try {
- return reader.read_str(((MalString)args.nth(0)).getValue());
- } catch (MalContinue c) {
- return types.Nil;
- }
- }
- });
- _ref(repl_env, "eval", new MalFunction() {
+ repl_env.set("eval", new MalFunction() {
public MalVal apply(MalList args) throws MalThrowable {
return EVAL(args.nth(0), repl_env);
}
});
- _ref(repl_env, "slurp", new MalFunction() {
- public MalVal apply(MalList args) throws MalThrowable {
- String fname = ((MalString)args.nth(0)).getValue();
- return new MalString(slurp(fname));
- }
- });
+ // core.mal: defined using the language itself
RE(repl_env, "(def! not (fn* (a) (if a false true)))");
RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
+ RE(repl_env, "(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)))))))");
+ RE(repl_env, "(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))))))))");
Integer fileIdx = 0;
if (args.length > 0 && args[0].equals("--raw")) {
diff --git a/java/src/main/java/mal/stepA_more.java b/java/src/main/java/mal/stepA_more.java
index 76b8501..5ed5667 100644
--- a/java/src/main/java/mal/stepA_more.java
+++ b/java/src/main/java/mal/stepA_more.java
@@ -1,10 +1,7 @@
package mal;
import java.io.IOException;
-import java.io.FileNotFoundException;
-import java.util.Scanner;
-import java.io.File;
import java.io.StringWriter;
import java.io.PrintWriter;
import java.util.List;
@@ -231,62 +228,27 @@ public class stepA_more {
public static MalVal RE(Env env, String str) throws MalThrowable {
return EVAL(READ(str), env);
}
- public static Env _ref(Env env, String name, MalVal mv) {
- return env.set(name, mv);
- }
- public static String slurp(String fname) throws MalThrowable {
- try {
- return new Scanner(new File(fname))
- .useDelimiter("\\Z").next();
- } catch (FileNotFoundException e) {
- throw new MalError(e.getMessage());
- }
- }
public static void main(String[] args) throws MalThrowable {
String prompt = "user> ";
final Env repl_env = new Env(null);
+
+ // core.java: defined using Java
for (String key : core.ns.keySet()) {
- _ref(repl_env, key, core.ns.get(key));
+ repl_env.set(key, core.ns.get(key));
}
- _ref(repl_env, "readline", new MalFunction() {
- public MalVal apply(MalList args) throws MalThrowable {
- String prompt = ((MalString)args.nth(0)).getValue();
- try {
- return new MalString(readline.readline(prompt));
- } catch (IOException e) {
- throw new MalException(new MalString(e.getMessage()));
- } catch (readline.EOFException e) {
- throw new MalException(new MalString(e.getMessage()));
- }
- }
- });
- _ref(repl_env, "read-string", new MalFunction() {
- public MalVal apply(MalList args) throws MalThrowable {
- try {
- return reader.read_str(((MalString)args.nth(0)).getValue());
- } catch (MalContinue c) {
- return types.Nil;
- }
- }
- });
- _ref(repl_env, "eval", new MalFunction() {
+ repl_env.set("eval", new MalFunction() {
public MalVal apply(MalList args) throws MalThrowable {
return EVAL(args.nth(0), repl_env);
}
});
- _ref(repl_env, "slurp", new MalFunction() {
- public MalVal apply(MalList args) throws MalThrowable {
- String fname = ((MalString)args.nth(0)).getValue();
- return new MalString(slurp(fname));
- }
- });
+ // core.mal: defined using the language itself
RE(repl_env, "(def! not (fn* (a) (if a false true)))");
+ RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
RE(repl_env, "(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)))))))");
RE(repl_env, "(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))))))))");
- RE(repl_env, "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
Integer fileIdx = 0;
if (args.length > 0 && args[0].equals("--raw")) {
diff --git a/js/core.js b/js/core.js
index 7addc49..d5c014f 100644
--- a/js/core.js
+++ b/js/core.js
@@ -4,6 +4,8 @@ if (typeof module === 'undefined') {
var exports = core;
} else {
var types = require('./types'),
+ readline = require('./node_readline'),
+ reader = require('./reader'),
printer = require('./printer');
}
@@ -36,6 +38,10 @@ function println() {
}));
}
+function slurp(f) {
+ return require('fs').readFileSync(f, 'utf-8');
+}
+
// Hash Map functions
function assoc(src_hm) {
@@ -144,10 +150,14 @@ var ns = {'type': types._obj_type,
'false?': types._false_Q,
'symbol': types._symbol,
'symbol?': types._symbol_Q,
+
'pr-str': pr_str,
'str': str,
'prn': prn,
'println': println,
+ 'readline': readline.readline,
+ 'read-string': reader.read_str,
+ 'slurp': slurp,
'<' : function(a,b){return a<b;},
'<=' : function(a,b){return a<=b;},
'>' : function(a,b){return a>b;},
diff --git a/js/step3_env.js b/js/step3_env.js
index 86981d2..7dbefc4 100644
--- a/js/step3_env.js
+++ b/js/step3_env.js
@@ -69,12 +69,11 @@ function PRINT(exp) {
// repl
var repl_env = new Env();
var rep = function(str) { return PRINT(EVAL(READ(str), repl_env)); };
-_ref = function (k,v) { repl_env.set(k, v); }
-_ref('+', function(a,b){return a+b;});
-_ref('-', function(a,b){return a-b;});
-_ref('*', function(a,b){return a*b;});
-_ref('/', function(a,b){return a/b;});
+repl_env.set('+', function(a,b){return a+b;});
+repl_env.set('-', function(a,b){return a-b;});
+repl_env.set('*', function(a,b){return a*b;});
+repl_env.set('/', function(a,b){return a/b;});
if (typeof require === 'undefined') {
// Asynchronous browser mode
diff --git a/js/step4_if_fn_do.js b/js/step4_if_fn_do.js
index a80190e..7d679a9 100644
--- a/js/step4_if_fn_do.js
+++ b/js/step4_if_fn_do.js
@@ -84,12 +84,12 @@ function PRINT(exp) {
// repl
var repl_env = new Env();
var rep = function(str) { return PRINT(EVAL(READ(str), repl_env)); };
-_ref = function (k,v) { repl_env.set(k, v); }
-// Import core functions
+// core.js: defined using javascript
for (var n in core.ns) { repl_env.set(n, core.ns[n]); }
+repl_env.set('eval', function(ast) { return EVAL(ast, repl_env); });
-// Defined using the language itself
+// core.mal: defined using the language itself
rep("(def! not (fn* (a) (if a false true)))");
if (typeof require === 'undefined') {
diff --git a/js/step5_tco.js b/js/step5_tco.js
index dbeaa90..320807c 100644
--- a/js/step5_tco.js
+++ b/js/step5_tco.js
@@ -93,12 +93,12 @@ function PRINT(exp) {
// repl
var repl_env = new Env();
var rep = function(str) { return PRINT(EVAL(READ(str), repl_env)); };
-_ref = function (k,v) { repl_env.set(k, v); }
-// Import core functions
+// core.js: defined using javascript
for (var n in core.ns) { repl_env.set(n, core.ns[n]); }
+repl_env.set('eval', function(ast) { return EVAL(ast, repl_env); });
-// Defined using the language itself
+// core.mal: defined using the language itself
rep("(def! not (fn* (a) (if a false true)))");
if (typeof require === 'undefined') {
diff --git a/js/step6_file.js b/js/step6_file.js
index ee39501..aed1825 100644
--- a/js/step6_file.js
+++ b/js/step6_file.js
@@ -93,18 +93,12 @@ function PRINT(exp) {
// repl
var repl_env = new Env();
var rep = function(str) { return PRINT(EVAL(READ(str), repl_env)); };
-_ref = function (k,v) { repl_env.set(k, v); }
-// Import core functions
+// core.js: defined using javascript
for (var n in core.ns) { repl_env.set(n, core.ns[n]); }
+repl_env.set('eval', function(ast) { return EVAL(ast, repl_env); });
-_ref('read-string', reader.read_str);
-_ref('eval', function(ast) { return EVAL(ast, repl_env); });
-_ref('slurp', function(f) {
- return require('fs').readFileSync(f, 'utf-8');
-});
-
-// 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/js/step7_quote.js b/js/step7_quote.js
index 6782647..a7f4535 100644
--- a/js/step7_quote.js
+++ b/js/step7_quote.js
@@ -117,18 +117,12 @@ function PRINT(exp) {
// repl
var repl_env = new Env();
var rep = function(str) { return PRINT(EVAL(READ(str), repl_env)); };
-_ref = function (k,v) { repl_env.set(k, v); }
-// Import core functions
+// core.js: defined using javascript
for (var n in core.ns) { repl_env.set(n, core.ns[n]); }
+repl_env.set('eval', function(ast) { return EVAL(ast, repl_env); });
-_ref('read-string', reader.read_str);
-_ref('eval', function(ast) { return EVAL(ast, repl_env); });
-_ref('slurp', function(f) {
- return require('fs').readFileSync(f, 'utf-8');
-});
-
-// 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/js/step8_macros.js b/js/step8_macros.js
index f50bba4..1268a4d 100644
--- a/js/step8_macros.js
+++ b/js/step8_macros.js
@@ -141,20 +141,16 @@ function PRINT(exp) {
// repl
var repl_env = new Env();
var rep = function(str) { return PRINT(EVAL(READ(str), repl_env)); };
-_ref = function (k,v) { repl_env.set(k, v); }
-// Import core functions
+// core.js: defined using javascript
for (var n in core.ns) { repl_env.set(n, core.ns[n]); }
+repl_env.set('eval', function(ast) { return EVAL(ast, repl_env); });
-_ref('read-string', reader.read_str);
-_ref('eval', function(ast) { return EVAL(ast, repl_env); });
-_ref('slurp', function(f) {
- return require('fs').readFileSync(f, 'utf-8');
-});
-
-// 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 (typeof process !== 'undefined' && process.argv.length > 2) {
for (var i=2; i < process.argv.length; i++) {
diff --git a/js/step9_interop.js b/js/step9_interop.js
index 4987931..1fd07d4 100644
--- a/js/step9_interop.js
+++ b/js/step9_interop.js
@@ -147,20 +147,16 @@ function PRINT(exp) {
// repl
var repl_env = new Env();
var rep = function(str) { return PRINT(EVAL(READ(str), repl_env)); };
-_ref = function (k,v) { repl_env.set(k, v); }
-// Import core functions
+// core.js: defined using javascript
for (var n in core.ns) { repl_env.set(n, core.ns[n]); }
+repl_env.set('eval', function(ast) { return EVAL(ast, repl_env); });
-_ref('read-string', reader.read_str);
-_ref('eval', function(ast) { return EVAL(ast, repl_env); });
-_ref('slurp', function(f) {
- return require('fs').readFileSync(f, 'utf-8');
-});
-
-// 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 (typeof process !== 'undefined' && process.argv.length > 2) {
for (var i=2; i < process.argv.length; i++) {
diff --git a/js/stepA_more.js b/js/stepA_more.js
index a4fe21a..06eb43d 100644
--- a/js/stepA_more.js
+++ b/js/stepA_more.js
@@ -158,23 +158,16 @@ function PRINT(exp) {
// repl
var repl_env = new Env();
var rep = function(str) { return PRINT(EVAL(READ(str), repl_env)); };
-_ref = function (k,v) { repl_env.set(k, v); }
-// Import core functions
+// core.js: defined using javascript
for (var n in core.ns) { repl_env.set(n, core.ns[n]); }
+repl_env.set('eval', function(ast) { return EVAL(ast, repl_env); });
-_ref('readline', readline.readline)
-_ref('read-string', reader.read_str);
-_ref('eval', function(ast) { return EVAL(ast, repl_env); });
-_ref('slurp', function(f) {
- return require('fs').readFileSync(f, 'utf-8');
-});
-
-// 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 (typeof process !== 'undefined' && process.argv.length > 2) {
for (var i=2; i < process.argv.length; i++) {
diff --git a/make/core.mk b/make/core.mk
index fbea5ea..80f51ac 100644
--- a/make/core.mk
+++ b/make/core.mk
@@ -8,6 +8,8 @@ __mal_core_included := true
_TOP_DIR := $(dir $(lastword $(MAKEFILE_LIST)))
include $(_TOP_DIR)util.mk
include $(_TOP_DIR)types.mk
+include $(_TOP_DIR)readline.mk
+include $(_TOP_DIR)reader.mk
include $(_TOP_DIR)printer.mk
@@ -49,12 +51,16 @@ number_divide = $(call _pnumber,$(call int_divide,$($(word 1,$(1))_value),$($(wo
# String functions
+string? = $(if $(call _string?,$(1)),$(__true),$(__false))
+
pr_str = $(call _string,$(call _pr_str_mult,$(1),yes, ))
str = $(call _string,$(call _pr_str_mult,$(1),,))
prn = $(info $(call _pr_str_mult,$(1),yes, ))
println = $(info $(subst \n,$(NEWLINE),$(call _pr_str_mult,$(1),, )))
-string? = $(if $(call _string?,$(1)),$(__true),$(__false))
+readline= $(foreach res,$(call _string,$(call READLINE,"$(call str_decode,$($(1)_value))")),$(if $(READLINE_EOF),$(__nil),$(res)))
+read_str= $(call READ_STR,$(1))
+slurp = $(call _string,$(call _read_file,$(call str_decode,$($(1)_value))))
subs = $(strip \
$(foreach start,$(call gmsl_plus,1,$(call int_decode,$($(word 2,$(1))_value))),\
@@ -205,10 +211,14 @@ core_ns = type obj_type \
symbol? symbol? \
function? function? \
string? string? \
+ \
pr-str pr_str \
str str \
prn prn \
println println \
+ readline readline \
+ read-string read_str \
+ slurp slurp \
subs subs \
number? number? \
< number_lt \
diff --git a/make/step3_env.mk b/make/step3_env.mk
index 7c505cf..acc038d 100644
--- a/make/step3_env.mk
+++ b/make/step3_env.mk
@@ -86,11 +86,10 @@ REP = $(call PRINT,$(strip $(call EVAL,$(strip $(call READ,$(1))),$(REPL_ENV))))
REPL = $(info $(call REP,$(call READLINE,"user> ")))$(if $(READLINE_EOF),,$(call REPL))
# Setup the environment
-_ref = $(eval REPL_ENV := $(call ENV_SET,$(REPL_ENV),$(1),$(if $(2),$(2),$(1))))
-$(call _ref,+,number_plus)
-$(call _ref,-,number_subtract)
-$(call _ref,*,number_multiply)
-$(call _ref,/,number_divide)
+REPL_ENV := $(call ENV_SET,$(REPL_ENV),+,number_plus)
+REPL_ENV := $(call ENV_SET,$(REPL_ENV),-,number_subtract)
+REPL_ENV := $(call ENV_SET,$(REPL_ENV),*,number_multiply)
+REPL_ENV := $(call ENV_SET,$(REPL_ENV),/,number_divide)
# Call the read-eval-print loop
$(if $(strip $(INTERACTIVE)),$(call REPL))
diff --git a/make/step4_if_fn_do.mk b/make/step4_if_fn_do.mk
index f45cfa9..13dcf1c 100644
--- a/make/step4_if_fn_do.mk
+++ b/make/step4_if_fn_do.mk
@@ -101,14 +101,12 @@ REPL_ENV := $(call ENV)
REP = $(call PRINT,$(strip $(call EVAL,$(strip $(call READ,$(1))),$(REPL_ENV))))
REPL = $(info $(call REP,$(call READLINE,"user> ")))$(if $(READLINE_EOF),,$(call REPL))
-# Setup the environment
+# core.mk: defined using Make
_fref = $(eval REPL_ENV := $(call ENV_SET,$(REPL_ENV),$(1),$(call _function,$$(call $(2),$$1))))
-
-# Import core namespace
_import_core = $(if $(strip $(1)),$(call _fref,$(word 1,$(1)),$(word 2,$(1)))$(call _import_core,$(wordlist 3,$(words $(1)),$(1))),)
$(call _import_core,$(core_ns))
-# Defined in terms of the language itself
+# core.mal: defined in terms of the language itself
$(call do,$(call REP, (def! not (fn* (a) (if a false true))) ))
# Call the read-eval-print loop
diff --git a/make/step6_file.mk b/make/step6_file.mk
index c791b33..494cbb2 100644
--- a/make/step6_file.mk
+++ b/make/step6_file.mk
@@ -101,21 +101,13 @@ REPL_ENV := $(call ENV)
REP = $(call PRINT,$(strip $(call EVAL,$(strip $(call READ,$(1))),$(REPL_ENV))))
REPL = $(info $(call REP,$(call READLINE,"user> ")))$(if $(READLINE_EOF),,$(call REPL))
-# Setup the environment
-_ref = $(eval REPL_ENV := $(call ENV_SET,$(REPL_ENV),$(1),$(if $(2),$(2),$(1))))
+# core.mk: defined using Make
_fref = $(eval REPL_ENV := $(call ENV_SET,$(REPL_ENV),$(1),$(call _function,$$(call $(2),$$1))))
-
-# Import core namespace
_import_core = $(if $(strip $(1)),$(call _fref,$(word 1,$(1)),$(word 2,$(1)))$(call _import_core,$(wordlist 3,$(words $(1)),$(1))),)
$(call _import_core,$(core_ns))
+REPL_ENV := $(call ENV_SET,$(REPL_ENV),eval,$(call _function,$$(call EVAL,$$(1),$$(REPL_ENV))))
-$(call _ref,read-string,$(call _function,$$(call READ_STR,$$(1))))
-$(call _ref,eval,$(call _function,$$(call EVAL,$$(1),$$(REPL_ENV))))
-
-_slurp = $(call _string,$(call _read_file,$(1)))
-$(call _ref,slurp,$(call _function,$$(call _slurp,$$(call str_decode,$$($$(1)_value)))))
-
-# Defined in terms of the language itself
+# core.mal: defined in terms of the language itself
$(call do,$(call REP, (def! not (fn* (a) (if a false true))) ))
$(call do,$(call REP, (def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")"))))) ))
diff --git a/make/step7_quote.mk b/make/step7_quote.mk
index 46e5130..af14e85 100644
--- a/make/step7_quote.mk
+++ b/make/step7_quote.mk
@@ -118,21 +118,13 @@ REPL_ENV := $(call ENV)
REP = $(call PRINT,$(strip $(call EVAL,$(strip $(call READ,$(1))),$(REPL_ENV))))
REPL = $(info $(call REP,$(call READLINE,"user> ")))$(if $(READLINE_EOF),,$(call REPL))
-# Setup the environment
-_ref = $(eval REPL_ENV := $(call ENV_SET,$(REPL_ENV),$(1),$(if $(2),$(2),$(1))))
+# core.mk: defined using Make
_fref = $(eval REPL_ENV := $(call ENV_SET,$(REPL_ENV),$(1),$(call _function,$$(call $(2),$$1))))
-
-# Import core namespace
_import_core = $(if $(strip $(1)),$(call _fref,$(word 1,$(1)),$(word 2,$(1)))$(call _import_core,$(wordlist 3,$(words $(1)),$(1))),)
$(call _import_core,$(core_ns))
+REPL_ENV := $(call ENV_SET,$(REPL_ENV),eval,$(call _function,$$(call EVAL,$$(1),$$(REPL_ENV))))
-$(call _ref,read-string,$(call _function,$$(call READ_STR,$$(1))))
-$(call _ref,eval,$(call _function,$$(call EVAL,$$(1),$$(REPL_ENV))))
-
-_slurp = $(call _string,$(call _read_file,$(1)))
-$(call _ref,slurp,$(call _function,$$(call _slurp,$$(call str_decode,$$($$(1)_value)))))
-
-# Defined in terms of the language itself
+# core.mal: defined in terms of the language itself
$(call do,$(call REP, (def! not (fn* (a) (if a false true))) ))
$(call do,$(call REP, (def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")"))))) ))
diff --git a/make/step8_macros.mk b/make/step8_macros.mk
index fee4bb0..8ed5df8 100644
--- a/make/step8_macros.mk
+++ b/make/step8_macros.mk
@@ -141,23 +141,17 @@ REPL_ENV := $(call ENV)
REP = $(call PRINT,$(strip $(call EVAL,$(strip $(call READ,$(1))),$(REPL_ENV))))
REPL = $(info $(call REP,$(call READLINE,"user> ")))$(if $(READLINE_EOF),,$(call REPL))
-# Setup the environment
-_ref = $(eval REPL_ENV := $(call ENV_SET,$(REPL_ENV),$(1),$(if $(2),$(2),$(1))))
+# core.mk: defined using Make
_fref = $(eval REPL_ENV := $(call ENV_SET,$(REPL_ENV),$(1),$(call _function,$$(call $(2),$$1))))
-
-# Import core namespace
_import_core = $(if $(strip $(1)),$(call _fref,$(word 1,$(1)),$(word 2,$(1)))$(call _import_core,$(wordlist 3,$(words $(1)),$(1))),)
$(call _import_core,$(core_ns))
+REPL_ENV := $(call ENV_SET,$(REPL_ENV),eval,$(call _function,$$(call EVAL,$$(1),$$(REPL_ENV))))
-$(call _ref,read-string,$(call _function,$$(call READ_STR,$$(1))))
-$(call _ref,eval,$(call _function,$$(call EVAL,$$(1),$$(REPL_ENV))))
-
-_slurp = $(call _string,$(call _read_file,$(1)))
-$(call _ref,slurp,$(call _function,$$(call _slurp,$$(call str_decode,$$($$(1)_value)))))
-
-# Defined in terms of the language itself
+# core.mal: defined in terms of the language itself
$(call do,$(call REP, (def! not (fn* (a) (if a false true))) ))
$(call do,$(call REP, (def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")"))))) ))
+$(call do,$(call 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))))))) ))
+$(call do,$(call 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)))))))) ))
# Load and eval any files specified on the command line
$(if $(MAKECMDGOALS),\
diff --git a/make/step9_interop.mk b/make/step9_interop.mk
index 4b7eaff..8c9220c 100644
--- a/make/step9_interop.mk
+++ b/make/step9_interop.mk
@@ -145,23 +145,17 @@ REPL_ENV := $(call ENV)
REP = $(call PRINT,$(strip $(call EVAL,$(strip $(call READ,$(1))),$(REPL_ENV))))
REPL = $(info $(call REP,$(call READLINE,"user> ")))$(if $(READLINE_EOF),,$(call REPL))
-# Setup the environment
-_ref = $(eval REPL_ENV := $(call ENV_SET,$(REPL_ENV),$(1),$(if $(2),$(2),$(1))))
+# core.mk: defined using Make
_fref = $(eval REPL_ENV := $(call ENV_SET,$(REPL_ENV),$(1),$(call _function,$$(call $(2),$$1))))
-
-# Import core namespace
_import_core = $(if $(strip $(1)),$(call _fref,$(word 1,$(1)),$(word 2,$(1)))$(call _import_core,$(wordlist 3,$(words $(1)),$(1))),)
$(call _import_core,$(core_ns))
+REPL_ENV := $(call ENV_SET,$(REPL_ENV),eval,$(call _function,$$(call EVAL,$$(1),$$(REPL_ENV))))
-$(call _ref,read-string,$(call _function,$$(call READ_STR,$$(1))))
-$(call _ref,eval,$(call _function,$$(call EVAL,$$(1),$$(REPL_ENV))))
-
-_slurp = $(call _string,$(call _read_file,$(1)))
-$(call _ref,slurp,$(call _function,$$(call _slurp,$$(call str_decode,$$($$(1)_value)))))
-
-# Defined in terms of the language itself
+# core.mal: defined in terms of the language itself
$(call do,$(call REP, (def! not (fn* (a) (if a false true))) ))
$(call do,$(call REP, (def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")"))))) ))
+$(call do,$(call 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))))))) ))
+$(call do,$(call 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)))))))) ))
# Load and eval any files specified on the command line
$(if $(MAKECMDGOALS),\
diff --git a/make/stepA_more.mk b/make/stepA_more.mk
index 3cd0d2a..00ae252 100644
--- a/make/stepA_more.mk
+++ b/make/stepA_more.mk
@@ -160,26 +160,17 @@ REPL_ENV := $(call ENV)
REP = $(call PRINT,$(strip $(call EVAL,$(strip $(call READ,$(1))),$(REPL_ENV))))
REPL = $(info $(call REP,$(call READLINE,"user> ")))$(if $(READLINE_EOF),,$(call REPL))
-# Setup the environment
-_ref = $(eval REPL_ENV := $(call ENV_SET,$(REPL_ENV),$(1),$(if $(2),$(2),$(1))))
+# core.mk: defined using Make
_fref = $(eval REPL_ENV := $(call ENV_SET,$(REPL_ENV),$(1),$(call _function,$$(call $(2),$$1))))
-
-# Import core namespace
_import_core = $(if $(strip $(1)),$(call _fref,$(word 1,$(1)),$(word 2,$(1)))$(call _import_core,$(wordlist 3,$(words $(1)),$(1))),)
$(call _import_core,$(core_ns))
+REPL_ENV := $(call ENV_SET,$(REPL_ENV),eval,$(call _function,$$(call EVAL,$$(1),$$(REPL_ENV))))
-$(call _ref,readline,$(call _function,$$(foreach res,$$(call _string,$$(call READLINE,"$$(call str_decode,$$($$(1)_value))")),$$(if $$(READLINE_EOF),$$(__nil),$$(res)))))
-$(call _ref,read-string,$(call _function,$$(call READ_STR,$$(1))))
-$(call _ref,eval,$(call _function,$$(call EVAL,$$(1),$$(REPL_ENV))))
-
-_slurp = $(call _string,$(call _read_file,$(1)))
-$(call _ref,slurp,$(call _function,$$(call _slurp,$$(call str_decode,$$($$(1)_value)))))
-
-# Defined in terms of the language itself
+# core.mal: defined in terms of the language itself
$(call do,$(call REP, (def! not (fn* (a) (if a false true))) ))
+$(call do,$(call REP, (def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")"))))) ))
$(call do,$(call 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))))))) ))
$(call do,$(call 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)))))))) ))
-$(call do,$(call REP, (def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")"))))) ))
# Load and eval any files specified on the command line
$(if $(MAKECMDGOALS),\
diff --git a/mal/core.mal b/mal/core.mal
index b616603..33b6a5e 100644
--- a/mal/core.mal
+++ b/mal/core.mal
@@ -5,10 +5,14 @@
["true?" true?]
["false?" false?]
["symbol?" symbol?]
+
["pr-str" pr-str]
["str" str]
["prn" prn]
["println" println]
+ ["readline" readline]
+ ["read-string" read-string]
+ ["slurp" slurp]
["<" <]
["<=" <=]
[">" >]
diff --git a/mal/step3_env.mal b/mal/step3_env.mal
index a4f2c57..c812f17 100644
--- a/mal/step3_env.mal
+++ b/mal/step3_env.mal
@@ -60,11 +60,10 @@
(def! rep (fn* [strng]
(PRINT (EVAL (READ strng) repl-env))))
-(def! _ref (fn* [k v] (env-set repl-env k v)))
-(_ref "+" +)
-(_ref "-" -)
-(_ref "*" *)
-(_ref "/" /)
+(env-set repl-env "+" +)
+(env-set repl-env "-" -)
+(env-set repl-env "*" *)
+(env-set repl-env "/" /)
(def! -main (fn* []
(let* [line (readline "mal-user> ")]
diff --git a/mal/step4_if_fn_do.mal b/mal/step4_if_fn_do.mal
index 7107ac4..aa48112 100644
--- a/mal/step4_if_fn_do.mal
+++ b/mal/step4_if_fn_do.mal
@@ -57,7 +57,7 @@
(EVAL (nth ast 3) env)
nil)
(EVAL (nth ast 2) env)))
-
+
(= 'fn* a0)
(fn* [& args]
(EVAL (nth ast 2) (new-env env (nth ast 1) args)))
@@ -77,12 +77,10 @@
(def! rep (fn* [strng]
(PRINT (EVAL (READ strng) repl-env))))
-(def! _ref (fn* [k v] (env-set repl-env k v)))
-
-;; Import core namespace functions
-(map (fn* [data] (_ref (nth data 0) (nth data 1))) core_ns)
+;; core.mal: defined directly using mal
+(map (fn* [data] (env-set repl-env (nth data 0) (nth data 1))) core_ns)
-;; Defined using the language itself
+;; core.mal: defined using the new language itself
(rep "(def! not (fn* [a] (if a false true)))")
(def! -main (fn* []
diff --git a/mal/step6_file.mal b/mal/step6_file.mal
index fa5991a..905f9fd 100644
--- a/mal/step6_file.mal
+++ b/mal/step6_file.mal
@@ -77,16 +77,11 @@
(def! rep (fn* [strng]
(PRINT (EVAL (READ strng) repl-env))))
-(def! _ref (fn* [k v] (env-set repl-env k v)))
-
-;; Import core namespace functions
-(map (fn* [data] (_ref (nth data 0) (nth data 1))) core_ns)
-
-;; Defined using the language itself
-(_ref 'read-string read-string)
-(_ref 'eval (fn* [ast] (EVAL ast repl-env)))
-(_ref 'slurp slurp)
+;; core.mal: defined directly using mal
+(map (fn* [data] (env-set repl-env (nth data 0) (nth data 1))) core_ns)
+(env-set repl-env 'eval (fn* [ast] (EVAL ast repl-env)))
+;; core.mal: defined using the new 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/mal/step7_quote.mal b/mal/step7_quote.mal
index 5195d38..c95db5d 100644
--- a/mal/step7_quote.mal
+++ b/mal/step7_quote.mal
@@ -105,16 +105,11 @@
(def! rep (fn* [strng]
(PRINT (EVAL (READ strng) repl-env))))
-(def! _ref (fn* [k v] (env-set repl-env k v)))
-
-;; Import core namespace functions
-(map (fn* [data] (_ref (nth data 0) (nth data 1))) core_ns)
-
-;; Defined using the language itself
-(_ref 'read-string read-string)
-(_ref 'eval (fn* [ast] (EVAL ast repl-env)))
-(_ref 'slurp slurp)
+;; core.mal: defined directly using mal
+(map (fn* [data] (env-set repl-env (nth data 0) (nth data 1))) core_ns)
+(env-set repl-env 'eval (fn* [ast] (EVAL ast repl-env)))
+;; core.mal: defined using the new 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/mal/step8_macros.mal b/mal/step8_macros.mal
index d2b2bd4..feec227 100644
--- a/mal/step8_macros.mal
+++ b/mal/step8_macros.mal
@@ -137,18 +137,15 @@
(def! rep (fn* [strng]
(PRINT (EVAL (READ strng) repl-env))))
-(def! _ref (fn* [k v] (env-set repl-env k v)))
-
-;; Import core namespace functions
-(map (fn* [data] (_ref (nth data 0) (nth data 1))) core_ns)
-
-;; Defined using the language itself
-(_ref 'read-string read-string)
-(_ref 'eval (fn* [ast] (EVAL ast repl-env)))
-(_ref 'slurp slurp)
+;; core.mal: defined directly using mal
+(map (fn* [data] (env-set repl-env (nth data 0) (nth data 1))) core_ns)
+(env-set repl-env 'eval (fn* [ast] (EVAL ast repl-env)))
+;; core.mal: defined using the new 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))))))))")
(def! -main (fn* []
(let* [line (readline "mal-user> ")]
diff --git a/mal/stepA_more.mal b/mal/stepA_more.mal
index 61eb029..b56a697 100644
--- a/mal/stepA_more.mal
+++ b/mal/stepA_more.mal
@@ -148,21 +148,15 @@
(def! rep (fn* [strng]
(PRINT (EVAL (READ strng) repl-env))))
-(def! _ref (fn* [k v] (env-set repl-env k v)))
-
-;; Import core namespace functions
-(map (fn* [data] (_ref (nth data 0) (nth data 1))) core_ns)
-
-;; Defined using the language itself
-(_ref 'readline readline)
-(_ref 'read-string read-string)
-(_ref 'eval (fn* [ast] (EVAL ast repl-env)))
-(_ref 'slurp slurp)
+;; core.mal: defined directly using mal
+(map (fn* [data] (env-set repl-env (nth data 0) (nth data 1))) core_ns)
+(env-set repl-env 'eval (fn* [ast] (EVAL ast repl-env)))
+;; core.mal: defined using the new 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) \")\")))))")
(def! -main (fn* []
(let* [line (readline "mal-user> ")]
diff --git a/php/core.php b/php/core.php
index 16d34f8..39a22ac 100644
--- a/php/core.php
+++ b/php/core.php
@@ -1,6 +1,8 @@
<?php
require_once 'types.php';
+require_once 'readline.php';
+require_once 'reader.php';
require_once 'printer.php';
// Error/Exception functions
@@ -169,11 +171,15 @@ $core_ns = array(
'false?'=> function ($a) { return _false_Q($a); },
'symbol'=> function () { return call_user_func_array('_symbol', func_get_args()); },
'symbol?'=> function ($a) { return _symbol_Q($a); },
+
'string?'=> function ($a) { return _string_Q($a); },
'pr-str'=> function () { return call_user_func_array('pr_str', func_get_args()); },
'str'=> function () { return call_user_func_array('str', func_get_args()); },
'prn'=> function () { return call_user_func_array('prn', func_get_args()); },
'println'=>function () { return call_user_func_array('println', func_get_args()); },
+ 'readline'=>function ($a) { return mal_readline($a); },
+ 'read-string'=>function ($a) { return read_str($a); },
+ 'slurp'=> function ($a) { return file_get_contents($a); },
'<'=> function ($a, $b) { return $a < $b; },
'<='=> function ($a, $b) { return $a <= $b; },
'>'=> function ($a, $b) { return $a > $b; },
diff --git a/php/step2_eval.php b/php/step2_eval.php
index 0ef184a..1cec7f7 100644
--- a/php/step2_eval.php
+++ b/php/step2_eval.php
@@ -55,6 +55,7 @@ function rep($str) {
global $repl_env;
return MAL_PRINT(MAL_EVAL(READ($str), $repl_env));
}
+
$repl_env['+'] = function ($a, $b) { return intval($a + $b,10); };
$repl_env['-'] = function ($a, $b) { return intval($a - $b,10); };
$repl_env['*'] = function ($a, $b) { return intval($a * $b,10); };
diff --git a/php/step3_env.php b/php/step3_env.php
index 83ced32..3c46b04 100644
--- a/php/step3_env.php
+++ b/php/step3_env.php
@@ -72,12 +72,11 @@ function rep($str) {
global $repl_env;
return MAL_PRINT(MAL_EVAL(READ($str), $repl_env));
}
-function _ref($k, $v) { global $repl_env; $repl_env->set($k, $v); }
-_ref('+', function ($a, $b) { return intval($a + $b,10); });
-_ref('-', function ($a, $b) { return intval($a - $b,10); });
-_ref('*', function ($a, $b) { return intval($a * $b,10); });
-_ref('/', function ($a, $b) { return intval($a / $b,10); });
+$repl_env->set('+', function ($a, $b) { return intval($a + $b,10); });
+$repl_env->set('-', function ($a, $b) { return intval($a - $b,10); });
+$repl_env->set('*', function ($a, $b) { return intval($a * $b,10); });
+$repl_env->set('/', function ($a, $b) { return intval($a / $b,10); });
do {
try {
diff --git a/php/step4_if_fn_do.php b/php/step4_if_fn_do.php
index 25ca7c5..83734b1 100644
--- a/php/step4_if_fn_do.php
+++ b/php/step4_if_fn_do.php
@@ -90,11 +90,13 @@ function rep($str) {
global $repl_env;
return MAL_PRINT(MAL_EVAL(READ($str), $repl_env));
}
-function _ref($k, $v) { global $repl_env; $repl_env->set($k, $v); }
-// Import core functions
-foreach ($core_ns as $k=>$v) { _ref($k, $v); }
-// Defined using the language itself
+// core.php: defined using PHP
+foreach ($core_ns as $k=>$v) {
+ $repl_env->set($k, _function($v));
+}
+
+// core.mal: defined using the language itself
rep("(def! not (fn* (a) (if a false true)))");
do {
diff --git a/php/step5_tco.php b/php/step5_tco.php
index cd4787e..31e2980 100644
--- a/php/step5_tco.php
+++ b/php/step5_tco.php
@@ -99,14 +99,13 @@ function rep($str) {
global $repl_env;
return MAL_PRINT(MAL_EVAL(READ($str), $repl_env));
}
-function _ref($k, $v) {
- global $repl_env;
+
+// core.php: defined using PHP
+foreach ($core_ns as $k=>$v) {
$repl_env->set($k, _function($v));
}
-// Import core functions
-foreach ($core_ns as $k=>$v) { _ref($k, $v); }
-// Defined using the language itself
+// core.mal: defined using the language itself
rep("(def! not (fn* (a) (if a false true)))");
do {
diff --git a/php/step6_file.php b/php/step6_file.php
index 95b3982..0a632c0 100644
--- a/php/step6_file.php
+++ b/php/step6_file.php
@@ -99,22 +99,16 @@ function rep($str) {
global $repl_env;
return MAL_PRINT(MAL_EVAL(READ($str), $repl_env));
}
-function _ref($k, $v) {
- global $repl_env;
+
+// core.php: defined using PHP
+foreach ($core_ns as $k=>$v) {
$repl_env->set($k, _function($v));
}
-// Import core functions
-foreach ($core_ns as $k=>$v) { _ref($k, $v); }
-
-_ref('read-string', 'read_str');
-_ref('eval', function($ast) {
+$repl_env->set('eval', _function(function($ast) {
global $repl_env; return MAL_EVAL($ast, $repl_env);
-});
-_ref('slurp', function($f) {
- return file_get_contents($f);
-});
+}));
-// 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) \")\")))))");
@@ -122,21 +116,22 @@ if (count($argv) > 1) {
for ($i=1; $i < count($argv); $i++) {
rep('(load-file "' . $argv[$i] . '")');
}
-} else {
- do {
- try {
- $line = mal_readline("user> ");
- if ($line === NULL) { break; }
- if ($line !== "") {
- print(rep($line));
- }
- } catch (BlankException $e) {
- continue;
- } catch (Exception $e) {
- echo "Error: " . $e->getMessage() . "\n";
- echo $e->getTraceAsString() . "\n";
- }
- } while (true);
+ exit(0);
}
+do {
+ try {
+ $line = mal_readline("user> ");
+ if ($line === NULL) { break; }
+ if ($line !== "") {
+ print(rep($line));
+ }
+ } catch (BlankException $e) {
+ continue;
+ } catch (Exception $e) {
+ echo "Error: " . $e->getMessage() . "\n";
+ echo $e->getTraceAsString() . "\n";
+ }
+} while (true);
+
?>
diff --git a/php/step7_quote.php b/php/step7_quote.php
index 8c407c6..8296c1a 100644
--- a/php/step7_quote.php
+++ b/php/step7_quote.php
@@ -122,22 +122,16 @@ function rep($str) {
global $repl_env;
return MAL_PRINT(MAL_EVAL(READ($str), $repl_env));
}
-function _ref($k, $v) {
- global $repl_env;
+
+// core.php: defined using PHP
+foreach ($core_ns as $k=>$v) {
$repl_env->set($k, _function($v));
}
-// Import core functions
-foreach ($core_ns as $k=>$v) { _ref($k, $v); }
-
-_ref('read-string', 'read_str');
-_ref('eval', function($ast) {
+$repl_env->set('eval', _function(function($ast) {
global $repl_env; return MAL_EVAL($ast, $repl_env);
-});
-_ref('slurp', function($f) {
- return file_get_contents($f);
-});
+}));
-// 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) \")\")))))");
@@ -145,21 +139,22 @@ if (count($argv) > 1) {
for ($i=1; $i < count($argv); $i++) {
rep('(load-file "' . $argv[$i] . '")');
}
-} else {
- do {
- try {
- $line = mal_readline("user> ");
- if ($line === NULL) { break; }
- if ($line !== "") {
- print(rep($line));
- }
- } catch (BlankException $e) {
- continue;
- } catch (Exception $e) {
- echo "Error: " . $e->getMessage() . "\n";
- echo $e->getTraceAsString() . "\n";
- }
- } while (true);
+ exit(0);
}
+do {
+ try {
+ $line = mal_readline("user> ");
+ if ($line === NULL) { break; }
+ if ($line !== "") {
+ print(rep($line));
+ }
+ } catch (BlankException $e) {
+ continue;
+ } catch (Exception $e) {
+ echo "Error: " . $e->getMessage() . "\n";
+ echo $e->getTraceAsString() . "\n";
+ }
+} while (true);
+
?>
diff --git a/php/step8_macros.php b/php/step8_macros.php
index c6c7173..4723ffd 100644
--- a/php/step8_macros.php
+++ b/php/step8_macros.php
@@ -147,44 +147,41 @@ function rep($str) {
global $repl_env;
return MAL_PRINT(MAL_EVAL(READ($str), $repl_env));
}
-function _ref($k, $v) {
- global $repl_env;
+
+// core.php: defined using PHP
+foreach ($core_ns as $k=>$v) {
$repl_env->set($k, _function($v));
}
-// Import core functions
-foreach ($core_ns as $k=>$v) { _ref($k, $v); }
-
-_ref('read-string', 'read_str');
-_ref('eval', function($ast) {
+$repl_env->set('eval', _function(function($ast) {
global $repl_env; return MAL_EVAL($ast, $repl_env);
-});
-_ref('slurp', function($f) {
- return file_get_contents($f);
-});
+}));
-// 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 (count($argv) > 1) {
for ($i=1; $i < count($argv); $i++) {
rep('(load-file "' . $argv[$i] . '")');
}
-} else {
- do {
- try {
- $line = mal_readline("user> ");
- if ($line === NULL) { break; }
- if ($line !== "") {
- print(rep($line));
- }
- } catch (BlankException $e) {
- continue;
- } catch (Exception $e) {
- echo "Error: " . $e->getMessage() . "\n";
- echo $e->getTraceAsString() . "\n";
- }
- } while (true);
+ exit(0);
}
+do {
+ try {
+ $line = mal_readline("user> ");
+ if ($line === NULL) { break; }
+ if ($line !== "") {
+ print(rep($line));
+ }
+ } catch (BlankException $e) {
+ continue;
+ } catch (Exception $e) {
+ echo "Error: " . $e->getMessage() . "\n";
+ echo $e->getTraceAsString() . "\n";
+ }
+} while (true);
+
?>
diff --git a/php/step9_interop.php b/php/step9_interop.php
index 3debdc4..a46864c 100644
--- a/php/step9_interop.php
+++ b/php/step9_interop.php
@@ -149,44 +149,41 @@ function rep($str) {
global $repl_env;
return MAL_PRINT(MAL_EVAL(READ($str), $repl_env));
}
-function _ref($k, $v) {
- global $repl_env;
+
+// core.php: defined using PHP
+foreach ($core_ns as $k=>$v) {
$repl_env->set($k, _function($v));
}
-// Import core functions
-foreach ($core_ns as $k=>$v) { _ref($k, $v); }
-
-_ref('read-string', 'read_str');
-_ref('eval', function($ast) {
+$repl_env->set('eval', _function(function($ast) {
global $repl_env; return MAL_EVAL($ast, $repl_env);
-});
-_ref('slurp', function($f) {
- return file_get_contents($f);
-});
+}));
-// 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 (count($argv) > 1) {
for ($i=1; $i < count($argv); $i++) {
rep('(load-file "' . $argv[$i] . '")');
}
-} else {
- do {
- try {
- $line = mal_readline("user> ");
- if ($line === NULL) { break; }
- if ($line !== "") {
- print(rep($line));
- }
- } catch (BlankException $e) {
- continue;
- } catch (Exception $e) {
- echo "Error: " . $e->getMessage() . "\n";
- echo $e->getTraceAsString() . "\n";
- }
- } while (true);
+ exit(0);
}
+do {
+ try {
+ $line = mal_readline("user> ");
+ if ($line === NULL) { break; }
+ if ($line !== "") {
+ print(rep($line));
+ }
+ } catch (BlankException $e) {
+ continue;
+ } catch (Exception $e) {
+ echo "Error: " . $e->getMessage() . "\n";
+ echo $e->getTraceAsString() . "\n";
+ }
+} while (true);
+
?>
diff --git a/php/stepA_more.php b/php/stepA_more.php
index 7478ee8..c599986 100644
--- a/php/stepA_more.php
+++ b/php/stepA_more.php
@@ -167,47 +167,41 @@ function rep($str) {
global $repl_env;
return MAL_PRINT(MAL_EVAL(READ($str), $repl_env));
}
-function _ref($k, $v) {
- global $repl_env;
+
+// core.php: defined using PHP
+foreach ($core_ns as $k=>$v) {
$repl_env->set($k, _function($v));
}
-// Import core functions
-foreach ($core_ns as $k=>$v) { _ref($k, $v); }
-
-_ref('readline', 'mal_readline');
-_ref('read-string', 'read_str');
-_ref('eval', function($ast) {
+$repl_env->set('eval', _function(function($ast) {
global $repl_env; return MAL_EVAL($ast, $repl_env);
-});
-_ref('slurp', function($f) {
- return file_get_contents($f);
-});
+}));
-// 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 (count($argv) > 1) {
for ($i=1; $i < count($argv); $i++) {
rep('(load-file "' . $argv[$i] . '")');
}
-} else {
- do {
- try {
- $line = mal_readline("user> ");
- if ($line === NULL) { break; }
- if ($line !== "") {
- print(rep($line));
- }
- } catch (BlankException $e) {
- continue;
- } catch (Exception $e) {
- echo "Error: " . $e->getMessage() . "\n";
- echo $e->getTraceAsString() . "\n";
- }
- } while (true);
+ exit(0);
}
+do {
+ try {
+ $line = mal_readline("user> ");
+ if ($line === NULL) { break; }
+ if ($line !== "") {
+ print(rep($line));
+ }
+ } catch (BlankException $e) {
+ continue;
+ } catch (Exception $e) {
+ echo "Error: " . $e->getMessage() . "\n";
+ echo $e->getTraceAsString() . "\n";
+ }
+} while (true);
+
?>
diff --git a/ps/core.ps b/ps/core.ps
index 34e846e..f9397fa 100644
--- a/ps/core.ps
+++ b/ps/core.ps
@@ -223,10 +223,14 @@ end } def
(true?) { 0 _nth _true? }
(false?) { 0 _nth _false? }
(symbol?) { 0 _nth _symbol? }
+
(pr-str) { /data get ( ) true _pr_str_args }
(str) { /data get () false _pr_str_args }
(prn) { /data get ( ) true _pr_str_args print (\n) print null }
(println) { /data get ( ) false _pr_str_args print (\n) print null }
+ (readline) { 0 _nth _readline not { pop null } if }
+ (read-string) { 0 _nth read_str }
+ (slurp) { 0 _nth (r) file dup bytesavailable string readstring pop }
(<) { dup 0 _nth exch 1 _nth lt }
(<=) { dup 0 _nth exch 1 _nth le }
(>) { dup 0 _nth exch 1 _nth gt }
diff --git a/ps/step3_env.ps b/ps/step3_env.ps
index e94f92c..42eda2c 100644
--- a/ps/step3_env.ps
+++ b/ps/step3_env.ps
@@ -81,8 +81,8 @@ end } def
/repl_env null null null env_new def
/REP { READ repl_env EVAL PRINT } def
-/_ref { repl_env 3 1 roll env_set pop } def
+/_ref { repl_env 3 1 roll env_set pop } def
(+) { dup 0 _nth exch 1 _nth add } _ref
(-) { dup 0 _nth exch 1 _nth sub } _ref
(*) { dup 0 _nth exch 1 _nth mul } _ref
diff --git a/ps/step4_if_fn_do.ps b/ps/step4_if_fn_do.ps
index 952661a..b01c594 100644
--- a/ps/step4_if_fn_do.ps
+++ b/ps/step4_if_fn_do.ps
@@ -111,10 +111,12 @@ end } def
/RE { READ repl_env EVAL } def
/REP { READ repl_env EVAL PRINT } def
-/_ref { _function repl_env 3 1 roll env_set pop } def
+% core.ps: defined using postscript
+/_ref { _function repl_env 3 1 roll env_set pop } def
core_ns { _ref } forall
+% core.mal: defined using the language itself
(\(def! not \(fn* \(a\) \(if a false true\)\)\)) RE pop
{ % loop
diff --git a/ps/step5_tco.ps b/ps/step5_tco.ps
index 802f3d3..50bcdbf 100644
--- a/ps/step5_tco.ps
+++ b/ps/step5_tco.ps
@@ -121,10 +121,12 @@ end } def
/RE { READ repl_env EVAL } def
/REP { READ repl_env EVAL PRINT } def
-/_ref { _function repl_env 3 1 roll env_set pop } def
+% core.ps: defined using postscript
+/_ref { _function repl_env 3 1 roll env_set pop } def
core_ns { _ref } forall
+% core.mal: defined using the language itself
(\(def! not \(fn* \(a\) \(if a false true\)\)\)) RE pop
{ % loop
diff --git a/ps/step6_file.ps b/ps/step6_file.ps
index fc12cc1..faa7101 100644
--- a/ps/step6_file.ps
+++ b/ps/step6_file.ps
@@ -121,15 +121,13 @@ end } def
/RE { READ repl_env EVAL } def
/REP { READ repl_env EVAL PRINT } def
-/_ref { _function repl_env 3 1 roll env_set pop } def
+% core.ps: defined using postscript
+/_ref { _function repl_env 3 1 roll env_set pop } def
core_ns { _ref } forall
-
-(read-string) { 0 _nth read_str } _ref
(eval) { 0 _nth repl_env EVAL } _ref
-/slurp { (r) file dup bytesavailable string readstring pop } def
-(slurp) { 0 _nth slurp } _ref
+% core.mal: defined using the language itself
(\(def! not \(fn* \(a\) \(if a false true\)\)\)) RE pop
(\(def! load-file \(fn* \(f\) \(eval \(read-string \(str "\(do " \(slurp f\) "\)"\)\)\)\)\)) RE pop
diff --git a/ps/step7_quote.ps b/ps/step7_quote.ps
index 6913bf6..f335683 100644
--- a/ps/step7_quote.ps
+++ b/ps/step7_quote.ps
@@ -153,15 +153,13 @@ end } def
/RE { READ repl_env EVAL } def
/REP { READ repl_env EVAL PRINT } def
-/_ref { _function repl_env 3 1 roll env_set pop } def
+% core.ps: defined using postscript
+/_ref { _function repl_env 3 1 roll env_set pop } def
core_ns { _ref } forall
-
-(read-string) { 0 _nth read_str } _ref
(eval) { 0 _nth repl_env EVAL } _ref
-/slurp { (r) file dup bytesavailable string readstring pop } def
-(slurp) { 0 _nth slurp } _ref
+% core.mal: defined using the language itself
(\(def! not \(fn* \(a\) \(if a false true\)\)\)) RE pop
(\(def! load-file \(fn* \(f\) \(eval \(read-string \(str "\(do " \(slurp f\) "\)"\)\)\)\)\)) RE pop
diff --git a/ps/step8_macros.ps b/ps/step8_macros.ps
index 286c1ab..87fafb1 100644
--- a/ps/step8_macros.ps
+++ b/ps/step8_macros.ps
@@ -195,17 +195,17 @@ end } def
/RE { READ repl_env EVAL } def
/REP { READ repl_env EVAL PRINT } def
-/_ref { _function repl_env 3 1 roll env_set pop } def
+% core.ps: defined using postscript
+/_ref { _function repl_env 3 1 roll env_set pop } def
core_ns { _ref } forall
-
-(read-string) { 0 _nth read_str } _ref
(eval) { 0 _nth repl_env EVAL } _ref
-/slurp { (r) file dup bytesavailable string readstring pop } def
-(slurp) { 0 _nth slurp } _ref
+% core.mal: defined using the language itself
(\(def! not \(fn* \(a\) \(if a false true\)\)\)) RE pop
(\(def! load-file \(fn* \(f\) \(eval \(read-string \(str "\(do " \(slurp f\) "\)"\)\)\)\)\)) RE pop
+(\(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\)\)\)\)\)\)\)) RE pop
+(\(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\)\)\)\)\)\)\)\)) RE pop
userdict /ARGUMENTS known { %if command line arguments
ARGUMENTS length 0 gt { %if more than 0 arguments
diff --git a/ps/step9_interop.ps b/ps/step9_interop.ps
index f4380da..fbf51a5 100644
--- a/ps/step9_interop.ps
+++ b/ps/step9_interop.ps
@@ -209,17 +209,17 @@ end } def
/RE { READ repl_env EVAL } def
/REP { READ repl_env EVAL PRINT } def
-/_ref { _function repl_env 3 1 roll env_set pop } def
+% core.ps: defined using postscript
+/_ref { _function repl_env 3 1 roll env_set pop } def
core_ns { _ref } forall
-
-(read-string) { 0 _nth read_str } _ref
(eval) { 0 _nth repl_env EVAL } _ref
-/slurp { (r) file dup bytesavailable string readstring pop } def
-(slurp) { 0 _nth slurp } _ref
+% core.mal: defined using the language itself
(\(def! not \(fn* \(a\) \(if a false true\)\)\)) RE pop
(\(def! load-file \(fn* \(f\) \(eval \(read-string \(str "\(do " \(slurp f\) "\)"\)\)\)\)\)) RE pop
+(\(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\)\)\)\)\)\)\)) RE pop
+(\(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\)\)\)\)\)\)\)\)) RE pop
userdict /ARGUMENTS known { %if command line arguments
ARGUMENTS length 0 gt { %if more than 0 arguments
diff --git a/ps/stepA_more.ps b/ps/stepA_more.ps
index 91a1fc7..1720b94 100644
--- a/ps/stepA_more.ps
+++ b/ps/stepA_more.ps
@@ -245,20 +245,17 @@ end } def
/RE { READ repl_env EVAL } def
/REP { READ repl_env EVAL PRINT } def
-/_ref { _function repl_env 3 1 roll env_set pop } def
+% core.ps: defined using postscript
+/_ref { _function repl_env 3 1 roll env_set pop } def
core_ns { _ref } forall
-
-(readline) { 0 _nth _readline not { pop null } if } _ref
-(read-string) { 0 _nth read_str } _ref
(eval) { 0 _nth repl_env EVAL } _ref
-/slurp { (r) file dup bytesavailable string readstring pop } def
-(slurp) { 0 _nth slurp } _ref
+% core.mal: defined using the language itself
(\(def! not \(fn* \(a\) \(if a false true\)\)\)) RE pop
+(\(def! load-file \(fn* \(f\) \(eval \(read-string \(str "\(do " \(slurp f\) "\)"\)\)\)\)\)) RE pop
(\(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\)\)\)\)\)\)\)) RE pop
(\(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\)\)\)\)\)\)\)\)) RE pop
-(\(def! load-file \(fn* \(f\) \(eval \(read-string \(str "\(do " \(slurp f\) "\)"\)\)\)\)\)) RE pop
userdict /ARGUMENTS known { %if command line arguments
ARGUMENTS length 0 gt { %if more than 0 arguments
diff --git a/python/core.py b/python/core.py
index 20ac793..54737aa 100644
--- a/python/core.py
+++ b/python/core.py
@@ -3,6 +3,8 @@ from itertools import chain
import mal_types as types
from mal_types import List, Vector
+import mal_readline
+import reader
import printer
# Errors/Exceptions
@@ -112,10 +114,14 @@ ns = {
'false?': types._false_Q,
'symbol': types._symbol,
'symbol?': types._symbol_Q,
+
'pr-str': pr_str,
'str': do_str,
'prn': prn,
'println': println,
+ 'readline': lambda prompt: mal_readline.readline(prompt),
+ 'read-string': reader.read_str,
+ 'slurp': lambda file: open(file).read(),
'<': lambda a,b: a<b,
'<=': lambda a,b: a<=b,
'>': lambda a,b: a>b,
diff --git a/python/step3_env.py b/python/step3_env.py
index f684274..372adc4 100644
--- a/python/step3_env.py
+++ b/python/step3_env.py
@@ -57,12 +57,11 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-_ref('+', lambda a,b: a+b)
-_ref('-', lambda a,b: a-b)
-_ref('*', lambda a,b: a*b)
-_ref('/', lambda a,b: int(a/b))
+repl_env.set('+', lambda a,b: a+b)
+repl_env.set('-', lambda a,b: a-b)
+repl_env.set('*', lambda a,b: a*b)
+repl_env.set('/', lambda a,b: int(a/b))
while True:
try:
diff --git a/python/step4_if_fn_do.py b/python/step4_if_fn_do.py
index d9910f6..a06d10b 100644
--- a/python/step4_if_fn_do.py
+++ b/python/step4_if_fn_do.py
@@ -72,12 +72,11 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-# Import types functions
-for name, val in core.ns.items(): _ref(name, val)
+# core.py: defined using python
+for k, v in core.ns.items(): repl_env.set(k, v)
-# Defined using the language itself
+# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
while True:
diff --git a/python/step5_tco.py b/python/step5_tco.py
index 633cbd8..7982073 100644
--- a/python/step5_tco.py
+++ b/python/step5_tco.py
@@ -79,12 +79,11 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-# Import types functions
-for name, val in core.ns.items(): _ref(name, val)
+# core.py: defined using python
+for k, v in core.ns.items(): repl_env.set(k, v)
-# Defined using the language itself
+# core.mal: defined using the language itself
REP("(def! not (fn* (a) (if a false true)))")
while True:
diff --git a/python/step6_file.py b/python/step6_file.py
index 1a992cc..ba2d355 100644
--- a/python/step6_file.py
+++ b/python/step6_file.py
@@ -79,16 +79,12 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-# Import types functions
-for name, val in core.ns.items(): _ref(name, val)
+# core.py: defined using python
+for k, v in core.ns.items(): repl_env.set(k, v)
+repl_env.set('eval', lambda ast: EVAL(ast, repl_env))
-_ref('read-string', reader.read_str)
-_ref('eval', lambda ast: EVAL(ast, repl_env))
-_ref('slurp', lambda file: open(file).read())
-
-# 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/python/step7_quote.py b/python/step7_quote.py
index cae3c99..aefa421 100644
--- a/python/step7_quote.py
+++ b/python/step7_quote.py
@@ -101,16 +101,12 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-# Import types functions
-for name, val in core.ns.items(): _ref(name, val)
+# core.py: defined using python
+for k, v in core.ns.items(): repl_env.set(k, v)
+repl_env.set('eval', lambda ast: EVAL(ast, repl_env))
-_ref('read-string', reader.read_str)
-_ref('eval', lambda ast: EVAL(ast, repl_env))
-_ref('slurp', lambda file: open(file).read())
-
-# 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/python/step8_macros.py b/python/step8_macros.py
index adb4546..90aedf3 100644
--- a/python/step8_macros.py
+++ b/python/step8_macros.py
@@ -121,18 +121,16 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-# Import types functions
-for name, val in core.ns.items(): _ref(name, val)
+# core.py: defined using python
+for k, v in core.ns.items(): repl_env.set(k, v)
+repl_env.set('eval', lambda ast: EVAL(ast, repl_env))
-_ref('read-string', reader.read_str)
-_ref('eval', lambda ast: EVAL(ast, repl_env))
-_ref('slurp', lambda file: open(file).read())
-
-# 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 len(sys.argv) >= 2:
REP('(load-file "' + sys.argv[1] + '")')
diff --git a/python/step9_interop.py b/python/step9_interop.py
index 1d8e55a..eae7837 100644
--- a/python/step9_interop.py
+++ b/python/step9_interop.py
@@ -130,18 +130,16 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-# Import types functions
-for name, val in core.ns.items(): _ref(name, val)
+# core.py: defined using python
+for k, v in core.ns.items(): repl_env.set(k, v)
+repl_env.set('eval', lambda ast: EVAL(ast, repl_env))
-_ref('read-string', reader.read_str)
-_ref('eval', lambda ast: EVAL(ast, repl_env))
-_ref('slurp', lambda file: open(file).read())
-
-# 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 len(sys.argv) >= 2:
REP('(load-file "' + sys.argv[1] + '")')
diff --git a/python/stepA_more.py b/python/stepA_more.py
index dccce8e..fa79ec3 100644
--- a/python/stepA_more.py
+++ b/python/stepA_more.py
@@ -144,21 +144,16 @@ def PRINT(exp):
repl_env = Env()
def REP(str):
return PRINT(EVAL(READ(str), repl_env))
-def _ref(k,v): repl_env.set(k, v)
-# Import types functions
-for name, val in core.ns.items(): _ref(name, val)
+# core.py: defined using python
+for k, v in core.ns.items(): repl_env.set(k, v)
+repl_env.set('eval', lambda ast: EVAL(ast, repl_env))
-_ref('readline', lambda prompt: mal_readline.readline(prompt))
-_ref('read-string', reader.read_str)
-_ref('eval', lambda ast: EVAL(ast, repl_env))
-_ref('slurp', lambda file: open(file).read())
-
-# 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 len(sys.argv) >= 2:
REP('(load-file "' + sys.argv[1] + '")')
diff --git a/ruby/core.rb b/ruby/core.rb
index 8823112..c7fc8c3 100644
--- a/ruby/core.rb
+++ b/ruby/core.rb
@@ -1,3 +1,7 @@
+require "readline"
+require "reader"
+require "printer"
+
$core_ns = {
:"=" => lambda {|a,b| a == b},
:throw => lambda {|a| raise MalException.new(a), "Mal Exception"},
@@ -6,10 +10,14 @@ $core_ns = {
:false? => lambda {|a| a == false},
:symbol? => lambda {|a| a.is_a? Symbol},
:symbol? => lambda {|a| a.is_a? Symbol},
+
:"pr-str" => lambda {|*a| a.map {|e| _pr_str(e, true)}.join(" ")},
- :"str" => lambda {|*a| a.map {|e| _pr_str(e, false)}.join("")},
- :"prn" => lambda {|*a| puts(a.map {|e| _pr_str(e, true)}.join(" "))},
- :"println" => lambda {|*a| puts(a.map {|e| _pr_str(e, false)}.join(" "))},
+ :str => lambda {|*a| a.map {|e| _pr_str(e, false)}.join("")},
+ :prn => lambda {|*a| puts(a.map {|e| _pr_str(e, true)}.join(" "))},
+ :println => lambda {|*a| puts(a.map {|e| _pr_str(e, false)}.join(" "))},
+ :readline => lambda {|a| Readline.readline(a,true)},
+ :"read-string" => lambda {|a| read_str(a)},
+ :slurp => lambda {|a| File.read(a)},
:< => lambda {|a,b| a < b},
:<= => lambda {|a,b| a <= b},
:> => lambda {|a,b| a > b},
diff --git a/ruby/step3_env.rb b/ruby/step3_env.rb
index ee80432..7266424 100644
--- a/ruby/step3_env.rb
+++ b/ruby/step3_env.rb
@@ -60,12 +60,11 @@ end
# repl
repl_env = Env.new
REP = lambda {|str| PRINT(EVAL(READ(str), repl_env)) }
-_ref = lambda {|k,v| repl_env.set(k, v) }
-_ref[:+, lambda {|a,b| a + b}]
-_ref[:-, lambda {|a,b| a - b}]
-_ref[:*, lambda {|a,b| a * b}]
-_ref[:/, lambda {|a,b| a / b}]
+repl_env.set(:+, lambda {|a,b| a + b})
+repl_env.set(:-, lambda {|a,b| a - b})
+repl_env.set(:*, lambda {|a,b| a * b})
+repl_env.set(:/, lambda {|a,b| a / b})
while line = Readline.readline("user> ", true)
begin
diff --git a/ruby/step4_if_fn_do.rb b/ruby/step4_if_fn_do.rb
index e99ed6c..559f81e 100644
--- a/ruby/step4_if_fn_do.rb
+++ b/ruby/step4_if_fn_do.rb
@@ -77,12 +77,12 @@ end
repl_env = Env.new
RE = lambda {|str| EVAL(READ(str), repl_env) }
REP = lambda {|str| PRINT(EVAL(READ(str), repl_env)) }
-_ref = lambda {|k,v| repl_env.set(k, v) }
-# Import core functions
-$core_ns.each &_ref
+# core.rb: defined using ruby
+$core_ns.each do |k,v| repl_env.set(k,v) end
+repl_env.set(:eval, lambda {|ast| EVAL(ast, repl_env)})
-# Defined using the language itself
+# core.mal: defined using the language itself
RE["(def! not (fn* (a) (if a false true)))"]
while line = Readline.readline("user> ", true)
diff --git a/ruby/step5_tco.rb b/ruby/step5_tco.rb
index 0b28a09..c6b5782 100644
--- a/ruby/step5_tco.rb
+++ b/ruby/step5_tco.rb
@@ -86,12 +86,12 @@ end
repl_env = Env.new
RE = lambda {|str| EVAL(READ(str), repl_env) }
REP = lambda {|str| PRINT(EVAL(READ(str), repl_env)) }
-_ref = lambda {|k,v| repl_env.set(k, v) }
-# Import core functions
-$core_ns.each &_ref
+# core.rb: defined using ruby
+$core_ns.each do |k,v| repl_env.set(k,v) end
+repl_env.set(:eval, lambda {|ast| EVAL(ast, repl_env)})
-# Defined using the language itself
+# core.mal: defined using the language itself
RE["(def! not (fn* (a) (if a false true)))"]
while line = Readline.readline("user> ", true)
diff --git a/ruby/step6_file.rb b/ruby/step6_file.rb
index 5425eac..6ca0d6d 100644
--- a/ruby/step6_file.rb
+++ b/ruby/step6_file.rb
@@ -86,16 +86,12 @@ end
repl_env = Env.new
RE = lambda {|str| EVAL(READ(str), repl_env) }
REP = lambda {|str| PRINT(EVAL(READ(str), repl_env)) }
-_ref = lambda {|k,v| repl_env.set(k, v) }
-# Import core functions
-$core_ns.each &_ref
+# core.rb: defined using ruby
+$core_ns.each do |k,v| repl_env.set(k,v) end
+repl_env.set(:eval, lambda {|ast| EVAL(ast, repl_env)})
-_ref[:"read-string", lambda {|str| read_str str}]
-_ref[:eval, lambda {|ast| EVAL(ast, repl_env)}]
-_ref[:slurp, lambda {|f| File.read(f) }]
-
-# Defined using the language itself
+# core.mal: defined using the language itself
RE["(def! not (fn* (a) (if a false true)))"]
RE["(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"]
diff --git a/ruby/step7_quote.rb b/ruby/step7_quote.rb
index a39b0ce..78ef117 100644
--- a/ruby/step7_quote.rb
+++ b/ruby/step7_quote.rb
@@ -106,16 +106,12 @@ end
repl_env = Env.new
RE = lambda {|str| EVAL(READ(str), repl_env) }
REP = lambda {|str| PRINT(EVAL(READ(str), repl_env)) }
-_ref = lambda {|k,v| repl_env.set(k, v) }
-# Import core functions
-$core_ns.each &_ref
+# core.rb: defined using ruby
+$core_ns.each do |k,v| repl_env.set(k,v) end
+repl_env.set(:eval, lambda {|ast| EVAL(ast, repl_env)})
-_ref[:"read-string", lambda {|str| read_str str}]
-_ref[:eval, lambda {|ast| EVAL(ast, repl_env)}]
-_ref[:slurp, lambda {|f| File.read(f) }]
-
-# Defined using the language itself
+# core.mal: defined using the language itself
RE["(def! not (fn* (a) (if a false true)))"]
RE["(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"]
diff --git a/ruby/step8_macros.rb b/ruby/step8_macros.rb
index 36f2a0d..db34159 100644
--- a/ruby/step8_macros.rb
+++ b/ruby/step8_macros.rb
@@ -131,18 +131,16 @@ end
repl_env = Env.new
RE = lambda {|str| EVAL(READ(str), repl_env) }
REP = lambda {|str| PRINT(EVAL(READ(str), repl_env)) }
-_ref = lambda {|k,v| repl_env.set(k, v) }
-# Import core functions
-$core_ns.each &_ref
+# core.rb: defined using ruby
+$core_ns.each do |k,v| repl_env.set(k,v) end
+repl_env.set(:eval, lambda {|ast| EVAL(ast, repl_env)})
-_ref[:"read-string", lambda {|str| read_str str}]
-_ref[:eval, lambda {|ast| EVAL(ast, repl_env)}]
-_ref[:slurp, lambda {|f| File.read(f) }]
-
-# Defined using the language itself
+# core.mal: defined using the language itself
RE["(def! not (fn* (a) (if a false true)))"]
RE["(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"]
+RE["(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)))))))"]
+RE["(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 ARGV.size > 0
ARGV.each {|f|
diff --git a/ruby/step9_interop.rb b/ruby/step9_interop.rb
index 869a86d..ba35146 100644
--- a/ruby/step9_interop.rb
+++ b/ruby/step9_interop.rb
@@ -133,18 +133,16 @@ end
repl_env = Env.new
RE = lambda {|str| EVAL(READ(str), repl_env) }
REP = lambda {|str| PRINT(EVAL(READ(str), repl_env)) }
-_ref = lambda {|k,v| repl_env.set(k, v) }
-# Import core functions
-$core_ns.each &_ref
+# core.rb: defined using ruby
+$core_ns.each do |k,v| repl_env.set(k,v) end
+repl_env.set(:eval, lambda {|ast| EVAL(ast, repl_env)})
-_ref[:"read-string", lambda {|str| read_str str}]
-_ref[:eval, lambda {|ast| EVAL(ast, repl_env)}]
-_ref[:slurp, lambda {|f| File.read(f) }]
-
-# Defined using the language itself
+# core.mal: defined using the language itself
RE["(def! not (fn* (a) (if a false true)))"]
RE["(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"]
+RE["(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)))))))"]
+RE["(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 ARGV.size > 0
ARGV.each {|f|
diff --git a/ruby/stepA_more.rb b/ruby/stepA_more.rb
index 974b3c7..42eac5b 100644
--- a/ruby/stepA_more.rb
+++ b/ruby/stepA_more.rb
@@ -148,21 +148,16 @@ end
repl_env = Env.new
RE = lambda {|str| EVAL(READ(str), repl_env) }
REP = lambda {|str| PRINT(EVAL(READ(str), repl_env)) }
-_ref = lambda {|k,v| repl_env.set(k, v) }
-# Import core functions
-$core_ns.each &_ref
+# core.rb: defined using ruby
+$core_ns.each do |k,v| repl_env.set(k,v) end
+repl_env.set(:eval, lambda {|ast| EVAL(ast, repl_env)})
-_ref[:"readline", lambda {|prompt| Readline.readline(prompt,true)}]
-_ref[:"read-string", lambda {|str| read_str str}]
-_ref[:eval, lambda {|ast| EVAL(ast, repl_env)}]
-_ref[:slurp, lambda {|f| File.read(f) }]
-
-# Defined using the language itself
+# core.mal: defined using the language itself
RE["(def! not (fn* (a) (if a false true)))"]
+RE["(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"]
RE["(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)))))))"]
RE["(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))))))))"]
-RE["(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"]
if ARGV.size > 0
ARGV.each {|f|
diff --git a/tests/step8_macros.mal b/tests/step8_macros.mal
index 03128ca..023c3d5 100644
--- a/tests/step8_macros.mal
+++ b/tests/step8_macros.mal
@@ -146,7 +146,7 @@
(cond false 7 false 8 false 9)
;=>nil
-;Testing all EVAL of non-default locations
+;; Testing all EVAL of non-default locations
(let* [x (or nil "yes")] x)
;=>"yes"
diff --git a/tests/stepA_more.mal b/tests/stepA_more.mal
index f2cc7eb..764c47f 100644
--- a/tests/stepA_more.mal
+++ b/tests/stepA_more.mal
@@ -313,21 +313,3 @@
(readline "mal-user> ")
"hello"
;=>"\"hello\""
-
-;;
-;; Testing macros cond and or
-(cond 1 2 3 4)
-;=>2
-(cond false 2 3 4)
-;=>4
-(cond false 2 false 4)
-;=>nil
-
-(or)
-;=>nil
-(or 1)
-;=>1
-(or 1 2)
-;=>1
-(or nil 2)
-;=>2