Files
sex/Readme.org

7.2 KiB

The Sex language

./sex.png

Sex is a S-expressions language. Sex is written in Chicken, which is an R7RS Scheme. Sex is statically typed, compiled general purpose language.

Compilation

First, get yourself a Chicken, then, some Chicken deps. You also will need a C compiler.

Install Chicken Eggs

Tip: there's a way to make Chicken install eggs non-globally. You need to export CHICKEN_INSTALL_REPOSITORY and CHICKEN_REPOSITORY_PATH environment variables. Refer to the documentation for more info: https://wiki.call-cc.org/man/5/Extension%20tools#changing-the-repository-location

chicken-install `cat dependencies.txt`

Compilation

  make

Static compilation

The default CSC_FLAGS include -static, so sexc does not need .eggs at runtime and make install stays relocatable. Chicken must provide libchicken.a (E.g. for gentoo: dev-scheme/chicken with static-libs use flag).

To link dynamically instead (the binary will look for eggs under this tree's .eggs path):

  make CSC_FLAGS='-K prefix'

Installation

GNU directory variables: prefix, exec_prefix, bindir, DESTDIR.

  # default installation (/usr/local/bin/)
  make install
  # customize the prefix (installs to ~/.local/bin)
  make prefix=$(HOME)/.local install
  # staged install for packaging
  make DESTDIR=/tmp/stage prefix=/usr install

Usage

Summary

Usage: sexc [options] filename [-- options-for-c-compiler]
Options:
 --c-compiler=ARG         Select C compiler. Defaults to value of SEX_CC
                          environment variable, or if it is empty, to cc
 -c, --compile-object     Compile object file instead of executable program
 -f, --features=ARG       Comma-separated feature names, added to the host's own
                          for #+ and #- feature expressions. May be given
                          more than once
 --no-platform-features   Leave out the host's own features. With --features,
                          this reads a file the way another platform would
 -C, --emit-c             Emit C code
 --public-interface       Get module's public interface
 -h, --help               Show this help
 -m, --macro-expand       Emit macro-expanded semantically processed Sex code
 -o, --output=ARG         Write output to file. Default file name is a.out.
                          If -E or -m options are provided, defaults to stdout
 --line-directives=ARG    How much #line information to emit: statement (default),
                          toplevel, or none. `statement' is what makes a debugger
                          land on the right source line; `none' is for reading -C
                          output by eye

Compiling Hello World

sexc ./examples/hello-world.sex -o hello

That's it. Now you should have executable named hello in your directory. Sex uses C under the hood, the default C compiler is cc, but you can pass any using --c-compiler option, or by setting SEX_CC environment variable.

Everything after -- is handed to the C compiler exactly as written:

sexc example/sdl3-triangle.sex -o triangle -- `pkg-config --cflags --libs sdl3` -framework OpenGL

Example

An example of Sex source:

(include stdio.h)

(pub fn main ((argc int) (argv  [* const char])) int
  (puts "Hello from Sex!")
  (var name [char 512])
  (puts "What is your name?")
  (scanf "%s" (cast (& name) (* char)))
  (printf "Hello, %s!\n" name)
  (return 0))

Compile and run:

~/dev/sex $ ./sexc ./example/hello-world.sex -o hello-world
~/dev/sex $ ./hello-world
Hello from Sex!
What is your name?
Alex
Hello, Alex!

Features

Full C interoperability

Just (include "Your/Favourite/Library.h") and use it as you would have is C.

Auto kebabification

For hardcore fans of traditional Lisp naming convention, Sex offers automatic kebabification of all symbols, i.e. no more ugly GL_ARRAY_BUFFER s in your code, they may be written in their proper form: GL-ARRAY-BUFFER.

Modules

Each source file is a module. Module can provide public interface and be imported by using (import path/to/module) expression. Module search path consists of two parts: first is relative to the source being compiled location, and the second is SEX_MODULE_PATH environment variable.

Module's public interface consists of everything declared pub. Structures, function, macros, types, variables can be public.

Read-time feature expressions

Sex is able to use #+ and #- for conditional compilation: the form that follows is kept only when the feature expression is true, and otherwise is read and thrown away.

#+macosx (include OpenGL/gl3.h)
#-macosx (include GL/gl.h)

#+(and unix (not macosx)) (define HAVE-EPOLL 1)

An expression is a feature name, or and, or and not of them.

This is read time, not compile time. What does not apply never reaches macro expansion, the type database or the generated C.

The features are the host's (software-version), (software-type) and (machine-type), e.g. macosx unix arm64 or linux unix x86-64. --features adds to them:

sexc prog.sex -f debug,with-sdl
sexc prog.sex --features=debug --features=with-sdl

A feature is never taken away. The host's features can be disabled, e.g. for checking output for other platform:

sexc example/sdl3-triangle.sex -C --no-platform-features --features=linux,unix,x86-64

Syntactic macros

Sex has support for syntactic macros. Macro definitions look like functions: they have a name, an argument list and a body. Macro should return Sex code.

Examples:

Structure with templated value type
(pub defmacro (list-T type)
  (let ((list-type (cat 'list- type)))
    `(struct ,list-type
       ((value ,type)
        (next (* ,list-type))))))

(list-T int)

->

(struct list_int
 ((value int)
  (next (* list_int))))
Wrapper for checking return codes
(pub defmacro (check-sdl-return call message ret-code)
  `(if (< 0 ,call)
       (do
         (puts ,message)
         (return ,ret-code))))

(pub fn init () int
  (check-sdl-return
    (SDL-Init SDL-INIT-VIDEO) "Failed to initialize SDL" 1)
...)

->

(pub fn init () int
  (if (< 0 (SDL_Init SDL_INIT_VIDEO))
    (do (puts "Failed to initialize SDL") (return 1)))
  ...)

Compile-time type information

Sex has a number of type reflection features, aiming to help with macro writing. During the compilation, all type info is collected, and is accessible during macro expansion. This allows us to write things like providing auto serialization, adding meta information, and so on.

Use an established environment for development

As Sex is S-expressions, you always have Emacs with paredit as your best option.

sex-mode.el

To harness the power of sex-mode, add the following lines to your $HOME/.config/emacs/init.el:

(use-package sex-mode
  :load-path "/path/to/sex"
  :mode ("\\.sex\\'"))