2 # -*- Mode: Python; py-indent-offset: 4 -*-
3 from __future__ import generators
6 from cStringIO import StringIO
8 class error(Exception):
9 def __init__(self, filename, lineno, msg):
10 Exception.__init__(self, msg)
11 self.filename = filename
15 return '%s:%d: error: %s' % (self.filename, self.lineno, self.msg)
19 if chr(i) in string.letters + string.digits + '_':
23 trans = string.join(trans, '')
26 if isinstance(filename, str):
27 fp = open(filename, 'r')
28 else: # if not string, assume it is some kind of iterator
30 filename = getattr(fp, 'name', '<unknown>')
31 whitespace = ' \t\n\r\x0b\x0c'
32 nonsymbol = whitespace + '();\'"'
39 while pos < len(line):
40 if line[pos] in whitespace: # ignore whitespace
42 elif line[pos] == ';': # comment
44 elif line[pos:pos+2] == "'(":
45 pass # the open parenthesis will be handled next iteration
46 elif line[pos] == '(':
48 openlines.append(lineno)
49 elif line[pos] == ')':
51 raise error(filename, lineno, 'close parenthesis found when none open')
56 stack[-1] += (closed,)
59 elif line[pos] == '"': # quoted string
61 raise error(filename, lineno,
62 'string found outside of s-expression')
65 while endpos < len(line):
66 if endpos+1 < len(line) and line[endpos] == '\\':
68 if line[endpos] == 'n':
70 elif line[endpos] == 'r':
72 elif line[endpos] == 't':
76 chars.append(line[endpos])
77 elif line[endpos] == '"':
80 chars.append(line[endpos])
82 if endpos >= len(line):
83 raise error(filename, lineno, "unclosed quoted string")
85 stack[-1] += (''.join(chars),)
88 raise error(filename, lineno,
89 'identifier found outside of s-expression')
91 while endpos < len(line) and line[endpos] not in nonsymbol:
93 symbol = line[pos:endpos]
94 pos = max(pos, endpos-1)
95 try: symbol = int(symbol)
97 try: symbol = float(symbol)
98 except ValueError: pass
99 stack[-1] += (symbol,)
102 msg = '%d unclosed parentheses found at end of ' \
103 'file (opened on line(s) %s)' % (len(stack),
104 ', '.join(map(str, openlines)))
105 raise error(filename, lineno, msg)
108 def __init__(self, filename):
109 """Argument is either a string, a parse tree, or file object"""
110 self.filename = filename
111 def startParsing(self, filename=None):
112 statements = parse(filename or self.filename)
113 for statement in statements:
114 self.handle(statement)
115 def handle(self, tup):
116 cmd = string.translate(tup[0], trans)
117 if hasattr(self, cmd):
118 getattr(self, cmd)(*tup[1:])
121 def unknown(self, tup):
124 _testString = """; a scheme file
125 (define-func gdk_font_load ; a comment at end of line
129 (define-boxed GdkEvent
135 if __name__ == '__main__':
138 fp = open(sys.argv[1])
140 fp = StringIO(_testString)
141 statements = parse(fp)