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