diff options
author | Eevee (Alex Munroe) <eevee.git@veekun.com> | 2013-07-26 12:49:23 -0700 |
---|---|---|
committer | Eevee (Alex Munroe) <eevee.git@veekun.com> | 2013-08-23 15:54:02 -0700 |
commit | 28762f9ee008a276c4ae78096e3d9d358dd6b316 (patch) | |
tree | 95411be74b627956537ac963ab88b92a729f0fe3 | |
parent | 8b163b84c3d3c7aaee881d63005c85f23a96f205 (diff) | |
download | pyscss-28762f9ee008a276c4ae78096e3d9d358dd6b316.tar.gz |
Port the grammar to Parsley. Working, but unfinished.
This is on a separate branch because it slows the test suite down
significantly. I have pull requests open against parsley to make it
faster, but in the meantime this code is built against a combination of
parsley master and my own branches.
Other grammar improvements:
- Moves #-interpolation into the grammar.
- Vainly attempts to make the set of acceptable string characters more
correct.
- First-class support for url(); I believe before it would cause the
entire property to be treated as unparseable.
-rw-r--r-- | compile-grammar.py | 13 | ||||
-rw-r--r-- | scss/_generated/__init__.py | 0 | ||||
-rw-r--r-- | scss/_generated/expression.py | 1156 | ||||
-rw-r--r-- | scss/expression.parsley | 166 | ||||
-rw-r--r-- | scss/expression.py | 191 | ||||
-rw-r--r-- | scss/src/grammar/grammar.g | 26 | ||||
-rw-r--r-- | scss/tests/files/bugs/003-single-quoted-values.css | 6 |
7 files changed, 1532 insertions, 26 deletions
diff --git a/compile-grammar.py b/compile-grammar.py new file mode 100644 index 0000000..e6ce605 --- /dev/null +++ b/compile-grammar.py @@ -0,0 +1,13 @@ +from ometa.builder import writePython +from ometa.grammar import OMeta +import parsley + +with open('scss/expression.parsley') as f: + grammar_source = f.read() + +parser = OMeta(grammar_source) +tree = parser.parseGrammar('Grammar') +generated = writePython(tree, grammar_source) + +with open('scss/_generated/expression.py', 'w') as f: + f.write(generated) diff --git a/scss/_generated/__init__.py b/scss/_generated/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/scss/_generated/__init__.py diff --git a/scss/_generated/expression.py b/scss/_generated/expression.py new file mode 100644 index 0000000..2feb18e --- /dev/null +++ b/scss/_generated/expression.py @@ -0,0 +1,1156 @@ +def createParserClass(GrammarBase, ruleGlobals): + if ruleGlobals is None: + ruleGlobals = {} + class Grammar(GrammarBase): + def rule_UNITS(self): + _locals = {'self': self} + self.locals['UNITS'] = _locals + def _G_consumedby_1(): + def _G_or_2(): + self._trace(" 'p'", (29, 33), self.input.position) + _G_exactly_3, lastError = self.exactly('p') + self.considerError(lastError, None) + self._trace(" 'x'", (33, 37), self.input.position) + _G_exactly_4, lastError = self.exactly('x') + self.considerError(lastError, None) + return (_G_exactly_4, self.currentError) + def _G_or_5(): + self._trace(" 'c'", (39, 43), self.input.position) + _G_exactly_6, lastError = self.exactly('c') + self.considerError(lastError, None) + self._trace(" 'm'", (43, 47), self.input.position) + _G_exactly_7, lastError = self.exactly('m') + self.considerError(lastError, None) + return (_G_exactly_7, self.currentError) + def _G_or_8(): + self._trace(" 'm'", (49, 53), self.input.position) + _G_exactly_9, lastError = self.exactly('m') + self.considerError(lastError, None) + self._trace(" 'm'", (53, 57), self.input.position) + _G_exactly_10, lastError = self.exactly('m') + self.considerError(lastError, None) + return (_G_exactly_10, self.currentError) + def _G_or_11(): + self._trace(" 'h'", (59, 63), self.input.position) + _G_exactly_12, lastError = self.exactly('h') + self.considerError(lastError, None) + self._trace(" 'z'", (63, 67), self.input.position) + _G_exactly_13, lastError = self.exactly('z') + self.considerError(lastError, None) + return (_G_exactly_13, self.currentError) + def _G_or_14(): + self._trace(" 'i'", (69, 73), self.input.position) + _G_exactly_15, lastError = self.exactly('i') + self.considerError(lastError, None) + self._trace(" 'n'", (73, 77), self.input.position) + _G_exactly_16, lastError = self.exactly('n') + self.considerError(lastError, None) + return (_G_exactly_16, self.currentError) + def _G_or_17(): + self._trace(" '%'", (79, 83), self.input.position) + _G_exactly_18, lastError = self.exactly('%') + self.considerError(lastError, None) + return (_G_exactly_18, self.currentError) + _G_or_19, lastError = self._or([_G_or_2, _G_or_5, _G_or_8, _G_or_11, _G_or_14, _G_or_17]) + self.considerError(lastError, None) + return (_G_or_19, self.currentError) + _G_consumedby_20, lastError = self.consumedby(_G_consumedby_1) + self.considerError(lastError, 'UNITS') + return (_G_consumedby_20, self.currentError) + + + def rule_escape(self): + _locals = {'self': self} + self.locals['escape'] = _locals + self._trace(" '\\\\'", (506, 511), self.input.position) + _G_exactly_21, lastError = self.exactly('\\') + self.considerError(lastError, 'escape') + def _G_or_22(): + self._trace("\n '\\n'", (513, 526), self.input.position) + _G_exactly_23, lastError = self.exactly('\n') + self.considerError(lastError, None) + _G_python_24, lastError = (''), None + self.considerError(lastError, None) + return (_G_python_24, self.currentError) + def _G_or_25(): + def _G_consumedby_26(): + def _G_repeat_27(): + self._trace('hex', (602, 605), self.input.position) + _G_apply_28, lastError = self._apply(self.rule_hex, "hex", []) + self.considerError(lastError, None) + return (_G_apply_28, self.currentError) + _G_repeat_29, lastError = self.repeat(1, 6, _G_repeat_27) + self.considerError(lastError, None) + return (_G_repeat_29, self.currentError) + _G_consumedby_30, lastError = self.consumedby(_G_consumedby_26) + self.considerError(lastError, None) + _locals['cp'] = _G_consumedby_30 + def _G_optional_31(): + self._trace(' ws', (614, 617), self.input.position) + _G_apply_32, lastError = self._apply(self.rule_ws, "ws", []) + self.considerError(lastError, None) + return (_G_apply_32, self.currentError) + def _G_optional_33(): + return (None, self.input.nullError()) + _G_or_34, lastError = self._or([_G_optional_31, _G_optional_33]) + self.considerError(lastError, None) + _G_python_36, lastError = eval(self._G_expr_35, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_36, self.currentError) + def _G_or_37(): + self._trace(' anything', (758, 767), self.input.position) + _G_apply_38, lastError = self._apply(self.rule_anything, "anything", []) + self.considerError(lastError, None) + return (_G_apply_38, self.currentError) + _G_or_39, lastError = self._or([_G_or_22, _G_or_25, _G_or_37]) + self.considerError(lastError, 'escape') + return (_G_or_39, self.currentError) + + + def rule_identifier(self): + _locals = {'self': self} + self.locals['identifier'] = _locals + def _G_consumedby_40(): + self._trace(' letterish', (800, 810), self.input.position) + _G_apply_41, lastError = self._apply(self.rule_letterish, "letterish", []) + self.considerError(lastError, None) + def _G_many_42(): + def _G_or_43(): + self._trace('letterish', (812, 821), self.input.position) + _G_apply_44, lastError = self._apply(self.rule_letterish, "letterish", []) + self.considerError(lastError, None) + return (_G_apply_44, self.currentError) + def _G_or_45(): + self._trace(' digit', (823, 829), self.input.position) + _G_apply_46, lastError = self._apply(self.rule_digit, "digit", []) + self.considerError(lastError, None) + return (_G_apply_46, self.currentError) + _G_or_47, lastError = self._or([_G_or_43, _G_or_45]) + self.considerError(lastError, None) + return (_G_or_47, self.currentError) + _G_many_48, lastError = self.many(_G_many_42) + self.considerError(lastError, None) + return (_G_many_48, self.currentError) + _G_consumedby_49, lastError = self.consumedby(_G_consumedby_40) + self.considerError(lastError, 'identifier') + return (_G_consumedby_49, self.currentError) + + + def rule_number(self): + _locals = {'self': self} + self.locals['number'] = _locals + def _G_consumedby_50(): + def _G_or_51(): + def _G_many1_52(): + self._trace(' digit', (844, 850), self.input.position) + _G_apply_53, lastError = self._apply(self.rule_digit, "digit", []) + self.considerError(lastError, None) + return (_G_apply_53, self.currentError) + _G_many1_54, lastError = self.many(_G_many1_52, _G_many1_52()) + self.considerError(lastError, None) + def _G_optional_55(): + self._trace("'.'", (853, 856), self.input.position) + _G_exactly_56, lastError = self.exactly('.') + self.considerError(lastError, None) + def _G_many_57(): + self._trace(' digit', (856, 862), self.input.position) + _G_apply_58, lastError = self._apply(self.rule_digit, "digit", []) + self.considerError(lastError, None) + return (_G_apply_58, self.currentError) + _G_many_59, lastError = self.many(_G_many_57) + self.considerError(lastError, None) + return (_G_many_59, self.currentError) + def _G_optional_60(): + return (None, self.input.nullError()) + _G_or_61, lastError = self._or([_G_optional_55, _G_optional_60]) + self.considerError(lastError, None) + return (_G_or_61, self.currentError) + def _G_or_62(): + self._trace(" '.'", (867, 871), self.input.position) + _G_exactly_63, lastError = self.exactly('.') + self.considerError(lastError, None) + def _G_many1_64(): + self._trace(' digit', (871, 877), self.input.position) + _G_apply_65, lastError = self._apply(self.rule_digit, "digit", []) + self.considerError(lastError, None) + return (_G_apply_65, self.currentError) + _G_many1_66, lastError = self.many(_G_many1_64, _G_many1_64()) + self.considerError(lastError, None) + return (_G_many1_66, self.currentError) + _G_or_67, lastError = self._or([_G_or_51, _G_or_62]) + self.considerError(lastError, None) + return (_G_or_67, self.currentError) + _G_consumedby_68, lastError = self.consumedby(_G_consumedby_50) + self.considerError(lastError, 'number') + return (_G_consumedby_68, self.currentError) + + + def rule_variable(self): + _locals = {'self': self} + self.locals['variable'] = _locals + def _G_consumedby_69(): + self._trace(" '$'", (893, 897), self.input.position) + _G_exactly_70, lastError = self.exactly('$') + self.considerError(lastError, None) + self._trace(' identifier', (897, 908), self.input.position) + _G_apply_71, lastError = self._apply(self.rule_identifier, "identifier", []) + self.considerError(lastError, None) + return (_G_apply_71, self.currentError) + _G_consumedby_72, lastError = self.consumedby(_G_consumedby_69) + self.considerError(lastError, 'variable') + return (_G_consumedby_72, self.currentError) + + + def rule_expression(self): + _locals = {'self': self} + self.locals['expression'] = _locals + self._trace(' comma_list', (938, 949), self.input.position) + _G_apply_73, lastError = self._apply(self.rule_comma_list, "comma_list", []) + self.considerError(lastError, 'expression') + return (_G_apply_73, self.currentError) + + + def rule_comma_list(self): + _locals = {'self': self} + self.locals['comma_list'] = _locals + self._trace(' spaced_list', (963, 975), self.input.position) + _G_apply_74, lastError = self._apply(self.rule_spaced_list, "spaced_list", []) + self.considerError(lastError, 'comma_list') + _locals['head'] = _G_apply_74 + def _G_many_75(): + self._trace('\n ows', (982, 994), self.input.position) + _G_apply_76, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(" ','", (994, 998), self.input.position) + _G_exactly_77, lastError = self.exactly(',') + self.considerError(lastError, None) + self._trace(' ows', (998, 1002), self.input.position) + _G_apply_78, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace('\n spaced_list', (1002, 1022), self.input.position) + _G_apply_79, lastError = self._apply(self.rule_spaced_list, "spaced_list", []) + self.considerError(lastError, None) + _locals['tail'] = _G_apply_79 + _G_python_81, lastError = eval(self._G_expr_80, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_81, self.currentError) + _G_many_82, lastError = self.many(_G_many_75) + self.considerError(lastError, 'comma_list') + _locals['tails'] = _G_many_82 + _G_python_84, lastError = eval(self._G_expr_83, self.globals, _locals), None + self.considerError(lastError, 'comma_list') + return (_G_python_84, self.currentError) + + + def rule_spaced_list(self): + _locals = {'self': self} + self.locals['spaced_list'] = _locals + self._trace(' single_expression', (1113, 1131), self.input.position) + _G_apply_85, lastError = self._apply(self.rule_single_expression, "single_expression", []) + self.considerError(lastError, 'spaced_list') + _locals['head'] = _G_apply_85 + def _G_many_86(): + self._trace('\n ws', (1138, 1149), self.input.position) + _G_apply_87, lastError = self._apply(self.rule_ws, "ws", []) + self.considerError(lastError, None) + self._trace('\n single_expression', (1149, 1175), self.input.position) + _G_apply_88, lastError = self._apply(self.rule_single_expression, "single_expression", []) + self.considerError(lastError, None) + _locals['tail'] = _G_apply_88 + _G_python_89, lastError = eval(self._G_expr_80, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_89, self.currentError) + _G_many_90, lastError = self.many(_G_many_86) + self.considerError(lastError, 'spaced_list') + _locals['tails'] = _G_many_90 + _G_python_92, lastError = eval(self._G_expr_91, self.globals, _locals), None + self.considerError(lastError, 'spaced_list') + return (_G_python_92, self.currentError) + + + def rule_single_expression(self): + _locals = {'self': self} + self.locals['single_expression'] = _locals + self._trace(' or_test', (1286, 1294), self.input.position) + _G_apply_93, lastError = self._apply(self.rule_or_test, "or_test", []) + self.considerError(lastError, 'single_expression') + return (_G_apply_93, self.currentError) + + + def rule_or_test(self): + _locals = {'self': self} + self.locals['or_test'] = _locals + self._trace(' and_test', (1305, 1314), self.input.position) + _G_apply_94, lastError = self._apply(self.rule_and_test, "and_test", []) + self.considerError(lastError, 'or_test') + _locals['head'] = _G_apply_94 + def _G_many_95(): + self._trace("\n 'o'", (1321, 1333), self.input.position) + _G_exactly_96, lastError = self.exactly('o') + self.considerError(lastError, None) + self._trace(" 'r'", (1333, 1337), self.input.position) + _G_exactly_97, lastError = self.exactly('r') + self.considerError(lastError, None) + self._trace('\n and_test', (1337, 1354), self.input.position) + _G_apply_98, lastError = self._apply(self.rule_and_test, "and_test", []) + self.considerError(lastError, None) + _locals['tail'] = _G_apply_98 + _G_python_99, lastError = eval(self._G_expr_80, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_99, self.currentError) + _G_many_100, lastError = self.many(_G_many_95) + self.considerError(lastError, 'or_test') + _locals['tails'] = _G_many_100 + _G_python_102, lastError = eval(self._G_expr_101, self.globals, _locals), None + self.considerError(lastError, 'or_test') + return (_G_python_102, self.currentError) + + + def rule_and_test(self): + _locals = {'self': self} + self.locals['and_test'] = _locals + self._trace(' not_test', (1437, 1446), self.input.position) + _G_apply_103, lastError = self._apply(self.rule_not_test, "not_test", []) + self.considerError(lastError, 'and_test') + _locals['head'] = _G_apply_103 + def _G_many_104(): + self._trace("\n 'a'", (1453, 1465), self.input.position) + _G_exactly_105, lastError = self.exactly('a') + self.considerError(lastError, None) + self._trace(" 'n'", (1465, 1469), self.input.position) + _G_exactly_106, lastError = self.exactly('n') + self.considerError(lastError, None) + self._trace(" 'd'", (1469, 1473), self.input.position) + _G_exactly_107, lastError = self.exactly('d') + self.considerError(lastError, None) + self._trace('\n not_test', (1473, 1490), self.input.position) + _G_apply_108, lastError = self._apply(self.rule_not_test, "not_test", []) + self.considerError(lastError, None) + _locals['tail'] = _G_apply_108 + _G_python_109, lastError = eval(self._G_expr_80, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_109, self.currentError) + _G_many_110, lastError = self.many(_G_many_104) + self.considerError(lastError, 'and_test') + _locals['tails'] = _G_many_110 + _G_python_112, lastError = eval(self._G_expr_111, self.globals, _locals), None + self.considerError(lastError, 'and_test') + return (_G_python_112, self.currentError) + + + def rule_not_test(self): + _locals = {'self': self} + self.locals['not_test'] = _locals + def _G_or_113(): + self._trace(' comparison', (1573, 1584), self.input.position) + _G_apply_114, lastError = self._apply(self.rule_comparison, "comparison", []) + self.considerError(lastError, None) + return (_G_apply_114, self.currentError) + def _G_or_115(): + self._trace(" 'n'", (1588, 1592), self.input.position) + _G_exactly_116, lastError = self.exactly('n') + self.considerError(lastError, None) + self._trace(" 'o'", (1592, 1596), self.input.position) + _G_exactly_117, lastError = self.exactly('o') + self.considerError(lastError, None) + self._trace(" 't'", (1596, 1600), self.input.position) + _G_exactly_118, lastError = self.exactly('t') + self.considerError(lastError, None) + self._trace(' not_test', (1600, 1609), self.input.position) + _G_apply_119, lastError = self._apply(self.rule_not_test, "not_test", []) + self.considerError(lastError, None) + _locals['node'] = _G_apply_119 + _G_python_121, lastError = eval(self._G_expr_120, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_121, self.currentError) + _G_or_122, lastError = self._or([_G_or_113, _G_or_115]) + self.considerError(lastError, 'not_test') + return (_G_or_122, self.currentError) + + + def rule_comparison(self): + _locals = {'self': self} + self.locals['comparison'] = _locals + self._trace(' add_expr', (1645, 1654), self.input.position) + _G_apply_123, lastError = self._apply(self.rule_add_expr, "add_expr", []) + self.considerError(lastError, 'comparison') + _locals['node'] = _G_apply_123 + def _G_many_124(): + def _G_or_125(): + self._trace('\n ows', (1661, 1673), self.input.position) + _G_apply_126, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(" '<'", (1673, 1677), self.input.position) + _G_exactly_127, lastError = self.exactly('<') + self.considerError(lastError, None) + self._trace(' ows', (1677, 1681), self.input.position) + _G_apply_128, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(' add_expr', (1681, 1690), self.input.position) + _G_apply_129, lastError = self._apply(self.rule_add_expr, "add_expr", []) + self.considerError(lastError, None) + _locals['operand'] = _G_apply_129 + _G_python_131, lastError = eval(self._G_expr_130, self.globals, _locals), None + self.considerError(lastError, None) + _locals['node'] = _G_python_131 + return (_G_python_131, self.currentError) + def _G_or_132(): + self._trace(' ows', (1755, 1759), self.input.position) + _G_apply_133, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(" '>'", (1759, 1763), self.input.position) + _G_exactly_134, lastError = self.exactly('>') + self.considerError(lastError, None) + self._trace(' ows', (1763, 1767), self.input.position) + _G_apply_135, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(' add_expr', (1767, 1776), self.input.position) + _G_apply_136, lastError = self._apply(self.rule_add_expr, "add_expr", []) + self.considerError(lastError, None) + _locals['operand'] = _G_apply_136 + _G_python_138, lastError = eval(self._G_expr_137, self.globals, _locals), None + self.considerError(lastError, None) + _locals['node'] = _G_python_138 + return (_G_python_138, self.currentError) + def _G_or_139(): + self._trace(' ows', (1841, 1845), self.input.position) + _G_apply_140, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(" '<'", (1845, 1849), self.input.position) + _G_exactly_141, lastError = self.exactly('<') + self.considerError(lastError, None) + self._trace(" '='", (1849, 1853), self.input.position) + _G_exactly_142, lastError = self.exactly('=') + self.considerError(lastError, None) + self._trace(' ows', (1853, 1857), self.input.position) + _G_apply_143, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(' add_expr', (1857, 1866), self.input.position) + _G_apply_144, lastError = self._apply(self.rule_add_expr, "add_expr", []) + self.considerError(lastError, None) + _locals['operand'] = _G_apply_144 + _G_python_146, lastError = eval(self._G_expr_145, self.globals, _locals), None + self.considerError(lastError, None) + _locals['node'] = _G_python_146 + return (_G_python_146, self.currentError) + def _G_or_147(): + self._trace(' ows', (1931, 1935), self.input.position) + _G_apply_148, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(" '>'", (1935, 1939), self.input.position) + _G_exactly_149, lastError = self.exactly('>') + self.considerError(lastError, None) + self._trace(" '='", (1939, 1943), self.input.position) + _G_exactly_150, lastError = self.exactly('=') + self.considerError(lastError, None) + self._trace(' ows', (1943, 1947), self.input.position) + _G_apply_151, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(' add_expr', (1947, 1956), self.input.position) + _G_apply_152, lastError = self._apply(self.rule_add_expr, "add_expr", []) + self.considerError(lastError, None) + _locals['operand'] = _G_apply_152 + _G_python_154, lastError = eval(self._G_expr_153, self.globals, _locals), None + self.considerError(lastError, None) + _locals['node'] = _G_python_154 + return (_G_python_154, self.currentError) + def _G_or_155(): + self._trace(' ows', (2021, 2025), self.input.position) + _G_apply_156, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(" '='", (2025, 2029), self.input.position) + _G_exactly_157, lastError = self.exactly('=') + self.considerError(lastError, None) + self._trace(" '='", (2029, 2033), self.input.position) + _G_exactly_158, lastError = self.exactly('=') + self.considerError(lastError, None) + self._trace(' ows', (2033, 2037), self.input.position) + _G_apply_159, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(' add_expr', (2037, 2046), self.input.position) + _G_apply_160, lastError = self._apply(self.rule_add_expr, "add_expr", []) + self.considerError(lastError, None) + _locals['operand'] = _G_apply_160 + _G_python_162, lastError = eval(self._G_expr_161, self.globals, _locals), None + self.considerError(lastError, None) + _locals['node'] = _G_python_162 + return (_G_python_162, self.currentError) + def _G_or_163(): + self._trace(' ows', (2111, 2115), self.input.position) + _G_apply_164, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(" '!'", (2115, 2119), self.input.position) + _G_exactly_165, lastError = self.exactly('!') + self.considerError(lastError, None) + self._trace(" '='", (2119, 2123), self.input.position) + _G_exactly_166, lastError = self.exactly('=') + self.considerError(lastError, None) + self._trace(' ows', (2123, 2127), self.input.position) + _G_apply_167, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(' add_expr', (2127, 2136), self.input.position) + _G_apply_168, lastError = self._apply(self.rule_add_expr, "add_expr", []) + self.considerError(lastError, None) + _locals['operand'] = _G_apply_168 + _G_python_170, lastError = eval(self._G_expr_169, self.globals, _locals), None + self.considerError(lastError, None) + _locals['node'] = _G_python_170 + return (_G_python_170, self.currentError) + _G_or_171, lastError = self._or([_G_or_125, _G_or_132, _G_or_139, _G_or_147, _G_or_155, _G_or_163]) + self.considerError(lastError, None) + return (_G_or_171, self.currentError) + _G_many_172, lastError = self.many(_G_many_124) + self.considerError(lastError, 'comparison') + _G_python_174, lastError = eval(self._G_expr_173, self.globals, _locals), None + self.considerError(lastError, 'comparison') + return (_G_python_174, self.currentError) + + + def rule_add_expr(self): + _locals = {'self': self} + self.locals['add_expr'] = _locals + self._trace(' mult_expr', (2218, 2228), self.input.position) + _G_apply_175, lastError = self._apply(self.rule_mult_expr, "mult_expr", []) + self.considerError(lastError, 'add_expr') + _locals['node'] = _G_apply_175 + def _G_many_176(): + def _G_or_177(): + self._trace('\n ows', (2235, 2247), self.input.position) + _G_apply_178, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(" '+'", (2247, 2251), self.input.position) + _G_exactly_179, lastError = self.exactly('+') + self.considerError(lastError, None) + self._trace(' ows', (2251, 2255), self.input.position) + _G_apply_180, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(' mult_expr', (2255, 2265), self.input.position) + _G_apply_181, lastError = self._apply(self.rule_mult_expr, "mult_expr", []) + self.considerError(lastError, None) + _locals['operand'] = _G_apply_181 + _G_python_183, lastError = eval(self._G_expr_182, self.globals, _locals), None + self.considerError(lastError, None) + _locals['node'] = _G_python_183 + return (_G_python_183, self.currentError) + def _G_or_184(): + self._trace(' ows', (2331, 2335), self.input.position) + _G_apply_185, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(" '-'", (2335, 2339), self.input.position) + _G_exactly_186, lastError = self.exactly('-') + self.considerError(lastError, None) + self._trace(' ows', (2339, 2343), self.input.position) + _G_apply_187, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(' mult_expr', (2343, 2353), self.input.position) + _G_apply_188, lastError = self._apply(self.rule_mult_expr, "mult_expr", []) + self.considerError(lastError, None) + _locals['operand'] = _G_apply_188 + _G_python_190, lastError = eval(self._G_expr_189, self.globals, _locals), None + self.considerError(lastError, None) + _locals['node'] = _G_python_190 + return (_G_python_190, self.currentError) + _G_or_191, lastError = self._or([_G_or_177, _G_or_184]) + self.considerError(lastError, None) + return (_G_or_191, self.currentError) + _G_many_192, lastError = self.many(_G_many_176) + self.considerError(lastError, 'add_expr') + _G_python_193, lastError = eval(self._G_expr_173, self.globals, _locals), None + self.considerError(lastError, 'add_expr') + return (_G_python_193, self.currentError) + + + def rule_mult_expr(self): + _locals = {'self': self} + self.locals['mult_expr'] = _locals + self._trace(' unary_expr', (2437, 2448), self.input.position) + _G_apply_194, lastError = self._apply(self.rule_unary_expr, "unary_expr", []) + self.considerError(lastError, 'mult_expr') + _locals['node'] = _G_apply_194 + def _G_many_195(): + def _G_or_196(): + self._trace('\n ows', (2455, 2467), self.input.position) + _G_apply_197, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(" '*'", (2467, 2471), self.input.position) + _G_exactly_198, lastError = self.exactly('*') + self.considerError(lastError, None) + self._trace(' ows', (2471, 2475), self.input.position) + _G_apply_199, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(' unary_expr', (2475, 2486), self.input.position) + _G_apply_200, lastError = self._apply(self.rule_unary_expr, "unary_expr", []) + self.considerError(lastError, None) + _locals['operand'] = _G_apply_200 + _G_python_202, lastError = eval(self._G_expr_201, self.globals, _locals), None + self.considerError(lastError, None) + _locals['node'] = _G_python_202 + return (_G_python_202, self.currentError) + def _G_or_203(): + self._trace(' ows', (2552, 2556), self.input.position) + _G_apply_204, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(" '/'", (2556, 2560), self.input.position) + _G_exactly_205, lastError = self.exactly('/') + self.considerError(lastError, None) + self._trace(' ows', (2560, 2564), self.input.position) + _G_apply_206, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(' unary_expr', (2564, 2575), self.input.position) + _G_apply_207, lastError = self._apply(self.rule_unary_expr, "unary_expr", []) + self.considerError(lastError, None) + _locals['operand'] = _G_apply_207 + _G_python_209, lastError = eval(self._G_expr_208, self.globals, _locals), None + self.considerError(lastError, None) + _locals['node'] = _G_python_209 + return (_G_python_209, self.currentError) + _G_or_210, lastError = self._or([_G_or_196, _G_or_203]) + self.considerError(lastError, None) + return (_G_or_210, self.currentError) + _G_many_211, lastError = self.many(_G_many_195) + self.considerError(lastError, 'mult_expr') + _G_python_212, lastError = eval(self._G_expr_173, self.globals, _locals), None + self.considerError(lastError, 'mult_expr') + return (_G_python_212, self.currentError) + + + def rule_unary_expr(self): + _locals = {'self': self} + self.locals['unary_expr'] = _locals + def _G_or_213(): + self._trace("\n '-'", (2662, 2674), self.input.position) + _G_exactly_214, lastError = self.exactly('-') + self.considerError(lastError, None) + self._trace(' unary_expr', (2674, 2685), self.input.position) + _G_apply_215, lastError = self._apply(self.rule_unary_expr, "unary_expr", []) + self.considerError(lastError, None) + _locals['node'] = _G_apply_215 + _G_python_217, lastError = eval(self._G_expr_216, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_217, self.currentError) + def _G_or_218(): + self._trace(" '+'", (2731, 2735), self.input.position) + _G_exactly_219, lastError = self.exactly('+') + self.considerError(lastError, None) + self._trace(' unary_expr', (2735, 2746), self.input.position) + _G_apply_220, lastError = self._apply(self.rule_unary_expr, "unary_expr", []) + self.considerError(lastError, None) + _locals['node'] = _G_apply_220 + _G_python_222, lastError = eval(self._G_expr_221, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_222, self.currentError) + def _G_or_223(): + self._trace(' atom', (2792, 2797), self.input.position) + _G_apply_224, lastError = self._apply(self.rule_atom, "atom", []) + self.considerError(lastError, None) + return (_G_apply_224, self.currentError) + _G_or_225, lastError = self._or([_G_or_213, _G_or_218, _G_or_223]) + self.considerError(lastError, 'unary_expr') + return (_G_or_225, self.currentError) + + + def rule_atom(self): + _locals = {'self': self} + self.locals['atom'] = _locals + def _G_or_226(): + self._trace("\n # Parenthesized expression\n '('", (2813, 2860), self.input.position) + _G_exactly_227, lastError = self.exactly('(') + self.considerError(lastError, None) + self._trace(' comma_list', (2860, 2871), self.input.position) + _G_apply_228, lastError = self._apply(self.rule_comma_list, "comma_list", []) + self.considerError(lastError, None) + _locals['node'] = _G_apply_228 + self._trace(" ')'", (2876, 2880), self.input.position) + _G_exactly_229, lastError = self.exactly(')') + self.considerError(lastError, None) + _G_python_230, lastError = eval(self._G_expr_173, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_230, self.currentError) + def _G_or_231(): + self._trace(" '['", (2978, 2982), self.input.position) + _G_exactly_232, lastError = self.exactly('[') + self.considerError(lastError, None) + self._trace(' comma_list', (2982, 2993), self.input.position) + _G_apply_233, lastError = self._apply(self.rule_comma_list, "comma_list", []) + self.considerError(lastError, None) + _locals['node'] = _G_apply_233 + self._trace(" ']'", (2998, 3002), self.input.position) + _G_exactly_234, lastError = self.exactly(']') + self.considerError(lastError, None) + _G_python_235, lastError = eval(self._G_expr_173, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_235, self.currentError) + def _G_or_236(): + self._trace(" 'u'", (3043, 3047), self.input.position) + _G_exactly_237, lastError = self.exactly('u') + self.considerError(lastError, None) + self._trace(" 'r'", (3047, 3051), self.input.position) + _G_exactly_238, lastError = self.exactly('r') + self.considerError(lastError, None) + self._trace(" 'l'", (3051, 3055), self.input.position) + _G_exactly_239, lastError = self.exactly('l') + self.considerError(lastError, None) + self._trace(" '('", (3055, 3059), self.input.position) + _G_exactly_240, lastError = self.exactly('(') + self.considerError(lastError, None) + def _G_or_241(): + self._trace('string', (3061, 3067), self.input.position) + _G_apply_242, lastError = self._apply(self.rule_string, "string", []) + self.considerError(lastError, None) + return (_G_apply_242, self.currentError) + def _G_or_243(): + self._trace(' uri', (3069, 3073), self.input.position) + _G_apply_244, lastError = self._apply(self.rule_uri, "uri", []) + self.considerError(lastError, None) + return (_G_apply_244, self.currentError) + _G_or_245, lastError = self._or([_G_or_241, _G_or_243]) + self.considerError(lastError, None) + _locals['s'] = _G_or_245 + self._trace(" ')'", (3076, 3080), self.input.position) + _G_exactly_246, lastError = self.exactly(')') + self.considerError(lastError, None) + _G_python_248, lastError = eval(self._G_expr_247, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_248, self.currentError) + def _G_or_249(): + self._trace(' identifier', (3144, 3155), self.input.position) + _G_apply_250, lastError = self._apply(self.rule_identifier, "identifier", []) + self.considerError(lastError, None) + _locals['name'] = _G_apply_250 + self._trace(" '('", (3160, 3164), self.input.position) + _G_exactly_251, lastError = self.exactly('(') + self.considerError(lastError, None) + self._trace(' argspec', (3164, 3172), self.input.position) + _G_apply_252, lastError = self._apply(self.rule_argspec, "argspec", []) + self.considerError(lastError, None) + _locals['args'] = _G_apply_252 + self._trace(" ')'", (3177, 3181), self.input.position) + _G_exactly_253, lastError = self.exactly(')') + self.considerError(lastError, None) + _G_python_255, lastError = eval(self._G_expr_254, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_255, self.currentError) + def _G_or_256(): + def _G_consumedby_257(): + def _G_optional_258(): + self._trace(" '!'", (3235, 3239), self.input.position) + _G_exactly_259, lastError = self.exactly('!') + self.considerError(lastError, None) + return (_G_exactly_259, self.currentError) + def _G_optional_260(): + return (None, self.input.nullError()) + _G_or_261, lastError = self._or([_G_optional_258, _G_optional_260]) + self.considerError(lastError, None) + self._trace(' identifier', (3240, 3251), self.input.position) + _G_apply_262, lastError = self._apply(self.rule_identifier, "identifier", []) + self.considerError(lastError, None) + return (_G_apply_262, self.currentError) + _G_consumedby_263, lastError = self.consumedby(_G_consumedby_257) + self.considerError(lastError, None) + _locals['word'] = _G_consumedby_263 + _G_python_265, lastError = eval(self._G_expr_264, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_265, self.currentError) + def _G_or_266(): + self._trace(' number', (3319, 3326), self.input.position) + _G_apply_267, lastError = self._apply(self.rule_number, "number", []) + self.considerError(lastError, None) + _locals['number'] = _G_apply_267 + def _G_optional_268(): + def _G_consumedby_269(): + def _G_or_270(): + self._trace(" '%'", (3335, 3339), self.input.position) + _G_exactly_271, lastError = self.exactly('%') + self.considerError(lastError, None) + return (_G_exactly_271, self.currentError) + def _G_or_272(): + def _G_many1_273(): + self._trace(' letter', (3341, 3348), self.input.position) + _G_apply_274, lastError = self._apply(self.rule_letter, "letter", []) + self.considerError(lastError, None) + return (_G_apply_274, self.currentError) + _G_many1_275, lastError = self.many(_G_many1_273, _G_many1_273()) + self.considerError(lastError, None) + return (_G_many1_275, self.currentError) + _G_or_276, lastError = self._or([_G_or_270, _G_or_272]) + self.considerError(lastError, None) + return (_G_or_276, self.currentError) + _G_consumedby_277, lastError = self.consumedby(_G_consumedby_269) + self.considerError(lastError, None) + return (_G_consumedby_277, self.currentError) + def _G_optional_278(): + return (None, self.input.nullError()) + _G_or_279, lastError = self._or([_G_optional_268, _G_optional_278]) + self.considerError(lastError, None) + _locals['unit'] = _G_or_279 + _G_python_281, lastError = eval(self._G_expr_280, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_281, self.currentError) + def _G_or_282(): + self._trace(' string', (3435, 3442), self.input.position) + _G_apply_283, lastError = self._apply(self.rule_string, "string", []) + self.considerError(lastError, None) + return (_G_apply_283, self.currentError) + def _G_or_284(): + def _G_consumedby_285(): + self._trace(" '#'", (3538, 3542), self.input.position) + _G_exactly_286, lastError = self.exactly('#') + self.considerError(lastError, None) + def _G_or_287(): + def _G_consumedby_288(): + def _G_repeat_289(): + self._trace('hex', (3558, 3561), self.input.position) + _G_apply_290, lastError = self._apply(self.rule_hex, "hex", []) + self.considerError(lastError, None) + return (_G_apply_290, self.currentError) + _G_repeat_291, lastError = self.repeat(2, 2, _G_repeat_289) + self.considerError(lastError, None) + return (_G_repeat_291, self.currentError) + _G_consumedby_292, lastError = self.consumedby(_G_consumedby_288) + self.considerError(lastError, None) + _locals['red'] = _G_consumedby_292 + def _G_consumedby_293(): + def _G_repeat_294(): + self._trace('hex', (3571, 3574), self.input.position) + _G_apply_295, lastError = self._apply(self.rule_hex, "hex", []) + self.considerError(lastError, None) + return (_G_apply_295, self.currentError) + _G_repeat_296, lastError = self.repeat(2, 2, _G_repeat_294) + self.considerError(lastError, None) + return (_G_repeat_296, self.currentError) + _G_consumedby_297, lastError = self.consumedby(_G_consumedby_293) + self.considerError(lastError, None) + _locals['green'] = _G_consumedby_297 + def _G_consumedby_298(): + def _G_repeat_299(): + self._trace('hex', (3586, 3589), self.input.position) + _G_apply_300, lastError = self._apply(self.rule_hex, "hex", []) + self.considerError(lastError, None) + return (_G_apply_300, self.currentError) + _G_repeat_301, lastError = self.repeat(2, 2, _G_repeat_299) + self.considerError(lastError, None) + return (_G_repeat_301, self.currentError) + _G_consumedby_302, lastError = self.consumedby(_G_consumedby_298) + self.considerError(lastError, None) + _locals['blue'] = _G_consumedby_302 + return (_G_consumedby_302, self.currentError) + def _G_or_303(): + self._trace(' hex', (3727, 3731), self.input.position) + _G_apply_304, lastError = self._apply(self.rule_hex, "hex", []) + self.considerError(lastError, None) + _locals['red'] = _G_apply_304 + self._trace(' hex', (3735, 3739), self.input.position) + _G_apply_305, lastError = self._apply(self.rule_hex, "hex", []) + self.considerError(lastError, None) + _locals['green'] = _G_apply_305 + self._trace(' hex', (3745, 3749), self.input.position) + _G_apply_306, lastError = self._apply(self.rule_hex, "hex", []) + self.considerError(lastError, None) + _locals['blue'] = _G_apply_306 + return (_G_apply_306, self.currentError) + _G_or_307, lastError = self._or([_G_or_287, _G_or_303]) + self.considerError(lastError, None) + return (_G_or_307, self.currentError) + _G_consumedby_308, lastError = self.consumedby(_G_consumedby_285) + self.considerError(lastError, None) + _locals['color'] = _G_consumedby_308 + _G_python_310, lastError = eval(self._G_expr_309, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_310, self.currentError) + def _G_or_311(): + self._trace(' variable', (3957, 3966), self.input.position) + _G_apply_312, lastError = self._apply(self.rule_variable, "variable", []) + self.considerError(lastError, None) + _locals['name'] = _G_apply_312 + _G_python_314, lastError = eval(self._G_expr_313, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_314, self.currentError) + _G_or_315, lastError = self._or([_G_or_226, _G_or_231, _G_or_236, _G_or_249, _G_or_256, _G_or_266, _G_or_282, _G_or_284, _G_or_311]) + self.considerError(lastError, 'atom') + return (_G_or_315, self.currentError) + + + def rule_uri(self): + _locals = {'self': self} + self.locals['uri'] = _locals + def _G_many_316(): + def _G_or_317(): + self._trace('\n escape', (4164, 4179), self.input.position) + _G_apply_318, lastError = self._apply(self.rule_escape, "escape", []) + self.considerError(lastError, None) + return (_G_apply_318, self.currentError) + def _G_or_319(): + self._trace(' anything', (4189, 4198), self.input.position) + _G_apply_320, lastError = self._apply(self.rule_anything, "anything", []) + self.considerError(lastError, None) + _locals['ch'] = _G_apply_320 + def _G_pred_321(): + _G_python_323, lastError = eval(self._G_expr_322, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_323, self.currentError) + _G_pred_324, lastError = self.pred(_G_pred_321) + self.considerError(lastError, None) + _G_python_326, lastError = eval(self._G_expr_325, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_326, self.currentError) + _G_or_327, lastError = self._or([_G_or_317, _G_or_319]) + self.considerError(lastError, None) + return (_G_or_327, self.currentError) + _G_many_328, lastError = self.many(_G_many_316) + self.considerError(lastError, 'uri') + _locals['s'] = _G_many_328 + _G_python_330, lastError = eval(self._G_expr_329, self.globals, _locals), None + self.considerError(lastError, 'uri') + return (_G_python_330, self.currentError) + + + def rule_string(self): + _locals = {'self': self} + self.locals['string'] = _locals + def _G_or_331(): + self._trace('\n \'"\'', (4313, 4325), self.input.position) + _G_exactly_332, lastError = self.exactly('"') + self.considerError(lastError, None) + self._trace(' string_contents(\'"\')', (4325, 4346), self.input.position) + _G_python_333, lastError = ('"'), None + self.considerError(lastError, None) + _G_apply_334, lastError = self._apply(self.rule_string_contents, "string_contents", [_G_python_333]) + self.considerError(lastError, None) + _locals['node'] = _G_apply_334 + self._trace(' \'"\'', (4351, 4355), self.input.position) + _G_exactly_335, lastError = self.exactly('"') + self.considerError(lastError, None) + _G_python_336, lastError = eval(self._G_expr_173, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_336, self.currentError) + def _G_or_337(): + self._trace(" '\\''", (4373, 4378), self.input.position) + _G_exactly_338, lastError = self.exactly("'") + self.considerError(lastError, None) + self._trace(" string_contents('\\'')", (4378, 4400), self.input.position) + _G_python_339, lastError = ('\''), None + self.considerError(lastError, None) + _G_apply_340, lastError = self._apply(self.rule_string_contents, "string_contents", [_G_python_339]) + self.considerError(lastError, None) + _locals['node'] = _G_apply_340 + self._trace(" '\\''", (4405, 4410), self.input.position) + _G_exactly_341, lastError = self.exactly("'") + self.considerError(lastError, None) + _G_python_342, lastError = eval(self._G_expr_173, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_342, self.currentError) + _G_or_343, lastError = self._or([_G_or_331, _G_or_337]) + self.considerError(lastError, 'string') + return (_G_or_343, self.currentError) + + + def rule_interpolation(self): + _locals = {'self': self} + self.locals['interpolation'] = _locals + self._trace(" '#'", (4441, 4445), self.input.position) + _G_exactly_344, lastError = self.exactly('#') + self.considerError(lastError, 'interpolation') + self._trace(" '{'", (4445, 4449), self.input.position) + _G_exactly_345, lastError = self.exactly('{') + self.considerError(lastError, 'interpolation') + self._trace(' expression', (4449, 4460), self.input.position) + _G_apply_346, lastError = self._apply(self.rule_expression, "expression", []) + self.considerError(lastError, 'interpolation') + _locals['node'] = _G_apply_346 + self._trace(" '}'", (4465, 4469), self.input.position) + _G_exactly_347, lastError = self.exactly('}') + self.considerError(lastError, 'interpolation') + _G_python_348, lastError = eval(self._G_expr_173, self.globals, _locals), None + self.considerError(lastError, 'interpolation') + return (_G_python_348, self.currentError) + + + def rule_string_contents(self): + _locals = {'self': self} + self.locals['string_contents'] = _locals + _G_apply_349, lastError = self._apply(self.rule_anything, "anything", []) + self.considerError(lastError, 'string_contents') + _locals['quote'] = _G_apply_349 + self._trace('\n string_part(quote)', (4515, 4546), self.input.position) + _G_python_351, lastError = eval(self._G_expr_350, self.globals, _locals), None + self.considerError(lastError, 'string_contents') + _G_apply_352, lastError = self._apply(self.rule_string_part, "string_part", [_G_python_351]) + self.considerError(lastError, 'string_contents') + _locals['before'] = _G_apply_352 + _G_python_354, lastError = eval(self._G_expr_353, self.globals, _locals), None + self.considerError(lastError, 'string_contents') + _locals['retval'] = _G_python_354 + def _G_many_355(): + self._trace('\n interpolation', (4647, 4677), self.input.position) + _G_apply_356, lastError = self._apply(self.rule_interpolation, "interpolation", []) + self.considerError(lastError, None) + _locals['node'] = _G_apply_356 + self._trace('\n string_part(quote)', (4682, 4717), self.input.position) + _G_python_357, lastError = eval(self._G_expr_350, self.globals, _locals), None + self.considerError(lastError, None) + _G_apply_358, lastError = self._apply(self.rule_string_part, "string_part", [_G_python_357]) + self.considerError(lastError, None) + _locals['after'] = _G_apply_358 + _G_python_360, lastError = eval(self._G_expr_359, self.globals, _locals), None + self.considerError(lastError, None) + _locals['retval'] = _G_python_360 + return (_G_python_360, self.currentError) + _G_many_361, lastError = self.many(_G_many_355) + self.considerError(lastError, 'string_contents') + _G_python_363, lastError = eval(self._G_expr_362, self.globals, _locals), None + self.considerError(lastError, 'string_contents') + return (_G_python_363, self.currentError) + + + def rule_string_part(self): + _locals = {'self': self} + self.locals['string_part'] = _locals + _G_apply_364, lastError = self._apply(self.rule_anything, "anything", []) + self.considerError(lastError, 'string_part') + _locals['quote'] = _G_apply_364 + def _G_consumedby_365(): + def _G_many_366(): + def _G_or_367(): + self._trace("\n '#'", (4895, 4907), self.input.position) + _G_exactly_368, lastError = self.exactly('#') + self.considerError(lastError, None) + def _G_not_369(): + self._trace("'{'", (4909, 4912), self.input.position) + _G_exactly_370, lastError = self.exactly('{') + self.considerError(lastError, None) + return (_G_exactly_370, self.currentError) + _G_not_371, lastError = self._not(_G_not_369) + self.considerError(lastError, None) + return (_G_not_371, self.currentError) + def _G_or_372(): + self._trace(' anything', (4922, 4931), self.input.position) + _G_apply_373, lastError = self._apply(self.rule_anything, "anything", []) + self.considerError(lastError, None) + _locals['ch'] = _G_apply_373 + def _G_pred_374(): + _G_python_376, lastError = eval(self._G_expr_375, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_376, self.currentError) + _G_pred_377, lastError = self.pred(_G_pred_374) + self.considerError(lastError, None) + return (_G_pred_377, self.currentError) + _G_or_378, lastError = self._or([_G_or_367, _G_or_372]) + self.considerError(lastError, None) + return (_G_or_378, self.currentError) + _G_many_379, lastError = self.many(_G_many_366) + self.considerError(lastError, None) + return (_G_many_379, self.currentError) + _G_consumedby_380, lastError = self.consumedby(_G_consumedby_365) + self.considerError(lastError, 'string_part') + return (_G_consumedby_380, self.currentError) + + + def rule_argspec(self): + _locals = {'self': self} + self.locals['argspec'] = _locals + self._trace(' argspec_item', (5019, 5032), self.input.position) + _G_apply_381, lastError = self._apply(self.rule_argspec_item, "argspec_item", []) + self.considerError(lastError, 'argspec') + _locals['head'] = _G_apply_381 + def _G_many_382(): + self._trace('\n ows', (5039, 5051), self.input.position) + _G_apply_383, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(" ','", (5051, 5055), self.input.position) + _G_exactly_384, lastError = self.exactly(',') + self.considerError(lastError, None) + self._trace(' ows', (5055, 5059), self.input.position) + _G_apply_385, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace('\n argspec_item', (5059, 5080), self.input.position) + _G_apply_386, lastError = self._apply(self.rule_argspec_item, "argspec_item", []) + self.considerError(lastError, None) + _locals['tail'] = _G_apply_386 + _G_python_387, lastError = eval(self._G_expr_80, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_387, self.currentError) + _G_many_388, lastError = self.many(_G_many_382) + self.considerError(lastError, 'argspec') + _locals['tails'] = _G_many_388 + _G_python_390, lastError = eval(self._G_expr_389, self.globals, _locals), None + self.considerError(lastError, 'argspec') + return (_G_python_390, self.currentError) + + + def rule_argspec_item(self): + _locals = {'self': self} + self.locals['argspec_item'] = _locals + def _G_optional_391(): + self._trace(' variable', (5169, 5178), self.input.position) + _G_apply_392, lastError = self._apply(self.rule_variable, "variable", []) + self.considerError(lastError, None) + _locals['name'] = _G_apply_392 + self._trace(' ows', (5183, 5187), self.input.position) + _G_apply_393, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + self._trace(" ':'", (5187, 5191), self.input.position) + _G_exactly_394, lastError = self.exactly(':') + self.considerError(lastError, None) + self._trace(' ows', (5191, 5195), self.input.position) + _G_apply_395, lastError = self._apply(self.rule_ows, "ows", []) + self.considerError(lastError, None) + _G_python_397, lastError = eval(self._G_expr_396, self.globals, _locals), None + self.considerError(lastError, None) + return (_G_python_397, self.currentError) + def _G_optional_398(): + return (None, self.input.nullError()) + _G_or_399, lastError = self._or([_G_optional_391, _G_optional_398]) + self.considerError(lastError, 'argspec_item') + _locals['name'] = _G_or_399 + self._trace('\n spaced_list', (5211, 5231), self.input.position) + _G_apply_400, lastError = self._apply(self.rule_spaced_list, "spaced_list", []) + self.considerError(lastError, 'argspec_item') + _locals['value'] = _G_apply_400 + _G_python_402, lastError = eval(self._G_expr_401, self.globals, _locals), None + self.considerError(lastError, 'argspec_item') + return (_G_python_402, self.currentError) + + + _G_expr_353 = compile('Literal(String(before, quotes=quote))', '<string>', 'eval') + _G_expr_325 = compile('ch', '<string>', 'eval') + _G_expr_130 = compile('BinaryOp(operator.lt, node, operand)', '<string>', 'eval') + _G_expr_216 = compile('UnaryOp(operator.neg, node)', '<string>', 'eval') + _G_expr_309 = compile('Literal(ColorValue(ParserValue(color)))', '<string>', 'eval') + _G_expr_169 = compile('BinaryOp(operator.ne, node, operand)', '<string>', 'eval') + _G_expr_120 = compile('NotOp(node)', '<string>', 'eval') + _G_expr_322 = compile('ord(ch) > 32 and ch not in \' !"$\\\'()\'', '<string>', 'eval') + _G_expr_247 = compile("FunctionLiteral('url', s)", '<string>', 'eval') + _G_expr_264 = compile('Literal(parse_bareword(word))', '<string>', 'eval') + _G_expr_189 = compile('BinaryOp(operator.sub, node, operand)', '<string>', 'eval') + _G_expr_80 = compile('tail', '<string>', 'eval') + _G_expr_111 = compile('AllOp(*[head] + tails) if tails else head', '<string>', 'eval') + _G_expr_280 = compile('Literal(NumberValue(float(number), type=unit))', '<string>', 'eval') + _G_expr_350 = compile('quote', '<string>', 'eval') + _G_expr_254 = compile('CallOp(name, args)', '<string>', 'eval') + _G_expr_83 = compile('ListLiteral([head] + tails) if tails else head', '<string>', 'eval') + _G_expr_313 = compile('Variable(name)', '<string>', 'eval') + _G_expr_173 = compile('node', '<string>', 'eval') + _G_expr_221 = compile('UnaryOp(operator.pos, node)', '<string>', 'eval') + _G_expr_161 = compile('BinaryOp(operator.eq, node, operand)', '<string>', 'eval') + _G_expr_182 = compile('BinaryOp(operator.add, node, operand)', '<string>', 'eval') + _G_expr_137 = compile('BinaryOp(operator.gt, node, operand)', '<string>', 'eval') + _G_expr_389 = compile('ArgspecLiteral([head] + tails)', '<string>', 'eval') + _G_expr_208 = compile('BinaryOp(operator.div, node, operand)', '<string>', 'eval') + _G_expr_35 = compile('unichr(int(cp, 16))', '<string>', 'eval') + _G_expr_145 = compile('BinaryOp(operator.le, node, operand)', '<string>', 'eval') + _G_expr_91 = compile('ListLiteral([head] + tails, comma=False) if tails else head', '<string>', 'eval') + _G_expr_201 = compile('BinaryOp(operator.mul, node, operand)', '<string>', 'eval') + _G_expr_362 = compile('retval', '<string>', 'eval') + _G_expr_329 = compile("Literal(String(''.join(s), quotes=None))", '<string>', 'eval') + _G_expr_396 = compile('name', '<string>', 'eval') + _G_expr_401 = compile('(name, value)', '<string>', 'eval') + _G_expr_359 = compile('Interpolation(retval, node, Literal(String(after, quotes=quote)), quotes=quote)', '<string>', 'eval') + _G_expr_101 = compile('AnyOp(*[head] + tails) if tails else head', '<string>', 'eval') + _G_expr_153 = compile('BinaryOp(operator.ge, node, operand)', '<string>', 'eval') + _G_expr_375 = compile("ch not in ('#', quote)", '<string>', 'eval') + if Grammar.globals is not None: + Grammar.globals = Grammar.globals.copy() + Grammar.globals.update(ruleGlobals) + else: + Grammar.globals = ruleGlobals + return Grammar
\ No newline at end of file diff --git a/scss/expression.parsley b/scss/expression.parsley new file mode 100644 index 0000000..8dadd2f --- /dev/null +++ b/scss/expression.parsley @@ -0,0 +1,166 @@ +# Character classes +UNITS = < 'p' 'x' | 'c' 'm' | 'm' 'm' | 'h' 'z' | 'i' 'n' | '%' > + +### NOTE: These definitions are implemented in Python as an optimization, +### because lots of | has the most parsley overhead. The Python +### implementations are intended to match the behavior of the rules below. +#_space = ' ' | '\r' | '\n' | '\f' | '\t' +#ws = < _space+ > +#ows = < _space* > +#hex = DIGIT | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' +#letterish = letter | '_' | '-' + +escape = '\\' ( + '\n' -> '' + # TODO this is supposed to replace junk with FFFD + | <hex{1,6}>:cp ws? -> unichr(int(cp, 16)) + # TODO i think this should be... more specific? ascii + valid unicode? + # see also: rx.rb + | anything + ) + +# +# Tokens +identifier = < letterish (letterish | digit)* > +number = < digit+ ('.' digit*)? | '.' digit+ > +variable = < '$' identifier > + + +# Components +expression = comma_list + +comma_list = spaced_list:head ( + ows ',' ows + spaced_list:tail -> tail + )*:tails -> ListLiteral([head] + tails) if tails else head + +spaced_list = single_expression:head ( + ws + single_expression:tail -> tail + )*:tails -> ListLiteral([head] + tails, comma=False) if tails else head + + +single_expression = or_test + +or_test = and_test:head ( + 'o' 'r' + and_test:tail -> tail + )*:tails -> AnyOp(*[head] + tails) if tails else head + +and_test = not_test:head ( + 'a' 'n' 'd' + not_test:tail -> tail + )*:tails -> AllOp(*[head] + tails) if tails else head + +not_test = comparison | ( 'n' 'o' 't' not_test:node -> NotOp(node) ) + +comparison = add_expr:node ( + ows '<' ows add_expr:operand (-> BinaryOp(operator.lt, node, operand)):node + | ows '>' ows add_expr:operand (-> BinaryOp(operator.gt, node, operand)):node + | ows '<' '=' ows add_expr:operand (-> BinaryOp(operator.le, node, operand)):node + | ows '>' '=' ows add_expr:operand (-> BinaryOp(operator.ge, node, operand)):node + | ows '=' '=' ows add_expr:operand (-> BinaryOp(operator.eq, node, operand)):node + | ows '!' '=' ows add_expr:operand (-> BinaryOp(operator.ne, node, operand)):node + )* -> node + +add_expr = mult_expr:node ( + ows '+' ows mult_expr:operand (-> BinaryOp(operator.add, node, operand)):node + | ows '-' ows mult_expr:operand (-> BinaryOp(operator.sub, node, operand)):node + )* -> node + +mult_expr = unary_expr:node ( + ows '*' ows unary_expr:operand (-> BinaryOp(operator.mul, node, operand)):node + | ows '/' ows unary_expr:operand (-> BinaryOp(operator.div, node, operand)):node + )* -> node + +unary_expr = ( + '-' unary_expr:node -> UnaryOp(operator.neg, node) + | '+' unary_expr:node -> UnaryOp(operator.pos, node) + | atom + ) + +atom = ( + # Parenthesized expression + '(' comma_list:node ')' -> node + + # Old xCSS-style parenthesized expression + # TODO kill this off + | '[' comma_list:node ']' -> node + + # URL literal + | 'u' 'r' 'l' '(' (string | uri):s ')' -> FunctionLiteral('url', s) + + # Function call + | identifier:name '(' argspec:args ')' -> CallOp(name, args) + + # Bareword + | < '!'? identifier >:word -> Literal(parse_bareword(word)) + + # Number + | number:number < '%' | letter+ >?:unit -> Literal(NumberValue(float(number), type=unit)) + + # String + | string + + # Color literal + # TODO: stop making ColorValue finish this parsing + | < '#' ( + <hex{2}>:red <hex{2}>:green <hex{2}>:blue + #-> Literal(ColorValue.from_rgb(int(red, 16) / 255., int(green, 16) / 255., int(blue, 16) / 255.)) + | hex:red hex:green hex:blue + #-> Literal(ColorValue.from_rgb(int(red, 16) / 15., int(green, 16) / 15., int(blue, 16) / 15.)) + ) >:color -> Literal(ColorValue(ParserValue(color))) + + # Variable + | variable:name -> Variable(name) + ) + + +### Strings, literals, and interpolation +# TODO I'm not entirely sure any of these character classes are correct +# TODO ruby sass appears to preserve escapes + +uri = ( + escape + | anything:ch ?(ord(ch) > 32 and ch not in ' !"$\'()') -> ch + )*:s -> Literal(String(''.join(s), quotes=None)) + +string = ( + '"' string_contents('"'):node '"' -> node + | '\'' string_contents('\''):node '\'' -> node + ) + +interpolation = '#' '{' expression:node '}' -> node + +string_contents :quote = ( + ( + string_part(quote):before + -> Literal(String(before, quotes=quote)) + ):retval + ( + ( + interpolation:node + string_part(quote):after + -> Interpolation(retval, node, Literal(String(after, quotes=quote)), quotes=quote) + ):retval + )* + ) -> retval + +string_part :quote = <( + '#' ~'{' + | anything:ch ?(ch not in ('#', quote)) + )*> + + +### Function definitions and arguments +argspec = argspec_item:head ( + ows ',' ows + argspec_item:tail -> tail + )*:tails -> ArgspecLiteral([head] + tails) + + +argspec_item = ( + ( variable:name ows ':' ows -> name )?:name + spaced_list:value + -> (name, value) + ) diff --git a/scss/expression.py b/scss/expression.py index 91a164e..ea6dd8e 100644 --- a/scss/expression.py +++ b/scss/expression.py @@ -7,6 +7,7 @@ import re import six +import scss import scss.config as config from scss.cssdefs import COLOR_NAMES, is_builtin_css_function, _expr_glob_re, _interpolate_re, _variable_re from scss.errors import SassError, SassEvaluationError, SassParseError @@ -27,6 +28,70 @@ log = logging.getLogger(__name__) FATAL_UNDEFINED = True +from ometa.runtime import OMetaBase, expected +import string +HEXDIGITS = frozenset(string.hexdigits) +WHITESPACE = frozenset(' \n\r\t\f') +LETTERISH = frozenset(string.letters + '-_') +class GrammarBase(OMetaBase): + def rule_ws(self): + s, e = self.rule_ows() + if not s: + raise e.withMessage(expected("whitespace")) + + return s, e + + def rule_ows(self): + ret = [] + while True: + try: + c, e = self.input.head() + except EOFError: + break + + if c in WHITESPACE: + ret.append(c) + self.input = self.input.tail() + else: + break + + return ''.join(ret), e + + def rule_hex(self): + x, e = self.rule_anything() + if x in HEXDIGITS: + return x, e + else: + raise e.withMessage(expected("hex digit")) + + def rule_letterish(self): + x, e = self.rule_anything() + if x in LETTERISH: + return x, e + else: + raise e.withMessage(expected("letter or underscore or hyphen")) + +_grammar = None +def get_grammar(): + global _grammar + if _grammar: + return _grammar + + from parsley import wrapGrammar + from ometa.grammar import loadGrammar + grammar = loadGrammar(scss, 'expression', globals(), superclass=GrammarBase) + _grammar = wrapGrammar(grammar) + return grammar + + import parsley + import os.path + with open(os.path.dirname(__file__) + '/expression.parsley') as f: + grammar = parsley.makeGrammar(f.read(), globals()) + + _grammar = grammar + return grammar + + class Calculator(object): """Expression evaluator.""" @@ -99,7 +164,7 @@ class Calculator(object): def calculate(self, _base_str, divide=False): better_expr_str = _base_str - better_expr_str = self.do_glob_math(better_expr_str) + #better_expr_str = self.do_glob_math(better_expr_str) better_expr_str = self.evaluate_expression(better_expr_str, divide=divide) @@ -139,9 +204,22 @@ class Calculator(object): if key in self.ast_cache: return self.ast_cache[key] + grammar = get_grammar() + print("parsing:", repr(expr)) try: - parser = SassExpression(SassExpressionScanner(expr)) + if False: + print("got from original grammar:", end='') + parser = SassExpression(SassExpressionScanner(expr)) + ast = P.goal() + + else: + print("got from new grammar: ", end='') + parser = grammar(expr) + if target == 'goal': + target = 'expression' + ast = getattr(parser, target)() + print(repr(ast)) except SyntaxError as e: raise SassParseError(e, expression=expr, expression_pos=parser._char_pos) @@ -339,6 +417,16 @@ class Literal(Expression): return self.value +class FunctionLiteral(Expression): + def __init__(self, name, value_node): + self.name = name + self.value_node = value_node + + def evaluate(self, calculator): + value = self.value_node.evaluate(calculator) + return String(u"%s(%s)" % (self.name, value.render()), quotes=None) + + class Variable(Expression): def __repr__(self): return '<%s(%s)>' % (self.__class__.__name__, repr(self.name)) @@ -450,6 +538,33 @@ class ArgspecLiteral(Expression): yield var.name, value +class Interpolation(Expression): + def __init__(self, left, expr, right, quotes): + self.left = left + self.expr = expr + self.right = right + self.quotes = quotes + + def evaluate(self, calculator): + left_scss = self.left.evaluate(calculator) + if not isinstance(left_scss, String): + raise TypeError("Expected left side of interpolation to be String, got %r" % (left,)) + left = left_scss.value + + right_scss = self.right.evaluate(calculator) + if not isinstance(right_scss, String): + raise TypeError("Expected right side of interpolation to be String, got %r" % (left,)) + right = right_scss.value + + expr = self.expr.evaluate(calculator) + if isinstance(expr, String): + middle = expr.value + else: + middle = expr.render() + + return String(left + middle + right, quotes=self.quotes) + + def parse_bareword(word): if word in COLOR_NAMES: return Color.from_name(word) @@ -541,6 +656,12 @@ class SassExpressionScanner(Scanner): ('KWID', '[-a-zA-Z_][-a-zA-Z0-9_]*(?=\\s*:)'), ('ID', '[-a-zA-Z_][-a-zA-Z0-9_]*'), ('BANG_IMPORTANT', '!important'), + ('LINTERP', '#[{]'), + ('RINTERP', '[}]'), + ('SQUOT', "'"), + ('DQUOT', '"'), + ('SQCHAR', "([^'#]|#(?![{]))*"), + ('DQCHAR', '([^"#]|#(?![{]))*'), ] def __init__(self, input=None): @@ -606,7 +727,7 @@ class SassExpression(Parser): def expr_lst(self): expr_slst = self.expr_slst() v = [expr_slst] - while self._peek(self.argspec_rsts) == '","': + while self._peek(self.expr_lst_rsts) == '","': self._scan('","') expr_slst = self.expr_slst() v.append(expr_slst) @@ -615,7 +736,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_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] @@ -756,15 +877,33 @@ class SassExpression(Parser): 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(STR[1:-1], quotes="'")) - elif _token_ == 'QSTR': - QSTR = self._scan('QSTR') - return Literal(String(QSTR[1:-1], quotes='"')) elif _token_ == 'COLOR': COLOR = self._scan('COLOR') return Literal(Color(ParserValue(COLOR))) + elif _token_ == 'SQUOT': + SQUOT = self._scan('SQUOT') + SQCHAR = self._scan('SQCHAR') + v = Literal(String(SQCHAR, quotes="'")) + while self._peek(self.atom_rsts___) == 'LINTERP': + LINTERP = self._scan('LINTERP') + expr_lst = self.expr_lst() + RINTERP = self._scan('RINTERP') + SQCHAR = self._scan('SQCHAR') + v = Interpolation(v, expr_lst, Literal(String(SQCHAR, quotes="'")), quotes="'") + SQUOT = self._scan('SQUOT') + return v + elif _token_ == 'DQUOT': + DQUOT = self._scan('DQUOT') + DQCHAR = self._scan('DQCHAR') + v = Literal(String(DQCHAR, quotes='"')) + while self._peek(self.atom_rsts____) == 'LINTERP': + LINTERP = self._scan('LINTERP') + expr_lst = self.expr_lst() + RINTERP = self._scan('RINTERP') + DQCHAR = self._scan('DQCHAR') + v = Interpolation(v, expr_lst, Literal(String(DQCHAR, quotes='"')), quotes='"') + DQUOT = self._scan('DQUOT') + return v else: # == 'VAR' VAR = self._scan('VAR') return Variable(VAR) @@ -795,29 +934,33 @@ class SassExpression(Parser): KWVAR = self._scan('KWVAR') return Variable(KWVAR) - u_expr_chks = set(['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', 'GT', 'END', 'SIGN', 'GE', 'FNCT', 'STR', 'VAR', 'EQ', 'ID', 'AND', 'ADD', 'NOT', 'OR', '","']) + atom_rsts____ = set(['LINTERP', 'DQUOT']) + u_expr_chks = set(['LPAR', 'COLOR', 'SQUOT', 'DQUOT', 'NUM', 'FNCT', 'VAR', 'BANG_IMPORTANT', 'ID']) + m_expr_rsts = set(['LPAR', 'SUB', 'SQUOT', 'DQUOT', 'RPAR', 'MUL', 'DIV', 'BANG_IMPORTANT', 'LE', 'COLOR', 'NE', 'LT', 'NUM', 'GT', 'END', 'RINTERP', 'SIGN', 'GE', 'FNCT', 'VAR', 'EQ', 'ID', 'AND', 'ADD', 'NOT', 'OR', '","']) expr_map_rsts = set(['RPAR', '","']) + expr_lst_rsts = set(['RPAR', 'RINTERP', 'END', '","']) kwatom_rsts = set(['KWVAR', 'KWID', 'KWSTR', 'KWQSTR', 'KWCOLOR', '":"', 'KWNUM']) - argspec_item_chks = set(['LPAR', 'COLOR', 'QSTR', 'SIGN', 'VAR', 'ADD', 'NUM', 'FNCT', 'STR', 'NOT', 'BANG_IMPORTANT', 'ID']) + argspec_item_chks = set(['LPAR', 'COLOR', 'SQUOT', 'DQUOT', 'SIGN', 'VAR', 'ADD', 'NUM', 'FNCT', 'NOT', 'BANG_IMPORTANT', 'ID']) a_expr_chks = set(['ADD', 'SUB']) - expr_slst_rsts = set(['LPAR', 'END', 'COLOR', 'QSTR', 'SIGN', 'VAR', 'ADD', 'NUM', 'RPAR', 'FNCT', 'STR', 'NOT', 'BANG_IMPORTANT', 'ID', '","']) - a_expr_rsts = set(['LPAR', 'SUB', 'QSTR', 'RPAR', 'BANG_IMPORTANT', 'LE', 'COLOR', 'NE', 'LT', 'NUM', 'GT', 'END', 'SIGN', 'GE', 'FNCT', 'STR', 'VAR', 'EQ', 'ID', 'AND', 'ADD', 'NOT', 'OR', '","']) - or_expr_rsts = set(['LPAR', 'END', 'COLOR', 'QSTR', 'SIGN', 'VAR', 'ADD', 'NUM', 'RPAR', 'FNCT', 'STR', 'NOT', 'ID', 'BANG_IMPORTANT', 'OR', '","']) - argspec_item_rsts = set(['KWVAR', 'LPAR', 'COLOR', 'QSTR', 'SIGN', 'VAR', 'ADD', 'NUM', 'FNCT', 'STR', 'NOT', 'BANG_IMPORTANT', 'ID']) - atom_rsts = set(['KWVAR', 'KWID', 'KWSTR', 'BANG_IMPORTANT', 'LPAR', 'COLOR', 'KWQSTR', 'SIGN', 'KWCOLOR', 'VAR', 'ADD', 'NUM', '":"', 'STR', 'NOT', 'QSTR', 'KWNUM', 'ID', 'FNCT']) - comparison_rsts = set(['LPAR', 'QSTR', 'RPAR', 'BANG_IMPORTANT', 'LE', 'COLOR', 'NE', 'LT', 'NUM', 'GT', 'END', 'SIGN', 'ADD', 'FNCT', 'STR', 'VAR', 'EQ', 'ID', 'AND', 'GE', 'NOT', 'OR', '","']) - atom_rsts_ = set(['KWVAR', 'LPAR', 'BANG_IMPORTANT', 'END', 'COLOR', 'QSTR', 'SIGN', 'VAR', 'ADD', 'NUM', 'FNCT', 'STR', 'NOT', 'RPAR', 'ID']) + expr_slst_rsts = set(['LPAR', 'END', 'COLOR', 'SQUOT', 'DQUOT', 'RINTERP', 'SIGN', 'VAR', 'ADD', 'NUM', 'RPAR', 'FNCT', 'NOT', 'BANG_IMPORTANT', 'ID', '","']) + a_expr_rsts = set(['LPAR', 'SUB', 'SQUOT', 'DQUOT', 'RPAR', 'BANG_IMPORTANT', 'LE', 'COLOR', 'NE', 'LT', 'NUM', 'GT', 'END', 'RINTERP', 'SIGN', 'GE', 'FNCT', 'VAR', 'EQ', 'ID', 'AND', 'ADD', 'NOT', 'OR', '","']) + or_expr_rsts = set(['LPAR', 'END', 'COLOR', 'SQUOT', 'DQUOT', 'RINTERP', 'SIGN', 'VAR', 'ADD', 'NUM', 'RPAR', 'FNCT', 'NOT', 'ID', 'BANG_IMPORTANT', 'OR', '","']) + argspec_item_rsts = set(['KWVAR', 'LPAR', 'COLOR', 'SQUOT', 'DQUOT', 'SIGN', 'VAR', 'ADD', 'NUM', 'FNCT', 'NOT', 'BANG_IMPORTANT', 'ID']) + atom_rsts = set(['KWVAR', 'KWID', 'KWSTR', 'BANG_IMPORTANT', 'LPAR', 'COLOR', 'SQUOT', 'KWQSTR', 'DQUOT', 'SIGN', 'KWCOLOR', 'VAR', 'ADD', 'NUM', '":"', 'NOT', 'KWNUM', 'ID', 'FNCT']) + comparison_rsts = set(['LPAR', 'SQUOT', 'DQUOT', 'RPAR', 'BANG_IMPORTANT', 'LE', 'COLOR', 'NE', 'LT', 'NUM', 'GT', 'END', 'RINTERP', 'SIGN', 'ADD', 'FNCT', 'VAR', 'EQ', 'ID', 'AND', 'GE', 'NOT', 'OR', '","']) + atom_rsts_ = set(['KWVAR', 'LPAR', 'BANG_IMPORTANT', 'END', 'COLOR', 'SQUOT', 'DQUOT', 'SIGN', 'VAR', 'ADD', 'NUM', 'FNCT', 'NOT', 'RPAR', 'ID']) expr_map_rsts_ = set(['KWVAR', 'KWID', 'KWSTR', 'KWQSTR', 'RPAR', 'KWCOLOR', '":"', 'KWNUM', '","']) - u_expr_rsts = set(['LPAR', 'COLOR', 'QSTR', 'SIGN', 'ADD', 'NUM', 'FNCT', 'STR', 'VAR', 'BANG_IMPORTANT', 'ID']) + u_expr_rsts = set(['LPAR', 'COLOR', 'SQUOT', 'DQUOT', 'SIGN', 'ADD', 'NUM', 'FNCT', 'VAR', 'BANG_IMPORTANT', 'ID']) atom_chks = set(['END', 'RPAR']) comparison_chks = set(['GT', 'GE', 'NE', 'LT', 'LE', 'EQ']) - atom_rsts__ = set(['LPAR', 'SUB', 'QSTR', 'RPAR', 'VAR', 'MUL', 'DIV', 'BANG_IMPORTANT', 'LE', 'COLOR', 'NE', 'LT', 'NUM', 'GT', 'END', 'SIGN', 'GE', 'FNCT', 'STR', 'UNITS', 'EQ', 'ID', 'AND', 'ADD', 'NOT', 'OR', '","']) + atom_rsts__ = set(['LPAR', 'SUB', 'SQUOT', 'DQUOT', 'RPAR', 'VAR', 'MUL', 'DIV', 'BANG_IMPORTANT', 'LE', 'COLOR', 'NE', 'LT', 'NUM', 'GT', 'END', 'RINTERP', 'SIGN', 'GE', 'FNCT', 'UNITS', 'EQ', 'ID', 'AND', 'ADD', 'NOT', 'OR', '","']) m_expr_chks = set(['MUL', 'DIV']) kwatom_rsts_ = set(['UNITS', '":"']) + atom_rsts___ = set(['LINTERP', 'SQUOT']) argspec_rsts = set(['RPAR', 'END', '","']) - and_expr_rsts = set(['AND', 'LPAR', 'END', 'COLOR', 'QSTR', 'SIGN', 'VAR', 'ADD', 'NUM', 'RPAR', 'FNCT', 'STR', 'NOT', 'ID', 'BANG_IMPORTANT', 'OR', '","']) - argspec_rsts_ = set(['KWVAR', 'LPAR', 'BANG_IMPORTANT', 'END', 'COLOR', 'QSTR', 'SIGN', 'VAR', 'ADD', 'NUM', 'FNCT', 'STR', 'NOT', 'RPAR', 'ID', '","']) + and_expr_rsts = set(['AND', 'LPAR', 'END', 'COLOR', 'SQUOT', 'DQUOT', 'RINTERP', 'SIGN', 'VAR', 'ADD', 'NUM', 'RPAR', 'FNCT', 'NOT', 'ID', 'BANG_IMPORTANT', 'OR', '","']) + argspec_rsts_ = set(['KWVAR', 'LPAR', 'BANG_IMPORTANT', 'END', 'COLOR', 'SQUOT', 'DQUOT', 'SIGN', 'VAR', 'ADD', 'NUM', 'FNCT', 'NOT', 'RPAR', 'ID', '","']) + ### Grammar ends. ################################################################################ diff --git a/scss/src/grammar/grammar.g b/scss/src/grammar/grammar.g index 1da3f46..170729a 100644 --- a/scss/src/grammar/grammar.g +++ b/scss/src/grammar/grammar.g @@ -38,6 +38,12 @@ parser SassExpression: token KWID: "[-a-zA-Z_][-a-zA-Z0-9_]*(?=\s*:)" token ID: "[-a-zA-Z_][-a-zA-Z0-9_]*" token BANG_IMPORTANT: "!important" + token LINTERP: "#[{]" + token RINTERP: "[}]" + token SQUOT: "'" + token DQUOT: '"' + token SQCHAR: "([^'#]|#(?![{]))*" + token DQCHAR: '([^"#]|#(?![{]))*' # Goals: rule goal: expr_lst END {{ return expr_lst }} @@ -126,9 +132,25 @@ parser SassExpression: | ID {{ return Literal(parse_bareword(ID)) }} | NUM {{ UNITS = None }} [ UNITS ] {{ return Literal(Number(float(NUM), unit=UNITS)) }} - | STR {{ return Literal(String(STR[1:-1], quotes="'")) }} - | QSTR {{ return Literal(String(QSTR[1:-1], quotes='"')) }} | COLOR {{ return Literal(Color(ParserValue(COLOR))) }} + | SQUOT + SQCHAR {{ v = Literal(String(SQCHAR, quotes="'")) }} + ( + LINTERP + expr_lst + RINTERP + SQCHAR {{ v = Interpolation(v, expr_lst, Literal(String(SQCHAR, quotes="'")), quotes="'") }} + )* + SQUOT {{ return v }} + | DQUOT + DQCHAR {{ v = Literal(String(DQCHAR, quotes='"')) }} + ( + LINTERP + expr_lst + RINTERP + DQCHAR {{ v = Interpolation(v, expr_lst, Literal(String(DQCHAR, quotes='"')), quotes='"') }} + )* + DQUOT {{ return v }} | VAR {{ return Variable(VAR) }} rule kwatom: diff --git a/scss/tests/files/bugs/003-single-quoted-values.css b/scss/tests/files/bugs/003-single-quoted-values.css new file mode 100644 index 0000000..524ab2c --- /dev/null +++ b/scss/tests/files/bugs/003-single-quoted-values.css @@ -0,0 +1,6 @@ +div { + label: 'a b'; +} +div:after { + content: ''; +} |