summaryrefslogtreecommitdiff
path: root/src/guile/skribilo/lib.scm
diff options
context:
space:
mode:
Diffstat (limited to 'src/guile/skribilo/lib.scm')
-rw-r--r--src/guile/skribilo/lib.scm137
1 files changed, 92 insertions, 45 deletions
diff --git a/src/guile/skribilo/lib.scm b/src/guile/skribilo/lib.scm
index feb5c8a..96bf483 100644
--- a/src/guile/skribilo/lib.scm
+++ b/src/guile/skribilo/lib.scm
@@ -1,6 +1,6 @@
;;; lib.scm -- Utilities. -*- coding: iso-8859-1 -*-
;;;
-;;; Copyright 2005, 2007, 2009 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright 2005, 2007, 2009, 2012 Ludovic Courtès <ludo@gnu.org>
;;; Copyright 2003, 2004 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
;;;
;;;
@@ -65,50 +65,97 @@
;;;
;;; DEFINE-MARKUP
;;;
-(define-macro (define-markup bindings . body)
- ;; This is just an `(ice-9 optargs)' kind of `lambda*', with DSSSL
- ;; keyword-style conversion enabled. However, using `(ice-9 optargs)', the
- ;; `:rest' argument can only appear last, which is not what Skribe/DSSSL
- ;; expect, hence `fix-rest-arg'. In addition, all keyword arguments are
- ;; allowed (hence `:allow-other-keys'); they are then checked by `verify'.
- (define (fix-rest-arg args)
- (let loop ((args args)
- (result '())
- (rest-arg '())
- (has-keywords? #f))
- (cond ((null? args)
- (let ((result (if has-keywords?
- (cons :allow-other-keys result)
- result)))
- (append! (reverse! result) rest-arg)))
-
- ((list? args)
- (let ((is-rest-arg? (eq? (car args) :rest))
- (is-keyword? (eq? (car args) :key)))
- (if is-rest-arg?
- (loop (cddr args)
- result
- (list (car args) (cadr args))
- (or has-keywords? is-keyword?))
- (loop (cdr args)
- (cons (car args) result)
- rest-arg
- (or has-keywords? is-keyword?)))))
-
- ((pair? args)
- (loop '()
- (cons (car args) result)
- (list #:rest (cdr args))
- has-keywords?)))))
-
- (let ((name (car bindings))
- (opts (cdr bindings)))
- `(define*-public ,(cons name (fix-rest-arg opts))
- ;; Memorize the invocation location. Note: the invocation depth
- ;; passed to `invocation-location' was determined experimentally and
- ;; may change as Guile changes (XXX).
- (let ((&invocation-location (invocation-location 3)))
- ,@body))))
+
+(define (dsssl->guile-formals args)
+ ;; When using `(ice-9 optargs)', the `:rest' argument can only appear last,
+ ;; which is not what Skribe/DSSSL expect'. In addition, all keyword
+ ;; arguments are allowed (hence `:allow-other-keys'); they are then checked
+ ;; by `verify'. This procedure shuffles ARGS accordingly.
+
+ (let loop ((args args)
+ (result '())
+ (rest-arg '())
+ (has-keywords? #f))
+ (cond ((null? args)
+ (let ((result (if has-keywords?
+ (cons :allow-other-keys result)
+ result)))
+ (append (reverse result) rest-arg)))
+
+ ((list? args)
+ (let ((is-rest-arg? (eq? (car args) :rest))
+ (is-keyword? (eq? (car args) :key)))
+ (if is-rest-arg?
+ (loop (cddr args)
+ result
+ (list (car args) (cadr args))
+ (or has-keywords? is-keyword?))
+ (loop (cdr args)
+ (cons (car args) result)
+ rest-arg
+ (or has-keywords? is-keyword?)))))
+
+ ((pair? args)
+ (loop '()
+ (cons (car args) result)
+ (list :rest (cdr args))
+ has-keywords?)))))
+
+;; `define-markup' is similar to Guile's `lambda*', with DSSSL
+;; keyword style, and a couple other differences handled by
+;; `dsssl->guile-formals'.
+
+(cond-expand
+ (guile-2
+ ;; On Guile 2.0, `define-markup' generates a macro for the markup, such
+ ;; that the macro captures its invocation source location using
+ ;; `current-source-location'.
+
+ (define-syntax define-markup
+ (lambda (s)
+ (syntax-case s ()
+ ;; Note: Use a dotted pair for formals, to allow for dotted forms
+ ;; like: `(define-markup (foo x . rest) ...)'.
+ ((_ (name . formals) body ...)
+ (let ((formals (map (lambda (s)
+ (datum->syntax #'formals s))
+ (dsssl->guile-formals (syntax->datum #'formals))))
+ (internal (symbol-append '% (syntax->datum #'name)
+ '-internal)))
+ (with-syntax ((internal/loc (datum->syntax #'name internal)))
+ #`(begin
+ (define* (internal/loc loc #,@formals)
+ (syntax-parameterize ((&invocation-location
+ (identifier-syntax loc)))
+ body ...))
+ (define-syntax name
+ (lambda (s)
+ (syntax-case s ()
+ ((_ . args)
+ #'(let ((loc (source-properties->location
+ (current-source-location))))
+ (internal/loc loc . args)))
+ (_
+ #'(lambda args
+ (let ((loc (source-properties->location
+ (current-source-location))))
+ (apply internal/loc loc args)))))))
+ internal/loc ; mark it as used
+ (export name)))))))))
+
+ (else ; Guile 1.8
+ ;; On Guile 1.8, a markup is a procedure. Its invocation source location
+ ;; is captured by walking the stack, which is fragile.
+
+ (define-macro (define-markup bindings . body)
+ (let ((name (car bindings))
+ (opts (cdr bindings)))
+ `(define*-public ,(cons name (dsssl->guile-formals opts))
+ ;; Memorize the invocation location. Note: the invocation depth
+ ;; passed to `invocation-location' was determined experimentally and
+ ;; may change as Guile changes (XXX).
+ (let ((&invocation-location (invocation-location 3)))
+ ,@body))))))
;;;