1 
2 /******************************************************************************
3 * MODULE     : object.cpp
4 * DESCRIPTION: Implementation of scheme objects
5 * COPYRIGHT  : (C) 1999-2011 Joris van der Hoeven and Massimiliano Gubinelli
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11 
12 #include "object.hpp"
13 #include "glue.hpp"
14 
15 #include "config.h"
16 #include "list.hpp"
17 #include "array.hpp"
18 #include "promise.hpp"
19 #include "widget.hpp"
20 #include "boot.hpp"
21 #include "editor.hpp"
22 #include "modification.hpp"
23 #include "patch.hpp"
24 
25 /******************************************************************************
26 * The object representation class
27 ******************************************************************************/
28 
29 static list<tmscm > destroy_list;
30 extern tmscm object_stack;
31 
tmscm_object_rep(tmscm obj)32 tmscm_object_rep::tmscm_object_rep (tmscm obj) {
33   while (!is_nil (destroy_list)) {
34     tmscm handle= destroy_list->item;
35 
36     tmscm_set_car (handle, tmscm_null ());
37     while (tmscm_is_pair (tmscm_cdr (handle)) && tmscm_is_null (tmscm_cadr (handle)))
38       tmscm_set_cdr (handle, tmscm_cddr( (handle)) );
39     destroy_list= destroy_list->next;
40   }
41   handle = tmscm_cons ( tmscm_cons (obj, tmscm_null ()), tmscm_car (object_stack) );
42   tmscm_set_car (object_stack, handle);
43 }
44 
~tmscm_object_rep()45 tmscm_object_rep::~tmscm_object_rep () {
46     // Be careful: can't call Scheme code from this destructor,
47     // because the destructor can be called during garbage collection.
48   destroy_list= list<tmscm > ( handle, destroy_list);
49 }
50 
51 
52 /******************************************************************************
53 * Routines on objects
54 ******************************************************************************/
55 
56 tm_ostream&
operator <<(tm_ostream & out,object obj)57 operator << (tm_ostream& out, object obj) {
58   out.flush ();
59   if (out == cout) call ("write", obj);
60   else if (out == cerr) call ("write-err", obj);
61   else FAILED ("not yet implemented");
62   call ("force-output");
63   return out;
64 }
65 
66 bool
operator ==(object obj1,object obj2)67 operator == (object obj1, object obj2) {
68   tmscm o1= object_to_tmscm (obj1), o2= object_to_tmscm (obj2);
69   return tmscm_is_equal (o1, o2);
70 }
71 
72 bool
operator !=(object obj1,object obj2)73 operator != (object obj1, object obj2) {
74   return !(obj1 == obj2);
75 }
76 
77 int
hash(object obj)78 hash (object obj) {
79   return as_int (call ("hash", obj, object (1234567)));
80 }
81 
82 
83 /******************************************************************************
84 * Utilities
85 ******************************************************************************/
86 
null_object()87 object null_object () {
88   return tmscm_to_object (tmscm_null ()); }
cons(object obj1,object obj2)89 object cons (object obj1, object obj2) {
90   return tmscm_to_object (tmscm_cons (object_to_tmscm (obj1), object_to_tmscm (obj2))); }
list_object(object obj1)91 object list_object (object obj1) {
92   return cons (obj1, null_object ()); }
list_object(object obj1,object obj2)93 object list_object (object obj1, object obj2) {
94   return cons (obj1, cons (obj2, null_object ())); }
list_object(object obj1,object obj2,object obj3)95 object list_object (object obj1, object obj2, object obj3) {
96   return cons (obj1, cons (obj2, cons (obj3, null_object ()))); }
symbol_object(string s)97 object symbol_object (string s) {
98   return tmscm_to_object ( symbol_to_tmscm (s) ); }
car(object obj)99 object car (object obj) {
100   return tmscm_to_object (tmscm_car (object_to_tmscm (obj))); }
cdr(object obj)101 object cdr (object obj) {
102   return tmscm_to_object (tmscm_cdr (object_to_tmscm (obj))); }
caar(object obj)103 object caar (object obj) {
104   return tmscm_to_object (tmscm_caar (object_to_tmscm (obj))); }
cdar(object obj)105 object cdar (object obj) {
106   return tmscm_to_object (tmscm_cdar (object_to_tmscm (obj))); }
cadr(object obj)107 object cadr (object obj) {
108   return tmscm_to_object (tmscm_cadr (object_to_tmscm (obj))); }
cddr(object obj)109 object cddr (object obj) {
110   return tmscm_to_object (tmscm_cddr (object_to_tmscm (obj))); }
caddr(object obj)111 object caddr (object obj) {
112   return tmscm_to_object (tmscm_caddr (object_to_tmscm (obj))); }
cadddr(object obj)113 object cadddr (object obj) {
114   return tmscm_to_object (tmscm_cadddr (object_to_tmscm (obj))); }
115 
116 
117 /******************************************************************************
118 * Predicates
119 ******************************************************************************/
120 
is_null(object obj)121 bool is_null (object obj) { return tmscm_is_null (object_to_tmscm (obj)); }
is_list(object obj)122 bool is_list (object obj) { return tmscm_is_list (object_to_tmscm (obj)); }
is_bool(object obj)123 bool is_bool (object obj) { return tmscm_is_bool (object_to_tmscm (obj)); }
is_int(object obj)124 bool is_int (object obj) { return tmscm_is_int (object_to_tmscm (obj)); }
is_double(object obj)125 bool is_double (object obj) { return tmscm_is_double (object_to_tmscm (obj)); }
is_string(object obj)126 bool is_string (object obj) { return tmscm_is_string (object_to_tmscm (obj)); }
is_symbol(object obj)127 bool is_symbol (object obj) { return tmscm_is_symbol (object_to_tmscm (obj)); }
is_tree(object obj)128 bool is_tree (object obj) { return tmscm_is_tree (object_to_tmscm (obj)); }
is_path(object obj)129 bool is_path (object obj) { return tmscm_is_path (object_to_tmscm (obj)); }
is_url(object obj)130 bool is_url (object obj) { return tmscm_is_url (object_to_tmscm (obj)); }
is_widget(object obj)131 bool is_widget (object obj) { return tmscm_is_widget (object_to_tmscm (obj)); }
is_patch(object obj)132 bool is_patch (object obj) { return tmscm_is_patch (object_to_tmscm (obj)); }
is_modification(object obj)133 bool is_modification (object obj) {
134   return tmscm_is_modification (object_to_tmscm (obj)); }
135 
136 /******************************************************************************
137 * Basic conversions
138 ******************************************************************************/
139 
object(tmscm_object_rep * o)140 object::object (tmscm_object_rep* o): rep (static_cast<object_rep*>(o)) {}
object()141 object::object (): rep (tm_new<tmscm_object_rep> (tmscm_null ())) {}
object(bool b)142 object::object (bool b): rep (tm_new<tmscm_object_rep> (bool_to_tmscm (b))) {}
object(int i)143 object::object (int i): rep (tm_new<tmscm_object_rep> (int_to_tmscm (i))) {}
object(double x)144 object::object (double x):
145   rep (tm_new<tmscm_object_rep> (double_to_tmscm (x))) {}
object(const char * s)146 object::object (const char* s):
147   rep (tm_new<tmscm_object_rep> (string_to_tmscm (string (s)))) {}
object(string s)148 object::object (string s):
149   rep (tm_new<tmscm_object_rep> (string_to_tmscm (s))) {}
object(tree t)150 object::object (tree t):
151   rep (tm_new<tmscm_object_rep> (tree_to_tmscm (t))) {}
object(list<string> l)152 object::object (list<string> l):
153   rep (tm_new<tmscm_object_rep> (list_string_to_tmscm (l))) {}
object(list<tree> l)154 object::object (list<tree> l):
155   rep (tm_new<tmscm_object_rep> (list_tree_to_tmscm (l))) {}
object(path p)156 object::object (path p): rep (tm_new<tmscm_object_rep> (path_to_tmscm (p))) {}
object(url u)157 object::object (url u): rep (tm_new<tmscm_object_rep> (url_to_tmscm (u))) {}
object(patch m)158 object::object (patch m):
159   rep (tm_new<tmscm_object_rep> (patch_to_tmscm (m))) {}
object(modification m)160 object::object (modification m):
161   rep (tm_new<tmscm_object_rep> (modification_to_tmscm (m))) {}
162 
163 bool
as_bool(object obj)164 as_bool (object obj) {
165   tmscm b= object_to_tmscm (obj);
166   if (!tmscm_is_bool (b)) return false;
167   return tmscm_to_bool (b);
168 }
169 
170 int
as_int(object obj)171 as_int (object obj) {
172   tmscm i= object_to_tmscm (obj);
173   if (!tmscm_is_int (i)) return 0;
174   return tmscm_to_int (i);
175 }
176 
177 double
as_double(object obj)178 as_double (object obj) {
179   tmscm x= object_to_tmscm (obj);
180   if (!tmscm_is_double (x)) return 0.0;
181   return tmscm_to_double (x);
182 }
183 
184 string
as_string(object obj)185 as_string (object obj) {
186   tmscm s= object_to_tmscm (obj);
187   if (!tmscm_is_string (s)) return "";
188   return tmscm_to_string (s);
189 }
190 
191 string
as_symbol(object obj)192 as_symbol (object obj) {
193   tmscm s= object_to_tmscm (obj);
194   if (!tmscm_is_symbol (s)) return "";
195   return tmscm_to_symbol (s);
196 }
197 
198 tree
as_tree(object obj)199 as_tree (object obj) {
200   tmscm t= object_to_tmscm (obj);
201   if (!tmscm_is_tree (t)) return tree ();
202   return tmscm_to_tree (t);
203 }
204 
205 scheme_tree
as_tmscm_tree(object obj)206 as_tmscm_tree (object obj) {
207   tmscm t= object_to_tmscm (obj);
208   return tmscm_to_scheme_tree (t);
209 }
210 
211 list<string>
as_list_string(object obj)212 as_list_string (object obj) {
213   tmscm l= object_to_tmscm (obj);
214   if (!tmscm_is_list_string (l)) return list<string> ();
215   return tmscm_to_list_string (l);
216 }
217 
218 list<tree>
as_list_tree(object obj)219 as_list_tree (object obj) {
220   tmscm l= object_to_tmscm (obj);
221   if (!tmscm_is_list_tree (l)) return list<tree> ();
222   return tmscm_to_list_tree (l);
223 }
224 
225 path
as_path(object obj)226 as_path (object obj) {
227   tmscm t= object_to_tmscm (obj);
228   if (!tmscm_is_path (t)) return path ();
229   return tmscm_to_path (t);
230 }
231 
232 array<object>
as_array_object(object obj)233 as_array_object (object obj) {
234   ASSERT (is_list (obj), "list expected");
235   array<object> ret;
236   while (!is_null (obj)) {
237     ret << car (obj);
238     obj= cdr (obj);
239   }
240   return ret;
241 }
242 
243 url
as_url(object obj)244 as_url (object obj) {
245   tmscm t= object_to_tmscm (obj);
246   if (!tmscm_is_url (t)) return url ("");
247   return tmscm_to_url (t);
248 }
249 
250 modification
as_modification(object obj)251 as_modification (object obj) {
252   tmscm m= object_to_tmscm (obj);
253   if (!tmscm_is_modification (m))
254     return mod_assign (path (), "");
255   return tmscm_to_modification (m);
256 }
257 
258 patch
as_patch(object obj)259 as_patch (object obj) {
260   tmscm p= object_to_tmscm (obj);
261   if (!tmscm_is_patch (p))
262     return patch (array<patch> ());
263   return tmscm_to_patch (p);
264 }
265 
266 widget
as_widget(object obj)267 as_widget (object obj) {
268   tmscm w= object_to_tmscm (obj);
269   if (!tmscm_is_widget (w)) return widget ();
270   return tmscm_to_widget (w);
271 }
272 
273 object
tree_to_stree(scheme_tree t)274 tree_to_stree (scheme_tree t) {
275   return call ("tree->stree", t);
276 }
277 
278 tree
stree_to_tree(object obj)279 stree_to_tree (object obj) {
280   return as_tree (call ("stree->tree", obj));
281 }
282 
283 tree
content_to_tree(object obj)284 content_to_tree (object obj) {
285   return tmscm_to_content (object_to_tmscm (obj));
286     // return as_tree (call ("content->tree", obj));
287 }
288 
289 object
string_to_object(string s)290 string_to_object (string s) {
291   return call ("string->object", s);
292 }
293 
294 string
object_to_string(object obj)295 object_to_string (object obj) {
296   return as_string (call ("object->string", obj));
297 }
298 
299 object
scheme_cmd(const char * s)300 scheme_cmd (const char* s) {
301   return eval ("(lambda () " * string (s) * ")");
302 }
303 
304 object
scheme_cmd(string s)305 scheme_cmd (string s) {
306   return eval ("(lambda () " * s * ")");
307 }
308 
309 object
scheme_cmd(object cmd)310 scheme_cmd (object cmd) {
311   cmd= cons (cmd, null_object ());
312   cmd= cons (null_object (), cmd);
313   cmd= cons (eval ("'lambda"), cmd);
314   return eval (cmd);
315 }
316 
317 /******************************************************************************
318 * Conversions to functional objects
319 ******************************************************************************/
320 
321 static inline array<tmscm >
array_lookup(array<object> a)322 array_lookup (array<object> a) {
323   const int n=N(a);
324   array<tmscm > tmscm (n);
325   int i;
326   for (i=0; i<n; i++) tmscm [i]= object_to_tmscm (a[i]);
327   return tmscm ;
328 }
329 
330 class object_command_rep: public command_rep {
331   object obj;
332 public:
object_command_rep(object obj2)333   object_command_rep (object obj2): obj (obj2) {}
apply()334   void apply () { (void) call_scheme (object_to_tmscm (obj)); }
apply(object args)335   void apply (object args) {
336     (void) call_scheme (object_to_tmscm (obj),
337                         array_lookup (as_array_object (args))); }
print(tm_ostream & out)338   tm_ostream& print (tm_ostream& out) { return out << obj; }
339 };
340 
341 command
as_command(object obj)342 as_command (object obj) {
343   return tm_new<object_command_rep> (obj);
344 }
345 
346 class object_promise_widget_rep: public promise_rep<widget> {
347   object obj;
348 public:
object_promise_widget_rep(object obj2)349   object_promise_widget_rep (object obj2): obj (obj2) {}
print(tm_ostream & out)350   tm_ostream& print (tm_ostream& out) { return out << obj; }
eval()351   widget eval () {
352     tmscm result= call_scheme (object_to_tmscm (obj));
353     if (tmscm_is_widget (result)) return tmscm_to_widget (result);
354     else {
355       FAILED ("widget expected");
356       return glue_widget ();
357     }
358   }
359 };
360 
361 promise<widget>
as_promise_widget(object obj)362 as_promise_widget (object obj) {
363   return tm_new<object_promise_widget_rep> (obj);
364 }
365 
366 /******************************************************************************
367 * Evaluation and function calls
368 ******************************************************************************/
369 
eval(const char * expr)370 object eval (const char* expr) {
371   return tmscm_to_object (eval_scheme (expr)); }
eval(string expr)372 object eval (string expr) {
373   return tmscm_to_object (eval_scheme (expr)); }
eval(object expr)374 object eval (object expr) {
375   return call ("eval", expr); }
eval_secure(string expr)376 object eval_secure (string expr) {
377   return eval ("(wrap-eval-secure " * expr * ")"); }
eval_file(string name)378 object eval_file (string name) {
379   return tmscm_to_object (eval_scheme_file (name)); }
exec_file(url u)380 bool exec_file (url u) {
381   object ret= eval_file (materialize (u));
382   return ret != object ("#<unspecified>"); }
383 
call(const char * fun)384 object call (const char* fun) {
385   return tmscm_to_object (call_scheme (eval_scheme(fun))); }
call(const char * fun,object a1)386 object call (const char* fun, object a1) {
387   return tmscm_to_object (call_scheme (eval_scheme(fun), object_to_tmscm (a1))); }
call(const char * fun,object a1,object a2)388 object call (const char* fun, object a1, object a2) {
389   return tmscm_to_object (call_scheme (eval_scheme(fun), object_to_tmscm (a1), object_to_tmscm (a2))); }
call(const char * fun,object a1,object a2,object a3)390 object call (const char* fun, object a1, object a2, object a3) {
391   return tmscm_to_object (call_scheme (eval_scheme(fun), object_to_tmscm (a1),
392                                        object_to_tmscm (a2), object_to_tmscm (a3))); }
call(const char * fun,object a1,object a2,object a3,object a4)393 object call (const char* fun, object a1, object a2, object a3, object a4) {
394   return tmscm_to_object (call_scheme (eval_scheme(fun), object_to_tmscm (a1),
395                                        object_to_tmscm (a2), object_to_tmscm (a3), object_to_tmscm (a4))); }
call(const char * fun,array<object> a)396 object call (const char* fun, array<object> a) {
397   return tmscm_to_object (call_scheme (eval_scheme(fun), array_lookup(a))); }
398 
call(string fun)399 object call (string fun) {
400   return tmscm_to_object (call_scheme (eval_scheme(fun))); }
call(string fun,object a1)401 object call (string fun, object a1) {
402   return tmscm_to_object (call_scheme (eval_scheme(fun), object_to_tmscm (a1))); }
call(string fun,object a1,object a2)403 object call (string fun, object a1, object a2) {
404   return tmscm_to_object (call_scheme (eval_scheme(fun), object_to_tmscm (a1), object_to_tmscm (a2))); }
call(string fun,object a1,object a2,object a3)405 object call (string fun, object a1, object a2, object a3) {
406   return tmscm_to_object (call_scheme (eval_scheme(fun), object_to_tmscm (a1),
407                                        object_to_tmscm (a2), object_to_tmscm (a3))); }
call(string fun,object a1,object a2,object a3,object a4)408 object call (string fun, object a1, object a2, object a3, object a4) {
409   return tmscm_to_object (call_scheme (eval_scheme(fun), object_to_tmscm (a1),
410                                        object_to_tmscm (a2), object_to_tmscm (a3), object_to_tmscm (a4))); }
call(string fun,array<object> a)411 object call (string fun, array<object> a) {
412   return tmscm_to_object (call_scheme (eval_scheme(fun), array_lookup(a))); }
413 
call(object fun)414 object call (object fun) {
415   return tmscm_to_object (call_scheme (object_to_tmscm (fun))); }
call(object fun,object a1)416 object call (object fun, object a1) {
417   return tmscm_to_object (call_scheme (object_to_tmscm (fun), object_to_tmscm (a1))); }
call(object fun,object a1,object a2)418 object call (object fun, object a1, object a2) {
419   return tmscm_to_object (call_scheme (object_to_tmscm (fun), object_to_tmscm (a1), object_to_tmscm (a2))); }
call(object fun,object a1,object a2,object a3)420 object call (object fun, object a1, object a2, object a3) {
421   return tmscm_to_object (call_scheme (object_to_tmscm (fun), object_to_tmscm (a1),
422                                        object_to_tmscm (a2), object_to_tmscm (a3))); }
call(object fun,object a1,object a2,object a3,object a4)423 object call (object fun, object a1, object a2, object a3, object a4) {
424   return tmscm_to_object (call_scheme (object_to_tmscm (fun), object_to_tmscm (a1),
425                                        object_to_tmscm (a2), object_to_tmscm (a3), object_to_tmscm (a4))); }
call(object fun,array<object> a)426 object call (object fun, array<object> a) {
427   return tmscm_to_object (call_scheme (object_to_tmscm (fun), array_lookup(a))); }
428 
429 /******************************************************************************
430 * User preferences
431 ******************************************************************************/
432 
433 static bool preferences_ok= false;
434 
435 void
notify_preferences_booted()436 notify_preferences_booted () {
437   preferences_ok= true;
438 }
439 
440 void
set_preference(string var,string val)441 set_preference (string var, string val) {
442   if (!preferences_ok) set_user_preference (var, val);
443   else (void) call ("set-preference", var, val);
444 }
445 
446 void
notify_preference(string var)447 notify_preference (string var) {
448   if (preferences_ok) (void) call ("notify-preference", var);
449 }
450 
451 string
get_preference(string var,string def)452 get_preference (string var, string def) {
453   if (!preferences_ok)
454     return get_user_preference (var, def);
455   else {
456     string pref= as_string (call ("get-preference", var));
457     if (pref == "default") return def; else return pref;
458   }
459 }
460 
461 /******************************************************************************
462 * Delayed evaluation
463 ******************************************************************************/
464 
465 #ifndef QTTEXMACS
466 static array<object> delayed_queue;
467 static array<time_t> start_queue;
468 
469 void
exec_delayed(object cmd)470 exec_delayed (object cmd) {
471   delayed_queue << cmd;
472   start_queue << (((time_t) texmacs_time ()) - 1000000000);
473 }
474 
475 void
exec_delayed_pause(object cmd)476 exec_delayed_pause (object cmd) {
477   delayed_queue << cmd;
478   start_queue << ((time_t) texmacs_time ());
479 }
480 
481 void
exec_pending_commands()482 exec_pending_commands () {
483   array<object> a= delayed_queue;
484   array<time_t> b= start_queue;
485   delayed_queue= array<object> (0);
486   start_queue  = array<time_t> (0);
487   int i, n= N(a);
488   for (i=0; i<n; i++) {
489     time_t now= (time_t) texmacs_time ();
490     if ((now - b[i]) >= 0) {
491       object obj= call (a[i]);
492       if (is_int (obj) && (now - b[i] < 1000000000)) {
493           //cout << "pause= " << obj << "\n";
494         delayed_queue << a[i];
495         start_queue << (now + as_int (obj));
496       }
497     }
498     else {
499       delayed_queue << a[i];
500       start_queue << b[i];
501     }
502   }
503 }
504 
505 void
clear_pending_commands()506 clear_pending_commands () {
507   delayed_queue= array<object> (0);
508   start_queue  = array<time_t> (0);
509 }
510 #endif // QTTEXMACS
511 
512 /******************************************************************************
513 * Protected evaluation
514 ******************************************************************************/
515 
516 void
protected_call(object cmd)517 protected_call (object cmd) {
518 #ifdef USE_EXCEPTIONS
519   try {
520 #endif
521     get_current_editor()->before_menu_action ();
522     call (cmd);
523     get_current_editor()->after_menu_action ();
524 #ifdef USE_EXCEPTIONS
525   }
526   catch (string s) {
527     get_current_editor()->cancel_menu_action ();
528   }
529   handle_exceptions ();
530 #endif
531 }
532