NEURON
token_mapping.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 <cstring>
9 #include <map>
10 #include <vector>
11 
12 #include "ast/ast.hpp"
13 #include "lexer/modl.h"
14 #include "lexer/token_mapping.hpp"
15 #include "parser/nmodl/nmodl_parser.hpp"
16 
17 namespace nmodl {
18 
19 using Token = parser::NmodlParser::token;
21 
22 /// details of lexer tokens
23 namespace details {
24 
25 /**
26  * \brief Keywords from NMODL language
27  *
28  * Keywords are defined with key-value pair where key is name
29  * from scanner and value is token type used in parser.
30  *
31  * \todo Some keywords have different token names, e.g. TITLE
32  * keyword has MODEL as a keyword. These token names are used
33  * in multiple context and hence we are keeping original names.
34  * Once we finish code generation part then we change this.
35  */
36 const static std::map<std::string, TokenType> keywords = {
37  {"VERBATIM", Token::VERBATIM},
38  {"COMMENT", Token::BLOCK_COMMENT},
39  {"TITLE", Token::MODEL},
40  {"CONSTANT", Token::CONSTANT},
41  {"PARAMETER", Token::PARAMETER},
42  {"INDEPENDENT", Token::INDEPENDENT},
43  {"ASSIGNED", Token::ASSIGNED},
44  {"INITIAL", Token::INITIAL1},
45  {"DERIVATIVE", Token::DERIVATIVE},
46  {"EQUATION", Token::BREAKPOINT},
47  {"BREAKPOINT", Token::BREAKPOINT},
48  {"CONDUCTANCE", Token::CONDUCTANCE},
49  {"SOLVE", Token::SOLVE},
50  {"STATE", Token::STATE},
51  {"LINEAR", Token::LINEAR},
52  {"NONLINEAR", Token::NONLINEAR},
53  {"DISCRETE", Token::DISCRETE},
54  {"FUNCTION", Token::FUNCTION1},
55  {"FUNCTION_TABLE", Token::FUNCTION_TABLE},
56  {"PROCEDURE", Token::PROCEDURE},
57  {"DEL2", Token::DEL2},
58  {"DEL", Token::DEL},
59  {"LOCAL", Token::LOCAL},
60  {"METHOD", Token::USING},
61  {"STEADYSTATE", Token::STEADYSTATE},
62  {"STEP", Token::STEP},
63  {"WITH", Token::WITH},
64  {"FROM", Token::FROM},
65  {"TO", Token::TO},
66  {"BY", Token::BY},
67  {"if", Token::IF},
68  {"else", Token::ELSE},
69  {"while", Token::WHILE},
70  {"START", Token::START1},
71  {"DEFINE", Token::DEFINE1},
72  {"KINETIC", Token::KINETIC},
73  {"CONSERVE", Token::CONSERVE},
74  {"VS", Token::VS},
75  {"LAG", Token::LAG},
76  {"SWEEP", Token::SWEEP},
77  {"COMPARTMENT", Token::COMPARTMENT},
78  {"LONGITUDINAL_DIFFUSION", Token::LONGDIFUS},
79  {"SOLVEFOR", Token::SOLVEFOR},
80  {"UNITS", Token::UNITS},
81  {"UNITSON", Token::UNITSON},
82  {"UNITSOFF", Token::UNITSOFF},
83  {"TABLE", Token::TABLE},
84  {"DEPEND", Token::DEPEND},
85  {"NEURON", Token::NEURON},
86  {"SUFFIX", Token::SUFFIX},
87  {"POINT_PROCESS", Token::SUFFIX},
88  {"ARTIFICIAL_CELL", Token::SUFFIX},
89  {"NONSPECIFIC_CURRENT", Token::NONSPECIFIC},
90  {"ELECTRODE_CURRENT", Token::ELECTRODE_CURRENT},
91  {"RANGE", Token::RANGE},
92  {"USEION", Token::USEION},
93  {"READ", Token::READ},
94  {"REPRESENTS", Token::REPRESENTS},
95  {"WRITE", Token::WRITE},
96  {"VALENCE", Token::VALENCE},
97  {"CHARGE", Token::VALENCE},
98  {"GLOBAL", Token::GLOBAL},
99  {"POINTER", Token::POINTER},
100  {"RANDOM", Token::RANDOM},
101  {"BBCOREPOINTER", Token::BBCOREPOINTER},
102  {"EXTERNAL", Token::EXTERNAL},
103  {"INCLUDE", Token::INCLUDE1},
104  {"CONSTRUCTOR", Token::CONSTRUCTOR},
105  {"DESTRUCTOR", Token::DESTRUCTOR},
106  {"NET_RECEIVE", Token::NETRECEIVE},
107  {"BEFORE", Token::BEFORE},
108  {"AFTER", Token::AFTER},
109  {"WATCH", Token::WATCH},
110  {"FOR_NETCONS", Token::FOR_NETCONS},
111  {"THREADSAFE", Token::THREADSAFE},
112  {"PROTECT", Token::PROTECT},
113  {"MUTEXLOCK", Token::NRNMUTEXLOCK},
114  {"MUTEXUNLOCK", Token::NRNMUTEXUNLOCK}};
115 
116 
117 /**
118  * \class MethodInfo
119  * \brief Information about integration method
120  */
121 struct MethodInfo {
122  /// block types where this method will work with
123  int64_t subtype = 0;
124 
125  /// true if it is a variable timestep method
127 
128  MethodInfo() = default;
129 
130  MethodInfo(int64_t s, int v)
131  : subtype(s)
132  , variable_timestep(v) {}
133 };
134 
135 
136 /**
137  * Integration methods available in the NMODL
138  *
139  * Different integration methods are available in NMODL and they are used with
140  * different block types in NMODL. This variable provide list of method names,
141  * which blocks they can be used with and whether it is usable with variable
142  * timestep.
143  *
144  * \todo MethodInfo::subtype should be changed from integer flag to proper type
145  */
146 const static std::map<std::string, MethodInfo> methods = {{"runge", MethodInfo(DERF | KINF, 0)},
147  {"euler", MethodInfo(DERF | KINF, 0)},
148  {"newton", MethodInfo(NLINF, 0)},
149  {"simeq", MethodInfo(LINF, 0)},
150  {"_advance", MethodInfo(KINF, 0)},
151  {"sparse", MethodInfo(KINF, 0)},
152  {"matexp", MethodInfo(KINF, 0)},
153  {"derivimplicit", MethodInfo(DERF, 0)},
154  {"cnexp", MethodInfo(DERF, 0)},
155  {"after_cvode", MethodInfo(0, 0)},
156  {"cvode_t", MethodInfo(0, 0)},
157  {"cvode_t_v", MethodInfo(0, 0)}};
158 
159 const static std::vector<std::string> extern_definitions = {"acos",
160  "asin",
161  "at_time",
162  "atan",
163  "atan2",
164  "b_flux",
165  "boundary",
166  "ceil",
167  "cos",
168  "cosh",
169  "deflate",
170  "derivs",
171  "erf",
172  "error",
173  "exp",
174  "expfit",
175  "exprand",
176  "f_flux",
177  "fabs",
178  "factorial",
179  "first_time",
180  "floor",
181  "fmod",
182  "force",
183  "gauss",
184  "harmonic",
185  "hyperbol",
186  "invert",
187  "legendre",
188  "log",
189  "log10",
190  "net_event",
191  "net_move",
192  "net_send",
193  "normrand",
194  "nrn_ghk",
195  "nrn_pointing",
196  "nrn_random_play",
197  "perpulse",
198  "perstep",
199  "poisrand",
200  "poisson",
201  "pow",
202  "printf",
203  "prterr",
204  "pulse",
205  "ramp",
206  "revhyperbol",
207  "revsawtooth",
208  "revsigmoid",
209  "romberg",
210  "sawtooth",
211  "schedule",
212  "scop_random",
213  "set_seed",
214  "setseed",
215  "sigmoid",
216  "sin",
217  "sinh",
218  "spline",
219  "sqrt",
220  "squarewave",
221  "state_discontinuity",
222  "step",
223  "stepforce",
224  "tan",
225  "tanh",
226  "threshold"};
227 const static std::vector<std::string> need_nt = {"at_time"};
228 
229 /**
230  * Checks if \c token is one of the functions coming from NEURON/CoreNEURON and needs
231  * passing NrnThread* as first argument (typical name of variable \c nt)
232  *
233  * @param token Name of function
234  * @return True or false depending if the function needs NrnThread* argument
235  */
236 bool needs_neuron_thread_first_arg(const std::string& token) {
237  return std::find(need_nt.cbegin(), need_nt.cend(), token) != need_nt.cend();
238 }
239 
240 
241 /**
242  * Variables from NEURON that are directly used in NMODL
243  *
244  * NEURON exposes certain variable that can be directly used in NMODLvar.
245  * The passes like scope checker needs to know if certain variable is
246  * undefined and hence these needs to be inserted into symbol table
247  */
248 static std::vector<std::string> const NEURON_VARIABLES =
249  {"t", "dt", "celsius", "v", "diam", "area", "pi", "secondorder"};
250 
251 
252 /// Return token type for the keyword
253 TokenType keyword_type(const std::string& name) {
254  return keywords.at(name);
255 }
256 
257 } // namespace details
258 
259 
260 /**
261  * Check if given name is a keyword in NMODL
262  * @param name token name
263  * @return true if name is a keyword
264  */
265 bool is_keyword(const std::string& name) {
266  return details::keywords.find(name) != details::keywords.end();
267 }
268 
269 
270 /**
271  * Check if given name is an integration method in NMODL
272  * @param name Name of the integration method
273  * @return true if name is an integration method in NMODL
274  */
275 bool is_method(const std::string& name) {
276  return (details::methods.find(name) != details::methods.end());
277 }
278 
279 
280 /**
281  * Return token type for given token name
282  * @param name Token name from lexer
283  * @return type of NMODL token
284  */
285 TokenType token_type(const std::string& name) {
286  if (is_keyword(name)) {
287  return details::keyword_type(name);
288  }
289  if (is_method(name)) {
290  return Token::METHOD;
291  }
292  throw std::runtime_error("token_type called for non-existent token " + name);
293 }
294 
295 
296 /**
297  * Return variables declared in NEURON that are available to NMODL
298  * @return vector of NEURON variables
299  */
300 std::vector<std::string> get_external_variables() {
302 }
303 
304 
305 /**
306  * Return functions that can be used in the NMODL
307  * @return vector of function names used in NMODL
308  */
309 std::vector<std::string> get_external_functions() {
310  std::vector<std::string> result;
311  result.reserve(details::methods.size() + details::extern_definitions.size());
312  for (auto& method: details::methods) {
313  result.push_back(method.first);
314  }
315  result.insert(result.cend(),
318  return result;
319 }
320 
321 } // namespace nmodl
Auto generated AST classes declaration.
#define v
Definition: md1redef.h:11
#define STEP
Definition: errcodes.h:33
#define RANGE
Definition: errcodes.h:62
parser::CParser::token Token
Definition: main_c.cpp:28
#define STATE
Definition: membfunc.hpp:65
#define DERF
Definition: model.h:114
#define LINF
Definition: model.h:115
#define KINF
Definition: model.h:120
#define NLINF
Definition: model.h:116
const char * name
Definition: init.cpp:16
static const std::vector< std::string > extern_definitions
bool needs_neuron_thread_first_arg(const std::string &token)
Checks if token is one of the functions coming from NEURON/CoreNEURON and needs passing NrnThread* as...
static const std::map< std::string, MethodInfo > methods
Integration methods available in the NMODL.
static std::vector< std::string > const NEURON_VARIABLES
Variables from NEURON that are directly used in NMODL.
TokenType keyword_type(const std::string &name)
Return token type for the keyword.
static const std::vector< std::string > need_nt
static const std::map< std::string, TokenType > keywords
Keywords from NMODL language.
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
std::vector< std::string > get_external_variables()
Return variables declared in NEURON that are available to NMODL.
TokenType token_type(const std::string &name)
Return token type for given token name.
bool is_method(const std::string &name)
Check if given name is an integration method in NMODL.
std::vector< std::string > get_external_functions()
Return functions that can be used in the NMODL.
parser::NmodlParser::token_type TokenType
Definition: main_nmodl.cpp:35
bool is_keyword(const std::string &name)
Check if given name is a keyword in NMODL.
Legacy macro definitions from mod2c/nocmodl implementation.
s
Definition: multisend.cpp:521
int find(const int, const int, const int, const int, const int)
Information about integration method.
int variable_timestep
true if it is a variable timestep method
MethodInfo(int64_t s, int v)
int64_t subtype
block types where this method will work with
Map different tokens from lexer to token types.
NmodlParser::token_type TokenType
Definition: tokens.cpp:22