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.py405
1 files changed, 405 insertions, 0 deletions
diff --git a/scss/grammar/expression.py b/scss/grammar/expression.py
new file mode 100644
index 0000000..aed08b9
--- /dev/null
+++ b/scss/grammar/expression.py
@@ -0,0 +1,405 @@
+"""Grammar for parsing Sass expressions."""
+# This is a GENERATED FILE -- DO NOT EDIT DIRECTLY!
+# Edit scss/grammar/expression.g, then run:
+#
+# python2 yapps2.py scss/grammar/expression.g
+
+import operator
+import re
+
+from scss.ast import Parentheses
+from scss.ast import UnaryOp
+from scss.ast import BinaryOp
+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 Literal
+from scss.ast import ListLiteral
+from scss.ast import MapLiteral
+from scss.ast import ArgspecLiteral
+from scss.types import Color
+from scss.types import Number
+from scss.types import String
+from scss.types import Url
+from scss.util import dequote
+
+from scss.grammar import Parser
+from scss.grammar import Scanner
+
+
+
+class SassExpressionScanner(Scanner):
+ patterns = None
+ _patterns = [
+ ('"\'"', "'"),
+ ('"\\""', '"'),
+ ('"url"', 'url'),
+ ('":"', ':'),
+ ('","', ','),
+ ('[ \r\t\n]+', '[ \r\t\n]+'),
+ ('LPAR', '\\(|\\['),
+ ('RPAR', '\\)|\\]'),
+ ('END', '$'),
+ ('MUL', '[*]'),
+ ('DIV', '/'),
+ ('ADD', '[+]'),
+ ('SUB', '-\\s'),
+ ('SIGN', '-(?![a-zA-Z_])'),
+ ('AND', '(?<![-\\w])and(?![-\\w])'),
+ ('OR', '(?<![-\\w])or(?![-\\w])'),
+ ('NOT', '(?<![-\\w])not(?![-\\w])'),
+ ('NE', '!='),
+ ('INV', '!'),
+ ('EQ', '=='),
+ ('LE', '<='),
+ ('GE', '>='),
+ ('LT', '<'),
+ ('GT', '>'),
+ ('DOTDOTDOT', '[.]{3}'),
+ ('KWSTR', "'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'(?=\\s*:)"),
+ ('STR', "'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'"),
+ ('KWQSTR', '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"(?=\\s*:)'),
+ ('QSTR', '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'),
+ ('UNITS', '(?<!\\s)(?:[a-zA-Z]+|%)(?![-\\w])'),
+ ('KWNUM', '(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?=\\s*:)'),
+ ('NUM', '(?:\\d+(?:\\.\\d*)?|\\.\\d+)'),
+ ('KWCOLOR', '#(?:[a-fA-F0-9]{6}|[a-fA-F0-9]{3})(?![a-fA-F0-9])(?=\\s*:)'),
+ ('COLOR', '#(?:[a-fA-F0-9]{6}|[a-fA-F0-9]{3})(?![a-fA-F0-9])'),
+ ('KWVAR', '\\$[-a-zA-Z0-9_]+(?=\\s*:)'),
+ ('SLURPYVAR', '\\$[-a-zA-Z0-9_]+(?=[.][.][.])'),
+ ('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_]*'),
+ ('BANG_IMPORTANT', '!important'),
+ ('URL', '(?:[\\\\].|[^$\'"()\\x00-\\x08\\x0b\\x0e-\\x1f\\x7f])*'),
+ ]
+
+ def __init__(self, input=None):
+ if hasattr(self, 'setup_patterns'):
+ self.setup_patterns(self._patterns)
+ elif self.patterns is None:
+ self.__class__.patterns = []
+ for t, p in self._patterns:
+ self.patterns.append((t, re.compile(p)))
+ super(SassExpressionScanner, self).__init__(None, ['[ \r\t\n]+'], input)
+
+
+class SassExpression(Parser):
+ def goal(self):
+ expr_lst = self.expr_lst()
+ END = self._scan('END')
+ return expr_lst
+
+ def goal_argspec(self):
+ argspec = self.argspec()
+ END = self._scan('END')
+ return argspec
+
+ def argspec(self):
+ _token_ = self._peek(self.argspec_rsts)
+ if _token_ not in self.argspec_chks:
+ if self._peek(self.argspec_rsts_) not in self.argspec_chks_:
+ argspec_items = self.argspec_items()
+ args, slurpy = argspec_items
+ return ArgspecLiteral(args, slurp=slurpy)
+ return ArgspecLiteral([])
+ elif _token_ == 'SLURPYVAR':
+ SLURPYVAR = self._scan('SLURPYVAR')
+ DOTDOTDOT = self._scan('DOTDOTDOT')
+ return ArgspecLiteral([], slurp=SLURPYVAR)
+ else: # == 'DOTDOTDOT'
+ DOTDOTDOT = self._scan('DOTDOTDOT')
+ return ArgspecLiteral([], slurp=all)
+
+ def argspec_items(self):
+ slurpy = None
+ argspec_item = self.argspec_item()
+ args = [argspec_item]
+ if self._peek(self.argspec_items_rsts) == '","':
+ self._scan('","')
+ if self._peek(self.argspec_items_rsts_) not in self.argspec_chks_:
+ _token_ = self._peek(self.argspec_items_rsts__)
+ if _token_ == 'SLURPYVAR':
+ SLURPYVAR = self._scan('SLURPYVAR')
+ DOTDOTDOT = self._scan('DOTDOTDOT')
+ slurpy = SLURPYVAR
+ elif _token_ == 'DOTDOTDOT':
+ DOTDOTDOT = self._scan('DOTDOTDOT')
+ slurpy = all
+ else: # in self.argspec_items_chks
+ argspec_items = self.argspec_items()
+ more_args, slurpy = argspec_items
+ args.extend(more_args)
+ return args, slurpy
+
+ def argspec_item(self):
+ _token_ = self._peek(self.argspec_items_chks)
+ if _token_ == 'KWVAR':
+ KWVAR = self._scan('KWVAR')
+ self._scan('":"')
+ expr_slst = self.expr_slst()
+ return (Variable(KWVAR), expr_slst)
+ else: # in self.argspec_item_chks
+ expr_slst = self.expr_slst()
+ return (None, expr_slst)
+
+ def expr_map(self):
+ map_item = self.map_item()
+ pairs = [map_item]
+ while self._peek(self.expr_map_rsts) == '","':
+ self._scan('","')
+ map_item = (None, None)
+ if self._peek(self.expr_map_rsts_) not in self.expr_map_rsts:
+ map_item = self.map_item()
+ pairs.append(map_item)
+ return MapLiteral(pairs)
+
+ def map_item(self):
+ kwatom = self.kwatom()
+ self._scan('":"')
+ expr_slst = self.expr_slst()
+ return (kwatom, expr_slst)
+
+ def expr_lst(self):
+ expr_slst = self.expr_slst()
+ v = [expr_slst]
+ while self._peek(self.argspec_items_rsts) == '","':
+ self._scan('","')
+ expr_slst = self.expr_slst()
+ v.append(expr_slst)
+ return ListLiteral(v) if len(v) > 1 else v[0]
+
+ 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:
+ or_expr = self.or_expr()
+ v.append(or_expr)
+ return ListLiteral(v, comma=False) if len(v) > 1 else v[0]
+
+ def or_expr(self):
+ and_expr = self.and_expr()
+ v = and_expr
+ while self._peek(self.or_expr_rsts) == 'OR':
+ OR = self._scan('OR')
+ and_expr = self.and_expr()
+ v = AnyOp(v, and_expr)
+ return v
+
+ def and_expr(self):
+ not_expr = self.not_expr()
+ v = not_expr
+ while self._peek(self.and_expr_rsts) == 'AND':
+ AND = self._scan('AND')
+ not_expr = self.not_expr()
+ v = AllOp(v, not_expr)
+ return v
+
+ def not_expr(self):
+ _token_ = self._peek(self.argspec_item_chks)
+ if _token_ != 'NOT':
+ comparison = self.comparison()
+ return comparison
+ else: # == 'NOT'
+ NOT = self._scan('NOT')
+ not_expr = self.not_expr()
+ return NotOp(not_expr)
+
+ def comparison(self):
+ a_expr = self.a_expr()
+ v = a_expr
+ while self._peek(self.comparison_rsts) in self.comparison_chks:
+ _token_ = self._peek(self.comparison_chks)
+ if _token_ == 'LT':
+ LT = self._scan('LT')
+ a_expr = self.a_expr()
+ v = BinaryOp(operator.lt, v, a_expr)
+ elif _token_ == 'GT':
+ GT = self._scan('GT')
+ a_expr = self.a_expr()
+ v = BinaryOp(operator.gt, v, a_expr)
+ elif _token_ == 'LE':
+ LE = self._scan('LE')
+ a_expr = self.a_expr()
+ v = BinaryOp(operator.le, v, a_expr)
+ elif _token_ == 'GE':
+ GE = self._scan('GE')
+ a_expr = self.a_expr()
+ v = BinaryOp(operator.ge, v, a_expr)
+ elif _token_ == 'EQ':
+ EQ = self._scan('EQ')
+ a_expr = self.a_expr()
+ v = BinaryOp(operator.eq, v, a_expr)
+ else: # == 'NE'
+ NE = self._scan('NE')
+ a_expr = self.a_expr()
+ v = BinaryOp(operator.ne, v, a_expr)
+ return v
+
+ def a_expr(self):
+ m_expr = self.m_expr()
+ v = m_expr
+ while self._peek(self.a_expr_rsts) in self.a_expr_chks:
+ _token_ = self._peek(self.a_expr_chks)
+ if _token_ == 'ADD':
+ ADD = self._scan('ADD')
+ m_expr = self.m_expr()
+ v = BinaryOp(operator.add, v, m_expr)
+ else: # == 'SUB'
+ SUB = self._scan('SUB')
+ m_expr = self.m_expr()
+ v = BinaryOp(operator.sub, v, m_expr)
+ return v
+
+ def m_expr(self):
+ u_expr = self.u_expr()
+ v = u_expr
+ while self._peek(self.m_expr_rsts) in self.m_expr_chks:
+ _token_ = self._peek(self.m_expr_chks)
+ if _token_ == 'MUL':
+ MUL = self._scan('MUL')
+ u_expr = self.u_expr()
+ v = BinaryOp(operator.mul, v, u_expr)
+ else: # == 'DIV'
+ DIV = self._scan('DIV')
+ u_expr = self.u_expr()
+ v = BinaryOp(operator.truediv, v, u_expr)
+ return v
+
+ def u_expr(self):
+ _token_ = self._peek(self.u_expr_rsts)
+ if _token_ == 'SIGN':
+ SIGN = self._scan('SIGN')
+ u_expr = self.u_expr()
+ return UnaryOp(operator.neg, u_expr)
+ elif _token_ == 'ADD':
+ ADD = self._scan('ADD')
+ u_expr = self.u_expr()
+ return UnaryOp(operator.pos, u_expr)
+ else: # in self.u_expr_chks
+ atom = self.atom()
+ return atom
+
+ def atom(self):
+ _token_ = self._peek(self.u_expr_chks)
+ if _token_ == 'LPAR':
+ LPAR = self._scan('LPAR')
+ _token_ = self._peek(self.atom_rsts)
+ if _token_ == 'RPAR':
+ v = ListLiteral([], comma=False)
+ elif _token_ not in self.argspec_item_chks:
+ expr_map = self.expr_map()
+ v = expr_map
+ else: # in self.argspec_item_chks
+ expr_lst = self.expr_lst()
+ v = expr_lst
+ RPAR = self._scan('RPAR')
+ return Parentheses(v)
+ 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 = "'"
+ RPAR = self._scan('RPAR')
+ return Literal(Url(URL, quotes=quotes))
+ elif _token_ == 'FNCT':
+ FNCT = self._scan('FNCT')
+ LPAR = self._scan('LPAR')
+ argspec = self.argspec()
+ RPAR = self._scan('RPAR')
+ return CallOp(FNCT, argspec)
+ 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_ == 'NUM':
+ NUM = self._scan('NUM')
+ UNITS = None
+ 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_ == 'COLOR':
+ COLOR = self._scan('COLOR')
+ return Literal(Color.from_hex(COLOR, literal=True))
+ else: # == 'VAR'
+ VAR = self._scan('VAR')
+ return Variable(VAR)
+
+ def kwatom(self):
+ _token_ = self._peek(self.kwatom_rsts)
+ if _token_ == '":"':
+ pass
+ elif _token_ == 'KWID':
+ KWID = self._scan('KWID')
+ return Literal.from_bareword(KWID)
+ elif _token_ == 'KWNUM':
+ KWNUM = self._scan('KWNUM')
+ UNITS = None
+ if self._peek(self.kwatom_rsts_) == 'UNITS':
+ UNITS = self._scan('UNITS')
+ return Literal(Number(float(KWNUM), unit=UNITS))
+ elif _token_ == 'KWSTR':
+ KWSTR = self._scan('KWSTR')
+ return Literal(String(dequote(KWSTR), quotes="'"))
+ elif _token_ == 'KWQSTR':
+ KWQSTR = self._scan('KWQSTR')
+ return Literal(String(dequote(KWQSTR), quotes='"'))
+ elif _token_ == 'KWCOLOR':
+ KWCOLOR = self._scan('KWCOLOR')
+ return Literal(Color.from_hex(KWCOLOR, literal=True))
+ else: # == 'KWVAR'
+ 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', '","'])
+ 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'])
+ 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'])
+ 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', '","'])
+ argspec_chks = set(['DOTDOTDOT', 'SLURPYVAR'])
+ atom_rsts_ = set(['URL', '"\\""', '"\'"'])
+ 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'])
+ 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', '","'])
+ 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'])
+ 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'])
+
+