def visit_declaration(self, node): """ Checks the coco for a declaration. :param node: a single declaration. :type node: ASTDeclaration """ assert isinstance(node, ASTDeclaration) if node.has_invariant(): invariant_type = node.get_invariant().type if invariant_type is None or isinstance(invariant_type, ErrorTypeSymbol): code, message = Messages.get_type_could_not_be_derived( str(node.get_invariant())) Logger.log_message( error_position=node.get_invariant().get_source_position(), code=code, message=message, log_level=LoggingLevel.ERROR) elif not invariant_type.equals(PredefinedTypes.get_boolean_type()): code, message = Messages.get_type_different_from_expected( PredefinedTypes.get_boolean_type(), invariant_type) Logger.log_message( error_position=node.get_invariant().get_source_position(), code=code, message=message, log_level=LoggingLevel.ERROR) return
def handle_unit(unit_type): """ Handles a handed over unit by creating the corresponding unit-type, storing it in the list of predefined units, creating a type symbol and returning it. :param unit_type: a single sympy unit symbol :type unit_type: Symbol (sympy) :return: a new type symbol :rtype: type_symbol """ # first ensure that it does not already exists, if not create it and register it in the set of predefined units # first clean up the unit of not required components, here it is the 1.0 in front of the unit # e.g., 1.0 * 1 / ms. This step is not mandatory for correctness, but makes reporting easier if isinstance(unit_type, units.Quantity) and unit_type.value == 1.0: to_process = unit_type.unit else: to_process = unit_type if str(to_process) not in PredefinedUnits.get_units().keys(): unit_type_t = UnitType(name=str(to_process), unit=to_process) PredefinedUnits.register_unit(unit_type_t) # now create the corresponding type symbol if it does not exists if PredefinedTypes.get_type(str(to_process)) is None: type_symbol = UnitTypeSymbol( unit=PredefinedUnits.get_unit(str(to_process))) PredefinedTypes.register_type(type_symbol) return PredefinedTypes.get_type(name=str(to_process))
def endvisit_function(self, node): symbol = self.symbol_stack.pop() scope = self.scope_stack.pop() assert isinstance(symbol, FunctionSymbol), 'Not a function symbol' for arg in node.get_parameters(): # given the fact that the name is not directly equivalent to the one as stated in the model, # we have to get it by the sub-visitor data_type_visitor = ASTDataTypeVisitor() arg.get_data_type().accept(data_type_visitor) type_name = data_type_visitor.result # first collect the types for the parameters of the function symbol symbol.add_parameter_type(PredefinedTypes.get_type(type_name)) # update the scope of the arg arg.update_scope(scope) # create the corresponding variable symbol representing the parameter var_symbol = VariableSymbol(element_reference=arg, scope=scope, name=arg.get_name(), block_type=BlockType.LOCAL, is_predefined=False, is_function=False, is_recordable=False, type_symbol=PredefinedTypes.get_type(type_name), variable_type=VariableType.VARIABLE) assert isinstance(scope, Scope) scope.add_symbol(var_symbol) if node.has_return_type(): data_type_visitor = ASTDataTypeVisitor() node.get_return_type().accept(data_type_visitor) symbol.set_return_type(PredefinedTypes.get_type(data_type_visitor.result)) else: symbol.set_return_type(PredefinedTypes.get_void_type()) self.block_type_stack.pop() # before leaving update the type
def visit_while_stmt(self, node): """ Visits a single while stmt and checks that its condition is of boolean type. :param node: a single while stmt :type node: ASTWhileStmt """ if node.get_source_position().equals( ASTSourceLocation.get_added_source_position()): # no type checks are executed for added nodes, since we assume correctness return cond_type = node.get_condition().type if isinstance(cond_type, ErrorTypeSymbol): code, message = Messages.get_type_could_not_be_derived( node.get_condition()) Logger.log_message( code=code, message=message, error_position=node.get_condition().get_source_position(), log_level=LoggingLevel.ERROR) elif not cond_type.equals(PredefinedTypes.get_boolean_type()): code, message = Messages.get_type_different_from_expected( PredefinedTypes.get_boolean_type(), cond_type) Logger.log_message( code=code, message=message, error_position=node.get_condition().get_source_position(), log_level=LoggingLevel.ERROR) return
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 endvisit_function(self, node): symbol = self.symbol_stack.pop() scope = self.scope_stack.pop() assert isinstance(symbol, FunctionSymbol), 'Not a function symbol' for arg in node.get_parameters(): # given the fact that the name is not directly equivalent to the one as stated in the model, # we have to get it by the sub-visitor data_type_visitor = ASTDataTypeVisitor() arg.get_data_type().accept(data_type_visitor) type_name = data_type_visitor.result # first collect the types for the parameters of the function symbol symbol.add_parameter_type(PredefinedTypes.get_type(type_name)) # update the scope of the arg arg.update_scope(scope) # create the corresponding variable symbol representing the parameter var_symbol = VariableSymbol( element_reference=arg, scope=scope, name=arg.get_name(), block_type=BlockType.LOCAL, is_predefined=False, is_function=False, is_recordable=False, type_symbol=PredefinedTypes.get_type(type_name), variable_type=VariableType.VARIABLE) assert isinstance(scope, Scope) scope.add_symbol(var_symbol) if node.has_return_type(): data_type_visitor = ASTDataTypeVisitor() node.get_return_type().accept(data_type_visitor) symbol.set_return_type( PredefinedTypes.get_type(data_type_visitor.result)) else: symbol.set_return_type(PredefinedTypes.get_void_type()) self.block_type_stack.pop() # before leaving update the type
def visit_simple_expression(self, node): """ Visit a simple rhs and update the type of a numeric literal. :param node: a single meta_model node :type node: ast_node :return: no value returned, the type is updated in-place :rtype: void """ assert node.get_scope() is not None, "Run symboltable creator." # if variable is also set in this rhs, the var type overrides the literal if node.get_variable() is not None: scope = node.get_scope() var_name = node.get_variable().get_name() variable_symbol_resolve = scope.resolve_to_symbol(var_name, SymbolKind.VARIABLE) if not variable_symbol_resolve is None: node.type = variable_symbol_resolve.get_type_symbol() else: node.type = scope.resolve_to_symbol(var_name, SymbolKind.TYPE) node.type.referenced_object = node return if node.get_numeric_literal() is not None and isinstance(node.get_numeric_literal(), float): node.type = PredefinedTypes.get_real_type() node.type.referenced_object = node return elif node.get_numeric_literal() is not None and isinstance(node.get_numeric_literal(), int): node.type = PredefinedTypes.get_integer_type() node.type.referenced_object = node return
def visit_simple_expression(self, node): """ Visit a simple rhs and update the type of a numeric literal. :param node: a single meta_model node :type node: ast_node :return: no value returned, the type is updated in-place :rtype: void """ assert node.get_scope() is not None, "Run symboltable creator." # if variable is also set in this rhs, the var type overrides the literal if node.get_variable() is not None: scope = node.get_scope() var_name = node.get_variable().get_name() variable_symbol_resolve = scope.resolve_to_symbol(var_name, SymbolKind.VARIABLE) if variable_symbol_resolve is not None: node.type = variable_symbol_resolve.get_type_symbol() else: type_symbol_resolve = scope.resolve_to_symbol(var_name, SymbolKind.TYPE) if type_symbol_resolve is not None: node.type = type_symbol_resolve else: node.type = ErrorTypeSymbol() node.type.referenced_object = node return if node.get_numeric_literal() is not None and isinstance(node.get_numeric_literal(), float): node.type = PredefinedTypes.get_real_type() node.type.referenced_object = node return elif node.get_numeric_literal() is not None and isinstance(node.get_numeric_literal(), int): node.type = PredefinedTypes.get_integer_type() node.type.referenced_object = node return
def __register_random_normal_function(cls): """ Registers the random method as used to generate a random normal (Gaussian) distributed variable with first parameter "mean" and second parameter "standard deviation". """ symbol = FunctionSymbol(name=cls.RANDOM_NORMAL, param_types=[PredefinedTypes.get_template_type(0), PredefinedTypes.get_template_type(0)], return_type=PredefinedTypes.get_template_type(0), element_reference=None, is_predefined=True) cls.name2function[cls.RANDOM_NORMAL] = symbol
def __register_random_uniform_function(cls): """ Registers the random method as used to generate a random sample from a uniform distribution in the interval [offset, offset + scale). """ symbol = FunctionSymbol(name=cls.RANDOM_UNIFORM, param_types=[PredefinedTypes.get_template_type(0), PredefinedTypes.get_template_type(0)], return_type=PredefinedTypes.get_template_type(0), element_reference=None, is_predefined=True) cls.name2function[cls.RANDOM_UNIFORM] = symbol
def visit_kernel(self, node): """ Checks the coco on the current node. :param node: AST kernel object :type node: ASTKernel """ for var, expr in zip(node.variables, node.expressions): # check kernel type if (var.get_differential_order() == 0 and not type(expr.type) in [IntegerTypeSymbol, RealTypeSymbol]) \ or (var.get_differential_order() > 0 and not expr.type.is_castable_to(PredefinedTypes.get_type("ms")**-var.get_differential_order())): actual_type_str = str(expr.type) if 'unit' in dir(expr.type) \ and expr.type.unit is not None \ and expr.type.unit.unit is not None: actual_type_str = str(expr.type.unit.unit) code, message = Messages.get_kernel_wrong_type( var.get_name(), var.get_differential_order(), actual_type_str) Logger.log_message(error_position=node.get_source_position(), log_level=LoggingLevel.ERROR, code=code, message=message) # check types of the state variables for order in range(var.get_differential_order()): iv_name = var.get_name() + order * "'" decl = ASTUtils.get_declaration_by_name( self._neuron.get_state_blocks(), iv_name) if decl is None: code, message = Messages.get_variable_not_defined(iv_name) Logger.log_message( node=self._neuron, code=code, message=message, log_level=LoggingLevel.ERROR, error_position=node.get_source_position()) continue assert len( self._neuron.get_state_blocks().get_declarations() [0].get_variables() ) == 1, "Only single variables are supported as targets of an assignment." iv = decl.get_variables()[0] if not iv.get_type_symbol().get_value().is_castable_to( PredefinedTypes.get_type("ms")**-order): actual_type_str = DebugTypeConverter.convert( iv.get_type_symbol()) expected_type_str = "s^-" + str(order) code, message = Messages.get_kernel_iv_wrong_type( iv_name, actual_type_str, expected_type_str) Logger.log_message( error_position=node.get_source_position(), log_level=LoggingLevel.ERROR, code=code, message=message)
def __register_print_function(cls): """ Registers the print function. """ params = list() params.append(PredefinedTypes.get_string_type()) symbol = FunctionSymbol(name=cls.PRINT, param_types=params, return_type=PredefinedTypes.get_void_type(), element_reference=None, is_predefined=True) cls.name2function[cls.PRINT] = symbol
def __register_delta_function(cls): """ Registers the delta function. """ params = list() params.append(PredefinedTypes.get_type('ms')) symbol = FunctionSymbol(name=cls.DELTA, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.DELTA] = symbol
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 __register_exp1_function(cls): """ Registers the alternative version of the exponent function, exp1. """ params = list() params.append(PredefinedTypes.get_real_type()) # the argument symbol = FunctionSymbol(name=cls.EXPM1, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.EXPM1] = symbol
def __register_logger_warning_function(cls): """ Registers the logger warning method. """ params = list() params.append(PredefinedTypes.get_string_type()) # the argument symbol = FunctionSymbol(name=cls.LOGGER_WARNING, param_types=params, return_type=PredefinedTypes.get_void_type(), element_reference=None, is_predefined=True) cls.name2function[cls.LOGGER_WARNING] = symbol
def __register_logger_warning_function(cls): """ Registers the logger warning method. """ params = list() params.append(PredefinedTypes.get_string_type()) # the argument symbol = FunctionSymbol(name=cls.LOGGER_WARNING, param_types=params, return_type=PredefinedTypes.get_void_type(), element_reference=None, is_predefined=True) cls.name2function[cls.LOGGER_WARNING] = symbol
def __register_logger_info_function(cls): """ Registers the logger info method into the scope. """ params = list() params.append(PredefinedTypes.get_string_type()) # the argument symbol = FunctionSymbol(name=cls.LOGGER_INFO, param_types=params, return_type=PredefinedTypes.get_void_type(), element_reference=None, is_predefined=True) cls.name2function[cls.LOGGER_INFO] = symbol
def __register_abs_function(cls): """ Registers the absolute value function. """ params = list() params.append(PredefinedTypes.get_template_type(0)) symbol = FunctionSymbol(name=cls.ABS, param_types=params, return_type=PredefinedTypes.get_template_type(0), element_reference=None, is_predefined=True) cls.name2function[cls.ABS] = symbol
def __register_ln_function(cls): """ Registers the natural logarithm function, i.e. the logarithm function of base :math:`e`. """ params = list() params.append(PredefinedTypes.get_real_type()) # the argument symbol = FunctionSymbol(name=cls.LN, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.LN] = symbol
def __register_logger_info_function(cls): """ Registers the logger info method into the scope. """ params = list() params.append(PredefinedTypes.get_string_type()) # the argument symbol = FunctionSymbol(name=cls.LOGGER_INFO, param_types=params, return_type=PredefinedTypes.get_void_type(), element_reference=None, is_predefined=True) cls.name2function[cls.LOGGER_INFO] = symbol
def __register_tanh_function(cls): """ Registers the hyperbolic tangent function. """ params = list() params.append(PredefinedTypes.get_real_type()) # the argument symbol = FunctionSymbol(name=cls.TANH, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.TANH] = symbol
def __register_log10_function(cls): """ Registers the logarithm function of base 10. """ params = list() params.append(PredefinedTypes.get_real_type()) # the argument symbol = FunctionSymbol(name=cls.LOG10, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.LOG10] = symbol
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 __register_log_function(cls): """ Registers the logarithm function (to base 10). """ params = list() params.append(PredefinedTypes.get_real_type()) # the argument symbol = FunctionSymbol(name=cls.LOG, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.LOG] = symbol
def __register_exp1_function(cls): """ Registers the alternative version of the exponent function, exp1. """ params = list() params.append(PredefinedTypes.get_real_type()) # the argument symbol = FunctionSymbol(name=cls.EXPM1, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.EXPM1] = symbol
def __register_print_ln_function(cls): """ Registers the print-line function. """ params = list() params.append(PredefinedTypes.get_string_type()) symbol = FunctionSymbol(name=cls.PRINTLN, param_types=params, return_type=PredefinedTypes.get_void_type(), element_reference=None, is_predefined=True) cls.name2function[cls.PRINTLN] = symbol
def __register_min_function(cls): """ Registers the minimum function. """ params = list() params.append(PredefinedTypes.get_template_type(0)) params.append(PredefinedTypes.get_template_type(0)) symbol = FunctionSymbol(name=cls.MIN, param_types=params, return_type=PredefinedTypes.get_template_type(0), element_reference=None, is_predefined=True) cls.name2function[cls.MIN] = symbol
def __register_predefined_type_variables(cls): """ Registers all predefined type variables, e.g., mV and integer. """ for name in PredefinedTypes.get_types().keys(): symbol = VariableSymbol(name=name, block_type=BlockType.PREDEFINED, is_predefined=True, type_symbol=PredefinedTypes.get_type(name), variable_type=VariableType.TYPE) cls.name2variable[name] = symbol return
def __register_convolve(cls): """ Registers the convolve function into the system. """ params = list() params.append(PredefinedTypes.get_real_type()) params.append(PredefinedTypes.get_real_type()) symbol = FunctionSymbol(name=cls.CONVOLVE, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.CONVOLVE] = symbol
def __register_cond_sum_function(cls): """ Registers the cond_sum function into scope. """ params = list() params.append(PredefinedTypes.get_type('nS')) params.append(PredefinedTypes.get_real_type()) symbol = FunctionSymbol(name=cls.COND_SUM, param_types=params, return_type=PredefinedTypes.get_type('nS'), element_reference=None, is_predefined=True) cls.name2function[cls.COND_SUM] = symbol
def __register_min_bounded_function(cls): """ Registers the minimum (bounded) function. """ params = list() params.append(PredefinedTypes.get_real_type()) params.append(PredefinedTypes.get_real_type()) symbol = FunctionSymbol(name=cls.BOUNDED_MIN, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.BOUNDED_MIN] = symbol
def __register_max_function(cls): """ Registers the maximum function. """ params = list() params.append(PredefinedTypes.get_real_type()) params.append(PredefinedTypes.get_real_type()) symbol = FunctionSymbol(name=cls.MAX, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.MAX] = symbol
def __register_delta_function(cls): """ Registers the delta function. """ params = list() params.append(PredefinedTypes.get_type('ms')) params.append(PredefinedTypes.get_type('ms')) symbol = FunctionSymbol(name=cls.DELTA, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.DELTA] = symbol
def __register_time_steps_function(cls): """ Registers the time-resolution. """ params = list() params.append(PredefinedTypes.get_type('ms')) symbol = FunctionSymbol(name=cls.TIME_STEPS, param_types=params, return_type=PredefinedTypes.get_integer_type(), element_reference=None, is_predefined=True) cls.name2function[cls.TIME_STEPS] = symbol return
def __register_time_steps_function(cls): """ Registers the time-resolution. """ params = list() params.append(PredefinedTypes.get_type('ms')) symbol = FunctionSymbol(name=cls.TIME_STEPS, param_types=params, return_type=PredefinedTypes.get_integer_type(), element_reference=None, is_predefined=True) cls.name2function[cls.TIME_STEPS] = symbol return
def __register_power_function(cls): """ Registers the power function. """ params = list() params.append(PredefinedTypes.get_real_type()) # the base type params.append(PredefinedTypes.get_real_type()) # the exponent type symbol = FunctionSymbol(name=cls.POW, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.POW] = symbol
def __register_predefined_type_variables(cls): """ Registers all predefined type variables, e.g., mV and integer. """ for name in PredefinedTypes.get_types().keys(): symbol = VariableSymbol(name=name, block_type=BlockType.PREDEFINED, is_predefined=True, type_symbol=PredefinedTypes.get_type(name), variable_type=VariableType.TYPE) cls.name2variable[name] = symbol return
def __register_convolve(cls): """ Registers the convolve function into the system. """ params = list() params.append(PredefinedTypes.get_real_type()) params.append(PredefinedTypes.get_real_type()) symbol = FunctionSymbol(name=cls.CONVOLVE, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.CONVOLVE] = symbol
def __register_min_bounded_function(cls): """ Registers the minimum (bounded) function. """ params = list() params.append(PredefinedTypes.get_real_type()) params.append(PredefinedTypes.get_real_type()) symbol = FunctionSymbol(name=cls.BOUNDED_MIN, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.BOUNDED_MIN] = symbol
def __register_max_function(cls): """ Registers the maximum function. """ params = list() params.append(PredefinedTypes.get_real_type()) params.append(PredefinedTypes.get_real_type()) symbol = FunctionSymbol(name=cls.MAX, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.MAX] = symbol
def __register_power_function(cls): """ Registers the power function. """ params = list() params.append(PredefinedTypes.get_real_type()) # the base type params.append(PredefinedTypes.get_real_type()) # the exponent type symbol = FunctionSymbol(name=cls.POW, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.POW] = symbol
def __register_cond_sum_function(cls): """ Registers the cond_sum function into scope. """ params = list() params.append(PredefinedTypes.get_type('nS')) params.append(PredefinedTypes.get_real_type()) symbol = FunctionSymbol(name=cls.COND_SUM, param_types=params, return_type=PredefinedTypes.get_type('nS'), element_reference=None, is_predefined=True) cls.name2function[cls.COND_SUM] = symbol
def __register_deliver_spike(cls): """ Registers the deliver-spike function. """ params = list() params.append(PredefinedTypes.get_real_type()) params.append(PredefinedTypes.get_type('ms')) symbol = FunctionSymbol(name=cls.DELIVER_SPIKE, param_types=params, return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.DELIVER_SPIKE] = symbol
def __register_clip_function(cls): """ Registers the clip function (bound a number between a minimum and a maximum value). """ params = list() params.append(PredefinedTypes.get_template_type(0)) # value params.append(PredefinedTypes.get_template_type(0)) # min params.append(PredefinedTypes.get_template_type(0)) # max symbol = FunctionSymbol(name=cls.CLIP, param_types=params, return_type=PredefinedTypes.get_template_type(0), element_reference=None, is_predefined=True) cls.name2function[cls.CLIP] = symbol
def endvisit_input_line(self, node): buffer_type = BlockType.INPUT_BUFFER_SPIKE if node.is_spike() else BlockType.INPUT_BUFFER_CURRENT if node.is_spike() and node.has_datatype(): type_symbol = node.get_datatype().get_type_symbol() elif node.is_spike(): type_symbol = PredefinedTypes.get_type('nS') else: type_symbol = PredefinedTypes.get_type('pA') type_symbol.is_buffer = True # set it as a buffer symbol = VariableSymbol(element_reference=node, scope=node.get_scope(), name=node.get_name(), block_type=buffer_type, vector_parameter=node.get_index_parameter(), is_predefined=False, is_function=False, is_recordable=False, type_symbol=type_symbol, variable_type=VariableType.BUFFER) symbol.set_comment(node.get_comment()) node.get_scope().add_symbol(symbol)
def endvisit_input_line(self, node): buffer_type = BlockType.INPUT_BUFFER_SPIKE if node.is_spike() else BlockType.INPUT_BUFFER_CURRENT if node.is_spike() and node.has_datatype(): type_symbol = node.get_datatype().get_type_symbol() elif node.is_spike(): type_symbol = PredefinedTypes.get_type('nS') else: type_symbol = PredefinedTypes.get_type('pA') type_symbol.is_buffer = True # set it as a buffer symbol = VariableSymbol(element_reference=node, scope=node.get_scope(), name=node.get_name(), block_type=buffer_type, vector_parameter=node.get_index_parameter(), is_predefined=False, is_function=False, is_recordable=False, type_symbol=type_symbol, variable_type=VariableType.BUFFER) symbol.set_comment(node.get_comment()) node.get_scope().add_symbol(symbol)
def visit_expression(self, node): """ Visits an expression which uses a binary logic operator and updates the type. :param node: a single expression. :type node: ast_expression """ lhs_type = node.get_lhs().type rhs_type = node.get_rhs().type lhs_type.referenced_object = node.get_lhs() rhs_type.referenced_object = node.get_rhs() if isinstance(lhs_type, BooleanTypeSymbol) and isinstance(rhs_type, BooleanTypeSymbol): node.type = PredefinedTypes.get_boolean_type() else: if isinstance(lhs_type, BooleanTypeSymbol): offending_type = lhs_type else: offending_type = rhs_type code, message = Messages.get_type_different_from_expected(BooleanTypeSymbol(), offending_type) Logger.log_message(code=code, message=message, error_position=lhs_type.referenced_object.get_source_position(), log_level=LoggingLevel.ERROR) node.type = ErrorTypeSymbol() return
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 check_co_co(cls, _neuron=None): """ Checks the coco for the handed over neuron. :param _neuron: a single neuron instance. :type _neuron: ASTNeuron """ assert (_neuron is not None and isinstance(_neuron, ASTNeuron)), \ '(PyNestML.CoCo.FunctionCallsConsistent) No or wrong type of neuron provided (%s)!' % type(_neuron) cls.__neuronName = _neuron.get_name() for userDefinedFunction in _neuron.get_functions(): cls.processed_function = userDefinedFunction symbol = userDefinedFunction.get_scope().resolve_to_symbol(userDefinedFunction.get_name(), SymbolKind.FUNCTION) # first ensure that the block contains at least one statement if symbol is not None and len(userDefinedFunction.get_block().get_stmts()) > 0: # now check that the last statement is a return cls.__check_return_recursively(symbol.get_return_type(), userDefinedFunction.get_block().get_stmts(), False) # now if it does not have a statement, but uses a return type, it is an error elif symbol is not None and userDefinedFunction.has_return_type() and \ not symbol.get_return_type().equals(PredefinedTypes.get_void_type()): code, message = Messages.get_no_return() Logger.log_message(neuron=_neuron, code=code, message=message, error_position=userDefinedFunction.get_source_position(), log_level=LoggingLevel.ERROR) return
def visit_simple_expression(self, node): """ Visits a singe simple rhs which consists of a string literal and updates the type. :param node: a simple rhs containing a string literal :type node: ast_simple_expression """ node.type = PredefinedTypes.get_string_type() node.type.referenced_object = node
def __register_emit_spike_function(cls): """ Registers the emit-spike function. """ symbol = FunctionSymbol(name=cls.EMIT_SPIKE, param_types=list(), return_type=PredefinedTypes.get_real_type(), element_reference=None, is_predefined=True) cls.name2function[cls.EMIT_SPIKE] = symbol
def __register_print_ln_function(cls): """ Registers the print-line function. """ symbol = FunctionSymbol(name=cls.PRINTLN, param_types=list(), return_type=PredefinedTypes.get_void_type(), element_reference=None, is_predefined=True) cls.name2function[cls.PRINTLN] = symbol
def __register_random_int_function(cls): """ Registers the random method as used to generate a random integer-typed value. """ symbol = FunctionSymbol(name=cls.RANDOM_INT, param_types=list(), return_type=PredefinedTypes.get_integer_type(), element_reference=None, is_predefined=True) cls.name2function[cls.RANDOM_INT] = symbol
def __register_time_resolution_function(cls): """ Registers the time resolution function. """ symbol = FunctionSymbol(name=cls.TIME_RESOLUTION, param_types=list(), return_type=PredefinedTypes.get_type('ms'), element_reference=None, is_predefined=True, scope=None) cls.name2function[cls.TIME_RESOLUTION] = symbol
def visit_simple_expression(self, node): """ Visits a single simple rhs containing an inf literal and updates its type. :param node: a simple rhs :type node: ast_simple_expression """ node.type = PredefinedTypes.get_real_type() node.type.referenced_object = node
def __register_euler_constant(cls): """ Adds the euler constant e. """ symbol = VariableSymbol(name='e', block_type=BlockType.STATE, is_predefined=True, type_symbol=PredefinedTypes.get_real_type(), variable_type=VariableType.VARIABLE) cls.name2variable[cls.E_CONSTANT] = symbol return
def __register_time_constant(cls): """ Adds the time constant t. """ symbol = VariableSymbol(name='t', block_type=BlockType.STATE, is_predefined=True, type_symbol=PredefinedTypes.get_type('ms'), variable_type=VariableType.VARIABLE) cls.name2variable[cls.TIME_CONSTANT] = symbol return
def __register_integrated_odes_function(cls): """ Registers the integrate-odes function. """ params = list() symbol = FunctionSymbol(name=cls.INTEGRATE_ODES, param_types=params, return_type=PredefinedTypes.get_void_type(), element_reference=None, is_predefined=True) cls.name2function[cls.INTEGRATE_ODES] = symbol
def inverse_of_unit(cls, other): """ :param other: the unit to invert :type other: unit_type_symbol :return: UnitTypeSymbol """ from pynestml.symbols.predefined_types import PredefinedTypes result = PredefinedTypes.get_type(1 / other.astropy_unit) return result