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  {"derivimplicit", MethodInfo(DERF, 0)},
153  {"cnexp", MethodInfo(DERF, 0)},
154  {"after_cvode", MethodInfo(0, 0)},
155  {"cvode_t", MethodInfo(0, 0)},
156  {"cvode_t_v", MethodInfo(0, 0)}};
157 
158 const static std::vector<std::string> extern_definitions = {"acos",
159  "asin",
160  "at_time",
161  "atan",
162  "atan2",
163  "b_flux",
164  "boundary",
165  "ceil",
166  "cos",
167  "cosh",
168  "deflate",
169  "derivs",
170  "erf",
171  "error",
172  "exp",
173  "expfit",
174  "exprand",
175  "f_flux",
176  "fabs",
177  "factorial",
178  "first_time",
179  "floor",
180  "fmod",
181  "force",
182  "gauss",
183  "harmonic",
184  "hyperbol",
185  "invert",
186  "legendre",
187  "log",
188  "log10",
189  "net_event",
190  "net_move",
191  "net_send",
192  "normrand",
193  "nrn_ghk",
194  "nrn_pointing",
195  "nrn_random_play",
196  "perpulse",
197  "perstep",
198  "poisrand",
199  "poisson",
200  "pow",
201  "printf",
202  "prterr",
203  "pulse",
204  "ramp",
205  "revhyperbol",
206  "revsawtooth",
207  "revsigmoid",
208  "romberg",
209  "sawtooth",
210  "schedule",
211  "scop_random",
212  "set_seed",
213  "setseed",
214  "sigmoid",
215  "sin",
216  "sinh",
217  "spline",
218  "sqrt",
219  "squarewave",
220  "state_discontinuity",
221  "step",
222  "stepforce",
223  "tan",
224  "tanh",
225  "threshold"};
226 const static std::vector<std::string> need_nt = {"at_time"};
227 
228 /**
229  * Checks if \c token is one of the functions coming from NEURON/CoreNEURON and needs
230  * passing NrnThread* as first argument (typical name of variable \c nt)
231  *
232  * @param token Name of function
233  * @return True or false depending if the function needs NrnThread* argument
234  */
235 bool needs_neuron_thread_first_arg(const std::string& token) {
236  return std::find(need_nt.cbegin(), need_nt.cend(), token) != need_nt.cend();
237 }
238 
239 
240 /**
241  * Variables from NEURON that are directly used in NMODL
242  *
243  * NEURON exposes certain variable that can be directly used in NMODLvar.
244  * The passes like scope checker needs to know if certain variable is
245  * undefined and hence these needs to be inserted into symbol table
246  */
247 static std::vector<std::string> const NEURON_VARIABLES =
248  {"t", "dt", "celsius", "v", "diam", "area", "pi", "secondorder"};
249 
250 
251 /// Return token type for the keyword
252 TokenType keyword_type(const std::string& name) {
253  return keywords.at(name);
254 }
255 
256 } // namespace details
257 
258 
259 /**
260  * Check if given name is a keyword in NMODL
261  * @param name token name
262  * @return true if name is a keyword
263  */
264 bool is_keyword(const std::string& name) {
265  return details::keywords.find(name) != details::keywords.end();
266 }
267 
268 
269 /**
270  * Check if given name is an integration method in NMODL
271  * @param name Name of the integration method
272  * @return true if name is an integration method in NMODL
273  */
274 bool is_method(const std::string& name) {
275  return (details::methods.find(name) != details::methods.end());
276 }
277 
278 
279 /**
280  * Return token type for given token name
281  * @param name Token name from lexer
282  * @return type of NMODL token
283  */
284 TokenType token_type(const std::string& name) {
285  if (is_keyword(name)) {
286  return details::keyword_type(name);
287  }
288  if (is_method(name)) {
289  return Token::METHOD;
290  }
291  throw std::runtime_error("token_type called for non-existent token " + name);
292 }
293 
294 
295 /**
296  * Return variables declared in NEURON that are available to NMODL
297  * @return vector of NEURON variables
298  */
299 std::vector<std::string> get_external_variables() {
301 }
302 
303 
304 /**
305  * Return functions that can be used in the NMODL
306  * @return vector of function names used in NMODL
307  */
308 std::vector<std::string> get_external_functions() {
309  std::vector<std::string> result;
310  result.reserve(details::methods.size() + details::extern_definitions.size());
311  for (auto& method: details::methods) {
312  result.push_back(method.first);
313  }
314  result.insert(result.cend(),
317  return result;
318 }
319 
320 } // 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