diff --git a/polyply/src/top_parser.py b/polyply/src/top_parser.py index d95bf5e8..01b0e7a0 100644 --- a/polyply/src/top_parser.py +++ b/polyply/src/top_parser.py @@ -63,7 +63,8 @@ def __init__(self, topology, cwdir=None): } self.pragma_actions = { '#define': self.parse_define, - '#include': self.parse_include + '#include': self.parse_include, + '#error': self.parse_error, } def dispatch(self, line): @@ -392,9 +393,30 @@ def _molecule(self, line, lineno=0): """ self.current_itp.append(line) + def parse_error(self, line, lineno=0): + """ + Parse the #error statement. + """ + if self.current_meta: + # In this case the #error is enclosed in an + # #ifdef statement. However tag of the #ifdef + # has not been defined previously. Thus the + # error is not triggered. + if self.current_meta["condition"] == "ifdef"\ + and self.current_meta["tag"] not in self.topology.defines: + return + # the #error file is enlosed in an #ifndef + # so if tag is defined, we ignore this #error + elif self.current_meta["condition"] == "ifndef"\ + and self.current_meta["tag"] in self.topology.defines: + return + # we remove the #error + msg = line[7:] + raise NotImplementedError(msg) + def parse_define(self, line): """ - Parse define statemetns + Parse define statements """ tokens = line.split() diff --git a/polyply/tests/test_top_parser.py b/polyply/tests/test_top_parser.py index 56d6e3b2..bf9a1bd4 100644 --- a/polyply/tests/test_top_parser.py +++ b/polyply/tests/test_top_parser.py @@ -384,6 +384,55 @@ def test_skip_directives(lines): "gen-pairs":'no', "fudgeLJ":1.0, "fudgeQQ":1.0} + @staticmethod + @pytest.mark.parametrize('lines', ( + """ + #define GMXERROR + #ifdef GMXERROR + #error "This will raise an error." + #endif + """, + """ + #error "This will raise an error." + """, + )) + def test_error_parsing(lines): + """ + Test that the #error pragma raises an error. + """ + new_lines = textwrap.dedent(lines) + new_lines = new_lines.splitlines() + force_field = vermouth.forcefield.ForceField(name='test_ff') + top = Topology(force_field, name="test") + with pytest.raises(NotImplementedError) as err_info: + polyply.src.top_parser.read_topology(new_lines, top) + assert str(err_info.value) == "\"This will raise an error.\"" + + @staticmethod + @pytest.mark.parametrize('lines', ( + """ + #define NOERROR + #ifdef GMXERROR + #error "This will raise an error." + #endif + """, + """ + #define NOERROR + #ifndef NOERROR + #error This will raise an error. + #endif + """, + )) + def test_error_skipped(lines): + """ + Test that the #error pragma is skipped when not defined. + """ + new_lines = textwrap.dedent(lines) + new_lines = new_lines.splitlines() + force_field = vermouth.forcefield.ForceField(name='test_ff') + top = Topology(force_field, name="test") + polyply.src.top_parser.read_topology(new_lines, top) + assert top.defines == {'NOERROR': True} def test_consistency(): """