1 /*
2 Copyright (c) 2009 Masatake YAMATO
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE. */
21
22 #if defined (HAVE_CONFIG_H)
23 # include <config.h>
24 #endif
25
26 #include "es.h"
27
28
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <limits.h>
33
34 #include <regex.h>
35
36 static int es_debug = 0;
37
38 typedef struct _EsInteger EsInteger;
39 typedef struct _EsReal EsReal;
40 typedef struct _EsBoolean EsBoolean;
41 typedef struct _EsString EsString;
42 typedef struct _EsSingleton EsSingleton;
43 typedef struct _EsSymbol EsSymbol;
44 typedef struct _EsError EsError;
45 typedef struct _EsCons EsCons;
46 typedef struct _EsRegex EsRegex;
47 typedef struct _EsPointer EsPointer;
48
49 struct _EsObject
50 {
51 EsType type;
52 union
53 {
54 int ref_count;
55 EsSingleton* next;
56 };
57 };
58
59 struct _EsInteger
60 {
61 EsObject base;
62 int value;
63 };
64
65 struct _EsReal
66 {
67 EsObject base;
68 double value;
69 };
70
71 struct _EsBoolean
72 {
73 EsObject base;
74 int value;
75 };
76
77 struct _EsString
78 {
79 EsObject base;
80 char* value;
81 };
82
83 struct _EsSingleton
84 {
85 EsObject base;
86 char* quark;
87 };
88
89 struct _EsSymbol
90 {
91 EsSingleton base;
92 void *data;
93 };
94
95 struct _EsError
96 {
97 EsSingleton base;
98 EsObject *object;
99 };
100
101 struct _EsCons
102 {
103 EsObject base;
104 EsObject* car;
105 EsObject* cdr;
106 };
107
108 struct _EsRegex
109 {
110 EsObject base;
111 regex_t *code;
112 char* literal;
113 int case_insensitive;
114 };
115
116 struct _EsPointer
117 {
118 EsObject base;
119 void *ptr;
120 char fat [];
121 };
122
123 enum EsObjectFlag
124 {
125 ES_OBJECT_FLAG_ATOM = 1 << 0,
126 };
127
128 typedef struct _EsObjectClass EsObjectClass;
129 struct _EsObjectClass
130 {
131 size_t size;
132 void (* free) (EsObject* object);
133 int (* equal) (const EsObject* self, const EsObject* other);
134 void (* print) (const EsObject* object, MIO* fp);
135 unsigned flags;
136 EsSingleton **obarray;
137 const char* name;
138 };
139
140
141 static void es_nil_free(EsObject* object);
142 static int es_nil_equal(const EsObject* self, const EsObject* other);
143 static void es_nil_print(const EsObject* object, MIO* fp);
144
145 static void es_integer_free(EsObject* object);
146 static int es_integer_equal(const EsObject* self, const EsObject* other);
147 static void es_integer_print(const EsObject* object, MIO* fp);
148
149 static void es_real_free(EsObject* object);
150 static int es_real_equal(const EsObject* self, const EsObject* other);
151 static void es_real_print(const EsObject* object, MIO* fp);
152
153 static void es_boolean_free(EsObject* object);
154 static int es_boolean_equal(const EsObject* self, const EsObject* other);
155 static void es_boolean_print(const EsObject* object, MIO* fp);
156
157 static void es_string_free(EsObject* object);
158 static int es_string_equal(const EsObject* self, const EsObject* other);
159 static void es_string_print(const EsObject* self, MIO* fp);
160
161 static void es_symbol_free(EsObject* object);
162 static int es_symbol_equal(const EsObject* self, const EsObject* other);
163 static void es_symbol_print(const EsObject* object, MIO* fp);
164
165 static void es_cons_free(EsObject* object);
166 static int es_cons_equal(const EsObject* self, const EsObject* other);
167 static void es_cons_print(const EsObject* object, MIO* fp);
168
169 static void es_regex_free(EsObject* object);
170 static int es_regex_equal(const EsObject* self, const EsObject* other);
171 static void es_regex_print(const EsObject* object, MIO* fp);
172
173 static void es_error_free(EsObject* object);
174 static int es_error_equal(const EsObject* self, const EsObject* other);
175 static void es_error_print(const EsObject* object, MIO* fp);
176
177 static void es_pointer_free(EsObject* object);
178 static int es_pointer_equal(const EsObject* self, const EsObject* other);
179 static void es_pointer_print(const EsObject* object, MIO* fp);
180
181 static EsSingleton* es_obarray_intern(EsType type, const char* name);
182 static const char* es_singleton_get (EsSingleton *singleton);
183 static unsigned int hash(const char* keyarg);
184 #define OBARRAY_SIZE 83
185 static EsSingleton *symbol_obarray[OBARRAY_SIZE];
186 static EsSingleton *error_obarray [OBARRAY_SIZE];
187
188 static EsObjectClass es_nil_class = {
189 .size = 0,
190 .free = es_nil_free,
191 .equal = es_nil_equal,
192 .print = es_nil_print,
193 .flags = ES_OBJECT_FLAG_ATOM,
194 .obarray = NULL,
195 .name = "nil",
196 };
197
198 static EsObjectClass es_integer_class = {
199 .size = sizeof(EsInteger),
200 .free = es_integer_free,
201 .equal = es_integer_equal,
202 .print = es_integer_print,
203 .flags = ES_OBJECT_FLAG_ATOM,
204 .obarray = NULL,
205 .name = "integer",
206 };
207
208 static EsObjectClass es_real_class = {
209 .size = sizeof(EsReal),
210 .free = es_real_free,
211 .equal = es_real_equal,
212 .print = es_real_print,
213 .flags = ES_OBJECT_FLAG_ATOM,
214 .obarray = NULL,
215 .name = "real",
216 };
217
218 static EsObjectClass es_boolean_class = {
219 .size = sizeof(EsBoolean),
220 .free = es_boolean_free,
221 .equal = es_boolean_equal,
222 .print = es_boolean_print,
223 .flags = ES_OBJECT_FLAG_ATOM,
224 .obarray = (void*)1,
225 .name = "boolean",
226 };
227
228 static EsObjectClass es_symbol_class = {
229 .size = sizeof(EsSymbol),
230 .free = es_symbol_free,
231 .equal = es_symbol_equal,
232 .print = es_symbol_print,
233 .flags = ES_OBJECT_FLAG_ATOM,
234 .obarray = symbol_obarray,
235 .name = "symbol",
236 };
237
238 static EsObjectClass es_string_class = {
239 .size = sizeof(EsString),
240 .free = es_string_free,
241 .equal = es_string_equal,
242 .print = es_string_print,
243 .flags = ES_OBJECT_FLAG_ATOM,
244 .obarray = NULL,
245 .name = "string",
246 };
247
248 static EsObjectClass es_cons_class = {
249 .size = sizeof(EsCons),
250 .free = es_cons_free,
251 .equal = es_cons_equal,
252 .print = es_cons_print,
253 .flags = 0,
254 .obarray = NULL,
255 .name = "cons",
256 };
257
258 static EsObjectClass es_regex_class = {
259 .size = sizeof(EsRegex),
260 .free = es_regex_free,
261 .equal = es_regex_equal,
262 .print = es_regex_print,
263 .flags = ES_OBJECT_FLAG_ATOM,
264 .obarray = NULL,
265 .name = "regex",
266 };
267
268 static EsObjectClass es_error_class = {
269 .size = sizeof(EsError),
270 .free = es_error_free,
271 .equal = es_error_equal,
272 .print = es_error_print,
273 .flags = ES_OBJECT_FLAG_ATOM,
274 .obarray = error_obarray,
275 .name = "error",
276 };
277
278
279 #define ES_TYPE_CLASS_MAX 32
280 static int classes_count = ES_TYPE_FOREIGNER_START;
281 static EsObjectClass *classes[ES_TYPE_CLASS_MAX] = {
282 [ES_TYPE_NIL] = &es_nil_class,
283 [ES_TYPE_INTEGER] = &es_integer_class,
284 [ES_TYPE_REAL] = &es_real_class,
285 [ES_TYPE_BOOLEAN] = &es_boolean_class,
286 [ES_TYPE_SYMBOL] = &es_symbol_class,
287 [ES_TYPE_STRING] = &es_string_class,
288 [ES_TYPE_CONS] = &es_cons_class,
289 [ES_TYPE_REGEX] = &es_regex_class,
290 [ES_TYPE_ERROR] = &es_error_class,
291 };
292
293
294
mio_stdout(void)295 static MIO *mio_stdout (void)
296 {
297 static MIO *out;
298
299 if (out == NULL)
300 out = mio_new_fp (stdout, NULL);
301
302 return out;
303 }
304
mio_stdin(void)305 static MIO *mio_stdin (void)
306 {
307 static MIO *out;
308
309 if (out == NULL)
310 out = mio_new_fp (stdin, NULL);
311
312 return out;
313 }
314
mio_stderr(void)315 static MIO *mio_stderr (void)
316 {
317 static MIO *out;
318
319 if (out == NULL)
320 out = mio_new_fp (stderr, NULL);
321
322 return out;
323 }
324
325
326
327 static EsObjectClass*
class_of(const EsObject * object)328 class_of(const EsObject* object)
329 {
330 return (classes[es_object_get_type(object)]);
331 }
332
333 static EsObject*
es_object_new(EsType type)334 es_object_new(EsType type)
335 {
336 EsObject* r;
337
338
339 r = calloc(1, (classes[type])->size);
340 if (r == NULL)
341 return ES_ERROR_MEMORY;
342 r->type = type;
343 r->ref_count = 1;
344
345 if (es_debug)
346 mio_printf(mio_stderr(), ";; new{%s}: 0x%p\n",
347 (classes[type])->name,
348 r);
349
350 return r;
351 }
352
353 static void
es_object_free(EsObject * object)354 es_object_free(EsObject* object)
355 {
356 memset(object, 0, class_of(object)->size);
357 free(object);
358 }
359
360 static int
es_object_type_p(const EsObject * object,EsType type)361 es_object_type_p(const EsObject* object, EsType type)
362 {
363 return es_object_get_type(object) == type;
364 }
365
es_type_get_name(int t)366 const char* es_type_get_name (int t)
367 {
368 return (classes[t]->name);
369 }
370
371 EsType
es_object_get_type(const EsObject * object)372 es_object_get_type (const EsObject* object)
373 {
374 return object? object->type: ES_TYPE_NIL;
375 }
376
377 EsObject*
es_object_ref(EsObject * object)378 es_object_ref (EsObject* object)
379 {
380 if (object)
381 {
382 if (class_of(object)->obarray)
383 return object;
384
385 if (es_debug)
386 mio_printf(mio_stderr(), ";; ref{%s}: [%d]0x%p\n",
387 class_of(object)->name,
388 object->ref_count,
389 object);
390 object->ref_count++;
391 }
392 return object;
393 }
394
395 void
es_object_unref(EsObject * object)396 es_object_unref (EsObject* object)
397 {
398
399 if (object)
400 {
401 if (class_of(object)->obarray)
402 return;
403
404 if (object->ref_count == 0)
405 if ((1 || es_debug))
406 {
407 mio_printf(mio_stderr(), "*** ref_count < 0: 0x%p ***\n", object);
408 mio_printf(mio_stderr(), "*** BOOSTING while(1). ***\n");
409 while (1);
410 }
411
412 object->ref_count--;
413 if (es_debug)
414 mio_printf(mio_stderr(), ";; unref{%s}: [%d]0x%p\n",
415 class_of(object)->name,
416 object->ref_count, object);
417 if (object->ref_count == 0)
418 {
419 if (es_debug)
420 mio_printf(mio_stderr(), ";; free{%s}: 0x%p\n",
421 class_of(object)->name,
422 object);
423 class_of(object)->free(object);
424 }
425 }
426 }
427
428 void
es_object_unref_batch(EsObject * array[],unsigned int count)429 es_object_unref_batch (EsObject* array[],
430 unsigned int count)
431 {
432 unsigned int i;
433
434 for (i = 0; i < count; i++)
435 {
436 es_object_unref(array[i]);
437 array[i] = es_nil;
438 }
439 }
440
441 int
es_object_equal(const EsObject * self,const EsObject * other)442 es_object_equal (const EsObject* self,
443 const EsObject* other)
444 {
445 if (self == other)
446 return 1;
447
448 return class_of(self)->equal(self, other);
449 }
450
451
452 int
es_atom(const EsObject * object)453 es_atom (const EsObject* object)
454 {
455 return class_of(object)->flags & ES_OBJECT_FLAG_ATOM;
456 }
457
458
459 /*
460 * Nil
461 */
462 int
es_null(const EsObject * object)463 es_null(const EsObject* object)
464 {
465 return (object == es_nil)? 1: 0;
466 }
467
468 static void
es_nil_free(EsObject * object)469 es_nil_free(EsObject* object)
470 {
471 /* DO NOTHING */
472 }
473
474 static int
es_nil_equal(const EsObject * self,const EsObject * other)475 es_nil_equal(const EsObject* self, const EsObject* other)
476 {
477 return es_null(other);
478 }
479
480 static void
es_nil_print(const EsObject * object,MIO * fp)481 es_nil_print(const EsObject* object, MIO* fp)
482 {
483 mio_puts(fp, "()");
484 }
485
486 /*
487 * Integer
488 */
489 EsObject*
es_integer_new(int value)490 es_integer_new (int value)
491 {
492 EsObject* r;
493
494 r = es_object_new(ES_TYPE_INTEGER);
495 ((EsInteger*)r)->value = value;
496 return r;
497 }
498
499 int
es_integer_p(const EsObject * object)500 es_integer_p (const EsObject* object)
501 {
502 return es_object_type_p(object, ES_TYPE_INTEGER);
503 }
504
505 int
es_integer_get(const EsObject * object)506 es_integer_get (const EsObject* object)
507 {
508 if (es_integer_p(object))
509 return ((EsInteger *)object)->value;
510 else
511 {
512 mio_printf(mio_stderr(), ";; es_integer_get, Wrong type argument: ");
513 es_print(object, mio_stderr());
514 mio_putc(mio_stderr(), '\n');
515 return -1;
516 }
517 }
518
519 static void
es_integer_free(EsObject * object)520 es_integer_free(EsObject* object)
521 {
522 es_object_free(object);
523 }
524
525 static int
es_integer_equal(const EsObject * self,const EsObject * other)526 es_integer_equal(const EsObject* self, const EsObject* other)
527 {
528 return ((es_integer_p(other))
529 && (es_integer_get(self) == es_integer_get(other)))? 1: 0;
530 }
531
532 static void
es_integer_print(const EsObject * object,MIO * fp)533 es_integer_print(const EsObject* object, MIO* fp)
534 {
535 mio_printf(fp, "%d", es_integer_get(object));
536 }
537
538
539 /*
540 * Real
541 */
542 EsObject*
es_real_new(double value)543 es_real_new (double value)
544 {
545 EsObject* r;
546
547 r = es_object_new(ES_TYPE_REAL);
548 ((EsReal*)r)->value = value;
549 return r;
550 }
551
552 int
es_real_p(const EsObject * object)553 es_real_p (const EsObject* object)
554 {
555 return es_object_type_p(object, ES_TYPE_REAL);
556 }
557
558 double
es_real_get(const EsObject * object)559 es_real_get (const EsObject* object)
560 {
561 if (es_real_p(object))
562 return ((EsReal *)object)->value;
563 else
564 {
565 mio_printf(mio_stderr(), ";; es_real_get, Wrong type argument: ");
566 es_print(object, mio_stderr());
567 mio_putc(mio_stderr(), '\n');
568 return -1;
569 }
570 }
571
572 static void
es_real_free(EsObject * object)573 es_real_free(EsObject* object)
574 {
575 es_object_free(object);
576 }
577
578 static int
es_real_equal(const EsObject * self,const EsObject * other)579 es_real_equal(const EsObject* self, const EsObject* other)
580 {
581 return ((es_real_p(other))
582 /* TODO: Too restricted? */
583 && (es_real_get(self) == es_real_get(other)))? 1: 0;
584 }
585
586 static void
es_real_print(const EsObject * object,MIO * fp)587 es_real_print(const EsObject* object, MIO* fp)
588 {
589 mio_printf(fp, "%f", es_real_get(object));
590 }
591
592 /*
593 * Use Integer as Real
594 */
595 int
es_number_p(const EsObject * object)596 es_number_p (const EsObject* object)
597 {
598 return (es_integer_p(object) || es_real_p(object))? 1: 0;
599 }
600
601 double
es_number_get(const EsObject * object)602 es_number_get (const EsObject* object)
603 {
604 double r;
605
606 switch(es_object_get_type(object))
607 {
608 case ES_TYPE_INTEGER:
609 r = (double)es_integer_get(object);
610 break;
611 case ES_TYPE_REAL:
612 r = es_real_get(object);
613 break;
614 default:
615 mio_printf(mio_stderr(), ";; es_number_get, Wrong type argument: ");
616 es_print(object, mio_stderr());
617 mio_putc(mio_stderr(), '\n');
618 r = -1.0;
619 break;
620 }
621 return r;
622 }
623
624
625 /*
626 * Boolean
627 */
628 EsObject*
es_boolean_new(int value)629 es_boolean_new (int value)
630 {
631 static EsObject* T;
632 static EsObject* F;
633
634 if (!T)
635 {
636 T = es_object_new(ES_TYPE_BOOLEAN);
637 ((EsBoolean*)T)->value = 1;
638 }
639 if (!F)
640 {
641 F = es_object_new(ES_TYPE_BOOLEAN);
642 ((EsBoolean*)F)->value = 0;
643 }
644
645 return value? T: F;
646 }
647
648 int
es_boolean_p(const EsObject * object)649 es_boolean_p (const EsObject* object)
650 {
651 return es_object_type_p(object, ES_TYPE_BOOLEAN);
652 }
653
654 int
es_boolean_get(const EsObject * object)655 es_boolean_get (const EsObject* object)
656 {
657 if (es_boolean_p(object))
658 return ((EsBoolean *)object)->value;
659 else
660 {
661 mio_printf(mio_stderr(), ";; es_boolean_get, Wrong type argument: ");
662 es_print(object, mio_stderr());
663 mio_putc(mio_stderr(), '\n');
664 return -1;
665 }
666 }
667
668 static void
es_boolean_free(EsObject * object)669 es_boolean_free(EsObject* object)
670 {
671 /* Do nothing */
672 }
673
674 static int
es_boolean_equal(const EsObject * self,const EsObject * other)675 es_boolean_equal(const EsObject* self, const EsObject* other)
676 {
677 return (self == other)? 1: 0;
678 }
679
680 static void
es_boolean_print(const EsObject * object,MIO * fp)681 es_boolean_print(const EsObject* object, MIO* fp)
682 {
683 mio_printf(fp, "#%c", (es_boolean_get(object)? 't': 'f'));
684 }
685
686 /*
687 * Singleton
688 */
689 static EsSingleton*
es_obarray_intern(EsType type,const char * name)690 es_obarray_intern(EsType type, const char* name)
691 {
692 unsigned int hv;
693 EsSingleton** obarray;
694 EsSingleton* s;
695 EsSingleton* tmp;
696
697
698 obarray = (classes[type])->obarray;
699 if (!obarray)
700 return NULL;
701
702 hv = hash(name);
703 tmp = obarray[hv];
704
705 s = NULL;
706 while (tmp)
707 {
708 if (!strcmp(tmp->quark, name))
709 {
710 s = tmp;
711 break;
712 }
713 else
714 tmp = ((EsObject *)tmp)->next;
715 }
716
717 if (!s)
718 {
719 s = (EsSingleton*) es_object_new(type);
720 s->quark = strdup(name);
721 tmp = obarray[hv];
722 obarray[hv] = s;
723 ((EsObject *)s)->next = tmp;
724 }
725
726 return s;
727
728 }
729
730 static const char*
es_singleton_get(EsSingleton * singleton)731 es_singleton_get (EsSingleton *singleton)
732 {
733 return singleton->quark;
734 }
735
736
737 /*
738 * Symbol
739 */
740 static unsigned char get_char_class(int c);
741
742
743 EsObject*
es_symbol_intern(const char * name)744 es_symbol_intern (const char* name)
745 {
746 EsSingleton* r;
747
748 r = es_obarray_intern(ES_TYPE_SYMBOL, name);
749 return (EsObject*)r;
750 }
751
752 int
es_symbol_p(const EsObject * object)753 es_symbol_p (const EsObject* object)
754 {
755 return es_object_type_p(object, ES_TYPE_SYMBOL);
756 }
757
758 const char*
es_symbol_get(const EsObject * object)759 es_symbol_get (const EsObject* object)
760 {
761 if (es_symbol_p(object))
762 return es_singleton_get((EsSingleton*)object);
763 else
764 {
765 mio_printf(mio_stderr(), ";; es_symbol_get, Wrong type argument: ");
766 es_print(object, mio_stderr());
767 mio_putc(mio_stderr(), '\n');
768 return NULL;
769 }
770 }
771
es_symbol_set_data(const EsObject * object,void * data)772 void* es_symbol_set_data (const EsObject* object, void *data)
773 {
774 if (es_symbol_p(object))
775 {
776 void* old_data;
777
778 old_data = ((EsSymbol*)object)->data;
779 ((EsSymbol*)object)->data = data;
780 return old_data;
781 }
782 else
783 {
784 mio_printf(mio_stderr(), ";; es_symbol_set_data, Wrong type argument: ");
785 es_print(object, mio_stderr());
786 mio_putc(mio_stderr(), '\n');
787 return NULL;
788 }
789 }
790
es_symbol_get_data(const EsObject * object)791 void* es_symbol_get_data (const EsObject* object)
792 {
793 if (es_symbol_p(object))
794 return ((EsSymbol*)object)->data;
795 else
796 {
797 mio_printf(mio_stderr(), ";; es_symbol_get_data, Wrong type argument: ");
798 es_print(object, mio_stderr());
799 mio_putc(mio_stderr(), '\n');
800 return NULL;
801 }
802 }
803
804 static void
es_symbol_free(EsObject * object)805 es_symbol_free(EsObject* object)
806 {
807 /* DO NOTHING */
808 }
809
810 static int
es_symbol_equal(const EsObject * self,const EsObject * other)811 es_symbol_equal(const EsObject* self, const EsObject* other)
812 {
813 return (self == other)? 1: 0;
814 }
815
816 static void
es_symbol_print(const EsObject * object,MIO * fp)817 es_symbol_print(const EsObject* object, MIO* fp)
818 {
819 const char* string;
820 size_t len;
821 char c;
822 unsigned char cc;
823 unsigned char mask;
824 int needs_bar;
825 int i;
826
827 string = es_symbol_get(object);
828 if (!string)
829 return;
830
831 len = strlen(string);
832 if (len == 0)
833 needs_bar = 1;
834
835 c = string[0];
836 cc = get_char_class(c);
837 mask = 0x1;
838 needs_bar = (cc & mask)? 1: 0;
839 if (!needs_bar)
840 {
841 /* 0 => 1? */
842 mask = 0x2;
843 for (i = 0; i< len; i++)
844 {
845 c = string[i];
846 cc = get_char_class(c);
847 needs_bar = (cc & mask)? 1: 0;
848 if (needs_bar)
849 break;
850 }
851
852 }
853
854 if (needs_bar)
855 mio_printf(fp, "|");
856
857 for (i = 0; i < len; i++)
858 {
859 c = string[i];
860 if (c == '\\' || c == '|')
861 mio_printf(fp, "\\");
862 mio_printf(fp, "%c", c);
863 }
864
865 if (needs_bar)
866 mio_printf(fp, "|");
867 }
868
869
870 /*
871 * symbol.c - symbol implementation
872 *
873 * Copyright (c) 2000-2007 Shiro Kawai <shiro@acm.org>
874 *
875 * Redistribution and use in source and binary forms, with or without
876 * modification, are permitted provided that the following conditions
877 * are met:
878 *
879 * 1. Redistributions of source code must retain the above copyright
880 * notice, this list of conditions and the following disclaimer.
881 *
882 * 2. Redistributions in binary form must reproduce the above copyright
883 * notice, this list of conditions and the following disclaimer in the
884 * documentation and/or other materials provided with the distribution.
885 *
886 * 3. Neither the name of the authors nor the names of its contributors
887 * may be used to endorse or promote products derived from this
888 * software without specific prior written permission.
889 *
890 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
891 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
892 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
893 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
894 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
895 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
896 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
897 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
898 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
899 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
900 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
901 *
902 * $Id: symbol.c,v 1.40 2007/09/13 12:30:28 shirok Exp $
903 */
904 /* table of special chars.
905 bit 0: bad char for symbol to begin with
906 bit 1: bad char for symbol to contain
907 bit 2: bad char for symbol, and should be written as \nnn
908 bit 3: bad char for symbol, and should be written as \c
909 bit 4: may be escaped when case fold mode
910 */
911 static char symbol_special[] = {
912 /* NUL .... */
913 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
914 /* .... */
915 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
916 /* ! " # $ % & ' ( ) * + , - . / */
917 3, 0, 3, 3, 0, 0, 0, 3, 3, 3, 0, 1, 3, 1, 1, 0,
918 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
919 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 0, 0, 0, 0,
920 /* @ A B C D E F G H I J K L M N O */
921 1, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
922 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
923 16,16,16,16,16,16,16,16,16,16,16,3, 11,3, 0, 0,
924 /* ` a b c d e f g h i j k l m n o */
925 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
926 /* p q r s t u v w x y z { | } ~ ^? */
927 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 11,3, 0, 7
928 };
929
930 /* symbol_special[':'] was 1 in the symbol.c of Gauche.
931 However I modified it to 0.
932 Because a keyword is a just a symbol started from `:'
933 in Es. */
934 static unsigned char
get_char_class(int c)935 get_char_class(int c)
936 {
937 return (c < 0)? 0xff: symbol_special[c];
938 }
939
940 /*
941 * String
942 */
943 EsObject*
es_string_new(const char * value)944 es_string_new (const char* value)
945 {
946 EsObject* r;
947
948 r = es_object_new(ES_TYPE_STRING);
949 ((EsString*)r)->value = strdup(value);
950 return r;
951 }
952
953 EsObject*
es_string_newL(const char * value,size_t len)954 es_string_newL (const char* value, size_t len)
955 {
956 EsObject* r;
957
958 r = es_object_new(ES_TYPE_STRING);
959 if (es_error_p (r))
960 return r;
961
962 void * v = malloc (len + 1);
963 if (v == NULL)
964 {
965 ((EsString*)r)->value = NULL;
966 es_object_free (r);
967 return ES_ERROR_MEMORY;
968 }
969 memcpy (v, value, len);
970 ((char *)v)[len] = '\0';
971 ((EsString*)r)->value = v;
972 return r;
973 }
974
975 int
es_string_p(const EsObject * object)976 es_string_p (const EsObject* object)
977 {
978 return es_object_type_p(object, ES_TYPE_STRING);
979 }
980
981 const char*
es_string_get(const EsObject * object)982 es_string_get (const EsObject* object)
983 {
984 if (es_string_p(object))
985 return ((EsString *)object)->value;
986 else
987 {
988 mio_printf(mio_stderr(), ";; es_string_get, Wrong type argument: ");
989 es_print(object, mio_stderr());
990 mio_putc(mio_stderr(), '\n');
991 return NULL;
992 }
993 }
994
995 static void
es_string_free(EsObject * object)996 es_string_free(EsObject* object)
997 {
998 if (es_string_p(object))
999 {
1000 free(((EsString*) object)->value);
1001 ((EsString*) object)->value = NULL;
1002 es_object_free(object);
1003 }
1004 else
1005 {
1006 mio_printf(mio_stderr(), ";; Internal error: \n");
1007 mio_printf(mio_stderr(), ";;es_string_free, Wrong type argument: ");
1008 es_print(object, mio_stderr());
1009 mio_putc(mio_stderr(), '\n');
1010 }
1011 }
1012
1013
1014 static int
es_string_equal(const EsObject * self,const EsObject * other)1015 es_string_equal(const EsObject* self, const EsObject* other)
1016 {
1017 if (es_string_p(other))
1018 {
1019 return (!strcmp(es_string_get(self), es_string_get(other)));
1020 }
1021 else
1022 return 0;
1023 }
1024
1025 static void
es_string_print(const EsObject * object,MIO * fp)1026 es_string_print(const EsObject* object, MIO* fp)
1027 {
1028 const char* string;
1029 char c;
1030 size_t len;
1031 int i;
1032
1033
1034 string = es_string_get(object);
1035 len = strlen(string);
1036
1037 mio_printf(fp, "\"");
1038
1039 for (i = 0; i < len; i++)
1040 {
1041 char cc;
1042
1043 c = string[i];
1044 switch (c)
1045 {
1046 case '\n':
1047 cc = 'n';
1048 break;
1049 case '\t':
1050 cc = 't';
1051 break;
1052 case '\r':
1053 cc = 'r';
1054 break;
1055 case '\f':
1056 cc = 'f';
1057 break;
1058 default:
1059 cc = 0;
1060 break;
1061 }
1062 if (cc)
1063 {
1064 mio_printf(fp, "\\");
1065 mio_printf(fp, "%c", cc);
1066 continue;
1067 }
1068
1069 if (c == '\\' || c == '"')
1070 mio_printf(fp, "\\");
1071 mio_printf(fp, "%c", c);
1072 }
1073
1074 mio_printf(fp, "\"");
1075 }
1076
1077 /*
1078 * Cons
1079 */
1080 EsObject*
es_cons(EsObject * car,EsObject * cdr)1081 es_cons (EsObject* car, EsObject* cdr)
1082 {
1083 EsObject* r;
1084
1085 if (!es_list_p(cdr))
1086 {
1087 /* This library doesn't permit to dotted list. */
1088 return es_nil;
1089 }
1090
1091
1092 r = es_object_new(ES_TYPE_CONS);
1093 if (es_error_p (r))
1094 return r;
1095 if (es_debug)
1096 {
1097 mio_printf(mio_stderr(), ";; cons[0x%p] = (0x%p . 0x%p)\n", r, car, cdr);
1098 /* es_print(car, mio_stderr());
1099 mio_putc('\n', mio_stderr());
1100 es_print(cdr, mio_stderr());
1101 mio_putc('\n', mio_stderr()); */
1102 }
1103 ((EsCons*)r)->car = es_object_ref(car);
1104 ((EsCons*)r)->cdr = es_object_ref(cdr);
1105
1106 return r;
1107 }
1108
1109 int
es_cons_p(const EsObject * object)1110 es_cons_p (const EsObject* object)
1111 {
1112 return es_object_type_p(object, ES_TYPE_CONS);
1113 }
1114
1115 int
es_list_p(const EsObject * object)1116 es_list_p (const EsObject* object)
1117 {
1118 EsType t;
1119
1120 t = es_object_get_type(object);
1121 return (t == ES_TYPE_NIL || t == ES_TYPE_CONS);
1122 }
1123
1124 EsObject*
es_car(const EsObject * object)1125 es_car (const EsObject* object)
1126 {
1127 if (es_cons_p(object))
1128 return ((EsCons*)object)->car;
1129 else if (es_null(object))
1130 return es_nil;
1131 else
1132 {
1133 mio_printf(mio_stderr(), ";; es_car, Wrong type argument: ");
1134 es_print(object, mio_stderr());
1135 mio_putc(mio_stderr(), '\n');
1136 return es_nil;
1137 }
1138 }
1139
1140 EsObject*
es_cdr(const EsObject * object)1141 es_cdr (const EsObject* object)
1142 {
1143 if (es_cons_p(object))
1144 return ((EsCons*)object)->cdr;
1145 else if (es_null(object))
1146 return es_nil;
1147 else
1148 {
1149 mio_printf(mio_stderr(), ";; es_cdr, Wrong type argument: ");
1150 es_print(object, mio_stderr());
1151 mio_putc(mio_stderr(), '\n');
1152 return es_nil;
1153 }
1154 }
1155
1156 static void
es_cons_free(EsObject * object)1157 es_cons_free(EsObject* object)
1158 {
1159 EsCons* cons;
1160
1161 if (es_cons_p(object))
1162 {
1163 cons = ((EsCons*)object);
1164
1165 es_object_unref(cons->car);
1166 cons->car = NULL;
1167
1168 es_object_unref(cons->cdr);
1169 cons->cdr = NULL;
1170 es_object_free(object);
1171 }
1172 else if (es_null(object))
1173 ; /* DO NOTHING */
1174 else
1175 {
1176 mio_printf(mio_stderr(), ";; Internal error: \n");
1177 mio_printf(mio_stderr(), ";; es_cons_free, Wrong type argument: ");
1178 es_print(object, mio_stderr());
1179 mio_putc(mio_stderr(), '\n');
1180 }
1181 }
1182
1183 static int
es_cons_equal(const EsObject * self,const EsObject * other)1184 es_cons_equal(const EsObject* self, const EsObject* other)
1185 {
1186 return (es_null(other)
1187 || (!es_cons_p(other))
1188 || (!es_object_equal(es_car(self), es_car(other)))
1189 || (!es_object_equal(es_cdr(self), es_cdr(other))))
1190 ? 0
1191 : 1;
1192 }
1193
1194 static void
es_cons_print(const EsObject * object,MIO * fp)1195 es_cons_print(const EsObject* object, MIO* fp)
1196 {
1197 EsObject* car;
1198 EsObject* cdr;
1199
1200 mio_printf(fp, "(");
1201 while(!es_null(object))
1202 {
1203 car = es_car(object);
1204 cdr = es_cdr(object);
1205
1206 es_print(car, fp);
1207 if (es_cons_p(cdr))
1208 mio_putc(fp, ' ');
1209 else if (!es_null(cdr))
1210 {
1211 mio_printf(mio_stderr(), ";; es_cons_print, dotted list given: ");
1212 mio_putc(mio_stderr(), '\n');
1213 }
1214 object = cdr;
1215 }
1216 mio_printf(fp, ")");
1217 }
1218
1219 static EsObject* es_cons_reverse_rec(EsObject* cdr,
1220 EsObject* car,
1221 EsObject* gathered);
1222
1223 static EsObject*
es_cons_reverse(EsObject * cons)1224 es_cons_reverse (EsObject* cons)
1225 {
1226 /* g_return_val_if_fail (es_null(cons) || es_cons_p(cons), es_nil);
1227 g_return_val_if_fail (!es_cproc_dotted_p(cons), es_nil); */
1228
1229 if (es_null(cons))
1230 return es_nil;
1231 else
1232 return es_cons_reverse_rec(es_cdr(cons),
1233 es_car(cons),
1234 es_nil);
1235 }
1236
1237 EsObject*
es_reverse(EsObject * cons)1238 es_reverse (EsObject* cons)
1239 {
1240 return es_cons_reverse(cons);
1241 }
1242
1243 static EsObject*
es_cons_reverse_rec(EsObject * cdr,EsObject * car,EsObject * gathered)1244 es_cons_reverse_rec(EsObject* cdr,
1245 EsObject* car,
1246 EsObject* gathered)
1247 {
1248 EsObject* cons;
1249 EsObject* o;
1250
1251 cons = es_cons(car, o = gathered);
1252 es_object_unref(o);
1253
1254 if (es_null(cdr))
1255 return cons;
1256 else
1257 return es_cons_reverse_rec(es_cdr(cdr),
1258 es_car(cdr),
1259 cons);
1260 }
1261
1262 /*
1263 * Regex
1264 */
1265 EsObject*
es_regex_compile(const char * pattern_literal,int case_insensitive)1266 es_regex_compile (const char* pattern_literal, int case_insensitive)
1267 {
1268 EsObject* r;
1269 regex_t *code;
1270 int err;
1271 int flag = REG_EXTENDED | REG_NEWLINE
1272 | (case_insensitive? REG_ICASE: 0);
1273
1274 code = malloc(sizeof(regex_t));
1275 if (!code)
1276 return ES_ERROR_MEMORY;
1277
1278 err = regcomp(code, pattern_literal,
1279 flag);
1280 if (err)
1281 {
1282 #if 0
1283 /* TODO: This should be reported to caller. */
1284 char errmsg [256];
1285 regerror (err, code, errmsg, 256);
1286 #endif
1287 regfree (code);
1288 free (code);
1289 return ES_ERROR_REGEX;
1290 }
1291
1292 r = es_object_new(ES_TYPE_REGEX);
1293 ((EsRegex*)r)->code = code;
1294 ((EsRegex*)r)->literal = strdup(pattern_literal);
1295 if (!((EsRegex*)r)->literal)
1296 {
1297 regfree(((EsRegex*)r)->code);
1298 free(((EsRegex*)r)->code);
1299 es_object_free(r);
1300 return ES_ERROR_MEMORY;
1301 }
1302 ((EsRegex*)r)->case_insensitive = case_insensitive;
1303 return r;
1304 }
1305
1306 int
es_regex_p(const EsObject * object)1307 es_regex_p (const EsObject* object)
1308 {
1309 return es_object_type_p(object, ES_TYPE_REGEX);
1310 }
1311
es_regex_free(EsObject * object)1312 static void es_regex_free(EsObject* object)
1313 {
1314 free(((EsRegex*)object)->literal);
1315 regfree(((EsRegex*)object)->code);
1316 free(((EsRegex*)object)->code);
1317 es_object_free(object);
1318 }
1319
1320 static int
es_regex_equal(const EsObject * self,const EsObject * other)1321 es_regex_equal(const EsObject* self, const EsObject* other)
1322 {
1323 return (es_regex_p (other)
1324 && (strcmp (((EsRegex*)self)->literal,
1325 ((EsRegex*)other)->literal) == 0)
1326 && (((EsRegex*)self)->case_insensitive ==
1327 ((EsRegex*)other)->case_insensitive));
1328 }
1329
1330 static void
es_regex_print(const EsObject * object,MIO * fp)1331 es_regex_print(const EsObject* object, MIO* fp)
1332 {
1333 mio_puts(fp, "#/");
1334 const char *s = ((EsRegex*)object)->literal;
1335 while (*s)
1336 {
1337 if (*s == '/')
1338 mio_putc(fp, '\\');
1339 mio_putc(fp, *s);
1340 s++;
1341 }
1342 mio_putc(fp, '/');
1343 if (((EsRegex*)object)->case_insensitive)
1344 mio_putc(fp, 'i');
1345 }
1346
1347 EsObject*
es_regex_exec(const EsObject * regex,const EsObject * str)1348 es_regex_exec (const EsObject* regex,
1349 const EsObject* str)
1350 {
1351 return regexec (((EsRegex*)regex)->code, es_string_get (str),
1352 0, NULL, 0)? es_false: es_true;
1353 }
1354
1355 /*
1356 * Error
1357 */
1358 EsObject*
es_error_intern(const char * name)1359 es_error_intern (const char* name)
1360 {
1361 EsSingleton* r;
1362
1363 r = es_obarray_intern(ES_TYPE_ERROR, name);
1364 return (EsObject*)r;
1365 }
1366
1367 int
es_error_p(const EsObject * object)1368 es_error_p (const EsObject* object)
1369 {
1370 return es_object_type_p(object, ES_TYPE_ERROR);
1371 }
1372
1373 const char*
es_error_name(const EsObject * object)1374 es_error_name (const EsObject* object)
1375 {
1376 if (es_error_p(object))
1377 return es_singleton_get((EsSingleton *)object);
1378 else
1379 {
1380 mio_printf(mio_stderr(), ";; es_error_name, Wrong type argument: ");
1381 es_print(object, mio_stderr());
1382 mio_putc(mio_stderr(), '\n');
1383 return NULL;
1384 }
1385 }
1386
1387 EsObject*
es_error_set_object(EsObject * error,EsObject * object)1388 es_error_set_object (EsObject* error, EsObject* object)
1389 {
1390 EsError *e = (EsError *)error;
1391 if (e->object)
1392 es_object_unref (e->object);
1393
1394 e->object = es_object_ref (object);
1395 return error;
1396 }
1397
1398 EsObject*
es_error_get_object(const EsObject * error)1399 es_error_get_object (const EsObject* error)
1400 {
1401 EsError *e = (EsError *)error;
1402 return e->object;
1403 }
1404
1405 static void
es_error_free(EsObject * object)1406 es_error_free(EsObject* object)
1407 {
1408 /* DO NOTHING */
1409 }
1410
1411 static int
es_error_equal(const EsObject * self,const EsObject * other)1412 es_error_equal(const EsObject* self, const EsObject* other)
1413 {
1414 return (self == other)? 1: 0;
1415 }
1416
1417 static void
es_error_print(const EsObject * object,MIO * fp)1418 es_error_print(const EsObject* object, MIO* fp)
1419 {
1420 const char* string;
1421 EsError *e = (EsError *)object;
1422
1423 string = es_error_name(object);
1424 mio_printf(fp, "#%s:", string);
1425 es_print (e->object, fp);
1426 }
1427
1428 /*
1429 * Foreigner
1430 */
1431 typedef struct _EsPointerClass EsPointerClass;
1432 struct _EsPointerClass
1433 {
1434 EsObjectClass base;
1435
1436 size_t fat_size;
1437 EsObject *(* init_fat) (void *fat, void * ptr, void *extra);
1438
1439 void (* free_ptr) (void *);
1440 int (* equal_ptr) (const void*, const void*);
1441 void (* print_ptr) (const void*, MIO *);
1442
1443
1444 void (* free_fatptr) (void *, void *);
1445 int (* equal_fatptr) (const void*, const void*,
1446 const void*, const void*);
1447 void (* print_fatptr) (const void*, const void*, MIO *);
1448 };
1449
1450 static EsType
es_type_define_pointer_full(const char * name,size_t fat_size,EsObject * (* initfat_fn)(void * fat,void * ptr,void * extra),void (* freefn)(void *),int (* equalfn)(const void *,const void *),void (* printfn)(const void *,MIO *),void (* freefn_fat)(void * ptr,void * fat),int (* equalfn_fat)(const void * ptr_a,const void * fat_a,const void * ptr_b,const void * fat_b),void (* printfn_fat)(const void * ptr,const void * fat,MIO *))1451 es_type_define_pointer_full(const char *name,
1452 size_t fat_size,
1453 EsObject *(* initfat_fn) (void *fat, void * ptr, void *extra),
1454 void (* freefn) (void *),
1455 int (* equalfn) (const void*, const void*),
1456 void (* printfn) (const void*, MIO *),
1457 void (* freefn_fat) (void * ptr, void *fat),
1458 int (* equalfn_fat) (const void* ptr_a, const void* fat_a,
1459 const void* ptr_b, const void* fat_b),
1460 void (* printfn_fat) (const void* ptr, const void *fat, MIO *))
1461 {
1462 EsType t = ES_TYPE_NIL;
1463 if (classes_count >= ES_TYPE_CLASS_MAX)
1464 return t;
1465
1466 EsPointerClass *c = calloc (1, sizeof (EsPointerClass));
1467 if (c == NULL)
1468 return t;
1469
1470 c->fat_size = fat_size;
1471 c->init_fat = initfat_fn;
1472 c->free_ptr = freefn;
1473 c->equal_ptr = equalfn;
1474 c->print_ptr = printfn;
1475 c->free_fatptr = freefn_fat;
1476 c->equal_fatptr = equalfn_fat;
1477 c->print_fatptr = printfn_fat;
1478
1479 c->base.size = sizeof (EsPointer) + c->fat_size;
1480 c->base.free = es_pointer_free;
1481 c->base.equal = es_pointer_equal;
1482 c->base.print = es_pointer_print;
1483 c->base.flags = ES_OBJECT_FLAG_ATOM;
1484 c->base.name = strdup (name);
1485 if (c->base.name == NULL)
1486 {
1487 free (c);
1488 return t;
1489 }
1490
1491 t = classes_count++;
1492 classes [t] = (EsObjectClass *)c;
1493
1494 return t;
1495 }
1496
1497 EsType
es_type_define_pointer(const char * name,void (* freefn)(void *),int (* equalfn)(const void *,const void *),void (* printfn)(const void *,MIO *))1498 es_type_define_pointer(const char *name,
1499 void (* freefn) (void *),
1500 int (* equalfn) (const void*, const void*),
1501 void (* printfn) (const void*, MIO *))
1502 {
1503
1504 return es_type_define_pointer_full (name, 0, NULL,
1505 freefn, equalfn, printfn,
1506 NULL, NULL, NULL);
1507 }
1508
1509 EsType
es_type_define_fatptr(const char * name,size_t fat_size,EsObject * (* initfat_fn)(void * fat,void * ptr,void * extra),void (* freefn)(void * ptr,void * fat),int (* equalfn)(const void * ptr_a,const void * fat_a,const void * ptr_b,const void * fat_b),void (* printfn)(const void * ptr,const void * fat,MIO *))1510 es_type_define_fatptr (const char *name,
1511 size_t fat_size,
1512 EsObject *(* initfat_fn) (void *fat, void * ptr, void *extra),
1513 void (* freefn) (void * ptr, void *fat),
1514 int (* equalfn) (const void* ptr_a, const void* fat_a,
1515 const void* ptr_b, const void* fat_b),
1516 void (* printfn) (const void* ptr, const void *fat, MIO *))
1517 {
1518 return es_type_define_pointer_full (name, fat_size, initfat_fn,
1519 NULL, NULL, NULL,
1520 freefn, equalfn, printfn);
1521 }
1522
es_pointer_free(EsObject * object)1523 static void es_pointer_free(EsObject* object)
1524 {
1525 EsObjectClass *c = class_of(object);
1526 if (((EsPointer*)object)->ptr)
1527 {
1528 if (((EsPointerClass *)c)->free_fatptr)
1529 ((EsPointerClass *)c)->free_fatptr (((EsPointer*)object)->ptr,
1530 ((EsPointer*)object)->fat);
1531 else if (((EsPointerClass *)c)->free_ptr)
1532 ((EsPointerClass *)c)->free_ptr (((EsPointer*)object)->ptr);
1533 }
1534 es_object_free (object);
1535 }
1536
es_pointer_equal(const EsObject * self,const EsObject * other)1537 static int es_pointer_equal(const EsObject* self, const EsObject* other)
1538 {
1539 if (es_object_get_type (self) != es_object_get_type (other))
1540 return 0;
1541
1542 EsPointerClass *c = (EsPointerClass *)class_of(self);
1543 void *self_ptr = ((EsPointer *)self)->ptr;
1544 void *other_ptr = ((EsPointer *)other)->ptr;
1545
1546 if (c->fat_size == 0 && self_ptr == other_ptr)
1547 return 1;
1548
1549 if (self_ptr == NULL)
1550 return 0;
1551
1552 if (c->equal_fatptr)
1553 return c->equal_fatptr (self_ptr, ((EsPointer*)self)->fat,
1554 other_ptr, ((EsPointer*)other)->fat);
1555 else if (c->equal_ptr)
1556 return c->equal_ptr (self_ptr, other_ptr);
1557 return 0;
1558 }
1559
es_pointer_print(const EsObject * object,MIO * fp)1560 static void es_pointer_print(const EsObject* object, MIO* fp)
1561 {
1562 EsObjectClass *c = class_of(object);
1563 if (((EsPointerClass *)c)->print_fatptr)
1564 {
1565 ((EsPointerClass *)c)->print_fatptr (((EsPointer *)object)->ptr,
1566 ((EsPointer *)object)->fat,
1567 fp);
1568 }
1569 else if (((EsPointerClass *)c)->print_ptr)
1570 {
1571 ((EsPointerClass *)c)->print_ptr (((EsPointer *)object)->ptr, fp);
1572 }
1573 else
1574 {
1575 mio_puts(fp, "#<");
1576 mio_puts(fp, c->name);
1577 mio_putc(fp, ' ');
1578 mio_printf(fp, "(%p, %p)", object, ((EsPointer *)object)->ptr);
1579 mio_putc(fp, '>');
1580 }
1581 }
1582
1583 static EsObject*
es_pointer_new_common(EsType type,void * ptr)1584 es_pointer_new_common (EsType type, void *ptr)
1585 {
1586 EsObject *r;
1587
1588 r = es_object_new (type);
1589 if (es_error_p (r))
1590 return r;
1591
1592 ((EsPointer *)r)->ptr = ptr;
1593 return r;
1594 }
1595
1596 /*
1597 * Pointer
1598 */
1599 EsObject*
es_pointer_new(EsType type,void * ptr)1600 es_pointer_new (EsType type, void *ptr)
1601 {
1602 EsObject *r = es_pointer_new_common (type, ptr);
1603 if (es_error_p (r))
1604 return r;
1605
1606 if (((EsPointerClass *) (classes [type]))->fat_size > 0)
1607 memset(((EsPointer *)r)->fat, 0,
1608 ((EsPointerClass *) (classes [type]))->fat_size);
1609 return r;
1610 }
1611
1612 void*
es_pointer_get(const EsObject * object)1613 es_pointer_get (const EsObject *object)
1614 {
1615 return ((EsPointer *)object)->ptr;
1616 }
1617
1618 void*
es_pointer_take(EsObject * object)1619 es_pointer_take (EsObject *object)
1620 {
1621 void *r = ((EsPointer *)object)->ptr;
1622 ((EsPointer *)object)->ptr = NULL;
1623 return r;
1624 }
1625
1626 /*
1627 * Fat pointer
1628 */
1629 EsObject*
es_fatptr_new(EsType type,void * ptr,void * extra)1630 es_fatptr_new (EsType type, void *ptr, void *extra)
1631 {
1632 EsObject *r = es_pointer_new_common (type, ptr);
1633 if (es_error_p (r))
1634 return r;
1635
1636 if (((EsPointerClass *) (classes [type]))->fat_size > 0)
1637 {
1638 if (((EsPointerClass *) (classes [type]))->init_fat)
1639 {
1640 EsObject *f = (* ((EsPointerClass *) (classes [type]))->init_fat)
1641 (((EsPointer *)r)->fat, ptr, extra);
1642 if (es_error_p (f))
1643 {
1644 es_object_free (r);
1645 return f;
1646 }
1647 }
1648 else if (extra)
1649 memcpy (((EsPointer *)r)->fat, extra,
1650 ((EsPointerClass *) (classes [type]))->fat_size);
1651 else
1652 memset(((EsPointer *)r)->fat, 0,
1653 ((EsPointerClass *) (classes [type]))->fat_size);
1654 }
1655 return r;
1656 }
1657
1658 void*
es_fatptr_get(const EsObject * object)1659 es_fatptr_get (const EsObject *object)
1660 {
1661 EsObjectClass *c = class_of(object);
1662 if (((EsPointerClass *)c)->fat_size == 0)
1663 return NULL;
1664
1665 return ((EsPointer *)object)->fat;
1666 }
1667
1668
1669
1670 /* http://www.cse.yorku.ca/~oz/hash.html */
1671 static unsigned long
djb2(unsigned char * str)1672 djb2(unsigned char *str)
1673 {
1674 unsigned long hash = 5381;
1675 int c;
1676
1677 while ((c = *str++))
1678 hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
1679
1680 return hash;
1681 }
1682
hash(const char * keyarg)1683 static unsigned int hash(const char* keyarg)
1684 {
1685 return ((unsigned int)djb2((unsigned char *)keyarg)) % OBARRAY_SIZE;
1686 }
1687
1688 /*
1689 * Print
1690 */
1691 void
es_print(const EsObject * object,MIO * out)1692 es_print (const EsObject* object,
1693 MIO* out)
1694 {
1695 class_of(object)->print(object, out? out: mio_stdout());
1696 }
1697
1698
1699 char*
es_print_to_string(EsObject * object)1700 es_print_to_string (EsObject* object)
1701 {
1702 char *bp;
1703 size_t size;
1704 MIO* out;
1705
1706
1707 out = mio_new_memory (NULL, 0, realloc, NULL);
1708 if (!out)
1709 {
1710 /* TODO: Report error */
1711 return NULL;
1712 }
1713
1714 es_print(object, out);
1715 bp = (char *)mio_memory_get_data (out, &size);
1716 mio_unref(out);
1717
1718 return bp;
1719 }
1720
1721 static const char* comment_prefix = ";; ";
1722 void
es_comment(const char * comment,MIO * out)1723 es_comment (const char* comment, MIO* out)
1724 {
1725 const char* p;
1726 const char* c;
1727
1728 p = comment_prefix? comment_prefix: ";; ";
1729 c = comment? comment: "";
1730 out = out? out: mio_stdout();
1731
1732 /* ""
1733 => ;;
1734
1735 "a"
1736 => ;; a
1737
1738 "a\n"
1739 => ;; a
1740
1741
1742 "a\nb"
1743 => ;; a
1744 ;; b
1745
1746 "a\nb\n"
1747 => ;; a
1748 ;;b
1749
1750
1751 */
1752 while (1)
1753 {
1754 mio_puts(out, p);
1755
1756 while(1)
1757 {
1758 if (*c == '\0')
1759 {
1760 mio_putc(out, '\n');
1761 return;
1762 }
1763 else
1764 {
1765 mio_putc(out, *c++);
1766 if (*(c - 1) == '\n')
1767 break;
1768 }
1769 }
1770 }
1771 }
1772
1773 char*
es_comment_to_string(const char * comment)1774 es_comment_to_string (const char* comment)
1775 {
1776 char *bp;
1777 size_t size;
1778 MIO* out;
1779
1780 out = mio_new_memory (NULL, 0, realloc, NULL);
1781 if (!out)
1782 {
1783 /* TODO: Report error */
1784 return NULL;
1785 }
1786
1787 es_comment(comment, out);
1788 bp = (char *)mio_memory_get_data (out, &size);
1789 mio_unref(out);
1790
1791 return bp;
1792 }
1793
1794
1795
1796
1797 /*
1798 * Read
1799 */
1800 typedef struct _Token Token;
1801 struct _Token
1802 {
1803 char* buffer;
1804 size_t filled;
1805 size_t allocated;
1806 };
1807 static Token* token_new (char seed);
1808 static void token_free (Token* token);
1809 static Token* token_append(Token* token, char c);
1810
1811 static Token eof_token;
1812 #define EOF_TOKEN (&eof_token)
1813 static Token open_paren_token;
1814 #define OPEN_PAREN_TOKEN (&open_paren_token)
1815 static Token close_paren_token;
1816 #define CLOSE_PAREN_TOKEN (&close_paren_token)
1817
1818 static Token* get_token (MIO* in);
1819 static void skip_to_newline(MIO* in);
1820 static int is_whitespace (char c);
1821 static int is_paren_open (char c);
1822 static int is_paren_close (char c);
1823 static int is_comment_start (char c);
1824 static int is_string_start (char c);
1825 static int is_fence_start (char c);
1826 static int is_reader_macro_prefix(char c);
1827
1828 typedef
1829 int (*TerminalDetector) (int c);
1830
1831 static int is_string_end (int c);
1832 static int is_fence_end (int c);
1833 static int is_separator (int c);
1834
1835 static Token* get_sequence (MIO* fp,
1836 Token* seed,
1837 TerminalDetector is_terminator,
1838 int include_terminator);
1839 static Token* get_string (MIO* fp, char seed);
1840 static Token* get_escaped_symbol(MIO* fp, char seed);
1841 static Token* get_symbol (MIO* fp, char seed);
1842 static Token* get_regex (MIO* fp);
1843 static void inject_regex_flag (Token* t, char c);
1844
1845 static EsObject* fill_list (MIO* fp);
1846 static EsObject* make_atom (Token* token);
1847 static EsObject* make_string (char* t);
1848 static EsObject* make_symbol (char* t,
1849 int is_wrapped);
1850 static EsObject* make_boolean (int b);
1851 static int is_integer (const char* t,
1852 int* i);
1853 static EsObject* make_integer (int i);
1854 static int is_real (const char* t,
1855 double* d);
1856 static EsObject* make_real (double d);
1857 static EsObject* make_regex (const char *pat,
1858 int case_insensitive);
1859
1860
1861 EsObject*
es_read(MIO * in)1862 es_read (MIO* in)
1863 {
1864 Token* t;
1865 EsObject* r;
1866
1867
1868 in = in? in: mio_stdin();
1869
1870 t = get_token(in);
1871
1872 if (t == NULL)
1873 return ES_READER_ERROR;
1874 else if (t == EOF_TOKEN)
1875 return ES_READER_EOF;
1876 else if (t == OPEN_PAREN_TOKEN)
1877 r = fill_list(in);
1878 else if (t == CLOSE_PAREN_TOKEN)
1879 return ES_READER_ERROR;
1880 else
1881 r = make_atom(t);
1882
1883 token_free(t);
1884
1885 return r;
1886 }
1887
1888
1889 static Token*
get_token(MIO * in)1890 get_token(MIO* in)
1891 {
1892 Token* t;
1893
1894 int c;
1895 while (1)
1896 {
1897 c = mio_getc(in);
1898
1899 if (c == EOF)
1900 {
1901 t = EOF_TOKEN;
1902 break;
1903 }
1904 else
1905 {
1906 char c0;
1907
1908 c0 = (char)c;
1909
1910 if (is_whitespace(c0))
1911 continue;
1912 else if (is_comment_start(c0))
1913 {
1914 skip_to_newline(in);
1915 /* TODO */
1916 continue;
1917 }
1918 else if (is_paren_open(c0))
1919 {
1920 t = OPEN_PAREN_TOKEN;
1921 break;
1922 }
1923 else if (is_paren_close(c0))
1924 {
1925 t = CLOSE_PAREN_TOKEN;
1926 break;
1927 }
1928 else if (is_string_start(c0))
1929 {
1930 t = get_string(in, c0);
1931 break;
1932 }
1933 else if (is_fence_start(c0))
1934 {
1935 t = get_escaped_symbol(in, c0);
1936 break;
1937 }
1938 else if (is_reader_macro_prefix(c0))
1939 {
1940 c = mio_getc(in);
1941 if (c == EOF)
1942 {
1943 t = get_symbol(in, c0);
1944 break;
1945 }
1946 else if (c == '/')
1947 {
1948 t = get_regex(in);
1949 break;
1950 }
1951 else
1952 {
1953 mio_ungetc (in, c);
1954 t = get_symbol(in, c0);
1955 break;
1956 }
1957 }
1958 else
1959 {
1960 t = get_symbol(in, c0);
1961 break;
1962 }
1963 }
1964 }
1965
1966 return t;
1967 }
1968
1969 static int
is_whitespace(char c)1970 is_whitespace (char c)
1971 {
1972 static const char* const whitespace_chars = " \t\n\r\f";
1973
1974 return strchr(whitespace_chars, c)? 1: 0;
1975 }
1976
1977 static int
is_paren_open(char c)1978 is_paren_open (char c)
1979 {
1980 return (c == '(')? 1: 0;
1981 }
1982
1983 static int
is_paren_close(char c)1984 is_paren_close (char c)
1985 {
1986 return (c == ')')? 1: 0;
1987 }
1988
1989 static int
is_comment_start(char c)1990 is_comment_start (char c)
1991 {
1992 return (c == ';')? 1: 0;
1993 }
1994
1995 static int
is_string_start(char c)1996 is_string_start (char c)
1997 {
1998 return (c == '"')? 1: 0;
1999 }
2000
2001 static int
is_fence_start(char c)2002 is_fence_start (char c)
2003 {
2004 return (c == '|')? 1: 0;
2005 }
2006
2007 static int
is_reader_macro_prefix(char c)2008 is_reader_macro_prefix(char c)
2009 {
2010 return (c == '#')? 1: 0;
2011 }
2012
2013 static void
skip_to_newline(MIO * fp)2014 skip_to_newline (MIO* fp)
2015 {
2016 int c;
2017
2018
2019 while (1)
2020 {
2021 char c0;
2022
2023
2024 c = mio_getc(fp);
2025 if (c == EOF)
2026 break;
2027
2028 c0 = (char)c;
2029 if (c0 == '\n')
2030 break;
2031 }
2032 }
2033
2034 static int
is_string_end(int c)2035 is_string_end (int c)
2036 {
2037 return ((char)(c) == '"')? 1: 0;
2038 }
2039
2040 static int
is_fence_end(int c)2041 is_fence_end (int c)
2042 {
2043 return ((char)(c) == '|')? 1: 0;
2044 }
2045
2046 static int
is_separator(int c)2047 is_separator (int c)
2048 {
2049 if (c == EOF)
2050 return 1;
2051 else
2052 {
2053 char c0;
2054
2055
2056 c0 = (char)(c);
2057 if (is_whitespace(c0)
2058 || is_comment_start(c0)
2059 || is_paren_open(c0)
2060 || is_paren_close(c0)
2061 || is_string_start(c0)
2062 || is_fence_start(c0))
2063 return 1;
2064 }
2065
2066 return 0;
2067 }
2068
2069 static Token*
get_string(MIO * fp,char seed)2070 get_string (MIO* fp,
2071 char seed)
2072 {
2073 Token* t;
2074
2075 t = token_new(seed);
2076 return get_sequence(fp, t, is_string_end, 1);
2077 }
2078
2079 static Token*
get_escaped_symbol(MIO * fp,char seed)2080 get_escaped_symbol (MIO* fp,
2081 char seed)
2082 {
2083 Token* t;
2084
2085 t = token_new(seed);
2086 return get_sequence(fp, t, is_fence_end, 1);
2087 }
2088
2089 static Token*
get_symbol(MIO * fp,char seed)2090 get_symbol (MIO* fp,
2091 char seed)
2092 {
2093 Token* t;
2094
2095 t = token_new(seed);
2096 return get_sequence(fp, t, is_separator, 0);
2097 }
2098
2099 static Token*
get_regex(MIO * fp)2100 get_regex (MIO* fp)
2101 {
2102 Token *t;
2103 t = token_new('#');
2104 if (!t)
2105 return NULL;
2106
2107 if (!token_append(t, '/'))
2108 return NULL;
2109
2110 /* Inject a placeholder representing
2111 * case-{in}sesitive. */
2112 if (!token_append(t, ' '))
2113 return NULL;
2114
2115 int c;
2116 int in_escape = 0;
2117 while (1)
2118 {
2119 c = mio_getc(fp);
2120 if (EOF == c)
2121 {
2122 /* TODO: Propagate the error to upper layer. */
2123 mio_printf(mio_stderr(),
2124 ";; unexpected termination during parsing regex pattern\n");
2125 token_free (t);
2126 return NULL;
2127 }
2128
2129 char c0 = c;
2130 if (in_escape)
2131 {
2132 in_escape = 0;
2133
2134 if (c0 == 'n')
2135 c0 = '\n';
2136 else if (c0 == 't')
2137 c0 = '\t';
2138 else if (c0 != '/')
2139 {
2140 if (!token_append(t, '\\'))
2141 return NULL;
2142 }
2143
2144 if (!token_append(t, c0))
2145 return NULL;
2146 }
2147 else if (c0 == '\\')
2148 in_escape = 1;
2149 else if (c0 == '/')
2150 {
2151 c = mio_getc(fp);
2152 if (c == 'i')
2153 /* Refill the placeholder. */
2154 inject_regex_flag (t, 'i');
2155 else if (c != EOF)
2156 mio_ungetc (fp, c);
2157 break;
2158 }
2159 else
2160 if (!token_append(t, c0))
2161 return NULL;
2162 }
2163 return t;
2164 }
2165
2166 static void
dump_token(MIO * stream,const char * prefix,Token * seed)2167 dump_token (MIO* stream, const char* prefix, Token* seed)
2168 {
2169 const char* buf;
2170 int i;
2171 char c;
2172
2173
2174 buf = seed->buffer;
2175 mio_printf(stream, "%s", prefix);
2176 for (i = 0; i < ( seed->filled - 1 ); i++)
2177 {
2178 c = buf[i];
2179 mio_putc(stream, c);
2180 if (buf[i] == '\n')
2181 mio_printf(stream, "%s", prefix);
2182 }
2183 mio_putc(mio_stderr(), '\n');
2184 }
2185
2186 static Token*
get_sequence(MIO * fp,Token * seed,TerminalDetector is_terminator,int include_terminator)2187 get_sequence (MIO* fp,
2188 Token* seed,
2189 TerminalDetector is_terminator,
2190 int include_terminator)
2191 {
2192 int c;
2193 int in_escape;
2194
2195 in_escape = 0;
2196 while (1)
2197 {
2198 c = mio_getc(fp);
2199 if (EOF == c)
2200 {
2201 if (in_escape)
2202 {
2203 /*
2204 throw ReadError("no character after escape character: " + seed);
2205 */
2206 mio_printf(mio_stderr(), ";; no character after escape character:\n");
2207 {
2208 seed = token_append(seed, '\\');
2209 dump_token(mio_stderr(), "; ", seed);
2210 }
2211 token_free(seed);
2212 return NULL;
2213 }
2214 else if (is_terminator(c))
2215 break;
2216 else
2217 {
2218 /*
2219 throw ReadError("got EOF during reading a sequence: " + seed);
2220 */
2221 mio_printf(mio_stderr(), ";; got EOF during reading a sequence: \n");
2222 dump_token(mio_stderr(), "; ", seed);
2223 token_free(seed);
2224 return NULL;
2225 }
2226 }
2227 else
2228 {
2229 char c0;
2230
2231
2232 c0 = (char)(c);
2233 if (in_escape)
2234 {
2235 switch (c0)
2236 {
2237 case 'n': c0 = '\n'; break;
2238 case 't': c0 = '\t'; break;
2239 case 'r': c0 = '\r'; break;
2240 case 'f': c0 = '\f'; break;
2241 default: break;
2242 }
2243 seed = token_append(seed, c0);
2244 in_escape = 0;
2245 continue;
2246 }
2247 else if (c0 == '\\')
2248 {
2249 in_escape = 1;
2250 continue;
2251 }
2252 else if (is_terminator(c))
2253 {
2254 if (include_terminator)
2255 seed = token_append(seed, c0);
2256 else
2257 {
2258 if (mio_ungetc(fp, c) == EOF)
2259 {
2260 token_free(seed);
2261 return NULL;
2262 }
2263 }
2264 break;
2265 }
2266 else
2267 {
2268 seed = token_append(seed, c0);
2269 in_escape = 0;
2270 continue;
2271 }
2272 }
2273 }
2274 return seed;
2275 }
2276
2277
2278 /*
2279 (let ((total-length 0)
2280 (count-symbol 0))
2281 (mapatoms (lambda (s) (setq total-length (+ total-length (length (symbol-name s)))
2282 count-symbol (+ 1 count-symbol)
2283 )))
2284 (/ total-length count-symbol)) => 15
2285 */
2286 #define DEFAULT_TOKEN_LENGHT 16
2287 static Token*
token_new(char seed)2288 token_new (char seed)
2289 {
2290 Token *t;
2291
2292
2293 t = malloc(sizeof(Token));
2294 if (!t)
2295 return NULL;
2296
2297 t->buffer = calloc(1, sizeof(char) * DEFAULT_TOKEN_LENGHT);
2298 if (!t->buffer)
2299 {
2300 free(t);
2301 return NULL;
2302 }
2303
2304 t->filled = 0;
2305 t->buffer[t->filled++] = seed;
2306 t->buffer[t->filled++] = '\0';
2307 t->allocated = DEFAULT_TOKEN_LENGHT;
2308
2309 return t;
2310 }
2311
2312 static void
token_free(Token * token)2313 token_free (Token* token)
2314 {
2315 if ((token == NULL)
2316 || (token == EOF_TOKEN)
2317 || (token == OPEN_PAREN_TOKEN)
2318 || (token == CLOSE_PAREN_TOKEN))
2319 return;
2320
2321
2322 free(token->buffer);
2323 token->buffer = NULL;
2324 free(token);
2325 }
2326
2327 static Token*
token_append(Token * t,char c)2328 token_append(Token* t, char c)
2329 {
2330 size_t d;
2331
2332
2333 d = t->allocated - t->filled;
2334 if (d < 1)
2335 {
2336 char* tmp;
2337
2338 tmp = t->buffer;
2339 t->buffer = realloc(t->buffer, t->allocated *= 2);
2340 if (!t->buffer)
2341 {
2342 t->buffer = tmp;
2343 token_free(t);
2344 return NULL;
2345 }
2346 }
2347
2348 t->buffer[t->filled - 1] = c;
2349 t->buffer[t->filled++] = '\0';
2350
2351 return t;
2352 }
2353
2354 /* We use the third character of buffer
2355 * as a flag representing an option for
2356 * regex pattern.
2357 *
2358 * 'i': case_insensitive
2359 */
2360 static void
inject_regex_flag(Token * t,char c)2361 inject_regex_flag(Token* t, char c)
2362 {
2363 t->buffer [2] = c;
2364 }
2365
2366 static EsObject*
fill_list(MIO * fp)2367 fill_list (MIO* fp)
2368 {
2369 EsObject* r;
2370 Token* t;
2371
2372 r = es_nil;
2373 while(1)
2374 {
2375 t = get_token(fp);
2376 if (t == NULL)
2377 {
2378 es_object_unref(r);
2379 return ES_READER_ERROR;
2380 }
2381 else if (t == EOF_TOKEN)
2382 {
2383 es_object_unref(r);
2384 return ES_READER_ERROR;
2385 }
2386 else if (t == CLOSE_PAREN_TOKEN)
2387 {
2388 EsObject* tmp;
2389
2390 tmp = es_cons_reverse(r);
2391 es_object_unref(r);
2392 r = tmp;
2393 break;
2394 }
2395 else if (t == OPEN_PAREN_TOKEN)
2396 {
2397 EsObject* car;
2398 EsObject* cdr;
2399
2400 car = fill_list(fp);
2401 if (es_error_p(car))
2402 {
2403 es_object_unref(r);
2404 r = car;
2405 break;
2406 }
2407
2408 cdr = r;
2409 r = es_cons(car, cdr);
2410 es_object_unref(car);
2411 es_object_unref(cdr);
2412
2413 continue;
2414 }
2415 else
2416 {
2417 EsObject* car;
2418 EsObject* cdr;
2419
2420 car = make_atom(t);
2421 token_free(t);
2422
2423 if (es_error_p (car))
2424 {
2425 es_object_unref(r);
2426 r = car;
2427 break;
2428 }
2429
2430 cdr = r;
2431 r = es_cons(car, cdr);
2432 es_object_unref(car);
2433 es_object_unref(cdr);
2434
2435 continue;
2436 }
2437 }
2438
2439 return r;
2440 }
2441
2442
2443 static EsObject*
make_atom(Token * token)2444 make_atom (Token* token)
2445 {
2446 EsObject* r;
2447 char* t;
2448
2449 int i;
2450 double d;
2451
2452
2453 t = token->buffer;
2454
2455 if (t[0] == '"')
2456 r = make_string(t);
2457 else if (t[0] == '|')
2458 r = make_symbol(t, 1);
2459 else if (strcmp(t, "#t") == 0)
2460 r = make_boolean(1);
2461 else if (strcmp(t, "#f") == 0)
2462 r = make_boolean(0);
2463 else if ((strncmp(t, "#/", 2) == 0)
2464 && t[2] != '\0')
2465 r = make_regex (t + 3, (t[2] == 'i'));
2466 else if (is_integer(t, &i))
2467 {
2468 r = make_integer(i);
2469 }
2470 else if (is_real(t, &d))
2471 {
2472 r = make_real(d);
2473 }
2474 else
2475 r = make_symbol(t, 0);
2476
2477 return r;
2478 }
2479
2480 static EsObject*
make_string(char * t)2481 make_string (char* t)
2482 {
2483 size_t len;
2484
2485
2486 len = strlen(t);
2487 t[(len - 1)] = '\0';
2488 return es_string_new(t + 1);
2489 }
2490
2491 static EsObject*
make_symbol(char * t,int is_wrapped)2492 make_symbol (char* t,
2493 int is_wrapped)
2494 {
2495 if (is_wrapped)
2496 {
2497 size_t len;
2498
2499 len = strlen(t);
2500 t[(len - 1)] = '\0';
2501 t = t + 1;
2502 }
2503
2504 return es_symbol_intern(t);
2505 }
2506
2507
2508 static EsObject*
make_boolean(int b)2509 make_boolean (int b)
2510 {
2511 return es_boolean_new(b);
2512 }
2513
2514 static int
is_integer(const char * cstr,int * i)2515 is_integer (const char* cstr,
2516 int* i)
2517 {
2518 char* endptr;
2519 long r;
2520
2521 endptr = NULL;
2522 errno = 0;
2523 r = strtol(cstr, &endptr, 10);
2524
2525 if (errno || (endptr == cstr))
2526 return 0;
2527 else if (*endptr != '\0')
2528 return 0;
2529
2530 if ((r > INT_MAX) || r < INT_MIN)
2531 {
2532 /* TODO: What I should do?
2533 TODO: Set error */
2534 /*
2535 throw ReadError("Too large integer for `int': " + r);
2536 */
2537 mio_printf(mio_stderr(), ";; is_integer, Integer out of range: %s\n", cstr);
2538 return 0;
2539 }
2540
2541 *i = r;
2542 return 1;
2543 }
2544
2545 static EsObject*
make_integer(int i)2546 make_integer (int i)
2547 {
2548 return es_integer_new(i);
2549 }
2550
2551 static int
is_real(const char * cstr,double * d)2552 is_real (const char* cstr,
2553 double* d)
2554 {
2555 char* endptr;
2556
2557 endptr = NULL;
2558 errno = 0;
2559 *d = strtod(cstr, &endptr);
2560
2561 if (errno || (endptr == cstr))
2562 return 0;
2563 else if (*endptr != '\0')
2564 return 0;
2565
2566 /* TODO: INF, NAN... */
2567 return 1;
2568 }
2569
2570 static EsObject*
make_real(double d)2571 make_real (double d)
2572 {
2573 return es_real_new(d);
2574 }
2575
2576 static EsObject*
make_regex(const char * pat,int case_insensitive)2577 make_regex (const char *pat,
2578 int case_insensitive)
2579 {
2580 return es_regex_compile(pat, case_insensitive);
2581 }
2582
2583 EsObject*
es_read_from_string(const char * buf,const char ** saveptr)2584 es_read_from_string(const char* buf,
2585 const char** saveptr)
2586 {
2587 MIO* in;
2588 EsObject* o;
2589
2590
2591 /* IN is opend in "r" mode and the stream pointed by
2592 IN is short-lived here. */
2593 in = mio_new_memory((void *)buf, strlen(buf), NULL, NULL);
2594 o = es_read(in);
2595 if (saveptr)
2596 *saveptr = buf + mio_tell(in);
2597 mio_unref(in);
2598
2599 return o;
2600 }
2601
2602
2603
2604 typedef struct _EsAutounrefPool EsAutounrefPool;
2605 typedef struct _EsChain EsChain;
2606
2607 struct _EsChain
2608 {
2609 EsObject* object;
2610 EsChain* next;
2611 };
2612
2613 struct _EsAutounrefPool
2614 {
2615 EsAutounrefPool * parent_pool;
2616 EsChain* chain;
2617 };
2618
2619 static EsAutounrefPool * currrent_pool;
2620
2621 static EsAutounrefPool* es_autounref_pool_new(void);
2622 static void es_autounref_pool_free(EsAutounrefPool* pool);
2623 static EsChain* es_chain_new(EsObject* object);
2624 static void es_chain_free(EsChain* chain);
2625
2626
2627 void
es_autounref_pool_push(void)2628 es_autounref_pool_push(void)
2629 {
2630 EsAutounrefPool* r;
2631
2632 r = es_autounref_pool_new();
2633 r->parent_pool = currrent_pool;
2634 currrent_pool = r;
2635 }
2636
2637 void
es_autounref_pool_pop(void)2638 es_autounref_pool_pop (void)
2639 {
2640 EsAutounrefPool *tmp;
2641
2642 tmp = currrent_pool;
2643 currrent_pool = tmp->parent_pool;
2644
2645 es_autounref_pool_free(tmp);
2646 }
2647
2648 static void
es_autounref_pool_free(EsAutounrefPool * pool)2649 es_autounref_pool_free(EsAutounrefPool* pool)
2650 {
2651 pool->parent_pool = NULL;
2652 es_chain_free(pool->chain);
2653 pool->chain = NULL;
2654
2655 free(pool);
2656 }
2657
2658 EsObject*
es_object_autounref(EsObject * object)2659 es_object_autounref (EsObject* object)
2660 {
2661 EsChain* r;
2662
2663 r = es_chain_new(object);
2664 r->next = currrent_pool->chain;
2665 currrent_pool->chain = r;
2666
2667 return object;
2668 }
2669
2670 static EsAutounrefPool*
es_autounref_pool_new(void)2671 es_autounref_pool_new(void)
2672 {
2673 EsAutounrefPool* r;
2674
2675 r = calloc(1, sizeof(EsAutounrefPool));
2676 return r;
2677 }
2678
2679 static EsChain*
es_chain_new(EsObject * object)2680 es_chain_new(EsObject *object)
2681 {
2682 EsChain* r;
2683
2684 r = calloc(1, sizeof(EsChain));
2685 r->object = object;
2686 return r;
2687 }
2688
2689 static void
es_chain_free(EsChain * chain)2690 es_chain_free(EsChain *chain)
2691 {
2692 EsChain *tmp;
2693
2694 while(chain)
2695 {
2696 tmp = chain;
2697 chain = chain->next;
2698
2699 es_object_unref(tmp->object);
2700 tmp->object = NULL;
2701 tmp->next = NULL;
2702 free(tmp);
2703 }
2704 }
2705
2706
2707 #include <stdarg.h>
2708 static EsObject* es_list_va(EsObject* object, va_list *ap);
2709
2710 EsObject*
es_list(EsObject * object,...)2711 es_list(EsObject* object,...)
2712 {
2713 EsObject* r;
2714 va_list ap;
2715
2716 va_start(ap, object);
2717 r = es_list_va(object, &ap);
2718 va_end(ap);
2719
2720 return r;
2721 }
2722
2723 static EsObject*
es_list_va(EsObject * object,va_list * ap)2724 es_list_va(EsObject* object, va_list *ap)
2725 {
2726 EsObject* r;
2727 EsObject* p;
2728 EsObject* tmp;
2729
2730 r = es_nil;
2731 p = object;
2732 es_autounref_pool_push();
2733 do {
2734 if (p == ES_READER_EOF)
2735 break;
2736
2737 r = es_cons((p), es_object_autounref(r));
2738 p = va_arg(*ap, EsObject *);
2739 } while(1);
2740 es_autounref_pool_pop();
2741
2742 tmp = r;
2743 r = es_cons_reverse(r);
2744 es_object_unref(tmp);
2745
2746 return r;
2747 }
2748
2749
2750 static EsObject* es_append0(EsObject* tail, EsObject* body);
2751 static EsObject* es_append1(EsObject* tail, EsObject* body0);
2752
2753 EsObject*
es_append(EsObject * list,...)2754 es_append(EsObject* list,...)
2755 {
2756 EsObject *r;
2757 EsObject *tmp;
2758 EsObject *tail;
2759 EsObject *body;
2760 va_list ap;
2761
2762
2763 va_start(ap, list);
2764 r = es_list_va(list, &ap);
2765 va_end(ap);
2766
2767 tmp = r;
2768 r = es_cons_reverse(r);
2769 es_object_unref(tmp);
2770
2771 /* r */
2772 tail = es_car(r);
2773 body = es_cdr(r);
2774 tmp = r;
2775 r = es_append0(tail, body);
2776 es_object_unref(tmp);
2777
2778 return r;
2779 }
2780
2781 static EsObject*
es_append0(EsObject * tail,EsObject * body)2782 es_append0(EsObject* tail, EsObject* body)
2783 {
2784 if (es_null(body))
2785 return tail;
2786 else
2787 {
2788 EsObject* car;
2789
2790 car = es_cons_reverse(es_car(body));
2791 tail = es_append1(tail, car);
2792 es_object_unref(car);
2793 body = es_cdr(body);
2794 return es_append0(tail, body);
2795 }
2796 }
2797
2798 static EsObject*
es_append1(EsObject * tail,EsObject * body0)2799 es_append1(EsObject* tail, EsObject* body0)
2800 {
2801 if (es_null(body0))
2802 return es_object_ref(tail);
2803 else
2804 {
2805 EsObject* car;
2806 EsObject* r;
2807
2808 car = es_car(body0);
2809 tail = es_cons(car, tail);
2810
2811 r = es_append1(tail, es_cdr(body0));
2812 es_object_unref(tail);
2813 return r;
2814 }
2815 }
2816
2817
2818
2819 static EsObject* pattern_d = NULL;
2820 static EsObject* pattern_f = NULL;
2821 static EsObject* pattern_F = NULL;
2822 static EsObject* pattern_s = NULL;
2823 static EsObject* pattern_S = NULL;
2824 static EsObject* pattern_b = NULL;
2825 static EsObject* pattern_rest = NULL;
2826 static EsObject* pattern_unquote = NULL;
2827 static EsObject* pattern_splice = NULL;
2828
2829 static EsObject* pattern_i_d = NULL;
2830 static EsObject* pattern_i_f = NULL;
2831 static EsObject* pattern_i_F = NULL;
2832 static EsObject* pattern_i_s = NULL;
2833 static EsObject* pattern_i_S = NULL;
2834 static EsObject* pattern_i_b = NULL;
2835 static EsObject* pattern_i_rest = NULL;
2836 static EsObject* pattern_i_unquote = NULL;
2837
2838 static void
pattern_init(void)2839 pattern_init(void)
2840 {
2841 if (!pattern_d) (pattern_d = es_symbol_intern("%d"));
2842 if (!pattern_f) (pattern_f = es_symbol_intern("%f"));
2843 if (!pattern_F) (pattern_F = es_symbol_intern("%F"));
2844 if (!pattern_s) (pattern_s = es_symbol_intern("%s"));
2845 if (!pattern_S) (pattern_S = es_symbol_intern("%S"));
2846 if (!pattern_b) (pattern_b = es_symbol_intern("%b"));
2847 if (!pattern_rest) (pattern_rest = es_symbol_intern("%@"));
2848 if (!pattern_unquote) (pattern_unquote = es_symbol_intern("%,"));
2849 if (!pattern_splice) (pattern_splice = es_symbol_intern("%,@"));
2850
2851 if (!pattern_i_d) (pattern_i_d = es_symbol_intern("%_d"));
2852 if (!pattern_i_f) (pattern_i_f = es_symbol_intern("%_f"));
2853 if (!pattern_i_F) (pattern_i_F = es_symbol_intern("%_F"));
2854 if (!pattern_i_s) (pattern_i_s = es_symbol_intern("%_s"));
2855 if (!pattern_i_S) (pattern_i_S = es_symbol_intern("%_S"));
2856 if (!pattern_i_b) (pattern_i_b = es_symbol_intern("%_b"));
2857 if (!pattern_i_rest) (pattern_i_rest = es_symbol_intern("%_@"));
2858 if (!pattern_i_unquote) (pattern_i_unquote = es_symbol_intern("%_,"));
2859 }
2860
2861 static EsObject*
es_vrealize_atom(EsObject * fmt_object,va_list * ap)2862 es_vrealize_atom(EsObject* fmt_object, va_list *ap)
2863 {
2864 if (fmt_object == pattern_d)
2865 return es_integer_new(va_arg(*ap, int));
2866 else if (fmt_object == pattern_f)
2867 {
2868 double x = va_arg(*ap, double);
2869 mio_printf(mio_stderr(), "=>%f\n", x);
2870 return es_real_new(x);
2871 }
2872 else if (fmt_object == pattern_s)
2873 return es_string_new(va_arg(*ap, char *));
2874 else if (fmt_object == pattern_S)
2875 return es_symbol_intern(va_arg(*ap, char *));
2876 else if (fmt_object == pattern_b)
2877 return es_boolean_new(va_arg(*ap, int));
2878 else if ((fmt_object == pattern_unquote)
2879 || (fmt_object == pattern_splice))
2880 return es_object_ref(va_arg(*ap, EsObject*));
2881 else
2882 return es_object_ref(fmt_object);
2883 }
2884
2885 static EsObject*
es_vrealize(EsObject * fmt_object,va_list * ap)2886 es_vrealize(EsObject* fmt_object, va_list *ap)
2887 {
2888 pattern_init();
2889
2890 if (es_cons_p(fmt_object))
2891 {
2892 EsObject* car;
2893 EsObject* cdr;
2894 EsObject* kar;
2895 EsObject* kdr;
2896 EsObject* r;
2897
2898 car = es_car(fmt_object);
2899
2900 if (car == pattern_rest)
2901 r = es_object_ref(va_arg(*ap, EsObject*));
2902 else
2903 {
2904 cdr = es_cdr(fmt_object);
2905
2906 kar = es_vrealize(car, ap);
2907 kdr = es_vrealize(cdr, ap);
2908
2909 if (car == pattern_splice)
2910 {
2911 if (es_cons_p(kar))
2912 r = es_append(kar, kdr, ES_READER_EOF);
2913 else
2914 {
2915 /* TODO: error */
2916 char *fmt;
2917
2918 mio_printf(mio_stderr(),
2919 ";; an atom is passed for splice format:\n");
2920 fmt = es_print_to_string(fmt_object);
2921 mio_printf(mio_stderr(), ";; => %s\n", fmt);
2922 free(fmt);
2923 r = es_nil;
2924 }
2925 }
2926 else
2927 r = es_cons(kar, kdr);
2928
2929 es_object_unref(kar);
2930 es_object_unref(kdr);
2931 }
2932 return r;
2933 }
2934 else
2935 return es_vrealize_atom(fmt_object, ap);
2936 }
2937
2938 EsObject*
es_realize(EsObject * fmt_object,...)2939 es_realize (EsObject* fmt_object,...)
2940 {
2941 EsObject* object;
2942 va_list ap;
2943
2944 if (es_error_p(fmt_object))
2945 return es_object_ref(fmt_object);
2946
2947 va_start(ap, fmt_object);
2948 object = es_vrealize(fmt_object, &ap);
2949 va_end(ap);
2950
2951 return object;
2952 }
2953
2954 EsObject*
es_srealize(const char * fmt,...)2955 es_srealize (const char* fmt,...)
2956 {
2957 EsObject* fmt_object;
2958 EsObject* object;
2959 va_list ap;
2960
2961 fmt_object = es_read_from_string(fmt, NULL);
2962 if (es_error_p(fmt_object))
2963 return fmt_object;
2964
2965 va_start(ap, fmt);
2966 object = es_vrealize(fmt_object, &ap);
2967 va_end(ap);
2968
2969 es_object_unref(fmt_object);
2970
2971 return object;
2972 }
2973
es_map(EsObject * (* fn)(EsObject *,void *),EsObject * list,void * user_data)2974 EsObject* es_map (EsObject * (*fn) (EsObject *, void *),
2975 EsObject *list, void *user_data)
2976 {
2977 if (es_null (list))
2978 return list;
2979
2980 EsObject *c = es_car (list);
2981 c = fn (c, user_data);
2982 if (es_error_p (c))
2983 return c;
2984
2985 EsObject *r = es_map (fn, es_cdr (list), user_data);
2986 if (es_error_p (r))
2987 {
2988 es_object_unref (c);
2989 return r;
2990 }
2991
2992 EsObject *o = es_cons (c, r);
2993 es_object_unref (r);
2994 es_object_unref (c);
2995
2996 return o;
2997 }
2998
es_foreach(EsObject * (* fn)(EsObject *,void *),EsObject * list,void * user_data)2999 EsObject* es_foreach (EsObject * (*fn) (EsObject *, void *),
3000 EsObject *list, void *user_data)
3001 {
3002 if (es_null (list))
3003 return es_false;
3004
3005 for (EsObject *c = list; !es_null (c); c = es_cdr (c))
3006 {
3007 EsObject *r = fn (es_car (c), user_data);
3008 if (!es_object_equal (r, es_false))
3009 return r;
3010 }
3011
3012 return es_false;
3013 }
3014
es_fold(EsObject * (* kons)(EsObject *,EsObject *,void *),EsObject * knil,EsObject * list,void * user_data)3015 EsObject* es_fold (EsObject * (*kons) (EsObject *, EsObject *, void *),
3016 EsObject * knil, EsObject * list, void *user_data)
3017 {
3018 EsObject *r = knil;
3019
3020 es_autounref_pool_push();
3021 while (!es_null (list))
3022 {
3023 EsObject *e = es_car (list);
3024 list = es_cdr (list);
3025
3026 r = (* kons) (e, (r == knil) ? r : es_object_autounref (r),
3027 user_data);
3028 if (es_error_p (r))
3029 break;
3030 }
3031 es_autounref_pool_pop();
3032
3033 return r;
3034 }
3035
3036 static EsObject*
es_vmatch_atom_input(EsObject * input,EsObject * fmt_object,va_list * ap)3037 es_vmatch_atom_input(EsObject* input, EsObject* fmt_object, va_list *ap)
3038 {
3039 return ES_READER_ERROR;
3040 }
3041
3042 static EsObject*
es_vmatch_atom_fmt(EsObject * input,EsObject * fmt_object,va_list * ap)3043 es_vmatch_atom_fmt(EsObject* input, EsObject* fmt_object, va_list *ap)
3044 {
3045 if (fmt_object == pattern_unquote)
3046 *(va_arg(*ap, EsObject**)) = /* es_object_ref */(input);
3047 else if (fmt_object == pattern_i_unquote)
3048 ;
3049 else
3050 return ES_READER_ERROR;
3051
3052 return fmt_object;
3053 }
3054
3055 static EsObject*
es_vmatch_atom(EsObject * input,EsObject * fmt_object,va_list * ap)3056 es_vmatch_atom(EsObject* input, EsObject* fmt_object, va_list *ap)
3057 {
3058 if (fmt_object == pattern_d)
3059 {
3060 if (es_integer_p(input))
3061 *(va_arg(*ap, int*)) = es_integer_get(input);
3062 else
3063 return ES_READER_ERROR;
3064 }
3065 else if (fmt_object == pattern_i_d)
3066 {
3067 if (es_integer_p(input))
3068 ;
3069 else
3070 return ES_READER_ERROR;
3071 }
3072 else if (fmt_object == pattern_f)
3073 {
3074 if (es_real_p(input))
3075 *(va_arg(*ap, double*)) = es_real_get(input);
3076 else
3077 return ES_READER_ERROR;
3078 }
3079 else if (fmt_object == pattern_i_f)
3080 {
3081 if (es_real_p(input))
3082 ;
3083 else
3084 return ES_READER_ERROR;
3085 }
3086 else if (fmt_object == pattern_F)
3087 {
3088 if (es_integer_p(input))
3089 {
3090 int i;
3091
3092 i = es_integer_get(input);
3093 *(va_arg(*ap, double*)) = (double)i;
3094 }
3095 else if (es_real_p(input))
3096 {
3097 *(va_arg(*ap, double*)) = es_real_get(input);
3098 }
3099 else
3100 return ES_READER_ERROR;
3101 }
3102 else if (fmt_object == pattern_i_F)
3103 {
3104 if (es_integer_p(input) || es_real_p(input))
3105 ;
3106 else
3107 return ES_READER_ERROR;
3108 }
3109 else if (fmt_object == pattern_s)
3110 {
3111 if (es_string_p(input))
3112 *(va_arg(*ap, const char**)) = /* strdup */(es_string_get(input));
3113 else
3114 return ES_READER_ERROR;
3115 }
3116 else if (fmt_object == pattern_i_s)
3117 {
3118 if (es_string_p(input))
3119 ;
3120 else
3121 return ES_READER_ERROR;
3122 }
3123 else if (fmt_object == pattern_S)
3124 {
3125 if (es_symbol_p(input))
3126 *(va_arg(*ap, const char**)) = /* strdup */(es_symbol_get(input));
3127 else
3128 return ES_READER_ERROR;
3129 }
3130 else if (fmt_object == pattern_i_S)
3131 {
3132 if (es_symbol_p(input))
3133 ;
3134 else
3135 return ES_READER_ERROR;
3136 }
3137 else if (fmt_object == pattern_b)
3138 {
3139 if (es_boolean_p(input))
3140 *(va_arg(*ap, int*)) = es_boolean_get(input);
3141 else
3142 return ES_READER_ERROR;
3143 }
3144 else if (fmt_object == pattern_i_b)
3145 {
3146 if (es_boolean_p(input))
3147 ;
3148 else
3149 return ES_READER_ERROR;
3150 }
3151 else if (fmt_object == pattern_unquote)
3152 *(va_arg(*ap, EsObject**)) = /* es_object_ref */(input);
3153 else if (fmt_object == pattern_i_unquote)
3154 ;
3155 else if (es_object_equal(fmt_object, input))
3156 ;
3157 else
3158 return ES_READER_ERROR;
3159
3160 return fmt_object;
3161 }
3162
3163 static void
recover(EsObject * fmt_object,va_list * aq)3164 recover(EsObject* fmt_object, va_list *aq)
3165 {
3166 if (es_cons_p(fmt_object))
3167 {
3168 recover(es_car(fmt_object), aq);
3169 recover(es_cdr(fmt_object), aq);
3170 }
3171 else
3172 {
3173 if (fmt_object == pattern_s
3174 || fmt_object == pattern_S)
3175 {
3176 char **s;
3177
3178 s = va_arg(*aq, char **);
3179 (void)/* free */(*s);
3180
3181 *s = NULL;
3182 }
3183 else if (fmt_object == pattern_rest
3184 || fmt_object == pattern_unquote)
3185 {
3186 EsObject** o;
3187
3188 o = va_arg(*aq, EsObject**);
3189 (void)/* es_object_unref */(*o);
3190 *o = NULL;
3191 }
3192 }
3193 }
3194
3195 static EsObject*
es_vmatch(EsObject * input,EsObject * fmt_object,va_list * ap)3196 es_vmatch(EsObject* input, EsObject* fmt_object, va_list *ap)
3197 {
3198 pattern_init();
3199
3200 if (es_cons_p(fmt_object) && es_cons_p(input))
3201 {
3202 EsObject* fmt_car;
3203 EsObject* fmt_cdr;
3204 EsObject* i_car;
3205 EsObject* i_cdr;
3206
3207 EsObject* r_car;
3208 EsObject* r_cdr;
3209
3210 va_list aq;
3211
3212 fmt_car = es_car(fmt_object);
3213
3214 if (fmt_car == pattern_rest)
3215 {
3216 *(va_arg(*ap, EsObject**)) = /* es_object_ref */(input);
3217 return fmt_car;
3218 }
3219 else if (fmt_car == pattern_i_rest)
3220 {
3221 return fmt_car;
3222 }
3223
3224 fmt_cdr = es_cdr(fmt_object);
3225
3226 i_car = es_car(input);
3227 i_cdr = es_cdr(input);
3228
3229 va_copy(aq, *ap);
3230 r_car = es_vmatch(i_car, fmt_car, ap);
3231 if (es_error_p(r_car))
3232 {
3233 va_end(aq);
3234 return r_car;
3235 }
3236
3237 r_cdr = es_vmatch(i_cdr, fmt_cdr, ap);
3238 if (es_error_p(r_cdr))
3239 {
3240 recover(fmt_car, &aq);
3241 va_end(aq);
3242 return r_cdr;
3243 }
3244 va_end(aq);
3245 return r_cdr;
3246 }
3247 else if (es_cons_p(fmt_object))
3248 {
3249 return es_vmatch_atom_input(input, fmt_object, ap);
3250 }
3251 else if (es_cons_p(input))
3252 {
3253 if (fmt_object == pattern_rest)
3254 {
3255 *(va_arg(*ap, EsObject**)) = /* es_object_ref */(input);
3256 return fmt_object;
3257 }
3258 else if (fmt_object == pattern_i_rest)
3259 return fmt_object;
3260 else
3261 return es_vmatch_atom_fmt(input, fmt_object, ap);
3262 }
3263 else
3264 {
3265 return es_vmatch_atom(input, fmt_object, ap);
3266 }
3267 }
3268
3269 int
es_match(EsObject * input,EsObject * fmt_object,...)3270 es_match(EsObject* input, EsObject* fmt_object,...)
3271 {
3272 EsObject* object;
3273 va_list ap;
3274
3275 va_start(ap, fmt_object);
3276 object = es_vmatch(input, fmt_object, &ap);
3277 va_end(ap);
3278
3279 return !(es_error_p(object));
3280 }
3281
3282 int
es_smatch(EsObject * input,const char * fmt,...)3283 es_smatch (EsObject* input, const char* fmt,...)
3284 {
3285 int r;
3286 EsObject* object;
3287 EsObject* fmt_object;
3288 va_list ap;
3289
3290 fmt_object = es_read_from_string(fmt, NULL);
3291 if (es_error_p(fmt_object))
3292 return 0;
3293
3294 va_start(ap, fmt);
3295 object = es_vmatch(input, fmt_object, &ap);
3296 va_end(ap);
3297
3298 r = !(es_error_p(object));
3299 es_object_unref(fmt_object);
3300
3301 return r;
3302 }
3303
3304 EsObject*
es_pget(EsObject * plist,EsObject * key,EsObject * default_value)3305 es_pget (EsObject* plist, EsObject* key, EsObject* default_value)
3306 {
3307 if (es_cons_p(plist))
3308 {
3309 EsObject* car;
3310 EsObject* cdr;
3311 EsObject* cadr;
3312 EsObject* cddr;
3313
3314 car = es_car(plist);
3315 cdr = es_cdr(plist);
3316
3317 if (es_cons_p(cdr))
3318 {
3319 cadr = es_car(cdr);
3320 cddr = es_cdr(cdr);
3321
3322 if (es_object_equal(car, key))
3323 return cadr;
3324 else
3325 return es_pget(cddr, key, default_value);
3326 }
3327 else
3328 return ES_READER_ERROR;
3329 }
3330 else
3331 return default_value;
3332 }
3333