880f4d814a
Review URL: https://chromiumcodereview.appspot.com//10913125 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@12082 260f80e4-7a28-3924-810f-c04153c831b5
117 lines
3.4 KiB
Python
117 lines
3.4 KiB
Python
#!/usr/bin/python
|
|
# 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:
|
|
#
|
|
# //$ Comment line removed by preprocessor
|
|
# $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.
|
|
|
|
Args:
|
|
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
|
|
else:
|
|
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()
|
|
|
|
else:
|
|
# Something else, like '$!MEMBERS'
|
|
if active:
|
|
out.append(full_line)
|
|
elif line.startswith('//$'):
|
|
pass # Ignore pre-processor comment.
|
|
|
|
else:
|
|
if active:
|
|
out.append(full_line)
|
|
continue
|
|
|
|
if condition_stack:
|
|
error(len(lines), 'Unterminated $if')
|
|
|
|
return ''.join(out)
|