diff options
Diffstat (limited to 'scss/grammar/expression.py')
-rw-r--r-- | scss/grammar/expression.py | 179 |
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']) |