~a-roehler/python-mode/XEmacs-compat-test

« back to all changes in this revision

Viewing changes to pymacs/pymacs.py

  • Committer: Andreas Roehler
  • Date: 2011-10-27 10:14:29 UTC
  • Revision ID: andreas.roehler@online.de-20111027101429-1f5sg5jj4ro3ar5k
Pymacs integrated

No separate install required any more, works
out-of-the-box.

Customize `py-install-directory', if Pymacs should run from
other place than default set by python-mode.el.

If `py-install-directory' is nil, python-mode assumes
 it's default directory `pymacs' beneath location where
 python-mode.el resides

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
# -*- coding: utf-8 -*-
 
3
# Copyright © 2001, 2002, 2003 Progiciels Bourbeau-Pinard inc.
 
4
# François Pinard <pinard@iro.umontreal.ca>, 2001.
 
5
 
 
6
# This program is free software; you can redistribute it and/or modify
 
7
# it under the terms of the GNU General Public License as published by
 
8
# the Free Software Foundation; either version 2, or (at your option)
 
9
# any later version.
 
10
#
 
11
# This program is distributed in the hope that it will be useful,
 
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
# GNU General Public License for more details.
 
15
#
 
16
# You should have received a copy of the GNU General Public License
 
17
# along with this program; if not, write to the Free Software Foundation,
 
18
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.  */
 
19
 
 
20
"""\
 
21
Interface between Emacs Lisp and Python - Python part.
 
22
 
 
23
Emacs may launch this module as a stand-alone program, in which case it
 
24
acts as a server of Python facilities for that Emacs session, reading
 
25
requests from standard input and writing replies on standard output.
 
26
When used in this way, the program is called "the Pymacs helper".
 
27
 
 
28
This module may also be usefully imported by those other Python modules.
 
29
See the Pymacs documentation (in `README') for more information.
 
30
"""
 
31
 
 
32
__metaclass__ = type
 
33
import os, sys
 
34
 
 
35
old_style_exception = not isinstance(Exception, type)
 
36
 
 
37
## Python services for Emacs applications.
 
38
 
 
39
class Main:
 
40
    debug_file = None
 
41
    signal_file = None
 
42
 
 
43
    def main(self, *arguments):
 
44
        """\
 
45
Execute Python services for Emacs, and Emacs services for Python.
 
46
This program is meant to be called from Emacs, using `pymacs.el'.
 
47
 
 
48
Debugging options:
 
49
    -d FILE  Debug the protocol to FILE.
 
50
    -s FILE  Trace received signals to FILE.
 
51
 
 
52
Arguments are added to the search path for Python modules.
 
53
"""
 
54
        # Decode options.
 
55
        arguments = (os.environ.get('PYMACS_OPTIONS', '').split()
 
56
                     + list(arguments))
 
57
        import getopt
 
58
        options, arguments = getopt.getopt(arguments, 'd:s:')
 
59
        for option, value in options:
 
60
            if option == '-d':
 
61
                self.debug_file = value
 
62
            elif option == '-s':
 
63
                self.signal_file = value
 
64
        arguments.reverse()
 
65
        for argument in arguments:
 
66
            if os.path.isdir(argument):
 
67
                sys.path.insert(0, argument)
 
68
        # Inhibit signals.
 
69
        import signal
 
70
        self.original_handler = signal.signal(
 
71
                signal.SIGINT, self.interrupt_handler)
 
72
        for counter in range(1, signal.NSIG):
 
73
            if counter == signal.SIGINT:
 
74
                self.original_handler = signal.signal(counter,
 
75
                                                      self.interrupt_handler)
 
76
 
 
77
            # The following few lines of code are reported to create IO
 
78
            # problems within the Pymacs helper itself, so I merely comment
 
79
            # them for now, until we know better.
 
80
 
 
81
            #else:
 
82
            #    try:
 
83
            #        signal.signal(counter, self.generic_handler)
 
84
            #    except RuntimeError:
 
85
            #        pass
 
86
        self.inhibit_quit = True
 
87
        # Start protocol and services.
 
88
        from Pymacs import __version__
 
89
        lisp._protocol.send('version', '"%s"' % __version__)
 
90
        lisp._protocol.loop()
 
91
 
 
92
    def generic_handler(self, number, frame):
 
93
        if self.signal_file:
 
94
            file(self.signal_file, 'a').write('%d\n' % number)
 
95
 
 
96
    def interrupt_handler(self, number, frame):
 
97
        if self.signal_file:
 
98
            star = (' *', '')[self.inhibit_quit]
 
99
            file(self.signal_file, 'a').write('%d%s\n' % (number, star))
 
100
        if not self.inhibit_quit:
 
101
            self.original_handler(number, frame)
 
102
 
 
103
run = Main()
 
104
main = run.main
 
105
 
 
106
if old_style_exception:
 
107
    ProtocolError = 'ProtocolError'
 
108
    ZombieError = 'ZombieError'
 
109
else:
 
110
    class error(Exception): pass
 
111
    class ProtocolError(error): pass
 
112
    class ZombieError(error): pass
 
113
 
 
114
class Protocol:
 
115
 
 
116
    # All exec's and eval's triggered from the Emacs side are all executed
 
117
    # within the "loop" method below, so all user context is kept as
 
118
    # local variables within this single routine.  Different instances
 
119
    # of this Protocol class would yield independant evaluation contexts.
 
120
    # But in the usual case, there is only one such instance kept within a
 
121
    # Lisp_Interface instance, and the "lisp" global variable within this
 
122
    # module holds such a Lisp_Interface instance.
 
123
 
 
124
    def __init__(self):
 
125
        self.freed = []
 
126
 
 
127
    def loop(self):
 
128
        # The server loop repeatedly receives a request from Emacs and
 
129
        # returns a response, which is either the value of the received
 
130
        # Python expression, or the Python traceback if an error occurs
 
131
        # while evaluating the expression.
 
132
 
 
133
        # The server loop may also be executed, as a recursive invocation,
 
134
        # in the context of Emacs serving a Python request.  In which
 
135
        # case, we might also receive a notification from Emacs telling
 
136
        # that the reply has been transmitted, or that an error occurred.
 
137
        # A reply notification from Emacs interrupts the loop: the result
 
138
        # of this function is then the value returned from Emacs.
 
139
        done = False
 
140
        while not done:
 
141
            try:
 
142
                action, text = self.receive()
 
143
                if action == 'eval':
 
144
                    action = 'return'
 
145
                    try:
 
146
                        run.inhibit_quit = False
 
147
                        value = eval(text)
 
148
                    finally:
 
149
                        run.inhibit_quit = True
 
150
                elif action == 'exec':
 
151
                    action = 'return'
 
152
                    value = None
 
153
                    try:
 
154
                        run.inhibit_quit = False
 
155
                        exec text
 
156
                    finally:
 
157
                        run.inhibit_quit = True
 
158
                elif action == 'return':
 
159
                    done = True
 
160
                    try:
 
161
                        run.inhibit_quit = False
 
162
                        value = eval(text)
 
163
                    finally:
 
164
                        run.inhibit_quit = True
 
165
                elif action == 'raise':
 
166
                    action = 'raise'
 
167
                    value = 'Emacs: ' + text
 
168
                else:
 
169
                    if old_style_exception:
 
170
                        raise ProtocolError, "Unknown action %r" % action
 
171
                    raise ProtocolError("Unknown action %r" % action)
 
172
            except KeyboardInterrupt:
 
173
                if done:
 
174
                    raise
 
175
                action = 'raise'
 
176
                value = '*Interrupted*'
 
177
            except ProtocolError, exception:
 
178
                sys.exit("Protocol error: %s\n" % exception)
 
179
            except:
 
180
                import StringIO, traceback
 
181
                buffer = StringIO.StringIO()
 
182
                traceback.print_exc(file=buffer)
 
183
                action = 'raise'
 
184
                value = buffer.getvalue()
 
185
            if not done:
 
186
                fragments = []
 
187
                print_lisp(value, fragments.append, True)
 
188
                self.send(action, ''.join(fragments))
 
189
        return value
 
190
 
 
191
    def receive(self):
 
192
        # Receive a Python expression from Emacs, return (ACTION, TEXT).
 
193
        prefix = sys.stdin.read(3)
 
194
        if not prefix or prefix[0] != '>':
 
195
            if old_style_exception:
 
196
                raise ProtocolError, "`>' expected."
 
197
            raise ProtocolError("`>' expected.")
 
198
        while prefix[-1] != '\t':
 
199
            character = sys.stdin.read(1)
 
200
            if not character:
 
201
                if old_style_exception:
 
202
                    raise ProtocolError, "Empty stdin read."
 
203
                raise ProtocolError("Empty stdin read.")
 
204
            prefix += character
 
205
        text = sys.stdin.read(int(prefix[1:-1]))
 
206
        if run.debug_file is not None:
 
207
            file(run.debug_file, 'a').write(prefix + text)
 
208
        return text.split(None, 1)
 
209
 
 
210
    def send(self, action, text):
 
211
        # Send ACTION and its TEXT argument to Emacs.
 
212
        if self.freed:
 
213
            # All delayed Lisp cleanup is piggied back on the transmission.
 
214
            text = ('(free (%s) %s %s)\n'
 
215
                    % (' '.join(map(str, self.freed)), action, text))
 
216
            self.freed = []
 
217
        else:
 
218
            text = '(%s %s)\n' % (action, text)
 
219
        prefix = '<%d\t' % len(text)
 
220
        if run.debug_file is not None:
 
221
            file(run.debug_file, 'a').write(prefix + text)
 
222
        sys.stdout.write(prefix + text)
 
223
        sys.stdout.flush()
 
224
 
 
225
def pymacs_load_helper(file_without_extension, prefix):
 
226
    # This function imports a Python module, then returns a Lisp expression
 
227
    # which, when later evaluated, will install trampoline definitions in
 
228
    # Emacs for accessing the Python module facilities.  MODULE may be a
 
229
    # full path, yet without the `.py' or `.pyc' extension, in which case
 
230
    # the directory is temporarily added to the Python search path for
 
231
    # the sole duration of that import.  All defined symbols on the Lisp
 
232
    # side have have PREFIX prepended, and have Python underlines in Python
 
233
    # turned into dashes.  If PREFIX is None, it then defaults to the base
 
234
    # name of MODULE with underlines turned to dashes, followed by a dash.
 
235
    directory, module_name = os.path.split(file_without_extension)
 
236
    module_components = module_name.split('.')
 
237
    if prefix is None:
 
238
        prefix = module_components[-1].replace('_', '-') + '-'
 
239
    try:
 
240
        object = sys.modules.get(module_name)
 
241
        if object:
 
242
            reload(object)
 
243
        else:
 
244
            try:
 
245
                if directory:
 
246
                    sys.path.insert(0, directory)
 
247
                object = __import__(module_name)
 
248
            finally:
 
249
                if directory:
 
250
                    del sys.path[0]
 
251
            # Whenever MODULE_NAME is of the form [PACKAGE.]...MODULE,
 
252
            # __import__ returns the outer PACKAGE, not the module.
 
253
            for component in module_components[1:]:
 
254
                object = getattr(object, component)
 
255
    except ImportError:
 
256
        return None
 
257
    load_hook = object.__dict__.get('pymacs_load_hook')
 
258
    if load_hook:
 
259
        load_hook()
 
260
    interactions = object.__dict__.get('interactions', {})
 
261
    if not isinstance(interactions, dict):
 
262
        interactions = {}
 
263
    arguments = []
 
264
    for name, value in object.__dict__.items():
 
265
        if callable(value) and value is not lisp:
 
266
            arguments.append(allocate_python(value))
 
267
            arguments.append(lisp[prefix + name.replace('_', '-')])
 
268
            try:
 
269
                interaction = value.interaction
 
270
            except AttributeError:
 
271
                interaction = interactions.get(value)
 
272
            if callable(interaction):
 
273
                arguments.append(allocate_python(interaction))
 
274
            else:
 
275
                arguments.append(interaction)
 
276
    if arguments:
 
277
        return [lisp.progn,
 
278
                [lisp.pymacs_defuns, [lisp.quote, arguments]],
 
279
                object]
 
280
    return [lisp.quote, object]
 
281
 
 
282
def doc_string(object):
 
283
    if hasattr(object, '__doc__'):
 
284
        return object.__doc__
 
285
 
 
286
## Garbage collection matters.
 
287
 
 
288
# Many Python types do not have direct Lisp equivalents, and may not be
 
289
# directly returned to Lisp for this reason.  They are rather allocated in
 
290
# a list of handles, below, and a handle index is used for communication
 
291
# instead of the Python value.  Whenever such a handle is freed from the
 
292
# Lisp side, its index is added of a freed list for later reuse.
 
293
 
 
294
python = []
 
295
freed_list = []
 
296
 
 
297
def allocate_python(value):
 
298
    assert not isinstance(value, str), (type(value), repr(value))
 
299
    # Allocate some handle to hold VALUE, return its index.
 
300
    if freed_list:
 
301
        index = freed_list[-1]
 
302
        del freed_list[-1]
 
303
        python[index] = value
 
304
    else:
 
305
        index = len(python)
 
306
        python.append(value)
 
307
    return index
 
308
 
 
309
def free_python(*indices):
 
310
    # Return many handles to the pool.
 
311
    for index in indices:
 
312
        python[index] = None
 
313
        freed_list.append(index)
 
314
 
 
315
def zombie_python(*indices):
 
316
    # Ensure that some handles are _not_ in the pool.
 
317
    for index in indices:
 
318
        while index >= len(python):
 
319
            freed_list.append(len(python))
 
320
            python.append(None)
 
321
        python[index] = zombie
 
322
        freed_list.remove(index)
 
323
    # Merely to make `*Pymacs*' a bit more readable.
 
324
    freed_list.sort()
 
325
 
 
326
def zombie(*arguments):
 
327
    # This catch-all function is set as the value for any function which
 
328
    # disappeared with a previous Pymacs helper process, so calling
 
329
    # such a function from Emacs will trigger a decipherable diagnostic.
 
330
    diagnostic = "Object vanished when the Pymacs helper was killed"
 
331
    if lisp.pymacs_dreadful_zombies.value():
 
332
        if old_style_exception:
 
333
            raise ZombieError, diagnostic
 
334
        raise ZombieError(diagnostic)
 
335
    lisp.message(diagnostic)
 
336
 
 
337
## Emacs services for Python applications.
 
338
 
 
339
class Let:
 
340
 
 
341
    def __init__(self, **keywords):
 
342
        # The stack holds (METHOD, DATA) pairs, where METHOD is the expected
 
343
        # unbound pop_* method, and DATA holds information to be restored.
 
344
        # METHOD may not be bound to the instance, as this would induce
 
345
        # reference cycles, and then, __del__ would not be called timely.
 
346
        self.stack = []
 
347
        self.push(**keywords)
 
348
 
 
349
    def __del__(self):
 
350
        while self.stack:
 
351
            self.stack[-1][0](self)
 
352
 
 
353
    def __nonzero__(self):
 
354
        # So stylistic `if let:' executes faster.
 
355
        return True
 
356
 
 
357
    def push(self, **keywords):
 
358
        data = []
 
359
        for name, value in keywords.items():
 
360
            data.append((name, getattr(lisp, name).value()))
 
361
            setattr(lisp, name, value)
 
362
        self.stack.append((Let.pop, data))
 
363
        return self
 
364
 
 
365
    def pop(self):
 
366
        method, data = self.stack.pop()
 
367
        assert method == Let.pop, (method, data)
 
368
        for name, value in data:
 
369
            setattr(lisp, name, value)
 
370
 
 
371
    def push_excursion(self):
 
372
        self.stack.append((Let.pop_excursion, (lisp.current_buffer(),
 
373
                                               lisp.point_marker(),
 
374
                                               lisp.mark_marker())))
 
375
        return self
 
376
 
 
377
    def pop_excursion(self):
 
378
        method, data = self.stack.pop()
 
379
        assert method == Let.pop_excursion, (method, data)
 
380
        buffer, point_marker, mark_marker = data
 
381
        lisp.set_buffer(buffer)
 
382
        lisp.goto_char(point_marker)
 
383
        lisp.set_mark(mark_marker)
 
384
        lisp.set_marker(point_marker, None)
 
385
        lisp.set_marker(mark_marker, None)
 
386
 
 
387
    def push_match_data(self):
 
388
        self.stack.append((Let.pop_match_data, lisp.match_data()))
 
389
        return self
 
390
 
 
391
    def pop_match_data(self):
 
392
        method, data = self.stack.pop()
 
393
        assert method == Let.pop_match_data, (method, data)
 
394
        lisp.set_match_data(data)
 
395
 
 
396
    def push_restriction(self):
 
397
        self.stack.append((Let.pop_restriction, (lisp.point_min_marker(),
 
398
                                                 lisp.point_max_marker())))
 
399
        return self
 
400
 
 
401
    def pop_restriction(self):
 
402
        method, data = self.stack.pop()
 
403
        assert method == Let.pop_restriction, (method, data)
 
404
        point_min_marker, point_max_marker = data
 
405
        lisp.narrow_to_region(point_min_marker, point_max_marker)
 
406
        lisp.set_marker(point_min_marker, None)
 
407
        lisp.set_marker(point_max_marker, None)
 
408
 
 
409
    def push_selected_window(self):
 
410
        self.stack.append((Let.pop_selected_window, lisp.selected_window()))
 
411
        return self
 
412
 
 
413
    def pop_selected_window(self):
 
414
        method, data = self.stack.pop()
 
415
        assert method == Let.pop_selected_window, (method, data)
 
416
        lisp.select_window(data)
 
417
 
 
418
    def push_window_excursion(self):
 
419
        self.stack.append((Let.pop_window_excursion,
 
420
                           lisp.current_window_configuration()))
 
421
        return self
 
422
 
 
423
    def pop_window_excursion(self):
 
424
        method, data = self.stack.pop()
 
425
        assert method == Let.pop_window_excursion, (method, data)
 
426
        lisp.set_window_configuration(data)
 
427
 
 
428
class Symbol:
 
429
 
 
430
    def __init__(self, text):
 
431
        self.text = text
 
432
 
 
433
    def __repr__(self):
 
434
        return 'lisp[%s]' % repr(self.text)
 
435
 
 
436
    def __str__(self):
 
437
        return '\'' + self.text
 
438
 
 
439
    def value(self):
 
440
        return lisp._eval(self.text)
 
441
 
 
442
    def copy(self):
 
443
        return lisp._expand(self.text)
 
444
 
 
445
    def set(self, value):
 
446
        if value is None:
 
447
            lisp._eval('(setq %s nil)' % self.text)
 
448
        else:
 
449
            fragments = []
 
450
            write = fragments.append
 
451
            write('(progn (setq %s ' % self.text)
 
452
            print_lisp(value, write, True)
 
453
            write(') nil)')
 
454
            lisp._eval(''.join(fragments))
 
455
 
 
456
    def __call__(self, *arguments):
 
457
        fragments = []
 
458
        write = fragments.append
 
459
        write('(%s' % self.text)
 
460
        for argument in arguments:
 
461
            write(' ')
 
462
            print_lisp(argument, write, True)
 
463
        write(')')
 
464
        return lisp._eval(''.join(fragments))
 
465
 
 
466
class Lisp:
 
467
 
 
468
    def __init__(self, index):
 
469
        self.index = index
 
470
 
 
471
    def __del__(self):
 
472
        lisp._protocol.freed.append(self.index)
 
473
 
 
474
    def __repr__(self):
 
475
        return ('lisp(%s)' % repr(lisp('(prin1-to-string %s)' % self)))
 
476
 
 
477
    def __str__(self):
 
478
        return '(aref pymacs-lisp %d)' % self.index
 
479
 
 
480
    def value(self):
 
481
        return self
 
482
 
 
483
    def copy(self):
 
484
        return lisp._expand(str(self))
 
485
 
 
486
class Buffer(Lisp):
 
487
    pass
 
488
 
 
489
    #def write(text):
 
490
    #    # So you could do things like
 
491
    #    # print >>lisp.current_buffer(), "Hello World"
 
492
    #    lisp.insert(text, self)
 
493
 
 
494
    #def point(self):
 
495
    #    return lisp.point(self)
 
496
 
 
497
class List(Lisp):
 
498
 
 
499
    def __call__(self, *arguments):
 
500
        fragments = []
 
501
        write = fragments.append
 
502
        write('(%s' % self)
 
503
        for argument in arguments:
 
504
            write(' ')
 
505
            print_lisp(argument, write, True)
 
506
        write(')')
 
507
        return lisp._eval(''.join(fragments))
 
508
 
 
509
    def __len__(self):
 
510
        return lisp._eval('(length %s)' % self)
 
511
 
 
512
    def __getitem__(self, key):
 
513
        value = lisp._eval('(nth %d %s)' % (key, self))
 
514
        if value is None and key >= len(self):
 
515
            if old_style_exception:
 
516
                raise IndexError, key
 
517
            raise IndexError(key)
 
518
        return value
 
519
 
 
520
    def __setitem__(self, key, value):
 
521
        fragments = []
 
522
        write = fragments.append
 
523
        write('(setcar (nthcdr %d %s) ' % (key, self))
 
524
        print_lisp(value, write, True)
 
525
        write(')')
 
526
        lisp._eval(''.join(fragments))
 
527
 
 
528
class Table(Lisp):
 
529
 
 
530
    def __getitem__(self, key):
 
531
        fragments = []
 
532
        write = fragments.append
 
533
        write('(gethash ')
 
534
        print_lisp(key, write, True)
 
535
        write(' %s)' % self)
 
536
        return lisp._eval(''.join(fragments))
 
537
 
 
538
    def __setitem__(self, key, value):
 
539
        fragments = []
 
540
        write = fragments.append
 
541
        write('(puthash ')
 
542
        print_lisp(key, write, True)
 
543
        write(' ')
 
544
        print_lisp(value, write, True)
 
545
        write(' %s)' % self)
 
546
        lisp._eval(''.join(fragments))
 
547
 
 
548
class Vector(Lisp):
 
549
 
 
550
    def __len__(self):
 
551
        return lisp._eval('(length %s)' % self)
 
552
 
 
553
    def __getitem__(self, key):
 
554
        return lisp._eval('(aref %s %d)' % (self, key))
 
555
 
 
556
    def __setitem__(self, key, value):
 
557
        fragments = []
 
558
        write = fragments.append
 
559
        write('(aset %s %d ' % (self, key))
 
560
        print_lisp(value, write, True)
 
561
        write(')')
 
562
        lisp._eval(''.join(fragments))
 
563
 
 
564
class Lisp_Interface:
 
565
 
 
566
    def __init__(self):
 
567
        self.__dict__['_cache'] = {'nil': None}
 
568
        self.__dict__['_protocol'] = Protocol()
 
569
 
 
570
    def __call__(self, text):
 
571
        return self._eval('(progn %s)' % text)
 
572
 
 
573
    def _eval(self, text):
 
574
        self._protocol.send('eval', text)
 
575
        return self._protocol.loop()
 
576
 
 
577
    def _expand(self, text):
 
578
        self._protocol.send('expand', text)
 
579
        return self._protocol.loop()
 
580
 
 
581
    def __getattr__(self, name):
 
582
        if name[0] == '_':
 
583
            if old_style_exception:
 
584
                raise AttributeError, name
 
585
            raise AttributeError(name)
 
586
        return self[name.replace('_', '-')]
 
587
 
 
588
    def __setattr__(self, name, value):
 
589
        if name[0] == '_':
 
590
            if old_style_exception:
 
591
                raise AttributeError, name
 
592
            raise AttributeError(name)
 
593
        self[name.replace('_', '-')] = value
 
594
 
 
595
    def __getitem__(self, name):
 
596
        try:
 
597
            return self._cache[name]
 
598
        except KeyError:
 
599
            symbol = self._cache[name] = Symbol(name)
 
600
            return symbol
 
601
 
 
602
    def __setitem__(self, name, value):
 
603
        try:
 
604
            symbol = self._cache[name]
 
605
        except KeyError:
 
606
            symbol = self._cache[name] = Symbol(name)
 
607
        symbol.set(value)
 
608
 
 
609
lisp = Lisp_Interface()
 
610
 
 
611
print_lisp_quoted_specials = {
 
612
        '"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f',
 
613
        '\n': '\\n', '\r': '\\r', '\t': '\\t'}
 
614
 
 
615
def print_lisp(value, write, quoted):
 
616
    if value is None:
 
617
        write('nil')
 
618
    elif isinstance(value, bool):
 
619
        write(('nil', 't')[value])
 
620
    elif isinstance(value, int):
 
621
        write(repr(value))
 
622
    elif isinstance(value, float):
 
623
        write(repr(value))
 
624
    elif isinstance(value, basestring):
 
625
        multibyte = False
 
626
        if isinstance(value, unicode):
 
627
            try:
 
628
                value = value.encode('ASCII')
 
629
            except UnicodeEncodeError:
 
630
                value = value.encode('UTF-8')
 
631
                multibyte = True
 
632
        if multibyte:
 
633
            write('(decode-coding-string ')
 
634
        write('"')
 
635
        for character in value:
 
636
            special = print_lisp_quoted_specials.get(character)
 
637
            if special is not None:
 
638
                write(special)
 
639
            elif 32 <= ord(character) < 127:
 
640
                write(character)
 
641
            else:
 
642
                write('\\%.3o' % ord(character))
 
643
        write('"')
 
644
        if multibyte:
 
645
            write(' \'utf-8)')
 
646
    elif isinstance(value, list):
 
647
        if quoted:
 
648
            write("'")
 
649
        if len(value) == 0:
 
650
            write('nil')
 
651
        elif len(value) == 2 and value[0] == lisp.quote:
 
652
            write("'")
 
653
            print_lisp(value[1], write, False)
 
654
        else:
 
655
            write('(')
 
656
            print_lisp(value[0], write, False)
 
657
            for sub_value in value[1:]:
 
658
                write(' ')
 
659
                print_lisp(sub_value, write, False)
 
660
            write(')')
 
661
    elif isinstance(value, tuple):
 
662
        write('[')
 
663
        if len(value) > 0:
 
664
            print_lisp(value[0], write, False)
 
665
            for sub_value in value[1:]:
 
666
                write(' ')
 
667
                print_lisp(sub_value, write, False)
 
668
        write(']')
 
669
    elif isinstance(value, Lisp):
 
670
        write(str(value))
 
671
    elif isinstance(value, Symbol):
 
672
        if quoted:
 
673
            write("'")
 
674
        write(value.text)
 
675
    elif callable(value):
 
676
        write('(pymacs-defun %d nil)' % allocate_python(value))
 
677
    else:
 
678
        write('(pymacs-python %d)' % allocate_python(value))
 
679
 
 
680
if __name__ == '__main__':
 
681
    main(*sys.argv[1:])