diff --git a/py/dml/ctree.py b/py/dml/ctree.py index 62d59f3b..2a466759 100644 --- a/py/dml/ctree.py +++ b/py/dml/ctree.py @@ -5167,9 +5167,10 @@ def toc(self): path = self.site.filename() (ident, h_path) = dmldir_macro(path) out('#define %s "%s"\n' % (ident, quote_filename(h_path))) - if dml.globals.linemarks: - linemark(self.site.lineno, path) - out(self.text) + for (i, line) in enumerate(self.text.splitlines(keepends=True)): + if dml.globals.linemarks: + linemark(self.site.lineno + i, path) + out(line) if not output.current().bol: out('\n') if dml.globals.linemarks: diff --git a/py/dml/output.py b/py/dml/output.py index 27acd5c5..5618adf5 100644 --- a/py/dml/output.py +++ b/py/dml/output.py @@ -35,6 +35,7 @@ def __init__(self, indent=0): self.bol = True self.redirected_filename = None self.redirected_lineno = None + self.linemark_is_fresh = False def write(self, s): assert False @@ -55,6 +56,7 @@ def linemark(self, lineno, filename): % (lineno, quote_filename(filename))) self.redirected_filename = filename self.redirected_lineno = lineno + self.linemark_is_fresh = True def reset_line_directive(self): assert self.filename is not None @@ -72,6 +74,12 @@ def indeterminate_line_directive(self): def out(self, output, preindent = 0, postindent = 0): self.indent += preindent * indent_level + if (self.bol and self.redirected_lineno is not None + and not self.linemark_is_fresh): + raise ICE(SimpleSite(f'{self.redirected_filename}' + f':{self.redirected_lineno}'), + 'missing linemark') + self.linemark_is_fresh = False if output == '\n': # Don't indent empty lines... self.write('\n') @@ -84,6 +92,10 @@ def out(self, output, preindent = 0, postindent = 0): self.write(output) self.bol = (output.endswith('\n')) no_lines = output.count('\n') + if no_lines > 1 and self.redirected_lineno is not None: + raise ICE(SimpleSite(f'{self.redirected_filename}' + f':{self.redirected_lineno}'), + 'missing linemark') self.indent += postindent * indent_level self.lineno += no_lines if self.redirected_lineno is not None: diff --git a/py/dml/output_test.py b/py/dml/output_test.py new file mode 100644 index 00000000..5867d4c1 --- /dev/null +++ b/py/dml/output_test.py @@ -0,0 +1,19 @@ +import unittest + +from dml import output, logging + +class TestOutput(unittest.TestCase): + def test_linemark_validation(self): + out = output.StrOutput() + out.linemark(3, 'foo') + out.out('foo') + # ok, not beginning of line + out.out('bar\n') + out.linemark(4, 'foo') + out.out('foo') + out.out('bar\n') + with self.assertRaisesRegex(logging.ICE, '.*missing linemark'): + out.out('foo') + out.linemark(5, 'foo') + with self.assertRaisesRegex(logging.ICE, '.*missing linemark'): + out.out('foo\nbar\n')