Commits

Victor Kotseruba committed 734a96d

parse_sass function

Comments (0)

Files changed (1)

 from pyparsing import *
 import pprint
 
-__all__ = ('get_sass_parser', )
+__all__ = ('parse_sass', )
 
 ParserElement.setDefaultWhitespaceChars(' ')
 
 def get_sass_parser():
     
-    def strip_name(s, loc, toks):
-        return toks[0].strip('!:= ')
+    def parser():
     
-    stack = [1]
+        def strip_name(s, loc, toks):
+            return toks[0].strip('!:= ')
     
-    # common
-    NAME = Word(alphas + '-')
-    ENDL = LineEnd().suppress()
-    LPAR = Suppress('(')
-    RPAR = Suppress(')')
+        stack = [1]
     
-    # expressions
-    NUMBER = Regex(r'-?\d+(?:\.\d+)?(?:px|em|pt|%)?').setResultsName('number')
-    OPERATOR = (Literal('+') | Literal('-') | Literal('/') | Literal('*') | Literal('==')).setResultsName('operator')
-    STRING = (QuotedString(quoteChar='"') | QuotedString(quoteChar="'")).setResultsName('string')
-    VARIABLE = Regex(r'![\w-]+').addParseAction(strip_name).setResultsName('variable')
-    EXPRESSION = Forward()
-    ATOM = (NUMBER | VARIABLE | STRING) | (LPAR + Group(EXPRESSION) + RPAR)
-    EXPRESSION << ATOM + ZeroOrMore(OPERATOR + ATOM)
+        # common
+        NAME = Word(alphas + '-')
+        ENDL = LineEnd().suppress()
+        LPAR = Suppress('(')
+        RPAR = Suppress(')')
     
-    # properties
-    PROP_KEY= Regex(r'(?::[\w-]+|[\w-]+:)').addParseAction(strip_name)
-    PROP = Group(PROP_KEY + White(' ').suppress() + Group(OneOrMore(Word(printables)))) + ENDL
-    PROP_KEY_EXPR = Regex(r':?[\w-]+').addParseAction(strip_name)
-    PROP_EXPR = Group(PROP_KEY_EXPR + White(' ').suppress() + Suppress('=') + EXPRESSION) + ENDL
-    PROP_PREFIX = (Suppress(':') + Word(alphas + '-')) | (Word(alphas + '-') + Suppress(':')) + ENDL
-    PREFIX_NODE = Forward()
-    prefix_node_suit = PROP_EXPR | PROP | LineEnd().suppress()
-    PREFIX_NODE << Group(PROP_PREFIX + indentedBlock(prefix_node_suit, stack)).setResultsName('prefix-node')
+        # expressions
+        NUMBER = Regex(r'-?\d+(?:\.\d+)?(?:px|em|pt|%)?').setResultsName('number')
+        OPERATOR = (Literal('+') | Literal('-') | Literal('/') | Literal('*') | Literal('==')).setResultsName('operator')
+        STRING = (QuotedString(quoteChar='"') | QuotedString(quoteChar="'")).setResultsName('string')
+        VARIABLE = Regex(r'![\w-]+').addParseAction(strip_name).setResultsName('variable')
+        EXPRESSION = Forward()
+        ATOM = (NUMBER | VARIABLE | STRING) | (LPAR + Group(EXPRESSION) + RPAR)
+        EXPRESSION << ATOM + ZeroOrMore(OPERATOR + ATOM)
     
-    SELECTOR_NODE = Forward()
-    CONTROL = Forward()
+        # properties
+        PROP_KEY= Regex(r'(?::[\w-]+|[\w-]+:)').addParseAction(strip_name)
+        PROP = Group(PROP_KEY + White(' ').suppress() + Group(OneOrMore(Word(printables)))) + ENDL
+        PROP_KEY_EXPR = Regex(r':?[\w-]+').addParseAction(strip_name)
+        PROP_EXPR = Group(PROP_KEY_EXPR + White(' ').suppress() + Suppress('=') + EXPRESSION) + ENDL
+        PROP_PREFIX = (Suppress(':') + Word(alphas + '-')) | (Word(alphas + '-') + Suppress(':')) + ENDL
+        PREFIX_NODE = Forward()
+        prefix_node_suit = PROP_EXPR | PROP | LineEnd().suppress()
+        PREFIX_NODE << Group(PROP_PREFIX + indentedBlock(prefix_node_suit, stack)).setResultsName('prefix-node')
     
-    # mixins
-    ARG = VARIABLE
-    ARG_WITH_DEFAULTS = Group(VARIABLE + Suppress('=') + EXPRESSION)
-    ARGS = ZeroOrMore(ARG + Suppress(',')) + ARG
-    MIXIN_USE = Suppress('+') + NAME + Optional(LPAR + Optional(Group(EXPRESSION) + ZeroOrMore(Suppress(',') + Group(EXPRESSION))) + RPAR) + ENDL
-    MIXIN_DEF = Suppress('=') + NAME + Group(Optional(LPAR + Optional(ARGS) + RPAR)) + ENDL
-    MIXIN_NODE = Forward()
+        SELECTOR_NODE = Forward()
+        CONTROL = Forward()
     
-    # selectors
-    SELECTOR = Regex(r'(?!(?::|[\w-]:[^\w])).+') + ENDL
-    selector_node_suit = LineEnd().suppress() | PROP_EXPR | PROP | PREFIX_NODE | MIXIN_USE | CONTROL | SELECTOR_NODE
+        # mixins
+        ARG = VARIABLE
+        ARG_WITH_DEFAULTS = Group(VARIABLE + Suppress('=') + EXPRESSION)
+        ARGS = ZeroOrMore(ARG + Suppress(',')) + ARG
+        MIXIN_USE = Suppress('+') + NAME + Optional(LPAR + Optional(Group(EXPRESSION) + ZeroOrMore(Suppress(',') + Group(EXPRESSION))) + RPAR) + ENDL
+        MIXIN_DEF = Suppress('=') + NAME + Group(Optional(LPAR + Optional(ARGS) + RPAR)) + ENDL
+        MIXIN_NODE = Forward()
     
-    # control directives
-    FOR = Keyword('@for') + VARIABLE + Keyword('from') + EXPRESSION + (Keyword('to') | Keyword('through')) + EXPRESSION + ENDL
-    FOR_NODE = Group(FOR + indentedBlock(selector_node_suit, stack)).setResultsName('for-node')
-    IF = Keyword('@if') + EXPRESSION + ENDL
-    ELSE = Keyword('@else') + ENDL
-    ELSE_IF = Keyword('@else') + Keyword('if') + EXPRESSION + ENDL
-    ELSE_NODE = Group(ELSE + indentedBlock(selector_node_suit, stack)).setResultsName('else-node')
-    ELSE_IF_NODE = Group(ELSE_IF + indentedBlock(selector_node_suit, stack)).setResultsName('else-if-node')
-    IF_NODE = Group(IF + indentedBlock(selector_node_suit, stack)  + ZeroOrMore(ELSE_IF_NODE) + Optional(ELSE_NODE))
-    CONTROL << (FOR_NODE | IF_NODE)
+        # selectors
+        SELECTOR = Regex(r'(?!(?::|[\w-]:[^\w])).+') + ENDL
+        selector_node_suit = LineEnd().suppress() | PROP_EXPR | PROP | PREFIX_NODE | MIXIN_USE | CONTROL | SELECTOR_NODE
     
-    # nodes
-    SELECTOR_NODE << Group(SELECTOR + indentedBlock(selector_node_suit, stack)).setResultsName('selector-node')
-    MIXIN_NODE << Group(MIXIN_DEF + indentedBlock(selector_node_suit, stack)).setResultsName('mixin-node')
-    suite = OneOrMore(ENDL | MIXIN_NODE | CONTROL | SELECTOR_NODE)
+        # control directives
+        FOR = Keyword('@for') + VARIABLE + Keyword('from') + EXPRESSION + (Keyword('to') | Keyword('through')) + EXPRESSION + ENDL
+        FOR_NODE = Group(FOR + indentedBlock(selector_node_suit, stack)).setResultsName('for-node')
+        IF = Keyword('@if') + EXPRESSION + ENDL
+        ELSE = Keyword('@else') + ENDL
+        ELSE_IF = Keyword('@else') + Keyword('if') + EXPRESSION + ENDL
+        ELSE_NODE = Group(ELSE + indentedBlock(selector_node_suit, stack)).setResultsName('else-node')
+        ELSE_IF_NODE = Group(ELSE_IF + indentedBlock(selector_node_suit, stack)).setResultsName('else-if-node')
+        IF_NODE = Group(IF + indentedBlock(selector_node_suit, stack)  + ZeroOrMore(ELSE_IF_NODE) + Optional(ELSE_NODE))
+        CONTROL << (FOR_NODE | IF_NODE)
     
-    return suite
+        # nodes
+        SELECTOR_NODE << Group(SELECTOR + indentedBlock(selector_node_suit, stack)).setResultsName('selector-node')
+        MIXIN_NODE << Group(MIXIN_DEF + indentedBlock(selector_node_suit, stack)).setResultsName('mixin-node')
+        suite = OneOrMore(ENDL | MIXIN_NODE | CONTROL | SELECTOR_NODE)
+        
+        return suite
+    
+    def parse(string):
+        return parser().parseString(string)
+            
+    return parse
+
+
+parse_sass = get_sass_parser()
 
 
 if __name__ == '__main__':
 
-    tree = get_sass_parser().parseString("""
+    tree = parse_sass("""
 
 @for !i from 1 to 2
     .test-#{!i}
     .page.active
         +test(1, 2, 3, 4)
         +empty(45px + "123123")
-    
+
 """)
 
     pprint.PrettyPrinter(indent=2).pprint(tree.asList())