User Guide
tokens.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 <string>
9 
10 #include <catch2/catch_test_macros.hpp>
11 
12 #include "lexer/modtoken.hpp"
13 #include "lexer/nmodl_lexer.hpp"
14 #include "parser/nmodl_driver.hpp"
15 
16 using namespace nmodl;
17 
20 using parser::NmodlParser;
21 using Token = NmodlParser::token;
24 
25 
26 /// retrieve token type from lexer and check if it's of given type
27 bool check_token_type(const std::string& name, TokenType type) {
28  std::istringstream ss(name);
29  std::istream& in = ss;
30 
32  NmodlLexer scanner(driver, &in);
33 
34  SymbolType sym = scanner.next_token();
35  int token_type = sym.type_get();
36 
37  auto get_token_type = [](TokenType token) {
38  return parser::NmodlParser::by_type(token).type_get();
39  };
40 
41  /**
42  * Lexer returns raw pointers for some AST types
43  * and we need to clean-up memory for those.
44  * Todo: add tests later for checking values
45  */
46  // clang-format off
47  if (token_type == get_token_type(Token::NAME) ||
48  token_type == get_token_type(Token::METHOD) ||
49  token_type == get_token_type(Token::SUFFIX) ||
50  token_type == get_token_type(Token::VALENCE) ||
51  token_type == get_token_type(Token::DEL) ||
52  token_type == get_token_type(Token::DEL2)) {
53  auto value = sym.value.as<ast::Name>();
54  REQUIRE(!value.get_node_name().empty());
55  }
56  // clang-format on
57  // prime variable
58  else if (token_type == get_token_type(Token::PRIME)) {
59  auto value = sym.value.as<ast::PrimeName>();
60  REQUIRE(!value.get_node_name().empty());
61  }
62  // integer constant
63  else if (token_type == get_token_type(Token::INTEGER)) {
64  auto value = sym.value.as<ast::Integer>();
65  REQUIRE(value.get_value() != 0);
66  }
67  // float constant
68  else if (token_type == get_token_type(Token::REAL)) {
69  auto value = sym.value.as<ast::Double>();
70  REQUIRE(value.to_double() != 0);
71  }
72  // const char*
73  else if (token_type == get_token_type(Token::STRING)) {
74  auto value = sym.value.as<ast::String>();
75  REQUIRE(!value.get_value().empty());
76  }
77  // string block representation verbatim or block comment
78  else if (token_type == get_token_type(Token::VERBATIM) ||
79  token_type == get_token_type(Token::BLOCK_COMMENT) ||
80  token_type == get_token_type(Token::LINE_PART)) {
81  auto value = sym.value.as<std::string>();
82  REQUIRE(!value.empty());
83  }
84  // rest of the tokens
85  else {
86  auto value = sym.value.as<ModToken>();
87  REQUIRE(!value.text().empty());
88  }
89 
90  return sym.type_get() == get_token_type(type);
91 }
92 
93 TEST_CASE("NMODL Lexer returning valid token types", "[Lexer]") {
94  SECTION("Some keywords") {
95  REQUIRE(check_token_type("VERBATIM Hello ENDVERBATIM", Token::VERBATIM));
96  REQUIRE(check_token_type("INITIAL", Token::INITIAL1));
97  REQUIRE(check_token_type("SOLVE", Token::SOLVE));
98  }
99 
100  SECTION("NMODL language keywords and constructs") {
101  REQUIRE(check_token_type(" h' = (hInf-h)/hTau\n", Token::PRIME));
102  REQUIRE(check_token_type("while", Token::WHILE));
103  REQUIRE(check_token_type("if", Token::IF));
104  REQUIRE(check_token_type("else", Token::ELSE));
105  REQUIRE(check_token_type("WHILE", Token::WHILE));
106  REQUIRE(check_token_type("IF", Token::IF));
107  REQUIRE(check_token_type("ELSE", Token::ELSE));
108  REQUIRE(check_token_type("REPRESENTS NCIT:C17145", Token::REPRESENTS));
109  }
110 
111  SECTION("Different number types") {
112  REQUIRE(check_token_type("123", Token::INTEGER));
113  REQUIRE(check_token_type("123.32", Token::REAL));
114  REQUIRE(check_token_type("1.32E+3", Token::REAL));
115  REQUIRE(check_token_type("1.32e-3", Token::REAL));
116  REQUIRE(check_token_type("32e-3", Token::REAL));
117  REQUIRE(check_token_type("1e+23", Token::REAL));
118  REQUIRE(check_token_type("1e-23", Token::REAL));
119  REQUIRE_FALSE(check_token_type("124.11", Token::INTEGER));
120  }
121 
122  SECTION("Name/Strings types") {
123  REQUIRE(check_token_type("neuron", Token::NAME));
124  REQUIRE(check_token_type("\"Quoted String\"", Token::STRING));
125  }
126 
127  SECTION("Logical operator types") {
128  REQUIRE(check_token_type(">", Token::GT));
129  REQUIRE(check_token_type(">=", Token::GE));
130  REQUIRE(check_token_type("<", Token::LT));
131  REQUIRE(check_token_type("==", Token::EQ));
132  REQUIRE(check_token_type("!=", Token::NE));
133  REQUIRE(check_token_type("<->", Token::REACT1));
134  REQUIRE(check_token_type("~+", Token::NONLIN1));
135  }
136 
137  SECTION("Brace types") {
138  REQUIRE(check_token_type("{", Token::OPEN_BRACE));
139  REQUIRE(check_token_type("}", Token::CLOSE_BRACE));
140  REQUIRE(check_token_type("(", Token::OPEN_PARENTHESIS));
141  REQUIRE_FALSE(check_token_type(")", Token::OPEN_PARENTHESIS));
142  }
143 }
nmodl::TokenType
parser::NmodlParser::token_type TokenType
Definition: main_nmodl.cpp:35
nmodl::parser::NmodlDriver
Class that binds all pieces together for parsing nmodl file.
Definition: nmodl_driver.hpp:67
nmodl::ast::Double
Represents a double variable.
Definition: double.hpp:53
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::ast::Integer
Represents an integer variable.
Definition: integer.hpp:49
nmodl_lexer.hpp
driver
nmodl::parser::UnitDriver driver
Definition: parser.cpp:28
nmodl::parser::NmodlLexer
Represent Lexer/Scanner class for NMODL language parsing.
Definition: nmodl_lexer.hpp:60
nmodl::ast::PrimeName
Represents a prime variable (for ODE)
Definition: prime_name.hpp:48
TEST_CASE
TEST_CASE("NMODL Lexer returning valid token types", "[Lexer]")
Definition: tokens.cpp:93
Token
parser::CParser::token Token
Definition: main_c.cpp:28
nmodl::parser::NmodlLexer::next_token
virtual NmodlParser::symbol_type next_token()
Function for lexer to scan token (replacement for yylex())
nmodl::SymbolType
parser::NmodlParser::symbol_type SymbolType
Definition: main_nmodl.cpp:33
modtoken.hpp
nmodl_driver.hpp
symbol_type
void symbol_type(const std::string &name, T &value)
Definition: modtoken.cpp:32
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
check_token_type
bool check_token_type(const std::string &name, TokenType type)
retrieve token type from lexer and check if it's of given type
Definition: tokens.cpp:27
nmodl::ModToken
Represent token returned by scanner.
Definition: modtoken.hpp:50
nmodl::ast::String
Represents a string.
Definition: string.hpp:52