2 lily-parser-scheme.cc -- implement Lily_parser bindings
4 source file of the GNU LilyPond music typesetter
6 (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
11 #include "file-name.hh"
12 #include "file-path.hh"
14 #include "lily-parser.hh"
17 #include "lily-lexer.hh"
19 #include "lilypond-key.hh"
20 #include "ly-module.hh"
21 #include "output-def.hh"
23 #include "paper-book.hh"
24 #include "file-name-map.hh"
26 /* Do not append `!' suffix, since 1st argument is not modified. */
27 LY_DEFINE (ly_set_point_and_click, "ly:set-point-and-click",
32 warning (_f ("deprecated function called: %s", "ly:set-point-and-click"));
33 return SCM_UNSPECIFIED;
36 LY_DEFINE (ly_parse_file, "ly:parse-file",
38 "Parse a single @code{.ly} file. "
39 "Upon failure, throw @code{ly-file-failed} key.")
41 SCM_ASSERT_TYPE (scm_is_string (name), name, SCM_ARG1, __FUNCTION__, "string");
42 char const *file = scm_i_string_chars (name);
43 char const *extensions[] = {"ly", "", 0};
45 String file_name = global_path.find (file, extensions);
47 /* By default, use base name of input file for output file name,
48 write output to cwd; do not use root and directory parts of input
50 File_name out_file_name (file_name);
52 global_path.append (out_file_name.dir_);
54 out_file_name.ext_ = "";
55 out_file_name.root_ = "";
56 out_file_name.dir_ = "";
58 if (!output_name_global.is_empty ())
60 if (is_dir (output_name_global))
63 getcwd (cwd, PATH_MAX);
65 if (output_name_global != cwd)
67 global_path.prepend (cwd);
68 message (_f ("Changing working directory to `%s'",
69 output_name_global.to_str0 ()));
70 chdir (output_name_global.to_str0 ());
73 output_name_global = "";
76 out_file_name = File_name (output_name_global);
80 if (!init_name_global.is_empty ())
81 init = init_name_global;
85 String out_file = out_file_name.to_string ();
87 if (init.length () && global_path.find (init).is_empty ())
89 warning (_f ("can't find init file: `%s'", init));
90 warning (_f ("(search path: `%s')",
91 global_path.to_string ().to_str0 ()));
95 if ((file_name != "-") && global_path.find (file_name).is_empty ())
97 warning (_f ("can't find file: `%s'", file_name));
98 scm_throw (ly_symbol2scm ("ly-file-failed"),
99 scm_list_1 (scm_makfrom0str (file_name.to_str0 ())));
104 sources.set_path (&global_path);
106 String mapped_fn = map_file_name (file_name);
107 message (_f ("Processing `%s'", mapped_fn.to_str0 ()));
108 progress_indication ("\n");
110 Lily_parser *parser = new Lily_parser (&sources);
112 parser->parse_file (init, file_name, out_file);
114 bool error = parser->error_level_;
115 scm_gc_unprotect_object (parser->self_scm ());
118 /* TODO: pass renamed input file too. */
119 scm_throw (ly_symbol2scm ("ly-file-failed"),
120 scm_list_1 (scm_makfrom0str (file_name.to_str0 ())));
122 return SCM_UNSPECIFIED;
125 LY_DEFINE (ly_parse_string, "ly:parse-string",
126 1, 0, 0, (SCM ly_code),
127 "Parse the string LY_CODE. "
128 "Upon failure, throw @code{ly-file-failed} key.")
130 SCM_ASSERT_TYPE (scm_is_string (ly_code), ly_code, SCM_ARG1, __FUNCTION__, "string");
133 sources.set_path (&global_path);
134 Lily_parser *parser = new Lily_parser (&sources);
135 scm_module_define (global_lily_module, ly_symbol2scm ("parser"),
136 parser->self_scm ());
137 parser->parse_string (ly_scm2string (ly_code));
138 scm_gc_unprotect_object (parser->self_scm ());
141 return SCM_UNSPECIFIED;
144 LY_DEFINE (ly_clone_parser, "ly:clone-parser",
145 1, 0, 0, (SCM parser_smob),
146 "Return a clone of PARSER_SMOB.")
148 Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
149 Lily_parser *clone = new Lily_parser (*parser);
151 /* FIXME: should copy scopes too. */
152 return scm_gc_unprotect_object (clone->self_scm ());
155 LY_DEFINE (ly_parser_define, "ly:parser-define",
156 3, 0, 0, (SCM parser_smob, SCM symbol, SCM val),
157 "Bind SYMBOL to VAL in PARSER_SMOB's module.")
159 Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
160 SCM_ASSERT_TYPE (scm_is_symbol (symbol), symbol, SCM_ARG2, __FUNCTION__, "symbol");
161 SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG2, __FUNCTION__, "parser");
163 parser->lexer_->set_identifier (scm_symbol_to_string (symbol), val);
164 return SCM_UNSPECIFIED;
167 LY_DEFINE (ly_parser_lookup, "ly:parser-lookup",
168 2, 0, 0, (SCM parser_smob, SCM symbol),
169 "Lookup @var{symbol} in @var{parser_smob}'s module. "
172 Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
174 SCM_ASSERT_TYPE (scm_is_symbol (symbol), symbol, SCM_ARG2, __FUNCTION__, "symbol");
175 SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG2, __FUNCTION__, "parser");
177 SCM val = parser->lexer_->lookup_identifier (ly_scm2string (scm_symbol_to_string (symbol)));
178 if (val != SCM_UNDEFINED)
184 LY_DEFINE (ly_parser_parse_string, "ly:parser-parse-string",
185 2, 0, 0, (SCM parser_smob, SCM ly_code),
186 "Parse the string LY_CODE with PARSER_SMOB."
187 "Upon failure, throw @code{ly-file-failed} key.")
189 Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
191 SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG1, __FUNCTION__, "parser");
192 SCM_ASSERT_TYPE (scm_is_string (ly_code), ly_code, SCM_ARG2, __FUNCTION__, "string");
194 parser->parse_string (ly_scm2string (ly_code));
196 return SCM_UNSPECIFIED;
199 /* TODO: move this to Scheme? Why take the parser arg, and all the back
200 & forth between scm and c++? */
201 LY_DEFINE (ly_parser_print_score, "ly:parser-print-score",
203 (SCM parser_smob, SCM score_smob),
204 "Print score, i.e., the classic way.")
206 Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
207 Score *score = unsmob_score (score_smob);
209 Object_key *key = new Lilypond_general_key (0, score->user_key_, 0);
211 if (score->error_found_)
212 return SCM_UNSPECIFIED;
214 SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG1, __FUNCTION__, "parser");
215 SCM_ASSERT_TYPE (score, score_smob, SCM_ARG2, __FUNCTION__, "score");
217 SCM header = ly_c_module_p (score->header_)
219 : parser->lexer_->lookup_identifier ("$globalheader");
221 File_name outname (parser->output_basename_);
222 int *c = &parser->book_count_;
224 outname.base_ += "-" + to_string (*c);
227 SCM os = scm_makfrom0str (outname.to_string ().to_str0 ());
228 SCM paper = get_paper (parser)->self_scm ();
229 for (int i = 0; i < score->defs_.size (); i++)
230 default_rendering (score->get_music (), score->defs_[i]->self_scm (),
231 paper, header, os, key->self_scm ());
233 if (score->defs_.is_empty ())
235 Output_def *layout = get_layout (parser);
236 default_rendering (score->get_music (),
239 header, os, key->self_scm ());
241 scm_gc_unprotect_object (layout->self_scm ());
244 scm_gc_unprotect_object (paper);
245 scm_gc_unprotect_object (key->self_scm ());
246 return SCM_UNSPECIFIED;
249 LY_DEFINE (ly_parser_set_note_names, "ly:parser-set-note-names",
250 2, 0, 0, (SCM parser, SCM names),
251 "Replace current note names in @var{parser}. "
252 "@var{names} is an alist of symbols. "
253 "This only has effect if the current mode is notes.")
255 Lily_parser *p = unsmob_my_lily_parser (parser);
256 SCM_ASSERT_TYPE (p, parser, SCM_ARG1, __FUNCTION__, "Lilypond parser");
258 if (p->lexer_->is_note_state ())
260 p->lexer_->pop_state ();
261 p->lexer_->push_note_state (alist_to_hashq (names));
264 return SCM_UNSPECIFIED;
267 LY_DEFINE (ly_parser_print_book, "ly:parser-print-book",
268 2, 0, 0, (SCM parser_smob, SCM book_smob),
271 Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
272 Book *book = unsmob_book (book_smob);
273 Output_def *bp = unsmob_output_def (parser->lexer_->lookup_identifier ("$defaultpaper"));
275 SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG1, __FUNCTION__, "Lilypond parser");
276 SCM_ASSERT_TYPE (book, book_smob, SCM_ARG2, __FUNCTION__, "Book");
278 /* ugh. changing argument.*/
281 File_name outname (parser->output_basename_);
282 int *c = &parser->book_count_;
284 outname.base_ += "-" + to_string (*c);
287 Output_def *layout = get_layout (parser);
288 Paper_book *pb = book->process (outname.to_string (), layout);
292 pb->output (outname.to_string ());
293 scm_gc_unprotect_object (pb->self_scm ());
296 scm_gc_unprotect_object (layout->self_scm ());
297 return SCM_UNSPECIFIED;