Colin Hogben / micropython

Dependents:   micropython-repl

Committer:
pythontech
Date:
Sat Apr 16 17:11:56 2016 +0000
Revision:
0:5868e8752d44
Split off library from repl

Who changed what in which revision?

UserRevisionLine numberNew contents of line
pythontech 0:5868e8752d44 1 /*
pythontech 0:5868e8752d44 2 * This file is part of the Micro Python project, http://micropython.org/
pythontech 0:5868e8752d44 3 *
pythontech 0:5868e8752d44 4 * The MIT License (MIT)
pythontech 0:5868e8752d44 5 *
pythontech 0:5868e8752d44 6 * Copyright (c) 2013, 2014 Damien P. George
pythontech 0:5868e8752d44 7 * Copyright (c) 2014 Paul Sokolovsky
pythontech 0:5868e8752d44 8 *
pythontech 0:5868e8752d44 9 * Permission is hereby granted, free of charge, to any person obtaining a copy
pythontech 0:5868e8752d44 10 * of this software and associated documentation files (the "Software"), to deal
pythontech 0:5868e8752d44 11 * in the Software without restriction, including without limitation the rights
pythontech 0:5868e8752d44 12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
pythontech 0:5868e8752d44 13 * copies of the Software, and to permit persons to whom the Software is
pythontech 0:5868e8752d44 14 * furnished to do so, subject to the following conditions:
pythontech 0:5868e8752d44 15 *
pythontech 0:5868e8752d44 16 * The above copyright notice and this permission notice shall be included in
pythontech 0:5868e8752d44 17 * all copies or substantial portions of the Software.
pythontech 0:5868e8752d44 18 *
pythontech 0:5868e8752d44 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
pythontech 0:5868e8752d44 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
pythontech 0:5868e8752d44 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
pythontech 0:5868e8752d44 22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
pythontech 0:5868e8752d44 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
pythontech 0:5868e8752d44 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
pythontech 0:5868e8752d44 25 * THE SOFTWARE.
pythontech 0:5868e8752d44 26 */
pythontech 0:5868e8752d44 27
pythontech 0:5868e8752d44 28 #include <stdlib.h>
pythontech 0:5868e8752d44 29 #include <string.h>
pythontech 0:5868e8752d44 30
pythontech 0:5868e8752d44 31 #include "py/nlr.h"
pythontech 0:5868e8752d44 32 #include "py/smallint.h"
pythontech 0:5868e8752d44 33 #include "py/objint.h"
pythontech 0:5868e8752d44 34 #include "py/runtime0.h"
pythontech 0:5868e8752d44 35 #include "py/runtime.h"
pythontech 0:5868e8752d44 36
pythontech 0:5868e8752d44 37 #if MICROPY_PY_BUILTINS_FLOAT
pythontech 0:5868e8752d44 38 #include <math.h>
pythontech 0:5868e8752d44 39 #endif
pythontech 0:5868e8752d44 40
pythontech 0:5868e8752d44 41 #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG
pythontech 0:5868e8752d44 42
pythontech 0:5868e8752d44 43 // Python3 no longer has "l" suffix for long ints. We allow to use it
pythontech 0:5868e8752d44 44 // for debugging purpose though.
pythontech 0:5868e8752d44 45 #ifdef DEBUG
pythontech 0:5868e8752d44 46 #define SUFFIX "l"
pythontech 0:5868e8752d44 47 #else
pythontech 0:5868e8752d44 48 #define SUFFIX ""
pythontech 0:5868e8752d44 49 #endif
pythontech 0:5868e8752d44 50
pythontech 0:5868e8752d44 51 #if MICROPY_PY_SYS_MAXSIZE
pythontech 0:5868e8752d44 52 // Export value for sys.maxsize
pythontech 0:5868e8752d44 53 const mp_obj_int_t mp_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX};
pythontech 0:5868e8752d44 54 #endif
pythontech 0:5868e8752d44 55
pythontech 0:5868e8752d44 56 void mp_obj_int_to_bytes_impl(mp_obj_t self_in, bool big_endian, mp_uint_t len, byte *buf) {
pythontech 0:5868e8752d44 57 assert(MP_OBJ_IS_TYPE(self_in, &mp_type_int));
pythontech 0:5868e8752d44 58 mp_obj_int_t *self = self_in;
pythontech 0:5868e8752d44 59 long long val = self->val;
pythontech 0:5868e8752d44 60 if (big_endian) {
pythontech 0:5868e8752d44 61 byte *b = buf + len;
pythontech 0:5868e8752d44 62 while (b > buf) {
pythontech 0:5868e8752d44 63 *--b = val;
pythontech 0:5868e8752d44 64 val >>= 8;
pythontech 0:5868e8752d44 65 }
pythontech 0:5868e8752d44 66 } else {
pythontech 0:5868e8752d44 67 for (; len > 0; --len) {
pythontech 0:5868e8752d44 68 *buf++ = val;
pythontech 0:5868e8752d44 69 val >>= 8;
pythontech 0:5868e8752d44 70 }
pythontech 0:5868e8752d44 71 }
pythontech 0:5868e8752d44 72 }
pythontech 0:5868e8752d44 73
pythontech 0:5868e8752d44 74 int mp_obj_int_sign(mp_obj_t self_in) {
pythontech 0:5868e8752d44 75 mp_longint_impl_t val;
pythontech 0:5868e8752d44 76 if (MP_OBJ_IS_SMALL_INT(self_in)) {
pythontech 0:5868e8752d44 77 val = MP_OBJ_SMALL_INT_VALUE(self_in);
pythontech 0:5868e8752d44 78 } else {
pythontech 0:5868e8752d44 79 mp_obj_int_t *self = self_in;
pythontech 0:5868e8752d44 80 val = self->val;
pythontech 0:5868e8752d44 81 }
pythontech 0:5868e8752d44 82 if (val < 0) {
pythontech 0:5868e8752d44 83 return -1;
pythontech 0:5868e8752d44 84 } else if (val > 0) {
pythontech 0:5868e8752d44 85 return 1;
pythontech 0:5868e8752d44 86 } else {
pythontech 0:5868e8752d44 87 return 0;
pythontech 0:5868e8752d44 88 }
pythontech 0:5868e8752d44 89 }
pythontech 0:5868e8752d44 90
pythontech 0:5868e8752d44 91 // This must handle int and bool types, and must raise a
pythontech 0:5868e8752d44 92 // TypeError if the argument is not integral
pythontech 0:5868e8752d44 93 mp_obj_t mp_obj_int_abs(mp_obj_t self_in) {
pythontech 0:5868e8752d44 94 if (MP_OBJ_IS_TYPE(self_in, &mp_type_int)) {
pythontech 0:5868e8752d44 95 mp_obj_int_t *self = self_in;
pythontech 0:5868e8752d44 96 self = mp_obj_new_int_from_ll(self->val);
pythontech 0:5868e8752d44 97 if (self->val < 0) {
pythontech 0:5868e8752d44 98 // TODO could overflow long long
pythontech 0:5868e8752d44 99 self->val = -self->val;
pythontech 0:5868e8752d44 100 }
pythontech 0:5868e8752d44 101 return self;
pythontech 0:5868e8752d44 102 } else {
pythontech 0:5868e8752d44 103 mp_int_t val = mp_obj_get_int(self_in);
pythontech 0:5868e8752d44 104 if (val == MP_SMALL_INT_MIN) {
pythontech 0:5868e8752d44 105 return mp_obj_new_int_from_ll(-val);
pythontech 0:5868e8752d44 106 } else {
pythontech 0:5868e8752d44 107 if (val < 0) {
pythontech 0:5868e8752d44 108 val = -val;
pythontech 0:5868e8752d44 109 }
pythontech 0:5868e8752d44 110 return MP_OBJ_NEW_SMALL_INT(val);
pythontech 0:5868e8752d44 111 }
pythontech 0:5868e8752d44 112 }
pythontech 0:5868e8752d44 113 }
pythontech 0:5868e8752d44 114
pythontech 0:5868e8752d44 115 mp_obj_t mp_obj_int_unary_op(mp_uint_t op, mp_obj_t o_in) {
pythontech 0:5868e8752d44 116 mp_obj_int_t *o = o_in;
pythontech 0:5868e8752d44 117 switch (op) {
pythontech 0:5868e8752d44 118 case MP_UNARY_OP_BOOL: return mp_obj_new_bool(o->val != 0);
pythontech 0:5868e8752d44 119
pythontech 0:5868e8752d44 120 // truncate value to fit in mp_int_t, which gives the same hash as
pythontech 0:5868e8752d44 121 // small int if the value fits without truncation
pythontech 0:5868e8752d44 122 case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT((mp_int_t)o->val);
pythontech 0:5868e8752d44 123
pythontech 0:5868e8752d44 124 case MP_UNARY_OP_POSITIVE: return o_in;
pythontech 0:5868e8752d44 125 case MP_UNARY_OP_NEGATIVE: return mp_obj_new_int_from_ll(-o->val);
pythontech 0:5868e8752d44 126 case MP_UNARY_OP_INVERT: return mp_obj_new_int_from_ll(~o->val);
pythontech 0:5868e8752d44 127 default: return MP_OBJ_NULL; // op not supported
pythontech 0:5868e8752d44 128 }
pythontech 0:5868e8752d44 129 }
pythontech 0:5868e8752d44 130
pythontech 0:5868e8752d44 131 mp_obj_t mp_obj_int_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
pythontech 0:5868e8752d44 132 long long lhs_val;
pythontech 0:5868e8752d44 133 long long rhs_val;
pythontech 0:5868e8752d44 134
pythontech 0:5868e8752d44 135 if (MP_OBJ_IS_SMALL_INT(lhs_in)) {
pythontech 0:5868e8752d44 136 lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs_in);
pythontech 0:5868e8752d44 137 } else if (MP_OBJ_IS_TYPE(lhs_in, &mp_type_int)) {
pythontech 0:5868e8752d44 138 lhs_val = ((mp_obj_int_t*)lhs_in)->val;
pythontech 0:5868e8752d44 139 } else {
pythontech 0:5868e8752d44 140 return MP_OBJ_NULL; // op not supported
pythontech 0:5868e8752d44 141 }
pythontech 0:5868e8752d44 142
pythontech 0:5868e8752d44 143 if (MP_OBJ_IS_SMALL_INT(rhs_in)) {
pythontech 0:5868e8752d44 144 rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs_in);
pythontech 0:5868e8752d44 145 } else if (MP_OBJ_IS_TYPE(rhs_in, &mp_type_int)) {
pythontech 0:5868e8752d44 146 rhs_val = ((mp_obj_int_t*)rhs_in)->val;
pythontech 0:5868e8752d44 147 } else {
pythontech 0:5868e8752d44 148 // delegate to generic function to check for extra cases
pythontech 0:5868e8752d44 149 return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in);
pythontech 0:5868e8752d44 150 }
pythontech 0:5868e8752d44 151
pythontech 0:5868e8752d44 152 switch (op) {
pythontech 0:5868e8752d44 153 case MP_BINARY_OP_ADD:
pythontech 0:5868e8752d44 154 case MP_BINARY_OP_INPLACE_ADD:
pythontech 0:5868e8752d44 155 return mp_obj_new_int_from_ll(lhs_val + rhs_val);
pythontech 0:5868e8752d44 156 case MP_BINARY_OP_SUBTRACT:
pythontech 0:5868e8752d44 157 case MP_BINARY_OP_INPLACE_SUBTRACT:
pythontech 0:5868e8752d44 158 return mp_obj_new_int_from_ll(lhs_val - rhs_val);
pythontech 0:5868e8752d44 159 case MP_BINARY_OP_MULTIPLY:
pythontech 0:5868e8752d44 160 case MP_BINARY_OP_INPLACE_MULTIPLY:
pythontech 0:5868e8752d44 161 return mp_obj_new_int_from_ll(lhs_val * rhs_val);
pythontech 0:5868e8752d44 162 case MP_BINARY_OP_FLOOR_DIVIDE:
pythontech 0:5868e8752d44 163 case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE:
pythontech 0:5868e8752d44 164 return mp_obj_new_int_from_ll(lhs_val / rhs_val);
pythontech 0:5868e8752d44 165 case MP_BINARY_OP_MODULO:
pythontech 0:5868e8752d44 166 case MP_BINARY_OP_INPLACE_MODULO:
pythontech 0:5868e8752d44 167 return mp_obj_new_int_from_ll(lhs_val % rhs_val);
pythontech 0:5868e8752d44 168
pythontech 0:5868e8752d44 169 case MP_BINARY_OP_AND:
pythontech 0:5868e8752d44 170 case MP_BINARY_OP_INPLACE_AND:
pythontech 0:5868e8752d44 171 return mp_obj_new_int_from_ll(lhs_val & rhs_val);
pythontech 0:5868e8752d44 172 case MP_BINARY_OP_OR:
pythontech 0:5868e8752d44 173 case MP_BINARY_OP_INPLACE_OR:
pythontech 0:5868e8752d44 174 return mp_obj_new_int_from_ll(lhs_val | rhs_val);
pythontech 0:5868e8752d44 175 case MP_BINARY_OP_XOR:
pythontech 0:5868e8752d44 176 case MP_BINARY_OP_INPLACE_XOR:
pythontech 0:5868e8752d44 177 return mp_obj_new_int_from_ll(lhs_val ^ rhs_val);
pythontech 0:5868e8752d44 178
pythontech 0:5868e8752d44 179 case MP_BINARY_OP_LSHIFT:
pythontech 0:5868e8752d44 180 case MP_BINARY_OP_INPLACE_LSHIFT:
pythontech 0:5868e8752d44 181 return mp_obj_new_int_from_ll(lhs_val << (int)rhs_val);
pythontech 0:5868e8752d44 182 case MP_BINARY_OP_RSHIFT:
pythontech 0:5868e8752d44 183 case MP_BINARY_OP_INPLACE_RSHIFT:
pythontech 0:5868e8752d44 184 return mp_obj_new_int_from_ll(lhs_val >> (int)rhs_val);
pythontech 0:5868e8752d44 185
pythontech 0:5868e8752d44 186 case MP_BINARY_OP_POWER:
pythontech 0:5868e8752d44 187 case MP_BINARY_OP_INPLACE_POWER: {
pythontech 0:5868e8752d44 188 long long ans = 1;
pythontech 0:5868e8752d44 189 while (rhs_val > 0) {
pythontech 0:5868e8752d44 190 if (rhs_val & 1) {
pythontech 0:5868e8752d44 191 ans *= lhs_val;
pythontech 0:5868e8752d44 192 }
pythontech 0:5868e8752d44 193 if (rhs_val == 1) {
pythontech 0:5868e8752d44 194 break;
pythontech 0:5868e8752d44 195 }
pythontech 0:5868e8752d44 196 rhs_val /= 2;
pythontech 0:5868e8752d44 197 lhs_val *= lhs_val;
pythontech 0:5868e8752d44 198 }
pythontech 0:5868e8752d44 199 return mp_obj_new_int_from_ll(ans);
pythontech 0:5868e8752d44 200 }
pythontech 0:5868e8752d44 201
pythontech 0:5868e8752d44 202 case MP_BINARY_OP_LESS:
pythontech 0:5868e8752d44 203 return mp_obj_new_bool(lhs_val < rhs_val);
pythontech 0:5868e8752d44 204 case MP_BINARY_OP_MORE:
pythontech 0:5868e8752d44 205 return mp_obj_new_bool(lhs_val > rhs_val);
pythontech 0:5868e8752d44 206 case MP_BINARY_OP_LESS_EQUAL:
pythontech 0:5868e8752d44 207 return mp_obj_new_bool(lhs_val <= rhs_val);
pythontech 0:5868e8752d44 208 case MP_BINARY_OP_MORE_EQUAL:
pythontech 0:5868e8752d44 209 return mp_obj_new_bool(lhs_val >= rhs_val);
pythontech 0:5868e8752d44 210 case MP_BINARY_OP_EQUAL:
pythontech 0:5868e8752d44 211 return mp_obj_new_bool(lhs_val == rhs_val);
pythontech 0:5868e8752d44 212
pythontech 0:5868e8752d44 213 default:
pythontech 0:5868e8752d44 214 return MP_OBJ_NULL; // op not supported
pythontech 0:5868e8752d44 215 }
pythontech 0:5868e8752d44 216 }
pythontech 0:5868e8752d44 217
pythontech 0:5868e8752d44 218 mp_obj_t mp_obj_new_int(mp_int_t value) {
pythontech 0:5868e8752d44 219 if (MP_SMALL_INT_FITS(value)) {
pythontech 0:5868e8752d44 220 return MP_OBJ_NEW_SMALL_INT(value);
pythontech 0:5868e8752d44 221 }
pythontech 0:5868e8752d44 222 return mp_obj_new_int_from_ll(value);
pythontech 0:5868e8752d44 223 }
pythontech 0:5868e8752d44 224
pythontech 0:5868e8752d44 225 mp_obj_t mp_obj_new_int_from_uint(mp_uint_t value) {
pythontech 0:5868e8752d44 226 // SMALL_INT accepts only signed numbers, so make sure the input
pythontech 0:5868e8752d44 227 // value fits completely in the small-int positive range.
pythontech 0:5868e8752d44 228 if ((value & ~MP_SMALL_INT_POSITIVE_MASK) == 0) {
pythontech 0:5868e8752d44 229 return MP_OBJ_NEW_SMALL_INT(value);
pythontech 0:5868e8752d44 230 }
pythontech 0:5868e8752d44 231 return mp_obj_new_int_from_ll(value);
pythontech 0:5868e8752d44 232 }
pythontech 0:5868e8752d44 233
pythontech 0:5868e8752d44 234 mp_obj_t mp_obj_new_int_from_ll(long long val) {
pythontech 0:5868e8752d44 235 mp_obj_int_t *o = m_new_obj(mp_obj_int_t);
pythontech 0:5868e8752d44 236 o->base.type = &mp_type_int;
pythontech 0:5868e8752d44 237 o->val = val;
pythontech 0:5868e8752d44 238 return o;
pythontech 0:5868e8752d44 239 }
pythontech 0:5868e8752d44 240
pythontech 0:5868e8752d44 241 mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) {
pythontech 0:5868e8752d44 242 // TODO raise an exception if the unsigned long long won't fit
pythontech 0:5868e8752d44 243 if (val >> (sizeof(unsigned long long) * 8 - 1) != 0) {
pythontech 0:5868e8752d44 244 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "ulonglong too large"));
pythontech 0:5868e8752d44 245 }
pythontech 0:5868e8752d44 246 mp_obj_int_t *o = m_new_obj(mp_obj_int_t);
pythontech 0:5868e8752d44 247 o->base.type = &mp_type_int;
pythontech 0:5868e8752d44 248 o->val = val;
pythontech 0:5868e8752d44 249 return o;
pythontech 0:5868e8752d44 250 }
pythontech 0:5868e8752d44 251
pythontech 0:5868e8752d44 252 #if MICROPY_PY_BUILTINS_FLOAT
pythontech 0:5868e8752d44 253 mp_obj_t mp_obj_new_int_from_float(mp_float_t val) {
pythontech 0:5868e8752d44 254 int cl = fpclassify(val);
pythontech 0:5868e8752d44 255 if (cl == FP_INFINITE) {
pythontech 0:5868e8752d44 256 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_OverflowError, "can't convert inf to int"));
pythontech 0:5868e8752d44 257 } else if (cl == FP_NAN) {
pythontech 0:5868e8752d44 258 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "can't convert NaN to int"));
pythontech 0:5868e8752d44 259 } else {
pythontech 0:5868e8752d44 260 mp_fp_as_int_class_t icl = mp_classify_fp_as_int(val);
pythontech 0:5868e8752d44 261 if (icl == MP_FP_CLASS_FIT_SMALLINT) {
pythontech 0:5868e8752d44 262 return MP_OBJ_NEW_SMALL_INT((mp_int_t)val);
pythontech 0:5868e8752d44 263 } else if (icl == MP_FP_CLASS_FIT_LONGINT) {
pythontech 0:5868e8752d44 264 return mp_obj_new_int_from_ll((long long)val);
pythontech 0:5868e8752d44 265 } else {
pythontech 0:5868e8752d44 266 nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "float too big"));
pythontech 0:5868e8752d44 267 }
pythontech 0:5868e8752d44 268 }
pythontech 0:5868e8752d44 269 }
pythontech 0:5868e8752d44 270 #endif
pythontech 0:5868e8752d44 271
pythontech 0:5868e8752d44 272 mp_obj_t mp_obj_new_int_from_str_len(const char **str, mp_uint_t len, bool neg, mp_uint_t base) {
pythontech 0:5868e8752d44 273 // TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated
pythontech 0:5868e8752d44 274 // TODO check overflow
pythontech 0:5868e8752d44 275 mp_obj_int_t *o = m_new_obj(mp_obj_int_t);
pythontech 0:5868e8752d44 276 o->base.type = &mp_type_int;
pythontech 0:5868e8752d44 277 char *endptr;
pythontech 0:5868e8752d44 278 o->val = strtoll(*str, &endptr, base);
pythontech 0:5868e8752d44 279 *str = endptr;
pythontech 0:5868e8752d44 280 return o;
pythontech 0:5868e8752d44 281 }
pythontech 0:5868e8752d44 282
pythontech 0:5868e8752d44 283 mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) {
pythontech 0:5868e8752d44 284 if (MP_OBJ_IS_SMALL_INT(self_in)) {
pythontech 0:5868e8752d44 285 return MP_OBJ_SMALL_INT_VALUE(self_in);
pythontech 0:5868e8752d44 286 } else {
pythontech 0:5868e8752d44 287 const mp_obj_int_t *self = self_in;
pythontech 0:5868e8752d44 288 return self->val;
pythontech 0:5868e8752d44 289 }
pythontech 0:5868e8752d44 290 }
pythontech 0:5868e8752d44 291
pythontech 0:5868e8752d44 292 mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) {
pythontech 0:5868e8752d44 293 // TODO: Check overflow
pythontech 0:5868e8752d44 294 return mp_obj_int_get_truncated(self_in);
pythontech 0:5868e8752d44 295 }
pythontech 0:5868e8752d44 296
pythontech 0:5868e8752d44 297 #if MICROPY_PY_BUILTINS_FLOAT
pythontech 0:5868e8752d44 298 mp_float_t mp_obj_int_as_float(mp_obj_t self_in) {
pythontech 0:5868e8752d44 299 if (MP_OBJ_IS_SMALL_INT(self_in)) {
pythontech 0:5868e8752d44 300 return MP_OBJ_SMALL_INT_VALUE(self_in);
pythontech 0:5868e8752d44 301 } else {
pythontech 0:5868e8752d44 302 mp_obj_int_t *self = self_in;
pythontech 0:5868e8752d44 303 return self->val;
pythontech 0:5868e8752d44 304 }
pythontech 0:5868e8752d44 305 }
pythontech 0:5868e8752d44 306 #endif
pythontech 0:5868e8752d44 307
pythontech 0:5868e8752d44 308 #endif