Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: franksort/css3tool
...
head fork: franksort/css3tool
  • 6 commits
  • 9 files changed
  • 0 commit comments
  • 1 contributor
View
6 example/at.css
@@ -0,0 +1,6 @@
+@media print {
+ body {
+ background-color: white;
+ color: black;
+ }
+}
View
5 example/atkeyword.css
@@ -1,5 +0,0 @@
-@media print {
- body {
- whatever: cool;
- }
-}
View
4 example/font-face.css
@@ -0,0 +1,4 @@
+@font-face {
+ font-family: Helvetica;
+ color: #000;
+}
View
2  example/import.css
@@ -0,0 +1,2 @@
+@import 'whatever';
+@import url('whatever') cool, url('dope') hi;
View
6 example/media.css
@@ -0,0 +1,6 @@
+@media not print and (color), whatever and something {
+ h3 {
+ background-color: white;
+ color: black;
+ }
+}
View
4 example/namespace.css
@@ -0,0 +1,4 @@
+@namespace name "string";
+@namespace name url('url');
+@namespace "string";
+@namespace url('url');
View
7 example/page.css
@@ -0,0 +1,7 @@
+@page ident:pseudo {
+ background-color: #000;
+ color: #000;
+}
+@page :pseudo {
+ background-color: #000;
+}
View
58 lexer.py
@@ -95,9 +95,9 @@ def t_DIMENSION(self, t): return t
############################################################
### Functions
- tokens.append('NOT')
- def t_NOT(self, t): return t
- t_NOT.__doc__ = r'not\('
+ tokens.append('NOTFUNC')
+ def t_NOTFUNC(self, t): return t
+ t_NOTFUNC.__doc__ = r'not\('
tokens.append('URI')
def t_URI(self, t): return t
@@ -115,16 +115,41 @@ def t_FUNCTION(self, t): return t
def t_HASH(self, t): return t
t_HASH.__doc__ = r'\#{0}'.format(name)
- #tokens.append('ATKEYWORD')
- #def t_ATKEYWORD(t): return t
- #t_ATKEYWORD.__doc__ = r'\@{0}'.format(name)
-
tokens.append('PERCENTAGE')
def t_PERCENTAGE(self, t): return t
t_PERCENTAGE.__doc__ = r'{0}\%'.format(num)
############################################################
+ ### At-keywords
+
+ tokens.append('IMPORT_SYM')
+ def t_IMPORT_SYM(self, t):
+ r'\@import'
+ return t
+
+ tokens.append('NAMESPACE_SYM')
+ def t_NAMESPACE_SYM(self, t):
+ r'\@namespace'
+ return t
+
+ tokens.append('PAGE_SYM')
+ def t_PAGE_SYM(self, t):
+ r'\@page'
+ return t
+
+ tokens.append('FONT_FACE_SYM')
+ def t_FONT_FACE_SYM(self, t):
+ r'\@font-face'
+ return t
+
+ tokens.append('MEDIA_SYM')
+ def t_MEDIA_SYM(self, t):
+ r'\@media'
+ return t
+
+
+ ############################################################
### Comments
tokens.append('CDO')
@@ -149,6 +174,21 @@ def t_NUMBER(self, t): return t
def t_STRING(self, t): return t
t_STRING.__doc__ = r'{0}'.format(string)
+ tokens.append('ONLY')
+ def t_ONLY(self, t):
+ r'only'
+ return t
+
+ tokens.append('AND')
+ def t_AND(self, t):
+ r'and'
+ return t
+
+ tokens.append('NOT')
+ def t_NOT(self, t):
+ r'not'
+ return t
+
tokens.append('IDENT')
def t_IDENT(self, t): return t
t_IDENT.__doc__ = r'{0}'.format(ident)
@@ -165,9 +205,9 @@ def t_error(self, t):
print "Illegal character '{0}'".format(t.value[0])
t.lexer.skip(1)
- def test(self, data):
+ def debug(self, data):
self.lexer.input(data)
while True:
tok = self.lexer.token()
if not tok: break
- print tok
+ logging.debug(tok)
View
180 parser.py
@@ -9,13 +9,16 @@ class CSSParser:
def __init__(self, debug=False):
- self.lexer = CSSLexer(debug=debug)
+ self.debug = debug
+ self.lexer = CSSLexer(debug=self.debug)
self.tokens = self.lexer.tokens
self.parser = yacc.yacc(module=self, debug=debug, write_tables=0)
self.selectors = []
def parse(self, data):
if data:
+ if self.debug:
+ self.lexer.debug(data)
return self.parser.parse(data, self.lexer.lexer)
else:
return []
@@ -37,35 +40,159 @@ def p_statements(self, p):
def p_statement(self, p):
"""statement : ruleset
+ | import
+ | namespace
+ | page
+ | font-face
+ | media
"""
- # | at-rule
p[0] = p[1]
logging.debug('FOUND STATEMENT: {0}'.format(p[0]))
- #def p_at_rule(p):
- # """at-rule : ATKEYWORD anys block
- # | ATKEYWORD anys ';'
- # """
- # p[0] = reduce(lambda x, y: x+y, p[1:])
- # print 'FOUND AT RULE: {0:s}'.format(p[0])
-
- #def p_block(p):
- # """block : '{' block_term '}'
- # | '{' '}'
- # """
- # p[0] = reduce(lambda x, y: x+y, p[1:])
- # print 'FOUND BLOCK: {0:s}'.format(p[0])
- # blocks.append(p[0])
-
- #def p_block_term(p):
- # """block_term : any
- # | block
- # | ATKEYWORD
- # | ';'
- # """
- # p[0] = reduce(lambda x, y: x+y, p[1:])
- # print 'FOUND BLOCK TERM: {0:s}'.format(p[0])
+ ##########################################################
+ ### Import
+
+ def p_import(self, p):
+ """import : IMPORT_SYM STRING import_term ';'
+ | IMPORT_SYM STRING ';'
+ | IMPORT_SYM URI import_term ';'
+ | IMPORT_SYM URI ';'
+ """
+ p[0] = reduce(lambda x, y: x+y, p[1:])
+ logging.debug('FOUND IMPORT: {0}'.format(p[0]))
+
+ def p_import_term(self, p):
+ """import_term : IDENT ',' import_term
+ | IDENT
+ """
+ p[0] = reduce(lambda x, y: x+y, p[1:])
+ logging.debug('FOUND IMPORT TERM: {0}'.format(p[0]))
+
+
+ ##########################################################
+ ### At Rule: namespace
+
+ def p_namespace(self, p):
+ """namespace : NAMESPACE_SYM IDENT STRING ';'
+ | NAMESPACE_SYM IDENT URI ';'
+ | NAMESPACE_SYM STRING ';'
+ | NAMESPACE_SYM URI ';'
+ """
+ p[0] = reduce(lambda x, y: x+y, p[1:])
+ logging.debug('FOUND NAMESPACE: {0}'.format(p[0]))
+
+
+ ##########################################################
+ ### At Rule: page
+
+ def p_page(self, p):
+ """page : PAGE_SYM IDENT pseudo_page '{' declarations '}'
+ | PAGE_SYM pseudo_page '{' declarations '}'
+ """
+ p[0] = reduce(lambda x, y: x+y, p[1:])
+ logging.debug('FOUND PAGE: {0}'.format(p[0]))
+
+ def p_pseudo_page(self, p):
+ """pseudo_page : ':' IDENT"""
+ p[0] = p[1] + p[2]
+ logging.debug('FOUND PSEUDO PAGE: {0}'.format(p[0]))
+
+
+ ##########################################################
+ ### At Rule: font-face
+
+ def p_font_face(self, p):
+ """font-face : FONT_FACE_SYM '{' declarations '}'"""
+ p[0] = reduce(lambda x, y: x+y, p[1:])
+ logging.debug('FOUND FONT FACE: {0}'.format(p[0]))
+
+
+ ##########################################################
+ ### At Rule: media query
+
+ def p_media(self, p):
+ """media : MEDIA_SYM media_query_list '{' ruleset '}'
+ | MEDIA_SYM media_query_list '{' '}'
+ | MEDIA_SYM '{' '}'
+ """
+ p[0] = reduce(lambda x, y: x+y, p[1:])
+ logging.debug('FOUND MEDIA LIST: {0}'.format(p[0]))
+
+ def p_media_query_list(self, p):
+ """media_query_list : media_query ',' media_query_list
+ | media_query
+ """
+ p[0] = reduce(lambda x, y: x+y, p[1:])
+ logging.debug('FOUND MEDIA LIST: {0}'.format(p[0]))
+
+ def p_media_query(self, p):
+ """media_query : ONLY media_expressions
+ | NOT media_expressions
+ | media_expressions
+ """
+ p[0] = reduce(lambda x, y: x+y, p[1:])
+ logging.debug('FOUND MEDIA QUERY: {0}'.format(p[0]))
+
+ def p_media_expressions(self, p):
+ """media_expressions : media_expression AND media_expressions
+ | media_expression
+ """
+ p[0] = reduce(lambda x, y: x+y, p[1:])
+ logging.debug('FOUND MEDIA EXPRESSIONS: {0}'.format(p[0]))
+
+ def p_media_expression(self, p):
+ """media_expression : '(' IDENT ':' expr ')'
+ | '(' IDENT ')'
+ | IDENT
+ """
+ p[0] = reduce(lambda x, y: x+y, p[1:])
+ logging.debug('FOUND MEDIA EXPRESSION: {0}'.format(p[0]))
+
+ def p_expr(self, p):
+ """expr : helper expr
+ | helper
+ """
+ p[0] = reduce(lambda x, y: x+y, p[1:])
+ logging.debug('FOUND EXPR: {0}'.format(p[0]))
+
+ def p_helper(self, p):
+ """helper : ',' term
+ | '\' term
+ | term
+ """
+ p[0] = reduce(lambda x, y: x+y, p[1:])
+ logging.debug('FOUND HELPER: {0}'.format(p[0]))
+
+
+ def p_unary_operator(self, p):
+ """unary_operator : '+'
+ | '-'
+ |
+ """
+ p[0] = p[1]
+ logging.debug('FOUND UNARY OPERATOR: {0}'.format(p[0]))
+
+ def p_term(self, p):
+ """term : unary_operator NUMBER
+ | unary_operator PERCENTAGE
+ | unary_operator DIMENSION
+ | STRING
+ | IDENT
+ | URI
+ | function
+ """
+ p[0] = reduce(lambda x, y: x+y, p[1:])
+ logging.debug('FOUND TERM: {0}'.format(p[0]))
+
+ def p_function(self, p):
+ """function : FUNCTION expr ')'"""
+ p[0] = reduce(lambda x, y: x+y, p[1:])
+ logging.debug('FOUND TERM: {0}'.format(p[0]))
+
+
+ ##########################################################
+ ### Ruleset
def p_ruleset(self, p):
"""ruleset : selector_group '{' declarations '}'
@@ -89,7 +216,6 @@ def p_declaration(self, p):
p[0] = reduce(lambda x, y: x+y, p[1:])
logging.debug('FOUND DECLARATION: {0}'.format(p[0]))
-
def p_property(self, p):
"""property : IDENT"""
p[0] = p[1]
@@ -269,7 +395,7 @@ def p_expression(self, p):
logging.debug('FOUND EXPRESSION {0}'.format(p[0]))
def p_negation(self, p):
- """negation : ':' NOT negation_arg ')'"""
+ """negation : ':' NOTFUNC negation_arg ')'"""
p[0] = reduce(lambda x, y: x+y, p[1:])
logging.debug('FOUND NEGATION: {0}'.format(p[0]))

No commit comments for this range

Something went wrong with that request. Please try again.