| 1 | # |
| 2 | # Command line settings |
| 3 | # |
| 4 | |
| 5 | MAL_IMPL = js |
| 6 | |
| 7 | PYTHON = python |
| 8 | |
| 9 | # |
| 10 | # Settings |
| 11 | # |
| 12 | |
| 13 | IMPLS = awk bash c clojure coffee cpp crystal cs erlang elixir es6 factor forth fsharp go groovy \ |
| 14 | haskell java julia js lua make mal ocaml matlab miniMAL nim \ |
| 15 | perl php ps python r racket rpython ruby rust scala swift vb guile |
| 16 | |
| 17 | step0 = step0_repl |
| 18 | step1 = step1_read_print |
| 19 | step2 = step2_eval |
| 20 | step3 = step3_env |
| 21 | step4 = step4_if_fn_do |
| 22 | step5 = step5_tco |
| 23 | step6 = step6_file |
| 24 | step7 = step7_quote |
| 25 | step8 = step8_macros |
| 26 | step9 = step9_try |
| 27 | stepA = stepA_mal |
| 28 | |
| 29 | EXCLUDE_TESTS += test^awk^step5 # completes at 10,000 |
| 30 | EXCLUDE_TESTS += test^bash^step5 # no stack exhaustion or completion |
| 31 | EXCLUDE_TESTS += test^c^step5 # segfault |
| 32 | EXCLUDE_TESTS += test^cpp^step5 # completes at 10,000 |
| 33 | EXCLUDE_TESTS += test^cs^step5 # fatal stack overflow fault |
| 34 | EXCLUDE_TESTS += test^erlang^step5 # erlang is TCO, test passes |
| 35 | EXCLUDE_TESTS += test^elixir^step5 # elixir is TCO, test passes |
| 36 | EXCLUDE_TESTS += test^fsharp^step5 # completes at 10,000, fatal stack overflow at 100,000 |
| 37 | EXCLUDE_TESTS += test^haskell^step5 # test completes |
| 38 | EXCLUDE_TESTS += test^julia^step5 # hangs test |
| 39 | EXCLUDE_TESTS += test^make^step5 # no TCO capability/step |
| 40 | EXCLUDE_TESTS += test^mal^step5 # no TCO capability/step |
| 41 | EXCLUDE_TESTS += test^miniMAL^step5 # strange error with runtest.py |
| 42 | EXCLUDE_TESTS += test^nim^step5 # test completes, even at 100,000 |
| 43 | EXCLUDE_TESTS += test^go^step5 # test completes, even at 100,000 |
| 44 | EXCLUDE_TESTS += test^php^step5 # test completes, even at 100,000 |
| 45 | EXCLUDE_TESTS += test^racket^step5 # test completes |
| 46 | EXCLUDE_TESTS += test^ruby^step5 # test completes, even at 100,000 |
| 47 | EXCLUDE_TESTS += test^rust^step5 # no catching stack overflows |
| 48 | EXCLUDE_TESTS += test^ocaml^step5 # test completes, even at 1,000,000 |
| 49 | EXCLUDE_TESTS += test^vb^step5 # completes at 10,000 |
| 50 | EXCLUDE_TESTS += test^crystal^step5 # test completes, even at 1,000,000 |
| 51 | |
| 52 | EXCLUDE_PERFS = perf^mal # TODO: fix this |
| 53 | |
| 54 | # |
| 55 | # Utility functions |
| 56 | # |
| 57 | |
| 58 | STEP_TEST_FILES = $(strip $(wildcard $(1)/tests/$($(2)).mal) $(wildcard tests/$($(2)).mal)) |
| 59 | |
| 60 | awk_STEP_TO_PROG = awk/$($(1)).awk |
| 61 | bash_STEP_TO_PROG = bash/$($(1)).sh |
| 62 | c_STEP_TO_PROG = c/$($(1)) |
| 63 | clojure_STEP_TO_PROG = clojure/src/$($(1)).clj |
| 64 | coffee_STEP_TO_PROG = coffee/$($(1)).coffee |
| 65 | cpp_STEP_TO_PROG = cpp/$($(1)) |
| 66 | crystal_STEP_TO_PROG = crystal/$($(1)) |
| 67 | cs_STEP_TO_PROG = cs/$($(1)).exe |
| 68 | elixir_STEP_TO_PROG = elixir/lib/mix/tasks/$($(1)).ex |
| 69 | erlang_STEP_TO_PROG = erlang/$($(1)) |
| 70 | es6_STEP_TO_PROG = es6/build/$($(1)).js |
| 71 | factor_STEP_TO_PROG = factor/src/$($(1))/$($(1)).factor |
| 72 | forth_STEP_TO_PROG = forth/$($(1)).fs |
| 73 | fsharp_STEP_TO_PROG = fsharp/$($(1)).exe |
| 74 | go_STEP_TO_PROG = go/$($(1)) |
| 75 | groovy_STEP_TO_PROG = groovy/$($(1)).groovy |
| 76 | java_STEP_TO_PROG = java/src/main/java/mal/$($(1)).java |
| 77 | haskell_STEP_TO_PROG = haskell/$($(1)) |
| 78 | julia_STEP_TO_PROG = julia/$($(1)).jl |
| 79 | js_STEP_TO_PROG = js/$($(1)).js |
| 80 | lua_STEP_TO_PROG = lua/$($(1)).lua |
| 81 | make_STEP_TO_PROG = make/$($(1)).mk |
| 82 | mal_STEP_TO_PROG = mal/$($(1)).mal |
| 83 | ocaml_STEP_TO_PROG = ocaml/$($(1)) |
| 84 | matlab_STEP_TO_PROG = matlab/$($(1)).m |
| 85 | miniMAL_STEP_TO_PROG = miniMAL/$($(1)).json |
| 86 | nim_STEP_TO_PROG = nim/$($(1)) |
| 87 | perl_STEP_TO_PROG = perl/$($(1)).pl |
| 88 | php_STEP_TO_PROG = php/$($(1)).php |
| 89 | ps_STEP_TO_PROG = ps/$($(1)).ps |
| 90 | python_STEP_TO_PROG = python/$($(1)).py |
| 91 | r_STEP_TO_PROG = r/$($(1)).r |
| 92 | racket_STEP_TO_PROG = racket/$($(1)).rkt |
| 93 | rpython_STEP_TO_PROG = rpython/$($(1)) |
| 94 | ruby_STEP_TO_PROG = ruby/$($(1)).rb |
| 95 | rust_STEP_TO_PROG = rust/target/release/$($(1)) |
| 96 | scala_STEP_TO_PROG = scala/$($(1)).scala |
| 97 | swift_STEP_TO_PROG = swift/$($(1)) |
| 98 | vb_STEP_TO_PROG = vb/$($(1)).exe |
| 99 | guile_STEP_TO_PROG = guile/$($(1)).scm |
| 100 | |
| 101 | # Needed some argument munging |
| 102 | COMMA = , |
| 103 | noop = |
| 104 | SPACE = $(noop) $(noop) |
| 105 | export FACTOR_ROOTS := src |
| 106 | |
| 107 | awk_RUNSTEP = awk -O -f ../$(2) $(3) |
| 108 | bash_RUNSTEP = bash ../$(2) $(3) |
| 109 | c_RUNSTEP = ../$(2) $(3) |
| 110 | clojure_RUNSTEP = lein with-profile +$(1) trampoline run $(3) |
| 111 | coffee_RUNSTEP = coffee ../$(2) $(3) |
| 112 | cpp_RUNSTEP = ../$(2) $(3) |
| 113 | crystal_RUNSTEP = ../$(2) $(3) |
| 114 | cs_RUNSTEP = mono ../$(2) --raw $(3) |
| 115 | elixir_RUNSTEP = mix $(notdir $(basename $(2))) $(3) |
| 116 | erlang_RUNSTEP = ../$(2) $(3) |
| 117 | es6_RUNSTEP = node ../$(2) $(3) |
| 118 | factor_RUNSTEP = factor ../$(2) $(3) |
| 119 | forth_RUNSTEP = gforth ../$(2) $(3) |
| 120 | fsharp_RUNSTEP = mono ../$(2) --raw $(3) |
| 121 | go_RUNSTEP = ../$(2) $(3) |
| 122 | groovy_RUNSTEP = groovy ../$(2) $(3) |
| 123 | haskell_RUNSTEP = ../$(2) $(3) |
| 124 | java_RUNSTEP = mvn -quiet exec:java -Dexec.mainClass="mal.$($(1))" $(if $(3), -Dexec.args="$(3)",) |
| 125 | julia_RUNSTEP = ../$(2) $(3) |
| 126 | js_RUNSTEP = node ../$(2) $(3) |
| 127 | lua_RUNSTEP = ../$(2) $(3) |
| 128 | make_RUNSTEP = make -f ../$(2) $(3) |
| 129 | mal_RUNSTEP = $(call $(MAL_IMPL)_RUNSTEP,$(1),$(call $(MAL_IMPL)_STEP_TO_PROG,stepA),../$(2),") #" |
| 130 | ocaml_RUNSTEP = ../$(2) $(3) |
| 131 | matlab_args = $(subst $(SPACE),$(COMMA),$(foreach x,$(strip $(1)),'$(x)')) |
| 132 | matlab_RUNSTEP = matlab -nodisplay -nosplash -nodesktop -nojvm -r "$($(1))($(call matlab_args,$(3)));quit;" |
| 133 | miniMAL_RUNSTEP = miniMAL ../$(2) $(3) |
| 134 | nim_RUNSTEP = ../$(2) $(3) |
| 135 | perl_RUNSTEP = perl ../$(2) $(3) |
| 136 | php_RUNSTEP = php ../$(2) $(3) |
| 137 | ps_RUNSTEP = $(4)gs -q -I./ -dNODISPLAY -- ../$(2) $(3)$(4) |
| 138 | python_RUNSTEP = $(PYTHON) ../$(2) $(3) |
| 139 | r_RUNSTEP = Rscript ../$(2) $(3) |
| 140 | racket_RUNSTEP = ../$(2) $(3) |
| 141 | rpython_RUNSTEP = ../$(2) $(3) |
| 142 | ruby_RUNSTEP = ruby ../$(2) $(3) |
| 143 | rust_RUNSTEP = ../$(2) $(3) |
| 144 | scala_RUNSTEP = sbt 'run-main $($(1))$(if $(3), $(3),)' |
| 145 | swift_RUNSTEP = ../$(2) $(3) |
| 146 | vb_RUNSTEP = mono ../$(2) --raw $(3) |
| 147 | # needs TERM=dumb to work with readline |
| 148 | guile_RUNSTEP = guile -L ../guile ../$(2) $(3) |
| 149 | |
| 150 | # Extra options to pass to runtest.py |
| 151 | TEST_OPTS = |
| 152 | # Extra implementation specific options to pass to runtest.py |
| 153 | mal_TEST_OPTS = --start-timeout 60 --test-timeout 120 |
| 154 | |
| 155 | |
| 156 | # Derived lists |
| 157 | STEPS = $(sort $(filter step%,$(.VARIABLES))) |
| 158 | DO_IMPLS = $(filter-out $(SKIP_IMPLS),$(IMPLS)) |
| 159 | IMPL_TESTS = $(foreach impl,$(DO_IMPLS),test^$(impl)) |
| 160 | STEP_TESTS = $(foreach step,$(STEPS),test^$(step)) |
| 161 | ALL_TESTS = $(filter-out $(EXCLUDE_TESTS),\ |
| 162 | $(strip $(sort \ |
| 163 | $(foreach impl,$(DO_IMPLS),\ |
| 164 | $(foreach step,$(STEPS),test^$(impl)^$(step)))))) |
| 165 | |
| 166 | IMPL_STATS = $(foreach impl,$(DO_IMPLS),stats^$(impl)) |
| 167 | IMPL_STATS_LISP = $(foreach impl,$(DO_IMPLS),stats-lisp^$(impl)) |
| 168 | |
| 169 | DOCKER_BUILD = $(foreach impl,$(DO_IMPLS),docker-build^$(impl)) |
| 170 | |
| 171 | IMPL_PERF = $(filter-out $(EXCLUDE_PERFS),$(foreach impl,$(DO_IMPLS),perf^$(impl))) |
| 172 | |
| 173 | # |
| 174 | # Build rules |
| 175 | # |
| 176 | |
| 177 | # Build a program in an implementation directory |
| 178 | $(foreach i,$(DO_IMPLS),$(foreach s,$(STEPS),$(call $(i)_STEP_TO_PROG,$(s)))): |
| 179 | $(MAKE) -C $(dir $(@)) $(notdir $(@)) |
| 180 | |
| 181 | # Allow test, test^STEP, test^IMPL, and test^IMPL^STEP |
| 182 | .SECONDEXPANSION: |
| 183 | $(IMPL_TESTS): $$(filter $$@^%,$$(ALL_TESTS)) |
| 184 | |
| 185 | .SECONDEXPANSION: |
| 186 | $(STEP_TESTS): $$(foreach step,$$(subst test^,,$$@),$$(filter %^$$(step),$$(ALL_TESTS))) |
| 187 | |
| 188 | .SECONDEXPANSION: |
| 189 | $(ALL_TESTS): $$(call $$(word 2,$$(subst ^, ,$$(@)))_STEP_TO_PROG,$$(word 3,$$(subst ^, ,$$(@)))) |
| 190 | @$(foreach impl,$(word 2,$(subst ^, ,$(@))),\ |
| 191 | $(foreach step,$(word 3,$(subst ^, ,$(@))),\ |
| 192 | cd $(if $(filter mal,$(impl)),$(MAL_IMPL),$(impl)); \ |
| 193 | $(foreach test,$(call STEP_TEST_FILES,$(impl),$(step)),\ |
| 194 | echo '----------------------------------------------'; \ |
| 195 | echo 'Testing $@, step file: $+, test file: $(test)'; \ |
| 196 | echo 'Running: ../runtest.py $(TEST_OPTS) $(call $(impl)_TEST_OPTS) ../$(test) -- $(call $(impl)_RUNSTEP,$(step),$(+))'; \ |
| 197 | ../runtest.py $(TEST_OPTS) $(call $(impl)_TEST_OPTS) ../$(test) -- $(call $(impl)_RUNSTEP,$(step),$(+));))) |
| 198 | |
| 199 | test: $(ALL_TESTS) |
| 200 | tests: $(ALL_TESTS) |
| 201 | |
| 202 | |
| 203 | # Stats rules |
| 204 | |
| 205 | stats: $(IMPL_STATS) |
| 206 | stats-lisp: $(IMPL_STATS_LISP) |
| 207 | |
| 208 | .SECONDEXPANSION: |
| 209 | $(IMPL_STATS): |
| 210 | @echo "----------------------------------------------"; \ |
| 211 | $(foreach impl,$(word 2,$(subst ^, ,$(@))),\ |
| 212 | echo "Stats for $(impl):"; \ |
| 213 | $(MAKE) --no-print-directory -C $(impl) stats) |
| 214 | |
| 215 | .SECONDEXPANSION: |
| 216 | $(IMPL_STATS_LISP): |
| 217 | @echo "----------------------------------------------"; \ |
| 218 | $(foreach impl,$(word 2,$(subst ^, ,$(@))),\ |
| 219 | echo "Stats (lisp only) for $(impl):"; \ |
| 220 | $(MAKE) --no-print-directory -C $(impl) stats-lisp) |
| 221 | |
| 222 | # Docker build rules |
| 223 | |
| 224 | docker-build: $(DOCKER_BUILD) |
| 225 | |
| 226 | .SECONDEXPANSION: |
| 227 | $(DOCKER_BUILD): |
| 228 | echo "----------------------------------------------"; \ |
| 229 | $(foreach impl,$(word 2,$(subst ^, ,$(@))),\ |
| 230 | echo "Running: docker build -t kanaka/mal-test-$(impl) .:"; \ |
| 231 | cd $(impl) && docker build -t kanaka/mal-test-$(impl) .) |
| 232 | |
| 233 | # Performance test rules |
| 234 | |
| 235 | perf: $(IMPL_PERF) |
| 236 | |
| 237 | .SECONDEXPANSION: |
| 238 | $(IMPL_PERF): |
| 239 | @echo "----------------------------------------------"; \ |
| 240 | $(foreach impl,$(word 2,$(subst ^, ,$(@))),\ |
| 241 | cd $(if $(filter mal,$(impl)),$(MAL_IMPL),$(impl)); \ |
| 242 | echo "Performance test for $(impl):"; \ |
| 243 | echo 'Running: $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf1.mal)'; \ |
| 244 | $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf1.mal); \ |
| 245 | echo 'Running: $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf2.mal)'; \ |
| 246 | $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf2.mal); \ |
| 247 | echo 'Running: $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf3.mal)'; \ |
| 248 | $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf3.mal)) |