225 lines
5.9 KiB
Org Mode
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
|