diff options
author | Eevee (Alex Munroe) <eevee.git@veekun.com> | 2014-12-10 15:12:48 -0800 |
---|---|---|
committer | Eevee (Alex Munroe) <eevee.git@veekun.com> | 2014-12-10 15:12:48 -0800 |
commit | f957acd97788a7fb12f1f6b1947c41bc9ead6aaa (patch) | |
tree | 9d2de9de8c0609eaec69486372b64abbb45fa380 | |
parent | 20c74b6796a244f118c2dcb4cf6b7b1e05b6789d (diff) | |
download | pyscss-f957acd97788a7fb12f1f6b1947c41bc9ead6aaa.tar.gz |
Stop using apply_vars on block arguments; use the parser instead.
-rw-r--r-- | scss/calculator.py | 20 | ||||
-rw-r--r-- | scss/compiler.py | 6 | ||||
-rw-r--r-- | scss/grammar/expression.g | 16 | ||||
-rw-r--r-- | scss/grammar/expression.py | 25 |
4 files changed, 58 insertions, 9 deletions
diff --git a/scss/calculator.py b/scss/calculator.py index 39eb623..c6c8fb1 100644 --- a/scss/calculator.py +++ b/scss/calculator.py @@ -113,12 +113,12 @@ class Calculator(object): return cont def calculate(self, expression, divide=False): - expression = self.evaluate_expression(expression, divide=divide) + result = self.evaluate_expression(expression, divide=divide) - if expression is None: + if result is None: return String.unquoted(self.apply_vars(expression)) - return expression + return result # TODO only used by magic-import...? def interpolate(self, var): @@ -179,6 +179,18 @@ class Calculator(object): # must not have any interpolations, right? if '#' not in string: return Literal(String.unquoted(string)) - return self.parse_expression(string, 'goal_interpolated_anything') + return self.parse_expression(string, 'goal_interpolated_literal') + + def parse_vars_and_interpolations(self, string): + """Parse a string for variables and interpolations, but don't treat + anything else as Sass syntax. Returns an AST node. + """ + # Shortcut: if there are no #s or $s in the string in the first place, + # it must not have anything of interest. + if '#' not in string and '$' not in string: + return Literal(String.unquoted(string)) + return self.parse_expression( + string, 'goal_interpolated_literal_with_vars') + __all__ = ('Calculator',) diff --git a/scss/compiler.py b/scss/compiler.py index 9bc912d..434f7ac 100644 --- a/scss/compiler.py +++ b/scss/compiler.py @@ -1139,7 +1139,11 @@ class Compilation(object): # generally? calculator = self._make_calculator(rule.namespace) if block.header.argument: - block.header.argument = calculator.apply_vars(block.header.argument) + # TODO is this correct? do ALL at-rules ALWAYS allow both vars and + # interpolation? + node = calculator.parse_vars_and_interpolations( + block.header.argument) + block.header.argument = node.evaluate(calculator).render() # TODO merge into RuleAncestry new_ancestry = list(rule.ancestry.headers) diff --git a/scss/grammar/expression.g b/scss/grammar/expression.g index 8f4e5ad..fef8959 100644 --- a/scss/grammar/expression.g +++ b/scss/grammar/expression.g @@ -45,6 +45,7 @@ parser SassExpression: token SINGLE_STRING_GUTS: '([^\'\\\\#]|[\\\\].|#(?![{]))*' token DOUBLE_STRING_GUTS: "([^\"\\\\#]|[\\\\].|#(?![{]))*" token INTERP_ANYTHING: "([^#]|#(?![{]))*" + token INTERP_NO_VARS: "([^#$]|#(?![{]))*" token INTERP_NO_PARENS: "([^#()]|#(?![{]))*" # This is a stupid lookahead used for diverting url(#{...}) to its own @@ -374,7 +375,7 @@ parser SassExpression: )* {{ return parts }} - rule goal_interpolated_anything: + rule goal_interpolated_literal: # This isn't part of the grammar, but rather a separate goal, used for # text that might contain interpolations but should not be parsed # outside of them -- e.g., selector strings. @@ -385,4 +386,17 @@ parser SassExpression: )* END {{ return Interpolation.maybe(parts) }} + rule goal_interpolated_literal_with_vars: + # Another goal used for literal text that might contain interpolations + # OR variables. Created for the header of @media blocks. + INTERP_NO_VARS {{ parts = [INTERP_NO_VARS] }} + ( + ( + interpolation {{ parts.append(interpolation) }} + | VAR {{ parts.append(Variable(VAR)) }} + ) + INTERP_NO_VARS {{ parts.append(INTERP_NO_VARS) }} + )* + END {{ return Interpolation.maybe(parts) }} + %% diff --git a/scss/grammar/expression.py b/scss/grammar/expression.py index a808eae..1d2a6b5 100644 --- a/scss/grammar/expression.py +++ b/scss/grammar/expression.py @@ -48,6 +48,7 @@ class SassExpressionScanner(Scanner): ('SINGLE_STRING_GUTS', "([^'\\\\#]|[\\\\].|#(?![{]))*"), ('DOUBLE_STRING_GUTS', '([^"\\\\#]|[\\\\].|#(?![{]))*'), ('INTERP_ANYTHING', '([^#]|#(?![{]))*'), + ('INTERP_NO_VARS', '([^#$]|#(?![{]))*'), ('INTERP_NO_PARENS', '([^#()]|#(?![{]))*'), ('INTERP_START_URL_HACK', '(?=[#][{])'), ('INTERP_START', '#[{]'), @@ -508,10 +509,10 @@ class SassExpression(Parser): parts[-1] += RPAR + INTERP_NO_PARENS return parts - def goal_interpolated_anything(self): + def goal_interpolated_literal(self): INTERP_ANYTHING = self._scan('INTERP_ANYTHING') parts = [INTERP_ANYTHING] - while self._peek(self.goal_interpolated_anything_rsts) == 'INTERP_START': + while self._peek(self.goal_interpolated_literal_rsts) == 'INTERP_START': interpolation = self.interpolation() parts.append(interpolation) INTERP_ANYTHING = self._scan('INTERP_ANYTHING') @@ -519,6 +520,22 @@ class SassExpression(Parser): END = self._scan('END') return Interpolation.maybe(parts) + def goal_interpolated_literal_with_vars(self): + INTERP_NO_VARS = self._scan('INTERP_NO_VARS') + parts = [INTERP_NO_VARS] + while self._peek(self.goal_interpolated_literal_with_vars_rsts) != 'END': + _token_ = self._peek(self.goal_interpolated_literal_with_vars_rsts_) + if _token_ == 'INTERP_START': + interpolation = self.interpolation() + parts.append(interpolation) + else: # == 'VAR' + VAR = self._scan('VAR') + parts.append(Variable(VAR)) + INTERP_NO_VARS = self._scan('INTERP_NO_VARS') + parts.append(INTERP_NO_VARS) + END = self._scan('END') + return Interpolation.maybe(parts) + atom_chks_ = frozenset(['BAREWORD', 'INTERP_START']) expr_map_or_list_rsts__ = frozenset(['LPAR', 'DOUBLE_QUOTE', 'VAR', 'URL_FUNCTION', 'BAREWORD', 'COLOR', 'ALPHA_FUNCTION', 'INTERP_START', 'SIGN', 'LITERAL_FUNCTION', 'ADD', 'NUM', 'RPAR', 'FNCT', 'NOT', 'BANG_IMPORTANT', 'SINGLE_QUOTE', '","']) u_expr_chks = frozenset(['LPAR', 'DOUBLE_QUOTE', 'BAREWORD', 'URL_FUNCTION', 'INTERP_START', 'COLOR', 'ALPHA_FUNCTION', 'VAR', 'NUM', 'FNCT', 'LITERAL_FUNCTION', 'BANG_IMPORTANT', 'SINGLE_QUOTE']) @@ -527,7 +544,9 @@ class SassExpression(Parser): argspec_items_rsts = frozenset(['RPAR', 'END', '","']) expr_slst_chks = frozenset(['INTERP_END', 'RPAR', 'END', '":"', '","']) expr_lst_rsts = frozenset(['INTERP_END', 'RPAR', 'END', '","']) + goal_interpolated_literal_rsts = frozenset(['END', 'INTERP_START']) expr_map_or_list_rsts = frozenset(['RPAR', '":"', '","']) + goal_interpolated_literal_with_vars_rsts = frozenset(['VAR', 'END', 'INTERP_START']) argspec_item_chks = frozenset(['LPAR', 'DOUBLE_QUOTE', 'VAR', 'URL_FUNCTION', 'BAREWORD', 'COLOR', 'ALPHA_FUNCTION', 'INTERP_START', 'SIGN', 'LITERAL_FUNCTION', 'ADD', 'NUM', 'FNCT', 'NOT', 'BANG_IMPORTANT', 'SINGLE_QUOTE']) a_expr_chks = frozenset(['ADD', 'SUB']) interpolated_function_parens_rsts = frozenset(['LPAR', 'RPAR', 'INTERP_START']) @@ -555,7 +574,7 @@ class SassExpression(Parser): interpolated_string_rsts = frozenset(['DOUBLE_QUOTE', 'SINGLE_QUOTE']) interpolated_bareword_rsts__ = frozenset(['LPAR', 'DOUBLE_QUOTE', 'SUB', 'ALPHA_FUNCTION', 'RPAR', 'MUL', 'INTERP_END', 'BANG_IMPORTANT', 'DIV', 'LE', 'URL_FUNCTION', 'INTERP_START', 'COLOR', 'NE', 'LT', 'NUM', '":"', 'LITERAL_FUNCTION', 'GT', 'END', 'SIGN', 'BAREWORD', 'GE', 'FNCT', 'VAR', 'EQ', 'AND', 'ADD', 'SINGLE_QUOTE', 'NOT', 'MOD', 'OR', '","']) m_expr_chks = frozenset(['MUL', 'DIV', 'MOD']) - goal_interpolated_anything_rsts = frozenset(['END', 'INTERP_START']) + goal_interpolated_literal_with_vars_rsts_ = frozenset(['VAR', 'INTERP_START']) interpolated_bare_url_rsts = frozenset(['RPAR', 'INTERP_START']) argspec_items_chks = frozenset(['KWVAR', 'LPAR', 'DOUBLE_QUOTE', 'VAR', 'URL_FUNCTION', 'BAREWORD', 'COLOR', 'ALPHA_FUNCTION', 'INTERP_START', 'SIGN', 'LITERAL_FUNCTION', 'ADD', 'NUM', 'FNCT', 'NOT', 'BANG_IMPORTANT', 'SINGLE_QUOTE']) argspec_rsts = frozenset(['KWVAR', 'LPAR', 'DOUBLE_QUOTE', 'BANG_IMPORTANT', 'END', 'SLURPYVAR', 'URL_FUNCTION', 'BAREWORD', 'COLOR', 'ALPHA_FUNCTION', 'DOTDOTDOT', 'INTERP_START', 'RPAR', 'LITERAL_FUNCTION', 'ADD', 'NUM', 'VAR', 'FNCT', 'NOT', 'SIGN', 'SINGLE_QUOTE']) |