The Sex language
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'
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\\'"))