##// END OF EJS Templates
color: labeled text should be passed to ui.write() as ui.labeled...
color: labeled text should be passed to ui.write() as ui.labeled Some implementations of ui.label() (HTML versions in particular) must escape the provided text and then markup the text with their tags. When this marked up text is then passed to ui.write(), we must label the text as 'ui.labeled' so the implementation knows not to escape it a second time (exposing the initial markup). This required the addition of a 'ui.plain' label for text that is purposefully not marked up. I was a little pedantic here, passing even ' ' strings to ui.label() when it would be included with other labeled text in a ui.write() call. But it seemed appropriate to lean to the side of caution.

File last commit:

r11289:4215ce51 default
r11302:e1dde736 default
Show More
parser.py
91 lines | 3.5 KiB | text/x-python | PythonLexer
Matt Mackall
revset: introduce basic parser
r11274 # parser.py - simple top-down operator precedence parser for mercurial
#
# Copyright 2010 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
# see http://effbot.org/zone/simple-top-down-parsing.txt and
# http://eli.thegreenplace.net/2010/01/02/top-down-operator-precedence-parsing/
# for background
# takes a tokenizer and elements
# tokenizer is an iterator that returns type, value pairs
# elements is a mapping of types to binding strength, prefix and infix actions
# an action is a tree node name, a tree label, and an optional match
# __call__(program) parses program into a labelled tree
Matt Mackall
revset: raise ParseError exceptions
r11289 import error
Matt Mackall
revset: introduce basic parser
r11274 class parser(object):
def __init__(self, tokenizer, elements, methods=None):
self._tokenizer = tokenizer
self._elements = elements
self._methods = methods
def _advance(self):
'advance the tokenizer'
t = self.current
Matt Mackall
revset: add support for prefix and suffix versions of : and ::
r11278 try:
self.current = self._iter.next()
except StopIteration:
pass
Matt Mackall
revset: introduce basic parser
r11274 return t
def _match(self, m):
'make sure the tokenizer matches an end condition'
if self.current[0] != m:
Matt Mackall
revset: raise ParseError exceptions
r11289 raise error.ParseError("unexpected token: %s" % self.current[2],
pos)
Matt Mackall
revset: introduce basic parser
r11274 self._advance()
def _parse(self, bind=0):
Matt Mackall
revset: raise ParseError exceptions
r11289 token, value, pos = self._advance()
Matt Mackall
revset: introduce basic parser
r11274 # handle prefix rules on current token
prefix = self._elements[token][1]
if not prefix:
Matt Mackall
revset: raise ParseError exceptions
r11289 raise error.ParseError("not a prefix: %s" % token, pos)
Matt Mackall
revset: introduce basic parser
r11274 if len(prefix) == 1:
expr = (prefix[0], value)
else:
if len(prefix) > 2 and prefix[2] == self.current[0]:
self._match(prefix[2])
expr = (prefix[0], None)
else:
expr = (prefix[0], self._parse(prefix[1]))
if len(prefix) > 2:
self._match(prefix[2])
# gather tokens until we meet a lower binding strength
while bind < self._elements[self.current[0]][0]:
Matt Mackall
revset: raise ParseError exceptions
r11289 token, value, pos = self._advance()
Matt Mackall
revset: add support for prefix and suffix versions of : and ::
r11278 e = self._elements[token]
# check for suffix - next token isn't a valid prefix
if len(e) == 4 and not self._elements[self.current[0]][1]:
suffix = e[3]
expr = (suffix[0], expr)
Matt Mackall
revset: introduce basic parser
r11274 else:
Matt Mackall
revset: add support for prefix and suffix versions of : and ::
r11278 # handle infix rules
infix = self._elements[token][2]
if len(infix) == 3 and infix[2] == self.current[0]:
Matt Mackall
revset: introduce basic parser
r11274 self._match(infix[2])
Matt Mackall
revset: add support for prefix and suffix versions of : and ::
r11278 expr = (infix[0], expr, (None))
else:
if not infix[0]:
Matt Mackall
revset: raise ParseError exceptions
r11289 raise error.ParseError("not an infix: %s" % token, pos)
Matt Mackall
revset: add support for prefix and suffix versions of : and ::
r11278 expr = (infix[0], expr, self._parse(infix[1]))
if len(infix) == 3:
self._match(infix[2])
Matt Mackall
revset: introduce basic parser
r11274 return expr
def parse(self, message):
'generate a parse tree from a message'
self._iter = self._tokenizer(message)
self.current = self._iter.next()
return self._parse()
def eval(self, tree):
'recursively evaluate a parse tree using node methods'
if not isinstance(tree, tuple):
return tree
return self._methods[tree[0]](*[self.eval(t) for t in tree[1:]])
def __call__(self, message):
'parse a message into a parse tree and evaluate if methods given'
t = self.parse(message)
if self._methods:
return self.eval(t)
return t