davide carboni / Mbed 2 deprecated pymite_http_get

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers interp.c Source File

interp.c

Go to the documentation of this file.
00001 /*
00002 # This file is Copyright 2003, 2006, 2007, 2009 Dean Hall.
00003 #
00004 # This file is part of the PyMite VM.
00005 # The PyMite VM is free software: you can redistribute it and/or modify
00006 # it under the terms of the GNU GENERAL PUBLIC LICENSE Version 2.
00007 #
00008 # The PyMite VM is distributed in the hope that it will be useful,
00009 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00011 # A copy of the GNU GENERAL PUBLIC LICENSE Version 2
00012 # is seen in the file COPYING in this directory.
00013 */
00014 
00015 
00016 #undef __FILE_ID__
00017 #define __FILE_ID__ 0x09
00018 
00019 
00020 /**
00021  * \file
00022  * \brief VM Interpreter
00023  *
00024  * VM interpreter operations.
00025  */
00026 
00027 
00028 #include "pm.h"
00029 
00030 
00031 extern PmReturn_t (*std_nat_fxn_table[]) (pPmFrame_t *);
00032 extern PmReturn_t (*usr_nat_fxn_table[]) (pPmFrame_t *);
00033 
00034 
00035 PmReturn_t
00036 interpret(const uint8_t returnOnNoThreads)
00037 {
00038     PmReturn_t retval = PM_RET_OK;
00039     pPmObj_t pobj1 = C_NULL;
00040     pPmObj_t pobj2 = C_NULL;
00041     pPmObj_t pobj3 = C_NULL;
00042     int16_t t16 = 0;
00043     int8_t t8 = 0;
00044     uint8_t bc;
00045 
00046     /* Activate a thread the first time */
00047     retval = interp_reschedule();
00048     PM_RETURN_IF_ERROR(retval);
00049 
00050     /* Interpret loop */
00051     for (;;)
00052     {
00053         if (gVmGlobal.pthread == C_NULL)
00054         {
00055             if (returnOnNoThreads)
00056             {
00057                 /* User chose to return on no threads left */
00058                 return retval;
00059             }
00060 
00061             /*
00062              * Without a frame there is nothing to execute, so reschedule
00063              * (possibly activating a recently added thread).
00064              */
00065             retval = interp_reschedule();
00066             PM_BREAK_IF_ERROR(retval);
00067             continue;
00068         }
00069 
00070         /* Reschedule threads if flag is true? */
00071         if (gVmGlobal.reschedule)
00072         {
00073             retval = interp_reschedule();
00074             PM_BREAK_IF_ERROR(retval);
00075         }
00076 
00077         /* Get byte; the func post-incrs IP */
00078         bc = mem_getByte(MS, &IP);
00079         switch (bc)
00080         {
00081             case POP_TOP:
00082                 pobj1 = PM_POP();
00083                 continue;
00084 
00085             case ROT_TWO:
00086                 pobj1 = TOS;
00087                 TOS = TOS1;
00088                 TOS1 = pobj1;
00089                 continue;
00090 
00091             case ROT_THREE:
00092                 pobj1 = TOS;
00093                 TOS = TOS1;
00094                 TOS1 = TOS2;
00095                 TOS2 = pobj1;
00096                 continue;
00097 
00098             case DUP_TOP:
00099                 pobj1 = TOS;
00100                 PM_PUSH(pobj1);
00101                 continue;
00102 
00103             case ROT_FOUR:
00104                 pobj1 = TOS;
00105                 TOS = TOS1;
00106                 TOS1 = TOS2;
00107                 TOS2 = TOS3;
00108                 TOS3 = pobj1;
00109                 continue;
00110 
00111             case NOP:
00112                 continue;
00113 
00114             case UNARY_POSITIVE:
00115                 /* Raise TypeError if TOS is not an int */
00116                 if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
00117 #ifdef HAVE_FLOAT
00118                     && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_FLT)
00119 #endif /* HAVE_FLOAT */
00120                     )
00121                 {
00122                     PM_RAISE(retval, PM_RET_EX_TYPE);
00123                     break;
00124                 }
00125 
00126                 /* When TOS is an int, this is a no-op */
00127                 continue;
00128 
00129             case UNARY_NEGATIVE:
00130 #ifdef HAVE_FLOAT
00131                 if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
00132                 {
00133                     retval = float_negative(TOS, &pobj2);
00134                 }
00135                 else
00136 #endif /* HAVE_FLOAT */
00137                 {
00138                     retval = int_negative(TOS, &pobj2);
00139                 }
00140                 PM_BREAK_IF_ERROR(retval);
00141                 TOS = pobj2;
00142                 continue;
00143 
00144             case UNARY_NOT:
00145                 pobj1 = PM_POP();
00146                 if (obj_isFalse(pobj1))
00147                 {
00148                     PM_PUSH(PM_TRUE);
00149                 }
00150                 else
00151                 {
00152                     PM_PUSH(PM_FALSE);
00153                 }
00154                 continue;
00155 
00156 #ifdef HAVE_BACKTICK
00157             /* #244 Add support for the backtick operation (UNARY_CONVERT) */
00158             case UNARY_CONVERT:
00159                 retval = obj_repr(TOS, &pobj3);
00160                 PM_BREAK_IF_ERROR(retval);
00161                 TOS = pobj3;
00162                 continue;
00163 #endif /* HAVE_BACKTICK */
00164 
00165             case UNARY_INVERT:
00166                 /* Raise TypeError if it's not an int */
00167                 if (OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
00168                 {
00169                     PM_RAISE(retval, PM_RET_EX_TYPE);
00170                     break;
00171                 }
00172 
00173                 /* Otherwise perform bit-wise complement */
00174                 retval = int_bitInvert(TOS, &pobj2);
00175                 PM_BREAK_IF_ERROR(retval);
00176                 TOS = pobj2;
00177                 continue;
00178 
00179             case LIST_APPEND:
00180                 /* list_append will raise a TypeError if TOS1 is not a list */
00181                 retval = list_append(TOS1, TOS);
00182                 SP -= 2;
00183                 continue;
00184 
00185             case BINARY_POWER:
00186             case INPLACE_POWER:
00187 
00188 #ifdef HAVE_FLOAT
00189                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
00190                     || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
00191                 {
00192                     /* Calculate float power */
00193                     retval = float_op(TOS1, TOS, &pobj3, 'P');
00194                     PM_BREAK_IF_ERROR(retval);
00195                     SP--;
00196                     TOS = pobj3;
00197                     continue;
00198                 }
00199 #endif /* HAVE_FLOAT */
00200 
00201                 /* Calculate integer power */
00202                 retval = int_pow(TOS1, TOS, &pobj3);
00203                 PM_BREAK_IF_ERROR(retval);
00204 
00205                 /* Set return value */
00206                 SP--;
00207                 TOS = pobj3;
00208                 continue;
00209 
00210             case GET_ITER:
00211 #ifdef HAVE_GENERATORS
00212                 /* Raise TypeError if TOS is an instance, but not iterable */
00213                 if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
00214                 {
00215                     retval = class_getAttr(TOS, PM_NEXT_STR, &pobj1);
00216                     if (retval != PM_RET_OK)
00217                     {
00218                         PM_RAISE(retval, PM_RET_EX_TYPE);
00219                         break;
00220                     }
00221                 }
00222                 else
00223 #endif /* HAVE_GENERATORS */
00224                 {
00225                     /* Convert sequence to sequence-iterator */
00226                     retval = seqiter_new(TOS, &pobj1);
00227                     PM_BREAK_IF_ERROR(retval);
00228 
00229                     /* Put sequence-iterator on top of stack */
00230                     TOS = pobj1;
00231                 }
00232                 continue;
00233 
00234             case BINARY_MULTIPLY:
00235             case INPLACE_MULTIPLY:
00236                 /* If both objs are ints, perform the op */
00237                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00238                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00239                 {
00240                     retval = int_new(((pPmInt_t)TOS1)->val *
00241                                      ((pPmInt_t)TOS)->val, &pobj3);
00242                     PM_BREAK_IF_ERROR(retval);
00243                     SP--;
00244                     TOS = pobj3;
00245                     continue;
00246                 }
00247 
00248 #ifdef HAVE_FLOAT
00249                 else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
00250                          || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
00251                 {
00252                     retval = float_op(TOS1, TOS, &pobj3, '*');
00253                     PM_BREAK_IF_ERROR(retval);
00254                     SP--;
00255                     TOS = pobj3;
00256                     continue;
00257                 }
00258 #endif /* HAVE_FLOAT */
00259 
00260 #ifdef HAVE_REPLICATION
00261                 /* If it's a list replication operation */
00262                 else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00263                          && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST))
00264                 {
00265                     t16 = (int16_t)((pPmInt_t)TOS)->val;
00266                     if (t16 < 0)
00267                     {
00268                         t16 = 0;
00269                     }
00270 
00271                     retval = list_replicate(TOS1, t16, &pobj3);
00272                     PM_BREAK_IF_ERROR(retval);
00273                     SP--;
00274                     TOS = pobj3;
00275                     continue;
00276                 }
00277 
00278                 /* If it's a tuple replication operation */
00279                 else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00280                          && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_TUP))
00281                 {
00282                     t16 = (int16_t)((pPmInt_t)TOS)->val;
00283                     if (t16 < 0)
00284                     {
00285                         t16 = 0;
00286                     }
00287 
00288                     retval = tuple_replicate(TOS1, t16, &pobj3);
00289                     PM_BREAK_IF_ERROR(retval);
00290                     SP--;
00291                     TOS = pobj3;
00292                     continue;
00293                 }
00294 
00295                 /* If it's a string replication operation */
00296                 else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00297                          && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR))
00298                 {
00299                     t16 = (int16_t)((pPmInt_t)TOS)->val;
00300                     if (t16 < 0)
00301                     {
00302                         t16 = 0;
00303                     }
00304 
00305                     pobj2 = TOS1;
00306                     pobj2 = (pPmObj_t)&((pPmString_t)pobj2)->val;
00307                     retval = string_replicate(
00308                         (uint8_t const **)(uint8_t *)&pobj2, t16, &pobj3);
00309                     PM_BREAK_IF_ERROR(retval);
00310                     SP--;
00311                     TOS = pobj3;
00312                     continue;
00313                 }
00314 #endif /* HAVE_REPLICATION */
00315 
00316                 /* Otherwise raise a TypeError */
00317                 PM_RAISE(retval, PM_RET_EX_TYPE);
00318                 break;
00319 
00320             case BINARY_DIVIDE:
00321             case INPLACE_DIVIDE:
00322             case BINARY_FLOOR_DIVIDE:
00323             case INPLACE_FLOOR_DIVIDE:
00324 
00325 #ifdef HAVE_FLOAT
00326                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
00327                     || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
00328                 {
00329                     retval = float_op(TOS1, TOS, &pobj3, '/');
00330                     PM_BREAK_IF_ERROR(retval);
00331                     SP--;
00332                     TOS = pobj3;
00333                     continue;
00334                 }
00335 #endif /* HAVE_FLOAT */
00336 
00337                 /* Raise TypeError if args aren't ints */
00338                 if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
00339                     || (OBJ_GET_TYPE(TOS1) != OBJ_TYPE_INT))
00340                 {
00341                     PM_RAISE(retval, PM_RET_EX_TYPE);
00342                     break;
00343                 }
00344 
00345                 /* Raise ZeroDivisionError if denominator is zero */
00346                 if (((pPmInt_t)TOS)->val == 0)
00347                 {
00348                     PM_RAISE(retval, PM_RET_EX_ZDIV);
00349                     break;
00350                 }
00351 
00352                 /* Otherwise perform operation */
00353                 retval = int_new(((pPmInt_t)TOS1)->val /
00354                                  ((pPmInt_t)TOS)->val, &pobj3);
00355                 PM_BREAK_IF_ERROR(retval);
00356                 SP--;
00357                 TOS = pobj3;
00358                 continue;
00359 
00360             case BINARY_MODULO:
00361             case INPLACE_MODULO:
00362 
00363 #ifdef HAVE_STRING_FORMAT
00364                 /* If it's a string, perform string format */
00365                 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR)
00366                 {
00367                     retval = string_format((pPmString_t)TOS1, TOS, &pobj3);
00368                     PM_BREAK_IF_ERROR(retval);
00369                     SP--;
00370                     TOS = pobj3;
00371                     continue;
00372                 }
00373 #endif /* HAVE_STRING_FORMAT */
00374 
00375 #ifdef HAVE_FLOAT
00376                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
00377                     || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
00378                 {
00379                     retval = float_op(TOS1, TOS, &pobj3, '%');
00380                     PM_BREAK_IF_ERROR(retval);
00381                     SP--;
00382                     TOS = pobj3;
00383                     continue;
00384                 }
00385 #endif /* HAVE_FLOAT */
00386 
00387                 /* Raise TypeError if args aren't ints */
00388                 if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
00389                     || (OBJ_GET_TYPE(TOS1) != OBJ_TYPE_INT))
00390                 {
00391                     PM_RAISE(retval, PM_RET_EX_TYPE);
00392                     break;
00393                 }
00394 
00395                 /* Raise ZeroDivisionError if denominator is zero */
00396                 if (((pPmInt_t)TOS)->val == 0)
00397                 {
00398                     PM_RAISE(retval, PM_RET_EX_ZDIV);
00399                     break;
00400                 }
00401 
00402                 /* Otherwise perform operation */
00403                 retval = int_new(((pPmInt_t)TOS1)->val %
00404                                  ((pPmInt_t)TOS)->val, &pobj3);
00405                 PM_BREAK_IF_ERROR(retval);
00406                 SP--;
00407                 TOS = pobj3;
00408                 continue;
00409 
00410             case STORE_MAP:
00411                 /* #213: Add support for Python 2.6 bytecodes */
00412                 C_ASSERT(OBJ_GET_TYPE(TOS2) == OBJ_TYPE_DIC);
00413                 retval = dict_setItem(TOS2, TOS, TOS1);
00414                 PM_BREAK_IF_ERROR(retval);
00415                 SP -= 2;
00416                 continue;
00417 
00418             case BINARY_ADD:
00419             case INPLACE_ADD:
00420 
00421 #ifdef HAVE_FLOAT
00422                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
00423                     || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
00424                 {
00425                     retval = float_op(TOS1, TOS, &pobj3, '+');
00426                     PM_BREAK_IF_ERROR(retval);
00427                     SP--;
00428                     TOS = pobj3;
00429                     continue;
00430                 }
00431 #endif /* HAVE_FLOAT */
00432 
00433                 /* If both objs are ints, perform the op */
00434                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00435                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00436                 {
00437                     retval = int_new(((pPmInt_t)TOS1)->val +
00438                                      ((pPmInt_t)TOS)->val, &pobj3);
00439                     PM_BREAK_IF_ERROR(retval);
00440                     SP--;
00441                     TOS = pobj3;
00442                     continue;
00443                 }
00444 
00445                 /* #242: If both objs are strings, perform concatenation */
00446                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_STR)
00447                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR))
00448                 {
00449                     retval = string_concat((pPmString_t)TOS1,
00450                                            (pPmString_t)TOS,
00451                                            &pobj3);
00452                     PM_BREAK_IF_ERROR(retval);
00453                     SP--;
00454                     TOS = pobj3;
00455                     continue;
00456                 }
00457 
00458                 /* Otherwise raise a TypeError */
00459                 PM_RAISE(retval, PM_RET_EX_TYPE);
00460                 break;
00461 
00462             case BINARY_SUBTRACT:
00463             case INPLACE_SUBTRACT:
00464 
00465 #ifdef HAVE_FLOAT
00466                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
00467                     || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
00468                 {
00469                     retval = float_op(TOS1, TOS, &pobj3, '-');
00470                     PM_BREAK_IF_ERROR(retval);
00471                     SP--;
00472                     TOS = pobj3;
00473                     continue;
00474                 }
00475 #endif /* HAVE_FLOAT */
00476 
00477                 /* If both objs are ints, perform the op */
00478                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00479                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00480                 {
00481                     retval = int_new(((pPmInt_t)TOS1)->val -
00482                                      ((pPmInt_t)TOS)->val, &pobj3);
00483                     PM_BREAK_IF_ERROR(retval);
00484                     SP--;
00485                     TOS = pobj3;
00486                     continue;
00487                 }
00488 
00489                 /* Otherwise raise a TypeError */
00490                 PM_RAISE(retval, PM_RET_EX_TYPE);
00491                 break;
00492 
00493             case BINARY_SUBSCR:
00494                 /* Implements TOS = TOS1[TOS]. */
00495 
00496                 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC)
00497                 {
00498                     retval = dict_getItem(TOS1, TOS, &pobj3);
00499                 }
00500                 else
00501                 {
00502                     /* Raise a TypeError if index is not an Integer or Bool */
00503                     if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
00504                         && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL))
00505                     {
00506                         PM_RAISE(retval, PM_RET_EX_TYPE);
00507                         break;
00508                     }
00509 
00510                     pobj1 = TOS1;
00511 #ifdef HAVE_BYTEARRAY
00512                     /* If object is an instance, get the thing it contains */
00513                     if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLI)
00514                     {
00515                         retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj1)->cli_attrs,
00516                                               PM_NONE,
00517                                               &pobj2);
00518                         PM_RETURN_IF_ERROR(retval);
00519                         pobj1 = pobj2;
00520                     }
00521 #endif /* HAVE_BYTEARRAY */
00522 
00523                     /* Ensure the index doesn't overflow */
00524                     C_ASSERT(((pPmInt_t)TOS)->val <= 0x0000FFFF);
00525                     t16 = (int16_t)((pPmInt_t)TOS)->val;
00526 
00527                     retval = seq_getSubscript(pobj1, t16, &pobj3);
00528                 }
00529                 PM_BREAK_IF_ERROR(retval);
00530                 SP--;
00531                 TOS = pobj3;
00532                 continue;
00533 
00534 #ifdef HAVE_FLOAT
00535             /* #213: Add support for Python 2.6 bytecodes */
00536             case BINARY_TRUE_DIVIDE:
00537             case INPLACE_TRUE_DIVIDE:
00538 
00539                 /* Perform division; float_op() checks for types and zero-div */
00540                 retval = float_op(TOS1, TOS, &pobj3, '/');
00541                 PM_BREAK_IF_ERROR(retval);
00542                 SP--;
00543                 TOS = pobj3;
00544                 continue;
00545 #endif /* HAVE_FLOAT */
00546 
00547             case SLICE_0:
00548                 /* Implements TOS = TOS[:], push a copy of the sequence */
00549 
00550                 /* Create a copy if it is a list */
00551                 if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_LST)
00552                 {
00553                     retval = list_copy(TOS, &pobj2);
00554                     PM_BREAK_IF_ERROR(retval);
00555 
00556                     TOS = pobj2;
00557                 }
00558 
00559                 /* If TOS is an immutable sequence leave it (no op) */
00560 
00561                 /* Raise a TypeError for types that can not be sliced */
00562                 else if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_STR)
00563                          && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_TUP))
00564                 {
00565                     PM_RAISE(retval, PM_RET_EX_TYPE);
00566                     break;
00567                 }
00568                 continue;
00569 
00570             case STORE_SUBSCR:
00571                 /* Implements TOS1[TOS] = TOS2 */
00572 
00573                 /* If it's a list */
00574                 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST)
00575                 {
00576                     /* Ensure subscr is an int or bool */
00577                     if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
00578                         && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL))
00579                     {
00580                         PM_RAISE(retval, PM_RET_EX_TYPE);
00581                         break;
00582                     }
00583 
00584                     /* Set the list item */
00585                     retval = list_setItem(TOS1,
00586                                           (int16_t)(((pPmInt_t)TOS)->val),
00587                                           TOS2);
00588                     PM_BREAK_IF_ERROR(retval);
00589                     SP -= 3;
00590                     continue;
00591                 }
00592 
00593                 /* If it's a dict */
00594                 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC)
00595                 {
00596                     /* Set the dict item */
00597                     retval = dict_setItem(TOS1, TOS, TOS2);
00598                     PM_BREAK_IF_ERROR(retval);
00599                     SP -= 3;
00600                     continue;
00601                 }
00602 
00603 #ifdef HAVE_BYTEARRAY
00604                 /* If object is an instance, get the thing it contains */
00605                 if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_CLI)
00606                 {
00607                     retval = dict_getItem((pPmObj_t)((pPmInstance_t)TOS1)->cli_attrs,
00608                                           PM_NONE,
00609                                           &pobj2);
00610 
00611                     /* Raise TypeError if instance isn't a ByteArray */
00612                     if ((retval == PM_RET_EX_KEY) 
00613                         || (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_BYA))
00614                     {
00615                         PM_RAISE(retval, PM_RET_EX_TYPE);
00616                         break;
00617                     }
00618                     PM_BREAK_IF_ERROR(retval);
00619 
00620                     /* Ensure subscr is an int or bool */
00621                     if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT)
00622                         && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL))
00623                     {
00624                         PM_RAISE(retval, PM_RET_EX_TYPE);
00625                         break;
00626                     }
00627 
00628                     retval = bytearray_setItem(pobj2,
00629                                                (int16_t)(((pPmInt_t)TOS)->val),
00630                                                TOS2);
00631                     PM_BREAK_IF_ERROR(retval);
00632                     SP -= 3;
00633                     continue;
00634                 }
00635 #endif /* HAVE_BYTEARRAY */
00636 
00637                 /* TypeError for all else */
00638                 PM_RAISE(retval, PM_RET_EX_TYPE);
00639                 break;
00640 
00641 #ifdef HAVE_DEL
00642             case DELETE_SUBSCR:
00643 
00644                 if ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST)
00645                     && (OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT))
00646                 {
00647                     retval = list_delItem(TOS1,
00648                                           (int16_t)((pPmInt_t)TOS)->val);
00649                 }
00650 
00651                 else if ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC)
00652                          && (OBJ_GET_TYPE(TOS) <= OBJ_TYPE_HASHABLE_MAX))
00653                 {
00654                     retval = dict_delItem(TOS1, TOS);
00655                 }
00656 
00657                 /* Raise TypeError if obj is not a list or dict */
00658                 else
00659                 {
00660                     PM_RAISE(retval, PM_RET_EX_TYPE);
00661                 }
00662 
00663                 PM_BREAK_IF_ERROR(retval);
00664                 SP -= 2;
00665                 continue;
00666 #endif /* HAVE_DEL */
00667 
00668             case BINARY_LSHIFT:
00669             case INPLACE_LSHIFT:
00670                 /* If both objs are ints, perform the op */
00671                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00672                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00673                 {
00674                     retval = int_new(((pPmInt_t)TOS1)->val <<
00675                                      ((pPmInt_t)TOS)->val, &pobj3);
00676                     PM_BREAK_IF_ERROR(retval);
00677                     SP--;
00678                     TOS = pobj3;
00679                     continue;
00680                 }
00681 
00682                 /* Otherwise raise a TypeError */
00683                 PM_RAISE(retval, PM_RET_EX_TYPE);
00684                 break;
00685 
00686             case BINARY_RSHIFT:
00687             case INPLACE_RSHIFT:
00688                 /* If both objs are ints, perform the op */
00689                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00690                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00691                 {
00692                     retval = int_new(((pPmInt_t)TOS1)->val >>
00693                                      ((pPmInt_t)TOS)->val, &pobj3);
00694                     PM_BREAK_IF_ERROR(retval);
00695                     SP--;
00696                     TOS = pobj3;
00697                     continue;
00698                 }
00699 
00700                 /* Otherwise raise a TypeError */
00701                 PM_RAISE(retval, PM_RET_EX_TYPE);
00702                 break;
00703 
00704             case BINARY_AND:
00705             case INPLACE_AND:
00706                 /* If both objs are ints, perform the op */
00707                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00708                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00709                 {
00710                     retval = int_new(((pPmInt_t)TOS1)->val &
00711                                      ((pPmInt_t)TOS)->val, &pobj3);
00712                     PM_BREAK_IF_ERROR(retval);
00713                     SP--;
00714                     TOS = pobj3;
00715                     continue;
00716                 }
00717 
00718                 /* Otherwise raise a TypeError */
00719                 PM_RAISE(retval, PM_RET_EX_TYPE);
00720                 break;
00721 
00722             case BINARY_XOR:
00723             case INPLACE_XOR:
00724                 /* If both objs are ints, perform the op */
00725                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00726                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00727                 {
00728                     retval = int_new(((pPmInt_t)TOS1)->val ^
00729                                      ((pPmInt_t)TOS)->val, &pobj3);
00730                     PM_BREAK_IF_ERROR(retval);
00731                     SP--;
00732                     TOS = pobj3;
00733                     continue;
00734                 }
00735 
00736                 /* Otherwise raise a TypeError */
00737                 PM_RAISE(retval, PM_RET_EX_TYPE);
00738                 break;
00739 
00740             case BINARY_OR:
00741             case INPLACE_OR:
00742                 /* If both objs are ints, perform the op */
00743                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
00744                     && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT))
00745                 {
00746                     retval = int_new(((pPmInt_t)TOS1)->val |
00747                                      ((pPmInt_t)TOS)->val, &pobj3);
00748                     PM_BREAK_IF_ERROR(retval);
00749                     SP--;
00750                     TOS = pobj3;
00751                     continue;
00752                 }
00753 
00754                 /* Otherwise raise a TypeError */
00755                 PM_RAISE(retval, PM_RET_EX_TYPE);
00756                 break;
00757 
00758 #ifdef HAVE_PRINT
00759             case PRINT_EXPR:
00760                 /* Print interactive expression */
00761                 /* Fallthrough */
00762 
00763             case PRINT_ITEM:
00764                 /* Print out topmost stack element */
00765                 retval = obj_print(TOS, (uint8_t)0);
00766                 PM_BREAK_IF_ERROR(retval);
00767                 SP--;
00768                 if (bc != PRINT_EXPR)
00769                 {
00770                     retval = plat_putByte(' ');
00771                     PM_BREAK_IF_ERROR(retval);
00772                     continue;
00773                 }
00774                 /* If PRINT_EXPR, Fallthrough to print a newline */
00775 
00776             case PRINT_NEWLINE:
00777                 retval = plat_putByte('\n');
00778                 PM_BREAK_IF_ERROR(retval);
00779                 continue;
00780 #endif /* HAVE_PRINT */
00781 
00782             case BREAK_LOOP:
00783             {
00784                 pPmBlock_t pb1 = FP->fo_blockstack;
00785 
00786                 /* Ensure there's a block */
00787                 C_ASSERT(pb1 != C_NULL);
00788 
00789                 /* Delete blocks until first loop block */
00790                 while ((pb1->b_type != B_LOOP) && (pb1->next != C_NULL))
00791                 {
00792                     pobj2 = (pPmObj_t)pb1;
00793                     pb1 = pb1->next;
00794                     retval = heap_freeChunk(pobj2);
00795                     PM_BREAK_IF_ERROR(retval);
00796                 }
00797 
00798                 /* Test again outside while loop */
00799                 PM_BREAK_IF_ERROR(retval);
00800 
00801                 /* Restore SP */
00802                 SP = pb1->b_sp;
00803 
00804                 /* Goto handler */
00805                 IP = pb1->b_handler;
00806 
00807                 /* Pop and delete this block */
00808                 FP->fo_blockstack = pb1->next;
00809                 retval = heap_freeChunk((pPmObj_t)pb1);
00810                 PM_BREAK_IF_ERROR(retval);
00811             }
00812                 continue;
00813 
00814             case LOAD_LOCALS:
00815                 /* Pushes local attrs dict of current frame */
00816                 /* WARNING: does not copy fo_locals to attrs */
00817                 PM_PUSH((pPmObj_t)FP->fo_attrs);
00818                 continue;
00819 
00820             case RETURN_VALUE:
00821                 /* Get expiring frame's TOS */
00822                 pobj2 = PM_POP();
00823 
00824 #if 0 /*__DEBUG__*/
00825                 /* #251: This safety check is disabled because it breaks ipm */
00826                 /* #109: Check that stack should now be empty */
00827                 /* If this is regular frame (not native and not a generator) */
00828                 if ((FP != (pPmFrame_t)(&gVmGlobal.nativeframe)) &&
00829                     !(FP->fo_func->f_co->co_flags & CO_GENERATOR))
00830                 {
00831                     /* Get this func's number of locals */
00832                     pobj3 = (pPmObj_t)(((uint8_t *)
00833                             (FP->fo_func->f_co->co_codeimgaddr))
00834                             + CI_NLOCALS_FIELD);
00835                     t8 = mem_getByte(FP->fo_func->f_co->co_memspace,
00836                                      (uint8_t const **)&pobj3);
00837 
00838                     /* An empty stack points one past end of locals */
00839                     C_ASSERT(SP == &(FP->fo_locals[t8]));
00840                 }
00841 #endif /* __DEBUG__ */
00842 
00843                 /* Keep ref of expiring frame */
00844                 pobj1 = (pPmObj_t)FP;
00845                 C_ASSERT(OBJ_GET_TYPE(pobj1) == OBJ_TYPE_FRM);
00846 
00847                 /* If no previous frame, quit thread */
00848                 if (FP->fo_back == C_NULL)
00849                 {
00850                     gVmGlobal.pthread->interpctrl = INTERP_CTRL_EXIT;
00851                     retval = PM_RET_OK;
00852                     break;
00853                 }
00854 
00855                 /* Otherwise return to previous frame */
00856                 FP = FP->fo_back;
00857 
00858 #ifdef HAVE_GENERATORS
00859                 /* If returning function was a generator */
00860                 if (((pPmFrame_t)pobj1)->fo_func->f_co->co_flags & CO_GENERATOR)
00861                 {
00862                     /* If a loop handler is in-place, use it and pop it */
00863                     if ((FP->fo_blockstack != C_NULL)
00864                         && (FP->fo_blockstack->b_type == B_LOOP))
00865                     {
00866                         SP = ((pPmBlock_t)pobj1)->b_sp;
00867                         IP = ((pPmBlock_t)pobj1)->b_handler;
00868                         FP->fo_blockstack = FP->fo_blockstack->next;
00869                     }
00870 
00871                     /* Otherwise, raise a StopIteration exception */
00872                     else
00873                     {
00874                         PM_RAISE(retval, PM_RET_EX_STOP);
00875                         break;
00876                     }
00877                 }
00878                 PM_BREAK_IF_ERROR(retval);
00879 #endif /* HAVE_GENERATORS */
00880 
00881 #ifdef HAVE_CLASSES
00882                 /*
00883                  * If returning function was class initializer
00884                  * do not push a return object
00885                  */
00886                 if (((pPmFrame_t)pobj1)->fo_isInit)
00887                 {
00888                     /* Raise TypeError if __init__ did not return None */
00889                     if (pobj2 != PM_NONE)
00890                     {
00891                         PM_RAISE(retval, PM_RET_EX_TYPE);
00892                         break;
00893                     }
00894                 }
00895                 else
00896 #endif /* HAVE_CLASSES */
00897 
00898                 /*
00899                  * Push frame's return val, except if the expiring frame
00900                  * was due to an import statement
00901                  */
00902                 if (!(((pPmFrame_t)pobj1)->fo_isImport))
00903                 {
00904                     PM_PUSH(pobj2);
00905                 }
00906 
00907                 /* Deallocate expired frame */
00908                 PM_BREAK_IF_ERROR(heap_freeChunk(pobj1));
00909                 continue;
00910 
00911 #ifdef HAVE_IMPORTS
00912             case IMPORT_STAR:
00913                 /* #102: Implement the remaining IMPORT_ bytecodes */
00914                 /* Expect a module on the top of the stack */
00915                 C_ASSERT(OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD);
00916 
00917                 /* Update FP's attrs with those of the module on the stack */
00918                 retval = dict_update((pPmObj_t)FP->fo_attrs,
00919                                      (pPmObj_t)((pPmFunc_t)TOS)->f_attrs);
00920                 PM_BREAK_IF_ERROR(retval);
00921                 SP--;
00922                 continue;
00923 #endif /* HAVE_IMPORTS */
00924 
00925 #ifdef HAVE_GENERATORS
00926             case YIELD_VALUE:
00927                 /* #207: Add support for the yield keyword */
00928                 /* Get expiring frame's TOS */
00929                 pobj1 = PM_POP();
00930 
00931                 /* Raise TypeError if __init__ did not return None */
00932                 /* (Yield means this is a generator) */
00933                 if ((FP)->fo_isInit)
00934                 {
00935                     PM_RAISE(retval, PM_RET_EX_TYPE);
00936                     break;
00937                 }
00938 
00939                 /* Return to previous frame */
00940                 FP = FP->fo_back;
00941 
00942                 /* Push yield value onto caller's TOS */
00943                 PM_PUSH(pobj1);
00944                 continue;
00945 #endif /* HAVE_GENERATORS */
00946 
00947             case POP_BLOCK:
00948                 /* Get ptr to top block */
00949                 pobj1 = (pPmObj_t)FP->fo_blockstack;
00950 
00951                 /* If there's no block, raise SystemError */
00952                 C_ASSERT(pobj1 != C_NULL);
00953 
00954                 /* Pop block */
00955                 FP->fo_blockstack = FP->fo_blockstack->next;
00956 
00957                 /* Set stack to previous level, jump to code outside block */
00958                 SP = ((pPmBlock_t)pobj1)->b_sp;
00959                 IP = ((pPmBlock_t)pobj1)->b_handler;
00960 
00961                 PM_BREAK_IF_ERROR(heap_freeChunk(pobj1));
00962                 continue;
00963 
00964 #ifdef HAVE_CLASSES
00965             case BUILD_CLASS:
00966                 /* Create and push new class */
00967                 retval = class_new(TOS, TOS1, TOS2, &pobj2);
00968                 PM_BREAK_IF_ERROR(retval);
00969                 SP -= 2;
00970                 TOS = pobj2;
00971                 continue;
00972 #endif /* HAVE_CLASSES */
00973 
00974 
00975             /***************************************************
00976              * All bytecodes after 90 (0x5A) have a 2-byte arg
00977              * that needs to be swallowed using GET_ARG().
00978              **************************************************/
00979 
00980             case STORE_NAME:
00981                 /* Get name index */
00982                 t16 = GET_ARG();
00983 
00984                 /* Get key */
00985                 pobj2 = FP->fo_func->f_co->co_names->val[t16];
00986 
00987                 /* Set key=val in current frame's attrs dict */
00988                 retval = dict_setItem((pPmObj_t)FP->fo_attrs, pobj2, TOS);
00989                 PM_BREAK_IF_ERROR(retval);
00990                 SP--;
00991                 continue;
00992 
00993 #ifdef HAVE_DEL
00994             case DELETE_NAME:
00995                 /* Get name index */
00996                 t16 = GET_ARG();
00997 
00998                 /* Get key */
00999                 pobj2 = FP->fo_func->f_co->co_names->val[t16];
01000 
01001                 /* Remove key,val pair from current frame's attrs dict */
01002                 retval = dict_delItem((pPmObj_t)FP->fo_attrs, pobj2);
01003                 PM_BREAK_IF_ERROR(retval);
01004                 continue;
01005 #endif /* HAVE_DEL */
01006 
01007             case UNPACK_SEQUENCE:
01008                 /* Get ptr to sequence */
01009                 pobj1 = PM_POP();
01010 
01011 #ifdef HAVE_BYTEARRAY
01012                 /* If object is an instance, get the thing it contains */
01013                 if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLI)
01014                 {
01015                     retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj1)->cli_attrs,
01016                                           PM_NONE,
01017                                           &pobj2);
01018                     PM_RETURN_IF_ERROR(retval);
01019                     pobj1 = pobj2;
01020                 }
01021 #endif /* HAVE_BYTEARRAY */
01022 
01023                 /*
01024                  * Get the length of the sequence; this will
01025                  * raise TypeError if obj is not a sequence.
01026                  *
01027                  * #59: Unpacking to a Dict shall not be supported
01028                  */
01029                 retval = seq_getLength(pobj1, &t16);
01030                 if (retval != PM_RET_OK)
01031                 {
01032                     GET_ARG();
01033                     break;
01034                 }
01035 
01036                 /* Raise ValueError if seq length does not match num args */
01037                 if (t16 != GET_ARG())
01038                 {
01039                     PM_RAISE(retval, PM_RET_EX_VAL);
01040                     break;
01041                 }
01042 
01043                 /* Push sequence's objs onto stack */
01044                 for (; --t16 >= 0;)
01045                 {
01046                     retval = seq_getSubscript(pobj1, t16, &pobj2);
01047                     PM_BREAK_IF_ERROR(retval);
01048                     PM_PUSH(pobj2);
01049                 }
01050 
01051                 /* Test again outside the for loop */
01052                 PM_BREAK_IF_ERROR(retval);
01053                 continue;
01054 
01055             case FOR_ITER:
01056                 t16 = GET_ARG();
01057 
01058 #ifdef HAVE_GENERATORS
01059                 /* If TOS is an instance, call next method */
01060                 if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
01061                 {
01062                     /* Get the next() func */
01063                     retval = class_getAttr(TOS, PM_NEXT_STR, &pobj1);
01064                     PM_BREAK_IF_ERROR(retval);
01065 
01066                     /* Push the func and instance as an arg */
01067                     pobj2 = TOS;
01068                     PM_PUSH(pobj1);
01069                     PM_PUSH(pobj2);
01070                     t16 = 1;
01071 
01072                     /* Ensure pobj1 is the func */
01073                     goto CALL_FUNC_FOR_ITER;
01074                 }
01075                 else
01076 #endif /* HAVE_GENERATORS */
01077                 {
01078                     /* Get the next item in the sequence iterator */
01079                     retval = seqiter_getNext(TOS, &pobj2);
01080                 }
01081 
01082                 /* Catch StopIteration early: pop iterator and break loop */
01083                 if (retval == PM_RET_EX_STOP)
01084                 {
01085                     SP--;
01086                     retval = PM_RET_OK;
01087                     IP += t16;
01088                     continue;
01089                 }
01090                 PM_BREAK_IF_ERROR(retval);
01091 
01092                 /* Push the next item onto the stack */
01093                 PM_PUSH(pobj2);
01094                 continue;
01095 
01096             case STORE_ATTR:
01097                 /* TOS.name = TOS1 */
01098                 /* Get names index */
01099                 t16 = GET_ARG();
01100 
01101                 /* Get attrs dict from obj */
01102                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN)
01103                     || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD))
01104                 {
01105                     pobj2 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs;
01106                 }
01107 
01108 #ifdef HAVE_CLASSES
01109                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
01110                 {
01111                     pobj2 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs;
01112                 }
01113                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
01114                 {
01115                     pobj2 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs;
01116                 }
01117                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH)
01118                 {
01119                     pobj2 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs;
01120                 }
01121 #endif /* HAVE_CLASSES */
01122 
01123                 /* Other types result in an AttributeError */
01124                 else
01125                 {
01126                     PM_RAISE(retval, PM_RET_EX_ATTR);
01127                     break;
01128                 }
01129 
01130                 /* If attrs is not a dict, raise SystemError */
01131                 if (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_DIC)
01132                 {
01133                     PM_RAISE(retval, PM_RET_EX_SYS);
01134                     break;
01135                 }
01136 
01137                 /* Get name/key obj */
01138                 pobj3 = FP->fo_func->f_co->co_names->val[t16];
01139 
01140                 /* Set key=val in obj's dict */
01141                 retval = dict_setItem(pobj2, pobj3, TOS1);
01142                 PM_BREAK_IF_ERROR(retval);
01143                 SP -= 2;
01144                 continue;
01145 
01146 #ifdef HAVE_DEL
01147             case DELETE_ATTR:
01148                 /* del TOS.name */
01149                 /* Get names index */
01150                 t16 = GET_ARG();
01151 
01152                 /* Get attrs dict from obj */
01153                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN)
01154                     || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD))
01155                 {
01156                     pobj2 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs;
01157                 }
01158 
01159 #ifdef HAVE_CLASSES
01160                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
01161                 {
01162                     pobj2 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs;
01163                 }
01164                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
01165                 {
01166                     pobj2 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs;
01167                 }
01168                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH)
01169                 {
01170                     pobj2 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs;
01171                 }
01172 #endif /* HAVE_CLASSES */
01173 
01174                 /* Other types result in an AttributeError */
01175                 else
01176                 {
01177                     PM_RAISE(retval, PM_RET_EX_ATTR);
01178                     break;
01179                 }
01180 
01181                 /* If attrs is not a dict, raise SystemError */
01182                 if (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_DIC)
01183                 {
01184                     PM_RAISE(retval, PM_RET_EX_SYS);
01185                     break;
01186                 }
01187 
01188                 /* Get name/key obj */
01189                 pobj3 = FP->fo_func->f_co->co_names->val[t16];
01190 
01191                 /* Remove key,val from obj's dict */
01192                 retval = dict_delItem(pobj2, pobj3);
01193 
01194                 /* Raise an AttributeError if key is not found */
01195                 if (retval == PM_RET_EX_KEY)
01196                 {
01197                     PM_RAISE(retval, PM_RET_EX_ATTR);
01198                 }
01199 
01200                 PM_BREAK_IF_ERROR(retval);
01201                 SP--;
01202                 continue;
01203 #endif /* HAVE_DEL */
01204 
01205             case STORE_GLOBAL:
01206                 /* Get name index */
01207                 t16 = GET_ARG();
01208 
01209                 /* Get key */
01210                 pobj2 = FP->fo_func->f_co->co_names->val[t16];
01211 
01212                 /* Set key=val in global dict */
01213                 retval = dict_setItem((pPmObj_t)FP->fo_globals, pobj2, TOS);
01214                 PM_BREAK_IF_ERROR(retval);
01215                 SP--;
01216                 continue;
01217 
01218 #ifdef HAVE_DEL
01219             case DELETE_GLOBAL:
01220                 /* Get name index */
01221                 t16 = GET_ARG();
01222 
01223                 /* Get key */
01224                 pobj2 = FP->fo_func->f_co->co_names->val[t16];
01225 
01226                 /* Remove key,val from globals */
01227                 retval = dict_delItem((pPmObj_t)FP->fo_globals, pobj2);
01228                 PM_BREAK_IF_ERROR(retval);
01229                 continue;
01230 #endif /* HAVE_DEL */
01231 
01232             case DUP_TOPX:
01233                 t16 = GET_ARG();
01234                 C_ASSERT(t16 <= 3);
01235 
01236                 pobj1 = TOS;
01237                 pobj2 = TOS1;
01238                 pobj3 = TOS2;
01239                 if (t16 >= 3)
01240                     PM_PUSH(pobj3);
01241                 if (t16 >= 2)
01242                     PM_PUSH(pobj2);
01243                 if (t16 >= 1)
01244                     PM_PUSH(pobj1);
01245                 continue;
01246 
01247             case LOAD_CONST:
01248                 /* Get const's index in CO */
01249                 t16 = GET_ARG();
01250 
01251                 /* Push const on stack */
01252                 PM_PUSH(FP->fo_func->f_co->co_consts->val[t16]);
01253                 continue;
01254 
01255             case LOAD_NAME:
01256                 /* Get name index */
01257                 t16 = GET_ARG();
01258 
01259                 /* Get name from names tuple */
01260                 pobj1 = FP->fo_func->f_co->co_names->val[t16];
01261 
01262                 /* Get value from frame's attrs dict */
01263                 retval = dict_getItem((pPmObj_t)FP->fo_attrs, pobj1, &pobj2);
01264                 if (retval == PM_RET_EX_KEY)
01265                 {
01266                     /* Get val from globals */
01267                     retval = dict_getItem((pPmObj_t)FP->fo_globals,
01268                                           pobj1, &pobj2);
01269 
01270                     /* Check for name in the builtins module if it is loaded */
01271                     if ((retval == PM_RET_EX_KEY) && (PM_PBUILTINS != C_NULL))
01272                     {
01273                         /* Get val from builtins */
01274                         retval = dict_getItem(PM_PBUILTINS, pobj1, &pobj2);
01275                         if (retval == PM_RET_EX_KEY)
01276                         {
01277                             /* Name not defined, raise NameError */
01278                             PM_RAISE(retval, PM_RET_EX_NAME);
01279                             break;
01280                         }
01281                     }
01282                 }
01283                 PM_BREAK_IF_ERROR(retval);
01284                 PM_PUSH(pobj2);
01285                 continue;
01286 
01287             case BUILD_TUPLE:
01288                 /* Get num items */
01289                 t16 = GET_ARG();
01290                 retval = tuple_new(t16, &pobj1);
01291                 PM_BREAK_IF_ERROR(retval);
01292 
01293                 /* Fill tuple with ptrs to objs */
01294                 for (; --t16 >= 0;)
01295                 {
01296                     ((pPmTuple_t)pobj1)->val[t16] = PM_POP();
01297                 }
01298                 PM_PUSH(pobj1);
01299                 continue;
01300 
01301             case BUILD_LIST:
01302                 t16 = GET_ARG();
01303                 /* WARNING: Is list object protected from GC sweep? */
01304                 retval = list_new(&pobj1);
01305                 PM_BREAK_IF_ERROR(retval);
01306                 for (; --t16 >= 0;)
01307                 {
01308                     /* Insert obj into list */
01309                     retval = list_insert(pobj1, 0, TOS);
01310                     PM_BREAK_IF_ERROR(retval);
01311                     SP--;
01312                 }
01313                 /* Test again outside for loop */
01314                 PM_BREAK_IF_ERROR(retval);
01315 
01316                 /* push list onto stack */
01317                 PM_PUSH(pobj1);
01318                 continue;
01319 
01320             case BUILD_MAP:
01321                 /* Argument is ignored */
01322                 t16 = GET_ARG();
01323                 retval = dict_new(&pobj1);
01324                 PM_BREAK_IF_ERROR(retval);
01325                 PM_PUSH(pobj1);
01326                 continue;
01327 
01328             case LOAD_ATTR:
01329                 /* Implements TOS.attr */
01330                 t16 = GET_ARG();
01331 
01332                 /* Get attrs dict from obj */
01333                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN) ||
01334                     (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD))
01335                 {
01336                     pobj1 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs;
01337                 }
01338 
01339 #ifdef HAVE_CLASSES
01340                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
01341                 {
01342                     pobj1 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs;
01343                 }
01344                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)
01345                 {
01346                     pobj1 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs;
01347                 }
01348                 else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH)
01349                 {
01350                     pobj1 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs;
01351                 }
01352 #endif /* HAVE_CLASSES */
01353 
01354                 /* Other types result in an AttributeError */
01355                 else
01356                 {
01357                     PM_RAISE(retval, PM_RET_EX_ATTR);
01358                     break;
01359                 }
01360 
01361                 /* If attrs is not a dict, raise SystemError */
01362                 if (OBJ_GET_TYPE(pobj1) != OBJ_TYPE_DIC)
01363                 {
01364                     PM_RAISE(retval, PM_RET_EX_SYS);
01365                     break;
01366                 }
01367 
01368                 /* Get name */
01369                 pobj2 = FP->fo_func->f_co->co_names->val[t16];
01370 
01371                 /* Get attr with given name */
01372                 retval = dict_getItem(pobj1, pobj2, &pobj3);
01373 
01374 #ifdef HAVE_CLASSES
01375                 /*
01376                  * If attr is not found and object is a class or instance,
01377                  * try to get the attribute from the class attrs or parent(s)
01378                  */
01379                 if ((retval == PM_RET_EX_KEY) &&
01380                     ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO)
01381                         || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI)))
01382                 {
01383                     retval = class_getAttr(TOS, pobj2, &pobj3);
01384                 }
01385 #endif /* HAVE_CLASSES */
01386 
01387                 /* Raise an AttributeError if key is not found */
01388                 if (retval == PM_RET_EX_KEY)
01389                 {
01390                     PM_RAISE(retval, PM_RET_EX_ATTR);
01391                 }
01392                 PM_BREAK_IF_ERROR(retval);
01393 
01394 #ifdef HAVE_CLASSES
01395                 /* If obj is an instance and attr is a func, create method */
01396                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI) &&
01397                     (OBJ_GET_TYPE(pobj3) == OBJ_TYPE_FXN))
01398                 {
01399                     pobj2 = pobj3;
01400                     retval = class_method(TOS, pobj2, &pobj3);
01401                     PM_BREAK_IF_ERROR(retval);
01402                 }
01403 #endif /* HAVE_CLASSES */
01404 
01405                 /* Put attr on the stack */
01406                 TOS = pobj3;
01407                 continue;
01408 
01409             case COMPARE_OP:
01410                 retval = PM_RET_OK;
01411                 t16 = GET_ARG();
01412 
01413 #ifdef HAVE_FLOAT
01414                 if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT)
01415                     || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT))
01416                 {
01417                     retval = float_compare(TOS1, TOS, &pobj3, (PmCompare_t)t16);
01418                     SP--;
01419                     TOS = pobj3;
01420                     continue;
01421                 }
01422 #endif /* HAVE_FLOAT */
01423 
01424                 /* Handle all integer-to-integer (or bool) comparisons */
01425                 if (((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)
01426                      || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_BOOL))
01427                     && ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT)
01428                         || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_BOOL)))
01429                 {
01430                     int32_t a = ((pPmInt_t)TOS1)->val;
01431                     int32_t b = ((pPmInt_t)TOS)->val;
01432 
01433                     switch (t16)
01434                     {
01435                         /* *INDENT-OFF* */
01436                         case COMP_LT: t8 = (int8_t)(a <  b); break;
01437                         case COMP_LE: t8 = (int8_t)(a <= b); break;
01438                         case COMP_EQ: t8 = (int8_t)(a == b); break;
01439                         case COMP_NE: t8 = (int8_t)(a != b); break;
01440                         case COMP_GT: t8 = (int8_t)(a >  b); break;
01441                         case COMP_GE: t8 = (int8_t)(a >= b); break;
01442                         case COMP_IS: t8 = (int8_t)(TOS == TOS1); break;
01443                         case COMP_IS_NOT: t8 = (int8_t)(TOS != TOS1);break;
01444                         case COMP_IN:
01445                         case COMP_NOT_IN:
01446                             PM_RAISE(retval, PM_RET_EX_TYPE);
01447                             break;
01448 
01449                         default:
01450                             /* Other compares are not yet supported */
01451                             PM_RAISE(retval, PM_RET_EX_SYS);
01452                             break;
01453                         /* *INDENT-ON* */
01454                     }
01455                     PM_BREAK_IF_ERROR(retval);
01456                     pobj3 = (t8) ? PM_TRUE : PM_FALSE;
01457                 }
01458 
01459                 /* Handle non-integer comparisons */
01460                 else
01461                 {
01462                     retval = PM_RET_OK;
01463                     switch (t16)
01464                     {
01465                         case COMP_EQ:
01466                         case COMP_NE:
01467                             /* Handle equality for non-int types */
01468                             pobj3 = PM_FALSE;
01469                             t8 = obj_compare(TOS, TOS1);
01470                             if (((t8 == C_SAME) && (t16 == COMP_EQ))
01471                                 || ((t8 == C_DIFFER) && (t16 == COMP_NE)))
01472                             {
01473                                 pobj3 = PM_TRUE;
01474                             }
01475                             break;
01476 
01477                         case COMP_IN:
01478                         case COMP_NOT_IN:
01479                             /* Handle membership comparisons */
01480                             pobj3 = PM_FALSE;
01481                             retval = obj_isIn(TOS, TOS1);
01482                             if (retval == PM_RET_OK)
01483                             {
01484                                 if (t16 == COMP_IN)
01485                                 {
01486                                     pobj3 = PM_TRUE;
01487                                 }
01488                             }
01489                             else if (retval == PM_RET_NO)
01490                             {
01491                                 retval = PM_RET_OK;
01492                                 if (t16 == COMP_NOT_IN)
01493                                 {
01494                                     pobj3 = PM_TRUE;
01495                                 }
01496                             }
01497                             break;
01498 
01499                         default:
01500                             /* Other comparisons are not implemented */
01501                             PM_RAISE(retval, PM_RET_EX_SYS);
01502                             break;
01503                     }
01504                     PM_BREAK_IF_ERROR(retval);
01505                 }
01506                 SP--;
01507                 TOS = pobj3;
01508                 continue;
01509 
01510             case IMPORT_NAME:
01511                 /* Get name index */
01512                 t16 = GET_ARG();
01513 
01514                 /* Get name String obj */
01515                 pobj1 = FP->fo_func->f_co->co_names->val[t16];
01516 
01517                 /* Pop unused None object */
01518                 SP--;
01519 
01520                 /* Ensure "level" is -1; no support for relative import yet */
01521                 C_ASSERT(obj_compare(TOS, PM_NEGONE) == C_SAME);
01522 
01523                 /* #110: Prevent importing previously-loaded module */
01524                 /* If the named module is in globals, put it on the stack */
01525                 retval =
01526                     dict_getItem((pPmObj_t)FP->fo_globals, pobj1, &pobj2);
01527                 if ((retval == PM_RET_OK)
01528                     && (OBJ_GET_TYPE(pobj2) == OBJ_TYPE_MOD))
01529                 {
01530                     TOS = pobj2;
01531                     continue;
01532                 }
01533 
01534                 /* Load module from image */
01535                 retval = mod_import(pobj1, &pobj2);
01536                 PM_BREAK_IF_ERROR(retval);
01537 
01538                 /* Put Module on top of stack */
01539                 TOS = pobj2;
01540 
01541                 /* Code after here is a duplicate of CALL_FUNCTION */
01542                 /* Make frame object to interpret the module's root code */
01543                 retval = frame_new(pobj2, &pobj3);
01544                 PM_BREAK_IF_ERROR(retval);
01545 
01546                 /* No arguments to pass */
01547 
01548                 /* Keep ref to current frame */
01549                 ((pPmFrame_t)pobj3)->fo_back = FP;
01550 
01551                 /* Handle to have None popped on return */
01552                 ((pPmFrame_t)pobj3)->fo_isImport = (uint8_t)1;
01553 
01554                 /* Set new frame */
01555                 FP = (pPmFrame_t)pobj3;
01556                 continue;
01557 
01558 #ifdef HAVE_IMPORTS
01559             case IMPORT_FROM:
01560                 /* #102: Implement the remaining IMPORT_ bytecodes */
01561                 /* Expect the module on the top of the stack */
01562                 C_ASSERT(OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD);
01563                 pobj1 = TOS;
01564 
01565                 /* Get the name of the object to import */
01566                 t16 = GET_ARG();
01567                 pobj2 = FP->fo_func->f_co->co_names->val[t16];
01568 
01569                 /* Get the object from the module's attributes */
01570                 retval = dict_getItem((pPmObj_t)((pPmFunc_t)pobj1)->f_attrs,
01571                                       pobj2, &pobj3);
01572                 PM_BREAK_IF_ERROR(retval);
01573 
01574                 /* Push the object onto the top of the stack */
01575                 PM_PUSH(pobj3);
01576                 continue;
01577 #endif /* HAVE_IMPORTS */
01578 
01579             case JUMP_FORWARD:
01580                 t16 = GET_ARG();
01581                 IP += t16;
01582                 continue;
01583 
01584             case JUMP_IF_FALSE:
01585                 t16 = GET_ARG();
01586                 if (obj_isFalse(TOS))
01587                 {
01588                     IP += t16;
01589                 }
01590                 continue;
01591 
01592             case JUMP_IF_TRUE:
01593                 t16 = GET_ARG();
01594                 if (!obj_isFalse(TOS))
01595                 {
01596                     IP += t16;
01597                 }
01598                 continue;
01599 
01600             case JUMP_ABSOLUTE:
01601             case CONTINUE_LOOP:
01602                 /* Get target offset (bytes) */
01603                 t16 = GET_ARG();
01604 
01605                 /* Jump to base_ip + arg */
01606                 IP = FP->fo_func->f_co->co_codeaddr + t16;
01607                 continue;
01608 
01609             case LOAD_GLOBAL:
01610                 /* Get name */
01611                 t16 = GET_ARG();
01612                 pobj1 = FP->fo_func->f_co->co_names->val[t16];
01613 
01614                 /* Try globals first */
01615                 retval = dict_getItem((pPmObj_t)FP->fo_globals,
01616                                       pobj1, &pobj2);
01617 
01618                 /* If that didn't work, try builtins */
01619                 if (retval == PM_RET_EX_KEY)
01620                 {
01621                     retval = dict_getItem(PM_PBUILTINS, pobj1, &pobj2);
01622 
01623                     /* No such global, raise NameError */
01624                     if (retval == PM_RET_EX_KEY)
01625                     {
01626                         PM_RAISE(retval, PM_RET_EX_NAME);
01627                         break;
01628                     }
01629                 }
01630                 PM_BREAK_IF_ERROR(retval);
01631                 PM_PUSH(pobj2);
01632                 continue;
01633 
01634             case SETUP_LOOP:
01635             {
01636                 uint8_t *pchunk;
01637 
01638                 /* Get block span (bytes) */
01639                 t16 = GET_ARG();
01640 
01641                 /* Create block */
01642                 retval = heap_getChunk(sizeof(PmBlock_t), &pchunk);
01643                 PM_BREAK_IF_ERROR(retval);
01644                 pobj1 = (pPmObj_t)pchunk;
01645                 OBJ_SET_TYPE(pobj1, OBJ_TYPE_BLK);
01646 
01647                 /* Store current stack pointer */
01648                 ((pPmBlock_t)pobj1)->b_sp = SP;
01649 
01650                 /* Default handler is to exit block/loop */
01651                 ((pPmBlock_t)pobj1)->b_handler = IP + t16;
01652                 ((pPmBlock_t)pobj1)->b_type = B_LOOP;
01653 
01654                 /* Insert block into blockstack */
01655                 ((pPmBlock_t)pobj1)->next = FP->fo_blockstack;
01656                 FP->fo_blockstack = (pPmBlock_t)pobj1;
01657                 continue;
01658             }
01659 
01660             case LOAD_FAST:
01661                 t16 = GET_ARG();
01662                 PM_PUSH(FP->fo_locals[t16]);
01663                 continue;
01664 
01665             case STORE_FAST:
01666                 t16 = GET_ARG();
01667                 FP->fo_locals[t16] = PM_POP();
01668                 continue;
01669 
01670 #ifdef HAVE_DEL
01671             case DELETE_FAST:
01672                 t16 = GET_ARG();
01673                 FP->fo_locals[t16] = PM_NONE;
01674                 continue;
01675 #endif /* HAVE_DEL */
01676 
01677 #ifdef HAVE_ASSERT
01678             case RAISE_VARARGS:
01679                 t16 = GET_ARG();
01680 
01681                 /* Only supports taking 1 arg for now */
01682                 if (t16 != 1)
01683                 {
01684                     PM_RAISE(retval, PM_RET_EX_SYS);
01685                     break;
01686                 }
01687 
01688                 /* Load Exception class from builtins */
01689                 retval = dict_getItem(PM_PBUILTINS, PM_EXCEPTION_STR, &pobj2);
01690                 if (retval != PM_RET_OK)
01691                 {
01692                     PM_RAISE(retval, PM_RET_EX_SYS);
01693                     break;
01694                 }
01695 
01696                 /* Raise TypeError if TOS is not an instance of Exception */
01697                 pobj1 = TOS;
01698                 if ((OBJ_GET_TYPE(pobj1) != OBJ_TYPE_CLO)
01699                     || !class_isSubclass(pobj1, pobj2))
01700                 {
01701                     PM_RAISE(retval, PM_RET_EX_TYPE);
01702                     break;
01703                 }
01704 
01705                 /* Push the traceback, parameter and exception object */
01706                 TOS = PM_NONE;
01707                 PM_PUSH(PM_NONE);
01708                 PM_PUSH(pobj1);
01709 
01710                 /* Get the exception's code attr */
01711                 retval = dict_getItem((pPmObj_t)((pPmClass_t)pobj1)->cl_attrs,
01712                                       PM_CODE_STR, &pobj2);
01713                 PM_BREAK_IF_ERROR(retval);
01714 
01715                 /* Raise exception by breaking with retval set to code */
01716                 PM_RAISE(retval, (PmReturn_t)(((pPmInt_t)pobj2)->val & 0xFF));
01717                 break;
01718 #endif /* HAVE_ASSERT */
01719 
01720             case CALL_FUNCTION:
01721                 /* Get num args */
01722                 t16 = GET_ARG();
01723 
01724                 /* Ensure no keyword args */
01725                 if ((t16 & (uint16_t)0xFF00) != 0)
01726                 {
01727                     PM_RAISE(retval, PM_RET_EX_SYS);
01728                     break;
01729                 }
01730 
01731                 /* Get the callable */
01732                 pobj1 = STACK(t16);
01733 
01734                 C_DEBUG_PRINT(VERBOSITY_LOW,
01735                     "interpret(), CALL_FUNCTION on <obj type=%d @ %p>\n",
01736                     OBJ_GET_TYPE(pobj1), pobj1);
01737 
01738 #ifdef HAVE_GENERATORS
01739                 /* If the callable is a generator function (can't be native) */
01740                 if ((OBJ_GET_TYPE(pobj1) == OBJ_TYPE_FXN)
01741                     && (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) == OBJ_TYPE_COB)
01742                     && (((pPmFunc_t)pobj1)->f_co->co_flags & CO_GENERATOR))
01743                 {
01744                     /* Collect the function and arguments into a tuple */
01745                     retval = tuple_new(t16 + 1, &pobj2);
01746                     PM_BREAK_IF_ERROR(retval);
01747                     sli_memcpy((uint8_t *)&((pPmTuple_t)pobj2)->val,
01748                                (uint8_t *)&STACK(t16),
01749                                (t16 + 1) * sizeof(pPmObj_t));
01750 
01751                     /* Remove old args, push func/args tuple as one arg */
01752                     SP -= t16;
01753                     PM_PUSH(pobj2);
01754                     t16 = 1;
01755 
01756                     /* Set pobj1 and stack to create an instance of Generator */
01757                     retval = dict_getItem(PM_PBUILTINS, PM_GENERATOR_STR,
01758                                           &pobj1);
01759                     PM_RETURN_IF_ERROR(retval);
01760                     STACK(t16) = pobj1;
01761                 }
01762 #endif /* HAVE_GENERATORS */
01763 
01764 #ifdef HAVE_CLASSES
01765                 /* If the callable is a class, create an instance of it */
01766                 if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLO)
01767                 {
01768                     /* This marks that the original callable was a class */
01769                     bc = 0;
01770 
01771                     /* Replace class with new instance */
01772                     retval = class_instantiate(pobj1, &pobj2);
01773                     STACK(t16) = pobj2;
01774 
01775                     /* If __init__ does not exist */
01776                     pobj3 = C_NULL;
01777                     retval = class_getAttr(pobj1, PM_INIT_STR, &pobj3);
01778                     if (retval == PM_RET_EX_KEY)
01779                     {
01780                         /* Raise TypeError if there are args */
01781                         if (t16 > 0)
01782                         {
01783                             PM_RAISE(retval, PM_RET_EX_TYPE);
01784                             break;
01785                         }
01786 
01787                         /* Otherwise, continue with instance */
01788                         continue;
01789                     }
01790                     else if (retval != PM_RET_OK)
01791                     {
01792                         PM_BREAK_IF_ERROR(retval);
01793                     }
01794 
01795                     /* Slide the arguments up 1 slot in the stack */
01796                     SP++;
01797                     for (t8 = 0; t8 < t16; t8++)
01798                     {
01799                         STACK(t8) = STACK(t8 + 1);
01800                     }
01801 
01802                     /* Convert __init__ to method, insert it as the callable */
01803                     retval = class_method(pobj2, pobj3, &pobj1);
01804                     PM_BREAK_IF_ERROR(retval);
01805                     STACK(t16) = pobj1;
01806                     /* Fall through to call the method */
01807                 }
01808 
01809                 if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_MTH)
01810                 {
01811                     /* Set the method's func to be the callable */
01812                     STACK(t16) = (pPmObj_t)((pPmMethod_t)pobj1)->m_func;
01813 
01814                     /* Slide the arguments up 1 slot in the stack */
01815                     SP++;
01816                     for (t8 = 0; t8 < t16; t8++)
01817                     {
01818                         STACK(t8) = STACK(t8 + 1);
01819                     }
01820 
01821                     /* Insert instance as "self" arg to the method */
01822                     STACK(t16++) = (pPmObj_t)((pPmMethod_t)pobj1)->m_instance;
01823 
01824                     /* Refresh the callable */
01825                     pobj1 = (pPmObj_t)((pPmMethod_t)pobj1)->m_func;
01826                 }
01827 #endif /* HAVE_CLASSES */
01828 
01829 #ifdef HAVE_GENERATORS
01830 CALL_FUNC_FOR_ITER:
01831 #endif /* HAVE_GENERATORS */
01832                 /* Raise a TypeError if object is not callable */
01833                 if (OBJ_GET_TYPE(pobj1) != OBJ_TYPE_FXN)
01834                 {
01835                     PM_RAISE(retval, PM_RET_EX_TYPE);
01836                     break;
01837                 }
01838 
01839                 /* If it is a regular func (not native) */
01840                 if (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) == OBJ_TYPE_COB)
01841                 {
01842                     /*
01843                      * #132 Raise TypeError if num args does not match the
01844                      * code object's expected argcount
01845                      */
01846 
01847 #ifdef HAVE_DEFAULTARGS
01848                     /* Num required args := argcount - num default args */
01849                     t8 = ((pPmFunc_t)pobj1)->f_co->co_argcount;
01850                     if (((pPmFunc_t)pobj1)->f_defaultargs != C_NULL)
01851                     {
01852                         t8 -= ((pPmTuple_t)((pPmFunc_t)pobj1)->f_defaultargs)->
01853                             length;
01854                     }
01855 
01856                     /*
01857                      * Raise a TypeError if num args passed
01858                      * is more than allowed or less than required
01859                      */
01860                     if (((t16 & ((uint8_t)0xFF))
01861                          > ((pPmFunc_t)pobj1)->f_co->co_argcount)
01862                         || ((t16 & ((uint8_t)0xFF)) < t8))
01863 #else
01864                     if ((t16 & ((uint8_t)0xFF)) !=
01865                         ((pPmFunc_t)pobj1)->f_co->co_argcount)
01866 #endif /* HAVE_DEFAULTARGS */
01867                     {
01868                         PM_RAISE(retval, PM_RET_EX_TYPE);
01869                         break;
01870                     }
01871 
01872                     /* Make frame object to run the func object */
01873                     retval = frame_new(pobj1, &pobj2);
01874                     PM_BREAK_IF_ERROR(retval);
01875 
01876 #ifdef HAVE_CLASSES
01877                     /*
01878                      * If the original callable was a class, indicate that
01879                      * the frame is running the initializer so that
01880                      * its return object is checked for None and ignored.
01881                      */
01882                     if (bc == 0)
01883                     {
01884                         ((pPmFrame_t)pobj2)->fo_isInit = C_TRUE;
01885                     }
01886 #endif /* HAVE_CLASSES */
01887 
01888 #ifdef HAVE_DEFAULTARGS
01889                     /* If this func has default arguments, put them in place */
01890                     if (((pPmFunc_t)pobj1)->f_defaultargs != C_NULL)
01891                     {
01892                         int8_t i = 0;
01893 
01894                         /* Copy default args into the new frame's locals */
01895                         for ( /* t8 set above */ ;
01896                              t8 < ((pPmFunc_t)pobj1)->f_co->co_argcount; t8++)
01897                         {
01898                             ((pPmFrame_t)pobj2)->fo_locals[t8] =
01899                                 ((pPmTuple_t)((pPmFunc_t)pobj1)->
01900                                  f_defaultargs)->val[i++];
01901                         }
01902                     }
01903 #endif /* HAVE_DEFAULTARGS */
01904 
01905                     /* Pass args to new frame */
01906                     while (--t16 >= 0)
01907                     {
01908                         /*
01909                          * Pop args from stack right to left,
01910                          * since args are pushed left to right,
01911                          */
01912                         ((pPmFrame_t)pobj2)->fo_locals[t16] = PM_POP();
01913                     }
01914 
01915 #ifdef HAVE_CLOSURES
01916                     /* #256: Add support for closures */
01917                     /* Copy arguments that become cellvars */
01918                     if (((pPmFunc_t)pobj1)->f_co->co_cellvars != C_NULL)
01919                     {
01920                         for (t8 = 0;
01921                              t8 < ((pPmFunc_t)pobj1)->f_co->co_cellvars->length;
01922                              t8++)
01923                         {
01924                             if (((pPmInt_t)((pPmFunc_t)pobj1)->
01925                                 f_co->co_cellvars->val[t8])->val >= 0)
01926                             {
01927                                 ((pPmFrame_t)pobj2)->fo_locals[
01928                                     ((pPmFunc_t)pobj1)->f_co->co_nlocals + t8] =
01929                                     ((pPmFrame_t)pobj2)->fo_locals[
01930                                         ((pPmInt_t)(((pPmFunc_t)pobj1)->
01931                                             f_co->co_cellvars->val[t8]))->val
01932                                     ];
01933                             }
01934                         }
01935                     }
01936 
01937                     /* Fill frame's freevars with references from closure */
01938                     for (t8 = 0;
01939                          t8 < ((pPmFunc_t)pobj1)->f_co->co_nfreevars;
01940                          t8++)
01941                     {
01942                         C_ASSERT(((pPmFunc_t)pobj1)->f_closure != C_NULL);
01943                         ((pPmFrame_t)pobj2)->fo_locals[
01944                             ((pPmFunc_t)pobj1)->f_co->co_nlocals
01945                             + ((((pPmFunc_t)pobj1)->f_co->co_cellvars == C_NULL) ? 0 : ((pPmFunc_t)pobj1)->f_co->co_cellvars->length)
01946                             + t8] = ((pPmFunc_t)pobj1)->f_closure->val[t8];
01947                     }
01948 #endif /* HAVE_CLOSURES */
01949 
01950                     /* Pop func obj */
01951                     pobj3 = PM_POP();
01952 
01953                     /* Keep ref to current frame */
01954                     ((pPmFrame_t)pobj2)->fo_back = FP;
01955 
01956                     /* Set new frame */
01957                     FP = (pPmFrame_t)pobj2;
01958                 }
01959 
01960                 /* If it's native func */
01961                 else if (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) ==
01962                          OBJ_TYPE_NOB)
01963                 {
01964 
01965                     /* Ensure num args fits in native frame */
01966                     if (t16 > NATIVE_MAX_NUM_LOCALS)
01967                     {
01968                         PM_RAISE(retval, PM_RET_EX_SYS);
01969                         break;
01970                     }
01971 
01972                     /* Set number of locals (arguments) */
01973                     gVmGlobal.nativeframe.nf_numlocals = (uint8_t)t16;
01974 
01975                     /* Pop args from stack */
01976                     while (--t16 >= 0)
01977                     {
01978                         gVmGlobal.nativeframe.nf_locals[t16] = PM_POP();
01979                     }
01980 
01981 #ifdef HAVE_GC
01982                     /* If the heap is low on memory, run the GC */
01983                     if (heap_getAvail () < HEAP_GC_NF_THRESHOLD)
01984                     {
01985                         retval = heap_gcRun();
01986                         PM_BREAK_IF_ERROR(retval);
01987                     }
01988 #endif /* HAVE_GC */
01989 
01990                     /* Pop the function object */
01991                     SP--;
01992 
01993                     /* Get native function index */
01994                     pobj2 = (pPmObj_t)((pPmFunc_t)pobj1)->f_co;
01995                     t16 = ((pPmNo_t)pobj2)->no_funcindx;
01996 
01997                     /* Set flag, so the GC knows a native session is active */
01998                     gVmGlobal.nativeframe.nf_active = C_TRUE;
01999 
02000                     /*
02001                      * CALL NATIVE FXN: pass caller's frame and numargs
02002                      */
02003                     /* Positive index is a stdlib func */
02004                     if (t16 >= 0)
02005                     {
02006                         retval = std_nat_fxn_table[t16] (&FP);
02007                     }
02008 
02009                     /* Negative index is a usrlib func */
02010                     else
02011                     {
02012                         retval = usr_nat_fxn_table[-t16] (&FP);
02013                     }
02014 
02015                     /*
02016                      * RETURN FROM NATIVE FXN
02017                      */
02018 
02019                     /* Clear flag, so frame will not be marked by the GC */
02020                     gVmGlobal.nativeframe.nf_active = C_FALSE;
02021 
02022 #ifdef HAVE_CLASSES
02023                     /* If class's __init__ called, do not push a return obj */
02024                     if (bc == 0)
02025                     {
02026                         /* Raise TypeError if returned obj was not None */
02027                         if ((retval == PM_RET_OK)
02028                             && (gVmGlobal.nativeframe.nf_stack != PM_NONE))
02029                         {
02030                             PM_RAISE(retval, PM_RET_EX_TYPE);
02031                             break;
02032                         }
02033                     }
02034                     else
02035 #endif /* HAVE_CLASSES */
02036 
02037                     /* If the frame pointer was switched, do nothing to TOS */
02038                     if (retval == PM_RET_FRAME_SWITCH)
02039                     {
02040                         retval = PM_RET_OK;
02041                     }
02042 
02043                     /* Otherwise, return the result from the native function */
02044                     else
02045                     {
02046                         PM_PUSH(gVmGlobal.nativeframe.nf_stack);
02047                     }
02048                     PM_BREAK_IF_ERROR(retval);
02049                 }
02050                 continue;
02051 
02052             case MAKE_FUNCTION:
02053                 /* Get num default args to fxn */
02054                 t16 = GET_ARG();
02055 
02056                 /*
02057                  * The current frame's globals become the function object's
02058                  * globals.  The current frame is the container object
02059                  * of this new function object
02060                  */
02061                 retval = func_new(TOS, (pPmObj_t)FP->fo_globals, &pobj2);
02062                 PM_BREAK_IF_ERROR(retval);
02063 
02064                 /* Put any default args in a tuple */
02065                 if (t16 > 0)
02066                 {
02067 
02068 #ifdef HAVE_DEFAULTARGS
02069                     retval = tuple_new(t16, &pobj3);
02070                     PM_BREAK_IF_ERROR(retval);
02071                     SP--;
02072                     while (--t16 >= 0)
02073                     {
02074                         ((pPmTuple_t)pobj3)->val[t16] = PM_POP();
02075                     }
02076 
02077                     /* Set func's default args */
02078                     ((pPmFunc_t)pobj2)->f_defaultargs = (pPmTuple_t)pobj3;
02079 #else
02080                     /* Default arguments not configured in pmfeatures.h */
02081                     PM_RAISE(retval, PM_RET_EX_SYS);
02082                     break;
02083 #endif /* HAVE_DEFAULTARGS */
02084 
02085                 }
02086                 else
02087                 {
02088                     SP--;
02089                 }
02090 
02091                 /* Push func obj */
02092                 PM_PUSH(pobj2);
02093                 continue;
02094 
02095 #ifdef HAVE_CLOSURES
02096             case MAKE_CLOSURE:
02097                 /* Get number of default args */
02098                 t16 = GET_ARG();
02099                 retval = func_new(TOS, (pPmObj_t)FP->fo_globals, &pobj2);
02100                 PM_BREAK_IF_ERROR(retval);
02101 
02102                 /* Set closure of the new function */
02103                 ((pPmFunc_t)pobj2)->f_closure = (pPmTuple_t)TOS1;
02104                 SP -= 2;
02105 
02106                 /* Collect any default arguments into tuple */
02107                 if (t16 > 0)
02108                 {
02109                     retval = tuple_new(t16, &pobj3);
02110                     PM_BREAK_IF_ERROR(retval);
02111 
02112                     while (--t16 >= 0)
02113                     {
02114                         ((pPmTuple_t)pobj3)->val[t16] = PM_POP();
02115                     }
02116                     ((pPmFunc_t)pobj2)->f_defaultargs = (pPmTuple_t)pobj3;
02117                 }
02118 
02119                 /* Push new func with closure */
02120                 PM_PUSH(pobj2);
02121                 continue;
02122 
02123             case LOAD_CLOSURE:
02124             case LOAD_DEREF:
02125                 /* Loads the i'th cell of free variable storage onto TOS */
02126                 t16 = GET_ARG();
02127                 pobj1 = FP->fo_locals[FP->fo_func->f_co->co_nlocals + t16];
02128                 if (pobj1 == C_NULL)
02129                 {
02130                     PM_RAISE(retval, PM_RET_EX_SYS);
02131                     break;
02132                 }
02133                 PM_PUSH(pobj1);
02134                 continue;
02135 
02136             case STORE_DEREF:
02137                 /* Stores TOS into the i'th cell of free variable storage */
02138                 t16 = GET_ARG();
02139                 FP->fo_locals[FP->fo_func->f_co->co_nlocals + t16] = PM_POP();
02140                 continue;
02141 #endif /* HAVE_CLOSURES */
02142 
02143 
02144             default:
02145                 /* SystemError, unknown or unimplemented opcode */
02146                 PM_RAISE(retval, PM_RET_EX_SYS);
02147                 break;
02148         }
02149 
02150 #ifdef HAVE_GENERATORS
02151         /* If got a StopIteration exception, check for a B_LOOP block */
02152         if (retval == PM_RET_EX_STOP)
02153         {
02154             pobj1 = (pPmObj_t)FP;
02155             while (pobj1 != C_NULL)
02156             {
02157                 pobj2 = (pPmObj_t)((pPmFrame_t)pobj1)->fo_blockstack;
02158                 while (pobj2 != C_NULL)
02159                 {
02160                     if (((pPmBlock_t)pobj2)->b_type == B_LOOP)
02161                     {
02162                         /* Resume execution where the block handler says */
02163                         /* Set FP first, so SP and IP are set in the frame */
02164                         FP = (pPmFrame_t)pobj1;
02165                         SP = ((pPmBlock_t)pobj2)->b_sp;
02166                         IP = ((pPmBlock_t)pobj2)->b_handler;
02167                         ((pPmFrame_t)pobj1)->fo_blockstack =
02168                             ((pPmFrame_t)pobj1)->fo_blockstack->next;
02169                         retval = PM_RET_OK;
02170                         break;
02171                     }
02172 
02173                     pobj2 = (pPmObj_t)((pPmBlock_t)pobj2)->next;
02174                 }
02175                 pobj1 = (pPmObj_t)((pPmFrame_t)pobj1)->fo_back;
02176             }
02177             if (retval == PM_RET_OK)
02178             {
02179                 continue;
02180             }
02181         }
02182 #endif /* HAVE_GENERATORS */
02183 
02184         /*
02185          * If execution reaches this point, it is because
02186          * a return value (from above) is not OK or we should exit the thread
02187          * (return of the function). In any case, remove the
02188          * current thread and reschedule.
02189          */
02190         PM_REPORT_IF_ERROR(retval);
02191 
02192         /* If this is the last thread, return the error code */
02193         if ((gVmGlobal.threadList->length <= 1) && (retval != PM_RET_OK))
02194         {
02195             break;
02196         }
02197 
02198         retval = list_remove((pPmObj_t)gVmGlobal.threadList,
02199                              (pPmObj_t)gVmGlobal.pthread);
02200         gVmGlobal.pthread = C_NULL;
02201         PM_BREAK_IF_ERROR(retval);
02202 
02203         retval = interp_reschedule();
02204         PM_BREAK_IF_ERROR(retval);
02205     }
02206 
02207     return retval;
02208 }
02209 
02210 
02211 PmReturn_t
02212 interp_reschedule(void)
02213 {
02214     PmReturn_t retval = PM_RET_OK;
02215     static uint8_t threadIndex = (uint8_t)0;
02216     pPmObj_t pobj;
02217 
02218     /* If there are no threads in the runnable list, null the active thread */
02219     if (gVmGlobal.threadList->length == 0)
02220     {
02221         gVmGlobal.pthread = C_NULL;
02222     }
02223 
02224     /* Otherwise, get the next thread in the list (round robin) */
02225     else
02226     {
02227         if (++threadIndex >= gVmGlobal.threadList->length)
02228         {
02229             threadIndex = (uint8_t)0;
02230         }
02231         retval = list_getItem((pPmObj_t)gVmGlobal.threadList, threadIndex,
02232                               &pobj);
02233         gVmGlobal.pthread = (pPmThread_t)pobj;
02234         PM_RETURN_IF_ERROR(retval);
02235     }
02236 
02237     /* Clear flag to indicate a reschedule has occurred */
02238     interp_setRescheduleFlag(0);
02239     return retval;
02240 }
02241 
02242 
02243 PmReturn_t
02244 interp_addThread(pPmFunc_t pfunc)
02245 {
02246     PmReturn_t retval;
02247     pPmObj_t pframe;
02248     pPmObj_t pthread;
02249 
02250     /* Create a frame for the func */
02251     retval = frame_new((pPmObj_t)pfunc, &pframe);
02252     PM_RETURN_IF_ERROR(retval);
02253 
02254     /* Create a thread with this new frame */
02255     retval = thread_new(pframe, &pthread);
02256     PM_RETURN_IF_ERROR(retval);
02257 
02258     /* Add thread to end of list */
02259     return list_append((pPmObj_t)gVmGlobal.threadList, pthread);
02260 }
02261 
02262 
02263 void
02264 interp_setRescheduleFlag(uint8_t boolean)
02265 {
02266     gVmGlobal.reschedule = boolean;
02267 }