• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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