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 /* When running from gui, generate output in .ly source directory. */
59 if (output_name_global.is_empty ()
60 && scm_call_0 (ly_lily_module_constant ("running-from-gui?")) == SCM_BOOL_T)
65 output_name_global = f.to_string ();
68 if (!output_name_global.is_empty ())
70 /* Interpret --output=DIR to mean --output=DIR/BASE. */
71 if (is_dir (output_name_global))
74 getcwd (cwd, PATH_MAX);
76 if (output_name_global != cwd)
78 global_path.prepend (cwd);
79 message (_f ("Changing working directory to `%s'",
80 output_name_global.to_str0 ()));
81 chdir (output_name_global.to_str0 ());
84 output_name_global = "";
87 out_file_name = File_name (output_name_global);
91 if (!init_name_global.is_empty ())
92 init = init_name_global;
96 String out_file = out_file_name.to_string ();
98 if (init.length () && global_path.find (init).is_empty ())
100 warning (_f ("can't find init file: `%s'", init));
101 warning (_f ("(search path: `%s')",
102 global_path.to_string ().to_str0 ()));
106 if ((file_name != "-") && global_path.find (file_name).is_empty ())
108 warning (_f ("can't find file: `%s'", file_name));
109 scm_throw (ly_symbol2scm ("ly-file-failed"),
110 scm_list_1 (scm_makfrom0str (file_name.to_str0 ())));
115 sources.set_path (&global_path);
117 String mapped_fn = map_file_name (file_name);
118 message (_f ("Processing `%s'", mapped_fn.to_str0 ()));
119 progress_indication ("\n");
121 Lily_parser *parser = new Lily_parser (&sources);
123 parser->parse_file (init, file_name, out_file);
125 bool error = parser->error_level_;
126 scm_gc_unprotect_object (parser->self_scm ());
129 /* TODO: pass renamed input file too. */
130 scm_throw (ly_symbol2scm ("ly-file-failed"),
131 scm_list_1 (scm_makfrom0str (file_name.to_str0 ())));
133 return SCM_UNSPECIFIED;
136 LY_DEFINE (ly_parse_string, "ly:parse-string",
137 1, 0, 0, (SCM ly_code),
138 "Parse the string LY_CODE. "
139 "Upon failure, throw @code{ly-file-failed} key.")
141 SCM_ASSERT_TYPE (scm_is_string (ly_code), ly_code, SCM_ARG1, __FUNCTION__, "string");
144 sources.set_path (&global_path);
145 Lily_parser *parser = new Lily_parser (&sources);
146 scm_module_define (global_lily_module, ly_symbol2scm ("parser"),
147 parser->self_scm ());
148 parser->parse_string (ly_scm2string (ly_code));
149 scm_gc_unprotect_object (parser->self_scm ());
152 return SCM_UNSPECIFIED;
155 LY_DEFINE (ly_clone_parser, "ly:clone-parser",
156 1, 0, 0, (SCM parser_smob),
157 "Return a clone of PARSER_SMOB.")
159 Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
160 Lily_parser *clone = new Lily_parser (*parser);
162 /* FIXME: should copy scopes too. */
163 return scm_gc_unprotect_object (clone->self_scm ());
166 LY_DEFINE (ly_parser_define, "ly:parser-define",
167 3, 0, 0, (SCM parser_smob, SCM symbol, SCM val),
168 "Bind SYMBOL to VAL in PARSER_SMOB's module.")
170 Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
171 SCM_ASSERT_TYPE (scm_is_symbol (symbol), symbol, SCM_ARG2, __FUNCTION__, "symbol");
172 SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG2, __FUNCTION__, "parser");
174 parser->lexer_->set_identifier (scm_symbol_to_string (symbol), val);
175 return SCM_UNSPECIFIED;
178 LY_DEFINE (ly_parser_lookup, "ly:parser-lookup",
179 2, 0, 0, (SCM parser_smob, SCM symbol),
180 "Lookup @var{symbol} in @var{parser_smob}'s module. "
183 Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
185 SCM_ASSERT_TYPE (scm_is_symbol (symbol), symbol, SCM_ARG2, __FUNCTION__, "symbol");
186 SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG2, __FUNCTION__, "parser");
188 SCM val = parser->lexer_->lookup_identifier (ly_scm2string (scm_symbol_to_string (symbol)));
189 if (val != SCM_UNDEFINED)
195 LY_DEFINE (ly_parser_parse_string, "ly:parser-parse-string",
196 2, 0, 0, (SCM parser_smob, SCM ly_code),
197 "Parse the string LY_CODE with PARSER_SMOB."
198 "Upon failure, throw @code{ly-file-failed} key.")
200 Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
202 SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG1, __FUNCTION__, "parser");
203 SCM_ASSERT_TYPE (scm_is_string (ly_code), ly_code, SCM_ARG2, __FUNCTION__, "string");
205 parser->parse_string (ly_scm2string (ly_code));
207 return SCM_UNSPECIFIED;
210 /* TODO: move this to Scheme? Why take the parser arg, and all the back
211 & forth between scm and c++? */
212 LY_DEFINE (ly_parser_print_score, "ly:parser-print-score",
214 (SCM parser_smob, SCM score_smob),
215 "Print score, i.e., the classic way.")
217 Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
218 Score *score = unsmob_score (score_smob);
220 Object_key *key = new Lilypond_general_key (0, score->user_key_, 0);
222 if (score->error_found_)
223 return SCM_UNSPECIFIED;
225 SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG1, __FUNCTION__, "parser");
226 SCM_ASSERT_TYPE (score, score_smob, SCM_ARG2, __FUNCTION__, "score");
228 SCM header = ly_c_module_p (score->header_)
230 : parser->lexer_->lookup_identifier ("$globalheader");
232 File_name outname (parser->output_basename_);
233 int *c = &parser->book_count_;
235 outname.base_ += "-" + to_string (*c);
238 SCM os = scm_makfrom0str (outname.to_string ().to_str0 ());
239 SCM paper = get_paper (parser)->self_scm ();
240 for (int i = 0; i < score->defs_.size (); i++)
241 default_rendering (score->get_music (), score->defs_[i]->self_scm (),
242 paper, header, os, key->self_scm ());
244 if (score->defs_.is_empty ())
246 Output_def *layout = get_layout (parser);
247 default_rendering (score->get_music (),
250 header, os, key->self_scm ());
252 scm_gc_unprotect_object (layout->self_scm ());
255 scm_gc_unprotect_object (paper);
256 scm_gc_unprotect_object (key->self_scm ());
257 return SCM_UNSPECIFIED;
260 LY_DEFINE (ly_parser_set_note_names, "ly:parser-set-note-names",
261 2, 0, 0, (SCM parser, SCM names),
262 "Replace current note names in @var{parser}. "
263 "@var{names} is an alist of symbols. "
264 "This only has effect if the current mode is notes.")
266 Lily_parser *p = unsmob_my_lily_parser (parser);
267 SCM_ASSERT_TYPE (p, parser, SCM_ARG1, __FUNCTION__, "Lilypond parser");
269 if (p->lexer_->is_note_state ())
271 p->lexer_->pop_state ();
272 p->lexer_->push_note_state (alist_to_hashq (names));
275 return SCM_UNSPECIFIED;
278 LY_DEFINE (ly_parser_print_book, "ly:parser-print-book",
279 2, 0, 0, (SCM parser_smob, SCM book_smob),
282 Lily_parser *parser = unsmob_my_lily_parser (parser_smob);
283 Book *book = unsmob_book (book_smob);
284 Output_def *bp = unsmob_output_def (parser->lexer_->lookup_identifier ("$defaultpaper"));
286 SCM_ASSERT_TYPE (parser, parser_smob, SCM_ARG1, __FUNCTION__, "Lilypond parser");
287 SCM_ASSERT_TYPE (book, book_smob, SCM_ARG2, __FUNCTION__, "Book");
289 /* ugh. changing argument.*/
292 File_name outname (parser->output_basename_);
293 int *c = &parser->book_count_;
295 outname.base_ += "-" + to_string (*c);
298 Output_def *layout = get_layout (parser);
299 Paper_book *pb = book->process (outname.to_string (), layout);
303 pb->output (outname.to_string ());
304 scm_gc_unprotect_object (pb->self_scm ());
307 scm_gc_unprotect_object (layout->self_scm ());
308 return SCM_UNSPECIFIED;