diff --git a/src/lexer/token_mapping.cpp b/src/lexer/token_mapping.cpp index 6a1ce6b7bb..57ae4a0f6e 100644 --- a/src/lexer/token_mapping.cpp +++ b/src/lexer/token_mapping.cpp @@ -244,6 +244,31 @@ const static std::vector extern_definitions = {"acos", "tanh", "threshold"}; const static std::vector need_nt = {"at_time"}; +const static std::vector not_thread_safe = {"force", + "deflate", + "expfit", + "derivs", + "spline", + "exprand", + "gauss", + "normrand", + "poisrand", + "poisson", + "setseed", + "scop_random", + "boundary", + "romberg", + "invert", + "stepforce", + "schedule", + "set_seed", + "nrn_random_play"}; + +bool is_external_definitions(const std::string& token) { + return std::find(extern_definitions.cbegin(), extern_definitions.cend(), token) != + extern_definitions.cend(); +} + /** * Checks if \c token is one of the functions coming from NEURON/CoreNEURON and needs @@ -257,6 +282,12 @@ bool needs_neuron_thread_first_arg(const std::string& token) { } +bool is_not_thread_safe(const std::string& token) { + return std::find(not_thread_safe.cbegin(), not_thread_safe.cend(), token) != + not_thread_safe.cend(); +} + + /** * Variables from NEURON that are directly used in NMODL * diff --git a/src/lexer/token_mapping.hpp b/src/lexer/token_mapping.hpp index 6f1fb3255f..a39f9e4d3f 100644 --- a/src/lexer/token_mapping.hpp +++ b/src/lexer/token_mapping.hpp @@ -27,7 +27,9 @@ std::vector get_external_functions(); namespace details { +bool is_external_definitions(const std::string& token); bool needs_neuron_thread_first_arg(const std::string& token); +bool is_not_thread_safe(const std::string& token); } // namespace details diff --git a/src/visitors/semantic_analysis_visitor.cpp b/src/visitors/semantic_analysis_visitor.cpp index 602b2eb502..107f9c4ed3 100644 --- a/src/visitors/semantic_analysis_visitor.cpp +++ b/src/visitors/semantic_analysis_visitor.cpp @@ -4,6 +4,7 @@ #include "ast/program.hpp" #include "ast/suffix.hpp" #include "ast/table_statement.hpp" +#include "lexer/token_mapping.hpp" #include "symtab/symbol_properties.hpp" #include "utils/logger.hpp" #include "visitors/visitor_utils.hpp" @@ -101,5 +102,17 @@ void SemanticAnalysisVisitor::visit_destructor_block(const ast::DestructorBlock& /// --> } +void SemanticAnalysisVisitor::visit_function_call(const ast::FunctionCall& node) { + /// <-- This code is for check 5 + const auto& name = node.get_node_name(); + if (details::is_external_definitions(name) && details::is_not_thread_safe(name)) { + logger->critical( + "SemanticAnalysisVisitor :: '{}' is not thread safe and incompatible with CoreNEURON", + name); + check_fail = true; + } + /// --> +} + } // namespace visitor } // namespace nmodl diff --git a/src/visitors/semantic_analysis_visitor.hpp b/src/visitors/semantic_analysis_visitor.hpp index 35fef8d44b..09a78e0cd9 100644 --- a/src/visitors/semantic_analysis_visitor.hpp +++ b/src/visitors/semantic_analysis_visitor.hpp @@ -28,6 +28,7 @@ * 2. Check that destructor blocks are only inside mod file that are point_process. * 3. A TABLE statement in functions cannot have name list, and should have one in procedures. * 4. Check if ion variables from a `USEION` statement are not declared in `CONSTANT` block. + * 5. Check that an external definition is allowed by CoreNeuron */ #include "ast/ast.hpp" #include "visitors/ast_visitor.hpp" @@ -60,6 +61,10 @@ class SemanticAnalysisVisitor: public ConstAstVisitor { /// Visit destructor and check that the file is of type POINT_PROCESS or ARTIFICIAL_CELL void visit_destructor_block(const ast::DestructorBlock& node) override; + /// Visit function call and check if the function is not thread safe and so not + /// compatible with CoreNeuron + void visit_function_call(const ast::FunctionCall& node) override; + public: SemanticAnalysisVisitor() = default;