* 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 An example of Sex source: #+begin_src (include stdio.h) (pub fn int main ((int argc) (char **argv)) (puts "Hello from Sex!") (var (array char 512) name) (puts "What is your name?") (scanf "%s" (cast char* &name)) (printf "Hello, %s!\n" name) 0) #+end_src Compile and run: #+begin_src ~/dev/sex $ ./sexc ./example/hello-world.sex -o hello-world ~/dev/sex $ ./hello-world Hello from Sex! What is your name? Alex Hello, Alex! #+end_src * Features ** Full C interoperability Just ~(include "Your/Favourite/Library.h")~ and use it as you would have is C. ** Auto unkebabification 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~. ** 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