87 {% if var %}...{% endif %} |
87 {% if var %}...{% endif %} |
88 |
88 |
89 Comments are within curly-hash markers:: |
89 Comments are within curly-hash markers:: |
90 |
90 |
91 {# This will be ignored #} |
91 {# This will be ignored #} |
|
92 |
|
93 Any of these constructs can have a hypen at the end (`-}}`, `-%}`, `-#}`), |
|
94 which will collapse the whitespace following the tag. |
92 |
95 |
93 Construct a Templite with the template text, then use `render` against a |
96 Construct a Templite with the template text, then use `render` against a |
94 dictionary context to create a finished string:: |
97 dictionary context to create a finished string:: |
95 |
98 |
96 templite = Templite(''' |
99 templite = Templite(''' |
149 ops_stack = [] |
152 ops_stack = [] |
150 |
153 |
151 # Split the text to form a list of tokens. |
154 # Split the text to form a list of tokens. |
152 tokens = re.split(r"(?s)({{.*?}}|{%.*?%}|{#.*?#})", text) |
155 tokens = re.split(r"(?s)({{.*?}}|{%.*?%}|{#.*?#})", text) |
153 |
156 |
|
157 squash = False |
|
158 |
154 for token in tokens: |
159 for token in tokens: |
155 if token.startswith('{#'): |
160 if token.startswith('{'): |
156 # Comment: ignore it and move on. |
161 start, end = 2, -2 |
157 continue |
162 squash = (token[-3] == '-') |
158 elif token.startswith('{{'): |
163 if squash: |
159 # An expression to evaluate. |
164 end = -3 |
160 expr = self._expr_code(token[2:-2].strip()) |
165 |
161 buffered.append("to_str(%s)" % expr) |
166 if token.startswith('{#'): |
162 elif token.startswith('{%'): |
167 # Comment: ignore it and move on. |
163 # Action tag: split into words and parse further. |
168 continue |
164 flush_output() |
169 elif token.startswith('{{'): |
165 words = token[2:-2].strip().split() |
170 # An expression to evaluate. |
166 if words[0] == 'if': |
171 expr = self._expr_code(token[start:end].strip()) |
167 # An if statement: evaluate the expression to determine if. |
172 buffered.append("to_str(%s)" % expr) |
168 if len(words) != 2: |
173 elif token.startswith('{%'): |
169 self._syntax_error("Don't understand if", token) |
174 # Action tag: split into words and parse further. |
170 ops_stack.append('if') |
175 flush_output() |
171 code.add_line("if %s:" % self._expr_code(words[1])) |
176 |
172 code.indent() |
177 words = token[start:end].strip().split() |
173 elif words[0] == 'for': |
178 if words[0] == 'if': |
174 # A loop: iterate over expression result. |
179 # An if statement: evaluate the expression to determine if. |
175 if len(words) != 4 or words[2] != 'in': |
180 if len(words) != 2: |
176 self._syntax_error("Don't understand for", token) |
181 self._syntax_error("Don't understand if", token) |
177 ops_stack.append('for') |
182 ops_stack.append('if') |
178 self._variable(words[1], self.loop_vars) |
183 code.add_line("if %s:" % self._expr_code(words[1])) |
179 code.add_line( |
184 code.indent() |
180 "for c_%s in %s:" % ( |
185 elif words[0] == 'for': |
181 words[1], |
186 # A loop: iterate over expression result. |
182 self._expr_code(words[3]) |
187 if len(words) != 4 or words[2] != 'in': |
|
188 self._syntax_error("Don't understand for", token) |
|
189 ops_stack.append('for') |
|
190 self._variable(words[1], self.loop_vars) |
|
191 code.add_line( |
|
192 "for c_%s in %s:" % ( |
|
193 words[1], |
|
194 self._expr_code(words[3]) |
|
195 ) |
183 ) |
196 ) |
184 ) |
197 code.indent() |
185 code.indent() |
198 elif words[0].startswith('end'): |
186 elif words[0].startswith('end'): |
199 # Endsomething. Pop the ops stack. |
187 # Endsomething. Pop the ops stack. |
200 if len(words) != 1: |
188 if len(words) != 1: |
201 self._syntax_error("Don't understand end", token) |
189 self._syntax_error("Don't understand end", token) |
202 end_what = words[0][3:] |
190 end_what = words[0][3:] |
203 if not ops_stack: |
191 if not ops_stack: |
204 self._syntax_error("Too many ends", token) |
192 self._syntax_error("Too many ends", token) |
205 start_what = ops_stack.pop() |
193 start_what = ops_stack.pop() |
206 if start_what != end_what: |
194 if start_what != end_what: |
207 self._syntax_error("Mismatched end tag", end_what) |
195 self._syntax_error("Mismatched end tag", end_what) |
208 code.dedent() |
196 code.dedent() |
209 else: |
197 else: |
210 self._syntax_error("Don't understand tag", words[0]) |
198 self._syntax_error("Don't understand tag", words[0]) |
|
199 else: |
211 else: |
200 # Literal content. If it isn't empty, output it. |
212 # Literal content. If it isn't empty, output it. |
|
213 if squash: |
|
214 token = token.lstrip() |
201 if token: |
215 if token: |
202 buffered.append(repr(token)) |
216 buffered.append(repr(token)) |
203 |
217 |
204 if ops_stack: |
218 if ops_stack: |
205 self._syntax_error("Unmatched action tag", ops_stack[-1]) |
219 self._syntax_error("Unmatched action tag", ops_stack[-1]) |