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