def setUp(self): Logger.init_logger(LoggingLevel.INFO) SymbolTable.initialize_symbol_table(ASTSourceLocation(start_line=0, start_column=0, end_line=0, end_column=0)) PredefinedUnits.register_units() PredefinedTypes.register_types() PredefinedVariables.register_variables() PredefinedFunctions.register_functions()
def setUp(self): PredefinedUnits.register_units() PredefinedTypes.register_types() PredefinedFunctions.register_functions() PredefinedVariables.register_variables() SymbolTable.initialize_symbol_table(ASTSourceLocation(start_line=0, start_column=0, end_line=0, end_column=0)) Logger.init_logger(LoggingLevel.INFO) self.target_path = str(os.path.realpath(os.path.join(os.path.dirname(__file__), os.path.join( os.pardir, 'target'))))
def setUp(self) -> None: PredefinedUnits.register_units() PredefinedTypes.register_types() PredefinedFunctions.register_functions() PredefinedVariables.register_variables() SymbolTable.initialize_symbol_table(ASTSourceLocation(start_line=0, start_column=0, end_line=0, end_column=0)) Logger.init_logger(LoggingLevel.INFO) self.target_path = str(os.path.realpath(os.path.join(os.path.dirname(__file__), os.path.join(os.pardir, 'target'))))
def visit_neuron(self, node): """ Private method: Used to visit a single neuron and create the corresponding global as well as local scopes. :return: a single neuron. :rtype: ast_neuron """ # set current processed neuron Logger.set_current_neuron(node) code, message = Messages.get_start_building_symbol_table() Logger.log_message(neuron=node, code=code, error_position=node.get_source_position(), message=message, log_level=LoggingLevel.INFO) # before starting the work on the neuron, make everything which was implicit explicit # but if we have a model without an equations block, just skip this step if node.get_equations_blocks() is not None: make_implicit_odes_explicit(node.get_equations_blocks()) scope = Scope(scope_type=ScopeType.GLOBAL, source_position=node.get_source_position()) node.update_scope(scope) node.get_body().update_scope(scope) # now first, we add all predefined elements to the scope variables = PredefinedVariables.get_variables() functions = PredefinedFunctions.get_function_symbols() types = PredefinedTypes.get_types() for symbol in variables.keys(): node.get_scope().add_symbol(variables[symbol]) for symbol in functions.keys(): node.get_scope().add_symbol(functions[symbol]) for symbol in types.keys(): node.get_scope().add_symbol(types[symbol])
def visit_neuron(self, node): """ Private method: Used to visit a single neuron and create the corresponding global as well as local scopes. :return: a single neuron. :rtype: ast_neuron """ # set current processed neuron Logger.set_current_node(node) code, message = Messages.get_start_building_symbol_table() Logger.log_message(node=node, code=code, error_position=node.get_source_position(), message=message, log_level=LoggingLevel.INFO) scope = Scope(scope_type=ScopeType.GLOBAL, source_position=node.get_source_position()) node.update_scope(scope) node.get_body().update_scope(scope) # now first, we add all predefined elements to the scope variables = PredefinedVariables.get_variables() functions = PredefinedFunctions.get_function_symbols() types = PredefinedTypes.get_types() for symbol in variables.keys(): node.get_scope().add_symbol(variables[symbol]) for symbol in functions.keys(): node.get_scope().add_symbol(functions[symbol]) for symbol in types.keys(): node.get_scope().add_symbol(types[symbol])
def color_components(self): complete_text_as_lines = self.text.get('1.0', tk.END + '-1c').splitlines() active = False for number, line in enumerate(complete_text_as_lines): last_start_index = -1 if '#' in line: s_l = number + 1 s_c = line.index('#') e_l = s_l e_c = len(line) self.color_comment(s_l, s_c, e_l, e_c) if '/*' in line and '*/' in line: s_l = number + 1 s_c = line.index('/*') e_l = s_l e_c = line.index('*/') + 2 self.color_comment(s_l, s_c, e_l, e_c) elif '/*' in line: active = True s_l = number + 1 s_c = line.index('/*') e_l = s_l e_c = len(line) self.color_comment(s_l, s_c, e_l, e_c) elif '*/' in line: active = False s_l = number + 1 s_c = 0 e_l = s_l e_c = line.index('*/') + 2 self.color_comment(s_l, s_c, e_l, e_c) elif active: s_l = number + 1 s_c = 0 e_l = s_l e_c = len(line) self.color_comment(s_l, s_c, e_l, e_c) cur_line = line indices = [(index, word) for (index, word) in enumerate(self.pat.findall(line))] for _, word in indices: s_l = number + 1 s_c = cur_line.find(word) e_l = s_l e_c = s_c + len(word) cur_line = cur_line.replace(word, 'X' * len(word), 1) # skip it if it is already tagged if self.editor.textPad.tag_names('%s.%s' % (s_l, s_c)): continue if word in PredefinedTypes.get_types(): self.color_type(s_l, s_c, e_l, e_c) if word in PredefinedFunctions.get_function_symbols(): self.make_italic(s_l, s_c, e_l, e_c) if word in keywords: self.make_bold(s_l, s_c, e_l, e_c)
from pynestml.meta_model.ast_nestml_compilation_unit import ASTNestMLCompilationUnit from pynestml.utils.ast_source_location import ASTSourceLocation from pynestml.generated.PyNestMLLexer import PyNestMLLexer from pynestml.generated.PyNestMLParser import PyNestMLParser from pynestml.symbol_table.symbol_table import SymbolTable from pynestml.symbols.predefined_functions import PredefinedFunctions from pynestml.symbols.predefined_types import PredefinedTypes from pynestml.symbols.predefined_units import PredefinedUnits from pynestml.symbols.predefined_variables import PredefinedVariables from pynestml.utils.logger import LoggingLevel, Logger from pynestml.visitors.ast_builder_visitor import ASTBuilderVisitor # setups the infrastructure PredefinedUnits.register_units() PredefinedTypes.register_types() PredefinedFunctions.register_functions() PredefinedVariables.register_variables() SymbolTable.initialize_symbol_table( ASTSourceLocation(start_line=0, start_column=0, end_line=0, end_column=0)) Logger.init_logger(LoggingLevel.INFO) class ASTBuildingTest(unittest.TestCase): def test(self): for filename in os.listdir( os.path.realpath( os.path.join(os.path.dirname(__file__), os.path.join('..', 'models')))): if filename.endswith(".nestml"): print('Start creating AST for ' + filename + ' ...'), input_file = FileStream(
def convert_function_call(cls, function_call, prefix=''): """ Converts a single handed over function call to C++ NEST API syntax. Parameters ---------- function_call : ASTFunctionCall The function call node to convert. prefix : str Optional string that will be prefixed to the function call. For example, to refer to a function call in the class "node", use a prefix equal to "node." or "node->". Predefined functions will not be prefixed. Returns ------- s : str The function call string in C++ syntax. """ function_name = function_call.get_name() if function_name == 'and': return '&&' if function_name == 'or': return '||' if function_name == PredefinedFunctions.TIME_RESOLUTION: return 'nest::Time::get_resolution().get_ms()' if function_name == PredefinedFunctions.TIME_STEPS: return 'nest::Time(nest::Time::ms((double) ({!s}))).get_steps()' if function_name == PredefinedFunctions.CLIP: # warning: the arguments of this function must swapped and # are therefore [v_max, v_min, v], hence its structure return 'std::min({2!s}, std::max({1!s}, {0!s}))' if function_name == PredefinedFunctions.MAX: return 'std::max({!s}, {!s})' if function_name == PredefinedFunctions.MIN: return 'std::min({!s}, {!s})' if function_name == PredefinedFunctions.EXP: return 'std::exp({!s})' if function_name == PredefinedFunctions.LN: return 'std::log({!s})' if function_name == PredefinedFunctions.LOG10: return 'std::log10({!s})' if function_name == PredefinedFunctions.COSH: return 'std::cosh({!s})' if function_name == PredefinedFunctions.SINH: return 'std::sinh({!s})' if function_name == PredefinedFunctions.TANH: return 'std::tanh({!s})' if function_name == PredefinedFunctions.EXPM1: return 'numerics::expm1({!s})' if function_name == PredefinedFunctions.RANDOM_NORMAL: return '(({!s}) + ({!s}) * ' + prefix + 'normal_dev_( nest::kernel().rng_manager.get_rng( ' + prefix + 'get_thread() ) ))' if function_name == PredefinedFunctions.RANDOM_UNIFORM: return '(({!s}) + ({!s}) * nest::kernel().rng_manager.get_rng( ' + prefix + 'get_thread() )->drand())' if function_name == PredefinedFunctions.EMIT_SPIKE: return 'set_spiketime(nest::Time::step(origin.get_steps()+lag+1));\n' \ 'nest::SpikeEvent se;\n' \ 'nest::kernel().event_delivery_manager.send(*this, se, lag)' # suppress prefix for misc. predefined functions # check if function is "predefined" purely based on the name, as we don't have access to the function symbol here function_is_predefined = PredefinedFunctions.get_function( function_name) if function_is_predefined: prefix = '' if ASTUtils.needs_arguments(function_call): n_args = len(function_call.get_args()) return prefix + function_name + '(' + ', '.join( ['{!s}' for _ in range(n_args)]) + ')' return prefix + function_name + '()'
def init_predefined(): # initialize the predefined elements PredefinedUnits.register_units() PredefinedTypes.register_types() PredefinedFunctions.register_functions() PredefinedVariables.register_variables()
import unittest from pynestml.meta_model.ast_source_location import ASTSourceLocation from pynestml.symbol_table.symbol_table import SymbolTable from pynestml.symbols.predefined_functions import PredefinedFunctions from pynestml.symbols.predefined_types import PredefinedTypes from pynestml.symbols.predefined_units import PredefinedUnits from pynestml.symbols.predefined_variables import PredefinedVariables from pynestml.utils.ast_nestml_printer import ASTNestMLPrinter from pynestml.utils.logger import LoggingLevel, Logger from pynestml.utils.model_parser import ModelParser # setups the infrastructure PredefinedUnits.register_units() PredefinedTypes.register_types() PredefinedFunctions.register_functions() PredefinedVariables.register_variables() SymbolTable.initialize_symbol_table(ASTSourceLocation(start_line=0, start_column=0, end_line=0, end_column=0)) Logger.init_logger(LoggingLevel.INFO) class NestMLPrinterTest(unittest.TestCase): """ Tests if the NestML printer works as intended. """ def test_block_with_variables_with_comments(self): block = '\n' \ '/* pre1\n' \ '* pre2\n' \ '*/\n' \
def convert_function_call(self, function_call, prefix=''): """Convert a single function call to C++ GSL API syntax. Parameters ---------- function_call : ASTFunctionCall The function call node to convert. prefix : str Optional string that will be prefixed to the function call. For example, to refer to a function call in the class "node", use a prefix equal to "node." or "node->". Predefined functions will not be prefixed. Returns ------- s : str The function call string in C++ syntax. """ function_name = function_call.get_name() if function_name == PredefinedFunctions.TIME_RESOLUTION: return 'nest::Time::get_resolution().get_ms()' if function_name == PredefinedFunctions.TIME_STEPS: return 'nest::Time(nest::Time::ms((double) {!s})).get_steps()' if function_name == PredefinedFunctions.MAX: return 'std::max({!s}, {!s})' if function_name == PredefinedFunctions.MIN: return 'std::min({!s}, {!s})' if function_name == PredefinedFunctions.CLIP: # warning: the arguments of this function have been swapped and # are therefore [v_max, v_min, v], hence its structure return 'std::min({2!s}, std::max({1!s}, {0!s}))' if function_name == PredefinedFunctions.EXP: if self.is_upper_bound: return 'std::exp(std::min({!s},' + str( self.maximal_exponent) + '))' else: return 'std::exp({!s})' if function_name == PredefinedFunctions.COSH: if self.is_upper_bound: return 'std::cosh(std::min(std::abs({!s}),' + str( self.maximal_exponent) + '))' else: return 'std::cosh({!s})' if function_name == PredefinedFunctions.SINH: if self.is_upper_bound: return 'std::sinh(({!s} > 0 ? 1 : -1)*std::min(std::abs({!s}),' + str( self.maximal_exponent) + '))' else: return 'std::sinh({!s})' if function_name == PredefinedFunctions.TANH: return 'std::tanh({!s})' if function_name == PredefinedFunctions.LN: return 'std::log({!s})' if function_name == PredefinedFunctions.LOG10: return 'std::log10({!s})' if function_name == PredefinedFunctions.EXPM1: return 'numerics::expm1({!s})' if function_name == PredefinedFunctions.RANDOM_NORMAL: return '(({!s}) + ({!s}) * ' + prefix + 'normal_dev_( nest::get_vp_specific_rng( ' + prefix + 'get_thread() ) ))' if function_name == PredefinedFunctions.RANDOM_UNIFORM: return '(({!s}) + ({!s}) * nest::get_vp_specific_rng( ' + prefix + 'get_thread() )->drand())' if function_name == PredefinedFunctions.EMIT_SPIKE: return 'set_spiketime(nest::Time::step(origin.get_steps()+lag+1));\n' \ 'nest::SpikeEvent se;\n' \ 'nest::kernel().event_delivery_manager.send(*this, se, lag)' if function_name == PredefinedFunctions.DELIVER_SPIKE: return ''' set_delay( {1!s} ); const long __delay_steps = nest::Time::delay_ms_to_steps( get_delay() ); set_delay_steps(__delay_steps); e.set_receiver( *__target ); e.set_weight( {0!s} ); // use accessor functions (inherited from Connection< >) to obtain delay in steps and rport e.set_delay_steps( get_delay_steps() ); e.set_rport( get_rport() ); e(); ''' # suppress prefix for misc. predefined functions # check if function is "predefined" purely based on the name, as we don't have access to the function symbol here function_is_predefined = PredefinedFunctions.get_function( function_name) if function_is_predefined: prefix = '' if ASTUtils.needs_arguments(function_call): n_args = len(function_call.get_args()) return prefix + function_name + '(' + ', '.join( ['{!s}' for _ in range(n_args)]) + ')' return prefix + function_name + '()'
def convert_function_call(self, function_call, prefix=''): """Convert a single function call to C++ GSL API syntax. Parameters ---------- function_call : ASTFunctionCall The function call node to convert. prefix : str Optional string that will be prefixed to the function call. For example, to refer to a function call in the class "node", use a prefix equal to "node." or "node->". Predefined functions will not be prefixed. Returns ------- s : str The function call string in C++ syntax. """ function_name = function_call.get_name() if function_name == PredefinedFunctions.TIME_RESOLUTION: return 'nest::Time::get_resolution().get_ms()' if function_name == PredefinedFunctions.TIME_STEPS: return 'nest::Time(nest::Time::ms((double) {!s})).get_steps()' if function_name == PredefinedFunctions.MAX: return 'std::max({!s}, {!s})' if function_name == PredefinedFunctions.MIN: return 'std::min({!s}, {!s})' if function_name == PredefinedFunctions.CLIP: # warning: the arguments of this function have been swapped and # are therefore [v_max, v_min, v], hence its structure return 'std::min({2!s}, std::max({1!s}, {0!s}))' if function_name == PredefinedFunctions.EXP: if self.is_upper_bound: return 'std::exp(std::min({!s},' + str( self.maximal_exponent) + '))' else: return 'std::exp({!s})' if function_name == PredefinedFunctions.COSH: if self.is_upper_bound: return 'std::cosh(std::min(std::abs({!s}),' + str( self.maximal_exponent) + '))' else: return 'std::cosh({!s})' if function_name == PredefinedFunctions.SINH: if self.is_upper_bound: return 'std::sinh(({!s} > 0 ? 1 : -1)*std::min(std::abs({!s}),' + str( self.maximal_exponent) + '))' else: return 'std::sinh({!s})' if function_name == PredefinedFunctions.TANH: return 'std::tanh({!s})' if function_name == PredefinedFunctions.LOG: return 'std::log({!s})' if function_name == PredefinedFunctions.EXPM1: return 'numerics::expm1({!s})' if function_name == PredefinedFunctions.EMIT_SPIKE: return 'set_spiketime(nest::Time::step(origin.get_steps()+lag+1));\n' \ 'nest::SpikeEvent se;\n' \ 'nest::kernel().event_delivery_manager.send(*this, se, lag)' # suppress prefix for misc. predefined functions function_is_predefined = PredefinedFunctions.get_function( function_name ) # check if function is "predefined" purely based on the name, as we don't have access to the function symbol here if function_is_predefined: prefix = '' if ASTUtils.needs_arguments(function_call): n_args = len(function_call.get_args()) return prefix + function_name + '(' + ', '.join( ['{!s}' for _ in range(n_args)]) + ')' return prefix + function_name + '()'
def convert_function_call(cls, function_call, prefix=''): """ Converts a single handed over function call to C++ NEST API syntax. Parameters ---------- function_call : ASTFunctionCall The function call node to convert. prefix : str Optional string that will be prefixed to the function call. For example, to refer to a function call in the class "node", use a prefix equal to "node." or "node->". Predefined functions will not be prefixed. Returns ------- s : str The function call string in C++ syntax. """ function_name = function_call.get_name() if function_name == 'and': return '&&' if function_name == 'or': return '||' if function_name == PredefinedFunctions.TIME_RESOLUTION: return 'nest::Time::get_resolution().get_ms()' if function_name == PredefinedFunctions.TIME_STEPS: return 'nest::Time(nest::Time::ms((double) %s)).get_steps()' if function_name == PredefinedFunctions.POW: return 'std::pow(%s, %s)' if function_name == PredefinedFunctions.MAX or function_name == PredefinedFunctions.BOUNDED_MAX: return 'std::max(%s, %s)' if function_name == PredefinedFunctions.MIN or function_name == PredefinedFunctions.BOUNDED_MIN: return 'std::min(%s, %s)' if function_name == PredefinedFunctions.EXP: return 'std::exp(%s)' if function_name == PredefinedFunctions.LOG: return 'std::log(%s)' if function_name == PredefinedFunctions.EXPM1: return 'numerics::expm1(%s)' if function_name == PredefinedFunctions.EMIT_SPIKE: return 'set_spiketime(nest::Time::step(origin.get_steps()+lag+1));\n' \ 'nest::SpikeEvent se;\n' \ 'nest::kernel().event_delivery_manager.send(*this, se, lag)' # suppress prefix for misc. predefined functions function_is_predefined = PredefinedFunctions.get_function( function_name ) # check if function is "predefined" purely based on the name, as we don't have access to the function symbol here if function_is_predefined: prefix = '' if ASTUtils.needs_arguments(function_call): n_args = len(function_call.get_args()) return prefix + function_name + '(' + ', '.join( ['%s' for _ in range(n_args)]) + ')' return prefix + function_name + '()'