| 1 | #include "Python.h"
 | 
| 2 | 
 | 
| 3 | // Notes on thread-local state that objects use (PyThreadState)
 | 
| 4 | //
 | 
| 5 | // Py_EnterRecursiveCall / Py_LeaveRecursiveCall -- so we don't blow the stack
 | 
| 6 | // Py_ReprEnter / Py_ReprLeave -- for printing [...] in self-referential structures
 | 
| 7 | //
 | 
| 8 | // PyErr_Occurred -- check for exceptions, stubbed in pgenmain
 | 
| 9 | // PyErr_CheckSignals -- for OS signals, stubbed in sigcheck.c, and here
 | 
| 10 | //
 | 
| 11 | // Notes on builtins like int().  See Python/bltinmodule.c.
 | 
| 12 | //
 | 
| 13 | // #define SETBUILTIN(NAME, OBJECT) \
 | 
| 14 | //     if (PyDict_SetItemString(dict, NAME, (PyObject *)OBJECT) < 0)       \
 | 
| 15 | //         return NULL;                                                    \
 | 
| 16 | //     ADD_TO_ALL(OBJECT)
 | 
| 17 | //
 | 
| 18 | // SETBUILTIN("int",                   &PyInt_Type);
 | 
| 19 | //
 | 
| 20 | // It creates the __builtin__ module, which has a __dict__.  And then the types
 | 
| 21 | // are here.   So you can just call a type directly?  Sure.
 | 
| 22 | 
 | 
| 23 | // #include "longintrepr.h"  // 32 bytes
 | 
| 24 | 
 | 
| 25 | #include <stdarg.h>  // va_list, etc.
 | 
| 26 | #include <stdio.h>  // vprintf
 | 
| 27 | 
 | 
| 28 | void Log(const char* fmt, ...) {
 | 
| 29 |   va_list args;
 | 
| 30 |   va_start(args, fmt);
 | 
| 31 |   vprintf(fmt, args);
 | 
| 32 |   va_end(args);
 | 
| 33 |   printf("\n");
 | 
| 34 | }
 | 
| 35 | 
 | 
| 36 | 
 | 
| 37 | int Py_VerboseFlag; /* pythonrun.c, does only intobject.c use it? */
 | 
| 38 | 
 | 
| 39 | PyThreadState *_PyThreadState_Current = NULL;
 | 
| 40 | 
 | 
| 41 | struct _inittab _PyImport_Inittab[] = {
 | 
| 42 |     /* Sentinel */
 | 
| 43 |     {0, 0}
 | 
| 44 | };
 | 
| 45 | 
 | 
| 46 | void
 | 
| 47 | Py_FatalError(const char *msg)
 | 
| 48 | {
 | 
| 49 |     fprintf(stderr, "Fatal Python error: %s\n", msg);
 | 
| 50 |     abort();
 | 
| 51 | }
 | 
| 52 | 
 | 
| 53 | /* Even smaller than Python/sigcheck.c */
 | 
| 54 | int
 | 
| 55 | PyErr_CheckSignals(void)
 | 
| 56 | {
 | 
| 57 | 	return 0;
 | 
| 58 | }
 | 
| 59 | 
 | 
| 60 | /* APIs to write to sys.stdout or sys.stderr using a printf-like interface.
 | 
| 61 |    Adapted from code submitted by Just van Rossum.
 | 
| 62 | 
 | 
| 63 |    PySys_WriteStdout(format, ...)
 | 
| 64 |    PySys_WriteStderr(format, ...)
 | 
| 65 | 
 | 
| 66 |       The first function writes to sys.stdout; the second to sys.stderr.  When
 | 
| 67 |       there is a problem, they write to the real (C level) stdout or stderr;
 | 
| 68 |       no exceptions are raised.
 | 
| 69 | 
 | 
| 70 |       Both take a printf-style format string as their first argument followed
 | 
| 71 |       by a variable length argument list determined by the format string.
 | 
| 72 | 
 | 
| 73 |       *** WARNING ***
 | 
| 74 | 
 | 
| 75 |       The format should limit the total size of the formatted output string to
 | 
| 76 |       1000 bytes.  In particular, this means that no unrestricted "%s" formats
 | 
| 77 |       should occur; these should be limited using "%.<N>s where <N> is a
 | 
| 78 |       decimal number calculated so that <N> plus the maximum size of other
 | 
| 79 |       formatted text does not exceed 1000 bytes.  Also watch out for "%f",
 | 
| 80 |       which can print hundreds of digits for very large numbers.
 | 
| 81 | 
 | 
| 82 |  */
 | 
| 83 | 
 | 
| 84 | static void
 | 
| 85 | mywrite(char *name, FILE *fp, const char *format, va_list va)
 | 
| 86 | {
 | 
| 87 | #ifdef OBJECTS_ONLY
 | 
| 88 |     assert(0);
 | 
| 89 | #else
 | 
| 90 |     PyObject *file;
 | 
| 91 |     PyObject *error_type, *error_value, *error_traceback;
 | 
| 92 | 
 | 
| 93 |     PyErr_Fetch(&error_type, &error_value, &error_traceback);
 | 
| 94 |     file = PySys_GetObject(name);
 | 
| 95 |     if (file == NULL || PyFile_AsFile(file) == fp)
 | 
| 96 |         vfprintf(fp, format, va);
 | 
| 97 |     else {
 | 
| 98 |         char buffer[1001];
 | 
| 99 |         const int written = PyOS_vsnprintf(buffer, sizeof(buffer),
 | 
| 100 |                                            format, va);
 | 
| 101 |         if (PyFile_WriteString(buffer, file) != 0) {
 | 
| 102 |             PyErr_Clear();
 | 
| 103 |             fputs(buffer, fp);
 | 
| 104 |         }
 | 
| 105 |         if (written < 0 || (size_t)written >= sizeof(buffer)) {
 | 
| 106 |             const char *truncated = "... truncated";
 | 
| 107 |             if (PyFile_WriteString(truncated, file) != 0) {
 | 
| 108 |                 PyErr_Clear();
 | 
| 109 |                 fputs(truncated, fp);
 | 
| 110 |             }
 | 
| 111 |         }
 | 
| 112 |     }
 | 
| 113 |     PyErr_Restore(error_type, error_value, error_traceback);
 | 
| 114 | #endif
 | 
| 115 | }
 | 
| 116 | 
 | 
| 117 | /*
 | 
| 118 | void
 | 
| 119 | PySys_WriteStdout(const char *format, ...)
 | 
| 120 | {
 | 
| 121 |     va_list va;
 | 
| 122 | 
 | 
| 123 |     va_start(va, format);
 | 
| 124 |     mywrite("stdout", stdout, format, va);
 | 
| 125 |     va_end(va);
 | 
| 126 | }
 | 
| 127 | */
 | 
| 128 | 
 | 
| 129 | void
 | 
| 130 | PySys_WriteStderr(const char *format, ...)
 | 
| 131 | {
 | 
| 132 |     va_list va;
 | 
| 133 | 
 | 
| 134 |     va_start(va, format);
 | 
| 135 |     mywrite("stderr", stderr, format, va);
 | 
| 136 |     va_end(va);
 | 
| 137 | }
 | 
| 138 | 
 | 
| 139 | 
 | 
| 140 | #define FILE_BEGIN_ALLOW_THREADS(fobj)
 | 
| 141 | #define FILE_END_ALLOW_THREADS(fobj)
 | 
| 142 | 
 | 
| 143 | static PyObject *
 | 
| 144 | err_closed(void)
 | 
| 145 | {
 | 
| 146 |     PyErr_SetString(PyExc_ValueError, "I/O operation on closed file");
 | 
| 147 |     return NULL;
 | 
| 148 | }
 | 
| 149 | 
 | 
| 150 | /* Interfaces to write objects/strings to file-like objects */
 | 
| 151 | 
 | 
| 152 | int
 | 
| 153 | PyFile_WriteObject(PyObject *v, PyObject *f, int flags)
 | 
| 154 | {
 | 
| 155 | #ifdef OBJECTS_ONLY
 | 
| 156 |     assert(0);
 | 
| 157 | #else
 | 
| 158 |     PyObject *writer, *value, *args, *result;
 | 
| 159 |     if (f == NULL) {
 | 
| 160 |         PyErr_SetString(PyExc_TypeError, "writeobject with NULL file");
 | 
| 161 |         return -1;
 | 
| 162 |     }
 | 
| 163 |     else if (PyFile_Check(f)) {
 | 
| 164 |         PyFileObject *fobj = (PyFileObject *) f;
 | 
| 165 | #ifdef Py_USING_UNICODE
 | 
| 166 |         PyObject *enc = fobj->f_encoding;
 | 
| 167 |         int result;
 | 
| 168 | #endif
 | 
| 169 |         if (fobj->f_fp == NULL) {
 | 
| 170 |             err_closed();
 | 
| 171 |             return -1;
 | 
| 172 |         }
 | 
| 173 | #ifdef Py_USING_UNICODE
 | 
| 174 |         if ((flags & Py_PRINT_RAW) &&
 | 
| 175 |             PyUnicode_Check(v) && enc != Py_None) {
 | 
| 176 |             char *cenc = PyString_AS_STRING(enc);
 | 
| 177 |             char *errors = fobj->f_errors == Py_None ?
 | 
| 178 |               "strict" : PyString_AS_STRING(fobj->f_errors);
 | 
| 179 |             value = PyUnicode_AsEncodedString(v, cenc, errors);
 | 
| 180 |             if (value == NULL)
 | 
| 181 |                 return -1;
 | 
| 182 |         } else {
 | 
| 183 |             value = v;
 | 
| 184 |             Py_INCREF(value);
 | 
| 185 |         }
 | 
| 186 |         result = file_PyObject_Print(value, fobj, flags);
 | 
| 187 |         Py_DECREF(value);
 | 
| 188 |         return result;
 | 
| 189 | #else
 | 
| 190 |         return file_PyObject_Print(v, fobj, flags);
 | 
| 191 | #endif
 | 
| 192 |     }
 | 
| 193 |     writer = PyObject_GetAttrString(f, "write");
 | 
| 194 |     if (writer == NULL)
 | 
| 195 |         return -1;
 | 
| 196 |     if (flags & Py_PRINT_RAW) {
 | 
| 197 |         if (PyUnicode_Check(v)) {
 | 
| 198 |             value = v;
 | 
| 199 |             Py_INCREF(value);
 | 
| 200 |         } else
 | 
| 201 |             value = PyObject_Str(v);
 | 
| 202 |     }
 | 
| 203 |     else
 | 
| 204 |         value = PyObject_Repr(v);
 | 
| 205 |     if (value == NULL) {
 | 
| 206 |         Py_DECREF(writer);
 | 
| 207 |         return -1;
 | 
| 208 |     }
 | 
| 209 |     args = PyTuple_Pack(1, value);
 | 
| 210 |     if (args == NULL) {
 | 
| 211 |         Py_DECREF(value);
 | 
| 212 |         Py_DECREF(writer);
 | 
| 213 |         return -1;
 | 
| 214 |     }
 | 
| 215 |     result = PyEval_CallObject(writer, args);
 | 
| 216 |     Py_DECREF(args);
 | 
| 217 |     Py_DECREF(value);
 | 
| 218 |     Py_DECREF(writer);
 | 
| 219 |     if (result == NULL)
 | 
| 220 |         return -1;
 | 
| 221 |     Py_DECREF(result);
 | 
| 222 | #endif
 | 
| 223 |     return 0;
 | 
| 224 | }
 | 
| 225 | 
 | 
| 226 | int
 | 
| 227 | PyFile_WriteString(const char *s, PyObject *f)
 | 
| 228 | {
 | 
| 229 | #ifdef OBJECTS_ONLY
 | 
| 230 |     assert(0);
 | 
| 231 | #else
 | 
| 232 |     if (f == NULL) {
 | 
| 233 |         /* Should be caused by a pre-existing error */
 | 
| 234 |         if (!PyErr_Occurred())
 | 
| 235 |             PyErr_SetString(PyExc_SystemError,
 | 
| 236 |                             "null file for PyFile_WriteString");
 | 
| 237 |         return -1;
 | 
| 238 |     }
 | 
| 239 |     else if (PyFile_Check(f)) {
 | 
| 240 |         PyFileObject *fobj = (PyFileObject *) f;
 | 
| 241 |         FILE *fp = PyFile_AsFile(f);
 | 
| 242 |         if (fp == NULL) {
 | 
| 243 |             err_closed();
 | 
| 244 |             return -1;
 | 
| 245 |         }
 | 
| 246 |         FILE_BEGIN_ALLOW_THREADS(fobj)
 | 
| 247 |         fputs(s, fp);
 | 
| 248 |         FILE_END_ALLOW_THREADS(fobj)
 | 
| 249 |         return 0;
 | 
| 250 |     }
 | 
| 251 |     else if (!PyErr_Occurred()) {
 | 
| 252 |         PyObject *v = PyString_FromString(s);
 | 
| 253 |         int err;
 | 
| 254 |         if (v == NULL)
 | 
| 255 |             return -1;
 | 
| 256 |         err = PyFile_WriteObject(v, f, Py_PRINT_RAW);
 | 
| 257 |         Py_DECREF(v);
 | 
| 258 |         return err;
 | 
| 259 |     }
 | 
| 260 |     else
 | 
| 261 |         return -1;
 | 
| 262 | #endif
 | 
| 263 | }
 | 
| 264 | 
 | 
| 265 | 
 | 
| 266 | /* Stub of function in Python/_warnings.c */
 | 
| 267 | int
 | 
| 268 | PyErr_WarnEx(PyObject *category, const char *text, Py_ssize_t stack_level)
 | 
| 269 | {
 | 
| 270 |   return 0;
 | 
| 271 | }
 | 
| 272 | 
 | 
| 273 | /* from Python/ceval.c */
 | 
| 274 | 
 | 
| 275 | #define Py_DEFAULT_RECURSION_LIMIT 1000
 | 
| 276 | /* a lot of code uses this too */
 | 
| 277 | int _Py_CheckRecursionLimit = Py_DEFAULT_RECURSION_LIMIT;
 | 
| 278 | 
 | 
| 279 | int
 | 
| 280 | Py_GetRecursionLimit(void)
 | 
| 281 | {
 | 
| 282 |     return Py_DEFAULT_RECURSION_LIMIT;
 | 
| 283 | }
 | 
| 284 | 
 | 
| 285 | void
 | 
| 286 | Py_SetRecursionLimit(int new_limit)
 | 
| 287 | {
 | 
| 288 | }
 | 
| 289 | 
 | 
| 290 | int
 | 
| 291 | _Py_CheckRecursiveCall(const char *where)
 | 
| 292 | {
 | 
| 293 |   return 0;
 | 
| 294 | }
 | 
| 295 | 
 | 
| 296 | /* Extract a slice index from a PyInt or PyLong or an object with the
 | 
| 297 |    nb_index slot defined, and store in *pi.
 | 
| 298 |    Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX,
 | 
| 299 |    and silently boost values less than -PY_SSIZE_T_MAX-1 to -PY_SSIZE_T_MAX-1.
 | 
| 300 |    Return 0 on error, 1 on success.
 | 
| 301 | */
 | 
| 302 | /* Note:  If v is NULL, return success without storing into *pi.  This
 | 
| 303 |    is because_PyEval_SliceIndex() is called by apply_slice(), which can be
 | 
| 304 |    called by the SLICE opcode with v and/or w equal to NULL.
 | 
| 305 | */
 | 
| 306 | int
 | 
| 307 | _PyEval_SliceIndex(PyObject *v, Py_ssize_t *pi)
 | 
| 308 | {
 | 
| 309 |     if (v != NULL) {
 | 
| 310 |         Py_ssize_t x;
 | 
| 311 |         if (PyInt_Check(v)) {
 | 
| 312 |             /* XXX(nnorwitz): I think PyInt_AS_LONG is correct,
 | 
| 313 |                however, it looks like it should be AsSsize_t.
 | 
| 314 |                There should be a comment here explaining why.
 | 
| 315 |             */
 | 
| 316 |             x = PyInt_AS_LONG(v);
 | 
| 317 |         }
 | 
| 318 |         else if (PyIndex_Check(v)) {
 | 
| 319 |             x = PyNumber_AsSsize_t(v, NULL);
 | 
| 320 |             if (x == -1 && PyErr_Occurred())
 | 
| 321 |                 return 0;
 | 
| 322 |         }
 | 
| 323 |         else {
 | 
| 324 |             PyErr_SetString(PyExc_TypeError,
 | 
| 325 |                             "slice indices must be integers or "
 | 
| 326 |                             "None or have an __index__ method");
 | 
| 327 |             return 0;
 | 
| 328 |         }
 | 
| 329 |         *pi = x;
 | 
| 330 |     }
 | 
| 331 |     return 1;
 | 
| 332 | }
 | 
| 333 | 
 | 
| 334 | /* External interface to call any callable object.
 | 
| 335 |    The arg must be a tuple or NULL.  The kw must be a dict or NULL. */
 | 
| 336 | 
 | 
| 337 | PyObject *
 | 
| 338 | PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)
 | 
| 339 | {
 | 
| 340 |     PyObject *result;
 | 
| 341 | 
 | 
| 342 |     if (arg == NULL) {
 | 
| 343 |         arg = PyTuple_New(0);
 | 
| 344 |         if (arg == NULL)
 | 
| 345 |             return NULL;
 | 
| 346 |     }
 | 
| 347 |     else if (!PyTuple_Check(arg)) {
 | 
| 348 |         PyErr_SetString(PyExc_TypeError,
 | 
| 349 |                         "argument list must be a tuple");
 | 
| 350 |         return NULL;
 | 
| 351 |     }
 | 
| 352 |     else
 | 
| 353 |         Py_INCREF(arg);
 | 
| 354 | 
 | 
| 355 |     if (kw != NULL && !PyDict_Check(kw)) {
 | 
| 356 |         PyErr_SetString(PyExc_TypeError,
 | 
| 357 |                         "keyword list must be a dictionary");
 | 
| 358 |         Py_DECREF(arg);
 | 
| 359 |         return NULL;
 | 
| 360 |     }
 | 
| 361 | 
 | 
| 362 |     result = PyObject_Call(func, arg, kw);
 | 
| 363 |     Py_DECREF(arg);
 | 
| 364 |     return result;
 | 
| 365 | }
 | 
| 366 | 
 | 
| 367 | /* NOTE: Can't use a switch here because it's not an integer constant!
 | 
| 368 |  *
 | 
| 369 |  * Instead of "with tagswitch", do "with typeswitch"?
 | 
| 370 |  * */
 | 
| 371 | 
 | 
| 372 | void Type(PyObject* obj) {
 | 
| 373 |     struct _typeobject* type = obj->ob_type;
 | 
| 374 | 
 | 
| 375 |     if (type == &PyBool_Type) {
 | 
| 376 |         Log("bool");
 | 
| 377 |     } else if (type == &PyLong_Type) {
 | 
| 378 |         Log("long");
 | 
| 379 |     } else if (type == &PyFloat_Type) {
 | 
| 380 |         Log("float");
 | 
| 381 |     } else if (type == &PyString_Type) {
 | 
| 382 |         Log("string");
 | 
| 383 |     } else if (type == &PyTuple_Type) {
 | 
| 384 |         Log("tuple");
 | 
| 385 |     } else if (type == &PyList_Type) {
 | 
| 386 |         Log("list");
 | 
| 387 |     } else if (type == &PyDict_Type) {
 | 
| 388 |         Log("dict");
 | 
| 389 |     } else {
 | 
| 390 |         Log("unknown type");
 | 
| 391 |     }
 | 
| 392 | }
 | 
| 393 | 
 | 
| 394 | void PrintList(reprfunc list_repr, PyObject* list) {
 | 
| 395 |   PyObject* r = list_repr(list);
 | 
| 396 |   assert(r != NULL);
 | 
| 397 |   PyStringObject* rstr = (PyStringObject*) r;
 | 
| 398 | 
 | 
| 399 |   fprintf(stderr, "list = %.*s\n", (int)rstr->ob_size, rstr->ob_sval);
 | 
| 400 | }
 | 
| 401 | 
 | 
| 402 | int main(int argc, char **argv) {
 | 
| 403 |   PyObject* bool1 = PyBool_FromLong(1);
 | 
| 404 | 
 | 
| 405 |   reprfunc bool_repr = PyBool_Type.tp_repr;
 | 
| 406 |   PyObject* b = bool_repr(bool1);
 | 
| 407 | 
 | 
| 408 |   PyStringObject* br = (PyStringObject*) b;
 | 
| 409 | 
 | 
| 410 |   fprintf(stderr, "true = %.*s\n", (int)br->ob_size, br->ob_sval);
 | 
| 411 | 
 | 
| 412 | 
 | 
| 413 |   PyObject* long1 = PyLong_FromLong(42);
 | 
| 414 |   PyObject* long2 = PyLong_FromLong(1);
 | 
| 415 | 
 | 
| 416 |   binaryfunc long_add = PyLong_Type.tp_as_number->nb_add;
 | 
| 417 |   PyObject* long_sum = long_add(long1, long2);
 | 
| 418 | 
 | 
| 419 |   reprfunc long_repr = PyLong_Type.tp_repr;
 | 
| 420 |   PyObject* r = long_repr(long_sum);
 | 
| 421 | 
 | 
| 422 |   PyStringObject* rstr = (PyStringObject*) r;
 | 
| 423 | 
 | 
| 424 |   fprintf(stderr, "42 + 1 = %.*s\n", (int)rstr->ob_size, rstr->ob_sval);
 | 
| 425 | 
 | 
| 426 | 
 | 
| 427 |   PyObject* float1 = PyFloat_FromDouble(42.1);
 | 
| 428 |   PyObject* float2 = PyFloat_FromDouble(1.2);
 | 
| 429 | 
 | 
| 430 |   binaryfunc float_add = PyFloat_Type.tp_as_number->nb_add;
 | 
| 431 |   PyObject* float_sum = float_add(float1, float2);
 | 
| 432 | 
 | 
| 433 |   reprfunc float_repr = PyFloat_Type.tp_repr;
 | 
| 434 |   PyObject* r3 = float_repr(float_sum);
 | 
| 435 | 
 | 
| 436 |   PyStringObject* rstr3 = (PyStringObject*) r3;
 | 
| 437 | 
 | 
| 438 |   fprintf(stderr, "42.1 + 1.2 = %.*s\n", (int)rstr3->ob_size, rstr3->ob_sval);
 | 
| 439 | 
 | 
| 440 | 
 | 
| 441 |   PyObject* str1 = PyString_FromString("foo ");
 | 
| 442 |   PyObject* str2 = PyString_FromString("bar");
 | 
| 443 | 
 | 
| 444 |   binaryfunc str_add = PyString_Type.tp_as_sequence->sq_concat;
 | 
| 445 |   PyObject* concat = str_add(str1, str2);
 | 
| 446 | 
 | 
| 447 |   reprfunc str_repr = PyString_Type.tp_repr;
 | 
| 448 |   PyObject* r2 = str_repr(concat);
 | 
| 449 | 
 | 
| 450 |   PyStringObject* rstr2 = (PyStringObject*) r2;
 | 
| 451 | 
 | 
| 452 |   fprintf(stderr, "foo + bar = %.*s\n", (int)rstr2->ob_size, rstr2->ob_sval);
 | 
| 453 | 
 | 
| 454 |   // List
 | 
| 455 | 
 | 
| 456 |   PyObject* list = PyList_New(3);
 | 
| 457 |   PyList_SetItem(list, 0, long_sum);
 | 
| 458 |   PyList_SetItem(list, 1, float_sum);
 | 
| 459 |   /* Test the printing of cyclic data structures */
 | 
| 460 |   PyList_SetItem(list, 2, list);
 | 
| 461 | 
 | 
| 462 |   reprfunc list_repr = PyList_Type.tp_repr;
 | 
| 463 |   PyObject* r5 = list_repr(list);
 | 
| 464 |   assert(r5 != NULL);
 | 
| 465 |   PyStringObject* rstr5 = (PyStringObject*) r5;
 | 
| 466 | 
 | 
| 467 |   fprintf(stderr, "list = %.*s\n", (int)rstr5->ob_size, rstr5->ob_sval);
 | 
| 468 | 
 | 
| 469 |   Log("");
 | 
| 470 | 
 | 
| 471 |   // Sort and reverse list
 | 
| 472 |   PyObject* list2 = PyList_New(3);
 | 
| 473 |   PyList_SetItem(list2, 0, long1);
 | 
| 474 |   PyList_SetItem(list2, 1, long2);
 | 
| 475 |   PyList_SetItem(list2, 2, long_sum);
 | 
| 476 |   PrintList(list_repr, list2);
 | 
| 477 | 
 | 
| 478 |   // These are internal API calls.  listsort() and listreverse() are in the
 | 
| 479 |   // method table, and do less work.
 | 
| 480 |   PyList_Sort(list2);
 | 
| 481 |   PrintList(list_repr, list2);
 | 
| 482 | 
 | 
| 483 |   PyList_Reverse(list2);
 | 
| 484 |   PrintList(list_repr, list2);
 | 
| 485 | 
 | 
| 486 |   /* Works if you make it non-static
 | 
| 487 |   listreverse(list2);
 | 
| 488 |   PrintList(list_repr, list2);
 | 
| 489 |   */
 | 
| 490 | 
 | 
| 491 |   Log("");
 | 
| 492 | 
 | 
| 493 |   // Tuple
 | 
| 494 | 
 | 
| 495 |   PyObject* tuple = PyTuple_New(3);
 | 
| 496 |   PyTuple_SetItem(tuple, 0, long_sum);
 | 
| 497 |   PyTuple_SetItem(tuple, 1, float_sum);
 | 
| 498 |   PyTuple_SetItem(tuple, 2, concat);
 | 
| 499 | 
 | 
| 500 |   reprfunc tuple_repr = PyTuple_Type.tp_repr;
 | 
| 501 |   PyObject* r4 = tuple_repr(tuple);
 | 
| 502 |   assert(r4 != NULL);
 | 
| 503 | 
 | 
| 504 |   PyStringObject* rstr4 = (PyStringObject*) r4;
 | 
| 505 | 
 | 
| 506 |   fprintf(stderr, "tuple = %.*s\n", (int)rstr4->ob_size, rstr4->ob_sval);
 | 
| 507 | 
 | 
| 508 |   // Dict
 | 
| 509 | 
 | 
| 510 |   PyObject* dict = PyDict_New();
 | 
| 511 |   PyDict_SetItem(dict, concat, long_sum);
 | 
| 512 | 
 | 
| 513 |   reprfunc dict_repr = PyDict_Type.tp_repr;
 | 
| 514 |   PyObject* d = dict_repr(dict);
 | 
| 515 |   assert(d != NULL);
 | 
| 516 | 
 | 
| 517 |   PyStringObject* dr = (PyStringObject*) d;
 | 
| 518 | 
 | 
| 519 |   fprintf(stderr, "dict = %.*s\n", (int)dr->ob_size, dr->ob_sval);
 | 
| 520 | 
 | 
| 521 |   // suceess
 | 
| 522 |   PyObject* val = PyDict_GetItem(dict, concat);
 | 
| 523 |   Log("val = %p", val);
 | 
| 524 | 
 | 
| 525 |   // fail
 | 
| 526 |   PyObject* val2 = PyDict_GetItem(dict, long1);
 | 
| 527 |   Log("val2 = %p", val2);
 | 
| 528 |   // TODO: How to get exception?
 | 
| 529 | 
 | 
| 530 |   Type(long_sum);
 | 
| 531 |   Type(float_sum);
 | 
| 532 |   Type(list);
 | 
| 533 |   Type(dict);
 | 
| 534 | 
 | 
| 535 |   Log("sizeof(PyBoolObject) = %zu", sizeof(PyBoolObject));  // 24
 | 
| 536 |   // 32 bytes, needs header
 | 
| 537 |   //Log("sizeof(PyLongObject) = %zu", sizeof(PyLongObject));
 | 
| 538 |   Log("sizeof(PyFloatObject) = %zu", sizeof(PyFloatObject));  // 24
 | 
| 539 |   Log("sizeof(PyStringObject) = %zu", sizeof(PyStringObject));  // 40
 | 
| 540 |   Log("sizeof(PyTupleObject) = %zu", sizeof(PyTupleObject));  // 32
 | 
| 541 |   Log("sizeof(PyListObject) = %zu", sizeof(PyListObject));  // 40
 | 
| 542 |   Log("sizeof(PyDictObject) = %zu", sizeof(PyDictObject));  // 248
 | 
| 543 | 
 | 
| 544 | 
 | 
| 545 |   // TODO:
 | 
| 546 |   // - Iterate over dicts and lists
 | 
| 547 |   // - Call methods -- how?
 | 
| 548 |   //   - .keys() and .value() -- see addmethods()
 | 
| 549 |   //   - respect calling convention flags for L.sort() and L.reverse()
 | 
| 550 |   // - Test exceptions like IndexError, KeyError, and more
 | 
| 551 |   // - Other types: slices?  What about range and enumeration?
 | 
| 552 |   // - repr(None)?  How?  Py_None
 | 
| 553 |   //   object.c has PyNone_Type, but it's not in a header!
 | 
| 554 |   // - builtins like int() str()
 | 
| 555 | 	return 0;
 | 
| 556 | }
 |