summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEevee (Alex Munroe) <eevee.git@veekun.com>2014-12-10 15:12:48 -0800
committerEevee (Alex Munroe) <eevee.git@veekun.com>2014-12-10 15:12:48 -0800
commitf957acd97788a7fb12f1f6b1947c41bc9ead6aaa (patch)
tree9d2de9de8c0609eaec69486372b64abbb45fa380
parent20c74b6796a244f118c2dcb4cf6b7b1e05b6789d (diff)
downloadpyscss-f957acd97788a7fb12f1f6b1947c41bc9ead6aaa.tar.gz
Stop using apply_vars on block arguments; use the parser instead.
-rw-r--r--scss/calculator.py20
-rw-r--r--scss/compiler.py6
-rw-r--r--scss/grammar/expression.g16
-rw-r--r--scss/grammar/expression.py25
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'])