<s> from __future__ import absolute_import <EOL> from . lexer import Lexer <EOL> from . import nodes <EOL> import six <EOL> class Parser ( object ) : <EOL> def __init__ ( self , str , filename = None , ** options ) : <EOL> self . input = str <EOL> self . lexer = Lexer ( str , ** options ) <EOL> self . filename = filename <EOL> self . bloks = { } <EOL> self . options = options <EOL> self . contexts = [ self ] <EOL> self . extending = False <EOL> self . _spaces = None <EOL> def context ( self , parser ) : <EOL> if parser : self . context . append ( parser ) <EOL> else : self . contexts . pop ( ) <EOL> def advance ( self ) : <EOL> return self . lexer . advance ( ) <EOL> def skip ( self , n ) : <EOL> while n > <NUM_LIT:1> : <EOL> self . advance ( ) <EOL> n -= <NUM_LIT:1> <EOL> def peek ( self ) : <EOL> p = self . lookahead ( <NUM_LIT:1> ) <EOL> return p <EOL> def line ( self ) : <EOL> return self . lexer . lineno <EOL> def lookahead ( self , n ) : <EOL> return self . lexer . lookahead ( n ) <EOL> def parse ( self ) : <EOL> block = nodes . Block ( ) <EOL> parser = None <EOL> block . line = self . line ( ) <EOL> while '<STR_LIT>' != self . peek ( ) . type : <EOL> if '<STR_LIT>' == self . peek ( ) . type : self . advance ( ) <EOL> else : block . append ( self . parseExpr ( ) ) <EOL> parser = self . extending <EOL> if parser : <EOL> self . context ( parser ) <EOL> ast = parser . parse ( ) <EOL> self . context ( ) <EOL> return ast <EOL> return block <EOL> def expect ( self , type ) : <EOL> t = self . peek ( ) . type <EOL> if t == type : return self . advance ( ) <EOL> else : <EOL> raise Exception ( '<STR_LIT>' % <EOL> ( type , t , self . filename , self . line ( ) ) ) <EOL> def accept ( self , type ) : <EOL> if self . peek ( ) . type == type : return self . advance ( ) <EOL> def parseExpr ( self ) : <EOL> t = self . peek ( ) . type <EOL> if '<STR_LIT>' == t : <EOL> self . advance ( ) <EOL> block = nodes . Block ( ) <EOL> block . _yield = True <EOL> return block <EOL> elif t in ( '<STR_LIT:id>' , '<STR_LIT:class>' ) : <EOL> tok = self . advance ( ) <EOL> new_div = self . lexer . tok ( '<STR_LIT>' , '<STR_LIT>' ) <EOL> new_div . inline_level = tok . inline_level <EOL> self . lexer . stash . append ( new_div ) <EOL> self . lexer . stash . append ( tok ) <EOL> return self . parseExpr ( ) <EOL> funcName = '<STR_LIT>' % t . capitalize ( ) <EOL> if hasattr ( self , funcName ) : <EOL> return getattr ( self , funcName ) ( ) <EOL> else : <EOL> raise Exception ( '<STR_LIT>' % <EOL> ( t , self . filename , self . line ( ) ) ) <EOL> def parseString ( self ) : <EOL> tok = self . expect ( '<STR_LIT:string>' ) <EOL> node = nodes . String ( tok . val , inline = tok . inline_level > <NUM_LIT:0> ) <EOL> node . line = self . line ( ) <EOL> return node <EOL> def parseText ( self ) : <EOL> tok = self . expect ( '<STR_LIT:text>' ) <EOL> node = nodes . Text ( tok . val ) <EOL> node . line = self . line ( ) <EOL> return node <EOL> def parseBlockExpansion ( self ) : <EOL> if '<STR_LIT::>' == self . peek ( ) . type : <EOL> self . advance ( ) <EOL> return nodes . Block ( self . parseExpr ( ) ) <EOL> else : <EOL> return self . block ( ) <EOL> def parseAssignment ( self ) : <EOL> tok = self . expect ( '<STR_LIT>' ) <EOL> return nodes . Assignment ( tok . name , tok . val ) <EOL> def parseCode ( self ) : <EOL> tok = self . expect ( '<STR_LIT:code>' ) <EOL> node = nodes . Code ( tok . val , tok . buffer , tok . escape ) <EOL> block , i = None , <NUM_LIT:1> <EOL> node . line = self . line ( ) <EOL> while self . lookahead ( i ) and '<STR_LIT>' == self . lookahead ( i ) . type : <EOL> i += <NUM_LIT:1> <EOL> block = '<STR_LIT>' == self . lookahead ( i ) . type <EOL> if block : <EOL> self . skip ( i - <NUM_LIT:1> ) <EOL> node . block = self . block ( ) <EOL> return node <EOL> def parseComment ( self ) : <EOL> tok = self . expect ( '<STR_LIT>' ) <EOL> if '<STR_LIT>' == self . peek ( ) . type : <EOL> node = nodes . BlockComment ( tok . val , self . block ( ) , tok . buffer ) <EOL> else : <EOL> node = nodes . Comment ( tok . val , tok . buffer ) <EOL> node . line = self . line ( ) <EOL> return node <EOL> def parseDoctype ( self ) : <EOL> tok = self . expect ( '<STR_LIT>' ) <EOL> node = nodes . Doctype ( tok . val ) <EOL> node . line = self . line ( ) <EOL> return node <EOL> def parseFilter ( self ) : <EOL> tok = self . expect ( '<STR_LIT>' ) <EOL> attrs = self . accept ( '<STR_LIT>' ) <EOL> self . lexer . pipeless = True <EOL> block = self . parseTextBlock ( ) <EOL> self . lexer . pipeless = False <EOL> node = nodes . Filter ( tok . val , block , attrs and attrs . attrs ) <EOL> node . line = self . line ( ) <EOL> return node <EOL> def parseASTFilter ( self ) : <EOL> tok = self . expect ( '<STR_LIT>' ) <EOL> attrs = self . accept ( '<STR_LIT>' ) <EOL> self . expect ( '<STR_LIT::>' ) <EOL> block = self . block ( ) <EOL> node = nodes . Filter ( tok . val , block , attrs and attrs . attrs ) <EOL> node . line = self . line ( ) <EOL> return node <EOL> def parseEach ( self ) : <EOL> tok = self . expect ( '<STR_LIT>' ) <EOL> node = nodes . Each ( tok . code , tok . keys ) <EOL> node . line = self . line ( ) <EOL> node . block = self . block ( ) <EOL> return node <EOL> def parseConditional ( self ) : <EOL> tok = self . expect ( '<STR_LIT>' ) <EOL> node = nodes . Conditional ( tok . val , tok . sentence ) <EOL> node . line = self . line ( ) <EOL> node . block = self . block ( ) <EOL> while True : <EOL> t = self . peek ( ) <EOL> if '<STR_LIT>' == t . type and node . can_append ( t . val ) : <EOL> node . append ( self . parseConditional ( ) ) <EOL> else : <EOL> break <EOL> return node <EOL> def parseExtends ( self ) : <EOL> path = self . expect ( '<STR_LIT>' ) . val . strip ( '<STR_LIT>' ) <EOL> return nodes . Extends ( path ) <EOL> def parseCall ( self ) : <EOL> tok = self . expect ( '<STR_LIT>' ) <EOL> name = tok . val <EOL> args = tok . args <EOL> if args is None : <EOL> args = "<STR_LIT>" <EOL> block = self . block ( ) if '<STR_LIT>' == self . peek ( ) . type else None <EOL> return nodes . Mixin ( name , args , block , True ) <EOL> def parseMixin ( self ) : <EOL> tok = self . expect ( '<STR_LIT>' ) <EOL> name = tok . val <EOL> args = tok . args <EOL> if args is None : <EOL> args = "<STR_LIT>" <EOL> block = self . block ( ) if '<STR_LIT>' == self . peek ( ) . type else None <EOL> return nodes . Mixin ( name , args , block , block is None ) <EOL> def parseBlock ( self ) : <EOL> block = self . expect ( '<STR_LIT>' ) <EOL> mode = block . mode <EOL> name = block . val . strip ( ) <EOL> block = self . block ( cls = nodes . CodeBlock ) if '<STR_LIT>' == self . peek ( ) . type else nodes . CodeBlock ( nodes . Literal ( '<STR_LIT>' ) ) <EOL> block . mode = mode <EOL> block . name = name <EOL> return block <EOL> def parseInclude ( self ) : <EOL> path = self . expect ( '<STR_LIT>' ) . val . strip ( ) <EOL> return nodes . Include ( path ) <EOL> def parseTextBlock ( self , tag = None ) : <EOL> text = nodes . Text ( ) <EOL> text . line = self . line ( ) <EOL> if ( tag ) : <EOL> text . parent == tag <EOL> spaces = self . expect ( '<STR_LIT>' ) . val <EOL> if not self . _spaces : self . _spaces = spaces <EOL> indent = '<STR_LIT:U+0020>' * ( spaces - self . _spaces ) <EOL> while '<STR_LIT>' != self . peek ( ) . type : <EOL> t = self . peek ( ) . type <EOL> if '<STR_LIT>' == t : <EOL> text . append ( '<STR_LIT:\n>' ) <EOL> self . advance ( ) <EOL> elif '<STR_LIT>' == t : <EOL> text . append ( '<STR_LIT:\n>' ) <EOL> for node in self . parseTextBlock ( ) . nodes : text . append ( node ) <EOL> text . append ( '<STR_LIT:\n>' ) <EOL> else : <EOL> text . append ( indent + self . advance ( ) . val ) <EOL> if spaces == self . _spaces : self . _spaces = None <EOL> self . expect ( '<STR_LIT>' ) <EOL> return text <EOL> def block ( self , cls = nodes . Block ) : <EOL> block = cls ( ) <EOL> block . line = self . line ( ) <EOL> self . expect ( '<STR_LIT>' ) <EOL> while '<STR_LIT>' != self . peek ( ) . type : <EOL> if '<STR_LIT>' == self . peek ( ) . type : <EOL> self . advance ( ) <EOL> else : <EOL> block . append ( self . parseExpr ( ) ) <EOL> self . expect ( '<STR_LIT>' ) <EOL> return block <EOL> def processInline ( self , current_tag , current_level ) : <EOL> next_level = current_level + <NUM_LIT:1> <EOL> while self . peek ( ) . inline_level == next_level : <EOL> current_tag . block . append ( self . parseExpr ( ) ) <EOL> if self . peek ( ) . inline_level > next_level : <EOL> self . processInline ( current_tag , next_level ) <EOL> def processTagText ( self , tag ) : <EOL> if self . peek ( ) . inline_level < tag . inline_level : <EOL> return <EOL> if not self . lookahead ( <NUM_LIT:2> ) . inline_level > tag . inline_level : <EOL> tag . text = self . parseText ( ) <EOL> return <EOL> while self . peek ( ) . inline_level == tag . inline_level and self . peek ( ) . type == '<STR_LIT:string>' : <EOL> tag . block . append ( self . parseExpr ( ) ) <EOL> if self . peek ( ) . inline_level > tag . inline_level : <EOL> self . processInline ( tag , tag . inline_level ) <EOL> def parseTag ( self ) : <EOL> i = <NUM_LIT:2> <EOL> if '<STR_LIT>' == self . lookahead ( i ) . type : i += <NUM_LIT:1> <EOL> if '<STR_LIT::>' == self . lookahead ( i ) . type : <EOL> if '<STR_LIT>' == self . lookahead ( i + <NUM_LIT:1> ) . type : <EOL> raise Exception ( '<STR_LIT>' % <EOL> ( self . filename , self . line ( ) ) ) <EOL> tok = self . advance ( ) <EOL> tag = nodes . Tag ( tok . val , buffer = tok . val [ <NUM_LIT:0> ] == '<STR_LIT:#>' ) <EOL> tag . inline_level = tok . inline_level <EOL> dot = None <EOL> tag . line = self . line ( ) <EOL> while True : <EOL> t = self . peek ( ) . type <EOL> if t in ( '<STR_LIT:id>' , '<STR_LIT:class>' ) : <EOL> tok = self . advance ( ) <EOL> tag . setAttribute ( tok . type , '<STR_LIT>' % tok . val , True ) <EOL> continue <EOL> elif '<STR_LIT>' == t : <EOL> tok = self . advance ( ) <EOL> for n , v in six . iteritems ( tok . attrs ) : <EOL> tag . setAttribute ( n , v , n in tok . static_attrs ) <EOL> continue <EOL> else : <EOL> break <EOL> v = self . peek ( ) . val <EOL> if '<STR_LIT:.>' == v : <EOL> dot = tag . textOnly = True <EOL> self . advance ( ) <EOL> elif '<STR_LIT:<>' == v : <EOL> tag . inline = True <EOL> self . advance ( ) <EOL> t = self . peek ( ) . type <EOL> if '<STR_LIT:code>' == t : tag . code = self . parseCode ( ) <EOL> elif '<STR_LIT::>' == t : <EOL> self . advance ( ) <EOL> tag . block = nodes . Block ( ) <EOL> tag . block . append ( self . parseExpr ( ) ) <EOL> elif '<STR_LIT:string>' == t : self . processTagText ( tag ) <EOL> elif '<STR_LIT:text>' == t : tag . text = self . parseText ( ) <EOL> while '<STR_LIT>' == self . peek ( ) . type : self . advance ( ) <EOL> if '<STR_LIT>' == self . peek ( ) . type : <EOL> if tag . textOnly : <EOL> self . lexer . pipeless = True <EOL> tag . block = self . parseTextBlock ( tag ) <EOL> self . lexer . pipeless = False <EOL> else : <EOL> block = self . block ( ) <EOL> if tag . block : <EOL> for node in block . nodes : <EOL> tag . block . append ( node ) <EOL> else : <EOL> tag . block = block <EOL> return tag </s>
