OILS / demo / cpython / py_object_main.c View on Github | oilshell.org

556 lines, 307 significant
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
28void 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
37int Py_VerboseFlag; /* pythonrun.c, does only intobject.c use it? */
38
39PyThreadState *_PyThreadState_Current = NULL;
40
41struct _inittab _PyImport_Inittab[] = {
42 /* Sentinel */
43 {0, 0}
44};
45
46void
47Py_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 */
54int
55PyErr_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
84static void
85mywrite(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/*
118void
119PySys_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
129void
130PySys_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
143static PyObject *
144err_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
152int
153PyFile_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
226int
227PyFile_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 */
267int
268PyErr_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 */
277int _Py_CheckRecursionLimit = Py_DEFAULT_RECURSION_LIMIT;
278
279int
280Py_GetRecursionLimit(void)
281{
282 return Py_DEFAULT_RECURSION_LIMIT;
283}
284
285void
286Py_SetRecursionLimit(int new_limit)
287{
288}
289
290int
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*/
306int
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
337PyObject *
338PyEval_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
372void 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
394void 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
402int 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}