aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-04-17 21:49:07 -0500
committerJoel Martin <github@martintribe.org>2014-04-17 21:49:07 -0500
commitdb4c329aff4621e05b92a55be4f18173f5a4f655 (patch)
tree92baaa6d88246e509cfd6a7d03d8fab997e0b935
parent8cb5cda46cf3aef847ae3926dc53a5e5f87fe261 (diff)
downloadmal-db4c329aff4621e05b92a55be4f18173f5a4f655.tar.gz
mal-db4c329aff4621e05b92a55be4f18173f5a4f655.zip
All: perf test, Makefile refactor, add *host-language*
Other: - bash,make,postscript: quasiquote of vectors - Fix Java slurp - add time function to core.mal - switches on *host-language* for make time-secs vs time-ms - Ignore */experiments directories
-rw-r--r--.gitignore1
-rw-r--r--Makefile82
-rw-r--r--bash/core.sh9
-rwxr-xr-xbash/step7_quote.sh2
-rwxr-xr-xbash/step8_macros.sh2
-rwxr-xr-xbash/step9_interop.sh2
-rwxr-xr-xbash/stepA_more.sh5
-rw-r--r--c/core.c12
-rw-r--r--c/core.h2
-rw-r--r--c/stepA_more.c1
-rw-r--r--clojure/src/core.clj11
-rw-r--r--clojure/src/stepA_more.clj1
-rw-r--r--core.mal16
-rw-r--r--cs/core.cs6
-rw-r--r--cs/stepA_more.cs1
-rw-r--r--docs/TODO5
-rw-r--r--java/src/main/java/mal/core.java11
-rw-r--r--java/src/main/java/mal/stepA_more.java1
-rw-r--r--js/core.js5
-rw-r--r--js/stepA_more.js1
-rw-r--r--make/core.mk3
-rw-r--r--make/step7_quote.mk2
-rw-r--r--make/step8_macros.mk2
-rw-r--r--make/step9_interop.mk2
-rw-r--r--make/stepA_more.mk3
-rw-r--r--mal/stepA_more.mal1
-rw-r--r--php/core.php7
-rw-r--r--php/stepA_more.php1
-rw-r--r--ps/core.ps3
-rw-r--r--ps/env.ps2
-rw-r--r--ps/printer.ps2
-rw-r--r--ps/reader.ps2
-rw-r--r--ps/step7_quote.ps2
-rw-r--r--ps/step8_macros.ps2
-rw-r--r--ps/step9_interop.ps2
-rw-r--r--ps/stepA_more.ps3
-rw-r--r--ps/types.ps2
-rw-r--r--python/core.py3
-rw-r--r--python/stepA_more.py3
-rw-r--r--ruby/core.rb1
-rw-r--r--ruby/stepA_more.rb1
-rw-r--r--tests/perf1.mal10
-rw-r--r--tests/perf2.mal12
-rw-r--r--tests/step7_quote.mal6
44 files changed, 192 insertions, 61 deletions
diff --git a/.gitignore b/.gitignore
index 19ba294..0061f6e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+*/experiments
make/mal.mk
js/node_modules
js/mal.js
diff --git a/Makefile b/Makefile
index e986df4..2a99452 100644
--- a/Makefile
+++ b/Makefile
@@ -25,6 +25,7 @@ step9 = step9_interop
stepA = stepA_more
EXCLUDE_TESTS = test^make^step5 test^mal^step0 test^mal^step5 test^mal^step9 test^java^step9 test^cs^step9
+EXCLUDE_PERFS = perf^mal # TODO: fix this
#
# Utility functions
@@ -32,32 +33,36 @@ EXCLUDE_TESTS = test^make^step5 test^mal^step0 test^mal^step5 test^mal^step9 tes
STEP_TEST_FILES = $(strip $(wildcard $(1)/tests/$($(2)).mal) $(wildcard tests/$($(2)).mal))
-bash_STEP_TO_PROG = bash/$($(1)).sh
-c_STEP_TO_PROG = c/$($(1))
+bash_STEP_TO_PROG = bash/$($(1)).sh
+c_STEP_TO_PROG = c/$($(1))
clojure_STEP_TO_PROG = clojure/src/$($(1)).clj
-cs_STEP_TO_PROG = cs/$($(1)).exe
-java_STEP_TO_PROG = java/src/main/java/mal/$($(1)).java
-js_STEP_TO_PROG = js/$($(1)).js
-make_STEP_TO_PROG = make/$($(1)).mk
-mal_STEP_TO_PROG = mal/$($(1)).mal
-php_STEP_TO_PROG = php/$($(1)).php
-ps_STEP_TO_PROG = ps/$($(1)).ps
-python_STEP_TO_PROG = python/$($(1)).py
-ruby_STEP_TO_PROG = ruby/$($(1)).rb
-
-
-bash_RUNTEST = ../runtest.py $(4) ../$(1) -- bash ../$(2) $(5)
-c_RUNTEST = ../runtest.py $(4) ../$(1) -- ../$(2) $(5)
-clojure_RUNTEST = ../runtest.py $(4) ../$(1) -- lein with-profile +$(3) trampoline run $(5)
-cs_RUNTEST = ../runtest.py --redirect $(4) ../$(1) -- mono --debug ../$(2) --raw $(5)
-java_RUNTEST = ../runtest.py $(4) ../$(1) -- mvn -quiet exec:java -Dexec.mainClass="mal.$($(3))" -Dexec.args="--raw$(if $(5), $(5),)"
-js_RUNTEST = ../runtest.py $(4) ../$(1) -- node ../$(2) $(5)
-make_RUNTEST = ../runtest.py $(4) ../$(1) -- make -f ../$(2) $(5)
-mal_RUNTEST = $(call $(MAL_IMPL)_RUNTEST,$(1),$(call $(MAL_IMPL)_STEP_TO_PROG,stepA),stepA,--start-timeout 30 --test-timeout 120,../$(2))
-php_RUNTEST = ../runtest.py $(4) ../$(1) -- php ../$(2) $(5)
-ps_RUNTEST = ../runtest.py $(4) ../$(1) -- "gs -q -dNODISPLAY -- ../$(2) $(5)"
-python_RUNTEST = ../runtest.py $(4) ../$(1) -- $(PYTHON) ../$(2) $(5)
-ruby_RUNTEST = ../runtest.py $(4) ../$(1) -- ruby ../$(2) $(5)
+cs_STEP_TO_PROG = cs/$($(1)).exe
+java_STEP_TO_PROG = java/src/main/java/mal/$($(1)).java
+js_STEP_TO_PROG = js/$($(1)).js
+make_STEP_TO_PROG = make/$($(1)).mk
+mal_STEP_TO_PROG = mal/$($(1)).mal
+php_STEP_TO_PROG = php/$($(1)).php
+ps_STEP_TO_PROG = ps/$($(1)).ps
+python_STEP_TO_PROG = python/$($(1)).py
+ruby_STEP_TO_PROG = ruby/$($(1)).rb
+
+
+bash_RUNSTEP = bash ../$(2) $(3)
+c_RUNSTEP = ../$(2) $(3)
+clojure_RUNSTEP = lein with-profile +$(1) trampoline run $(3)
+cs_RUNSTEP = mono ../$(2) --raw $(3)
+java_RUNSTEP = mvn -quiet exec:java -Dexec.mainClass="mal.$($(1))" -Dexec.args="--raw$(if $(3), $(3),)"
+js_RUNSTEP = node ../$(2) $(3)
+make_RUNSTEP = make -f ../$(2) $(3)
+mal_RUNSTEP = $(call $(MAL_IMPL)_RUNSTEP,$(1),$(call $(MAL_IMPL)_STEP_TO_PROG,stepA),../$(2),") #"
+php_RUNSTEP = php ../$(2) $(3)
+ps_RUNSTEP = $(4)gs -q -dNODISPLAY -- ../$(2) $(3)$(4)
+python_RUNSTEP = $(PYTHON) ../$(2) $(3)
+ruby_RUNSTEP = ruby ../$(2) $(3)
+
+# Extra options to pass to runtest.py
+cs_TEST_OPTS = --redirect
+mal_TEST_OPTS = --start-timeout 30 --test-timeout 120
# Derived lists
@@ -72,6 +77,8 @@ ALL_TESTS = $(filter-out $(EXCLUDE_TESTS),\
IMPL_STATS = $(foreach impl,$(IMPLS),stats^$(impl))
IMPL_STATS_LISP = $(foreach impl,$(IMPLS),stats-lisp^$(impl))
+IMPL_PERF = $(filter-out $(EXCLUDE_PERFS),$(foreach impl,$(IMPLS),perf^$(impl)))
+
#
# Build rules
#
@@ -95,8 +102,8 @@ $(ALL_TESTS): $$(call $$(word 2,$$(subst ^, ,$$(@)))_STEP_TO_PROG,$$(word 3,$$(s
$(foreach test,$(call STEP_TEST_FILES,$(impl),$(step)),\
echo '----------------------------------------------'; \
echo 'Testing $@, step file: $+, test file: $(test)'; \
- echo 'Running: $(call $(impl)_RUNTEST,$(test),$(+),$(step))'; \
- $(call $(impl)_RUNTEST,$(test),$(+),$(step)))))
+ echo 'Running: ../runtest.py $(call $(impl)_TEST_OPTS) ../$(test) -- $(call $(impl)_RUNSTEP,$(step),$(+))'; \
+ ../runtest.py $(call $(impl)_TEST_OPTS) ../$(test) -- $(call $(impl)_RUNSTEP,$(step),$(+)))))
test: $(ALL_TESTS)
tests: $(ALL_TESTS)
@@ -104,6 +111,9 @@ tests: $(ALL_TESTS)
# Stats rules
+stats: $(IMPL_STATS)
+stats-lisp: $(IMPL_STATS_LISP)
+
.SECONDEXPANSION:
$(IMPL_STATS):
@echo "----------------------------------------------"; \
@@ -118,5 +128,19 @@ $(IMPL_STATS_LISP):
echo "Stats (lisp only) for $(impl):"; \
$(MAKE) --no-print-directory -C $(impl) stats-lisp)
-stats: $(IMPL_STATS)
-stats-lisp: $(IMPL_STATS_LISP)
+
+# Performance test rules
+
+perf: $(IMPL_PERF)
+
+.SECONDEXPANSION:
+$(IMPL_PERF):
+ @echo "----------------------------------------------"; \
+ $(foreach impl,$(word 2,$(subst ^, ,$(@))),\
+ cd $(if $(filter mal,$(impl)),$(MAL_IMPL),$(impl)); \
+ echo "Performance test for $(impl):"; \
+ echo 'Running: $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf1.mal)'; \
+ $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf1.mal); \
+ echo 'Running: $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf2.mal)'; \
+ $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf2.mal))
+
diff --git a/bash/core.sh b/bash/core.sh
index e0cba38..c8a0261 100644
--- a/bash/core.sh
+++ b/bash/core.sh
@@ -56,6 +56,12 @@ num_gte () { r=$(( ${ANON["${1}"]} >= ${ANON["${2}"]} )); _num_bool "${r}";
num_lt () { r=$(( ${ANON["${1}"]} < ${ANON["${2}"]} )); _num_bool "${r}"; }
num_lte () { r=$(( ${ANON["${1}"]} <= ${ANON["${2}"]} )); _num_bool "${r}"; }
+# return number of milliseconds since epoch
+time_ms () {
+ local ms=$(date +%s%3N)
+ _number "${ms}"
+}
+
# String functions
@@ -280,7 +286,7 @@ meta () {
}
-# atoms
+# Atom functions
atom? () { _atom? "${1}" && r="${__true}" || r="${__false}"; }
deref () {
@@ -327,6 +333,7 @@ declare -A core_ns=(
[-]=num_minus
[__STAR__]=num_multiply
[/]=num_divide
+ [time-ms]=time_ms
[list]=_list
[list?]=list?
diff --git a/bash/step7_quote.sh b/bash/step7_quote.sh
index b541d67..14721ba 100755
--- a/bash/step7_quote.sh
+++ b/bash/step7_quote.sh
@@ -14,7 +14,7 @@ READ () {
}
IS_PAIR () {
- if _list? "${1}"; then
+ if _sequential? "${1}"; then
_count "${1}"
[[ "${r}" > 0 ]] && return 0
fi
diff --git a/bash/step8_macros.sh b/bash/step8_macros.sh
index 0e58404..e311489 100755
--- a/bash/step8_macros.sh
+++ b/bash/step8_macros.sh
@@ -14,7 +14,7 @@ READ () {
}
IS_PAIR () {
- if _list? "${1}"; then
+ if _sequential? "${1}"; then
_count "${1}"
[[ "${r}" > 0 ]] && return 0
fi
diff --git a/bash/step9_interop.sh b/bash/step9_interop.sh
index c2b0931..0491f7f 100755
--- a/bash/step9_interop.sh
+++ b/bash/step9_interop.sh
@@ -14,7 +14,7 @@ READ () {
}
IS_PAIR () {
- if _list? "${1}"; then
+ if _sequential? "${1}"; then
_count "${1}"
[[ "${r}" > 0 ]] && return 0
fi
diff --git a/bash/stepA_more.sh b/bash/stepA_more.sh
index d968942..8a8366a 100755
--- a/bash/stepA_more.sh
+++ b/bash/stepA_more.sh
@@ -14,7 +14,7 @@ READ () {
}
IS_PAIR () {
- if _list? "${1}"; then
+ if _sequential? "${1}"; then
_count "${1}"
[[ "${r}" > 0 ]] && return 0
fi
@@ -254,8 +254,11 @@ _fref () { _function "${2} \"\${@}\""; ENV_SET "${REPL_ENV}" "${1}" "${r}"; }
for n in "${!core_ns[@]}"; do _fref "${n}" "${core_ns["${n}"]}"; done
_eval () { EVAL "${1}" "${REPL_ENV}"; }
_fref "eval" _eval
+_time_ms () { local ms=$(date +%s%3N); _number "${ms}"; }
+_fref "time-ms" _time_ms
# core.mal: defined using the language itself
+REP "(def! *host-language* \"bash\")"
REP "(def! not (fn* (a) (if a false true)))"
REP "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))"
REP "(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))"
diff --git a/c/core.c b/c/core.c
index 2c76a95..10c9fc9 100644
--- a/c/core.c
+++ b/c/core.c
@@ -135,6 +135,15 @@ WRAP_INTEGER_CMP_OP(gte,>=)
WRAP_INTEGER_CMP_OP(lt,<)
WRAP_INTEGER_CMP_OP(lte,<=)
+MalVal *time_ms(MalVal *_) {
+ struct timeval tv;
+ long msecs;
+ gettimeofday(&tv, NULL);
+ msecs = tv.tv_sec * 1000 + tv.tv_usec/1000.0 + 0.5;
+
+ return malval_new_integer(msecs);
+}
+
// List functions
@@ -422,7 +431,7 @@ MalVal *swap_BANG(MalVal *args) {
-core_ns_entry core_ns[53] = {
+core_ns_entry core_ns[54] = {
{"=", (void*(*)(void*))equal_Q, 2},
{"throw", (void*(*)(void*))throw, 1},
{"nil?", (void*(*)(void*))nil_Q, 1},
@@ -446,6 +455,7 @@ core_ns_entry core_ns[53] = {
{"-", (void*(*)(void*))int_minus, 2},
{"*", (void*(*)(void*))int_multiply, 2},
{"/", (void*(*)(void*))int_divide, 2},
+ {"time-ms", (void*(*)(void*))time_ms, 0},
{"list", (void*(*)(void*))list, -1},
{"list?", (void*(*)(void*))list_Q, 1},
diff --git a/c/core.h b/c/core.h
index a8b7a5f..49f8bee 100644
--- a/c/core.h
+++ b/c/core.h
@@ -10,6 +10,6 @@ typedef struct {
int arg_cnt;
} core_ns_entry;
-extern core_ns_entry core_ns[53];
+extern core_ns_entry core_ns[54];
#endif
diff --git a/c/stepA_more.c b/c/stepA_more.c
index 82bf3db..8547607 100644
--- a/c/stepA_more.c
+++ b/c/stepA_more.c
@@ -298,6 +298,7 @@ void init_repl_env() {
malval_new_function((void*(*)(void *))do_eval, 1));
// core.mal: defined using the language itself
+ RE(repl_env, "", "(def! *host-language* \"c\")");
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/clojure/src/core.clj b/clojure/src/core.clj
index 73d8fb4..6b0d9b5 100644
--- a/clojure/src/core.clj
+++ b/clojure/src/core.clj
@@ -5,7 +5,12 @@
(defn mal_throw [obj]
(throw (ex-info "mal exception" {:data obj})))
-;; Metadata
+;; Number functions
+
+(defn time-ms []
+ (System/currentTimeMillis))
+
+;; Metadata functions
;; - store metadata at :meta key of the real metadata
(defn mal_with_meta [obj m]
(let [new-meta (assoc (meta obj) :meta m)]
@@ -14,8 +19,7 @@
(defn mal_meta [obj]
(:meta (meta obj)))
-
-;; Atoms
+;; Atom functions
(defn atom? [atm]
(= (type atm) clojure.lang.Atom))
@@ -43,6 +47,7 @@
['- -]
['* *]
['/ /]
+ ['time-ms time-ms]
['list list]
['list? seq?]
diff --git a/clojure/src/stepA_more.clj b/clojure/src/stepA_more.clj
index d45d86a..9739760 100644
--- a/clojure/src/stepA_more.clj
+++ b/clojure/src/stepA_more.clj
@@ -154,6 +154,7 @@
(env/env-set repl-env 'eval (fn [ast] (EVAL ast repl-env)))
;; core.mal: defined using the language itself
+(rep "(def! *host-language* \"clojure\")")
(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)))))))")
diff --git a/core.mal b/core.mal
index 2896dcc..9cd41eb 100644
--- a/core.mal
+++ b/core.mal
@@ -81,3 +81,19 @@
`(~(first form) ~@(rest form) ~x)
(list form x))
`(->> (->> ~x ~form) ~@more))))))
+
+(if (= "make" *host-language*)
+ (defmacro! time
+ (fn* (exp)
+ `(let* [start_FIXME (time-secs)
+ ret_FIXME ~exp]
+ (do
+ (prn (str "Elapsed time: " (- (time-secs) start_FIXME) "000 msecs"))
+ ret_FIXME))))
+ (defmacro! time
+ (fn* (exp)
+ `(let* [start_FIXME (time-ms)
+ ret_FIXME ~exp]
+ (do
+ (prn (str "Elapsed time: " (- (time-ms) start_FIXME) " msecs"))
+ ret_FIXME)))))
diff --git a/cs/core.cs b/cs/core.cs
index 62a121c..7cfb772 100644
--- a/cs/core.cs
+++ b/cs/core.cs
@@ -36,6 +36,11 @@ namespace Mal {
a => a[0] is MalSymbol ? True : False);
+ // Number functions
+ static MalFunction time_ms = new MalFunction(
+ a => new MalInteger((int)(
+ DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond)));
+
// String functions
static public MalFunction pr_str = new MalFunction(
a => new MalString(printer._pr_str_args(a, " ", true)) );
@@ -265,6 +270,7 @@ namespace Mal {
{"-", 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])},
+ {"time-ms", time_ms},
{"list", new MalFunction(a => new MalList(a.getValue()))},
{"list?", list_Q},
diff --git a/cs/stepA_more.cs b/cs/stepA_more.cs
index cbbc91f..dbbf53d 100644
--- a/cs/stepA_more.cs
+++ b/cs/stepA_more.cs
@@ -234,6 +234,7 @@ namespace Mal {
repl_env.set("eval", new MalFunction(a => EVAL(a[0], repl_env)));
// core.mal: defined using the language itself
+ RE(repl_env, "(def! *host-language* \"c#\")");
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)))))))");
diff --git a/docs/TODO b/docs/TODO
index 43c11a2..c930055 100644
--- a/docs/TODO
+++ b/docs/TODO
@@ -12,6 +12,7 @@ All:
- Print full exception when test gets EOF from expect
- Break out impl eval into step0.5
+ - Fix quasiquoting of vectors
---------------------------------------------
@@ -22,6 +23,7 @@ C:
C#:
- step9_interop
+ - use same history file
Clojure:
@@ -50,7 +52,8 @@ Postscript:
Python:
Ruby:
- - use same history file
+ - save history and use same history file
+ - setup require search path
---------------------------------------------
diff --git a/java/src/main/java/mal/core.java b/java/src/main/java/mal/core.java
index ea6787d..0f1d226 100644
--- a/java/src/main/java/mal/core.java
+++ b/java/src/main/java/mal/core.java
@@ -117,8 +117,10 @@ public class core {
public MalVal apply(MalList args) throws MalThrowable {
String fname = ((MalString)args.nth(0)).getValue();
try {
+ // Scanner drops final newline, so add it back
return new MalString(
- new Scanner(new File(fname)).useDelimiter("\\Z").next());
+ new Scanner(new File(fname)).useDelimiter("\\Z").next()
+ + "\n");
} catch (FileNotFoundException e) {
throw new MalError(e.getMessage());
}
@@ -169,6 +171,12 @@ public class core {
}
};
+ static MalFunction time_ms = new MalFunction() {
+ public MalVal apply(MalList a) throws MalThrowable {
+ return new MalInteger((int)System.currentTimeMillis());
+ }
+ };
+
// List functions
static MalFunction new_list = new MalFunction() {
@@ -480,6 +488,7 @@ public class core {
.put("-", subtract)
.put("*", multiply)
.put("/", divide)
+ .put("time-ms", time_ms)
.put("list", new_list)
.put("list?", list_Q)
diff --git a/java/src/main/java/mal/stepA_more.java b/java/src/main/java/mal/stepA_more.java
index 5ed5667..17bdb16 100644
--- a/java/src/main/java/mal/stepA_more.java
+++ b/java/src/main/java/mal/stepA_more.java
@@ -245,6 +245,7 @@ public class stepA_more {
});
// core.mal: defined using the language itself
+ RE(repl_env, "(def! *host-language* \"java\")");
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)))))))");
diff --git a/js/core.js b/js/core.js
index d5c014f..f9e478e 100644
--- a/js/core.js
+++ b/js/core.js
@@ -43,6 +43,10 @@ function slurp(f) {
}
+// Number functions
+function time_ms() { return new Date().getTime(); }
+
+
// Hash Map functions
function assoc(src_hm) {
var hm = types._clone(src_hm);
@@ -166,6 +170,7 @@ var ns = {'type': types._obj_type,
'-' : function(a,b){return a-b;},
'*' : function(a,b){return a*b;},
'/' : function(a,b){return a/b;},
+ "time-ms": time_ms,
'list': types._list,
'list?': types._list_Q,
diff --git a/js/stepA_more.js b/js/stepA_more.js
index 06eb43d..a2035dc 100644
--- a/js/stepA_more.js
+++ b/js/stepA_more.js
@@ -164,6 +164,7 @@ for (var n in core.ns) { repl_env.set(n, core.ns[n]); }
repl_env.set('eval', function(ast) { return EVAL(ast, repl_env); });
// core.mal: defined using the language itself
+rep("(def! *host-language* \"javascript\")")
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)))))))");
diff --git a/make/core.mk b/make/core.mk
index 80f51ac..2ee6597 100644
--- a/make/core.mk
+++ b/make/core.mk
@@ -48,6 +48,8 @@ number_subtract = $(call _pnumber,$(call int_subtract,$($(word 1,$(1))_value),$(
number_multiply = $(call _pnumber,$(call int_multiply,$($(word 1,$(1))_value),$($(word 2,$(1))_value)))
number_divide = $(call _pnumber,$(call int_divide,$($(word 1,$(1))_value),$($(word 2,$(1))_value)))
+time_secs = $(call _number,$(shell echo $$(( $$(date +%s) % 65536 ))))
+
# String functions
@@ -229,6 +231,7 @@ core_ns = type obj_type \
- number_subtract \
* number_multiply \
/ number_divide \
+ time-secs time_secs \
\
list _list \
list? list? \
diff --git a/make/step7_quote.mk b/make/step7_quote.mk
index af14e85..072e407 100644
--- a/make/step7_quote.mk
+++ b/make/step7_quote.mk
@@ -18,7 +18,7 @@ $(if $(READLINE_EOF)$(__ERROR),,$(call READ_STR,$(if $(1),$(1),$(call READLINE,"
endef
# EVAL: evaluate the parameter
-IS_PAIR = $(if $(call _EQ,list,$(call _obj_type,$(1))),$(if $(call _EQ,0,$(call _count,$(1))),,true),)
+IS_PAIR = $(if $(call _sequential?,$(1)),$(if $(call _EQ,0,$(call _count,$(1))),,true),)
define QUASIQUOTE
$(strip \
diff --git a/make/step8_macros.mk b/make/step8_macros.mk
index 8ed5df8..f4234d2 100644
--- a/make/step8_macros.mk
+++ b/make/step8_macros.mk
@@ -18,7 +18,7 @@ $(if $(READLINE_EOF)$(__ERROR),,$(call READ_STR,$(if $(1),$(1),$(call READLINE,"
endef
# EVAL: evaluate the parameter
-IS_PAIR = $(if $(call _EQ,list,$(call _obj_type,$(1))),$(if $(call _EQ,0,$(call _count,$(1))),,true),)
+IS_PAIR = $(if $(call _sequential?,$(1)),$(if $(call _EQ,0,$(call _count,$(1))),,true),)
define QUASIQUOTE
$(strip \
diff --git a/make/step9_interop.mk b/make/step9_interop.mk
index 8c9220c..2dfe7e0 100644
--- a/make/step9_interop.mk
+++ b/make/step9_interop.mk
@@ -18,7 +18,7 @@ $(if $(READLINE_EOF)$(__ERROR),,$(call READ_STR,$(if $(1),$(1),$(call READLINE,"
endef
# EVAL: evaluate the parameter
-IS_PAIR = $(if $(call _EQ,list,$(call _obj_type,$(1))),$(if $(call _EQ,0,$(call _count,$(1))),,true),)
+IS_PAIR = $(if $(call _sequential?,$(1)),$(if $(call _EQ,0,$(call _count,$(1))),,true),)
define QUASIQUOTE
$(strip \
diff --git a/make/stepA_more.mk b/make/stepA_more.mk
index 00ae252..8b92178 100644
--- a/make/stepA_more.mk
+++ b/make/stepA_more.mk
@@ -18,7 +18,7 @@ $(if $(READLINE_EOF)$(__ERROR),,$(call READ_STR,$(if $(1),$(1),$(call READLINE,"
endef
# EVAL: evaluate the parameter
-IS_PAIR = $(if $(call _EQ,list,$(call _obj_type,$(1))),$(if $(call _EQ,0,$(call _count,$(1))),,true),)
+IS_PAIR = $(if $(call _sequential?,$(1)),$(if $(call _EQ,0,$(call _count,$(1))),,true),)
define QUASIQUOTE
$(strip \
@@ -167,6 +167,7 @@ $(call _import_core,$(core_ns))
REPL_ENV := $(call ENV_SET,$(REPL_ENV),eval,$(call _function,$$(call EVAL,$$(1),$$(REPL_ENV))))
# core.mal: defined in terms of the language itself
+$(call do,$(call REP, (def! *host-language* "make") ))
$(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))))))) ))
diff --git a/mal/stepA_more.mal b/mal/stepA_more.mal
index b56a697..1af0d25 100644
--- a/mal/stepA_more.mal
+++ b/mal/stepA_more.mal
@@ -153,6 +153,7 @@
(env-set repl-env 'eval (fn* [ast] (EVAL ast repl-env)))
;; core.mal: defined using the new language itself
+(rep (str "(def! *host-language* \"" *host-language* "-mal\")"))
(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)))))))")
diff --git a/php/core.php b/php/core.php
index 39a22ac..4cb4667 100644
--- a/php/core.php
+++ b/php/core.php
@@ -37,6 +37,12 @@ function println() {
}
+// Number functions
+function time_ms() {
+ return intval(microtime(1) * 1000);
+}
+
+
// Hash Map functions
function assoc($src_hm) {
$args = func_get_args();
@@ -188,6 +194,7 @@ $core_ns = array(
'-'=> function ($a, $b) { return intval($a - $b,10); },
'*'=> function ($a, $b) { return intval($a * $b,10); },
'/'=> function ($a, $b) { return intval($a / $b,10); },
+ 'time-ms'=>function () { return time_ms(); },
'list'=> function () { return call_user_func_array('_list', func_get_args()); },
'list?'=> function ($a) { return _list_Q($a); },
diff --git a/php/stepA_more.php b/php/stepA_more.php
index c599986..2eae095 100644
--- a/php/stepA_more.php
+++ b/php/stepA_more.php
@@ -177,6 +177,7 @@ $repl_env->set('eval', _function(function($ast) {
}));
// core.mal: defined using the language itself
+rep("(def! *host-language* \"php\")");
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)))))))");
diff --git a/ps/core.ps b/ps/core.ps
index f9397fa..191e5c3 100644
--- a/ps/core.ps
+++ b/ps/core.ps
@@ -1,5 +1,3 @@
-(in core.ps\n) print
-
% requires types.ps
% Errors/Exceptions
@@ -239,6 +237,7 @@ end } def
(-) { dup 0 _nth exch 1 _nth sub }
(*) { dup 0 _nth exch 1 _nth mul }
(/) { dup 0 _nth exch 1 _nth idiv }
+ (time-ms) { pop realtime }
(list) { /data get _list_from_array }
(list?) { 0 _nth _list? }
diff --git a/ps/env.ps b/ps/env.ps
index 4eb3484..f6d5b88 100644
--- a/ps/env.ps
+++ b/ps/env.ps
@@ -1,5 +1,3 @@
-(in env.ps\n) print
-
% outer binds exprs -> env_new -> new_env
/env_new { 3 dict begin
%(in env_new\n) print
diff --git a/ps/printer.ps b/ps/printer.ps
index de91d80..3062e2d 100644
--- a/ps/printer.ps
+++ b/ps/printer.ps
@@ -1,5 +1,3 @@
-(in printer.ps\n) print
-
% requires types.ps to be included first
% ast print_readably -> _pr_str -> string
diff --git a/ps/reader.ps b/ps/reader.ps
index 188a121..f1f63f6 100644
--- a/ps/reader.ps
+++ b/ps/reader.ps
@@ -1,5 +1,3 @@
-(in reader\n) print
-
% requires types.ps to be included first
/token_delim (;,"` \n{}\(\)[]) def
diff --git a/ps/step7_quote.ps b/ps/step7_quote.ps
index f335683..93bf464 100644
--- a/ps/step7_quote.ps
+++ b/ps/step7_quote.ps
@@ -17,7 +17,7 @@
% is_pair?: ast -> is_pair? -> bool
% return true if non-empty list, otherwise false
/is_pair? {
- dup _list? { _count 0 gt }{ pop false } ifelse
+ dup _sequential? { _count 0 gt }{ pop false } ifelse
} def
% ast -> quasiquote -> new_ast
diff --git a/ps/step8_macros.ps b/ps/step8_macros.ps
index 87fafb1..814b62b 100644
--- a/ps/step8_macros.ps
+++ b/ps/step8_macros.ps
@@ -17,7 +17,7 @@
% is_pair?: ast -> is_pair? -> bool
% return true if non-empty list, otherwise false
/is_pair? {
- dup _list? { _count 0 gt }{ pop false } ifelse
+ dup _sequential? { _count 0 gt }{ pop false } ifelse
} def
% ast -> quasiquote -> new_ast
diff --git a/ps/step9_interop.ps b/ps/step9_interop.ps
index fbf51a5..e8d837f 100644
--- a/ps/step9_interop.ps
+++ b/ps/step9_interop.ps
@@ -17,7 +17,7 @@
% is_pair?: ast -> is_pair? -> bool
% return true if non-empty list, otherwise false
/is_pair? {
- dup _list? { _count 0 gt }{ pop false } ifelse
+ dup _sequential? { _count 0 gt }{ pop false } ifelse
} def
% ast -> quasiquote -> new_ast
diff --git a/ps/stepA_more.ps b/ps/stepA_more.ps
index 1720b94..73403b0 100644
--- a/ps/stepA_more.ps
+++ b/ps/stepA_more.ps
@@ -17,7 +17,7 @@
% is_pair?: ast -> is_pair? -> bool
% return true if non-empty list, otherwise false
/is_pair? {
- dup _list? { _count 0 gt }{ pop false } ifelse
+ dup _sequential? { _count 0 gt }{ pop false } ifelse
} def
% ast -> quasiquote -> new_ast
@@ -252,6 +252,7 @@ core_ns { _ref } forall
(eval) { 0 _nth repl_env EVAL } _ref
% core.mal: defined using the language itself
+(\(def! *host-language* "postscript"\)) RE pop
(\(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
diff --git a/ps/types.ps b/ps/types.ps
index 2b26582..82be9c2 100644
--- a/ps/types.ps
+++ b/ps/types.ps
@@ -1,5 +1,3 @@
-(in types.ps\n) print
-
% General functions
% concatenate: concatenate two strings or two arrays
diff --git a/python/core.py b/python/core.py
index 54737aa..d10047d 100644
--- a/python/core.py
+++ b/python/core.py
@@ -1,4 +1,4 @@
-import copy
+import copy, time
from itertools import chain
import mal_types as types
@@ -130,6 +130,7 @@ ns = {
'-': lambda a,b: a-b,
'*': lambda a,b: a*b,
'/': lambda a,b: int(a/b),
+ 'time-ms': lambda : int(time.time() * 1000),
'list': types._list,
'list?': types._list_Q,
diff --git a/python/stepA_more.py b/python/stepA_more.py
index fa79ec3..e4bc768 100644
--- a/python/stepA_more.py
+++ b/python/stepA_more.py
@@ -58,7 +58,7 @@ def eval_ast(ast, env):
def EVAL(ast, env):
while True:
- #print("EVAL %s" % ast)
+ #print("EVAL %s" % printer._pr_str(ast))
if not types._list_Q(ast):
return eval_ast(ast, env)
@@ -150,6 +150,7 @@ for k, v in core.ns.items(): repl_env.set(k, v)
repl_env.set('eval', lambda ast: EVAL(ast, repl_env))
# core.mal: defined using the language itself
+REP("(def! *host-language* \"python\")")
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)))))))")
diff --git a/ruby/core.rb b/ruby/core.rb
index c7fc8c3..6b127ba 100644
--- a/ruby/core.rb
+++ b/ruby/core.rb
@@ -26,6 +26,7 @@ $core_ns = {
:- => lambda {|a,b| a - b},
:* => lambda {|a,b| a * b},
:/ => lambda {|a,b| a / b},
+ :"time-ms" => lambda {|| (Time.now.to_f * 1000).to_i},
:list => lambda {|*a| List.new a},
:list? => lambda {|*a| a[0].is_a? List},
diff --git a/ruby/stepA_more.rb b/ruby/stepA_more.rb
index 42eac5b..a2fc5cc 100644
--- a/ruby/stepA_more.rb
+++ b/ruby/stepA_more.rb
@@ -154,6 +154,7 @@ $core_ns.each do |k,v| repl_env.set(k,v) end
repl_env.set(:eval, lambda {|ast| EVAL(ast, repl_env)})
# core.mal: defined using the language itself
+RE["(def! *host-language* \"ruby\")"]
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)))))))"]
diff --git a/tests/perf1.mal b/tests/perf1.mal
new file mode 100644
index 0000000..871e28f
--- /dev/null
+++ b/tests/perf1.mal
@@ -0,0 +1,10 @@
+(load-file "../core.mal")
+
+;;(prn "Start: basic macros performance test")
+
+(time (do
+ (or false nil false nil false nil false nil false nil 4)
+ (cond false 1 nil 2 false 3 nil 4 false 5 nil 6 "else" 7)
+ (-> (list 1 2 3 4 5 6 7 8 9) rest rest rest rest rest rest first)))
+
+;;(prn "Done: basic macros performance test")
diff --git a/tests/perf2.mal b/tests/perf2.mal
new file mode 100644
index 0000000..3889191
--- /dev/null
+++ b/tests/perf2.mal
@@ -0,0 +1,12 @@
+(load-file "../core.mal")
+
+;;(prn "Start: basic math/recursion test")
+
+(def! sumdown (fn* (N) (if (> N 0) (+ N (sumdown (- N 1))) 0)))
+(def! fib (fn* (N) (if (= N 0) 1 (if (= N 1) 1 (+ (fib (- N 1)) (fib (- N 2)))))))
+
+(time (do
+ (sumdown 10)
+ (fib 12)))
+
+;;(prn "Done: basic math/recursion test")
diff --git a/tests/step7_quote.mal b/tests/step7_quote.mal
index c41c7e2..9166065 100644
--- a/tests/step7_quote.mal
+++ b/tests/step7_quote.mal
@@ -47,6 +47,9 @@
;=>(1 b 3)
`(1 ~b 3)
;=>(1 (1 "b" "d") 3)
+;;; TODO: fix this
+;;;`[1 ~b 3]
+;;;;=>[1 (1 "b" "d") 3]
;; Testing splice-unquote
@@ -56,6 +59,9 @@
;=>(1 c 3)
`(1 ~@c 3)
;=>(1 1 "b" "d" 3)
+;;; TODO: fix this
+;;;`[1 ~@c 3]
+;;;;=>[1 1 "b" "d" 3]
;; Testing symbol equality