9 #include <catch2/catch_test_macros.hpp>
21 using namespace nmodl;
22 using namespace visitor;
24 using namespace test_utils;
32 std::tuple<std::shared_ptr<ast::Program>, std::shared_ptr<units::UnitTable>>
run_units_visitor(
33 const std::string&
text) {
36 const auto& ast =
driver.get_ast();
47 std::shared_ptr<units::UnitTable> unit_table = units_driver.
table;
52 return {ast, unit_table};
78 for (
const auto& unit_def: unit_defs) {
79 auto unit_name = unit_def->get_node_name();
80 unit_name.erase(remove_if(unit_name.begin(), unit_name.end(), isspace), unit_name.end());
82 ss << fmt::format(
"{} {:g}:", unit_name,
unit->get_factor());
87 for (
const auto& dimension:
unit->get_dimensions()) {
118 std::stringstream ss;
120 for (
const auto& factor_def: factor_defs) {
121 const auto& factor_def_cast = std::dynamic_pointer_cast<const ast::FactorDef>(factor_def);
122 ss << fmt::format(
"{} {}\n",
123 factor_def_cast->get_node_name(),
124 factor_def_cast->get_value()->get_value());
129 SCENARIO(
"Parse UNITS block of mod files using Units Visitor",
"[visitor][units]") {
130 GIVEN(
"UNITS block with different cases of UNITS definitions") {
136 (uS) = (microsiemens)
144 (fAm) = (femto amp meter)
148 (mA/cm2) = (nanoamp/cm2)
149 (molar) = (1 / liter)
151 (mse-1) = (1/millisec)
155 FARADAY1 = (faraday) (coulomb)
156 FARADAY2 = (faraday) (kilocoulombs)
157 FARADAY3 = (faraday) (10000 coulomb)
159 R1 = (k-mole) (joule/degC)
160 R2 = 8.314 (volt-coul/degC)
161 R3 = (mole k) (mV-coulomb/degC)
162 R4 = 8.314 (volt-coul/degK)
163 R5 = 8.314500000000001 (volt coul/kelvin)
164 dummy1 = 123.45 (m 1/sec2)
165 dummy2 = 123.45e3 (millimeters/sec2)
166 dummy3 = 12345e-2 (m/sec2)
167 KTOMV = 0.0853 (mV/degC)
168 B = 0.26 (mM-cm2/mA-ms)
172 oldJ = (R-mole) (1) : compute oldJ based on the value of R which is registered in the UnitTable
173 R = 8 (joule/degC) : define a new value for R that should be visible only in the mod file
174 J = (R-mole) (1) : recalculate J. It's value should be the same as oldJ because R shouldn't change in the UnitTable
175 (myR) = (8 joule/degC) : Define my own R and mole and compute myRnew and myJ based on them
178 myJ = (myR-mymole) (1)
182 static const std::string unit_definitions = R
"(
183 nA 1e-09: sec-1 coul1
184 mA 0.001: sec-1 coul1
185 mV 0.001: m2 kg1 sec-2 coul-1
186 uS 1e-06: m-2 kg-1 sec1 coul2
187 nS 1e-09: m-2 kg-1 sec1 coul2
188 pS 1e-12: m-2 kg-1 sec1 coul2
189 umho 1e-06: m-2 kg-1 sec1 coul2
194 fAm 1e-15: m1 sec-1 coul1
198 mA/cm2 1e-05: m-2 sec-1 coul1
200 S 1: m-2 kg-1 sec1 coul2
205 myR 8: m2 kg1 sec-2 K-1
206 mymole 6e+23: constant
209 static const std::string factor_definitions = R
"(
210 FARADAY1 0x1.78e555060882cp+16
211 FARADAY2 0x1.81f0fae775425p+6
212 FARADAY3 0x1.34c0c8b92a9b7p+3
213 pi 0x1.921fb54442d18p+1
214 R1 0x1.0a1013e8990bep+3
216 R3 0x1.03d3b37125759p+13
227 oldJ 0x1.0912acba81b67p+82
229 J 0x1.0912acba81b67p+82
231 myJ 0x1.fc3842bd1f072p+81
234 THEN("Print the units that were added") {
236 auto expected_result_unit_definitions =
reindent_text(unit_definitions);
237 auto expected_result_factor_definitions =
reindent_text(factor_definitions);
241 auto reindented_result_unit_definitions =
reindent_text(generated_unit_definitions);
242 auto reindented_result_factor_definitions =
reindent_text(generated_factor_definitions);
243 REQUIRE(reindented_result_unit_definitions == expected_result_unit_definitions);
244 REQUIRE(reindented_result_factor_definitions == expected_result_factor_definitions);
247 GIVEN(
"UNITS block with Unit definition which is already defined") {
253 THEN("Throw redefinition exception") {
Visitor for checking parents of ast nodes
Represents top level AST node for whole NMODL input.
Class that binds all pieces together for parsing nmodl file.
Class that binds all pieces together for parsing C units.
Class that stores all the units, prefixes and names of base units used.
const std::string & get_base_unit_name(int id) const noexcept
Get base unit name based on the ID number of the dimension.
const std::shared_ptr< Unit > & get_unit(const std::string &unit_name) const
Get the unit_name of the UnitTable's table.
Visitor for Units blocks of AST.
const parser::UnitDriver & get_unit_driver() const noexcept
Get the parser::UnitDriver to be able to use it outside the visitor::UnitsVisitor scope keeping the s...
void visit_program(ast::Program &node) override
Override visit_program function to parse the nrnunits.lib unit file before starting visiting the AST ...
Visitor for checking parents of ast nodes
int check_ast(const ast::Ast &node)
A small wrapper to have a nicer call in parser.cpp.
Auto generated AST classes declaration.
Auto generated AST classes declaration.
@ UNIT_DEF
type of ast::UnitDef
@ FACTOR_DEF
type of ast::FactorDef
std::shared_ptr< nmodl::units::UnitTable > table
shared pointer to the UnitTable that stores all the unit definitions
bool parse_string(const std::string &input)
parser Units provided as string (used for testing)
std::string reindent_text(const std::string &text, int indent_level)
Reindent nmodl text for text-to-text comparison.
encapsulates code generation backend implementations
std::vector< std::shared_ptr< const ast::Ast > > collect_nodes(const ast::Ast &node, const std::vector< ast::AstNodeType > &types)
traverse node recursively and collect nodes of given types
Version information and units file path.
Auto generated AST classes declaration.
static std::string get_path()
Return path of units database file.
SCENARIO("Parse UNITS block of mod files using Units Visitor", "[visitor][units]")
std::tuple< std::shared_ptr< ast::Program >, std::shared_ptr< units::UnitTable > > run_units_visitor(const std::string &text)
std::string get_unit_definitions(const ast::Program &ast, const units::UnitTable &unit_table)
Returns all the UnitDef s of the ast::Program.
std::string get_factor_definitions(const ast::Program &ast)
Returns all the FactorDef s of the ast::Program.
nmodl::parser::UnitDriver driver
Visitor for Units blocks of AST.