Value environment: standard library using `%external`

Merged E. Rivas requested to merge er433/poc/lib2 into dev


Implement a library using %external

This MR implements two libraries using %external: stdlib and testlib.

The library stdlib comprises the modules Tezos, Map, Big_map, List, Set, Option, Bitwise.

The library testlib comprises only the Test module.

The code looks a bit like (see build/

module Tezos = struct
  [@thunk] [@hidden] [@inline] let balance : tez = [%external "BALANCE"]
  [@hidden] [@inline] let voting_power (kh : key_hash) : nat = [%external "VOTING_POWER"] kh

The %external insertions (represented with an E_raw_code { language = "external" ; _ }) are replaced by the corresponding E_constant in the pass 05-self_ast_imperative (

Needed changes:

  • Abstraction: when we had a M.f, where M was one of the predefined modules, we had some special handling. This MR modifies the abstraction so that it works as a regular module access.
  • Having in the library let balance = [%external "BALANCE"] forces an evaluation of BALANCE in the interpreter (I think we should change the type of balance to be unit -> tez instead of just tez, but that's left to another MR). To prevent that, a new attribute was added @thunk, that make balance not to evaluate in the interpreter (V_Thunk values), and also force inlining in the compiling (15-self_mini_c).
  • Had to move CREATE_CONTRACT check of free variables to 15-self_mini_c: now stdlib functions like failwith are free variables (in the Tezos.create_contract argument). So I moved the check to mini-c, after inlining has been done.

There are two versions of the test library. A real one, and one that's used when we are not in the testing framework, in which everything fails. This is needed to keep remove_unused working.

TODO (future MRs?):

  • Improve the representation of libs (src/main/build/, we could write it in a .ligo file directly and include it as a resource, or compile it as an sexp, and prevent recompilation each time we load it.
  • Hack in monomorphisation: (* TODO: This is a hack needed for external typers, as they keep information *) -> find a more principled way of doing this. EDIT: after discussion with @lesenechal.remi , this hack has been improved.
  • Handle operations +, -, *, etc. in the same way (right now the abstractors for each language do custom things?)

Changelog details:

Breaking changes

  • Less lenient on the usage of Map and Big_map functions (e.g. Map.update will only work on maps and not on big_maps as before)
Edited by E. Rivas