1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-01 04:10:18 +02:00
guile/module/system/base/message.scm
Ludovic Courtès 8e6c15a6f0 Add warnings for obvious syntax errors in format strings.
* module/language/tree-il/analyze.scm (&syntax-error): New variable.
  (format-string-argument-count): Throw to &SYNTAX-ERROR when a syntax
  error in a format string is encountered.
  (format-analysis): Catch &SYNTAX-ERROR and convert as a warning of the
  appropriate type.

* module/system/base/message.scm (%warning-types)[format]: Handle
  `syntax-error' warnings.

* test-suite/tests/tree-il.test
  ("warnings")["conditionals"]("unterminated", "unexpected ~;",
  "unexpected ~]"): New tests.
  ["unterminated ~{...~}"]: New test.
2010-10-10 19:10:11 +02:00

186 lines
6.7 KiB
Scheme
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; User interface messages
;; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
;;; This library is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU Lesser General Public
;;; License as published by the Free Software Foundation; either
;;; version 3 of the License, or (at your option) any later version.
;;;
;;; This library is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;; Lesser General Public License for more details.
;;;
;;; You should have received a copy of the GNU Lesser General Public
;;; License along with this library; if not, write to the Free Software
;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;;; Commentary:
;;;
;;; This module provide a simple interface to send messages to the user.
;;; TODO: Internationalize messages.
;;;
;;; Code:
(define-module (system base message)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-9)
#:use-module (ice-9 match)
#:export (*current-warning-port* warning
warning-type? warning-type-name warning-type-description
warning-type-printer lookup-warning-type
%warning-types))
;;;
;;; Source location
;;;
(define (location-string loc)
(if (pair? loc)
(format #f "~a:~a:~a"
(or (assoc-ref loc 'filename) "<stdin>")
(1+ (assoc-ref loc 'line))
(assoc-ref loc 'column))
"<unknown-location>"))
;;;
;;; Warnings
;;;
(define *current-warning-port*
;; The port where warnings are sent.
(make-fluid))
(fluid-set! *current-warning-port* (current-error-port))
(define-record-type <warning-type>
(make-warning-type name description printer)
warning-type?
(name warning-type-name)
(description warning-type-description)
(printer warning-type-printer))
(define %warning-types
;; List of know warning types.
(map (lambda (args)
(apply make-warning-type args))
`((unsupported-warning ;; a "meta warning"
"warn about unknown warning types"
,(lambda (port unused name)
(format port "warning: unknown warning type `~A'~%"
name)))
(unused-variable
"report unused variables"
,(lambda (port loc name)
(format port "~A: warning: unused variable `~A'~%"
loc name)))
(unused-toplevel
"report unused local top-level variables"
,(lambda (port loc name)
(format port "~A: warning: possibly unused local top-level variable `~A'~%"
loc name)))
(unbound-variable
"report possibly unbound variables"
,(lambda (port loc name)
(format port "~A: warning: possibly unbound variable `~A'~%"
loc name)))
(arity-mismatch
"report procedure arity mismatches (wrong number of arguments)"
,(lambda (port loc name certain?)
(if certain?
(format port
"~A: warning: wrong number of arguments to `~A'~%"
loc name)
(format port
"~A: warning: possibly wrong number of arguments to `~A'~%"
loc name))))
(format
"report wrong number of arguments to `format'"
,(lambda (port loc . rest)
(define (escape-newlines str)
(list->string
(string-fold-right (lambda (c r)
(if (eq? c #\newline)
(append '(#\\ #\n) r)
(cons c r)))
'()
str)))
(define (range min max)
(cond ((eq? min 'any)
(if (eq? max 'any)
"any number" ;; can't happen
(format #f "up to ~a" max)))
((eq? max 'any)
(format #f "at least ~a" min))
((= min max) (number->string min))
(else
(format #f "~a to ~a" min max))))
(match rest
(('wrong-format-arg-count fmt min max actual)
(format port
"~A: warning: ~S: wrong number of `format' arguments: expected ~A, got ~A~%"
loc (escape-newlines fmt)
(range min max) actual))
(('syntax-error 'unterminated-iteration fmt)
(format port "~A: warning: ~S: unterminated iteration~%"
loc (escape-newlines fmt)))
(('syntax-error 'unterminated-conditional fmt)
(format port "~A: warning: ~S: unterminated conditional~%"
loc (escape-newlines fmt)))
(('syntax-error 'unexpected-semicolon fmt)
(format port "~A: warning: ~S: unexpected `~~;'~%"
loc (escape-newlines fmt)))
(('syntax-error 'unexpected-conditional-termination fmt)
(format port "~A: warning: ~S: unexpected `~~]'~%"
loc (escape-newlines fmt)))
(('wrong-port wrong-port)
(format port
"~A: warning: ~S: wrong port argument~%"
loc wrong-port))
(('wrong-format-string fmt)
(format port
"~A: warning: ~S: wrong format string~%"
loc fmt))
(('non-literal-format-string)
(format port
"~A: warning: non-literal format string~%"
loc))
(('wrong-num-args count)
(format port
"~A: warning: wrong number of arguments to `format'~%"
loc))
(else
(format port "~A: `format' warning~%" loc))))))))
(define (lookup-warning-type name)
"Return the warning type NAME or `#f' if not found."
(find (lambda (wt)
(eq? name (warning-type-name wt)))
%warning-types))
(define (warning type location . args)
"Emit a warning of type TYPE for source location LOCATION (a source
property alist) using the data in ARGS."
(let ((wt (lookup-warning-type type))
(port (fluid-ref *current-warning-port*)))
(if (warning-type? wt)
(apply (warning-type-printer wt)
port (location-string location)
args)
(format port "~A: unknown warning type `~A': ~A~%"
(location-string location) type args))))
;;; message.scm ends here