User Guide
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
modl.h
Legacy macro definitions from mod2c/nocmodl implementation.
nmodl::TokenType
parser::NmodlParser::token_type TokenType
Definition: nmodl_utils.hpp:28
nmodl::details::MethodInfo::MethodInfo
MethodInfo()=default
nmodl::details::extern_definitions
const static std::vector< std::string > extern_definitions
Definition: token_mapping.cpp:158
nmodl::get_external_functions
std::vector< std::string > get_external_functions()
Return functions that can be used in the NMODL.
Definition: token_mapping.cpp:308
nmodl::details::needs_neuron_thread_first_arg
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...
Definition: token_mapping.cpp:235
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::details::keyword_type
TokenType keyword_type(const std::string &name)
Return token type for the keyword.
Definition: token_mapping.cpp:252
token_mapping.hpp
Map different tokens from lexer to token types.
nmodl::details::MethodInfo::MethodInfo
MethodInfo(int64_t s, int v)
Definition: token_mapping.cpp:130
nmodl::details::MethodInfo::variable_timestep
int variable_timestep
true if it is a variable timestep method
Definition: token_mapping.cpp:126
LINF
#define LINF
Definition: modl.h:25
nmodl::is_method
bool is_method(const std::string &name)
Check if given name is an integration method in NMODL.
Definition: token_mapping.cpp:274
nmodl::is_keyword
bool is_keyword(const std::string &name)
Check if given name is a keyword in NMODL.
Definition: token_mapping.cpp:264
nmodl::details::need_nt
const static std::vector< std::string > need_nt
Definition: token_mapping.cpp:226
NLINF
#define NLINF
Definition: modl.h:26
Token
parser::CParser::token Token
Definition: main_c.cpp:26
ast.hpp
Auto generated AST classes declaration.
nmodl::details::keywords
const static std::map< std::string, TokenType > keywords
Keywords from NMODL language.
Definition: token_mapping.cpp:36
nmodl::details::MethodInfo
Information about integration method.
Definition: token_mapping.cpp:121
TokenType
parser::NmodlParser::token_type TokenType
Definition: main_nmodl.cpp:35
DERF
#define DERF
bit masks for block types where integration method are used
Definition: modl.h:23
KINF
#define KINF
Definition: modl.h:24
nmodl::details::methods
const static std::map< std::string, MethodInfo > methods
Integration methods available in the NMODL.
Definition: token_mapping.cpp:146
nmodl::details::NEURON_VARIABLES
static const std::vector< std::string > NEURON_VARIABLES
Variables from NEURON that are directly used in NMODL.
Definition: token_mapping.cpp:247
nmodl::token_type
TokenType token_type(const std::string &name)
Return token type for given token name.
Definition: token_mapping.cpp:284
nmodl::get_external_variables
std::vector< std::string > get_external_variables()
Return variables declared in NEURON that are available to NMODL.
Definition: token_mapping.cpp:299
nmodl::details::MethodInfo::subtype
int64_t subtype
block types where this method will work with
Definition: token_mapping.cpp:123