Diagnostics.Mod 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. MODULE Diagnostics; (** AUTHOR "staubesv"; PURPOSE "Generic diagnostics reporting facility"; *)
  2. IMPORT Streams;
  3. CONST
  4. (** Indicate that a position or an errorcode is not valid *)
  5. Invalid* = MIN(LONGINT);
  6. (** Entry types *)
  7. TypeInformation* = 0;
  8. TypeWarning* = 1;
  9. TypeError* = 2;
  10. (** DiagnosticsList.ToStream mask argument *)
  11. All* = {0..2};
  12. Tab = 9X;
  13. TYPE
  14. Diagnostics* = OBJECT
  15. PROCEDURE Error*(CONST source : ARRAY OF CHAR; position, errorCode : LONGINT; CONST message : ARRAY OF CHAR);
  16. END Error;
  17. PROCEDURE Warning*(CONST source : ARRAY OF CHAR; position, errorCode : LONGINT; CONST message : ARRAY OF CHAR);
  18. END Warning;
  19. PROCEDURE Information*(CONST source : ARRAY OF CHAR; position, errorCode : LONGINT; CONST message : ARRAY OF CHAR);
  20. END Information;
  21. END Diagnostics;
  22. TYPE
  23. Entry* = POINTER TO RECORD
  24. type*: WORD;
  25. source*: ARRAY 128 OF CHAR;
  26. position*, errorCode*: LONGINT;
  27. message*: ARRAY 256 OF CHAR;
  28. next*: Entry;
  29. END;
  30. EntryArray* = POINTER TO ARRAY OF Entry;
  31. EnumProc* = PROCEDURE {DELEGATE} (e : Entry);
  32. TYPE
  33. DiagnosticsList* = OBJECT(Diagnostics)
  34. VAR
  35. (* Intended for subclassing only *)
  36. entries- : Entry;
  37. nofErrors- : SIZE;
  38. nofWarnings- : SIZE;
  39. nofInformations- : SIZE;
  40. nofMessages- : SIZE;
  41. PROCEDURE Error*(CONST source : ARRAY OF CHAR; position, errorCode : LONGINT; CONST message : ARRAY OF CHAR);
  42. BEGIN {EXCLUSIVE}
  43. InsertSorted(TypeError, source, position, errorCode, message, nofErrors)
  44. END Error;
  45. PROCEDURE Warning*(CONST source : ARRAY OF CHAR; position, errorCode : LONGINT; CONST message : ARRAY OF CHAR);
  46. BEGIN {EXCLUSIVE}
  47. InsertSorted(TypeWarning, source, position, errorCode, message, nofWarnings);
  48. END Warning;
  49. PROCEDURE Information*(CONST source : ARRAY OF CHAR; position, errorCode : LONGINT; CONST message : ARRAY OF CHAR);
  50. BEGIN {EXCLUSIVE}
  51. InsertSorted(TypeInformation, source, position, errorCode, message, nofInformations);
  52. END Information;
  53. PROCEDURE ToStream*(w : Streams.Writer; mask : SET);
  54. VAR entry : Entry;
  55. BEGIN {EXCLUSIVE}
  56. ASSERT(w # NIL);
  57. entry := entries;
  58. WHILE (entry # NIL) DO
  59. IF (entry.type IN mask) THEN
  60. Print (w, entry.source, entry.position, entry.errorCode, entry.type, entry.message);
  61. END;
  62. entry := entry.next;
  63. END;
  64. END ToStream;
  65. PROCEDURE &Reset*;
  66. BEGIN {EXCLUSIVE}
  67. entries := NIL;
  68. nofErrors := 0; nofWarnings := 0; nofInformations := 0;
  69. nofMessages := 0;
  70. END Reset;
  71. PROCEDURE ForAll*(proc : EnumProc);
  72. VAR e : Entry;
  73. BEGIN {EXCLUSIVE}
  74. ASSERT(proc # NIL);
  75. e := entries;
  76. WHILE (e # NIL) DO
  77. proc(e);
  78. e := e.next;
  79. END;
  80. END ForAll;
  81. PROCEDURE GetEntries*() : EntryArray;
  82. VAR e : Entry; result : EntryArray; nofEntries, i : SIZE;
  83. BEGIN {EXCLUSIVE}
  84. result := NIL;
  85. nofEntries := nofErrors + nofWarnings + nofInformations;
  86. IF (nofEntries > 0) THEN
  87. NEW(result, nofEntries);
  88. e := entries; i := 0;
  89. WHILE (e # NIL) DO
  90. result[i] := e; INC(i);
  91. e := e.next;
  92. END;
  93. END;
  94. RETURN result;
  95. END GetEntries;
  96. PROCEDURE InsertSorted(type: WORD; CONST source : ARRAY OF CHAR; position, errorCode : LONGINT; CONST message : ARRAY OF CHAR; VAR counter: SIZE);
  97. VAR prev, entry : Entry;
  98. BEGIN
  99. entry := entries; prev := NIL;
  100. WHILE (entry # NIL) & (entry.position <= position) DO prev := entry; entry := entry.next END;
  101. IF (entry = NIL) OR (entry.type # type) OR (entry.position # position) OR (entry.errorCode # errorCode) OR (entry.message # message) THEN
  102. INC(nofMessages); INC (counter);
  103. entry := NewEntry (type, source, position, errorCode, message, entry);
  104. IF prev = NIL THEN entries := entry ELSE prev.next := entry END
  105. END
  106. END InsertSorted;
  107. PROCEDURE NewEntry*(type: WORD; CONST source : ARRAY OF CHAR; position, errorCode : LONGINT; CONST message : ARRAY OF CHAR; next: Entry) : Entry;
  108. VAR entry : Entry;
  109. BEGIN
  110. NEW(entry);
  111. entry.type := type;
  112. COPY (source, entry.source);
  113. entry.position := position;
  114. entry.errorCode := errorCode;
  115. COPY (message, entry.message);
  116. entry.next := next;
  117. RETURN entry;
  118. END NewEntry;
  119. END DiagnosticsList;
  120. TYPE
  121. StreamDiagnostics* = OBJECT (Diagnostics);
  122. VAR
  123. writer: Streams.Writer;
  124. PROCEDURE &Init *(w: Streams.Writer);
  125. BEGIN
  126. ASSERT(w # NIL);
  127. writer := w;
  128. END Init;
  129. PROCEDURE Error* (CONST source : ARRAY OF CHAR; position, errorCode : LONGINT; CONST message : ARRAY OF CHAR);
  130. BEGIN Print (writer, source, position, errorCode, TypeError, message);
  131. END Error;
  132. PROCEDURE Warning* (CONST source : ARRAY OF CHAR; position, errorCode : LONGINT; CONST message : ARRAY OF CHAR);
  133. BEGIN Print (writer, source, position, errorCode, TypeWarning, message);
  134. END Warning;
  135. PROCEDURE Information* (CONST source : ARRAY OF CHAR; position, errorCode : LONGINT; CONST message : ARRAY OF CHAR);
  136. BEGIN Print (writer, source, position, errorCode, TypeInformation, message);
  137. END Information;
  138. END StreamDiagnostics;
  139. PROCEDURE Print (w: Streams.Writer; CONST source : ARRAY OF CHAR; position, errorCode: LONGINT; type: WORD; CONST message: ARRAY OF CHAR);
  140. BEGIN
  141. w.Char(Tab);
  142. IF (source # "") THEN w.String (source); END;
  143. IF (position # Invalid) THEN w.Char ('@'); w.Int(position, 0); END;
  144. w.String(": ");
  145. IF (type = TypeWarning) THEN
  146. w.String("warning");
  147. ELSIF (type = TypeError) THEN
  148. w.String("error");
  149. END;
  150. IF (errorCode # Invalid) THEN
  151. IF (type # TypeInformation) THEN w.Char (' ') END;
  152. w.Int(errorCode, 0);
  153. END;
  154. IF (type # TypeInformation) THEN w.String(": ") END;
  155. w.String(message); w.Ln;
  156. w.Update;
  157. END Print;
  158. END Diagnostics.