]> git.donarmstrong.com Git - lilypond.git/blob - scm/parser-ly-from-scheme.scm
[scm] Improve formatting of `define-public' functions.
[lilypond.git] / scm / parser-ly-from-scheme.scm
1 ;;;; This file is part of LilyPond, the GNU music typesetter.
2 ;;;;
3 ;;;; Copyright (C) 2004--2011  Nicolas Sceaux  <nicolas.sceaux@free.fr>
4 ;;;;           Jan Nieuwenhuizen <janneke@gnu.org>
5 ;;;;
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.
10 ;;;;
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.
15 ;;;;
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/>.
18
19 (define gen-lily-sym
20   ;; Generate a lilyvartmpXX symbol, that may be (hopefully) unique.
21   (let ((var-idx -1))
22     (lambda ()
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)))))))))
30
31 (define-public (parse-string-result str parser)
32   "Parse @var{str}, which is supposed to contain a music expression."
33
34   (ly:parser-parse-string
35    parser
36    (format #f "parseStringResult = \\notemode { ~a }" str))
37   (ly:parser-lookup parser 'parseStringResult))
38
39 (define-public (read-lily-expression chr port)
40   "Read a lilypond music expression enclosed within @code{#@}} and @code{#@}}
41 from @var{port} and return the corresponding Scheme music expression.
42 The @samp{$} character may be used to introduce Scheme forms, typically
43 symbols.  @code{$$} may be used to simply write a @samp{$} character itself."
44   (let ((bindings '()))
45
46     (define (create-binding! val)
47       "Create a new symbol, bind it to `val' and return it."
48       (let ((tmp-symbol (gen-lily-sym)))
49         (set! bindings (cons (cons tmp-symbol val) bindings))
50         tmp-symbol))
51     
52     (define (remove-dollars! form)
53       "Generate a form where `$variable' and `$ value' mottos are replaced
54       by new symbols, which are binded to the adequate values."
55       (cond (;; $variable
56              (and (symbol? form)
57                   (string=? (substring (symbol->string form) 0 1) "$")
58                   (not (and (<= 2 (string-length (symbol->string form)))
59                             (string=? (substring (symbol->string form) 1 2) "$"))))
60              (create-binding! (string->symbol (substring (symbol->string form) 1))))
61             (;; atom
62              (not (pair? form)) form)
63             (;; ($ value ...)
64              (eqv? (car form) '$)
65              (cons (create-binding! (cadr form)) (remove-dollars! (cddr form))))
66             (else ;; (something ...)
67              (cons (remove-dollars! (car form)) (remove-dollars! (cdr form))))))
68     
69     (let ((lily-string (call-with-output-string
70                         (lambda (out)
71                           (do ((c (read-char port) (read-char port)))
72                               ((and (char=? c #\#)
73                                     (char=? (peek-char port) #\})) ;; we stop when #} is encoutered
74                                (read-char port))
75                             (cond
76                              ;; a $form expression
77                              ((and (char=? c #\$) (not (char=? (peek-char port) #\$)))
78                               (format out "\\~a" (create-binding! (read port))))
79                              ;; just a $ character
80                              ((and (char=? c #\$) (char=? (peek-char port) #\$))
81                               ;; pop the second $
82                               (display (read-char port) out))
83                              ;; a #scheme expression
84                              ((char=? c #\#)
85                               (let ((expr (read port)))
86                                 (format out "#~s" (if (eq? '$ expr)
87                                                       (create-binding! (read port))
88                                                       (remove-dollars! expr)))))
89                              ;; other caracters
90                              (else
91                               (display c out))))))))
92       `(let ((parser-clone (ly:parser-clone parser)))
93          ,@(map (lambda (binding)
94                   `(ly:parser-define! parser-clone ',(car binding) ,(cdr binding)))
95                 (reverse bindings))
96          (parse-string-result ,lily-string parser-clone)))))
97
98 (read-hash-extend #\{ read-lily-expression)