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