1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
#----------------------------------------------------------------------
# Name: parse.py
# Author: David N. Mashburn <david.n.mashburn@gmail.com>
# Created: 12/20/2009
# Tags: phoenix-port
#----------------------------------------------------------------------
"""parse.py is a utility that allows simple checking for line continuations
to give the shell information about where text is commented and where it is
not and also how to appropriately break up a sequence of commands into
separate multi-line commands...
"""
__author__ = "David N. Mashburn <david.n.mashburn@gmail.com>"
# created 12/20/2009
import re
# change this to testForContinuations
def testForContinuations(codeBlock,ignoreErrors=False):
""" Test 4 different types of continuations:""" + \
""" String Continuations (ie with ''')""" + \
""" Indentation Block Continuations (ie "if 1:" )""" + \
""" Line Continuations (ie with \\ character )""" + \
""" Parenthetical continuations (, [, or {"""
stringMark = None
paraList = []
indentNumber=[0]
stringMarks = ['"""',"'''",'"',"'"]
openMarks = ['(','[','{']
closeMarks = [')',']','}']
paraMarkDict = { '(':')', '[':']', '{':'}' }
stringContinuationList=[]
lineContinuationList=[] # For \ continuations ... False because cannot start as line Continuation...
indentationBlockList=[]
parentheticalContinuationList=[]
newIndent=False
lspContinuation=False
for i,l in enumerate(codeBlock.split('\n')):
currentIndentation = len(l)-len(l.lstrip())
if i>0:
lspContinuation = lineContinuationList[-1] or \
stringContinuationList[-1] or \
parentheticalContinuationList[-1]
# first, check for non-executing lines (whitespace and/or comments only)
if l.lstrip()=='':
emptyLine=True
elif l.strip()[0]=='#':
emptyLine=True
else: # otherwise, check the indentation...
emptyLine=False
if newIndent and currentIndentation>indentNumber[-1]:
newIndent=False
indentNumber.append(currentIndentation)
elif lspContinuation:
pass
elif not newIndent and currentIndentation in indentNumber:
while currentIndentation<indentNumber[-1]:
indentNumber.pop() # This is the end of an indentation block
elif not ignoreErrors:
#print('Invalid Indentation!!')
return ['Invalid Indentation Error',i]
firstWord = re.match(r' *\w*',l).group().lstrip()
if firstWord in ['if','else','elif','for','while',
'def','class','try','except','finally']:
hasContinuationWord = True
else:
hasContinuationWord = False
commented=False
nonCommentLength=len(l)
result = re.finditer('"""'+'|'+"'''" + r'''|"|'|\"|\'|\(|\)|\[|\]|\{|\}|#''',l)
for r in result:
j = r.group()
if stringMark is None:
if j=='#': # If it is a legitimate comment, ignore everything after
commented=True
# get length up to last non-comment character
nonCommentLength = r.start()
break
elif j in stringMarks:
stringMark=j
else:
if paraList != [] and j in closeMarks:
if paraMarkDict[paraList[-1]]==j:
paraList.pop()
elif not ignoreErrors:
#print('Invalid Syntax!!')
return ['Invalid Syntax Error',i]
if j in openMarks:
paraList.append(j)
elif stringMark==j:
stringMark=None
stringContinuationList.append(stringMark!=None)
indentationBlockList.append(False)
nonCommentString = l[:nonCommentLength].rstrip()
if nonCommentString!='' and stringContinuationList[-1]==False:
if nonCommentString[-1]==':':
indentationBlockList[-1]=True
newIndent=True
lineContinuationList.append(False)
if len(l)>0 and not commented:
if l[-1]=='\\':
lineContinuationList[-1]=True
parentheticalContinuationList.append( paraList != [] )
# Now stringContinuationList (et al) is line by line key for magic
# telling it whether or not each next line is part of a string continuation
if (stringContinuationList[-1] or indentationBlockList[-1] or \
lineContinuationList[-1] or parentheticalContinuationList[-1]) \
and not ignoreErrors:
#print('Incomplete Syntax!!')
return ['Incomplete Syntax Error',i]
if newIndent and not ignoreErrors:
#print('Incomplete Indentation!')
return ['Incomplete Indentation Error',i]
# Note that if one of these errors above gets thrown, the best solution is to pass the resulting block
# to the interpreter as exec instead of interp
return stringContinuationList,indentationBlockList,lineContinuationList,parentheticalContinuationList
|