User Guide
nmodl_utils.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 <iostream>
10 
11 #include "ast/ast.hpp"
12 #include "lexer/modtoken.hpp"
13 #include "lexer/nmodl_utils.hpp"
14 #include "lexer/token_mapping.hpp"
15 #include "utils/string_utils.hpp"
16 
17 namespace nmodl {
18 
19 using Parser = parser::NmodlParser;
20 
21 /**
22  * Create a symbol for ast::Double AST class
23  *
24  * @param value Double value parsed by lexer
25  * @param pos Position of value in the mod file
26  * @return Symbol for double value
27  */
28 SymbolType double_symbol(const std::string& value, PositionType& pos) {
29  ModToken token(value, Token::REAL, pos);
30  ast::Double float_value(value);
31  float_value.set_token(token);
32  return Parser::make_REAL(float_value, pos);
33 }
34 
35 
36 /**
37  * Create a symbol for ast::Integer AST
38  *
39  * ast::Integer class also represent macro definition and
40  * hence could have associated text.
41  *
42  * @param value Integer value parsed by lexer
43  * @param pos Position of value in the mod file
44  * @param text associated macro for the value
45  * @return Symbol for integer value
46  */
47 SymbolType integer_symbol(int value, PositionType& pos, const char* text) {
48  ast::Name* macro = nullptr;
49  ModToken token(std::to_string(value), Token::INTEGER, pos);
50 
51  if (text != nullptr) {
52  macro = new ast::Name(new ast::String(text));
53  macro->set_token(token);
54  }
55 
56  ast::Integer int_value(value, macro);
57  int_value.set_token(token);
58  return Parser::make_INTEGER(int_value, pos);
59 }
60 
61 
62 /**
63  * Create symbol for ast::Name AST class
64  *
65  * @param text Text value parsed by lexer
66  * @param pos Position of value in the mod file
67  * @param type Token type returned by lexer (see parser::NmodlParser::token::yytokentype)
68  * @return Symbol for name value
69  *
70  * \todo
71  * In addition to keywords and methods, there are also external
72  * definitions for math and neuron specific functions/variables.
73  * In the token we should mark those as external.
74  */
75 SymbolType name_symbol(const std::string& text, PositionType& pos, TokenType type) {
76  ModToken token(text, type, pos);
77  ast::Name value(new ast::String(text));
78  value.set_token(token);
79  return Parser::make_NAME(value, pos);
80 }
81 
82 
83 /**
84  * Create symbol for ast::Prime AST class
85  *
86  * ast::Prime has name as well as order. Text returned by lexer has single
87  * quote (`'`) as an order. We count the order and remove quote from the text.
88  *
89  * @param text Prime variable name parsed by lexer
90  * @param pos Position of text in the mod file
91  * @return Symbol for prime variable
92  */
93 SymbolType prime_symbol(std::string text, PositionType& pos) {
94  ModToken token(text, Token::PRIME, pos);
95  auto order = std::count(text.begin(), text.end(), '\'');
96  text = stringutils::remove_character(text, '\'');
97 
98  auto prime_name = new ast::String(text);
99  assert(order <= std::numeric_limits<int>::max());
100  auto prime_order = new ast::Integer(static_cast<int>(order), nullptr);
101  ast::PrimeName value(prime_name, prime_order);
102  value.set_token(token);
103  return Parser::make_PRIME(value, pos);
104 }
105 
106 
107 /**
108  * Create symbol for ast::String AST class
109  * @param text Text value parsed by lexer
110  * @param pos Position of value in the mod file
111  * @return Symbol for string value
112  */
113 SymbolType string_symbol(const std::string& text, PositionType& pos) {
114  ModToken token(text, Token::STRING, pos);
115  ast::String value(text);
116  value.set_token(token);
117  return Parser::make_STRING(value, pos);
118 }
119 
120 
121 /**
122  * Create symbol for AST class
123  *
124  * These tokens doesn't have specific value to pass to the parser. They are more
125  * part of grammar. Depending on the type of toke, we create appropriate
126  * symbol. From lexer we pass token type (which is optional). This is required
127  * for reaction parsing where we have "lexical context". Hence, if token type is
128  * passed then we don't check/search for the token type.
129  *
130  * @param key Text parsed by lexer
131  * @param pos Position of value in the mod file
132  * @param type Token type returned by lexer (see parser::NmodlParser::token::yytokentype)
133  * @return Symbol for given token
134  */
135 SymbolType token_symbol(const std::string& key, PositionType& pos, TokenType type) {
136  /// if token type is not passed, check if it is keyword or method
137  if (type == Token::UNKNOWN) {
138  if (is_keyword(key) || is_method(key)) {
139  type = token_type(key);
140  }
141  }
142 
143  ModToken token(key, type, pos);
144 
145  switch (static_cast<int>(type)) {
146  case Token::AFTER:
147  return Parser::make_AFTER(token, pos);
148  case Token::BBCOREPOINTER:
149  return Parser::make_BBCOREPOINTER(token, pos);
150  case Token::BEFORE:
151  return Parser::make_BEFORE(token, pos);
152  case Token::BREAKPOINT:
153  return Parser::make_BREAKPOINT(token, pos);
154  case Token::BY:
155  return Parser::make_BY(token, pos);
156  case Token::COMPARTMENT:
157  return Parser::make_COMPARTMENT(token, pos);
158  case Token::CONDUCTANCE:
159  return Parser::make_CONDUCTANCE(token, pos);
160  case Token::CONSERVE:
161  return Parser::make_CONSERVE(token, pos);
162  case Token::CONSTANT:
163  return Parser::make_CONSTANT(token, pos);
164  case Token::CONSTRUCTOR:
165  return Parser::make_CONSTRUCTOR(token, pos);
166  case Token::DEFINE1:
167  return Parser::make_DEFINE1(token, pos);
168  case Token::DEPEND:
169  return Parser::make_DEPEND(token, pos);
170  case Token::ASSIGNED:
171  return Parser::make_ASSIGNED(token, pos);
172  case Token::DERIVATIVE:
173  return Parser::make_DERIVATIVE(token, pos);
174  case Token::DESTRUCTOR:
175  return Parser::make_DESTRUCTOR(token, pos);
176  case Token::DISCRETE:
177  return Parser::make_DISCRETE(token, pos);
178  case Token::ELECTRODE_CURRENT:
179  return Parser::make_ELECTRODE_CURRENT(token, pos);
180  case Token::ELSE:
181  return Parser::make_ELSE(token, pos);
182  case Token::EQUATION:
183  return Parser::make_EQUATION(token, pos);
184  case Token::EXTERNAL:
185  return Parser::make_EXTERNAL(token, pos);
186  case Token::FOR_NETCONS:
187  return Parser::make_FOR_NETCONS(token, pos);
188  case Token::FROM:
189  return Parser::make_FROM(token, pos);
190  case Token::FUNCTION1:
191  return Parser::make_FUNCTION1(token, pos);
192  case Token::FUNCTION_TABLE:
193  return Parser::make_FUNCTION_TABLE(token, pos);
194  case Token::GLOBAL:
195  return Parser::make_GLOBAL(token, pos);
196  case Token::IF:
197  return Parser::make_IF(token, pos);
198  case Token::INCLUDE1:
199  return Parser::make_INCLUDE1(token, pos);
200  case Token::INDEPENDENT:
201  return Parser::make_INDEPENDENT(token, pos);
202  case Token::INITIAL1:
203  return Parser::make_INITIAL1(token, pos);
204  case Token::KINETIC:
205  return Parser::make_KINETIC(token, pos);
206  case Token::LAG:
207  return Parser::make_LAG(token, pos);
208  case Token::LINEAR:
209  return Parser::make_LINEAR(token, pos);
210  case Token::LOCAL:
211  return Parser::make_LOCAL(token, pos);
212  case Token::LONGDIFUS:
213  return Parser::make_LONGDIFUS(token, pos);
214  case Token::MODEL:
215  return Parser::make_MODEL(token, pos);
216  case Token::NETRECEIVE:
217  return Parser::make_NETRECEIVE(token, pos);
218  case Token::NEURON:
219  return Parser::make_NEURON(token, pos);
220  case Token::NONLINEAR:
221  return Parser::make_NONLINEAR(token, pos);
222  case Token::NONSPECIFIC:
223  return Parser::make_NONSPECIFIC(token, pos);
224  case Token::NRNMUTEXLOCK:
225  return Parser::make_NRNMUTEXLOCK(token, pos);
226  case Token::NRNMUTEXUNLOCK:
227  return Parser::make_NRNMUTEXUNLOCK(token, pos);
228  case Token::PARAMETER:
229  return Parser::make_PARAMETER(token, pos);
230  case Token::POINTER:
231  return Parser::make_POINTER(token, pos);
232  case Token::PROCEDURE:
233  return Parser::make_PROCEDURE(token, pos);
234  case Token::PROTECT:
235  return Parser::make_PROTECT(token, pos);
236  case Token::RANDOM:
237  return Parser::make_RANDOM(token, pos);
238  case Token::RANGE:
239  return Parser::make_RANGE(token, pos);
240  case Token::READ:
241  return Parser::make_READ(token, pos);
242  case Token::SOLVE:
243  return Parser::make_SOLVE(token, pos);
244  case Token::SOLVEFOR:
245  return Parser::make_SOLVEFOR(token, pos);
246  case Token::START1:
247  return Parser::make_START1(token, pos);
248  case Token::STATE:
249  return Parser::make_STATE(token, pos);
250  case Token::STEADYSTATE:
251  return Parser::make_STEADYSTATE(token, pos);
252  case Token::STEP:
253  return Parser::make_STEP(token, pos);
254  case Token::SWEEP:
255  return Parser::make_SWEEP(token, pos);
256  case Token::TABLE:
257  return Parser::make_TABLE(token, pos);
258  case Token::THREADSAFE:
259  return Parser::make_THREADSAFE(token, pos);
260  case Token::TO:
261  return Parser::make_TO(token, pos);
262  case Token::UNITS:
263  return Parser::make_UNITS(token, pos);
264  case Token::UNITSOFF:
265  return Parser::make_UNITSOFF(token, pos);
266  case Token::UNITSON:
267  return Parser::make_UNITSON(token, pos);
268  case Token::USEION:
269  return Parser::make_USEION(token, pos);
270  case Token::USING:
271  return Parser::make_USING(token, pos);
272  case Token::VS:
273  return Parser::make_VS(token, pos);
274  case Token::WATCH:
275  return Parser::make_WATCH(token, pos);
276  case Token::WHILE:
277  return Parser::make_WHILE(token, pos);
278  case Token::WITH:
279  return Parser::make_WITH(token, pos);
280  case Token::WRITE:
281  return Parser::make_WRITE(token, pos);
282  case Token::REACT1:
283  return Parser::make_REACT1(token, pos);
284  case Token::NONLIN1:
285  return Parser::make_NONLIN1(token, pos);
286  case Token::LIN1:
287  return Parser::make_LIN1(token, pos);
288  case Token::REACTION:
289  return Parser::make_REACTION(token, pos);
290  case Token::GT:
291  return Parser::make_GT(token, pos);
292  case Token::GE:
293  return Parser::make_GE(token, pos);
294  case Token::LT:
295  return Parser::make_LT(token, pos);
296  case Token::LE:
297  return Parser::make_LE(token, pos);
298  case Token::EQ:
299  return Parser::make_EQ(token, pos);
300  case Token::NE:
301  return Parser::make_NE(token, pos);
302  case Token::NOT:
303  return Parser::make_NOT(token, pos);
304  case Token::AND:
305  return Parser::make_AND(token, pos);
306  case Token::OR:
307  return Parser::make_OR(token, pos);
308  case Token::OPEN_BRACE:
309  return Parser::make_OPEN_BRACE(token, pos);
310  case Token::CLOSE_BRACE:
311  return Parser::make_CLOSE_BRACE(token, pos);
312  case Token::OPEN_PARENTHESIS:
313  return Parser::make_OPEN_PARENTHESIS(token, pos);
314  case Token::CLOSE_PARENTHESIS:
315  return Parser::make_CLOSE_PARENTHESIS(token, pos);
316  case Token::OPEN_BRACKET:
317  return Parser::make_OPEN_BRACKET(token, pos);
318  case Token::CLOSE_BRACKET:
319  return Parser::make_CLOSE_BRACKET(token, pos);
320  case Token::AT:
321  return Parser::make_AT(token, pos);
322  case Token::ADD:
323  return Parser::make_ADD(token, pos);
324  case Token::MINUS:
325  return Parser::make_MINUS(token, pos);
326  case Token::MULTIPLY:
327  return Parser::make_MULTIPLY(token, pos);
328  case Token::DIVIDE:
329  return Parser::make_DIVIDE(token, pos);
330  case Token::EQUAL:
331  return Parser::make_EQUAL(token, pos);
332  case Token::CARET:
333  return Parser::make_CARET(token, pos);
334  case Token::COLON:
335  return Parser::make_COLON(token, pos);
336  case Token::COMMA:
337  return Parser::make_COMMA(token, pos);
338  case Token::PERIOD:
339  return Parser::make_PERIOD(token, pos);
340  case Token::REPRESENTS:
341  return Parser::make_REPRESENTS(token, pos);
342  /**
343  * we hit default case for missing token type. This is more likely
344  * a bug in the implementation where we forgot to handle token type.
345  */
346  default:
347  auto msg = "Token type not found while creating a symbol!";
348  throw std::runtime_error(msg);
349  }
350 }
351 
352 } // namespace nmodl
nmodl::TokenType
parser::NmodlParser::token_type TokenType
Definition: nmodl_utils.hpp:28
nmodl::string_symbol
SymbolType string_symbol(const std::string &text, PositionType &pos)
Create symbol for ast::String AST class.
Definition: nmodl_utils.cpp:113
nmodl::ast::Integer::set_token
void set_token(const ModToken &tok)
Set token for the current ast node.
Definition: integer.hpp:176
nmodl::ast::Double
Represents a double variable.
Definition: double.hpp:53
nmodl::double_symbol
SymbolType double_symbol(const std::string &value, PositionType &pos)
Create a symbol for ast::Double AST class.
Definition: nmodl_utils.cpp:28
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::ast::Name::set_token
void set_token(const ModToken &tok)
Set token for the current ast node.
Definition: name.hpp:182
token_mapping.hpp
Map different tokens from lexer to token types.
nmodl::ast::Integer
Represents an integer variable.
Definition: integer.hpp:49
string_utils.hpp
Implement string manipulation functions.
nmodl::SymbolType
parser::NmodlParser::symbol_type SymbolType
Definition: nmodl_utils.hpp:26
nmodl::integer_symbol
SymbolType integer_symbol(int value, PositionType &pos, const char *text)
Create a symbol for ast::Integer AST.
Definition: nmodl_utils.cpp:47
nmodl::PositionType
parser::location PositionType
Definition: nmodl_utils.hpp: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::Parser
parser::NmodlParser Parser
Definition: nmodl_utils.cpp:19
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::symtab::syminfo::to_string
std::string to_string(const T &obj)
Definition: symbol_properties.hpp:279
nmodl_utils.hpp
Utility functions for NMODL lexer.
nmodl::token_symbol
SymbolType token_symbol(const std::string &key, PositionType &pos, TokenType type)
Create symbol for AST class.
Definition: nmodl_utils.cpp:135
nmodl::ast::PrimeName
Represents a prime variable (for ODE)
Definition: prime_name.hpp:48
nmodl::ast::String::set_token
void set_token(const ModToken &tok)
Set token for the current ast node.
Definition: string.hpp:167
ast.hpp
Auto generated AST classes declaration.
nmodl::ast::PrimeName::set_token
void set_token(const ModToken &tok)
Set token for the current ast node.
Definition: prime_name.hpp:187
nmodl::stringutils::remove_character
static std::string remove_character(std::string text, const char c)
Remove all occurrences of a given character in a text.
Definition: string_utils.hpp:73
nmodl::prime_symbol
SymbolType prime_symbol(std::string text, PositionType &pos)
Create symbol for ast::Prime AST class.
Definition: nmodl_utils.cpp:93
modtoken.hpp
nmodl::name_symbol
SymbolType name_symbol(const std::string &text, PositionType &pos, TokenType type)
Create symbol for ast::Name AST class.
Definition: nmodl_utils.cpp:75
nmodl::ast::Name
Represents a name.
Definition: name.hpp:44
nmodl::token_type
TokenType token_type(const std::string &name)
Return token type for given token name.
Definition: token_mapping.cpp:284
nmodl::ast::Double::set_token
void set_token(const ModToken &tok)
Set token for the current ast node.
Definition: double.hpp:168
nmodl::ModToken
Represent token returned by scanner.
Definition: modtoken.hpp:50
nmodl::ast::String
Represents a string.
Definition: string.hpp:52