User Guide
pynmodl.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Blue Brain Project, EPFL.
3  * See the top-level LICENSE file for details.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include "ast/program.hpp"
9 #include "config/config.h"
10 #include "parser/nmodl_driver.hpp"
11 #include "pybind/pybind_utils.hpp"
13 
14 #include <pybind11/iostream.h>
15 #include <pybind11/pybind11.h>
16 #include <pybind11/stl.h>
17 
18 #include <memory>
19 #include <set>
20 
21 /**
22  * \dir
23  * \brief Python Interface Implementation
24  *
25  * \file
26  * \brief Top level nmodl Python module implementation
27  */
28 
29 namespace py = pybind11;
30 using namespace pybind11::literals;
31 
32 namespace nmodl {
33 
34 /** \brief docstring of Python exposed API */
35 namespace docstring {
36 
37 static const char* const driver = R"(
38  This is the NmodlDriver class documentation
39 )";
40 
41 static const char* const driver_ast = R"(
42  Get ast
43 
44  Returns:
45  Instance of :py:class:`Program`
46 )";
47 
48 static const char* const driver_parse_string = R"(
49  Parse NMODL provided as a string
50 
51  Args:
52  input (str): C code as string
53  Returns:
54  AST: ast root node if success, throws an exception otherwise
55 
56  >>> ast = driver.parse_string("DEFINE NSTEP 6")
57 )";
58 
59 static const char* const driver_parse_file = R"(
60  Parse NMODL provided as a file
61 
62  Args:
63  filename (str): name of the C file
64 
65  Returns:
66  AST: ast root node if success, throws an exception otherwise
67 )";
68 
69 static const char* const driver_parse_stream = R"(
70  Parse NMODL file provided as istream
71 
72  Args:
73  in (file): ifstream object
74 
75  Returns:
76  AST: ast root node if success, throws an exception otherwise
77 )";
78 
79 static const char* const to_nmodl = R"(
80  Given AST node, return the NMODL string representation
81 
82  Args:
83  node (AST): AST node
84  excludeTypes (set of AstNodeType): Excluded node types
85 
86  Returns:
87  str: NMODL string representation
88 
89  >>> ast = driver.parse_string("NEURON{}")
90  >>> nmodl.to_nmodl(ast)
91  'NEURON {\n}\n'
92 )";
93 
94 static const char* const to_json = R"(
95  Given AST node, return the JSON string representation
96 
97  Args:
98  node (AST): AST node
99  compact (bool): Compact node
100  expand (bool): Expand node
101 
102  Returns:
103  str: JSON string representation
104 
105  >>> ast = driver.parse_string("NEURON{}")
106  >>> nmodl.to_json(ast, True)
107  '{"Program":[{"NeuronBlock":[{"StatementBlock":[]}]}]}'
108 )";
109 
110 } // namespace docstring
111 
112 /**
113  * \class PyNmodlDriver
114  * \brief Class to bridge C++ NmodlDriver with Python world using pybind11
115  */
117  public:
118  std::shared_ptr<nmodl::ast::Program> parse_stream(py::object const& object) {
119  py::object tiob = py::module::import("io").attr("TextIOBase");
120  if (py::isinstance(object, tiob)) {
121  py::detail::pythonibuf<py::str> buf(object);
122  std::istream istr(&buf);
123  return NmodlDriver::parse_stream(istr);
124  } else {
125  py::detail::pythonibuf<py::bytes> buf(object);
126  std::istream istr(&buf);
127  return NmodlDriver::parse_stream(istr);
128  }
129  }
130 };
131 
132 } // namespace nmodl
133 
134 // forward declaration of submodule init functions
135 void init_visitor_module(py::module& m);
136 void init_ast_module(py::module& m);
137 void init_symtab_module(py::module& m);
138 
139 PYBIND11_MODULE(_nmodl, m_nmodl) {
140  m_nmodl.doc() = "NMODL : Source-to-Source Code Generation Framework";
141  m_nmodl.attr("__version__") = nmodl::Version::NMODL_VERSION;
142 
143  py::class_<nmodl::parser::NmodlDriver> _{m_nmodl, "nmodl::parser::NmodlDriver"};
144  py::class_<nmodl::PyNmodlDriver, nmodl::parser::NmodlDriver> nmodl_driver(
145  m_nmodl, "NmodlDriver", nmodl::docstring::driver);
146  nmodl_driver.def(py::init<>())
147  .def("parse_string",
149  "input"_a,
151  .def(
152  "parse_file",
153  [](nmodl::PyNmodlDriver& driver, const std::string& file) {
154  return driver.parse_file(file, nullptr);
155  },
156  "filename"_a,
158  .def("parse_stream",
160  "in"_a,
163 
164  m_nmodl.def("to_nmodl",
165  static_cast<std::string (*)(const nmodl::ast::Ast&,
166  const std::set<nmodl::ast::AstNodeType>&)>(
168  "node"_a,
169  "exclude_types"_a = std::set<nmodl::ast::AstNodeType>(),
171  m_nmodl.def("to_json",
173  "node"_a,
174  "compact"_a = false,
175  "expand"_a = false,
176  "add_nmodl"_a = false,
178 
179  init_visitor_module(m_nmodl);
180  init_ast_module(m_nmodl);
181  init_symtab_module(m_nmodl);
182 }
nmodl::parser::NmodlDriver
Class that binds all pieces together for parsing nmodl file.
Definition: nmodl_driver.hpp:67
nmodl::to_nmodl
std::string to_nmodl(const ast::Ast &node, const std::set< ast::AstNodeType > &exclude_types)
Given AST node, return the NMODL string representation.
Definition: visitor_utils.cpp:234
nmodl::docstring::to_json
static const char *const to_json
Definition: pynmodl.cpp:94
nmodl::ast::Ast
Base class for all Abstract Syntax Tree node types.
Definition: ast.hpp:69
nmodl::parser::NmodlDriver::get_ast
const std::shared_ptr< ast::Program > & get_ast() const noexcept
return previously parsed AST otherwise nullptr
Definition: nmodl_driver.hpp:136
init_symtab_module
void init_symtab_module(py::module &m)
nmodl::docstring::driver
static const char *const driver
Definition: pynmodl.cpp:37
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::to_json
std::string to_json(const ast::Ast &node, bool compact, bool expand, bool add_nmodl)
Given AST node, return the JSON string representation.
Definition: visitor_utils.cpp:242
nmodl::docstring::to_nmodl
static const char *const to_nmodl
Definition: pynmodl.cpp:79
nmodl::docstring::driver_ast
static const char *const driver_ast
Definition: pynmodl.cpp:41
nmodl::PyNmodlDriver::parse_stream
std::shared_ptr< nmodl::ast::Program > parse_stream(py::object const &object)
Definition: pynmodl.cpp:118
visitor_utils.hpp
Utility functions for visitors implementation.
program.hpp
Auto generated AST classes declaration.
driver
nmodl::parser::UnitDriver driver
Definition: parser.cpp:28
init_ast_module
void init_ast_module(py::module &m)
PYBIND11_MODULE
PYBIND11_MODULE(_nmodl, m_nmodl)
Definition: pynmodl.cpp:139
nmodl::docstring::driver_parse_string
static const char *const driver_parse_string
Definition: pynmodl.cpp:48
nmodl::parser::NmodlDriver::parse_string
std::shared_ptr< ast::Program > parse_string(const std::string &input)
parser nmodl provided as string (used for testing)
Definition: nmodl_driver.cpp:89
nmodl::Version::NMODL_VERSION
static const std::string NMODL_VERSION
project tagged version in the cmake
Definition: config.h:36
nmodl::docstring::driver_parse_file
static const char *const driver_parse_file
Definition: pynmodl.cpp:59
nmodl_driver.hpp
config.h
Version information and units file path.
nmodl::PyNmodlDriver
Class to bridge C++ NmodlDriver with Python world using pybind11.
Definition: pynmodl.cpp:116
nmodl::docstring::driver_parse_stream
static const char *const driver_parse_stream
Definition: pynmodl.cpp:69
init_visitor_module
void init_visitor_module(py::module &m)
nmodl::parser::UnitDriver::parse_file
bool parse_file(const std::string &filename)
parse Units file
Definition: unit_driver.cpp:29