summaryrefslogtreecommitdiff
path: root/lib/spack/external/jinja2/compiler.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/spack/external/jinja2/compiler.py')
-rw-r--r--lib/spack/external/jinja2/compiler.py88
1 files changed, 78 insertions, 10 deletions
diff --git a/lib/spack/external/jinja2/compiler.py b/lib/spack/external/jinja2/compiler.py
index b2ab6fe6a8..d534a82739 100644
--- a/lib/spack/external/jinja2/compiler.py
+++ b/lib/spack/external/jinja2/compiler.py
@@ -130,9 +130,10 @@ class MacroRef(object):
class Frame(object):
"""Holds compile time information for us."""
- def __init__(self, eval_ctx, parent=None):
+ def __init__(self, eval_ctx, parent=None, level=None):
self.eval_ctx = eval_ctx
- self.symbols = Symbols(parent and parent.symbols or None)
+ self.symbols = Symbols(parent and parent.symbols or None,
+ level=level)
# a toplevel frame is the root + soft frames such as if conditions.
self.toplevel = False
@@ -168,8 +169,10 @@ class Frame(object):
rv.symbols = self.symbols.copy()
return rv
- def inner(self):
+ def inner(self, isolated=False):
"""Return an inner frame."""
+ if isolated:
+ return Frame(self.eval_ctx, level=self.symbols.level + 1)
return Frame(self.eval_ctx, self)
def soft(self):
@@ -302,6 +305,9 @@ class CodeGenerator(NodeVisitor):
# Tracks parameter definition blocks
self._param_def_block = []
+ # Tracks the current context.
+ self._context_reference_stack = ['context']
+
# -- Various compilation helpers
def fail(self, msg, lineno):
@@ -472,8 +478,8 @@ class CodeGenerator(NodeVisitor):
if action == VAR_LOAD_PARAMETER:
pass
elif action == VAR_LOAD_RESOLVE:
- self.writeline('%s = resolve(%r)' %
- (target, param))
+ self.writeline('%s = %s(%r)' %
+ (target, self.get_resolve_func(), param))
elif action == VAR_LOAD_ALIAS:
self.writeline('%s = %s' % (target, param))
elif action == VAR_LOAD_UNDEFINED:
@@ -625,6 +631,27 @@ class CodeGenerator(NodeVisitor):
if self._param_def_block:
self._param_def_block[-1].discard(target)
+ def push_context_reference(self, target):
+ self._context_reference_stack.append(target)
+
+ def pop_context_reference(self):
+ self._context_reference_stack.pop()
+
+ def get_context_ref(self):
+ return self._context_reference_stack[-1]
+
+ def get_resolve_func(self):
+ target = self._context_reference_stack[-1]
+ if target == 'context':
+ return 'resolve'
+ return '%s.resolve' % target
+
+ def derive_context(self, frame):
+ return '%s.derived(%s)' % (
+ self.get_context_ref(),
+ self.dump_local_context(frame),
+ )
+
def parameter_is_undeclared(self, target):
"""Checks if a given target is an undeclared parameter."""
if not self._param_def_block:
@@ -793,8 +820,11 @@ class CodeGenerator(NodeVisitor):
self.writeline('if parent_template is None:')
self.indent()
level += 1
- context = node.scoped and (
- 'context.derived(%s)' % self.dump_local_context(frame)) or 'context'
+
+ if node.scoped:
+ context = self.derive_context(frame)
+ else:
+ context = self.get_context_ref()
if supports_yield_from and not self.environment.is_async and \
frame.buffer is None:
@@ -1082,9 +1112,9 @@ class CodeGenerator(NodeVisitor):
self.write(')')
if node.recursive:
- self.write(', loop_render_func, depth):')
+ self.write(', undefined, loop_render_func, depth):')
else:
- self.write(extended_loop and '):' or ':')
+ self.write(extended_loop and ', undefined):' or ':')
self.indent()
self.enter_frame(loop_frame)
@@ -1129,6 +1159,13 @@ class CodeGenerator(NodeVisitor):
self.indent()
self.blockvisit(node.body, if_frame)
self.outdent()
+ for elif_ in node.elif_:
+ self.writeline('elif ', elif_)
+ self.visit(elif_.test, if_frame)
+ self.write(':')
+ self.indent()
+ self.blockvisit(elif_.body, if_frame)
+ self.outdent()
if node.else_:
self.writeline('else:')
self.indent()
@@ -1348,7 +1385,12 @@ class CodeGenerator(NodeVisitor):
self.newline(node)
self.visit(node.target, frame)
self.write(' = (Markup if context.eval_ctx.autoescape '
- 'else identity)(concat(%s))' % block_frame.buffer)
+ 'else identity)(')
+ if node.filter is not None:
+ self.visit_Filter(node.filter, block_frame)
+ else:
+ self.write('concat(%s)' % block_frame.buffer)
+ self.write(')')
self.pop_assign_tracking(frame)
self.leave_frame(block_frame)
@@ -1373,6 +1415,18 @@ class CodeGenerator(NodeVisitor):
self.write(ref)
+ def visit_NSRef(self, node, frame):
+ # NSRefs can only be used to store values; since they use the normal
+ # `foo.bar` notation they will be parsed as a normal attribute access
+ # when used anywhere but in a `set` context
+ ref = frame.symbols.ref(node.name)
+ self.writeline('if not isinstance(%s, Namespace):' % ref)
+ self.indent()
+ self.writeline('raise TemplateRuntimeError(%r)' %
+ 'cannot assign attribute on non-namespace object')
+ self.outdent()
+ self.writeline('%s[%r]' % (ref, node.attr))
+
def visit_Const(self, node, frame):
val = node.as_const(frame.eval_ctx)
if isinstance(val, float):
@@ -1631,6 +1685,20 @@ class CodeGenerator(NodeVisitor):
self.blockvisit(node.body, scope_frame)
self.leave_frame(scope_frame)
+ def visit_OverlayScope(self, node, frame):
+ ctx = self.temporary_identifier()
+ self.writeline('%s = %s' % (ctx, self.derive_context(frame)))
+ self.writeline('%s.vars = ' % ctx)
+ self.visit(node.context, frame)
+ self.push_context_reference(ctx)
+
+ scope_frame = frame.inner(isolated=True)
+ scope_frame.symbols.analyze_node(node)
+ self.enter_frame(scope_frame)
+ self.blockvisit(node.body, scope_frame)
+ self.leave_frame(scope_frame)
+ self.pop_context_reference()
+
def visit_EvalContextModifier(self, node, frame):
for keyword in node.options:
self.writeline('context.eval_ctx.%s = ' % keyword.key)