~certify-web-dev/twisted/certify-trunk

« back to all changes in this revision

Viewing changes to twisted/eco/sexpy.py

  • Committer: Bazaar Package Importer
  • Author(s): Moshe Zadka
  • Date: 2002-03-08 07:14:16 UTC
  • Revision ID: james.westby@ubuntu.com-20020308071416-oxvuw76tpcpi5v1q
Tags: upstream-0.15.5
ImportĀ upstreamĀ versionĀ 0.15.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
"""S-expressions for python.
 
4
 
 
5
This provides a wire-protocol reader and object representation for
 
6
s-expressions.
 
7
"""
 
8
 
 
9
import types
 
10
import string
 
11
import re
 
12
import copy
 
13
import cStringIO
 
14
 
 
15
from twisted.protocols import protocol
 
16
 
 
17
def lispString(st):
 
18
    return '"'+string.replace(string.replace(st, '\\', '\\\\'),'"','\\"')+'"'
 
19
 
 
20
def pythonString(st):
 
21
    assert st[0] == '"' and st[-1] == '"'
 
22
    # strip off the quotes
 
23
    st = st[1:-1]
 
24
    # unescape backslashes
 
25
    st = string.replace(st, '\\\\', '\\')
 
26
    # unescape quotes
 
27
    st = string.replace(st, '\\"', '"')
 
28
    return st
 
29
    
 
30
class Atom:
 
31
    """
 
32
    class to represent atoms, to distinguish them from strings.
 
33
    """
 
34
    def __init__(self, st):
 
35
        self.string = st
 
36
    def __cmp__(self, other):
 
37
        if isinstance(other, Atom):
 
38
            return cmp(self.string, other.string)
 
39
        else:
 
40
            return cmp(self.string, other)
 
41
 
 
42
    def __hash__(self):
 
43
        return hash(self.string)
 
44
    
 
45
    def __repr__(self):
 
46
        return "atom(%s)" % repr(self.string)
 
47
    
 
48
    def __str__(self):
 
49
        return self.string
 
50
    
 
51
 
 
52
 
 
53
def atom(st):
 
54
    """
 
55
    return an atom, first checking to see if it's valid
 
56
    """
 
57
    assert ATOM.match(st), "invalid atom"
 
58
    return Atom(st)
 
59
 
 
60
# SYMBOL = re.compile(r'[a-zA-Z]([a-zA-Z0-9]|\\.)*')
 
61
ATOM = re.compile(r'[^ \-\n\r\t0-9"\\()]([^ \n\r\t"\[\]()\\]|\\.)*')
 
62
STRING = re.compile(r'"([^\\"]|\\.)*"')
 
63
NUMBER = re.compile(r'-?[0-9]+(\.[0-9]*)?')
 
64
WHITESPACE = re.compile('[ \n\r\t]+')
 
65
 
 
66
 
 
67
class SymbolicExpressionReceiver(protocol.Protocol):
 
68
    buffer = ''
 
69
 
 
70
    def __init__(self):
 
71
        self.expq = []
 
72
        self.quoteLevel = 0
 
73
        self.quotes = []
 
74
    # I don't ever want to buffer more than 64k of data before bailing.
 
75
    maxUnparsedBufferSize = 32 * 1024 
 
76
    
 
77
    def symbolicExpressionReceived(self, expr):
 
78
        """
 
79
        This class's raison d'etre, this callback is made when a full
 
80
        S-expression is received.  (Note that a full expression may be a single
 
81
        token)
 
82
        """
 
83
        print "unimplemented symbolicExpressionReceived(%s)" % repr(expr)
 
84
 
 
85
 
 
86
    def sendSymbolicExpression(self, expr):
 
87
        """
 
88
        Sends a symbolic expression to the other end.
 
89
        """
 
90
        assert isinstance(expr, SymbolicExpression)
 
91
        if self.connected:
 
92
            self.transport.write(str(expr))
 
93
        else:
 
94
            self.expq.append(expr)
 
95
 
 
96
    def connectionMade(self):
 
97
        self.listStack = []
 
98
        xpq = self.expq
 
99
        del self.expq
 
100
        for xp in xpq:
 
101
            self.sendSymbolicExpression(xp)
 
102
 
 
103
    def openParen(self):
 
104
        newCurrentSexp = []
 
105
        if self.listStack:
 
106
            self.listStack[-1].append(newCurrentSexp)
 
107
        self.listStack.append(newCurrentSexp)
 
108
 
 
109
    def openQuote(self, name):
 
110
        newCurrentSexp = [Atom(name)]
 
111
        self.quotes.append(newCurrentSexp)
 
112
        if self.listStack:
 
113
            self.listStack[-1].append(newCurrentSexp)
 
114
        self.listStack.append(newCurrentSexp)
 
115
 
 
116
 
 
117
 
 
118
    def closeParen(self):
 
119
        aList = self.listStack.pop()
 
120
        for i in range(len(self.quotes)):
 
121
            if aList is self.quotes[i][1]:                
 
122
                del self.quotes[i]
 
123
                i = self.listStack.pop()
 
124
                if not self.listStack:
 
125
                    self._sexpRecv(i)
 
126
                break
 
127
        if not self.listStack:                
 
128
            self._sexpRecv(aList)
 
129
 
 
130
    def _tokenReceived(self, tok):
 
131
                
 
132
        if self.listStack:
 
133
            self.listStack[-1].append(tok)
 
134
            if self.quotes and self.listStack[-1] is self.quotes[-1]:
 
135
                del self.quotes[-1]
 
136
                i = self.listStack.pop()
 
137
                if not self.listStack:
 
138
                    self._sexpRecv(i)
 
139
        else:
 
140
                self._sexpRecv(tok)
 
141
 
 
142
 
 
143
    def _sexpRecv(self, xp):
 
144
        self.symbolicExpressionReceived(xp)
 
145
 
 
146
    def dataReceived(self, data):
 
147
        buffer = self.buffer + data
 
148
        while buffer:
 
149
            # eat any whitespace at the beginning of the string.
 
150
            m = WHITESPACE.match(buffer)
 
151
            if m:
 
152
                buffer = buffer[m.end():]
 
153
                continue
 
154
            
 
155
            if buffer[0] == '[':
 
156
                self.openParen()
 
157
                buffer = buffer[1:]
 
158
                continue
 
159
            if buffer[0] == ']':
 
160
                self.closeParen()
 
161
                buffer = buffer[1:]
 
162
                continue
 
163
            if buffer[0] == '(':
 
164
                self.quoteLevel = self.quoteLevel + 1
 
165
                self.openParen()
 
166
                self.listStack[-1].append(Atom("backquote"))
 
167
                self.openParen()
 
168
                buffer = buffer[1:]
 
169
                continue
 
170
            if buffer[0] == ')':
 
171
                self.quoteLevel = self.quoteLevel - 1
 
172
                if self.quoteLevel < 0:
 
173
                    raise Error("Too many )s")
 
174
                self.closeParen()
 
175
                self.closeParen()
 
176
                buffer = buffer[1:]
 
177
                continue
 
178
            if buffer[0] == ",":
 
179
                if buffer[1] == "@":
 
180
                    self.openQuote("unquote-splice")
 
181
                    buffer = buffer[2:]
 
182
                else:
 
183
                    self.openQuote("unquote")
 
184
                    buffer = buffer[1:]
 
185
                continue
 
186
            if buffer[0] == "'":
 
187
                self.openQuote("quote")
 
188
                buffer = buffer[1:]
 
189
                continue
 
190
            m = STRING.match(buffer)
 
191
            if m:
 
192
                end = m.end()
 
193
                st, buffer = buffer[:end], buffer[end:]
 
194
                self._tokenReceived(pythonString(st))
 
195
                continue
 
196
            m = NUMBER.match(buffer)
 
197
            if m:
 
198
                end = m.end()
 
199
                if end != len(buffer):
 
200
                    number, buffer = buffer[:end], buffer[end:]
 
201
                    # If this fails, the RE is buggy.
 
202
                    if '.' in number:
 
203
                        number = float(number)
 
204
                    else:
 
205
                        number = int(number)
 
206
                    self._tokenReceived(number)
 
207
                    continue
 
208
            m = ATOM.match(buffer)
 
209
            if m:
 
210
                end = m.end()
 
211
                if end != len(buffer):
 
212
                    symbol, buffer = buffer[:end], buffer[end:]
 
213
                    self._tokenReceived(Atom(symbol))
 
214
                    continue
 
215
            break
 
216
        if len(buffer) > self.maxUnparsedBufferSize:
 
217
            raise SymbolicExpressionParseError("Too much unparsed data.")
 
218
        self.buffer = buffer
 
219
 
 
220
    def connectionLost(self):
 
221
        if self.listStack:
 
222
            self.symbolicExpressionReceived(self.listStack[-1])
 
223
                                                       
 
224
class _fromString(SymbolicExpressionReceiver):
 
225
 
 
226
    def symbolicExpressionReceived(self, expr):
 
227
        self.exp = expr
 
228
    
 
229
    def __init__(self, st):
 
230
        SymbolicExpressionReceiver.__init__(self)
 
231
        self.connectionMade()
 
232
        self.dataReceived(st)
 
233
        self.connectionLost()
 
234
 
 
235
def fromString(st):
 
236
    
 
237
    f = _fromString(st)
 
238
    return f.exp
 
239
 
 
240