;;;; This file is part of LilyPond, the GNU music typesetter.
;;;;
-;;;; Copyright (C) 2006--2010 Erik Sandberg <mandolaerik@gmail.com>
+;;;; Copyright (C) 2006--2011 Erik Sandberg <mandolaerik@gmail.com>
;;;;
;;;; LilyPond is free software: you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License as published by
;; TODO: use separate module for syntax
;; constructors. Also create wrapper around the constructor?
-(define define-ly-syntax define-public)
+(defmacro define-ly-syntax (args . body)
+ `(define-public ,args ,(cons 'begin body)))
;; A ly-syntax constructor takes two extra parameters, parser and
;; location. These are mainly used for reporting errors and
;; location arg to set the origin of the returned music object; this
;; behaviour is usually desired
(defmacro define-ly-syntax-loc (args . body)
- (primitive-eval `(define-ly-syntax ,args
- (let ((m ,(cons 'begin body)))
- (set! (ly:music-property m 'origin) ,(third args))
- m))))
-
+ `(define-public ,args
+ (let ((m ,(cons 'begin body)))
+ (set! (ly:music-property m 'origin) ,(third args))
+ m)))
;; Like define-ly-syntax-loc, but adds parser and location
;; parameters. Useful for simple constructors that don't need to
;; report errors.
(defmacro define-ly-syntax-simple (args . body)
- (primitive-eval `(define-ly-syntax ,(cons* (car args)
- 'parser
- 'location
- (cdr args))
- (let ((m ,(cons 'begin body)))
- (set! (ly:music-property m 'origin) location)
- m))))
+ `(define-public ,(cons* (car args)
+ 'parser
+ 'location
+ (cdr args))
+ (let ((m ,(cons 'begin body)))
+ (set! (ly:music-property m 'origin) location)
+ m)))
;; Music function: Apply function and check return value.
-(define-ly-syntax-loc (music-function parser loc fun args)
- (let ((m (apply fun (cons* parser loc args))))
- (if (ly:music? m)
- m
+;; args are in reverse order, rest may specify additional ones
+;;
+;; If args is not a proper list, an error has been flagged earlier
+;; and no fallback value had been available. In this case,
+;; we don't call the function but rather return the general
+;; fallback.
+(define-ly-syntax (music-function parser loc fun args . rest)
+ (let* ((sig (object-property fun 'music-function-signature))
+ (pred (if (pair? (car sig)) (caar sig) (car sig)))
+ (good (proper-list? args))
+ (m (and good (apply fun parser loc (reverse! args rest)))))
+ (if (and good (pred m))
+ (begin
+ (if (ly:music? m)
+ (set! (ly:music-property m 'origin) loc))
+ m)
(begin
- (ly:parser-error parser (_ "Music head function must return Music object") loc)
- (make-music 'Music)))))
+ (if good
+ (ly:parser-error parser
+ (format #f (_ "~a function cannot return ~a")
+ (type-name pred) m)
+ loc))
+ (and (pair? (car sig)) (cdar sig))))))
+
+(define-ly-syntax (argument-error parser location n pred arg)
+ (ly:parser-error
+ parser
+ (format #f
+ (_ "wrong type for argument ~a. Expecting ~a, found ~s")
+ n (type-name pred) arg)
+ location))
(define-ly-syntax-simple (void-music)
(make-music 'Music))
'numerator (car fraction)
'denominator (cdr fraction)))
-(define-ly-syntax-simple (transpose-music pitch music)
- (make-music 'TransposedMusic
- 'element (ly:music-transpose music pitch)))
-
-(define-ly-syntax-simple (tempo text duration tempo)
- (let ((props (list
- (make-property-set 'tempoWholesPerMinute
- (ly:moment-mul (ly:make-moment tempo 1)
- (ly:duration-length duration)))
- (make-property-set 'tempoUnitDuration duration)
- (make-property-set 'tempoUnitCount tempo))))
- (set! props (cons
- (if text (make-property-set 'tempoText text)
- (make-property-unset 'tempoText))
- props))
- (context-spec-music
- (make-sequential-music props)
- 'Score)))
-
-(define-ly-syntax-simple (tempoText text)
- (context-spec-music
- (make-sequential-music
- (list
- (make-property-unset 'tempoUnitDuration)
- (make-property-unset 'tempoUnitCount)
- (make-property-set 'tempoText text)))
- 'Score))
-
-(define-ly-syntax-simple (skip-music dur)
- (make-music 'SkipMusic
- 'duration dur))
+(define-ly-syntax (tempo parser location text . rest)
+ (let* ((unit (and (pair? rest)
+ (car rest)))
+ (count (and unit
+ (cadr rest)))
+ (range-tempo? (pair? count))
+ (tempo-change (make-music 'TempoChangeEvent
+ 'origin location
+ 'text text
+ 'tempo-unit unit
+ 'metronome-count count))
+ (tempo-set
+ (and unit
+ (context-spec-music
+ (make-property-set 'tempoWholesPerMinute
+ (ly:moment-mul
+ (ly:make-moment
+ (if range-tempo?
+ (round (/ (+ (car count) (cdr count))
+ 2))
+ count)
+ 1)
+ (ly:duration-length unit)))
+ 'Score))))
+
+ (if tempo-set
+ (make-sequential-music (list tempo-change tempo-set))
+ tempo-change)))
(define-ly-syntax-simple (repeat type num body alts)
(make-repeat type num body alts))
'element (repetition-function previous-chord location duration articulations)
'origin location))
-(define-ly-syntax-simple (context-specification type id mus ops create-new)
+(define-ly-syntax-simple (context-specification type id ops create-new mus)
(let* ((type-sym (if (symbol? type) type (string->symbol type)))
(csm (context-spec-music mus type-sym id)))
(set! (ly:music-property csm 'property-operations) ops)
(let* ((set (and (integer? label)
(context-spec-music (make-property-set 'rehearsalMark label)
'Score)))
- (ev (make-music 'MarkEvent))
- (ch (make-event-chord (list ev))))
+ (ev (make-music 'MarkEvent
+ 'origin location)))
- (set! (ly:music-property ev 'origin) location)
(if set
- (make-sequential-music (list set ch))
+ (make-sequential-music (list set ev))
(begin
(set! (ly:music-property ev 'label) label)
- ch))))
+ ev))))