176 lines
4.3 KiB
Org Mode
176 lines
4.3 KiB
Org Mode
* 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 [[https://call-cc.org][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.
|
|
#+begin_src
|
|
cat hello-world.sex | sexc > hello_world.c
|
|
cc hello_world.c -o hello_world
|
|
#+end_src
|
|
|
|
* 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:
|
|
#+begin_src
|
|
(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)
|
|
#+end_src
|
|
|
|
The resulting C source:
|
|
#+begin_src
|
|
#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;
|
|
}
|
|
#+end_src
|
|
|
|
* 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:
|
|
#+begin_src
|
|
(struct foo
|
|
((float a)
|
|
(int b)))
|
|
#+end_src
|
|
expands to
|
|
#+begin_src
|
|
typedef struct foo foo;
|
|
|
|
struct foo {
|
|
float a;
|
|
int b;
|
|
};
|
|
#+end_src
|
|
|
|
** 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:
|
|
1. 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.
|
|
2. If the value is a 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:
|
|
#+begin_src
|
|
(template (name (substiture-args ...) other-args ...)
|
|
body ...)
|
|
#+end_src
|
|
|
|
Exapmle:
|
|
#+begin_src
|
|
(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"))
|
|
#+end_src
|
|
Then will be expanded in the following code:
|
|
#+begin_src
|
|
(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"))
|
|
#+end_src
|
|
|
|
And then translated to:
|
|
#+begin_src
|
|
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");
|
|
}
|
|
#+end_src
|
|
|
|
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.
|
|
|
|
** COMING SOON: Polymorhpism
|