run_tests.sh 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. #!/bin/sh
  2. # Step-1 regression: M2 -> gen_ssa/*.ssa -> qbe -> cc -> exit code.
  3. # Usage: ./run_tests.sh (from the compiler directory)
  4. pass=0; fail=0
  5. modof() {
  6. sed -n 's/^MODULE \([A-Za-z][A-Za-z0-9]*\).*/\1/p' "tests/$1" | head -n 1
  7. }
  8. expect_run() {
  9. # $1 = test file (no dir), $2 = expected exit code
  10. name="$1"; want="$2"; mod=$(modof "$name")
  11. rm -f "gen_ssa/$mod.ssa" "gen_ssa/$mod.s" "gen_ssa/$mod"
  12. if ./M2 "tests/$name" 2>&1 | grep -q "Parsed correctly"; then :; else
  13. fail=$((fail+1)); echo "FAIL(run): $name rejected"; return
  14. fi
  15. if [ ! -f "gen_ssa/$mod.ssa" ]; then
  16. fail=$((fail+1)); echo "FAIL(run): $name no gen_ssa/$mod.ssa"; return
  17. fi
  18. if ! qbe -o "gen_ssa/$mod.s" "gen_ssa/$mod.ssa" 2> "gen_ssa/$mod.qbeerr"; then
  19. fail=$((fail+1)); echo "FAIL(run): $name qbe:"; cat "gen_ssa/$mod.qbeerr"; return
  20. fi
  21. if ! cc "gen_ssa/$mod.s" -o "gen_ssa/$mod" 2> "gen_ssa/$mod.ccerr"; then
  22. fail=$((fail+1)); echo "FAIL(run): $name cc:"; cat "gen_ssa/$mod.ccerr"; return
  23. fi
  24. timeout 10 "gen_ssa/$mod" > /dev/null 2>&1; got=$?
  25. if [ "$got" = "$want" ]; then
  26. pass=$((pass+1)); echo "PASS(run): $name -> $got"
  27. else
  28. fail=$((fail+1)); echo "FAIL(run): $name got $got want $want"
  29. fi
  30. }
  31. expect_fail() {
  32. # $1 = test file, $2 = message text expected in the .LST
  33. name="$1"; want="$2"
  34. if ./M2 "tests/$name" 2>&1 | grep -q "Incorrect source"; then :; else
  35. fail=$((fail+1)); echo "FAIL(fail): $name accepted"; return
  36. fi
  37. lst="tests/$(basename "$name" .mod).LST"
  38. if grep -q "$want" "$lst" 2>/dev/null; then
  39. pass=$((pass+1)); echo "PASS(fail): $name [$want]"
  40. else
  41. fail=$((fail+1)); echo "FAIL(fail): [$want] not found in $lst"
  42. fi
  43. }
  44. mkdir -p gen_ssa
  45. expect_run t_minimal.mod 0
  46. expect_run t_exit.mod 7
  47. expect_run t_arith.mod 25
  48. expect_run showcase1.mod 50
  49. expect_run t_types.mod 8
  50. expect_run showcase2.mod 71
  51. expect_run t_if.mod 25
  52. expect_run t_while.mod 55
  53. expect_run t_repeat.mod 55
  54. expect_run t_loop.mod 55
  55. expect_run t_for.mod 85
  56. expect_run t_case.mod 103
  57. expect_run t_bool.mod 42
  58. expect_run t_real.mod 31
  59. expect_run t_array.mod 108
  60. expect_run t_highlen.mod 18
  61. expect_run t_builtins.mod 42
  62. expect_run t_long.mod 42
  63. expect_run t_charbounds.mod 3
  64. expect_run t_record.mod 160
  65. expect_run t_with.mod 114
  66. expect_run t_set.mod 131
  67. expect_run t_setchar.mod 77
  68. expect_run t_setrange.mod 55
  69. expect_fail t_classdef.mod "not supported yet"
  70. expect_fail t_class.mod "not supported yet"
  71. expect_fail t_bad_parent.mod "undeclared identifier"
  72. expect_run showcase3.mod 183
  73. expect_run showcase4.mod 44
  74. expect_fail showcase5.mod "not supported yet"
  75. expect_run showcase6.mod 34
  76. expect_run showcase7.mod 219
  77. expect_run showcase8.mod 170
  78. expect_run showcase9.mod 140
  79. expect_run showcase10.mod 86
  80. expect_run t_pointer.mod 42
  81. expect_run t_ptrarray.mod 15
  82. expect_run t_ptrrec.mod 15
  83. expect_run t_ptrnest.mod 10
  84. expect_fail t_opaqueptr.mod ""
  85. expect_fail t_enumdecl.mod "not supported yet"
  86. expect_run t_proc.mod 0
  87. expect_run t_forward.mod 0
  88. expect_run t_call.mod 125
  89. expect_run t_varpar.mod 40
  90. expect_run t_mutual.mod 11
  91. expect_run t_withfield.mod 13
  92. expect_run t_valarray.mod 6
  93. expect_run t_openarr.mod 7
  94. expect_run t_nestedproc.mod 20
  95. expect_run t_nestdeep.mod 211
  96. expect_run t_nestrec.mod 15
  97. expect_fail t_bad_undecl.mod "undeclared identifier"
  98. expect_fail t_bad_dup.mod "duplicate identifier"
  99. expect_fail t_bad_mismatch.mod "module name mismatch"
  100. expect_fail t_bad_opaque.mod "opaque type outside definition"
  101. expect_fail t_bad_while.mod "BOOLEAN condition required"
  102. expect_fail t_bad_exit.mod "not supported yet"
  103. expect_fail t_bad_return.mod "bad RETURN"
  104. expect_fail t_bad_for.mod "FOR needs integer variable and bounds"
  105. expect_fail t_bad_mixed.mod "incompatible assignment"
  106. expect_fail t_bad_arity.mod "invalid call"
  107. expect_fail t_bad_actual.mod "invalid call"
  108. expect_fail t_bad_funstmt.mod "invalid call"
  109. expect_fail t_bad_deref.mod "not a POINTER type"
  110. expect_fail t_bad_new.mod "not a POINTER type"
  111. expect_fail t_bad_field.mod "unknown field"
  112. expect_fail t_bad_with.mod "not a RECORD type"
  113. expect_fail t_bad_recassign.mod "incompatible assignment"
  114. expect_fail t_bad_setelem.mod "set operand mismatch"
  115. expect_fail t_bad_setbase.mod "not supported yet"
  116. expect_fail t_bad_in.mod "set operand mismatch"
  117. expect_fail t_bad_index.mod "array index must be integer"
  118. expect_fail t_bad_bounds.mod "not supported yet"
  119. expect_fail t_bad_varbound.mod "not supported yet"
  120. expect_fail t_bad_manydims.mod "not supported yet"
  121. expect_fail t_openformal.mod "not supported yet"
  122. expect_fail t_bad_open.mod "not supported yet"
  123. expect_trap() {
  124. # $1 = test file — must parse, assemble, link, then abort (rc=134)
  125. name="$1"; mod=$(modof "$name")
  126. rm -f "gen_ssa/$mod.ssa" "gen_ssa/$mod.s" "gen_ssa/$mod"
  127. if ./M2 "tests/$name" 2>&1 | grep -q "Parsed correctly"; then :; else
  128. fail=$((fail+1)); echo "FAIL(trap): $name rejected"; return
  129. fi
  130. if ! qbe -o "gen_ssa/$mod.s" "gen_ssa/$mod.ssa" 2> "gen_ssa/$mod.qbeerr"; then
  131. fail=$((fail+1)); echo "FAIL(trap): $name qbe"; return
  132. fi
  133. if ! cc "gen_ssa/$mod.s" -o "gen_ssa/$mod" 2> "gen_ssa/$mod.ccerr"; then
  134. fail=$((fail+1)); echo "FAIL(trap): $name cc"; return
  135. fi
  136. timeout 10 "gen_ssa/$mod" > /dev/null 2>&1; got=$?
  137. if [ "$got" = "134" ]; then
  138. pass=$((pass+1)); echo "PASS(trap): $name -> abort"
  139. else
  140. fail=$((fail+1)); echo "FAIL(trap): $name rc=$got want 134"
  141. fi
  142. }
  143. expect_trap t_trap_index.mod
  144. expect_trap t_trap_count.mod
  145. expect_trap t_trap_setspan.mod
  146. expect_trap t_trap_emptystr.mod
  147. expect_fail t_defunit.mod ""
  148. expect_fail t_implunit.mod ""
  149. expect_fail t_nested.mod "not supported yet"
  150. # --- separate compilation (step 4.3): $1 prog module, $2 exit code,
  151. # then the session's source files (program last by convention) ---
  152. SHIM="../runtime/syslib/shim.c"
  153. # Build a session image; echoes 0 on success, non-zero on failure.
  154. build_session() {
  155. prog="$1"; shift
  156. files=""
  157. for f in "$@"; do
  158. case "$f" in */*) files="$files $f";; *) files="$files tests/$f";; esac
  159. done
  160. rm -f "gen_ssa/$prog.ssa" "gen_ssa/$prog.s" "gen_ssa/$prog"
  161. if ./M2 $files 2>&1 | grep -q "Parsed correctly"; then :; else
  162. echo "rejected"; return 1
  163. fi
  164. [ -f "gen_ssa/$prog.ssa" ] || { echo "no image"; return 1; }
  165. qbe -o "gen_ssa/$prog.s" "gen_ssa/$prog.ssa" 2> "gen_ssa/$prog.qbeerr" \
  166. || { echo "qbe"; cat "gen_ssa/$prog.qbeerr"; return 1; }
  167. cc "gen_ssa/$prog.s" "$SHIM" -o "gen_ssa/$prog" -lm 2> "gen_ssa/$prog.ccerr" \
  168. || { echo "cc"; cat "gen_ssa/$prog.ccerr"; return 1; }
  169. return 0
  170. }
  171. expect_run_files() {
  172. prog="$1"; want="$2"; shift 2
  173. if ! build_session "$prog" "$@"; then
  174. fail=$((fail+1)); echo "FAIL(session): $prog $? ($(build_session "$prog" "$@" 2>&1))"; return
  175. fi
  176. timeout 10 "gen_ssa/$prog" > /dev/null 2>&1; got=$?
  177. if [ "$got" = "$want" ]; then
  178. pass=$((pass+1)); echo "PASS(session): $prog -> $got"
  179. else
  180. fail=$((fail+1)); echo "FAIL(session): $prog got $got want $want"
  181. fi
  182. }
  183. expect_run_files_out() {
  184. # $1 prog, $2 exit code, $3 expected first output line, then files
  185. prog="$1"; want="$2"; wantline="$3"; shift 3
  186. if ! build_session "$prog" "$@"; then
  187. fail=$((fail+1)); echo "FAIL(session-out): $prog build failed"; return
  188. fi
  189. out=$(timeout 10 "gen_ssa/$prog" 2>/dev/null); got=$?
  190. first=$(printf '%s\n' "$out" | head -n 1)
  191. if [ "$got" = "$want" ] && [ "$first" = "$wantline" ]; then
  192. pass=$((pass+1)); echo "PASS(session-out): $prog -> $got [$first]"
  193. else
  194. fail=$((fail+1)); echo "FAIL(session-out): $prog rc=$got line=[$first] want=[$wantline]"
  195. fi
  196. }
  197. expect_run_files DBasicProg 49 d_basic.def d_basic.mod d_basic_prog.mod
  198. expect_run_files DQualProg 46 d_basic.def d_basic.mod d_qual_prog.mod
  199. expect_run_files DTypesProg 36 d_types.def d_types.mod d_types_prog.mod
  200. expect_run_files DOpaqueProg 55 d_opaque.def d_opaque.mod d_opaque_prog.mod
  201. expect_run_files StorageProg 42 ../stdlib/storage.def ../stdlib/storage.mod storage_prog.mod
  202. expect_run_files ClashProg 60 d_clash_a.def d_clash_a.mod d_clash_b.def d_clash_b.mod d_clash_prog.mod
  203. expect_run_files_out Hello 0 "Hello, Modula-2!" ../stdlib/sysio.def ../stdlib/sysio.mod hello.mod
  204. expect_run_files_out StringsProg 0 "Hello World" ../stdlib/sysio.def ../stdlib/sysio.mod ../stdlib/strings.def ../stdlib/strings.mod strings_prog.mod
  205. expect_run_files MathProg 12 ../stdlib/sysio.def ../stdlib/sysio.mod ../stdlib/math.def ../stdlib/math.mod math_prog.mod
  206. expect_run_files_in() {
  207. # $1 prog, $2 exit code, $3 expected first line, $4 stdin, then files
  208. prog="$1"; want="$2"; wantline="$3"; input="$4"; shift 4
  209. if ! build_session "$prog" "$@"; then
  210. fail=$((fail+1)); echo "FAIL(session-in): $prog build failed"; return
  211. fi
  212. out=$(printf '%s\n' "$input" | timeout 10 "gen_ssa/$prog" 2>/dev/null); got=$?
  213. first=$(printf '%s\n' "$out" | head -n 1)
  214. if [ "$got" = "$want" ] && [ "$first" = "$wantline" ]; then
  215. pass=$((pass+1)); echo "PASS(session-in): $prog -> $got [$first]"
  216. else
  217. fail=$((fail+1)); echo "FAIL(session-in): $prog rc=$got line=[$first] want=[$wantline]"
  218. fi
  219. }
  220. expect_run_files_in ReadProg 0 "42" "20 22" ../stdlib/sysio.def ../stdlib/sysio.mod read_prog.mod
  221. expect_run_files_in WholeIOProg 0 "42" "6 7" ../stdlib/sysio.def ../stdlib/sysio.mod ../stdlib/wholeio.def ../stdlib/wholeio.mod wholeio_prog.mod
  222. expect_run_files FilesProg 42 ../stdlib/files.def ../stdlib/files.mod files_prog.mod
  223. rm -f gen_ssa/_files_tmp.txt
  224. expect_run_files_in Showcase11 80 "Modula-2" "42" \
  225. ../stdlib/sysio.def ../stdlib/sysio.mod \
  226. ../stdlib/textio.def ../stdlib/textio.mod \
  227. ../stdlib/wholeio.def ../stdlib/wholeio.mod \
  228. ../stdlib/strings.def ../stdlib/strings.mod \
  229. ../stdlib/math.def ../stdlib/math.mod \
  230. ../stdlib/files.def ../stdlib/files.mod \
  231. showcase11.mod
  232. rm -f gen_ssa/_showcase11.txt
  233. expect_run_files_out MixProg 0 "7" ../stdlib/textio.def ../stdlib/textio.mod ../stdlib/sysio.def ../stdlib/sysio.mod ../stdlib/files.def ../stdlib/files.mod d_mix_prog.mod
  234. rm -f gen_ssa/_mix.txt
  235. expect_fail_files() {
  236. # $1 = listing basename, $2 = message (may be empty), then files
  237. lst="$1"; want="$2"; shift 2
  238. files=""
  239. for f in "$@"; do files="$files tests/$f"; done
  240. if ./M2 $files 2>&1 | grep -q "Incorrect source"; then :; else
  241. fail=$((fail+1)); echo "FAIL(session-rej): $lst accepted"; return
  242. fi
  243. if [ -z "$want" ]; then
  244. pass=$((pass+1)); echo "PASS(session-rej): $lst"
  245. elif grep -q "$want" "tests/$lst.LST" 2>/dev/null; then
  246. pass=$((pass+1)); echo "PASS(session-rej): $lst [$want]"
  247. else
  248. fail=$((fail+1)); echo "FAIL(session-rej): [$want] not in tests/$lst.LST"
  249. fi
  250. }
  251. expect_fail_files d_badimp_prog "undeclared identifier" d_basic.def d_basic.mod d_badimp_prog.mod
  252. echo "--- $pass passed, $fail failed ---"
  253. [ "$fail" -eq 0 ]