Skip to content

Commit aff935f

Browse files
committed
implements filenames and line numbers for syntax errors
1 parent 95d962b commit aff935f

4 files changed

Lines changed: 83 additions & 8 deletions

File tree

src/auxml/macro.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from copy import deepcopy
33
from auxml.util import *
44
from auxml.err import SyntaxErrorAuXML
5+
import auxml.parser as parser
6+
57
'''
68
<define-macro name="blue"><span style="color: #00f"><b><contents/></b></span></define-macro>
79
'''
@@ -27,7 +29,22 @@ def append_tail(el, s):
2729
class MacroDef():
2830
def __init__(self, el):
2931
self.el = el
32+
self.check_for_name()
3033
self.name = el.get("name")
34+
35+
def check_for_name(self):
36+
if self.el.get("name") is None:
37+
fileinfo = parser.el_location_info(self.el)
38+
msg = f'''
39+
Encountered macro definition with missing `name` attribute
40+
{fileinfo}
41+
42+
Suggestion: change the macro definition include a name attribute:
43+
44+
<define-macro name="..."> ... </define-macro>
45+
^^^^
46+
'''
47+
raise SyntaxErrorAuXML(msg)
3148

3249
def replace_one_var(self, el, varname, valuem):
3350
pass
@@ -39,12 +56,15 @@ def get_body(self):
3956
# the following line assumes the macro body only has one element.
4057
# TODO let macros definition have text and elements.
4158
cs = self.el.getchildren()
59+
fileinfo = parser.el_location_info(self.el)
4260

4361
if len(cs) == 0:
44-
raise SyntaxErrorAuXML(f"Encountered empty macro body in macro definition: `{self.name}`")
62+
# maybe this should be a warning?
63+
msg = f"Encountered empty macro body in macro definition: `{self.name}`, {fileinfo}"
64+
raise SyntaxErrorAuXML(msg)
4565

4666
if len(cs) > 1:
47-
msg = "macro definitions may not yet have more than one element"
67+
msg = f"Macro definitions may not yet have more than one element, {fileinfo}"
4868
raise SyntaxErrorAuXML(msg)
4969

5070
return deepcopy(self.el.getchildren()[0])
@@ -83,8 +103,9 @@ def attr_vars(self):
83103

84104
def ensure_attrs_match(self, mcall):
85105
for var in self.attr_vars():
86-
if not mcall.contains_attr(var):
87-
raise Exception(f"Macro call: {mcall.name()} on line ... must have attribute: {var}")
106+
if not mcall.contains_attr(var):
107+
info = mcall.fileinfo()
108+
raise SyntaxErrorAuXML(f"Macro call: {mcall.name()} on line ... must have attribute: {var} {info}")
88109

89110

90111
def replace_one_content(self, mcall, con):
@@ -196,6 +217,9 @@ def __init__(self, el):
196217
self.el = el
197218
self.counter = MacroCall.counter
198219
MacroCall.counter += 1
220+
221+
def fileinfo(self):
222+
return parser.el_location_info(self.el)
199223

200224
def unique_id(self):
201225
return f"{self.name()}-{self.counter}"

src/auxml/parser.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,39 @@
11
from lxml import etree
22
from bs4 import BeautifulSoup
3+
import pudb
4+
35
_html_parser = etree.HTMLParser(remove_blank_text=True, remove_comments=True)
46
_xml_parser = etree.XMLParser(remove_blank_text=True, remove_comments=True)
57

8+
ATTR_FILENAME = 'auxml-data-filename'
9+
ATTR_LINENUM = 'auxml-data-line'
10+
11+
def el_location_info(el):
12+
filename = el.get(ATTR_FILENAME)
13+
linenum = el.get(ATTR_LINENUM)
14+
return f'''
15+
in file ...... : {filename}
16+
on line number.. : {linenum}
17+
'''
18+
19+
def tag_els_with_info(el, fname):
20+
if hasattr(el, 'sourceline'):
21+
line_number = el.sourceline
22+
el[ATTR_FILENAME] = fname
23+
el[ATTR_LINENUM] = str(line_number)
24+
25+
for child in el.children:
26+
if isinstance(child, str):
27+
continue
28+
tag_els_with_info(child, fname)
29+
630
def parse_html_file(fname):
731
text = open(fname).read()
832
soup = BeautifulSoup(text, "html.parser")
33+
34+
# mutate soup in place
35+
tag_els_with_info(soup, fname)
36+
937
tree = etree.fromstring(str(soup), _xml_parser)
1038
return tree
1139

12-
# def parse_xml_file(fname):
13-
# tree = etree.parse(fname, _xml_parser)
14-
# return tree.getroot()
15-

tests/fileinfo_test.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import pytest
2+
import sys
3+
import pudb
4+
from lxml import etree
5+
from xmldiff.diff import Differ
6+
from auxml.macro import MacroDef, MacroCall
7+
from auxml.macro_manager import MacroManager
8+
from auxml.util import *
9+
from auxml.err import SyntaxErrorAuXML
10+
11+
12+
def with_mm_file(filename):
13+
mm = MacroManager()
14+
mm.load_macro_file(filename)
15+
16+
def causes_syntax_err(filename):
17+
with pytest.raises(SyntaxErrorAuXML):
18+
with_mm_file(filename)
19+
20+
def test_fileinfo():
21+
causes_syntax_err("tests/test-html/macros-fileinfo-1.html")
22+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<macros>
2+
<define-macro namename="bad">
3+
<div>this macro needs an attribute called "name"</div>
4+
</define-macro>
5+
</macros>

0 commit comments

Comments
 (0)