summaryrefslogtreecommitdiff
path: root/scss/grammar/expression.py
diff options
context:
space:
mode:
Diffstat (limited to 'scss/grammar/expression.py')
-rw-r--r--scss/grammar/expression.py179
1 files changed, 130 insertions, 49 deletions
diff --git a/scss/grammar/expression.py b/scss/grammar/expression.py
index aed08b9..7a5f8e6 100644
--- a/scss/grammar/expression.py
+++ b/scss/grammar/expression.py
@@ -14,11 +14,13 @@ from scss.ast import AnyOp
from scss.ast import AllOp
from scss.ast import NotOp
from scss.ast import CallOp
-from scss.ast import Variable
+from scss.ast import Interpolation
from scss.ast import Literal
+from scss.ast import Variable
from scss.ast import ListLiteral
from scss.ast import MapLiteral
from scss.ast import ArgspecLiteral
+from scss.cssdefs import unescape
from scss.types import Color
from scss.types import Number
from scss.types import String
@@ -33,8 +35,6 @@ from scss.grammar import Scanner
class SassExpressionScanner(Scanner):
patterns = None
_patterns = [
- ('"\'"', "'"),
- ('"\\""', '"'),
('"url"', 'url'),
('":"', ':'),
('","', ','),
@@ -58,6 +58,10 @@ class SassExpressionScanner(Scanner):
('LT', '<'),
('GT', '>'),
('DOTDOTDOT', '[.]{3}'),
+ ('SINGLE_QUOTE', "'"),
+ ('DOUBLE_QUOTE', '"'),
+ ('SINGLE_STRING_GUTS', "([^'\\\\#]|[\\\\].|#(?![{]))*"),
+ ('DOUBLE_STRING_GUTS', '([^"\\\\#]|[\\\\].|#(?![{]))*'),
('KWSTR', "'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'(?=\\s*:)"),
('STR', "'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'"),
('KWQSTR', '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"(?=\\s*:)'),
@@ -72,9 +76,12 @@ class SassExpressionScanner(Scanner):
('VAR', '\\$[-a-zA-Z0-9_]+'),
('FNCT', '[-a-zA-Z_][-a-zA-Z0-9_]*(?=\\()'),
('KWID', '[-a-zA-Z_][-a-zA-Z0-9_]*(?=\\s*:)'),
- ('ID', '[-a-zA-Z_][-a-zA-Z0-9_]*'),
+ ('BAREWORD', '[-a-zA-Z_][-a-zA-Z0-9_]*'),
('BANG_IMPORTANT', '!important'),
- ('URL', '(?:[\\\\].|[^$\'"()\\x00-\\x08\\x0b\\x0e-\\x1f\\x7f])*'),
+ ('INTERP_START', '#[{]'),
+ ('INTERP_END', '[}]'),
+ ('INTERP_ANYTHING', '([^#]|#(?![{]))*'),
+ ('BAREURL', '(?:[\\\\].|[^#$\'"()\\x00-\\x08\\x0b\\x0e-\\x1f\\x7f]|#(?![{]))*'),
]
def __init__(self, input=None):
@@ -166,7 +173,7 @@ class SassExpression(Parser):
def expr_lst(self):
expr_slst = self.expr_slst()
v = [expr_slst]
- while self._peek(self.argspec_items_rsts) == '","':
+ while self._peek(self.expr_lst_rsts) == '","':
self._scan('","')
expr_slst = self.expr_slst()
v.append(expr_slst)
@@ -175,7 +182,7 @@ class SassExpression(Parser):
def expr_slst(self):
or_expr = self.or_expr()
v = [or_expr]
- while self._peek(self.expr_slst_rsts) not in self.argspec_items_rsts:
+ while self._peek(self.expr_slst_rsts) not in self.expr_lst_rsts:
or_expr = self.or_expr()
v.append(or_expr)
return ListLiteral(v, comma=False) if len(v) > 1 else v[0]
@@ -301,22 +308,9 @@ class SassExpression(Parser):
elif _token_ == '"url"':
self._scan('"url"')
LPAR = self._scan('LPAR')
- _token_ = self._peek(self.atom_rsts_)
- if _token_ == 'URL':
- URL = self._scan('URL')
- quotes = None
- elif _token_ == '"\\""':
- self._scan('"\\""')
- URL = self._scan('URL')
- self._scan('"\\""')
- quotes = '"'
- else: # == '"\'"'
- self._scan('"\'"')
- URL = self._scan('URL')
- self._scan('"\'"')
- quotes = "'"
+ interpolated_url = self.interpolated_url()
RPAR = self._scan('RPAR')
- return Literal(Url(URL, quotes=quotes))
+ print("url!"); return interpolated_url
elif _token_ == 'FNCT':
FNCT = self._scan('FNCT')
LPAR = self._scan('LPAR')
@@ -326,21 +320,18 @@ class SassExpression(Parser):
elif _token_ == 'BANG_IMPORTANT':
BANG_IMPORTANT = self._scan('BANG_IMPORTANT')
return Literal(String(BANG_IMPORTANT, quotes=None))
- elif _token_ == 'ID':
- ID = self._scan('ID')
- return Literal.from_bareword(ID)
+ elif _token_ == 'BAREWORD':
+ interpolated_bareword = self.interpolated_bareword()
+ return Interpolation.maybe(interpolated_bareword)
elif _token_ == 'NUM':
NUM = self._scan('NUM')
UNITS = None
- if self._peek(self.atom_rsts__) == 'UNITS':
+ if self._peek(self.atom_rsts_) == 'UNITS':
UNITS = self._scan('UNITS')
return Literal(Number(float(NUM), unit=UNITS))
- elif _token_ == 'STR':
- STR = self._scan('STR')
- return Literal(String(dequote(STR), quotes="'"))
- elif _token_ == 'QSTR':
- QSTR = self._scan('QSTR')
- return Literal(String(dequote(QSTR), quotes='"'))
+ elif _token_ not in self.atom_chks:
+ interpolated_string = self.interpolated_string()
+ return interpolated_string
elif _token_ == 'COLOR':
COLOR = self._scan('COLOR')
return Literal(Color.from_hex(COLOR, literal=True))
@@ -374,32 +365,122 @@ class SassExpression(Parser):
KWVAR = self._scan('KWVAR')
return Variable(KWVAR)
- u_expr_chks = set(['"url"', 'LPAR', 'COLOR', 'QSTR', 'NUM', 'FNCT', 'STR', 'VAR', 'BANG_IMPORTANT', 'ID'])
- m_expr_rsts = set(['LPAR', 'SUB', 'QSTR', 'RPAR', 'MUL', 'DIV', 'BANG_IMPORTANT', 'LE', 'COLOR', 'NE', 'LT', 'NUM', '"url"', 'GT', 'END', 'SIGN', 'GE', 'FNCT', 'STR', 'VAR', 'EQ', 'ID', 'AND', 'ADD', 'NOT', 'OR', '","'])
+ def interpolation(self):
+ INTERP_START = self._scan('INTERP_START')
+ expr_lst = self.expr_lst()
+ INTERP_END = self._scan('INTERP_END')
+ return expr_lst
+
+ def interpolated_url(self):
+ _token_ = self._peek(self.interpolated_url_rsts)
+ if _token_ == 'BAREURL':
+ interpolated_bare_url = self.interpolated_bare_url()
+ return Interpolation.maybe(interpolated_bare_url, type=Url, quotes=None)
+ elif _token_ == 'SINGLE_QUOTE':
+ interpolated_string_single = self.interpolated_string_single()
+ return Interpolation.maybe(interpolated_string_single, type=Url, quotes="'")
+ else: # == 'DOUBLE_QUOTE'
+ interpolated_string_double = self.interpolated_string_double()
+ return Interpolation.maybe(interpolated_string_double, type=Url, quotes='"')
+
+ def interpolated_bare_url(self):
+ BAREURL = self._scan('BAREURL')
+ parts = [unescape(BAREURL)]
+ while self._peek(self.interpolated_bare_url_rsts) == 'INTERP_START':
+ interpolation = self.interpolation()
+ parts.append(interpolation)
+ BAREURL = self._scan('BAREURL')
+ parts.append(unescape(BAREURL))
+ return parts
+
+ def interpolated_string(self):
+ _token_ = self._peek(self.interpolated_string_rsts)
+ if _token_ == 'SINGLE_QUOTE':
+ interpolated_string_single = self.interpolated_string_single()
+ return Interpolation.maybe(interpolated_string_single, quotes="'")
+ else: # == 'DOUBLE_QUOTE'
+ interpolated_string_double = self.interpolated_string_double()
+ return Interpolation.maybe(interpolated_string_double, quotes='"')
+
+ def interpolated_string_single(self):
+ SINGLE_QUOTE = self._scan('SINGLE_QUOTE')
+ SINGLE_STRING_GUTS = self._scan('SINGLE_STRING_GUTS')
+ parts = [unescape(SINGLE_STRING_GUTS)]
+ while self._peek(self.interpolated_string_single_rsts) == 'INTERP_START':
+ interpolation = self.interpolation()
+ parts.append(interpolation)
+ SINGLE_STRING_GUTS = self._scan('SINGLE_STRING_GUTS')
+ parts.append(unescape(SINGLE_STRING_GUTS))
+ SINGLE_QUOTE = self._scan('SINGLE_QUOTE')
+ return parts
+
+ def interpolated_string_double(self):
+ DOUBLE_QUOTE = self._scan('DOUBLE_QUOTE')
+ DOUBLE_STRING_GUTS = self._scan('DOUBLE_STRING_GUTS')
+ parts = [unescape(DOUBLE_STRING_GUTS)]
+ while self._peek(self.interpolated_string_double_rsts) == 'INTERP_START':
+ interpolation = self.interpolation()
+ parts.append(interpolation)
+ DOUBLE_STRING_GUTS = self._scan('DOUBLE_STRING_GUTS')
+ parts.append(unescape(DOUBLE_STRING_GUTS))
+ DOUBLE_QUOTE = self._scan('DOUBLE_QUOTE')
+ return parts
+
+ def interpolated_bareword(self):
+ BAREWORD = self._scan('BAREWORD')
+ parts = [unescape(BAREWORD)]
+ while self._peek(self.interpolated_bareword_rsts) == 'INTERP_START':
+ interpolation = self.interpolation()
+ parts.append(interpolation)
+ BAREWORD = self._scan('BAREWORD')
+ parts.append(unescape(BAREWORD))
+ return parts
+
+ def goal_interpolated_anything(self):
+ INTERP_ANYTHING = self._scan('INTERP_ANYTHING')
+ parts = [INTERP_ANYTHING]
+ while self._peek(self.goal_interpolated_anything_rsts) == 'INTERP_START':
+ interpolation = self.interpolation()
+ parts.append(interpolation)
+ INTERP_ANYTHING = self._scan('INTERP_ANYTHING')
+ parts.append(INTERP_ANYTHING)
+ END = self._scan('END')
+ return Interpolation.maybe(parts)
+
+ u_expr_chks = set(['"url"', 'LPAR', 'DOUBLE_QUOTE', 'COLOR', 'BAREWORD', 'NUM', 'FNCT', 'VAR', 'BANG_IMPORTANT', 'SINGLE_QUOTE'])
+ m_expr_rsts = set(['LPAR', 'DOUBLE_QUOTE', 'SUB', 'RPAR', 'MUL', 'INTERP_END', 'BANG_IMPORTANT', 'DIV', 'LE', 'COLOR', 'NE', 'LT', 'NUM', 'BAREWORD', '"url"', 'GT', 'END', 'SIGN', 'GE', 'FNCT', 'VAR', 'EQ', 'AND', 'ADD', 'SINGLE_QUOTE', 'NOT', 'OR', '","'])
argspec_items_rsts = set(['RPAR', 'END', '","'])
expr_map_rsts = set(['RPAR', '","'])
- argspec_items_rsts__ = set(['KWVAR', 'LPAR', 'QSTR', 'SLURPYVAR', 'COLOR', 'DOTDOTDOT', 'SIGN', 'VAR', 'ADD', 'NUM', '"url"', 'FNCT', 'STR', 'NOT', 'BANG_IMPORTANT', 'ID'])
+ argspec_items_rsts__ = set(['KWVAR', 'LPAR', 'DOUBLE_QUOTE', 'BAREWORD', 'SLURPYVAR', 'COLOR', 'DOTDOTDOT', 'SIGN', 'VAR', 'ADD', 'NUM', '"url"', 'FNCT', 'NOT', 'BANG_IMPORTANT', 'SINGLE_QUOTE'])
kwatom_rsts = set(['KWVAR', 'KWID', 'KWSTR', 'KWQSTR', 'KWCOLOR', '":"', 'KWNUM'])
- argspec_item_chks = set(['"url"', 'LPAR', 'COLOR', 'QSTR', 'SIGN', 'VAR', 'ADD', 'NUM', 'FNCT', 'STR', 'NOT', 'BANG_IMPORTANT', 'ID'])
+ argspec_item_chks = set(['"url"', 'LPAR', 'DOUBLE_QUOTE', 'BAREWORD', 'COLOR', 'SIGN', 'VAR', 'ADD', 'NUM', 'FNCT', 'NOT', 'BANG_IMPORTANT', 'SINGLE_QUOTE'])
a_expr_chks = set(['ADD', 'SUB'])
- expr_slst_rsts = set(['"url"', 'LPAR', 'END', 'COLOR', 'QSTR', 'SIGN', 'VAR', 'ADD', 'NUM', 'RPAR', 'FNCT', 'STR', 'NOT', 'BANG_IMPORTANT', 'ID', '","'])
- atom_rsts__ = set(['LPAR', 'SUB', 'QSTR', 'RPAR', 'VAR', 'MUL', 'DIV', 'BANG_IMPORTANT', 'LE', 'COLOR', 'NE', 'LT', 'NUM', '"url"', 'GT', 'END', 'SIGN', 'GE', 'FNCT', 'STR', 'UNITS', 'EQ', 'ID', 'AND', 'ADD', 'NOT', 'OR', '","'])
- or_expr_rsts = set(['"url"', 'LPAR', 'END', 'COLOR', 'QSTR', 'SIGN', 'VAR', 'ADD', 'NUM', 'RPAR', 'FNCT', 'STR', 'NOT', 'ID', 'BANG_IMPORTANT', 'OR', '","'])
- and_expr_rsts = set(['AND', 'LPAR', 'RPAR', 'END', 'COLOR', 'QSTR', 'SIGN', 'VAR', 'ADD', 'NUM', '"url"', 'FNCT', 'STR', 'NOT', 'ID', 'BANG_IMPORTANT', 'OR', '","'])
- comparison_rsts = set(['LPAR', 'QSTR', 'RPAR', 'BANG_IMPORTANT', 'LE', 'COLOR', 'NE', 'LT', 'NUM', '"url"', 'GT', 'END', 'SIGN', 'ADD', 'FNCT', 'STR', 'VAR', 'EQ', 'ID', 'AND', 'GE', 'NOT', 'OR', '","'])
+ expr_slst_rsts = set(['"url"', 'LPAR', 'DOUBLE_QUOTE', 'BAREWORD', 'END', 'COLOR', 'SIGN', 'VAR', 'ADD', 'NUM', 'RPAR', 'FNCT', 'NOT', 'INTERP_END', 'BANG_IMPORTANT', 'SINGLE_QUOTE', '","'])
+ interpolated_bareword_rsts = set(['LPAR', 'DOUBLE_QUOTE', 'SUB', 'RPAR', 'MUL', 'INTERP_END', 'BANG_IMPORTANT', 'DIV', 'LE', 'INTERP_START', 'COLOR', 'NE', 'LT', 'NUM', 'BAREWORD', '"url"', 'GT', 'END', 'SIGN', 'GE', 'FNCT', 'VAR', 'EQ', 'AND', 'ADD', 'SINGLE_QUOTE', 'NOT', 'OR', '","'])
+ or_expr_rsts = set(['"url"', 'LPAR', 'DOUBLE_QUOTE', 'BAREWORD', 'END', 'SINGLE_QUOTE', 'COLOR', 'SIGN', 'VAR', 'ADD', 'NUM', 'RPAR', 'FNCT', 'NOT', 'INTERP_END', 'BANG_IMPORTANT', 'OR', '","'])
+ interpolated_url_rsts = set(['DOUBLE_QUOTE', 'BAREURL', 'SINGLE_QUOTE'])
+ interpolated_string_single_rsts = set(['SINGLE_QUOTE', 'INTERP_START'])
+ and_expr_rsts = set(['AND', 'LPAR', 'DOUBLE_QUOTE', 'BAREWORD', 'END', 'SINGLE_QUOTE', 'COLOR', 'RPAR', 'SIGN', 'VAR', 'ADD', 'NUM', '"url"', 'FNCT', 'NOT', 'INTERP_END', 'BANG_IMPORTANT', 'OR', '","'])
+ comparison_rsts = set(['LPAR', 'DOUBLE_QUOTE', 'RPAR', 'INTERP_END', 'BANG_IMPORTANT', 'LE', 'COLOR', 'NE', 'LT', 'NUM', 'BAREWORD', '"url"', 'GT', 'END', 'SIGN', 'ADD', 'FNCT', 'VAR', 'EQ', 'AND', 'GE', 'SINGLE_QUOTE', 'NOT', 'OR', '","'])
argspec_chks = set(['DOTDOTDOT', 'SLURPYVAR'])
- atom_rsts_ = set(['URL', '"\\""', '"\'"'])
+ atom_rsts_ = set(['LPAR', 'DOUBLE_QUOTE', 'SUB', 'RPAR', 'VAR', 'MUL', 'INTERP_END', 'BANG_IMPORTANT', 'DIV', 'LE', 'COLOR', 'NE', 'LT', 'NUM', 'BAREWORD', '"url"', 'GT', 'END', 'SIGN', 'GE', 'FNCT', 'UNITS', 'EQ', 'AND', 'ADD', 'SINGLE_QUOTE', 'NOT', 'OR', '","'])
+ interpolated_string_double_rsts = set(['DOUBLE_QUOTE', 'INTERP_START'])
expr_map_rsts_ = set(['KWVAR', 'KWID', 'KWSTR', 'KWQSTR', 'RPAR', 'KWCOLOR', '":"', 'KWNUM', '","'])
- u_expr_rsts = set(['"url"', 'LPAR', 'COLOR', 'QSTR', 'SIGN', 'ADD', 'NUM', 'FNCT', 'STR', 'VAR', 'BANG_IMPORTANT', 'ID'])
+ u_expr_rsts = set(['"url"', 'LPAR', 'DOUBLE_QUOTE', 'COLOR', 'SIGN', 'BAREWORD', 'ADD', 'NUM', 'FNCT', 'VAR', 'BANG_IMPORTANT', 'SINGLE_QUOTE'])
+ atom_chks = set(['COLOR', 'VAR'])
comparison_chks = set(['GT', 'GE', 'NE', 'LT', 'LE', 'EQ'])
- argspec_items_rsts_ = set(['KWVAR', 'LPAR', 'RPAR', 'QSTR', 'END', 'SLURPYVAR', 'COLOR', 'DOTDOTDOT', 'SIGN', 'VAR', 'ADD', 'NUM', '"url"', 'FNCT', 'STR', 'NOT', 'BANG_IMPORTANT', 'ID'])
- a_expr_rsts = set(['LPAR', 'SUB', 'QSTR', 'RPAR', 'BANG_IMPORTANT', 'LE', 'COLOR', 'NE', 'LT', 'NUM', '"url"', 'GT', 'END', 'SIGN', 'GE', 'FNCT', 'STR', 'VAR', 'EQ', 'ID', 'AND', 'ADD', 'NOT', 'OR', '","'])
+ argspec_items_rsts_ = set(['KWVAR', 'LPAR', 'RPAR', 'BAREWORD', 'END', 'SLURPYVAR', 'COLOR', 'DOTDOTDOT', 'DOUBLE_QUOTE', 'SIGN', 'VAR', 'ADD', 'NUM', '"url"', 'FNCT', 'NOT', 'BANG_IMPORTANT', 'SINGLE_QUOTE'])
+ a_expr_rsts = set(['LPAR', 'DOUBLE_QUOTE', 'SUB', 'RPAR', 'INTERP_END', 'BANG_IMPORTANT', 'LE', 'COLOR', 'NE', 'LT', 'NUM', 'BAREWORD', '"url"', 'GT', 'END', 'SIGN', 'GE', 'FNCT', 'VAR', 'EQ', 'AND', 'ADD', 'SINGLE_QUOTE', 'NOT', 'OR', '","'])
+ interpolated_string_rsts = set(['DOUBLE_QUOTE', 'SINGLE_QUOTE'])
m_expr_chks = set(['MUL', 'DIV'])
kwatom_rsts_ = set(['UNITS', '":"'])
- argspec_items_chks = set(['KWVAR', '"url"', 'LPAR', 'COLOR', 'QSTR', 'SIGN', 'VAR', 'ADD', 'NUM', 'FNCT', 'STR', 'NOT', 'BANG_IMPORTANT', 'ID'])
- argspec_rsts = set(['KWVAR', 'LPAR', 'BANG_IMPORTANT', 'END', 'SLURPYVAR', 'COLOR', 'DOTDOTDOT', 'RPAR', 'VAR', 'ADD', 'NUM', '"url"', 'FNCT', 'STR', 'NOT', 'QSTR', 'SIGN', 'ID'])
- atom_rsts = set(['KWVAR', 'KWID', 'KWSTR', 'BANG_IMPORTANT', 'LPAR', 'COLOR', 'KWQSTR', 'SIGN', 'RPAR', 'KWCOLOR', 'VAR', 'ADD', 'NUM', '"url"', '":"', 'STR', 'NOT', 'QSTR', 'KWNUM', 'ID', 'FNCT'])
+ goal_interpolated_anything_rsts = set(['END', 'INTERP_START'])
+ interpolated_bare_url_rsts = set(['RPAR', 'INTERP_START'])
+ expr_lst_rsts = set(['INTERP_END', 'RPAR', 'END', '","'])
+ argspec_items_chks = set(['KWVAR', '"url"', 'DOUBLE_QUOTE', 'BAREWORD', 'LPAR', 'COLOR', 'SIGN', 'VAR', 'ADD', 'NUM', 'FNCT', 'NOT', 'BANG_IMPORTANT', 'SINGLE_QUOTE'])
+ argspec_rsts = set(['KWVAR', 'LPAR', 'DOUBLE_QUOTE', 'BANG_IMPORTANT', 'END', 'SLURPYVAR', 'COLOR', 'BAREWORD', 'DOTDOTDOT', 'RPAR', 'VAR', 'ADD', 'NUM', '"url"', 'FNCT', 'NOT', 'SIGN', 'SINGLE_QUOTE'])
+ atom_rsts = set(['KWVAR', 'KWID', 'KWSTR', 'BANG_IMPORTANT', 'LPAR', 'COLOR', 'BAREWORD', 'KWQSTR', 'SIGN', 'DOUBLE_QUOTE', 'RPAR', 'KWCOLOR', 'VAR', 'ADD', 'NUM', '"url"', '":"', 'NOT', 'KWNUM', 'SINGLE_QUOTE', 'FNCT'])
argspec_chks_ = set(['END', 'RPAR'])
- argspec_rsts_ = set(['KWVAR', 'LPAR', 'BANG_IMPORTANT', 'END', 'COLOR', 'QSTR', 'SIGN', 'VAR', 'ADD', 'NUM', '"url"', 'FNCT', 'STR', 'NOT', 'RPAR', 'ID'])
+ argspec_rsts_ = set(['KWVAR', 'LPAR', 'DOUBLE_QUOTE', 'BANG_IMPORTANT', 'END', 'COLOR', 'BAREWORD', 'SIGN', 'VAR', 'ADD', 'NUM', '"url"', 'FNCT', 'NOT', 'RPAR', 'SINGLE_QUOTE'])