Files
sex/Readme.org

254 lines
6.4 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
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
** Summary
#+begin_src
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
-E, --preprocess Emit C code
--public-interface Get module's public interface
-h, --help Show this help
-m, --macro-expand Emit macro-expanded 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
#+end_src
** Compiling Hello World
#+begin_src
sexc ./examples/hell-world.sex -o hello
#+end_src
That't 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.
** 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
** 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: firs is relative to the source
being compiled location, and the second is ~SEX_MODULE_PATH~
environment variable.
Module's public interface consists of everything declarred
~pub~. Structures, function, templates, types, varialbes can be
public.
** Syntactic templates
Sex has support for template substitutions. Any piece of code can be
templated. Template declarations look like functions: they have a
name, an argument list and a body. When declared template is
encountered during reading of Sex code, its body will udergo syntactic
rewriting using the 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 non-symbolic form, all arguments in a body are
replaced with it, but no symbolic substitution is performed.
Formally, template declaration has the following syntax:
#+begin_src
(template (name . substitute-args) . body)
#+end_src
*** Examples:
**** Structure with templated value type
#+begin_src
(template (foo ?T)
(struct foo-?T
((?T value))))
(foo float)
#+end_src
->
#+begin_src
typedef struct foo_float foo_float;
struct foo_float {
float value;
};
#+end_src
Note that ~?~ at the start of template argument is not syntax, just
convention.
**** Wrapper for checking return codes
#+begin_src
(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)
...)
#+end_src
->
#+begin_src
static int init () {
if (0 < SDL_Init(SDL_INIT_VIDEO)) {
puts("Failed to initialize SDL");
return 1;
}
return 0;
}
#+end_src
**** A bit of everything
#+begin_src
(template (list-T ?T)
(struct list-?T
((?T value)
((* list-?T) next))))
(template (list-for-each type list-var elt-var body)
(var type elt-var (-> list-var value))
(while (!= (-> list-var next) NULL)
body
(= 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 int l v (printf "%d " 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 (const list_int *l) {
int v = l->value;
while (l->next != NULL) {
printf("%d ", v);
l = l->next;
v = l->value;
}
printf("\n");
}
#+end_src
** 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~:
#+begin_src
(use-package sex-mode
:load-path "/path/to/sex"
:mode ("\\.sex\\'" "\\.seh\\'"))
#+end_src
** COMING SOON?: Polymorphism