]> git.donarmstrong.com Git - lilypond.git/blob - scm/ly-from-scheme.scm
* scm/output-gnome.scm (FIXME-glyph-string): New function. Cannot
[lilypond.git] / scm / ly-from-scheme.scm
1 ;;;; ly-from-scheme.scm -- parsing LilyPond music expressions from scheme
2 ;;;;
3 ;;;;  source file of the GNU LilyPond music typesetter
4 ;;;; 
5 ;;;; (c) 2004  Nicolas Sceaux  <nicolas.sceaux@free.fr>
6 ;;;;           Jan Nieuwenhuizen <janneke@gnu.org>
7
8 (define gen-lily-sym
9   ;; Generate a lilyvartmpXX symbol, that may be (hopefully) unique.
10   (let ((var-idx -1))
11     (lambda ()
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)))))))))
18
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
23      parser
24      (format #f "
25 ~a = { ~a }
26 #(ly:export '~a)
27 #(module-define! (resolve-module '~a) '~a ~a)
28 "
29              music-sym str music-sym (module-name module) music-sym music-sym))
30   (eval `,music-sym module)))
31
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 `$'
36 character."
37   (let ((bindings '()))
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))
42         tmp-symbol))
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."
46       (cond (;; $variable
47              (and (symbol? form)
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))))
52             (;; atom
53              (not (pair? form)) form)
54             (;; ($ value ...)
55              (eqv? (car 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
60                         (lambda (out)
61                           (do ((c (read-char port) (read-char port)))
62                              ((and (char=? c #\#)
63                                    (char=? (peek-char port) #\})) ;; we stop when #} is encoutered
64                               (read-char port))
65                            (cond
66                             ;; a $form expression
67                             ((and (char=? c #\$) (not (char=? (peek-char port) #\$)))
68                              (format out "\\~a" (create-binding! (read port))))
69                             ;; just a $ character
70                             ((and (char=? c #\$) (char=? (peek-char port) #\$))
71                              ;; pop the second $
72                              (display (read-char port) out))
73                             ;; a #scheme expression
74                             ((char=? c #\#)
75                              (let ((expr (read port)))
76                                (format out "#~s" (if (eq? '$ expr)
77                                                      (create-binding! (read port))
78                                                      (remove-dollars! expr)))))
79                             ;; other caracters
80                             (else
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)))
85                 (reverse bindings))
86          (ly:parse-string-result ,lily-string parser-clone (current-module))))))
87
88 (read-hash-extend #\{ read-lily-expression)