lambda.scm 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. (define-module (lang elisp internals lambda)
  2. #:use-module (lang elisp internals fset)
  3. #:use-module (lang elisp transform)
  4. #:export (parse-formals
  5. transform-lambda/interactive
  6. interactive-spec))
  7. ;;; Parses a list of elisp formals, e.g. (x y &optional b &rest r) and
  8. ;;; returns three values: (i) list of symbols for required arguments,
  9. ;;; (ii) list of symbols for optional arguments, (iii) rest symbol, or
  10. ;;; #f if there is no rest argument.
  11. (define (parse-formals formals)
  12. (letrec ((do-required
  13. (lambda (required formals)
  14. (if (null? formals)
  15. (values (reverse required) '() #f)
  16. (let ((next-sym (car formals)))
  17. (cond ((not (symbol? next-sym))
  18. (error "Bad formals (non-symbol in required list)"))
  19. ((eq? next-sym '&optional)
  20. (do-optional required '() (cdr formals)))
  21. ((eq? next-sym '&rest)
  22. (do-rest required '() (cdr formals)))
  23. (else
  24. (do-required (cons next-sym required)
  25. (cdr formals))))))))
  26. (do-optional
  27. (lambda (required optional formals)
  28. (if (null? formals)
  29. (values (reverse required) (reverse optional) #f)
  30. (let ((next-sym (car formals)))
  31. (cond ((not (symbol? next-sym))
  32. (error "Bad formals (non-symbol in optional list)"))
  33. ((eq? next-sym '&rest)
  34. (do-rest required optional (cdr formals)))
  35. (else
  36. (do-optional required
  37. (cons next-sym optional)
  38. (cdr formals))))))))
  39. (do-rest
  40. (lambda (required optional formals)
  41. (if (= (length formals) 1)
  42. (let ((next-sym (car formals)))
  43. (if (symbol? next-sym)
  44. (values (reverse required) (reverse optional) next-sym)
  45. (error "Bad formals (non-symbol rest formal)")))
  46. (error "Bad formals (more than one rest formal)")))))
  47. (do-required '() (cond ((list? formals)
  48. formals)
  49. ((symbol? formals)
  50. (list '&rest formals))
  51. (else
  52. (error "Bad formals (not a list or a single symbol)"))))))
  53. (define (transform-lambda exp)
  54. (call-with-values (lambda () (parse-formals (cadr exp)))
  55. (lambda (required optional rest)
  56. (let ((num-required (length required))
  57. (num-optional (length optional)))
  58. `(,lambda %--args
  59. (,let ((%--num-args (,length %--args)))
  60. (,cond ((,< %--num-args ,num-required)
  61. (,error "Wrong number of args (not enough required args)"))
  62. ,@(if rest
  63. '()
  64. `(((,> %--num-args ,(+ num-required num-optional))
  65. (,error "Wrong number of args (too many args)"))))
  66. (else
  67. (, @bind ,(append (map (lambda (i)
  68. (list (list-ref required i)
  69. `(,list-ref %--args ,i)))
  70. (iota num-required))
  71. (map (lambda (i)
  72. (let ((i+nr (+ i num-required)))
  73. (list (list-ref optional i)
  74. `(,if (,> %--num-args ,i+nr)
  75. (,list-ref %--args ,i+nr)
  76. ,%nil))))
  77. (iota num-optional))
  78. (if rest
  79. (list (list rest
  80. `(,if (,> %--num-args
  81. ,(+ num-required
  82. num-optional))
  83. (,list-tail %--args
  84. ,(+ num-required
  85. num-optional))
  86. ,%nil)))
  87. '()))
  88. ,@(map transformer (cddr exp)))))))))))
  89. (define (set-not-subr! proc boolean)
  90. (set! (not-subr? proc) boolean))
  91. (define (transform-lambda/interactive exp name)
  92. (fluid-set! interactive-spec #f)
  93. (let* ((x (transform-lambda exp))
  94. (is (fluid-ref interactive-spec)))
  95. `(,let ((%--lambda ,x))
  96. (,set-procedure-property! %--lambda (,quote name) (,quote ,name))
  97. (,set-not-subr! %--lambda #t)
  98. ,@(if is
  99. `((,set! (,interactive-specification %--lambda) (,quote ,is)))
  100. '())
  101. %--lambda)))
  102. (define interactive-spec (make-fluid))