Skip to content
Snippets Groups Projects
Commit 6bacfd87 authored by Mike Bayer's avatar Mike Bayer
Browse files

more logic for control lines, ternaries

parent 7dac1fc2
No related branches found
No related tags found
No related merge requests found
......@@ -11,6 +11,7 @@ class Lexer(object):
self.lineno = 1
self.match_position = 0
self.tag = []
self.control_line = []
def match(self, regexp, flags=None):
"""match the given regular expression string and flags to the current text position.
......@@ -49,7 +50,15 @@ class Lexer(object):
self.nodes.append(node)
if isinstance(node, parsetree.Tag):
self.tag.append(node)
elif isinstance(node, parsetree.ControlLine):
if node.isend:
self.control_line.pop()
elif node.is_primary:
self.control_line.append(node)
elif len(self.control_line) and not self.control_line[-1].is_ternary(node.keyword):
raise exceptions.SyntaxException("Keyword '%s' not a legal ternary for keyword '%s'" % (node.keyword, self.control_line[-1].keyword), self.matched_lineno, self.matched_charpos)
def parse(self):
length = len(self.text)
while (True):
......@@ -134,7 +143,6 @@ class Lexer(object):
\Z # end of string
)""", re.X | re.S)
if match:
text = match.group(1)
self.append_node(parsetree.Text, text)
......@@ -175,6 +183,12 @@ class Lexer(object):
raise exceptions.SyntaxException("Invalid control line: '%s'" % text, self.matched_lineno, self.matched_charpos)
(isend, keyword) = m2.group(1, 2)
isend = (isend is not None)
if isend:
if not len(self.control_line):
raise exceptions.SyntaxException("No starting keyword '%s' for '%s'" % (keyword, text), self.matched_lineno, self.matched_charpos)
elif self.control_line[-1].keyword != keyword:
raise exceptions.SyntaxException("Keyword '%s' doesn't match keyword '%s'" % (text, self.control_line[-1].keyword), self.matched_lineno, self.matched_charpos)
self.append_node(parsetree.ControlLine, keyword, isend, text)
else:
self.append_node(parsetree.Comment, text)
......
"""object model defining a Mako template."""
from mako import exceptions, ast
from mako import exceptions, ast, util
class Node(object):
"""base class for a Node in the parse tree."""
......@@ -18,13 +18,22 @@ class ControlLine(Node):
(markup)
% endif
"""
def __init__(self, keyword, text, isend, **kwargs):
def __init__(self, keyword, isend, text, **kwargs):
super(ControlLine, self).__init__(**kwargs)
self.text = text
self.keyword = keyword
self.isend = isend
self.is_primary = keyword in ['for','if', 'while', 'try']
def is_ternary(self, keyword):
"""return true if the given keyword is a ternary keyword for this ControlLine"""
return keyword in {
'if':util.Set(['else', 'elif']),
'try':util.Set(['except', 'finally']),
'for':util.Set(['else'])
}.get(self.keyword, [])
def __repr__(self):
return "ControlLine(%s, %s, %s, %s)" % (repr(self.keyword), repr(self.isend), repr(self.text), repr((self.lineno, self.pos)))
return "ControlLine(%s, %s, %s, %s)" % (repr(self.keyword), repr(self.text), repr(self.isend), repr((self.lineno, self.pos)))
class Text(Node):
"""defines plain text in the template."""
......
......@@ -125,10 +125,52 @@ text text la la
"""
nodes = Lexer(template).parse()
print nodes
#print nodes
assert repr(nodes) == r"""[Text('\ntext text la la\n', (1, 1)), ControlLine('if', 'if foo():', False, (3, 1)), Text(' mroe text la la blah blah\n', (4, 1)), ControlLine('if', 'endif', True, (5, 1)), Text('\n and osme more stuff\n', (6, 1)), ControlLine('for', 'for l in range(1,5):', False, (8, 1)), Text(' tex tesl asdl l is ', (9, 1)), Expression('l', [], (9, 24)), Text(' kfmas d\n', (9, 28)), ControlLine('for', 'endfor', True, (10, 1)), Text(' tetx text\n \n', (11, 1))]"""
def test_unmatched_control(self):
template = """
% if foo:
% for x in range(1,5):
% endif
"""
try:
nodes = Lexer(template).parse()
assert False
except exceptions.SyntaxException, e:
assert str(e) == "Keyword 'endif' doesn't match keyword 'for' at line: 5 char: 1"
def test_unmatched_control_2(self):
template = """
% if foo:
% for x in range(1,5):
% endlala
% endif
"""
try:
nodes = Lexer(template).parse()
assert False
except exceptions.SyntaxException, e:
assert str(e) == "Keyword 'endlala' doesn't match keyword 'for' at line: 5 char: 1"
def test_ternary_control(self):
template = """
% if x:
hi
% elif y+7==10:
there
% elif lala:
lala
% else:
hi
% endif
"""
nodes = Lexer(template).parse()
#print nodes
assert repr(nodes) == r"""[ControlLine('if', 'if x:', False, (1, 1)), Text(' hi\n', (3, 1)), ControlLine('elif', 'elif y+7==10:', False, (4, 1)), Text(' there\n', (5, 1)), ControlLine('elif', 'elif lala:', False, (6, 1)), Text(' lala\n', (7, 1)), ControlLine('else', 'else:', False, (8, 1)), Text(' hi\n', (9, 1)), ControlLine('if', 'endif', True, (10, 1))]"""
def test_integration(self):
template = """<%namespace name="foo" file="somefile.html"/>
# inherit from foobar.html
......@@ -152,7 +194,7 @@ text text la la
</table>
"""
nodes = Lexer(template).parse()
print nodes
#print nodes
assert repr(nodes) == r"""[NamespaceTag('namespace', {'name': '"foo"', 'file': '"somefile.html"'}, (1, 1), []), Text('\n', (1, 46)), Comment('inherit from foobar.html', (2, 1)), InheritTag('inherit', {'file': '"foobar.html"'}, (3, 1), []), Text('\n\n', (3, 31)), ComponentTag('component', {'name': '"header"'}, (5, 1), ["Text('\\n <div>header</div>\\n', (5, 27))"]), Text('\n', (7, 14)), ComponentTag('component', {'name': '"footer"'}, (8, 1), ["Text('\\n <div> footer</div>\\n', (8, 27))"]), Text('\n\n<table>\n', (10, 14)), ControlLine('for', 'for j in data():', False, (13, 1)), Text(' <tr>\n', (14, 1)), ControlLine('for', 'for x in j:', False, (15, 1)), Text(' <td>Hello ', (16, 1)), Expression('x', ['h'], (16, 23)), Text('</td>\n', (16, 30)), ControlLine('for', 'endfor', True, (17, 1)), Text(' </tr>\n', (18, 1)), ControlLine('for', 'endfor', True, (19, 1)), Text('</table>\n', (20, 1))]"""
if __name__ == '__main__':
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment