mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2024-12-05 13:24:11 +01:00
271 lines
6.4 KiB
C
271 lines
6.4 KiB
C
|
/*
|
||
|
# This file is Copyright 2006, 2007, 2009, 2010 Dean Hall.
|
||
|
#
|
||
|
# This file is part of the PyMite VM.
|
||
|
# The PyMite VM is free software: you can redistribute it and/or modify
|
||
|
# it under the terms of the GNU GENERAL PUBLIC LICENSE Version 2.
|
||
|
#
|
||
|
# The PyMite VM is distributed in the hope that it will be useful,
|
||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
# A copy of the GNU GENERAL PUBLIC LICENSE Version 2
|
||
|
# is seen in the file COPYING in this directory.
|
||
|
*/
|
||
|
|
||
|
|
||
|
#undef __FILE_ID__
|
||
|
#define __FILE_ID__ 0x14
|
||
|
|
||
|
|
||
|
/**
|
||
|
* \file
|
||
|
* \brief Sequence
|
||
|
*
|
||
|
* Functions that operate on sequences
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include "pm.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Compares two sequence objects
|
||
|
* Assumes both objects are of same type (guaranteed by obj_compare)
|
||
|
*/
|
||
|
int8_t
|
||
|
seq_compare(pPmObj_t pobj1, pPmObj_t pobj2)
|
||
|
{
|
||
|
int16_t l1;
|
||
|
int16_t l2;
|
||
|
pPmObj_t pa;
|
||
|
pPmObj_t pb;
|
||
|
PmReturn_t retval;
|
||
|
int8_t retcompare;
|
||
|
|
||
|
/* Get the lengths of supported types or return differ */
|
||
|
if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_TUP)
|
||
|
{
|
||
|
l1 = ((pPmTuple_t)pobj1)->length;
|
||
|
l2 = ((pPmTuple_t)pobj2)->length;
|
||
|
}
|
||
|
else if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_LST)
|
||
|
{
|
||
|
l1 = ((pPmList_t)pobj1)->length;
|
||
|
l2 = ((pPmList_t)pobj2)->length;
|
||
|
}
|
||
|
|
||
|
#ifdef HAVE_BYTEARRAY
|
||
|
else if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_BYA)
|
||
|
{
|
||
|
/* Return if the lengths differ */
|
||
|
l1 = ((pPmBytearray_t)pobj1)->length;
|
||
|
l2 = ((pPmBytearray_t)pobj2)->length;
|
||
|
if (l1 != l2)
|
||
|
{
|
||
|
return C_DIFFER;
|
||
|
}
|
||
|
|
||
|
return sli_strncmp((char const *)&(((pPmBytes_t)((pPmBytearray_t)pobj1)->val)->val),
|
||
|
(char const *)&(((pPmBytes_t)((pPmBytearray_t)pobj2)->val)->val),
|
||
|
l1)
|
||
|
? C_DIFFER : C_SAME;
|
||
|
}
|
||
|
#endif /* HAVE_BYTEARRAY */
|
||
|
|
||
|
else
|
||
|
{
|
||
|
return C_DIFFER;
|
||
|
}
|
||
|
|
||
|
/* Return if the lengths differ */
|
||
|
if (l1 != l2)
|
||
|
{
|
||
|
return C_DIFFER;
|
||
|
}
|
||
|
|
||
|
/* Compare all items in the sequences */
|
||
|
while (--l1 >= 0)
|
||
|
{
|
||
|
retval = seq_getSubscript(pobj1, l1, &pa);
|
||
|
if (retval != PM_RET_OK)
|
||
|
{
|
||
|
return C_DIFFER;
|
||
|
}
|
||
|
retval = seq_getSubscript(pobj2, l1, &pb);
|
||
|
if (retval != PM_RET_OK)
|
||
|
{
|
||
|
return C_DIFFER;
|
||
|
}
|
||
|
retcompare = obj_compare(pa, pb);
|
||
|
if (retcompare != C_SAME)
|
||
|
{
|
||
|
return retcompare;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return C_SAME;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Returns the length of the sequence */
|
||
|
PmReturn_t
|
||
|
seq_getLength(pPmObj_t pobj, int16_t *r_index)
|
||
|
{
|
||
|
PmReturn_t retval = PM_RET_OK;
|
||
|
|
||
|
switch (OBJ_GET_TYPE(pobj))
|
||
|
{
|
||
|
case OBJ_TYPE_STR:
|
||
|
*r_index = ((pPmString_t)pobj)->length;
|
||
|
break;
|
||
|
|
||
|
case OBJ_TYPE_TUP:
|
||
|
*r_index = ((pPmTuple_t)pobj)->length;
|
||
|
break;
|
||
|
|
||
|
case OBJ_TYPE_LST:
|
||
|
*r_index = ((pPmList_t)pobj)->length;
|
||
|
break;
|
||
|
|
||
|
#ifdef HAVE_BYTEARRAY
|
||
|
case OBJ_TYPE_BYA:
|
||
|
*r_index = ((pPmBytearray_t)pobj)->length;
|
||
|
break;
|
||
|
#endif /* HAVE_BYTEARRAY */
|
||
|
|
||
|
default:
|
||
|
/* Raise TypeError, non-sequence object */
|
||
|
PM_RAISE(retval, PM_RET_EX_TYPE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Returns the object sequence[index] */
|
||
|
PmReturn_t
|
||
|
seq_getSubscript(pPmObj_t pobj, int16_t index, pPmObj_t *r_pobj)
|
||
|
{
|
||
|
PmReturn_t retval;
|
||
|
uint8_t c;
|
||
|
|
||
|
switch (OBJ_GET_TYPE(pobj))
|
||
|
{
|
||
|
case OBJ_TYPE_STR:
|
||
|
/* Adjust for negative index */
|
||
|
if (index < 0)
|
||
|
{
|
||
|
index += ((pPmString_t)pobj)->length;
|
||
|
}
|
||
|
|
||
|
/* Raise IndexError if index is out of bounds */
|
||
|
if ((index < 0) || (index > ((pPmString_t)pobj)->length))
|
||
|
{
|
||
|
PM_RAISE(retval, PM_RET_EX_INDX);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Get the character from the string */
|
||
|
c = ((pPmString_t)pobj)->val[index];
|
||
|
|
||
|
/* Create a new string from the character */
|
||
|
retval = string_newFromChar(c, r_pobj);
|
||
|
break;
|
||
|
|
||
|
case OBJ_TYPE_TUP:
|
||
|
/* Get the tuple item */
|
||
|
retval = tuple_getItem(pobj, index, r_pobj);
|
||
|
break;
|
||
|
|
||
|
case OBJ_TYPE_LST:
|
||
|
/* Get the list item */
|
||
|
retval = list_getItem(pobj, index, r_pobj);
|
||
|
break;
|
||
|
|
||
|
#ifdef HAVE_BYTEARRAY
|
||
|
case OBJ_TYPE_BYA:
|
||
|
retval = bytearray_getItem(pobj, index, r_pobj);
|
||
|
break;
|
||
|
#endif /* HAVE_BYTEARRAY */
|
||
|
|
||
|
default:
|
||
|
/* Raise TypeError, unsubscriptable object */
|
||
|
PM_RAISE(retval, PM_RET_EX_TYPE);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
PmReturn_t
|
||
|
seqiter_getNext(pPmObj_t pobj, pPmObj_t *r_pitem)
|
||
|
{
|
||
|
PmReturn_t retval;
|
||
|
int16_t length;
|
||
|
|
||
|
C_ASSERT(pobj != C_NULL);
|
||
|
C_ASSERT(*r_pitem != C_NULL);
|
||
|
C_ASSERT(OBJ_GET_TYPE(pobj) == OBJ_TYPE_SQI);
|
||
|
|
||
|
/*
|
||
|
* Raise TypeError if sequence iterator's object is not a sequence
|
||
|
* otherwise, the get sequence's length
|
||
|
*/
|
||
|
retval = seq_getLength(((pPmSeqIter_t)pobj)->si_sequence, &length);
|
||
|
PM_RETURN_IF_ERROR(retval);
|
||
|
|
||
|
/* Raise StopIteration if at the end of the sequence */
|
||
|
if (((pPmSeqIter_t)pobj)->si_index == length)
|
||
|
{
|
||
|
/* Make null the pointer to the sequence */
|
||
|
((pPmSeqIter_t)pobj)->si_sequence = C_NULL;
|
||
|
PM_RAISE(retval, PM_RET_EX_STOP);
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
/* Get the item at the current index */
|
||
|
retval = seq_getSubscript(((pPmSeqIter_t)pobj)->si_sequence,
|
||
|
((pPmSeqIter_t)pobj)->si_index, r_pitem);
|
||
|
|
||
|
/* Increment the index */
|
||
|
((pPmSeqIter_t)pobj)->si_index++;
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
PmReturn_t
|
||
|
seqiter_new(pPmObj_t pobj, pPmObj_t *r_pobj)
|
||
|
{
|
||
|
PmReturn_t retval;
|
||
|
uint8_t *pchunk;
|
||
|
pPmSeqIter_t psi;
|
||
|
|
||
|
C_ASSERT(pobj != C_NULL);
|
||
|
C_ASSERT(*r_pobj != C_NULL);
|
||
|
|
||
|
/* Raise a TypeError if pobj is not a sequence */
|
||
|
if ((OBJ_GET_TYPE(pobj) != OBJ_TYPE_STR)
|
||
|
&& (OBJ_GET_TYPE(pobj) != OBJ_TYPE_TUP)
|
||
|
&& (OBJ_GET_TYPE(pobj) != OBJ_TYPE_LST))
|
||
|
{
|
||
|
PM_RAISE(retval, PM_RET_EX_TYPE);
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
/* Alloc a chunk for the sequence iterator obj */
|
||
|
retval = heap_getChunk(sizeof(PmSeqIter_t), &pchunk);
|
||
|
PM_RETURN_IF_ERROR(retval);
|
||
|
|
||
|
/* Set the sequence iterator's fields */
|
||
|
psi = (pPmSeqIter_t)pchunk;
|
||
|
OBJ_SET_TYPE(psi, OBJ_TYPE_SQI);
|
||
|
psi->si_sequence = pobj;
|
||
|
psi->si_index = 0;
|
||
|
|
||
|
*r_pobj = (pPmObj_t)psi;
|
||
|
return retval;
|
||
|
}
|