message.scm 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. ;;; User interface messages
  2. ;; Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
  3. ;;; This library is free software; you can redistribute it and/or
  4. ;;; modify it under the terms of the GNU Lesser General Public
  5. ;;; License as published by the Free Software Foundation; either
  6. ;;; version 3 of the License, or (at your option) any later version.
  7. ;;;
  8. ;;; This library is distributed in the hope that it will be useful,
  9. ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;;; Lesser General Public License for more details.
  12. ;;;
  13. ;;; You should have received a copy of the GNU Lesser General Public
  14. ;;; License along with this library; if not, write to the Free Software
  15. ;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. ;;; Commentary:
  17. ;;;
  18. ;;; This module provide a simple interface to send messages to the user.
  19. ;;; TODO: Internationalize messages.
  20. ;;;
  21. ;;; Code:
  22. (define-module (system base message)
  23. #:use-module (srfi srfi-1)
  24. #:use-module (srfi srfi-9)
  25. #:use-module (ice-9 match)
  26. #:export (*current-warning-port*
  27. *current-warning-prefix*
  28. warning
  29. warning-type? warning-type-name warning-type-description
  30. warning-type-printer lookup-warning-type
  31. %warning-types))
  32. ;;;
  33. ;;; Source location
  34. ;;;
  35. (define (location-string loc)
  36. (if (pair? loc)
  37. (format #f "~a:~a:~a"
  38. (or (assoc-ref loc 'filename) "<stdin>")
  39. (1+ (assoc-ref loc 'line))
  40. (assoc-ref loc 'column))
  41. "<unknown-location>"))
  42. ;;;
  43. ;;; Warnings
  44. ;;;
  45. ;; This name existed before %current-warning-port was introduced, but
  46. ;; otherwise it is a deprecated binding.
  47. (define *current-warning-port*
  48. ;; Can't play the identifier-syntax deprecation game in Guile 2.0, as
  49. ;; other modules might depend on this being a normal binding and not a
  50. ;; syntax binding.
  51. (parameter-fluid current-warning-port))
  52. (define *current-warning-prefix*
  53. ;; Prefix string when emitting a warning.
  54. (make-fluid ";;; "))
  55. (define-record-type <warning-type>
  56. (make-warning-type name description printer)
  57. warning-type?
  58. (name warning-type-name)
  59. (description warning-type-description)
  60. (printer warning-type-printer))
  61. (define %warning-types
  62. ;; List of known warning types.
  63. (map (lambda (args)
  64. (apply make-warning-type args))
  65. (let-syntax ((emit
  66. (lambda (s)
  67. (syntax-case s ()
  68. ((_ port fmt args ...)
  69. (string? (syntax->datum #'fmt))
  70. (with-syntax ((fmt
  71. (string-append "~a"
  72. (syntax->datum
  73. #'fmt))))
  74. #'(format port fmt
  75. (fluid-ref *current-warning-prefix*)
  76. args ...)))))))
  77. `((unsupported-warning ;; a "meta warning"
  78. "warn about unknown warning types"
  79. ,(lambda (port unused name)
  80. (emit port "warning: unknown warning type `~A'~%"
  81. name)))
  82. (unused-variable
  83. "report unused variables"
  84. ,(lambda (port loc name)
  85. (emit port "~A: warning: unused variable `~A'~%"
  86. loc name)))
  87. (unused-toplevel
  88. "report unused local top-level variables"
  89. ,(lambda (port loc name)
  90. (emit port "~A: warning: possibly unused local top-level variable `~A'~%"
  91. loc name)))
  92. (unbound-variable
  93. "report possibly unbound variables"
  94. ,(lambda (port loc name)
  95. (emit port "~A: warning: possibly unbound variable `~A'~%"
  96. loc name)))
  97. (arity-mismatch
  98. "report procedure arity mismatches (wrong number of arguments)"
  99. ,(lambda (port loc name certain?)
  100. (if certain?
  101. (emit port
  102. "~A: warning: wrong number of arguments to `~A'~%"
  103. loc name)
  104. (emit port
  105. "~A: warning: possibly wrong number of arguments to `~A'~%"
  106. loc name))))
  107. (duplicate-case-datum
  108. "report a duplicate datum in a case expression"
  109. ,(lambda (port loc datum clause case-expr)
  110. (emit port
  111. "~A: warning: duplicate datum ~S in clause ~S of case expression ~S~%"
  112. loc datum clause case-expr)))
  113. (bad-case-datum
  114. "report a case datum that cannot be meaningfully compared using `eqv?'"
  115. ,(lambda (port loc datum clause case-expr)
  116. (emit port
  117. "~A: warning: datum ~S cannot be meaningfully compared using `eqv?' in clause ~S of case expression ~S~%"
  118. loc datum clause case-expr)))
  119. (format
  120. "report wrong number of arguments to `format'"
  121. ,(lambda (port loc . rest)
  122. (define (escape-newlines str)
  123. (list->string
  124. (string-fold-right (lambda (c r)
  125. (if (eq? c #\newline)
  126. (append '(#\\ #\n) r)
  127. (cons c r)))
  128. '()
  129. str)))
  130. (define (range min max)
  131. (cond ((eq? min 'any)
  132. (if (eq? max 'any)
  133. "any number" ;; can't happen
  134. (emit #f "up to ~a" max)))
  135. ((eq? max 'any)
  136. (emit #f "at least ~a" min))
  137. ((= min max) (number->string min))
  138. (else
  139. (emit #f "~a to ~a" min max))))
  140. (match rest
  141. (('simple-format fmt opt)
  142. (emit port
  143. "~A: warning: ~S: unsupported format option ~~~A, use (ice-9 format) instead~%"
  144. loc (escape-newlines fmt) opt))
  145. (('wrong-format-arg-count fmt min max actual)
  146. (emit port
  147. "~A: warning: ~S: wrong number of `format' arguments: expected ~A, got ~A~%"
  148. loc (escape-newlines fmt)
  149. (range min max) actual))
  150. (('syntax-error 'unterminated-iteration fmt)
  151. (emit port "~A: warning: ~S: unterminated iteration~%"
  152. loc (escape-newlines fmt)))
  153. (('syntax-error 'unterminated-conditional fmt)
  154. (emit port "~A: warning: ~S: unterminated conditional~%"
  155. loc (escape-newlines fmt)))
  156. (('syntax-error 'unexpected-semicolon fmt)
  157. (emit port "~A: warning: ~S: unexpected `~~;'~%"
  158. loc (escape-newlines fmt)))
  159. (('syntax-error 'unexpected-conditional-termination fmt)
  160. (emit port "~A: warning: ~S: unexpected `~~]'~%"
  161. loc (escape-newlines fmt)))
  162. (('wrong-port wrong-port)
  163. (emit port
  164. "~A: warning: ~S: wrong port argument~%"
  165. loc wrong-port))
  166. (('wrong-format-string fmt)
  167. (emit port
  168. "~A: warning: ~S: wrong format string~%"
  169. loc fmt))
  170. (('non-literal-format-string)
  171. (emit port
  172. "~A: warning: non-literal format string~%"
  173. loc))
  174. (('wrong-num-args count)
  175. (emit port
  176. "~A: warning: wrong number of arguments to `format'~%"
  177. loc))
  178. (else
  179. (emit port "~A: `format' warning~%" loc)))))))))
  180. (define (lookup-warning-type name)
  181. "Return the warning type NAME or `#f' if not found."
  182. (find (lambda (wt)
  183. (eq? name (warning-type-name wt)))
  184. %warning-types))
  185. (define (warning type location . args)
  186. "Emit a warning of type TYPE for source location LOCATION (a source
  187. property alist) using the data in ARGS."
  188. (let ((wt (lookup-warning-type type))
  189. (port (current-warning-port)))
  190. (if (warning-type? wt)
  191. (apply (warning-type-printer wt)
  192. port (location-string location)
  193. args)
  194. (format port "~A: unknown warning type `~A': ~A~%"
  195. (location-string location) type args))))
  196. ;;; message.scm ends here