--- a/mercurial/templater.py Tue Mar 29 17:27:34 2016 +0900
+++ b/mercurial/templater.py Sun Mar 27 20:29:03 2016 +0900
@@ -40,7 +40,9 @@
"end": (0, None, None, None, None),
}
-def tokenize(program, start, end):
+def tokenize(program, start, end, term=None):
+ """Parse a template expression into a stream of tokens, which must end
+ with term if specified"""
pos = start
while pos < end:
c = program[pos]
@@ -127,13 +129,15 @@
sym = program[s:pos]
yield ('symbol', sym, s)
pos -= 1
- elif c == '}':
+ elif c == term:
yield ('end', None, pos + 1)
return
else:
raise error.ParseError(_("syntax error"), pos)
pos += 1
- raise error.ParseError(_("unterminated template expansion"), start)
+ if term:
+ raise error.ParseError(_("unterminated template expansion"), start)
+ yield ('end', None, pos)
def _parsetemplate(tmpl, start, stop, quote=''):
r"""
@@ -171,7 +175,7 @@
if c == quote:
return parsed, n + 1
- parseres, pos = p.parse(tokenize(tmpl, n + 1, stop))
+ parseres, pos = p.parse(tokenize(tmpl, n + 1, stop, '}'))
parsed.append(parseres)
if quote:
@@ -218,6 +222,28 @@
assert pos == len(tmpl), 'unquoted template should be consumed'
return _unnesttemplatelist(('template', parsed))
+def _parseexpr(expr):
+ """Parse a template expression into tree
+
+ >>> _parseexpr('"foo"')
+ ('string', 'foo')
+ >>> _parseexpr('foo(bar)')
+ ('func', ('symbol', 'foo'), ('symbol', 'bar'))
+ >>> _parseexpr('foo(')
+ Traceback (most recent call last):
+ ...
+ ParseError: ('not a prefix: end', 4)
+ >>> _parseexpr('"foo" "bar"')
+ Traceback (most recent call last):
+ ...
+ ParseError: ('invalid token', 7)
+ """
+ p = parser.parser(elements)
+ tree, pos = p.parse(tokenize(expr, 0, len(expr)))
+ if pos != len(expr):
+ raise error.ParseError(_('invalid token'), pos)
+ return _unnesttemplatelist(tree)
+
def prettyformat(tree):
return parser.prettyformat(tree, ('integer', 'string', 'symbol'))