• 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_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