"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "Cheetah/Parser.py" between
cheetah3-3.1.0.tar.gz and cheetah3-3.2.0.tar.gz

About: Cheetah3 is a template engine and code generation tool for e.g. for Web development or Java, SQL, LaTeX, form email ... (written in Python).

Parser.py  (cheetah3-3.1.0):Parser.py  (cheetah3-3.2.0)
skipping to change at line 42 skipping to change at line 42
_regexCache[pattern] = re.compile(pattern) _regexCache[pattern] = re.compile(pattern)
return _regexCache[pattern] return _regexCache[pattern]
def escapeRegexChars(txt, def escapeRegexChars(txt,
escapeRE=re.compile(r'([\$\^\*\+\.\?\{\}\[\]\(\)\|\\])')): escapeRE=re.compile(r'([\$\^\*\+\.\?\{\}\[\]\(\)\|\\])')):
"""Return a txt with all special regular expressions chars escaped.""" """Return a txt with all special regular expressions chars escaped."""
return escapeRE.sub(r'\\\1', txt) return escapeRE.sub(r'\\\1', txt)
def group(*choices): return '(' + '|'.join(choices) + ')' def group(*choices):
return '(' + '|'.join(choices) + ')'
def nongroup(*choices): return '(?:' + '|'.join(choices) + ')' def nongroup(*choices):
return '(?:' + '|'.join(choices) + ')'
def namedGroup(name, *choices): def namedGroup(name, *choices):
return '(P:<' + name + '>' + '|'.join(choices) + ')' return '(P:<' + name + '>' + '|'.join(choices) + ')'
def any(*choices): return group(*choices) + '*' def any(*choices):
return group(*choices) + '*'
def maybe(*choices): return group(*choices) + '?' def maybe(*choices):
return group(*choices) + '?'
################################################## ##################################################
# CONSTANTS & GLOBALS ## # CONSTANTS & GLOBALS ##
NO_CACHE = 0 NO_CACHE = 0
STATIC_CACHE = 1 STATIC_CACHE = 1
REFRESH_CACHE = 2 REFRESH_CACHE = 2
SET_LOCAL = 0 SET_LOCAL = 0
SET_GLOBAL = 1 SET_GLOBAL = 1
SET_MODULE = 2 SET_MODULE = 2
################################################## ##################################################
# Tokens for the parser ## # Tokens for the parser ##
# generic # generic
identchars = "abcdefghijklmnopqrstuvwxyz" \ identchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ_"
namechars = identchars + "0123456789" namechars = identchars + "0123456789"
# operators # operators
powerOp = '**' powerOp = '**'
unaryArithOps = ('+', '-', '~') unaryArithOps = ('+', '-', '~')
binaryArithOps = ('+', '-', '/', '//', '%') binaryArithOps = ('+', '-', '/', '//', '%')
shiftOps = ('>>', '<<') shiftOps = ('>>', '<<')
bitwiseOps = ('&', '|', '^') bitwiseOps = ('&', '|', '^')
assignOp = '=' assignOp = '='
augAssignOps = ('+=', '-=', '/=', '*=', '**=', '^=', '%=', augAssignOps = ('+=', '-=', '/=', '*=', '**=', '^=', '%=',
'>>=', '<<=', '&=', '|=', ) '>>=', '<<=', '&=', '|=', )
assignmentOps = (assignOp,) + augAssignOps assignmentOps = (assignOp,) + augAssignOps
compOps = ('<', '>', '==', '!=', '<=', '>=', '<>', 'is', 'in',) compOps = ('<', '>', '==', '!=', '<=', '>=', '<>', 'is', 'in',)
booleanOps = ('and', 'or', 'not') booleanOps = ('and', 'or', 'not')
operators = (powerOp,) + unaryArithOps + binaryArithOps \ operators = (powerOp,) + unaryArithOps + binaryArithOps \
+ shiftOps + bitwiseOps + assignmentOps \ + shiftOps + bitwiseOps + assignmentOps \
+ compOps + booleanOps + compOps + booleanOps
delimeters = ('(', ')', '{', '}', '[', ']', delimeters = ('(', ')', '{', '}', '[', ']',
',', '.', ':', ';', '=', '`') + augAssignOps ',', '.', ':', ';', '=', '`') + augAssignOps
keywords = ('and', 'del', 'for', 'is', 'raise', keywords = ('and', 'del', 'for', 'is', 'raise', # noq
'assert', 'elif', 'from', 'lambda', 'return', a: E241,E501 multiple spaces after ','
'break', 'else', 'global', 'not', 'try', 'assert', 'elif', 'from', 'lambda', 'return', # noq
'class', 'except', 'if', 'or', 'while', a: E241,E501 multiple spaces after ','
'continue', 'exec', 'import', 'pass', 'break', 'else', 'global', 'not', 'try', # noq
'def', 'finally', 'in', 'print', a: E241,E501 multiple spaces after ','
'class', 'except', 'if', 'or', 'while', # noq
a: E241,E501 multiple spaces after ','
'continue', 'exec', 'import', 'pass', # noq
a: E241,E501 multiple spaces after ','
'def', 'finally', 'in', 'print', # noq
a: E241,E501 multiple spaces after ','
) )
single3 = "'''" single3 = "'''"
double3 = '"""' double3 = '"""'
tripleQuotedStringStarts = ("'''", '"""', tripleQuotedStringStarts = ("'''", '"""',
"r'''", 'r"""', "R'''", 'R"""', "r'''", 'r"""', "R'''", 'R"""',
"u'''", 'u"""', "U'''", 'U"""', "u'''", 'u"""', "U'''", 'U"""',
"ur'''", 'ur"""', "Ur'''", 'Ur"""', "ur'''", 'ur"""', "Ur'''", 'Ur"""',
"uR'''", 'uR"""', "UR'''", 'UR"""') "uR'''", 'uR"""', "UR'''", 'UR"""')
skipping to change at line 227 skipping to change at line 230
# intructions to the parser and compiler # intructions to the parser and compiler
'breakpoint': 'eatBreakPoint', 'breakpoint': 'eatBreakPoint',
'compiler': 'eatCompiler', 'compiler': 'eatCompiler',
'compiler-settings': 'eatCompilerSettings', 'compiler-settings': 'eatCompilerSettings',
# misc # misc
'shBang': 'eatShbang', 'shBang': 'eatShbang',
'encoding': 'eatEncoding', 'encoding': 'eatEncoding',
'end': 'eatEndDirective', 'end': 'eatEndDirective',
} }
endDirectiveNamesAndHandlers = { endDirectiveNamesAndHandlers = {
'def': 'handleEndDef', # has short-form 'def': 'handleEndDef', # has short-form
'block': None, # has short-form 'block': None, # has short-form
'closure': None, # has short-form 'closure': None, # has short-form
'cache': None, # has short-form 'cache': None, # has short-form
'call': None, # has short-form 'call': None, # has short-form
'capture': None, # has short-form 'capture': None, # has short-form
'filter': None, 'filter': None,
'errorCatcher': None, 'errorCatcher': None,
'while': None, # has short-form 'while': None, # has short-form
'for': None, # has short-form 'for': None, # has short-form
'if': None, # has short-form 'if': None, # has short-form
'try': None, # has short-form 'try': None, # has short-form
'repeat': None, # has short-form 'repeat': None, # has short-form
'unless': None, # has short-form 'unless': None, # has short-form
} }
################################################## ##################################################
# CLASSES ## # CLASSES ##
# @@TR: SyntaxError doesn't call exception.__str__ for some reason! # @@TR: SyntaxError doesn't call exception.__str__ for some reason!
# class ParseError(SyntaxError): # class ParseError(SyntaxError):
class ParseError(ValueError): class ParseError(ValueError):
def __init__(self, stream, msg='Invalid Syntax', extMsg='', def __init__(self, stream, msg='Invalid Syntax', extMsg='',
lineno=None, col=None): lineno=None, col=None):
skipping to change at line 276 skipping to change at line 279
def report(self): def report(self):
stream = self.stream stream = self.stream
if stream.filename(): if stream.filename():
f = " in file %s" % stream.filename() f = " in file %s" % stream.filename()
else: else:
f = '' f = ''
report = '' report = ''
if self.lineno: if self.lineno:
lineno = self.lineno lineno = self.lineno
row, col, line = (lineno, (self.col or 0), row, col, line = (lineno, (self.col or 0),
self.stream.splitlines()[lineno-1]) self.stream.splitlines()[lineno - 1])
else: else:
row, col, line = self.stream.getRowColLine() row, col, line = self.stream.getRowColLine()
# get the surrounding lines # get the surrounding lines
lines = stream.splitlines() lines = stream.splitlines()
prevLines = [] # (rowNum, content) prevLines = [] # (rowNum, content)
for i in range(1, 4): for i in range(1, 4):
if row - 1 - i <= 0: if row - 1 - i <= 0:
break break
prevLines.append((row-i, lines[row-1-i])) prevLines.append((row - i, lines[row - 1 - i]))
nextLines = [] # (rowNum, content) nextLines = [] # (rowNum, content)
for i in range(1, 4): for i in range(1, 4):
if not row-1+i < len(lines): if not row - 1 + i < len(lines):
break break
nextLines.append((row+i, lines[row-1+i])) nextLines.append((row + i, lines[row - 1 + i]))
nextLines.reverse() nextLines.reverse()
# print the main message # print the main message
report += "\n\n%s\n" % self.msg report += "\n\n%s\n" % self.msg
report += "Line %i, column %i%s\n\n" % (row, col, f) report += "Line %i, column %i%s\n\n" % (row, col, f)
report += 'Line|Cheetah Code\n' report += 'Line|Cheetah Code\n'
report += '----|-----------------------------' \ report += '----|-----------------------------' \
'--------------------------------\n' '--------------------------------\n'
while prevLines: while prevLines:
lineInfo = prevLines.pop() lineInfo = prevLines.pop()
report += "%(row)-4d|%(line)s\n" \ report += "%(row)-4d|%(line)s\n" \
% {'row': lineInfo[0], 'line': lineInfo[1]} % {'row': lineInfo[0], 'line': lineInfo[1]}
report += "%(row)-4d|%(line)s\n" % {'row': row, 'line': line} report += "%(row)-4d|%(line)s\n" % {'row': row, 'line': line}
report += ' '*5 + ' '*(col-1) + "^\n" report += ' '*5 + ' '*(col - 1) + "^\n" # noqa: E226,E501 missing white space around operator
while nextLines: while nextLines:
lineInfo = nextLines.pop() lineInfo = nextLines.pop()
report += "%(row)-4d|%(line)s\n" \ report += "%(row)-4d|%(line)s\n" \
% {'row': lineInfo[0], 'line': lineInfo[1]} % {'row': lineInfo[0], 'line': lineInfo[1]}
# add the extra msg # add the extra msg
if self.extMsg: if self.extMsg:
report += self.extMsg + '\n' report += self.extMsg + '\n'
return report return report
skipping to change at line 410 skipping to change at line 413
def configureParser(self): def configureParser(self):
"""Is called by the Compiler instance after the parser has had a """Is called by the Compiler instance after the parser has had a
settingsManager assigned with self.setSettingsManager() settingsManager assigned with self.setSettingsManager()
""" """
self._makeCheetahVarREs() self._makeCheetahVarREs()
self._makeCommentREs() self._makeCommentREs()
self._makeDirectiveREs() self._makeDirectiveREs()
self._makePspREs() self._makePspREs()
self._possibleNonStrConstantChars = ( self._possibleNonStrConstantChars = (
self.setting('commentStartToken')[0] + self.setting('commentStartToken')[0]
self.setting('multiLineCommentStartToken')[0] + + self.setting('multiLineCommentStartToken')[0]
self.setting('cheetahVarStartToken')[0] + + self.setting('cheetahVarStartToken')[0]
self.setting('directiveStartToken')[0] + + self.setting('directiveStartToken')[0]
self.setting('PSPStartToken')[0]) + self.setting('PSPStartToken')[0])
self._nonStrConstMatchers = [ self._nonStrConstMatchers = [
self.matchCommentStartToken, self.matchCommentStartToken,
self.matchMultiLineCommentStartToken, self.matchMultiLineCommentStartToken,
self.matchVariablePlaceholderStart, self.matchVariablePlaceholderStart,
self.matchExpressionPlaceholderStart, self.matchExpressionPlaceholderStart,
self.matchDirective, self.matchDirective,
self.matchPSPStartToken, self.matchPSPStartToken,
self.matchEOLSlurpToken, self.matchEOLSlurpToken,
] ]
# regex setup ## # regex setup ##
def _makeCheetahVarREs(self): def _makeCheetahVarREs(self):
"""Setup the regexs for Cheetah $var parsing.""" """Setup the regexs for Cheetah $var parsing."""
num = r'[0-9\.]+' num = r'[0-9\.]+'
interval = (r'(?P<interval>' + interval = (r'(?P<interval>'
num + r's|' + + num + r's|'
num + r'm|' + + num + r'm|'
num + r'h|' + + num + r'h|'
num + r'd|' + + num + r'd|'
num + r'w|' + + num + r'w|'
num + ')' + num + ')'
) )
cacheToken = (r'(?:' + cacheToken = (r'(?:'
r'(?P<REFRESH_CACHE>\*' + interval + '\*)' + + r'(?P<REFRESH_CACHE>\*' + interval + '\*)'
'|' + + '|'
r'(?P<STATIC_CACHE>\*)' + + r'(?P<STATIC_CACHE>\*)'
'|' + + '|'
r'(?P<NO_CACHE>)' + + r'(?P<NO_CACHE>)'
')') + ')')
self.cacheTokenRE = cachedRegex(cacheToken) self.cacheTokenRE = cachedRegex(cacheToken)
silentPlaceholderToken = (r'(?:' + silentPlaceholderToken = (r'(?:'
r'(?P<SILENT>' + escapeRegexChars('!')+')' + + r'(?P<SILENT>'
'|' + + escapeRegexChars('!') + ')'
r'(?P<NOT_SILENT>)' + + '|'
')') + r'(?P<NOT_SILENT>)'
+ ')')
self.silentPlaceholderTokenRE = cachedRegex(silentPlaceholderToken) self.silentPlaceholderTokenRE = cachedRegex(silentPlaceholderToken)
self.cheetahVarStartRE = cachedRegex( self.cheetahVarStartRE = cachedRegex(
escCharLookBehind + r'(?P<startToken>' + escCharLookBehind + r'(?P<startToken>'
escapeRegexChars(self.setting('cheetahVarStartToken')) + ')' + + escapeRegexChars(self.setting('cheetahVarStartToken')) + ')'
r'(?P<silenceToken>' + silentPlaceholderToken+')' + + r'(?P<silenceToken>' + silentPlaceholderToken + ')'
r'(?P<cacheToken>' + cacheToken + ')' + + r'(?P<cacheToken>' + cacheToken + ')'
# allow WS after enclosure # allow WS after enclosure
r'(?P<enclosure>|(?:(?:\{|\(|\[)[ \t\f]*))' + r'(?=[A-Za-z_])') + r'(?P<enclosure>|(?:(?:\{|\(|\[)[ \t\f]*))' + r'(?=[A-Za-z_])')
validCharsLookAhead = r'(?=[A-Za-z_\*!\{\(\[])' validCharsLookAhead = r'(?=[A-Za-z_\*!\{\(\[])'
self.cheetahVarStartToken = self.setting('cheetahVarStartToken') self.cheetahVarStartToken = self.setting('cheetahVarStartToken')
self.cheetahVarStartTokenRE = cachedRegex( self.cheetahVarStartTokenRE = cachedRegex(
escCharLookBehind + escCharLookBehind
escapeRegexChars(self.setting('cheetahVarStartToken')) + escapeRegexChars(self.setting('cheetahVarStartToken'))
+ validCharsLookAhead + validCharsLookAhead
) )
self.cheetahVarInExpressionStartTokenRE = cachedRegex( self.cheetahVarInExpressionStartTokenRE = cachedRegex(
escapeRegexChars(self.setting('cheetahVarStartToken')) escapeRegexChars(self.setting('cheetahVarStartToken'))
+ r'(?=[A-Za-z_])' + r'(?=[A-Za-z_])'
) )
self.expressionPlaceholderStartRE = cachedRegex( self.expressionPlaceholderStartRE = cachedRegex(
escCharLookBehind + r'(?P<startToken>' + escCharLookBehind + r'(?P<startToken>'
escapeRegexChars(self.setting('cheetahVarStartToken')) + ')' + + escapeRegexChars(self.setting('cheetahVarStartToken'))
r'(?P<cacheToken>' + cacheToken + ')' + + ')'
+ r'(?P<cacheToken>' + cacheToken + ')'
# r'\[[ \t\f]*' # r'\[[ \t\f]*'
r'(?:\{|\(|\[)[ \t\f]*' + r'(?=[^\)\}\]])') + r'(?:\{|\(|\[)[ \t\f]*' + r'(?=[^\)\}\]])')
if self.setting('EOLSlurpToken'): if self.setting('EOLSlurpToken'):
self.EOLSlurpRE = cachedRegex( self.EOLSlurpRE = cachedRegex(
escapeRegexChars(self.setting('EOLSlurpToken')) escapeRegexChars(self.setting('EOLSlurpToken'))
+ r'[ \t\f]*' + r'[ \t\f]*'
+ r'(?:'+EOL+')' + r'(?:' + EOL + ')'
) )
else: else:
self.EOLSlurpRE = None self.EOLSlurpRE = None
def _makeCommentREs(self): def _makeCommentREs(self):
"""Construct the regex bits that are used in comment parsing.""" """Construct the regex bits that are used in comment parsing."""
startTokenEsc = escapeRegexChars(self.setting('commentStartToken')) startTokenEsc = escapeRegexChars(self.setting('commentStartToken'))
self.commentStartTokenRE = cachedRegex( self.commentStartTokenRE = cachedRegex(
escCharLookBehind + startTokenEsc) escCharLookBehind + startTokenEsc)
del startTokenEsc del startTokenEsc
startTokenEsc = escapeRegexChars( startTokenEsc = escapeRegexChars(
self.setting('multiLineCommentStartToken')) self.setting('multiLineCommentStartToken'))
endTokenEsc = escapeRegexChars( endTokenEsc = escapeRegexChars(
self.setting('multiLineCommentEndToken')) self.setting('multiLineCommentEndToken'))
self.multiLineCommentTokenStartRE = cachedRegex(escCharLookBehind + self.multiLineCommentTokenStartRE = cachedRegex(
startTokenEsc) escCharLookBehind + startTokenEsc)
self.multiLineCommentEndTokenRE = cachedRegex(escCharLookBehind + self.multiLineCommentEndTokenRE = cachedRegex(
endTokenEsc) escCharLookBehind + endTokenEsc)
def _makeDirectiveREs(self): def _makeDirectiveREs(self):
"""Construct the regexs that are used in directive parsing.""" """Construct the regexs that are used in directive parsing."""
startToken = self.setting('directiveStartToken') startToken = self.setting('directiveStartToken')
endToken = self.setting('directiveEndToken') endToken = self.setting('directiveEndToken')
startTokenEsc = escapeRegexChars(startToken) startTokenEsc = escapeRegexChars(startToken)
endTokenEsc = escapeRegexChars(endToken) endTokenEsc = escapeRegexChars(endToken)
validSecondCharsLookAhead = r'(?=[A-Za-z_@])' validSecondCharsLookAhead = r'(?=[A-Za-z_@])'
reParts = [escCharLookBehind, startTokenEsc] reParts = [escCharLookBehind, startTokenEsc]
if self.setting('allowWhitespaceAfterDirectiveStartToken'): if self.setting('allowWhitespaceAfterDirectiveStartToken'):
skipping to change at line 728 skipping to change at line 733
"""Returns False or the name of the directive matched. """Returns False or the name of the directive matched.
""" """
startPos = self.pos() startPos = self.pos()
if not self.matchDirectiveStartToken(): if not self.matchDirectiveStartToken():
return False return False
self.getDirectiveStartToken() self.getDirectiveStartToken()
directiveName = self.matchDirectiveName() directiveName = self.matchDirectiveName()
self.setPos(startPos) self.setPos(startPos)
return directiveName return directiveName
def matchDirectiveName(self, directiveNameChars=identchars+'0123456789-@'): def matchDirectiveName(self,
directiveNameChars=identchars + '0123456789-@'):
startPos = self.pos() startPos = self.pos()
possibleMatches = self._directiveNamesAndParsers.keys() possibleMatches = self._directiveNamesAndParsers.keys()
name = '' name = ''
match = None match = None
while not self.atEnd(): while not self.atEnd():
c = self.getc() c = self.getc()
if c not in directiveNameChars: if c not in directiveNameChars:
break break
name += c name += c
skipping to change at line 775 skipping to change at line 781
return self.directiveEndTokenRE.match(self.src(), self.pos()) return self.directiveEndTokenRE.match(self.src(), self.pos())
def getDirectiveEndToken(self): def getDirectiveEndToken(self):
match = self.matchDirectiveEndToken() match = self.matchDirectiveEndToken()
if not match: if not match:
raise ParseError(self, msg='Invalid directive end token') raise ParseError(self, msg='Invalid directive end token')
return self.readTo(match.end()) return self.readTo(match.end())
def matchColonForSingleLineShortFormDirective(self): def matchColonForSingleLineShortFormDirective(self):
if not self.atEnd() and self.peek() == ':': if not self.atEnd() and self.peek() == ':':
restOfLine = self[self.pos()+1:self.findEOL()] restOfLine = self[self.pos()+1:self.findEOL()] # noqa: E226,E501 mi ssing whitespace around operator
restOfLine = restOfLine.strip() restOfLine = restOfLine.strip()
if not restOfLine: if not restOfLine:
return False return False
elif self.commentStartTokenRE.match(restOfLine): elif self.commentStartTokenRE.match(restOfLine):
return False return False
else: # non-whitespace, non-commment chars found else: # non-whitespace, non-commment chars found
return True return True
return False return False
def matchPSPStartToken(self): def matchPSPStartToken(self):
skipping to change at line 921 skipping to change at line 927
""" """
chunks = [] chunks = []
while self.pos() < len(self): while self.pos() < len(self):
rest = '' rest = ''
autoCall = True autoCall = True
if not self.peek() in identchars + '.': if not self.peek() in identchars + '.':
break break
elif self.peek() == '.': elif self.peek() == '.':
if self.pos()+1 < len(self) and self.peek(1) in identchars: if self.pos() + 1 < len(self) and self.peek(1) in identchars:
# discard the period as it isn't needed with NameMapper # discard the period as it isn't needed with NameMapper
self.advance() self.advance()
else: else:
break break
dottedName = self.getDottedName() dottedName = self.getDottedName()
if not self.atEnd() and self.peek() in '([': if not self.atEnd() and self.peek() in '([':
if self.peek() == '(': if self.peek() == '(':
rest = self.getCallArgString() rest = self.getCallArgString()
else: else:
rest = self.getExpression(enclosed=True) rest = self.getExpression(enclosed=True)
period = max(dottedName.rfind('.'), 0) period = max(dottedName.rfind('.'), 0)
if period: if period:
chunks.append((dottedName[:period], autoCall, '')) chunks.append((dottedName[:period], autoCall, ''))
dottedName = dottedName[period+1:] dottedName = dottedName[period+1:] # noqa: E226,E501 missin g whitespace around operator
if rest and rest[0] == '(': if rest and rest[0] == '(':
autoCall = False autoCall = False
chunks.append((dottedName, autoCall, rest)) chunks.append((dottedName, autoCall, rest))
return chunks return chunks
def getCallArgString(self, def getCallArgString(self,
# list of tuples (char, pos), where char is ( { or [ # list of tuples (char, pos), where char is ( { or [
enclosures=[], enclosures=[],
useNameMapper=Unspecified): useNameMapper=Unspecified):
skipping to change at line 978 skipping to change at line 984
argStringBits = ['('] argStringBits = ['(']
addBit = argStringBits.append addBit = argStringBits.append
while True: while True:
if self.atEnd(): if self.atEnd():
open = enclosures[-1][0] open = enclosures[-1][0]
close = closurePairsRev[open] close = closurePairsRev[open]
self.setPos(enclosures[-1][1]) self.setPos(enclosures[-1][1])
raise ParseError( raise ParseError(
self, msg="EOF was reached before a matching '" + close + self, msg="EOF was reached before a matching '" + close
"' was found for the '" + open + "'") + "' was found for the '" + open + "'")
c = self.peek() c = self.peek()
if c in ")}]": # get the ending enclosure and break if c in ")}]": # get the ending enclosure and break
if not enclosures: if not enclosures:
raise ParseError(self) raise ParseError(self)
c = self.getc() c = self.getc()
open = closurePairs[c] open = closurePairs[c]
if enclosures[-1][0] == open: if enclosures[-1][0] == open:
enclosures.pop() enclosures.pop()
addBit(')') addBit(')')
skipping to change at line 1147 skipping to change at line 1153
srcLen = len(self) srcLen = len(self)
exprBits = [] exprBits = []
while True: while True:
if self.atEnd(): if self.atEnd():
if enclosures: if enclosures:
open = enclosures[-1][0] open = enclosures[-1][0]
close = closurePairsRev[open] close = closurePairsRev[open]
self.setPos(enclosures[-1][1]) self.setPos(enclosures[-1][1])
raise ParseError( raise ParseError(
self, self,
msg="EOF was reached before a matching '" + close + msg="EOF was reached before a matching '" + close
"' was found for the '" + open + "'") + "' was found for the '" + open + "'")
else: else:
break break
c = self.peek() c = self.peek()
if c in "{([": if c in "{([":
exprBits.append(c) exprBits.append(c)
enclosures.append((c, self.pos())) enclosures.append((c, self.pos()))
self.advance() self.advance()
elif enclosed and not enclosures: elif enclosed and not enclosures:
break break
skipping to change at line 1173 skipping to change at line 1179
if enclosures[-1][0] == open: if enclosures[-1][0] == open:
enclosures.pop() enclosures.pop()
exprBits.append(c) exprBits.append(c)
else: else:
open = enclosures[-1][0] open = enclosures[-1][0]
close = closurePairsRev[open] close = closurePairsRev[open]
row, col = self.getRowCol() row, col = self.getRowCol()
self.setPos(enclosures[-1][1]) self.setPos(enclosures[-1][1])
raise ParseError( raise ParseError(
self, self,
msg="A '" + c + "' was found at line " + str(row) + msg="A '" + c + "' was found at line " + str(row)
", col " + str(col) + + ", col " + str(col)
" before a matching '" + close + + " before a matching '" + close
"' was found\nfor the '" + open + "'") + "' was found\nfor the '" + open + "'")
self.advance() self.advance()
elif c in " \f\t": elif c in " \f\t":
exprBits.append(self.getWhiteSpace()) exprBits.append(self.getWhiteSpace())
elif self.matchDirectiveEndToken() and not enclosures: elif self.matchDirectiveEndToken() and not enclosures:
break break
elif c == "\\" and self.pos()+1 < srcLen: elif c == "\\" and self.pos() + 1 < srcLen:
eolMatch = EOLre.match(self.src(), self.pos()+1) eolMatch = EOLre.match(self.src(), self.pos() + 1)
if not eolMatch: if not eolMatch:
self.advance() self.advance()
raise ParseError(self, msg='Line ending expected') raise ParseError(self, msg='Line ending expected')
self.setPos(eolMatch.end()) self.setPos(eolMatch.end())
elif c in '\r\n': elif c in '\r\n':
if enclosures: if enclosures:
self.advance() self.advance()
else: else:
break break
elif self.matchCheetahVarInExpressionStartToken(): elif self.matchCheetahVarInExpressionStartToken():
skipping to change at line 1259 skipping to change at line 1265
token = nextToken.upper() token = nextToken.upper()
theStr = eval(token) theStr = eval(token)
endPos = self.pos() endPos = self.pos()
if not theStr: if not theStr:
return return
if token.startswith(single3) or token.startswith(double3): if token.startswith(single3) or token.startswith(double3):
startPosIdx = 3 startPosIdx = 3
else: else:
startPosIdx = 1 startPosIdx = 1
self.setPos(beforeTokenPos+startPosIdx+1) self.setPos(beforeTokenPos + startPosIdx + 1)
outputExprs = [] outputExprs = []
strConst = '' strConst = ''
while self.pos() < (endPos-startPosIdx): while self.pos() < (endPos - startPosIdx):
if self.matchCheetahVarStart() \ if self.matchCheetahVarStart() \
or self.matchExpressionPlaceholderStart(): or self.matchExpressionPlaceholderStart():
if strConst: if strConst:
outputExprs.append(repr(strConst)) outputExprs.append(repr(strConst))
strConst = '' strConst = ''
placeholderExpr = self.getPlaceholder() placeholderExpr = self.getPlaceholder()
outputExprs.append('str('+placeholderExpr+')') outputExprs.append('str(' + placeholderExpr + ')')
else: else:
strConst += self.getc() strConst += self.getc()
self.setPos(endPos) self.setPos(endPos)
if strConst: if strConst:
outputExprs.append(repr(strConst)) outputExprs.append(repr(strConst))
token = "''.join(["+','.join(outputExprs)+"])" token = "''.join([" + ','.join(outputExprs) + "])"
return token return token
def _raiseErrorAboutInvalidCheetahVarSyntaxInExpr(self): def _raiseErrorAboutInvalidCheetahVarSyntaxInExpr(self):
match = self.matchCheetahVarStart() match = self.matchCheetahVarStart()
groupdict = match.groupdict() groupdict = match.groupdict()
if groupdict.get('cacheToken'): if groupdict.get('cacheToken'):
raise ParseError( raise ParseError(
self, self,
msg='Cache tokens are not valid inside expressions. ' msg='Cache tokens are not valid inside expressions. '
'Use them in top-level $placeholders only.') 'Use them in top-level $placeholders only.')
skipping to change at line 1494 skipping to change at line 1500
- rawExpr is the original source string that Cheetah parsed. This - rawExpr is the original source string that Cheetah parsed. This
might be None in some cases. might be None in some cases.
- startPos is the character position in the source string/file - startPos is the character position in the source string/file
where the parser started parsing the current expression. where the parser started parsing the current expression.
@@TR: I realize this use of the term 'expression' is a bit wonky @@TR: I realize this use of the term 'expression' is a bit wonky
as many of the 'expressions' are actually statements, as many of the 'expressions' are actually statements,
but I haven't thought of a better name yet. Suggestions? but I haven't thought of a better name yet. Suggestions?
""" """
for callback in self.setting('expressionFilterHooks'): for callback in self.setting('expressionFilterHooks'):
expr = callback(parser=self, expr=expr, exprType=exprType, expr = callback(parser=self, expr=expr, exprType=exprType,
rawExpr=rawExpr, startPos=startPos) rawExpr=rawExpr, startPos=startPos)
return expr return expr
def _filterDisabledDirectives(self, directiveName): def _filterDisabledDirectives(self, directiveName):
directiveName = directiveName.lower() directiveName = directiveName.lower()
if (directiveName in self.setting('disabledDirectives') if (directiveName in self.setting('disabledDirectives')
or (self.setting('enabledDirectives') or (self.setting('enabledDirectives')
and directiveName not in self.setting('enabledDirectives'))): and directiveName not in self.setting('enabledDirectives'))):
for callback in self.setting('disabledDirectiveHooks'): for callback in self.setting('disabledDirectiveHooks'):
callback(parser=self, directiveName=directiveName) callback(parser=self, directiveName=directiveName)
skipping to change at line 1658 skipping to change at line 1664
callback(parser=self, directiveName=directiveName) callback(parser=self, directiveName=directiveName)
# subclasses can override the default behaviours here by providing an # subclasses can override the default behaviours here by providing an
# eater method in self._directiveNamesAndParsers[directiveName] # eater method in self._directiveNamesAndParsers[directiveName]
directiveParser = self._directiveNamesAndParsers.get(directiveName) directiveParser = self._directiveNamesAndParsers.get(directiveName)
if directiveParser: if directiveParser:
directiveParser() directiveParser()
elif directiveName in self._simpleIndentingDirectives: elif directiveName in self._simpleIndentingDirectives:
handlerName = self._directiveHandlerNames.get(directiveName) handlerName = self._directiveHandlerNames.get(directiveName)
if not handlerName: if not handlerName:
handlerName = 'add'+directiveName.capitalize() handlerName = 'add' + directiveName.capitalize()
handler = getattr(self._compiler, handlerName) handler = getattr(self._compiler, handlerName)
self.eatSimpleIndentingDirective(directiveName, callback=handler) self.eatSimpleIndentingDirective(directiveName, callback=handler)
elif directiveName in self._simpleExprDirectives: elif directiveName in self._simpleExprDirectives:
handlerName = self._directiveHandlerNames.get(directiveName) handlerName = self._directiveHandlerNames.get(directiveName)
if not handlerName: if not handlerName:
handlerName = 'add'+directiveName.capitalize() handlerName = 'add' + directiveName.capitalize()
handler = getattr(self._compiler, handlerName) handler = getattr(self._compiler, handlerName)
if directiveName in ('silent', 'echo'): if directiveName in ('silent', 'echo'):
includeDirectiveNameInExpr = False includeDirectiveNameInExpr = False
else: else:
includeDirectiveNameInExpr = True includeDirectiveNameInExpr = True
expr = self.eatSimpleExprDirective( expr = self.eatSimpleExprDirective(
directiveName, directiveName,
includeDirectiveNameInExpr=includeDirectiveNameInExpr) includeDirectiveNameInExpr=includeDirectiveNameInExpr)
handler(expr) handler(expr)
## ##
skipping to change at line 1919 skipping to change at line 1925
'compiler', startPos=startPos) 'compiler', startPos=startPos)
self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine) self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLine)
try: try:
self._compiler.setCompilerSetting(settingName, valueExpr) self._compiler.setCompilerSetting(settingName, valueExpr)
except Exception: except Exception:
sys.stderr.write( sys.stderr.write(
'An error occurred while processing ' 'An error occurred while processing '
'the following #compiler directive.\n') 'the following #compiler directive.\n')
sys.stderr.write( sys.stderr.write(
'------------------------------------' '------------------------------------'
'----------------------------------\n') '----------------------------------\n')
sys.stderr.write('%s\n' % self[startPos:endPos]) sys.stderr.write('%s\n' % self[startPos:endPos])
sys.stderr.write( sys.stderr.write(
'------------------------------------' '------------------------------------'
'----------------------------------\n') '----------------------------------\n')
sys.stderr.write('Please check the syntax of these settings.\n\n') sys.stderr.write('Please check the syntax of these settings.\n\n')
raise raise
def eatCompilerSettings(self): def eatCompilerSettings(self):
# filtered # filtered
isLineClearToStartToken = self.isLineClearToStartToken() isLineClearToStartToken = self.isLineClearToStartToken()
endOfFirstLine = self.findEOL() endOfFirstLine = self.findEOL()
self.getDirectiveStartToken() self.getDirectiveStartToken()
self.advance(len('compiler-settings')) # to end of 'settings' self.advance(len('compiler-settings')) # to end of 'settings'
skipping to change at line 1959 skipping to change at line 1965
settingsStr = self._applyExpressionFilters( settingsStr = self._applyExpressionFilters(
settingsStr, 'compilerSettings', startPos=startPos) settingsStr, 'compilerSettings', startPos=startPos)
try: try:
self._compiler.setCompilerSettings(keywords=keywords, self._compiler.setCompilerSettings(keywords=keywords,
settingsStr=settingsStr) settingsStr=settingsStr)
except Exception: except Exception:
sys.stderr.write( sys.stderr.write(
'An error occurred while processing ' 'An error occurred while processing '
'the following compiler settings.\n') 'the following compiler settings.\n')
sys.stderr.write( sys.stderr.write(
'------------------------------------' '------------------------------------'
'----------------------------------\n') '----------------------------------\n')
sys.stderr.write('%s\n' % settingsStr.strip()) sys.stderr.write('%s\n' % settingsStr.strip())
sys.stderr.write( sys.stderr.write(
'------------------------------------' '------------------------------------'
'----------------------------------\n') '----------------------------------\n')
sys.stderr.write('Please check the syntax of these settings.\n\n') sys.stderr.write('Please check the syntax of these settings.\n\n')
raise raise
def eatAttr(self): def eatAttr(self):
# filtered # filtered
isLineClearToStartToken = self.isLineClearToStartToken() isLineClearToStartToken = self.isLineClearToStartToken()
skipping to change at line 2020 skipping to change at line 2026
# filtered # filtered
self._eatDefOrBlock('def') self._eatDefOrBlock('def')
def eatBlock(self): def eatBlock(self):
# filtered # filtered
startPos = self.pos() startPos = self.pos()
methodName, rawSignature = self._eatDefOrBlock('block') methodName, rawSignature = self._eatDefOrBlock('block')
self._compiler._blockMetaData[methodName] = { self._compiler._blockMetaData[methodName] = {
'raw': rawSignature, 'raw': rawSignature,
'lineCol': self.getRowCol(startPos), 'lineCol': self.getRowCol(startPos),
} }
def eatClosure(self): def eatClosure(self):
# filtered # filtered
self._eatDefOrBlock('closure') self._eatDefOrBlock('closure')
def _eatDefOrBlock(self, directiveName): def _eatDefOrBlock(self, directiveName):
# filtered # filtered
assert directiveName in ('def', 'block', 'closure') assert directiveName in ('def', 'block', 'closure')
isLineClearToStartToken = self.isLineClearToStartToken() isLineClearToStartToken = self.isLineClearToStartToken()
endOfFirstLinePos = self.findEOL() endOfFirstLinePos = self.findEOL()
skipping to change at line 2102 skipping to change at line 2108
return methodName, rawSignature return methodName, rawSignature
def _eatMultiLineDef(self, directiveName, methodName, argsList, startPos, def _eatMultiLineDef(self, directiveName, methodName, argsList, startPos,
isLineClearToStartToken=False): isLineClearToStartToken=False):
# filtered in calling method # filtered in calling method
self.getExpression() # slurp up any garbage left at the end self.getExpression() # slurp up any garbage left at the end
signature = self[startPos:self.pos()] signature = self[startPos:self.pos()]
endOfFirstLinePos = self.findEOL() endOfFirstLinePos = self.findEOL()
self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos) self._eatRestOfDirectiveTag(isLineClearToStartToken, endOfFirstLinePos)
signature = ' '.join([line.strip() for line in signature.splitlines()]) signature = ' '.join([line.strip() for line in signature.splitlines()])
parserComment = ('## CHEETAH: generated from ' + signature + parserComment = ('## CHEETAH: generated from ' + signature
' at line %s, col %s' % self.getRowCol(startPos) + ' at line %s, col %s' % self.getRowCol(startPos)
+ '.') + '.')
isNestedDef = (self.setting('allowNestedDefScopes') isNestedDef = (self.setting('allowNestedDefScopes')
and len([name for name in self._openDirectivesStack and len([name for name in self._openDirectivesStack
if name == 'def']) > 1) if name == 'def']) > 1)
if directiveName == 'block' or ( if directiveName == 'block' or (
directiveName == 'def' and not isNestedDef): directiveName == 'def' and not isNestedDef):
self._compiler.startMethodDef(methodName, argsList, parserComment) self._compiler.startMethodDef(methodName, argsList, parserComment)
else: # closure else: # closure
self._useSearchList_orig = self.setting('useSearchList') self._useSearchList_orig = self.setting('useSearchList')
self.setSetting('useSearchList', False) self.setSetting('useSearchList', False)
self._compiler.addClosure(methodName, argsList, parserComment) self._compiler.addClosure(methodName, argsList, parserComment)
return methodName return methodName
def _eatSingleLineDef(self, directiveName, methodName, def _eatSingleLineDef(self, directiveName, methodName,
argsList, startPos, endPos): argsList, startPos, endPos):
# filtered in calling method # filtered in calling method
fullSignature = self[startPos:endPos] fullSignature = self[startPos:endPos]
parserComment = ('## Generated from ' + fullSignature + parserComment = ('## Generated from ' + fullSignature
' at line %s, col %s' % self.getRowCol(startPos) + ' at line %s, col %s' % self.getRowCol(startPos)
+ '.') + '.')
isNestedDef = (self.setting('allowNestedDefScopes') isNestedDef = (self.setting('allowNestedDefScopes')
and [name for name in self._openDirectivesStack and [name for name in self._openDirectivesStack
if name == 'def']) if name == 'def'])
if directiveName == 'block' or ( if directiveName == 'block' or (
directiveName == 'def' and not isNestedDef): directiveName == 'def' and not isNestedDef):
self._compiler.startMethodDef(methodName, argsList, parserComment) self._compiler.startMethodDef(methodName, argsList, parserComment)
else: # closure else: # closure
# @@TR: temporary hack of useSearchList # @@TR: temporary hack of useSearchList
useSearchList_orig = self.setting('useSearchList') useSearchList_orig = self.setting('useSearchList')
skipping to change at line 2687 skipping to change at line 2693
isLineClearToStartToken = self.isLineClearToStartToken() isLineClearToStartToken = self.isLineClearToStartToken()
endOfFirstLine = self.findEOL() endOfFirstLine = self.findEOL()
lineCol = self.getRowCol() lineCol = self.getRowCol()
self.getDirectiveStartToken() self.getDirectiveStartToken()
startPos = self.pos() startPos = self.pos()
expressionParts = self.getExpressionParts(pyTokensToBreakAt=[':']) expressionParts = self.getExpressionParts(pyTokensToBreakAt=[':'])
expr = ''.join(expressionParts).strip() expr = ''.join(expressionParts).strip()
expr = self._applyExpressionFilters(expr, 'if', startPos=startPos) expr = self._applyExpressionFilters(expr, 'if', startPos=startPos)
isTernaryExpr = ('then' in expressionParts and isTernaryExpr = ('then' in expressionParts
'else' in expressionParts) and 'else' in expressionParts)
if isTernaryExpr: if isTernaryExpr:
conditionExpr = [] conditionExpr = []
trueExpr = [] trueExpr = []
falseExpr = [] falseExpr = []
currentExpr = conditionExpr currentExpr = conditionExpr
for part in expressionParts: for part in expressionParts:
if part.strip() == 'then': if part.strip() == 'then':
currentExpr = trueExpr currentExpr = trueExpr
elif part.strip() == 'else': elif part.strip() == 'else':
currentExpr = falseExpr currentExpr = falseExpr
skipping to change at line 2727 skipping to change at line 2733
if self.peek() == ':': if self.peek() == ':':
self.advance() self.advance()
self.getWhiteSpace() self.getWhiteSpace()
self._eatRestOfDirectiveTag(isLineClearToStartToken, self._eatRestOfDirectiveTag(isLineClearToStartToken,
endOfFirstLine) endOfFirstLine)
self.pushToOpenDirectivesStack('if') self.pushToOpenDirectivesStack('if')
self._compiler.addIf(expr, lineCol=lineCol) self._compiler.addIf(expr, lineCol=lineCol)
# end directive handlers # end directive handlers
def handleEndDef(self): def handleEndDef(self):
isNestedDef = (self.setting('allowNestedDefScopes') and isNestedDef = (self.setting('allowNestedDefScopes')
[name for name in self._openDirectivesStack and [name for name in self._openDirectivesStack
if name == 'def']) if name == 'def'])
if not isNestedDef: if not isNestedDef:
self._compiler.closeDef() self._compiler.closeDef()
else: else:
# @@TR: temporary hack of useSearchList # @@TR: temporary hack of useSearchList
self.setSetting('useSearchList', self._useSearchList_orig) self.setSetting('useSearchList', self._useSearchList_orig)
self._compiler.commitStrConst() self._compiler.commitStrConst()
self._compiler.dedent() self._compiler.dedent()
### ###
def pushToOpenDirectivesStack(self, directiveName): def pushToOpenDirectivesStack(self, directiveName):
 End of changes. 51 change blocks. 
102 lines changed or deleted 114 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)