python-on-a-chip online compiler

Dependencies:   mbed TSI

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers class.c Source File

class.c

Go to the documentation of this file.
00001 /*
00002 # This file is Copyright 2009 Dean Hall.
00003 # This file is part of the PyMite VM.
00004 # This file is licensed under the MIT License.
00005 # See the LICENSE file for details.
00006 */
00007 
00008 
00009 #undef __FILE_ID__
00010 #define __FILE_ID__ 0x18
00011 
00012 
00013 /**
00014  * \file
00015  * \brief Class Object Type
00016  *
00017  * Class object type operations.
00018  */
00019 
00020 
00021 #include "pm.h"
00022 
00023 
00024 #ifdef HAVE_AUTOBOX
00025 static uint8_t const *liststr = (uint8_t const *)"list";
00026 static uint8_t const *dictstr = (uint8_t const *)"dict";
00027 static uint8_t const *stringstr = (uint8_t const *)"string";
00028 static uint8_t const *autoboxstr = (uint8_t const *)"_Autobox";
00029 static uint8_t const *objstr = (uint8_t const *)"obj";
00030 #endif
00031 
00032 
00033 PmReturn_t
00034 class_new(pPmObj_t pattrs, pPmObj_t pbases, pPmObj_t pname, pPmObj_t *r_pclass)
00035 {
00036     PmReturn_t retval = PM_RET_OK;
00037     uint8_t *pchunk;
00038     pPmObj_t pobj;
00039 
00040     /* Ensure types */
00041     if ((OBJ_GET_TYPE(pattrs) != OBJ_TYPE_DIC)
00042         || (OBJ_GET_TYPE(pbases) != OBJ_TYPE_TUP)
00043         || (OBJ_GET_TYPE(pname) != OBJ_TYPE_STR))
00044     {
00045         PM_RAISE(retval, PM_RET_EX_TYPE);
00046         return retval;
00047     }
00048 
00049     /* Allocate a class obj */
00050     retval = heap_getChunk(sizeof(PmClass_t), &pchunk);
00051     PM_RETURN_IF_ERROR(retval);
00052     pobj = (pPmObj_t)pchunk;
00053     OBJ_SET_TYPE(pobj, OBJ_TYPE_CLO);
00054 
00055     /* Class has no access to its CO */
00056     ((pPmClass_t)pobj)->cl_attrs = (pPmDict_t)pattrs;
00057     ((pPmClass_t)pobj)->cl_bases = (pPmTuple_t)pbases;
00058 
00059     *r_pclass = pobj;
00060 
00061     return retval;
00062 }
00063 
00064 
00065 /* Returns an instance of the class by reference */
00066 PmReturn_t
00067 class_instantiate(pPmObj_t pclass, pPmObj_t *r_pobj)
00068 {
00069     PmReturn_t retval = PM_RET_OK;
00070     uint8_t *pchunk;
00071     pPmObj_t pobj;
00072     pPmObj_t pattrs;
00073     uint8_t objid;
00074 
00075     /* Allocate a class instance */
00076     retval = heap_getChunk(sizeof(PmInstance_t), &pchunk);
00077     PM_RETURN_IF_ERROR(retval);
00078     pobj = (pPmObj_t)pchunk;
00079     OBJ_SET_TYPE(pobj, OBJ_TYPE_CLI);
00080 
00081     /* Set the instance's fields */
00082     ((pPmInstance_t)pobj)->cli_class = (pPmClass_t)pclass;
00083     ((pPmInstance_t)pobj)->cli_attrs = C_NULL;
00084 
00085     /* Create the attributes dict */
00086     heap_gcPushTempRoot(pobj, &objid);
00087     retval = dict_new(&pattrs);
00088     heap_gcPopTempRoot(objid);
00089     ((pPmInstance_t)pobj)->cli_attrs = (pPmDict_t)pattrs;
00090 
00091     /* TODO: Store pclass in __class__ attr */
00092 
00093     *r_pobj = pobj;
00094     return retval;
00095 }
00096 
00097 
00098 #ifdef HAVE_AUTOBOX
00099 PmReturn_t
00100 class_autobox(pPmObj_t *pobj)
00101 {
00102     PmReturn_t retval = PM_RET_OK;
00103     pPmObj_t pmodule, pstr, pclass, pwrapped, pmodcache;
00104 
00105     uint8_t const *pliststr = liststr;
00106     uint8_t const *pdictstr = dictstr;
00107     uint8_t const *pstringstr = stringstr;
00108 
00109     uint8_t const *pAutoboxstr = autoboxstr;
00110     uint8_t const *pobjstr = objstr;
00111 
00112     /* Load the appropriate module name,
00113      * or do nothing if we have a non-boxable type
00114      */
00115     if (OBJ_GET_TYPE(*pobj) == OBJ_TYPE_LST) {
00116         retval = string_new(&pliststr, &pstr);
00117         PM_RETURN_IF_ERROR(retval);
00118     } else if (OBJ_GET_TYPE(*pobj) == OBJ_TYPE_DIC) {
00119         retval = string_new(&pdictstr, &pstr);
00120         PM_RETURN_IF_ERROR(retval);
00121     } else if (OBJ_GET_TYPE(*pobj) == OBJ_TYPE_STR) {
00122         retval = string_new(&pstringstr, &pstr);
00123         PM_RETURN_IF_ERROR(retval);
00124     } else {
00125         return retval;
00126     }
00127 
00128     /** first, try to get the module from the cache */
00129     retval = dict_getItem(PM_PBUILTINS, PM_MD_STR, &pmodcache);
00130     PM_RETURN_IF_ERROR(retval);
00131 
00132     retval = dict_getItem(pmodcache, pstr, &pmodule);
00133     PM_RETURN_IF_ERROR(retval);
00134 
00135     if (!((retval == PM_RET_OK) && (OBJ_GET_TYPE(pmodule) == OBJ_TYPE_MOD)))
00136     {
00137         PM_RAISE(retval, PM_RET_EX_SYS);
00138         return retval;
00139     }
00140 
00141     /* grab the class from within the loaded module */
00142     retval = string_new(&pAutoboxstr, &pstr);
00143     PM_RETURN_IF_ERROR(retval);
00144     retval = dict_getItem((pPmObj_t) ((pPmFunc_t)pmodule)->f_attrs, pstr, &pclass);
00145     PM_RETURN_IF_ERROR(retval);
00146 
00147     /* instantiate instance of (type)._Autobox */
00148     retval = class_instantiate(pclass, &pwrapped);
00149     PM_RETURN_IF_ERROR(retval);
00150 
00151     /* store object as _Autobox().obj */
00152     retval = string_new(&pobjstr, &pstr);
00153     PM_RETURN_IF_ERROR(retval);
00154     retval = dict_setItem((pPmObj_t)((pPmInstance_t)pwrapped)->cli_attrs,
00155                           pstr, *pobj);
00156     PM_RETURN_IF_ERROR(retval);
00157 
00158     /** replace old object with new instance in place */
00159     *pobj = pwrapped;
00160 
00161     return retval;
00162 }
00163 #endif
00164 
00165 
00166 PmReturn_t
00167 class_method(pPmObj_t pinstance, pPmObj_t pfunc, pPmObj_t *r_pmeth)
00168 {
00169     PmReturn_t retval = PM_RET_OK;
00170     uint8_t *pchunk;
00171     pPmMethod_t pmeth;
00172     pPmObj_t pattrs;
00173     uint8_t objid;
00174 
00175     /* Allocate a method */
00176     retval = heap_getChunk(sizeof(PmMethod_t), &pchunk);
00177     PM_RETURN_IF_ERROR(retval);
00178     OBJ_SET_TYPE(pchunk, OBJ_TYPE_MTH);
00179 
00180     /* Set method fields */
00181     pmeth = (pPmMethod_t)pchunk;
00182     pmeth->m_instance = (pPmInstance_t)pinstance;
00183     pmeth->m_func = (pPmFunc_t)pfunc;
00184     pmeth->m_attrs = C_NULL;
00185 
00186     /* Create the attributes dict */
00187     heap_gcPushTempRoot((pPmObj_t)pmeth, &objid);
00188     retval = dict_new(&pattrs);
00189     heap_gcPopTempRoot(objid);
00190     pmeth->m_attrs = (pPmDict_t)pattrs;
00191 
00192     *r_pmeth = (pPmObj_t)pmeth;
00193     return retval;
00194 }
00195 
00196 
00197 PmReturn_t
00198 class_getAttr(pPmObj_t pobj, pPmObj_t pname, pPmObj_t *r_pobj)
00199 {
00200     PmReturn_t retval;
00201     uint16_t i;
00202     pPmObj_t pparent;
00203 
00204     /* If the given obj is an instance, check its attrs */
00205     if (OBJ_GET_TYPE(pobj) == OBJ_TYPE_CLI)
00206     {
00207         retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj)->cli_attrs, pname,
00208                               r_pobj);
00209         if (retval == PM_RET_OK)
00210         {
00211             return retval;
00212         }
00213 
00214         /* Otherwise, check the instance's class */
00215         pobj = (pPmObj_t)((pPmInstance_t)pobj)->cli_class;
00216     }
00217 
00218     C_ASSERT(OBJ_GET_TYPE(pobj) == OBJ_TYPE_CLO);
00219 
00220     retval = dict_getItem((pPmObj_t)((pPmClass_t)pobj)->cl_attrs, pname,
00221                           r_pobj);
00222 
00223     /* If attr is not found, search parent(s) */
00224     if ((retval == PM_RET_EX_KEY) && (((pPmClass_t)pobj)->cl_bases != C_NULL))
00225     {
00226         for (i = 0; i < ((pPmClass_t)pobj)->cl_bases->length; i++)
00227         {
00228             pparent = ((pPmClass_t)pobj)->cl_bases->val[i];
00229             retval = class_getAttr(pparent, pname, r_pobj);
00230             if (retval == PM_RET_OK)
00231             {
00232                 break;
00233             }
00234         }
00235     }
00236 
00237     return retval;
00238 }
00239 
00240 
00241 uint8_t /* boolean */
00242 class_isSubclass(pPmObj_t ptest_class, pPmObj_t pbase_class)
00243 {
00244     uint8_t i;
00245     uint8_t retval;
00246 
00247     retval = C_FALSE;
00248 
00249     if (ptest_class == pbase_class)
00250     {
00251         return C_TRUE;
00252     }
00253 
00254     /* Recursively check if test class has a matching base class */
00255     if (((pPmClass_t)ptest_class)->cl_bases != C_NULL)
00256     {
00257         for (i = 0; i < ((pPmClass_t)ptest_class)->cl_bases->length; i++)
00258         {
00259             retval = class_isSubclass(((pPmClass_t)ptest_class)->cl_bases->val[i],
00260                                         pbase_class);
00261             if (retval)
00262             {
00263                 break;
00264             }
00265         }
00266     }
00267     return retval;
00268 }