Skip to content

Instantly share code, notes, and snippets.

@tearflake
Last active June 23, 2025 13:50
Show Gist options
  • Save tearflake/569db7fdc8b363b7d320ebfeef8ab503 to your computer and use it in GitHub Desktop.
Save tearflake/569db7fdc8b363b7d320ebfeef8ab503 to your computer and use it in GitHub Desktop.

S-expr

[about document]
Peculiar kind of S-expressions specification document

[intended audience]
beginners in programming

table of contents

1. introduction

S-expressions (Symbolic Expressions) are a fundamental concept in computer science and programming language theory. S-expressions are a simple, yet powerful notation for representing nested list data structures and code in a parenthesized form. They are commonly associated with the Lisp family of programming languages, where they serve both as a way to represent code and data uniformly.

S-expr is a S-expression parsing library. Other than usual treatment of atoms and lists, it features peculiar decisions in syntax definition regarding strings, comments, and transposed blocks of contents.

2. informal definition

The general form of an S-expression is either:

  • An atom (e.g., atom), or
  • A list of S-expressions (e.g., (expr1 expr2 expr3)).

Lists can be nested, allowing for the representation of complex hierarchical structures. For example:

(eq (mul x x) (pow x 2))

This S-expression depicts equality between multiplication and square.

3. strings, comments and transposed blocks

Although a great part of S-expressions power lies in its simplicity, let's introduce a few extensions in a hope of making expressed code more readable, namely: strings, comments, and transposed blocks.

strings

Strings in S-expr may be single-line or multi-line. Single-line strings are atoms enclosed in "..." pairs, like in expression "this is a single-line string", and represent Unicode format strings. Multi-line strings are enclosed between an odd number greater than 1 of " symbols in the following manner:

"""
this is a
multi-line
string
       """

Enclosing between a pair of """ symbols, multi-line strings are bound in a rectangle between the start of the first """ symbol, and the end of the second """ symbol. Remember to be careful when modifying contents of multi-line strings to make sure that the end of the second """ symbol is always placed horizontally behind the longest line in the string.

Notice that it is also possible to write expressions like:

(fst-atom """   trd-atom)
          00001
          00002
          00003
            """

where the expression stands for three atoms in a list.

comments

Comment expressions are ignored by the system, and they serve as notes to help programmers reading their code. They are parsed just like strings, only using the / instead of the " symbol. Thus, a single-line comment may be written as /this is a single-line comment/, and may appear repeatedly wherever a whitespace is expected. An example of a multi-line comment may be:

///
this is a
multi-line
comment
       ///

Just like strings enclosing between a pair of """ symbols, multi-line comments are bound in a rectangle between the start of the first /// symbol, and the end of the second /// symbol. Notice that it is also possible to write expressions like:

///
00001 (
00002   fst-atom
00003   snd-atom
00004   trd-atom
00005 )
  ///

where the expression stands for three atoms in a list.

transposed blocks

S-expression based languages are often criticised for unreadable sequences at the end of expressions. Using transposed blocks may be a solution to this problem, but it comes with downsides, too.

Transposed blocks are something new and unusual in the world of S-expression parsing. They represent blocks of code where rows and columns diagonally swap their places. Naturally, vertically spanned S-expressions have ability to horizontally indent their contents. Analogously, Transposed blocks span horizontally, and have ability to vertically indent their contents, thus using two-dimensional space in a diagonally mirrored manner.

For example, the expression:

(impl (impl p (impl q r)) (impl (impl p q) (impl p r)))

may be also written with horizontal indenting as:

(
    impl
    (
        impl
        p
        (
            impl
            q
            r
        )
    )
    (
        impl
        (
            impl
            p
            q
        )
        (
            impl
            p
            r
        )
    )
)

which, in turn, may be transposed using * symbol sequences as in the following example:

* (                                               )
*   i (               ) (                       )
*   m   i p (       )     i (       ) (       )
    p   m     i q r       m   i p q     i p r
    l   p     m           p   m         m           *
        l     p           l   p         p           *
              l               l         l           *

Transposed blocks are noted by an odd number greater than 1 of * symbols spanned vertically. These blocks represent an attempt to tackle with unreadable sequences of parenthesis usually placed at the end of expressions when writing S-expression code. Thus, if the optional vertical indenting in transposed blocks follows the syntax tree of an expression, we may get more readable version of the original expression. Notice that we can nest transposed blocks where odd blocks in the sequence visually relate vertically regarding even blocks in the sequence.

Along with transposed blocks, as a final add-on, let's introduce transposed lines, vertically enclosed within a pair of single * symbols:

*
t
w
i
s
t
*

This expression behaves just like we wrote twist horizontally, in a single line. Combining it with transposed blocks, we can get this form of our transposed block from above:

* (                                                                                           )
*   *impl* (                               ) (                                              )   *
*            *impl* *p* (                )     *impl* (                ) (                )     *
                          *impl* *q* *r*                *impl* *p* *q*     *impl* *p* *r*       *

Transposed lines within this block are written horizontally because in the transposed block, rows and columns swap their place.

4. conclusion

We informally defined S-expr code format and introduced a very peculiar way to treat strings and comments. By the same rules, we also introduced a strange twist using transposed contents in a try to cope with bulk sequences of ending parenthesis. We tried to be consistent with these add-ons to keep possible implementation as simple as possible, but the resulting implementation is more complicated than it is in usual Lisp languages, which is not very desirable when designing S-expression parsers.

In the end, as an ASCII art, this approach may have some value, but as a programming tool, the approach may not be a good fit for everyone, especially if one seeks for a professional grade solution. The question we may pose is: how much would we let the child inside us to play.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment