"""\ ParseString(s) -> LispList is the function you want to use. The rest? Merely players.""" from __future__ import generators #### Huge terminology contradiction!!! ### # THe string-checking functions use the term LispList to mean a pre-pared # string like (1 2 3) or '(a 3 42). # BUT often functions in all.py take in a 'lispList' which is a _parsed_ # list: NOT a string. # Another note: If the parsing functions seem hacky, # that's because python strings are immutable, so you need to return them # all the time. It would probably clean stuff up in some places to just # implement something like java's StringBuffer. ah well. ##print 'Loading Parser.py' #I use this because the python ide IDLE has.. issues DELIMS = ' \r\t\n' SYMBOL_STARTERS = [chr(x) for x in range(32,127)] for not_a_starter in DELIMS + "()'": if not_a_starter in SYMBOL_STARTERS: SYMBOL_STARTERS.remove(not_a_starter) print """Parser.py: Legitimate characters to begin a lisp atom/symbol: """, SYMBOL_STARTERS def StripFront(s, delims): "Strips delimiters off the front, returns the new string" i=0 while(s[i] in delims): i += 1 return s[:i] def ParenCount(s): "Returns how many right parens are needed to finish off the expr" parenLvl = 0 for c in s: if c == '(': parenLvl += 1 elif c == ')': parenLvl -= 1 elif c == ']': return 0 return parenLvl def ReplaceSuperBracket(s): if s[-1] != ']': return s return s[:-1] + ')' * ParenCount(s[:-1]) def WellformedLispList(s): "DOes parenthesis checking, and runs IsLiteral and Quoted on it" s = ReplaceSuperBracket(s) if not IsLiteralLispList(s) and not QuotedLispList(s): return 0 return ParenCount(s) == 0 def IsLiteralLispList(s): "Something like (1 2 3). No quote at beginning." return len(s) >=2 and s[0] == '(' and s[-1] in ')]' def QuotedLispList(s): return len(s) >= 3 and s[0:2] == "'(" and s[-1] in ')]' def ParseElemsGen(lispLiteral): """Give this sucker an UNQUOTED lisp-string. Generates strings and only strings.""" def _GotoMatchingParen(i, curParenDepth): assert 'curListStr' in locals() while(i < len(curListStr) and curParenDepth > 0): if curListStr[i] == '(': curParenDepth += 1 elif curListStr[i] == ')': curParenDepth -= 1 else: assert curListStr[i] != ']' #shouldn't hit those in this function i += 1 assert not (i == len(curListStr) and curParenDepth > 0), "Parenthesis Mismatch error! (Big surprise forLISP). For %s" %lispLiteral return i #STart actual function body assert IsLiteralLispList(lispLiteral) curListStr = lispLiteral[1:-1] #Now strip off the outermost parentheses ## print "ParseElemsGen: parsing '%s'" %curListStr elem = "" while(curListStr): #Progress through, chopping off what's been processed #We should now be at beginning of a new element if curListStr[0] in DELIMS: StripFront(curListStr, DELIMS) ## print "ParseElemsGen: \"%s\"" %curListStr if curListStr[0] in SYMBOL_STARTERS: i = 0 while(i < len(curListStr) and curListStr[i] not in DELIMS): i += 1 yield curListStr[:i] curListStr = curListStr[i:] elif curListStr[0] == '(': matchingPos = _GotoMatchingParen(1,1) #Start off after the first open-paren yield curListStr[:matchingPos] curListStr = curListStr[matchingPos:] elif curListStr[0:2] == "'(": matchingPos = _GotoMatchingParen(2,1) yield curListStr[:matchingPos] curListStr = curListStr[matchingPos:] else: raise Exception, "Dunno what to do with '%s'" %curListStr #Now, clear past delimiters to the next expr while curListStr and curListStr[0] in DELIMS: curListStr = curListStr[1:] def ParseString( lispListStr): """lispListStr can either be quoted or unquoted. Prepends the quote macro and all.""" def HelperGen(s): for elem in ParseElemsGen(s): ## print "ParseString: '%s' " %elem , ## print "Wellformed? %s " % WellformedLispList(elem), ## print "Quoted? %s" % QuotedLispList(elem) if WellformedLispList(elem): yield ParseString(elem) else: yield elem assert WellformedLispList(lispListStr) #Begin actual function body lispListStr = ReplaceSuperBracket(lispListStr) if QuotedLispList(lispListStr): notQuotedPart = lispListStr[1:] ret = ['quote', list(HelperGen(notQuotedPart))] else: ret = list(HelperGen(lispListStr)) return ret if __name__=='__main__': pass