1
1
mirror of https://github.com/kanaka/mal.git synced 2024-07-15 01:20:29 +03:00
mal/impls/vala
Nicolas Boulenguez fbfe6784d2 Change quasiquote algorithm
- Add a `vec` built-in function in step7 so that `quasiquote` does not
  require `apply` from step9.
- Introduce quasiquoteexpand special in order to help debugging step7.
  This may also prepare newcomers to understand step8.
- Add soft tests.
- Do not quote numbers, strings and so on.

Should ideally have been in separate commits:
- elisp: simplify and fix (keyword :k)
- factor: fix copy/paste error in let*/step7, simplify eval-ast.
- guile: improve list/vector types
- haskell: revert evaluation during quasiquote
- logo, make: cosmetic issues
2020-08-11 01:01:56 +02:00
..
.gitignore Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
core.vala Change quasiquote algorithm 2020-08-11 01:01:56 +02:00
Dockerfile Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
env.vala Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
gc.vala Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
Makefile Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
printer.vala Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
reader.vala Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
README.md Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
run Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
step0_repl.vala Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
step1_read_print.vala Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
step2_eval.vala Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
step3_env.vala Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
step4_if_fn_do.vala Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
step5_tco.vala Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
step6_file.vala Move implementations into impls/ dir 2020-02-10 23:50:16 -06:00
step7_quote.vala Change quasiquote algorithm 2020-08-11 01:01:56 +02:00
step8_macros.vala Change quasiquote algorithm 2020-08-11 01:01:56 +02:00
step9_try.vala Change quasiquote algorithm 2020-08-11 01:01:56 +02:00
stepA_mal.vala Change quasiquote algorithm 2020-08-11 01:01:56 +02:00
types.vala Change quasiquote algorithm 2020-08-11 01:01:56 +02:00

Vala implementation

Notes on building:

  • With the Debian or Ubuntu packages valac and libreadline-dev installed, and GNU make, you should be able to build using the provided Makefile.

  • The build will not be warning-clean, because the shared modules like types.vala and core.vala are shared between all the stepN main programs, and not all the steps use all the functions in the shared modules, and the Vala compiler has no way to turn off the warning about unused pieces of source code.

  • The Vala compiler works by translating the program to C and then compiling that. The C compilation stage can sometimes encounter an error, in which case the compiler will leave .c source files in the working directory. If that happens, you can run make clean-c to get rid of them.

Design notes on the implementation:

  • Vala has exceptions (which it calls 'error domains'), but they don't let you store an arbitrary data type: every exception subclass you make stores the same data, namely a string. So mal exceptions are implemented by storing a mal value in a static variable, and then throwing a particular Vala error whose semantics are 'check that variable when you catch me'.

  • Vala's bare function pointers are hard to use, especially if you want one to survive the scope it was created in. So all the core functions are implemented as classes with a call method, which leads to a lot of boilerplate.

  • To make types.vala work in step 2, when the Env type doesn't exist yet, I had to use #if to condition out the parts of the code that depend on that type.

  • Mutability of objects at the Vala level is a bit informal. A lot of core functions construct a list by making an empty Mal.List and then mutating the GLib.List contained in it. But once they've finished and returned the Mal.List to their caller, that list is never mutated again, which means it's safe for the copying operation in with-meta to make a second Mal.List sharing the reference to the same GLib.List.

  • Vala has a reference counting system built in to the language, but that's not enough to implement mal sensibly, because the common construction (def! FUNC (fn* [ARGS] BODY)) causes a length-2 cycle of references: the environment captured in FUNC's function object is the same one where def! inserts the definition of FUNC, so the function and environment both link to each other. And either element of the cycle could end up being the last one referred to from elsewhere, so you can't break the link by just making the right one of those references weak. So instead there's a small garbage collector in gc.vala, which works by being the only part of the program that keeps a non-weak reference to any Mal.Val or Mal.Env: it links all GCable objects together into a list, and when the collector runs, it unlinks dead objects from that list and allows Vala's normal reference counting to free them.