SEXpy User's Manual

SEXpy is an alternate S-expression syntax for the Python language.

Synopsis

$ ./sex.py
SEXpy> (def (square x) (return (* x x)))
SEXpy> (square 2)
4
SEXpy> (exit)

Executing SEXpy code

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

Interactive shell

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.

Using SEXpy from Python programs

Importing SEXpy modules

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! ;-)

Constructing SEXpy code at runtime

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 Syntax Reference

SEXpy is basically a straightforward translation of the Python AST into S-expressions.

Literal values

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

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."

Function calls

hello(a, b, spam) becomes (hello a b spam)

Keyword arguments (and many other things) are not (yet) supported.

Attribute access

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)).

Item access

object[index] becomes (.. object index) which is ultimately unpythonic and counter-intuitive. If you can imagine some better syntax, let us know. :)

Operators

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.

String interpolation

"x = %i" % x" becomes (% "x = %i" x).

Module imports

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).

Raising exceptions

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

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

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

while statement has the following syntax:

(while test statement1 statement2 ...)

else clause is not supported.

Function definitions

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))))

Class definitions

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)))))