1 #include "pegen.h"
2 #include "pycore_compile.h" // _PyAST_Compile()
3
4
5 PyObject *
_build_return_object(mod_ty module,int mode,PyObject * filename_ob,PyArena * arena)6 _build_return_object(mod_ty module, int mode, PyObject *filename_ob, PyArena *arena)
7 {
8 PyObject *result = NULL;
9
10 if (mode == 2) {
11 result = (PyObject *)_PyAST_Compile(module, filename_ob, NULL, -1, arena);
12 } else if (mode == 1) {
13 result = PyAST_mod2obj(module);
14 } else {
15 result = Py_None;
16 Py_INCREF(result);
17 }
18
19 return result;
20 }
21
22 static PyObject *
parse_file(PyObject * self,PyObject * args,PyObject * kwds)23 parse_file(PyObject *self, PyObject *args, PyObject *kwds)
24 {
25 static char *keywords[] = {"file", "mode", NULL};
26 const char *filename;
27 int mode = 2;
28 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", keywords, &filename, &mode)) {
29 return NULL;
30 }
31 if (mode < 0 || mode > 2) {
32 return PyErr_Format(PyExc_ValueError, "Bad mode, must be 0 <= mode <= 2");
33 }
34
35 PyArena *arena = _PyArena_New();
36 if (arena == NULL) {
37 return NULL;
38 }
39
40 PyObject *result = NULL;
41
42 PyObject *filename_ob = PyUnicode_FromString(filename);
43 if (filename_ob == NULL) {
44 goto error;
45 }
46
47 FILE *fp = fopen(filename, "rb");
48 if (fp == NULL) {
49 PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
50 goto error;
51 }
52
53 PyCompilerFlags flags = _PyCompilerFlags_INIT;
54 mod_ty res = _PyPegen_run_parser_from_file_pointer(
55 fp, Py_file_input, filename_ob,
56 NULL, NULL, NULL, &flags, NULL, arena);
57 fclose(fp);
58 if (res == NULL) {
59 goto error;
60 }
61
62 result = _build_return_object(res, mode, filename_ob, arena);
63
64 error:
65 Py_XDECREF(filename_ob);
66 _PyArena_Free(arena);
67 return result;
68 }
69
70 static PyObject *
parse_string(PyObject * self,PyObject * args,PyObject * kwds)71 parse_string(PyObject *self, PyObject *args, PyObject *kwds)
72 {
73 static char *keywords[] = {"str", "mode", NULL};
74 const char *the_string;
75 int mode = 2;
76 if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", keywords, &the_string, &mode)) {
77 return NULL;
78 }
79 if (mode < 0 || mode > 2) {
80 return PyErr_Format(PyExc_ValueError, "Bad mode, must be 0 <= mode <= 2");
81 }
82
83 PyArena *arena = _PyArena_New();
84 if (arena == NULL) {
85 return NULL;
86 }
87
88 PyObject *result = NULL;
89
90 PyObject *filename_ob = PyUnicode_FromString("<string>");
91 if (filename_ob == NULL) {
92 goto error;
93 }
94
95 PyCompilerFlags flags = _PyCompilerFlags_INIT;
96 mod_ty res = _PyPegen_run_parser_from_string(the_string, Py_file_input, filename_ob,
97 &flags, arena);
98 if (res == NULL) {
99 goto error;
100 }
101 result = _build_return_object(res, mode, filename_ob, arena);
102
103 error:
104 Py_XDECREF(filename_ob);
105 _PyArena_Free(arena);
106 return result;
107 }
108
109 static PyObject *
clear_memo_stats(PyObject * Py_UNUSED (self),PyObject * Py_UNUSED (ignored))110 clear_memo_stats(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
111 {
112 #if defined(PY_DEBUG)
113 _PyPegen_clear_memo_statistics();
114 #endif
115 Py_RETURN_NONE;
116 }
117
118 static PyObject *
get_memo_stats(PyObject * Py_UNUSED (self),PyObject * Py_UNUSED (ignored))119 get_memo_stats(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
120 {
121 #if defined(PY_DEBUG)
122 return _PyPegen_get_memo_statistics();
123 #else
124 Py_RETURN_NONE;
125 #endif
126 }
127
128 // TODO: Write to Python's sys.stdout instead of C's stdout.
129 static PyObject *
dump_memo_stats(PyObject * Py_UNUSED (self),PyObject * Py_UNUSED (ignored))130 dump_memo_stats(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(ignored))
131 {
132 #if defined(PY_DEBUG)
133 PyObject *list = _PyPegen_get_memo_statistics();
134 if (list == NULL) {
135 return NULL;
136 }
137 Py_ssize_t len = PyList_Size(list);
138 for (Py_ssize_t i = 0; i < len; i++) {
139 PyObject *value = PyList_GetItem(list, i); // Borrowed reference.
140 long count = PyLong_AsLong(value);
141 if (count < 0) {
142 break;
143 }
144 if (count > 0) {
145 printf("%4zd %9ld\n", i, count);
146 }
147 }
148 Py_DECREF(list);
149 #endif
150 Py_RETURN_NONE;
151 }
152
153 static PyMethodDef ParseMethods[] = {
154 {"parse_file", (PyCFunction)(void(*)(void))parse_file, METH_VARARGS|METH_KEYWORDS, "Parse a file."},
155 {"parse_string", (PyCFunction)(void(*)(void))parse_string, METH_VARARGS|METH_KEYWORDS, "Parse a string."},
156 {"clear_memo_stats", clear_memo_stats, METH_NOARGS},
157 {"dump_memo_stats", dump_memo_stats, METH_NOARGS},
158 {"get_memo_stats", get_memo_stats, METH_NOARGS},
159 {NULL, NULL, 0, NULL} /* Sentinel */
160 };
161
162 static struct PyModuleDef parsemodule = {
163 PyModuleDef_HEAD_INIT,
164 .m_name = "parse",
165 .m_doc = "A parser.",
166 .m_methods = ParseMethods,
167 };
168
169 PyMODINIT_FUNC
PyInit_parse(void)170 PyInit_parse(void)
171 {
172 return PyModule_Create(&parsemodule);
173 }
174