this repo has no description
at trunk 143 lines 4.2 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include <cstring> 3 4#include "cpython-data.h" 5#include "cpython-func.h" 6#include "cpython-types.h" 7 8extern "C" { 9// Python-ast.h is an internal header. Redeclare the only things we need from 10// it instead of including it. 11typedef struct _mod* mod_ty; 12PyObject* PyAST_mod2obj(mod_ty t); 13} 14 15static const char* source_as_string(PyObject* cmd, PyCompilerFlags* cf, 16 PyObject** cmd_copy) { 17 Py_buffer view; 18 Py_ssize_t size; 19 const char* str; 20 *cmd_copy = nullptr; 21 if (PyUnicode_Check(cmd)) { 22 cf->cf_flags |= PyCF_IGNORE_COOKIE; 23 str = PyUnicode_AsUTF8AndSize(cmd, &size); 24 if (str == nullptr) return nullptr; 25 } else if (PyBytes_Check(cmd)) { 26 str = PyBytes_AS_STRING(cmd); 27 size = PyBytes_GET_SIZE(cmd); 28 } else if (PyByteArray_Check(cmd)) { 29 str = PyByteArray_AS_STRING(cmd); 30 size = PyByteArray_GET_SIZE(cmd); 31 } else if (PyObject_GetBuffer(cmd, &view, PyBUF_SIMPLE) == 0) { 32 // Copy to NUL-terminated buffer. 33 *cmd_copy = PyBytes_FromStringAndSize( 34 const_cast<const char*>(reinterpret_cast<char*>(view.buf)), view.len); 35 PyBuffer_Release(&view); 36 if (*cmd_copy == nullptr) { 37 return nullptr; 38 } 39 str = PyBytes_AS_STRING(*cmd_copy); 40 size = PyBytes_GET_SIZE(*cmd_copy); 41 } else { 42 PyErr_Format(PyExc_TypeError, 43 "parse() arg 1 must be a string, bytes or AST object"); 44 return nullptr; 45 } 46 47 if (strlen(str) != static_cast<size_t>(size)) { 48 PyErr_SetString(PyExc_ValueError, 49 "source code string cannot contain null bytes"); 50 Py_CLEAR(*cmd_copy); 51 return nullptr; 52 } 53 return str; 54} 55 56static PyObject* parse(PyObject* /* module */, PyObject** args, 57 Py_ssize_t nargs, PyObject* kwnames) { 58 static const char* const parser_kwnames[] = {"source", "filename", "mode", 59 "flags", nullptr}; 60 static _PyArg_Parser parser = {"OO&s|i:compile", parser_kwnames, nullptr}; 61 PyObject* source; 62 PyObject* filename; 63 const char* mode; 64 int flags = 0; 65 if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &parser, &source, 66 PyUnicode_FSDecoder, &filename, &mode, 67 &flags)) { 68 return nullptr; 69 } 70 71 int compile_mode = -1; 72 if (std::strcmp(mode, "exec") == 0) { 73 compile_mode = 0; 74 } else if (std::strcmp(mode, "eval") == 0) { 75 compile_mode = 1; 76 } else if (std::strcmp(mode, "single") == 0) { 77 compile_mode = 2; 78 } else { 79 PyErr_SetString(PyExc_ValueError, 80 "parse() mode must be 'exec', 'eval' or 'single'"); 81 Py_DECREF(filename); 82 return nullptr; 83 } 84 85 PyCompilerFlags cf = _PyCompilerFlags_INIT; 86 cf.cf_flags = flags | PyCF_SOURCE_IS_UTF8; 87 PyArena* arena = PyArena_New(); 88 if (arena == nullptr) return nullptr; 89 90 PyObject* source_copy; 91 const char* str = source_as_string(source, &cf, &source_copy); 92 if (str == nullptr) { 93 Py_DECREF(filename); 94 PyArena_Free(arena); 95 return nullptr; 96 } 97 98 static const int start[] = {Py_file_input, Py_eval_input, Py_single_input}; 99 mod_ty mod = PyParser_ASTFromStringObject(str, filename, start[compile_mode], 100 &cf, arena); 101 if (mod == nullptr) { 102 Py_XDECREF(source_copy); 103 PyArena_Free(arena); 104 return nullptr; 105 } 106 PyObject* result = PyAST_mod2obj(mod); 107 Py_XDECREF(source_copy); 108 PyArena_Free(arena); 109 return result; 110} 111 112static PyMethodDef _parse_methods[] = { 113 {"parse", 114 reinterpret_cast<PyCFunction>(reinterpret_cast<void (*)()>(parse)), 115 METH_FASTCALL | METH_KEYWORDS, ""}, 116 {nullptr, nullptr}}; 117 118static struct PyModuleDef _parsermodule = { 119 PyModuleDef_HEAD_INIT, 120 "_parser", 121 "", 122 0, 123 _parse_methods, 124 nullptr, 125 nullptr, 126 nullptr, 127 nullptr, 128}; 129 130PyMODINIT_FUNC PyInit__parser() { 131 PyObject* module = PyState_FindModule(&_parsermodule); 132 if (module != nullptr) { 133 Py_INCREF(module); 134 return module; 135 } 136 module = PyModule_Create(&_parsermodule); 137 if (module == nullptr) { 138 return nullptr; 139 } 140 141 PyState_AddModule(module, &_parsermodule); 142 return module; 143}