Add support for f-strings to PTL compiler.
This commit is contained in:
parent
5e147894d4
commit
fad65207ef
|
@ -48,6 +48,8 @@ except ImportError:
|
|||
from quixote.html._py_htmltext import htmltext, htmlescape, \
|
||||
stringify, TemplateIO
|
||||
|
||||
from quixote.html._py_htmltext import _wraparg
|
||||
|
||||
ValuelessAttr = object() # magic singleton object
|
||||
|
||||
def htmltag(tag, xml_end=False, css_class=None, **attrs):
|
||||
|
@ -106,6 +108,34 @@ def url_quote(value, fallback=None):
|
|||
return fallback
|
||||
return urllib.parse.quote(stringify(value))
|
||||
|
||||
def _q_join(*args):
|
||||
# Used by f-strings to join the {..} parts
|
||||
return htmltext('').join(args)
|
||||
|
||||
def _q_format(value, conversion=-1, format_spec=None):
|
||||
# Used by f-strings to format the {..} parts
|
||||
if conversion == -1 and format_spec is None:
|
||||
return htmlescape(value) # simple and fast case
|
||||
if conversion == -1:
|
||||
fmt = '{%s}'
|
||||
else:
|
||||
conversion = chr(conversion)
|
||||
if conversion == 'r':
|
||||
fmt = '{%s!r}'
|
||||
elif conversion == 's':
|
||||
fmt = '{%s!s}'
|
||||
elif conversion == 'a':
|
||||
fmt = '{%s!a}'
|
||||
else:
|
||||
assert 0, 'invalid conversion %r' % conversion
|
||||
arg = _wraparg(value)
|
||||
if format_spec:
|
||||
fmt = fmt % (':' + str(format_spec))
|
||||
else:
|
||||
fmt = fmt % ''
|
||||
return htmltext(fmt.format(arg))
|
||||
|
||||
|
||||
_saved = None
|
||||
def use_qpy():
|
||||
"""
|
||||
|
|
|
@ -35,7 +35,12 @@ class TemplateTransformer(ast.NodeTransformer):
|
|||
names=[ast.alias(name='TemplateIO',
|
||||
asname='_q_TemplateIO'),
|
||||
ast.alias(name='htmltext',
|
||||
asname='_q_htmltext')],
|
||||
asname='_q_htmltext'),
|
||||
ast.alias(name='_q_join',
|
||||
asname='_q_join'),
|
||||
ast.alias(name='_q_format',
|
||||
asname='_q_format'),
|
||||
],
|
||||
level=0)
|
||||
ast.fix_missing_locations(html_imp)
|
||||
vars_imp = ast.ImportFrom(module='builtins',
|
||||
|
@ -116,6 +121,46 @@ class TemplateTransformer(ast.NodeTransformer):
|
|||
else:
|
||||
return node
|
||||
|
||||
def visit_JoinedStr(self, node):
|
||||
# JoinedStr is used for combining the parts of an f-string.
|
||||
# In CPython, it is done with the BUILD_STRING opcode. We
|
||||
# call quixote.html._q_join() instead
|
||||
node = self.generic_visit(node)
|
||||
if "html" == self._get_template_type():
|
||||
n = ast.Name(id='_q_join', ctx=ast.Load())
|
||||
n = ast.Call(func=n, args=node.values, keywords=[],
|
||||
starargs=None,
|
||||
kwargs=None)
|
||||
ast.copy_location(n, node)
|
||||
ast.fix_missing_locations(n)
|
||||
return n
|
||||
else:
|
||||
return node
|
||||
|
||||
def visit_FormattedValue(self, node):
|
||||
# FormattedValue is used for the {..} parts of an f-string.
|
||||
# In CPython, there is a FORMAT_VALUE opcode. We call
|
||||
# quixote.html._q_format instead.
|
||||
node = self.generic_visit(node)
|
||||
if "html" == self._get_template_type():
|
||||
n = ast.Name(id='_q_format', ctx=ast.Load())
|
||||
conversion = ast.copy_location(ast.Num(node.conversion), node)
|
||||
args = [node.value]
|
||||
if node.format_spec is not None:
|
||||
args += [conversion, node.format_spec]
|
||||
elif node.conversion != -1:
|
||||
args += [conversion]
|
||||
n = ast.Call(func=n, args=args,
|
||||
keywords=[],
|
||||
starargs=None,
|
||||
kwargs=None)
|
||||
ast.copy_location(n, node)
|
||||
ast.fix_missing_locations(n)
|
||||
return n
|
||||
else:
|
||||
return node
|
||||
|
||||
|
||||
_template_re = re.compile(r'''
|
||||
^(?P<indent>[ \t]*) def (?:[ \t]+)
|
||||
(?P<name>[a-zA-Z_][a-zA-Z_0-9]*)
|
||||
|
|
Loading…
Reference in New Issue