240 lines
7.3 KiB
Org Mode
240 lines
7.3 KiB
Org Mode
* The Sex language
|
|
|
|
#+NAME: the Sex logo
|
|
#+ATTR_HTML: :width 300px
|
|
[[sex.png][file:./sex.png]]
|
|
|
|
Sex is a S-expressions language. Sex is written in Chicken, which is an
|
|
[[https://call-cc.org][R7RS Scheme]].
|
|
Sex is statically typed, compiled general purpose language.
|
|
|
|
* Compilation
|
|
First, get yourself a Chicken, then, some Chicken deps. You also will
|
|
need a C compiler.
|
|
|
|
** Development
|
|
#+begin_src sh
|
|
make deps
|
|
make
|
|
#+end_src
|
|
|
|
~make deps~ installs pinned eggs from ~eggs.lock~ into a project-local
|
|
~.eggs/~ repository. ~dependencies.txt~ is the unpinned request list.
|
|
To refresh ~eggs.lock~ after changing it:
|
|
|
|
#+begin_src sh
|
|
make deps-update
|
|
#+end_src
|
|
|
|
** Packaging for system package managers
|
|
- Depend ~sex~ package on Chicken-6 (with ~libchicken.a~) and all eggs from ~dependencies.txt~.
|
|
- Compile and install with ~make~ (usually no other arguments required).
|
|
- Move resulting ~sexc~ binary to the appropriate place.
|
|
|
|
** Static compilation
|
|
The default ~CSC_FLAGS~ include ~-static~, so ~sexc~ does not need
|
|
~.eggs~ at runtime and ~make install~ stays relocatable. Chicken must
|
|
provide ~libchicken.a~ (E.g. for gentoo: ~dev-scheme/chicken~ with
|
|
~static-libs~ use flag).
|
|
|
|
To link dynamically instead (the binary will look for eggs under this
|
|
tree's ~.eggs~ path):
|
|
|
|
#+begin_src sh
|
|
make CSC_FLAGS='-K prefix'
|
|
#+end_src
|
|
|
|
** Installation
|
|
GNU directory variables: ~prefix~, ~exec_prefix~, ~bindir~, ~DESTDIR~.
|
|
|
|
#+begin_src sh
|
|
# default installation (/usr/local/bin/)
|
|
make install
|
|
# customize the prefix (installs to ~/.local/bin)
|
|
make prefix=$(HOME)/.local install
|
|
# staged install for packaging
|
|
make DESTDIR=/tmp/stage prefix=/usr install
|
|
#+end_src
|
|
|
|
* 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
|
|
-f, --features=ARG Comma-separated feature names, added to the host's own
|
|
for #+ and #- feature expressions. May be given
|
|
more than once
|
|
--no-platform-features Leave out the host's own features. With --features,
|
|
this reads a file the way another platform would
|
|
-C, --emit-c Emit C code
|
|
--public-interface Get module's public interface
|
|
-h, --help Show this help
|
|
-m, --macro-expand Emit macro-expanded semantically processed 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
|
|
--line-directives=ARG How much #line information to emit: statement (default),
|
|
toplevel, or none. `statement' is what makes a debugger
|
|
land on the right source line; `none' is for reading -C
|
|
output by eye
|
|
#+end_src
|
|
** Compiling Hello World
|
|
#+begin_src shell
|
|
sexc ./examples/hello-world.sex -o hello
|
|
#+end_src
|
|
|
|
That's 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.
|
|
|
|
Everything after ~--~ is handed to the C compiler exactly as written:
|
|
|
|
#+begin_src shell
|
|
sexc example/sdl3-triangle.sex -o triangle -- `pkg-config --cflags --libs sdl3` -framework OpenGL
|
|
#+end_src
|
|
|
|
** Example
|
|
An example of Sex source:
|
|
#+begin_src scheme
|
|
(include stdio.h)
|
|
|
|
(pub fn main ((argc int) (argv [* const char])) int
|
|
(puts "Hello from Sex!")
|
|
(var name [char 512])
|
|
(puts "What is your name?")
|
|
(scanf "%s" (cast (& name) (* char)))
|
|
(printf "Hello, %s!\n" name)
|
|
(return 0))
|
|
#+end_src
|
|
|
|
Compile and run:
|
|
#+begin_src shell
|
|
~/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 kebabification
|
|
For hardcore fans of traditional Lisp naming convention,
|
|
Sex offers automatic kebabification 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: first is relative to the source
|
|
being compiled location, and the second is ~SEX_MODULE_PATH~
|
|
environment variable.
|
|
|
|
Module's public interface consists of everything declared
|
|
~pub~. Structures, function, macros, types, variables can be
|
|
public.
|
|
|
|
** Read-time feature expressions
|
|
Sex is able to use ~#+~ and ~#-~ for conditional compilation: the form that
|
|
follows is kept only when the feature expression is true, and otherwise
|
|
is read and thrown away.
|
|
|
|
#+begin_src scheme
|
|
#+macosx (include OpenGL/gl3.h)
|
|
#-macosx (include GL/gl.h)
|
|
|
|
#+(and unix (not macosx)) (define HAVE-EPOLL 1)
|
|
#+end_src
|
|
|
|
An expression is a feature name, or ~and~, ~or~ and ~not~ of them.
|
|
|
|
This is read time, not compile time. What does not apply never reaches macro
|
|
expansion, the type database or the generated C.
|
|
|
|
The features are the host's ~(software-version)~, ~(software-type)~
|
|
and ~(machine-type)~, e.g. ~macosx unix arm64~ or ~linux unix
|
|
x86-64~. ~--features~ adds to them:
|
|
|
|
#+begin_src shell
|
|
sexc prog.sex -f debug,with-sdl
|
|
sexc prog.sex --features=debug --features=with-sdl
|
|
#+end_src
|
|
|
|
A feature is never taken away. The host's features can be disabled,
|
|
e.g. for checking output for other platform:
|
|
|
|
#+begin_src shell
|
|
sexc example/sdl3-triangle.sex -C --no-platform-features --features=linux,unix,x86-64
|
|
#+end_src
|
|
|
|
** Syntactic macros
|
|
Sex has support for syntactic macros. Macro definitions look like
|
|
functions: they have a name, an argument list and a body. Macro should
|
|
return Sex code.
|
|
|
|
*** Examples:
|
|
**** Structure with templated value type
|
|
#+begin_src scheme
|
|
(pub defmacro (list-T type)
|
|
(let ((list-type (cat 'list- type)))
|
|
`(struct ,list-type
|
|
((value ,type)
|
|
(next (* ,list-type))))))
|
|
|
|
(list-T int)
|
|
#+end_src
|
|
->
|
|
#+begin_src scheme
|
|
(struct list_int
|
|
((value int)
|
|
(next (* list_int))))
|
|
#+end_src
|
|
|
|
**** Wrapper for checking return codes
|
|
#+begin_src scheme
|
|
(pub defmacro (check-sdl-return call message ret-code)
|
|
`(if (< 0 ,call)
|
|
(do
|
|
(puts ,message)
|
|
(return ,ret-code))))
|
|
|
|
(pub fn init () int
|
|
(check-sdl-return
|
|
(SDL-Init SDL-INIT-VIDEO) "Failed to initialize SDL" 1)
|
|
...)
|
|
#+end_src
|
|
->
|
|
#+begin_src scheme
|
|
(pub fn init () int
|
|
(if (< 0 (SDL_Init SDL_INIT_VIDEO))
|
|
(do (puts "Failed to initialize SDL") (return 1)))
|
|
...)
|
|
#+end_src
|
|
|
|
** Compile-time type information
|
|
Sex has a number of type reflection features, aiming to help with
|
|
macro writing. During the compilation, all type info is collected, and
|
|
is accessible during macro expansion. This allows us to write things
|
|
like providing auto serialization, adding meta information, and so on.
|
|
|
|
** 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 emacs-lisp
|
|
(use-package sex-mode
|
|
:load-path "/path/to/sex"
|
|
:mode ("\\.sex\\'"))
|
|
#+end_src
|