Merged in f5soh/librepilot/update_credits (pull request #529)
[librepilot.git] / flight / libraries / PyMite / vm / obj.c
bloba12fbd3b03932f67db7e51f6bc088b31c3fdd8d9
1 /*
2 # This file is Copyright 2003, 2006, 2007, 2009, 2010 Dean Hall.
4 # This file is part of the PyMite VM.
5 # The PyMite VM is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU GENERAL PUBLIC LICENSE Version 2.
8 # The PyMite VM is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 # A copy of the GNU GENERAL PUBLIC LICENSE Version 2
12 # is seen in the file COPYING in this directory.
16 #undef __FILE_ID__
17 #define __FILE_ID__ 0x0F
20 /**
21 * \file
22 * \brief Object Type
24 * Object type operations.
28 #include "pm.h"
31 PmReturn_t
32 obj_loadFromImg(PmMemSpace_t memspace,
33 uint8_t const **paddr, pPmObj_t *r_pobj)
35 PmReturn_t retval = PM_RET_OK;
36 PmObj_t obj;
39 /* Get the object descriptor */
40 obj.od = (PmObjDesc_t)0x0000;
41 OBJ_SET_TYPE(&obj, mem_getByte(memspace, paddr));
43 switch (OBJ_GET_TYPE(&obj))
45 case OBJ_TYPE_NON:
46 /* If it's the None object, return global None */
47 *r_pobj = PM_NONE;
48 break;
50 case OBJ_TYPE_INT:
51 /* Read an integer and create an integer object with the value */
52 retval = int_new(mem_getInt(memspace, paddr), r_pobj);
53 break;
55 #ifdef HAVE_FLOAT
56 case OBJ_TYPE_FLT:
57 /* Read a float and create an float object with the value */
58 retval = float_new(mem_getFloat(memspace, paddr), r_pobj);
59 break;
60 #endif /* HAVE_FLOAT */
62 case OBJ_TYPE_STR:
63 retval = string_loadFromImg(memspace, paddr, r_pobj);
64 break;
66 case OBJ_TYPE_TUP:
67 retval = tuple_loadFromImg(memspace, paddr, r_pobj);
68 break;
70 case OBJ_TYPE_NIM:
71 /* If it's a native code img, load into a code obj */
72 retval = no_loadFromImg(memspace, paddr, r_pobj);
73 break;
75 case OBJ_TYPE_CIM:
76 /* If it's a code img, load into a code obj */
77 retval = co_loadFromImg(memspace, paddr, r_pobj);
78 break;
80 default:
81 /* All other types should not be in an img obj */
82 PM_RAISE(retval, PM_RET_EX_SYS);
83 break;
85 return retval;
89 PmReturn_t
90 obj_loadFromImgObj(pPmObj_t pimg, pPmObj_t *r_pobj)
92 uint8_t const *imgaddr;
93 PmReturn_t retval;
95 C_ASSERT(OBJ_GET_TYPE(pimg) == OBJ_TYPE_CIO);
96 imgaddr = (uint8_t const *)&(((pPmCodeImgObj_t)pimg)->val);
98 retval = obj_loadFromImg(MEMSPACE_RAM, &imgaddr, r_pobj);
99 C_ASSERT(OBJ_GET_TYPE(*r_pobj) == OBJ_TYPE_COB);
101 /* All COs must reference the top of the code img obj
102 * so the image is marked and prevented from being reclaimed */
103 co_rSetCodeImgAddr((pPmCo_t)*r_pobj, (uint8_t const *)pimg);
105 return retval;
109 /* Returns true if the obj is false */
110 int8_t
111 obj_isFalse(pPmObj_t pobj)
113 C_ASSERT(pobj != C_NULL);
115 switch (OBJ_GET_TYPE(pobj))
117 case OBJ_TYPE_NON:
118 /* None evaluates to false, so return true */
119 return C_TRUE;
121 case OBJ_TYPE_INT:
122 /* Only the integer zero is false */
123 return ((pPmInt_t)pobj)->val == 0;
125 #ifdef HAVE_FLOAT
126 case OBJ_TYPE_FLT:
127 /* The floats 0.0 and -0.0 are false */
128 return (((pPmFloat_t) pobj)->val == 0.0)
129 || (((pPmFloat_t) pobj)->val == -0.0);
130 #endif /* HAVE_FLOAT */
132 case OBJ_TYPE_STR:
133 /* An empty string is false */
134 return ((pPmString_t)pobj)->length == 0;
136 case OBJ_TYPE_TUP:
137 /* An empty tuple is false */
138 return ((pPmTuple_t)pobj)->length == 0;
140 case OBJ_TYPE_LST:
141 /* An empty list is false */
142 return ((pPmList_t)pobj)->length == 0;
144 case OBJ_TYPE_DIC:
145 /* An empty dict is false */
146 return ((pPmDict_t)pobj)->length == 0;
148 case OBJ_TYPE_BOOL:
149 /* C int zero means false */
150 return ((pPmBoolean_t) pobj)->val == 0;
152 default:
154 * The following types are always not false:
155 * CodeObj, Function, Module, Class, ClassInstance.
157 return C_FALSE;
162 /* Returns true if the item is in the container object */
163 PmReturn_t
164 obj_isIn(pPmObj_t pobj, pPmObj_t pitem)
166 PmReturn_t retval = PM_RET_NO;
167 pPmObj_t ptestItem;
168 int16_t i;
169 uint8_t c;
171 switch (OBJ_GET_TYPE(pobj))
173 case OBJ_TYPE_TUP:
174 /* Iterate over tuple to find item */
175 for (i = 0; i < ((pPmTuple_t)pobj)->length; i++)
177 PM_RETURN_IF_ERROR(tuple_getItem(pobj, i, &ptestItem));
179 if (obj_compare(pitem, ptestItem) == C_SAME)
181 retval = PM_RET_OK;
182 break;
185 break;
187 case OBJ_TYPE_STR:
188 /* Raise a TypeError if item is not a string */
189 if ((OBJ_GET_TYPE(pitem) != OBJ_TYPE_STR))
191 retval = PM_RET_EX_TYPE;
192 break;
195 /* Empty string is alway present */
196 if (((pPmString_t)pitem)->length == 0)
198 retval = PM_RET_OK;
199 break;
202 /* Raise a ValueError if the string is more than 1 char */
203 else if (((pPmString_t)pitem)->length != 1)
205 retval = PM_RET_EX_VAL;
206 break;
209 /* Iterate over string to find char */
210 c = ((pPmString_t)pitem)->val[0];
211 for (i = 0; i < ((pPmString_t)pobj)->length; i++)
213 if (c == ((pPmString_t)pobj)->val[i])
215 retval = PM_RET_OK;
216 break;
219 break;
221 case OBJ_TYPE_LST:
222 /* Iterate over list to find item */
223 for (i = 0; i < ((pPmList_t)pobj)->length; i++)
225 PM_RETURN_IF_ERROR(list_getItem(pobj, i, &ptestItem));
227 if (obj_compare(pitem, ptestItem) == C_SAME)
229 retval = PM_RET_OK;
230 break;
233 break;
235 case OBJ_TYPE_DIC:
236 /* Check if the item is one of the keys of the dict */
237 retval = dict_getItem(pobj, pitem, &ptestItem);
238 if (retval == PM_RET_EX_KEY)
240 retval = PM_RET_NO;
242 break;
244 default:
245 retval = PM_RET_EX_TYPE;
246 break;
249 return retval;
253 int8_t
254 obj_compare(pPmObj_t pobj1, pPmObj_t pobj2)
256 #ifdef HAVE_BYTEARRAY
257 PmReturn_t retval;
258 pPmObj_t pobj;
259 #endif /* HAVE_BYTEARRAY */
261 C_ASSERT(pobj1 != C_NULL);
262 C_ASSERT(pobj2 != C_NULL);
264 /* Check if pointers are same */
265 if (pobj1 == pobj2)
267 return C_SAME;
270 /* If types are different, objs must differ */
271 if (OBJ_GET_TYPE(pobj1) != OBJ_GET_TYPE(pobj2))
273 return C_DIFFER;
276 #ifdef HAVE_BYTEARRAY
277 /* If object is an instance, get the thing it contains */
278 if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLI)
280 retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj1)->cli_attrs,
281 PM_NONE,
282 &pobj);
283 PM_RETURN_IF_ERROR(retval);
284 pobj1 = pobj;
286 if (OBJ_GET_TYPE(pobj2) == OBJ_TYPE_CLI)
288 retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj2)->cli_attrs,
289 PM_NONE,
290 &pobj);
291 PM_RETURN_IF_ERROR(retval);
292 pobj2 = pobj;
295 /* If types are different, objs must differ */
296 if (OBJ_GET_TYPE(pobj1) != OBJ_GET_TYPE(pobj2))
298 return C_DIFFER;
300 #endif /* HAVE_BYTEARRAY */
302 /* Otherwise handle types individually */
303 switch (OBJ_GET_TYPE(pobj1))
305 case OBJ_TYPE_NON:
306 return C_SAME;
308 case OBJ_TYPE_INT:
309 return ((pPmInt_t)pobj1)->val ==
310 ((pPmInt_t)pobj2)->val ? C_SAME : C_DIFFER;
312 #ifdef HAVE_FLOAT
313 case OBJ_TYPE_FLT:
315 pPmObj_t r_pobj;
317 float_compare(pobj1, pobj2, &r_pobj, COMP_EQ);
318 return (r_pobj == PM_TRUE) ? C_SAME : C_DIFFER;
320 #endif /* HAVE_FLOAT */
322 case OBJ_TYPE_STR:
323 return string_compare((pPmString_t)pobj1, (pPmString_t)pobj2);
325 case OBJ_TYPE_TUP:
326 case OBJ_TYPE_LST:
327 #ifdef HAVE_BYTEARRAY
328 case OBJ_TYPE_BYA:
329 #endif /* HAVE_BYTEARRAY */
330 return seq_compare(pobj1, pobj2);
332 case OBJ_TYPE_DIC:
333 /* #17: PyMite does not support Dict comparisons (yet) */
334 default:
335 break;
338 /* All other types would need same pointer to be true */
339 return C_DIFFER;
343 #ifdef HAVE_PRINT
344 PmReturn_t
345 obj_print(pPmObj_t pobj, uint8_t is_expr_repr, uint8_t is_nested)
347 PmReturn_t retval = PM_RET_OK;
349 C_ASSERT(pobj != C_NULL);
351 /* Something gets printed unless it's None in an unnested expression */
352 if (!((OBJ_GET_TYPE(pobj) == OBJ_TYPE_NON) && is_expr_repr && !is_nested))
354 gVmGlobal.somethingPrinted = C_TRUE;
357 switch (OBJ_GET_TYPE(pobj))
359 case OBJ_TYPE_NON:
360 if (!is_expr_repr || is_nested)
362 plat_putByte('N');
363 plat_putByte('o');
364 plat_putByte('n');
365 retval = plat_putByte('e');
367 break;
368 case OBJ_TYPE_INT:
369 retval = int_print(pobj);
370 break;
371 #ifdef HAVE_FLOAT
372 case OBJ_TYPE_FLT:
373 retval = float_print(pobj);
374 break;
375 #endif /* HAVE_FLOAT */
376 case OBJ_TYPE_STR:
377 retval = string_print(pobj, (is_expr_repr || is_nested));
378 break;
379 case OBJ_TYPE_TUP:
380 retval = tuple_print(pobj);
381 break;
382 case OBJ_TYPE_LST:
383 retval = list_print(pobj);
384 break;
385 case OBJ_TYPE_DIC:
386 retval = dict_print(pobj);
387 break;
388 case OBJ_TYPE_BOOL:
389 if (((pPmBoolean_t) pobj)->val == C_TRUE)
391 plat_putByte('T');
392 plat_putByte('r');
393 plat_putByte('u');
395 else
397 plat_putByte('F');
398 plat_putByte('a');
399 plat_putByte('l');
400 plat_putByte('s');
402 retval = plat_putByte('e');
403 break;
405 case OBJ_TYPE_CLI:
406 #ifdef HAVE_BYTEARRAY
408 pPmObj_t pobj2;
410 retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj)->cli_attrs,
411 PM_NONE,
412 (pPmObj_t *)&pobj2);
413 if ((retval == PM_RET_OK)
414 && (OBJ_GET_TYPE(pobj2) == OBJ_TYPE_BYA))
416 retval = bytearray_print(pobj2);
417 break;
420 #endif /* HAVE_BYTEARRAY */
422 case OBJ_TYPE_COB:
423 case OBJ_TYPE_MOD:
424 case OBJ_TYPE_CLO:
425 case OBJ_TYPE_FXN:
426 case OBJ_TYPE_CIM:
427 case OBJ_TYPE_NIM:
428 case OBJ_TYPE_NOB:
429 case OBJ_TYPE_THR:
430 case OBJ_TYPE_CIO:
431 case OBJ_TYPE_MTH:
432 case OBJ_TYPE_SQI:
433 plat_putByte('<');
434 plat_putByte('o');
435 plat_putByte('b');
436 plat_putByte('j');
437 plat_putByte(' ');
438 plat_putByte('t');
439 plat_putByte('y');
440 plat_putByte('p');
441 plat_putByte('e');
442 plat_putByte(' ');
443 plat_putByte('0');
444 plat_putByte('x');
445 int_printHexByte(OBJ_GET_TYPE(pobj));
446 plat_putByte(' ');
447 plat_putByte('@');
448 plat_putByte(' ');
449 plat_putByte('0');
450 plat_putByte('x');
451 _int_printHex((intptr_t)pobj);
452 retval = plat_putByte('>');
453 break;
455 default:
456 /* Otherwise raise a TypeError */
457 PM_RAISE(retval, PM_RET_EX_TYPE);
458 break;
460 return retval;
462 #endif /* HAVE_PRINT */
465 #ifdef HAVE_BACKTICK
466 PmReturn_t
467 obj_repr(pPmObj_t pobj, pPmObj_t *r_pstr)
469 uint8_t tBuffer[32];
470 uint8_t bytesWritten = 0;
471 PmReturn_t retval = PM_RET_OK;
472 uint8_t const *pcstr = (uint8_t *)tBuffer;;
474 C_ASSERT(pobj != C_NULL);
476 switch (OBJ_GET_TYPE(pobj))
478 case OBJ_TYPE_INT:
479 bytesWritten = snprintf((char *)&tBuffer, sizeof(tBuffer), "%li",
480 (long)((pPmInt_t)pobj)->val);
481 retval = string_new(&pcstr, r_pstr);
482 break;
484 #ifdef HAVE_FLOAT
485 case OBJ_TYPE_FLT:
486 bytesWritten = snprintf((char *)&tBuffer, sizeof(tBuffer), "%f",
487 ((pPmFloat_t)pobj)->val);
488 retval = string_new(&pcstr, r_pstr);
489 break;
490 #endif /* HAVE_FLOAT */
492 default:
493 /* Otherwise raise a TypeError */
494 PM_RAISE(retval, PM_RET_EX_TYPE);
495 break;
498 /* Sanity check */
499 C_ASSERT(bytesWritten < sizeof(tBuffer));
501 return retval;
503 #endif /* HAVE_BACKTICK */