1 ;;;; ly-from-scheme.scm -- parsing LilyPond music expressions from scheme
3 ;;;; source file of the GNU LilyPond music typesetter
5 ;;;; (c) 2004 Nicolas Sceaux <nicolas.sceaux@free.fr>
6 ;;;; Jan Nieuwenhuizen <janneke@gnu.org>
9 ;; Generate a lilyvartmpXX symbol, that may be (hopefully) unique.
12 (set! var-idx (1+ var-idx))
13 (string->symbol (format #f "lilyvartmp~a"
14 (list->string (map (lambda (chr)
15 (integer->char (+ (char->integer #\a) (- (char->integer chr)
16 (char->integer #\0)))))
17 (string->list (number->string var-idx)))))))))
19 (define-public (ly:parse-string-result str parser module)
20 "Parse `str', which is supposed to contain a music expression."
21 (let ((music-sym (gen-lily-sym)))
22 (ly:parser-parse-string
27 #(module-define! (resolve-module '~a) '~a ~a)
29 music-sym str music-sym (module-name module) music-sym music-sym))
30 (eval `,music-sym module)))
32 (define-public (read-lily-expression chr port)
33 "Read a #{ lily music expression #} from port and return
34 the scheme music expression. The $ character may be used to introduce
35 scheme forms, typically symbols. $$ may be used to simply write a `$'
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))
43 (define (remove-dollars! form)
44 "Generate a form where `$variable' and `$ value' mottos are replaced
45 by new symbols, which are binded to the adequate values."
48 (string=? (substring (symbol->string form) 0 1) "$")
49 (not (and (<= 2 (string-length (symbol->string form)))
50 (string=? (substring (symbol->string form) 1 2) "$"))))
51 (create-binding! (string->symbol (substring (symbol->string form) 1))))
53 (not (pair? form)) form)
56 (cons (create-binding! (cadr form)) (remove-dollars! (cddr form))))
57 (else ;; (something ...)
58 (cons (remove-dollars! (car form)) (remove-dollars! (cdr form))))))
59 (let ((lily-string (call-with-output-string
61 (do ((c (read-char port) (read-char port)))
63 (char=? (peek-char port) #\})) ;; we stop when #} is encoutered
67 ((and (char=? c #\$) (not (char=? (peek-char port) #\$)))
68 (format out "\\~a" (create-binding! (read port))))
70 ((and (char=? c #\$) (char=? (peek-char port) #\$))
72 (display (read-char port) out))
73 ;; a #scheme expression
75 (let ((expr (read port)))
76 (format out "#~s" (if (eq? '$ expr)
77 (create-binding! (read port))
78 (remove-dollars! expr)))))
81 (display c out))))))))
82 `(let ((parser-clone (ly:clone-parser parser)))
83 ,@(map (lambda (binding)
84 `(ly:parser-define parser-clone ',(car binding) ,(cdr binding)))
86 (ly:parse-string-result ,lily-string parser-clone (current-module))))))
88 (read-hash-extend #\{ read-lily-expression)