gm2-probes.sh 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. #!/bin/sh
  2. # gm2-probes.sh -- what GNU Modula-2 (Gm2) accepts, measured.
  3. #
  4. # WHY THIS EXISTS
  5. # Porting Resources/TP3/CALC.PAS to Gnu Modula-2 needs to know which
  6. # ISO Modula-2 constructs the toolchain actually supports, because CALC
  7. # leans on several of them. Rather than assume, this script compiles one
  8. # minimal module per construct and records accept/reject.
  9. #
  10. # It is an ASSERTION, not a report: EXPECTED below is what was measured on
  11. # this machine. If a future Gm2 gains (or loses) a construct, this goes red
  12. # and the difference is printed. Re-baseline deliberately -- do not edit
  13. # EXPECTED to make a failure disappear.
  14. #
  15. # MEASURED ON
  16. # gm2 (GCC) 16.0.1 20260325 (experimental), invoked -fiso -Wall
  17. # /home/eric/bin/Modula2/Gm2/bin/gm2
  18. #
  19. # USAGE
  20. # sh calc-port/gm2-probes.sh report, and check against EXPECTED
  21. # sh calc-port/gm2-probes.sh --bless re-baseline EXPECTED from what it sees
  22. #
  23. # NOTE ON WRITING PROBE FILES
  24. # Use the heredocs below (quoted delimiter, so ' survives). Do NOT try to
  25. # build these with `printf '%s' "$src"` -- %s does not expand \n, so the
  26. # module lands on one line and every diagnostic becomes nonsense. Use
  27. # `printf "$fmt"` with \n in the FORMAT, or a heredoc.
  28. GM2=${GM2:-/home/eric/bin/Modula2/Gm2/bin/gm2}
  29. DIR=$(mktemp -d "${TMPDIR:-/tmp}/gm2probe.XXXXXX") || exit 1
  30. trap 'rm -rf "$DIR"' EXIT
  31. BLESS=no
  32. [ "$1" = "--bless" ] && BLESS=yes
  33. # ---------------------------------------------------------------- probes ----
  34. # name : expect(accept|reject) : one-line description
  35. # Each probe is the smallest module that exercises exactly one construct.
  36. emit() { cat > "$DIR/$1.mod"; }
  37. emit char_literal <<'EOF'
  38. MODULE char_literal;
  39. VAR c : CHAR;
  40. BEGIN c := 'A' END char_literal.
  41. EOF
  42. emit array_of_char <<'EOF'
  43. MODULE array_of_char;
  44. VAR s : ARRAY [0..70] OF CHAR;
  45. BEGIN s [0] := 'x' END array_of_char.
  46. EOF
  47. emit string_into_char_array <<'EOF'
  48. MODULE string_into_char_array;
  49. VAR s : ARRAY [0..5] OF CHAR;
  50. BEGIN s := "ABS" END string_into_char_array.
  51. EOF
  52. emit array_subrange_bound <<'EOF'
  53. MODULE array_subrange_bound;
  54. VAR a : ARRAY [0..20] OF INTEGER;
  55. BEGIN a [0] := 1 END array_subrange_bound.
  56. EOF
  57. emit nested_proc_forward <<'EOF'
  58. MODULE nested_proc_forward;
  59. PROCEDURE Go (n : INTEGER);
  60. PROCEDURE H (x : INTEGER) : BOOLEAN; FORWARD;
  61. PROCEDURE O (x : INTEGER);
  62. BEGIN IF H (x) THEN END END O;
  63. PROCEDURE H (x : INTEGER) : BOOLEAN;
  64. BEGIN RETURN x > 0 END H;
  65. BEGIN O (n) END Go;
  66. BEGIN Go (4) END nested_proc_forward.
  67. EOF
  68. emit nested_function <<'EOF'
  69. MODULE nested_function;
  70. PROCEDURE Go (n : INTEGER);
  71. FUNCTION F (x : INTEGER) : INTEGER;
  72. BEGIN RETURN x END F;
  73. BEGIN n := F (n) END Go;
  74. BEGIN Go (4) END nested_function.
  75. EOF
  76. emit named_shortsubrange <<'EOF'
  77. MODULE named_shortsubrange;
  78. TYPE Dec = 0..20;
  79. VAR d : Dec;
  80. BEGIN d := 2 END named_shortsubrange.
  81. EOF
  82. emit inline_shortsubrange <<'EOF'
  83. MODULE inline_shortsubrange;
  84. VAR d : 0..20;
  85. BEGIN d := 2 END inline_shortsubrange.
  86. EOF
  87. emit char_subrange_type <<'EOF'
  88. MODULE char_subrange_type;
  89. TYPE Col = 'A'..'G';
  90. VAR c : Col;
  91. BEGIN c := 'A' END char_subrange_type.
  92. EOF
  93. emit enum_indexed_array <<'EOF'
  94. MODULE enum_indexed_array;
  95. TYPE Sf = (fabs, fsqrt, fsqr);
  96. Nm = ARRAY [Sf] OF ARRAY [0..5] OF CHAR;
  97. VAR c : CHAR;
  98. BEGIN c := Nm [fsqrt] [1] END enum_indexed_array.
  99. EOF
  100. emit set_of_char_literal <<'EOF'
  101. MODULE set_of_char_literal;
  102. VAR c : CHAR; b : BOOLEAN;
  103. BEGIN b := c IN {'0'..'9'} END set_of_char_literal.
  104. EOF
  105. emit bitset_instead_of_set <<'EOF'
  106. MODULE bitset_instead_of_set;
  107. (* CALC's `CellStatus : set of Attributes` and `Numbers : set of Char`
  108. have no SET OF here; BITSET + INCL + membership is the replacement. *)
  109. VAR b : BITSET;
  110. BEGIN
  111. b := {};
  112. INCL (b, 2);
  113. IF 2 IN b THEN INCL (b, 3) END
  114. END bitset_instead_of_set.
  115. EOF
  116. emit char_range_comparisons <<'EOF'
  117. MODULE char_range_comparisons;
  118. VAR c : CHAR; b : BOOLEAN;
  119. BEGIN b := (c >= '0') AND (c <= '9') END char_range_comparisons.
  120. EOF
  121. # ------------------------------------------------------------- expected -----
  122. # name:expect -- measured on gm2 16.0.1 -fiso, 2026-10-05
  123. cat > "$DIR/EXPECTED" <<'EOF'
  124. char_literal:accept
  125. array_of_char:accept
  126. string_into_char_array:accept
  127. array_subrange_bound:accept
  128. nested_proc_forward:accept
  129. nested_function:reject
  130. named_shortsubrange:reject
  131. inline_shortsubrange:reject
  132. char_subrange_type:reject
  133. enum_indexed_array:reject
  134. set_of_char_literal:reject
  135. bitset_instead_of_set:accept
  136. char_range_comparisons:accept
  137. EOF
  138. # ----------------------------------------------------------------- run ------
  139. echo "gm2: $("$GM2" --version 2>&1 | head -1)"
  140. echo
  141. bad=0
  142. for spec in \
  143. "char_literal:accept" \
  144. "array_of_char:accept" \
  145. "string_into_char_array:accept" \
  146. "array_subrange_bound:accept" \
  147. "nested_proc_forward:accept" \
  148. "nested_function:reject" \
  149. "named_shortsubrange:reject" \
  150. "inline_shortsubrange:reject" \
  151. "char_subrange_type:reject" \
  152. "enum_indexed_array:reject" \
  153. "set_of_char_literal:reject" \
  154. "bitset_instead_of_set:accept" \
  155. "char_range_comparisons:accept"
  156. do
  157. name=${spec%%:*}
  158. want=${spec##*:}
  159. err=$("$GM2" -fiso -Wall -o "$DIR/$name" "$DIR/$name.mod" 2>&1 |
  160. grep ": error" | head -1)
  161. if [ -z "$err" ]; then got=accept; else got=reject; fi
  162. mark=" "
  163. if [ "$got" != "$want" ]; then mark="!! "; bad=$((bad+1)); fi
  164. printf '%s%-24s want=%-6s got=%-6s' "$mark" "$name" "$want" "$got"
  165. if [ -n "$err" ]; then
  166. printf ' %s' "$(printf '%s' "$err" | sed 's/.*error: //')"
  167. fi
  168. echo
  169. done
  170. echo
  171. if [ "$BLESS" = yes ]; then
  172. echo "--bless: EXPECTED is written from what was just measured:"
  173. for spec in \
  174. "char_literal" "array_of_char" "string_into_char_array" \
  175. "array_subrange_bound" "nested_proc_forward" "nested_function" \
  176. "named_shortsubrange" "inline_shortsubrange" "char_subrange_type" \
  177. "enum_indexed_array" "set_of_char_literal" "bitset_instead_of_set" \
  178. "char_range_comparisons"
  179. do
  180. name=$spec
  181. err=$("$GM2" -fiso -Wall -o "$DIR/$name" "$DIR/$name.mod" 2>&1 |
  182. grep ": error" | head -1)
  183. if [ -z "$err" ]; then echo "$name:accept"; else echo "$name:reject"; fi
  184. done
  185. exit 0
  186. fi
  187. if [ "$bad" -eq 0 ]; then
  188. echo "PASS: all 13 constructs match what this Gm2 was measured to do"
  189. exit 0
  190. fi
  191. echo "FAIL: $bad construct(s) differ from EXPECTED -- Gm2 may have changed."
  192. echo " Re-run with --bless only if the new behaviour is understood."
  193. exit 1