xref: /Universal-ctags/dsl/optscript.c (revision 6390fe9d816d95c2a2574da045139323522d11c8)
1d8f6b0edSMasatake YAMATO // for x in $(grep ^declop ~/var/ctags/dsl/optscript.c | sed -e 's/declop(\([^)]*\));/\1/'); do grep -q $x Tmain/optscript.d/*.ps || echo $x; done
2d8f6b0edSMasatake YAMATO /*
3d8f6b0edSMasatake YAMATO  *   Copyright (c) 2020, Masatake YAMATO
4d8f6b0edSMasatake YAMATO  *   Copyright (c) 2020, Red Hat, Inc.
5d8f6b0edSMasatake YAMATO  *
6d8f6b0edSMasatake YAMATO  *   This source code is released for free distribution under the terms of the
7d8f6b0edSMasatake YAMATO  *   GNU General Public License version 2 or (at your option) any later version.
8d8f6b0edSMasatake YAMATO  */
9d8f6b0edSMasatake YAMATO 
10d8f6b0edSMasatake YAMATO 
11d8f6b0edSMasatake YAMATO #include "general.h"
12d8f6b0edSMasatake YAMATO 
13d8f6b0edSMasatake YAMATO #include "debug.h"
14d8f6b0edSMasatake YAMATO #include "es.h"
15d8f6b0edSMasatake YAMATO #include "htable.h"
16d8f6b0edSMasatake YAMATO #include "optscript.h"
17d8f6b0edSMasatake YAMATO #include "ptrarray.h"
18d8f6b0edSMasatake YAMATO #include "routines.h"
19d8f6b0edSMasatake YAMATO #include "vstring.h"
20d8f6b0edSMasatake YAMATO 
21d8f6b0edSMasatake YAMATO #include <ctype.h>
22d8f6b0edSMasatake YAMATO #include <string.h>
23d8f6b0edSMasatake YAMATO 
24d8f6b0edSMasatake YAMATO 
25d8f6b0edSMasatake YAMATO struct sOptVM
26d8f6b0edSMasatake YAMATO {
27d8f6b0edSMasatake YAMATO 	ptrArray  *ostack;
28d8f6b0edSMasatake YAMATO 	ptrArray  *dstack;
29d8f6b0edSMasatake YAMATO 	ptrArray  *estack;
30d8f6b0edSMasatake YAMATO 
31d8f6b0edSMasatake YAMATO 	int        dstack_protection;
32d8f6b0edSMasatake YAMATO 	MIO       *in;
33d8f6b0edSMasatake YAMATO 	MIO       *out;
34d8f6b0edSMasatake YAMATO 	MIO       *err;
35d8f6b0edSMasatake YAMATO 
36d8f6b0edSMasatake YAMATO 	EsObject  *error;
37d8f6b0edSMasatake YAMATO 
38d8f6b0edSMasatake YAMATO 	int        print_depth;
39d8f6b0edSMasatake YAMATO 	int        read_depth;
40d8f6b0edSMasatake YAMATO 	char      *prompt;
41d8f6b0edSMasatake YAMATO 	void      *app_data;
42d8f6b0edSMasatake YAMATO };
43d8f6b0edSMasatake YAMATO 
44d8f6b0edSMasatake YAMATO typedef struct sOperatorFat
45d8f6b0edSMasatake YAMATO {
46d8f6b0edSMasatake YAMATO 	EsObject *name;
47d8f6b0edSMasatake YAMATO 	int arity;
48d8f6b0edSMasatake YAMATO 	const char *help_str;
49d8f6b0edSMasatake YAMATO } OperatorFat;
50d8f6b0edSMasatake YAMATO 
51d8f6b0edSMasatake YAMATO typedef struct sOperatorExtra
52d8f6b0edSMasatake YAMATO {
53d8f6b0edSMasatake YAMATO 	const char *name;
54d8f6b0edSMasatake YAMATO 	int arity;
55d8f6b0edSMasatake YAMATO 	const char *help_str;
56d8f6b0edSMasatake YAMATO } OperatorExtra;
57d8f6b0edSMasatake YAMATO 
58d8f6b0edSMasatake YAMATO typedef OptOperatorFn Operator;
59d8f6b0edSMasatake YAMATO 
60d8f6b0edSMasatake YAMATO typedef enum eAttr {
61d8f6b0edSMasatake YAMATO 	ATTR_READABLE   = 1 << 0,
62d8f6b0edSMasatake YAMATO 	ATTR_WRITABLE   = 1 << 1,
63d8f6b0edSMasatake YAMATO 	ATTR_EXECUTABLE = 1 << 2,
64d8f6b0edSMasatake YAMATO } Attr;
65d8f6b0edSMasatake YAMATO 
66d8f6b0edSMasatake YAMATO typedef struct sDictFat
67d8f6b0edSMasatake YAMATO {
68d8f6b0edSMasatake YAMATO 	unsigned int attr;
69d8f6b0edSMasatake YAMATO } DictFat;
70d8f6b0edSMasatake YAMATO 
71d8f6b0edSMasatake YAMATO typedef struct sArrayFat
72d8f6b0edSMasatake YAMATO {
73d8f6b0edSMasatake YAMATO 	unsigned int attr;
74d8f6b0edSMasatake YAMATO } ArrayFat;
75d8f6b0edSMasatake YAMATO 
76d8f6b0edSMasatake YAMATO typedef struct sStringFat
77d8f6b0edSMasatake YAMATO {
78d8f6b0edSMasatake YAMATO 	unsigned int attr;
79d8f6b0edSMasatake YAMATO } StringFat;
80d8f6b0edSMasatake YAMATO 
81d8f6b0edSMasatake YAMATO typedef struct sNameFat
82d8f6b0edSMasatake YAMATO {
83d8f6b0edSMasatake YAMATO 	unsigned int attr;
84d8f6b0edSMasatake YAMATO } NameFat;
85d8f6b0edSMasatake YAMATO 
86d8f6b0edSMasatake YAMATO static EsObject* opt_system_dict;
87d8f6b0edSMasatake YAMATO 
88d8f6b0edSMasatake YAMATO int OPT_TYPE_ARRAY;
89d8f6b0edSMasatake YAMATO int OPT_TYPE_DICT;
90d8f6b0edSMasatake YAMATO int OPT_TYPE_OPERATOR;
91d8f6b0edSMasatake YAMATO int OPT_TYPE_STRING;
92d8f6b0edSMasatake YAMATO int OPT_TYPE_NAME;
93d8f6b0edSMasatake YAMATO int OPT_TYPE_MARK;
94d8f6b0edSMasatake YAMATO 
95d8f6b0edSMasatake YAMATO static EsObject *OPT_ERR_UNDEFINED;
96d8f6b0edSMasatake YAMATO static EsObject *OPT_ERR_SYNTAX;
97d8f6b0edSMasatake YAMATO EsObject *OPT_ERR_UNDERFLOW;
98d8f6b0edSMasatake YAMATO EsObject *OPT_ERR_TYPECHECK;
99d8f6b0edSMasatake YAMATO EsObject *OPT_ERR_RANGECHECK;
100d8f6b0edSMasatake YAMATO static EsObject *OPT_ERR_DICTSTACKUNDERFLOW;
101d8f6b0edSMasatake YAMATO static EsObject *OPT_ERR_UNMATCHEDMARK;
102d8f6b0edSMasatake YAMATO static EsObject *OPT_ERR_INTERNALERROR;
103d8f6b0edSMasatake YAMATO static EsObject *OPT_ERR_END_PROC;
104d8f6b0edSMasatake YAMATO static EsObject *OPT_ERR_INVALIDEXIT;
105d8f6b0edSMasatake YAMATO static EsObject *OPT_ERR_STOPPED;
106d8f6b0edSMasatake YAMATO EsObject *OPT_ERR_QUIT;
107d8f6b0edSMasatake YAMATO static EsObject *OPT_ERR_INVALIDACCESS;
108d8f6b0edSMasatake YAMATO static EsObject *OPT_ERR_INTOVERFLOW;
109d8f6b0edSMasatake YAMATO 
110d8f6b0edSMasatake YAMATO static EsObject* OPT_MARK_ARRAY;
111d8f6b0edSMasatake YAMATO static EsObject* OPT_MARK_DICT;
112d8f6b0edSMasatake YAMATO static EsObject* OPT_MARK_MARK;
113d8f6b0edSMasatake YAMATO 
114d8f6b0edSMasatake YAMATO static EsObject* OPT_KEY_newerror;
115d8f6b0edSMasatake YAMATO static EsObject* OPT_KEY_errorname;
116d8f6b0edSMasatake YAMATO static EsObject* OPT_KEY_command;
117d8f6b0edSMasatake YAMATO static EsObject* OPT_KEY_ostack;
118d8f6b0edSMasatake YAMATO static EsObject* OPT_KEY_estack;
119d8f6b0edSMasatake YAMATO static EsObject* OPT_KEY_dstack;
120d8f6b0edSMasatake YAMATO 
121d8f6b0edSMasatake YAMATO /* Naming conversions
122d8f6b0edSMasatake YAMATO  *
123d8f6b0edSMasatake YAMATO  * Opt|OPT
124d8f6b0edSMasatake YAMATO  * =====================================================================
125d8f6b0edSMasatake YAMATO  * exported as part of the library API
126d8f6b0edSMasatake YAMATO  *
127d8f6b0edSMasatake YAMATO  * optscript and ctags may refer these names.
128d8f6b0edSMasatake YAMATO  *
129d8f6b0edSMasatake YAMATO  *
130d8f6b0edSMasatake YAMATO  * <datatype>_...
131d8f6b0edSMasatake YAMATO  * =====================================================================
132d8f6b0edSMasatake YAMATO  * functions released to PS datatypes
133d8f6b0edSMasatake YAMATO  * PS datatypes are array, dict, operator, ...
134d8f6b0edSMasatake YAMATO  *
135d8f6b0edSMasatake YAMATO  * <datatype>_es_...
136d8f6b0edSMasatake YAMATO  * ---------------------------------------------------------------------
137d8f6b0edSMasatake YAMATO  * functions for representing the PS datatype object as EsObject object
138d8f6b0edSMasatake YAMATO  *
139d8f6b0edSMasatake YAMATO  * <datatype>_op_...
140d8f6b0edSMasatake YAMATO  * ---------------------------------------------------------------------
141d8f6b0edSMasatake YAMATO  * functions for accessing the datatype object from vm internal purpose
142d8f6b0edSMasatake YAMATO  *
143d8f6b0edSMasatake YAMATO  *
144d8f6b0edSMasatake YAMATO  * op_...<operator>
145d8f6b0edSMasatake YAMATO  * =====================================================================
146d8f6b0edSMasatake YAMATO  * functions implementing operators
147d8f6b0edSMasatake YAMATO  *
148d8f6b0edSMasatake YAMATO  *
149d8f6b0edSMasatake YAMATO  * vm_...
150d8f6b0edSMasatake YAMATO  * =====================================================================
151d8f6b0edSMasatake YAMATO  * the rest VM related functions
152d8f6b0edSMasatake YAMATO  *
153d8f6b0edSMasatake YAMATO  */
154d8f6b0edSMasatake YAMATO 
155d8f6b0edSMasatake YAMATO static EsObject* array_new (unsigned int attr);
156d8f6b0edSMasatake YAMATO 
157d8f6b0edSMasatake YAMATO static EsObject*    array_es_init_fat (void *fat, void *ptr, void *extra);
158d8f6b0edSMasatake YAMATO static void         array_es_free  (void *ptr, void *fat);
159d8f6b0edSMasatake YAMATO static int          array_es_equal (const void *a,
160d8f6b0edSMasatake YAMATO 									const void *afat,
161d8f6b0edSMasatake YAMATO 									const void *b,
162d8f6b0edSMasatake YAMATO 									const void *bfat);
163d8f6b0edSMasatake YAMATO static void         array_es_print (const void *ptr, const void *fat, MIO *out);
164d8f6b0edSMasatake YAMATO 
165d8f6b0edSMasatake YAMATO static void         array_op_add    (EsObject* array, EsObject* elt);
166d8f6b0edSMasatake YAMATO static unsigned int array_op_length (const EsObject* array);
167d8f6b0edSMasatake YAMATO static EsObject*    array_op_get    (const EsObject* array, unsigned int n);
168d8f6b0edSMasatake YAMATO static void         array_op_put    (EsObject* array, unsigned int n, EsObject *obj);
169d8f6b0edSMasatake YAMATO 
170d8f6b0edSMasatake YAMATO 
171d8f6b0edSMasatake YAMATO static EsObject* dict_new (unsigned int size, unsigned int attr);
172d8f6b0edSMasatake YAMATO 
173d8f6b0edSMasatake YAMATO static EsObject* dict_es_init_fat (void *fat, void *ptr, void *extra);
174d8f6b0edSMasatake YAMATO static void      dict_es_free  (void *ptr, void *fat);
175d8f6b0edSMasatake YAMATO static int       dict_es_equal (const void *a,
176d8f6b0edSMasatake YAMATO 								const void *afat,
177d8f6b0edSMasatake YAMATO 								const void *b,
178d8f6b0edSMasatake YAMATO 								const void *bfat);
179d8f6b0edSMasatake YAMATO static void      dict_es_print (const void *ptr, const void *fat, MIO *out);
180d8f6b0edSMasatake YAMATO 
181d8f6b0edSMasatake YAMATO 
182d8f6b0edSMasatake YAMATO static void      dict_op_def           (EsObject* dict, EsObject *key, EsObject *val);
183d8f6b0edSMasatake YAMATO static bool      dict_op_undef         (EsObject* dict, EsObject *key);
184d8f6b0edSMasatake YAMATO static bool      dict_op_known_and_get (EsObject* dict, EsObject *key, EsObject **val);
185d8f6b0edSMasatake YAMATO static void      dict_op_clear         (EsObject* dict);
186d8f6b0edSMasatake YAMATO 
187d8f6b0edSMasatake YAMATO 
188d8f6b0edSMasatake YAMATO static EsObject* operator_new (Operator op, const char *name, int arity, const char *help_str);
189d8f6b0edSMasatake YAMATO 
190d8f6b0edSMasatake YAMATO static EsObject* operator_es_init_fat (void *fat, void *ptr, void *extra);
191d8f6b0edSMasatake YAMATO static void      operator_es_print (const void *ptr, const void *fat, MIO *out);
192d8f6b0edSMasatake YAMATO static void      operator_es_free  (void *ptr, void *fat);
193d8f6b0edSMasatake YAMATO 
194d8f6b0edSMasatake YAMATO 
195d8f6b0edSMasatake YAMATO static EsObject* string_new   (vString *vstr);
196d8f6b0edSMasatake YAMATO 
197d8f6b0edSMasatake YAMATO static EsObject* string_es_init_fat (void *fat, void *ptr, void *extra);
198d8f6b0edSMasatake YAMATO static void      string_es_free  (void *ptr, void *fat);
199d8f6b0edSMasatake YAMATO static int       string_es_equal (const void *a,
200d8f6b0edSMasatake YAMATO 								  const void *afat,
201d8f6b0edSMasatake YAMATO 								  const void *b,
202d8f6b0edSMasatake YAMATO 								  const void *bfat);
203d8f6b0edSMasatake YAMATO static void      string_es_print (const void *ptr, const void *fat, MIO *out);
204d8f6b0edSMasatake YAMATO 
205d8f6b0edSMasatake YAMATO 
206d8f6b0edSMasatake YAMATO static EsObject* name_new     (EsObject* symbol, unsigned int attr);
207d8f6b0edSMasatake YAMATO static EsObject* name_newS    (const char*s, unsigned int attr);
208d8f6b0edSMasatake YAMATO static EsObject* name_newS_cb (const char*s, void *attr);
209d8f6b0edSMasatake YAMATO 
210d8f6b0edSMasatake YAMATO static EsObject* name_es_init_fat (void *fat, void *ptr, void *extra);
211d8f6b0edSMasatake YAMATO static void      name_es_print (const void *ptr, const void *fat, MIO *out);
212d8f6b0edSMasatake YAMATO static void      name_es_free  (void *ptr, void *fat);
213d8f6b0edSMasatake YAMATO static int       name_es_equal (const void *a,
214d8f6b0edSMasatake YAMATO 								const void *afat,
215d8f6b0edSMasatake YAMATO 								const void *b,
216d8f6b0edSMasatake YAMATO 								const void *bfat);
217d8f6b0edSMasatake YAMATO 
218d8f6b0edSMasatake YAMATO 
219d8f6b0edSMasatake YAMATO static EsObject* mark_new      (const char* mark);
220d8f6b0edSMasatake YAMATO 
221d8f6b0edSMasatake YAMATO static void      mark_es_print (const void *ptr, MIO *out);
222d8f6b0edSMasatake YAMATO static void      mark_es_free  (void *ptr);
223d8f6b0edSMasatake YAMATO static int       mark_es_equal (const void *a, const void *b);
224d8f6b0edSMasatake YAMATO 
225d8f6b0edSMasatake YAMATO static EsObject* vm_read          (OptVM *vm);
226d8f6b0edSMasatake YAMATO static EsObject* vm_call_operator (OptVM *vm, EsObject *op);
227d8f6b0edSMasatake YAMATO static EsObject* vm_call_proc     (OptVM *vm, EsObject *proc);
228d8f6b0edSMasatake YAMATO static void      vm_print         (OptVM *vm, EsObject *o);
229d8f6b0edSMasatake YAMATO static void      vm_print_full    (OptVM *vm, EsObject *o, bool string_as_is, int dict_recursion);
230d8f6b0edSMasatake YAMATO static void      vm_help          (OptVM *vm, MIO *out, struct OptHelpExtender *extop, void *data);
231d8f6b0edSMasatake YAMATO static void      vm_record_stop   (OptVM *vm, EsObject *cmd);
232d8f6b0edSMasatake YAMATO static void      vm_record_error  (OptVM *vm, EsObject *e, EsObject *cmd);
233d8f6b0edSMasatake YAMATO static void      vm_report_error  (OptVM *vm, EsObject *e);
234d8f6b0edSMasatake YAMATO static void      vm_bind_proc     (OptVM *vm, ptrArray *proc);
235d8f6b0edSMasatake YAMATO 
236d8f6b0edSMasatake YAMATO static void         vm_ostack_push        (OptVM *vm, EsObject *o);
237d8f6b0edSMasatake YAMATO static EsObject*    vm_ostack_pop         (OptVM *vm);
238d8f6b0edSMasatake YAMATO static unsigned int vm_ostack_count       (OptVM *vm);
239d8f6b0edSMasatake YAMATO static EsObject*    vm_ostack_top         (OptVM *vm);
240d8f6b0edSMasatake YAMATO static EsObject*    vm_ostack_peek        (OptVM *vm, int index_from_top);
241d8f6b0edSMasatake YAMATO static int          vm_ostack_counttomark (OptVM *vm);
242d8f6b0edSMasatake YAMATO 
243d8f6b0edSMasatake YAMATO static void         vm_dict_def           (OptVM *vm, EsObject *key, EsObject *val);
244d8f6b0edSMasatake YAMATO 
245d8f6b0edSMasatake YAMATO /* Returns the dictionary where the value for the key is found.
246d8f6b0edSMasatake YAMATO  * val can be NULL. */
247d8f6b0edSMasatake YAMATO static EsObject*    vm_dstack_known_and_get (OptVM *vm, EsObject *key, EsObject **val);
248d8f6b0edSMasatake YAMATO static void         vm_dstack_push          (OptVM *vm, EsObject *o);
249d8f6b0edSMasatake YAMATO /* FIXME: return type */
250d8f6b0edSMasatake YAMATO static int          vm_dstack_count         (OptVM *vm);
251d8f6b0edSMasatake YAMATO static EsObject*    vm_dstack_pop           (OptVM *vm);
252d8f6b0edSMasatake YAMATO static void         vm_dstack_clear         (OptVM *vm);
253d8f6b0edSMasatake YAMATO 
254d8f6b0edSMasatake YAMATO static EsObject*    vm_estack_push          (OptVM *vm, EsObject *p);
255d8f6b0edSMasatake YAMATO static EsObject*    vm_estack_pop           (OptVM *vm);
256d8f6b0edSMasatake YAMATO 
257d8f6b0edSMasatake YAMATO #define declop(OP)										\
258d8f6b0edSMasatake YAMATO 	static EsObject* op_##OP(OptVM *vm, EsObject *name)
259d8f6b0edSMasatake YAMATO 
260d8f6b0edSMasatake YAMATO 
261d8f6b0edSMasatake YAMATO #define defOP(DICT, FN, NAME, ARITY, HELP)								\
262d8f6b0edSMasatake YAMATO 	dict_op_def (DICT,													\
263d8f6b0edSMasatake YAMATO 				 es_object_autounref(es_symbol_intern (NAME)),			\
264d8f6b0edSMasatake YAMATO 				 es_object_autounref(operator_new (FN, NAME, ARITY, HELP)))
265d8f6b0edSMasatake YAMATO 
266d8f6b0edSMasatake YAMATO #define defop(DICT, NAME, ARITY, HELP)			\
267d8f6b0edSMasatake YAMATO 	defOP (DICT, op_##NAME, #NAME, ARITY, HELP)
268d8f6b0edSMasatake YAMATO 
269d8f6b0edSMasatake YAMATO static EsObject* op__print_objdict_rec (OptVM *vm, EsObject *name);
270d8f6b0edSMasatake YAMATO static EsObject* op__print_objdict     (OptVM *vm, EsObject *name);
271d8f6b0edSMasatake YAMATO static EsObject* op__print_object      (OptVM *vm, EsObject *name);
272d8f6b0edSMasatake YAMATO static EsObject* op__print             (OptVM *vm, EsObject *name);
273d8f6b0edSMasatake YAMATO static EsObject* op__make_array        (OptVM *vm, EsObject *name);
274d8f6b0edSMasatake YAMATO static EsObject* op__make_dict         (OptVM *vm, EsObject *name);
275d8f6b0edSMasatake YAMATO 
276d8f6b0edSMasatake YAMATO /* non-standard operator */
277d8f6b0edSMasatake YAMATO declop(_help);
278d8f6b0edSMasatake YAMATO 
279d8f6b0edSMasatake YAMATO /* tested in pstack.ps */
280d8f6b0edSMasatake YAMATO declop(pstack);
281d8f6b0edSMasatake YAMATO 
282d8f6b0edSMasatake YAMATO /* error related non-standard operators */
283d8f6b0edSMasatake YAMATO declop(_newerror);
284d8f6b0edSMasatake YAMATO declop(_errorname);
285d8f6b0edSMasatake YAMATO 
286d8f6b0edSMasatake YAMATO /* Operators for operand stack manipulation
287d8f6b0edSMasatake YAMATO  * tested in stack.ps */
288d8f6b0edSMasatake YAMATO declop(pop);
289d8f6b0edSMasatake YAMATO declop(exch);
290d8f6b0edSMasatake YAMATO declop(dup);
291d8f6b0edSMasatake YAMATO declop(index);
292d8f6b0edSMasatake YAMATO declop(roll);
293d8f6b0edSMasatake YAMATO declop(clear);
294d8f6b0edSMasatake YAMATO declop(count);
295d8f6b0edSMasatake YAMATO declop(mark);
296d8f6b0edSMasatake YAMATO declop(cleartomark);
297d8f6b0edSMasatake YAMATO declop(counttomark);
298d8f6b0edSMasatake YAMATO 
299d8f6b0edSMasatake YAMATO /* Arithmetic Operators
300d8f6b0edSMasatake YAMATO    tested in arithmetic.ps */
301d8f6b0edSMasatake YAMATO declop(add);
302d8f6b0edSMasatake YAMATO declop(idiv);
303d8f6b0edSMasatake YAMATO declop(mod);
304d8f6b0edSMasatake YAMATO declop(mul);
305d8f6b0edSMasatake YAMATO declop(sub);
306d8f6b0edSMasatake YAMATO declop(abs);
307d8f6b0edSMasatake YAMATO declop(neg);
308d8f6b0edSMasatake YAMATO 
309d8f6b0edSMasatake YAMATO /* Operators for array manipulation
310d8f6b0edSMasatake YAMATO    tested in array.ps */
311d8f6b0edSMasatake YAMATO declop(array);
312d8f6b0edSMasatake YAMATO declop(astore);
313d8f6b0edSMasatake YAMATO declop(aload);
314d8f6b0edSMasatake YAMATO 
315d8f6b0edSMasatake YAMATO /* Operators for dictionary manipulation
316d8f6b0edSMasatake YAMATO  * tested in dict.ps */
317d8f6b0edSMasatake YAMATO declop(dict);
318d8f6b0edSMasatake YAMATO declop(begin);
319d8f6b0edSMasatake YAMATO declop(end);
320d8f6b0edSMasatake YAMATO declop(def);
321d8f6b0edSMasatake YAMATO declop(load);
322d8f6b0edSMasatake YAMATO declop(undef);
323d8f6b0edSMasatake YAMATO declop(known);
324d8f6b0edSMasatake YAMATO declop(where);
325d8f6b0edSMasatake YAMATO declop(currentdict);
326d8f6b0edSMasatake YAMATO declop(countdictstack);
327d8f6b0edSMasatake YAMATO declop(store);
328d8f6b0edSMasatake YAMATO declop(dictstack);
329d8f6b0edSMasatake YAMATO declop(cleardictstack);
330d8f6b0edSMasatake YAMATO 
331d8f6b0edSMasatake YAMATO /* Operators for string manipulation
332d8f6b0edSMasatake YAMATO    tested in string.ps */
333d8f6b0edSMasatake YAMATO /* -anchorsearch, -search, -token */
334d8f6b0edSMasatake YAMATO declop(string);
335d8f6b0edSMasatake YAMATO declop(_strstr);
336d8f6b0edSMasatake YAMATO declop(_strrstr);
337d8f6b0edSMasatake YAMATO declop(_strchr);
338d8f6b0edSMasatake YAMATO declop(_strrchr);
339d8f6b0edSMasatake YAMATO declop(_strpbrk);
340d8f6b0edSMasatake YAMATO 
341d8f6b0edSMasatake YAMATO /* Relation, logical, and bit operators
342d8f6b0edSMasatake YAMATO    tested in relalogbit.ps */
343d8f6b0edSMasatake YAMATO declop(eq);
344d8f6b0edSMasatake YAMATO declop(ne);
345d8f6b0edSMasatake YAMATO declop(true);
346d8f6b0edSMasatake YAMATO declop(false);
347d8f6b0edSMasatake YAMATO declop(and);
348d8f6b0edSMasatake YAMATO declop(or);
349d8f6b0edSMasatake YAMATO declop(xor);
350d8f6b0edSMasatake YAMATO declop(not);
351d8f6b0edSMasatake YAMATO declop(bitshift);
352d8f6b0edSMasatake YAMATO declop(ge);
353d8f6b0edSMasatake YAMATO declop(gt);
354d8f6b0edSMasatake YAMATO declop(le);
355d8f6b0edSMasatake YAMATO declop(lt);
356d8f6b0edSMasatake YAMATO 
357d8f6b0edSMasatake YAMATO /* Operators for control flow
358d8f6b0edSMasatake YAMATO  * tested in control.ps */
359d8f6b0edSMasatake YAMATO declop(exec);
360d8f6b0edSMasatake YAMATO declop(if);
361d8f6b0edSMasatake YAMATO declop(ifelse);
362d8f6b0edSMasatake YAMATO declop(repeat);
363d8f6b0edSMasatake YAMATO declop(loop);
364d8f6b0edSMasatake YAMATO declop(exit);
365d8f6b0edSMasatake YAMATO declop(stop);
366d8f6b0edSMasatake YAMATO declop(stopped);
367d8f6b0edSMasatake YAMATO declop(for);
368d8f6b0edSMasatake YAMATO declop(quit);
369d8f6b0edSMasatake YAMATO declop(countexecstack);
370d8f6b0edSMasatake YAMATO declop(execstack);
371d8f6b0edSMasatake YAMATO /* ?start */
372d8f6b0edSMasatake YAMATO 
373d8f6b0edSMasatake YAMATO /* Operators for type, attribute and their conversion
374d8f6b0edSMasatake YAMATO  * tested in typeattrconv.ps */
375d8f6b0edSMasatake YAMATO declop(type);
376d8f6b0edSMasatake YAMATO declop(cvn);
377*6390fe9dSMasatake YAMATO declop(cvs);
378*6390fe9dSMasatake YAMATO 
379d8f6b0edSMasatake YAMATO /* cvlit, cvx, xcheck, executeonly, noacess, readonly,
380d8f6b0edSMasatake YAMATO    rcheck, wcheck, cvi, cvr, cvrs, cvs,... */
381d8f6b0edSMasatake YAMATO 
382d8f6b0edSMasatake YAMATO /* Operators for Virtual Memory Operators  */
383d8f6b0edSMasatake YAMATO /* ?save, ?restore */
384d8f6b0edSMasatake YAMATO 
385d8f6b0edSMasatake YAMATO /* Misc operators
386d8f6b0edSMasatake YAMATO  * tested in misc.ps */
387d8f6b0edSMasatake YAMATO declop(null);
388d8f6b0edSMasatake YAMATO declop(bind);
389d8f6b0edSMasatake YAMATO 
390d8f6b0edSMasatake YAMATO /* Methods for compound objects
391d8f6b0edSMasatake YAMATO    tested in compound.ps */
392d8f6b0edSMasatake YAMATO declop(length);
393d8f6b0edSMasatake YAMATO declop(copy);
394d8f6b0edSMasatake YAMATO declop(get);
395d8f6b0edSMasatake YAMATO declop(put);
396d8f6b0edSMasatake YAMATO declop(forall);
397d8f6b0edSMasatake YAMATO declop(putinterval);
398d8f6b0edSMasatake YAMATO declop(_copyinterval);
399d8f6b0edSMasatake YAMATO /* -getinterval .... */
400d8f6b0edSMasatake YAMATO 
401d8f6b0edSMasatake YAMATO 
402d8f6b0edSMasatake YAMATO /*
403d8f6b0edSMasatake YAMATO  * Public functions
404d8f6b0edSMasatake YAMATO  */
405d8f6b0edSMasatake YAMATO 
406d8f6b0edSMasatake YAMATO int
opt_init(void)407d8f6b0edSMasatake YAMATO opt_init (void)
408d8f6b0edSMasatake YAMATO {
409d8f6b0edSMasatake YAMATO 	OPT_TYPE_ARRAY    = es_type_define_fatptr ("arraytype",
410d8f6b0edSMasatake YAMATO 											   sizeof (ArrayFat),
411d8f6b0edSMasatake YAMATO 											   array_es_init_fat,
412d8f6b0edSMasatake YAMATO 											   array_es_free,
413d8f6b0edSMasatake YAMATO 											   array_es_equal,
414d8f6b0edSMasatake YAMATO 											   array_es_print);
415d8f6b0edSMasatake YAMATO 	OPT_TYPE_DICT     = es_type_define_fatptr ("dicttype",
416d8f6b0edSMasatake YAMATO 											   sizeof (DictFat),
417d8f6b0edSMasatake YAMATO 											   dict_es_init_fat,
418d8f6b0edSMasatake YAMATO 											   dict_es_free,
419d8f6b0edSMasatake YAMATO 											   dict_es_equal,
420d8f6b0edSMasatake YAMATO 											   dict_es_print);
421d8f6b0edSMasatake YAMATO 	OPT_TYPE_OPERATOR = es_type_define_fatptr ("operatortype",
422d8f6b0edSMasatake YAMATO 											   sizeof (OperatorFat),
423d8f6b0edSMasatake YAMATO 											   operator_es_init_fat,
424d8f6b0edSMasatake YAMATO 											   operator_es_free,
425d8f6b0edSMasatake YAMATO 											   NULL,
426d8f6b0edSMasatake YAMATO 											   operator_es_print);
427d8f6b0edSMasatake YAMATO 	OPT_TYPE_STRING   = es_type_define_fatptr ("stringtype",
428d8f6b0edSMasatake YAMATO 											   sizeof (StringFat),
429d8f6b0edSMasatake YAMATO 											   string_es_init_fat,
430d8f6b0edSMasatake YAMATO 											   string_es_free,
431d8f6b0edSMasatake YAMATO 											   string_es_equal,
432d8f6b0edSMasatake YAMATO 											   string_es_print);
433d8f6b0edSMasatake YAMATO 	OPT_TYPE_NAME     = es_type_define_fatptr ("nametype",
434d8f6b0edSMasatake YAMATO 											   sizeof (NameFat),
435d8f6b0edSMasatake YAMATO 											   name_es_init_fat,
436d8f6b0edSMasatake YAMATO 											   name_es_free,
437d8f6b0edSMasatake YAMATO 											   name_es_equal,
438d8f6b0edSMasatake YAMATO 											   name_es_print);
439d8f6b0edSMasatake YAMATO 	OPT_TYPE_MARK   = es_type_define_pointer ("marktype",
440d8f6b0edSMasatake YAMATO 											  mark_es_free,
441d8f6b0edSMasatake YAMATO 											  mark_es_equal,
442d8f6b0edSMasatake YAMATO 											  mark_es_print);
443d8f6b0edSMasatake YAMATO 
444d8f6b0edSMasatake YAMATO 	OPT_ERR_UNDEFINED          = es_error_intern ("undefined");
445d8f6b0edSMasatake YAMATO 	OPT_ERR_SYNTAX             = es_error_intern ("syntaxerror");
446d8f6b0edSMasatake YAMATO 	OPT_ERR_UNDERFLOW          = es_error_intern ("stackunderflow");
447d8f6b0edSMasatake YAMATO 	OPT_ERR_TYPECHECK          = es_error_intern ("typecheck");
448d8f6b0edSMasatake YAMATO 	OPT_ERR_RANGECHECK         = es_error_intern ("rangecheck");
449d8f6b0edSMasatake YAMATO 	OPT_ERR_DICTSTACKUNDERFLOW = es_error_intern ("dictstackunderflow");
450d8f6b0edSMasatake YAMATO 	OPT_ERR_UNMATCHEDMARK      = es_error_intern ("unmatchedmark");
451d8f6b0edSMasatake YAMATO 	OPT_ERR_INTERNALERROR      = es_error_intern ("internalerror");
452d8f6b0edSMasatake YAMATO 	OPT_ERR_END_PROC           = es_error_intern ("}");
453d8f6b0edSMasatake YAMATO 	OPT_ERR_INVALIDEXIT        = es_error_intern ("invalidexit");
454d8f6b0edSMasatake YAMATO 	OPT_ERR_STOPPED            = es_error_intern ("stopped");
455d8f6b0edSMasatake YAMATO 	OPT_ERR_QUIT               = es_error_intern ("quit");
456d8f6b0edSMasatake YAMATO 	OPT_ERR_INVALIDACCESS      = es_error_intern ("invalidaccess");
457d8f6b0edSMasatake YAMATO 	OPT_ERR_INTOVERFLOW        = es_error_intern ("intoverflow");
458d8f6b0edSMasatake YAMATO 
459d8f6b0edSMasatake YAMATO 	es_symbol_intern ("true");
460d8f6b0edSMasatake YAMATO 	es_symbol_intern ("false");
461d8f6b0edSMasatake YAMATO 	es_symbol_intern ("null");
462d8f6b0edSMasatake YAMATO 
463d8f6b0edSMasatake YAMATO 	OPT_MARK_ARRAY = mark_new ("[");
464d8f6b0edSMasatake YAMATO 	OPT_MARK_DICT  = mark_new ("<<");
465d8f6b0edSMasatake YAMATO 	OPT_MARK_MARK  = mark_new ("mark");
466d8f6b0edSMasatake YAMATO 
467d8f6b0edSMasatake YAMATO 	opt_system_dict = dict_new (101, ATTR_READABLE);
468d8f6b0edSMasatake YAMATO 
469d8f6b0edSMasatake YAMATO 	es_autounref_pool_push ();
470d8f6b0edSMasatake YAMATO 
471d8f6b0edSMasatake YAMATO 	defOP (opt_system_dict, op__print_objdict_rec,"====", 1,  "any === -");
472d8f6b0edSMasatake YAMATO 	defOP (opt_system_dict, op__print_objdict,    "===",  1,  "any === -");
473d8f6b0edSMasatake YAMATO 	defOP (opt_system_dict, op__print_object,     "==",   1,  "any == -");
474d8f6b0edSMasatake YAMATO 	defOP (opt_system_dict, op__print,            "=",    1,  "any == -");
475d8f6b0edSMasatake YAMATO 
476d8f6b0edSMasatake YAMATO 	defOP (opt_system_dict, op_mark,           "<<",  0,  "- << mark");
477d8f6b0edSMasatake YAMATO 	defOP (opt_system_dict, op_mark,           "[",   0,  "- [ mark");
478d8f6b0edSMasatake YAMATO 	defOP (opt_system_dict, op__make_array,    "]",   1,  "[ any1 ... anyn ] array");
479d8f6b0edSMasatake YAMATO 	defOP (opt_system_dict, op__make_dict ,    ">>",  1, "<< key1 value1 ... keyn valuen >> dict");
480d8f6b0edSMasatake YAMATO 
481d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, _help,  0, "- _HELP -");
482d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, pstack, 0, "|- any1 ... anyn PSTACK |- any1 ... anyn");
483d8f6b0edSMasatake YAMATO 
484d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, _newerror,  0, "- _NEWERROR bool");
485d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, _errorname, 0, "- _ERRORNAME error:name|null");
486d8f6b0edSMasatake YAMATO 
487d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, pop,    1, "any POP -");
488d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, exch,   2, "any1 any2 EXCH any2 any1");
489d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, dup,    1, "any DUP any any");
490d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, index,  1, "anyn ... any0 n INDEX anyn ... any0 anyn");
491d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, roll,   2, "any_n-1 ... any0 n j ROLL any_(j-1)_mod_n ... any_n-1 ... any_j_mod_n");
492d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, clear,  0, "|- any1 ... anyn CLEAR |-");
493d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, count,  0, "|- any1 ... anyn COUNT any1 ... anyn n");
494d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, mark,   0, "- MARK mark");
495d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, cleartomark, 1, "mark any1 ... anyn CLEARTOMARK -");
496d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, counttomark, 1, "mark any1 ... anyn COUNTTOMARK mark any1 ... anyn n");
497d8f6b0edSMasatake YAMATO 
498d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, add,  2, "int1 int2 ADD int");
499d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, idiv, 2, "int1 int2 IDIV int");
500d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, mod,  2, "int1 int1 MOD int");
501d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, mul,  2, "int1 int2 MUL int");
502d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, sub,  2, "int1 int2 SUB int");
503d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, abs,  1, "int1 ABS int2");
504d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, neg,  1, "int1 NEG int2");
505d8f6b0edSMasatake YAMATO 
506d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, array,  1, "int ARRAY array");
507d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, astore, 1, "any0 ... any_n_1 array ASTORE array");
508d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, aload,  1, "array ALOAD any0 ... any_n-1 array");
509d8f6b0edSMasatake YAMATO 
510d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, eq,       2, "any1 any2 EQ bool");
511d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, ne,       2, "any1 any2 NE bool");
512d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, true,     0, "- TRUE true");
513d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, false,    0, "- FALSE false");
514d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, ge,       2, "int1 int2 GE bool%"
515d8f6b0edSMasatake YAMATO 		   "string1 string2 GE bool");
516d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, gt,       2, "int1 int2 GT bool%"
517d8f6b0edSMasatake YAMATO 		   "string1 string2 GT bool");
518d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, le,       2, "int1 int2 LE bool%"
519d8f6b0edSMasatake YAMATO 		   "string1 string2 LE bool");
520d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, lt,       2, "int1 int2 LT bool%"
521d8f6b0edSMasatake YAMATO 		   "string1 string2 LT bool");
522d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, and,      2, "bool1 bool2 AND bool3%"
523d8f6b0edSMasatake YAMATO 		   "int1 int2 AND int3");
524d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, or,       2, "bool1 bool2 OR bool3%"
525d8f6b0edSMasatake YAMATO 		   "int1 int2 OR int3");
526d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, xor,      2, "bool1 bool2 XOR bool3%"
527d8f6b0edSMasatake YAMATO 		   "int1 int2 XOR int3");
528d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, not,      1, "bool1|int1 NOT bool2|int2");
529d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, bitshift, 2, "int1 shift BITSHIFT int2");
530d8f6b0edSMasatake YAMATO 
531d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, dict,           1, "int DICT dict");
532d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, begin,          1, "dict BEGIN -");
533d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, end,            0, "- END -");
534d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, def,            2, "key value DEF -");
535d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, load,           1, "key LOAD value");
536d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, undef,          2, "dict key UNDEF -");
537d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, known,          2, "dict key KNOWN bool");
538d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, where,          1, "key WHERE dict true%key WHERE false");
539d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, store,          2, "key value STORE -");
540d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, currentdict,    0, "- CURRENTDICT dict");
541d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, countdictstack, 0, "- COUNTDICTSTACK int");
542d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, dictstack,      1, "array DICTSTACK array");
543d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, cleardictstack, 0, "- CLEARDICTSTACK -");
544d8f6b0edSMasatake YAMATO 
545d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, string,   1, "int STRING -");
546d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, _strstr,  2, "string seek _STRSTR string offset true%"
547d8f6b0edSMasatake YAMATO 		   "string seek _STRSTR string false");
548d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, _strrstr, 2, "string seek _STRRSTR string offset true%"
549d8f6b0edSMasatake YAMATO 		   "string seek _STRRSTR string false");
550d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, _strchr,  2, "string chr _STRCHR string offset true%"
551d8f6b0edSMasatake YAMATO 		   "string chr _STRCHR string false");
552d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, _strrchr, 2, "string chr _STRRCHR string offset true%"
553d8f6b0edSMasatake YAMATO 		   "string chr _STRRCHR string false");
554d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, _strpbrk, 2, "string accept _STRPBRK string offset true%"
555d8f6b0edSMasatake YAMATO 		   "string accept _STRPBRK string false");
556d8f6b0edSMasatake YAMATO 
557d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, exec,           1, "any EXEC -");
558d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, if,             2, "bool proc IF -");
559d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, ifelse,         3, "bool proc_t proc_f IFELSE -");
560d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, repeat,         2, "int proc REPEAT -");
561d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, loop,           1, "proc LOOP -");
562d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, exit,           0, "- EXIT -");
563d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, stop,           0, "- STOP -");
564d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, stopped,        1, "any STOPPED bool");
565d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, for,            4, "initial increment limit proc FOR -");
566d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, quit,           0, "- quit -");
567d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, countexecstack, 0, "- countexecstack int");
568d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, execstack,      1, "array EXECSTACK array");
569d8f6b0edSMasatake YAMATO 
570d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, type,   1, "any TYPE name");
571d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, cvn,    1, "string CVN name");
572*6390fe9dSMasatake YAMATO 	defop (opt_system_dict, cvs,    2, "any string CVS string");
573d8f6b0edSMasatake YAMATO 
574d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, null,   0, "- NULL null");
575d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, bind,   1, "proc BIND proc");
576d8f6b0edSMasatake YAMATO 
577d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, copy,   1, "any1 ... anyn n COPY any1 ... anyn any1 ... anyn%"
578d8f6b0edSMasatake YAMATO 		   "array1 array2 COPY array2%"
579d8f6b0edSMasatake YAMATO 		   "dict1 dict2 COPY dict2%"
580d8f6b0edSMasatake YAMATO 		   "string1 string2 COPY string2");
581d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, length, 1, "array LENGTH int%"
582d8f6b0edSMasatake YAMATO 		   "dict LENGTH int%"
583d8f6b0edSMasatake YAMATO 		   "string LENGTH int");
584d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, get,    2, "array index GET any%"
585d8f6b0edSMasatake YAMATO 		   "dict key GET any%"
586d8f6b0edSMasatake YAMATO 		   "string int GET int");
587d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, put,    3, "array index any PUT -%"
588d8f6b0edSMasatake YAMATO 		   "dict key any PUT -%"
589d8f6b0edSMasatake YAMATO 		   "string index int PUT -");
590d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, forall, 2, "array proc FORALL -%"
591d8f6b0edSMasatake YAMATO 		   "dict proc FORALL -%"
592d8f6b0edSMasatake YAMATO 		   "string proc FORALL -");
593d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, putinterval, 3, "array1 index array2 PUTINTERVAL -%"
594d8f6b0edSMasatake YAMATO 		   "string1 index string2 PUTINTERVAL -");
595d8f6b0edSMasatake YAMATO 	defop (opt_system_dict, _copyinterval, 4, "array1 index count array2 _COPYINTERVAL array2%"
596d8f6b0edSMasatake YAMATO 		   "string1 index count string2 _COPYINTERVAL string2");
597d8f6b0edSMasatake YAMATO 
598d8f6b0edSMasatake YAMATO #define defKey(S) OPT_KEY_##S = es_symbol_intern(#S)
599d8f6b0edSMasatake YAMATO 	defKey(newerror);
600d8f6b0edSMasatake YAMATO 	defKey(errorname);
601d8f6b0edSMasatake YAMATO 	defKey(command);
602d8f6b0edSMasatake YAMATO 	defKey(ostack);
603d8f6b0edSMasatake YAMATO 	defKey(estack);
604d8f6b0edSMasatake YAMATO 	defKey(dstack);
605d8f6b0edSMasatake YAMATO 
606d8f6b0edSMasatake YAMATO 	es_autounref_pool_pop ();
607d8f6b0edSMasatake YAMATO 
608d8f6b0edSMasatake YAMATO 	return 0;
609d8f6b0edSMasatake YAMATO }
610d8f6b0edSMasatake YAMATO 
611d8f6b0edSMasatake YAMATO OptVM *
opt_vm_new(MIO * in,MIO * out,MIO * err)612d8f6b0edSMasatake YAMATO opt_vm_new (MIO *in, MIO *out, MIO *err)
613d8f6b0edSMasatake YAMATO {
614d8f6b0edSMasatake YAMATO 	OptVM *vm = xCalloc (1, OptVM);
615d8f6b0edSMasatake YAMATO 
616d8f6b0edSMasatake YAMATO 	vm->in    = mio_ref (in);
617d8f6b0edSMasatake YAMATO 	vm->out   = mio_ref (out);
618d8f6b0edSMasatake YAMATO 	vm->err   = mio_ref (err);
619d8f6b0edSMasatake YAMATO 
620d8f6b0edSMasatake YAMATO 	EsObject *tmp;
621d8f6b0edSMasatake YAMATO 
622d8f6b0edSMasatake YAMATO 	tmp = array_new (0);
623d8f6b0edSMasatake YAMATO 	vm->ostack = (ptrArray *)es_pointer_take (tmp);
624d8f6b0edSMasatake YAMATO 	es_object_unref (tmp);
625d8f6b0edSMasatake YAMATO 
626d8f6b0edSMasatake YAMATO 	tmp = array_new (0);
627d8f6b0edSMasatake YAMATO 	vm->dstack = (ptrArray *)es_pointer_take (tmp);
628d8f6b0edSMasatake YAMATO 	es_object_unref (tmp);
629d8f6b0edSMasatake YAMATO 
630d8f6b0edSMasatake YAMATO 	tmp = array_new (0);
631d8f6b0edSMasatake YAMATO 	vm->estack = (ptrArray *)es_pointer_take (tmp);
632d8f6b0edSMasatake YAMATO 	es_object_unref (tmp);
633d8f6b0edSMasatake YAMATO 
634d8f6b0edSMasatake YAMATO 	vm->dstack_protection = 0;
635d8f6b0edSMasatake YAMATO 	vm_dstack_push (vm, opt_system_dict);
636d8f6b0edSMasatake YAMATO 	vm->dstack_protection++;
637d8f6b0edSMasatake YAMATO 
638d8f6b0edSMasatake YAMATO 	vm->error = dict_new (6, ATTR_READABLE|ATTR_WRITABLE);
639d8f6b0edSMasatake YAMATO 
640d8f6b0edSMasatake YAMATO 	vm->print_depth = 0;
641d8f6b0edSMasatake YAMATO 	vm->read_depth = 0;
642d8f6b0edSMasatake YAMATO 	vm->prompt = NULL;
643d8f6b0edSMasatake YAMATO 
644d8f6b0edSMasatake YAMATO 	return vm;
645d8f6b0edSMasatake YAMATO }
646d8f6b0edSMasatake YAMATO 
647d8f6b0edSMasatake YAMATO void
opt_vm_clear(OptVM * vm)648d8f6b0edSMasatake YAMATO opt_vm_clear (OptVM *vm)
649d8f6b0edSMasatake YAMATO {
650d8f6b0edSMasatake YAMATO 	ptrArrayClear  (vm->estack);
651d8f6b0edSMasatake YAMATO 	ptrArrayClear  (vm->ostack);
652d8f6b0edSMasatake YAMATO 	vm_dstack_clear (vm);
653d8f6b0edSMasatake YAMATO 	vm->app_data = NULL;
654d8f6b0edSMasatake YAMATO 	dict_op_clear (vm->error);
655d8f6b0edSMasatake YAMATO }
656d8f6b0edSMasatake YAMATO 
657d8f6b0edSMasatake YAMATO void
opt_vm_delete(OptVM * vm)658d8f6b0edSMasatake YAMATO opt_vm_delete (OptVM *vm)
659d8f6b0edSMasatake YAMATO {
660d8f6b0edSMasatake YAMATO 	ptrArrayDelete  (vm->estack);
661d8f6b0edSMasatake YAMATO 	ptrArrayDelete (vm->dstack);
662d8f6b0edSMasatake YAMATO 	ptrArrayDelete  (vm->ostack);
663d8f6b0edSMasatake YAMATO 	es_object_unref (vm->error);
664d8f6b0edSMasatake YAMATO 
665d8f6b0edSMasatake YAMATO 	mio_unref (vm->err);
666d8f6b0edSMasatake YAMATO 	mio_unref (vm->out);
667d8f6b0edSMasatake YAMATO 	mio_unref (vm->in);
668d8f6b0edSMasatake YAMATO 	eFree (vm);
669d8f6b0edSMasatake YAMATO }
670d8f6b0edSMasatake YAMATO 
671d8f6b0edSMasatake YAMATO EsObject *
opt_dict_new(unsigned int size)672d8f6b0edSMasatake YAMATO opt_dict_new (unsigned int size)
673d8f6b0edSMasatake YAMATO {
674d8f6b0edSMasatake YAMATO 	return dict_new (size, ATTR_READABLE|ATTR_WRITABLE);
675d8f6b0edSMasatake YAMATO }
676d8f6b0edSMasatake YAMATO 
677d8f6b0edSMasatake YAMATO bool
opt_dict_known_and_get_cstr(EsObject * dict,const char * name,EsObject ** val)678d8f6b0edSMasatake YAMATO opt_dict_known_and_get_cstr (EsObject *dict, const char* name, EsObject **val)
679d8f6b0edSMasatake YAMATO {
680d8f6b0edSMasatake YAMATO 	if (es_object_get_type (dict) != OPT_TYPE_DICT)
681d8f6b0edSMasatake YAMATO 		return false;
682d8f6b0edSMasatake YAMATO 
683d8f6b0edSMasatake YAMATO 	EsObject *sym = es_symbol_intern (name);
684d8f6b0edSMasatake YAMATO 	return dict_op_known_and_get (dict, sym, val);
685d8f6b0edSMasatake YAMATO }
686d8f6b0edSMasatake YAMATO 
687d8f6b0edSMasatake YAMATO bool
opt_dict_foreach(EsObject * dict,bool (* fn)(EsObject *,EsObject *,void *),void * data)688d8f6b0edSMasatake YAMATO opt_dict_foreach (EsObject *dict, bool (* fn) (EsObject *, EsObject *, void*), void *data)
689d8f6b0edSMasatake YAMATO {
690d8f6b0edSMasatake YAMATO 	if (es_object_get_type (dict) != OPT_TYPE_DICT)
691d8f6b0edSMasatake YAMATO 		return false;
692d8f6b0edSMasatake YAMATO 
693d8f6b0edSMasatake YAMATO 	hashTable *htable = es_pointer_get (dict);
694d8f6b0edSMasatake YAMATO 	return hashTableForeachItem (htable, (hashTableForeachFunc) fn, data);
695d8f6b0edSMasatake YAMATO }
696d8f6b0edSMasatake YAMATO 
697d8f6b0edSMasatake YAMATO void
opt_dict_def(EsObject * dict,EsObject * sym,EsObject * val)698d8f6b0edSMasatake YAMATO opt_dict_def (EsObject *dict, EsObject *sym, EsObject *val)
699d8f6b0edSMasatake YAMATO {
700d8f6b0edSMasatake YAMATO 	Assert (!es_null(sym));
701d8f6b0edSMasatake YAMATO 	dict_op_def (dict, sym, val);
702d8f6b0edSMasatake YAMATO }
703d8f6b0edSMasatake YAMATO 
704d8f6b0edSMasatake YAMATO bool
opt_dict_undef(EsObject * dict,EsObject * sym)705d8f6b0edSMasatake YAMATO opt_dict_undef (EsObject *dict, EsObject *sym)
706d8f6b0edSMasatake YAMATO {
707d8f6b0edSMasatake YAMATO 	Assert (!es_null(sym));
708d8f6b0edSMasatake YAMATO 	return dict_op_undef (dict, sym);
709d8f6b0edSMasatake YAMATO }
710d8f6b0edSMasatake YAMATO 
711d8f6b0edSMasatake YAMATO void
opt_dict_clear(EsObject * dict)712d8f6b0edSMasatake YAMATO opt_dict_clear (EsObject *dict)
713d8f6b0edSMasatake YAMATO {
714d8f6b0edSMasatake YAMATO 	Assert (es_object_get_type (dict) == OPT_TYPE_DICT);
715d8f6b0edSMasatake YAMATO 	dict_op_clear (dict);
716d8f6b0edSMasatake YAMATO }
717d8f6b0edSMasatake YAMATO 
718d8f6b0edSMasatake YAMATO EsObject *
opt_array_new(void)719d8f6b0edSMasatake YAMATO opt_array_new (void)
720d8f6b0edSMasatake YAMATO {
721d8f6b0edSMasatake YAMATO 	return array_new (ATTR_READABLE | ATTR_WRITABLE);
722d8f6b0edSMasatake YAMATO }
723d8f6b0edSMasatake YAMATO 
724d8f6b0edSMasatake YAMATO EsObject *
opt_array_get(const EsObject * array,unsigned int index)725d8f6b0edSMasatake YAMATO opt_array_get (const EsObject *array, unsigned int index)
726d8f6b0edSMasatake YAMATO {
727d8f6b0edSMasatake YAMATO 	return array_op_get (array, index);
728d8f6b0edSMasatake YAMATO }
729d8f6b0edSMasatake YAMATO 
730d8f6b0edSMasatake YAMATO void
opt_array_put(EsObject * array,unsigned int index,EsObject * obj)731d8f6b0edSMasatake YAMATO opt_array_put (EsObject *array, unsigned int index, EsObject *obj)
732d8f6b0edSMasatake YAMATO {
733d8f6b0edSMasatake YAMATO 	array_op_put (array, index, obj);
734d8f6b0edSMasatake YAMATO }
735d8f6b0edSMasatake YAMATO 
7368cfef1a8SMasatake YAMATO void
opt_array_add(EsObject * array,EsObject * elt)7378cfef1a8SMasatake YAMATO opt_array_add (EsObject *array, EsObject* elt)
7388cfef1a8SMasatake YAMATO {
7398cfef1a8SMasatake YAMATO 	array_op_add (array, elt);
7408cfef1a8SMasatake YAMATO }
7418cfef1a8SMasatake YAMATO 
742d8f6b0edSMasatake YAMATO unsigned int
opt_array_length(const EsObject * array)743d8f6b0edSMasatake YAMATO opt_array_length(const EsObject *array)
744d8f6b0edSMasatake YAMATO {
745d8f6b0edSMasatake YAMATO 	return array_op_length (array);
746d8f6b0edSMasatake YAMATO }
747d8f6b0edSMasatake YAMATO 
748d8f6b0edSMasatake YAMATO void
opt_vm_dstack_push(OptVM * vm,EsObject * dict)749d8f6b0edSMasatake YAMATO opt_vm_dstack_push  (OptVM *vm, EsObject *dict)
750d8f6b0edSMasatake YAMATO {
751d8f6b0edSMasatake YAMATO 	vm_dstack_push (vm, dict);
752d8f6b0edSMasatake YAMATO 	vm->dstack_protection++;
753d8f6b0edSMasatake YAMATO }
754d8f6b0edSMasatake YAMATO 
755d8f6b0edSMasatake YAMATO void
opt_vm_dstack_pop(OptVM * vm)756d8f6b0edSMasatake YAMATO opt_vm_dstack_pop  (OptVM *vm)
757d8f6b0edSMasatake YAMATO {
758d8f6b0edSMasatake YAMATO 	vm->dstack_protection--;
759d8f6b0edSMasatake YAMATO 	vm_dstack_pop (vm);
760d8f6b0edSMasatake YAMATO }
761d8f6b0edSMasatake YAMATO 
762d8f6b0edSMasatake YAMATO EsObject*
opt_vm_ostack_top(OptVM * vm)763d8f6b0edSMasatake YAMATO opt_vm_ostack_top (OptVM *vm)
764d8f6b0edSMasatake YAMATO {
765d8f6b0edSMasatake YAMATO 	return vm_ostack_top (vm);
766d8f6b0edSMasatake YAMATO }
767d8f6b0edSMasatake YAMATO 
768d8f6b0edSMasatake YAMATO EsObject*
opt_vm_ostack_peek(OptVM * vm,int index_from_top)769d8f6b0edSMasatake YAMATO opt_vm_ostack_peek (OptVM *vm, int index_from_top)
770d8f6b0edSMasatake YAMATO {
771d8f6b0edSMasatake YAMATO 	return vm_ostack_peek (vm, index_from_top);
772d8f6b0edSMasatake YAMATO }
773d8f6b0edSMasatake YAMATO 
774d8f6b0edSMasatake YAMATO EsObject*
opt_vm_ostack_pop(OptVM * vm)775d8f6b0edSMasatake YAMATO opt_vm_ostack_pop (OptVM *vm)
776d8f6b0edSMasatake YAMATO {
777d8f6b0edSMasatake YAMATO 	return vm_ostack_pop (vm);
778d8f6b0edSMasatake YAMATO }
779d8f6b0edSMasatake YAMATO 
780d8f6b0edSMasatake YAMATO void
opt_vm_ostack_push(OptVM * vm,EsObject * obj)781d8f6b0edSMasatake YAMATO opt_vm_ostack_push        (OptVM *vm, EsObject *obj)
782d8f6b0edSMasatake YAMATO {
783d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, obj);
784d8f6b0edSMasatake YAMATO }
785d8f6b0edSMasatake YAMATO 
786d8f6b0edSMasatake YAMATO unsigned int
opt_vm_ostack_count(OptVM * vm)787d8f6b0edSMasatake YAMATO opt_vm_ostack_count (OptVM *vm)
788d8f6b0edSMasatake YAMATO {
789d8f6b0edSMasatake YAMATO 	return vm_ostack_count (vm);
790d8f6b0edSMasatake YAMATO }
791d8f6b0edSMasatake YAMATO 
792d8f6b0edSMasatake YAMATO static EsObject*
vm_eval(OptVM * vm,EsObject * o)793d8f6b0edSMasatake YAMATO vm_eval (OptVM *vm, EsObject * o)
794d8f6b0edSMasatake YAMATO {
795d8f6b0edSMasatake YAMATO 	EsObject *r = es_false;
796d8f6b0edSMasatake YAMATO 
797d8f6b0edSMasatake YAMATO 	if (es_error_p (o))
798d8f6b0edSMasatake YAMATO 	{
799d8f6b0edSMasatake YAMATO 		r = o;
800d8f6b0edSMasatake YAMATO 		goto out;
801d8f6b0edSMasatake YAMATO 	}
802d8f6b0edSMasatake YAMATO 	else if (es_object_get_type (o) == OPT_TYPE_NAME)
803d8f6b0edSMasatake YAMATO 	{
804d8f6b0edSMasatake YAMATO 		unsigned int attr = ((NameFat *)es_fatptr_get (o))->attr;
805d8f6b0edSMasatake YAMATO 		if (attr & ATTR_EXECUTABLE)
806d8f6b0edSMasatake YAMATO 		{
807d8f6b0edSMasatake YAMATO 			EsObject *sym = es_pointer_get (o);
808d8f6b0edSMasatake YAMATO 			EsObject *val  = es_nil;
809d8f6b0edSMasatake YAMATO 			EsObject *dict = vm_dstack_known_and_get (vm, sym, &val);
810d8f6b0edSMasatake YAMATO 
811d8f6b0edSMasatake YAMATO 			if (es_object_get_type (dict) == OPT_TYPE_DICT)
812d8f6b0edSMasatake YAMATO 			{
813d8f6b0edSMasatake YAMATO 				int t = es_object_get_type (val);
814d8f6b0edSMasatake YAMATO 				if (t == OPT_TYPE_OPERATOR)
815d8f6b0edSMasatake YAMATO 					r = vm_call_operator (vm, val);
816d8f6b0edSMasatake YAMATO 				else if (t == OPT_TYPE_ARRAY
817d8f6b0edSMasatake YAMATO 						 && (((ArrayFat *)es_fatptr_get (val))->attr & ATTR_EXECUTABLE))
818d8f6b0edSMasatake YAMATO 					r = vm_call_proc (vm, val);
819d8f6b0edSMasatake YAMATO 				else
820d8f6b0edSMasatake YAMATO 				{
821d8f6b0edSMasatake YAMATO 					vm_ostack_push (vm, val);
822d8f6b0edSMasatake YAMATO 					r = es_false;
823d8f6b0edSMasatake YAMATO 				}
824d8f6b0edSMasatake YAMATO 
825d8f6b0edSMasatake YAMATO 				if (es_error_p (r))
826d8f6b0edSMasatake YAMATO 					goto out;
827d8f6b0edSMasatake YAMATO 			}
828d8f6b0edSMasatake YAMATO 			else
829d8f6b0edSMasatake YAMATO 			{
830d8f6b0edSMasatake YAMATO 				r = es_error_set_object (OPT_ERR_UNDEFINED, o);
831d8f6b0edSMasatake YAMATO 				vm_record_error (vm, r, o); /* TODO */
832d8f6b0edSMasatake YAMATO 				goto out;
833d8f6b0edSMasatake YAMATO 			}
834d8f6b0edSMasatake YAMATO 		}
835d8f6b0edSMasatake YAMATO 		else
836d8f6b0edSMasatake YAMATO 			vm_ostack_push (vm, o);
837d8f6b0edSMasatake YAMATO 	}
838d8f6b0edSMasatake YAMATO 	else if (es_object_get_type (o) == OPT_TYPE_OPERATOR)
839d8f6b0edSMasatake YAMATO 	{
840d8f6b0edSMasatake YAMATO 		r = vm_call_operator (vm, o);
841d8f6b0edSMasatake YAMATO 		goto out;
842d8f6b0edSMasatake YAMATO 	}
843d8f6b0edSMasatake YAMATO 	else
844d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, o);
845d8f6b0edSMasatake YAMATO  out:
846d8f6b0edSMasatake YAMATO 	return r;
847d8f6b0edSMasatake YAMATO }
848d8f6b0edSMasatake YAMATO 
849d8f6b0edSMasatake YAMATO EsObject*
opt_vm_read(OptVM * vm,MIO * in)850d8f6b0edSMasatake YAMATO opt_vm_read (OptVM *vm, MIO *in)
851d8f6b0edSMasatake YAMATO {
852d8f6b0edSMasatake YAMATO 	EsObject *e;
853d8f6b0edSMasatake YAMATO 	MIO *tmp;
854d8f6b0edSMasatake YAMATO 	if (in)
855d8f6b0edSMasatake YAMATO 	{
856d8f6b0edSMasatake YAMATO 		tmp = vm->in;
857d8f6b0edSMasatake YAMATO 		vm->in = in;
858d8f6b0edSMasatake YAMATO 	}
859d8f6b0edSMasatake YAMATO 	e = vm_read (vm);
860d8f6b0edSMasatake YAMATO 	if (in)
861d8f6b0edSMasatake YAMATO 		vm->in = tmp;
862d8f6b0edSMasatake YAMATO 	return e;
863d8f6b0edSMasatake YAMATO }
864d8f6b0edSMasatake YAMATO 
865d8f6b0edSMasatake YAMATO EsObject *
opt_vm_eval(OptVM * vm,EsObject * obj)866d8f6b0edSMasatake YAMATO opt_vm_eval (OptVM *vm, EsObject *obj)
867d8f6b0edSMasatake YAMATO {
868d8f6b0edSMasatake YAMATO 	return vm_eval (vm, obj);
869d8f6b0edSMasatake YAMATO }
870d8f6b0edSMasatake YAMATO 
871d8f6b0edSMasatake YAMATO void
opt_vm_report_error(OptVM * vm,EsObject * eobj,MIO * err)872d8f6b0edSMasatake YAMATO opt_vm_report_error (OptVM *vm, EsObject *eobj, MIO *err)
873d8f6b0edSMasatake YAMATO {
874d8f6b0edSMasatake YAMATO 	MIO *tmp;
875d8f6b0edSMasatake YAMATO 
876d8f6b0edSMasatake YAMATO 	if (err)
877d8f6b0edSMasatake YAMATO 	{
878d8f6b0edSMasatake YAMATO 		tmp = vm->err;
879d8f6b0edSMasatake YAMATO 		vm->err = err;
880d8f6b0edSMasatake YAMATO 	}
881d8f6b0edSMasatake YAMATO 	vm_report_error	(vm, eobj);
882d8f6b0edSMasatake YAMATO 	if (err)
883d8f6b0edSMasatake YAMATO 		vm->err = tmp;
884d8f6b0edSMasatake YAMATO }
885d8f6b0edSMasatake YAMATO 
886d8f6b0edSMasatake YAMATO char*
opt_vm_set_prompt(OptVM * vm,char * prompt)887d8f6b0edSMasatake YAMATO opt_vm_set_prompt (OptVM *vm, char *prompt)
888d8f6b0edSMasatake YAMATO {
889d8f6b0edSMasatake YAMATO 	char *tmp = vm->prompt;
890d8f6b0edSMasatake YAMATO 	vm->prompt = prompt;
891d8f6b0edSMasatake YAMATO 	return tmp;
892d8f6b0edSMasatake YAMATO }
893d8f6b0edSMasatake YAMATO 
894d8f6b0edSMasatake YAMATO void
opt_vm_print_prompt(OptVM * vm)895d8f6b0edSMasatake YAMATO opt_vm_print_prompt   (OptVM *vm)
896d8f6b0edSMasatake YAMATO {
897d8f6b0edSMasatake YAMATO 	if (vm->prompt && vm->read_depth == 0)
898d8f6b0edSMasatake YAMATO 	{
899d8f6b0edSMasatake YAMATO 		mio_puts (vm->err, vm->prompt);
900d8f6b0edSMasatake YAMATO 		unsigned int c = ptrArrayCount (vm->ostack);
901d8f6b0edSMasatake YAMATO 
902d8f6b0edSMasatake YAMATO 		if (c > 0)
903d8f6b0edSMasatake YAMATO 			mio_printf (vm->err, "<%u> ", c);
904d8f6b0edSMasatake YAMATO 		else
905d8f6b0edSMasatake YAMATO 			mio_printf (vm->err, "> ");
906d8f6b0edSMasatake YAMATO 	}
907d8f6b0edSMasatake YAMATO }
908d8f6b0edSMasatake YAMATO 
909d8f6b0edSMasatake YAMATO void*
opt_vm_get_app_data(OptVM * vm)910d8f6b0edSMasatake YAMATO opt_vm_get_app_data (OptVM *vm)
911d8f6b0edSMasatake YAMATO {
912d8f6b0edSMasatake YAMATO 	return vm->app_data;
913d8f6b0edSMasatake YAMATO }
914d8f6b0edSMasatake YAMATO 
915d8f6b0edSMasatake YAMATO void*
opt_vm_set_app_data(OptVM * vm,void * app_data)916d8f6b0edSMasatake YAMATO opt_vm_set_app_data (OptVM *vm, void *app_data)
917d8f6b0edSMasatake YAMATO {
918d8f6b0edSMasatake YAMATO 	void *tmp = vm->app_data;
919d8f6b0edSMasatake YAMATO 	vm->app_data = app_data;
920d8f6b0edSMasatake YAMATO 	return tmp;
921d8f6b0edSMasatake YAMATO }
922d8f6b0edSMasatake YAMATO 
923d8f6b0edSMasatake YAMATO int
opt_vm_help(OptVM * vm,MIO * out,struct OptHelpExtender * extop,void * data)924d8f6b0edSMasatake YAMATO opt_vm_help    (OptVM *vm, MIO *out, struct OptHelpExtender *extop, void *data)
925d8f6b0edSMasatake YAMATO {
926d8f6b0edSMasatake YAMATO 	vm_help (vm, out? out: vm->out, extop, data);
927d8f6b0edSMasatake YAMATO 	return 0;
928d8f6b0edSMasatake YAMATO }
929d8f6b0edSMasatake YAMATO 
930d8f6b0edSMasatake YAMATO EsObject *
opt_operator_new(OptOperatorFn op,const char * name,int arity,const char * help_str)931d8f6b0edSMasatake YAMATO opt_operator_new (OptOperatorFn op, const char *name, int arity, const char *help_str)
932d8f6b0edSMasatake YAMATO {
933d8f6b0edSMasatake YAMATO 	return operator_new (op, name, arity, help_str);
934d8f6b0edSMasatake YAMATO }
935d8f6b0edSMasatake YAMATO 
opt_string_new_from_cstr(const char * cstr)936d8f6b0edSMasatake YAMATO EsObject *opt_string_new_from_cstr     (const char *cstr)
937d8f6b0edSMasatake YAMATO {
938d8f6b0edSMasatake YAMATO 	vString *vstr = vStringNewInit (cstr? cstr: "");
939d8f6b0edSMasatake YAMATO 	return string_new (vstr);
940d8f6b0edSMasatake YAMATO }
941d8f6b0edSMasatake YAMATO 
opt_string_get_cstr(const EsObject * str)942d8f6b0edSMasatake YAMATO const char* opt_string_get_cstr (const EsObject *str)
943d8f6b0edSMasatake YAMATO {
944d8f6b0edSMasatake YAMATO 	vString *vstr = es_pointer_get (str);
945d8f6b0edSMasatake YAMATO 	return vStringValue (vstr);
946d8f6b0edSMasatake YAMATO }
947d8f6b0edSMasatake YAMATO 
opt_name_new_from_cstr(const char * cstr)948d8f6b0edSMasatake YAMATO EsObject *opt_name_new_from_cstr (const char *cstr)
949d8f6b0edSMasatake YAMATO {
950d8f6b0edSMasatake YAMATO 	return name_newS (cstr, ATTR_READABLE);
951d8f6b0edSMasatake YAMATO }
952d8f6b0edSMasatake YAMATO 
opt_name_get_cstr(const EsObject * name)953d8f6b0edSMasatake YAMATO const char* opt_name_get_cstr (const EsObject *name)
954d8f6b0edSMasatake YAMATO {
955d8f6b0edSMasatake YAMATO 	if (es_object_get_type (name) == OPT_TYPE_NAME)
956d8f6b0edSMasatake YAMATO 		name = es_pointer_get (name);
957d8f6b0edSMasatake YAMATO 	if (!es_symbol_p (name))
958d8f6b0edSMasatake YAMATO 		return NULL;
959d8f6b0edSMasatake YAMATO 	return es_symbol_get (name);
960d8f6b0edSMasatake YAMATO }
961d8f6b0edSMasatake YAMATO 
962d8f6b0edSMasatake YAMATO 
963d8f6b0edSMasatake YAMATO /*
964d8f6b0edSMasatake YAMATO  * VM
965d8f6b0edSMasatake YAMATO  */
966d8f6b0edSMasatake YAMATO static void
vm_read_skip_comment(OptVM * vm)967d8f6b0edSMasatake YAMATO vm_read_skip_comment(OptVM *vm)
968d8f6b0edSMasatake YAMATO {
969d8f6b0edSMasatake YAMATO 	while (true)
970d8f6b0edSMasatake YAMATO 	{
971d8f6b0edSMasatake YAMATO 		int c = mio_getc (vm->in);
972d8f6b0edSMasatake YAMATO 		if (c == EOF || c == '\n' || c == '\r')
973d8f6b0edSMasatake YAMATO 		{
974d8f6b0edSMasatake YAMATO 			if (c != EOF)
975d8f6b0edSMasatake YAMATO 				opt_vm_print_prompt (vm);
976d8f6b0edSMasatake YAMATO 			return;
977d8f6b0edSMasatake YAMATO 		}
978d8f6b0edSMasatake YAMATO 	}
979d8f6b0edSMasatake YAMATO }
980d8f6b0edSMasatake YAMATO 
9813773fd94SMasatake YAMATO #define is_meta_char(c) ((c) == '%'				\
9823773fd94SMasatake YAMATO 						 || (c) == '/'			\
9833773fd94SMasatake YAMATO 						 || (c) == '('			\
9843773fd94SMasatake YAMATO 						 || (c) == '{'			\
9853773fd94SMasatake YAMATO 						 || (c) == '}'			\
9863773fd94SMasatake YAMATO 						 || (c) == '['			\
9873773fd94SMasatake YAMATO 						 || (c) == ']'			\
9883773fd94SMasatake YAMATO 						 || (c) == '<'			\
9893773fd94SMasatake YAMATO 						 || (c) == '>')
9903773fd94SMasatake YAMATO 
991d8f6b0edSMasatake YAMATO static EsObject*
vm_read_char(OptVM * vm)992d8f6b0edSMasatake YAMATO vm_read_char (OptVM *vm)
993d8f6b0edSMasatake YAMATO {
994d8f6b0edSMasatake YAMATO 	int c = mio_getc (vm->in);
995d8f6b0edSMasatake YAMATO 	int i;
996d8f6b0edSMasatake YAMATO 
997d8f6b0edSMasatake YAMATO 	if (c == EOF)
998d8f6b0edSMasatake YAMATO 		return OPT_ERR_SYNTAX;
999d8f6b0edSMasatake YAMATO 	else if (c == '\\')
1000d8f6b0edSMasatake YAMATO 	{
1001d8f6b0edSMasatake YAMATO 		c = mio_getc (vm->in);
1002d8f6b0edSMasatake YAMATO 		int i;
1003d8f6b0edSMasatake YAMATO 		switch (c)
1004d8f6b0edSMasatake YAMATO 		{
1005d8f6b0edSMasatake YAMATO 		case 't':
1006d8f6b0edSMasatake YAMATO 			i = '\t';
1007d8f6b0edSMasatake YAMATO 			break;
1008d8f6b0edSMasatake YAMATO 		case 'n':
1009d8f6b0edSMasatake YAMATO 			i = '\n';
1010d8f6b0edSMasatake YAMATO 			break;
1011d8f6b0edSMasatake YAMATO 		case 'f':
1012d8f6b0edSMasatake YAMATO 			i = '\f';
1013d8f6b0edSMasatake YAMATO 			break;
1014d8f6b0edSMasatake YAMATO 		case 'r':
1015d8f6b0edSMasatake YAMATO 			i = '\r';
1016d8f6b0edSMasatake YAMATO 			break;
1017d8f6b0edSMasatake YAMATO 		case 'v':
1018d8f6b0edSMasatake YAMATO 			i = '\v';
1019d8f6b0edSMasatake YAMATO 			break;
1020d8f6b0edSMasatake YAMATO 		case ' ':
1021d8f6b0edSMasatake YAMATO 		case '_':
1022d8f6b0edSMasatake YAMATO 			i = ' ';
1023d8f6b0edSMasatake YAMATO 			break;
1024d8f6b0edSMasatake YAMATO 		case '\\':
1025d8f6b0edSMasatake YAMATO 			i = '\\';
1026d8f6b0edSMasatake YAMATO 			break;
1027d8f6b0edSMasatake YAMATO 		default:
1028d8f6b0edSMasatake YAMATO 			return OPT_ERR_SYNTAX;
1029d8f6b0edSMasatake YAMATO 		}
1030d8f6b0edSMasatake YAMATO 		c = mio_getc (vm->in);
10313773fd94SMasatake YAMATO 		if (!(c == EOF || isspace (c) || is_meta_char (c)))
1032d8f6b0edSMasatake YAMATO 			return OPT_ERR_SYNTAX;
1033d8f6b0edSMasatake YAMATO 		mio_ungetc (vm->in, c);
1034d8f6b0edSMasatake YAMATO 		return es_integer_new (i);
1035d8f6b0edSMasatake YAMATO 	}
1036d8f6b0edSMasatake YAMATO 	else if (isgraph(c))
1037d8f6b0edSMasatake YAMATO 	{
1038d8f6b0edSMasatake YAMATO 		i = c;
1039d8f6b0edSMasatake YAMATO 
1040d8f6b0edSMasatake YAMATO 		c = mio_getc (vm->in);
10413773fd94SMasatake YAMATO 		if (!(c == EOF || isspace (c) || is_meta_char (c)))
1042d8f6b0edSMasatake YAMATO 			return OPT_ERR_SYNTAX;
1043d8f6b0edSMasatake YAMATO 		mio_ungetc (vm->in, c);
1044d8f6b0edSMasatake YAMATO 
1045d8f6b0edSMasatake YAMATO 		return es_integer_new (i);
1046d8f6b0edSMasatake YAMATO 	}
1047d8f6b0edSMasatake YAMATO 	else
1048d8f6b0edSMasatake YAMATO 		return OPT_ERR_SYNTAX;
1049d8f6b0edSMasatake YAMATO }
1050d8f6b0edSMasatake YAMATO 
1051d8f6b0edSMasatake YAMATO static EsObject*
vm_read_string(OptVM * vm)1052d8f6b0edSMasatake YAMATO vm_read_string (OptVM *vm)
1053d8f6b0edSMasatake YAMATO {
1054d8f6b0edSMasatake YAMATO 	int depth = 0;
1055d8f6b0edSMasatake YAMATO 	vString *s = vStringNew ();
1056d8f6b0edSMasatake YAMATO 	while (true)
1057d8f6b0edSMasatake YAMATO 	{
1058d8f6b0edSMasatake YAMATO 		int c = mio_getc (vm->in);
1059d8f6b0edSMasatake YAMATO 		if (c == ')')
1060d8f6b0edSMasatake YAMATO 		{
1061d8f6b0edSMasatake YAMATO 			if (depth == 0)
1062d8f6b0edSMasatake YAMATO 				return string_new (s);
1063d8f6b0edSMasatake YAMATO 			vStringPut (s, c);
1064d8f6b0edSMasatake YAMATO 			depth--;
1065d8f6b0edSMasatake YAMATO 		}
1066d8f6b0edSMasatake YAMATO 		else if (c == '(')
1067d8f6b0edSMasatake YAMATO 		{
1068d8f6b0edSMasatake YAMATO 			vStringPut (s, c);
1069d8f6b0edSMasatake YAMATO 			depth++;
1070d8f6b0edSMasatake YAMATO 		}
1071d8f6b0edSMasatake YAMATO 		else if (c == '\\')
1072d8f6b0edSMasatake YAMATO 		{
1073d8f6b0edSMasatake YAMATO 			c = mio_getc (vm->in);
1074d8f6b0edSMasatake YAMATO 			switch (c)
1075d8f6b0edSMasatake YAMATO 			{
1076d8f6b0edSMasatake YAMATO 			case EOF:
1077d8f6b0edSMasatake YAMATO 				vStringDelete (s);
1078d8f6b0edSMasatake YAMATO 				return OPT_ERR_SYNTAX;
1079d8f6b0edSMasatake YAMATO 			case 'n':
1080d8f6b0edSMasatake YAMATO 				vStringPut (s, '\n');
1081d8f6b0edSMasatake YAMATO 				break;
1082d8f6b0edSMasatake YAMATO 			case 't':
1083d8f6b0edSMasatake YAMATO 				vStringPut (s, '\t');
1084d8f6b0edSMasatake YAMATO 				break;
1085d8f6b0edSMasatake YAMATO 			case 'r':
1086d8f6b0edSMasatake YAMATO 				vStringPut (s, '\r');
1087d8f6b0edSMasatake YAMATO 				break;
1088d8f6b0edSMasatake YAMATO 			case 'f':
1089d8f6b0edSMasatake YAMATO 				vStringPut (s, '\f');
1090d8f6b0edSMasatake YAMATO 				break;
1091d8f6b0edSMasatake YAMATO 			case 'v':
1092d8f6b0edSMasatake YAMATO 				vStringPut (s, '\v');
1093d8f6b0edSMasatake YAMATO 				break;
1094d8f6b0edSMasatake YAMATO 			case '\\':
1095d8f6b0edSMasatake YAMATO 			case '(':
1096d8f6b0edSMasatake YAMATO 			case ')':
1097d8f6b0edSMasatake YAMATO 				vStringPut (s, c);
1098d8f6b0edSMasatake YAMATO 				break;
1099d8f6b0edSMasatake YAMATO 			default:
1100d8f6b0edSMasatake YAMATO 				vStringPut (s, c);
1101d8f6b0edSMasatake YAMATO 				break;
1102d8f6b0edSMasatake YAMATO 				;
1103d8f6b0edSMasatake YAMATO 			}
1104d8f6b0edSMasatake YAMATO 		}
1105d8f6b0edSMasatake YAMATO 		else if (c == EOF)
1106d8f6b0edSMasatake YAMATO 		{
1107d8f6b0edSMasatake YAMATO 			vStringDelete (s);
1108d8f6b0edSMasatake YAMATO 			return OPT_ERR_SYNTAX;
1109d8f6b0edSMasatake YAMATO 		}
1110d8f6b0edSMasatake YAMATO 		else
1111d8f6b0edSMasatake YAMATO 			vStringPut (s, c);
1112d8f6b0edSMasatake YAMATO 	}
1113d8f6b0edSMasatake YAMATO }
1114d8f6b0edSMasatake YAMATO 
1115d8f6b0edSMasatake YAMATO static EsObject*
vm_read_generic(OptVM * vm,int c,EsObject * (* make_object)(const char *,void *),void * data)1116d8f6b0edSMasatake YAMATO vm_read_generic(OptVM *vm, int c,
1117d8f6b0edSMasatake YAMATO 				EsObject * (* make_object) (const char *, void *),
1118d8f6b0edSMasatake YAMATO 				void *data)
1119d8f6b0edSMasatake YAMATO {
1120d8f6b0edSMasatake YAMATO 	vString *name = vStringNew ();
1121d8f6b0edSMasatake YAMATO 	vStringPut (name, c);
1122d8f6b0edSMasatake YAMATO 
1123d8f6b0edSMasatake YAMATO 	while (1)
1124d8f6b0edSMasatake YAMATO 	{
1125d8f6b0edSMasatake YAMATO 		c = mio_getc (vm->in);
1126d8f6b0edSMasatake YAMATO 		if (c == EOF)
1127d8f6b0edSMasatake YAMATO 			break;
1128d8f6b0edSMasatake YAMATO 		else if (isspace (c) || is_meta_char (c))
1129d8f6b0edSMasatake YAMATO 		{
1130d8f6b0edSMasatake YAMATO 			mio_ungetc (vm->in, c);
1131d8f6b0edSMasatake YAMATO 			break;
1132d8f6b0edSMasatake YAMATO 		}
1133d8f6b0edSMasatake YAMATO 		else
1134d8f6b0edSMasatake YAMATO 			vStringPut (name, c);
1135d8f6b0edSMasatake YAMATO 	}
1136d8f6b0edSMasatake YAMATO 	EsObject *n = make_object (vStringValue (name), data);
1137d8f6b0edSMasatake YAMATO 	vStringDelete (name);
1138d8f6b0edSMasatake YAMATO 	return n;
1139d8f6b0edSMasatake YAMATO }
1140d8f6b0edSMasatake YAMATO 
1141d8f6b0edSMasatake YAMATO static EsObject*
vm_read_name(OptVM * vm,int c,unsigned int attr)1142d8f6b0edSMasatake YAMATO vm_read_name (OptVM *vm, int c, unsigned int attr)
1143d8f6b0edSMasatake YAMATO {
1144d8f6b0edSMasatake YAMATO 	return vm_read_generic (vm, c, name_newS_cb, &attr);
1145d8f6b0edSMasatake YAMATO }
1146d8f6b0edSMasatake YAMATO 
1147d8f6b0edSMasatake YAMATO struct name_or_number_data {
1148d8f6b0edSMasatake YAMATO 	unsigned int attr;
1149d8f6b0edSMasatake YAMATO 	bool negative;
1150d8f6b0edSMasatake YAMATO };
1151d8f6b0edSMasatake YAMATO 
1152d8f6b0edSMasatake YAMATO static EsObject*
name_or_number_new(const char * s,void * data)1153d8f6b0edSMasatake YAMATO name_or_number_new (const char* s, void *data)
1154d8f6b0edSMasatake YAMATO {
1155d8f6b0edSMasatake YAMATO 	struct name_or_number_data *d = data;
1156d8f6b0edSMasatake YAMATO 
1157d8f6b0edSMasatake YAMATO 	bool number = true;
1158d8f6b0edSMasatake YAMATO 	const char *t = s;
1159d8f6b0edSMasatake YAMATO 	while (*t)
1160d8f6b0edSMasatake YAMATO 	{
1161d8f6b0edSMasatake YAMATO 		if (!isdigit ((int)*t))
1162d8f6b0edSMasatake YAMATO 		{
1163d8f6b0edSMasatake YAMATO 			number = false;
1164d8f6b0edSMasatake YAMATO 			break;
1165d8f6b0edSMasatake YAMATO 		}
1166d8f6b0edSMasatake YAMATO 		t++;
1167d8f6b0edSMasatake YAMATO 	}
1168d8f6b0edSMasatake YAMATO 	if (number)
1169d8f6b0edSMasatake YAMATO 	{
1170d8f6b0edSMasatake YAMATO 		int n;
1171d8f6b0edSMasatake YAMATO 		if (strToInt (s, 10, &n))
1172d8f6b0edSMasatake YAMATO 			return es_integer_new (n * ((d->negative)? -1: 1));
1173d8f6b0edSMasatake YAMATO 		else
1174d8f6b0edSMasatake YAMATO 			return OPT_ERR_INTOVERFLOW;
1175d8f6b0edSMasatake YAMATO 	}
1176d8f6b0edSMasatake YAMATO 	else
1177d8f6b0edSMasatake YAMATO 		return name_newS_cb (s, &d->attr);
1178d8f6b0edSMasatake YAMATO }
1179d8f6b0edSMasatake YAMATO 
1180d8f6b0edSMasatake YAMATO static EsObject*
vm_read_name_or_number(OptVM * vm,int c,unsigned int attr,bool negative)1181d8f6b0edSMasatake YAMATO vm_read_name_or_number (OptVM *vm, int c, unsigned int attr, bool negative)
1182d8f6b0edSMasatake YAMATO {
1183d8f6b0edSMasatake YAMATO 	struct name_or_number_data data = {
1184d8f6b0edSMasatake YAMATO 		.attr     = attr,
1185d8f6b0edSMasatake YAMATO 		.negative = negative,
1186d8f6b0edSMasatake YAMATO 	};
1187d8f6b0edSMasatake YAMATO 
1188d8f6b0edSMasatake YAMATO 	return vm_read_generic (vm, c, name_or_number_new, &data);
1189d8f6b0edSMasatake YAMATO }
1190d8f6b0edSMasatake YAMATO 
1191d8f6b0edSMasatake YAMATO static EsObject*
vm_read_quoted(OptVM * vm)1192d8f6b0edSMasatake YAMATO vm_read_quoted (OptVM *vm)
1193d8f6b0edSMasatake YAMATO {
1194d8f6b0edSMasatake YAMATO 	bool immediate = false;
1195d8f6b0edSMasatake YAMATO 
1196d8f6b0edSMasatake YAMATO 	int c = mio_getc (vm->in);
1197d8f6b0edSMasatake YAMATO 	switch (c)
1198d8f6b0edSMasatake YAMATO 	{
1199d8f6b0edSMasatake YAMATO 	case '/':
1200d8f6b0edSMasatake YAMATO 		immediate = true;
1201d8f6b0edSMasatake YAMATO 		c = mio_getc (vm->in);
1202d8f6b0edSMasatake YAMATO 		break;
1203d8f6b0edSMasatake YAMATO 	default:
1204d8f6b0edSMasatake YAMATO 		break;
1205d8f6b0edSMasatake YAMATO 	}
1206d8f6b0edSMasatake YAMATO 
1207d8f6b0edSMasatake YAMATO 	EsObject *s = vm_read_name (vm, c, ATTR_READABLE);
1208d8f6b0edSMasatake YAMATO 	if (immediate)
1209d8f6b0edSMasatake YAMATO 	{
1210d8f6b0edSMasatake YAMATO 		EsObject *q;
1211d8f6b0edSMasatake YAMATO 
1212d8f6b0edSMasatake YAMATO 		EsObject *val  = es_nil;
1213d8f6b0edSMasatake YAMATO 		EsObject *dict = vm_dstack_known_and_get (vm, s, &val);
1214d8f6b0edSMasatake YAMATO 		if (es_object_get_type (dict) == OPT_TYPE_DICT)
1215d8f6b0edSMasatake YAMATO 			q = es_object_ref (val);
1216d8f6b0edSMasatake YAMATO 		else
1217d8f6b0edSMasatake YAMATO 		{
1218d8f6b0edSMasatake YAMATO 			q = es_error_set_object (OPT_ERR_UNDEFINED, s);
1219d8f6b0edSMasatake YAMATO 			vm_record_error (vm, q, s); /* TODO */
1220d8f6b0edSMasatake YAMATO 		}
1221d8f6b0edSMasatake YAMATO 		es_object_unref (s);
1222d8f6b0edSMasatake YAMATO 		return q;
1223d8f6b0edSMasatake YAMATO 	}
1224d8f6b0edSMasatake YAMATO 	else
1225d8f6b0edSMasatake YAMATO 		return s;
1226d8f6b0edSMasatake YAMATO }
1227d8f6b0edSMasatake YAMATO 
1228d8f6b0edSMasatake YAMATO static EsObject*
vm_read_proc(OptVM * vm)1229d8f6b0edSMasatake YAMATO vm_read_proc (OptVM *vm)
1230d8f6b0edSMasatake YAMATO {
1231d8f6b0edSMasatake YAMATO 	EsObject *proc = array_new (ATTR_EXECUTABLE|ATTR_READABLE);
1232d8f6b0edSMasatake YAMATO 
1233d8f6b0edSMasatake YAMATO 	vm->read_depth++;
1234d8f6b0edSMasatake YAMATO 	while (true)
1235d8f6b0edSMasatake YAMATO 	{
1236d8f6b0edSMasatake YAMATO 		EsObject *o = vm_read (vm);
1237d8f6b0edSMasatake YAMATO 		if (es_object_equal (o, OPT_ERR_END_PROC))
1238d8f6b0edSMasatake YAMATO 		{
1239d8f6b0edSMasatake YAMATO 			break;
1240d8f6b0edSMasatake YAMATO 		}
1241d8f6b0edSMasatake YAMATO 		else if (es_error_p (o))
1242d8f6b0edSMasatake YAMATO 		{
1243d8f6b0edSMasatake YAMATO 			es_object_unref (proc);
1244d8f6b0edSMasatake YAMATO 			proc = o;
1245d8f6b0edSMasatake YAMATO 			break;
1246d8f6b0edSMasatake YAMATO 		}
1247d8f6b0edSMasatake YAMATO 		else
1248d8f6b0edSMasatake YAMATO 		{
1249d8f6b0edSMasatake YAMATO 			array_op_add (proc, o);
1250d8f6b0edSMasatake YAMATO 			es_object_unref (o);
1251d8f6b0edSMasatake YAMATO 		}
1252d8f6b0edSMasatake YAMATO 	}
1253d8f6b0edSMasatake YAMATO 	vm->read_depth--;
1254d8f6b0edSMasatake YAMATO 	return proc;
1255d8f6b0edSMasatake YAMATO }
1256d8f6b0edSMasatake YAMATO 
1257d8f6b0edSMasatake YAMATO static EsObject*
vm_read(OptVM * vm)1258d8f6b0edSMasatake YAMATO vm_read (OptVM *vm)
1259d8f6b0edSMasatake YAMATO {
1260d8f6b0edSMasatake YAMATO 	while (true)
1261d8f6b0edSMasatake YAMATO 	{
1262d8f6b0edSMasatake YAMATO 		int c = mio_getc (vm->in);
1263d8f6b0edSMasatake YAMATO 		if (c == EOF)
1264d8f6b0edSMasatake YAMATO 			return es_object_ref (ES_READER_EOF);
1265d8f6b0edSMasatake YAMATO 		else if (c == '\n' || c == '\r')
1266d8f6b0edSMasatake YAMATO 		{
1267d8f6b0edSMasatake YAMATO 			opt_vm_print_prompt (vm);
1268d8f6b0edSMasatake YAMATO 			continue;
1269d8f6b0edSMasatake YAMATO 		}
1270d8f6b0edSMasatake YAMATO 		else if (isspace (c))
1271d8f6b0edSMasatake YAMATO 			continue;
1272d8f6b0edSMasatake YAMATO 		else if (c == '%')
1273d8f6b0edSMasatake YAMATO 		{
1274d8f6b0edSMasatake YAMATO 			vm_read_skip_comment (vm);
1275d8f6b0edSMasatake YAMATO 			continue;
1276d8f6b0edSMasatake YAMATO 		}
1277d8f6b0edSMasatake YAMATO 		else if (isdigit (c))
1278d8f6b0edSMasatake YAMATO 		{
1279d8f6b0edSMasatake YAMATO 			return vm_read_name_or_number (vm, c, ATTR_EXECUTABLE|ATTR_READABLE,
1280d8f6b0edSMasatake YAMATO 										   false);
1281d8f6b0edSMasatake YAMATO 		}
1282d8f6b0edSMasatake YAMATO 		else if (c == '-' || c == '+')
1283d8f6b0edSMasatake YAMATO 		{
1284d8f6b0edSMasatake YAMATO 			bool negative = (c == '-');
1285d8f6b0edSMasatake YAMATO 			c = mio_getc (vm->in);
1286d8f6b0edSMasatake YAMATO 			if (isdigit (c))
1287d8f6b0edSMasatake YAMATO 				return vm_read_name_or_number (vm, c, ATTR_EXECUTABLE|ATTR_READABLE,
1288d8f6b0edSMasatake YAMATO 											   negative);
1289d8f6b0edSMasatake YAMATO 			else
1290d8f6b0edSMasatake YAMATO 			{
1291d8f6b0edSMasatake YAMATO 				mio_ungetc (vm->in, c);
1292d8f6b0edSMasatake YAMATO 				return vm_read_name_or_number (vm, '-', ATTR_EXECUTABLE|ATTR_READABLE,
1293d8f6b0edSMasatake YAMATO 											   false);
1294d8f6b0edSMasatake YAMATO 			}
1295d8f6b0edSMasatake YAMATO 		}
1296d8f6b0edSMasatake YAMATO 		else if (c == '/')
1297d8f6b0edSMasatake YAMATO 			return vm_read_quoted (vm);
1298d8f6b0edSMasatake YAMATO 		else if (c == '(')
1299d8f6b0edSMasatake YAMATO 			return vm_read_string (vm);
1300d8f6b0edSMasatake YAMATO 		else if (c == '{')
1301d8f6b0edSMasatake YAMATO 			return vm_read_proc (vm);
1302d8f6b0edSMasatake YAMATO 		else if (c == '}')
1303d8f6b0edSMasatake YAMATO 		{
1304d8f6b0edSMasatake YAMATO 			if (vm->read_depth)
1305d8f6b0edSMasatake YAMATO 				return OPT_ERR_END_PROC;
1306d8f6b0edSMasatake YAMATO 			else
1307d8f6b0edSMasatake YAMATO 				return OPT_ERR_SYNTAX;
1308d8f6b0edSMasatake YAMATO 		}
1309d8f6b0edSMasatake YAMATO 		else if (c == '[' || c == ']')
1310d8f6b0edSMasatake YAMATO 		{
1311d8f6b0edSMasatake YAMATO 			const char name[2] = { [0] = c, [1] = '\0' };
1312d8f6b0edSMasatake YAMATO 			EsObject *s = es_symbol_intern (name);
1313d8f6b0edSMasatake YAMATO 			EsObject *n = name_new (s, ATTR_EXECUTABLE|ATTR_READABLE);
1314d8f6b0edSMasatake YAMATO 			return n;
1315d8f6b0edSMasatake YAMATO 		}
1316d8f6b0edSMasatake YAMATO 		else if (c == '<' || c == '>')
1317d8f6b0edSMasatake YAMATO 		{
1318d8f6b0edSMasatake YAMATO 			int c0 = mio_getc (vm->in);
1319d8f6b0edSMasatake YAMATO 			if (c != c0)
1320d8f6b0edSMasatake YAMATO 				return OPT_ERR_SYNTAX;
1321d8f6b0edSMasatake YAMATO 
1322d8f6b0edSMasatake YAMATO 			const char name [3] = { [0] = c, [1] = c, [2] = '\0' };
1323d8f6b0edSMasatake YAMATO 			EsObject *s = es_symbol_intern (name);
1324d8f6b0edSMasatake YAMATO 			EsObject *n = name_new (s, ATTR_EXECUTABLE|ATTR_READABLE);
1325d8f6b0edSMasatake YAMATO 			return n;
1326d8f6b0edSMasatake YAMATO 		}
1327d8f6b0edSMasatake YAMATO 		else if (c == '?')
1328d8f6b0edSMasatake YAMATO 			return vm_read_char (vm);
1329d8f6b0edSMasatake YAMATO 		else
1330d8f6b0edSMasatake YAMATO 			return vm_read_name (vm, c, ATTR_EXECUTABLE|ATTR_READABLE);
1331d8f6b0edSMasatake YAMATO 	}
1332d8f6b0edSMasatake YAMATO }
1333d8f6b0edSMasatake YAMATO 
1334d8f6b0edSMasatake YAMATO static void
vm_ostack_push(OptVM * vm,EsObject * o)1335d8f6b0edSMasatake YAMATO vm_ostack_push (OptVM *vm, EsObject *o)
1336d8f6b0edSMasatake YAMATO {
1337d8f6b0edSMasatake YAMATO 	ptrArrayAdd (vm->ostack, es_object_ref (o));
1338d8f6b0edSMasatake YAMATO }
1339d8f6b0edSMasatake YAMATO 
1340d8f6b0edSMasatake YAMATO static EsObject*
vm_ostack_pop(OptVM * vm)1341d8f6b0edSMasatake YAMATO vm_ostack_pop (OptVM *vm)
1342d8f6b0edSMasatake YAMATO {
1343d8f6b0edSMasatake YAMATO 	unsigned int c = vm_ostack_count (vm);
1344d8f6b0edSMasatake YAMATO 
1345d8f6b0edSMasatake YAMATO 	if (c > 0)
1346d8f6b0edSMasatake YAMATO 	{
1347d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLast (vm->ostack);
1348d8f6b0edSMasatake YAMATO 		return es_false;
1349d8f6b0edSMasatake YAMATO 	}
1350d8f6b0edSMasatake YAMATO 
1351d8f6b0edSMasatake YAMATO 	return OPT_ERR_UNDERFLOW;
1352d8f6b0edSMasatake YAMATO }
1353d8f6b0edSMasatake YAMATO 
1354d8f6b0edSMasatake YAMATO static unsigned int
vm_ostack_count(OptVM * vm)1355d8f6b0edSMasatake YAMATO vm_ostack_count (OptVM *vm)
1356d8f6b0edSMasatake YAMATO {
1357d8f6b0edSMasatake YAMATO 	return ptrArrayCount (vm->ostack);
1358d8f6b0edSMasatake YAMATO }
1359d8f6b0edSMasatake YAMATO 
1360d8f6b0edSMasatake YAMATO static int
vm_ostack_counttomark(OptVM * vm)1361d8f6b0edSMasatake YAMATO vm_ostack_counttomark (OptVM *vm)
1362d8f6b0edSMasatake YAMATO {
1363d8f6b0edSMasatake YAMATO 	unsigned int c = ptrArrayCount (vm->ostack);
1364d8f6b0edSMasatake YAMATO 	unsigned int i;
1365d8f6b0edSMasatake YAMATO 
1366d8f6b0edSMasatake YAMATO 	if  (c == 0)
1367d8f6b0edSMasatake YAMATO 		return -1;
1368d8f6b0edSMasatake YAMATO 
1369d8f6b0edSMasatake YAMATO 	for (i = c; i > 0; i--)
1370d8f6b0edSMasatake YAMATO 	{
1371d8f6b0edSMasatake YAMATO 		EsObject *elt = ptrArrayItem (vm->ostack, i - 1);
1372d8f6b0edSMasatake YAMATO 		if (es_object_get_type (elt) == OPT_TYPE_MARK)
1373d8f6b0edSMasatake YAMATO 			break;
1374d8f6b0edSMasatake YAMATO 	}
1375d8f6b0edSMasatake YAMATO 
1376d8f6b0edSMasatake YAMATO 	if (i == 0)
1377d8f6b0edSMasatake YAMATO 		return -1;
1378d8f6b0edSMasatake YAMATO 
1379d8f6b0edSMasatake YAMATO 	int r = (c - i);
1380d8f6b0edSMasatake YAMATO 	if (r < 0)					/* FIXME */
1381d8f6b0edSMasatake YAMATO 		r = -1;
1382d8f6b0edSMasatake YAMATO 	return r;
1383d8f6b0edSMasatake YAMATO }
1384d8f6b0edSMasatake YAMATO 
1385d8f6b0edSMasatake YAMATO static EsObject*
vm_ostack_top(OptVM * vm)1386d8f6b0edSMasatake YAMATO vm_ostack_top (OptVM *vm)
1387d8f6b0edSMasatake YAMATO {
1388d8f6b0edSMasatake YAMATO 	if (ptrArrayCount (vm->ostack) > 0)
1389d8f6b0edSMasatake YAMATO 		return ptrArrayLast (vm->ostack);
1390d8f6b0edSMasatake YAMATO 	return OPT_ERR_UNDERFLOW;
1391d8f6b0edSMasatake YAMATO }
1392d8f6b0edSMasatake YAMATO 
1393d8f6b0edSMasatake YAMATO static EsObject*
vm_ostack_peek(OptVM * vm,int index_from_top)1394d8f6b0edSMasatake YAMATO vm_ostack_peek (OptVM *vm, int index_from_top)
1395d8f6b0edSMasatake YAMATO {
1396d8f6b0edSMasatake YAMATO 	unsigned int c = ptrArrayCount (vm->ostack);
1397d8f6b0edSMasatake YAMATO 	if (c > (unsigned int)index_from_top)
1398d8f6b0edSMasatake YAMATO 	{
1399d8f6b0edSMasatake YAMATO 		unsigned int i = (c - ((unsigned int)index_from_top)) - 1;
1400d8f6b0edSMasatake YAMATO 		Assert (i < c);
1401d8f6b0edSMasatake YAMATO 		return ptrArrayItem (vm->ostack, i);
1402d8f6b0edSMasatake YAMATO 	}
1403d8f6b0edSMasatake YAMATO 	return OPT_ERR_UNDERFLOW;
1404d8f6b0edSMasatake YAMATO }
1405d8f6b0edSMasatake YAMATO 
1406d8f6b0edSMasatake YAMATO static EsObject*
vm_dstack_known_and_get(OptVM * vm,EsObject * key,EsObject ** val)1407d8f6b0edSMasatake YAMATO vm_dstack_known_and_get (OptVM *vm, EsObject *key, EsObject **val)
1408d8f6b0edSMasatake YAMATO {
1409d8f6b0edSMasatake YAMATO 	if (es_object_get_type (key) == OPT_TYPE_NAME)
1410d8f6b0edSMasatake YAMATO 		key = es_pointer_get (key);
1411d8f6b0edSMasatake YAMATO 
1412d8f6b0edSMasatake YAMATO 	int c = ptrArrayCount (vm->dstack);
1413d8f6b0edSMasatake YAMATO 
1414d8f6b0edSMasatake YAMATO 	for (int i = c - 1; i >= 0; i--)
1415d8f6b0edSMasatake YAMATO 	{
1416d8f6b0edSMasatake YAMATO 		EsObject *d = ptrArrayItem (vm->dstack, i);
1417d8f6b0edSMasatake YAMATO 		if (dict_op_known_and_get (d, key, val))
1418d8f6b0edSMasatake YAMATO 			return d;
1419d8f6b0edSMasatake YAMATO 	}
1420d8f6b0edSMasatake YAMATO 	return es_false;
1421d8f6b0edSMasatake YAMATO }
1422d8f6b0edSMasatake YAMATO 
1423d8f6b0edSMasatake YAMATO static void
vm_dict_def(OptVM * vm,EsObject * key,EsObject * val)1424d8f6b0edSMasatake YAMATO vm_dict_def (OptVM *vm, EsObject *key, EsObject *val)
1425d8f6b0edSMasatake YAMATO {
1426d8f6b0edSMasatake YAMATO 	Assert (!es_null(key));
1427d8f6b0edSMasatake YAMATO 	dict_op_def (ptrArrayLast(vm->dstack), key, val);
1428d8f6b0edSMasatake YAMATO }
1429d8f6b0edSMasatake YAMATO 
1430d8f6b0edSMasatake YAMATO static void
vm_dstack_push(OptVM * vm,EsObject * o)1431d8f6b0edSMasatake YAMATO vm_dstack_push  (OptVM *vm, EsObject *o)
1432d8f6b0edSMasatake YAMATO {
1433d8f6b0edSMasatake YAMATO 	ptrArrayAdd (vm->dstack, es_object_ref (o));
1434d8f6b0edSMasatake YAMATO }
1435d8f6b0edSMasatake YAMATO 
1436d8f6b0edSMasatake YAMATO static int
vm_dstack_count(OptVM * vm)1437d8f6b0edSMasatake YAMATO vm_dstack_count (OptVM *vm)
1438d8f6b0edSMasatake YAMATO {
1439d8f6b0edSMasatake YAMATO 	return ptrArrayCount (vm->dstack);
1440d8f6b0edSMasatake YAMATO }
1441d8f6b0edSMasatake YAMATO 
1442d8f6b0edSMasatake YAMATO static EsObject*
vm_dstack_pop(OptVM * vm)1443d8f6b0edSMasatake YAMATO vm_dstack_pop (OptVM *vm)
1444d8f6b0edSMasatake YAMATO {
1445d8f6b0edSMasatake YAMATO 	if (vm_dstack_count (vm) <= vm->dstack_protection)
1446d8f6b0edSMasatake YAMATO 		return OPT_ERR_DICTSTACKUNDERFLOW;
1447d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->dstack);
1448d8f6b0edSMasatake YAMATO 	return es_false;
1449d8f6b0edSMasatake YAMATO }
1450d8f6b0edSMasatake YAMATO 
1451d8f6b0edSMasatake YAMATO static void
vm_dstack_clear(OptVM * vm)1452d8f6b0edSMasatake YAMATO vm_dstack_clear         (OptVM *vm)
1453d8f6b0edSMasatake YAMATO {
1454d8f6b0edSMasatake YAMATO 	while (ptrArrayCount (vm->dstack) > 1)
1455d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLast (vm->dstack);
1456d8f6b0edSMasatake YAMATO 
1457d8f6b0edSMasatake YAMATO 	vm->dstack_protection = 1;
1458d8f6b0edSMasatake YAMATO }
1459d8f6b0edSMasatake YAMATO 
1460d8f6b0edSMasatake YAMATO static EsObject*
vm_call_operator(OptVM * vm,EsObject * op)1461d8f6b0edSMasatake YAMATO vm_call_operator (OptVM *vm, EsObject *op)
1462d8f6b0edSMasatake YAMATO {
1463d8f6b0edSMasatake YAMATO 	EsObject *r;
1464d8f6b0edSMasatake YAMATO 
1465d8f6b0edSMasatake YAMATO 	Operator operator = es_pointer_get (op);
1466d8f6b0edSMasatake YAMATO 	OperatorFat *ofat = es_fatptr_get (op);
1467d8f6b0edSMasatake YAMATO 
1468d8f6b0edSMasatake YAMATO 	vm_estack_push (vm, op);
1469d8f6b0edSMasatake YAMATO 
1470d8f6b0edSMasatake YAMATO 	if (ofat->arity > 0)
1471d8f6b0edSMasatake YAMATO 	{
1472d8f6b0edSMasatake YAMATO 		unsigned int c = ptrArrayCount (vm->ostack);
1473d8f6b0edSMasatake YAMATO 		if (c < (unsigned int)ofat->arity)
1474d8f6b0edSMasatake YAMATO 		{
1475d8f6b0edSMasatake YAMATO 			vm_estack_pop (vm);
1476d8f6b0edSMasatake YAMATO 			vm_record_error (vm, OPT_ERR_UNDERFLOW, op);
1477d8f6b0edSMasatake YAMATO 			return OPT_ERR_UNDERFLOW;
1478d8f6b0edSMasatake YAMATO 		}
1479d8f6b0edSMasatake YAMATO 	}
1480d8f6b0edSMasatake YAMATO 
1481d8f6b0edSMasatake YAMATO 	r = (* operator) (vm, ofat->name);
1482d8f6b0edSMasatake YAMATO 	if (es_error_p (r))
1483d8f6b0edSMasatake YAMATO 	{
1484d8f6b0edSMasatake YAMATO 		vm_estack_pop (vm);
1485d8f6b0edSMasatake YAMATO 		if (es_object_equal (OPT_ERR_STOPPED, r))
1486d8f6b0edSMasatake YAMATO 			vm_record_stop (vm, op);
1487d8f6b0edSMasatake YAMATO 		else
1488d8f6b0edSMasatake YAMATO 			vm_record_error (vm, r, op);
1489d8f6b0edSMasatake YAMATO 		return r;
1490d8f6b0edSMasatake YAMATO 	}
1491d8f6b0edSMasatake YAMATO 
1492d8f6b0edSMasatake YAMATO 	vm_estack_pop (vm);
1493d8f6b0edSMasatake YAMATO 	return es_false;
1494d8f6b0edSMasatake YAMATO }
1495d8f6b0edSMasatake YAMATO 
1496d8f6b0edSMasatake YAMATO static EsObject*
vm_call_proc(OptVM * vm,EsObject * proc)1497d8f6b0edSMasatake YAMATO vm_call_proc     (OptVM *vm, EsObject *proc)
1498d8f6b0edSMasatake YAMATO {
1499d8f6b0edSMasatake YAMATO 	ptrArray *a = es_pointer_get (proc);
1500d8f6b0edSMasatake YAMATO 	unsigned int c = ptrArrayCount (a);
1501d8f6b0edSMasatake YAMATO 
1502d8f6b0edSMasatake YAMATO 	vm_estack_push (vm, proc);
1503d8f6b0edSMasatake YAMATO 	for (unsigned int i = 0; i < c; i++)
1504d8f6b0edSMasatake YAMATO 	{
1505d8f6b0edSMasatake YAMATO 		EsObject *o = ptrArrayItem (a, i);
1506d8f6b0edSMasatake YAMATO 		EsObject* e = vm_eval (vm, o);
1507d8f6b0edSMasatake YAMATO 		if (es_error_p (e))
1508d8f6b0edSMasatake YAMATO 		{
1509d8f6b0edSMasatake YAMATO 			vm_estack_pop (vm);	/* ??? */
1510d8f6b0edSMasatake YAMATO 			return e;
1511d8f6b0edSMasatake YAMATO 		}
1512d8f6b0edSMasatake YAMATO 	}
1513d8f6b0edSMasatake YAMATO 	vm_estack_pop (vm);
1514d8f6b0edSMasatake YAMATO 
1515d8f6b0edSMasatake YAMATO 	return es_false;
1516d8f6b0edSMasatake YAMATO }
1517d8f6b0edSMasatake YAMATO 
1518d8f6b0edSMasatake YAMATO static EsObject*
vm_estack_push(OptVM * vm,EsObject * p)1519d8f6b0edSMasatake YAMATO vm_estack_push (OptVM *vm, EsObject *p)
1520d8f6b0edSMasatake YAMATO {
1521d8f6b0edSMasatake YAMATO 	ptrArrayAdd (vm->estack, es_object_ref (p));
1522d8f6b0edSMasatake YAMATO 	return es_false;
1523d8f6b0edSMasatake YAMATO }
1524d8f6b0edSMasatake YAMATO 
1525d8f6b0edSMasatake YAMATO static EsObject*
vm_estack_pop(OptVM * vm)1526d8f6b0edSMasatake YAMATO vm_estack_pop (OptVM *vm)
1527d8f6b0edSMasatake YAMATO {
1528d8f6b0edSMasatake YAMATO 	if (ptrArrayCount (vm->estack) < 1)
1529d8f6b0edSMasatake YAMATO 		return OPT_ERR_INTERNALERROR;
1530d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->estack);
1531d8f6b0edSMasatake YAMATO 	return es_false;
1532d8f6b0edSMasatake YAMATO }
1533d8f6b0edSMasatake YAMATO 
1534d8f6b0edSMasatake YAMATO static void
insert_spaces(MIO * mio,int n)1535d8f6b0edSMasatake YAMATO insert_spaces (MIO *mio, int n)
1536d8f6b0edSMasatake YAMATO {
1537d8f6b0edSMasatake YAMATO 	while (n-- > 0)
1538d8f6b0edSMasatake YAMATO 		mio_putc(mio, ' ');
1539d8f6b0edSMasatake YAMATO }
1540d8f6b0edSMasatake YAMATO 
1541d8f6b0edSMasatake YAMATO struct htable_print_data {
1542d8f6b0edSMasatake YAMATO 	OptVM *vm;
1543d8f6b0edSMasatake YAMATO 	int dict_recursion;
1544d8f6b0edSMasatake YAMATO };
1545d8f6b0edSMasatake YAMATO 
1546d8f6b0edSMasatake YAMATO static bool
htable_print_entry(const void * key,void * val,void * user_data)1547d8f6b0edSMasatake YAMATO htable_print_entry (const void *key, void *val, void *user_data)
1548d8f6b0edSMasatake YAMATO {
1549d8f6b0edSMasatake YAMATO 	struct htable_print_data *data = user_data;
1550d8f6b0edSMasatake YAMATO 
1551d8f6b0edSMasatake YAMATO 	vm_print_full (data->vm, (EsObject *)key, false, data->dict_recursion);
1552d8f6b0edSMasatake YAMATO 	mio_putc (data->vm->out, ' ');
1553d8f6b0edSMasatake YAMATO 	vm_print_full (data->vm, (EsObject *)val, false, data->dict_recursion);
1554d8f6b0edSMasatake YAMATO 
1555d8f6b0edSMasatake YAMATO 	return true;
1556d8f6b0edSMasatake YAMATO }
1557d8f6b0edSMasatake YAMATO 
1558d8f6b0edSMasatake YAMATO static bool
htable_print_entries(const void * key,void * val,void * user_data)1559d8f6b0edSMasatake YAMATO htable_print_entries (const void *key, void *val, void *user_data)
1560d8f6b0edSMasatake YAMATO {
1561d8f6b0edSMasatake YAMATO 	struct htable_print_data *data = user_data;
1562d8f6b0edSMasatake YAMATO 
1563d8f6b0edSMasatake YAMATO 	insert_spaces (data->vm->out, data->vm->print_depth * 2);
1564d8f6b0edSMasatake YAMATO 	htable_print_entry (key, val, user_data);
1565d8f6b0edSMasatake YAMATO 	mio_putc (data->vm->out, '\n');
1566d8f6b0edSMasatake YAMATO 
1567d8f6b0edSMasatake YAMATO 	return true;
1568d8f6b0edSMasatake YAMATO }
1569d8f6b0edSMasatake YAMATO 
1570d8f6b0edSMasatake YAMATO static void
vm_print(OptVM * vm,EsObject * elt)1571d8f6b0edSMasatake YAMATO vm_print (OptVM *vm, EsObject *elt)
1572d8f6b0edSMasatake YAMATO {
1573d8f6b0edSMasatake YAMATO 	vm_print_full (vm, elt, false, 0);
1574d8f6b0edSMasatake YAMATO }
1575d8f6b0edSMasatake YAMATO 
1576d8f6b0edSMasatake YAMATO static void
vm_print_full(OptVM * vm,EsObject * elt,bool string_as_is,int dict_recursion)1577d8f6b0edSMasatake YAMATO vm_print_full(OptVM *vm, EsObject *elt, bool string_as_is, int dict_recursion)
1578d8f6b0edSMasatake YAMATO {
1579d8f6b0edSMasatake YAMATO 	if (es_object_equal (elt, es_true))
1580d8f6b0edSMasatake YAMATO 		mio_puts (vm->out, "true");
1581d8f6b0edSMasatake YAMATO 	else if (es_object_equal (elt, es_false))
1582d8f6b0edSMasatake YAMATO 		mio_puts (vm->out, "false");
1583d8f6b0edSMasatake YAMATO 	else if (es_object_equal (elt, es_nil))
1584d8f6b0edSMasatake YAMATO 		mio_puts (vm->out, "null");
1585d8f6b0edSMasatake YAMATO 	else if (es_error_p (elt))
1586d8f6b0edSMasatake YAMATO 	{
1587d8f6b0edSMasatake YAMATO 		mio_putc (vm->out, '/');
1588d8f6b0edSMasatake YAMATO 		mio_puts (vm->out, es_error_name (elt));
1589d8f6b0edSMasatake YAMATO 	}
1590d8f6b0edSMasatake YAMATO 	else if (es_object_get_type (elt) == OPT_TYPE_DICT)
1591d8f6b0edSMasatake YAMATO 	{
1592d8f6b0edSMasatake YAMATO 		hashTable *d = es_pointer_get (elt);
1593d8f6b0edSMasatake YAMATO 
1594d8f6b0edSMasatake YAMATO 		struct htable_print_data data = {
1595d8f6b0edSMasatake YAMATO 			.vm = vm,
1596d8f6b0edSMasatake YAMATO 			.dict_recursion = dict_recursion - 1,
1597d8f6b0edSMasatake YAMATO 		};
1598d8f6b0edSMasatake YAMATO 
1599d8f6b0edSMasatake YAMATO 		if (dict_recursion)
1600d8f6b0edSMasatake YAMATO 		{
1601d8f6b0edSMasatake YAMATO 			switch (hashTableCountItem (d))
1602d8f6b0edSMasatake YAMATO 			{
1603d8f6b0edSMasatake YAMATO 			case 0:
1604d8f6b0edSMasatake YAMATO 				mio_puts(vm->out, "<<>> ");
1605d8f6b0edSMasatake YAMATO 				break;
1606d8f6b0edSMasatake YAMATO 			case 1:
1607d8f6b0edSMasatake YAMATO 				mio_puts(vm->out, "<<");
1608d8f6b0edSMasatake YAMATO 				hashTableForeachItem (d, htable_print_entry, &data);
1609d8f6b0edSMasatake YAMATO 				mio_puts(vm->out, ">> ");
1610d8f6b0edSMasatake YAMATO 				break;
1611d8f6b0edSMasatake YAMATO 			default:
1612d8f6b0edSMasatake YAMATO 				mio_puts(vm->out, "<<\n");
1613d8f6b0edSMasatake YAMATO 				vm->print_depth++;
1614d8f6b0edSMasatake YAMATO 				hashTableForeachItem (d, htable_print_entries, &data);
1615d8f6b0edSMasatake YAMATO 				vm->print_depth--;
1616d8f6b0edSMasatake YAMATO 				insert_spaces (vm->out, vm->print_depth*2);
1617d8f6b0edSMasatake YAMATO 				mio_puts(vm->out, ">> ");
1618d8f6b0edSMasatake YAMATO 				break;
1619d8f6b0edSMasatake YAMATO 			}
1620d8f6b0edSMasatake YAMATO 		}
1621d8f6b0edSMasatake YAMATO 		else
1622d8f6b0edSMasatake YAMATO 		{
1623d8f6b0edSMasatake YAMATO 			mio_printf (vm->out, "-dict:%u-",
1624d8f6b0edSMasatake YAMATO 						hashTableCountItem (d));
1625d8f6b0edSMasatake YAMATO 		}
1626d8f6b0edSMasatake YAMATO 	}
1627d8f6b0edSMasatake YAMATO 	else if (es_object_get_type (elt) == OPT_TYPE_ARRAY)
1628d8f6b0edSMasatake YAMATO 	{
1629d8f6b0edSMasatake YAMATO 		ArrayFat *afat = (ArrayFat *)es_fatptr_get (elt);
1630d8f6b0edSMasatake YAMATO 		ptrArray *a    = (ptrArray *)es_pointer_get (elt);
1631d8f6b0edSMasatake YAMATO 		unsigned int c = ptrArrayCount (a);
1632d8f6b0edSMasatake YAMATO 		int is_proc = (afat->attr & ATTR_EXECUTABLE)? 1: 0;
1633d8f6b0edSMasatake YAMATO 
1634d8f6b0edSMasatake YAMATO 		mio_putc (vm->out, is_proc? '{': '[');
1635d8f6b0edSMasatake YAMATO 		vm->print_depth += is_proc;
1636d8f6b0edSMasatake YAMATO 		for (unsigned int i = 0; i < c; i++)
1637d8f6b0edSMasatake YAMATO 		{
1638d8f6b0edSMasatake YAMATO 			vm_print_full (vm, (EsObject *)ptrArrayItem (a, i), false, dict_recursion);
1639d8f6b0edSMasatake YAMATO 			if (i != c - 1)
1640d8f6b0edSMasatake YAMATO 				mio_putc (vm->out, ' ');
1641d8f6b0edSMasatake YAMATO 		}
1642d8f6b0edSMasatake YAMATO 		vm->print_depth -= is_proc;
1643d8f6b0edSMasatake YAMATO 		mio_putc (vm->out, is_proc? '}': ']');
1644d8f6b0edSMasatake YAMATO 	}
1645d8f6b0edSMasatake YAMATO 	else if (es_object_get_type (elt) == OPT_TYPE_STRING && string_as_is)
1646d8f6b0edSMasatake YAMATO 	{
1647d8f6b0edSMasatake YAMATO 		const char *cstr = opt_string_get_cstr (elt);
1648d8f6b0edSMasatake YAMATO 		mio_puts (vm->out, cstr);
1649d8f6b0edSMasatake YAMATO 	}
1650d8f6b0edSMasatake YAMATO 	else if ((es_object_get_type (elt) == OPT_TYPE_NAME || es_symbol_p (elt))
1651d8f6b0edSMasatake YAMATO 			 && string_as_is)
1652d8f6b0edSMasatake YAMATO 	{
1653d8f6b0edSMasatake YAMATO 		const char *cstr = opt_name_get_cstr (elt);
1654d8f6b0edSMasatake YAMATO 		mio_puts (vm->out, cstr);
1655d8f6b0edSMasatake YAMATO 	}
1656d8f6b0edSMasatake YAMATO 	else if (es_symbol_p (elt) && (! string_as_is))
1657d8f6b0edSMasatake YAMATO 	{
1658d8f6b0edSMasatake YAMATO 		mio_putc (vm->out, '/');
1659d8f6b0edSMasatake YAMATO 		es_print (elt, vm->out);
1660d8f6b0edSMasatake YAMATO 	}
1661d8f6b0edSMasatake YAMATO 	else
1662d8f6b0edSMasatake YAMATO 		es_print (elt, vm->out);
1663d8f6b0edSMasatake YAMATO }
1664d8f6b0edSMasatake YAMATO 
1665d8f6b0edSMasatake YAMATO static bool
collect_operators(const void * key,void * value,void * user_data)1666d8f6b0edSMasatake YAMATO collect_operators (const void *key, void *value, void *user_data)
1667d8f6b0edSMasatake YAMATO {
1668d8f6b0edSMasatake YAMATO 	ptrArray *a = user_data;
1669d8f6b0edSMasatake YAMATO 	EsObject *op   = value;
1670d8f6b0edSMasatake YAMATO 
1671d8f6b0edSMasatake YAMATO 	if (es_object_get_type (op) == OPT_TYPE_OPERATOR)
1672d8f6b0edSMasatake YAMATO 	{
1673d8f6b0edSMasatake YAMATO 		OperatorFat *ofat = es_fatptr_get (op);
1674d8f6b0edSMasatake YAMATO 		if (ofat->help_str)
1675d8f6b0edSMasatake YAMATO 			ptrArrayAdd (a, op);
1676d8f6b0edSMasatake YAMATO 	}
1677d8f6b0edSMasatake YAMATO 	return true;
1678d8f6b0edSMasatake YAMATO }
1679d8f6b0edSMasatake YAMATO 
1680d8f6b0edSMasatake YAMATO static const char*
callable_get_name(const EsObject * callable)1681d8f6b0edSMasatake YAMATO callable_get_name (const EsObject *callable)
1682d8f6b0edSMasatake YAMATO {
1683d8f6b0edSMasatake YAMATO 	if (es_object_get_type (callable) == OPT_TYPE_OPERATOR)
1684d8f6b0edSMasatake YAMATO 	{
1685d8f6b0edSMasatake YAMATO 		const OperatorFat *ofat_callable = es_fatptr_get (callable);
1686d8f6b0edSMasatake YAMATO 		return es_symbol_get (ofat_callable->name);
1687d8f6b0edSMasatake YAMATO 	}
1688d8f6b0edSMasatake YAMATO 	else
1689d8f6b0edSMasatake YAMATO 		return opt_name_get_cstr(callable);
1690d8f6b0edSMasatake YAMATO }
1691d8f6b0edSMasatake YAMATO 
1692d8f6b0edSMasatake YAMATO static int
compare_callable_by_name(const void * a,const void * b)1693d8f6b0edSMasatake YAMATO compare_callable_by_name (const void *a, const void *b)
1694d8f6b0edSMasatake YAMATO {
1695d8f6b0edSMasatake YAMATO 	const char *str_a = callable_get_name (a);
1696d8f6b0edSMasatake YAMATO 	const char *str_b = callable_get_name (b);
1697d8f6b0edSMasatake YAMATO 
1698d8f6b0edSMasatake YAMATO 	return strcmp (str_a, str_b);
1699d8f6b0edSMasatake YAMATO }
1700d8f6b0edSMasatake YAMATO 
1701d8f6b0edSMasatake YAMATO static void
vm_help(OptVM * vm,MIO * out,struct OptHelpExtender * extop,void * data)1702d8f6b0edSMasatake YAMATO vm_help (OptVM *vm, MIO *out, struct OptHelpExtender *extop, void *data)
1703d8f6b0edSMasatake YAMATO {
1704d8f6b0edSMasatake YAMATO 	unsigned int c = ptrArrayCount (vm->dstack);
1705d8f6b0edSMasatake YAMATO 
1706d8f6b0edSMasatake YAMATO 	ptrArray *a = ptrArrayNew (NULL);
1707d8f6b0edSMasatake YAMATO 	for (unsigned int i = 0; i < c; i++)
1708d8f6b0edSMasatake YAMATO 	{
1709d8f6b0edSMasatake YAMATO 		hashTable *t = es_pointer_get (ptrArrayItem (vm->dstack, i));
1710d8f6b0edSMasatake YAMATO 		hashTableForeachItem (t, collect_operators, a);
1711d8f6b0edSMasatake YAMATO 	}
1712d8f6b0edSMasatake YAMATO 	if (extop)
1713d8f6b0edSMasatake YAMATO 		extop->add (a, data);
1714d8f6b0edSMasatake YAMATO 
1715d8f6b0edSMasatake YAMATO 	ptrArraySort (a, compare_callable_by_name);
1716d8f6b0edSMasatake YAMATO 
1717d8f6b0edSMasatake YAMATO 	unsigned int ca = ptrArrayCount (a);
1718d8f6b0edSMasatake YAMATO 	size_t maxlen = 0;
1719d8f6b0edSMasatake YAMATO 	for (unsigned int i = 0; i < ca; i++)
1720d8f6b0edSMasatake YAMATO 	{
1721d8f6b0edSMasatake YAMATO 		EsObject* obj = ptrArrayItem (a, i);
1722d8f6b0edSMasatake YAMATO 		const char *name = callable_get_name (obj);
1723d8f6b0edSMasatake YAMATO 
1724d8f6b0edSMasatake YAMATO 		size_t l = strlen (name);
1725d8f6b0edSMasatake YAMATO 		if (l > maxlen)
1726d8f6b0edSMasatake YAMATO 			maxlen = l;
1727d8f6b0edSMasatake YAMATO 	}
1728d8f6b0edSMasatake YAMATO 
1729d8f6b0edSMasatake YAMATO 	for (unsigned int i = 0; i < ca; i++)
1730d8f6b0edSMasatake YAMATO 	{
1731d8f6b0edSMasatake YAMATO 		EsObject* obj = ptrArrayItem (a, i);
1732d8f6b0edSMasatake YAMATO 		const char *name = NULL;
1733d8f6b0edSMasatake YAMATO 		const char *help_str_head = NULL;
1734d8f6b0edSMasatake YAMATO 		const char *help_str_original = NULL;
1735d8f6b0edSMasatake YAMATO 
1736d8f6b0edSMasatake YAMATO 		if (es_object_get_type (obj) == OPT_TYPE_OPERATOR)
1737d8f6b0edSMasatake YAMATO 		{
1738d8f6b0edSMasatake YAMATO 			OperatorFat *ofat = es_fatptr_get (obj);
1739d8f6b0edSMasatake YAMATO 			name = es_symbol_get (ofat->name);
1740d8f6b0edSMasatake YAMATO 			help_str_head = ofat->help_str;
1741d8f6b0edSMasatake YAMATO 		}
1742d8f6b0edSMasatake YAMATO 		else if (extop)
1743d8f6b0edSMasatake YAMATO 		{
1744d8f6b0edSMasatake YAMATO 			name = opt_name_get_cstr (obj);
1745d8f6b0edSMasatake YAMATO 			help_str_head = extop->get_help_str (obj, data);
1746d8f6b0edSMasatake YAMATO 		}
1747d8f6b0edSMasatake YAMATO 		help_str_original = help_str_head;
1748d8f6b0edSMasatake YAMATO 
1749d8f6b0edSMasatake YAMATO 		if (name == NULL || help_str_head == NULL)
1750d8f6b0edSMasatake YAMATO 			continue;
1751d8f6b0edSMasatake YAMATO 
1752d8f6b0edSMasatake YAMATO 		while (help_str_head)
1753d8f6b0edSMasatake YAMATO 		{
1754d8f6b0edSMasatake YAMATO 			const char *next = strpbrk (help_str_head, "%\n");
1755d8f6b0edSMasatake YAMATO 			const char *label = (help_str_head == help_str_original)? name: NULL;
1756d8f6b0edSMasatake YAMATO 			if (next)
1757d8f6b0edSMasatake YAMATO 			{
1758d8f6b0edSMasatake YAMATO 				char *tmp = eStrndup (help_str_head, next - help_str_head);
1759d8f6b0edSMasatake YAMATO 				bool desc = (tmp[0] == ':');
1760d8f6b0edSMasatake YAMATO 				mio_printf (out, "%*s%s%s\n",
1761d8f6b0edSMasatake YAMATO 							(int)maxlen, label? label: "",
1762d8f6b0edSMasatake YAMATO 							((desc || (label == NULL))? "		": "	->	"),
1763d8f6b0edSMasatake YAMATO 							(desc? tmp + 1: tmp));
1764d8f6b0edSMasatake YAMATO 				eFree ((char *)tmp);
1765d8f6b0edSMasatake YAMATO 				help_str_head = next + 1;
1766d8f6b0edSMasatake YAMATO 				while (*help_str_head && isspace ((unsigned char)*help_str_head))
1767d8f6b0edSMasatake YAMATO 					help_str_head++;
1768d8f6b0edSMasatake YAMATO 			}
1769d8f6b0edSMasatake YAMATO 			else
1770d8f6b0edSMasatake YAMATO 			{
1771d8f6b0edSMasatake YAMATO 				if (*help_str_head != '\0')
1772d8f6b0edSMasatake YAMATO 				{
1773d8f6b0edSMasatake YAMATO 					bool desc = (help_str_head[0] == ':');
1774d8f6b0edSMasatake YAMATO 					mio_printf (out, "%*s%s%s\n",
1775d8f6b0edSMasatake YAMATO 								(int)maxlen, label? label: "",
1776d8f6b0edSMasatake YAMATO 								((desc || (label == NULL))? "		": "	->	"),
1777d8f6b0edSMasatake YAMATO 								(desc? help_str_head + 1: help_str_head));
1778d8f6b0edSMasatake YAMATO 				}
1779d8f6b0edSMasatake YAMATO 				help_str_head = NULL;
1780d8f6b0edSMasatake YAMATO 			}
1781d8f6b0edSMasatake YAMATO 		}
1782d8f6b0edSMasatake YAMATO 	}
1783d8f6b0edSMasatake YAMATO 
1784d8f6b0edSMasatake YAMATO 	ptrArrayDelete (a);
1785d8f6b0edSMasatake YAMATO }
1786d8f6b0edSMasatake YAMATO 
1787d8f6b0edSMasatake YAMATO static EsObject *
array_new_from_stack(ptrArray * src)1788d8f6b0edSMasatake YAMATO array_new_from_stack (ptrArray *src)
1789d8f6b0edSMasatake YAMATO {
1790d8f6b0edSMasatake YAMATO 	EsObject *dst = array_new (0);
1791d8f6b0edSMasatake YAMATO 	ptrArray *a = (ptrArray *)es_pointer_get (dst);
1792d8f6b0edSMasatake YAMATO 	for (unsigned int i = 0; i < ptrArrayCount(src); i++)
1793d8f6b0edSMasatake YAMATO 		ptrArrayAdd (a, es_object_ref (ptrArrayItem (src, i)));
1794d8f6b0edSMasatake YAMATO 	return dst;
1795d8f6b0edSMasatake YAMATO }
1796d8f6b0edSMasatake YAMATO 
1797d8f6b0edSMasatake YAMATO static void
vm_record_stop(OptVM * vm,EsObject * cmd)1798d8f6b0edSMasatake YAMATO vm_record_stop   (OptVM *vm, EsObject *cmd)
1799d8f6b0edSMasatake YAMATO {
1800d8f6b0edSMasatake YAMATO 	dict_op_def (vm->error, OPT_KEY_command, cmd);
1801d8f6b0edSMasatake YAMATO 	dict_op_def (vm->error, OPT_KEY_errorname, es_nil);
1802d8f6b0edSMasatake YAMATO 	dict_op_def (vm->error, OPT_KEY_newerror, es_false);
1803d8f6b0edSMasatake YAMATO 	/* OPT_KEY_{o,e,o}stack are kept as is. */
1804d8f6b0edSMasatake YAMATO }
1805d8f6b0edSMasatake YAMATO 
1806d8f6b0edSMasatake YAMATO static void
vm_record_error(OptVM * vm,EsObject * e,EsObject * cmd)1807d8f6b0edSMasatake YAMATO vm_record_error  (OptVM *vm, EsObject *e, EsObject *cmd)
1808d8f6b0edSMasatake YAMATO {
1809d8f6b0edSMasatake YAMATO 	EsObject *newerror = es_nil;
1810d8f6b0edSMasatake YAMATO 	if (dict_op_known_and_get (vm->error, OPT_KEY_newerror, &newerror)
1811d8f6b0edSMasatake YAMATO 		&& es_object_equal (newerror, es_true))
1812d8f6b0edSMasatake YAMATO 		return;
1813d8f6b0edSMasatake YAMATO 
1814d8f6b0edSMasatake YAMATO 	dict_op_def (vm->error, OPT_KEY_newerror, es_true);
1815d8f6b0edSMasatake YAMATO 	dict_op_def (vm->error, OPT_KEY_errorname, e);
1816d8f6b0edSMasatake YAMATO 	dict_op_def (vm->error, OPT_KEY_command, cmd);
1817d8f6b0edSMasatake YAMATO 
1818d8f6b0edSMasatake YAMATO 	EsObject *a;
1819d8f6b0edSMasatake YAMATO 
1820d8f6b0edSMasatake YAMATO 	a = array_new_from_stack (vm->ostack);
1821d8f6b0edSMasatake YAMATO 	dict_op_def (vm->error, OPT_KEY_ostack, a);
1822d8f6b0edSMasatake YAMATO 	es_object_unref (a);
1823d8f6b0edSMasatake YAMATO 
1824d8f6b0edSMasatake YAMATO 	a = array_new_from_stack (vm->estack);
1825d8f6b0edSMasatake YAMATO 	dict_op_def (vm->error, OPT_KEY_estack, a);
1826d8f6b0edSMasatake YAMATO 	es_object_unref (a);
1827d8f6b0edSMasatake YAMATO 
1828d8f6b0edSMasatake YAMATO 	a = array_new_from_stack (vm->dstack);
1829d8f6b0edSMasatake YAMATO 	dict_op_def (vm->error, OPT_KEY_dstack, a);
1830d8f6b0edSMasatake YAMATO 	es_object_unref (a);
1831d8f6b0edSMasatake YAMATO }
1832d8f6b0edSMasatake YAMATO 
1833d8f6b0edSMasatake YAMATO static void
vm_report_error(OptVM * vm,EsObject * e)1834d8f6b0edSMasatake YAMATO vm_report_error (OptVM *vm, EsObject *e)
1835d8f6b0edSMasatake YAMATO {
1836d8f6b0edSMasatake YAMATO 	MIO *out = vm->out;
1837d8f6b0edSMasatake YAMATO 	vm->out = vm->err;
1838d8f6b0edSMasatake YAMATO 	mio_puts (vm->err, "Error: ");
1839d8f6b0edSMasatake YAMATO 
1840d8f6b0edSMasatake YAMATO 	EsObject *newerror = es_nil;
1841d8f6b0edSMasatake YAMATO 	if (!dict_op_known_and_get (vm->error, OPT_KEY_newerror, &newerror))
1842d8f6b0edSMasatake YAMATO 	{
1843d8f6b0edSMasatake YAMATO 		vm_print (vm, e);
1844d8f6b0edSMasatake YAMATO 		mio_putc (vm->err, '\n');
1845d8f6b0edSMasatake YAMATO 		goto out;
1846d8f6b0edSMasatake YAMATO 	}
1847d8f6b0edSMasatake YAMATO 
1848d8f6b0edSMasatake YAMATO 	if (es_object_equal (newerror, es_false))
1849d8f6b0edSMasatake YAMATO 	{
1850d8f6b0edSMasatake YAMATO 		vm_print (vm, e);
1851d8f6b0edSMasatake YAMATO 		mio_putc (vm->err, '\n');
1852d8f6b0edSMasatake YAMATO 		goto out;
1853d8f6b0edSMasatake YAMATO 	}
1854d8f6b0edSMasatake YAMATO 
1855d8f6b0edSMasatake YAMATO 	if (!dict_op_known_and_get (vm->error, OPT_KEY_errorname, &e))
1856d8f6b0edSMasatake YAMATO 	{
1857d8f6b0edSMasatake YAMATO 		vm_print (vm, OPT_ERR_INTERNALERROR);
1858d8f6b0edSMasatake YAMATO 		mio_putc (vm->err, '\n');
1859d8f6b0edSMasatake YAMATO 		goto out;
1860d8f6b0edSMasatake YAMATO 	}
1861d8f6b0edSMasatake YAMATO 
1862d8f6b0edSMasatake YAMATO 	vm_print (vm, e);
1863d8f6b0edSMasatake YAMATO 
1864d8f6b0edSMasatake YAMATO 	EsObject *command = es_nil;
1865d8f6b0edSMasatake YAMATO 	dict_op_known_and_get (vm->error, OPT_KEY_command, &command);
1866d8f6b0edSMasatake YAMATO 	EsObject *attached_object = es_error_get_object (e);
1867d8f6b0edSMasatake YAMATO 
1868d8f6b0edSMasatake YAMATO 	if (!es_null (attached_object))
1869d8f6b0edSMasatake YAMATO 	{
1870d8f6b0edSMasatake YAMATO 		mio_puts (vm->err, " in ");
1871d8f6b0edSMasatake YAMATO 		vm_print (vm, attached_object);
1872d8f6b0edSMasatake YAMATO 	}
1873d8f6b0edSMasatake YAMATO 	else if (!es_null (command))
1874d8f6b0edSMasatake YAMATO 	{
1875d8f6b0edSMasatake YAMATO 		mio_puts (vm->err, " in ");
1876d8f6b0edSMasatake YAMATO 		vm_print (vm, command);
1877d8f6b0edSMasatake YAMATO 		command = es_nil;
1878d8f6b0edSMasatake YAMATO 	}
1879d8f6b0edSMasatake YAMATO 	mio_putc (vm->err, '\n');
1880d8f6b0edSMasatake YAMATO 
1881d8f6b0edSMasatake YAMATO 	EsObject *ostack = es_nil;
1882d8f6b0edSMasatake YAMATO 	if (dict_op_known_and_get (vm->error, OPT_KEY_ostack, &ostack))
1883d8f6b0edSMasatake YAMATO 	{
1884d8f6b0edSMasatake YAMATO 		mio_puts (vm->err, "Operand stack:\n");
1885d8f6b0edSMasatake YAMATO 		mio_puts (vm->err, "top|");
1886d8f6b0edSMasatake YAMATO 		ptrArray *a = es_pointer_get (ostack);
1887d8f6b0edSMasatake YAMATO 		for (unsigned int i = ptrArrayCount (a); i > 0; i--)
1888d8f6b0edSMasatake YAMATO 		{
1889d8f6b0edSMasatake YAMATO 			EsObject *o = ptrArrayItem (a, i - 1);
1890d8f6b0edSMasatake YAMATO 			mio_puts (vm->err, "   ");
1891d8f6b0edSMasatake YAMATO 			vm_print (vm, o);
1892d8f6b0edSMasatake YAMATO 		}
1893d8f6b0edSMasatake YAMATO 	}
1894d8f6b0edSMasatake YAMATO 	mio_puts (vm->err, "   |bottom\n");
1895d8f6b0edSMasatake YAMATO 
1896d8f6b0edSMasatake YAMATO 	EsObject *estack = es_nil;
1897d8f6b0edSMasatake YAMATO 	if (dict_op_known_and_get (vm->error, OPT_KEY_estack, &estack))
1898d8f6b0edSMasatake YAMATO 	{
1899d8f6b0edSMasatake YAMATO 		mio_puts (vm->err, "Execution stack:\n");
1900d8f6b0edSMasatake YAMATO 		mio_puts (vm->err, "top|");
1901d8f6b0edSMasatake YAMATO 
1902d8f6b0edSMasatake YAMATO 		if (!es_null (command))
1903d8f6b0edSMasatake YAMATO 		{
1904d8f6b0edSMasatake YAMATO 			mio_puts (vm->err, "   ");
1905d8f6b0edSMasatake YAMATO 			vm_print (vm, command);
1906d8f6b0edSMasatake YAMATO 		}
1907d8f6b0edSMasatake YAMATO 
1908d8f6b0edSMasatake YAMATO 		ptrArray *a = es_pointer_get (estack);
1909d8f6b0edSMasatake YAMATO 		for (unsigned int i = ptrArrayCount (a); i > 0; i--)
1910d8f6b0edSMasatake YAMATO 		{
1911d8f6b0edSMasatake YAMATO 			EsObject *o = ptrArrayItem (a, i - 1);
1912d8f6b0edSMasatake YAMATO 			mio_puts (vm->err, "   ");
1913d8f6b0edSMasatake YAMATO 			vm_print (vm, o);
1914d8f6b0edSMasatake YAMATO 		}
1915d8f6b0edSMasatake YAMATO 	}
1916d8f6b0edSMasatake YAMATO 	mio_puts (vm->err, "   |bottom\n");
1917d8f6b0edSMasatake YAMATO 
1918d8f6b0edSMasatake YAMATO 	EsObject *dstack = es_nil;
1919d8f6b0edSMasatake YAMATO 	if (dict_op_known_and_get (vm->error, OPT_KEY_dstack, &dstack))
1920d8f6b0edSMasatake YAMATO 	{
1921d8f6b0edSMasatake YAMATO 		mio_puts (vm->err, "Dictionary stack:\n");
1922d8f6b0edSMasatake YAMATO 		mio_puts (vm->err, "top|");
1923d8f6b0edSMasatake YAMATO 		ptrArray *a = es_pointer_get (dstack);
1924d8f6b0edSMasatake YAMATO 		for (unsigned int i = ptrArrayCount (a); i > 0; i--)
1925d8f6b0edSMasatake YAMATO 		{
1926d8f6b0edSMasatake YAMATO 			EsObject *o = ptrArrayItem (a, i - 1);
1927d8f6b0edSMasatake YAMATO 			mio_puts (vm->err, "   ");
1928d8f6b0edSMasatake YAMATO 			vm_print (vm, o);
1929d8f6b0edSMasatake YAMATO 		}
1930d8f6b0edSMasatake YAMATO 	}
1931d8f6b0edSMasatake YAMATO 	mio_puts (vm->err, "   |bottom\n");
1932d8f6b0edSMasatake YAMATO 
1933d8f6b0edSMasatake YAMATO  out:
1934d8f6b0edSMasatake YAMATO 	dict_op_def (vm->error, OPT_KEY_newerror, es_false);
1935d8f6b0edSMasatake YAMATO 	vm->out = out;
1936d8f6b0edSMasatake YAMATO }
1937d8f6b0edSMasatake YAMATO 
1938d8f6b0edSMasatake YAMATO static void
vm_bind_proc(OptVM * vm,ptrArray * proc)1939d8f6b0edSMasatake YAMATO vm_bind_proc (OptVM *vm, ptrArray *proc)
1940d8f6b0edSMasatake YAMATO {
1941d8f6b0edSMasatake YAMATO 	unsigned int c = ptrArrayCount (proc);
1942d8f6b0edSMasatake YAMATO 	for (unsigned int i = 0; i < c; i++)
1943d8f6b0edSMasatake YAMATO 	{
1944d8f6b0edSMasatake YAMATO 		EsObject *x = ptrArrayItem (proc, i);
1945d8f6b0edSMasatake YAMATO 
1946d8f6b0edSMasatake YAMATO 		if (es_object_get_type (x) == OPT_TYPE_ARRAY)
1947d8f6b0edSMasatake YAMATO 			vm_bind_proc (vm, es_pointer_get (x));
1948d8f6b0edSMasatake YAMATO 		else if (es_object_get_type (x) == OPT_TYPE_NAME)
1949d8f6b0edSMasatake YAMATO 		{
1950d8f6b0edSMasatake YAMATO 			if (!(((NameFat *)es_fatptr_get (x))->attr
1951d8f6b0edSMasatake YAMATO 				  & ATTR_EXECUTABLE))
1952d8f6b0edSMasatake YAMATO 				continue;
1953d8f6b0edSMasatake YAMATO 
1954d8f6b0edSMasatake YAMATO 			EsObject* val = NULL;
1955d8f6b0edSMasatake YAMATO 			EsObject *r = vm_dstack_known_and_get (vm, x, &val);
1956d8f6b0edSMasatake YAMATO 			if (es_object_get_type (r) == OPT_TYPE_DICT)
1957d8f6b0edSMasatake YAMATO 			{
1958d8f6b0edSMasatake YAMATO 				if (es_object_get_type (val) == OPT_TYPE_OPERATOR)
1959d8f6b0edSMasatake YAMATO 					ptrArrayUpdate (proc, i, es_object_ref (val), es_nil);
1960d8f6b0edSMasatake YAMATO 			}
1961d8f6b0edSMasatake YAMATO 		}
1962d8f6b0edSMasatake YAMATO 	}
1963d8f6b0edSMasatake YAMATO }
1964d8f6b0edSMasatake YAMATO 
1965d8f6b0edSMasatake YAMATO 
1966d8f6b0edSMasatake YAMATO /*
1967d8f6b0edSMasatake YAMATO  * Array
1968d8f6b0edSMasatake YAMATO  */
1969d8f6b0edSMasatake YAMATO static EsObject*
array_new(unsigned int attr)1970d8f6b0edSMasatake YAMATO array_new (unsigned int attr)
1971d8f6b0edSMasatake YAMATO {
1972d8f6b0edSMasatake YAMATO 	ptrArray *a = ptrArrayNew ((ptrArrayDeleteFunc)es_object_unref);
1973d8f6b0edSMasatake YAMATO 	return es_fatptr_new  (OPT_TYPE_ARRAY, a, &attr);
1974d8f6b0edSMasatake YAMATO }
1975d8f6b0edSMasatake YAMATO 
1976d8f6b0edSMasatake YAMATO static EsObject*
array_es_init_fat(void * fat,void * ptr,void * extra)1977d8f6b0edSMasatake YAMATO array_es_init_fat (void *fat, void *ptr, void *extra)
1978d8f6b0edSMasatake YAMATO {
1979d8f6b0edSMasatake YAMATO 	ArrayFat *a = fat;
1980d8f6b0edSMasatake YAMATO 	a->attr = *((unsigned int *)extra);
1981d8f6b0edSMasatake YAMATO 	return es_false;
1982d8f6b0edSMasatake YAMATO }
1983d8f6b0edSMasatake YAMATO 
1984d8f6b0edSMasatake YAMATO static void
array_es_free(void * ptr,void * fat)1985d8f6b0edSMasatake YAMATO array_es_free (void *ptr, void *fat)
1986d8f6b0edSMasatake YAMATO {
1987d8f6b0edSMasatake YAMATO 	if (ptr)
1988d8f6b0edSMasatake YAMATO 		ptrArrayDelete ((ptrArray *)ptr);
1989d8f6b0edSMasatake YAMATO }
1990d8f6b0edSMasatake YAMATO 
1991d8f6b0edSMasatake YAMATO static int
array_es_equal(const void * a,const void * afat,const void * b,const void * bfat)1992d8f6b0edSMasatake YAMATO array_es_equal (const void *a, const void *afat, const void *b, const void *bfat)
1993d8f6b0edSMasatake YAMATO {
1994d8f6b0edSMasatake YAMATO 	if (((ArrayFat *)afat)->attr != ((ArrayFat *)bfat)->attr)
1995d8f6b0edSMasatake YAMATO 		return 0;
1996d8f6b0edSMasatake YAMATO 
1997d8f6b0edSMasatake YAMATO 	if (ptrArrayIsEmpty ((ptrArray *)a) && ptrArrayIsEmpty ((ptrArray*)b))
1998d8f6b0edSMasatake YAMATO 		return 1;
1999d8f6b0edSMasatake YAMATO 	else if (a == b)
2000d8f6b0edSMasatake YAMATO 		return 1;
2001d8f6b0edSMasatake YAMATO 	else
2002d8f6b0edSMasatake YAMATO 		return 0;
2003d8f6b0edSMasatake YAMATO }
2004d8f6b0edSMasatake YAMATO 
2005d8f6b0edSMasatake YAMATO static void
array_es_print(const void * ptr,const void * fat,MIO * out)2006d8f6b0edSMasatake YAMATO array_es_print (const void *ptr, const void *fat, MIO *out)
2007d8f6b0edSMasatake YAMATO {
2008d8f6b0edSMasatake YAMATO 	unsigned int c = ptrArrayCount ((ptrArray *)ptr);
2009d8f6b0edSMasatake YAMATO 	ArrayFat *a = (ArrayFat *)fat;
2010d8f6b0edSMasatake YAMATO 	mio_printf (out, "%c%c%c count: %u",
2011d8f6b0edSMasatake YAMATO 				(a->attr & ATTR_READABLE)  ? 'r': '-',
2012d8f6b0edSMasatake YAMATO 				(a->attr & ATTR_WRITABLE)  ? 'w': '-',
2013d8f6b0edSMasatake YAMATO 				(a->attr & ATTR_EXECUTABLE)? 'x': '-',
2014d8f6b0edSMasatake YAMATO 				c);
2015d8f6b0edSMasatake YAMATO }
2016d8f6b0edSMasatake YAMATO 
2017d8f6b0edSMasatake YAMATO static void
array_op_add(EsObject * array,EsObject * elt)2018d8f6b0edSMasatake YAMATO array_op_add (EsObject* array, EsObject* elt)
2019d8f6b0edSMasatake YAMATO {
2020d8f6b0edSMasatake YAMATO 	ptrArray *a = es_pointer_get (array);
2021d8f6b0edSMasatake YAMATO 	ptrArrayAdd (a, es_object_ref (elt));
2022d8f6b0edSMasatake YAMATO }
2023d8f6b0edSMasatake YAMATO 
2024d8f6b0edSMasatake YAMATO static unsigned int
array_op_length(const EsObject * array)2025d8f6b0edSMasatake YAMATO array_op_length (const EsObject* array)
2026d8f6b0edSMasatake YAMATO {
2027d8f6b0edSMasatake YAMATO 	ptrArray *a = es_pointer_get (array);
2028d8f6b0edSMasatake YAMATO 	return ptrArrayCount (a);
2029d8f6b0edSMasatake YAMATO }
2030d8f6b0edSMasatake YAMATO 
2031d8f6b0edSMasatake YAMATO static EsObject*
array_op_get(const EsObject * array,unsigned int n)2032d8f6b0edSMasatake YAMATO array_op_get (const EsObject* array, unsigned int n)
2033d8f6b0edSMasatake YAMATO {
2034d8f6b0edSMasatake YAMATO 	ptrArray *a = es_pointer_get (array);
2035d8f6b0edSMasatake YAMATO 	unsigned int len = ptrArrayCount (a);
2036d8f6b0edSMasatake YAMATO 	if (n >= len)
2037d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
2038d8f6b0edSMasatake YAMATO 	return ptrArrayItem (a, n);
2039d8f6b0edSMasatake YAMATO }
2040d8f6b0edSMasatake YAMATO 
2041d8f6b0edSMasatake YAMATO static void
array_op_put(EsObject * array,unsigned int n,EsObject * obj)2042d8f6b0edSMasatake YAMATO array_op_put (EsObject* array, unsigned int n, EsObject *obj)
2043d8f6b0edSMasatake YAMATO {
2044d8f6b0edSMasatake YAMATO 	ptrArray *a = es_pointer_get (array);
2045d8f6b0edSMasatake YAMATO 	ptrArrayUpdate (a, n,
2046d8f6b0edSMasatake YAMATO 					es_object_ref (obj), es_nil);
2047d8f6b0edSMasatake YAMATO }
2048d8f6b0edSMasatake YAMATO 
2049d8f6b0edSMasatake YAMATO 
2050d8f6b0edSMasatake YAMATO /*
2051d8f6b0edSMasatake YAMATO  * Dictionary
2052d8f6b0edSMasatake YAMATO  */
2053d8f6b0edSMasatake YAMATO static unsigned int
opt_es_hash(const void * const key)2054d8f6b0edSMasatake YAMATO opt_es_hash (const void * const key)
2055d8f6b0edSMasatake YAMATO {
2056d8f6b0edSMasatake YAMATO 	const EsObject *k = key;
2057d8f6b0edSMasatake YAMATO 
2058d8f6b0edSMasatake YAMATO 	if (es_integer_p (key))
2059d8f6b0edSMasatake YAMATO 		return hashInthash (key);
206089d6b969SMasatake YAMATO 	else if (es_boolean_p (key))
206189d6b969SMasatake YAMATO 		return es_object_equal (key, es_true)? 1: 0;
2062d8f6b0edSMasatake YAMATO 
2063d8f6b0edSMasatake YAMATO 	return hashPtrhash (k);
2064d8f6b0edSMasatake YAMATO }
2065d8f6b0edSMasatake YAMATO 
2066d8f6b0edSMasatake YAMATO static bool
opt_es_eq(const void * a,const void * b)2067d8f6b0edSMasatake YAMATO opt_es_eq (const void* a, const void* b)
2068d8f6b0edSMasatake YAMATO {
2069d8f6b0edSMasatake YAMATO 	return es_object_equal (a, b);
2070d8f6b0edSMasatake YAMATO }
2071d8f6b0edSMasatake YAMATO 
2072d8f6b0edSMasatake YAMATO static EsObject*
dict_new(unsigned int size,unsigned int attr)2073d8f6b0edSMasatake YAMATO dict_new (unsigned int size, unsigned int attr)
2074d8f6b0edSMasatake YAMATO {
2075d8f6b0edSMasatake YAMATO 	hashTable *t = hashTableNew (size,
2076d8f6b0edSMasatake YAMATO 								 opt_es_hash,
2077d8f6b0edSMasatake YAMATO 								 opt_es_eq,
2078d8f6b0edSMasatake YAMATO 								 (hashTableDeleteFunc)es_object_unref,
2079d8f6b0edSMasatake YAMATO 								 (hashTableDeleteFunc)es_object_unref);
2080d8f6b0edSMasatake YAMATO 	hashTableSetValueForUnknownKey (t, t, NULL);
2081d8f6b0edSMasatake YAMATO 	return es_fatptr_new  (OPT_TYPE_DICT, t, &attr);
2082d8f6b0edSMasatake YAMATO }
2083d8f6b0edSMasatake YAMATO 
2084d8f6b0edSMasatake YAMATO static EsObject*
dict_es_init_fat(void * fat,void * ptr,void * extra)2085d8f6b0edSMasatake YAMATO dict_es_init_fat (void *fat, void *ptr, void *extra)
2086d8f6b0edSMasatake YAMATO {
2087d8f6b0edSMasatake YAMATO 	DictFat *a = fat;
2088d8f6b0edSMasatake YAMATO 	a->attr = *((unsigned int *)extra);
2089d8f6b0edSMasatake YAMATO 	return es_false;
2090d8f6b0edSMasatake YAMATO }
2091d8f6b0edSMasatake YAMATO 
2092d8f6b0edSMasatake YAMATO static void
dict_es_free(void * ptr,void * fat)2093d8f6b0edSMasatake YAMATO dict_es_free (void *ptr, void *fat)
2094d8f6b0edSMasatake YAMATO {
2095d8f6b0edSMasatake YAMATO 	if (ptr)
2096d8f6b0edSMasatake YAMATO 		hashTableDelete ((hashTable *)ptr);
2097d8f6b0edSMasatake YAMATO }
2098d8f6b0edSMasatake YAMATO 
2099d8f6b0edSMasatake YAMATO static int
dict_es_equal(const void * a,const void * afat,const void * b,const void * bfat)2100d8f6b0edSMasatake YAMATO dict_es_equal (const void *a, const void *afat, const void *b, const void *bfat)
2101d8f6b0edSMasatake YAMATO {
2102d8f6b0edSMasatake YAMATO 	if (a == b)
2103d8f6b0edSMasatake YAMATO 		return 1;
2104d8f6b0edSMasatake YAMATO 	return 0;
2105d8f6b0edSMasatake YAMATO }
2106d8f6b0edSMasatake YAMATO 
2107d8f6b0edSMasatake YAMATO static void
dict_es_print(const void * ptr,const void * fat,MIO * out)2108d8f6b0edSMasatake YAMATO dict_es_print (const void *ptr, const void *fat, MIO *out)
2109d8f6b0edSMasatake YAMATO {
2110d8f6b0edSMasatake YAMATO 	unsigned int c = hashTableCountItem ((hashTable *)ptr);
2111d8f6b0edSMasatake YAMATO 	DictFat *a = (DictFat *)fat;
2112d8f6b0edSMasatake YAMATO 	mio_printf (out, "%c%c%c count: %u",
2113d8f6b0edSMasatake YAMATO 				(a->attr & ATTR_READABLE)  ? 'r': '-',
2114d8f6b0edSMasatake YAMATO 				(a->attr & ATTR_WRITABLE)  ? 'w': '-',
2115d8f6b0edSMasatake YAMATO 				(a->attr & ATTR_EXECUTABLE)? 'x': '-',
2116d8f6b0edSMasatake YAMATO 				c);
2117d8f6b0edSMasatake YAMATO }
2118d8f6b0edSMasatake YAMATO 
2119d8f6b0edSMasatake YAMATO static void
dict_op_def(EsObject * dict,EsObject * key,EsObject * val)2120d8f6b0edSMasatake YAMATO dict_op_def (EsObject* dict, EsObject *key, EsObject *val)
2121d8f6b0edSMasatake YAMATO {
2122d8f6b0edSMasatake YAMATO 	hashTable *t = es_pointer_get (dict);
2123d8f6b0edSMasatake YAMATO 	Assert (t);
2124d8f6b0edSMasatake YAMATO 	Assert (!es_null (key));
2125d8f6b0edSMasatake YAMATO 
2126d8f6b0edSMasatake YAMATO 	if (es_object_get_type (key) == OPT_TYPE_NAME)
2127d8f6b0edSMasatake YAMATO 		key = es_pointer_get (key);
2128d8f6b0edSMasatake YAMATO 
2129d8f6b0edSMasatake YAMATO 	key = es_object_ref (key);
2130d8f6b0edSMasatake YAMATO 	val = es_object_ref (val);
2131d8f6b0edSMasatake YAMATO 
2132d8f6b0edSMasatake YAMATO 	hashTableUpdateItem (t, key, val);
2133d8f6b0edSMasatake YAMATO }
2134d8f6b0edSMasatake YAMATO 
2135d8f6b0edSMasatake YAMATO static bool
dict_op_undef(EsObject * dict,EsObject * key)2136d8f6b0edSMasatake YAMATO dict_op_undef (EsObject *dict, EsObject *key)
2137d8f6b0edSMasatake YAMATO {
2138d8f6b0edSMasatake YAMATO 	hashTable *t = es_pointer_get (dict);
2139d8f6b0edSMasatake YAMATO 	Assert (t);
2140d8f6b0edSMasatake YAMATO 
2141d8f6b0edSMasatake YAMATO 	if (es_object_get_type (key) == OPT_TYPE_NAME)
2142d8f6b0edSMasatake YAMATO 		key = es_pointer_get (key);
2143d8f6b0edSMasatake YAMATO 
2144d8f6b0edSMasatake YAMATO 	/* TODO: handle the case key == NULL */
2145d8f6b0edSMasatake YAMATO 	return hashTableDeleteItem (t, key);
2146d8f6b0edSMasatake YAMATO }
2147d8f6b0edSMasatake YAMATO 
2148d8f6b0edSMasatake YAMATO static bool
dict_op_known_and_get(EsObject * dict,EsObject * key,EsObject ** val)2149d8f6b0edSMasatake YAMATO dict_op_known_and_get(EsObject* dict, EsObject *key, EsObject **val)
2150d8f6b0edSMasatake YAMATO {
2151d8f6b0edSMasatake YAMATO 	hashTable *t = es_pointer_get (dict);
2152d8f6b0edSMasatake YAMATO 	Assert (t);
2153d8f6b0edSMasatake YAMATO 
215489d6b969SMasatake YAMATO 	if (es_object_get_type (key) == OPT_TYPE_STRING)
215589d6b969SMasatake YAMATO 	{
215689d6b969SMasatake YAMATO 		const char * cstr = opt_string_get_cstr (key);
215789d6b969SMasatake YAMATO 		key = es_symbol_intern (cstr);
215889d6b969SMasatake YAMATO 	}
215989d6b969SMasatake YAMATO 
2160d8f6b0edSMasatake YAMATO 	if (es_object_get_type (key) == OPT_TYPE_NAME)
2161d8f6b0edSMasatake YAMATO 		key = es_pointer_get (key);
2162d8f6b0edSMasatake YAMATO 
2163d8f6b0edSMasatake YAMATO 	void *tmp = hashTableGetItem (t, key);
2164d8f6b0edSMasatake YAMATO 	if (tmp == t)
2165d8f6b0edSMasatake YAMATO 		return false;
2166d8f6b0edSMasatake YAMATO 
2167d8f6b0edSMasatake YAMATO 	if (val)
2168d8f6b0edSMasatake YAMATO 		*val = tmp;
2169d8f6b0edSMasatake YAMATO 	return true;
2170d8f6b0edSMasatake YAMATO }
2171d8f6b0edSMasatake YAMATO 
2172d8f6b0edSMasatake YAMATO static void
dict_op_clear(EsObject * dict)2173d8f6b0edSMasatake YAMATO dict_op_clear (EsObject* dict)
2174d8f6b0edSMasatake YAMATO {
2175d8f6b0edSMasatake YAMATO 	hashTable *h = es_pointer_get (dict);
2176d8f6b0edSMasatake YAMATO 	Assert (h);
2177d8f6b0edSMasatake YAMATO 
2178d8f6b0edSMasatake YAMATO 	hashTableClear (h);
2179d8f6b0edSMasatake YAMATO }
2180d8f6b0edSMasatake YAMATO 
2181d8f6b0edSMasatake YAMATO 
2182d8f6b0edSMasatake YAMATO /*
2183d8f6b0edSMasatake YAMATO  * Operator
2184d8f6b0edSMasatake YAMATO  */
2185d8f6b0edSMasatake YAMATO static EsObject*
operator_new(Operator op,const char * name,int arity,const char * help_str)2186d8f6b0edSMasatake YAMATO operator_new (Operator op, const char *name, int arity, const char *help_str)
2187d8f6b0edSMasatake YAMATO {
2188d8f6b0edSMasatake YAMATO 	OperatorExtra extra = { .name = name, .arity = arity, .help_str = help_str };
2189d8f6b0edSMasatake YAMATO 	return es_fatptr_new (OPT_TYPE_OPERATOR, op, &extra);
2190d8f6b0edSMasatake YAMATO }
2191d8f6b0edSMasatake YAMATO 
2192d8f6b0edSMasatake YAMATO static EsObject*
operator_es_init_fat(void * fat,void * ptr,void * extra)2193d8f6b0edSMasatake YAMATO operator_es_init_fat (void *fat, void *ptr, void *extra)
2194d8f6b0edSMasatake YAMATO {
2195d8f6b0edSMasatake YAMATO 	OperatorFat *ofat = fat;
2196d8f6b0edSMasatake YAMATO 
2197d8f6b0edSMasatake YAMATO 	if (!extra)
2198d8f6b0edSMasatake YAMATO 	{
2199d8f6b0edSMasatake YAMATO 		ofat->name = NULL;
2200d8f6b0edSMasatake YAMATO 		return es_true;
2201d8f6b0edSMasatake YAMATO 	}
2202d8f6b0edSMasatake YAMATO 
2203d8f6b0edSMasatake YAMATO 	OperatorExtra *oextra = extra;
2204d8f6b0edSMasatake YAMATO 	const char *name = oextra->name;
2205d8f6b0edSMasatake YAMATO 	EsObject *o = es_symbol_intern (name);
2206d8f6b0edSMasatake YAMATO 
2207d8f6b0edSMasatake YAMATO 	if (es_error_p (o))
2208d8f6b0edSMasatake YAMATO 		return o;
2209d8f6b0edSMasatake YAMATO 	ofat->name = o;
2210d8f6b0edSMasatake YAMATO 	ofat->arity = oextra->arity;
2211d8f6b0edSMasatake YAMATO 	ofat->help_str = oextra->help_str? eStrdup (oextra->help_str): NULL;
2212d8f6b0edSMasatake YAMATO 	return es_true;
2213d8f6b0edSMasatake YAMATO }
2214d8f6b0edSMasatake YAMATO 
2215d8f6b0edSMasatake YAMATO static void
operator_es_free(void * ptr,void * fat)2216d8f6b0edSMasatake YAMATO operator_es_free  (void *ptr, void *fat)
2217d8f6b0edSMasatake YAMATO {
2218d8f6b0edSMasatake YAMATO 	OperatorFat *ofat = fat;
2219d8f6b0edSMasatake YAMATO 	if (ofat->help_str)
2220d8f6b0edSMasatake YAMATO 		eFree ((char *)ofat->help_str);
2221d8f6b0edSMasatake YAMATO }
2222d8f6b0edSMasatake YAMATO 
2223d8f6b0edSMasatake YAMATO static void
operator_es_print(const void * ptr,const void * fat,MIO * out)2224d8f6b0edSMasatake YAMATO operator_es_print (const void *ptr, const void *fat, MIO *out)
2225d8f6b0edSMasatake YAMATO {
2226d8f6b0edSMasatake YAMATO 	OperatorFat *ofat = (OperatorFat *)fat;
2227d8f6b0edSMasatake YAMATO 	mio_printf (out, "--%s--", es_symbol_get (ofat->name));
2228d8f6b0edSMasatake YAMATO }
2229d8f6b0edSMasatake YAMATO 
2230d8f6b0edSMasatake YAMATO /*
2231d8f6b0edSMasatake YAMATO  * String
2232d8f6b0edSMasatake YAMATO  */
2233d8f6b0edSMasatake YAMATO static EsObject*
string_new(vString * vstr)2234d8f6b0edSMasatake YAMATO string_new   (vString *vstr)
2235d8f6b0edSMasatake YAMATO {
2236d8f6b0edSMasatake YAMATO 	unsigned int attr = ATTR_READABLE|ATTR_WRITABLE;
2237d8f6b0edSMasatake YAMATO 
2238d8f6b0edSMasatake YAMATO 	if (vstr == NULL)
2239d8f6b0edSMasatake YAMATO 		vstr = vStringNew ();
2240d8f6b0edSMasatake YAMATO 
2241d8f6b0edSMasatake YAMATO 	return es_fatptr_new  (OPT_TYPE_STRING, vstr, &attr);
2242d8f6b0edSMasatake YAMATO }
2243d8f6b0edSMasatake YAMATO 
2244d8f6b0edSMasatake YAMATO static EsObject*
string_es_init_fat(void * fat,void * ptr,void * extra)2245d8f6b0edSMasatake YAMATO string_es_init_fat (void *fat, void *ptr, void *extra)
2246d8f6b0edSMasatake YAMATO {
2247d8f6b0edSMasatake YAMATO 	StringFat *s = fat;
2248d8f6b0edSMasatake YAMATO 	s->attr = *((unsigned int *)extra);
2249d8f6b0edSMasatake YAMATO 	return es_false;
2250d8f6b0edSMasatake YAMATO }
2251d8f6b0edSMasatake YAMATO 
2252d8f6b0edSMasatake YAMATO static void
string_es_free(void * ptr,void * fat)2253d8f6b0edSMasatake YAMATO string_es_free  (void *ptr, void *fat)
2254d8f6b0edSMasatake YAMATO {
2255d8f6b0edSMasatake YAMATO 	if (ptr)
2256d8f6b0edSMasatake YAMATO 		vStringDelete (ptr);
2257d8f6b0edSMasatake YAMATO }
2258d8f6b0edSMasatake YAMATO 
2259d8f6b0edSMasatake YAMATO static int
string_es_equal(const void * a,const void * afat,const void * b,const void * bfat)2260d8f6b0edSMasatake YAMATO string_es_equal (const void *a,
2261d8f6b0edSMasatake YAMATO 				 const void *afat,
2262d8f6b0edSMasatake YAMATO 				 const void *b,
2263d8f6b0edSMasatake YAMATO 				 const void *bfat)
2264d8f6b0edSMasatake YAMATO {
2265d8f6b0edSMasatake YAMATO 	if (!strcmp (vStringValue ((vString *)a),
2266d8f6b0edSMasatake YAMATO 				 vStringValue ((vString *)b)))
2267d8f6b0edSMasatake YAMATO 		return 1;
2268d8f6b0edSMasatake YAMATO 	return 0;
2269d8f6b0edSMasatake YAMATO }
2270d8f6b0edSMasatake YAMATO 
2271d8f6b0edSMasatake YAMATO 
2272d8f6b0edSMasatake YAMATO static void
string_es_print(const void * ptr,const void * fat,MIO * out)2273d8f6b0edSMasatake YAMATO string_es_print (const void *ptr, const void *fat, MIO *out)
2274d8f6b0edSMasatake YAMATO {
2275d8f6b0edSMasatake YAMATO 	char *v = vStringValue ((vString *)ptr);
2276d8f6b0edSMasatake YAMATO 
2277d8f6b0edSMasatake YAMATO 	mio_putc (out, '(');
2278d8f6b0edSMasatake YAMATO 	while (*v != '\0')
2279d8f6b0edSMasatake YAMATO 	{
2280d8f6b0edSMasatake YAMATO 		switch (*v)
2281d8f6b0edSMasatake YAMATO 		{
2282d8f6b0edSMasatake YAMATO 		case '(':
2283d8f6b0edSMasatake YAMATO 		case ')':
2284d8f6b0edSMasatake YAMATO 		case '\\':
2285d8f6b0edSMasatake YAMATO 			mio_putc (out, '\\');
2286d8f6b0edSMasatake YAMATO 			mio_putc (out, *v);
2287d8f6b0edSMasatake YAMATO 			break;
2288d8f6b0edSMasatake YAMATO 		case '\n':
2289d8f6b0edSMasatake YAMATO 			mio_putc (out, '\\');
2290d8f6b0edSMasatake YAMATO 			mio_putc (out, 'n');
2291d8f6b0edSMasatake YAMATO 			break;
2292d8f6b0edSMasatake YAMATO 		case '\r':
2293d8f6b0edSMasatake YAMATO 			mio_putc (out, '\\');
2294d8f6b0edSMasatake YAMATO 			mio_putc (out, 'r');
2295d8f6b0edSMasatake YAMATO 			break;
2296d8f6b0edSMasatake YAMATO 		case '\t':
2297d8f6b0edSMasatake YAMATO 			mio_putc (out, '\\');
2298d8f6b0edSMasatake YAMATO 			mio_putc (out, 't');
2299d8f6b0edSMasatake YAMATO 			break;
2300d8f6b0edSMasatake YAMATO 		case '\f':
2301d8f6b0edSMasatake YAMATO 			mio_putc (out, '\\');
2302d8f6b0edSMasatake YAMATO 			mio_putc (out, 'f');
2303d8f6b0edSMasatake YAMATO 			break;
2304d8f6b0edSMasatake YAMATO 		case '\v':
2305d8f6b0edSMasatake YAMATO 			mio_putc (out, '\\');
2306d8f6b0edSMasatake YAMATO 			mio_putc (out, 'v');
2307d8f6b0edSMasatake YAMATO 			break;
2308d8f6b0edSMasatake YAMATO 		default:
2309d8f6b0edSMasatake YAMATO 			mio_putc (out, *v);
2310d8f6b0edSMasatake YAMATO 		}
2311d8f6b0edSMasatake YAMATO 		v++;
2312d8f6b0edSMasatake YAMATO 	}
2313d8f6b0edSMasatake YAMATO 	mio_putc (out, ')');
2314d8f6b0edSMasatake YAMATO }
2315d8f6b0edSMasatake YAMATO 
2316d8f6b0edSMasatake YAMATO 
2317d8f6b0edSMasatake YAMATO /*
2318d8f6b0edSMasatake YAMATO  * Name
2319d8f6b0edSMasatake YAMATO  */
2320d8f6b0edSMasatake YAMATO static EsObject*
name_new(EsObject * symbol,unsigned int attr)2321d8f6b0edSMasatake YAMATO name_new     (EsObject* symbol, unsigned int attr)
2322d8f6b0edSMasatake YAMATO {
2323d8f6b0edSMasatake YAMATO 	return es_fatptr_new (OPT_TYPE_NAME,
2324d8f6b0edSMasatake YAMATO 						  es_object_ref (symbol), &attr);
2325d8f6b0edSMasatake YAMATO }
2326d8f6b0edSMasatake YAMATO 
2327d8f6b0edSMasatake YAMATO static EsObject*
name_newS(const char * s,unsigned int attr)2328d8f6b0edSMasatake YAMATO name_newS    (const char*s, unsigned int attr)
2329d8f6b0edSMasatake YAMATO {
2330d8f6b0edSMasatake YAMATO 	EsObject *sym = es_symbol_intern (s);
2331d8f6b0edSMasatake YAMATO 	return name_new (sym, attr);
2332d8f6b0edSMasatake YAMATO }
2333d8f6b0edSMasatake YAMATO 
name_newS_cb(const char * s,void * attr)2334d8f6b0edSMasatake YAMATO static EsObject* name_newS_cb (const char*s, void *attr)
2335d8f6b0edSMasatake YAMATO {
2336d8f6b0edSMasatake YAMATO 	return name_newS (s, *((unsigned int *)attr));
2337d8f6b0edSMasatake YAMATO }
2338d8f6b0edSMasatake YAMATO 
2339d8f6b0edSMasatake YAMATO static EsObject*
name_es_init_fat(void * fat,void * ptr,void * extra)2340d8f6b0edSMasatake YAMATO name_es_init_fat (void *fat, void *ptr, void *extra)
2341d8f6b0edSMasatake YAMATO {
2342d8f6b0edSMasatake YAMATO 	ArrayFat *a = fat;
2343d8f6b0edSMasatake YAMATO 	a->attr = *((unsigned int *)extra);
2344d8f6b0edSMasatake YAMATO 	return es_false;
2345d8f6b0edSMasatake YAMATO }
2346d8f6b0edSMasatake YAMATO 
2347d8f6b0edSMasatake YAMATO static void
name_es_print(const void * ptr,const void * fat,MIO * out)2348d8f6b0edSMasatake YAMATO name_es_print (const void *ptr, const void *fat, MIO *out)
2349d8f6b0edSMasatake YAMATO {
2350d8f6b0edSMasatake YAMATO 	const EsObject *symbol = ptr;
2351d8f6b0edSMasatake YAMATO 	const NameFat *qfat = fat;
2352d8f6b0edSMasatake YAMATO 	if (!(qfat->attr & ATTR_EXECUTABLE))
2353d8f6b0edSMasatake YAMATO 		mio_putc (out, '/');
2354d8f6b0edSMasatake YAMATO 	const char *name = es_symbol_get (symbol);
2355d8f6b0edSMasatake YAMATO 	mio_puts (out, name);
2356d8f6b0edSMasatake YAMATO }
2357d8f6b0edSMasatake YAMATO 
2358d8f6b0edSMasatake YAMATO static void
name_es_free(void * ptr,void * fat)2359d8f6b0edSMasatake YAMATO name_es_free  (void *ptr, void *fat)
2360d8f6b0edSMasatake YAMATO {
2361d8f6b0edSMasatake YAMATO 	if (ptr)
2362d8f6b0edSMasatake YAMATO 		es_object_unref (ptr);
2363d8f6b0edSMasatake YAMATO }
2364d8f6b0edSMasatake YAMATO 
2365d8f6b0edSMasatake YAMATO static int
name_es_equal(const void * a,const void * afat,const void * b,const void * bfat)2366d8f6b0edSMasatake YAMATO name_es_equal (const void *a, const void *afat,
2367d8f6b0edSMasatake YAMATO 			   const void *b, const void *bfat)
2368d8f6b0edSMasatake YAMATO {
2369d8f6b0edSMasatake YAMATO 	const EsObject * asym = a;
2370d8f6b0edSMasatake YAMATO 	const EsObject * bsym = b;
2371d8f6b0edSMasatake YAMATO 	return es_object_equal (asym, bsym);
2372d8f6b0edSMasatake YAMATO }
2373d8f6b0edSMasatake YAMATO 
2374d8f6b0edSMasatake YAMATO /*
2375d8f6b0edSMasatake YAMATO  * Mark
2376d8f6b0edSMasatake YAMATO  */
2377d8f6b0edSMasatake YAMATO static EsObject*
mark_new(const char * mark)2378d8f6b0edSMasatake YAMATO mark_new (const char* mark)
2379d8f6b0edSMasatake YAMATO {
2380d8f6b0edSMasatake YAMATO 	return es_pointer_new (OPT_TYPE_MARK,
2381d8f6b0edSMasatake YAMATO 						   eStrdup (mark));
2382d8f6b0edSMasatake YAMATO }
2383d8f6b0edSMasatake YAMATO 
2384d8f6b0edSMasatake YAMATO static void
mark_es_print(const void * ptr,MIO * out)2385d8f6b0edSMasatake YAMATO mark_es_print (const void *ptr, MIO *out)
2386d8f6b0edSMasatake YAMATO {
2387d8f6b0edSMasatake YAMATO 	if (ptr == NULL || (strcmp (ptr, "mark") == 0))
2388d8f6b0edSMasatake YAMATO 		mio_printf (out, "-mark-");
2389d8f6b0edSMasatake YAMATO 	else
2390d8f6b0edSMasatake YAMATO 		mio_printf (out, "-mark:%s-", (char *)ptr);
2391d8f6b0edSMasatake YAMATO }
2392d8f6b0edSMasatake YAMATO 
2393d8f6b0edSMasatake YAMATO static void
mark_es_free(void * ptr)2394d8f6b0edSMasatake YAMATO mark_es_free (void *ptr)
2395d8f6b0edSMasatake YAMATO {
2396d8f6b0edSMasatake YAMATO 	if (ptr)
2397d8f6b0edSMasatake YAMATO 		eFree (ptr);
2398d8f6b0edSMasatake YAMATO }
2399d8f6b0edSMasatake YAMATO 
2400d8f6b0edSMasatake YAMATO static int
mark_es_equal(const void * a,const void * b)2401d8f6b0edSMasatake YAMATO mark_es_equal (const void *a, const void *b)
2402d8f6b0edSMasatake YAMATO {
2403d8f6b0edSMasatake YAMATO 	return 1;
2404d8f6b0edSMasatake YAMATO }
2405d8f6b0edSMasatake YAMATO 
2406d8f6b0edSMasatake YAMATO 
2407d8f6b0edSMasatake YAMATO /*
2408d8f6b0edSMasatake YAMATO  * Operator implementations
2409d8f6b0edSMasatake YAMATO  */
2410d8f6b0edSMasatake YAMATO #define GEN_PRINTER(NAME, BODY)								\
2411d8f6b0edSMasatake YAMATO 	static EsObject*										\
2412d8f6b0edSMasatake YAMATO 	NAME(OptVM *vm, EsObject *name)							\
2413d8f6b0edSMasatake YAMATO 	{														\
2414d8f6b0edSMasatake YAMATO 		EsObject * elt = ptrArrayRemoveLast (vm->ostack);	\
2415d8f6b0edSMasatake YAMATO 		BODY;												\
2416d8f6b0edSMasatake YAMATO 		mio_putc (vm->out, '\n');							\
2417d8f6b0edSMasatake YAMATO 		es_object_unref (elt);								\
2418d8f6b0edSMasatake YAMATO 		return es_false;									\
2419d8f6b0edSMasatake YAMATO 	}
2420d8f6b0edSMasatake YAMATO 
2421d8f6b0edSMasatake YAMATO GEN_PRINTER(op__print_objdict_rec, vm_print_full (vm, elt, false, 10))
2422d8f6b0edSMasatake YAMATO GEN_PRINTER(op__print_objdict,     vm_print_full (vm, elt, false, 1))
2423d8f6b0edSMasatake YAMATO GEN_PRINTER(op__print_object,      vm_print_full (vm, elt, false, 0))
2424d8f6b0edSMasatake YAMATO GEN_PRINTER(op__print,             vm_print_full (vm, elt, true,  0))
2425d8f6b0edSMasatake YAMATO 
2426d8f6b0edSMasatake YAMATO static EsObject*
op__make_array(OptVM * vm,EsObject * name)2427d8f6b0edSMasatake YAMATO op__make_array (OptVM *vm, EsObject *name)
2428d8f6b0edSMasatake YAMATO {
2429d8f6b0edSMasatake YAMATO 	int n = vm_ostack_counttomark (vm);
2430d8f6b0edSMasatake YAMATO 	if (n < 0)
2431d8f6b0edSMasatake YAMATO 		return OPT_ERR_UNMATCHEDMARK;
2432d8f6b0edSMasatake YAMATO 
2433d8f6b0edSMasatake YAMATO 	unsigned int count = vm_ostack_count (vm);
2434d8f6b0edSMasatake YAMATO 	EsObject *a = array_new (ATTR_READABLE | ATTR_WRITABLE);
2435d8f6b0edSMasatake YAMATO 	for (int i = (int)(count - n); i < count; i++)
2436d8f6b0edSMasatake YAMATO 	{
2437d8f6b0edSMasatake YAMATO 		EsObject *elt = ptrArrayItem (vm->ostack, i);
2438d8f6b0edSMasatake YAMATO 		array_op_add (a, elt);
2439d8f6b0edSMasatake YAMATO 	}
2440d8f6b0edSMasatake YAMATO 
2441d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, n + 1);
2442d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, a);
2443d8f6b0edSMasatake YAMATO 	es_object_unref (a);
2444d8f6b0edSMasatake YAMATO 	return es_false;
2445d8f6b0edSMasatake YAMATO }
2446d8f6b0edSMasatake YAMATO 
2447d8f6b0edSMasatake YAMATO static EsObject*
op__make_dict(OptVM * vm,EsObject * name)2448d8f6b0edSMasatake YAMATO op__make_dict (OptVM *vm, EsObject *name)
2449d8f6b0edSMasatake YAMATO {
2450d8f6b0edSMasatake YAMATO 	int n = vm_ostack_counttomark (vm);
2451d8f6b0edSMasatake YAMATO 	if (n < 0)
2452d8f6b0edSMasatake YAMATO 		return OPT_ERR_UNMATCHEDMARK;
2453d8f6b0edSMasatake YAMATO 
2454d8f6b0edSMasatake YAMATO 	if (n % 2)
2455d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
2456d8f6b0edSMasatake YAMATO 
245789d6b969SMasatake YAMATO 	for (int i = 0; i < (n / 2); i++)
245889d6b969SMasatake YAMATO 	{
245989d6b969SMasatake YAMATO 		EsObject *key = ptrArrayItemFromLast (vm->ostack, 2 * i + 1);
246089d6b969SMasatake YAMATO 
246189d6b969SMasatake YAMATO 		if (es_object_get_type (key) != OPT_TYPE_NAME
246289d6b969SMasatake YAMATO 			&& es_object_get_type (key) != OPT_TYPE_STRING
246389d6b969SMasatake YAMATO 			&& !es_integer_p (key) && !es_boolean_p (key))
246489d6b969SMasatake YAMATO 			return OPT_ERR_TYPECHECK;
246589d6b969SMasatake YAMATO 	}
246689d6b969SMasatake YAMATO 
2467d8f6b0edSMasatake YAMATO 	EsObject *d = dict_new (n % 2 + 1, ATTR_READABLE|ATTR_WRITABLE); /* FIXME: + 1 */
2468d8f6b0edSMasatake YAMATO 	for (int i = 0; i < (n / 2); i++)
2469d8f6b0edSMasatake YAMATO 	{
2470d8f6b0edSMasatake YAMATO 		EsObject *val = ptrArrayLast (vm->ostack);
2471d8f6b0edSMasatake YAMATO 		EsObject *key = ptrArrayItemFromLast (vm->ostack, 1);
247289d6b969SMasatake YAMATO 		bool converted = false;
247389d6b969SMasatake YAMATO 
247489d6b969SMasatake YAMATO 		if (es_object_get_type (key) == OPT_TYPE_STRING)
247589d6b969SMasatake YAMATO 		{
247689d6b969SMasatake YAMATO 			const char *cstr = opt_string_get_cstr (key);
247789d6b969SMasatake YAMATO 			key = opt_name_new_from_cstr (cstr);
247889d6b969SMasatake YAMATO 			converted = true;
247989d6b969SMasatake YAMATO 		}
2480d8f6b0edSMasatake YAMATO 		dict_op_def (d, key, val);
248189d6b969SMasatake YAMATO 		if (converted)
248289d6b969SMasatake YAMATO 			es_object_unref (key);
248389d6b969SMasatake YAMATO 
2484d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLastInBatch (vm->ostack, 2);
2485d8f6b0edSMasatake YAMATO 	}
2486d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack); /* Remove the mark */
2487d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, d);
2488d8f6b0edSMasatake YAMATO 	es_object_unref (d);
2489d8f6b0edSMasatake YAMATO 	return es_false;
2490d8f6b0edSMasatake YAMATO }
2491d8f6b0edSMasatake YAMATO 
2492d8f6b0edSMasatake YAMATO static EsObject*
op__help(OptVM * vm,EsObject * name)2493d8f6b0edSMasatake YAMATO op__help (OptVM *vm, EsObject *name)
2494d8f6b0edSMasatake YAMATO {
2495d8f6b0edSMasatake YAMATO 	vm_help (vm, vm->out, NULL, NULL);
2496d8f6b0edSMasatake YAMATO 	return es_false;
2497d8f6b0edSMasatake YAMATO }
2498d8f6b0edSMasatake YAMATO 
2499d8f6b0edSMasatake YAMATO static EsObject*
op_pstack(OptVM * vm,EsObject * name)2500d8f6b0edSMasatake YAMATO op_pstack (OptVM *vm, EsObject *name)
2501d8f6b0edSMasatake YAMATO {
2502d8f6b0edSMasatake YAMATO 	unsigned int c = vm_ostack_count (vm);
2503d8f6b0edSMasatake YAMATO 
2504d8f6b0edSMasatake YAMATO 	for (unsigned int i = c; i > 0; i--)
2505d8f6b0edSMasatake YAMATO 	{
2506d8f6b0edSMasatake YAMATO 		EsObject * elt = ptrArrayItem (vm->ostack, i - 1);
2507d8f6b0edSMasatake YAMATO 		vm_print (vm, elt);
2508d8f6b0edSMasatake YAMATO 		mio_putc (vm->out, '\n');
2509d8f6b0edSMasatake YAMATO 	}
2510d8f6b0edSMasatake YAMATO 	return es_false;
2511d8f6b0edSMasatake YAMATO }
2512d8f6b0edSMasatake YAMATO 
2513d8f6b0edSMasatake YAMATO static EsObject*
op__newerror(OptVM * vm,EsObject * name)2514d8f6b0edSMasatake YAMATO op__newerror (OptVM *vm, EsObject *name)
2515d8f6b0edSMasatake YAMATO {
2516d8f6b0edSMasatake YAMATO 	EsObject *newerror;
2517d8f6b0edSMasatake YAMATO 	if (dict_op_known_and_get (vm->error, OPT_KEY_newerror, &newerror))
2518d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, newerror);
2519d8f6b0edSMasatake YAMATO 	else
2520d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, es_false);
2521d8f6b0edSMasatake YAMATO 	return es_false;
2522d8f6b0edSMasatake YAMATO }
2523d8f6b0edSMasatake YAMATO 
2524d8f6b0edSMasatake YAMATO static EsObject*
op__errorname(OptVM * vm,EsObject * name)2525d8f6b0edSMasatake YAMATO op__errorname (OptVM *vm, EsObject *name)
2526d8f6b0edSMasatake YAMATO {
2527d8f6b0edSMasatake YAMATO 	EsObject *errorname;
2528d8f6b0edSMasatake YAMATO 	if (dict_op_known_and_get (vm->error, OPT_KEY_errorname, &errorname))
2529d8f6b0edSMasatake YAMATO 	{
2530d8f6b0edSMasatake YAMATO 		EsObject *sym = es_nil;
2531d8f6b0edSMasatake YAMATO 		if (!es_null (errorname))
2532d8f6b0edSMasatake YAMATO 		{
2533d8f6b0edSMasatake YAMATO 			const char *cstr = es_error_name(errorname);
2534d8f6b0edSMasatake YAMATO 			sym = opt_name_new_from_cstr (cstr);
2535d8f6b0edSMasatake YAMATO 		}
2536d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, sym);
2537d8f6b0edSMasatake YAMATO 		if (!es_null (errorname))
2538d8f6b0edSMasatake YAMATO 			es_object_unref (sym);
2539d8f6b0edSMasatake YAMATO 	}
2540d8f6b0edSMasatake YAMATO 	else
2541d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, es_nil);
2542d8f6b0edSMasatake YAMATO 	return es_false;
2543d8f6b0edSMasatake YAMATO }
2544d8f6b0edSMasatake YAMATO 
2545d8f6b0edSMasatake YAMATO static EsObject*
op_quit(OptVM * vm,EsObject * name)2546d8f6b0edSMasatake YAMATO op_quit (OptVM *vm, EsObject *name)
2547d8f6b0edSMasatake YAMATO {
2548d8f6b0edSMasatake YAMATO 	int c = mio_getc (vm->in);
2549d8f6b0edSMasatake YAMATO 	if (!(c == '\n' || c == '\r' || c == EOF))
2550d8f6b0edSMasatake YAMATO 		mio_ungetc (vm->in, c);
2551d8f6b0edSMasatake YAMATO 	return OPT_ERR_QUIT;
2552d8f6b0edSMasatake YAMATO }
2553d8f6b0edSMasatake YAMATO 
2554d8f6b0edSMasatake YAMATO static EsObject*
op_countexecstack(OptVM * vm,EsObject * name)2555d8f6b0edSMasatake YAMATO op_countexecstack (OptVM *vm, EsObject *name)
2556d8f6b0edSMasatake YAMATO {
2557d8f6b0edSMasatake YAMATO 	unsigned int c = ptrArrayCount (vm->estack);
2558d8f6b0edSMasatake YAMATO 	int n = c;
2559d8f6b0edSMasatake YAMATO 
2560d8f6b0edSMasatake YAMATO 	if (n < 0)
2561d8f6b0edSMasatake YAMATO 		return OPT_ERR_INTERNALERROR; /* TODO: integer overflow */
2562d8f6b0edSMasatake YAMATO 
2563d8f6b0edSMasatake YAMATO 	EsObject *nobj = es_integer_new (n);
2564d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, nobj);
2565d8f6b0edSMasatake YAMATO 	es_object_unref (nobj);
2566d8f6b0edSMasatake YAMATO 
2567d8f6b0edSMasatake YAMATO 	return es_false;
2568d8f6b0edSMasatake YAMATO }
2569d8f6b0edSMasatake YAMATO 
2570d8f6b0edSMasatake YAMATO static EsObject*
op__stack_common(OptVM * vm,EsObject * name,ptrArray * stack,EsObject * dstarrayobj,bool ignoreLast)2571d8f6b0edSMasatake YAMATO op__stack_common (OptVM *vm, EsObject *name, ptrArray *stack, EsObject *dstarrayobj,
2572d8f6b0edSMasatake YAMATO 				  bool ignoreLast)
2573d8f6b0edSMasatake YAMATO {
2574d8f6b0edSMasatake YAMATO 	unsigned int c = ptrArrayCount (stack);
2575d8f6b0edSMasatake YAMATO 	ptrArray *a = es_pointer_get (dstarrayobj);
2576d8f6b0edSMasatake YAMATO 
2577d8f6b0edSMasatake YAMATO 	if (ignoreLast && c == 0)
2578d8f6b0edSMasatake YAMATO 		return OPT_ERR_INTERNALERROR; /* TODO: integer overflow */
2579d8f6b0edSMasatake YAMATO 
2580d8f6b0edSMasatake YAMATO 	ptrArrayClear (a);
2581d8f6b0edSMasatake YAMATO 	for (unsigned int i = 0; i < c - (ignoreLast? 1: 0); i++)
2582d8f6b0edSMasatake YAMATO 	{
2583d8f6b0edSMasatake YAMATO 		EsObject *d = ptrArrayItem (stack, i);
2584d8f6b0edSMasatake YAMATO 		ptrArrayAdd (a, es_object_ref (d));
2585d8f6b0edSMasatake YAMATO 	}
2586d8f6b0edSMasatake YAMATO 
2587d8f6b0edSMasatake YAMATO 	return es_false;
2588d8f6b0edSMasatake YAMATO }
2589d8f6b0edSMasatake YAMATO 
2590d8f6b0edSMasatake YAMATO static EsObject*
op_execstack(OptVM * vm,EsObject * name)2591d8f6b0edSMasatake YAMATO op_execstack (OptVM *vm, EsObject *name)
2592d8f6b0edSMasatake YAMATO {
2593d8f6b0edSMasatake YAMATO 	EsObject *obj = ptrArrayLast (vm->ostack);
2594d8f6b0edSMasatake YAMATO 	if (es_object_get_type (obj) != OPT_TYPE_ARRAY)
2595d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
2596d8f6b0edSMasatake YAMATO 
2597d8f6b0edSMasatake YAMATO 	return op__stack_common (vm, name, vm->estack, obj, true);
2598d8f6b0edSMasatake YAMATO }
2599d8f6b0edSMasatake YAMATO 
2600d8f6b0edSMasatake YAMATO 
2601d8f6b0edSMasatake YAMATO /*
2602d8f6b0edSMasatake YAMATO  * Operators for operand stack manipulation
2603d8f6b0edSMasatake YAMATO  */
2604d8f6b0edSMasatake YAMATO static EsObject*
op_pop(OptVM * vm,EsObject * name)2605d8f6b0edSMasatake YAMATO op_pop (OptVM *vm, EsObject *name)
2606d8f6b0edSMasatake YAMATO {
2607d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
2608d8f6b0edSMasatake YAMATO 	return es_false;
2609d8f6b0edSMasatake YAMATO }
2610d8f6b0edSMasatake YAMATO 
2611d8f6b0edSMasatake YAMATO static EsObject*
op_exch(OptVM * vm,EsObject * name)2612d8f6b0edSMasatake YAMATO op_exch (OptVM *vm, EsObject *name)
2613d8f6b0edSMasatake YAMATO {
2614d8f6b0edSMasatake YAMATO 	EsObject * top = ptrArrayRemoveLast (vm->ostack);
2615d8f6b0edSMasatake YAMATO 	EsObject * next = ptrArrayRemoveLast (vm->ostack);
2616d8f6b0edSMasatake YAMATO 	ptrArrayAdd (vm->ostack, top);
2617d8f6b0edSMasatake YAMATO 	ptrArrayAdd (vm->ostack, next);
2618d8f6b0edSMasatake YAMATO 	return es_false;
2619d8f6b0edSMasatake YAMATO }
2620d8f6b0edSMasatake YAMATO 
2621d8f6b0edSMasatake YAMATO static EsObject*
op_dup(OptVM * vm,EsObject * name)2622d8f6b0edSMasatake YAMATO op_dup (OptVM *vm, EsObject *name)
2623d8f6b0edSMasatake YAMATO {
2624d8f6b0edSMasatake YAMATO 	EsObject * top = vm_ostack_top (vm);
2625d8f6b0edSMasatake YAMATO 	if (es_error_p (top))
2626d8f6b0edSMasatake YAMATO 		return top;
2627d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, top);
2628d8f6b0edSMasatake YAMATO 	return es_false;
2629d8f6b0edSMasatake YAMATO }
2630d8f6b0edSMasatake YAMATO 
2631d8f6b0edSMasatake YAMATO static bool
dict_copy_cb(const void * key,void * value,void * user_data)2632d8f6b0edSMasatake YAMATO dict_copy_cb (const void *key, void *value, void *user_data)
2633d8f6b0edSMasatake YAMATO {
2634d8f6b0edSMasatake YAMATO 	hashTable *dst = user_data;
2635d8f6b0edSMasatake YAMATO 	hashTablePutItem (dst, es_object_ref ((void *)key), es_object_ref (value));
2636d8f6b0edSMasatake YAMATO 	return true;
2637d8f6b0edSMasatake YAMATO }
2638d8f6b0edSMasatake YAMATO 
2639d8f6b0edSMasatake YAMATO static EsObject*
op__copy_compound(OptVM * vm,EsObject * name,unsigned int c,EsObject * obj2)2640d8f6b0edSMasatake YAMATO op__copy_compound (OptVM *vm, EsObject *name, unsigned int c, EsObject *obj2)
2641d8f6b0edSMasatake YAMATO {
2642d8f6b0edSMasatake YAMATO 	int t = es_object_get_type (obj2);
2643d8f6b0edSMasatake YAMATO 	if (!(t == OPT_TYPE_ARRAY || t == OPT_TYPE_DICT || t == OPT_TYPE_STRING))
2644d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
2645d8f6b0edSMasatake YAMATO 
2646d8f6b0edSMasatake YAMATO 	if (c < 2)
2647d8f6b0edSMasatake YAMATO 		return OPT_ERR_UNDERFLOW;
2648d8f6b0edSMasatake YAMATO 
2649d8f6b0edSMasatake YAMATO 	EsObject *obj1 = ptrArrayItemFromLast (vm->ostack, 1);
2650d8f6b0edSMasatake YAMATO 	if (es_object_get_type (obj1) != t)
2651d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
2652d8f6b0edSMasatake YAMATO 
2653d8f6b0edSMasatake YAMATO 	if (t == OPT_TYPE_ARRAY)
2654d8f6b0edSMasatake YAMATO 	{
2655d8f6b0edSMasatake YAMATO 		ptrArray *a1 = es_pointer_get (obj1);
2656d8f6b0edSMasatake YAMATO 		ptrArray *a2 = es_pointer_get (obj2);
2657d8f6b0edSMasatake YAMATO 		ptrArrayClear (a2);
2658d8f6b0edSMasatake YAMATO 		unsigned int len = ptrArrayCount (a1);
2659d8f6b0edSMasatake YAMATO 		for (unsigned int i = 0; i < len; i++)
2660d8f6b0edSMasatake YAMATO 		{
2661d8f6b0edSMasatake YAMATO 			EsObject *o = ptrArrayItem (a1, i);
2662d8f6b0edSMasatake YAMATO 			ptrArrayAdd (a2, es_object_ref (o));
2663d8f6b0edSMasatake YAMATO 		}
2664d8f6b0edSMasatake YAMATO 	}
2665d8f6b0edSMasatake YAMATO 	else if (t == OPT_TYPE_DICT)
2666d8f6b0edSMasatake YAMATO 	{
2667d8f6b0edSMasatake YAMATO 		hashTable *ht1 = es_pointer_get (obj1);
2668d8f6b0edSMasatake YAMATO 		hashTable *ht2 = es_pointer_get (obj2);
2669d8f6b0edSMasatake YAMATO 		hashTableClear (ht2);
2670d8f6b0edSMasatake YAMATO 		hashTableForeachItem (ht1, dict_copy_cb, ht2);
2671d8f6b0edSMasatake YAMATO 	}
2672d8f6b0edSMasatake YAMATO 	else
2673d8f6b0edSMasatake YAMATO 	{
2674d8f6b0edSMasatake YAMATO 		vString *str1 = es_pointer_get (obj1);
2675d8f6b0edSMasatake YAMATO 		vString *str2 = es_pointer_get (obj2);
2676d8f6b0edSMasatake YAMATO 		vStringCopy (str2, str1);
2677d8f6b0edSMasatake YAMATO 	}
2678d8f6b0edSMasatake YAMATO 
2679d8f6b0edSMasatake YAMATO 	ptrArrayRemoveLast (vm->ostack);
2680d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
2681d8f6b0edSMasatake YAMATO 	ptrArrayAdd (vm->ostack, obj2);
2682d8f6b0edSMasatake YAMATO 	return es_false;
2683d8f6b0edSMasatake YAMATO }
2684d8f6b0edSMasatake YAMATO 
2685d8f6b0edSMasatake YAMATO static EsObject*
op_copy(OptVM * vm,EsObject * name)2686d8f6b0edSMasatake YAMATO op_copy (OptVM *vm, EsObject *name)
2687d8f6b0edSMasatake YAMATO {
2688d8f6b0edSMasatake YAMATO 	unsigned int c = vm_ostack_count (vm);
2689d8f6b0edSMasatake YAMATO 
2690d8f6b0edSMasatake YAMATO 	if (c > 0)
2691d8f6b0edSMasatake YAMATO 	{
2692d8f6b0edSMasatake YAMATO 		EsObject * nobj = ptrArrayLast(vm->ostack);
2693d8f6b0edSMasatake YAMATO 
2694d8f6b0edSMasatake YAMATO 
2695d8f6b0edSMasatake YAMATO 		if (!es_integer_p (nobj))
2696d8f6b0edSMasatake YAMATO 			return op__copy_compound (vm, name, c, nobj);
2697d8f6b0edSMasatake YAMATO 
2698d8f6b0edSMasatake YAMATO 		int n = es_integer_get (nobj);
2699d8f6b0edSMasatake YAMATO 		if (n < 0)
2700d8f6b0edSMasatake YAMATO 			return OPT_ERR_RANGECHECK;
2701d8f6b0edSMasatake YAMATO 
2702d8f6b0edSMasatake YAMATO 		c--;
2703d8f6b0edSMasatake YAMATO 
2704d8f6b0edSMasatake YAMATO 		if (((int)c) - n < 0)
2705d8f6b0edSMasatake YAMATO 			return OPT_ERR_UNDERFLOW;
2706d8f6b0edSMasatake YAMATO 
2707d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLast(vm->ostack);
2708d8f6b0edSMasatake YAMATO 
2709d8f6b0edSMasatake YAMATO 		for (int i = c - n; i < c; i++)
2710d8f6b0edSMasatake YAMATO 		{
2711d8f6b0edSMasatake YAMATO 			EsObject * elt = ptrArrayItem (vm->ostack, i);
2712d8f6b0edSMasatake YAMATO 			vm_ostack_push (vm, elt);
2713d8f6b0edSMasatake YAMATO 		}
2714d8f6b0edSMasatake YAMATO 		return es_false;
2715d8f6b0edSMasatake YAMATO 	}
2716d8f6b0edSMasatake YAMATO 	return OPT_ERR_UNDERFLOW;
2717d8f6b0edSMasatake YAMATO }
2718d8f6b0edSMasatake YAMATO 
2719d8f6b0edSMasatake YAMATO static EsObject*
op_index(OptVM * vm,EsObject * name)2720d8f6b0edSMasatake YAMATO op_index (OptVM *vm, EsObject *name)
2721d8f6b0edSMasatake YAMATO {
2722d8f6b0edSMasatake YAMATO 	unsigned int c = vm_ostack_count (vm);
2723d8f6b0edSMasatake YAMATO 
2724d8f6b0edSMasatake YAMATO 	EsObject * nobj = ptrArrayLast(vm->ostack);
2725d8f6b0edSMasatake YAMATO 	if (!es_integer_p (nobj))
2726d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
2727d8f6b0edSMasatake YAMATO 
2728d8f6b0edSMasatake YAMATO 	int n = es_integer_get (nobj);
2729d8f6b0edSMasatake YAMATO 	if (n < 0)
2730d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
2731d8f6b0edSMasatake YAMATO 	if (c < (unsigned int)(n + 2))
2732d8f6b0edSMasatake YAMATO 		return OPT_ERR_UNDERFLOW;
2733d8f6b0edSMasatake YAMATO 
2734d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
2735d8f6b0edSMasatake YAMATO 
2736d8f6b0edSMasatake YAMATO 	EsObject * elt = ptrArrayItem (vm->ostack, c - n - 2);
2737d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, elt);
2738d8f6b0edSMasatake YAMATO 	return es_false;
2739d8f6b0edSMasatake YAMATO 
2740d8f6b0edSMasatake YAMATO 	return OPT_ERR_UNDERFLOW;
2741d8f6b0edSMasatake YAMATO }
2742d8f6b0edSMasatake YAMATO 
2743d8f6b0edSMasatake YAMATO static EsObject*
op_roll(OptVM * vm,EsObject * name)2744d8f6b0edSMasatake YAMATO op_roll (OptVM *vm, EsObject *name)
2745d8f6b0edSMasatake YAMATO {
2746d8f6b0edSMasatake YAMATO 	unsigned int c = vm_ostack_count (vm);
2747d8f6b0edSMasatake YAMATO 
2748d8f6b0edSMasatake YAMATO 	EsObject *jobj = ptrArrayLast (vm->ostack);
2749d8f6b0edSMasatake YAMATO 	if (!es_integer_p (jobj))
2750d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
2751d8f6b0edSMasatake YAMATO 	int j = es_integer_get (jobj);
2752d8f6b0edSMasatake YAMATO 
2753d8f6b0edSMasatake YAMATO 	EsObject *nobj = ptrArrayItemFromLast (vm->ostack, 1);
2754d8f6b0edSMasatake YAMATO 	if (!es_integer_p (nobj))
2755d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
2756d8f6b0edSMasatake YAMATO 	int n = es_integer_get (nobj);
2757d8f6b0edSMasatake YAMATO 
2758d8f6b0edSMasatake YAMATO 	if ((((int)c) - 2) < n)
2759d8f6b0edSMasatake YAMATO 		return OPT_ERR_UNDERFLOW;
2760d8f6b0edSMasatake YAMATO 
2761d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 2);
2762d8f6b0edSMasatake YAMATO 	if (j == 0)
2763d8f6b0edSMasatake YAMATO 		return es_false;
2764d8f6b0edSMasatake YAMATO 
2765d8f6b0edSMasatake YAMATO 	unsigned int indx = c - 2 - n;
2766d8f6b0edSMasatake YAMATO 	EsObject *p;
2767d8f6b0edSMasatake YAMATO 	if (j > 0)
2768d8f6b0edSMasatake YAMATO 	{
2769d8f6b0edSMasatake YAMATO 		while (j-- != 0)
2770d8f6b0edSMasatake YAMATO 		{
2771d8f6b0edSMasatake YAMATO 			p = ptrArrayRemoveLast (vm->ostack);
2772d8f6b0edSMasatake YAMATO 			ptrArrayInsertItem (vm->ostack, indx, p);
2773d8f6b0edSMasatake YAMATO 		}
2774d8f6b0edSMasatake YAMATO 	}
2775d8f6b0edSMasatake YAMATO 	else
2776d8f6b0edSMasatake YAMATO 	{
2777d8f6b0edSMasatake YAMATO 		while (j++ != 0)
2778d8f6b0edSMasatake YAMATO 		{
2779d8f6b0edSMasatake YAMATO 			p = ptrArrayRemoveItem(vm->ostack, indx);
2780d8f6b0edSMasatake YAMATO 			ptrArrayAdd (vm->ostack, p);
2781d8f6b0edSMasatake YAMATO 		}
2782d8f6b0edSMasatake YAMATO 
2783d8f6b0edSMasatake YAMATO 	}
2784d8f6b0edSMasatake YAMATO 
2785d8f6b0edSMasatake YAMATO 	return es_false;
2786d8f6b0edSMasatake YAMATO }
2787d8f6b0edSMasatake YAMATO 
2788d8f6b0edSMasatake YAMATO static EsObject*
op_clear(OptVM * vm,EsObject * name)2789d8f6b0edSMasatake YAMATO op_clear (OptVM *vm, EsObject *name)
2790d8f6b0edSMasatake YAMATO {
2791d8f6b0edSMasatake YAMATO 	ptrArrayClear (vm->ostack);
2792d8f6b0edSMasatake YAMATO 
2793d8f6b0edSMasatake YAMATO 	return es_false;
2794d8f6b0edSMasatake YAMATO }
2795d8f6b0edSMasatake YAMATO 
2796d8f6b0edSMasatake YAMATO static EsObject*
op_count(OptVM * vm,EsObject * name)2797d8f6b0edSMasatake YAMATO op_count (OptVM *vm, EsObject *name)
2798d8f6b0edSMasatake YAMATO {
2799d8f6b0edSMasatake YAMATO 	unsigned int c = ptrArrayCount (vm->ostack);
2800d8f6b0edSMasatake YAMATO 
2801d8f6b0edSMasatake YAMATO 	EsObject *n = es_integer_new ((int)c);
2802d8f6b0edSMasatake YAMATO 	ptrArrayAdd (vm->ostack, n);
2803d8f6b0edSMasatake YAMATO 
2804d8f6b0edSMasatake YAMATO 	return es_false;
2805d8f6b0edSMasatake YAMATO }
2806d8f6b0edSMasatake YAMATO 
2807d8f6b0edSMasatake YAMATO static EsObject*
op_mark(OptVM * vm,EsObject * name)2808d8f6b0edSMasatake YAMATO op_mark (OptVM *vm, EsObject *name)
2809d8f6b0edSMasatake YAMATO {
2810d8f6b0edSMasatake YAMATO 	EsObject *mark;
2811d8f6b0edSMasatake YAMATO 	if (es_object_equal (name, es_symbol_intern ("[")))
2812d8f6b0edSMasatake YAMATO 		mark = OPT_MARK_ARRAY;
2813d8f6b0edSMasatake YAMATO 	else if (es_object_equal (name, es_symbol_intern ("<<")))
2814d8f6b0edSMasatake YAMATO 		mark = OPT_MARK_DICT;
2815d8f6b0edSMasatake YAMATO 	else
2816d8f6b0edSMasatake YAMATO 		mark = OPT_MARK_MARK;
2817d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, mark);
2818d8f6b0edSMasatake YAMATO 
2819d8f6b0edSMasatake YAMATO 	return es_false;
2820d8f6b0edSMasatake YAMATO }
2821d8f6b0edSMasatake YAMATO 
2822d8f6b0edSMasatake YAMATO static EsObject*
op_cleartomark(OptVM * vm,EsObject * name)2823d8f6b0edSMasatake YAMATO op_cleartomark (OptVM *vm, EsObject *name)
2824d8f6b0edSMasatake YAMATO {
2825d8f6b0edSMasatake YAMATO 	int r = vm_ostack_counttomark (vm);
2826d8f6b0edSMasatake YAMATO 
2827d8f6b0edSMasatake YAMATO 	if (r < 0)
2828d8f6b0edSMasatake YAMATO 		return OPT_ERR_UNMATCHEDMARK;
2829d8f6b0edSMasatake YAMATO 
2830d8f6b0edSMasatake YAMATO 	if (r < 0)
2831d8f6b0edSMasatake YAMATO 		return OPT_ERR_UNMATCHEDMARK;
2832d8f6b0edSMasatake YAMATO 
2833d8f6b0edSMasatake YAMATO 	for (int i = 0; i <= r; i++)
2834d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLast (vm->ostack);
2835d8f6b0edSMasatake YAMATO 	return es_false;
2836d8f6b0edSMasatake YAMATO }
2837d8f6b0edSMasatake YAMATO 
2838d8f6b0edSMasatake YAMATO static EsObject*
op_counttomark(OptVM * vm,EsObject * name)2839d8f6b0edSMasatake YAMATO op_counttomark (OptVM *vm, EsObject *name)
2840d8f6b0edSMasatake YAMATO {
2841d8f6b0edSMasatake YAMATO 	int r = vm_ostack_counttomark (vm);
2842d8f6b0edSMasatake YAMATO 
2843d8f6b0edSMasatake YAMATO 	if (r < 0)
2844d8f6b0edSMasatake YAMATO 		return OPT_ERR_UNMATCHEDMARK;
2845d8f6b0edSMasatake YAMATO 
2846d8f6b0edSMasatake YAMATO 	ptrArrayAdd (vm->ostack, es_integer_new (r));
2847d8f6b0edSMasatake YAMATO 	return es_false;
2848d8f6b0edSMasatake YAMATO }
2849d8f6b0edSMasatake YAMATO 
2850d8f6b0edSMasatake YAMATO 
2851d8f6b0edSMasatake YAMATO /*
2852d8f6b0edSMasatake YAMATO  * Arithmetic Operators
2853d8f6b0edSMasatake YAMATO  */
2854d8f6b0edSMasatake YAMATO #define INTEGER_BINOP(OP)									\
2855d8f6b0edSMasatake YAMATO 	EsObject *n0obj = ptrArrayLast (vm->ostack);			\
2856d8f6b0edSMasatake YAMATO 	if (!es_integer_p (n0obj))								\
2857d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;							\
2858d8f6b0edSMasatake YAMATO 	int n0 = es_integer_get (n0obj);						\
2859d8f6b0edSMasatake YAMATO 															\
2860d8f6b0edSMasatake YAMATO 	EsObject *n1obj = ptrArrayItemFromLast (vm->ostack, 1);	\
2861d8f6b0edSMasatake YAMATO 	if (!es_integer_p (n1obj))								\
2862d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;							\
2863d8f6b0edSMasatake YAMATO 	int n1 = es_integer_get (n1obj);						\
2864d8f6b0edSMasatake YAMATO 															\
2865d8f6b0edSMasatake YAMATO 	EsObject *r = es_integer_new (n1 OP n0);				\
2866d8f6b0edSMasatake YAMATO 	if (es_error_p (r))										\
2867d8f6b0edSMasatake YAMATO 		return r;											\
2868d8f6b0edSMasatake YAMATO 															\
2869d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 2);				\
2870d8f6b0edSMasatake YAMATO 	ptrArrayAdd (vm->ostack, r);							\
2871d8f6b0edSMasatake YAMATO 	return es_false
2872d8f6b0edSMasatake YAMATO 
2873d8f6b0edSMasatake YAMATO static EsObject*
op_add(OptVM * vm,EsObject * name)2874d8f6b0edSMasatake YAMATO op_add (OptVM *vm, EsObject *name)
2875d8f6b0edSMasatake YAMATO {
2876d8f6b0edSMasatake YAMATO 	INTEGER_BINOP(+);
2877d8f6b0edSMasatake YAMATO }
2878d8f6b0edSMasatake YAMATO 
2879d8f6b0edSMasatake YAMATO static EsObject*
op_idiv(OptVM * vm,EsObject * name)2880d8f6b0edSMasatake YAMATO op_idiv (OptVM *vm, EsObject *name)
2881d8f6b0edSMasatake YAMATO {
2882d8f6b0edSMasatake YAMATO 	INTEGER_BINOP(/);
2883d8f6b0edSMasatake YAMATO }
2884d8f6b0edSMasatake YAMATO 
2885d8f6b0edSMasatake YAMATO static EsObject*
op_mod(OptVM * vm,EsObject * name)2886d8f6b0edSMasatake YAMATO op_mod (OptVM *vm, EsObject *name)
2887d8f6b0edSMasatake YAMATO {
2888d8f6b0edSMasatake YAMATO 	INTEGER_BINOP(%);
2889d8f6b0edSMasatake YAMATO }
2890d8f6b0edSMasatake YAMATO 
2891d8f6b0edSMasatake YAMATO static EsObject*
op_mul(OptVM * vm,EsObject * name)2892d8f6b0edSMasatake YAMATO op_mul (OptVM *vm, EsObject *name)
2893d8f6b0edSMasatake YAMATO {
2894d8f6b0edSMasatake YAMATO 	INTEGER_BINOP(*);
2895d8f6b0edSMasatake YAMATO }
2896d8f6b0edSMasatake YAMATO 
2897d8f6b0edSMasatake YAMATO static EsObject*
op_sub(OptVM * vm,EsObject * name)2898d8f6b0edSMasatake YAMATO op_sub (OptVM *vm, EsObject *name)
2899d8f6b0edSMasatake YAMATO {
2900d8f6b0edSMasatake YAMATO 	INTEGER_BINOP(-);
2901d8f6b0edSMasatake YAMATO }
2902d8f6b0edSMasatake YAMATO 
2903d8f6b0edSMasatake YAMATO static EsObject*
op_abs(OptVM * vm,EsObject * name)2904d8f6b0edSMasatake YAMATO op_abs (OptVM *vm, EsObject *name)
2905d8f6b0edSMasatake YAMATO {
2906d8f6b0edSMasatake YAMATO 	EsObject *nobj = ptrArrayLast (vm->ostack);
2907d8f6b0edSMasatake YAMATO 	if (!es_integer_p (nobj))
2908d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
2909d8f6b0edSMasatake YAMATO 
2910d8f6b0edSMasatake YAMATO 	int n = es_integer_get(nobj);
2911d8f6b0edSMasatake YAMATO 	if (n >= 0)
2912d8f6b0edSMasatake YAMATO 		return es_false;
2913d8f6b0edSMasatake YAMATO 
2914d8f6b0edSMasatake YAMATO 	EsObject *r = es_integer_new (-n);
2915d8f6b0edSMasatake YAMATO 	if (es_error_p (r))
2916d8f6b0edSMasatake YAMATO 		return r;
2917d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
2918d8f6b0edSMasatake YAMATO 	ptrArrayAdd (vm->ostack, r);
2919d8f6b0edSMasatake YAMATO 	return es_false;
2920d8f6b0edSMasatake YAMATO }
2921d8f6b0edSMasatake YAMATO 
2922d8f6b0edSMasatake YAMATO static EsObject*
op_neg(OptVM * vm,EsObject * name)2923d8f6b0edSMasatake YAMATO op_neg (OptVM *vm, EsObject *name)
2924d8f6b0edSMasatake YAMATO {
2925d8f6b0edSMasatake YAMATO 	EsObject *nobj = ptrArrayLast (vm->ostack);
2926d8f6b0edSMasatake YAMATO 	if (!es_integer_p (nobj))
2927d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
2928d8f6b0edSMasatake YAMATO 	int n = es_integer_get(nobj);
2929d8f6b0edSMasatake YAMATO 	EsObject *r = es_integer_new (-n);
2930d8f6b0edSMasatake YAMATO 	if (es_error_p (r))
2931d8f6b0edSMasatake YAMATO 		return r;
2932d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
2933d8f6b0edSMasatake YAMATO 	ptrArrayAdd (vm->ostack, r);
2934d8f6b0edSMasatake YAMATO 	return es_false;
2935d8f6b0edSMasatake YAMATO }
2936d8f6b0edSMasatake YAMATO 
2937d8f6b0edSMasatake YAMATO 
2938d8f6b0edSMasatake YAMATO /*
2939d8f6b0edSMasatake YAMATO  * Operators for array manipulation
2940d8f6b0edSMasatake YAMATO  */
2941d8f6b0edSMasatake YAMATO static EsObject*
op_array(OptVM * vm,EsObject * name)2942d8f6b0edSMasatake YAMATO op_array (OptVM *vm, EsObject *name)
2943d8f6b0edSMasatake YAMATO {
2944d8f6b0edSMasatake YAMATO 	EsObject *nobj = ptrArrayLast (vm->ostack);
2945d8f6b0edSMasatake YAMATO 	if (!es_integer_p (nobj))
2946d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
2947d8f6b0edSMasatake YAMATO 
2948d8f6b0edSMasatake YAMATO 	int n = es_integer_get (nobj);
2949d8f6b0edSMasatake YAMATO 	if (n < 0)
2950d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
2951d8f6b0edSMasatake YAMATO 
2952d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
2953d8f6b0edSMasatake YAMATO 
2954d8f6b0edSMasatake YAMATO 	EsObject *array = array_new (ATTR_WRITABLE|ATTR_READABLE);
2955d8f6b0edSMasatake YAMATO 	ptrArray *a = es_pointer_get (array);
2956d8f6b0edSMasatake YAMATO 	for (int i = 0; i < n; i++)
2957d8f6b0edSMasatake YAMATO 		ptrArrayAdd (a, es_nil);
2958d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, array);
2959d8f6b0edSMasatake YAMATO 	es_object_unref (array);
2960d8f6b0edSMasatake YAMATO 
2961d8f6b0edSMasatake YAMATO 	return es_false;
2962d8f6b0edSMasatake YAMATO }
2963d8f6b0edSMasatake YAMATO 
2964d8f6b0edSMasatake YAMATO static EsObject*
op_astore(OptVM * vm,EsObject * name)2965d8f6b0edSMasatake YAMATO op_astore (OptVM *vm, EsObject *name)
2966d8f6b0edSMasatake YAMATO {
2967d8f6b0edSMasatake YAMATO 	EsObject *array = ptrArrayLast (vm->ostack);
2968d8f6b0edSMasatake YAMATO 	if (es_object_get_type (array) != OPT_TYPE_ARRAY)
2969d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
2970d8f6b0edSMasatake YAMATO 
2971d8f6b0edSMasatake YAMATO 	unsigned int c = ptrArrayCount (vm->ostack);
2972d8f6b0edSMasatake YAMATO 	ptrArray *a = es_pointer_get (array);
2973d8f6b0edSMasatake YAMATO 	unsigned int l = ptrArrayCount (a);
2974d8f6b0edSMasatake YAMATO 
2975d8f6b0edSMasatake YAMATO 	if (l == 0)
2976d8f6b0edSMasatake YAMATO 		return es_false;
2977d8f6b0edSMasatake YAMATO 
2978d8f6b0edSMasatake YAMATO 	/* +1 is for the array itself. */
2979d8f6b0edSMasatake YAMATO 	if (c < (l + 1))
2980d8f6b0edSMasatake YAMATO 		return OPT_ERR_UNDERFLOW;
2981d8f6b0edSMasatake YAMATO 
2982d8f6b0edSMasatake YAMATO 	ptrArrayClear (a);
2983d8f6b0edSMasatake YAMATO 	ptrArrayRemoveLast (vm->ostack);
2984d8f6b0edSMasatake YAMATO 
2985d8f6b0edSMasatake YAMATO 	int i = l - 1;
2986d8f6b0edSMasatake YAMATO 	if (i < 0)
2987d8f6b0edSMasatake YAMATO 		return OPT_ERR_INTERNALERROR; /* TODO: integer overflow */
2988d8f6b0edSMasatake YAMATO 	for (; i >= 0; i--)
2989d8f6b0edSMasatake YAMATO 	{
2990d8f6b0edSMasatake YAMATO 		EsObject * o = ptrArrayItemFromLast (vm->ostack, i);
2991d8f6b0edSMasatake YAMATO 		ptrArrayAdd (a, es_object_ref (o));
2992d8f6b0edSMasatake YAMATO 	}
2993d8f6b0edSMasatake YAMATO 
2994d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, l);
2995d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, array);
2996d8f6b0edSMasatake YAMATO 	es_object_unref (array);
2997d8f6b0edSMasatake YAMATO 	return es_false;
2998d8f6b0edSMasatake YAMATO }
2999d8f6b0edSMasatake YAMATO 
3000d8f6b0edSMasatake YAMATO static EsObject*
op_aload(OptVM * vm,EsObject * name)3001d8f6b0edSMasatake YAMATO op_aload (OptVM *vm, EsObject *name)
3002d8f6b0edSMasatake YAMATO {
3003d8f6b0edSMasatake YAMATO 	EsObject *array = ptrArrayLast (vm->ostack);
3004d8f6b0edSMasatake YAMATO 	if (es_object_get_type (array) != OPT_TYPE_ARRAY)
3005d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3006d8f6b0edSMasatake YAMATO 	ptrArray *a = es_pointer_get (array);
3007d8f6b0edSMasatake YAMATO 
3008d8f6b0edSMasatake YAMATO 	ptrArrayRemoveLast (vm->ostack);
3009d8f6b0edSMasatake YAMATO 	unsigned int c =  ptrArrayCount (a);
3010d8f6b0edSMasatake YAMATO 	for (unsigned int i = 0; i < c; i++)
3011d8f6b0edSMasatake YAMATO 	{
3012d8f6b0edSMasatake YAMATO 		EsObject *o = ptrArrayItem (a, i);
3013d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, o);
3014d8f6b0edSMasatake YAMATO 	}
3015d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, array);
3016d8f6b0edSMasatake YAMATO 	es_object_unref (array);
3017d8f6b0edSMasatake YAMATO 	return es_false;
3018d8f6b0edSMasatake YAMATO }
3019d8f6b0edSMasatake YAMATO 
3020d8f6b0edSMasatake YAMATO 
3021d8f6b0edSMasatake YAMATO /*
3022d8f6b0edSMasatake YAMATO  * Operators for dictionary manipulation
3023d8f6b0edSMasatake YAMATO  */
3024d8f6b0edSMasatake YAMATO static EsObject*
op_dict(OptVM * vm,EsObject * name)3025d8f6b0edSMasatake YAMATO op_dict (OptVM *vm, EsObject *name)
3026d8f6b0edSMasatake YAMATO {
3027d8f6b0edSMasatake YAMATO 	EsObject *nobj = ptrArrayLast (vm->ostack);
3028d8f6b0edSMasatake YAMATO 	if (!es_integer_p (nobj))
3029d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3030d8f6b0edSMasatake YAMATO 
3031d8f6b0edSMasatake YAMATO 	int n = es_integer_get (nobj);
3032d8f6b0edSMasatake YAMATO 	if (n < 1)
3033d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
3034d8f6b0edSMasatake YAMATO 
3035d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3036d8f6b0edSMasatake YAMATO 
3037d8f6b0edSMasatake YAMATO 	EsObject *dict = dict_new (n, ATTR_READABLE|ATTR_WRITABLE);
3038d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, dict);
3039d8f6b0edSMasatake YAMATO 	es_object_unref (dict);
3040d8f6b0edSMasatake YAMATO 
3041d8f6b0edSMasatake YAMATO 	return es_false;
3042d8f6b0edSMasatake YAMATO }
3043d8f6b0edSMasatake YAMATO 
3044d8f6b0edSMasatake YAMATO static EsObject*
op_def(OptVM * vm,EsObject * name)3045d8f6b0edSMasatake YAMATO op_def (OptVM *vm, EsObject *name)
3046d8f6b0edSMasatake YAMATO {
3047d8f6b0edSMasatake YAMATO 	EsObject *val = ptrArrayLast (vm->ostack);
3048d8f6b0edSMasatake YAMATO 	EsObject *key = ptrArrayItemFromLast (vm->ostack, 1);
3049d8f6b0edSMasatake YAMATO 	/* TODO */
3050d8f6b0edSMasatake YAMATO 	if (es_object_get_type (key) != OPT_TYPE_NAME)
3051d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3052d8f6b0edSMasatake YAMATO 
3053d8f6b0edSMasatake YAMATO 	vm_dict_def (vm, key, val);
3054d8f6b0edSMasatake YAMATO 
3055d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch(vm->ostack, 2);
3056d8f6b0edSMasatake YAMATO 
3057d8f6b0edSMasatake YAMATO 	return es_false;
3058d8f6b0edSMasatake YAMATO }
3059d8f6b0edSMasatake YAMATO 
3060d8f6b0edSMasatake YAMATO static EsObject*
op_undef(OptVM * vm,EsObject * name)3061d8f6b0edSMasatake YAMATO op_undef (OptVM *vm, EsObject *name)
3062d8f6b0edSMasatake YAMATO {
3063d8f6b0edSMasatake YAMATO 	EsObject *key = ptrArrayLast (vm->ostack);
3064d8f6b0edSMasatake YAMATO 	EsObject *dict = ptrArrayItemFromLast (vm->ostack, 1);
3065d8f6b0edSMasatake YAMATO 
3066d8f6b0edSMasatake YAMATO 	if (es_object_get_type (key) != OPT_TYPE_NAME)
3067d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3068d8f6b0edSMasatake YAMATO 
3069d8f6b0edSMasatake YAMATO 	if (es_object_get_type (dict) != OPT_TYPE_DICT)
3070d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3071d8f6b0edSMasatake YAMATO 
3072d8f6b0edSMasatake YAMATO 	unsigned int attr = ((DictFat *)es_fatptr_get (dict))->attr;
3073d8f6b0edSMasatake YAMATO 	if (!(attr & ATTR_WRITABLE))
3074d8f6b0edSMasatake YAMATO 		return OPT_ERR_INVALIDACCESS;
3075d8f6b0edSMasatake YAMATO 
3076d8f6b0edSMasatake YAMATO 	if (!dict_op_undef (dict, key))
3077d8f6b0edSMasatake YAMATO 		return es_error_set_object (OPT_ERR_UNDEFINED, key);
3078d8f6b0edSMasatake YAMATO 
3079d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 2);
3080d8f6b0edSMasatake YAMATO 	return es_false;
3081d8f6b0edSMasatake YAMATO }
3082d8f6b0edSMasatake YAMATO 
3083d8f6b0edSMasatake YAMATO static EsObject*
op_begin(OptVM * vm,EsObject * name)3084d8f6b0edSMasatake YAMATO op_begin (OptVM *vm, EsObject *name)
3085d8f6b0edSMasatake YAMATO {
3086d8f6b0edSMasatake YAMATO 	EsObject *d = ptrArrayLast (vm->ostack);
3087d8f6b0edSMasatake YAMATO 	if (es_object_get_type (d) != OPT_TYPE_DICT)
3088d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3089d8f6b0edSMasatake YAMATO 
3090d8f6b0edSMasatake YAMATO 	vm_dstack_push (vm, d);
3091d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3092d8f6b0edSMasatake YAMATO 
3093d8f6b0edSMasatake YAMATO 	return es_false;
3094d8f6b0edSMasatake YAMATO }
3095d8f6b0edSMasatake YAMATO 
3096d8f6b0edSMasatake YAMATO static EsObject*
op_end(OptVM * vm,EsObject * name)3097d8f6b0edSMasatake YAMATO op_end (OptVM *vm, EsObject *name)
3098d8f6b0edSMasatake YAMATO {
3099d8f6b0edSMasatake YAMATO 	return vm_dstack_pop (vm);
3100d8f6b0edSMasatake YAMATO }
3101d8f6b0edSMasatake YAMATO 
3102d8f6b0edSMasatake YAMATO static EsObject*
op_currentdict(OptVM * vm,EsObject * name)3103d8f6b0edSMasatake YAMATO op_currentdict (OptVM *vm, EsObject *name)
3104d8f6b0edSMasatake YAMATO {
3105d8f6b0edSMasatake YAMATO 	EsObject *dict = ptrArrayLast (vm->dstack);
3106d8f6b0edSMasatake YAMATO 
3107d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, dict);
3108d8f6b0edSMasatake YAMATO 
3109d8f6b0edSMasatake YAMATO 	return es_false;
3110d8f6b0edSMasatake YAMATO }
3111d8f6b0edSMasatake YAMATO 
3112d8f6b0edSMasatake YAMATO static EsObject*
op_countdictstack(OptVM * vm,EsObject * name)3113d8f6b0edSMasatake YAMATO op_countdictstack (OptVM *vm, EsObject *name)
3114d8f6b0edSMasatake YAMATO {
3115d8f6b0edSMasatake YAMATO 	unsigned int c = ptrArrayCount (vm->dstack);
3116d8f6b0edSMasatake YAMATO 	int n = c;
3117d8f6b0edSMasatake YAMATO 
3118d8f6b0edSMasatake YAMATO 	if (n < 0)
3119d8f6b0edSMasatake YAMATO 		return OPT_ERR_INTERNALERROR; /* TODO: integer overflow */
3120d8f6b0edSMasatake YAMATO 
3121d8f6b0edSMasatake YAMATO 	EsObject *nobj = es_integer_new (n);
3122d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, nobj);
3123d8f6b0edSMasatake YAMATO 	es_object_unref (nobj);
3124d8f6b0edSMasatake YAMATO 
3125d8f6b0edSMasatake YAMATO 	return es_false;
3126d8f6b0edSMasatake YAMATO }
3127d8f6b0edSMasatake YAMATO 
3128d8f6b0edSMasatake YAMATO static EsObject*
op_dictstack(OptVM * vm,EsObject * name)3129d8f6b0edSMasatake YAMATO op_dictstack (OptVM *vm, EsObject *name)
3130d8f6b0edSMasatake YAMATO {
3131d8f6b0edSMasatake YAMATO 	EsObject *obj = ptrArrayLast (vm->ostack);
3132d8f6b0edSMasatake YAMATO 	if (es_object_get_type (obj) != OPT_TYPE_ARRAY)
3133d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3134d8f6b0edSMasatake YAMATO 
3135d8f6b0edSMasatake YAMATO 	return op__stack_common (vm, name, vm->dstack, obj, false);
3136d8f6b0edSMasatake YAMATO }
3137d8f6b0edSMasatake YAMATO 
3138d8f6b0edSMasatake YAMATO static EsObject*
op_cleardictstack(OptVM * vm,EsObject * name)3139d8f6b0edSMasatake YAMATO op_cleardictstack (OptVM *vm, EsObject *name)
3140d8f6b0edSMasatake YAMATO {
3141d8f6b0edSMasatake YAMATO 	unsigned int d = ptrArrayCount (vm->dstack) - vm->dstack_protection;
3142d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->dstack, d);
3143d8f6b0edSMasatake YAMATO 	return es_false;
3144d8f6b0edSMasatake YAMATO }
3145d8f6b0edSMasatake YAMATO 
3146d8f6b0edSMasatake YAMATO static EsObject*
op_where(OptVM * vm,EsObject * name)3147d8f6b0edSMasatake YAMATO op_where (OptVM *vm, EsObject *name)
3148d8f6b0edSMasatake YAMATO {
3149d8f6b0edSMasatake YAMATO 	EsObject *key = ptrArrayLast (vm->ostack);
3150d8f6b0edSMasatake YAMATO 	if (es_object_get_type (key) != OPT_TYPE_NAME)
3151d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3152d8f6b0edSMasatake YAMATO 
3153d8f6b0edSMasatake YAMATO 	EsObject *dict = vm_dstack_known_and_get (vm, key, NULL);
3154d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3155d8f6b0edSMasatake YAMATO 
3156d8f6b0edSMasatake YAMATO 	if (es_object_get_type (dict) != OPT_TYPE_DICT)
3157d8f6b0edSMasatake YAMATO 	{
3158d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, es_false);
3159d8f6b0edSMasatake YAMATO 		return es_false;
3160d8f6b0edSMasatake YAMATO 	}
3161d8f6b0edSMasatake YAMATO 	else
3162d8f6b0edSMasatake YAMATO 	{
3163d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, dict);
3164d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, es_true);
3165d8f6b0edSMasatake YAMATO 		return es_false;
3166d8f6b0edSMasatake YAMATO 	}
3167d8f6b0edSMasatake YAMATO }
3168d8f6b0edSMasatake YAMATO 
3169d8f6b0edSMasatake YAMATO static EsObject*
op_known(OptVM * vm,EsObject * name)3170d8f6b0edSMasatake YAMATO op_known (OptVM *vm, EsObject *name)
3171d8f6b0edSMasatake YAMATO {
3172d8f6b0edSMasatake YAMATO 	EsObject *key  = ptrArrayLast (vm->ostack);
3173d8f6b0edSMasatake YAMATO 	EsObject *dict = ptrArrayItemFromLast (vm->ostack, 1);
3174d8f6b0edSMasatake YAMATO 
3175d8f6b0edSMasatake YAMATO 	if (es_object_get_type (dict) != OPT_TYPE_DICT)
3176d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3177d8f6b0edSMasatake YAMATO 
3178d8f6b0edSMasatake YAMATO 	EsObject *b =  dict_op_known_and_get (dict, key, NULL)
3179d8f6b0edSMasatake YAMATO 		? es_true
3180d8f6b0edSMasatake YAMATO 		: es_false;
3181d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 2);
3182d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, b);
3183d8f6b0edSMasatake YAMATO 
3184d8f6b0edSMasatake YAMATO 	return false;
3185d8f6b0edSMasatake YAMATO }
3186d8f6b0edSMasatake YAMATO 
3187d8f6b0edSMasatake YAMATO static EsObject*
op_store(OptVM * vm,EsObject * name)3188d8f6b0edSMasatake YAMATO op_store (OptVM *vm, EsObject *name)
3189d8f6b0edSMasatake YAMATO {
3190d8f6b0edSMasatake YAMATO 	EsObject *val = ptrArrayLast (vm->ostack);
3191d8f6b0edSMasatake YAMATO 	EsObject *key = ptrArrayItemFromLast (vm->ostack, 1);
3192d8f6b0edSMasatake YAMATO 
3193d8f6b0edSMasatake YAMATO 	if (es_null (key))
3194d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3195d8f6b0edSMasatake YAMATO 	if (es_object_get_type (key) != OPT_TYPE_NAME)
3196d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3197d8f6b0edSMasatake YAMATO 
3198d8f6b0edSMasatake YAMATO 	EsObject *dict = vm_dstack_known_and_get (vm, key, NULL);
3199d8f6b0edSMasatake YAMATO 	if (es_object_get_type (dict) != OPT_TYPE_DICT)
3200d8f6b0edSMasatake YAMATO 		vm_dict_def (vm, key, val);
3201d8f6b0edSMasatake YAMATO 	else if (!(((DictFat *)es_fatptr_get (dict))->attr & ATTR_WRITABLE))
3202d8f6b0edSMasatake YAMATO 		return OPT_ERR_INVALIDACCESS;
3203d8f6b0edSMasatake YAMATO 	else
3204d8f6b0edSMasatake YAMATO 		dict_op_def (dict, key, val);
3205d8f6b0edSMasatake YAMATO 
3206d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch(vm->ostack, 2);
3207d8f6b0edSMasatake YAMATO 	return es_false;
3208d8f6b0edSMasatake YAMATO }
3209d8f6b0edSMasatake YAMATO 
3210d8f6b0edSMasatake YAMATO static EsObject*
op_load(OptVM * vm,EsObject * name)3211d8f6b0edSMasatake YAMATO op_load (OptVM *vm, EsObject *name)
3212d8f6b0edSMasatake YAMATO {
3213d8f6b0edSMasatake YAMATO 	EsObject *key = ptrArrayLast (vm->ostack);
3214d8f6b0edSMasatake YAMATO 	EsObject *val = NULL;
3215d8f6b0edSMasatake YAMATO 	EsObject *dict = vm_dstack_known_and_get (vm, key, &val);
3216d8f6b0edSMasatake YAMATO 
3217d8f6b0edSMasatake YAMATO 	if (es_object_get_type (dict) != OPT_TYPE_DICT)
3218d8f6b0edSMasatake YAMATO 		return es_error_set_object (OPT_ERR_UNDEFINED, key);
3219d8f6b0edSMasatake YAMATO 	else
3220d8f6b0edSMasatake YAMATO 	{
3221d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLast (vm->ostack);
3222d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, val);
3223d8f6b0edSMasatake YAMATO 		return es_false;
3224d8f6b0edSMasatake YAMATO 	}
3225d8f6b0edSMasatake YAMATO }
3226d8f6b0edSMasatake YAMATO 
3227d8f6b0edSMasatake YAMATO 
3228d8f6b0edSMasatake YAMATO /*
3229d8f6b0edSMasatake YAMATO  * Operators for string manipulation
3230d8f6b0edSMasatake YAMATO  */
3231d8f6b0edSMasatake YAMATO static EsObject*
op_string(OptVM * vm,EsObject * name)3232d8f6b0edSMasatake YAMATO op_string (OptVM *vm, EsObject *name)
3233d8f6b0edSMasatake YAMATO {
3234d8f6b0edSMasatake YAMATO 	EsObject *nobj = ptrArrayLast (vm->ostack);
3235d8f6b0edSMasatake YAMATO 	if (!es_integer_p (nobj))
3236d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3237d8f6b0edSMasatake YAMATO 	int n = es_integer_get (nobj);
3238d8f6b0edSMasatake YAMATO 	if (n < 0)
3239d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
3240d8f6b0edSMasatake YAMATO 
3241d8f6b0edSMasatake YAMATO 	vString *s = vStringNew ();
3242d8f6b0edSMasatake YAMATO 
3243d8f6b0edSMasatake YAMATO 	while (n-- > 0)
3244d8f6b0edSMasatake YAMATO 		vStringPut (s, ' ');
3245d8f6b0edSMasatake YAMATO 
3246d8f6b0edSMasatake YAMATO 	EsObject *sobj = string_new (s);
3247d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3248d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, sobj);
3249d8f6b0edSMasatake YAMATO 	es_object_unref (sobj);
3250d8f6b0edSMasatake YAMATO 	return es_false;
3251d8f6b0edSMasatake YAMATO }
3252d8f6b0edSMasatake YAMATO 
3253d8f6b0edSMasatake YAMATO static EsObject*
op__strstr_common(OptVM * vm,EsObject * name,bool fromTail)3254d8f6b0edSMasatake YAMATO op__strstr_common (OptVM *vm, EsObject *name, bool fromTail)
3255d8f6b0edSMasatake YAMATO {
3256d8f6b0edSMasatake YAMATO 	EsObject *seekobj = ptrArrayLast (vm->ostack);
3257d8f6b0edSMasatake YAMATO 	EsObject *strobj = ptrArrayItemFromLast (vm->ostack, 1);
3258d8f6b0edSMasatake YAMATO 
3259d8f6b0edSMasatake YAMATO 	if (es_object_get_type (strobj) != OPT_TYPE_STRING)
3260d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3261d8f6b0edSMasatake YAMATO 	if (es_object_get_type (seekobj) != OPT_TYPE_STRING)
3262d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3263d8f6b0edSMasatake YAMATO 
3264d8f6b0edSMasatake YAMATO 	vString *stringv = es_pointer_get (strobj);
3265d8f6b0edSMasatake YAMATO 	vString *seekv = es_pointer_get (seekobj);
3266d8f6b0edSMasatake YAMATO 
3267d8f6b0edSMasatake YAMATO 	if (vStringLength (stringv) < vStringLength (seekv))
3268d8f6b0edSMasatake YAMATO 	{
3269d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLast (vm->ostack);
3270d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, es_false);
3271d8f6b0edSMasatake YAMATO 		return es_false;
3272d8f6b0edSMasatake YAMATO 	}
3273d8f6b0edSMasatake YAMATO 
3274d8f6b0edSMasatake YAMATO 	const char *stringc = vStringValue (stringv);
3275d8f6b0edSMasatake YAMATO 	const char *seekc = vStringValue (seekv);
3276d8f6b0edSMasatake YAMATO 	char *tmp = (fromTail? strrstr: strstr) (stringc, seekc);
3277d8f6b0edSMasatake YAMATO 
3278d8f6b0edSMasatake YAMATO 	if (tmp == NULL)
3279d8f6b0edSMasatake YAMATO 	{
3280d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLast (vm->ostack);
3281d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, es_false);
3282d8f6b0edSMasatake YAMATO 		return es_false;
3283d8f6b0edSMasatake YAMATO 	}
3284d8f6b0edSMasatake YAMATO 
3285d8f6b0edSMasatake YAMATO 	unsigned int ud = tmp - stringc;
3286d8f6b0edSMasatake YAMATO 	int d = (int)ud;
3287d8f6b0edSMasatake YAMATO 	if (d < 0)
3288d8f6b0edSMasatake YAMATO 		return OPT_ERR_INTERNALERROR; /* TODO: integer overflow */
3289d8f6b0edSMasatake YAMATO 
3290d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3291d8f6b0edSMasatake YAMATO 	EsObject* dobj = es_integer_new (d);
3292d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, dobj);
3293d8f6b0edSMasatake YAMATO 	es_object_unref (dobj);
3294d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, es_true);
3295d8f6b0edSMasatake YAMATO 	return es_false;
3296d8f6b0edSMasatake YAMATO }
3297d8f6b0edSMasatake YAMATO 
3298d8f6b0edSMasatake YAMATO static EsObject*
op__strstr(OptVM * vm,EsObject * name)3299d8f6b0edSMasatake YAMATO op__strstr (OptVM *vm, EsObject *name)
3300d8f6b0edSMasatake YAMATO {
3301d8f6b0edSMasatake YAMATO 	return op__strstr_common (vm, name, false);
3302d8f6b0edSMasatake YAMATO }
3303d8f6b0edSMasatake YAMATO 
3304d8f6b0edSMasatake YAMATO static EsObject*
op__strrstr(OptVM * vm,EsObject * name)3305d8f6b0edSMasatake YAMATO op__strrstr (OptVM *vm, EsObject *name)
3306d8f6b0edSMasatake YAMATO {
3307d8f6b0edSMasatake YAMATO 	return op__strstr_common (vm, name, true);
3308d8f6b0edSMasatake YAMATO }
3309d8f6b0edSMasatake YAMATO 
3310d8f6b0edSMasatake YAMATO static EsObject*
op__strchr_common(OptVM * vm,EsObject * name,bool fromTail)3311d8f6b0edSMasatake YAMATO op__strchr_common (OptVM *vm, EsObject *name, bool fromTail)
3312d8f6b0edSMasatake YAMATO {
3313d8f6b0edSMasatake YAMATO 	EsObject *chrobj = ptrArrayLast (vm->ostack);
3314d8f6b0edSMasatake YAMATO 	EsObject *strobj = ptrArrayItemFromLast (vm->ostack, 1);
3315d8f6b0edSMasatake YAMATO 
3316d8f6b0edSMasatake YAMATO 	if (! es_integer_p (chrobj))
3317d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3318d8f6b0edSMasatake YAMATO 
3319d8f6b0edSMasatake YAMATO 	unsigned int chr = (unsigned int)es_integer_get (chrobj);
3320d8f6b0edSMasatake YAMATO 	/* 0 is unacceptable. */
3321d8f6b0edSMasatake YAMATO 	if (! (0 < chr && chr < 256))
3322d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
3323d8f6b0edSMasatake YAMATO 
3324d8f6b0edSMasatake YAMATO 	if (es_object_get_type (strobj) != OPT_TYPE_STRING)
3325d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3326d8f6b0edSMasatake YAMATO 
3327d8f6b0edSMasatake YAMATO 	vString *strv = es_pointer_get (strobj);
3328d8f6b0edSMasatake YAMATO 	const char *str = vStringValue (strv);
3329d8f6b0edSMasatake YAMATO 
3330d8f6b0edSMasatake YAMATO 	char * p = (fromTail? strrchr: strchr) (str, (int)chr);
3331d8f6b0edSMasatake YAMATO 	if (p)
3332d8f6b0edSMasatake YAMATO 	{
3333d8f6b0edSMasatake YAMATO 		int d = p - str;
3334d8f6b0edSMasatake YAMATO 		if (d < 0)
3335d8f6b0edSMasatake YAMATO 			return OPT_ERR_INTERNALERROR; /* TODO: integer overflow */
3336d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLast (vm->ostack);
3337d8f6b0edSMasatake YAMATO 		EsObject *dobj = es_integer_new (d);
3338d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, dobj);
3339d8f6b0edSMasatake YAMATO 		es_object_unref (dobj);
3340d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, es_true);
3341d8f6b0edSMasatake YAMATO 		return es_false;
3342d8f6b0edSMasatake YAMATO 	}
3343d8f6b0edSMasatake YAMATO 	else
3344d8f6b0edSMasatake YAMATO 	{
3345d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLast (vm->ostack);
3346d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, es_false);
3347d8f6b0edSMasatake YAMATO 		return es_false;
3348d8f6b0edSMasatake YAMATO 	}
3349d8f6b0edSMasatake YAMATO }
3350d8f6b0edSMasatake YAMATO 
3351d8f6b0edSMasatake YAMATO static EsObject*
op__strchr(OptVM * vm,EsObject * name)3352d8f6b0edSMasatake YAMATO op__strchr (OptVM *vm, EsObject *name)
3353d8f6b0edSMasatake YAMATO {
3354d8f6b0edSMasatake YAMATO 	return op__strchr_common (vm, name, false);
3355d8f6b0edSMasatake YAMATO }
3356d8f6b0edSMasatake YAMATO 
3357d8f6b0edSMasatake YAMATO static EsObject*
op__strrchr(OptVM * vm,EsObject * name)3358d8f6b0edSMasatake YAMATO op__strrchr (OptVM *vm, EsObject *name)
3359d8f6b0edSMasatake YAMATO {
3360d8f6b0edSMasatake YAMATO 	return op__strchr_common (vm, name, true);
3361d8f6b0edSMasatake YAMATO }
3362d8f6b0edSMasatake YAMATO 
3363d8f6b0edSMasatake YAMATO static EsObject*
op__strpbrk(OptVM * vm,EsObject * name)3364d8f6b0edSMasatake YAMATO op__strpbrk (OptVM *vm, EsObject *name)
3365d8f6b0edSMasatake YAMATO {
3366d8f6b0edSMasatake YAMATO 	EsObject *acceptobj = ptrArrayLast (vm->ostack);
3367d8f6b0edSMasatake YAMATO 	EsObject *strobj = ptrArrayItemFromLast (vm->ostack, 1);
3368d8f6b0edSMasatake YAMATO 
3369d8f6b0edSMasatake YAMATO 	if (es_object_get_type (strobj) != OPT_TYPE_STRING)
3370d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3371d8f6b0edSMasatake YAMATO 	if (es_object_get_type (acceptobj) != OPT_TYPE_STRING)
3372d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3373d8f6b0edSMasatake YAMATO 
3374d8f6b0edSMasatake YAMATO 	vString *strv = es_pointer_get (strobj);
3375d8f6b0edSMasatake YAMATO 	vString *acceptv = es_pointer_get (acceptobj);
3376d8f6b0edSMasatake YAMATO 
3377d8f6b0edSMasatake YAMATO 	const char *str = vStringValue (strv);
3378d8f6b0edSMasatake YAMATO 	char *p = strpbrk (str, vStringValue (acceptv));
3379d8f6b0edSMasatake YAMATO 	if (p)
3380d8f6b0edSMasatake YAMATO 	{
3381d8f6b0edSMasatake YAMATO 		int d = p - str;
3382d8f6b0edSMasatake YAMATO 		if (d < 0)
3383d8f6b0edSMasatake YAMATO 			return OPT_ERR_INTERNALERROR; /* TODO: integer overflow */
3384d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLast (vm->ostack);
3385d8f6b0edSMasatake YAMATO 		EsObject *dobj = es_integer_new (d);
3386d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, dobj);
3387d8f6b0edSMasatake YAMATO 		es_object_unref (dobj);
3388d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, es_true);
3389d8f6b0edSMasatake YAMATO 		return es_false;
3390d8f6b0edSMasatake YAMATO 	}
3391d8f6b0edSMasatake YAMATO 	else
3392d8f6b0edSMasatake YAMATO 	{
3393d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLast (vm->ostack);
3394d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, es_false);
3395d8f6b0edSMasatake YAMATO 		return es_false;
3396d8f6b0edSMasatake YAMATO 	}
3397d8f6b0edSMasatake YAMATO }
3398d8f6b0edSMasatake YAMATO 
3399d8f6b0edSMasatake YAMATO 
3400d8f6b0edSMasatake YAMATO /*
3401d8f6b0edSMasatake YAMATO  * Relation, logical, and bit operators
3402d8f6b0edSMasatake YAMATO  */
3403d8f6b0edSMasatake YAMATO static EsObject*
op__eq_full(OptVM * vm,EsObject * name,bool inversion)3404d8f6b0edSMasatake YAMATO op__eq_full (OptVM *vm, EsObject *name, bool inversion)
3405d8f6b0edSMasatake YAMATO {
3406d8f6b0edSMasatake YAMATO 	EsObject *a = ptrArrayItemFromLast (vm->ostack, 0);
3407d8f6b0edSMasatake YAMATO 	EsObject *b = ptrArrayItemFromLast (vm->ostack, 1);
3408d8f6b0edSMasatake YAMATO 
3409d8f6b0edSMasatake YAMATO 	bool eq = opt_es_eq (a, b);
3410d8f6b0edSMasatake YAMATO 	EsObject *r = (inversion? (!eq): eq)? es_true: es_false;
3411d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 2);
3412d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, r);
3413d8f6b0edSMasatake YAMATO 	return es_false;
3414d8f6b0edSMasatake YAMATO }
3415d8f6b0edSMasatake YAMATO 
3416d8f6b0edSMasatake YAMATO 
3417d8f6b0edSMasatake YAMATO /*
3418d8f6b0edSMasatake YAMATO  * Relation, logical, and bit operators
3419d8f6b0edSMasatake YAMATO  */
3420d8f6b0edSMasatake YAMATO static EsObject*
op_eq(OptVM * vm,EsObject * name)3421d8f6b0edSMasatake YAMATO op_eq (OptVM *vm, EsObject *name)
3422d8f6b0edSMasatake YAMATO {
3423d8f6b0edSMasatake YAMATO 	op__eq_full (vm, name, false);
3424d8f6b0edSMasatake YAMATO 	return es_false;
3425d8f6b0edSMasatake YAMATO 
3426d8f6b0edSMasatake YAMATO }
3427d8f6b0edSMasatake YAMATO 
3428d8f6b0edSMasatake YAMATO static EsObject*
op_ne(OptVM * vm,EsObject * name)3429d8f6b0edSMasatake YAMATO op_ne (OptVM *vm, EsObject *name)
3430d8f6b0edSMasatake YAMATO {
3431d8f6b0edSMasatake YAMATO 	op__eq_full (vm, name, true);
3432d8f6b0edSMasatake YAMATO 	return es_false;
3433d8f6b0edSMasatake YAMATO 
3434d8f6b0edSMasatake YAMATO }
3435d8f6b0edSMasatake YAMATO 
3436d8f6b0edSMasatake YAMATO static EsObject*
op_true(OptVM * vm,EsObject * name)3437d8f6b0edSMasatake YAMATO op_true (OptVM *vm, EsObject *name)
3438d8f6b0edSMasatake YAMATO {
3439d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, es_true);
3440d8f6b0edSMasatake YAMATO 	return es_false;
3441d8f6b0edSMasatake YAMATO 
3442d8f6b0edSMasatake YAMATO }
3443d8f6b0edSMasatake YAMATO 
3444d8f6b0edSMasatake YAMATO static EsObject*
op_false(OptVM * vm,EsObject * name)3445d8f6b0edSMasatake YAMATO op_false (OptVM *vm, EsObject *name)
3446d8f6b0edSMasatake YAMATO {
3447d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, es_false);
3448d8f6b0edSMasatake YAMATO 	return es_false;
3449d8f6b0edSMasatake YAMATO }
3450d8f6b0edSMasatake YAMATO 
3451d8f6b0edSMasatake YAMATO #define CMP_OP(OP)											\
3452d8f6b0edSMasatake YAMATO 	EsObject *o0 = ptrArrayLast (vm->ostack);				\
3453d8f6b0edSMasatake YAMATO 	EsObject *o1 = ptrArrayItemFromLast (vm->ostack, 1);	\
3454d8f6b0edSMasatake YAMATO 	EsObject *r;											\
3455d8f6b0edSMasatake YAMATO 															\
3456d8f6b0edSMasatake YAMATO 	if (es_integer_p (o0))									\
3457d8f6b0edSMasatake YAMATO 	{														\
3458d8f6b0edSMasatake YAMATO 		if (!es_integer_p (o1))								\
3459d8f6b0edSMasatake YAMATO 			return OPT_ERR_TYPECHECK;						\
3460d8f6b0edSMasatake YAMATO 															\
3461d8f6b0edSMasatake YAMATO 		int i0 = es_integer_get (o0);						\
3462d8f6b0edSMasatake YAMATO 		int i1 = es_integer_get (o1);						\
3463d8f6b0edSMasatake YAMATO 		r = es_boolean_new (i1 OP i0);						\
3464d8f6b0edSMasatake YAMATO 	}														\
3465d8f6b0edSMasatake YAMATO 	else if (es_object_get_type (o0) == OPT_TYPE_STRING)	\
3466d8f6b0edSMasatake YAMATO 	{														\
3467d8f6b0edSMasatake YAMATO 		if (es_object_get_type (o1) != OPT_TYPE_STRING)		\
3468d8f6b0edSMasatake YAMATO 			return OPT_ERR_TYPECHECK;						\
3469d8f6b0edSMasatake YAMATO 		vString *vs0 = es_pointer_get (o0);					\
3470d8f6b0edSMasatake YAMATO 		vString *vs1 = es_pointer_get (o1);					\
3471d8f6b0edSMasatake YAMATO 		const char *s0 = vStringValue (vs0);				\
3472d8f6b0edSMasatake YAMATO 		const char *s1 = vStringValue (vs1);				\
3473d8f6b0edSMasatake YAMATO 		int d = strcmp (s1, s0);							\
3474d8f6b0edSMasatake YAMATO 		r = es_boolean_new (d OP 0);						\
3475d8f6b0edSMasatake YAMATO 	}														\
3476d8f6b0edSMasatake YAMATO 	else													\
3477d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;							\
3478d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 2);				\
3479d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, r);									\
3480d8f6b0edSMasatake YAMATO 	es_object_unref (r);									\
3481d8f6b0edSMasatake YAMATO 	return es_false
3482d8f6b0edSMasatake YAMATO 
3483d8f6b0edSMasatake YAMATO static EsObject*
op_ge(OptVM * vm,EsObject * name)3484d8f6b0edSMasatake YAMATO op_ge (OptVM *vm, EsObject *name)
3485d8f6b0edSMasatake YAMATO {
3486d8f6b0edSMasatake YAMATO 	CMP_OP (>=);
3487d8f6b0edSMasatake YAMATO }
3488d8f6b0edSMasatake YAMATO 
3489d8f6b0edSMasatake YAMATO static EsObject*
op_gt(OptVM * vm,EsObject * name)3490d8f6b0edSMasatake YAMATO op_gt (OptVM *vm, EsObject *name)
3491d8f6b0edSMasatake YAMATO {
3492d8f6b0edSMasatake YAMATO 	CMP_OP (>);
3493d8f6b0edSMasatake YAMATO }
3494d8f6b0edSMasatake YAMATO 
3495d8f6b0edSMasatake YAMATO static EsObject*
op_le(OptVM * vm,EsObject * name)3496d8f6b0edSMasatake YAMATO op_le (OptVM *vm, EsObject *name)
3497d8f6b0edSMasatake YAMATO {
3498d8f6b0edSMasatake YAMATO 	CMP_OP (<=);
3499d8f6b0edSMasatake YAMATO }
3500d8f6b0edSMasatake YAMATO 
3501d8f6b0edSMasatake YAMATO static EsObject*
op_lt(OptVM * vm,EsObject * name)3502d8f6b0edSMasatake YAMATO op_lt (OptVM *vm, EsObject *name)
3503d8f6b0edSMasatake YAMATO {
3504d8f6b0edSMasatake YAMATO 	CMP_OP (<);
3505d8f6b0edSMasatake YAMATO }
3506d8f6b0edSMasatake YAMATO 
3507d8f6b0edSMasatake YAMATO #define LOGBIT_OP(LOGOP, BITOP)									\
3508d8f6b0edSMasatake YAMATO 	EsObject *o0 = ptrArrayLast (vm->ostack);					\
3509d8f6b0edSMasatake YAMATO 	EsObject *o1 = ptrArrayItemFromLast (vm->ostack, 1);		\
3510d8f6b0edSMasatake YAMATO 	EsObject *r;												\
3511d8f6b0edSMasatake YAMATO 																\
3512d8f6b0edSMasatake YAMATO 	if (es_boolean_p (o0))										\
3513d8f6b0edSMasatake YAMATO 	{															\
3514d8f6b0edSMasatake YAMATO 		if (!es_boolean_p (o1))									\
3515d8f6b0edSMasatake YAMATO 			return OPT_ERR_TYPECHECK;							\
3516d8f6b0edSMasatake YAMATO 		bool b0 = es_boolean_get (o0);							\
3517d8f6b0edSMasatake YAMATO 		bool b1 = es_boolean_get (o1);							\
3518d8f6b0edSMasatake YAMATO 		bool b  = b0 LOGOP b1;									\
3519d8f6b0edSMasatake YAMATO 		r = es_boolean_new (b);									\
3520d8f6b0edSMasatake YAMATO 	}															\
3521d8f6b0edSMasatake YAMATO 	else if (es_integer_p (o0))									\
3522d8f6b0edSMasatake YAMATO 	{															\
3523d8f6b0edSMasatake YAMATO 		if (!es_integer_p (o1))									\
3524d8f6b0edSMasatake YAMATO 			return OPT_ERR_TYPECHECK;							\
3525d8f6b0edSMasatake YAMATO 		int i0 = es_integer_get (o0);							\
3526d8f6b0edSMasatake YAMATO 		int i1 = es_integer_get (o1);							\
3527d8f6b0edSMasatake YAMATO 		int i  = i0 BITOP i1;									\
3528d8f6b0edSMasatake YAMATO 		r = es_integer_new (i);									\
3529d8f6b0edSMasatake YAMATO 	}															\
3530d8f6b0edSMasatake YAMATO 	else														\
3531d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;								\
3532d8f6b0edSMasatake YAMATO 																\
3533d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 2);					\
3534d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, r);										\
3535d8f6b0edSMasatake YAMATO 	es_object_unref (r);										\
3536d8f6b0edSMasatake YAMATO 	return es_false;
3537d8f6b0edSMasatake YAMATO 
3538d8f6b0edSMasatake YAMATO static EsObject*
op_and(OptVM * vm,EsObject * name)3539d8f6b0edSMasatake YAMATO op_and (OptVM *vm, EsObject *name)
3540d8f6b0edSMasatake YAMATO {
3541d8f6b0edSMasatake YAMATO 	LOGBIT_OP (&&, &);
3542d8f6b0edSMasatake YAMATO }
3543d8f6b0edSMasatake YAMATO 
3544d8f6b0edSMasatake YAMATO static EsObject*
op_or(OptVM * vm,EsObject * name)3545d8f6b0edSMasatake YAMATO op_or (OptVM *vm, EsObject *name)
3546d8f6b0edSMasatake YAMATO {
3547d8f6b0edSMasatake YAMATO 	LOGBIT_OP (||, |);
3548d8f6b0edSMasatake YAMATO }
3549d8f6b0edSMasatake YAMATO 
3550d8f6b0edSMasatake YAMATO static EsObject*
op_xor(OptVM * vm,EsObject * name)3551d8f6b0edSMasatake YAMATO op_xor (OptVM *vm, EsObject *name)
3552d8f6b0edSMasatake YAMATO {
3553d8f6b0edSMasatake YAMATO 	LOGBIT_OP (!=, ^);
3554d8f6b0edSMasatake YAMATO }
3555d8f6b0edSMasatake YAMATO 
3556d8f6b0edSMasatake YAMATO static EsObject*
op_not(OptVM * vm,EsObject * name)3557d8f6b0edSMasatake YAMATO op_not (OptVM *vm, EsObject *name)
3558d8f6b0edSMasatake YAMATO {
3559d8f6b0edSMasatake YAMATO 	EsObject *o = ptrArrayLast (vm->ostack);
3560d8f6b0edSMasatake YAMATO 	EsObject *r;
3561d8f6b0edSMasatake YAMATO 
3562d8f6b0edSMasatake YAMATO 	if (es_boolean_p (o))
3563d8f6b0edSMasatake YAMATO 		r = es_boolean_new (!es_boolean_get (o));
3564d8f6b0edSMasatake YAMATO 	else if (es_integer_p (o))
3565d8f6b0edSMasatake YAMATO 		r = es_integer_new (~ es_integer_get (o));
3566d8f6b0edSMasatake YAMATO 	else
3567d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3568d8f6b0edSMasatake YAMATO 
3569d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3570d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, r);
3571d8f6b0edSMasatake YAMATO 	es_object_unref (r);
3572d8f6b0edSMasatake YAMATO 	return es_false;
3573d8f6b0edSMasatake YAMATO }
3574d8f6b0edSMasatake YAMATO 
3575d8f6b0edSMasatake YAMATO static EsObject*
op_bitshift(OptVM * vm,EsObject * name)3576d8f6b0edSMasatake YAMATO op_bitshift (OptVM *vm, EsObject *name)
3577d8f6b0edSMasatake YAMATO {
3578d8f6b0edSMasatake YAMATO 	EsObject *shiftobj = ptrArrayLast (vm->ostack);
3579d8f6b0edSMasatake YAMATO 	if (!es_integer_p (shiftobj))
3580d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3581d8f6b0edSMasatake YAMATO 
3582d8f6b0edSMasatake YAMATO 	EsObject *iobj = ptrArrayItemFromLast (vm->ostack, 1);
3583d8f6b0edSMasatake YAMATO 	if (!es_integer_p (iobj))
3584d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3585d8f6b0edSMasatake YAMATO 
3586d8f6b0edSMasatake YAMATO 	int shift = es_integer_get (shiftobj);
3587d8f6b0edSMasatake YAMATO 	int i = es_integer_get (iobj);
3588d8f6b0edSMasatake YAMATO 
3589d8f6b0edSMasatake YAMATO 	EsObject *r;
3590d8f6b0edSMasatake YAMATO 	if (i == 0 || shift == 0)
3591d8f6b0edSMasatake YAMATO 		r = es_object_ref (iobj);
3592d8f6b0edSMasatake YAMATO 	else if (shift > 0)
3593d8f6b0edSMasatake YAMATO 		r = es_integer_new (i << shift);
3594d8f6b0edSMasatake YAMATO 	else
3595d8f6b0edSMasatake YAMATO 		r = es_integer_new (i >> -shift);
3596d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 2);
3597d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, r);
3598d8f6b0edSMasatake YAMATO 	es_object_unref (r);
3599d8f6b0edSMasatake YAMATO 
3600d8f6b0edSMasatake YAMATO 	return es_false;
3601d8f6b0edSMasatake YAMATO }
3602d8f6b0edSMasatake YAMATO 
3603d8f6b0edSMasatake YAMATO 
3604d8f6b0edSMasatake YAMATO /*
3605d8f6b0edSMasatake YAMATO  * Operators for control flow
3606d8f6b0edSMasatake YAMATO  */
3607d8f6b0edSMasatake YAMATO static EsObject*
op_exec(OptVM * vm,EsObject * name)3608d8f6b0edSMasatake YAMATO op_exec (OptVM *vm, EsObject *name)
3609d8f6b0edSMasatake YAMATO {
3610d8f6b0edSMasatake YAMATO 	EsObject *x = ptrArrayRemoveLast (vm->ostack);
3611d8f6b0edSMasatake YAMATO 
3612d8f6b0edSMasatake YAMATO 	EsObject *e;
3613d8f6b0edSMasatake YAMATO 	if (es_object_get_type (x) == OPT_TYPE_ARRAY
3614d8f6b0edSMasatake YAMATO 		&& (((ArrayFat *)es_fatptr_get (x))->attr & ATTR_EXECUTABLE))
3615d8f6b0edSMasatake YAMATO 		e = vm_call_proc (vm, x);
3616d8f6b0edSMasatake YAMATO 	else
3617d8f6b0edSMasatake YAMATO 		e = vm_eval (vm, x);
3618d8f6b0edSMasatake YAMATO 
3619d8f6b0edSMasatake YAMATO 	es_object_unref (x);
3620d8f6b0edSMasatake YAMATO 	return e;
3621d8f6b0edSMasatake YAMATO }
3622d8f6b0edSMasatake YAMATO 
3623d8f6b0edSMasatake YAMATO static EsObject*
op_if(OptVM * vm,EsObject * name)3624d8f6b0edSMasatake YAMATO op_if (OptVM *vm, EsObject *name)
3625d8f6b0edSMasatake YAMATO {
3626d8f6b0edSMasatake YAMATO 	EsObject *proc = ptrArrayLast (vm->ostack);
3627d8f6b0edSMasatake YAMATO 	if (!((es_object_get_type (proc) == OPT_TYPE_ARRAY)
3628d8f6b0edSMasatake YAMATO 		  && (((ArrayFat *)es_fatptr_get (proc))->attr & ATTR_EXECUTABLE)))
3629d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3630d8f6b0edSMasatake YAMATO 
3631d8f6b0edSMasatake YAMATO 	EsObject *b = ptrArrayItemFromLast	(vm->ostack, 1);
3632d8f6b0edSMasatake YAMATO 	if (!es_boolean_p (b))
3633d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3634d8f6b0edSMasatake YAMATO 
3635d8f6b0edSMasatake YAMATO 	if (es_object_equal (b, es_false))
3636d8f6b0edSMasatake YAMATO 	{
3637d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLast (vm->ostack);
3638d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLast (vm->ostack);
3639d8f6b0edSMasatake YAMATO 		return es_false;
3640d8f6b0edSMasatake YAMATO 	}
3641d8f6b0edSMasatake YAMATO 
3642d8f6b0edSMasatake YAMATO 	es_object_ref (proc);
3643d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3644d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3645d8f6b0edSMasatake YAMATO 	EsObject *e = vm_call_proc (vm, proc);
3646d8f6b0edSMasatake YAMATO 	es_object_unref (proc);
3647d8f6b0edSMasatake YAMATO 
3648d8f6b0edSMasatake YAMATO 	return e;
3649d8f6b0edSMasatake YAMATO }
3650d8f6b0edSMasatake YAMATO 
3651d8f6b0edSMasatake YAMATO static EsObject*
op_ifelse(OptVM * vm,EsObject * name)3652d8f6b0edSMasatake YAMATO op_ifelse (OptVM *vm, EsObject *name)
3653d8f6b0edSMasatake YAMATO {
3654d8f6b0edSMasatake YAMATO 	EsObject *procf = ptrArrayLast (vm->ostack);
3655d8f6b0edSMasatake YAMATO 	if (!((es_object_get_type (procf) == OPT_TYPE_ARRAY)
3656d8f6b0edSMasatake YAMATO 		  && (((ArrayFat *)es_fatptr_get (procf))->attr & ATTR_EXECUTABLE)))
3657d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3658d8f6b0edSMasatake YAMATO 
3659d8f6b0edSMasatake YAMATO 	EsObject *proct = ptrArrayItemFromLast	(vm->ostack, 1);
3660d8f6b0edSMasatake YAMATO 	if (!((es_object_get_type (proct) == OPT_TYPE_ARRAY)
3661d8f6b0edSMasatake YAMATO 		  && (((ArrayFat *)es_fatptr_get (proct))->attr & ATTR_EXECUTABLE)))
3662d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3663d8f6b0edSMasatake YAMATO 
3664d8f6b0edSMasatake YAMATO 	EsObject *b = ptrArrayItemFromLast	(vm->ostack, 2);
3665d8f6b0edSMasatake YAMATO 	if (!es_boolean_p (b))
3666d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3667d8f6b0edSMasatake YAMATO 
3668d8f6b0edSMasatake YAMATO 	EsObject *p = (es_object_equal (b, es_false))? procf: proct;
3669d8f6b0edSMasatake YAMATO 
3670d8f6b0edSMasatake YAMATO 	es_object_ref (p);
3671d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3672d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3673d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3674d8f6b0edSMasatake YAMATO 	EsObject *e = vm_call_proc (vm, p);
3675d8f6b0edSMasatake YAMATO 	es_object_unref (p);
3676d8f6b0edSMasatake YAMATO 
3677d8f6b0edSMasatake YAMATO 	return e;
3678d8f6b0edSMasatake YAMATO }
3679d8f6b0edSMasatake YAMATO 
3680d8f6b0edSMasatake YAMATO static EsObject*
op_loop(OptVM * vm,EsObject * name)3681d8f6b0edSMasatake YAMATO op_loop (OptVM *vm, EsObject *name)
3682d8f6b0edSMasatake YAMATO {
3683d8f6b0edSMasatake YAMATO 	EsObject *proc = ptrArrayLast (vm->ostack);
3684d8f6b0edSMasatake YAMATO 	if (!((es_object_get_type (proc) == OPT_TYPE_ARRAY)
3685d8f6b0edSMasatake YAMATO 		  && (((ArrayFat *)es_fatptr_get (proc))->attr & ATTR_EXECUTABLE)))
3686d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3687d8f6b0edSMasatake YAMATO 
3688d8f6b0edSMasatake YAMATO 	es_object_ref (proc);
3689d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3690d8f6b0edSMasatake YAMATO 
3691d8f6b0edSMasatake YAMATO 	EsObject *e;
3692d8f6b0edSMasatake YAMATO 	while (true)
3693d8f6b0edSMasatake YAMATO 	{
3694d8f6b0edSMasatake YAMATO 		e = vm_call_proc (vm, proc);
3695d8f6b0edSMasatake YAMATO 		if (es_object_equal (e, OPT_ERR_INVALIDEXIT))
3696d8f6b0edSMasatake YAMATO 		{
3697d8f6b0edSMasatake YAMATO 			dict_op_def (vm->error, OPT_KEY_newerror, es_false);
3698d8f6b0edSMasatake YAMATO 			e = es_false;
3699d8f6b0edSMasatake YAMATO 			break;
3700d8f6b0edSMasatake YAMATO 		}
3701d8f6b0edSMasatake YAMATO 		else if (es_error_p (e))
3702d8f6b0edSMasatake YAMATO 			break;
3703d8f6b0edSMasatake YAMATO 	}
3704d8f6b0edSMasatake YAMATO 	es_object_unref (proc);
3705d8f6b0edSMasatake YAMATO 	return e;
3706d8f6b0edSMasatake YAMATO }
3707d8f6b0edSMasatake YAMATO 
3708d8f6b0edSMasatake YAMATO static EsObject*
op_exit(OptVM * vm,EsObject * name)3709d8f6b0edSMasatake YAMATO op_exit (OptVM *vm, EsObject *name)
3710d8f6b0edSMasatake YAMATO {
3711d8f6b0edSMasatake YAMATO 	return OPT_ERR_INVALIDEXIT;
3712d8f6b0edSMasatake YAMATO }
3713d8f6b0edSMasatake YAMATO 
3714d8f6b0edSMasatake YAMATO static EsObject*
op_repeat(OptVM * vm,EsObject * name)3715d8f6b0edSMasatake YAMATO op_repeat (OptVM *vm, EsObject *name)
3716d8f6b0edSMasatake YAMATO {
3717d8f6b0edSMasatake YAMATO 	EsObject *proc = ptrArrayLast (vm->ostack);
3718d8f6b0edSMasatake YAMATO 	if (!((es_object_get_type (proc) == OPT_TYPE_ARRAY)
3719d8f6b0edSMasatake YAMATO 		  && (((ArrayFat *)es_fatptr_get (proc))->attr & ATTR_EXECUTABLE)))
3720d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3721d8f6b0edSMasatake YAMATO 
3722d8f6b0edSMasatake YAMATO 	EsObject *nobj = ptrArrayItemFromLast (vm->ostack, 1);
3723d8f6b0edSMasatake YAMATO 	if (!es_integer_p (nobj))
3724d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3725d8f6b0edSMasatake YAMATO 
3726d8f6b0edSMasatake YAMATO 	int n = es_integer_get (nobj);
3727d8f6b0edSMasatake YAMATO 	if (n < 0)
3728d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
3729d8f6b0edSMasatake YAMATO 
3730d8f6b0edSMasatake YAMATO 	es_object_ref (proc);
3731d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3732d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3733d8f6b0edSMasatake YAMATO 
3734d8f6b0edSMasatake YAMATO 	EsObject *e = es_false;;
3735d8f6b0edSMasatake YAMATO 	for (int i = 0; i < n; i++)
3736d8f6b0edSMasatake YAMATO 	{
3737d8f6b0edSMasatake YAMATO 		e = vm_call_proc (vm, proc);
3738d8f6b0edSMasatake YAMATO 		if (es_object_equal (e, OPT_ERR_INVALIDEXIT))
3739d8f6b0edSMasatake YAMATO 		{
3740bf0cb18dSMasatake YAMATO 			dict_op_def (vm->error, OPT_KEY_newerror, es_false);
3741d8f6b0edSMasatake YAMATO 			e = es_false;
3742d8f6b0edSMasatake YAMATO 			break;
3743d8f6b0edSMasatake YAMATO 		}
3744d8f6b0edSMasatake YAMATO 		else if (es_error_p (e))
3745d8f6b0edSMasatake YAMATO 			break;
3746d8f6b0edSMasatake YAMATO 	}
3747d8f6b0edSMasatake YAMATO 	es_object_unref (proc);
3748d8f6b0edSMasatake YAMATO 	return e;
3749d8f6b0edSMasatake YAMATO }
3750d8f6b0edSMasatake YAMATO 
3751d8f6b0edSMasatake YAMATO static EsObject*
op_stop(OptVM * vm,EsObject * name)3752d8f6b0edSMasatake YAMATO op_stop (OptVM *vm, EsObject *name)
3753d8f6b0edSMasatake YAMATO {
3754d8f6b0edSMasatake YAMATO 	return OPT_ERR_STOPPED;
3755d8f6b0edSMasatake YAMATO }
3756d8f6b0edSMasatake YAMATO 
3757d8f6b0edSMasatake YAMATO static EsObject*
op_stopped(OptVM * vm,EsObject * name)3758d8f6b0edSMasatake YAMATO op_stopped (OptVM *vm, EsObject *name)
3759d8f6b0edSMasatake YAMATO {
3760d8f6b0edSMasatake YAMATO 	EsObject *e = op_exec (vm, name);
3761d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, es_error_p (e)? es_true: es_false);
3762d8f6b0edSMasatake YAMATO 	return es_false;
3763d8f6b0edSMasatake YAMATO }
3764d8f6b0edSMasatake YAMATO 
3765d8f6b0edSMasatake YAMATO static EsObject*
op_for(OptVM * vm,EsObject * name)3766d8f6b0edSMasatake YAMATO op_for (OptVM *vm, EsObject *name)
3767d8f6b0edSMasatake YAMATO {
3768d8f6b0edSMasatake YAMATO 	EsObject *proc = ptrArrayLast (vm->ostack);
3769d8f6b0edSMasatake YAMATO 	if (!((es_object_get_type (proc) == OPT_TYPE_ARRAY)
3770d8f6b0edSMasatake YAMATO 		  && (((ArrayFat *)es_fatptr_get (proc))->attr & ATTR_EXECUTABLE)))
3771d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3772d8f6b0edSMasatake YAMATO 
3773d8f6b0edSMasatake YAMATO 	EsObject *limitobj = ptrArrayItemFromLast (vm->ostack, 1);
3774d8f6b0edSMasatake YAMATO 	if (! es_integer_p (limitobj))
3775d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3776d8f6b0edSMasatake YAMATO 	int limit = es_integer_get (limitobj);
3777d8f6b0edSMasatake YAMATO 
3778d8f6b0edSMasatake YAMATO 	EsObject *incrementobj = ptrArrayItemFromLast (vm->ostack, 2);
3779d8f6b0edSMasatake YAMATO 	if (! es_integer_p (incrementobj))
3780d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3781d8f6b0edSMasatake YAMATO 	int increment = es_integer_get (incrementobj);
3782d8f6b0edSMasatake YAMATO 
3783d8f6b0edSMasatake YAMATO 	EsObject *initialobj = ptrArrayItemFromLast (vm->ostack, 3);
3784d8f6b0edSMasatake YAMATO 	if (! es_integer_p (initialobj))
3785d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3786d8f6b0edSMasatake YAMATO 	int initial = es_integer_get (initialobj);
3787d8f6b0edSMasatake YAMATO 
3788d8f6b0edSMasatake YAMATO 	ptrArrayRemoveLast (vm->ostack);
3789d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 3);
3790d8f6b0edSMasatake YAMATO 
3791d8f6b0edSMasatake YAMATO 	EsObject *r = es_false;
3792d8f6b0edSMasatake YAMATO 	for (int i = initial;
3793d8f6b0edSMasatake YAMATO 		 (increment >= 0) ? (i <= limit) : (i >= limit);
3794d8f6b0edSMasatake YAMATO 		 i += increment)
3795d8f6b0edSMasatake YAMATO 	{
3796d8f6b0edSMasatake YAMATO 		EsObject *iobj = es_integer_new (i);
3797d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, iobj);
3798d8f6b0edSMasatake YAMATO 		r = vm_call_proc (vm, proc);
3799d8f6b0edSMasatake YAMATO 		es_object_unref (iobj);
3800d8f6b0edSMasatake YAMATO 
3801a4af4778SMasatake YAMATO 		if (es_object_equal (r, OPT_ERR_INVALIDEXIT))
3802a4af4778SMasatake YAMATO 		{
3803a4af4778SMasatake YAMATO 			dict_op_def (vm->error, OPT_KEY_newerror, es_false);
3804a4af4778SMasatake YAMATO 			r = es_false;
3805a4af4778SMasatake YAMATO 			break;
3806a4af4778SMasatake YAMATO 		}
3807d8f6b0edSMasatake YAMATO 		if (es_error_p (r))
3808d8f6b0edSMasatake YAMATO 			break;
3809d8f6b0edSMasatake YAMATO 	}
3810d8f6b0edSMasatake YAMATO 	es_object_unref (proc);
3811d8f6b0edSMasatake YAMATO 	return r;
3812d8f6b0edSMasatake YAMATO }
3813d8f6b0edSMasatake YAMATO 
3814d8f6b0edSMasatake YAMATO 
3815d8f6b0edSMasatake YAMATO /*
3816d8f6b0edSMasatake YAMATO  * Operators for type, attribute and their conversion
3817d8f6b0edSMasatake YAMATO  */
3818*6390fe9dSMasatake YAMATO static const char*
get_type_name(EsObject * o)3819*6390fe9dSMasatake YAMATO get_type_name (EsObject *o)
3820d8f6b0edSMasatake YAMATO {
3821d8f6b0edSMasatake YAMATO 	const char *n;
3822d8f6b0edSMasatake YAMATO 
3823d8f6b0edSMasatake YAMATO 	if (o == es_nil)
3824d8f6b0edSMasatake YAMATO 		n = "nulltype";
3825d8f6b0edSMasatake YAMATO 	else if (es_boolean_p (o))
3826d8f6b0edSMasatake YAMATO 		n = "booleantype";
3827d8f6b0edSMasatake YAMATO 	else if (es_integer_p (o))
3828d8f6b0edSMasatake YAMATO 		n = "integertype";
3829d8f6b0edSMasatake YAMATO 	else
3830d8f6b0edSMasatake YAMATO 	{
3831d8f6b0edSMasatake YAMATO 		int t = es_object_get_type (o);
3832d8f6b0edSMasatake YAMATO 		n = es_type_get_name (t);
3833d8f6b0edSMasatake YAMATO 	}
3834d8f6b0edSMasatake YAMATO 
3835*6390fe9dSMasatake YAMATO 	return n;
3836*6390fe9dSMasatake YAMATO }
3837*6390fe9dSMasatake YAMATO 
3838*6390fe9dSMasatake YAMATO static EsObject*
op_type(OptVM * vm,EsObject * name)3839*6390fe9dSMasatake YAMATO op_type (OptVM *vm, EsObject *name)
3840*6390fe9dSMasatake YAMATO {
3841*6390fe9dSMasatake YAMATO 	EsObject *o = ptrArrayRemoveLast (vm->ostack);
3842*6390fe9dSMasatake YAMATO 	const char *n;
3843*6390fe9dSMasatake YAMATO 
3844*6390fe9dSMasatake YAMATO 	n = get_type_name (o);
3845*6390fe9dSMasatake YAMATO 
3846d8f6b0edSMasatake YAMATO 	EsObject *p = name_newS (n, ATTR_EXECUTABLE|ATTR_READABLE);
3847d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, p);
3848d8f6b0edSMasatake YAMATO 	es_object_unref (p);
3849d8f6b0edSMasatake YAMATO 	es_object_unref (o);
3850d8f6b0edSMasatake YAMATO 	return es_false;
3851d8f6b0edSMasatake YAMATO }
3852d8f6b0edSMasatake YAMATO 
3853d8f6b0edSMasatake YAMATO static EsObject*
op_cvn(OptVM * vm,EsObject * name)3854d8f6b0edSMasatake YAMATO op_cvn (OptVM *vm, EsObject *name)
3855d8f6b0edSMasatake YAMATO {
3856d8f6b0edSMasatake YAMATO 	EsObject *o = ptrArrayLast (vm->ostack);
3857d8f6b0edSMasatake YAMATO 	if (es_object_get_type (o) != OPT_TYPE_STRING)
3858d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3859d8f6b0edSMasatake YAMATO 
3860d8f6b0edSMasatake YAMATO 	vString *vstr = es_pointer_get (o);
3861d8f6b0edSMasatake YAMATO 	const char *cstr = vStringValue (vstr);
3862d8f6b0edSMasatake YAMATO 	StringFat *sfat = es_fatptr_get (o);
3863d8f6b0edSMasatake YAMATO 	EsObject *n = name_newS (cstr, sfat->attr);
3864d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3865d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, n);
3866d8f6b0edSMasatake YAMATO 	es_object_unref (n);
3867d8f6b0edSMasatake YAMATO 	return es_false;
3868d8f6b0edSMasatake YAMATO }
3869d8f6b0edSMasatake YAMATO 
3870*6390fe9dSMasatake YAMATO static EsObject *
op_cvs(OptVM * vm,EsObject * name)3871*6390fe9dSMasatake YAMATO op_cvs (OptVM *vm, EsObject *name)
3872*6390fe9dSMasatake YAMATO {
3873*6390fe9dSMasatake YAMATO 	EsObject *o = ptrArrayLast (vm->ostack);
3874*6390fe9dSMasatake YAMATO 	if (es_object_get_type (o) != OPT_TYPE_STRING)
3875*6390fe9dSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3876*6390fe9dSMasatake YAMATO 
3877*6390fe9dSMasatake YAMATO 	EsObject *any = ptrArrayItemFromLast (vm->ostack, 1);
3878*6390fe9dSMasatake YAMATO 	vString *vstr = es_pointer_get (o);
3879*6390fe9dSMasatake YAMATO 	int t = es_object_get_type (any);
3880*6390fe9dSMasatake YAMATO 
3881*6390fe9dSMasatake YAMATO 	if (t == OPT_TYPE_STRING)
3882*6390fe9dSMasatake YAMATO 	{
3883*6390fe9dSMasatake YAMATO 		vString *vany = es_pointer_get (any);
3884*6390fe9dSMasatake YAMATO 		vStringCopy (vstr, vany);
3885*6390fe9dSMasatake YAMATO 	}
3886*6390fe9dSMasatake YAMATO 	else if (t == OPT_TYPE_NAME || t == ES_TYPE_SYMBOL)
3887*6390fe9dSMasatake YAMATO 	{
3888*6390fe9dSMasatake YAMATO 		if (t == OPT_TYPE_NAME)
3889*6390fe9dSMasatake YAMATO 			any = es_pointer_get (any);
3890*6390fe9dSMasatake YAMATO 
3891*6390fe9dSMasatake YAMATO 		const char *cany = es_symbol_get (any);
3892*6390fe9dSMasatake YAMATO 		vStringCopyS (vstr, cany);
3893*6390fe9dSMasatake YAMATO 	}
3894*6390fe9dSMasatake YAMATO 	else if (t == ES_TYPE_INTEGER)
3895*6390fe9dSMasatake YAMATO 	{
3896*6390fe9dSMasatake YAMATO 		int iany = es_integer_get (any);
3897*6390fe9dSMasatake YAMATO #define buf_len 13
3898*6390fe9dSMasatake YAMATO 		char buf[buf_len];
3899*6390fe9dSMasatake YAMATO 		if (!(snprintf (buf, buf_len, "%d", iany) > 0))
3900*6390fe9dSMasatake YAMATO 			buf [0] = '\0';
3901*6390fe9dSMasatake YAMATO 		vStringCopyS (vstr, buf);
3902*6390fe9dSMasatake YAMATO 	}
3903*6390fe9dSMasatake YAMATO 	else if (t == ES_TYPE_BOOLEAN)
3904*6390fe9dSMasatake YAMATO 		vStringCopyS (vstr, any == es_true? "true": "false");
3905*6390fe9dSMasatake YAMATO 	else
3906*6390fe9dSMasatake YAMATO 	{
3907*6390fe9dSMasatake YAMATO 		const char *type_name = get_type_name (any);
3908*6390fe9dSMasatake YAMATO 		vStringCopyS (vstr, "--");
3909*6390fe9dSMasatake YAMATO 		vStringCatS (vstr, type_name);
3910*6390fe9dSMasatake YAMATO 		vStringCatS (vstr, "--");
3911*6390fe9dSMasatake YAMATO 	}
3912*6390fe9dSMasatake YAMATO 
3913*6390fe9dSMasatake YAMATO 	es_object_ref (o);
3914*6390fe9dSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 2);
3915*6390fe9dSMasatake YAMATO 	vm_ostack_push (vm, o);
3916*6390fe9dSMasatake YAMATO 	es_object_unref (o);
3917*6390fe9dSMasatake YAMATO 
3918*6390fe9dSMasatake YAMATO 	return es_false;
3919*6390fe9dSMasatake YAMATO }
3920*6390fe9dSMasatake YAMATO 
3921d8f6b0edSMasatake YAMATO 
3922d8f6b0edSMasatake YAMATO /*
3923d8f6b0edSMasatake YAMATO  * Misc operators
3924d8f6b0edSMasatake YAMATO  */
3925d8f6b0edSMasatake YAMATO static EsObject*
op_null(OptVM * vm,EsObject * name)3926d8f6b0edSMasatake YAMATO op_null (OptVM *vm, EsObject *name)
3927d8f6b0edSMasatake YAMATO {
3928d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, es_nil);
3929d8f6b0edSMasatake YAMATO 	return es_false;
3930d8f6b0edSMasatake YAMATO }
3931d8f6b0edSMasatake YAMATO 
3932d8f6b0edSMasatake YAMATO static EsObject*
op_bind(OptVM * vm,EsObject * name)3933d8f6b0edSMasatake YAMATO op_bind (OptVM *vm, EsObject *name)
3934d8f6b0edSMasatake YAMATO {
3935d8f6b0edSMasatake YAMATO 	EsObject *proc = ptrArrayLast (vm->ostack);
3936d8f6b0edSMasatake YAMATO 	if (!((es_object_get_type (proc) == OPT_TYPE_ARRAY)
3937d8f6b0edSMasatake YAMATO 		  && (((ArrayFat *)es_fatptr_get (proc))->attr & ATTR_EXECUTABLE)))
3938d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3939d8f6b0edSMasatake YAMATO 
3940d8f6b0edSMasatake YAMATO 	vm_bind_proc (vm, es_pointer_get (proc));
3941d8f6b0edSMasatake YAMATO 	return es_false;
3942d8f6b0edSMasatake YAMATO }
3943d8f6b0edSMasatake YAMATO 
3944d8f6b0edSMasatake YAMATO 
3945d8f6b0edSMasatake YAMATO /*
3946d8f6b0edSMasatake YAMATO  * Methods for compound objects
3947d8f6b0edSMasatake YAMATO  */
3948d8f6b0edSMasatake YAMATO static EsObject*
op_length(OptVM * vm,EsObject * name)3949d8f6b0edSMasatake YAMATO op_length (OptVM *vm, EsObject *name)
3950d8f6b0edSMasatake YAMATO {
3951d8f6b0edSMasatake YAMATO 	EsObject *o = ptrArrayLast (vm->ostack);
3952d8f6b0edSMasatake YAMATO 	unsigned int c;
3953d8f6b0edSMasatake YAMATO 
3954d8f6b0edSMasatake YAMATO 	int t = es_object_get_type (o);
3955d8f6b0edSMasatake YAMATO 	if (t == OPT_TYPE_ARRAY)
3956d8f6b0edSMasatake YAMATO 	{
3957d8f6b0edSMasatake YAMATO 		ptrArray *a = es_pointer_get (o);
3958d8f6b0edSMasatake YAMATO 		c = ptrArrayCount (a);
3959d8f6b0edSMasatake YAMATO 	}
3960d8f6b0edSMasatake YAMATO 	else if (t == OPT_TYPE_DICT)
3961d8f6b0edSMasatake YAMATO 	{
3962d8f6b0edSMasatake YAMATO 		hashTable *h = es_pointer_get (o);
3963d8f6b0edSMasatake YAMATO 		c = hashTableCountItem (h);
3964d8f6b0edSMasatake YAMATO 	}
3965d8f6b0edSMasatake YAMATO 	else if (t == OPT_TYPE_STRING)
3966d8f6b0edSMasatake YAMATO 	{
3967d8f6b0edSMasatake YAMATO 		vString *s = es_pointer_get (o);
3968d8f6b0edSMasatake YAMATO 		c = (unsigned int)vStringLength (s);
3969d8f6b0edSMasatake YAMATO 	}
3970d8f6b0edSMasatake YAMATO 	else if (t == OPT_TYPE_NAME)
3971d8f6b0edSMasatake YAMATO 	{
3972d8f6b0edSMasatake YAMATO 		EsObject *sym = es_pointer_get (o);
3973d8f6b0edSMasatake YAMATO 		const char* cstr = es_symbol_get (sym);
3974d8f6b0edSMasatake YAMATO 		c = (unsigned int) strlen (cstr);
3975d8f6b0edSMasatake YAMATO 	}
3976d8f6b0edSMasatake YAMATO 	else
3977d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3978d8f6b0edSMasatake YAMATO 
3979d8f6b0edSMasatake YAMATO 	int n = c;
3980d8f6b0edSMasatake YAMATO 	if (n < 0)
3981d8f6b0edSMasatake YAMATO 		return OPT_ERR_INTERNALERROR; /* TODO: integer overflow */
3982d8f6b0edSMasatake YAMATO 
3983d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLast (vm->ostack);
3984d8f6b0edSMasatake YAMATO 	EsObject *nobj = es_integer_new (n);
3985d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, nobj);
3986d8f6b0edSMasatake YAMATO 	es_object_unref (nobj);
3987d8f6b0edSMasatake YAMATO 
3988d8f6b0edSMasatake YAMATO 	return es_false;
3989d8f6b0edSMasatake YAMATO }
3990d8f6b0edSMasatake YAMATO 
3991d8f6b0edSMasatake YAMATO static EsObject*
op__get_array(OptVM * vm,EsObject * name,EsObject * k,EsObject * obj)3992d8f6b0edSMasatake YAMATO op__get_array (OptVM *vm, EsObject *name,
3993d8f6b0edSMasatake YAMATO 			   EsObject *k, EsObject *obj)
3994d8f6b0edSMasatake YAMATO {
3995d8f6b0edSMasatake YAMATO 	if (!es_integer_p (k))
3996d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
3997d8f6b0edSMasatake YAMATO 	int n = es_integer_get (k);
3998d8f6b0edSMasatake YAMATO 	if (n < 0)
3999d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4000d8f6b0edSMasatake YAMATO 	EsObject *r = array_op_get (obj, (unsigned int)n);
4001d8f6b0edSMasatake YAMATO 	if (es_error_p (r))
4002d8f6b0edSMasatake YAMATO 		return r;
4003d8f6b0edSMasatake YAMATO 	es_object_ref (r);
4004d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 2);
4005d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, r);
4006d8f6b0edSMasatake YAMATO 	es_object_unref (r);
4007d8f6b0edSMasatake YAMATO 	return es_false;
4008d8f6b0edSMasatake YAMATO }
4009d8f6b0edSMasatake YAMATO 
4010d8f6b0edSMasatake YAMATO static EsObject*
op__get_dict(OptVM * vm,EsObject * name,EsObject * k,EsObject * obj)4011d8f6b0edSMasatake YAMATO op__get_dict (OptVM *vm, EsObject *name,
4012d8f6b0edSMasatake YAMATO 			  EsObject *k, EsObject *obj)
4013d8f6b0edSMasatake YAMATO {
4014d8f6b0edSMasatake YAMATO 	EsObject *v = NULL;
4015d8f6b0edSMasatake YAMATO 	if (!dict_op_known_and_get (obj, k, &v))
4016d8f6b0edSMasatake YAMATO 		return es_error_set_object (OPT_ERR_UNDEFINED, k);
4017d8f6b0edSMasatake YAMATO 	es_object_ref (v);
4018d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 2);
4019d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, v);
4020d8f6b0edSMasatake YAMATO 	es_object_unref (v);
4021d8f6b0edSMasatake YAMATO 	return es_false;
4022d8f6b0edSMasatake YAMATO }
4023d8f6b0edSMasatake YAMATO 
4024d8f6b0edSMasatake YAMATO static EsObject*
op__get_str(OptVM * vm,EsObject * name,EsObject * k,EsObject * obj)4025d8f6b0edSMasatake YAMATO op__get_str (OptVM *vm, EsObject *name,
4026d8f6b0edSMasatake YAMATO 			 EsObject *k, EsObject *obj)
4027d8f6b0edSMasatake YAMATO {
4028d8f6b0edSMasatake YAMATO 	if (!es_integer_p (k))
4029d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
4030d8f6b0edSMasatake YAMATO 	int n = es_integer_get (k);
4031d8f6b0edSMasatake YAMATO 	if (n < 0)
4032d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4033d8f6b0edSMasatake YAMATO 	vString *s = es_pointer_get (obj);
4034d8f6b0edSMasatake YAMATO 	unsigned int len = vStringLength (s);
4035d8f6b0edSMasatake YAMATO 	if ((unsigned int)n >= len)
4036d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4037d8f6b0edSMasatake YAMATO 	unsigned char chr = vStringChar (s, n);
4038d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 2);
4039d8f6b0edSMasatake YAMATO 	EsObject *chrobj = es_integer_new (chr);
4040d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, chrobj);
4041d8f6b0edSMasatake YAMATO 	es_object_unref (chrobj);
4042d8f6b0edSMasatake YAMATO 	return es_false;
4043d8f6b0edSMasatake YAMATO }
4044d8f6b0edSMasatake YAMATO 
4045d8f6b0edSMasatake YAMATO static EsObject*
op_get(OptVM * vm,EsObject * name)4046d8f6b0edSMasatake YAMATO op_get (OptVM *vm, EsObject *name)
4047d8f6b0edSMasatake YAMATO {
4048d8f6b0edSMasatake YAMATO 	EsObject *k = ptrArrayLast (vm->ostack);
4049d8f6b0edSMasatake YAMATO 	EsObject *obj = ptrArrayItemFromLast (vm->ostack, 1);
4050d8f6b0edSMasatake YAMATO 
4051d8f6b0edSMasatake YAMATO 	int t = es_object_get_type (obj);
4052d8f6b0edSMasatake YAMATO 	if (t == OPT_TYPE_ARRAY)
4053d8f6b0edSMasatake YAMATO 		return op__get_array (vm, name, k, obj);
4054d8f6b0edSMasatake YAMATO 	else if (t == OPT_TYPE_DICT)
4055d8f6b0edSMasatake YAMATO 		return op__get_dict (vm, name, k, obj);
4056d8f6b0edSMasatake YAMATO 	else if (t == OPT_TYPE_STRING)
4057d8f6b0edSMasatake YAMATO 		return op__get_str (vm, name, k, obj);
4058d8f6b0edSMasatake YAMATO 
4059d8f6b0edSMasatake YAMATO 	return OPT_ERR_TYPECHECK;
4060d8f6b0edSMasatake YAMATO }
4061d8f6b0edSMasatake YAMATO 
4062d8f6b0edSMasatake YAMATO static EsObject*
op__put_array(OptVM * vm,EsObject * name,EsObject * v,EsObject * k,EsObject * array)4063d8f6b0edSMasatake YAMATO op__put_array (OptVM *vm, EsObject *name,
4064d8f6b0edSMasatake YAMATO 			   EsObject *v, EsObject *k, EsObject *array)
4065d8f6b0edSMasatake YAMATO {
4066d8f6b0edSMasatake YAMATO 	if (!es_integer_p (k))
4067d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
4068d8f6b0edSMasatake YAMATO 	int index = es_integer_get (k);
4069d8f6b0edSMasatake YAMATO 	if (index < 0)
4070d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4071d8f6b0edSMasatake YAMATO 
4072d8f6b0edSMasatake YAMATO 	array_op_put (array, (unsigned int)index, v);
4073d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 3);
4074d8f6b0edSMasatake YAMATO 	return es_false;
4075d8f6b0edSMasatake YAMATO }
4076d8f6b0edSMasatake YAMATO 
4077d8f6b0edSMasatake YAMATO static EsObject*
op__put_dict(OptVM * vm,EsObject * name,EsObject * v,EsObject * k,EsObject * dict)4078d8f6b0edSMasatake YAMATO op__put_dict (OptVM *vm, EsObject *name,
4079d8f6b0edSMasatake YAMATO 			  EsObject *v, EsObject *k, EsObject *dict)
4080d8f6b0edSMasatake YAMATO {
408189d6b969SMasatake YAMATO 	EsObject *key = k;
408289d6b969SMasatake YAMATO 
408389d6b969SMasatake YAMATO 	if (es_null (key))
4084d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
4085d8f6b0edSMasatake YAMATO 
408689d6b969SMasatake YAMATO 	if (es_object_get_type (key) == OPT_TYPE_STRING)
408789d6b969SMasatake YAMATO 	{
408889d6b969SMasatake YAMATO 		const char *cstr = opt_string_get_cstr (key);
408989d6b969SMasatake YAMATO 		key = opt_name_new_from_cstr (cstr);
409089d6b969SMasatake YAMATO 	}
409189d6b969SMasatake YAMATO 
409289d6b969SMasatake YAMATO 	if (es_object_get_type (key) != OPT_TYPE_NAME
409389d6b969SMasatake YAMATO 		&& !es_integer_p (key) && !es_boolean_p (key))
409489d6b969SMasatake YAMATO 		return OPT_ERR_TYPECHECK;
409589d6b969SMasatake YAMATO 
409689d6b969SMasatake YAMATO 	dict_op_def (dict, key, v);
409789d6b969SMasatake YAMATO 	if (key != k)
409889d6b969SMasatake YAMATO 		es_object_unref (key);
4099d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 3);
4100d8f6b0edSMasatake YAMATO 	return es_false;
4101d8f6b0edSMasatake YAMATO }
4102d8f6b0edSMasatake YAMATO 
4103d8f6b0edSMasatake YAMATO static EsObject*
op__put_str(OptVM * vm,EsObject * name,EsObject * v,EsObject * k,EsObject * str)4104d8f6b0edSMasatake YAMATO op__put_str (OptVM *vm, EsObject *name,
4105d8f6b0edSMasatake YAMATO 			 EsObject *v, EsObject *k, EsObject *str)
4106d8f6b0edSMasatake YAMATO {
4107d8f6b0edSMasatake YAMATO 	if (!es_integer_p (v))
4108d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
4109d8f6b0edSMasatake YAMATO 	int c = es_integer_get (v);
4110d8f6b0edSMasatake YAMATO 	if (!(c >= 0 && c < 256))
4111d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4112d8f6b0edSMasatake YAMATO 	if (!es_integer_p (k))
4113d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
4114d8f6b0edSMasatake YAMATO 	int index = es_integer_get (k);
4115d8f6b0edSMasatake YAMATO 	if (index < 0)
4116d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4117d8f6b0edSMasatake YAMATO 
4118d8f6b0edSMasatake YAMATO 	vString *vstr = es_pointer_get (str);
4119d8f6b0edSMasatake YAMATO 	size_t len    = vStringLength (vstr);
4120d8f6b0edSMasatake YAMATO 	if (len > (size_t)index)
4121d8f6b0edSMasatake YAMATO 	{
4122d8f6b0edSMasatake YAMATO 		if (c == 0)
4123d8f6b0edSMasatake YAMATO 			vStringTruncate (vstr, (size_t)index);
4124d8f6b0edSMasatake YAMATO 		else
4125d8f6b0edSMasatake YAMATO 			vStringChar(vstr, index) = (char)c;
4126d8f6b0edSMasatake YAMATO 	}
4127d8f6b0edSMasatake YAMATO 	else
4128d8f6b0edSMasatake YAMATO 	{
4129d8f6b0edSMasatake YAMATO 		size_t d = index - len;
4130d8f6b0edSMasatake YAMATO 		for (size_t i = 0; i < d; i++)
4131d8f6b0edSMasatake YAMATO 			vStringPut (vstr, ' ');
4132d8f6b0edSMasatake YAMATO 		if (c != 0)
4133d8f6b0edSMasatake YAMATO 			vStringPut (vstr, (char)c);
4134d8f6b0edSMasatake YAMATO 	}
4135d8f6b0edSMasatake YAMATO 
4136d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 3);
4137d8f6b0edSMasatake YAMATO 	return es_false;
4138d8f6b0edSMasatake YAMATO }
4139d8f6b0edSMasatake YAMATO 
4140d8f6b0edSMasatake YAMATO static EsObject*
op_put(OptVM * vm,EsObject * name)4141d8f6b0edSMasatake YAMATO op_put (OptVM *vm, EsObject *name)
4142d8f6b0edSMasatake YAMATO {
4143d8f6b0edSMasatake YAMATO 	EsObject *v = ptrArrayLast (vm->ostack);
4144d8f6b0edSMasatake YAMATO 	EsObject *k = ptrArrayItemFromLast (vm->ostack, 1);
4145d8f6b0edSMasatake YAMATO 	EsObject *obj = ptrArrayItemFromLast (vm->ostack, 2);
4146d8f6b0edSMasatake YAMATO 
4147d8f6b0edSMasatake YAMATO 	int t = es_object_get_type (obj);
4148d8f6b0edSMasatake YAMATO 	if (t == OPT_TYPE_ARRAY)
4149d8f6b0edSMasatake YAMATO 		return op__put_array (vm, name, v, k, obj);
4150d8f6b0edSMasatake YAMATO 	else if (t == OPT_TYPE_DICT)
4151d8f6b0edSMasatake YAMATO 		return op__put_dict (vm, name, v, k, obj);
4152d8f6b0edSMasatake YAMATO 	else if (t == OPT_TYPE_STRING)
4153d8f6b0edSMasatake YAMATO 		return op__put_str (vm, name, v, k, obj);
4154d8f6b0edSMasatake YAMATO 
4155d8f6b0edSMasatake YAMATO 	return OPT_ERR_TYPECHECK;
4156d8f6b0edSMasatake YAMATO }
4157d8f6b0edSMasatake YAMATO 
4158d8f6b0edSMasatake YAMATO static EsObject*
op__forall_array(OptVM * vm,EsObject * name,EsObject * proc,EsObject * obj)4159d8f6b0edSMasatake YAMATO op__forall_array (OptVM *vm, EsObject *name,
4160d8f6b0edSMasatake YAMATO 				  EsObject *proc, EsObject *obj)
4161d8f6b0edSMasatake YAMATO {
4162d8f6b0edSMasatake YAMATO 	ptrArray *a = es_pointer_get (obj);
4163d8f6b0edSMasatake YAMATO 	unsigned int c = ptrArrayCount (a);
4164d8f6b0edSMasatake YAMATO 	if (((int)c) < 0)
4165d8f6b0edSMasatake YAMATO 		return OPT_ERR_INTERNALERROR; /* TODO: integer overflow */
4166d8f6b0edSMasatake YAMATO 
4167d8f6b0edSMasatake YAMATO 	EsObject *e = es_false;
4168d8f6b0edSMasatake YAMATO 	for (int i = 0; i < c; i++)
4169d8f6b0edSMasatake YAMATO 	{
4170d8f6b0edSMasatake YAMATO 		EsObject *o = ptrArrayItem (a, i);
4171d8f6b0edSMasatake YAMATO 		es_object_ref (o);
4172d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, o);
4173d8f6b0edSMasatake YAMATO 		e = vm_call_proc (vm, proc);
4174d8f6b0edSMasatake YAMATO 		es_object_unref (o);
4175d8f6b0edSMasatake YAMATO 		if (es_error_p (e))
4176d8f6b0edSMasatake YAMATO 			break;
4177d8f6b0edSMasatake YAMATO 	}
4178d8f6b0edSMasatake YAMATO 
4179d8f6b0edSMasatake YAMATO 	return e;
4180d8f6b0edSMasatake YAMATO }
4181d8f6b0edSMasatake YAMATO 
4182d8f6b0edSMasatake YAMATO struct dictForallData {
4183d8f6b0edSMasatake YAMATO 	OptVM *vm;
4184d8f6b0edSMasatake YAMATO 	EsObject *proc;
4185d8f6b0edSMasatake YAMATO 	EsObject *err;
4186d8f6b0edSMasatake YAMATO };
4187d8f6b0edSMasatake YAMATO 
4188d8f6b0edSMasatake YAMATO static bool
dict_forall_cb(const void * key,void * value,void * user_data)4189d8f6b0edSMasatake YAMATO dict_forall_cb (const void *key, void *value, void *user_data)
4190d8f6b0edSMasatake YAMATO {
4191d8f6b0edSMasatake YAMATO 	bool r = true;
4192d8f6b0edSMasatake YAMATO 	EsObject *k = (EsObject *)key;
4193d8f6b0edSMasatake YAMATO 	EsObject *v = value;
4194d8f6b0edSMasatake YAMATO 	struct dictForallData *d = user_data;
4195d8f6b0edSMasatake YAMATO 
4196d8f6b0edSMasatake YAMATO 	/* TODO */
4197d8f6b0edSMasatake YAMATO 	if (es_symbol_p (k))
4198d8f6b0edSMasatake YAMATO 		k = name_new (k, ATTR_READABLE);
4199d8f6b0edSMasatake YAMATO 	else
4200d8f6b0edSMasatake YAMATO 		es_object_ref ((EsObject *)k);
4201d8f6b0edSMasatake YAMATO 	es_object_ref (v);
4202d8f6b0edSMasatake YAMATO 
4203d8f6b0edSMasatake YAMATO 	vm_ostack_push (d->vm, (EsObject *)k);
4204d8f6b0edSMasatake YAMATO 	vm_ostack_push (d->vm, v);
4205d8f6b0edSMasatake YAMATO 	EsObject *e = vm_call_proc (d->vm, d->proc);
4206d8f6b0edSMasatake YAMATO 	if (es_error_p (e))
4207d8f6b0edSMasatake YAMATO 	{
4208d8f6b0edSMasatake YAMATO 		d->err = e;
4209d8f6b0edSMasatake YAMATO 		r = false;
4210d8f6b0edSMasatake YAMATO 	}
4211d8f6b0edSMasatake YAMATO 	es_object_unref ((EsObject *)k);
4212d8f6b0edSMasatake YAMATO 	es_object_unref (v);
4213d8f6b0edSMasatake YAMATO 
4214d8f6b0edSMasatake YAMATO 	return r;
4215d8f6b0edSMasatake YAMATO }
4216d8f6b0edSMasatake YAMATO 
4217d8f6b0edSMasatake YAMATO static EsObject*
op__forall_dict(OptVM * vm,EsObject * name,EsObject * proc,EsObject * obj)4218d8f6b0edSMasatake YAMATO op__forall_dict (OptVM *vm, EsObject *name,
4219d8f6b0edSMasatake YAMATO 				 EsObject *proc, EsObject *obj)
4220d8f6b0edSMasatake YAMATO {
4221d8f6b0edSMasatake YAMATO 	EsObject *r = es_false;;
4222d8f6b0edSMasatake YAMATO 	hashTable *ht = es_pointer_get (obj);
4223d8f6b0edSMasatake YAMATO 	struct dictForallData data = {
4224d8f6b0edSMasatake YAMATO 		.vm   = vm,
4225d8f6b0edSMasatake YAMATO 		.proc = proc
4226d8f6b0edSMasatake YAMATO 	};
4227d8f6b0edSMasatake YAMATO 
4228d8f6b0edSMasatake YAMATO 	if (!hashTableForeachItem (ht, dict_forall_cb, &data))
4229d8f6b0edSMasatake YAMATO 		r = data.err;
4230d8f6b0edSMasatake YAMATO 
4231d8f6b0edSMasatake YAMATO 	return r;
4232d8f6b0edSMasatake YAMATO }
4233d8f6b0edSMasatake YAMATO 
4234d8f6b0edSMasatake YAMATO static EsObject*
op__forall_string(OptVM * vm,EsObject * name,EsObject * proc,EsObject * obj)4235d8f6b0edSMasatake YAMATO op__forall_string (OptVM *vm, EsObject *name,
4236d8f6b0edSMasatake YAMATO 				   EsObject *proc, EsObject *obj)
4237d8f6b0edSMasatake YAMATO {
4238d8f6b0edSMasatake YAMATO 	vString *s = es_pointer_get (obj);
4239d8f6b0edSMasatake YAMATO 	unsigned int c = vStringLength (s);
4240d8f6b0edSMasatake YAMATO 	if (((int)c) < 0)
4241d8f6b0edSMasatake YAMATO 		return OPT_ERR_INTERNALERROR; /* TODO: integer overflow */
4242d8f6b0edSMasatake YAMATO 
4243d8f6b0edSMasatake YAMATO 	EsObject *e = es_false;
4244d8f6b0edSMasatake YAMATO 	for (int i = 0; i < c; i++)
4245d8f6b0edSMasatake YAMATO 	{
4246d8f6b0edSMasatake YAMATO 		unsigned char chr = vStringChar (s, i);
4247d8f6b0edSMasatake YAMATO 		EsObject *o = es_integer_new (chr);
4248d8f6b0edSMasatake YAMATO 		vm_ostack_push (vm, o);
4249d8f6b0edSMasatake YAMATO 		es_object_unref (o);
4250d8f6b0edSMasatake YAMATO 		e = vm_call_proc (vm, proc);
4251d8f6b0edSMasatake YAMATO 		if (es_error_p (e))
4252d8f6b0edSMasatake YAMATO 			break;
4253d8f6b0edSMasatake YAMATO 	}
4254d8f6b0edSMasatake YAMATO 
4255d8f6b0edSMasatake YAMATO 	return e;
4256d8f6b0edSMasatake YAMATO }
4257d8f6b0edSMasatake YAMATO 
4258d8f6b0edSMasatake YAMATO static EsObject*
op_forall(OptVM * vm,EsObject * name)4259d8f6b0edSMasatake YAMATO op_forall (OptVM *vm, EsObject *name)
4260d8f6b0edSMasatake YAMATO {
4261d8f6b0edSMasatake YAMATO 	EsObject *proc = ptrArrayLast (vm->ostack);
4262d8f6b0edSMasatake YAMATO 	if (!(es_object_get_type (proc) == OPT_TYPE_ARRAY
4263d8f6b0edSMasatake YAMATO 		  && (((ArrayFat *)es_fatptr_get (proc))->attr & ATTR_EXECUTABLE)))
4264d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
4265d8f6b0edSMasatake YAMATO 
4266d8f6b0edSMasatake YAMATO 	EsObject *obj = ptrArrayItemFromLast (vm->ostack, 1);
4267d8f6b0edSMasatake YAMATO 
4268d8f6b0edSMasatake YAMATO 	int t = es_object_get_type (obj);
42696998fc11SMasatake YAMATO 	EsObject * (* proc_driver) (OptVM *, EsObject *,
42706998fc11SMasatake YAMATO 								EsObject *, EsObject *) = NULL;
4271d8f6b0edSMasatake YAMATO 	if (t == OPT_TYPE_ARRAY)
42726998fc11SMasatake YAMATO 		proc_driver = op__forall_array;
4273d8f6b0edSMasatake YAMATO 	else if (t == OPT_TYPE_DICT)
42746998fc11SMasatake YAMATO 		proc_driver = op__forall_dict;
4275d8f6b0edSMasatake YAMATO 	else if (t == OPT_TYPE_STRING)
42766998fc11SMasatake YAMATO 		proc_driver = op__forall_string;
42776998fc11SMasatake YAMATO 	else
4278d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
42796998fc11SMasatake YAMATO 
42806998fc11SMasatake YAMATO 	ptrArrayRemoveLast (vm->ostack);
42816998fc11SMasatake YAMATO 	ptrArrayRemoveLast (vm->ostack);
42826998fc11SMasatake YAMATO 	EsObject *e = (*proc_driver) (vm, name, proc, obj);
42836998fc11SMasatake YAMATO 	es_object_unref (proc);
42846998fc11SMasatake YAMATO 	es_object_unref (obj);
42856998fc11SMasatake YAMATO 
4286a4af4778SMasatake YAMATO 	if (es_object_equal (e, OPT_ERR_INVALIDEXIT))
4287a4af4778SMasatake YAMATO 	{
4288a4af4778SMasatake YAMATO 		dict_op_def (vm->error, OPT_KEY_newerror, es_false);
4289a4af4778SMasatake YAMATO 		e = es_false;
4290a4af4778SMasatake YAMATO 	}
42916998fc11SMasatake YAMATO 	return e;
4292d8f6b0edSMasatake YAMATO }
4293d8f6b0edSMasatake YAMATO 
4294d8f6b0edSMasatake YAMATO static EsObject*
op__putinterval_array(OptVM * vm,EsObject * name,ptrArray * srca,int index,ptrArray * dsta)4295d8f6b0edSMasatake YAMATO op__putinterval_array (OptVM *vm, EsObject *name,
4296d8f6b0edSMasatake YAMATO 					   ptrArray *srca, int index, ptrArray *dsta)
4297d8f6b0edSMasatake YAMATO {
4298d8f6b0edSMasatake YAMATO 	unsigned int dlen = ptrArrayCount (dsta);
4299d8f6b0edSMasatake YAMATO 	unsigned int slen = ptrArrayCount (srca);
4300d8f6b0edSMasatake YAMATO 	if (dlen > index)
4301d8f6b0edSMasatake YAMATO 	{
4302d8f6b0edSMasatake YAMATO 		if ((dlen - index) <= slen)
4303d8f6b0edSMasatake YAMATO 		{
4304d8f6b0edSMasatake YAMATO 			ptrArrayDeleteLastInBatch (dsta, dlen - index);
4305d8f6b0edSMasatake YAMATO 			for (unsigned int i = 0; i < slen; i++)
4306d8f6b0edSMasatake YAMATO 				ptrArrayAdd (dsta, es_object_ref (ptrArrayItem (srca, i)));
4307d8f6b0edSMasatake YAMATO 			return es_false;
4308d8f6b0edSMasatake YAMATO 		}
4309d8f6b0edSMasatake YAMATO 		else
4310d8f6b0edSMasatake YAMATO 		{
4311d8f6b0edSMasatake YAMATO 			for (size_t i = 0; i < slen; i++)
4312d8f6b0edSMasatake YAMATO 				ptrArrayUpdate (dsta, ((size_t)index) + i,
4313d8f6b0edSMasatake YAMATO 								es_object_ref (ptrArrayItem (srca, i)),
4314d8f6b0edSMasatake YAMATO 								es_nil);
4315d8f6b0edSMasatake YAMATO 			return es_false;
4316d8f6b0edSMasatake YAMATO 		}
4317d8f6b0edSMasatake YAMATO 	}
4318d8f6b0edSMasatake YAMATO 	else if (dlen == index)
4319d8f6b0edSMasatake YAMATO 	{
4320d8f6b0edSMasatake YAMATO 		for (unsigned int i = 0; i < slen; i++)
4321d8f6b0edSMasatake YAMATO 			ptrArrayAdd (dsta, es_object_ref (ptrArrayItem (srca, i)));
4322d8f6b0edSMasatake YAMATO 		return es_false;
4323d8f6b0edSMasatake YAMATO 	}
4324d8f6b0edSMasatake YAMATO 	else
4325d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4326d8f6b0edSMasatake YAMATO }
4327d8f6b0edSMasatake YAMATO 
4328d8f6b0edSMasatake YAMATO static EsObject*
op__putinterval_string(OptVM * vm,EsObject * name,vString * srcv,int index,vString * dstv)4329d8f6b0edSMasatake YAMATO op__putinterval_string (OptVM *vm, EsObject *name,
4330d8f6b0edSMasatake YAMATO 						vString *srcv, int index, vString *dstv)
4331d8f6b0edSMasatake YAMATO {
4332d8f6b0edSMasatake YAMATO 	size_t dlen = vStringLength (dstv);
4333d8f6b0edSMasatake YAMATO 	if (dlen > index)
4334d8f6b0edSMasatake YAMATO 	{
4335d8f6b0edSMasatake YAMATO 		size_t slen = vStringLength (srcv);
4336d8f6b0edSMasatake YAMATO 		if ((dlen - index) <= slen)
4337d8f6b0edSMasatake YAMATO 		{
4338d8f6b0edSMasatake YAMATO 			vStringTruncate (dstv, (size_t)index);
4339d8f6b0edSMasatake YAMATO 			vStringCat (dstv, srcv);
4340d8f6b0edSMasatake YAMATO 			return es_false;
4341d8f6b0edSMasatake YAMATO 		}
4342d8f6b0edSMasatake YAMATO 		else
4343d8f6b0edSMasatake YAMATO 		{
4344d8f6b0edSMasatake YAMATO 			for (size_t i = 0; i < slen; i++)
4345d8f6b0edSMasatake YAMATO 				vStringChar (dstv, index + i) = vStringChar (srcv, i);
4346d8f6b0edSMasatake YAMATO 			return es_false;
4347d8f6b0edSMasatake YAMATO 		}
4348d8f6b0edSMasatake YAMATO 	}
4349d8f6b0edSMasatake YAMATO 	else if (dlen == index)
4350d8f6b0edSMasatake YAMATO 	{
4351d8f6b0edSMasatake YAMATO 		vStringCat (dstv, srcv);
4352d8f6b0edSMasatake YAMATO 		return es_false;
4353d8f6b0edSMasatake YAMATO 	}
4354d8f6b0edSMasatake YAMATO 	else
4355d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4356d8f6b0edSMasatake YAMATO }
4357d8f6b0edSMasatake YAMATO 
4358d8f6b0edSMasatake YAMATO static EsObject*
op_putinterval(OptVM * vm,EsObject * name)4359d8f6b0edSMasatake YAMATO op_putinterval (OptVM *vm, EsObject *name)
4360d8f6b0edSMasatake YAMATO {
4361d8f6b0edSMasatake YAMATO 	EsObject *src = ptrArrayLast (vm->ostack);
4362d8f6b0edSMasatake YAMATO 	EsObject *indexobj = ptrArrayItemFromLast (vm->ostack, 1);
4363d8f6b0edSMasatake YAMATO 	EsObject *dst = ptrArrayItemFromLast (vm->ostack, 2);
4364d8f6b0edSMasatake YAMATO 
4365d8f6b0edSMasatake YAMATO 	int t = es_object_get_type (src);
4366d8f6b0edSMasatake YAMATO 	if (t == OPT_TYPE_ARRAY || t == OPT_TYPE_STRING)
4367d8f6b0edSMasatake YAMATO 	{
4368d8f6b0edSMasatake YAMATO 		if (!es_integer_p (indexobj))
4369d8f6b0edSMasatake YAMATO 			return OPT_ERR_TYPECHECK;
4370d8f6b0edSMasatake YAMATO 		if (es_object_get_type (dst) != t)
4371d8f6b0edSMasatake YAMATO 			return OPT_ERR_TYPECHECK;
4372d8f6b0edSMasatake YAMATO 	}
4373d8f6b0edSMasatake YAMATO 	else
4374d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
4375d8f6b0edSMasatake YAMATO 
4376d8f6b0edSMasatake YAMATO 	int index = es_integer_get (indexobj);
4377d8f6b0edSMasatake YAMATO 	if (index < 0)
4378d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4379d8f6b0edSMasatake YAMATO 
4380d8f6b0edSMasatake YAMATO 	EsObject *r;
4381d8f6b0edSMasatake YAMATO 	if (t == OPT_TYPE_ARRAY)
4382d8f6b0edSMasatake YAMATO 		r = op__putinterval_array (vm, name,
4383d8f6b0edSMasatake YAMATO 								   es_pointer_get (src),
4384d8f6b0edSMasatake YAMATO 								   index,
4385d8f6b0edSMasatake YAMATO 								   es_pointer_get (dst));
4386d8f6b0edSMasatake YAMATO 	else
4387d8f6b0edSMasatake YAMATO 		r = op__putinterval_string (vm, name,
4388d8f6b0edSMasatake YAMATO 									es_pointer_get (src),
4389d8f6b0edSMasatake YAMATO 									index,
4390d8f6b0edSMasatake YAMATO 									es_pointer_get (dst));
4391d8f6b0edSMasatake YAMATO 
4392d8f6b0edSMasatake YAMATO 	if (!es_error_p (r))
4393d8f6b0edSMasatake YAMATO 		ptrArrayDeleteLastInBatch (vm->ostack, 3);
4394d8f6b0edSMasatake YAMATO 
4395d8f6b0edSMasatake YAMATO 	return r;
4396d8f6b0edSMasatake YAMATO }
4397d8f6b0edSMasatake YAMATO 
4398d8f6b0edSMasatake YAMATO static EsObject*
op__copyinterval_array(OptVM * vm,EsObject * name,ptrArray * dsta,int count,int index,ptrArray * srca)4399d8f6b0edSMasatake YAMATO op__copyinterval_array (OptVM *vm, EsObject *name,
4400d8f6b0edSMasatake YAMATO 						ptrArray *dsta,
4401d8f6b0edSMasatake YAMATO 						int count,
4402d8f6b0edSMasatake YAMATO 						int index,
4403d8f6b0edSMasatake YAMATO 						ptrArray *srca)
4404d8f6b0edSMasatake YAMATO {
4405d8f6b0edSMasatake YAMATO 	unsigned long srcl = ptrArrayCount (srca);
4406d8f6b0edSMasatake YAMATO 
4407d8f6b0edSMasatake YAMATO 	if ((unsigned long)index > srcl)
4408d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4409d8f6b0edSMasatake YAMATO 
4410d8f6b0edSMasatake YAMATO 	if ((unsigned long)(index + count) > srcl)
4411d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4412d8f6b0edSMasatake YAMATO 
4413d8f6b0edSMasatake YAMATO 	for (unsigned int i = (unsigned int)index; i < index + count; i++)
4414d8f6b0edSMasatake YAMATO 		ptrArrayAdd (dsta, es_object_ref (ptrArrayItem (srca, i)));
4415d8f6b0edSMasatake YAMATO 	return es_false;
4416d8f6b0edSMasatake YAMATO }
4417d8f6b0edSMasatake YAMATO 
4418d8f6b0edSMasatake YAMATO static EsObject*
op__copyinterval_string(OptVM * vm,EsObject * name,vString * dsts,int count,int index,vString * srcs)4419d8f6b0edSMasatake YAMATO op__copyinterval_string (OptVM *vm, EsObject *name,
4420d8f6b0edSMasatake YAMATO 						 vString *dsts,
4421d8f6b0edSMasatake YAMATO 						 int count,
4422d8f6b0edSMasatake YAMATO 						 int index,
4423d8f6b0edSMasatake YAMATO 						 vString *srcs)
4424d8f6b0edSMasatake YAMATO {
4425d8f6b0edSMasatake YAMATO 	size_t srcl = vStringLength (srcs);
4426d8f6b0edSMasatake YAMATO 
4427d8f6b0edSMasatake YAMATO 	if ((size_t)index > srcl)
4428d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4429d8f6b0edSMasatake YAMATO 
4430d8f6b0edSMasatake YAMATO 	if ((size_t)(index + count) > srcl)
4431d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4432d8f6b0edSMasatake YAMATO 
4433d8f6b0edSMasatake YAMATO 	vStringNCatSUnsafe (dsts, vStringValue (srcs) + index, (size_t)count);
4434d8f6b0edSMasatake YAMATO 	return es_false;
4435d8f6b0edSMasatake YAMATO }
4436d8f6b0edSMasatake YAMATO 
4437d8f6b0edSMasatake YAMATO static EsObject*
op__copyinterval(OptVM * vm,EsObject * name)4438d8f6b0edSMasatake YAMATO op__copyinterval (OptVM *vm, EsObject *name)
4439d8f6b0edSMasatake YAMATO {
4440d8f6b0edSMasatake YAMATO 	EsObject *dstobj = ptrArrayLast (vm->ostack);
4441d8f6b0edSMasatake YAMATO 	EsObject *countobj = ptrArrayItemFromLast (vm->ostack, 1);
4442d8f6b0edSMasatake YAMATO 	EsObject *indexobj = ptrArrayItemFromLast (vm->ostack, 2);
4443d8f6b0edSMasatake YAMATO 	EsObject *srcobj = ptrArrayItemFromLast (vm->ostack, 3);
4444d8f6b0edSMasatake YAMATO 
4445d8f6b0edSMasatake YAMATO 	int t = es_object_get_type (dstobj);
4446d8f6b0edSMasatake YAMATO 	if (! (t == OPT_TYPE_ARRAY || t == OPT_TYPE_STRING))
4447d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
4448d8f6b0edSMasatake YAMATO 	if (t != es_object_get_type (srcobj))
4449d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
4450d8f6b0edSMasatake YAMATO 
4451d8f6b0edSMasatake YAMATO 	if (!es_integer_p (countobj))
4452d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
4453d8f6b0edSMasatake YAMATO 	if (!es_integer_p (indexobj))
4454d8f6b0edSMasatake YAMATO 		return OPT_ERR_TYPECHECK;
4455d8f6b0edSMasatake YAMATO 
4456d8f6b0edSMasatake YAMATO 	int count = es_integer_get (countobj);
4457d8f6b0edSMasatake YAMATO 	if (count < 0)
4458d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4459d8f6b0edSMasatake YAMATO 
4460d8f6b0edSMasatake YAMATO 	int index = es_integer_get (indexobj);
4461d8f6b0edSMasatake YAMATO 	if (index < 0)
4462d8f6b0edSMasatake YAMATO 		return OPT_ERR_RANGECHECK;
4463d8f6b0edSMasatake YAMATO 
4464d8f6b0edSMasatake YAMATO 	EsObject* r;
4465d8f6b0edSMasatake YAMATO 	if (t == OPT_TYPE_ARRAY)
4466d8f6b0edSMasatake YAMATO 		r = op__copyinterval_array (vm, name,
4467d8f6b0edSMasatake YAMATO 									es_pointer_get (dstobj),
4468d8f6b0edSMasatake YAMATO 									count,
4469d8f6b0edSMasatake YAMATO 									index,
4470d8f6b0edSMasatake YAMATO 									es_pointer_get (srcobj));
4471d8f6b0edSMasatake YAMATO 	else
4472d8f6b0edSMasatake YAMATO 		r = op__copyinterval_string (vm, name,
4473d8f6b0edSMasatake YAMATO 									 es_pointer_get (dstobj),
4474d8f6b0edSMasatake YAMATO 									 count,
4475d8f6b0edSMasatake YAMATO 									 index,
4476d8f6b0edSMasatake YAMATO 									 es_pointer_get (srcobj));
4477d8f6b0edSMasatake YAMATO 
4478d8f6b0edSMasatake YAMATO 	if (es_error_p (r))
4479d8f6b0edSMasatake YAMATO 		return r;
4480d8f6b0edSMasatake YAMATO 
4481d8f6b0edSMasatake YAMATO 	es_object_ref (dstobj);
4482d8f6b0edSMasatake YAMATO 	ptrArrayDeleteLastInBatch (vm->ostack, 4);
4483d8f6b0edSMasatake YAMATO 	vm_ostack_push (vm, dstobj);
4484d8f6b0edSMasatake YAMATO 	es_object_unref (dstobj);
4485d8f6b0edSMasatake YAMATO 	return r;
4486d8f6b0edSMasatake YAMATO }
4487