Files
sex/Readme.org
2025-08-02 10:49:38 +03:00

225 lines
5.9 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
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