The Sex language
Sex is a S-expressions language, which transpiles to C.
Sex is also Chicken, since all source processing and compile-time computations are written in Chicken.
And Chicken is R5RS Scheme.
Compilation and usage
First, get yourself a Chicken. Second, some Chicken deps.
Install Chicken Eggs
By the way, there's a way to make Chicken install eggs non-globally. Refer to the documentation for more info: https://wiki.call-cc.org/man/5/Extension%20tools#changing-the-repository-location
chicken-install fmt getopt-long brev-separate
Compilation
make
Usage
You'll also need a C compiler, so pick any.
cat hello-world.sex | sexc > hello_world.c
cc hello_world.c -o hello_world
Example
Here is an example, demonstrating what Sex source looks like, and what it compiles too. An avid reader also shall notice how we call Chicken procedures in Sex source.
The Sex source:
(include stdio.h)
(define (foo)
"Hello from Chicken code!\n")
(pub fn int main ((int argc) (char **argv))
(puts "Hello from Sex!")
(var (array char 512) name)
(puts "What is your name?")
(scanf "%s" &name)
(printf "Hello, %s!\n" name)
(printf ,(foo))
0)
The resulting C source:
#include <stdio.h>
int main (int argc, char **argv) {
puts("Hello from Sex!");
char name[512];
puts("What is your name?");
scanf("%s", &name);
printf("Hello, %s!\n", name);
printf("Hello from Chicken code!\n");
return 0;
}
Features
Full C interoperability
Just (include "Your/Favourite/Library.h") and use it as you would
have is C.
For hardcore fans of traditional Lisp naming convention,
Sex offers automatic unkebabification 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.
Auto typedef for structs
Probably harmless idk. Example:
(struct foo
((float a)
(int b)))
expands to
typedef struct foo foo;
struct foo {
float a;
int b;
};
Templating (and Chickening)
Sex has support for template substitutions. Any piece of code can be
templated. After declaring, templates should be instanced in order to
be used. To instance template, use ,-prefixed form in Sex
code. During instancing, template arguments in the body get
replaced with provided values by the following rules:
- If the value is a symbol, all arguments in a body are replaced with the value, and also all parts of any other symbol equal to the value also get replaced.
- If the value is a non-symbolic form, all arguments in a body are replaced with it, but no symbolic substitution is performed.
In general, the form of a template declaration is like this:
(template (name (substitute-args ...) other-args ...)
body ...)
Examples:
Structure with templated value type
(template (foo (T))
(struct foo-T
((T value))))
,(foo '(float))
->
typedef struct foo_float foo_float;
struct foo_float {
float value;
};
Wrapper for checking return codes
(template (check-sdl-return (call message ret-code))
(if (< 0 call)
(begin
(puts message)
(return ret-code))))
(fn int init ()
,(check-sdl-return
'((SDL-Init SDL-INIT-VIDEO) "Failed to initialize SDL" 1))
...)
->
static int init () {
if (0 < SDL_Init(SDL_INIT_VIDEO)) {
puts("Failed to initialize SDL");
return 1;
}
return 0;
}
A bit of everything
(template (list-T (T))
(struct list-T
((T value)
((* list-T) next))))
(template (list-for-each (what-do type list-var elt-var))
(var type elt-var (-> list-var value))
(while (!= (-> list-var next) NULL)
what-do
(= list-var (-> list-var next))
(= elt-var (-> list-var value))))
; ... somewhere later
,(list-T '(int))
(pub fn void print-list (const list-int *l)
,(list-for-each '((printf "%d " v) int l v))
(printf "\n"))
Then will be expanded in the following code:
(typedef struct list_int list_int)
(struct list_int ((int value) ((* list_int) next)))
(%fun void
print_list
(const list_int *l)
(%var int v (-> l value))
(while (!= (-> l next) NULL)
(printf "%d " v)
(= l (-> l next))
(= v (-> l value)))
(printf "\n"))
And then translated to:
typedef struct list_int list_int;
struct list_int {
int value;
list_int *next;
};
void print_list (int const, int list_int, int *l) {
int v = l->value;
while (l->next != NULL) {
printf("%d ", v);
l = l->next;
v = l->value;
}
printf("\n");
}
Also, as a bonus, not only a template can be used after , in Sex
source, but in fact any Chicken code you want to run during the
transpilation.
Use an established environment for development
As Sex is S-expressions, you always have Emacs with paredit as your best option.