1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3 
4   Copyright (C) 1998--2021 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 
20 #ifndef LILY_GUILE_HH
21 #define LILY_GUILE_HH
22 
23 #include "config.hh"
24 
25 #if __MINGW32__
26 #include "mingw-compatibility.hh"
27 #endif
28 
29 #if HAVE_LIBGUILE18_H
30 # include <libguile18.h>
31 #else
32 # include <libguile.h>
33 #endif
34 #include <limits>
35 #include <string.h>
36 
37 /*
38   Hack for various MacOS incarnations.
39  */
40 #ifndef GUILE_ELLIPSIS
41 #define GUILE_ELLIPSIS
42 #endif
43 
44 #include "axis.hh"
45 #include "memory.hh"
46 #include "guile-compatibility.hh"
47 #include "interval.hh"
48 #include "lily-guile-macros.hh"
49 
50 /** Conversion functions follow the GUILE naming convention, i.e.
51     A ly_B2A (B b);  */
52 
53 SCM ly_last (SCM list);
54 std::string ly_scm_write_string (SCM s);
55 SCM ly_deep_copy (SCM);
56 
57 std::string gulp_file_to_string (const std::string &fn, bool must_exist, int size);
58 
59 SCM ly_string2scm (std::string const &s);
60 std::string ly_scm2string (SCM s);
61 std::string ly_symbol2string (SCM);
62 std::string robust_symbol2string (SCM, const std::string &);
63 SCM ly_chain_assoc (SCM key, SCM achain);
64 SCM ly_chain_assoc_get (SCM key, SCM achain, SCM default_value, SCM strict_checking = SCM_BOOL_F);
65 
ly_assoc(SCM key,SCM alist)66 inline SCM ly_assoc (SCM key, SCM alist)
67 {
68   return (scm_is_symbol (key) || SCM_IMP (key)) ? scm_assq (key, alist) : scm_assoc (key, alist);
69 }
70 
71 SCM ly_assoc_get (SCM key, SCM alist, SCM default_value, SCM strict_checking = SCM_BOOL_F);
72 SCM ly_memv (SCM, SCM);
73 Slice int_list_to_slice (SCM l);
74 unique_stdlib_ptr<char> ly_scm2str0 (SCM str);
75 
76 std::string robust_scm2string (SCM, const std::string &);
77 
78 bool type_check_assignment (SCM val, SCM sym, SCM type_symbol);
79 std::string print_scm_val (SCM val);
80 SCM ly_number2string (SCM s);
81 
82 SCM parse_symbol_list (char const *);
83 SCM robust_list_ref (int i, SCM l);
84 SCM alist_to_hashq (SCM);
85 
86 SCM ly_alist_vals (SCM alist);
87 SCM ly_hash2alist (SCM tab);
88 SCM ly_hash_table_keys (SCM tab);
89 
90 SCM ly_assoc_prepend_x (SCM alist, SCM key, SCM val);
91 SCM ly_alist_copy (SCM alist);
92 
ly_is_list(SCM x)93 inline bool ly_is_list (SCM x) { return scm_is_true (scm_list_p (x)); }
ly_cheap_is_list(SCM x)94 inline bool ly_cheap_is_list (SCM x) { return scm_is_pair (x) || scm_is_null (x); }
ly_is_module(SCM x)95 inline bool ly_is_module (SCM x) { return SCM_MODULEP (x); }
ly_is_procedure(SCM x)96 inline bool ly_is_procedure (SCM x) { return scm_is_true (scm_procedure_p (x)); }
ly_is_port(SCM x)97 inline bool ly_is_port (SCM x) { return scm_is_true (scm_port_p (x)); }
98 
99 /*
100   want to take the address of this function; scm_is_symbol() is a
101   macro.
102  */
ly_is_symbol(SCM x)103 inline bool ly_is_symbol (SCM x) { return scm_is_symbol (x); }
104 
105 // Is the given value an *integer* in the valid range of Unicode code points?
106 // Note the difference between this and a *character*.
ly_is_unicode_integer(SCM x)107 inline bool ly_is_unicode_integer (SCM x)
108 {
109   return scm_is_unsigned_integer (x, 0, 0x10FFFFL);
110 }
111 
ly_is_equal(SCM x,SCM y)112 inline bool ly_is_equal (SCM x, SCM y)
113 {
114   return scm_is_true (scm_equal_p (x, y));
115 }
116 
ly_scm2bool(SCM x)117 inline bool ly_scm2bool (SCM x) { return scm_is_true (x); }
ly_scm2char(SCM x)118 inline char ly_scm2char (SCM x) { return (char)SCM_CHAR (x); }
ly_bool2scm(bool x)119 inline SCM ly_bool2scm (bool x) { return scm_from_bool (x); }
120 
ly_append2(SCM x1,SCM x2)121 inline SCM ly_append2 (SCM x1, SCM x2)
122 {
123   return scm_append (scm_list_2 (x1, x2));
124 }
ly_append3(SCM x1,SCM x2,SCM x3)125 inline SCM ly_append3 (SCM x1, SCM x2, SCM x3)
126 {
127   return scm_append (scm_list_3 (x1, x2, x3));
128 }
ly_append4(SCM x1,SCM x2,SCM x3,SCM x4)129 inline SCM ly_append4 (SCM x1, SCM x2, SCM x3, SCM x4)
130 {
131   return scm_append (scm_list_4 (x1, x2, x3, x4));
132 }
133 
134 /*
135   display and print newline.
136 */
137 extern "C" {
138   void ly_display_scm (SCM s);
139 }
140 
141 void read_lily_scm_file (std::string);
142 void ly_c_init_guile ();
143 
144 bool is_number_pair (SCM);
145 
146 SCM index_get_cell (SCM cell, Direction d);
147 SCM index_set_cell (SCM cell, Direction d, SCM val);
148 
149 /*
150   snarfing.
151 */
152 void add_scm_init_func (void ( *) ());
153 
154 /*
155   Inline these for performance reasons.
156  */
157 #define scm_cdr ly_cdr
158 #define scm_car ly_car
159 
160 #ifndef scm_is_pair
161 #define scm_is_pair ly_is_pair
162 #endif
163 
ly_car(SCM x)164 inline SCM ly_car (SCM x) { return SCM_CAR (x); }
ly_cdr(SCM x)165 inline SCM ly_cdr (SCM x) { return SCM_CDR (x); }
ly_is_pair(SCM x)166 inline bool ly_is_pair (SCM x) { return SCM_I_CONSP (x); }
167 
168 // Wrap scm_internal_hash_fold() to reduce the number of places we need to use
169 // reinterpret_cast.
170 inline SCM
ly_scm_hash_fold(SCM (* fn)(void * closure,SCM key,SCM val,SCM result),void * closure,SCM init,SCM table)171 ly_scm_hash_fold (SCM (*fn) (void *closure, SCM key, SCM val, SCM result),
172                   void *closure, SCM init, SCM table)
173 {
174 #if !HAVE_GUILE_HASH_FUNC
175   // For backward compatibility with Guile 1.8
176   typedef SCM (*scm_t_hash_fold_fn) (GUILE_ELLIPSIS);
177 #endif
178 
179   return scm_internal_hash_fold (reinterpret_cast<scm_t_hash_fold_fn> (fn),
180                                  closure, init, table);
181 }
182 
183 // These are patterns for conversion functions.  We currently use them to
184 // predict the return types of overloaded functions before they are defined,
185 // but other things could be added here, if necessary.
186 template <typename T>
187 struct conv_scm_traits
188 {
189   static T from (SCM);
190 
191   static SCM to (const T &);
192 };
193 
194 // specialization for SCM passthrough, which is convenient in generic code
195 template <>
196 struct conv_scm_traits<SCM>
197 {
198   static const SCM &from (const SCM &);
199   static SCM &from (SCM &);
200 
201   static const SCM &to (const SCM &);
202   static SCM &to (SCM &);
203 };
204 
205 // since partial template specialisation is not available for
206 // functions, we default to reflecting to a helper class for template
207 // types like Drul_array
208 template <typename T> struct scm_conversions;
209 
210 template <typename T> inline bool
is_scm(SCM s)211 is_scm (SCM s)
212 {
213   return scm_conversions<T>::is_scm (s);
214 }
215 
216 template <typename T> inline auto
from_scm(const SCM & s)217 from_scm (const SCM &s)->decltype (conv_scm_traits<T>::from (s))
218 {
219   return scm_conversions<T>::from_scm (s);
220 }
221 template <typename T> inline auto
from_scm(SCM & s)222 from_scm (SCM &s)->decltype (conv_scm_traits<T>::from (s))
223 {
224   const auto &cs = s;
225   return ::from_scm<T> (cs); // defer to the const & overload
226 }
227 
228 // "robust" variant with fallback
229 template <typename T> inline auto
from_scm(const SCM & s,T fallback)230 from_scm (const SCM &s, T fallback)->decltype (conv_scm_traits<T>::from (s))
231 {
232   return scm_conversions<T>::from_scm (s, fallback);
233 }
234 template <typename T> inline auto
from_scm(SCM & s,T fallback)235 from_scm (SCM &s, T fallback)->decltype (conv_scm_traits<T>::from (s))
236 {
237   const auto &cs = s;
238   return ::from_scm<T> (cs, fallback); // defer to the const & overload
239 }
240 
241 template <typename T> inline auto
to_scm(const T & v)242 to_scm (const T &v)->decltype (conv_scm_traits<T>::to (v))
243 {
244   return scm_conversions<T>::to_scm (v);
245 }
246 template <typename T> inline auto
to_scm(T & v)247 to_scm (T &v)->decltype (conv_scm_traits<T>::to (v))
248 {
249   const auto &cv = v;
250   return ::to_scm (cv); // defer to the const & overload
251 }
252 
253 template <typename T> struct scm_conversions
254 {
255   // Add a default rule implementing robust_scm2T
256   //
257   // For better or worse, whenever we are specialising
258   // scm_conversions, we'll need to add this rule back in.
259   //
260   // An alternative would be to have a separate specialisation class
261   // just for the fallback
from_scmscm_conversions262   static T from_scm (SCM s, T fallback)
263   {
264     return ::is_scm<T> (s) ? ::from_scm<T> (s) : fallback;
265   }
266 };
267 
268 // These pass-through conversions for SCM are useful in generic code.
is_scm(SCM)269 template <> inline bool is_scm<SCM> (SCM) { return true; }
270 
from_scm(const SCM & s)271 template <> inline const SCM &from_scm<SCM> (const SCM &s) { return s; }
from_scm(SCM & s)272 template <> inline SCM &from_scm<SCM> (SCM &s) { return s; }
273 
from_scm(const SCM & s,SCM)274 template <> inline const SCM &from_scm<SCM> (const SCM &s, SCM) { return s; }
from_scm(SCM & s,SCM)275 template <> inline SCM &from_scm<SCM> (SCM &s, SCM) { return s; }
276 
to_scm(const SCM & s)277 template <> inline const SCM &to_scm<SCM> (const SCM &s) { return s; }
to_scm(SCM & s)278 template <> inline SCM &to_scm<SCM> (SCM &s) { return s; }
279 
280 template <> inline bool
is_scm(SCM s)281 is_scm<short> (SCM s)
282 {
283   using limits = std::numeric_limits<short>;
284   return scm_is_signed_integer (s, limits::min (), limits::max ());
285 }
286 template <> inline short
from_scm(const SCM & s)287 from_scm<short> (const SCM &s)
288 {
289   return scm_to_short (s);
290 }
291 template <> inline SCM
to_scm(const short & i)292 to_scm<short> (const short &i)
293 {
294   return scm_from_short (i);
295 }
296 
297 template <> inline bool
is_scm(SCM s)298 is_scm<int> (SCM s)
299 {
300   using limits = std::numeric_limits<int>;
301   return scm_is_signed_integer (s, limits::min (), limits::max ());
302 }
303 template <> inline int
from_scm(const SCM & s)304 from_scm<int> (const SCM &s)
305 {
306   return scm_to_int (s);
307 }
308 template <> inline SCM
to_scm(const int & i)309 to_scm<int> (const int &i)
310 {
311   return scm_from_int (i);
312 }
313 
314 template <> inline bool
is_scm(SCM s)315 is_scm<long> (SCM s)
316 {
317   using limits = std::numeric_limits<long>;
318   return scm_is_signed_integer (s, limits::min (), limits::max ());
319 }
320 template <> inline long
from_scm(const SCM & s)321 from_scm<long> (const SCM &s)
322 {
323   return scm_to_long (s);
324 }
325 template <> inline SCM
to_scm(const long & i)326 to_scm<long> (const long &i)
327 {
328   return scm_from_long (i);
329 }
330 
331 template <> inline bool
is_scm(SCM s)332 is_scm<long long> (SCM s)
333 {
334   using limits = std::numeric_limits<long long>;
335   return scm_is_signed_integer (s, limits::min (), limits::max ());
336 }
337 template <> inline long long
from_scm(const SCM & s)338 from_scm<long long> (const SCM &s)
339 {
340   return scm_to_long_long (s);
341 }
342 template <> inline SCM
to_scm(const long long & i)343 to_scm<long long> (const long long &i)
344 {
345   return scm_from_long_long (i);
346 }
347 
348 template <> inline bool
is_scm(SCM s)349 is_scm<unsigned short> (SCM s)
350 {
351   using limits = std::numeric_limits<unsigned short>;
352   return scm_is_unsigned_integer (s, limits::min (), limits::max ());
353 }
354 template <> inline unsigned short
from_scm(const SCM & s)355 from_scm<unsigned short> (const SCM &s)
356 {
357   return scm_to_ushort (s);
358 }
359 template <> inline SCM
to_scm(const unsigned short & i)360 to_scm<unsigned short> (const unsigned short &i)
361 {
362   return scm_from_ushort (i);
363 }
364 
365 template <> inline bool
is_scm(SCM s)366 is_scm<unsigned> (SCM s)
367 {
368   using limits = std::numeric_limits<unsigned>;
369   return scm_is_unsigned_integer (s, limits::min (), limits::max ());
370 }
371 template <> inline unsigned
from_scm(const SCM & s)372 from_scm<unsigned> (const SCM &s)
373 {
374   return scm_to_uint (s);
375 }
376 template <> inline SCM
to_scm(const unsigned & i)377 to_scm<unsigned> (const unsigned &i)
378 {
379   return scm_from_uint (i);
380 }
381 
382 template <> inline bool
is_scm(SCM s)383 is_scm<unsigned long> (SCM s)
384 {
385   using limits = std::numeric_limits<unsigned long>;
386   return scm_is_unsigned_integer (s, limits::min (), limits::max ());
387 }
388 template <> inline unsigned long
from_scm(const SCM & s)389 from_scm<unsigned long> (const SCM &s)
390 {
391   return scm_to_ulong (s);
392 }
393 template <> inline SCM
to_scm(const unsigned long & i)394 to_scm<unsigned long> (const unsigned long &i)
395 {
396   return scm_from_ulong (i);
397 }
398 
399 template <> inline bool
is_scm(SCM s)400 is_scm<unsigned long long> (SCM s)
401 {
402   using limits = std::numeric_limits<unsigned long long>;
403   return scm_is_unsigned_integer (s, limits::min (), limits::max ());
404 }
405 template <> inline unsigned long long
from_scm(const SCM & s)406 from_scm<unsigned long long> (const SCM &s)
407 {
408   return scm_to_ulong_long (s);
409 }
410 template <> inline SCM
to_scm(const unsigned long long & i)411 to_scm<unsigned long long> (const unsigned long long &i)
412 {
413   return scm_from_ulong_long (i);
414 }
415 
416 template <> inline bool
is_scm(SCM s)417 is_scm<bool> (SCM s)
418 {
419   return scm_is_bool (s);
420 }
421 // from_scm<bool> does not error out for a non-boolean but defaults to
422 // #f as that's what we generally need for an undefined boolean.  This
423 // differs from Scheme which interprets anything but #f as true.
424 template <> inline bool
from_scm(const SCM & s)425 from_scm<bool> (const SCM &s)
426 {
427   return scm_is_eq (s, SCM_BOOL_T);
428 }
429 template <> inline bool
from_scm(const SCM & s,bool fallback)430 from_scm<bool> (const SCM &s, bool fallback)
431 {
432   if (fallback)
433     return scm_is_true (s);
434   else
435     return from_scm<bool> (s);
436 }
437 template <> inline SCM
to_scm(const bool & i)438 to_scm<bool> (const bool &i)
439 {
440   return scm_from_bool (i);
441 }
442 
443 template <> inline bool
is_scm(SCM s)444 is_scm<double> (SCM s)
445 {
446   return scm_is_real (s);
447 }
448 template <> inline double
from_scm(const SCM & s)449 from_scm<double> (const SCM &s)
450 {
451   return scm_to_double (s);
452 }
453 template <> inline SCM
to_scm(const double & i)454 to_scm<double> (const double &i)
455 {
456   return scm_from_double (i);
457 }
458 
459 template <> inline bool
is_scm(SCM s)460 is_scm<Axis> (SCM s)
461 {
462   return scm_is_unsigned_integer (s, X_AXIS, Y_AXIS);
463 }
464 template <> inline Axis
from_scm(const SCM & s)465 from_scm<Axis> (const SCM &s)
466 {
467   return Axis (scm_to_unsigned_integer (s, X_AXIS, Y_AXIS));
468 }
469 template <> inline SCM
to_scm(const Axis & d)470 to_scm<Axis> (const Axis &d)
471 {
472   return to_scm<int> (d);
473 }
474 
475 template <> inline bool
is_scm(SCM s)476 is_scm<Direction> (SCM s)
477 {
478   return scm_is_signed_integer (s, LEFT, RIGHT);
479 }
480 // from_scm<Direction> does not error out for a non-direction but
481 // defaults to CENTER as that's what we generally need for an
482 // undefined direction.  In order not to have to call
483 // is_scm<Direction> more than once, we hard-code the defaulting
484 // variant and implement the one-argument version based on it.
485 template <> inline Direction
from_scm(const SCM & s,Direction fallback)486 from_scm<Direction> (const SCM &s, Direction fallback)
487 {
488   return is_scm<Direction> (s) ? Direction (scm_to_int (s)) : fallback;
489 }
490 template <> inline Direction
from_scm(const SCM & s)491 from_scm<Direction> (const SCM &s)
492 {
493   return from_scm<Direction> (s, CENTER);
494 }
495 template <> inline SCM
to_scm(const Direction & d)496 to_scm<Direction> (const Direction &d)
497 {
498   return to_scm<int> (d);
499 }
500 
501 template <> bool is_scm<Rational> (SCM s);
502 template <> Rational from_scm<Rational> (const SCM &s);
503 template <> SCM to_scm<Rational> (const Rational &i);
504 
505 template <typename T> inline bool
is_scm_pair(SCM s)506 is_scm_pair (SCM s)
507 {
508   return scm_is_pair (s) && is_scm<T> (scm_car (s)) && is_scm<T> (scm_cdr (s));
509 }
510 // No generic from_scm_pair and to_scm_pair for now since the
511 // construction and deconstruction of a pair-based type is not
512 // standardised well enough.  We could demand typename value_type,
513 // accessor functions first and second, and a two-argument
514 // constructor.  Not done for now.
515 
516 template <> inline bool
is_scm(SCM s)517 is_scm<Offset> (SCM s)
518 {
519   return is_scm_pair<Real> (s);
520 }
521 
522 template <> Offset from_scm<Offset> (const SCM &s);
523 template <> SCM to_scm<Offset> (const Offset &i);
524 
525 // partial function specialisation is not allowed, partially
526 // specialize helper class
527 template <typename T>
528 struct scm_conversions <T *>
529 {
is_scmscm_conversions530   static bool is_scm (SCM s) { return unsmob<T> (s); }
from_scmscm_conversions531   static T *from_scm (SCM s) { return unsmob<T> (s); }
from_scmscm_conversions532   static T *from_scm (SCM s, T *fallback)
533   {
534     if (T *res = unsmob<T> (s))
535       return res;
536     return fallback;
537   }
to_scmscm_conversions538   static SCM to_scm (T *p) { return p->self_scm (); }
539 };
540 
541 template <typename T>
542 struct scm_conversions <Drul_array<T>>
543 {
is_scmscm_conversions544   static bool is_scm (SCM s)
545   {
546     return scm_is_pair (s) && ::is_scm<T> (scm_car (s)) && ::is_scm<T> (scm_cdr (s));
547   }
from_scmscm_conversions548   static Drul_array<T> from_scm (SCM s)
549   {
550     return Drul_array<T> (::from_scm<T> (scm_car (s)), ::from_scm<T> (scm_cdr (s)));
551   }
from_scmscm_conversions552   static Drul_array<T> from_scm (SCM s, Drul_array<T> fallback)
553   {
554     return is_scm (s) ? from_scm (s) : fallback;
555   }
to_scmscm_conversions556   static SCM to_scm (const Drul_array<T> &s)
557   {
558     return scm_cons (::to_scm (s[LEFT]), ::to_scm (s[RIGHT]));
559   }
560 };
561 
562 template <typename T>
563 struct scm_conversions <Interval_t<T>>
564 {
is_scmscm_conversions565   static bool is_scm (SCM s)
566   {
567     return scm_is_pair (s) && ::is_scm<T> (scm_car (s)) && ::is_scm<T> (scm_cdr (s));
568   }
from_scmscm_conversions569   static Interval_t<T> from_scm (SCM s)
570   {
571     return Interval_t<T> (::from_scm<T> (scm_car (s)), ::from_scm<T> (scm_cdr (s)));
572   }
from_scmscm_conversions573   static Interval_t<T> from_scm (SCM s, Interval_t<T> fallback)
574   {
575     return is_scm (s) ? from_scm (s) : fallback;
576   }
to_scmscm_conversions577   static SCM to_scm (const Interval_t<T> &s)
578   {
579     return scm_cons (::to_scm (s[LEFT]), ::to_scm (s[RIGHT]));
580   }
581 };
582 
583 // Convert the given SCM list to a container.
584 // The container must support the push_back method.
585 template <class T> T
from_scm_list(SCM s)586 from_scm_list (SCM s)
587 {
588   T ct;
589   for (; scm_is_pair (s); s = scm_cdr (s))
590     {
591       ct.push_back (from_scm<typename T::value_type> (scm_car (s)));
592     }
593   return ct;
594 }
595 // Convert the given container to an SCM list.
596 // The container must support reverse iteration.
597 template <class T> SCM
to_scm_list(const T & ct)598 to_scm_list (const T &ct)
599 {
600   SCM lst = SCM_EOL;
601   for (auto i = ct.crbegin (); i != ct.crend (); ++i)
602     {
603       lst = scm_cons (::to_scm (*i), lst);
604     }
605   return lst;
606 }
607 
608 #endif /* LILY_GUILE_HH */
609