| | 63 | class BlockEvaluator: |
|---|
| | 64 | def __init__(self): |
|---|
| | 65 | self.children = [] |
|---|
| | 66 | self.delegate = None |
|---|
| | 67 | |
|---|
| | 68 | def evaluate(self, output_stream, expression_lookup): |
|---|
| | 69 | for child in self.children: |
|---|
| | 70 | child.evaluate(output_stream, expression_lookup) |
|---|
| | 71 | |
|---|
| | 72 | def add_evaluator(self, evaluator): |
|---|
| | 73 | self.children.append(evaluator) |
|---|
| | 74 | if hasattr(evaluator, 'add_evaluator'): |
|---|
| | 75 | self.delegate = evaluator |
|---|
| | 76 | |
|---|
| | 77 | def delegate_token(self, token_type, token_value): |
|---|
| | 78 | if self.delegate: |
|---|
| | 79 | if self.delegate.feed(token_type, token_value): |
|---|
| | 80 | return True |
|---|
| | 81 | else: self.delegate = None |
|---|
| | 82 | return False |
|---|
| | 83 | |
|---|
| | 84 | def feed(self, token_type, token_value): |
|---|
| | 85 | if self.delegate_token(token_type, token_value): |
|---|
| | 86 | return True |
|---|
| | 87 | if token_type == Tokeniser.END: return False |
|---|
| | 88 | elif token_type == Tokeniser.PLAIN: self.add_evaluator(PlainTextEvaluator(token_value)) |
|---|
| | 89 | elif token_type == Tokeniser.PLACEHOLDER: self.add_evaluator(PlaceholderEvaluator(token_value)) |
|---|
| | 90 | elif token_type == Tokeniser.FOREACH: self.add_evaluator(ForeachEvaluator(token_value)) |
|---|
| | 91 | elif token_type == Tokeniser.IF: self.add_evaluator(IfEvaluator(token_value)) |
|---|
| | 92 | else: raise TemplateSyntaxError("illegal token in block: %s, %s" % (token_type, token_value)) |
|---|
| | 93 | return True |
|---|
| | 94 | |
|---|
| | 95 | |
|---|
| | 96 | class PlainTextEvaluator: |
|---|
| | 97 | def __init__(self, text): |
|---|
| | 98 | self.text = text |
|---|
| | 99 | |
|---|
| | 100 | def evaluate(self, output_stream, expression_lookup): |
|---|
| | 101 | output_stream.write(self.text) |
|---|
| | 102 | |
|---|
| | 103 | |
|---|
| | 104 | class PlaceholderEvaluator: |
|---|
| | 105 | def __init__(self, token_value): |
|---|
| | 106 | self.expression, self.silent, self.original_text = token_value |
|---|
| | 107 | |
|---|
| | 108 | def evaluate(self, output_stream, expression_lookup): |
|---|
| | 109 | value = expression_lookup(self.expression) |
|---|
| | 110 | if value is None: |
|---|
| | 111 | if self.silent: expression_value = '' |
|---|
| | 112 | else: expression_value = self.original_text |
|---|
| | 113 | else: |
|---|
| | 114 | expression_value = str(value) |
|---|
| | 115 | output_stream.write(expression_value) |
|---|
| | 116 | |
|---|
| | 117 | |
|---|
| | 118 | class IfEvaluator(BlockEvaluator): |
|---|
| | 119 | def __init__(self, token_value): |
|---|
| | 120 | BlockEvaluator.__init__(self) |
|---|
| | 121 | self.condition_expression = token_value |
|---|
| | 122 | |
|---|
| | 123 | def evaluate(self, output_stream, expression_lookup): |
|---|
| | 124 | value = expression_lookup(self.condition_expression) |
|---|
| | 125 | if value: |
|---|
| | 126 | BlockEvaluator.evaluate(self, output_stream, expression_lookup) |
|---|
| | 127 | |
|---|
| | 128 | |
|---|
| | 129 | class ForeachEvaluator(BlockEvaluator): |
|---|
| | 130 | def __init__(self, token_value): |
|---|
| | 131 | BlockEvaluator.__init__(self) |
|---|
| | 132 | self.expression, self.iter_var = token_value |
|---|
| | 133 | |
|---|
| | 134 | def evaluate(self, output_stream, expression_lookup): |
|---|
| | 135 | values = expression_lookup(self.expression) |
|---|
| | 136 | for value in values: |
|---|
| | 137 | BlockEvaluator.evaluate(self, output_stream, expression_lookup) |
|---|
| | 138 | |
|---|
| | 139 | |
|---|
| 69 | | filter_output_at_nesting_level = [False] |
|---|
| 70 | | tokens = list(Tokeniser().tokenise(str(content))) |
|---|
| 71 | | tokens.reverse() |
|---|
| 72 | | while tokens: |
|---|
| 73 | | token_type, token_value = tokens.pop() |
|---|
| 74 | | filter_at_this_level = filter_output_at_nesting_level[-1] |
|---|
| 75 | | if token_type == Tokeniser.PLAIN: |
|---|
| 76 | | if not filter_at_this_level: output.append(token_value) |
|---|
| 77 | | continue |
|---|
| 78 | | if token_type == Tokeniser.PLACEHOLDER: |
|---|
| 79 | | expression, silent, original_text = token_value |
|---|
| 80 | | value = self.find(expression) |
|---|
| 81 | | if value is None: |
|---|
| 82 | | if silent: expression_value = '' |
|---|
| 83 | | else: expression_value = original_text |
|---|
| 84 | | else: |
|---|
| 85 | | expression_value = str(value) |
|---|
| 86 | | if not filter_at_this_level: output.append(expression_value) |
|---|
| 87 | | continue |
|---|
| 88 | | if token_type == Tokeniser.IF: |
|---|
| 89 | | value = self.find(token_value) |
|---|
| 90 | | filter_my_content = filter_at_this_level or not bool(value) |
|---|
| 91 | | filter_output_at_nesting_level.append(filter_my_content) |
|---|
| 92 | | continue |
|---|
| 93 | | if token_type == Tokeniser.FOREACH: |
|---|
| 94 | | expression, iter_var = token_value |
|---|
| 95 | | filter_output_at_nesting_level.append(filter_at_this_level) |
|---|
| 96 | | token_type, token_value = tokens.pop() |
|---|
| 97 | | values = self.find(expression) |
|---|
| 98 | | if token_type == Tokeniser.PLAIN: |
|---|
| 99 | | for item in values: |
|---|
| 100 | | if not filter_at_this_level: output.append(token_value) |
|---|
| 101 | | continue |
|---|
| 102 | | if token_type == Tokeniser.END: |
|---|
| 103 | | if len(filter_output_at_nesting_level) == 1: |
|---|
| 104 | | raise TemplateSyntaxError("#end without beginning of block") |
|---|
| 105 | | del filter_output_at_nesting_level[-1] |
|---|
| 106 | | continue |
|---|
| 107 | | raise TemplateSyntaxError("invalid token: %s" % text[:40]) |
|---|
| 108 | | |
|---|
| 109 | | if len(filter_output_at_nesting_level) > 1: |
|---|
| 110 | | raise TemplateSyntaxError("Unclosed block") |
|---|
| 111 | | return ''.join(output) |
|---|
| 112 | | |
|---|
| | 146 | evaluator = BlockEvaluator() |
|---|
| | 147 | for token_type, token_value in Tokeniser().tokenise(str(content)): |
|---|
| | 148 | evaluator.feed(token_type, token_value) |
|---|
| | 149 | output = StringIO.StringIO() |
|---|
| | 150 | evaluator.evaluate(output, self.find) |
|---|
| | 151 | return output.getvalue() |
|---|