32559fa40c19c6b3889fa67a4185966ceffda607 — Tim Morgan a month ago 40a4321 master
Moving to GitHub
85 files changed, 2 insertions(+), 18267 deletions(-)

D .github/workflows/build.yml
D .gitignore
D .gitmodules
D Dockerfile
D LICENSE
D Makefile
M README.md
D core.c
D core.h
D env.c
D env.h
D examples/fib.mal
D examples/filter.mal
D examples/hello.mal
D hashmap.c
D hashmap.h
D mal/LICENSE
D mal/Makefile
D mal/README.md
D mal/core.mal
D mal/mal/Dockerfile
D mal/mal/Makefile
D mal/mal/core.mal
D mal/mal/env.mal
D mal/mal/run
D mal/mal/step0_repl.mal
D mal/mal/step1_read_print.mal
D mal/mal/step2_eval.mal
D mal/mal/step3_env.mal
D mal/mal/step4_if_fn_do.mal
D mal/mal/step6_file.mal
D mal/mal/step7_quote.mal
D mal/mal/step8_macros.mal
D mal/mal/step9_try.mal
D mal/mal/stepA_mal.mal
D mal/perf.mal
D mal/run_argv_test.sh
D mal/runtest.py
D mal/tests/docker-build.sh
D mal/tests/docker-run.sh
D mal/tests/docker/Dockerfile
D mal/tests/inc.mal
D mal/tests/incA.mal
D mal/tests/incB.mal
D mal/tests/incC.mal
D mal/tests/perf1.mal
D mal/tests/perf2.mal
D mal/tests/perf3.mal
D mal/tests/print_argv.mal
D mal/tests/step0_repl.mal
D mal/tests/step1_read_print.mal
D mal/tests/step2_eval.mal
D mal/tests/step3_env.mal
D mal/tests/step4_if_fn_do.mal
D mal/tests/step5_tco.mal
D mal/tests/step6_file.mal
D mal/tests/step7_quote.mal
D mal/tests/step8_macros.mal
D mal/tests/step9_try.mal
D mal/tests/stepA_mal.mal
D mal/tests/test.txt
D malcc.c
D printer.c
D printer.h
D reader.c
D reader.h
D self_hosted_run
D step0_repl.c
D step1_read_print.c
D step2_eval.c
D step3_env.c
D step4_if_fn_do.c
D step5_tco.c
D step6_file.c
D step7_quote.c
D step8_macros.c
D step9_try.c
D stepA_mal.c
D tests/regex.mal
D tests/utf-8.mal
D tinycc
D types.c
D types.h
D util.c
D util.h
D .github/workflows/build.yml => .github/workflows/build.yml +0 -19
@@ 1,19 0,0 @@
-name: Build
-
-on: push
-
-jobs:
-  build:
-    runs-on: ubuntu-18.04
-    steps:
-    - uses: actions/checkout@v1
-    - name: fetch submodules
-      run: git submodule update --init
-    - name: install dependencies
-      run: sudo apt update && sudo apt install -y -q build-essential libedit-dev libgc-dev libpcre3-dev python
-    - name: set environment
-      run: export LC_ALL="C.UTF-8"
-    - name: build
-      run: make all
-    - name: test
-      run: make test

D .gitignore => .gitignore +0 -17
@@ 1,17 0,0 @@
-step0_repl
-step1_read_print
-step2_eval
-step3_env
-step4_if_fn_do
-step5_tco
-step6_file
-step7_quote
-step8_macros
-step9_try
-stepA_mal
-malcc
-mal-in-mal
-mal-in-mal.c
-mal-in-mal.dSYM
-*.o
-history.txt

D .gitmodules => .gitmodules +0 -3
@@ 1,3 0,0 @@
-[submodule "tinycc"]
-	path = tinycc
-	url = https://repo.or.cz/tinycc.git

D Dockerfile => Dockerfile +0 -25
@@ 1,25 0,0 @@
-FROM ubuntu:18.04
-
-RUN apt-get update
-RUN apt-get install -y -q \
-  build-essential \
-  gdb \
-  libedit-dev \
-  libgc-dev \
-  libpcre3-dev \
-  python \
-  valgrind \
-  wget
-
-RUN cd /tmp && \
-    wget http://eradman.com/entrproject/code/entr-4.1.tar.gz && \
-    tar xzf entr-4.1.tar.gz && \
-    cd eradman-entr-* && \
-    ./configure && \
-    make install
-
-ENV LC_ALL C.UTF-8
-
-WORKDIR /malcc
-
-CMD ["bash"]

D LICENSE => LICENSE +0 -21
@@ 1,21 0,0 @@
-MIT License
-
-Copyright (c) 2019 Tim Morgan
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.

D Makefile => Makefile +0 -145
@@ 1,145 0,0 @@
-OS:=$(shell uname)
-CC=gcc
-CFLAGS=-Itinycc -Wall -Wextra -Werror -g
-LDLIBS=-ledit -ltermcap -lgc -lpcre -ldl
-
-ALL_STEPS=step0_repl step1_read_print step2_eval step3_env step4_if_fn_do step5_tco step6_file step7_quote step8_macros step9_try stepA_mal malcc
-
-.PHONY: all clean test test-current cloc docker-build
-
-all: $(ALL_STEPS)
-
-step0_repl: step0_repl.o
-step1_read_print: step1_read_print.o hashmap.o printer.o reader.o types.o util.o
-step2_eval: step2_eval.o hashmap.o printer.o reader.o types.o util.o tinycc/libtcc.a
-step3_env: step3_env.o env.o hashmap.o printer.o reader.o types.o util.o tinycc/libtcc.a
-step4_if_fn_do: step4_if_fn_do.o core.o env.o hashmap.o printer.o reader.o types.o util.o tinycc/libtcc.a
-step5_tco: step5_tco.o core.o env.o hashmap.o printer.o reader.o types.o util.o tinycc/libtcc.a
-step6_file: step6_file.o core.o env.o hashmap.o printer.o reader.o types.o util.o tinycc/libtcc.a
-step7_quote: step7_quote.o core.o env.o hashmap.o printer.o reader.o types.o util.o tinycc/libtcc.a
-step8_macros: step8_macros.o core.o env.o hashmap.o printer.o reader.o types.o util.o tinycc/libtcc.a
-step9_try: step9_try.o core.o env.o hashmap.o printer.o reader.o types.o util.o tinycc/libtcc.a
-stepA_mal: stepA_mal.o core.o env.o hashmap.o printer.o reader.o types.o util.o tinycc/libtcc.a
-malcc: malcc.o core.o env.o hashmap.o printer.o reader.o types.o util.o tinycc/libtcc.a
-
-tinycc/libtcc.a:
-	cd tinycc && ./configure && make
-
-clean:
-	rm -f $(ALL_STEPS) *.o
-	cd tinycc && make clean
-
-mal-in-mal: all
-	cd mal/mal && ../../malcc --compile stepA_mal.mal ../../mal-in-mal
-
-test: test0 test1 test2 test3 test4 test5 test6 test7 test8 test9 testA test-malcc test-self-hosted test-supplemental test-mal-in-mal
-
-RUN_TEST_CMD=mal/runtest.py --rundir mal/tests --hard --deferrable --optional --start-timeout 1 --test-timeout 1
-
-test0: all
-	$(RUN_TEST_CMD) step0_repl.mal ../../step0_repl
-
-test1: all
-	$(RUN_TEST_CMD) step1_read_print.mal ../../step1_read_print
-
-test2: all
-	$(RUN_TEST_CMD) step2_eval.mal ../../step2_eval
-
-test3: all
-	$(RUN_TEST_CMD) step3_env.mal ../../step3_env
-
-test4: all
-	$(RUN_TEST_CMD) step4_if_fn_do.mal ../../step4_if_fn_do
-
-test5: all
-	$(RUN_TEST_CMD) step5_tco.mal ../../step5_tco
-
-test6: all
-	$(RUN_TEST_CMD) step6_file.mal ../../step6_file
-	mal/run_argv_test.sh ./step6_file
-
-test7: all
-	$(RUN_TEST_CMD) step7_quote.mal ../../step7_quote
-
-test8: all
-	$(RUN_TEST_CMD) step8_macros.mal ../../step8_macros
-
-test9: all
-	$(RUN_TEST_CMD) step9_try.mal ../../step9_try
-
-testA: all
-	$(RUN_TEST_CMD) step2_eval.mal ../../stepA_mal
-	$(RUN_TEST_CMD) step3_env.mal ../../stepA_mal
-	$(RUN_TEST_CMD) step4_if_fn_do.mal ../../stepA_mal
-	$(RUN_TEST_CMD) step5_tco.mal ../../stepA_mal
-	$(RUN_TEST_CMD) step6_file.mal ../../stepA_mal
-	$(RUN_TEST_CMD) step7_quote.mal ../../stepA_mal
-	$(RUN_TEST_CMD) step8_macros.mal ../../stepA_mal
-	$(RUN_TEST_CMD) step9_try.mal ../../stepA_mal
-	$(RUN_TEST_CMD) stepA_mal.mal ../../stepA_mal
-
-test-malcc: all
-	$(RUN_TEST_CMD) step2_eval.mal ../../malcc
-	$(RUN_TEST_CMD) step3_env.mal ../../malcc
-	$(RUN_TEST_CMD) step4_if_fn_do.mal ../../malcc
-	$(RUN_TEST_CMD) step5_tco.mal ../../malcc
-	$(RUN_TEST_CMD) step6_file.mal ../../malcc
-	$(RUN_TEST_CMD) step7_quote.mal ../../malcc
-	$(RUN_TEST_CMD) step8_macros.mal ../../malcc
-	$(RUN_TEST_CMD) step9_try.mal ../../malcc
-	$(RUN_TEST_CMD) stepA_mal.mal ../../malcc
-
-test-self-hosted: all
-	$(RUN_TEST_CMD) --test-timeout 30 step2_eval.mal ../../self_hosted_run
-	$(RUN_TEST_CMD) --test-timeout 30 step3_env.mal ../../self_hosted_run
-	$(RUN_TEST_CMD) --test-timeout 30 step4_if_fn_do.mal ../../self_hosted_run
-	$(RUN_TEST_CMD) --test-timeout 30 step5_tco.mal ../../self_hosted_run
-	$(RUN_TEST_CMD) --test-timeout 30 step6_file.mal ../../self_hosted_run
-	$(RUN_TEST_CMD) --test-timeout 30 step7_quote.mal ../../self_hosted_run
-	$(RUN_TEST_CMD) --test-timeout 30 step8_macros.mal ../../self_hosted_run
-	$(RUN_TEST_CMD) --test-timeout 30 step9_try.mal ../../self_hosted_run
-	$(RUN_TEST_CMD) --test-timeout 30 stepA_mal.mal ../../self_hosted_run
-
-test-supplemental: all
-	$(RUN_TEST_CMD) --test-timeout 30 ../../tests/utf-8.mal ../../malcc
-	$(RUN_TEST_CMD) --test-timeout 30 ../../tests/regex.mal ../../malcc
-
-test-mal-in-mal: mal-in-mal
-	$(RUN_TEST_CMD) --test-timeout 30 step2_eval.mal ../../mal-in-mal
-	$(RUN_TEST_CMD) --test-timeout 30 step3_env.mal ../../mal-in-mal
-	$(RUN_TEST_CMD) --test-timeout 30 step4_if_fn_do.mal ../../mal-in-mal
-	$(RUN_TEST_CMD) --test-timeout 30 step5_tco.mal ../../mal-in-mal
-	$(RUN_TEST_CMD) --test-timeout 30 step6_file.mal ../../mal-in-mal
-	$(RUN_TEST_CMD) --test-timeout 30 step7_quote.mal ../../mal-in-mal
-	$(RUN_TEST_CMD) --test-timeout 30 step8_macros.mal ../../mal-in-mal
-	$(RUN_TEST_CMD) --test-timeout 30 step9_try.mal ../../mal-in-mal
-	$(RUN_TEST_CMD) --test-timeout 30 stepA_mal.mal ../../mal-in-mal
-
-perf: all
-	cd mal/tests && ../../malcc perf1.mal && ../../malcc perf2.mal && ../../malcc perf3.mal
-
-cloc:
-	cloc --exclude-dir='tinycc,mal' --not-match-f='hashmap.*|step.*' .
-
-docker-build:
-	docker build . -t malcc
-
-RUN_DOCKER_CMD=docker run --security-opt seccomp=unconfined -t -i --rm -v $(PWD):/malcc malcc
-
-docker-bash: docker-build
-	$(RUN_DOCKER_CMD) bash
-
-docker-test: docker-build
-	$(RUN_DOCKER_CMD) make test
-
-docker-test-supplemental: docker-build
-	$(RUN_DOCKER_CMD) make test-supplemental
-
-docker-watch: docker-build
-	$(RUN_DOCKER_CMD) bash -c "ls *.c *.h Makefile | entr -c -s 'make test'"
-
-update-mal-directory:
-	rm -rf /tmp/mal mal
-	mkdir mal
-	git clone https://github.com/kanaka/mal.git /tmp/mal
-	cp -r /tmp/mal/LICENSE /tmp/mal/Makefile /tmp/mal/README.md /tmp/mal/core.mal /tmp/mal/mal /tmp/mal/perf.mal /tmp/mal/run_argv_test.sh /tmp/mal/runtest.py /tmp/mal/tests mal/

M README.md => README.md +2 -141
@@ 1,142 1,3 @@
-# malcc
+# Moved
 
-Mal (Make A Lisp) Compiler in C
-
-![](https://github.com/seven1m/malcc/workflows/Build/badge.svg)
-
-## Overview
-
-[Mal](https://github.com/kanaka/mal) is Clojure inspired Lisp interpreter
-created by Joel Martin.
-
-**malcc** is an incremental compiler implementation for the Mal language.
-It uses the [Tiny C Compiler](https://bellard.org/tcc/) as the compiler backend
-and has full support for the Mal language, including macros, tail-call elimination,
-and even run-time eval.
-
-malcc can also be used as an ahead-of-time compiler for Mal, producing a single
-binary file for distribution (though using it this way sacrifices run-time eval
-functionality since the compiler is not shipped in the resulting binary).
-
-## Building and Running
-
-malcc has been tested on Ubuntu 18.04 and macOS 10.14 Mojave.
-
-**Prerequisites on Mac:**
-
-```bash
-sudo xcode-select --install
-brew install pcre libgc
-```
-
-On Macos 10.14.4, there is a problem building TinyCC. This fixes that:
-
-```bash
-cd /usr/local/lib
-sudo ln -s ../../lib/libSystem.B.dylib libgcc_s.10.4.dylib
-```
-
-**Prerequisites on Ubuntu/Debian:**
-
-```bash
-apt-get install libpcre3-dev libedit-dev libgc-dev
-```
-
-**Building malcc:**
-
-```bash
-git submodule update --init
-make all
-```
-
-**Running the REPL:**
-
-```bash
-→ ./malcc
-Mal [malcc]
-user> (+ 1 2)
-3
-user> ^D
-```
-
-**Running a mal file:**
-
-```bash
-→ ./malcc examples/fib.mal
-55
-12586269025
-```
-
-**Ahead-of-Time compiling a mal file:**
-
-```bash
-→ ./malcc --compile examples/fib.mal fib
-→ ./fib
-55
-12586269025
-```
-
-## Speed
-
-malcc is fast! Running the microbenchmarks on my Macbook Pro yields an
-order-of-magnitude speedup for long-running code vs the C++ implementation:
-
-**C++:**
-
-```bash
-→ ../cpp/stepA_mal perf1.mal
-"Elapsed time: 1 msecs"
-→ ../cpp/stepA_mal perf2.mal
-"Elapsed time: 2 msecs"
-→ ../cpp/stepA_mal perf3.mal
-iters over 10 seconds: 12415
-```
-
-**malcc:**
-
-```bash
-→ ../../stepA_mal perf1.mal
-"Elapsed time: 0 msecs"
-→ ../../stepA_mal perf2.mal
-"Elapsed time: 3 msecs"
-→ ../../stepA_mal perf3.mal
-iters over 10 seconds: 226216
-```
-
-Note: I'm not sure if this is a fair comparison, but I could not coax the C
-interpreter implementation of mal to run the perf3 test, so I figured the C++
-implementation was the next-best thing.
-
-## Approach
-
-I followed the Mal guide to implement malcc, using the same steps that any
-other implementation would follow. Naturally, since malcc is a compiler
-rather than a straight interpreter, there are some differences from other
-implementations:
-
-1. Additional functions not specified in the Mal guide are employed to
-   generate the C code that is passed to the TinyCC compiler. These functions
-   all start with `gen_` and should be fairly self-explanatory.
-2. `load-file` is implemented as a special form rather than a simple function.
-   This is because macros defined in a file must be found and compiled during
-   code generation--they cannot be discovered at run-time.
-3. I chose to publish malcc in a separate repository and have structured it to
-   suit my taste. A copy of the mal implementation of mal and the mal tests
-   were copied into the `mal` directory to provide test coverage.
-
-## Contributing
-
-Contributors are welcome! ❤️
-
-File an issue on [GitHub](https://github.com/seven1m/malcc/issues) if you find
-a bug or you want to propose a new feature!
-
-## License
-
-This project's sourcecode is copyrighted by Tim Morgan and licensed under the
-MIT license, included in the `LICENSE` file in this repository.
-
-The subdirectory `mal` contains a copy of the Mal language repository and is
-copyrighted by Joel Martin and released under the Mozilla Public License 2.0
-(MPL 2.0). The text of the MPL 2.0 license is included in the `mal/LICENSE`
-file.
+I have moved this back to GitHub here: https://github.com/seven1m/malcc

D core.c => core.c +0 -808
@@ 1,808 0,0 @@
-#include <assert.h>
-#include <gc.h>
-#include <pcre.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/time.h>
-
-#include "env.h"
-#include "core.h"
-#include "reader.h"
-#include "printer.h"
-#include "types.h"
-#include "util.h"
-
-struct hashmap* core_ns() {
-  struct hashmap *ns = GC_MALLOC(sizeof(struct hashmap));
-  hashmap_init(ns, hashmap_hash_string, hashmap_compare_string, 100);
-  hashmap_set_key_alloc_funcs(ns, hashmap_alloc_key_string, NULL);
-  hashmap_put(ns, "+", core_add);
-  hashmap_put(ns, "-", core_sub);
-  hashmap_put(ns, "*", core_mul);
-  hashmap_put(ns, "/", core_div);
-  hashmap_put(ns, "count", core_count);
-  hashmap_put(ns, "prn", core_prn);
-  hashmap_put(ns, "list", core_list);
-  hashmap_put(ns, "list?", core_is_list);
-  hashmap_put(ns, "empty?", core_is_empty);
-  hashmap_put(ns, "=", core_is_equal);
-  hashmap_put(ns, ">", core_is_gt);
-  hashmap_put(ns, ">=", core_is_gte);
-  hashmap_put(ns, "<", core_is_lt);
-  hashmap_put(ns, "<=", core_is_lte);
-  hashmap_put(ns, "pr-str", core_pr_str);
-  hashmap_put(ns, "str", core_str);
-  hashmap_put(ns, "println", core_println);
-  hashmap_put(ns, "read-string", core_read_string);
-  hashmap_put(ns, "slurp", core_slurp);
-  hashmap_put(ns, "atom", core_atom);
-  hashmap_put(ns, "atom?", core_is_atom);
-  hashmap_put(ns, "deref", core_deref);
-  hashmap_put(ns, "reset!", core_reset);
-  hashmap_put(ns, "swap!", core_swap);
-  hashmap_put(ns, "cons", core_cons);
-  hashmap_put(ns, "concat", core_concat);
-  hashmap_put(ns, "nth", core_nth);
-  hashmap_put(ns, "first", core_first);
-  hashmap_put(ns, "rest", core_rest);
-  hashmap_put(ns, "throw", core_throw);
-  hashmap_put(ns, "apply", core_apply);
-  hashmap_put(ns, "map", core_map);
-  hashmap_put(ns, "nil?", core_is_nil);
-  hashmap_put(ns, "true?", core_is_true);
-  hashmap_put(ns, "false?", core_is_false);
-  hashmap_put(ns, "symbol?", core_is_symbol);
-  hashmap_put(ns, "keyword?", core_is_keyword);
-  hashmap_put(ns, "vector?", core_is_vector);
-  hashmap_put(ns, "map?", core_is_map);
-  hashmap_put(ns, "sequential?", core_is_sequential);
-  hashmap_put(ns, "symbol", core_symbol);
-  hashmap_put(ns, "keyword", core_keyword);
-  hashmap_put(ns, "vector", core_vector);
-  hashmap_put(ns, "hash-map", core_hash_map);
-  hashmap_put(ns, "assoc", core_assoc);
-  hashmap_put(ns, "dissoc", core_dissoc);
-  hashmap_put(ns, "get", core_get);
-  hashmap_put(ns, "contains?", core_contains);
-  hashmap_put(ns, "keys", core_keys);
-  hashmap_put(ns, "vals", core_vals);
-  hashmap_put(ns, "readline", core_readline);
-  hashmap_put(ns, "meta", core_meta);
-  hashmap_put(ns, "with-meta", core_with_meta);
-  hashmap_put(ns, "seq", core_seq);
-  hashmap_put(ns, "conj", core_conj);
-  hashmap_put(ns, "time-ms", core_time_ms);
-  hashmap_put(ns, "string?", core_is_string);
-  hashmap_put(ns, "number?", core_is_number);
-  hashmap_put(ns, "fn?", core_is_fn);
-  hashmap_put(ns, "macro?", core_is_macro);
-  hashmap_put(ns, "regex?", core_is_regex);
-  hashmap_put(ns, "regex-match", core_regex_match);
-  return ns;
-}
-
-MalType* core_add(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  if (argc == 0) {
-    return mal_number(0);
-  } else {
-    long long result = args[0]->number;
-    for (size_t i=1; i<argc; i++) {
-      result += args[i]->number;
-    }
-    return mal_number(result);
-  }
-}
-
-MalType* core_sub(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  assert(argc > 0);
-  long long result = args[0]->number;
-  for (size_t i=1; i<argc; i++) {
-    result -= args[i]->number;
-  }
-  return mal_number(result);
-}
-
-MalType* core_mul(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  if (argc == 0) {
-    return mal_number(1);
-  } else {
-    long long result = args[0]->number;
-    for (size_t i=1; i<argc; i++) {
-      result *= args[i]->number;
-    }
-    return mal_number(result);
-  }
-}
-
-MalType* core_div(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  assert(argc > 0);
-  long long result = args[0]->number;
-  for (size_t i=1; i<argc; i++) {
-    result /= args[i]->number;
-  }
-  return mal_number(result);
-}
-
-MalType* core_count(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to count");
-  MalType *arg = args[0];
-  switch (arg->type) {
-    case MAL_EMPTY_TYPE:
-    case MAL_NIL_TYPE:
-      return mal_number(0);
-    case MAL_CONS_TYPE:
-      return mal_number(mal_list_len(arg));
-    case MAL_VECTOR_TYPE:
-      return mal_number(mal_vector_len(arg));
-    default:
-      printf("Object type to count not supported\n");
-      return mal_nil();
-  }
-}
-
-MalType* core_prn(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  MalType *out = mal_string("");
-  for (size_t i=0; i<argc; i++) {
-    mal_string_append(out, pr_str(args[i], 1));
-    if (i < argc-1) mal_string_append_char(out, ' ');
-  }
-  printf("%s\n", out->str);
-  return mal_nil();
-}
-
-MalType* core_list(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  MalType *vec = mal_vector();
-  for (size_t i=0; i<argc; i++) {
-    mal_vector_push(vec, args[i]);
-  }
-  return mal_vector_to_list(vec);
-}
-
-MalType* core_is_list(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to list?");
-  MalType *arg = args[0];
-  return is_empty(arg) || is_cons(arg) ? mal_true() : mal_false();
-}
-
-MalType* core_is_empty(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to empty?");
-  MalType *arg = args[0];
-  if (is_empty(arg)) return mal_true();
-  if (is_vector(arg) && arg->vec_len == 0) return mal_true();
-  return mal_false();
-}
-
-MalType* core_is_equal(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 2, "Expected 2 argument to =");
-  return is_equal(args[0], args[1]) ? mal_true() : mal_false();
-}
-
-MalType* core_is_gt(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 2, "Expected 2 argument to >");
-  MalType *arg1 = args[0];
-  MalType *arg2 = args[1];
-  mal_assert(is_number(arg1) && is_number(arg2), "Both arguments to > must be numbers");
-  return arg1->number > arg2->number ? mal_true() : mal_false();
-}
-
-MalType* core_is_gte(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 2, "Expected 2 argument to >=");
-  MalType *arg1 = args[0];
-  MalType *arg2 = args[1];
-  mal_assert(is_number(arg1) && is_number(arg2), "Both arguments to >= must be numbers");
-  return arg1->number == arg2->number || arg1->number > arg2->number ? mal_true() : mal_false();
-}
-
-MalType* core_is_lt(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 2, "Expected 2 argument to <");
-  MalType *arg1 = args[0];
-  MalType *arg2 = args[1];
-  mal_assert(is_number(arg1) && is_number(arg2), "Both arguments to < must be numbers");
-  return arg1->number < arg2->number ? mal_true() : mal_false();
-}
-
-MalType* core_is_lte(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 2, "Expected 2 argument to <=");
-  MalType *arg1 = args[0];
-  MalType *arg2 = args[1];
-  mal_assert(is_number(arg1) && is_number(arg2), "Both arguments to <= must be numbers");
-  return arg1->number == arg2->number || arg1->number < arg2->number ? mal_true() : mal_false();
-}
-
-MalType* core_pr_str(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  MalType *out = mal_string("");
-  for (size_t i=0; i<argc; i++) {
-    mal_string_append(out, pr_str(args[i], 1));
-    if (i < argc-1) mal_string_append_char(out, ' ');
-  }
-  return out;
-}
-
-MalType* core_str(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  MalType *out = mal_string("");
-  for (size_t i=0; i<argc; i++) {
-    mal_string_append(out, pr_str(args[i], 0));
-  }
-  return out;
-}
-
-MalType* core_println(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  MalType *out = mal_string("");
-  for (size_t i=0; i<argc; i++) {
-    mal_string_append(out, pr_str(args[i], 0));
-    if (i < argc-1) mal_string_append_char(out, ' ');
-  }
-  printf("%s\n", out->str);
-  return mal_nil();
-}
-
-MalType* core_read_string(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to read-string");
-  MalType *code = args[0];
-  mal_assert(is_string(code), "read-string expects a string argument");
-  return read_str(code->str);
-}
-
-MalType* core_slurp(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to slurp");
-  MalType *filename = args[0];
-  mal_assert(is_string(filename), "slurp expects a string argument");
-  return read_file(filename->str);
-}
-
-MalType* core_atom(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to atom");
-  return mal_atom(args[0]);
-}
-
-MalType* core_is_atom(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to atom?");
-  return is_atom(args[0]) ? mal_true() : mal_false();
-}
-
-MalType* core_deref(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to deref");
-  MalType *val = args[0];
-  mal_assert(is_atom(val), "deref expects an atom argument");
-  return val->atom_val;
-}
-
-MalType* core_reset(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 2, "Expected 2 arguments to reset!");
-  MalType *atom = args[0];
-  mal_assert(is_atom(atom), "reset! expects an atom argument");
-  MalType *inner_val = args[1];
-  atom->atom_val = inner_val;
-  return inner_val;
-}
-
-MalType* core_swap(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc >= 2, "Expected at least 2 arguments to swap!");
-  MalType *atom = args[0];
-  mal_assert(is_atom(atom), "swap! expects an atom argument");
-  MalType *lambda = args[1];
-  mal_assert(is_lambda(lambda), "swap! expects a lambda argument");
-  MalType **swap_args = GC_MALLOC(argc * sizeof(MalType*));
-  swap_args[0] = atom->atom_val;
-  for(size_t i=2; i<argc; i++) {
-    swap_args[i - 1] = args[i];
-  }
-  atom->atom_val = trampoline(mal_continuation(lambda->fn, lambda->env, argc - 1, swap_args));
-  return atom->atom_val;
-}
-
-MalType* core_cons(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 2, "Expected 2 arguments to cons");
-  MalType *new_item = args[0];
-  if (is_vector(args[1])) {
-    MalType *vec = args[1];
-    MalType *new_vec = mal_vector();
-    mal_vector_push(new_vec, new_item);
-    for (size_t i=0; i<mal_vector_len(vec); i++) {
-      mal_vector_push(new_vec, vec->vec[i]);
-    }
-    return mal_vector_to_list(new_vec);
-  } else {
-    return mal_cons(new_item, args[1]);
-  }
-}
-
-MalType* core_concat(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  MalType *final = mal_vector(), *item;
-  struct list_or_vector_iter *iter;
-  for (size_t i=0; i<argc; i++) {
-    for (iter = list_or_vector_iter(args[i]); iter; iter = list_or_vector_iter_next(iter)) {
-      item = list_or_vector_iter_get_obj(iter);
-      mal_vector_push(final, item);
-    }
-  }
-  return mal_vector_to_list(final);
-}
-
-MalType* core_nth(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 2, "Expected 2 arguments to nth");
-  MalType *list_or_vector = args[0];
-  mal_assert(is_list_like(list_or_vector), "nth expects a list or a vector argument");
-  MalType *mal_index = args[1];
-  mal_assert(is_number(mal_index), "nth expects a number as the index argument");
-  size_t index = (size_t)mal_index->number;
-  if (is_vector(list_or_vector)) {
-    size_t size = mal_vector_len(list_or_vector);
-    if (index >= size) {
-      return mal_error(mal_string("nth index out of range"));
-    }
-    return mal_vector_ref(list_or_vector, index);
-  } else {
-    size_t size = mal_list_len(list_or_vector);
-    if (index >= size) {
-      return mal_error(mal_string("nth index out of range"));
-    }
-    return mal_list_ref(list_or_vector, index);
-  }
-}
-
-MalType* core_first(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to first");
-  MalType *list = args[0];
-  mal_assert(is_list_like(list) || is_nil(list), "first expects a list or a vector argument");
-  if (is_empty(list) || is_nil(list)) {
-    return mal_nil();
-  } else if (is_cons(list)) {
-    return list->car;
-  } else if (list->vec_len > 0) {
-    return list->vec[0];
-  } else {
-    return mal_nil();
-  }
-}
-
-MalType* core_rest(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to rest");
-  MalType *list = args[0];
-  mal_assert(is_list_like(list) || is_nil(list), "rest expects a list or a vector argument");
-  if (is_empty(list) || is_nil(list)) {
-    return mal_empty();
-  } else if (is_cons(list)) {
-    return list->cdr;
-  } else if (list->vec_len > 0) {
-    return mal_cdr2(list);
-  } else {
-    return mal_empty();
-  }
-}
-
-MalType* core_throw(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to throw");
-  MalType *val = args[0];
-  return mal_error(val);
-}
-
-MalType* core_apply(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc >= 2, "Expected at least 2 arguments to apply");
-  MalType *lambda = args[0];
-  mal_assert(is_lambda(lambda), "Expected first argument of apply to be a lambda");
-  MalType *args_vec = mal_vector();
-  struct list_or_vector_iter *iter;
-  MalType *arg;
-  for (size_t i=1; i<argc; i++) {
-    if (is_list_like(args[i])) {
-      for (iter = list_or_vector_iter(args[i]); iter; iter = list_or_vector_iter_next(iter)) {
-        arg = list_or_vector_iter_get_obj(iter);
-        mal_vector_push(args_vec, arg);
-      }
-    } else {
-      mal_vector_push(args_vec, args[i]);
-    }
-  }
-  return trampoline(mal_continuation(lambda->fn, lambda->env, args_vec->vec_len, args_vec->vec));
-}
-
-MalType* core_map(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 2, "Expected 2 arguments to map");
-  MalType *lambda = args[0];
-  mal_assert(is_lambda(lambda), "Expected first argument of map to be a lambda");
-  MalType *list = args[1];
-  mal_assert(is_list_like(list), "Expected second argument of map to be a list or vector");
-  MalType *result_vec = mal_vector();
-  struct list_or_vector_iter *iter;
-  MalType *val;
-  for (iter = list_or_vector_iter(list); iter; iter = list_or_vector_iter_next(iter)) {
-    val = list_or_vector_iter_get_obj(iter);
-    val = trampoline(mal_continuation_1(lambda->fn, lambda->env, val));
-    bubble_if_error(val);
-    mal_vector_push(result_vec, val);
-  }
-  return mal_vector_to_list(result_vec);
-}
-
-MalType* core_is_nil(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to nil?");
-  MalType *val = args[0];
-  return is_nil(val) ? mal_true() : mal_false();
-}
-
-MalType* core_is_true(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to true?");
-  MalType *val = args[0];
-  return is_true(val) ? mal_true() : mal_false();
-}
-
-MalType* core_is_false(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to false?");
-  MalType *val = args[0];
-  return is_false(val) ? mal_true() : mal_false();
-}
-
-MalType* core_is_symbol(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to symbol?");
-  MalType *val = args[0];
-  return is_symbol(val) ? mal_true() : mal_false();
-}
-
-MalType* core_is_keyword(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to keyword?");
-  MalType *val = args[0];
-  return is_keyword(val) ? mal_true() : mal_false();
-}
-
-MalType* core_is_vector(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to vector?");
-  MalType *val = args[0];
-  return is_vector(val) ? mal_true() : mal_false();
-}
-
-MalType* core_is_map(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to map?");
-  MalType *val = args[0];
-  return is_hashmap(val) ? mal_true() : mal_false();
-}
-
-MalType* core_is_sequential(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to sequential?");
-  MalType *val = args[0];
-  return is_list_like(val) ? mal_true() : mal_false();
-}
-
-MalType* core_symbol(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to symbol function");
-  MalType *val = args[0];
-  mal_assert(is_string(val), "symbol function expects a string argument");
-  return mal_symbol(val->str);
-}
-
-MalType* core_keyword(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to keyword function");
-  MalType *val = args[0];
-  if (is_keyword(val)) {
-    return val;
-  }
-  mal_assert(is_string(val), "keyword function expects a string argument");
-  return mal_keyword(val->str);
-}
-
-MalType* core_vector(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  MalType *vec = mal_vector();
-  for (size_t i=0; i<argc; i++) {
-    mal_vector_push(vec, args[i]);
-  }
-  return vec;
-}
-
-MalType* core_hash_map(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc % 2 == 0, "Expected even number of arguments to hash-map");
-  MalType *map = mal_hashmap();
-  for (size_t i=0; i<argc; i+=2) {
-    mal_hashmap_put(map, args[i], args[i+1]);
-  }
-  return map;
-}
-
-MalType* core_assoc(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc % 2 == 1, "Expected odd number of arguments to assoc");
-  MalType *map = args[0];
-  mal_assert(is_hashmap(map), "Expected first argument to assoc to be a hash-map");
-  MalType *new_map = mal_hashmap();
-  struct hashmap_iter *iter;
-  MalType *key, *val;
-  for (iter = hashmap_iter(&map->hashmap); iter; iter = hashmap_iter_next(&map->hashmap, iter)) {
-    key = read_str((char*)hashmap_iter_get_key(iter));
-    val = (MalType*)hashmap_iter_get_data(iter);
-    mal_hashmap_put(new_map, key, val);
-  }
-  for (size_t i=1; i<argc; i+=2) {
-    mal_hashmap_put(new_map, args[i], args[i+1]);
-  }
-  return new_map;
-}
-
-MalType* core_dissoc(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc >= 2, "Expected at least 2 arguments to disassoc");
-  MalType *map = args[0];
-  mal_assert(is_hashmap(map), "Expected first argument to disassoc to be a hash-map");
-  MalType *new_map = mal_hashmap();
-  struct hashmap_iter *iter;
-  MalType *key, *val;
-  int skip;
-  for (iter = hashmap_iter(&map->hashmap); iter; iter = hashmap_iter_next(&map->hashmap, iter)) {
-    skip = 0;
-    key = read_str((char*)hashmap_iter_get_key(iter));
-    for (size_t i=1; i<argc; i++) {
-      if (is_equal(args[i], key)) skip = 1;
-    }
-    if (skip) continue;
-    val = (MalType*)hashmap_iter_get_data(iter);
-    mal_hashmap_put(new_map, key, val);
-  }
-  return new_map;
-}
-
-MalType* core_get(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 2, "Expected 2 arguments to get");
-  MalType *map = args[0];
-  if (is_nil(map)) {
-    return mal_nil();
-  }
-  mal_assert(is_hashmap(map), "Expected first argument to get function to be a hash-map");
-  MalType *key = args[1];
-  MalType *val = mal_hashmap_get(map, key);
-  if (val) {
-    return val;
-  } else {
-    return mal_nil();
-  }
-}
-
-MalType* core_contains(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 2, "Expected 2 arguments to contains?");
-  MalType *map = args[0];
-  mal_assert(is_hashmap(map), "Expected first argument to contains function to be a hash-map");
-  MalType *key = args[1];
-  return mal_hashmap_get(map, key) ? mal_true() : mal_false();
-}
-
-MalType* core_keys(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to keys");
-  MalType *map = args[0];
-  mal_assert(is_hashmap(map), "Expected first argument to keys function to be a hash-map");
-  MalType *keys_vec = mal_hashmap_keys_to_vector(map);
-  return mal_vector_to_list(keys_vec);
-}
-
-MalType* core_vals(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to vals");
-  MalType *map = args[0];
-  mal_assert(is_hashmap(map), "Expected first argument to vals function to be a hash-map");
-  MalType *vals_vec = mal_vector();
-  struct hashmap_iter *iter;
-  MalType *val;
-  for (iter = hashmap_iter(&map->hashmap); iter; iter = hashmap_iter_next(&map->hashmap, iter)) {
-    val = (MalType*)hashmap_iter_get_data(iter);
-    mal_vector_push(vals_vec, val);
-  }
-  return mal_vector_to_list(vals_vec);
-}
-
-MalType* core_readline(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to readline");
-  MalType *prompt = args[0];
-  mal_assert(is_string(prompt), "Expected first argument to readline to be a string");
-  char buffer[1000];
-  printf("%s", prompt->str);
-  if (fgets(buffer, 1000, stdin) == NULL) {
-    return mal_nil();
-  } else {
-    size_t len = strlen(buffer);
-    if (buffer[len-1] == '\n') {
-      buffer[len-1] = 0; // strip the newline
-    }
-    return mal_string(buffer);
-  }
-}
-
-MalType* core_meta(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to meta");
-  MalType *val = args[0];
-  if (val->meta) {
-    return val->meta;
-  } else {
-    return mal_nil();
-  }
-}
-
-MalType* core_with_meta(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 2, "Expected 2 arguments to with-meta");
-  MalType *val = args[0];
-  MalType *new_val = mal_alloc();
-  memcpy(new_val, val, sizeof(MalType));
-  new_val->meta = args[1];
-  return new_val;
-}
-
-MalType* core_seq(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 arguments to seq");
-  MalType *val = args[0];
-  switch (val->type) {
-    case MAL_CONS_TYPE:
-      return val;
-    case MAL_STRING_TYPE:
-      if (val->str_len == 0) {
-        return mal_nil();
-      } else {
-        return mal_string_to_list(val);
-      }
-    case MAL_VECTOR_TYPE:
-      if (val->vec_len == 0) {
-        return mal_nil();
-      } else {
-        return mal_vector_to_list(val);
-      }
-    default:
-      return mal_nil();
-	}
-}
-
-MalType* core_conj(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc >= 2, "Expected at least 2 arguments to conj");
-  MalType *collection = args[0];
-  mal_assert(
-    is_empty(collection) || is_cons(collection) || is_vector(collection),
-    "Expected first argument to conj to be a list or vector"
-  );
-  if (is_empty(collection) || is_cons(collection)) {
-    MalType *node = collection;
-    for (size_t i=1; i<argc; i++) {
-      node = mal_cons(args[i], node);
-    }
-    return node;
-  } else {
-    MalType *vec = mal_vector();
-    for (size_t i=0; i<collection->vec_len; i++) {
-      mal_vector_push(vec, collection->vec[i]);
-    }
-    for (size_t i=1; i<argc; i++) {
-      mal_vector_push(vec, args[i]);
-    }
-    return vec;
-  }
-}
-
-MalType* core_time_ms(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  UNUSED(args);
-  mal_assert(argc == 0, "Expected 0 arguments to time-ms");
-  struct timeval tval;
-  gettimeofday(&tval, NULL);
-  long long microseconds = (tval.tv_sec * 1000000) + tval.tv_usec;
-  return mal_number(microseconds / 1000);
-}
-
-MalType* core_is_string(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to string?");
-  MalType *val = args[0];
-  return is_string(val) ? mal_true() : mal_false();
-}
-
-MalType* core_is_number(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to number?");
-  MalType *val = args[0];
-  return is_number(val) ? mal_true() : mal_false();
-}
-
-MalType* core_is_fn(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to fn?");
-  MalType *val = args[0];
-  return is_lambda(val) && !val->is_macro ? mal_true() : mal_false();
-}
-
-MalType* core_is_macro(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to macro?");
-  MalType *val = args[0];
-  return is_macro(val) ? mal_true() : mal_false();
-}
-
-MalType* core_is_regex(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 1, "Expected 1 argument to regex?");
-  MalType *val = args[0];
-  return is_regex(val) ? mal_true() : mal_false();
-}
-
-MalType* core_regex_match(MalEnv *env, size_t argc, MalType **args) {
-  UNUSED(env);
-  mal_assert(argc == 2, "Expected 2 argument to regex-match");
-  MalType *regex = args[0];
-  mal_assert(is_regex(regex), "Expected first argument to regex-match to be a regex");
-  MalType *str = args[1];
-  mal_assert(is_string(str), "Expected second argument to regex-match to be a string");
-
-  const char *pcreErrorStr;
-  int pcreErrorOffset;
-  pcre *reCompiled = pcre_compile(regex->regex, 0, &pcreErrorStr, &pcreErrorOffset, NULL);
-  if(reCompiled == NULL) {
-    return mal_error(mal_string("Could not compile regex."));
-  }
-
-  pcre_extra *pcreExtra = pcre_study(reCompiled, PCRE_EXTENDED, &pcreErrorStr);
-  if(pcreErrorStr != NULL) {
-    return mal_error(mal_string("Could not study regex."));
-  }
-
-  int subStrVec[30];
-  int pcreExecRet = pcre_exec(reCompiled, pcreExtra, str->str, str->str_len, 0, 0, subStrVec, 30);
-
-  pcre_free(reCompiled);
-
-  return pcreExecRet < 0 ? mal_nil() : mal_number(subStrVec[0]);
-}
-
-void add_core_ns_to_env(MalEnv *env) {
-  struct hashmap *ns = core_ns();
-  struct hashmap_iter *core_iter;
-  char *name;
-  MalType* (*fn)(MalEnv*, size_t, MalType**);
-  for (core_iter = hashmap_iter(ns); core_iter; core_iter = hashmap_iter_next(ns, core_iter)) {
-    name = (char*)hashmap_iter_get_key(core_iter);
-    fn = hashmap_iter_get_data(core_iter);
-    env_set(env, name, mal_builtin_function(fn, name, env));
-  }
-}

D core.h => core.h +0 -74
@@ 1,74 0,0 @@
-#ifndef __MAL_CORE__
-#define __MAL_CORE__
-
-#include <stddef.h>
-
-#include "env.h"
-#include "types.h"
-
-struct hashmap* core_ns();
-MalType* core_add(MalEnv *env, size_t argc, MalType **args);
-MalType* core_sub(MalEnv *env, size_t argc, MalType **args);
-MalType* core_mul(MalEnv *env, size_t argc, MalType **args);
-MalType* core_div(MalEnv *env, size_t argc, MalType **args);
-MalType* core_count(MalEnv *env, size_t argc, MalType **args);
-MalType* core_prn(MalEnv *env, size_t argc, MalType **args);
-MalType* core_list(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_list(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_empty(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_equal(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_gt(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_gte(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_lt(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_lte(MalEnv *env, size_t argc, MalType **args);
-MalType* core_pr_str(MalEnv *env, size_t argc, MalType **args);
-MalType* core_str(MalEnv *env, size_t argc, MalType **args);
-MalType* core_println(MalEnv *env, size_t argc, MalType **args);
-MalType* core_read_string(MalEnv *env, size_t argc, MalType **args);
-MalType* core_slurp(MalEnv *env, size_t argc, MalType **args);
-MalType* core_atom(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_atom(MalEnv *env, size_t argc, MalType **args);
-MalType* core_deref(MalEnv *env, size_t argc, MalType **args);
-MalType* core_reset(MalEnv *env, size_t argc, MalType **args);
-MalType* core_swap(MalEnv *env, size_t argc, MalType **args);
-MalType* core_cons(MalEnv *env, size_t argc, MalType **args);
-MalType* core_concat(MalEnv *env, size_t argc, MalType **args);
-MalType* core_nth(MalEnv *env, size_t argc, MalType **args);
-MalType* core_first(MalEnv *env, size_t argc, MalType **args);
-MalType* core_rest(MalEnv *env, size_t argc, MalType **args);
-MalType* core_throw(MalEnv *env, size_t argc, MalType **args);
-MalType* core_apply(MalEnv *env, size_t argc, MalType **args);
-MalType* core_map(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_nil(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_true(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_false(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_symbol(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_keyword(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_vector(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_map(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_sequential(MalEnv *env, size_t argc, MalType **args);
-MalType* core_symbol(MalEnv *env, size_t argc, MalType **args);
-MalType* core_keyword(MalEnv *env, size_t argc, MalType **args);
-MalType* core_vector(MalEnv *env, size_t argc, MalType **args);
-MalType* core_hash_map(MalEnv *env, size_t argc, MalType **args);
-MalType* core_assoc(MalEnv *env, size_t argc, MalType **args);
-MalType* core_dissoc(MalEnv *env, size_t argc, MalType **args);
-MalType* core_get(MalEnv *env, size_t argc, MalType **args);
-MalType* core_contains(MalEnv *env, size_t argc, MalType **args);
-MalType* core_keys(MalEnv *env, size_t argc, MalType **args);
-MalType* core_vals(MalEnv *env, size_t argc, MalType **args);
-MalType* core_readline(MalEnv *env, size_t argc, MalType **args);
-MalType* core_meta(MalEnv *env, size_t argc, MalType **args);
-MalType* core_with_meta(MalEnv *env, size_t argc, MalType **args);
-MalType* core_seq(MalEnv *env, size_t argc, MalType **args);
-MalType* core_conj(MalEnv *env, size_t argc, MalType **args);
-MalType* core_time_ms(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_string(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_number(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_fn(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_macro(MalEnv *env, size_t argc, MalType **args);
-MalType* core_is_regex(MalEnv *env, size_t argc, MalType **args);
-MalType* core_regex_match(MalEnv *env, size_t argc, MalType **args);
-void add_core_ns_to_env(MalEnv *env);
-
-#endif

D env.c => env.c +0 -57
@@ 1,57 0,0 @@
-#include <gc.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "env.h"
-#include "hashmap.h"
-#include "printer.h"
-#include "types.h"
-#include "util.h"
-
-MalEnv* build_top_env() {
-  MalEnv *top_env = build_env(NULL);
-  top_env->num = 0;
-  return top_env;
-}
-
-MalEnv* build_env(MalEnv *outer) {
-  MalEnv *env = GC_MALLOC(sizeof(MalEnv));
-  env->outer = outer;
-  hashmap_init(&env->data, hashmap_hash_string, hashmap_compare_string, 100);
-  hashmap_set_key_alloc_funcs(&env->data, hashmap_alloc_key_string, NULL);
-  return env;
-}
-
-MalType* env_get(MalEnv *env, char *key) {
-  env = env_find(env, key);
-  if (!env) {
-    return mal_error(mal_sprintf("'%s' not found", key));
-  }
-  MalType *val = hashmap_get(&env->data, key);
-  if (val) {
-    return val;
-  } else {
-    return mal_error(mal_sprintf("'%s' not found", key));
-  }
-}
-
-MalType* env_set(MalEnv *env, char *key, MalType *val) {
-  if (is_blank_line(val)) return val;
-  hashmap_remove(&env->data, key);
-  hashmap_put(&env->data, key, val);
-  return val;
-}
-
-void env_delete(MalEnv *env, char *key) {
-  hashmap_remove(&env->data, key);
-}
-
-MalEnv* env_find(MalEnv *env, char *key) {
-  if (hashmap_get(&env->data, key)) {
-    return env;
-  } else if (env->outer) {
-    return env_find(env->outer, key);
-  } else {
-    return NULL;
-  }
-}

D env.h => env.h +0 -20
@@ 1,20 0,0 @@
-#ifndef __MAL_ENV__
-#define __MAL_ENV__
-
-#include <stdarg.h>
-#include <stddef.h>
-
-#include "hashmap.h"
-#include "types.h"
-
-#define env_get_bubble_error(env, key) ({ MalType *v = env_get((env), (key)); if (is_error(v)) { return v; }; v; })
-
-MalEnv* build_top_env();
-MalEnv* build_env(MalEnv *outer);
-MalType* env_get(MalEnv *env, char *key);
-MalType* env_set(MalEnv *env, char *key, MalType *val);
-void env_delete(MalEnv *env, char *key);
-MalEnv* env_find(MalEnv *env, char *key);
-void inspect_env(MalEnv *env);
-
-#endif

D examples/fib.mal => examples/fib.mal +0 -19
@@ 1,19 0,0 @@
-(def! fib
-  (fn* (n)
-    (if (< n 2)
-        n
-        (+
-          (fib (- n 1))
-          (fib (- n 2))))))
-
-(def! fib2
-  (fn* (n)
-    (let* (f (fn* (n1 n2 c)
-                  (if (= c n)
-                    n2
-                    (f n2 (+ n1 n2) (+ c 1)))))
-      (f 0 1 1))))
-
-(println (fib 10))
-(println (fib2 50))
-

D examples/filter.mal => examples/filter.mal +0 -12
@@ 1,12 0,0 @@
-(def! filter
-      (fn* (l f)
-           (let* [filter* (fn* (l1 l2 f)
-                               (if (empty? l1)
-                                 (seq l2)
-                                 (if (apply f (first l1))
-                                   (filter* (rest l1) (concat l2 (list (first l1))) f)
-                                   (filter* (rest l1) l2 f))))]
-             (filter* l [] f))))
-
-(prn (filter '(1 2 3 4 5 6 7 8 0 9) (fn* (i) (< i 5))))
-(prn (filter [0 1 2 3 4 5 6 7 8 9] (fn* (i) (< i 5))))

D examples/hello.mal => examples/hello.mal +0 -1
@@ 1,1 0,0 @@
-(println "hello world")

D hashmap.c => hashmap.c +0 -724
@@ 1,724 0,0 @@
-/*
- * Copyright (c) 2016-2018 David Leeds <davidesleeds@gmail.com>
- *
- * Hashmap is free software; you can redistribute it and/or modify
- * it under the terms of the MIT license. See LICENSE for details.
- *
- * Updated 2018-02-16 by Tim Morgan to use GC_MALLOC and friends.
- */
-
-#include <gc.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-
-#include "hashmap.h"
-
-#ifndef HASHMAP_NOASSERT
-#include <assert.h>
-#define HASHMAP_ASSERT(expr)            assert(expr)
-#else
-#define HASHMAP_ASSERT(expr)
-#endif
-
-/* Table sizes must be powers of 2 */
-#define HASHMAP_SIZE_MIN                (1 << 5)    /* 32 */
-#define HASHMAP_SIZE_DEFAULT            (1 << 8)    /* 256 */
-#define HASHMAP_SIZE_MOD(map, val)      ((val) & ((map)->table_size - 1))
-
-/* Limit for probing is 1/2 of table_size */
-#define HASHMAP_PROBE_LEN(map)          ((map)->table_size >> 1)
-/* Return the next linear probe index */
-#define HASHMAP_PROBE_NEXT(map, index)  HASHMAP_SIZE_MOD(map, (index) + 1)
-
-/* Check if index b is less than or equal to index a */
-#define HASHMAP_INDEX_LE(map, a, b)     \
-    ((a) == (b) || (((b) - (a)) & ((map)->table_size >> 1)) != 0)
-
-
-struct hashmap_entry {
-    void *key;
-    void *data;
-#ifdef HASHMAP_METRICS
-    size_t num_collisions;
-#endif
-};
-
-
-/*
- * Enforce a maximum 0.75 load factor.
- */
-static inline size_t hashmap_table_min_size_calc(size_t num_entries)
-{
-    return num_entries + (num_entries / 3);
-}
-
-/*
- * Calculate the optimal table size, given the specified max number
- * of elements.
- */
-static size_t hashmap_table_size_calc(size_t num_entries)
-{
-    size_t table_size;
-    size_t min_size;
-
-    table_size = hashmap_table_min_size_calc(num_entries);
-
-    /* Table size is always a power of 2 */
-    min_size = HASHMAP_SIZE_MIN;
-    while (min_size < table_size) {
-        min_size <<= 1;
-    }
-    return min_size;
-}
-
-/*
- * Get a valid hash table index from a key.
- */
-static inline size_t hashmap_calc_index(const struct hashmap *map,
-    const void *key)
-{
-    return HASHMAP_SIZE_MOD(map, map->hash(key));
-}
-
-/*
- * Return the next populated entry, starting with the specified one.
- * Returns NULL if there are no more valid entries.
- */
-static struct hashmap_entry *hashmap_entry_get_populated(
-    const struct hashmap *map, struct hashmap_entry *entry)
-{
-    for (; entry < &map->table[map->table_size]; ++entry) {
-        if (entry->key) {
-            return entry;
-        }
-    }
-    return NULL;
-}
-
-/*
- * Find the hashmap entry with the specified key, or an empty slot.
- * Returns NULL if the entire table has been searched without finding a match.
- */
-static struct hashmap_entry *hashmap_entry_find(const struct hashmap *map,
-    const void *key, bool find_empty)
-{
-    size_t i;
-    size_t index;
-    size_t probe_len = HASHMAP_PROBE_LEN(map);
-    struct hashmap_entry *entry;
-
-    index = hashmap_calc_index(map, key);
-
-    /* Linear probing */
-    for (i = 0; i < probe_len; ++i) {
-        entry = &map->table[index];
-        if (!entry->key) {
-            if (find_empty) {
-#ifdef HASHMAP_METRICS
-                entry->num_collisions = i;
-#endif
-                return entry;
-            }
-            return NULL;
-        }
-        if (map->key_compare(key, entry->key) == 0) {
-            return entry;
-        }
-        index = HASHMAP_PROBE_NEXT(map, index);
-    }
-    return NULL;
-}
-
-/*
- * Removes the specified entry and processes the proceeding entries to reduce
- * the load factor and keep the chain continuous.  This is a required
- * step for hash maps using linear probing.
- */
-static void hashmap_entry_remove(struct hashmap *map,
-    struct hashmap_entry *removed_entry)
-{
-    size_t i;
-#ifdef HASHMAP_METRICS
-    size_t removed_i = 0;
-#endif
-    size_t index;
-    size_t entry_index;
-    size_t removed_index = (removed_entry - map->table);
-    struct hashmap_entry *entry;
-
-    /* Free the key */
-    if (map->key_free) {
-        map->key_free(removed_entry->key);
-    }
-    --map->num_entries;
-
-    /* Fill the free slot in the chain */
-    index = HASHMAP_PROBE_NEXT(map, removed_index);
-    for (i = 1; i < map->table_size; ++i) {
-        entry = &map->table[index];
-        if (!entry->key) {
-            /* Reached end of chain */
-            break;
-        }
-        entry_index = hashmap_calc_index(map, entry->key);
-        /* Shift in entries with an index <= to the removed slot */
-        if (HASHMAP_INDEX_LE(map, removed_index, entry_index)) {
-#ifdef HASHMAP_METRICS
-            entry->num_collisions -= (i - removed_i);
-            removed_i = i;
-#endif
-            memcpy(removed_entry, entry, sizeof(*removed_entry));
-            removed_index = index;
-            removed_entry = entry;
-        }
-        index = HASHMAP_PROBE_NEXT(map, index);
-    }
-    /* Clear the last removed entry */
-    memset(removed_entry, 0, sizeof(*removed_entry));
-}
-
-/*
- * Reallocates the hash table to the new size and rehashes all entries.
- * new_size MUST be a power of 2.
- * Returns 0 on success and -errno on allocation or hash function failure.
- */
-static int hashmap_rehash(struct hashmap *map, size_t new_size)
-{
-    size_t old_size;
-    struct hashmap_entry *old_table;
-    struct hashmap_entry *new_table;
-    struct hashmap_entry *entry;
-    struct hashmap_entry *new_entry;
-
-    HASHMAP_ASSERT(new_size >= HASHMAP_SIZE_MIN);
-    HASHMAP_ASSERT((new_size & (new_size - 1)) == 0);
-
-    new_table = (struct hashmap_entry *)GC_MALLOC(new_size * sizeof(struct hashmap_entry));
-    if (!new_table) {
-        return -ENOMEM;
-    }
-    /* Backup old elements in case of rehash failure */
-    old_size = map->table_size;
-    old_table = map->table;
-    map->table_size = new_size;
-    map->table = new_table;
-    /* Rehash */
-    for (entry = old_table; entry < &old_table[old_size]; ++entry) {
-        if (!entry->data) {
-            /* Only copy entries with data */
-            continue;
-        }
-        new_entry = hashmap_entry_find(map, entry->key, true);
-        if (!new_entry) {
-            /*
-             * The load factor is too high with the new table
-             * size, or a poor hash function was used.
-             */
-            goto revert;
-        }
-        /* Shallow copy (intentionally omits num_collisions) */
-        new_entry->key = entry->key;
-        new_entry->data = entry->data;
-    }
-    GC_FREE(old_table);
-    return 0;
-revert:
-    map->table_size = old_size;
-    map->table = old_table;
-    GC_FREE(new_table);
-    return -EINVAL;
-}
-
-/*
- * Iterate through all entries and free all keys.
- */
-static void hashmap_free_keys(struct hashmap *map)
-{
-    struct hashmap_iter *iter;
-
-    if (!map->key_free) {
-        return;
-    }
-    for (iter = hashmap_iter(map); iter;
-        iter = hashmap_iter_next(map, iter)) {
-        map->key_free((void *)hashmap_iter_get_key(iter));
-    }
-}
-
-/*
- * Initialize an empty hashmap.
- *
- * hash_func should return an even distribution of numbers between 0
- * and SIZE_MAX varying on the key provided.  If set to NULL, the default
- * case-sensitive string hash function is used: hashmap_hash_string
- *
- * key_compare_func should return 0 if the keys match, and non-zero otherwise.
- * If set to NULL, the default case-sensitive string comparator function is
- * used: hashmap_compare_string
- *
- * initial_size is optional, and may be set to the max number of entries
- * expected to be put in the hash table.  This is used as a hint to
- * pre-allocate the hash table to the minimum size needed to avoid
- * gratuitous rehashes.  If initial_size is 0, a default size will be used.
- *
- * Returns 0 on success and -errno on failure.
- */
-int hashmap_init(struct hashmap *map, size_t (*hash_func)(const void *),
-    int (*key_compare_func)(const void *, const void *),
-    size_t initial_size)
-{
-    HASHMAP_ASSERT(map != NULL);
-
-    if (!initial_size) {
-        initial_size = HASHMAP_SIZE_DEFAULT;
-    } else {
-        /* Convert init size to valid table size */
-        initial_size = hashmap_table_size_calc(initial_size);
-    }
-    map->table_size_init = initial_size;
-    map->table_size = initial_size;
-    map->num_entries = 0;
-    map->table = (struct hashmap_entry *)GC_MALLOC(initial_size * sizeof(struct hashmap_entry));
-    if (!map->table) {
-        return -ENOMEM;
-    }
-    map->hash = hash_func ?
-            hash_func : hashmap_hash_string;
-    map->key_compare = key_compare_func ?
-            key_compare_func : hashmap_compare_string;
-    map->key_alloc = NULL;
-    map->key_free = NULL;
-    return 0;
-}
-
-/*
- * Free the hashmap and all associated memory.
- */
-void hashmap_destroy(struct hashmap *map)
-{
-    if (!map) {
-        return;
-    }
-    hashmap_free_keys(map);
-    GC_FREE(map->table);
-    memset(map, 0, sizeof(*map));
-}
-
-/*
- * Enable internal memory management of hash keys.
- */
-void hashmap_set_key_alloc_funcs(struct hashmap *map,
-    void *(*key_alloc_func)(const void *),
-    void (*key_free_func)(void *))
-{
-    HASHMAP_ASSERT(map != NULL);
-
-    map->key_alloc = key_alloc_func;
-    map->key_free = key_free_func;
-}
-
-/*
- * Add an entry to the hashmap.  If an entry with a matching key already
- * exists and has a data pointer associated with it, the existing data
- * pointer is returned, instead of assigning the new value.  Compare
- * the return value with the data passed in to determine if a new entry was
- * created.  Returns NULL if memory allocation failed.
- */
-void *hashmap_put(struct hashmap *map, const void *key, void *data)
-{
-    struct hashmap_entry *entry;
-
-    HASHMAP_ASSERT(map != NULL);
-    HASHMAP_ASSERT(key != NULL);
-
-    /* Rehash with 2x capacity if load factor is approaching 0.75 */
-    if (map->table_size <= hashmap_table_min_size_calc(map->num_entries)) {
-        hashmap_rehash(map, map->table_size << 1);
-    }
-    entry = hashmap_entry_find(map, key, true);
-    if (!entry) {
-        /*
-         * Cannot find an empty slot.  Either out of memory, or using
-         * a poor hash function.  Attempt to rehash once to reduce
-         * chain length.
-         */
-        if (hashmap_rehash(map, map->table_size << 1) < 0) {
-            return NULL;
-        }
-        entry = hashmap_entry_find(map, key, true);
-        if (!entry) {
-            return NULL;
-        }
-    }
-    if (!entry->key) {
-        /* Allocate copy of key to simplify memory management */
-        if (map->key_alloc) {
-            entry->key = map->key_alloc(key);
-            if (!entry->key) {
-                return NULL;
-            }
-        } else {
-            entry->key = (void *)key;
-        }
-        ++map->num_entries;
-    } else if (entry->data) {
-        /* Do not overwrite existing data */
-        return entry->data;
-    }
-    entry->data = data;
-    return data;
-}
-
-/*
- * Return the data pointer, or NULL if no entry exists.
- */
-void *hashmap_get(const struct hashmap *map, const void *key)
-{
-    struct hashmap_entry *entry;
-
-    HASHMAP_ASSERT(map != NULL);
-    HASHMAP_ASSERT(key != NULL);
-
-    entry = hashmap_entry_find(map, key, false);
-    if (!entry) {
-        return NULL;
-    }
-    return entry->data;
-}
-
-/*
- * Remove an entry with the specified key from the map.
- * Returns the data pointer, or NULL, if no entry was found.
- */
-void *hashmap_remove(struct hashmap *map, const void *key)
-{
-    struct hashmap_entry *entry;
-    void *data;
-
-    HASHMAP_ASSERT(map != NULL);
-    HASHMAP_ASSERT(key != NULL);
-
-    entry = hashmap_entry_find(map, key, false);
-    if (!entry) {
-        return NULL;
-    }
-    data = entry->data;
-    /* Clear the entry and make the chain contiguous */
-    hashmap_entry_remove(map, entry);
-    return data;
-}
-
-/*
- * Remove all entries.
- */
-void hashmap_clear(struct hashmap *map)
-{
-    HASHMAP_ASSERT(map != NULL);
-
-    hashmap_free_keys(map);
-    map->num_entries = 0;
-    memset(map->table, 0, sizeof(struct hashmap_entry) * map->table_size);
-}
-
-/*
- * Remove all entries and reset the hash table to its initial size.
- */
-void hashmap_reset(struct hashmap *map)
-{
-    struct hashmap_entry *new_table;
-
-    HASHMAP_ASSERT(map != NULL);
-
-    hashmap_clear(map);
-    if (map->table_size == map->table_size_init) {
-        return;
-    }
-    new_table = (struct hashmap_entry *)GC_REALLOC(map->table,
-        sizeof(struct hashmap_entry) * map->table_size_init);
-    if (!new_table) {
-        return;
-    }
-    map->table = new_table;
-    map->table_size = map->table_size_init;
-}
-
-/*
- * Return the number of entries in the hash map.
- */
-size_t hashmap_size(const struct hashmap *map)
-{
-    HASHMAP_ASSERT(map != NULL);
-
-    return map->num_entries;
-}
-
-/*
- * Get a new hashmap iterator.  The iterator is an opaque
- * pointer that may be used with hashmap_iter_*() functions.
- * Hashmap iterators are INVALID after a put or remove operation is performed.
- * hashmap_iter_remove() allows safe removal during iteration.
- */
-struct hashmap_iter *hashmap_iter(const struct hashmap *map)
-{
-    HASHMAP_ASSERT(map != NULL);
-
-    if (!map->num_entries) {
-        return NULL;
-    }
-    return (struct hashmap_iter *)hashmap_entry_get_populated(map,
-        map->table);
-}
-
-/*
- * Return an iterator to the next hashmap entry.  Returns NULL if there are
- * no more entries.
- */
-struct hashmap_iter *hashmap_iter_next(const struct hashmap *map,
-    const struct hashmap_iter *iter)
-{
-    struct hashmap_entry *entry = (struct hashmap_entry *)iter;
-
-    HASHMAP_ASSERT(map != NULL);
-
-    if (!iter) {
-        return NULL;
-    }
-    return (struct hashmap_iter *)hashmap_entry_get_populated(map,
-        entry + 1);
-}
-
-/*
- * Remove the hashmap entry pointed to by this iterator and return an
- * iterator to the next entry.  Returns NULL if there are no more entries.
- */
-struct hashmap_iter *hashmap_iter_remove(struct hashmap *map,
-    const struct hashmap_iter *iter)
-{
-    struct hashmap_entry *entry = (struct hashmap_entry *)iter;
-
-    HASHMAP_ASSERT(map != NULL);
-
-    if (!iter) {
-        return NULL;
-    }
-    if (!entry->key) {
-        /* Iterator is invalid, so just return the next valid entry */
-        return hashmap_iter_next(map, iter);
-    }
-    hashmap_entry_remove(map, entry);
-    return (struct hashmap_iter *)hashmap_entry_get_populated(map, entry);
-}
-
-/*
- * Return the key of the entry pointed to by the iterator.
- */
-const void *hashmap_iter_get_key(const struct hashmap_iter *iter)
-{
-    if (!iter) {
-        return NULL;
-    }
-    return (const void *)((struct hashmap_entry *)iter)->key;
-}
-
-/*
- * Return the data of the entry pointed to by the iterator.
- */
-void *hashmap_iter_get_data(const struct hashmap_iter *iter)
-{
-    if (!iter) {
-        return NULL;
-    }
-    return ((struct hashmap_entry *)iter)->data;
-}
-
-/*
- * Set the data pointer of the entry pointed to by the iterator.
- */
-void hashmap_iter_set_data(const struct hashmap_iter *iter, void *data)
-{
-    if (!iter) {
-        return;
-    }
-    ((struct hashmap_entry *)iter)->data = data;
-}
-
-/*
- * Invoke func for each entry in the hashmap.  Unlike the hashmap_iter_*()
- * interface, this function supports calls to hashmap_remove() during iteration.
- * However, it is an error to put or remove an entry other than the current one,
- * and doing so will immediately halt iteration and return an error.
- * Iteration is stopped if func returns non-zero.  Returns func's return
- * value if it is < 0, otherwise, 0.
- */
-int hashmap_foreach(const struct hashmap *map,
-    int (*func)(const void *, void *, void *), void *arg)
-{
-    struct hashmap_entry *entry;
-    size_t num_entries;
-    const void *key;
-    int rc;
-
-    HASHMAP_ASSERT(map != NULL);
-    HASHMAP_ASSERT(func != NULL);
-
-    entry = map->table;
-    for (entry = map->table; entry < &map->table[map->table_size];
-        ++entry) {
-        if (!entry->key) {
-            continue;
-        }
-        num_entries = map->num_entries;
-        key = entry->key;
-        rc = func(entry->key, entry->data, arg);
-        if (rc < 0) {
-            return rc;
-        }
-        if (rc > 0) {
-            return 0;
-        }
-        /* Run this entry again if func() deleted it */
-        if (entry->key != key) {
-            --entry;
-        } else if (num_entries != map->num_entries) {
-            /* Stop immediately if func put/removed another entry */
-            return -1;
-        }
-    }
-    return 0;
-}
-
-/*
- * Default hash function for string keys.
- * This is an implementation of the well-documented Jenkins one-at-a-time
- * hash function.
- */
-size_t hashmap_hash_string(const void *key)
-{
-    const char *key_str = (const char *)key;
-    size_t hash = 0;
-
-    for (; *key_str; ++key_str) {
-        hash += *key_str;
-        hash += (hash << 10);
-        hash ^= (hash >> 6);
-    }
-    hash += (hash << 3);
-    hash ^= (hash >> 11);
-    hash += (hash << 15);
-    return hash;
-}
-
-/*
- * Default key comparator function for string keys.
- */
-int hashmap_compare_string(const void *a, const void *b)
-{
-    return strcmp((const char *)a, (const char *)b);
-}
-
-/*
- * Default key allocation function for string keys.  Use free() for the
- * key_free_func.
- */
-void *hashmap_alloc_key_string(const void *key)
-{
-    return (void *)strdup((const char *)key);
-}
-
-/*
- * Case insensitive hash function for string keys.
- */
-size_t hashmap_hash_string_i(const void *key)
-{
-    const char *key_str = (const char *)key;
-    size_t hash = 0;
-
-    for (; *key_str; ++key_str) {
-        hash += tolower(*key_str);
-        hash += (hash << 10);
-        hash ^= (hash >> 6);
-    }
-    hash += (hash << 3);
-    hash ^= (hash >> 11);
-    hash += (hash << 15);
-    return hash;
-}
-
-/*
- * Case insensitive key comparator function for string keys.
- */
-int hashmap_compare_string_i(const void *a, const void *b)
-{
-    return strcasecmp((const char *)a, (const char *)b);
-}
-
-
-#ifdef HASHMAP_METRICS
-/*
- * Return the load factor.
- */
-double hashmap_load_factor(const struct hashmap *map)
-{
-    HASHMAP_ASSERT(map != NULL);
-
-    if (!map->table_size) {
-        return 0;
-    }
-    return (double)map->num_entries / map->table_size;
-}
-
-/*
- * Return the average number of collisions per entry.
- */
-double hashmap_collisions_mean(const struct hashmap *map)
-{
-    struct hashmap_entry *entry;
-    size_t total_collisions = 0;
-
-    HASHMAP_ASSERT(map != NULL);
-
-    if (!map->num_entries) {
-        return 0;
-    }
-    for (entry = map->table; entry < &map->table[map->table_size];
-        ++entry) {
-        if (!entry->key) {
-            continue;
-        }
-        total_collisions += entry->num_collisions;
-    }
-    return (double)total_collisions / map->num_entries;
-}
-
-/*
- * Return the variance between entry collisions.  The higher the variance,
- * the more likely the hash function is poor and is resulting in clustering.
- */
-double hashmap_collisions_variance(const struct hashmap *map)
-{
-    struct hashmap_entry *entry;
-    double mean_collisions;
-    double variance;
-    double total_variance = 0;
-
-    HASHMAP_ASSERT(map != NULL);
-
-    if (!map->num_entries) {
-        return 0;
-    }
-    mean_collisions = hashmap_collisions_mean(map);
-    for (entry = map->table; entry < &map->table[map->table_size];
-        ++entry) {
-        if (!entry->key) {
-            continue;
-        }
-        variance = (double)entry->num_collisions - mean_collisions;
-        total_variance += variance * variance;
-    }
-    return total_variance / map->num_entries;
-}
-#endif

D hashmap.h => hashmap.h +0 -281
@@ 1,281 0,0 @@
-/*
- * Copyright (c) 2016-2018 David Leeds <davidesleeds@gmail.com>
- *
- * Hashmap is free software; you can redistribute it and/or modify
- * it under the terms of the MIT license. See LICENSE for details.
- */
-
-#ifndef __HASHMAP_H__
-#define __HASHMAP_H__
-
-#include <stddef.h>
-
-/*
- * Define HASHMAP_METRICS to compile in performance analysis
- * functions for use in assessing hash function performance.
- */
-/* #define HASHMAP_METRICS */
-
-/*
- * Define HASHMAP_NOASSERT to compile out all assertions used internally.
- */
-/* #define HASHMAP_NOASSERT */
-
-/*
- * Macros to declare type-specific versions of hashmap_*() functions to
- * allow compile-time type checking and avoid the need for type casting.
- */
-#define HASHMAP_FUNCS_DECLARE(name, key_type, data_type)                \
-    data_type *name##_hashmap_put(struct hashmap *map,                  \
-            const key_type *key, data_type *data);                      \
-    data_type *name##_hashmap_get(const struct hashmap *map,            \
-            const key_type *key);                                       \
-    data_type *name##_hashmap_remove(struct hashmap *map,               \
-            const key_type *key);                                       \
-    const key_type *name##_hashmap_iter_get_key(                        \
-            const struct hashmap_iter *iter);                           \
-    data_type *name##_hashmap_iter_get_data(                            \
-            const struct hashmap_iter *iter);                           \
-    void name##_hashmap_iter_set_data(const struct hashmap_iter *iter,  \
-            data_type *data);                                           \
-    int name##_hashmap_foreach(const struct hashmap *map,               \
-            int (*func)(const key_type *, data_type *, void *), void *arg);
-
-#define HASHMAP_FUNCS_CREATE(name, key_type, data_type)                 \
-    data_type *name##_hashmap_put(struct hashmap *map,                  \
-            const key_type *key, data_type *data)                       \
-    {                                                                   \
-        return (data_type *)hashmap_put(map, (const void *)key,         \
-                (void *)data);                                          \
-    }                                                                   \
-    data_type *name##_hashmap_get(const struct hashmap *map,            \
-            const key_type *key)                                        \
-    {                                                                   \
-        return (data_type *)hashmap_get(map, (const void *)key);        \
-    }                                                                   \
-    data_type *name##_hashmap_remove(struct hashmap *map,               \
-            const key_type *key)                                        \
-    {                                                                   \
-        return (data_type *)hashmap_remove(map, (const void *)key);     \
-    }                                                                   \
-    const key_type *name##_hashmap_iter_get_key(                        \
-            const struct hashmap_iter *iter)                            \
-    {                                                                   \
-        return (const key_type *)hashmap_iter_get_key(iter);            \
-    }                                                                   \
-    data_type *name##_hashmap_iter_get_data(                            \
-            const struct hashmap_iter *iter)                            \
-    {                                                                   \
-        return (data_type *)hashmap_iter_get_data(iter);                \
-    }                                                                   \
-    void name##_hashmap_iter_set_data(const struct hashmap_iter *iter,  \
-            data_type *data)                                            \
-    {                                                                   \
-        hashmap_iter_set_data(iter, (void *)data);                      \
-    }                                                                   \
-    struct __##name##_hashmap_foreach_state {                           \
-        int (*func)(const key_type *, data_type *, void *);             \
-        void *arg;                                                      \
-    };                                                                  \
-    static inline int __##name##_hashmap_foreach_callback(              \
-            const void *key, void *data, void *arg)                     \
-    {                                                                   \
-        struct __##name##_hashmap_foreach_state *s =                    \
-            (struct __##name##_hashmap_foreach_state *)arg;             \
-        return s->func((const key_type *)key,                           \
-                (data_type *)data, s->arg);                             \
-    }                                                                   \
-    int name##_hashmap_foreach(const struct hashmap *map,               \
-            int (*func)(const key_type *, data_type *, void *),         \
-            void *arg)                                                  \
-    {                                                                   \
-        struct __##name##_hashmap_foreach_state s = { func, arg };      \
-        return hashmap_foreach(map,                                     \
-            __##name##_hashmap_foreach_callback, &s);                   \
-    }
-
-
-struct hashmap_iter;
-struct hashmap_entry;
-
-/*
- * The hashmap state structure.
- */
-struct hashmap {
-    size_t table_size_init;
-    size_t table_size;
-    size_t num_entries;
-    struct hashmap_entry *table;
-    size_t (*hash)(const void *);
-    int (*key_compare)(const void *, const void *);
-    void *(*key_alloc)(const void *);
-    void (*key_free)(void *);
-};
-
-/*
- * Initialize an empty hashmap.
- *
- * hash_func should return an even distribution of numbers between 0
- * and SIZE_MAX varying on the key provided.  If set to NULL, the default
- * case-sensitive string hash function is used: hashmap_hash_string
- *
- * key_compare_func should return 0 if the keys match, and non-zero otherwise.
- * If set to NULL, the default case-sensitive string comparator function is
- * used: hashmap_compare_string
- *
- * initial_size is optional, and may be set to the max number of entries
- * expected to be put in the hash table.  This is used as a hint to
- * pre-allocate the hash table to the minimum size needed to avoid
- * gratuitous rehashes.  If initial_size is 0, a default size will be used.
- *
- * Returns 0 on success and -errno on failure.
- */
-int hashmap_init(struct hashmap *map, size_t (*hash_func)(const void *),
-    int (*key_compare_func)(const void *, const void *),
-    size_t initial_size);
-
-/*
- * Free the hashmap and all associated memory.
- */
-void hashmap_destroy(struct hashmap *map);
-
-/*
- * Enable internal memory allocation and management of hash keys.
- */
-void hashmap_set_key_alloc_funcs(struct hashmap *map,
-    void *(*key_alloc_func)(const void *),
-    void (*key_free_func)(void *));
-
-/*
- * Add an entry to the hashmap.  If an entry with a matching key already
- * exists and has a data pointer associated with it, the existing data
- * pointer is returned, instead of assigning the new value.  Compare
- * the return value with the data passed in to determine if a new entry was
- * created.  Returns NULL if memory allocation failed.
- */
-void *hashmap_put(struct hashmap *map, const void *key, void *data);
-
-/*
- * Return the data pointer, or NULL if no entry exists.
- */
-void *hashmap_get(const struct hashmap *map, const void *key);
-
-/*
- * Remove an entry with the specified key from the map.
- * Returns the data pointer, or NULL, if no entry was found.
- */
-void *hashmap_remove(struct hashmap *map, const void *key);
-
-/*
- * Remove all entries.
- */
-void hashmap_clear(struct hashmap *map);
-
-/*
- * Remove all entries and reset the hash table to its initial size.
- */
-void hashmap_reset(struct hashmap *map);
-
-/*
- * Return the number of entries in the hash map.
- */
-size_t hashmap_size(const struct hashmap *map);
-
-/*
- * Get a new hashmap iterator.  The iterator is an opaque
- * pointer that may be used with hashmap_iter_*() functions.
- * Hashmap iterators are INVALID after a put or remove operation is performed.
- * hashmap_iter_remove() allows safe removal during iteration.
- */
-struct hashmap_iter *hashmap_iter(const struct hashmap *map);
-
-/*
- * Return an iterator to the next hashmap entry.  Returns NULL if there are
- * no more entries.
- */
-struct hashmap_iter *hashmap_iter_next(const struct hashmap *map,
-    const struct hashmap_iter *iter);
-
-/*
- * Remove the hashmap entry pointed to by this iterator and returns an
- * iterator to the next entry.  Returns NULL if there are no more entries.
- */
-struct hashmap_iter *hashmap_iter_remove(struct hashmap *map,
-    const struct hashmap_iter *iter);
-
-/*
- * Return the key of the entry pointed to by the iterator.
- */
-const void *hashmap_iter_get_key(const struct hashmap_iter *iter);
-
-/*
- * Return the data of the entry pointed to by the iterator.
- */
-void *hashmap_iter_get_data(const struct hashmap_iter *iter);
-
-/*
- * Set the data pointer of the entry pointed to by the iterator.
- */
-void hashmap_iter_set_data(const struct hashmap_iter *iter, void *data);
-
-/*
- * Invoke func for each entry in the hashmap.  Unlike the hashmap_iter_*()
- * interface, this function supports calls to hashmap_remove() during iteration.
- * However, it is an error to put or remove an entry other than the current one,
- * and doing so will immediately halt iteration and return an error.
- * Iteration is stopped if func returns non-zero.  Returns func's return
- * value if it is < 0, otherwise, 0.
- */
-int hashmap_foreach(const struct hashmap *map,
-    int (*func)(const void *, void *, void *), void *arg);
-
-/*
- * Default hash function for string keys.
- * This is an implementation of the well-documented Jenkins one-at-a-time
- * hash function.
- */
-size_t hashmap_hash_string(const void *key);
-
-/*
- * Default key comparator function for string keys.
- */
-int hashmap_compare_string(const void *a, const void *b);
-
-/*
- * Default key allocation function for string keys.  Use free() for the
- * key_free_func.
- */
-void *hashmap_alloc_key_string(const void *key);
-
-/*
- * Case insensitive hash function for string keys.
- */
-size_t hashmap_hash_string_i(const void *key);
-
-/*
- * Case insensitive key comparator function for string keys.
- */
-int hashmap_compare_string_i(const void *a, const void *b);
-
-
-#ifdef HASHMAP_METRICS
-/*
- * Return the load factor.
- */
-double hashmap_load_factor(const struct hashmap *map);
-
-/*
- * Return the average number of collisions per entry.
- */
-double hashmap_collisions_mean(const struct hashmap *map);
-
-/*
- * Return the variance between entry collisions.  The higher the variance,
- * the more likely the hash function is poor and is resulting in clustering.
- */
-double hashmap_collisions_variance(const struct hashmap *map);
-#endif
-
-
-#endif /* __HASHMAP_H__ */
-

D mal/LICENSE => mal/LICENSE +0 -387
@@ 1,387 0,0 @@
-Copyright (C) 2015 Joel Martin <github@martintribe.org>
-
-Mal (make-a-lisp) is licensed under the MPL 2.0 (Mozilla Public
-License 2.0). The text of the MPL 2.0 license is included below and
-can be found at https://www.mozilla.org/MPL/2.0/
-
-Many of the implementations run or compile using a line editing
-library. In some cases, the implementations provide an option in the
-code to switch between the GNU GPL licensed GNU readline library and
-the BSD licensed editline (libedit) library.
-
-
-Mozilla Public License Version 2.0
-==================================
-
-1. Definitions
---------------
-
-1.1. "Contributor"
-    means each individual or legal entity that creates, contributes to
-    the creation of, or owns Covered Software.
-
-1.2. "Contributor Version"
-    means the combination of the Contributions of others (if any) used
-    by a Contributor and that particular Contributor's Contribution.
-
-1.3. "Contribution"
-    means Covered Software of a particular Contributor.
-
-1.4. "Covered Software"
-    means Source Code Form to which the initial Contributor has attached
-    the notice in Exhibit A, the Executable Form of such Source Code
-    Form, and Modifications of such Source Code Form, in each case
-    including portions thereof.
-
-1.5. "Incompatible With Secondary Licenses"
-    means
-
-    (a) that the initial Contributor has attached the notice described
-        in Exhibit B to the Covered Software; or
-
-    (b) that the Covered Software was made available under the terms of
-        version 1.1 or earlier of the License, but not also under the
-        terms of a Secondary License.
-
-1.6. "Executable Form"
-    means any form of the work other than Source Code Form.
-
-1.7. "Larger Work"
-    means a work that combines Covered Software with other material, in
-    a separate file or files, that is not Covered Software.
-
-1.8. "License"
-    means this document.
-
-1.9. "Licensable"
-    means having the right to grant, to the maximum extent possible,
-    whether at the time of the initial grant or subsequently, any and
-    all of the rights conveyed by this License.
-
-1.10. "Modifications"
-    means any of the following:
-
-    (a) any file in Source Code Form that results from an addition to,
-        deletion from, or modification of the contents of Covered
-        Software; or
-
-    (b) any new file in Source Code Form that contains any Covered
-        Software.
-
-1.11. "Patent Claims" of a Contributor
-    means any patent claim(s), including without limitation, method,
-    process, and apparatus claims, in any patent Licensable by such
-    Contributor that would be infringed, but for the grant of the
-    License, by the making, using, selling, offering for sale, having
-    made, import, or transfer of either its Contributions or its
-    Contributor Version.
-
-1.12. "Secondary License"
-    means either the GNU General Public License, Version 2.0, the GNU
-    Lesser General Public License, Version 2.1, the GNU Affero General
-    Public License, Version 3.0, or any later versions of those
-    licenses.
-
-1.13. "Source Code Form"
-    means the form of the work preferred for making modifications.
-
-1.14. "You" (or "Your")
-    means an individual or a legal entity exercising rights under this
-    License. For legal entities, "You" includes any entity that
-    controls, is controlled by, or is under common control with You. For
-    purposes of this definition, "control" means (a) the power, direct
-    or indirect, to cause the direction or management of such entity,
-    whether by contract or otherwise, or (b) ownership of more than
-    fifty percent (50%) of the outstanding shares or beneficial
-    ownership of such entity.
-
-2. License Grants and Conditions
---------------------------------
-
-2.1. Grants
-
-Each Contributor hereby grants You a world-wide, royalty-free,
-non-exclusive license:
-
-(a) under intellectual property rights (other than patent or trademark)
-    Licensable by such Contributor to use, reproduce, make available,
-    modify, display, perform, distribute, and otherwise exploit its
-    Contributions, either on an unmodified basis, with Modifications, or
-    as part of a Larger Work; and
-
-(b) under Patent Claims of such Contributor to make, use, sell, offer
-    for sale, have made, import, and otherwise transfer either its
-    Contributions or its Contributor Version.
-
-2.2. Effective Date
-
-The licenses granted in Section 2.1 with respect to any Contribution
-become effective for each Contribution on the date the Contributor first
-distributes such Contribution.
-
-2.3. Limitations on Grant Scope
-
-The licenses granted in this Section 2 are the only rights granted under
-this License. No additional rights or licenses will be implied from the
-distribution or licensing of Covered Software under this License.
-Notwithstanding Section 2.1(b) above, no patent license is granted by a
-Contributor:
-
-(a) for any code that a Contributor has removed from Covered Software;
-    or
-
-(b) for infringements caused by: (i) Your and any other third party's
-    modifications of Covered Software, or (ii) the combination of its
-    Contributions with other software (except as part of its Contributor
-    Version); or
-
-(c) under Patent Claims infringed by Covered Software in the absence of
-    its Contributions.
-
-This License does not grant any rights in the trademarks, service marks,
-or logos of any Contributor (except as may be necessary to comply with
-the notice requirements in Section 3.4).
-
-2.4. Subsequent Licenses
-
-No Contributor makes additional grants as a result of Your choice to
-distribute the Covered Software under a subsequent version of this
-License (see Section 10.2) or under the terms of a Secondary License (if
-permitted under the terms of Section 3.3).
-
-2.5. Representation
-
-Each Contributor represents that the Contributor believes its
-Contributions are its original creation(s) or it has sufficient rights
-to grant the rights to its Contributions conveyed by this License.
-
-2.6. Fair Use
-
-This License is not intended to limit any rights You have under
-applicable copyright doctrines of fair use, fair dealing, or other
-equivalents.
-
-2.7. Conditions
-
-Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
-in Section 2.1.
-
-3. Responsibilities
--------------------
-
-3.1. Distribution of Source Form
-
-All distribution of Covered Software in Source Code Form, including any
-Modifications that You create or to which You contribute, must be under
-the terms of this License. You must inform recipients that the Source
-Code Form of the Covered Software is governed by the terms of this
-License, and how they can obtain a copy of this License. You may not
-attempt to alter or restrict the recipients' rights in the Source Code
-Form.
-
-3.2. Distribution of Executable Form
-
-If You distribute Covered Software in Executable Form then:
-
-(a) such Covered Software must also be made available in Source Code
-    Form, as described in Section 3.1, and You must inform recipients of
-    the Executable Form how they can obtain a copy of such Source Code
-    Form by reasonable means in a timely manner, at a charge no more
-    than the cost of distribution to the recipient; and
-
-(b) You may distribute such Executable Form under the terms of this
-    License, or sublicense it under different terms, provided that the
-    license for the Executable Form does not attempt to limit or alter
-    the recipients' rights in the Source Code Form under this License.
-
-3.3. Distribution of a Larger Work
-
-You may create and distribute a Larger Work under terms of Your choice,
-provided that You also comply with the requirements of this License for
-the Covered Software. If the Larger Work is a combination of Covered
-Software with a work governed by one or more Secondary Licenses, and the
-Covered Software is not Incompatible With Secondary Licenses, this
-License permits You to additionally distribute such Covered Software
-under the terms of such Secondary License(s), so that the recipient of
-the Larger Work may, at their option, further distribute the Covered
-Software under the terms of either this License or such Secondary
-License(s).
-
-3.4. Notices
-
-You may not remove or alter the substance of any license notices
-(including copyright notices, patent notices, disclaimers of warranty,
-or limitations of liability) contained within the Source Code Form of
-the Covered Software, except that You may alter any license notices to
-the extent required to remedy known factual inaccuracies.
-
-3.5. Application of Additional Terms
-
-You may choose to offer, and to charge a fee for, warranty, support,
-indemnity or liability obligations to one or more recipients of Covered
-Software. However, You may do so only on Your own behalf, and not on
-behalf of any Contributor. You must make it absolutely clear that any
-such warranty, support, indemnity, or liability obligation is offered by
-You alone, and You hereby agree to indemnify every Contributor for any
-liability incurred by such Contributor as a result of warranty, support,
-indemnity or liability terms You offer. You may include additional
-disclaimers of warranty and limitations of liability specific to any
-jurisdiction.
-
-4. Inability to Comply Due to Statute or Regulation
----------------------------------------------------
-
-If it is impossible for You to comply with any of the terms of this
-License with respect to some or all of the Covered Software due to
-statute, judicial order, or regulation then You must: (a) comply with
-the terms of this License to the maximum extent possible; and (b)
-describe the limitations and the code they affect. Such description must
-be placed in a text file included with all distributions of the Covered
-Software under this License. Except to the extent prohibited by statute
-or regulation, such description must be sufficiently detailed for a
-recipient of ordinary skill to be able to understand it.
-
-5. Termination
---------------
-
-5.1. The rights granted under this License will terminate automatically
-if You fail to comply with any of its terms. However, if You become
-compliant, then the rights granted under this License from a particular
-Contributor are reinstated (a) provisionally, unless and until such
-Contributor explicitly and finally terminates Your grants, and (b) on an
-ongoing basis, if such Contributor fails to notify You of the
-non-compliance by some reasonable means prior to 60 days after You have
-come back into compliance. Moreover, Your grants from a particular
-Contributor are reinstated on an ongoing basis if such Contributor
-notifies You of the non-compliance by some reasonable means, this is the
-first time You have received notice of non-compliance with this License
-from such Contributor, and You become compliant prior to 30 days after
-Your receipt of the notice.
-
-5.2. If You initiate litigation against any entity by asserting a patent
-infringement claim (excluding declaratory judgment actions,
-counter-claims, and cross-claims) alleging that a Contributor Version
-directly or indirectly infringes any patent, then the rights granted to
-You by any and all Contributors for the Covered Software under Section
-2.1 of this License shall terminate.
-
-5.3. In the event of termination under Sections 5.1 or 5.2 above, all
-end user license agreements (excluding distributors and resellers) which
-have been validly granted by You or Your distributors under this License
-prior to termination shall survive termination.
-
-************************************************************************
-*                                                                      *
-*  6. Disclaimer of Warranty                                           *
-*  -------------------------                                           *
-*                                                                      *
-*  Covered Software is provided under this License on an "as is"       *
-*  basis, without warranty of any kind, either expressed, implied, or  *
-*  statutory, including, without limitation, warranties that the       *
-*  Covered Software is free of defects, merchantable, fit for a        *
-*  particular purpose or non-infringing. The entire risk as to the     *
-*  quality and performance of the Covered Software is with You.        *
-*  Should any Covered Software prove defective in any respect, You     *
-*  (not any Contributor) assume the cost of any necessary servicing,   *
-*  repair, or correction. This disclaimer of warranty constitutes an   *
-*  essential part of this License. No use of any Covered Software is   *
-*  authorized under this License except under this disclaimer.         *
-*                                                                      *
-************************************************************************
-
-************************************************************************
-*                                                                      *
-*  7. Limitation of Liability                                          *
-*  --------------------------                                          *
-*                                                                      *
-*  Under no circumstances and under no legal theory, whether tort      *
-*  (including negligence), contract, or otherwise, shall any           *
-*  Contributor, or anyone who distributes Covered Software as          *
-*  permitted above, be liable to You for any direct, indirect,         *
-*  special, incidental, or consequential damages of any character      *
-*  including, without limitation, damages for lost profits, loss of    *
-*  goodwill, work stoppage, computer failure or malfunction, or any    *
-*  and all other commercial damages or losses, even if such party      *
-*  shall have been informed of the possibility of such damages. This   *
-*  limitation of liability shall not apply to liability for death or   *
-*  personal injury resulting from such party's negligence to the       *
-*  extent applicable law prohibits such limitation. Some               *
-*  jurisdictions do not allow the exclusion or limitation of           *
-*  incidental or consequential damages, so this exclusion and          *
-*  limitation may not apply to You.                                    *
-*                                                                      *
-************************************************************************
-
-8. Litigation
--------------
-
-Any litigation relating to this License may be brought only in the
-courts of a jurisdiction where the defendant maintains its principal
-place of business and such litigation shall be governed by laws of that
-jurisdiction, without reference to its conflict-of-law provisions.
-Nothing in this Section shall prevent a party's ability to bring
-cross-claims or counter-claims.
-
-9. Miscellaneous
-----------------
-
-This License represents the complete agreement concerning the subject
-matter hereof. If any provision of this License is held to be
-unenforceable, such provision shall be reformed only to the extent
-necessary to make it enforceable. Any law or regulation which provides
-that the language of a contract shall be construed against the drafter
-shall not be used to construe this License against a Contributor.
-
-10. Versions of the License
----------------------------
-
-10.1. New Versions
-
-Mozilla Foundation is the license steward. Except as provided in Section
-10.3, no one other than the license steward has the right to modify or
-publish new versions of this License. Each version will be given a
-distinguishing version number.
-
-10.2. Effect of New Versions
-
-You may distribute the Covered Software under the terms of the version
-of the License under which You originally received the Covered Software,
-or under the terms of any subsequent version published by the license
-steward.
-
-10.3. Modified Versions
-
-If you create software not governed by this License, and you want to
-create a new license for such software, you may create and use a
-modified version of this License if you rename the license and remove
-any references to the name of the license steward (except to note that
-such modified license differs from this License).
-
-10.4. Distributing Source Code Form that is Incompatible With Secondary
-Licenses
-
-If You choose to distribute Source Code Form that is Incompatible With
-Secondary Licenses under the terms of this version of the License, the
-notice described in Exhibit B of this License must be attached.
-
-Exhibit A - Source Code Form License Notice
--------------------------------------------
-
-  This Source Code Form is subject to the terms of the Mozilla Public
-  License, v. 2.0. If a copy of the MPL was not distributed with this
-  file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-If it is not possible or desirable to put the notice in a particular
-file, then You may include the notice in a location (such as a LICENSE
-file in a relevant directory) where a recipient would be likely to look
-for such a notice.
-
-You may add additional accurate notices of copyright ownership.
-
-Exhibit B - "Incompatible With Secondary Licenses" Notice
----------------------------------------------------------
-
-  This Source Code Form is "Incompatible With Secondary Licenses", as
-  defined by the Mozilla Public License, v. 2.0.
-
-

D mal/Makefile => mal/Makefile +0 -504
@@ 1,504 0,0 @@
-# Usage/help
-all help:
-	@echo
-	@echo 'USAGE:'
-	@echo
-	@echo 'Rules/Targets:'
-	@echo
-	@echo 'make "IMPL"                       # build all steps of IMPL'
-	@echo 'make "IMPL^STEP"                  # build STEP of IMPL'
-	@echo
-	@echo 'make "test"                       # test all implementations'
-	@echo 'make "test^IMPL"                  # test all steps of IMPL'
-	@echo 'make "test^STEP"                  # test STEP for all implementations'
-	@echo 'make "test^IMPL^STEP"             # test STEP of IMPL'
-	@echo
-	@echo 'make "perf"                       # run microbenchmarks for all implementations'
-	@echo 'make "perf^IMPL"                  # run microbenchmarks for IMPL'
-	@echo
-	@echo 'make "repl^IMPL"                  # run stepA of IMPL'
-	@echo 'make "repl^IMPL^STEP"             # test STEP of IMPL'
-	@echo
-	@echo 'make "clean"                      # run 'make clean' for all implementations'
-	@echo 'make "clean^IMPL"                 # run 'make clean' for IMPL'
-	@echo
-	@echo 'make "stats"                      # run 'make stats' for all implementations'
-	@echo 'make "stats-lisp"                 # run 'make stats-lisp' for all implementations'
-	@echo 'make "stats^IMPL"                 # run 'make stats' for IMPL'
-	@echo 'make "stats-lisp^IMPL"            # run 'make stats-lisp' for IMPL'
-	@echo
-	@echo 'Options/Settings:'
-	@echo
-	@echo 'make MAL_IMPL=IMPL "test^mal..."  # use IMPL for self-host tests'
-	@echo 'make REGRESS=1 "test..."          # test with previous step tests too'
-	@echo 'make DOCKERIZE=1 ...              # to dockerize above rules/targets'
-	@echo 'make TEST_OPTS="--opt ..."        # options to pass to runtest.py'
-	@echo
-	@echo 'Other:'
-	@echo
-	@echo 'make "docker-build^IMPL"          # build docker image for IMPL'
-	@echo
-	@echo 'make "docker-shell^IMPL"          # start bash shell in docker image for IMPL'
-	@echo
-
-#
-# Command line settings
-#
-
-MAL_IMPL = js
-
-# cbm or qbasic
-basic_MODE = cbm
-# clj or cljs (Clojure vs ClojureScript/lumo)
-clojure_MODE = clj
-# python, js, cpp, or neko
-haxe_MODE = neko
-# octave or matlab
-matlab_MODE = octave
-# python, python2 or python3
-python_MODE = python
-# scheme (chibi, kawa, gauche, chicken, sagittarius, cyclone, foment)
-scheme_MODE = chibi
-# js wace_libc wace_fooboot
-wasm_MODE = wace_libc
-
-# Path to loccount for counting LOC stats
-LOCCOUNT = loccount
-
-# Extra options to pass to runtest.py
-TEST_OPTS =
-
-# Test with previous test files not just the test files for the
-# current step. Step 0 and 1 tests are special and not included in
-# later steps.
-REGRESS =
-
-DEFERRABLE=1
-OPTIONAL=1
-
-# Run target/rule within docker image for the implementation
-DOCKERIZE =
-
-
-#
-# Implementation specific settings
-#
-
-IMPLS = ada ada.2 awk bash basic c chuck clojure coffee common-lisp cpp crystal cs d dart \
-	elisp elixir elm erlang es6 factor fantom forth fsharp go groovy gnu-smalltalk \
-	guile haskell haxe hy io java js julia kotlin livescript logo lua make mal \
-	matlab miniMAL nasm nim objc objpascal ocaml perl perl6 php picolisp plpgsql \
-	plsql powershell ps python r racket rexx rpython ruby rust scala scheme skew \
-	swift swift3 swift4 tcl ts vb vhdl vimscript wasm yorick
-
-EXTENSION = .mal
-
-step0 = step0_repl
-step1 = step1_read_print
-step2 = step2_eval
-step3 = step3_env
-step4 = step4_if_fn_do
-step5 = step5_tco
-step6 = step6_file
-step7 = step7_quote
-step8 = step8_macros
-step9 = step9_try
-stepA = stepA_mal
-
-argv_STEP = step6_file
-
-
-regress_step0 = step0
-regress_step1 = step1
-regress_step2 = step2
-regress_step3 = $(regress_step2) step3
-regress_step4 = $(regress_step3) step4
-regress_step5 = $(regress_step4) step5
-regress_step6 = $(regress_step5) step6
-regress_step7 = $(regress_step6) step7
-regress_step8 = $(regress_step7) step8
-regress_step9 = $(regress_step8) step9
-regress_stepA = $(regress_step9) stepA
-
-step5_EXCLUDES += bash        # never completes at 10,000
-step5_EXCLUDES += basic       # too slow, and limited to ints of 2^16
-step5_EXCLUDES += logo        # too slow for 10,000
-step5_EXCLUDES += make        # no TCO capability (iteration or recursion)
-step5_EXCLUDES += mal         # host impl dependent
-step5_EXCLUDES += matlab      # never completes at 10,000
-step5_EXCLUDES += plpgsql     # too slow for 10,000
-step5_EXCLUDES += plsql       # too slow for 10,000
-step5_EXCLUDES += powershell  # too slow for 10,000
-step5_EXCLUDES += $(if $(filter cpp,$(haxe_MODE)),haxe,) # cpp finishes 10,000, segfaults at 100,000
-
-dist_EXCLUDES += mal
-# TODO: still need to implement dist
-dist_EXCLUDES += guile io julia matlab swift
-
-
-# Extra options to pass to runtest.py
-logo_TEST_OPTS = --start-timeout 60 --test-timeout 120
-mal_TEST_OPTS = --start-timeout 60 --test-timeout 120
-miniMAL_TEST_OPTS = --start-timeout 60 --test-timeout 120
-perl6_TEST_OPTS = --test-timeout=60
-plpgsql_TEST_OPTS = --start-timeout 60 --test-timeout 180
-plsql_TEST_OPTS = --start-timeout 120 --test-timeout 120
-vimscript_TEST_OPTS = --test-timeout 30
-ifeq ($(MAL_IMPL),vimscript)
-mal_TEST_OPTS = --start-timeout 60 --test-timeout 180
-else ifeq ($(MAL_IMPL),powershell)
-mal_TEST_OPTS = --start-timeout 60 --test-timeout 180
-endif
-
-
-#
-# Implementation specific utility functions
-#
-
-basic_STEP_TO_PROG_cbm    = basic/$($(1)).bas
-basic_STEP_TO_PROG_qbasic = basic/$($(1))
-
-clojure_STEP_TO_PROG_clj  = clojure/target/$($(1)).jar
-clojure_STEP_TO_PROG_cljs = clojure/src/mal/$($(1)).cljc
-
-haxe_STEP_TO_PROG_neko   = haxe/$($(1)).n
-haxe_STEP_TO_PROG_python = haxe/$($(1)).py
-haxe_STEP_TO_PROG_cpp    = haxe/cpp/$($(1))
-haxe_STEP_TO_PROG_js     = haxe/$($(1)).js
-
-scheme_STEP_TO_PROG_chibi       = scheme/$($(1)).scm
-scheme_STEP_TO_PROG_kawa        = scheme/out/$($(1)).class
-scheme_STEP_TO_PROG_gauche      = scheme/$($(1)).scm
-scheme_STEP_TO_PROG_chicken     = scheme/$($(1))
-scheme_STEP_TO_PROG_sagittarius = scheme/$($(1)).scm
-scheme_STEP_TO_PROG_cyclone     = scheme/$($(1))
-scheme_STEP_TO_PROG_foment      = scheme/$($(1)).scm
-
-# Map of step (e.g. "step8") to executable file for that step
-ada_STEP_TO_PROG =     ada/$($(1))
-ada.2_STEP_TO_PROG =   ada.2/$($(1))
-awk_STEP_TO_PROG =     awk/$($(1)).awk
-bash_STEP_TO_PROG =    bash/$($(1)).sh
-basic_STEP_TO_PROG =   $(basic_STEP_TO_PROG_$(basic_MODE))
-c_STEP_TO_PROG =       c/$($(1))
-chuck_STEP_TO_PROG =   chuck/$($(1)).ck
-clojure_STEP_TO_PROG = $(clojure_STEP_TO_PROG_$(clojure_MODE))
-coffee_STEP_TO_PROG =  coffee/$($(1)).coffee
-common-lisp_STEP_TO_PROG =  common-lisp/$($(1))
-cpp_STEP_TO_PROG =     cpp/$($(1))
-crystal_STEP_TO_PROG = crystal/$($(1))
-cs_STEP_TO_PROG =      cs/$($(1)).exe
-d_STEP_TO_PROG =       d/$($(1))
-dart_STEP_TO_PROG =    dart/$($(1)).dart
-elisp_STEP_TO_PROG =   elisp/$($(1)).el
-elixir_STEP_TO_PROG =  elixir/lib/mix/tasks/$($(1)).ex
-elm_STEP_TO_PROG =     elm/$($(1)).js
-erlang_STEP_TO_PROG =  erlang/$($(1))
-es6_STEP_TO_PROG =     es6/$($(1)).mjs
-factor_STEP_TO_PROG =  factor/$($(1))/$($(1)).factor
-fantom_STEP_TO_PROG =  fantom/lib/fan/$($(1)).pod
-forth_STEP_TO_PROG =   forth/$($(1)).fs
-fsharp_STEP_TO_PROG =  fsharp/$($(1)).exe
-go_STEP_TO_PROG =      go/$($(1))
-groovy_STEP_TO_PROG =  groovy/$($(1)).groovy
-gnu-smalltalk_STEP_TO_PROG = gnu-smalltalk/$($(1)).st
-guile_STEP_TO_PROG =   guile/$($(1)).scm
-haskell_STEP_TO_PROG = haskell/$($(1))
-haxe_STEP_TO_PROG =    $(haxe_STEP_TO_PROG_$(haxe_MODE))
-hy_STEP_TO_PROG =      hy/$($(1)).hy
-io_STEP_TO_PROG =      io/$($(1)).io
-java_STEP_TO_PROG =    java/target/classes/mal/$($(1)).class
-js_STEP_TO_PROG =      js/$($(1)).js
-julia_STEP_TO_PROG =   julia/$($(1)).jl
-kotlin_STEP_TO_PROG =  kotlin/$($(1)).jar
-livescript_STEP_TO_PROG = livescript/$($(1)).js
-logo_STEP_TO_PROG =    logo/$($(1)).lg
-lua_STEP_TO_PROG =     lua/$($(1)).lua
-make_STEP_TO_PROG =    make/$($(1)).mk
-mal_STEP_TO_PROG =     mal/$($(1)).mal
-matlab_STEP_TO_PROG =  matlab/$($(1)).m
-miniMAL_STEP_TO_PROG = miniMAL/$($(1)).json
-nasm_STEP_TO_PROG =    nasm/$($(1))
-nim_STEP_TO_PROG =     nim/$($(1))
-objc_STEP_TO_PROG =    objc/$($(1))
-objpascal_STEP_TO_PROG = objpascal/$($(1))
-ocaml_STEP_TO_PROG =   ocaml/$($(1))
-perl_STEP_TO_PROG =    perl/$($(1)).pl
-perl6_STEP_TO_PROG =   perl6/$($(1)).pl
-php_STEP_TO_PROG =     php/$($(1)).php
-picolisp_STEP_TO_PROG = picolisp/$($(1)).l
-plpgsql_STEP_TO_PROG = plpgsql/$($(1)).sql
-plsql_STEP_TO_PROG =   plsql/$($(1)).sql
-powershell_STEP_TO_PROG =  powershell/$($(1)).ps1
-ps_STEP_TO_PROG =      ps/$($(1)).ps
-python_STEP_TO_PROG =  python/$($(1)).py
-r_STEP_TO_PROG =       r/$($(1)).r
-racket_STEP_TO_PROG =  racket/$($(1)).rkt
-rexx_STEP_TO_PROG =    rexx/$($(1)).rexxpp
-rpython_STEP_TO_PROG = rpython/$($(1))
-ruby_STEP_TO_PROG =    ruby/$($(1)).rb
-rust_STEP_TO_PROG =    rust/$($(1))
-scala_STEP_TO_PROG =   scala/target/scala-2.11/classes/$($(1)).class
-scheme_STEP_TO_PROG =  $(scheme_STEP_TO_PROG_$(scheme_MODE))
-skew_STEP_TO_PROG =    skew/$($(1)).js
-swift_STEP_TO_PROG =   swift/$($(1))
-swift3_STEP_TO_PROG =  swift3/$($(1))
-swift4_STEP_TO_PROG =  swift4/$($(1))
-tcl_STEP_TO_PROG =     tcl/$($(1)).tcl
-ts_STEP_TO_PROG =      ts/$($(1)).js
-vb_STEP_TO_PROG =      vb/$($(1)).exe
-vhdl_STEP_TO_PROG =    vhdl/$($(1))
-vimscript_STEP_TO_PROG = vimscript/$($(1)).vim
-wasm_STEP_TO_PROG =    wasm/$($(1)).wasm
-yorick_STEP_TO_PROG =  yorick/$($(1)).i
-
-
-#
-# General settings and utility functions
-#
-
-# Needed some argument munging
-COMMA = ,
-noop =
-SPACE = $(noop) $(noop)
-export FACTOR_ROOTS := .
-
-opt_DEFERRABLE      = $(if $(strip $(DEFERRABLE)),$(if $(filter t true T True TRUE 1 y yes Yes YES,$(DEFERRABLE)),--deferrable,--no-deferrable),--no-deferrable)
-opt_OPTIONAL        = $(if $(strip $(OPTIONAL)),$(if $(filter t true T True TRUE 1 y yes Yes YES,$(OPTIONAL)),--optional,--no-optional),--no-optional)
-
-# Return list of test files for a given step. If REGRESS is set then
-# test files will include step 2 tests through tests for the step
-# being tested.
-STEP_TEST_FILES = $(strip $(wildcard \
-		    $(foreach s,$(if $(strip $(REGRESS)),\
-			$(filter-out $(if $(filter $(1),$(step5_EXCLUDES)),step5,),\
-			  $(regress_$(2)))\
-			,$(2)),\
-		      $(1)/tests/$($(s))$(EXTENSION) tests/$($(s))$(EXTENSION))))
-
-# DOCKERIZE utility functions
-lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$1))))))))))))))))))))))))))
-impl_to_image = kanaka/mal-test-$(call lc,$(1))
-
-actual_impl = $(if $(filter mal,$(1)),$(MAL_IMPL),$(1))
-
-# Takes impl
-# Returns nothing if DOCKERIZE is not set, otherwise returns the
-# docker prefix necessary to run make within the docker environment
-# for this impl
-get_build_command = $(strip $(if $(strip $(DOCKERIZE)),\
-    docker run \
-    -it --rm -u $(shell id -u) \
-    -v $(dir $(abspath $(lastword $(MAKEFILE_LIST)))):/mal \
-    -w /mal/$(1) \
-    $(if $(strip $($(1)_MODE)),-e $(1)_MODE=$($(1)_MODE),) \
-    $(if $(filter factor,$(1)),-e FACTOR_ROOTS=$(FACTOR_ROOTS),) \
-    $(call impl_to_image,$(1)) \
-    $(MAKE) $(if $(strip $($(1)_MODE)),$(1)_MODE=$($(1)_MODE),) \
-    ,\
-    $(MAKE) $(if $(strip $($(1)_MODE)),$(1)_MODE=$($(1)_MODE),)))
-
-# Takes impl and step args. Optional env vars and dockerize args
-# Returns a command prefix (docker command and environment variables)
-# necessary to launch the given impl and step
-get_run_prefix = $(strip $(if $(strip $(DOCKERIZE) $(4)),\
-    docker run -e STEP=$($2) -e MAL_IMPL=$(MAL_IMPL) \
-    -it --rm -u $(shell id -u) \
-    -v $(dir $(abspath $(lastword $(MAKEFILE_LIST)))):/mal \
-    -w /mal/$(call actual_impl,$(1)) \
-    $(if $(strip $($(1)_MODE)),-e $(1)_MODE=$($(1)_MODE),) \
-    $(if $(filter factor,$(1)),-e FACTOR_ROOTS=$(FACTOR_ROOTS),) \
-    $(foreach env,$(3),-e $(env)) \
-    $(call impl_to_image,$(call actual_impl,$(1))) \
-    ,\
-    env STEP=$($2) MAL_IMPL=$(MAL_IMPL) \
-    $(if $(strip $($(1)_MODE)),$(1)_MODE=$($(1)_MODE),) \
-    $(if $(filter factor,$(1)),FACTOR_ROOTS=$(FACTOR_ROOTS),) \
-    $(3)))
-
-# Takes impl and step
-# Returns the runtest command prefix (with runtest options) for testing the given step
-get_runtest_cmd = $(call get_run_prefix,$(1),$(2),$(if $(filter cs fsharp tcl vb,$(1)),RAW=1,)) \
-		    ../runtest.py $(opt_DEFERRABLE) $(opt_OPTIONAL) $(call $(1)_TEST_OPTS) $(TEST_OPTS)
-
-# Takes impl and step
-# Returns the runtest command prefix (with runtest options) for testing the given step
-get_argvtest_cmd = $(call get_run_prefix,$(1),$(2)) ../run_argv_test.sh
-
-# Derived lists
-STEPS = $(sort $(filter-out %_EXCLUDES,$(filter step%,$(.VARIABLES))))
-DO_IMPLS = $(filter-out $(SKIP_IMPLS),$(IMPLS))
-IMPL_TESTS = $(foreach impl,$(DO_IMPLS),test^$(impl))
-STEP_TESTS = $(foreach step,$(STEPS),test^$(step))
-ALL_TESTS = $(filter-out $(foreach e,$(step5_EXCLUDES),test^$(e)^step5),\
-              $(strip $(sort \
-                $(foreach impl,$(DO_IMPLS),\
-                  $(foreach step,$(STEPS),test^$(impl)^$(step))))))
-
-DOCKER_BUILD = $(foreach impl,$(DO_IMPLS),docker-build^$(impl))
-
-DOCKER_SHELL = $(foreach impl,$(DO_IMPLS),docker-shell^$(impl))
-
-IMPL_PERF = $(foreach impl,$(filter-out $(perf_EXCLUDES),$(DO_IMPLS)),perf^$(impl))
-
-IMPL_STATS = $(foreach impl,$(DO_IMPLS),stats^$(impl))
-
-IMPL_REPL = $(foreach impl,$(DO_IMPLS),repl^$(impl))
-ALL_REPL = $(strip $(sort \
-             $(foreach impl,$(DO_IMPLS),\
-               $(foreach step,$(STEPS),repl^$(impl)^$(step)))))
-
-
-#
-# Build rules
-#
-
-# Enable secondary expansion for all rules
-.SECONDEXPANSION:
-
-# Build a program in an implementation directory
-# Make sure we always try and build first because the dependencies are
-# encoded in the implementation Makefile not here
-.PHONY: $(foreach i,$(DO_IMPLS),$(foreach s,$(STEPS),$(call $(i)_STEP_TO_PROG,$(s))))
-$(foreach i,$(DO_IMPLS),$(foreach s,$(STEPS),$(call $(i)_STEP_TO_PROG,$(s)))):
-	$(foreach impl,$(word 1,$(subst /, ,$(@))),\
-	  $(if $(DOCKERIZE), \
-	    $(call get_build_command,$(impl)) $(patsubst $(impl)/%,%,$(@)), \
-	    $(call get_build_command,$(impl)) -C $(impl) $(subst $(impl)/,,$(@))))
-
-# Allow IMPL, and IMPL^STEP
-$(DO_IMPLS): $$(foreach s,$$(STEPS),$$(call $$(@)_STEP_TO_PROG,$$(s)))
-
-$(foreach i,$(DO_IMPLS),$(foreach s,$(STEPS),$(i)^$(s))): $$(call $$(word 1,$$(subst ^, ,$$(@)))_STEP_TO_PROG,$$(word 2,$$(subst ^, ,$$(@))))
-
-
-#
-# Test rules
-#
-
-$(ALL_TESTS): $$(call $$(word 2,$$(subst ^, ,$$(@)))_STEP_TO_PROG,$$(word 3,$$(subst ^, ,$$(@))))
-	@$(foreach impl,$(word 2,$(subst ^, ,$(@))),\
-	  $(foreach step,$(word 3,$(subst ^, ,$(@))),\
-	    cd $(if $(filter mal,$(impl)),$(MAL_IMPL),$(impl)) && \
-	    $(foreach test,$(call STEP_TEST_FILES,$(impl),$(step)),\
-	      echo '----------------------------------------------' && \
-	      echo 'Testing $@; step file: $+, test file: $(test)' && \
-	      echo 'Running: $(call get_runtest_cmd,$(impl),$(step)) ../$(test) -- ../$(impl)/run' && \
-	      $(call get_runtest_cmd,$(impl),$(step)) ../$(test) -- ../$(impl)/run && \
-	      $(if $(filter tests/$(argv_STEP)$(EXTENSION),$(test)),\
-	        echo '----------------------------------------------' && \
-	        echo 'Testing ARGV of $@; step file: $+' && \
-	        echo 'Running: $(call get_argvtest_cmd,$(impl),$(step)) ../$(impl)/run ' && \
-	        $(call get_argvtest_cmd,$(impl),$(step)) ../$(impl)/run  && ,\
-		true && ))\
-	    true))
-
-# Allow test, tests, test^STEP, test^IMPL, and test^IMPL^STEP
-test: $(ALL_TESTS)
-tests: $(ALL_TESTS)
-
-$(IMPL_TESTS): $$(filter $$@^%,$$(ALL_TESTS))
-
-$(STEP_TESTS): $$(foreach step,$$(subst test^,,$$@),$$(filter %^$$(step),$$(ALL_TESTS)))
-
-
-#
-# Docker build rules
-#
-
-docker-build: $(DOCKER_BUILD)
-
-$(DOCKER_BUILD):
-	@echo "----------------------------------------------"; \
-	$(foreach impl,$(word 2,$(subst ^, ,$(@))),\
-	  echo "Running: docker build -t $(call impl_to_image,$(impl)) .:"; \
-	  cd $(impl) && docker build -t $(call impl_to_image,$(impl)) .)
-
-#
-# Docker shell rules
-#
-
-$(DOCKER_SHELL):
-	@echo "----------------------------------------------"; \
-	$(foreach impl,$(word 2,$(subst ^, ,$(@))),\
-	  echo "Running: $(call get_run_prefix,$(impl),stepA,,dockerize) bash"; \
-	  $(call get_run_prefix,$(impl),stepA,,dockerize) bash)
-
-
-#
-# Performance test rules
-#
-
-perf: $(IMPL_PERF)
-
-$(IMPL_PERF):
-	@echo "----------------------------------------------"; \
-	$(foreach impl,$(word 2,$(subst ^, ,$(@))),\
-	  cd $(if $(filter mal,$(impl)),$(MAL_IMPL),$(impl)); \
-	  echo "Performance test for $(impl):"; \
-	  echo 'Running: $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf1.mal'; \
-	  $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf1.mal; \
-	  echo 'Running: $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf2.mal'; \
-	  $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf2.mal; \
-	  echo 'Running: $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf3.mal'; \
-	  $(call get_run_prefix,$(impl),stepA) ../$(impl)/run ../tests/perf3.mal)
-
-
-#
-# REPL invocation rules
-#
-
-$(ALL_REPL): $$(call $$(word 2,$$(subst ^, ,$$(@)))_STEP_TO_PROG,$$(word 3,$$(subst ^, ,$$(@))))
-	@$(foreach impl,$(word 2,$(subst ^, ,$(@))),\
-	  $(foreach step,$(word 3,$(subst ^, ,$(@))),\
-	    cd $(if $(filter mal,$(impl)),$(MAL_IMPL),$(impl)); \
-	    echo 'REPL implementation $(impl), step file: $+'; \
-	    echo 'Running: $(call get_run_prefix,$(impl),$(step)) ../$(impl)/run $(RUN_ARGS)'; \
-	    $(call get_run_prefix,$(impl),$(step)) ../$(impl)/run $(RUN_ARGS);))
-
-# Allow repl^IMPL^STEP and repl^IMPL (which starts REPL of stepA)
-$(IMPL_REPL): $$@^stepA
-
-#
-# Stats test rules
-#
-
-# For a concise summary:
-#   make stats | egrep -A1 "^Stats for|^all" | egrep -v "^all|^--"
-stats: $(IMPL_STATS)
-
-$(IMPL_STATS):
-	@$(foreach impl,$(word 2,$(subst ^, ,$(@))),\
-	  echo "Stats for $(impl):"; \
-	  $(LOCCOUNT) -x "Makefile|node_modules" $(impl))
-
-#
-# Utility functions
-#
-print-%:
-	@echo "$($(*))"
-
-#
-# Recursive rules (call make FOO in each subdirectory)
-#
-
-define recur_template
-.PHONY: $(1)
-$(1): $(2)
-$(2):
-	@echo "----------------------------------------------"; \
-	$$(foreach impl,$$(word 2,$$(subst ^, ,$$(@))),\
-	  $$(if $$(DOCKERIZE), \
-	    echo "Running: $$(call get_build_command,$$(impl)) --no-print-directory $(1)"; \
-	    $$(call get_build_command,$$(impl)) --no-print-directory $(1), \
-	    echo "Running: $$(call get_build_command,$$(impl)) --no-print-directory -C $$(impl) $(1)"; \
-	    $$(call get_build_command,$$(impl)) --no-print-directory -C $$(impl) $(1)))
-endef
-
-recur_impls_ = $(filter-out $(foreach impl,$($(1)_EXCLUDES),$(1)^$(impl)),$(foreach impl,$(IMPLS),$(1)^$(impl)))
-
-# recursive clean
-$(eval $(call recur_template,clean,$(call recur_impls_,clean)))
-
-# recursive dist
-$(eval $(call recur_template,dist,$(call recur_impls_,dist)))

D mal/README.md => mal/README.md +0 -1232
@@ 1,1232 0,0 @@
-# mal - Make a Lisp
-
-[![Build Status](https://travis-ci.org/kanaka/mal.svg?branch=master)](https://travis-ci.org/kanaka/mal)
-
-## Description
-
-**1. Mal is a Clojure inspired Lisp interpreter**
-
-**2. Mal is implemented in 75 languages (76 implementations total)**
-
-| Language | Creator |
-| -------- | ------- |
-| [Ada](#ada) | [Chris Moore](https://github.com/zmower) |
-| [Ada #2](#ada2) | [Nicolas Boulenguez](https://github.com/asarhaddon) |
-| [GNU Awk](#gnu-awk) | [Miutsuru Kariya](https://github.com/kariya-mitsuru) |
-| [Bash 4](#bash-4) | [Joel Martin](https://github.com/kanaka)  |
-| [BASIC](#basic-c64-and-qbasic) (C64 &amp; QBasic) | [Joel Martin](https://github.com/kanaka) |
-| [C](#c) | [Joel Martin](https://github.com/kanaka)  |
-| [C++](#c-1) | [Stephen Thirlwall](https://github.com/sdt) |
-| [C#](#c-2) | [Joel Martin](https://github.com/kanaka)  |
-| [ChucK](#chuck) | [Vasilij Schneidermann](https://github.com/wasamasa) |
-| [Clojure](#clojure) (Clojure &amp; ClojureScript) | [Joel Martin](https://github.com/kanaka) |
-| [CoffeeScript](#coffeescript) | [Joel Martin](https://github.com/kanaka)  |
-| [Common Lisp](#common-lisp) | [Iqbal Ansari](https://github.com/iqbalansari) |
-| [Crystal](#crystal) | [Linda_pp](https://github.com/rhysd) |
-| [D](#d) | [Dov Murik](https://github.com/dubek) |
-| [Dart](#dart) | [Harry Terkelsen](https://github.com/hterkelsen) |
-| [Elixir](#elixir) | [Martin Ek](https://github.com/ekmartin) |
-| [Elm](#elm) | [Jos van Bakel](https://github.com/c0deaddict) |
-| [Emacs Lisp](#emacs-lisp) | [Vasilij Schneidermann](https://github.com/wasamasa) |
-| [Erlang](#erlang) | [Nathan Fiedler](https://github.com/nlfiedler) |
-| [ES6](#es6-ecmascript-2015) (ECMAScript 2015) | [Joel Martin](https://github.com/kanaka) |
-| [F#](#f) | [Peter Stephens](https://github.com/pstephens) |
-| [Factor](#factor) | [Jordan Lewis](https://github.com/jordanlewis) |
-| [Fantom](#fantom) | [Dov Murik](https://github.com/dubek) |
-| [Forth](#forth) | [Chris Houser](https://github.com/chouser) |
-| [GNU Guile](#gnu-guile-21) | [Mu Lei](https://github.com/NalaGinrut) |
-| [GNU Smalltalk](#gnu-smalltalk) | [Vasilij Schneidermann](https://github.com/wasamasa) |
-| [Go](#go) | [Joel Martin](https://github.com/kanaka)  |
-| [Groovy](#groovy) | [Joel Martin](https://github.com/kanaka)  |
-| [Haskell](#haskell) | [Joel Martin](https://github.com/kanaka)  |
-| [Haxe](#haxe-neko-python-c-and-javascript) (Neko, Python, C++, &amp; JS) | [Joel Martin](https://github.com/kanaka) |
-| [Hy](#hy) | [Joel Martin](https://github.com/kanaka)  |
-| [Io](#io) | [Dov Murik](https://github.com/dubek) |
-| [Java](#java-17) | [Joel Martin](https://github.com/kanaka)  |
-| [JavaScript](#javascriptnode) ([Demo](http://kanaka.github.io/mal)) | [Joel Martin](https://github.com/kanaka) |
-| [Julia](#julia) | [Joel Martin](https://github.com/kanaka)  |
-| [Kotlin](#kotlin) | [Javier Fernandez-Ivern](https://github.com/ivern) |
-| [LiveScript](#livescript) | [Jos van Bakel](https://github.com/c0deaddict) |
-| [Logo](#logo) | [Dov Murik](https://github.com/dubek) |
-| [Lua](#lua) | [Joel Martin](https://github.com/kanaka)  |
-| [GNU Make](#gnu-make-381) | [Joel Martin](https://github.com/kanaka)  |
-| [mal itself](#mal) | [Joel Martin](https://github.com/kanaka)  |
-| [MATLAB](#matlab-gnu-octave-and-matlab) (GNU Octave &amp; MATLAB) | [Joel Martin](https://github.com/kanaka) |
-| [miniMAL](#minimal) ([Repo](https://github.com/kanaka/miniMAL), [Demo](https://kanaka.github.io/miniMAL/)) | [Joel Martin](https://github.com/kanaka) |
-| [NASM](#nasm) | [Ben Dudson](https://github.com/bendudson) |
-| [Nim](#nim-0170) | [Dennis Felsing](https://github.com/def-) |
-| [Object Pascal](#object-pascal) | [Joel Martin](https://github.com/kanaka)  |
-| [Objective C](#objective-c) | [Joel Martin](https://github.com/kanaka)  |
-| [OCaml](#ocaml-4010) | [Chris Houser](https://github.com/chouser) |
-| [Perl](#perl-58) | [Joel Martin](https://github.com/kanaka)  |
-| [Perl 6](#perl-6) | [Hinrik Örn Sigurðsson](https://github.com/hinrik) |
-| [PHP](#php-53) | [Joel Martin](https://github.com/kanaka)  |
-| [Picolisp](#picolisp) | [Vasilij Schneidermann](https://github.com/wasamasa) |
-| [PL/pgSQL](#plpgsql-postgres-sql-procedural-language) (Postgres) | [Joel Martin](https://github.com/kanaka) |
-| [PL/SQL](#plsql-oracle-sql-procedural-language) (Oracle) | [Joel Martin](https://github.com/kanaka) |
-| [PostScript](#postscript-level-23) | [Joel Martin](https://github.com/kanaka)  |
-| [PowerShell](#powershell) | [Joel Martin](https://github.com/kanaka)  |
-| [Python](#python-2x-and-3x) (2.X &amp; 3.X) | [Joel Martin](https://github.com/kanaka) |
-| [RPython](#rpython) | [Joel Martin](https://github.com/kanaka)  |
-| [R](#r) | [Joel Martin](https://github.com/kanaka)  |
-| [Racket](#racket-53) | [Joel Martin](https://github.com/kanaka)  |
-| [Rexx](#rexx) | [Dov Murik](https://github.com/dubek) |
-| [Ruby](#ruby-19) | [Joel Martin](https://github.com/kanaka)  |
-| [Rust](#rust-100-nightly) | [Joel Martin](https://github.com/kanaka)  |
-| [Scala](#scala) | [Joel Martin](https://github.com/kanaka)  |
-| [Scheme (R7RS)](#scheme-r7rs) | [Vasilij Schneidermann](https://github.com/wasamasa) |
-| [Skew](#skew) | [Dov Murik](https://github.com/dubek) |
-| [Swift 2](#swift) | [Keith Rollin](https://github.com/keith-rollin) |
-| [Swift 3](#swift-3) | [Joel Martin](https://github.com/kanaka)  |
-| [Swift 4](#swift-4) | [陆遥](https://github.com/LispLY)  |
-| [Tcl](#tcl-86) | [Dov Murik](https://github.com/dubek) |
-| [TypeScript](#typescript) | [Masahiro Wakame](https://github.com/vvakame) |
-| [VHDL](#vhdl) | [Dov Murik](https://github.com/dubek) |
-| [Vimscript](#vimscript) | [Dov Murik](https://github.com/dubek) |
-| [Visual Basic.NET](#visual-basicnet) | [Joel Martin](https://github.com/kanaka)  |
-| [WebAssembly](#webassembly-wasm) (wasm) | [Joel Martin](https://github.com/kanaka) |
-| [Yorick](#yorick) | [Dov Murik](https://github.com/dubek) |
-
-
-**3. Mal is a learning tool**
-
-Each implementation of mal is separated into
-11 incremental, self-contained (and testable) steps that demonstrate
-core concepts of Lisp. The last step is capable of self-hosting
-(running the mal implementation of mal). See the [make-a-lisp process
-guide](process/guide.md). 
-
-The make-a-lisp steps are:
-
-* [step0_repl](process/guide.md#step0)
-* [step1_read_print](process/guide.md#step1)
-* [step2_eval](process/guide.md#step2)
-* [step3_env](process/guide.md#step3)
-* [step4_if_fn_do](process/guide.md#step4)
-* [step5_tco](process/guide.md#step5)
-* [step6_file](process/guide.md#step6)
-* [step7_quote](process/guide.md#step7)
-* [step8_macros](process/guide.md#step8)
-* [step9_try](process/guide.md#step9)
-* [stepA_mal](process/guide.md#stepA)
-
-Each make-a-lisp step has an associated architectural diagram. That elements
-that are new for that step are highlighted in red.
-Here is the final diagram for [step A](process/guide.md#stepA):
-
-![stepA_mal architecture](process/stepA_mal.png)
-
-If you are interesting in creating a mal implementation (or just
-interested in using mal for something), please drop by the #mal
-channel on freenode. In addition to the [make-a-lisp process
-guide](process/guide.md) there is also a [mal/make-a-lisp
-FAQ](docs/FAQ.md) where I attempt to answer some common questions.
-
-
-## Presentations
-
-Mal was presented publicly for the first time in a lightning talk at
-Clojure West 2014 (unfortunately there is no video). See
-examples/clojurewest2014.mal for the presentation that was given at the
-conference (yes, the presentation is a mal program).
-
-At Midwest.io 2015, Joel Martin gave a presentation on Mal titled
-"Achievement Unlocked: A Better Path to Language Learning".
-[Video](https://www.youtube.com/watch?v=lgyOAiRtZGw),
-[Slides](http://kanaka.github.io/midwest.io.mal/).
-
-More recently Joel gave a presentation on "Make Your Own Lisp Interpreter
-in 10 Incremental Steps" at LambdaConf 2016:
-[Part 1](https://www.youtube.com/watch?v=jVhupfthTEk),
-[Part 2](https://www.youtube.com/watch?v=X5OQBMGpaTU),
-[Part 3](https://www.youtube.com/watch?v=6mARZzGgX4U),
-[Part 4](https://www.youtube.com/watch?v=dCO1SYR5kDU),
-[Slides](http://kanaka.github.io/lambdaconf/).
-
-## Building/running implementations
-
-The simplest way to run any given implementation is to use docker.
-Every implementation has a docker image pre-built with language
-dependencies installed. You can launch the REPL using a convenient
-target in the top level Makefile (where IMPL is the implementation
-directory name and stepX is the step to run):
-
-```
-make DOCKERIZE=1 "repl^IMPL^stepX"
-    # OR stepA is the default step:
-make DOCKERIZE=1 "repl^IMPL"
-```
-
-
-### Ada
-
-The Ada implementation was developed with GNAT 4.9 on debian. It also
-compiles unchanged on windows if you have windows versions of git,
-GNAT and (optionally) make.  There are no external dependencies
-(readline not implemented).
-
-```
-cd ada
-make
-./stepX_YYY
-```
-
-### Ada.2
-
-The second Ada implementation was developed with GNAT 8 and links with
-the GNU readline library.
-
-```
-cd ada
-make
-./stepX_YYY
-```
-
-### GNU awk
-
-The GNU awk implementation of mal has been tested with GNU awk 4.1.1.
-
-```
-cd gawk
-gawk -O -f stepX_YYY.awk
-```
-
-### Bash 4
-
-```
-cd bash
-bash stepX_YYY.sh
-```
-
-### BASIC (C64 and QBasic)
-
-The BASIC implementation uses a preprocessor that can generate BASIC
-code that is compatible with both C64 BASIC (CBM v2) and QBasic. The
-C64 mode has been tested with
-[cbmbasic](https://github.com/kanaka/cbmbasic) (the patched version is
-currently required to fix issues with line input) and the QBasic mode
-has been tested with [qb64](http://www.qb64.net/).
-
-Generate C64 code and run it using cbmbasic:
-
-```
-cd basic
-make stepX_YYY.bas
-STEP=stepX_YYY ./run
-```
-
-Generate QBasic code and load it into qb64:
-
-```
-cd basic
-make MODE=qbasic stepX_YYY.bas
-./qb64 stepX_YYY.bas
-```
-
-Thanks to [Steven Syrek](https://github.com/sjsyrek) for the original
-inspiration for this implementation.
-
-
-### C
-
-The C implementation of mal requires the following libraries (lib and
-header packages): glib, libffi6, libgc, and either the libedit or GNU readline
-library.
-
-```
-cd c
-make
-./stepX_YYY
-```
-
-### C++
-
-The C++ implementation of mal requires g++-4.9 or clang++-3.5 and
-a readline compatible library to build. See the `cpp/README.md` for
-more details:
-
-```
-cd cpp
-make
-    # OR
-make CXX=clang++-3.5
-./stepX_YYY
-```
-
-
-### C# ###
-
-The C# implementation of mal has been tested on Linux using the Mono
-C# compiler (mcs) and the Mono runtime (version 2.10.8.1). Both are
-required to build and run the C# implementation.
-
-```
-cd cs
-make
-mono ./stepX_YYY.exe
-```
-
-### ChucK
-
-The ChucK implementation has been tested with ChucK 1.3.5.2.
-
-```
-cd chuck
-./run
-```
-
-### Clojure
-
-For the most part the Clojure implementation requires Clojure 1.5,
-however, to pass all tests, Clojure 1.8.0-RC4 is required.
-
-```
-cd clojure
-lein with-profile +stepX trampoline run
-```
-
-### CoffeeScript
-
-```
-sudo npm install -g coffee-script
-cd coffee
-coffee ./stepX_YYY
-```
-
-### Common Lisp
-
-The implementation has been tested with SBCL, CCL, CMUCL, GNU CLISP, ECL and
-Allegro CL on Ubuntu 16.04 and Ubuntu 12.04, see
-the [README](common-lisp/README.org) for more details. Provided you have the
-dependencies mentioned installed, do the following to run the implementation
-
-```
-cd common-lisp
-make
-./run
-```
-
-### Crystal
-
-The Crystal implementation of mal has been tested with Crystal 0.26.1.
-
-```
-cd crystal
-crystal run ./stepX_YYY.cr
-    # OR
-make   # needed to run tests
-./stepX_YYY
-```
-
-### D
-
-The D implementation of mal was tested with GDC 4.8.  It requires the GNU
-readline library.
-
-```
-cd d
-make
-./stepX_YYY
-```
-
-### Dart
-
-The Dart implementation has been tested with Dart 1.20.
-
-```
-cd dart
-dart ./stepX_YYY
-```
-
-### Emacs Lisp
-
-The Emacs Lisp implementation of mal has been tested with Emacs 24.3
-and 24.5.  While there is very basic readline editing (`<backspace>`
-and `C-d` work, `C-c` cancels the process), it is recommended to use
-`rlwrap`.
-
-```
-cd elisp
-emacs -Q --batch --load stepX_YYY.el
-# with full readline support
-rlwrap emacs -Q --batch --load stepX_YYY.el
-```
-
-### Elixir
-
-The Elixir implementation of mal has been tested with Elixir 1.0.5.
-
-```
-cd elixir
-mix stepX_YYY
-# Or with readline/line editing functionality:
-iex -S mix stepX_YYY
-```
-
-### Elm
-
-The Elm implementation of mal has been tested with Elm 0.18.0
-
-```
-cd elm
-make stepX_YYY.js
-STEP=stepX_YYY ./run
-```
-
-### Erlang
-
-The Erlang implementation of mal requires [Erlang/OTP R17](http://www.erlang.org/download.html)
-and [rebar](https://github.com/rebar/rebar) to build.
-
-```
-cd erlang
-make
-    # OR
-MAL_STEP=stepX_YYY rebar compile escriptize # build individual step
-./stepX_YYY
-```
-
-### ES6 (ECMAScript 2015)
-
-The ES6 / ECMAScript 2015 implementation uses the
-[babel](https://babeljs.io) compiler to generate ES5 compatible
-JavaScript. The generated code has been tested with Node 0.12.4.
-
-```
-cd es6
-make
-node build/stepX_YYY.js
-```
-
-
-### F# ###
-
-The F# implementation of mal has been tested on Linux using the Mono
-F# compiler (fsharpc) and the Mono runtime (version 3.12.1). The mono C#
-compiler (mcs) is also necessary to compile the readline dependency. All are
-required to build and run the F# implementation.
-
-```
-cd fsharp
-make
-mono ./stepX_YYY.exe
-```
-
-### Factor
-
-The Factor implementation of mal has been tested with Factor 0.97
-([factorcode.org](http://factorcode.org)).
-
-```
-cd factor
-FACTOR_ROOTS=. factor -run=stepX_YYY
-```
-
-### Fantom
-
-The Fantom implementation of mal has been tested with Fantom 1.0.70.
-
-```
-cd fantom
-make lib/fan/stepX_YYY.pod
-STEP=stepX_YYY ./run
-```
-
-### Forth
-
-```
-cd forth
-gforth stepX_YYY.fs
-```
-
-### GNU Guile 2.1+
-
-```
-cd guile
-guile -L ./ stepX_YYY.scm
-```
-
-### GNU Smalltalk
-
-The Smalltalk implementation of mal has been tested with GNU Smalltalk 3.2.91.
-
-```
-cd gnu-smalltalk
-./run
-```
-
-### Go
-
-The Go implementation of mal requires that go is installed on on the
-path. The implementation has been tested with Go 1.3.1.
-
-```
-cd go
-make
-./stepX_YYY
-```
-
-
-### Groovy
-
-The Groovy implementation of mal requires Groovy to run and has been
-tested with Groovy 1.8.6.
-
-```
-cd groovy
-make
-groovy ./stepX_YYY.groovy
-```
-
-### Haskell
-
-The Haskell implementation requires the ghc compiler version 7.10.1 or
-later and also the Haskell parsec and readline (or editline) packages.
-
-```
-cd haskell
-make
-./stepX_YYY
-```
-
-### Haxe (Neko, Python, C++ and JavaScript)
-
-The Haxe implementation of mal requires Haxe version 3.2 to compile.
-Four different Haxe targets are supported: Neko, Python, C++, and
-JavaScript.
-
-```
-cd haxe
-# Neko
-make all-neko
-neko ./stepX_YYY.n
-# Python
-make all-python
-python3 ./stepX_YYY.py
-# C++
-make all-cpp
-./cpp/stepX_YYY
-# JavaScript
-make all-js
-node ./stepX_YYY.js
-```
-
-### Hy
-
-The Hy implementation of mal has been tested with Hy 0.13.0.
-
-```
-cd hy
-./stepX_YYY.hy
-```
-
-### Io
-
-The Io implementation of mal has been tested with Io version 20110905.
-
-```
-cd io
-io ./stepX_YYY.io
-```
-
-### Java 1.7
-
-The Java implementation of mal requires maven2 to build.
-
-```
-cd java
-mvn compile
-mvn -quiet exec:java -Dexec.mainClass=mal.stepX_YYY
-    # OR
-mvn -quiet exec:java -Dexec.mainClass=mal.stepX_YYY -Dexec.args="CMDLINE_ARGS"
-```
-
-### JavaScript/Node
-
-```
-cd js
-npm update
-node stepX_YYY.js
-```
-
-### Julia
-
-The Julia implementation of mal requires Julia 0.4.
-
-```
-cd julia
-julia stepX_YYY.jl
-```
-
-### Kotlin
-
-The Kotlin implementation of mal has been tested with Kotlin 1.0.
-
-```
-cd kotlin
-make
-java -jar stepX_YYY.jar
-```
-
-### LiveScript
-
-The LiveScript implementation of mal has been tested with LiveScript 1.5.
-
-```
-cd livescript
-make
-node_modules/.bin/lsc stepX_YYY.ls
-```
-
-### Logo
-
-The Logo implementation of mal has been tested with UCBLogo 6.0.
-
-```
-cd logo
-logo stepX_YYY.lg
-```
-
-### Lua
-
-The Lua implementation of mal has been tested with Lua 5.2. The
-implementation requires that luarocks and the lua-rex-pcre library
-are installed.
-
-```
-cd lua
-make  # to build and link linenoise.so
-./stepX_YYY.lua
-```
-
-### Mal
-
-Running the mal implementation of mal involves running stepA of one of
-the other implementations and passing the mal step to run as a command
-line argument.
-
-```
-cd IMPL
-IMPL_STEPA_CMD ../mal/stepX_YYY.mal
-
-```
-
-### GNU Make 3.81
-
-```
-cd make
-make -f stepX_YYY.mk
-```
-
-### NASM
-
-The NASM implementation of mal is written for x86-64 Linux, and has been tested
-with Linux 3.16.0-4-amd64 and NASM version 2.11.05.
-
-```
-cd nasm
-make
-./stepX_YYY
-```
-
-### Nim 0.17.0
-
-The Nim implementation of mal has been tested with Nim 0.17.0.
-
-```
-cd nim
-make
-  # OR
-nimble build
-./stepX_YYY
-```
-
-### Object Pascal
-
-The Object Pascal implementation of mal has been built and tested on
-Linux using the Free Pascal compiler version 2.6.2 and 2.6.4.
-
-```
-cd objpascal
-make
-./stepX_YYY
-```
-
-### Objective C
-
-The Objective C implementation of mal has been built and tested on
-Linux using clang/LLVM 3.6. It has also been built and tested on OS
-X using XCode 7.
-
-```
-cd objc
-make
-./stepX_YYY
-```
-
-### OCaml 4.01.0
-
-```
-cd ocaml
-make
-./stepX_YYY
-```
-
-### MATLAB (GNU Octave and MATLAB)
-
-The MatLab implementation has been tested with GNU Octave 4.2.1.
-It has also been tested with MATLAB version R2014a on Linux. Note that
-MATLAB is a commercial product.
-
-```
-cd matlab
-./stepX_YYY
-octave -q --no-gui --no-history --eval "stepX_YYY();quit;"
-matlab -nodisplay -nosplash -nodesktop -nojvm -r "stepX_YYY();quit;"
-    # OR with command line arguments
-octave -q --no-gui --no-history --eval "stepX_YYY('arg1','arg2');quit;"
-matlab -nodisplay -nosplash -nodesktop -nojvm -r "stepX_YYY('arg1','arg2');quit;"
-```
-
-### miniMAL
-
-[miniMAL](https://github.com/kanaka/miniMAL) is small Lisp interpreter
-implemented in less than 1024 bytes of JavaScript. To run the miniMAL
-implementation of mal you need to download/install the miniMAL
-interpreter (which requires Node.js).
-```
-cd miniMAL
-# Download miniMAL and dependencies
-npm install
-export PATH=`pwd`/node_modules/minimal-lisp/:$PATH
-# Now run mal implementation in miniMAL
-miniMAL ./stepX_YYY
-```
-
-### Perl 5.8
-
-For readline line editing support, install Term::ReadLine::Perl or
-Term::ReadLine::Gnu from CPAN.
-
-```
-cd perl
-perl stepX_YYY.pl
-```
-
-### Perl 6
-
-The Perl 6 implementation was tested on Rakudo Perl 6 2016.04.
-
-```
-cd perl6
-perl6 stepX_YYY.pl
-```
-
-### PHP 5.3
-
-The PHP implementation of mal requires the php command line interface
-to run.
-
-```
-cd php
-php stepX_YYY.php
-```
-
-### Picolisp
-
-The Picolisp implementation requires libreadline and Picolisp 3.1.11
-or later.
-
-```
-cd picolisp
-./run
-```
-
-### PL/pgSQL (Postgres SQL Procedural Language)
-
-The PL/pgSQL implementation of mal requires a running Postgres server
-(the "kanaka/mal-test-plpgsql" docker image automatically starts
-a Postgres server). The implementation connects to the Postgres server
-and create a database named "mal" to store tables and stored
-procedures. The wrapper script uses the psql command to connect to the
-server and defaults to the user "postgres" but this can be overridden
-with the PSQL_USER environment variable. A password can be specified
-using the PGPASSWORD environment variable. The implementation has been
-tested with Postgres 9.4.
-
-```
-cd plpgsql
-./wrap.sh stepX_YYY.sql
-    # OR
-PSQL_USER=myuser PGPASSWORD=mypass ./wrap.sh stepX_YYY.sql
-```
-
-### PL/SQL (Oracle SQL Procedural Language)
-
-The PL/pgSQL implementation of mal requires a running Oracle DB
-server (the "kanaka/mal-test-plsql" docker image automatically
-starts an Oracle Express server). The implementation connects to the
-Oracle server to create types, tables and stored procedures. The
-default SQL*Plus logon value (username/password@connect_identifier) is
-"system/oracle" but this can be overridden with the ORACLE_LOGON
-environment variable. The implementation has been tested with Oracle
-Express Edition 11g Release 2. Note that any SQL*Plus connection
-warnings (user password expiration, etc) will interfere with the
-ability of the wrapper script to communicate with the DB.
-
-```
-cd plsql
-./wrap.sh stepX_YYY.sql
-    # OR
-ORACLE_LOGON=myuser/mypass@ORCL ./wrap.sh stepX_YYY.sql
-```
-
-### Postscript Level 2/3
-
-The Postscript implementation of mal requires ghostscript to run. It
-has been tested with ghostscript 9.10.
-
-```
-cd ps
-gs -q -dNODISPLAY -I./ stepX_YYY.ps
-```
-
-### PowerShell
-
-The PowerShell implementation of mal requires the PowerShell script
-language. It has been tested with PowerShell 6.0.0 Alpha 9 on Linux.
-
-```
-cd powershell
-powershell ./stepX_YYY.ps1
-```
-
-### Python (2.X and 3.X)
-
-```
-cd python
-python stepX_YYY.py
-```
-
-### RPython
-
-You must have [rpython](https://rpython.readthedocs.org/) on your path
-(included with [pypy](https://bitbucket.org/pypy/pypy/)).
-
-```
-cd rpython
-make        # this takes a very long time
-./stepX_YYY
-```
-
-### R
-
-The R implementation of mal requires R (r-base-core) to run.
-
-```
-cd r
-make libs  # to download and build rdyncall
-Rscript stepX_YYY.r
-```
-
-### Racket (5.3)
-
-The Racket implementation of mal requires the Racket
-compiler/interpreter to run.
-
-```
-cd racket
-./stepX_YYY.rkt
-```
-
-### Rexx
-
-The Rexx implementation of mal has been tested with Regina Rexx 3.6.
-
-```
-cd rexx
-make
-rexx -a ./stepX_YYY.rexxpp
-```
-
-### Ruby (1.9+)
-
-```
-cd ruby
-ruby stepX_YYY.rb
-```
-
-### Rust (1.0.0 nightly)
-
-The rust implementation of mal requires the rust compiler and build
-tool (cargo) to build.
-
-```
-cd rust
-cargo run --release --bin stepX_YYY
-```
-
-### Scala ###
-
-Install scala and sbt (http://www.scala-sbt.org/0.13/tutorial/Installing-sbt-on-Linux.html):
-
-```
-cd scala
-sbt 'run-main stepX_YYY'
-    # OR
-sbt compile
-scala -classpath target/scala*/classes stepX_YYY
-```
-
-### Scheme (R7RS) ###
-
-The Scheme implementation of mal has been tested with Chibi-Scheme
-0.7.3, Kawa 2.4, Gauche 0.9.5, CHICKEN 4.11.0, Sagittarius 0.8.3,
-Cyclone 0.6.3 (Git version) and Foment 0.4 (Git version).  You should
-be able to get it running on other conforming R7RS implementations
-after figuring out how libraries are loaded and adjusting the
-`Makefile` and `run` script accordingly.
-
-```
-cd scheme
-make symlinks
-# chibi
-scheme_MODE=chibi ./run
-# kawa
-make kawa
-scheme_MODE=kawa ./run
-# gauche
-scheme_MODE=gauche ./run
-# chicken
-make chicken
-scheme_MODE=chicken ./run
-# sagittarius
-scheme_MODE=sagittarius ./run
-# cyclone
-make cyclone
-scheme_MODE=cyclone ./run
-# foment
-scheme_MODE=foment ./run
-```
-
-### Skew ###
-
-The Skew implementation of mal has been tested with Skew 0.7.42.
-
-```
-cd skew
-make
-node stepX_YYY.js
-```
-
-
-### Swift
-
-The Swift implementation of mal requires the Swift 2.0 compiler (XCode
-7.0) to build. Older versions will not work due to changes in the
-language and standard library.
-
-```
-cd swift
-make
-./stepX_YYY
-```
-
-### Swift 3
-
-The Swift 3 implementation of mal requires the Swift 3.0 compiler. It
-has been tested with Swift 3 Preview 3.
-
-```
-cd swift3
-make
-./stepX_YYY
-```
-
-### Swift 4
-
-The Swift 4 implementation of mal requires the Swift 4.0 compiler. It
-has been tested with Swift 4.2.3 release.
-
-```
-cd swift4
-make
-./stepX_YYY
-```
-
-### Tcl 8.6
-
-The Tcl implementation of mal requires Tcl 8.6 to run.  For readline line
-editing support, install tclreadline.
-
-```
-cd tcl
-tclsh ./stepX_YYY.tcl
-```
-
-### TypeScript
-
-The TypeScript implementation of mal requires the TypeScript 2.2 compiler.
-It has been tested with Node.js v6.
-
-```
-cd ts
-make
-node ./stepX_YYY.js
-```
-
-### VHDL
-
-The VHDL implementation of mal has been tested with GHDL 0.29.
-
-```
-cd vhdl
-make
-./run_vhdl.sh ./stepX_YYY
-```
-
-### Vimscript
-
-The Vimscript implementation of mal requires Vim 8.0 to run.
-
-```
-cd vimscript
-./run_vimscript.sh ./stepX_YYY.vim
-```
-
-### Visual Basic.NET ###
-
-The VB.NET implementation of mal has been tested on Linux using the Mono
-VB compiler (vbnc) and the Mono runtime (version 2.10.8.1). Both are
-required to build and run the VB.NET implementation.
-
-```
-cd vb
-make
-mono ./stepX_YYY.exe
-```
-
-### WebAssembly (wasm) ###
-
-The WebAssembly implementation is written in
-[Wam](https://github.com/kanaka/wam) (WebAssembly Macro language) and
-runs under the [wac/wace](https://github.com/kanaka/wac) WebAssembly
-runtime.
-
-```
-cd wasm
-make
-wace ./stepX_YYY.wasm
-```
-
-### Yorick
-
-The Yorick implementation of mal was tested on Yorick 2.2.04.
-
-```
-cd yorick
-yorick -batch ./stepX_YYY.i
-```
-
-
-
-## Running tests
-
-The top level Makefile has a number of useful targets to assist with
-implementation development and testing. The `help` target provides
-a list of the targets and options:
-
-```
-make help
-```
-
-### Functional tests
-
-The are over 600 generic functional tests (for all implementations)
-in the `tests/` directory. Each step has a corresponding test file
-containing tests specific to that step. The `runtest.py` test harness
-launches a Mal step implementation and then feeds the tests one at
-a time to the implementation and compares the output/return value to
-the expected output/return value.
-
-* To run all the tests across all implementations (be prepared to wait):
-
-```
-make test
-```
-
-* To run all tests against a single implementation:
-
-```
-make "test^IMPL"
-
-# e.g.
-make "test^clojure"
-make "test^js"
-```
-
-* To run tests for a single step against all implementations:
-
-```
-make "test^stepX"
-
-# e.g.
-make "test^step2"
-make "test^step7"
-```
-
-* To run tests for a specific step against a single implementation:
-
-```
-make "test^IMPL^stepX"
-
-# e.g
-make "test^ruby^step3"
-make "test^ps^step4"
-```
-
-### Self-hosted functional tests
-
-* To run the functional tests in self-hosted mode, you specify `mal`
-  as the test implementation and use the `MAL_IMPL` make variable
-  to change the underlying host language (default is JavaScript):
-```
-make MAL_IMPL=IMPL "test^mal^step2"
-
-# e.g.
-make "test^mal^step2"   # js is default
-make MAL_IMPL=ruby "test^mal^step2"
-make MAL_IMPL=python "test^mal^step2"
-```
-
-### Starting the REPL
-
-* To start the REPL of an implementation in a specific step:
-
-```
-make "repl^IMPL^stepX"
-
-# e.g
-make "repl^ruby^step3"
-make "repl^ps^step4"
-```
-
-* If you omit the step, then `stepA` is used:
-
-```
-make "repl^IMPL"
-
-# e.g
-make "repl^ruby"
-make "repl^ps"
-```
-
-* To start the REPL of the self-hosted implementation, specify `mal` as the
-  REPL implementation and use the `MAL_IMPL` make variable to change the
-  underlying host language (default is JavaScript):
-```
-make MAL_IMPL=IMPL "repl^mal^stepX"
-
-# e.g.
-make "repl^mal^step2"   # js is default
-make MAL_IMPL=ruby "repl^mal^step2"
-make MAL_IMPL=python "repl^mal"
-```
-
-### Performance tests
-
-Warning: These performance tests are neither statistically valid nor
-comprehensive; runtime performance is a not a primary goal of mal. If
-you draw any serious conclusions from these performance tests, then
-please contact me about some amazing oceanfront property in Kansas
-that I'm willing to sell you for cheap.
-
-* To run performance tests against a single implementation:
-```
-make "perf^IMPL"
-
-# e.g.
-make "perf^js"
-```
-
-* To run performance tests against all implementations:
-```
-make "perf"
-```
-
-### Generating language statistics
-
-* To report line and byte statistics for a single implementation:
-```
-make "stats^IMPL"
-
-# e.g.
-make "stats^js"
-```
-
-* To report line and bytes statistics for general Lisp code (env, core
-  and stepA):
-```
-make "stats-lisp^IMPL"
-
-# e.g.
-make "stats-lisp^js"
-```
-
-## Dockerized testing
-
-Every implementation directory contains a Dockerfile to create
-a docker image containing all the dependencies for that
-implementation. In addition, the top-level Makefile contains support
-for running the tests target (and perf, stats, repl, etc) within
-a docker container for that implementation by passing *"DOCKERIZE=1"*
-on the make command line. For example:
-
-```
-make DOCKERIZE=1 "test^js^step3"
-```
-
-Existing implementations already have docker images built and pushed
-to the docker registry. However, if
-you wish to build or rebuild a docker image locally, the toplevel
-Makefile provides a rule for building docker images:
-
-```
-make "docker-build^IMPL"
-```
-
-
-**Notes**:
-* Docker images are named *"kanaka/mal-test-IMPL"*
-* JVM-based language implementations (Groovy, Java, Clojure, Scala):
-  you will probably need to run this command once manually
-  first `make DOCKERIZE=1 "repl^IMPL"` before you can run tests because
-  runtime dependencies need to be downloaded to avoid the tests timing
-  out. These dependencies are downloaded to dot-files in the /mal
-  directory so they will persist between runs.
-
-
-## External Implementations
-
-The following implementations are maintained as separate projects:
-
-### HolyC
-
-* [by Alexander Bagnalla](https://github.com/bagnalla/holyc_mal)
-
-### Rust
-
-* [by Tim Morgan](https://github.com/seven1m/mal-rust)
-* [by vi](https://github.com/vi/mal-rust-vi) - using [Pest](https://pest.rs/) grammar, not using typical Mal infrastructure (cargo-ized steps and built-in converted tests).
-
-
-## Other mal Projects
-
- * [malc](https://github.com/dubek/malc) - Mal (Make A Lisp) compiler. Compiles a Mal program to LLVM assembly language, then binary.
- * [malcc](https://git.sr.ht/~tim/malcc) (@seven1m) - malcc is an incremental compiler implementation for the Mal language. It uses the Tiny C Compiler as the compiler backend and has full support for the Mal language, including macros, tail-call elimination, and even run-time eval. ["I Built a Lisp Compiler"](https://mpov.timmorgan.org/i-built-a-lisp-compiler/) post about the process.
- * [frock](https://github.com/chr15m/frock) - Clojure-flavoured PHP. Uses mal/php to run programs.
-
-## License
-
-Mal (make-a-lisp) is licensed under the MPL 2.0 (Mozilla Public
-License 2.0). See LICENSE.txt for more details.

D mal/core.mal => mal/core.mal +0 -87
@@ 1,87 0,0 @@
-(def! inc (fn* (a) (+ a 1)))
-
-(def! dec (fn* (a) (- a 1)))
-
-(def! zero? (fn* (n) (= 0 n)))
-
-(def! reduce
-  (fn* (f init xs)
-    (if (> (count xs) 0)
-      (reduce f (f init (first xs)) (rest xs))
-      init)))
-
-(def! identity (fn* (x) x))
-
-(def! every?
-  (fn* (pred xs)
-    (if (> (count xs) 0)
-      (if (pred (first xs))
-        (every? pred (rest xs))
-        false)
-      true)))
-
-(def! not (fn* (x) (if x false true)))
-
-(def! some
-  (fn* (pred xs)
-    (if (> (count xs) 0)
-      (let* (res (pred (first xs)))
-        (if (pred (first xs))
-          res
-          (some pred (rest xs))))
-      nil)))
-
-(defmacro! and
-  (fn* (& xs)
-    (if (empty? xs)
-      true
-      (if (= 1 (count xs))
-        (first xs)
-        (let* (condvar (gensym))
-          `(let* (~condvar ~(first xs))
-            (if ~condvar (and ~@(rest xs)) ~condvar)))))))
-
-(defmacro! or
-  (fn* (& xs)
-    (if (empty? xs)
-      nil
-      (if (= 1 (count xs))
-        (first xs)
-        (let* (condvar (gensym))
-          `(let* (~condvar ~(first xs))
-             (if ~condvar ~condvar (or ~@(rest xs)))))))))
-
-(defmacro! cond
-  (fn* (& clauses)
-    (if (> (count clauses) 0)
-      (list 'if (first clauses)
-            (if (> (count clauses) 1)
-                (nth clauses 1)
-                (throw "cond requires an even number of forms"))
-            (cons 'cond (rest (rest clauses)))))))
-
-(defmacro! ->
-  (fn* (x & xs)
-    (if (empty? xs)
-      x
-      (let* (form (first xs)
-             more (rest xs))
-        (if (empty? more)
-          (if (list? form)
-            `(~(first form) ~x ~@(rest form))
-            (list form x))
-          `(-> (-> ~x ~form) ~@more))))))
-
-(defmacro! ->>
-  (fn* (x & xs)
-    (if (empty? xs)
-      x
-      (let* (form (first xs)
-             more (rest xs))
-        (if (empty? more)
-          (if (list? form)
-            `(~(first form) ~@(rest form) ~x)
-            (list form x))
-          `(->> (->> ~x ~form) ~@more))))))
-
-nil

D mal/mal/Dockerfile => mal/mal/Dockerfile +0 -34
@@ 1,34 0,0 @@
-FROM ubuntu:18.04
-MAINTAINER Joel Martin <github@martintribe.org>
-
-##########################################################
-# General requirements for testing or common across many
-# implementations
-##########################################################
-
-RUN apt-get -y update
-
-# Required for running tests
-RUN apt-get -y install make python
-
-# Some typical implementation and test requirements
-RUN apt-get -y install curl libreadline-dev libedit-dev
-
-RUN mkdir -p /mal
-WORKDIR /mal
-
-##########################################################
-# Specific implementation requirements
-##########################################################
-
-# For building node modules
-RUN apt-get -y install g++
-
-# Add nodesource apt repo config for 10.x stable
-RUN apt-get -y install gnupg
-RUN curl -sL https://deb.nodesource.com/setup_10.x | bash -
-
-# Install nodejs
-RUN apt-get -y install nodejs
-
-ENV NPM_CONFIG_CACHE /mal/.npm

D mal/mal/Makefile => mal/mal/Makefile +0 -7
@@ 1,7 0,0 @@
-all: mal.mal
-
-mal.mal: stepA_mal.mal
-	cp $< $@
-
-clean:
-	rm -f mal.mal

D mal/mal/core.mal => mal/mal/core.mal +0 -80
@@ 1,80 0,0 @@
-(def! _fn? (fn* [x]
-  (if (fn? x)
-    (if (get (meta x) "ismacro")
-      false
-      true)
-    false)))
-
-(def! macro? (fn* [x]
-  (if (fn? x)
-    (if (get (meta x) "ismacro")
-      true
-      false)
-    false)))
-
-(def! core_ns
-  [["=" =]
-   ["throw" throw]
-   ["nil?" nil?]
-   ["true?" true?]
-   ["false?" false?]
-   ["number?" number?]
-   ["string?" string?]
-   ["symbol" symbol]
-   ["symbol?" symbol?]
-   ["keyword" keyword]
-   ["keyword?" keyword?]
-   ["fn?" _fn?]
-   ["macro?" macro?]
-
-   ["pr-str" pr-str]
-   ["str" str]
-   ["prn" prn]
-   ["println" println]
-   ["readline" readline]
-   ["read-string" read-string]
-   ["slurp" slurp]
-   ["<" <]
-   ["<=" <=]
-   [">" >]
-   [">=" >=]
-   ["+" +]
-   ["-" -]
-   ["*" *]
-   ["/" /]
-   ["time-ms" time-ms]
-
-   ["list" list]
-   ["list?" list?]
-   ["vector" vector]
-   ["vector?" vector?]
-   ["hash-map" hash-map]
-   ["map?" map?]
-   ["assoc" assoc]
-   ["dissoc" dissoc]
-   ["get" get]
-   ["contains?" contains?]
-   ["keys" keys]
-   ["vals" vals]
-
-   ["sequential?" sequential?]
-   ["cons" cons]
-   ["concat" concat]
-   ["nth" nth]
-   ["first" first]
-   ["rest" rest]
-   ["empty?" empty?]
-   ["count" count]
-   ["apply" apply]
-   ["map" map]
-
-   ["conj" conj]
-   ["seq" seq]
-
-   ["with-meta" with-meta]
-   ["meta" meta]
-   ["atom" atom]
-   ["atom?" atom?]
-   ["deref" deref]
-   ["reset!" reset!]
-   ["swap!" swap!]])

D mal/mal/env.mal => mal/mal/env.mal +0 -40
@@ 1,40 0,0 @@
-;; env 
-
-(def! bind-env (fn* [env b e]
-  (if (empty? b)
-    env
-
-    (if (= "&" (str (first b)))
-      (assoc env (str (nth b 1)) e)
-
-      (bind-env (assoc env (str (first b)) (first e))
-                (rest b) (rest e))))))
-
-(def! new-env (fn* [& args]
-  (if (<= (count args) 1)
-    (atom {"--outer--" (first args)})
-    (atom (bind-env {"--outer--" (first args)}
-                    (nth args 1) (nth args 2))))))
-
-(def! env-find (fn* [env k]
-  (let* [ks (str k)
-         data @env]
-    (if (contains? data ks)
-      env
-      (if (get data "--outer--")
-        (env-find (get data "--outer--") ks)
-        nil)))))
-
-(def! env-get (fn* [env k]
-  (let* [ks (str k)
-         e (env-find env ks)]
-    (if e
-      (get @e ks)
-      (throw (str "'" ks "' not found"))))))
-
-(def! env-set (fn* [env k v]
-  (do
-    (swap! env assoc (str k) v)
-    v)))
-
-;;(prn "loaded env.mal")

D mal/mal/run => mal/mal/run +0 -5
@@ 1,5 0,0 @@
-#!/bin/bash
-cd $(dirname $0)
-MAL_FILE=./../mal/${STEP:-stepA_mal}.mal
-export STEP=stepA_mal # force MAL_IMPL to use stepA
-exec ./../${MAL_IMPL:-js}/run ${MAL_FILE} "${@}"

D mal/mal/step0_repl.mal => mal/mal/step0_repl.mal +0 -30
@@ 1,30 0,0 @@
-;; read
-(def! READ (fn* [strng]
-  strng))
-
-;; eval
-(def! EVAL (fn* [ast env]
-  ast))
-
-;; print
-(def! PRINT (fn* [exp] exp))
-
-;; repl
-(def! rep (fn* [strng]
-  (PRINT (EVAL (READ strng) {}))))
-
-;; repl loop
-(def! repl-loop (fn* []
-  (let* [line (readline "mal-user> ")]
-    (if line
-      (do
-        (if (not (= "" line))
-          (try*
-            (println (rep line))
-            (catch* exc
-              (println "Uncaught exception:" exc))))
-        (repl-loop))))))
-
-(def! -main (fn* [& args] 
-  (repl-loop)))
-(-main)

D mal/mal/step1_read_print.mal => mal/mal/step1_read_print.mal +0 -30
@@ 1,30 0,0 @@
-;; read
-(def! READ (fn* [strng]
-  (read-string strng)))
-
-;; eval
-(def! EVAL (fn* [ast env]
-  ast))
-
-;; print
-(def! PRINT (fn* [exp] (pr-str exp)))
-
-;; repl
-(def! rep (fn* [strng]
-  (PRINT (EVAL (READ strng) {}))))
-
-;; repl loop
-(def! repl-loop (fn* []
-  (let* [line (readline "mal-user> ")]
-    (if line
-      (do
-        (if (not (= "" line))
-          (try*
-            (println (rep line))
-            (catch* exc
-              (println "Uncaught exception:" exc))))
-        (repl-loop))))))
-
-(def! -main (fn* [& args] 
-  (repl-loop)))
-(-main)

D mal/mal/step2_eval.mal => mal/mal/step2_eval.mal +0 -64
@@ 1,64 0,0 @@
-;; read
-(def! READ (fn* [strng]
-  (read-string strng)))
-
-
-;; eval
-(def! eval-ast (fn* [ast env] (do
-  ;;(do (prn "eval-ast" ast "/" (keys env)) )
-  (cond
-    (symbol? ast) (let* [res (get env (str ast))]
-                    (if res res (throw (str ast " not found"))))
-
-    (list? ast)   (map (fn* [exp] (EVAL exp env)) ast)
-
-    (vector? ast) (apply vector (map (fn* [exp] (EVAL exp env)) ast))
-
-    (map? ast)    (apply hash-map
-                      (apply concat
-                        (map (fn* [k] [k (EVAL (get ast k) env)])
-                             (keys ast))))
-
-    "else"        ast))))
-
-
-(def! EVAL (fn* [ast env] (do
-  ;;(do (prn "EVAL" ast "/" (keys @env)) )
-  (if (not (list? ast))
-    (eval-ast ast env)
-
-    ;; apply list
-    (if (empty? ast)
-      ast
-      (let* [el (eval-ast ast env)
-            f (first el)
-            args (rest el)]
-        (apply f args)))))))
-
-
-;; print
-(def! PRINT (fn* [exp] (pr-str exp)))
-
-;; repl
-(def! repl-env {"+" +
-                "-" -
-                "*" * 
-                "/" /})
-(def! rep (fn* [strng]
-  (PRINT (EVAL (READ strng) repl-env))))
-
-;; repl loop
-(def! repl-loop (fn* []
-  (let* [line (readline "mal-user> ")]
-    (if line
-      (do
-        (if (not (= "" line))
-          (try*
-            (println (rep line))
-            (catch* exc
-              (println "Uncaught exception:" exc))))
-        (repl-loop))))))
-
-(def! -main (fn* [& args] 
-  (repl-loop)))
-(-main)

D mal/mal/step3_env.mal => mal/mal/step3_env.mal +0 -85
@@ 1,85 0,0 @@
-(load-file "../mal/env.mal")
-
-;; read
-(def! READ (fn* [strng]
-  (read-string strng)))
-
-
-;; eval
-(def! eval-ast (fn* [ast env] (do
-  ;;(do (prn "eval-ast" ast "/" (keys env)) )
-  (cond
-    (symbol? ast) (env-get env ast)
-
-    (list? ast)   (map (fn* [exp] (EVAL exp env)) ast)
-
-    (vector? ast) (apply vector (map (fn* [exp] (EVAL exp env)) ast))
-
-    (map? ast)    (apply hash-map
-                      (apply concat
-                        (map (fn* [k] [k (EVAL (get ast k) env)])
-                             (keys ast))))
-
-    "else"        ast))))
-
-(def! LET (fn* [env args]
-  (if (> (count args) 0)
-    (do
-      (env-set env (nth args 0) (EVAL (nth args 1) env))
-      (LET env (rest (rest args)))))))
-
-(def! EVAL (fn* [ast env] (do
-  ;;(do (prn "EVAL" ast "/" (keys @env)) )
-  (if (not (list? ast))
-    (eval-ast ast env)
-
-    ;; apply list
-    (let* [a0 (first ast)]
-      (cond
-        (nil? a0)
-        ast
-
-        (= 'def! a0)
-        (env-set env (nth ast 1) (EVAL (nth ast 2) env))
-
-        (= 'let* a0)
-        (let* [let-env (new-env env)]
-          (do
-            (LET let-env (nth ast 1))
-            (EVAL (nth ast 2) let-env)))
-
-        "else"
-        (let* [el (eval-ast ast env)
-              f (first el)
-              args (rest el)]
-          (apply f args))))))))
-
-
-;; print
-(def! PRINT (fn* [exp] (pr-str exp)))
-
-;; repl
-(def! repl-env (new-env))
-(def! rep (fn* [strng]
-  (PRINT (EVAL (READ strng) repl-env))))
-
-(env-set repl-env "+" +)
-(env-set repl-env "-" -)
-(env-set repl-env "*" *)
-(env-set repl-env "/" /)
-
-;; repl loop
-(def! repl-loop (fn* []
-  (let* [line (readline "mal-user> ")]
-    (if line
-      (do
-        (if (not (= "" line))
-          (try*
-            (println (rep line))
-            (catch* exc
-              (println "Uncaught exception:" exc))))
-        (repl-loop))))))
-
-(def! -main (fn* [& args] 
-  (repl-loop)))
-(-main)

D mal/mal/step4_if_fn_do.mal => mal/mal/step4_if_fn_do.mal +0 -103
@@ 1,103 0,0 @@
-(load-file "../mal/env.mal")
-(load-file "../mal/core.mal")
-
-;; read
-(def! READ (fn* [strng]
-  (read-string strng)))
-
-
-;; eval
-(def! eval-ast (fn* [ast env] (do
-  ;;(do (prn "eval-ast" ast "/" (keys env)) )
-  (cond
-    (symbol? ast) (env-get env ast)
-
-    (list? ast)   (map (fn* [exp] (EVAL exp env)) ast)
-
-    (vector? ast) (apply vector (map (fn* [exp] (EVAL exp env)) ast))
-
-    (map? ast)    (apply hash-map
-                      (apply concat
-                        (map (fn* [k] [k (EVAL (get ast k) env)])
-                             (keys ast))))
-
-    "else"        ast))))
-
-(def! LET (fn* [env args]
-  (if (> (count args) 0)
-    (do
-      (env-set env (nth args 0) (EVAL (nth args 1) env))
-      (LET env (rest (rest args)))))))
-
-(def! EVAL (fn* [ast env] (do
-  ;;(do (prn "EVAL" ast "/" (keys @env)) )
-  (if (not (list? ast))
-    (eval-ast ast env)
-
-    ;; apply list
-    (let* [a0 (first ast)]
-      (cond
-        (nil? a0)
-        ast
-
-        (= 'def! a0)
-        (env-set env (nth ast 1) (EVAL (nth ast 2) env))
-
-        (= 'let* a0)
-        (let* [let-env (new-env env)]
-          (do
-            (LET let-env (nth ast 1))
-            (EVAL (nth ast 2) let-env)))
-
-        (= 'do a0)
-        (let* [el (eval-ast (rest ast) env)]
-          (nth el (- (count el) 1)))
-
-        (= 'if a0)
-        (let* [cond (EVAL (nth ast 1) env)]
-          (if (or (= cond nil) (= cond false))
-            (if (> (count ast) 3)
-              (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)))
-
-        "else"
-        (let* [el (eval-ast ast env)
-              f (first el)
-              args (rest el)]
-          (apply f args))))))))
-
-
-;; print
-(def! PRINT (fn* [exp] (pr-str exp)))
-
-;; repl
-(def! repl-env (new-env))
-(def! rep (fn* [strng]
-  (PRINT (EVAL (READ strng) repl-env))))
-
-;; core.mal: defined directly using mal
-(map (fn* [data] (env-set repl-env (nth data 0) (nth data 1))) core_ns)
-
-;; core.mal: defined using the new language itself 
-(rep "(def! not (fn* [a] (if a false true)))")
-
-;; repl loop
-(def! repl-loop (fn* []
-  (let* [line (readline "mal-user> ")]
-    (if line
-      (do
-        (if (not (= "" line))
-          (try*
-            (println (rep line))
-            (catch* exc
-              (println "Uncaught exception:" exc))))
-        (repl-loop))))))
-
-(def! -main (fn* [& args] 
-  (repl-loop)))
-(-main)

D mal/mal/step6_file.mal => mal/mal/step6_file.mal +0 -108
@@ 1,108 0,0 @@
-(load-file "../mal/env.mal")
-(load-file "../mal/core.mal")
-
-;; read
-(def! READ (fn* [strng]
-  (read-string strng)))
-
-
-;; eval
-(def! eval-ast (fn* [ast env] (do
-  ;;(do (prn "eval-ast" ast "/" (keys env)) )
-  (cond
-    (symbol? ast) (env-get env ast)
-
-    (list? ast)   (map (fn* [exp] (EVAL exp env)) ast)
-
-    (vector? ast) (apply vector (map (fn* [exp] (EVAL exp env)) ast))
-
-    (map? ast)    (apply hash-map
-                      (apply concat
-                        (map (fn* [k] [k (EVAL (get ast k) env)])
-                             (keys ast))))
-
-    "else"        ast))))
-
-(def! LET (fn* [env args]
-  (if (> (count args) 0)
-    (do
-      (env-set env (nth args 0) (EVAL (nth args 1) env))
-      (LET env (rest (rest args)))))))
-
-(def! EVAL (fn* [ast env] (do
-  ;;(do (prn "EVAL" ast "/" (keys @env)) )
-  (if (not (list? ast))
-    (eval-ast ast env)
-
-    ;; apply list
-    (let* [a0 (first ast)]
-      (cond
-        (nil? a0)
-        ast
-
-        (= 'def! a0)
-        (env-set env (nth ast 1) (EVAL (nth ast 2) env))
-
-        (= 'let* a0)
-        (let* [let-env (new-env env)]
-          (do
-            (LET let-env (nth ast 1))
-            (EVAL (nth ast 2) let-env)))
-
-        (= 'do a0)
-        (let* [el (eval-ast (rest ast) env)]
-          (nth el (- (count el) 1)))
-
-        (= 'if a0)
-        (let* [cond (EVAL (nth ast 1) env)]
-          (if (or (= cond nil) (= cond false))
-            (if (> (count ast) 3)
-              (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)))
-
-        "else"
-        (let* [el (eval-ast ast env)
-              f (first el)
-              args (rest el)]
-          (apply f args))))))))
-
-
-;; print
-(def! PRINT (fn* [exp] (pr-str exp)))
-
-;; repl
-(def! repl-env (new-env))
-(def! rep (fn* [strng]
-  (PRINT (EVAL (READ strng) repl-env))))
-
-;; 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)))
-(env-set repl-env '*ARGV* (rest *ARGV*))
-
-;; 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) \")\")))))")
-
-;; repl loop
-(def! repl-loop (fn* []
-  (let* [line (readline "mal-user> ")]
-    (if line
-      (do
-        (if (not (= "" line))
-          (try*
-            (println (rep line))
-            (catch* exc
-              (println "Uncaught exception:" exc))))
-        (repl-loop))))))
-
-(def! -main (fn* [& args] 
-  (if (> (count args) 0)
-    (rep (str "(load-file \"" (first args) "\")"))
-    (repl-loop))))
-(apply -main *ARGV*)

D mal/mal/step7_quote.mal => mal/mal/step7_quote.mal +0 -136
@@ 1,136 0,0 @@
-(load-file "../mal/env.mal")
-(load-file "../mal/core.mal")
-
-;; read
-(def! READ (fn* [strng]
-  (read-string strng)))
-
-
-;; eval
-(def! is-pair (fn* [x]
-  (if (sequential? x)
-    (if (> (count x) 0)
-      true))))
-
-(def! QUASIQUOTE (fn* [ast]
-  (cond
-    (not (is-pair ast))
-    (list 'quote ast)
-
-    (= 'unquote (first ast))
-    (nth ast 1)
-
-    (if (is-pair (first ast))
-      (if (= 'splice-unquote (first (first ast)))
-        true))
-    (list 'concat (nth (first ast) 1) (QUASIQUOTE (rest ast)))
-
-    "else"
-    (list 'cons (QUASIQUOTE (first ast)) (QUASIQUOTE (rest ast))))))
-
-(def! eval-ast (fn* [ast env] (do
-  ;;(do (prn "eval-ast" ast "/" (keys env)) )
-  (cond
-    (symbol? ast) (env-get env ast)
-
-    (list? ast)   (map (fn* [exp] (EVAL exp env)) ast)
-
-    (vector? ast) (apply vector (map (fn* [exp] (EVAL exp env)) ast))
-
-    (map? ast)    (apply hash-map
-                      (apply concat
-                        (map (fn* [k] [k (EVAL (get ast k) env)])
-                             (keys ast))))
-
-    "else"        ast))))
-
-(def! LET (fn* [env args]
-  (if (> (count args) 0)
-    (do
-      (env-set env (nth args 0) (EVAL (nth args 1) env))
-      (LET env (rest (rest args)))))))
-
-(def! EVAL (fn* [ast env] (do
-  ;;(do (prn "EVAL" ast "/" (keys @env)) )
-  (if (not (list? ast))
-    (eval-ast ast env)
-
-    ;; apply list
-    (let* [a0 (first ast)]
-      (cond
-        (nil? a0)
-        ast
-
-        (= 'def! a0)
-        (env-set env (nth ast 1) (EVAL (nth ast 2) env))
-
-        (= 'let* a0)
-        (let* [let-env (new-env env)]
-          (do
-            (LET let-env (nth ast 1))
-            (EVAL (nth ast 2) let-env)))
-
-        (= 'quote a0)
-        (nth ast 1)
-
-        (= 'quasiquote a0)
-        (let* [a1 (nth ast 1)]
-          (EVAL (QUASIQUOTE a1) env))
-
-        (= 'do a0)
-        (let* [el (eval-ast (rest ast) env)]
-          (nth el (- (count el) 1)))
-
-        (= 'if a0)
-        (let* [cond (EVAL (nth ast 1) env)]
-          (if (or (= cond nil) (= cond false))
-            (if (> (count ast) 3)
-              (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)))
-
-        "else"
-        (let* [el (eval-ast ast env)
-              f (first el)
-              args (rest el)]
-          (apply f args))))))))
-
-
-;; print
-(def! PRINT (fn* [exp] (pr-str exp)))
-
-;; repl
-(def! repl-env (new-env))
-(def! rep (fn* [strng]
-  (PRINT (EVAL (READ strng) repl-env))))
-
-;; 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)))
-(env-set repl-env '*ARGV* (rest *ARGV*))
-
-;; 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) \")\")))))")
-
-;; repl loop
-(def! repl-loop (fn* []
-  (let* [line (readline "mal-user> ")]
-    (if line
-      (do
-        (if (not (= "" line))
-          (try*
-            (println (rep line))
-            (catch* exc
-              (println "Uncaught exception:" exc))))
-        (repl-loop))))))
-
-(def! -main (fn* [& args] 
-  (if (> (count args) 0)
-    (rep (str "(load-file \"" (first args) "\")"))
-    (repl-loop))))
-(apply -main *ARGV*)

D mal/mal/step8_macros.mal => mal/mal/step8_macros.mal +0 -170
@@ 1,170 0,0 @@
-(load-file "../mal/env.mal")
-(load-file "../mal/core.mal")
-
-;; read
-(def! READ (fn* [strng]
-  (read-string strng)))
-
-
-;; eval
-(def! is-pair (fn* [x]
-  (if (sequential? x)
-    (if (> (count x) 0)
-      true))))
-
-(def! QUASIQUOTE (fn* [ast]
-  (cond
-    (not (is-pair ast))
-    (list 'quote ast)
-
-    (= 'unquote (first ast))
-    (nth ast 1)
-
-    (if (is-pair (first ast))
-      (if (= 'splice-unquote (first (first ast)))
-        true))
-    (list 'concat (nth (first ast) 1) (QUASIQUOTE (rest ast)))
-
-    "else"
-    (list 'cons (QUASIQUOTE (first ast)) (QUASIQUOTE (rest ast))))))
-
-(def! is-macro-call (fn* [ast env]
-  (if (list? ast)
-    (let* [a0 (first ast)]
-      (if (symbol? a0)
-        (if (env-find env a0)
-          (let* [m (meta (env-get env a0))]
-            (if m
-              (if (get m "ismacro")
-                true)))))))))
-
-(def! MACROEXPAND (fn* [ast env]
-  (if (is-macro-call ast env)
-    (let* [mac (env-get env (first ast))]
-      (MACROEXPAND (apply mac (rest ast)) env))
-    ast)))
-
-(def! eval-ast (fn* [ast env] (do
-  ;;(do (prn "eval-ast" ast "/" (keys env)) )
-  (cond
-    (symbol? ast) (env-get env ast)
-
-    (list? ast)   (map (fn* [exp] (EVAL exp env)) ast)
-
-    (vector? ast) (apply vector (map (fn* [exp] (EVAL exp env)) ast))
-
-    (map? ast)    (apply hash-map
-                      (apply concat
-                        (map (fn* [k] [k (EVAL (get ast k) env)])
-                             (keys ast))))
-
-    "else"        ast))))
-
-(def! LET (fn* [env args]
-  (if (> (count args) 0)
-    (do
-      (env-set env (nth args 0) (EVAL (nth args 1) env))
-      (LET env (rest (rest args)))))))
-
-(def! EVAL (fn* [ast env] (do
-  ;;(do (prn "EVAL" ast "/" (keys @env)) )
-  (if (not (list? ast))
-    (eval-ast ast env)
-
-    ;; apply list
-    (let* [ast (MACROEXPAND ast env)]
-      (if (not (list? ast))
-        (eval-ast ast env)
-
-        (let* [a0 (first ast)]
-          (cond
-            (nil? a0)
-            ast
-
-            (= 'def! a0)
-            (env-set env (nth ast 1) (EVAL (nth ast 2) env))
-
-            (= 'let* a0)
-            (let* [let-env (new-env env)]
-              (do
-                (LET let-env (nth ast 1))
-                (EVAL (nth ast 2) let-env)))
-
-            (= 'quote a0)
-            (nth ast 1)
-
-            (= 'quasiquote a0)
-            (let* [a1 (nth ast 1)]
-              (EVAL (QUASIQUOTE a1) env))
-
-            (= 'defmacro! a0)
-            (let* [a1 (nth ast 1)
-                   a2 (nth ast 2)
-                   f (EVAL a2 env)
-                   m (or (meta f) {})
-                   mac (with-meta f (assoc m "ismacro" true))]
-              (env-set env a1 mac))
-
-            (= 'macroexpand a0)
-            (let* [a1 (nth ast 1)]
-              (MACROEXPAND a1 env))
-
-            (= 'do a0)
-            (let* [el (eval-ast (rest ast) env)]
-              (nth el (- (count el) 1)))
-
-            (= 'if a0)
-            (let* [cond (EVAL (nth ast 1) env)]
-              (if (or (= cond nil) (= cond false))
-                (if (> (count ast) 3)
-                  (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)))
-
-            "else"
-            (let* [el (eval-ast ast env)
-                  f (first el)
-                  args (rest el)]
-              (apply f args))))))))))
-
-
-;; print
-(def! PRINT (fn* [exp] (pr-str exp)))
-
-;; repl
-(def! repl-env (new-env))
-(def! rep (fn* [strng]
-  (PRINT (EVAL (READ strng) repl-env))))
-
-;; 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)))
-(env-set repl-env '*ARGV* (rest *ARGV*))
-
-;; 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))))))))")
-
-;; repl loop
-(def! repl-loop (fn* []
-  (let* [line (readline "mal-user> ")]
-    (if line
-      (do
-        (if (not (= "" line))
-          (try*
-            (println (rep line))
-            (catch* exc
-              (println "Uncaught exception:" exc))))
-        (repl-loop))))))
-
-(def! -main (fn* [& args] 
-  (if (> (count args) 0)
-    (rep (str "(load-file \"" (first args) "\")"))
-    (repl-loop))))
-(apply -main *ARGV*)

D mal/mal/step9_try.mal => mal/mal/step9_try.mal +0 -182
@@ 1,182 0,0 @@
-(load-file "../mal/env.mal")
-(load-file "../mal/core.mal")
-
-;; read
-(def! READ (fn* [strng]
-  (read-string strng)))
-
-
-;; eval
-(def! is-pair (fn* [x]
-  (if (sequential? x)
-    (if (> (count x) 0)
-      true))))
-
-(def! QUASIQUOTE (fn* [ast]
-  (cond
-    (not (is-pair ast))
-    (list 'quote ast)
-
-    (= 'unquote (first ast))
-    (nth ast 1)
-
-    (if (is-pair (first ast))
-      (if (= 'splice-unquote (first (first ast)))
-        true))
-    (list 'concat (nth (first ast) 1) (QUASIQUOTE (rest ast)))
-
-    "else"
-    (list 'cons (QUASIQUOTE (first ast)) (QUASIQUOTE (rest ast))))))
-
-(def! is-macro-call (fn* [ast env]
-  (if (list? ast)
-    (let* [a0 (first ast)]
-      (if (symbol? a0)
-        (if (env-find env a0)
-          (let* [m (meta (env-get env a0))]
-            (if m
-              (if (get m "ismacro")
-                true)))))))))
-
-(def! MACROEXPAND (fn* [ast env]
-  (if (is-macro-call ast env)
-    (let* [mac (env-get env (first ast))]
-      (MACROEXPAND (apply mac (rest ast)) env))
-    ast)))
-
-(def! eval-ast (fn* [ast env] (do
-  ;;(do (prn "eval-ast" ast "/" (keys env)) )
-  (cond
-    (symbol? ast) (env-get env ast)
-
-    (list? ast)   (map (fn* [exp] (EVAL exp env)) ast)
-
-    (vector? ast) (apply vector (map (fn* [exp] (EVAL exp env)) ast))
-
-    (map? ast)    (apply hash-map
-                      (apply concat
-                        (map (fn* [k] [k (EVAL (get ast k) env)])
-                             (keys ast))))
-
-    "else"        ast))))
-
-(def! LET (fn* [env args]
-  (if (> (count args) 0)
-    (do
-      (env-set env (nth args 0) (EVAL (nth args 1) env))
-      (LET env (rest (rest args)))))))
-
-(def! EVAL (fn* [ast env] (do
-  ;;(do (prn "EVAL" ast "/" (keys @env)) )
-  (if (not (list? ast))
-    (eval-ast ast env)
-
-    ;; apply list
-    (let* [ast (MACROEXPAND ast env)]
-      (if (not (list? ast))
-        (eval-ast ast env)
-
-        (let* [a0 (first ast)]
-          (cond
-            (nil? a0)
-            ast
-
-            (= 'def! a0)
-            (env-set env (nth ast 1) (EVAL (nth ast 2) env))
-
-            (= 'let* a0)
-            (let* [let-env (new-env env)]
-              (do
-                (LET let-env (nth ast 1))
-                (EVAL (nth ast 2) let-env)))
-
-            (= 'quote a0)
-            (nth ast 1)
-
-            (= 'quasiquote a0)
-            (let* [a1 (nth ast 1)]
-              (EVAL (QUASIQUOTE a1) env))
-
-            (= 'defmacro! a0)
-            (let* [a1 (nth ast 1)
-                   a2 (nth ast 2)
-                   f (EVAL a2 env)
-                   m (or (meta f) {})
-                   mac (with-meta f (assoc m "ismacro" true))]
-              (env-set env a1 mac))
-
-            (= 'macroexpand a0)
-            (let* [a1 (nth ast 1)]
-              (MACROEXPAND a1 env))
-
-            (= 'try* a0)
-            (if (or (< (count ast) 3)
-                    (not (= 'catch* (nth (nth ast 2) 0))))
-              (EVAL (nth ast 1) env)
-              (try*
-                (EVAL (nth ast 1) env)
-                (catch* exc
-                  (EVAL (nth (nth ast 2) 2)
-                        (new-env env
-                                 [(nth (nth ast 2)1)]
-                                 [exc])))))
-
-            (= 'do a0)
-            (let* [el (eval-ast (rest ast) env)]
-              (nth el (- (count el) 1)))
-
-            (= 'if a0)
-            (let* [cond (EVAL (nth ast 1) env)]
-              (if (or (= cond nil) (= cond false))
-                (if (> (count ast) 3)
-                  (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)))
-
-            "else"
-            (let* [el (eval-ast ast env)
-                  f (first el)
-                  args (rest el)]
-              (apply f args))))))))))
-
-
-;; print
-(def! PRINT (fn* [exp] (pr-str exp)))
-
-;; repl
-(def! repl-env (new-env))
-(def! rep (fn* [strng]
-  (PRINT (EVAL (READ strng) repl-env))))
-
-;; 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)))
-(env-set repl-env '*ARGV* (rest *ARGV*))
-
-;; 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))))))))")
-
-;; repl loop
-(def! repl-loop (fn* []
-  (let* [line (readline "mal-user> ")]
-    (if line
-      (do
-        (if (not (= "" line))
-          (try*
-            (println (rep line))
-            (catch* exc
-              (println "Uncaught exception:" exc))))
-        (repl-loop))))))
-
-(def! -main (fn* [& args] 
-  (if (> (count args) 0)
-    (rep (str "(load-file \"" (first args) "\")"))
-    (repl-loop))))
-(apply -main *ARGV*)

D mal/mal/stepA_mal.mal => mal/mal/stepA_mal.mal +0 -187
@@ 1,187 0,0 @@
-(load-file "../mal/env.mal")
-(load-file "../mal/core.mal")
-
-;; read
-(def! READ (fn* [strng]
-  (read-string strng)))
-
-
-;; eval
-(def! is-pair (fn* [x]
-  (if (sequential? x)
-    (if (> (count x) 0)
-      true))))
-
-(def! QUASIQUOTE (fn* [ast]
-  (cond
-    (not (is-pair ast))
-    (list 'quote ast)
-
-    (= 'unquote (first ast))
-    (nth ast 1)
-
-    (if (is-pair (first ast))
-      (if (= 'splice-unquote (first (first ast)))
-        true))
-    (list 'concat (nth (first ast) 1) (QUASIQUOTE (rest ast)))
-
-    "else"
-    (list 'cons (QUASIQUOTE (first ast)) (QUASIQUOTE (rest ast))))))
-
-(def! is-macro-call (fn* [ast env]
-  (if (list? ast)
-    (let* [a0 (first ast)]
-      (if (symbol? a0)
-        (if (env-find env a0)
-          (let* [m (meta (env-get env a0))]
-            (if m
-              (if (get m "ismacro")
-                true)))))))))
-
-(def! MACROEXPAND (fn* [ast env]
-  (if (is-macro-call ast env)
-    (let* [mac (env-get env (first ast))]
-      (MACROEXPAND (apply mac (rest ast)) env))
-    ast)))
-
-(def! eval-ast (fn* [ast env] (do
-  ;;(do (prn "eval-ast" ast "/" (keys env)) )
-  (cond
-    (symbol? ast) (env-get env ast)
-
-    (list? ast)   (map (fn* [exp] (EVAL exp env)) ast)
-
-    (vector? ast) (apply vector (map (fn* [exp] (EVAL exp env)) ast))
-
-    (map? ast)    (apply hash-map
-                      (apply concat
-                        (map (fn* [k] [k (EVAL (get ast k) env)])
-                             (keys ast))))
-
-    "else"        ast))))
-
-(def! LET (fn* [env args]
-  (if (> (count args) 0)
-    (do
-      (env-set env (nth args 0) (EVAL (nth args 1) env))
-      (LET env (rest (rest args)))))))
-
-(def! EVAL (fn* [ast env] (do
-  ;;(do (prn "EVAL" ast "/" (keys @env)) )
-  (if (not (list? ast))
-    (eval-ast ast env)
-
-    ;; apply list
-    (let* [ast (MACROEXPAND ast env)]
-      (if (not (list? ast))
-        (eval-ast ast env)
-
-        (let* [a0 (first ast)]
-          (cond
-            (nil? a0)
-            ast
-
-            (= 'def! a0)
-            (env-set env (nth ast 1) (EVAL (nth ast 2) env))
-
-            (= 'let* a0)
-            (let* [let-env (new-env env)]
-              (do
-                (LET let-env (nth ast 1))
-                (EVAL (nth ast 2) let-env)))
-
-            (= 'quote a0)
-            (nth ast 1)
-
-            (= 'quasiquote a0)
-            (let* [a1 (nth ast 1)]
-              (EVAL (QUASIQUOTE a1) env))
-
-            (= 'defmacro! a0)
-            (let* [a1 (nth ast 1)
-                   a2 (nth ast 2)
-                   f (EVAL a2 env)
-                   m (or (meta f) {})
-                   mac (with-meta f (assoc m "ismacro" true))]
-              (env-set env a1 mac))
-
-            (= 'macroexpand a0)
-            (let* [a1 (nth ast 1)]
-              (MACROEXPAND a1 env))
-
-            (= 'try* a0)
-            (if (or (< (count ast) 3)
-                    (not (= 'catch* (nth (nth ast 2) 0))))
-              (EVAL (nth ast 1) env)
-              (try*
-                (EVAL (nth ast 1) env)
-                (catch* exc
-                  (EVAL (nth (nth ast 2) 2)
-                        (new-env env
-                                 [(nth (nth ast 2)1)]
-                                 [exc])))))
-
-            (= 'do a0)
-            (let* [el (eval-ast (rest ast) env)]
-              (nth el (- (count el) 1)))
-
-            (= 'if a0)
-            (let* [cond (EVAL (nth ast 1) env)]
-              (if (or (= cond nil) (= cond false))
-                (if (> (count ast) 3)
-                  (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)))
-
-            "else"
-            (let* [el (eval-ast ast env)
-                  f (first el)
-                  args (rest el)]
-              (apply f args))))))))))
-
-
-;; print
-(def! PRINT (fn* [exp] (pr-str exp)))
-
-;; repl
-(def! repl-env (new-env))
-(def! rep (fn* [strng]
-  (PRINT (EVAL (READ strng) repl-env))))
-
-;; 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)))
-(env-set repl-env '*ARGV* (rest *ARGV*))
-
-;; 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)))))))")
-(rep "(def! *gensym-counter* (atom 0))")
-(rep "(def! gensym (fn* [] (symbol (str \"G__\" (swap! *gensym-counter* (fn* [x] (+ 1 x)))))))")
-(rep "(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) (let* (condvar (gensym)) `(let* (~condvar ~(first xs)) (if ~condvar ~condvar (or ~@(rest xs)))))))))")
-
-;; repl loop
-(def! repl-loop (fn* []
-  (let* [line (readline "mal-user> ")]
-    (if line
-      (do
-        (if (not (= "" line))
-          (try*
-            (println (rep line))
-            (catch* exc
-              (println "Uncaught exception:" exc))))
-        (repl-loop))))))
-
-(def! -main (fn* [& args] 
-  (if (> (count args) 0)
-    (rep (str "(load-file \"" (first args) "\")"))
-    (do
-      (rep "(println (str \"Mal [\" *host-language* \"]\"))")
-      (repl-loop)))))
-(apply -main *ARGV*)

D mal/perf.mal => mal/perf.mal +0 -27
@@ 1,27 0,0 @@
-(defmacro! time
-  (fn* (exp)
-    `(let* (start_FIXME (time-ms)
-            ret_FIXME ~exp)
-      (do
-        (prn (str "Elapsed time: " (- (time-ms) start_FIXME) " msecs"))
-        ret_FIXME))))
-
-(def! run-fn-for*
-  (fn* [fn max-ms acc-ms last-iters]
-    (let* [start (time-ms)
-           _ (fn)
-           elapsed (- (time-ms) start)
-           iters (+ 1 last-iters)
-           new-acc-ms (+ acc-ms elapsed)]
-      ;(do (prn "new-acc-ms:" new-acc-ms "iters:" iters))
-      (if (>= new-acc-ms max-ms)
-        last-iters
-        (run-fn-for* fn max-ms new-acc-ms iters)))))
-
-(def! run-fn-for
-  (fn* [fn max-secs]
-    (do
-      ;; Warm it up first
-      (run-fn-for* fn 1000 0 0)
-      ;; Now do the test
-      (run-fn-for* fn (* 1000 max-secs) 0 0))))

D mal/run_argv_test.sh => mal/run_argv_test.sh +0 -39
@@ 1,39 0,0 @@
-#!/bin/bash
-
-#
-# Usage: run_argv_test.sh <command line arguments to run mal>
-#
-# Example: run_argv_test.sh python step6_file.py
-#
-
-assert_equal() {
-  if [ "$1" = "$2" ] ; then
-    echo "OK: '$1'"
-  else
-    echo "FAIL: Expected '$1' but got '$2'"
-    echo
-    exit 1
-  fi
-}
-
-if [ -z "$1" ] ; then
-  echo "Usage: $0 <command line arguments to run mal>"
-  exit 1
-fi
-
-root="$(dirname $0)"
-
-out="$( $@ $root/tests/print_argv.mal aaa bbb ccc | tr -d '\r' )"
-assert_equal '("aaa" "bbb" "ccc")' "$out"
-
-# Note: The 'make' implementation cannot handle arguments with spaces in them,
-# so for now we skip this test.
-#
-# out="$( $@ $root/tests/print_argv.mal aaa 'bbb ccc' ddd )"
-# assert_equal '("aaa" "bbb ccc" "ddd")' "$out"
-
-out="$( $@ $root/tests/print_argv.mal | tr -d '\r' )"
-assert_equal '()' "$out"
-
-echo 'Passed all *ARGV* tests'
-echo

D mal/runtest.py => mal/runtest.py +0 -360
@@ 1,360 0,0 @@
-#!/usr/bin/env python
-
-from __future__ import print_function
-import os, sys, re
-import argparse, time
-import signal, atexit
-
-from subprocess import Popen, STDOUT, PIPE
-from select import select
-
-# Pseudo-TTY and terminal manipulation
-import pty, array, fcntl, termios
-
-IS_PY_3 = sys.version_info[0] == 3
-
-debug_file = None
-log_file = None
-
-def debug(data):
-    if debug_file:
-        debug_file.write(data)
-        debug_file.flush()
-
-def log(data, end='\n'):
-    if log_file:
-        log_file.write(data + end)
-        log_file.flush()
-    print(data, end=end)
-    sys.stdout.flush()
-
-# TODO: do we need to support '\n' too
-import platform
-if platform.system().find("CYGWIN_NT") >= 0:
-    # TODO: this is weird, is this really right on Cygwin?
-    sep = "\n\r\n"
-else:
-    sep = "\r\n"
-rundir = None
-
-parser = argparse.ArgumentParser(
-        description="Run a test file against a Mal implementation")
-parser.add_argument('--rundir',
-        help="change to the directory before running tests")
-parser.add_argument('--start-timeout', default=10, type=int,
-        help="default timeout for initial prompt")
-parser.add_argument('--test-timeout', default=20, type=int,
-        help="default timeout for each individual test action")
-parser.add_argument('--pre-eval', default=None, type=str,
-        help="Mal code to evaluate prior to running the test")
-parser.add_argument('--no-pty', action='store_true',
-        help="Use direct pipes instead of pseudo-tty")
-parser.add_argument('--log-file', type=str,
-        help="Write messages to the named file in addition the screen")
-parser.add_argument('--debug-file', type=str,
-        help="Write all test interaction the named file")
-parser.add_argument('--hard', action='store_true',
-        help="Turn soft tests following a ';>>> soft=True' into hard failures")
-
-# Control whether deferrable and optional tests are executed
-parser.add_argument('--deferrable', dest='deferrable', action='store_true',
-        help="Enable deferrable tests that follow a ';>>> deferrable=True'")
-parser.add_argument('--no-deferrable', dest='deferrable', action='store_false',
-        help="Disable deferrable tests that follow a ';>>> deferrable=True'")
-parser.set_defaults(deferrable=True)
-parser.add_argument('--optional', dest='optional', action='store_true',
-        help="Enable optional tests that follow a ';>>> optional=True'")
-parser.add_argument('--no-optional', dest='optional', action='store_false',
-        help="Disable optional tests that follow a ';>>> optional=True'")
-parser.set_defaults(optional=True)
-
-parser.add_argument('test_file', type=str,
-        help="a test file formatted as with mal test data")
-parser.add_argument('mal_cmd', nargs="*",
-        help="Mal implementation command line. Use '--' to "
-             "specify a Mal command line with dashed options.")
-
-class Runner():
-    def __init__(self, args, no_pty=False):
-        #print "args: %s" % repr(args)
-        self.no_pty = no_pty
-
-        # Cleanup child process on exit
-        atexit.register(self.cleanup)
-
-        self.p = None
-        env = os.environ
-        env['TERM'] = 'dumb'
-        env['INPUTRC'] = '/dev/null'
-        env['PERL_RL'] = 'false'
-        if no_pty:
-            self.p = Popen(args, bufsize=0,
-                           stdin=PIPE, stdout=PIPE, stderr=STDOUT,
-                           preexec_fn=os.setsid,
-                           env=env)
-            self.stdin = self.p.stdin
-            self.stdout = self.p.stdout
-        else:
-            # provide tty to get 'interactive' readline to work
-            master, slave = pty.openpty()
-
-            # Set terminal size large so that readline will not send
-            # ANSI/VT escape codes when the lines are long.
-            buf = array.array('h', [100, 200, 0, 0])
-            fcntl.ioctl(master, termios.TIOCSWINSZ, buf, True)
-
-            self.p = Popen(args, bufsize=0,
-                           stdin=slave, stdout=slave, stderr=STDOUT,
-                           preexec_fn=os.setsid,
-                           env=env)
-            # Now close slave so that we will get an exception from
-            # read when the child exits early
-            # http://stackoverflow.com/questions/11165521
-            os.close(slave)
-            self.stdin = os.fdopen(master, 'r+b', 0)
-            self.stdout = self.stdin
-
-        #print "started"
-        self.buf = ""
-        self.last_prompt = ""
-
-    def read_to_prompt(self, prompts, timeout):
-        end_time = time.time() + timeout
-        while time.time() < end_time:
-            [outs,_,_] = select([self.stdout], [], [], 1)
-            if self.stdout in outs:
-                new_data = self.stdout.read(1)
-                new_data = new_data.decode("utf-8") if IS_PY_3 else new_data
-                #print("new_data: '%s'" % new_data)
-                debug(new_data)
-                # Perform newline cleanup
-                if self.no_pty:
-                    self.buf += new_data.replace("\n", "\r\n")
-                else:
-                    self.buf += new_data
-                self.buf = self.buf.replace("\r\r", "\r")
-                # Remove ANSI codes generally
-                #ansi_escape = re.compile(r'\x1B\[[0-?]*[ -/]*[@-~]')
-                # Remove rustyline ANSI CSI codes:
-                #  - [6C - CR + cursor forward
-                #  - [6K - CR + erase in line
-                ansi_escape = re.compile(r'\r\x1B\[[0-9]*[CK]')
-                self.buf = ansi_escape.sub('', self.buf)
-                for prompt in prompts:
-                    regexp = re.compile(prompt)
-                    match = regexp.search(self.buf)
-                    if match:
-                        end = match.end()
-                        buf = self.buf[0:match.start()]
-                        self.buf = self.buf[end:]
-                        self.last_prompt = prompt
-                        return buf.replace("^M", "\r")
-        return None
-
-    def writeline(self, str):
-        def _to_bytes(s):
-            return bytes(s, "utf-8") if IS_PY_3 else s
-
-        self.stdin.write(_to_bytes(str.replace('\r', '\x16\r') + "\n"))
-
-    def cleanup(self):
-        #print "cleaning up"
-        if self.p:
-            try:
-                os.killpg(self.p.pid, signal.SIGTERM)
-            except OSError:
-                pass
-            self.p = None
-
-class TestReader:
-    def __init__(self, test_file):
-        self.line_num = 0
-        f = open(test_file, newline='') if IS_PY_3 else open(test_file)
-        self.data = f.read().split('\n')
-        self.soft = False
-        self.deferrable = False
-        self.optional = False
-
-    def next(self):
-        self.msg = None
-        self.form = None
-        self.out = ""
-        self.ret = None
-
-        while self.data:
-            self.line_num += 1
-            line = self.data.pop(0)
-            if re.match(r"^\s*$", line):   # blank line
-                continue
-            elif line[0:3] == ";;;":       # ignore comment
-                continue
-            elif line[0:2] == ";;":        # output comment
-                self.msg = line[3:]
-                return True
-            elif line[0:5] == ";>>> ":     # settings/commands
-                settings = {}
-                exec(line[5:], {}, settings)
-                if 'soft' in settings:
-                    self.soft = settings['soft']
-                if 'deferrable' in settings and settings['deferrable']:
-                    self.deferrable = "\nSkipping deferrable and optional tests"
-                    return True
-                if 'optional' in settings and settings['optional']:
-                    self.optional = "\nSkipping optional tests"
-                    return True
-                continue
-            elif line[0:1] == ";":         # unexpected comment
-                raise Exception("Test data error at line %d:\n%s" % (self.line_num, line))
-            self.form = line   # the line is a form to send
-
-            # Now find the output and return value
-            while self.data:
-                line = self.data[0]
-                if line[0:3] == ";=>":
-                    self.ret = line[3:]
-                    self.line_num += 1
-                    self.data.pop(0)
-                    break
-                elif line[0:2] == ";/":
-                    self.out = self.out + line[2:] + sep
-                    self.line_num += 1
-                    self.data.pop(0)
-                else:
-                    self.ret = ""
-                    break
-            if self.ret != None: break
-
-        if self.out[-2:] == sep and not self.ret:
-            # If there is no return value, output should not end in
-            # separator
-            self.out = self.out[0:-2]
-        return self.form
-
-args = parser.parse_args(sys.argv[1:])
-# Workaround argparse issue with two '--' on command line
-if sys.argv.count('--') > 0:
-    args.mal_cmd = sys.argv[sys.argv.index('--')+1:]
-
-if args.rundir: os.chdir(args.rundir)
-
-if args.log_file:   log_file   = open(args.log_file, "a")
-if args.debug_file: debug_file = open(args.debug_file, "a")
-
-r = Runner(args.mal_cmd, no_pty=args.no_pty)
-t = TestReader(args.test_file)
-
-
-def assert_prompt(runner, prompts, timeout):
-    # Wait for the initial prompt
-    header = runner.read_to_prompt(prompts, timeout=timeout)
-    if not header == None:
-        if header:
-            log("Started with:\n%s" % header)
-    else:
-        log("Did not one of following prompt(s): %s" % repr(prompts))
-        log("    Got      : %s" % repr(r.buf))
-        sys.exit(1)
-
-
-# Wait for the initial prompt
-try:
-    assert_prompt(r, ['[^\s()<>]+> '], args.start_timeout)
-except:
-    _, exc, _ = sys.exc_info()
-    log("\nException: %s" % repr(exc))
-    log("Output before exception:\n%s" % r.buf)
-    sys.exit(1)
-
-# Send the pre-eval code if any
-if args.pre_eval:
-    sys.stdout.write("RUNNING pre-eval: %s" % args.pre_eval)
-    p.write(args.pre_eval)
-    assert_prompt(args.test_timeout)
-
-test_cnt = 0
-pass_cnt = 0
-fail_cnt = 0
-soft_fail_cnt = 0
-failures = []
-
-while t.next():
-    if args.deferrable == False and t.deferrable:
-        log(t.deferrable)
-        break
-
-    if args.optional == False and t.optional:
-        log(t.optional)
-        break
-
-    if t.msg != None:
-        log(t.msg)
-        continue
-
-    if t.form == None: continue
-
-    log("TEST: %s -> [%s,%s]" % (repr(t.form), repr(t.out), t.ret), end='')
-
-    # The repeated form is to get around an occasional OS X issue
-    # where the form is repeated.
-    # https://github.com/kanaka/mal/issues/30
-    expects = ["%s%s%s%s" % (re.escape(t.form), sep,
-                              t.out, re.escape(t.ret)),
-               "%s%s%s%s%s%s" % (re.escape(t.form), sep,
-                                  re.escape(t.form), sep,
-                                  t.out, re.escape(t.ret))]
-
-    r.writeline(t.form)
-    try:
-        test_cnt += 1
-        res = r.read_to_prompt(['\r\n[^\s()<>]+> ', '\n[^\s()<>]+> '],
-                                timeout=args.test_timeout)
-        #print "%s,%s,%s" % (idx, repr(p.before), repr(p.after))
-        if (t.ret == "" and t.out == ""):
-            log(" -> SUCCESS (result ignored)")
-            pass_cnt += 1
-        elif (re.search(expects[0], res, re.S) or
-                re.search(expects[1], res, re.S)):
-            log(" -> SUCCESS")
-            pass_cnt += 1
-        else:
-            if t.soft and not args.hard:
-                log(" -> SOFT FAIL (line %d):" % t.line_num)
-                soft_fail_cnt += 1
-                fail_type = "SOFT "
-            else:
-                log(" -> FAIL (line %d):" % t.line_num)
-                fail_cnt += 1
-                fail_type = ""
-            log("    Expected : %s" % repr(expects[0]))
-            log("    Got      : %s" % repr(res))
-            failed_test = """%sFAILED TEST (line %d): %s -> [%s,%s]:
-    Expected : %s
-    Got      : %s""" % (fail_type, t.line_num, t.form, repr(t.out),
-                        t.ret, repr(expects[0]), repr(res))
-            failures.append(failed_test)
-    except:
-        _, exc, _ = sys.exc_info()
-        log("\nException: %s" % repr(exc))
-        log("Output before exception:\n%s" % r.buf)
-        sys.exit(1)
-
-if len(failures) > 0:
-    log("\nFAILURES:")
-    for f in failures:
-        log(f)
-
-results = """
-TEST RESULTS (for %s):
-  %3d: soft failing tests
-  %3d: failing tests
-  %3d: passing tests
-  %3d: total tests
-""" % (args.test_file, soft_fail_cnt, fail_cnt,
-        pass_cnt, test_cnt)
-log(results)
-
-debug("\n") # add some separate to debug log
-
-if fail_cnt > 0:
-    sys.exit(1)
-sys.exit(0)

D mal/tests/docker-build.sh => mal/tests/docker-build.sh +0 -6
@@ 1,6 0,0 @@
-#!/bin/bash
-
-IMAGE_NAME=${IMAGE_NAME:-mal-test-ubuntu-utopic}
-GIT_TOP=$(git rev-parse --show-toplevel)
-
-docker build -t "${IMAGE_NAME}" "${GIT_TOP}/tests/docker"

D mal/tests/docker-run.sh => mal/tests/docker-run.sh +0 -9
@@ 1,9 0,0 @@
-#!/bin/bash
-
-IMAGE_NAME=${IMAGE_NAME:-mal-test-ubuntu-utopic}
-GIT_TOP=$(git rev-parse --show-toplevel)
- 
-docker run -it --rm -u ${EUID} \
-    --volume=${GIT_TOP}:/mal \
-    ${IMAGE_NAME} \
-    "${@}"

D mal/tests/docker/Dockerfile => mal/tests/docker/Dockerfile +0 -178
@@