Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2. ================================================================================
  3.  
  4. tinypy contains tinypy code licensed in a MIT format license.  It also
  5. contains some goodies grabbed from Python, so that license is included
  6. as well.
  7.  
  8. ================================================================================
  9.  
  10. The tinypy License
  11.  
  12. Copyright (c) 2008 Phil Hassey
  13.  
  14. Permission is hereby granted, free of charge, to any person obtaining a copy
  15. of this software and associated documentation files (the "Software"), to deal
  16. in the Software without restriction, including without limitation the rights
  17. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  18. copies of the Software, and to permit persons to whom the Software is
  19. furnished to do so, subject to the following conditions:
  20.  
  21. The above copyright notice and this permission notice shall be included in
  22. all copies or substantial portions of the Software.
  23.  
  24. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  25. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  26. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  27. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  28. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  29. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  30. THE SOFTWARE.
  31.  
  32. ================================================================================
  33.  
  34. PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
  35. --------------------------------------------
  36.  
  37. 1. This LICENSE AGREEMENT is between the Python Software Foundation
  38. ("PSF"), and the Individual or Organization ("Licensee") accessing and
  39. otherwise using this software ("Python") in source or binary form and
  40. its associated documentation.
  41.  
  42. 2. Subject to the terms and conditions of this License Agreement, PSF
  43. hereby grants Licensee a nonexclusive, royalty-free, world-wide
  44. license to reproduce, analyze, test, perform and/or display publicly,
  45. prepare derivative works, distribute, and otherwise use Python
  46. alone or in any derivative version, provided, however, that PSF's
  47. License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
  48. 2001, 2002, 2003, 2004, 2005, 2006, 2007 Python Software Foundation;
  49. All Rights Reserved" are retained in Python alone or in any derivative
  50. version prepared by Licensee.
  51.  
  52. 3. In the event Licensee prepares a derivative work that is based on
  53. or incorporates Python or any part thereof, and wants to make
  54. the derivative work available to others as provided herein, then
  55. Licensee hereby agrees to include in any such work a brief summary of
  56. the changes made to Python.
  57.  
  58. 4. PSF is making Python available to Licensee on an "AS IS"
  59. basis.  PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
  60. IMPLIED.  BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
  61. DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
  62. FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
  63. INFRINGE ANY THIRD PARTY RIGHTS.
  64.  
  65. 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
  66. FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
  67. A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
  68. OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
  69.  
  70. 6. This License Agreement will automatically terminate upon a material
  71. breach of its terms and conditions.
  72.  
  73. 7. Nothing in this License Agreement shall be deemed to create any
  74. relationship of agency, partnership, or joint venture between PSF and
  75. Licensee.  This License Agreement does not grant permission to use PSF
  76. trademarks or trade name in a trademark sense to endorse or promote
  77. products or services of Licensee, or any third party.
  78.  
  79. 8. By copying, installing or otherwise using Python, Licensee
  80. agrees to be bound by the terms and conditions of this License
  81. Agreement.
  82.  
  83. ================================================================================
  84. */
  85.  
  86. #ifndef TINYPY_H
  87. #define TINYPY_H
  88. /* File: General
  89.  * Things defined in tp.h.
  90.  */
  91. #ifndef TP_H
  92. #define TP_H
  93.  
  94. #include <setjmp.h>
  95. #include <sys/stat.h>
  96.  
  97. #ifndef __USE_ISOC99
  98. #define __USE_ISOC99
  99. #endif
  100. #include <stdio.h>
  101. #include <stdlib.h>
  102. #include <string.h>
  103. #include <stdarg.h>
  104. #include <math.h>
  105. #include <time.h>
  106.  
  107. #include "bc.c"
  108.  
  109. #ifdef __GNUC__
  110. #define tp_inline __inline__
  111. #endif
  112.  
  113. #ifdef _MSC_VER
  114. #ifdef NDEBUG
  115. #define tp_inline __inline
  116. #else
  117. /* don't inline in debug builds (for easier debugging) */
  118. #define tp_inline
  119. #endif
  120. #endif
  121.  
  122. #ifndef tp_inline
  123. #error "Unsuported compiler"
  124. #endif
  125.  
  126. #define TP_CSTR(v) ((tp_str(tp,(v))).string.val)
  127.  
  128. /*  #define tp_malloc(x) calloc((x),1)
  129.     #define tp_realloc(x,y) realloc(x,y)
  130.     #define tp_free(x) free(x) */
  131.  
  132. /* #include <gc/gc.h>
  133.    #define tp_malloc(x) GC_MALLOC(x)
  134.    #define tp_realloc(x,y) GC_REALLOC(x,y)
  135.    #define tp_free(x)*/
  136.  
  137. enum {
  138.     TP_NONE,TP_NUMBER,TP_STRING,TP_DICT,
  139.     TP_LIST,TP_FNC,TP_DATA,
  140. };
  141.  
  142. typedef double tp_num;
  143.  
  144. typedef struct tp_number_ {
  145.     int type;
  146.     tp_num val;
  147. } tp_number_;
  148. typedef struct tp_string_ {
  149.     int type;
  150.     struct _tp_string *info;
  151.     char const *val;
  152.     int len;
  153. } tp_string_;
  154. typedef struct tp_list_ {
  155.     int type;
  156.     struct _tp_list *val;
  157. } tp_list_;
  158. typedef struct tp_dict_ {
  159.     int type;
  160.     struct _tp_dict *val;
  161.     int dtype;
  162. } tp_dict_;
  163. typedef struct tp_fnc_ {
  164.     int type;
  165.     struct _tp_fnc *info;
  166.     int ftype;
  167.     void *cfnc;
  168. } tp_fnc_;
  169. typedef struct tp_data_ {
  170.     int type;
  171.     struct _tp_data *info;
  172.     void *val;
  173.     int magic;
  174. } tp_data_;
  175.  
  176. /* Type: tp_obj
  177.  * Tinypy's object representation.
  178.  *
  179.  * Every object in tinypy is of this type in the C API.
  180.  *
  181.  * Fields:
  182.  * type - This determines what kind of objects it is. It is either TP_NONE, in
  183.  *        which case this is the none type and no other fields can be accessed.
  184.  *        Or it has one of the values listed below, and the corresponding
  185.  *        fields can be accessed.
  186.  * number - TP_NUMBER
  187.  * number.val - A double value with the numeric value.
  188.  * string - TP_STRING
  189.  * string.val - A pointer to the string data.
  190.  * string.len - Length in bytes of the string data.
  191.  * dict - TP_DICT
  192.  * list - TP_LIST
  193.  * fnc - TP_FNC
  194.  * data - TP_DATA
  195.  * data.val - The user-provided data pointer.
  196.  * data.magic - The user-provided magic number for identifying the data type.
  197.  */
  198. typedef union tp_obj {
  199.     int type;
  200.     tp_number_ number;
  201.     struct { int type; int *data; } gci;
  202.     tp_string_ string;
  203.     tp_dict_ dict;
  204.     tp_list_ list;
  205.     tp_fnc_ fnc;
  206.     tp_data_ data;
  207. } tp_obj;
  208.  
  209. typedef struct _tp_string {
  210.     int gci;
  211.     int len;
  212.     char s[1];
  213. } _tp_string;
  214. typedef struct _tp_list {
  215.     int gci;
  216.     tp_obj *items;
  217.     int len;
  218.     int alloc;
  219. } _tp_list;
  220. typedef struct tp_item {
  221.     int used;
  222.     int hash;
  223.     tp_obj key;
  224.     tp_obj val;
  225. } tp_item;
  226. typedef struct _tp_dict {
  227.     int gci;
  228.     tp_item *items;
  229.     int len;
  230.     int alloc;
  231.     int cur;
  232.     int mask;
  233.     int used;
  234.     tp_obj meta;
  235. } _tp_dict;
  236. typedef struct _tp_fnc {
  237.     int gci;
  238.     tp_obj self;
  239.     tp_obj globals;
  240.     tp_obj code;
  241. } _tp_fnc;
  242.  
  243.  
  244. typedef union tp_code {
  245.     unsigned char i;
  246.     struct { unsigned char i,a,b,c; } regs;
  247.     struct { char val[4]; } string;
  248.     struct { float val; } number;
  249. } tp_code;
  250.  
  251. typedef struct tp_frame_ {
  252. /*    tp_code *codes; */
  253.     tp_obj code;
  254.     tp_code *cur;
  255.     tp_code *jmp;
  256.     tp_obj *regs;
  257.     tp_obj *ret_dest;
  258.     tp_obj fname;
  259.     tp_obj name;
  260.     tp_obj line;
  261.     tp_obj globals;
  262.     int lineno;
  263.     int cregs;
  264. } tp_frame_;
  265.  
  266. #define TP_GCMAX 4096
  267. #define TP_FRAMES 256
  268. #define TP_REGS_EXTRA 2
  269. /* #define TP_REGS_PER_FRAME 256*/
  270. #define TP_REGS 16384
  271.  
  272. /* Type: tp_vm
  273.  * Representation of a tinypy virtual machine instance.
  274.  *
  275.  * A new tp_vm struct is created with <tp_init>, and will be passed to most
  276.  * tinypy functions as first parameter. It contains all the data associated
  277.  * with an instance of a tinypy virtual machine - so it is easy to have
  278.  * multiple instances running at the same time. When you want to free up all
  279.  * memory used by an instance, call <tp_deinit>.
  280.  *
  281.  * Fields:
  282.  * These fields are currently documented:
  283.  *
  284.  * builtins - A dictionary containing all builtin objects.
  285.  * modules - A dictionary with all loaded modules.
  286.  * params - A list of parameters for the current function call.
  287.  * frames - A list of all call frames.
  288.  * cur - The index of the currently executing call frame.
  289.  * frames[n].globals - A dictionary of global sybmols in callframe n.
  290.  */
  291. typedef struct tp_vm {
  292.     tp_obj builtins;
  293.     tp_obj modules;
  294.     tp_frame_ frames[TP_FRAMES];
  295.     tp_obj _params;
  296.     tp_obj params;
  297.     tp_obj _regs;
  298.     tp_obj *regs;
  299.     tp_obj root;
  300.     jmp_buf buf;
  301. #ifdef CPYTHON_MOD
  302.     jmp_buf nextexpr;
  303. #endif
  304.     int jmp;
  305.     tp_obj ex;
  306.     char chars[256][2];
  307.     int cur;
  308.     /* gc */
  309.     _tp_list *white;
  310.     _tp_list *grey;
  311.     _tp_list *black;
  312.     int steps;
  313.     /* sandbox */
  314.     clock_t clocks;
  315.     double time_elapsed;
  316.     double time_limit;
  317.     unsigned long mem_limit;
  318.     unsigned long mem_used;
  319.     int mem_exceeded;
  320. } tp_vm;
  321.  
  322. #define TP tp_vm *tp
  323. typedef struct _tp_data {
  324.     int gci;
  325.     void (*free)(TP,tp_obj);
  326. } _tp_data;
  327.  
  328. #define tp_True tp_number(1)
  329. #define tp_False tp_number(0)
  330.  
  331. extern tp_obj tp_None;
  332.  
  333. #ifdef TP_SANDBOX
  334. void *tp_malloc(TP, unsigned long);
  335. void *tp_realloc(TP, void *, unsigned long);
  336. void tp_free(TP, void *);
  337. #else
  338. #define tp_malloc(TP,x) calloc((x),1)
  339. #define tp_realloc(TP,x,y) realloc(x,y)
  340. #define tp_free(TP,x) free(x)
  341. #endif
  342.  
  343. void tp_sandbox(TP, double, unsigned long);
  344. void tp_time_update(TP);
  345. void tp_mem_update(TP);
  346.  
  347. void tp_run(TP,int cur);
  348. void tp_set(TP,tp_obj,tp_obj,tp_obj);
  349. tp_obj tp_get(TP,tp_obj,tp_obj);
  350. tp_obj tp_has(TP,tp_obj self, tp_obj k);
  351. tp_obj tp_len(TP,tp_obj);
  352. void tp_del(TP,tp_obj,tp_obj);
  353. tp_obj tp_str(TP,tp_obj);
  354. int tp_bool(TP,tp_obj);
  355. int tp_cmp(TP,tp_obj,tp_obj);
  356. void _tp_raise(TP,tp_obj);
  357. tp_obj tp_printf(TP,char const *fmt,...);
  358. tp_obj tp_track(TP,tp_obj);
  359. void tp_grey(TP,tp_obj);
  360. tp_obj tp_call(TP, tp_obj fnc, tp_obj params);
  361. tp_obj tp_add(TP,tp_obj a, tp_obj b) ;
  362.  
  363. /* __func__ __VA_ARGS__ __FILE__ __LINE__ */
  364.  
  365. /* Function: tp_raise
  366.  * Macro to raise an exception.
  367.  *
  368.  * This macro will return from the current function returning "r". The
  369.  * remaining parameters are used to format the exception message.
  370.  */
  371. /*
  372. #define tp_raise(r,fmt,...) { \
  373.     _tp_raise(tp,tp_printf(tp,fmt,__VA_ARGS__)); \
  374.     return r; \
  375. }
  376. */
  377. #define tp_raise(r,v) { \
  378.     _tp_raise(tp,v); \
  379.     return r; \
  380. }
  381.  
  382. /* Function: tp_string
  383.  * Creates a new string object from a C string.
  384.  *
  385.  * Given a pointer to a C string, creates a tinypy object representing the
  386.  * same string.
  387.  *
  388.  * *Note* Only a reference to the string will be kept by tinypy, so make sure
  389.  * it does not go out of scope, and don't de-allocate it. Also be aware that
  390.  * tinypy will not delete the string for you. In many cases, it is best to
  391.  * use <tp_string_t> or <tp_string_slice> to create a string where tinypy
  392.  * manages storage for you.
  393.  */
  394. tp_inline static tp_obj tp_string(char const *v) {
  395.     tp_obj val;
  396.     tp_string_ s = {TP_STRING, 0, v, 0};
  397.     s.len = strlen(v);
  398.     val.string = s;
  399.     return val;
  400. }
  401.  
  402. #define TP_CSTR_LEN 256
  403.  
  404. tp_inline static void tp_cstr(TP,tp_obj v, char *s, int l) {
  405.     if (v.type != TP_STRING) {
  406.         tp_raise(,tp_string("(tp_cstr) TypeError: value not a string"));
  407.     }
  408.     if (v.string.len >= l) {
  409.         tp_raise(,tp_string("(tp_cstr) TypeError: value too long"));
  410.     }
  411.     memset(s,0,l);
  412.     memcpy(s,v.string.val,v.string.len);
  413. }
  414.  
  415.  
  416. #define TP_OBJ() (tp_get(tp,tp->params,tp_None))
  417. tp_inline static tp_obj tp_type(TP,int t,tp_obj v) {
  418.     if (v.type != t) { tp_raise(tp_None,tp_string("(tp_type) TypeError: unexpected type")); }
  419.     return v;
  420. }
  421.  
  422.  
  423.  
  424. #define TP_NO_LIMIT 0
  425. #define TP_TYPE(t) tp_type(tp,t,TP_OBJ())
  426. #define TP_NUM() (TP_TYPE(TP_NUMBER).number.val)
  427. /* #define TP_STR() (TP_CSTR(TP_TYPE(TP_STRING))) */
  428. #define TP_STR() (TP_TYPE(TP_STRING))
  429. #define TP_DEFAULT(d) (tp->params.list.val->len?tp_get(tp,tp->params,tp_None):(d))
  430.  
  431. /* Macro: TP_LOOP
  432.  * Macro to iterate over all remaining arguments.
  433.  *
  434.  * If you have a function which takes a variable number of arguments, you can
  435.  * iterate through all remaining arguments for example like this:
  436.  *
  437.  * > tp_obj *my_func(tp_vm *tp)
  438.  * > {
  439.  * >     // We retrieve the first argument like normal.
  440.  * >     tp_obj first = TP_OBJ();
  441.  * >     // Then we iterate over the remaining arguments.
  442.  * >     tp_obj arg;
  443.  * >     TP_LOOP(arg)
  444.  * >         // do something with arg
  445.  * >     TP_END
  446.  * > }
  447.  */
  448. #define TP_LOOP(e) \
  449.     int __l = tp->params.list.val->len; \
  450.     int __i; for (__i=0; __i<__l; __i++) { \
  451.     (e) = _tp_list_get(tp,tp->params.list.val,__i,"TP_LOOP");
  452. #define TP_END \
  453.     }
  454.  
  455. tp_inline static int _tp_min(int a, int b) { return (a<b?a:b); }
  456. tp_inline static int _tp_max(int a, int b) { return (a>b?a:b); }
  457. tp_inline static int _tp_sign(tp_num v) { return (v<0?-1:(v>0?1:0)); }
  458.  
  459. /* Function: tp_number
  460.  * Creates a new numeric object.
  461.  */
  462. tp_inline static tp_obj tp_number(tp_num v) {
  463.     tp_obj val = {TP_NUMBER};
  464.     val.number.val = v;
  465.     return val;
  466. }
  467.  
  468. tp_inline static void tp_echo(TP,tp_obj e) {
  469.     e = tp_str(tp,e);
  470.     fwrite(e.string.val,1,e.string.len,stdout);
  471. }
  472.  
  473. /* Function: tp_string_n
  474.  * Creates a new string object from a partial C string.
  475.  *
  476.  * Like <tp_string>, but you specify how many bytes of the given C string to
  477.  * use for the string object. The *note* also applies for this function, as the
  478.  * string reference and length are kept, but no actual substring is stored.
  479.  */
  480. tp_inline static tp_obj tp_string_n(char const *v,int n) {
  481.     tp_obj val;
  482.     tp_string_ s = {TP_STRING, 0,v,n};
  483.     val.string = s;
  484.     return val;
  485. }
  486.  
  487. #endif
  488. void _tp_list_realloc(TP, _tp_list *self,int len) ;
  489. void _tp_list_set(TP,_tp_list *self,int k, tp_obj v, const char *error) ;
  490. void _tp_list_free(TP, _tp_list *self) ;
  491. tp_obj _tp_list_get(TP,_tp_list *self,int k,const char *error) ;
  492. void _tp_list_insertx(TP,_tp_list *self, int n, tp_obj v) ;
  493. void _tp_list_appendx(TP,_tp_list *self, tp_obj v) ;
  494. void _tp_list_insert(TP,_tp_list *self, int n, tp_obj v) ;
  495. void _tp_list_append(TP,_tp_list *self, tp_obj v) ;
  496. tp_obj _tp_list_pop(TP,_tp_list *self, int n, const char *error) ;
  497. int _tp_list_find(TP,_tp_list *self, tp_obj v) ;
  498. tp_obj tp_index(TP) ;
  499. _tp_list *_tp_list_new(TP) ;
  500. tp_obj _tp_list_copy(TP, tp_obj rr) ;
  501. tp_obj tp_append(TP) ;
  502. tp_obj tp_pop(TP) ;
  503. tp_obj tp_insert(TP) ;
  504. tp_obj tp_extend(TP) ;
  505. tp_obj tp_list_nt(TP) ;
  506. tp_obj tp_list(TP) ;
  507. tp_obj tp_list_n(TP,int n,tp_obj *argv) ;
  508. int _tp_sort_cmp(tp_obj *a,tp_obj *b) ;
  509. tp_obj tp_sort(TP) ;
  510. int tp_lua_hash(void const *v,int l) ;
  511. void _tp_dict_free(TP, _tp_dict *self) ;
  512. int tp_hash(TP,tp_obj v) ;
  513. void _tp_dict_hash_set(TP,_tp_dict *self, int hash, tp_obj k, tp_obj v) ;
  514. void _tp_dict_tp_realloc(TP,_tp_dict *self,int len) ;
  515. int _tp_dict_hash_find(TP,_tp_dict *self, int hash, tp_obj k) ;
  516. int _tp_dict_find(TP,_tp_dict *self,tp_obj k) ;
  517. void _tp_dict_setx(TP,_tp_dict *self,tp_obj k, tp_obj v) ;
  518. void _tp_dict_set(TP,_tp_dict *self,tp_obj k, tp_obj v) ;
  519. tp_obj _tp_dict_get(TP,_tp_dict *self,tp_obj k, const char *error) ;
  520. void _tp_dict_del(TP,_tp_dict *self,tp_obj k, const char *error) ;
  521. _tp_dict *_tp_dict_new(TP) ;
  522. tp_obj _tp_dict_copy(TP,tp_obj rr) ;
  523. int _tp_dict_next(TP,_tp_dict *self) ;
  524. tp_obj tp_merge(TP) ;
  525. tp_obj tp_dict(TP) ;
  526. tp_obj tp_dict_n(TP,int n, tp_obj* argv) ;
  527. tp_obj _tp_dcall(TP,tp_obj fnc(TP)) ;
  528. tp_obj _tp_tcall(TP,tp_obj fnc) ;
  529. tp_obj tp_fnc_new(TP,int t, void *v, tp_obj c,tp_obj s, tp_obj g) ;
  530. tp_obj tp_def(TP,tp_obj code, tp_obj g) ;
  531. tp_obj tp_fnc(TP,tp_obj v(TP)) ;
  532. tp_obj tp_method(TP,tp_obj self,tp_obj v(TP)) ;
  533. tp_obj tp_data(TP,int magic,void *v) ;
  534. tp_obj tp_params(TP) ;
  535. tp_obj tp_params_n(TP,int n, tp_obj argv[]) ;
  536. tp_obj tp_params_v(TP,int n,...) ;
  537. tp_obj tp_string_t(TP, int n) ;
  538. tp_obj tp_string_copy(TP, const char *s, int n) ;
  539. tp_obj tp_string_sub(TP, tp_obj s, int a, int b) ;
  540. int _tp_str_index(tp_obj s, tp_obj k) ;
  541. tp_obj tp_join(TP) ;
  542. tp_obj tp_split(TP) ;
  543. tp_obj tp_find(TP) ;
  544. tp_obj tp_str_index(TP) ;
  545. tp_obj tp_str2(TP) ;
  546. tp_obj tp_chr(TP) ;
  547. tp_obj tp_ord(TP) ;
  548. tp_obj tp_strip(TP) ;
  549. tp_obj tp_replace(TP) ;
  550. tp_obj tp_print(TP) ;
  551. tp_obj tp_bind(TP) ;
  552. tp_obj tp_min(TP) ;
  553. tp_obj tp_max(TP) ;
  554. tp_obj tp_copy(TP) ;
  555. tp_obj tp_len_(TP) ;
  556. tp_obj tp_assert(TP) ;
  557. tp_obj tp_range(TP) ;
  558. tp_obj tp_system(TP) ;
  559. tp_obj tp_istype(TP) ;
  560. tp_obj tp_float(TP) ;
  561. tp_obj tp_save(TP) ;
  562. tp_obj tp_load(TP) ;
  563. tp_obj tp_fpack(TP) ;
  564. tp_obj tp_abs(TP) ;
  565. tp_obj tp_int(TP) ;
  566. tp_num _roundf(tp_num v) ;
  567. tp_obj tp_round(TP) ;
  568. tp_obj tp_exists(TP) ;
  569. tp_obj tp_mtime(TP) ;
  570. int _tp_lookup_(TP,tp_obj self, tp_obj k, tp_obj *meta, int depth) ;
  571. int _tp_lookup(TP,tp_obj self, tp_obj k, tp_obj *meta) ;
  572. tp_obj tp_setmeta(TP) ;
  573. tp_obj tp_getmeta(TP) ;
  574. tp_obj tp_object(TP) ;
  575. tp_obj tp_object_new(TP) ;
  576. tp_obj tp_object_call(TP) ;
  577. tp_obj tp_getraw(TP) ;
  578. tp_obj tp_class(TP) ;
  579. tp_obj tp_builtins_bool(TP) ;
  580. void tp_follow(TP,tp_obj v) ;
  581. void tp_reset(TP) ;
  582. void tp_gc_init(TP) ;
  583. void tp_gc_deinit(TP) ;
  584. void tp_delete(TP,tp_obj v) ;
  585. void tp_collect(TP) ;
  586. void _tp_gcinc(TP) ;
  587. void tp_full(TP) ;
  588. void tp_gcinc(TP) ;
  589. tp_obj tp_iter(TP,tp_obj self, tp_obj k) ;
  590. int tp_iget(TP,tp_obj *r, tp_obj self, tp_obj k) ;
  591. tp_obj tp_mul(TP,tp_obj a, tp_obj b) ;
  592. tp_obj tp_bitwise_not(TP, tp_obj a) ;
  593. tp_vm *_tp_init(void) ;
  594. void tp_deinit(TP) ;
  595. void tp_frame(TP,tp_obj globals,tp_obj code,tp_obj *ret_dest) ;
  596. void tp_print_stack(TP) ;
  597. void tp_handle(TP) ;
  598. void tp_return(TP, tp_obj v) ;
  599. int tp_step(TP) ;
  600. void _tp_run(TP,int cur) ;
  601. tp_obj tp_ez_call(TP, const char *mod, const char *fnc, tp_obj params) ;
  602. tp_obj _tp_import(TP, tp_obj fname, tp_obj name, tp_obj code) ;
  603. tp_obj tp_import(TP, const char * fname, const char * name, void *codes, int len) ;
  604. tp_obj tp_exec_(TP) ;
  605. tp_obj tp_import_(TP) ;
  606. void tp_builtins(TP) ;
  607. void tp_args(TP,int argc, char *argv[]) ;
  608. tp_obj tp_main(TP,char *fname, void *code, int len) ;
  609. tp_obj tp_compile(TP, tp_obj text, tp_obj fname) ;
  610. tp_obj tp_exec(TP, tp_obj code, tp_obj globals) ;
  611. tp_obj tp_eval(TP, const char *text, tp_obj globals) ;
  612. tp_vm *tp_init(int argc, char *argv[]) ;
  613. void tp_compiler(TP) ;
  614. tp_obj tp_sandbox_(TP) ;
  615. void tp_bounds(TP, tp_code *cur, int n) ;
  616. #endif
  617.  
  618. void _tp_list_realloc(TP, _tp_list *self,int len) {
  619.     if (!len) { len=1; }
  620.     self->items = (tp_obj*)tp_realloc(tp, self->items,len*sizeof(tp_obj));
  621.     self->alloc = len;
  622. }
  623.  
  624. void _tp_list_set(TP,_tp_list *self,int k, tp_obj v, const char *error) {
  625.     if (k >= self->len) {
  626.         tp_raise(,tp_string("(_tp_list_set) KeyError"));
  627.     }
  628.     self->items[k] = v;
  629.     tp_grey(tp,v);
  630. }
  631. void _tp_list_free(TP, _tp_list *self) {
  632.     tp_free(tp, self->items);
  633.     tp_free(tp, self);
  634. }
  635.  
  636. tp_obj _tp_list_get(TP,_tp_list *self,int k,const char *error) {
  637.     if (k >= self->len) {
  638.         tp_raise(tp_None,tp_string("(_tp_list_set) KeyError"));
  639.     }
  640.     return self->items[k];
  641. }
  642. void _tp_list_insertx(TP,_tp_list *self, int n, tp_obj v) {
  643.     if (self->len >= self->alloc) {
  644.         _tp_list_realloc(tp, self,self->alloc*2);
  645.     }
  646.     if (n < self->len) { memmove(&self->items[n+1],&self->items[n],sizeof(tp_obj)*(self->len-n)); }
  647.     self->items[n] = v;
  648.     self->len += 1;
  649. }
  650. void _tp_list_appendx(TP,_tp_list *self, tp_obj v) {
  651.     _tp_list_insertx(tp,self,self->len,v);
  652. }
  653. void _tp_list_insert(TP,_tp_list *self, int n, tp_obj v) {
  654.     _tp_list_insertx(tp,self,n,v);
  655.     tp_grey(tp,v);
  656. }
  657. void _tp_list_append(TP,_tp_list *self, tp_obj v) {
  658.     _tp_list_insert(tp,self,self->len,v);
  659. }
  660. tp_obj _tp_list_pop(TP,_tp_list *self, int n, const char *error) {
  661.     tp_obj r = _tp_list_get(tp,self,n,error);
  662.     if (n != self->len-1) { memmove(&self->items[n],&self->items[n+1],sizeof(tp_obj)*(self->len-(n+1))); }
  663.     self->len -= 1;
  664.     return r;
  665. }
  666.  
  667. int _tp_list_find(TP,_tp_list *self, tp_obj v) {
  668.     int n;
  669.     for (n=0; n<self->len; n++) {
  670.         if (tp_cmp(tp,v,self->items[n]) == 0) {
  671.             return n;
  672.         }
  673.     }
  674.     return -1;
  675. }
  676.  
  677. tp_obj tp_index(TP) {
  678.     tp_obj self = TP_OBJ();
  679.     tp_obj v = TP_OBJ();
  680.     int i = _tp_list_find(tp,self.list.val,v);
  681.     if (i < 0) {
  682.         tp_raise(tp_None,tp_string("(tp_index) ValueError: list.index(x): x not in list"));
  683.     }
  684.     return tp_number(i);
  685. }
  686.  
  687. _tp_list *_tp_list_new(TP) {
  688.     return (_tp_list*)tp_malloc(tp, sizeof(_tp_list));
  689. }
  690.  
  691. tp_obj _tp_list_copy(TP, tp_obj rr) {
  692.     tp_obj val = {TP_LIST};
  693.     _tp_list *o = rr.list.val;
  694.     _tp_list *r = _tp_list_new(tp);
  695.     *r = *o; r->gci = 0;
  696.     r->items = (tp_obj*)tp_malloc(tp, sizeof(tp_obj)*o->len);
  697.     memcpy(r->items,o->items,sizeof(tp_obj)*o->len);
  698.     val.list.val = r;
  699.     return tp_track(tp,val);
  700. }
  701.  
  702. tp_obj tp_append(TP) {
  703.     tp_obj self = TP_OBJ();
  704.     tp_obj v = TP_OBJ();
  705.     _tp_list_append(tp,self.list.val,v);
  706.     return tp_None;
  707. }
  708.  
  709. tp_obj tp_pop(TP) {
  710.     tp_obj self = TP_OBJ();
  711.     return _tp_list_pop(tp,self.list.val,self.list.val->len-1,"pop");
  712. }
  713.  
  714. tp_obj tp_insert(TP) {
  715.     tp_obj self = TP_OBJ();
  716.     int n = TP_NUM();
  717.     tp_obj v = TP_OBJ();
  718.     _tp_list_insert(tp,self.list.val,n,v);
  719.     return tp_None;
  720. }
  721.  
  722. tp_obj tp_extend(TP) {
  723.     tp_obj self = TP_OBJ();
  724.     tp_obj v = TP_OBJ();
  725.     int i;
  726.     for (i=0; i<v.list.val->len; i++) {
  727.         _tp_list_append(tp,self.list.val,v.list.val->items[i]);
  728.     }
  729.     return tp_None;
  730. }
  731.  
  732. tp_obj tp_list_nt(TP) {
  733.     tp_obj r = {TP_LIST};
  734.     r.list.val = _tp_list_new(tp);
  735.     return r;
  736. }
  737.  
  738. tp_obj tp_list(TP) {
  739.     tp_obj r = {TP_LIST};
  740.     r.list.val = _tp_list_new(tp);
  741.     return tp_track(tp,r);
  742. }
  743.  
  744. tp_obj tp_list_n(TP,int n,tp_obj *argv) {
  745.     int i;
  746.     tp_obj r = tp_list(tp); _tp_list_realloc(tp, r.list.val,n);
  747.     for (i=0; i<n; i++) {
  748.         _tp_list_append(tp,r.list.val,argv[i]);
  749.     }
  750.     return r;
  751. }
  752.  
  753. int _tp_sort_cmp(tp_obj *a,tp_obj *b) {
  754.     return tp_cmp(0,*a,*b);
  755. }
  756.  
  757. tp_obj tp_sort(TP) {
  758.     tp_obj self = TP_OBJ();
  759.     qsort(self.list.val->items, self.list.val->len, sizeof(tp_obj), (int(*)(const void*,const void*))_tp_sort_cmp);
  760.     return tp_None;
  761. }
  762.  
  763. /* File: Dict
  764.  * Functions for dealing with dictionaries.
  765.  */
  766. int tp_lua_hash(void const *v,int l) {
  767.     int i,step = (l>>5)+1;
  768.     int h = l + (l >= 4?*(int*)v:0);
  769.     for (i=l; i>=step; i-=step) {
  770.         h = h^((h<<5)+(h>>2)+((unsigned char *)v)[i-1]);
  771.     }
  772.     return h;
  773. }
  774. void _tp_dict_free(TP, _tp_dict *self) {
  775.     tp_free(tp, self->items);
  776.     tp_free(tp, self);
  777. }
  778.  
  779. /* void _tp_dict_reset(_tp_dict *self) {
  780.        memset(self->items,0,self->alloc*sizeof(tp_item));
  781.        self->len = 0;
  782.        self->used = 0;
  783.        self->cur = 0;
  784.    }*/
  785.  
  786. int tp_hash(TP,tp_obj v) {
  787.     switch (v.type) {
  788.         case TP_NONE: return 0;
  789.         case TP_NUMBER: return tp_lua_hash(&v.number.val,sizeof(tp_num));
  790.         case TP_STRING: return tp_lua_hash(v.string.val,v.string.len);
  791.         case TP_DICT: return tp_lua_hash(&v.dict.val,sizeof(void*));
  792.         case TP_LIST: {
  793.             int r = v.list.val->len; int n; for(n=0; n<v.list.val->len; n++) {
  794.             tp_obj vv = v.list.val->items[n]; r += vv.type != TP_LIST?tp_hash(tp,v.list.val->items[n]):tp_lua_hash(&vv.list.val,sizeof(void*)); } return r;
  795.         }
  796.         case TP_FNC: return tp_lua_hash(&v.fnc.info,sizeof(void*));
  797.         case TP_DATA: return tp_lua_hash(&v.data.val,sizeof(void*));
  798.     }
  799.     tp_raise(0,tp_string("(tp_hash) TypeError: value unhashable"));
  800. }
  801.  
  802. void _tp_dict_hash_set(TP,_tp_dict *self, int hash, tp_obj k, tp_obj v) {
  803.     tp_item item;
  804.     int i,idx = hash&self->mask;
  805.     for (i=idx; i<idx+self->alloc; i++) {
  806.         int n = i&self->mask;
  807.         if (self->items[n].used > 0) { continue; }
  808.         if (self->items[n].used == 0) { self->used += 1; }
  809.         item.used = 1;
  810.         item.hash = hash;
  811.         item.key = k;
  812.         item.val = v;
  813.         self->items[n] = item;
  814.         self->len += 1;
  815.         return;
  816.     }
  817.     tp_raise(,tp_string("(_tp_dict_hash_set) RuntimeError: ?"));
  818. }
  819.  
  820. void _tp_dict_tp_realloc(TP,_tp_dict *self,int len) {
  821.     tp_item *items = self->items;
  822.     int i,alloc = self->alloc;
  823.     len = _tp_max(8,len);
  824.  
  825.     self->items = (tp_item*)tp_malloc(tp, len*sizeof(tp_item));
  826.     self->alloc = len; self->mask = len-1;
  827.     self->len = 0; self->used = 0;
  828.  
  829.     for (i=0; i<alloc; i++) {
  830.         if (items[i].used != 1) { continue; }
  831.         _tp_dict_hash_set(tp,self,items[i].hash,items[i].key,items[i].val);
  832.     }
  833.     tp_free(tp, items);
  834. }
  835.  
  836. int _tp_dict_hash_find(TP,_tp_dict *self, int hash, tp_obj k) {
  837.     int i,idx = hash&self->mask;
  838.     for (i=idx; i<idx+self->alloc; i++) {
  839.         int n = i&self->mask;
  840.         if (self->items[n].used == 0) { break; }
  841.         if (self->items[n].used < 0) { continue; }
  842.         if (self->items[n].hash != hash) { continue; }
  843.         if (tp_cmp(tp,self->items[n].key,k) != 0) { continue; }
  844.         return n;
  845.     }
  846.     return -1;
  847. }
  848. int _tp_dict_find(TP,_tp_dict *self,tp_obj k) {
  849.     return _tp_dict_hash_find(tp,self,tp_hash(tp,k),k);
  850. }
  851.  
  852. void _tp_dict_setx(TP,_tp_dict *self,tp_obj k, tp_obj v) {
  853.     int hash = tp_hash(tp,k); int n = _tp_dict_hash_find(tp,self,hash,k);
  854.     if (n == -1) {
  855.         if (self->len >= (self->alloc/2)) {
  856.             _tp_dict_tp_realloc(tp,self,self->alloc*2);
  857.         } else if (self->used >= (self->alloc*3/4)) {
  858.             _tp_dict_tp_realloc(tp,self,self->alloc);
  859.         }
  860.         _tp_dict_hash_set(tp,self,hash,k,v);
  861.     } else {
  862.         self->items[n].val = v;
  863.     }
  864. }
  865.  
  866. void _tp_dict_set(TP,_tp_dict *self,tp_obj k, tp_obj v) {
  867.     _tp_dict_setx(tp,self,k,v);
  868.     tp_grey(tp,k); tp_grey(tp,v);
  869. }
  870.  
  871. tp_obj _tp_dict_get(TP,_tp_dict *self,tp_obj k, const char *error) {
  872.     int n = _tp_dict_find(tp,self,k);
  873.     if (n < 0) {
  874.         tp_raise(tp_None,tp_add(tp,tp_string("(_tp_dict_get) KeyError: "),tp_str(tp,k)));
  875.     }
  876.     return self->items[n].val;
  877. }
  878.  
  879. void _tp_dict_del(TP,_tp_dict *self,tp_obj k, const char *error) {
  880.     int n = _tp_dict_find(tp,self,k);
  881.     if (n < 0) {
  882.         tp_raise(,tp_add(tp,tp_string("(_tp_dict_del) KeyError: "),tp_str(tp,k)));
  883.     }
  884.     self->items[n].used = -1;
  885.     self->len -= 1;
  886. }
  887.  
  888. _tp_dict *_tp_dict_new(TP) {
  889.     _tp_dict *self = (_tp_dict*)tp_malloc(tp, sizeof(_tp_dict));
  890.     return self;
  891. }
  892. tp_obj _tp_dict_copy(TP,tp_obj rr) {
  893.     tp_obj obj = {TP_DICT};
  894.     _tp_dict *o = rr.dict.val;
  895.     _tp_dict *r = _tp_dict_new(tp);
  896.     *r = *o; r->gci = 0;
  897.     r->items = (tp_item*)tp_malloc(tp, sizeof(tp_item)*o->alloc);
  898.     memcpy(r->items,o->items,sizeof(tp_item)*o->alloc);
  899.     obj.dict.val = r;
  900.     obj.dict.dtype = 1;
  901.     return tp_track(tp,obj);
  902. }
  903.  
  904. int _tp_dict_next(TP,_tp_dict *self) {
  905.     if (!self->len) {
  906.         tp_raise(0,tp_string("(_tp_dict_next) RuntimeError"));
  907.     }
  908.     while (1) {
  909.         self->cur = ((self->cur + 1) & self->mask);
  910.         if (self->items[self->cur].used > 0) {
  911.             return self->cur;
  912.         }
  913.     }
  914. }
  915.  
  916. tp_obj tp_merge(TP) {
  917.     tp_obj self = TP_OBJ();
  918.     tp_obj v = TP_OBJ();
  919.     int i; for (i=0; i<v.dict.val->len; i++) {
  920.         int n = _tp_dict_next(tp,v.dict.val);
  921.         _tp_dict_set(tp,self.dict.val,
  922.             v.dict.val->items[n].key,v.dict.val->items[n].val);
  923.     }
  924.     return tp_None;
  925. }
  926.  
  927. /* Function: tp_dict
  928.  *
  929.  * Creates a new dictionary object.
  930.  *
  931.  * *Note* If you use <tp_setmeta> on the dictionary, you have to use <tp_getraw> to
  932.  * access the "raw" dictionary again.
  933.  *
  934.  * Returns:
  935.  * The newly created dictionary.
  936.  */
  937. tp_obj tp_dict(TP) {
  938.     tp_obj r = {TP_DICT};
  939.     r.dict.val = _tp_dict_new(tp);
  940.     r.dict.dtype = 1;
  941.     return tp ? tp_track(tp,r) : r;
  942. }
  943.  
  944. tp_obj tp_dict_n(TP,int n, tp_obj* argv) {
  945.     tp_obj r = tp_dict(tp);
  946.     int i; for (i=0; i<n; i++) { tp_set(tp,r,argv[i*2],argv[i*2+1]); }
  947.     return r;
  948. }
  949.  
  950.  
  951. /* File: Miscellaneous
  952.  * Various functions to help interface tinypy.
  953.  */
  954.  
  955. tp_obj _tp_dcall(TP,tp_obj fnc(TP)) {
  956.     return fnc(tp);
  957. }
  958. tp_obj _tp_tcall(TP,tp_obj fnc) {
  959.     if (fnc.fnc.ftype&2) {
  960.         _tp_list_insert(tp,tp->params.list.val,0,fnc.fnc.info->self);
  961.     }
  962.     return _tp_dcall(tp,(tp_obj (*)(tp_vm *))fnc.fnc.cfnc);
  963. }
  964.  
  965. tp_obj tp_fnc_new(TP,int t, void *v, tp_obj c,tp_obj s, tp_obj g) {
  966.     tp_obj r = {TP_FNC};
  967.     _tp_fnc *info = (_tp_fnc*)tp_malloc(tp, sizeof(_tp_fnc));
  968.     info->code = c;
  969.     info->self = s;
  970.     info->globals = g;
  971.     r.fnc.ftype = t;
  972.     r.fnc.info = info;
  973.     r.fnc.cfnc = v;
  974.     return tp_track(tp,r);
  975. }
  976.  
  977. tp_obj tp_def(TP,tp_obj code, tp_obj g) {
  978.     tp_obj r = tp_fnc_new(tp,1,0,code,tp_None,g);
  979.     return r;
  980. }
  981.  
  982. /* Function: tp_fnc
  983.  * Creates a new tinypy function object.
  984.  *
  985.  * This is how you can create a tinypy function object which, when called in
  986.  * the script, calls the provided C function.
  987.  */
  988. tp_obj tp_fnc(TP,tp_obj v(TP)) {
  989.     return tp_fnc_new(tp,0,v,tp_None,tp_None,tp_None);
  990. }
  991.  
  992. tp_obj tp_method(TP,tp_obj self,tp_obj v(TP)) {
  993.     return tp_fnc_new(tp,2,v,tp_None,self,tp_None);
  994. }
  995.  
  996. /* Function: tp_data
  997.  * Creates a new data object.
  998.  *
  999.  * Parameters:
  1000.  * magic - An integer number associated with the data type. This can be used
  1001.  *         to check the type of data objects.
  1002.  * v     - A pointer to user data. Only the pointer is stored in the object,
  1003.  *         you keep all responsibility for the data it points to.
  1004.  *
  1005.  *
  1006.  * Returns:
  1007.  * The new data object.
  1008.  *
  1009.  * Public fields:
  1010.  * The following fields can be access in a data object:
  1011.  *
  1012.  * magic      - An integer number stored in the object.
  1013.  * val        - The data pointer of the object.
  1014.  * info->free - If not NULL, a callback function called when the object gets
  1015.  *              destroyed.
  1016.  *
  1017.  * Example:
  1018.  * > void *__free__(TP, tp_obj self)
  1019.  * > {
  1020.  * >     free(self.data.val);
  1021.  * > }
  1022.  * >
  1023.  * > tp_obj my_obj = tp_data(TP, 0, my_ptr);
  1024.  * > my_obj.data.info->free = __free__;
  1025.  */
  1026. tp_obj tp_data(TP,int magic,void *v) {
  1027.     tp_obj r = {TP_DATA};
  1028.     r.data.info = (_tp_data*)tp_malloc(tp, sizeof(_tp_data));
  1029.     r.data.val = v;
  1030.     r.data.magic = magic;
  1031.     return tp_track(tp,r);
  1032. }
  1033.  
  1034. /* Function: tp_params
  1035.  * Initialize the tinypy parameters.
  1036.  *
  1037.  * When you are calling a tinypy function, you can use this to initialize the
  1038.  * list of parameters getting passed to it. Usually, you may want to use
  1039.  * <tp_params_n> or <tp_params_v>.
  1040.  */
  1041. tp_obj tp_params(TP) {
  1042.     tp_obj r;
  1043.     tp->params = tp->_params.list.val->items[tp->cur];
  1044.     r = tp->_params.list.val->items[tp->cur];
  1045.     r.list.val->len = 0;
  1046.     return r;
  1047. }
  1048.  
  1049. /* Function: tp_params_n
  1050.  * Specify a list of objects as function call parameters.
  1051.  *
  1052.  * See also: <tp_params>, <tp_params_v>
  1053.  *
  1054.  * Parameters:
  1055.  * n - The number of parameters.
  1056.  * argv - A list of n tinypy objects, which will be passed as parameters.
  1057.  *
  1058.  * Returns:
  1059.  * The parameters list. You may modify it before performing the function call.
  1060.  */
  1061. tp_obj tp_params_n(TP,int n, tp_obj argv[]) {
  1062.     tp_obj r = tp_params(tp);
  1063.     int i; for (i=0; i<n; i++) { _tp_list_append(tp,r.list.val,argv[i]); }
  1064.     return r;
  1065. }
  1066.  
  1067. /* Function: tp_params_v
  1068.  * Pass parameters for a tinypy function call.
  1069.  *
  1070.  * When you want to call a tinypy method, then you use this to pass parameters
  1071.  * to it.
  1072.  *
  1073.  * Parameters:
  1074.  * n   - The number of variable arguments following.
  1075.  * ... - Pass n tinypy objects, which a subsequently called tinypy method will
  1076.  *       receive as parameters.
  1077.  *
  1078.  * Returns:
  1079.  * A tinypy list object representing the current call parameters. You can modify
  1080.  * the list before doing the function call.
  1081.  */
  1082. tp_obj tp_params_v(TP,int n,...) {
  1083.     int i;
  1084.     tp_obj r = tp_params(tp);
  1085.     va_list a; va_start(a,n);
  1086.     for (i=0; i<n; i++) {
  1087.         _tp_list_append(tp,r.list.val,va_arg(a,tp_obj));
  1088.     }
  1089.     va_end(a);
  1090.     return r;
  1091. }
  1092. /* File: String
  1093.  * String handling functions.
  1094.  */
  1095.  
  1096. /*
  1097.  * Create a new empty string of a certain size.
  1098.  * Does not put it in for GC tracking, since contents should be
  1099.  * filled after returning.
  1100.  */
  1101. tp_obj tp_string_t(TP, int n) {
  1102.     tp_obj r = tp_string_n(0,n);
  1103.     r.string.info = (_tp_string*)tp_malloc(tp, sizeof(_tp_string)+n);
  1104.     r.string.info->len = n;
  1105.     r.string.val = r.string.info->s;
  1106.     return r;
  1107. }
  1108.  
  1109. /*
  1110.  * Create a new string which is a copy of some memory.
  1111.  * This is put into GC tracking for you.
  1112.  */
  1113. tp_obj tp_string_copy(TP, const char *s, int n) {
  1114.     tp_obj r = tp_string_t(tp,n);
  1115.     memcpy(r.string.info->s,s,n);
  1116.     return tp_track(tp,r);
  1117. }
  1118.  
  1119. /*
  1120.  * Create a new string which is a substring slice of another STRING.
  1121.  * Does not need to be put into GC tracking, as its parent is
  1122.  * already being tracked (supposedly).
  1123.  */
  1124. tp_obj tp_string_sub(TP, tp_obj s, int a, int b) {
  1125.     int l = s.string.len;
  1126.     a = _tp_max(0,(a<0?l+a:a)); b = _tp_min(l,(b<0?l+b:b));
  1127.     tp_obj r = s;
  1128.     r.string.val += a;
  1129.     r.string.len = b-a;
  1130.     return r;
  1131. }
  1132.  
  1133. tp_obj tp_printf(TP, char const *fmt,...) {
  1134.     int l;
  1135.     tp_obj r;
  1136.     char *s;
  1137.     va_list arg;
  1138.     va_start(arg, fmt);
  1139.     l = vsnprintf(NULL, 0, fmt,arg);
  1140.     r = tp_string_t(tp,l);
  1141.     s = r.string.info->s;
  1142.     va_end(arg);
  1143.     va_start(arg, fmt);
  1144.     vsprintf(s,fmt,arg);
  1145.     va_end(arg);
  1146.     return tp_track(tp,r);
  1147. }
  1148.  
  1149. int _tp_str_index(tp_obj s, tp_obj k) {
  1150.     int i=0;
  1151.     while ((s.string.len - i) >= k.string.len) {
  1152.         if (memcmp(s.string.val+i,k.string.val,k.string.len) == 0) {
  1153.             return i;
  1154.         }
  1155.         i += 1;
  1156.     }
  1157.     return -1;
  1158. }
  1159.  
  1160. tp_obj tp_join(TP) {
  1161.     tp_obj delim = TP_OBJ();
  1162.     tp_obj val = TP_OBJ();
  1163.     int l=0,i;
  1164.     tp_obj r;
  1165.     char *s;
  1166.     for (i=0; i<val.list.val->len; i++) {
  1167.         if (i!=0) { l += delim.string.len; }
  1168.         l += tp_str(tp,val.list.val->items[i]).string.len;
  1169.     }
  1170.     r = tp_string_t(tp,l);
  1171.     s = r.string.info->s;
  1172.     l = 0;
  1173.     for (i=0; i<val.list.val->len; i++) {
  1174.         tp_obj e;
  1175.         if (i!=0) {
  1176.             memcpy(s+l,delim.string.val,delim.string.len); l += delim.string.len;
  1177.         }
  1178.         e = tp_str(tp,val.list.val->items[i]);
  1179.         memcpy(s+l,e.string.val,e.string.len); l += e.string.len;
  1180.     }
  1181.     return tp_track(tp,r);
  1182. }
  1183.  
  1184. tp_obj tp_split(TP) {
  1185.     tp_obj v = TP_OBJ();
  1186.     tp_obj d = TP_OBJ();
  1187.     tp_obj r = tp_list(tp);
  1188.  
  1189.     int i;
  1190.     while ((i=_tp_str_index(v,d))!=-1) {
  1191.         _tp_list_append(tp,r.list.val,tp_string_sub(tp,v,0,i));
  1192.         v.string.val += i + d.string.len; v.string.len -= i + d.string.len;
  1193.     }
  1194.     _tp_list_append(tp,r.list.val,tp_string_sub(tp,v,0,v.string.len));
  1195.     return r;
  1196. }
  1197.  
  1198.  
  1199. tp_obj tp_find(TP) {
  1200.     tp_obj s = TP_OBJ();
  1201.     tp_obj v = TP_OBJ();
  1202.     return tp_number(_tp_str_index(s,v));
  1203. }
  1204.  
  1205. tp_obj tp_str_index(TP) {
  1206.     tp_obj s = TP_OBJ();
  1207.     tp_obj v = TP_OBJ();
  1208.     int n = _tp_str_index(s,v);
  1209.     if (n >= 0) { return tp_number(n); }
  1210.     tp_raise(tp_None,tp_string("(tp_str_index) ValueError: substring not found"));
  1211. }
  1212.  
  1213. tp_obj tp_str2(TP) {
  1214.     tp_obj v = TP_OBJ();
  1215.     return tp_str(tp,v);
  1216. }
  1217.  
  1218. tp_obj tp_chr(TP) {
  1219.     int v = TP_NUM();
  1220.     return tp_string_n(tp->chars[(unsigned char)v],1);
  1221. }
  1222. tp_obj tp_ord(TP) {
  1223.     tp_obj s = TP_STR();
  1224.     if (s.string.len != 1) {
  1225.         tp_raise(tp_None,tp_string("(tp_ord) TypeError: ord() expected a character"));
  1226.     }
  1227.     return tp_number((unsigned char)s.string.val[0]);
  1228. }
  1229.  
  1230. tp_obj tp_strip(TP) {
  1231.     tp_obj o = TP_TYPE(TP_STRING);
  1232.     char const *v = o.string.val; int l = o.string.len;
  1233.     int i; int a = l, b = 0;
  1234.     tp_obj r;
  1235.     char *s;
  1236.     for (i=0; i<l; i++) {
  1237.         if (v[i] != ' ' && v[i] != '\n' && v[i] != '\t' && v[i] != '\r') {
  1238.             a = _tp_min(a,i); b = _tp_max(b,i+1);
  1239.         }
  1240.     }
  1241.     if ((b-a) < 0) { return tp_string(""); }
  1242.     r = tp_string_t(tp,b-a);
  1243.     s = r.string.info->s;
  1244.     memcpy(s,v+a,b-a);
  1245.     return tp_track(tp,r);
  1246. }
  1247.  
  1248. tp_obj tp_replace(TP) {
  1249.     tp_obj s = TP_OBJ();
  1250.     tp_obj k = TP_OBJ();
  1251.     tp_obj v = TP_OBJ();
  1252.     tp_obj p = s;
  1253.     int i,n = 0;
  1254.     int c;
  1255.     int l;
  1256.     tp_obj rr;
  1257.     char *r;
  1258.     char *d;
  1259.     tp_obj z;
  1260.     while ((i = _tp_str_index(p,k)) != -1) {
  1261.         n += 1;
  1262.         p.string.val += i + k.string.len; p.string.len -= i + k.string.len;
  1263.     }
  1264. /*     fprintf(stderr,"ns: %d\n",n); */
  1265.     l = s.string.len + n * (v.string.len-k.string.len);
  1266.     rr = tp_string_t(tp,l);
  1267.     r = rr.string.info->s;
  1268.     d = r;
  1269.     z = p = s;
  1270.     while ((i = _tp_str_index(p,k)) != -1) {
  1271.         p.string.val += i; p.string.len -= i;
  1272.         memcpy(d,z.string.val,c=(p.string.val-z.string.val)); d += c;
  1273.         p.string.val += k.string.len; p.string.len -= k.string.len;
  1274.         memcpy(d,v.string.val,v.string.len); d += v.string.len;
  1275.         z = p;
  1276.     }
  1277.     memcpy(d,z.string.val,(s.string.val + s.string.len) - z.string.val);
  1278.  
  1279.     return tp_track(tp,rr);
  1280. }
  1281.  
  1282. /* File: Builtins
  1283.  * Builtin tinypy functions.
  1284.  */
  1285. #ifdef CONIO
  1286.     #include "conio.c"
  1287.     tp_obj tp_print(TP) {
  1288.         console_init();
  1289.         int n = 0;
  1290.         tp_obj e;
  1291.         TP_LOOP(e)
  1292.         if (n) { con_printf(" "); }
  1293.         con_printf("%s",TP_CSTR(e));
  1294.         n += 1;
  1295.         TP_END;
  1296.         con_printf("\n");
  1297.         return tp_None;
  1298.     }
  1299.  
  1300.     #define BUF_SIZE 2048
  1301.     tp_obj tp_raw_input(TP) {
  1302.         console_init();
  1303.         tp_obj prompt;
  1304.         char *buf = malloc(BUF_SIZE);
  1305.         if (tp->params.list.val->len){
  1306.             prompt = TP_OBJ();
  1307.             con_printf("%s", TP_CSTR(prompt));
  1308.         }
  1309.         con_gets(buf, BUF_SIZE);
  1310.         return tp_string(buf);
  1311. }
  1312. #else
  1313. tp_obj tp_print(TP) {
  1314.     int n = 0;
  1315.     tp_obj e;
  1316.     TP_LOOP(e)
  1317.         if (n) { printf(" "); }
  1318.         tp_echo(tp,e);
  1319.         n += 1;
  1320.     TP_END;
  1321.     printf("\n");
  1322.     return tp_None;
  1323. }
  1324. #endif
  1325.  
  1326. tp_obj tp_bind(TP) {
  1327.     tp_obj r = TP_TYPE(TP_FNC);
  1328.     tp_obj self = TP_OBJ();
  1329.     return tp_fnc_new(tp,
  1330.         r.fnc.ftype|2,r.fnc.cfnc,r.fnc.info->code,
  1331.         self,r.fnc.info->globals);
  1332. }
  1333.  
  1334. tp_obj tp_min(TP) {
  1335.     tp_obj r = TP_OBJ();
  1336.     tp_obj e;
  1337.     TP_LOOP(e)
  1338.         if (tp_cmp(tp,r,e) > 0) { r = e; }
  1339.     TP_END;
  1340.     return r;
  1341. }
  1342.  
  1343. tp_obj tp_max(TP) {
  1344.     tp_obj r = TP_OBJ();
  1345.     tp_obj e;
  1346.     TP_LOOP(e)
  1347.         if (tp_cmp(tp,r,e) < 0) { r = e; }
  1348.     TP_END;
  1349.     return r;
  1350. }
  1351.  
  1352. tp_obj tp_copy(TP) {
  1353.     tp_obj r = TP_OBJ();
  1354.     int type = r.type;
  1355.     if (type == TP_LIST) {
  1356.         return _tp_list_copy(tp,r);
  1357.     } else if (type == TP_DICT) {
  1358.         return _tp_dict_copy(tp,r);
  1359.     }
  1360.     tp_raise(tp_None,tp_string("(tp_copy) TypeError: ?"));
  1361. }
  1362.  
  1363.  
  1364. tp_obj tp_len_(TP) {
  1365.     tp_obj e = TP_OBJ();
  1366.     return tp_len(tp,e);
  1367. }
  1368.  
  1369. tp_obj tp_assert(TP) {
  1370.     int a = TP_NUM();
  1371.     if (a) { return tp_None; }
  1372.     tp_raise(tp_None,tp_string("(tp_assert) AssertionError"));
  1373. }
  1374.  
  1375. tp_obj tp_range(TP) {
  1376.     int a,b,c,i;
  1377.     tp_obj r = tp_list(tp);
  1378.     switch (tp->params.list.val->len) {
  1379.         case 1: a = 0; b = TP_NUM(); c = 1; break;
  1380.         case 2:
  1381.         case 3: a = TP_NUM(); b = TP_NUM(); c = TP_DEFAULT(tp_number(1)).number.val; break;
  1382.         default: return r;
  1383.     }
  1384.     if (c != 0) {
  1385.         for (i=a; (c>0) ? i<b : i>b; i+=c) {
  1386.             _tp_list_append(tp,r.list.val,tp_number(i));
  1387.         }
  1388.     }
  1389.     return r;
  1390. }
  1391.  
  1392. /* Function: tp_system
  1393.  *
  1394.  * The system builtin. A grave security flaw. If your version of tinypy
  1395.  * enables this, you better remove it before deploying your app :P
  1396.  */
  1397. tp_obj tp_system(TP) {
  1398.     char s[TP_CSTR_LEN]; tp_cstr(tp,TP_STR(),s,TP_CSTR_LEN);
  1399.     int r = system(s);
  1400.     return tp_number(r);
  1401. }
  1402.  
  1403. tp_obj tp_istype(TP) {
  1404.     tp_obj v = TP_OBJ();
  1405.     tp_obj t = TP_STR();
  1406.     if (tp_cmp(tp,t,tp_string("string")) == 0) { return tp_number(v.type == TP_STRING); }
  1407.     if (tp_cmp(tp,t,tp_string("list")) == 0) { return tp_number(v.type == TP_LIST); }
  1408.     if (tp_cmp(tp,t,tp_string("dict")) == 0) { return tp_number(v.type == TP_DICT); }
  1409.     if (tp_cmp(tp,t,tp_string("number")) == 0) { return tp_number(v.type == TP_NUMBER); }
  1410.     if (tp_cmp(tp,t,tp_string("fnc")) == 0) { return tp_number(v.type == TP_FNC && (v.fnc.ftype&2) == 0); }
  1411.     if (tp_cmp(tp,t,tp_string("method")) == 0) { return tp_number(v.type == TP_FNC && (v.fnc.ftype&2) != 0); }
  1412.     tp_raise(tp_None,tp_string("(is_type) TypeError: ?"));
  1413. }
  1414.  
  1415.  
  1416. tp_obj tp_float(TP) {
  1417.     tp_obj v = TP_OBJ();
  1418.     int ord = TP_DEFAULT(tp_number(0)).number.val;
  1419.     int type = v.type;
  1420.     if (type == TP_NUMBER) { return v; }
  1421.     if (type == TP_STRING && v.string.len < 32) {
  1422.         char s[32]; memset(s,0,v.string.len+1);
  1423.         memcpy(s,v.string.val,v.string.len);
  1424.         if (strchr(s,'.')) { return tp_number(atof(s)); }
  1425.         return(tp_number(strtoul(s,0,ord)));
  1426.     }
  1427.     tp_raise(tp_None,tp_string("(tp_float) TypeError: ?"));
  1428. }
  1429.  
  1430.  
  1431. tp_obj tp_save(TP) {
  1432.     char fname[256]; tp_cstr(tp,TP_STR(),fname,256);
  1433.     tp_obj v = TP_OBJ();
  1434.     FILE *f;
  1435.     f = fopen(fname,"wb");
  1436.     if (!f) { tp_raise(tp_None,tp_string("(tp_save) IOError: ?")); }
  1437.     fwrite(v.string.val,v.string.len,1,f);
  1438.     fclose(f);
  1439.     return tp_None;
  1440. }
  1441.  
  1442. tp_obj tp_load(TP) {
  1443.     FILE *f;
  1444.     long l;
  1445.     tp_obj r;
  1446.     char *s;
  1447.     char fname[256]; tp_cstr(tp,TP_STR(),fname,256);
  1448.     struct stat stbuf;
  1449.     stat(fname, &stbuf);
  1450.     l = stbuf.st_size;
  1451.     f = fopen(fname,"rb");
  1452.     if (!f) {
  1453.         tp_raise(tp_None,tp_string("(tp_load) IOError: ?"));
  1454.     }
  1455.     r = tp_string_t(tp,l);
  1456.     s = r.string.info->s;
  1457.     fread(s,1,l,f);
  1458. /*    if (rr !=l) { printf("hmmn: %d %d\n",rr,(int)l); }*/
  1459.     fclose(f);
  1460.     return tp_track(tp,r);
  1461. }
  1462.  
  1463.  
  1464. tp_obj tp_fpack(TP) {
  1465.     tp_num v = TP_NUM();
  1466.     tp_obj r = tp_string_t(tp,sizeof(tp_num));
  1467.     *(tp_num*)r.string.val = v;
  1468.     return tp_track(tp,r);
  1469. }
  1470.  
  1471. tp_obj tp_abs(TP) {
  1472.     return tp_number(fabs(tp_float(tp).number.val));
  1473. }
  1474. tp_obj tp_int(TP) {
  1475.     return tp_number((long)tp_float(tp).number.val);
  1476. }
  1477. tp_num _roundf(tp_num v) {
  1478.     tp_num av = fabs(v); tp_num iv = (long)av;
  1479.     av = (av-iv < 0.5?iv:iv+1);
  1480.     return (v<0?-av:av);
  1481. }
  1482. tp_obj tp_round(TP) {
  1483.     return tp_number(_roundf(tp_float(tp).number.val));
  1484. }
  1485.  
  1486. tp_obj tp_exists(TP) {
  1487.     char fname[TP_CSTR_LEN]; tp_cstr(tp,TP_STR(),fname,TP_CSTR_LEN);
  1488.     struct stat stbuf;
  1489.     return tp_number(!stat(fname,&stbuf));
  1490. }
  1491. tp_obj tp_mtime(TP) {
  1492.     char fname[TP_CSTR_LEN]; tp_cstr(tp,TP_STR(),fname,TP_CSTR_LEN);
  1493.     struct stat stbuf;
  1494.     if (!stat(fname,&stbuf)) { return tp_number(stbuf.st_mtime); }
  1495.     tp_raise(tp_None,tp_string("(tp_mtime) IOError: ?"));
  1496. }
  1497.  
  1498. int _tp_lookup_(TP,tp_obj self, tp_obj k, tp_obj *meta, int depth) {
  1499.     int n = _tp_dict_find(tp,self.dict.val,k);
  1500.     if (n != -1) {
  1501.         *meta = self.dict.val->items[n].val;
  1502.         return 1;
  1503.     }
  1504.     depth--; if (!depth) { tp_raise(0,tp_string("(tp_lookup) RuntimeError: maximum lookup depth exceeded")); }
  1505.     if (self.dict.dtype && self.dict.val->meta.type == TP_DICT && _tp_lookup_(tp,self.dict.val->meta,k,meta,depth)) {
  1506.         if (self.dict.dtype == 2 && meta->type == TP_FNC) {
  1507.             *meta = tp_fnc_new(tp,meta->fnc.ftype|2,
  1508.                 meta->fnc.cfnc,meta->fnc.info->code,
  1509.                 self,meta->fnc.info->globals);
  1510.         }
  1511.         return 1;
  1512.     }
  1513.     return 0;
  1514. }
  1515.  
  1516. int _tp_lookup(TP,tp_obj self, tp_obj k, tp_obj *meta) {
  1517.     return _tp_lookup_(tp,self,k,meta,8);
  1518. }
  1519.  
  1520. #define TP_META_BEGIN(self,name) \
  1521.     if (self.dict.dtype == 2) { \
  1522.         tp_obj meta; if (_tp_lookup(tp,self,tp_string(name),&meta)) {
  1523.  
  1524. #define TP_META_END \
  1525.         } \
  1526.     }
  1527.  
  1528. /* Function: tp_setmeta
  1529.  * Set a "dict's meta".
  1530.  *
  1531.  * This is a builtin function, so you need to use <tp_params> to provide the
  1532.  * parameters.
  1533.  *
  1534.  * In tinypy, each dictionary can have a so-called "meta" dictionary attached
  1535.  * to it. When dictionary attributes are accessed, but not present in the
  1536.  * dictionary, they instead are looked up in the meta dictionary. To get the
  1537.  * raw dictionary, you can use <tp_getraw>.
  1538.  *
  1539.  * This function is particulary useful for objects and classes, which are just
  1540.  * special dictionaries created with <tp_object> and <tp_class>. There you can
  1541.  * use tp_setmeta to change the class of the object or parent class of a class.
  1542.  *
  1543.  * Parameters:
  1544.  * self - The dictionary for which to set a meta.
  1545.  * meta - The meta dictionary.
  1546.  *
  1547.  * Returns:
  1548.  * None
  1549.  */
  1550. tp_obj tp_setmeta(TP) {
  1551.     tp_obj self = TP_TYPE(TP_DICT);
  1552.     tp_obj meta = TP_TYPE(TP_DICT);
  1553.     self.dict.val->meta = meta;
  1554.     return tp_None;
  1555. }
  1556.  
  1557. tp_obj tp_getmeta(TP) {
  1558.     tp_obj self = TP_TYPE(TP_DICT);
  1559.     return self.dict.val->meta;
  1560. }
  1561.  
  1562. /* Function: tp_object
  1563.  * Creates a new object.
  1564.  *
  1565.  * Returns:
  1566.  * The newly created object. The object initially has no parent class, use
  1567.  * <tp_setmeta> to set a class. Also see <tp_object_new>.
  1568.  */
  1569. tp_obj tp_object(TP) {
  1570.     tp_obj self = tp_dict(tp);
  1571.     self.dict.dtype = 2;
  1572.     return self;
  1573. }
  1574.  
  1575. tp_obj tp_object_new(TP) {
  1576.     tp_obj klass = TP_TYPE(TP_DICT);
  1577.     tp_obj self = tp_object(tp);
  1578.     self.dict.val->meta = klass;
  1579.     TP_META_BEGIN(self,"__init__");
  1580.         tp_call(tp,meta,tp->params);
  1581.     TP_META_END;
  1582.     return self;
  1583. }
  1584.  
  1585. tp_obj tp_object_call(TP) {
  1586.     tp_obj self;
  1587.     if (tp->params.list.val->len) {
  1588.         self = TP_TYPE(TP_DICT);
  1589.         self.dict.dtype = 2;
  1590.     } else {
  1591.         self = tp_object(tp);
  1592.     }
  1593.     return self;
  1594. }
  1595.  
  1596. /* Function: tp_getraw
  1597.  * Retrieve the raw dict of a dict.
  1598.  *
  1599.  * This builtin retrieves one dict parameter from tinypy, and returns its raw
  1600.  * dict. This is very useful when implementing your own __get__ and __set__
  1601.  * functions, as it allows you to directly access the attributes stored in the
  1602.  * dict.
  1603.  */
  1604. tp_obj tp_getraw(TP) {
  1605.     tp_obj self = TP_TYPE(TP_DICT);
  1606.     self.dict.dtype = 0;
  1607.     return self;
  1608. }
  1609.  
  1610. /* Function: tp_class
  1611.  * Creates a new base class.
  1612.  *
  1613.  * Parameters:
  1614.  * none
  1615.  *
  1616.  * Returns:
  1617.  * A new, empty class (derived from tinypy's builtin "object" class).
  1618.  */
  1619. tp_obj tp_class(TP) {
  1620.     tp_obj klass = tp_dict(tp);
  1621.     klass.dict.val->meta = tp_get(tp,tp->builtins,tp_string("object"));
  1622.     return klass;
  1623. }
  1624.  
  1625. /* Function: tp_builtins_bool
  1626.  * Coerces any value to a boolean.
  1627.  */
  1628. tp_obj tp_builtins_bool(TP) {
  1629.     tp_obj v = TP_OBJ();
  1630.     return (tp_number(tp_bool(tp, v)));
  1631. }
  1632. /* tp_obj tp_track(TP,tp_obj v) { return v; }
  1633.    void tp_grey(TP,tp_obj v) { }
  1634.    void tp_full(TP) { }
  1635.    void tp_gc_init(TP) { }
  1636.    void tp_gc_deinit(TP) { }
  1637.    void tp_delete(TP,tp_obj v) { }*/
  1638.  
  1639. void tp_grey(TP,tp_obj v) {
  1640.     if (v.type < TP_STRING || (!v.gci.data) || *v.gci.data) { return; }
  1641.     *v.gci.data = 1;
  1642.     if (v.type == TP_STRING || v.type == TP_DATA) {
  1643.         _tp_list_appendx(tp,tp->black,v);
  1644.         return;
  1645.     }
  1646.     _tp_list_appendx(tp,tp->grey,v);
  1647. }
  1648.  
  1649. void tp_follow(TP,tp_obj v) {
  1650.     int type = v.type;
  1651.     if (type == TP_LIST) {
  1652.         int n;
  1653.         for (n=0; n<v.list.val->len; n++) {
  1654.             tp_grey(tp,v.list.val->items[n]);
  1655.         }
  1656.     }
  1657.     if (type == TP_DICT) {
  1658.         int i;
  1659.         for (i=0; i<v.dict.val->len; i++) {
  1660.             int n = _tp_dict_next(tp,v.dict.val);
  1661.             tp_grey(tp,v.dict.val->items[n].key);
  1662.             tp_grey(tp,v.dict.val->items[n].val);
  1663.         }
  1664.         tp_grey(tp,v.dict.val->meta);
  1665.     }
  1666.     if (type == TP_FNC) {
  1667.         tp_grey(tp,v.fnc.info->self);
  1668.         tp_grey(tp,v.fnc.info->globals);
  1669.         tp_grey(tp,v.fnc.info->code);
  1670.     }
  1671. }
  1672.  
  1673. void tp_reset(TP) {
  1674.     int n;
  1675.     _tp_list *tmp;
  1676.     for (n=0; n<tp->black->len; n++) {
  1677.         *tp->black->items[n].gci.data = 0;
  1678.     }
  1679.     tmp = tp->white;
  1680.     tp->white = tp->black;
  1681.     tp->black = tmp;
  1682. }
  1683.  
  1684. void tp_gc_init(TP) {
  1685.     tp->white = _tp_list_new(tp);
  1686.     tp->grey = _tp_list_new(tp);
  1687.     tp->black = _tp_list_new(tp);
  1688.     tp->steps = 0;
  1689. }
  1690.  
  1691. void tp_gc_deinit(TP) {
  1692.     _tp_list_free(tp, tp->white);
  1693.     _tp_list_free(tp, tp->grey);
  1694.     _tp_list_free(tp, tp->black);
  1695. }
  1696.  
  1697. void tp_delete(TP,tp_obj v) {
  1698.     int type = v.type;
  1699.     if (type == TP_LIST) {
  1700.         _tp_list_free(tp, v.list.val);
  1701.         return;
  1702.     } else if (type == TP_DICT) {
  1703.         _tp_dict_free(tp, v.dict.val);
  1704.         return;
  1705.     } else if (type == TP_STRING) {
  1706.         tp_free(tp, v.string.info);
  1707.         return;
  1708.     } else if (type == TP_DATA) {
  1709.         if (v.data.info->free) {
  1710.             v.data.info->free(tp,v);
  1711.         }
  1712.         tp_free(tp, v.data.info);
  1713.         return;
  1714.     } else if (type == TP_FNC) {
  1715.         tp_free(tp, v.fnc.info);
  1716.         return;
  1717.     }
  1718.     tp_raise(,tp_string("(tp_delete) TypeError: ?"));
  1719. }
  1720.  
  1721. void tp_collect(TP) {
  1722.     int n;
  1723.     for (n=0; n<tp->white->len; n++) {
  1724.         tp_obj r = tp->white->items[n];
  1725.         if (*r.gci.data) { continue; }
  1726.         tp_delete(tp,r);
  1727.     }
  1728.     tp->white->len = 0;
  1729.     tp_reset(tp);
  1730. }
  1731.  
  1732. void _tp_gcinc(TP) {
  1733.     tp_obj v;
  1734.     if (!tp->grey->len) {
  1735.         return;
  1736.     }
  1737.     v = _tp_list_pop(tp,tp->grey,tp->grey->len-1,"_tp_gcinc");
  1738.     tp_follow(tp,v);
  1739.     _tp_list_appendx(tp,tp->black,v);
  1740. }
  1741.  
  1742. void tp_full(TP) {
  1743.     while (tp->grey->len) {
  1744.         _tp_gcinc(tp);
  1745.     }
  1746.     tp_collect(tp);
  1747.     tp_follow(tp,tp->root);
  1748. }
  1749.  
  1750. void tp_gcinc(TP) {
  1751.     tp->steps += 1;
  1752.     if (tp->steps < TP_GCMAX || tp->grey->len > 0) {
  1753.         _tp_gcinc(tp); _tp_gcinc(tp);
  1754.     }
  1755.     if (tp->steps < TP_GCMAX || tp->grey->len > 0) { return; }
  1756.     tp->steps = 0;
  1757.     tp_full(tp);
  1758.     return;
  1759. }
  1760.  
  1761. tp_obj tp_track(TP,tp_obj v) {
  1762.     tp_gcinc(tp);
  1763.     tp_grey(tp,v);
  1764.     return v;
  1765. }
  1766.  
  1767. /**/
  1768.  
  1769. /* File: Operations
  1770.  * Various tinypy operations.
  1771.  */
  1772.  
  1773. /* Function: tp_str
  1774.  * String representation of an object.
  1775.  *
  1776.  * Returns a string object representating self.
  1777.  */
  1778. tp_obj tp_str(TP,tp_obj self) {
  1779.     int type = self.type;
  1780.     if (type == TP_STRING) { return self; }
  1781.     if (type == TP_NUMBER) {
  1782.         tp_num v = self.number.val;
  1783.         if ((fabs(v)-fabs((long)v)) < 0.000001) { return tp_printf(tp,"%ld",(long)v); }
  1784.         return tp_printf(tp,"%f",v);
  1785.     } else if(type == TP_DICT) {
  1786.         return tp_printf(tp,"<dict 0x%x>",self.dict.val);
  1787.     } else if(type == TP_LIST) {
  1788.         return tp_printf(tp,"<list 0x%x>",self.list.val);
  1789.     } else if (type == TP_NONE) {
  1790.         return tp_string("None");
  1791.     } else if (type == TP_DATA) {
  1792.         return tp_printf(tp,"<data 0x%x>",self.data.val);
  1793.     } else if (type == TP_FNC) {
  1794.         return tp_printf(tp,"<fnc 0x%x>",self.fnc.info);
  1795.     }
  1796.     return tp_string("<?>");
  1797. }
  1798.  
  1799. /* Function: tp_bool
  1800.  * Check the truth value of an object
  1801.  *
  1802.  * Returns false if v is a numeric object with a value of exactly 0, v is of
  1803.  * type None or v is a string list or dictionary with a length of 0. Else true
  1804.  * is returned.
  1805.  */
  1806. int tp_bool(TP,tp_obj v) {
  1807.     switch(v.type) {
  1808.         case TP_NUMBER: return v.number.val != 0;
  1809.         case TP_NONE: return 0;
  1810.         case TP_STRING: return v.string.len != 0;
  1811.         case TP_LIST: return v.list.val->len != 0;
  1812.         case TP_DICT: return v.dict.val->len != 0;
  1813.     }
  1814.     return 1;
  1815. }
  1816.  
  1817.  
  1818. /* Function: tp_has
  1819.  * Checks if an object contains a key.
  1820.  *
  1821.  * Returns tp_True if self[k] exists, tp_False otherwise.
  1822.  */
  1823. tp_obj tp_has(TP,tp_obj self, tp_obj k) {
  1824.     int type = self.type;
  1825.     if (type == TP_DICT) {
  1826.         if (_tp_dict_find(tp,self.dict.val,k) != -1) { return tp_True; }
  1827.         return tp_False;
  1828.     } else if (type == TP_STRING && k.type == TP_STRING) {
  1829.         return tp_number(_tp_str_index(self,k)!=-1);
  1830.     } else if (type == TP_LIST) {
  1831.         return tp_number(_tp_list_find(tp,self.list.val,k)!=-1);
  1832.     }
  1833.     tp_raise(tp_None,tp_string("(tp_has) TypeError: iterable argument required"));
  1834. }
  1835.  
  1836. /* Function: tp_del
  1837.  * Remove a dictionary entry.
  1838.  *
  1839.  * Removes the key k from self. Also works on classes and objects.
  1840.  *
  1841.  * Note that unlike with Python, you cannot use this to remove list items.
  1842.  */
  1843. void tp_del(TP,tp_obj self, tp_obj k) {
  1844.     int type = self.type;
  1845.     if (type == TP_DICT) {
  1846.         _tp_dict_del(tp,self.dict.val,k,"tp_del");
  1847.         return;
  1848.     }
  1849.     tp_raise(,tp_string("(tp_del) TypeError: object does not support item deletion"));
  1850. }
  1851.  
  1852.  
  1853. /* Function: tp_iter
  1854.  * Iterate through a list or dict.
  1855.  *
  1856.  * If self is a list/string/dictionary, this will iterate over the
  1857.  * elements/characters/keys respectively, if k is an increasing index
  1858.  * starting with 0 up to the length of the object-1.
  1859.  *
  1860.  * In the case of a list of string, the returned items will correspond to the
  1861.  * item at index k. For a dictionary, no guarantees are made about the order.
  1862.  * You also cannot call the function with a specific k to get a specific
  1863.  * item -- it is only meant for iterating through all items, calling this
  1864.  * function len(self) times. Use <tp_get> to retrieve a specific item, and
  1865.  * <tp_len> to get the length.
  1866.  *
  1867.  * Parameters:
  1868.  * self - The object over which to iterate.
  1869.  * k - You must pass 0 on the first call, then increase it by 1 after each call,
  1870.  *     and don't call the function with k >= len(self).
  1871.  *
  1872.  * Returns:
  1873.  * The first (k = 0) or next (k = 1 .. len(self)-1) item in the iteration.
  1874.  */
  1875. tp_obj tp_iter(TP,tp_obj self, tp_obj k) {
  1876.     int type = self.type;
  1877.     if (type == TP_LIST || type == TP_STRING) { return tp_get(tp,self,k); }
  1878.     if (type == TP_DICT && k.type == TP_NUMBER) {
  1879.         return self.dict.val->items[_tp_dict_next(tp,self.dict.val)].key;
  1880.     }
  1881.     tp_raise(tp_None,tp_string("(tp_iter) TypeError: iteration over non-sequence"));
  1882. }
  1883.  
  1884.  
  1885. /* Function: tp_get
  1886.  * Attribute lookup.
  1887.  *
  1888.  * This returns the result of using self[k] in actual code. It works for
  1889.  * dictionaries (including classes and instantiated objects), lists and strings.
  1890.  *
  1891.  * As a special case, if self is a list, self[None] will return the first
  1892.  * element in the list and subsequently remove it from the list.
  1893.  */
  1894. tp_obj tp_get(TP,tp_obj self, tp_obj k) {
  1895.     int type = self.type;
  1896.     tp_obj r;
  1897.     if (type == TP_DICT) {
  1898.         TP_META_BEGIN(self,"__get__");
  1899.             return tp_call(tp,meta,tp_params_v(tp,1,k));
  1900.         TP_META_END;
  1901.         if (self.dict.dtype && _tp_lookup(tp,self,k,&r)) { return r; }
  1902.         return _tp_dict_get(tp,self.dict.val,k,"tp_get");
  1903.     } else if (type == TP_LIST) {
  1904.         if (k.type == TP_NUMBER) {
  1905.             int l = tp_len(tp,self).number.val;
  1906.             int n = k.number.val;
  1907.             n = (n<0?l+n:n);
  1908.             return _tp_list_get(tp,self.list.val,n,"tp_get");
  1909.         } else if (k.type == TP_STRING) {
  1910.             if (tp_cmp(tp,tp_string("append"),k) == 0) {
  1911.                 return tp_method(tp,self,tp_append);
  1912.             } else if (tp_cmp(tp,tp_string("pop"),k) == 0) {
  1913.                 return tp_method(tp,self,tp_pop);
  1914.             } else if (tp_cmp(tp,tp_string("index"),k) == 0) {
  1915.                 return tp_method(tp,self,tp_index);
  1916.             } else if (tp_cmp(tp,tp_string("sort"),k) == 0) {
  1917.                 return tp_method(tp,self,tp_sort);
  1918.             } else if (tp_cmp(tp,tp_string("extend"),k) == 0) {
  1919.                 return tp_method(tp,self,tp_extend);
  1920.             } else if (tp_cmp(tp,tp_string("*"),k) == 0) {
  1921.                 tp_params_v(tp,1,self);
  1922.                 r = tp_copy(tp);
  1923.                 self.list.val->len=0;
  1924.                 return r;
  1925.             }
  1926.         } else if (k.type == TP_NONE) {
  1927.             return _tp_list_pop(tp,self.list.val,0,"tp_get");
  1928.         }
  1929.     } else if (type == TP_STRING) {
  1930.         if (k.type == TP_NUMBER) {
  1931.             int l = self.string.len;
  1932.             int n = k.number.val;
  1933.             n = (n<0?l+n:n);
  1934.             if (n >= 0 && n < l) { return tp_string_n(tp->chars[(unsigned char)self.string.val[n]],1); }
  1935.         } else if (k.type == TP_STRING) {
  1936.             if (tp_cmp(tp,tp_string("join"),k) == 0) {
  1937.                 return tp_method(tp,self,tp_join);
  1938.             } else if (tp_cmp(tp,tp_string("split"),k) == 0) {
  1939.                 return tp_method(tp,self,tp_split);
  1940.             } else if (tp_cmp(tp,tp_string("index"),k) == 0) {
  1941.                 return tp_method(tp,self,tp_str_index);
  1942.             } else if (tp_cmp(tp,tp_string("strip"),k) == 0) {
  1943.                 return tp_method(tp,self,tp_strip);
  1944.             } else if (tp_cmp(tp,tp_string("replace"),k) == 0) {
  1945.                 return tp_method(tp,self,tp_replace);
  1946.             }
  1947.         }
  1948.     }
  1949.  
  1950.     if (k.type == TP_LIST) {
  1951.         int a,b,l;
  1952.         tp_obj tmp;
  1953.         l = tp_len(tp,self).number.val;
  1954.         tmp = tp_get(tp,k,tp_number(0));
  1955.         if (tmp.type == TP_NUMBER) { a = tmp.number.val; }
  1956.         else if(tmp.type == TP_NONE) { a = 0; }
  1957.         else { tp_raise(tp_None,tp_string("(tp_get) TypeError: indices must be numbers")); }
  1958.         tmp = tp_get(tp,k,tp_number(1));
  1959.         if (tmp.type == TP_NUMBER) { b = tmp.number.val; }
  1960.         else if(tmp.type == TP_NONE) { b = l; }
  1961.         else { tp_raise(tp_None,tp_string("(tp_get) TypeError: indices must be numbers")); }
  1962.         a = _tp_max(0,(a<0?l+a:a)); b = _tp_min(l,(b<0?l+b:b));
  1963.         if (type == TP_LIST) {
  1964.             return tp_list_n(tp,b-a,&self.list.val->items[a]);
  1965.         } else if (type == TP_STRING) {
  1966.             return tp_string_sub(tp,self,a,b);
  1967.         }
  1968.     }
  1969.  
  1970.     tp_raise(tp_None,tp_string("(tp_get) TypeError: ?"));
  1971. }
  1972.  
  1973. /* Function: tp_iget
  1974.  * Failsafe attribute lookup.
  1975.  *
  1976.  * This is like <tp_get>, except it will return false if the attribute lookup
  1977.  * failed. Otherwise, it will return true, and the object will be returned
  1978.  * over the reference parameter r.
  1979.  */
  1980. int tp_iget(TP,tp_obj *r, tp_obj self, tp_obj k) {
  1981.     if (self.type == TP_DICT) {
  1982.         int n = _tp_dict_find(tp,self.dict.val,k);
  1983.         if (n == -1) { return 0; }
  1984.         *r = self.dict.val->items[n].val;
  1985.         tp_grey(tp,*r);
  1986.         return 1;
  1987.     }
  1988.     if (self.type == TP_LIST && !self.list.val->len) { return 0; }
  1989.     *r = tp_get(tp,self,k); tp_grey(tp,*r);
  1990.     return 1;
  1991. }
  1992.  
  1993. /* Function: tp_set
  1994.  * Attribute modification.
  1995.  *
  1996.  * This is the counterpart of tp_get, it does the same as self[k] = v would do
  1997.  * in actual tinypy code.
  1998.  */
  1999. void tp_set(TP,tp_obj self, tp_obj k, tp_obj v) {
  2000.     int type = self.type;
  2001.  
  2002.     if (type == TP_DICT) {
  2003.         TP_META_BEGIN(self,"__set__");
  2004.             tp_call(tp,meta,tp_params_v(tp,2,k,v));
  2005.             return;
  2006.         TP_META_END;
  2007.         _tp_dict_set(tp,self.dict.val,k,v);
  2008.         return;
  2009.     } else if (type == TP_LIST) {
  2010.         if (k.type == TP_NUMBER) {
  2011.             _tp_list_set(tp,self.list.val,k.number.val,v,"tp_set");
  2012.             return;
  2013.         } else if (k.type == TP_NONE) {
  2014.             _tp_list_append(tp,self.list.val,v);
  2015.             return;
  2016.         } else if (k.type == TP_STRING) {
  2017.             if (tp_cmp(tp,tp_string("*"),k) == 0) {
  2018.                 tp_params_v(tp,2,self,v); tp_extend(tp);
  2019.                 return;
  2020.             }
  2021.         }
  2022.     }
  2023.     tp_raise(,tp_string("(tp_set) TypeError: object does not support item assignment"));
  2024. }
  2025.  
  2026. tp_obj tp_add(TP,tp_obj a, tp_obj b) {
  2027.     if (a.type == TP_NUMBER && a.type == b.type) {
  2028.         return tp_number(a.number.val+b.number.val);
  2029.     } else if (a.type == TP_STRING && a.type == b.type) {
  2030.         int al = a.string.len, bl = b.string.len;
  2031.         tp_obj r = tp_string_t(tp,al+bl);
  2032.         char *s = r.string.info->s;
  2033.         memcpy(s,a.string.val,al); memcpy(s+al,b.string.val,bl);
  2034.         return tp_track(tp,r);
  2035.     } else if (a.type == TP_LIST && a.type == b.type) {
  2036.         tp_obj r;
  2037.         tp_params_v(tp,1,a);
  2038.         r = tp_copy(tp);
  2039.         tp_params_v(tp,2,r,b);
  2040.         tp_extend(tp);
  2041.         return r;
  2042.     }
  2043.     tp_raise(tp_None,tp_string("(tp_add) TypeError: ?"));
  2044. }
  2045.  
  2046. tp_obj tp_mul(TP,tp_obj a, tp_obj b) {
  2047.     if (a.type == TP_NUMBER && a.type == b.type) {
  2048.         return tp_number(a.number.val*b.number.val);
  2049.     } else if ((a.type == TP_STRING && b.type == TP_NUMBER) ||
  2050.                (a.type == TP_NUMBER && b.type == TP_STRING)) {
  2051.         if(a.type == TP_NUMBER) {
  2052.             tp_obj c = a; a = b; b = c;
  2053.         }
  2054.         int al = a.string.len; int n = b.number.val;
  2055.         if(n <= 0) {
  2056.             tp_obj r = tp_string_t(tp,0);
  2057.             return tp_track(tp,r);
  2058.         }
  2059.         tp_obj r = tp_string_t(tp,al*n);
  2060.         char *s = r.string.info->s;
  2061.         int i; for (i=0; i<n; i++) { memcpy(s+al*i,a.string.val,al); }
  2062.         return tp_track(tp,r);
  2063.     }
  2064.     tp_raise(tp_None,tp_string("(tp_mul) TypeError: ?"));
  2065. }
  2066.  
  2067. /* Function: tp_len
  2068.  * Returns the length of an object.
  2069.  *
  2070.  * Returns the number of items in a list or dict, or the length of a string.
  2071.  */
  2072. tp_obj tp_len(TP,tp_obj self) {
  2073.     int type = self.type;
  2074.     if (type == TP_STRING) {
  2075.         return tp_number(self.string.len);
  2076.     } else if (type == TP_DICT) {
  2077.         return tp_number(self.dict.val->len);
  2078.     } else if (type == TP_LIST) {
  2079.         return tp_number(self.list.val->len);
  2080.     }
  2081.  
  2082.     tp_raise(tp_None,tp_string("(tp_len) TypeError: len() of unsized object"));
  2083. }
  2084.  
  2085. int tp_cmp(TP,tp_obj a, tp_obj b) {
  2086.     if (a.type != b.type) { return a.type-b.type; }
  2087.     switch(a.type) {
  2088.         case TP_NONE: return 0;
  2089.         case TP_NUMBER: return _tp_sign(a.number.val-b.number.val);
  2090.         case TP_STRING: {
  2091.             int l = _tp_min(a.string.len,b.string.len);
  2092.             int v = memcmp(a.string.val,b.string.val,l);
  2093.             if (v == 0) {
  2094.                 v = a.string.len-b.string.len;
  2095.             }
  2096.             return v;
  2097.         }
  2098.         case TP_LIST: {
  2099.             int n,v; for(n=0;n<_tp_min(a.list.val->len,b.list.val->len);n++) {
  2100.         tp_obj aa = a.list.val->items[n]; tp_obj bb = b.list.val->items[n];
  2101.             if (aa.type == TP_LIST && bb.type == TP_LIST) { v = aa.list.val-bb.list.val; } else { v = tp_cmp(tp,aa,bb); }
  2102.             if (v) { return v; } }
  2103.             return a.list.val->len-b.list.val->len;
  2104.         }
  2105.         case TP_DICT: return a.dict.val - b.dict.val;
  2106.         case TP_FNC: return a.fnc.info - b.fnc.info;
  2107.         case TP_DATA: return (char*)a.data.val - (char*)b.data.val;
  2108.     }
  2109.     tp_raise(0,tp_string("(tp_cmp) TypeError: ?"));
  2110. }
  2111.  
  2112. #define TP_OP(name,expr) \
  2113.     tp_obj name(TP,tp_obj _a,tp_obj _b) { \
  2114.     if (_a.type == TP_NUMBER && _a.type == _b.type) { \
  2115.         tp_num a = _a.number.val; tp_num b = _b.number.val; \
  2116.         return tp_number(expr); \
  2117.     } \
  2118.     tp_raise(tp_None,tp_string("(" #name ") TypeError: unsupported operand type(s)")); \
  2119. }
  2120.  
  2121. TP_OP(tp_bitwise_and,((long)a)&((long)b));
  2122. TP_OP(tp_bitwise_or,((long)a)|((long)b));
  2123. TP_OP(tp_bitwise_xor,((long)a)^((long)b));
  2124. TP_OP(tp_mod,((long)a)%((long)b));
  2125. TP_OP(tp_lsh,((long)a)<<((long)b));
  2126. TP_OP(tp_rsh,((long)a)>>((long)b));
  2127. TP_OP(tp_sub,a-b);
  2128. TP_OP(tp_div,a/b);
  2129. TP_OP(tp_pow,pow(a,b));
  2130.  
  2131. tp_obj tp_bitwise_not(TP, tp_obj a) {
  2132.     if (a.type == TP_NUMBER) {
  2133.         return tp_number(~(long)a.number.val);
  2134.     }
  2135.     tp_raise(tp_None,tp_string("(tp_bitwise_not) TypeError: unsupported operand type"));
  2136. }
  2137.  
  2138. /**/
  2139. /* File: VM
  2140.  * Functionality pertaining to the virtual machine.
  2141.  */
  2142.  
  2143. tp_vm *_tp_init(void) {
  2144.     int i;
  2145.     tp_vm *tp = (tp_vm*)calloc(sizeof(tp_vm),1);
  2146.     tp->time_limit = TP_NO_LIMIT;
  2147.     tp->clocks = clock();
  2148.     tp->time_elapsed = 0.0;
  2149.     tp->mem_limit = TP_NO_LIMIT;
  2150.     tp->mem_exceeded = 0;
  2151.     tp->mem_used = sizeof(tp_vm);
  2152.     tp->cur = 0;
  2153.     tp->jmp = 0;
  2154.     tp->ex = tp_None;
  2155.     tp->root = tp_list_nt(tp);
  2156.     for (i=0; i<256; i++) { tp->chars[i][0]=i; }
  2157.     tp_gc_init(tp);
  2158.     tp->_regs = tp_list(tp);
  2159.     for (i=0; i<TP_REGS; i++) { tp_set(tp,tp->_regs,tp_None,tp_None); }
  2160.     tp->builtins = tp_dict(tp);
  2161.     tp->modules = tp_dict(tp);
  2162.     tp->_params = tp_list(tp);
  2163.     for (i=0; i<TP_FRAMES; i++) { tp_set(tp,tp->_params,tp_None,tp_list(tp)); }
  2164.     tp_set(tp,tp->root,tp_None,tp->builtins);
  2165.     tp_set(tp,tp->root,tp_None,tp->modules);
  2166.     tp_set(tp,tp->root,tp_None,tp->_regs);
  2167.     tp_set(tp,tp->root,tp_None,tp->_params);
  2168.     tp_set(tp,tp->builtins,tp_string("MODULES"),tp->modules);
  2169.     tp_set(tp,tp->modules,tp_string("BUILTINS"),tp->builtins);
  2170.     tp_set(tp,tp->builtins,tp_string("BUILTINS"),tp->builtins);
  2171.     tp_obj sys = tp_dict(tp);
  2172.     tp_set(tp, sys, tp_string("version"), tp_string("tinypy 1.2+SVN"));
  2173.     tp_set(tp,tp->modules, tp_string("sys"), sys);
  2174.     tp->regs = tp->_regs.list.val->items;
  2175.     tp_full(tp);
  2176.     return tp;
  2177. }
  2178.  
  2179.  
  2180. /* Function: tp_deinit
  2181.  * Destroys a VM instance.
  2182.  *
  2183.  * When you no longer need an instance of tinypy, you can use this to free all
  2184.  * memory used by it. Even when you are using only a single tinypy instance, it
  2185.  * may be good practice to call this function on shutdown.
  2186.  */
  2187. void tp_deinit(TP) {
  2188.     while (tp->root.list.val->len) {
  2189.         _tp_list_pop(tp,tp->root.list.val,0,"tp_deinit");
  2190.     }
  2191.     tp_full(tp); tp_full(tp);
  2192.     tp_delete(tp,tp->root);
  2193.     tp_gc_deinit(tp);
  2194.     tp->mem_used -= sizeof(tp_vm);
  2195.     free(tp);
  2196. }
  2197.  
  2198. /* tp_frame_*/
  2199. void tp_frame(TP,tp_obj globals,tp_obj code,tp_obj *ret_dest) {
  2200.     tp_frame_ f;
  2201.     f.globals = globals;
  2202.     f.code = code;
  2203.     f.cur = (tp_code*)f.code.string.val;
  2204.     f.jmp = 0;
  2205. /*     fprintf(stderr,"tp->cur: %d\n",tp->cur);*/
  2206.     f.regs = (tp->cur <= 0?tp->regs:tp->frames[tp->cur].regs+tp->frames[tp->cur].cregs);
  2207.  
  2208.     f.regs[0] = f.globals;
  2209.     f.regs[1] = f.code;
  2210.     f.regs += TP_REGS_EXTRA;
  2211.  
  2212.     f.ret_dest = ret_dest;
  2213.     f.lineno = 0;
  2214.     f.line = tp_string("");
  2215.     f.name = tp_string("?");
  2216.     f.fname = tp_string("?");
  2217.     f.cregs = 0;
  2218. /*     return f;*/
  2219.     if (f.regs+(256+TP_REGS_EXTRA) >= tp->regs+TP_REGS || tp->cur >= TP_FRAMES-1) {
  2220.         tp_raise(,tp_string("(tp_frame) RuntimeError: stack overflow"));
  2221.     }
  2222.     tp->cur += 1;
  2223.     tp->frames[tp->cur] = f;
  2224. }
  2225.  
  2226. void _tp_raise(TP,tp_obj e) {
  2227.     /*char *x = 0; x[0]=0;*/
  2228.     if (!tp || !tp->jmp) {
  2229. #ifndef CPYTHON_MOD
  2230.         printf("\nException:\n"); tp_echo(tp,e); printf("\n");
  2231.         exit(-1);
  2232. #else
  2233.         tp->ex = e;
  2234.         longjmp(tp->nextexpr,1);
  2235. #endif
  2236.     }
  2237.     if (e.type != TP_NONE) { tp->ex = e; }
  2238.     tp_grey(tp,e);
  2239.     longjmp(tp->buf,1);
  2240. }
  2241.  
  2242. void tp_print_stack(TP) {
  2243.     int i;
  2244.     printf("\n");
  2245.     for (i=0; i<=tp->cur; i++) {
  2246.         if (!tp->frames[i].lineno) { continue; }
  2247.         printf("File \""); tp_echo(tp,tp->frames[i].fname); printf("\", ");
  2248.         printf("line %d, in ",tp->frames[i].lineno);
  2249.         tp_echo(tp,tp->frames[i].name); printf("\n ");
  2250.         tp_echo(tp,tp->frames[i].line); printf("\n");
  2251.     }
  2252.     printf("\nException:\n"); tp_echo(tp,tp->ex); printf("\n");
  2253. }
  2254.  
  2255. void tp_handle(TP) {
  2256.     int i;
  2257.     for (i=tp->cur; i>=0; i--) {
  2258.         if (tp->frames[i].jmp) { break; }
  2259.     }
  2260.     if (i >= 0) {
  2261.         tp->cur = i;
  2262.         tp->frames[i].cur = tp->frames[i].jmp;
  2263.         tp->frames[i].jmp = 0;
  2264.         return;
  2265.     }
  2266. #ifndef CPYTHON_MOD
  2267.     tp_print_stack(tp);
  2268.     exit(-1);
  2269. #else
  2270.     longjmp(tp->nextexpr,1);
  2271. #endif
  2272. }
  2273.  
  2274. /* Function: tp_call
  2275.  * Calls a tinypy function.
  2276.  *
  2277.  * Use this to call a tinypy function.
  2278.  *
  2279.  * Parameters:
  2280.  * tp - The VM instance.
  2281.  * self - The object to call.
  2282.  * params - Parameters to pass.
  2283.  *
  2284.  * Example:
  2285.  * > tp_call(tp,
  2286.  * >     tp_get(tp, tp->builtins, tp_string("foo")),
  2287.  * >     tp_params_v(tp, tp_string("hello")))
  2288.  * This will look for a global function named "foo", then call it with a single
  2289.  * positional parameter containing the string "hello".
  2290.  */
  2291. tp_obj tp_call(TP,tp_obj self, tp_obj params) {
  2292.     /* I'm not sure we should have to do this, but
  2293.     just for giggles we will. */
  2294.     tp->params = params;
  2295.  
  2296.     if (self.type == TP_DICT) {
  2297.         if (self.dict.dtype == 1) {
  2298.             tp_obj meta; if (_tp_lookup(tp,self,tp_string("__new__"),&meta)) {
  2299.                 _tp_list_insert(tp,params.list.val,0,self);
  2300.                 return tp_call(tp,meta,params);
  2301.             }
  2302.         } else if (self.dict.dtype == 2) {
  2303.             TP_META_BEGIN(self,"__call__");
  2304.                 return tp_call(tp,meta,params);
  2305.             TP_META_END;
  2306.         }
  2307.     }
  2308.     if (self.type == TP_FNC && !(self.fnc.ftype&1)) {
  2309.         tp_obj r = _tp_tcall(tp,self);
  2310.         tp_grey(tp,r);
  2311.         return r;
  2312.     }
  2313.     if (self.type == TP_FNC) {
  2314.         tp_obj dest = tp_None;
  2315.         tp_frame(tp,self.fnc.info->globals,self.fnc.info->code,&dest);
  2316.         if ((self.fnc.ftype&2)) {
  2317.             tp->frames[tp->cur].regs[0] = params;
  2318.             _tp_list_insert(tp,params.list.val,0,self.fnc.info->self);
  2319.         } else {
  2320.             tp->frames[tp->cur].regs[0] = params;
  2321.         }
  2322.         tp_run(tp,tp->cur);
  2323.         return dest;
  2324.     }
  2325.     tp_params_v(tp,1,self); tp_print(tp);
  2326.     tp_raise(tp_None,tp_string("(tp_call) TypeError: object is not callable"));
  2327. }
  2328.  
  2329.  
  2330. void tp_return(TP, tp_obj v) {
  2331.     tp_obj *dest = tp->frames[tp->cur].ret_dest;
  2332.     if (dest) { *dest = v; tp_grey(tp,v); }
  2333. /*     memset(tp->frames[tp->cur].regs,0,TP_REGS_PER_FRAME*sizeof(tp_obj));
  2334.        fprintf(stderr,"regs:%d\n",(tp->frames[tp->cur].cregs+1));*/
  2335.     memset(tp->frames[tp->cur].regs-TP_REGS_EXTRA,0,(TP_REGS_EXTRA+tp->frames[tp->cur].cregs)*sizeof(tp_obj));
  2336.     tp->cur -= 1;
  2337. }
  2338.  
  2339. enum {
  2340.     TP_IEOF,TP_IADD,TP_ISUB,TP_IMUL,TP_IDIV,TP_IPOW,TP_IBITAND,TP_IBITOR,TP_ICMP,TP_IGET,TP_ISET,
  2341.     TP_INUMBER,TP_ISTRING,TP_IGGET,TP_IGSET,TP_IMOVE,TP_IDEF,TP_IPASS,TP_IJUMP,TP_ICALL,
  2342.     TP_IRETURN,TP_IIF,TP_IDEBUG,TP_IEQ,TP_ILE,TP_ILT,TP_IDICT,TP_ILIST,TP_INONE,TP_ILEN,
  2343.     TP_ILINE,TP_IPARAMS,TP_IIGET,TP_IFILE,TP_INAME,TP_INE,TP_IHAS,TP_IRAISE,TP_ISETJMP,
  2344.     TP_IMOD,TP_ILSH,TP_IRSH,TP_IITER,TP_IDEL,TP_IREGS,TP_IBITXOR, TP_IIFN,
  2345.     TP_INOT, TP_IBITNOT,
  2346.     TP_ITOTAL
  2347. };
  2348.  
  2349. /* char *tp_strings[TP_ITOTAL] = {
  2350.        "EOF","ADD","SUB","MUL","DIV","POW","BITAND","BITOR","CMP","GET","SET","NUM",
  2351.        "STR","GGET","GSET","MOVE","DEF","PASS","JUMP","CALL","RETURN","IF","DEBUG",
  2352.        "EQ","LE","LT","DICT","LIST","NONE","LEN","LINE","PARAMS","IGET","FILE",
  2353.        "NAME","NE","HAS","RAISE","SETJMP","MOD","LSH","RSH","ITER","DEL","REGS",
  2354.        "BITXOR", "IFN", "NOT", "BITNOT",
  2355.    };*/
  2356.  
  2357. #define VA ((int)e.regs.a)
  2358. #define VB ((int)e.regs.b)
  2359. #define VC ((int)e.regs.c)
  2360. #define RA regs[e.regs.a]
  2361. #define RB regs[e.regs.b]
  2362. #define RC regs[e.regs.c]
  2363. #define UVBC (unsigned short)(((VB<<8)+VC))
  2364. #define SVBC (short)(((VB<<8)+VC))
  2365. #define GA tp_grey(tp,RA)
  2366. #define SR(v) f->cur = cur; return(v);
  2367.  
  2368.  
  2369. int tp_step(TP) {
  2370.     tp_frame_ *f = &tp->frames[tp->cur];
  2371.     tp_obj *regs = f->regs;
  2372.     tp_code *cur = f->cur;
  2373.     while(1) {
  2374.     #ifdef TP_SANDBOX
  2375.     tp_bounds(tp,cur,1);
  2376.     #endif
  2377.     tp_code e = *cur;
  2378.     /*
  2379.      fprintf(stderr,"%2d.%4d: %-6s %3d %3d %3d\n",tp->cur,cur - (tp_code*)f->code.string.val,tp_strings[e.i],VA,VB,VC);
  2380.        int i; for(i=0;i<16;i++) { fprintf(stderr,"%d: %s\n",i,TP_xSTR(regs[i])); }
  2381.     */
  2382.     switch (e.i) {
  2383.         case TP_IEOF: tp_return(tp,tp_None); SR(0); break;
  2384.         case TP_IADD: RA = tp_add(tp,RB,RC); break;
  2385.         case TP_ISUB: RA = tp_sub(tp,RB,RC); break;
  2386.         case TP_IMUL: RA = tp_mul(tp,RB,RC); break;
  2387.         case TP_IDIV: RA = tp_div(tp,RB,RC); break;
  2388.         case TP_IPOW: RA = tp_pow(tp,RB,RC); break;
  2389.         case TP_IBITAND: RA = tp_bitwise_and(tp,RB,RC); break;
  2390.         case TP_IBITOR:  RA = tp_bitwise_or(tp,RB,RC); break;
  2391.         case TP_IBITXOR:  RA = tp_bitwise_xor(tp,RB,RC); break;
  2392.         case TP_IMOD:  RA = tp_mod(tp,RB,RC); break;
  2393.         case TP_ILSH:  RA = tp_lsh(tp,RB,RC); break;
  2394.         case TP_IRSH:  RA = tp_rsh(tp,RB,RC); break;
  2395.         case TP_ICMP: RA = tp_number(tp_cmp(tp,RB,RC)); break;
  2396.         case TP_INE: RA = tp_number(tp_cmp(tp,RB,RC)!=0); break;
  2397.         case TP_IEQ: RA = tp_number(tp_cmp(tp,RB,RC)==0); break;
  2398.         case TP_ILE: RA = tp_number(tp_cmp(tp,RB,RC)<=0); break;
  2399.         case TP_ILT: RA = tp_number(tp_cmp(tp,RB,RC)<0); break;
  2400.         case TP_IBITNOT:  RA = tp_bitwise_not(tp,RB); break;
  2401.         case TP_INOT: RA = tp_number(!tp_bool(tp,RB)); break;
  2402.         case TP_IPASS: break;
  2403.         case TP_IIF: if (tp_bool(tp,RA)) { cur += 1; } break;
  2404.         case TP_IIFN: if (!tp_bool(tp,RA)) { cur += 1; } break;
  2405.         case TP_IGET: RA = tp_get(tp,RB,RC); GA; break;
  2406.         case TP_IITER:
  2407.             if (RC.number.val < tp_len(tp,RB).number.val) {
  2408.                 RA = tp_iter(tp,RB,RC); GA;
  2409.                 RC.number.val += 1;
  2410.                 #ifdef TP_SANDBOX
  2411.                 tp_bounds(tp,cur,1);
  2412.                 #endif
  2413.                 cur += 1;
  2414.             }
  2415.             break;
  2416.         case TP_IHAS: RA = tp_has(tp,RB,RC); break;
  2417.         case TP_IIGET: tp_iget(tp,&RA,RB,RC); break;
  2418.         case TP_ISET: tp_set(tp,RA,RB,RC); break;
  2419.         case TP_IDEL: tp_del(tp,RA,RB); break;
  2420.         case TP_IMOVE: RA = RB; break;
  2421.         case TP_INUMBER:
  2422.             #ifdef TP_SANDBOX
  2423.             tp_bounds(tp,cur,sizeof(tp_num)/4);
  2424.             #endif
  2425.             RA = tp_number(*(tp_num*)(*++cur).string.val);
  2426.             cur += sizeof(tp_num)/4;
  2427.             continue;
  2428.         case TP_ISTRING: {
  2429.             #ifdef TP_SANDBOX
  2430.             tp_bounds(tp,cur,(UVBC/4)+1);
  2431.             #endif
  2432.             /* RA = tp_string_n((*(cur+1)).string.val,UVBC); */
  2433.             int a = (*(cur+1)).string.val-f->code.string.val;
  2434.             RA = tp_string_sub(tp,f->code,a,a+UVBC),
  2435.             cur += (UVBC/4)+1;
  2436.             }
  2437.             break;
  2438.         case TP_IDICT: RA = tp_dict_n(tp,VC/2,&RB); break;
  2439.         case TP_ILIST: RA = tp_list_n(tp,VC,&RB); break;
  2440.         case TP_IPARAMS: RA = tp_params_n(tp,VC,&RB); break;
  2441.         case TP_ILEN: RA = tp_len(tp,RB); break;
  2442.         case TP_IJUMP: cur += SVBC; continue; break;
  2443.         case TP_ISETJMP: f->jmp = SVBC?cur+SVBC:0; break;
  2444.         case TP_ICALL:
  2445.             #ifdef TP_SANDBOX
  2446.             tp_bounds(tp,cur,1);
  2447.             #endif
  2448.             f->cur = cur + 1;  RA = tp_call(tp,RB,RC); GA;
  2449.             return 0; break;
  2450.         case TP_IGGET:
  2451.             if (!tp_iget(tp,&RA,f->globals,RB)) {
  2452.                 RA = tp_get(tp,tp->builtins,RB); GA;
  2453.             }
  2454.             break;
  2455.         case TP_IGSET: tp_set(tp,f->globals,RA,RB); break;
  2456.         case TP_IDEF: {
  2457. /*            RA = tp_def(tp,(*(cur+1)).string.val,f->globals);*/
  2458.             #ifdef TP_SANDBOX
  2459.             tp_bounds(tp,cur,SVBC);
  2460.             #endif
  2461.             int a = (*(cur+1)).string.val-f->code.string.val;
  2462.             RA = tp_def(tp,
  2463.                 /*tp_string_n((*(cur+1)).string.val,(SVBC-1)*4),*/
  2464.                 tp_string_sub(tp,f->code,a,a+(SVBC-1)*4),
  2465.                 f->globals);
  2466.             cur += SVBC; continue;
  2467.             }
  2468.             break;
  2469.  
  2470.         case TP_IRETURN: tp_return(tp,RA); SR(0); break;
  2471.         case TP_IRAISE: _tp_raise(tp,RA); SR(0); break;
  2472.         case TP_IDEBUG:
  2473.             tp_params_v(tp,3,tp_string("DEBUG:"),tp_number(VA),RA); tp_print(tp);
  2474.             break;
  2475.         case TP_INONE: RA = tp_None; break;
  2476.         case TP_ILINE:
  2477.             #ifdef TP_SANDBOX
  2478.             tp_bounds(tp,cur,VA);
  2479.             #endif
  2480.             ;
  2481.             int a = (*(cur+1)).string.val-f->code.string.val;
  2482. /*            f->line = tp_string_n((*(cur+1)).string.val,VA*4-1);*/
  2483.             f->line = tp_string_sub(tp,f->code,a,a+VA*4-1);
  2484. /*             fprintf(stderr,"%7d: %s\n",UVBC,f->line.string.val);*/
  2485.             cur += VA; f->lineno = UVBC;
  2486.             break;
  2487.         case TP_IFILE: f->fname = RA; break;
  2488.         case TP_INAME: f->name = RA; break;
  2489.         case TP_IREGS: f->cregs = VA; break;
  2490.         default:
  2491.             tp_raise(0,tp_string("(tp_step) RuntimeError: invalid instruction"));
  2492.             break;
  2493.     }
  2494.     #ifdef TP_SANDBOX
  2495.     tp_time_update(tp);
  2496.     tp_mem_update(tp);
  2497.     tp_bounds(tp,cur,1);
  2498.     #endif
  2499.     cur += 1;
  2500.     }
  2501.     SR(0);
  2502. }
  2503.  
  2504. void _tp_run(TP,int cur) {
  2505.     tp->jmp += 1; if (setjmp(tp->buf)) { tp_handle(tp); }
  2506.     while (tp->cur >= cur && tp_step(tp) != -1);
  2507.     tp->jmp -= 1;
  2508. }
  2509.  
  2510. void tp_run(TP,int cur) {
  2511.     jmp_buf tmp;
  2512.     memcpy(tmp,tp->buf,sizeof(jmp_buf));
  2513.     _tp_run(tp,cur);
  2514.     memcpy(tp->buf,tmp,sizeof(jmp_buf));
  2515. }
  2516.  
  2517.  
  2518. tp_obj tp_ez_call(TP, const char *mod, const char *fnc, tp_obj params) {
  2519.     tp_obj tmp;
  2520.     tmp = tp_get(tp,tp->modules,tp_string(mod));
  2521.     tmp = tp_get(tp,tmp,tp_string(fnc));
  2522.     return tp_call(tp,tmp,params);
  2523. }
  2524.  
  2525. tp_obj _tp_import(TP, tp_obj fname, tp_obj name, tp_obj code) {
  2526.     tp_obj g;
  2527.  
  2528.     if (!((fname.type != TP_NONE && _tp_str_index(fname,tp_string(".tpc"))!=-1) || code.type != TP_NONE)) {
  2529.         return tp_ez_call(tp,"py2bc","import_fname",tp_params_v(tp,2,fname,name));
  2530.     }
  2531.  
  2532.     if (code.type == TP_NONE) {
  2533.         tp_params_v(tp,1,fname);
  2534.         code = tp_load(tp);
  2535.     }
  2536.  
  2537.     g = tp_dict(tp);
  2538.     tp_set(tp,g,tp_string("__name__"),name);
  2539.     tp_set(tp,g,tp_string("__code__"),code);
  2540.     tp_set(tp,g,tp_string("__dict__"),g);
  2541.     tp_frame(tp,g,code,0);
  2542.     tp_set(tp,tp->modules,name,g);
  2543.  
  2544.     if (!tp->jmp) { tp_run(tp,tp->cur); }
  2545.  
  2546.     return g;
  2547. }
  2548.  
  2549.  
  2550. /* Function: tp_import
  2551.  * Imports a module.
  2552.  *
  2553.  * Parameters:
  2554.  * fname - The filename of a file containing the module's code.
  2555.  * name - The name of the module.
  2556.  * codes - The module's code.  If this is given, fname is ignored.
  2557.  * len - The length of the bytecode.
  2558.  *
  2559.  * Returns:
  2560.  * The module object.
  2561.  */
  2562. tp_obj tp_import(TP, const char * fname, const char * name, void *codes, int len) {
  2563.     tp_obj f = fname?tp_string(fname):tp_None;
  2564.     tp_obj bc = codes?tp_string_n((const char*)codes,len):tp_None;
  2565.     return _tp_import(tp,f,tp_string(name),bc);
  2566. }
  2567.  
  2568.  
  2569.  
  2570. tp_obj tp_exec_(TP) {
  2571.     tp_obj code = TP_OBJ();
  2572.     tp_obj globals = TP_OBJ();
  2573.     tp_obj r = tp_None;
  2574.     tp_frame(tp,globals,code,&r);
  2575.     tp_run(tp,tp->cur);
  2576.     return r;
  2577. }
  2578.  
  2579.  
  2580. tp_obj tp_import_(TP) {
  2581.     tp_obj mod = TP_OBJ();
  2582.     tp_obj r;
  2583.  
  2584.     if (tp_has(tp,tp->modules,mod).number.val) {
  2585.         return tp_get(tp,tp->modules,mod);
  2586.     }
  2587.  
  2588.     r = _tp_import(tp,tp_add(tp,mod,tp_string(".tpc")),mod,tp_None);
  2589.     return r;
  2590. }
  2591.  
  2592. void tp_builtins(TP) {
  2593.     tp_obj o;
  2594.     struct {const char *s;void *f;} b[] = {
  2595.     {"print",tp_print}, {"range",tp_range}, {"min",tp_min},
  2596.     {"max",tp_max}, {"bind",tp_bind}, {"copy",tp_copy},
  2597.     {"import",tp_import_}, {"len",tp_len_}, {"assert",tp_assert},
  2598.     {"str",tp_str2}, {"float",tp_float}, {"system",tp_system},
  2599.     {"istype",tp_istype}, {"chr",tp_chr}, {"save",tp_save},
  2600.     {"load",tp_load}, {"fpack",tp_fpack}, {"abs",tp_abs},
  2601.     {"int",tp_int}, {"exec",tp_exec_}, {"exists",tp_exists},
  2602.     {"mtime",tp_mtime}, {"number",tp_float}, {"round",tp_round},
  2603.     {"ord",tp_ord}, {"merge",tp_merge}, {"getraw",tp_getraw},
  2604.     {"setmeta",tp_setmeta}, {"getmeta",tp_getmeta},
  2605.     {"bool", tp_builtins_bool},
  2606.     #ifdef TP_SANDBOX
  2607.     {"sandbox",tp_sandbox_},
  2608.     #endif
  2609.     {0,0},
  2610.     };
  2611.     int i; for(i=0; b[i].s; i++) {
  2612.         tp_set(tp,tp->builtins,tp_string(b[i].s),tp_fnc(tp,(tp_obj (*)(tp_vm *))b[i].f));
  2613.     }
  2614.  
  2615.     o = tp_object(tp);
  2616.     tp_set(tp,o,tp_string("__call__"),tp_fnc(tp,tp_object_call));
  2617.     tp_set(tp,o,tp_string("__new__"),tp_fnc(tp,tp_object_new));
  2618.     tp_set(tp,tp->builtins,tp_string("object"),o);
  2619. }
  2620.  
  2621.  
  2622. void tp_args(TP,int argc, char *argv[]) {
  2623.     tp_obj self = tp_list(tp);
  2624.     int i;
  2625.     for (i=1; i<argc; i++) { _tp_list_append(tp,self.list.val,tp_string(argv[i])); }
  2626.     tp_set(tp,tp->builtins,tp_string("ARGV"),self);
  2627. }
  2628.  
  2629. tp_obj tp_main(TP,char *fname, void *code, int len) {
  2630.     return tp_import(tp,fname,"__main__",code, len);
  2631. }
  2632.  
  2633. /* Function: tp_compile
  2634.  * Compile some tinypy code.
  2635.  *
  2636.  */
  2637. tp_obj tp_compile(TP, tp_obj text, tp_obj fname) {
  2638.     return tp_ez_call(tp,"BUILTINS","compile",tp_params_v(tp,2,text,fname));
  2639. }
  2640.  
  2641. /* Function: tp_exec
  2642.  * Execute VM code.
  2643.  */
  2644. tp_obj tp_exec(TP, tp_obj code, tp_obj globals) {
  2645.     tp_obj r=tp_None;
  2646.     tp_frame(tp,globals,code,&r);
  2647.     tp_run(tp,tp->cur);
  2648.     return r;
  2649. }
  2650.  
  2651. tp_obj tp_eval(TP, const char *text, tp_obj globals) {
  2652.     tp_obj code = tp_compile(tp,tp_string(text),tp_string("<eval>"));
  2653.     return tp_exec(tp,code,globals);
  2654. }
  2655.  
  2656. /* Function: tp_init
  2657.  * Initializes a new virtual machine.
  2658.  *
  2659.  * The given parameters have the same format as the parameters to main, and
  2660.  * allow passing arguments to your tinypy scripts.
  2661.  *
  2662.  * Returns:
  2663.  * The newly created tinypy instance.
  2664.  */
  2665. tp_vm *tp_init(int argc, char *argv[]) {
  2666.     tp_vm *tp = _tp_init();
  2667.     tp_builtins(tp);
  2668.     tp_args(tp,argc,argv);
  2669.     tp_compiler(tp);
  2670.     return tp;
  2671. }
  2672.  
  2673. #ifndef TP_COMPILER
  2674. #define TP_COMPILER 1
  2675. #endif
  2676.  
  2677. #ifdef TP_SANDBOX
  2678. #endif
  2679.  
  2680. void tp_compiler(TP);
  2681.  
  2682. tp_obj tp_None = {TP_NONE};
  2683.  
  2684. #if TP_COMPILER
  2685. void tp_compiler(TP) {
  2686.     tp_import(tp,0,"tokenize",tp_tokenize,sizeof(tp_tokenize));
  2687.     tp_import(tp,0,"parse",tp_parse,sizeof(tp_parse));
  2688.     tp_import(tp,0,"encode",tp_encode,sizeof(tp_encode));
  2689.     tp_import(tp,0,"py2bc",tp_py2bc,sizeof(tp_py2bc));
  2690.     tp_ez_call(tp,"py2bc","_init",tp_None);
  2691. }
  2692. #else
  2693. void tp_compiler(TP) { }
  2694. #endif
  2695.  
  2696. /**/
  2697.  
  2698. void tp_sandbox(TP, double time_limit, unsigned long mem_limit) {
  2699.     tp->time_limit = time_limit;
  2700.     tp->mem_limit = mem_limit;
  2701. }
  2702.  
  2703. void tp_mem_update(TP) {
  2704. /*    static long maxmem = 0;
  2705.     if (tp->mem_used/1024 > maxmem) {
  2706.         maxmem = tp->mem_used/1024;
  2707.         fprintf(stderr,"%ld k\n",maxmem);
  2708.     }*/
  2709.     if((!tp->mem_exceeded) &&
  2710.        (tp->mem_used > tp->mem_limit) &&
  2711.        (tp->mem_limit != TP_NO_LIMIT)) {
  2712.         tp->mem_exceeded = 1;
  2713.         tp_raise(,tp_string("(tp_mem_update) SandboxError: memory limit exceeded"));
  2714.     }
  2715. }
  2716.  
  2717. void tp_time_update(TP) {
  2718.     clock_t tmp = tp->clocks;
  2719.     if(tp->time_limit != TP_NO_LIMIT)
  2720.     {
  2721.         tp->clocks = clock();
  2722.         tp->time_elapsed += ((double) (tp->clocks - tmp) / CLOCKS_PER_SEC) * 1000.0;
  2723.         if(tp->time_elapsed >= tp->time_limit)
  2724.             tp_raise(,tp_string("(tp_time_update) SandboxError: time limit exceeded"));
  2725.     }
  2726. }
  2727.  
  2728. #ifdef TP_SANDBOX
  2729.  
  2730. void *tp_malloc(TP, unsigned long bytes) {
  2731.     unsigned long *ptr = (unsigned long *) calloc(bytes + sizeof(unsigned long), 1);
  2732.     if(ptr) {
  2733.         *ptr = bytes;
  2734.         tp->mem_used += bytes + sizeof(unsigned long);
  2735.     }
  2736.     tp_mem_update(tp);
  2737.     return ptr+1;
  2738. }
  2739.  
  2740. void tp_free(TP, void *ptr) {
  2741.     unsigned long *temp = (unsigned long *) ptr;
  2742.     if(temp) {
  2743.         --temp;
  2744.         tp->mem_used -= (*temp + sizeof(unsigned long));
  2745.         free(temp);
  2746.     }
  2747.     tp_mem_update(tp);
  2748. }
  2749.  
  2750. void *tp_realloc(TP, void *ptr, unsigned long bytes) {
  2751.     unsigned long *temp = (unsigned long *) ptr;
  2752.     int diff;
  2753.     if(temp && bytes) {
  2754.         --temp;
  2755.         diff = bytes - *temp;
  2756.         *temp = bytes;
  2757.         tp->mem_used += diff;
  2758.         temp = (unsigned long *) realloc(temp, bytes+sizeof(unsigned long));
  2759.         return temp+1;
  2760.     }
  2761.     else if(temp && !bytes) {
  2762.         tp_free(tp, temp);
  2763.         return NULL;
  2764.     }
  2765.     else if(!temp && bytes) {
  2766.         return tp_malloc(tp, bytes);
  2767.     }
  2768.     else {
  2769.         return NULL;
  2770.     }
  2771. }
  2772.  
  2773. #endif
  2774.  
  2775. tp_obj tp_sandbox_(TP) {
  2776.     tp_num time = TP_NUM();
  2777.     tp_num mem = TP_NUM();
  2778.     tp_sandbox(tp, time, mem);
  2779.     tp_del(tp, tp->builtins, tp_string("sandbox"));
  2780.     tp_del(tp, tp->builtins, tp_string("mtime"));
  2781.     tp_del(tp, tp->builtins, tp_string("load"));
  2782.     tp_del(tp, tp->builtins, tp_string("save"));
  2783.     tp_del(tp, tp->builtins, tp_string("system"));
  2784.     return tp_None;
  2785. }
  2786.  
  2787. void tp_bounds(TP, tp_code *cur, int n) {
  2788.     char *s = (char *)(cur + n);
  2789.     tp_obj code = tp->frames[tp->cur].code;
  2790.     if (s < code.string.val || s > (code.string.val+code.string.len)) {
  2791.         tp_raise(,tp_string("(tp_bounds) SandboxError: bytecode bounds reached"));
  2792.     }
  2793. }
  2794.