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