blob: 64e4a8da0e0c8ce36e7391bd7f7d3f04cf4a5e90 [file] [log] [blame]
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
# Template loader and preprocessor.
# Preprocessor language:
# $if VAR
# $else
# $endif
# VAR must be defined in the conditions dictionary.
import os
class TemplateLoader(object):
"""Loads template files from a path."""
def __init__(self, root, subpaths, conditions = {}):
"""Initializes loader.
root - a string, the directory under which the templates are stored.
subpaths - a list of strings, subpaths of root in search order.
conditions - a dictionay from strings to booleans. Any conditional
expression must be a key in the map.
self._root = root
self._subpaths = subpaths
self._conditions = conditions
self._cache = {}
def TryLoad(self, name):
"""Returns content of template file as a string, or None of not found."""
if name in self._cache:
return self._cache[name]
for subpath in self._subpaths:
template_file = os.path.join(self._root, subpath, name)
if os.path.exists(template_file):
template = ''.join(open(template_file).readlines())
template = self._Preprocess(template, template_file)
self._cache[name] = template
return template
return None
def Load(self, name):
"""Returns contents of template file as a string, or raises an exception."""
template = self.TryLoad(name)
if template is not None: # Can be empty string
return template
raise Exception("Could not find template '%s' on %s / %s" % (
name, self._root, self._subpaths))
def _Preprocess(self, template, filename):
def error(lineno, message):
raise Exception('%s:%s: %s' % (filename, lineno, message))
lines = template.splitlines(True)
out = []
condition_stack = []
active = True
seen_else = False
for (lineno, full_line) in enumerate(lines):
line = full_line.strip()
if line.startswith('$'):
words = line.split()
directive = words[0]
if directive == '$if':
if len(words) != 2:
error(lineno, '$if does not have single variable')
variable = words[1]
if variable in self._conditions:
condition_stack.append((active, seen_else))
active = self._conditions[variable]
seen_else = False
error(lineno, "Unknown $if variable '%s'" % variable)
elif directive == '$else':
if not condition_stack:
error(lineno, '$else without $if')
if seen_else:
raise error(lineno, 'Double $else')
seen_else = True
active = not active
elif directive == '$endif':
if not condition_stack:
error(lineno, '$endif without $if')
(active, seen_else) = condition_stack.pop()
# Something else, like '$!MEMBERS'
if active:
if active:
if condition_stack:
error(len(lines), 'Unterminated $if')
return ''.join(out)