"""BraceConverter.py Contributed 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 sys class BraceConverter: CSKIP = re.compile("(^[^\"'{}:#]+)") COLONBRACE = re.compile(":\s*{\s*([^\s].*)?$") def __init__(self): self.inquote = 0 self.dictlevel = 0 def parseLine(self, line, writer): """Parse a line. The only public method of this class, call with subsequent lines and an instance of PSPServletWriter. """ self.line = line if self.inquote and self.line: self.skipquote(writer) self.line = self.line.lstrip() 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') def openBlock(self, writer): """Open a new block.""" 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:] def openBrace(self, writer): """Open brace encountered.""" writer.printChars("{") self.line = self.line[1:] self.dictlevel += 1 def closeBrace(self, writer): """Close brace encountered.""" if self.dictlevel: writer.printChars("}") self.line = self.line[1:] self.dictlevel -= 1 else: writer.popIndent() self.line = self.line[1:].lstrip() if self.line: writer.printChars('\n') writer.printIndent() def skipquote(self, writer): """Skip to end of quote. Skip over all chars until the line is exhausted or the current non-escaped quote sequence is encountered. """ pos = self.line.find(self.quotechars) if pos == -1: writer.printChars(self.line) self.line = "" elif (pos > 0) and self.line[pos-1] == '\\': pos += 1 writer.printChars(self.line[:pos]) self.line = self.line[pos:] self.skipquote(writer) else: pos += len(self.quotechars) writer.printChars(self.line[:pos]) self.line = self.line[pos:] self.inquote = 0 def handleQuote(self, quote, writer): "Check and handle if current pos is a single or triple quote.""" 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 class DummyWriter(ServletWriter): """For stand alone testing.""" 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._emptyString 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)