Skip to content

Instantly share code, notes, and snippets.

@trnila
Created February 21, 2017 08:22
Show Gist options
  • Save trnila/6c846bb5b24625fc47f0b68e2cadf4cf to your computer and use it in GitHub Desktop.
Save trnila/6c846bb5b24625fc47f0b68e2cadf4cf to your computer and use it in GitHub Desktop.
from enum import Enum
import logging
class ParseException(Exception):
pass
class Tokens(Enum):
START_PROPS = 1
END_PROPS = 2
TEXT = 3
SEMICOLON = 4
COLON = 5
EOF = 6
def tokenize(data):
last = ""
for c in data:
if c in ['{', '}', ';', ':', ' ', '\n']:
if last:
yield (Tokens.TEXT, last)
last = ""
if c == '{':
yield (Tokens.START_PROPS, None)
elif c == '}':
yield (Tokens.END_PROPS, None)
elif c == ';':
yield (Tokens.SEMICOLON, None)
elif c == ':':
yield (Tokens.COLON, None)
else:
last += c
yield (Tokens.EOF, None)
class Parser:
def __init__(self, data):
self.tokens = tokenize(data)
self.currentSelector = None
def next_token(self):
token = next(self.tokens)
logging.debug("consumed %s", token)
return token
def check(self, wanted):
tok = self.next_token()
if tok[0] != wanted:
raise ParseException("got {}, but expected {}".format(tok, wanted))
def selector(self, tok):
logging.debug("selector %s", tok[1])
self.currentSelector = tok[1]
if tok[0] != Tokens.TEXT or not tok[1].startswith("."):
raise ParseException("Only class selectors are allowed")
def prop(self, property):
self.check(Tokens.COLON)
value = []
token = self.next_token()
while token[0] == Tokens.TEXT:
value.append(token[1])
token = self.next_token()
logging.debug("property %s: %s", property[1], value)
self.on_property(self.currentSelector, property[1], value)
return token
def on_property(self, selector, property, value):
pass
def props(self, token):
if token[0] in [Tokens.END_PROPS]:
return
token = self.prop(token)
if token[0] == Tokens.SEMICOLON:
token = self.next_token()
self.props(token)
def rule(self, c):
self.selector(c)
self.check(Tokens.START_PROPS)
self.props(self.next_token())
def parse(self):
c = self.next_token()
if c[0] == Tokens.EOF:
return
self.rule(c)
self.parse()
class VisibilityParser(Parser):
def __init__(self, data):
super().__init__(data)
self.hidden_classes = []
def on_property(self, selector, property, value):
if property != 'display' or not selector.startswith('.') or value[0] == 'inline':
return
className = selector[1:]
if className not in self.hidden_classes:
self.hidden_classes.append(className)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment