CompileTest.mod 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. MODULE CompileTest ;
  2. (* Direct test harness for the TP3 compiler.
  3. Reads fixture paths from stdin, one per line, loads each into TextBuf
  4. exactly the way the shell's LoadWorkFile does, then calls Compiler.Compile
  5. and prints a one-line verdict plus a source excerpt with a caret under the
  6. error position.
  7. This is the fast loop for compiler work: no pty, no editor, no screen
  8. redraws - just Compile's own errNo / errPos, which is what actually
  9. matters. (The pty harness in matrix.py covers the shell/editor UI.)
  10. Usage: printf 'a.pas\nb.pas\n' | ./compiletest *)
  11. FROM Posix IMPORT read, write, open, close ;
  12. FROM TextBuf IMPORT TextLimit, Clear, Length, CharAt, InsertCh ;
  13. FROM Compiler IMPORT Compile, CodeBytes, DataBytes, CodeByteAt,
  14. ImageBytes, ImageByteAt, DataBase ;
  15. FROM SYSTEM IMPORT ADR, BYTE ;
  16. CONST
  17. STDIN = 0 ;
  18. STDOUT = 1 ;
  19. O_RDONLY = 0 ;
  20. VAR
  21. lineBuf : ARRAY [0..255] OF CHAR ;
  22. pathCopy : ARRAY [0..511] OF CHAR ;
  23. txt : ARRAY [0..79] OF CHAR ;
  24. mark : ARRAY [0..79] OF CHAR ;
  25. PROCEDURE PutCh (ch : CHAR) ;
  26. VAR n : LONGINT ;
  27. BEGIN
  28. n := write (STDOUT, ADR (ch), 1)
  29. END PutCh ;
  30. PROCEDURE PutStr (s : ARRAY OF CHAR) ;
  31. VAR i : CARDINAL ; n : LONGINT ;
  32. BEGIN
  33. i := 0 ;
  34. WHILE (i <= HIGH (s)) AND (s [i] # 0C) DO
  35. n := write (STDOUT, ADR (s [i]), 1) ;
  36. INC (i)
  37. END
  38. END PutStr ;
  39. PROCEDURE PutCard (n : CARDINAL) ;
  40. VAR dig : ARRAY [0..9] OF CHAR ; i : CARDINAL ;
  41. BEGIN
  42. IF n = 0 THEN
  43. PutCh ("0")
  44. ELSE
  45. i := 0 ;
  46. WHILE n > 0 DO
  47. dig [i] := CHR (ORD ("0") + (n MOD 10)) ;
  48. n := n DIV 10 ;
  49. INC (i)
  50. END ;
  51. WHILE i > 0 DO
  52. DEC (i) ;
  53. PutCh (dig [i])
  54. END
  55. END
  56. END PutCard ;
  57. PROCEDURE NL ;
  58. BEGIN
  59. PutCh (CHR (13)) ;
  60. PutCh (CHR (10))
  61. END NL ;
  62. PROCEDURE StrCopy (VAR dst : ARRAY OF CHAR ; src : ARRAY OF CHAR) ;
  63. VAR i : CARDINAL ;
  64. BEGIN
  65. i := 0 ;
  66. WHILE (i <= HIGH (dst)) AND (i <= HIGH (src)) AND (src [i] # 0C) DO
  67. dst [i] := src [i] ;
  68. INC (i)
  69. END ;
  70. IF i <= HIGH (dst) THEN
  71. dst [i] := 0C
  72. END
  73. END StrCopy ;
  74. PROCEDURE ReadLineStr (VAR s : ARRAY OF CHAR) : BOOLEAN ;
  75. (* one line from stdin; FALSE at EOF/blank line *)
  76. VAR ch : CHAR ; n : LONGINT ; i : CARDINAL ;
  77. BEGIN
  78. i := 0 ;
  79. s [0] := 0C ;
  80. LOOP
  81. n := read (STDIN, ADR (ch), 1) ;
  82. IF n # 1 THEN
  83. IF i = 0 THEN
  84. RETURN FALSE
  85. END ;
  86. s [i] := 0C ;
  87. RETURN TRUE
  88. END ;
  89. IF (ch = CHR (10)) OR (ch = CHR (13)) THEN
  90. IF i = 0 THEN
  91. RETURN FALSE
  92. END ;
  93. s [i] := 0C ;
  94. RETURN TRUE
  95. END ;
  96. IF i < HIGH (s) THEN
  97. s [i] := ch ;
  98. INC (i)
  99. END
  100. END
  101. END ReadLineStr ;
  102. PROCEDURE LoadFile (p : ARRAY OF CHAR) : BOOLEAN ;
  103. (* same CR/LF normalisation as the shell's LoadWorkFile *)
  104. VAR fd : INTEGER ; k : LONGINT ; b : BYTE ; prevCR : BOOLEAN ;
  105. BEGIN
  106. fd := open (ADR (p), O_RDONLY, 0) ;
  107. IF fd < 0 THEN
  108. RETURN FALSE
  109. END ;
  110. Clear ;
  111. prevCR := FALSE ;
  112. LOOP
  113. IF Length () >= TextLimit THEN
  114. EXIT
  115. END ;
  116. k := read (fd, ADR (b), 1) ;
  117. IF k # 1 THEN
  118. EXIT
  119. END ;
  120. IF b = 26 THEN
  121. EXIT (* ^Z ends the text *)
  122. ELSIF b = 10 THEN
  123. IF NOT prevCR THEN
  124. InsertCh (Length (), CHR (13)) (* lone LF -> CR *)
  125. END ;
  126. prevCR := FALSE
  127. ELSIF b = 13 THEN
  128. InsertCh (Length (), CHR (13)) ;
  129. prevCR := TRUE
  130. ELSE
  131. InsertCh (Length (), CHR (ORD (b))) ;
  132. prevCR := FALSE
  133. END
  134. END ;
  135. k := close (fd) ;
  136. RETURN TRUE
  137. END LoadFile ;
  138. PROCEDURE ShowAt (pos : CARDINAL) ;
  139. (* print the source around pos, with '^' under pos *)
  140. VAR s, e, i : CARDINAL ;
  141. BEGIN
  142. IF pos > 40 THEN
  143. s := pos - 40
  144. ELSE
  145. s := 0
  146. END ;
  147. e := pos + 30 ;
  148. IF e > Length () THEN
  149. e := Length ()
  150. END ;
  151. IF e > s + 78 THEN
  152. e := s + 78
  153. END ;
  154. i := 0 ;
  155. WHILE s + i < e DO
  156. txt [i] := CharAt (s + i) ;
  157. IF txt [i] = CHR (13) THEN
  158. txt [i] := " "
  159. END ;
  160. IF s + i = pos THEN
  161. mark [i] := "^"
  162. ELSE
  163. mark [i] := "-"
  164. END ;
  165. INC (i)
  166. END ;
  167. txt [i] := 0C ;
  168. mark [i] := 0C ;
  169. PutStr (" " ) ;
  170. PutStr (txt) ;
  171. NL ;
  172. PutStr (" " ) ;
  173. PutStr (mark) ;
  174. NL
  175. END ShowAt ;
  176. VAR
  177. errNo, errPos : CARDINAL ;
  178. ok : BOOLEAN ;
  179. dump, image : BOOLEAN ;
  180. PROCEDURE Hex (b : BYTE ; VAR out : ARRAY OF CHAR) ;
  181. (* ISO will not index a plain string constant as an array, so compute the
  182. two nibbles instead of using a "0123456789ABCDEF" lookup. *)
  183. VAR d : CARDINAL ;
  184. BEGIN
  185. d := VAL (CARDINAL, b) DIV 16 ; (* BYTE arith yields BYTE *)
  186. IF d < 10 THEN
  187. out [0] := CHR (ORD ("0") + d)
  188. ELSE
  189. out [0] := CHR (ORD ("A") + d - 10)
  190. END ;
  191. d := VAL (CARDINAL, b) MOD 16 ;
  192. IF d < 10 THEN
  193. out [1] := CHR (ORD ("0") + d)
  194. ELSE
  195. out [1] := CHR (ORD ("A") + d - 10)
  196. END
  197. END Hex ;
  198. PROCEDURE PutHexNib (d : CARDINAL) ;
  199. (* one hex digit. Do NOT reuse Hex for this: Hex formats a BYTE as two
  200. chars, so printing 4 nibbles through it emits 8 digits and every offset
  201. reads 16x too large. *)
  202. VAR c : CHAR ;
  203. BEGIN
  204. IF d < 10 THEN
  205. c := CHR (ORD ("0") + d)
  206. ELSE
  207. c := CHR (ORD ("A") + d - 10)
  208. END ;
  209. PutCh (c)
  210. END PutHexNib ;
  211. PROCEDURE PutCardHex4 (n : CARDINAL) ;
  212. (* 4 hex digits, e.g. "0010" for 16 *)
  213. VAR d : CARDINAL ;
  214. BEGIN
  215. d := 4096 ; (* 16^3, no "**" needed *)
  216. WHILE d > 0 DO
  217. PutHexNib ((n DIV d) MOD 16) ;
  218. d := d DIV 16
  219. END ;
  220. PutStr (": ")
  221. END PutCardHex4 ;
  222. PROCEDURE DumpCode ;
  223. (* hex dump of the emitted PROGRAM, 16 bytes per line. The runtime is not
  224. part of the program, so the program starts at 0 and is CodeBytes() long. *)
  225. VAR i, n : CARDINAL ;
  226. hx : ARRAY [0..1] OF CHAR ;
  227. b : BYTE ;
  228. BEGIN
  229. i := 0 ;
  230. WHILE i < CodeBytes () DO
  231. PutStr (" " ) ;
  232. PutCardHex4 (i) ;
  233. n := 0 ;
  234. WHILE (n < 16) AND (i + n < CodeBytes ()) DO
  235. b := CodeByteAt (i + n) ;
  236. Hex (b, hx) ;
  237. PutCh (hx [0]) ;
  238. PutCh (hx [1]) ;
  239. PutCh (" ") ;
  240. INC (n)
  241. END ;
  242. NL ;
  243. i := i + 16
  244. END
  245. END DumpCode ;
  246. PROCEDURE DumpImage ;
  247. (* The whole linked image - [runtime][program header][program code] - which is
  248. what a .COM would actually contain. The runtime's own 391 bytes are shown
  249. only at the head and the tail: enough to prove the blob is really in there,
  250. without burying the program in 24 lines of library. *)
  251. VAR i, n, rtSz, total, from, lim : CARDINAL ;
  252. hx : ARRAY [0..1] OF CHAR ;
  253. BEGIN
  254. rtSz := ImageBytes () - CodeBytes () ;
  255. total := ImageBytes () ;
  256. PutStr (" image=") ;
  257. PutCard (total) ;
  258. PutStr (" rtSz=") ;
  259. PutCard (rtSz) ;
  260. PutStr (" dataBase=") ;
  261. PutCard (DataBase ()) ;
  262. PutStr (" dataEnd=") ;
  263. PutCard (DataBase () + DataBytes ()) ;
  264. NL ;
  265. PutStr (" rt head " ) ;
  266. i := 0 ;
  267. WHILE i < 16 DO
  268. Hex (ImageByteAt (i), hx) ;
  269. PutCh (hx [0]) ; PutCh (hx [1]) ; PutCh (" ") ;
  270. INC (i)
  271. END ;
  272. NL ;
  273. i := rtSz - 16 ;
  274. WHILE i < total DO
  275. from := i ;
  276. lim := total ;
  277. IF lim > from + 16 THEN
  278. lim := from + 16
  279. END ;
  280. PutStr (" " ) ;
  281. PutCardHex4 (from) ;
  282. n := 0 ;
  283. WHILE (n < 16) AND (from + n < lim) DO
  284. Hex (ImageByteAt (from + n), hx) ;
  285. PutCh (hx [0]) ; PutCh (hx [1]) ; PutCh (" ") ;
  286. INC (n)
  287. END ;
  288. NL ;
  289. i := i + 16
  290. END
  291. END DumpImage ;
  292. PROCEDURE IsCmd (c1, c2, c3, c4, c5 : CHAR ) : BOOLEAN ;
  293. (* the line "@word" switches a dump mode on for the rest of the run *)
  294. VAR i : CARDINAL ;
  295. BEGIN
  296. IF lineBuf [0] # "@" THEN
  297. RETURN FALSE
  298. END ;
  299. i := 0 ;
  300. WHILE (i <= HIGH (lineBuf)) AND (lineBuf [i] # 0C) DO
  301. INC (i)
  302. END ;
  303. IF i # 6 THEN
  304. RETURN FALSE
  305. END ;
  306. RETURN (lineBuf [1] = c1) AND (lineBuf [2] = c2) AND (lineBuf [3] = c3)
  307. AND (lineBuf [4] = c4) AND (lineBuf [5] = c5)
  308. END IsCmd ;
  309. BEGIN
  310. PutStr ("FIXTURE RESULT") ;
  311. NL ;
  312. WHILE ReadLineStr (lineBuf) DO
  313. IF IsCmd ("d", "u", "m", "p", " ") THEN
  314. dump := TRUE (* "@dump": hex-dump from here on *)
  315. ELSIF IsCmd ("i", "m", "a", "g", "e") THEN
  316. image := TRUE (* "@image": whole image, layout too *)
  317. ELSE
  318. StrCopy (pathCopy, lineBuf) ;
  319. IF LoadFile (pathCopy) THEN
  320. ok := Compile (errNo, errPos) ;
  321. IF ok THEN
  322. PutStr (lineBuf) ;
  323. PutStr (" OK code=") ;
  324. PutCard (CodeBytes ()) ;
  325. PutStr (" data=") ;
  326. PutCard (DataBytes ()) ;
  327. NL ;
  328. IF image THEN
  329. DumpImage ()
  330. ELSIF dump THEN
  331. DumpCode ()
  332. END
  333. ELSE
  334. PutStr (lineBuf) ;
  335. PutStr (" ERROR ") ;
  336. PutCard (errNo) ;
  337. PutStr (" at pos ") ;
  338. PutCard (errPos) ;
  339. NL ;
  340. ShowAt (errPos)
  341. END
  342. ELSE
  343. PutStr (lineBuf) ;
  344. PutStr (" CANNOT OPEN") ;
  345. NL
  346. END
  347. END
  348. END
  349. END CompileTest.