Overview of python-spexy
A Python module for converting statements written in a LISP-like dialect directly into Python code.
As I have been reading through all this lost code and trying to get my mind wrapped around the concepts that underly it, I've discovered that I had set some rules for myself in this game of pre-processing.
- No non-user imports. The generated Python code is only allowed to import what the user explicitly asks it to import. It may not inject other imports (which means no functools or itertools).
- No additional dependencies. As an extension to the above, the generated Python code cannot require Spexy as a module to function at runtime.
- No non-user defines. Don't inject methods or variables into the output other than those that the user asks for.
The above makes this whole project significantly more interesting, and at the same time significantly less useful (as if that were possible) for other users. It's more like a puzzle and less like an actual project. Yay!
Here is the original README from 2007:
The idea here is to use Python's pluggable encoding support to create a pre-processor that will take a file of code in SEXP and generate something Python can actually use.
Effectively, you'll be writing in almost-lisp, but keeping the full functionality of Python. You'll be able to export the module you've written, and you'll be able to import any other Python module.
I got the idea from someone who wrote a curly-braces encoding for Python.
test.pyto see some "interesting" output.
Want to be able to switch between Python and Spexy-lisp at-will? Just use
spexy.repl(sys.stdin)from within your interactive Python session, and there you go! (quit) when you want to back out of the Spexy REPL, and you'll be back in Python, with all of your Spexy defines still available. Switch back and forth as often as you like.
In Python, some things are expressions and some things are statements. In Spexy, everything is an expression. There are a few things which I could not figure out ways to "express," such as try/except/finally, raise, yield, return, break, and print. However, a number of things which would normally be written as Python statements can instead be written as expressions, such as if/elif/else, multi-line code blocks (via progn), class definitions, for/while, and variable assignment.
The following are examples (from the original 2007 spexy.text) that show Spexy inputs and their resulting Python outputs.
Note that in many of these cases the actual implementation differs
from the example. The
defclass forms especially emit
wildly different code. I'll update them later, for now I'm just trying
to merge the scattered examples and documentation into one place.
Also note that as Python has evolved, better variants are now
available. In particular the spexy
if could be a Python
(let ((x 1) (y 2) (z (something 3))) (activity x y z))
(lambda x, y, z: \ (activity(x, y, z),)[-1])(,,[something(3)])
(let ((x 1) (y 2) (z None)) (setf z (something (+ x y))) (activity x y z))
(lambda x, y, z: \ (z.__setitem__(0, something(x + y)), activity(x, y, z))[-1])(, , [None])
if as an expression
(if foo 1 2)
((lambda: 1),(lambda: 2))[not (foo)]()
see note above regarding innaccuracies in examples
(define make_adder (lambda (by) (lambda (x) (+ x by)))) (define add_8 (make_adder 8))
make_adder = lambda by: lambda x: x + by add_8 = make_adder(8)
see note above regarding innaccuracies in examples
(defclass Foo (object) (define x 1) (defun __init__ (self x) (setf self 'x x))))
class Foo(object): x = 1 def __init__(self, x): self.setattr("x", x)
- Python 2.5 or later (no support for Python 3 -- but who cares, nobody should actually use this anyway)
Lost in time
The original spexy was posted into a CVS repository on a host which has long since been replaced, replaced again, and replaced again again. I wasn't able to dig up that original cvsroot. All I have is the checkout of what I presume to be the most up-to-date code.
If you need a material lesson on one of the many values of a distributed revision control system, let this serve as such. I most likely have lost any and all history (commit messages, diffs, timestamps, etc) for this project. Had I been using a DRCS, then I'd still have everything.
Luckily, the utility of this particular project is so negligible that I can safely say nothing of great value was lost.
author: Christopher O'Brien email@example.com
This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License along with this library; if not, see http://www.gnu.org/licenses/.