GCCPY:
[official-gcc.git] / libgpython / runtime / gpy-module-stack.c
blob3af8ae09570112bb6d88a73509ab852ec90213c9
1 /* This file is part of GCC.
3 GCC is free software; you can redistribute it and/or modify it under
4 the terms of the GNU General Public License as published by the Free
5 Software Foundation; either version 3, or (at your option) any later
6 version.
8 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
9 WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 for more details.
13 You should have received a copy of the GNU General Public License
14 along with GCC; see the file COPYING3. If not see
15 <http://www.gnu.org/licenses/>. */
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdbool.h>
25 #include <stdarg.h>
27 #include <gpython/gpython.h>
28 #include <gpython/vectors.h>
29 #include <gpython/objects.h>
30 #include <gpython/runtime.h>
32 // Holds all runtime information to primitive types
33 gpy_vector_t * __GPY_GLOBL_PRIMITIVES;
35 // runtime stack for all module runtime data
38 NOTE on thread-saftey for future, this stack will need
39 Global Lock, and a per thread __CALL_STACK & __RET_ADDR
43 __STACK
44 -> _LENGTH
45 -> --------
46 -> * maybe __CALL_STACK //TODO
47 -> * maybe __RET_ADDR //TODO
48 -> --------
49 -> MODULE_A
50 -> MODULE_B
51 ...
53 #define __GPY_INIT_LEN 3
54 static int __GPY_GLOBL_modOffs = 0;
55 static int __GPY_GLOBAL_STACK_LEN = 0;
56 static gpy_hash_tab_t stack_table;
58 static bool __GPY_GLOBAL_RETURN;
59 gpy_object_t ** __GPY_MODULE_RR_STACK;
60 gpy_object_t ** __GPY_RR_STACK_PTR;
62 #define GPY_MODULE_STACK_RET_ADDR \
63 (__GPY_MODULE_RR_STACK + 1)
64 #define GPY_MODULE_STACK_RET_VAL \
65 *(__GPY_MODULE_RR_STACK + 1)
67 static
68 void gpy_rr_init_primitives (void)
70 gpy_obj_func_mod_init (__GPY_GLOBL_PRIMITIVES);
71 gpy_obj_integer_mod_init (__GPY_GLOBL_PRIMITIVES);
72 gpy_obj_staticmethod_mod_init (__GPY_GLOBL_PRIMITIVES);
73 gpy_obj_class_mod_init (__GPY_GLOBL_PRIMITIVES);
74 gpy_obj_classmethod_mod_init (__GPY_GLOBL_PRIMITIVES);
75 gpy_obj_list_mod_init (__GPY_GLOBL_PRIMITIVES);
76 gpy_obj_module_mod_init (__GPY_GLOBL_PRIMITIVES);
77 gpy_obj_string_mod_init (__GPY_GLOBL_PRIMITIVES);
80 static
81 void gpy_rr_init_runtime_stack (void)
83 __GPY_GLOBAL_RETURN = false;
84 gpy_dd_hash_init_table (&stack_table);
86 __GPY_GLOBL_PRIMITIVES = gpy_malloc (sizeof (gpy_vector_t));
87 gpy_vec_init (__GPY_GLOBL_PRIMITIVES);
88 gpy_rr_init_primitives ();
90 __GPY_MODULE_RR_STACK = (gpy_object_t **) gpy_calloc
91 (__GPY_INIT_LEN, sizeof (gpy_object_t *));
93 *__GPY_MODULE_RR_STACK = gpy_rr_fold_integer (__GPY_INIT_LEN);
94 __GPY_RR_STACK_PTR = (__GPY_MODULE_RR_STACK + __GPY_INIT_LEN);
96 __GPY_GLOBAL_STACK_LEN += __GPY_INIT_LEN;
99 /* remember to update the stack pointer's and the stack size */
100 void gpy_rr_extend_runtime_stack (int nslots)
102 // calculate the size of reallocation
103 size_t size = sizeof (gpy_object_t *) * (__GPY_INIT_LEN + nslots);
104 __GPY_MODULE_RR_STACK = gpy_realloc (__GPY_MODULE_RR_STACK, size);
105 __GPY_GLOBAL_STACK_LEN += nslots;
107 // update the stack pointer to the begining of all modules
108 __GPY_RR_STACK_PTR = __GPY_MODULE_RR_STACK;
109 __GPY_RR_STACK_PTR += __GPY_GLOBAL_STACK_LEN + (nslots - 1);
112 /* More of a helper function than trying to do this directly in GENERIC */
113 char ** gpy_rr_modAttribList (int n, ...)
115 char ** retval = NULL;
116 if (n > 0)
118 retval = (char **)
119 gpy_calloc (n + 1, sizeof (char *));
121 va_list ap;
122 va_start (ap, n);
124 int i;
125 for (i = 0; i < n; ++i)
127 char * y = va_arg (ap, char *);
128 retval[i] = strdup (y);
131 retval[i] = NULL;
132 va_end (ap);
134 return retval;
138 * @slots is the length to which the stack needs extended
139 * @stack_id is the id of the module which is being loaded
140 * @elems is the _ordered_ list of attributes of the class
142 int gpy_rr_extendRRStack (int slots,
143 const char * stack_id,
144 char ** elems)
146 int retOffs = -1;
147 /* Make sure it doesn't already exist! */
148 gpy_hashval_t h = gpy_dd_hash_string (stack_id);
149 gpy_hash_entry_t * e = gpy_dd_hash_lookup_table (&stack_table, h);
151 if (e == NULL || e->data == NULL)
153 /* extend the stack and setup the stack pointer for the callee' */
154 gpy_rr_extend_runtime_stack (slots);
156 gpy_moduleInfo_t * info = (gpy_moduleInfo_t *)
157 gpy_malloc (sizeof (gpy_moduleInfo_t));
158 info->offset = __GPY_GLOBL_modOffs;
159 info->length = slots;
160 info->modID = strdup (stack_id);
161 info->idents = elems;
163 gpy_assert (!gpy_dd_hash_insert (h, (void *) info, &stack_table));
164 retOffs = info->offset;
166 // update the offset for next module load...
167 __GPY_GLOBL_modOffs += slots;
169 else
170 fatal ("Stack id <%s> already exists!\n", stack_id);
172 return retOffs;
175 void gpy_rr_init_runtime (void)
177 gpy_rr_init_runtime_stack ();
180 void gpy_rr_cleanup_final (void)
183 Cleanup the runtime stack and all other object data
184 .....
186 return;
189 gpy_object_attrib_t * gpy_rr_fold_attribute (const unsigned char * identifier,
190 unsigned char * code_addr,
191 unsigned int offset, int nargs)
193 gpy_object_attrib_t * attrib = gpy_malloc (sizeof (gpy_object_attrib_t));
194 attrib->identifier = identifier;
195 attrib->T = GPY_GCCPY;
196 if (code_addr)
198 gpy_object_t * f = gpy_rr_fold_classmethod_decl (identifier, code_addr, nargs);
199 attrib->addr = f;
201 else
202 attrib->addr = NULL;
204 attrib->offset = offset;
205 return attrib;
208 gpy_object_attrib_t ** gpy_rr_fold_attrib_list (int n, ...)
210 gpy_object_attrib_t ** retval = NULL;
211 if (n > 0)
213 /* +1 for the sentinal */
214 retval = (gpy_object_attrib_t **)
215 gpy_calloc (n+1, sizeof (gpy_object_attrib_t *));
217 va_list ap;
218 int idx;
219 va_start (ap, n);
220 for (idx = 0; idx < n; ++idx)
222 gpy_object_attrib_t * i = va_arg (ap, gpy_object_attrib_t *);
223 retval[idx] = i;
225 /* sentinal */
226 retval[idx] = NULL;
227 va_end (ap);
229 return retval;
232 gpy_object_t * gpy_rr_fold_encList (int n, ...)
234 gpy_object_t * retval = NULL;
235 va_list ap;
236 va_start (ap, n);
238 gpy_object_t ** elems = (gpy_object_t **)
239 gpy_calloc (n + 1, sizeof (gpy_object_t *));
241 int i;
242 for (i = 0; i < n; ++i)
244 gpy_object_t * elem = va_arg (ap, gpy_object_t *);
245 elems [i] = elem;
247 elems [i] = NULL;
248 va_end (ap);
250 /* + 2 for first argument the length of elements and for sentinal */
251 gpy_object_t ** args = (gpy_object_t **)
252 gpy_calloc (3, sizeof (gpy_object_t *));
254 gpy_literal_t num;
255 num.type = TYPE_INTEGER;
256 num.literal.integer = n;
258 gpy_literal_t elements;
259 elements.type = TYPE_VEC;
260 elements.literal.vec = elems;
262 gpy_object_t a1 = { .T = TYPE_OBJECT_LIT, .o.literal = &num };
263 gpy_object_t a2 = { .T = TYPE_OBJECT_LIT, .o.literal = &elements };
264 gpy_object_t a3 = { .T = TYPE_NULL, .o.literal = NULL };
265 args [0] = &a1;
266 args [1] = &a2;
267 args [2] = &a3;
269 gpy_typedef_t * def = __gpy_list_type_node;
270 retval = def->tp_new (def, args);
272 gpy_free (args);
273 gpy_free (elems);
275 gpy_assert (retval->T == TYPE_OBJECT_STATE);
276 return retval;
279 gpy_object_t * gpy_rr_fold_class_decl (gpy_object_attrib_t ** attribs,
280 int size, const char * identifier)
282 gpy_object_t * retval = NULL_OBJECT;
284 gpy_object_t ** args = (gpy_object_t **)
285 gpy_calloc (4, sizeof(gpy_object_t*));
287 gpy_literal_t A;
288 A.type = TYPE_ATTRIB_L;
289 A.literal.attribs = attribs;
291 gpy_literal_t i;
292 i.type = TYPE_INTEGER;
293 i.literal.integer = size;
295 gpy_literal_t s;
296 s.type = TYPE_STRING;
297 s.literal.string = (char *) identifier;
299 gpy_object_t a1 = { .T = TYPE_OBJECT_LIT, .o.literal = &A };
300 gpy_object_t a2 = { .T = TYPE_OBJECT_LIT, .o.literal = &i };
301 gpy_object_t a3 = { .T = TYPE_OBJECT_LIT, .o.literal = &s };
302 gpy_object_t a4 = { .T = TYPE_NULL, .o.literal = NULL };
304 args[0] = &a1;
305 args[1] = &a2;
306 args[2] = &a3;
307 args[3] = &a4;
309 gpy_typedef_t * def = __gpy_class_type_node;
310 retval = def->tp_new (def, args);
311 gpy_free (args);
313 gpy_assert (retval->T == TYPE_OBJECT_DECL);
314 return retval;
317 gpy_object_t * gpy_rr_fold_staticmethod_decl (const char * identifier,
318 unsigned char * code_addr,
319 int nargs)
321 gpy_object_t * retval = NULL_OBJECT;
323 gpy_object_t ** args = (gpy_object_t **)
324 gpy_calloc (4, sizeof(gpy_object_t*));
326 gpy_literal_t i;
327 i.type = TYPE_STRING;
328 i.literal.string = (char *)identifier;
330 gpy_literal_t p;
331 p.type = TYPE_ADDR;
332 p.literal.addr = code_addr;
334 gpy_literal_t n;
335 n.type = TYPE_INTEGER;
336 n.literal.integer = nargs;
338 gpy_object_t a1 = { .T = TYPE_OBJECT_LIT, .o.literal = &i };
339 gpy_object_t a2 = { .T = TYPE_OBJECT_LIT, .o.literal = &p };
340 gpy_object_t a3 = { .T = TYPE_OBJECT_LIT, .o.literal = &n };
341 gpy_object_t a4 = { .T = TYPE_NULL, .o.literal = NULL };
343 args[0] = &a1;
344 args[1] = &a2;
345 args[2] = &a3;
346 args[3] = &a4;
348 gpy_typedef_t * def = __gpy_staticmethod_type_node;
349 retval = def->tp_new (def, args);
350 gpy_free (args);
352 gpy_assert (retval->T == TYPE_OBJECT_DECL);
354 return retval;
357 gpy_object_t * gpy_rr_fold_classmethod_decl (const char * identifier,
358 unsigned char * code_addr,
359 int nargs)
361 gpy_object_t * retval = NULL_OBJECT;
363 gpy_object_t ** args = (gpy_object_t **)
364 gpy_calloc (4, sizeof(gpy_object_t*));
366 gpy_literal_t s;
367 s.type = TYPE_STRING;
368 s.literal.string = (char *)identifier;
370 gpy_literal_t p;
371 p.type = TYPE_ADDR;
372 p.literal.addr = code_addr;
374 gpy_literal_t n;
375 n.type = TYPE_INTEGER;
376 n.literal.integer = nargs;
378 gpy_object_t a1 = { .T = TYPE_OBJECT_LIT, .o.literal = &s };
379 gpy_object_t a2 = { .T = TYPE_OBJECT_LIT, .o.literal = &p };
380 gpy_object_t a3 = { .T = TYPE_OBJECT_LIT, .o.literal = &n };
381 gpy_object_t a4 = { .T = TYPE_NULL, .o.literal = NULL };
383 args[0] = &a1;
384 args[1] = &a2;
385 args[2] = &a3;
386 args[3] = &a4;
388 gpy_typedef_t * def = __gpy_classmethod_type_node;
389 retval = def->tp_new (def, args);
390 gpy_free (args);
392 gpy_assert (retval->T == TYPE_OBJECT_DECL);
394 return retval;
397 gpy_object_t ** gpy_rr_getRefSlice (gpy_object_t * decl, gpy_object_t * slice)
399 gpy_typedef_t * type = decl->o.object_state->definition;
401 if (type->tp_slice)
402 return type->tp_ref_slice (decl, slice);
403 else
404 fatal ("Object <%p> has no slice assign hook!\n", (void *) decl);
406 return NULL;
409 gpy_object_t * gpy_rr_getSlice (gpy_object_t * decl, gpy_object_t * slice)
411 gpy_typedef_t * type = decl->o.object_state->definition;
413 if (type->tp_slice)
414 return type->tp_slice (decl, slice);
415 else
416 fatal ("Object <%p> has no slice hook!\n", (void *) decl);
418 return NULL;
421 void gpy_rr_foldImport (gpy_object_t ** decl,
422 const char * module)
424 gpy_moduleInfo_t * mod = NULL;
425 gpy_hashval_t h = gpy_dd_hash_string (module);
426 gpy_hash_entry_t * e = gpy_dd_hash_lookup_table (&stack_table, h);
428 gpy_assert (e);
429 gpy_assert (e->data);
430 mod = (gpy_moduleInfo_t *) e->data;
432 gpy_object_t ** args = (gpy_object_t **)
433 gpy_calloc (5, sizeof (gpy_object_t *));
435 gpy_literal_t A;
436 A.type = TYPE_INTEGER;
437 A.literal.integer = mod->offset;
439 gpy_literal_t i;
440 i.type = TYPE_INTEGER;
441 i.literal.integer = mod->length;
443 gpy_literal_t s;
444 s.type = TYPE_STRING;
445 s.literal.string = mod->modID;
447 gpy_literal_t S;
448 S.type = TYPE_STR_ARRY;
449 S.literal.sarray = mod->idents;
451 gpy_object_t a0 = { .T = TYPE_OBJECT_LIT, .o.literal = &A };
452 gpy_object_t a1 = { .T = TYPE_OBJECT_LIT, .o.literal = &i };
453 gpy_object_t a2 = { .T = TYPE_OBJECT_LIT, .o.literal = &s };
454 gpy_object_t a3 = { .T = TYPE_OBJECT_LIT, .o.literal = &S };
455 gpy_object_t a4 = { .T = TYPE_NULL, .o.literal = NULL };
457 args[0] = &a0;
458 args[1] = &a1;
459 args[2] = &a2;
460 args[3] = &a3;
461 args[4] = &a4;
463 gpy_typedef_t * def = __gpy_module_type_node;
464 *decl = def->tp_new (def, args);
465 gpy_free (args);
467 gpy_assert ((*decl)->T == TYPE_OBJECT_DECL);
470 gpy_object_t * gpy_rr_fold_call (gpy_object_t * decl, int nargs, ...)
472 gpy_object_t * retval = NULL_OBJECT;
474 gpy_assert (decl->T == TYPE_OBJECT_DECL);
475 gpy_typedef_t * type = decl->o.object_state->definition;
477 /* + 1 for sentinal */
478 gpy_object_t ** args = calloc (nargs + 1, sizeof (gpy_object_t *));
479 int idx = 0;
480 if (nargs > 0)
482 va_list ap;
483 va_start (ap, nargs);
484 for (idx = 0; idx < nargs; ++idx)
486 args[idx] = va_arg (ap, gpy_object_t *);
489 args[idx] = NULL;
491 if (type->tp_call)
493 /* args length checks ... */
494 int nparms = type->tp_nparms (decl);
496 // if its not a class method we can drop the first argument
497 // since we dont need the self reference, this will be NULL
498 // on normal calls outside of attrib references on modules
499 bool iscmeth = false;
500 if (!strcmp ("classmethod", type->identifier) ||
501 !strcmp ("func", type->identifier))
502 iscmeth = true;
504 if (iscmeth)
506 if (nargs == nparms)
507 retval = type->tp_call (decl, args);
508 else
510 fatal ("call takes %i arguments (%i given)!\n", nparms, nargs);
511 retval = NULL;
514 else
516 nargs -= 1;
517 if (nargs == nparms)
518 retval = type->tp_call (decl, args + 1);
519 else
521 fatal ("call takes %i arguments (%i given)!\n", nparms, nargs);
522 retval = NULL;
526 else
527 fatal ("name is not callable!\n");
528 gpy_free (args);
530 if (__GPY_GLOBAL_RETURN)
532 retval = GPY_MODULE_STACK_RET_VAL;
533 __GPY_GLOBAL_RETURN = false;
536 return retval;
539 unsigned char * gpy_rr_eval_attrib_reference (gpy_object_t * base,
540 const char * attrib)
542 unsigned char * retval = NULL;
543 gpy_typedef_t * type = base->o.object_state->definition;
545 struct gpy_object_attrib_t ** members = type->members_defintion;
546 gpy_object_state_t * objs = base->o.object_state;
548 if (members)
550 int idx, offset = -1;
551 for (idx = 0; members[idx] != NULL; ++idx)
553 struct gpy_object_attrib_t * it = members[idx];
554 if (!strcmp (attrib, it->identifier))
556 if (it->T == GPY_GCCPY)
558 /* when part of the type we can access the instance from the state */
559 offset = it->offset;
560 unsigned char * state = (unsigned char *)objs->state;
561 retval = state + offset;
563 else if (it->T == GPY_MOD)
565 /* when part of the type we can access the instance from the state */
566 offset = it->offset;
567 unsigned char * state = (unsigned char *)objs->state;
568 unsigned char * sref = state + offset;
570 void ** ref = (void **) sref;
571 retval = (unsigned char *) *ref;
573 else
575 // this is probably an internal C attribute to an object.
576 gpy_assert (it->T = GPY_CATTR);
577 retval = (unsigned char *) &(it->addr);
579 break;
583 if (!retval)
584 fatal ("object has no attribute <%s>\n", attrib);
586 gpy_assert (retval);
587 return retval;
590 gpy_object_t * gpy_rr_fold_string (char * string)
592 gpy_object_t * retval = NULL_OBJECT;
594 gpy_object_t ** args = (gpy_object_t **)
595 gpy_calloc (2, sizeof (gpy_object_t *));
596 gpy_assert (args);
598 gpy_literal_t s;
599 s.type = TYPE_STRING;
600 s.literal.string = string;
602 gpy_object_t s1 = { .T = TYPE_OBJECT_LIT, .o.literal = &s };
603 gpy_object_t s2 = { .T = TYPE_NULL, .o.literal = NULL };
605 args [0] = &s1;
606 args [1] = &s2;
608 gpy_typedef_t * Str_def = __gpy_string_type_node;
609 retval = Str_def->tp_new (Str_def, args);
610 gpy_free (args);
611 gpy_assert (retval->T == TYPE_OBJECT_STATE);
613 return retval;
616 gpy_object_t * gpy_rr_fold_integer (const int x)
618 gpy_object_t * retval = NULL_OBJECT;
620 gpy_object_t ** args = (gpy_object_t **)
621 gpy_calloc (2, sizeof(gpy_object_t *));
623 gpy_literal_t i;
624 i.type = TYPE_INTEGER;
625 i.literal.integer = x;
627 gpy_object_t a1 = { .T = TYPE_OBJECT_LIT, .o.literal = &i };
628 gpy_object_t a2 = { .T = TYPE_NULL, .o.literal = NULL };
630 args[0] = &a1;
631 args[1] = &a2;
633 gpy_typedef_t * Int_def = __gpy_integer_type_node;
634 retval = Int_def->tp_new (Int_def, args);
635 gpy_free (args);
636 gpy_assert (retval->T == TYPE_OBJECT_STATE);
638 return retval;
641 inline
642 void * gpy_rr_get_object_state (gpy_object_t * o)
644 gpy_assert (o);
645 return o->o.object_state->state;
648 void gpy_rr_eval_return (gpy_object_t * o)
650 gpy_assert (o);
651 gpy_object_t ** addr = GPY_MODULE_STACK_RET_ADDR;
652 *addr = o;
653 __GPY_GLOBAL_RETURN = true;
657 * int fd: we could use bit masks to represent:
658 * stdout/stderr ...
660 void gpy_rr_eval_print (int fd, int count, ...)
662 va_list vl;
663 int idx;
664 va_start (vl,count);
666 gpy_object_t * it = NULL;
667 for (idx = 0; idx < count; ++idx)
669 it = va_arg (vl, gpy_object_t *);
670 struct gpy_typedef_t * definition = it->o.object_state->definition;
672 switch (fd)
674 case 1:
675 definition->tp_print (it, stdout, false);
676 break;
678 case 2:
679 definition->tp_print (it, stderr, false);
680 break;
682 default:
683 fatal ("invalid print file-descriptor <%i>!\n", fd );
684 break;
688 fprintf (stdout, "\n");
689 va_end (vl);
692 inline
693 void gpy_rr_incr_ref_count (gpy_object_t * x1)
695 gpy_assert (x1->T == TYPE_OBJECT_STATE);
696 gpy_object_state_t * x = x1->o.object_state;
698 debug ("incrementing ref count on <%p>:<%i> to <%i>!\n",
699 (void*) x, x->ref_count, (x->ref_count + 1));
700 x->ref_count++;
703 inline
704 void gpy_rr_decr_ref_count (gpy_object_t * x1)
706 gpy_assert (x1->T == TYPE_OBJECT_STATE);
707 gpy_object_state_t * x = x1->o.object_state;
709 debug ("decrementing ref count on <%p>:<%i> to <%i>!\n",
710 (void*) x, x->ref_count, (x->ref_count - 1));
711 x->ref_count--;
714 bool gpy_rr_eval_boolean (gpy_object_t * x)
716 bool retval = false;
718 gpy_assert (x->T == TYPE_OBJECT_STATE);
719 gpy_object_state_t * state = x->o.object_state;
721 struct gpy_typedef_t * def = state->definition;
722 if (def->tp_eval_boolean)
723 retval = def->tp_eval_boolean (x);
725 return retval;
728 gpy_object_t * gpy_rr_eval_expression (gpy_object_t * x1,
729 gpy_object_t * y1,
730 unsigned int op)
732 gpy_object_t * retval = NULL;
734 gpy_assert (x1->T == TYPE_OBJECT_STATE);
735 gpy_assert (y1->T == TYPE_OBJECT_STATE);
736 gpy_object_state_t * x = x1->o.object_state;
737 gpy_object_state_t * y = y1->o.object_state;
739 struct gpy_typedef_t * def = x1->o.object_state->definition;
740 struct gpy_number_prot_t * binops = (*def).binary_protocol;
741 struct gpy_number_prot_t binops_l = (*binops);
743 binary_op o = NULL;
744 switch (op)
746 case 1:
747 o = binops_l.n_add;
748 break;
750 case 2:
751 o = binops_l.n_sub;
752 break;
754 case 3:
755 o = binops_l.n_div;
756 break;
758 case 4:
759 o = binops_l.n_mul;
760 break;
762 case 5:
763 o = binops_l.n_pow;
764 break;
766 case 6:
767 o = binops_l.n_let;
768 break;
770 case 8:
771 o = binops_l.n_get;
772 break;
774 case 10:
775 o = binops_l.n_eee;
776 break;
778 case 11:
779 o = binops_l.n_nee;
780 break;
782 case 12:
783 o = binops_l.n_orr;
784 break;
786 case 13:
787 o = binops_l.n_and;
788 break;
790 default:
791 fatal("unhandled binary operation <%x>!\n", op );
792 break;
795 if (o)
796 retval = o (x1,y1);
797 else
798 fatal ("no binary protocol!\n");
799 return retval;