NEURON
symtab_visitor_helper.hpp
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 #pragma once
9 
10 #include <utility>
11 
12 #include "codegen/codegen_info.hpp"
14 #include "lexer/token_mapping.hpp"
16 
17 
18 namespace nmodl {
19 namespace visitor {
20 
21 using symtab::Symbol;
23 
24 // create symbol for given node
25 static std::shared_ptr<Symbol> create_symbol_for_node(ast::Node* node,
26  NmodlType property,
27  bool under_state_block) {
28  ModToken token;
29  auto token_ptr = node->get_token();
30  if (token_ptr != nullptr) {
31  token = *token_ptr;
32  }
33 
34  /// add new symbol
35  auto symbol = std::make_shared<Symbol>(node->get_node_name(), node, token);
36  symbol->add_property(property);
37 
38  // non specific variable is range
39  if (property == NmodlType::nonspecific_cur_var) {
40  symbol->add_property(NmodlType::range_var);
41  }
42 
43  /// extra property for state variables
44  if (under_state_block) {
45  symbol->add_property(NmodlType::state_var);
46  }
47  return symbol;
48 }
49 
50 
51 /// helper function to setup/insert symbol into symbol table
52 /// for the ast nodes which are of variable types
54  std::shared_ptr<Symbol> symbol;
55  auto name = node->get_node_name();
56 
57  /// if prime variable is already exist in symbol table
58  /// then just update the order
59  if (node->is_prime_name()) {
60  auto prime = dynamic_cast<ast::PrimeName*>(node);
61  symbol = modsymtab->lookup(name);
62  if (symbol) {
63  symbol->set_order(prime->get_order()->eval());
64  symbol->add_property(property);
65  return;
66  }
67  }
68 
69  /// range and non_spec_cur can appear in any order in neuron block.
70  /// for both properties, we have to check if symbol is already exist.
71  /// if so we have to return to avoid duplicate definition error.
72  if (property == NmodlType::range_var || property == NmodlType::nonspecific_cur_var) {
73  auto s = modsymtab->lookup(name);
74  if (s && s->has_any_property(NmodlType::nonspecific_cur_var | NmodlType::range_var)) {
75  s->add_property(property);
76  return;
77  }
78  }
79 
80  symbol = create_symbol_for_node(node, property, under_state_block);
81 
82  /// insert might return different symbol if already exist in the same scope
83  symbol = modsymtab->insert(symbol);
84 
85  if (node->is_param_assign()) {
86  auto parameter = dynamic_cast<ast::ParamAssign*>(node);
87  const auto& value = parameter->get_value();
88  const auto& name = parameter->get_name();
89  if (value) {
90  symbol->set_value(value->to_double());
91  }
92  if (name->is_indexed_name()) {
93  auto index_name = dynamic_cast<ast::IndexedName*>(name.get());
94  auto length = dynamic_cast<ast::Integer*>(index_name->get_length().get());
95  symbol->set_as_array(length->eval());
96  }
97  }
98 
99  if (node->is_assigned_definition()) {
100  auto variable = dynamic_cast<ast::AssignedDefinition*>(node);
101  auto length = variable->get_length();
102  if (length) {
103  symbol->set_as_array(length->eval());
104  }
105  }
106 
107  if (node->is_constant_var()) {
108  auto constant = dynamic_cast<ast::ConstantVar*>(node);
109  auto value = constant->get_value();
110  if (value) {
111  symbol->set_value(value->to_double());
112  }
113  }
114 
115  if (node->is_local_var()) {
116  auto variable = dynamic_cast<ast::LocalVar*>(node);
117  auto name = variable->get_name();
118  if (name->is_indexed_name()) {
119  auto index_name = dynamic_cast<ast::IndexedName*>(name.get());
120  auto length = dynamic_cast<ast::Integer*>(index_name->get_length().get());
121  symbol->set_as_array(length->eval());
122  }
123  }
124 
125  if (node->is_define()) {
126  auto define = dynamic_cast<ast::Define*>(node);
127  symbol->set_value(define->get_value()->to_double());
128  }
129 
130  // for a given USEION statement, add all possible ion variables
131  // these variables can be used within VERBATIM block and hence
132  // needs to be populated in the symbol table
133  if (node->is_useion()) {
134  auto use_ion = dynamic_cast<ast::Useion*>(node);
135  auto name = use_ion->get_name()->get_node_name();
136  for (const auto& variable: codegen::Ion::get_possible_variables(name)) {
137  std::string ion_variable(codegen::naming::ION_VARNAME_PREFIX + variable);
138  auto symbol = std::make_shared<symtab::Symbol>(ion_variable);
139  symbol->add_property(NmodlType::codegen_var);
140  modsymtab->insert(symbol);
141  }
142  }
143 
144  /// visit children, most likely variables are already
145  /// leaf nodes, not necessary to visit
146  node->visit_children(*this);
147 }
148 
149 
151  auto name = node->get_node_name();
152  std::shared_ptr<Symbol> symbol;
153  if (node->get_token()) { // token can be nullptr
154  symbol = std::make_shared<Symbol>(name, node, *node->get_token());
155  } else {
156  symbol = std::make_shared<Symbol>(name, node, ModToken{});
157  }
158  symbol->add_property(property);
159 
160  if (block_to_solve.find(name) != block_to_solve.cend()) {
161  symbol->add_property(NmodlType::to_solve);
162  }
163 
164  modsymtab->insert(symbol);
165 }
166 
167 
169  ModToken tok(true);
170  auto variables = nmodl::get_external_variables();
171  for (auto variable: variables) {
172  auto symbol = std::make_shared<Symbol>(variable, tok);
173  symbol->add_property(NmodlType::extern_neuron_variable);
174  symtab->insert(symbol);
175  }
177  for (auto method: methods) {
178  auto symbol = std::make_shared<Symbol>(method, tok);
179  symbol->add_property(NmodlType::extern_method);
180  symtab->insert(symbol);
181  }
182 }
183 
184 
185 void SymtabVisitor::setup_symbol_table(ast::Ast* node, const std::string& name, bool is_global) {
186  /// entering into new nmodl block
187  auto symtab = modsymtab->enter_scope(name, node, is_global, node->get_symbol_table());
188 
189  if (node->is_state_block()) {
190  under_state_block = true;
191  }
192 
193  /// there is only one solve statement allowed in mod file
194  if (node->is_solve_block()) {
195  auto solve_block = dynamic_cast<ast::SolveBlock*>(node);
196  block_to_solve.insert(solve_block->get_block_name()->get_node_name());
197  }
198 
199  /// not required at the moment but every node
200  /// has pointer to associated symbol table
201  node->set_symbol_table(symtab);
202 
203  /// when visiting highest level node i.e. Program, we insert
204  /// all global variables to the global symbol table
205  if (node->is_program()) {
207  }
208 
209  /// look for all children blocks recursively
210  node->visit_children(*this);
211 
212  /// existing nmodl block
214 
215  if (node->is_state_block()) {
216  under_state_block = false;
217  }
218 }
219 
220 
221 /**
222  * Symtab visitor could be called multiple times, after optimization passes,
223  * in which case we have to throw awayold symbol tables and setup new ones.
224  */
226  modsymtab = node->get_model_symbol_table();
228  setup_symbol_table(node, node->get_node_type_name(), true);
229 }
230 
231 
233  setup_symbol_table(node, node->get_node_type_name(), true);
234 }
235 
236 
238  setup_symbol_table(node, name, false);
239 }
240 
241 
242 /**
243  * Visit table statement and update symbol in symbol table
244  *
245  * @todo we assume table statement follows variable declaration
246  */
248  auto update_symbol =
249  [this](const ast::NameVector& variables, NmodlType property, int num_values) {
250  for (auto& var: variables) {
251  auto name = var->get_node_name();
252  auto symbol = modsymtab->lookup(name);
253  if (symbol) {
254  symbol->add_property(property);
255  symbol->set_num_values(num_values);
256  }
257  }
258  };
259  int num_values = node.get_with()->eval() + 1;
260  update_symbol(node.get_table_vars(), NmodlType::table_statement_var, num_values);
261  update_symbol(node.get_depend_vars(), NmodlType::table_assigned_var, num_values);
262 }
263 
264 } // namespace visitor
265 } // namespace nmodl
Represent token returned by scanner.
Definition: modtoken.hpp:50
Represents a statement in ASSIGNED or STATE block.
Represents a variable in the ast::ConstantBlock.
Represents a DEFINE statement in NMODL.
Definition: define.hpp:38
void set_value(std::shared_ptr< Integer > &&value)
Setter for member variable Define::value (rvalue reference)
Definition: ast.cpp:8249
Represents specific element of an array variable.
Represents an integer variable.
Definition: integer.hpp:49
Base class for all AST node.
Definition: node.hpp:40
Represents a prime variable (for ODE)
Definition: prime_name.hpp:48
Represents top level AST node for whole NMODL input.
Definition: program.hpp:39
Represents TABLE statement in NMODL.
Represents USEION statement in NMODL.
Definition: useion.hpp:40
void leave_scope()
leaving current nmodl block
SymbolTable * enter_scope(const std::string &name, ast::Ast *node, bool global, SymbolTable *node_symtab)
entering into new nmodl block
std::shared_ptr< Symbol > insert(const std::shared_ptr< Symbol > &symbol)
insert new symbol into current table
void set_mode(bool update_mode)
re-initialize members to throw away old symbol tables this is required as symtab visitor pass runs mu...
std::shared_ptr< Symbol > lookup(const std::string &name)
lookup for symbol into current as well as all parent tables
void setup_symbol_table_for_program_block(ast::Program *node)
Symtab visitor could be called multiple times, after optimization passes, in which case we have to th...
void add_model_symbol_with_property(ast::Node *node, symtab::syminfo::NmodlType property)
symtab::ModelSymbolTable * modsymtab
void setup_symbol_table_for_scoped_block(ast::Node *node, const std::string &name)
void setup_symbol(ast::Node *node, symtab::syminfo::NmodlType property)
helper function to setup/insert symbol into symbol table for the ast nodes which are of variable type...
void setup_symbol_table_for_global_block(ast::Node *node)
std::set< std::string > block_to_solve
void visit_table_statement(ast::TableStatement &node) override
Visit table statement and update symbol in symbol table.
void setup_symbol_table(ast::Ast *node, const std::string &name, bool is_global)
Various types to store code generation specific information.
virtual const ModToken * get_token() const
Return associated token for the AST node.
Definition: ast.cpp:36
virtual std::string get_node_name() const
Return name of of the node.
Definition: ast.cpp:28
std::vector< std::shared_ptr< Name > > NameVector
Definition: ast_decl.hpp:312
double var(InputIterator begin, InputIterator end)
Definition: ivocvect.h:108
static struct @27 methods[]
const char * name
Definition: init.cpp:16
char Symbol
Definition: nrnconf.h:25
static constexpr char ION_VARNAME_PREFIX[]
prefix for ion variable
NmodlType
NMODL variable properties.
static void add_external_symbols(symtab::ModelSymbolTable *symtab)
static std::shared_ptr< Symbol > create_symbol_for_node(ast::Node *node, NmodlType property, bool under_state_block)
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.
std::vector< std::string > get_external_functions()
Return functions that can be used in the NMODL.
static Node * node(Object *)
Definition: netcvode.cpp:291
s
Definition: multisend.cpp:521
static uint32_t value
Definition: scoprand.cpp:25
Base class for all Abstract Syntax Tree node types.
Definition: ast.hpp:52
static std::vector< std::string > get_possible_variables(const std::string &ion_name)
for a given ion, return different variable names/properties like internal/external concentration,...
THIS FILE IS GENERATED AT BUILD TIME AND SHALL NOT BE EDITED.
Map different tokens from lexer to token types.