""" BraceConverter (2000-09-04) by Dave Wallace (dwallace@delanet.com) Converts Brace-blocked Python into normal indented Python. Brace-blocked Python is non-indentation aware and blocks are delimited by ':{' and '}' pairs. Thus: for x in range(10) :{ if x%2 :{ print x } else :{ print z } } Becomes: (roughly, barring some spurious newlines) for x in range(10) : if x%2 : print x else : print z This implementation is fed a line at a time via parseLine(), outputs to a PSPServletWriter, and tracks the current quotation and block levels internally. """ import re import string import sys class BraceConverter: CSKIP = re.compile("(^[^\"'{}:#]+)") COLONBRACE=re.compile(":\s*{\s*([^\s].*)?$") def __init__(self): self.inquote = 0 self.dictlevel = 0 # The only public method of this class, call with subsequent lines and an # instance of PSPServletWriter def parseLine(self,line,writer): self.line = line if self.inquote and self.line: self.skipquote(writer) self.line = string.lstrip(self.line) if not self.line: writer.printChars('\n') return writer.printIndent() while self.line: while self.inquote and self.line: self.skipquote(writer) match = self.CSKIP.search(self.line) if match: writer.printChars(self.line[:match.end(1)]) self.line = self.line[match.end(1):] else: ch = self.line[0] if ch == "'": self.handleQuote("'",writer) self.skipquote(writer) elif ch == '"': self.handleQuote('"',writer) self.skipquote(writer) elif ch == '{': self.openBrace(writer) elif ch == '}': self.closeBrace(writer) elif ch == ':': self.openBlock(writer) elif ch == '#': writer.printChars(self.line) self.line="" else: # should never get here raise Exception() else: writer.printChars('\n') # open a new block def openBlock(self,writer): match = self.COLONBRACE.match(self.line) if match and not self.dictlevel: writer.printChars(":") writer.pushIndent() if match.group(1): # text follows :{, if its a comment leave it on the same line # else start a new line and leave the text for processing if match.group(1)[0] == '#': writer.printChars(" " + match.group(1)) self.line = "" else: writer.printChars('\n') writer.printIndent() self.line = match.group(1) else: self.line = "" else: writer.printChars(":") self.line = self.line[1:] # open brace encountered def openBrace(self,writer): writer.printChars("{") self.line=self.line[1:] self.dictlevel = self.dictlevel + 1 # close brace encountered def closeBrace(self,writer): if self.dictlevel: writer.printChars("}") self.line=self.line[1:] self.dictlevel = self.dictlevel - 1 else: writer.popIndent() self.line = string.lstrip(self.line[1:]) if (self.line): writer.printChars('\n') writer.printIndent() # skip over all chars until the line is exhausted # or the current non-escaped quote sequence is encountered def skipquote(self,writer): pos = string.find(self.line,self.quotechars) if -1 == pos: writer.printChars(self.line) self.line="" elif (pos > 0) and self.line[pos-1] == '\\': pos = pos +1 writer.printChars(self.line[:pos]) self.line = self.line[pos:] self.skipquote(writer) else: pos = pos + len(self.quotechars) writer.printChars(self.line[:pos]) self.line = self.line[pos:] self.inquote = 0 # Check and handle if current pos is a single or triple quote def handleQuote(self,quote,writer): self.inquote=1 triple = quote*3 if self.line[0:3]==triple: self.quotechars=triple writer.printChars(triple) self.line = self.line[3:] else: self.quotechars=quote writer.printChars(quote) self.line = self.line[1:] ### testing if __name__ == "__main__": from ServletWriter import ServletWriter # for stand alone testing class DummyWriter(ServletWriter): def __init__(self): self._filehandle = sys.stdout self._tabcnt = 0 self._blockcount = 0 # a hack to handle nested blocks of python code self._indentSpaces = ServletWriter.SPACES self._useTabs=1 self._useBraces=0 self._indent='\t' self._userIndent = ServletWriter.EMPTY_STRING test=r""" for x in range(10) :{ q={ 'test':x } print x } for x in range(10) :{ q={'test':x}; print x} else :{ print "\"done\"" #""}{ x = { 'test1':{'sub2':{'subsub1':2}} # yee ha } } print "all done" """ p = BraceConverter() dw = DummyWriter() for line in test.split('\n'): p.parseLine(line,dw)