From abaef3e26f435c650b2b9409e33f6a14fdca4246 Mon Sep 17 00:00:00 2001 From: msolo Date: Thu, 9 Jun 2011 21:06:58 +0000 Subject: [PATCH] integrate fixes for optional whitespace when using #strip_lines --- spitfire/compiler/ast.py | 9 +++++---- spitfire/compiler/parser.g | 18 ++++++++--------- spitfire/compiler/parser.py | 20 +++++++++---------- tests/condensed_if.tmpl | 17 ++++++++++++++-- .../condensed_if.txt | 2 +- tests/output/condensed_if.txt | 2 +- tests/output/template_elif_2.txt | 2 +- 7 files changed, 42 insertions(+), 28 deletions(-) diff --git a/spitfire/compiler/ast.py b/spitfire/compiler/ast.py index 732d24e..1346c1c 100644 --- a/spitfire/compiler/ast.py +++ b/spitfire/compiler/ast.py @@ -801,9 +801,10 @@ def make_optional(node_list): pass # this is another hack to support line-wise stripping of white space nodes -# inside a #strip_lines directive -def strip_whitespace(node_list): - optional = True +# inside a #strip_lines directive. +def strip_whitespace(node_list, starts_new_line=True): + # starts as optional only if we're at the beginning of a new line. + optional = starts_new_line for i, node in enumerate(node_list): if isinstance(node, (OptionalWhitespaceNode, NewlineNode)): optional = True @@ -820,7 +821,7 @@ def strip_whitespace(node_list): optional = False elif not (node.statement or node.child_nodes or isinstance(node, CommentNode)): optional = False - + if optional and i > 0: prev_node = node_list[i - 1] if isinstance(prev_node, TextNode): diff --git a/spitfire/compiler/parser.g b/spitfire/compiler/parser.g index f81be62..6219aae 100644 --- a/spitfire/compiler/parser.g +++ b/spitfire/compiler/parser.g @@ -155,7 +155,7 @@ parser _SpitfireParser: 'block' SPACE ID CLOSE_DIRECTIVE {{ _block = BlockNode(ID) }} {{ start = CLOSE_DIRECTIVE.endswith('\n') }} ( block<> {{ _block.append(block) }} ) * - {{ self.make_optional(_block.child_nodes) }} + {{ self.make_optional(_block.child_nodes, start) }} END_DIRECTIVE SPACE 'block' CLOSE_DIRECTIVE {{ _node_list.append(_block) }} | 'i18n' {{ _macro = MacroNode('i18n') }} @@ -180,14 +180,14 @@ parser _SpitfireParser: CLOSE_DIRECTIVE {{ start = CLOSE_DIRECTIVE.endswith('\n') }} ( block<> {{ _def.append(block) }} ) * - {{ self.make_optional(_def.child_nodes) }} + {{ self.make_optional(_def.child_nodes, start) }} END_DIRECTIVE SPACE 'def' CLOSE_DIRECTIVE {{ _node_list.append(_def) }} | 'for[ \t]*' target_list '[ \t]*in[ \t]*' expression_list CLOSE_DIRECTIVE {{ _for_loop = ForNode(target_list, expression_list) }} {{ start = CLOSE_DIRECTIVE.endswith('\n') }} ( block<> {{ _for_loop.append(block) }} ) * - {{ self.make_optional(_for_loop.child_nodes) }} + {{ self.make_optional(_for_loop.child_nodes, start) }} END_DIRECTIVE SPACE 'for' CLOSE_DIRECTIVE {{ _node_list.append(_for_loop) }} | 'strip_lines' @@ -198,7 +198,7 @@ parser _SpitfireParser: {{ _strip_lines_node = StripLinesNode() }} {{ start = CLOSE_DIRECTIVE.endswith('\n') }} ( block<> {{ _strip_lines_node.append(block) }} ) * - {{ self.make_optional(_strip_lines_node.child_nodes) }} + {{ self.make_optional(_strip_lines_node.child_nodes, start) }} {{ self.strip_whitespace = False }} END_DIRECTIVE SPACE 'strip_lines' CLOSE_DIRECTIVE {{ _node_list.append(_strip_lines_node) }} | @@ -206,19 +206,19 @@ parser _SpitfireParser: {{ _last_condition_node = _if_node }} {{ start = CLOSE_DIRECTIVE.endswith('\n') }} ( block<> {{ _if_node.append(block) }} ) * - {{ self.make_optional(_if_node.child_nodes) }} + {{ self.make_optional(_if_node.child_nodes, start) }} ( '#elif' SPACE expression CLOSE_DIRECTIVE {{ _elif_node = IfNode(expression) }} {{ _last_condition_node.else_.append(_elif_node) }} {{ _last_condition_node = _elif_node }} {{ start = CLOSE_DIRECTIVE.endswith('\n') }} ( block<> {{ _elif_node.append(block) }} ) * + {{ self.make_optional(_elif_node.child_nodes, start) }} ) * - {{ self.make_optional(_last_condition_node.child_nodes) }} [ '#else' CLOSE_DIRECTIVE {{ start = CLOSE_DIRECTIVE.endswith('\n') }} ( block<> {{ _last_condition_node.else_.append(block) }} ) * - {{ self.make_optional(_last_condition_node.else_.child_nodes) }} + {{ self.make_optional(_last_condition_node.else_.child_nodes, start) }} ] END_DIRECTIVE SPACE 'if' CLOSE_DIRECTIVE {{ _node_list.append(_if_node) }} | @@ -570,8 +570,8 @@ parser _SpitfireParser: class SpitfireParser(_SpitfireParser): strip_whitespace = False - def make_optional(self, node_list): + def make_optional(self, node_list, starts_new_line=False): if self.strip_whitespace: - return strip_whitespace(node_list) + return strip_whitespace(node_list, starts_new_line=starts_new_line) else: return make_optional(node_list) diff --git a/spitfire/compiler/parser.py b/spitfire/compiler/parser.py index 897442d..13e4541 100644 --- a/spitfire/compiler/parser.py +++ b/spitfire/compiler/parser.py @@ -261,7 +261,7 @@ def directive(self): while self._peek('LITERAL_DOLLAR_SIGN', 'LITERAL_BACKSLASH', 'START_DIRECTIVE', 'SPACE', 'NEWLINE', 'START_PLACEHOLDER', 'END_DIRECTIVE', 'TEXT') != 'END_DIRECTIVE': block = self.block(start) _block.append(block) - self.make_optional(_block.child_nodes) + self.make_optional(_block.child_nodes, start) END_DIRECTIVE = self._scan('END_DIRECTIVE') SPACE = self._scan('SPACE') self._scan("'block'") @@ -306,7 +306,7 @@ def directive(self): while self._peek('LITERAL_DOLLAR_SIGN', 'LITERAL_BACKSLASH', 'START_DIRECTIVE', 'SPACE', 'NEWLINE', 'START_PLACEHOLDER', 'END_DIRECTIVE', 'TEXT') != 'END_DIRECTIVE': block = self.block(start) _def.append(block) - self.make_optional(_def.child_nodes) + self.make_optional(_def.child_nodes, start) END_DIRECTIVE = self._scan('END_DIRECTIVE') SPACE = self._scan('SPACE') self._scan("'def'") @@ -323,7 +323,7 @@ def directive(self): while self._peek('LITERAL_DOLLAR_SIGN', 'LITERAL_BACKSLASH', 'START_DIRECTIVE', 'SPACE', 'NEWLINE', 'START_PLACEHOLDER', 'END_DIRECTIVE', 'TEXT') != 'END_DIRECTIVE': block = self.block(start) _for_loop.append(block) - self.make_optional(_for_loop.child_nodes) + self.make_optional(_for_loop.child_nodes, start) END_DIRECTIVE = self._scan('END_DIRECTIVE') SPACE = self._scan('SPACE') self._scan("'for'") @@ -338,7 +338,7 @@ def directive(self): while self._peek('LITERAL_DOLLAR_SIGN', 'LITERAL_BACKSLASH', 'START_DIRECTIVE', 'SPACE', 'NEWLINE', 'START_PLACEHOLDER', 'TEXT', 'END_DIRECTIVE') != 'END_DIRECTIVE': block = self.block(start) _strip_lines_node.append(block) - self.make_optional(_strip_lines_node.child_nodes) + self.make_optional(_strip_lines_node.child_nodes, start) self.strip_whitespace = False END_DIRECTIVE = self._scan('END_DIRECTIVE') SPACE = self._scan('SPACE') @@ -356,8 +356,8 @@ def directive(self): while self._peek('LITERAL_DOLLAR_SIGN', 'LITERAL_BACKSLASH', 'START_DIRECTIVE', 'SPACE', 'NEWLINE', 'START_PLACEHOLDER', "'#elif'", 'TEXT', "'#else'", 'END_DIRECTIVE') not in ["'#elif'", "'#else'", 'END_DIRECTIVE']: block = self.block(start) _if_node.append(block) - self.make_optional(_if_node.child_nodes) - while self._peek("'#elif'", 'LITERAL_DOLLAR_SIGN', 'LITERAL_BACKSLASH', 'START_DIRECTIVE', 'SPACE', 'NEWLINE', 'START_PLACEHOLDER', "'#else'", 'TEXT', 'END_DIRECTIVE') == "'#elif'": + self.make_optional(_if_node.child_nodes, start) + while self._peek("'#elif'", "'#else'", 'END_DIRECTIVE') == "'#elif'": self._scan("'#elif'") SPACE = self._scan('SPACE') expression = self.expression() @@ -369,7 +369,7 @@ def directive(self): while self._peek('LITERAL_DOLLAR_SIGN', 'LITERAL_BACKSLASH', 'START_DIRECTIVE', 'SPACE', 'NEWLINE', 'START_PLACEHOLDER', 'TEXT', "'#elif'", "'#else'", 'END_DIRECTIVE') not in ["'#elif'", "'#else'", 'END_DIRECTIVE']: block = self.block(start) _elif_node.append(block) - self.make_optional(_last_condition_node.child_nodes) + self.make_optional(_elif_node.child_nodes, start) if self._peek("'#else'", 'END_DIRECTIVE') == "'#else'": self._scan("'#else'") CLOSE_DIRECTIVE = self.CLOSE_DIRECTIVE() @@ -377,7 +377,7 @@ def directive(self): while self._peek('LITERAL_DOLLAR_SIGN', 'LITERAL_BACKSLASH', 'START_DIRECTIVE', 'SPACE', 'NEWLINE', 'START_PLACEHOLDER', 'TEXT', 'END_DIRECTIVE') != 'END_DIRECTIVE': block = self.block(start) _last_condition_node.else_.append(block) - self.make_optional(_last_condition_node.else_.child_nodes) + self.make_optional(_last_condition_node.else_.child_nodes, start) END_DIRECTIVE = self._scan('END_DIRECTIVE') SPACE = self._scan('SPACE') self._scan("'if'") @@ -867,8 +867,8 @@ def parse(rule, text): class SpitfireParser(_SpitfireParser): strip_whitespace = False - def make_optional(self, node_list): + def make_optional(self, node_list, starts_new_line=False): if self.strip_whitespace: - return strip_whitespace(node_list) + return strip_whitespace(node_list, starts_new_line=starts_new_line) else: return make_optional(node_list) diff --git a/tests/condensed_if.tmpl b/tests/condensed_if.tmpl index a64eedd..a59bea8 100644 --- a/tests/condensed_if.tmpl +++ b/tests/condensed_if.tmpl @@ -1,8 +1,21 @@ #strip_lines #set $there = "there" - #if $there - everywhere + + #if $there + everywhere + #end if + + ## Test for a bug where the space after #if $foo# is considered optional. + #if $there# somewhere #end if# + + ## Test for a bug where the space is preserved only inside the #elif. + #if not $there + will not evaluate + #elif $there.strip() + nowhere + #elif $there + will not evaluate #end if $there #end strip_lines diff --git a/tests/output-preserve-whitespace/condensed_if.txt b/tests/output-preserve-whitespace/condensed_if.txt index e002b1f..af1b6ce 100644 --- a/tests/output-preserve-whitespace/condensed_if.txt +++ b/tests/output-preserve-whitespace/condensed_if.txt @@ -1 +1 @@ - everywhere there + everywhere somewhere nowhere there diff --git a/tests/output/condensed_if.txt b/tests/output/condensed_if.txt index c067cce..5e823b7 100644 --- a/tests/output/condensed_if.txt +++ b/tests/output/condensed_if.txt @@ -1 +1 @@ - everywhere there + everywhere somewhere nowhere there diff --git a/tests/output/template_elif_2.txt b/tests/output/template_elif_2.txt index 2899861..68e6fad 100644 --- a/tests/output/template_elif_2.txt +++ b/tests/output/template_elif_2.txt @@ -1,4 +1,4 @@ test if 1 test elif 1 1 - test elif 2 1 + test elif 2 1 else nothing 0 0