5"""Templating to help generate structured text."""
10_logger = logging.getLogger(
'emitter')
14 """Create a string using the same template syntax as Emitter.Emit."""
16 e._Emit(template, parameters)
17 return ''.
join(e.Fragments())
21 """An Emitter collects string fragments to be assembled into a single string.
26 self.
_bindings = bindings
or Emitter.Frame({},
None)
29 """Emits literal string with no substitution."""
32 def Emit(self, template_source, **parameters):
33 """Emits a template, substituting named parameters and returning emitters to
36 Ordinary substitution occurs at $NAME or $(NAME). If there
is no parameter
37 called NAME, the text
is left
as-
is. So long
as you don
't bind FOO as a
38 parameter, $FOO in the template will
pass through to the generated text.
40 Substitution of $?NAME
and $(?NAME) yields an empty string
if NAME
is not a
43 Values passed
as named parameters should be strings
or simple integral
46 Named holes are created at $!NAME
or $(!NAME). A hole marks a position
in
47 the template that may be filled
in later. An Emitter
is returned
for each
48 named hole
in the template. The holes are filled by emitting to the
49 corresponding emitter.
51 Subtemplates can be created by using $
52 inside of the parentheses
and will conditionally expand depending on
if
53 NAME
is set to
True or False. The text inside the parentheses may use
57 Emit returns either a single Emitter
if the template contains one hole
or a
58 tuple of emitters
for several holes,
in the order that the holes occur
in
61 The emitters
for the holes remember the parameters passed to the initial
62 call to Emit. Holes can be used to provide a binding context.
64 return self.
_Emit(template_source, parameters)
66 def _Emit(self, template_source, parameters):
67 """Implementation of Emit, with map in place of named parameters."""
71 hole_names = template._holes
76 for name
in hole_names:
77 emitter =
Emitter(parameter_bindings)
78 replacements[name] = emitter._items
79 hole_map[name] = emitter
80 full_bindings = parameter_bindings.Extend(replacements)
82 full_bindings = parameter_bindings
84 self._ApplyTemplate(template, full_bindings, self.
_items)
89 if len(hole_names) == 1:
90 return hole_map[hole_names[0]]
92 return tuple(hole_map[name]
for name
in hole_names)
95 """Returns a list of all the string fragments emitted."""
97 def _FlattenTo(item, output):
98 if isinstance(item, list):
100 _FlattenTo(subitem, output)
101 elif isinstance(item, Emitter.DeferredLookup):
102 value = item._environment.Lookup(item._lookup._name,
103 item._lookup._value_if_missing)
104 if item._lookup._subtemplate:
105 _FlattenSubtemplate(item, value, output)
107 _FlattenTo(value, output)
109 output.append(str(item))
111 def _FlattenSubtemplate(item, value, output):
112 """Handles subtemplates created by $#NAME(...)"""
115 _FlattenTo(item._lookup._subitems, output)
116 elif value
is not False:
117 if value != item._lookup._value_if_missing:
119 'Value for NAME in $#NAME(...) syntax must be a boolean'
123 _FlattenTo(value, output)
124 _FlattenTo(item._lookup._subitems, output)
125 _FlattenTo(
')', output)
128 _FlattenTo(self.
_items, output)
131 def Bind(self, var, template_source, **parameters):
132 """Adds a binding for var to this emitter."""
135 raise RuntimeError(
'Cannot have holes in Emitter.Bind')
138 value._ApplyTemplate(template, bindings, self.
_items)
142 def _ParseTemplate(self, source):
143 """Converts the template string into a Template object."""
151 match = Emitter._SUBST_RE.search(source, pos)
153 items.append(source[pos:])
155 text_fragment = source[pos:match.start()]
157 items.append(text_fragment)
160 name = match.group(1)
or match.group(2)
162 item = Emitter.Lookup(name, term, term)
165 name = match.group(3)
or match.group(4)
167 item = Emitter.Lookup(name, term, term)
171 name = match.group(5)
or match.group(6)
173 item = Emitter.Lookup(name, term,
'')
177 name = match.group(7)
183 while curr_pos <
len(source):
184 if source[curr_pos] ==
')':
188 elif source[curr_pos] ==
'(':
192 if curr_pos ==
len(source):
198 if len(matched_template._holes) > 0:
200 '$#NAME syntax cannot contains holes in its arguments')
201 item = Emitter.Lookup(name, term, term, matched_template)
206 raise RuntimeError(
'Unexpected group')
209 raise RuntimeError(
'Cannot have repeated holes %s' % holes)
210 return Emitter.Template(items, holes)
212 _SUBST_RE = re.compile(
214 r'\$(\w+)|\$\((\w+)\)|\$!(\w+)|\$\(!(\w+)\)|\$\?(\w+)|\$\(\?(\w+)\)|\$#(\w+)\('
217 def _ApplyTemplate(self, template, bindings, items_list):
218 """Emits the items from the parsed template."""
220 for item
in template._items:
221 if isinstance(item, str):
224 elif isinstance(item, Emitter.Lookup):
227 result.append(Emitter.DeferredLookup(item, bindings))
230 if item._subtemplate:
231 self._ApplyTemplate(item._subtemplate, bindings,
234 raise RuntimeError(
'Unexpected template element')
237 items_list.append(result)
239 class Lookup(object):
240 """An element of a parsed template."""
242 def __init__(self, name, original, default, subtemplate=None):
244 self._original = original
245 self._value_if_missing = default
246 self._subtemplate = subtemplate
249 class DeferredLookup(object):
250 """A lookup operation that is deferred until final string generation."""
255 def __init__(self, lookup, environment):
256 self._lookup = lookup
257 self._environment = environment
259 class Template(object):
260 """A parsed template."""
267 """A Frame is a set of bindings derived from a parent."""
271 self._parent = parent
273 def Lookup(self, name, default):
274 if name
in self._map:
275 return self._map[name]
277 return self._parent.Lookup(name, default)
281 return Emitter.Frame(map, self)
def Emit(self, template_source, **parameters)
def __init__(self, bindings=None)
def Bind(self, var, template_source, **parameters)
def _ParseTemplate(self, source)
def _Emit(self, template_source, parameters)
static void append(char **dst, size_t *count, const char *src, size_t n)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not set
def Format(template, **parameters)
static SkString join(const CommandLineFlags::StringArray &)