python-on-a-chip online compiler

Dependencies:   mbed TSI

/media/uploads/va009039/p14p-f446re.png

more info: python-on-a-chip

Revision:
0:65f1469d6bfb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vm/strobj.c	Sat Mar 02 11:54:20 2013 +0000
@@ -0,0 +1,599 @@
+/*
+# This file is Copyright 2002 Dean Hall.
+# This file is part of the PyMite VM.
+# This file is licensed under the MIT License.
+# See the LICENSE file for details.
+*/
+
+
+#undef __FILE_ID__
+#define __FILE_ID__ 0x12
+
+
+/**
+ * \file
+ * \brief String Object Type
+ *
+ * String object type opeartions.
+ */
+
+#include "pm.h"
+
+
+#if USE_STRING_CACHE
+/** String obj cachche: a list of all string objects. */
+static pPmString_t pstrcache = C_NULL;
+#endif /* USE_STRING_CACHE */
+
+
+/* The following 2 ascii values are used to escape printing to ipm */
+#define REPLY_TERMINATOR 0x04
+#define ESCAPE_CHAR 0x1B
+
+
+/*
+ * If USE_STRING_CACHE is defined nonzero, the string cache
+ * will be searched for an existing String object.
+ * If not found, a new object is created and inserted
+ * into the cache.
+ */
+PmReturn_t
+string_create(PmMemSpace_t memspace, uint8_t const **paddr, int16_t len,
+              int16_t n, pPmObj_t *r_pstring)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmString_t pstr = C_NULL;
+    uint8_t *pdst = C_NULL;
+    uint8_t const *psrc = C_NULL;
+
+#if USE_STRING_CACHE
+    pPmString_t pcacheentry = C_NULL;
+#endif /* USE_STRING_CACHE */
+    uint8_t *pchunk;
+
+    /* If loading from an image, get length from the image */
+    if (len < 0)
+    {
+        len = mem_getWord(memspace, paddr);
+    }
+
+    /* If loading from a C string, get its strlen (first null) */
+    else if (len == 0)
+    {
+        len = sli_strlen((char const *)*paddr);
+    }
+
+    /* Get space for String obj */
+    retval = heap_getChunk(sizeof(PmString_t) + len * n, &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pstr = (pPmString_t)pchunk;
+
+    /* Fill the string obj */
+    OBJ_SET_TYPE(pstr, OBJ_TYPE_STR);
+    pstr->length = len * n;
+
+    /* Copy C-string into String obj */
+    pdst = (uint8_t *)&(pstr->val);
+    while (--n >= 0)
+    {
+        psrc = *paddr;
+        mem_copy(memspace, &pdst, &psrc, len);
+    }
+
+    /* Be sure paddr points to one byte past the end of the source string */
+    *paddr = psrc;
+
+    /* Zero-pad end of string */
+    for (; pdst < (uint8_t *)pstr + PM_OBJ_GET_SIZE(pstr); pdst++)
+    {
+        *pdst = 0;
+    }
+
+#if USE_STRING_CACHE
+    /* Check for twin string in cache */
+    for (pcacheentry = pstrcache;
+         pcacheentry != C_NULL; pcacheentry = pcacheentry->next)
+    {
+        /* If string already exists */
+        if (string_compare(pcacheentry, pstr) == C_SAME)
+        {
+            /* Free the string */
+            retval = heap_freeChunk((pPmObj_t)pstr);
+
+            /* Return ptr to old */
+            *r_pstring = (pPmObj_t)pcacheentry;
+            return retval;
+        }
+    }
+
+    /* Insert string obj into cache */
+    pstr->next = pstrcache;
+    pstrcache = pstr;
+
+#endif /* USE_STRING_CACHE */
+
+    *r_pstring = (pPmObj_t)pstr;
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+string_newFromChar(uint8_t const c, pPmObj_t *r_pstring)
+{
+    PmReturn_t retval;
+    uint8_t cstr[2];
+    uint8_t const *pcstr;
+
+    cstr[0] = c;
+    cstr[1] = '\0';
+    pcstr = cstr;
+
+    retval = string_new(&pcstr, r_pstring);
+
+    /* If c was a null character, force the length to 1 */
+    if (c == '\0')
+    {
+        ((pPmString_t)*r_pstring)->length = 1;
+    }
+
+    return retval;
+}
+
+
+int8_t
+string_compare(pPmString_t pstr1, pPmString_t pstr2)
+{
+    /* Return false if lengths are not equal */
+    if (pstr1->length != pstr2->length)
+    {
+        return C_DIFFER;
+    }
+
+    /* Compare the strings' contents */
+    return sli_strncmp((char const *)&(pstr1->val),
+                       (char const *)&(pstr2->val),
+                       pstr1->length) == 0 ? C_SAME : C_DIFFER;
+}
+
+
+#ifdef HAVE_PRINT
+PmReturn_t
+string_printFormattedBytes(uint8_t *pb, uint8_t is_escaped, uint16_t n)
+{
+    uint16_t i;
+    uint8_t ch;
+    uint8_t nibble;
+    PmReturn_t retval = PM_RET_OK;
+
+    if (is_escaped)
+    {
+        retval = plat_putByte('\'');
+        PM_RETURN_IF_ERROR(retval);
+    }
+
+    for (i = 0; i < n; i++)
+    {
+        ch = pb[i];
+        if (is_escaped && (ch == '\\'))
+        {
+            /* Output an additional backslash to escape it. */
+            retval = plat_putByte('\\');
+            PM_RETURN_IF_ERROR(retval);
+        }
+
+        /* Print the hex escape code of non-printable characters */
+        if (is_escaped
+            && ((ch < (uint8_t)32) || (ch >= (uint8_t)128) || (ch == '\'')))
+        {
+            plat_putByte('\\');
+            plat_putByte('x');
+
+            nibble = (ch >> (uint8_t)4) + '0';
+            if (nibble > '9')
+                nibble += ('a' - '0' - (uint8_t)10);
+            plat_putByte(nibble);
+
+            nibble = (ch & (uint8_t)0x0F) + '0';
+            if (nibble > '9')
+                nibble += ('a' - '0' - (uint8_t)10);
+            plat_putByte(nibble);
+        }
+        else
+        {
+            /* Escape the escape and reply terminator chars */
+            if ((ch == ESCAPE_CHAR) || (ch == REPLY_TERMINATOR))
+            {
+                plat_putByte(ESCAPE_CHAR);
+            }
+
+            /* Output character */
+            retval = plat_putByte(ch);
+            PM_RETURN_IF_ERROR(retval);
+        }
+    }
+    if (is_escaped)
+    {
+        retval = plat_putByte('\'');
+    }
+
+    return retval;
+}
+
+
+PmReturn_t
+string_print(pPmObj_t pstr, uint8_t is_escaped)
+{
+    PmReturn_t retval = PM_RET_OK;
+
+    C_ASSERT(pstr != C_NULL);
+
+    /* Ensure string obj */
+    if (OBJ_GET_TYPE(pstr) != OBJ_TYPE_STR)
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    retval = string_printFormattedBytes(&(((pPmString_t)pstr)->val[0]),
+                                        is_escaped,
+                                        ((pPmString_t)pstr)->length);
+
+    return retval;
+}
+#endif /* HAVE_PRINT */
+
+
+PmReturn_t
+string_cacheInit(void)
+{
+    pstrcache = C_NULL;
+
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+string_getCache(pPmString_t **r_ppstrcache)
+{
+#if USE_STRING_CACHE
+    *r_ppstrcache = &pstrcache;
+#else
+    *r_ppstrcache = C_NULL;
+#endif
+    return PM_RET_OK;
+}
+
+
+PmReturn_t
+string_concat(pPmString_t pstr1, pPmString_t pstr2, pPmObj_t *r_pstring)
+{
+    PmReturn_t retval = PM_RET_OK;
+    pPmString_t pstr = C_NULL;
+    uint8_t *pdst = C_NULL;
+    uint8_t const *psrc = C_NULL;
+#if USE_STRING_CACHE
+    pPmString_t pcacheentry = C_NULL;
+#endif /* USE_STRING_CACHE */
+    uint8_t *pchunk;
+    uint16_t len;
+
+    /* Create the String obj */
+    len = pstr1->length + pstr2->length;
+    retval = heap_getChunk(sizeof(PmString_t) + len, &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pstr = (pPmString_t)pchunk;
+    OBJ_SET_TYPE(pstr, OBJ_TYPE_STR);
+    pstr->length = len;
+
+    /* Concatenate C-strings into String obj and apply null terminator */
+    pdst = (uint8_t *)&(pstr->val);
+    psrc = (uint8_t const *)&(pstr1->val);
+    mem_copy(MEMSPACE_RAM, &pdst, &psrc, pstr1->length);
+    psrc = (uint8_t const *)&(pstr2->val);
+    mem_copy(MEMSPACE_RAM, &pdst, &psrc, pstr2->length);
+    *pdst = '\0';
+
+#if USE_STRING_CACHE
+    /* Check for twin string in cache */
+    for (pcacheentry = pstrcache;
+         pcacheentry != C_NULL; pcacheentry = pcacheentry->next)
+    {
+        /* If string already exists */
+        if (string_compare(pcacheentry, pstr) == C_SAME)
+        {
+            /* Free the string */
+            retval = heap_freeChunk((pPmObj_t)pstr);
+
+            /* Return ptr to old */
+            *r_pstring = (pPmObj_t)pcacheentry;
+            return retval;
+        }
+    }
+
+    /* Insert string obj into cache */
+    pstr->next = pstrcache;
+    pstrcache = pstr;
+#endif /* USE_STRING_CACHE */
+
+    *r_pstring = (pPmObj_t)pstr;
+    return PM_RET_OK;
+}
+
+
+#ifdef HAVE_STRING_FORMAT
+
+#define SIZEOF_FMTDBUF 42
+#define SIZEOF_SMALLFMT 8
+
+PmReturn_t
+string_format(pPmString_t pstr, pPmObj_t parg, pPmObj_t *r_pstring)
+{
+    PmReturn_t retval;
+    uint16_t strsize = 0;
+    uint16_t strindex;
+    uint8_t *fmtcstr;
+    uint8_t smallfmtcstr[SIZEOF_SMALLFMT];
+    uint8_t fmtdbuf[SIZEOF_FMTDBUF];
+    uint8_t i;
+    uint8_t j;
+    uint8_t argtupleindex = 0;
+    pPmObj_t pobj;
+    int fmtretval;
+    uint8_t expectedargcount = 0;
+    pPmString_t pnewstr;
+    uint8_t *pchunk;
+#if USE_STRING_CACHE
+    pPmString_t pcacheentry = C_NULL;
+#endif /* USE_STRING_CACHE */
+
+    /* Get the first arg */
+    pobj = parg;
+
+    /* Calculate the size of the resulting string */
+    fmtcstr = pstr->val;
+    for (i = 0; i < pstr->length; i++)
+    {
+        /* Count non-format chars */
+        if (fmtcstr[i] != '%') { strsize++; continue; }
+
+        /* If double percents, count one percent */
+        if (fmtcstr[++i] == '%') { strsize++; continue; }
+
+        /* Get arg from the tuple */
+        if (OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP)
+        {
+            pobj = ((pPmTuple_t)parg)->val[argtupleindex++];
+        }
+
+        fmtretval = -1;
+
+        /* Format one arg to get its length */
+        smallfmtcstr[0] = '%';
+        for(j = 1; (i < pstr->length) && (j < SIZEOF_SMALLFMT); i++)
+        {
+            smallfmtcstr[j] = fmtcstr[i];
+            j++;
+
+            if ((fmtcstr[i] == 'd')
+                || (fmtcstr[i] == 'x')
+                || (fmtcstr[i] == 'X'))
+            {
+                if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_INT)
+                {
+                    PM_RAISE(retval, PM_RET_EX_TYPE);
+                    return retval;
+                }
+                smallfmtcstr[j] = '\0';
+#ifdef HAVE_SNPRINTF_FORMAT
+                fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
+                    (char *)smallfmtcstr, ((pPmInt_t)pobj)->val);
+#else
+                if (fmtcstr[i] == 'd')
+                {
+                    retval = sli_ltoa10(((pPmInt_t)pobj)->val,
+                                        fmtdbuf,
+                                        sizeof(fmtdbuf));
+                    PM_RETURN_IF_ERROR(retval);
+                }
+                else
+                {
+                    sli_ltoa16(((pPmInt_t)pobj)->val,
+                               fmtdbuf,
+                               sizeof(fmtdbuf),
+                               fmtcstr[i] == 'X');
+                }
+                fmtretval = sli_strlen((char *)fmtdbuf);
+#endif /* HAVE_SNPRINTF_FORMAT */
+                break;
+            }
+
+#ifdef HAVE_FLOAT
+            else if ((fmtcstr[i] == 'f') || (fmtcstr[i] == 'F'))
+            {
+                if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_FLT)
+                {
+                    PM_RAISE(retval, PM_RET_EX_TYPE);
+                    return retval;
+                }
+#ifdef HAVE_SNPRINTF_FORMAT
+                smallfmtcstr[j] = '\0';
+                fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
+                    (char *)smallfmtcstr, ((pPmFloat_t)pobj)->val);
+#else
+                sli_ftoa(((pPmFloat_t)pobj)->val, fmtdbuf, SIZEOF_FMTDBUF);
+                fmtretval = sli_strlen((char *)fmtdbuf);
+#endif /* HAVE_SNPRINTF_FORMAT */
+                break;
+            }
+#endif /* HAVE_FLOAT */
+
+            else if (fmtcstr[i] == 's')
+            {
+                if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_STR)
+                {
+                    PM_RAISE(retval, PM_RET_EX_TYPE);
+                    return retval;
+                }
+
+                /* Skip using snprintf(), just use length of string arg */
+                fmtretval = ((pPmString_t)pobj)->length;
+                break;
+            }
+        }
+
+        /* Raise ValueError if the format string was bad */
+        if (fmtretval < 0)
+        {
+            PM_RAISE(retval, PM_RET_EX_VAL);
+            return retval;
+        }
+
+        expectedargcount++;
+        strsize += fmtretval;
+    }
+
+    /* TypeError wrong number args */
+    if (((OBJ_GET_TYPE(parg) != OBJ_TYPE_TUP) && (expectedargcount != 1))
+        || ((OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP)
+            && (expectedargcount != ((pPmTuple_t)parg)->length)))
+    {
+        PM_RAISE(retval, PM_RET_EX_TYPE);
+        return retval;
+    }
+
+    /* Allocate and initialize String obj */
+    retval = heap_getChunk(sizeof(PmString_t) + strsize, &pchunk);
+    PM_RETURN_IF_ERROR(retval);
+    pnewstr = (pPmString_t)pchunk;
+    OBJ_SET_TYPE(pnewstr, OBJ_TYPE_STR);
+    pnewstr->length = strsize;
+
+    /* Fill contents of String obj */
+    strindex = 0;
+    argtupleindex = 0;
+    pobj = parg;
+
+    for (i = 0; i < pstr->length; i++)
+    {
+        /* Copy non-format chars */
+        if (fmtcstr[i] != '%')
+        {
+            pnewstr->val[strindex++] = fmtcstr[i];
+            continue;
+        }
+
+        /* If double percents, copy one percent */
+        if (fmtcstr[++i] == '%')
+        {
+            pnewstr->val[strindex++] = '%';
+            continue;
+        }
+
+        /* Get arg from the tuple */
+        if (OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP)
+        {
+            pobj = ((pPmTuple_t)parg)->val[argtupleindex++];
+        }
+
+        fmtretval = -1;
+
+        /* Format one arg to get its length */
+        smallfmtcstr[0] = '%';
+        for(j = 1; (i < pstr->length) && (j < SIZEOF_SMALLFMT); i++)
+        {
+            smallfmtcstr[j] = fmtcstr[i];
+            j++;
+
+            if ((fmtcstr[i] == 'd')
+                || (fmtcstr[i] == 'x')
+                || (fmtcstr[i] == 'X'))
+            {
+                smallfmtcstr[j] = '\0';
+#ifdef HAVE_SNPRINTF_FORMAT
+                fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
+                    (char *)smallfmtcstr, ((pPmInt_t)pobj)->val);
+#else
+                if (fmtcstr[i] == 'd')
+                {
+                    retval = sli_ltoa10(((pPmInt_t)pobj)->val,
+                                        fmtdbuf,
+                                        sizeof(fmtdbuf));
+                    PM_RETURN_IF_ERROR(retval);
+                }
+                else
+                {
+                    sli_ltoa16(((pPmInt_t)pobj)->val,
+                               fmtdbuf,
+                               sizeof(fmtdbuf),
+                               fmtcstr[i] == 'X');
+                }
+                fmtretval = sli_strlen((char *)fmtdbuf);
+#endif /* HAVE_SNPRINTF_FORMAT */
+                break;
+            }
+
+#ifdef HAVE_FLOAT
+            else if ((fmtcstr[i] == 'f') || (fmtcstr[i] == 'F'))
+            {
+#ifdef HAVE_SNPRINTF_FORMAT
+                smallfmtcstr[j] = '\0';
+                fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
+                    (char *)smallfmtcstr, ((pPmFloat_t)pobj)->val);
+#else
+                sli_ftoa(((pPmFloat_t)pobj)->val, fmtdbuf, SIZEOF_FMTDBUF);
+                fmtretval = sli_strlen((char *)fmtdbuf);
+#endif /* HAVE_SNPRINTF_FORMAT */
+                break;
+            }
+#endif /* HAVE_FLOAT */
+
+            else if (fmtcstr[i] == 's')
+            {
+#ifdef HAVE_SNPRINTF_FORMAT
+                smallfmtcstr[j] = '\0';
+                fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
+                    (char *)smallfmtcstr, ((pPmString_t)pobj)->val);
+#else
+                sli_memcpy(fmtdbuf, ((pPmString_t)pobj)->val,
+                           ((pPmString_t)pobj)->length);
+                fmtretval = ((pPmString_t)pobj)->length;
+#endif /* HAVE_SNPRINTF_FORMAT */
+                break;
+            }
+        }
+
+        /* Copy formatted C string into new string object */
+        for (j = 0; j < fmtretval; j++)
+        {
+            pnewstr->val[strindex++] = fmtdbuf[j];
+        }
+    }
+    pnewstr->val[strindex] = '\0';
+
+#if USE_STRING_CACHE
+    /* Check for twin string in cache */
+    for (pcacheentry = pstrcache;
+         pcacheentry != C_NULL; pcacheentry = pcacheentry->next)
+    {
+        /* If string already exists */
+        if (string_compare(pcacheentry, pnewstr) == C_SAME)
+        {
+            /* Free the string */
+            retval = heap_freeChunk((pPmObj_t)pnewstr);
+
+            /* Return ptr to old */
+            *r_pstring = (pPmObj_t)pcacheentry;
+            return retval;
+        }
+    }
+
+    /* Insert string obj into cache */
+    pnewstr->next = pstrcache;
+    pstrcache = pnewstr;
+
+#endif /* USE_STRING_CACHE */
+
+    *r_pstring = (pPmObj_t)pnewstr;
+    return PM_RET_OK;
+}
+#endif /* HAVE_STRING_FORMAT */