diff --git a/src/lexer/token_mapping.cpp b/src/lexer/token_mapping.cpp index 5bfc9299b5..287ca6a2cd 100644 --- a/src/lexer/token_mapping.cpp +++ b/src/lexer/token_mapping.cpp @@ -246,6 +246,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 @@ -259,6 +284,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 618200edc3..348ad2475d 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 "utils/logger.hpp" #include "visitors/visitor_utils.hpp" @@ -78,5 +79,17 @@ void SemanticAnalysisVisitor::visit_destructor_block(const ast::DestructorBlock& /// --> } +void SemanticAnalysisVisitor::visit_function_call(const ast::FunctionCall& node) { + /// <-- This code is for check 4 + 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 7d1bbb90e2..1b0421a5fd 100644 --- a/src/visitors/semantic_analysis_visitor.hpp +++ b/src/visitors/semantic_analysis_visitor.hpp @@ -27,6 +27,7 @@ * (mandatory in mod2c). * 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 that an external definition is allowed by CoreNeuron */ #include "ast/ast.hpp" #include "visitors/ast_visitor.hpp" @@ -59,6 +60,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;