From 4656e3b448b057ecf91eecd1b36e7a6f05d89a3a Mon Sep 17 00:00:00 2001 From: "C.A.P. Linssen" Date: Thu, 28 Nov 2024 02:24:10 +0100 Subject: [PATCH] clean up NESTML grammar definition --- ...user_defined_function_correctly_defined.py | 14 +- .../codegeneration/printers/model_printer.py | 8 +- .../codegeneration/printers/nestml_printer.py | 89 +- .../point_neuron/common/NeuronClass.jinja2 | 16 +- .../common/SynapseHeader.h.jinja2 | 28 +- .../directives_cpp/ForStatement.jinja2 | 8 +- .../directives_cpp/IfStatement.jinja2 | 12 +- .../{Block.jinja2 => StmtsBody.jinja2} | 4 +- .../directives_cpp/WhileStatement.jinja2 | 8 +- ...cm_neuroncurrents_@NEURON_NAME@.cpp.jinja2 | 16 +- .../point_neuron/@NEURON_NAME@.py.jinja2 | 16 +- .../directives_py/ForStatement.jinja2 | 4 +- .../directives_py/IfStatement.jinja2 | 12 +- .../directives_py/WhileStatement.jinja2 | 4 +- .../@NEURON_NAME@_impl.h.jinja2 | 4 +- .../@SYNAPSE_NAME@_impl.c.jinja2 | 8 +- pynestml/generated/PyNestMLLexer.py | 4 +- pynestml/generated/PyNestMLLexerBase.py | 9 +- pynestml/generated/PyNestMLParser.py | 1206 ++++++++++------- pynestml/generated/PyNestMLParserVisitor.py | 10 +- pynestml/grammars/PyNestMLLexer.g4 | 42 +- pynestml/grammars/PyNestMLParser.g4 | 226 +-- pynestml/meta_model/ast_elif_clause.py | 44 +- pynestml/meta_model/ast_else_clause.py | 37 +- pynestml/meta_model/ast_for_stmt.py | 50 +- pynestml/meta_model/ast_function.py | 35 +- pynestml/meta_model/ast_if_clause.py | 40 +- pynestml/meta_model/ast_node_factory.py | 20 +- pynestml/meta_model/ast_on_condition_block.py | 24 +- pynestml/meta_model/ast_on_receive_block.py | 22 +- .../{ast_block.py => ast_stmts_body.py} | 24 +- pynestml/meta_model/ast_update_block.py | 43 +- pynestml/meta_model/ast_while_stmt.py | 34 +- .../synapse_post_neuron_transformer.py | 2 +- pynestml/utils/ast_utils.py | 24 +- pynestml/utils/model_parser.py | 35 +- ...ign_implicit_conversion_factors_visitor.py | 14 +- pynestml/visitors/ast_builder_visitor.py | 35 +- pynestml/visitors/ast_symbol_table_visitor.py | 20 +- pynestml/visitors/ast_visitor.py | 44 +- ...printer_test.py => test_nestml_printer.py} | 151 ++- tests/test_unit_system.py | 4 +- 42 files changed, 1307 insertions(+), 1143 deletions(-) rename pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/{Block.jinja2 => StmtsBody.jinja2} (72%) rename pynestml/meta_model/{ast_block.py => ast_stmts_body.py} (84%) rename tests/{nestml_printer_test.py => test_nestml_printer.py} (60%) diff --git a/pynestml/cocos/co_co_user_defined_function_correctly_defined.py b/pynestml/cocos/co_co_user_defined_function_correctly_defined.py index 50fb915bc..ec62a9ac4 100644 --- a/pynestml/cocos/co_co_user_defined_function_correctly_defined.py +++ b/pynestml/cocos/co_co_user_defined_function_correctly_defined.py @@ -61,10 +61,10 @@ def check_co_co(cls, _node=None): 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: + if symbol is not None and len(userDefinedFunction.get_stmts_body().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) + userDefinedFunction.get_stmts_body().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()): @@ -135,19 +135,19 @@ def __check_return_recursively(cls, type_symbol=None, stmts=None, ret_defined=Fa # otherwise it is a compound stmt, thus check recursively if stmt.is_if_stmt(): cls.__check_return_recursively(type_symbol, - stmt.get_if_stmt().get_if_clause().get_block().get_stmts(), + stmt.get_if_stmt().get_if_clause().get_stmts_body().get_stmts(), ret_defined) for else_ifs in stmt.get_if_stmt().get_elif_clauses(): - cls.__check_return_recursively(type_symbol, else_ifs.get_block().get_stmts(), ret_defined) + cls.__check_return_recursively(type_symbol, else_ifs.get_stmts_body().get_stmts(), ret_defined) if stmt.get_if_stmt().has_else_clause(): cls.__check_return_recursively(type_symbol, - stmt.get_if_stmt().get_else_clause().get_block().get_stmts(), + stmt.get_if_stmt().get_else_clause().get_stmts_body().get_stmts(), ret_defined) elif stmt.is_while_stmt(): - cls.__check_return_recursively(type_symbol, stmt.get_while_stmt().get_block().get_stmts(), + cls.__check_return_recursively(type_symbol, stmt.get_while_stmt().get_stmts_body().get_stmts(), ret_defined) elif stmt.is_for_stmt(): - cls.__check_return_recursively(type_symbol, stmt.get_for_stmt().get_block().get_stmts(), + cls.__check_return_recursively(type_symbol, stmt.get_for_stmt().get_stmts_body().get_stmts(), ret_defined) # now, if a return statement has not been defined in the corresponding higher level block, we have # to ensure that it is defined here diff --git a/pynestml/codegeneration/printers/model_printer.py b/pynestml/codegeneration/printers/model_printer.py index ab52c5569..b8b257dff 100644 --- a/pynestml/codegeneration/printers/model_printer.py +++ b/pynestml/codegeneration/printers/model_printer.py @@ -23,7 +23,7 @@ from pynestml.meta_model.ast_arithmetic_operator import ASTArithmeticOperator from pynestml.meta_model.ast_assignment import ASTAssignment from pynestml.meta_model.ast_bit_operator import ASTBitOperator -from pynestml.meta_model.ast_block import ASTBlock +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody from pynestml.meta_model.ast_block_with_variables import ASTBlockWithVariables from pynestml.meta_model.ast_compound_stmt import ASTCompoundStmt from pynestml.meta_model.ast_data_type import ASTDataType @@ -78,7 +78,7 @@ def print_assignment(self, node: ASTAssignment) -> str: def print_bit_operator(self, node: ASTBitOperator) -> str: raise Exception("Printer does not support printing this node type") - def print_block(self, node: ASTBlock) -> str: + def print_stmts_body(self, node: ASTStmtsBody) -> str: raise Exception("Printer does not support printing this node type") def print_block_with_variables(self, node: ASTBlockWithVariables) -> str: @@ -196,8 +196,8 @@ def print(self, node: ASTNode) -> str: if isinstance(node, ASTBitOperator): return self.print_bit_operator(node) - if isinstance(node, ASTBlock): - return self.print_block(node) + if isinstance(node, ASTStmtsBody): + return self.print_stmts_body(node) if isinstance(node, ASTBlockWithVariables): return self.print_block_with_variables(node) diff --git a/pynestml/codegeneration/printers/nestml_printer.py b/pynestml/codegeneration/printers/nestml_printer.py index 481fc9a6a..3703ed6c5 100644 --- a/pynestml/codegeneration/printers/nestml_printer.py +++ b/pynestml/codegeneration/printers/nestml_printer.py @@ -23,7 +23,7 @@ from pynestml.meta_model.ast_arithmetic_operator import ASTArithmeticOperator from pynestml.meta_model.ast_assignment import ASTAssignment from pynestml.meta_model.ast_bit_operator import ASTBitOperator -from pynestml.meta_model.ast_block import ASTBlock +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody from pynestml.meta_model.ast_block_with_variables import ASTBlockWithVariables from pynestml.meta_model.ast_comparison_operator import ASTComparisonOperator from pynestml.meta_model.ast_compound_stmt import ASTCompoundStmt @@ -76,10 +76,9 @@ def __init__(self): def print_model(self, node: ASTModel) -> str: ret = print_ml_comments(node.pre_comments, self.indent, False) - self.inc_indent() ret += "model " + node.get_name() + ":" + print_sl_comment(node.in_comment) ret += "\n" + self.print(node.get_body()) - self.dec_indent() + return ret def print_arithmetic_operator(celf, node: ASTArithmeticOperator) -> str: @@ -138,21 +137,17 @@ def print_bit_operator(self, node: ASTBitOperator) -> str: raise RuntimeError("Unknown bit operator") - def print_block(self, node: ASTBlock) -> str: + def print_stmts_body(self, node: ASTStmtsBody) -> str: ret = "" - self.inc_indent() for stmt in node.stmts: ret += self.print(stmt) - self.dec_indent() - return ret def print_block_with_variables(self, node: ASTBlockWithVariables) -> str: - temp_indent = self.indent - self.inc_indent() - ret = print_ml_comments(node.pre_comments, temp_indent, False) - ret += print_n_spaces(temp_indent) + ret = print_ml_comments(node.pre_comments, self.indent, False) + ret += print_n_spaces(self.indent) + if node.is_state: ret += "state" elif node.is_parameters: @@ -160,17 +155,26 @@ def print_block_with_variables(self, node: ASTBlockWithVariables) -> str: else: assert node.is_internals ret += "internals" + ret += ":" + print_sl_comment(node.in_comment) + "\n" + if node.get_declarations() is not None: + self.inc_indent() for decl in node.get_declarations(): ret += self.print(decl) - self.dec_indent() + + self.dec_indent() + return ret def print_model_body(self, node: ASTModelBody) -> str: + self.inc_indent() ret = "" for elem in node.body_elements: ret += self.print(elem) + + self.dec_indent() + return ret def print_comparison_operator(self, node: ASTComparisonOperator) -> str: @@ -257,11 +261,20 @@ def print_declaration(self, node: ASTDeclaration) -> str: return ret def print_elif_clause(self, node: ASTElifClause) -> str: - return (print_n_spaces(self.indent) + "elif " + self.print(node.get_condition()) - + ":\n" + self.print(node.get_block())) + ret = print_n_spaces(self.indent) + "elif " + self.print(node.get_condition()) + ":\n" + self.inc_indent() + ret += self.print(node.get_stmts_body()) + self.dec_indent() + + return ret def print_else_clause(self, node: ASTElseClause) -> str: - return print_n_spaces(self.indent) + "else:\n" + self.print(node.get_block()) + ret = print_n_spaces(self.indent) + "else:\n" + self.inc_indent() + ret += self.print(node.get_stmts_body()) + self.dec_indent() + + return ret def print_equations_block(self, node: ASTEquationsBlock) -> str: temp_indent = self.indent @@ -301,12 +314,14 @@ def print_for_stmt(self, node: ASTForStmt) -> str: ret += ("for " + node.get_variable() + " in " + self.print(node.get_start_from()) + "..." + self.print(node.get_end_at()) + " step " + str(node.get_step()) + ":" + print_sl_comment(node.in_comment) + "\n") - ret += self.print(node.get_block()) + self.inc_indent() + ret += self.print(node.get_stmts_body()) + self.dec_indent() return ret def print_function(self, node: ASTFunction) -> str: ret = print_ml_comments(node.pre_comments, self.indent) - ret += "function " + node.get_name() + "(" + ret += print_n_spaces(self.indent) + "function " + node.get_name() + "(" if node.has_parameters(): for par in node.get_parameters(): ret += self.print(par) @@ -314,7 +329,10 @@ def print_function(self, node: ASTFunction) -> str: if node.has_return_type(): ret += " " + self.print(node.get_return_type()) ret += ":" + print_sl_comment(node.in_comment) + "\n" - ret += self.print(node.get_block()) + "\n" + self.inc_indent() + ret += self.print(node.get_stmts_body()) + "\n" + self.dec_indent() + return ret def print_function_call(self, node: ASTFunctionCall) -> str: @@ -323,14 +341,19 @@ def print_function_call(self, node: ASTFunctionCall) -> str: ret += self.print(node.get_args()[i]) if i < len(node.get_args()) - 1: # in the case that it is not the last arg, print also a comma ret += "," + ret += ")" + return ret def print_if_clause(self, node: ASTIfClause) -> str: ret = print_ml_comments(node.pre_comments, self.indent) ret += print_n_spaces(self.indent) + "if " + self.print(node.get_condition()) + ":" ret += print_sl_comment(node.in_comment) + "\n" - ret += self.print(node.get_block()) + self.inc_indent() + ret += self.print(node.get_stmts_body()) + self.dec_indent() + return ret def print_if_stmt(self, node: ASTIfStmt) -> str: @@ -341,6 +364,7 @@ def print_if_stmt(self, node: ASTIfStmt) -> str: if node.get_else_clause() is not None: ret += self.print(node.get_else_clause()) ret += print_n_spaces(self.indent) + "\n" + return ret def print_input_block(self, node: ASTInputBlock) -> str: @@ -519,31 +543,39 @@ def print_unit_type(self, node: ASTUnitType) -> str: return self.print(node.base) + "**" + str(node.exponent) if node.is_arithmetic_expression(): - t_lhs = ( - self.print(node.get_lhs()) if isinstance(node.get_lhs(), ASTUnitType) else str(node.get_lhs())) + t_lhs = self.print(node.get_lhs()) if isinstance(node.get_lhs(), ASTUnitType) else str(node.get_lhs()) if node.is_times: return t_lhs + "*" + self.print(node.get_rhs()) - else: - return t_lhs + "/" + self.print(node.get_rhs()) + + return t_lhs + "/" + self.print(node.get_rhs()) return node.unit def print_on_receive_block(self, node: ASTOnReceiveBlock) -> str: ret = print_ml_comments(node.pre_comments, self.indent, False) ret += print_n_spaces(self.indent) + "onReceive(" + node.port_name + "):" + print_sl_comment(node.in_comment) + "\n" - ret += self.print(node.get_block()) + self.inc_indent() + ret += self.print(node.get_stmts_body()) + self.dec_indent() + return ret def print_on_condition_block(self, node: ASTOnConditionBlock) -> str: ret = print_ml_comments(node.pre_comments, self.indent, False) ret += print_n_spaces(self.indent) + "onCondition(" + self.print(node.get_cond_expr()) + "):" + print_sl_comment(node.in_comment) + "\n" - ret += self.print(node.get_block()) + self.inc_indent() + ret += self.print(node.get_stmts_body()) + self.dec_indent() + return ret def print_update_block(self, node: ASTUpdateBlock): ret = print_ml_comments(node.pre_comments, self.indent, False) ret += print_n_spaces(self.indent) + "update:" + print_sl_comment(node.in_comment) + "\n" - ret += self.print(node.get_block()) + self.inc_indent() + ret += self.print(node.get_stmts_body()) + self.dec_indent() + return ret def print_variable(self, node: ASTVariable): @@ -561,7 +593,10 @@ def print_while_stmt(self, node: ASTWhileStmt) -> str: ret = print_ml_comments(node.pre_comments, self.indent, False) ret += (print_n_spaces(self.indent) + "while " + self.print(node.get_condition()) + ":" + print_sl_comment(node.in_comment) + "\n") - ret += self.print(node.get_block()) + self.inc_indent() + ret += self.print(node.get_stmts_body()) + self.dec_indent() + return ret def inc_indent(self): diff --git a/pynestml/codegeneration/resources_nest/point_neuron/common/NeuronClass.jinja2 b/pynestml/codegeneration/resources_nest/point_neuron/common/NeuronClass.jinja2 index a4253ce90..8cc3dd0dc 100644 --- a/pynestml/codegeneration/resources_nest/point_neuron/common/NeuronClass.jinja2 +++ b/pynestml/codegeneration/resources_nest/point_neuron/common/NeuronClass.jinja2 @@ -588,8 +588,8 @@ void {{ neuronName }}::pre_run_hook() {{ function_declaration.FunctionDeclaration(function, neuronName + "::") }} { {%- filter indent(2,True) %} -{%- with ast = function.get_block() %} -{%- include "directives_cpp/Block.jinja2" %} +{%- with ast = function.get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endwith %} {%- endfilter %} } @@ -782,13 +782,13 @@ void {{ neuronName }}::update(nest::Time const & origin, const long from, const {% if neuron.get_update_blocks() %} {%- filter indent(2) %} {%- for block in neuron.get_update_blocks() %} -{%- set ast = block.get_block() %} +{%- set ast = block.get_stmts_body() %} {%- if ast.print_comment('*')|length > 1 %} /* {{ast.print_comment('*')}} */ {%- endif %} -{%- include "directives_cpp/Block.jinja2" %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endfor %} {%- endfilter %} {%- endif %} @@ -853,14 +853,14 @@ void {{ neuronName }}::update(nest::Time const & origin, const long from, const {%- for block in neuron.get_on_condition_blocks() %} if ({{ printer.print(block.get_cond_expr()) }}) { -{%- set ast = block.get_block() %} +{%- set ast = block.get_stmts_body() %} {%- if ast.print_comment('*') | length > 1 %} /* {{ast.print_comment('*')}} */ {%- endif %} {%- filter indent(6) %} -{%- include "directives_cpp/Block.jinja2" %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endfilter %} } {%- endfor %} @@ -1141,14 +1141,14 @@ void {{ neuronName }}::handle(nest::CurrentEvent& e) // ------------------------------------------------------------------------- {%- for blk in neuron.get_on_receive_blocks() %} -{%- set ast = blk.get_block() %} +{%- set ast = blk.get_stmts_body() %} void {{ neuronName }}::on_receive_block_{{ blk.get_port_name() }}() { const double __timestep = nest::Time::get_resolution().get_ms(); // do not remove, this is necessary for the timestep() function {%- filter indent(2, True) -%} -{%- include "directives_cpp/Block.jinja2" %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endfilter %} } diff --git a/pynestml/codegeneration/resources_nest/point_neuron/common/SynapseHeader.h.jinja2 b/pynestml/codegeneration/resources_nest/point_neuron/common/SynapseHeader.h.jinja2 index 86cd059a0..de4e2f85b 100644 --- a/pynestml/codegeneration/resources_nest/point_neuron/common/SynapseHeader.h.jinja2 +++ b/pynestml/codegeneration/resources_nest/point_neuron/common/SynapseHeader.h.jinja2 @@ -851,8 +851,8 @@ void get_entry_from_continuous_variable_history(double t, **/ {% if synapse.get_on_receive_block(post_port) %} {%- set dynamics = synapse.get_on_receive_block(post_port) %} -{%- with ast = dynamics.get_block() %} -{%- include "directives_cpp/Block.jinja2" %} +{%- with ast = dynamics.get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endwith %} {%- endif %} {%- endfor %} @@ -903,9 +903,9 @@ void get_entry_from_continuous_variable_history(double t, **/ {% if synapse.get_on_receive_block(pre_port) %} {%- set dynamics = synapse.get_on_receive_block(pre_port) %} -{%- with ast = dynamics.get_block() %} +{%- with ast = dynamics.get_stmts_body() %} {%- filter indent(6, True) %} -{%- include "directives_cpp/Block.jinja2" %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endfilter %} {%- endwith %} {%- endif %} @@ -951,8 +951,8 @@ void get_entry_from_continuous_variable_history(double t, **/ {%- if synapse.get_on_receive_block(post_port) %} {%- set dynamics = synapse.get_on_receive_block(post_port) %} -{%- with ast = dynamics.get_block() %} -{%- include "directives_cpp/Block.jinja2" %} +{%- with ast = dynamics.get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endwith %} {%- endif %} {%- endfor %} @@ -1027,8 +1027,8 @@ void {%- filter indent(4, True) %} {%- set dynamics = synapse.get_on_receive_block(vt_port) %} -{%- with ast = dynamics.get_block() %} -{%- include "directives_cpp/Block.jinja2" %} +{%- with ast = dynamics.get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endwith %} {%- endfilter %} // process remaining dopa spikes in (t0, t1] @@ -1047,8 +1047,8 @@ void **/ {%- filter indent(6, True) %} {%- set dynamics = synapse.get_on_receive_block(vt_port) %} -{%- with ast = dynamics.get_block() %} -{%- include "directives_cpp/Block.jinja2" %} +{%- with ast = dynamics.get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endwith %} {%- endfilter %} @@ -1325,13 +1325,13 @@ inline void {%- if synapse.get_update_blocks() %} {%- filter indent(2) %} {%- for block in synapse.get_update_blocks() %} -{%- set ast = block.get_block() %} +{%- set ast = block.get_stmts_body() %} {%- if ast.print_comment('*')|length > 1 %} /* {{ast.print_comment('*')}} */ {%- endif %} -{%- include "directives_cpp/Block.jinja2" %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endfor %} {%- endfilter %} {%- endif %} @@ -1410,8 +1410,8 @@ inline void **/ {%- set dynamics = synapse.get_on_receive_block(post_port) %} -{%- with ast = dynamics.get_block() %} -{%- include "directives_cpp/Block.jinja2" %} +{%- with ast = dynamics.get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endwith %} {%- endfor %} {%- endif %} diff --git a/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/ForStatement.jinja2 b/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/ForStatement.jinja2 index f5c32841b..53fd412a5 100644 --- a/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/ForStatement.jinja2 +++ b/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/ForStatement.jinja2 @@ -14,7 +14,9 @@ for ( {{ ast.get_variable() }} = {{ printer.print(ast.get_start_from()) }}; {%- endif -%} {{ printer.print(ast.get_end_at()) }}; {{ ast.get_variable() }} += {{ ast.get_step() }} ) { -{%- with ast = ast.get_block() %} -{%- include "directives_cpp/Block.jinja2" %} -{%- endwith %} +{%- filter indent(2) %} +{%- with ast = ast.get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} +{%- endwith %} +{%- endfilter %} } diff --git a/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/IfStatement.jinja2 b/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/IfStatement.jinja2 index 137f10cf0..cf4a45608 100644 --- a/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/IfStatement.jinja2 +++ b/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/IfStatement.jinja2 @@ -6,8 +6,8 @@ if ({{ printer.print(ast.get_if_clause().get_condition()) }}) { {%- filter indent(2, True) %} -{%- with ast = ast.get_if_clause().get_block() %} -{%- include "directives_cpp/Block.jinja2" %} +{%- with ast = ast.get_if_clause().get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endwith %} {%- endfilter %} {%- for elif in ast.get_elif_clauses() %} @@ -15,8 +15,8 @@ if ({{ printer.print(ast.get_if_clause().get_condition()) }}) else if ({{ printer.print(elif.get_condition()) }}) { {%- filter indent(2, True) %} -{%- with ast = elif.get_block() %} -{%- include "directives_cpp/Block.jinja2" %} +{%- with ast = elif.get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endwith %} {%- endfilter %} {%- endfor %} @@ -25,8 +25,8 @@ else if ({{ printer.print(elif.get_condition()) }}) else { {%- filter indent(2, True) %} -{%- with ast = ast.get_else_clause().get_block() %} -{%- include "directives_cpp/Block.jinja2" %} +{%- with ast = ast.get_else_clause().get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endwith %} {%- endfilter %} {%- endif %} diff --git a/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/Block.jinja2 b/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/StmtsBody.jinja2 similarity index 72% rename from pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/Block.jinja2 rename to pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/StmtsBody.jinja2 index 61ea653c0..dc1419aaf 100644 --- a/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/Block.jinja2 +++ b/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/StmtsBody.jinja2 @@ -1,7 +1,5 @@ {# - Handles a complex block statement - @grammar: Block = ( Stmt | NEWLINE )*; - @param ast ASTBlock + Handles an ASTStmtsBody #} {%- if tracing %}/* generated by {{self._TemplateReference__context.name}} */ {% endif %} {%- for statement in ast.get_stmts() %} diff --git a/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/WhileStatement.jinja2 b/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/WhileStatement.jinja2 index 0606b5f87..ef171ac81 100644 --- a/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/WhileStatement.jinja2 +++ b/pynestml/codegeneration/resources_nest/point_neuron/directives_cpp/WhileStatement.jinja2 @@ -5,7 +5,9 @@ {%- if tracing %}/* generated by {{self._TemplateReference__context.name}} */ {% endif %} while ( {{ printer.print(ast.get_condition()) }}) { -{%- with ast = ast.get_block() %} -{%- include "directives_cpp/Block.jinja2" %} -{%- endwith %} +{%- filter indent(2) %} +{%- with ast = ast.get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} +{%- endwith %} +{%- endfilter %} } diff --git a/pynestml/codegeneration/resources_nest_compartmental/cm_neuron/cm_neuroncurrents_@NEURON_NAME@.cpp.jinja2 b/pynestml/codegeneration/resources_nest_compartmental/cm_neuron/cm_neuroncurrents_@NEURON_NAME@.cpp.jinja2 index fdf83b974..3cc3e4730 100644 --- a/pynestml/codegeneration/resources_nest_compartmental/cm_neuron/cm_neuroncurrents_@NEURON_NAME@.cpp.jinja2 +++ b/pynestml/codegeneration/resources_nest_compartmental/cm_neuron/cm_neuroncurrents_@NEURON_NAME@.cpp.jinja2 @@ -85,8 +85,8 @@ along with NEST. If not, see . inline {{ function_declaration.FunctionDeclaration(function, "nest::"~ion_channel_name~cm_unique_suffix~"::") }} { {%- filter indent(2,True) %} -{%- with ast = function.get_block() %} -{%- include "directives_cpp/Block.jinja2" %} +{%- with ast = function.get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endwith %} {%- endfilter %} } @@ -98,8 +98,8 @@ inline {{ function_declaration.FunctionDeclaration(function, "nest::"~ion_channe {{ vectorized_function_declaration.FunctionDeclaration(function, "nest::"~ion_channel_name~cm_unique_suffix~"::") }} { {%- filter indent(2,True) %} -{%- with ast = function.get_block() %} -{%- include "directives_cpp/VectorizedBlock.jinja2" %} +{%- with ast = function.get_stmts_body() %} +{%- include "directives_cpp/VectorizedStmtsBody.jinja2" %} {%- endwith %} {%- endfilter %} } @@ -799,8 +799,8 @@ std::pair< std::vector< double >, std::vector< double > > nest::{{synapse_name}} inline {{ function_declaration.FunctionDeclaration(function, "nest::"~synapse_name~cm_unique_suffix~"::") }} { {%- filter indent(2,True) %} -{%- with ast = function.get_block() %} -{%- include "directives/Block.jinja2" %} +{%- with ast = function.get_stmts_body() %} +{%- include "directives/StmtsBody.jinja2" %} {%- endwith %} {%- endfilter %} } @@ -1002,8 +1002,8 @@ std::pair< std::vector< double >, std::vector< double > > nest::{{continuous_nam inline {{ function_declaration.FunctionDeclaration(function, "nest::"~continuous_name~cm_unique_suffix~"::") }} { {%- filter indent(2,True) %} -{%- with ast = function.get_block() %} -{%- include "directives/Block.jinja2" %} +{%- with ast = function.get_stmts_body() %} +{%- include "directives/StmtsBody.jinja2" %} {%- endwith %} {%- endfilter %} } diff --git a/pynestml/codegeneration/resources_python_standalone/point_neuron/@NEURON_NAME@.py.jinja2 b/pynestml/codegeneration/resources_python_standalone/point_neuron/@NEURON_NAME@.py.jinja2 index 9e3d1e404..a54f210ba 100644 --- a/pynestml/codegeneration/resources_python_standalone/point_neuron/@NEURON_NAME@.py.jinja2 +++ b/pynestml/codegeneration/resources_python_standalone/point_neuron/@NEURON_NAME@.py.jinja2 @@ -208,8 +208,8 @@ class Neuron_{{neuronName}}(Neuron): {% for function in neuron.get_functions() -%} {{ function_declaration.FunctionDeclaration(function, neuronName) }}: {%- filter indent(4,True) %} -{%- with ast = function.get_block() %} -{%- include "directives_py/Block.jinja2" %} +{%- with ast = function.get_stmts_body() %} +{%- include "directives_py/StmtsBody.jinja2" %} {%- endwith %} {%- endfilter %} {%- endfor %} @@ -300,8 +300,8 @@ class Neuron_{{neuronName}}(Neuron): {% if neuron.get_update_blocks()|length > 0 %} {%- filter indent(4) %} {%- for dynamics in neuron.get_update_blocks() %} -{%- set ast = dynamics.get_block() %} -{%- include "directives_py/Block.jinja2" %} +{%- set ast = dynamics.get_stmts_body() %} +{%- include "directives_py/StmtsBody.jinja2" %} {%- endfor %} {%- endfilter %} {%- endif %} @@ -346,12 +346,12 @@ class Neuron_{{neuronName}}(Neuron): # ------------------------------------------------------------------------- {%- for block in neuron.get_on_condition_blocks() %} if {{ printer.print(block.get_cond_expr()) }}: -{%- set ast = block.get_block() %} +{%- set ast = block.get_stmts_body() %} {%- if ast.print_comment('#') | length > 1 %} # {{ast.print_comment('#')}} {%- endif %} {%- filter indent(6) %} -{%- include "directives_py/Block.jinja2" %} +{%- include "directives_py/StmtsBody.jinja2" %} {%- endfilter %} {%- endfor %} @@ -383,9 +383,9 @@ class Neuron_{{neuronName}}(Neuron): # ------------------------------------------------------------------------- {%- for blk in neuron.get_on_receive_blocks() %} -{%- set ast = blk.get_block() %} +{%- set ast = blk.get_stmts_body() %} def on_receive_block_{{ blk.get_port_name() }}(self): {%- filter indent(4, True) -%} -{%- include "directives_py/Block.jinja2" %} +{%- include "directives_py/StmtsBody.jinja2" %} {%- endfilter %} {% endfor %} diff --git a/pynestml/codegeneration/resources_python_standalone/point_neuron/directives_py/ForStatement.jinja2 b/pynestml/codegeneration/resources_python_standalone/point_neuron/directives_py/ForStatement.jinja2 index d3509ade5..262038f16 100644 --- a/pynestml/codegeneration/resources_python_standalone/point_neuron/directives_py/ForStatement.jinja2 +++ b/pynestml/codegeneration/resources_python_standalone/point_neuron/directives_py/ForStatement.jinja2 @@ -6,8 +6,8 @@ for {{ ast.get_variable() }} in range({{ printer.print(ast.get_start_from()) }}, {{ printer.print(ast.get_end_at()) }}): {%- filter indent(2) %} -{%- with ast = ast.get_block() %} -{%- include "directives_py/Block.jinja2" %} +{%- with ast = ast.get_stmts_body() %} +{%- include "directives_py/StmtsBody.jinja2" %} {%- endwith %} {%- endfilter %} {{ ast.get_variable() }} += {{ ast.get_step() }} diff --git a/pynestml/codegeneration/resources_python_standalone/point_neuron/directives_py/IfStatement.jinja2 b/pynestml/codegeneration/resources_python_standalone/point_neuron/directives_py/IfStatement.jinja2 index 89634dd9d..baf9ee70e 100644 --- a/pynestml/codegeneration/resources_python_standalone/point_neuron/directives_py/IfStatement.jinja2 +++ b/pynestml/codegeneration/resources_python_standalone/point_neuron/directives_py/IfStatement.jinja2 @@ -5,20 +5,20 @@ {%- if tracing %}# generated by {{self._TemplateReference__context.name}} {% endif %} if {{ printer.print(ast.get_if_clause().get_condition()) }}: {%- filter indent(2) %} -{%- set ast = ast.get_if_clause().get_block() %} -{%- include "directives_py/Block.jinja2" %} +{%- set ast = ast.get_if_clause().get_stmts_body() %} +{%- include "directives_py/StmtsBody.jinja2" %} {%- endfilter %} {%- for elif in ast.get_elif_clauses() %} elif {{ printer.print(elif.get_condition()) }}: {%- filter indent(2) %} -{%- set ast = elif.get_block() %} -{%- include "directives_py/Block.jinja2" %} +{%- set ast = elif.get_stmts_body() %} +{%- include "directives_py/StmtsBody.jinja2" %} {%- endfilter %} {%- endfor %} {%- if ast.has_else_clause() %} else: {%- filter indent(2) %} -{%- set ast = ast.get_else_clause().get_block() %} -{%- include "directives_py/Block.jinja2" %} +{%- set ast = ast.get_else_clause().get_stmts_body() %} +{%- include "directives_py/StmtsBody.jinja2" %} {%- endfilter %} {%- endif %} diff --git a/pynestml/codegeneration/resources_python_standalone/point_neuron/directives_py/WhileStatement.jinja2 b/pynestml/codegeneration/resources_python_standalone/point_neuron/directives_py/WhileStatement.jinja2 index 50970cc29..324769f8b 100644 --- a/pynestml/codegeneration/resources_python_standalone/point_neuron/directives_py/WhileStatement.jinja2 +++ b/pynestml/codegeneration/resources_python_standalone/point_neuron/directives_py/WhileStatement.jinja2 @@ -5,6 +5,6 @@ {%- if tracing %}# generated by {{self._TemplateReference__context.name}}{% endif %} while {{ printer.print(ast.get_condition()) }}: {%- filter indent(2) %} -{%- set ast = ast.get_block() %} -{%- include "directives_py/Block.jinja2" %} +{%- set ast = ast.get_stmts_body() %} +{%- include "directives_py/StmtsBody.jinja2" %} {%- endfilter %} diff --git a/pynestml/codegeneration/resources_spinnaker/@NEURON_NAME@_impl.h.jinja2 b/pynestml/codegeneration/resources_spinnaker/@NEURON_NAME@_impl.h.jinja2 index 891c888dd..c1bacaa7c 100644 --- a/pynestml/codegeneration/resources_spinnaker/@NEURON_NAME@_impl.h.jinja2 +++ b/pynestml/codegeneration/resources_spinnaker/@NEURON_NAME@_impl.h.jinja2 @@ -230,13 +230,13 @@ static void neuron_impl_do_timestep_update( {%- if neuron.get_update_blocks() %} {%- filter indent(8) %} {%- for block in neuron.get_update_blocks() %} -{%- set ast = block.get_block() %} +{%- set ast = block.get_stmts_body() %} {%- if ast.print_comment('*')|length > 1 %} /* {{ast.print_comment('*')}} */ {%- endif %} -{%- include "directives_cpp/Block.jinja2" %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endfor %} {%- endfilter %} {%- endif %} diff --git a/pynestml/codegeneration/resources_spinnaker/@SYNAPSE_NAME@_impl.c.jinja2 b/pynestml/codegeneration/resources_spinnaker/@SYNAPSE_NAME@_impl.c.jinja2 index e7fe320a3..a36f0d12c 100644 --- a/pynestml/codegeneration/resources_spinnaker/@SYNAPSE_NAME@_impl.c.jinja2 +++ b/pynestml/codegeneration/resources_spinnaker/@SYNAPSE_NAME@_impl.c.jinja2 @@ -189,8 +189,8 @@ static inline update_state_t timing_apply_post_spike( // {%- set dynamics = synapse.get_on_receive_block(post_port) %} -{%- with ast = dynamics.get_block() %} -{%- include "directives_cpp/Block.jinja2" %} +{%- with ast = dynamics.get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endwith %} {%- endfor %} {%- endif %} @@ -224,8 +224,8 @@ static inline update_state_t timing_apply_pre_spike( // {%- set dynamics = synapse.get_on_receive_block(pre_port) %} -{%- with ast = dynamics.get_block() %} -{%- include "directives_cpp/Block.jinja2" %} +{%- with ast = dynamics.get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} {%- endwith %} {%- endfor %} {%- endfilter %} diff --git a/pynestml/generated/PyNestMLLexer.py b/pynestml/generated/PyNestMLLexer.py index fe99b1dd7..426cb4ae6 100644 --- a/pynestml/generated/PyNestMLLexer.py +++ b/pynestml/generated/PyNestMLLexer.py @@ -461,7 +461,7 @@ def action(self, localctx:RuleContext, ruleIndex:int, actionIndex:int): def NEWLINE_action(self, localctx:RuleContext , actionIndex:int): if actionIndex == 0: - self.onNewLine() + self.onNewLine() def sempred(self, localctx:RuleContext, ruleIndex:int, predIndex:int): @@ -477,7 +477,7 @@ def sempred(self, localctx:RuleContext, ruleIndex:int, predIndex:int): def NEWLINE_sempred(self, localctx:RuleContext, predIndex:int): if predIndex == 0: - return self.atStartOfInput() + return self.atStartOfInput() diff --git a/pynestml/generated/PyNestMLLexerBase.py b/pynestml/generated/PyNestMLLexerBase.py index 8480f5354..f8509be4d 100644 --- a/pynestml/generated/PyNestMLLexerBase.py +++ b/pynestml/generated/PyNestMLLexerBase.py @@ -18,13 +18,14 @@ # # You should have received a copy of the GNU General Public License # along with NEST. If not, see . -from typing import TextIO -from antlr4 import * -from antlr4.Token import CommonToken -import sys from typing import TextIO + import re +import sys + +from antlr4 import * +from antlr4.Token import CommonToken from pynestml.generated.PyNestMLParser import PyNestMLParser diff --git a/pynestml/generated/PyNestMLParser.py b/pynestml/generated/PyNestMLParser.py index 2c51de196..a15b7af49 100644 --- a/pynestml/generated/PyNestMLParser.py +++ b/pynestml/generated/PyNestMLParser.py @@ -10,7 +10,7 @@ def serializedATN(): return [ - 4,1,91,628,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7, + 4,1,91,654,2,0,7,0,2,1,7,1,2,2,7,2,2,3,7,3,2,4,7,4,2,5,7,5,2,6,7, 6,2,7,7,7,2,8,7,8,2,9,7,9,2,10,7,10,2,11,7,11,2,12,7,12,2,13,7,13, 2,14,7,14,2,15,7,15,2,16,7,16,2,17,7,17,2,18,7,18,2,19,7,19,2,20, 7,20,2,21,7,21,2,22,7,22,2,23,7,23,2,24,7,24,2,25,7,25,2,26,7,26, @@ -33,63 +33,65 @@ def serializedATN(): 11,1,11,1,12,1,12,1,12,1,12,3,12,271,8,12,1,12,5,12,274,8,12,10, 12,12,12,277,9,12,1,12,1,12,1,13,1,13,1,13,1,13,1,13,1,13,1,13,1, 13,1,13,5,13,290,8,13,10,13,12,13,293,9,13,1,13,3,13,296,8,13,1, - 13,1,13,1,14,1,14,1,14,4,14,303,8,14,11,14,12,14,304,1,14,1,14,1, - 15,1,15,3,15,311,8,15,1,16,1,16,1,16,3,16,316,8,16,1,17,1,17,1,17, - 1,17,3,17,322,8,17,1,17,1,17,1,18,1,18,1,18,1,18,1,18,1,18,3,18, - 332,8,18,1,18,1,18,1,19,3,19,337,8,19,1,19,3,19,340,8,19,1,19,1, - 19,1,19,5,19,345,8,19,10,19,12,19,348,9,19,1,19,1,19,1,19,3,19,353, - 8,19,1,19,1,19,1,19,1,19,3,19,359,8,19,1,19,5,19,362,8,19,10,19, - 12,19,365,9,19,1,20,1,20,1,20,1,21,1,21,1,21,1,21,1,21,1,21,1,21, - 3,21,377,8,21,1,22,1,22,1,23,1,23,1,24,1,24,3,24,385,8,24,1,25,1, - 25,5,25,389,8,25,10,25,12,25,392,9,25,1,25,3,25,395,8,25,1,26,1, - 26,1,26,1,26,1,26,1,27,1,27,1,27,1,27,1,27,1,28,1,28,1,28,1,28,1, - 29,1,29,1,29,1,29,1,29,1,29,1,29,1,29,3,29,419,8,29,1,29,1,29,1, - 29,1,29,1,30,1,30,1,30,1,30,1,30,1,31,1,31,4,31,432,8,31,11,31,12, - 31,433,1,31,1,31,1,32,1,32,1,32,1,32,1,33,1,33,1,33,1,33,1,33,1, - 33,1,33,1,33,1,33,1,33,1,33,4,33,453,8,33,11,33,12,33,454,1,33,1, - 33,1,34,1,34,1,34,1,34,1,34,5,34,464,8,34,10,34,12,34,467,9,34,1, - 34,1,34,1,34,1,34,1,35,1,35,1,35,1,35,1,35,5,35,478,8,35,10,35,12, - 35,481,9,35,1,35,1,35,1,35,1,35,1,36,1,36,1,36,1,36,1,36,4,36,492, - 8,36,11,36,12,36,493,1,36,1,36,1,37,1,37,1,37,1,37,1,38,1,38,1,38, - 1,38,1,38,1,38,1,38,4,38,509,8,38,11,38,12,38,510,1,38,1,38,1,39, - 1,39,1,39,1,39,1,39,1,39,3,39,521,8,39,1,39,1,39,1,39,1,39,5,39, - 527,8,39,10,39,12,39,530,9,39,3,39,532,8,39,1,39,3,39,535,8,39,4, - 39,537,8,39,11,39,12,39,538,1,39,1,39,1,40,1,40,1,40,1,40,1,40,3, - 40,548,8,40,1,40,1,40,5,40,552,8,40,10,40,12,40,555,9,40,1,40,1, - 40,1,40,1,41,1,41,1,41,1,41,1,41,3,41,565,8,41,1,41,1,41,1,41,1, - 41,1,41,1,42,1,42,3,42,574,8,42,1,43,1,43,1,43,1,43,1,43,1,43,1, - 43,1,43,1,43,5,43,585,8,43,10,43,12,43,588,9,43,3,43,590,8,43,1, - 43,3,43,593,8,43,1,43,3,43,596,8,43,1,43,1,43,1,43,1,44,1,44,1,44, - 1,44,1,44,1,44,5,44,607,8,44,10,44,12,44,610,9,44,3,44,612,8,44, - 1,44,1,44,3,44,616,8,44,1,44,1,44,1,44,1,45,1,45,1,45,1,46,1,46, - 1,46,1,46,1,46,0,2,2,6,47,0,2,4,6,8,10,12,14,16,18,20,22,24,26,28, - 30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66,68,70,72, - 74,76,78,80,82,84,86,88,90,92,0,4,2,0,51,51,75,75,1,0,90,91,1,0, - 32,34,3,0,25,25,87,88,90,91,689,0,100,1,0,0,0,2,111,1,0,0,0,4,128, - 1,0,0,0,6,143,1,0,0,0,8,193,1,0,0,0,10,198,1,0,0,0,12,205,1,0,0, - 0,14,214,1,0,0,0,16,218,1,0,0,0,18,220,1,0,0,0,20,233,1,0,0,0,22, - 248,1,0,0,0,24,266,1,0,0,0,26,280,1,0,0,0,28,299,1,0,0,0,30,310, - 1,0,0,0,32,315,1,0,0,0,34,321,1,0,0,0,36,325,1,0,0,0,38,336,1,0, - 0,0,40,366,1,0,0,0,42,376,1,0,0,0,44,378,1,0,0,0,46,380,1,0,0,0, - 48,382,1,0,0,0,50,386,1,0,0,0,52,396,1,0,0,0,54,401,1,0,0,0,56,406, - 1,0,0,0,58,410,1,0,0,0,60,424,1,0,0,0,62,431,1,0,0,0,64,437,1,0, - 0,0,66,441,1,0,0,0,68,458,1,0,0,0,70,472,1,0,0,0,72,486,1,0,0,0, - 74,497,1,0,0,0,76,501,1,0,0,0,78,514,1,0,0,0,80,542,1,0,0,0,82,559, - 1,0,0,0,84,573,1,0,0,0,86,575,1,0,0,0,88,600,1,0,0,0,90,620,1,0, - 0,0,92,623,1,0,0,0,94,101,5,10,0,0,95,101,5,11,0,0,96,101,5,12,0, - 0,97,101,5,13,0,0,98,101,5,14,0,0,99,101,3,2,1,0,100,94,1,0,0,0, - 100,95,1,0,0,0,100,96,1,0,0,0,100,97,1,0,0,0,100,98,1,0,0,0,100, - 99,1,0,0,0,101,1,1,0,0,0,102,103,6,1,-1,0,103,104,5,49,0,0,104,105, - 3,2,1,0,105,106,5,50,0,0,106,112,1,0,0,0,107,108,5,90,0,0,108,109, - 5,79,0,0,109,112,3,2,1,2,110,112,5,89,0,0,111,102,1,0,0,0,111,107, - 1,0,0,0,111,110,1,0,0,0,112,124,1,0,0,0,113,116,10,3,0,0,114,117, - 5,77,0,0,115,117,5,79,0,0,116,114,1,0,0,0,116,115,1,0,0,0,117,118, - 1,0,0,0,118,123,3,2,1,4,119,120,10,4,0,0,120,121,5,78,0,0,121,123, - 3,4,2,0,122,113,1,0,0,0,122,119,1,0,0,0,123,126,1,0,0,0,124,122, - 1,0,0,0,124,125,1,0,0,0,125,3,1,0,0,0,126,124,1,0,0,0,127,129,7, - 0,0,0,128,127,1,0,0,0,128,129,1,0,0,0,129,130,1,0,0,0,130,131,5, - 90,0,0,131,5,1,0,0,0,132,133,6,3,-1,0,133,134,5,49,0,0,134,135,3, - 6,3,0,135,136,5,50,0,0,136,144,1,0,0,0,137,138,3,10,5,0,138,139, + 13,1,13,1,14,3,14,301,8,14,1,14,1,14,3,14,305,8,14,1,15,1,15,1,15, + 3,15,310,8,15,1,16,1,16,1,16,1,16,3,16,316,8,16,1,16,1,16,1,17,1, + 17,1,17,1,17,1,17,1,17,3,17,326,8,17,1,17,1,17,1,18,3,18,331,8,18, + 1,18,3,18,334,8,18,1,18,1,18,1,18,5,18,339,8,18,10,18,12,18,342, + 9,18,1,18,1,18,1,18,3,18,347,8,18,1,18,1,18,1,18,1,18,3,18,353,8, + 18,1,18,5,18,356,8,18,10,18,12,18,359,9,18,1,19,1,19,1,19,1,20,1, + 20,1,20,1,20,1,20,1,20,1,20,3,20,371,8,20,1,21,1,21,1,22,1,22,1, + 23,4,23,378,8,23,11,23,12,23,379,1,24,1,24,3,24,384,8,24,1,25,1, + 25,5,25,388,8,25,10,25,12,25,391,9,25,1,25,3,25,394,8,25,1,26,1, + 26,1,26,1,26,1,26,1,26,1,26,1,26,1,27,1,27,1,27,1,27,1,27,1,27,1, + 27,1,27,1,28,1,28,1,28,1,28,1,28,1,28,1,28,1,29,1,29,1,29,1,29,1, + 29,1,29,1,29,1,29,3,29,427,8,29,1,29,1,29,1,29,1,29,1,29,1,29,1, + 29,1,30,1,30,1,30,1,30,1,30,1,30,1,30,1,30,1,31,1,31,4,31,446,8, + 31,11,31,12,31,447,1,31,1,31,1,32,1,32,1,32,1,32,1,32,1,33,1,33, + 1,33,1,33,1,33,1,33,1,33,1,33,1,33,1,33,4,33,467,8,33,11,33,12,33, + 468,1,33,1,33,1,34,1,34,1,34,1,34,1,34,5,34,478,8,34,10,34,12,34, + 481,9,34,1,34,1,34,1,34,1,34,1,34,1,34,1,34,1,35,1,35,1,35,1,35, + 1,35,5,35,495,8,35,10,35,12,35,498,9,35,1,35,1,35,1,35,1,35,1,35, + 1,35,1,35,1,36,1,36,1,36,1,36,1,36,4,36,512,8,36,11,36,12,36,513, + 1,36,1,36,1,37,1,37,1,37,1,37,1,37,1,37,1,37,1,38,1,38,1,38,1,38, + 1,38,1,38,1,38,4,38,532,8,38,11,38,12,38,533,1,38,1,38,1,39,1,39, + 1,39,1,39,1,39,1,39,3,39,544,8,39,1,39,1,39,1,39,1,39,5,39,550,8, + 39,10,39,12,39,553,9,39,3,39,555,8,39,1,39,3,39,558,8,39,4,39,560, + 8,39,11,39,12,39,561,1,39,1,39,1,40,1,40,1,40,1,40,1,40,3,40,571, + 8,40,1,40,1,40,5,40,575,8,40,10,40,12,40,578,9,40,1,40,1,40,1,40, + 1,41,1,41,1,41,1,41,1,41,3,41,588,8,41,1,41,1,41,1,41,1,41,1,41, + 1,42,1,42,3,42,597,8,42,1,43,1,43,1,43,1,43,1,43,1,43,1,43,1,43, + 1,43,5,43,608,8,43,10,43,12,43,611,9,43,3,43,613,8,43,1,43,3,43, + 616,8,43,1,43,3,43,619,8,43,1,43,1,43,1,43,1,44,1,44,1,44,1,44,1, + 44,1,44,5,44,630,8,44,10,44,12,44,633,9,44,3,44,635,8,44,1,44,1, + 44,3,44,639,8,44,1,44,1,44,1,44,1,44,1,44,1,44,1,45,1,45,1,45,1, + 46,1,46,1,46,1,46,1,46,0,2,2,6,47,0,2,4,6,8,10,12,14,16,18,20,22, + 24,26,28,30,32,34,36,38,40,42,44,46,48,50,52,54,56,58,60,62,64,66, + 68,70,72,74,76,78,80,82,84,86,88,90,92,0,4,2,0,51,51,75,75,1,0,90, + 91,1,0,32,34,3,0,25,25,87,88,90,91,716,0,100,1,0,0,0,2,111,1,0,0, + 0,4,128,1,0,0,0,6,143,1,0,0,0,8,193,1,0,0,0,10,198,1,0,0,0,12,205, + 1,0,0,0,14,214,1,0,0,0,16,218,1,0,0,0,18,220,1,0,0,0,20,233,1,0, + 0,0,22,248,1,0,0,0,24,266,1,0,0,0,26,280,1,0,0,0,28,300,1,0,0,0, + 30,309,1,0,0,0,32,315,1,0,0,0,34,319,1,0,0,0,36,330,1,0,0,0,38,360, + 1,0,0,0,40,370,1,0,0,0,42,372,1,0,0,0,44,374,1,0,0,0,46,377,1,0, + 0,0,48,381,1,0,0,0,50,385,1,0,0,0,52,395,1,0,0,0,54,403,1,0,0,0, + 56,411,1,0,0,0,58,418,1,0,0,0,60,435,1,0,0,0,62,445,1,0,0,0,64,451, + 1,0,0,0,66,456,1,0,0,0,68,472,1,0,0,0,70,489,1,0,0,0,72,506,1,0, + 0,0,74,517,1,0,0,0,76,524,1,0,0,0,78,537,1,0,0,0,80,565,1,0,0,0, + 82,582,1,0,0,0,84,596,1,0,0,0,86,598,1,0,0,0,88,623,1,0,0,0,90,646, + 1,0,0,0,92,649,1,0,0,0,94,101,5,10,0,0,95,101,5,11,0,0,96,101,5, + 12,0,0,97,101,5,13,0,0,98,101,5,14,0,0,99,101,3,2,1,0,100,94,1,0, + 0,0,100,95,1,0,0,0,100,96,1,0,0,0,100,97,1,0,0,0,100,98,1,0,0,0, + 100,99,1,0,0,0,101,1,1,0,0,0,102,103,6,1,-1,0,103,104,5,49,0,0,104, + 105,3,2,1,0,105,106,5,50,0,0,106,112,1,0,0,0,107,108,5,90,0,0,108, + 109,5,79,0,0,109,112,3,2,1,2,110,112,5,89,0,0,111,102,1,0,0,0,111, + 107,1,0,0,0,111,110,1,0,0,0,112,124,1,0,0,0,113,116,10,3,0,0,114, + 117,5,77,0,0,115,117,5,79,0,0,116,114,1,0,0,0,116,115,1,0,0,0,117, + 118,1,0,0,0,118,123,3,2,1,4,119,120,10,4,0,0,120,121,5,78,0,0,121, + 123,3,4,2,0,122,113,1,0,0,0,122,119,1,0,0,0,123,126,1,0,0,0,124, + 122,1,0,0,0,124,125,1,0,0,0,125,3,1,0,0,0,126,124,1,0,0,0,127,129, + 7,0,0,0,128,127,1,0,0,0,128,129,1,0,0,0,129,130,1,0,0,0,130,131, + 5,90,0,0,131,5,1,0,0,0,132,133,6,3,-1,0,133,134,5,49,0,0,134,135, + 3,6,3,0,135,136,5,50,0,0,136,144,1,0,0,0,137,138,3,10,5,0,138,139, 3,6,3,9,139,144,1,0,0,0,140,141,5,28,0,0,141,144,3,6,3,4,142,144, 3,8,4,0,143,132,1,0,0,0,143,137,1,0,0,0,143,140,1,0,0,0,143,142, 1,0,0,0,144,181,1,0,0,0,145,146,10,10,0,0,146,147,5,78,0,0,147,180, @@ -129,119 +131,126 @@ def serializedATN(): 21,1,0,0,0,247,249,5,29,0,0,248,247,1,0,0,0,248,249,1,0,0,0,249, 250,1,0,0,0,250,251,5,16,0,0,251,252,5,89,0,0,252,253,3,0,0,0,253, 254,5,76,0,0,254,256,3,6,3,0,255,257,5,84,0,0,256,255,1,0,0,0,256, - 257,1,0,0,0,257,261,1,0,0,0,258,260,3,42,21,0,259,258,1,0,0,0,260, + 257,1,0,0,0,257,261,1,0,0,0,258,260,3,40,20,0,259,258,1,0,0,0,260, 263,1,0,0,0,261,259,1,0,0,0,261,262,1,0,0,0,262,264,1,0,0,0,263, 261,1,0,0,0,264,265,5,9,0,0,265,23,1,0,0,0,266,267,3,18,9,0,267, 268,5,76,0,0,268,270,3,6,3,0,269,271,5,84,0,0,270,269,1,0,0,0,270, - 271,1,0,0,0,271,275,1,0,0,0,272,274,3,42,21,0,273,272,1,0,0,0,274, + 271,1,0,0,0,271,275,1,0,0,0,272,274,3,40,20,0,273,272,1,0,0,0,274, 277,1,0,0,0,275,273,1,0,0,0,275,276,1,0,0,0,276,278,1,0,0,0,277, 275,1,0,0,0,278,279,5,9,0,0,279,25,1,0,0,0,280,281,5,30,0,0,281, 282,3,18,9,0,282,283,5,76,0,0,283,291,3,6,3,0,284,285,5,4,0,0,285, 286,3,18,9,0,286,287,5,76,0,0,287,288,3,6,3,0,288,290,1,0,0,0,289, 284,1,0,0,0,290,293,1,0,0,0,291,289,1,0,0,0,291,292,1,0,0,0,292, 295,1,0,0,0,293,291,1,0,0,0,294,296,5,84,0,0,295,294,1,0,0,0,295, - 296,1,0,0,0,296,297,1,0,0,0,297,298,5,9,0,0,298,27,1,0,0,0,299,300, - 5,9,0,0,300,302,5,1,0,0,301,303,3,30,15,0,302,301,1,0,0,0,303,304, - 1,0,0,0,304,302,1,0,0,0,304,305,1,0,0,0,305,306,1,0,0,0,306,307, - 5,2,0,0,307,29,1,0,0,0,308,311,3,34,17,0,309,311,3,32,16,0,310,308, - 1,0,0,0,310,309,1,0,0,0,311,31,1,0,0,0,312,316,3,50,25,0,313,316, - 3,58,29,0,314,316,3,60,30,0,315,312,1,0,0,0,315,313,1,0,0,0,315, - 314,1,0,0,0,316,33,1,0,0,0,317,322,3,36,18,0,318,322,3,20,10,0,319, - 322,3,38,19,0,320,322,3,48,24,0,321,317,1,0,0,0,321,318,1,0,0,0, - 321,319,1,0,0,0,321,320,1,0,0,0,322,323,1,0,0,0,323,324,5,9,0,0, - 324,35,1,0,0,0,325,331,3,18,9,0,326,332,5,76,0,0,327,332,5,66,0, - 0,328,332,5,67,0,0,329,332,5,68,0,0,330,332,5,69,0,0,331,326,1,0, - 0,0,331,327,1,0,0,0,331,328,1,0,0,0,331,329,1,0,0,0,331,330,1,0, - 0,0,332,333,1,0,0,0,333,334,3,6,3,0,334,37,1,0,0,0,335,337,5,29, - 0,0,336,335,1,0,0,0,336,337,1,0,0,0,337,339,1,0,0,0,338,340,5,16, - 0,0,339,338,1,0,0,0,339,340,1,0,0,0,340,341,1,0,0,0,341,346,3,18, - 9,0,342,343,5,74,0,0,343,345,3,18,9,0,344,342,1,0,0,0,345,348,1, - 0,0,0,346,344,1,0,0,0,346,347,1,0,0,0,347,349,1,0,0,0,348,346,1, - 0,0,0,349,352,3,0,0,0,350,351,5,76,0,0,351,353,3,6,3,0,352,350,1, - 0,0,0,352,353,1,0,0,0,353,358,1,0,0,0,354,355,5,59,0,0,355,356,3, - 6,3,0,356,357,5,60,0,0,357,359,1,0,0,0,358,354,1,0,0,0,358,359,1, - 0,0,0,359,363,1,0,0,0,360,362,3,42,21,0,361,360,1,0,0,0,362,365, - 1,0,0,0,363,361,1,0,0,0,363,364,1,0,0,0,364,39,1,0,0,0,365,363,1, - 0,0,0,366,367,3,38,19,0,367,368,5,9,0,0,368,41,1,0,0,0,369,377,5, - 45,0,0,370,377,5,46,0,0,371,372,5,47,0,0,372,373,3,44,22,0,373,374, - 5,83,0,0,374,375,3,46,23,0,375,377,1,0,0,0,376,369,1,0,0,0,376,370, - 1,0,0,0,376,371,1,0,0,0,377,43,1,0,0,0,378,379,5,89,0,0,379,45,1, - 0,0,0,380,381,5,89,0,0,381,47,1,0,0,0,382,384,5,17,0,0,383,385,3, - 6,3,0,384,383,1,0,0,0,384,385,1,0,0,0,385,49,1,0,0,0,386,390,3,52, - 26,0,387,389,3,54,27,0,388,387,1,0,0,0,389,392,1,0,0,0,390,388,1, - 0,0,0,390,391,1,0,0,0,391,394,1,0,0,0,392,390,1,0,0,0,393,395,3, - 56,28,0,394,393,1,0,0,0,394,395,1,0,0,0,395,51,1,0,0,0,396,397,5, - 18,0,0,397,398,3,6,3,0,398,399,5,82,0,0,399,400,3,28,14,0,400,53, - 1,0,0,0,401,402,5,19,0,0,402,403,3,6,3,0,403,404,5,82,0,0,404,405, - 3,28,14,0,405,55,1,0,0,0,406,407,5,20,0,0,407,408,5,82,0,0,408,409, - 3,28,14,0,409,57,1,0,0,0,410,411,5,21,0,0,411,412,5,89,0,0,412,413, - 5,23,0,0,413,414,3,6,3,0,414,415,5,48,0,0,415,416,3,6,3,0,416,418, - 5,24,0,0,417,419,5,75,0,0,418,417,1,0,0,0,418,419,1,0,0,0,419,420, - 1,0,0,0,420,421,7,1,0,0,421,422,5,82,0,0,422,423,3,28,14,0,423,59, - 1,0,0,0,424,425,5,22,0,0,425,426,3,6,3,0,426,427,5,82,0,0,427,428, - 3,28,14,0,428,61,1,0,0,0,429,432,3,64,32,0,430,432,5,9,0,0,431,429, - 1,0,0,0,431,430,1,0,0,0,432,433,1,0,0,0,433,431,1,0,0,0,433,434, - 1,0,0,0,434,435,1,0,0,0,435,436,5,0,0,1,436,63,1,0,0,0,437,438,5, - 31,0,0,438,439,5,89,0,0,439,440,3,66,33,0,440,65,1,0,0,0,441,442, - 5,82,0,0,442,443,5,9,0,0,443,452,5,1,0,0,444,453,3,72,36,0,445,453, - 3,76,38,0,446,453,3,78,39,0,447,453,3,86,43,0,448,453,3,88,44,0, - 449,453,3,68,34,0,450,453,3,70,35,0,451,453,3,74,37,0,452,444,1, - 0,0,0,452,445,1,0,0,0,452,446,1,0,0,0,452,447,1,0,0,0,452,448,1, - 0,0,0,452,449,1,0,0,0,452,450,1,0,0,0,452,451,1,0,0,0,453,454,1, - 0,0,0,454,452,1,0,0,0,454,455,1,0,0,0,455,456,1,0,0,0,456,457,5, - 2,0,0,457,67,1,0,0,0,458,459,5,40,0,0,459,460,5,49,0,0,460,465,5, - 89,0,0,461,462,5,74,0,0,462,464,3,92,46,0,463,461,1,0,0,0,464,467, - 1,0,0,0,465,463,1,0,0,0,465,466,1,0,0,0,466,468,1,0,0,0,467,465, - 1,0,0,0,468,469,5,50,0,0,469,470,5,82,0,0,470,471,3,28,14,0,471, - 69,1,0,0,0,472,473,5,41,0,0,473,474,5,49,0,0,474,479,3,6,3,0,475, + 296,1,0,0,0,296,297,1,0,0,0,297,298,5,9,0,0,298,27,1,0,0,0,299,301, + 5,9,0,0,300,299,1,0,0,0,300,301,1,0,0,0,301,304,1,0,0,0,302,305, + 3,32,16,0,303,305,3,30,15,0,304,302,1,0,0,0,304,303,1,0,0,0,305, + 29,1,0,0,0,306,310,3,50,25,0,307,310,3,58,29,0,308,310,3,60,30,0, + 309,306,1,0,0,0,309,307,1,0,0,0,309,308,1,0,0,0,310,31,1,0,0,0,311, + 316,3,34,17,0,312,316,3,20,10,0,313,316,3,36,18,0,314,316,3,48,24, + 0,315,311,1,0,0,0,315,312,1,0,0,0,315,313,1,0,0,0,315,314,1,0,0, + 0,316,317,1,0,0,0,317,318,5,9,0,0,318,33,1,0,0,0,319,325,3,18,9, + 0,320,326,5,76,0,0,321,326,5,66,0,0,322,326,5,67,0,0,323,326,5,68, + 0,0,324,326,5,69,0,0,325,320,1,0,0,0,325,321,1,0,0,0,325,322,1,0, + 0,0,325,323,1,0,0,0,325,324,1,0,0,0,326,327,1,0,0,0,327,328,3,6, + 3,0,328,35,1,0,0,0,329,331,5,29,0,0,330,329,1,0,0,0,330,331,1,0, + 0,0,331,333,1,0,0,0,332,334,5,16,0,0,333,332,1,0,0,0,333,334,1,0, + 0,0,334,335,1,0,0,0,335,340,3,18,9,0,336,337,5,74,0,0,337,339,3, + 18,9,0,338,336,1,0,0,0,339,342,1,0,0,0,340,338,1,0,0,0,340,341,1, + 0,0,0,341,343,1,0,0,0,342,340,1,0,0,0,343,346,3,0,0,0,344,345,5, + 76,0,0,345,347,3,6,3,0,346,344,1,0,0,0,346,347,1,0,0,0,347,352,1, + 0,0,0,348,349,5,59,0,0,349,350,3,6,3,0,350,351,5,60,0,0,351,353, + 1,0,0,0,352,348,1,0,0,0,352,353,1,0,0,0,353,357,1,0,0,0,354,356, + 3,40,20,0,355,354,1,0,0,0,356,359,1,0,0,0,357,355,1,0,0,0,357,358, + 1,0,0,0,358,37,1,0,0,0,359,357,1,0,0,0,360,361,3,36,18,0,361,362, + 5,9,0,0,362,39,1,0,0,0,363,371,5,45,0,0,364,371,5,46,0,0,365,366, + 5,47,0,0,366,367,3,42,21,0,367,368,5,83,0,0,368,369,3,44,22,0,369, + 371,1,0,0,0,370,363,1,0,0,0,370,364,1,0,0,0,370,365,1,0,0,0,371, + 41,1,0,0,0,372,373,5,89,0,0,373,43,1,0,0,0,374,375,5,89,0,0,375, + 45,1,0,0,0,376,378,3,28,14,0,377,376,1,0,0,0,378,379,1,0,0,0,379, + 377,1,0,0,0,379,380,1,0,0,0,380,47,1,0,0,0,381,383,5,17,0,0,382, + 384,3,6,3,0,383,382,1,0,0,0,383,384,1,0,0,0,384,49,1,0,0,0,385,389, + 3,52,26,0,386,388,3,54,27,0,387,386,1,0,0,0,388,391,1,0,0,0,389, + 387,1,0,0,0,389,390,1,0,0,0,390,393,1,0,0,0,391,389,1,0,0,0,392, + 394,3,56,28,0,393,392,1,0,0,0,393,394,1,0,0,0,394,51,1,0,0,0,395, + 396,5,18,0,0,396,397,3,6,3,0,397,398,5,82,0,0,398,399,5,9,0,0,399, + 400,5,1,0,0,400,401,3,46,23,0,401,402,5,2,0,0,402,53,1,0,0,0,403, + 404,5,19,0,0,404,405,3,6,3,0,405,406,5,82,0,0,406,407,5,9,0,0,407, + 408,5,1,0,0,408,409,3,46,23,0,409,410,5,2,0,0,410,55,1,0,0,0,411, + 412,5,20,0,0,412,413,5,82,0,0,413,414,5,9,0,0,414,415,5,1,0,0,415, + 416,3,46,23,0,416,417,5,2,0,0,417,57,1,0,0,0,418,419,5,21,0,0,419, + 420,5,89,0,0,420,421,5,23,0,0,421,422,3,6,3,0,422,423,5,48,0,0,423, + 424,3,6,3,0,424,426,5,24,0,0,425,427,5,75,0,0,426,425,1,0,0,0,426, + 427,1,0,0,0,427,428,1,0,0,0,428,429,7,1,0,0,429,430,5,82,0,0,430, + 431,5,9,0,0,431,432,5,1,0,0,432,433,3,46,23,0,433,434,5,2,0,0,434, + 59,1,0,0,0,435,436,5,22,0,0,436,437,3,6,3,0,437,438,5,82,0,0,438, + 439,5,9,0,0,439,440,5,1,0,0,440,441,3,46,23,0,441,442,5,2,0,0,442, + 61,1,0,0,0,443,446,3,64,32,0,444,446,5,9,0,0,445,443,1,0,0,0,445, + 444,1,0,0,0,446,447,1,0,0,0,447,445,1,0,0,0,447,448,1,0,0,0,448, + 449,1,0,0,0,449,450,5,0,0,1,450,63,1,0,0,0,451,452,5,31,0,0,452, + 453,5,89,0,0,453,454,5,82,0,0,454,455,3,66,33,0,455,65,1,0,0,0,456, + 457,5,9,0,0,457,466,5,1,0,0,458,467,3,72,36,0,459,467,3,76,38,0, + 460,467,3,78,39,0,461,467,3,86,43,0,462,467,3,88,44,0,463,467,3, + 68,34,0,464,467,3,70,35,0,465,467,3,74,37,0,466,458,1,0,0,0,466, + 459,1,0,0,0,466,460,1,0,0,0,466,461,1,0,0,0,466,462,1,0,0,0,466, + 463,1,0,0,0,466,464,1,0,0,0,466,465,1,0,0,0,467,468,1,0,0,0,468, + 466,1,0,0,0,468,469,1,0,0,0,469,470,1,0,0,0,470,471,5,2,0,0,471, + 67,1,0,0,0,472,473,5,40,0,0,473,474,5,49,0,0,474,479,5,89,0,0,475, 476,5,74,0,0,476,478,3,92,46,0,477,475,1,0,0,0,478,481,1,0,0,0,479, 477,1,0,0,0,479,480,1,0,0,0,480,482,1,0,0,0,481,479,1,0,0,0,482, - 483,5,50,0,0,483,484,5,82,0,0,484,485,3,28,14,0,485,71,1,0,0,0,486, - 487,7,2,0,0,487,488,5,82,0,0,488,489,5,9,0,0,489,491,5,1,0,0,490, - 492,3,40,20,0,491,490,1,0,0,0,492,493,1,0,0,0,493,491,1,0,0,0,493, - 494,1,0,0,0,494,495,1,0,0,0,495,496,5,2,0,0,496,73,1,0,0,0,497,498, - 5,35,0,0,498,499,5,82,0,0,499,500,3,28,14,0,500,75,1,0,0,0,501,502, - 5,36,0,0,502,503,5,82,0,0,503,504,5,9,0,0,504,508,5,1,0,0,505,509, - 3,22,11,0,506,509,3,24,12,0,507,509,3,26,13,0,508,505,1,0,0,0,508, - 506,1,0,0,0,508,507,1,0,0,0,509,510,1,0,0,0,510,508,1,0,0,0,510, - 511,1,0,0,0,511,512,1,0,0,0,512,513,5,2,0,0,513,77,1,0,0,0,514,515, - 5,37,0,0,515,516,5,82,0,0,516,517,5,9,0,0,517,536,5,1,0,0,518,521, - 3,80,40,0,519,521,3,82,41,0,520,518,1,0,0,0,520,519,1,0,0,0,521, - 534,1,0,0,0,522,531,5,49,0,0,523,528,3,90,45,0,524,525,5,74,0,0, - 525,527,3,90,45,0,526,524,1,0,0,0,527,530,1,0,0,0,528,526,1,0,0, - 0,528,529,1,0,0,0,529,532,1,0,0,0,530,528,1,0,0,0,531,523,1,0,0, - 0,531,532,1,0,0,0,532,533,1,0,0,0,533,535,5,50,0,0,534,522,1,0,0, - 0,534,535,1,0,0,0,535,537,1,0,0,0,536,520,1,0,0,0,537,538,1,0,0, - 0,538,536,1,0,0,0,538,539,1,0,0,0,539,540,1,0,0,0,540,541,5,2,0, - 0,541,79,1,0,0,0,542,547,5,89,0,0,543,544,5,56,0,0,544,545,3,6,3, - 0,545,546,5,58,0,0,546,548,1,0,0,0,547,543,1,0,0,0,547,548,1,0,0, - 0,548,549,1,0,0,0,549,553,5,57,0,0,550,552,3,84,42,0,551,550,1,0, - 0,0,552,555,1,0,0,0,553,551,1,0,0,0,553,554,1,0,0,0,554,556,1,0, - 0,0,555,553,1,0,0,0,556,557,5,42,0,0,557,558,5,9,0,0,558,81,1,0, - 0,0,559,564,5,89,0,0,560,561,5,56,0,0,561,562,3,6,3,0,562,563,5, - 58,0,0,563,565,1,0,0,0,564,560,1,0,0,0,564,565,1,0,0,0,565,566,1, - 0,0,0,566,567,3,0,0,0,567,568,5,57,0,0,568,569,5,39,0,0,569,570, - 5,9,0,0,570,83,1,0,0,0,571,574,5,43,0,0,572,574,5,44,0,0,573,571, - 1,0,0,0,573,572,1,0,0,0,574,85,1,0,0,0,575,576,5,38,0,0,576,577, - 5,82,0,0,577,578,5,9,0,0,578,595,5,1,0,0,579,592,5,42,0,0,580,589, - 5,49,0,0,581,586,3,90,45,0,582,583,5,74,0,0,583,585,3,90,45,0,584, - 582,1,0,0,0,585,588,1,0,0,0,586,584,1,0,0,0,586,587,1,0,0,0,587, - 590,1,0,0,0,588,586,1,0,0,0,589,581,1,0,0,0,589,590,1,0,0,0,590, - 591,1,0,0,0,591,593,5,50,0,0,592,580,1,0,0,0,592,593,1,0,0,0,593, - 596,1,0,0,0,594,596,5,39,0,0,595,579,1,0,0,0,595,594,1,0,0,0,596, - 597,1,0,0,0,597,598,5,9,0,0,598,599,5,2,0,0,599,87,1,0,0,0,600,601, - 5,15,0,0,601,602,5,89,0,0,602,611,5,49,0,0,603,608,3,90,45,0,604, - 605,5,74,0,0,605,607,3,90,45,0,606,604,1,0,0,0,607,610,1,0,0,0,608, - 606,1,0,0,0,608,609,1,0,0,0,609,612,1,0,0,0,610,608,1,0,0,0,611, - 603,1,0,0,0,611,612,1,0,0,0,612,613,1,0,0,0,613,615,5,50,0,0,614, - 616,3,0,0,0,615,614,1,0,0,0,615,616,1,0,0,0,616,617,1,0,0,0,617, - 618,5,82,0,0,618,619,3,28,14,0,619,89,1,0,0,0,620,621,5,89,0,0,621, - 622,3,0,0,0,622,91,1,0,0,0,623,624,5,89,0,0,624,625,5,76,0,0,625, - 626,7,3,0,0,626,93,1,0,0,0,69,100,111,116,122,124,128,143,152,158, + 483,5,50,0,0,483,484,5,82,0,0,484,485,5,9,0,0,485,486,5,1,0,0,486, + 487,3,46,23,0,487,488,5,2,0,0,488,69,1,0,0,0,489,490,5,41,0,0,490, + 491,5,49,0,0,491,496,3,6,3,0,492,493,5,74,0,0,493,495,3,92,46,0, + 494,492,1,0,0,0,495,498,1,0,0,0,496,494,1,0,0,0,496,497,1,0,0,0, + 497,499,1,0,0,0,498,496,1,0,0,0,499,500,5,50,0,0,500,501,5,82,0, + 0,501,502,5,9,0,0,502,503,5,1,0,0,503,504,3,46,23,0,504,505,5,2, + 0,0,505,71,1,0,0,0,506,507,7,2,0,0,507,508,5,82,0,0,508,509,5,9, + 0,0,509,511,5,1,0,0,510,512,3,38,19,0,511,510,1,0,0,0,512,513,1, + 0,0,0,513,511,1,0,0,0,513,514,1,0,0,0,514,515,1,0,0,0,515,516,5, + 2,0,0,516,73,1,0,0,0,517,518,5,35,0,0,518,519,5,82,0,0,519,520,5, + 9,0,0,520,521,5,1,0,0,521,522,3,46,23,0,522,523,5,2,0,0,523,75,1, + 0,0,0,524,525,5,36,0,0,525,526,5,82,0,0,526,527,5,9,0,0,527,531, + 5,1,0,0,528,532,3,22,11,0,529,532,3,24,12,0,530,532,3,26,13,0,531, + 528,1,0,0,0,531,529,1,0,0,0,531,530,1,0,0,0,532,533,1,0,0,0,533, + 531,1,0,0,0,533,534,1,0,0,0,534,535,1,0,0,0,535,536,5,2,0,0,536, + 77,1,0,0,0,537,538,5,37,0,0,538,539,5,82,0,0,539,540,5,9,0,0,540, + 559,5,1,0,0,541,544,3,80,40,0,542,544,3,82,41,0,543,541,1,0,0,0, + 543,542,1,0,0,0,544,557,1,0,0,0,545,554,5,49,0,0,546,551,3,90,45, + 0,547,548,5,74,0,0,548,550,3,90,45,0,549,547,1,0,0,0,550,553,1,0, + 0,0,551,549,1,0,0,0,551,552,1,0,0,0,552,555,1,0,0,0,553,551,1,0, + 0,0,554,546,1,0,0,0,554,555,1,0,0,0,555,556,1,0,0,0,556,558,5,50, + 0,0,557,545,1,0,0,0,557,558,1,0,0,0,558,560,1,0,0,0,559,543,1,0, + 0,0,560,561,1,0,0,0,561,559,1,0,0,0,561,562,1,0,0,0,562,563,1,0, + 0,0,563,564,5,2,0,0,564,79,1,0,0,0,565,570,5,89,0,0,566,567,5,56, + 0,0,567,568,3,6,3,0,568,569,5,58,0,0,569,571,1,0,0,0,570,566,1,0, + 0,0,570,571,1,0,0,0,571,572,1,0,0,0,572,576,5,57,0,0,573,575,3,84, + 42,0,574,573,1,0,0,0,575,578,1,0,0,0,576,574,1,0,0,0,576,577,1,0, + 0,0,577,579,1,0,0,0,578,576,1,0,0,0,579,580,5,42,0,0,580,581,5,9, + 0,0,581,81,1,0,0,0,582,587,5,89,0,0,583,584,5,56,0,0,584,585,3,6, + 3,0,585,586,5,58,0,0,586,588,1,0,0,0,587,583,1,0,0,0,587,588,1,0, + 0,0,588,589,1,0,0,0,589,590,3,0,0,0,590,591,5,57,0,0,591,592,5,39, + 0,0,592,593,5,9,0,0,593,83,1,0,0,0,594,597,5,43,0,0,595,597,5,44, + 0,0,596,594,1,0,0,0,596,595,1,0,0,0,597,85,1,0,0,0,598,599,5,38, + 0,0,599,600,5,82,0,0,600,601,5,9,0,0,601,618,5,1,0,0,602,615,5,42, + 0,0,603,612,5,49,0,0,604,609,3,90,45,0,605,606,5,74,0,0,606,608, + 3,90,45,0,607,605,1,0,0,0,608,611,1,0,0,0,609,607,1,0,0,0,609,610, + 1,0,0,0,610,613,1,0,0,0,611,609,1,0,0,0,612,604,1,0,0,0,612,613, + 1,0,0,0,613,614,1,0,0,0,614,616,5,50,0,0,615,603,1,0,0,0,615,616, + 1,0,0,0,616,619,1,0,0,0,617,619,5,39,0,0,618,602,1,0,0,0,618,617, + 1,0,0,0,619,620,1,0,0,0,620,621,5,9,0,0,621,622,5,2,0,0,622,87,1, + 0,0,0,623,624,5,15,0,0,624,625,5,89,0,0,625,634,5,49,0,0,626,631, + 3,90,45,0,627,628,5,74,0,0,628,630,3,90,45,0,629,627,1,0,0,0,630, + 633,1,0,0,0,631,629,1,0,0,0,631,632,1,0,0,0,632,635,1,0,0,0,633, + 631,1,0,0,0,634,626,1,0,0,0,634,635,1,0,0,0,635,636,1,0,0,0,636, + 638,5,50,0,0,637,639,3,0,0,0,638,637,1,0,0,0,638,639,1,0,0,0,639, + 640,1,0,0,0,640,641,5,82,0,0,641,642,5,9,0,0,642,643,5,1,0,0,643, + 644,3,46,23,0,644,645,5,2,0,0,645,89,1,0,0,0,646,647,5,89,0,0,647, + 648,3,0,0,0,648,91,1,0,0,0,649,650,5,89,0,0,650,651,5,76,0,0,651, + 652,7,3,0,0,652,93,1,0,0,0,70,100,111,116,122,124,128,143,152,158, 179,181,188,193,198,205,214,218,225,230,240,243,248,256,261,270, - 275,291,295,304,310,315,321,331,336,339,346,352,358,363,376,384, - 390,394,418,431,433,452,454,465,479,493,508,510,520,528,531,534, - 538,547,553,564,573,586,589,592,595,608,611,615 + 275,291,295,300,304,309,315,325,330,333,340,346,352,357,370,379, + 383,389,393,426,445,447,466,468,479,496,513,531,533,543,551,554, + 557,561,570,576,587,596,609,612,615,618,631,634,638 ] class PyNestMLParser ( Parser ): @@ -312,16 +321,16 @@ class PyNestMLParser ( Parser ): RULE_inlineExpression = 11 RULE_odeEquation = 12 RULE_kernel = 13 - RULE_block = 14 - RULE_stmt = 15 - RULE_compoundStmt = 16 - RULE_smallStmt = 17 - RULE_assignment = 18 - RULE_declaration = 19 - RULE_declaration_newline = 20 - RULE_anyDecorator = 21 - RULE_namespaceDecoratorNamespace = 22 - RULE_namespaceDecoratorName = 23 + RULE_stmt = 14 + RULE_compoundStmt = 15 + RULE_smallStmt = 16 + RULE_assignment = 17 + RULE_declaration = 18 + RULE_declaration_newline = 19 + RULE_anyDecorator = 20 + RULE_namespaceDecoratorNamespace = 21 + RULE_namespaceDecoratorName = 22 + RULE_stmtsBody = 23 RULE_returnStmt = 24 RULE_ifStmt = 25 RULE_ifClause = 26 @@ -349,15 +358,16 @@ class PyNestMLParser ( Parser ): ruleNames = [ "dataType", "unitType", "unitTypeExponent", "expression", "simpleExpression", "unaryOperator", "bitOperator", "comparisonOperator", "logicalOperator", "variable", "functionCall", "inlineExpression", - "odeEquation", "kernel", "block", "stmt", "compoundStmt", - "smallStmt", "assignment", "declaration", "declaration_newline", - "anyDecorator", "namespaceDecoratorNamespace", "namespaceDecoratorName", - "returnStmt", "ifStmt", "ifClause", "elifClause", "elseClause", - "forStmt", "whileStmt", "nestMLCompilationUnit", "model", - "modelBody", "onReceiveBlock", "onConditionBlock", "blockWithVariables", - "updateBlock", "equationsBlock", "inputBlock", "spikeInputPort", - "continuousInputPort", "inputQualifier", "outputBlock", - "function", "parameter", "constParameter" ] + "odeEquation", "kernel", "stmt", "compoundStmt", "smallStmt", + "assignment", "declaration", "declaration_newline", "anyDecorator", + "namespaceDecoratorNamespace", "namespaceDecoratorName", + "stmtsBody", "returnStmt", "ifStmt", "ifClause", "elifClause", + "elseClause", "forStmt", "whileStmt", "nestMLCompilationUnit", + "model", "modelBody", "onReceiveBlock", "onConditionBlock", + "blockWithVariables", "updateBlock", "equationsBlock", + "inputBlock", "spikeInputPort", "continuousInputPort", + "inputQualifier", "outputBlock", "function", "parameter", + "constParameter" ] EOF = Token.EOF INDENT=1 @@ -1213,19 +1223,21 @@ def unaryOperator(self): localctx = PyNestMLParser.UnaryOperatorContext(self, self._ctx, self.state) self.enterRule(localctx, 10, self.RULE_unaryOperator) try: - self.enterOuterAlt(localctx, 1) self.state = 198 self._errHandler.sync(self) token = self._input.LA(1) if token in [51]: + self.enterOuterAlt(localctx, 1) self.state = 195 localctx.unaryPlus = self.match(PyNestMLParser.PLUS) pass elif token in [75]: + self.enterOuterAlt(localctx, 2) self.state = 196 localctx.unaryMinus = self.match(PyNestMLParser.MINUS) pass elif token in [52]: + self.enterOuterAlt(localctx, 3) self.state = 197 localctx.unaryTilde = self.match(PyNestMLParser.TILDE) pass @@ -1285,27 +1297,31 @@ def bitOperator(self): localctx = PyNestMLParser.BitOperatorContext(self, self._ctx, self.state) self.enterRule(localctx, 12, self.RULE_bitOperator) try: - self.enterOuterAlt(localctx, 1) self.state = 205 self._errHandler.sync(self) token = self._input.LA(1) if token in [55]: + self.enterOuterAlt(localctx, 1) self.state = 200 localctx.bitAnd = self.match(PyNestMLParser.AMPERSAND) pass elif token in [54]: + self.enterOuterAlt(localctx, 2) self.state = 201 localctx.bitXor = self.match(PyNestMLParser.CARET) pass elif token in [53]: + self.enterOuterAlt(localctx, 3) self.state = 202 localctx.bitOr = self.match(PyNestMLParser.PIPE) pass elif token in [61]: + self.enterOuterAlt(localctx, 4) self.state = 203 localctx.bitShiftLeft = self.match(PyNestMLParser.LEFT_LEFT_ANGLE) pass elif token in [62]: + self.enterOuterAlt(localctx, 5) self.state = 204 localctx.bitShiftRight = self.match(PyNestMLParser.RIGHT_RIGHT_ANGLE) pass @@ -1373,35 +1389,41 @@ def comparisonOperator(self): localctx = PyNestMLParser.ComparisonOperatorContext(self, self._ctx, self.state) self.enterRule(localctx, 14, self.RULE_comparisonOperator) try: - self.enterOuterAlt(localctx, 1) self.state = 214 self._errHandler.sync(self) token = self._input.LA(1) if token in [63]: + self.enterOuterAlt(localctx, 1) self.state = 207 localctx.lt = self.match(PyNestMLParser.LEFT_ANGLE) pass elif token in [65]: + self.enterOuterAlt(localctx, 2) self.state = 208 localctx.le = self.match(PyNestMLParser.LEFT_ANGLE_EQUALS) pass elif token in [70]: + self.enterOuterAlt(localctx, 3) self.state = 209 localctx.eq = self.match(PyNestMLParser.EQUALS_EQUALS) pass elif token in [71]: + self.enterOuterAlt(localctx, 4) self.state = 210 localctx.ne = self.match(PyNestMLParser.EXCLAMATION_EQUALS) pass elif token in [72]: + self.enterOuterAlt(localctx, 5) self.state = 211 localctx.ne2 = self.match(PyNestMLParser.LEFT_ANGLE_RIGHT_ANGLE) pass elif token in [73]: + self.enterOuterAlt(localctx, 6) self.state = 212 localctx.ge = self.match(PyNestMLParser.RIGHT_ANGLE_EQUALS) pass elif token in [64]: + self.enterOuterAlt(localctx, 7) self.state = 213 localctx.gt = self.match(PyNestMLParser.RIGHT_ANGLE) pass @@ -1449,15 +1471,16 @@ def logicalOperator(self): localctx = PyNestMLParser.LogicalOperatorContext(self, self._ctx, self.state) self.enterRule(localctx, 16, self.RULE_logicalOperator) try: - self.enterOuterAlt(localctx, 1) self.state = 218 self._errHandler.sync(self) token = self._input.LA(1) if token in [26]: + self.enterOuterAlt(localctx, 1) self.state = 216 localctx.logicalAnd = self.match(PyNestMLParser.AND_KEYWORD) pass elif token in [27]: + self.enterOuterAlt(localctx, 2) self.state = 217 localctx.logicalOr = self.match(PyNestMLParser.OR_KEYWORD) pass @@ -1938,75 +1961,6 @@ def kernel(self): return localctx - class BlockContext(ParserRuleContext): - __slots__ = 'parser' - - def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): - super().__init__(parent, invokingState) - self.parser = parser - - def NEWLINE(self): - return self.getToken(PyNestMLParser.NEWLINE, 0) - - def INDENT(self): - return self.getToken(PyNestMLParser.INDENT, 0) - - def DEDENT(self): - return self.getToken(PyNestMLParser.DEDENT, 0) - - def stmt(self, i:int=None): - if i is None: - return self.getTypedRuleContexts(PyNestMLParser.StmtContext) - else: - return self.getTypedRuleContext(PyNestMLParser.StmtContext,i) - - - def getRuleIndex(self): - return PyNestMLParser.RULE_block - - def accept(self, visitor:ParseTreeVisitor): - if hasattr( visitor, "visitBlock" ): - return visitor.visitBlock(self) - else: - return visitor.visitChildren(self) - - - - - def block(self): - - localctx = PyNestMLParser.BlockContext(self, self._ctx, self.state) - self.enterRule(localctx, 28, self.RULE_block) - self._la = 0 # Token type - try: - self.enterOuterAlt(localctx, 1) - self.state = 299 - self.match(PyNestMLParser.NEWLINE) - self.state = 300 - self.match(PyNestMLParser.INDENT) - self.state = 302 - self._errHandler.sync(self) - _la = self._input.LA(1) - while True: - self.state = 301 - self.stmt() - self.state = 304 - self._errHandler.sync(self) - _la = self._input.LA(1) - if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & 543621120) != 0) or _la==89): - break - - self.state = 306 - self.match(PyNestMLParser.DEDENT) - except RecognitionException as re: - localctx.exception = re - self._errHandler.reportError(self, re) - self._errHandler.recover(self, re) - finally: - self.exitRule() - return localctx - - class StmtContext(ParserRuleContext): __slots__ = 'parser' @@ -2022,6 +1976,9 @@ def compoundStmt(self): return self.getTypedRuleContext(PyNestMLParser.CompoundStmtContext,0) + def NEWLINE(self): + return self.getToken(PyNestMLParser.NEWLINE, 0) + def getRuleIndex(self): return PyNestMLParser.RULE_stmt @@ -2037,19 +1994,27 @@ def accept(self, visitor:ParseTreeVisitor): def stmt(self): localctx = PyNestMLParser.StmtContext(self, self._ctx, self.state) - self.enterRule(localctx, 30, self.RULE_stmt) + self.enterRule(localctx, 28, self.RULE_stmt) + self._la = 0 # Token type try: - self.state = 310 + self.enterOuterAlt(localctx, 1) + self.state = 300 + self._errHandler.sync(self) + _la = self._input.LA(1) + if _la==9: + self.state = 299 + self.match(PyNestMLParser.NEWLINE) + + + self.state = 304 self._errHandler.sync(self) token = self._input.LA(1) if token in [16, 17, 29, 89]: - self.enterOuterAlt(localctx, 1) - self.state = 308 + self.state = 302 self.smallStmt() pass elif token in [18, 21, 22]: - self.enterOuterAlt(localctx, 2) - self.state = 309 + self.state = 303 self.compoundStmt() pass else: @@ -2098,24 +2063,24 @@ def accept(self, visitor:ParseTreeVisitor): def compoundStmt(self): localctx = PyNestMLParser.CompoundStmtContext(self, self._ctx, self.state) - self.enterRule(localctx, 32, self.RULE_compoundStmt) + self.enterRule(localctx, 30, self.RULE_compoundStmt) try: - self.state = 315 + self.state = 309 self._errHandler.sync(self) token = self._input.LA(1) if token in [18]: self.enterOuterAlt(localctx, 1) - self.state = 312 + self.state = 306 self.ifStmt() pass elif token in [21]: self.enterOuterAlt(localctx, 2) - self.state = 313 + self.state = 307 self.forStmt() pass elif token in [22]: self.enterOuterAlt(localctx, 3) - self.state = 314 + self.state = 308 self.whileStmt() pass else: @@ -2171,34 +2136,34 @@ def accept(self, visitor:ParseTreeVisitor): def smallStmt(self): localctx = PyNestMLParser.SmallStmtContext(self, self._ctx, self.state) - self.enterRule(localctx, 34, self.RULE_smallStmt) + self.enterRule(localctx, 32, self.RULE_smallStmt) try: self.enterOuterAlt(localctx, 1) - self.state = 321 + self.state = 315 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,31,self._ctx) if la_ == 1: - self.state = 317 + self.state = 311 self.assignment() pass elif la_ == 2: - self.state = 318 + self.state = 312 self.functionCall() pass elif la_ == 3: - self.state = 319 + self.state = 313 self.declaration() pass elif la_ == 4: - self.state = 320 + self.state = 314 self.returnStmt() pass - self.state = 323 + self.state = 317 self.match(PyNestMLParser.NEWLINE) except RecognitionException as re: localctx.exception = re @@ -2260,38 +2225,38 @@ def accept(self, visitor:ParseTreeVisitor): def assignment(self): localctx = PyNestMLParser.AssignmentContext(self, self._ctx, self.state) - self.enterRule(localctx, 36, self.RULE_assignment) + self.enterRule(localctx, 34, self.RULE_assignment) try: self.enterOuterAlt(localctx, 1) - self.state = 325 + self.state = 319 localctx.lhs_variable = self.variable() - self.state = 331 + self.state = 325 self._errHandler.sync(self) token = self._input.LA(1) if token in [76]: - self.state = 326 + self.state = 320 localctx.directAssignment = self.match(PyNestMLParser.EQUALS) pass elif token in [66]: - self.state = 327 + self.state = 321 localctx.compoundSum = self.match(PyNestMLParser.PLUS_EQUALS) pass elif token in [67]: - self.state = 328 + self.state = 322 localctx.compoundMinus = self.match(PyNestMLParser.MINUS_EQUALS) pass elif token in [68]: - self.state = 329 + self.state = 323 localctx.compoundProduct = self.match(PyNestMLParser.STAR_EQUALS) pass elif token in [69]: - self.state = 330 + self.state = 324 localctx.compoundQuotient = self.match(PyNestMLParser.FORWARD_SLASH_EQUALS) pass else: raise NoViableAltException(self) - self.state = 333 + self.state = 327 self.expression(0) except RecognitionException as re: localctx.exception = re @@ -2375,71 +2340,71 @@ def accept(self, visitor:ParseTreeVisitor): def declaration(self): localctx = PyNestMLParser.DeclarationContext(self, self._ctx, self.state) - self.enterRule(localctx, 38, self.RULE_declaration) + self.enterRule(localctx, 36, self.RULE_declaration) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 336 + self.state = 330 self._errHandler.sync(self) _la = self._input.LA(1) if _la==29: - self.state = 335 + self.state = 329 localctx.isRecordable = self.match(PyNestMLParser.RECORDABLE_KEYWORD) - self.state = 339 + self.state = 333 self._errHandler.sync(self) _la = self._input.LA(1) if _la==16: - self.state = 338 + self.state = 332 localctx.isInlineExpression = self.match(PyNestMLParser.INLINE_KEYWORD) - self.state = 341 + self.state = 335 self.variable() - self.state = 346 + self.state = 340 self._errHandler.sync(self) _la = self._input.LA(1) while _la==74: - self.state = 342 + self.state = 336 self.match(PyNestMLParser.COMMA) - self.state = 343 + self.state = 337 self.variable() - self.state = 348 + self.state = 342 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 349 + self.state = 343 self.dataType() - self.state = 352 + self.state = 346 self._errHandler.sync(self) _la = self._input.LA(1) if _la==76: - self.state = 350 + self.state = 344 self.match(PyNestMLParser.EQUALS) - self.state = 351 + self.state = 345 localctx.rhs = self.expression(0) - self.state = 358 + self.state = 352 self._errHandler.sync(self) _la = self._input.LA(1) if _la==59: - self.state = 354 + self.state = 348 self.match(PyNestMLParser.LEFT_LEFT_SQUARE) - self.state = 355 + self.state = 349 localctx.invariant = self.expression(0) - self.state = 356 + self.state = 350 self.match(PyNestMLParser.RIGHT_RIGHT_SQUARE) - self.state = 363 + self.state = 357 self._errHandler.sync(self) _la = self._input.LA(1) while (((_la) & ~0x3f) == 0 and ((1 << _la) & 246290604621824) != 0): - self.state = 360 + self.state = 354 localctx.decorator = self.anyDecorator() - self.state = 365 + self.state = 359 self._errHandler.sync(self) _la = self._input.LA(1) @@ -2481,12 +2446,12 @@ def accept(self, visitor:ParseTreeVisitor): def declaration_newline(self): localctx = PyNestMLParser.Declaration_newlineContext(self, self._ctx, self.state) - self.enterRule(localctx, 40, self.RULE_declaration_newline) + self.enterRule(localctx, 38, self.RULE_declaration_newline) try: self.enterOuterAlt(localctx, 1) - self.state = 366 + self.state = 360 self.declaration() - self.state = 367 + self.state = 361 self.match(PyNestMLParser.NEWLINE) except RecognitionException as re: localctx.exception = re @@ -2539,30 +2504,30 @@ def accept(self, visitor:ParseTreeVisitor): def anyDecorator(self): localctx = PyNestMLParser.AnyDecoratorContext(self, self._ctx, self.state) - self.enterRule(localctx, 42, self.RULE_anyDecorator) + self.enterRule(localctx, 40, self.RULE_anyDecorator) try: - self.state = 376 + self.state = 370 self._errHandler.sync(self) token = self._input.LA(1) if token in [45]: self.enterOuterAlt(localctx, 1) - self.state = 369 + self.state = 363 self.match(PyNestMLParser.DECORATOR_HOMOGENEOUS) pass elif token in [46]: self.enterOuterAlt(localctx, 2) - self.state = 370 + self.state = 364 self.match(PyNestMLParser.DECORATOR_HETEROGENEOUS) pass elif token in [47]: self.enterOuterAlt(localctx, 3) - self.state = 371 + self.state = 365 self.match(PyNestMLParser.AT) - self.state = 372 + self.state = 366 self.namespaceDecoratorNamespace() - self.state = 373 + self.state = 367 self.match(PyNestMLParser.DOUBLE_COLON) - self.state = 374 + self.state = 368 self.namespaceDecoratorName() pass else: @@ -2603,10 +2568,10 @@ def accept(self, visitor:ParseTreeVisitor): def namespaceDecoratorNamespace(self): localctx = PyNestMLParser.NamespaceDecoratorNamespaceContext(self, self._ctx, self.state) - self.enterRule(localctx, 44, self.RULE_namespaceDecoratorNamespace) + self.enterRule(localctx, 42, self.RULE_namespaceDecoratorNamespace) try: self.enterOuterAlt(localctx, 1) - self.state = 378 + self.state = 372 localctx.name = self.match(PyNestMLParser.NAME) except RecognitionException as re: localctx.exception = re @@ -2643,10 +2608,10 @@ def accept(self, visitor:ParseTreeVisitor): def namespaceDecoratorName(self): localctx = PyNestMLParser.NamespaceDecoratorNameContext(self, self._ctx, self.state) - self.enterRule(localctx, 46, self.RULE_namespaceDecoratorName) + self.enterRule(localctx, 44, self.RULE_namespaceDecoratorName) try: self.enterOuterAlt(localctx, 1) - self.state = 380 + self.state = 374 localctx.name = self.match(PyNestMLParser.NAME) except RecognitionException as re: localctx.exception = re @@ -2657,6 +2622,60 @@ def namespaceDecoratorName(self): return localctx + class StmtsBodyContext(ParserRuleContext): + __slots__ = 'parser' + + def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): + super().__init__(parent, invokingState) + self.parser = parser + + def stmt(self, i:int=None): + if i is None: + return self.getTypedRuleContexts(PyNestMLParser.StmtContext) + else: + return self.getTypedRuleContext(PyNestMLParser.StmtContext,i) + + + def getRuleIndex(self): + return PyNestMLParser.RULE_stmtsBody + + def accept(self, visitor:ParseTreeVisitor): + if hasattr( visitor, "visitStmtsBody" ): + return visitor.visitStmtsBody(self) + else: + return visitor.visitChildren(self) + + + + + def stmtsBody(self): + + localctx = PyNestMLParser.StmtsBodyContext(self, self._ctx, self.state) + self.enterRule(localctx, 46, self.RULE_stmtsBody) + self._la = 0 # Token type + try: + self.enterOuterAlt(localctx, 1) + self.state = 377 + self._errHandler.sync(self) + _la = self._input.LA(1) + while True: + self.state = 376 + self.stmt() + self.state = 379 + self._errHandler.sync(self) + _la = self._input.LA(1) + if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & 543621632) != 0) or _la==89): + break + + except RecognitionException as re: + localctx.exception = re + self._errHandler.reportError(self, re) + self._errHandler.recover(self, re) + finally: + self.exitRule() + return localctx + + class ReturnStmtContext(ParserRuleContext): __slots__ = 'parser' @@ -2690,13 +2709,13 @@ def returnStmt(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 382 + self.state = 381 self.match(PyNestMLParser.RETURN_KEYWORD) - self.state = 384 + self.state = 383 self._errHandler.sync(self) _la = self._input.LA(1) if (((_la) & ~0x3f) == 0 and ((1 << _la) & 7318349696466944) != 0) or ((((_la - 75)) & ~0x3f) == 0 and ((1 << (_la - 75)) & 126977) != 0): - self.state = 383 + self.state = 382 self.expression(0) @@ -2750,23 +2769,23 @@ def ifStmt(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 386 + self.state = 385 self.ifClause() - self.state = 390 + self.state = 389 self._errHandler.sync(self) _la = self._input.LA(1) while _la==19: - self.state = 387 + self.state = 386 self.elifClause() - self.state = 392 + self.state = 391 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 394 + self.state = 393 self._errHandler.sync(self) _la = self._input.LA(1) if _la==20: - self.state = 393 + self.state = 392 self.elseClause() @@ -2796,9 +2815,18 @@ def expression(self): def COLON(self): return self.getToken(PyNestMLParser.COLON, 0) - def block(self): - return self.getTypedRuleContext(PyNestMLParser.BlockContext,0) + def NEWLINE(self): + return self.getToken(PyNestMLParser.NEWLINE, 0) + + def INDENT(self): + return self.getToken(PyNestMLParser.INDENT, 0) + + def stmtsBody(self): + return self.getTypedRuleContext(PyNestMLParser.StmtsBodyContext,0) + + def DEDENT(self): + return self.getToken(PyNestMLParser.DEDENT, 0) def getRuleIndex(self): return PyNestMLParser.RULE_ifClause @@ -2818,14 +2846,20 @@ def ifClause(self): self.enterRule(localctx, 52, self.RULE_ifClause) try: self.enterOuterAlt(localctx, 1) - self.state = 396 + self.state = 395 self.match(PyNestMLParser.IF_KEYWORD) - self.state = 397 + self.state = 396 self.expression(0) - self.state = 398 + self.state = 397 self.match(PyNestMLParser.COLON) + self.state = 398 + self.match(PyNestMLParser.NEWLINE) self.state = 399 - self.block() + self.match(PyNestMLParser.INDENT) + self.state = 400 + self.stmtsBody() + self.state = 401 + self.match(PyNestMLParser.DEDENT) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) @@ -2852,10 +2886,19 @@ def expression(self): def COLON(self): return self.getToken(PyNestMLParser.COLON, 0) - def block(self): - return self.getTypedRuleContext(PyNestMLParser.BlockContext,0) + def NEWLINE(self): + return self.getToken(PyNestMLParser.NEWLINE, 0) + + def INDENT(self): + return self.getToken(PyNestMLParser.INDENT, 0) + + def stmtsBody(self): + return self.getTypedRuleContext(PyNestMLParser.StmtsBodyContext,0) + def DEDENT(self): + return self.getToken(PyNestMLParser.DEDENT, 0) + def getRuleIndex(self): return PyNestMLParser.RULE_elifClause @@ -2874,14 +2917,20 @@ def elifClause(self): self.enterRule(localctx, 54, self.RULE_elifClause) try: self.enterOuterAlt(localctx, 1) - self.state = 401 + self.state = 403 self.match(PyNestMLParser.ELIF_KEYWORD) - self.state = 402 + self.state = 404 self.expression(0) - self.state = 403 + self.state = 405 self.match(PyNestMLParser.COLON) - self.state = 404 - self.block() + self.state = 406 + self.match(PyNestMLParser.NEWLINE) + self.state = 407 + self.match(PyNestMLParser.INDENT) + self.state = 408 + self.stmtsBody() + self.state = 409 + self.match(PyNestMLParser.DEDENT) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) @@ -2904,10 +2953,19 @@ def ELSE_KEYWORD(self): def COLON(self): return self.getToken(PyNestMLParser.COLON, 0) - def block(self): - return self.getTypedRuleContext(PyNestMLParser.BlockContext,0) + def NEWLINE(self): + return self.getToken(PyNestMLParser.NEWLINE, 0) + + def INDENT(self): + return self.getToken(PyNestMLParser.INDENT, 0) + + def stmtsBody(self): + return self.getTypedRuleContext(PyNestMLParser.StmtsBodyContext,0) + def DEDENT(self): + return self.getToken(PyNestMLParser.DEDENT, 0) + def getRuleIndex(self): return PyNestMLParser.RULE_elseClause @@ -2926,12 +2984,18 @@ def elseClause(self): self.enterRule(localctx, 56, self.RULE_elseClause) try: self.enterOuterAlt(localctx, 1) - self.state = 406 + self.state = 411 self.match(PyNestMLParser.ELSE_KEYWORD) - self.state = 407 + self.state = 412 self.match(PyNestMLParser.COLON) - self.state = 408 - self.block() + self.state = 413 + self.match(PyNestMLParser.NEWLINE) + self.state = 414 + self.match(PyNestMLParser.INDENT) + self.state = 415 + self.stmtsBody() + self.state = 416 + self.match(PyNestMLParser.DEDENT) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) @@ -2967,9 +3031,18 @@ def STEP_KEYWORD(self): def COLON(self): return self.getToken(PyNestMLParser.COLON, 0) - def block(self): - return self.getTypedRuleContext(PyNestMLParser.BlockContext,0) + def NEWLINE(self): + return self.getToken(PyNestMLParser.NEWLINE, 0) + def INDENT(self): + return self.getToken(PyNestMLParser.INDENT, 0) + + def stmtsBody(self): + return self.getTypedRuleContext(PyNestMLParser.StmtsBodyContext,0) + + + def DEDENT(self): + return self.getToken(PyNestMLParser.DEDENT, 0) def NAME(self): return self.getToken(PyNestMLParser.NAME, 0) @@ -3009,40 +3082,46 @@ def forStmt(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 410 + self.state = 418 self.match(PyNestMLParser.FOR_KEYWORD) - self.state = 411 + self.state = 419 localctx.var = self.match(PyNestMLParser.NAME) - self.state = 412 + self.state = 420 self.match(PyNestMLParser.IN_KEYWORD) - self.state = 413 + self.state = 421 localctx.start_from = self.expression(0) - self.state = 414 + self.state = 422 self.match(PyNestMLParser.ELLIPSIS) - self.state = 415 + self.state = 423 localctx.end_at = self.expression(0) - self.state = 416 + self.state = 424 self.match(PyNestMLParser.STEP_KEYWORD) - self.state = 418 + self.state = 426 self._errHandler.sync(self) _la = self._input.LA(1) if _la==75: - self.state = 417 + self.state = 425 localctx.negative = self.match(PyNestMLParser.MINUS) - self.state = 420 + self.state = 428 _la = self._input.LA(1) if not(_la==90 or _la==91): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() - self.state = 421 + self.state = 429 self.match(PyNestMLParser.COLON) - self.state = 422 - self.block() + self.state = 430 + self.match(PyNestMLParser.NEWLINE) + self.state = 431 + self.match(PyNestMLParser.INDENT) + self.state = 432 + self.stmtsBody() + self.state = 433 + self.match(PyNestMLParser.DEDENT) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) @@ -3069,9 +3148,18 @@ def expression(self): def COLON(self): return self.getToken(PyNestMLParser.COLON, 0) - def block(self): - return self.getTypedRuleContext(PyNestMLParser.BlockContext,0) + def NEWLINE(self): + return self.getToken(PyNestMLParser.NEWLINE, 0) + + def INDENT(self): + return self.getToken(PyNestMLParser.INDENT, 0) + def stmtsBody(self): + return self.getTypedRuleContext(PyNestMLParser.StmtsBodyContext,0) + + + def DEDENT(self): + return self.getToken(PyNestMLParser.DEDENT, 0) def getRuleIndex(self): return PyNestMLParser.RULE_whileStmt @@ -3091,14 +3179,20 @@ def whileStmt(self): self.enterRule(localctx, 60, self.RULE_whileStmt) try: self.enterOuterAlt(localctx, 1) - self.state = 424 + self.state = 435 self.match(PyNestMLParser.WHILE_KEYWORD) - self.state = 425 + self.state = 436 self.expression(0) - self.state = 426 + self.state = 437 self.match(PyNestMLParser.COLON) - self.state = 427 - self.block() + self.state = 438 + self.match(PyNestMLParser.NEWLINE) + self.state = 439 + self.match(PyNestMLParser.INDENT) + self.state = 440 + self.stmtsBody() + self.state = 441 + self.match(PyNestMLParser.DEDENT) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) @@ -3150,31 +3244,31 @@ def nestMLCompilationUnit(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 431 + self.state = 445 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 431 + self.state = 445 self._errHandler.sync(self) token = self._input.LA(1) if token in [31]: - self.state = 429 + self.state = 443 self.model() pass elif token in [9]: - self.state = 430 + self.state = 444 self.match(PyNestMLParser.NEWLINE) pass else: raise NoViableAltException(self) - self.state = 433 + self.state = 447 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==9 or _la==31): break - self.state = 435 + self.state = 449 self.match(PyNestMLParser.EOF) except RecognitionException as re: localctx.exception = re @@ -3198,6 +3292,9 @@ def MODEL_KEYWORD(self): def NAME(self): return self.getToken(PyNestMLParser.NAME, 0) + def COLON(self): + return self.getToken(PyNestMLParser.COLON, 0) + def modelBody(self): return self.getTypedRuleContext(PyNestMLParser.ModelBodyContext,0) @@ -3220,11 +3317,13 @@ def model(self): self.enterRule(localctx, 64, self.RULE_model) try: self.enterOuterAlt(localctx, 1) - self.state = 437 + self.state = 451 self.match(PyNestMLParser.MODEL_KEYWORD) - self.state = 438 + self.state = 452 self.match(PyNestMLParser.NAME) - self.state = 439 + self.state = 453 + self.match(PyNestMLParser.COLON) + self.state = 454 self.modelBody() except RecognitionException as re: localctx.exception = re @@ -3242,9 +3341,6 @@ def __init__(self, parser, parent:ParserRuleContext=None, invokingState:int=-1): super().__init__(parent, invokingState) self.parser = parser - def COLON(self): - return self.getToken(PyNestMLParser.COLON, 0) - def NEWLINE(self): return self.getToken(PyNestMLParser.NEWLINE, 0) @@ -3329,61 +3425,59 @@ def modelBody(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 441 - self.match(PyNestMLParser.COLON) - self.state = 442 + self.state = 456 self.match(PyNestMLParser.NEWLINE) - self.state = 443 + self.state = 457 self.match(PyNestMLParser.INDENT) - self.state = 452 + self.state = 466 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 452 + self.state = 466 self._errHandler.sync(self) token = self._input.LA(1) if token in [32, 33, 34]: - self.state = 444 + self.state = 458 self.blockWithVariables() pass elif token in [36]: - self.state = 445 + self.state = 459 self.equationsBlock() pass elif token in [37]: - self.state = 446 + self.state = 460 self.inputBlock() pass elif token in [38]: - self.state = 447 + self.state = 461 self.outputBlock() pass elif token in [15]: - self.state = 448 + self.state = 462 self.function() pass elif token in [40]: - self.state = 449 + self.state = 463 self.onReceiveBlock() pass elif token in [41]: - self.state = 450 + self.state = 464 self.onConditionBlock() pass elif token in [35]: - self.state = 451 + self.state = 465 self.updateBlock() pass else: raise NoViableAltException(self) - self.state = 454 + self.state = 468 self._errHandler.sync(self) _la = self._input.LA(1) if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & 3843995762688) != 0)): break - self.state = 456 + self.state = 470 self.match(PyNestMLParser.DEDENT) except RecognitionException as re: localctx.exception = re @@ -3414,9 +3508,18 @@ def RIGHT_PAREN(self): def COLON(self): return self.getToken(PyNestMLParser.COLON, 0) - def block(self): - return self.getTypedRuleContext(PyNestMLParser.BlockContext,0) + def NEWLINE(self): + return self.getToken(PyNestMLParser.NEWLINE, 0) + def INDENT(self): + return self.getToken(PyNestMLParser.INDENT, 0) + + def stmtsBody(self): + return self.getTypedRuleContext(PyNestMLParser.StmtsBodyContext,0) + + + def DEDENT(self): + return self.getToken(PyNestMLParser.DEDENT, 0) def NAME(self): return self.getToken(PyNestMLParser.NAME, 0) @@ -3453,30 +3556,36 @@ def onReceiveBlock(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 458 + self.state = 472 self.match(PyNestMLParser.ON_RECEIVE_KEYWORD) - self.state = 459 + self.state = 473 self.match(PyNestMLParser.LEFT_PAREN) - self.state = 460 + self.state = 474 localctx.inputPortName = self.match(PyNestMLParser.NAME) - self.state = 465 + self.state = 479 self._errHandler.sync(self) _la = self._input.LA(1) while _la==74: - self.state = 461 + self.state = 475 self.match(PyNestMLParser.COMMA) - self.state = 462 + self.state = 476 self.constParameter() - self.state = 467 + self.state = 481 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 468 + self.state = 482 self.match(PyNestMLParser.RIGHT_PAREN) - self.state = 469 + self.state = 483 self.match(PyNestMLParser.COLON) - self.state = 470 - self.block() + self.state = 484 + self.match(PyNestMLParser.NEWLINE) + self.state = 485 + self.match(PyNestMLParser.INDENT) + self.state = 486 + self.stmtsBody() + self.state = 487 + self.match(PyNestMLParser.DEDENT) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) @@ -3506,10 +3615,19 @@ def RIGHT_PAREN(self): def COLON(self): return self.getToken(PyNestMLParser.COLON, 0) - def block(self): - return self.getTypedRuleContext(PyNestMLParser.BlockContext,0) + def NEWLINE(self): + return self.getToken(PyNestMLParser.NEWLINE, 0) + + def INDENT(self): + return self.getToken(PyNestMLParser.INDENT, 0) + + def stmtsBody(self): + return self.getTypedRuleContext(PyNestMLParser.StmtsBodyContext,0) + def DEDENT(self): + return self.getToken(PyNestMLParser.DEDENT, 0) + def expression(self): return self.getTypedRuleContext(PyNestMLParser.ExpressionContext,0) @@ -3546,30 +3664,36 @@ def onConditionBlock(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 472 + self.state = 489 self.match(PyNestMLParser.ON_CONDITION_KEYWORD) - self.state = 473 + self.state = 490 self.match(PyNestMLParser.LEFT_PAREN) - self.state = 474 + self.state = 491 localctx.condition = self.expression(0) - self.state = 479 + self.state = 496 self._errHandler.sync(self) _la = self._input.LA(1) while _la==74: - self.state = 475 + self.state = 492 self.match(PyNestMLParser.COMMA) - self.state = 476 + self.state = 493 self.constParameter() - self.state = 481 + self.state = 498 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 482 + self.state = 499 self.match(PyNestMLParser.RIGHT_PAREN) - self.state = 483 + self.state = 500 self.match(PyNestMLParser.COLON) - self.state = 484 - self.block() + self.state = 501 + self.match(PyNestMLParser.NEWLINE) + self.state = 502 + self.match(PyNestMLParser.INDENT) + self.state = 503 + self.stmtsBody() + self.state = 504 + self.match(PyNestMLParser.DEDENT) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) @@ -3634,7 +3758,7 @@ def blockWithVariables(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 486 + self.state = 506 localctx.blockType = self._input.LT(1) _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & 30064771072) != 0)): @@ -3642,25 +3766,25 @@ def blockWithVariables(self): else: self._errHandler.reportMatch(self) self.consume() - self.state = 487 + self.state = 507 self.match(PyNestMLParser.COLON) - self.state = 488 + self.state = 508 self.match(PyNestMLParser.NEWLINE) - self.state = 489 + self.state = 509 self.match(PyNestMLParser.INDENT) - self.state = 491 + self.state = 511 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 490 + self.state = 510 self.declaration_newline() - self.state = 493 + self.state = 513 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==16 or _la==29 or _la==89): break - self.state = 495 + self.state = 515 self.match(PyNestMLParser.DEDENT) except RecognitionException as re: localctx.exception = re @@ -3684,10 +3808,19 @@ def UPDATE_KEYWORD(self): def COLON(self): return self.getToken(PyNestMLParser.COLON, 0) - def block(self): - return self.getTypedRuleContext(PyNestMLParser.BlockContext,0) + def NEWLINE(self): + return self.getToken(PyNestMLParser.NEWLINE, 0) + + def INDENT(self): + return self.getToken(PyNestMLParser.INDENT, 0) + + def stmtsBody(self): + return self.getTypedRuleContext(PyNestMLParser.StmtsBodyContext,0) + def DEDENT(self): + return self.getToken(PyNestMLParser.DEDENT, 0) + def getRuleIndex(self): return PyNestMLParser.RULE_updateBlock @@ -3706,12 +3839,18 @@ def updateBlock(self): self.enterRule(localctx, 74, self.RULE_updateBlock) try: self.enterOuterAlt(localctx, 1) - self.state = 497 + self.state = 517 self.match(PyNestMLParser.UPDATE_KEYWORD) - self.state = 498 + self.state = 518 self.match(PyNestMLParser.COLON) - self.state = 499 - self.block() + self.state = 519 + self.match(PyNestMLParser.NEWLINE) + self.state = 520 + self.match(PyNestMLParser.INDENT) + self.state = 521 + self.stmtsBody() + self.state = 522 + self.match(PyNestMLParser.DEDENT) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) @@ -3783,43 +3922,43 @@ def equationsBlock(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 501 + self.state = 524 self.match(PyNestMLParser.EQUATIONS_KEYWORD) - self.state = 502 + self.state = 525 self.match(PyNestMLParser.COLON) - self.state = 503 + self.state = 526 self.match(PyNestMLParser.NEWLINE) - self.state = 504 + self.state = 527 self.match(PyNestMLParser.INDENT) - self.state = 508 + self.state = 531 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 508 + self.state = 531 self._errHandler.sync(self) token = self._input.LA(1) if token in [16, 29]: - self.state = 505 + self.state = 528 self.inlineExpression() pass elif token in [89]: - self.state = 506 + self.state = 529 self.odeEquation() pass elif token in [30]: - self.state = 507 + self.state = 530 self.kernel() pass else: raise NoViableAltException(self) - self.state = 510 + self.state = 533 self._errHandler.sync(self) _la = self._input.LA(1) if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & 1610678272) != 0) or _la==89): break - self.state = 512 + self.state = 535 self.match(PyNestMLParser.DEDENT) except RecognitionException as re: localctx.exception = re @@ -3910,69 +4049,69 @@ def inputBlock(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 514 + self.state = 537 self.match(PyNestMLParser.INPUT_KEYWORD) - self.state = 515 + self.state = 538 self.match(PyNestMLParser.COLON) - self.state = 516 + self.state = 539 self.match(PyNestMLParser.NEWLINE) - self.state = 517 + self.state = 540 self.match(PyNestMLParser.INDENT) - self.state = 536 + self.state = 559 self._errHandler.sync(self) _la = self._input.LA(1) while True: - self.state = 520 + self.state = 543 self._errHandler.sync(self) - la_ = self._interp.adaptivePredict(self._input,53,self._ctx) + la_ = self._interp.adaptivePredict(self._input,54,self._ctx) if la_ == 1: - self.state = 518 + self.state = 541 self.spikeInputPort() pass elif la_ == 2: - self.state = 519 + self.state = 542 self.continuousInputPort() pass - self.state = 534 + self.state = 557 self._errHandler.sync(self) _la = self._input.LA(1) if _la==49: - self.state = 522 + self.state = 545 self.match(PyNestMLParser.LEFT_PAREN) - self.state = 531 + self.state = 554 self._errHandler.sync(self) _la = self._input.LA(1) if _la==89: - self.state = 523 + self.state = 546 self.parameter() - self.state = 528 + self.state = 551 self._errHandler.sync(self) _la = self._input.LA(1) while _la==74: - self.state = 524 + self.state = 547 self.match(PyNestMLParser.COMMA) - self.state = 525 + self.state = 548 self.parameter() - self.state = 530 + self.state = 553 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 533 + self.state = 556 self.match(PyNestMLParser.RIGHT_PAREN) - self.state = 538 + self.state = 561 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==89): break - self.state = 540 + self.state = 563 self.match(PyNestMLParser.DEDENT) except RecognitionException as re: localctx.exception = re @@ -4040,35 +4179,35 @@ def spikeInputPort(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 542 + self.state = 565 localctx.name = self.match(PyNestMLParser.NAME) - self.state = 547 + self.state = 570 self._errHandler.sync(self) _la = self._input.LA(1) if _la==56: - self.state = 543 + self.state = 566 self.match(PyNestMLParser.LEFT_SQUARE_BRACKET) - self.state = 544 + self.state = 567 localctx.sizeParameter = self.expression(0) - self.state = 545 + self.state = 568 self.match(PyNestMLParser.RIGHT_SQUARE_BRACKET) - self.state = 549 + self.state = 572 self.match(PyNestMLParser.LEFT_ANGLE_MINUS) - self.state = 553 + self.state = 576 self._errHandler.sync(self) _la = self._input.LA(1) while _la==43 or _la==44: - self.state = 550 + self.state = 573 self.inputQualifier() - self.state = 555 + self.state = 578 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 556 + self.state = 579 self.match(PyNestMLParser.SPIKE_KEYWORD) - self.state = 557 + self.state = 580 self.match(PyNestMLParser.NEWLINE) except RecognitionException as re: localctx.exception = re @@ -4133,27 +4272,27 @@ def continuousInputPort(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 559 + self.state = 582 localctx.name = self.match(PyNestMLParser.NAME) - self.state = 564 + self.state = 587 self._errHandler.sync(self) _la = self._input.LA(1) if _la==56: - self.state = 560 + self.state = 583 self.match(PyNestMLParser.LEFT_SQUARE_BRACKET) - self.state = 561 + self.state = 584 localctx.sizeParameter = self.expression(0) - self.state = 562 + self.state = 585 self.match(PyNestMLParser.RIGHT_SQUARE_BRACKET) - self.state = 566 + self.state = 589 self.dataType() - self.state = 567 + self.state = 590 self.match(PyNestMLParser.LEFT_ANGLE_MINUS) - self.state = 568 + self.state = 591 self.match(PyNestMLParser.CONTINUOUS_KEYWORD) - self.state = 569 + self.state = 592 self.match(PyNestMLParser.NEWLINE) except RecognitionException as re: localctx.exception = re @@ -4197,15 +4336,15 @@ def inputQualifier(self): self.enterRule(localctx, 84, self.RULE_inputQualifier) try: self.enterOuterAlt(localctx, 1) - self.state = 573 + self.state = 596 self._errHandler.sync(self) token = self._input.LA(1) if token in [43]: - self.state = 571 + self.state = 594 localctx.isInhibitory = self.match(PyNestMLParser.INHIBITORY_KEYWORD) pass elif token in [44]: - self.state = 572 + self.state = 595 localctx.isExcitatory = self.match(PyNestMLParser.EXCITATORY_KEYWORD) pass else: @@ -4292,61 +4431,61 @@ def outputBlock(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 575 + self.state = 598 self.match(PyNestMLParser.OUTPUT_KEYWORD) - self.state = 576 + self.state = 599 self.match(PyNestMLParser.COLON) - self.state = 577 + self.state = 600 self.match(PyNestMLParser.NEWLINE) - self.state = 578 + self.state = 601 self.match(PyNestMLParser.INDENT) - self.state = 595 + self.state = 618 self._errHandler.sync(self) token = self._input.LA(1) if token in [42]: - self.state = 579 + self.state = 602 localctx.isSpike = self.match(PyNestMLParser.SPIKE_KEYWORD) - self.state = 592 + self.state = 615 self._errHandler.sync(self) _la = self._input.LA(1) if _la==49: - self.state = 580 + self.state = 603 self.match(PyNestMLParser.LEFT_PAREN) - self.state = 589 + self.state = 612 self._errHandler.sync(self) _la = self._input.LA(1) if _la==89: - self.state = 581 + self.state = 604 localctx.attribute = self.parameter() - self.state = 586 + self.state = 609 self._errHandler.sync(self) _la = self._input.LA(1) while _la==74: - self.state = 582 + self.state = 605 self.match(PyNestMLParser.COMMA) - self.state = 583 + self.state = 606 localctx.attribute = self.parameter() - self.state = 588 + self.state = 611 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 591 + self.state = 614 self.match(PyNestMLParser.RIGHT_PAREN) pass elif token in [39]: - self.state = 594 + self.state = 617 localctx.isContinuous = self.match(PyNestMLParser.CONTINUOUS_KEYWORD) pass else: raise NoViableAltException(self) - self.state = 597 + self.state = 620 self.match(PyNestMLParser.NEWLINE) - self.state = 598 + self.state = 621 self.match(PyNestMLParser.DEDENT) except RecognitionException as re: localctx.exception = re @@ -4380,9 +4519,18 @@ def RIGHT_PAREN(self): def COLON(self): return self.getToken(PyNestMLParser.COLON, 0) - def block(self): - return self.getTypedRuleContext(PyNestMLParser.BlockContext,0) + def NEWLINE(self): + return self.getToken(PyNestMLParser.NEWLINE, 0) + + def INDENT(self): + return self.getToken(PyNestMLParser.INDENT, 0) + def stmtsBody(self): + return self.getTypedRuleContext(PyNestMLParser.StmtsBodyContext,0) + + + def DEDENT(self): + return self.getToken(PyNestMLParser.DEDENT, 0) def parameter(self, i:int=None): if i is None: @@ -4420,46 +4568,52 @@ def function(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 600 + self.state = 623 self.match(PyNestMLParser.FUNCTION_KEYWORD) - self.state = 601 + self.state = 624 self.match(PyNestMLParser.NAME) - self.state = 602 + self.state = 625 self.match(PyNestMLParser.LEFT_PAREN) - self.state = 611 + self.state = 634 self._errHandler.sync(self) _la = self._input.LA(1) if _la==89: - self.state = 603 + self.state = 626 self.parameter() - self.state = 608 + self.state = 631 self._errHandler.sync(self) _la = self._input.LA(1) while _la==74: - self.state = 604 + self.state = 627 self.match(PyNestMLParser.COMMA) - self.state = 605 + self.state = 628 self.parameter() - self.state = 610 + self.state = 633 self._errHandler.sync(self) _la = self._input.LA(1) - self.state = 613 + self.state = 636 self.match(PyNestMLParser.RIGHT_PAREN) - self.state = 615 + self.state = 638 self._errHandler.sync(self) _la = self._input.LA(1) if (((_la) & ~0x3f) == 0 and ((1 << _la) & 562949953453056) != 0) or _la==89 or _la==90: - self.state = 614 + self.state = 637 localctx.returnType = self.dataType() - self.state = 617 + self.state = 640 self.match(PyNestMLParser.COLON) - self.state = 618 - self.block() + self.state = 641 + self.match(PyNestMLParser.NEWLINE) + self.state = 642 + self.match(PyNestMLParser.INDENT) + self.state = 643 + self.stmtsBody() + self.state = 644 + self.match(PyNestMLParser.DEDENT) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) @@ -4501,9 +4655,9 @@ def parameter(self): self.enterRule(localctx, 90, self.RULE_parameter) try: self.enterOuterAlt(localctx, 1) - self.state = 620 + self.state = 646 self.match(PyNestMLParser.NAME) - self.state = 621 + self.state = 647 self.dataType() except RecognitionException as re: localctx.exception = re @@ -4563,11 +4717,11 @@ def constParameter(self): self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) - self.state = 623 + self.state = 649 localctx.name = self.match(PyNestMLParser.NAME) - self.state = 624 + self.state = 650 self.match(PyNestMLParser.EQUALS) - self.state = 625 + self.state = 651 localctx.value = self._input.LT(1) _la = self._input.LA(1) if not(_la==25 or ((((_la - 87)) & ~0x3f) == 0 and ((1 << (_la - 87)) & 27) != 0)): diff --git a/pynestml/generated/PyNestMLParserVisitor.py b/pynestml/generated/PyNestMLParserVisitor.py index dc4499256..30972fcda 100644 --- a/pynestml/generated/PyNestMLParserVisitor.py +++ b/pynestml/generated/PyNestMLParserVisitor.py @@ -79,11 +79,6 @@ def visitKernel(self, ctx:PyNestMLParser.KernelContext): return self.visitChildren(ctx) - # Visit a parse tree produced by PyNestMLParser#block. - def visitBlock(self, ctx:PyNestMLParser.BlockContext): - return self.visitChildren(ctx) - - # Visit a parse tree produced by PyNestMLParser#stmt. def visitStmt(self, ctx:PyNestMLParser.StmtContext): return self.visitChildren(ctx) @@ -129,6 +124,11 @@ def visitNamespaceDecoratorName(self, ctx:PyNestMLParser.NamespaceDecoratorNameC return self.visitChildren(ctx) + # Visit a parse tree produced by PyNestMLParser#stmtsBody. + def visitStmtsBody(self, ctx:PyNestMLParser.StmtsBodyContext): + return self.visitChildren(ctx) + + # Visit a parse tree produced by PyNestMLParser#returnStmt. def visitReturnStmt(self, ctx:PyNestMLParser.ReturnStmtContext): return self.visitChildren(ctx) diff --git a/pynestml/grammars/PyNestMLLexer.g4 b/pynestml/grammars/PyNestMLLexer.g4 index b5e36be4f..9b562117d 100644 --- a/pynestml/grammars/PyNestMLLexer.g4 +++ b/pynestml/grammars/PyNestMLLexer.g4 @@ -29,7 +29,7 @@ lexer grammar PyNestMLLexer; } // N.B. the zeroth channel is the normal channel, the first is HIDDEN, so COMMENT=2 - channels {COMMENT} + channels { COMMENT } DOCSTRING_TRIPLEQUOTE : '"""'; fragment NEWLINE_FRAG : '\r'? '\n'; // non-capturing newline, as a helper to define the channel rules @@ -43,21 +43,17 @@ lexer grammar PyNestMLLexer; DOCSTRING : DOCSTRING_TRIPLEQUOTE .*? DOCSTRING_TRIPLEQUOTE NEWLINE_FRAG+? -> channel(2); - SL_COMMENT: ('#' (~('\n' |'\r' ))*) -> channel(2); + SL_COMMENT : ('#' (~('\n' | '\r'))* ) -> channel(2); // we cannot capture the final \n here, because the comment might appear to the right of an expression - // newline is defined as a token - NEWLINE - : ( {self.atStartOfInput()}? WS - | ( '\r'? '\n' ) WS? - ) - {self.onNewLine()} - ; + // newline is handled inside the ``onNewLine()`` method of the PyNestMLLexerBase class + NEWLINE : ( { self.atStartOfInput() }? WS | ('\r'? '\n') WS? ) + { self.onNewLine() }; /** - * Symbols and literals are parsed first - * - * Decorator (@) keywords are defined with their @-symbol in front, because otherwise they would preclude the user from defining variables with the same name as a decorator keyword. (Rules are matched in the order in which they appear.) - */ + * Symbols and literals are parsed first + * + * Decorator (@) keywords are defined with their @-symbol in front, because otherwise they would preclude the user from defining variables with the same name as a decorator keyword. (Rules are matched in the order in which they appear.) + */ INTEGER_KEYWORD : 'integer'; REAL_KEYWORD : 'real'; @@ -142,16 +138,15 @@ lexer grammar PyNestMLLexer; /** - * Boolean values, i.e., true and false, should be handled as tokens in order to enable handling of lower - * and upper case definitions. Here, we allow both concepts, the python like syntax starting with upper case and - * the concept as currently used in NESTML with the lower case. - */ + * Boolean values, i.e., true and false, should be handled as tokens in order to enable handling of lower + * and upper case definitions. Here, we allow both concepts, the python like syntax starting with upper case and + * the concept as currently used in NESTML with the lower case. + */ BOOLEAN_LITERAL : 'true' | 'True' | 'false' | 'False' ; /** - * String literals are always enclosed in "...". - */ - + * String literals are always enclosed in double quotation marks. + */ STRING_LITERAL : '"' ('\\' (([ \t]+ ('\r'? '\n')?)|.) | ~[\\\r\n"])* '"'; NAME : ( [a-zA-Z] | '_' | '$' )( [a-zA-Z] | '_' | [0-9] | '$' )*; @@ -176,9 +171,8 @@ lexer grammar PyNestMLLexer; FLOAT : POINT_FLOAT | EXPONENT_FLOAT; fragment POINT_FLOAT : UNSIGNED_INTEGER? FULLSTOP UNSIGNED_INTEGER - | UNSIGNED_INTEGER FULLSTOP - ; + | UNSIGNED_INTEGER FULLSTOP; - fragment EXPONENT_FLOAT: ( UNSIGNED_INTEGER | POINT_FLOAT ) [eE] EXPONENT ; + fragment EXPONENT_FLOAT : ( UNSIGNED_INTEGER | POINT_FLOAT ) [eE] EXPONENT; - fragment EXPONENT: ( PLUS | MINUS )? UNSIGNED_INTEGER; + fragment EXPONENT : ( PLUS | MINUS )? UNSIGNED_INTEGER; diff --git a/pynestml/grammars/PyNestMLParser.g4 b/pynestml/grammars/PyNestMLParser.g4 index 5c5b4c270..e743c3be8 100644 --- a/pynestml/grammars/PyNestMLParser.g4 +++ b/pynestml/grammars/PyNestMLParser.g4 @@ -63,17 +63,16 @@ parser grammar PyNestMLParser; e.g., 10mV + V_m - (V_reset * 2)/ms, or a simple expression, e.g. 10mV. */ expression : leftParentheses=LEFT_PAREN term=expression rightParentheses=RIGHT_PAREN - | left=expression powOp=STAR_STAR right=expression - | unaryOperator term=expression - | left=expression (timesOp=STAR | divOp=FORWARD_SLASH | moduloOp=PERCENT) right=expression - | left=expression (plusOp=PLUS | minusOp=MINUS) right=expression - | left=expression bitOperator right=expression - | left=expression comparisonOperator right=expression - | logicalNot=NOT_KEYWORD term=expression - | left=expression logicalOperator right=expression - | condition=expression QUESTION ifTrue=expression COLON ifNot=expression - | simpleExpression - ; + | left=expression powOp=STAR_STAR right=expression + | unaryOperator term=expression + | left=expression (timesOp=STAR | divOp=FORWARD_SLASH | moduloOp=PERCENT) right=expression + | left=expression (plusOp=PLUS | minusOp=MINUS) right=expression + | left=expression bitOperator right=expression + | left=expression comparisonOperator right=expression + | logicalNot=NOT_KEYWORD term=expression + | left=expression logicalOperator right=expression + | condition=expression QUESTION ifTrue=expression COLON ifNot=expression + | simpleExpression; /** ASTSimpleExpression, consisting of a single element without combining operator, e.g., @@ -86,19 +85,32 @@ parser grammar PyNestMLParser; @attribute isInf: True iff, this expression shall represent the value infinity. */ simpleExpression : functionCall - | BOOLEAN_LITERAL // true & false; - | (UNSIGNED_INTEGER | FLOAT) (variable)? - | string=STRING_LITERAL - | isInf=INF_KEYWORD - | variable; - - unaryOperator : (unaryPlus=PLUS | unaryMinus=MINUS | unaryTilde=TILDE); - - bitOperator : (bitAnd=AMPERSAND | bitXor=CARET | bitOr=PIPE | bitShiftLeft=LEFT_LEFT_ANGLE | bitShiftRight=RIGHT_RIGHT_ANGLE); - - comparisonOperator : (lt=LEFT_ANGLE | le=LEFT_ANGLE_EQUALS | eq=EQUALS_EQUALS | ne=EXCLAMATION_EQUALS | ne2=LEFT_ANGLE_RIGHT_ANGLE | ge=RIGHT_ANGLE_EQUALS | gt=RIGHT_ANGLE); - - logicalOperator : (logicalAnd=AND_KEYWORD | logicalOr=OR_KEYWORD ); + | BOOLEAN_LITERAL // true & false; + | (UNSIGNED_INTEGER | FLOAT) (variable)? + | string=STRING_LITERAL + | isInf=INF_KEYWORD + | variable; + + unaryOperator : unaryPlus=PLUS + | unaryMinus=MINUS + | unaryTilde=TILDE; + + bitOperator : bitAnd=AMPERSAND + | bitXor=CARET + | bitOr=PIPE + | bitShiftLeft=LEFT_LEFT_ANGLE + | bitShiftRight=RIGHT_RIGHT_ANGLE; + + comparisonOperator : lt=LEFT_ANGLE + | le=LEFT_ANGLE_EQUALS + | eq=EQUALS_EQUALS + | ne=EXCLAMATION_EQUALS + | ne2=LEFT_ANGLE_RIGHT_ANGLE + | ge=RIGHT_ANGLE_EQUALS + | gt=RIGHT_ANGLE; + + logicalOperator : logicalAnd=AND_KEYWORD + | logicalOr=OR_KEYWORD; /** ASTVariable Provides a 'marker' AST node to identify variables used in expressions. @@ -107,8 +119,8 @@ parser grammar PyNestMLParser; @attribute differentialOrder: The corresponding differential order, e.g. 2 */ variable : name=NAME - (LEFT_SQUARE_BRACKET vectorParameter=expression RIGHT_SQUARE_BRACKET)? - (DIFFERENTIAL_ORDER)*; + (LEFT_SQUARE_BRACKET vectorParameter=expression RIGHT_SQUARE_BRACKET)? + (DIFFERENTIAL_ORDER)*; /** ASTFunctionCall Represents a function call, e.g. myFun("a", "b"). @@ -118,8 +130,8 @@ parser grammar PyNestMLParser; functionCall : calleeName=NAME LEFT_PAREN (expression (COMMA expression)*)? RIGHT_PAREN; /********************************************************************************************************************* - * Equations-Language - *********************************************************************************************************************/ + * Equations-Language + *********************************************************************************************************************/ inlineExpression : (recordable=RECORDABLE_KEYWORD)? INLINE_KEYWORD variableName=NAME dataType EQUALS expression (SEMICOLON)? decorator=anyDecorator* NEWLINE; @@ -128,28 +140,26 @@ parser grammar PyNestMLParser; kernel : KERNEL_KEYWORD variable EQUALS expression (KERNEL_JOINING variable EQUALS expression)* SEMICOLON? NEWLINE; /********************************************************************************************************************* - * Procedural-Language - *********************************************************************************************************************/ - - block : NEWLINE INDENT stmt+ DEDENT; + * Procedural-Language + *********************************************************************************************************************/ - stmt : smallStmt | compoundStmt; + stmt : NEWLINE? (smallStmt | compoundStmt); compoundStmt : ifStmt - | forStmt - | whileStmt; + | forStmt + | whileStmt; smallStmt : (assignment - | functionCall - | declaration - | returnStmt) NEWLINE; + | functionCall + | declaration + | returnStmt) NEWLINE; assignment : lhs_variable=variable - (directAssignment=EQUALS | - compoundSum=PLUS_EQUALS | - compoundMinus=MINUS_EQUALS | - compoundProduct=STAR_EQUALS | - compoundQuotient=FORWARD_SLASH_EQUALS) + (directAssignment=EQUALS + | compoundSum=PLUS_EQUALS + | compoundMinus=MINUS_EQUALS + | compoundProduct=STAR_EQUALS + | compoundQuotient=FORWARD_SLASH_EQUALS) expression; /** ASTDeclaration A variable declaration. It can be a simple declaration defining one or multiple variables: @@ -161,68 +171,68 @@ parser grammar PyNestMLParser; @attribute rhs: An optional initial expression, e.g., 'a real = 10+10' @attribute invariant: A single, optional invariant expression, e.g., '[a < 21]' */ - declaration : - (isRecordable=RECORDABLE_KEYWORD)? (isInlineExpression=INLINE_KEYWORD)? - variable (COMMA variable)* - dataType - ( EQUALS rhs = expression)? - (LEFT_LEFT_SQUARE invariant=expression RIGHT_RIGHT_SQUARE)? - decorator=anyDecorator*; - - declaration_newline: declaration NEWLINE; + declaration : (isRecordable=RECORDABLE_KEYWORD)? (isInlineExpression=INLINE_KEYWORD)? + variable (COMMA variable)* + dataType + (EQUALS rhs = expression)? + (LEFT_LEFT_SQUARE invariant=expression RIGHT_RIGHT_SQUARE)? + decorator=anyDecorator*; - /** ... - */ - anyDecorator : DECORATOR_HOMOGENEOUS | DECORATOR_HETEROGENEOUS | AT namespaceDecoratorNamespace DOUBLE_COLON namespaceDecoratorName; + declaration_newline : declaration NEWLINE; /** - ASTVariable Provides a 'marker' AST node to identify variables used in expressions. - @attribute name: The name of the variable without the differential order, e.g. V_m - @attribute differentialOrder: The corresponding differential order, e.g. 2 - */ + * Decorators on equations, expressions, declarations, etc. + */ + anyDecorator : DECORATOR_HOMOGENEOUS + | DECORATOR_HETEROGENEOUS + | AT namespaceDecoratorNamespace DOUBLE_COLON namespaceDecoratorName; + namespaceDecoratorNamespace : name=NAME; namespaceDecoratorName : name=NAME; + stmtsBody : stmt+; + /** ASTReturnStmt Models the return statement in a function. @expression An optional return expression, e.g., return tempVar */ returnStmt : RETURN_KEYWORD expression?; - ifStmt : ifClause - elifClause* - (elseClause)?; + ifStmt : ifClause elifClause* (elseClause)?; - ifClause : IF_KEYWORD expression COLON block; + ifClause : IF_KEYWORD expression COLON + NEWLINE INDENT stmtsBody DEDENT; - elifClause : ELIF_KEYWORD expression COLON block; + elifClause : ELIF_KEYWORD expression COLON + NEWLINE INDENT stmtsBody DEDENT; - elseClause : ELSE_KEYWORD COLON block; + elseClause : ELSE_KEYWORD COLON + NEWLINE INDENT stmtsBody DEDENT; - forStmt : FOR_KEYWORD var=NAME IN_KEYWORD start_from=expression ELLIPSIS end_at=expression STEP_KEYWORD - (negative=MINUS?) (UNSIGNED_INTEGER | FLOAT) - COLON - block; + forStmt : FOR_KEYWORD var=NAME IN_KEYWORD start_from=expression ELLIPSIS end_at=expression STEP_KEYWORD (negative=MINUS?) (UNSIGNED_INTEGER | FLOAT) COLON + NEWLINE INDENT stmtsBody DEDENT; - whileStmt : WHILE_KEYWORD expression COLON block; + whileStmt : WHILE_KEYWORD expression COLON + NEWLINE INDENT stmtsBody DEDENT; /********************************************************************************************************************* - * NestML: language root element - *********************************************************************************************************************/ + * NestML: language root element + *********************************************************************************************************************/ /** ASTNestMLCompilationUnit represents a collection of models. @attribute model: A list of processed models. - */ - nestMLCompilationUnit: ( model | NEWLINE )+ EOF; + */ + nestMLCompilationUnit : ( model | NEWLINE )+ EOF; -/********************************************************************************************************************* - * NestML model and model blocks - *********************************************************************************************************************/ + /********************************************************************************************************************* + * NestML model and model blocks + *********************************************************************************************************************/ - /** ASTModel Represents a single dynamical system model, such as a neuron or a synapse. + /* ASTModel Represents a single dynamical system model, such as a neuron or a synapse. @attribute Name: The name of the model, e.g., ht_neuron. @attribute body: The body of the model consisting of several sub-blocks. */ - model : MODEL_KEYWORD NAME modelBody; + model : MODEL_KEYWORD NAME COLON + modelBody; /** ASTBody The body of the model, e.g. internal, state, parameter... @attribute blockWithVariables: A single block of variables, e.g. the state block. @@ -231,21 +241,20 @@ parser grammar PyNestMLParser; @attribute outputBlock: A block of output declarations. @attribute updateBlock: A single update block containing the dynamic behavior. @attribute function: A block declaring a user-defined function. - */ - modelBody: COLON - NEWLINE INDENT ( blockWithVariables | equationsBlock | inputBlock | outputBlock | function | onReceiveBlock | onConditionBlock | updateBlock )+ DEDENT; + */ + modelBody : NEWLINE INDENT ( blockWithVariables | equationsBlock | inputBlock | outputBlock | function | onReceiveBlock | onConditionBlock | updateBlock )+ DEDENT; /** ASTOnReceiveBlock @attribute block implementation of the dynamics */ - onReceiveBlock: ON_RECEIVE_KEYWORD LEFT_PAREN inputPortName=NAME (COMMA constParameter)* RIGHT_PAREN COLON - block; + onReceiveBlock : ON_RECEIVE_KEYWORD LEFT_PAREN inputPortName=NAME (COMMA constParameter)* RIGHT_PAREN COLON + NEWLINE INDENT stmtsBody DEDENT; /** ASTOnConditionBlock @attribute block implementation of the dynamics */ - onConditionBlock: ON_CONDITION_KEYWORD LEFT_PAREN condition=expression (COMMA constParameter)* RIGHT_PAREN COLON - block; + onConditionBlock : ON_CONDITION_KEYWORD LEFT_PAREN condition=expression (COMMA constParameter)* RIGHT_PAREN COLON + NEWLINE INDENT stmtsBody DEDENT; /** ASTBlockWithVariables Represent a block with variables and constants, e.g.: state: @@ -256,10 +265,8 @@ parser grammar PyNestMLParser; @attribute internals: True iff the varblock is a state internals block. @attribute declaration: A list of corresponding declarations. */ - blockWithVariables: - blockType=(STATE_KEYWORD | PARAMETERS_KEYWORD | INTERNALS_KEYWORD) - COLON - NEWLINE INDENT declaration_newline+ DEDENT; + blockWithVariables : blockType=(STATE_KEYWORD | PARAMETERS_KEYWORD | INTERNALS_KEYWORD) COLON + NEWLINE INDENT declaration_newline+ DEDENT; /** ASTUpdateBlock The definition of a block where the dynamical behavior of the neuron is stated: update: @@ -267,14 +274,14 @@ parser grammar PyNestMLParser; integrate(V) @attribute block Implementation of the dynamics. */ - updateBlock: UPDATE_KEYWORD COLON - block; + updateBlock : UPDATE_KEYWORD COLON + NEWLINE INDENT stmtsBody DEDENT; /** ASTEquationsBlock A block declaring equations and inline expressions. @attribute inlineExpression: A single inline expression, e.g., inline V_m mV = ... @attribute odeEquation: A single ode equation statement, e.g., V_m' = ... */ - equationsBlock: EQUATIONS_KEYWORD COLON + equationsBlock : EQUATIONS_KEYWORD COLON NEWLINE INDENT ( inlineExpression | odeEquation | kernel )+ DEDENT; /** ASTInputBlock represents a single input block, e.g.: @@ -283,8 +290,8 @@ parser grammar PyNestMLParser; current_in pA <- continuous @attribute inputPort: A list of input ports. */ - inputBlock: INPUT_KEYWORD COLON - NEWLINE INDENT ((spikeInputPort | continuousInputPort) (LEFT_PAREN (parameter (COMMA parameter)*)? RIGHT_PAREN)?)+ DEDENT; + inputBlock : INPUT_KEYWORD COLON + NEWLINE INDENT ((spikeInputPort | continuousInputPort) (LEFT_PAREN (parameter (COMMA parameter)*)? RIGHT_PAREN)?)+ DEDENT; /** ASTInputPort represents a single input port, e.g.: spike_in[3] <- excitatory spike @@ -296,11 +303,10 @@ parser grammar PyNestMLParser; @attribute isSpike: Indicates that this input port accepts spikes. @attribute isContinuous: Indicates that this input port accepts continuous-time input. */ - spikeInputPort: - name=NAME - (LEFT_SQUARE_BRACKET sizeParameter=expression RIGHT_SQUARE_BRACKET)? - LEFT_ANGLE_MINUS inputQualifier* - SPIKE_KEYWORD NEWLINE; + spikeInputPort : name=NAME + (LEFT_SQUARE_BRACKET sizeParameter=expression RIGHT_SQUARE_BRACKET)? + LEFT_ANGLE_MINUS inputQualifier* + SPIKE_KEYWORD NEWLINE; continuousInputPort: name = NAME @@ -321,9 +327,9 @@ parser grammar PyNestMLParser; @attribute isSpike: true if and only if the neuron has a spike output. @attribute isContinuous: true if and only if the neuron has a continuous-time output. */ - outputBlock: OUTPUT_KEYWORD COLON - NEWLINE INDENT ((isSpike=SPIKE_KEYWORD (LEFT_PAREN (attribute=parameter (COMMA attribute=parameter)*)? RIGHT_PAREN)?) | isContinuous=CONTINUOUS_KEYWORD) - NEWLINE DEDENT; + outputBlock : OUTPUT_KEYWORD COLON + NEWLINE INDENT ((isSpike=SPIKE_KEYWORD (LEFT_PAREN (attribute=parameter (COMMA attribute=parameter)*)? RIGHT_PAREN)?) | isContinuous=CONTINUOUS_KEYWORD) + NEWLINE DEDENT; /** ASTFunction A single declaration of a user-defined function definition: function set_V_m(v mV): @@ -333,10 +339,8 @@ parser grammar PyNestMLParser; @attribute returnType: An arbitrary return type, e.g. string or mV. @attribute block: Implementation of the function. */ - function: FUNCTION_KEYWORD NAME LEFT_PAREN (parameter (COMMA parameter)*)? RIGHT_PAREN (returnType=dataType)? - COLON - block - ; + function: FUNCTION_KEYWORD NAME LEFT_PAREN (parameter (COMMA parameter)*)? RIGHT_PAREN (returnType=dataType)? COLON + NEWLINE INDENT stmtsBody DEDENT; /** ASTParameter represents a single parameter consisting of a name and the corresponding data type, e.g. T_in ms @@ -350,7 +354,7 @@ parser grammar PyNestMLParser; @attribute value: The corresponding default value. */ constParameter : name=NAME EQUALS value=(BOOLEAN_LITERAL - | UNSIGNED_INTEGER - | FLOAT - | STRING_LITERAL - | INF_KEYWORD); + | UNSIGNED_INTEGER + | FLOAT + | STRING_LITERAL + | INF_KEYWORD); diff --git a/pynestml/meta_model/ast_elif_clause.py b/pynestml/meta_model/ast_elif_clause.py index 1165cd3b7..8332409ca 100644 --- a/pynestml/meta_model/ast_elif_clause.py +++ b/pynestml/meta_model/ast_elif_clause.py @@ -20,21 +20,18 @@ # along with NEST. If not, see . from typing import List +from pynestml.meta_model.ast_expression import ASTExpression from pynestml.meta_model.ast_node import ASTNode +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody class ASTElifClause(ASTNode): - """ + r""" This class is used to store elif-clauses. - Grammar: - elifClause : 'elif' rhs BLOCK_OPEN block; - Attribute: - condition = None - block = None """ - def __init__(self, condition, block, *args, **kwargs): + def __init__(self, condition, stmts_body: ASTStmtsBody, *args, **kwargs): """ Standard constructor. @@ -42,11 +39,10 @@ def __init__(self, condition, block, *args, **kwargs): :param condition: the condition of the block. :type condition: ast_expression - :param block: a block of statements. - :type block: ast_block + :param stmts_body: a body of statements. """ super(ASTElifClause, self).__init__(*args, **kwargs) - self.block = block + self.stmts_body = stmts_body self.condition = condition def clone(self): @@ -56,13 +52,13 @@ def clone(self): :return: new AST node instance :rtype: ASTElifClause """ - block_dup = None - if self.block: - block_dup = self.block.clone() + stmts_body_dup = None + if self.stmts_body: + stmts_body_dup = self.stmts_body.clone() condition_dup = None if self.condition: condition_dup = self.condition.clone() - dup = ASTElifClause(block=block_dup, + dup = ASTElifClause(stmts_body=stmts_body_dup, condition=condition_dup, # ASTNode common attributes: source_position=self.source_position, @@ -74,21 +70,19 @@ def clone(self): return dup - def get_condition(self): + def get_condition(self) -> ASTExpression: """ - Returns the condition of the block. + Returns the condition of the elif. :return: the condition. - :rtype: ast_expression """ return self.condition - def get_block(self): + def get_stmts_body(self) -> ASTStmtsBody: """ - Returns the block of statements. - :return: the block of statements. - :rtype: ast_block + Returns the body of statements. + :return: the body of statements. """ - return self.block + return self.stmts_body def get_children(self) -> List[ASTNode]: r""" @@ -99,8 +93,8 @@ def get_children(self) -> List[ASTNode]: if self.get_condition(): children.append(self.get_condition()) - if self.get_block(): - children.append(self.get_block()) + if self.get_stmts_body(): + children.append(self.get_stmts_body()) return children @@ -111,4 +105,4 @@ def equals(self, other: ASTNode) -> bool: if not isinstance(other, ASTElifClause): return False - return self.get_condition().equals(other.get_condition()) and self.get_block().equals(other.get_block()) + return self.get_condition().equals(other.get_condition()) and self.get_stmts_body().equals(other.get_stmts_body()) diff --git a/pynestml/meta_model/ast_else_clause.py b/pynestml/meta_model/ast_else_clause.py index 55bd8fdea..a6c604107 100644 --- a/pynestml/meta_model/ast_else_clause.py +++ b/pynestml/meta_model/ast_else_clause.py @@ -22,28 +22,24 @@ from typing import List from pynestml.meta_model.ast_node import ASTNode +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody class ASTElseClause(ASTNode): - """ + r""" This class is used to store a single else-clause. - Grammar: - elseClause : 'else' BLOCK_OPEN block; - Attributes: - block = None """ - def __init__(self, block, *args, **kwargs): + def __init__(self, stmts_body: ASTStmtsBody, *args, **kwargs): """ Standard constructor. Parameters for superclass (ASTNode) can be passed through :python:`*args` and :python:`**kwargs`. - :param block: a block of statements. - :type block: ast_block + :param stmts_body: a body of statements. """ super(ASTElseClause, self).__init__(*args, **kwargs) - self.block = block + self.stmts_body = stmts_body def clone(self): """ @@ -52,10 +48,10 @@ def clone(self): :return: new AST node instance :rtype: ASTElseClause """ - block_dup = None - if self.block: - block_dup = self.block.clone() - dup = ASTElseClause(block=block_dup, + stmts_body_dup = None + if self.stmts_body: + stmts_body_dup = self.stmts_body.clone() + dup = ASTElseClause(stmts_body=stmts_body_dup, # ASTNode common attributes: source_position=self.source_position, scope=self.scope, @@ -66,21 +62,20 @@ def clone(self): return dup - def get_block(self): + def get_stmts_body(self) -> ASTStmtsBody: """ - Returns the block of statements. - :return: the block of statements. - :rtype: ast_block + Returns the body of statements. + :return: the body of statements. """ - return self.block + return self.stmts_body def get_children(self) -> List[ASTNode]: r""" Returns the children of this node, if any. :return: List of children of this node. """ - if self.get_block(): - return [self.get_block()] + if self.get_stmts_body(): + return [self.get_stmts_body()] return [] @@ -91,4 +86,4 @@ def equals(self, other: ASTNode) -> bool: if not isinstance(other, ASTElseClause): return False - return self.get_block().equals(other.get_block()) + return self.get_stmts_body().equals(other.get_stmts_body()) diff --git a/pynestml/meta_model/ast_for_stmt.py b/pynestml/meta_model/ast_for_stmt.py index 399071d01..191bf6cd9 100644 --- a/pynestml/meta_model/ast_for_stmt.py +++ b/pynestml/meta_model/ast_for_stmt.py @@ -22,23 +22,15 @@ from typing import List from pynestml.meta_model.ast_node import ASTNode +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody class ASTForStmt(ASTNode): - """ - This class is used to store a for-block. - Grammar: - forStmt : 'for' var=NAME 'in' vrom=rhs - '...' to=rhs 'step' step=signedNumericLiteral BLOCK_OPEN block BLOCK_CLOSE; - Attributes: - variable = None - start_from = None - end_at = None - step = None - block = None + r""" + This class is used to store a "for" statement. """ - def __init__(self, variable, start_from, end_at, step, block, *args, **kwargs): + def __init__(self, variable, start_from, end_at, step, stmts_body: ASTStmtsBody, *args, **kwargs): """ Standard constructor. @@ -52,15 +44,14 @@ def __init__(self, variable, start_from, end_at, step, block, *args, **kwargs): :type end_at: ast_expression :param step: the length of a single step. :type step: float/int - :param block: a block of statements. - :type block: ast_block + :param stmts_body: a body of statements. """ super(ASTForStmt, self).__init__(*args, **kwargs) - self.block = block - self.step = step - self.end_at = end_at - self.start_from = start_from self.variable = variable + self.start_from = start_from + self.end_at = end_at + self.step = step + self.stmts_body = stmts_body def clone(self): """ @@ -81,14 +72,14 @@ def clone(self): step_dup = None if self.step: step_dup = self.step - block_dup = None - if self.block: - block_dup = self.block.clone() + stmts_body_dup = None + if self.stmts_body: + stmts_body_dup = self.stmts_body.clone() dup = ASTForStmt(variable=variable_dup, start_from=start_from_dup, end_at=end_at_dup, step=step_dup, - block=block_dup, + stmts_body=stmts_body_dup, # ASTNode common attributes: source_position=self.source_position, scope=self.scope, @@ -131,13 +122,12 @@ def get_step(self): """ return self.step - def get_block(self): + def get_stmts_body(self) -> ASTStmtsBody: """ - Returns the block of statements. - :return: the block of statements. - :rtype: ast_block + Returns the body of statements. + :return: the body of statements. """ - return self.block + return self.stmts_body def get_children(self) -> List[ASTNode]: r""" @@ -151,8 +141,8 @@ def get_children(self) -> List[ASTNode]: if self.get_end_at(): children.append(self.get_end_at()) - if self.get_block(): - children.append(self.get_block()) + if self.get_stmts_body(): + children.append(self.get_stmts_body()) return children @@ -170,4 +160,4 @@ def equals(self, other: ASTNode) -> bool: return False if self.get_step() != other.get_step(): return False - return self.get_block().equals(other.get_block()) + return self.get_stmts_body().equals(other.get_stmts_body()) diff --git a/pynestml/meta_model/ast_function.py b/pynestml/meta_model/ast_function.py index 842c086ad..989a7dfae 100644 --- a/pynestml/meta_model/ast_function.py +++ b/pynestml/meta_model/ast_function.py @@ -23,7 +23,7 @@ from copy import copy -from pynestml.meta_model.ast_block import ASTBlock +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody from pynestml.meta_model.ast_data_type import ASTDataType from pynestml.meta_model.ast_node import ASTNode from pynestml.meta_model.ast_parameter import ASTParameter @@ -54,7 +54,7 @@ class ASTFunction(ASTNode): type_symbol = None """ - def __init__(self, name: str, parameters: List[ASTParameter], return_type: Optional[ASTDataType], block: ASTBlock, type_symbol=None, *args, **kwargs): + def __init__(self, name: str, parameters: List[ASTParameter], return_type: Optional[ASTDataType], stmts_body: ASTStmtsBody, type_symbol=None, *args, **kwargs): """ Standard constructor. @@ -63,13 +63,13 @@ def __init__(self, name: str, parameters: List[ASTParameter], return_type: Optio :param name: the name of the defined function. :param parameters: (Optional) Set of parameters. :param return_type: (Optional) Return type. - :param block: a block of declarations. + :param stmts_body: a body of declarations. """ super(ASTFunction, self).__init__(*args, **kwargs) - self.block = block - self.return_type = return_type - self.parameters = parameters self.name = name + self.parameters = parameters + self.return_type = return_type + self.stmts_body = stmts_body self.type_symbol = type_symbol def clone(self): @@ -79,9 +79,9 @@ def clone(self): :return: new AST node instance :rtype: ASTFunction """ - block_dup = None - if self.block: - block_dup = self.block.clone() + stmts_body_dup = None + if self.stmts_body: + stmts_body_dup = self.stmts_body.clone() return_type_dup = None if self.return_type: return_type_dup = self.return_type.clone() @@ -90,7 +90,7 @@ def clone(self): dup = ASTFunction(name=self.name, parameters=parameters_dup, return_type=return_type_dup, - block=block_dup, + stmts_body=stmts_body_dup, type_symbol=self.type_symbol, # ASTNode common attributes: source_position=self.source_position, @@ -140,13 +140,12 @@ def get_return_type(self): """ return self.return_type - def get_block(self): + def get_stmts_body(self) -> ASTStmtsBody: """ - Returns the block containing the definitions. - :return: the block of the definitions. - :rtype: ast_block + Returns the body containing the statements. + :return: the body """ - return self.block + return self.stmts_body def get_type_symbol(self): """ @@ -175,8 +174,8 @@ def get_children(self) -> List[ASTNode]: if self.has_return_type(): children.append(self.get_return_type()) - if self.get_block(): - children.append(self.get_block()) + if self.get_stmts_body(): + children.append(self.get_stmts_body()) return children @@ -206,4 +205,4 @@ def equals(self, other: ASTNode) -> bool: and not self.get_return_type().equals(other.get_return_type())): return False - return self.get_block().equals(other.get_block()) + return self.get_stmts_body().equals(other.get_stmts_body()) diff --git a/pynestml/meta_model/ast_if_clause.py b/pynestml/meta_model/ast_if_clause.py index 36b8cdc9b..999485f9b 100644 --- a/pynestml/meta_model/ast_if_clause.py +++ b/pynestml/meta_model/ast_if_clause.py @@ -22,19 +22,15 @@ from typing import List from pynestml.meta_model.ast_node import ASTNode +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody class ASTIfClause(ASTNode): - """ - This class is used to store a single if-clause. - Grammar: - ifClause : 'if' expr BLOCK_OPEN block; - Attributes: - condition = None - block = None + r""" + This class is used to store a single ``if``-clause. """ - def __init__(self, condition, block, *args, **kwargs): + def __init__(self, condition, stmts_body: ASTStmtsBody, *args, **kwargs): """ Standard constructor. @@ -43,11 +39,10 @@ def __init__(self, condition, block, *args, **kwargs): :param condition: the condition of the block. :type condition: ASTExpression :param block: a block of statements. - :type block: ASTBlock """ super(ASTIfClause, self).__init__(*args, **kwargs) - self.block = block self.condition = condition + self.stmts_body = stmts_body def clone(self): """ @@ -56,14 +51,14 @@ def clone(self): :return: new AST node instance :rtype: ASTIfClause """ - block_dup = None - if self.block: - block_dup = self.block.clone() + stmts_body_dup = None + if self.stmts_body: + stmts_body_dup = self.stmts_body.clone() condition_dup = None if self.condition: condition_dup = self.condition.clone() dup = ASTIfClause(condition=condition_dup, - block=block_dup, + stmts_body=stmts_body_dup, # ASTNode common attributes: source_position=self.source_position, scope=self.scope, @@ -76,19 +71,18 @@ def clone(self): def get_condition(self): """ - Returns the condition of the block. + Returns the condition of the if statement. :return: the condition. :rtype: ASTExpression """ return self.condition - def get_block(self): + def get_stmts_body(self) -> ASTStmtsBody: """ - Returns the block of statements. - :return: the block of statements. - :rtype: ASTBlock + Returns the body of statements. + :return: the body of statements. """ - return self.block + return self.stmts_body def get_children(self) -> List[ASTNode]: r""" @@ -100,8 +94,8 @@ def get_children(self) -> List[ASTNode]: if self.get_condition(): children.append(self.get_condition()) - if self.get_block(): - children.append(self.get_block()) + if self.get_stmts_body(): + children.append(self.get_stmts_body()) return children @@ -111,4 +105,4 @@ def equals(self, other: ASTNode) -> bool: """ if not isinstance(other, ASTIfClause): return False - return self.get_condition().equals(other.get_condition()) and self.get_block().equals(other.get_block()) + return self.get_condition().equals(other.get_condition()) and self.get_stmts_body().equals(other.get_stmts_body()) diff --git a/pynestml/meta_model/ast_node_factory.py b/pynestml/meta_model/ast_node_factory.py index 781d75f9e..63775f023 100644 --- a/pynestml/meta_model/ast_node_factory.py +++ b/pynestml/meta_model/ast_node_factory.py @@ -24,7 +24,7 @@ from pynestml.meta_model.ast_arithmetic_operator import ASTArithmeticOperator from pynestml.meta_model.ast_assignment import ASTAssignment from pynestml.meta_model.ast_bit_operator import ASTBitOperator -from pynestml.meta_model.ast_block import ASTBlock +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody from pynestml.meta_model.ast_block_with_variables import ASTBlockWithVariables from pynestml.meta_model.ast_comparison_operator import ASTComparisonOperator from pynestml.meta_model.ast_compound_stmt import ASTCompoundStmt @@ -101,8 +101,8 @@ def create_ast_bit_operator(cls, is_bit_and=False, is_bit_xor=False, is_bit_or=F @classmethod def create_ast_block(cls, stmts, source_position): - # type: (list(ASTSmallStmt|ASTCompoundStmt),ASTSourceLocation) -> ASTBlock - return ASTBlock(stmts, source_position=source_position) + # type: (list(ASTSmallStmt|ASTCompoundStmt),ASTSourceLocation) -> ASTStmtsBody + return ASTStmtsBody(stmts, source_position=source_position) @classmethod def create_ast_block_with_variables(cls, is_state=False, is_parameters=False, is_internals=False, @@ -162,12 +162,12 @@ def create_ast_declaration(cls, @classmethod def create_ast_elif_clause(cls, condition, block, source_position=None): - # type: (ASTExpression|ASTSimpleExpression,ASTBlock,ASTSourceLocation) -> ASTElifClause + # type: (ASTExpression|ASTSimpleExpression,ASTStmtsBody,ASTSourceLocation) -> ASTElifClause return ASTElifClause(condition, block, source_position=source_position) @classmethod def create_ast_else_clause(cls, block, source_position): - # type: (ASTBlock,ASTSourceLocation) -> ASTElseClause + # type: (ASTStmtsBody,ASTSourceLocation) -> ASTElseClause return ASTElseClause(block, source_position=source_position) @classmethod @@ -222,14 +222,14 @@ def create_ast_for_stmt(cls, start_from, # type: Union(ASTSimpleExpression,ASTExpression) end_at, # type: Union(ASTSimpleExpression,ASTExpression) step=0, # type: float - block=None, # type: ASTBlock + block=None, # type: ASTStmtsBody source_position=None # type: ASTSourceLocation ): # type: (...) -> ASTForStmt return ASTForStmt(variable, start_from, end_at, step, block, source_position=source_position) @classmethod def create_ast_function(cls, name, parameters, return_type, block, source_position): - # type: (str,(None|list(ASTParameter)),(ASTDataType|None),ASTBlock,ASTSourceLocation) -> ASTFunction + # type: (str,(None|list(ASTParameter)),(ASTDataType|None),ASTStmtsBody,ASTSourceLocation) -> ASTFunction return ASTFunction(name, parameters, return_type, block, source_position=source_position) @classmethod @@ -239,7 +239,7 @@ def create_ast_function_call(cls, callee_name, args, source_position=None): @classmethod def create_ast_if_clause(cls, condition, block, source_position): - # type: (ASTSimpleExpression|ASTExpression,ASTBlock,ASTSourceLocation) -> ASTIfClause + # type: (ASTSimpleExpression|ASTExpression,ASTStmtsBody,ASTSourceLocation) -> ASTIfClause return ASTIfClause(condition, block, source_position=source_position) @classmethod @@ -355,7 +355,7 @@ def create_ast_unit_type(cls, @classmethod def create_ast_update_block(cls, block, source_position): - # type: (ASTBlock,ASTSourceLocation) -> ASTUpdateBlock + # type: (ASTStmtsBody,ASTSourceLocation) -> ASTUpdateBlock return ASTUpdateBlock(block, source_position=source_position) @classmethod @@ -369,7 +369,7 @@ def create_ast_variable(cls, name: str, differential_order: int = 0, vector_para @classmethod def create_ast_while_stmt(cls, condition, # type: Union(ASTSimpleExpression,ASTExpression) - block, # type: ASTBlock + block, # type: ASTStmtsBody source_position # type: ASTSourceLocation ): # type: (...) -> ASTWhileStmt return ASTWhileStmt(condition, block, source_position=source_position) diff --git a/pynestml/meta_model/ast_on_condition_block.py b/pynestml/meta_model/ast_on_condition_block.py index d8e1ac4cd..6f38044d8 100644 --- a/pynestml/meta_model/ast_on_condition_block.py +++ b/pynestml/meta_model/ast_on_condition_block.py @@ -23,7 +23,7 @@ from typing import Any, List, Optional, Mapping -from pynestml.meta_model.ast_block import ASTBlock +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody from pynestml.meta_model.ast_expression import ASTExpression from pynestml.meta_model.ast_node import ASTNode @@ -33,14 +33,14 @@ class ASTOnConditionBlock(ASTNode): This class is used to store a declaration of an onCondition block """ - def __init__(self, block: ASTBlock, cond_expr: ASTExpression, const_parameters: Optional[Mapping] = None, *args, **kwargs): + def __init__(self, stmts_body: ASTStmtsBody, cond_expr: ASTExpression, const_parameters: Optional[Mapping] = None, *args, **kwargs): r""" Standard constructor. - :param block: a block of definitions. + :param stmts_body: a body of statements. :param source_position: the position of this element in the source file. """ super(ASTOnConditionBlock, self).__init__(*args, **kwargs) - self.block = block + self.stmts_body = stmts_body self.cond_expr = cond_expr self.const_parameters = const_parameters if self.const_parameters is None: @@ -52,7 +52,7 @@ def clone(self) -> ASTOnConditionBlock: :return: new AST node instance """ - dup = ASTOnConditionBlock(block=self.block.clone(), + dup = ASTOnConditionBlock(stmts_body=self.stmts_body.clone(), cond_expr=self.cond_expr, const_parameters=self.const_parameters, # ASTNode common attributes: @@ -68,12 +68,12 @@ def clone(self) -> ASTOnConditionBlock: def get_const_parameters(self): return self.const_parameters - def get_block(self) -> ASTBlock: + def get_stmts_body(self) -> ASTStmtsBody: r""" - Returns the block of definitions. - :return: the block + Returns the body of statements. + :return: the body of statements """ - return self.block + return self.stmts_body def get_cond_expr(self) -> str: r""" @@ -91,8 +91,8 @@ def get_children(self) -> List[ASTNode]: if self.cond_expr: children.append(self.cond_expr) - if self.get_block(): - children.append(self.get_block()) + if self.get_stmts_body(): + children.append(self.get_stmts_body()) return children @@ -103,4 +103,4 @@ def equals(self, other: ASTNode) -> bool: if not isinstance(other, ASTOnConditionBlock): return False - return self.get_block().equals(other.get_block()) and self.cond_expr == other.cond_expr + return self.get_stmts_body().equals(other.get_stmts_body()) and self.cond_expr == other.cond_expr diff --git a/pynestml/meta_model/ast_on_receive_block.py b/pynestml/meta_model/ast_on_receive_block.py index d7ca37812..9118eea4c 100644 --- a/pynestml/meta_model/ast_on_receive_block.py +++ b/pynestml/meta_model/ast_on_receive_block.py @@ -23,7 +23,7 @@ from typing import Any, List, Optional, Mapping -from pynestml.meta_model.ast_block import ASTBlock +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody from pynestml.meta_model.ast_node import ASTNode @@ -38,14 +38,14 @@ class ASTOnReceiveBlock(ASTNode): """ - def __init__(self, block: ASTBlock, port_name: str, const_parameters: Optional[Mapping] = None, *args, **kwargs): + def __init__(self, stmts_body: ASTStmtsBody, port_name: str, const_parameters: Optional[Mapping] = None, *args, **kwargs): r""" Standard constructor. - :param block: a block of definitions. + :param stmts_body: a body of statements. :param source_position: the position of this element in the source file. """ super(ASTOnReceiveBlock, self).__init__(*args, **kwargs) - self.block = block + self.stmts_body = stmts_body self.port_name = port_name self.const_parameters = const_parameters if self.const_parameters is None: @@ -57,7 +57,7 @@ def clone(self) -> ASTOnReceiveBlock: :return: new AST node instance """ - dup = ASTOnReceiveBlock(block=self.block.clone(), + dup = ASTOnReceiveBlock(stmts_body=self.stmts_body.clone(), port_name=self.port_name, const_parameters=self.const_parameters, # ASTNode common attributes: @@ -73,12 +73,12 @@ def clone(self) -> ASTOnReceiveBlock: def get_const_parameters(self): return self.const_parameters - def get_block(self) -> ASTBlock: + def get_stmts_body(self) -> ASTStmtsBody: r""" - Returns the block of definitions. - :return: the block + Returns the body of statements. + :return: the body of statements """ - return self.block + return self.stmts_body def get_port_name(self) -> str: r""" @@ -92,7 +92,7 @@ def get_children(self) -> List[ASTNode]: Returns the children of this node, if any. :return: List of children of this node. """ - return [self.get_block()] + return [self.get_stmts_body()] def equals(self, other: ASTNode) -> bool: r""" @@ -101,4 +101,4 @@ def equals(self, other: ASTNode) -> bool: if not isinstance(other, ASTOnReceiveBlock): return False - return self.get_block().equals(other.get_block()) and self.port_name == other.port_name + return self.get_stmts_body().equals(other.get_stmts_body()) and self.port_name == other.port_name diff --git a/pynestml/meta_model/ast_block.py b/pynestml/meta_model/ast_stmts_body.py similarity index 84% rename from pynestml/meta_model/ast_block.py rename to pynestml/meta_model/ast_stmts_body.py index 436378e43..52e7159d9 100644 --- a/pynestml/meta_model/ast_block.py +++ b/pynestml/meta_model/ast_stmts_body.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# ast_block.py +# ast_stmts_body.py # # This file is part of NEST. # @@ -24,7 +24,7 @@ from pynestml.meta_model.ast_node import ASTNode -class ASTBlock(ASTNode): +class ASTStmtsBody(ASTNode): """ This class is used to store a single block of declarations, i.e., statements. Grammar: @@ -49,7 +49,7 @@ def __init__(self, stmts, *args, **kwargs): assert (stmt is not None and isinstance(stmt, ASTStmt)), \ '(PyNestML.ASTBlock) No or wrong type of statement provided (%s)!' % type(stmt) - super(ASTBlock, self).__init__(*args, **kwargs) + super(ASTStmtsBody, self).__init__(*args, **kwargs) self.stmts = stmts def clone(self): @@ -60,14 +60,14 @@ def clone(self): :rtype: ASTBlock """ stmts_dup = [stmt.clone() for stmt in self.stmts] - dup = ASTBlock(stmts_dup, - # ASTNode common attriutes: - source_position=self.source_position, - scope=self.scope, - comment=self.comment, - pre_comments=[s for s in self.pre_comments], - in_comment=self.in_comment, - implicit_conversion_factor=self.implicit_conversion_factor) + dup = ASTStmtsBody(stmts_dup, + # ASTNode common attriutes: + source_position=self.source_position, + scope=self.scope, + comment=self.comment, + pre_comments=[s for s in self.pre_comments], + in_comment=self.in_comment, + implicit_conversion_factor=self.implicit_conversion_factor) return dup @@ -108,7 +108,7 @@ def equals(self, other: ASTNode) -> bool: r""" The equality method. """ - if not isinstance(other, ASTBlock): + if not isinstance(other, ASTStmtsBody): return False if len(self.get_stmts()) != len(other.get_stmts()): return False diff --git a/pynestml/meta_model/ast_update_block.py b/pynestml/meta_model/ast_update_block.py index 27c84fa1a..6a7f05dc3 100644 --- a/pynestml/meta_model/ast_update_block.py +++ b/pynestml/meta_model/ast_update_block.py @@ -21,41 +21,26 @@ from typing import List -from pynestml.meta_model.ast_block import ASTBlock +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody from pynestml.meta_model.ast_node import ASTNode class ASTUpdateBlock(ASTNode): + r""" + The ``update`` block in the model. """ - This class is used to store dynamic blocks. - ASTUpdateBlock is a special function definition: - update: - if r == 0: # not refractory - integrate(V) - @attribute block Implementation of the dynamics. - Grammar: - updateBlock: - 'update' - BLOCK_OPEN - block - BLOCK_CLOSE; - Attributes: - block = None - """ - - def __init__(self, block, *args, **kwargs): + def __init__(self, stmts_body: ASTStmtsBody, *args, **kwargs): """ Standard constructor. Parameters for superclass (ASTNode) can be passed through :python:`*args` and :python:`**kwargs`. :param block: a block of definitions. - :type block: ASTBlock """ super(ASTUpdateBlock, self).__init__(*args, **kwargs) - assert isinstance(block, ASTBlock) - self.block = block + assert isinstance(stmts_body, ASTStmtsBody) + self.stmts_body = stmts_body def clone(self): """ @@ -64,7 +49,7 @@ def clone(self): :return: new AST node instance :rtype: ASTUpdateBlock """ - dup = ASTUpdateBlock(block=self.block.clone(), + dup = ASTUpdateBlock(stmts_body=self.stmts_body.clone(), # ASTNode common attributes: source_position=self.source_position, scope=self.scope, @@ -75,20 +60,19 @@ def clone(self): return dup - def get_block(self): + def get_stmts_body(self) -> ASTStmtsBody: """ - Returns the block of definitions. - :return: the block - :rtype: ASTBlock + Returns the body of statements. + :return: the statements body """ - return self.block + return self.stmts_body def get_children(self) -> List[ASTNode]: r""" Returns the children of this node, if any. :return: List of children of this node. """ - return [self.get_block()] + return [self.get_stmts_body()] def equals(self, other: ASTNode) -> bool: r""" @@ -96,4 +80,5 @@ def equals(self, other: ASTNode) -> bool: """ if not isinstance(other, ASTUpdateBlock): return False - return self.get_block().equals(other.get_block()) + + return self.get_stmts_body().equals(other.get_stmts_body()) diff --git a/pynestml/meta_model/ast_while_stmt.py b/pynestml/meta_model/ast_while_stmt.py index 88d87eb22..1a1c51138 100644 --- a/pynestml/meta_model/ast_while_stmt.py +++ b/pynestml/meta_model/ast_while_stmt.py @@ -21,7 +21,7 @@ from typing import List -from pynestml.meta_model.ast_block import ASTBlock +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody from pynestml.meta_model.ast_expression import ASTExpression from pynestml.meta_model.ast_node import ASTNode @@ -36,19 +36,18 @@ class ASTWhileStmt(ASTNode): block = None """ - def __init__(self, condition: ASTExpression, block: ASTBlock, *args, **kwargs): + def __init__(self, condition: ASTExpression, stmts_body: ASTStmtsBody, *args, **kwargs): """ Standard constructor. Parameters for superclass (ASTNode) can be passed through :python:`*args` and :python:`**kwargs`. - :param condition: the condition of the block. + :param condition: the condition of the ``while`` loop. :type condition: ASTExpression - :param block: a block of statements. - :type block: ASTBlock + :param stmts_body: a body of statements. """ super(ASTWhileStmt, self).__init__(*args, **kwargs) - self.block = block + self.stmts_body = stmts_body self.condition = condition def clone(self): @@ -58,13 +57,13 @@ def clone(self): :return: new AST node instance :rtype: ASTWhileStmt """ - block_dup = None - if self.block: - block_dup = self.block.clone() + stmts_body_dup = None + if self.stmts_body: + stmts_body_dup = self.stmts_body.clone() condition_dup = None if self.condition: condition_dup = self.condition.clone() - dup = ASTWhileStmt(block=block_dup, + dup = ASTWhileStmt(stmts_body=stmts_body_dup, condition=condition_dup, # ASTNode common attributes: source_position=self.source_position, @@ -84,13 +83,12 @@ def get_condition(self): """ return self.condition - def get_block(self): + def get_stmts_body(self) -> ASTStmtsBody: """ - Returns the block of statements. - :return: the block of statements. - :rtype: ASTBlock + Returns the body of statements. + :return: the body of statements. """ - return self.block + return self.stmts_body def get_children(self) -> List[ASTNode]: r""" @@ -101,8 +99,8 @@ def get_children(self) -> List[ASTNode]: if self.get_condition(): children.append(self.get_condition()) - if self.get_block(): - children.append(self.get_block()) + if self.get_stmts_body(): + children.append(self.get_stmts_body()) return children @@ -112,4 +110,4 @@ def equals(self, other: ASTNode) -> bool: """ if not isinstance(other, ASTWhileStmt): return False - return self.get_condition().equals(other.get_condition()) and self.get_block().equals(other.get_block()) + return self.get_condition().equals(other.get_condition()) and self.get_stmts_body().equals(other.get_stmts_body()) diff --git a/pynestml/transformers/synapse_post_neuron_transformer.py b/pynestml/transformers/synapse_post_neuron_transformer.py index 5ba8aef26..81089ecb2 100644 --- a/pynestml/transformers/synapse_post_neuron_transformer.py +++ b/pynestml/transformers/synapse_post_neuron_transformer.py @@ -486,7 +486,7 @@ def mark_post_port(_expr=None): if self.is_post_port(port.name, new_neuron.name, new_synapse.name): post_receive_blocks = ASTUtils.get_on_receive_blocks_by_input_port_name(new_synapse, port.name) for post_receive_block in post_receive_blocks: - stmts = post_receive_block.get_block().get_stmts() + stmts = post_receive_block.get_stmts_body().get_stmts() for stmt in stmts: if stmt.is_small_stmt() \ and stmt.small_stmt.is_assignment() \ diff --git a/pynestml/utils/ast_utils.py b/pynestml/utils/ast_utils.py index d66318130..14a18f242 100644 --- a/pynestml/utils/ast_utils.py +++ b/pynestml/utils/ast_utils.py @@ -31,7 +31,7 @@ from pynestml.frontend.frontend_configuration import FrontendConfiguration from pynestml.generated.PyNestMLLexer import PyNestMLLexer from pynestml.meta_model.ast_assignment import ASTAssignment -from pynestml.meta_model.ast_block import ASTBlock +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody from pynestml.meta_model.ast_block_with_variables import ASTBlockWithVariables from pynestml.meta_model.ast_declaration import ASTDeclaration from pynestml.meta_model.ast_elif_clause import ASTElifClause @@ -518,7 +518,7 @@ def contains_convolve_call(cls, variable: VariableSymbol) -> bool: return False @classmethod - def get_declaration_by_name(cls, blocks: Union[ASTBlock, List[ASTBlock]], var_name: str) -> Optional[ASTDeclaration]: + def get_declaration_by_name(cls, blocks: Union[ASTStmtsBody, List[ASTStmtsBody]], var_name: str) -> Optional[ASTDeclaration]: """ Get a declaration by variable name. :param blocks: the block or blocks to look for the variable in @@ -534,7 +534,7 @@ def get_declaration_by_name(cls, blocks: Union[ASTBlock, List[ASTBlock]], var_na return None @classmethod - def all_variables_defined_in_block(cls, blocks: Union[ASTBlock, List[ASTBlock]]) -> List[ASTVariable]: + def all_variables_defined_in_block(cls, blocks: Union[ASTStmtsBody, List[ASTStmtsBody]]) -> List[ASTVariable]: """return a list of all variable declarations in a block or blocks""" if isinstance(blocks, ASTNode): blocks = [blocks] @@ -998,7 +998,7 @@ def add_ode_to_variable(cls, ode_equation: ASTOdeEquation): @classmethod def get_statements_from_block(cls, var_name, block): """XXX: only simple statements such as assignments are supported for now. if..then..else compound statements and so are not yet supported.""" - block = block.get_block() + block = block.get_stmts_body() all_stmts = block.get_stmts() stmts = [] for node in all_stmts: @@ -1200,9 +1200,9 @@ def add_assignment_to_update_block(cls, assignment: ASTAssignment, neuron: ASTMo source_position=ASTSourceLocation.get_added_source_position()) if not neuron.get_update_blocks(): neuron.create_empty_update_block() - neuron.get_update_blocks()[0].get_block().get_stmts().append(stmt) - small_stmt.update_scope(neuron.get_update_blocks()[0].get_block().get_scope()) - stmt.update_scope(neuron.get_update_blocks()[0].get_block().get_scope()) + neuron.get_update_blocks()[0].get_stmts_body().get_stmts().append(stmt) + small_stmt.update_scope(neuron.get_update_blocks()[0].get_stmts_body().get_scope()) + stmt.update_scope(neuron.get_update_blocks()[0].get_stmts_body().get_scope()) return neuron @classmethod @@ -1220,9 +1220,9 @@ def add_declaration_to_update_block(cls, declaration: ASTDeclaration, neuron: AS source_position=ASTSourceLocation.get_added_source_position()) if not neuron.get_update_blocks(): neuron.create_empty_update_block() - neuron.get_update_blocks()[0].get_block().get_stmts().append(stmt) - small_stmt.update_scope(neuron.get_update_blocks()[0].get_block().get_scope()) - stmt.update_scope(neuron.get_update_blocks()[0].get_block().get_scope()) + neuron.get_update_blocks()[0].get_stmts_body().get_stmts().append(stmt) + small_stmt.update_scope(neuron.get_update_blocks()[0].get_stmts_body().get_scope()) + stmt.update_scope(neuron.get_update_blocks()[0].get_stmts_body().get_scope()) return neuron @classmethod @@ -1680,7 +1680,7 @@ def collect_vars(_expr=None): return vars_used_ @classmethod - def get_declarations_from_block(cls, var_name: str, block: ASTBlock) -> List[ASTDeclaration]: + def get_declarations_from_block(cls, var_name: str, block: ASTStmtsBody) -> List[ASTDeclaration]: """ Get declarations from the given block containing the given variable on the left-hand side. @@ -2441,7 +2441,7 @@ def get_function_calls(cls, ast_node: ASTNode, function_list: List[str]) -> List return res @classmethod - def resolve_to_variable_symbol_in_blocks(cls, variable_name: str, blocks: List[ASTBlock]): + def resolve_to_variable_symbol_in_blocks(cls, variable_name: str, blocks: List[ASTStmtsBody]): r""" Resolve a variable (by name) to its corresponding ``Symbol`` within the AST blocks in ``blocks``. """ diff --git a/pynestml/utils/model_parser.py b/pynestml/utils/model_parser.py index d11618119..d67612eab 100644 --- a/pynestml/utils/model_parser.py +++ b/pynestml/utils/model_parser.py @@ -23,14 +23,15 @@ from antlr4 import CommonTokenStream, FileStream, InputStream from antlr4.error.ErrorStrategy import BailErrorStrategy, DefaultErrorStrategy -from antlr4.error.ErrorListener import ConsoleErrorListener -from pynestml.cocos.co_cos_manager import CoCosManager +from antlr4.error.ErrorListener import ConsoleErrorListener, ErrorListener +from antlr4.error.Errors import ParseCancellationException +from pynestml.cocos.co_cos_manager import CoCosManager from pynestml.generated.PyNestMLLexer import PyNestMLLexer from pynestml.generated.PyNestMLParser import PyNestMLParser from pynestml.meta_model.ast_arithmetic_operator import ASTArithmeticOperator from pynestml.meta_model.ast_assignment import ASTAssignment -from pynestml.meta_model.ast_block import ASTBlock +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody from pynestml.meta_model.ast_block_with_variables import ASTBlockWithVariables from pynestml.meta_model.ast_comparison_operator import ASTComparisonOperator from pynestml.meta_model.ast_compound_stmt import ASTCompoundStmt @@ -196,14 +197,6 @@ def parse_bit_operator(cls, string): ret.accept(ASTHigherOrderVisitor(log_set_added_source_position)) return ret - @classmethod - def parse_block(cls, string): - # type: (str) -> ASTBlock - (builder, parser) = tokenize(string) - ret = builder.visit(parser.block()) - ret.accept(ASTHigherOrderVisitor(log_set_added_source_position)) - return ret - @classmethod def parse_block_with_variables(cls, string): # type: (str) -> ASTBlockWithVariables @@ -215,7 +208,7 @@ def parse_block_with_variables(cls, string): @classmethod def parse_model_body(cls, string: str) -> ASTModelBody: (builder, parser) = tokenize(string) - ret = builder.visit(parser.body()) + ret = builder.visit(parser.modelBody()) ret.accept(ASTHigherOrderVisitor(log_set_added_source_position)) return ret @@ -459,6 +452,20 @@ def parse_while_stmt(cls, string): ret.accept(ASTHigherOrderVisitor(log_set_added_source_position)) return ret + @classmethod + def parse_stmts_body(cls, string): + # type: (str) -> ASTStmtsBody + (builder, parser) = tokenize(string) + ret = builder.visit(parser.stmtsBody()) + ret.accept(ASTHigherOrderVisitor(log_set_added_source_position)) + return ret + +class BailConsoleErrorListener(ErrorListener): + def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e): + s = "line " + str(line) + ":" + str(column) + " " + msg + print(s) + raise ParseCancellationException(s) + def tokenize(string: str) -> Tuple[ASTBuilderVisitor, PyNestMLParser]: lexer = PyNestMLLexer(InputStream(string)) @@ -466,7 +473,11 @@ def tokenize(string: str) -> Tuple[ASTBuilderVisitor, PyNestMLParser]: stream = CommonTokenStream(lexer) stream.fill() parser = PyNestMLParser(stream) + + parser.addErrorListener(BailConsoleErrorListener()) + builder = ASTBuilderVisitor(stream.tokens) + return builder, parser diff --git a/pynestml/visitors/assign_implicit_conversion_factors_visitor.py b/pynestml/visitors/assign_implicit_conversion_factors_visitor.py index 0fe4b93a7..bad89d52c 100644 --- a/pynestml/visitors/assign_implicit_conversion_factors_visitor.py +++ b/pynestml/visitors/assign_implicit_conversion_factors_visitor.py @@ -221,11 +221,11 @@ def __assign_return_types(self, _node): 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: + if symbol is not None and len(userDefinedFunction.get_stmts_body().get_stmts()) > 0: # now check that the last statement is a return self.__check_return_recursively(userDefinedFunction, symbol.get_return_type(), - userDefinedFunction.get_block().get_stmts(), + userDefinedFunction.get_stmts_body().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 \ @@ -300,23 +300,23 @@ def __check_return_recursively(self, processed_function, type_symbol=None, stmts if stmt.is_if_stmt(): self.__check_return_recursively(processed_function, type_symbol, - stmt.get_if_stmt().get_if_clause().get_block().get_stmts(), + stmt.get_if_stmt().get_if_clause().get_stmts_body().get_stmts(), ret_defined) for else_ifs in stmt.get_if_stmt().get_elif_clauses(): self.__check_return_recursively(processed_function, - type_symbol, else_ifs.get_block().get_stmts(), ret_defined) + type_symbol, else_ifs.get_stmts_body().get_stmts(), ret_defined) if stmt.get_if_stmt().has_else_clause(): self.__check_return_recursively(processed_function, type_symbol, - stmt.get_if_stmt().get_else_clause().get_block().get_stmts(), + stmt.get_if_stmt().get_else_clause().get_stmts_body().get_stmts(), ret_defined) elif stmt.is_while_stmt(): self.__check_return_recursively(processed_function, - type_symbol, stmt.get_while_stmt().get_block().get_stmts(), + type_symbol, stmt.get_while_stmt().get_stmts_body().get_stmts(), ret_defined) elif stmt.is_for_stmt(): self.__check_return_recursively(processed_function, - type_symbol, stmt.get_for_stmt().get_block().get_stmts(), + type_symbol, stmt.get_for_stmt().get_stmts_body().get_stmts(), ret_defined) # now, if a return statement has not been defined in the corresponding higher level block, we have to ensure that it is defined here elif not ret_defined and stmts.index(c_stmt) == (len(stmts) - 1): diff --git a/pynestml/visitors/ast_builder_visitor.py b/pynestml/visitors/ast_builder_visitor.py index 02a9bd396..edcab7a22 100644 --- a/pynestml/visitors/ast_builder_visitor.py +++ b/pynestml/visitors/ast_builder_visitor.py @@ -184,8 +184,8 @@ def visitExpression(self, ctx): elif (condition is not None) and (if_true is not None) and (if_not is not None): return ASTNodeFactory.create_ast_ternary_expression(condition=condition, if_true=if_true, if_not=if_not, source_position=source_pos) - else: - raise RuntimeError('Type of rhs @%s,%s not recognized!' % (ctx.start.line, ctx.start.column)) + + raise RuntimeError('Type of rhs @%s,%s not recognized!' % (ctx.start.line, ctx.start.column)) # Visit a parse tree produced by PyNESTMLParser#simpleExpression. def visitSimpleExpression(self, ctx): @@ -201,12 +201,13 @@ def visitSimpleExpression(self, ctx): is_inf = (True if ctx.isInf is not None else False) variable = (self.visit(ctx.variable()) if ctx.variable() is not None else None) string = (str(ctx.string.text) if ctx.string is not None else None) - return ASTNodeFactory.create_ast_simple_expression(function_call=function_call, + node = ASTNodeFactory.create_ast_simple_expression(function_call=function_call, boolean_literal=boolean_literal, numeric_literal=numeric_literal, is_inf=is_inf, variable=variable, string=string, source_position=create_source_pos(ctx)) + return node # Visit a parse tree produced by PyNESTMLParser#unaryOperator. def visitUnaryOperator(self, ctx): @@ -323,8 +324,8 @@ def visitKernel(self, ctx): update_node_comments(kernel, self.__comments.visit(ctx)) return kernel - # Visit a parse tree produced by PyNESTMLParser#block. - def visitBlock(self, ctx): + # Visit a parse tree produced by PyNESTMLParser#stmtsBody + def visitStmtsBody(self, ctx): stmts = list() if ctx.stmt() is not None: for stmt in ctx.stmt(): @@ -402,7 +403,8 @@ def visitDeclaration(self, ctx): # Visit a parse tree produced by PyNESTMLParser#returnStmt. def visitReturnStmt(self, ctx): ret_expression = self.visit(ctx.expression()) if ctx.expression() is not None else None - return ASTNodeFactory.create_ast_return_stmt(expression=ret_expression, source_position=create_source_pos(ctx)) + node = ASTNodeFactory.create_ast_return_stmt(expression=ret_expression, source_position=create_source_pos(ctx)) + return node # Visit a parse tree produced by PyNESTMLParser#ifStmt. def visitIfStmt(self, ctx): @@ -419,7 +421,7 @@ def visitIfStmt(self, ctx): # Visit a parse tree produced by PyNESTMLParser#ifClause. def visitIfClause(self, ctx): condition = self.visit(ctx.expression()) if ctx.expression() is not None else None - block = self.visit(ctx.block()) if ctx.block() is not None else None + block = self.visit(ctx.stmtsBody()) if ctx.stmtsBody() is not None else None ret = ASTNodeFactory.create_ast_if_clause(condition=condition, block=block, source_position=create_source_pos(ctx)) update_node_comments(ret, self.__comments.visitStmt(ctx)) @@ -428,7 +430,7 @@ def visitIfClause(self, ctx): # Visit a parse tree produced by PyNESTMLParser#elifClause. def visitElifClause(self, ctx): condition = self.visit(ctx.expression()) if ctx.expression() is not None else None - block = self.visit(ctx.block()) if ctx.block() is not None else None + block = self.visit(ctx.stmtsBody()) if ctx.stmtsBody() is not None else None node = ASTNodeFactory.create_ast_elif_clause(condition=condition, block=block, source_position=create_source_pos(ctx)) update_node_comments(node, self.__comments.visit(ctx)) @@ -436,7 +438,7 @@ def visitElifClause(self, ctx): # Visit a parse tree produced by PyNESTMLParser#elseClause. def visitElseClause(self, ctx): - block = self.visit(ctx.block()) if ctx.block() is not None else None + block = self.visit(ctx.stmtsBody()) if ctx.stmtsBody() is not None else None node = ASTNodeFactory.create_ast_else_clause(block=block, source_position=create_source_pos(ctx)) update_node_comments(node, self.__comments.visit(ctx)) return node @@ -453,7 +455,7 @@ def visitForStmt(self, ctx): value = float(str(ctx.FLOAT())) step = step_scalar * value - block = self.visit(ctx.block()) if ctx.block() is not None else None + block = self.visit(ctx.stmtsBody()) if ctx.stmtsBody() is not None else None node = ASTNodeFactory.create_ast_for_stmt(variable=variable, start_from=start_from, end_at=end_at, step=step, block=block, source_position=create_source_pos(ctx)) update_node_comments(node, self.__comments.visit(ctx)) @@ -462,7 +464,7 @@ def visitForStmt(self, ctx): # Visit a parse tree produced by PyNESTMLParser#whileStmt. def visitWhileStmt(self, ctx): cond = self.visit(ctx.expression()) if ctx.expression() is not None else None - block = self.visit(ctx.block()) if ctx.block() is not None else None + block = self.visit(ctx.stmtsBody()) if ctx.stmtsBody() is not None else None node = ASTNodeFactory.create_ast_while_stmt(condition=cond, block=block, source_position=create_source_pos(ctx)) update_node_comments(node, self.__comments.visit(ctx)) return node @@ -563,7 +565,7 @@ def visitBlockWithVariables(self, ctx): return ret def visitUpdateBlock(self, ctx): - block = self.visit(ctx.block()) if ctx.block() is not None else None + block = self.visit(ctx.stmtsBody()) if ctx.stmtsBody() is not None else None ret = ASTNodeFactory.create_ast_update_block(block=block, source_position=create_source_pos(ctx)) update_node_comments(ret, self.__comments.visit(ctx)) return ret @@ -673,7 +675,7 @@ def visitFunction(self, ctx): parameters.append(self.visit(par)) elif ctx.parameters() is not None: parameters.append(ctx.parameter()) - block = self.visit(ctx.block()) if ctx.block() is not None else None + block = self.visit(ctx.stmtsBody()) if ctx.stmtsBody() is not None else None return_type = self.visit(ctx.returnType) if ctx.returnType is not None else None node = ASTNodeFactory.create_ast_function(name=name, parameters=parameters, block=block, return_type=return_type, source_position=create_source_pos(ctx)) @@ -694,7 +696,7 @@ def visitStmt(self, ctx): return ASTNodeFactory.create_ast_stmt(small, compound, create_source_pos(ctx)) def visitOnReceiveBlock(self, ctx): - block = self.visit(ctx.block()) if ctx.block() is not None else None + block = self.visit(ctx.stmtsBody()) if ctx.stmtsBody() is not None else None port_name = ctx.inputPortName.text const_parameters = {} for el in ctx.constParameter(): @@ -704,7 +706,7 @@ def visitOnReceiveBlock(self, ctx): return ret def visitOnConditionBlock(self, ctx): - block = self.visit(ctx.block()) if ctx.block() is not None else None + block = self.visit(ctx.stmtsBody()) if ctx.stmtsBody() is not None else None cond_expr: ASTExpression = self.visit(ctx.condition) const_parameters = {} for el in ctx.constParameter(): @@ -715,6 +717,9 @@ def visitOnConditionBlock(self, ctx): def update_node_comments(node, comments): + if not comments: + return + node.comment = comments[0] node.pre_comments = comments[1] node.in_comment = comments[2] diff --git a/pynestml/visitors/ast_symbol_table_visitor.py b/pynestml/visitors/ast_symbol_table_visitor.py index f9cde46e4..a0f01e9fa 100644 --- a/pynestml/visitors/ast_symbol_table_visitor.py +++ b/pynestml/visitors/ast_symbol_table_visitor.py @@ -113,8 +113,8 @@ def visit_function(self, node): if node.has_return_type(): node.get_return_type().update_scope(scope) - if node.get_block() is not None: - node.get_block().update_scope(scope) + if node.get_stmts_body() is not None: + node.get_stmts_body().update_scope(scope) def endvisit_function(self, node): symbol = self.symbol_stack.pop() @@ -158,7 +158,7 @@ def visit_update_block(self, node): scope = Scope(scope_type=ScopeType.UPDATE, enclosing_scope=node.get_scope(), source_position=node.get_source_position()) node.get_scope().add_scope(scope) - node.get_block().update_scope(scope) + node.get_stmts_body().update_scope(scope) return def endvisit_update_block(self, node=None): @@ -175,7 +175,7 @@ def visit_on_receive_block(self, node): scope = Scope(scope_type=ScopeType.ON_RECEIVE, enclosing_scope=node.get_scope(), source_position=node.get_source_position()) node.get_scope().add_scope(scope) - node.get_block().update_scope(scope) + node.get_stmts_body().update_scope(scope) def endvisit_on_receive_block(self, node=None): self.block_type_stack.pop() @@ -190,7 +190,7 @@ def visit_on_condition_block(self, node): scope = Scope(scope_type=ScopeType.ON_CONDITION, enclosing_scope=node.get_scope(), source_position=node.get_source_position()) node.get_scope().add_scope(scope) - node.get_block().update_scope(scope) + node.get_stmts_body().update_scope(scope) node.get_cond_expr().update_scope(node.get_scope()) def endvisit_on_condition_block(self, node=None): @@ -355,7 +355,7 @@ def visit_if_clause(self, node): :type node: ast_if_clause """ node.get_condition().update_scope(node.get_scope()) - node.get_block().update_scope(node.get_scope()) + node.get_stmts_body().update_scope(node.get_scope()) def visit_elif_clause(self, node): """ @@ -364,7 +364,7 @@ def visit_elif_clause(self, node): :type node: ast_elif_clause """ node.get_condition().update_scope(node.get_scope()) - node.get_block().update_scope(node.get_scope()) + node.get_stmts_body().update_scope(node.get_scope()) def visit_else_clause(self, node): """ @@ -372,7 +372,7 @@ def visit_else_clause(self, node): :param node: an else clause. :type node: ast_else_clause """ - node.get_block().update_scope(node.get_scope()) + node.get_stmts_body().update_scope(node.get_scope()) def visit_for_stmt(self, node): """ @@ -382,7 +382,7 @@ def visit_for_stmt(self, node): """ node.get_start_from().update_scope(node.get_scope()) node.get_end_at().update_scope(node.get_scope()) - node.get_block().update_scope(node.get_scope()) + node.get_stmts_body().update_scope(node.get_scope()) def visit_while_stmt(self, node): """ @@ -391,7 +391,7 @@ def visit_while_stmt(self, node): :type node: ast_while_stmt """ node.get_condition().update_scope(node.get_scope()) - node.get_block().update_scope(node.get_scope()) + node.get_stmts_body().update_scope(node.get_scope()) def visit_data_type(self, node): """ diff --git a/pynestml/visitors/ast_visitor.py b/pynestml/visitors/ast_visitor.py index c2b4dab01..630759f6d 100644 --- a/pynestml/visitors/ast_visitor.py +++ b/pynestml/visitors/ast_visitor.py @@ -22,7 +22,7 @@ from pynestml.meta_model.ast_arithmetic_operator import ASTArithmeticOperator from pynestml.meta_model.ast_assignment import ASTAssignment from pynestml.meta_model.ast_bit_operator import ASTBitOperator -from pynestml.meta_model.ast_block import ASTBlock +from pynestml.meta_model.ast_stmts_body import ASTStmtsBody from pynestml.meta_model.ast_block_with_variables import ASTBlockWithVariables from pynestml.meta_model.ast_comparison_operator import ASTComparisonOperator from pynestml.meta_model.ast_compound_stmt import ASTCompoundStmt @@ -745,7 +745,7 @@ def visit(self, node: ASTNode): if isinstance(node, ASTBitOperator): self.visit_bit_operator(node) return - if isinstance(node, ASTBlock): + if isinstance(node, ASTStmtsBody): self.visit_block(node) return if isinstance(node, ASTBlockWithVariables): @@ -876,7 +876,7 @@ def traverse(self, node): if isinstance(node, ASTBitOperator): self.traverse_bit_operator(node) return - if isinstance(node, ASTBlock): + if isinstance(node, ASTStmtsBody): self.traverse_block(node) return if isinstance(node, ASTBlockWithVariables): @@ -1007,7 +1007,7 @@ def endvisit(self, node): if isinstance(node, ASTBitOperator): self.endvisit_bit_operator(node) return - if isinstance(node, ASTBlock): + if isinstance(node, ASTStmtsBody): self.endvisit_block(node) return if isinstance(node, ASTBlockWithVariables): @@ -1178,12 +1178,12 @@ def traverse_declaration(self, node): def traverse_elif_clause(self, node): if node.get_condition() is not None: node.get_condition().accept(self.get_real_self()) - if node.get_block() is not None: - node.get_block().accept(self.get_real_self()) + if node.get_stmts_body() is not None: + node.get_stmts_body().accept(self.get_real_self()) def traverse_else_clause(self, node): - if node.get_block() is not None: - node.get_block().accept(self.get_real_self()) + if node.get_stmts_body() is not None: + node.get_stmts_body().accept(self.get_real_self()) def traverse_equations_block(self, node): if node.get_declarations() is not None: @@ -1213,16 +1213,16 @@ def traverse_for_stmt(self, node): node.get_start_from().accept(self.get_real_self()) if node.get_end_at() is not None: node.get_end_at().accept(self.get_real_self()) - if node.get_block() is not None: - node.get_block().accept(self.get_real_self()) + if node.get_stmts_body() is not None: + node.get_stmts_body().accept(self.get_real_self()) def traverse_function(self, node): for sub_node in node.get_parameters(): sub_node.accept(self.get_real_self()) if node.get_return_type() is not None: node.get_return_type().accept(self.get_real_self()) - if node.get_block() is not None: - node.get_block().accept(self.get_real_self()) + if node.get_stmts_body() is not None: + node.get_stmts_body().accept(self.get_real_self()) def traverse_function_call(self, node): if node.get_args() is not None: @@ -1232,8 +1232,8 @@ def traverse_function_call(self, node): def traverse_if_clause(self, node): if node.get_condition() is not None: node.get_condition().accept(self.get_real_self()) - if node.get_block() is not None: - node.get_block().accept(self.get_real_self()) + if node.get_stmts_body() is not None: + node.get_stmts_body().accept(self.get_real_self()) def traverse_if_stmt(self, node): if node.get_if_clause() is not None: @@ -1327,18 +1327,18 @@ def traverse_unit_type(self, node): node.compound_unit.accept(self.get_real_self()) def traverse_update_block(self, node): - if node.get_block() is not None: - node.get_block().accept(self.get_real_self()) + if node.get_stmts_body() is not None: + node.get_stmts_body().accept(self.get_real_self()) def traverse_on_receive_block(self, node): - if node.get_block() is not None: - node.get_block().accept(self.get_real_self()) + if node.get_stmts_body() is not None: + node.get_stmts_body().accept(self.get_real_self()) def traverse_on_condition_block(self, node): if node.get_cond_expr() is not None: node.get_cond_expr().accept(self.get_real_self()) - if node.get_block() is not None: - node.get_block().accept(self.get_real_self()) + if node.get_stmts_body() is not None: + node.get_stmts_body().accept(self.get_real_self()) def traverse_variable(self, node): if node.get_vector_parameter() is not None: @@ -1347,8 +1347,8 @@ def traverse_variable(self, node): def traverse_while_stmt(self, node): if node.get_condition() is not None: node.get_condition().accept(self.get_real_self()) - if node.get_block() is not None: - node.get_block().accept(self.get_real_self()) + if node.get_stmts_body() is not None: + node.get_stmts_body().accept(self.get_real_self()) def traverse_stmt(self, node): if node.is_small_stmt(): diff --git a/tests/nestml_printer_test.py b/tests/test_nestml_printer.py similarity index 60% rename from tests/nestml_printer_test.py rename to tests/test_nestml_printer.py index 2ac258a3e..9fb73c720 100644 --- a/tests/nestml_printer_test.py +++ b/tests/test_nestml_printer.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # -# nestml_printer_test.py +# test_nestml_printer.py # # This file is part of NEST. # @@ -18,8 +18,9 @@ # # You should have received a copy of the GNU General Public License # along with NEST. If not, see . + import os -import unittest +import pytest from pynestml.codegeneration.printers.nestml_printer import NESTMLPrinter from pynestml.symbol_table.symbol_table import SymbolTable @@ -32,13 +33,13 @@ from pynestml.utils.model_parser import ModelParser -class NestMLPrinterTest(unittest.TestCase): +class TestNESTMLMLPrinter: """ Tests if NESTMLPrinter works as intended. """ + @pytest.fixture(scope="module", autouse=True) def setUp(self): - # setups the infrastructure PredefinedUnits.register_units() PredefinedTypes.register_types() PredefinedFunctions.register_functions() @@ -47,52 +48,52 @@ def setUp(self): Logger.init_logger(LoggingLevel.INFO) def test_block_with_variables_with_comments(self): - block = "# pre1\n" \ - "state: # in\n" \ - " # real pre\n" \ - " # real pre2\n" \ - " r real = 0\n" - model = ModelParser.parse_block_with_variables(block) + block = " # pre1\n" \ + " state: # in\n" \ + " # real pre\n" \ + " # real pre2\n" \ + " r real = 0\n" + model = ModelParser.parse_model_body(block) model_printer = NESTMLPrinter() - self.assertEqual(block, model_printer.print(model)) + assert block == model_printer.print(model) def test_block_with_variables_with_in_comments(self): - block = "# pre1\n" \ - "state:\n" \ - " r real = 0 # in comment\n" - model = ModelParser.parse_block_with_variables(block) + block = " # pre1\n" \ + " state:\n" \ + " r real = 0 # in comment\n" + model = ModelParser.parse_model_body(block) model_printer = NESTMLPrinter() - self.assertEqual(block, model_printer.print(model)) + assert block == model_printer.print(model) def test_block_with_variables_without_comments(self): block = "state:\n" \ " r real = 0\n" model = ModelParser.parse_block_with_variables(block) model_printer = NESTMLPrinter() - self.assertEqual(block, model_printer.print(model)) + assert block == model_printer.print(model) def test_assignment_with_comments(self): - assignment = " # pre\n" \ - " a = b # in\n" - model = ModelParser.parse_block(assignment) + assignment = "# pre\n" \ + "a = b # in\n" + model = ModelParser.parse_stmts_body(assignment) model_printer = NESTMLPrinter() - self.assertEqual(assignment, model_printer.print(model)) + assert assignment == model_printer.print(model) def test_assignment_without_comments(self): assignment = "a = b\n" model = ModelParser.parse_assignment(assignment) model_printer = NESTMLPrinter() - self.assertEqual(assignment, model_printer.print(model)) + assert assignment == model_printer.print(model) def test_function_with_comments(self): - t_function = "# pre func\n" \ - "function test(Tau_1 ms) real: # in func\n" \ - " # decl pre\n" \ - " exact_integration_adjustment real = ((1 / Tau_2) - (1 / Tau_1)) * ms # decl in\n" \ - " return normalisation_factor\n" - model = ModelParser.parse_function(t_function) + t_function = " # pre func\n" \ + " function test(Tau_1 ms) real: # in func\n" \ + " # decl pre\n" \ + " exact_integration_adjustment real = ((1 / Tau_2) - (1 / Tau_1)) * ms # decl in\n" \ + " return normalisation_factor\n" + model = ModelParser.parse_model_body(t_function) model_printer = NESTMLPrinter() - self.assertEqual(t_function, model_printer.print(model)) + assert t_function == model_printer.print(model) def test_function_without_comments(self): t_function = "function test(Tau_1 ms) real:\n" \ @@ -100,20 +101,20 @@ def test_function_without_comments(self): " return normalisation_factor\n" model = ModelParser.parse_function(t_function) model_printer = NESTMLPrinter() - self.assertEqual(t_function, model_printer.print(model)) + assert t_function == model_printer.print(model) def test_function_call_with_comments(self): - function_call = " # pre\n" \ - " min(1,2) # in\n" - model = ModelParser.parse_block(function_call) + function_call = "# pre\n" \ + "min(1,2) # in\n" + model = ModelParser.parse_stmts_body(function_call) model_printer = NESTMLPrinter() - self.assertEqual(function_call, model_printer.print(model)) + assert function_call == model_printer.print(model) def test_function_call_without_comments(self): function_call = "min(1,2)\n" model = ModelParser.parse_stmt(function_call) model_printer = NESTMLPrinter() - self.assertEqual(function_call, model_printer.print(model)) + assert function_call == model_printer.print(model) def test_neuron_with_comments(self): neuron = "# pre\n" \ @@ -122,107 +123,109 @@ def test_neuron_with_comments(self): " foo integer = 0\n" model = ModelParser.parse_nestml_compilation_unit(neuron) model_printer = NESTMLPrinter() - self.assertEqual(neuron, model_printer.print(model)) + assert neuron == model_printer.print(model) def test_neuron_with_docstring(self): neuron = '"""hello, world\n" \ "\n" \ - "3.141592653589793"""\n'\ - "model test:\n" + "3.141592653589793"""\n' \ + "model test:\n" \ + " parameters:\n" \ + " foo integer = 0\n" model = ModelParser.parse_model(neuron) model_printer = NESTMLPrinter() - self.assertEqual(neuron, model_printer.print(model)) + assert neuron == model_printer.print(model) def test_declaration_with_comments(self): - declaration = " # pre\n" \ - " test mV = 10mV # in\n" - model = ModelParser.parse_block(declaration) + declaration = "# pre\n" \ + "test mV = 10mV # in\n" + model = ModelParser.parse_stmts_body(declaration) model_printer = NESTMLPrinter() - self.assertEqual(declaration, model_printer.print(model)) + assert declaration == model_printer.print(model) def test_declaration_without_comments(self): declaration = "test mV = 10mV\n" model = ModelParser.parse_declaration(declaration) model_printer = NESTMLPrinter() - self.assertEqual(declaration, model_printer.print(model)) + assert declaration == model_printer.print(model) def test_equations_block_with_comments(self): - block = "# pre\n" \ - "equations: # in\n" \ - " # pre1 v\n" \ - " # pre2 v\n" \ - " v' = -v / t\n" - model = ModelParser.parse_equations_block(block) + block = " # pre\n" \ + " equations: # in\n" \ + " # pre1 v\n" \ + " # pre2 v\n" \ + " v' = -v / t\n" + model = ModelParser.parse_model_body(block) model_printer = NESTMLPrinter() - self.assertEqual(block, model_printer.print(model)) + assert block == model_printer.print(model) def test_equations_block_without_comments(self): block = "equations:\n" \ " v' = -v / t\n" model = ModelParser.parse_equations_block(block) model_printer = NESTMLPrinter() - self.assertEqual(block, model_printer.print(model)) + assert block == model_printer.print(model) def test_for_stmt_with_comments(self): - stmt = " # pre\n" \ - " for i in 10 - 3.14...10 + 3.14 step -1: # in\n" \ - " j = j + 1\n" - model = ModelParser.parse_block(stmt) + stmt = "# pre\n" \ + "for i in 10 - 3.14...10 + 3.14 step -1: # in\n" \ + " j = j + 1\n" + model = ModelParser.parse_stmts_body(stmt) model_printer = NESTMLPrinter() - self.assertEqual(stmt, model_printer.print(model)) + assert stmt == model_printer.print(model) def test_for_stmt_without_comments(self): stmt = "for i in 10 - 3.14...10 + 3.14 step -1: # in\n" \ " j += 1\n" model = ModelParser.parse_for_stmt(stmt) model_printer = NESTMLPrinter() - self.assertEqual(stmt, model_printer.print(model)) + assert stmt == model_printer.print(model) def test_while_stmt_with_comments(self): - stmt = " # pre\n" \ - " while true: # in\n" \ - " i += 1\n" - model = ModelParser.parse_block(stmt) + stmt = "# pre\n" \ + "while true: # in\n" \ + " i += 1\n" + model = ModelParser.parse_stmts_body(stmt) model_printer = NESTMLPrinter() - self.assertEqual(stmt, model_printer.print(model)) + assert stmt == model_printer.print(model) def test_while_stmt_without_comments(self): stmt = "while true:\n" \ " i -= 0.5\n" model = ModelParser.parse_while_stmt(stmt) model_printer = NESTMLPrinter() - self.assertEqual(stmt, model_printer.print(model)) + assert stmt == model_printer.print(model) def test_update_block_with_comments(self): - block = "# pre\n" \ - "update: # in\n" \ - " j = 0\n" - model = ModelParser.parse_update_block(block) + block = " # pre\n" \ + " update: # in\n" \ + " j = 0\n" + model = ModelParser.parse_model_body(block) model_printer = NESTMLPrinter() - self.assertEqual(block, model_printer.print(model)) + assert block == model_printer.print(model) def test_update_block_without_comments(self): block = "update:\n" \ " j = 3\n" model = ModelParser.parse_update_block(block) model_printer = NESTMLPrinter() - self.assertEqual(block, model_printer.print(model)) + assert block == model_printer.print(model) def test_variable(self): var = "V_m" model = ModelParser.parse_variable(var) model_printer = NESTMLPrinter() - self.assertEqual(var, model_printer.print(model)) + assert var == model_printer.print(model) def test_unit_type(self): unit = "1/(mV*kg**2)" model = ModelParser.parse_unit_type(unit) model_printer = NESTMLPrinter() - self.assertEqual(unit, model_printer.print(model)) + assert unit == model_printer.print(model) def test_unary_operator(self): - ops = {"-", "+", "~"} + ops = ["-", "+", "~"] for op in ops: model = ModelParser.parse_unary_operator(op) model_printer = NESTMLPrinter() - self.assertEqual(op, model_printer.print(model)) + assert op == model_printer.print(model) diff --git a/tests/test_unit_system.py b/tests/test_unit_system.py index 2cad0b98d..ab4b5a560 100644 --- a/tests/test_unit_system.py +++ b/tests/test_unit_system.py @@ -72,7 +72,7 @@ def setUp(self, request): def get_first_statement_in_update_block(self, model): if model.get_model_list()[0].get_update_blocks()[0]: - return model.get_model_list()[0].get_update_blocks()[0].get_block().get_stmts()[0] + return model.get_model_list()[0].get_update_blocks()[0].get_stmts_body().get_stmts()[0] return None @@ -103,7 +103,7 @@ def print_rhs_of_first_declaration_in_state_block(self, model): def print_first_return_statement_in_first_declared_function(self, model): func = self.get_first_declared_function(model) - return_expression = func.get_block().get_stmts()[0].small_stmt.get_return_stmt().get_expression() + return_expression = func.get_stmts_body().get_stmts()[0].small_stmt.get_return_stmt().get_expression() return self.printer.print(return_expression) def test_expression_after_magnitude_conversion_in_direct_assignment(self):