diff --git a/src/gboml/gboml.lark b/src/gboml/gboml.lark index a5864f761f72ba0895a873e80e096c426dd23463..33149d60704efdaa3baddd9899ac69c36ebd41f5 100644 --- a/src/gboml/gboml.lark +++ b/src/gboml/gboml.lark @@ -15,27 +15,27 @@ separated_list{sub, sep}: _separated_list{sub, sep} _separated_maybe_empty_list{sub, sep}: _separated_list{sub, sep}? separated_maybe_empty_list{sub, sep}: _separated_list{sub, sep}? plist{content}: content* +_block_repeat_or_pass{name, content}: name (_PASS ";" | content+) +_block_shortcut{name, content}: name (_PASS? ";" | content) +_PASS.1: "pass" // HEADER start: [time_horizon] global_block program_block program_block: _program* ?time_horizon: "#TIMEHORIZON" "T" "=" INT ";" -global_block: ("#GLOBAL" definition*)? +global_block: _block_repeat_or_pass{"#GLOBAL",definition}? _program: node | hyperedge // NODES ?node: node_definition | node_import -node_definition: "#NODE" var_or_param [loop] \ - parameters_block \ - program_block \ - variables_block \ - constraints_block \ - objectives_block - -parameters_block: ("#PARAMETERS" definition*)? -variables_block: "#VARIABLES" variable_definition* -constraints_block: ("#CONSTRAINTS" constraint*)? -objectives_block: ("#OBJECTIVES" objective*)? +node_definition: _block_shortcut{_node_header, _node_content} +_node_header: "#NODE" var_or_param [loop] +_node_content: parameters_block program_block variables_block constraints_block objectives_block + +parameters_block: (_block_repeat_or_pass{"#PARAMETERS",definition})? +variables_block: _block_repeat_or_pass{"#VARIABLES",variable_definition} +constraints_block: (_block_repeat_or_pass{"#CONSTRAINTS",constraint})? +objectives_block: (_block_repeat_or_pass{"#OBJECTIVES",objective})? node_import: "#NODE" ID "=" "import" var_or_param "from" STRING node_redefs node_redefs: ("with" redefinition*) | ";" @@ -45,9 +45,9 @@ variable_scope_change: ID SCOPE ";" // HYPEREDGES ?hyperedge: hyperedge_definition | hyperedge_import -hyperedge_definition: "#HYPEREDGE" var_or_param [loop] \ - parameters_block \ - constraints_block +hyperedge_definition: _block_shortcut{_hyperedge_header, _hyperedge_content} +_hyperedge_header: "#HYPEREDGE" var_or_param [loop] +_hyperedge_content: parameters_block constraints_block hyperedge_import: "#HYPEREDGE" ID "=" "import" var_or_param "from" STRING hyperedge_redefs hyperedge_redefs: "with" definition* | ";" diff --git a/src/gboml/parsing.py b/src/gboml/parsing.py index 83fd7cfde1e75ecaf0bec656ca0dd45ab20c3e76..376053be2ca9a355f5cdfdd9160fcf2e222c44cd 100644 --- a/src/gboml/parsing.py +++ b/src/gboml/parsing.py @@ -118,7 +118,13 @@ def _lark_to_gboml(tree: Tree, filename: Optional[str] = None) -> GBOMLGraph: def program_block(self, meta: Meta, *childrens: list[Node | HyperEdge]) -> NodesAndHyperEdges: return self.NodesAndHyperEdges([x for x in childrens if isinstance(x, Node)], [x for x in childrens if isinstance(x, HyperEdge)]) - def hyperedge_definition(self, meta: Meta, name: VarOrParam, loop: Optional[Loop], param_block: list[Definition], constraint_block: list[Constraint]): + def hyperedge_definition(self, meta: Meta, name: VarOrParam, loop: Optional[Loop], + param_block: list[Definition] = None, constraint_block: list[Constraint] = None): + if constraint_block is None: + constraint_block = [] + if param_block is None: + param_block = [] + if loop is None: if len(name.path) != 1 or len(name.path[0].indices) != 0: raise Exception(f"Invalid name for node: {name}") @@ -126,9 +132,21 @@ def _lark_to_gboml(tree: Tree, filename: Optional[str] = None) -> GBOMLGraph: else: return HyperEdgeGenerator(name, loop, param_block, constraint_block, meta=meta) - def node_definition(self, meta: Meta, name: VarOrParam, loop: Optional[Loop], param_block: list[Definition], subprogram_block: NodesAndHyperEdges, - variable_block: list[VariableDefinition], constraint_block: list[Constraint], - objectives_block: list[Objective]): + def node_definition(self, meta: Meta, name: VarOrParam, loop: Optional[Loop], + param_block: list[Definition] = None, subprogram_block: NodesAndHyperEdges = None, + variable_block: list[VariableDefinition] = None, constraint_block: list[Constraint] = None, + objectives_block: list[Objective] = None): + if objectives_block is None: + objectives_block = [] + if constraint_block is None: + constraint_block = [] + if variable_block is None: + variable_block = [] + if param_block is None: + param_block = [] + if subprogram_block is None: + subprogram_block = self.NodesAndHyperEdges([], []) + if loop is None: if len(name.path) != 1 or len(name.path[0].indices) != 0: raise Exception(f"Invalid name for node: {name}") diff --git a/tests/instances/ko_parsing/wrong_global.txt b/tests/instances/ko_parsing/wrong_global.txt new file mode 100644 index 0000000000000000000000000000000000000000..67d6345587bfcaf6066a4d9349263e53a0ffbe15 --- /dev/null +++ b/tests/instances/ko_parsing/wrong_global.txt @@ -0,0 +1,5 @@ +#GLOBAL + +#NODE x + #VARIABLES + internal: a; \ No newline at end of file diff --git a/tests/instances/ok/complex_parsing.txt b/tests/instances/ok/complex_parsing.txt index fed325b24bd164514610fae54de247fe052065b1..2259377171f49e43423bc1d57edbee618f22e67c 100644 --- a/tests/instances/ok/complex_parsing.txt +++ b/tests/instances/ok/complex_parsing.txt @@ -15,8 +15,10 @@ c internal; #NODE nodeL[i] for i in [0:10] #VARIABLES + pass; #HYPEREDGE E[i] for i in [0:10] #CONSTRAINTS + pass; #NODE node1 #PARAMETERS a = 2; diff --git a/tests/instances/ok/good_global.txt b/tests/instances/ok/good_global.txt new file mode 100644 index 0000000000000000000000000000000000000000..559373b5bef43df51beadbdf520b447bcbd7ae02 --- /dev/null +++ b/tests/instances/ok/good_global.txt @@ -0,0 +1,16 @@ +#GLOBAL + pass; + +#NODE x + #VARIABLES + internal: a; + +#NODE y + pass; + +#NODE z; + +#HYPEREDGE e; + +#HYPEREDGE e2 + pass; \ No newline at end of file