SEXpy is an alternate S-expression syntax for the Python language.
$ ./sex.py SEXpy> (def (square x) (return (* x x))) SEXpy> (square 2) 4 SEXpy> (exit)
The easiest way to execute a SEXpy script is to use sex.py utility:
$ sex.py myscript.sex
SEXpy scripts can be also compiled to Python bytecode:
$ sex.py -c myscript.sex
The resulting bytecode file can be imported from a Python program or executed as a standalone script:
$ python myscript.pyc
Launching sex.py without arguments will give you an interactive shell. There is nothing special about it - just enter some expressions and see what happens.
Besides importing Python modules from SEXpy it is also possible to import SEXpy files from a Python program:
>>> from sexpy import import_file >>> foo = import_file('examples/foo.sex') >>> foo.bar() Test passed! ;-)
It is also possible to compile SEXpy code to Python bytecode:
$ sex.py -c foo.sexpy
The resulting .pyc file can be imported juat like a regular module:
>>> import foo >>> foo.bar() Test passed! ;-)
.pyc files can also be executed like a regular Python scripts:
$ python foo.pyc Test passed! ;-)
It is possible to construct SEXpy code at runtime. The rules are simple:
- SEXpy code is just a Python list or tuple
- use plain numbers for numeric literals
- use sexpy.String for string literals
- use sexpy.List for list literals
Here is what is looks like:
from sexpy import sex_compile, String as S code = ( ('=', 's', ('%', S("2 * 2 = %i"), ('*', 2, 2))), ('print', 's'), ) exec(sex_compile(code))
SEXpy is basically a straightforward translation of the Python AST into S-expressions.
SEXpy understands the following types of literal values:
names: | foo |
---|---|
integers: | 123 |
long integers: | 1000L |
floats: | 100.3e4 |
strings: | "I'm a string!" |
lists: | #(a b c) |
Bytestrings and dictionary literals are not (yet) supported. String escapes are also not supported, all strings in SEXpy behave like raw strings in Python.
Comments start with a semicolon. Pythonic string comments work too:
; What happen ? (print "All you base are belong to us.") ; Ha Ha Ha Ha .... "For great justice."
hello(a, b, spam) becomes (hello a b spam)
Keyword arguments (and many other things) are not (yet) supported.
foo.bar becomes (. foo bar) and foo.bar.baz becomes (. (. foo bar) baz). bar and baz must be plain names here, while foo can be an arbitrary expression.
To avoid unnessessary verbosity SEXpy supports foo.bar.baz notation (where foo, bar, and baz are plain names). In other words, Python's s.strip() can be written either as (s.strip) or as ((. s strip)), while for s.strip().toupper() you have to write ((. (. s strip) toupper)).
object[index] becomes (.. object index) which is ultimately unpythonic and counter-intuitive. If you can imagine some better syntax, let us know. :)
Most Python's arythmetic and comparison operators (+, -, >, <, etc.) are supported. The syntax is the same as for function calls: x * 2 becomes (+ x 2). Note that Python binary operators are still binary in SEXpy, so you have to write a1 * a2 * a3 as (* (* a1 a2) a3) (this may be changed in future versions of SEXpy). Also note that despite the syntax these operators are not first class functions in SEXpy (as well as in Python). If you want them to be functions, you probably need to have a look at operator module.
"x = %i" % x" becomes (% "x = %i" x).
Use (import foo bar baz) instead of import foo, bar, baz. Instead of from spam import eggs use (from spam import eggs). import keyword is just a syntax sugar here and can be omitted giving (from spam eggs).
Just use (raise SomeException). Of course, (raise (SomeException "Bad Thing happened")) is also possible.
Ironically, try, except and finally are not (yet) supported. Stay tuned. :)
if statement has the following syntax:
(if condigion1 ((statement1 statement2)) ((else_statements1 else_statement2)))
The else clause if optional.
Example:
if t >= 0: print "Nice weather!" go_for_a_walk() elif t < 0: print "Winter the Matushka has come!" else: print "Time to take some more red pills"
becomes:
(if (>= t 0) ((print "Nice weather!") (go_for_a_walk)) ((if (> t 0) ((print "Winter the Matushka has come!")) ((print "Time to take some more red pills")))))
elif is not supported yet.
for statement in SEXpy has the following syntax:
(for variable list statement1 statement2 ...)
Python's for i in [1, 2, 3]: print i becomes (for i #(1 2 3) (print i)). else clause is not supported.
while statement has the following syntax:
(while test statement1 statement2 ...)
else clause is not supported.
Function definitions are Scheme-style:
(def (hello name) (print (% "Hello %s!" name)) (print "Nice to meet you."))
Use (return something) to return a value:
(def (square x) (return (* x x)))
yield is also supported:
(def (squares n) (for i (range n) (yield (* i i))))
The general syntax is:
(class (classname baseclass1 baseclass2 ...) statement1 statement2 ...)
Here is an example:
class Egg(object): def __init__(self, animal): self.animal = animal def __str__(self): return "The amazing %s's egg!" % self.animal
becomes:
(class (Egg object) (def (__init__ self animal) (= (. self animal) animal)) (def (__str__ self) (return (% "The amazing %s's egg!" (. self animal)))))