2 # This file is Copyright 2003, 2006, 2007, 2009, 2010 Dean Hall.
4 # This file is part of the PyMite VM.
5 # The PyMite VM is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU GENERAL PUBLIC LICENSE Version 2.
8 # The PyMite VM is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 # A copy of the GNU GENERAL PUBLIC LICENSE Version 2
12 # is seen in the file COPYING in this directory.
17 #define __FILE_ID__ 0x09
22 * \brief VM Interpreter
24 * VM interpreter operations.
32 interpret(const uint8_t returnOnNoThreads
)
34 PmReturn_t retval
= PM_RET_OK
;
35 pPmObj_t pobj1
= C_NULL
;
36 pPmObj_t pobj2
= C_NULL
;
37 pPmObj_t pobj3
= C_NULL
;
41 uint8_t objid
, objid2
;
43 /* Activate a thread the first time */
44 retval
= interp_reschedule();
45 PM_RETURN_IF_ERROR(retval
);
50 if (gVmGlobal
.pthread
== C_NULL
)
52 if (returnOnNoThreads
)
54 /* User chose to return on no threads left */
59 * Without a frame there is nothing to execute, so reschedule
60 * (possibly activating a recently added thread).
62 retval
= interp_reschedule();
63 PM_BREAK_IF_ERROR(retval
);
67 /* Reschedule threads if flag is true? */
68 if (gVmGlobal
.reschedule
)
70 retval
= interp_reschedule();
71 PM_BREAK_IF_ERROR(retval
);
74 /* Get byte; the func post-incrs PM_IP */
75 bc
= mem_getByte(PM_FP
->fo_memspace
, &PM_IP
);
112 /* Raise TypeError if TOS is not an int */
113 if ((OBJ_GET_TYPE(TOS
) != OBJ_TYPE_INT
)
115 && (OBJ_GET_TYPE(TOS
) != OBJ_TYPE_FLT
)
116 #endif /* HAVE_FLOAT */
119 PM_RAISE(retval
, PM_RET_EX_TYPE
);
123 /* When TOS is an int, this is a no-op */
128 if (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_FLT
)
130 retval
= float_negative(TOS
, &pobj2
);
133 #endif /* HAVE_FLOAT */
135 retval
= int_negative(TOS
, &pobj2
);
137 PM_BREAK_IF_ERROR(retval
);
143 if (obj_isFalse(pobj1
))
154 /* #244 Add support for the backtick operation (UNARY_CONVERT) */
156 retval
= obj_repr(TOS
, &pobj3
);
157 PM_BREAK_IF_ERROR(retval
);
160 #endif /* HAVE_BACKTICK */
163 /* Raise TypeError if it's not an int */
164 if (OBJ_GET_TYPE(TOS
) != OBJ_TYPE_INT
)
166 PM_RAISE(retval
, PM_RET_EX_TYPE
);
170 /* Otherwise perform bit-wise complement */
171 retval
= int_bitInvert(TOS
, &pobj2
);
172 PM_BREAK_IF_ERROR(retval
);
177 /* list_append will raise a TypeError if TOS1 is not a list */
178 retval
= list_append(TOS1
, TOS
);
186 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_FLT
)
187 || (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_FLT
))
189 /* Calculate float power */
190 retval
= float_op(TOS1
, TOS
, &pobj3
, 'P');
191 PM_BREAK_IF_ERROR(retval
);
196 #endif /* HAVE_FLOAT */
198 /* Calculate integer power */
199 retval
= int_pow(TOS1
, TOS
, &pobj3
);
200 PM_BREAK_IF_ERROR(retval
);
202 /* Set return value */
208 #ifdef HAVE_GENERATORS
209 /* Raise TypeError if TOS is an instance, but not iterable */
210 if (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_CLI
)
212 retval
= class_getAttr(TOS
, PM_NEXT_STR
, &pobj1
);
213 if (retval
!= PM_RET_OK
)
215 PM_RAISE(retval
, PM_RET_EX_TYPE
);
220 #endif /* HAVE_GENERATORS */
222 /* Convert sequence to sequence-iterator */
223 retval
= seqiter_new(TOS
, &pobj1
);
224 PM_BREAK_IF_ERROR(retval
);
226 /* Put sequence-iterator on top of stack */
231 case BINARY_MULTIPLY
:
232 case INPLACE_MULTIPLY
:
233 /* If both objs are ints, perform the op */
234 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_INT
)
235 && (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_INT
))
237 retval
= int_new(((pPmInt_t
)TOS1
)->val
*
238 ((pPmInt_t
)TOS
)->val
, &pobj3
);
239 PM_BREAK_IF_ERROR(retval
);
246 else if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_FLT
)
247 || (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_FLT
))
249 retval
= float_op(TOS1
, TOS
, &pobj3
, '*');
250 PM_BREAK_IF_ERROR(retval
);
255 #endif /* HAVE_FLOAT */
257 #ifdef HAVE_REPLICATION
258 /* If it's a list replication operation */
259 else if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_INT
)
260 && (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_LST
))
262 t16
= (int16_t)((pPmInt_t
)TOS
)->val
;
268 retval
= list_replicate(TOS1
, t16
, &pobj3
);
269 PM_BREAK_IF_ERROR(retval
);
275 /* If it's a tuple replication operation */
276 else if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_INT
)
277 && (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_TUP
))
279 t16
= (int16_t)((pPmInt_t
)TOS
)->val
;
285 retval
= tuple_replicate(TOS1
, t16
, &pobj3
);
286 PM_BREAK_IF_ERROR(retval
);
292 /* If it's a string replication operation */
293 else if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_INT
)
294 && (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_STR
))
296 t16
= (int16_t)((pPmInt_t
)TOS
)->val
;
303 pobj2
= (pPmObj_t
)&((pPmString_t
)pobj2
)->val
;
304 retval
= string_replicate(
305 (uint8_t const **)(uint8_t *)&pobj2
, t16
, &pobj3
);
306 PM_BREAK_IF_ERROR(retval
);
311 #endif /* HAVE_REPLICATION */
313 /* Otherwise raise a TypeError */
314 PM_RAISE(retval
, PM_RET_EX_TYPE
);
319 case BINARY_FLOOR_DIVIDE
:
320 case INPLACE_FLOOR_DIVIDE
:
323 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_FLT
)
324 || (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_FLT
))
326 retval
= float_op(TOS1
, TOS
, &pobj3
, '/');
327 PM_BREAK_IF_ERROR(retval
);
332 #endif /* HAVE_FLOAT */
334 /* Raise TypeError if args aren't ints */
335 if ((OBJ_GET_TYPE(TOS
) != OBJ_TYPE_INT
)
336 || (OBJ_GET_TYPE(TOS1
) != OBJ_TYPE_INT
))
338 PM_RAISE(retval
, PM_RET_EX_TYPE
);
342 /* Raise ZeroDivisionError if denominator is zero */
343 if (((pPmInt_t
)TOS
)->val
== 0)
345 PM_RAISE(retval
, PM_RET_EX_ZDIV
);
349 /* Otherwise perform operation */
350 retval
= int_new(((pPmInt_t
)TOS1
)->val
/
351 ((pPmInt_t
)TOS
)->val
, &pobj3
);
352 PM_BREAK_IF_ERROR(retval
);
360 #ifdef HAVE_STRING_FORMAT
361 /* If it's a string, perform string format */
362 if (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_STR
)
364 retval
= string_format((pPmString_t
)TOS1
, TOS
, &pobj3
);
365 PM_BREAK_IF_ERROR(retval
);
370 #endif /* HAVE_STRING_FORMAT */
373 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_FLT
)
374 || (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_FLT
))
376 retval
= float_op(TOS1
, TOS
, &pobj3
, '%');
377 PM_BREAK_IF_ERROR(retval
);
382 #endif /* HAVE_FLOAT */
384 /* Raise TypeError if args aren't ints */
385 if ((OBJ_GET_TYPE(TOS
) != OBJ_TYPE_INT
)
386 || (OBJ_GET_TYPE(TOS1
) != OBJ_TYPE_INT
))
388 PM_RAISE(retval
, PM_RET_EX_TYPE
);
392 /* Raise ZeroDivisionError if denominator is zero */
393 if (((pPmInt_t
)TOS
)->val
== 0)
395 PM_RAISE(retval
, PM_RET_EX_ZDIV
);
399 /* Otherwise perform operation */
400 retval
= int_new(((pPmInt_t
)TOS1
)->val
%
401 ((pPmInt_t
)TOS
)->val
, &pobj3
);
402 PM_BREAK_IF_ERROR(retval
);
408 /* #213: Add support for Python 2.6 bytecodes */
409 C_ASSERT(OBJ_GET_TYPE(TOS2
) == OBJ_TYPE_DIC
);
410 retval
= dict_setItem(TOS2
, TOS
, TOS1
);
411 PM_BREAK_IF_ERROR(retval
);
419 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_FLT
)
420 || (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_FLT
))
422 retval
= float_op(TOS1
, TOS
, &pobj3
, '+');
423 PM_BREAK_IF_ERROR(retval
);
428 #endif /* HAVE_FLOAT */
430 /* If both objs are ints, perform the op */
431 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_INT
)
432 && (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_INT
))
434 retval
= int_new(((pPmInt_t
)TOS1
)->val
+
435 ((pPmInt_t
)TOS
)->val
, &pobj3
);
436 PM_BREAK_IF_ERROR(retval
);
442 /* #242: If both objs are strings, perform concatenation */
443 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_STR
)
444 && (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_STR
))
446 retval
= string_concat((pPmString_t
)TOS1
,
449 PM_BREAK_IF_ERROR(retval
);
455 /* Otherwise raise a TypeError */
456 PM_RAISE(retval
, PM_RET_EX_TYPE
);
459 case BINARY_SUBTRACT
:
460 case INPLACE_SUBTRACT
:
463 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_FLT
)
464 || (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_FLT
))
466 retval
= float_op(TOS1
, TOS
, &pobj3
, '-');
467 PM_BREAK_IF_ERROR(retval
);
472 #endif /* HAVE_FLOAT */
474 /* If both objs are ints, perform the op */
475 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_INT
)
476 && (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_INT
))
478 retval
= int_new(((pPmInt_t
)TOS1
)->val
-
479 ((pPmInt_t
)TOS
)->val
, &pobj3
);
480 PM_BREAK_IF_ERROR(retval
);
486 /* Otherwise raise a TypeError */
487 PM_RAISE(retval
, PM_RET_EX_TYPE
);
491 /* Implements TOS = TOS1[TOS]. */
493 if (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_DIC
)
495 retval
= dict_getItem(TOS1
, TOS
, &pobj3
);
499 /* Raise a TypeError if index is not an Integer or Bool */
500 if ((OBJ_GET_TYPE(TOS
) != OBJ_TYPE_INT
)
501 && (OBJ_GET_TYPE(TOS
) != OBJ_TYPE_BOOL
))
503 PM_RAISE(retval
, PM_RET_EX_TYPE
);
508 #ifdef HAVE_BYTEARRAY
509 /* If object is an instance, get the thing it contains */
510 if (OBJ_GET_TYPE(pobj1
) == OBJ_TYPE_CLI
)
512 retval
= dict_getItem((pPmObj_t
)((pPmInstance_t
)pobj1
)->cli_attrs
,
515 PM_RETURN_IF_ERROR(retval
);
518 #endif /* HAVE_BYTEARRAY */
520 /* Ensure the index doesn't overflow */
521 C_ASSERT(((pPmInt_t
)TOS
)->val
<= 0x0000FFFF);
522 t16
= (int16_t)((pPmInt_t
)TOS
)->val
;
524 retval
= seq_getSubscript(pobj1
, t16
, &pobj3
);
526 PM_BREAK_IF_ERROR(retval
);
532 /* #213: Add support for Python 2.6 bytecodes */
533 case BINARY_TRUE_DIVIDE
:
534 case INPLACE_TRUE_DIVIDE
:
536 /* Perform division; float_op() checks for types and zero-div */
537 retval
= float_op(TOS1
, TOS
, &pobj3
, '/');
538 PM_BREAK_IF_ERROR(retval
);
542 #endif /* HAVE_FLOAT */
545 /* Implements TOS = TOS[:], push a copy of the sequence */
547 /* Create a copy if it is a list */
548 if (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_LST
)
550 retval
= list_copy(TOS
, &pobj2
);
551 PM_BREAK_IF_ERROR(retval
);
556 /* If TOS is an immutable sequence leave it (no op) */
558 /* Raise a TypeError for types that can not be sliced */
559 else if ((OBJ_GET_TYPE(TOS
) != OBJ_TYPE_STR
)
560 && (OBJ_GET_TYPE(TOS
) != OBJ_TYPE_TUP
))
562 PM_RAISE(retval
, PM_RET_EX_TYPE
);
568 /* Implements TOS1[TOS] = TOS2 */
571 if (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_LST
)
573 /* Ensure subscr is an int or bool */
574 if ((OBJ_GET_TYPE(TOS
) != OBJ_TYPE_INT
)
575 && (OBJ_GET_TYPE(TOS
) != OBJ_TYPE_BOOL
))
577 PM_RAISE(retval
, PM_RET_EX_TYPE
);
581 /* Set the list item */
582 retval
= list_setItem(TOS1
,
583 (int16_t)(((pPmInt_t
)TOS
)->val
),
585 PM_BREAK_IF_ERROR(retval
);
591 if (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_DIC
)
593 /* Set the dict item */
594 retval
= dict_setItem(TOS1
, TOS
, TOS2
);
595 PM_BREAK_IF_ERROR(retval
);
600 #ifdef HAVE_BYTEARRAY
601 /* If object is an instance, get the thing it contains */
602 if (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_CLI
)
604 retval
= dict_getItem((pPmObj_t
)((pPmInstance_t
)TOS1
)->cli_attrs
,
608 /* Raise TypeError if instance isn't a ByteArray */
609 if ((retval
== PM_RET_EX_KEY
)
610 || (OBJ_GET_TYPE(pobj2
) != OBJ_TYPE_BYA
))
612 PM_RAISE(retval
, PM_RET_EX_TYPE
);
615 PM_BREAK_IF_ERROR(retval
);
617 /* Ensure subscr is an int or bool */
618 if ((OBJ_GET_TYPE(TOS
) != OBJ_TYPE_INT
)
619 && (OBJ_GET_TYPE(TOS
) != OBJ_TYPE_BOOL
))
621 PM_RAISE(retval
, PM_RET_EX_TYPE
);
625 retval
= bytearray_setItem(pobj2
,
626 (int16_t)(((pPmInt_t
)TOS
)->val
),
628 PM_BREAK_IF_ERROR(retval
);
632 #endif /* HAVE_BYTEARRAY */
634 /* TypeError for all else */
635 PM_RAISE(retval
, PM_RET_EX_TYPE
);
641 if ((OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_LST
)
642 && (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_INT
))
644 retval
= list_delItem(TOS1
,
645 (int16_t)((pPmInt_t
)TOS
)->val
);
648 else if ((OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_DIC
)
649 && (OBJ_GET_TYPE(TOS
) <= OBJ_TYPE_HASHABLE_MAX
))
651 retval
= dict_delItem(TOS1
, TOS
);
654 /* Raise TypeError if obj is not a list or dict */
657 PM_RAISE(retval
, PM_RET_EX_TYPE
);
660 PM_BREAK_IF_ERROR(retval
);
663 #endif /* HAVE_DEL */
667 /* If both objs are ints, perform the op */
668 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_INT
)
669 && (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_INT
))
671 retval
= int_new(((pPmInt_t
)TOS1
)->val
<<
672 ((pPmInt_t
)TOS
)->val
, &pobj3
);
673 PM_BREAK_IF_ERROR(retval
);
679 /* Otherwise raise a TypeError */
680 PM_RAISE(retval
, PM_RET_EX_TYPE
);
685 /* If both objs are ints, perform the op */
686 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_INT
)
687 && (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_INT
))
689 retval
= int_new(((pPmInt_t
)TOS1
)->val
>>
690 ((pPmInt_t
)TOS
)->val
, &pobj3
);
691 PM_BREAK_IF_ERROR(retval
);
697 /* Otherwise raise a TypeError */
698 PM_RAISE(retval
, PM_RET_EX_TYPE
);
703 /* If both objs are ints, perform the op */
704 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_INT
)
705 && (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_INT
))
707 retval
= int_new(((pPmInt_t
)TOS1
)->val
&
708 ((pPmInt_t
)TOS
)->val
, &pobj3
);
709 PM_BREAK_IF_ERROR(retval
);
715 /* Otherwise raise a TypeError */
716 PM_RAISE(retval
, PM_RET_EX_TYPE
);
721 /* If both objs are ints, perform the op */
722 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_INT
)
723 && (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_INT
))
725 retval
= int_new(((pPmInt_t
)TOS1
)->val
^
726 ((pPmInt_t
)TOS
)->val
, &pobj3
);
727 PM_BREAK_IF_ERROR(retval
);
733 /* Otherwise raise a TypeError */
734 PM_RAISE(retval
, PM_RET_EX_TYPE
);
739 /* If both objs are ints, perform the op */
740 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_INT
)
741 && (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_INT
))
743 retval
= int_new(((pPmInt_t
)TOS1
)->val
|
744 ((pPmInt_t
)TOS
)->val
, &pobj3
);
745 PM_BREAK_IF_ERROR(retval
);
751 /* Otherwise raise a TypeError */
752 PM_RAISE(retval
, PM_RET_EX_TYPE
);
757 /* Print interactive expression */
761 if (gVmGlobal
.needSoftSpace
&& (bc
== PRINT_ITEM
))
763 retval
= plat_putByte(' ');
764 PM_BREAK_IF_ERROR(retval
);
766 gVmGlobal
.needSoftSpace
= C_TRUE
;
768 /* Print out topmost stack element */
769 retval
= obj_print(TOS
, (uint8_t)(bc
== PRINT_EXPR
), C_FALSE
);
770 PM_BREAK_IF_ERROR(retval
);
772 if (bc
!= PRINT_EXPR
)
776 /* If PRINT_EXPR, Fallthrough to print a newline */
779 gVmGlobal
.needSoftSpace
= C_FALSE
;
780 if (gVmGlobal
.somethingPrinted
)
782 retval
= plat_putByte('\n');
783 gVmGlobal
.somethingPrinted
= C_FALSE
;
785 PM_BREAK_IF_ERROR(retval
);
787 #endif /* HAVE_PRINT */
791 pPmBlock_t pb1
= PM_FP
->fo_blockstack
;
793 /* Ensure there's a block */
794 C_ASSERT(pb1
!= C_NULL
);
796 /* Delete blocks until first loop block */
797 while ((pb1
->b_type
!= B_LOOP
) && (pb1
->next
!= C_NULL
))
799 pobj2
= (pPmObj_t
)pb1
;
801 retval
= heap_freeChunk(pobj2
);
802 PM_BREAK_IF_ERROR(retval
);
805 /* Test again outside while loop */
806 PM_BREAK_IF_ERROR(retval
);
812 PM_IP
= pb1
->b_handler
;
814 /* Pop and delete this block */
815 PM_FP
->fo_blockstack
= pb1
->next
;
816 retval
= heap_freeChunk((pPmObj_t
)pb1
);
817 PM_BREAK_IF_ERROR(retval
);
822 /* Pushes local attrs dict of current frame */
823 /* WARNING: does not copy fo_locals to attrs */
824 PM_PUSH((pPmObj_t
)PM_FP
->fo_attrs
);
828 /* Get expiring frame's TOS */
832 /* #251: This safety check is disabled because it breaks ipm */
833 /* #109: Check that stack should now be empty */
834 /* If this is regular frame (not native and not a generator) */
835 if ((PM_FP
!= (pPmFrame_t
)(&gVmGlobal
.nativeframe
)) &&
836 !(PM_FP
->fo_func
->f_co
->co_flags
& CO_GENERATOR
))
838 /* An empty stack points one past end of locals */
839 t8
= PM_FP
->fo_func
->f_co
->co_nlocals
;
840 C_ASSERT(PM_SP
== &(PM_FP
->fo_locals
[t8
]));
842 #endif /* __DEBUG__ */
844 /* Keep ref of expiring frame */
845 pobj1
= (pPmObj_t
)PM_FP
;
846 C_ASSERT(OBJ_GET_TYPE(pobj1
) == OBJ_TYPE_FRM
);
848 /* If no previous frame, quit thread */
849 if (PM_FP
->fo_back
== C_NULL
)
851 gVmGlobal
.pthread
->interpctrl
= INTERP_CTRL_EXIT
;
856 /* Otherwise return to previous frame */
857 PM_FP
= PM_FP
->fo_back
;
859 #ifdef HAVE_GENERATORS
860 /* If returning function was a generator */
861 if (((pPmFrame_t
)pobj1
)->fo_func
->f_co
->co_flags
& CO_GENERATOR
)
863 /* Raise a StopIteration exception */
864 PM_RAISE(retval
, PM_RET_EX_STOP
);
867 #endif /* HAVE_GENERATORS */
871 * If returning function was class initializer
872 * do not push a return object
874 if (((pPmFrame_t
)pobj1
)->fo_isInit
)
876 /* Raise TypeError if __init__ did not return None */
877 if (pobj2
!= PM_NONE
)
879 PM_RAISE(retval
, PM_RET_EX_TYPE
);
884 #endif /* HAVE_CLASSES */
887 * Push frame's return val, except if the expiring frame
888 * was due to an import statement
890 if (!(((pPmFrame_t
)pobj1
)->fo_isImport
))
895 /* Deallocate expired frame */
896 PM_BREAK_IF_ERROR(heap_freeChunk(pobj1
));
901 /* #102: Implement the remaining IMPORT_ bytecodes */
902 /* Expect a module on the top of the stack */
903 C_ASSERT(OBJ_GET_TYPE(TOS
) == OBJ_TYPE_MOD
);
905 /* Update PM_FP's attrs with those of the module on the stack */
906 retval
= dict_update((pPmObj_t
)PM_FP
->fo_attrs
,
907 (pPmObj_t
)((pPmFunc_t
)TOS
)->f_attrs
);
908 PM_BREAK_IF_ERROR(retval
);
911 #endif /* HAVE_IMPORTS */
913 #ifdef HAVE_GENERATORS
915 /* #207: Add support for the yield keyword */
916 /* Get expiring frame's TOS */
919 /* Raise TypeError if __init__ did not return None */
920 /* (Yield means this is a generator) */
921 if ((PM_FP
)->fo_isInit
)
923 PM_RAISE(retval
, PM_RET_EX_TYPE
);
927 /* Return to previous frame */
928 PM_FP
= PM_FP
->fo_back
;
930 /* Push yield value onto caller's TOS */
933 #endif /* HAVE_GENERATORS */
936 /* Get ptr to top block */
937 pobj1
= (pPmObj_t
)PM_FP
->fo_blockstack
;
939 /* If there's no block, raise SystemError */
940 C_ASSERT(pobj1
!= C_NULL
);
943 PM_FP
->fo_blockstack
= PM_FP
->fo_blockstack
->next
;
945 /* Set stack to previous level, jump to code outside block */
946 PM_SP
= ((pPmBlock_t
)pobj1
)->b_sp
;
947 PM_IP
= ((pPmBlock_t
)pobj1
)->b_handler
;
949 PM_BREAK_IF_ERROR(heap_freeChunk(pobj1
));
954 /* Create and push new class */
955 retval
= class_new(TOS
, TOS1
, TOS2
, &pobj2
);
956 PM_BREAK_IF_ERROR(retval
);
960 #endif /* HAVE_CLASSES */
963 /***************************************************
964 * All bytecodes after 90 (0x5A) have a 2-byte arg
965 * that needs to be swallowed using GET_ARG().
966 **************************************************/
973 pobj2
= PM_FP
->fo_func
->f_co
->co_names
->val
[t16
];
975 /* Set key=val in current frame's attrs dict */
976 retval
= dict_setItem((pPmObj_t
)PM_FP
->fo_attrs
, pobj2
, TOS
);
977 PM_BREAK_IF_ERROR(retval
);
987 pobj2
= PM_FP
->fo_func
->f_co
->co_names
->val
[t16
];
989 /* Remove key,val pair from current frame's attrs dict */
990 retval
= dict_delItem((pPmObj_t
)PM_FP
->fo_attrs
, pobj2
);
991 PM_BREAK_IF_ERROR(retval
);
993 #endif /* HAVE_DEL */
995 case UNPACK_SEQUENCE
:
996 /* Get ptr to sequence */
999 #ifdef HAVE_BYTEARRAY
1000 /* If object is an instance, get the thing it contains */
1001 if (OBJ_GET_TYPE(pobj1
) == OBJ_TYPE_CLI
)
1003 retval
= dict_getItem((pPmObj_t
)((pPmInstance_t
)pobj1
)->cli_attrs
,
1006 PM_RETURN_IF_ERROR(retval
);
1009 #endif /* HAVE_BYTEARRAY */
1012 * Get the length of the sequence; this will
1013 * raise TypeError if obj is not a sequence.
1015 * #59: Unpacking to a Dict shall not be supported
1017 retval
= seq_getLength(pobj1
, &t16
);
1018 if (retval
!= PM_RET_OK
)
1024 /* Raise ValueError if seq length does not match num args */
1025 if (t16
!= GET_ARG())
1027 PM_RAISE(retval
, PM_RET_EX_VAL
);
1031 /* Push sequence's objs onto stack */
1034 retval
= seq_getSubscript(pobj1
, t16
, &pobj2
);
1035 PM_BREAK_IF_ERROR(retval
);
1039 /* Test again outside the for loop */
1040 PM_BREAK_IF_ERROR(retval
);
1046 #ifdef HAVE_GENERATORS
1047 /* If TOS is an instance, call next method */
1048 if (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_CLI
)
1050 /* Get the next() func */
1051 retval
= class_getAttr(TOS
, PM_NEXT_STR
, &pobj1
);
1052 PM_BREAK_IF_ERROR(retval
);
1054 /* Push the func and instance as an arg */
1060 /* Ensure pobj1 is the func */
1061 goto CALL_FUNC_FOR_ITER
;
1064 #endif /* HAVE_GENERATORS */
1066 /* Get the next item in the sequence iterator */
1067 retval
= seqiter_getNext(TOS
, &pobj2
);
1070 /* Catch StopIteration early: pop iterator and break loop */
1071 if (retval
== PM_RET_EX_STOP
)
1078 PM_BREAK_IF_ERROR(retval
);
1080 /* Push the next item onto the stack */
1085 /* TOS.name = TOS1 */
1086 /* Get names index */
1089 /* Get attrs dict from obj */
1090 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_FXN
)
1091 || (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_MOD
))
1093 pobj2
= (pPmObj_t
)((pPmFunc_t
)TOS
)->f_attrs
;
1097 else if (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_CLO
)
1099 pobj2
= (pPmObj_t
)((pPmClass_t
)TOS
)->cl_attrs
;
1101 else if (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_CLI
)
1103 pobj2
= (pPmObj_t
)((pPmInstance_t
)TOS
)->cli_attrs
;
1105 else if (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_MTH
)
1107 pobj2
= (pPmObj_t
)((pPmMethod_t
)TOS
)->m_attrs
;
1109 #endif /* HAVE_CLASSES */
1111 /* Other types result in an AttributeError */
1114 PM_RAISE(retval
, PM_RET_EX_ATTR
);
1118 /* If attrs is not a dict, raise SystemError */
1119 if (OBJ_GET_TYPE(pobj2
) != OBJ_TYPE_DIC
)
1121 PM_RAISE(retval
, PM_RET_EX_SYS
);
1125 /* Get name/key obj */
1126 pobj3
= PM_FP
->fo_func
->f_co
->co_names
->val
[t16
];
1128 /* Set key=val in obj's dict */
1129 retval
= dict_setItem(pobj2
, pobj3
, TOS1
);
1130 PM_BREAK_IF_ERROR(retval
);
1137 /* Get names index */
1140 /* Get attrs dict from obj */
1141 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_FXN
)
1142 || (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_MOD
))
1144 pobj2
= (pPmObj_t
)((pPmFunc_t
)TOS
)->f_attrs
;
1148 else if (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_CLO
)
1150 pobj2
= (pPmObj_t
)((pPmClass_t
)TOS
)->cl_attrs
;
1152 else if (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_CLI
)
1154 pobj2
= (pPmObj_t
)((pPmInstance_t
)TOS
)->cli_attrs
;
1156 else if (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_MTH
)
1158 pobj2
= (pPmObj_t
)((pPmMethod_t
)TOS
)->m_attrs
;
1160 #endif /* HAVE_CLASSES */
1162 /* Other types result in an AttributeError */
1165 PM_RAISE(retval
, PM_RET_EX_ATTR
);
1169 /* If attrs is not a dict, raise SystemError */
1170 if (OBJ_GET_TYPE(pobj2
) != OBJ_TYPE_DIC
)
1172 PM_RAISE(retval
, PM_RET_EX_SYS
);
1176 /* Get name/key obj */
1177 pobj3
= PM_FP
->fo_func
->f_co
->co_names
->val
[t16
];
1179 /* Remove key,val from obj's dict */
1180 retval
= dict_delItem(pobj2
, pobj3
);
1182 /* Raise an AttributeError if key is not found */
1183 if (retval
== PM_RET_EX_KEY
)
1185 PM_RAISE(retval
, PM_RET_EX_ATTR
);
1188 PM_BREAK_IF_ERROR(retval
);
1191 #endif /* HAVE_DEL */
1194 /* Get name index */
1198 pobj2
= PM_FP
->fo_func
->f_co
->co_names
->val
[t16
];
1200 /* Set key=val in global dict */
1201 retval
= dict_setItem((pPmObj_t
)PM_FP
->fo_globals
, pobj2
, TOS
);
1202 PM_BREAK_IF_ERROR(retval
);
1208 /* Get name index */
1212 pobj2
= PM_FP
->fo_func
->f_co
->co_names
->val
[t16
];
1214 /* Remove key,val from globals */
1215 retval
= dict_delItem((pPmObj_t
)PM_FP
->fo_globals
, pobj2
);
1216 PM_BREAK_IF_ERROR(retval
);
1218 #endif /* HAVE_DEL */
1236 /* Get const's index in CO */
1239 /* Push const on stack */
1240 PM_PUSH(PM_FP
->fo_func
->f_co
->co_consts
->val
[t16
]);
1244 /* Get name index */
1247 /* Get name from names tuple */
1248 pobj1
= PM_FP
->fo_func
->f_co
->co_names
->val
[t16
];
1250 /* Get value from frame's attrs dict */
1251 retval
= dict_getItem((pPmObj_t
)PM_FP
->fo_attrs
, pobj1
, &pobj2
);
1252 if (retval
== PM_RET_EX_KEY
)
1254 /* Get val from globals */
1255 retval
= dict_getItem((pPmObj_t
)PM_FP
->fo_globals
,
1258 /* Check for name in the builtins module if it is loaded */
1259 if ((retval
== PM_RET_EX_KEY
) && (PM_PBUILTINS
!= C_NULL
))
1261 /* Get val from builtins */
1262 retval
= dict_getItem(PM_PBUILTINS
, pobj1
, &pobj2
);
1263 if (retval
== PM_RET_EX_KEY
)
1265 /* Name not defined, raise NameError */
1266 PM_RAISE(retval
, PM_RET_EX_NAME
);
1271 PM_BREAK_IF_ERROR(retval
);
1278 retval
= tuple_new(t16
, &pobj1
);
1279 PM_BREAK_IF_ERROR(retval
);
1281 /* Fill tuple with ptrs to objs */
1284 ((pPmTuple_t
)pobj1
)->val
[t16
] = PM_POP();
1291 retval
= list_new(&pobj1
);
1292 PM_BREAK_IF_ERROR(retval
);
1295 /* Insert obj into list */
1296 heap_gcPushTempRoot(pobj1
, &objid
);
1297 retval
= list_insert(pobj1
, 0, TOS
);
1298 heap_gcPopTempRoot(objid
);
1299 PM_BREAK_IF_ERROR(retval
);
1302 /* Test again outside for loop */
1303 PM_BREAK_IF_ERROR(retval
);
1305 /* push list onto stack */
1310 /* Argument is ignored */
1312 retval
= dict_new(&pobj1
);
1313 PM_BREAK_IF_ERROR(retval
);
1318 /* Implements TOS.attr */
1321 /* Get attrs dict from obj */
1322 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_FXN
) ||
1323 (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_MOD
))
1325 pobj1
= (pPmObj_t
)((pPmFunc_t
)TOS
)->f_attrs
;
1329 else if (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_CLO
)
1331 pobj1
= (pPmObj_t
)((pPmClass_t
)TOS
)->cl_attrs
;
1333 else if (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_CLI
)
1335 pobj1
= (pPmObj_t
)((pPmInstance_t
)TOS
)->cli_attrs
;
1337 else if (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_MTH
)
1339 pobj1
= (pPmObj_t
)((pPmMethod_t
)TOS
)->m_attrs
;
1341 #endif /* HAVE_CLASSES */
1343 /* Other types result in an AttributeError */
1346 PM_RAISE(retval
, PM_RET_EX_ATTR
);
1350 /* If attrs is not a dict, raise SystemError */
1351 if (OBJ_GET_TYPE(pobj1
) != OBJ_TYPE_DIC
)
1353 PM_RAISE(retval
, PM_RET_EX_SYS
);
1358 pobj2
= PM_FP
->fo_func
->f_co
->co_names
->val
[t16
];
1360 /* Get attr with given name */
1361 retval
= dict_getItem(pobj1
, pobj2
, &pobj3
);
1365 * If attr is not found and object is a class or instance,
1366 * try to get the attribute from the class attrs or parent(s)
1368 if ((retval
== PM_RET_EX_KEY
) &&
1369 ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_CLO
)
1370 || (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_CLI
)))
1372 retval
= class_getAttr(TOS
, pobj2
, &pobj3
);
1374 #endif /* HAVE_CLASSES */
1376 /* Raise an AttributeError if key is not found */
1377 if (retval
== PM_RET_EX_KEY
)
1379 PM_RAISE(retval
, PM_RET_EX_ATTR
);
1381 PM_BREAK_IF_ERROR(retval
);
1384 /* If obj is an instance and attr is a func, create method */
1385 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_CLI
) &&
1386 (OBJ_GET_TYPE(pobj3
) == OBJ_TYPE_FXN
))
1389 retval
= class_method(TOS
, pobj2
, &pobj3
);
1390 PM_BREAK_IF_ERROR(retval
);
1392 #endif /* HAVE_CLASSES */
1394 /* Put attr on the stack */
1403 if ((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_FLT
)
1404 || (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_FLT
))
1406 retval
= float_compare(TOS1
, TOS
, &pobj3
, (PmCompare_t
)t16
);
1411 #endif /* HAVE_FLOAT */
1413 /* Handle all integer-to-integer (or bool) comparisons */
1414 if (((OBJ_GET_TYPE(TOS
) == OBJ_TYPE_INT
)
1415 || (OBJ_GET_TYPE(TOS
) == OBJ_TYPE_BOOL
))
1416 && ((OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_INT
)
1417 || (OBJ_GET_TYPE(TOS1
) == OBJ_TYPE_BOOL
)))
1419 int32_t a
= ((pPmInt_t
)TOS1
)->val
;
1420 int32_t b
= ((pPmInt_t
)TOS
)->val
;
1425 case COMP_LT
: t8
= (int8_t)(a
< b
); break;
1426 case COMP_LE
: t8
= (int8_t)(a
<= b
); break;
1427 case COMP_EQ
: t8
= (int8_t)(a
== b
); break;
1428 case COMP_NE
: t8
= (int8_t)(a
!= b
); break;
1429 case COMP_GT
: t8
= (int8_t)(a
> b
); break;
1430 case COMP_GE
: t8
= (int8_t)(a
>= b
); break;
1431 case COMP_IS
: t8
= (int8_t)(TOS
== TOS1
); break;
1432 case COMP_IS_NOT
: t8
= (int8_t)(TOS
!= TOS1
);break;
1435 PM_RAISE(retval
, PM_RET_EX_TYPE
);
1439 /* Other compares are not yet supported */
1440 PM_RAISE(retval
, PM_RET_EX_SYS
);
1444 PM_BREAK_IF_ERROR(retval
);
1445 pobj3
= (t8
) ? PM_TRUE
: PM_FALSE
;
1448 /* Handle non-integer comparisons */
1456 /* Handle equality for non-int types */
1458 t8
= obj_compare(TOS
, TOS1
);
1459 if (((t8
== C_SAME
) && (t16
== COMP_EQ
))
1460 || ((t8
== C_DIFFER
) && (t16
== COMP_NE
)))
1468 /* Handle membership comparisons */
1470 retval
= obj_isIn(TOS
, TOS1
);
1471 if (retval
== PM_RET_OK
)
1478 else if (retval
== PM_RET_NO
)
1481 if (t16
== COMP_NOT_IN
)
1489 /* Other comparisons are not implemented */
1490 PM_RAISE(retval
, PM_RET_EX_SYS
);
1493 PM_BREAK_IF_ERROR(retval
);
1500 /* Get name index */
1503 /* Get name String obj */
1504 pobj1
= PM_FP
->fo_func
->f_co
->co_names
->val
[t16
];
1506 /* Pop unused None object */
1509 /* Ensure "level" is -1; no support for relative import yet */
1510 C_ASSERT(obj_compare(TOS
, PM_NEGONE
) == C_SAME
);
1512 /* #110: Prevent importing previously-loaded module */
1513 /* If the named module is in globals, put it on the stack */
1515 dict_getItem((pPmObj_t
)PM_FP
->fo_globals
, pobj1
, &pobj2
);
1516 if ((retval
== PM_RET_OK
)
1517 && (OBJ_GET_TYPE(pobj2
) == OBJ_TYPE_MOD
))
1523 /* Load module from image */
1524 retval
= mod_import(pobj1
, &pobj2
);
1525 PM_BREAK_IF_ERROR(retval
);
1527 /* Put Module on top of stack */
1530 /* Code after here is a duplicate of CALL_FUNCTION */
1531 /* Make frame object to interpret the module's root code */
1532 heap_gcPushTempRoot(pobj2
, &objid
);
1533 retval
= frame_new(pobj2
, &pobj3
);
1534 heap_gcPopTempRoot(objid
);
1535 PM_BREAK_IF_ERROR(retval
);
1537 /* No arguments to pass */
1539 /* Keep ref to current frame */
1540 ((pPmFrame_t
)pobj3
)->fo_back
= PM_FP
;
1542 /* Handle to have None popped on return */
1543 ((pPmFrame_t
)pobj3
)->fo_isImport
= (uint8_t)1;
1546 PM_FP
= (pPmFrame_t
)pobj3
;
1551 /* #102: Implement the remaining IMPORT_ bytecodes */
1552 /* Expect the module on the top of the stack */
1553 C_ASSERT(OBJ_GET_TYPE(TOS
) == OBJ_TYPE_MOD
);
1556 /* Get the name of the object to import */
1558 pobj2
= PM_FP
->fo_func
->f_co
->co_names
->val
[t16
];
1560 /* Get the object from the module's attributes */
1561 retval
= dict_getItem((pPmObj_t
)((pPmFunc_t
)pobj1
)->f_attrs
,
1563 PM_BREAK_IF_ERROR(retval
);
1565 /* Push the object onto the top of the stack */
1568 #endif /* HAVE_IMPORTS */
1577 if (obj_isFalse(TOS
))
1585 if (!obj_isFalse(TOS
))
1593 /* Get target offset (bytes) */
1596 /* Jump to base_ip + arg */
1597 PM_IP
= PM_FP
->fo_func
->f_co
->co_codeaddr
+ t16
;
1603 pobj1
= PM_FP
->fo_func
->f_co
->co_names
->val
[t16
];
1605 /* Try globals first */
1606 retval
= dict_getItem((pPmObj_t
)PM_FP
->fo_globals
,
1609 /* If that didn't work, try builtins */
1610 if (retval
== PM_RET_EX_KEY
)
1612 retval
= dict_getItem(PM_PBUILTINS
, pobj1
, &pobj2
);
1614 /* No such global, raise NameError */
1615 if (retval
== PM_RET_EX_KEY
)
1617 PM_RAISE(retval
, PM_RET_EX_NAME
);
1621 PM_BREAK_IF_ERROR(retval
);
1629 /* Get block span (bytes) */
1633 retval
= heap_getChunk(sizeof(PmBlock_t
), &pchunk
);
1634 PM_BREAK_IF_ERROR(retval
);
1635 pobj1
= (pPmObj_t
)pchunk
;
1636 OBJ_SET_TYPE(pobj1
, OBJ_TYPE_BLK
);
1638 /* Store current stack pointer */
1639 ((pPmBlock_t
)pobj1
)->b_sp
= PM_SP
;
1641 /* Default handler is to exit block/loop */
1642 ((pPmBlock_t
)pobj1
)->b_handler
= PM_IP
+ t16
;
1643 ((pPmBlock_t
)pobj1
)->b_type
= B_LOOP
;
1645 /* Insert block into blockstack */
1646 ((pPmBlock_t
)pobj1
)->next
= PM_FP
->fo_blockstack
;
1647 PM_FP
->fo_blockstack
= (pPmBlock_t
)pobj1
;
1653 PM_PUSH(PM_FP
->fo_locals
[t16
]);
1658 PM_FP
->fo_locals
[t16
] = PM_POP();
1664 PM_FP
->fo_locals
[t16
] = PM_NONE
;
1666 #endif /* HAVE_DEL */
1672 /* Only supports taking 1 arg for now */
1675 PM_RAISE(retval
, PM_RET_EX_SYS
);
1679 /* Load Exception class from builtins */
1680 retval
= dict_getItem(PM_PBUILTINS
, PM_EXCEPTION_STR
, &pobj2
);
1681 if (retval
!= PM_RET_OK
)
1683 PM_RAISE(retval
, PM_RET_EX_SYS
);
1687 /* Raise TypeError if TOS is not an instance of Exception */
1689 if ((OBJ_GET_TYPE(pobj1
) != OBJ_TYPE_CLO
)
1690 || !class_isSubclass(pobj1
, pobj2
))
1692 PM_RAISE(retval
, PM_RET_EX_TYPE
);
1696 /* Push the traceback, parameter and exception object */
1701 /* Get the exception's code attr */
1702 retval
= dict_getItem((pPmObj_t
)((pPmClass_t
)pobj1
)->cl_attrs
,
1703 PM_CODE_STR
, &pobj2
);
1704 PM_BREAK_IF_ERROR(retval
);
1706 /* Raise exception by breaking with retval set to code */
1707 PM_RAISE(retval
, (PmReturn_t
)(((pPmInt_t
)pobj2
)->val
& 0xFF));
1709 #endif /* HAVE_ASSERT */
1715 /* Ensure no keyword args */
1716 if ((t16
& (uint16_t)0xFF00) != 0)
1718 PM_RAISE(retval
, PM_RET_EX_SYS
);
1722 /* Get the callable */
1725 /* Useless push to get temp-roots stack level used in cleanup */
1726 heap_gcPushTempRoot(pobj1
, &objid
);
1728 C_DEBUG_PRINT(VERBOSITY_LOW
,
1729 "interpret(), CALL_FUNCTION on <obj type=%d @ %p>\n",
1730 OBJ_GET_TYPE(pobj1
), pobj1
);
1732 #ifdef HAVE_GENERATORS
1733 /* If the callable is a generator function (can't be native) */
1734 if ((OBJ_GET_TYPE(pobj1
) == OBJ_TYPE_FXN
)
1735 && (OBJ_GET_TYPE(((pPmFunc_t
)pobj1
)->f_co
) == OBJ_TYPE_COB
)
1736 && (((pPmFunc_t
)pobj1
)->f_co
->co_flags
& CO_GENERATOR
))
1738 #ifdef HAVE_DEFAULTARGS
1739 /* Num required args := argcount - num default args */
1740 t8
= ((pPmFunc_t
)pobj1
)->f_co
->co_argcount
;
1741 if (((pPmFunc_t
)pobj1
)->f_defaultargs
!= C_NULL
)
1743 t8
-= ((pPmTuple_t
)((pPmFunc_t
)pobj1
)->f_defaultargs
)->
1748 * Raise a TypeError if num args passed
1749 * is more than allowed or less than required
1751 if (((t16
& ((uint8_t)0xFF))
1752 > ((pPmFunc_t
)pobj1
)->f_co
->co_argcount
)
1753 || ((t16
& ((uint8_t)0xFF)) < t8
))
1755 if ((t16
& ((uint8_t)0xFF)) !=
1756 ((pPmFunc_t
)pobj1
)->f_co
->co_argcount
)
1757 #endif /* HAVE_DEFAULTARGS */
1759 PM_RAISE(retval
, PM_RET_EX_TYPE
);
1763 /* Collect the function and arguments into a tuple */
1764 retval
= tuple_new(t16
+ 1, &pobj2
);
1765 heap_gcPushTempRoot(pobj2
, &objid2
);
1766 PM_GOTO_IF_ERROR(retval
, CALL_FUNC_CLEANUP
);
1767 sli_memcpy((uint8_t *)&((pPmTuple_t
)pobj2
)->val
,
1768 (uint8_t *)&STACK(t16
),
1769 (t16
+ 1) * sizeof(pPmObj_t
));
1771 /* Remove old args, push func/args tuple as one arg */
1776 /* Set pobj1 and stack to create an instance of Generator */
1777 retval
= dict_getItem(PM_PBUILTINS
, PM_GENERATOR_STR
,
1779 C_ASSERT(retval
== PM_RET_OK
);
1782 #endif /* HAVE_GENERATORS */
1785 /* If the callable is a class, create an instance of it */
1786 if (OBJ_GET_TYPE(pobj1
) == OBJ_TYPE_CLO
)
1788 /* This marks that the original callable was a class */
1791 /* Replace class with new instance */
1792 retval
= class_instantiate(pobj1
, &pobj2
);
1793 heap_gcPushTempRoot(pobj2
, &objid2
);
1796 /* If __init__ does not exist */
1798 retval
= class_getAttr(pobj1
, PM_INIT_STR
, &pobj3
);
1799 if (retval
== PM_RET_EX_KEY
)
1801 /* Raise TypeError if there are args */
1804 PM_RAISE(retval
, PM_RET_EX_TYPE
);
1805 goto CALL_FUNC_CLEANUP
;
1808 /* Otherwise, continue with instance */
1809 heap_gcPopTempRoot(objid
);
1812 else if (retval
!= PM_RET_OK
)
1814 PM_GOTO_IF_ERROR(retval
, CALL_FUNC_CLEANUP
);
1817 /* Slide the arguments up 1 slot in the stack */
1819 for (t8
= 0; t8
< t16
; t8
++)
1821 STACK(t8
) = STACK(t8
+ 1);
1824 /* Convert __init__ to method, insert it as the callable */
1825 retval
= class_method(pobj2
, pobj3
, &pobj1
);
1826 PM_GOTO_IF_ERROR(retval
, CALL_FUNC_CLEANUP
);
1827 heap_gcPushTempRoot(pobj2
, &objid2
);
1829 /* Fall through to call the method */
1832 if (OBJ_GET_TYPE(pobj1
) == OBJ_TYPE_MTH
)
1834 /* Set the method's func to be the callable */
1835 STACK(t16
) = (pPmObj_t
)((pPmMethod_t
)pobj1
)->m_func
;
1837 /* Slide the arguments up 1 slot in the stack */
1839 for (t8
= 0; t8
< t16
; t8
++)
1841 STACK(t8
) = STACK(t8
+ 1);
1844 /* Insert instance as "self" arg to the method */
1845 STACK(t16
++) = (pPmObj_t
)((pPmMethod_t
)pobj1
)->m_instance
;
1847 /* Refresh the callable */
1848 pobj1
= (pPmObj_t
)((pPmMethod_t
)pobj1
)->m_func
;
1850 #endif /* HAVE_CLASSES */
1852 #ifdef HAVE_GENERATORS
1854 #endif /* HAVE_GENERATORS */
1855 /* Raise a TypeError if object is not callable */
1856 if (OBJ_GET_TYPE(pobj1
) != OBJ_TYPE_FXN
)
1858 PM_RAISE(retval
, PM_RET_EX_TYPE
);
1859 goto CALL_FUNC_CLEANUP
;
1862 /* If it is a regular func (not native) */
1863 if (OBJ_GET_TYPE(((pPmFunc_t
)pobj1
)->f_co
) == OBJ_TYPE_COB
)
1866 * #132 Raise TypeError if num args does not match the
1867 * code object's expected argcount
1870 #ifdef HAVE_DEFAULTARGS
1871 /* Num required args := argcount - num default args */
1872 t8
= ((pPmFunc_t
)pobj1
)->f_co
->co_argcount
;
1873 if (((pPmFunc_t
)pobj1
)->f_defaultargs
!= C_NULL
)
1875 t8
-= ((pPmTuple_t
)((pPmFunc_t
)pobj1
)->f_defaultargs
)->
1880 * Raise a TypeError if num args passed
1881 * is more than allowed or less than required
1883 if (((t16
& ((uint8_t)0xFF))
1884 > ((pPmFunc_t
)pobj1
)->f_co
->co_argcount
)
1885 || ((t16
& ((uint8_t)0xFF)) < t8
))
1887 if ((t16
& ((uint8_t)0xFF)) !=
1888 ((pPmFunc_t
)pobj1
)->f_co
->co_argcount
)
1889 #endif /* HAVE_DEFAULTARGS */
1891 PM_RAISE(retval
, PM_RET_EX_TYPE
);
1895 /* Make frame object to run the func object */
1896 retval
= frame_new(pobj1
, &pobj2
);
1897 heap_gcPushTempRoot(pobj2
, &objid2
);
1898 PM_GOTO_IF_ERROR(retval
, CALL_FUNC_CLEANUP
);
1902 * If the original callable was a class, indicate that
1903 * the frame is running the initializer so that
1904 * its return object is checked for None and ignored.
1908 ((pPmFrame_t
)pobj2
)->fo_isInit
= C_TRUE
;
1910 #endif /* HAVE_CLASSES */
1912 #ifdef HAVE_DEFAULTARGS
1913 /* If this func has default arguments, put them in place */
1914 if (((pPmFunc_t
)pobj1
)->f_defaultargs
!= C_NULL
)
1918 /* Copy default args into the new frame's locals */
1919 for ( /* t8 set above */ ;
1920 t8
< ((pPmFunc_t
)pobj1
)->f_co
->co_argcount
; t8
++)
1922 ((pPmFrame_t
)pobj2
)->fo_locals
[t8
] =
1923 ((pPmTuple_t
)((pPmFunc_t
)pobj1
)->
1924 f_defaultargs
)->val
[i
++];
1927 #endif /* HAVE_DEFAULTARGS */
1929 /* Pass args to new frame */
1933 * Pop args from stack right to left,
1934 * since args are pushed left to right,
1936 ((pPmFrame_t
)pobj2
)->fo_locals
[t16
] = PM_POP();
1939 #ifdef HAVE_CLOSURES
1940 /* #256: Add support for closures */
1941 /* Copy arguments that become cellvars */
1942 if (((pPmFunc_t
)pobj1
)->f_co
->co_cellvars
!= C_NULL
)
1945 t8
< ((pPmFunc_t
)pobj1
)->f_co
->co_cellvars
->length
;
1948 if (((pPmInt_t
)((pPmFunc_t
)pobj1
)->
1949 f_co
->co_cellvars
->val
[t8
])->val
>= 0)
1951 ((pPmFrame_t
)pobj2
)->fo_locals
[
1952 ((pPmFunc_t
)pobj1
)->f_co
->co_nlocals
+ t8
] =
1953 ((pPmFrame_t
)pobj2
)->fo_locals
[
1954 ((pPmInt_t
)(((pPmFunc_t
)pobj1
)->
1955 f_co
->co_cellvars
->val
[t8
]))->val
1961 /* Fill frame's freevars with references from closure */
1963 t8
< ((pPmFunc_t
)pobj1
)->f_co
->co_nfreevars
;
1966 C_ASSERT(((pPmFunc_t
)pobj1
)->f_closure
!= C_NULL
);
1967 ((pPmFrame_t
)pobj2
)->fo_locals
[
1968 ((pPmFunc_t
)pobj1
)->f_co
->co_nlocals
1969 + ((((pPmFunc_t
)pobj1
)->f_co
->co_cellvars
== C_NULL
) ? 0 : ((pPmFunc_t
)pobj1
)->f_co
->co_cellvars
->length
)
1970 + t8
] = ((pPmFunc_t
)pobj1
)->f_closure
->val
[t8
];
1972 #endif /* HAVE_CLOSURES */
1977 /* Keep ref to current frame */
1978 ((pPmFrame_t
)pobj2
)->fo_back
= PM_FP
;
1981 PM_FP
= (pPmFrame_t
)pobj2
;
1984 /* If it's native func */
1985 else if (OBJ_GET_TYPE(((pPmFunc_t
)pobj1
)->f_co
) ==
1988 /* Set number of locals (arguments) */
1989 gVmGlobal
.nativeframe
.nf_numlocals
= (uint8_t)t16
;
1991 /* Pop args from stack */
1994 gVmGlobal
.nativeframe
.nf_locals
[t16
] = PM_POP();
1998 /* If the heap is low on memory, run the GC */
1999 if (heap_getAvail() < HEAP_GC_NF_THRESHOLD
)
2001 retval
= heap_gcRun();
2002 PM_GOTO_IF_ERROR(retval
, CALL_FUNC_CLEANUP
);
2004 #endif /* HAVE_GC */
2006 /* Pop the function object */
2009 /* Get native function index */
2010 pobj2
= (pPmObj_t
)((pPmFunc_t
)pobj1
)->f_co
;
2011 t16
= ((pPmNo_t
)pobj2
)->no_funcindx
;
2013 /* Set flag, so the GC knows a native session is active */
2014 gVmGlobal
.nativeframe
.nf_active
= C_TRUE
;
2017 * CALL NATIVE FXN: pass caller's frame and numargs
2019 /* Positive index is a stdlib func */
2022 retval
= std_nat_fxn_table
[t16
] (&PM_FP
);
2025 /* Negative index is a usrlib func */
2028 retval
= usr_nat_fxn_table
[-t16
] (&PM_FP
);
2032 * RETURN FROM NATIVE FXN
2035 /* Clear flag, so frame will not be marked by the GC */
2036 gVmGlobal
.nativeframe
.nf_active
= C_FALSE
;
2039 /* If class's __init__ called, do not push a return obj */
2042 /* Raise TypeError if returned obj was not None */
2043 if ((retval
== PM_RET_OK
)
2044 && (gVmGlobal
.nativeframe
.nf_stack
!= PM_NONE
))
2046 PM_RAISE(retval
, PM_RET_EX_TYPE
);
2047 goto CALL_FUNC_CLEANUP
;
2051 #endif /* HAVE_CLASSES */
2053 /* If the frame pointer was switched, do nothing to TOS */
2054 if (retval
== PM_RET_FRAME_SWITCH
)
2059 /* Otherwise, return the result from the native function */
2062 PM_PUSH(gVmGlobal
.nativeframe
.nf_stack
);
2066 heap_gcPopTempRoot(objid
);
2067 PM_BREAK_IF_ERROR(retval
);
2071 /* Get num default args to fxn */
2075 * The current frame's globals become the function object's
2076 * globals. The current frame is the container object
2077 * of this new function object
2079 retval
= func_new(TOS
, (pPmObj_t
)PM_FP
->fo_globals
, &pobj2
);
2080 PM_BREAK_IF_ERROR(retval
);
2082 /* Put any default args in a tuple */
2086 #ifdef HAVE_DEFAULTARGS
2087 heap_gcPushTempRoot(pobj2
, &objid
);
2088 retval
= tuple_new(t16
, &pobj3
);
2089 heap_gcPopTempRoot(objid
);
2090 PM_BREAK_IF_ERROR(retval
);
2094 ((pPmTuple_t
)pobj3
)->val
[t16
] = PM_POP();
2097 /* Set func's default args */
2098 ((pPmFunc_t
)pobj2
)->f_defaultargs
= (pPmTuple_t
)pobj3
;
2100 /* Default arguments not configured in pmfeatures.h */
2101 PM_RAISE(retval
, PM_RET_EX_SYS
);
2103 #endif /* HAVE_DEFAULTARGS */
2115 #ifdef HAVE_CLOSURES
2117 /* Get number of default args */
2119 retval
= func_new(TOS
, (pPmObj_t
)PM_FP
->fo_globals
, &pobj2
);
2120 PM_BREAK_IF_ERROR(retval
);
2122 /* Set closure of the new function */
2123 ((pPmFunc_t
)pobj2
)->f_closure
= (pPmTuple_t
)TOS1
;
2126 /* Collect any default arguments into tuple */
2129 heap_gcPushTempRoot(pobj2
, &objid
);
2130 retval
= tuple_new(t16
, &pobj3
);
2131 heap_gcPopTempRoot(objid
);
2132 PM_BREAK_IF_ERROR(retval
);
2136 ((pPmTuple_t
)pobj3
)->val
[t16
] = PM_POP();
2138 ((pPmFunc_t
)pobj2
)->f_defaultargs
= (pPmTuple_t
)pobj3
;
2141 /* Push new func with closure */
2147 /* Loads the i'th cell of free variable storage onto TOS */
2149 pobj1
= PM_FP
->fo_locals
[PM_FP
->fo_func
->f_co
->co_nlocals
+ t16
];
2150 if (pobj1
== C_NULL
)
2152 PM_RAISE(retval
, PM_RET_EX_SYS
);
2159 /* Stores TOS into the i'th cell of free variable storage */
2161 PM_FP
->fo_locals
[PM_FP
->fo_func
->f_co
->co_nlocals
+ t16
] = PM_POP();
2163 #endif /* HAVE_CLOSURES */
2167 /* SystemError, unknown or unimplemented opcode */
2168 PM_RAISE(retval
, PM_RET_EX_SYS
);
2172 #ifdef HAVE_GENERATORS
2173 /* If got a StopIteration exception, check for a B_LOOP block */
2174 if (retval
== PM_RET_EX_STOP
)
2176 pobj1
= (pPmObj_t
)PM_FP
;
2177 while ((retval
== PM_RET_EX_STOP
) && (pobj1
!= C_NULL
))
2179 pobj2
= (pPmObj_t
)((pPmFrame_t
)pobj1
)->fo_blockstack
;
2180 while ((retval
== PM_RET_EX_STOP
) && (pobj2
!= C_NULL
))
2182 if (((pPmBlock_t
)pobj2
)->b_type
== B_LOOP
)
2184 /* Resume execution where the block handler says */
2185 /* Set PM_FP first, so PM_SP and PM_IP are set in the frame */
2186 PM_FP
= (pPmFrame_t
)pobj1
;
2187 PM_SP
= ((pPmBlock_t
)pobj2
)->b_sp
;
2188 PM_IP
= ((pPmBlock_t
)pobj2
)->b_handler
;
2189 ((pPmFrame_t
)pobj1
)->fo_blockstack
=
2190 ((pPmFrame_t
)pobj1
)->fo_blockstack
->next
;
2195 pobj2
= (pPmObj_t
)((pPmBlock_t
)pobj2
)->next
;
2197 pobj1
= (pPmObj_t
)((pPmFrame_t
)pobj1
)->fo_back
;
2199 if (retval
== PM_RET_OK
)
2204 #endif /* HAVE_GENERATORS */
2207 * If execution reaches this point, it is because
2208 * a return value (from above) is not OK or we should exit the thread
2209 * (return of the function). In any case, remove the
2210 * current thread and reschedule.
2212 PM_REPORT_IF_ERROR(retval
);
2214 /* If this is the last thread, return the error code */
2215 if ((gVmGlobal
.threadList
->length
<= 1) && (retval
!= PM_RET_OK
))
2220 retval
= list_remove((pPmObj_t
)gVmGlobal
.threadList
,
2221 (pPmObj_t
)gVmGlobal
.pthread
);
2222 gVmGlobal
.pthread
= C_NULL
;
2223 PM_BREAK_IF_ERROR(retval
);
2225 retval
= interp_reschedule();
2226 PM_BREAK_IF_ERROR(retval
);
2234 interp_reschedule(void)
2236 PmReturn_t retval
= PM_RET_OK
;
2237 static uint8_t threadIndex
= (uint8_t)0;
2240 /* If there are no threads in the runnable list, null the active thread */
2241 if (gVmGlobal
.threadList
->length
== 0)
2243 gVmGlobal
.pthread
= C_NULL
;
2246 /* Otherwise, get the next thread in the list (round robin) */
2249 if (++threadIndex
>= gVmGlobal
.threadList
->length
)
2251 threadIndex
= (uint8_t)0;
2253 retval
= list_getItem((pPmObj_t
)gVmGlobal
.threadList
, threadIndex
,
2255 gVmGlobal
.pthread
= (pPmThread_t
)pobj
;
2256 PM_RETURN_IF_ERROR(retval
);
2259 /* Clear flag to indicate a reschedule has occurred */
2260 interp_setRescheduleFlag(0);
2266 interp_addThread(pPmFunc_t pfunc
)
2271 uint8_t objid1
, objid2
;
2273 /* Create a frame for the func */
2274 retval
= frame_new((pPmObj_t
)pfunc
, &pframe
);
2275 PM_RETURN_IF_ERROR(retval
);
2277 /* Create a thread with this new frame */
2278 heap_gcPushTempRoot(pframe
, &objid1
);
2279 retval
= thread_new(pframe
, &pthread
);
2280 if (retval
!= PM_RET_OK
)
2282 heap_gcPopTempRoot(objid1
);
2286 /* Add thread to end of list */
2287 heap_gcPushTempRoot(pthread
, &objid2
);
2288 retval
= list_append((pPmObj_t
)gVmGlobal
.threadList
, pthread
);
2289 heap_gcPopTempRoot(objid1
);
2295 interp_setRescheduleFlag(uint8_t boolean
)
2297 gVmGlobal
.reschedule
= boolean
;