Davi Souza
/
pymite
python
Fork of pymite by
Revision 0:65f1469d6bfb, committed 2013-03-02
- Comitter:
- va009039
- Date:
- Sat Mar 02 11:54:20 2013 +0000
- Child:
- 1:28afb064a41c
- Commit message:
- first commit
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/3d0ef94e36ec \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/platform/mbed/main.cpp Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,41 @@ +/* +# This file is Copyright 2009 Dean Hall. +# +# This file is part of the Python-on-a-Chip program. +# Python-on-a-Chip is free software: you can redistribute it and/or modify +# it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1. +# +# Python-on-a-Chip 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 LESSER GENERAL PUBLIC LICENSE Version 2.1 +# is seen in the file COPYING up one directory from this. +*/ + + +#include "pm.h" + + +#ifdef __cplusplus +extern +#endif + +#define HEAP_SIZE 0x7000 + +unsigned char const usrlib_img[]; + + +int +main(void) +{ + uint8_t heap[HEAP_SIZE]; + PmReturn_t retval; + + retval = pm_init(heap, HEAP_SIZE, MEMSPACE_PROG, usrlib_img); + PM_RETURN_IF_ERROR(retval); + + /* Run the sample program */ + retval = pm_run((uint8_t *)"main"); + + return (int)retval; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/platform/mbed/main_img.cpp Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,274 @@ +/** + * PyMite library image file. + * + * Automatically created from: + * main.py + * mbed.py + * img-list-terminator + * by pmImgCreator.py on + * Sat Mar 02 20:27:03 2013. + * + * Byte count: 1916 + * + * Selected memspace type: RAM + * + * DO NOT EDIT THIS FILE. + * ANY CHANGES WILL BE LOST. + */ + +/* Place the image into RAM */ +#ifdef __cplusplus +extern +#endif +unsigned char const +usrlib_img[32368] = +{ + + +/* main.py */ + 0x0A, 0x5D, 0x00, 0x00, 0x40, 0x03, 0x00, 0x00, + 0x0D, 0x00, 0x04, 0x03, 0x03, 0x03, 0x00, 0x69, + 0x70, 0x6D, 0x03, 0x07, 0x00, 0x67, 0x6C, 0x6F, + 0x62, 0x61, 0x6C, 0x73, 0x03, 0x04, 0x00, 0x6D, + 0x61, 0x69, 0x6E, 0x03, 0x02, 0x00, 0x0C, 0x01, + 0x03, 0x08, 0x00, 0x6D, 0x61, 0x69, 0x6E, 0x2E, + 0x70, 0x79, 0x00, 0x04, 0x02, 0x01, 0xFF, 0xFF, + 0xFF, 0xFF, 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, + 0x64, 0x01, 0x00, 0x6B, 0x00, 0x00, 0x5A, 0x00, + 0x00, 0x65, 0x00, 0x00, 0x69, 0x00, 0x00, 0x65, + 0x01, 0x00, 0x83, 0x00, 0x00, 0x83, 0x01, 0x00, + 0x01, 0x64, 0x01, 0x00, 0x53, + +/* mbed.py */ + 0x0A, 0x1E, 0x07, 0x00, 0x40, 0x03, 0x00, 0x00, + 0x1D, 0x00, 0x04, 0x0C, 0x03, 0x07, 0x00, 0x5F, + 0x5F, 0x64, 0x6F, 0x63, 0x5F, 0x5F, 0x03, 0x06, + 0x00, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x03, + 0x08, 0x00, 0x41, 0x6E, 0x61, 0x6C, 0x6F, 0x67, + 0x49, 0x6E, 0x03, 0x09, 0x00, 0x41, 0x6E, 0x61, + 0x6C, 0x6F, 0x67, 0x4F, 0x75, 0x74, 0x03, 0x09, + 0x00, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, 0x6C, + 0x49, 0x6E, 0x03, 0x0A, 0x00, 0x44, 0x69, 0x67, + 0x69, 0x74, 0x61, 0x6C, 0x4F, 0x75, 0x74, 0x03, + 0x06, 0x00, 0x50, 0x77, 0x6D, 0x4F, 0x75, 0x74, + 0x03, 0x06, 0x00, 0x53, 0x65, 0x72, 0x69, 0x61, + 0x6C, 0x03, 0x03, 0x00, 0x53, 0x50, 0x49, 0x03, + 0x03, 0x00, 0x49, 0x32, 0x43, 0x03, 0x07, 0x00, + 0x73, 0x65, 0x74, 0x5F, 0x6C, 0x65, 0x64, 0x03, + 0x04, 0x00, 0x6D, 0x62, 0x65, 0x64, 0x03, 0x14, + 0x00, 0x06, 0x03, 0x16, 0x6F, 0x16, 0xA9, 0x16, + 0x4E, 0x16, 0x76, 0x16, 0xFF, 0x00, 0x3F, 0x16, + 0xA3, 0x16, 0xB7, 0x16, 0xB8, 0x03, 0x08, 0x00, + 0x6D, 0x62, 0x65, 0x64, 0x2E, 0x70, 0x79, 0x00, + 0x04, 0x13, 0x00, 0x03, 0x08, 0x00, 0x41, 0x6E, + 0x61, 0x6C, 0x6F, 0x67, 0x49, 0x6E, 0x0A, 0x93, + 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x20, 0x00, + 0x04, 0x06, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, + 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, + 0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, + 0x5F, 0x5F, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x69, + 0x6E, 0x69, 0x74, 0x5F, 0x5F, 0x03, 0x08, 0x00, + 0x72, 0x65, 0x61, 0x64, 0x5F, 0x75, 0x31, 0x36, + 0x03, 0x04, 0x00, 0x72, 0x65, 0x61, 0x64, 0x03, + 0x08, 0x00, 0x41, 0x6E, 0x61, 0x6C, 0x6F, 0x67, + 0x49, 0x6E, 0x03, 0x06, 0x00, 0x06, 0x02, 0x09, + 0x2B, 0x09, 0x21, 0x03, 0x08, 0x00, 0x6D, 0x62, + 0x65, 0x64, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x03, + 0x0B, 0x02, 0xFF, 0xFF, 0x0B, 0x01, 0xFE, 0xFF, + 0x0B, 0x01, 0xFD, 0xFF, 0x04, 0x00, 0x65, 0x00, + 0x00, 0x5A, 0x01, 0x00, 0x64, 0x00, 0x00, 0x84, + 0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, 0x01, 0x00, + 0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, 0x64, 0x02, + 0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x52, + 0x53, 0x03, 0x09, 0x00, 0x41, 0x6E, 0x61, 0x6C, + 0x6F, 0x67, 0x4F, 0x75, 0x74, 0x0A, 0xAC, 0x00, + 0x00, 0x42, 0x01, 0x00, 0x00, 0x8F, 0x00, 0x04, + 0x07, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, + 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 0x5F, + 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x5F, + 0x5F, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x69, 0x6E, + 0x69, 0x74, 0x5F, 0x5F, 0x03, 0x09, 0x00, 0x77, + 0x72, 0x69, 0x74, 0x65, 0x5F, 0x75, 0x31, 0x36, + 0x03, 0x05, 0x00, 0x77, 0x72, 0x69, 0x74, 0x65, + 0x03, 0x04, 0x00, 0x72, 0x65, 0x61, 0x64, 0x03, + 0x09, 0x00, 0x41, 0x6E, 0x61, 0x6C, 0x6F, 0x67, + 0x4F, 0x75, 0x74, 0x03, 0x08, 0x00, 0x06, 0x02, + 0x09, 0x2C, 0x09, 0x28, 0x09, 0x32, 0x03, 0x08, + 0x00, 0x6D, 0x62, 0x65, 0x64, 0x2E, 0x70, 0x79, + 0x00, 0x04, 0x04, 0x0B, 0x02, 0xFC, 0xFF, 0x0B, + 0x02, 0xFB, 0xFF, 0x0B, 0x02, 0xFA, 0xFF, 0x0B, + 0x01, 0xF9, 0xFF, 0x04, 0x00, 0x65, 0x00, 0x00, + 0x5A, 0x01, 0x00, 0x64, 0x00, 0x00, 0x84, 0x00, + 0x00, 0x5A, 0x02, 0x00, 0x64, 0x01, 0x00, 0x84, + 0x00, 0x00, 0x5A, 0x03, 0x00, 0x64, 0x02, 0x00, + 0x84, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x64, 0x03, + 0x00, 0x84, 0x00, 0x00, 0x5A, 0x05, 0x00, 0x52, + 0x53, 0x03, 0x09, 0x00, 0x44, 0x69, 0x67, 0x69, + 0x74, 0x61, 0x6C, 0x49, 0x6E, 0x0A, 0x7A, 0x00, + 0x00, 0x42, 0x01, 0x00, 0x00, 0x38, 0x01, 0x04, + 0x05, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, + 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 0x5F, + 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x5F, + 0x5F, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x69, 0x6E, + 0x69, 0x74, 0x5F, 0x5F, 0x03, 0x04, 0x00, 0x72, + 0x65, 0x61, 0x64, 0x03, 0x09, 0x00, 0x44, 0x69, + 0x67, 0x69, 0x74, 0x61, 0x6C, 0x49, 0x6E, 0x03, + 0x04, 0x00, 0x06, 0x02, 0x09, 0x2B, 0x03, 0x08, + 0x00, 0x6D, 0x62, 0x65, 0x64, 0x2E, 0x70, 0x79, + 0x00, 0x04, 0x02, 0x0B, 0x02, 0xF8, 0xFF, 0x0B, + 0x01, 0xF7, 0xFF, 0x04, 0x00, 0x65, 0x00, 0x00, + 0x5A, 0x01, 0x00, 0x64, 0x00, 0x00, 0x84, 0x00, + 0x00, 0x5A, 0x02, 0x00, 0x64, 0x01, 0x00, 0x84, + 0x00, 0x00, 0x5A, 0x03, 0x00, 0x52, 0x53, 0x03, + 0x0A, 0x00, 0x44, 0x69, 0x67, 0x69, 0x74, 0x61, + 0x6C, 0x4F, 0x75, 0x74, 0x0A, 0x92, 0x00, 0x00, + 0x42, 0x01, 0x00, 0x00, 0x86, 0x01, 0x04, 0x06, + 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, 0x6D, + 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 0x5F, 0x5F, + 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x5F, 0x5F, + 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x69, 0x6E, 0x69, + 0x74, 0x5F, 0x5F, 0x03, 0x04, 0x00, 0x72, 0x65, + 0x61, 0x64, 0x03, 0x05, 0x00, 0x77, 0x72, 0x69, + 0x74, 0x65, 0x03, 0x0A, 0x00, 0x44, 0x69, 0x67, + 0x69, 0x74, 0x61, 0x6C, 0x4F, 0x75, 0x74, 0x03, + 0x06, 0x00, 0x06, 0x02, 0x09, 0x2B, 0x09, 0x21, + 0x03, 0x08, 0x00, 0x6D, 0x62, 0x65, 0x64, 0x2E, + 0x70, 0x79, 0x00, 0x04, 0x03, 0x0B, 0x02, 0xF6, + 0xFF, 0x0B, 0x01, 0xF5, 0xFF, 0x0B, 0x02, 0xF4, + 0xFF, 0x04, 0x00, 0x65, 0x00, 0x00, 0x5A, 0x01, + 0x00, 0x64, 0x00, 0x00, 0x84, 0x00, 0x00, 0x5A, + 0x02, 0x00, 0x64, 0x01, 0x00, 0x84, 0x00, 0x00, + 0x5A, 0x03, 0x00, 0x64, 0x02, 0x00, 0x84, 0x00, + 0x00, 0x5A, 0x04, 0x00, 0x52, 0x53, 0x03, 0x06, + 0x00, 0x50, 0x77, 0x6D, 0x4F, 0x75, 0x74, 0x0A, + 0x1F, 0x01, 0x00, 0x42, 0x01, 0x00, 0x00, 0xFC, + 0x01, 0x04, 0x0B, 0x03, 0x08, 0x00, 0x5F, 0x5F, + 0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, + 0x00, 0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, + 0x65, 0x5F, 0x5F, 0x03, 0x08, 0x00, 0x5F, 0x5F, + 0x69, 0x6E, 0x69, 0x74, 0x5F, 0x5F, 0x03, 0x04, + 0x00, 0x72, 0x65, 0x61, 0x64, 0x03, 0x06, 0x00, + 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x03, 0x09, + 0x00, 0x70, 0x65, 0x72, 0x69, 0x6F, 0x64, 0x5F, + 0x6D, 0x73, 0x03, 0x09, 0x00, 0x70, 0x65, 0x72, + 0x69, 0x6F, 0x64, 0x5F, 0x75, 0x73, 0x03, 0x0A, + 0x00, 0x70, 0x75, 0x6C, 0x73, 0x65, 0x77, 0x69, + 0x64, 0x74, 0x68, 0x03, 0x0D, 0x00, 0x70, 0x75, + 0x73, 0x6C, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x5F, 0x6D, 0x73, 0x03, 0x0D, 0x00, 0x70, 0x75, + 0x6C, 0x73, 0x65, 0x77, 0x69, 0x64, 0x74, 0x68, + 0x5F, 0x75, 0x73, 0x03, 0x06, 0x00, 0x50, 0x77, + 0x6D, 0x4F, 0x75, 0x74, 0x03, 0x10, 0x00, 0x06, + 0x02, 0x09, 0x2B, 0x09, 0x21, 0x09, 0x28, 0x09, + 0x28, 0x09, 0x28, 0x09, 0x28, 0x09, 0x28, 0x03, + 0x08, 0x00, 0x6D, 0x62, 0x65, 0x64, 0x2E, 0x70, + 0x79, 0x00, 0x04, 0x08, 0x0B, 0x02, 0xF3, 0xFF, + 0x0B, 0x01, 0xF2, 0xFF, 0x0B, 0x02, 0xF1, 0xFF, + 0x0B, 0x02, 0xF0, 0xFF, 0x0B, 0x02, 0xEF, 0xFF, + 0x0B, 0x02, 0xEE, 0xFF, 0x0B, 0x02, 0xED, 0xFF, + 0x0B, 0x02, 0xEC, 0xFF, 0x04, 0x00, 0x65, 0x00, + 0x00, 0x5A, 0x01, 0x00, 0x64, 0x00, 0x00, 0x84, + 0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, 0x01, 0x00, + 0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, 0x64, 0x02, + 0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x64, + 0x03, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x05, 0x00, + 0x64, 0x04, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x06, + 0x00, 0x64, 0x05, 0x00, 0x84, 0x00, 0x00, 0x5A, + 0x07, 0x00, 0x64, 0x06, 0x00, 0x84, 0x00, 0x00, + 0x5A, 0x08, 0x00, 0x64, 0x07, 0x00, 0x84, 0x00, + 0x00, 0x5A, 0x09, 0x00, 0x52, 0x53, 0x03, 0x06, + 0x00, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6C, 0x0A, + 0xA3, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x3A, + 0x03, 0x04, 0x07, 0x03, 0x08, 0x00, 0x5F, 0x5F, + 0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, + 0x00, 0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, + 0x65, 0x5F, 0x5F, 0x03, 0x08, 0x00, 0x5F, 0x5F, + 0x69, 0x6E, 0x69, 0x74, 0x5F, 0x5F, 0x03, 0x04, + 0x00, 0x70, 0x75, 0x74, 0x63, 0x03, 0x04, 0x00, + 0x70, 0x75, 0x74, 0x73, 0x03, 0x04, 0x00, 0x67, + 0x65, 0x74, 0x63, 0x03, 0x06, 0x00, 0x53, 0x65, + 0x72, 0x69, 0x61, 0x6C, 0x03, 0x08, 0x00, 0x06, + 0x02, 0x09, 0x30, 0x09, 0x28, 0x09, 0x28, 0x03, + 0x08, 0x00, 0x6D, 0x62, 0x65, 0x64, 0x2E, 0x70, + 0x79, 0x00, 0x04, 0x04, 0x0B, 0x03, 0xEB, 0xFF, + 0x0B, 0x02, 0xEA, 0xFF, 0x0B, 0x02, 0xE9, 0xFF, + 0x0B, 0x01, 0xE8, 0xFF, 0x04, 0x00, 0x65, 0x00, + 0x00, 0x5A, 0x01, 0x00, 0x64, 0x00, 0x00, 0x84, + 0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, 0x01, 0x00, + 0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, 0x64, 0x02, + 0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x64, + 0x03, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x05, 0x00, + 0x52, 0x53, 0x03, 0x03, 0x00, 0x53, 0x50, 0x49, + 0x0A, 0xB0, 0x00, 0x00, 0x42, 0x02, 0x00, 0x00, + 0xDD, 0x03, 0x04, 0x07, 0x03, 0x08, 0x00, 0x5F, + 0x5F, 0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, + 0x0A, 0x00, 0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, + 0x6C, 0x65, 0x5F, 0x5F, 0x03, 0x08, 0x00, 0x5F, + 0x5F, 0x69, 0x6E, 0x69, 0x74, 0x5F, 0x5F, 0x03, + 0x06, 0x00, 0x66, 0x6F, 0x72, 0x6D, 0x61, 0x74, + 0x03, 0x09, 0x00, 0x66, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x6E, 0x63, 0x79, 0x03, 0x05, 0x00, 0x77, + 0x72, 0x69, 0x74, 0x65, 0x03, 0x03, 0x00, 0x53, + 0x50, 0x49, 0x03, 0x08, 0x00, 0x06, 0x02, 0x09, + 0x34, 0x0C, 0x30, 0x09, 0x28, 0x03, 0x08, 0x00, + 0x6D, 0x62, 0x65, 0x64, 0x2E, 0x70, 0x79, 0x00, + 0x04, 0x05, 0x0B, 0x04, 0xE7, 0xFF, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x0B, 0x03, 0xE6, 0xFF, 0x0B, + 0x02, 0xE5, 0xFF, 0x0B, 0x02, 0xE4, 0xFF, 0x04, + 0x00, 0x65, 0x00, 0x00, 0x5A, 0x01, 0x00, 0x64, + 0x00, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, 0x00, + 0x64, 0x01, 0x00, 0x64, 0x02, 0x00, 0x84, 0x01, + 0x00, 0x5A, 0x03, 0x00, 0x64, 0x03, 0x00, 0x84, + 0x00, 0x00, 0x5A, 0x04, 0x00, 0x64, 0x04, 0x00, + 0x84, 0x00, 0x00, 0x5A, 0x05, 0x00, 0x52, 0x53, + 0x03, 0x03, 0x00, 0x49, 0x32, 0x43, 0x0A, 0xA6, + 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x94, 0x04, + 0x04, 0x07, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, + 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, + 0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, + 0x5F, 0x5F, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x69, + 0x6E, 0x69, 0x74, 0x5F, 0x5F, 0x03, 0x09, 0x00, + 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6E, 0x63, + 0x79, 0x03, 0x04, 0x00, 0x72, 0x65, 0x61, 0x64, + 0x03, 0x05, 0x00, 0x77, 0x72, 0x69, 0x74, 0x65, + 0x03, 0x03, 0x00, 0x49, 0x32, 0x43, 0x03, 0x08, + 0x00, 0x06, 0x02, 0x09, 0x30, 0x09, 0x28, 0x09, + 0x30, 0x03, 0x08, 0x00, 0x6D, 0x62, 0x65, 0x64, + 0x2E, 0x70, 0x79, 0x00, 0x04, 0x04, 0x0B, 0x03, + 0xE3, 0xFF, 0x0B, 0x02, 0xE2, 0xFF, 0x0B, 0x04, + 0xE1, 0xFF, 0x0B, 0x04, 0xE0, 0xFF, 0x04, 0x00, + 0x65, 0x00, 0x00, 0x5A, 0x01, 0x00, 0x64, 0x00, + 0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, + 0x01, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, + 0x64, 0x02, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, + 0x00, 0x64, 0x03, 0x00, 0x84, 0x00, 0x00, 0x5A, + 0x05, 0x00, 0x52, 0x53, 0x0B, 0x02, 0xDF, 0xFF, + 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 0x5A, 0x00, + 0x00, 0x64, 0x01, 0x00, 0x65, 0x01, 0x00, 0x66, + 0x01, 0x00, 0x64, 0x02, 0x00, 0x84, 0x00, 0x00, + 0x83, 0x00, 0x00, 0x59, 0x5A, 0x02, 0x00, 0x64, + 0x03, 0x00, 0x65, 0x01, 0x00, 0x66, 0x01, 0x00, + 0x64, 0x04, 0x00, 0x84, 0x00, 0x00, 0x83, 0x00, + 0x00, 0x59, 0x5A, 0x03, 0x00, 0x64, 0x05, 0x00, + 0x65, 0x01, 0x00, 0x66, 0x01, 0x00, 0x64, 0x06, + 0x00, 0x84, 0x00, 0x00, 0x83, 0x00, 0x00, 0x59, + 0x5A, 0x04, 0x00, 0x64, 0x07, 0x00, 0x65, 0x01, + 0x00, 0x66, 0x01, 0x00, 0x64, 0x08, 0x00, 0x84, + 0x00, 0x00, 0x83, 0x00, 0x00, 0x59, 0x5A, 0x05, + 0x00, 0x64, 0x09, 0x00, 0x65, 0x01, 0x00, 0x66, + 0x01, 0x00, 0x64, 0x0A, 0x00, 0x84, 0x00, 0x00, + 0x83, 0x00, 0x00, 0x59, 0x5A, 0x06, 0x00, 0x64, + 0x0B, 0x00, 0x65, 0x01, 0x00, 0x66, 0x01, 0x00, + 0x64, 0x0C, 0x00, 0x84, 0x00, 0x00, 0x83, 0x00, + 0x00, 0x59, 0x5A, 0x07, 0x00, 0x64, 0x0D, 0x00, + 0x65, 0x01, 0x00, 0x66, 0x01, 0x00, 0x64, 0x0E, + 0x00, 0x84, 0x00, 0x00, 0x83, 0x00, 0x00, 0x59, + 0x5A, 0x08, 0x00, 0x64, 0x0F, 0x00, 0x65, 0x01, + 0x00, 0x66, 0x01, 0x00, 0x64, 0x10, 0x00, 0x84, + 0x00, 0x00, 0x83, 0x00, 0x00, 0x59, 0x5A, 0x09, + 0x00, 0x64, 0x11, 0x00, 0x84, 0x00, 0x00, 0x5A, + 0x0A, 0x00, 0x64, 0x12, 0x00, 0x53, + +/* img-list-terminator */ + 0xFF, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/platform/mbed/main_nat.cpp Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,1472 @@ +#undef __FILE_ID__ +#define __FILE_ID__ 0x0A +/** + * PyMite usr native function file + * + * automatically created by pmImgCreator.py + * on Sat Mar 02 20:27:03 2013 + * + * DO NOT EDIT THIS FILE. + * ANY CHANGES WILL BE LOST. + * + * @file main_nat.cpp + */ + +#define __IN_LIBNATIVE_C__ +#include "pm.h" + +/* From: mbed.py */ +#include "mbed.h" + +static DigitalOut led1(LED1); +static DigitalOut led2(LED2); +static DigitalOut led3(LED3); +static DigitalOut led4(LED4); + +/* PinName lookup table. Converts pin number to PinName. */ +static PinName const pinNumToName[] = { + NC, LED1, LED2, LED3, LED4, p5, p6, p7, p8, p9, + p10, p11, p12, p13, p14, p15, p16, p17, p18, p19, + p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, + p30 +}; + +PmReturn_t +nat_placeholder_func(pPmFrame_t *ppframe) +{ + + /* + * Use placeholder because an index + * value of zero denotes the stdlib. + * This function should not be called. + */ + PmReturn_t retval; + PM_RAISE(retval, PM_RET_EX_SYS); + return retval; + +} + +PmReturn_t +nat_01_mbed___init__(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + AnalogIn *adc; + uint8_t objid; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Instantiate the C++ object */ + adc = new AnalogIn(pinNumToName[((pPmInt_t)pn)->val]); + + /* Save the pointer to adc as an inaccessible attribute */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = int_new((uint32_t)adc, &pn); + PM_RETURN_IF_ERROR(retval); + heap_gcPushTempRoot(pn, &objid); + retval = dict_setItem(pattrs, PM_NONE, pn); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_02_mbed_read_u16(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + AnalogIn *adc; + int32_t n; + + /* If wrong number of args, throw type exception */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + adc = (AnalogIn *)((pPmInt_t)pn)->val; + + /* Return input value on the stack */ + n = adc->read_u16(); + retval = int_new(n, &pn); + NATIVE_SET_TOS(pn); + + return retval; + +} + +PmReturn_t +nat_03_mbed_read(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + AnalogIn *adc; + float n; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + adc = (AnalogIn *)((pPmInt_t)pn)->val; + + /* Return input value on the stack */ + n = adc->read(); + retval = float_new(n, &pn); + NATIVE_SET_TOS(pn); + + return retval; + +} + +PmReturn_t +nat_04_mbed___init__(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + AnalogOut *dac; + uint8_t objid; + + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Instantiate the object */ + dac = new AnalogOut(pinNumToName[((pPmInt_t)pn)->val]); + + /* Save the pointer to adc as an inaccessible attribute */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = int_new((uint32_t)dac, &pn); + PM_RETURN_IF_ERROR(retval); + heap_gcPushTempRoot(pn, &objid); + retval = dict_setItem(pattrs, PM_NONE, pn); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_05_mbed_write_u16(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + AnalogOut *dac; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + dac = (AnalogOut *)((pPmInt_t)pn)->val; + + /* Write value to DAC */ + pn = NATIVE_GET_LOCAL(1); + dac->write_u16(((pPmInt_t)pn)->val); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_06_mbed_write(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + AnalogOut *dac; + float n; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_FLT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + dac = (AnalogOut *)((pPmInt_t)pn)->val; + + /* Saturate and write value to DAC */ + pn = NATIVE_GET_LOCAL(1); + n = ((pPmFloat_t)pn)->val; + if (n < 0.0) + { + n = 0.0; + } + else if (n > 1.0) + { + n = 1.0; + } + dac->write(n); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_07_mbed_read(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + AnalogOut *dac; + float n; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + dac = (AnalogOut *)((pPmInt_t)pn)->val; + + /* Return output value on the stack */ + n = dac->read(); + retval = float_new(n, &pn); + NATIVE_SET_TOS(pn); + + return retval; + +} + +PmReturn_t +nat_08_mbed___init__(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + DigitalIn *din; + uint8_t objid; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Instantiate the C++ object */ + din = new DigitalIn(pinNumToName[((pPmInt_t)pn)->val]); + + /* Save the pointer to adc as an inaccessible attribute */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = int_new((uint32_t)din, &pn); + PM_RETURN_IF_ERROR(retval); + heap_gcPushTempRoot(pn, &objid); + retval = dict_setItem(pattrs, PM_NONE, pn); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_09_mbed_read(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + DigitalIn *din; + int32_t n; + + /* If wrong number of args, throw type exception */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + din = (DigitalIn *)((pPmInt_t)pn)->val; + + /* Return input value on the stack */ + n = din->read(); + retval = int_new(n, &pn); + NATIVE_SET_TOS(pn); + + return retval; + +} + +PmReturn_t +nat_10_mbed___init__(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + DigitalOut *dout; + uint8_t objid; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Instantiate the C++ object */ + dout = new DigitalOut(pinNumToName[((pPmInt_t)pn)->val]); + + /* Save the pointer to adc as an inaccessible attribute */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = int_new((uint32_t)dout, &pn); + PM_RETURN_IF_ERROR(retval); + heap_gcPushTempRoot(pn, &objid); + retval = dict_setItem(pattrs, PM_NONE, pn); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_11_mbed_read(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + DigitalOut *dout; + int32_t n; + + /* If wrong number of args, throw type exception */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + dout = (DigitalOut *)((pPmInt_t)pn)->val; + + /* Return input value on the stack */ + n = dout->read(); + retval = int_new(n, &pn); + NATIVE_SET_TOS(pn); + + return retval; + +} + +PmReturn_t +nat_12_mbed_write(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + DigitalOut *dout; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + dout = (DigitalOut *)((pPmInt_t)pn)->val; + + /* Write value to DAC */ + pn = NATIVE_GET_LOCAL(1); + dout->write(((pPmInt_t)pn)->val); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_13_mbed___init__(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + PwmOut *pwm; + uint8_t objid; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Instantiate the C++ object */ + pwm = new PwmOut(pinNumToName[((pPmInt_t)pn)->val]); + + /* Save the pointer to pwm as an inaccessible attribute */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = int_new((uint32_t)pwm, &pn); + PM_RETURN_IF_ERROR(retval); + heap_gcPushTempRoot(pn, &objid); + retval = dict_setItem(pattrs, PM_NONE, pn); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_14_mbed_read(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + DigitalOut *dout; + int32_t n; + + /* If wrong number of args, throw type exception */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + dout = (DigitalOut *)((pPmInt_t)pn)->val; + + /* Return input value on the stack */ + n = dout->read(); + retval = int_new(n, &pn); + NATIVE_SET_TOS(pn); + + return retval; + +} + +PmReturn_t +nat_15_mbed_period(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + PwmOut *pwm; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + pwm = (PwmOut *)((pPmInt_t)pn)->val; + + /* Write value to DAC */ + pn = NATIVE_GET_LOCAL(1); + pwm->period(((pPmInt_t)pn)->val); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_16_mbed_period_ms(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + PwmOut *pwm; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + pwm = (PwmOut *)((pPmInt_t)pn)->val; + + /* Write value to DAC */ + pn = NATIVE_GET_LOCAL(1); + pwm->period_ms(((pPmInt_t)pn)->val); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_17_mbed_period_us(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + PwmOut *pwm; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + pwm = (PwmOut *)((pPmInt_t)pn)->val; + + /* Write value to DAC */ + pn = NATIVE_GET_LOCAL(1); + pwm->period_us(((pPmInt_t)pn)->val); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_18_mbed_pulsewidth(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + PwmOut *pwm; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + pwm = (PwmOut *)((pPmInt_t)pn)->val; + + /* Write value to DAC */ + pn = NATIVE_GET_LOCAL(1); + pwm->pulsewidth(((pPmInt_t)pn)->val); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_19_mbed_puslewidth_ms(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + PwmOut *pwm; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + pwm = (PwmOut *)((pPmInt_t)pn)->val; + + /* Write value to DAC */ + pn = NATIVE_GET_LOCAL(1); + pwm->pulsewidth_ms(((pPmInt_t)pn)->val); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_20_mbed_pulsewidth_us(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + PwmOut *pwm; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + pwm = (PwmOut *)((pPmInt_t)pn)->val; + + /* Write value to DAC */ + pn = NATIVE_GET_LOCAL(1); + pwm->pulsewidth_us(((pPmInt_t)pn)->val); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_21_mbed___init__(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t ptx; + pPmObj_t prx; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + Serial *ser; + uint8_t objid; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 3) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + ptx = NATIVE_GET_LOCAL(1); + prx = NATIVE_GET_LOCAL(2); + if ((OBJ_GET_TYPE(ptx) != OBJ_TYPE_INT) + || (OBJ_GET_TYPE(prx) != OBJ_TYPE_INT)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Instantiate the C++ object */ + ser = new Serial(pinNumToName[((pPmInt_t)ptx)->val], + pinNumToName[((pPmInt_t)prx)->val]); + + /* Save the pointer to ser as an inaccessible attribute */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = int_new((uint32_t)ser, &pn); + PM_RETURN_IF_ERROR(retval); + heap_gcPushTempRoot(pn, &objid); + retval = dict_setItem(pattrs, PM_NONE, pn); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_22_mbed_putc(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + Serial *ser; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_STR) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + ser = (Serial *)((pPmInt_t)pn)->val; + + /* Write value to DAC */ + pn = NATIVE_GET_LOCAL(1); + ser->putc(((pPmString_t)pn)->val[0]); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_23_mbed_puts(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + Serial *ser; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pn = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_STR) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + ser = (Serial *)((pPmInt_t)pn)->val; + + /* Write value to DAC */ + pn = NATIVE_GET_LOCAL(1); + ser->puts((const char *)((pPmString_t)pn)->val); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_24_mbed_getc(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + Serial *ser; + int32_t n; + + /* If wrong number of args, throw type exception */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + ser = (Serial *)((pPmInt_t)pn)->val; + + /* Return char (as string) on the stack */ + n = ser->getc(); + retval = string_newFromChar((uint8_t)n, &pn); + NATIVE_SET_TOS(pn); + + return retval; + +} + +PmReturn_t +nat_25_mbed___init__(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pmosi; + pPmObj_t pmiso; + pPmObj_t psclk; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + SPI *spi; + uint8_t objid; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 4) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pmosi = NATIVE_GET_LOCAL(1); + pmiso = NATIVE_GET_LOCAL(2); + psclk = NATIVE_GET_LOCAL(3); + if ((OBJ_GET_TYPE(pmosi) != OBJ_TYPE_INT) + || (OBJ_GET_TYPE(pmiso) != OBJ_TYPE_INT) + || (OBJ_GET_TYPE(psclk) != OBJ_TYPE_INT)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Instantiate the C++ object */ + spi = new SPI(pinNumToName[((pPmInt_t)pmosi)->val], + pinNumToName[((pPmInt_t)pmiso)->val], + pinNumToName[((pPmInt_t)psclk)->val]); + + /* Save the pointer to ser as an inaccessible attribute */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = int_new((uint32_t)spi, &pn); + PM_RETURN_IF_ERROR(retval); + heap_gcPushTempRoot(pn, &objid); + retval = dict_setItem(pattrs, PM_NONE, pn); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_26_mbed_format(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pbits; + pPmObj_t pmode; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + SPI *spi; + + /* Raise TypeError if wrong number of args */ + if ((NATIVE_GET_NUM_ARGS() < 2) || (NATIVE_GET_NUM_ARGS() > 3)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pbits = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pbits) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the mode arg if it exists */ + pmode = PM_ZERO; + if (NATIVE_GET_NUM_ARGS() == 3) + { + pmode = NATIVE_GET_LOCAL(3); + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + spi = (SPI *)((pPmInt_t)pn)->val; + + /* Set format args */ + spi->format(((pPmInt_t)pbits)->val, ((pPmInt_t)pmode)->val); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_27_mbed_frequency(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t phz; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + SPI *spi; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + phz = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(phz) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + spi = (SPI *)((pPmInt_t)pn)->val; + + /* Set frequency */ + spi->frequency(((pPmInt_t)phz)->val); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_28_mbed_write(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t pv; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + SPI *spi; + int32_t r; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + pv = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pv) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + spi = (SPI *)((pPmInt_t)pn)->val; + + /* Write the value and return the response */ + r = spi->write(((pPmInt_t)pv)->val); + retval = int_new(r, &pn); + NATIVE_SET_TOS(pn); + return retval; + +} + +PmReturn_t +nat_29_mbed___init__(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t psda; + pPmObj_t pscl; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + I2C *i2c; + uint8_t objid; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 3) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + psda = NATIVE_GET_LOCAL(1); + pscl = NATIVE_GET_LOCAL(2); + if ((OBJ_GET_TYPE(psda) != OBJ_TYPE_INT) + || (OBJ_GET_TYPE(pscl) != OBJ_TYPE_INT)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Instantiate the C++ object */ + i2c = new I2C(pinNumToName[((pPmInt_t)psda)->val], + pinNumToName[((pPmInt_t)pscl)->val]); + + /* Save the pointer to ser as an inaccessible attribute */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = int_new((uint32_t)i2c, &pn); + PM_RETURN_IF_ERROR(retval); + heap_gcPushTempRoot(pn, &objid); + retval = dict_setItem(pattrs, PM_NONE, pn); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_30_mbed_frequency(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t phz; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + I2C *i2c; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + phz = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(phz) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + i2c = (I2C *)((pPmInt_t)pn)->val; + + /* Set frequency */ + i2c->frequency(((pPmInt_t)phz)->val); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_31_mbed_read(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t paddr; + pPmObj_t pdata; + pPmObj_t plen; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + I2C *i2c; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 4) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + paddr = NATIVE_GET_LOCAL(1); + pdata = NATIVE_GET_LOCAL(2); + plen = NATIVE_GET_LOCAL(3); + if ((OBJ_GET_TYPE(paddr) != OBJ_TYPE_INT) + || (OBJ_GET_TYPE(pdata) != OBJ_TYPE_STR) + || (OBJ_GET_TYPE(plen) != OBJ_TYPE_INT)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + i2c = (I2C *)((pPmInt_t)pn)->val; + + /* Read the bytes into the string */ + /* WARNING: Changing the bytes of a string object is BAD. */ + i2c->read(((pPmInt_t)paddr)->val, + (char *)((pPmString_t)pdata)->val, + ((pPmInt_t)plen)->val); + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_32_mbed_write(pPmFrame_t *ppframe) +{ + + pPmObj_t pself; + pPmObj_t pn; + pPmObj_t paddr; + pPmObj_t pdata; + pPmObj_t plen; + pPmObj_t pattrs; + PmReturn_t retval = PM_RET_OK; + I2C *i2c; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 4) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + pself = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not the right type */ + paddr = NATIVE_GET_LOCAL(1); + pdata = NATIVE_GET_LOCAL(2); + plen = NATIVE_GET_LOCAL(3); + if ((OBJ_GET_TYPE(paddr) != OBJ_TYPE_INT) + || (OBJ_GET_TYPE(pdata) != OBJ_TYPE_STR) + || (OBJ_GET_TYPE(plen) != OBJ_TYPE_INT)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the the C++ instance */ + pattrs = (pPmObj_t)((pPmInstance_t)pself)->cli_attrs; + retval = dict_getItem(pattrs, PM_NONE, &pn); + PM_RETURN_IF_ERROR(retval); + i2c = (I2C *)((pPmInt_t)pn)->val; + + /* Write the value and return the response */ + i2c->write(((pPmInt_t)paddr)->val, + (char *)((pPmString_t)pdata)->val, + ((pPmInt_t)plen)->val); + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_33_mbed_set_led(pPmFrame_t *ppframe) +{ + + pPmObj_t pled; + pPmObj_t pval; + int32_t nled; + int32_t nval; + PmReturn_t retval = PM_RET_OK; + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() > 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* If arg is not an int, raise TypeError */ + pled = NATIVE_GET_LOCAL(0); + pval = NATIVE_GET_LOCAL(1); + if ((OBJ_GET_TYPE(pled) != OBJ_TYPE_INT) + || (OBJ_GET_TYPE(pval) != OBJ_TYPE_INT)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get int value from the arg */ + nled = ((pPmInt_t)pled)->val; + nval = ((pPmInt_t)pval)->val; + + /* Set the LED to the given value */ + switch (nled) + { + case 1: led1 = nval; break; + case 2: led2 = nval; break; + case 3: led3 = nval; break; + case 4: led4 = nval; break; + } + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +/* Native function lookup table */ +pPmNativeFxn_t const usr_nat_fxn_table[] = +{ + nat_placeholder_func, + nat_01_mbed___init__, + nat_02_mbed_read_u16, + nat_03_mbed_read, + nat_04_mbed___init__, + nat_05_mbed_write_u16, + nat_06_mbed_write, + nat_07_mbed_read, + nat_08_mbed___init__, + nat_09_mbed_read, + nat_10_mbed___init__, + nat_11_mbed_read, + nat_12_mbed_write, + nat_13_mbed___init__, + nat_14_mbed_read, + nat_15_mbed_period, + nat_16_mbed_period_ms, + nat_17_mbed_period_us, + nat_18_mbed_pulsewidth, + nat_19_mbed_puslewidth_ms, + nat_20_mbed_pulsewidth_us, + nat_21_mbed___init__, + nat_22_mbed_putc, + nat_23_mbed_puts, + nat_24_mbed_getc, + nat_25_mbed___init__, + nat_26_mbed_format, + nat_27_mbed_frequency, + nat_28_mbed_write, + nat_29_mbed___init__, + nat_30_mbed_frequency, + nat_31_mbed_read, + nat_32_mbed_write, + nat_33_mbed_set_led, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/platform/mbed/plat.cpp Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,333 @@ +/* +# This file is Copyright 2009 Dean Hall. +# +# This file is part of the Python-on-a-Chip program. +# Python-on-a-Chip is free software: you can redistribute it and/or modify +# it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1. +# +# Python-on-a-Chip 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 LESSER GENERAL PUBLIC LICENSE Version 2.1 +# is seen in the file COPYING up one directory from this. +*/ + + +#undef __FILE_ID__ +#define __FILE_ID__ 0x70 + + +/** PyMite platform-specific routines for ARM7 target */ + + +#include "mbed.h" +#include "pm.h" + + +#define CALLBACK_MS 10 + + +Serial serial(USBTX, USBRX, "serial"); +Ticker ticker; + + +static void +ticker_callback(void) +{ + PmReturn_t retval; + + retval = pm_vmPeriodic(CALLBACK_MS * 1000); + PM_REPORT_IF_ERROR(retval); +} + + +PmReturn_t +plat_init(void) +{ + serial.baud(19200); + serial.format(8, serial.None, 1); + + ticker.attach_us(ticker_callback, CALLBACK_MS * 1000); + + return PM_RET_OK; +} + + +PmReturn_t +plat_deinit(void) +{ + /* Detach the callback from the ticker */ + ticker.detach(); + + return PM_RET_OK; +} + + +uint8_t +plat_memGetByte(PmMemSpace_t memspace, uint8_t const **paddr) +{ + uint8_t b = 0; + + switch (memspace) + { + case MEMSPACE_RAM: + case MEMSPACE_PROG: + b = **paddr; + *paddr += 1; + return b; + + case MEMSPACE_EEPROM: + case MEMSPACE_SEEPROM: + case MEMSPACE_OTHER0: + case MEMSPACE_OTHER1: + case MEMSPACE_OTHER2: + case MEMSPACE_OTHER3: + default: + return 0; + } +} + + +PmReturn_t +plat_getByte(uint8_t *b) +{ + int c; + PmReturn_t retval = PM_RET_OK; + + c = serial.getc(); + *b = c & 0xFF; + + if (c > 0xFF) + { + PM_RAISE(retval, PM_RET_EX_IO); + } + + return retval; +} + + +PmReturn_t +plat_putByte(uint8_t b) +{ + while (!serial.writeable()); + serial.putc(b); + + return PM_RET_OK; +} + + +PmReturn_t +plat_getMsTicks(uint32_t *r_ticks) +{ + *r_ticks = pm_timerMsTicks; + + return PM_RET_OK; +} + + +void +plat_reportError(PmReturn_t result) +{ + +#ifdef HAVE_DEBUG_INFO +#define LEN_FNLOOKUP 26 +#define LEN_EXNLOOKUP 18 + + uint8_t res; + pPmFrame_t pframe; + pPmObj_t pstr; + PmReturn_t retval; + uint16_t bcindex; + uint16_t bcsum; + uint16_t linesum; + uint16_t len_lnotab; + uint8_t const *plnotab; + uint16_t i; + + /* This table should match src/vm/fileid.txt */ + char const * const fnlookup[LEN_FNLOOKUP] = { + "<no file>", + "codeobj.c", + "dict.c", + "frame.c", + "func.c", + "global.c", + "heap.c", + "img.c", + "int.c", + "interp.c", + "pmstdlib_nat.c", + "list.c", + "main.c", + "mem.c", + "module.c", + "obj.c", + "seglist.c", + "sli.c", + "strobj.c", + "tuple.c", + "seq.c", + "pm.c", + "thread.c", + "float.c", + "class.c", + "bytearray.c", + }; + + /* This table should match src/vm/pm.h PmReturn_t */ + char const * const exnlookup[LEN_EXNLOOKUP] = { + "Exception", + "SystemExit", + "IoError", + "ZeroDivisionError", + "AssertionError", + "AttributeError", + "ImportError", + "IndexError", + "KeyError", + "MemoryError", + "NameError", + "SyntaxError", + "SystemError", + "TypeError", + "ValueError", + "StopIteration", + "Warning", + "OverflowError", + }; + + /* Print traceback */ + printf("Traceback (most recent call first):\n"); + + /* Get the top frame */ + pframe = gVmGlobal.pthread->pframe; + + /* If it's the native frame, print the native function name */ + if (pframe == (pPmFrame_t)&(gVmGlobal.nativeframe)) + { + + /* The last name in the names tuple of the code obj is the name */ + retval = tuple_getItem((pPmObj_t)gVmGlobal.nativeframe.nf_func-> + f_co->co_names, -1, &pstr); + if ((retval) != PM_RET_OK) + { + printf(" Unable to get native func name.\n"); + return; + } + else + { + printf(" %s() __NATIVE__\n", ((pPmString_t)pstr)->val); + } + + /* Get the frame that called the native frame */ + pframe = (pPmFrame_t)gVmGlobal.nativeframe.nf_back; + } + + /* Print the remaining frame stack */ + for (; pframe != C_NULL; pframe = pframe->fo_back) + { + /* The last name in the names tuple of the code obj is the name */ + retval = tuple_getItem((pPmObj_t)pframe->fo_func->f_co->co_names, + -1, + &pstr); + if ((retval) != PM_RET_OK) break; + + /* + * Get the line number of the current bytecode. Algorithm comes from: + * http://svn.python.org/view/python/trunk/Objects/lnotab_notes.txt?view=markup + */ + bcindex = pframe->fo_ip - pframe->fo_func->f_co->co_codeaddr; + plnotab = pframe->fo_func->f_co->co_lnotab; + len_lnotab = mem_getWord(MEMSPACE_PROG, &plnotab); + bcsum = 0; + linesum = pframe->fo_func->f_co->co_firstlineno; + for (i = 0; i < len_lnotab; i += 2) + { + bcsum += mem_getByte(MEMSPACE_PROG, &plnotab); + if (bcsum > bcindex) break; + linesum += mem_getByte(MEMSPACE_PROG, &plnotab); + } + printf(" File \"%s\", line %d, in %s\n", + ((pPmFrame_t)pframe)->fo_func->f_co->co_filename, + linesum, + ((pPmString_t)pstr)->val); + } + + /* Print error */ + res = (uint8_t)result; + if ((res > 0) && ((res - PM_RET_EX) < LEN_EXNLOOKUP)) + { + printf("%s", exnlookup[res - PM_RET_EX]); + } + else + { + printf("Error code 0x%02X", result); + } + printf(" detected by "); + + if ((gVmGlobal.errFileId > 0) && (gVmGlobal.errFileId < LEN_FNLOOKUP)) + { + printf("%s:", fnlookup[gVmGlobal.errFileId]); + } + else + { + printf("FileId 0x%02X line ", gVmGlobal.errFileId); + } + printf("%d\n", gVmGlobal.errLineNum); + +#else /* HAVE_DEBUG_INFO */ + + /* Print error */ + printf("Error: 0x%02X\n", result); + printf(" Release: 0x%02X\n", gVmGlobal.errVmRelease); + printf(" FileId: 0x%02X\n", gVmGlobal.errFileId); + printf(" LineNum: %d\n", gVmGlobal.errLineNum); + + /* Print traceback */ + { + pPmObj_t pframe; + pPmObj_t pstr; + PmReturn_t retval; + + printf("Traceback (top first):\n"); + + /* Get the top frame */ + pframe = (pPmObj_t)gVmGlobal.pthread->pframe; + + /* If it's the native frame, print the native function name */ + if (pframe == (pPmObj_t)&(gVmGlobal.nativeframe)) + { + + /* The last name in the names tuple of the code obj is the name */ + retval = tuple_getItem((pPmObj_t)gVmGlobal.nativeframe.nf_func-> + f_co->co_names, -1, &pstr); + if ((retval) != PM_RET_OK) + { + printf(" Unable to get native func name.\n"); + return; + } + else + { + printf(" %s() __NATIVE__\n", ((pPmString_t)pstr)->val); + } + + /* Get the frame that called the native frame */ + pframe = (pPmObj_t)gVmGlobal.nativeframe.nf_back; + } + + /* Print the remaining frame stack */ + for (; + pframe != C_NULL; + pframe = (pPmObj_t)((pPmFrame_t)pframe)->fo_back) + { + /* The last name in the names tuple of the code obj is the name */ + retval = tuple_getItem((pPmObj_t)((pPmFrame_t)pframe)-> + fo_func->f_co->co_names, -1, &pstr); + if ((retval) != PM_RET_OK) break; + + printf(" %s()\n", ((pPmString_t)pstr)->val); + } + printf(" <module>.\n"); + } +#endif /* HAVE_DEBUG_INFO */ +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/platform/mbed/plat.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,22 @@ +/* +# This file is Copyright 2009 Dean Hall. +# +# This file is part of the Python-on-a-Chip program. +# Python-on-a-Chip is free software: you can redistribute it and/or modify +# it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1. +# +# Python-on-a-Chip 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 LESSER GENERAL PUBLIC LICENSE Version 2.1 +# is seen in the file COPYING up one directory from this. +*/ + +#ifndef _PLAT_H_ +#define _PLAT_H_ + +#define PM_FLOAT_LITTLE_ENDIAN +#define PM_PLAT_HEAP_ATTR __attribute__((aligned (4))) +#define PM_PLAT_POINTER_SIZE 4 + +#endif /* _PLAT_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/platform/mbed/pmfeatures.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,16 @@ +/* Automatically generated by ../../tools/pmGenPmFeatures.py on Sat Mar 02 20:27:03 2013. DO NOT EDIT. */ +#define HAVE_PRINT +#define HAVE_CLASSES +#define HAVE_REPLICATION +#define HAVE_DEFAULTARGS +#define HAVE_DEL +#define HAVE_BACKTICK +#define HAVE_FLOAT +#define HAVE_GC +#define HAVE_STRING_FORMAT +#define HAVE_AUTOBOX +#define HAVE_ASSERT +#define HAVE_CLOSURES +#define HAVE_GENERATORS +#define HAVE_IMPORTS +#define HAVE_DEBUG_INFO
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/platform/mbed/pmstdlib_img.cpp Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,710 @@ +/** + * PyMite library image file. + * + * Automatically created from: + * ../../lib/__bi.py + * ../../lib/dict.py + * ../../lib/list.py + * ../../lib/string.py + * ../../lib/sys.py + * ../../lib/ipm.py + * img-list-terminator + * by pmImgCreator.py on + * Sat Mar 02 20:27:03 2013. + * + * Byte count: 5264 + * + * Selected memspace type: FLASH + * + * DO NOT EDIT THIS FILE. + * ANY CHANGES WILL BE LOST. + */ + +/* Place the image into FLASH */ +#ifdef __cplusplus +extern +#endif +unsigned char const +#if defined(__AVR__) +__attribute__((progmem)) +#endif +stdlib_img[] = +{ + + +/* ../../lib/__bi.py */ + 0x0A, 0x03, 0x06, 0x00, 0x40, 0x03, 0x00, 0x00, + 0x12, 0x00, 0x04, 0x19, 0x03, 0x03, 0x00, 0x61, + 0x62, 0x73, 0x03, 0x03, 0x00, 0x63, 0x68, 0x72, + 0x03, 0x03, 0x00, 0x64, 0x69, 0x72, 0x03, 0x04, + 0x00, 0x65, 0x76, 0x61, 0x6C, 0x03, 0x06, 0x00, + 0x66, 0x69, 0x6C, 0x74, 0x65, 0x72, 0x03, 0x07, + 0x00, 0x67, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x73, + 0x03, 0x02, 0x00, 0x69, 0x64, 0x03, 0x03, 0x00, + 0x6C, 0x65, 0x6E, 0x03, 0x06, 0x00, 0x6C, 0x6F, + 0x63, 0x61, 0x6C, 0x73, 0x03, 0x03, 0x00, 0x6D, + 0x61, 0x70, 0x03, 0x03, 0x00, 0x6F, 0x72, 0x64, + 0x03, 0x03, 0x00, 0x70, 0x6F, 0x77, 0x03, 0x05, + 0x00, 0x72, 0x61, 0x6E, 0x67, 0x65, 0x03, 0x03, + 0x00, 0x73, 0x75, 0x6D, 0x03, 0x04, 0x00, 0x74, + 0x79, 0x70, 0x65, 0x03, 0x02, 0x00, 0x43, 0x6F, + 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, 0x6D, + 0x65, 0x5F, 0x5F, 0x03, 0x06, 0x00, 0x6F, 0x62, + 0x6A, 0x65, 0x63, 0x74, 0x03, 0x09, 0x00, 0x45, + 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6F, 0x6E, + 0x03, 0x0E, 0x00, 0x41, 0x73, 0x73, 0x65, 0x72, + 0x74, 0x69, 0x6F, 0x6E, 0x45, 0x72, 0x72, 0x6F, + 0x72, 0x03, 0x04, 0x00, 0x63, 0x6F, 0x64, 0x65, + 0x03, 0x09, 0x00, 0x47, 0x65, 0x6E, 0x65, 0x72, + 0x61, 0x74, 0x6F, 0x72, 0x03, 0x06, 0x00, 0x69, + 0x73, 0x6D, 0x61, 0x69, 0x6E, 0x03, 0x04, 0x00, + 0x5F, 0x5F, 0x6D, 0x64, 0x03, 0x04, 0x00, 0x5F, + 0x5F, 0x62, 0x69, 0x03, 0x2E, 0x00, 0x09, 0x05, + 0x09, 0x26, 0x09, 0x5B, 0x09, 0x64, 0x09, 0x04, + 0x09, 0x19, 0x09, 0x1B, 0x09, 0x43, 0x09, 0x15, + 0x09, 0x0E, 0x09, 0x22, 0x09, 0x04, 0x09, 0x61, + 0x09, 0x68, 0x09, 0x25, 0x09, 0x23, 0x06, 0x06, + 0x13, 0x07, 0x16, 0x03, 0x16, 0x02, 0x09, 0x0B, + 0x16, 0xA2, 0x09, 0x3B, 0x03, 0x12, 0x00, 0x2E, + 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, + 0x2F, 0x5F, 0x5F, 0x62, 0x69, 0x2E, 0x70, 0x79, + 0x00, 0x04, 0x1D, 0x0A, 0x4B, 0x00, 0x01, 0x43, + 0x03, 0x01, 0x00, 0x12, 0x00, 0x04, 0x01, 0x03, + 0x03, 0x00, 0x61, 0x62, 0x73, 0x03, 0x02, 0x00, + 0x00, 0x02, 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, + 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x5F, + 0x5F, 0x62, 0x69, 0x2E, 0x70, 0x79, 0x00, 0x04, + 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x7C, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x0B, + 0x66, 0x02, 0x00, 0x7C, 0x00, 0x00, 0x64, 0x01, + 0x00, 0x6A, 0x00, 0x00, 0x19, 0x53, 0x0B, 0x01, + 0x00, 0x00, 0x0B, 0x01, 0x01, 0x00, 0x0B, 0x03, + 0x02, 0x00, 0x0A, 0x64, 0x00, 0x02, 0x43, 0x04, + 0x04, 0x00, 0xFC, 0x00, 0x04, 0x01, 0x03, 0x06, + 0x00, 0x66, 0x69, 0x6C, 0x74, 0x65, 0x72, 0x03, + 0x02, 0x00, 0x00, 0x01, 0x03, 0x12, 0x00, 0x2E, + 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, + 0x2F, 0x5F, 0x5F, 0x62, 0x69, 0x2E, 0x70, 0x79, + 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x67, 0x00, + 0x00, 0x04, 0x7D, 0x02, 0x00, 0x7C, 0x01, 0x00, + 0x44, 0x5D, 0x1E, 0x00, 0x7D, 0x03, 0x00, 0x7C, + 0x00, 0x00, 0x7C, 0x03, 0x00, 0x83, 0x01, 0x00, + 0x6F, 0x0B, 0x00, 0x01, 0x7C, 0x02, 0x00, 0x7C, + 0x03, 0x00, 0x12, 0x71, 0x0B, 0x00, 0x01, 0x71, + 0x0B, 0x00, 0x7E, 0x02, 0x00, 0x53, 0x0B, 0x00, + 0x03, 0x00, 0x0B, 0x01, 0x04, 0x00, 0x0B, 0x01, + 0x05, 0x00, 0x0B, 0x00, 0x06, 0x00, 0x0A, 0x9C, + 0x00, 0x02, 0x43, 0x04, 0x05, 0x00, 0x8C, 0x01, + 0x04, 0x03, 0x03, 0x04, 0x00, 0x4E, 0x6F, 0x6E, + 0x65, 0x03, 0x03, 0x00, 0x6C, 0x65, 0x6E, 0x03, + 0x03, 0x00, 0x6D, 0x61, 0x70, 0x03, 0x0E, 0x00, + 0x00, 0x02, 0x13, 0x03, 0x06, 0x01, 0x07, 0x00, + 0x06, 0x01, 0x10, 0x01, 0x0E, 0x03, 0x03, 0x12, + 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, + 0x69, 0x62, 0x2F, 0x5F, 0x5F, 0x62, 0x69, 0x2E, + 0x70, 0x79, 0x00, 0x04, 0x03, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x64, 0x00, 0x00, 0x67, 0x01, 0x00, + 0x74, 0x01, 0x00, 0x7C, 0x01, 0x00, 0x83, 0x01, + 0x00, 0x14, 0x7D, 0x02, 0x00, 0x64, 0x01, 0x00, + 0x7D, 0x03, 0x00, 0x78, 0x28, 0x00, 0x7C, 0x01, + 0x00, 0x44, 0x5D, 0x20, 0x00, 0x7D, 0x04, 0x00, + 0x7C, 0x00, 0x00, 0x7C, 0x04, 0x00, 0x83, 0x01, + 0x00, 0x7C, 0x02, 0x00, 0x7C, 0x03, 0x00, 0x3C, + 0x7C, 0x03, 0x00, 0x64, 0x02, 0x00, 0x37, 0x7D, + 0x03, 0x00, 0x71, 0x20, 0x00, 0x57, 0x7C, 0x02, + 0x00, 0x53, 0x0B, 0x01, 0x07, 0x00, 0x0A, 0x39, + 0x00, 0x02, 0x43, 0x02, 0x02, 0x00, 0xBC, 0x01, + 0x04, 0x01, 0x03, 0x03, 0x00, 0x70, 0x6F, 0x77, + 0x03, 0x02, 0x00, 0x00, 0x01, 0x03, 0x12, 0x00, + 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, + 0x62, 0x2F, 0x5F, 0x5F, 0x62, 0x69, 0x2E, 0x70, + 0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x7C, + 0x00, 0x00, 0x7C, 0x01, 0x00, 0x13, 0x53, 0x0B, + 0x03, 0x08, 0x00, 0x0B, 0x01, 0x09, 0x00, 0x0B, + 0x01, 0x0A, 0x00, 0x0B, 0x01, 0x0B, 0x00, 0x03, + 0x03, 0x00, 0x54, 0x42, 0x44, 0x03, 0x06, 0x00, + 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x0A, 0x53, + 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0xD7, 0x02, + 0x04, 0x03, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, + 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, + 0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, + 0x5F, 0x5F, 0x03, 0x06, 0x00, 0x6F, 0x62, 0x6A, + 0x65, 0x63, 0x74, 0x03, 0x02, 0x00, 0x06, 0x01, + 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, + 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x5F, 0x5F, 0x62, + 0x69, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x00, 0x04, + 0x00, 0x65, 0x00, 0x00, 0x5A, 0x01, 0x00, 0x52, + 0x53, 0x03, 0x09, 0x00, 0x45, 0x78, 0x63, 0x65, + 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x0A, 0x56, 0x00, + 0x00, 0x42, 0x01, 0x00, 0x00, 0xDE, 0x02, 0x04, + 0x03, 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, + 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 0x5F, + 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x5F, + 0x5F, 0x03, 0x09, 0x00, 0x45, 0x78, 0x63, 0x65, + 0x70, 0x74, 0x69, 0x6F, 0x6E, 0x03, 0x02, 0x00, + 0x06, 0x01, 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, + 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x5F, + 0x5F, 0x62, 0x69, 0x2E, 0x70, 0x79, 0x00, 0x04, + 0x00, 0x04, 0x00, 0x65, 0x00, 0x00, 0x5A, 0x01, + 0x00, 0x52, 0x53, 0x03, 0x0E, 0x00, 0x41, 0x73, + 0x73, 0x65, 0x72, 0x74, 0x69, 0x6F, 0x6E, 0x45, + 0x72, 0x72, 0x6F, 0x72, 0x0A, 0x5B, 0x00, 0x00, + 0x42, 0x01, 0x00, 0x00, 0xE1, 0x02, 0x04, 0x03, + 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, 0x6D, + 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 0x5F, 0x5F, + 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x5F, 0x5F, + 0x03, 0x0E, 0x00, 0x41, 0x73, 0x73, 0x65, 0x72, + 0x74, 0x69, 0x6F, 0x6E, 0x45, 0x72, 0x72, 0x6F, + 0x72, 0x03, 0x02, 0x00, 0x06, 0x01, 0x03, 0x12, + 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, + 0x69, 0x62, 0x2F, 0x5F, 0x5F, 0x62, 0x69, 0x2E, + 0x70, 0x79, 0x00, 0x04, 0x00, 0x04, 0x00, 0x65, + 0x00, 0x00, 0x5A, 0x01, 0x00, 0x52, 0x53, 0x01, + 0xE4, 0x00, 0x00, 0x00, 0x03, 0x09, 0x00, 0x47, + 0x65, 0x6E, 0x65, 0x72, 0x61, 0x74, 0x6F, 0x72, + 0x0A, 0xE3, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, + 0xEE, 0x02, 0x04, 0x06, 0x03, 0x08, 0x00, 0x5F, + 0x5F, 0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, + 0x0A, 0x00, 0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, + 0x6C, 0x65, 0x5F, 0x5F, 0x03, 0x08, 0x00, 0x5F, + 0x5F, 0x69, 0x6E, 0x69, 0x74, 0x5F, 0x5F, 0x03, + 0x04, 0x00, 0x6E, 0x65, 0x78, 0x74, 0x03, 0x04, + 0x00, 0x73, 0x65, 0x6E, 0x64, 0x03, 0x09, 0x00, + 0x47, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x74, 0x6F, + 0x72, 0x03, 0x06, 0x00, 0x06, 0x02, 0x09, 0x37, + 0x09, 0x04, 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, + 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x5F, + 0x5F, 0x62, 0x69, 0x2E, 0x70, 0x79, 0x00, 0x04, + 0x03, 0x0B, 0x02, 0x0C, 0x00, 0x0A, 0x4D, 0x00, + 0x01, 0x43, 0x02, 0x01, 0x00, 0x27, 0x03, 0x04, + 0x03, 0x03, 0x04, 0x00, 0x73, 0x65, 0x6E, 0x64, + 0x03, 0x04, 0x00, 0x4E, 0x6F, 0x6E, 0x65, 0x03, + 0x04, 0x00, 0x6E, 0x65, 0x78, 0x74, 0x03, 0x02, + 0x00, 0x00, 0x01, 0x03, 0x12, 0x00, 0x2E, 0x2E, + 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, + 0x5F, 0x5F, 0x62, 0x69, 0x2E, 0x70, 0x79, 0x00, + 0x04, 0x01, 0x00, 0x04, 0x00, 0x7C, 0x00, 0x00, + 0x69, 0x00, 0x00, 0x64, 0x00, 0x00, 0x83, 0x01, + 0x00, 0x53, 0x0B, 0x02, 0x0D, 0x00, 0x04, 0x00, + 0x65, 0x00, 0x00, 0x5A, 0x01, 0x00, 0x64, 0x00, + 0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, + 0x01, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, + 0x64, 0x02, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, + 0x00, 0x52, 0x53, 0x0B, 0x00, 0x0E, 0x00, 0x00, + 0x04, 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 0x84, + 0x00, 0x00, 0x5A, 0x00, 0x00, 0x64, 0x01, 0x00, + 0x84, 0x00, 0x00, 0x5A, 0x01, 0x00, 0x64, 0x02, + 0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, + 0x03, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, + 0x64, 0x04, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, + 0x00, 0x64, 0x05, 0x00, 0x84, 0x00, 0x00, 0x5A, + 0x05, 0x00, 0x64, 0x06, 0x00, 0x84, 0x00, 0x00, + 0x5A, 0x06, 0x00, 0x64, 0x07, 0x00, 0x84, 0x00, + 0x00, 0x5A, 0x07, 0x00, 0x64, 0x08, 0x00, 0x84, + 0x00, 0x00, 0x5A, 0x08, 0x00, 0x64, 0x09, 0x00, + 0x84, 0x00, 0x00, 0x5A, 0x09, 0x00, 0x64, 0x0A, + 0x00, 0x84, 0x00, 0x00, 0x5A, 0x0A, 0x00, 0x64, + 0x0B, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x0B, 0x00, + 0x64, 0x0C, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x0C, + 0x00, 0x64, 0x0D, 0x00, 0x84, 0x00, 0x00, 0x5A, + 0x0D, 0x00, 0x64, 0x0E, 0x00, 0x84, 0x00, 0x00, + 0x5A, 0x0E, 0x00, 0x64, 0x0F, 0x00, 0x84, 0x00, + 0x00, 0x5A, 0x0F, 0x00, 0x64, 0x10, 0x00, 0x5A, + 0x10, 0x00, 0x64, 0x11, 0x00, 0x64, 0x1C, 0x00, + 0x64, 0x12, 0x00, 0x84, 0x00, 0x00, 0x83, 0x00, + 0x00, 0x59, 0x5A, 0x11, 0x00, 0x64, 0x13, 0x00, + 0x65, 0x11, 0x00, 0x66, 0x01, 0x00, 0x64, 0x14, + 0x00, 0x84, 0x00, 0x00, 0x83, 0x00, 0x00, 0x59, + 0x5A, 0x12, 0x00, 0x64, 0x15, 0x00, 0x65, 0x12, + 0x00, 0x66, 0x01, 0x00, 0x64, 0x16, 0x00, 0x84, + 0x00, 0x00, 0x83, 0x00, 0x00, 0x59, 0x5A, 0x13, + 0x00, 0x64, 0x17, 0x00, 0x65, 0x13, 0x00, 0x5F, + 0x14, 0x00, 0x64, 0x18, 0x00, 0x65, 0x11, 0x00, + 0x66, 0x01, 0x00, 0x64, 0x19, 0x00, 0x84, 0x00, + 0x00, 0x83, 0x00, 0x00, 0x59, 0x5A, 0x15, 0x00, + 0x64, 0x1A, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x16, + 0x00, 0x68, 0x00, 0x00, 0x5A, 0x17, 0x00, 0x64, + 0x1B, 0x00, 0x53, + +/* ../../lib/dict.py */ + 0x0A, 0x0A, 0x03, 0x00, 0x40, 0x03, 0x00, 0x00, + 0x0C, 0x00, 0x04, 0x08, 0x03, 0x08, 0x00, 0x5F, + 0x5F, 0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, + 0x08, 0x00, 0x5F, 0x41, 0x75, 0x74, 0x6F, 0x62, + 0x6F, 0x78, 0x03, 0x05, 0x00, 0x63, 0x6C, 0x65, + 0x61, 0x72, 0x03, 0x04, 0x00, 0x6B, 0x65, 0x79, + 0x73, 0x03, 0x07, 0x00, 0x68, 0x61, 0x73, 0x5F, + 0x6B, 0x65, 0x79, 0x03, 0x06, 0x00, 0x76, 0x61, + 0x6C, 0x75, 0x65, 0x73, 0x03, 0x06, 0x00, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x03, 0x04, 0x00, + 0x64, 0x69, 0x63, 0x74, 0x03, 0x0C, 0x00, 0x06, + 0x03, 0x13, 0x0E, 0x09, 0x18, 0x09, 0x2B, 0x09, + 0x04, 0x09, 0x2B, 0x03, 0x12, 0x00, 0x2E, 0x2E, + 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, + 0x64, 0x69, 0x63, 0x74, 0x2E, 0x70, 0x79, 0x00, + 0x04, 0x0A, 0x03, 0x04, 0x00, 0x64, 0x69, 0x63, + 0x74, 0x03, 0x08, 0x00, 0x5F, 0x41, 0x75, 0x74, + 0x6F, 0x62, 0x6F, 0x78, 0x0A, 0xE0, 0x01, 0x00, + 0x42, 0x01, 0x00, 0x00, 0x0F, 0x00, 0x04, 0x07, + 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, 0x6D, + 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 0x5F, 0x5F, + 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x5F, 0x5F, + 0x03, 0x05, 0x00, 0x63, 0x6C, 0x65, 0x61, 0x72, + 0x03, 0x04, 0x00, 0x6B, 0x65, 0x79, 0x73, 0x03, + 0x07, 0x00, 0x68, 0x61, 0x73, 0x5F, 0x6B, 0x65, + 0x79, 0x03, 0x06, 0x00, 0x76, 0x61, 0x6C, 0x75, + 0x65, 0x73, 0x03, 0x08, 0x00, 0x5F, 0x41, 0x75, + 0x74, 0x6F, 0x62, 0x6F, 0x78, 0x03, 0x08, 0x00, + 0x06, 0x01, 0x09, 0x03, 0x09, 0x03, 0x09, 0x03, + 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, + 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x64, 0x69, 0x63, + 0x74, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x04, 0x0A, + 0x4E, 0x00, 0x01, 0x43, 0x02, 0x01, 0x00, 0x10, + 0x00, 0x04, 0x03, 0x03, 0x05, 0x00, 0x63, 0x6C, + 0x65, 0x61, 0x72, 0x03, 0x03, 0x00, 0x6F, 0x62, + 0x6A, 0x03, 0x05, 0x00, 0x63, 0x6C, 0x65, 0x61, + 0x72, 0x03, 0x02, 0x00, 0x00, 0x01, 0x03, 0x12, + 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, + 0x69, 0x62, 0x2F, 0x64, 0x69, 0x63, 0x74, 0x2E, + 0x70, 0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, + 0x74, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x69, 0x01, + 0x00, 0x83, 0x01, 0x00, 0x53, 0x0A, 0x4C, 0x00, + 0x01, 0x43, 0x02, 0x01, 0x00, 0x13, 0x00, 0x04, + 0x03, 0x03, 0x04, 0x00, 0x6B, 0x65, 0x79, 0x73, + 0x03, 0x03, 0x00, 0x6F, 0x62, 0x6A, 0x03, 0x04, + 0x00, 0x6B, 0x65, 0x79, 0x73, 0x03, 0x02, 0x00, + 0x00, 0x01, 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, + 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x64, + 0x69, 0x63, 0x74, 0x2E, 0x70, 0x79, 0x00, 0x04, + 0x01, 0x00, 0x04, 0x00, 0x74, 0x00, 0x00, 0x7C, + 0x00, 0x00, 0x69, 0x01, 0x00, 0x83, 0x01, 0x00, + 0x53, 0x0A, 0x55, 0x00, 0x02, 0x43, 0x03, 0x02, + 0x00, 0x16, 0x00, 0x04, 0x03, 0x03, 0x07, 0x00, + 0x68, 0x61, 0x73, 0x5F, 0x6B, 0x65, 0x79, 0x03, + 0x03, 0x00, 0x6F, 0x62, 0x6A, 0x03, 0x07, 0x00, + 0x68, 0x61, 0x73, 0x5F, 0x6B, 0x65, 0x79, 0x03, + 0x02, 0x00, 0x00, 0x01, 0x03, 0x12, 0x00, 0x2E, + 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, + 0x2F, 0x64, 0x69, 0x63, 0x74, 0x2E, 0x70, 0x79, + 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x74, 0x00, + 0x00, 0x7C, 0x00, 0x00, 0x69, 0x01, 0x00, 0x7C, + 0x01, 0x00, 0x83, 0x02, 0x00, 0x53, 0x0A, 0x50, + 0x00, 0x01, 0x43, 0x02, 0x01, 0x00, 0x19, 0x00, + 0x04, 0x03, 0x03, 0x06, 0x00, 0x76, 0x61, 0x6C, + 0x75, 0x65, 0x73, 0x03, 0x03, 0x00, 0x6F, 0x62, + 0x6A, 0x03, 0x06, 0x00, 0x76, 0x61, 0x6C, 0x75, + 0x65, 0x73, 0x03, 0x02, 0x00, 0x00, 0x01, 0x03, + 0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, + 0x6C, 0x69, 0x62, 0x2F, 0x64, 0x69, 0x63, 0x74, + 0x2E, 0x70, 0x79, 0x00, 0x04, 0x01, 0x00, 0x04, + 0x00, 0x74, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x69, + 0x01, 0x00, 0x83, 0x01, 0x00, 0x53, 0x04, 0x00, + 0x65, 0x00, 0x00, 0x5A, 0x01, 0x00, 0x64, 0x00, + 0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, + 0x01, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, + 0x64, 0x02, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, + 0x00, 0x64, 0x03, 0x00, 0x84, 0x00, 0x00, 0x5A, + 0x05, 0x00, 0x52, 0x53, 0x0B, 0x01, 0x0F, 0x00, + 0x0B, 0x01, 0x10, 0x00, 0x0A, 0x3F, 0x00, 0x02, + 0x43, 0x02, 0x02, 0x00, 0x60, 0x00, 0x04, 0x01, + 0x03, 0x07, 0x00, 0x68, 0x61, 0x73, 0x5F, 0x6B, + 0x65, 0x79, 0x03, 0x02, 0x00, 0x00, 0x01, 0x03, + 0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, + 0x6C, 0x69, 0x62, 0x2F, 0x64, 0x69, 0x63, 0x74, + 0x2E, 0x70, 0x79, 0x00, 0x04, 0x01, 0x00, 0x04, + 0x00, 0x7C, 0x01, 0x00, 0x7C, 0x00, 0x00, 0x6A, + 0x06, 0x00, 0x53, 0x0B, 0x01, 0x11, 0x00, 0x0B, + 0x02, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, + 0x64, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x64, 0x01, + 0x00, 0x64, 0x09, 0x00, 0x64, 0x02, 0x00, 0x84, + 0x00, 0x00, 0x83, 0x00, 0x00, 0x59, 0x5A, 0x01, + 0x00, 0x64, 0x03, 0x00, 0x84, 0x00, 0x00, 0x5A, + 0x02, 0x00, 0x64, 0x04, 0x00, 0x84, 0x00, 0x00, + 0x5A, 0x03, 0x00, 0x64, 0x05, 0x00, 0x84, 0x00, + 0x00, 0x5A, 0x04, 0x00, 0x64, 0x06, 0x00, 0x84, + 0x00, 0x00, 0x5A, 0x05, 0x00, 0x64, 0x07, 0x00, + 0x84, 0x00, 0x00, 0x5A, 0x06, 0x00, 0x64, 0x08, + 0x00, 0x53, + +/* ../../lib/list.py */ + 0x0A, 0x41, 0x05, 0x00, 0x40, 0x03, 0x00, 0x00, + 0x10, 0x00, 0x04, 0x0A, 0x03, 0x08, 0x00, 0x5F, + 0x5F, 0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, + 0x08, 0x00, 0x5F, 0x41, 0x75, 0x74, 0x6F, 0x62, + 0x6F, 0x78, 0x03, 0x06, 0x00, 0x61, 0x70, 0x70, + 0x65, 0x6E, 0x64, 0x03, 0x05, 0x00, 0x63, 0x6F, + 0x75, 0x6E, 0x74, 0x03, 0x06, 0x00, 0x65, 0x78, + 0x74, 0x65, 0x6E, 0x64, 0x03, 0x05, 0x00, 0x69, + 0x6E, 0x64, 0x65, 0x78, 0x03, 0x06, 0x00, 0x69, + 0x6E, 0x73, 0x65, 0x72, 0x74, 0x03, 0x03, 0x00, + 0x70, 0x6F, 0x70, 0x03, 0x06, 0x00, 0x72, 0x65, + 0x6D, 0x6F, 0x76, 0x65, 0x03, 0x04, 0x00, 0x6C, + 0x69, 0x73, 0x74, 0x03, 0x10, 0x00, 0x06, 0x02, + 0x13, 0x1A, 0x09, 0x17, 0x09, 0x08, 0x09, 0x05, + 0x09, 0x22, 0x09, 0x27, 0x09, 0x37, 0x03, 0x12, + 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, + 0x69, 0x62, 0x2F, 0x6C, 0x69, 0x73, 0x74, 0x2E, + 0x70, 0x79, 0x00, 0x04, 0x0C, 0x03, 0x04, 0x00, + 0x6C, 0x69, 0x73, 0x74, 0x03, 0x08, 0x00, 0x5F, + 0x41, 0x75, 0x74, 0x6F, 0x62, 0x6F, 0x78, 0x0A, + 0x4D, 0x03, 0x00, 0x42, 0x02, 0x00, 0x00, 0x12, + 0x00, 0x04, 0x0B, 0x03, 0x08, 0x00, 0x5F, 0x5F, + 0x6E, 0x61, 0x6D, 0x65, 0x5F, 0x5F, 0x03, 0x0A, + 0x00, 0x5F, 0x5F, 0x6D, 0x6F, 0x64, 0x75, 0x6C, + 0x65, 0x5F, 0x5F, 0x03, 0x06, 0x00, 0x61, 0x70, + 0x70, 0x65, 0x6E, 0x64, 0x03, 0x05, 0x00, 0x63, + 0x6F, 0x75, 0x6E, 0x74, 0x03, 0x06, 0x00, 0x65, + 0x78, 0x74, 0x65, 0x6E, 0x64, 0x03, 0x05, 0x00, + 0x69, 0x6E, 0x64, 0x65, 0x78, 0x03, 0x06, 0x00, + 0x69, 0x6E, 0x73, 0x65, 0x72, 0x74, 0x03, 0x04, + 0x00, 0x4E, 0x6F, 0x6E, 0x65, 0x03, 0x03, 0x00, + 0x70, 0x6F, 0x70, 0x03, 0x06, 0x00, 0x72, 0x65, + 0x6D, 0x6F, 0x76, 0x65, 0x03, 0x08, 0x00, 0x5F, + 0x41, 0x75, 0x74, 0x6F, 0x62, 0x6F, 0x78, 0x03, + 0x0E, 0x00, 0x06, 0x01, 0x09, 0x03, 0x09, 0x03, + 0x09, 0x03, 0x09, 0x03, 0x09, 0x03, 0x0C, 0x06, + 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, + 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x6C, 0x69, 0x73, + 0x74, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x08, 0x0A, + 0x53, 0x00, 0x02, 0x43, 0x03, 0x02, 0x00, 0x13, + 0x00, 0x04, 0x03, 0x03, 0x06, 0x00, 0x61, 0x70, + 0x70, 0x65, 0x6E, 0x64, 0x03, 0x03, 0x00, 0x6F, + 0x62, 0x6A, 0x03, 0x06, 0x00, 0x61, 0x70, 0x70, + 0x65, 0x6E, 0x64, 0x03, 0x02, 0x00, 0x00, 0x01, + 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, + 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x6C, 0x69, 0x73, + 0x74, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x01, 0x00, + 0x04, 0x00, 0x74, 0x00, 0x00, 0x7C, 0x00, 0x00, + 0x69, 0x01, 0x00, 0x7C, 0x01, 0x00, 0x83, 0x02, + 0x00, 0x53, 0x0A, 0x51, 0x00, 0x02, 0x43, 0x03, + 0x02, 0x00, 0x16, 0x00, 0x04, 0x03, 0x03, 0x05, + 0x00, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x03, 0x03, + 0x00, 0x6F, 0x62, 0x6A, 0x03, 0x05, 0x00, 0x63, + 0x6F, 0x75, 0x6E, 0x74, 0x03, 0x02, 0x00, 0x00, + 0x01, 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, + 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x6C, 0x69, + 0x73, 0x74, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x01, + 0x00, 0x04, 0x00, 0x74, 0x00, 0x00, 0x7C, 0x00, + 0x00, 0x69, 0x01, 0x00, 0x7C, 0x01, 0x00, 0x83, + 0x02, 0x00, 0x53, 0x0A, 0x53, 0x00, 0x02, 0x43, + 0x03, 0x02, 0x00, 0x19, 0x00, 0x04, 0x03, 0x03, + 0x06, 0x00, 0x65, 0x78, 0x74, 0x65, 0x6E, 0x64, + 0x03, 0x03, 0x00, 0x6F, 0x62, 0x6A, 0x03, 0x06, + 0x00, 0x65, 0x78, 0x74, 0x65, 0x6E, 0x64, 0x03, + 0x02, 0x00, 0x00, 0x01, 0x03, 0x12, 0x00, 0x2E, + 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, + 0x2F, 0x6C, 0x69, 0x73, 0x74, 0x2E, 0x70, 0x79, + 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x74, 0x00, + 0x00, 0x7C, 0x00, 0x00, 0x69, 0x01, 0x00, 0x7C, + 0x01, 0x00, 0x83, 0x02, 0x00, 0x53, 0x0A, 0x51, + 0x00, 0x02, 0x43, 0x03, 0x02, 0x00, 0x1C, 0x00, + 0x04, 0x03, 0x03, 0x05, 0x00, 0x69, 0x6E, 0x64, + 0x65, 0x78, 0x03, 0x03, 0x00, 0x6F, 0x62, 0x6A, + 0x03, 0x05, 0x00, 0x69, 0x6E, 0x64, 0x65, 0x78, + 0x03, 0x02, 0x00, 0x00, 0x01, 0x03, 0x12, 0x00, + 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, + 0x62, 0x2F, 0x6C, 0x69, 0x73, 0x74, 0x2E, 0x70, + 0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x74, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0x69, 0x01, 0x00, + 0x7C, 0x01, 0x00, 0x83, 0x02, 0x00, 0x53, 0x0A, + 0x56, 0x00, 0x03, 0x43, 0x04, 0x03, 0x00, 0x1F, + 0x00, 0x04, 0x03, 0x03, 0x06, 0x00, 0x69, 0x6E, + 0x73, 0x65, 0x72, 0x74, 0x03, 0x03, 0x00, 0x6F, + 0x62, 0x6A, 0x03, 0x06, 0x00, 0x69, 0x6E, 0x73, + 0x65, 0x72, 0x74, 0x03, 0x02, 0x00, 0x00, 0x01, + 0x03, 0x12, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, + 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x6C, 0x69, 0x73, + 0x74, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x01, 0x00, + 0x04, 0x00, 0x74, 0x00, 0x00, 0x7C, 0x00, 0x00, + 0x69, 0x01, 0x00, 0x7C, 0x01, 0x00, 0x7C, 0x02, + 0x00, 0x83, 0x03, 0x00, 0x53, 0x0A, 0x77, 0x00, + 0x02, 0x43, 0x03, 0x02, 0x00, 0x22, 0x00, 0x04, + 0x04, 0x03, 0x04, 0x00, 0x4E, 0x6F, 0x6E, 0x65, + 0x03, 0x03, 0x00, 0x70, 0x6F, 0x70, 0x03, 0x03, + 0x00, 0x6F, 0x62, 0x6A, 0x03, 0x03, 0x00, 0x70, + 0x6F, 0x70, 0x03, 0x06, 0x00, 0x00, 0x01, 0x0D, + 0x01, 0x0E, 0x02, 0x03, 0x12, 0x00, 0x2E, 0x2E, + 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, + 0x6C, 0x69, 0x73, 0x74, 0x2E, 0x70, 0x79, 0x00, + 0x04, 0x01, 0x00, 0x04, 0x00, 0x7C, 0x01, 0x00, + 0x64, 0x00, 0x00, 0x6A, 0x02, 0x00, 0x6F, 0x0E, + 0x00, 0x01, 0x74, 0x01, 0x00, 0x7C, 0x00, 0x00, + 0x69, 0x02, 0x00, 0x83, 0x01, 0x00, 0x53, 0x01, + 0x74, 0x01, 0x00, 0x7C, 0x00, 0x00, 0x69, 0x02, + 0x00, 0x7C, 0x01, 0x00, 0x83, 0x02, 0x00, 0x53, + 0x64, 0x00, 0x00, 0x53, 0x0A, 0x53, 0x00, 0x02, + 0x43, 0x03, 0x02, 0x00, 0x28, 0x00, 0x04, 0x03, + 0x03, 0x06, 0x00, 0x72, 0x65, 0x6D, 0x6F, 0x76, + 0x65, 0x03, 0x03, 0x00, 0x6F, 0x62, 0x6A, 0x03, + 0x06, 0x00, 0x72, 0x65, 0x6D, 0x6F, 0x76, 0x65, + 0x03, 0x02, 0x00, 0x00, 0x01, 0x03, 0x12, 0x00, + 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, + 0x62, 0x2F, 0x6C, 0x69, 0x73, 0x74, 0x2E, 0x70, + 0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x74, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0x69, 0x01, 0x00, + 0x7C, 0x01, 0x00, 0x83, 0x02, 0x00, 0x53, 0x00, + 0x04, 0x00, 0x65, 0x00, 0x00, 0x5A, 0x01, 0x00, + 0x64, 0x00, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, + 0x00, 0x64, 0x01, 0x00, 0x84, 0x00, 0x00, 0x5A, + 0x03, 0x00, 0x64, 0x02, 0x00, 0x84, 0x00, 0x00, + 0x5A, 0x04, 0x00, 0x64, 0x03, 0x00, 0x84, 0x00, + 0x00, 0x5A, 0x05, 0x00, 0x64, 0x04, 0x00, 0x84, + 0x00, 0x00, 0x5A, 0x06, 0x00, 0x64, 0x07, 0x00, + 0x64, 0x05, 0x00, 0x84, 0x01, 0x00, 0x5A, 0x08, + 0x00, 0x64, 0x06, 0x00, 0x84, 0x00, 0x00, 0x5A, + 0x09, 0x00, 0x52, 0x53, 0x0B, 0x02, 0x13, 0x00, + 0x0A, 0x7D, 0x00, 0x02, 0x43, 0x03, 0x04, 0x00, + 0x43, 0x00, 0x04, 0x01, 0x03, 0x05, 0x00, 0x63, + 0x6F, 0x75, 0x6E, 0x74, 0x03, 0x0C, 0x00, 0x00, + 0x01, 0x06, 0x01, 0x07, 0x00, 0x06, 0x01, 0x0D, + 0x01, 0x12, 0x01, 0x03, 0x12, 0x00, 0x2E, 0x2E, + 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, + 0x6C, 0x69, 0x73, 0x74, 0x2E, 0x70, 0x79, 0x00, + 0x04, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x64, + 0x01, 0x00, 0x7D, 0x02, 0x00, 0x78, 0x29, 0x00, + 0x7C, 0x00, 0x00, 0x44, 0x5D, 0x21, 0x00, 0x7D, + 0x03, 0x00, 0x7C, 0x03, 0x00, 0x7C, 0x01, 0x00, + 0x6A, 0x02, 0x00, 0x6F, 0x0E, 0x00, 0x01, 0x7C, + 0x02, 0x00, 0x64, 0x02, 0x00, 0x17, 0x7D, 0x02, + 0x00, 0x71, 0x0D, 0x00, 0x01, 0x71, 0x0D, 0x00, + 0x57, 0x7C, 0x02, 0x00, 0x53, 0x0A, 0x63, 0x00, + 0x02, 0x43, 0x04, 0x03, 0x00, 0x4B, 0x00, 0x04, + 0x02, 0x03, 0x06, 0x00, 0x61, 0x70, 0x70, 0x65, + 0x6E, 0x64, 0x03, 0x06, 0x00, 0x65, 0x78, 0x74, + 0x65, 0x6E, 0x64, 0x03, 0x06, 0x00, 0x00, 0x01, + 0x07, 0x00, 0x06, 0x01, 0x03, 0x12, 0x00, 0x2E, + 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, + 0x2F, 0x6C, 0x69, 0x73, 0x74, 0x2E, 0x70, 0x79, + 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x78, 0x1B, + 0x00, 0x7C, 0x01, 0x00, 0x44, 0x5D, 0x13, 0x00, + 0x7D, 0x02, 0x00, 0x74, 0x00, 0x00, 0x7C, 0x00, + 0x00, 0x7C, 0x02, 0x00, 0x83, 0x02, 0x00, 0x01, + 0x71, 0x07, 0x00, 0x57, 0x64, 0x00, 0x00, 0x53, + 0x0B, 0x02, 0x14, 0x00, 0x0B, 0x03, 0x15, 0x00, + 0x0B, 0x02, 0x16, 0x00, 0x0B, 0x02, 0x17, 0x00, + 0x00, 0x04, 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, + 0x5A, 0x00, 0x00, 0x64, 0x01, 0x00, 0x64, 0x0B, + 0x00, 0x64, 0x02, 0x00, 0x84, 0x00, 0x00, 0x83, + 0x00, 0x00, 0x59, 0x5A, 0x01, 0x00, 0x64, 0x03, + 0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, 0x00, 0x64, + 0x04, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x03, 0x00, + 0x64, 0x05, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x04, + 0x00, 0x64, 0x06, 0x00, 0x84, 0x00, 0x00, 0x5A, + 0x05, 0x00, 0x64, 0x07, 0x00, 0x84, 0x00, 0x00, + 0x5A, 0x06, 0x00, 0x64, 0x08, 0x00, 0x84, 0x00, + 0x00, 0x5A, 0x07, 0x00, 0x64, 0x09, 0x00, 0x84, + 0x00, 0x00, 0x5A, 0x08, 0x00, 0x64, 0x0A, 0x00, + 0x53, + +/* ../../lib/string.py */ + 0x0A, 0xBF, 0x03, 0x00, 0x40, 0x03, 0x00, 0x00, + 0x10, 0x00, 0x04, 0x0B, 0x03, 0x07, 0x00, 0x5F, + 0x5F, 0x64, 0x6F, 0x63, 0x5F, 0x5F, 0x03, 0x08, + 0x00, 0x5F, 0x5F, 0x6E, 0x61, 0x6D, 0x65, 0x5F, + 0x5F, 0x03, 0x08, 0x00, 0x5F, 0x41, 0x75, 0x74, + 0x6F, 0x62, 0x6F, 0x78, 0x03, 0x06, 0x00, 0x64, + 0x69, 0x67, 0x69, 0x74, 0x73, 0x03, 0x09, 0x00, + 0x68, 0x65, 0x78, 0x64, 0x69, 0x67, 0x69, 0x74, + 0x73, 0x03, 0x07, 0x00, 0x6C, 0x65, 0x74, 0x74, + 0x65, 0x72, 0x73, 0x03, 0x04, 0x00, 0x61, 0x74, + 0x6F, 0x69, 0x03, 0x05, 0x00, 0x63, 0x6F, 0x75, + 0x6E, 0x74, 0x03, 0x04, 0x00, 0x66, 0x69, 0x6E, + 0x64, 0x03, 0x04, 0x00, 0x6A, 0x6F, 0x69, 0x6E, + 0x03, 0x06, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, + 0x67, 0x03, 0x12, 0x00, 0x06, 0x03, 0x06, 0x03, + 0x13, 0x0B, 0x06, 0x01, 0x06, 0x01, 0x06, 0x07, + 0x09, 0x45, 0x09, 0x57, 0x09, 0x3B, 0x03, 0x14, + 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, + 0x69, 0x62, 0x2F, 0x73, 0x74, 0x72, 0x69, 0x6E, + 0x67, 0x2E, 0x70, 0x79, 0x00, 0x04, 0x0E, 0x00, + 0x03, 0x06, 0x00, 0x73, 0x74, 0x72, 0x69, 0x6E, + 0x67, 0x03, 0x08, 0x00, 0x5F, 0x41, 0x75, 0x74, + 0x6F, 0x62, 0x6F, 0x78, 0x0A, 0x81, 0x01, 0x00, + 0x42, 0x01, 0x00, 0x00, 0x16, 0x00, 0x04, 0x06, + 0x03, 0x08, 0x00, 0x5F, 0x5F, 0x6E, 0x61, 0x6D, + 0x65, 0x5F, 0x5F, 0x03, 0x0A, 0x00, 0x5F, 0x5F, + 0x6D, 0x6F, 0x64, 0x75, 0x6C, 0x65, 0x5F, 0x5F, + 0x03, 0x04, 0x00, 0x6A, 0x6F, 0x69, 0x6E, 0x03, + 0x05, 0x00, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x03, + 0x04, 0x00, 0x66, 0x69, 0x6E, 0x64, 0x03, 0x08, + 0x00, 0x5F, 0x41, 0x75, 0x74, 0x6F, 0x62, 0x6F, + 0x78, 0x03, 0x06, 0x00, 0x06, 0x01, 0x09, 0x03, + 0x09, 0x03, 0x03, 0x14, 0x00, 0x2E, 0x2E, 0x2F, + 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x73, + 0x74, 0x72, 0x69, 0x6E, 0x67, 0x2E, 0x70, 0x79, + 0x00, 0x04, 0x03, 0x0A, 0x51, 0x00, 0x02, 0x43, + 0x03, 0x02, 0x00, 0x17, 0x00, 0x04, 0x03, 0x03, + 0x04, 0x00, 0x6A, 0x6F, 0x69, 0x6E, 0x03, 0x03, + 0x00, 0x6F, 0x62, 0x6A, 0x03, 0x04, 0x00, 0x6A, + 0x6F, 0x69, 0x6E, 0x03, 0x02, 0x00, 0x00, 0x01, + 0x03, 0x14, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, + 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x73, 0x74, 0x72, + 0x69, 0x6E, 0x67, 0x2E, 0x70, 0x79, 0x00, 0x04, + 0x01, 0x00, 0x04, 0x00, 0x74, 0x00, 0x00, 0x7C, + 0x00, 0x00, 0x69, 0x01, 0x00, 0x7C, 0x01, 0x00, + 0x83, 0x02, 0x00, 0x53, 0x0A, 0x53, 0x00, 0x02, + 0x43, 0x03, 0x02, 0x00, 0x1A, 0x00, 0x04, 0x03, + 0x03, 0x05, 0x00, 0x63, 0x6F, 0x75, 0x6E, 0x74, + 0x03, 0x03, 0x00, 0x6F, 0x62, 0x6A, 0x03, 0x05, + 0x00, 0x63, 0x6F, 0x75, 0x6E, 0x74, 0x03, 0x02, + 0x00, 0x00, 0x01, 0x03, 0x14, 0x00, 0x2E, 0x2E, + 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, + 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x2E, 0x70, + 0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, 0x74, + 0x00, 0x00, 0x7C, 0x00, 0x00, 0x69, 0x01, 0x00, + 0x7C, 0x01, 0x00, 0x83, 0x02, 0x00, 0x53, 0x0A, + 0x51, 0x00, 0x02, 0x43, 0x03, 0x02, 0x00, 0x1D, + 0x00, 0x04, 0x03, 0x03, 0x04, 0x00, 0x66, 0x69, + 0x6E, 0x64, 0x03, 0x03, 0x00, 0x6F, 0x62, 0x6A, + 0x03, 0x04, 0x00, 0x66, 0x69, 0x6E, 0x64, 0x03, + 0x02, 0x00, 0x00, 0x01, 0x03, 0x14, 0x00, 0x2E, + 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, + 0x2F, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x2E, + 0x70, 0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, + 0x74, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x69, 0x01, + 0x00, 0x7C, 0x01, 0x00, 0x83, 0x02, 0x00, 0x53, + 0x04, 0x00, 0x65, 0x00, 0x00, 0x5A, 0x01, 0x00, + 0x64, 0x00, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x02, + 0x00, 0x64, 0x01, 0x00, 0x84, 0x00, 0x00, 0x5A, + 0x03, 0x00, 0x64, 0x02, 0x00, 0x84, 0x00, 0x00, + 0x5A, 0x04, 0x00, 0x52, 0x53, 0x03, 0x0A, 0x00, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x03, 0x16, 0x00, 0x30, 0x31, 0x32, + 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, + 0x62, 0x63, 0x64, 0x65, 0x66, 0x41, 0x42, 0x43, + 0x44, 0x45, 0x46, 0x03, 0x34, 0x00, 0x61, 0x62, + 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, + 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, + 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, + 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, + 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, + 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, + 0x59, 0x5A, 0x0B, 0x02, 0x18, 0x00, 0x0B, 0x02, + 0x19, 0x00, 0x0B, 0x02, 0x1A, 0x00, 0x03, 0x01, + 0x00, 0x20, 0x0A, 0xBC, 0x00, 0x02, 0x43, 0x03, + 0x05, 0x00, 0x01, 0x01, 0x04, 0x02, 0x03, 0x03, + 0x00, 0x6C, 0x65, 0x6E, 0x03, 0x04, 0x00, 0x6A, + 0x6F, 0x69, 0x6E, 0x03, 0x14, 0x00, 0x00, 0x01, + 0x0C, 0x01, 0x0D, 0x01, 0x05, 0x01, 0x0A, 0x01, + 0x06, 0x01, 0x03, 0x00, 0x0D, 0x01, 0x12, 0x01, + 0x0F, 0x01, 0x03, 0x14, 0x00, 0x2E, 0x2E, 0x2F, + 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, 0x73, + 0x74, 0x72, 0x69, 0x6E, 0x67, 0x2E, 0x70, 0x79, + 0x00, 0x04, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x74, 0x00, 0x00, 0x7C, 0x00, + 0x00, 0x83, 0x01, 0x00, 0x7D, 0x02, 0x00, 0x7C, + 0x02, 0x00, 0x64, 0x01, 0x00, 0x6A, 0x02, 0x00, + 0x6F, 0x05, 0x00, 0x01, 0x64, 0x02, 0x00, 0x53, + 0x01, 0x7C, 0x00, 0x00, 0x64, 0x01, 0x00, 0x19, + 0x7D, 0x03, 0x00, 0x64, 0x03, 0x00, 0x7D, 0x04, + 0x00, 0x78, 0x2E, 0x00, 0x7C, 0x04, 0x00, 0x7C, + 0x02, 0x00, 0x6A, 0x00, 0x00, 0x6F, 0x20, 0x00, + 0x01, 0x7C, 0x03, 0x00, 0x7C, 0x01, 0x00, 0x17, + 0x7C, 0x00, 0x00, 0x7C, 0x04, 0x00, 0x19, 0x17, + 0x7D, 0x03, 0x00, 0x7C, 0x04, 0x00, 0x64, 0x03, + 0x00, 0x37, 0x7D, 0x04, 0x00, 0x71, 0x31, 0x00, + 0x01, 0x57, 0x7C, 0x03, 0x00, 0x53, 0x00, 0x04, + 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 0x5A, 0x00, + 0x00, 0x64, 0x01, 0x00, 0x5A, 0x01, 0x00, 0x64, + 0x02, 0x00, 0x64, 0x0D, 0x00, 0x64, 0x03, 0x00, + 0x84, 0x00, 0x00, 0x83, 0x00, 0x00, 0x59, 0x5A, + 0x02, 0x00, 0x64, 0x04, 0x00, 0x5A, 0x03, 0x00, + 0x64, 0x05, 0x00, 0x5A, 0x04, 0x00, 0x64, 0x06, + 0x00, 0x5A, 0x05, 0x00, 0x64, 0x07, 0x00, 0x84, + 0x00, 0x00, 0x5A, 0x06, 0x00, 0x64, 0x08, 0x00, + 0x84, 0x00, 0x00, 0x5A, 0x07, 0x00, 0x64, 0x09, + 0x00, 0x84, 0x00, 0x00, 0x5A, 0x08, 0x00, 0x64, + 0x0A, 0x00, 0x64, 0x0B, 0x00, 0x84, 0x01, 0x00, + 0x5A, 0x09, 0x00, 0x64, 0x0C, 0x00, 0x53, + +/* ../../lib/sys.py */ + 0x0A, 0x5E, 0x01, 0x00, 0x40, 0x01, 0x00, 0x00, + 0x16, 0x00, 0x04, 0x0A, 0x03, 0x06, 0x00, 0x6D, + 0x61, 0x78, 0x69, 0x6E, 0x74, 0x03, 0x04, 0x00, + 0x65, 0x78, 0x69, 0x74, 0x03, 0x02, 0x00, 0x67, + 0x63, 0x03, 0x04, 0x00, 0x67, 0x65, 0x74, 0x62, + 0x03, 0x04, 0x00, 0x68, 0x65, 0x61, 0x70, 0x03, + 0x04, 0x00, 0x70, 0x75, 0x74, 0x62, 0x03, 0x0B, + 0x00, 0x72, 0x75, 0x6E, 0x49, 0x6E, 0x54, 0x68, + 0x72, 0x65, 0x61, 0x64, 0x03, 0x04, 0x00, 0x74, + 0x69, 0x6D, 0x65, 0x03, 0x04, 0x00, 0x77, 0x61, + 0x69, 0x74, 0x03, 0x03, 0x00, 0x73, 0x79, 0x73, + 0x03, 0x10, 0x00, 0x06, 0x03, 0x09, 0x23, 0x09, + 0x18, 0x09, 0x1A, 0x09, 0x30, 0x09, 0x21, 0x09, + 0x1E, 0x09, 0x26, 0x03, 0x11, 0x00, 0x2E, 0x2E, + 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, + 0x73, 0x79, 0x73, 0x2E, 0x70, 0x79, 0x00, 0x04, + 0x0A, 0x01, 0xFF, 0xFF, 0xFF, 0x7F, 0x0B, 0x01, + 0x1B, 0x00, 0x0B, 0x00, 0x1C, 0x00, 0x0B, 0x00, + 0x1D, 0x00, 0x0B, 0x00, 0x1E, 0x00, 0x0B, 0x01, + 0x1F, 0x00, 0x0B, 0x01, 0x20, 0x00, 0x0B, 0x00, + 0x21, 0x00, 0x0A, 0x67, 0x00, 0x01, 0x43, 0x02, + 0x02, 0x00, 0x03, 0x01, 0x04, 0x02, 0x03, 0x04, + 0x00, 0x74, 0x69, 0x6D, 0x65, 0x03, 0x04, 0x00, + 0x77, 0x61, 0x69, 0x74, 0x03, 0x08, 0x00, 0x00, + 0x01, 0x0D, 0x01, 0x03, 0x00, 0x10, 0x01, 0x03, + 0x11, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, + 0x6C, 0x69, 0x62, 0x2F, 0x73, 0x79, 0x73, 0x2E, + 0x70, 0x79, 0x00, 0x04, 0x01, 0x00, 0x04, 0x00, + 0x74, 0x00, 0x00, 0x83, 0x00, 0x00, 0x7C, 0x00, + 0x00, 0x17, 0x7D, 0x01, 0x00, 0x78, 0x15, 0x00, + 0x74, 0x00, 0x00, 0x83, 0x00, 0x00, 0x7C, 0x01, + 0x00, 0x6A, 0x00, 0x00, 0x6F, 0x04, 0x00, 0x01, + 0x71, 0x10, 0x00, 0x01, 0x57, 0x64, 0x00, 0x00, + 0x53, 0x00, 0x04, 0x00, 0x64, 0x00, 0x00, 0x5A, + 0x00, 0x00, 0x64, 0x01, 0x00, 0x84, 0x00, 0x00, + 0x5A, 0x01, 0x00, 0x64, 0x02, 0x00, 0x84, 0x00, + 0x00, 0x5A, 0x02, 0x00, 0x64, 0x03, 0x00, 0x84, + 0x00, 0x00, 0x5A, 0x03, 0x00, 0x64, 0x04, 0x00, + 0x84, 0x00, 0x00, 0x5A, 0x04, 0x00, 0x64, 0x05, + 0x00, 0x84, 0x00, 0x00, 0x5A, 0x05, 0x00, 0x64, + 0x06, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x06, 0x00, + 0x64, 0x07, 0x00, 0x84, 0x00, 0x00, 0x5A, 0x07, + 0x00, 0x64, 0x08, 0x00, 0x84, 0x00, 0x00, 0x5A, + 0x08, 0x00, 0x64, 0x09, 0x00, 0x53, + +/* ../../lib/ipm.py */ + 0x0A, 0x24, 0x01, 0x00, 0x40, 0x02, 0x00, 0x00, + 0x11, 0x00, 0x04, 0x04, 0x03, 0x07, 0x00, 0x5F, + 0x67, 0x65, 0x74, 0x49, 0x6D, 0x67, 0x03, 0x03, + 0x00, 0x78, 0x30, 0x34, 0x03, 0x03, 0x00, 0x69, + 0x70, 0x6D, 0x03, 0x03, 0x00, 0x69, 0x70, 0x6D, + 0x03, 0x04, 0x00, 0x09, 0x39, 0x09, 0x0B, 0x03, + 0x11, 0x00, 0x2E, 0x2E, 0x2F, 0x2E, 0x2E, 0x2F, + 0x6C, 0x69, 0x62, 0x2F, 0x69, 0x70, 0x6D, 0x2E, + 0x70, 0x79, 0x00, 0x04, 0x04, 0x0B, 0x00, 0x22, + 0x00, 0x0B, 0x00, 0x23, 0x00, 0x0A, 0xB2, 0x00, + 0x01, 0x43, 0x03, 0x04, 0x00, 0x55, 0x00, 0x04, + 0x07, 0x03, 0x07, 0x00, 0x5F, 0x67, 0x65, 0x74, + 0x49, 0x6D, 0x67, 0x03, 0x02, 0x00, 0x43, 0x6F, + 0x03, 0x04, 0x00, 0x65, 0x76, 0x61, 0x6C, 0x03, + 0x03, 0x00, 0x78, 0x30, 0x34, 0x03, 0x05, 0x00, + 0x46, 0x61, 0x6C, 0x73, 0x65, 0x03, 0x0E, 0x00, + 0x41, 0x73, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6F, + 0x6E, 0x45, 0x72, 0x72, 0x6F, 0x72, 0x03, 0x03, + 0x00, 0x69, 0x70, 0x6D, 0x03, 0x0C, 0x00, 0x00, + 0x01, 0x03, 0x04, 0x09, 0x01, 0x0C, 0x01, 0x0F, + 0x01, 0x0A, 0x04, 0x03, 0x11, 0x00, 0x2E, 0x2E, + 0x2F, 0x2E, 0x2E, 0x2F, 0x6C, 0x69, 0x62, 0x2F, + 0x69, 0x70, 0x6D, 0x2E, 0x70, 0x79, 0x00, 0x04, + 0x01, 0x00, 0x04, 0x00, 0x78, 0x2E, 0x00, 0x74, + 0x00, 0x00, 0x83, 0x00, 0x00, 0x7D, 0x01, 0x00, + 0x74, 0x01, 0x00, 0x7C, 0x01, 0x00, 0x83, 0x01, + 0x00, 0x7D, 0x02, 0x00, 0x74, 0x02, 0x00, 0x7C, + 0x02, 0x00, 0x7C, 0x00, 0x00, 0x83, 0x02, 0x00, + 0x7D, 0x03, 0x00, 0x74, 0x03, 0x00, 0x83, 0x00, + 0x00, 0x01, 0x71, 0x03, 0x00, 0x74, 0x04, 0x00, + 0x70, 0x07, 0x00, 0x01, 0x74, 0x05, 0x00, 0x82, + 0x01, 0x00, 0x01, 0x64, 0x00, 0x00, 0x53, 0x00, + 0x04, 0x00, 0x64, 0x00, 0x00, 0x84, 0x00, 0x00, + 0x5A, 0x00, 0x00, 0x64, 0x01, 0x00, 0x84, 0x00, + 0x00, 0x5A, 0x01, 0x00, 0x68, 0x00, 0x00, 0x64, + 0x02, 0x00, 0x84, 0x01, 0x00, 0x5A, 0x02, 0x00, + 0x64, 0x03, 0x00, 0x53, + +/* img-list-terminator */ + 0xFF, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/platform/mbed/pmstdlib_nat.cpp Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,1647 @@ +#undef __FILE_ID__ +#define __FILE_ID__ 0x0A +/** + * PyMite std native function file + * + * automatically created by pmImgCreator.py + * on Sat Mar 02 20:27:03 2013 + * + * DO NOT EDIT THIS FILE. + * ANY CHANGES WILL BE LOST. + * + * @file pmstdlib_nat.cpp + */ + +#define __IN_LIBNATIVE_C__ +#include "pm.h" + +/* From: ../../lib/string.py */ +#include <stdlib.h> +#include <string.h> + +PmReturn_t +nat_00___bi_chr(pPmFrame_t *ppframe) +{ + + pPmObj_t ps; + pPmObj_t pn; + int32_t n; + PmReturn_t retval; + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Raise TypeError if arg is not an int */ + pn = NATIVE_GET_LOCAL(0); + if (OBJ_GET_TYPE(pn) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Raise ValueError if arg is not int within range(256) */ + n = ((pPmInt_t)pn)->val; + if ((n < 0) || (n > 255)) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + + /* Create char string from integer value */ + retval = string_newFromChar((uint8_t)n, &ps); + NATIVE_SET_TOS(ps); + return retval; + +} + +PmReturn_t +nat_01___bi_dir(pPmFrame_t *ppframe) +{ + + PmReturn_t retval = PM_RET_OK; + pPmObj_t po; + pPmObj_t pk; + pPmObj_t pl; + pSeglist_t psl; + int16_t i; + uint8_t objid; + + /* Use globals if no arg given */ + if (NATIVE_GET_NUM_ARGS() == 0) + { + /* Get the globals dict */ + po = (pPmObj_t)NATIVE_GET_PFRAME()->fo_globals; + } + + /* Otherwise use the given arg */ + else if (NATIVE_GET_NUM_ARGS() == 1) + { + po = NATIVE_GET_LOCAL(0); + + /* If object is a function or module, use its attrs dict */ + if ((OBJ_GET_TYPE(po) == OBJ_TYPE_FXN) + || (OBJ_GET_TYPE(po) == OBJ_TYPE_MOD)) + { + po = (pPmObj_t)((pPmFunc_t)po)->f_attrs; + } + +#ifdef HAVE_CLASSES + else if (OBJ_GET_TYPE(po) == OBJ_TYPE_CLO) + { + po = (pPmObj_t)((pPmClass_t)po)->cl_attrs; + } + else if (OBJ_GET_TYPE(po) == OBJ_TYPE_CLI) + { + po = (pPmObj_t)((pPmInstance_t)po)->cli_attrs; + } + else if (OBJ_GET_TYPE(po) == OBJ_TYPE_MTH) + { + po = (pPmObj_t)((pPmMethod_t)po)->m_attrs; + } +#endif /* HAVE_CLASSES */ + + else + { + po = C_NULL; + } + } + + /* Raise TypeError if wrong number of args */ + else + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + if (po == C_NULL) + { + pl = PM_NONE; + } + else + { + /* Create new list */ + retval = list_new(&pl); + PM_RETURN_IF_ERROR(retval); + + /* Copy dict's keys to the list */ + psl = ((pPmDict_t)po)->d_keys; + for (i = 0; i < ((pPmDict_t)po)->length; i++) + { + retval = seglist_getItem(psl, i, &pk); + PM_RETURN_IF_ERROR(retval); + heap_gcPushTempRoot(pl, &objid); + retval = list_append(pl, pk); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + } + } + + NATIVE_SET_TOS(pl); + return retval; + +} + +PmReturn_t +nat_02___bi_eval(pPmFrame_t *ppframe) +{ + + PmReturn_t retval; + pPmObj_t pco; + pPmObj_t pfunc; + pPmObj_t pnewframe; + pPmObj_t pg = C_NULL; + pPmObj_t pl = C_NULL; + uint8_t objid; + + /* If wrong number of args, raise TypeError */ + if ((NATIVE_GET_NUM_ARGS() == 0) || (NATIVE_GET_NUM_ARGS() > 3)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Raise ValueError if first arg is not a Code Object */ + pco = NATIVE_GET_LOCAL(0); + if (OBJ_GET_TYPE(pco) != OBJ_TYPE_COB) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + + /* If 2nd arg exists, raise ValueError if it is not a Dict */ + if (NATIVE_GET_NUM_ARGS() >= 2) + { + pg = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pg) != OBJ_TYPE_DIC) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + } + + /* If no args are given, use the caller's globals for the function's */ + else + { + pg = (pPmObj_t)NATIVE_GET_PFRAME()->fo_globals; + } + + /* If 3rd arg exists, raise ValueError if it is not a Dict */ + if (NATIVE_GET_NUM_ARGS() >= 3) + { + pl = NATIVE_GET_LOCAL(2); + if (OBJ_GET_TYPE(pl) != OBJ_TYPE_DIC) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + } + + /* Create func from code object */ + retval = func_new(pco, pg, &pfunc); + PM_RETURN_IF_ERROR(retval); + + /* Create frame from module object; globals is set to null */ + heap_gcPushTempRoot(pfunc, &objid); + retval = frame_new(pfunc, &pnewframe); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + + /* TODO: Reclaim pnewframe's attrs dict created in frame_new */ + /* + * By default use calling frame's attrs as local namespace. + * This works for ipm because the interactive mode + * needs a locals namespace that persists across calls to eval() + */ + ((pPmFrame_t)pnewframe)->fo_attrs = NATIVE_GET_PFRAME()->fo_attrs; + + /* If 2nd arg exists, use it as the global namespace for the new func */ + if (NATIVE_GET_NUM_ARGS() >= 2) + { + ((pPmFrame_t)pnewframe)->fo_globals = (pPmDict_t)pg; + + /* If only globals is given, locals defaults to it */ + ((pPmFrame_t)pnewframe)->fo_attrs = (pPmDict_t)pg; + } + + /* If 3rd arg exists, use it as the local namespace for the new func */ + if (NATIVE_GET_NUM_ARGS() >= 3) + { + ((pPmFrame_t)pnewframe)->fo_attrs = (pPmDict_t)pl; + } + + /* + * Set the fo_back frame so flow returns to eval()'s caller when completed. + * Set the frame pointer so the new frame is interpreted immediately + * after this function returns. + */ + ((pPmFrame_t)pnewframe)->fo_back = NATIVE_GET_PFRAME(); + NATIVE_GET_PFRAME() = (pPmFrame_t)pnewframe; + retval = PM_RET_FRAME_SWITCH; + + return retval; + +} + +PmReturn_t +nat_03___bi_globals(pPmFrame_t *ppframe) +{ + + pPmObj_t pr = C_NULL; + PmReturn_t retval; + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 0) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Return calling frame's globals dict on stack*/ + pr = (pPmObj_t)NATIVE_GET_PFRAME()->fo_globals; + NATIVE_SET_TOS(pr); + + return PM_RET_OK; + +} + +PmReturn_t +nat_04___bi_id(pPmFrame_t *ppframe) +{ + + PmReturn_t retval; + pPmObj_t pr = C_NULL; + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Return object's address as an int on the stack */ + retval = int_new((intptr_t)NATIVE_GET_LOCAL(0), &pr); + NATIVE_SET_TOS(pr); + + return retval; + +} + +PmReturn_t +nat_05___bi_len(pPmFrame_t *ppframe) +{ + + PmReturn_t retval; + pPmObj_t ps = C_NULL; + pPmObj_t pr = C_NULL; + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get first arg */ + ps = NATIVE_GET_LOCAL(0); + +#ifdef HAVE_BYTEARRAY + /* If object is an instance, get the thing it contains */ + if (OBJ_GET_TYPE(ps) == OBJ_TYPE_CLI) + { + retval = dict_getItem((pPmObj_t)((pPmInstance_t)ps)->cli_attrs, + PM_NONE, + &pr); + + /* If None wasn't in attributes, obj is wrong type for len() */ + if (retval == PM_RET_EX_KEY) retval = PM_RET_EX_TYPE; + PM_RETURN_IF_ERROR(retval); + ps = pr; + } +#endif /* HAVE_BYTEARRAY */ + + /* Get the length of the arg based on its type */ + switch (OBJ_GET_TYPE(ps)) + { + case OBJ_TYPE_STR: + retval = int_new(((pPmString_t)ps)->length, &pr); + break; + + case OBJ_TYPE_TUP: + retval = int_new(((pPmTuple_t)ps)->length, &pr); + break; + + case OBJ_TYPE_LST: + retval = int_new(((pPmList_t)ps)->length, &pr); + break; + + case OBJ_TYPE_DIC: + retval = int_new(((pPmDict_t)ps)->length, &pr); + break; + +#ifdef HAVE_BYTEARRAY + case OBJ_TYPE_BYA: + retval = int_new(((pPmBytearray_t)ps)->length, &pr); + break; +#endif /* HAVE_BYTEARRAY */ + + default: + /* If not a string or sequence type, raise TypeError */ + PM_RAISE(retval, PM_RET_EX_TYPE); + } + + NATIVE_SET_TOS(pr); + return retval; + +} + +PmReturn_t +nat_06___bi_locals(pPmFrame_t *ppframe) +{ + + pPmObj_t pr = C_NULL; + PmReturn_t retval; + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 0) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Return calling frame's local attrs dict on the stack */ + pr = (pPmObj_t)NATIVE_GET_PFRAME()->fo_attrs; + NATIVE_SET_TOS(pr); + + return PM_RET_OK; + +} + +PmReturn_t +nat_07___bi_ord(pPmFrame_t *ppframe) +{ + + pPmObj_t ps; + pPmObj_t pn; + int32_t n; + PmReturn_t retval; + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + ps = NATIVE_GET_LOCAL(0); + + /* Raise TypeError if arg is not string of length 1 */ + if ((OBJ_GET_TYPE(ps) != OBJ_TYPE_STR) + || (((pPmString_t)ps)->length != 1)) + + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get integer value of character */ + n = ((pPmString_t)ps)->val[0]; + retval = int_new(n, &pn); + NATIVE_SET_TOS(pn); + return retval; + +} + +PmReturn_t +nat_08___bi_range(pPmFrame_t *ppframe) +{ + + PmReturn_t retval; + pPmObj_t pa = C_NULL; + pPmObj_t pb = C_NULL; + pPmObj_t pc = C_NULL; + pPmObj_t pi = C_NULL; + pPmObj_t pr = C_NULL; + int16_t i = 0; + uint8_t objid1, objid2; + + switch (NATIVE_GET_NUM_ARGS()) + { + case 1: + pa = PM_ZERO; + pb = NATIVE_GET_LOCAL(0); + pc = PM_ONE; + break; + + case 2: + pa = NATIVE_GET_LOCAL(0); + pb = NATIVE_GET_LOCAL(1); + pc = PM_ONE; + break; + + case 3: + pa = NATIVE_GET_LOCAL(0); + pb = NATIVE_GET_LOCAL(1); + pc = NATIVE_GET_LOCAL(2); + + /* If 3rd arg is 0, ValueError */ + if (((pPmInt_t)pc)->val == 0) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + break; + + default: + /* If wrong number of args, raise TypeError */ + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Allocate list */ + retval = list_new(&pr); + PM_RETURN_IF_ERROR(retval); + + /* Iterate depending on counting direction */ + if (((pPmInt_t)pc)->val > 0) + { + for (i = ((pPmInt_t)pa)->val; + i < ((pPmInt_t)pb)->val; + i += ((pPmInt_t)pc)->val) + { + heap_gcPushTempRoot(pr, &objid1); + retval = int_new(i, &pi); + if (retval != PM_RET_OK) + { + heap_gcPopTempRoot(objid1); + return retval; + } + + heap_gcPushTempRoot(pi, &objid2); + retval = list_append(pr, pi); + heap_gcPopTempRoot(objid1); + PM_RETURN_IF_ERROR(retval); + } + } + else + { + for (i = ((pPmInt_t)pa)->val; + i > ((pPmInt_t)pb)->val; + i += ((pPmInt_t)pc)->val) + { + heap_gcPushTempRoot(pr, &objid1); + retval = int_new(i, &pi); + if (retval != PM_RET_OK) + { + heap_gcPopTempRoot(objid1); + return retval; + } + + heap_gcPushTempRoot(pi, &objid2); + retval = list_append(pr, pi); + heap_gcPopTempRoot(objid1); + PM_RETURN_IF_ERROR(retval); + } + } + + /* Return list */ + NATIVE_SET_TOS(pr); + return retval; + +} + +PmReturn_t +nat_09___bi_sum(pPmFrame_t *ppframe) +{ + + pPmObj_t ps; + pPmObj_t pn; + pPmObj_t po; + int32_t n; + uint16_t len; + uint16_t i; + PmReturn_t retval; +#ifdef HAVE_FLOAT + float f; + uint8_t usefloat = C_FALSE; +#endif /* HAVE_FLOAT */ + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + ps = NATIVE_GET_LOCAL(0); + +#ifdef HAVE_BYTEARRAY + /* Bytearray is a special case to save RAM converting each byte to an Int */ + if (OBJ_GET_TYPE(ps) == OBJ_TYPE_BYA) + { + n = 0; + len = ((pPmBytearray_t)ps)->length; + po = (pPmObj_t)((pPmBytearray_t)ps)->val; + for (i = 0; i < len; i++) + { + n += (uint8_t)((pPmBytes_t)po)->val[i]; + } + retval = int_new(n, &pn); + NATIVE_SET_TOS(pn); + return retval; + } +#endif /* HAVE_BYTEARRAY */ + + /* Raise TypeError if arg is not a sequence */ + if ((OBJ_GET_TYPE(ps) != OBJ_TYPE_TUP) + && (OBJ_GET_TYPE(ps) != OBJ_TYPE_LST) + && (OBJ_GET_TYPE(ps) != OBJ_TYPE_DIC)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the length of the sequence */ + retval = seq_getLength(ps, &len); + PM_RETURN_IF_ERROR(retval); + + /* Calculate the sum of the sequence */ + n = 0; +#ifdef HAVE_FLOAT + f = 0.0; +#endif + for (i = 0; i < len; i++) + { + retval = seq_getSubscript(ps, i, &po); + + if (OBJ_GET_TYPE(po) == OBJ_TYPE_INT) + { + /* Add value to sum */ + n += ((pPmInt_t)po)->val; +#ifdef HAVE_FLOAT + f += (float)((pPmInt_t)po)->val; +#endif /* HAVE_FLOAT */ + } + +#ifdef HAVE_FLOAT + else if (OBJ_GET_TYPE(po) == OBJ_TYPE_FLT) + { + /* Add value to sum */ + f += ((pPmFloat_t)po)->val; + usefloat = C_TRUE; + } +#endif /* HAVE_FLOAT */ + + /* Raise TypeError if item is not an integer */ + else + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + } + +#ifdef HAVE_FLOAT + if (usefloat) + { + retval = float_new(f, &pn); + } + else +#endif /* HAVE_FLOAT */ + { + retval = int_new(n, &pn); + } + NATIVE_SET_TOS(pn); + return retval; + +} + +PmReturn_t +nat_10___bi_type(pPmFrame_t *ppframe) +{ + + PmReturn_t retval; + pPmObj_t po = C_NULL; + pPmObj_t pr = C_NULL; + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get arg */ + po = NATIVE_GET_LOCAL(0); + + /* Create int from type enum */ + retval = int_new(OBJ_GET_TYPE(po), &pr); + NATIVE_SET_TOS(pr); + return retval; + +} + +PmReturn_t +nat_11___bi_Co(pPmFrame_t *ppframe) +{ + + PmReturn_t retval; + pPmObj_t pimg; + pPmObj_t pco; + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Raise ValueError if arg is not an Image Obj */ + pimg = NATIVE_GET_LOCAL(0); + if (OBJ_GET_TYPE(pimg) != OBJ_TYPE_CIO) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + + /* Create a code object from the image */ + retval = obj_loadFromImgObj(pimg, &pco); + PM_RETURN_IF_ERROR(retval); + + /* Return the code object */ + NATIVE_SET_TOS(pco); + return retval; + +} + +PmReturn_t +nat_12___bi___init__(pPmFrame_t *ppframe) +{ + + PmReturn_t retval; + pPmObj_t pself; + pPmObj_t pfa; + pPmObj_t pfunc; + pPmObj_t pframe; + uint8_t i; + uint8_t objid; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Raise ValueError if first args are not: instance, tuple */ + pself = NATIVE_GET_LOCAL(0); + pfa = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pself) != OBJ_TYPE_CLI) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + if (OBJ_GET_TYPE(pfa) != OBJ_TYPE_TUP) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + + /* Create a new frame for the function */ + pfunc = ((pPmTuple_t)pfa)->val[0]; + retval = frame_new(pfunc, &pframe); + PM_RETURN_IF_ERROR(retval); + + /* Copy args into frame's locals */ + for (i = 0; i < ((pPmTuple_t)pfa)->length - 1; i++) + { + /* The pfa tuple is (func, [arg0, ... argN]) */ + ((pPmFrame_t)pframe)->fo_locals[i] = ((pPmTuple_t)pfa)->val[i + 1]; + } + + /* Store frame in None attr of instance */ + heap_gcPushTempRoot(pframe, &objid); + retval = dict_setItem((pPmObj_t)((pPmInstance_t)pself)->cli_attrs, + PM_NONE, pframe); + heap_gcPopTempRoot(objid); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_13___bi_send(pPmFrame_t *ppframe) +{ + + PmReturn_t retval; + pPmObj_t pself; + pPmObj_t parg; + pPmObj_t pgenframe; + + /* Raise TypeError if wrong number of args */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Raise ValueError if first arg is not an instance */ + pself = NATIVE_GET_LOCAL(0); + parg = NATIVE_GET_LOCAL(1); + if (OBJ_GET_TYPE(pself) != OBJ_TYPE_CLI) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + + /* Get the generator's frame */ + retval = dict_getItem((pPmObj_t)((pPmInstance_t)pself)->cli_attrs, + PM_NONE, &pgenframe); + PM_RETURN_IF_ERROR(retval); + + /* Push argument onto generator's frame's stack */ + *(((pPmFrame_t)pgenframe)->fo_sp) = parg; + ((pPmFrame_t)pgenframe)->fo_sp++; + + /* Set generator's frame's fo_back so yielded value goes to caller */ + ((pPmFrame_t)pgenframe)->fo_back = NATIVE_GET_PFRAME(); + + /* Set active frame to run generator */ + NATIVE_GET_PFRAME() = (pPmFrame_t)pgenframe; + + return PM_RET_FRAME_SWITCH; + +} + +PmReturn_t +nat_14___bi_ismain(pPmFrame_t *ppframe) +{ + + + NATIVE_SET_TOS((NATIVE_GET_PFRAME()->fo_isImport) ? PM_FALSE : PM_TRUE); + + return PM_RET_OK; + +} + +PmReturn_t +nat_15_dict_clear(pPmFrame_t *ppframe) +{ + + pPmObj_t pd; + PmReturn_t retval = PM_RET_OK; + + /* Raise TypeError if it's not a dict or wrong number of args, */ + pd = NATIVE_GET_LOCAL(0); + if ((OBJ_GET_TYPE(pd) != OBJ_TYPE_DIC) || (NATIVE_GET_NUM_ARGS() != 1)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Clear the contents of the dict */ + retval = dict_clear(pd); + PM_RETURN_IF_ERROR(retval); + + NATIVE_SET_TOS(PM_NONE); + + return retval; + +} + +PmReturn_t +nat_16_dict_keys(pPmFrame_t *ppframe) +{ + + pPmObj_t pd; + pPmObj_t pl; + pPmObj_t pk; + pSeglist_t psl; + uint16_t i; + PmReturn_t retval = PM_RET_OK; + uint8_t objid; + + /* Raise TypeError if it's not a dict or wrong number of args, */ + pd = NATIVE_GET_LOCAL(0); + if ((OBJ_GET_TYPE(pd) != OBJ_TYPE_DIC) || (NATIVE_GET_NUM_ARGS() != 1)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Create empty list */ + retval = list_new(&pl); + PM_RETURN_IF_ERROR(retval); + + /* Iterate through the keys seglist */ + psl = ((pPmDict_t)pd)->d_keys; + for (i = 0; i < ((pPmDict_t)pd)->length; i++) + { + /* Get the key and append it to the list */ + retval = seglist_getItem(psl, i, &pk); + PM_RETURN_IF_ERROR(retval); + heap_gcPushTempRoot(pl, &objid); + retval = list_append(pl, pk); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + } + + /* Return the list of keys to the caller */ + NATIVE_SET_TOS(pl); + + return retval; + +} + +PmReturn_t +nat_17_dict_values(pPmFrame_t *ppframe) +{ + + pPmObj_t pd; + pPmObj_t pl; + pPmObj_t pv; + pSeglist_t psl; + uint16_t i; + PmReturn_t retval = PM_RET_OK; + uint8_t objid; + + /* Raise TypeError if it's not a dict or wrong number of args, */ + pd = NATIVE_GET_LOCAL(0); + if ((OBJ_GET_TYPE(pd) != OBJ_TYPE_DIC) || (NATIVE_GET_NUM_ARGS() != 1)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Create empty list */ + retval = list_new(&pl); + PM_RETURN_IF_ERROR(retval); + + /* Iterate through the values seglist */ + psl = ((pPmDict_t)pd)->d_vals; + for (i = 0; i < ((pPmDict_t)pd)->length; i++) + { + /* Get the value and append it to the list */ + retval = seglist_getItem(psl, i, &pv); + PM_RETURN_IF_ERROR(retval); + heap_gcPushTempRoot(pl, &objid); + retval = list_append(pl, pv); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + } + + /* Return the list of values to the caller */ + NATIVE_SET_TOS(pl); + + return retval; + +} + +PmReturn_t +nat_18_dict_update(pPmFrame_t *ppframe) +{ + + pPmObj_t pd1; + pPmObj_t pd2; + PmReturn_t retval; + + /* Raise TypeError if wrong number of args, */ + if (NATIVE_GET_NUM_ARGS() != 2) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + pd1 = NATIVE_GET_LOCAL(0); + pd2 = NATIVE_GET_LOCAL(1); + retval = dict_update(pd1, pd2, C_FALSE); + + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_19_list_append(pPmFrame_t *ppframe) +{ + + pPmObj_t pl; + PmReturn_t retval = PM_RET_OK; + + /* Raise TypeError if it's not a list or wrong number of args, */ + pl = NATIVE_GET_LOCAL(0); + if ((OBJ_GET_TYPE(pl) != OBJ_TYPE_LST) || (NATIVE_GET_NUM_ARGS() != 2)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Append the object to the list */ + retval = list_append(pl, NATIVE_GET_LOCAL(1)); + + NATIVE_SET_TOS(PM_NONE); + + return retval; + +} + +PmReturn_t +nat_20_list_index(pPmFrame_t *ppframe) +{ + + pPmObj_t pl; + pPmObj_t po; + pPmObj_t pi; + PmReturn_t retval = PM_RET_OK; + uint16_t i; + + /* Raise TypeError if it's not a list or wrong number of args, */ + pl = NATIVE_GET_LOCAL(0); + if ((OBJ_GET_TYPE(pl) != OBJ_TYPE_LST) || (NATIVE_GET_NUM_ARGS() != 2)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the index of the object in the list */ + po = NATIVE_GET_LOCAL(1); + retval = list_index(pl, po, &i); + + if (retval == PM_RET_EX_VAL) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + + int_new((int32_t)i, &pi); + NATIVE_SET_TOS(pi); + + return retval; + +} + +PmReturn_t +nat_21_list_insert(pPmFrame_t *ppframe) +{ + + pPmObj_t pl; + pPmObj_t pi; + pPmObj_t po; + PmReturn_t retval = PM_RET_OK; + uint16_t i; + + /* + * Raise TypeError if wrong number of args, first arg is not a list, or + * second arg is not an int + */ + pl = NATIVE_GET_LOCAL(0); + pi = NATIVE_GET_LOCAL(1); + po = NATIVE_GET_LOCAL(2); + if ((NATIVE_GET_NUM_ARGS() != 3) + || (OBJ_GET_TYPE(pl) != OBJ_TYPE_LST) + || (OBJ_GET_TYPE(pi) != OBJ_TYPE_INT) ) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Insert the object before the given index */ + i = (uint16_t)((pPmInt_t)pi)->val; + retval = list_insert(pl, i, po); + + if (retval != PM_RET_OK) + { + PM_RAISE(retval, PM_RET_EX_SYS); + } + + NATIVE_SET_TOS(PM_NONE); + + return retval; + +} + +PmReturn_t +nat_22_list_pop(pPmFrame_t *ppframe) +{ + + pPmObj_t pl; + pPmObj_t pi; + pPmObj_t po; + PmReturn_t retval = PM_RET_OK; + int16_t i; + + /* + * Raise TypeError if first arg is not a list o second arg is not an int + * or there are the wrong number of arguments + */ + pl = NATIVE_GET_LOCAL(0); + if (OBJ_GET_TYPE(pl) != OBJ_TYPE_LST) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + pi = NATIVE_GET_LOCAL(1); + if (NATIVE_GET_NUM_ARGS() == 2) + { + if (OBJ_GET_TYPE(pi) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + i = (uint16_t)((pPmInt_t)pi)->val; + } + else + { + i = -1; + } + if ((NATIVE_GET_NUM_ARGS() < 1) || (NATIVE_GET_NUM_ARGS() > 2)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the object at the given index */ + retval = list_getItem(pl, i, &po); + PM_RETURN_IF_ERROR(retval); + + /* Return the object to the caller */ + NATIVE_SET_TOS(po); + + /* Remove the object from the given index */ + retval = list_delItem(pl, i); + PM_RETURN_IF_ERROR(retval); + + return retval; + +} + +PmReturn_t +nat_23_list_remove(pPmFrame_t *ppframe) +{ + + pPmObj_t pl; + pPmObj_t pv; + PmReturn_t retval = PM_RET_OK; + + /* Raise TypeError if it's not a list or wrong number of args, */ + pl = NATIVE_GET_LOCAL(0); + if ((OBJ_GET_TYPE(pl) != OBJ_TYPE_LST) || (NATIVE_GET_NUM_ARGS() != 2)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Remove the value from the list */ + pv = NATIVE_GET_LOCAL(1); + retval = list_remove(pl, pv); + if (retval != PM_RET_OK) + { + PM_RAISE(retval, retval); + } + + NATIVE_SET_TOS(PM_NONE); + + return retval; + +} + +PmReturn_t +nat_24_string_atoi(pPmFrame_t *ppframe) +{ + + pPmObj_t pa; + pPmObj_t pb; + char const *pc; + char *pend; + long i; + int8_t base; + pPmObj_t pi; + PmReturn_t retval = PM_RET_OK; + + /* Raise TypeError if it's not a string or wrong number of args, */ + pa = NATIVE_GET_LOCAL(0); + if ((OBJ_GET_TYPE(pa) != OBJ_TYPE_STR) || (NATIVE_GET_NUM_ARGS() < 1) + || (NATIVE_GET_NUM_ARGS() > 2)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the base, if it exists; otherwise assume 10 */ + base = 10; + if (NATIVE_GET_NUM_ARGS() == 2) + { + pb = NATIVE_GET_LOCAL(1); + + /* Raise a TypeError if 2nd arg is not an int */ + if (OBJ_GET_TYPE(pb) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + base = ((pPmInt_t)pb)->val; + + /* Raise ValueError if base is out of range */ + if ((base < 0) || (base == 1) || (base > 36)) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + } + + /* Perform conversion */ + pend = C_NULL; + pc = (char const *)&(((pPmString_t)pa)->val); + i = strtol(pc, &pend, base); + + /* Raise ValueError if there was a conversion error */ + if (*pend != C_NULL) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + + /* Create an int object to hold the result of the conversion */ + retval = int_new(i, &pi); + + NATIVE_SET_TOS(pi); + + return retval; + +} + +PmReturn_t +nat_25_string_count(pPmFrame_t *ppframe) +{ + + pPmObj_t ps1; + pPmObj_t ps2; + uint8_t *pc1; + uint8_t *pc2; + uint8_t *pscan; + uint8_t *pmatch; + uint8_t pc2c0; + uint16_t pc1len; + uint16_t pc2len; + uint16_t n; + uint16_t remaining; + uint16_t cmp; + pPmObj_t pn; + PmReturn_t retval = PM_RET_OK; + + /* Raise TypeError if it's not a string or wrong number of args, */ + ps1 = NATIVE_GET_LOCAL(0); + ps2 = NATIVE_GET_LOCAL(1); + if ((OBJ_GET_TYPE(ps1) != OBJ_TYPE_STR) || (NATIVE_GET_NUM_ARGS() != 2) + || (OBJ_GET_TYPE(ps2) != OBJ_TYPE_STR)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + pc1 = ((pPmString_t)ps1)->val; + pc2 = ((pPmString_t)ps2)->val; + pc1len = ((pPmString_t)ps1)->length; + pc2len = ((pPmString_t)ps2)->length; + n = 0; + + /* Handle some quick special cases (order of if-clauses is important) */ + if (pc2len == 0) + { + n = pc1len + 1; + } + else if (pc1len == 0) + { + n = 0; + } + + /* Count the number of matches */ + else + { + n = 0; + remaining = pc1len; + pscan = pc1; + pc2c0 = pc2[0]; + while (pscan <= (pc1 + (pc1len - pc2len))) + { + /* Find the next possible start */ + pmatch = (uint8_t *)memchr(pscan, pc2c0, remaining); + if (pmatch == C_NULL) break; + remaining -= (pmatch - pscan); + pscan = pmatch; + + /* If it matches, increase the count, else try the next char */ + cmp = memcmp(pscan, pc2, pc2len); + if (cmp == 0) + { + n++; + pscan += pc2len; + remaining -= pc2len; + } + else + { + pscan++; + remaining--; + } + } + } + + retval = int_new(n, &pn); + + NATIVE_SET_TOS(pn); + + return retval; + +} + +PmReturn_t +nat_26_string_find(pPmFrame_t *ppframe) +{ + + pPmObj_t ps1; + pPmObj_t ps2; + uint8_t *pc1; + uint8_t *pc2; + uint8_t *pmatch; + uint16_t pc1len; + uint16_t pc2len; + int32_t n; + pPmObj_t pn; + PmReturn_t retval = PM_RET_OK; + + /* Raise TypeError if it's not a string or wrong number of args, */ + ps1 = NATIVE_GET_LOCAL(0); + ps2 = NATIVE_GET_LOCAL(1); + if ((OBJ_GET_TYPE(ps1) != OBJ_TYPE_STR) || (NATIVE_GET_NUM_ARGS() != 2) + || (OBJ_GET_TYPE(ps2) != OBJ_TYPE_STR)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + pc1 = ((pPmString_t)ps1)->val; + pc2 = ((pPmString_t)ps2)->val; + pc1len = ((pPmString_t)ps1)->length; + pc2len = ((pPmString_t)ps2)->length; + n = -1; + + /* Handle a quick special case */ + if (pc2len == 0) + { + n = 0; + } + + /* Try to find the index of the substring */ + else + { + /* Find the next possible start */ + pmatch = (uint8_t *)memchr(pc1, pc2[0], pc1len); + if (pmatch != C_NULL) + { + /* If it matches, calculate the index */ + if (memcmp(pmatch, pc2, pc2len) == 0) + { + n = pmatch - pc1; + } + } + } + + retval = int_new(n, &pn); + + NATIVE_SET_TOS(pn); + + return retval; + +} + +PmReturn_t +nat_27_sys_exit(pPmFrame_t *ppframe) +{ + + pPmObj_t pval = C_NULL; + PmReturn_t retval; + + /* If no arg given, assume return 0 */ + if (NATIVE_GET_NUM_ARGS() == 0) + { + NATIVE_SET_TOS(PM_ZERO); + } + + /* If 1 arg given, put it on stack */ + else if (NATIVE_GET_NUM_ARGS() == 1) + { + pval = NATIVE_GET_LOCAL(0); + NATIVE_SET_TOS(pval); + } + + /* If wrong number of args, raise TypeError */ + else + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Raise the SystemExit exception */ + PM_RAISE(retval, PM_RET_EX_EXIT); + return retval; + +} + +PmReturn_t +nat_28_sys_gc(pPmFrame_t *ppframe) +{ + + PmReturn_t retval = PM_RET_OK; +#ifdef HAVE_GC + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 0) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + retval = heap_gcRun(); +#endif + NATIVE_SET_TOS(PM_NONE); + + return retval; + +} + +PmReturn_t +nat_29_sys_getb(pPmFrame_t *ppframe) +{ + + uint8_t b; + pPmObj_t pb; + PmReturn_t retval; + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 0) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + retval = plat_getByte(&b); + PM_RETURN_IF_ERROR(retval); + + retval = int_new((int32_t)b, &pb); + NATIVE_SET_TOS(pb); + return retval; + +} + +PmReturn_t +nat_30_sys_heap(pPmFrame_t *ppframe) +{ + + PmReturn_t retval; + pPmObj_t pavail; + pPmObj_t psize; + pPmObj_t ptup; + uint8_t objid; + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 0) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Allocate a tuple to store the return values */ + retval = tuple_new(2, &ptup); + PM_RETURN_IF_ERROR(retval); + + /* Get the maximum heap size */ + heap_gcPushTempRoot(ptup, &objid); + retval = int_new(heap_getSize(), &psize); + if (retval != PM_RET_OK) + { + heap_gcPopTempRoot(objid); + return retval; + } + + /* Allocate an int to hold the amount of heap available */ + retval = int_new(heap_getAvail() - sizeof(PmInt_t), &pavail); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + + /* Put the two heap values in the tuple */ + ((pPmTuple_t)ptup)->val[0] = pavail; + ((pPmTuple_t)ptup)->val[1] = psize; + + /* Return the tuple on the stack */ + NATIVE_SET_TOS(ptup); + + return retval; + +} + +PmReturn_t +nat_31_sys_putb(pPmFrame_t *ppframe) +{ + + uint8_t b; + pPmObj_t pb; + PmReturn_t retval; + + pb = NATIVE_GET_LOCAL(0); + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* If arg is not an int, raise TypeError */ + if (OBJ_GET_TYPE(pb) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + b = ((pPmInt_t)pb)->val & 0xFF; + retval = plat_putByte(b); + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_32_sys_runInThread(pPmFrame_t *ppframe) +{ + + PmReturn_t retval; + pPmObj_t pf; + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 1) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* If arg is not a function, raise TypeError */ + pf = NATIVE_GET_LOCAL(0); + if (OBJ_GET_TYPE(pf) != OBJ_TYPE_FXN) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + retval = interp_addThread((pPmFunc_t)pf); + NATIVE_SET_TOS(PM_NONE); + return retval; + +} + +PmReturn_t +nat_33_sys_time(pPmFrame_t *ppframe) +{ + + uint32_t t; + pPmObj_t pt; + PmReturn_t retval; + + /* If wrong number of args, raise TypeError */ + if (NATIVE_GET_NUM_ARGS() != 0) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the system time (milliseconds since init) */ + retval = plat_getMsTicks(&t); + PM_RETURN_IF_ERROR(retval); + + /* + * Raise ValueError if there is an overflow + * (plat_getMsTicks is unsigned; int is signed) + */ + if ((int32_t)t < 0) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + + /* Return an int object with the time value */ + retval = int_new((int32_t)t, &pt); + NATIVE_SET_TOS(pt); + return retval; + +} + +PmReturn_t +nat_34_ipm__getImg(pPmFrame_t *ppframe) +{ + + PmReturn_t retval; + uint8_t imgType; + uint16_t imgSize; + uint8_t *pchunk; + pPmCodeImgObj_t pimg; + uint16_t i; + uint8_t b; + + /* Get the image type */ + retval = plat_getByte(&imgType); + PM_RETURN_IF_ERROR(retval); + + /* Quit if a code image type was not received */ + if (imgType != OBJ_TYPE_CIM) + { + PM_RAISE(retval, PM_RET_EX_STOP); + return retval; + } + + /* Get the image size (little endien) */ + retval = plat_getByte(&b); + PM_RETURN_IF_ERROR(retval); + imgSize = b; + retval = plat_getByte(&b); + PM_RETURN_IF_ERROR(retval); + imgSize |= (b << 8); + + /* Get space for CodeImgObj */ + retval = heap_getChunk(sizeof(PmCodeImgObj_t) + imgSize, &pchunk); + PM_RETURN_IF_ERROR(retval); + pimg = (pPmCodeImgObj_t)pchunk; + OBJ_SET_TYPE(pimg, OBJ_TYPE_CIO); + + /* Start the image with the bytes that have already been received */ + i = 0; + pimg->val[i++] = imgType; + pimg->val[i++] = imgSize & 0xFF; + pimg->val[i++] = (imgSize >> 8) & 0xFF; + + /* Get the remaining bytes in the image */ + for(; i < imgSize; i++) + { + retval = plat_getByte(&b); + PM_RETURN_IF_ERROR(retval); + + pimg->val[i] = b; + } + + /* Return the image as a code image object on the stack */ + NATIVE_SET_TOS((pPmObj_t)pimg); + return retval; + +} + +PmReturn_t +nat_35_ipm_x04(pPmFrame_t *ppframe) +{ + + NATIVE_SET_TOS(PM_NONE); + return plat_putByte(0x04); + +} + +/* Native function lookup table */ +pPmNativeFxn_t const std_nat_fxn_table[] = +{ + nat_00___bi_chr, + nat_01___bi_dir, + nat_02___bi_eval, + nat_03___bi_globals, + nat_04___bi_id, + nat_05___bi_len, + nat_06___bi_locals, + nat_07___bi_ord, + nat_08___bi_range, + nat_09___bi_sum, + nat_10___bi_type, + nat_11___bi_Co, + nat_12___bi___init__, + nat_13___bi_send, + nat_14___bi_ismain, + nat_15_dict_clear, + nat_16_dict_keys, + nat_17_dict_values, + nat_18_dict_update, + nat_19_list_append, + nat_20_list_index, + nat_21_list_insert, + nat_22_list_pop, + nat_23_list_remove, + nat_24_string_atoi, + nat_25_string_count, + nat_26_string_find, + nat_27_sys_exit, + nat_28_sys_gc, + nat_29_sys_getb, + nat_30_sys_heap, + nat_31_sys_putb, + nat_32_sys_runInThread, + nat_33_sys_time, + nat_34_ipm__getImg, + nat_35_ipm_x04, +};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/bytearray.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,267 @@ +/* +# This file is Copyright 2010 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__ 0x19 + + +/** + * \file + * \brief VM Bytearray Type + * + * VM Bytearray object type operations. + */ + +#include "pm.h" +#ifdef HAVE_BYTEARRAY + + +#define ROUND_UP_TO_MUL_OF_FOUR(n) n = (((n) + 3) & ~3) + + +/* Returns a container that can hold at least n bytes */ +static +PmReturn_t +bytes_new(int16_t n, pPmObj_t *r_pobj) +{ + PmReturn_t retval = PM_RET_OK; + pPmBytes_t pb = C_NULL; + + ROUND_UP_TO_MUL_OF_FOUR(n); + + /* Allocate a container */ + retval = heap_getChunk(sizeof(PmBytes_t) + n, (uint8_t **)&pb); + PM_RETURN_IF_ERROR(retval); + OBJ_SET_TYPE(pb, OBJ_TYPE_BYS); + pb->length = n; + + *r_pobj = (pPmObj_t)pb; + return retval; +} + + +/* Returns the int or one-char string as a byte */ +static +PmReturn_t +bytes_getByteFromObj(pPmObj_t pobj, uint8_t *b) +{ + PmReturn_t retval = PM_RET_OK; + + if (OBJ_GET_TYPE(pobj) == OBJ_TYPE_INT) + { + if ((((pPmInt_t)pobj)->val > 255) || (((pPmInt_t)pobj)->val < 0)) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + + *b = (uint8_t)((pPmInt_t)pobj)->val; + } + + else if (OBJ_GET_TYPE(pobj) == OBJ_TYPE_STR) + { + if (((pPmString_t)pobj)->length != 1) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + *b = ((pPmString_t)pobj)->val[0]; + } + + else + { + PM_RAISE(retval, PM_RET_EX_TYPE); + } + return retval; +} + + +PmReturn_t +bytearray_new(pPmObj_t pobj, pPmObj_t *r_pobj) +{ + PmReturn_t retval = PM_RET_OK; + pPmBytearray_t pba = C_NULL; + pPmBytes_t pb = C_NULL; + pPmObj_t pitem; + int32_t i; + int16_t n; + uint8_t b; + uint8_t objid; + + /* If object is an instance, get the thing it is containing */ + if (OBJ_GET_TYPE(pobj) == OBJ_TYPE_CLI) + { + retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj)->cli_attrs, + PM_NONE, + (pPmObj_t *)&pba); + PM_RETURN_IF_ERROR(retval); + pobj = (pPmObj_t)pba; + } + + /* Get the requested length of the new bytearray */ + switch (OBJ_GET_TYPE(pobj)) + { + case OBJ_TYPE_INT: + i = ((pPmInt_t)pobj)->val; + if ((i < 0) || (i > 65535)) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + n = i; + break; + + case OBJ_TYPE_STR: + n = ((pPmString_t)pobj)->length; + break; + + case OBJ_TYPE_LST: + n = ((pPmList_t)pobj)->length; + break; + + case OBJ_TYPE_TUP: + n = ((pPmTuple_t)pobj)->length; + break; + + case OBJ_TYPE_BYA: + n = ((pPmBytearray_t)pobj)->length; + break; + + default: + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Allocate a bytearray */ + retval = heap_getChunk(sizeof(PmBytearray_t), (uint8_t **)&pba); + PM_RETURN_IF_ERROR(retval); + OBJ_SET_TYPE(pba, OBJ_TYPE_BYA); + pba->length = n; + pba->val = C_NULL; + + /* Allocate the bytes container */ + heap_gcPushTempRoot((pPmObj_t)pba, &objid); + retval = bytes_new(n, (pPmObj_t *)&pb); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + pba->val = pb; + + /* Fill the bytes */ + switch (OBJ_GET_TYPE(pobj)) + { + case OBJ_TYPE_INT: + sli_memset((unsigned char *)&(pb->val), '\0', n); + break; + + case OBJ_TYPE_BYA: + pitem = (pPmObj_t)((pPmBytearray_t)pobj)->val; + sli_memcpy(&(pb->val[0]), &(((pPmBytes_t)pitem)->val[0]), n); + break; + + case OBJ_TYPE_STR: + sli_memcpy(&(pb->val[0]), &(((pPmString_t)pobj)->val[0]), n); + break; + + case OBJ_TYPE_LST: + case OBJ_TYPE_TUP: + for (i = 0; i < n; i++) + { + retval = seq_getSubscript(pobj, i, &pitem); + PM_RETURN_IF_ERROR(retval); + retval = bytes_getByteFromObj(pitem, &b); + PM_RETURN_IF_ERROR(retval); + pb->val[i] = b; + } + break; + } + + *r_pobj = (pPmObj_t)pba; + return retval; +} + + +PmReturn_t +bytearray_getItem(pPmObj_t pobj, int16_t index, pPmObj_t *r_pobj) +{ + PmReturn_t retval = PM_RET_OK; + pPmBytearray_t pba; + pPmBytes_t pb; + int32_t n; + + pba = (pPmBytearray_t)pobj; + + /* Adjust a negative index */ + if (index < 0) + { + index += pba->length; + } + + /* Check the bounds of the index */ + if ((index < 0) || (index >= pba->length)) + { + PM_RAISE(retval, PM_RET_EX_INDX); + return retval; + } + + /* Create int from byte at index */ + pb = pba->val; + n = (int32_t)pb->val[index]; + retval = int_new(n, r_pobj); + + return retval; +} + + +PmReturn_t +bytearray_setItem(pPmObj_t pba, int16_t index, pPmObj_t pobj) +{ + PmReturn_t retval; + pPmBytes_t pb; + uint8_t b = 0; + + /* Adjust a negative index */ + if (index < 0) + { + index += ((pPmBytearray_t)pba)->length; + } + + /* Check the bounds of the index */ + if ((index < 0) || (index >= ((pPmBytearray_t)pba)->length)) + { + PM_RAISE(retval, PM_RET_EX_INDX); + return retval; + } + + /* Set the item */ + retval = bytes_getByteFromObj(pobj, &b); + pb = ((pPmBytearray_t)pba)->val; + pb->val[index] = b; + + return retval; +} + + +#ifdef HAVE_PRINT +PmReturn_t +bytearray_print(pPmObj_t pobj) +{ + PmReturn_t retval; + pPmBytes_t pb; + + obj_print(PM_BYTEARRAY_STR, C_FALSE, C_FALSE); + plat_putByte('('); + plat_putByte('b'); + pb = ((pPmBytearray_t)pobj)->val; + retval = string_printFormattedBytes(&(pb->val[0]), + C_TRUE, + ((pPmBytearray_t)pobj)->length); + plat_putByte(')'); + return retval; +} +#endif /* HAVE_PRINT */ +#endif /* HAVE_BYTEARRAY */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/bytearray.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,63 @@ +/* +# This file is Copyright 2010 Dean Hall. +# This file is part of the PyMite VM. +# This file is licensed under the MIT License. +# See the LICENSE file for details. +*/ + + +#ifndef __BYTEARRAY_H__ +#define __BYTEARRAY_H__ + +/** + * \file + * \brief Bytearray Object Type + * + * Bytearray object type header. + */ + + +/** + * Bytes container + * + * Holds actual byte payload + */ +typedef struct PmBytes_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** Physical number of bytes in the C array (below) */ + uint16_t length; + + /** C array of bytes */ + uint8_t val[1]; +} PmBytes_t, + *pPmBytes_t; + + +/** + * Bytearray obj + * + * Mutable ordered sequence of bytes. Contains ptr to chunk of bytes. + */ +typedef struct PmBytearray_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** Bytearray length; logical number of bytes */ + uint16_t length; + + /** Ptr to bytes container (may hold more bytes than length) */ + pPmBytes_t val; +} PmBytearray_t, + *pPmBytearray_t; + + +PmReturn_t bytearray_new(pPmObj_t pobj, pPmObj_t *r_pobj); +PmReturn_t bytearray_getItem(pPmObj_t pobj, int16_t index, pPmObj_t *r_pobj); +PmReturn_t bytearray_setItem(pPmObj_t pba, int16_t index, pPmObj_t pobj); +PmReturn_t bytearray_print(pPmObj_t pobj); + +#endif /* __BYTEARRAY_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/class.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,268 @@ +/* +# This file is Copyright 2009 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__ 0x18 + + +/** + * \file + * \brief Class Object Type + * + * Class object type operations. + */ + + +#include "pm.h" + + +#ifdef HAVE_AUTOBOX +static uint8_t const *liststr = (uint8_t const *)"list"; +static uint8_t const *dictstr = (uint8_t const *)"dict"; +static uint8_t const *stringstr = (uint8_t const *)"string"; +static uint8_t const *autoboxstr = (uint8_t const *)"_Autobox"; +static uint8_t const *objstr = (uint8_t const *)"obj"; +#endif + + +PmReturn_t +class_new(pPmObj_t pattrs, pPmObj_t pbases, pPmObj_t pname, pPmObj_t *r_pclass) +{ + PmReturn_t retval = PM_RET_OK; + uint8_t *pchunk; + pPmObj_t pobj; + + /* Ensure types */ + if ((OBJ_GET_TYPE(pattrs) != OBJ_TYPE_DIC) + || (OBJ_GET_TYPE(pbases) != OBJ_TYPE_TUP) + || (OBJ_GET_TYPE(pname) != OBJ_TYPE_STR)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Allocate a class obj */ + retval = heap_getChunk(sizeof(PmClass_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + pobj = (pPmObj_t)pchunk; + OBJ_SET_TYPE(pobj, OBJ_TYPE_CLO); + + /* Class has no access to its CO */ + ((pPmClass_t)pobj)->cl_attrs = (pPmDict_t)pattrs; + ((pPmClass_t)pobj)->cl_bases = (pPmTuple_t)pbases; + + *r_pclass = pobj; + + return retval; +} + + +/* Returns an instance of the class by reference */ +PmReturn_t +class_instantiate(pPmObj_t pclass, pPmObj_t *r_pobj) +{ + PmReturn_t retval = PM_RET_OK; + uint8_t *pchunk; + pPmObj_t pobj; + pPmObj_t pattrs; + uint8_t objid; + + /* Allocate a class instance */ + retval = heap_getChunk(sizeof(PmInstance_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + pobj = (pPmObj_t)pchunk; + OBJ_SET_TYPE(pobj, OBJ_TYPE_CLI); + + /* Set the instance's fields */ + ((pPmInstance_t)pobj)->cli_class = (pPmClass_t)pclass; + ((pPmInstance_t)pobj)->cli_attrs = C_NULL; + + /* Create the attributes dict */ + heap_gcPushTempRoot(pobj, &objid); + retval = dict_new(&pattrs); + heap_gcPopTempRoot(objid); + ((pPmInstance_t)pobj)->cli_attrs = (pPmDict_t)pattrs; + + /* TODO: Store pclass in __class__ attr */ + + *r_pobj = pobj; + return retval; +} + + +#ifdef HAVE_AUTOBOX +PmReturn_t +class_autobox(pPmObj_t *pobj) +{ + PmReturn_t retval = PM_RET_OK; + pPmObj_t pmodule, pstr, pclass, pwrapped, pmodcache; + + uint8_t const *pliststr = liststr; + uint8_t const *pdictstr = dictstr; + uint8_t const *pstringstr = stringstr; + + uint8_t const *pAutoboxstr = autoboxstr; + uint8_t const *pobjstr = objstr; + + /* Load the appropriate module name, + * or do nothing if we have a non-boxable type + */ + if (OBJ_GET_TYPE(*pobj) == OBJ_TYPE_LST) { + retval = string_new(&pliststr, &pstr); + PM_RETURN_IF_ERROR(retval); + } else if (OBJ_GET_TYPE(*pobj) == OBJ_TYPE_DIC) { + retval = string_new(&pdictstr, &pstr); + PM_RETURN_IF_ERROR(retval); + } else if (OBJ_GET_TYPE(*pobj) == OBJ_TYPE_STR) { + retval = string_new(&pstringstr, &pstr); + PM_RETURN_IF_ERROR(retval); + } else { + return retval; + } + + /** first, try to get the module from the cache */ + retval = dict_getItem(PM_PBUILTINS, PM_MD_STR, &pmodcache); + PM_RETURN_IF_ERROR(retval); + + retval = dict_getItem(pmodcache, pstr, &pmodule); + PM_RETURN_IF_ERROR(retval); + + if (!((retval == PM_RET_OK) && (OBJ_GET_TYPE(pmodule) == OBJ_TYPE_MOD))) + { + PM_RAISE(retval, PM_RET_EX_SYS); + return retval; + } + + /* grab the class from within the loaded module */ + retval = string_new(&pAutoboxstr, &pstr); + PM_RETURN_IF_ERROR(retval); + retval = dict_getItem((pPmObj_t) ((pPmFunc_t)pmodule)->f_attrs, pstr, &pclass); + PM_RETURN_IF_ERROR(retval); + + /* instantiate instance of (type)._Autobox */ + retval = class_instantiate(pclass, &pwrapped); + PM_RETURN_IF_ERROR(retval); + + /* store object as _Autobox().obj */ + retval = string_new(&pobjstr, &pstr); + PM_RETURN_IF_ERROR(retval); + retval = dict_setItem((pPmObj_t)((pPmInstance_t)pwrapped)->cli_attrs, + pstr, *pobj); + PM_RETURN_IF_ERROR(retval); + + /** replace old object with new instance in place */ + *pobj = pwrapped; + + return retval; +} +#endif + + +PmReturn_t +class_method(pPmObj_t pinstance, pPmObj_t pfunc, pPmObj_t *r_pmeth) +{ + PmReturn_t retval = PM_RET_OK; + uint8_t *pchunk; + pPmMethod_t pmeth; + pPmObj_t pattrs; + uint8_t objid; + + /* Allocate a method */ + retval = heap_getChunk(sizeof(PmMethod_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + OBJ_SET_TYPE(pchunk, OBJ_TYPE_MTH); + + /* Set method fields */ + pmeth = (pPmMethod_t)pchunk; + pmeth->m_instance = (pPmInstance_t)pinstance; + pmeth->m_func = (pPmFunc_t)pfunc; + pmeth->m_attrs = C_NULL; + + /* Create the attributes dict */ + heap_gcPushTempRoot((pPmObj_t)pmeth, &objid); + retval = dict_new(&pattrs); + heap_gcPopTempRoot(objid); + pmeth->m_attrs = (pPmDict_t)pattrs; + + *r_pmeth = (pPmObj_t)pmeth; + return retval; +} + + +PmReturn_t +class_getAttr(pPmObj_t pobj, pPmObj_t pname, pPmObj_t *r_pobj) +{ + PmReturn_t retval; + uint16_t i; + pPmObj_t pparent; + + /* If the given obj is an instance, check its attrs */ + if (OBJ_GET_TYPE(pobj) == OBJ_TYPE_CLI) + { + retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj)->cli_attrs, pname, + r_pobj); + if (retval == PM_RET_OK) + { + return retval; + } + + /* Otherwise, check the instance's class */ + pobj = (pPmObj_t)((pPmInstance_t)pobj)->cli_class; + } + + C_ASSERT(OBJ_GET_TYPE(pobj) == OBJ_TYPE_CLO); + + retval = dict_getItem((pPmObj_t)((pPmClass_t)pobj)->cl_attrs, pname, + r_pobj); + + /* If attr is not found, search parent(s) */ + if ((retval == PM_RET_EX_KEY) && (((pPmClass_t)pobj)->cl_bases != C_NULL)) + { + for (i = 0; i < ((pPmClass_t)pobj)->cl_bases->length; i++) + { + pparent = ((pPmClass_t)pobj)->cl_bases->val[i]; + retval = class_getAttr(pparent, pname, r_pobj); + if (retval == PM_RET_OK) + { + break; + } + } + } + + return retval; +} + + +uint8_t /* boolean */ +class_isSubclass(pPmObj_t ptest_class, pPmObj_t pbase_class) +{ + uint8_t i; + uint8_t retval; + + retval = C_FALSE; + + if (ptest_class == pbase_class) + { + return C_TRUE; + } + + /* Recursively check if test class has a matching base class */ + if (((pPmClass_t)ptest_class)->cl_bases != C_NULL) + { + for (i = 0; i < ((pPmClass_t)ptest_class)->cl_bases->length; i++) + { + retval = class_isSubclass(((pPmClass_t)ptest_class)->cl_bases->val[i], + pbase_class); + if (retval) + { + break; + } + } + } + return retval; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/class.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,132 @@ +/* +# This file is Copyright 2009 Dean Hall. +# This file is part of the PyMite VM. +# This file is licensed under the MIT License. +# See the LICENSE file for details. +*/ + + +#ifndef __CLASS_H__ +#define __CLASS_H__ + +/** + * \file + * \brief Class header. + */ + + +/** + * Class struct + * + * This C struct is used for PyMite class objects + * Note: Exceptions are objects. + */ +typedef struct PmClass_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** Attributes dict */ + pPmDict_t cl_attrs; + + /** Bases tuple */ + pPmTuple_t cl_bases; +} PmClass_t, + *pPmClass_t; + +/** Class instance struct */ +typedef struct PmInstance_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** Class of this instance */ + pPmClass_t cli_class; + + /** Attributes dict */ + pPmDict_t cli_attrs; +} PmInstance_t, +*pPmInstance_t; + +/** Method struct */ +typedef struct PmMethod_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** Class instance of this method */ + pPmInstance_t m_instance; + + /** Func of this method */ + pPmFunc_t m_func; + + /** Attributes dict */ + pPmDict_t m_attrs; +} PmMethod_t, +*pPmMethod_t; + + +/** + * Creates a new Class object from the methods dict, bases tuple, + * and name string. + * + * @param pmeths ptr to methods dict. + * @param pbases ptr to bases tuple. + * @param pname ptr to name string. + * @param r_pclass Return by ref, ptr to new class + * @return Return status + */ +PmReturn_t class_new(pPmObj_t pmeths, pPmObj_t pbases, pPmObj_t pname, + pPmObj_t *r_pclass); + +/** + * Returns an instance of the given class + * + * @param pclass Pointer to class object + * @param r_pobj Return by ref, instance object + * @return Return status + */ +PmReturn_t class_instantiate(pPmObj_t pclass, pPmObj_t *r_pobj); + +#ifdef HAVE_AUTOBOX +/** + * Autoboxes an object in place + * + * @param pclass Pointer to object + * @return Return status + */ +PmReturn_t class_autobox(pPmObj_t *pobj); +#endif + +/** + * Returns a method based on the given inputs + * + * @param pinstance ptr to instance + * @param pfunc ptr to func + * @param r_pmeth Return by ref, ptr to new method + * @return Return status + */ +PmReturn_t class_method(pPmObj_t pinstance, pPmObj_t pfunc, pPmObj_t *r_pmeth); + +/** + * Returns the first attribute named __init__ in the class' inheritance tree + * + * @param pobj ptr to class or instance to search + * @param pname ptr to name of attr to find + * @param r_pobj Return by ref, ptr to attr if found, or undetermined + * @return Return status + */ +PmReturn_t class_getAttr(pPmObj_t pobj, pPmObj_t pname, pPmObj_t *r_pobj); + +/** + * Returns a C boolean if the base class is found in the inheritance tree + * of the test class. NOTE: This function is recursive. + * + * @param ptest_class ptr to class whose inheritance tree is searched + * @param pbase_class ptr to class to look for + * @return Returns C_TRUE if pbase_class is found in the inheritance tree; + * C_FALSE otherwise. + */ +uint8_t class_isSubclass(pPmObj_t ptest_class, pPmObj_t pbase_class); + +#endif /* __CLASS_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/codeobj.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,176 @@ +/* +# 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__ 0x01 + + +/** + * \file + * \brief CodeObj Type + * + * CodeObj type operations. + */ + + +#include "pm.h" + + +/* The image format is defined by co_to_str() in src/tools/pmImgCreator.py */ +PmReturn_t +co_loadFromImg(PmMemSpace_t memspace, uint8_t const **paddr, pPmObj_t *r_pco) +{ + PmReturn_t retval = PM_RET_OK; + pPmObj_t pobj; + pPmCo_t pco = C_NULL; + uint8_t *pchunk; + uint8_t objid; +#ifdef HAVE_DEBUG_INFO + uint8_t objtype; + uint16_t len_str; +#endif /* HAVE_DEBUG_INFO */ + + /* Store ptr to top of code img (less type byte) */ + uint8_t const *pci = *paddr - 1; + + /* Get size of code img */ + uint16_t size = mem_getWord(memspace, paddr); + + /* Allocate a code obj */ + retval = heap_getChunk(sizeof(PmCo_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + pco = (pPmCo_t)pchunk; + + /* Fill in the CO struct */ + OBJ_SET_TYPE(pco, OBJ_TYPE_COB); + pco->co_memspace = memspace; + pco->co_argcount = mem_getByte(memspace, paddr); + pco->co_flags = mem_getByte(memspace, paddr); + pco->co_stacksize = mem_getByte(memspace, paddr); + pco->co_nlocals = mem_getByte(memspace, paddr); + + /* Do not set code image address if image is in RAM. + * CIs in RAM have their image address set in obj_loadFromImgObj() */ + pco->co_codeimgaddr = (memspace == MEMSPACE_RAM) ? C_NULL : pci; + + /* Set these to null in case a GC occurs before their objects are alloc'd */ + pco->co_names = C_NULL; + pco->co_consts = C_NULL; + pco->co_codeaddr = C_NULL; + +#ifdef HAVE_CLOSURES + pco->co_nfreevars = mem_getByte(memspace, paddr); + pco->co_cellvars = C_NULL; +#endif /* HAVE_CLOSURES */ + +#ifdef HAVE_DEBUG_INFO + pco->co_firstlineno = mem_getWord(memspace, paddr); + pco->co_lnotab = C_NULL; + pco->co_filename = C_NULL; +#endif /* HAVE_DEBUG_INFO */ + + /* Load names (tuple obj) */ + heap_gcPushTempRoot((pPmObj_t)pco, &objid); + retval = obj_loadFromImg(memspace, paddr, &pobj); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + pco->co_names = (pPmTuple_t)pobj; + +#ifdef HAVE_DEBUG_INFO + /* Get address in memspace of line number table (including length) */ + objtype = mem_getByte(memspace, paddr); + C_ASSERT(objtype == OBJ_TYPE_STR); + pco->co_lnotab = *paddr; + len_str = mem_getWord(memspace, paddr); + *paddr = *paddr + len_str; + + /* Get address in memspace of CO's filename (excluding length) */ + objtype = mem_getByte(memspace, paddr); + C_ASSERT(objtype == OBJ_TYPE_STR); + len_str = mem_getWord(memspace, paddr); + pco->co_filename = *paddr; + *paddr = *paddr + len_str; +#endif /* HAVE_DEBUG_INFO */ + + /* Load consts (tuple obj) assume it follows names */ + heap_gcPushTempRoot((pPmObj_t)pco, &objid); + retval = obj_loadFromImg(memspace, paddr, &pobj); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + pco->co_consts = (pPmTuple_t)pobj; + +#ifdef HAVE_CLOSURES + heap_gcPushTempRoot((pPmObj_t)pco, &objid); + retval = obj_loadFromImg(memspace, paddr, &pobj); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + + /* Save RAM, don't keep empty tuple */ + if (((pPmTuple_t)pobj)->length == 0) + { + heap_freeChunk(pobj); + } + else + { + pco->co_cellvars = (pPmTuple_t)pobj; + } +#endif /* HAVE_CLOSURES */ + + /* Start of bcode always follows consts */ + pco->co_codeaddr = *paddr; + + /* Set addr to point one past end of img */ + *paddr = pci + size; + + *r_pco = (pPmObj_t)pco; + return PM_RET_OK; +} + + +void +co_rSetCodeImgAddr(pPmCo_t pco, uint8_t const *pimg) +{ + uint8_t i; + + pco->co_codeimgaddr = pimg; + + /* Set the image address for any COs in the constant pool */ + for (i = 0; i < pco->co_consts->length; i++) + { + if (OBJ_GET_TYPE(pco->co_consts->val[i]) == OBJ_TYPE_COB) + { + co_rSetCodeImgAddr((pPmCo_t)pco->co_consts->val[i], pimg); + } + } + + return; +} + + +PmReturn_t +no_loadFromImg(PmMemSpace_t memspace, uint8_t const **paddr, pPmObj_t *r_pno) +{ + PmReturn_t retval = PM_RET_OK; + pPmNo_t pno = C_NULL; + uint8_t *pchunk; + + /* Allocate a code obj */ + retval = heap_getChunk(sizeof(PmNo_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + pno = (pPmNo_t)pchunk; + + /* Fill in the NO struct */ + OBJ_SET_TYPE(pno, OBJ_TYPE_NOB); + pno->no_argcount = mem_getByte(memspace, paddr); + + /* Get index into native fxn table */ + pno->no_funcindx = (int16_t)mem_getWord(memspace, paddr); + + *r_pno = (pPmObj_t)pno; + return PM_RET_OK; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/codeobj.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,211 @@ +/* +# 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. +*/ + + +#ifndef __CODEOBJ_H__ +#define __CODEOBJ_H__ + + +/** + * \file + * \brief CodeObj Type + * + * CodeObj type header. + */ + + +/** Code image field offset consts */ +#define CI_TYPE_FIELD 0 +#define CI_SIZE_FIELD 1 +#define CI_ARGCOUNT_FIELD 3 +#define CI_FLAGS_FIELD 4 +#define CI_STACKSIZE_FIELD 5 +#define CI_NLOCALS_FIELD 6 + +#ifdef HAVE_CLOSURES +# define CI_FREEVARS_FIELD 7 +# ifdef HAVE_DEBUG_INFO +# define CI_FIRST_LINE_NO 8 +# define CI_NAMES_FIELD 10 +# else +# define CI_NAMES_FIELD 8 +# endif /* HAVE_DEBUG_INFO */ +#else +# ifdef HAVE_DEBUG_INFO +# define CI_FIRST_LINE_NO 7 +# define CI_NAMES_FIELD 9 +# else +# define CI_NAMES_FIELD 7 +# endif /* HAVE_DEBUG_INFO */ +#endif /* HAVE_CLOSURES */ + + +/** Native code image size */ +#define NATIVE_IMAGE_SIZE 4 + +/* Masks for co_flags (from Python's code.h) */ +#define CO_OPTIMIZED 0x01 +#define CO_NEWLOCALS 0x02 +#define CO_VARARGS 0x04 +#define CO_VARKEYWORDS 0x08 +#define CO_NESTED 0x10 +#define CO_GENERATOR 0x20 +#define CO_NOFREE 0x40 + +/** + * Code Object + * + * An extended object that holds only the most frequently used parts + * of the static code image. Other parts can be obtained by + * inspecting the code image itself. + */ +typedef struct PmCo_s +{ + /** Object descriptor */ + PmObjDesc_t od; + /** Address in progmem of the code image, or of code img obj in heap */ + uint8_t const *co_codeimgaddr; + /** Address in RAM of names tuple */ + pPmTuple_t co_names; + /** Address in RAM of constants tuple */ + pPmTuple_t co_consts; + /** Address in memspace of bytecode (or native function) */ + uint8_t const *co_codeaddr; + +#ifdef HAVE_DEBUG_INFO + /** Address in memspace of the line number table */ + uint8_t const *co_lnotab; + /** Address in memspace of the filename */ + uint8_t const *co_filename; + /** Line number of first source line of lnotab */ + uint16_t co_firstlineno; +#endif /* HAVE_DEBUG_INFO */ + +#ifdef HAVE_CLOSURES + /** Address in RAM of cellvars tuple */ + pPmTuple_t co_cellvars; + /** Number of freevars */ + uint8_t co_nfreevars; +#endif /* HAVE_CLOSURES */ + + /** Memory space selector */ + PmMemSpace_t co_memspace:8; + /** Number of positional arguments the function expects */ + uint8_t co_argcount; + /** Compiler flags */ + uint8_t co_flags; + /** Stack size */ + uint8_t co_stacksize; + /** Number of local variables */ + uint8_t co_nlocals; +} PmCo_t, + *pPmCo_t; + +/** + * Native Code Object + * + * An extended object that holds only the most frequently used parts + * of the static native image. Other parts can be obtained by + * inspecting the native image itself. + */ +typedef struct PmNo_s +{ + /** object descriptor */ + PmObjDesc_t od; + /** expected num args to the func */ + int8_t no_argcount; + /** index into native function table */ + int16_t no_funcindx; +} PmNo_t, + *pPmNo_t; + + +/** + * Creates a CodeObj by loading info from a code image in memory. + * + * An image is a static representation of a Python object. + * The process of converting an object to and from an image + * is also called marshalling. + * In PyMite, code images are the equivalent of .pyc files. + * Code images can only contain a select subset of object types + * (None, Int, Float, String, Slice?, Tuple, and CodeImg). + * All other types (Lists, Dicts, CodeObjs, Modules, Classes, + * Functions, ClassInstances) are built at runtime. + * + * All multibyte values are in Little Endian order + * (least significant byte comes first in the byte stream). + * + * memspace and *paddr determine the start of the code image. + * Load the code object with values from the code image, + * including the names and consts tuples. + * Leave contents of paddr pointing one byte past end of + * code img. + * + * The code image has the following structure: + * -type: 8b - OBJ_TYPE_CIM + * -size: 16b - number of bytes + * the code image occupies. + * -argcount: 8b - number of arguments to this code obj. + * -stacksz: 8b - the maximum arg-stack size needed. + * -nlocals: 8b - number of local vars in the code obj. + * -names: Tuple - tuple of string objs. + * -consts: Tuple - tuple of objs. + * -code: 8b[] - bytecode array. + * + * @param memspace memory space containing image + * @param paddr ptr to ptr to code img in memspace + * return by reference: paddr points one byte + * past end of code img + * @param r_pco Return arg. New code object with fields + * filled in. + * @return Return status + */ +PmReturn_t +co_loadFromImg(PmMemSpace_t memspace, uint8_t const **paddr, pPmObj_t *r_pco); + +/** + * Recursively sets image address of the CO and all its nested COs + * in its constant pool. This is done so that an image that was + * received during an interactive session will persist as long as any + * of its COs/funcs/objects is still alive. + * + * @param pco Pointer to root code object whose images are set + * @param pimg Pointer to very top of code image (PmodeImgObj) + */ +void co_rSetCodeImgAddr(pPmCo_t pco, uint8_t const *pimg); + +/** + * Creates a Native code object by loading a native image. + * + * An image is a static representation of a Python object. + * A native image is much smaller than a regular image + * because only two items of data are needed after the type: + * the number of args the func expects and the index into + * the native function table. + * A reference to the image is not needed since it is + * just as efficient to store the info in RAM as it is to + * store a pointer and memspace value. + * + * memspace and *paddr determine the start of the native image. + * Loads the argcount and the func index from the native object. + * Leaves contents of paddr pointing one byte past end of + * code img. + * + * The native image has the following structure: + * -type: 8b - OBJ_TYPE_CIM + * -argcount: 8b - number of arguments to this code obj. + * -code: 16b - index into native function table. + * + * @param memspace memory space containing image + * @param paddr ptr to ptr to code img in memspace (return) + * @param r_pno Return by reference, new code object + * @return Return status + */ +PmReturn_t no_loadFromImg(PmMemSpace_t memspace, + uint8_t const **paddr, pPmObj_t *r_pno); + +#endif /* __CODEOBJ_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/dict.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,375 @@ +/* +# 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__ 0x02 + + +/** + * \file + * \brief Dict Object Type + * + * Dict object type operations. + */ + + +#include "pm.h" + + +PmReturn_t +dict_new(pPmObj_t *r_pdict) +{ + PmReturn_t retval = PM_RET_OK; + pPmDict_t pdict = C_NULL; + uint8_t *pchunk; + + /* Allocate a dict */ + retval = heap_getChunk(sizeof(PmDict_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + + /* Init dict fields */ + pdict = (pPmDict_t)pchunk; + OBJ_SET_TYPE(pdict, OBJ_TYPE_DIC); + pdict->length = 0; + pdict->d_keys = C_NULL; + pdict->d_vals = C_NULL; + + *r_pdict = (pPmObj_t)pchunk; + return retval; +} + + +PmReturn_t +dict_clear(pPmObj_t pdict) +{ + PmReturn_t retval = PM_RET_OK; + + C_ASSERT(pdict != C_NULL); + + /* Raise TypeError if arg is not a dict */ + if (OBJ_GET_TYPE(pdict) != OBJ_TYPE_DIC) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* clear length */ + ((pPmDict_t)pdict)->length = 0; + + /* Free the keys and values seglists if needed */ + if (((pPmDict_t)pdict)->d_keys != C_NULL) + { + PM_RETURN_IF_ERROR(seglist_clear(((pPmDict_t)pdict)->d_keys)); + PM_RETURN_IF_ERROR(heap_freeChunk((pPmObj_t) + ((pPmDict_t)pdict)->d_keys)); + ((pPmDict_t)pdict)->d_keys = C_NULL; + } + if (((pPmDict_t)pdict)->d_vals != C_NULL) + { + PM_RETURN_IF_ERROR(seglist_clear(((pPmDict_t)pdict)->d_vals)); + retval = heap_freeChunk((pPmObj_t)((pPmDict_t)pdict)->d_vals); + ((pPmDict_t)pdict)->d_vals = C_NULL; + } + return retval; +} + + +/* + * Sets a value in the dict using the given key. + * + * Scans dict for the key. If key val found, replace old + * with new val. If no key found, add key/val pair to dict. + */ +PmReturn_t +dict_setItem(pPmObj_t pdict, pPmObj_t pkey, pPmObj_t pval) +{ + PmReturn_t retval = PM_RET_OK; + int16_t indx; + + C_ASSERT(pdict != C_NULL); + C_ASSERT(pkey != C_NULL); + C_ASSERT(pval != C_NULL); + + /* If it's not a dict, raise TypeError */ + if (OBJ_GET_TYPE(pdict) != OBJ_TYPE_DIC) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* #112: Force Dict keys to be of hashable type */ + /* If key is not hashable, raise TypeError */ + if (OBJ_GET_TYPE(pkey) > OBJ_TYPE_HASHABLE_MAX) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* #147: Change boolean keys to integers */ + if (pkey == PM_TRUE) + { + pkey = PM_ONE; + } + else if (pkey == PM_FALSE) + { + pkey = PM_ZERO; + } + + /* + * #115: If this is the first key/value pair to be added to the Dict, + * allocate the key and value seglists that hold those items + */ + if (((pPmDict_t)pdict)->length == 0) + { + retval = seglist_new(&((pPmDict_t)pdict)->d_keys); + PM_RETURN_IF_ERROR(retval); + retval = seglist_new(&((pPmDict_t)pdict)->d_vals); + PM_RETURN_IF_ERROR(retval); + } + else + { + /* Check for matching key */ + indx = 0; + retval = seglist_findEqual(((pPmDict_t)pdict)->d_keys, pkey, &indx); + + /* If found a matching key, replace val obj */ + if (retval == PM_RET_OK) + { + retval = seglist_setItem(((pPmDict_t)pdict)->d_vals, pval, indx); + return retval; + } + } + + /* Otherwise, insert the key,val pair */ + retval = seglist_insertItem(((pPmDict_t)pdict)->d_keys, pkey, 0); + PM_RETURN_IF_ERROR(retval); + retval = seglist_insertItem(((pPmDict_t)pdict)->d_vals, pval, 0); + ((pPmDict_t)pdict)->length++; + + return retval; +} + + +PmReturn_t +dict_getItem(pPmObj_t pdict, pPmObj_t pkey, pPmObj_t *r_pobj) +{ + PmReturn_t retval = PM_RET_OK; + int16_t indx = 0; + +/* C_ASSERT(pdict != C_NULL);*/ + + /* if it's not a dict, raise TypeError */ + if (OBJ_GET_TYPE(pdict) != OBJ_TYPE_DIC) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* if dict is empty, raise KeyError */ + if (((pPmDict_t)pdict)->length <= 0) + { + PM_RAISE(retval, PM_RET_EX_KEY); + return retval; + } + + /* #147: Change boolean keys to integers */ + if (pkey == PM_TRUE) + { + pkey = PM_ONE; + } + else if (pkey == PM_FALSE) + { + pkey = PM_ZERO; + } + + /* check for matching key */ + retval = seglist_findEqual(((pPmDict_t)pdict)->d_keys, pkey, &indx); + /* if key not found, raise KeyError */ + if (retval == PM_RET_NO) + { + PM_RAISE(retval, PM_RET_EX_KEY); + } + /* return any other error */ + PM_RETURN_IF_ERROR(retval); + + /* key was found, get obj from vals */ + retval = seglist_getItem(((pPmDict_t)pdict)->d_vals, indx, r_pobj); + return retval; +} + + +#ifdef HAVE_DEL +PmReturn_t +dict_delItem(pPmObj_t pdict, pPmObj_t pkey) +{ + PmReturn_t retval = PM_RET_OK; + int16_t indx = 0; + + C_ASSERT(pdict != C_NULL); + + /* Check for matching key */ + retval = seglist_findEqual(((pPmDict_t)pdict)->d_keys, pkey, &indx); + + /* Raise KeyError if key is not found */ + if (retval == PM_RET_NO) + { + PM_RAISE(retval, PM_RET_EX_KEY); + } + + /* Return any other error */ + PM_RETURN_IF_ERROR(retval); + + /* Remove the key and value */ + retval = seglist_removeItem(((pPmDict_t)pdict)->d_keys, indx); + PM_RETURN_IF_ERROR(retval); + retval = seglist_removeItem(((pPmDict_t)pdict)->d_vals, indx); + + /* Reduce the item count */ + ((pPmDict_t)pdict)->length--; + + return retval; +} +#endif /* HAVE_DEL */ + + +#ifdef HAVE_PRINT +PmReturn_t +dict_print(pPmObj_t pdict) +{ + PmReturn_t retval = PM_RET_OK; + int16_t index; + pSeglist_t keys, + vals; + pPmObj_t pobj1; + + C_ASSERT(pdict != C_NULL); + + /* if it's not a dict, raise TypeError */ + if (OBJ_GET_TYPE(pdict) != OBJ_TYPE_DIC) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + plat_putByte('{'); + + keys = ((pPmDict_t)pdict)->d_keys; + vals = ((pPmDict_t)pdict)->d_vals; + + /* if dict is empty, raise KeyError */ + for (index = 0; index < ((pPmDict_t)pdict)->length; index++) + { + if (index != 0) + { + plat_putByte(','); + plat_putByte(' '); + } + retval = seglist_getItem(keys, index, &pobj1); + PM_RETURN_IF_ERROR(retval); + retval = obj_print(pobj1, C_FALSE, C_TRUE); + PM_RETURN_IF_ERROR(retval); + + plat_putByte(':'); + retval = seglist_getItem(vals, index, &pobj1); + PM_RETURN_IF_ERROR(retval); + retval = obj_print(pobj1, C_FALSE, C_TRUE); + PM_RETURN_IF_ERROR(retval); + } + + return plat_putByte('}'); +} +#endif /* HAVE_PRINT */ + + +PmReturn_t +dict_update(pPmObj_t pdestdict, pPmObj_t psourcedict, uint8_t omit_underscored) +{ + PmReturn_t retval = PM_RET_OK; + int16_t i; + pPmObj_t pkey; + pPmObj_t pval; + + C_ASSERT(pdestdict != C_NULL); + C_ASSERT(psourcedict != C_NULL); + + /* If it's not a dict, raise TypeError */ + if (OBJ_GET_TYPE(pdestdict) != OBJ_TYPE_DIC) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* If it's not a dict, raise TypeError */ + if (OBJ_GET_TYPE(psourcedict) != OBJ_TYPE_DIC) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Iterate over the add-on dict */ + for (i = 0; i < ((pPmDict_t)psourcedict)->length; i++) + { + /* Get the key,val from the add-on dict */ + retval = seglist_getItem(((pPmDict_t)psourcedict)->d_keys, i, &pkey); + PM_RETURN_IF_ERROR(retval); + retval = seglist_getItem(((pPmDict_t)psourcedict)->d_vals, i, &pval); + PM_RETURN_IF_ERROR(retval); + + if (!(omit_underscored && (OBJ_GET_TYPE(pkey) == OBJ_TYPE_STR) + && ((pPmString_t)pkey)->val[0] == '_')) + { + /* Set the key,val to the destination dict */ + retval = dict_setItem(pdestdict, pkey, pval); + PM_RETURN_IF_ERROR(retval); + } + } + + return retval; +} + + +int8_t +dict_compare(pPmObj_t d1, pPmObj_t d2) +{ + pPmDict_t pd1 = (pPmDict_t)d1; + pPmDict_t pd2 = (pPmDict_t)d2; + pPmObj_t pkey1; + pPmObj_t pval1; + pPmObj_t pval2; + uint16_t i; + PmReturn_t retval; + + /* Return if lengths are not equal */ + if (pd1->length != pd2->length) + { + return C_DIFFER; + } + + for (i = 0; i < pd1->length; i++) + { + /* Get the key,val from one dict */ + retval = seglist_getItem(pd1->d_keys, i, &pkey1); + PM_RETURN_IF_ERROR(retval); + retval = seglist_getItem(pd1->d_vals, i, &pval1); + PM_RETURN_IF_ERROR(retval); + + /* Return if the key,val pair is not in the other dict */ + retval = dict_getItem(d2, pkey1, &pval2); + if (retval != PM_RET_OK) + { + return C_DIFFER; + } + if (obj_compare(pval1, pval2) != C_SAME) + { + return C_DIFFER; + } + } + + /* All key,values match */ + return C_SAME; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/dict.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,130 @@ +/* +# 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. +*/ + + +#ifndef __DICT_H__ +#define __DICT_H__ + + +/** + * \file + * \brief Dict Object Type + * + * Dict object type header. + */ + + +/** + * Dict + * + * Contains ptr to two seglists, + * one for keys, the other for values; + * and a length, the number of key/value pairs. + */ +typedef struct PmDict_s +{ + /** object descriptor */ + PmObjDesc_t od; + /** number of key,value pairs in the dict */ + uint16_t length; + /** ptr to seglist containing keys */ + pSeglist_t d_keys; + /** ptr to seglist containing values */ + pSeglist_t d_vals; +} PmDict_t, + *pPmDict_t; + + +/** + * Clears the contents of a dict. + * after this operation, the dict should in the same state + * as if it were just created using dict_new(). + * + * @param pdict ptr to dict to clear. + * @return nothing + */ +PmReturn_t dict_clear(pPmObj_t pdict); + +/** + * Gets the value in the dict using the given key. + * + * @param pdict ptr to dict to search + * @param pkey ptr to key obj + * @param r_pobj Return; addr of ptr to obj + * @return Return status + */ +PmReturn_t dict_getItem(pPmObj_t pdict, pPmObj_t pkey, pPmObj_t *r_pobj); + +#ifdef HAVE_DEL +/** + * Removes a key and value from the dict. + * Throws TypeError if pdict is not a dict. + * Throws KeyError if pkey does not exist in pdict. + * + * @param pdict Ptr to dict to search + * @param pkey Ptr to key obj + * @return Return status + */ +PmReturn_t dict_delItem(pPmObj_t pdict, pPmObj_t pkey); +#endif /* HAVE_DEL */ + +/** + * Allocates space for a new Dict. + * Return a pointer to the dict by reference. + * + * @param r_pdict Return; Addr of ptr to dict + * @return Return status + */ +PmReturn_t dict_new(pPmObj_t *r_pdict); + +/** + * Sets a value in the dict using the given key. + * + * If the dict already contains a matching key, the value is + * replaced; otherwise the new key,val pair is inserted + * at the front of the dict (for fast lookup). + * In the later case, the length of the dict is incremented. + * + * @param pdict ptr to dict in which (key,val) will go + * @param pkey ptr to key obj + * @param pval ptr to val obj + * @return Return status + */ +PmReturn_t dict_setItem(pPmObj_t pdict, pPmObj_t pkey, pPmObj_t pval); + +#ifdef HAVE_PRINT +/** + * Prints out a dict. Uses obj_print() to print elements. + * + * @param pobj Object to print. + * @return Return status + */ +PmReturn_t dict_print(pPmObj_t pdict); +#endif /* HAVE_PRINT */ + +/** + * Updates the destination dict with the key,value pairs from the source dict + * + * @param pdestdict ptr to destination dict in which key,val pairs will go + * @param psourcedict ptr to source dict which has all key,val pairs to copy + * @param omit_underscored Boolean set to true to omit key,val pairs where + * the key starts with an underscore '_'. + * @return Return status + */ +PmReturn_t dict_update(pPmObj_t pdestdict, pPmObj_t psourcedict, + uint8_t omit_underscored); + +/** + * Returns C_SAME if the two given dictionaries have the same contents + * + * @param d1 ptr to a dictionary object + * @param d2 ptr to another dictionary object + * @return C_DIFFER or C_SAME + */ +int8_t dict_compare(pPmObj_t d1, pPmObj_t d2); + +#endif /* __DICT_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/float.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,217 @@ +/* +# This file is Copyright 2009 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__ 0x17 + + +/** + * \file + * \brief Float Object Type + * + * Float object type operations. + */ + + +#include "pm.h" + + +#ifdef HAVE_FLOAT +#include <math.h> + + +PmReturn_t +float_new(float f, pPmObj_t *r_pf) +{ + PmReturn_t retval = PM_RET_OK; + + retval = heap_getChunk(sizeof(PmFloat_t), (uint8_t **)r_pf); + PM_RETURN_IF_ERROR(retval); + OBJ_SET_TYPE(*r_pf, OBJ_TYPE_FLT); + ((pPmFloat_t) * r_pf)->val = f; + return retval; +} + + +#ifdef HAVE_PRINT + +PmReturn_t +float_print(pPmObj_t pf) +{ + uint8_t tBuffer[32]; + uint8_t bytesWritten; + uint8_t *p; + PmReturn_t retval = PM_RET_OK; + + C_ASSERT(pf != C_NULL); + + /* Raise TypeError if obj is not an float */ + if (OBJ_GET_TYPE(pf) != OBJ_TYPE_FLT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* #212: Use homebrew float formatter */ + retval = sli_ftoa(((pPmFloat_t)pf)->val, tBuffer, sizeof(tBuffer)); + bytesWritten = sli_strlen((char *)tBuffer); + + /* Remove trailing zeroes (per Python convention) */ + for (p = &tBuffer[bytesWritten] - 1; + p[0] == '0' && p[-1] != '.'; + --p, bytesWritten--); + ++p; + *p = '\0'; + + /* Sanity check */ + C_ASSERT(bytesWritten != 0); + C_ASSERT(bytesWritten < sizeof(tBuffer)); + + sli_puts(tBuffer); + return PM_RET_OK; +} + + +PmReturn_t +float_negative(pPmObj_t pf, pPmObj_t *r_pf) +{ + /* Create new int obj */ + return float_new(-((pPmFloat_t) pf)->val, r_pf); +} + +#endif /* HAVE_PRINT */ + + +PmReturn_t +float_op(pPmObj_t px, pPmObj_t py, pPmObj_t *r_pn, int8_t op) +{ + float x; + float y; + float r; + PmReturn_t retval; + + /* Raise TypeError if args aren't ints or floats */ + if (((OBJ_GET_TYPE(px) != OBJ_TYPE_INT) + && (OBJ_GET_TYPE(px) != OBJ_TYPE_FLT)) + || ((OBJ_GET_TYPE(py) != OBJ_TYPE_INT) + && (OBJ_GET_TYPE(py) != OBJ_TYPE_FLT))) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the values as floats */ + if (OBJ_GET_TYPE(px) == OBJ_TYPE_INT) + { + x = (float)((pPmInt_t)px)->val; + } + else + { + x = ((pPmFloat_t) px)->val; + } + + if (OBJ_GET_TYPE(py) == OBJ_TYPE_INT) + { + y = (float)((pPmInt_t)py)->val; + } + else + { + y = ((pPmFloat_t) py)->val; + } + + /* Raise ZeroDivisionError if denominator is zero */ + if ((y == 0.0) && ((op == '/') || (op == '%'))) + { + PM_RAISE(retval, PM_RET_EX_ZDIV); + return retval; + } + + /* Calculate x raised to y */ + switch (op) + { + /* *INDENT-OFF* */ + case '+': r = x + y; break; + case '-': r = x - y; break; + case '*': r = x * y; break; + case '/': r = x / y; break; + case '%': r = fmodf(x, y); break; + case 'P': r = powf(x, y); break; + default: r = 0.0; break; + /* *INDENT-ON* */ + } + + retval = float_new(r, r_pn); + + return retval; +} + +PmReturn_t +float_compare(pPmObj_t px, pPmObj_t py, pPmObj_t *r_pobj, PmCompare_t cmp) +{ + float x; + float y; + PmReturn_t retval = PM_RET_OK; + int8_t t8 = 0; + + /* Raise TypeError if args aren't ints or floats */ + if (((OBJ_GET_TYPE(px) != OBJ_TYPE_INT) + && (OBJ_GET_TYPE(px) != OBJ_TYPE_FLT)) + || ((OBJ_GET_TYPE(py) != OBJ_TYPE_INT) + && (OBJ_GET_TYPE(py) != OBJ_TYPE_FLT))) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Get the values as floats */ + if (OBJ_GET_TYPE(px) == OBJ_TYPE_INT) + { + x = (float)((pPmInt_t)px)->val; + } + else + { + x = ((pPmFloat_t) px)->val; + } + + if (OBJ_GET_TYPE(py) == OBJ_TYPE_INT) + { + y = (float)((pPmInt_t)py)->val; + } + else + { + y = ((pPmFloat_t) py)->val; + } + + switch (cmp) + { + /* *INDENT-OFF* */ + case COMP_LT: t8 = (int8_t)(x < y); break; + case COMP_LE: t8 = (int8_t)(x <= y); break; + case COMP_EQ: t8 = (int8_t)(x == y); break; + case COMP_NE: t8 = (int8_t)(x != y); break; + case COMP_GT: t8 = (int8_t)(x > y); break; + case COMP_GE: t8 = (int8_t)(x >= y); break; + case COMP_IS: t8 = (int8_t)(px == py); break; + case COMP_IS_NOT: t8 = (int8_t)(px != py);break; + case COMP_IN: + case COMP_NOT_IN: + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + + default: + /* Other compares are not yet supported */ + PM_RAISE(retval, PM_RET_EX_SYS); + break; + /* *INDENT-ON* */ + } + *r_pobj = (t8) ? PM_TRUE : PM_FALSE; + + return retval; +} + +#endif /* HAVE_FLOAT */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/float.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,95 @@ +/* +# This file is Copyright 2009 Dean Hall. +# This file is part of the PyMite VM. +# This file is licensed under the MIT License. +# See the LICENSE file for details. +*/ + + +#ifndef __FLOAT_H__ +#define __FLOAT_H__ + + +/** + * \file + * \brief Float Object Type + * + * Float object type header. + */ + + +/** + * Float obj + * + * 32b floating point number + */ +typedef struct PmFloat_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** Float value */ + float val; +} PmFloat_t, *pPmFloat_t; + + +#ifdef HAVE_FLOAT + +/** + * Creates a new Float object + * + * @param f Value to assign float (signed 32-bit). + * @param r_pint Return by ref, ptr to new float + * @return Return status + */ +PmReturn_t float_new(float f, pPmObj_t *r_pf); + +/** + * Implements the UNARY_NEGATIVE bcode. + * + * Creates a new float with a value that is the negative of the given float. + * + * @param pobj Pointer to target object + * @param r_pint Return by ref, ptr to float + * @return Return status + */ +PmReturn_t float_negative(pPmObj_t pf, pPmObj_t *r_pf); + +/** + * Returns by reference a float that is x op y. + * + * @param px The float left-hand argument + * @param py The float right-hand argument + * @param r_pn The return value of x op y + * @param op The operator (+,-,*,/ and power) + * @return Return status + */ +PmReturn_t float_op(pPmObj_t px, pPmObj_t py, pPmObj_t *r_pn, int8_t op); + +/** + * Returns by reference a boolean that is x op y. + * + * @param px The float left-hand argument + * @param py The float right-hand argument + * @param r_pn The return value of x cmp y + * @param cmp The comparison operator + * @return Return status + */ +PmReturn_t float_compare(pPmObj_t px, pPmObj_t py, pPmObj_t *r_pobj, + PmCompare_t cmp); + +#ifdef HAVE_PRINT +/** + * Sends out a float object. + * The number is preceded with a "-" when necessary. + * + * @param pObj Ptr to float object + * @return Return status + */ +PmReturn_t float_print(pPmObj_t pf); + +#endif /* HAVE_PRINT */ + +#endif /* HAVE_FLOAT */ + +#endif /* __FLOAT_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/frame.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,100 @@ +/* +# 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__ 0x03 + + +/** + * \file + * \brief VM Frame + * + * VM frame operations. + */ + + +#include "pm.h" + + +PmReturn_t +frame_new(pPmObj_t pfunc, pPmObj_t *r_pobj) +{ + PmReturn_t retval = PM_RET_OK; + int16_t fsize = 0; + pPmCo_t pco = C_NULL; + pPmFrame_t pframe = C_NULL; + uint8_t *pchunk; + + /* Get fxn's code obj */ + pco = ((pPmFunc_t)pfunc)->f_co; + + /* TypeError if passed func's CO is not a true COB */ + if (OBJ_GET_TYPE(pco) != OBJ_TYPE_COB) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + +#ifdef HAVE_GENERATORS + /* #207: Initializing a Generator using CALL_FUNC needs extra stack slot */ + fsize = sizeof(PmFrame_t) + (pco->co_stacksize + pco->co_nlocals + 2) * sizeof(pPmObj_t); +#elif defined(HAVE_CLASSES) + /* #230: Calling a class's __init__() takes two extra spaces on the stack */ + fsize = sizeof(PmFrame_t) + (pco->co_stacksize + pco->co_nlocals + 1) * sizeof(pPmObj_t); +#else + fsize = sizeof(PmFrame_t) + (pco->co_stacksize + pco->co_nlocals - 1) * sizeof(pPmObj_t); +#endif /* HAVE_CLASSES */ + +#ifdef HAVE_CLOSURES + /* #256: Add support for closures */ + fsize = fsize + pco->co_nfreevars + + ((pco->co_cellvars == C_NULL) ? 0 : pco->co_cellvars->length); +#endif /* HAVE_CLOSURES */ + + /* Allocate a frame */ + retval = heap_getChunk(fsize, &pchunk); + PM_RETURN_IF_ERROR(retval); + pframe = (pPmFrame_t)pchunk; + + /* Set frame fields */ + OBJ_SET_TYPE(pframe, OBJ_TYPE_FRM); + pframe->fo_back = C_NULL; + pframe->fo_func = (pPmFunc_t)pfunc; + pframe->fo_memspace = pco->co_memspace; + + /* Init instruction pointer and block stack */ + pframe->fo_ip = pco->co_codeaddr; + pframe->fo_blockstack = C_NULL; + + /* Get globals and attrs from the function object */ + pframe->fo_globals = ((pPmFunc_t)pfunc)->f_globals; + pframe->fo_attrs = ((pPmFunc_t)pfunc)->f_attrs; + +#ifndef HAVE_CLOSURES + /* Empty stack points to one past locals */ + pframe->fo_sp = &(pframe->fo_locals[pco->co_nlocals]); +#else + /* #256: Add support for closures */ + pframe->fo_sp = &(pframe->fo_locals[pco->co_nlocals + pco->co_nfreevars + + ((pco->co_cellvars == C_NULL) ? 0 : pco->co_cellvars->length)]); +#endif /* HAVE_CLOSURES */ + + /* By default, this is a normal frame, not an import or __init__ one */ + pframe->fo_isImport = 0; +#ifdef HAVE_CLASSES + pframe->fo_isInit = 0; +#endif + + /* Clear the stack */ + sli_memset((unsigned char *)&(pframe->fo_locals), (char const)0, + (unsigned int)fsize - sizeof(PmFrame_t)); + + /* Return ptr to frame */ + *r_pobj = (pPmObj_t)pframe; + return retval; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/frame.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,175 @@ +/* +# 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. +*/ + + +#ifndef __FRAME_H__ +#define __FRAME_H__ + + +/** + * \file + * \brief VM Frame + * + * VM frame header. + */ + + +/** + * The maximum number of local variables a native function can have. + * This defines the length of the locals array in the native frame struct. + */ +#define NATIVE_MAX_NUM_LOCALS 8 + + +/** + * Block Type + * + * Numerical values to put in the 'b_type' field of the tPmBlockType struct. + */ +typedef enum PmBlockType_e +{ + /** Invalid block type */ + B_INVALID = 0, + + /** Loop type */ + B_LOOP, + + /** Try type */ + B_TRY +} PmBlockType_t, *pPmBlockType_t; + + +/** + * Block + * + * Extra info for loops and trys (others?) + * Frames use linked list of blocks to handle + * nested loops and try-catch blocks. + */ +typedef struct PmBlock_s +{ + /** Obligatory obj descriptor */ + PmObjDesc_t od; + + /** Ptr to backup stack ptr */ + pPmObj_t *b_sp; + + /** Handler fxn obj */ + uint8_t const *b_handler; + + /** Block type */ + PmBlockType_t b_type:8; + + /** Next block in stack */ + struct PmBlock_s *next; +} PmBlock_t, + *pPmBlock_t; + + +/** + * Frame + * + * A struct that holds the execution frame of a function, including the stack, + * local vars and pointer to the code object. + * + * This struct doesn't declare the stack. + * frame_new() is responsible for allocating the extra memory + * at the tail of fo_locals[] to hold both the locals and stack. + */ +typedef struct PmFrame_s +{ + /** Obligatory obj descriptor */ + PmObjDesc_t od; + + /** Ptr to previous frame obj */ + struct PmFrame_s *fo_back; + + /** Ptr to fxn obj */ + pPmFunc_t fo_func; + + /** Mem space where func's CO comes from */ + PmMemSpace_t fo_memspace:8; + + /** Instrxn ptr (pts into memspace) */ + uint8_t const *fo_ip; + + /** Linked list of blocks */ + pPmBlock_t fo_blockstack; + + /** Local attributes dict (non-fast locals) */ + pPmDict_t fo_attrs; + + /** Global attributes dict (pts to root frame's globals */ + pPmDict_t fo_globals; + + /** Points to next empty slot in fo_locals (1 past TOS) */ + pPmObj_t *fo_sp; + + /** Frame can be an import-frame that handles RETURN differently */ + uint8_t fo_isImport:1; + +#ifdef HAVE_CLASSES + /** Flag to indicate class initailzer frame; handle RETURN differently */ + uint8_t fo_isInit:1; +#endif /* HAVE_CLASSES */ + + /** Array of local vars and stack (space appended at alloc) */ + pPmObj_t fo_locals[1]; + /* WARNING: Do not put new fields below fo_locals */ +} PmFrame_t, + *pPmFrame_t; + + +/** + * Native Frame + * + * A struct that holds the execution frame of a native function, + * including the args and single stack slot, and pointer to the code object. + * + * This struct doesn't need an OD because it is only used statically in the + * globals struct. There's only one native frame, the global one. + * This happens because a native function is a leaf node + * in the call tree (a native func can't call python funcs). + */ +typedef struct PmNativeFrame_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** Ptr to previous frame obj */ + struct PmFrame_s *nf_back; + + /** Ptr to fxn obj */ + pPmFunc_t nf_func; + + /** Single stack slot */ + pPmObj_t nf_stack; + + /** Boolean to indicate if the native frame is active */ + uint8_t nf_active; + + /** Number of args passed to the native function */ + uint8_t nf_numlocals; + + /** Local vars */ + pPmObj_t nf_locals[NATIVE_MAX_NUM_LOCALS]; +} PmNativeFrame_t, + *pPmNativeFrame_t; + + +/** + * Allocate space for a new frame, fill its fields + * with respect to the given function object. + * Return pointer to the new frame. + * + * @param pfunc ptr to Function object. + * @param r_pobj Return value; the new frame. + * @return Return status. + */ +PmReturn_t frame_new(pPmObj_t pfunc, pPmObj_t *r_pobj); + +#endif /* __FRAME_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/func.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,73 @@ +/* +# 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__ 0x04 + + +/** + * \file + * \brief Function Object Type + * + * Function object type operations. + */ + + +#include "pm.h" + + +PmReturn_t +func_new(pPmObj_t pco, pPmObj_t pglobals, pPmObj_t *r_pfunc) +{ + PmReturn_t retval = PM_RET_OK; + pPmFunc_t pfunc = C_NULL; + uint8_t *pchunk; + pPmObj_t pobj; + uint8_t objid; + + C_ASSERT(OBJ_GET_TYPE(pco) != OBJ_TYPE_COB + || OBJ_GET_TYPE(pco) != OBJ_TYPE_NOB); + C_ASSERT(OBJ_GET_TYPE(pglobals) == OBJ_TYPE_DIC); + + /* Allocate a func obj */ + retval = heap_getChunk(sizeof(PmFunc_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + pfunc = (pPmFunc_t)pchunk; + + /* Init func */ + OBJ_SET_TYPE(pfunc, OBJ_TYPE_FXN); + pfunc->f_co = (pPmCo_t)pco; + pfunc->f_globals = C_NULL; + pfunc->f_attrs = C_NULL; + +#ifdef HAVE_DEFAULTARGS + /* Clear default args (will be set later, if at all) */ + pfunc->f_defaultargs = C_NULL; +#endif /* HAVE_DEFAULTARGS */ + +#ifdef HAVE_CLOSURES + /* Clear field for closure tuple */ + pfunc->f_closure = C_NULL; +#endif /* HAVE_CLOSURES */ + + /* Create attrs dict for regular func (not native) */ + if (OBJ_GET_TYPE(pco) == OBJ_TYPE_COB) + { + heap_gcPushTempRoot((pPmObj_t)pfunc, &objid); + retval = dict_new(&pobj); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + pfunc->f_attrs = (pPmDict_t)pobj; + + /* Store the given globals dict */ + pfunc->f_globals = (pPmDict_t)pglobals; + } + + *r_pfunc = (pPmObj_t)pfunc; + return PM_RET_OK; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/func.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,67 @@ +/* +# 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. +*/ + + +#ifndef __FUNC_H__ +#define __FUNC_H__ + +/** + * \file + * \brief Function Object Type + * + * Function object type header. + */ + +/** + * Function obj + * + * A function is like an instance of a code obj. + * Contains ptr to its code obj and has its own attributes dict. + * + * The first (__main__) module that is executed has a function obj + * created for it to execute the bytecode which builds the module. + */ +typedef struct PmFunc_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** Ptr to code obj */ + pPmCo_t f_co; + + /** Ptr to attribute dict */ + pPmDict_t f_attrs; + + /** Ptr to globals dict */ + pPmDict_t f_globals; + +#ifdef HAVE_DEFAULTARGS + /** Ptr to tuple holding default args */ + pPmTuple_t f_defaultargs; +#endif /* HAVE_DEFAULTARGS */ + +#ifdef HAVE_CLOSURES + /** Ptr to tuple of cell values */ + pPmTuple_t f_closure; +#endif /* HAVE_CLOSURES */ + +} PmFunc_t, + *pPmFunc_t; + + +/** + * Creates a Function Obj for the given Code Obj. + * Allocate space for a Func obj and fill the fields. + * + * @param pco ptr to code obj + * @param pglobals ptr to globals dict (from containing func/module) + * @param r_pfunc Return by reference; pointer to new function + * @return Return status + */ +PmReturn_t func_new(pPmObj_t pco, pPmObj_t pglobals, pPmObj_t *r_pfunc); + +#endif /* __FUNC_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/global.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,256 @@ +/* +# 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__ 0x05 + + +/** + * \file + * \brief VM Globals + * + * VM globals operations. + * PyMite's global struct def and initial values. + */ + + +#include "pm.h" + + +extern unsigned char const *stdlib_img; + +static uint8_t const *bistr = (uint8_t const *)"__bi"; + + +/** Most PyMite globals all in one convenient place */ +volatile PmVmGlobal_t gVmGlobal; + + +PmReturn_t +global_init(void) +{ + PmReturn_t retval; + uint8_t *codestr = (uint8_t *)"code"; + uint8_t *pchunk; + pPmObj_t pobj; +#ifdef HAVE_CLASSES + uint8_t const *initstr = (uint8_t const *)"__init__"; +#endif /* HAVE_CLASSES */ +#ifdef HAVE_GENERATORS + uint8_t const *genstr = (uint8_t const *)"Generator"; + uint8_t const *nextstr = (uint8_t const *)"next"; +#endif /* HAVE_GENERATORS */ +#ifdef HAVE_ASSERT + uint8_t const *exnstr = (uint8_t const *)"Exception"; +#endif /* HAVE_ASSERT */ +#ifdef HAVE_BYTEARRAY + uint8_t const *pbastr = (uint8_t const *)"bytearray"; +#endif /* HAVE_BYTEARRAY */ + uint8_t const *pmdstr = (uint8_t const *)"__md"; + + /* Clear the global struct */ + sli_memset((uint8_t *)&gVmGlobal, '\0', sizeof(PmVmGlobal_t)); + + /* Set the PyMite release num (for debug and post mortem) */ + gVmGlobal.errVmRelease = PM_RELEASE; + + /* Init zero */ + retval = heap_getChunk(sizeof(PmInt_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + pobj = (pPmObj_t)pchunk; + OBJ_SET_TYPE(pobj, OBJ_TYPE_INT); + ((pPmInt_t)pobj)->val = (int32_t)0; + gVmGlobal.pzero = (pPmInt_t)pobj; + + /* Init one */ + retval = heap_getChunk(sizeof(PmInt_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + pobj = (pPmObj_t)pchunk; + OBJ_SET_TYPE(pobj, OBJ_TYPE_INT); + ((pPmInt_t)pobj)->val = (int32_t)1; + gVmGlobal.pone = (pPmInt_t)pobj; + + /* Init negone */ + retval = heap_getChunk(sizeof(PmInt_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + pobj = (pPmObj_t)pchunk; + OBJ_SET_TYPE(pobj, OBJ_TYPE_INT); + ((pPmInt_t)pobj)->val = (int32_t)-1; + gVmGlobal.pnegone = (pPmInt_t)pobj; + + /* Init False */ + retval = heap_getChunk(sizeof(PmBoolean_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + pobj = (pPmObj_t)pchunk; + OBJ_SET_TYPE(pobj, OBJ_TYPE_BOOL); + ((pPmBoolean_t) pobj)->val = (int32_t)C_FALSE; + gVmGlobal.pfalse = (pPmInt_t)pobj; + + /* Init True */ + retval = heap_getChunk(sizeof(PmBoolean_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + pobj = (pPmObj_t)pchunk; + OBJ_SET_TYPE(pobj, OBJ_TYPE_BOOL); + ((pPmBoolean_t) pobj)->val = (int32_t)C_TRUE; + gVmGlobal.ptrue = (pPmInt_t)pobj; + + /* Init None */ + retval = heap_getChunk(sizeof(PmObj_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + pobj = (pPmObj_t)pchunk; + OBJ_SET_TYPE(pobj, OBJ_TYPE_NON); + gVmGlobal.pnone = pobj; + + /* Init "code" string obj */ + retval = string_new((uint8_t const **)&codestr, &pobj); + PM_RETURN_IF_ERROR(retval); + gVmGlobal.pcodeStr = (pPmString_t)pobj; + +#ifdef HAVE_CLASSES + /* Init "__init__" string obj */ + retval = string_new((uint8_t const **)&initstr, &pobj); + PM_RETURN_IF_ERROR(retval); + gVmGlobal.pinitStr = (pPmString_t)pobj; +#endif /* HAVE_CLASSES */ + +#ifdef HAVE_GENERATORS + /* Init "Generator" string obj */ + retval = string_new((uint8_t const **)&genstr, &pobj); + PM_RETURN_IF_ERROR(retval); + gVmGlobal.pgenStr = (pPmString_t)pobj; + + /* Init "next" string obj */ + retval = string_new((uint8_t const **)&nextstr, &pobj); + PM_RETURN_IF_ERROR(retval); + gVmGlobal.pnextStr = (pPmString_t)pobj; +#endif /* HAVE_GENERATORS */ + +#ifdef HAVE_ASSERT + /* Init "Exception" string obj */ + retval = string_new((uint8_t const **)&exnstr, &pobj); + PM_RETURN_IF_ERROR(retval); + gVmGlobal.pexnStr = (pPmString_t)pobj; +#endif /* HAVE_ASSERT */ + +#ifdef HAVE_BYTEARRAY + /* Init "bytearray" string obj */ + retval = string_new((uint8_t const **)&pbastr, &pobj); + PM_RETURN_IF_ERROR(retval); + gVmGlobal.pbaStr = (pPmString_t)pobj; +#endif /* HAVE_BYTEARRAY */ + + /* Init "__md" string obj */ + retval = string_new((uint8_t const **)&pmdstr, &pobj); + PM_RETURN_IF_ERROR(retval); + gVmGlobal.pmdStr = (pPmString_t)pobj; + + /* Init empty builtins */ + gVmGlobal.builtins = C_NULL; + + /* Init native frame */ + gVmGlobal.nativeframe.od = sizeof(PmNativeFrame_t); + OBJ_SET_TYPE(&gVmGlobal.nativeframe, OBJ_TYPE_NFM); + gVmGlobal.nativeframe.nf_func = C_NULL; + gVmGlobal.nativeframe.nf_stack = C_NULL; + gVmGlobal.nativeframe.nf_active = C_FALSE; + gVmGlobal.nativeframe.nf_numlocals = 0; + + /* Create empty threadList */ + retval = list_new(&pobj); + gVmGlobal.threadList = (pPmList_t)pobj; + + /* Init the PmImgPaths with std image info */ + gVmGlobal.imgPaths.memspace[0] = MEMSPACE_PROG; + gVmGlobal.imgPaths.pimg[0] = (uint8_t *)&stdlib_img; + gVmGlobal.imgPaths.pathcount = 1; + +#ifdef HAVE_PRINT + gVmGlobal.needSoftSpace = C_FALSE; + gVmGlobal.somethingPrinted = C_FALSE; +#endif /* HAVE_PRINT */ + + return retval; +} + + +PmReturn_t +global_setBuiltins(pPmFunc_t pmod) +{ + PmReturn_t retval = PM_RET_OK; + pPmObj_t pkey = C_NULL; + uint8_t const *pbistr = bistr; + uint8_t objid; + + if (PM_PBUILTINS == C_NULL) + { + /* Need to load builtins first */ + global_loadBuiltins(); + } + + /* Put builtins module in the module's attrs dict */ + retval = string_new(&pbistr, &pkey); + PM_RETURN_IF_ERROR(retval); + + heap_gcPushTempRoot(pkey, &objid); + retval = dict_setItem((pPmObj_t)pmod->f_attrs, pkey, PM_PBUILTINS); + heap_gcPopTempRoot(objid); + + return retval; +} + + +PmReturn_t +global_loadBuiltins(void) +{ + PmReturn_t retval = PM_RET_OK; + pPmObj_t pkey = C_NULL; + uint8_t const *nonestr = (uint8_t const *)"None"; + uint8_t const *falsestr = (uint8_t const *)"False"; + uint8_t const *truestr = (uint8_t const *)"True"; + pPmObj_t pstr = C_NULL; + pPmObj_t pbimod; + uint8_t const *pbistr = bistr; + + /* Import the builtins */ + retval = string_new(&pbistr, &pstr); + PM_RETURN_IF_ERROR(retval); + retval = mod_import(pstr, &pbimod); + PM_RETURN_IF_ERROR(retval); + + /* Must interpret builtins' root code to set the attrs */ + C_ASSERT(gVmGlobal.threadList->length == 0); + interp_addThread((pPmFunc_t)pbimod); + retval = interpret(INTERP_RETURN_ON_NO_THREADS); + PM_RETURN_IF_ERROR(retval); + + /* Builtins points to the builtins module's attrs dict */ + gVmGlobal.builtins = ((pPmFunc_t)pbimod)->f_attrs; + + /* Set None manually */ + retval = string_new(&nonestr, &pkey); + PM_RETURN_IF_ERROR(retval); + retval = dict_setItem(PM_PBUILTINS, pkey, PM_NONE); + PM_RETURN_IF_ERROR(retval); + + /* Set False manually */ + retval = string_new(&falsestr, &pkey); + PM_RETURN_IF_ERROR(retval); + retval = dict_setItem(PM_PBUILTINS, pkey, PM_FALSE); + PM_RETURN_IF_ERROR(retval); + + /* Set True manually */ + retval = string_new(&truestr, &pkey); + PM_RETURN_IF_ERROR(retval); + retval = dict_setItem(PM_PBUILTINS, pkey, PM_TRUE); + PM_RETURN_IF_ERROR(retval); + + /* Deallocate builtins module */ + retval = heap_freeChunk((pPmObj_t)pbimod); + + return retval; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/global.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,193 @@ +/* +# 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. +*/ + + +#ifndef __GLOBAL_H__ +#define __GLOBAL_H__ + + +/** + * \file + * \brief VM Globals + * + * VM globals header. + */ + + +/** The global root PmGlobals Dict object */ +#define PM_PBUILTINS (pPmObj_t)(gVmGlobal.builtins) + +/** The global None object */ +#define PM_NONE (pPmObj_t)(gVmGlobal.pnone) + +/** The global False object */ +#define PM_FALSE (pPmObj_t)(gVmGlobal.pfalse) + +/** The global True object */ +#define PM_TRUE (pPmObj_t)(gVmGlobal.ptrue) + +/** The global integer 0 object */ +#define PM_ZERO (pPmObj_t)(gVmGlobal.pzero) + +/** The global integer 1 object */ +#define PM_ONE (pPmObj_t)(gVmGlobal.pone) + +/** The global integer -1 object */ +#define PM_NEGONE (pPmObj_t)(gVmGlobal.pnegone) + +/** The global string "code" */ +#define PM_CODE_STR (pPmObj_t)(gVmGlobal.pcodeStr) + +#ifdef HAVE_CLASSES +/** The global string "__init__" */ +#define PM_INIT_STR (pPmObj_t)(gVmGlobal.pinitStr) +#endif /* HAVE_CLASSES */ + +#ifdef HAVE_GENERATORS +/** The global string "Generator" */ +#define PM_GENERATOR_STR (pPmObj_t)(gVmGlobal.pgenStr) +/** The global string "next" */ +#define PM_NEXT_STR (pPmObj_t)(gVmGlobal.pnextStr) +#endif /* HAVE_GENERATORS */ + +#ifdef HAVE_ASSERT +/** The global string "Exception" */ +#define PM_EXCEPTION_STR (pPmObj_t)(gVmGlobal.pexnStr) +#endif /* HAVE_ASSERT */ + +#ifdef HAVE_BYTEARRAY +/** The global string "bytearray" */ +#define PM_BYTEARRAY_STR (pPmObj_t)(gVmGlobal.pbaStr) +#endif /* HAVE_BYTEARRAY */ + +/** The global string "__md" */ +#define PM_MD_STR (pPmObj_t)(gVmGlobal.pmdStr) + + +/** + * This struct contains ALL of PyMite's globals + */ +typedef struct PmVmGlobal_s +{ + /** Global none obj (none) */ + pPmObj_t pnone; + + /** Global integer 0 obj */ + pPmInt_t pzero; + + /** Global integer 1 obj */ + pPmInt_t pone; + + /** Global integer -1 obj */ + pPmInt_t pnegone; + + /** Global boolean False obj */ + pPmInt_t pfalse; + + /** Global boolean True obj */ + pPmInt_t ptrue; + + /** The string "code", used in interp.c RAISE_VARARGS */ + pPmString_t pcodeStr; + + /** Dict for builtins */ + pPmDict_t builtins; + + /** Paths to available images */ + PmImgPaths_t imgPaths; + + /** The single native frame. Static alloc so it won't be GC'd */ + PmNativeFrame_t nativeframe; + + /** PyMite release value for when an error occurs */ + uint8_t errVmRelease; + + /** PyMite source file ID number for when an error occurs */ + uint8_t errFileId; + + /** Line number for when an error occurs */ + uint16_t errLineNum; + + /** Thread list */ + pPmList_t threadList; + + /** Ptr to current thread */ + pPmThread_t pthread; + +#ifdef HAVE_CLASSES + /* NOTE: placing this field before the nativeframe field causes errors */ + /** The string "__init__", used in interp.c CALL_FUNCTION */ + pPmString_t pinitStr; +#endif /* HAVE_CLASSES */ + +#ifdef HAVE_GENERATORS + /** The string "Generator", used in interp.c CALL_FUNCTION */ + pPmString_t pgenStr; + /** The string "next", used in interp.c FOR_ITER */ + pPmString_t pnextStr; +#endif /* HAVE_GENERATORS */ + +#ifdef HAVE_ASSERT + /** The string "Exception", used in RAISE_VARARGS */ + pPmString_t pexnStr; +#endif /* HAVE_ASSERT */ + +#ifdef HAVE_BYTEARRAY + /** The global string "bytearray" */ + pPmString_t pbaStr; +#endif /* HAVE_BYTEARRAY */ + + /** The global string "__md" */ + pPmString_t pmdStr; + +#ifdef HAVE_PRINT + /** Remembers when a space is needed before printing the next object */ + uint8_t needSoftSpace; + /** Remembers when something has printed since the last newline */ + uint8_t somethingPrinted; +#endif /* HAVE_PRINT */ + + /** Flag to trigger rescheduling */ + uint8_t reschedule; +} PmVmGlobal_t, + *pPmVmGlobal_t; + + +extern volatile PmVmGlobal_t gVmGlobal; + + +/** + * Initializes the global struct + * + * @return Return status + */ +PmReturn_t global_init(void); + +/** + * Sets the builtins dict into the given module's attrs. + * + * If not yet done, loads the "__bt" module via global_loadBuiltins(). + * Restrictions described in that functions documentation apply. + * + * @param pmod Module whose attrs receive builtins + * @return Return status + */ +PmReturn_t global_setBuiltins(pPmFunc_t pmod); + +/** + * Loads the "__bt" module and sets the builtins dict (PM_PBUILTINS) + * to point to __bt's attributes dict. + * Creates "None" = None entry in builtins. + * + * When run, there should not be any other threads in the interpreter + * thread list yet. + * + * @return Return status + */ +PmReturn_t global_loadBuiltins(void); + +#endif /* __GLOBAL_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/heap.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,1244 @@ +/* +# 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__ 0x06 + + +/** + * \file + * \brief VM Heap + * + * VM heap operations. + * All of PyMite's dynamic memory is obtained from this heap. + * The heap provides dynamic memory on demand. + */ + + +#include "pm.h" + + +/** The size of the temporary roots stack */ +#define HEAP_NUM_TEMP_ROOTS 24 + +/** + * The maximum size a live chunk can be (a live chunk is one that is in use). + * The live chunk size is determined by the size field in the *object* + * descriptor. That field is nine bits with two assumed lsbs (zeros): + * (0x1FF << 2) == 2044 + */ +#ifdef PM_PLAT_POINTER_SIZE +#if PM_PLAT_POINTER_SIZE == 8 +#define HEAP_MAX_LIVE_CHUNK_SIZE 2040 +#else +#define HEAP_MAX_LIVE_CHUNK_SIZE 2044 +#endif +#endif + +/** + * The maximum size a free chunk can be (a free chunk is one that is not in use). + * The free chunk size is limited by the size field in the *heap* descriptor. + * That field is fourteen bits with two assumed least significant bits (zeros): + * (0x3FFF << 2) == 65532 + * For 64-bit platforms, the value is 4 bytes less so that a max-sized chunk is + * a multiple of 8, so that max-sized chunks created during heap_init() have a + * good boundary value. + */ +#ifdef PM_PLAT_POINTER_SIZE +#if PM_PLAT_POINTER_SIZE == 8 +#define HEAP_MAX_FREE_CHUNK_SIZE 65528 +#else +#define HEAP_MAX_FREE_CHUNK_SIZE 65532 +#endif +#endif + +/** The minimum size a chunk can be + * (rounded up to a multiple of platform-pointer-size) */ +#ifdef PM_PLAT_POINTER_SIZE +#if PM_PLAT_POINTER_SIZE == 8 +#define HEAP_MIN_CHUNK_SIZE ((sizeof(PmHeapDesc_t) + 7) & ~7) +#else +#define HEAP_MIN_CHUNK_SIZE ((sizeof(PmHeapDesc_t) + 3) & ~3) +#endif +#endif + + + +/** + * Gets the GC's mark bit for the object. + * This MUST NOT be called on objects that are free. + */ +#define OBJ_GET_GCVAL(pobj) (((pPmObj_t)pobj)->od & OD_MARK_MASK) + +/** + * Sets the GC's mark bit for the object + * This MUST NOT be called on objects that are free. + */ +#ifdef HAVE_GC +#define OBJ_SET_GCVAL(pobj, gcval) \ + do \ + { \ + ((pPmObj_t)pobj)->od = (gcval) ? ((pPmObj_t)pobj)->od | OD_MARK_MASK \ + : ((pPmObj_t)pobj)->od & ~OD_MARK_MASK;\ + } \ + while (0) +#else +#define OBJ_SET_GCVAL(pobj, gcval) +#endif /* HAVE_GC */ + +#define CHUNK_GET_SIZE(pchunk) (((pPmHeapDesc_t)pchunk)->hd & HD_SIZE_MASK) + +/** Sets the size of the chunk in bytes. */ +#define CHUNK_SET_SIZE(pchunk, size) \ + do \ + { \ + ((pPmHeapDesc_t)(pchunk))->hd &= ~HD_SIZE_MASK; \ + ((pPmHeapDesc_t)(pchunk))->hd |= ((size) & HD_SIZE_MASK); \ + } \ + while (0) + +#define OBJ_SET_SIZE(pobj, size) \ + do \ + { \ + ((pPmObj_t)pobj)->od &= ~OD_SIZE_MASK; \ + ((pPmObj_t)pobj)->od |= ((size) & OD_SIZE_MASK); \ + } \ + while (0) + + +/** + * The following is a diagram of the heap descriptor at the head of the chunk: + * @verbatim + * MSb LSb + * 7 6 5 4 3 2 1 0 + * pchunk-> +-+-+-+-+-+-+-+-+ S := Size of the chunk (2 LSbs dropped) + * | S |F|R| F := Chunk free bit (not in use) + * +-----------+-+-+ R := Bit reserved for future use + * | S | + * +---------------+ + * | P(L) | P := hd_prev: Pointer to previous node + * | P(H) | N := hd_next: Pointer to next node + * | N(L) | + * | N(H) | + * +---------------+ + * | unused space | + * ... ... + * | end chunk | + * +---------------+ + * @endverbatim + * + * On an 8-bit MCU with 16-bit addresses, the theoretical minimum size of the + * heap descriptor is 6 bytes. The effective size (due to pointer alignment) + * is usually 8 bytes. On an MCU with 32-bit addresses, the heap descriptor's + * size is 12 bytes. + */ +typedef struct PmHeapDesc_s +{ + /** Heap descriptor */ + uint16_t hd; + + /** Ptr to prev heap chunk */ + struct PmHeapDesc_s *prev; + + /** Ptr to next heap chunk */ + struct PmHeapDesc_s *next; +} PmHeapDesc_t, + *pPmHeapDesc_t; + +typedef struct PmHeap_s +{ + /** Pointer to base of heap. Set at initialization of VM */ + uint8_t *base; + + /** Size of the heap. Set at initialization of VM */ + uint32_t size; + + /** Ptr to list of free chunks; sorted smallest to largest. */ + pPmHeapDesc_t pfreelist; + + /** The amount of heap space available in free list */ + uint32_t avail; + +#ifdef HAVE_GC + /** Garbage collection mark value */ + uint8_t gcval; + + /** Boolean to indicate if GC should run automatically */ + uint8_t auto_gc; + + /* #239: Fix GC when 2+ unlinked allocs occur */ + /** Stack of objects to be held as temporary roots */ + pPmObj_t temp_roots[HEAP_NUM_TEMP_ROOTS]; + + uint8_t temp_root_index; +#endif /* HAVE_GC */ + +} PmHeap_t, + *pPmHeap_t; + + +/** The PyMite heap */ +static PmHeap_t pmHeap PM_PLAT_HEAP_ATTR; + + +#if 0 +static void +heap_gcPrintFreelist(void) +{ + pPmHeapDesc_t pchunk = pmHeap.pfreelist; + + printf("DEBUG: pmHeap.avail = %d\n", pmHeap.avail); + printf("DEBUG: freelist:\n"); + while (pchunk != C_NULL) + { + printf("DEBUG: free chunk (%d bytes) @ 0x%0x\n", + CHUNK_GET_SIZE(pchunk), (int)pchunk); + pchunk = pchunk->next; + } +} +#endif + + +#if 0 +/** DEBUG: dumps the heap and roots list to a file */ +static void +heap_dump(void) +{ + static int n = 0; + uint16_t s; + uint32_t i; + char filename[17] = "pmheapdump0N.bin\0"; + FILE *fp; + + filename[11] = '0' + n++; + fp = fopen(filename, "wb"); + + /* magic : PMDUMP for little endian or PMUDMP for big endian */ + fwrite(&"PM", 1, 2, fp); + s = 0x5544; + fwrite(&s, sizeof(uint16_t), 1, fp); + fwrite(&"MP", 1, 2, fp); + + /* pointer size */ + s = sizeof(intptr_t); + fwrite(&s, sizeof(uint16_t), 1, fp); + + /* dump version */ + s = 1; + fwrite(&s, sizeof(uint16_t), 1, fp); + + /* pmfeatures */ + s = 0; +#ifdef USE_STRING_CACHE + s |= 1<<0; +#endif +#ifdef HAVE_DEFAULTARGS + s |= 1<<1; +#endif +#ifdef HAVE_CLOSURES + s |= 1<<2; +#endif +#ifdef HAVE_CLASSES + s |= 1<<3; +#endif + fwrite(&s, sizeof(uint16_t), 1, fp); + + /* Size of heap */ + fwrite(&pmHeap.size, sizeof(uint32_t), 1, fp); + + /* Write base address of heap */ + fwrite((void*)&pmHeap.base, sizeof(intptr_t), 1, fp); + + /* Write contents of heap */ + fwrite(pmHeap.base, 1, pmHeap.size, fp); + + /* Write num roots*/ + i = 10; + fwrite(&i, sizeof(uint32_t), 1, fp); + + /* Write heap root ptrs */ + fwrite((void *)&gVmGlobal.pnone, sizeof(intptr_t), 1, fp); + fwrite((void *)&gVmGlobal.pfalse, sizeof(intptr_t), 1, fp); + fwrite((void *)&gVmGlobal.ptrue, sizeof(intptr_t), 1, fp); + fwrite((void *)&gVmGlobal.pzero, sizeof(intptr_t), 1, fp); + fwrite((void *)&gVmGlobal.pone, sizeof(intptr_t), 1, fp); + fwrite((void *)&gVmGlobal.pnegone, sizeof(intptr_t), 1, fp); + fwrite((void *)&gVmGlobal.pcodeStr, sizeof(intptr_t), 1, fp); + fwrite((void *)&gVmGlobal.builtins, sizeof(intptr_t), 1, fp); + fwrite((void *)&gVmGlobal.nativeframe, sizeof(intptr_t), 1, fp); + fwrite((void *)&gVmGlobal.threadList, sizeof(intptr_t), 1, fp); + fclose(fp); +} +#endif + + +/* Removes the given chunk from the free list; leaves list in sorted order */ +static PmReturn_t +heap_unlinkFromFreelist(pPmHeapDesc_t pchunk) +{ + C_ASSERT(pchunk != C_NULL); + + pmHeap.avail -= CHUNK_GET_SIZE(pchunk); + + if (pchunk->next != C_NULL) + { + pchunk->next->prev = pchunk->prev; + } + + /* If pchunk was the first chunk in the free list, update the heap ptr */ + if (pchunk->prev == C_NULL) + { + pmHeap.pfreelist = pchunk->next; + } + else + { + pchunk->prev->next = pchunk->next; + } + + return PM_RET_OK; +} + + +/* Inserts in order a chunk into the free list. Caller adjusts heap state */ +static PmReturn_t +heap_linkToFreelist(pPmHeapDesc_t pchunk) +{ + uint16_t size; + pPmHeapDesc_t pscan; + + /* Ensure the object is already free */ + C_ASSERT(OBJ_GET_FREE(pchunk) != 0); + + pmHeap.avail += CHUNK_GET_SIZE(pchunk); + + /* If free list is empty, add to head of list */ + if (pmHeap.pfreelist == C_NULL) + { + pmHeap.pfreelist = pchunk; + pchunk->next = C_NULL; + pchunk->prev = C_NULL; + + return PM_RET_OK; + } + + /* Scan free list for insertion point */ + pscan = pmHeap.pfreelist; + size = CHUNK_GET_SIZE(pchunk); + while ((CHUNK_GET_SIZE(pscan) < size) && (pscan->next != C_NULL)) + { + pscan = pscan->next; + } + + /* + * Insert chunk after the scan chunk (next is NULL). + * This is a slightly rare case where the last chunk in the free list + * is smaller than the chunk being freed. + */ + if (size > CHUNK_GET_SIZE(pscan)) + { + pchunk->next = pscan->next; + pscan->next = pchunk; + pchunk->prev = pscan; + } + + /* Insert chunk before the scan chunk */ + else + { + pchunk->next = pscan; + pchunk->prev = pscan->prev; + + /* If chunk will be first item in free list */ + if (pscan->prev == C_NULL) + { + pmHeap.pfreelist = pchunk; + } + else + { + pscan->prev->next = pchunk; + } + pscan->prev = pchunk; + } + + return PM_RET_OK; +} + + +PmReturn_t +heap_init(uint8_t *base, uint32_t size) +{ + pPmHeapDesc_t pchunk; + uint32_t hs; + uint8_t *adjbase; + + /* Round-up Heap base by the size of the platform pointer */ + adjbase = base + ((sizeof(intptr_t) - 1) & ~(sizeof(intptr_t) - 1)); + pmHeap.base = adjbase; + pmHeap.size = size - (adjbase - base); + +#if __DEBUG__ + /* Fill the heap with a non-NULL value to bring out any heap bugs. */ + sli_memset(pmHeap.base, 0xAA, pmHeap.size); +#endif + + /* Init heap globals */ + pmHeap.pfreelist = C_NULL; + pmHeap.avail = 0; +#ifdef HAVE_GC + pmHeap.gcval = (uint8_t)0; + pmHeap.temp_root_index = (uint8_t)0; + heap_gcSetAuto(C_TRUE); +#endif /* HAVE_GC */ + + pchunk = (pPmHeapDesc_t)pmHeap.base; + hs = pmHeap.size; + + /* #180 Proactively link memory previously lost/neglected at tail of heap */ + if ((hs % HEAP_MAX_FREE_CHUNK_SIZE) < HEAP_MIN_CHUNK_SIZE) + { + OBJ_SET_FREE(pchunk, 1); + CHUNK_SET_SIZE(pchunk, HEAP_MIN_CHUNK_SIZE); + heap_linkToFreelist(pchunk); + hs -= HEAP_MIN_CHUNK_SIZE; + pchunk = (pPmHeapDesc_t)((uint8_t *)pchunk + HEAP_MIN_CHUNK_SIZE); + } + + /* Create as many max-sized chunks as possible in the freelist */ + for (; + hs >= HEAP_MAX_FREE_CHUNK_SIZE; hs -= HEAP_MAX_FREE_CHUNK_SIZE) + { + OBJ_SET_FREE(pchunk, 1); + CHUNK_SET_SIZE(pchunk, HEAP_MAX_FREE_CHUNK_SIZE); + heap_linkToFreelist(pchunk); + pchunk = (pPmHeapDesc_t)((uint8_t *)pchunk + HEAP_MAX_FREE_CHUNK_SIZE); + } + + /* Add any leftover memory to the freelist */ + if (hs >= HEAP_MIN_CHUNK_SIZE) + { + /* Round down to a multiple of four */ + hs = hs & ~3; + OBJ_SET_FREE(pchunk, 1); + CHUNK_SET_SIZE(pchunk, hs); + heap_linkToFreelist(pchunk); + } + + C_DEBUG_PRINT(VERBOSITY_LOW, "heap_init(), id=%p, s=%u\n", + pmHeap.base, (unsigned int)pmHeap.avail); + +#if USE_STRING_CACHE + string_cacheInit(); +#endif + + return PM_RET_OK; +} + + +/** + * Obtains a chunk of memory from the free list + * + * Performs the Best Fit algorithm. + * Iterates through the freelist to see if a chunk of suitable size exists. + * Shaves a chunk to perfect size iff the remainder is greater than + * the minimum chunk size. + * + * @param size Requested chunk size + * @param r_pchunk Return ptr to chunk + * @return Return status + */ +static PmReturn_t +heap_getChunkImpl(uint16_t size, uint8_t **r_pchunk) +{ + PmReturn_t retval; + pPmHeapDesc_t pchunk; + pPmHeapDesc_t premainderChunk; + + C_ASSERT(r_pchunk != C_NULL); + + /* Skip to the first chunk that can hold the requested size */ + pchunk = pmHeap.pfreelist; + while ((pchunk != C_NULL) && (CHUNK_GET_SIZE(pchunk) < size)) + { + pchunk = pchunk->next; + } + + /* No chunk of appropriate size was found, raise OutOfMemory exception */ + if (pchunk == C_NULL) + { + *r_pchunk = C_NULL; + PM_RAISE(retval, PM_RET_EX_MEM); + return retval; + } + + /* Remove the chunk from the free list */ + retval = heap_unlinkFromFreelist(pchunk); + PM_RETURN_IF_ERROR(retval); + + /* Check if a chunk should be carved from what is available */ + if (CHUNK_GET_SIZE(pchunk) - size >= HEAP_MIN_CHUNK_SIZE) + { + /* Create the heap descriptor for the remainder chunk */ + premainderChunk = (pPmHeapDesc_t)((uint8_t *)pchunk + size); + OBJ_SET_FREE(premainderChunk, 1); + CHUNK_SET_SIZE(premainderChunk, CHUNK_GET_SIZE(pchunk) - size); + + /* Put the remainder chunk back in the free list */ + retval = heap_linkToFreelist(premainderChunk); + PM_RETURN_IF_ERROR(retval); + + /* Convert the chunk from a heap descriptor to an object descriptor */ + OBJ_SET_SIZE(pchunk, 0); + OBJ_SET_FREE(pchunk, 0); + OBJ_SET_SIZE(pchunk, size); + + C_DEBUG_PRINT(VERBOSITY_HIGH, + "heap_getChunkImpl()carved, id=%p, s=%d\n", pchunk, + size); + } + else + { + /* Set chunk's type to none (overwrites size field's high byte) */ + OBJ_SET_TYPE((pPmObj_t)pchunk, OBJ_TYPE_NON); + OBJ_SET_FREE(pchunk, 0); + + C_DEBUG_PRINT(VERBOSITY_HIGH, + "heap_getChunkImpl()exact, id=%p, s=%d\n", pchunk, + PM_OBJ_GET_SIZE(pchunk)); + } + + /* + * Set the chunk's GC mark so it will be collected during the next GC cycle + * if it is not reachable + */ + OBJ_SET_GCVAL(pchunk, pmHeap.gcval); + + /* Return the chunk */ + *r_pchunk = (uint8_t *)pchunk; + + return retval; +} + + +/* + * Allocates chunk of memory. + * Filters out invalid sizes. + * Rounds the size up to the next multiple of the platform pointer size. + * Obtains a chunk of at least the desired size. + */ +PmReturn_t +heap_getChunk(uint16_t requestedsize, uint8_t **r_pchunk) +{ + PmReturn_t retval; + uint16_t adjustedsize; + + /* Ensure size request is valid */ + if (requestedsize > HEAP_MAX_LIVE_CHUNK_SIZE) + { + PM_RAISE(retval, PM_RET_EX_MEM); + return retval; + } + + else if (requestedsize < HEAP_MIN_CHUNK_SIZE) + { + requestedsize = HEAP_MIN_CHUNK_SIZE; + } + + /* + * Round up the size to a multiple of N bytes, + * where N is 8 for 64-bit platforms and 4 for all else. + * This maintains pointer alignment in the heap (required). + */ +#ifdef PM_PLAT_POINTER_SIZE +#if PM_PLAT_POINTER_SIZE == 8 + adjustedsize = ((requestedsize + 7) & ~7); +#else + adjustedsize = ((requestedsize + 3) & ~3); +#endif /* PM_PLAT_POINTER_SIZE */ +#else + adjustedsize = ((requestedsize + 3) & ~3); +#endif /* PM_PLAT_POINTER_SIZE */ + + /* Attempt to get a chunk */ + retval = heap_getChunkImpl(adjustedsize, r_pchunk); + +#ifdef HAVE_GC + /* Perform GC if out of memory, gc is enabled and not in native session */ + if ((retval == PM_RET_EX_MEM) && (pmHeap.auto_gc == C_TRUE) + && (gVmGlobal.nativeframe.nf_active == C_FALSE)) + { + retval = heap_gcRun(); + PM_RETURN_IF_ERROR(retval); + + /* Attempt to get a chunk */ + retval = heap_getChunkImpl(adjustedsize, r_pchunk); + } +#endif /* HAVE_GC */ + + /* Ensure that the pointer is N-byte aligned */ + if (retval == PM_RET_OK) + { +#ifdef PM_PLAT_POINTER_SIZE +#if PM_PLAT_POINTER_SIZE == 8 + C_ASSERT(((intptr_t)*r_pchunk & 7) == 0); +#else + C_ASSERT(((intptr_t)*r_pchunk & 3) == 0); +#endif /* PM_PLAT_POINTER_SIZE */ +#else + C_ASSERT(((intptr_t)*r_pchunk & 3) == 0); +#endif /* PM_PLAT_POINTER_SIZE */ + } + + return retval; +} + + +/* Releases chunk to the free list */ +PmReturn_t +heap_freeChunk(pPmObj_t ptr) +{ + PmReturn_t retval; + + C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_freeChunk(), id=%p, s=%d\n", + ptr, PM_OBJ_GET_SIZE(ptr)); + + /* Ensure the chunk falls within the heap */ + C_ASSERT(((uint8_t *)ptr >= &pmHeap.base[0]) + && ((uint8_t *)ptr <= &pmHeap.base[pmHeap.size])); + + /* Insert the chunk into the freelist */ + OBJ_SET_FREE(ptr, 1); + + /* Clear type so that heap descriptor's size's upper byte is zero */ + OBJ_SET_TYPE(ptr, 0); + retval = heap_linkToFreelist((pPmHeapDesc_t)ptr); + PM_RETURN_IF_ERROR(retval); + + return retval; +} + + +uint32_t +heap_getAvail(void) +{ + return pmHeap.avail; +} + + +uint32_t +heap_getSize(void) +{ + return pmHeap.size; +} + + +#ifdef HAVE_GC +/* + * Marks the given object and the objects it references. + * + * @param pobj Any non-free heap object + * @return Return code + */ +static PmReturn_t +heap_gcMarkObj(pPmObj_t pobj) +{ + PmReturn_t retval = PM_RET_OK; + int16_t i = 0; + int16_t n; + PmType_t type; + + /* Return if ptr is null or object is already marked */ + if (pobj == C_NULL) + { + return retval; + } + if (OBJ_GET_GCVAL(pobj) == pmHeap.gcval) + { + return retval; + } + + /* The pointer must be within the heap (native frame is special case) */ + C_ASSERT((((uint8_t *)pobj >= &pmHeap.base[0]) + && ((uint8_t *)pobj <= &pmHeap.base[pmHeap.size])) + || ((uint8_t *)pobj == (uint8_t *)&gVmGlobal.nativeframe)); + + /* The object must not already be free */ + C_ASSERT(OBJ_GET_FREE(pobj) == 0); + + type = (PmType_t)OBJ_GET_TYPE(pobj); + switch (type) + { + /* Objects with no references to other objects */ + case OBJ_TYPE_NON: + case OBJ_TYPE_INT: + case OBJ_TYPE_FLT: + case OBJ_TYPE_STR: + case OBJ_TYPE_NOB: + case OBJ_TYPE_BOOL: + case OBJ_TYPE_CIO: + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + break; + + case OBJ_TYPE_TUP: + i = ((pPmTuple_t)pobj)->length; + + /* Mark tuple head */ + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + /* Mark each obj in tuple */ + while (--i >= 0) + { + retval = heap_gcMarkObj(((pPmTuple_t)pobj)->val[i]); + PM_RETURN_IF_ERROR(retval); + } + break; + + case OBJ_TYPE_LST: + + /* Mark the list */ + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + /* Mark the seglist */ + retval = heap_gcMarkObj((pPmObj_t)((pPmList_t)pobj)->val); + break; + + case OBJ_TYPE_DIC: + /* Mark the dict head */ + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + /* Mark the keys seglist */ + retval = heap_gcMarkObj((pPmObj_t)((pPmDict_t)pobj)->d_keys); + PM_RETURN_IF_ERROR(retval); + + /* Mark the vals seglist */ + retval = heap_gcMarkObj((pPmObj_t)((pPmDict_t)pobj)->d_vals); + break; + + case OBJ_TYPE_COB: + /* Mark the code obj head */ + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + /* Mark the names tuple */ + retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_names); + PM_RETURN_IF_ERROR(retval); + + /* Mark the consts tuple */ + retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_consts); + PM_RETURN_IF_ERROR(retval); + + /* #122: Mark the code image if it is in RAM */ + if (((pPmCo_t)pobj)->co_memspace == MEMSPACE_RAM) + { + retval = heap_gcMarkObj((pPmObj_t) + (((pPmCo_t)pobj)->co_codeimgaddr)); + PM_RETURN_IF_ERROR(retval); + } + +#ifdef HAVE_CLOSURES + /* #256: Add support for closures */ + /* Mark the cellvars tuple */ + retval = heap_gcMarkObj((pPmObj_t)((pPmCo_t)pobj)->co_cellvars); +#endif /* HAVE_CLOSURES */ + break; + + case OBJ_TYPE_MOD: + case OBJ_TYPE_FXN: + /* Module and Func objs are implemented via the PmFunc_t */ + /* Mark the func obj head */ + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + /* Mark the code obj */ + retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_co); + PM_RETURN_IF_ERROR(retval); + + /* Mark the attr dict */ + retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_attrs); + PM_RETURN_IF_ERROR(retval); + + /* Mark the globals dict */ + retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_globals); + PM_RETURN_IF_ERROR(retval); + +#ifdef HAVE_DEFAULTARGS + /* Mark the default args tuple */ + retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_defaultargs); + PM_RETURN_IF_ERROR(retval); +#endif /* HAVE_DEFAULTARGS */ + +#ifdef HAVE_CLOSURES + /* #256: Mark the closure tuple */ + retval = heap_gcMarkObj((pPmObj_t)((pPmFunc_t)pobj)->f_closure); +#endif /* HAVE_CLOSURES */ + break; + +#ifdef HAVE_CLASSES + case OBJ_TYPE_CLI: + /* Mark the obj head */ + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + /* Mark the class */ + retval = heap_gcMarkObj((pPmObj_t)((pPmInstance_t)pobj)->cli_class); + PM_RETURN_IF_ERROR(retval); + + /* Mark the attrs dict */ + retval = heap_gcMarkObj((pPmObj_t)((pPmInstance_t)pobj)->cli_attrs); + break; + + case OBJ_TYPE_MTH: + /* Mark the obj head */ + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + /* Mark the instance */ + retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_instance); + PM_RETURN_IF_ERROR(retval); + + /* Mark the func */ + retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_func); + PM_RETURN_IF_ERROR(retval); + + /* Mark the attrs dict */ + retval = heap_gcMarkObj((pPmObj_t)((pPmMethod_t)pobj)->m_attrs); + break; + + case OBJ_TYPE_CLO: + /* Mark the obj head */ + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + /* Mark the attrs dict */ + retval = heap_gcMarkObj((pPmObj_t)((pPmClass_t)pobj)->cl_attrs); + PM_RETURN_IF_ERROR(retval); + + /* Mark the base tuple */ + retval = heap_gcMarkObj((pPmObj_t)((pPmClass_t)pobj)->cl_bases); + break; +#endif /* HAVE_CLASSES */ + + /* + * An obj in ram should not be of these types. + * Images arrive in RAM as string objects (image is array of bytes) + */ + case OBJ_TYPE_CIM: + case OBJ_TYPE_NIM: + PM_RAISE(retval, PM_RET_EX_SYS); + return retval; + + case OBJ_TYPE_FRM: + { + pPmObj_t *ppobj2 = C_NULL; + + /* Mark the frame obj head */ + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + /* Mark the previous frame, if this isn't a generator's frame */ + /* Issue #129: Fix iterator losing its object */ + if ((((pPmFrame_t)pobj)->fo_func->f_co->co_flags & CO_GENERATOR) == 0) + { + retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_back); + PM_RETURN_IF_ERROR(retval); + } + + /* Mark the fxn obj */ + retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_func); + PM_RETURN_IF_ERROR(retval); + + /* Mark the blockstack */ + retval = heap_gcMarkObj((pPmObj_t) + ((pPmFrame_t)pobj)->fo_blockstack); + PM_RETURN_IF_ERROR(retval); + + /* Mark the attrs dict */ + retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_attrs); + PM_RETURN_IF_ERROR(retval); + + /* Mark the globals dict */ + retval = heap_gcMarkObj((pPmObj_t)((pPmFrame_t)pobj)->fo_globals); + PM_RETURN_IF_ERROR(retval); + + /* Mark each obj in the locals list and the stack */ + ppobj2 = ((pPmFrame_t)pobj)->fo_locals; + while (ppobj2 < ((pPmFrame_t)pobj)->fo_sp) + { + retval = heap_gcMarkObj(*ppobj2); + PM_RETURN_IF_ERROR(retval); + ppobj2++; + } + break; + } + + case OBJ_TYPE_BLK: + /* Mark the block obj head */ + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + /* Mark the next block in the stack */ + retval = heap_gcMarkObj((pPmObj_t)((pPmBlock_t)pobj)->next); + break; + + case OBJ_TYPE_SGL: + /* Mark the seglist obj head */ + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + /* Mark the seglist's segments */ + n = ((pSeglist_t)pobj)->sl_length; + pobj = (pPmObj_t)((pSeglist_t)pobj)->sl_rootseg; + for (i = 0; i < n; i++) + { + /* Mark the segment item */ + retval = heap_gcMarkObj(((pSegment_t)pobj)->s_val[i % SEGLIST_OBJS_PER_SEG]); + PM_RETURN_IF_ERROR(retval); + + /* Mark the segment obj head */ + if ((i % SEGLIST_OBJS_PER_SEG) == 0) + { + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + } + + /* Point to the next segment */ + else + if ((i % SEGLIST_OBJS_PER_SEG) == (SEGLIST_OBJS_PER_SEG - 1)) + { + pobj = (pPmObj_t)((pSegment_t)pobj)->next; + if (pobj == C_NULL) + { + break; + } + } + } + break; + + case OBJ_TYPE_SQI: + /* Mark the sequence iterator obj head */ + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + /* Mark the sequence */ + retval = heap_gcMarkObj(((pPmSeqIter_t)pobj)->si_sequence); + break; + + case OBJ_TYPE_THR: + /* Mark the thread obj head */ + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + /* Mark the current frame */ + retval = heap_gcMarkObj((pPmObj_t)((pPmThread_t)pobj)->pframe); + break; + + case OBJ_TYPE_NFM: + /* + * Mark the obj desc. This doesn't really do much since the + * native frame is declared static (not from the heap), but this + * is here in case that ever changes + */ + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + /* Mark the native frame's remaining fields if active */ + if (gVmGlobal.nativeframe.nf_active) + { + /* Mark the frame stack */ + retval = heap_gcMarkObj((pPmObj_t) + gVmGlobal.nativeframe.nf_back); + PM_RETURN_IF_ERROR(retval); + + /* Mark the function object */ + retval = heap_gcMarkObj((pPmObj_t) + gVmGlobal.nativeframe.nf_func); + PM_RETURN_IF_ERROR(retval); + + /* Mark the stack object */ + retval = heap_gcMarkObj(gVmGlobal.nativeframe.nf_stack); + PM_RETURN_IF_ERROR(retval); + + /* Mark the args to the native func */ + for (i = 0; i < NATIVE_GET_NUM_ARGS(); i++) + { + retval = + heap_gcMarkObj(gVmGlobal.nativeframe.nf_locals[i]); + PM_RETURN_IF_ERROR(retval); + } + } + break; + +#ifdef HAVE_BYTEARRAY + case OBJ_TYPE_BYA: + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + + retval = heap_gcMarkObj((pPmObj_t)((pPmBytearray_t)pobj)->val); + break; + + case OBJ_TYPE_BYS: + OBJ_SET_GCVAL(pobj, pmHeap.gcval); + break; +#endif /* HAVE_BYTEARRAY */ + + default: + /* There should be no invalid types */ + PM_RAISE(retval, PM_RET_EX_SYS); + break; + } + return retval; +} + + +/* + * Marks the root objects so they won't be collected during the sweep phase. + * Recursively marks all objects reachable from the roots. + */ +static PmReturn_t +heap_gcMarkRoots(void) +{ + PmReturn_t retval; + uint8_t i; + + /* Toggle the GC marking value so it differs from the last run */ + pmHeap.gcval ^= 1; + + /* Mark the constant objects */ + retval = heap_gcMarkObj(PM_NONE); + PM_RETURN_IF_ERROR(retval); + retval = heap_gcMarkObj(PM_FALSE); + PM_RETURN_IF_ERROR(retval); + retval = heap_gcMarkObj(PM_TRUE); + PM_RETURN_IF_ERROR(retval); + retval = heap_gcMarkObj(PM_ZERO); + PM_RETURN_IF_ERROR(retval); + retval = heap_gcMarkObj(PM_ONE); + PM_RETURN_IF_ERROR(retval); + retval = heap_gcMarkObj(PM_NEGONE); + PM_RETURN_IF_ERROR(retval); + retval = heap_gcMarkObj(PM_CODE_STR); + PM_RETURN_IF_ERROR(retval); + + /* Mark the builtins dict */ + retval = heap_gcMarkObj(PM_PBUILTINS); + PM_RETURN_IF_ERROR(retval); + + /* Mark the native frame if it is active */ + retval = heap_gcMarkObj((pPmObj_t)&gVmGlobal.nativeframe); + PM_RETURN_IF_ERROR(retval); + + /* Mark the thread list */ + retval = heap_gcMarkObj((pPmObj_t)gVmGlobal.threadList); + PM_RETURN_IF_ERROR(retval); + + /* Mark the temporary roots */ + for (i = 0; i < pmHeap.temp_root_index; i++) + { + retval = heap_gcMarkObj(pmHeap.temp_roots[i]); + PM_RETURN_IF_ERROR(retval); + } + + return retval; +} + + +#if USE_STRING_CACHE +/** + * Unlinks free objects from the string cache. + * This function must only be called by the GC after the heap has been marked + * and before the heap has been swept. + * + * This solves the problem where a string object would be collected + * but its chunk was still linked into the free list + * + * @param gcval The current value for chunks marked by the GC + */ +static PmReturn_t +heap_purgeStringCache(uint8_t gcval) +{ + PmReturn_t retval; + pPmString_t *ppstrcache; + pPmString_t pstr; + + /* Update string cache pointer if the first string objs are not marked */ + retval = string_getCache(&ppstrcache); + if (ppstrcache == C_NULL) + { + return retval; + } + while ((*ppstrcache != C_NULL) && (OBJ_GET_GCVAL(*ppstrcache) != gcval)) + { + *ppstrcache = (*ppstrcache)->next; + } + if (*ppstrcache == C_NULL) + { + return retval; + } + + /* Unlink remaining strings that are not marked */ + for (pstr = *ppstrcache; pstr->next != C_NULL;) + { + /* Unlink consecutive non-marked strings */ + while ((pstr->next != C_NULL) && (OBJ_GET_GCVAL(pstr->next) != gcval)) + { + pstr->next = pstr->next->next; + } + + /* If not at end of cache, string must be marked, skip it */ + if (pstr->next != C_NULL) + { + pstr = pstr->next; + } + } + + return retval; +} +#endif + + +/* + * Reclaims any object that does not have a current mark. + * Puts it in the free list. Coalesces all contiguous free chunks. + */ +static PmReturn_t +heap_gcSweep(void) +{ + PmReturn_t retval; + pPmObj_t pobj; + pPmHeapDesc_t pchunk; + uint16_t totalchunksize; + +#if USE_STRING_CACHE + retval = heap_purgeStringCache(pmHeap.gcval); +#endif + + /* Start at the base of the heap */ + pobj = (pPmObj_t)pmHeap.base; + while ((uint8_t *)pobj < &pmHeap.base[pmHeap.size]) + { + /* Skip to the next unmarked or free chunk within the heap */ + while (!OBJ_GET_FREE(pobj) + && (OBJ_GET_GCVAL(pobj) == pmHeap.gcval) + && ((uint8_t *)pobj < &pmHeap.base[pmHeap.size])) + { + pobj = (pPmObj_t)((uint8_t *)pobj + PM_OBJ_GET_SIZE(pobj)); + } + + /* Stop if reached the end of the heap */ + if ((uint8_t *)pobj >= &pmHeap.base[pmHeap.size]) + { + break; + } + + /* Accumulate the sizes of all consecutive unmarked or free chunks */ + totalchunksize = 0; + + /* Coalesce all contiguous free chunks */ + pchunk = (pPmHeapDesc_t)pobj; + while (OBJ_GET_FREE(pchunk) + || (!OBJ_GET_FREE(pchunk) + && (OBJ_GET_GCVAL(pchunk) != pmHeap.gcval))) + { + /* + * If the chunk is already free, unlink it because its size + * is about to change + */ + if (OBJ_GET_FREE(pchunk)) + { + if ((totalchunksize + CHUNK_GET_SIZE(pchunk)) + > HEAP_MAX_FREE_CHUNK_SIZE) + { + break; + } + retval = heap_unlinkFromFreelist(pchunk); + PM_RETURN_IF_ERROR(retval); + } + + /* Otherwise free and reclaim the unmarked chunk */ + else + { + if ((totalchunksize + PM_OBJ_GET_SIZE(pchunk)) + > HEAP_MAX_FREE_CHUNK_SIZE) + { + break; + } + OBJ_SET_TYPE(pchunk, 0); + OBJ_SET_FREE(pchunk, 1); + } + totalchunksize = totalchunksize + CHUNK_GET_SIZE(pchunk); + + C_DEBUG_PRINT(VERBOSITY_HIGH, "heap_gcSweep(), id=%p, s=%d\n", + pchunk, CHUNK_GET_SIZE(pchunk)); + + /* Proceed to the next chunk */ + pchunk = (pPmHeapDesc_t) + ((uint8_t *)pchunk + CHUNK_GET_SIZE(pchunk)); + + /* Stop if it's past the end of the heap */ + if ((uint8_t *)pchunk >= &pmHeap.base[pmHeap.size]) + { + break; + } + } + + /* Set the heap descriptor data */ + OBJ_SET_FREE(pobj, 1); + CHUNK_SET_SIZE(pobj, totalchunksize); + + /* Insert chunk into free list */ + retval = heap_linkToFreelist((pPmHeapDesc_t)pobj); + PM_RETURN_IF_ERROR(retval); + + /* Continue to the next chunk */ + pobj = (pPmObj_t)pchunk; + } + + return PM_RET_OK; +} + + +/* Runs the mark-sweep garbage collector */ +PmReturn_t +heap_gcRun(void) +{ + PmReturn_t retval; + + /* #239: Fix GC when 2+ unlinked allocs occur */ + /* This assertion fails when there are too many objects on the temporary + * root stack and a GC occurs; consider increasing PM_HEAP_NUM_TEMP_ROOTS + */ + C_ASSERT(pmHeap.temp_root_index < HEAP_NUM_TEMP_ROOTS); + + C_DEBUG_PRINT(VERBOSITY_LOW, "heap_gcRun()\n"); + + retval = heap_gcMarkRoots(); + PM_RETURN_IF_ERROR(retval); + + /*heap_dump();*/ + retval = heap_gcSweep(); + /*heap_dump();*/ + return retval; +} + + +/* Enables or disables automatic garbage collection */ +PmReturn_t +heap_gcSetAuto(uint8_t auto_gc) +{ + pmHeap.auto_gc = auto_gc; + return PM_RET_OK; +} + +void heap_gcPushTempRoot(pPmObj_t pobj, uint8_t *r_objid) +{ + if (pmHeap.temp_root_index < HEAP_NUM_TEMP_ROOTS) + { + *r_objid = pmHeap.temp_root_index; + pmHeap.temp_roots[pmHeap.temp_root_index] = pobj; + pmHeap.temp_root_index++; + } + return; +} + + +void heap_gcPopTempRoot(uint8_t objid) +{ + pmHeap.temp_root_index = objid; +} + +#else + +void heap_gcPushTempRoot(pPmObj_t pobj, uint8_t *r_objid) {} +void heap_gcPopTempRoot(uint8_t objid) {} + +#endif /* HAVE_GC */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/heap.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,106 @@ +/* +# 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. +*/ + + +#ifndef __HEAP_H__ +#define __HEAP_H__ + + +/** + * \file + * \brief VM Heap + * + * VM heap header. + */ + + +/** + * The threshold of heap.avail under which the interpreter will run the GC + * just before starting a native session. + */ +#define HEAP_GC_NF_THRESHOLD (512) + + +#ifdef __DEBUG__ +#define DEBUG_PRINT_HEAP_AVAIL(s) \ + do { uint16_t n; heap_getAvail(&n); printf(s "heap avail = %d\n", n); } \ + while (0) +#else +#define DEBUG_PRINT_HEAP_AVAIL(s) +#endif + + +/** + * Initializes the heap for use. + * + * @param base The address where the contiguous heap begins + * @param size The size in bytes (octets) of the given heap. + * @return Return code. + */ +PmReturn_t heap_init(uint8_t *base, uint32_t size); + +/** + * Returns a free chunk from the heap. + * + * The chunk will be at least the requested size. + * The actual size can be found in the return chunk's od.od_size. + * + * @param requestedsize Requested size of the chunk in bytes. + * @param r_pchunk Addr of ptr to chunk (return). + * @return Return code + */ +PmReturn_t heap_getChunk(uint16_t requestedsize, uint8_t **r_pchunk); + +/** + * Places the chunk back in the heap. + * + * @param ptr Pointer to object to free. + */ +PmReturn_t heap_freeChunk(pPmObj_t ptr); + +/** @return Return number of bytes available in the heap */ +uint32_t heap_getAvail(void); + +/** @return Return the size of the heap in bytes */ +uint32_t heap_getSize(void); + +#ifdef HAVE_GC +/** + * Runs the mark-sweep garbage collector + * + * @return Return code + */ +PmReturn_t heap_gcRun(void); + +/** + * Enables (if true) or disables automatic garbage collection + * + * @param bool Value to enable or disable auto GC + * @return Return code + */ +PmReturn_t heap_gcSetAuto(uint8_t auto_gc); + +#endif /* HAVE_GC */ + +/** + * Pushes an object onto the temporary roots stack if there is room + * to protect the objects from a potential garbage collection + * + * @param pobj Object to push onto the roots stack + * @param r_objid By reference; ID to use when popping the object from the stack + */ +void heap_gcPushTempRoot(pPmObj_t pobj, uint8_t *r_objid); + +/** + * Pops from the temporary roots stack all objects upto and including the one + * denoted by the given ID + * + * @param objid ID of object to pop + */ +void heap_gcPopTempRoot(uint8_t objid); + +#endif /* __HEAP_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/img.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,147 @@ +/* +# 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__ 0x07 + + +/** + * \file + * \brief Image routines + * + * Created to eliminate a circular include + * among mem, string and obj. + */ + + +#include "pm.h" + + +/* + * Searches for a module's name in a contiguous array of images + * in the given namespace starting at the given address. + * A module's name is stored in the last index of the names tuple of an image. + */ +static PmReturn_t +img_findInPath(uint8_t *cname, uint16_t cnamelen, PmMemSpace_t memspace, + uint8_t const **paddr) +{ + uint8_t const *imgtop; + PmType_t type; + uint16_t len; + int16_t size = 0; + uint8_t i = 0; + + /* Addr is top of img */ + imgtop = *paddr; + + /* Get img's type byte */ + type = (PmType_t)mem_getByte(memspace, paddr); + + /* Search all sequential images */ + while (type == OBJ_TYPE_CIM) + { + /* Use size field to calc addr of next potential img */ + size = mem_getWord(memspace, paddr); + + /* Point to names tuple */ + *paddr = imgtop + CI_NAMES_FIELD; + + /* Ensure it's a tuple */ + type = (PmType_t)mem_getByte(memspace, paddr); + C_ASSERT(type == OBJ_TYPE_TUP); + + /* Scan to last name in tuple (it's the module's name) */ + i = mem_getByte(memspace, paddr) - (uint8_t)1; + for (; i > 0; i--) + { + /* Ensure obj is a string */ + type = (PmType_t)mem_getByte(memspace, paddr); + C_ASSERT(type == OBJ_TYPE_STR); + + /* Skip the length of the string */ + len = mem_getWord(memspace, paddr); + (*paddr) += len; + } + + /* Ensure it's a string */ + type = (PmType_t)mem_getByte(memspace, paddr); + C_ASSERT(type == OBJ_TYPE_STR); + + /* If strings match, return the address of this image */ + if ((cnamelen == mem_getWord(memspace, paddr)) + && (PM_RET_OK == mem_cmpn(cname, cnamelen, memspace, paddr))) + { + *paddr = imgtop; + return PM_RET_OK; + } + + /* Calc imgtop for next iteration */ + imgtop += size; + + /* Point to next potential img */ + *paddr = imgtop; + + /* Check if another img follows this one */ + type = (PmType_t)mem_getByte(memspace, paddr); + } + return PM_RET_NO; +} + + +PmReturn_t +img_findInPaths(pPmObj_t pname, PmMemSpace_t *r_memspace, + uint8_t const **r_imgaddr) +{ + uint8_t i; + PmReturn_t retval = PM_RET_NO; + + /* Search in each path in the paths */ + for (i = 0; i < gVmGlobal.imgPaths.pathcount; i++) + { + *r_imgaddr = gVmGlobal.imgPaths.pimg[i]; + *r_memspace = gVmGlobal.imgPaths.memspace[i]; + retval = img_findInPath(((pPmString_t)pname)->val, + ((pPmString_t)pname)->length, + *r_memspace, r_imgaddr); + if (retval == PM_RET_NO) + { + continue; + } + else if (retval == PM_RET_OK) + { + break; + } + else + { + return retval; + } + } + + return retval; +} + + +PmReturn_t +img_appendToPath(PmMemSpace_t memspace, uint8_t const * const paddr) +{ + uint8_t i; + + if (gVmGlobal.imgPaths.pathcount >= PM_NUM_IMG_PATHS) + { + return PM_RET_NO; + } + + i = gVmGlobal.imgPaths.pathcount; + + gVmGlobal.imgPaths.memspace[i] = memspace; + gVmGlobal.imgPaths.pimg[i] = paddr; + gVmGlobal.imgPaths.pathcount++; + + return PM_RET_OK; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/img.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,75 @@ +/* +# 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. +*/ + + +#ifndef __IMG_H__ +#define __IMG_H__ + + +/** + * \file + * \brief Image header + * + * Created to eliminate a circular include + * among mem, string and obj. + */ + + +/** The maximum number of paths available in PmImgPaths */ +#define PM_NUM_IMG_PATHS 4 + + +typedef struct PmImgPaths_s +{ + PmMemSpace_t memspace[PM_NUM_IMG_PATHS]; + uint8_t const *pimg[PM_NUM_IMG_PATHS]; + uint8_t pathcount; +} +PmImgPaths_t, *pPmImgPaths_t; + + +/** + * Code image object + * + * A type to hold code images in the heap. + * A code image with an object descriptor at the front. + * Used for storing image objects during ipm; + * the code object keeps a reference to this object. + */ +typedef struct PmCodeImgObj_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** Null-term? char array */ + uint8_t val[1]; +} PmCodeImgObj_t, + *pPmCodeImgObj_t; + + +/** + * Iterates over all paths in the paths array until the named module is found. + * Returns the memspace,address of the head of the module. + * + * @param pname Pointer to the name of the desired module + * @param r_memspace Return by reference the memory space of the module + * @param r_imgaddr Return by reference the address of the module's image + * @return Return status + */ +PmReturn_t img_findInPaths(pPmObj_t pname, PmMemSpace_t *r_memspace, + uint8_t const **r_imgaddr); + +/** + * Appends the given memspace and address to the image path array + * + * @param memspace The memspace + * @param paddr The address + * @return Return status + */ +PmReturn_t img_appendToPath(PmMemSpace_t memspace, uint8_t const * const paddr); + +#endif /* __IMG_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/int.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,272 @@ +/* +# 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__ 0x08 + + +/** + * \file + * \brief Integer Object Type + * + * Integer object type operations. + */ + +#include <limits.h> + +#include "pm.h" + + +PmReturn_t +int_dup(pPmObj_t pint, pPmObj_t *r_pint) +{ + PmReturn_t retval = PM_RET_OK; + + /* Allocate new int */ + retval = heap_getChunk(sizeof(PmInt_t), (uint8_t **)r_pint); + PM_RETURN_IF_ERROR(retval); + + /* Copy value */ + OBJ_SET_TYPE(*r_pint, OBJ_TYPE_INT); + ((pPmInt_t)*r_pint)->val = ((pPmInt_t)pint)->val; + return retval; +} + + +PmReturn_t +int_new(int32_t n, pPmObj_t *r_pint) +{ + PmReturn_t retval = PM_RET_OK; + + /* If n is 0,1,-1, return static int objects from global struct */ + if (n == 0) + { + *r_pint = PM_ZERO; + return PM_RET_OK; + } + if (n == 1) + { + *r_pint = PM_ONE; + return PM_RET_OK; + } + if (n == -1) + { + *r_pint = PM_NEGONE; + return PM_RET_OK; + } + + /* Else create and return new int obj */ + retval = heap_getChunk(sizeof(PmInt_t), (uint8_t **)r_pint); + PM_RETURN_IF_ERROR(retval); + OBJ_SET_TYPE(*r_pint, OBJ_TYPE_INT); + ((pPmInt_t)*r_pint)->val = n; + return retval; +} + + +PmReturn_t +int_positive(pPmObj_t pobj, pPmObj_t *r_pint) +{ + PmReturn_t retval; + + /* Raise TypeError if obj is not an int */ + if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Create new int obj */ + return int_new(((pPmInt_t)pobj)->val, r_pint); +} + + +PmReturn_t +int_negative(pPmObj_t pobj, pPmObj_t *r_pint) +{ + PmReturn_t retval; + + /* Raise TypeError if obj is not an int */ + if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Create new int obj */ + return int_new(-((pPmInt_t)pobj)->val, r_pint); +} + + +PmReturn_t +int_bitInvert(pPmObj_t pobj, pPmObj_t *r_pint) +{ + PmReturn_t retval; + + /* Raise TypeError if obj is not an int */ + if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Create new int obj */ + return int_new(~((pPmInt_t)pobj)->val, r_pint); +} + + +PmReturn_t +int_print(pPmObj_t pint) +{ + PmReturn_t retval = PM_RET_OK; + uint8_t buf[12]; + + C_ASSERT(pint != C_NULL); + + /* Raise TypeError if obj is not an int */ + if (OBJ_GET_TYPE(pint) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + retval = sli_ltoa10(((pPmInt_t)pint)->val, buf, sizeof(buf)); + PM_RETURN_IF_ERROR(retval); + sli_puts(buf); + + return retval; +} + + +PmReturn_t +int_printHex(pPmObj_t pint) +{ + uint8_t buf[9]; + PmReturn_t retval = PM_RET_OK; + + C_ASSERT(OBJ_GET_TYPE(pint) == OBJ_TYPE_INT); + + /* Print the integer object */ + retval = sli_ltoa16(((pPmInt_t)pint)->val, buf, sizeof(buf), 1); + sli_puts(buf); + return retval; +} + + +PmReturn_t +int_pow(pPmObj_t px, pPmObj_t py, pPmObj_t *r_pn) +{ + int32_t x; + int32_t y; + int32_t n; + PmReturn_t retval; + + /* Raise TypeError if args aren't ints */ + if ((OBJ_GET_TYPE(px) != OBJ_TYPE_INT) + || (OBJ_GET_TYPE(py) != OBJ_TYPE_INT)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + x = ((pPmInt_t)px)->val; + y = ((pPmInt_t)py)->val; + + /* Raise Value error if exponent is negative */ + if (y < 0) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + + /* Calculate x raised to y */ + n = 1; + while (y > 0) + { + n = n * x; + y--; + } + retval = int_new(n, r_pn); + + return retval; +} + + +PmReturn_t +int_divmod(pPmObj_t px, pPmObj_t py, uint8_t op, pPmObj_t *r_pxopy) +{ + int32_t x; + int32_t y; + int32_t xdivy; + int32_t xmody; + int32_t xopy; + PmReturn_t retval = PM_RET_OK; + + /* Raise TypeError if args aren't ints */ + if ((OBJ_GET_TYPE(px) != OBJ_TYPE_INT) + || (OBJ_GET_TYPE(py) != OBJ_TYPE_INT)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + x = ((pPmInt_t)px)->val; + y = ((pPmInt_t)py)->val; + + /* Raise ZeroDivisionError if denominator is zero */ + if (y == 0) + { + PM_RAISE(retval, PM_RET_EX_ZDIV); + return retval; + } + + /* Issue #167: Make overflow silent until exceptions can be caught */ + /* (-sys.maxint-1)/-1 is the only overflow case. */ + /* TODO: enable the overflow for Issue #169 */ + /* + if ((y == -1) && (op == '/') && (x < 0) + && ((uint32_t)x == (0 - (uint32_t)x))) + { + PM_RAISE(retval, PM_RET_EX_OFLOW); + return retval; + } + */ + + /* Shortcut when denominator is one or negative one */ + if (y == 1) + { + xdivy = x; + xmody = 0; + } + else if (y == -1) + { + xdivy = -x; + xmody = 0; + } + + else + { + xdivy = x / y; + xmody = x - xdivy * y; + + /* + * If the remainder is non-0 and the signs of x and y differ, + * C89 doesn't define whether xdivy is now the floor or the + * ceiling of the infinitely precise quotient. We want the floor, + * and we have it iff the remainder's sign matches y's. + */ + if ((xmody != 0) && ((y ^ xmody) < 0)) + { + xmody += y; + --xdivy; + C_ASSERT(xmody && ((y ^ xmody) >= 0)); + } + } + xopy = (op == '/') ? xdivy : xmody; + return int_new(xopy, r_pxopy); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/int.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,129 @@ +/* +# 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. +*/ + + +#ifndef __INT_H__ +#define __INT_H__ + + +/** + * \file + * \brief Integer Object Type + * + * Integer object type header. + */ + +/** + * Integer obj + * + * 32b signed integer + */ +typedef struct PmInt_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** Integer value */ + int32_t val; +} PmInt_t, + *pPmInt_t; + + +/** + * Creates a duplicate Integer object + * + * Created specifically for the index value in FOR_LOOP. + * + * @param pint Pointer to int obj to duplicate. + * @param r_pint Return by ref, ptr to new int + * @return Return status + */ +PmReturn_t int_dup(pPmObj_t pint, pPmObj_t *r_pint); + +/** + * Creates a new Integer object + * + * @param val Value to assign int (signed 32-bit). + * @param r_pint Return by ref, ptr to new int + * @return Return status + */ +PmReturn_t int_new(int32_t val, pPmObj_t *r_pint); + +/** + * Implements the UNARY_POSITIVE bcode. + * + * Creates a new int with the same value as the given int. + * + * @param pobj Pointer to integer object + * @param r_pint Return by reference, ptr to int + * @return Return status + */ +PmReturn_t int_positive(pPmObj_t pobj, pPmObj_t *r_pint); + +/** + * Implements the UNARY_NEGATIVE bcode. + * + * Creates a new int with a value that is the negative of the given int. + * + * @param pobj Pointer to target object + * @param r_pint Return by ref, ptr to int + * @return Return status + */ +PmReturn_t int_negative(pPmObj_t pobj, pPmObj_t *r_pint); + +/** + * Implements the UNARY_INVERT bcode. + * + * Creates a new int with a value that is + * the bitwise inversion of the given int. + * + * @param pobj Pointer to integer to invert + * @param r_pint Return by reference; new integer + * @return Return status + */ +PmReturn_t int_bitInvert(pPmObj_t pobj, pPmObj_t *r_pint); + +#ifdef HAVE_PRINT +/** + * Sends out an integer object in decimal notation with MSB first. + * The number is preceded with a "-" when necessary. + * + * @param pObj Ptr to int object + * @return Return status + */ +PmReturn_t int_print(pPmObj_t pint); + +/** + * Prints the Int object in ascii-coded hexadecimal out the platform output + * + * @param pint Pointer to Int object + */ +PmReturn_t int_printHex(pPmObj_t pint); +#endif /* HAVE_PRINT */ + +/** + * Returns by reference an integer that is x raised to the power of y. + * + * @param px The integer base + * @param py The integer exponent + * @param r_pn Return by reference; New integer with value of x ** y + * @return Return status + */ +PmReturn_t int_pow(pPmObj_t px, pPmObj_t py, pPmObj_t *r_pn); + +/** + * Returns by reference the result of the selected operation. + * + * @param px The integer numerator + * @param py The integer denominator + * @param op The operator selector. '/' selects division, all else is modulus. + * @param r_pn Return by reference; New integer with value of x / y or x % y. + * @return Return status + */ +PmReturn_t int_divmod(pPmObj_t px, pPmObj_t py, uint8_t op, pPmObj_t *r_pxopy); + +#endif /* __INT_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/interp.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,2288 @@ +/* +# 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__ 0x09 + + +/** + * \file + * \brief VM Interpreter + * + * VM interpreter operations. + */ + + +#include "pm.h" + + +PmReturn_t +interpret(const uint8_t returnOnNoThreads) +{ + PmReturn_t retval = PM_RET_OK; + pPmObj_t pobj1 = C_NULL; + pPmObj_t pobj2 = C_NULL; + pPmObj_t pobj3 = C_NULL; + int16_t t16 = 0; + int8_t t8 = 0; + uint8_t bc; + uint8_t objid, objid2; + + /* Activate a thread the first time */ + retval = interp_reschedule(); + PM_RETURN_IF_ERROR(retval); + + /* Interpret loop */ + for (;;) + { + if (gVmGlobal.pthread == C_NULL) + { + if (returnOnNoThreads) + { + /* User chose to return on no threads left */ + return retval; + } + + /* + * Without a frame there is nothing to execute, so reschedule + * (possibly activating a recently added thread). + */ + retval = interp_reschedule(); + PM_BREAK_IF_ERROR(retval); + continue; + } + + /* Reschedule threads if flag is true? */ + if (gVmGlobal.reschedule) + { + retval = interp_reschedule(); + PM_BREAK_IF_ERROR(retval); + } + + /* Get byte; the func post-incrs PM_IP */ + bc = mem_getByte(PM_FP->fo_memspace, &PM_IP); + switch (bc) + { + case POP_TOP: + pobj1 = PM_POP(); + continue; + + case ROT_TWO: + pobj1 = TOS; + TOS = TOS1; + TOS1 = pobj1; + continue; + + case ROT_THREE: + pobj1 = TOS; + TOS = TOS1; + TOS1 = TOS2; + TOS2 = pobj1; + continue; + + case DUP_TOP: + pobj1 = TOS; + PM_PUSH(pobj1); + continue; + + case ROT_FOUR: + pobj1 = TOS; + TOS = TOS1; + TOS1 = TOS2; + TOS2 = TOS3; + TOS3 = pobj1; + continue; + + case NOP: + continue; + + case UNARY_POSITIVE: + /* Raise TypeError if TOS is not an int */ + if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT) +#ifdef HAVE_FLOAT + && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_FLT) +#endif /* HAVE_FLOAT */ + ) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + + /* When TOS is an int, this is a no-op */ + continue; + + case UNARY_NEGATIVE: +#ifdef HAVE_FLOAT + if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT) + { + retval = float_negative(TOS, &pobj2); + } + else +#endif /* HAVE_FLOAT */ + { + retval = int_negative(TOS, &pobj2); + } + PM_BREAK_IF_ERROR(retval); + TOS = pobj2; + continue; + + case UNARY_NOT: + pobj1 = PM_POP(); + if (obj_isFalse(pobj1)) + { + PM_PUSH(PM_TRUE); + } + else + { + PM_PUSH(PM_FALSE); + } + continue; + +#ifdef HAVE_BACKTICK + /* #244 Add support for the backtick operation (UNARY_CONVERT) */ + case UNARY_CONVERT: + retval = obj_repr(TOS, &pobj3); + PM_BREAK_IF_ERROR(retval); + TOS = pobj3; + continue; +#endif /* HAVE_BACKTICK */ + + case UNARY_INVERT: + /* Raise TypeError if it's not an int */ + if (OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + + /* Otherwise perform bit-wise complement */ + retval = int_bitInvert(TOS, &pobj2); + PM_BREAK_IF_ERROR(retval); + TOS = pobj2; + continue; + + case LIST_APPEND: + /* list_append will raise a TypeError if TOS1 is not a list */ + retval = list_append(TOS1, TOS); + PM_SP -= 2; + continue; + + case BINARY_POWER: + case INPLACE_POWER: + +#ifdef HAVE_FLOAT + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT) + || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT)) + { + /* Calculate float power */ + retval = float_op(TOS1, TOS, &pobj3, 'P'); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } +#endif /* HAVE_FLOAT */ + + /* Calculate integer power */ + retval = int_pow(TOS1, TOS, &pobj3); + PM_BREAK_IF_ERROR(retval); + + /* Set return value */ + PM_SP--; + TOS = pobj3; + continue; + + case GET_ITER: +#ifdef HAVE_GENERATORS + /* Raise TypeError if TOS is an instance, but not iterable */ + if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI) + { + retval = class_getAttr(TOS, PM_NEXT_STR, &pobj1); + if (retval != PM_RET_OK) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + } + else +#endif /* HAVE_GENERATORS */ + { + /* Convert sequence to sequence-iterator */ + retval = seqiter_new(TOS, &pobj1); + PM_BREAK_IF_ERROR(retval); + + /* Put sequence-iterator on top of stack */ + TOS = pobj1; + } + continue; + + case BINARY_MULTIPLY: + case INPLACE_MULTIPLY: + /* If both objs are ints, perform the op */ + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT) + && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT)) + { + retval = int_new(((pPmInt_t)TOS1)->val * + ((pPmInt_t)TOS)->val, &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } + +#ifdef HAVE_FLOAT + else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT) + || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT)) + { + retval = float_op(TOS1, TOS, &pobj3, '*'); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } +#endif /* HAVE_FLOAT */ + +#ifdef HAVE_REPLICATION + /* If it's a list replication operation */ + else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT) + && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST)) + { + t16 = (int16_t)((pPmInt_t)TOS)->val; + if (t16 < 0) + { + t16 = 0; + } + + retval = list_replicate(TOS1, t16, &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } + + /* If it's a tuple replication operation */ + else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT) + && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_TUP)) + { + t16 = (int16_t)((pPmInt_t)TOS)->val; + if (t16 < 0) + { + t16 = 0; + } + + retval = tuple_replicate(TOS1, t16, &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } + + /* If it's a string replication operation */ + else if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT) + && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR)) + { + t16 = (int16_t)((pPmInt_t)TOS)->val; + if (t16 < 0) + { + t16 = 0; + } + + pobj2 = TOS1; + pobj2 = (pPmObj_t)&((pPmString_t)pobj2)->val; + retval = string_replicate( + (uint8_t const **)(uint8_t *)&pobj2, t16, &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } +#endif /* HAVE_REPLICATION */ + + /* Otherwise raise a TypeError */ + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + + case BINARY_DIVIDE: + case INPLACE_DIVIDE: + case BINARY_FLOOR_DIVIDE: + case INPLACE_FLOOR_DIVIDE: + +#ifdef HAVE_FLOAT + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT) + || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT)) + { + retval = float_op(TOS1, TOS, &pobj3, '/'); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } +#endif /* HAVE_FLOAT */ + + /* Otherwise perform operation */ + retval = int_divmod(TOS1, TOS, '/', &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + + case BINARY_MODULO: + case INPLACE_MODULO: + +#ifdef HAVE_STRING_FORMAT + /* If it's a string, perform string format */ + if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR) + { + retval = string_format((pPmString_t)TOS1, TOS, &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } +#endif /* HAVE_STRING_FORMAT */ + +#ifdef HAVE_FLOAT + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT) + || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT)) + { + retval = float_op(TOS1, TOS, &pobj3, '%'); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } +#endif /* HAVE_FLOAT */ + + /* Otherwise perform operation */ + retval = int_divmod(TOS1, TOS, '%', &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + + case STORE_MAP: + /* #213: Add support for Python 2.6 bytecodes */ + C_ASSERT(OBJ_GET_TYPE(TOS2) == OBJ_TYPE_DIC); + retval = dict_setItem(TOS2, TOS, TOS1); + PM_BREAK_IF_ERROR(retval); + PM_SP -= 2; + continue; + + case BINARY_ADD: + case INPLACE_ADD: + +#ifdef HAVE_FLOAT + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT) + || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT)) + { + retval = float_op(TOS1, TOS, &pobj3, '+'); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } +#endif /* HAVE_FLOAT */ + + /* If both objs are ints, perform the op */ + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT) + && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT)) + { + retval = int_new(((pPmInt_t)TOS1)->val + + ((pPmInt_t)TOS)->val, &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } + + /* #242: If both objs are strings, perform concatenation */ + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_STR) + && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_STR)) + { + retval = string_concat((pPmString_t)TOS1, + (pPmString_t)TOS, + &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } + + /* Otherwise raise a TypeError */ + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + + case BINARY_SUBTRACT: + case INPLACE_SUBTRACT: + +#ifdef HAVE_FLOAT + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT) + || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT)) + { + retval = float_op(TOS1, TOS, &pobj3, '-'); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } +#endif /* HAVE_FLOAT */ + + /* If both objs are ints, perform the op */ + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT) + && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT)) + { + retval = int_new(((pPmInt_t)TOS1)->val - + ((pPmInt_t)TOS)->val, &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } + + /* Otherwise raise a TypeError */ + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + + case BINARY_SUBSCR: + /* Implements TOS = TOS1[TOS]. */ + + if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC) + { + retval = dict_getItem(TOS1, TOS, &pobj3); + } + else + { + /* Raise a TypeError if index is not an Integer or Bool */ + if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT) + && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + + pobj1 = TOS1; +#ifdef HAVE_BYTEARRAY + /* If object is an instance, get the thing it contains */ + if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLI) + { + retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj1)->cli_attrs, + PM_NONE, + &pobj2); + PM_RETURN_IF_ERROR(retval); + pobj1 = pobj2; + } +#endif /* HAVE_BYTEARRAY */ + + /* Ensure the index doesn't overflow */ + C_ASSERT(((pPmInt_t)TOS)->val <= 0x0000FFFF); + t16 = (int16_t)((pPmInt_t)TOS)->val; + + retval = seq_getSubscript(pobj1, t16, &pobj3); + } + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + +#ifdef HAVE_FLOAT + /* #213: Add support for Python 2.6 bytecodes */ + case BINARY_TRUE_DIVIDE: + case INPLACE_TRUE_DIVIDE: + + /* Perform division; float_op() checks for types and zero-div */ + retval = float_op(TOS1, TOS, &pobj3, '/'); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; +#endif /* HAVE_FLOAT */ + + case SLICE_0: + /* Implements TOS = TOS[:], push a copy of the sequence */ + + /* Create a copy if it is a list */ + if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_LST) + { + retval = list_copy(TOS, &pobj2); + PM_BREAK_IF_ERROR(retval); + + TOS = pobj2; + } + + /* If TOS is an immutable sequence leave it (no op) */ + + /* Raise a TypeError for types that can not be sliced */ + else if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_STR) + && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_TUP)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + continue; + + case STORE_SUBSCR: + /* Implements TOS1[TOS] = TOS2 */ + + /* If it's a list */ + if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST) + { + /* Ensure subscr is an int or bool */ + if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT) + && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + + /* Set the list item */ + retval = list_setItem(TOS1, + (int16_t)(((pPmInt_t)TOS)->val), + TOS2); + PM_BREAK_IF_ERROR(retval); + PM_SP -= 3; + continue; + } + + /* If it's a dict */ + if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC) + { + /* Set the dict item */ + retval = dict_setItem(TOS1, TOS, TOS2); + PM_BREAK_IF_ERROR(retval); + PM_SP -= 3; + continue; + } + +#ifdef HAVE_BYTEARRAY + /* If object is an instance, get the thing it contains */ + if (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_CLI) + { + retval = dict_getItem((pPmObj_t)((pPmInstance_t)TOS1)->cli_attrs, + PM_NONE, + &pobj2); + + /* Raise TypeError if instance isn't a ByteArray */ + if ((retval == PM_RET_EX_KEY) + || (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_BYA)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + PM_BREAK_IF_ERROR(retval); + + /* Ensure subscr is an int or bool */ + if ((OBJ_GET_TYPE(TOS) != OBJ_TYPE_INT) + && (OBJ_GET_TYPE(TOS) != OBJ_TYPE_BOOL)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + + retval = bytearray_setItem(pobj2, + (int16_t)(((pPmInt_t)TOS)->val), + TOS2); + PM_BREAK_IF_ERROR(retval); + PM_SP -= 3; + continue; + } +#endif /* HAVE_BYTEARRAY */ + + /* TypeError for all else */ + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + +#ifdef HAVE_DEL + case DELETE_SUBSCR: + + if ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_LST) + && (OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT)) + { + retval = list_delItem(TOS1, + (int16_t)((pPmInt_t)TOS)->val); + } + + else if ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_DIC) + && (OBJ_GET_TYPE(TOS) <= OBJ_TYPE_HASHABLE_MAX)) + { + retval = dict_delItem(TOS1, TOS); + } + + /* Raise TypeError if obj is not a list or dict */ + else + { + PM_RAISE(retval, PM_RET_EX_TYPE); + } + + PM_BREAK_IF_ERROR(retval); + PM_SP -= 2; + continue; +#endif /* HAVE_DEL */ + + case BINARY_LSHIFT: + case INPLACE_LSHIFT: + /* If both objs are ints, perform the op */ + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT) + && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT)) + { + retval = int_new(((pPmInt_t)TOS1)->val << + ((pPmInt_t)TOS)->val, &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } + + /* Otherwise raise a TypeError */ + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + + case BINARY_RSHIFT: + case INPLACE_RSHIFT: + /* If both objs are ints, perform the op */ + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT) + && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT)) + { + retval = int_new(((pPmInt_t)TOS1)->val >> + ((pPmInt_t)TOS)->val, &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } + + /* Otherwise raise a TypeError */ + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + + case BINARY_AND: + case INPLACE_AND: + /* If both objs are ints, perform the op */ + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT) + && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT)) + { + retval = int_new(((pPmInt_t)TOS1)->val & + ((pPmInt_t)TOS)->val, &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } + + /* Otherwise raise a TypeError */ + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + + case BINARY_XOR: + case INPLACE_XOR: + /* If both objs are ints, perform the op */ + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT) + && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT)) + { + retval = int_new(((pPmInt_t)TOS1)->val ^ + ((pPmInt_t)TOS)->val, &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } + + /* Otherwise raise a TypeError */ + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + + case BINARY_OR: + case INPLACE_OR: + /* If both objs are ints, perform the op */ + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT) + && (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT)) + { + retval = int_new(((pPmInt_t)TOS1)->val | + ((pPmInt_t)TOS)->val, &pobj3); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + TOS = pobj3; + continue; + } + + /* Otherwise raise a TypeError */ + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + +#ifdef HAVE_PRINT + case PRINT_EXPR: + /* Print interactive expression */ + /* Fallthrough */ + + case PRINT_ITEM: + if (gVmGlobal.needSoftSpace && (bc == PRINT_ITEM)) + { + retval = plat_putByte(' '); + PM_BREAK_IF_ERROR(retval); + } + gVmGlobal.needSoftSpace = C_TRUE; + + /* Print out topmost stack element */ + retval = obj_print(TOS, (uint8_t)(bc == PRINT_EXPR), C_FALSE); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + if (bc != PRINT_EXPR) + { + continue; + } + /* If PRINT_EXPR, Fallthrough to print a newline */ + + case PRINT_NEWLINE: + gVmGlobal.needSoftSpace = C_FALSE; + if (gVmGlobal.somethingPrinted) + { + retval = plat_putByte('\n'); + gVmGlobal.somethingPrinted = C_FALSE; + } + PM_BREAK_IF_ERROR(retval); + continue; +#endif /* HAVE_PRINT */ + + case BREAK_LOOP: + { + pPmBlock_t pb1 = PM_FP->fo_blockstack; + + /* Ensure there's a block */ + C_ASSERT(pb1 != C_NULL); + + /* Delete blocks until first loop block */ + while ((pb1->b_type != B_LOOP) && (pb1->next != C_NULL)) + { + pobj2 = (pPmObj_t)pb1; + pb1 = pb1->next; + retval = heap_freeChunk(pobj2); + PM_BREAK_IF_ERROR(retval); + } + + /* Test again outside while loop */ + PM_BREAK_IF_ERROR(retval); + + /* Restore PM_SP */ + PM_SP = pb1->b_sp; + + /* Goto handler */ + PM_IP = pb1->b_handler; + + /* Pop and delete this block */ + PM_FP->fo_blockstack = pb1->next; + retval = heap_freeChunk((pPmObj_t)pb1); + PM_BREAK_IF_ERROR(retval); + } + continue; + + case LOAD_LOCALS: + /* Pushes local attrs dict of current frame */ + /* WARNING: does not copy fo_locals to attrs */ + PM_PUSH((pPmObj_t)PM_FP->fo_attrs); + continue; + + case RETURN_VALUE: + /* Get expiring frame's TOS */ + pobj2 = PM_POP(); + +#if 0 /*__DEBUG__*/ + /* #251: This safety check is disabled because it breaks ipm */ + /* #109: Check that stack should now be empty */ + /* If this is regular frame (not native and not a generator) */ + if ((PM_FP != (pPmFrame_t)(&gVmGlobal.nativeframe)) && + !(PM_FP->fo_func->f_co->co_flags & CO_GENERATOR)) + { + /* An empty stack points one past end of locals */ + t8 = PM_FP->fo_func->f_co->co_nlocals; + C_ASSERT(PM_SP == &(PM_FP->fo_locals[t8])); + } +#endif /* __DEBUG__ */ + + /* Keep ref of expiring frame */ + pobj1 = (pPmObj_t)PM_FP; + C_ASSERT(OBJ_GET_TYPE(pobj1) == OBJ_TYPE_FRM); + + /* If no previous frame, quit thread */ + if (PM_FP->fo_back == C_NULL) + { + gVmGlobal.pthread->interpctrl = INTERP_CTRL_EXIT; + retval = PM_RET_OK; + break; + } + + /* Otherwise return to previous frame */ + PM_FP = PM_FP->fo_back; + +#ifdef HAVE_GENERATORS + /* If returning function was a generator */ + if (((pPmFrame_t)pobj1)->fo_func->f_co->co_flags & CO_GENERATOR) + { + /* Raise a StopIteration exception */ + PM_RAISE(retval, PM_RET_EX_STOP); + break; + } +#endif /* HAVE_GENERATORS */ + +#ifdef HAVE_CLASSES + /* + * If returning function was class initializer + * do not push a return object + */ + if (((pPmFrame_t)pobj1)->fo_isInit) + { + /* Raise TypeError if __init__ did not return None */ + if (pobj2 != PM_NONE) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + } + else +#endif /* HAVE_CLASSES */ + + /* + * Push frame's return val, except if the expiring frame + * was due to an import statement + */ + if (!(((pPmFrame_t)pobj1)->fo_isImport)) + { + PM_PUSH(pobj2); + } + + /* Deallocate expired frame */ + PM_BREAK_IF_ERROR(heap_freeChunk(pobj1)); + continue; + +#ifdef HAVE_IMPORTS + case IMPORT_STAR: + /* #102: Implement the remaining IMPORT_ bytecodes */ + /* Expect a module on the top of the stack */ + C_ASSERT(OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD); + + /* Update PM_FP's attrs with those of the module on the stack */ + retval = dict_update((pPmObj_t)PM_FP->fo_attrs, + (pPmObj_t)((pPmFunc_t)TOS)->f_attrs, + C_TRUE); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + continue; +#endif /* HAVE_IMPORTS */ + +#ifdef HAVE_GENERATORS + case YIELD_VALUE: + /* #207: Add support for the yield keyword */ + /* Get expiring frame's TOS */ + pobj1 = PM_POP(); + + /* Raise TypeError if __init__ did not return None */ + /* (Yield means this is a generator) */ + if ((PM_FP)->fo_isInit) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + + /* Return to previous frame */ + PM_FP = PM_FP->fo_back; + + /* Push yield value onto caller's TOS */ + PM_PUSH(pobj1); + continue; +#endif /* HAVE_GENERATORS */ + + case POP_BLOCK: + /* Get ptr to top block */ + pobj1 = (pPmObj_t)PM_FP->fo_blockstack; + + /* If there's no block, raise SystemError */ + C_ASSERT(pobj1 != C_NULL); + + /* Pop block */ + PM_FP->fo_blockstack = PM_FP->fo_blockstack->next; + + /* Set stack to previous level, jump to code outside block */ + PM_SP = ((pPmBlock_t)pobj1)->b_sp; + PM_IP = ((pPmBlock_t)pobj1)->b_handler; + + PM_BREAK_IF_ERROR(heap_freeChunk(pobj1)); + continue; + +#ifdef HAVE_CLASSES + case BUILD_CLASS: + /* Create and push new class */ + retval = class_new(TOS, TOS1, TOS2, &pobj2); + PM_BREAK_IF_ERROR(retval); + PM_SP -= 2; + TOS = pobj2; + continue; +#endif /* HAVE_CLASSES */ + + + /*************************************************** + * All bytecodes after 90 (0x5A) have a 2-byte arg + * that needs to be swallowed using GET_ARG(). + **************************************************/ + + case STORE_NAME: + /* Get name index */ + t16 = GET_ARG(); + + /* Get key */ + pobj2 = PM_FP->fo_func->f_co->co_names->val[t16]; + + /* Set key=val in current frame's attrs dict */ + retval = dict_setItem((pPmObj_t)PM_FP->fo_attrs, pobj2, TOS); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + continue; + +#ifdef HAVE_DEL + case DELETE_NAME: + /* Get name index */ + t16 = GET_ARG(); + + /* Get key */ + pobj2 = PM_FP->fo_func->f_co->co_names->val[t16]; + + /* Remove key,val pair from current frame's attrs dict */ + retval = dict_delItem((pPmObj_t)PM_FP->fo_attrs, pobj2); + PM_BREAK_IF_ERROR(retval); + continue; +#endif /* HAVE_DEL */ + + case UNPACK_SEQUENCE: + /* Get ptr to sequence */ + pobj1 = PM_POP(); + +#ifdef HAVE_BYTEARRAY + /* If object is an instance, get the thing it contains */ + if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLI) + { + retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj1)->cli_attrs, + PM_NONE, + &pobj2); + PM_RETURN_IF_ERROR(retval); + pobj1 = pobj2; + } +#endif /* HAVE_BYTEARRAY */ + + /* + * Get the length of the sequence; this will + * raise TypeError if obj is not a sequence. + * + * #59: Unpacking to a Dict shall not be supported + */ + retval = seq_getLength(pobj1, (uint16_t *)&t16); + if (retval != PM_RET_OK) + { + GET_ARG(); + break; + } + + /* Raise ValueError if seq length does not match num args */ + if (t16 != GET_ARG()) + { + PM_RAISE(retval, PM_RET_EX_VAL); + break; + } + + /* Push sequence's objs onto stack */ + for (; --t16 >= 0;) + { + retval = seq_getSubscript(pobj1, t16, &pobj2); + PM_BREAK_IF_ERROR(retval); + PM_PUSH(pobj2); + } + + /* Test again outside the for loop */ + PM_BREAK_IF_ERROR(retval); + continue; + + case FOR_ITER: + t16 = GET_ARG(); + +#ifdef HAVE_GENERATORS + /* If TOS is an instance, call next method */ + if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI) + { + /* Get the next() func */ + retval = class_getAttr(TOS, PM_NEXT_STR, &pobj1); + PM_BREAK_IF_ERROR(retval); + + /* Push the func and instance as an arg */ + pobj2 = TOS; + PM_PUSH(pobj1); + PM_PUSH(pobj2); + t16 = 1; + + /* Ensure pobj1 is the func */ + goto CALL_FUNC_FOR_ITER; + } + else +#endif /* HAVE_GENERATORS */ + { + /* Get the next item in the sequence iterator */ + retval = seqiter_getNext(TOS, &pobj2); + } + + /* Catch StopIteration early: pop iterator and break loop */ + if (retval == PM_RET_EX_STOP) + { + PM_SP--; + retval = PM_RET_OK; + PM_IP += t16; + continue; + } + PM_BREAK_IF_ERROR(retval); + + /* Push the next item onto the stack */ + PM_PUSH(pobj2); + continue; + + case STORE_ATTR: + /* TOS.name = TOS1 */ + /* Get names index */ + t16 = GET_ARG(); + + /* Get attrs dict from obj */ + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN) + || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD)) + { + pobj2 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs; + } + +#ifdef HAVE_CLASSES + else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO) + { + pobj2 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs; + } + else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI) + { + pobj2 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs; + } + else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH) + { + pobj2 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs; + } +#endif /* HAVE_CLASSES */ + + /* Other types result in an AttributeError */ + else + { + PM_RAISE(retval, PM_RET_EX_ATTR); + break; + } + + /* If attrs is not a dict, raise SystemError */ + if (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_DIC) + { + PM_RAISE(retval, PM_RET_EX_SYS); + break; + } + + /* Get name/key obj */ + pobj3 = PM_FP->fo_func->f_co->co_names->val[t16]; + + /* Set key=val in obj's dict */ + retval = dict_setItem(pobj2, pobj3, TOS1); + PM_BREAK_IF_ERROR(retval); + PM_SP -= 2; + continue; + +#ifdef HAVE_DEL + case DELETE_ATTR: + /* del TOS.name */ + /* Get names index */ + t16 = GET_ARG(); + + /* Get attrs dict from obj */ + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN) + || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD)) + { + pobj2 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs; + } + +#ifdef HAVE_CLASSES + else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO) + { + pobj2 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs; + } + else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI) + { + pobj2 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs; + } + else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH) + { + pobj2 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs; + } +#endif /* HAVE_CLASSES */ + + /* Other types result in an AttributeError */ + else + { + PM_RAISE(retval, PM_RET_EX_ATTR); + break; + } + + /* If attrs is not a dict, raise SystemError */ + if (OBJ_GET_TYPE(pobj2) != OBJ_TYPE_DIC) + { + PM_RAISE(retval, PM_RET_EX_SYS); + break; + } + + /* Get name/key obj */ + pobj3 = PM_FP->fo_func->f_co->co_names->val[t16]; + + /* Remove key,val from obj's dict */ + retval = dict_delItem(pobj2, pobj3); + + /* Raise an AttributeError if key is not found */ + if (retval == PM_RET_EX_KEY) + { + PM_RAISE(retval, PM_RET_EX_ATTR); + } + + PM_BREAK_IF_ERROR(retval); + PM_SP--; + continue; +#endif /* HAVE_DEL */ + + case STORE_GLOBAL: + /* Get name index */ + t16 = GET_ARG(); + + /* Get key */ + pobj2 = PM_FP->fo_func->f_co->co_names->val[t16]; + + /* Set key=val in global dict */ + retval = dict_setItem((pPmObj_t)PM_FP->fo_globals, pobj2, TOS); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + continue; + +#ifdef HAVE_DEL + case DELETE_GLOBAL: + /* Get name index */ + t16 = GET_ARG(); + + /* Get key */ + pobj2 = PM_FP->fo_func->f_co->co_names->val[t16]; + + /* Remove key,val from globals */ + retval = dict_delItem((pPmObj_t)PM_FP->fo_globals, pobj2); + PM_BREAK_IF_ERROR(retval); + continue; +#endif /* HAVE_DEL */ + + case DUP_TOPX: + t16 = GET_ARG(); + C_ASSERT(t16 <= 3); + + pobj1 = TOS; + pobj2 = TOS1; + pobj3 = TOS2; + if (t16 >= 3) + PM_PUSH(pobj3); + if (t16 >= 2) + PM_PUSH(pobj2); + if (t16 >= 1) + PM_PUSH(pobj1); + continue; + + case LOAD_CONST: + /* Get const's index in CO */ + t16 = GET_ARG(); + + /* Push const on stack */ + PM_PUSH(PM_FP->fo_func->f_co->co_consts->val[t16]); + continue; + + case LOAD_NAME: + /* Get name index */ + t16 = GET_ARG(); + + /* Get name from names tuple */ + pobj1 = PM_FP->fo_func->f_co->co_names->val[t16]; + + /* Get value from frame's attrs dict */ + retval = dict_getItem((pPmObj_t)PM_FP->fo_attrs, pobj1, &pobj2); + if (retval == PM_RET_EX_KEY) + { + /* Get val from globals */ + retval = dict_getItem((pPmObj_t)PM_FP->fo_globals, + pobj1, &pobj2); + + /* Check for name in the builtins module if it is loaded */ + if ((retval == PM_RET_EX_KEY) && (PM_PBUILTINS != C_NULL)) + { + /* Get val from builtins */ + retval = dict_getItem(PM_PBUILTINS, pobj1, &pobj2); + if (retval == PM_RET_EX_KEY) + { + /* Name not defined, raise NameError */ + PM_RAISE(retval, PM_RET_EX_NAME); + break; + } + } + } + PM_BREAK_IF_ERROR(retval); + PM_PUSH(pobj2); + continue; + + case BUILD_TUPLE: + /* Get num items */ + t16 = GET_ARG(); + retval = tuple_new(t16, &pobj1); + PM_BREAK_IF_ERROR(retval); + + /* Fill tuple with ptrs to objs */ + for (; --t16 >= 0;) + { + ((pPmTuple_t)pobj1)->val[t16] = PM_POP(); + } + PM_PUSH(pobj1); + continue; + + case BUILD_LIST: + t16 = GET_ARG(); + retval = list_new(&pobj1); + PM_BREAK_IF_ERROR(retval); + for (; --t16 >= 0;) + { + /* Insert obj into list */ + heap_gcPushTempRoot(pobj1, &objid); + retval = list_insert(pobj1, 0, TOS); + heap_gcPopTempRoot(objid); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + } + /* Test again outside for loop */ + PM_BREAK_IF_ERROR(retval); + + /* push list onto stack */ + PM_PUSH(pobj1); + continue; + + case BUILD_MAP: + /* Argument is ignored */ + t16 = GET_ARG(); + retval = dict_new(&pobj1); + PM_BREAK_IF_ERROR(retval); + PM_PUSH(pobj1); + continue; + + case LOAD_ATTR: + /* Implements TOS.attr */ + t16 = GET_ARG(); + +#ifdef HAVE_AUTOBOX + /* Autobox the object, if necessary */ + retval = class_autobox(&TOS); + PM_BREAK_IF_ERROR(retval); +#endif + + /* Get attrs dict from obj */ + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FXN) || + (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD)) + { + pobj1 = (pPmObj_t)((pPmFunc_t)TOS)->f_attrs; + } + +#ifdef HAVE_CLASSES + else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO) + { + pobj1 = (pPmObj_t)((pPmClass_t)TOS)->cl_attrs; + } + else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI) + { + pobj1 = (pPmObj_t)((pPmInstance_t)TOS)->cli_attrs; + } + else if (OBJ_GET_TYPE(TOS) == OBJ_TYPE_MTH) + { + pobj1 = (pPmObj_t)((pPmMethod_t)TOS)->m_attrs; + } +#endif /* HAVE_CLASSES */ + + /* Other types result in an AttributeError */ + else + { + PM_RAISE(retval, PM_RET_EX_ATTR); + break; + } + + /* If attrs is not a dict, raise SystemError */ + if (OBJ_GET_TYPE(pobj1) != OBJ_TYPE_DIC) + { + PM_RAISE(retval, PM_RET_EX_SYS); + break; + } + + /* Get name */ + pobj2 = PM_FP->fo_func->f_co->co_names->val[t16]; + + /* Get attr with given name */ + retval = dict_getItem(pobj1, pobj2, &pobj3); + +#ifdef HAVE_CLASSES + /* + * If attr is not found and object is a class or instance, + * try to get the attribute from the class attrs or parent(s) + */ + if ((retval == PM_RET_EX_KEY) && + ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLO) + || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI))) + { + retval = class_getAttr(TOS, pobj2, &pobj3); + } +#endif /* HAVE_CLASSES */ + + /* Raise an AttributeError if key is not found */ + if (retval == PM_RET_EX_KEY) + { + PM_RAISE(retval, PM_RET_EX_ATTR); + } + PM_BREAK_IF_ERROR(retval); + +#ifdef HAVE_CLASSES + /* If obj is an instance and attr is a func, create method */ + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_CLI) && + (OBJ_GET_TYPE(pobj3) == OBJ_TYPE_FXN)) + { + pobj2 = pobj3; + retval = class_method(TOS, pobj2, &pobj3); + PM_BREAK_IF_ERROR(retval); + } +#endif /* HAVE_CLASSES */ + + /* Put attr on the stack */ + TOS = pobj3; + continue; + + case COMPARE_OP: + retval = PM_RET_OK; + t16 = GET_ARG(); + +#ifdef HAVE_FLOAT + if ((OBJ_GET_TYPE(TOS) == OBJ_TYPE_FLT) + || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_FLT)) + { + retval = float_compare(TOS1, TOS, &pobj3, (PmCompare_t)t16); + PM_SP--; + TOS = pobj3; + continue; + } +#endif /* HAVE_FLOAT */ + + /* Handle all integer-to-integer (or bool) comparisons */ + if (((OBJ_GET_TYPE(TOS) == OBJ_TYPE_INT) + || (OBJ_GET_TYPE(TOS) == OBJ_TYPE_BOOL)) + && ((OBJ_GET_TYPE(TOS1) == OBJ_TYPE_INT) + || (OBJ_GET_TYPE(TOS1) == OBJ_TYPE_BOOL))) + { + int32_t a = ((pPmInt_t)TOS1)->val; + int32_t b = ((pPmInt_t)TOS)->val; + + switch (t16) + { + /* *INDENT-OFF* */ + case COMP_LT: t8 = (int8_t)(a < b); break; + case COMP_LE: t8 = (int8_t)(a <= b); break; + case COMP_EQ: t8 = (int8_t)(a == b); break; + case COMP_NE: t8 = (int8_t)(a != b); break; + case COMP_GT: t8 = (int8_t)(a > b); break; + case COMP_GE: t8 = (int8_t)(a >= b); break; + case COMP_IS: t8 = (int8_t)(TOS == TOS1); break; + case COMP_IS_NOT: t8 = (int8_t)(TOS != TOS1);break; + case COMP_IN: + case COMP_NOT_IN: + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + + default: + /* Other compares are not yet supported */ + PM_RAISE(retval, PM_RET_EX_SYS); + break; + /* *INDENT-ON* */ + } + PM_BREAK_IF_ERROR(retval); + pobj3 = (t8) ? PM_TRUE : PM_FALSE; + } + + /* Handle non-integer comparisons */ + else + { + retval = PM_RET_OK; + switch (t16) + { + case COMP_EQ: + case COMP_NE: + /* Handle equality for non-int types */ + pobj3 = PM_FALSE; + t8 = obj_compare(TOS, TOS1); + if (((t8 == C_SAME) && (t16 == COMP_EQ)) + || ((t8 == C_DIFFER) && (t16 == COMP_NE))) + { + pobj3 = PM_TRUE; + } + break; + + case COMP_IN: + case COMP_NOT_IN: + /* Handle membership comparisons */ + pobj3 = PM_FALSE; + retval = obj_isIn(TOS, TOS1); + if (retval == PM_RET_OK) + { + if (t16 == COMP_IN) + { + pobj3 = PM_TRUE; + } + } + else if (retval == PM_RET_NO) + { + retval = PM_RET_OK; + if (t16 == COMP_NOT_IN) + { + pobj3 = PM_TRUE; + } + } + break; + + case COMP_IS: + pobj3 = (TOS == TOS1) ? PM_TRUE : PM_FALSE; + break; + + case COMP_IS_NOT: + pobj3 = (TOS != TOS1) ? PM_TRUE : PM_FALSE; + break; + + default: + /* Other comparisons are not implemented */ + PM_RAISE(retval, PM_RET_EX_SYS); + break; + } + PM_BREAK_IF_ERROR(retval); + } + PM_SP--; + TOS = pobj3; + continue; + + case IMPORT_NAME: + /* Get name index */ + t16 = GET_ARG(); + + /* Get name String obj */ + pobj1 = PM_FP->fo_func->f_co->co_names->val[t16]; + + /* Pop unused None object */ + PM_SP--; + + /* Ensure "level" is -1; no support for relative import yet */ + C_ASSERT(obj_compare(TOS, PM_NEGONE) == C_SAME); + + /* #178: Fix import so modules are reused */ + /* Return the module if found in the modules dict (cache) */ + retval = dict_getItem(PM_PBUILTINS, PM_MD_STR, &pobj3); + PM_BREAK_IF_ERROR(retval); + retval = dict_getItem(pobj3, pobj1, &pobj2); + if (retval == PM_RET_OK) + { + TOS = pobj2; + continue; + } + if (retval != PM_RET_EX_KEY) + { + break; + } + + /* Load module from image */ + retval = mod_import(pobj1, &pobj2); + PM_BREAK_IF_ERROR(retval); + + /* #178: Fix import so modules are reused */ + /* + * Store the module's attrs/globals under the module's name + * in the global module dict (cache) + */ + heap_gcPushTempRoot(pobj2, &objid); + retval = dict_setItem(pobj3, pobj1, pobj2); + heap_gcPopTempRoot(objid); + PM_BREAK_IF_ERROR(retval); + + /* Put Module on top of stack */ + TOS = pobj2; + + /* Code after here is a duplicate of CALL_FUNCTION */ + /* Make frame object to interpret the module's root code */ + heap_gcPushTempRoot(pobj2, &objid); + retval = frame_new(pobj2, &pobj3); + heap_gcPopTempRoot(objid); + PM_BREAK_IF_ERROR(retval); + + /* No arguments to pass */ + + /* Keep ref to current frame */ + ((pPmFrame_t)pobj3)->fo_back = PM_FP; + + /* Handle to have None popped on return */ + ((pPmFrame_t)pobj3)->fo_isImport = (uint8_t)1; + + /* Set new frame */ + PM_FP = (pPmFrame_t)pobj3; + continue; + +#ifdef HAVE_IMPORTS + case IMPORT_FROM: + /* #102: Implement the remaining IMPORT_ bytecodes */ + /* Expect the module on the top of the stack */ + C_ASSERT(OBJ_GET_TYPE(TOS) == OBJ_TYPE_MOD); + pobj1 = TOS; + + /* Get the name of the object to import */ + t16 = GET_ARG(); + pobj2 = PM_FP->fo_func->f_co->co_names->val[t16]; + + /* Get the object from the module's attributes */ + retval = dict_getItem((pPmObj_t)((pPmFunc_t)pobj1)->f_attrs, + pobj2, &pobj3); + PM_BREAK_IF_ERROR(retval); + + /* Push the object onto the top of the stack */ + PM_PUSH(pobj3); + continue; +#endif /* HAVE_IMPORTS */ + + case JUMP_FORWARD: + t16 = GET_ARG(); + PM_IP += t16; + continue; + + case JUMP_IF_FALSE: + t16 = GET_ARG(); + if (obj_isFalse(TOS)) + { + PM_IP += t16; + } + continue; + + case JUMP_IF_TRUE: + t16 = GET_ARG(); + if (!obj_isFalse(TOS)) + { + PM_IP += t16; + } + continue; + + case JUMP_ABSOLUTE: + case CONTINUE_LOOP: + /* Get target offset (bytes) */ + t16 = GET_ARG(); + + /* Jump to base_ip + arg */ + PM_IP = PM_FP->fo_func->f_co->co_codeaddr + t16; + continue; + + case LOAD_GLOBAL: + /* Get name */ + t16 = GET_ARG(); + pobj1 = PM_FP->fo_func->f_co->co_names->val[t16]; + + /* Try globals first */ + retval = dict_getItem((pPmObj_t)PM_FP->fo_globals, + pobj1, &pobj2); + + /* If that didn't work, try builtins */ + if (retval == PM_RET_EX_KEY) + { + retval = dict_getItem(PM_PBUILTINS, pobj1, &pobj2); + + /* No such global, raise NameError */ + if (retval == PM_RET_EX_KEY) + { + PM_RAISE(retval, PM_RET_EX_NAME); + break; + } + } + PM_BREAK_IF_ERROR(retval); + PM_PUSH(pobj2); + continue; + + case SETUP_LOOP: + { + uint8_t *pchunk; + + /* Get block span (bytes) */ + t16 = GET_ARG(); + + /* Create block */ + retval = heap_getChunk(sizeof(PmBlock_t), &pchunk); + PM_BREAK_IF_ERROR(retval); + pobj1 = (pPmObj_t)pchunk; + OBJ_SET_TYPE(pobj1, OBJ_TYPE_BLK); + + /* Store current stack pointer */ + ((pPmBlock_t)pobj1)->b_sp = PM_SP; + + /* Default handler is to exit block/loop */ + ((pPmBlock_t)pobj1)->b_handler = PM_IP + t16; + ((pPmBlock_t)pobj1)->b_type = B_LOOP; + + /* Insert block into blockstack */ + ((pPmBlock_t)pobj1)->next = PM_FP->fo_blockstack; + PM_FP->fo_blockstack = (pPmBlock_t)pobj1; + continue; + } + + case LOAD_FAST: + t16 = GET_ARG(); + PM_PUSH(PM_FP->fo_locals[t16]); + continue; + + case STORE_FAST: + t16 = GET_ARG(); + PM_FP->fo_locals[t16] = PM_POP(); + continue; + +#ifdef HAVE_DEL + case DELETE_FAST: + t16 = GET_ARG(); + PM_FP->fo_locals[t16] = PM_NONE; + continue; +#endif /* HAVE_DEL */ + +#ifdef HAVE_ASSERT + case RAISE_VARARGS: + t16 = GET_ARG(); + + /* Only supports taking 1 arg for now */ + if (t16 != 1) + { + PM_RAISE(retval, PM_RET_EX_SYS); + break; + } + + /* Load Exception class from builtins */ + retval = dict_getItem(PM_PBUILTINS, PM_EXCEPTION_STR, &pobj2); + if (retval != PM_RET_OK) + { + PM_RAISE(retval, PM_RET_EX_SYS); + break; + } + + /* Raise TypeError if TOS is not an instance of Exception */ + pobj1 = TOS; + if ((OBJ_GET_TYPE(pobj1) != OBJ_TYPE_CLO) + || !class_isSubclass(pobj1, pobj2)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + + /* Push the traceback, parameter and exception object */ + TOS = PM_NONE; + PM_PUSH(PM_NONE); + PM_PUSH(pobj1); + + /* Get the exception's code attr */ + retval = dict_getItem((pPmObj_t)((pPmClass_t)pobj1)->cl_attrs, + PM_CODE_STR, &pobj2); + PM_BREAK_IF_ERROR(retval); + + /* Raise exception by breaking with retval set to code */ + PM_RAISE(retval, (PmReturn_t)(((pPmInt_t)pobj2)->val & 0xFF)); + break; +#endif /* HAVE_ASSERT */ + + case CALL_FUNCTION: + /* Get num args */ + t16 = GET_ARG(); + + /* Ensure no keyword args */ + if ((t16 & (uint16_t)0xFF00) != 0) + { + PM_RAISE(retval, PM_RET_EX_SYS); + break; + } + + /* Get the callable */ + pobj1 = STACK(t16); + + /* Useless push to get temp-roots stack level used in cleanup */ + heap_gcPushTempRoot(pobj1, &objid); + + C_DEBUG_PRINT(VERBOSITY_LOW, + "interpret(), CALL_FUNCTION on <obj type=%d @ %p>\n", + OBJ_GET_TYPE(pobj1), pobj1); + +#ifdef HAVE_GENERATORS + /* If the callable is a generator function (can't be native) */ + if ((OBJ_GET_TYPE(pobj1) == OBJ_TYPE_FXN) + && (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) == OBJ_TYPE_COB) + && (((pPmFunc_t)pobj1)->f_co->co_flags & CO_GENERATOR)) + { +#ifdef HAVE_DEFAULTARGS + /* Num required args := argcount - num default args */ + t8 = ((pPmFunc_t)pobj1)->f_co->co_argcount; + if (((pPmFunc_t)pobj1)->f_defaultargs != C_NULL) + { + t8 -= ((pPmTuple_t)((pPmFunc_t)pobj1)->f_defaultargs)-> + length; + } + + /* + * Raise a TypeError if num args passed + * is more than allowed or less than required + */ + if (((t16 & ((uint8_t)0xFF)) + > ((pPmFunc_t)pobj1)->f_co->co_argcount) + || ((t16 & ((uint8_t)0xFF)) < t8)) +#else + if ((t16 & ((uint8_t)0xFF)) != + ((pPmFunc_t)pobj1)->f_co->co_argcount) +#endif /* HAVE_DEFAULTARGS */ + { + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + + /* Collect the function and arguments into a tuple */ + retval = tuple_new(t16 + 1, &pobj2); + heap_gcPushTempRoot(pobj2, &objid2); + PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP); + sli_memcpy((uint8_t *)&((pPmTuple_t)pobj2)->val, + (uint8_t *)&STACK(t16), + (t16 + 1) * sizeof(pPmObj_t)); + + /* Remove old args, push func/args tuple as one arg */ + PM_SP -= t16; + PM_PUSH(pobj2); + t16 = 1; + + /* Set pobj1 and stack to create an instance of Generator */ + retval = dict_getItem(PM_PBUILTINS, PM_GENERATOR_STR, + &pobj1); + C_ASSERT(retval == PM_RET_OK); + STACK(t16) = pobj1; + } +#endif /* HAVE_GENERATORS */ + +#ifdef HAVE_CLASSES + /* If the callable is a class, create an instance of it */ + if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLO) + { + /* This marks that the original callable was a class */ + bc = 0; + + /* Replace class with new instance */ + retval = class_instantiate(pobj1, &pobj2); + heap_gcPushTempRoot(pobj2, &objid2); + STACK(t16) = pobj2; + + /* If __init__ does not exist */ + pobj3 = C_NULL; + retval = class_getAttr(pobj1, PM_INIT_STR, &pobj3); + if (retval == PM_RET_EX_KEY) + { + /* Raise TypeError if there are args */ + if (t16 > 0) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + goto CALL_FUNC_CLEANUP; + } + + /* Otherwise, continue with instance */ + heap_gcPopTempRoot(objid); + continue; + } + else if (retval != PM_RET_OK) + { + PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP); + } + + /* Slide the arguments up 1 slot in the stack */ + PM_SP++; + for (t8 = 0; t8 < t16; t8++) + { + STACK(t8) = STACK(t8 + 1); + } + + /* Convert __init__ to method, insert it as the callable */ + retval = class_method(pobj2, pobj3, &pobj1); + PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP); + heap_gcPushTempRoot(pobj2, &objid2); + STACK(t16) = pobj1; + /* Fall through to call the method */ + } + + if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_MTH) + { + /* Set the method's func to be the callable */ + STACK(t16) = (pPmObj_t)((pPmMethod_t)pobj1)->m_func; + + /* Slide the arguments up 1 slot in the stack */ + PM_SP++; + for (t8 = 0; t8 < t16; t8++) + { + STACK(t8) = STACK(t8 + 1); + } + + /* Insert instance as "self" arg to the method */ + STACK(t16++) = (pPmObj_t)((pPmMethod_t)pobj1)->m_instance; + + /* Refresh the callable */ + pobj1 = (pPmObj_t)((pPmMethod_t)pobj1)->m_func; + } +#endif /* HAVE_CLASSES */ + +#ifdef HAVE_GENERATORS +CALL_FUNC_FOR_ITER: +#endif /* HAVE_GENERATORS */ + /* Raise a TypeError if object is not callable */ + if (OBJ_GET_TYPE(pobj1) != OBJ_TYPE_FXN) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + goto CALL_FUNC_CLEANUP; + } + + /* If it is a regular func (not native) */ + if (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) == OBJ_TYPE_COB) + { + /* + * #132 Raise TypeError if num args does not match the + * code object's expected argcount + */ + +#ifdef HAVE_DEFAULTARGS + /* Num required args := argcount - num default args */ + t8 = ((pPmFunc_t)pobj1)->f_co->co_argcount; + if (((pPmFunc_t)pobj1)->f_defaultargs != C_NULL) + { + t8 -= ((pPmTuple_t)((pPmFunc_t)pobj1)->f_defaultargs)-> + length; + } + + /* + * Raise a TypeError if num args passed + * is more than allowed or less than required + */ + if (((t16 & ((uint8_t)0xFF)) + > ((pPmFunc_t)pobj1)->f_co->co_argcount) + || ((t16 & ((uint8_t)0xFF)) < t8)) +#else + if ((t16 & ((uint8_t)0xFF)) != + ((pPmFunc_t)pobj1)->f_co->co_argcount) +#endif /* HAVE_DEFAULTARGS */ + { + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + + /* Make frame object to run the func object */ + retval = frame_new(pobj1, &pobj2); + heap_gcPushTempRoot(pobj2, &objid2); + PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP); + +#ifdef HAVE_CLASSES + /* + * If the original callable was a class, indicate that + * the frame is running the initializer so that + * its return object is checked for None and ignored. + */ + if (bc == 0) + { + ((pPmFrame_t)pobj2)->fo_isInit = C_TRUE; + } +#endif /* HAVE_CLASSES */ + +#ifdef HAVE_DEFAULTARGS + /* If this func has default arguments, put them in place */ + if (((pPmFunc_t)pobj1)->f_defaultargs != C_NULL) + { + int8_t i = 0; + + /* Copy default args into the new frame's locals */ + for ( /* t8 set above */ ; + t8 < ((pPmFunc_t)pobj1)->f_co->co_argcount; t8++) + { + ((pPmFrame_t)pobj2)->fo_locals[t8] = + ((pPmTuple_t)((pPmFunc_t)pobj1)-> + f_defaultargs)->val[i++]; + } + } +#endif /* HAVE_DEFAULTARGS */ + + /* Pass args to new frame */ + while (--t16 >= 0) + { + /* + * Pop args from stack right to left, + * since args are pushed left to right, + */ + ((pPmFrame_t)pobj2)->fo_locals[t16] = PM_POP(); + } + +#ifdef HAVE_CLOSURES + /* #256: Add support for closures */ + /* Copy arguments that become cellvars */ + if (((pPmFunc_t)pobj1)->f_co->co_cellvars != C_NULL) + { + for (t8 = 0; + t8 < ((pPmFunc_t)pobj1)->f_co->co_cellvars->length; + t8++) + { + if (((pPmInt_t)((pPmFunc_t)pobj1)-> + f_co->co_cellvars->val[t8])->val >= 0) + { + ((pPmFrame_t)pobj2)->fo_locals[ + ((pPmFunc_t)pobj1)->f_co->co_nlocals + t8] = + ((pPmFrame_t)pobj2)->fo_locals[ + ((pPmInt_t)(((pPmFunc_t)pobj1)-> + f_co->co_cellvars->val[t8]))->val + ]; + } + } + } + + /* Fill frame's freevars with references from closure */ + for (t8 = 0; + t8 < ((pPmFunc_t)pobj1)->f_co->co_nfreevars; + t8++) + { + C_ASSERT(((pPmFunc_t)pobj1)->f_closure != C_NULL); + ((pPmFrame_t)pobj2)->fo_locals[ + ((pPmFunc_t)pobj1)->f_co->co_nlocals + + ((((pPmFunc_t)pobj1)->f_co->co_cellvars == C_NULL) ? 0 : ((pPmFunc_t)pobj1)->f_co->co_cellvars->length) + + t8] = ((pPmFunc_t)pobj1)->f_closure->val[t8]; + } +#endif /* HAVE_CLOSURES */ + + /* Pop func obj */ + pobj3 = PM_POP(); + + /* Keep ref to current frame */ + ((pPmFrame_t)pobj2)->fo_back = PM_FP; + + /* Set new frame */ + PM_FP = (pPmFrame_t)pobj2; + } + + /* If it's native func */ + else if (OBJ_GET_TYPE(((pPmFunc_t)pobj1)->f_co) == + OBJ_TYPE_NOB) + { + /* Set number of locals (arguments) */ + gVmGlobal.nativeframe.nf_numlocals = (uint8_t)t16; + + /* Pop args from stack */ + while (--t16 >= 0) + { + gVmGlobal.nativeframe.nf_locals[t16] = PM_POP(); + } + + /* Set flag, so the GC knows a native session is active */ + gVmGlobal.nativeframe.nf_active = C_TRUE; + +#ifdef HAVE_GC + /* If the heap is low on memory, run the GC */ + if (heap_getAvail() < HEAP_GC_NF_THRESHOLD) + { + retval = heap_gcRun(); + PM_GOTO_IF_ERROR(retval, CALL_FUNC_CLEANUP); + } +#endif /* HAVE_GC */ + + /* Pop the function object */ + PM_SP--; + + /* Get native function index */ + pobj2 = (pPmObj_t)((pPmFunc_t)pobj1)->f_co; + t16 = ((pPmNo_t)pobj2)->no_funcindx; + + /* + * CALL NATIVE FXN: pass caller's frame and numargs + */ + /* Positive index is a stdlib func */ + if (t16 >= 0) + { + retval = std_nat_fxn_table[t16] (&PM_FP); + } + + /* Negative index is a usrlib func */ + else + { + retval = usr_nat_fxn_table[-t16] (&PM_FP); + } + + /* + * RETURN FROM NATIVE FXN + */ + + /* Clear flag, so frame will not be marked by the GC */ + gVmGlobal.nativeframe.nf_active = C_FALSE; + +#ifdef HAVE_CLASSES + /* If class's __init__ called, do not push a return obj */ + if (bc == 0) + { + /* Raise TypeError if returned obj was not None */ + if ((retval == PM_RET_OK) + && (gVmGlobal.nativeframe.nf_stack != PM_NONE)) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + goto CALL_FUNC_CLEANUP; + } + } + else +#endif /* HAVE_CLASSES */ + + /* If the frame pointer was switched, do nothing to TOS */ + if (retval == PM_RET_FRAME_SWITCH) + { + retval = PM_RET_OK; + } + + /* Otherwise, return the result from the native function */ + else + { + PM_PUSH(gVmGlobal.nativeframe.nf_stack); + } + } +CALL_FUNC_CLEANUP: + heap_gcPopTempRoot(objid); + PM_BREAK_IF_ERROR(retval); + continue; + + case MAKE_FUNCTION: + /* Get num default args to fxn */ + t16 = GET_ARG(); + + /* + * The current frame's globals become the function object's + * globals. The current frame is the container object + * of this new function object + */ + retval = func_new(TOS, (pPmObj_t)PM_FP->fo_globals, &pobj2); + PM_BREAK_IF_ERROR(retval); + + /* Put any default args in a tuple */ + if (t16 > 0) + { + +#ifdef HAVE_DEFAULTARGS + heap_gcPushTempRoot(pobj2, &objid); + retval = tuple_new(t16, &pobj3); + heap_gcPopTempRoot(objid); + PM_BREAK_IF_ERROR(retval); + PM_SP--; + while (--t16 >= 0) + { + ((pPmTuple_t)pobj3)->val[t16] = PM_POP(); + } + + /* Set func's default args */ + ((pPmFunc_t)pobj2)->f_defaultargs = (pPmTuple_t)pobj3; +#else + /* Default arguments not configured in pmfeatures.h */ + PM_RAISE(retval, PM_RET_EX_SYS); + break; +#endif /* HAVE_DEFAULTARGS */ + + } + else + { + PM_SP--; + } + + /* Push func obj */ + PM_PUSH(pobj2); + continue; + +#ifdef HAVE_CLOSURES + case MAKE_CLOSURE: + /* Get number of default args */ + t16 = GET_ARG(); + retval = func_new(TOS, (pPmObj_t)PM_FP->fo_globals, &pobj2); + PM_BREAK_IF_ERROR(retval); + + /* Set closure of the new function */ + ((pPmFunc_t)pobj2)->f_closure = (pPmTuple_t)TOS1; + PM_SP -= 2; + + /* Collect any default arguments into tuple */ + if (t16 > 0) + { + heap_gcPushTempRoot(pobj2, &objid); + retval = tuple_new(t16, &pobj3); + heap_gcPopTempRoot(objid); + PM_BREAK_IF_ERROR(retval); + + while (--t16 >= 0) + { + ((pPmTuple_t)pobj3)->val[t16] = PM_POP(); + } + ((pPmFunc_t)pobj2)->f_defaultargs = (pPmTuple_t)pobj3; + } + + /* Push new func with closure */ + PM_PUSH(pobj2); + continue; + + case LOAD_CLOSURE: + case LOAD_DEREF: + /* Loads the i'th cell of free variable storage onto TOS */ + t16 = GET_ARG(); + pobj1 = PM_FP->fo_locals[PM_FP->fo_func->f_co->co_nlocals + t16]; + if (pobj1 == C_NULL) + { + PM_RAISE(retval, PM_RET_EX_SYS); + break; + } + PM_PUSH(pobj1); + continue; + + case STORE_DEREF: + /* Stores TOS into the i'th cell of free variable storage */ + t16 = GET_ARG(); + PM_FP->fo_locals[PM_FP->fo_func->f_co->co_nlocals + t16] = PM_POP(); + continue; +#endif /* HAVE_CLOSURES */ + + + default: + /* SystemError, unknown or unimplemented opcode */ + PM_RAISE(retval, PM_RET_EX_SYS); + break; + } + +#ifdef HAVE_GENERATORS + /* If got a StopIteration exception, check for a B_LOOP block */ + if (retval == PM_RET_EX_STOP) + { + pobj1 = (pPmObj_t)PM_FP; + while ((retval == PM_RET_EX_STOP) && (pobj1 != C_NULL)) + { + pobj2 = (pPmObj_t)((pPmFrame_t)pobj1)->fo_blockstack; + while ((retval == PM_RET_EX_STOP) && (pobj2 != C_NULL)) + { + if (((pPmBlock_t)pobj2)->b_type == B_LOOP) + { + /* Resume execution where the block handler says */ + /* Set PM_FP first, so PM_SP and PM_IP are set in the frame */ + PM_FP = (pPmFrame_t)pobj1; + PM_SP = ((pPmBlock_t)pobj2)->b_sp; + PM_IP = ((pPmBlock_t)pobj2)->b_handler; + ((pPmFrame_t)pobj1)->fo_blockstack = + ((pPmFrame_t)pobj1)->fo_blockstack->next; + retval = PM_RET_OK; + break; + } + + pobj2 = (pPmObj_t)((pPmBlock_t)pobj2)->next; + } + pobj1 = (pPmObj_t)((pPmFrame_t)pobj1)->fo_back; + } + if (retval == PM_RET_OK) + { + continue; + } + } +#endif /* HAVE_GENERATORS */ + + /* + * If execution reaches this point, it is because + * a return value (from above) is not OK or we should exit the thread + * (return of the function). In any case, remove the + * current thread and reschedule. + */ + PM_REPORT_IF_ERROR(retval); + + /* If this is the last thread, return the error code */ + if ((gVmGlobal.threadList->length <= 1) && (retval != PM_RET_OK)) + { + break; + } + + retval = list_remove((pPmObj_t)gVmGlobal.threadList, + (pPmObj_t)gVmGlobal.pthread); + gVmGlobal.pthread = C_NULL; + PM_BREAK_IF_ERROR(retval); + + retval = interp_reschedule(); + PM_BREAK_IF_ERROR(retval); + } + + return retval; +} + + +PmReturn_t +interp_reschedule(void) +{ + PmReturn_t retval = PM_RET_OK; + static uint8_t threadIndex = (uint8_t)0; + pPmObj_t pobj; + + /* If there are no threads in the runnable list, null the active thread */ + if (gVmGlobal.threadList->length == 0) + { + gVmGlobal.pthread = C_NULL; + } + + /* Otherwise, get the next thread in the list (round robin) */ + else + { + if (++threadIndex >= gVmGlobal.threadList->length) + { + threadIndex = (uint8_t)0; + } + retval = list_getItem((pPmObj_t)gVmGlobal.threadList, threadIndex, + &pobj); + gVmGlobal.pthread = (pPmThread_t)pobj; + PM_RETURN_IF_ERROR(retval); + } + + /* Clear flag to indicate a reschedule has occurred */ + interp_setRescheduleFlag(0); + return retval; +} + + +PmReturn_t +interp_addThread(pPmFunc_t pfunc) +{ + PmReturn_t retval; + pPmObj_t pframe; + pPmObj_t pthread; + uint8_t objid1, objid2; + + /* Create a frame for the func */ + retval = frame_new((pPmObj_t)pfunc, &pframe); + PM_RETURN_IF_ERROR(retval); + + /* Create a thread with this new frame */ + heap_gcPushTempRoot(pframe, &objid1); + retval = thread_new(pframe, &pthread); + if (retval != PM_RET_OK) + { + heap_gcPopTempRoot(objid1); + return retval; + } + + /* Add thread to end of list */ + heap_gcPushTempRoot(pthread, &objid2); + retval = list_append((pPmObj_t)gVmGlobal.threadList, pthread); + heap_gcPopTempRoot(objid1); + return retval; +} + + +void +interp_setRescheduleFlag(uint8_t boolean) +{ + gVmGlobal.reschedule = boolean; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/interp.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,316 @@ +/* +# 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. +*/ + + +#ifndef __INTERP_H__ +#define __INTERP_H__ + + +/** + * \file + * \brief VM Interpreter + * + * VM interpreter header. + */ + + +#include "thread.h" + + +#define INTERP_LOOP_FOREVER 0 +#define INTERP_RETURN_ON_NO_THREADS 1 + + +/** Frame pointer ; currently for single thread */ +#define PM_FP (gVmGlobal.pthread->pframe) +/** Instruction pointer */ +#define PM_IP (PM_FP->fo_ip) +/** Argument stack pointer */ +#define PM_SP (PM_FP->fo_sp) + +/** top of stack */ +#define TOS (*(PM_SP - 1)) +/** one under TOS */ +#define TOS1 (*(PM_SP - 2)) +/** two under TOS */ +#define TOS2 (*(PM_SP - 3)) +/** three under TOS */ +#define TOS3 (*(PM_SP - 4)) +/** index into stack; 0 is top, 1 is next */ +#define STACK(n) (*(PM_SP - ((n) + 1))) +/** pops an obj from the stack */ +#define PM_POP() (*(--PM_SP)) +/** pushes an obj on the stack */ +#define PM_PUSH(pobj) (*(PM_SP++) = (pobj)) +/** gets the argument (S16) from the instruction stream */ +#define GET_ARG() mem_getWord(PM_FP->fo_memspace, &PM_IP) + +/** pushes an obj in the only stack slot of the native frame */ +#define NATIVE_SET_TOS(pobj) (gVmGlobal.nativeframe.nf_stack = \ + (pobj)) +/** gets the nth local var from the native frame locals */ +#define NATIVE_GET_LOCAL(n) (gVmGlobal.nativeframe.nf_locals[n]) +/** gets a pointer to the frame that called this native fxn */ +#define NATIVE_GET_PFRAME() (*ppframe) +/** gets the number of args passed to the native fxn */ +#define NATIVE_GET_NUM_ARGS() (gVmGlobal.nativeframe.nf_numlocals) + + +/** + * COMPARE_OP enum. + * Used by the COMPARE_OP bytecode to determine + * which type of compare to perform. + * Must match those defined in Python. + */ +typedef enum PmCompare_e +{ + COMP_LT = 0, /**< less than */ + COMP_LE, /**< less than or equal */ + COMP_EQ, /**< equal */ + COMP_NE, /**< not equal */ + COMP_GT, /**< greater than */ + COMP_GE, /**< greater than or equal */ + COMP_IN, /**< is in */ + COMP_NOT_IN, /**< is not in */ + COMP_IS, /**< is */ + COMP_IS_NOT, /**< is not */ + COMP_EXN_MATCH /**< do exceptions match */ +} PmCompare_t, *pPmCompare_t; + +/** + * Byte code enumeration + */ +typedef enum PmBcode_e +{ + /* + * Python source to create this list: + * import dis + * o = dis.opname + * for i in range(256): + * if o[i][0] != '<': + * print "\t%s," % o[i] + * else: + * print "\tUNUSED_%02X," % i + */ + STOP_CODE = 0, /* 0x00 */ + POP_TOP, + ROT_TWO, + ROT_THREE, + DUP_TOP, + ROT_FOUR, + UNUSED_06, + UNUSED_07, + UNUSED_08, + NOP, + UNARY_POSITIVE, /* d010 */ + UNARY_NEGATIVE, + UNARY_NOT, + UNARY_CONVERT, + UNUSED_0E, + UNARY_INVERT, + UNUSED_10, /* 0x10 */ + UNUSED_11, + LIST_APPEND, + BINARY_POWER, + BINARY_MULTIPLY, /* d020 */ + BINARY_DIVIDE, + BINARY_MODULO, + BINARY_ADD, + BINARY_SUBTRACT, + BINARY_SUBSCR, + BINARY_FLOOR_DIVIDE, + BINARY_TRUE_DIVIDE, + INPLACE_FLOOR_DIVIDE, + INPLACE_TRUE_DIVIDE, + SLICE_0, /* d030 */ + SLICE_1, + SLICE_2, /* 0x20 */ + SLICE_3, + UNUSED_22, + UNUSED_23, + UNUSED_24, + UNUSED_25, + UNUSED_26, + UNUSED_27, + STORE_SLICE_0, /* d040 */ + STORE_SLICE_1, + STORE_SLICE_2, + STORE_SLICE_3, + UNUSED_2C, + UNUSED_2D, + UNUSED_2E, + UNUSED_2F, + UNUSED_30, /* 0x30 */ + UNUSED_31, + DELETE_SLICE_0, /* d050 */ + DELETE_SLICE_1, + DELETE_SLICE_2, + DELETE_SLICE_3, + STORE_MAP, + INPLACE_ADD, + INPLACE_SUBTRACT, + INPLACE_MULTIPLY, + INPLACE_DIVIDE, + INPLACE_MODULO, + STORE_SUBSCR, /* d060 */ + DELETE_SUBSCR, + BINARY_LSHIFT, + BINARY_RSHIFT, + BINARY_AND, /* 0x40 */ + BINARY_XOR, + BINARY_OR, + INPLACE_POWER, + GET_ITER, + UNUSED_45, + PRINT_EXPR, /* d070 */ + PRINT_ITEM, + PRINT_NEWLINE, + PRINT_ITEM_TO, + PRINT_NEWLINE_TO, + INPLACE_LSHIFT, + INPLACE_RSHIFT, + INPLACE_AND, + INPLACE_XOR, + INPLACE_OR, + BREAK_LOOP, /* 0x50 *//* d080 */ + WITH_CLEANUP, + LOAD_LOCALS, + RETURN_VALUE, + IMPORT_STAR, + EXEC_STMT, + YIELD_VALUE, + POP_BLOCK, + END_FINALLY, + BUILD_CLASS, + + /* Opcodes from here have an argument */ + HAVE_ARGUMENT = 90, /* d090 */ + STORE_NAME = 90, + DELETE_NAME, + UNPACK_SEQUENCE, + FOR_ITER, + UNUSED_5E, + STORE_ATTR, + DELETE_ATTR, /* 0x60 */ + STORE_GLOBAL, + DELETE_GLOBAL, + DUP_TOPX, + LOAD_CONST, /* d100 */ + LOAD_NAME, + BUILD_TUPLE, + BUILD_LIST, + BUILD_MAP, + LOAD_ATTR, + COMPARE_OP, + IMPORT_NAME, + IMPORT_FROM, + UNUSED_6D, + JUMP_FORWARD, /* d110 */ + JUMP_IF_FALSE, + JUMP_IF_TRUE, /* 0x70 */ + JUMP_ABSOLUTE, + UNUSED_72, + UNUSED_73, + LOAD_GLOBAL, + UNUSED_75, + UNUSED_76, + CONTINUE_LOOP, + SETUP_LOOP, /* d120 */ + SETUP_EXCEPT, + SETUP_FINALLY, + UNUSED_7B, + LOAD_FAST, + STORE_FAST, + DELETE_FAST, + UNUSED_79, + UNUSED_80, /* 0x80 */ + UNUSED_81, + RAISE_VARARGS, /* d130 */ + CALL_FUNCTION, + MAKE_FUNCTION, + BUILD_SLICE, + MAKE_CLOSURE, + LOAD_CLOSURE, + LOAD_DEREF, + STORE_DEREF, + UNUSED_8A, + UNUSED_8B, + CALL_FUNCTION_VAR, /* d140 */ + CALL_FUNCTION_KW, + CALL_FUNCTION_VAR_KW, + EXTENDED_ARG, + + UNUSED_90, UNUSED_91, UNUSED_92, UNUSED_93, + UNUSED_94, UNUSED_95, UNUSED_96, UNUSED_97, + UNUSED_98, UNUSED_99, UNUSED_9A, UNUSED_9B, + UNUSED_9C, UNUSED_9D, UNUSED_9E, UNUSED_9F, + UNUSED_A0, UNUSED_A1, UNUSED_A2, UNUSED_A3, + UNUSED_A4, UNUSED_A5, UNUSED_A6, UNUSED_A7, + UNUSED_A8, UNUSED_A9, UNUSED_AA, UNUSED_AB, + UNUSED_AC, UNUSED_AD, UNUSED_AE, UNUSED_AF, + UNUSED_B0, UNUSED_B1, UNUSED_B2, UNUSED_B3, + UNUSED_B4, UNUSED_B5, UNUSED_B6, UNUSED_B7, + UNUSED_B8, UNUSED_B9, UNUSED_BA, UNUSED_BB, + UNUSED_BC, UNUSED_BD, UNUSED_BE, UNUSED_BF, + UNUSED_C0, UNUSED_C1, UNUSED_C2, UNUSED_C3, + UNUSED_C4, UNUSED_C5, UNUSED_C6, UNUSED_C7, + UNUSED_C8, UNUSED_C9, UNUSED_CA, UNUSED_CB, + UNUSED_CC, UNUSED_CD, UNUSED_CE, UNUSED_CF, + UNUSED_D0, UNUSED_D1, UNUSED_D2, UNUSED_D3, + UNUSED_D4, UNUSED_D5, UNUSED_D6, UNUSED_D7, + UNUSED_D8, UNUSED_D9, UNUSED_DA, UNUSED_DB, + UNUSED_DC, UNUSED_DD, UNUSED_DE, UNUSED_DF, + UNUSED_E0, UNUSED_E1, UNUSED_E2, UNUSED_E3, + UNUSED_E4, UNUSED_E5, UNUSED_E6, UNUSED_E7, + UNUSED_E8, UNUSED_E9, UNUSED_EA, UNUSED_EB, + UNUSED_EC, UNUSED_ED, UNUSED_EE, UNUSED_EF, + UNUSED_F0, UNUSED_F1, UNUSED_F2, UNUSED_F3, + UNUSED_F4, UNUSED_F5, UNUSED_F6, UNUSED_F7, + UNUSED_F8, UNUSED_F9, UNUSED_FA, UNUSED_FB, + UNUSED_FC, UNUSED_FD, UNUSED_FE, UNUSED_FF +} PmBcode_t, *pPmBcode_t; + + +/** + * Interprets the available threads. Does not return. + * + * @param returnOnNoThreads Loop forever if 0, exit with status if no more + * threads left. + * @return Return status if called with returnOnNoThreads != 0, + * will not return otherwise. + */ +PmReturn_t interpret(const uint8_t returnOnNoThreads); + +/** + * Selects a thread to run and changes the VM internal variables to + * let the switch-loop execute the chosen one in the next iteration. + * For the moment the algorithm is primitive and will change the + * thread each time it is called in a round-robin fashion. + */ +PmReturn_t interp_reschedule(void); + +/** + * Creates a thread object and adds it to the queue of threads to be + * executed while interpret() is running. + * + * The given obj may be a function, module, or class. + * Creates a frame for the given function. + * + * @param pfunc Ptr to function to be executed as a thread. + * @return Return status + */ +PmReturn_t interp_addThread(pPmFunc_t pfunc); + +/** + * Sets the reschedule flag. + * + * @param boolean Reschedule on next occasion if boolean is true; clear + * the flag otherwise. + */ +void interp_setRescheduleFlag(uint8_t boolean); + +#endif /* __INTERP_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/list.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,417 @@ +/* +# 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__ 0x0B + + +/** + * \file + * \brief List Object Type + * + * List object type operations. + */ + + +#include "pm.h" + + +PmReturn_t +list_append(pPmObj_t plist, pPmObj_t pobj) +{ + PmReturn_t retval; + uint8_t objid; + + C_ASSERT(plist != C_NULL); + C_ASSERT(pobj != C_NULL); + + /* If plist is not a list, raise a TypeError exception */ + if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Create new seglist if needed */ + if (((pPmList_t)plist)->length == 0) + { + retval = seglist_new(&((pPmList_t)plist)->val); + PM_RETURN_IF_ERROR(retval); + } + + /* Append object to list */ + heap_gcPushTempRoot((pPmObj_t)((pPmList_t)plist)->val, &objid); + retval = seglist_appendItem(((pPmList_t)plist)->val, pobj); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + + /* Increment list length */ + ((pPmList_t)plist)->length++; + + return retval; +} + + +PmReturn_t +list_getItem(pPmObj_t plist, int16_t index, pPmObj_t *r_pobj) +{ + PmReturn_t retval; + + /* If it's not a list, raise TypeError */ + if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Adjust the index */ + if (index < 0) + { + index += ((pPmList_t)plist)->length; + } + + /* Check the bounds of the index */ + if ((index < 0) || (index >= ((pPmList_t)plist)->length)) + { + PM_RAISE(retval, PM_RET_EX_INDX); + return retval; + } + + /* Get item from seglist */ + retval = seglist_getItem(((pPmList_t)plist)->val, index, r_pobj); + return retval; +} + + +PmReturn_t +list_insert(pPmObj_t plist, int16_t index, pPmObj_t pobj) +{ + PmReturn_t retval; + int16_t len; + uint8_t objid; + + C_ASSERT(plist != C_NULL); + C_ASSERT(pobj != C_NULL); + + /* Raise a TypeError if plist is not a List */ + if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST) + { + retval = PM_RET_EX_TYPE; + PM_RETURN_IF_ERROR(retval); + } + + /* Adjust an out-of-bounds index value */ + len = ((pPmList_t)plist)->length; + if (index < 0) + { + index += len; + } + if (index < 0) + { + index = 0; + } + if (index > len) + { + index = len; + } + + /* Create new seglist if needed */ + if (((pPmList_t)plist)->length == 0) + { + retval = seglist_new(&((pPmList_t)plist)->val); + PM_RETURN_IF_ERROR(retval); + } + + /* Insert the item in the container */ + heap_gcPushTempRoot((pPmObj_t)((pPmList_t)plist)->val, &objid); + retval = seglist_insertItem(((pPmList_t)plist)->val, pobj, index); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + + /* Increment list length */ + ((pPmList_t)plist)->length++; + return retval; +} + + +PmReturn_t +list_new(pPmObj_t *r_pobj) +{ + PmReturn_t retval = PM_RET_OK; + pPmList_t plist = C_NULL; + + /* Allocate a list */ + retval = heap_getChunk(sizeof(PmList_t), (uint8_t **)r_pobj); + PM_RETURN_IF_ERROR(retval); + + /* Set list type, empty the contents */ + plist = (pPmList_t)*r_pobj; + OBJ_SET_TYPE(plist, OBJ_TYPE_LST); + plist->length = 0; + plist->val = C_NULL; + + return retval; +} + + +PmReturn_t +list_copy(pPmObj_t pobj, pPmObj_t *r_pobj) +{ + return list_replicate(pobj, 1, r_pobj); +} + + +PmReturn_t +list_replicate(pPmObj_t psrclist, int16_t n, pPmObj_t *r_pnewlist) +{ + PmReturn_t retval = PM_RET_OK; + int16_t i = 0; + int16_t j = 0; + int16_t length = 0; + pPmObj_t pitem = C_NULL; + uint8_t objid; + + C_ASSERT(psrclist != C_NULL); + C_ASSERT(r_pnewlist != C_NULL); + + /* If first arg is not a list, raise TypeError */ + if (OBJ_GET_TYPE(psrclist) != OBJ_TYPE_LST) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + length = ((pPmList_t)psrclist)->length; + + /* Allocate new list */ + retval = list_new(r_pnewlist); + PM_RETURN_IF_ERROR(retval); + + /* Copy srclist the designated number of times */ + for (i = n; i > 0; i--) + { + /* Iterate over the length of srclist */ + for (j = 0; j < length; j++) + { + retval = list_getItem(psrclist, j, &pitem); + PM_RETURN_IF_ERROR(retval); + heap_gcPushTempRoot(*r_pnewlist, &objid); + retval = list_append(*r_pnewlist, pitem); + heap_gcPopTempRoot(objid); + PM_RETURN_IF_ERROR(retval); + } + } + return retval; +} + + +PmReturn_t +list_setItem(pPmObj_t plist, int16_t index, pPmObj_t pobj) +{ + PmReturn_t retval; + + /* If it's not a list, raise TypeError */ + if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Adjust the index */ + if (index < 0) + { + index += ((pPmList_t)plist)->length; + } + + /* Check the bounds of the index */ + if ((index < 0) || (index >= ((pPmList_t)plist)->length)) + { + PM_RAISE(retval, PM_RET_EX_INDX); + return retval; + } + + /* Set the item */ + retval = seglist_setItem(((pPmList_t)plist)->val, pobj, index); + return retval; +} + + +PmReturn_t +list_remove(pPmObj_t plist, pPmObj_t item) +{ + PmReturn_t retval = PM_RET_OK; + uint16_t index; + + /* If it's not a list, raise TypeError */ + if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Locate the item to remove */ + retval = list_index(plist, item, &index); + PM_RETURN_IF_ERROR(retval); + + /* Remove the item and decrement the list length */ + retval = seglist_removeItem(((pPmList_t)plist)->val, index); + ((pPmList_t)plist)->length--; + + /* Unlink seglist if there are no contents */ + if (((pPmList_t)plist)->length == 0) + { + ((pPmList_t)plist)->val = C_NULL; + } + + return retval; +} + + +PmReturn_t +list_index(pPmObj_t plist, pPmObj_t pitem, uint16_t *r_index) +{ + PmReturn_t retval = PM_RET_OK; + pSeglist_t pseglist; + pPmObj_t pobj; + uint16_t index; + + /* If it's not a list, raise TypeError */ + if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Raise a ValueError if the list is empty */ + if (((pPmList_t)plist)->length == 0) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + + pseglist = ((pPmList_t)plist)->val; + + /* Iterate over the list's contents */ + for (index = 0; index < pseglist->sl_length; index++) + { + retval = seglist_getItem(pseglist, index, &pobj); + PM_RETURN_IF_ERROR(retval); + + /* If the list item matches the given item, return the index */ + if (obj_compare(pobj, pitem) == C_SAME) + { + *r_index = index; + return PM_RET_OK; + } + } + + return PM_RET_EX_VAL; +} + + +PmReturn_t +list_delItem(pPmObj_t plist, int16_t index) +{ + PmReturn_t retval = PM_RET_OK; + + /* If it's not a list, raise TypeError */ + if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Adjust the index */ + if (index < 0) + { + index += ((pPmList_t)plist)->length; + } + + /* Check the bounds of the index */ + if ((index < 0) || (index >= ((pPmList_t)plist)->length)) + { + PM_RAISE(retval, PM_RET_EX_INDX); + return retval; + } + + /* Remove the item and decrement the list length */ + retval = seglist_removeItem(((pPmList_t)plist)->val, index); + ((pPmList_t)plist)->length--; + + /* Unlink seglist if there are no contents */ + if (((pPmList_t)plist)->length == 0) + { + ((pPmList_t)plist)->val = C_NULL; + } + + return retval; +} + + +#ifdef HAVE_PRINT +PmReturn_t +list_print(pPmObj_t plist) +{ + PmReturn_t retval = PM_RET_OK; + int16_t index; + pSeglist_t vals; + pPmObj_t pobj1; + + C_ASSERT(plist != C_NULL); + + /* If it's not a list, raise TypeError */ + if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + plat_putByte('['); + + vals = ((pPmList_t)plist)->val; + + /* Iterate over the list's contents */ + for (index = 0; index < ((pPmList_t)plist)->length; index++) + { + if (index != 0) + { + plat_putByte(','); + plat_putByte(' '); + } + + /* Print each item */ + retval = seglist_getItem(vals, index, &pobj1); + PM_RETURN_IF_ERROR(retval); + retval = obj_print(pobj1, C_FALSE, C_TRUE); + PM_RETURN_IF_ERROR(retval); + } + + return plat_putByte(']'); +} +#endif /* HAVE_PRINT */ + + +PmReturn_t +list_clear(pPmObj_t plist) +{ + PmReturn_t retval = PM_RET_OK; + + C_ASSERT(plist != C_NULL); + + /* Raise TypeError if arg is not a dict */ + if (OBJ_GET_TYPE(plist) != OBJ_TYPE_LST) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Clear length and unlink seglist */ + ((pPmList_t)plist)->length = 0; + ((pPmList_t)plist)->val = C_NULL; + + return retval; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/list.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,168 @@ +/* +# 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. +*/ + + +#ifndef __LIST_H__ +#define __LIST_H__ + +/** + * \file + * \brief List Object Type + * + * List object type header. + */ + +/** + * List obj + * + * Mutable ordered sequence of objects. Contains ptr to linked list of nodes. + */ +typedef struct PmList_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** List length; number of objs linked */ + uint16_t length; + + /** Ptr to linked list of nodes */ + pSeglist_t val; +} PmList_t, + *pPmList_t; + + +/** + * Allocates a new List object. + * + * If there is not enough memory to allocate the List, + * the return status will indicate an OutOfMemoryError + * that must be passed up to the interpreter. + * Otherwise, a ptr to the list is returned by reference + * and the return status is OK. + * + * @param r_pobj Return; addr of ptr to obj + * @return Return status + */ +PmReturn_t list_new(pPmObj_t *r_pobj); + +/** + * Gets the object in the list at the index. + * + * @param plist Ptr to list obj + * @param index Index into list + * @param r_pobj Return by reference; ptr to item + * @return Return status + */ +PmReturn_t list_getItem(pPmObj_t plist, int16_t index, pPmObj_t *r_pobj); + +/** + * Sets the item in the list at the index. + * + * @param plist Ptr to list + * @param index Index into list + * @param pobj Ptr to obj to put into list + * @return Return status + */ +PmReturn_t list_setItem(pPmObj_t plist, int16_t index, pPmObj_t pobj); + +/** + * Makes a copy of the given list. + * + * Allocate the necessary memory for root and nodes. + * Duplicate ptrs to objs. + * + * @param pobj Ptr to source list + * @param r_pobj Return; Addr of ptr to return obj + * @return Return status + */ +PmReturn_t list_copy(pPmObj_t pobj, pPmObj_t *r_pobj); + +/** + * Appends the given obj to the end of the given list. + * + * Allocate the memory for the node. + * Do not copy obj, just reuse ptr. + * + * @param plist Ptr to list + * @param pobj Ptr to item to append + * @return Return status + */ +PmReturn_t list_append(pPmObj_t plist, pPmObj_t pobj); + +/** + * Creates a new list with the contents of psrclist + * copied pint number of times. + * This implements the python code "[0,...] * N" + * where the list can be any list and N is an integer. + * + * @param psrclist The source list to replicate + * @param n The integer number of times to replicate it + * @param r_pnewlist Return; new list with its contents set. + * @return Return status + */ +PmReturn_t list_replicate(pPmObj_t psrclist, int16_t n, pPmObj_t *r_pnewlist); + +/** + * Inserts the object into the list at the desired index. + * + * @param plist Ptr to list obj + * @param pobj Ptr to obj to insert + * @param index Index of where to insert obj + * @return Return status + */ +PmReturn_t list_insert(pPmObj_t plist, int16_t index, pPmObj_t pobj); + +/** + * Removes a given object from the list. + * + * @param plist Ptr to list obj + * @param item Ptr to object to be removed + * @return Return status + */ +PmReturn_t list_remove(pPmObj_t plist, pPmObj_t item); + +/** + * Finds the first index of the item that matches pitem. + * Returns an ValueError Exception if the item is not found. + * + * @param plist Ptr to list obj + * @param pitem Ptr to object to be removed + * @param r_index Return by reference; ptr to index (C uint16) + * @return Return status + */ +PmReturn_t list_index(pPmObj_t plist, pPmObj_t pitem, uint16_t *r_index); + +/** + * Removes the item at the given index. + * Raises a TypeError if the first argument is not a list. + * Raises an IndexError if the index is out of bounds. + * + * @param plist Ptr to list obj + * @param index Index of item to remove + * @return Return status + */ +PmReturn_t list_delItem(pPmObj_t plist, int16_t index); + +#ifdef HAVE_PRINT +/** + * Prints out a list. Uses obj_print() to print elements. + * + * @param pobj Object to print. + * @return Return status + */ +PmReturn_t list_print(pPmObj_t pobj); +#endif /* HAVE_PRINT */ + +/** + * Removes all items from the list and zeroes the length. + * + * @param plist List to clear + * @return Return status + */ +PmReturn_t list_clear(pPmObj_t plist); + +#endif /* __LIST_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/mem.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,147 @@ +/* +# 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__ 0x0D + + +/** + * \file + * \brief VM Memory + * + * VM memory operations. + * Implementations and stubs for getByte and memCopy functions. + * Functions to load object images from static memory. + */ + + +#include "pm.h" + + +uint16_t +mem_getWord(PmMemSpace_t memspace, uint8_t const **paddr) +{ + /* PyMite is little endian; get low byte first */ + uint8_t blo = mem_getByte(memspace, paddr); + uint8_t bhi = mem_getByte(memspace, paddr); + + return (uint16_t)(blo | (bhi << (int8_t)8)); +} + + +uint32_t +mem_getInt(PmMemSpace_t memspace, uint8_t const **paddr) +{ + /* PyMite is little endian; get low word first */ + uint16_t wlo = mem_getWord(memspace, paddr); + uint32_t whi = mem_getWord(memspace, paddr); + + return (uint32_t)(wlo | (whi << (int8_t)16)); +} + + +#ifdef HAVE_FLOAT +float +mem_getFloat(PmMemSpace_t memspace, uint8_t const **paddr) +{ + union + { + char c[4]; + float f; + } + v; + +#ifdef PM_FLOAT_BIG_ENDIAN + /* If the architecture is Big Endian, reverse the bytes of the float */ + v.c[3] = mem_getByte(memspace, paddr); + v.c[2] = mem_getByte(memspace, paddr); + v.c[1] = mem_getByte(memspace, paddr); + v.c[0] = mem_getByte(memspace, paddr); + +#else + v.c[0] = mem_getByte(memspace, paddr); + v.c[1] = mem_getByte(memspace, paddr); + v.c[2] = mem_getByte(memspace, paddr); + v.c[3] = mem_getByte(memspace, paddr); + +#ifndef PM_FLOAT_LITTLE_ENDIAN +#warning Neither PM_FLOAT_LITTLE_ENDIAN nor PM_FLOAT_BIG_ENDIAN is defined \ + for this platform; defaulting to little endian. +#endif +#endif + + return v.f; +} +#endif /* HAVE_FLOAT */ + + +void +mem_copy(PmMemSpace_t memspace, + uint8_t **pdest, uint8_t const **psrc, uint16_t count) +{ + /* Copy memory from RAM */ + if (memspace == MEMSPACE_RAM) + { + sli_memcpy(*pdest, *psrc, count); + *psrc += count; + *pdest += count; + return; + } + + /* Copy memory from non-RAM to RAM */ + else + { + uint8_t b; + + for (; count > 0; count--) + { + b = mem_getByte(memspace, psrc); + **pdest = b; + (*pdest)++; + } + return; + } +} + + +uint16_t +mem_getStringLength(PmMemSpace_t memspace, uint8_t const *const pstr) +{ + uint8_t const *psrc; + + /* If source is in RAM, use a possibly optimized strlen */ + if (memspace == MEMSPACE_RAM) + { + return sli_strlen((char const *)pstr); + } + + /* Otherwise calculate string length */ + psrc = pstr; + while (mem_getByte(memspace, &psrc) != (uint8_t)0); + return psrc - pstr - 1; +} + + +PmReturn_t +mem_cmpn(uint8_t *cname, uint16_t cnamelen, PmMemSpace_t memspace, + uint8_t const **paddr) +{ + uint16_t i; + uint8_t b; + + /* Iterate over all characters */ + for (i = 0; i < cnamelen; i++) + { + b = mem_getByte(memspace, paddr); + if (cname[i] != b) + { + return PM_RET_NO; + } + } + return PM_RET_OK; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/mem.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,131 @@ +/* +# 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. +*/ + + +#ifndef __MEM_H__ +#define __MEM_H__ + + +/** + * \file + * \brief VM Memory + * + * VM memory header. + */ + + +/** + * Memory Space enum. + * + * Defines the different addressable areas of the system. + */ +typedef enum PmMemSpace_e +{ + MEMSPACE_RAM = 0, + MEMSPACE_PROG, + MEMSPACE_EEPROM, + MEMSPACE_SEEPROM, + MEMSPACE_OTHER0, + MEMSPACE_OTHER1, + MEMSPACE_OTHER2, + MEMSPACE_OTHER3 +} PmMemSpace_t, *pPmMemSpace_t; + + +/** + * Returns the byte at the given address in memspace. + * + * Increments the address (just like getc and read(1)) + * to make image loading work (recursive). + * + * @param memspace memory space/type + * @param paddr ptr to address + * @return byte from memory. + * paddr - points to the next byte + */ +#define mem_getByte(memspace, paddr) plat_memGetByte((memspace), (paddr)) + +/** + * Returns the 2-byte word at the given address in memspace. + * + * Word obtained in LITTLE ENDIAN order (per Python convention). + * afterward, addr points one byte past the word. + * + * @param memspace memory space + * @param paddr ptr to address + * @return word from memory. + * addr - points one byte past the word + */ +uint16_t mem_getWord(PmMemSpace_t memspace, uint8_t const **paddr); + +/** + * Returns the 4-byte int at the given address in memspace. + * + * Int obtained in LITTLE ENDIAN order (per Python convention). + * afterward, addr points one byte past the int. + * + * @param memspace memory space + * @param paddr ptr to address + * @return int from memory. + * addr - points one byte past the word + */ +uint32_t mem_getInt(PmMemSpace_t memspace, uint8_t const **paddr); + +#ifdef HAVE_FLOAT +/** + * Returns the 4-byte float at the given address in memspace. + * + * Float obtained in LITTLE ENDIAN order (per Python convention). + * afterward, addr points one byte past the float. + * + * @param memspace memory space + * @param paddr ptr to address + * @return float from memory. + * addr - points one byte past the word + */ +float mem_getFloat(PmMemSpace_t memspace, uint8_t const **paddr); +#endif /* HAVE_FLOAT */ + +/** + * Copies count number of bytes from src in memspace to dest in RAM. + * Leaves dest and src pointing one byte past end of the data. + * + * @param memspace memory space/type of source + * @param pdest ptr to destination address + * @param psrc ptr to source address + * @param count number of bytes to copy + * @return nothing. + * src, dest - point 1 past end of data + * @see sli_memcpy + */ +void mem_copy(PmMemSpace_t memspace, + uint8_t **pdest, uint8_t const **psrc, uint16_t count); + +/** + * Returns the number of bytes in the C string pointed to by pstr. + * Does not modify pstr + * + * @param memspace memory space/type of source + * @param pstr ptr to source C string + * @return Number of bytes in the string. + */ +uint16_t mem_getStringLength(PmMemSpace_t memspace, + uint8_t const *const pstr); + +/** + * Compares a byte array in RAM to a byte array in the given memory space + * + * @param cname Pointer to byte array in RAM + * @param cnamelen Length of byte array to compare + * @param memspace Memory space of other byte array + * @param paddr Pointer to address of other byte array + * @return PM_RET_OK if all bytes in both arrays match; PM_RET_NO otherwise + */ +PmReturn_t mem_cmpn(uint8_t *cname, uint16_t cnamelen, PmMemSpace_t memspace, + uint8_t const **paddr); + +#endif /* __MEM_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/module.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,108 @@ +/* +# 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__ 0x0E + + +/** + * \file + * \brief Module Object Type + * + * Module object type operations. + */ + + +#include "pm.h" + + +PmReturn_t +mod_new(pPmObj_t pco, pPmObj_t *pmod) +{ + PmReturn_t retval; + uint8_t *pchunk; + pPmObj_t pobj; + uint8_t objid; + + /* If it's not a code obj, raise TypeError */ + if (OBJ_GET_TYPE(pco) != OBJ_TYPE_COB) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Alloc and init func obj */ + retval = heap_getChunk(sizeof(PmFunc_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + *pmod = (pPmObj_t)pchunk; + OBJ_SET_TYPE(*pmod, OBJ_TYPE_MOD); + ((pPmFunc_t)*pmod)->f_co = (pPmCo_t)pco; + ((pPmFunc_t)*pmod)->f_attrs = C_NULL; + ((pPmFunc_t)*pmod)->f_globals = C_NULL; + +#ifdef HAVE_DEFAULTARGS + /* Clear the default args (only used by funcs) */ + ((pPmFunc_t)*pmod)->f_defaultargs = C_NULL; +#endif /* HAVE_DEFAULTARGS */ + +#ifdef HAVE_CLOSURES + /* Clear field for closure tuple */ + ((pPmFunc_t)*pmod)->f_closure = C_NULL; +#endif /* HAVE_CLOSURES */ + + /* Alloc and init attrs dict */ + heap_gcPushTempRoot(*pmod, &objid); + retval = dict_new(&pobj); + heap_gcPopTempRoot(objid); + ((pPmFunc_t)*pmod)->f_attrs = (pPmDict_t)pobj; + + /* A module's globals is the same as its attrs */ + ((pPmFunc_t)*pmod)->f_globals = (pPmDict_t)pobj; + + return retval; +} + + +PmReturn_t +mod_import(pPmObj_t pstr, pPmObj_t *pmod) +{ + PmMemSpace_t memspace; + uint8_t const *imgaddr = C_NULL; + pPmCo_t pco = C_NULL; + PmReturn_t retval = PM_RET_OK; + pPmObj_t pobj; + uint8_t objid; + + /* If it's not a string obj, raise SyntaxError */ + if (OBJ_GET_TYPE(pstr) != OBJ_TYPE_STR) + { + PM_RAISE(retval, PM_RET_EX_SYNTAX); + return retval; + } + + /* Try to find the image in the paths */ + retval = img_findInPaths(pstr, &memspace, &imgaddr); + + /* If img was not found, raise ImportError */ + if (retval == PM_RET_NO) + { + PM_RAISE(retval, PM_RET_EX_IMPRT); + return retval; + } + + /* Load img into code obj */ + retval = obj_loadFromImg(memspace, &imgaddr, &pobj); + PM_RETURN_IF_ERROR(retval); + pco = (pPmCo_t)pobj; + + heap_gcPushTempRoot(pobj, &objid); + retval = mod_new((pPmObj_t)pco, pmod); + heap_gcPopTempRoot(objid); + + return retval; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/module.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,47 @@ +/* +# 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. +*/ + + +#ifndef __MODULE_H__ +#define __MODULE_H__ + + +/** + * \file + * \brief Module Object Type + * + * Module object type header. + */ + + +/** + * Creates a Module Obj for the given Code Obj. + * + * Use a func struct to represent the Module obj because + * the module's construction code must execute later, + * but set the type to OBJ_TYPE_MOD so that it is + * not otherwise callable. + * + * @param pco Ptr to code obj + * @param pmod Return by reference; ptr to new module obj + * @return Return status + */ +PmReturn_t mod_new(pPmObj_t pco, pPmObj_t *pmod); + +/** + * Imports a module of the given name. + * Searches for an image with a matching name. + * A code obj is created for the code image. + * A module obj is created for the code obj. + * + * @param pstr String obj containing name of code obj to load. + * @param pmod Return by reference; ptr to imported module + * @return Return status + */ +PmReturn_t mod_import(pPmObj_t pstr, pPmObj_t *pmod); + +#endif /* __MODULE_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/obj.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,471 @@ +/* +# 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__ 0x0F + + +/** + * \file + * \brief Object Type + * + * Object type operations. + */ + + +#include "pm.h" + + +PmReturn_t +obj_loadFromImg(PmMemSpace_t memspace, + uint8_t const **paddr, pPmObj_t *r_pobj) +{ + PmReturn_t retval = PM_RET_OK; + PmObj_t obj; + + + /* Get the object descriptor */ + obj.od = (PmObjDesc_t)0x0000; + OBJ_SET_TYPE(&obj, mem_getByte(memspace, paddr)); + + switch (OBJ_GET_TYPE(&obj)) + { + case OBJ_TYPE_NON: + /* If it's the None object, return global None */ + *r_pobj = PM_NONE; + break; + + case OBJ_TYPE_INT: + /* Read an integer and create an integer object with the value */ + retval = int_new(mem_getInt(memspace, paddr), r_pobj); + break; + +#ifdef HAVE_FLOAT + case OBJ_TYPE_FLT: + /* Read a float and create an float object with the value */ + retval = float_new(mem_getFloat(memspace, paddr), r_pobj); + break; +#endif /* HAVE_FLOAT */ + + case OBJ_TYPE_STR: + retval = string_loadFromImg(memspace, paddr, r_pobj); + break; + + case OBJ_TYPE_TUP: + retval = tuple_loadFromImg(memspace, paddr, r_pobj); + break; + + case OBJ_TYPE_NIM: + /* If it's a native code img, load into a code obj */ + retval = no_loadFromImg(memspace, paddr, r_pobj); + break; + + case OBJ_TYPE_CIM: + /* If it's a code img, load into a code obj */ + retval = co_loadFromImg(memspace, paddr, r_pobj); + break; + + default: + /* All other types should not be in an img obj */ + PM_RAISE(retval, PM_RET_EX_SYS); + break; + } + return retval; +} + + +PmReturn_t +obj_loadFromImgObj(pPmObj_t pimg, pPmObj_t *r_pobj) +{ + uint8_t const *imgaddr; + PmReturn_t retval; + + C_ASSERT(OBJ_GET_TYPE(pimg) == OBJ_TYPE_CIO); + imgaddr = (uint8_t const *)&(((pPmCodeImgObj_t)pimg)->val); + + retval = obj_loadFromImg(MEMSPACE_RAM, &imgaddr, r_pobj); + C_ASSERT(OBJ_GET_TYPE(*r_pobj) == OBJ_TYPE_COB); + + /* All COs must reference the top of the code img obj + * so the image is marked and prevented from being reclaimed */ + co_rSetCodeImgAddr((pPmCo_t)*r_pobj, (uint8_t const *)pimg); + + return retval; +} + + +/* Returns true if the obj is false */ +int8_t +obj_isFalse(pPmObj_t pobj) +{ + C_ASSERT(pobj != C_NULL); + + switch (OBJ_GET_TYPE(pobj)) + { + case OBJ_TYPE_NON: + /* None evaluates to false, so return true */ + return C_TRUE; + + case OBJ_TYPE_INT: + /* Only the integer zero is false */ + return ((pPmInt_t)pobj)->val == 0; + +#ifdef HAVE_FLOAT + case OBJ_TYPE_FLT: + /* The floats 0.0 and -0.0 are false */ + return (((pPmFloat_t) pobj)->val == 0.0) + || (((pPmFloat_t) pobj)->val == -0.0); +#endif /* HAVE_FLOAT */ + + case OBJ_TYPE_STR: + /* An empty string is false */ + return ((pPmString_t)pobj)->length == 0; + + case OBJ_TYPE_TUP: + /* An empty tuple is false */ + return ((pPmTuple_t)pobj)->length == 0; + + case OBJ_TYPE_LST: + /* An empty list is false */ + return ((pPmList_t)pobj)->length == 0; + + case OBJ_TYPE_DIC: + /* An empty dict is false */ + return ((pPmDict_t)pobj)->length == 0; + + case OBJ_TYPE_BOOL: + /* C int zero means false */ + return ((pPmBoolean_t) pobj)->val == 0; + + default: + /* + * The following types are always not false: + * CodeObj, Function, Module, Class, ClassInstance. + */ + return C_FALSE; + } +} + + +/* Returns true if the item is in the container object */ +PmReturn_t +obj_isIn(pPmObj_t pobj, pPmObj_t pitem) +{ + PmReturn_t retval = PM_RET_NO; + pPmObj_t ptestItem; + int16_t i; + uint8_t c; + + switch (OBJ_GET_TYPE(pobj)) + { + case OBJ_TYPE_TUP: + /* Iterate over tuple to find item */ + for (i = 0; i < ((pPmTuple_t)pobj)->length; i++) + { + PM_RETURN_IF_ERROR(tuple_getItem(pobj, i, &ptestItem)); + + if (obj_compare(pitem, ptestItem) == C_SAME) + { + retval = PM_RET_OK; + break; + } + } + break; + + case OBJ_TYPE_STR: + /* Raise a TypeError if item is not a string */ + if ((OBJ_GET_TYPE(pitem) != OBJ_TYPE_STR)) + { + retval = PM_RET_EX_TYPE; + break; + } + + /* Empty string is alway present */ + if (((pPmString_t)pitem)->length == 0) + { + retval = PM_RET_OK; + break; + } + + /* Raise a ValueError if the string is more than 1 char */ + else if (((pPmString_t)pitem)->length != 1) + { + retval = PM_RET_EX_VAL; + break; + } + + /* Iterate over string to find char */ + c = ((pPmString_t)pitem)->val[0]; + for (i = 0; i < ((pPmString_t)pobj)->length; i++) + { + if (c == ((pPmString_t)pobj)->val[i]) + { + retval = PM_RET_OK; + break; + } + } + break; + + case OBJ_TYPE_LST: + /* Iterate over list to find item */ + for (i = 0; i < ((pPmList_t)pobj)->length; i++) + { + PM_RETURN_IF_ERROR(list_getItem(pobj, i, &ptestItem)); + + if (obj_compare(pitem, ptestItem) == C_SAME) + { + retval = PM_RET_OK; + break; + } + } + break; + + case OBJ_TYPE_DIC: + /* Check if the item is one of the keys of the dict */ + retval = dict_getItem(pobj, pitem, &ptestItem); + if (retval == PM_RET_EX_KEY) + { + retval = PM_RET_NO; + } + break; + + default: + retval = PM_RET_EX_TYPE; + break; + } + + return retval; +} + + +int8_t +obj_compare(pPmObj_t pobj1, pPmObj_t pobj2) +{ +#ifdef HAVE_BYTEARRAY + PmReturn_t retval; + pPmObj_t pobj; +#endif /* HAVE_BYTEARRAY */ + + C_ASSERT(pobj1 != C_NULL); + C_ASSERT(pobj2 != C_NULL); + + /* Check if pointers are same */ + if (pobj1 == pobj2) + { + return C_SAME; + } + + /* If types are different, objs must differ */ + if (OBJ_GET_TYPE(pobj1) != OBJ_GET_TYPE(pobj2)) + { + return C_DIFFER; + } + +#ifdef HAVE_BYTEARRAY + /* If object is an instance, get the thing it contains */ + if (OBJ_GET_TYPE(pobj1) == OBJ_TYPE_CLI) + { + retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj1)->cli_attrs, + PM_NONE, + &pobj); + PM_RETURN_IF_ERROR(retval); + pobj1 = pobj; + } + if (OBJ_GET_TYPE(pobj2) == OBJ_TYPE_CLI) + { + retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj2)->cli_attrs, + PM_NONE, + &pobj); + PM_RETURN_IF_ERROR(retval); + pobj2 = pobj; + } + + /* If types are different, objs must differ */ + if (OBJ_GET_TYPE(pobj1) != OBJ_GET_TYPE(pobj2)) + { + return C_DIFFER; + } +#endif /* HAVE_BYTEARRAY */ + + /* Otherwise handle types individually */ + switch (OBJ_GET_TYPE(pobj1)) + { + case OBJ_TYPE_NON: + return C_SAME; + + case OBJ_TYPE_INT: + return ((pPmInt_t)pobj1)->val == + ((pPmInt_t)pobj2)->val ? C_SAME : C_DIFFER; + +#ifdef HAVE_FLOAT + case OBJ_TYPE_FLT: + { + pPmObj_t r_pobj; + + float_compare(pobj1, pobj2, &r_pobj, COMP_EQ); + return (r_pobj == PM_TRUE) ? C_SAME : C_DIFFER; + } +#endif /* HAVE_FLOAT */ + + case OBJ_TYPE_STR: + return string_compare((pPmString_t)pobj1, (pPmString_t)pobj2); + + case OBJ_TYPE_TUP: + case OBJ_TYPE_LST: +#ifdef HAVE_BYTEARRAY + case OBJ_TYPE_BYA: +#endif /* HAVE_BYTEARRAY */ + return seq_compare(pobj1, pobj2); + + case OBJ_TYPE_DIC: + return dict_compare(pobj1, pobj2); + + default: + break; + } + + /* All other types would need same pointer to be true */ + return C_DIFFER; +} + + +#ifdef HAVE_PRINT +PmReturn_t +obj_print(pPmObj_t pobj, uint8_t is_expr_repr, uint8_t is_nested) +{ + PmReturn_t retval = PM_RET_OK; + + C_ASSERT(pobj != C_NULL); + + /* Something gets printed unless it's None in an unnested expression */ + if (!((OBJ_GET_TYPE(pobj) == OBJ_TYPE_NON) && is_expr_repr && !is_nested)) + { + gVmGlobal.somethingPrinted = C_TRUE; + } + + switch (OBJ_GET_TYPE(pobj)) + { + case OBJ_TYPE_NON: + if (!is_expr_repr || is_nested) + { + sli_puts((uint8_t *)"None"); + } + break; + case OBJ_TYPE_INT: + retval = int_print(pobj); + break; +#ifdef HAVE_FLOAT + case OBJ_TYPE_FLT: + retval = float_print(pobj); + break; +#endif /* HAVE_FLOAT */ + case OBJ_TYPE_STR: + retval = string_print(pobj, (is_expr_repr || is_nested)); + break; + case OBJ_TYPE_TUP: + retval = tuple_print(pobj); + break; + case OBJ_TYPE_LST: + retval = list_print(pobj); + break; + case OBJ_TYPE_DIC: + retval = dict_print(pobj); + break; + case OBJ_TYPE_BOOL: + sli_puts( + (((pPmBoolean_t) pobj)->val == C_TRUE) + ? (uint8_t *)"True" + : (uint8_t *)"False"); + break; + + case OBJ_TYPE_CLI: +#ifdef HAVE_BYTEARRAY + { + pPmObj_t pobj2; + + retval = dict_getItem((pPmObj_t)((pPmInstance_t)pobj)->cli_attrs, + PM_NONE, + (pPmObj_t *)&pobj2); + if ((retval == PM_RET_OK) + && (OBJ_GET_TYPE(pobj2) == OBJ_TYPE_BYA)) + { + retval = bytearray_print(pobj2); + break; + } + } +#endif /* HAVE_BYTEARRAY */ + + case OBJ_TYPE_COB: + case OBJ_TYPE_MOD: + case OBJ_TYPE_CLO: + case OBJ_TYPE_FXN: + case OBJ_TYPE_CIM: + case OBJ_TYPE_NIM: + case OBJ_TYPE_NOB: + case OBJ_TYPE_THR: + case OBJ_TYPE_CIO: + case OBJ_TYPE_MTH: + case OBJ_TYPE_SQI: + { + uint8_t buf[17]; + sli_puts((uint8_t *)"<obj type 0x"); + sli_btoa16(OBJ_GET_TYPE(pobj), buf, sizeof(buf), C_TRUE); + sli_puts(buf); + sli_puts((uint8_t *)" @ 0x"); + sli_ptoa16((intptr_t)pobj, buf, sizeof(buf), C_TRUE); + sli_puts(buf); + retval = plat_putByte('>'); + break; + } + + default: + /* Otherwise raise a TypeError */ + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + return retval; +} +#endif /* HAVE_PRINT */ + + +#ifdef HAVE_BACKTICK +PmReturn_t +obj_repr(pPmObj_t pobj, pPmObj_t *r_pstr) +{ + uint8_t tBuffer[32]; + PmReturn_t retval = PM_RET_OK; + uint8_t const *pcstr = (uint8_t *)tBuffer;; + + C_ASSERT(pobj != C_NULL); + + switch (OBJ_GET_TYPE(pobj)) + { + case OBJ_TYPE_INT: + retval = sli_ltoa10(((pPmInt_t)pobj)->val, tBuffer, sizeof(tBuffer)); + PM_RETURN_IF_ERROR(retval); + retval = string_new(&pcstr, r_pstr); + break; + +#ifdef HAVE_FLOAT + case OBJ_TYPE_FLT: + /* #212: Use homebrew float formatter */ + retval = sli_ftoa(((pPmFloat_t)pobj)->val, tBuffer, sizeof(tBuffer)); + sli_strlen((char *)tBuffer); + retval = string_new(&pcstr, r_pstr); + break; +#endif /* HAVE_FLOAT */ + + default: + /* Otherwise raise a TypeError */ + PM_RAISE(retval, PM_RET_EX_TYPE); + break; + } + + return retval; +} +#endif /* HAVE_BACKTICK */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/obj.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,332 @@ +/* +# 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. +*/ + + +#ifndef __OBJ_H__ +#define __OBJ_H__ + + +/** + * \file + * \brief Object Type + * + * Object type header. + */ + + +/** Object descriptor field constants */ +#define OD_MARK_SHIFT (uint8_t)0 +#define OD_FREE_SHIFT (uint8_t)1 +#define OD_SIZE_SHIFT (uint8_t)0 +#define OD_TYPE_SHIFT (uint8_t)11 +#define OD_MARK_MASK (uint16_t)(1 << OD_MARK_SHIFT) +#define OD_FREE_MASK (uint16_t)(1 << OD_FREE_SHIFT) +#define OD_SIZE_MASK (uint16_t)(0x07FC) +#define OD_TYPE_MASK (uint16_t)(0xF800) + +/** Heap descriptor size mask */ +#define HD_SIZE_MASK (uint16_t)(OD_TYPE_MASK | OD_SIZE_MASK) +#define HD_SIZE_SHIFT OD_SIZE_SHIFT + +/** + * Gets the free bit of the given object to the given value. + * If the object is marked free, it is not being used by the VM. + */ +#define OBJ_GET_FREE(pobj) \ + ((((pPmObj_t)pobj)->od & OD_FREE_MASK) >> OD_FREE_SHIFT) + +/** + * Sets the free bit of the given object to the given value. + * Setting the free bit means that the object will use the heap descriptor + * structure instead of the object descriptor structure. + */ +#define OBJ_SET_FREE(pobj, free) \ + do \ + { \ + ((pPmObj_t)pobj)->od = ((uint8_t)free) \ + ? ((pPmObj_t)pobj)->od | OD_FREE_MASK \ + : ((pPmObj_t)pobj)->od & ~OD_FREE_MASK;\ + } \ + while (0) + +/* + * #99: od_size bits are shifted because size is a scaled value + * True size is always a multiple of 4, so the lower two bits are ignored + * and two more significant bits are gained. + */ +/** Gets the size in bytes of the object. */ +#define PM_OBJ_GET_SIZE(pobj) (((pPmObj_t)pobj)->od & OD_SIZE_MASK) + +/** + * Gets the type of the object + * This MUST NOT be called on objects that are free. + */ +#define OBJ_GET_TYPE(pobj) \ + ((((pPmObj_t)pobj)->od) >> OD_TYPE_SHIFT) + +/** + * Sets the type of the object + * This MUST NOT be called on objects that are free. + */ +#define OBJ_SET_TYPE(pobj, type) \ + do \ + { \ + ((pPmObj_t)pobj)->od &= ~OD_TYPE_MASK; \ + ((pPmObj_t)pobj)->od |= (((type) << OD_TYPE_SHIFT) & OD_TYPE_MASK); \ + } \ + while (0) + + +/** + * Object type enum + * + * These values go in the od_type fields of the obj descriptor. + * Be sure these values correspond to those in the image creator + * tool. + * The hashable types are grouped together for convenience. + * + * WARNING: od_type must be at most 5 bits! (must be < 0x20) + */ +typedef enum PmType_e +{ + OBJ_TYPE_HASHABLE_MIN = 0x00, + + /** None */ + OBJ_TYPE_NON = 0x00, + + /** Signed integer */ + OBJ_TYPE_INT = 0x01, + + /** Floating point 32b */ + OBJ_TYPE_FLT = 0x02, + + /** String */ + OBJ_TYPE_STR = 0x03, + + /** Tuple (immutable sequence) */ + OBJ_TYPE_TUP = 0x04, + + /** Code obj */ + OBJ_TYPE_COB = 0x05, + + /** Module obj */ + OBJ_TYPE_MOD = 0x06, + + /** Class obj */ + OBJ_TYPE_CLO = 0x07, + + /** Function obj (callable) */ + OBJ_TYPE_FXN = 0x08, + + /** Class instance */ + OBJ_TYPE_CLI = 0x09, + + /** Code image in static memory */ + OBJ_TYPE_CIM = 0x0A, + + /** Native function image */ + OBJ_TYPE_NIM = 0x0B, + + /** Native function object */ + OBJ_TYPE_NOB = 0x0C, + + /** Thread */ + OBJ_TYPE_THR = 0x0D, + + /** Boolean object */ + OBJ_TYPE_BOOL = 0x0F, + + /** Code image object */ + OBJ_TYPE_CIO = 0x10, + + /** Method object */ + OBJ_TYPE_MTH = 0x11, + + /* All types after this are not hashable */ + OBJ_TYPE_HASHABLE_MAX = 0x11, + + /** List (mutable sequence) */ + OBJ_TYPE_LST = 0x12, + + /** Dictionary (hash table) */ + OBJ_TYPE_DIC = 0x13, + +#ifdef HAVE_BYTEARRAY + /** Bytearray (mutable) */ + OBJ_TYPE_BYA = 0x14, +#endif /* HAVE_BYTEARRAY */ + + /* All types after this are not accessible to the user */ + OBJ_TYPE_ACCESSIBLE_MAX = 0x18, + +#ifdef HAVE_BYTEARRAY + /** Bytes (mutable container for Bytearray type) */ + OBJ_TYPE_BYS = 0x18, +#endif /* HAVE_BYTEARRAY */ + + /** Frame type */ + OBJ_TYPE_FRM = 0x19, + + /** Block type (for,while,try,etc) */ + OBJ_TYPE_BLK = 0x1A, + + /** Segment (within a seglist) */ + OBJ_TYPE_SEG = 0x1B, + + /** Seglist */ + OBJ_TYPE_SGL = 0x1C, + + /** Sequence iterator */ + OBJ_TYPE_SQI = 0x1D, + + /** Native frame (there is only one) */ + OBJ_TYPE_NFM = 0x1E, +} PmType_t, *pPmType_t; + + +/** + * Object Descriptor + * + * All active PyMite "objects" must have this at the top of their struct. + * The following is a diagram of the object descriptor: + * \verbatim + * MSb LSb + * 7 6 5 4 3 2 1 0 + * pchunk-> +-+-+-+-+-+-+-+-+ S := Size of the chunk (2 LSbs dropped) + * | S |F|M| F := Free bit + * +---------+-+-+-+ M := GC Mark bit + * | T | S | T := Object type (PyMite specific) + * +---------+-----+ + * | object data | + * ... ... + * | end data | + * +---------------+ + * \endverbatim + * + * The theoretical minimum size of an object descriptor is 2 bytes; + * however, the effective minimum size must be at least that of the minimum + * heap descriptor. So on an 8-bit MCU, the minimum size is 8 bytes + * and on an MCU with 32-bit addresses, the size is 12 bytes. + */ +typedef uint16_t PmObjDesc_t, *pPmObjDesc_t; + +/** The abstract empty object type for PyMite. */ +typedef struct PmObj_s +{ + /** Object descriptor */ + PmObjDesc_t od; +} PmObj_t, *pPmObj_t; + +/** Boolean object */ +typedef struct PmBoolean_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** Boolean value */ + int32_t val; +} +PmBoolean_t, *pPmBoolean_t; + + +/** + * Loads an object from an image in memory. + * Return pointer to object. + * Leave add pointing one byte past end of obj. + * + * The following lists the simple object types + * and their image structures: + * -None: + * -type: int8_t - OBJ_TYPE_NON + * + * -Int: + * -type: int8_t - OBJ_TYPE_INT + * -value: int32_t - signed integer value + * + * -Float: + * -type: int8_t - OBJ_TYPE_FLOAT + * -value: float32_t - 32-bit floating point value + * + * -Slice (is this allowed in img?): + * -type: int8_t - OBJ_TYPE_SLICE + * -index1: int16_t - first index. + * -index2: int16_t - second index. + * + * @param memspace memory space/type + * @param paddr ptr to ptr to obj + * return by reference: paddr pts to + * first byte after obj + * @param r_pobj Return arg, the loaded object. + * @return Return status + */ +PmReturn_t obj_loadFromImg(PmMemSpace_t memspace, + uint8_t const **paddr, pPmObj_t *r_pobj); + +/** + * Loads a code object from a code image object + * + * @param pimg Ptr to a code image object + * @param r_pobj Return arg, the loaded object + * @return Returns status + */ +PmReturn_t obj_loadFromImgObj(pPmObj_t pimg, pPmObj_t *r_pobj); + +/** + * Finds the boolean value of the given object. + * + * @param pobj Ptr to object to test. + * @return Nonzero value if object is False. + */ +int8_t obj_isFalse(pPmObj_t pobj); + +/** + * Returns the boolean true if the item is in the object + * + * @param pobj Ptr to container object + * @param pitem Ptr to item + */ +PmReturn_t obj_isIn(pPmObj_t pobj, pPmObj_t pitem); + +/** + * Compares two objects for equality. + * + * @param pobj1 Ptr to first object. + * @param pobj2 Ptr to second object. + * @return C_SAME if the items are equivalent, C_DIFFER otherwise. + */ +int8_t obj_compare(pPmObj_t pobj1, pPmObj_t pobj2); + +/** + * Print an object, thereby using objects helpers. + * + * @param pobj Ptr to object for printing. + * @param is_expr_repr Influences the way None and strings are printed. + * If 0, None is printed, strings are printed. + * If 1, None is not printed and strings are printed + * surrounded with single quotes and unprintable + * characters are escaped. + * @param is_nested Influences the way None and strings are printed. + * If 1, None will be printed and strings will be + * surrounded with single quotes and escaped. + * This argument overrides the is_expr_repr argument. + * @return Return status + */ +PmReturn_t obj_print(pPmObj_t pobj, uint8_t is_expr_repr, uint8_t is_nested); + +#ifdef HAVE_BACKTICK +/** + * Returns by reference a string object that is the human-readable + * representation of the object. Used by the backtick operation (UNARY_CONVERT). + * + * @param pobj Ptr to object to represent + * @param r_pstr Return arg, the string object + * @return Return status + */ +PmReturn_t obj_repr(pPmObj_t pobj, pPmObj_t *r_pstr); +#endif /* HAVE_BACKTICK */ + +#endif /* __OBJ_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/plat_interface.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,69 @@ +/* +# This file is Copyright 2010 Dean Hall. +# This file is part of the PyMite VM. +# This file is licensed under the MIT License. +# See the LICENSE file for details. +*/ + + +#ifndef __PLAT_H__ +#define __PLAT_H__ + + +/** + * \file + * \brief PyMite's Porting Interface + */ + + +/** + * Initializes the platform as needed by the routines + * in the platform implementation file. + */ +PmReturn_t plat_init(void); + +/** De-initializes the platform after the VM is done running. */ +PmReturn_t plat_deinit(void); + +/** + * Returns the byte at the given address in memspace. + * + * Increments the address (just like getc and read(1)) + * to make image loading work (recursively). + * + * PORT: fill in getByte for each memspace in the system; + * call sys_error for invalid memspaces. + * + * @param memspace memory space/type + * @param paddr ptr to address + * @return byte from memory. + * paddr - points to the next byte + */ +uint8_t plat_memGetByte(PmMemSpace_t memspace, uint8_t const **paddr); + +/** + * Receives one byte from the default connection, + * usually UART0 on a target device or stdio on the desktop + */ +PmReturn_t plat_getByte(uint8_t *b); + + +/** + * Sends one byte out on the default connection, + * usually UART0 on a target device or stdio on the desktop + */ +PmReturn_t plat_putByte(uint8_t b); + + +/** + * Gets the number of timer ticks that have passed since system start. + */ +PmReturn_t plat_getMsTicks(uint32_t *r_ticks); + + +/** + * Reports an exception or other error that caused the thread to quit + */ +void plat_reportError(PmReturn_t result); + +#endif /* __PLAT_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/pm.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,128 @@ +/* +# This file is Copyright 2006 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__ 0x15 + + +/** + * \file + * \brief PyMite User API + * + * High-level functions to initialize and run PyMite + */ + + +#include "pm.h" + + +/** Number of millisecond-ticks to pass before scheduler is run */ +#define PM_THREAD_TIMESLICE_MS 10 + + +/** Stores the timer millisecond-ticks since system start */ +volatile uint32_t pm_timerMsTicks = 0; + +/** Stores tick timestamp of last scheduler run */ +volatile uint32_t pm_lastRescheduleTimestamp = 0; + + +PmReturn_t +pm_init(uint8_t *heap_base, uint32_t heap_size, + PmMemSpace_t memspace, uint8_t const * const pusrimg) +{ + PmReturn_t retval; + + /* Initialize the hardware platform */ + retval = plat_init(); + PM_RETURN_IF_ERROR(retval); + + /* Initialize the heap and the globals */ + retval = heap_init(heap_base, heap_size); + PM_RETURN_IF_ERROR(retval); + + retval = global_init(); + PM_RETURN_IF_ERROR(retval); + + /* Load usr image info if given */ + if (pusrimg != C_NULL) + { + retval = img_appendToPath(memspace, pusrimg); + } + + return retval; +} + + +PmReturn_t +pm_run(uint8_t const *modstr) +{ + PmReturn_t retval; + pPmObj_t pmod; + pPmObj_t pstring; + uint8_t const *pmodstr = modstr; + uint8_t objid1; + uint8_t objid2; + + /* Import module from global struct */ + retval = string_new(&pmodstr, &pstring); + PM_RETURN_IF_ERROR(retval); + heap_gcPushTempRoot(pstring, &objid1); + retval = mod_import(pstring, &pmod); + PM_RETURN_IF_ERROR(retval); + + /* Load builtins into thread */ + heap_gcPushTempRoot(pmod, &objid2); + retval = global_setBuiltins((pPmFunc_t)pmod); + PM_RETURN_IF_ERROR(retval); + + /* Interpret the module's bcode */ + retval = interp_addThread((pPmFunc_t)pmod); + PM_RETURN_IF_ERROR(retval); + heap_gcPopTempRoot(objid1); + retval = interpret(INTERP_RETURN_ON_NO_THREADS); + + /* + * De-initialize the hardware platform. + * Ignore plat_deinit's retval so interpret's retval returns to caller. + */ + plat_deinit(); + + return retval; +} + + +/* Warning: Can be called in interrupt context! */ +PmReturn_t +pm_vmPeriodic(uint16_t usecsSinceLastCall) +{ + /* + * Add the full milliseconds to pm_timerMsTicks and store additional + * microseconds for the next run. Thus, usecsSinceLastCall must be + * less than 2^16-1000 so it will not overflow usecResidual. + */ + static uint16_t usecResidual = 0; + + C_ASSERT(usecsSinceLastCall < 64536); + + usecResidual += usecsSinceLastCall; + while (usecResidual >= 1000) + { + usecResidual -= 1000; + pm_timerMsTicks++; + } + + /* Check if enough time has passed for a scheduler run */ + if ((pm_timerMsTicks - pm_lastRescheduleTimestamp) + >= PM_THREAD_TIMESLICE_MS) + { + interp_setRescheduleFlag((uint8_t)1); + pm_lastRescheduleTimestamp = pm_timerMsTicks; + } + return PM_RET_OK; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/pm.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,262 @@ +/* +# 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. +*/ + + +#ifndef __PM_H__ +#define __PM_H__ + + +/** + * \file + * \brief PyMite Header + * + * Include things that are needed by nearly everything. + */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef HAVE_SNPRINTF_FORMAT +#include <stdio.h> +#endif +#include <stdint.h> + +/** + * Value indicating the release of PyMite + * + * This value should be incremented for every public release. + * It helps locate a defect when used in conjunction with a fileID + * and line number. + */ +#define PM_RELEASE 8 + + +/** null for C code */ +#define C_NULL 0 + +/** false for C code */ +#define C_FALSE (uint8_t)0 + +/** true for C code */ +#define C_TRUE (uint8_t)1 + +/** Comparison result is that items are the same */ +#define C_SAME (int8_t)0 + +/** Comparison result is that items differ */ +#define C_DIFFER (int8_t)-1 + +/** PORT inline for C code */ +#define INLINE __inline__ + + +/** + * Returns an exception error code and stores debug data + * + * This macro must be used as an rval statement. That is, it must + * be used after an assignment such as "retval = " or a return statement + */ +#if __DEBUG__ +#define PM_RAISE(retexn, exn) \ + do \ + { \ + retexn = (exn); \ + gVmGlobal.errFileId = __FILE_ID__; \ + gVmGlobal.errLineNum = (uint16_t)__LINE__; \ + } while (0) +#else +#define PM_RAISE(retexn, exn) \ + retexn = (exn) +#endif + +/** if retval is not OK, break from the block */ +#define PM_BREAK_IF_ERROR(retval) if ((retval) != PM_RET_OK) break + +/** return an error code if it is not PM_RET_OK */ +#define PM_RETURN_IF_ERROR(retval) if ((retval) != PM_RET_OK) return (retval) + +/** print an error message if argument is not PM_RET_OK */ +#define PM_REPORT_IF_ERROR(retval) if ((retval) != PM_RET_OK) \ + plat_reportError(retval) + +/** Jumps to a label if argument is not PM_RET_OK */ +#define PM_GOTO_IF_ERROR(retval, target) if ((retval) != PM_RET_OK) \ + goto target + +#if __DEBUG__ +/** If the boolean expression fails, return the ASSERT error code */ +#define C_ASSERT(boolexpr) \ + do \ + { \ + if (!((boolexpr))) \ + { \ + gVmGlobal.errFileId = __FILE_ID__; \ + gVmGlobal.errLineNum = (uint16_t)__LINE__; \ + return PM_RET_ASSERT_FAIL; \ + } \ + } \ + while (0) + +#else +/** Assert statements are removed from production code */ +#define C_ASSERT(boolexpr) +#endif + +/** Use as the first argument to C_DEBUG_PRINT for low volume messages */ +#define VERBOSITY_LOW 1 + +/** Use as the first argument to C_DEBUG_PRINT for medium volume messages */ +#define VERBOSITY_MEDIUM 2 + +/** Use as the first argument to C_DEBUG_PRINT for high volume messages */ +#define VERBOSITY_HIGH 3 + +#if __DEBUG__ +#include <stdio.h> + +/** To be used to set DEBUG_PRINT_VERBOSITY to a value so no prints occur */ +#define VERBOSITY_OFF 0 + +/** Sets the level of verbosity to allow in debug prints */ +#define DEBUG_PRINT_VERBOSITY VERBOSITY_OFF + +/** Prints a debug message when the verbosity is within the set value */ +#define C_DEBUG_PRINT(v, f, ...) \ + do \ + { \ + if (DEBUG_PRINT_VERBOSITY >= (v)) \ + { \ + printf("PM_DEBUG: " f, ## __VA_ARGS__); \ + } \ + } \ + while (0) + +#else +#define C_DEBUG_PRINT(...) +#endif + + +/** + * Return values for system functions + * to report status, errors, exceptions, etc. + * Normally, functions which use these values + * should propagate the same return value + * up the call tree to the interpreter. + */ +typedef enum PmReturn_e +{ + /* general status return values */ + PM_RET_OK = 0, /**< Everything is ok */ + PM_RET_NO = 0xFF, /**< General "no result" */ + PM_RET_ERR = 0xFE, /**< General failure */ + PM_RET_STUB = 0xFD, /**< Return val for stub fxn */ + PM_RET_ASSERT_FAIL = 0xFC, /**< Assertion failure */ + PM_RET_FRAME_SWITCH = 0xFB, /**< Frame pointer was modified */ + PM_RET_ALIGNMENT = 0xFA, /**< Heap is not aligned */ + + /* return vals that indicate an exception occured */ + PM_RET_EX = 0xE0, /**< General exception */ + PM_RET_EX_EXIT = 0xE1, /**< System exit */ + PM_RET_EX_IO = 0xE2, /**< Input/output error */ + PM_RET_EX_ZDIV = 0xE3, /**< Zero division error */ + PM_RET_EX_ASSRT = 0xE4, /**< Assertion error */ + PM_RET_EX_ATTR = 0xE5, /**< Attribute error */ + PM_RET_EX_IMPRT = 0xE6, /**< Import error */ + PM_RET_EX_INDX = 0xE7, /**< Index error */ + PM_RET_EX_KEY = 0xE8, /**< Key error */ + PM_RET_EX_MEM = 0xE9, /**< Memory error */ + PM_RET_EX_NAME = 0xEA, /**< Name error */ + PM_RET_EX_SYNTAX = 0xEB, /**< Syntax error */ + PM_RET_EX_SYS = 0xEC, /**< System error */ + PM_RET_EX_TYPE = 0xED, /**< Type error */ + PM_RET_EX_VAL = 0xEE, /**< Value error */ + PM_RET_EX_STOP = 0xEF, /**< Stop iteration */ + PM_RET_EX_WARN = 0xF0, /**< Warning */ + PM_RET_EX_OFLOW = 0xF1, /**< Overflow */ +} PmReturn_t; + + +extern volatile uint32_t pm_timerMsTicks; + + +/* WARNING: The order of the following includes is critical */ +#include "plat.h" +#include "pmfeatures.h" +#include "pmEmptyPlatformDefs.h" +#include "sli.h" +#include "mem.h" +#include "obj.h" +#include "seq.h" +#include "tuple.h" +#include "strobj.h" +#include "heap.h" +#include "int.h" +#include "seglist.h" +#include "list.h" +#include "dict.h" +#include "codeobj.h" +#include "func.h" +#include "module.h" +#include "frame.h" +#include "class.h" +#include "interp.h" +#include "img.h" +#include "global.h" +#include "thread.h" +#include "float.h" +#include "plat_interface.h" +#include "bytearray.h" + + +/** Pointer to a native function used for lookup tables in interp.c */ +typedef PmReturn_t (* pPmNativeFxn_t)(pPmFrame_t *); +extern pPmNativeFxn_t const std_nat_fxn_table[]; +extern pPmNativeFxn_t const usr_nat_fxn_table[]; + + +/** + * Initializes the PyMite virtual machine and indexes the user's application + * image. The VM heap and globals are reset. The argument, pusrimg, may be + * null for interactive sessions. + * + * @param heap_base The address where the contiguous heap begins + * @param heap_size The size in bytes (octets) of the given heap. + * Must be a multiple of four. + * @param memspace Memory space in which the user image is located + * @param pusrimg Address of the user image in the memory space + * @return Return status + */ +PmReturn_t pm_init(uint8_t *heap_base, uint32_t heap_size, + PmMemSpace_t memspace, uint8_t const * const pusrimg); + +/** + * Executes the named module + * + * @param modstr Name of module to run + * @return Return status + */ +PmReturn_t pm_run(uint8_t const *modstr); + +/** + * Needs to be called periodically by the host program. + * For the desktop target, it is periodically called using a signal. + * For embedded targets, it needs to be called periodically. It should + * be called from a timer interrupt. + * + * @param usecsSinceLastCall Microseconds (not less than those) that passed + * since last call. This must be <64535. + * @return Return status + */ +PmReturn_t pm_vmPeriodic(uint16_t usecsSinceLastCall); + +#ifdef __cplusplus +} +#endif + +#endif /* __PM_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/pmEmptyPlatformDefs.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,31 @@ +/* +# This file is Copyright 2010 Dean Hall. +# This file is part of the PyMite VM. +# This file is licensed under the MIT License. +# See the LICENSE file for details. +*/ + + +#ifndef __PM_EMPTY_PLATFORM_DEFS_H__ +#define __PM_EMPTY_PLATFORM_DEFS_H__ + + +/** + * \file + * \brief Empty platform-specific definitions + * + * This file #defines as blank any undefined platform-specific + * definitions. + */ + +/** + * Define a processor-specific specifier for use in declaring the heap. + * If not defined, make it empty. + * See <code>pmHeap</code> in heap.c for its use, which is:<br> + * <code>static PmHeap_t pmHeap PM_PLAT_HEAP_ATTR;</code> + */ +#if !defined(PM_PLAT_HEAP_ATTR) || defined(__DOXYGEN__) +#define PM_PLAT_HEAP_ATTR +#endif + +#endif /* __PM_EMPTY_PLATFORM_DEFS_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/pmFeatureDependencies.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,185 @@ +/* +# This file is Copyright 2010 Dean Hall. +# This file is part of the PyMite VM. +# This file is licensed under the MIT License. +# See the LICENSE file for details. +*/ + + +#ifndef __PM_EMPTY_PM_FEATURES_H__ +#define __PM_EMPTY_PM_FEATURES_H__ + + +/** + * \file + * \brief Platform feature descriptions and dependency checks + * + * This file explains the purpose of all of the HAVE_* features + * and provides logical checks for features that depend on other features. + * + * A platform defines the features it wants in src/platform/<plat>/pmfeatures.py + * A tool generates C HAVE_* definitions in pmfeatures.h from pmfeatures.py. + * + * + * HAVE_PRINT + * ---------- + * + * When defined, bytecodes PRINT_ITEM and PRINT_NEWLINE are supported. Along + * with these, helper routines in the object type are compiled in that allow + * printing of the object. + * REQUIRES stdio.h to have snprintf() + * + * + * HAVE_GC + * ------- + * + * When defined, the code to perform mark-sweep garbage collection is included + * in the build and automatic GC is enabled. When undefined the allocator + * will distribute memory until none is left, after which a memory exception + * will occur. + * + * + * HAVE_FLOAT + * ---------- + * + * When defined, the code to support floating point objects is included + * in the build. + * Issue #148 Create configurable float datatype + * + * + * HAVE_DEL + * -------- + * + * When defined, the code to support the keyword del is included in the build. + * This involves the bytecodes: DELETE_SUBSCR, DELETE_NAME, DELETE_ATTR, + * DELETE_GLOBAL and DELETE_FAST. + * + * + * HAVE_IMPORTS + * ------------ + * + * When defined, the code to support the IMPORT_FROM and IMPORT_STAR styles + * is included in the build. + * + * + * HAVE_DEFAULTARGS + * ---------------- + * + * When defined, the code to support default arguments to functions is included + * in the build. + * Issue #157 Support default args + * + * + * HAVE_REPLICATION + * ---------------- + * + * When defined, the code to support sequence (list, tuple, string) replcation + * is included in the build. + * This feature is required by the builtin function __bi.map(). + * #160 Add support for string and tuple replication + * + * + * HAVE_CLASSES + * ------------ + * + * When defined, the code to support classes, instances, methods, etc. + * is included in the build. + * Issue #202 Implement classes in the vm + * + * + * HAVE_ASSERT + * ----------- + * + * When defined, the code to support the assert statement is included + * in the build. + * + * + * HAVE_GENERATORS + * --------------- + * + * When defined, the code to support the yield keyword's use for + * generator-iterators is included in the build. + * Issue #207 Add support for the yield keyword + * + * + * HAVE_BACKTICK + * ------------- + * + * When defined, the code to support the backtick operation (`x`) is included + * in the build. + * REQUIRES stdio.h to have snprintf() + * Issue #244 Add support for the backtick operation (UNARY_CONVERT) + * + * + * HAVE_STRING_FORMAT + * ------------------ + * + * When defined, the code to perform string formatting using the binary modulo + * operator is included in the build. + * REQUIRES stdio.h to have snprintf() + * Issue #205 Add support for string format operation + * + * + * HAVE_CLOSURES + * ------------- + * + * When defined, the code to support function closures is included in the + * build. + * Issue #256 Add support for closures + * + * + * HAVE_BYTEARRAY + * -------------- + * + * When defined, the code to support the bytearray type is included in the + * build. NOTE: If this is defined, the bytearray class in src/lib/__bi.py + * must also be uncommented. + * Issue #289 Create bytearray datatype + * + * + * HAVE_DEBUG_INFO + * --------------- + * + * When defined, the code to support debug information in exception reports + * is included in the build. + * Issue #103 Add debug info to exception reports + * + * + * HAVE_SNPRINTF_FORMAT + * -------------------- + * + * When defined, the string format operation is performed using C's snprintf(). + * The snprintf() function and all its helper functions can take up program + * memory, so some people may choose to do without this. + * You should define this when you need precise control over numeric formatting + * such as when you supply numbers between the '%' and the type specifier, + * like so:: + * + * printf "Number = %4d" % someNumber + * pirntf "PI approx = %1.2" % 3.1415 + */ + +/* Check for dependencies */ + +#if defined(HAVE_ASSERT) && !defined(HAVE_CLASSES) +#error HAVE_ASSERT requires HAVE_CLASSES +#endif + + +#if defined(HAVE_GENERATORS) && !defined(HAVE_CLASSES) +#error HAVE_GENERATORS requires HAVE_CLASSES +#endif + + +#if defined(HAVE_CLOSURES) && !defined(HAVE_DEFAULTARGS) +#error HAVE_CLOSURES requires HAVE_DEFAULTARGS +#endif + + +#if defined(HAVE_BYTEARRAY) && !defined(HAVE_CLASSES) +#error HAVE_BYTEARRAY requires HAVE_CLASSES +#endif + +#if defined(HAVE_SNPRINTF_FORMAT) && !defined(HAVE_STRING_FORMAT) +#error HAVE_SNPRINTF_FORMAT requires HAVE_STRING_FORMAT +#endif /* __PM_EMPTY_PM_FEATURES_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/seglist.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,358 @@ +/* +# 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__ 0x10 + + +/** + * \file + * \brief Segmented list data type and operations + * + * The segmented list is used to implement the Python + * List and Dict data types. + * The segmented list is used in preference to the linked list + * in order to reduce the memory overhead. + * + * Unused slots in the segments are expected to contain C_NULL. + * + * List implementation: + * When used in a List, the Seglist.currseg field points + * to the last segment in the list. + * The function seglist_appendItem() should be used to append + * items to the List. + * Inserting and deleting List items is a more complicated + * matter. + * + * Dict implementation: + * The currseg field is meaningless since rootseg always + * points to the current active segment. + * The function seglist_pushItem() should be used to put + * items in the Dict. + * A Dict uses one Seglist for keys and another for values. + * A Dict entry's (key, value) pair share the same index in + * the Seglist. + */ + + +#include "pm.h" + + +/** + * Set this to 1 if seglist_clear() should manually free its segments. + * Set this to 0 if seglist_clear() should do nothing + * and let the GC reclaim objects. + */ +#define SEGLIST_CLEAR_SEGMENTS 1 + + +PmReturn_t +seglist_appendItem(pSeglist_t pseglist, pPmObj_t pobj) +{ + return seglist_insertItem(pseglist, pobj, pseglist->sl_length); +} + + +PmReturn_t +seglist_clear(pSeglist_t pseglist) +{ + pSegment_t pseg1 = C_NULL; + pSegment_t pseg2 = C_NULL; + +#if SEGLIST_CLEAR_SEGMENTS + /* Deallocate all linked segments */ + pseg1 = ((pSeglist_t)pseglist)->sl_rootseg; + while (pseg1 != C_NULL) + { + pseg2 = pseg1->next; + PM_RETURN_IF_ERROR(heap_freeChunk((pPmObj_t)pseg1)); + pseg1 = pseg2; + } +#endif + + /* Clear seglist fields */ + ((pSeglist_t)pseglist)->sl_rootseg = C_NULL; + ((pSeglist_t)pseglist)->sl_lastseg = C_NULL; + ((pSeglist_t)pseglist)->sl_length = 0; + + return PM_RET_OK; +} + + +PmReturn_t +seglist_findEqual(pSeglist_t pseglist, pPmObj_t pobj, int16_t *r_index) +{ + pSegment_t pseg; + int8_t i = 0; + uint8_t segindex; + + C_ASSERT(pseglist != C_NULL); + C_ASSERT(pobj != C_NULL); + C_ASSERT((*r_index >= 0)); + C_ASSERT((*r_index == 0) || (*r_index < pseglist->sl_length)); + + /* Walk out to the starting segment */ + pseg = pseglist->sl_rootseg; + for (i = (*r_index / SEGLIST_OBJS_PER_SEG); i > (int8_t)0; i--) + { + C_ASSERT(pseg != C_NULL); + pseg = pseg->next; + } + + /* Set the starting index within the segment */ + segindex = *r_index % SEGLIST_OBJS_PER_SEG; + + /* Search the remaining segments */ + for (; pseg != C_NULL; pseg = pseg->next) + { + while (segindex < SEGLIST_OBJS_PER_SEG) + { + /* If past the end of the seglist, return no item found */ + if (*r_index >= pseglist->sl_length) + { + return PM_RET_NO; + } + + /* If items are equal, return with index of found item */ + if (obj_compare(pobj, pseg->s_val[segindex]) == C_SAME) + { + return PM_RET_OK; + } + + /* Proceed to next item */ + segindex++; + (*r_index)++; + } + + /* Proceed to next segment */ + segindex = 0; + } + return PM_RET_NO; +} + + +PmReturn_t +seglist_getItem(pSeglist_t pseglist, int16_t index, pPmObj_t *r_pobj) +{ + pSegment_t pseg; + int16_t i; + + C_ASSERT(pseglist != C_NULL); + C_ASSERT(index >= 0); + C_ASSERT(index < pseglist->sl_length); + + /* Walk out to the proper segment */ + pseg = pseglist->sl_rootseg; + C_ASSERT(pseg != C_NULL); + for (i = (index / SEGLIST_OBJS_PER_SEG); i > 0; i--) + { + pseg = pseg->next; + C_ASSERT(pseg != C_NULL); + } + + /* Return ptr to obj in this seg at the index */ + *r_pobj = pseg->s_val[index % SEGLIST_OBJS_PER_SEG]; + return PM_RET_OK; +} + + +PmReturn_t +seglist_insertItem(pSeglist_t pseglist, pPmObj_t pobj, int16_t index) +{ + PmReturn_t retval = PM_RET_OK; + pSegment_t pseg = C_NULL; + pPmObj_t pobj1 = C_NULL; + pPmObj_t pobj2 = C_NULL; + int8_t indx = (int8_t)0; + int16_t i = 0; + uint8_t *pchunk; + + C_ASSERT(index <= pseglist->sl_length); + + /* If a new seg is needed */ + if ((pseglist->sl_length % SEGLIST_OBJS_PER_SEG) == 0) + { + /* Alloc and init new segment */ + retval = heap_getChunk(sizeof(Segment_t), &pchunk); + PM_RETURN_IF_ERROR(retval); + pseg = (pSegment_t)pchunk; + OBJ_SET_TYPE(pseg, OBJ_TYPE_SEG); + sli_memset((unsigned char *)pseg->s_val, + 0, SEGLIST_OBJS_PER_SEG * sizeof(pPmObj_t)); + pseg->next = C_NULL; + + /* If this is the first seg, set as root */ + if (pseglist->sl_rootseg == C_NULL) + { + pseglist->sl_rootseg = pseg; + } + + /* Else append the seg to the end */ + else + { + pseglist->sl_lastseg->next = pseg; + } + + /* Either way, this is now the last segment */ + pseglist->sl_lastseg = pseg; + } + + /* Walk out to the segment for insertion */ + pseg = pseglist->sl_rootseg; + C_ASSERT(pseg != C_NULL); + for (i = (index / SEGLIST_OBJS_PER_SEG); i > 0; i--) + { + pseg = pseg->next; + C_ASSERT(pseg != C_NULL); + } + + /* Insert obj and ripple copy all those afterward */ + indx = index % SEGLIST_OBJS_PER_SEG;; + pobj1 = pobj; + while (pobj1 != C_NULL) + { + pobj2 = pseg->s_val[indx]; + pseg->s_val[indx] = pobj1; + pobj1 = pobj2; + indx++; + + /* If indx exceeds this seg, go to next seg */ + if ((indx >= SEGLIST_OBJS_PER_SEG) && (pobj1 != C_NULL)) + { + pseg = pseg->next; + C_ASSERT(pseg != C_NULL); + indx = (int8_t)0; + } + } + pseglist->sl_length++; + return retval; +} + + +PmReturn_t +seglist_new(pSeglist_t *r_pseglist) +{ + PmReturn_t retval = PM_RET_OK; + + retval = heap_getChunk(sizeof(Seglist_t), (uint8_t **)r_pseglist); + PM_RETURN_IF_ERROR(retval); + + OBJ_SET_TYPE(*r_pseglist, OBJ_TYPE_SGL); + (*r_pseglist)->sl_rootseg = C_NULL; + (*r_pseglist)->sl_lastseg = C_NULL; + (*r_pseglist)->sl_length = 0; + return retval; +} + + +PmReturn_t +seglist_setItem(pSeglist_t pseglist, pPmObj_t pobj, int16_t index) +{ + pSegment_t pseg; + int16_t i; + + C_ASSERT(index <= pseglist->sl_length); + + /* Walk out to the proper segment */ + pseg = pseglist->sl_rootseg; + C_ASSERT(pseg != C_NULL); + for (i = (index / SEGLIST_OBJS_PER_SEG); i > 0; i--) + { + pseg = pseg->next; + C_ASSERT(pseg != C_NULL); + } + + /* Set item in this seg at the index */ + pseg->s_val[index % SEGLIST_OBJS_PER_SEG] = pobj; + return PM_RET_OK; +} + + +PmReturn_t +seglist_removeItem(pSeglist_t pseglist, uint16_t index) +{ + pSegment_t pseg; + int16_t i, + k; + + C_ASSERT(index < pseglist->sl_length); + + /* Walk through the segments */ + pseg = pseglist->sl_rootseg; + C_ASSERT(pseg != C_NULL); + for (i = (index / SEGLIST_OBJS_PER_SEG); i > 0; i--) + { + pseg = pseg->next; + C_ASSERT(pseg != C_NULL); + } + + /* + * pseg now points to the correct segment of the item to be removed, so + * start ripple copying all following items up to the last + * in the last segment + */ + + for (i = index; i < ((pseglist->sl_length) - 1); i++) + { + k = i % SEGLIST_OBJS_PER_SEG; + + /* Copy element i+1 to slot i */ + if ((k + 1) == SEGLIST_OBJS_PER_SEG) + { + /* Source is first item in next segment */ + pseg->s_val[i % SEGLIST_OBJS_PER_SEG] = (pseg->next)->s_val[0]; + pseg = pseg->next; + } + else + { + /* Source and target are in the same segment */ + pseg->s_val[k] = pseg->s_val[k + 1]; + } + } + + pseglist->sl_length -= 1; + + /* Remove the last segment if it was emptied */ + if (pseglist->sl_length % SEGLIST_OBJS_PER_SEG == 0) + { + pseg = pseglist->sl_rootseg; + + /* Find the segment before the last */ + for (i = 0; i < ((pseglist->sl_length - 1) / SEGLIST_OBJS_PER_SEG); + i++) + { + pseg = pseg->next; + C_ASSERT(pseg != C_NULL); + } + if (pseg->next == C_NULL) + { + /* + * Seglist is now completely empty and the last segment can be + * recycled. + */ +#if SEGLIST_CLEAR_SEGMENTS + PM_RETURN_IF_ERROR(heap_freeChunk((pPmObj_t)pseg)); +#endif + pseglist->sl_lastseg = C_NULL; + pseglist->sl_rootseg = C_NULL; + } + else + { + /* At least one segment remains */ + pseglist->sl_lastseg = pseg; + pseg->next = C_NULL; + } + } + else + { + /* Zero out the now unused slot */ + pseg->s_val[pseglist->sl_length % SEGLIST_OBJS_PER_SEG] = C_NULL; + } + + return PM_RET_OK; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/seglist.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,160 @@ +/* +# 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. +*/ + + +#ifndef __SEGLIST_H__ +#define __SEGLIST_H__ + + +/** + * \file + * \brief Segmented List data structure + * + * A seglist is a linked list of segments. + * A segment is an array of ptrs to objects + * (with a pointer to the next segment). + * Seglists are used to implement Lists and Dicts. + * + * This implementation of Seglist is straight. + * That is, the next pointer in the final segment + * contains C_NULL. + * + * This implementation of Seglist is dense. + * That is, there are no gaps in a segment. + * All entries point to an object, except entries + * that are beyond the index of the last item. + */ + + +/** Defines the length of the object array in a segment */ +#define SEGLIST_OBJS_PER_SEG 8 + + +/** Segment - an array of ptrs to objs */ +typedef struct Segment_s +{ + /** object descriptor */ + PmObjDesc_t od; + /** array of ptrs to objs */ + pPmObj_t s_val[SEGLIST_OBJS_PER_SEG]; + /** ptr to next segment */ + struct Segment_s *next; +} Segment_t, + *pSegment_t; + + +/** Seglist - linked list of segments with current index info */ +typedef struct Seglist_s +{ + /** object descriptor */ + PmObjDesc_t od; + /** index of (one past) last obj in last segment */ + int16_t sl_length; + /** ptr to first segment in list */ + pSegment_t sl_rootseg; + /** ptr to last segment */ + pSegment_t sl_lastseg; +} Seglist_t, + *pSeglist_t; + + +/** + * Puts the new object at the end of the list. + * This is intended for the List type where + * the List index matches the order of the Seglist index. + * Makes room if necessary by adding new segments. + * + * @param pseglist Ptr to seglist + * @param pobj Pointer to object to append + * @return Return status + */ +PmReturn_t seglist_appendItem(pSeglist_t pseglist, pPmObj_t pobj); + +/** + * Clears the the seglist by unlinking the root segment. + * + * @param pseglist Ptr to seglist to empty + */ +PmReturn_t seglist_clear(pSeglist_t pseglist); + +/** + * Finds the first obj equal to pobj in the seglist. + * Starts searching the list at the given segnum and indx. + * + * @param pseglist The seglist to search + * @param pobj The object to match + * @param r_index Return arg; the index of where to start the search. + * If a match is found, return the index by reference. + * If no match is found, this value is undefined. + * @return Return status; PM_RET_OK means a matching object + * was found. PM_RET_ERR otherwise. + */ +PmReturn_t seglist_findEqual(pSeglist_t pseglist, + pPmObj_t pobj, int16_t *r_index); + +/** + * Gets the item in the seglist at the given coordinates. + * The segment number and the index within the segment + * are the coordinates of the object to get. + * + * @param pseglist Ptr to seglist to scan + * @param index Index of item to get + * @param r_pobj Return arg; Ptr to object at the index + * @return Return status; PM_RET_OK if object found. + * PM_RET_ERR otherwise. + */ +PmReturn_t seglist_getItem(pSeglist_t pseglist, + int16_t index, pPmObj_t *r_pobj); + +/** + * Allocates a new empty seglist + * + * @param r_pseglist return; Address of ptr to new seglist + * @return Return status + */ +PmReturn_t seglist_new(pSeglist_t *r_pseglist); + + +/** + * Puts the item in the next available slot in the first available segment. + * This is intended for the Dict type where + * the Seglist index is insignificant. + * Pushing an object assures it will be found early + * during a call to seglist_findEqual(). + * + * @param pseglist Ptr to seglist in which object is placed. + * @param pobj Ptr to object which is inserted. + * @param index Index into seglist before which item is inserted + * @return Return status; PM_RET_OK if the item was inserted. + * Any error condition comes from heap_getChunk. + */ +PmReturn_t seglist_insertItem(pSeglist_t pseglist, + pPmObj_t pobj, int16_t index); + +/** + * Puts the item in the designated slot and segment. + * This is intended to be used after seglist_findEqual() + * returns the proper indeces. + * + * @param pseglist Ptr to seglist in which object is placed. + * @param pobj Ptr to object which is set. + * @param index Index into seglist of where to put object. + * @return Return status; PM_RET_OK if object is set. + * PM_RET_ERR otherwise. + */ +PmReturn_t seglist_setItem(pSeglist_t pseglist, pPmObj_t pobj, int16_t index); + +/** + * Removes the item at the given index. + * + * @param pseglist Ptr to seglist in which object is removed. + * @param index Index into seglist of where to put object. + * @return Return status + */ +PmReturn_t seglist_removeItem(pSeglist_t pseglist, uint16_t index); + +#endif /* __SEGLIST_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/seq.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,275 @@ +/* +# This file is Copyright 2006 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__ 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, uint16_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 */ + + case OBJ_TYPE_DIC: + *r_index = ((pPmDict_t)pobj)->length; + break; + + 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; + pSeglist_t pkeys; + 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 */ + + /* Issue #176 Add support to iterate over keys in a dict */ + case OBJ_TYPE_DIC: + pkeys = ((pPmDict_t)pobj)->d_keys; + retval = seglist_getItem(pkeys, index, r_pobj); + break; + + 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; + uint16_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) + && (OBJ_GET_TYPE(pobj) != OBJ_TYPE_DIC)) + { + 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; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/seq.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,86 @@ +/* +# This file is Copyright 2006 Dean Hall. +# This file is part of the PyMite VM. +# This file is licensed under the MIT License. +# See the LICENSE file for details. +*/ + + +#ifndef __SEQ_H__ +#define __SEQ_H__ + + +/** + * \file + * \brief Sequence Header + */ + + +/** + * Sequence Iterator Object + * + * Instances of this object are created by GET_ITER and used by FOR_ITER. + * Stores a pointer to a sequence and an index int16_t. + */ +typedef struct PmSeqIter_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** Sequence object */ + pPmObj_t si_sequence; + + /** Index value */ + int16_t si_index; +} PmSeqIter_t, + *pPmSeqIter_t; + + +/** + * Compares two sequences for equality + * + * @param pobj1 Ptr to first sequence. + * @param pobj2 Ptr to second sequence. + * @return C_SAME if the seuqences are equivalent, C_DIFFER otherwise. + */ +int8_t seq_compare(pPmObj_t pobj1, pPmObj_t pobj2); + +/** + * Returns the length of the sequence + * + * @param pobj Ptr to sequence. + * @param r_index Return arg, length of sequence + * @return Return status + */ +PmReturn_t seq_getLength(pPmObj_t pobj, uint16_t *r_index); + +/** + * Returns the object from sequence[index] + * + * @param pobj Ptr to sequence object to get object from + * @param index Int index into the sequence + * @param r_pobj Return arg, object from sequence + * @return Return status + */ +PmReturn_t seq_getSubscript(pPmObj_t pobj, int16_t index, pPmObj_t *r_pobj); + +/** + * Returns the next item from the sequence iterator object + * + * @param pobj Ptr to sequence iterator. + * @param r_pitem Return arg, pointer to next item from sequence. + * @return Return status. + */ +PmReturn_t seqiter_getNext(pPmObj_t pobj, pPmObj_t *r_pitem); + + +/** + * Returns a new sequence iterator object + * + * @param pobj Ptr to sequence. + * @param r_pobj Return by reference, new sequence iterator + * @return Return status. + */ +PmReturn_t seqiter_new(pPmObj_t pobj, pPmObj_t *r_pobj); + +#endif /* __SEQ_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/sli.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,442 @@ +/* +# 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__ 0x11 + + +/** + * \file + * \brief Standard Library Interface + * + * PyMite requires a few functions from a few different + * standard C libraries (memory, string, etc). + */ + + +#include "pm.h" + + +/** use Duff's Device or simple for-loop for memcpy. */ +#define USE_DUFFS_DEVICE 0 + + +#if !HAVE_STRING_H + +void * +sli_memcpy(unsigned char *to, unsigned char const *from, unsigned int n) +{ + unsigned char *tobak; + + /* Store init value of to */ + tobak = to; + +#if USE_DUFFS_DEVICE + if (n > 0) + { + switch (n & 0x7) + do + { + case 0: + *to++ = *from++; + case 7: + *to++ = *from++; + case 6: + *to++ = *from++; + case 5: + *to++ = *from++; + case 4: + *to++ = *from++; + case 3: + *to++ = *from++; + case 2: + *to++ = *from++; + case 1: + *to++ = *from++; + } + while ((n -= 8) > 0); + } +#else + for (; n > 0; n--) + { + *to = *from; + from++; + to++; + } +#endif /* USE_DUFFS_DEVICE */ + return tobak; +} + + +int +sli_strlen(char const *s) +{ + char const *si = s; + int len = 0; + + while (*si++) + { + len++; + } + return len; +} + + +int +sli_strcmp(char const *s1, char const *s2) +{ + /* While not at either strings' end and they're same */ + while ((*s1 != C_NULL) && (*s2 != C_NULL) && (*s1 == *s2)) + { + s1++; + s2++; + } + + /* Return string difference */ + return *s1 - *s2; +} + + +int +sli_strncmp(char const *s1, char const *s2, unsigned int n) +{ + unsigned int i = 0; + + if (n == 0) + { + return 0; + } + + /* Scan n bytes in string */ + for (i = 0; i < n; i++) + { + /* If bytes differ, return difference */ + if (s1[i] != s2[i]) + { + return s1[i] - s2[i]; + } + } + return 0; +} + +#endif /* HAVE_STRING_H */ + + +/* + * This function is moved outside of HAVE_STRING_H because the one in string.h + * will not accept a null value for the second arg + */ +void +sli_memset(unsigned char *dest, char const val, unsigned int n) +{ + unsigned int i; + + for (i = 0; i < n; i++) + { + *dest = (unsigned char)val; + dest++; + } +} + +void +sli_puts(uint8_t * s) +{ + uint8_t *ps = s; + uint8_t c; + + c = *ps; + ps++; + while (c != '\0') + { + plat_putByte(c); + c = *ps; + ps++; + } +} + + +PmReturn_t +sli_ltoa10(int32_t value, uint8_t *buf, uint8_t buflen) +{ + int32_t const decimal_places[] = { 1000000000, 100000000, 10000000, 1000000, + 100000, 10000, 1000, 100, 10, 1 }; + int32_t decimal_place; + int32_t number; + uint8_t c; + uint8_t printed_one = C_FALSE; + uint8_t i; + uint8_t j; + PmReturn_t retval = PM_RET_OK; + + C_ASSERT(buflen >= 12); + + number = value; + if (number == 0) + { + buf[0] = '0'; + buf[1] = '\0'; + return retval; + } + + /* Special case (can't convert it to positive value) */ + if (number == -2147483648) + { + sli_memcpy(buf, (unsigned char *)"-2147483648", 11); + return PM_RET_OK; + } + + j = 0; + if (number < 0) + { + buf[0] = '-'; + j++; + number = -number; + } + + for (i = 0; i < 10; i++) + { + decimal_place = decimal_places[i]; + c = '0'; + while (number >= decimal_place) + { + number -= decimal_place; + c++; + } + if ((c != '0') || printed_one) + { + buf[j++] = c; + printed_one = C_TRUE; + } + } + buf[j] = '\0'; + + return retval; +} + +char const * const hexChars = "0123456789abcdef"; + +/* MUST show leading zeros because callers don't keep track */ +PmReturn_t +sli_btoa16(uint8_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase) +{ + C_ASSERT(buflen >= 3); + + if (upperCase) upperCase = 'A' - 'a'; + + buf[0] = (value >> 4) > 9 + ? hexChars[value >> 4] + upperCase + : hexChars[value >> 4]; + buf[1] = (value & 0x0F) > 9 + ? hexChars[value & 0x0F] + upperCase + : hexChars[value & 0x0F]; + buf[2] = '\0'; + + return PM_RET_OK; +} + + +/* Does NOT show leading zeroes */ +PmReturn_t +sli_ltoa16(int32_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase) +{ + int8_t i; + uint8_t j = 0; + uint8_t showZero = C_FALSE; + uint8_t nibble; + + C_ASSERT(buflen >= 9); + + if (upperCase) upperCase = 'A' - 'a'; + + for (i = 28; i >= 0; i -= 4) + { + nibble = ((value >> i) & 0xF); + if ((nibble == 0) && !showZero) continue; + buf[j++] = (nibble > 9) + ? hexChars[nibble] + upperCase + : hexChars[nibble]; + showZero = C_TRUE; + } + buf[j] = '\0'; + + return PM_RET_OK; +} + + +PmReturn_t +sli_ptoa16(intptr_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase) +{ + PmReturn_t retval; + int8_t i; + int8_t j; + + C_ASSERT(buflen >= 2 * sizeof(intptr_t) + 1); + + /* Print the hex value, most significant byte first */ + for (j = 0, i = 8 * sizeof(intptr_t) - 8; i >= 0; i -= 8, j += 2) + { + retval = sli_btoa16((value >> i) & 0xFF, &buf[j], buflen - j, upperCase); + PM_BREAK_IF_ERROR(retval); + } + + return retval; +} + + +typedef union { + int32_t L; + float F; +} LF_t; + + +/* The buf MUST be at least 15 bytes long */ +PmReturn_t +sli_ftoa(float f, uint8_t *buf, uint8_t buflen) +{ + uint32_t mantissa, int_part, frac_part; + int16_t exp2; + LF_t x; + uint8_t *p; + int8_t adj = 0; + PmReturn_t retval = PM_RET_OK; + + C_ASSERT(buflen >= 15); + + if (f == 0.0) + { + buf[0] = '0'; + buf[1] = '.'; + buf[2] = '0'; + buf[3] = '\0'; + return PM_RET_OK; + } + x.F = f; + + exp2 = (0xFF & (x.L >> 23)) - 127; + mantissa = (x.L & 0xFFFFFF) | 0x800000; + frac_part = 0; + int_part = 0; + p = buf; + + /* Adjust large exponents using the approximation: 2**10 == k*10**3 */ + while (exp2 >= 31) + { + /* Reduce the binary exponent here (incr the decimal exponent below) */ + exp2 -= 10; + adj++; + + /* + * To use the approximation above, the mantissa must be multiplied by k + * where k = 1.024 ~= (1 + 12583/(2**19)) + * Divide first to avoid integer overflow (the mantissa is 24 bits) + */ + mantissa += ((mantissa >> 6) * 12583) >> 13; + } + + if (exp2 < -23) + { + // Unable to handle large negative exponents at this time + *p++ = '?'; + return PM_RET_OK; + } + else if (exp2 >= 23) + { + int_part = mantissa << (exp2 - 23); + } + else if (exp2 >= 0) + { + int_part = mantissa >> (23 - exp2); + frac_part = (mantissa << (exp2 + 1)) & 0xFFFFFF; + } + else /* if (exp2 < 0) */ + { + frac_part = (mantissa & 0xFFFFFF) >> -(exp2 + 1); + } + + if (x.L < 0) + { + *p++ = '-'; + } + + if (int_part == 0) + { + *p++ = '0'; + } + else + { + retval = sli_ltoa10(int_part, p, buflen - (p - buf)); + PM_RETURN_IF_ERROR(retval); + while (*p) p++; + } + *p++ = '.'; + + if (frac_part == 0) + { + *p++ = '0'; + } + else + { + char m, max; + + max = buflen - (p - buf) - 1; + if (max > 6) + { + max = 6; + } + + /* Print fractional part */ + for (m = 0; m < max; m++) + { + frac_part *= 10; + *p++ = '0' + (frac_part >> 24); + frac_part &= 0xFFFFFF; + } + + /* Remove ending zeroes */ + //for (--p; p[0] == '0' && p[-1] != '.'; --p); + //++p; + } + + /* + * If the exponent is large (adjustment took place above), + * normalize the string to scientific notation + */ + if (adj != 0) + { + uint8_t i; + + /* Shift chars to make room for the new decimal point */ + i = (p - buf + 1); + i = (i > (buflen - 1)) ? buflen - 1 : i; + for (; i > 1; i--) + { + buf[i] = buf[i-1]; + } + + /* Find the index of the old decimal point */ + for (i = 6; (buf[i] != '.') && (i < 15); i++); + + /* Set the new decimal point (normalized) */ + buf[1] = '.'; + + /* + * Adjust the decimal exponent (3 decimal places for every 10 bits) + * and add the amount for the normalization + */ + p = &buf[8]; + *p++ = 'e'; + *p++ = '+'; + retval = sli_ltoa10(3 * adj + (i - 2), p, buflen - (p - buf)); + PM_RETURN_IF_ERROR(retval); + while (*p) p++; + } + + *p = '\0'; + + return PM_RET_OK; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/sli.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,174 @@ +/* +# 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. +*/ + + +#ifndef __SLI_H__ +#define __SLI_H__ + + +/** + * \file + * \brief Standard Library Interface + * + * PyMite requires a few functions from a few different + * standard C libraries (memory, string, etc). + * If your microcontroller has these libraries, + * set the constant to 1 for each library available. + * This will cause a macro to be defined which wraps + * the function for use by PyMite. + * Otherwise, leave the constant as 0, and PyMite will + * use the function defined in sli.c + * Some of the functions in sli.c will need to be ported + * to the target system. + */ + + +/** + * If the compiler has string.h, set HAVE_STRING to 1; + * otherwise, leave it 0 and the sli functions will be used. + */ +#define HAVE_STRING_H 0 + + +/* + * This section creates a macro or a function prototype + * for each library based on the corresponding constant. + * For example, if HAVE_STRING_H is defined to non-zero, + * the system <string.h> file will be included, + * and a macro "sli_strcmp" will be created to wrap the strcmp() + * function. But if HAVE_STRING is zero, the sli_strcmp() + * prototype will be declared and sli_strcmp() must be + * implemented in sli.c + */ + +#if HAVE_STRING_H + +#include <string.h> + +#define sli_memcpy(to, from, n) memcpy((to), (from), (n)) +#define sli_strcmp(s1, s2) strcmp((s1),(s2)) +#define sli_strlen(s) strlen(s) +#define sli_strncmp(s1, s2, n) strncmp((s1),(s2),(n)) + +#else + +/** + * Copies a block of memory in RAM. + * + * @param to The destination address. + * @param from The source address. + * @param n The number of bytes to copy. + * @return The initial pointer value of the destination + * @see mem_copy + */ +void *sli_memcpy(unsigned char *to, unsigned char const *from, unsigned int n); + +/** + * Compares two strings. + * + * @param s1 Ptr to string 1. + * @param s2 Ptr to string 2. + * @return value that is less then, equal to or greater than 0 + * depending on whether s1's encoding is + * less than, equal to, or greater than s2's. + */ +int sli_strcmp(char const *s1, char const *s2); + +/** + * Obtain string length. + * + * @param s ptr to string. + * @return number of bytes in string. + */ +int sli_strlen(char const *s); + +/** + * Compare strings for a specific length. + * + * @param s1 ptr to string 1. + * @param s2 ptr to string 2. + * @param n number of chars to compare + * @return value that is less then, equal to or greater than 0 + * depending on whether s1's encoding is + * less than, equal to, or greater than s2's. + */ +int sli_strncmp(char const *s1, char const *s2, unsigned int n); + +#endif /* HAVE_STRING_H */ + +/** + * Copy a value repeatedly into a block of memory + * + * @param dest the destination address. + * @param val the value. + * @param n the number of bytes to copy. + * @return Nothing + * @see memset + */ +void sli_memset(unsigned char *dest, const char val, unsigned int n); + +/** + * Prints a string to stdout (using plat_putByte) + * + * @param s Pointer to the C string to print + */ +void sli_puts(uint8_t * s); + +/** + * Formats a 32-bit signed int as a decimal value. + * + * @param value the 32-bit signed value + * @param buf a pointer to where the formatted string goes + * @param buflen the length of the given buffer in bytes + * @return a pointer to the string. + */ +PmReturn_t sli_ltoa10(int32_t value, uint8_t *buf, uint8_t buflen); + +/** + * Formats an 8-bit int as a hexadecimal value. + * + * @param value the 8-bit value + * @param buf a pointer to where the formatted string goes + * @param buflen the length of the given buffer in bytes + * @param upperCase when zero, hex chars rendered lowercase, else uppercase + * @return Always PM_RET_OK + */ +PmReturn_t sli_btoa16(uint8_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase); + +/** + * Formats a 32-bit signed int as a hexadecimal value. + * + * @param value the 32-bit signed value + * @param buf a pointer to where the formatted string goes + * @param buflen the length of the given buffer in bytes + * @param upperCase when zero, hex chars rendered lowercase, else uppercase + * @return Always PM_RET_OK + */ +PmReturn_t sli_ltoa16(int32_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase); + +/** + * Formats a pointer as a hexadecimal value. + * + * @param value the pointer + * @param buf a pointer to where the formatted string goes + * @param buflen the length of the given buffer in bytes + * @param upperCase when zero, hex chars rendered lowercase, else uppercase + * @return Always PM_RET_OK + */ +PmReturn_t sli_ptoa16(intptr_t value, uint8_t *buf, uint8_t buflen, uint8_t upperCase); + +/** + * Formats a 32-bit (single-precision) float as an ascii string. + * + * @param f the float value + * @param buf a pointer to where the formatted string goes + * @param buflen the size of the buffer + * @return Status + */ +PmReturn_t sli_ftoa(float f, uint8_t *buf, uint8_t buflen); + +#endif /* __SLI_H__ */
--- /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 */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/strobj.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,215 @@ +/* +# 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. +*/ + + +#ifndef __STRING_H__ +#define __STRING_H__ + + +/** + * \file + * \brief String Object Type + * + * String object type header. + */ + + +/** Set to nonzero to enable string cache. DO NOT REMOVE THE DEFINITION. */ +#define USE_STRING_CACHE 1 + + +/** + * Loads a string from image + * + * @param ms memoryspace paddr points to + * @param paddr address in memoryspace of source string + * @param r_pstring Return by reference; a new string object + * @return Return status + */ +#define string_loadFromImg(ms, paddr, r_pstring) \ + string_create((ms), (paddr), (int16_t)-1, (int16_t)1, (r_pstring)) + +/** + * Creates String object from character array in RAM + * + * @param paddr pointer to address of source string + * @param r_pstring Return arg; addr of ptr to string + */ +#define string_new(paddr, r_pstring) \ + string_create(MEMSPACE_RAM, (uint8_t const **)(paddr), 0, (int16_t)1, (r_pstring)) + +/** + * Creates String object from character array in RAM which may contain + * embedded null characters. + * + * @param paddr pointer to address of source string + * @param len length of source string + * @param r_pstring Return arg; addr of ptr to string + */ +#define string_newWithLen(paddr, len, r_pstring) \ + string_create(MEMSPACE_RAM, (uint8_t const **)(paddr), (len), (int16_t)1, \ + (r_pstring)) + +/** + * Creates String object by replicating an existing C string, n times + * + * @param paddr pointer to address of source string + * @param n number of times to replicate the source string + * @param r_pstring Return arg; addr of ptr to string + */ +#define string_replicate(paddr, n, r_pstring) \ + string_create(MEMSPACE_RAM, (paddr), (uint8_t)0, (n), (r_pstring)) + +/*************************************************************** + * Types + **************************************************************/ + +/** + * String obj + * + * Null terminated array of chars. + */ +typedef struct PmString_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** Length of string */ + uint16_t length; + +#if USE_STRING_CACHE + /** Ptr to next string in cache */ + struct PmString_s *next; +#endif /* USE_STRING_CACHE */ + + /** + * Null-term char array + * + * Use length 1 here so that string-alloc function can use + * "sizeof(PmString_t) + len" and there will be room for the null-term + */ + uint8_t val[1]; +} PmString_t, + *pPmString_t; + + +/*************************************************************** + * Prototypes + **************************************************************/ + +/** + * Creates a new String obj. + * If len is less than zero, load from a String image. + * If len is zero, copy from a C string (which has a null terminator) + * If len is positive, copy as many chars as given in the len argument + * A string image has the following structure: + * -type: int8 - OBJ_TYPE_STRING + * -length: uint16 - number of bytes in the string + * -val: uint8[] - array of chars with null term + * + * Returns by reference a ptr to String obj. + * + * Obtain space for String from the heap. + * Copy string from memspace. + * Leave contents of paddr pointing one byte past end of str. + * + * THE PROGRAMMER SHOULD NOT CALL THIS FUNCTION DIRECTLY. + * Instead, use one of the two macros string_loadFromImg() + * or string_new(). + * + * @param memspace memory space where *paddr points + * @param paddr ptr to ptr to null term character array or image. + * @param len length of the C character array + * (use -1 for string images, 0 for C strings) + * @param n Number of times to replicate the given string argument + * @param r_pstring Return by reference; ptr to String obj + * @return Return status + */ +PmReturn_t string_create(PmMemSpace_t memspace, uint8_t const **paddr, + int16_t len, int16_t n, pPmObj_t *r_pstring); + +/** + * Creates a new String object from a single character. + * + * @param c The character to become the string + * @param r_pstring Return by reference; ptr to String obj + * @return Return status + */ +PmReturn_t string_newFromChar(uint8_t const c, pPmObj_t *r_pstring); + +/** + * Compares two String objects for equality. + * + * @param pstr1 Ptr to first string + * @param pstr2 Ptr to second string + * @return C_SAME if the strings are equivalent, C_DIFFER otherwise + */ +int8_t string_compare(pPmString_t pstr1, pPmString_t pstr2); + +#ifdef HAVE_PRINT +/** + * Sends out a string object bytewise. Escaping and framing is configurable + * via is_escaped. + * + * @param pstr Ptr to string object + * @param is_escaped If 0, print out string as is. Otherwise escape unprintable + * characters and surround string with single quotes. + * @return Return status + */ +PmReturn_t string_print(pPmObj_t pstr, uint8_t is_escaped); +#endif /* HAVE_PRINT */ + +/** + * Clears the string cache if one exists. + * Called by heap_init() + * + * @return Return status + */ +PmReturn_t string_cacheInit(void); + + +/** Returns a pointer to the base of the string cache */ +PmReturn_t string_getCache(pPmString_t **r_ppstrcache); + +/** + * Returns a new string object that is the concatenation + * of the two given strings. + * + * @param pstr1 First source string + * @param pstr2 Second source string + * @param r_pstring Return arg; ptr to new string object + * @return Return status + */ +PmReturn_t +string_concat(pPmString_t pstr1, pPmString_t pstr2, pPmObj_t *r_pstring); + +/** + * Returns a new string object that is created from the given format string + * and the argument(s). + * + * @param pstr Format string object + * @param parg Single argument or tuple of arguments + * @param r_pstring Return arg; ptr to new string object + * @return Return status + */ +PmReturn_t string_format(pPmString_t pstr, pPmObj_t parg, pPmObj_t *r_pstring); + +#ifdef HAVE_PRINT +/** + * Prints n bytes, formatting them if is_escaped is true + * + * @param pb Pointer to C bytes + * @param is_escaped Boolean true if string is to be escaped + * @param n Number of bytes to print + * @return Return status + */ +PmReturn_t string_printFormattedBytes(uint8_t *pb, + uint8_t is_escaped, + uint16_t n); +#endif /* HAVE_PRINT */ + +#endif /* __STRING_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/thread.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,50 @@ +/* +# This file is Copyright 2007 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__ 0x16 + + +/** + * \file + * \brief VM Thread + * + * Encapsulating a frame pointer, a root code object and thread state. + */ + + +#include "pm.h" + + +PmReturn_t +thread_new(pPmObj_t pframe, pPmObj_t *r_pobj) +{ + PmReturn_t retval = PM_RET_OK; + pPmThread_t pthread = C_NULL; + + C_ASSERT(pframe != C_NULL); + + /* If it's not a frame, raise TypeError */ + if (OBJ_GET_TYPE(pframe) != OBJ_TYPE_FRM) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + /* Allocate a thread */ + retval = heap_getChunk(sizeof(PmThread_t), (uint8_t **)r_pobj); + PM_RETURN_IF_ERROR(retval); + + /* Set type, frame and initialize status */ + pthread = (pPmThread_t)*r_pobj; + OBJ_SET_TYPE(pthread, OBJ_TYPE_THR); + pthread->pframe = (pPmFrame_t)pframe; + pthread->interpctrl = INTERP_CTRL_CONT; + + return retval; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/thread.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,81 @@ +/* +# This file is Copyright 2007 Dean Hall. +# This file is part of the PyMite VM. +# This file is licensed under the MIT License. +# See the LICENSE file for details. +*/ + + +#ifndef __THREAD_H__ +#define __THREAD_H__ + + +/** + * \file + * \brief VM Thread + * + * Encapsulating a frame pointer, a root code object and thread state. + */ + + +#include "interp.h" + + + /** Frequency in Hz to switch threads */ +#define THREAD_RESCHEDULE_FREQUENCY 10 + + +/** + * Interpreter return values + * + * Used to control interpreter loop + * and indicate return value. + * Negative values indicate erroneous results. + * Positive values indicate "continue interpreting", + * but first do something special like reschedule threads + * or (TBD) sweep the heap. + */ +typedef enum PmInterpCtrl_e +{ + /* other erroneous exits go here with negative values */ + INTERP_CTRL_ERR = -1, /**< Generic error causes exit */ + INTERP_CTRL_EXIT = 0, /**< Normal execution exit */ + INTERP_CTRL_CONT = 1, /**< Continue interpreting */ + INTERP_CTRL_RESCHED = 2 /**< Reschedule threads */ + /* all positive values indicate "continue interpreting" */ +} PmInterpCtrl_t, *pPmInterpCtrl_t; + +/** + * Thread obj + * + */ +typedef struct PmThread_s +{ + /** object descriptor */ + PmObjDesc_t od; + + /** current frame pointer */ + pPmFrame_t pframe; + + /** + * Interpreter loop control value + * + * A positive value means continue interpreting. + * A zero value means normal interpreter exit. + * A negative value signals an error exit. + */ + PmInterpCtrl_t interpctrl; +} PmThread_t, + *pPmThread_t; + + +/** + * Constructs a thread for a root frame. + * + * @param pframe Frame object as a basis for this thread. + * @param r_pobj Return by reference; Ptr to the newly created thread object. + * @return Return status + */ +PmReturn_t thread_new(pPmObj_t pframe, pPmObj_t *r_pobj); + +#endif /* __THREAD_H__ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/tuple.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,194 @@ +/* +# 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__ 0x13 + + +/** + * \file + * \brief Tuple Object Type + * + * Tuple object type operations. + */ + + +#include "pm.h" + + +/* The follwing value should match that in pmImgCreator.py */ +#define MAX_TUPLE_LEN 253 + + +PmReturn_t +tuple_loadFromImg(PmMemSpace_t memspace, + uint8_t const **paddr, pPmObj_t *r_ptuple) +{ + PmReturn_t retval = PM_RET_OK; + uint8_t i = (uint8_t)0; + uint8_t n = (uint8_t)0; + uint8_t objid; + + /* Get num objs in tuple */ + n = mem_getByte(memspace, paddr); + + /* Create empty tuple */ + retval = tuple_new(n, r_ptuple); + PM_RETURN_IF_ERROR(retval); + ((pPmTuple_t)*r_ptuple)->length = 0; + + /* Load the next n objs into tuple */ + heap_gcPushTempRoot((pPmObj_t)*r_ptuple, &objid); + for (i = (uint8_t)0; i < n; i++) + { + retval = obj_loadFromImg(memspace, + paddr, + (pPmObj_t *)&(((pPmTuple_t)*r_ptuple)-> + val[i])); + if (retval != PM_RET_OK) + { + heap_gcPopTempRoot(objid); + return retval; + } + ((pPmTuple_t)*r_ptuple)->length++; + } + heap_gcPopTempRoot(objid); + return PM_RET_OK; +} + + +PmReturn_t +tuple_new(uint16_t n, pPmObj_t *r_ptuple) +{ + PmReturn_t retval = PM_RET_OK; + uint16_t size = 0; + + /* Raise a SystemError for a Tuple that is too large */ + if (n > MAX_TUPLE_LEN) + { + PM_RAISE(retval, PM_RET_EX_SYS); + return retval; + } + + /* Calc size of struct to hold tuple; (n-1) because PmTuple_t has val[1] */ + size = sizeof(PmTuple_t) + ((n - 1) * sizeof(pPmObj_t)); + + /* Allocate a tuple */ + retval = heap_getChunk(size, (uint8_t **)r_ptuple); + PM_RETURN_IF_ERROR(retval); + OBJ_SET_TYPE(*r_ptuple, OBJ_TYPE_TUP); + + /* Set the number of objs in the tuple */ + ((pPmTuple_t)*r_ptuple)->length = n; + + /* Clear entries in the tuple so the GC doesn't try to mark/sweep them */ + if (n > 0) + { + size = n; + while (--size > 0) + { + ((pPmTuple_t)*r_ptuple)->val[size] = C_NULL; + } + } + + /* No need to null the ptrs because they are set by the caller */ + return retval; +} + + +PmReturn_t +tuple_replicate(pPmObj_t ptup, int16_t n, pPmObj_t *r_ptuple) +{ + PmReturn_t retval = PM_RET_OK; + int16_t length; + int16_t i; + int16_t j; + + /* Raise TypeError if object is not a Tuple */ + if (OBJ_GET_TYPE(ptup) != OBJ_TYPE_TUP) + { + PM_RAISE(retval, PM_RET_EX_SYS); + return retval; + } + + C_ASSERT(n >= 0); + + /* Allocate the new tuple */ + length = ((pPmTuple_t)ptup)->length; + retval = tuple_new(length * n, r_ptuple); + PM_RETURN_IF_ERROR(retval); + + /* Copy src tuple the designated number of times */ + for (i = 0; i < n; i++) + { + for (j = 0; j < length; j++) + { + ((pPmTuple_t)*r_ptuple)->val[length * i + j] = + ((pPmTuple_t)ptup)->val[j]; + } + } + return retval; +} + + +PmReturn_t +tuple_getItem(pPmObj_t ptup, int16_t index, pPmObj_t *r_pobj) +{ + PmReturn_t retval = PM_RET_OK; + + /* Adjust for negative index */ + if (index < 0) + { + index += ((pPmTuple_t)ptup)->length; + } + + /* Raise IndexError if index is out of bounds */ + if ((index < 0) || (index > ((pPmTuple_t)ptup)->length)) + { + PM_RAISE(retval, PM_RET_EX_INDX); + } + + /* Get the tuple item */ + *r_pobj = ((pPmTuple_t)ptup)->val[index]; + + return retval; +} + + +#ifdef HAVE_PRINT +PmReturn_t +tuple_print(pPmObj_t ptup) +{ + PmReturn_t retval = PM_RET_OK; + int16_t index; + + C_ASSERT(ptup != C_NULL); + + /* If it's not a tuple, raise TypeError */ + if (OBJ_GET_TYPE(ptup) != OBJ_TYPE_TUP) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } + + plat_putByte('('); + + for (index = 0; index < ((pPmTuple_t)ptup)->length; index++) + { + if (index != 0) + { + plat_putByte(','); + plat_putByte(' '); + } + retval = obj_print(((pPmTuple_t)ptup)->val[index], C_FALSE, C_TRUE); + PM_RETURN_IF_ERROR(retval); + } + + return plat_putByte(')'); +} +#endif /* HAVE_PRINT */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/tuple.h Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,109 @@ +/* +# 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. +*/ + + +#ifndef __TUPLE_H__ +#define __TUPLE_H__ + + +/** + * \file + * \brief Tuple Object Type + * + * Tuple object type header. + */ + +/** + * Tuple obj + * + * Immutable ordered sequence. Contains array of ptrs to objs. + */ +typedef struct PmTuple_s +{ + /** Object descriptor */ + PmObjDesc_t od; + + /** + * Length of tuple + * I don't expect a tuple to ever exceed 255 elements, + * but if I set this type to int8_t, a 0-element tuple + * is too small to be allocated. + */ + uint16_t length; + + /** Array of ptrs to objs */ + pPmObj_t val[1]; +} PmTuple_t, + *pPmTuple_t; + + +#define tuple_copy(src, dest) tuple_replicate((src), 1, (dest)) + + +/** + * Creates a Tuple by loading a tuple image from memory. + * + * Obtain space for tuple from the heap. + * Load all objs within the tuple img. + * Leave contents of paddr pointing one byte past end of + * last obj in tuple. + * + * The tuple image has the following structure: + * -type: S8 - OBJ_TYPE_TUPLE + * -length U8 - N number of objects in the tuple. + * N objects follow in the stream. + * + * @param memspace Memory space. + * @param paddr Ptr to ptr to tuple in memspace + * @param r_ptuple Return by reference; new filled tuple + * @return Return status + */ +PmReturn_t tuple_loadFromImg(PmMemSpace_t memspace, + uint8_t const **paddr, pPmObj_t *r_ptuple); + +/** + * Allocates space for a new Tuple. Returns a pointer to the tuple. + * + * @param n the number of elements the tuple will contain + * @param r_ptuple Return by ref, ptr to new tuple + * @return Return status + */ +PmReturn_t tuple_new(uint16_t n, pPmObj_t *r_ptuple); + +/** + * Replicates a tuple, n number of times to create a new tuple + * + * Copies the pointers (not the objects). + * + * @param ptup Ptr to source tuple. + * @param n Number of times to replicate the tuple. + * @param r_ptuple Return arg; Ptr to new tuple. + * @return Return status + */ +PmReturn_t tuple_replicate(pPmObj_t ptup, int16_t n, pPmObj_t *r_ptuple); + +/** + * Gets the object in the tuple at the index. + * + * @param ptup Ptr to tuple obj + * @param index Index into tuple + * @param r_pobj Return by reference; ptr to item + * @return Return status + */ +PmReturn_t tuple_getItem(pPmObj_t ptup, int16_t index, pPmObj_t *r_pobj); + +#ifdef HAVE_PRINT +/** + * Prints out a tuple. Uses obj_print() to print elements. + * + * @param pobj Object to print. + * @return Return status + */ +PmReturn_t tuple_print(pPmObj_t pobj); +#endif /* HAVE_PRINT */ + +#endif /* __TUPLE_H__ */