srfi-16.scm 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. ;;; srfi-16.scm --- case-lambda
  2. ;; Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc.
  3. ;;
  4. ;; This library is free software; you can redistribute it and/or
  5. ;; modify it under the terms of the GNU Lesser General Public
  6. ;; License as published by the Free Software Foundation; either
  7. ;; version 2.1 of the License, or (at your option) any later version.
  8. ;;
  9. ;; This library is distributed in the hope that it will be useful,
  10. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;; Lesser General Public License for more details.
  13. ;;
  14. ;; You should have received a copy of the GNU Lesser General Public
  15. ;; License along with this library; if not, write to the Free Software
  16. ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. ;;; Author: Martin Grabmueller
  18. ;;; Commentary:
  19. ;; Implementation of SRFI-16. `case-lambda' is a syntactic form
  20. ;; which permits writing functions acting different according to the
  21. ;; number of arguments passed.
  22. ;;
  23. ;; The syntax of the `case-lambda' form is defined in the following
  24. ;; EBNF grammar.
  25. ;;
  26. ;; <case-lambda>
  27. ;; --> (case-lambda <case-lambda-clause>)
  28. ;; <case-lambda-clause>
  29. ;; --> (<signature> <definition-or-command>*)
  30. ;; <signature>
  31. ;; --> (<identifier>*)
  32. ;; | (<identifier>* . <identifier>)
  33. ;; | <identifier>
  34. ;;
  35. ;; The value returned by a `case-lambda' form is a procedure which
  36. ;; matches the number of actual arguments against the signatures in
  37. ;; the various clauses, in order. The first matching clause is
  38. ;; selected, the corresponding values from the actual parameter list
  39. ;; are bound to the variable names in the clauses and the body of the
  40. ;; clause is evaluated.
  41. ;;; Code:
  42. (define-module (srfi srfi-16)
  43. :export-syntax (case-lambda))
  44. (cond-expand-provide (current-module) '(srfi-16))
  45. (define-macro (case-lambda . clauses)
  46. ;; Return the length of the list @var{l}, but allow dotted list.
  47. ;;
  48. (define (alength l)
  49. (cond ((null? l) 0)
  50. ((pair? l) (+ 1 (alength (cdr l))))
  51. (else 0)))
  52. ;; Return @code{#t} if @var{l} is a dotted list, @code{#f} if it is
  53. ;; a normal list.
  54. ;;
  55. (define (dotted? l)
  56. (cond ((null? l) #f)
  57. ((pair? l) (dotted? (cdr l)))
  58. (else #t)))
  59. ;; Return the expression for accessing the @var{index}th element of
  60. ;; the list called @var{args-name}. If @var{tail?} is true, code
  61. ;; for accessing the list-tail is generated, otherwise for accessing
  62. ;; the list element itself.
  63. ;;
  64. (define (accessor args-name index tail?)
  65. (if tail?
  66. (case index
  67. ((0) `,args-name)
  68. ((1) `(cdr ,args-name))
  69. ((2) `(cddr ,args-name))
  70. ((3) `(cdddr ,args-name))
  71. ((4) `(cddddr ,args-name))
  72. (else `(list-tail ,args-name ,index)))
  73. (case index
  74. ((0) `(car ,args-name))
  75. ((1) `(cadr ,args-name))
  76. ((2) `(caddr ,args-name))
  77. ((3) `(cadddr ,args-name))
  78. (else `(list-ref ,args-name ,index)))))
  79. ;; Generate the binding lists of the variables of one case-lambda
  80. ;; clause. @var{vars} is the (possibly dotted) list of variables
  81. ;; and @var{args-name} is the generated name used for the argument
  82. ;; list.
  83. ;;
  84. (define (gen-temps vars args-name)
  85. (let lp ((v vars) (i 0))
  86. (cond ((null? v) '())
  87. ((pair? v)
  88. (cons `(,(car v) ,(accessor args-name i #f))
  89. (lp (cdr v) (+ i 1))))
  90. (else `((,v ,(accessor args-name i #t)))))))
  91. ;; Generate the cond clauses for each of the clauses of case-lambda,
  92. ;; including the parameter count check, binding of the parameters
  93. ;; and the code of the corresponding body.
  94. ;;
  95. (define (gen-clauses l length-name args-name)
  96. (cond ((null? l) (list '(else (error "too few arguments"))))
  97. (else
  98. (cons
  99. `((,(if (dotted? (caar l)) '>= '=)
  100. ,length-name ,(alength (caar l)))
  101. (let ,(gen-temps (caar l) args-name)
  102. ,@(cdar l)))
  103. (gen-clauses (cdr l) length-name args-name)))))
  104. (let ((args-name (gensym))
  105. (length-name (gensym)))
  106. (let ((proc
  107. `(lambda ,args-name
  108. (let ((,length-name (length ,args-name)))
  109. (cond ,@(gen-clauses clauses length-name args-name))))))
  110. proc)))
  111. ;;; srfi-16.scm ends here