2 # Command line settings
9 # python, js, cpp, or neko are currently supported
12 # Extra options to pass to runtest.py
15 # Test with previous test files not just the test files for the
16 # current step. Step 0 and 1 tests are special and not included in
20 # Extra implementation specific options to pass to runtest.py
21 mal_TEST_OPTS
= --start-timeout
60 --test-timeout
120
27 IMPLS
= awk bash c d clojure coffee
cpp crystal cs erlang elixir es6 \
28 factor forth fsharp go groovy guile haskell haxe java julia \
29 js kotlin lua make mal ocaml matlab miniMAL nim perl php ps \
30 python r racket rpython ruby rust scala swift swift3 tcl vb vimscript
33 step1
= step1_read_print
36 step4
= step4_if_fn_do
47 regress_step3
= $(regress_step2
) step3
48 regress_step4
= $(regress_step3
) step4
49 regress_step5
= $(regress_step4
) step5
50 regress_step6
= $(regress_step5
) step6
51 regress_step7
= $(regress_step6
) step7
52 regress_step8
= $(regress_step7
) step8
53 regress_step9
= $(regress_step8
) step9
54 regress_stepA
= $(regress_step9
) stepA
56 STEP5_EXCLUDES
+= awk
# completes at 10,000
57 STEP5_EXCLUDES
+= bash
# no stack exhaustion or completion
58 STEP5_EXCLUDES
+= c
# segfault
59 STEP5_EXCLUDES
+= cpp # completes at 10,000
60 STEP5_EXCLUDES
+= cs
# fatal stack overflow fault
61 STEP5_EXCLUDES
+= d
# completes at 10,000, fatal stack overflow at 1,000,000
62 STEP5_EXCLUDES
+= erlang
# erlang is TCO, test passes
63 STEP5_EXCLUDES
+= elixir
# elixir is TCO, test passes
64 STEP5_EXCLUDES
+= fsharp
# completes at 10,000, fatal stack overflow at 100,000
65 STEP5_EXCLUDES
+= haskell
# test completes
66 STEP5_EXCLUDES
+= make
# no TCO capability/step
67 STEP5_EXCLUDES
+= mal
# no TCO capability/step
68 STEP5_EXCLUDES
+= matlab
# too slow to complete 10,000
69 STEP5_EXCLUDES
+= miniMAL
# strange error with runtest.py
70 STEP5_EXCLUDES
+= nim
# test completes, even at 100,000
71 STEP5_EXCLUDES
+= go
# test completes, even at 100,000
72 STEP5_EXCLUDES
+= php
# test completes, even at 100,000
73 STEP5_EXCLUDES
+= racket
# test completes
74 STEP5_EXCLUDES
+= ruby
# test completes, even at 100,000
75 STEP5_EXCLUDES
+= rust
# no catching stack overflows
76 STEP5_EXCLUDES
+= swift3
# no catching stack overflows
77 STEP5_EXCLUDES
+= ocaml
# test completes, even at 1,000,000
78 STEP5_EXCLUDES
+= vb
# completes at 10,000
79 STEP5_EXCLUDES
+= crystal
# test completes, even at 1,000,000
81 PERF_EXCLUDES
= mal
# TODO: fix this
84 # TODO: still need to implement dist
85 DIST_EXCLUDES
+= factor groovy guile io julia matlab miniMAL swift
91 MATLAB
= matlab
-nodisplay
-nosplash
-nodesktop
-nojvm
-r
92 OCTAVE
= octave
--no-gui
-q
--traditional
--eval
93 matlab_args
= $(subst $(SPACE
),$(COMMA
),$(foreach x
,$(strip $(1)),'$(x)'))
94 matlab_cmd
= $(if
$(strip $(USE_MATLAB
)),$(MATLAB
),$(OCTAVE
))
96 haxe_STEP_TO_PROG_neko
= haxe
/$($(1)).n
97 haxe_STEP_TO_PROG_python
= haxe
/$($(1)).py
98 haxe_STEP_TO_PROG_cpp
= haxe
/cpp/$($(1))
99 haxe_STEP_TO_PROG_js
= haxe
/$($(1)).js
101 haxe_RUNSTEP_neko
= neko ..
/$(2) $(3)
102 haxe_RUNSTEP_python
= python3 ..
/$(2) $(3)
103 haxe_RUNSTEP_cpp
= ..
/$(2) $(3)
104 haxe_RUNSTEP_js
= node ..
/$(2) $(3)
106 # Return list of test files for a given step. If REGRESS is set then
107 # test files will include step 2 tests through tests for the step
109 STEP_TEST_FILES
= $(strip $(wildcard \
110 $(foreach s
,$(if
$(strip $(REGRESS
)),$(regress_
$(2)),$(2)),\
111 $(1)/tests
/$($(s
)).mal tests
/$($(s
)).mal
)))
113 # Map of step (e.g. "step8") to executable file for that step
114 awk_STEP_TO_PROG
= awk
/$($(1)).awk
115 bash_STEP_TO_PROG
= bash
/$($(1)).sh
116 c_STEP_TO_PROG
= c
/$($(1))
117 d_STEP_TO_PROG
= d
/$($(1))
118 clojure_STEP_TO_PROG
= clojure
/src
/$($(1)).clj
119 coffee_STEP_TO_PROG
= coffee
/$($(1)).coffee
120 cpp_STEP_TO_PROG
= cpp/$($(1))
121 crystal_STEP_TO_PROG
= crystal
/$($(1))
122 cs_STEP_TO_PROG
= cs
/$($(1)).exe
123 elixir_STEP_TO_PROG
= elixir
/lib
/mix
/tasks
/$($(1)).ex
124 erlang_STEP_TO_PROG
= erlang
/$($(1))
125 es6_STEP_TO_PROG
= es6
/build
/$($(1)).js
126 factor_STEP_TO_PROG
= factor
/$($(1))/$($(1)).factor
127 forth_STEP_TO_PROG
= forth
/$($(1)).fs
128 fsharp_STEP_TO_PROG
= fsharp
/$($(1)).exe
129 go_STEP_TO_PROG
= go
/$($(1))
130 groovy_STEP_TO_PROG
= groovy
/$($(1)).groovy
131 java_STEP_TO_PROG
= java
/target
/classes
/mal
/$($(1)).class
132 haskell_STEP_TO_PROG
= haskell
/$($(1))
133 haxe_STEP_TO_PROG
= $(haxe_STEP_TO_PROG_
$(HAXE_MODE
))
134 julia_STEP_TO_PROG
= julia
/$($(1)).jl
135 js_STEP_TO_PROG
= js
/$($(1)).js
136 kotlin_STEP_TO_PROG
= kotlin
/$($(1)).jar
137 lua_STEP_TO_PROG
= lua
/$($(1)).lua
138 make_STEP_TO_PROG
= make
/$($(1)).mk
139 mal_STEP_TO_PROG
= mal
/$($(1)).mal
140 ocaml_STEP_TO_PROG
= ocaml
/$($(1))
141 matlab_STEP_TO_PROG
= matlab
/$($(1)).m
142 miniMAL_STEP_TO_PROG
= miniMAL
/$($(1)).json
143 nim_STEP_TO_PROG
= nim
/$($(1))
144 perl_STEP_TO_PROG
= perl
/$($(1)).pl
145 php_STEP_TO_PROG
= php
/$($(1)).php
146 ps_STEP_TO_PROG
= ps
/$($(1)).ps
147 python_STEP_TO_PROG
= python
/$($(1)).py
148 r_STEP_TO_PROG
= r
/$($(1)).r
149 racket_STEP_TO_PROG
= racket
/$($(1)).rkt
150 rpython_STEP_TO_PROG
= rpython
/$($(1))
151 ruby_STEP_TO_PROG
= ruby
/$($(1)).rb
152 rust_STEP_TO_PROG
= rust
/target
/release
/$($(1))
153 scala_STEP_TO_PROG
= scala
/$($(1)).scala
154 swift_STEP_TO_PROG
= swift
/$($(1))
155 swift3_STEP_TO_PROG
= swift3
/$($(1))
156 tcl_STEP_TO_PROG
= tcl
/$($(1)).tcl
157 vb_STEP_TO_PROG
= vb
/$($(1)).exe
158 vimscript_STEP_TO_PROG
= vimscript
/$($(1)).vim
159 guile_STEP_TO_PROG
= guile
/$($(1)).scm
162 # Needed some argument munging
165 SPACE
= $(noop
) $(noop
)
166 export FACTOR_ROOTS
:= .
168 # Macro for running a step:
169 # $(1): step (e.g. "stepA")
170 # $(2): program for step (e.g. result of *_STEP_TO_PROG
171 # $(3): program arguments
172 awk_RUNSTEP
= awk
-O
-f ..
/$(2) $(3)
173 bash_RUNSTEP
= bash ..
/$(2) $(3)
174 c_RUNSTEP
= ..
/$(2) $(3)
175 d_RUNSTEP
= ..
/$(2) $(3)
176 clojure_RUNSTEP
= lein with-profile
+$(1) trampoline run
$(3)
177 coffee_RUNSTEP
= coffee ..
/$(2) $(3)
178 cpp_RUNSTEP
= ..
/$(2) $(3)
179 crystal_RUNSTEP
= ..
/$(2) $(3)
180 cs_RUNSTEP
= mono ..
/$(2) --raw
$(3)
181 elixir_RUNSTEP
= mix
$(notdir $(basename $(2))) $(3)
182 erlang_RUNSTEP
= ..
/$(2) $(3)
183 es6_RUNSTEP
= node ..
/$(2) $(3)
184 factor_RUNSTEP
= factor ..
/$(2) $(3)
185 forth_RUNSTEP
= gforth ..
/$(2) $(3)
186 fsharp_RUNSTEP
= mono ..
/$(2) --raw
$(3)
187 go_RUNSTEP
= ..
/$(2) $(3)
188 groovy_RUNSTEP
= groovy ..
/$(2) $(3)
189 # needs TERM=dumb to work with readline
190 guile_RUNSTEP
= guile
--no-auto-compile
-L ..
/guile ..
/$(2) $(3)
191 haskell_RUNSTEP
= ..
/$(2) $(3)
192 haxe_RUNSTEP
= python3 ..
/$(2) $(3)
193 haxe_RUNSTEP
= $(haxe_RUNSTEP_
$(HAXE_MODE
))
194 java_RUNSTEP
= mvn
-quiet exec
:java
-Dexec.mainClass
="mal.$($(1))" $(if
$(3), -Dexec.args
="$(3)",)
195 julia_RUNSTEP
= ..
/$(2) $(3)
196 js_RUNSTEP
= node ..
/$(2) $(3)
197 kotlin_RUNSTEP
= java
-jar ..
/$(2) $(3)
198 lua_RUNSTEP
= ..
/$(2) $(3)
199 make_RUNSTEP
= make
-f ..
/$(2) $(3)
200 mal_RUNSTEP
= $(call
$(MAL_IMPL
)_RUNSTEP
,stepA
,$(call
$(MAL_IMPL
)_STEP_TO_PROG
,stepA
),..
/$(2),") #"
201 ocaml_RUNSTEP
= ..
/$(2) $(3)
202 matlab_RUNSTEP
= $(matlab_cmd
) "$($(1))($(call matlab_args,$(3)));quit;"
203 miniMAL_RUNSTEP
= miniMAL ..
/$(2) $(3)
204 nim_RUNSTEP
= ..
/$(2) $(3)
205 perl_RUNSTEP
= perl ..
/$(2) $(3)
206 php_RUNSTEP
= php ..
/$(2) $(3)
207 ps_RUNSTEP
= gs
-q
-I.
/ -dNODISPLAY
-- ..
/$(2) $(3)
208 python_RUNSTEP
= $(PYTHON
) ..
/$(2) $(3)
209 r_RUNSTEP
= Rscript ..
/$(2) $(3)
210 racket_RUNSTEP
= ..
/$(2) $(3)
211 rpython_RUNSTEP
= ..
/$(2) $(3)
212 ruby_RUNSTEP
= ruby ..
/$(2) $(3)
213 rust_RUNSTEP
= ..
/$(2) $(3)
214 scala_RUNSTEP
= sbt
'run-main $($(1))$(if $(3), $(3),)'
215 swift_RUNSTEP
= ..
/$(2) $(3)
216 swift3_RUNSTEP
= ..
/$(2) $(3)
217 tcl_RUNSTEP
= tclsh ..
/$(2) --raw
$(3)
218 vb_RUNSTEP
= mono ..
/$(2) --raw
$(3)
219 vimscript_RUNSTEP
= .
/run_vimscript.sh ..
/$(2) $(3)
222 vimscript_TEST_OPTS
= --test-timeout
30
223 ifeq ($(MAL_IMPL
),vimscript
)
224 mal_TEST_OPTS
= --start-timeout
60 --test-timeout
180
228 STEPS
= $(sort $(filter step
%,$(.VARIABLES
)))
229 DO_IMPLS
= $(filter-out $(SKIP_IMPLS
),$(IMPLS
))
230 IMPL_TESTS
= $(foreach impl
,$(DO_IMPLS
),test^
$(impl
))
231 STEP_TESTS
= $(foreach step
,$(STEPS
),test^
$(step
))
232 ALL_TESTS
= $(filter-out $(foreach impl
,$(STEP5_EXCLUDES
),test^
$(impl
)^step5
),\
234 $(foreach impl
,$(DO_IMPLS
),\
235 $(foreach step
,$(STEPS
),test^
$(impl
)^
$(step
))))))
237 IMPL_STATS
= $(foreach impl
,$(DO_IMPLS
),stats^
$(impl
))
238 IMPL_STATS_LISP
= $(foreach impl
,$(DO_IMPLS
),stats-lisp^
$(impl
))
240 IMPL_DIST
= $(filter-out $(foreach impl
,$(DIST_EXCLUDES
),dist^
$(impl
)),\
241 $(foreach impl
,$(DO_IMPLS
),dist^
$(impl
)))
243 DOCKER_BUILD
= $(foreach impl
,$(DO_IMPLS
),docker-build^
$(impl
))
245 IMPL_PERF
= $(foreach impl
,$(filter-out $(PERF_EXCLUDES
),$(DO_IMPLS
)),perf^
$(impl
))
247 IMPL_REPL
= $(foreach impl
,$(DO_IMPLS
),repl^
$(impl
))
248 ALL_REPL
= $(strip $(sort \
249 $(foreach impl
,$(DO_IMPLS
),\
250 $(foreach step
,$(STEPS
),repl^
$(impl
)^
$(step
)))))
256 # Build a program in an implementation directory
257 # Make sure we always try and build first because the dependencies are
258 # encoded in the implementation Makefile not here
259 .PHONY
: $(foreach i
,$(DO_IMPLS
),$(foreach s
,$(STEPS
),$(call
$(i
)_STEP_TO_PROG
,$(s
))))
260 $(foreach i
,$(DO_IMPLS
),$(foreach s
,$(STEPS
),$(call
$(i
)_STEP_TO_PROG
,$(s
)))):
261 $(foreach impl
,$(word 1,$(subst /, ,$(@
))),\
262 $(MAKE
) -C
$(impl
) $(subst $(impl
)/,,$(@
)))
264 # Allow test, test^STEP, test^IMPL, and test^IMPL^STEP
266 $(IMPL_TESTS
): $$(filter $$@^
%,$$(ALL_TESTS
))
269 $(STEP_TESTS
): $$(foreach step
,$$(subst test^
,,$$@
),$$(filter %^
$$(step
),$$(ALL_TESTS
)))
272 $(ALL_TESTS
): $$(call
$$(word 2,$$(subst ^
, ,$$(@
)))_STEP_TO_PROG
,$$(word 3,$$(subst ^
, ,$$(@
))))
273 @
$(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
274 $(foreach step
,$(word 3,$(subst ^
, ,$(@
))),\
275 cd
$(if
$(filter mal
,$(impl
)),$(MAL_IMPL
),$(impl
)); \
276 $(foreach test,$(call STEP_TEST_FILES
,$(impl
),$(step
)),\
277 echo
'----------------------------------------------'; \
278 echo
'Testing $@, step file: $+, test file: $(test)'; \
279 echo
'Running: ../runtest.py $(TEST_OPTS) $(call $(impl)_TEST_OPTS) ../$(test) -- $(call $(impl)_RUNSTEP,$(step),$(+))'; \
280 ..
/runtest.py
$(TEST_OPTS
) $(call
$(impl
)_TEST_OPTS
) ..
/$(test) -- $(call
$(impl
)_RUNSTEP
,$(step
),$(+));)))
289 stats-lisp
: $(IMPL_STATS_LISP
)
293 @echo
"----------------------------------------------"; \
294 $(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
295 echo
"Stats for $(impl):"; \
296 $(MAKE
) --no-print-directory
-C
$(impl
) stats
)
300 @echo
"----------------------------------------------"; \
301 $(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
302 echo
"Stats (lisp only) for $(impl):"; \
303 $(MAKE
) --no-print-directory
-C
$(impl
) stats-lisp
)
311 @echo
"----------------------------------------------"; \
312 $(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
313 echo
"Running: make -C $(impl) dist"; \
314 $(MAKE
) --no-print-directory
-C
$(impl
) dist)
318 docker-build
: $(DOCKER_BUILD
)
322 echo
"----------------------------------------------"; \
323 $(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
324 echo
"Running: docker build -t kanaka/mal-test-$(impl) .:"; \
325 cd
$(impl
) && docker build
-t kanaka
/mal-test-
$(impl
) .
)
327 # Performance test rules
333 @echo
"----------------------------------------------"; \
334 $(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
335 cd
$(if
$(filter mal
,$(impl
)),$(MAL_IMPL
),$(impl
)); \
336 echo
"Performance test for $(impl):"; \
337 echo
'Running: $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf1.mal)'; \
338 $(call
$(impl
)_RUNSTEP
,stepA
,$(call
$(impl
)_STEP_TO_PROG
,stepA
),..
/tests
/perf1.mal
); \
339 echo
'Running: $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf2.mal)'; \
340 $(call
$(impl
)_RUNSTEP
,stepA
,$(call
$(impl
)_STEP_TO_PROG
,stepA
),..
/tests
/perf2.mal
); \
341 echo
'Running: $(call $(impl)_RUNSTEP,stepA,$(call $(impl)_STEP_TO_PROG,stepA),../tests/perf3.mal)'; \
342 $(call
$(impl
)_RUNSTEP
,stepA
,$(call
$(impl
)_STEP_TO_PROG
,stepA
),..
/tests
/perf3.mal
))
344 # REPL invocation rules
345 # Allow repl^IMPL^STEP and repl^IMPL (which starts REPL of stepA)
348 $(IMPL_REPL
): $$@^stepA
351 $(ALL_REPL
): $$(call
$$(word 2,$$(subst ^
, ,$$(@
)))_STEP_TO_PROG
,$$(word 3,$$(subst ^
, ,$$(@
))))
352 @
$(foreach impl
,$(word 2,$(subst ^
, ,$(@
))),\
353 $(foreach step
,$(word 3,$(subst ^
, ,$(@
))),\
354 cd
$(if
$(filter mal
,$(impl
)),$(MAL_IMPL
),$(impl
)); \
355 echo
'REPL implementation $(impl), step file: $+'; \
356 echo
'Running: $(call $(impl)_RUNSTEP,$(step),$(+))'; \
357 $(call
$(impl
)_RUNSTEP
,$(step
),$(+));))