1 ;;;; This file is part of LilyPond, the GNU music typesetter.
3 ;;;; Copyright (C) 2004--2011 Nicolas Sceaux <nicolas.sceaux@free.fr>
4 ;;;; Jan Nieuwenhuizen <janneke@gnu.org>
6 ;;;; LilyPond is free software: you can redistribute it and/or modify
7 ;;;; it under the terms of the GNU General Public License as published by
8 ;;;; the Free Software Foundation, either version 3 of the License, or
9 ;;;; (at your option) any later version.
11 ;;;; LilyPond is distributed in the hope that it will be useful,
12 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ;;;; GNU General Public License for more details.
16 ;;;; You should have received a copy of the GNU General Public License
17 ;;;; along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 ;; Generate a lilyvartmpXX symbol, that may be (hopefully) unique.
23 (set! var-idx (1+ var-idx))
24 (string->symbol (format #f "lilyvartmp~a"
25 (list->string (map (lambda (chr)
26 (integer->char (+ (char->integer #\a)
27 (- (char->integer chr)
28 (char->integer #\0)))))
29 (string->list (number->string var-idx)))))))))
31 (define-public (read-lily-expression chr port)
32 "Read a lilypond music expression enclosed within @code{#@}} and @code{#@}}
33 from @var{port} and return the corresponding Scheme music expression.
34 The @samp{$} character may be used to introduce Scheme forms, typically
35 symbols. @code{$$} may be used to simply write a @samp{$} character itself."
38 (define (create-binding! val)
39 "Create a new symbol, bind it to `val' and return it."
40 (let ((tmp-symbol (gen-lily-sym)))
41 (set! bindings (cons (cons tmp-symbol val) bindings))
44 (define (remove-dollars! form)
45 "Generate a form where `$variable' and `$ value' mottos are replaced
46 by new symbols, which are binded to the adequate values."
49 (string=? (substring (symbol->string form) 0 1) "$")
50 (not (and (<= 2 (string-length (symbol->string form)))
51 (string=? (substring (symbol->string form) 1 2) "$"))))
52 (create-binding! (string->symbol (substring (symbol->string form) 1))))
54 (not (pair? form)) form)
57 (cons (create-binding! (cadr form)) (remove-dollars! (cddr form))))
58 (else ;; (something ...)
59 (cons (remove-dollars! (car form)) (remove-dollars! (cdr form))))))
61 (let ((lily-string (call-with-output-string
63 (do ((c (read-char port) (read-char port)))
65 (char=? (peek-char port) #\})) ;; we stop when #} is encoutered
69 ((and (char=? c #\$) (not (char=? (peek-char port) #\$)))
70 (format out "\\~a" (create-binding! (read port))))
72 ((and (char=? c #\$) (char=? (peek-char port) #\$))
74 (display (read-char port) out))
75 ;; a #scheme expression
77 (let ((expr (read port)))
78 (format out "#~s" (if (eq? '$ expr)
79 (create-binding! (read port))
80 (remove-dollars! expr)))))
83 (display c out))))))))
84 `(let ((parser-clone (ly:parser-clone parser)))
85 ,@(map (lambda (binding)
86 `(ly:parser-define! parser-clone ',(car binding) ,(cdr binding)))
88 (ly:parse-string-expression parser-clone ,lily-string)))))
90 (read-hash-extend #\{ read-lily-expression)