User Guide
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  */
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 
237 void SymtabVisitor::setup_symbol_table_for_scoped_block(ast::Node* node, const std::string& name) {
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
nmodl::ast::Program::get_model_symbol_table
symtab::ModelSymbolTable * get_model_symbol_table()
Return global symbol table for the mod file.
Definition: program.hpp:159
nmodl::ast::TableStatement::get_depend_vars
const NameVector & get_depend_vars() const noexcept
Getter for member variable TableStatement::depend_vars.
Definition: table_statement.hpp:175
nmodl::ast::ParamAssign
TODO.
Definition: param_assign.hpp:38
nmodl::ast::ConstantVar
Represents a variable in the ast::ConstantBlock.
Definition: constant_var.hpp:38
nmodl::ast::SolveBlock
TODO.
Definition: solve_block.hpp:38
nmodl::ast::Node
Base class for all AST node.
Definition: node.hpp:40
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::ast::Ast
Base class for all Abstract Syntax Tree node types.
Definition: ast.hpp:69
nmodl::codegen::Ion::get_possible_variables
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,...
Definition: codegen_info.hpp:129
nmodl::ast::AssignedDefinition
Represents a statement in ASSIGNED or STATE block.
Definition: assigned_definition.hpp:38
nmodl::visitor::SymtabVisitor::add_model_symbol_with_property
void add_model_symbol_with_property(ast::Node *node, symtab::syminfo::NmodlType property)
Definition: symtab_visitor_helper.hpp:150
nmodl::ast::Ast::is_local_var
virtual bool is_local_var() const noexcept
Check if the ast node is an instance of ast::LocalVar.
Definition: ast.cpp:172
nmodl::symtab::ModelSymbolTable::insert
std::shared_ptr< Symbol > insert(const std::shared_ptr< Symbol > &symbol)
insert new symbol into current table
Definition: symbol_table.cpp:286
nmodl::ast::TableStatement::get_with
std::shared_ptr< Integer > get_with() const noexcept
Getter for member variable TableStatement::with.
Definition: table_statement.hpp:202
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::ast::Define
Represents a DEFINE statement in NMODL.
Definition: define.hpp:38
nmodl::visitor::create_symbol_for_node
static std::shared_ptr< Symbol > create_symbol_for_node(ast::Node *node, NmodlType property, bool under_state_block)
Definition: symtab_visitor_helper.hpp:25
nmodl::ast::Program::get_node_type_name
std::string get_node_type_name() const noexcept override
Return type (ast::AstNodeType) of ast node as std::string.
Definition: program.hpp:111
token_mapping.hpp
Map different tokens from lexer to token types.
nmodl::ast::TableStatement
Represents TABLE statement in NMODL.
Definition: table_statement.hpp:39
nmodl::symtab::ModelSymbolTable::leave_scope
void leave_scope()
leaving current nmodl block
Definition: symbol_table.cpp:420
nmodl::visitor::SymtabVisitor::update
bool update
Definition: symtab_visitor.hpp:43
nmodl::ast::Integer
Represents an integer variable.
Definition: integer.hpp:49
nmodl::ast::Ast::is_constant_var
virtual bool is_constant_var() const noexcept
Check if the ast node is an instance of ast::ConstantVar.
Definition: ast.cpp:178
nmodl::ast::Ast::is_assigned_definition
virtual bool is_assigned_definition() const noexcept
Check if the ast node is an instance of ast::AssignedDefinition.
Definition: ast.cpp:222
codegen_naming.hpp
nmodl::visitor::SymtabVisitor::visit_table_statement
void visit_table_statement(ast::TableStatement &node) override
Visit table statement and update symbol in symbol table.
Definition: symtab_visitor_helper.hpp:247
nmodl::visitor::SymtabVisitor::setup_symbol_table_for_program_block
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...
Definition: symtab_visitor_helper.hpp:225
nmodl::ast::NameVector
std::vector< std::shared_ptr< Name > > NameVector
Definition: ast_decl.hpp:308
nmodl::visitor::SymtabVisitor::setup_symbol_table
void setup_symbol_table(ast::Ast *node, const std::string &name, bool is_global)
Definition: symtab_visitor_helper.hpp:185
nmodl::ast::IndexedName
Represents specific element of an array variable.
Definition: indexed_name.hpp:48
nmodl::ast::Ast::get_symbol_table
virtual symtab::SymbolTable * get_symbol_table() const
Return associated symbol table for the AST node.
Definition: ast.cpp:38
nmodl::visitor::SymtabVisitor::setup_symbol
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...
Definition: symtab_visitor_helper.hpp:53
nmodl::ast::Node::visit_children
virtual void visit_children(visitor::Visitor &v) override
visit children i.e.
Definition: ast.cpp:322
nmodl::visitor::SymtabVisitor::modsymtab
symtab::ModelSymbolTable * modsymtab
Definition: symtab_visitor.hpp:39
nmodl::visitor::SymtabVisitor::setup_symbol_table_for_scoped_block
void setup_symbol_table_for_scoped_block(ast::Node *node, const std::string &name)
Definition: symtab_visitor_helper.hpp:237
nmodl::ast::Useion
Represents USEION statement in NMODL.
Definition: useion.hpp:40
nmodl::symtab::ModelSymbolTable::lookup
std::shared_ptr< Symbol > lookup(const std::string &name)
lookup for symbol into current as well as all parent tables
Definition: symbol_table.cpp:173
nmodl::ast::PrimeName
Represents a prime variable (for ODE)
Definition: prime_name.hpp:48
nmodl::ast::Ast::is_state_block
virtual bool is_state_block() const noexcept
Check if the ast node is an instance of ast::StateBlock.
Definition: ast.cpp:122
nmodl::ast::Ast::get_token
virtual const ModToken * get_token() const
Return associated token for the AST node.
Definition: ast.cpp:36
codegen_info.hpp
Various types to store code generation specific information.
nmodl::ast::LocalVar
TODO.
Definition: local_var.hpp:38
nmodl::ast::Useion::get_name
std::shared_ptr< Name > get_name() const noexcept
Getter for member variable Useion::name.
Definition: useion.hpp:179
nmodl::symtab::ModelSymbolTable::enter_scope
SymbolTable * enter_scope(const std::string &name, ast::Ast *node, bool global, SymbolTable *node_symtab)
entering into new nmodl block
Definition: symbol_table.cpp:377
nmodl::ast::Ast::set_symbol_table
virtual void set_symbol_table(symtab::SymbolTable *symtab)
Set symbol table for the AST node.
Definition: ast.cpp:42
nmodl::ast::Ast::is_define
virtual bool is_define() const noexcept
Check if the ast node is an instance of ast::Define.
Definition: ast.cpp:216
nmodl::symtab::ModelSymbolTable::set_mode
void set_mode(bool update_mode)
re-initialize members to throw away old symbol tables this is required as symtab visitor pass runs mu...
Definition: symbol_table.cpp:435
nmodl::symtab::syminfo::NmodlType
NmodlType
NMODL variable properties.
Definition: symbol_properties.hpp:116
nmodl::ast::TableStatement::get_table_vars
const NameVector & get_table_vars() const noexcept
Getter for member variable TableStatement::table_vars.
Definition: table_statement.hpp:166
nmodl::ast::Ast::is_param_assign
virtual bool is_param_assign() const noexcept
Check if the ast node is an instance of ast::ParamAssign.
Definition: ast.cpp:220
nmodl::symtab::ModelSymbolTable
Hold top level (i.e.
Definition: symbol_table.hpp:239
nmodl::ast::Ast::is_prime_name
virtual bool is_prime_name() const noexcept
Check if the ast node is an instance of ast::PrimeName.
Definition: ast.cpp:86
nmodl::ast::Ast::is_program
virtual bool is_program() const noexcept
Check if the ast node is an instance of ast::Program.
Definition: ast.cpp:290
nmodl::visitor::add_external_symbols
static void add_external_symbols(symtab::ModelSymbolTable *symtab)
Definition: symtab_visitor_helper.hpp:168
nmodl::ast::Ast::is_solve_block
virtual bool is_solve_block() const noexcept
Check if the ast node is an instance of ast::SolveBlock.
Definition: ast.cpp:148
nmodl::visitor::SymtabVisitor::block_to_solve
std::set< std::string > block_to_solve
Definition: symtab_visitor.hpp:42
nmodl::details::methods
const static std::map< std::string, MethodInfo > methods
Integration methods available in the NMODL.
Definition: token_mapping.cpp:146
nmodl::ast::Program
Represents top level AST node for whole NMODL input.
Definition: program.hpp:39
symtab_visitor.hpp
THIS FILE IS GENERATED AT BUILD TIME AND SHALL NOT BE EDITED.
nmodl::visitor::SymtabVisitor::setup_symbol_table_for_global_block
void setup_symbol_table_for_global_block(ast::Node *node)
Definition: symtab_visitor_helper.hpp:232
nmodl::ast::Node::get_node_type_name
virtual std::string get_node_type_name() const noexcept override
Return type (ast::AstNodeType) of ast node as std::string.
Definition: node.hpp:100
nmodl::ast::Ast::visit_children
virtual void visit_children(visitor::Visitor &v)=0
Visit children i.e.
nmodl::ast::ConstantVar::get_value
std::shared_ptr< Number > get_value() const noexcept
Getter for member variable ConstantVar::value.
Definition: constant_var.hpp:168
nmodl::ModToken
Represent token returned by scanner.
Definition: modtoken.hpp:50
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::ast::Ast::get_node_name
virtual std::string get_node_name() const
Return name of of the node.
Definition: ast.cpp:28
nmodl::visitor::SymtabVisitor::under_state_block
bool under_state_block
Definition: symtab_visitor.hpp:44
nmodl::ast::Ast::is_useion
virtual bool is_useion() const noexcept
Check if the ast node is an instance of ast::Useion.
Definition: ast.cpp:262
nmodl::ast::ParamAssign::get_value
std::shared_ptr< Number > get_value() const noexcept
Getter for member variable ParamAssign::value.
Definition: param_assign.hpp:170
nmodl::codegen::naming::ION_VARNAME_PREFIX
static constexpr char ION_VARNAME_PREFIX[]
prefix for ion variable
Definition: codegen_naming.hpp:171