1  #include "pegen.h"
       2  #include "pycore_compile.h"       // _PyAST_Compile()
       3  
       4  
       5  PyObject *
       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 *
      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 *
      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 *
     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 *
     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 *
     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_CAST(parse_file), METH_VARARGS|METH_KEYWORDS, "Parse a file."},
     155      {"parse_string", _PyCFunction_CAST(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
     170  PyInit_parse(void)
     171  {
     172      return PyModule_Create(&parsemodule);
     173  }