From 37bffe9ebe23d6d36885a6b6017f8df4e355135a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ma=C3=ABlle=20MARTIN?= <maelle.martin@proton.me>
Date: Tue, 20 Aug 2024 18:21:12 +0200
Subject: [PATCH] SCRIPT: Rework the codegen and passes + Cleanup

---
 README.md                                     |  10 +-
 rsc/licence/MPL-2.0                           | 347 ++++++++++++++
 src/Rust/Cargo.lock                           | 106 ++---
 src/Rust/Cargo.toml                           |  21 +-
 src/Rust/vvs_ass/Cargo.toml                   |   7 +-
 src/Rust/vvs_ass/src/styles.rs                |   2 +-
 src/Rust/vvs_cli/Cargo.toml                   |  31 +-
 src/Rust/vvs_cli/src/args.rs                  |   2 +-
 src/Rust/vvs_cli/src/config.rs                |  82 ++--
 src/Rust/vvs_cli/src/main.rs                  | 157 +++----
 src/Rust/vvs_codegen/Cargo.toml               |  23 +-
 src/Rust/vvs_codegen/build.rs                 |   3 -
 src/Rust/vvs_codegen/src/context.rs           | 105 -----
 src/Rust/vvs_codegen/src/error.rs             |  15 +
 src/Rust/vvs_codegen/src/graph.rs             |   2 +
 src/Rust/vvs_codegen/src/lib.rs               |  30 +-
 src/Rust/vvs_codegen/src/lowerer/calls.rs     | 108 -----
 src/Rust/vvs_codegen/src/lowerer/cast.rs      | 329 -------------
 src/Rust/vvs_codegen/src/lowerer/constant.rs  |  59 ---
 src/Rust/vvs_codegen/src/lowerer/drops.rs     | 109 -----
 .../vvs_codegen/src/lowerer/expression.rs     | 347 --------------
 src/Rust/vvs_codegen/src/lowerer/function.rs  |  55 ---
 .../vvs_codegen/src/lowerer/instruction.rs    | 431 -----------------
 src/Rust/vvs_codegen/src/lowerer/mod.rs       | 266 +++--------
 src/Rust/vvs_codegen/src/lowerer/types.rs     |  59 +--
 src/Rust/vvs_codegen/src/value.rs             | 100 ----
 src/Rust/vvs_font/build.rs                    |  44 +-
 src/Rust/vvs_lang/Cargo.toml                  |  21 -
 src/Rust/vvs_lang/src/ast/constant.rs         | 134 ------
 src/Rust/vvs_lang/src/ast/expression.rs       | 441 ------------------
 src/Rust/vvs_lang/src/ast/extension.rs        |  11 -
 src/Rust/vvs_lang/src/ast/function.rs         |  36 --
 src/Rust/vvs_lang/src/ast/identifier.rs       |  57 ---
 src/Rust/vvs_lang/src/ast/import.rs           |  77 ---
 src/Rust/vvs_lang/src/ast/instruction.rs      | 187 --------
 src/Rust/vvs_lang/src/ast/maybe_const_expr.rs |  26 --
 src/Rust/vvs_lang/src/ast/mod.rs              |  64 ---
 src/Rust/vvs_lang/src/ast/module.rs           | 201 --------
 src/Rust/vvs_lang/src/ast/options.rs          |  64 ---
 src/Rust/vvs_lang/src/ast/pattern.rs          |  39 --
 src/Rust/vvs_lang/src/ast/program.rs          | 140 ------
 src/Rust/vvs_lang/src/ast/span.rs             |  76 ---
 src/Rust/vvs_lang/src/ast/string.rs           |  28 --
 src/Rust/vvs_lang/src/ast/type_context.rs     | 180 -------
 src/Rust/vvs_lang/src/ast/typed.rs            |  17 -
 src/Rust/vvs_lang/src/ast/types.rs            | 226 ---------
 src/Rust/vvs_lang/src/ast/variable.rs         | 119 -----
 src/Rust/vvs_lang/src/ast/variant.rs          | 192 --------
 src/Rust/vvs_lang/src/ast/visibility.rs       |  77 ---
 src/Rust/vvs_lang/src/lib.rs                  |   4 -
 src/Rust/vvs_lib/Cargo.toml                   |   3 +-
 src/Rust/vvs_llvm/Cargo.toml                  |  19 +-
 src/Rust/vvs_llvm/src/bindings/mod.rs         |  16 +-
 src/Rust/vvs_llvm/src/bindings/module.rs      |   8 +
 src/Rust/vvs_llvm/src/bindings/types.rs       |  28 +-
 src/Rust/vvs_llvm/src/lib.rs                  |   4 +-
 src/Rust/vvs_parser/Cargo.toml                |   9 +-
 src/Rust/vvs_parser/samples/tag.vvs           |   2 +-
 src/Rust/vvs_parser/src/ast/mod.rs            |  84 +++-
 src/Rust/vvs_parser/src/ast/options.rs        |   2 +-
 .../src/ast/parsers/structs/result.rs         |  16 +-
 src/Rust/vvs_parser/src/lib.rs                |   7 +-
 src/Rust/vvs_parser/src/tokenizer/lexer.rs    |   3 +
 src/Rust/vvs_parser/src/vivy/error_report.rs  |   7 +
 .../vvs_parser/src/vivy/frontend_pipeline.rs  | 150 +++---
 src/Rust/vvs_parser/src/vivy/main_program.rs  |  21 +-
 src/Rust/vvs_parser/src/vivy/mod.rs           |   4 +-
 .../src/vivy/passes/opts_transform.rs         |   5 +-
 .../src/vivy/passes/stmt_checker.rs           |  28 +-
 .../src/vivy/passes/type_checker.rs           | 278 +++++++----
 src/Rust/vvs_parser/src/vivy/search_path.rs   |  31 +-
 src/Rust/vvs_parser/src/vivy/symbol_table.rs  |  28 +-
 src/Rust/vvs_parser_derive/Cargo.toml         |   6 +-
 src/Rust/vvs_procmacro/src/vvrt/gen.rs        |  61 +--
 src/Rust/vvs_runtime/Cargo.toml               |  15 +-
 src/Rust/vvs_runtime/src/jit.rs               |  35 +-
 src/Rust/vvs_runtime_types/Cargo.toml         |  19 +-
 src/Rust/vvs_runtime_types/src/mangle.rs      |  15 -
 src/Rust/vvs_runtime_types/src/vvll.rs        |  40 +-
 src/Rust/vvs_shortstring/Cargo.toml           |  17 +
 .../src/lib.rs}                               |   0
 src/Rust/vvs_utils/src/xdg/config.rs          | 249 +++-------
 src/Rust/vvs_utils/src/xdg/mod.rs             |  14 +-
 src/Rust/vvs_utils/src/xdg/traits.rs          |   7 +
 84 files changed, 1353 insertions(+), 5145 deletions(-)
 create mode 100644 rsc/licence/MPL-2.0
 delete mode 100644 src/Rust/vvs_codegen/build.rs
 delete mode 100644 src/Rust/vvs_codegen/src/context.rs
 create mode 100644 src/Rust/vvs_codegen/src/error.rs
 delete mode 100644 src/Rust/vvs_codegen/src/lowerer/calls.rs
 delete mode 100644 src/Rust/vvs_codegen/src/lowerer/cast.rs
 delete mode 100644 src/Rust/vvs_codegen/src/lowerer/constant.rs
 delete mode 100644 src/Rust/vvs_codegen/src/lowerer/drops.rs
 delete mode 100644 src/Rust/vvs_codegen/src/lowerer/expression.rs
 delete mode 100644 src/Rust/vvs_codegen/src/lowerer/function.rs
 delete mode 100644 src/Rust/vvs_codegen/src/lowerer/instruction.rs
 delete mode 100644 src/Rust/vvs_codegen/src/value.rs
 delete mode 100644 src/Rust/vvs_lang/Cargo.toml
 delete mode 100644 src/Rust/vvs_lang/src/ast/constant.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/expression.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/extension.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/function.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/identifier.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/import.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/instruction.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/maybe_const_expr.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/mod.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/module.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/options.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/pattern.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/program.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/span.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/string.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/type_context.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/typed.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/types.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/variable.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/variant.rs
 delete mode 100644 src/Rust/vvs_lang/src/ast/visibility.rs
 delete mode 100644 src/Rust/vvs_lang/src/lib.rs
 create mode 100644 src/Rust/vvs_shortstring/Cargo.toml
 rename src/Rust/{vvs_parser/src/short_string.rs => vvs_shortstring/src/lib.rs} (100%)
 create mode 100644 src/Rust/vvs_utils/src/xdg/traits.rs

diff --git a/README.md b/README.md
index ac7fa9ed..8aaa7e44 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
 - C++ compiler with [C++17 support](https://en.cppreference.com/w/cpp/17)
 - [mpv](https://mpv.io/) development library
 - [Qt6](https://www.qt.io/) development library: QtCore, QtWidgets, QtOpenGL, QtOpenGLWidgets.
-- The AV libraries in e recent version: libavutil libavcodec libavformat
+- The AV libraries in a recent version: libavutil libavcodec libavformat
 - [cbindgen](https://github.com/mozilla/cbindgen): `cargo install --force cbindgen`
 - [cargo-insta](https://insta.rs/docs/cli/): `cargo install --force cargo-insta`
 - Some unix utils, the `jq` binary, the `bash` shell.
@@ -18,7 +18,7 @@ Simply use cmake to build in another folder of the source folder:
 
 ```bash
 # Prepare, compile and install
-cmake -Bbuild -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_INSTALL_PREFIX=$HOME/.local -GNinja
+cmake -Bbuild -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_INSTALL_PREFIX=$HOME/.local -GNinja
 ninja -Cbuild
 ninja -Cbuild install
 ```
@@ -50,8 +50,8 @@ cargo depgraph --build-deps --dedup-transitive-deps | dot -Tpdf | zathura -
 ## Licence
 
 - The C++ part of this software is licenced under [the LGPL v3.0 or latter](/LICENSE)
-- The Rust part (Vivy Script) is under the [MIT license](/src/Rust/LICENSE.txt)
+- The most of the [Rust part](/src/Rust) (Vivy Script) is under the [MIT license](/src/Rust/LICENSE.txt)
 - The NotoSans fonts are distributed using the [OFL licence](/rsc/licence/OFL-1.1)
-- Some parts of the Rust folder (vvs_parser, vvs_parser_derive) are under the
-  [MPL-2.0](/src/Rust/full_moon/LICENSE.txt)
+- Some parts of the Rust folder ([vvs_parser](/src/Rust/vvs_parser), [vvs_parser_derive](/src/Rust/vvs_parser_derive))
+  are under the [MPL 2.0](/src/Rust/full_moon/LICENSE.txt) and was originally written by *Kampfkarren <kampfkarren@gmail.com>*
 
diff --git a/rsc/licence/MPL-2.0 b/rsc/licence/MPL-2.0
new file mode 100644
index 00000000..2b8bbd45
--- /dev/null
+++ b/rsc/licence/MPL-2.0
@@ -0,0 +1,347 @@
+Mozilla Public License Version 2.0
+==================================
+
+### 1. Definitions
+
+**1.1. “Contributor”**
+    means each individual or legal entity that creates, contributes to
+    the creation of, or owns Covered Software.
+
+**1.2. “Contributor Version”**
+    means the combination of the Contributions of others (if any) used
+    by a Contributor and that particular Contributor's Contribution.
+
+**1.3. “Contribution”**
+    means Covered Software of a particular Contributor.
+
+**1.4. “Covered Software”**
+    means Source Code Form to which the initial Contributor has attached
+    the notice in Exhibit A, the Executable Form of such Source Code
+    Form, and Modifications of such Source Code Form, in each case
+    including portions thereof.
+
+**1.5. “Incompatible With Secondary Licenses”**
+    means
+
+* **(a)** that the initial Contributor has attached the notice described
+    in Exhibit B to the Covered Software; or
+* **(b)** that the Covered Software was made available under the terms of
+    version 1.1 or earlier of the License, but not also under the
+    terms of a Secondary License.
+
+**1.6. “Executable Form”**
+    means any form of the work other than Source Code Form.
+
+**1.7. “Larger Work”**
+    means a work that combines Covered Software with other material, in
+    a separate file or files, that is not Covered Software.
+
+**1.8. “License”**
+    means this document.
+
+**1.9. “Licensable”**
+    means having the right to grant, to the maximum extent possible,
+    whether at the time of the initial grant or subsequently, any and
+    all of the rights conveyed by this License.
+
+**1.10. “Modifications”**
+    means any of the following:
+
+* **(a)** any file in Source Code Form that results from an addition to,
+    deletion from, or modification of the contents of Covered
+    Software; or
+* **(b)** any new file in Source Code Form that contains any Covered
+    Software.
+
+**1.11. “Patent Claims” of a Contributor**
+    means any patent claim(s), including without limitation, method,
+    process, and apparatus claims, in any patent Licensable by such
+    Contributor that would be infringed, but for the grant of the
+    License, by the making, using, selling, offering for sale, having
+    made, import, or transfer of either its Contributions or its
+    Contributor Version.
+
+**1.12. “Secondary License”**
+    means either the GNU General Public License, Version 2.0, the GNU
+    Lesser General Public License, Version 2.1, the GNU Affero General
+    Public License, Version 3.0, or any later versions of those
+    licenses.
+
+**1.13. “Source Code Form”**
+    means the form of the work preferred for making modifications.
+
+**1.14. “You” (or “Your”)**
+    means an individual or a legal entity exercising rights under this
+    License. For legal entities, “You” includes any entity that
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, “control” means **(a)** the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or **(b)** ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+### 2. License Grants and Conditions
+
+#### 2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+* **(a)** under intellectual property rights (other than patent or trademark)
+    Licensable by such Contributor to use, reproduce, make available,
+    modify, display, perform, distribute, and otherwise exploit its
+    Contributions, either on an unmodified basis, with Modifications, or
+    as part of a Larger Work; and
+* **(b)** under Patent Claims of such Contributor to make, use, sell, offer
+    for sale, have made, import, and otherwise transfer either its
+    Contributions or its Contributor Version.
+
+#### 2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+#### 2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+* **(a)** for any code that a Contributor has removed from Covered Software;
+    or
+* **(b)** for infringements caused by: **(i)** Your and any other third party's
+    modifications of Covered Software, or **(ii)** the combination of its
+    Contributions with other software (except as part of its Contributor
+    Version); or
+* **(c)** under Patent Claims infringed by Covered Software in the absence of
+    its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+#### 2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+#### 2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+#### 2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+#### 2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+### 3. Responsibilities
+
+#### 3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+#### 3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+* **(a)** such Covered Software must also be made available in Source Code
+    Form, as described in Section 3.1, and You must inform recipients of
+    the Executable Form how they can obtain a copy of such Source Code
+    Form by reasonable means in a timely manner, at a charge no more
+    than the cost of distribution to the recipient; and
+
+* **(b)** You may distribute such Executable Form under the terms of this
+    License, or sublicense it under different terms, provided that the
+    license for the Executable Form does not attempt to limit or alter
+    the recipients' rights in the Source Code Form under this License.
+
+#### 3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+#### 3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+#### 3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+### 4. Inability to Comply Due to Statute or Regulation
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: **(a)** comply with
+the terms of this License to the maximum extent possible; and **(b)**
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+### 5. Termination
+
+**5.1.** The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated **(a)** provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and **(b)** on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+**5.2.** If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+**5.3.** In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+### 6. Disclaimer of Warranty
+
+> Covered Software is provided under this License on an “as is”
+> basis, without warranty of any kind, either expressed, implied, or
+> statutory, including, without limitation, warranties that the
+> Covered Software is free of defects, merchantable, fit for a
+> particular purpose or non-infringing. The entire risk as to the
+> quality and performance of the Covered Software is with You.
+> Should any Covered Software prove defective in any respect, You
+> (not any Contributor) assume the cost of any necessary servicing,
+> repair, or correction. This disclaimer of warranty constitutes an
+> essential part of this License. No use of any Covered Software is
+> authorized under this License except under this disclaimer.
+
+### 7. Limitation of Liability
+
+> Under no circumstances and under no legal theory, whether tort
+> (including negligence), contract, or otherwise, shall any
+> Contributor, or anyone who distributes Covered Software as
+> permitted above, be liable to You for any direct, indirect,
+> special, incidental, or consequential damages of any character
+> including, without limitation, damages for lost profits, loss of
+> goodwill, work stoppage, computer failure or malfunction, or any
+> and all other commercial damages or losses, even if such party
+> shall have been informed of the possibility of such damages. This
+> limitation of liability shall not apply to liability for death or
+> personal injury resulting from such party's negligence to the
+> extent applicable law prohibits such limitation. Some
+> jurisdictions do not allow the exclusion or limitation of
+> incidental or consequential damages, so this exclusion and
+> limitation may not apply to You.
+
+### 8. Litigation
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+### 9. Miscellaneous
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+### 10. Versions of the License
+
+#### 10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+#### 10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+#### 10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+#### 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+## Exhibit A - Source Code Form License Notice
+
+    This Source Code Form is subject to the terms of the Mozilla Public
+    License, v. 2.0. If a copy of the MPL was not distributed with this
+    file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+## Exhibit B - “Incompatible With Secondary Licenses” Notice
+
+    This Source Code Form is "Incompatible With Secondary Licenses", as
+    defined by the Mozilla Public License, v. 2.0.
diff --git a/src/Rust/Cargo.lock b/src/Rust/Cargo.lock
index e4d015d1..08c11d2e 100644
--- a/src/Rust/Cargo.lock
+++ b/src/Rust/Cargo.lock
@@ -160,16 +160,19 @@ dependencies = [
  "quote",
  "serde",
  "serde_json",
- "syn 2.0.74",
+ "syn 2.0.75",
  "tempfile",
  "toml",
 ]
 
 [[package]]
 name = "cc"
-version = "1.1.10"
+version = "1.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292"
+checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48"
+dependencies = [
+ "shlex",
+]
 
 [[package]]
 name = "cfg-if"
@@ -206,9 +209,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.15"
+version = "4.5.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc"
+checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -229,9 +232,9 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.16"
+version = "4.5.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c677cd0126f3026d8b093fa29eae5d812fde5c05bc66dbb29d0374eea95113a"
+checksum = "1ee158892bd7ce77aa15c208abbdb73e155d191c287a659b57abd5adb92feb03"
 dependencies = [
  "clap",
 ]
@@ -245,7 +248,7 @@ dependencies = [
  "heck 0.5.0",
  "proc-macro2",
  "quote",
- "syn 2.0.74",
+ "syn 2.0.75",
 ]
 
 [[package]]
@@ -395,7 +398,7 @@ dependencies = [
  "convert_case",
  "proc-macro2",
  "quote",
- "syn 2.0.74",
+ "syn 2.0.75",
  "unicode-xid",
 ]
 
@@ -480,9 +483,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.9"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
 
 [[package]]
 name = "indexmap"
@@ -511,9 +514,9 @@ dependencies = [
 
 [[package]]
 name = "is-terminal"
-version = "0.4.12"
+version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
+checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
 dependencies = [
  "hermit-abi",
  "libc",
@@ -558,9 +561,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "libc"
-version = "0.2.155"
+version = "0.2.158"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
 
 [[package]]
 name = "linked-hash-map"
@@ -779,29 +782,29 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
 
 [[package]]
 name = "serde"
-version = "1.0.207"
+version = "1.0.208"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5665e14a49a4ea1b91029ba7d3bca9f299e1f7cfa194388ccc20f14743e784f2"
+checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.207"
+version = "1.0.208"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6aea2634c86b0e8ef2cfdc0c340baede54ec27b1e46febd7f80dffb2aa44a00e"
+checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.74",
+ "syn 2.0.75",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.124"
+version = "1.0.125"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d"
+checksum = "83c8e735a073ccf5be70aa8066aa984eaf2fa000db6c8d0100ae605b366d31ed"
 dependencies = [
  "indexmap",
  "itoa",
@@ -819,6 +822,12 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
 [[package]]
 name = "similar"
 version = "2.6.0"
@@ -853,9 +862,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.74"
+version = "2.0.75"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7"
+checksum = "f6af063034fc1935ede7be0122941bafa9bacb949334d090b77ca98b5817c7d9"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -911,7 +920,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.74",
+ "syn 2.0.75",
 ]
 
 [[package]]
@@ -1027,6 +1036,7 @@ dependencies = [
  "thiserror",
  "toml",
  "vvs_ass",
+ "vvs_codegen",
  "vvs_font",
  "vvs_llvm",
  "vvs_parser",
@@ -1038,15 +1048,13 @@ dependencies = [
 name = "vvs_codegen"
 version = "0.5.0"
 dependencies = [
- "anyhow",
  "hashbrown",
  "log",
- "serde",
- "serde_json",
- "vvs_lang",
+ "thiserror",
  "vvs_llvm",
+ "vvs_parser",
  "vvs_runtime_types",
- "vvs_utils",
+ "vvs_shortstring",
 ]
 
 [[package]]
@@ -1059,23 +1067,6 @@ dependencies = [
  "ttf-parser",
 ]
 
-[[package]]
-name = "vvs_lang"
-version = "0.5.0"
-dependencies = [
- "anyhow",
- "derive_more",
- "hashbrown",
- "log",
- "paste",
- "regex",
- "serde",
- "thiserror",
- "toml",
- "vvs_parser",
- "vvs_utils",
-]
-
 [[package]]
 name = "vvs_lib"
 version = "0.5.0"
@@ -1096,6 +1087,8 @@ dependencies = [
  "llvm-sys",
  "log",
  "paste",
+ "thiserror",
+ "vvs_shortstring",
 ]
 
 [[package]]
@@ -1117,6 +1110,7 @@ dependencies = [
  "smol_str",
  "termcolor",
  "vvs_parser_derive",
+ "vvs_shortstring",
 ]
 
 [[package]]
@@ -1136,7 +1130,7 @@ dependencies = [
  "anyhow",
  "proc-macro2",
  "quote",
- "syn 2.0.74",
+ "syn 2.0.75",
 ]
 
 [[package]]
@@ -1147,6 +1141,7 @@ dependencies = [
  "log",
  "serde",
  "serde_json",
+ "vvs_ass",
  "vvs_llvm",
  "vvs_runtime_types",
  "vvs_utils",
@@ -1163,12 +1158,19 @@ dependencies = [
  "serde_json",
  "unicode-segmentation",
  "vvs_ass",
- "vvs_lang",
  "vvs_llvm",
  "vvs_procmacro",
  "vvs_utils",
 ]
 
+[[package]]
+name = "vvs_shortstring"
+version = "0.5.0"
+dependencies = [
+ "serde",
+ "smol_str",
+]
+
 [[package]]
 name = "vvs_utils"
 version = "0.5.0"
@@ -1211,7 +1213,7 @@ dependencies = [
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.74",
+ "syn 2.0.75",
  "wasm-bindgen-shared",
 ]
 
@@ -1233,7 +1235,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.74",
+ "syn 2.0.75",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -1437,5 +1439,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.74",
+ "syn 2.0.75",
 ]
diff --git a/src/Rust/Cargo.toml b/src/Rust/Cargo.toml
index 840c7a05..6d16464d 100644
--- a/src/Rust/Cargo.toml
+++ b/src/Rust/Cargo.toml
@@ -4,17 +4,18 @@ members = ["vvs_*"]
 
 
 [workspace.package]
-version = "0.5.0"
-authors = [
-    "Maëlle Martin <maelle.martin@proton.me>",
-    "Kampfkarren <kampfkarren@gmail.com>",
-]
+version      = "0.5.0"
 description  = "The V5 of the Vivy Script utility to manipulate in an easy way ASS files"
 edition      = "2021"
 license      = "MIT"
 rust-version = "1.76"
 
 
+authors = [
+    "Maëlle Martin <maelle.martin@proton.me>",
+]
+
+
 [profile.release]
 debug         = false
 opt-level     = 3
@@ -37,11 +38,11 @@ vvs_procmacro     = { path = "vvs_procmacro"     }
 vvs_utils         = { path = "vvs_utils"         }
 vvs_font          = { path = "vvs_font"          }
 vvs_ass           = { path = "vvs_ass"           }
-vvs_lang          = { path = "vvs_lang"          }
 vvs_runtime       = { path = "vvs_runtime"       }
-vvs_codegen       = { path = "vvs_codegen"       }
 vvs_llvm          = { path = "vvs_llvm"          }
 vvs_runtime_types = { path = "vvs_runtime_types" }
+vvs_shortstring   = { path = "vvs_shortstring"   }
+vvs_codegen       = { path = "vvs_codegen"       }
 
 # Utils
 bytecount   = "*"
@@ -60,6 +61,8 @@ bitflags    = { version = "*", default-features = false }
 
 # Parsing
 unicode-segmentation = "*"
+codespan             = "*"
+codespan-reporting   = "*"
 regex = { version = "*", default-features = false, features = ["std"] }
 
 # SerDe
@@ -99,7 +102,5 @@ clap = { version = "*", default-features = false, features = [
 ] }
 
 # FOR FULL-MOON TESTS
-codespan           = "*"
-codespan-reporting = "*"
-criterion          = "*"
+criterion = "*"
 insta = { version = "*", features = ["glob", "yaml"] }
diff --git a/src/Rust/vvs_ass/Cargo.toml b/src/Rust/vvs_ass/Cargo.toml
index 7200e2fc..43d28806 100644
--- a/src/Rust/vvs_ass/Cargo.toml
+++ b/src/Rust/vvs_ass/Cargo.toml
@@ -7,10 +7,9 @@ edition.workspace = true
 license.workspace = true
 
 [dependencies]
-vvs_procmacro.workspace = true
-vvs_utils.workspace     = true
-vvs_font.workspace      = true
-
+vvs_procmacro.workspace        = true
+vvs_utils.workspace            = true
+vvs_font.workspace             = true
 unicode-segmentation.workspace = true
 thiserror.workspace            = true
 anyhow.workspace               = true
diff --git a/src/Rust/vvs_ass/src/styles.rs b/src/Rust/vvs_ass/src/styles.rs
index 612e64df..dd0e5d75 100644
--- a/src/Rust/vvs_ass/src/styles.rs
+++ b/src/Rust/vvs_ass/src/styles.rs
@@ -126,7 +126,7 @@ impl ASSStyle {
 impl Default for ASSStyle {
     fn default() -> Self {
         let font = vvs_font::embeded_fonts()
-            .first()
+            .next()
             .expect("we should at least bundle one font");
         let font = vvs_font::Font::try_from(font.1).expect("the font we bundle is not valid");
         let font_name = font.name().expect("the font we bundle doesn't have a valid name");
diff --git a/src/Rust/vvs_cli/Cargo.toml b/src/Rust/vvs_cli/Cargo.toml
index 36de30fc..9b915097 100644
--- a/src/Rust/vvs_cli/Cargo.toml
+++ b/src/Rust/vvs_cli/Cargo.toml
@@ -1,33 +1,32 @@
 [package]
-name = "vvs_cli"
+name        = "vvs_cli"
+description = "The CLI for VVS (VVCC)"
+
 version.workspace = true
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
-description = "The CLI for VVS (VVCC)"
 
 [[bin]]
 name = "vvcc"
 path = "src/main.rs"
 
 [dependencies]
-vvs_ass.workspace     = true
-vvs_font.workspace    = true
-vvs_utils.workspace   = true
-vvs_parser.workspace  = true
-vvs_runtime.workspace = true
-# vvs_codegen.workspace = true
-
-thiserror.workspace = true
-anyhow.workspace    = true
-serde.workspace     = true
-toml.workspace      = true
-log.workspace       = true
-
+vvs_ass.workspace       = true
+vvs_font.workspace      = true
+vvs_utils.workspace     = true
+vvs_parser.workspace    = true
+vvs_runtime.workspace   = true
+vvs_codegen.workspace   = true
+thiserror.workspace     = true
+anyhow.workspace        = true
+serde.workspace         = true
+toml.workspace          = true
+log.workspace           = true
 clap_mangen.workspace   = true
 clap_complete.workspace = true
 clap.workspace          = true
 
 [build-dependencies]
-anyhow.workspace   = true
+anyhow.workspace = true
 vvs_llvm = { workspace = true, features = ["link"] }
diff --git a/src/Rust/vvs_cli/src/args.rs b/src/Rust/vvs_cli/src/args.rs
index 9f75870f..08e8ea60 100644
--- a/src/Rust/vvs_cli/src/args.rs
+++ b/src/Rust/vvs_cli/src/args.rs
@@ -56,7 +56,7 @@ pub struct Args {
          , action = clap::ArgAction::Append
          , id     = "include"
     )]
-    pub include_folders: Vec<PathBuf>,
+    pub includes: Vec<PathBuf>,
 
     /// Shows informations about a script.
     ///
diff --git a/src/Rust/vvs_cli/src/config.rs b/src/Rust/vvs_cli/src/config.rs
index 0222b83d..fd5718aa 100644
--- a/src/Rust/vvs_cli/src/config.rs
+++ b/src/Rust/vvs_cli/src/config.rs
@@ -2,7 +2,9 @@ use crate::args::Args;
 use clap_complete::Shell;
 use serde::{Deserialize, Serialize};
 use std::path::PathBuf;
+use thiserror::Error;
 use vvs_utils::*;
+use xdg::XDGConfigFileSerde;
 
 #[derive(Debug, Serialize, Deserialize)]
 pub struct ConfigKaraMaker {
@@ -14,8 +16,7 @@ pub struct ConfigKaraMaker {
 
 #[derive(Debug, Default, Serialize, Deserialize)]
 pub struct ConfigFile {
-    #[serde(rename = "includes")]
-    include_folders: Vec<PathBuf>,
+    includes: Vec<PathBuf>,
 
     karamaker: ConfigKaraMaker,
 }
@@ -36,7 +37,28 @@ pub struct Config {
     pub verbose: u8,
 
     // Merge of the two
-    pub include_folders: Vec<PathBuf>,
+    pub includes: Vec<PathBuf>,
+}
+
+#[derive(Debug, Error)]
+pub enum ConfigFileError {
+    #[error("deserialization error: {0}")]
+    Deserialize(toml::de::Error),
+
+    #[error("serialization error: {0}")]
+    Serialize(toml::ser::Error),
+}
+
+impl XDGConfigFileSerde for ConfigFile {
+    type Error = ConfigFileError;
+
+    fn deserialize(input: &str) -> Result<Self, Self::Error> {
+        toml::from_str(input).map_err(ConfigFileError::Deserialize)
+    }
+
+    fn serialize(&self) -> Result<String, Self::Error> {
+        toml::to_string_pretty(self).map_err(ConfigFileError::Serialize)
+    }
 }
 
 macro_rules! merge {
@@ -65,47 +87,43 @@ impl Extend<ConfigFile> for ConfigFile {
         iter.into_iter().for_each(|other| {
             let (km, self_km) = (other.karamaker, &mut self.karamaker);
             merge! {
-                append   other => self,    { include_folders };
+                append   other => self,    { includes };
                 override km    => self_km, { kara_maker };
             }
         });
     }
 }
 
-impl Extend<ConfigFile> for Config {
-    fn extend<T: IntoIterator<Item = ConfigFile>>(&mut self, iter: T) {
-        iter.into_iter().for_each(|cfg| {
-            let km = cfg.karamaker;
-            merge! {
-                append   cfg => self, { include_folders };
-                override km  => self, { kara_maker };
-            }
-        });
+impl Config {
+    /// Extends the config from config files.
+    pub fn with_config_files(self, iter: impl IntoIterator<Item = ConfigFile>) -> Self {
+        iter.into_iter().fold(self, |this, cfg| this.with_config_file(cfg))
     }
-}
 
-impl Extend<Args> for Config {
-    fn extend<T: IntoIterator<Item = Args>>(&mut self, iter: T) {
-        iter.into_iter().for_each(|args| {
-            merge! {
-                append     args => self, { include_folders };
-                set_if_not args => self, { script, ass_file, options, shell, font_info };
-                max        args => self, { verbose };
-                override   args => self, { info, manpage };
-            }
-        });
+    /// Extends the config from config file.
+    pub fn with_config_file(mut self, cfg: ConfigFile) -> Self {
+        merge! {
+            append   cfg           => self, { includes };
+            override cfg.karamaker => self, { kara_maker };
+        }
+        self
     }
-}
 
-impl ConfigFile {
-    #[inline]
-    pub fn serialize(&self) -> Result<String, Box<dyn std::error::Error>> {
-        Ok(toml::to_string_pretty(self).map_err(Box::new)?)
+    /// Extends the config from command line arguments.
+    pub fn with_args(mut self, args: Args) -> Self {
+        merge! {
+            append     args => self, { includes };
+            set_if_not args => self, { script, ass_file, options, shell, font_info };
+            max        args => self, { verbose };
+            override   args => self, { info, manpage };
+        }
+        self
     }
 
-    #[inline]
-    pub fn deserialize(input: String) -> Result<Self, Box<dyn std::error::Error>> {
-        Ok(toml::from_str(&input).map_err(Box::new)?)
+    /// Apply the logger setting and returns self.
+    pub fn apply_logger(self) -> Self {
+        crate::logger::level(self.verbose);
+        self
     }
 }
 
diff --git a/src/Rust/vvs_cli/src/main.rs b/src/Rust/vvs_cli/src/main.rs
index 8c6cbf0b..154af093 100644
--- a/src/Rust/vvs_cli/src/main.rs
+++ b/src/Rust/vvs_cli/src/main.rs
@@ -1,22 +1,20 @@
 //! The VivyScript cli
 
-use crate::args::Args;
-use anyhow::{anyhow, Context, Result};
-use clap::CommandFactory;
-use std::{fs, io};
-use vvs_ass::{ass_container_from_file, ASSContainer};
+use anyhow::{Context as _, Result};
+use clap::CommandFactory as _;
+use std::{fs, io, path::Path};
 use vvs_cli::{
-    args,
+    args::Args,
     config::{Config, ConfigFile},
     logger,
 };
+use vvs_codegen::lowerer;
 use vvs_parser::prelude::*;
-use vvs_runtime::{types::VVRTTable, JIT};
 use vvs_utils::xdg::*;
 
-fn print_face_info(name: &str, font: &[u8]) -> Result<()> {
-    let font = vvs_font::Font::try_from(font).with_context(|| format!("failed to parse font {name}"))?;
-
+fn print_font(name: impl AsRef<Path>, font: &[u8]) -> Result<()> {
+    let name = name.as_ref();
+    let font = vvs_font::Font::try_from(font).with_context(|| format!("failed to parse font {}", name.display()))?;
     let font_types = font
         .font_types()
         .into_iter()
@@ -35,99 +33,72 @@ fn print_face_info(name: &str, font: &[u8]) -> Result<()> {
 
 fn main() -> Result<()> {
     logger::init(None).context("failed to init logger")?;
-    let mut config = Config::default();
-    config.extend([
-        XDGConfig::<ConfigFile, XDGConfigMergedSilent>::new("vvcc", ConfigFile::deserialize)
-            .file("vvcc.toml")
-            .read_or_default(ConfigFile::serialize),
-    ]);
-    config.extend([<Args as clap::Parser>::parse()]);
-    let Config {
-        script,
-        ass_file: ass_file_path,
-        options: options_path,
-        info,
-        manpage,
-        shell,
-        font_info,
-        verbose,
-        include_folders: _,
-        kara_maker,
-    } = config;
-    logger::level(verbose);
 
+    let Config { script, ass_file, options, info, manpage, shell, font_info, includes, .. } = Config::default()
+        .with_config_file(
+            XDGConfig::<ConfigFile, XDGConfigMergedSilent>::new("vvcc")
+                .file("vvcc.toml")
+                .read_or_default(),
+        )
+        .with_args(<Args as clap::Parser>::parse())
+        .apply_logger();
+
+    // Handle auxiliary stuff
     if manpage {
-        log::debug!(target: "vvcc", "generate the manpage for vvcc");
         return clap_mangen::Man::new(Args::command())
             .render(&mut io::stdout())
             .context("failed to render manpage for vvcc");
-    }
-
-    if let Some(shell) = shell {
-        log::debug!(target: "vvcc", "generate shell completion script for shell {shell}");
-        let mut command = Args::command();
-        let command_name = command.get_name().to_string();
-        clap_complete::generate(shell, &mut command, command_name, &mut io::stdout());
+    } else if let Some(shell) = shell {
+        clap_complete::generate(shell, &mut Args::command(), Args::command().get_name().to_string(), &mut io::stdout());
         return Ok(());
-    }
-
-    if let Some(font_info) = font_info {
+    } else if let Some(font_info) = font_info {
         return match font_info {
-            Some(path) => print_face_info(
-                &path.to_string_lossy(),
-                &fs::read(&path).with_context(|| format!("failed to read font: {}", path.to_string_lossy()))?,
-            ),
-            None => vvs_font::embeded_fonts()
-                .iter()
-                .try_for_each(|(n, f)| print_face_info(n, f)),
+            Some(p) => print_font(&p, &fs::read(&p).with_context(|| format!("failed to read font: {}", p.display()))?),
+            None => vvs_font::embeded_fonts().try_for_each(|(n, f)| print_font(n, f)),
         };
     }
 
-    match script {
-        None => Args::command()
-            .print_help()
-            .context("failed to print help message for vvcc"),
-
-        Some(script) => {
-            let script = SourceCode::from_path(script)?;
-            log::info!("run as `{kara_maker}` script `{}`", script.name());
-            if let Some(ref options) = options_path {
-                log::info!("use option file `{}`", options.display())
-            }
-
-            let output = FrontendPipeline::new(&script)
-                .passes(&[])
-                .options(options_path.as_ref())
-                .context("failed to parse option file")?
-                .run()
-                .context("failed to parse script files")?;
-
-            if info {
-                match ass_file_path {
-                    Some(ref path) => println!("ass file ........... {}", path.display()),
-                    None => println!("ass file ........... ø"),
-                }
-                match options_path {
-                    Some(path) => println!("options file ....... {}", path.display()),
-                    None => println!("options file ....... ø"),
-                }
-                println!("{output}");
-            }
-
-            // let FrontendOutput { ast, imports, main, options, library } = output;
-
-            let ass: ASSContainer<VVRTTable> = ass_container_from_file(
-                ass_file_path.ok_or_else(|| anyhow!("no subtitle file to run the script `{}` on", script.name()))?,
-            )
-            .context("failed to parse the subtitle file")?;
-
-            // let jit = JIT::new()?;
-            // let module = unsafe { LowererBuilder::new(script.name(), jit.ctx()) }.build().lower();
-            // unsafe { jit.add_module(module)? };
-
-            log::error!("use the ASS container and insert it into the JIT: {ass:#?}");
-
-            unimplemented!()
+    // Parse, build, execute the script.
+    let Some(script) = script else {
+        return Ok(Args::command().print_help()?);
+    };
+
+    let output = FrontendPipeline::new(&SourceCode::from_path(&script)?)
+        .passes(&[])
+        .search(
+            &SearchPath::from_iter(includes)
+                .with_script_folder(script.parent().context("expected the script to have a parent folder")?),
+        )
+        .options(options.as_ref())
+        .context("failed to parse option file")?
+        .run()
+        .context("failed to parse script files")?;
+
+    if info {
+        match ass_file {
+            Some(ref path) => println!("ass file ........... {}", path.display()),
+            None => println!("ass file ........... ø"),
         }
+        match options {
+            Some(path) => println!("options file ....... {}", path.display()),
+            None => println!("options file ....... ø"),
+        }
+        println!("{output}");
     }
+
+    let jit = vvs_runtime::JIT::new()?;
+    jit.with_module(
+        lowerer::Lowerer::new(&jit.ctx(), &output.main.name)?
+            .declare_globals(output.declared_functions())?
+            .lower_module(&output.main.name, output.ast)?
+            .lower_modules(output.imports)?
+            .generate_main(output.main)?
+            .finished(),
+    )?
+    .run_on_file(
+        vvs_ass::ass_container_from_file(ass_file.context("no subtitle file to run the script on")?)
+            .context("failed to parse the subtitle file")?,
+    )?;
+
+    Ok(())
 }
diff --git a/src/Rust/vvs_codegen/Cargo.toml b/src/Rust/vvs_codegen/Cargo.toml
index 8e67079a..4b083963 100644
--- a/src/Rust/vvs_codegen/Cargo.toml
+++ b/src/Rust/vvs_codegen/Cargo.toml
@@ -1,24 +1,21 @@
 [package]
-name = "vvs_codegen"
+name        = "vvs_codegen"
+description = "Code generation from Lua to LLVM-IR"
+
 version.workspace = true
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
-description = "The codegen into LLVM for Vivy Script"
 
 [dependencies]
-log.workspace        = true
-serde.workspace      = true
-serde_json.workspace = true
-anyhow.workspace     = true
-hashbrown.workspace  = true
-
+log.workspace               = true
+hashbrown.workspace         = true
+thiserror.workspace         = true
+vvs_shortstring.workspace   = true
+vvs_parser.workspace        = true
 vvs_runtime_types.workspace = true
-vvs_utils.workspace         = true
-vvs_lang.workspace          = true
 
 vvs_llvm = { workspace = true, features = ["bindings"] }
 
-[build-dependencies]
-vvs_llvm = { workspace = true, features = ["link"] }
-anyhow.workspace = true
+[dev-dependencies]
+vvs_llvm = { workspace = true, features = ["bindings", "link"] }
diff --git a/src/Rust/vvs_codegen/build.rs b/src/Rust/vvs_codegen/build.rs
deleted file mode 100644
index a0148072..00000000
--- a/src/Rust/vvs_codegen/build.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() -> anyhow::Result<()> {
-    vvs_llvm::build::llvm_link()
-}
diff --git a/src/Rust/vvs_codegen/src/context.rs b/src/Rust/vvs_codegen/src/context.rs
deleted file mode 100644
index 9ba934ef..00000000
--- a/src/Rust/vvs_codegen/src/context.rs
+++ /dev/null
@@ -1,105 +0,0 @@
-use crate::Value;
-use hashbrown::HashMap;
-use vvs_llvm::sys::*;
-use vvs_runtime_types::vvll::LLVMTypeIsManaged;
-
-/// Just a hashmap used to store values in scope.
-#[derive(Default, Clone)]
-pub(crate) struct ValueContext {
-    /// The values in context.
-    values: HashMap<Box<str>, Value>,
-
-    /// The values that are to be droped, in the order of their définition! They must be dropped in
-    /// the reverse order in which they are stored!
-    to_drop: Vec<Value>,
-
-    /// The number of anon values present in this context.
-    anon_count: u64,
-}
-
-impl ValueContext {
-    /// Create a new sub-context. We clone the available values but not the destructors to run as
-    /// we don't want to run them too early.
-    pub fn sub_context(&self) -> Self {
-        let Self { values, anon_count: i, .. } = self;
-        Self { values: values.clone(), anon_count: *i, to_drop: vec![] }
-    }
-
-    /// Register a new value in the context. We don't give a shit about its name, see if we need a
-    /// destructor for this value.
-    pub fn register_anon(&mut self, value: Value) {
-        if let Some(name) = value.as_str() {
-            let name = format!(".anon.{}:{}", self.anon_count, name);
-            self.anon_count += 1;
-            self.register(name, value)
-        }
-    }
-
-    /// Clone the context and register a new value into it. Used to reduce a bit calls to clone
-    /// everywhere...
-    pub fn to_register(&self, name: impl AsRef<str>, value: Value) -> Self {
-        let mut this = self.clone();
-        this.register(name, value);
-        this
-    }
-
-    /// Clone the context and register a new value into it. Used to reduce a bit calls to clone
-    /// everywhere...
-    pub fn to_register_anon(&self, value: Value) -> Self {
-        let mut this = self.clone();
-        this.register_anon(value);
-        this
-    }
-
-    /// Register a new value in the context.
-    pub fn register(&mut self, name: impl AsRef<str>, value: Value) {
-        fn inner(this: &mut ValueContext, name: &str, value: Value) {
-            log::error!("take into account destructors for {name}");
-            if Value::Nil == value {
-                panic!("can't register nil value `{name}`")
-            } else if this.values.insert(name.into(), value).is_some() {
-                panic!("multiple definitions of `{name}`")
-            }
-        }
-        inner(self, name.as_ref(), value)
-    }
-
-    /// Register a multiple values in the context.
-    pub fn register_all(&mut self, iter: impl IntoIterator<Item = (impl AsRef<str>, Value)>) {
-        iter.into_iter().for_each(|(name, value)| self.register(name, value));
-    }
-
-    /// Get the values to drop in this context in the order of their definition. Also remove them
-    /// from this context.
-    pub fn get_values_to_drop(&mut self) -> Vec<Value> {
-        std::mem::take(&mut self.to_drop)
-    }
-
-    /// Forget a value to drop by its llvm value ref. This way we can also forget anon values.
-    pub fn forget_by_llvm_value(&mut self, value: LLVMValueRef) {
-        use Value::*;
-        if let Some(idx) = self.to_drop.iter().enumerate().find_map(|(idx, val)| {
-            matches!(*val, Const(_, val) | Alloca(_, _, val) | Function(_, _, val) if val == value).then_some(idx)
-        }) {
-            self.to_drop.remove(idx);
-        }
-    }
-
-    /// Add values to drop from another context to extend their lifetime. We can't fail that thing
-    /// because we ignore values that are re-registered.
-    pub fn add_values_to_drop(&mut self, mut values: Vec<Value>) {
-        values.retain(|v| {
-            v.llvm_value()
-                .is_some_and(|v| self.to_drop.iter().any(|u| u.llvm_value().is_some_and(|u| u == v)))
-                && v.llvm_type().is_some_and(|t| unsafe { LLVMTypeIsManaged(t) })
-        });
-        self.to_drop.append(&mut values);
-    }
-
-    /// Get the value by its name in the context, or panic!
-    pub fn get_value(&self, name: impl AsRef<str>) -> &Value {
-        self.values
-            .get(name.as_ref())
-            .unwrap_or_else(|| panic!("failed to find value `{}`", name.as_ref()))
-    }
-}
diff --git a/src/Rust/vvs_codegen/src/error.rs b/src/Rust/vvs_codegen/src/error.rs
new file mode 100644
index 00000000..f77595c9
--- /dev/null
+++ b/src/Rust/vvs_codegen/src/error.rs
@@ -0,0 +1,15 @@
+use std::ffi::NulError;
+use thiserror::Error;
+use vvs_shortstring::ShortString;
+
+#[derive(Debug, Error)]
+pub enum CodegenError {
+    #[error("redefinition of function: {0}.{1}")]
+    RedefinedFunction(ShortString, ShortString),
+
+    #[error("nul byte in string: {0}")]
+    NulError(NulError),
+
+    #[error("{0}")]
+    Error(ShortString),
+}
diff --git a/src/Rust/vvs_codegen/src/graph.rs b/src/Rust/vvs_codegen/src/graph.rs
index 51388796..aa73009f 100644
--- a/src/Rust/vvs_codegen/src/graph.rs
+++ b/src/Rust/vvs_codegen/src/graph.rs
@@ -1,3 +1,5 @@
+#![allow(dead_code)]
+
 //! Small utility to store a basic block graph of a function to compute dominance of values.
 
 use hashbrown::HashSet;
diff --git a/src/Rust/vvs_codegen/src/lib.rs b/src/Rust/vvs_codegen/src/lib.rs
index 6da3d4ee..57d8d548 100644
--- a/src/Rust/vvs_codegen/src/lib.rs
+++ b/src/Rust/vvs_codegen/src/lib.rs
@@ -1,29 +1,7 @@
-//! The code used to lower the Vivy Script AST into LLVM code.
+mod error;
 
-mod context;
-mod graph;
-// mod lowerer;
-mod value;
+pub(crate) mod graph;
 
-// Exports in this crate.
-use crate::{context::*, graph::*, value::*};
+pub mod lowerer;
 
-// Re-exports.
-// pub use lowerer::{Lowerer, LowererBuilder};
-
-type LLVMLowerContext = (vvs_llvm::sys::LLVMModuleRef, vvs_llvm::sys::LLVMContextRef, vvs_llvm::sys::LLVMBuilderRef);
-
-/// The number of temp / unnamed values.
-static mut TEMP_NAME_COUNTER: u64 = 0;
-
-#[macro_export]
-macro_rules! cstr {
-    ($str: literal, $($arg: expr),+ $(,)?) => {
-        format!(concat!($str, "\0"), $($arg),+).as_ptr() as *const i8
-    };
-
-    () => {{
-        $crate::TEMP_NAME_COUNTER += 1;
-        format!(".temp.{}\0", $crate::TEMP_NAME_COUNTER).as_ptr() as *const i8
-    }};
-}
+pub use error::CodegenError;
diff --git a/src/Rust/vvs_codegen/src/lowerer/calls.rs b/src/Rust/vvs_codegen/src/lowerer/calls.rs
deleted file mode 100644
index b9d0be84..00000000
--- a/src/Rust/vvs_codegen/src/lowerer/calls.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-use crate::lowerer::*;
-use vvs_lang::ast::*;
-use vvs_llvm::*;
-
-/// Lower a single instruction.
-pub(super) struct CallLowerer<'a> {
-    llvm: LLVMLowerContext,
-    ctx: &'a ValueContext,
-}
-
-impl<'a> CallLowerer<'a> {
-    pub(super) fn new(llvm: LLVMLowerContext, ctx: &'a ValueContext) -> Self {
-        Self { llvm, ctx }
-    }
-
-    pub(super) unsafe fn call_intrinsic<const N: usize>(
-        name: &'static str,
-        (m, _, b): LLVMLowerContext,
-        ret: LLVMTypeRef,
-        mut args: [LLVMValueRef; N],
-    ) -> LLVMValueRef {
-        let id = LLVMLookupIntrinsicID(name.as_ptr() as *const _, name.len());
-        let mut args_ty: Vec<_> = args.iter().map(|val| LLVMTypeOf(*val)).collect();
-        let (args_ty, args_len, args) = (args_ty.as_mut_ptr(), args.len().try_into().unwrap(), args.as_mut_ptr());
-        let (functy, func) = (
-            LLVMFunctionType(ret, args_ty, args_len, 0),
-            LLVMGetIntrinsicDeclaration(m, id, args_ty, args_len as usize),
-        );
-        LLVMBuildCall2(b, functy, func, args, args_len, cstr!())
-    }
-
-    pub(super) fn lower_method_invok(
-        self,
-        obj: &ASTExpr,
-        func: impl AsRef<str>,
-        args: &[ASTExpr],
-    ) -> (ValueContext, Value) {
-        let Self { llvm: llvm @ (_, c, b), ctx } = self;
-
-        let (ctx, object) = ExpressionLowerer::with_assumed_type(llvm, obj, ctx).lower();
-        let (oty, obj) = (object.get_ast_type(), object.loaded(c, b));
-
-        let (aargs, rty, lty, lfn) = match ctx.get_value(VVRTSymbol::method(oty, func.as_ref()).unwrap().to_string()) {
-            Value::Function(ASTType::Function(aargs, rty), lty, lfn) if args.len() == aargs.len() => {
-                (aargs.clone(), rty.clone(), *lty, *lfn)
-            }
-            val => unreachable!("unexpected not a function value: {val:?}"),
-        };
-
-        let mut largs = Vec::with_capacity(args.len());
-        let largc = 1 + args.len() as u32;
-        largs.push(obj);
-        let ctx = args.iter().zip(aargs).fold(ctx, |ctx, (arg, ty)| {
-            let (ctx, arg) = ExpressionLowerer::with_expected_type(llvm, arg, &ty, &ctx).lower();
-            largs.push(arg.loaded(c, b));
-            ctx
-        });
-
-        match *rty {
-            ASTType::Nil => unsafe {
-                LLVMBuildCall2(b, lty, lfn, largs.as_mut_ptr(), largc, c"".as_ptr());
-                (ctx, Value::Nil)
-            },
-            ty => unsafe {
-                let ret_ty = TypeLowerer::new(c, &ty).lower();
-                let ptr = LLVMBuildAlloca(b, ret_ty, cstr!());
-                let val = LLVMBuildCall2(b, lty, lfn, largs.as_mut_ptr(), largc, cstr!());
-                LLVMBuildStore(b, val, ptr);
-                (ctx, Value::Alloca(ty, ret_ty, ptr))
-            },
-        }
-    }
-
-    pub(super) fn lower_func_call(self, func: &ASTExpr, args: &[ASTExpr]) -> (ValueContext, Value) {
-        let Self { llvm: llvm @ (_, c, b), ctx } = self;
-
-        let (ctx, aty, rty_ast, lty, lfn) =
-            match ExpressionLowerer::with_expected_type(llvm, func, &ASTType::Nil, ctx).lower() {
-                (ctx, Value::Function(ASTType::Function(aty, rty), lty, lfn)) if args.len() == aty.len() => {
-                    (ctx, aty, rty, lty, lfn)
-                }
-                (_, what) => unreachable!("unexpected not-a-function-thingy: {what:?}"),
-            };
-
-        let mut largs = Vec::with_capacity(args.len());
-        let args_len = args.len().try_into().expect("too many arguments");
-        let mut ctx = args.iter().zip(aty).fold(ctx, |ctx, (arg, ty)| {
-            let (ctx, expr) = ExpressionLowerer::with_expected_type(llvm, arg, &ty, &ctx).lower();
-            largs.push(expr.loaded(c, b));
-            ctx
-        });
-
-        match unsafe { LLVMGetReturnType(lty) } {
-            rty if rty == unsafe { LLVMVoidTypeInContext(c) } => unsafe {
-                LLVMBuildCall2(b, lty, lfn, largs.as_mut_ptr(), args_len, c"".as_ptr());
-                (ctx, Value::Nil)
-            },
-            rty => unsafe {
-                let val = LLVMBuildCall2(b, lty, lfn, largs.as_mut_ptr(), args_len, cstr!());
-                let ptr = LLVMBuildAlloca(b, rty, c".ignored".as_ptr());
-                LLVMBuildStore(b, val, ptr);
-                let value = Value::Alloca(*rty_ast, rty, ptr);
-                ctx.register_anon(value.clone());
-                (ctx, value)
-            },
-        }
-    }
-}
diff --git a/src/Rust/vvs_codegen/src/lowerer/cast.rs b/src/Rust/vvs_codegen/src/lowerer/cast.rs
deleted file mode 100644
index 4d818f3a..00000000
--- a/src/Rust/vvs_codegen/src/lowerer/cast.rs
+++ /dev/null
@@ -1,329 +0,0 @@
-use crate::lowerer::*;
-use vvs_lang::ast::*;
-use vvs_llvm::*;
-use vvs_runtime_types::{types::*, vvll::LLVMExported};
-
-pub(super) struct CastLowerer<'a> {
-    llvm: LLVMLowerContext,
-
-    source: &'a Value,
-    from_type: &'a ASTType,
-    as_type: &'a ASTType,
-
-    ctx: &'a ValueContext,
-}
-
-/// Represents the value that was casted by the [CastLowerer] lowerer.
-#[derive(Debug)]
-pub(super) enum CastedValue {
-    /// A value can be [CastedValue::Unchanged] which means that we did nothing to it. you don't
-    /// need to register it again to trop it as it's nothing new...
-    Unchanged { value: Value },
-
-    /// A value can be [CastedValue::Dynamic] which means that we generated code to try to convert
-    /// the thing at runtime. The first element is the flag which is set to true if we did succeed,
-    /// false otherwise. This is an `i8` and must be checked at runtime. Because we created a
-    /// value, we muste register it to be dropped latter if needed.
-    Dynamic { flag: LLVMValueRef, value: Value },
-
-    /// A value can be [CastedValue::Static], which means that we did generate the code to cast the
-    /// thing and that we will always succeed. We still need to register this value to be dropped
-    /// if necessary...
-    Static { value: Value },
-}
-
-impl<'a> CastLowerer<'a> {
-    /// Create a new [CastLowerer] from an AST value.
-    pub fn from_ast(llvm: LLVMLowerContext, source: &'a ASTVar, as_type: &'a ASTType, ctx: &'a ValueContext) -> Self {
-        Self::from_llvm(llvm, ctx.get_value(source.name()), as_type, ctx)
-    }
-
-    /// Create a new [CastLowerer] from a LLVM value.
-    pub fn from_llvm(llvm: LLVMLowerContext, source: &'a Value, as_type: &'a ASTType, ctx: &'a ValueContext) -> Self {
-        Self { llvm, source, as_type, from_type: source.get_ast_type(), ctx }
-    }
-
-    /// Tells if the types are the same and we don't need to do the casting.
-    fn is_same_type(from: &ASTType, to: &ASTType) -> bool {
-        (to == from)
-            || (to.is_table() && from.is_table())
-            || (to.is_sequence() && from.is_sequence())
-            || (to.is_variant() && from.is_variant())
-    }
-
-    /// Lower in a static context, meaning that we assume that the casting process must succeed and
-    /// must not require a runtime check.
-    pub fn lower_static(self) -> CastedValue {
-        use ASTType::*;
-        let Self { llvm: llvm @ (_, c, b), source, from_type, as_type, ctx } = self;
-
-        if matches!(as_type, Nil) {
-            return CastedValue::Unchanged { value: ConstantLowerer::new(c, &ASTConst::Nil).lower() };
-        } else if Self::is_same_type(from_type, as_type) {
-            return CastedValue::Unchanged { value: source.clone() };
-        }
-
-        let loaded = source.loaded(c, b);
-        let store_into_ptr = |ty: ASTType, value: LLVMValueRef| unsafe {
-            let ptr = LLVMBuildAlloca(b, LLVMTypeOf(value), cstr!());
-            LLVMBuildStore(b, value, ptr);
-            CastedValue::Static { value: Value::Alloca(ty, LLVMTypeOf(value), ptr) }
-        };
-
-        macro_rules! build_into {
-            ($ty: ident: $conv: ident) => {
-                unsafe {
-                    let llvm_type = TypeLowerer::new(c, &$ty).lower();
-                    let ptr = LLVMBuildAlloca(b, llvm_type, cstr!());
-                    LLVMBuildStore(b, $conv(b, loaded, llvm_type, cstr!()), ptr);
-                    CastedValue::Static { value: Value::Alloca($ty, llvm_type, ptr) }
-                }
-            };
-        }
-
-        match from_type {
-            Nil => match as_type {
-                Integer => CastedValue::Static {
-                    value: Value::Const(Integer, unsafe {
-                        LLVMConstInt(TypeLowerer::new(c, &Integer).lower(), Default::default(), 0)
-                    }),
-                },
-                Floating => CastedValue::Static {
-                    value: Value::Const(Floating, unsafe {
-                        LLVMConstReal(TypeLowerer::new(c, &Floating).lower(), Default::default())
-                    }),
-                },
-                Boolean => CastedValue::Static {
-                    value: Value::Const(Boolean, unsafe {
-                        LLVMConstInt(TypeLowerer::new(c, &Boolean).lower(), Default::default(), 0)
-                    }),
-                },
-                ty if ty.is_table() => store_into_ptr(AnyTable, ctx.get_value("VVRTTable_new").call(b, [])),
-                ty if ty.is_sequence() => store_into_ptr(AnySequence, ctx.get_value("VVRTSeq_new").call(b, [])),
-                Any => store_into_ptr(Any, ctx.get_value("VVRTAny_nil").call(b, [])),
-                as_type => panic!("can't convert `{from_type} into {as_type}`"),
-            },
-
-            Integer => match as_type {
-                Integer => CastedValue::Unchanged { value: source.clone() },
-                Boolean => build_into! { Boolean: LLVMBuildIntCast },
-                Floating => build_into! { Floating: LLVMBuildSIToFP },
-                Any => store_into_ptr(Any, ctx.get_value("VVRTAny_from_integer").call(b, [loaded])),
-                as_type => panic!("can't convert `{from_type} into {as_type}`"),
-            },
-
-            Floating => match as_type {
-                Floating => CastedValue::Unchanged { value: source.clone() },
-                Integer => build_into! { Integer: LLVMBuildFPToSI },
-                Boolean => build_into! { Boolean: LLVMBuildFPToSI },
-                Any => store_into_ptr(Any, ctx.get_value("VVRTAny_from_floating").call(b, [loaded])),
-                as_type => panic!("can't convert `{from_type} into {as_type}`"),
-            },
-
-            Boolean => match as_type {
-                Boolean => CastedValue::Unchanged { value: source.clone() },
-                Integer => build_into! { Integer: LLVMBuildIntCast },
-                Floating => build_into! { Floating: LLVMBuildSIToFP },
-                Any => store_into_ptr(Any, ctx.get_value("VVRTAny_from_boolean").call(b, [loaded])),
-                as_type => panic!("can't convert `{from_type} into {as_type}`"),
-            },
-
-            ty if ty.is_sequence() => match as_type {
-                Any => store_into_ptr(Any, ctx.get_value("VVRTAny_from_seq").call(b, [source.loaded(c, b)])),
-                as_type => panic!("can't convert `{from_type} into {as_type}`"),
-            },
-
-            Tuple(tuple) => match as_type {
-                Tuple(as_tuple) if tuple.len() == as_tuple.len() => unsafe {
-                    let as_llvm = TypeLowerer::new(c, as_type).lower();
-                    let from_tuple = TypeLowerer::new(c, from_type).lower();
-                    let ptr = LLVMBuildAlloca(b, as_llvm, cstr!());
-
-                    tuple.iter().enumerate().for_each(|(idx, from)| {
-                        // Get the value that we must coerce.
-                        let from_ptr = LLVMBuildStructGEP2(b, from_tuple, loaded, idx as u32, cstr!());
-                        let from_val = Value::Alloca(from.clone(), TypeLowerer::new(c, from).lower(), from_ptr);
-
-                        // Because of how we define tuples, we don't have to register the temp
-                        // values here, they should only be integers, floats or booleans.
-                        let value = match CastLowerer::from_llvm(llvm, &from_val, as_type, ctx).lower_static() {
-                            CastedValue::Unchanged { value } | CastedValue::Static { value } => value.loaded(c, b),
-                            casted => unreachable!("should have statically casted, got: {casted:?}"),
-                        };
-                        let mut idxs = [
-                            LLVMConstInt(LLVMInt32TypeInContext(c), 0, 0),
-                            LLVMConstInt(LLVMInt32TypeInContext(c), idx as u64, 0),
-                        ];
-                        let ptr = LLVMBuildGEP2(b, as_llvm, ptr, idxs.as_mut_ptr(), idxs.len() as u32, cstr!());
-                        LLVMBuildStore(b, value, ptr);
-                    });
-
-                    CastedValue::Static { value: Value::Alloca(as_type.clone(), as_llvm, ptr) }
-                },
-
-                ty if ty.is_numeric() && tuple.len() == 1 => unsafe {
-                    let from_val = Value::Alloca(
-                        tuple[0].clone(),
-                        TypeLowerer::new(c, &tuple[0]).lower(),
-                        LLVMBuildStructGEP2(b, TypeLowerer::new(c, from_type).lower(), loaded, 0, cstr!()),
-                    );
-                    CastLowerer::from_llvm(llvm, &from_val, ty, ctx).lower_static()
-                },
-
-                ty if ty.is_table() => unsafe {
-                    let table = ctx.get_value("VVRTTable_new").call(b, []);
-                    let from_tuple = TypeLowerer::new(c, from_type).lower();
-
-                    tuple.iter().enumerate().for_each(|(idx, from)| {
-                        let from_ptr = LLVMBuildStructGEP2(b, from_tuple, loaded, idx as u32, cstr!());
-                        let from_val = Value::Alloca(from.clone(), TypeLowerer::new(c, from).lower(), from_ptr);
-
-                        // Here we don't need to clone because we know that all types whithing a
-                        // tuple are trivially copiable.
-                        let value = match CastLowerer::from_llvm(llvm, &from_val, &Any, ctx).lower_static() {
-                            CastedValue::Unchanged { value } | CastedValue::Static { value } => value.loaded(c, b),
-                            casted => unreachable!("should have statically casted, got: {casted:?}"),
-                        };
-
-                        let key = idx.to_string();
-                        let (key, len) = (
-                            LLVMConstStringInContext(c, key.as_ptr() as *const _, key.len() as u32, 1),
-                            LLVMConstInt(LLVMInt32TypeInContext(c), key.len() as u64, 0),
-                        );
-                        ctx.get_value("VVRTTable_insert_from_raw_key")
-                            .call(b, [table, key, len, value]);
-                    });
-
-                    let ptr = LLVMBuildAlloca(b, VVRTTable::llvm_type(c), cstr!());
-                    LLVMBuildStore(b, table, ptr);
-                    CastedValue::Static { value: Value::Alloca(AnyTable, VVRTTable::llvm_type(c), ptr) }
-                },
-
-                ty if ty.is_sequence() => unsafe {
-                    let seq = ctx.get_value("VVRTSeq_new").call(b, []);
-                    let from_tuple = TypeLowerer::new(c, from_type).lower();
-
-                    tuple.iter().enumerate().for_each(|(idx, from)| {
-                        let from_ptr = LLVMBuildStructGEP2(b, from_tuple, loaded, idx as u32, cstr!());
-                        let from_val = Value::Alloca(from.clone(), TypeLowerer::new(c, from).lower(), from_ptr);
-
-                        // Here we don't need to clone because we know that all types whithing a
-                        // tuple are trivially copiable.
-                        let value = match CastLowerer::from_llvm(llvm, &from_val, &Any, ctx).lower_static() {
-                            CastedValue::Unchanged { value } | CastedValue::Static { value } => value.loaded(c, b),
-                            casted => unreachable!("should have statically casted, got: {casted:?}"),
-                        };
-
-                        ctx.get_value("VVRTSeq_push").call(b, [seq, value]);
-                    });
-
-                    let ptr = LLVMBuildAlloca(b, VVRTSeq::llvm_type(c), cstr!());
-                    LLVMBuildStore(b, seq, ptr);
-                    CastedValue::Static { value: Value::Alloca(AnySequence, VVRTSeq::llvm_type(c), ptr) }
-                },
-
-                as_type => panic!("can't convert `{from_type} into {as_type}`"),
-            },
-
-            ty if ty.is_variant() => match as_type {
-                as_type if as_type.is_table() => todo!(),
-                String => store_into_ptr(String, ctx.get_value("VVRTVariant_to_string").call(b, [loaded])),
-                Any => store_into_ptr(Any, ctx.get_value("VVRTAny_from_variant").call(b, [loaded])),
-                as_type => panic!("can't convert `{from_type} into {as_type}`"),
-            },
-
-            // Forbiden casts or Dynamic casts
-            ty => panic!("can't cast a value of type `{ty}` or this type need a runtime check to do the cast"),
-        }
-    }
-
-    /// Try to do the lowering at runtime, if it failed we guarenty that the value will be nil and
-    /// that no values will need to be dropped. In case of success we calling function must
-    /// register the value in the context.
-    pub fn lower_dynamic(self) -> CastedValue {
-        use ASTType::*;
-        let Self { llvm: (_, c, b), source, from_type, as_type, ctx } = self;
-
-        if matches!(as_type, Nil) && !matches!(from_type, ASTType::Any) {
-            return CastedValue::Unchanged { value: ConstantLowerer::new(c, &ASTConst::Nil).lower() };
-        } else if Self::is_same_type(from_type, as_type) {
-            return CastedValue::Unchanged { value: source.clone() };
-        }
-
-        let loaded = source.loaded(c, b);
-        let store_into_ptr = |ty: ASTType, value: LLVMValueRef| unsafe {
-            let ptr = LLVMBuildAlloca(b, LLVMTypeOf(value), cstr!());
-            LLVMBuildStore(b, value, ptr);
-            Value::Alloca(ty, LLVMTypeOf(value), ptr)
-        };
-        let any_is_ty = |ty: VVRTType| {
-            ctx.get_value("VVRTAny_is_ty")
-                .call(b, [loaded, unsafe { ty.as_llvm_const(c) }])
-        };
-
-        match from_type {
-            ty if ty.is_table() => match as_type {
-                Any => CastedValue::Static {
-                    value: store_into_ptr(Any, ctx.get_value("VVRTAny_from_table").call(b, [loaded])),
-                },
-                ty if ty.is_variant() => todo!(),
-                ty if ty.is_sequence() => todo!(),
-                as_type => panic!("can't convert `{from_type} into {as_type}`"),
-            },
-
-            // Get value out of any.
-            Any => match as_type {
-                Nil => CastedValue::Dynamic {
-                    flag: any_is_ty(VVRTType::Nil),
-                    value: ConstantLowerer::new(c, &ASTConst::Nil).lower(),
-                },
-                Integer => CastedValue::Dynamic {
-                    flag: any_is_ty(VVRTType::Number),
-                    value: store_into_ptr(Integer, ctx.get_value("VVRTAny_maybe_as_integer").call(b, [loaded])),
-                },
-                Boolean => CastedValue::Dynamic {
-                    flag: any_is_ty(VVRTType::Number),
-                    value: store_into_ptr(Boolean, ctx.get_value("VVRTAny_maybe_as_boolean").call(b, [loaded])),
-                },
-                Floating => CastedValue::Dynamic {
-                    flag: any_is_ty(VVRTType::Number),
-                    value: store_into_ptr(Floating, ctx.get_value("VVRTAny_maybe_as_floating").call(b, [loaded])),
-                },
-                String => {
-                    let val = ctx.get_value("VVRTAny_maybe_as_string").call(b, [loaded]);
-                    let val = ctx.get_value("VVRTString_clone").call(b, [val]);
-                    CastedValue::Dynamic { flag: any_is_ty(VVRTType::String), value: store_into_ptr(String, val) }
-                }
-                Syllabe => {
-                    let val = ctx.get_value("VVRTAny_maybe_as_syllabe").call(b, [loaded]);
-                    let val = ctx.get_value("VVRTSyllabe_clone").call(b, [val]);
-                    CastedValue::Dynamic { flag: any_is_ty(VVRTType::ASSSyllabe), value: store_into_ptr(Syllabe, val) }
-                }
-                Line => {
-                    let val = ctx.get_value("VVRTAny_maybe_as_line").call(b, [loaded]);
-                    let val = ctx.get_value("VVRTLine_clone").call(b, [val]);
-                    CastedValue::Dynamic { flag: any_is_ty(VVRTType::ASSLine), value: store_into_ptr(Line, val) }
-                }
-                ty if ty.is_variant() => {
-                    let val = ctx.get_value("VVRTAny_maybe_as_variant").call(b, [loaded]);
-                    let val = ctx.get_value("VVRTVariant_clone").call(b, [val]);
-                    CastedValue::Dynamic { flag: any_is_ty(VVRTType::Variant), value: store_into_ptr(Variant, val) }
-                }
-                ty if ty.is_table() => {
-                    let val = ctx.get_value("VVRTAny_maybe_as_table").call(b, [loaded]);
-                    let val = ctx.get_value("VVRTTable_clone").call(b, [val]);
-                    CastedValue::Dynamic { flag: any_is_ty(VVRTType::Table), value: store_into_ptr(AnyTable, val) }
-                }
-                ty if ty.is_sequence() => {
-                    let val = ctx.get_value("VVRTAny_maybe_as_seq").call(b, [loaded]);
-                    let val = ctx.get_value("VVRTSeq_clone").call(b, [val]);
-                    CastedValue::Dynamic { flag: any_is_ty(VVRTType::Seq), value: store_into_ptr(AnySequence, val) }
-                }
-                as_type => panic!("can't convert `{from_type} into {as_type}`"),
-            },
-
-            // Don't need to perform a runtime check to do the cast, use the lower function
-            _ => self.lower_static(),
-        }
-    }
-}
diff --git a/src/Rust/vvs_codegen/src/lowerer/constant.rs b/src/Rust/vvs_codegen/src/lowerer/constant.rs
deleted file mode 100644
index e8a67e17..00000000
--- a/src/Rust/vvs_codegen/src/lowerer/constant.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use crate::Value;
-use std::mem;
-use vvs_lang::ast::*;
-use vvs_llvm::*;
-
-/// Lower a single constant. We only need the LLVM context what should be the type...
-pub(crate) struct ConstantLowerer<'a> {
-    /// The context.
-    c: LLVMContextRef,
-
-    /// We expression we want to lower.
-    constant: &'a ASTConst,
-}
-
-impl<'a> ConstantLowerer<'a> {
-    /// Create a new constant expression lowerer.
-    pub fn new(c: LLVMContextRef, constant: &'a ASTConst) -> Self {
-        Self { c, constant }
-    }
-
-    /// Create a sub-lowerer, for constants that need a recursive descent.
-    fn sub_lowerer(&self, constant: &'a ASTConst) -> Self {
-        Self { c: self.c, constant }
-    }
-
-    /// Lower the constant.
-    pub fn lower(self) -> Value {
-        let Self { c, constant } = self;
-        let ty = constant.get_const_type();
-        use {ASTConst::*, Value::*};
-        unsafe {
-            match constant {
-                ASTConst::Nil => Const(ty, LLVMConstPointerNull(LLVMInt64TypeInContext(c))),
-                False => Const(ty, LLVMConstInt(LLVMInt1TypeInContext(c), 0, 0)),
-                True => Const(ty, LLVMConstInt(LLVMInt1TypeInContext(c), 1, 0)),
-                Floating(f) => Const(ty, LLVMConstReal(LLVMFloatTypeInContext(c), *f as f64)),
-                String(s) => {
-                    let (ptr, len) = (s.as_bytes().as_ptr() as *const _, s.len().try_into().unwrap());
-                    Const(ty, LLVMConstString(ptr, len, 1))
-                }
-                Integer(i) => {
-                    let int = mem::transmute::<i64, u64>(*i as i64);
-                    Const(ty, LLVMConstInt(LLVMInt32TypeInContext(c), int, 1))
-                }
-                Tuple(inner) => {
-                    let i = inner.iter().map(|cnst| match self.sub_lowerer(cnst).lower() {
-                        Value::Const(_, val) => val,
-                        val => unreachable!("expected a constant, got {val:?}"),
-                    });
-                    let mut i = i.collect::<Vec<_>>();
-                    let (ptr, len) = (i.as_mut_ptr(), i.len().try_into().unwrap());
-                    Const(ty, LLVMConstStructInContext(c, ptr, len, 0))
-                }
-                Color(_) => panic!("need to implement colors"),
-                Table(_) => panic!("need to implement tables"),
-            }
-        }
-    }
-}
diff --git a/src/Rust/vvs_codegen/src/lowerer/drops.rs b/src/Rust/vvs_codegen/src/lowerer/drops.rs
deleted file mode 100644
index 9b556da8..00000000
--- a/src/Rust/vvs_codegen/src/lowerer/drops.rs
+++ /dev/null
@@ -1,109 +0,0 @@
-use crate::{value::Value, Graph, ValueContext};
-use std::collections::BTreeSet;
-use vvs_llvm::sys::*;
-
-/// Drop all the values in the correct order at the end of a given basic block. We take into
-/// account any terminator of said basic block.
-pub(super) struct DropLowerer<'a> {
-    /// The context.
-    c: LLVMContextRef,
-
-    /// Our own builder.
-    b: LLVMBuilderRef,
-
-    /// The values to drop, they are in the order of their declaration. We drop them in the reverse
-    /// order!
-    values: &'a [Value],
-
-    /// The function from which the values must be dropped.
-    func: LLVMValueRef,
-
-    /// The basic block to use to drop things. We will create our own builder to do the thing, so
-    /// we don't need others things to pass their builder.
-    bb: LLVMBasicBlockRef,
-
-    /// The value context.
-    ctx: &'a ValueContext,
-}
-
-impl<'a> DropLowerer<'a> {
-    /// Create a new lowerer to drop the specified values from a given function at the end of a
-    /// given basic block.
-    ///
-    /// # Safety
-    /// All the values must have been declared inside the passed the function. The basic block must
-    /// be from the passed function.
-    pub unsafe fn new(
-        c: LLVMContextRef,
-        func: LLVMValueRef,
-        values: &'a [Value],
-        bb: LLVMBasicBlockRef,
-        ctx: &'a ValueContext,
-    ) -> Self {
-        let b = unsafe { LLVMCreateBuilderInContext(c) };
-        Self { c, b, values, func, bb, ctx }
-    }
-
-    pub fn lower(self) {
-        use LLVMOpcode::*;
-        let Self { c, b, values, bb, func, ctx } = self;
-
-        // Position the builder correcly.
-
-        unsafe {
-            match LLVMGetLastInstruction(bb) {
-                last if last.is_null() => LLVMPositionBuilderAtEnd(b, bb),
-                last => match LLVMGetInstructionOpcode(last) {
-                    LLVMRet | LLVMBr | LLVMSwitch | LLVMIndirectBr | LLVMCallBr => LLVMPositionBuilderBefore(b, last),
-                    _ => LLVMPositionBuilderAtEnd(b, bb),
-                },
-            };
-        };
-
-        // Get the dominance graph to filter the values that we must really drop here!
-
-        let bbs_iter = unsafe { LLVMFunctionIter::new(func) };
-        let bbs = Graph::with_capacity(bbs_iter.count()).add_nodes(bbs_iter);
-        let bbs = bbs_iter.fold(bbs, |bbs, bb| unsafe {
-            match LLVMBasicBlockIter::new(bb).last() {
-                Some(instr) => match LLVMGetInstructionOpcode(instr) {
-                    LLVMBr => match LLVMGetNumOperands(instr) {
-                        1 => bbs.add_edge(bb, LLVMValueAsBasicBlock(LLVMGetOperand(instr, 0))),
-                        3 => bbs
-                            .add_edge(bb, LLVMValueAsBasicBlock(LLVMGetOperand(instr, 1)))
-                            .add_edge(bb, LLVMValueAsBasicBlock(LLVMGetOperand(instr, 2))),
-                        n => unreachable!("got br instruction with {n} operands"),
-                    },
-                    LLVMSwitch => todo!("handle switch, got {} operands", LLVMGetNumOperands(instr)),
-                    LLVMIndirectBr => todo!("handle indirectbr, got {} operands", LLVMGetNumOperands(instr)),
-                    _ => bbs,
-                },
-                None => bbs,
-            }
-        });
-
-        // Filter the values that we must really delete and call the destructors. We can destroy
-        // the values in any order because things are reference-counted. Also, just drop the values
-
-        let declared_values: BTreeSet<LLVMValueRef> = unsafe {
-            bbs.any_path_content(LLVMGetEntryBasicBlock(func), bb)
-                .into_iter()
-                .flat_map(|bb| LLVMBasicBlockIter::new(bb))
-                .collect()
-        };
-
-        values
-            .iter()
-            .filter(|val| val.llvm_value().map_or(false, |val| declared_values.contains(&val)))
-            .flat_map(|val| val.get_dropper_name().map(|drop| (val, drop)))
-            .for_each(|(val, drop)| {
-                ctx.get_value(drop).call(b, [val.loaded(c, b)]);
-            });
-    }
-}
-
-impl<'a> Drop for DropLowerer<'a> {
-    fn drop(&mut self) {
-        unsafe { LLVMDisposeBuilder(self.b) };
-    }
-}
diff --git a/src/Rust/vvs_codegen/src/lowerer/expression.rs b/src/Rust/vvs_codegen/src/lowerer/expression.rs
deleted file mode 100644
index d3a82d2e..00000000
--- a/src/Rust/vvs_codegen/src/lowerer/expression.rs
+++ /dev/null
@@ -1,347 +0,0 @@
-use crate::{lowerer::*, Value, ValueContext};
-use vvs_lang::ast::*;
-use vvs_llvm::sys::{LLVMIntPredicate::*, LLVMRealPredicate::*, *};
-use vvs_runtime_types::{
-    types::{VVRTString, VVRTTable},
-    vvll::LLVMExported,
-};
-use vvs_utils::either;
-
-/// Lower a single expression.
-pub(super) struct ExpressionLowerer<'a> {
-    llvm: LLVMLowerContext,
-
-    /// We expression we want to lower.
-    expr: &'a ASTExpr,
-
-    /// The expected type, to see if we need to generate coertion.
-    as_type: Option<&'a ASTType>,
-
-    /// The value context, this stores available already-lowered LLVM values.
-    ctx: &'a ValueContext,
-}
-
-impl<'a> ExpressionLowerer<'a> {
-    /// Create a new expression lowerer.
-    pub(super) fn with_assumed_type(llvm: LLVMLowerContext, expr: &'a ASTExpr, ctx: &'a ValueContext) -> Self {
-        Self { llvm, expr, as_type: None, ctx }
-    }
-
-    /// Create a new expression lowerer with an expected type for the lowered expression. If needed
-    /// the lower process will call [CastLowerer].
-    pub(super) fn with_expected_type(
-        llvm: LLVMLowerContext,
-        expr: &'a ASTExpr,
-        as_type: &'a ASTType,
-        ctx: &'a ValueContext,
-    ) -> Self {
-        Self { llvm, expr, as_type: Some(as_type), ctx }
-    }
-
-    /// Overwrite the used [ValueContext] used to do the lowering.
-    pub(super) fn with_ctx(mut self, ctx: &'a ValueContext) -> Self {
-        self.ctx = ctx;
-        self
-    }
-
-    /// Set the type that is expected by the expression, calling the [CastLowerer] if needed!
-    pub(super) fn into_type(mut self, ty: &'a ASTType) -> Self {
-        self.as_type = Some(ty);
-        self
-    }
-
-    /// Create a new sub-expression lowerer. Used for recusive descent to lower complexe
-    /// expressions, thus private.
-    fn sub_lowerer(&self, expr: &'a ASTExpr) -> Self {
-        let Self { llvm, ctx, .. } = *self;
-        Self { llvm, expr, as_type: None, ctx }
-    }
-
-    /// Lower an equality.
-    unsafe fn lower_equality(
-        llvm @ (_, c, b): LLVMLowerContext,
-        ctx: &ValueContext,
-        (l, lty): (LLVMValueRef, &ASTType),
-        (r, rty): (LLVMValueRef, &ASTType),
-    ) -> LLVMValueRef {
-        use ASTType::*;
-        match lty {
-            Nil => LLVMConstInt(LLVMInt1TypeInContext(c), 1, 0),
-            Boolean | Integer => LLVMBuildICmp(b, LLVMIntEQ, l, r, cstr!()),
-            Floating => {
-                let flt = LLVMFloatTypeInContext(c);
-                let diff = LLVMBuildFSub(b, l, r, c"".as_ptr());
-                let diff = CallLowerer::call_intrinsic("llvm.fabs.f32", llvm, flt, [diff]);
-                LLVMBuildFCmp(b, LLVMRealOLE, diff, LLVMConstReal(flt, 10e-5), c"".as_ptr())
-            }
-
-            Tuple(lt) => match rty {
-                Tuple(rt) if lt.len() == rt.len() => lt.iter().zip(rt).enumerate().fold(
-                    LLVMConstInt(LLVMInt1TypeInContext(c), 1, 0),
-                    |acc, (idx, (lt, rt))| {
-                        let idx = idx.try_into().expect("too many elements");
-                        let l = LLVMBuildStructGEP2(b, LLVMTypeOf(l), l, idx, cstr!());
-                        let r = LLVMBuildStructGEP2(b, LLVMTypeOf(r), r, idx, cstr!());
-                        let ret = Self::lower_equality(llvm, ctx, (l, lt), (r, rt));
-                        LLVMBuildAnd(b, ret, acc, cstr!())
-                    },
-                ),
-                _ => LLVMConstInt(LLVMInt1TypeInContext(c), 0, 0),
-            },
-
-            Any => ctx.get_value("VVRTAny_eq").call(b, [l, r]),
-            Line => ctx.get_value("VVRTLine_eq").call(b, [l, r]),
-            String => ctx.get_value("VVRTString_eq").call(b, [l, r]),
-            Syllabe => ctx.get_value("VVRTSyllabe_eq").call(b, [l, r]),
-            ty if ty.is_sequence() => ctx.get_value("VVRTSeq_eq").call(b, [l, r]),
-            ty if ty.is_variant() => ctx.get_value("VVRTVariant_eq").call(b, [l, r]),
-            ty if ty.is_table() => ctx.get_value("VVRTTable_eq").call(b, [l, r]),
-
-            _ => panic!("can't apply `{:?}` to expressions of type `{lty}` and `{rty}`", ASTBinop::CmpEQ),
-        }
-    }
-
-    /// Lower the value into LLVM-IR at the position specified by the builder passed at
-    /// construction time. If any value is created it will be added in the returned [ValueContext].
-    pub(super) fn lower(self) -> (ValueContext, Value) {
-        let Self { llvm: llvm @ (_, c, b), expr: ASTExpr { content, .. }, as_type, ctx } = self;
-        let (bln, int, flt) = (unsafe { LLVMInt1TypeInContext(c) }, unsafe { LLVMInt32TypeInContext(c) }, unsafe {
-            LLVMFloatTypeInContext(c)
-        });
-        let (false_, true_, zero_, one_) = (
-            unsafe { LLVMConstInt(bln, 0, 0) },
-            unsafe { LLVMConstInt(bln, 1, 0) },
-            unsafe { LLVMConstInt(int, 0, 0) },
-            unsafe { LLVMConstInt(int, 1, 0) },
-        );
-        let store_scalar = |ctx: ValueContext, val: LLVMValueRef, ty: LLVMTypeRef, ast: ASTType| unsafe {
-            let ptr = LLVMBuildAlloca(b, ty, cstr!());
-            LLVMBuildStore(b, val, ptr);
-            (ctx, Value::Alloca(ast, ty, ptr))
-        };
-
-        match content {
-            ASTExprVariant::Var(var) => (ctx.clone(), ctx.get_value(var.name()).clone()),
-
-            ASTExprVariant::Const(value) => {
-                let value = ConstantLowerer::new(c, value).lower();
-                match as_type {
-                    Some(expected_type) if expected_type != value.get_ast_type() => {
-                        match CastLowerer::from_llvm(llvm, &value, expected_type, ctx).lower_static() {
-                            CastedValue::Unchanged { value } => (ctx.clone(), value),
-                            CastedValue::Static { value } => (ctx.to_register_anon(value.clone()), value),
-                            CastedValue::Dynamic { .. } => unreachable!(),
-                        }
-                    }
-                    _ => (ctx.clone(), value),
-                }
-            }
-
-            ASTExprVariant::Tuple(tuple) => unsafe {
-                let (mut lowered_tuple, mut types, mut tuple_ty) =
-                    (Vec::with_capacity(tuple.len()), Vec::with_capacity(tuple.len()), Vec::with_capacity(tuple.len()));
-
-                let ctx = tuple.iter().fold(self.ctx.clone(), |ctx, item| {
-                    let (ctx, expr) = self.sub_lowerer(item).with_ctx(&ctx).lower();
-                    let (ast_type, expr) = (expr.get_ast_type(), expr.loaded(c, b));
-                    lowered_tuple.push(expr);
-                    types.push(LLVMTypeOf(expr));
-                    tuple_ty.push(ast_type.clone());
-                    ctx
-                });
-
-                let tuple_len = types.len().try_into().expect("too many elements");
-                let types = LLVMStructTypeInContext(c, types.as_mut_ptr(), tuple_len, 0);
-                let tuple_ptr = LLVMBuildAlloca(b, types, c"".as_ptr());
-
-                for (idx, val) in lowered_tuple.into_iter().enumerate() {
-                    let idx = idx.try_into().expect("too many elements");
-                    let ptr = LLVMBuildStructGEP2(b, types, tuple_ptr, idx, c"".as_ptr());
-                    LLVMBuildStore(b, val, ptr);
-                }
-
-                (ctx, Value::Alloca(ASTType::Tuple(tuple_ty), types, tuple_ptr))
-            },
-
-            ASTExprVariant::Table(table) => unsafe {
-                let ty = VVRTTable::llvm_type(c);
-                let ptr = LLVMBuildAlloca(b, ty, c"".as_ptr());
-                LLVMBuildStore(b, ctx.get_value("VVRTTable_new").call(b, []), ptr);
-                let mut ctx = table.iter().fold(self.ctx.clone(), |_, (key, value)| {
-                    // Static key! The table will create it's own string.
-                    let key_len: u32 = key.len().try_into().expect("too many elements");
-                    let key = LLVMConstStringInContext(c, key.as_ptr() as *const _, key_len, 1);
-                    let key_len = LLVMConstInt(LLVMInt32TypeInContext(c), key_len as u64, 0);
-
-                    // Lower the value and cast it into an Any.
-                    let (mut ctx, value) = self.sub_lowerer(value).into_type(&ASTType::Any).lower();
-                    let value = value.loaded(c, b);
-                    ctx.forget_by_llvm_value(value);
-
-                    // Insert the value with the correct key.
-                    ctx.get_value("VVRTTable_insert_from_raw_key")
-                        .call(b, [ptr, key, key_len, value]);
-                    ctx
-                });
-                let value = Value::Alloca(ASTType::AnyTable, ty, ptr);
-                ctx.register_anon(value.clone());
-                (ctx, value)
-            },
-
-            ASTExprVariant::FuncCall(func, args) => {
-                let (ctx, value) = CallLowerer::new(llvm, self.ctx).lower_func_call(func, args);
-                (ctx.to_register_anon(value.clone()), value)
-            }
-            ASTExprVariant::MethodInvok(obj, method, args) => {
-                let (ctx, value) = CallLowerer::new(llvm, self.ctx).lower_method_invok(obj, method, args);
-                (ctx.to_register_anon(value.clone()), value)
-            }
-
-            ASTExprVariant::Unop(op, inner) => unsafe {
-                use vvs_lang::ast::{ASTType::*, ASTUnop::*};
-
-                let (ctx, inner) = match as_type {
-                    Some(ty) => self.sub_lowerer(inner).into_type(ty).lower(),
-                    None => self.sub_lowerer(inner).lower(),
-                };
-                let (ty, inner) = (inner.get_ast_type(), inner.loaded(c, b));
-                let call_len = |ctx: ValueContext, func: &str| {
-                    let value = ctx.get_value(func).call(b, [inner]);
-                    store_scalar(ctx, value, int, Integer)
-                };
-
-                match op {
-                    LogicNot | BitNot | Neg if matches!(ty, Boolean) => {
-                        let cmp = LLVMBuildICmp(b, LLVMIntEQ, inner, false_, cstr!());
-                        let res = LLVMBuildSelect(b, cmp, true_, false_, cstr!());
-                        store_scalar(ctx, res, bln, Boolean)
-                    }
-
-                    LogicNot if matches!(ty, Integer) => {
-                        let cmp = LLVMBuildICmp(b, LLVMIntEQ, inner, zero_, cstr!());
-                        let res = LLVMBuildSelect(b, cmp, one_, zero_, cstr!());
-                        store_scalar(ctx, res, int, Integer)
-                    }
-
-                    BitNot if matches!(ty, Integer) => {
-                        let res = CallLowerer::call_intrinsic("llvm.bitreverse.i32", llvm, int, [inner]);
-                        store_scalar(ctx, res, int, Integer)
-                    }
-
-                    #[rustfmt::skip] Neg if matches!(ty, Integer ) => store_scalar(ctx, LLVMBuildNeg (b, inner, cstr!()), int, Integer ),
-                    #[rustfmt::skip] Neg if matches!(ty, Floating) => store_scalar(ctx, LLVMBuildFNeg(b, inner, cstr!()), flt, Floating),
-
-                    #[rustfmt::skip] Len => match ty {
-                        Line                   => call_len(ctx, "VVRTLine_len"),
-                        String                 => call_len(ctx, "VVRTString_len"),
-                        Syllabe                => call_len(ctx, "VVRTSyllabe_len"),
-                        ty if ty.is_sequence() => call_len(ctx, "VVRTSeq_len"),
-                        ty if ty.is_table()    => call_len(ctx, "VVRTTable_len"),
-                        Tuple(len) => {
-                            let len = TryInto::<i32>::try_into(len.len()).expect("too many elements") as u64;
-                            (ctx, Value::Const(Integer, LLVMConstInt(int, len, 0)))
-                        }
-                        ty => panic!("can't apply `{op:?}` to expression of type `{ty}`"),
-                    },
-
-                    op => panic!("can't apply `{op:?}` to expression of type `{ty}`"),
-                }
-            },
-
-            ASTExprVariant::Binop(left, op, right) => unsafe {
-                use vvs_lang::ast::{ASTBinop::*, ASTType::*};
-
-                let (ctx, left) = match as_type {
-                    Some(ty) => self.sub_lowerer(left).into_type(ty).lower(),
-                    None => self.sub_lowerer(left).lower(),
-                };
-                let lty = left.get_ast_type();
-                let (ctx, right) = self
-                    .sub_lowerer(right)
-                    .into_type(either!(*op == Power => &Integer; lty))
-                    .with_ctx(&ctx)
-                    .lower();
-                let (l, r, rty) = (left.loaded(c, b), right.loaded(c, b), right.get_ast_type());
-                let (is_int, is_flt, is_bln) =
-                    (matches!(lty, Integer), matches!(lty, Floating), matches!(lty, Boolean));
-
-                let (res, ty, ast) = match op {
-                    Power if is_int => todo!(),
-                    Power if is_flt => todo!(),
-
-                    #[rustfmt::skip] Mul if is_int => (LLVMBuildMul (b, l, r, cstr!()), int, Integer),
-                    #[rustfmt::skip] Div if is_int => (LLVMBuildSDiv(b, l, r, cstr!()), int, Integer),
-                    #[rustfmt::skip] Add if is_int => (LLVMBuildAdd (b, l, r, cstr!()), int, Integer),
-                    #[rustfmt::skip] Sub if is_int => (LLVMBuildSub (b, l, r, cstr!()), int, Integer),
-
-                    #[rustfmt::skip] Mul if is_flt => (LLVMBuildFMul(b, l, r, cstr!()), flt, Floating),
-                    #[rustfmt::skip] Div if is_flt => (LLVMBuildFDiv(b, l, r, cstr!()), flt, Floating),
-                    #[rustfmt::skip] Add if is_flt => (LLVMBuildFAdd(b, l, r, cstr!()), flt, Floating),
-                    #[rustfmt::skip] Sub if is_flt => (LLVMBuildFSub(b, l, r, cstr!()), flt, Floating),
-
-                    #[rustfmt::skip] Mod if is_int => (LLVMBuildSRem(b, l, r, cstr!()), int, Integer ),
-                    #[rustfmt::skip] Mod if is_flt => (LLVMBuildFRem(b, l, r, cstr!()), flt, Floating),
-
-                    #[rustfmt::skip] StrCat if matches!(lty, String) => {
-                        (ctx.get_value("VVRTString_cat").call(b, [l, r]), VVRTString::llvm_type(c), String)
-                    },
-
-                    #[rustfmt::skip] CmpLE if is_int => (LLVMBuildICmp(b, LLVMIntSLE,  l, r, cstr!()), bln, Boolean),
-                    #[rustfmt::skip] CmpLT if is_int => (LLVMBuildICmp(b, LLVMIntSLT,  l, r, cstr!()), bln, Boolean),
-                    #[rustfmt::skip] CmpGE if is_int => (LLVMBuildICmp(b, LLVMIntSGE,  l, r, cstr!()), bln, Boolean),
-                    #[rustfmt::skip] CmpGT if is_int => (LLVMBuildICmp(b, LLVMIntSGT,  l, r, cstr!()), bln, Boolean),
-
-                    #[rustfmt::skip] CmpLE if is_flt => (LLVMBuildFCmp(b, LLVMRealOLE, l, r, cstr!()), flt, Floating),
-                    #[rustfmt::skip] CmpLT if is_flt => (LLVMBuildFCmp(b, LLVMRealOLT, l, r, cstr!()), flt, Floating),
-                    #[rustfmt::skip] CmpGE if is_flt => (LLVMBuildFCmp(b, LLVMRealOGE, l, r, cstr!()), flt, Floating),
-                    #[rustfmt::skip] CmpGT if is_flt => (LLVMBuildFCmp(b, LLVMRealOGT, l, r, cstr!()), flt, Floating),
-
-                    #[rustfmt::skip] BitAnd | LogicAnd if is_bln => (LLVMBuildAnd(b, l, r, cstr!()), bln, Boolean),
-                    #[rustfmt::skip] BitXor | LogicXor if is_bln => (LLVMBuildXor(b, l, r, cstr!()), bln, Boolean),
-                    #[rustfmt::skip] BitOr  | LogicOr  if is_bln => (LLVMBuildOr (b, l, r, cstr!()), bln, Boolean),
-
-                    #[rustfmt::skip] BitAnd   if is_int => (LLVMBuildAnd(b, l, r, cstr!()), int, Integer),
-                    #[rustfmt::skip] BitXor   if is_int => (LLVMBuildXor(b, l, r, cstr!()), int, Integer),
-                    #[rustfmt::skip] BitOr    if is_int => (LLVMBuildOr (b, l, r, cstr!()), int, Integer),
-                    #[rustfmt::skip] LogicAnd if is_int => (LLVMBuildICmp(b, LLVMIntEQ, LLVMBuildAnd(b, l, r, cstr!()), one_, cstr!()), bln, Boolean),
-                    #[rustfmt::skip] LogicXor if is_int => (LLVMBuildICmp(b, LLVMIntEQ, LLVMBuildXor(b, l, r, cstr!()), one_, cstr!()), bln, Boolean),
-                    #[rustfmt::skip] LogicOr  if is_int => (LLVMBuildICmp(b, LLVMIntEQ, LLVMBuildOr (b, l, r, cstr!()), one_, cstr!()), bln, Boolean),
-
-                    #[rustfmt::skip] BitShiftLeft  if is_int => (LLVMBuildShl (b, l, r, cstr!()), int, Integer),
-                    #[rustfmt::skip] BitShiftRight if is_int => (LLVMBuildAShr(b, l, r, cstr!()), int, Integer),
-
-                    CmpEQ => (Self::lower_equality(llvm, &ctx, (l, lty), (r, rty)), bln, Boolean),
-                    CmpNE => {
-                        let not = Self::lower_equality(llvm, &ctx, (l, lty), (r, rty));
-                        (LLVMBuildNot(b, not, cstr!()), bln, Boolean)
-                    }
-
-                    op => panic!("can't apply `{op:?}` to expressions of type `{lty}` and `{rty}`"),
-                };
-                store_scalar(ctx, res, ty, ast)
-            },
-
-            ASTExprVariant::Suffixed(table, _fields) => {
-                let (_ctx, _table) = self.sub_lowerer(table).lower();
-                todo!()
-            }
-
-            ASTExprVariant::Color(variant) | ASTExprVariant::Movement(variant) => {
-                let mut arguments = Vec::with_capacity(variant.args_len());
-                let _ctx = variant.args().iter().fold(ctx.clone(), |ctx, expr| {
-                    let (ctx, expr) = self.sub_lowerer(expr).with_ctx(&ctx).lower();
-                    arguments.push(expr);
-                    ctx
-                });
-                let _variant = variant.variant();
-
-                todo!()
-            }
-
-            ASTExprVariant::Default(_) => todo!(),
-
-            // See later for clozures
-            ASTExprVariant::FuncBind(_, _) => unreachable!(),
-        }
-    }
-}
diff --git a/src/Rust/vvs_codegen/src/lowerer/function.rs b/src/Rust/vvs_codegen/src/lowerer/function.rs
deleted file mode 100644
index fd8ab087..00000000
--- a/src/Rust/vvs_codegen/src/lowerer/function.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-use crate::{lowerer::*, ValueContext};
-use vvs_lang::ast::*;
-use vvs_llvm::*;
-
-pub(super) struct FunctionLowerer<'a> {
-    llvm: LLVMLowerContext,
-
-    /// The global context, we store a reference, then we will add it the arguments of the
-    /// function.
-    ctx: &'a ValueContext,
-
-    /// The llvm function.
-    value: LLVMValueRef,
-
-    /// The vivy function.
-    function: &'a ASTFunction,
-}
-
-impl<'a> FunctionLowerer<'a> {
-    pub fn new(llvm: LLVMLowerContext, ctx: &'a ValueContext, v: LLVMValueRef, f: &'a ASTFunction) -> Self {
-        Self { llvm, ctx, value: v, function: f }
-    }
-
-    pub fn lower(self) {
-        let Self { llvm: llvm @ (_, c, b), value, function, .. } = self;
-        let ASTFunction { arguments, content, returns, .. } = function;
-        let mut ctx = self.ctx.clone();
-
-        let mut ctx = unsafe {
-            LLVMPositionBuilderAtEnd(b, LLVMAppendBasicBlockInContext(c, value, c"entry".as_ptr()));
-            for (idx, arg) in arguments.iter().enumerate() {
-                let ty = arg
-                    .get_specified_type()
-                    .expect("the type should be specified at this point");
-                let llvm_ty = TypeLowerer::new(c, ty).lower();
-                let arg_name = CString::new(arg.name().as_ref()).expect("invalid name");
-                let arg_param = LLVMGetParam(value, idx.try_into().expect("too many arguments"));
-                let ptr = LLVMBuildAlloca(b, llvm_ty, arg_name.as_ptr());
-                LLVMBuildStore(b, arg_param, ptr);
-                ctx.register(arg.name(), Value::Alloca(ty.clone(), llvm_ty, ptr));
-            }
-
-            InstructionLowerer::new(llvm, value, content, returns.clone(), ctx).lower()
-        };
-
-        let to_drop = ctx.get_values_to_drop();
-        unsafe { LLVMFunctionIter::new(value) }
-            .filter(|&bb| unsafe {
-                LLVMBasicBlockIter::new(bb)
-                    .last()
-                    .map_or(false, |instr| LLVMGetInstructionOpcode(instr) == LLVMOpcode::LLVMRet)
-            })
-            .for_each(|bb| unsafe { DropLowerer::new(c, value, &to_drop, bb, &ctx) }.lower());
-    }
-}
diff --git a/src/Rust/vvs_codegen/src/lowerer/instruction.rs b/src/Rust/vvs_codegen/src/lowerer/instruction.rs
deleted file mode 100644
index d731bfd9..00000000
--- a/src/Rust/vvs_codegen/src/lowerer/instruction.rs
+++ /dev/null
@@ -1,431 +0,0 @@
-use crate::lowerer::*;
-use std::sync::OnceLock;
-use vvs_lang::{anon_expression, anon_instruction, ast::*};
-use vvs_llvm::*;
-use vvs_utils::either;
-
-#[derive(Clone, Copy)]
-struct BBLoop {
-    body_entry: LLVMBasicBlockRef,
-    loop_exit: LLVMBasicBlockRef,
-}
-
-/// Lower a single instruction.
-pub(super) struct InstructionLowerer<'a> {
-    llvm: LLVMLowerContext,
-
-    /// The function containing the instruction to lower.
-    func: LLVMValueRef,
-
-    /// Remeber the last loop to be able to break or continue.
-    last_loop: Option<BBLoop>,
-
-    /// The instruction we want to lower.
-    instr: &'a ASTInstr,
-
-    /// The return type of the function, to see if we need to generetate coertion.
-    func_return_type: ASTType,
-
-    /// The value context, this stores available already-lowered LLVM values.
-    ctx: ValueContext,
-}
-
-impl<'a> InstructionLowerer<'a> {
-    /// Create a new expression lowerer.
-    pub(super) fn new(
-        llvm: LLVMLowerContext,
-        func: LLVMValueRef,
-        instruction: &'a ASTInstr,
-        func_return_type: ASTType,
-        ctx: ValueContext,
-    ) -> Self {
-        let last_loop = Default::default();
-        Self { llvm, func, instr: instruction, func_return_type, ctx, last_loop }
-    }
-
-    /// Create a new sub-expression lowerer. Used for recusive descent to lower complexe
-    /// expressions, thus private.
-    fn sub_lowerer(&self, instruction: &'a ASTInstr) -> Self {
-        let Self { llvm, func, last_loop, .. } = *self;
-        let func_return_type = self.func_return_type.clone();
-        let ctx = self.ctx.clone();
-        Self { llvm, instr: instruction, func, func_return_type, ctx, last_loop }
-    }
-
-    /// Short-hand to create an expression lowerer by passing some arguments correctly.
-    fn expr(&'a self, expr: &'a ASTExpr) -> ExpressionLowerer<'a> {
-        ExpressionLowerer::with_assumed_type(self.llvm, expr, &self.ctx)
-    }
-
-    /// Get a new sub-expression lowerer. We need to know the exit block of this scope so that we
-    /// can build the calls to drop for this scope.
-    fn scoped_lowerer(&mut self, exit_bb: LLVMBasicBlockRef, cb: impl FnOnce(Self) -> ValueContext) {
-        static mut NOOP: OnceLock<ASTInstr> = OnceLock::new();
-
-        // Save context.
-        let pre_ctx = self.ctx.clone();
-        self.ctx = pre_ctx.sub_context();
-
-        // Build an empty instruction to give as parent lowerer in scope.
-        let Self { llvm: llvm @ (_, c, _), func, last_loop, .. } = *self;
-        let instruction = unsafe { NOOP.get_or_init(|| anon_instruction!(Noop)) };
-        let func_return_type = self.func_return_type.clone();
-        let ctx = self.ctx.sub_context();
-        let this = Self { llvm, func, last_loop, instr: instruction, func_return_type, ctx };
-
-        // Drop what was declared in the scope
-        let mut ctx = cb(this);
-        unsafe { DropLowerer::new(c, func, &ctx.get_values_to_drop(), exit_bb, &ctx) }.lower();
-
-        // Restore context.
-        self.ctx = pre_ctx;
-    }
-
-    /// Set the last loop to lower a given instruction.
-    fn with_loop(mut self, r#loop: BBLoop) -> Self {
-        self.last_loop = Some(r#loop);
-        self
-    }
-
-    /// Set the value context.
-    fn with_ctx(mut self, ctx: ValueContext) -> Self {
-        self.ctx = ctx;
-        self
-    }
-
-    pub(super) fn lower(mut self) -> ValueContext {
-        let Self { llvm: llvm @ (_, c, b), func, instr: ASTInstr { content, span }, .. } = self;
-        match content {
-            // Nop
-            ASTInstrVariant::Noop => self.ctx,
-
-            // A simple list of instructions
-            ASTInstrVariant::Block(instructions) => unsafe {
-                let exit = LLVMAppendBasicBlockInContext(c, self.func, c".block".as_ptr());
-                self.scoped_lowerer(exit, |this| {
-                    instructions
-                        .iter()
-                        .fold(this.ctx.clone(), |ctx, instruction| this.sub_lowerer(instruction).with_ctx(ctx).lower())
-                });
-                LLVMBuildBr(b, exit);
-                LLVMPositionBuilderAtEnd(b, exit);
-                self.ctx
-            },
-
-            // Breaks/Continue
-            ASTInstrVariant::Break | ASTInstrVariant::Continue if self.last_loop.is_none() => {
-                panic!("try to lower break/continue while not being inside a loop")
-            }
-            ASTInstrVariant::Break => unsafe {
-                LLVMBuildBr(b, self.last_loop.expect("internal error").loop_exit);
-                self.ctx
-            },
-            ASTInstrVariant::Continue => unsafe {
-                LLVMBuildBr(b, self.last_loop.expect("internal error").body_entry);
-                self.ctx
-            },
-
-            // Return from function
-            ASTInstrVariant::Return(expr) => unsafe {
-                let (ctx, value) = self.expr(expr).lower();
-                match value {
-                    Value::Nil => LLVMBuildRetVoid(b),
-                    Value::Function(..) => panic!("error at `{span}`: can't return a function for now"),
-                    value => LLVMBuildRet(b, value.loaded(c, b)),
-                };
-                ctx
-            },
-
-            // Assignation
-            ASTInstrVariant::Assign(dests, srcs) if dests.len() != srcs.len() => {
-                unreachable!("internal error: verifier failed for assignations at `{span}`")
-            }
-            ASTInstrVariant::Assign(dests, srcs) => dests.iter().zip(srcs).fold(self.ctx, |ctx, (dest, src)| {
-                let (dest, dest_ty) = Self::compute_dest_location(c, b, &ctx, dest);
-                let (ctx, src) = ExpressionLowerer::with_expected_type(llvm, src, dest_ty, &ctx).lower();
-                Self::store_into(c, b, dest, &src);
-                ctx
-            }),
-
-            // Declarations
-            ASTInstrVariant::Decl(dests, srcs) if dests.len() != srcs.len() => {
-                unreachable!("internal error: verifier failed for declarations at `{span}`")
-            }
-            ASTInstrVariant::Decl(dests, srcs) => {
-                let mut declarations = Vec::with_capacity(dests.len());
-                let ctx = dests.iter().zip(srcs).fold(self.ctx.clone(), |ctx, (dest, src)| {
-                    let dest_ast_ty = dest.get_specified_type().expect("internal error");
-                    let dest_llvm_ty = TypeLowerer::new(c, dest_ast_ty).lower();
-                    let val = unsafe { LLVMBuildAlloca(b, dest_llvm_ty, cstr!("{}", dest.name())) };
-                    let (ctx, expr) = self.expr(src).with_ctx(&ctx).into_type(dest_ast_ty).lower();
-                    Self::store_into(c, b, val, &expr);
-                    declarations.push((dest.name(), Value::Alloca(dest_ast_ty.clone(), dest_llvm_ty, val)));
-                    ctx
-                });
-                declarations.into_iter().fold(ctx, |mut ctx, (name, val)| {
-                    ctx.register(name, val);
-                    ctx
-                })
-            }
-
-            // Call a function, discard the result
-            ASTInstrVariant::FuncCall(func, args) => {
-                let (ctx, value) = CallLowerer::new(llvm, &self.ctx).lower_func_call(func, args);
-                ctx.to_register_anon(value)
-            }
-            ASTInstrVariant::MethodInvok(obj, method, args) => {
-                let (ctx, value) = CallLowerer::new(llvm, &self.ctx).lower_method_invok(obj, method, args);
-                ctx.to_register_anon(value)
-            }
-
-            // If/Else/Elseif blocks
-            ASTInstrVariant::Cond { if_blocks, else_block } => unsafe {
-                let exit = LLVMAppendBasicBlockInContext(c, self.func, c".if.exit".as_ptr());
-                let pre_ctx = self.ctx.clone();
-                let true_cond = ASTCondition::BooleanTrue(anon_expression!(Const(ASTConst::True)));
-
-                let get_bb = move |idx: usize, what: &str| {
-                    LLVMAppendBasicBlockInContext(c, self.func, cstr!(".if.{}.{}", idx, what))
-                };
-                let mut bbs: HashMap<usize, LLVMBasicBlockRef> = Default::default();
-                let mut get_bb_cond = move |idx| *bbs.entry(idx).or_insert_with(move || get_bb(idx, "condition"));
-
-                /// Use a macro to not write the same code twice by forgeting something...
-                macro_rules! build_cond_block {
-                    (($if_num: expr, $if_cond: expr, $if_inner: expr), $else_bb: expr, $exit: expr) => {{
-                        let (if_bb_body, if_bb_body_exit) = (get_bb($if_num, "body"), get_bb($if_num, "body.exit"));
-                        self.scoped_lowerer(if_bb_body_exit, |mut scoped| {
-                            // CONDITION: We don't need to drop things even if we didn't succeded,
-                            //            add the new ctx to lower the conditional body. The head
-                            //            BB of the conditional is cached by it's number.
-                            LLVMPositionBuilderAtEnd(b, get_bb_cond($if_num));
-                            let ctx = scoped.lower_condition($if_cond, if_bb_body, $else_bb);
-
-                            // BODY: We need to drop things after the exit of the loop, we also
-                            //       drop the conditional stuff
-                            LLVMPositionBuilderAtEnd(b, if_bb_body);
-                            let ctx = scoped.sub_lowerer($if_inner).with_ctx(ctx).lower();
-                            LLVMBuildBr(b, if_bb_body_exit);
-                            LLVMPositionBuilderAtEnd(b, if_bb_body_exit);
-                            LLVMBuildBr(b, $exit);
-
-                            // WARN: scoped.ctx -> contains also the temporary values! We must drop
-                            //       all of those if we succeded or not.
-                            DropLowerer::new(c, func, &scoped.ctx.get_values_to_drop(), $else_bb, &ctx).lower();
-                            DropLowerer::new(c, func, &scoped.ctx.get_values_to_drop(), if_bb_body_exit, &ctx).lower();
-
-                            ctx
-                        })
-                    }};
-                }
-
-                let else_block = else_block.as_ref().map(|instr| (&true_cond, instr.as_ref()));
-                let if_blocks = if_blocks.iter().map(|(cond, instr): &_| (cond, instr));
-                let blocks = if_blocks.chain(else_block).enumerate().collect::<Vec<(_, (&_, &_))>>();
-                assert!(!blocks.is_empty(), "empty conditionals not allowed");
-
-                // IF -> Need to jump to the first condition checker
-                LLVMBuildBr(b, get_bb_cond(0));
-
-                // Build IF, for ELSE -> will be handled at next iteration
-                blocks.windows(2).for_each(|slice| match slice {
-                    [(if_num, (if_cond, if_inner)), (else_num, _)] => {
-                        build_cond_block!((*if_num, if_cond, if_inner), get_bb_cond(*else_num), exit)
-                    }
-                    _ => unreachable!(),
-                });
-
-                // ELSE / IF in the case where we have only one conditional -> Handle last item
-                let (else_num, (else_cond, else_inner)) = blocks.last().expect("internal error");
-                build_cond_block!((*else_num, else_cond, else_inner), exit, exit);
-
-                LLVMPositionBuilderAtEnd(b, exit);
-                pre_ctx
-            },
-
-            // While loops
-            ASTInstrVariant::WhileDo(condition, inner) => unsafe {
-                let (cond, exit, body, body_exit) = (
-                    LLVMAppendBasicBlockInContext(c, self.func, c".while.cond".as_ptr()),
-                    LLVMAppendBasicBlockInContext(c, self.func, c".while.exit".as_ptr()),
-                    LLVMAppendBasicBlockInContext(c, self.func, c".while.body".as_ptr()),
-                    LLVMAppendBasicBlockInContext(c, self.func, c".while.body.exit".as_ptr()),
-                );
-
-                self.scoped_lowerer(body_exit, |mut scoped| {
-                    // For a WhileDo the condition binding variables are only visible in the body
-                    // of the loop. Here we ensure variables are only available inside the loop.
-                    LLVMBuildBr(b, cond);
-                    LLVMPositionBuilderAtEnd(b, cond);
-                    let ctx = scoped.lower_condition(condition, body, exit);
-
-                    LLVMPositionBuilderAtEnd(b, body);
-                    let ctx = scoped
-                        .sub_lowerer(inner)
-                        .with_ctx(ctx)
-                        .with_loop(BBLoop { body_entry: body, loop_exit: exit })
-                        .lower();
-
-                    // Drop what was
-                    LLVMBuildBr(b, body_exit);
-                    LLVMPositionBuilderAtEnd(b, body_exit);
-                    DropLowerer::new(c, func, &scoped.ctx.get_values_to_drop(), body_exit, &ctx).lower();
-                    LLVMBuildBr(b, cond);
-                    ctx
-                });
-
-                LLVMPositionBuilderAtEnd(b, exit);
-                self.ctx
-            },
-
-            // For loop
-            ASTInstrVariant::ForLoop { var, lower: l, upper: u, step, body: inner } => unsafe {
-                let (cond, exit, body, body_exit) = (
-                    LLVMAppendBasicBlockInContext(c, self.func, c".forloop.cond".as_ptr()),
-                    LLVMAppendBasicBlockInContext(c, self.func, c".forloop.exit".as_ptr()),
-                    LLVMAppendBasicBlockInContext(c, self.func, c".forloop.body".as_ptr()),
-                    LLVMAppendBasicBlockInContext(c, self.func, c".forloop.body.exit".as_ptr()),
-                );
-
-                let (ctx, lower) = self.expr(l).into_type(&ASTType::Integer).lower();
-                let (mut ctx, upper) = self.expr(u).with_ctx(&ctx).into_type(&ASTType::Integer).lower();
-                let (lower, upper) = (lower.loaded(c, b), upper.loaded(c, b));
-
-                // Setup the index
-                let t_i32 = LLVMInt32TypeInContext(c);
-                let step = step.unwrap_or(1) as i64;
-                assert!(step > 0, "the for-loop step must be strictly positive");
-                let step = LLVMConstInt(t_i32, std::mem::transmute_copy(&step), 0);
-
-                let index = LLVMBuildAlloca(b, t_i32, cstr!(".index.{}", var));
-                ctx.register(var.name(), Value::Alloca(ASTType::Integer, t_i32, index));
-                LLVMBuildStore(b, lower, index);
-
-                // Build the condition check
-                LLVMBuildBr(b, cond);
-                LLVMPositionBuilderAtEnd(b, cond);
-                const PREDICATE: LLVMIntPredicate = LLVMIntPredicate::LLVMIntSLT;
-                let loaded = LLVMBuildLoad2(b, t_i32, index, cstr!(".index.{}.loaded", var));
-                let cont = LLVMBuildICmp(b, PREDICATE, loaded, upper, cstr!(".index.{}.flag", var));
-                LLVMBuildCondBr(b, cont, body, exit);
-
-                // Lower the body, we need a scope for that.
-                self.scoped_lowerer(body_exit, |scoped| {
-                    LLVMPositionBuilderAtEnd(b, body);
-                    let ctx = scoped
-                        .sub_lowerer(inner)
-                        .with_loop(BBLoop { body_entry: body, loop_exit: exit })
-                        .lower();
-                    let loaded = LLVMBuildLoad2(b, t_i32, index, cstr!(".index.{}.loaded", var));
-                    let loaded = LLVMBuildAdd(b, loaded, step, cstr!(".index.{}.incremented", var));
-                    LLVMBuildStore(b, loaded, index);
-                    LLVMBuildBr(b, body_exit);
-                    LLVMPositionBuilderAtEnd(b, body_exit);
-                    LLVMBuildBr(b, cond);
-                    ctx
-                });
-
-                // End of loop
-                LLVMPositionBuilderAtEnd(b, exit);
-                ctx
-            },
-            ASTInstrVariant::ForInto { .. } => unsafe {
-                let (_cond, _exit, _body, _body_exit) = (
-                    LLVMAppendBasicBlockInContext(c, self.func, c".foreach.cond".as_ptr()),
-                    LLVMAppendBasicBlockInContext(c, self.func, c".foreach.exit".as_ptr()),
-                    LLVMAppendBasicBlockInContext(c, self.func, c".foreach.body".as_ptr()),
-                    LLVMAppendBasicBlockInContext(c, self.func, c".foreach.body.exit".as_ptr()),
-                );
-                todo!()
-            },
-        }
-    }
-
-    /// Store the content of a value into a location in memory.
-    ///
-    /// TODO: Do that in the Value enum
-    fn store_into(c: LLVMContextRef, b: LLVMBuilderRef, dest: LLVMValueRef, src: &Value) {
-        match src {
-            Value::Function(_, _, _) => panic!("we don't handle function pointers for now"),
-            Value::Const(_, v) => unsafe { LLVMBuildStore(b, *v, dest) },
-            Value::Nil => match ConstantLowerer::new(c, &ASTConst::Nil).lower() {
-                Value::Const(_, v) => unsafe { LLVMBuildStore(b, v, dest) },
-                _ => unreachable!(),
-            },
-            Value::Alloca(_, ty, v) => unsafe {
-                let v = LLVMBuildLoad2(b, *ty, *v, cstr!());
-                LLVMBuildStore(b, v, dest)
-            },
-        };
-    }
-
-    /// Get the address and the type of a variable to store into it.
-    fn compute_dest_location<'b>(
-        _c: LLVMContextRef,
-        _b: LLVMBuilderRef,
-        _ctx: &'b ValueContext,
-        _expr: &'b ASTExpr,
-    ) -> (LLVMValueRef, &'b ASTType) {
-        todo!()
-    }
-
-    /// Lower the condition. Returns the new context with the added binded values if needed. If the
-    /// condition is not checked we don't need to drop anything from the returned value context.
-    /// This means that we must drop the returned context only on the then condition path.
-    ///
-    /// If things where allocated to check the condition, then we add them to the current context,
-    /// but not to the returned context! This means that may the condition succeed or not, you must
-    /// drop the context of the calling lowerer at the end of the `then` and `else` paths.
-    ///
-    /// Most of the time the context is already scopped, so it shouldn't be too difficult trop
-    /// things at the right moment.
-    fn lower_condition(
-        &mut self,
-        condition: &ASTCondition,
-        bb_then: LLVMBasicBlockRef,
-        bb_else: LLVMBasicBlockRef,
-    ) -> ValueContext {
-        let Self { llvm: llvm @ (_, c, b), .. } = *self;
-        match condition {
-            ASTCondition::BooleanTrue(cond) => unsafe {
-                let (mut ctx, cond) = self.expr(cond).into_type(&ASTType::Boolean).lower();
-                LLVMBuildCondBr(b, cond.loaded(c, b), bb_then, bb_else);
-
-                let ret_ctx = self.ctx.clone();
-                self.ctx.add_values_to_drop(ctx.get_values_to_drop());
-                ret_ctx
-            },
-
-            ASTCondition::CoercibleInto { new, as_type, source: src }
-                if src
-                    .get_specified_type()
-                    .expect("should be setted")
-                    .coercible_to(as_type) =>
-            unsafe {
-                let llvm_true = LLVMConstInt(LLVMInt1TypeInContext(c), 1, 0);
-                let (register, flag, src) = match CastLowerer::from_ast(llvm, src, as_type, &self.ctx).lower_dynamic() {
-                    CastedValue::Dynamic { flag, value } => (true, flag, value),
-                    CastedValue::Static { value } => (true, llvm_true, value),
-                    CastedValue::Unchanged { value } => (false, llvm_true, value),
-                };
-                LLVMBuildCondBr(b, flag, bb_then, bb_else);
-
-                LLVMPositionBuilderAtEnd(b, bb_then);
-                let ty = TypeLowerer::new(c, as_type).lower();
-                let dest = LLVMBuildAlloca(b, ty, cstr!(".{}.alloca", new));
-                LLVMBuildStore(b, src.loaded(c, b), dest);
-
-                either!(!register => self.ctx.clone();
-                    self.ctx.to_register(new.name(), Value::Alloca(as_type.clone(), ty, dest))
-                )
-            },
-
-            ASTCondition::CoercibleInto { .. } => unsafe {
-                LLVMBuildBr(b, bb_else);
-                self.ctx.clone()
-            },
-
-            ASTCondition::BindVariant { .. } => todo!(),
-        }
-    }
-}
diff --git a/src/Rust/vvs_codegen/src/lowerer/mod.rs b/src/Rust/vvs_codegen/src/lowerer/mod.rs
index 2de61638..53e5e2d3 100644
--- a/src/Rust/vvs_codegen/src/lowerer/mod.rs
+++ b/src/Rust/vvs_codegen/src/lowerer/mod.rs
@@ -1,221 +1,83 @@
-mod calls;
-mod cast;
-mod constant;
-mod drops;
-mod expression;
-mod function;
-mod instruction;
+//! Contains structs to lower from Lua code to LLVM-IR
+
 mod types;
 
-use crate::{
-    cstr,
-    lowerer::{calls::*, cast::*, drops::*, expression::*, function::*, instruction::*, types::*},
-    value::Value,
-    LLVMLowerContext, ValueContext,
-};
-use hashbrown::HashMap;
-use std::ffi::{CStr, CString};
-use vvs_lang::ast::*;
-use vvs_llvm::*;
+use crate::{lowerer::types::TypeLowerer, CodegenError};
+use vvs_llvm::prelude::*;
+use vvs_parser::prelude::{ast, MainProgram};
 use vvs_runtime_types::{VVRTSymbol, VVRTSymbolType};
 
-// Re-export the constant lowerer because it can be usefull in other parts of the codegen.
-pub(crate) use self::constant::ConstantLowerer;
-
-pub struct Lowerer<'a> {
-    llvm: LLVMLowerContext,
-
-    functions: Vec<(ASTString, ASTString, &'a ASTFunction)>,
-    globals: HashMap<(ASTString, ASTString), &'a ASTConst>,
-
-    ctx: ValueContext,
+pub struct Lowerer<'ctx, 'this>
+where
+    'ctx: 'this,
+{
+    context: &'this Context<'ctx>,
+    module: Module<'this>,
 }
 
-pub struct LowererBuilder<'a> {
-    name: CString,
-    c: LLVMContextRef,
-    m: Option<LLVMModuleRef>,
-    b: LLVMBuilderRef,
-    programs: Option<&'a ASTProgram>,
-    modules: Vec<&'a ASTModule>,
-}
-
-impl<'a> LowererBuilder<'a> {
-    /// Create a new lowerer builder. We need a name and the context from the JIT thing.
-    ///
-    /// # Safety
-    /// This function is unsafe because we use the LLVM context pointer passed from anywhere. This
-    /// pointer must be not null and be a valid LLVM context.
-    pub unsafe fn new(name: impl AsRef<str>, c: LLVMContextRef) -> Self {
-        Self {
-            c,
-            name: CString::new(name.as_ref()).expect("invalid module name"),
-            b: LLVMCreateBuilderInContext(c),
-            m: Default::default(),
-            modules: Default::default(),
-            programs: Default::default(),
-        }
+impl<'ctx, 'this> Lowerer<'ctx, 'this>
+where
+    'ctx: 'this,
+{
+    /// Create a new lowerer. We will lower things into a module.
+    pub fn new(context: &'this Context<'ctx>, module: impl AsRef<str>) -> Result<Self, CodegenError> {
+        let _ = vvs_llvm::init::initialize_llvm();
+        Ok(Self { context, module: context.create_module(module.as_ref()).map_err(CodegenError::NulError)? })
     }
 
-    /// Add a complete program to lower. If any other program was present, overwrite it.
-    pub fn program(mut self, program: &'a ASTProgram) -> Self {
-        self.programs = Some(program);
-        self
+    pub fn declare_globals<'a>(
+        self,
+        iter: impl IntoIterator<Item = (impl AsRef<str>, impl AsRef<str>, Vec<&'a ast::TypeInfo>, &'a ast::TypeInfo)>,
+    ) -> Result<Self, CodegenError> {
+        iter.into_iter()
+            .try_fold(self, |this, (module, name, args, ret)| this.declare_global(module, name, args.as_slice(), ret))
     }
 
-    /// Add a module to lower to the list of things to lower.
-    pub fn module(mut self, module: &'a ASTModule) -> Self {
-        self.modules.push(module);
-        self
+    pub fn declare_global(
+        mut self,
+        module_name: impl AsRef<str>,
+        name: impl AsRef<str>,
+        arguments: &[&ast::TypeInfo],
+        returns: &ast::TypeInfo,
+    ) -> Result<Self, CodegenError> {
+        let Self { context, ref mut module, .. } = self;
+        let (module_name, name) = (module_name.as_ref(), name.as_ref());
+        match module.get_function(&format!("{module_name}.{name}")).err() {
+            Some(LLVMError::Undefined(_)) => module
+                .add_function(
+                    VVRTSymbol::new(VVRTSymbolType::Function, module_name, name)
+                        .map_err(|err| CodegenError::Error(format!("{err}").into()))?
+                        .to_string(),
+                    FunctionType::from((
+                        TypeLowerer::new(context).lower_slice(arguments),
+                        TypeLowerer::new(context).lower(returns),
+                    )),
+                )
+                .map_err(CodegenError::NulError)?,
+            Some(LLVMError::NulError(err)) => return Err(CodegenError::NulError(err)),
+            None => return Err(CodegenError::RedefinedFunction(module_name.into(), name.into())),
+        };
+        Ok(self)
     }
 
-    /// Build the lowerer from this builder.
-    pub fn build(self) -> Lowerer<'a> {
-        let Self { c, m, b, programs, modules, name } = self;
-
-        // Get all the modules that will be lowered inside the final LLVM module. By doing this we
-        // have a similar thing to LTO for Vivy Script.
-
-        let init = HashMap::<ASTString, &'a ASTModule>::default();
-        let modules = modules
-            .into_iter()
-            .chain(programs.iter().flat_map(|prog| prog.modules()))
-            .fold(init, |mut map, module| match map.entry(module.name()) {
-                hashbrown::hash_map::Entry::Occupied(_) => map,
-                hashbrown::hash_map::Entry::Vacant(entry) => {
-                    entry.insert(module);
-                    map
-                }
-            });
-
-        // Get the globals that needs to be lowered / needs to be known by the lowerer. We first
-        // collect the setted options from the program as those will overwrite values from the
-        // modules, then we get what is defined as default in the module. To ensure we doesn't
-        // overwrite things, we only insert in the final hashmap if the thing was not already
-        // defined in the hashmap. Other than setted overwriting defaults, there should not be any
-        // other collisions.
-
-        let init: HashMap<(ASTString, ASTString), &'a ASTConst> = programs
-            .iter()
-            .flat_map(|prog| {
-                prog.setted_options()
-                    .iter()
-                    .map(|((m, n), v)| ((m.clone(), n.clone()), v))
-            })
-            .collect();
-        let globals = modules.iter().flat_map(|(mname, m)| {
-            let hdl = |(var, val): (&'a ASTVar, &'a _)| (mname.clone(), var.name(), val);
-            m.consts(ASTVisibilityRule::any()).map(hdl).chain(m.options().map(hdl))
-        });
-        let globals = globals.fold(init, |mut globals, (mn, n, val)| match globals.entry((mn, n)) {
-            hashbrown::hash_map::Entry::Occupied(_) => globals,
-            hashbrown::hash_map::Entry::Vacant(entry) => {
-                entry.insert(val);
-                globals
-            }
-        });
-
-        // Get the functions that are available in all the module to lower them. Should not be any
-        // collision.
-
-        let functions = modules.iter().flat_map(|(mname, m)| {
-            m.functions(ASTVisibilityRule::any())
-                .map(|(fname, f)| (mname.clone(), fname, f))
-        });
-        let functions = functions.collect();
-
-        // Now we can create the lowerer with the specified LLVM module or by creating a new one.
-
-        let m = m.unwrap_or_else(|| unsafe { LLVMModuleCreateWithNameInContext(name.as_ptr(), c) });
-        let mut ctx = ValueContext::default();
-        ctx.register_all(
-            unsafe { vvs_runtime_types::vvll::LLVMRegisterExportedIntoModule(c, m) }
-                .into_iter()
-                .map(|(name, asttype, val, ty)| (name, Value::Function(asttype, ty, val))),
-        );
-
-        Lowerer { llvm: (m, c, b), functions, globals, ctx }
+    pub fn lower_modules(
+        self,
+        iter: impl IntoIterator<Item = (impl AsRef<str>, ast::Ast)>,
+    ) -> Result<Self, CodegenError> {
+        iter.into_iter()
+            .try_fold(self, |this, (name, ast)| this.lower_module(name, ast))
     }
-}
-
-impl<'a> Lowerer<'a> {
-    /// Lower the content of the programs and modules, then returns the LLVM module containing
-    /// everything...
-    pub fn lower(self) -> LLVMModuleRef {
-        let Self { llvm: llvm @ (m, c, b), functions, globals, mut ctx } = self;
-
-        // Register all the globals in the context, they will be directly inlined in the lowering
-        // process.
-
-        ctx.register_all(
-            globals
-                .into_iter()
-                .map(|((m, n), cnst)| (format!("{m}.{n}"), ConstantLowerer::new(c, cnst).lower())),
-        );
-
-        // Lower all the functions. First declare the things and register them with the mangled
-        // name and the unmagnled name. As we collect the iterator we ensure that all the functions
-        // are declared before we generate them. Doing so allows us to use recursion and we don't
-        // need to find a good order to define-use the functions like in C. When we latter lower
-        // the content of the functions we try to find the first error and return it.
-
-        functions.into_iter().for_each(|(module, name, function)| {
-            // Declare the thing
-            let mangled = VVRTSymbol::new(VVRTSymbolType::Function, &module, &name)
-                .expect("invalid function names")
-                .mangle();
-            let ast_function_type = function.function_type();
-            let ty = TypeLowerer::new(c, &ast_function_type).lower();
-            let value = unsafe { LLVMAddFunction(m, mangled.as_ptr(), ty) };
 
-            // Register it. When we collect the iterator.
-            let to_register = Value::Function(ast_function_type, ty, value);
-            ctx.register(mangled.to_str().expect("invalid function names"), to_register.clone());
-            ctx.register(format!("{module}.{name}"), to_register);
-
-            // We will generate it latter
-            FunctionLowerer::new(llvm, &ctx, value, function).lower();
-        });
-
-        // Cleanup and optimize the code.
-
-        unsafe {
-            LLVMDisposeBuilder(b);
-            Self::verify_and_apply_optimizations(m, 3)
-        }
+    pub fn lower_module(self, name: impl AsRef<str>, ast: ast::Ast) -> Result<Self, CodegenError> {
+        todo!()
     }
 
-    /// Run the optimization passes on a module.
-    unsafe fn verify_and_apply_optimizations(m: LLVMModuleRef, lvl: u8) -> LLVMModuleRef {
-        let mut cmsg = std::ptr::null_mut();
-        if 0 != LLVMVerifyModule(m, LLVMVerifierFailureAction::LLVMPrintMessageAction, &mut cmsg) {
-            let msg = CStr::from_ptr(cmsg).to_string_lossy().to_string();
-            LLVMDisposeMessage(cmsg);
-            panic!("invalid module: {msg}");
-        }
-
-        let pbo = LLVMCreatePassBuilderOptions();
-        let pm = LLVMCreatePassManager();
-        let tm = LLVMCreateTargetMachine(
-            LLVMGetTargetFromName(LLVMGetTarget(m)),
-            LLVMGetDefaultTargetTriple(),
-            LLVMGetHostCPUName(),
-            LLVMGetHostCPUFeatures(),
-            LLVMCodeGenOptLevel::LLVMCodeGenLevelAggressive,
-            LLVMRelocMode::LLVMRelocPIC,
-            LLVMCodeModel::LLVMCodeModelDefault,
-        );
-
-        let err = LLVMRunPasses(m, cstr!("default<O{}>", lvl), tm, pbo);
-        if !err.is_null() {
-            let msg = CStr::from_ptr(LLVMGetErrorMessage(err)).to_string_lossy().to_string();
-            LLVMConsumeError(err);
-            panic!("failed to run optimizer with level O{lvl} on module: {msg}")
-        }
+    pub fn generate_main(self, main: MainProgram) -> Result<Self, CodegenError> {
+        todo!()
+    }
 
-        LLVMDisposePassBuilderOptions(pbo);
-        LLVMDisposePassManager(pm);
-        LLVMDisposeTargetMachine(tm);
-        m
+    /// Finished the lowering process and get the module out of the builder.
+    pub fn finished(self) -> Module<'this> {
+        self.module
     }
 }
diff --git a/src/Rust/vvs_codegen/src/lowerer/types.rs b/src/Rust/vvs_codegen/src/lowerer/types.rs
index 5e1b4748..6d721119 100644
--- a/src/Rust/vvs_codegen/src/lowerer/types.rs
+++ b/src/Rust/vvs_codegen/src/lowerer/types.rs
@@ -1,57 +1,24 @@
-use vvs_lang::ast::*;
-use vvs_llvm::*;
-use vvs_runtime_types::{types::*, vvll::LLVMExported};
+use vvs_llvm::prelude::*;
+use vvs_parser::prelude::ast;
 
-pub(super) struct TypeLowerer<'a> {
-    c: LLVMContextRef,
-    vivy_type: &'a ASTType,
+pub(crate) struct TypeLowerer<'a> {
+    context: &'a Context<'a>,
 }
 
 impl<'a> TypeLowerer<'a> {
-    pub(super) fn new(c: LLVMContextRef, vivy_type: &'a ASTType) -> Self {
-        Self { c, vivy_type }
+    pub fn new(context: &'a Context) -> Self {
+        Self { context }
     }
 
-    fn sub_lowerer(&self, ty: &'a ASTType) -> Self {
-        Self { c: self.c, vivy_type: ty }
+    pub fn lower(&self, ty: &ast::TypeInfo) -> Type {
+        todo!()
     }
 
-    pub(super) fn lower(self) -> LLVMTypeRef {
-        let Self { c, vivy_type } = self;
-        match vivy_type {
-            // Easy stuff...
-            ASTType::Nil => unsafe { LLVMVoidTypeInContext(c) },
-            ASTType::Integer => unsafe { LLVMInt32TypeInContext(c) },
-            ASTType::Floating => unsafe { LLVMFloatTypeInContext(c) },
-            ASTType::Boolean => unsafe { LLVMInt1TypeInContext(c) },
-
-            // Functions
-            ASTType::Function(args, returns) => unsafe {
-                let mut args = args.iter().map(|ty| self.sub_lowerer(ty).lower()).collect::<Vec<_>>();
-                LLVMFunctionType(
-                    self.sub_lowerer(returns).lower(),
-                    args.as_mut_ptr(),
-                    args.len().try_into().expect("too many arguments"),
-                    0,
-                )
-            },
-
-            // The tuple
-            ASTType::Tuple(inner) => unsafe {
-                let mut inner = inner.iter().map(|ty| self.sub_lowerer(ty).lower()).collect::<Vec<_>>();
-                LLVMStructType(inner.as_mut_ptr(), inner.len().try_into().expect("too many elements"), 0)
-            },
-
-            // Special structs, query the runtime for that...
-            ASTType::Any => unsafe { VVRTAny::llvm_type(c) },
-            ASTType::String => unsafe { VVRTString::llvm_type(c) },
-            ASTType::Syllabe => unsafe { VVRTSyllabe::llvm_type(c) },
-            ASTType::Line => unsafe { VVRTLine::llvm_type(c) },
-            ty if ty.is_table() => unsafe { VVRTTable::llvm_type(c) },
-            ty if ty.is_variant() => unsafe { VVRTVariant::llvm_type(c) },
-            ty if ty.is_sequence() => unsafe { VVRTSeq::llvm_type(c) },
+    pub fn lower_array<const N: usize>(&self, tys: [ast::TypeInfo; N]) -> [Type<'a>; N] {
+        todo!()
+    }
 
-            _ => unreachable!(),
-        }
+    pub fn lower_slice(&self, tys: &[&ast::TypeInfo]) -> Vec<Type<'a>> {
+        todo!()
     }
 }
diff --git a/src/Rust/vvs_codegen/src/value.rs b/src/Rust/vvs_codegen/src/value.rs
deleted file mode 100644
index 8ad8ed92..00000000
--- a/src/Rust/vvs_codegen/src/value.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-use crate::{cstr /*lowerer*/};
-use vvs_lang::ast::{ASTConst, ASTType, Typed};
-use vvs_llvm::sys::*;
-
-#[derive(Debug, Default, Clone, PartialEq, Eq)]
-pub(crate) enum Value {
-    /// Just the Nil/Null/None/nullptr value.
-    #[default]
-    Nil,
-
-    /// A constant.
-    Const(ASTType, LLVMValueRef),
-
-    /// A pointer to the stack plus the underlying type.
-    Alloca(ASTType, LLVMTypeRef, LLVMValueRef),
-
-    /// A function with its function type.
-    Function(ASTType, LLVMTypeRef, LLVMValueRef),
-}
-
-impl Value {
-    /// Try to get the name of the value. Only [Value::Nil] have no name.
-    pub fn as_str(&self) -> Option<&str> {
-        use Value::*;
-        match *self {
-            Nil => None,
-            Function(.., val) | Const(_, val) | Alloca(.., val) => unsafe {
-                let mut len = 0;
-                let str = LLVMGetValueName2(val, &mut len) as *const _;
-                Some(std::str::from_utf8_unchecked(std::slice::from_raw_parts(str, len)))
-            },
-        }
-    }
-
-    pub fn llvm_type(&self) -> Option<LLVMTypeRef> {
-        match self {
-            Value::Const(..) | Value::Nil => None,
-            Value::Alloca(_, t, _) | Value::Function(_, t, _) => Some(*t),
-        }
-    }
-
-    pub fn llvm_value(&self) -> Option<LLVMValueRef> {
-        match self {
-            Value::Nil => None,
-            Value::Const(_, v) | Value::Alloca(_, _, v) | Value::Function(_, _, v) => Some(*v),
-        }
-    }
-
-    pub fn loaded(&self, c: LLVMContextRef, b: LLVMBuilderRef) -> LLVMValueRef {
-        match self {
-            Value::Nil => todo!(), // lowerer::ConstantLowerer::new(c, &ASTConst::Nil).lower().loaded(c, b),
-            Value::Const(_, val) => *val,
-            Value::Alloca(_, ty, ptr) => unsafe { LLVMBuildLoad2(b, *ty, *ptr, cstr!()) },
-            Value::Function(_, _, func_ptr) => *func_ptr,
-        }
-    }
-
-    /// Get the name of the dropper function, if any!
-    pub fn get_dropper_name(&self) -> Option<&'static str> {
-        match self.get_ast_type() {
-            ty if ty.is_variant() => Some("VVRTVariant_drop"),
-            ty if ty.is_table() => Some("VVRTTable_drop"),
-            ty if ty.is_sequence() => Some("VVRTSeq_drop"),
-            ASTType::Syllabe => Some("VVRTSyllabe_drop"),
-            ASTType::String => Some("VVRTString_drop"),
-            ASTType::Line => Some("VVRTLine_drop"),
-            ASTType::Any => Some("VVRTAny_drop"),
-
-            ASTType::Function(_, _) => todo!("handle functions and clozures..."),
-            _ => None,
-        }
-    }
-
-    /// Call a function with some values. Note that this function won't create memory manage points
-    /// for the passed values (see types that are managed and the ones that are not.)
-    pub fn call<const N: usize>(&self, b: LLVMBuilderRef, mut args: [LLVMValueRef; N]) -> LLVMValueRef {
-        match self {
-            Value::Function(_, func_ty, func_val) => unsafe {
-                let args_ptr = args.as_mut_ptr();
-                let args_len = args.len().try_into().expect("too much arguments");
-                LLVMBuildCall2(b, *func_ty, *func_val, args_ptr, args_len, c"".as_ptr())
-            },
-            val => panic!("can't call a non-function value: {val:?}"),
-        }
-    }
-
-    pub fn get_ast_type(&self) -> &ASTType {
-        const NIL: ASTType = ASTType::Nil;
-        match self {
-            Value::Nil => &NIL,
-            Value::Const(ty, _) | Value::Alloca(ty, _, _) | Value::Function(ty, _, _) => ty,
-        }
-    }
-}
-
-impl Typed for Value {
-    fn get_type(&self, _: &vvs_lang::ast::ASTTypeContext) -> ASTType {
-        self.get_ast_type().clone()
-    }
-}
diff --git a/src/Rust/vvs_font/build.rs b/src/Rust/vvs_font/build.rs
index 1ae42238..1dce12b8 100644
--- a/src/Rust/vvs_font/build.rs
+++ b/src/Rust/vvs_font/build.rs
@@ -24,38 +24,36 @@ fn main() {
     let fonts = fs::read_dir(&font_dir)
         .expect("failed to read the font folder")
         .filter_map(Result::ok)
+        .filter(|file| file.file_type().map(|ft| ft.is_file()).unwrap_or_default())
         .filter(|file| {
-            file.file_type().map(|ft| ft.is_file()).unwrap_or_default() && {
-                let path = file.path();
-                path.file_name()
-                    .map(|f| !EXCLUDED_FONTS.iter().any(|pat| f.to_string_lossy().starts_with(pat)))
-                    .unwrap_or_default()
-                    && path.extension().map(|e| e == "ttf").unwrap_or_default()
-            }
+            let path = file.path();
+            path.file_name()
+                .map(|f| !EXCLUDED_FONTS.iter().any(|pat| f.to_string_lossy().starts_with(pat)))
+                .unwrap_or_default()
+                && path.extension().map(|e| e == "ttf").unwrap_or_default()
         })
         .map(|file| {
-            let (path, file_name) = (file.path(), file.file_name());
-            let path = path.to_string_lossy();
-            let name = file_name.to_string_lossy();
-            let name = name.rsplit_once('.').unwrap().0;
-            format!("({name:?}, include_bytes!({path:?}))")
+            format!(
+                "{{ const FONT: &[u8] = include_bytes!({path:?}); ({name:?}, FONT) }}",
+                path = file.path().display(),
+                name = file.file_name().to_string_lossy().rsplit_once('.').unwrap().0
+            )
         })
         .collect::<Vec<_>>()
         .join(",\n");
 
-    // Generate
-    let src_content = format!(
-        r#"
-pub const fn embeded_fonts() -> &'static [(&'static str, &'static [u8])] {{
-    &[ {fonts} ]
+    fs::write(
+        out_dir.join("generated_font_utils.rs"),
+        format!(
+            r#"
+pub fn embeded_fonts() -> impl Iterator<Item = (&'static str, &'static [u8])> {{
+    [ {fonts} ].into_iter()
 }}
-        "#
-    );
+            "#
+        ),
+    )
+    .expect("failed to write generated source file");
 
-    // Write
-    fs::write(out_dir.join("generated_font_utils.rs"), src_content).expect("failed to write generated source file");
-
-    // Rerun
     rerun_directory(&font_dir);
     println!("cargo:rerun-if-changed=build.rs");
 }
diff --git a/src/Rust/vvs_lang/Cargo.toml b/src/Rust/vvs_lang/Cargo.toml
deleted file mode 100644
index 538d8c5f..00000000
--- a/src/Rust/vvs_lang/Cargo.toml
+++ /dev/null
@@ -1,21 +0,0 @@
-[package]
-name              = "vvs_lang"
-description       = "Vivy Script Language"
-version.workspace = true
-authors.workspace = true
-edition.workspace = true
-license.workspace = true
-
-[dependencies]
-thiserror.workspace   = true
-paste.workspace       = true
-serde.workspace       = true
-hashbrown.workspace   = true
-log.workspace         = true
-regex.workspace       = true
-anyhow.workspace      = true
-toml.workspace        = true
-derive_more.workspace = true
-
-vvs_utils.workspace  = true
-vvs_parser.workspace = true
diff --git a/src/Rust/vvs_lang/src/ast/constant.rs b/src/Rust/vvs_lang/src/ast/constant.rs
deleted file mode 100644
index 22af5e6b..00000000
--- a/src/Rust/vvs_lang/src/ast/constant.rs
+++ /dev/null
@@ -1,134 +0,0 @@
-use crate::ast::*;
-use anyhow::{anyhow, ensure, Context};
-
-/// A constant expr.
-#[derive(Debug, PartialEq, Clone)]
-pub enum ASTConst {
-    Nil,
-    False,
-    True,
-    Tuple(Vec<ASTConst>),
-    Color(ASTVariant<ASTConst>),
-    String(ASTString),
-    Integer(ASTInteger),
-    Floating(ASTFloating),
-    Table(ASTTable<ASTConst>),
-}
-
-/// Get the type for a const table, returns the more specialized type ([ASTType::UniformTable], etc)
-fn get_const_table_type(table: &ASTTable<ASTConst>) -> ASTType {
-    let integer_keys = table.keys().all(|key| key.parse::<i64>().is_ok());
-    let mut uniform_values = table.values().map(|val| val.get_const_type()).collect::<Vec<_>>();
-    let uniform_values = uniform_values
-        .pop()
-        .map(|ty| uniform_values.into_iter().all(|a| ty.eq(&a)).then_some(ty));
-    match (integer_keys, uniform_values) {
-        (true, Some(Some(ty))) => ASTType::Sequence(Box::new(ty)),
-        _ => ASTType::Table(
-            table
-                .iter()
-                .map(|(key, value)| (key.clone(), value.get_const_type()))
-                .collect(),
-        ),
-    }
-}
-
-impl Typed for ASTConst {
-    #[inline]
-    fn get_type(&self, _: &ASTTypeContext) -> ASTType {
-        self.get_const_type()
-    }
-}
-
-impl std::fmt::Display for ASTConst {
-    #[inline]
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            ASTConst::Nil => f.write_str("nil"),
-            ASTConst::False => f.write_str("false"),
-            ASTConst::True => f.write_str("true"),
-            ASTConst::Color(ASTVariant { variant, args }) => write!(f, "color#{variant}{args:?}"),
-            ASTConst::String(str) => write!(f, "{str:?}"),
-            ASTConst::Integer(int) => write!(f, "{int}"),
-            ASTConst::Floating(flt) => write!(f, "{flt}"),
-            ASTConst::Table(table) => write_ast_table(f, table),
-            ASTConst::Tuple(tuple) => write_ast_tuple(f, tuple),
-        }
-    }
-}
-
-impl MaybeConstExpr for ASTConst {
-    #[inline]
-    fn is_const_expr(&self) -> bool {
-        true
-    }
-
-    #[inline]
-    fn eval_const_expr(&self) -> Option<ASTConst> {
-        Some(self.clone())
-    }
-}
-
-impl ASTConst {
-    #[inline]
-    pub fn get_const_type(&self) -> ASTType {
-        match self {
-            ASTConst::Nil => ASTType::Nil,
-            ASTConst::True | ASTConst::False => ASTType::Boolean,
-            ASTConst::Color(..) => ASTType::Color,
-            ASTConst::String(_) => ASTType::String,
-            ASTConst::Integer(_) => ASTType::Integer,
-            ASTConst::Floating(_) => ASTType::Floating,
-            ASTConst::Tuple(inner) => ASTType::Tuple(inner.iter().map(|expr| expr.get_const_type()).collect()),
-            ASTConst::Table(content) => get_const_table_type(content),
-        }
-    }
-
-    /// Try to create an [ASTConst] from a [toml::Value]. We verify that the value is valid, i.e.
-    /// we don't have nested tables and such.
-    ///
-    /// NOTE: For now we can't construct colors and/or movements from toml values...
-    pub fn from_toml_value(cache: &ASTStringCacheHandle, value: toml::Value) -> anyhow::Result<Self> {
-        use toml::Value as TomlValue;
-
-        fn table_from_toml_value(
-            cache: &ASTStringCacheHandle,
-            mut values: impl Iterator<Item = (ASTString, TomlValue)>,
-        ) -> anyhow::Result<ASTConst> {
-            let (lower, upper) = values.size_hint();
-            let table = ASTTable::with_capacity(upper.unwrap_or(lower));
-            let table = values.try_fold(table, |mut table, (key, value)| {
-                let value = ASTConst::from_toml_value(cache, value)?;
-                ensure!(!matches!(value, ASTConst::Table(_)), "forbiden nested tables");
-                table
-                    .insert(key, value)
-                    .map(|_| Err(anyhow!("redefinition of a value in the table")))
-                    .unwrap_or(Ok(table))
-            })?;
-            Ok(ASTConst::Table(table))
-        }
-
-        match value {
-            TomlValue::Datetime(date) => Ok(ASTConst::String(cache.get(date.to_string()))),
-            TomlValue::String(str) => Ok(ASTConst::String(cache.get(str))),
-
-            TomlValue::Float(num) => Ok(ASTConst::Floating(num as f32)),
-            TomlValue::Integer(num) => Ok(ASTConst::Integer(num.try_into().context("integer overflow")?)),
-            TomlValue::Boolean(true) => Ok(ASTConst::True),
-            TomlValue::Boolean(false) => Ok(ASTConst::False),
-
-            TomlValue::Array(values) => {
-                ensure!(values.len() < i32::MAX as usize, "too many elements in array");
-                let values = values
-                    .into_iter()
-                    .enumerate()
-                    .map(|(k, v)| (cache.get(k.to_string()), v));
-                table_from_toml_value(cache, values)
-            }
-            TomlValue::Table(values) => {
-                ensure!(values.len() < i32::MAX as usize, "too many elements in table");
-                table_from_toml_value(cache, values.into_iter().map(|(k, v)| (cache.get(k), v)))
-            }
-        }
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/expression.rs b/src/Rust/vvs_lang/src/ast/expression.rs
deleted file mode 100644
index 79d482fb..00000000
--- a/src/Rust/vvs_lang/src/ast/expression.rs
+++ /dev/null
@@ -1,441 +0,0 @@
-use crate::ast::*;
-use std::ops::{Deref, DerefMut};
-
-#[macro_export]
-macro_rules! anon_expression {
-    (const     $variant: ident $($args: tt)?) => { $crate::anon_expression!(Const (ASTConst::$variant $($args)?)) };
-    (box const $variant: ident $($args: tt)?) => { Box::new($crate::anon_expression!(Const (ASTConst::$variant $($args)?))) };
-    (box       $variant: ident $($args: tt)?) => { Box::new($crate::anon_expression!($variant $($args)?)) };
-
-    ($variant: ident $($args: tt)?) => {
-        ASTExpr {
-            span: Default::default(),
-            content: ASTExprVariant::$variant $($args)?,
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! expression {
-    ($span: expr, $variant: ident $($args: tt)?) => {
-        ASTExpr {
-            span: $span.into(),
-            content: ASTExprVariant::$variant $($args)?,
-        }
-    };
-}
-
-/// Binops, sorted by precedence.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum ASTBinop {
-    /// Assoc: right
-    Power,
-
-    Mul,
-    Div,
-    Mod,
-    Add,
-    Sub,
-
-    /// Assoc: right
-    StrCat,
-
-    CmpLE,
-    CmpLT,
-    CmpGE,
-    CmpGT,
-    CmpEQ,
-    CmpNE,
-
-    LogicAnd,
-    LogicXor,
-    LogicOr,
-
-    BitAnd,
-    BitXor,
-    BitOr,
-    BitShiftLeft,
-    BitShiftRight,
-}
-
-/// Unops.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum ASTUnop {
-    LogicNot,
-    BitNot,
-    Len,
-    Neg,
-}
-
-/// Expressions. For the partial equality we skip the span field to be able to test efficiently the
-/// parsing.
-#[derive(Debug, Clone, Default)]
-pub struct ASTExpr {
-    pub content: ASTExprVariant,
-    pub span: ASTSpan,
-}
-
-/// Expressions.
-#[derive(Debug, PartialEq, Clone)]
-pub enum ASTExprVariant {
-    /// A table, like in Lua
-    Table(ASTTable<ASTExpr>),
-
-    /// A binary operation, like in most of languages.
-    Binop(Box<ASTExpr>, ASTBinop, Box<ASTExpr>),
-
-    /// A unary operation, like in most of languages.
-    Unop(ASTUnop, Box<ASTExpr>),
-
-    /// A call to a function.
-    FuncCall(Box<ASTExpr>, Vec<ASTExpr>),
-
-    /// A function where the first arguments are binded.
-    FuncBind(Box<ASTExpr>, Vec<ASTExpr>),
-
-    /// Invocation of a method. To call a function from a table, we don't use the
-    /// [ASTExprVariant::MethodInvok] thing, but a [ASTExprVariant::FuncCall] where the first
-    /// element is the dereferencing of the table. Here the name of the method must be known and be
-    /// like: `{ty}::{method}`.
-    MethodInvok(Box<ASTExpr>, ASTString, Vec<ASTExpr>),
-
-    /// We access fields from an expression.
-    Suffixed(Box<ASTExpr>, Vec<ASTField>),
-
-    /// A non-constant expression color.
-    Color(ASTVariant<ASTExpr>),
-
-    /// Represents a movement for a line or syllabe. We don't have a constant variant for this
-    /// representation because movements are very dynamic (it depends on the resolution of the
-    /// video...) and thus doesn't make much sense to have a constant movement.
-    ///
-    /// NOTE: See if other people agree to that, there can be some arguments for having a constant
-    ///       movement or an optional one.
-    Movement(ASTVariant<ASTExpr>),
-
-    /// A tuple, Lua don't have ones but because we won't be stack based we can't do the multiple
-    /// return thing without a tuple...
-    Tuple(Vec<ASTExpr>),
-
-    /// A variable load.
-    Var(ASTVar),
-
-    /// A constant expression.
-    Const(ASTConst),
-
-    /// The default value for a type.
-    Default(ASTType),
-}
-
-/// Fields indexes can be expressions or identifiers
-#[derive(Debug, PartialEq, Clone)]
-pub enum ASTField {
-    /// We index by a string or an integer...
-    Expr(ASTSpan, ASTExprVariant),
-
-    /// A name field.
-    Identifier(ASTSpan, ASTString),
-}
-
-impl PartialEq for ASTExpr {
-    #[inline]
-    fn eq(&self, other: &Self) -> bool {
-        self.content == other.content
-    }
-}
-
-/// Get the type for a table, returns the more specialized type ([ASTType::UniformTable], etc)
-fn get_table_type<T: Typed>(table: &ASTTable<T>, ctx: &ASTTypeContext) -> ASTType {
-    let integer_keys = table.keys().all(|key| key.parse::<i64>().is_ok());
-    let mut uniform_values = table.values().map(|val| val.get_type(ctx)).collect::<Vec<_>>();
-    let uniform_values = uniform_values
-        .pop()
-        .map(|ty| uniform_values.into_iter().all(|a| ty.eq(&a)).then_some(ty));
-    match (integer_keys, uniform_values) {
-        (true, Some(Some(ty))) => ASTType::Sequence(Box::new(ty)),
-        _ => ASTType::Table(
-            table
-                .iter()
-                .map(|(key, value)| (key.clone(), value.get_type(ctx)))
-                .collect(),
-        ),
-    }
-}
-
-fn get_table_deref_type(ctx: &ASTTypeContext, table: ASTType, fields: &[ASTField]) -> ASTType {
-    let (first, tail) = match fields {
-        [] => return table,
-        [first, tail @ ..] => (first, tail),
-    };
-
-    match table {
-        ASTType::Tuple(_) => todo!(),
-
-        ASTType::AnyTable => ASTType::Any,
-        ASTType::Table(_) => todo!(),
-        ASTType::UniformTable(_) => todo!(),
-
-        ty @ ASTType::Syllabe | ty @ ASTType::Line => match first {
-            ASTField::Expr(..) => ASTType::Nil,
-            ASTField::Identifier(_, field) => {
-                let ty = crate::ast::get_field_extensions(ctx, ty)
-                    .find_map(|(key, ty)| key.eq(&field.as_ref()).then_some(ty.clone()))
-                    .unwrap_or(ASTType::Nil);
-                get_table_deref_type(ctx, ty, tail)
-            }
-        },
-
-        _ => ASTType::Nil,
-    }
-}
-
-impl Typed for ASTExprVariant {
-    fn get_type(&self, ctx: &ASTTypeContext) -> ASTType {
-        use crate::ast::{ASTBinop::*, ASTUnop::*};
-        match self {
-            ASTExprVariant::FuncBind(_, _) => todo!(),
-
-            ASTExprVariant::MethodInvok(_, _, _) => todo!(),
-
-            ASTExprVariant::FuncCall(_, _) => todo!(),
-
-            ASTExprVariant::Default(ty) => ty.clone(),
-            ASTExprVariant::Color(_) => ASTType::Color,
-            ASTExprVariant::Movement(_) => ASTType::Movement,
-            ASTExprVariant::Const(r#const) => r#const.get_type(ctx),
-
-            ASTExprVariant::Var(var) => match var.get_specified_type() {
-                Some(ty) => ty.clone(),
-                None => ctx.get(var),
-            },
-
-            ASTExprVariant::Tuple(tuple) => ASTType::Tuple(tuple.iter().map(|expr| expr.get_type(ctx)).collect()),
-            ASTExprVariant::Table(table) => get_table_type(table, ctx),
-            ASTExprVariant::Suffixed(expr, fields) => get_table_deref_type(ctx, expr.get_type(ctx), fields),
-
-            ASTExprVariant::Unop(op, inner) => {
-                use ASTType::*;
-                match (op, inner.get_type(ctx)) {
-                    (BitNot | LogicNot, ty @ Integer | ty @ Boolean) => ty,
-                    (Neg, ty @ Floating | ty @ Integer | ty @ Boolean) => ty,
-                    (
-                        Len,
-                        String | Tuple(_) | Syllabe | Line | AnyTable | UniformTable(_) | AnySequence | Table(_)
-                        | Sequence(_),
-                    ) => Integer,
-                    _ => Nil,
-                }
-            }
-
-            ASTExprVariant::Binop(left, op, right) => {
-                use ASTType::*;
-                let (left, right) = (left.get_type(ctx), right.get_type(ctx));
-                match op {
-                    Power => match (left, right) {
-                        (ty @ Integer | ty @ Floating, Integer) => ty,
-                        _ => Nil,
-                    },
-
-                    Mul | Div | Add | Sub => match (left, right) {
-                        (ty @ Integer, Integer) | (ty @ Floating, Floating) => ty,
-                        _ => Nil,
-                    },
-
-                    Mod => match (left, right) {
-                        (Integer, Integer) => Integer,
-                        _ => Nil,
-                    },
-
-                    StrCat => match (left, right) {
-                        (String, String) => String,
-                        _ => Nil,
-                    },
-
-                    CmpLE | CmpLT | CmpGE | CmpGT => match (left, right) {
-                        (Integer, Integer) | (Floating, Floating) => Boolean,
-                        _ => Nil,
-                    },
-
-                    CmpEQ | CmpNE => match right.coercible_to(&left) {
-                        true => Boolean,
-                        false => Nil,
-                    },
-
-                    LogicAnd | LogicXor | LogicOr => match (left, right) {
-                        (Boolean, Boolean) => Boolean,
-                        _ => Nil,
-                    },
-
-                    BitAnd | BitXor | BitOr => match (left, right) {
-                        (Integer, Integer) => Integer,
-                        (Boolean, Boolean) => Boolean,
-                        _ => Nil,
-                    },
-
-                    BitShiftLeft | BitShiftRight => match (left, right) {
-                        (Integer, Integer) => Integer,
-                        _ => Nil,
-                    },
-                }
-            }
-        }
-    }
-}
-
-impl Deref for ASTExpr {
-    type Target = ASTExprVariant;
-    #[inline]
-    fn deref(&self) -> &Self::Target {
-        &self.content
-    }
-}
-
-impl DerefMut for ASTExpr {
-    #[inline]
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.content
-    }
-}
-
-impl VariantName for ASTExpr {
-    #[inline]
-    fn variant_name(&self) -> &'static str {
-        self.content.variant_name()
-    }
-}
-
-impl VariantName for ASTExprVariant {
-    #[inline]
-    fn variant_name(&self) -> &'static str {
-        match self {
-            ASTExprVariant::Movement(_) => "movement",
-            ASTExprVariant::Color(_) => "color",
-            ASTExprVariant::Table(_) => "table",
-            ASTExprVariant::Binop(_, _, _) => "binary operation",
-            ASTExprVariant::Unop(_, _) => "unary operation",
-            ASTExprVariant::FuncCall(_, _) => "function call",
-            ASTExprVariant::FuncBind(_, _) => "function bind",
-            ASTExprVariant::MethodInvok(_, _, _) => "method invokation",
-            ASTExprVariant::Suffixed(_, _) => "prefixed expression",
-            ASTExprVariant::Tuple(_) => "tuple",
-            ASTExprVariant::Var(_) => "variable",
-            ASTExprVariant::Const(_) => "constant",
-            ASTExprVariant::Default(_) => "default",
-        }
-    }
-}
-
-impl ASTField {
-    #[inline]
-    pub fn span(&self) -> ASTSpan {
-        match self {
-            ASTField::Expr(span, _) | ASTField::Identifier(span, _) => *span,
-        }
-    }
-}
-
-impl MaybeConstExpr for ASTExprVariant {
-    fn is_const_expr(&self) -> bool {
-        use ASTExprVariant::*;
-        match self {
-            // We don't do constant method invokation for now.
-            FuncCall(_, _) | MethodInvok(_, _, _) | FuncBind(_, _) => false,
-
-            // Depends on the content.
-            Binop(l, _, r) => l.is_const_expr() && r.is_const_expr(),
-            Unop(_, inner) => inner.is_const_expr(),
-            Tuple(inner) => inner.iter().all(|expr| expr.is_const_expr()),
-            Color(variant) | Movement(variant) => variant.is_const_expr(),
-            Suffixed(table, suffixes) => table.is_const_expr() && suffixes.iter().all(|field| field.is_const_expr()),
-            Default(ty) => ty.is_const_constructible(),
-
-            // Well, it depend, for now we will say that it's not compile time evaluable.
-            Table(_) => false,
-            Var(_) => false,
-
-            // Obviously
-            Const(_) => true,
-        }
-    }
-
-    fn eval_const_expr(&self) -> Option<ASTConst> {
-        use ASTExprVariant::*;
-        match self {
-            Const(r#const) => Some(r#const.clone()),
-
-            Binop(_, _, _) => todo!(),
-            Unop(_, _) => todo!(),
-
-            Default(ty) if ty.is_const_constructible() => Some(match ty {
-                ASTType::Nil | ASTType::Any => ASTConst::Nil,
-                ASTType::Integer => ASTConst::Integer(0),
-                ASTType::Floating => ASTConst::Floating(0.),
-                ASTType::Boolean => ASTConst::False,
-                _ => unreachable!(),
-            }),
-
-            Color(ASTVariant { variant, args }) => Some(ASTConst::Color(ASTVariant {
-                variant: variant.clone(),
-                args: args
-                    .iter()
-                    .map(|expr| expr.eval_const_expr().ok_or(()))
-                    .collect::<Result<Vec<_>, _>>()
-                    .ok()?,
-            })),
-
-            Tuple(inner) => Some(ASTConst::Tuple(
-                inner
-                    .iter()
-                    .map(|expr| expr.eval_const_expr().ok_or(()))
-                    .collect::<Result<Vec<_>, _>>()
-                    .ok()?,
-            )),
-
-            Suffixed(_, _)
-            | FuncCall(_, _)
-            | FuncBind(_, _)
-            | MethodInvok(_, _, _)
-            | Table(_)
-            | Movement(_)
-            | Default(_)
-            | Var(_) => None,
-        }
-    }
-}
-
-impl Typed for ASTField {
-    #[inline]
-    fn get_type(&self, ctx: &ASTTypeContext) -> ASTType {
-        match self {
-            ASTField::Expr(_, expr) => expr.get_type(ctx),
-            ASTField::Identifier(sp, name) => {
-                let var = ASTVar::new(ctx.strings()).span(sp).name(name.clone()).build();
-                ctx.get(&var)
-            }
-        }
-    }
-}
-
-impl MaybeConstExpr for ASTField {
-    #[inline]
-    fn is_const_expr(&self) -> bool {
-        match self {
-            ASTField::Expr(_, expr) => expr.is_const_expr(),
-            ASTField::Identifier(_, _) => false,
-        }
-    }
-
-    #[inline]
-    fn eval_const_expr(&self) -> Option<ASTConst> {
-        match self {
-            ASTField::Identifier(..) => None,
-            ASTField::Expr(_, expr) => expr.eval_const_expr(),
-        }
-    }
-}
-
-impl Default for ASTExprVariant {
-    fn default() -> Self {
-        ASTExprVariant::Const(ASTConst::Nil)
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/extension.rs b/src/Rust/vvs_lang/src/ast/extension.rs
deleted file mode 100644
index 3cf13f38..00000000
--- a/src/Rust/vvs_lang/src/ast/extension.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use crate::ast::{ASTType, ASTTypeContext};
-
-#[inline]
-pub fn get_field_extensions(_: &ASTTypeContext, ass_type: ASTType) -> impl Iterator<Item = &(&'static str, ASTType)> {
-    log::error!("todo: add user options for each item");
-    match ass_type {
-        ASTType::Syllabe => [("start", ASTType::Integer), ("finish", ASTType::Integer)].iter(),
-        ASTType::Line => [("start", ASTType::Integer), ("finish", ASTType::Integer)].iter(),
-        _ => unreachable!(),
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/function.rs b/src/Rust/vvs_lang/src/ast/function.rs
deleted file mode 100644
index 6c20bc5b..00000000
--- a/src/Rust/vvs_lang/src/ast/function.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-use crate::ast::*;
-
-/// A function. Can also represent a job.
-#[derive(Debug, Clone)]
-pub struct ASTFunction {
-    pub name: ASTString,
-    pub returns: ASTType,
-    pub arguments: Vec<ASTVar>,
-    pub content: ASTInstr,
-
-    pub span: ASTSpan,
-}
-
-/// The signature of a callable thing in Vivy Script.
-pub type ASTFunctionSignature = (Vec<ASTType>, ASTType);
-
-impl ASTFunction {
-    /// Get the signature of a function.
-    #[inline]
-    pub fn signature(&self) -> ASTFunctionSignature {
-        let args = self
-            .arguments
-            .iter()
-            .flat_map(ASTVar::get_specified_type)
-            .cloned()
-            .collect();
-        (args, self.returns.clone())
-    }
-
-    /// Get the type of this function, as a function tpe.
-    #[inline]
-    pub fn function_type(&self) -> ASTType {
-        let (args, returns) = self.signature();
-        ASTType::Function(args, Box::new(returns))
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/identifier.rs b/src/Rust/vvs_lang/src/ast/identifier.rs
deleted file mode 100644
index 4cc9e144..00000000
--- a/src/Rust/vvs_lang/src/ast/identifier.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-use crate::ast::*;
-
-#[derive(Debug, Default, PartialEq, Eq, Clone)]
-pub enum ASTIdentifier {
-    /// We ignore the value, like in ocaml and rust, this is the '_'.
-    #[default]
-    Joker,
-
-    /// A normal identifier, one that can be used by the user.
-    String(ASTString),
-
-    /// If an identifier begins by '_' and is followed other things then it is reserved by the
-    /// parser, the generator, and other things. Those identifiers can't be used by a user and they
-    /// should never see one.
-    Reserved(ASTString),
-}
-
-impl std::fmt::Display for ASTIdentifier {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.write_str(self.as_ref())
-    }
-}
-
-impl AsRef<str> for ASTIdentifier {
-    fn as_ref(&self) -> &str {
-        use ASTIdentifier::*;
-        match self {
-            Joker => "_",
-            String(str) | Reserved(str) => str.as_ref(),
-        }
-    }
-}
-
-impl ASTIdentifier {
-    /// Create a new identifier. The passed string will be trimed. If the string is empty or
-    /// contains non ascii-alphanumeric-underscored characters then an error will be raised.
-    pub fn new(cache: ASTStringCacheHandle, identifier: impl AsRef<str>) -> Result<Self, String> {
-        let identifier = identifier.as_ref().trim();
-        match identifier
-            .char_indices()
-            .find(|(_, c)| '_'.ne(c) && !c.is_ascii_alphanumeric())
-        {
-            Some((idx, char)) => Err(format!("found invalid character '{char}' in identifier at index {idx}")),
-            None => {
-                if identifier.is_empty() {
-                    Err("an identifier can't be empty".to_string())
-                } else if identifier.starts_with('_') && identifier.len() == 1 {
-                    Ok(Self::Joker)
-                } else if identifier.starts_with('_') {
-                    Ok(Self::Reserved(cache.get(identifier.trim_start_matches('_'))))
-                } else {
-                    Ok(Self::Reserved(cache.get(identifier)))
-                }
-            }
-        }
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/import.rs b/src/Rust/vvs_lang/src/ast/import.rs
deleted file mode 100644
index f538506d..00000000
--- a/src/Rust/vvs_lang/src/ast/import.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-use crate::ast::{ASTModule, ASTModulePtr, ASTString};
-use hashbrown::HashMap;
-use std::{
-    cell::RefCell,
-    path::{Path, PathBuf},
-    rc::Rc,
-};
-
-/// Structure used to resolve module imports.
-///
-/// By default, includes the current working dir.
-#[derive(Debug)]
-pub struct ImportResolver {
-    path: Vec<PathBuf>,
-    cache: Rc<RefCell<HashMap<ASTString, ASTModulePtr>>>,
-}
-
-pub(crate) enum ResolveResult {
-    Path(PathBuf),
-    Module(ASTModulePtr),
-}
-
-impl FromIterator<PathBuf> for ImportResolver {
-    #[inline]
-    fn from_iter<T: IntoIterator<Item = PathBuf>>(iter: T) -> Self {
-        Self { path: iter.into_iter().collect(), cache: Default::default() }
-    }
-}
-
-impl Default for ImportResolver {
-    /// Get the default import resolver, always includes the current working dir...
-    #[inline]
-    fn default() -> Self {
-        Self { path: vec![std::env::current_dir().expect("failed to get the CWD")], cache: Default::default() }
-    }
-}
-
-impl ImportResolver {
-    /// Create a new empty resolver. Note that it's different from the default resolver that uses
-    /// the current working directory (CWD, PWD, etc...)
-    #[inline]
-    pub fn empty() -> Self {
-        Self { path: vec![], cache: Default::default() }
-    }
-
-    pub(crate) fn resolve(&self, module: impl AsRef<str>) -> Option<ResolveResult> {
-        let find = |prefix| Self::get_file_path(prefix, module.as_ref()).map(ResolveResult::Path);
-        self.cache
-            .borrow()
-            .get(module.as_ref())
-            .cloned()
-            .map(ResolveResult::Module)
-            .or_else(|| self.path.iter().find_map(find))
-    }
-
-    #[inline]
-    pub(crate) fn cache_module(&self, name: ASTString, module: ASTModulePtr) {
-        if let Some(module) = self.cache.borrow_mut().insert(name, module) {
-            log::error!("re-cache module `{}`", ASTModule::get(&module).name())
-        }
-    }
-
-    fn get_file_path(prefix: impl AsRef<Path>, module: impl AsRef<str>) -> Option<PathBuf> {
-        let mut file = prefix.as_ref().join(module.as_ref());
-        file.set_extension("vvl");
-        file.canonicalize()
-            .map_err(|err| match err.kind() {
-                std::io::ErrorKind::NotFound => (),
-                err => log::error!(
-                    "failed to lookup for `{}` in `{}`: {err}",
-                    module.as_ref(),
-                    prefix.as_ref().to_string_lossy()
-                ),
-            })
-            .ok()
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/instruction.rs b/src/Rust/vvs_lang/src/ast/instruction.rs
deleted file mode 100644
index 57e64ffa..00000000
--- a/src/Rust/vvs_lang/src/ast/instruction.rs
+++ /dev/null
@@ -1,187 +0,0 @@
-use crate::ast::*;
-use std::ops::{Deref, DerefMut};
-
-#[macro_export]
-macro_rules! anon_instruction {
-    ($variant: ident $($args: tt)?) => {
-        ASTInstr {
-            span: Default::default(),
-            content: ASTInstrVariant::$variant $($args)?,
-        }
-    };
-}
-
-#[macro_export]
-macro_rules! instruction {
-    ($span: expr, $variant: ident $($args: tt)?) => {
-        ASTInstr {
-            span: $span.into(),
-            content: ASTInstrVariant::$variant $($args)?,
-        }
-    };
-}
-
-/// Instructions.
-#[derive(Debug, Clone)]
-pub struct ASTInstr {
-    pub content: ASTInstrVariant,
-    pub span: ASTSpan,
-}
-
-/// Instructions.
-#[derive(Debug, PartialEq, Clone)]
-pub enum ASTInstrVariant {
-    /// Declare variables with something inside.
-    Decl(Vec<ASTVar>, Vec<ASTExpr>),
-
-    /// Assign into variables.
-    Assign(Vec<ASTExpr>, Vec<ASTExpr>),
-
-    /// A function call.
-    FuncCall(Box<ASTExpr>, Vec<ASTExpr>),
-
-    /// A method invokation.
-    MethodInvok(Box<ASTExpr>, ASTString, Vec<ASTExpr>),
-
-    /// Begin a block.
-    Block(Vec<ASTInstr>),
-
-    /// A WhileDo instruction.
-    WhileDo(ASTCondition, Box<ASTInstr>),
-
-    /// Conditionals, contract the elseid blocks.
-    Cond { if_blocks: Vec<(ASTCondition, ASTInstr)>, else_block: Option<Box<ASTInstr>> },
-
-    /// For loop, the classic one:
-    /// ```vvs
-    /// for elem = 1, 3, 1 do print(elem) end
-    /// ```
-    ForLoop { var: ASTVar, lower: ASTExpr, upper: ASTExpr, step: Option<ASTInteger>, body: Box<ASTInstr> },
-
-    /// For loop with an iterable expression (table):
-    /// ```vvs
-    /// for elem in { 1, 2, 3 } do print(elem) end
-    /// for elem in ( 1, 2, 3 ) do print(elem) end
-    /// for elem in my_table    do print(elem) end
-    /// ```
-    ForInto { var: ASTVar, list: ASTExpr, body: Box<ASTInstr> },
-
-    /// Just a noop.
-    Noop,
-
-    /// Final thing: break from block.
-    Break,
-
-    /// Final thing: continue to next iteration.
-    Continue,
-
-    /// Final thing: return something.
-    Return(ASTExpr),
-}
-
-impl PartialEq for ASTInstr {
-    fn eq(&self, other: &Self) -> bool {
-        self.content == other.content
-    }
-}
-
-fn get_instruction_slice_type(ctx: &ASTTypeContext, block: &[ASTInstr]) -> ASTType {
-    let Some((last, instructions)) = block.split_last() else {
-        return ASTType::Nil;
-    };
-    let coerce_type = |from: ASTType, var: &ASTVar| {
-        let (span, ty, name) = (var.span(), var.get_specified_type().unwrap_or(&from), var.name());
-        let strings = ctx.strings();
-        let var = ASTVar::new(strings).span(span).name(name.clone());
-        if from.coercible_to(ty) {
-            var.with_type(from).build()
-        } else {
-            log::error!(target: "cc", "{span}; try to assign value of type `{from}` into `{name}: {ty}`");
-            var.with_type(ASTType::Nil).build()
-        }
-    };
-    let fold_declaration = |mut ctx, (var, from): (&ASTVar, &ASTExpr)| {
-        let var = coerce_type(from.get_type(&ctx), var);
-        let (_, var_ty) = (var.span(), var.get_type(&ctx));
-        ctx.declare(var, var_ty);
-        ctx
-    };
-    let fold_on_declaration = |ctx, instruction: &ASTInstr| match &instruction.content {
-        ASTInstrVariant::Decl(vars, froms) => vars.iter().zip(froms.iter()).fold(ctx, fold_declaration),
-        _ => ctx,
-    };
-    last.get_type(&instructions.iter().fold(ctx.for_scope(), fold_on_declaration))
-}
-
-impl Typed for ASTInstrVariant {
-    fn get_type(&self, ctx: &ASTTypeContext) -> ASTType {
-        match self {
-            ASTInstrVariant::Decl(_, _)
-            | ASTInstrVariant::Noop
-            | ASTInstrVariant::Assign(_, _)
-            | ASTInstrVariant::Break
-            | ASTInstrVariant::Continue => ASTType::Nil,
-
-            ASTInstrVariant::WhileDo(_, _) | ASTInstrVariant::ForLoop { .. } | ASTInstrVariant::ForInto { .. } => {
-                ASTType::Nil
-            }
-
-            ASTInstrVariant::Return(expr) => expr.get_type(ctx),
-            ASTInstrVariant::Block(block) => get_instruction_slice_type(ctx, block),
-            ASTInstrVariant::Cond { if_blocks, else_block } => {
-                let mut types = else_block
-                    .as_ref()
-                    .map(|i| i.get_type(ctx))
-                    .into_iter()
-                    .chain(if_blocks.iter().map(|(_, i)| i.get_type(ctx)));
-                types
-                    .next()
-                    .and_then(|ty| types.all(|other| ty.eq(&other)).then_some(ty))
-                    .unwrap_or_default()
-            }
-
-            ASTInstrVariant::MethodInvok(_, _, _) | ASTInstrVariant::FuncCall(_, _) => todo!("implement clozures"),
-        }
-    }
-}
-
-impl Deref for ASTInstr {
-    type Target = ASTInstrVariant;
-
-    fn deref(&self) -> &Self::Target {
-        &self.content
-    }
-}
-
-impl DerefMut for ASTInstr {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        &mut self.content
-    }
-}
-
-impl VariantName for ASTInstr {
-    fn variant_name(&self) -> &'static str {
-        self.content.variant_name()
-    }
-}
-
-impl VariantName for ASTInstrVariant {
-    fn variant_name(&self) -> &'static str {
-        match self {
-            ASTInstrVariant::Decl(_, _) => "variable declaration",
-            ASTInstrVariant::Assign(_, _) => "variable assignation",
-            ASTInstrVariant::FuncCall(_, _) => "function call",
-            ASTInstrVariant::MethodInvok(_, _, _) => "method invokation",
-            ASTInstrVariant::Block(_) => "instruction block",
-            ASTInstrVariant::WhileDo(_, _) => "while loop",
-            ASTInstrVariant::Cond { .. } => "conditionals",
-            ASTInstrVariant::ForLoop { step: Some(_), .. } => "for loop with step",
-            ASTInstrVariant::ForLoop { step: None, .. } => "for loop",
-            ASTInstrVariant::ForInto { .. } => "for into loop",
-            ASTInstrVariant::Noop => "noop",
-            ASTInstrVariant::Break => "break statement",
-            ASTInstrVariant::Continue => "continue statement",
-            ASTInstrVariant::Return(_) => "return statement",
-        }
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/maybe_const_expr.rs b/src/Rust/vvs_lang/src/ast/maybe_const_expr.rs
deleted file mode 100644
index d0e05e45..00000000
--- a/src/Rust/vvs_lang/src/ast/maybe_const_expr.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-use crate::ast::*;
-use std::ops::Deref;
-
-/// Trait for objects that are typed and may be values known at compile time.
-///
-/// As long a a type can be dereferenced into a [MaybeConstExpr] thing, it is [MaybeConstExpr].
-pub trait MaybeConstExpr: Typed {
-    /// Tells whether the thing is a constant expression or not.
-    fn is_const_expr(&self) -> bool;
-
-    /// Evaluate the expression, if it is indeed a constant expression then returns the result,
-    /// otherwise return [None].
-    fn eval_const_expr(&self) -> Option<ASTConst>;
-}
-
-impl<S: MaybeConstExpr, T: Deref<Target = S>> MaybeConstExpr for T {
-    #[inline]
-    fn is_const_expr(&self) -> bool {
-        self.deref().is_const_expr()
-    }
-
-    #[inline]
-    fn eval_const_expr(&self) -> Option<ASTConst> {
-        self.deref().eval_const_expr()
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/mod.rs b/src/Rust/vvs_lang/src/ast/mod.rs
deleted file mode 100644
index 8da5d32a..00000000
--- a/src/Rust/vvs_lang/src/ast/mod.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-//! Module used to store all the definition of the AST used for parsing VVS/VVL files.
-
-mod constant;
-mod expression;
-mod extension;
-mod function;
-mod identifier;
-mod import;
-mod instruction;
-mod maybe_const_expr;
-mod module;
-mod options;
-mod pattern;
-mod program;
-mod span;
-mod string;
-mod type_context;
-mod typed;
-mod types;
-mod variable;
-mod variant;
-mod visibility;
-
-use hashbrown::HashMap;
-use std::rc::Rc;
-
-pub use self::{
-    constant::*, expression::*, extension::*, function::*, identifier::*, import::*, instruction::*,
-    maybe_const_expr::*, module::*, options::*, pattern::*, program::*, span::*, string::*, type_context::*, typed::*,
-    types::*, variable::*, variant::*, visibility::*,
-};
-
-pub type ASTString = Rc<str>;
-pub type ASTFloating = f32;
-pub type ASTInteger = i32;
-pub type ASTTable<T> = HashMap<ASTString, T>;
-
-pub fn write_ast_table<T: std::fmt::Display>(f: &mut std::fmt::Formatter<'_>, table: &ASTTable<T>) -> std::fmt::Result {
-    f.write_str("{")?;
-    if let Some((key, value)) = table.iter().next() {
-        write!(f, " {key} = {value}")?;
-    }
-    for (key, value) in table.iter().skip(1) {
-        write!(f, ", {key} = {value}")?;
-    }
-    f.write_str(" }")
-}
-
-pub fn write_ast_tuple<T: std::fmt::Display>(f: &mut std::fmt::Formatter<'_>, tuple: &[T]) -> std::fmt::Result {
-    f.write_str("(")?;
-    if let Some(value) = tuple.iter().next() {
-        write!(f, " {value}")?;
-    }
-    for value in tuple.iter().skip(1) {
-        write!(f, ", {value}")?;
-    }
-    f.write_str(" )")
-}
-
-/// Trait that allows to get a variant name out of an enum or a struct containing an enum.
-pub(crate) trait VariantName {
-    /// Get the name out of the value.
-    fn variant_name(&self) -> &'static str;
-}
diff --git a/src/Rust/vvs_lang/src/ast/module.rs b/src/Rust/vvs_lang/src/ast/module.rs
deleted file mode 100644
index d7eba73a..00000000
--- a/src/Rust/vvs_lang/src/ast/module.rs
+++ /dev/null
@@ -1,201 +0,0 @@
-use crate::ast::*;
-use hashbrown::{HashMap, HashSet};
-use std::{
-    cell::UnsafeCell,
-    rc::{Rc, Weak},
-};
-
-/// A VVL module of a Vivy Script
-#[derive(Debug, Clone)]
-pub struct ASTModule {
-    /// The name of the module, should be a valid identifier.
-    name: ASTString,
-
-    /// Checks if we want to put it into the type context or not...
-    variants: HashMap<ASTString, ASTVariantRules>,
-
-    functions: HashMap<ASTString, (ASTVisibility, ASTFunction)>,
-    jobs: HashMap<ASTString, (ASTVisibility, ASTFunction)>,
-    consts: HashMap<ASTString, (ASTVisibility, ASTVar, ASTConst)>,
-    options: HashMap<ASTString, (ASTVar, ASTConst)>,
-    imports: HashMap<ASTString, (ASTSpan, ASTModulePtr)>,
-
-    /// Contains all the symbols available in the module, to be sure that options, constants,
-    /// functions and jobs doesn't enter in collision.
-    symbols: HashSet<ASTString>,
-
-    /// Caching for strings, identified by their hash and reuse the same memory location to reduce
-    /// memory footprint. Use the .finish function from the hasher to get the key.
-    strings: ASTStringCacheHandle,
-
-    /// Type context intern to the module. This is self-referencing. Under the hood we use a weak
-    /// pointer and a lazy initialize thingy for the type context.
-    tyctx: ASTTypeContext,
-}
-
-pub type ASTModulePtr = Rc<UnsafeCell<ASTModule>>;
-pub type ASTModuleWeakPtr = Weak<UnsafeCell<ASTModule>>;
-
-impl ASTModule {
-    /// Create a new empty module.
-    #[inline]
-    pub fn new(name: ASTString, strings: ASTStringCacheHandle) -> ASTModulePtr {
-        Rc::new_cyclic(|ptr| {
-            let colors_rules = ASTVariantRules::new_colors(strings.clone());
-            let movement_rules = ASTVariantRules::new_movements(strings.clone());
-            UnsafeCell::new(Self {
-                name,
-                strings,
-                tyctx: ASTTypeContext::new(ptr.clone()),
-                variants: HashMap::from_iter([
-                    (colors_rules.name(), colors_rules),
-                    (movement_rules.name(), movement_rules),
-                ]),
-                symbols: Default::default(),
-                functions: Default::default(),
-                jobs: Default::default(),
-                consts: Default::default(),
-                options: Default::default(),
-                imports: Default::default(),
-            })
-        })
-    }
-
-    /// Get all the variant rules.
-    #[inline]
-    pub fn all_variant_rules(&self) -> &HashMap<ASTString, ASTVariantRules> {
-        &self.variants
-    }
-
-    /// Get a set of rule for a specified variant if it exists in a mutable way. We only expose
-    /// this function to this crate because it's the only place where we want to be able to mutate
-    /// the module.
-    #[inline]
-    pub(crate) fn variant_rules_mut(&mut self, rule: impl AsRef<str>) -> Option<&mut ASTVariantRules> {
-        self.variants.get_mut(rule.as_ref())
-    }
-
-    /// Get the type context in a constant way.
-    #[inline]
-    pub fn tyctx(&self) -> &ASTTypeContext {
-        &self.tyctx
-    }
-
-    /// Get the type context in a mutable way. Only possible if we have a mutable reference to the
-    /// module anyway. If there are multiple strong references to the module it won't be correct...
-    #[inline]
-    pub fn tyctx_mut(&mut self) -> &mut ASTTypeContext {
-        &mut self.tyctx
-    }
-
-    /// Get the name of the module.
-    #[inline]
-    pub fn name(&self) -> ASTString {
-        self.name.clone()
-    }
-
-    /// Get a specific option if it exists.
-    #[inline]
-    pub fn option(&self, option: impl AsRef<str>) -> Option<&(ASTVar, ASTConst)> {
-        self.options.get(option.as_ref())
-    }
-
-    /// Get a job by its name, returns [None] if the job was not defined.
-    #[inline]
-    pub fn job(&self, name: impl AsRef<str>) -> Option<&ASTFunction> {
-        self.jobs.get(name.as_ref()).map(|(_, job)| job)
-    }
-
-    /// Get a function by its name, returns [None] if the function was not defined.
-    #[inline]
-    pub fn function(&self, name: impl AsRef<str>) -> Option<&ASTFunction> {
-        self.functions.get(name.as_ref()).map(|(_, function)| function)
-    }
-
-    /// Get all the options... All the options are public by design so no visibility rule is
-    /// necessary to query them.
-    #[inline]
-    pub fn options(&self) -> impl Iterator<Item = (&ASTVar, &ASTConst)> {
-        self.options.values().map(|(a, b): &(_, _)| (a, b))
-    }
-
-    /// Get all the constants with the specified visibility rule.
-    #[inline]
-    pub fn consts(&self, rule: ASTVisibilityRule) -> impl Iterator<Item = (&ASTVar, &ASTConst)> {
-        self.consts
-            .values()
-            .filter_map(move |(v, var, value)| (rule.allows(*v)).then_some((var, value)))
-    }
-
-    /// Get all the functions from the module with the specified visibility rule.
-    #[inline]
-    pub fn functions(&self, rule: ASTVisibilityRule) -> impl Iterator<Item = (ASTString, &ASTFunction)> {
-        self.functions
-            .values()
-            .filter_map(move |(v, f)| rule.allows(*v).then_some((f.name.clone(), f)))
-    }
-
-    /// Get all the jobs from the module with the specified visibility rule.
-    #[inline]
-    pub fn jobs(&self, rule: ASTVisibilityRule) -> impl Iterator<Item = (ASTString, &ASTFunction)> {
-        self.jobs
-            .values()
-            .filter_map(move |(v, f)| rule.allows(*v).then_some((f.name.clone(), f)))
-    }
-
-    /// Get all the callable items from the module with the specified visibility rule. This
-    /// includes jobs and functions.
-    pub(crate) fn callables(&self, rule: ASTVisibilityRule) -> impl Iterator<Item = (ASTString, &ASTFunction)> {
-        self.functions(rule).chain(self.jobs(rule))
-    }
-
-    /// Get all the jobs from a module in a mutable way, with the specified visibility rule.
-    pub(crate) fn jobs_mut(&mut self, rule: ASTVisibilityRule) -> impl Iterator<Item = (ASTString, &mut ASTFunction)> {
-        self.jobs
-            .values_mut()
-            .filter_map(move |(v, f)| rule.allows(*v).then_some((f.name.clone(), f)))
-    }
-
-    /// Get all the fonctions from a module in a mutable way, with the specified visibility rule.
-    pub(crate) fn functions_mut(
-        &mut self,
-        rule: ASTVisibilityRule,
-    ) -> impl Iterator<Item = (ASTString, &mut ASTFunction)> {
-        self.functions
-            .values_mut()
-            .filter_map(move |(v, f)| rule.allows(*v).then_some((f.name.clone(), f)))
-    }
-
-    /// Get the imported modules, required by the current module.
-    #[inline]
-    pub fn imports(&self) -> impl Iterator<Item = &ASTModule> + '_ {
-        self.imports.iter().map(|(_, (_, module))| ASTModule::get(module))
-    }
-
-    /// Get the import location of a module, for debug purpose.
-    #[inline]
-    pub fn get_import_location(&self, import: &ASTString) -> Option<ASTSpan> {
-        self.imports
-            .iter()
-            .find_map(|(module, (span, _))| import.eq(module).then_some(*span))
-    }
-
-    /// Get a handle to the string cache.
-    #[inline]
-    pub fn strings(&self) -> &ASTStringCacheHandle {
-        &self.strings
-    }
-
-    /// Get a const reference to the module. As long as you don't use the [ASTModule::get_mut]
-    /// function, this one should be Ok.
-    #[inline]
-    pub(crate) fn get(this: &ASTModulePtr) -> &ASTModule {
-        unsafe { &*this.as_ref().get() }
-    }
-
-    /// Get a mutable reference to the module... Unsafe!
-    #[inline]
-    pub(crate) fn get_mut(this: &ASTModulePtr) -> *mut ASTModule {
-        this.as_ref().get()
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/options.rs b/src/Rust/vvs_lang/src/ast/options.rs
deleted file mode 100644
index 13d45a6f..00000000
--- a/src/Rust/vvs_lang/src/ast/options.rs
+++ /dev/null
@@ -1,64 +0,0 @@
-use crate::ast::*;
-use anyhow::{bail, Context};
-use hashbrown::HashMap;
-
-/// Options for a program, represent the thing that is red from a file.
-pub struct OptionTable {
-    modules: HashMap<ASTString, ASTTable<ASTConst>>,
-}
-
-impl OptionTable {
-    pub fn new(cache: &ASTStringCacheHandle, values: toml::Table) -> anyhow::Result<Self> {
-        let modules = HashMap::with_capacity(values.len());
-        let modules = values.into_iter().try_fold(modules, |mut modules, (name, values)| {
-            use hashbrown::hash_map::EntryRef::*;
-            let toml::Value::Table(values) = values else {
-                bail!("expected a table for `{name}`")
-            };
-            let table = modules
-                .entry(cache.get(&name))
-                .or_insert(ASTTable::with_capacity(values.len()));
-            values
-                .into_iter()
-                .try_for_each(|(option, value)| match table.entry_ref(option.as_str()) {
-                    Occupied(_) => bail!("redefinition of option `{option}` in module `{name}`"),
-                    Vacant(entry) => {
-                        entry.insert(ASTConst::from_toml_value(cache, value)?);
-                        Ok(())
-                    }
-                })?;
-            if table.is_empty() {
-                modules.remove(name.as_str());
-            }
-            Ok(modules)
-        });
-        Ok(Self { modules: modules.context("invalid toml file")? })
-    }
-}
-
-impl Iterator for OptionTable {
-    type Item = ((ASTString, ASTString), ASTConst);
-
-    fn next(&mut self) -> Option<Self::Item> {
-        let Self { modules } = self;
-        let module = modules.keys().next()?.clone();
-
-        let values = match modules.get_mut(&module) {
-            Some(values) => values,
-            None => {
-                modules.remove(&module);
-                return None;
-            }
-        };
-
-        let (option, value) = match values.keys().next().cloned() {
-            Some(option) => values.remove_entry(&option)?,
-            None => {
-                modules.remove(&module);
-                return None;
-            }
-        };
-
-        Some(((module, option), value))
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/pattern.rs b/src/Rust/vvs_lang/src/ast/pattern.rs
deleted file mode 100644
index 5b3707d4..00000000
--- a/src/Rust/vvs_lang/src/ast/pattern.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-//! In this file we declare things needed to do the pattern matching or boolean check for
-//! conditionals.
-//!
-//! Note that we can only pattern match variants.
-
-use crate::ast::*;
-
-/// A condition, two expression must be equal, or should we try to match a thing.
-#[derive(Debug, PartialEq, Clone)]
-pub enum ASTCondition {
-    /// Usual if check.
-    BooleanTrue(ASTExpr),
-
-    /// Does the expression can be pattern-matched or not. This is only for variants.
-    BindVariant { as_type: ASTType, variant: ASTString, pattern: Vec<ASTPatternElement>, source: ASTVar },
-
-    /// Tells whever a variable is coercible into a type or not.
-    CoercibleInto { new: ASTVar, as_type: ASTType, source: ASTVar },
-}
-
-/// When we match a pattern, we can do conditionals on the value of elements, or we can bind
-/// variables that will be visible in the if/elseif/if-let statement.
-#[derive(Debug, PartialEq, Clone)]
-pub enum ASTPatternElement {
-    /// Must be equal to this thing.
-    Const(ASTConst),
-
-    /// Expose this field of the struct in the block if the struct matched.
-    Var(ASTVar),
-}
-
-impl ASTPatternElement {
-    pub fn span(&self) -> Option<ASTSpan> {
-        match self {
-            ASTPatternElement::Const(_) => None,
-            ASTPatternElement::Var(var) => Some(var.span()),
-        }
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/program.rs b/src/Rust/vvs_lang/src/ast/program.rs
deleted file mode 100644
index 67088e1e..00000000
--- a/src/Rust/vvs_lang/src/ast/program.rs
+++ /dev/null
@@ -1,140 +0,0 @@
-use crate::ast::*;
-use hashbrown::HashMap;
-
-/// The first element of the tuple is the destination variable, the second is the tuple to describe
-/// the job picked from a module, the last is the list of variables to use as input for this job.
-pub type ProgramOperation = (ASTSpan, ASTString, (ASTString, ASTString), Option<Vec<ASTConst>>, Vec<ASTString>);
-
-/// The main VVS file/program.
-#[derive(Debug)]
-pub struct ASTProgram {
-    /// The list of all the modules used in the program, with their import location.
-    modules: HashMap<ASTString, (ASTSpan, ASTModulePtr)>,
-
-    /// The setted options, from the VVS file.
-    setted: Vec<((ASTString, ASTString), ASTConst)>,
-
-    /// The operations to do in order.
-    operations: Vec<ProgramOperation>,
-
-    /// What the program writes.
-    writes: (ASTSpan, Vec<ASTString>),
-
-    /// Initial variable.
-    initial_var: ASTString,
-
-    /// Caching for strings, identified by theyr hash and reuse the same memory location to reduce
-    /// memory footprint. Use the .finish function from the hasher to get the key.
-    strings: ASTStringCacheHandle,
-}
-
-impl ASTProgram {
-    pub fn new(strings: ASTStringCacheHandle) -> Self {
-        Self {
-            initial_var: strings.get("INIT"),
-            setted: Default::default(),
-            writes: Default::default(),
-            modules: Default::default(),
-            operations: Default::default(),
-            strings,
-        }
-    }
-
-    /// Iterate over all the modules in the program.
-    #[inline]
-    pub fn modules(&self) -> impl Iterator<Item = &ASTModule> + '_ {
-        self.modules.values().map(|(_, module)| ASTModule::get(module))
-    }
-
-    /// Get a handle to the string cache.
-    #[inline]
-    pub fn strings(&self) -> &ASTStringCacheHandle {
-        &self.strings
-    }
-
-    /// Get a const reference to a module.
-    pub fn module(&self, name: impl AsRef<str>) -> Option<&ASTModule> {
-        self.modules
-            .get(name.as_ref())
-            .map(|(_, module)| ASTModule::get(module))
-    }
-
-    /// Get the pointer to a module. Returns [None] if the module was not present in the program.
-    ///
-    /// # Safety
-    /// With this function we create the possibility to make multiple mutable references to the
-    /// same module down the line, so we mark it as an unsafe operation for now...
-    pub(crate) unsafe fn module_ptr(&self, name: impl AsRef<str>) -> Option<ASTModulePtr> {
-        self.modules.get(name.as_ref()).map(|(_, ptr)| ptr.clone())
-    }
-
-    /// Get all the available options for this program, with their default value.
-    pub fn available_options(&self) -> impl Iterator<Item = (ASTString, &ASTVar, &ASTConst)> {
-        self.modules()
-            .flat_map(|module| module.options().map(|(var, def)| (module.name(), var, def)))
-    }
-
-    /// Get all the setted options from the program.
-    #[inline]
-    pub fn setted_options(&self) -> &[((ASTString, ASTString), ASTConst)] {
-        self.setted.as_ref()
-    }
-
-    /// Get the value for an option. For the resolution: we first take the value from the setted
-    /// list before the default value. Note that if we set an option that was never declared we
-    /// don't return it here, it should have raised a warning and should not be used in the code
-    /// anyway.
-    pub fn option(&self, module: &ASTString, name: &ASTString) -> Option<ASTConst> {
-        let default = self
-            .module(module)?
-            .options()
-            .find_map(|(var, val)| var.name().eq(name).then_some(val))?
-            .clone();
-        let setted = self
-            .setted
-            .iter()
-            .find_map(|((mm, var), val)| (*module == *mm && *name == *var).then_some(val));
-        Some(setted.cloned().unwrap_or(default))
-    }
-
-    /// Get the operations and the variables to write. Note that no check is done here.
-    pub fn as_operations(&self) -> (ASTString, Vec<ProgramOperation>, Vec<ASTString>) {
-        (self.initial_var.clone(), self.operations.clone(), self.writes.1.clone())
-    }
-
-    #[inline]
-    pub(crate) fn writes_span(&self) -> ASTSpan {
-        self.writes.0
-    }
-
-    /// Set an option in the [Program], if the option was already set or was not declared in a
-    /// [Module] we raise a warning.
-    pub fn set_option(mut self, module: ASTString, name: ASTString, value: ASTConst) -> Self {
-        if self
-            .module(&module)
-            .map(|module| module.options().any(|(var, _)| var.name().eq(&name)))
-            .unwrap_or_default()
-        {
-            log::warn!(target: "cc", ";set option {module}.{name} which was not declared");
-        } else if self.setted.iter().any(|((mm, nn), _)| *mm == module && name == *nn) {
-            log::warn!(target: "cc", ";re-set option {module}.{name}");
-        }
-        self.setted.push(((module, name), value));
-        self
-    }
-
-    /// Import a module into the program.
-    #[inline]
-    pub(crate) fn import_module(mut self, name: ASTString, span: ASTSpan, module: ASTModulePtr) -> Self {
-        if let Some((_, module)) = self.modules.insert(name, (span, module)) {
-            log::warn!(target: "cc", ";re-import of module `{}`", ASTModule::get(&module).name())
-        }
-        self
-    }
-
-    /// Use options from a toml file to set things in the program and simplify a bit said
-    /// program...
-    pub fn with_options(self, _options: OptionTable) -> Self {
-        self
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/span.rs b/src/Rust/vvs_lang/src/ast/span.rs
deleted file mode 100644
index 512ad50d..00000000
--- a/src/Rust/vvs_lang/src/ast/span.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-/// A span, without the borrowed string.
-#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct ASTSpan {
-    line: u64,
-    column: u64,
-    offset: u64,
-}
-
-impl std::fmt::Display for ASTSpan {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        let Self { line, column, .. } = &self;
-        write!(f, "+{line}:{column}")
-    }
-}
-
-impl ASTSpan {
-    /// Create the span out of a line and column and an offset. The lines and
-    /// columns begeins at 1. The offset begins at 0.
-    #[inline]
-    pub fn new(line: u64, column: u64, offset: u64) -> Self {
-        assert!(line >= 1);
-        assert!(column >= 1);
-        Self { line, column, offset }
-    }
-
-    /// Get the column of the span. The column starts at 1
-    #[inline]
-    pub fn line(&self) -> u64 {
-        self.line
-    }
-
-    /// Get the column of the span. The column starts at 1
-    #[inline]
-    pub fn column(&self) -> u64 {
-        self.column
-    }
-
-    /// Get the offset of the span.
-    #[inline]
-    pub fn offset(&self) -> u64 {
-        self.offset
-    }
-
-    /// Merge two spans. For now we just take the first one (the one with the
-    /// lesser offset, i.e. the minimal one). In the future we will update the
-    /// length field (when it's added to the structure...)
-    #[inline]
-    pub fn merge(s1: Self, s2: Self) -> Self {
-        if PartialOrd::gt(&s1, &s2) {
-            s2
-        } else {
-            s1
-        }
-    }
-}
-
-impl From<&ASTSpan> for ASTSpan {
-    #[inline]
-    fn from(value: &ASTSpan) -> Self {
-        *value
-    }
-}
-
-impl From<&mut ASTSpan> for ASTSpan {
-    #[inline]
-    fn from(value: &mut ASTSpan) -> Self {
-        *value
-    }
-}
-
-impl PartialOrd for ASTSpan {
-    #[inline]
-    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
-        PartialOrd::partial_cmp(&self.offset, &other.offset)
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/string.rs b/src/Rust/vvs_lang/src/ast/string.rs
deleted file mode 100644
index acec81a7..00000000
--- a/src/Rust/vvs_lang/src/ast/string.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-use super::ASTString;
-use hashbrown::HashMap;
-use std::{cell::RefCell, collections::hash_map::DefaultHasher, hash::Hasher, rc::Rc};
-
-/// Used when iterating into the module with mut access, we might need to access the string
-/// cache...
-#[derive(Debug, Clone, Default)]
-pub struct ASTStringCacheHandle {
-    strings: Rc<RefCell<HashMap<u64, ASTString>>>,
-}
-
-impl ASTStringCacheHandle {
-    /// Get the id of a string.
-    fn get_id(str: impl AsRef<str>) -> u64 {
-        let mut hasher = DefaultHasher::new();
-        hasher.write(str.as_ref().as_bytes());
-        hasher.finish()
-    }
-
-    /// Get or create a string in the cache.
-    pub fn get(&self, str: impl AsRef<str>) -> ASTString {
-        self.strings
-            .borrow_mut()
-            .entry(Self::get_id(str.as_ref()))
-            .or_insert_with(|| ASTString::from(str.as_ref()))
-            .clone()
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/type_context.rs b/src/Rust/vvs_lang/src/ast/type_context.rs
deleted file mode 100644
index 829dcc0b..00000000
--- a/src/Rust/vvs_lang/src/ast/type_context.rs
+++ /dev/null
@@ -1,180 +0,0 @@
-use crate::ast::*;
-use core::cell::OnceCell;
-
-/// Match any item, private or public.
-const RULE_ANY: ASTVisibilityRule = ASTVisibilityRule::AtLeast(ASTVisibility::Private);
-const RULE_PUB: ASTVisibilityRule = ASTVisibilityRule::Only(ASTVisibility::Public);
-
-/// The ast context for storing types. Any use of the module must be delayed because when we create
-/// the type context for a module, we do it with a cyclic thingy, so the [Rc] is not already
-/// constructed (no strong reference), so all we have is a [std::rc::Weak].
-#[derive(Debug, Clone)]
-pub struct ASTTypeContext {
-    module: ASTModuleWeakPtr,
-    content: OnceCell<ASTTypeContextContent>,
-}
-
-/// The content of the [ASTTypeContext] must be lazyly initialized because of cyclic references
-/// with the module and it's type context.
-type ASTTypeContextContent = (
-    HashMap<ASTString, ASTType>,         // Variables
-    HashMap<ASTString, ASTVariantRules>, // Variants
-    ASTStringCacheHandle,                // String cache
-    Vec<ASTString>,                      // Name of imported modules
-);
-
-impl ASTTypeContext {
-    fn init_content(&self) -> ASTTypeContextContent {
-        let ptr = self.module.upgrade().expect("no more strong references to module...");
-        let module = ASTModule::get(&ptr);
-
-        // We need to import things from the current module and from the imported modules. But for
-        // imported modules we must prepend the constant/option/callable name by the module name
-        // with a dot, to call those things like in lua.
-        let modules = [(None, module)]
-            .into_iter()
-            .chain(module.imports().map(|module| (Some(module.name()), module)));
-
-        let scope = modules.flat_map(|(mname, module)| {
-            let rule = if mname.is_some() { RULE_PUB } else { RULE_ANY };
-            let (mname1, mname2, mname3) = (mname.clone(), mname.clone(), mname);
-
-            let options = module.options().map(move |(var, _)| {
-                let name = mname1
-                    .as_ref()
-                    .map(|n| module.strings().get(format!("{n}.{}", var.name())))
-                    .unwrap_or_else(|| var.name());
-                (name, var.get_specified_type_or_nil())
-            });
-
-            let consts = module.consts(rule).map(move |(var, _)| {
-                let name = mname2
-                    .as_ref()
-                    .map(|n| module.strings().get(format!("{n}.{}", var.name())))
-                    .unwrap_or_else(|| var.name());
-                (name, var.get_specified_type_or_nil())
-            });
-
-            let funcs = module.callables(rule).map(move |(name, func)| {
-                let name = mname3
-                    .as_ref()
-                    .map(|n| module.strings().get(format!("{n}.{name}")))
-                    .unwrap_or(name);
-
-                let arguments = func.arguments.iter().map(|arg| arg.get_specified_type_or_nil());
-                let func_type = ASTType::Function(arguments.collect(), Box::new(func.returns.clone()));
-
-                (name, func_type)
-            });
-
-            options.chain(consts).chain(funcs)
-        });
-
-        let strings = module.strings().clone();
-        let variants = module.all_variant_rules().clone();
-        let imports = module.imports().map(|module| module.name()).collect();
-        (scope.collect(), variants, strings, imports)
-    }
-
-    fn content(&self) -> &ASTTypeContextContent {
-        self.content.get_or_init(|| self.init_content())
-    }
-
-    fn content_mut(&mut self) -> &mut ASTTypeContextContent {
-        self.content();
-        self.content.get_mut().expect("should be initialized")
-    }
-
-    #[inline]
-    pub fn new(module: ASTModuleWeakPtr) -> Self {
-        Self { module, content: OnceCell::new() }
-    }
-
-    /// Try to map rules to a pattern. Returns the matching [Some] variables with their destination
-    /// types or [None] if the matching is not possible to do. Because all rules must be kown at
-    /// compile time we can now statically if a variant mapping is correct or not!
-    pub fn variant_try_map_rule(
-        &self,
-        rule: impl AsRef<str>,
-        to: &[ASTPatternElement],
-    ) -> Option<Vec<(ASTVar, ASTType)>> {
-        // Get the rule-set.
-        let rule = self.content().1.get(rule.as_ref())?;
-
-        // The first thing must be a constant string or identifier with the name of the sub-rule.
-        use ASTPatternElement::*;
-        let (rule, content) = match to {
-            [Const(ASTConst::String(sub_rule)), content @ ..] => (rule.rule(sub_rule)?, content),
-            [Var(var), content @ ..] => {
-                debug_assert!(
-                    var.get_specified_type().is_none(),
-                    "got a specified type for `{var}`, expected just an identifier"
-                );
-                (rule.rule(var.name())?, content)
-            }
-            _ => return None,
-        };
-
-        // Be sure that we capture everything in that rule. We don't have the `..` like in rust...
-        if rule.len() != content.len() {
-            return None;
-        }
-
-        Some(
-            // Do the matching for the sub-rule.
-            rule.iter().zip(content).map(|(rule, pat)| match pat {
-                // If a constant is provided we must ensure that the types are compatible!
-                Const(pat) => rule.coercible_to(&pat.get_const_type()).then_some(None).ok_or(()),
-                // If a variable is declared then we will return it. If the variable has a
-                // specified type, we must ensure that the element in the variant can be coerced
-                // into this specified type.
-                Var(var) => match var.get_specified_type() {
-                    Some(ty) => rule.coercible_to(ty).then(|| Some((var.clone(), rule.clone()))).ok_or(()),
-                    None => Ok(Some((var.clone(), rule.clone()))),
-                },
-            })
-            // Get ride of any errors because of impossible mappings.
-            .collect::<Result<Vec<Option<(ASTVar, ASTType)>>, ()>>().ok()?
-            // We collect the successful bindings into a vector, we don't care when a constant
-            // mapped with an element of the variant.
-            .into_iter().flatten().collect(),
-        )
-    }
-
-    /// Get a set of rule for a specified variant if it exists.
-    pub fn variant_complies_with_rule<T: Typed>(&self, rule: impl AsRef<str>, variant: &ASTVariant<T>) -> bool {
-        let rules = self.content().1.get(rule.as_ref());
-        rules.map_or(false, |rules| rules.complies(self, variant))
-    }
-
-    /// Create a new context, don't clone as we want to do other things...
-    #[inline]
-    pub fn for_scope(&self) -> Self {
-        self.clone()
-    }
-
-    /// Get the type of a variable by its name.
-    pub fn get(&self, name: &ASTVar) -> ASTType {
-        let (scope, ..) = self.content();
-        scope.get(name.name().as_ref()).unwrap().clone()
-    }
-
-    /// Declare a new variable. Returns an error on redefinition.
-    pub fn declare(&mut self, var: ASTVar, ty: ASTType) {
-        if var.is_joker() {
-            log::debug!("can't declare the joker as a variable at {}", var.span());
-        } else if self.content_mut().0.insert(var.name(), ty).is_some() {
-            panic!()
-        }
-    }
-
-    pub fn has_import(&self, import: impl AsRef<str>) -> bool {
-        self.content().3.iter().any(|scoped| scoped.as_ref() == import.as_ref())
-    }
-
-    /// Get the string cache out of the module pointer stored in the context.
-    #[inline]
-    pub fn strings(&self) -> &ASTStringCacheHandle {
-        &self.content().2
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/typed.rs b/src/Rust/vvs_lang/src/ast/typed.rs
deleted file mode 100644
index d2f8b537..00000000
--- a/src/Rust/vvs_lang/src/ast/typed.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-use crate::ast::*;
-use std::ops::Deref;
-
-/// Trait for objects that are types.
-///
-/// As long a a type can be dereferenced into a [Typed] thing, it is [Typed].
-pub trait Typed {
-    /// Get the type of the object.
-    fn get_type(&self, ctx: &ASTTypeContext) -> ASTType;
-}
-
-impl<S: Typed, T: Deref<Target = S>> Typed for T {
-    #[inline]
-    fn get_type(&self, ctx: &ASTTypeContext) -> ASTType {
-        self.deref().get_type(ctx)
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/types.rs b/src/Rust/vvs_lang/src/ast/types.rs
deleted file mode 100644
index cb231531..00000000
--- a/src/Rust/vvs_lang/src/ast/types.rs
+++ /dev/null
@@ -1,226 +0,0 @@
-use crate::ast::*;
-
-/// Types. Every object that can be manipulated by the user has a type. We have base types and
-/// collection types and special ASS types.
-///
-/// Some coercion is possible between collection types...
-#[derive(Debug, PartialEq, Eq, Clone, Default)]
-pub enum ASTType {
-    /// Null, unit, nullptr, etc. This is the default type
-    #[default]
-    Nil,
-
-    /// An integer
-    Integer,
-
-    /// A floating point number
-    Floating,
-
-    /// A string.
-    String,
-
-    /// A boolean, true/false.
-    Boolean,
-
-    /// A color
-    Color,
-
-    /// A movement of a syllabe or line.
-    Movement,
-
-    /// A variant, can be a color or a movement.
-    Variant,
-
-    /// A tuple
-    Tuple(Vec<ASTType>),
-
-    /// Special ASS type, a syllabe. A simple syllabe.
-    Syllabe,
-
-    /// Special ASS type, a line. It's a collection of [ASTType::Syllabe] with extra steps, can
-    /// iterate over it.
-    Line,
-
-    /// A table where the content is not really defined. Because we don't know the keys we can't
-    /// iterate over it.
-    AnyTable,
-
-    /// A table where everything inside is defined, a struct. We can't iterate over it but we
-    /// statically know the keys of the table.
-    Table(ASTTable<ASTType>),
-
-    /// A uniform table, where all the values has the same types, like a sequence but which string
-    /// keys.
-    UniformTable(Box<ASTType>),
-
-    /// A sequence where the content is not really defined, like the any table but with sequences.
-    AnySequence,
-
-    /// A sequence where every value has the same type. We can iterate over it, like a uniform
-    /// table, but with integer and continuous keys.
-    Sequence(Box<ASTType>),
-
-    /// A function type, needs the arguments and the return value.
-    Function(Vec<ASTType>, Box<ASTType>),
-
-    /// A type that is not known at compile time, the user must check its type with a switch case.
-    Any,
-}
-
-impl ASTType {
-    /// Try to see if a type can be pattern matched and if it's the case, returns [Some] bindings
-    /// to add them to the type context, otherwise return [None].
-    pub fn try_match(&self, mctx: &ASTTypeContext, to: &[ASTPatternElement]) -> Option<Vec<(ASTVar, ASTType)>> {
-        self.get_variant_rule()
-            .and_then(|rule| mctx.variant_try_map_rule(rule, to))
-    }
-
-    /// Tells wether the type is buildable in a const context or not.
-    #[inline]
-    pub fn is_const_constructible(&self) -> bool {
-        matches!(self, ASTType::Nil | ASTType::Tuple(_) | ASTType::Any)
-            || self.is_numeric()
-            || self.is_table()
-            || self.is_sequence()
-    }
-
-    /// Tells wether the type is numeric or not.
-    #[inline]
-    pub fn is_numeric(&self) -> bool {
-        matches!(self, ASTType::Boolean | ASTType::Integer | ASTType::Floating)
-    }
-
-    /// Tells whether the type is any sort of sequence or not.
-    #[inline]
-    pub fn is_sequence(&self) -> bool {
-        matches!(self, ASTType::Sequence(_) | ASTType::AnySequence)
-    }
-
-    /// Tells whether the type is any sort of table or not.
-    #[inline]
-    pub fn is_table(&self) -> bool {
-        matches!(self, ASTType::UniformTable(_) | ASTType::Table(_) | ASTType::AnyTable)
-    }
-
-    /// Tells whether the type is any sort of variant or not.
-    #[inline]
-    pub fn is_variant(&self) -> bool {
-        matches!(self, ASTType::Variant | ASTType::Color | ASTType::Movement)
-    }
-
-    /// Get the name of the rules to follow for this variant if it's really a variant.
-    #[inline]
-    pub fn get_variant_rule(&self) -> Option<&'static str> {
-        match self {
-            ASTType::Color => Some("color"),
-            ASTType::Movement => Some("movement"),
-            _ => None,
-        }
-    }
-
-    /// Tells whether a type is trivially copiable, i.e. this type won't be managed.
-    #[inline]
-    pub fn is_trivialy_copiable(&self) -> bool {
-        use ASTType::*;
-        matches!(self, Nil | Integer | Floating | Boolean | Tuple(_))
-    }
-
-    pub fn coercible_to(&self, to: &ASTType) -> bool {
-        use ASTType::*;
-        match (self, to) {
-            // Equals...
-            (x, y)
-                if (x == y)
-                    || (x.is_table() && matches!(y, AnyTable))
-                    || (x.is_sequence() && matches!(y, AnySequence))
-                    || (x.is_variant() && y.is_variant()) =>
-            {
-                true
-            }
-
-            // Nil things
-            (_, Nil) | (Nil, Integer | Floating | Boolean) => true,
-            (Nil, to) => to.is_table() || to.is_sequence(),
-
-            // Integer things
-            (Integer, Floating | Boolean) | (Boolean, Integer | Floating) | (Floating, Integer) => true,
-
-            // Sequence / ASS things
-            (String, Sequence(ty)) | (Sequence(ty), String) => matches!(&**ty, String),
-            (Sequence(x), Line) | (Line, Sequence(x)) => matches!(&**x, Syllabe),
-            (Syllabe, Sequence(x)) => matches!(&**x, String),
-
-            // Table / Sequence things
-            (from, AnyTable) => from.is_sequence() || from.is_table() || from.is_variant(),
-            (Sequence(to), UniformTable(from)) | (UniformTable(from), Sequence(to)) => from.coercible_to(to),
-            (Table(table), Sequence(ty)) => {
-                let integer_keys = table.keys().all(|key| key.parse::<i64>().is_ok());
-                let mut uniform_values = table.values().collect::<Vec<_>>();
-                let uniform_values = uniform_values
-                    .pop()
-                    .map(|ty| uniform_values.into_iter().all(|a| ty.eq(a)).then_some(ty));
-                integer_keys && matches!(uniform_values, Some(Some(table_ty)) if table_ty.eq(ty))
-            }
-
-            _ => false,
-        }
-    }
-}
-
-impl Typed for ASTType {
-    #[inline]
-    fn get_type(&self, _: &ASTTypeContext) -> ASTType {
-        self.clone()
-    }
-}
-
-impl std::fmt::Display for ASTType {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            ASTType::Nil => f.write_str("nil"),
-            ASTType::Any => f.write_str("any"),
-
-            ASTType::Integer => f.write_str("integer"),
-            ASTType::Floating => f.write_str("float"),
-            ASTType::String => f.write_str("string"),
-            ASTType::Boolean => f.write_str("boolean"),
-            ASTType::Color => f.write_str("color"),
-            ASTType::Variant => f.write_str("variant"),
-            ASTType::Movement => f.write_str("movement"),
-
-            ASTType::Function(args, ret) => {
-                f.write_str("function (")?;
-                if let Some(ty) = args.iter().next() {
-                    write!(f, " {ty}")?;
-                }
-                for ty in args.iter().skip(1) {
-                    write!(f, ", {ty}")?;
-                }
-                write!(f, " ) -> {ret}")
-            }
-
-            ASTType::Tuple(tuple) => {
-                f.write_str("(")?;
-                if let Some(ty) = tuple.iter().next() {
-                    write!(f, " {ty}")?;
-                }
-                for ty in tuple.iter().skip(1) {
-                    write!(f, ", {ty}")?;
-                }
-                f.write_str(" )")
-            }
-
-            ASTType::Line => f.write_str("line"),
-            ASTType::Syllabe => f.write_str("syllabe"),
-            ASTType::AnySequence => f.write_str("sequence { any }"),
-            ASTType::Sequence(ty) => write!(f, "sequence {{ {ty} }}"),
-
-            ASTType::AnyTable => f.write_str("table { any }"),
-            ASTType::UniformTable(inner) => write!(f, "table {{ {inner} }}"),
-            ASTType::Table(table) => {
-                f.write_str("table ")?;
-                write_ast_table(f, table)
-            }
-        }
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/variable.rs b/src/Rust/vvs_lang/src/ast/variable.rs
deleted file mode 100644
index 3cb53833..00000000
--- a/src/Rust/vvs_lang/src/ast/variable.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-use crate::ast::*;
-use std::sync::atomic::{AtomicU64, Ordering};
-
-/// Variable thing. Have a name, a where-it-is-defined span and optionally a type. Having to no
-/// type means that the type was not already found.
-///
-/// To get the type of a variable, it is either present in the context type hashmap, then we check
-/// the specified type, if all failed we return the [ASTType::Nil] type.
-#[derive(Debug, Clone)]
-pub struct ASTVar(ASTSpan, ASTString, Option<ASTType>);
-
-#[derive(Debug, Clone)]
-pub struct ASTVarBuilder<'a> {
-    span: ASTSpan,
-    cache: &'a ASTStringCacheHandle,
-    name: Option<ASTString>,
-    specified_ty: Option<ASTType>,
-}
-
-impl<'a> ASTVarBuilder<'a> {
-    pub fn build(self) -> ASTVar {
-        let name = self.name.unwrap_or_else(|| {
-            static ANON: AtomicU64 = AtomicU64::new(0);
-            self.cache.get(format!("_{}", ANON.fetch_add(1, Ordering::SeqCst)))
-        });
-        ASTVar(self.span, name, self.specified_ty)
-    }
-
-    pub fn span(mut self, span: impl Into<ASTSpan>) -> Self {
-        self.span = span.into();
-        self
-    }
-
-    pub fn with_type(mut self, ty: ASTType) -> Self {
-        self.specified_ty = Some(ty);
-        self
-    }
-
-    pub fn name_from(mut self, name: impl AsRef<str>) -> Self {
-        self.name = Some(self.cache.get(name.as_ref()));
-        self
-    }
-
-    pub fn name(mut self, name: ASTString) -> Self {
-        self.name = Some(name);
-        self
-    }
-}
-
-impl PartialEq for ASTVar {
-    #[inline]
-    fn eq(&self, other: &Self) -> bool {
-        self.1 == other.1 && self.2 == other.2
-    }
-}
-
-impl ASTVar {
-    #[inline]
-    #[allow(clippy::new_ret_no_self)]
-    pub fn new(cache: &ASTStringCacheHandle) -> ASTVarBuilder {
-        ASTVarBuilder { span: Default::default(), cache, name: None, specified_ty: None }
-    }
-
-    #[inline]
-    pub fn span(&self) -> ASTSpan {
-        self.0
-    }
-
-    /// Get the specified type if any.
-    #[inline]
-    pub fn get_specified_type(&self) -> Option<&ASTType> {
-        self.2.as_ref()
-    }
-
-    /// Get the specified type. If no type is specified then we say that we return [ASTType::Nil].
-    #[inline]
-    pub fn get_specified_type_or_nil(&self) -> ASTType {
-        self.get_specified_type().cloned().unwrap_or_default()
-    }
-
-    /// Set the specified type.
-    #[inline]
-    pub fn set_specified_type(&mut self, ty: ASTType) {
-        self.2 = Some(ty);
-    }
-
-    /// Get the name.
-    #[inline]
-    pub fn name(&self) -> ASTString {
-        self.1.clone()
-    }
-
-    /// Tells wether the variable is the joker or not. We can assign into the joker, in this case
-    /// we yeet the result, but we can never read it.
-    pub fn is_joker(&self) -> bool {
-        self.1.as_ref().eq("_")
-    }
-}
-
-impl From<&ASTVar> for ASTSpan {
-    #[inline]
-    fn from(value: &ASTVar) -> Self {
-        value.span()
-    }
-}
-
-impl std::fmt::Display for ASTVar {
-    #[inline]
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.write_str(self.1.as_ref())
-    }
-}
-
-impl Typed for ASTVar {
-    #[inline]
-    fn get_type(&self, ctx: &ASTTypeContext) -> ASTType {
-        ctx.get(self)
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/variant.rs b/src/Rust/vvs_lang/src/ast/variant.rs
deleted file mode 100644
index d6e6da7f..00000000
--- a/src/Rust/vvs_lang/src/ast/variant.rs
+++ /dev/null
@@ -1,192 +0,0 @@
-use crate::ast::*;
-
-/// A trait to describes types that are variants. Can be used to handle colors and movements in a
-/// generic way.
-///
-/// Represents a color in the AST. A color can be:
-/// - `#(rgb 0, 0, 0)` for black
-/// - `#(green)` for green
-/// - etc...
-///
-/// Represents a movement in the AST, a movement can be:
-/// - `#[pos 500, 500]`
-/// - `#[cmove 0, 0, 100, 50, 30]`
-/// - etc...
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct ASTVariant<T: Typed> {
-    pub(crate) variant: ASTString,
-    pub(crate) args: Vec<T>,
-}
-
-pub(crate) struct ASTFmtColor<'a, T: Typed>(&'a ASTVariant<T>, &'a ASTTypeContext);
-pub(crate) struct ASTFmtMovement<'a, T: Typed>(&'a ASTVariant<T>, &'a ASTTypeContext);
-
-impl<T: Typed> ASTVariant<T> {
-    #[inline]
-    pub fn variant(&self) -> ASTString {
-        self.variant.clone()
-    }
-
-    #[inline]
-    pub fn args(&self) -> &[T] {
-        &self.args
-    }
-
-    #[inline]
-    pub fn args_mut(&mut self) -> &mut [T] {
-        &mut self.args
-    }
-
-    #[inline]
-    pub fn args_len(&self) -> usize {
-        self.args.len()
-    }
-}
-
-impl ASTVariant<ASTExpr> {
-    #[inline]
-    pub fn is_const_expr(&self) -> bool {
-        self.args.iter().all(|expr| expr.is_const_expr())
-    }
-}
-
-impl ASTVariant<ASTConst> {
-    #[inline]
-    pub fn is_const_expr(&self) -> bool {
-        true
-    }
-}
-
-impl<'a, T: Typed> ASTFmtColor<'a, T> {
-    pub(crate) fn new(variant: &'a ASTVariant<T>, ctx: &'a ASTTypeContext) -> Self {
-        Self(variant, ctx)
-    }
-}
-
-impl<'a, T: Typed> ASTFmtMovement<'a, T> {
-    pub(crate) fn new(variant: &'a ASTVariant<T>, ctx: &'a ASTTypeContext) -> Self {
-        Self(variant, ctx)
-    }
-}
-
-impl<'a, T: Typed> std::fmt::Display for ASTFmtColor<'a, T> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        let Self(ASTVariant { variant, args }, ctx) = self;
-        write!(f, "#({variant}")?;
-        if let Some(arg) = args.iter().next() {
-            write!(f, " {}", arg.get_type(ctx))?;
-        }
-        for arg in args.iter().skip(1) {
-            write!(f, ", {}", arg.get_type(ctx))?;
-        }
-        f.write_str(" )")
-    }
-}
-
-impl<'a, T: Typed> std::fmt::Display for ASTFmtMovement<'a, T> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        let Self(ASTVariant { variant, args }, ctx) = self;
-        write!(f, "#[{variant}")?;
-        if let Some(arg) = args.iter().next() {
-            write!(f, " {}", arg.get_type(ctx))?;
-        }
-        for arg in args.iter().skip(1) {
-            write!(f, ", {}", arg.get_type(ctx))?;
-        }
-        f.write_str(" ]")
-    }
-}
-
-/// Describes a set of rules for a variant.
-#[derive(Debug, Clone)]
-pub struct ASTVariantRules {
-    family: ASTString,
-    rules: HashMap<ASTString, Vec<ASTType>>,
-}
-
-macro_rules! rule {
-    ($cache: expr, $name: literal) => { ($cache.get($name), vec![]) };
-    ($cache: expr, $name: literal -> [$($arg: ident),*]) => { ($cache.get($name), vec![$(ASTType::$arg,)*]) };
-}
-
-impl ASTVariantRules {
-    /// Default empty ruleset.
-    #[inline]
-    pub fn new(name: ASTString) -> Self {
-        Self { family: name, rules: Default::default() }
-    }
-
-    /// Get the name of the family of variants.
-    #[inline]
-    pub fn name(&self) -> ASTString {
-        self.family.clone()
-    }
-
-    /// Get all the rules of this family.
-    #[inline]
-    pub fn rules(&self) -> impl Iterator<Item = (&ASTString, &Vec<ASTType>)> {
-        self.rules.iter()
-    }
-
-    /// Get a specific rule if present.
-    #[inline]
-    pub fn rule(&self, variant: impl AsRef<str>) -> Option<&[ASTType]> {
-        self.rules.get(variant.as_ref()).map(|vec| vec.as_ref())
-    }
-
-    /// Create a new rule set for colors, the default one.
-    #[inline]
-    pub fn new_colors(cache: ASTStringCacheHandle) -> Self {
-        Self {
-            family: cache.get("color"),
-            rules: HashMap::from_iter([
-                rule!(cache, "rgb"  -> [Integer, Integer, Integer]),
-                rule!(cache, "rgba" -> [Integer, Integer, Integer, Integer]),
-                rule!(cache, "black"),
-                rule!(cache, "white"),
-                rule!(cache, "grey"),
-                rule!(cache, "red"),
-                rule!(cache, "green"),
-                rule!(cache, "blue"),
-            ]),
-        }
-    }
-
-    /// Create a new rule set for movements, the default one.
-    #[inline]
-    pub fn new_movements(cache: ASTStringCacheHandle) -> Self {
-        Self {
-            family: cache.get("movement"),
-            rules: HashMap::from_iter([
-                rule![cache, "implicit"],
-                rule!(cache, "fixed"       -> [Integer, Integer]),
-                rule!(cache, "linear"      -> [Integer, Integer, Integer, Integer]),
-                rule!(cache, "accelerated" -> [Integer, Integer, Integer, Integer, Floating]),
-            ]),
-        }
-    }
-
-    /// Insert a new rule in the ruleset, returns [true] if the rule was inserted successfully,
-    /// [false] otherwise.
-    #[must_use]
-    #[inline]
-    pub fn insert_rule(&mut self, name: ASTString, types: Vec<ASTType>) -> bool {
-        self.rules.insert(name, types).is_none()
-    }
-
-    /// Returns wether a variant complies with the set of allowed one.
-    #[must_use]
-    #[inline]
-    pub fn complies<T: Typed>(&self, ctx: &ASTTypeContext, variant: &ASTVariant<T>) -> bool {
-        match self.rules.get(&variant.variant) {
-            None => false,
-            Some(rule) => {
-                (rule.len() == variant.args.len())
-                    && rule
-                        .iter()
-                        .zip(variant.args.iter().map(|arg| arg.get_type(ctx)))
-                        .all(|(rule, arg)| arg.coercible_to(rule))
-            }
-        }
-    }
-}
diff --git a/src/Rust/vvs_lang/src/ast/visibility.rs b/src/Rust/vvs_lang/src/ast/visibility.rs
deleted file mode 100644
index 5d5c88f5..00000000
--- a/src/Rust/vvs_lang/src/ast/visibility.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-pub enum ASTVisibility {
-    #[default]
-    Private,
-    Public,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub enum ASTVisibilityRule {
-    Only(ASTVisibility),
-    AtLeast(ASTVisibility),
-}
-
-impl ASTVisibilityRule {
-    /// Checks if the rule allows to show an item with the specified visibility [ASTVisibility].
-    /// Used to factorize the functions in [crate::ast::ASTModule] and [crate::ast::ASTProgram].
-    #[inline]
-    pub fn allows(&self, vis: ASTVisibility) -> bool {
-        match self {
-            ASTVisibilityRule::Only(this) => vis.eq(this),
-            ASTVisibilityRule::AtLeast(this) => PartialOrd::le(this, &vis),
-        }
-    }
-
-    /// Allows all the visibilities.
-    #[inline]
-    pub fn any() -> Self {
-        Self::AtLeast(ASTVisibility::Private)
-    }
-}
-
-impl Default for ASTVisibilityRule {
-    fn default() -> Self {
-        Self::Only(ASTVisibility::Private)
-    }
-}
-
-impl ASTVisibility {
-    #[inline]
-    pub fn as_str(&self) -> &str {
-        match self {
-            ASTVisibility::Private => "private",
-            ASTVisibility::Public => "public",
-        }
-    }
-}
-
-impl AsRef<str> for ASTVisibility {
-    #[inline]
-    fn as_ref(&self) -> &str {
-        self.as_str()
-    }
-}
-
-#[test]
-fn test_visibility() {
-    assert!(ASTVisibility::Private < ASTVisibility::Public);
-}
-
-#[test]
-fn test_visibility_rules() {
-    use ASTVisibility::*;
-    use ASTVisibilityRule::*;
-
-    assert!(Only(Private).allows(Private));
-    assert!(!Only(Private).allows(Public));
-    assert!(Only(Public).allows(Public));
-    assert!(!Only(Public).allows(Private));
-
-    assert!(AtLeast(Private).allows(Public));
-    assert!(AtLeast(Private).allows(Private));
-    assert!(AtLeast(Public).allows(Public));
-    assert!(!AtLeast(Public).allows(Private));
-
-    assert!(ASTVisibilityRule::any().allows(Public));
-    assert!(ASTVisibilityRule::any().allows(Private));
-}
diff --git a/src/Rust/vvs_lang/src/lib.rs b/src/Rust/vvs_lang/src/lib.rs
deleted file mode 100644
index 97947b62..00000000
--- a/src/Rust/vvs_lang/src/lib.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-#![allow(dead_code)]
-
-// Old code, will be purged
-pub mod ast;
diff --git a/src/Rust/vvs_lib/Cargo.toml b/src/Rust/vvs_lib/Cargo.toml
index 0285744a..0a15308f 100644
--- a/src/Rust/vvs_lib/Cargo.toml
+++ b/src/Rust/vvs_lib/Cargo.toml
@@ -15,8 +15,7 @@ log.workspace        = true
 serde.workspace      = true
 hashbrown.workspace  = true
 serde_json.workspace = true
-
-vvs_ass.workspace = true
+vvs_ass.workspace    = true
 
 [build-dependencies]
 cbindgen.workspace = true
diff --git a/src/Rust/vvs_llvm/Cargo.toml b/src/Rust/vvs_llvm/Cargo.toml
index 41ce7c7a..3bde3081 100644
--- a/src/Rust/vvs_llvm/Cargo.toml
+++ b/src/Rust/vvs_llvm/Cargo.toml
@@ -1,15 +1,18 @@
 [package]
-name              = "vvs_llvm"
-description       = "Link against and re-export llvm things"
+name        = "vvs_llvm"
+description = "Link against and re-export llvm things"
+
 version.workspace = true
 authors.workspace = true
 edition.workspace = true
 license.workspace = true
 
 [dependencies]
-anyhow.workspace = true
-paste.workspace  = true
-log.workspace    = true
+anyhow.workspace          = true
+thiserror.workspace       = true
+paste.workspace           = true
+log.workspace             = true
+vvs_shortstring.workspace = true
 llvm-sys = { version = "181", features = [
     "strict-versioning",       # Be strict about versions, we do want the lattest thing
     "no-llvm-linking",         # We do the linking ourself because of problems when using spack: https://github.com/spack/spack/discussions/36192
@@ -17,7 +20,7 @@ llvm-sys = { version = "181", features = [
 ] }
 
 [features]
-sys = []
-link = []
-init = []
+sys      = []
+link     = []
+init     = []
 bindings = ["init"]
diff --git a/src/Rust/vvs_llvm/src/bindings/mod.rs b/src/Rust/vvs_llvm/src/bindings/mod.rs
index 3fed3a15..31f1a390 100644
--- a/src/Rust/vvs_llvm/src/bindings/mod.rs
+++ b/src/Rust/vvs_llvm/src/bindings/mod.rs
@@ -28,7 +28,7 @@ macro_rules! declare {
             /// # Safety
             /// Must be used from functions of the [crate::bindings::context::Context] to be sure that the
             /// usage is correct...
-            pub(super) unsafe fn from_ptr(inner: $llvm $($(, $field: $ty)*)?) -> Self {
+            pub unsafe fn from_ptr(inner: $llvm $($(, $field: $ty)*)?) -> Self {
                 Self {
                     inner $($(, $field)*)?,
                     marker: core::marker::PhantomData
@@ -36,7 +36,7 @@ macro_rules! declare {
             }
 
             /// Get the inner pointer.
-            pub(super) fn as_ptr(&self) -> $llvm {
+            pub fn as_ptr(&self) -> $llvm {
                 self.inner
             }
 
@@ -48,6 +48,18 @@ macro_rules! declare {
 }
 use declare;
 
+/// An error to describes what can go wrong here.
+#[derive(Debug, thiserror::Error)]
+pub enum Error {
+    /// Got an error because a nul byte was present in a stirng.
+    #[error("{0}")]
+    NulError(#[from] std::ffi::NulError),
+
+    /// A value with a given name was not present.
+    #[error("undefined item with name '{0}'")]
+    Undefined(vvs_shortstring::ShortString),
+}
+
 const fn cstr(content: &[u8]) -> &std::ffi::CStr {
     match std::ffi::CStr::from_bytes_with_nul(content) {
         Ok(string) => string,
diff --git a/src/Rust/vvs_llvm/src/bindings/module.rs b/src/Rust/vvs_llvm/src/bindings/module.rs
index 4205010b..b11a16c5 100644
--- a/src/Rust/vvs_llvm/src/bindings/module.rs
+++ b/src/Rust/vvs_llvm/src/bindings/module.rs
@@ -19,6 +19,14 @@ impl Module<'_> {
 
         Ok(unsafe { FunctionDeclaration::from_ptr(function) })
     }
+
+    /// Get a function out of the a module as a declaration.
+    pub fn get_function(&self, name: impl AsRef<str>) -> Result<FunctionDeclaration, LLVMError> {
+        match unsafe { LLVMGetNamedFunction(self.as_ptr(), CString::new(name.as_ref())?.as_ptr()) } {
+            ptr if ptr.is_null() => Err(LLVMError::Undefined(name.as_ref().into())),
+            ptr => Ok(unsafe { FunctionDeclaration::from_ptr(ptr) }),
+        }
+    }
 }
 
 impl Drop for Module<'_> {
diff --git a/src/Rust/vvs_llvm/src/bindings/types.rs b/src/Rust/vvs_llvm/src/bindings/types.rs
index 5969d4c9..33303aee 100644
--- a/src/Rust/vvs_llvm/src/bindings/types.rs
+++ b/src/Rust/vvs_llvm/src/bindings/types.rs
@@ -4,13 +4,6 @@ crate::bindings::declare! { const LLVMTypeRef as Type<'a> }
 crate::bindings::declare! { const LLVMTypeRef as FunctionType<'a> }
 
 impl FunctionType<'_> {
-    /// Create a new function type.
-    pub fn new<const N: usize>(args: [Type; N], returns: Type) -> Self {
-        unsafe {
-            Self::from_ptr(LLVMFunctionType(returns.as_ptr(), args.map(|ty| ty.as_ptr()).as_mut_ptr(), N as u32, 0))
-        }
-    }
-
     /// Get the returned type of the function.
     pub fn returns(&self) -> Type {
         unsafe { Type::from_ptr(LLVMGetReturnType(self.as_ptr())) }
@@ -31,6 +24,27 @@ impl FunctionType<'_> {
     }
 }
 
+impl<'a, const N: usize> From<([Type<'a>; N], Type<'a>)> for FunctionType<'a> {
+    fn from((args, returns): ([Type<'a>; N], Type<'a>)) -> Self {
+        let (returns, mut args) = (returns.as_ptr(), args.map(|ty| ty.as_ptr()));
+        unsafe { Self::from_ptr(LLVMFunctionType(returns, args.as_mut_ptr(), N as u32, 0)) }
+    }
+}
+
+impl<'a> From<(Vec<Type<'a>>, Type<'a>)> for FunctionType<'a> {
+    fn from((mut args, returns): (Vec<Type<'a>>, Type<'a>)) -> Self {
+        Self::from((args.as_mut_slice(), returns))
+    }
+}
+
+impl<'a> From<(&mut [Type<'a>], Type<'a>)> for FunctionType<'a> {
+    fn from((args, returns): (&mut [Type<'a>], Type<'a>)) -> Self {
+        let count = args.len() as u32;
+        let (returns, mut args) = (returns.as_ptr(), args.iter().map(|ty| ty.as_ptr()).collect::<Vec<_>>());
+        unsafe { Self::from_ptr(LLVMFunctionType(returns, args.as_mut_ptr(), count, 0)) }
+    }
+}
+
 macro_rules! type_is {
     ($llvm:ident as $name:ident) => {
         paste::paste! {
diff --git a/src/Rust/vvs_llvm/src/lib.rs b/src/Rust/vvs_llvm/src/lib.rs
index e2f7b5f4..9a3d9dc0 100644
--- a/src/Rust/vvs_llvm/src/lib.rs
+++ b/src/Rust/vvs_llvm/src/lib.rs
@@ -78,7 +78,9 @@ pub mod sys {
 
 #[cfg(feature = "bindings")]
 pub mod prelude {
-    pub use crate::bindings::{basic_block::*, builder::*, context::*, function::*, module::*, types::*, value::*};
+    pub use crate::bindings::{
+        basic_block::*, builder::*, context::*, function::*, module::*, types::*, value::*, Error as LLVMError,
+    };
 }
 
 #[cfg(feature = "bindings")]
diff --git a/src/Rust/vvs_parser/Cargo.toml b/src/Rust/vvs_parser/Cargo.toml
index f078adec..0239b3d0 100644
--- a/src/Rust/vvs_parser/Cargo.toml
+++ b/src/Rust/vvs_parser/Cargo.toml
@@ -4,13 +4,16 @@ license     = "MPL-2.0"
 description = "A lossless Lua parser hacked to parse VVS"
 
 version.workspace = true
-authors.workspace = true
 edition.workspace = true
 
+authors = [
+    "Maëlle Martin <maelle.martin@proton.me>",
+    "Kampfkarren <kampfkarren@gmail.com>",
+]
 
 [dependencies]
-vvs_parser_derive.workspace = true
-
+vvs_parser_derive.workspace  = true
+vvs_shortstring.workspace    = true
 bytecount.workspace          = true
 cfg-if.workspace             = true
 derive_more.workspace        = true
diff --git a/src/Rust/vvs_parser/samples/tag.vvs b/src/Rust/vvs_parser/samples/tag.vvs
index cf625d30..3850e9b9 100644
--- a/src/Rust/vvs_parser/samples/tag.vvs
+++ b/src/Rust/vvs_parser/samples/tag.vvs
@@ -12,7 +12,7 @@ end
 
 
 --- Returns only lines with the specified displacement.
-job line_modulo(every: number, ls: lines): line -- Note that jobs may only returns `line` or `syllabe`
+job line_modulo(every: number, disp: number, ls: lines): line -- Note that jobs may only returns `line` or `syllabe`
     for i,l in ls do
         if (i % every) == disp then
             yield l
diff --git a/src/Rust/vvs_parser/src/ast/mod.rs b/src/Rust/vvs_parser/src/ast/mod.rs
index 5ccfe1e9..eb11dd04 100644
--- a/src/Rust/vvs_parser/src/ast/mod.rs
+++ b/src/Rust/vvs_parser/src/ast/mod.rs
@@ -167,10 +167,13 @@ pub enum Field {
     ExpressionKey {
         /// The `[...]` part of `[expression] = value`
         brackets: ContainedSpan,
+
         /// The `expression` part of `[expression] = value`
         key: Expression,
+
         /// The `=` part of `[expression] = value`
         equal: TokenReference,
+
         /// The `value` part of `[expression] = value`
         value: Expression,
     },
@@ -180,8 +183,10 @@ pub enum Field {
     NameKey {
         /// The `name` part of `name = value`
         key: TokenReference,
+
         /// The `=` part of `name = value`
         equal: TokenReference,
+
         /// The `value` part of `name = value`
         value: Expression,
     },
@@ -191,6 +196,22 @@ pub enum Field {
     NoKey(Expression),
 }
 
+impl From<Field> for Expression {
+    fn from(value: Field) -> Self {
+        match value {
+            Field::ExpressionKey { value, .. } | Field::NameKey { value, .. } | Field::NoKey(value) => value,
+        }
+    }
+}
+
+impl<'a> From<&'a Field> for &'a Expression {
+    fn from(value: &'a Field) -> Self {
+        match value {
+            Field::ExpressionKey { value, .. } | Field::NameKey { value, .. } | Field::NoKey(value) => value,
+        }
+    }
+}
+
 /// A table being constructed, such as `{ 1, 2, 3 }` or `{ a = 1 }`
 #[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
 #[display("{}{fields}{}", braces.tokens().0, braces.tokens().1)]
@@ -495,9 +516,11 @@ pub enum FunctionArgs {
         /// The `1, 2, 3` part of `1, 2, 3`
         arguments: Punctuated<Expression>,
     },
+
     /// Used when a function is called in the form of `call "foobar"`
     #[display("{_0}")]
     String(TokenReference),
+
     /// Used when a function is called in the form of `call { 1, 2, 3 }`
     #[display("{_0}")]
     TableConstructor(TableConstructor),
@@ -507,10 +530,30 @@ impl FunctionArgs {
     pub(crate) fn empty() -> Self {
         FunctionArgs::Parentheses {
             parentheses: ContainedSpan::new(TokenReference::basic_symbol("("), TokenReference::basic_symbol(")")),
-
             arguments: Punctuated::new(),
         }
     }
+
+    /// Like [FunctionArgs::into_arguments], but without consuming the [FunctionArgs].
+    pub fn as_arguments(&self) -> Vec<Cow<'_, Field>> {
+        match self {
+            FunctionArgs::String(string) => vec![Cow::Owned(Field::NoKey(Expression::String(string.clone())))],
+            FunctionArgs::TableConstructor(table) => table.fields().iter().map(Cow::Borrowed).collect(),
+            FunctionArgs::Parentheses { arguments, .. } => {
+                arguments.iter().cloned().map(Field::NoKey).map(Cow::Owned).collect()
+            }
+        }
+    }
+
+    /// Turn the arguments from a function call into a list of fields that are used to call the
+    /// function…
+    pub fn into_arguments(self) -> Vec<Field> {
+        match self {
+            FunctionArgs::Parentheses { arguments, .. } => arguments.into_iter().map(Field::NoKey).collect(),
+            FunctionArgs::TableConstructor(table) => table.fields.into_iter().collect(),
+            FunctionArgs::String(string) => vec![Field::NoKey(Expression::String(string))],
+        }
+    }
 }
 
 /// A numeric for loop, such as `for index = 1, 10 do end`
@@ -2492,7 +2535,7 @@ mod tests {
 }
 
 /// Any type, such as `string`, `boolean?`, etc.
-#[derive(Clone, Debug, Display, IsVariant, PartialEq, Node, Deserialize, Serialize)]
+#[derive(Clone, Debug, Display, IsVariant, Node, Deserialize, Serialize)]
 #[non_exhaustive]
 pub enum TypeInfo {
     /// A shorthand type annotating the structure of an array: { number }
@@ -2608,6 +2651,29 @@ impl DefaultRef for TypeInfo {
     }
 }
 
+impl PartialEq for TypeInfo {
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            (Self::Basic(l0), Self::Basic(r0)) => l0.token_type() == r0.token_type(),
+
+            (Self::Array { type_info: lty, .. }, Self::Array { type_info: rty, .. })
+            | (Self::Optional { base: lty, .. }, Self::Optional { base: rty, .. }) => lty == rty,
+
+            (Self::Table { fields: l, .. }, Self::Table { fields: r, .. }) => {
+                l.iter().zip(r.iter()).all(|(l, r)| PartialEq::eq(l, r))
+            }
+
+            (Self::Tuple { types: l, .. }, Self::Tuple { types: r, .. }) => {
+                l.iter().zip(r.iter()).all(|(l, r)| PartialEq::eq(l, r))
+            }
+
+            (Self::Callback { .. }, Self::Callback { .. }) => unimplemented!("need to code the callback type check"),
+
+            _ => false,
+        }
+    }
+}
+
 /// A type field used within table types.
 /// The `foo: number` in `{ foo: number }`.
 #[derive(Clone, Debug, Display, PartialEq, Node, Visit, Deserialize, Serialize)]
@@ -2906,6 +2972,20 @@ impl CompoundOp {
             unreachable!("converting an unknown token into a compound operator")
         }
     }
+
+    /// The operator must be applied to numerical values.
+    pub fn is_numerical_op(&self) -> bool {
+        matches!(
+            self,
+            Self::PlusEqual(_)
+                | Self::MinusEqual(_)
+                | Self::StarEqual(_)
+                | Self::SlashEqual(_)
+                | Self::DoubleSlashEqual(_)
+                | Self::PercentEqual(_)
+                | Self::CaretEqual(_)
+        )
+    }
 }
 
 /// A Compound Assignment statement, such as `x += 1` or `x -= 1`
diff --git a/src/Rust/vvs_parser/src/ast/options.rs b/src/Rust/vvs_parser/src/ast/options.rs
index 228af95d..bf7a4562 100644
--- a/src/Rust/vvs_parser/src/ast/options.rs
+++ b/src/Rust/vvs_parser/src/ast/options.rs
@@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
 /// [module]
 /// option = some Lua/VivyScript expression
 /// ```
-#[derive(Default, Serialize, Deserialize)]
+#[derive(Default, Clone, Serialize, Deserialize)]
 pub struct OptionTable {
     modules: Vec<(ShortString, Vec<(ShortString, Expression)>)>,
 }
diff --git a/src/Rust/vvs_parser/src/ast/parsers/structs/result.rs b/src/Rust/vvs_parser/src/ast/parsers/structs/result.rs
index 8231bb82..67e75aae 100644
--- a/src/Rust/vvs_parser/src/ast/parsers/structs/result.rs
+++ b/src/Rust/vvs_parser/src/ast/parsers/structs/result.rs
@@ -1,13 +1,15 @@
 #[derive(Debug)]
 pub enum ParserResult<T> {
-    // This doesn't necessarily mean that there were no errors,
-    // because this can sometimes be a recovered value.
+    // This doesn't necessarily mean that there were no errors, because this can sometimes be a
+    // recovered value.
     Value(T),
 
-    // Couldn't get any sort of value, but the lexer has moved.
-    // This should always come with an error.
+    // Couldn't get any sort of value, but the lexer has moved. This should always come with an
+    // error.
     LexerMoved,
 
+    // The thing was not found, this can be an error or just that another parser should be used at
+    // this point.
     NotFound,
 }
 
@@ -28,11 +30,7 @@ impl<T> ParserResult<T> {
     }
 
     pub fn unwrap(self) -> T {
-        match self {
-            ParserResult::Value(value) => value,
-            ParserResult::LexerMoved => panic!("unwrap() called when value was LexerMoved"),
-            ParserResult::NotFound => panic!("unwrap() called when value was NotFound"),
-        }
+        self.expect("unwrap() called when value was LexerMoved or NotFound")
     }
 
     pub fn unwrap_or(self, default: T) -> T {
diff --git a/src/Rust/vvs_parser/src/lib.rs b/src/Rust/vvs_parser/src/lib.rs
index 63d28204..1fbe49d1 100644
--- a/src/Rust/vvs_parser/src/lib.rs
+++ b/src/Rust/vvs_parser/src/lib.rs
@@ -9,7 +9,6 @@ mod ast;
 mod error;
 mod node;
 mod private;
-mod short_string;
 mod tokenizer;
 mod traits;
 mod util;
@@ -19,13 +18,15 @@ mod vivy;
 #[cfg(test)]
 mod tests;
 
-use crate::{error::Error, short_string::ShortString};
+use crate::error::Error;
+use vvs_shortstring::ShortString;
 
 /// Crates depending upon [vss_parser] may import the prelude.
 pub mod prelude {
     /// Re-export everything that is linked to the [Ast].
     pub mod ast {
-        pub use crate::{ast::*, node::*, short_string::ShortString, tokenizer::*, visitors::*};
+        pub use crate::{ast::*, node::*, tokenizer::*, visitors::*};
+        pub use vvs_shortstring::ShortString;
     }
 
     /// Parsers, get the raw representation of things without transforming or checking the
diff --git a/src/Rust/vvs_parser/src/tokenizer/lexer.rs b/src/Rust/vvs_parser/src/tokenizer/lexer.rs
index 7ce1b9b5..e03d816d 100644
--- a/src/Rust/vvs_parser/src/tokenizer/lexer.rs
+++ b/src/Rust/vvs_parser/src/tokenizer/lexer.rs
@@ -53,6 +53,7 @@ impl Lexer {
     }
 
     /// Returns a vector of all tokens left in the source string.
+    #[allow(dead_code)]
     pub fn collect(self) -> LexerResult<Vec<Token>> {
         let mut tokens = Vec::new();
         let mut lexer = self;
@@ -733,6 +734,7 @@ impl<T: std::fmt::Debug> LexerResult<T> {
     }
 
     /// Unwraps the result, panicking if it is not [`LexerResult::Ok`].
+    #[allow(dead_code)]
     pub fn unwrap(self) -> T {
         match self {
             Self::Ok(value) => value,
@@ -749,6 +751,7 @@ impl<T: std::fmt::Debug> LexerResult<T> {
     }
 
     /// Returns the errors, if there was any.
+    #[allow(dead_code)]
     pub fn errors(self) -> Vec<TokenizerError> {
         match self {
             Self::Recovered(_, errors) => errors,
diff --git a/src/Rust/vvs_parser/src/vivy/error_report.rs b/src/Rust/vvs_parser/src/vivy/error_report.rs
index 1ddc23d0..b6b051bc 100644
--- a/src/Rust/vvs_parser/src/vivy/error_report.rs
+++ b/src/Rust/vvs_parser/src/vivy/error_report.rs
@@ -113,6 +113,13 @@ impl ErrorReport<'_> {
         ErrorReport::new().add_errors(name, source, [error.into()]).report();
     }
 
+    /// Reports multiple errors
+    pub fn errors(name: &'_ str, source: &'_ str, errors: impl IntoIterator<Item = impl Into<Error>>) {
+        ErrorReport::new()
+            .add_errors(name, source, errors.into_iter().map(Into::into))
+            .report();
+    }
+
     /// Reports a single warning
     pub fn warning(name: &'_ str, source: &'_ str, warning: impl Into<Error>) {
         ErrorReport::new().add_warnings(name, source, [warning.into()]).report();
diff --git a/src/Rust/vvs_parser/src/vivy/frontend_pipeline.rs b/src/Rust/vvs_parser/src/vivy/frontend_pipeline.rs
index ee70bd1e..57c0d4ba 100644
--- a/src/Rust/vvs_parser/src/vivy/frontend_pipeline.rs
+++ b/src/Rust/vvs_parser/src/vivy/frontend_pipeline.rs
@@ -4,7 +4,7 @@
 use crate::{
     ast::*,
     tokenizer::TokenReference,
-    traits::VecExtension as _,
+    traits::{DefaultRef, VecExtension as _},
     vivy::{
         error_report::ErrorReport,
         library::Library,
@@ -18,7 +18,6 @@ use crate::{
 use derive_more::Display;
 use hashbrown::{HashMap, HashSet};
 use std::{borrow::Cow, cell::RefCell, fmt, fs, mem, path::Path, rc::Rc};
-use symbol_table::SymbolTableLocked;
 
 /// Process a program.
 pub struct FrontendPipeline<'a> {
@@ -31,9 +30,6 @@ pub struct FrontendPipeline<'a> {
     /// List of imported modules.
     imports: HashMap<ShortString, Rc<(Ast, Cow<'static, str>)>>,
 
-    /// List of imported symbol tables.
-    symbols: Vec<Rc<SymbolTable<'a, TypeInfo, SymbolTableLocked>>>,
-
     /// The search path.
     search: &'a SearchPath,
 
@@ -53,21 +49,20 @@ pub struct FrontendPipeline<'a> {
 /// Record of all the options defined, unused, setted in the program.
 pub struct OptionsRecord {
     /// List of all unused declared options.
-    unused_options: Vec<(ShortString, ShortString)>,
+    unused: Vec<(ShortString, ShortString)>,
 
     /// All setted options.
-    setted_options: Vec<(ShortString, ShortString, Expression)>,
+    setted: Vec<(ShortString, ShortString, Expression)>,
 
     /// All declared options.
-    declared_options: Vec<(ShortString, ShortString, Expression)>,
+    declared: Vec<(ShortString, ShortString, TypeInfo, Expression)>,
 }
 
 impl fmt::Display for OptionsRecord {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let Self { setted_options, .. } = self;
-        match setted_options.iter().map(|(a, b, _)| a.len() + b.len()).max() {
+        match self.setted.iter().map(|(a, b, _)| a.len() + b.len()).max() {
             None | Some(0) => Ok(()),
-            Some(len) => setted_options.iter().try_for_each(|(module, name, expression)| {
+            Some(len) => self.setted.iter().try_for_each(|(module, name, expression)| {
                 writeln!(f, "{module}.{name: >len$} {expression}", len = len - module.len())
             }),
         }
@@ -110,6 +105,45 @@ pub struct FrontendOutput {
     pub library: Library,
 }
 
+impl FrontendOutput {
+    /// Get all the declared functions from the output of the frontend.
+    pub fn declared_functions(&self) -> impl Iterator<Item = (&str, ShortString, Vec<&TypeInfo>, &TypeInfo)> {
+        fn handle_function<'a>(
+            module: &'a str,
+            name: ShortString,
+            body: &'a FunctionBody,
+        ) -> (&'a str, ShortString, Vec<&'a TypeInfo>, &'a TypeInfo) {
+            let arguments = body
+                .type_specifiers()
+                .flat_map(|ty| Some(ty?.type_info()))
+                .collect::<Vec<_>>();
+            let returns = body
+                .return_type()
+                .map(TypeSpecifier::type_info)
+                .unwrap_or(TypeInfo::default_ref());
+            (module, name, arguments, returns)
+        }
+
+        fn handle_stmt<'a>(
+            module: &'a str,
+            stmt: &'a Stmt,
+        ) -> Option<(&'a str, ShortString, Vec<&'a TypeInfo>, &'a TypeInfo)> {
+            match stmt {
+                Stmt::FunctionDeclaration(d) => Some(handle_function(module, d.name().to_string().into(), d.body())),
+                Stmt::LocalFunction(d) => Some(handle_function(module, d.name().to_string().into(), d.body())),
+                Stmt::JobDeclaration(d) => Some(handle_function(module, d.name().to_string().into(), d.body())),
+                _ => None,
+            }
+        }
+
+        let this = self.ast.nodes().stmts().map(|stmt| (&self.main.name, stmt));
+        let others = self.imports.iter().map(|(m, a)| a.nodes().stmts().map(move |s| (m, s)));
+
+        this.chain(others.flatten())
+            .flat_map(|(module, stmt)| handle_stmt(module, stmt))
+    }
+}
+
 impl From<CompilerResult> for FrontendOutput {
     fn from(value: CompilerResult) -> Self {
         let CompilerResult { ast, imports, main, options, library } = value;
@@ -125,13 +159,10 @@ impl From<CompilerResult> for FrontendOutput {
 
 impl fmt::Display for FrontendOutput {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let Self { imports, main, options, library, .. } = self;
-        write!(f, "imported modules: ")?;
-        imports.keys().try_for_each(|module| write!(f, "{module} "))?;
-        writeln!(f)?;
-
+        let Self { imports, main, options, .. } = self;
+        writeln!(f, "imported modules:")?;
+        imports.keys().try_for_each(|module| writeln!(f, " - {module}"))?;
         writeln!(f, "{options}")?;
-        writeln!(f, "{library}")?;
         writeln!(f, "{main:#?}")
     }
 }
@@ -151,7 +182,7 @@ impl From<()> for FrontendError {
 
 #[derive(Default)]
 struct ImportAllResult {
-    declared_options: Vec<(ShortString, ShortString, Expression)>,
+    declared: Vec<(ShortString, ShortString, TypeInfo, Expression)>,
     unused: Vec<(ShortString, ShortString)>,
 }
 
@@ -162,8 +193,8 @@ impl FromIterator<ImportAllResult> for ImportAllResult {
             return Default::default();
         };
         iter.fold(ret, |mut ret, item| {
-            let Self { mut declared_options, unused } = item;
-            ret.declared_options.append(&mut declared_options);
+            let Self { mut declared, unused } = item;
+            ret.declared.append(&mut declared);
             ret.unused.retain(|option| unused.contains(option));
             ret
         })
@@ -173,15 +204,15 @@ impl FromIterator<ImportAllResult> for ImportAllResult {
 impl<'a> FrontendPipeline<'a> {
     /// Create a new pipeline to parse, to check and do black magic.
     pub fn new(SourceCode { name, code }: &'a SourceCode) -> Self {
+        log::debug!(target: "vvs_parser", "run script `{name}`");
         Self {
             program: Cow::Borrowed(code.as_ref()),
             options: None,
             imports: Default::default(),
-            symbols: vec![],
             is_main: true,
-            search: &DEFAULT_SEARCH_PATH,
-            process_path: vec![ShortString::new(name.as_ref())],
             library: Rc::new(RefCell::new(Library::default())),
+            process_path: vec![ShortString::new(name.as_ref())],
+            search: &DEFAULT_SEARCH_PATH,
             passes: &[],
         }
     }
@@ -246,7 +277,10 @@ impl<'a> FrontendPipeline<'a> {
             })?;
 
             let CompilerResult {
-                ast, imports, options: OptionsRecord { unused_options, declared_options, .. }, ..
+                ast,
+                imports, // Will replace the thing we already took
+                options: OptionsRecord { unused, declared, .. },
+                ..
             } = FrontendPipeline {
                 process_path: self.process_path.clone().join(ShortString::new(name)),
                 imports: mem::take(&mut self.imports), // Will be replaced.
@@ -255,7 +289,6 @@ impl<'a> FrontendPipeline<'a> {
                     Cow::Owned(ref program) => Cow::Borrowed(program.as_str()),
                 },
                 options: self.options.clone(),
-                symbols: self.symbols.clone(),
                 library: self.library.clone(),
                 is_main: false,
                 ..*self
@@ -267,61 +300,60 @@ impl<'a> FrontendPipeline<'a> {
                 let news = HashSet::<&ShortString>::from_iter(imports.keys());
                 (prev.len() <= news.len()) && (prev.intersection(&news).count() == prev.len())
             });
+
             let _ = mem::replace(&mut self.imports, imports); // Replace with a more complete import list.
             self.imports.insert(ShortString::new(name), Rc::new((ast, program)));
 
-            Ok(ImportAllResult { declared_options, unused: unused_options })
+            Ok(ImportAllResult { declared, unused })
         }))
     }
 
     /// Process the pipeline. Some returned values may be hidden from the user, or things
     /// transformed a but more for the main result, but here we keep them.
     fn process(mut self) -> Result<CompilerResult, FrontendError> {
-        let ast = AstResult::parse_fallible(&self.program).into_result().map_err(|err| {
-            let _ = ErrorReport::new().add_errors(self.name(), &self.program, err).report();
-        })?;
+        // Parse the source code.
+        let name = self.name().clone();
+        let ast = AstResult::parse_fallible(&self.program)
+            .into_result()
+            .map_err(|err| ErrorReport::errors(&name, &self.program, err))?;
 
-        let StmtCheckerResult { decl_opts, setd_opts, main, imported } =
-            StmtChecker::new(&ast, (self.name().as_str(), self.program.as_ref()))
+        // Import stuff and check vivy specific statements…
+        let StmtCheckerResult { setted, main, imported } =
+            StmtChecker::new(&ast, (name.as_str(), self.program.as_ref()))
                 .is_main(self.is_main)
                 .process()?;
-        let ImportAllResult { mut declared_options, unused } = self.import_all(imported)?;
-
-        declared_options.extend(
-            decl_opts
-                .into_iter()
-                .map(|(name, value)| (self.name().clone(), name, value.into())),
-        );
+        let result = self.import_all(imported)?;
+        let ImportAllResult { mut declared, unused } = result;
 
+        // Type checker + replace options in the AST…
+        let loc = (name.as_str(), self.program.as_ref());
         let symbols = SymbolTable::try_from(&ast)
-            .map_err(|err| {
-                let _ = ErrorReport::new()
-                    .add_errors(self.name(), &self.program, [err])
-                    .report();
-            })?
-            .import(self.symbols.iter().map(Rc::as_ref));
-
-        let loc = (self.name().as_str(), self.program.as_ref());
+            .map_err(|err| ErrorReport::error(&name, &self.program, err))?
+            .lock();
         TypeCollector::new(&ast, loc, &mut self.library.borrow_mut()).process()?;
-        TypeChecker::new(&ast, loc, &self.library.borrow(), symbols).process()?;
+        let opts = TypeChecker::new(&ast, loc, &self.library.borrow(), symbols)
+            .process()?
+            .options;
 
-        let (ast, OptsTransformResult { unused }) = match self.options.clone() {
-            None => (ast, Default::default()),
-            Some(options) => {
-                let (ast, results) = OptsTransform::new(ast, loc, &options).process()?;
-                (ast, OptsTransformResult { unused: results.unused.without(|opt| unused.contains(opt)) })
-            }
-        };
+        let mut option_table = self.options.map(Rc::unwrap_or_clone).unwrap_or_default();
+        option_table
+            .section_mut("self")
+            .extend(opts.iter().cloned().map(|(name, _, default)| (name, default)));
+        declared.extend(opts.into_iter().map(|(n, t, v)| (name.clone(), n, t, v)));
+
+        let (ast, results) = OptsTransform::new(ast, loc, &option_table, &declared).process()?;
+        let unused_options = results.unused.without(|opt| unused.contains(opt));
 
+        // User passes + return the result
         Ok(CompilerResult {
             ast: self.passes.iter().try_fold(ast, |prog, pass| {
-                log::debug!("apply pass {} on module {}", pass.name(), self.name());
-                pass.process(prog, self.name(), self.program.as_ref())
+                log::info!("apply pass {} on module {name}", pass.name());
+                pass.process(prog, &name, self.program.as_ref())
             })?,
             imports: self.imports,
-            options: OptionsRecord { declared_options, setted_options: setd_opts, unused_options: unused },
-            library: self.library.clone(),
-            main: main.unwrap_or_default(),
+            library: self.library,
+            options: OptionsRecord { declared, setted, unused: unused_options },
+            main: main.unwrap_or_default().with_name(name),
         })
     }
 
diff --git a/src/Rust/vvs_parser/src/vivy/main_program.rs b/src/Rust/vvs_parser/src/vivy/main_program.rs
index 54ddd090..656534e3 100644
--- a/src/Rust/vvs_parser/src/vivy/main_program.rs
+++ b/src/Rust/vvs_parser/src/vivy/main_program.rs
@@ -4,8 +4,11 @@ use crate::{ast::Expression, ShortString};
 use derive_more::{IntoIterator, IsVariant};
 
 /// The main program to execute in the parsed script.
-#[derive(Default, Debug)]
+#[derive(Debug)]
 pub struct MainProgram {
+    /// The name of the program, i.e. the main module.
+    pub name: ShortString,
+
     /// The initial variable name of the read ASS file.
     pub initial: ShortString,
 
@@ -16,7 +19,23 @@ pub struct MainProgram {
     pub returns: MainProgramReturns,
 }
 
+impl Default for MainProgram {
+    fn default() -> Self {
+        Self {
+            name: ShortString::new_static("stdin"),
+            initial: ShortString::new_static("init"),
+            steps: Default::default(),
+            returns: Default::default(),
+        }
+    }
+}
+
 impl MainProgram {
+    /// Set the name of the progeam.
+    pub fn with_name(self, name: ShortString) -> Self {
+        Self { name, ..self }
+    }
+
     /// Set the initial variable name.
     pub fn with_initial(self, initial: ShortString) -> Self {
         Self { initial, ..self }
diff --git a/src/Rust/vvs_parser/src/vivy/mod.rs b/src/Rust/vvs_parser/src/vivy/mod.rs
index e28ae6ec..8435c2e6 100644
--- a/src/Rust/vvs_parser/src/vivy/mod.rs
+++ b/src/Rust/vvs_parser/src/vivy/mod.rs
@@ -10,7 +10,9 @@ mod symbol_table;
 
 use std::{borrow::Cow, fs, io, path::Path};
 
-pub use self::{error_report::ErrorReport, frontend_pipeline::*, main_program::*, passes::UserFrontendPass};
+pub use self::{
+    error_report::ErrorReport, frontend_pipeline::*, main_program::*, passes::UserFrontendPass, search_path::SearchPath,
+};
 
 /// The representation of a source file.
 pub struct SourceCode {
diff --git a/src/Rust/vvs_parser/src/vivy/passes/opts_transform.rs b/src/Rust/vvs_parser/src/vivy/passes/opts_transform.rs
index d6976e49..b3fb20d2 100644
--- a/src/Rust/vvs_parser/src/vivy/passes/opts_transform.rs
+++ b/src/Rust/vvs_parser/src/vivy/passes/opts_transform.rs
@@ -6,7 +6,10 @@ declare_pass! {
     #[allow(dead_code)]
     transform::OptsTransform: 'a {}
 
-    aux    { options: &'a OptionTable                 }
+    aux {
+        options: &'a OptionTable,
+        setted: &'a [(ShortString, ShortString, TypeInfo, Expression)]
+    }
     result { unused:  Vec<(ShortString, ShortString)> }
 }
 
diff --git a/src/Rust/vvs_parser/src/vivy/passes/stmt_checker.rs b/src/Rust/vvs_parser/src/vivy/passes/stmt_checker.rs
index 0bb444e7..517dc2f5 100644
--- a/src/Rust/vvs_parser/src/vivy/passes/stmt_checker.rs
+++ b/src/Rust/vvs_parser/src/vivy/passes/stmt_checker.rs
@@ -14,14 +14,14 @@ declare_pass! {
     /// The statement checker is here to verify that statements are not used in incorrect positions.
     visit::StmtChecker: 'a {
         in_job: bool,
+        decl_opts: Vec<(ShortString, OptionDefaultValue)>,
     }
 
     opt    { is_main: bool }
     result {
-        imported:  Vec<TokenReference>,
-        setd_opts: Vec<(ShortString, ShortString, Expression)>,
-        decl_opts: Vec<(ShortString, OptionDefaultValue)>,
-        main:      Option<MainProgram>,
+        imported: Vec<TokenReference>,
+        setted:   Vec<(ShortString, ShortString, Expression)>,
+        main:     Option<MainProgram>,
     }
 }
 
@@ -32,6 +32,7 @@ impl crate::visitors::Visitor for StmtChecker<'_> {
             Stmt::Main(main) => self.check_main(main),
             Stmt::Assignment(assignment) => self.check_option_set(assignment),
             Stmt::OptionDecl(declaration) => self.check_option_decl(declaration),
+            Stmt::FunctionCall(call) => self.check_top_level_function_call(call),
 
             stmt @ Stmt::FunctionDeclaration(_) | stmt @ Stmt::LocalFunction(_) => stmt.visit(self),
             stmt @ Stmt::JobDeclaration(_) => {
@@ -112,6 +113,23 @@ impl StmtChecker<'_> {
         }
     }
 
+    fn check_top_level_function_call(&mut self, call: &FunctionCall) {
+        let token = call.tokens().next().unwrap();
+        let Prefix::Name(function) = call.prefix() else {
+            return self.error(token, "unexpected function call here, can only call the 'assert' functions here");
+        };
+
+        match call.suffixes().next() {
+            Some(Suffix::Call(Call::AnonymousCall(_))) if call.suffixes().count() == 1 => {}
+            _ => return self.error(token, "expected to call the 'assert' functions simply here…"),
+        }
+
+        match function.token_type().as_str() {
+            "assert" | "assert_eq" | "assert_neq" => {}
+            function => self.error(token, format!("can't call function '{function}' in this position")),
+        }
+    }
+
     fn check_option_decl(&mut self, declaration: &OptionDecl) {
         declaration.declarations().for_each(|(n, ty, v)| match n.token_type() {
             TokenType::Identifier { identifier } if self.decl_opts.iter().any(|(opt, _)| opt == identifier) => {
@@ -175,7 +193,7 @@ impl StmtChecker<'_> {
             .into_iter()
             .zip(assignation.expressions().into_iter().cloned())
             .map(|((module, name), val)| (module, name, val));
-        self.setd_opts.extend(options);
+        self.setted.extend(options);
     }
 
     fn check_main(&mut self, main: &Main) {
diff --git a/src/Rust/vvs_parser/src/vivy/passes/type_checker.rs b/src/Rust/vvs_parser/src/vivy/passes/type_checker.rs
index 71556dbb..8a826036 100644
--- a/src/Rust/vvs_parser/src/vivy/passes/type_checker.rs
+++ b/src/Rust/vvs_parser/src/vivy/passes/type_checker.rs
@@ -1,35 +1,49 @@
+use std::borrow::Cow;
+
 use crate::{
     ast::*,
     node::Node,
     tokenizer::*,
     traits::DefaultRef,
     vivy::{library::*, passes::declare_pass, symbol_table::*},
+    ShortString,
 };
 
 declare_pass! {
     /// The type checker is here to verify type corectness of the program and infer types, etc. To
     /// check the types we will need to do custom things...
-    ///
-    /// TODO: Verify unique functions at top level, with correct names
     visit::TypeChecker: 'a {}
 
     aux {
         library: &'a Library,
         symbols: SymbolTable<'a, TypeInfo, SymbolTableLocked>,
     }
+
+    result {
+        options: Vec<(ShortString, TypeInfo, Expression)>,
+    }
+}
+
+macro_rules! box_error {
+    ($token: expr, $format: literal                   $(,)?) => { Box::new(AstError::from_parts($token.into(), format!($format            ))) };
+    ($token: expr, $format: literal, $($args: expr),+ $(,)?) => { Box::new(AstError::from_parts($token.into(), format!($format, $($args),+))) };
 }
 
 impl crate::visitors::Visitor for TypeChecker<'_> {
     fn visit_ast(&mut self, ast: &Ast) {
         log::error!("todo: verify unique functions at top level, with correct names");
         for error in Vec::from_iter(ast.nodes().stmts().flat_map(|stmt| match stmt {
-            Stmt::JobDeclaration(decl) => self.type_compute().callable(decl.body(), true).err(),
             Stmt::FunctionDeclaration(decl) => self.type_compute().callable(decl.body(), false).err(),
-            Stmt::LocalFunction(decl) => self.type_compute().callable(decl.body(), false).err(),
+            Stmt::JobDeclaration(decl) => self.type_compute().callable(decl.body(), true).err(),
             Stmt::Assignment(assignments) => self.type_compute().assignments(assignments).map(|_| ()).err(),
-            Stmt::OptionDecl(_) | Stmt::Import(_) => None, // NOOP / Types already registered...
+            Stmt::LocalFunction(decl) => self.type_compute().callable(decl.body(), false).err(),
+            Stmt::OptionDecl(decl) => self.handle_type_decl(decl).err(),
+            Stmt::FunctionCall(call) => self.handle_top_level_function_call(call).err(),
+
+            Stmt::Import(_) => None,
             Stmt::TypeDeclaration(_) => unimplemented!("custom types are tbd"),
-            _ => unreachable!("already checked that they are not here"),
+
+            stmt => unreachable!("already checked that they are not here: {stmt}"),
         })) {
             self.report.add_errors(self.name, self.source, [*error]);
         }
@@ -43,6 +57,70 @@ impl TypeChecker<'_> {
     fn type_compute(&self) -> TypeCompute {
         TypeCompute::new(self.library, self.symbols.sub_scope())
     }
+
+    fn handle_top_level_function_call(&mut self, call: &FunctionCall) -> Result<(), TypeComputeError> {
+        let token = call.tokens().next().unwrap();
+        let Prefix::Name(function) = call.prefix() else {
+            return Err(box_error!(token, "expected a function name here"));
+        };
+
+        let args: Vec<Cow<_>> = match call.suffixes().next() {
+            Some(Suffix::Call(Call::AnonymousCall(args))) if call.suffixes().count() == 1 => {
+                Vec::from_iter(args.as_arguments().into_iter().map(|field| match field {
+                    Cow::Borrowed(field) => Cow::Borrowed(field.into()),
+                    Cow::Owned(field) => Cow::Owned(field.into()),
+                }))
+            }
+            _ => return Err(box_error!(token, "expected a simple function call here")),
+        };
+
+        match function.token_type().as_str() {
+            "assert" => match args.len() {
+                1 => self.type_compute().expr_as_type(TypeInfo::number(), &args[0]),
+                2 => {
+                    self.type_compute().expr_as_type(TypeInfo::number(), &args[0])?;
+                    self.type_compute().expr_as_type(TypeInfo::string(), &args[1])?;
+                    Ok(())
+                }
+                n => Err(box_error!(token, "expected 1 or 2 arguments when calling 'assert', got {n}")),
+            },
+            function @ ("assert_eq" | "assert_neq") => match args.len() {
+                2 => {
+                    let (ty, _) = self.type_compute().expr(&args[0])?;
+                    self.type_compute().expr_as_type(&ty, &args[1])
+                }
+                3 => {
+                    let (ty, _) = self.type_compute().expr(&args[0])?;
+                    self.type_compute().expr_as_type(&ty, &args[1])?;
+                    self.type_compute().expr_as_type(TypeInfo::string(), &args[2])
+                }
+                n => Err(box_error!(token, "expected 2 or 3 arguments when calling '{function}', got {n}")),
+            },
+            function => Err(box_error!(token, "unexpected call to function '{function}', expected 'assert' functions")),
+        }
+    }
+
+    fn handle_type_decl(&mut self, decl: &OptionDecl) -> Result<(), TypeComputeError> {
+        if decl.names().len() != decl.expressions().len() {
+            return Err(box_error!(decl.option_token(), ""));
+        }
+
+        let expressions = decl
+            .expressions()
+            .iter()
+            .map(|expr| (expr, self.type_compute().expr(expr)));
+        let names = decl
+            .names()
+            .iter()
+            .map(|name| ShortString::new(name.token_type().as_str()));
+        let options = names
+            .zip(expressions)
+            .map(|(n, (e, r))| r.map(|(t, _)| (n, t, e.clone())))
+            .collect::<Result<Vec<_>, _>>()?;
+        self.options.extend(options);
+
+        Ok(())
+    }
 }
 
 /// The thing that will actually compute types and returns errors in case of problems.
@@ -57,11 +135,6 @@ struct TypeCompute<'a> {
 type TypeComputeError = Box<AstError>;
 type TypeComputeResult<'a> = Result<(TypeInfo, SymbolTable<'a, TypeInfo, SymbolTableMutable>), TypeComputeError>;
 
-macro_rules! box_error {
-    ($token: expr, $format: literal                   $(,)?) => { Box::new(AstError::from_parts($token.into(), format!($format            ))) };
-    ($token: expr, $format: literal, $($args: expr),+ $(,)?) => { Box::new(AstError::from_parts($token.into(), format!($format, $($args),+))) };
-}
-
 fn unsupported<T>(token: &TokenReference, whats: &str) -> Result<T, TypeComputeError> {
     Err(box_error!(token, "{whats} are not supported for now"))
 }
@@ -88,7 +161,7 @@ impl<'a> TypeCompute<'a> {
 
     fn assignments(self, assignments: &'a Assignment) -> TypeComputeResult<'a> {
         let mut assignments = assignments.variables().iter().zip(assignments.expressions());
-        assignments.try_for_each(|(dest, expr)| self.sub().assignation(dest, expr))?;
+        assignments.try_for_each(|(dest, expr)| self.sub().assignation(dest, expr).map(|_| ()))?;
         Ok((TypeInfo::default(), self.symbols))
     }
 
@@ -121,48 +194,36 @@ impl<'a> TypeCompute<'a> {
         func_args: &FunctionArgs,
         token: &TokenReference,
     ) -> Result<TypeInfo, TypeComputeError> {
-        match func_args {
-            FunctionArgs::String(_) => match arguments.first() {
-                Some(type_info) if arguments.len() == 1 && type_info == TypeInfo::string() => Ok(returns.clone()),
-                Some(type_info) if arguments.len() == 1 => Err(box_error!(
-                    token,
-                    "try to pass a string argument to a function that a variable of type {type_info}"
-                )),
-                Some(_) => {
-                    Err(box_error!(token, "try to pass an argument to a function that takes {}", arguments.len()))
-                }
-                None => Err(box_error!(token, "try to pass an argument to a function that takes none",)),
-            },
-
-            FunctionArgs::TableConstructor(_) if arguments.len() != 1 => Err(box_error!(
-                token,
-                "try to pass a table as argument to a function that takes {} arguments",
-                arguments.len()
-            )),
-            FunctionArgs::TableConstructor(args) => {
-                debug_assert_eq!(arguments.len(), 1);
-                todo!("find a way to correctly parse expected types...");
-                // We can pass a table because we expect a table, or because we pass named
-                // arguments...
-            }
-
-            FunctionArgs::Parentheses { arguments: args, .. } => {
-                if args.len() != arguments.len() {
-                    let (arg_len, func_len) = (args.len(), arguments.len());
-                    return Err(box_error!(
-                        token,
-                        "try to pass {arg_len} arguments to a function that takes {func_len}"
-                    ));
-                }
-                let mut arguments = args.iter().enumerate().zip(arguments.iter());
-                match arguments.find_map(|((idx, arg), type_info)| {
-                    self.sub()
-                        .expr_as_type(type_info, arg)
-                        .is_err()
-                        .then(|| (idx, arg.tokens().next().unwrap(), type_info))
-                }) {
-                    Some((n, tok, ty)) => Err(box_error!(tok, "expected argument n°{n} to be of type {ty}")),
-                    None => Ok(returns.clone()),
+        log::error!("what to do in case of table?");
+
+        match arguments {
+            // Treat the passed thing as a table construct if needed.
+            [TypeInfo::Basic(name)] if name.token_type().as_str() == "table" => todo!(),
+
+            // Treat the thing as an argument list.
+            _ => {
+                let func_args = func_args.as_arguments();
+                func_args
+                    .iter()
+                    .any(|f| matches!(&**f, Field::ExpressionKey { .. } | Field::NameKey { .. }))
+                    .then_some(())
+                    .ok_or_else(|| {
+                        box_error!(token, "passing named argument to a function that didn't expect a table")
+                    })?;
+
+                let args = Vec::from_iter(func_args.into_iter().map(|field| match field {
+                    Cow::Borrowed(field) => Cow::Borrowed(Into::<&_>::into(field)),
+                    Cow::Owned(field) => Cow::Owned(field.into()),
+                }));
+
+                let (arguments_len, args_len) = (arguments.len(), args.len());
+                if args_len != arguments_len {
+                    Err(box_error!(token, "argument count mismatch, expected {arguments_len}, got {args_len}"))
+                } else {
+                    args.into_iter()
+                        .zip(arguments)
+                        .try_for_each(|(expr, ty)| self.sub().expr_as_type(ty, &expr))
+                        .map(|_| returns.clone())
                 }
             }
         }
@@ -202,9 +263,7 @@ impl<'a> TypeCompute<'a> {
                 match unop {
                     Minus(_) | Not(_) | Tilde(_) if ty == *TypeInfo::number() => Ok((ty, symbols)),
                     Hash(_) if is_container => Ok((TypeInfo::number().clone(), symbols)),
-                    _ => {
-                        Err(box_error!(unop.token(), "can't apply this unary operator to an expression of type '{ty}'"))
-                    }
+                    _ => Err(box_error!(unop.token(), "can't apply this operator to expression of type '{ty}'")),
                 }
             }
 
@@ -224,10 +283,7 @@ impl<'a> TypeCompute<'a> {
                         Ok((ty, self.symbols))
                     }
 
-                    _ => Err(box_error!(
-                        binop.token(),
-                        "can't apply this binary operator to an expression of type '{ty}'",
-                    )),
+                    _ => Err(box_error!(binop.token(), "can't apply this operator to expression of type '{ty}'")),
                 }
             }
 
@@ -369,17 +425,14 @@ impl<'a> TypeCompute<'a> {
         let variables = assignment.names().iter();
         let variables = variables
             .zip(assignment.type_specifiers().map(|ty| ty.map(TypeSpecifier::type_info)))
-            .zip(assignment.expressions());
-        let variables = variables.map(|((name, ty), val)| {
-            let ty = match ty {
-                None => self.sub().expr(val)?.0,
+            .zip(assignment.expressions())
+            .map(|((name, ty), val)| match ty {
+                None => Ok((name.token_type().as_str().into(), self.sub().expr(val)?.0)),
                 Some(ty) => {
                     self.sub().expr_as_type(ty, val)?;
-                    ty.clone()
+                    Ok((name.token_type().as_str().into(), ty.clone()))
                 }
-            };
-            Ok::<_, TypeComputeError>((name.token_type().as_str().into(), ty))
-        });
+            });
         self.symbols
             .extend(variables.collect::<Result<Vec<_>, TypeComputeError>>()?)
             .map_err(|variable| {
@@ -388,27 +441,49 @@ impl<'a> TypeCompute<'a> {
         Ok((TypeInfo::default(), self.symbols))
     }
 
-    fn compound_assignment(self, assignment: &'a CompoundAssignment) -> TypeComputeResult<'a> {
-        todo!()
-    }
-
     fn yields(self, yields: &'a Yield) -> TypeComputeResult<'a> {
         if !self.in_job {
-            Err(box_error!(yields.token(), "yielding values is only possible from jobs"))
-        } else {
-            todo!()
+            return Err(box_error!(yields.token(), "yielding values is only possible from jobs"));
         }
+
+        for expr in yields.yields().iter() {
+            match (self.sub().expr(expr)?.0, self.returns) {
+                (TypeInfo::Basic(expr), TypeInfo::Basic(returns))
+                    if matches!(
+                        (expr.token_type().as_str(), returns.token_type().as_str()),
+                        ("line" | "syllabe" | "lines" | "syllabes", "line") | ("syllabe" | "syllabes", "syllabe")
+                    ) => {}
+                (expr, returns) => {
+                    return Err(box_error!(
+                        expr.tokens().next().unwrap(),
+                        "can't yield an expression of type '{expr}' as '{returns}'"
+                    ))
+                }
+            }
+        }
+
+        Ok((TypeInfo::default(), self.symbols))
     }
 
-    fn assignation(self, variable: &'a Var, expression: &'a Expression) -> Result<(), TypeComputeError> {
+    fn compound_assignment(self, assignment: &'a CompoundAssignment) -> TypeComputeResult<'a> {
+        let symbols = self.symbols.clone();
+        let ty = self.assignation(assignment.lhs(), assignment.rhs())?;
+        match assignment.compound_operator() {
+            op if op.is_numerical_op() && ty == *TypeInfo::number() => Ok((TypeInfo::default(), symbols)),
+            CompoundOp::TwoDotsEqual(_) if ty == *TypeInfo::string() => Ok((TypeInfo::default(), symbols)),
+            operator => Err(box_error!(operator.token(), "can't apply this operator to a variable of type '{ty}'")),
+        }
+    }
+
+    fn assignation(self, variable: &'a Var, expression: &'a Expression) -> Result<TypeInfo, TypeComputeError> {
         match variable {
-            Var::Expression(_) => todo!(),
+            Var::Expression(var) => todo!("handle assign into varexpr: {var:?}"),
             Var::Name(variable) => match variable.token_type() {
                 TokenType::Identifier { identifier } if self.symbols.is_global(identifier) => {
                     Err(box_error!(variable, "try to assign a global variable"))
                 }
                 TokenType::Identifier { identifier } => match self.symbols.get(identifier).cloned() {
-                    Some(ty) => self.expr_as_type(&ty, expression),
+                    Some(ty) => self.expr_as_type(&ty, expression).map(|_| ty),
                     None => Err(box_error!(variable, "try to assign an undefined variable")),
                 },
                 _ => unreachable!(),
@@ -416,7 +491,7 @@ impl<'a> TypeCompute<'a> {
         }
     }
 
-    fn stmt(self, stmt: &'a Stmt) -> TypeComputeResult<'a> {
+    fn stmt(mut self, stmt: &'a Stmt) -> TypeComputeResult<'a> {
         match stmt {
             Stmt::CompoundAssignment(assignments) => self.compound_assignment(assignments),
             Stmt::LocalAssignment(assignment) => self.local_assignment(assignment),
@@ -464,12 +539,49 @@ impl<'a> TypeCompute<'a> {
                 Ok((TypeInfo::default(), self.symbols))
             }
 
-            Stmt::GenericFor(_) => todo!(),
+            Stmt::GenericFor(for_stmt) if for_stmt.names().len() == for_stmt.expressions().len() => {
+                let symbols = self.symbols.clone();
+                self.symbols.extend(for_stmt
+                    .type_specifiers()
+                    .zip(for_stmt.names().iter().map(|name| ShortString::new(name.token_type().as_str())))
+                    .zip(for_stmt.expressions())
+                    .map(|((ty, name), expr)| match ty {
+                        None => self.sub().expr(expr).map(|(ty, _)| (name, ty)),
+                        Some(ty) => self.sub().expr_as_type(ty.type_info(), expr).map(|_| (name, ty.type_info().clone())),
+                    })
+                    .collect::<Result<Vec<_>, _>>()?)
+                    .map_err(|name| box_error!(for_stmt.for_token(), "can't declare a variable with the name '{name}', is it a global?"))?;
+
+                self.sub().in_loop().block(for_stmt.block())?;
+                Ok((TypeInfo::default(), symbols))
+            }
+            Stmt::GenericFor(for_stmt) if for_stmt.expressions().len() == 1 => {
+                let (it_type, _) = self.sub().expr(for_stmt.expressions().first_value().expect("oupsy"))?;
+                let symbols = self.symbols.clone();
+                let names = for_stmt.names();
+                let handle = |name| box_error!(for_stmt.for_token(), "can't declare a variable with the name '{name}', is it a global?");
+
+                match for_stmt.names().len() {
+                    1 => self.symbols
+                        .set(names.first_value().unwrap().token_type().as_str(), it_type)
+                        .map_err(handle)?,
+                    2 => self.symbols
+                        .set(names.first_value().unwrap().token_type().as_str(), TypeInfo::number().clone())
+                        .map_err(handle)?
+                        .set(names.iter().nth(1).unwrap().token_type().as_str(), it_type)
+                        .map_err(handle)?,
+                    n => return Err(box_error!(for_stmt.for_token(), "expected one or two variables for this generic for, got {n} of them")),
+                };
 
-            Stmt::JobDeclaration(decl) => {
-                Err(box_error!(decl.function_token(), "nested declaration of job is forbidden"))
+                self.sub().in_loop().block(for_stmt.block())?;
+                Ok((TypeInfo::default(), symbols))
             }
 
+            Stmt::JobDeclaration(decl) => Err(box_error!(decl.function_token(), "nested declaration of job is forbidden")),
+            Stmt::GenericFor(for_stmt) => Err(box_error!(for_stmt.for_token(),
+                "a generic for loop can either have the same amount of iterators as the expressions, or a single expression"
+            )),
+
             Stmt::FunctionDeclaration(decl) => unsupported(decl.function_token(), "nested declaration of functions"),
             Stmt::LocalFunction(decl) => unsupported(decl.function_token(), "nested declaration of functions"),
             Stmt::TypeDeclaration(_) => unsupported(stmt.tokens().next().unwrap(), "custom types"),
diff --git a/src/Rust/vvs_parser/src/vivy/search_path.rs b/src/Rust/vvs_parser/src/vivy/search_path.rs
index fd24ed86..ec3f1bf5 100644
--- a/src/Rust/vvs_parser/src/vivy/search_path.rs
+++ b/src/Rust/vvs_parser/src/vivy/search_path.rs
@@ -1,10 +1,15 @@
 //! Used to search for other files when using the `import` statement in Vivy Script.
 
-use std::{borrow::Cow, fs, path::PathBuf};
+use std::{
+    borrow::Cow,
+    fs,
+    path::{Path, PathBuf},
+};
 
 /// Search path, can pass the name of a module and will try to return the associated code.
 #[derive(Default)]
 pub struct SearchPath {
+    script_folder: Option<PathBuf>,
     folders: Vec<PathBuf>,
 }
 
@@ -14,36 +19,34 @@ pub const VIVY_SCRIPT_EXTENSION: &str = "vvs";
 impl SearchPath {
     /// Create a new search path.
     pub const fn new() -> Self {
-        Self { folders: Vec::new() }
+        Self { script_folder: None, folders: Vec::new() }
     }
 
     /// Resolve the search path to get the desired code.
     pub fn resolve(&self, import: &str) -> Option<Cow<'static, str>> {
-        self.folders.iter().find_map(|folder| {
+        self.script_folder.iter().chain(&self.folders).find_map(|folder| {
             let mut path = folder.join(import);
             path.set_extension(VIVY_SCRIPT_EXTENSION);
-            let code = fs::read_to_string(path).ok()?;
-            Some(Cow::Owned(code))
+            Some(Cow::Owned(fs::read_to_string(path).ok()?))
         })
     }
 
-    /// Add a folder to the search list.
-    pub fn push(&mut self, folder: PathBuf) {
-        self.folders.push(folder)
+    /// Set the folder in which the script resides.
+    pub fn with_script_folder(self, folder: impl AsRef<Path>) -> Self {
+        Self { script_folder: Some(folder.as_ref().to_path_buf()), ..self }
     }
-}
 
-impl Extend<PathBuf> for SearchPath {
-    /// Add multiple folders to the search list.
-    fn extend<T: IntoIterator<Item = PathBuf>>(&mut self, iter: T) {
-        self.folders.extend(iter)
+    /// Add a folder to the search list.
+    pub fn with_include(mut self, folder: PathBuf) -> Self {
+        self.folders.push(folder);
+        self
     }
 }
 
 impl FromIterator<PathBuf> for SearchPath {
     /// Create a search list from a list of folders.
     fn from_iter<T: IntoIterator<Item = PathBuf>>(iter: T) -> Self {
-        Self { folders: iter.into_iter().collect() }
+        Self { folders: iter.into_iter().collect(), script_folder: None }
     }
 }
 
diff --git a/src/Rust/vvs_parser/src/vivy/symbol_table.rs b/src/Rust/vvs_parser/src/vivy/symbol_table.rs
index 72203c7c..aa8341d9 100644
--- a/src/Rust/vvs_parser/src/vivy/symbol_table.rs
+++ b/src/Rust/vvs_parser/src/vivy/symbol_table.rs
@@ -22,9 +22,6 @@ pub struct SymbolTable<'a, T: Clone, State> {
     /// A possible parent for this scope.
     parent: Option<&'a SymbolTable<'a, T, SymbolTableLocked>>,
 
-    /// Imported scopes.
-    imported: Vec<&'a SymbolTable<'a, T, SymbolTableLocked>>,
-
     /// List of symbols from this scope.
     symbols: HashMap<ShortString, T>,
 
@@ -34,14 +31,14 @@ pub struct SymbolTable<'a, T: Clone, State> {
 
 impl<T: Clone, State> Default for SymbolTable<'_, T, State> {
     fn default() -> Self {
-        Self { parent: None, symbols: HashMap::new(), imported: vec![], _state: marker::PhantomData }
+        Self { parent: None, symbols: HashMap::new(), _state: marker::PhantomData }
     }
 }
 
 impl<'a, T: Clone> SymbolTable<'a, T, SymbolTableLocked> {
     /// Create a new sub-scoped symbol table.
     pub fn sub_scope(&'a self) -> SymbolTable<'a, T, SymbolTableMutable> {
-        SymbolTable { parent: Some(self), symbols: Default::default(), imported: vec![], _state: marker::PhantomData }
+        SymbolTable { parent: Some(self), symbols: Default::default(), _state: marker::PhantomData }
     }
 
     /// Get the root scope.
@@ -57,8 +54,8 @@ impl<'a, T: Clone> SymbolTable<'a, T, SymbolTableLocked> {
 impl<'a, T: Clone> SymbolTable<'a, T, SymbolTableMutable> {
     /// Lock the table.
     pub fn lock(self) -> SymbolTable<'a, T, SymbolTableLocked> {
-        let Self { parent, imported, symbols, .. } = self;
-        SymbolTable::<'a, T, SymbolTableLocked> { parent, imported, symbols, _state: marker::PhantomData }
+        let Self { parent, symbols, .. } = self;
+        SymbolTable::<'a, T, SymbolTableLocked> { parent, symbols, _state: marker::PhantomData }
     }
 
     /// Add a new variable to the current scope. We override symbols (non-UB shadowing of
@@ -83,15 +80,6 @@ impl<'a, T: Clone> SymbolTable<'a, T, SymbolTableMutable> {
         iter.into_iter()
             .try_fold(self, |this, (symbol, value)| this.set(symbol, value))
     }
-
-    /// Imports other scopes into this one.
-    pub fn import(
-        mut self,
-        iter: impl IntoIterator<Item = &'a SymbolTable<'a, T, SymbolTableLocked>>,
-    ) -> SymbolTable<'a, T, SymbolTableLocked> {
-        self.imported.extend(iter);
-        self.lock()
-    }
 }
 
 impl<'a, T: Clone, State> SymbolTable<'a, T, State> {
@@ -99,7 +87,6 @@ impl<'a, T: Clone, State> SymbolTable<'a, T, State> {
     pub fn get(&self, symbol: impl AsRef<str>) -> Option<&T> {
         self.symbols
             .get(symbol.as_ref())
-            .or_else(|| self.imported.iter().find_map(|scope| scope.get(symbol.as_ref())))
             .or_else(|| self.parent?.get(symbol.as_ref()))
     }
 
@@ -186,14 +173,9 @@ fn fold_table_on_stmt<'a>(
         // Function declarations
         Stmt::LocalFunction(local) => handle_decl(symbol, local.name().token_type().as_str(), local.body()),
         Stmt::FunctionDeclaration(decl) => {
-            let name = decl.name().names().into_iter().next().unwrap().token_type().as_str();
-            handle_decl(symbol, name, decl.body())
+            handle_decl(symbol, decl.name().names().first_value().unwrap().token_type().as_str(), decl.body())
         }
 
-        // Options & constants
-        Stmt::OptionDecl(_) => todo!(),
-        Stmt::LocalAssignment(_) => todo!("handle constants"),
-
         // Ignore
         _ => Ok(symbol),
     }
diff --git a/src/Rust/vvs_parser_derive/Cargo.toml b/src/Rust/vvs_parser_derive/Cargo.toml
index f25fee11..8615d3cf 100644
--- a/src/Rust/vvs_parser_derive/Cargo.toml
+++ b/src/Rust/vvs_parser_derive/Cargo.toml
@@ -4,9 +4,13 @@ license     = "MPL-2.0"
 description = "Internally used for the vvs_parser project. Do not use."
 
 version.workspace = true
-authors.workspace = true
 edition.workspace = true
 
+authors = [
+    "Maëlle Martin <maelle.martin@proton.me>",
+    "Kampfkarren <kampfkarren@gmail.com>",
+]
+
 [lib]
 proc-macro = true
 
diff --git a/src/Rust/vvs_procmacro/src/vvrt/gen.rs b/src/Rust/vvs_procmacro/src/vvrt/gen.rs
index 77a6e0f2..67a46a28 100644
--- a/src/Rust/vvs_procmacro/src/vvrt/gen.rs
+++ b/src/Rust/vvs_procmacro/src/vvrt/gen.rs
@@ -1,41 +1,8 @@
-use crate::vvrt::{MethodInfo, Role, Type};
+use crate::vvrt::{MethodInfo, Role};
 use anyhow::bail;
 use proc_macro2::TokenStream;
 use quote::quote;
 
-fn gen_type_call(ty: &Type, arg: &syn::Ident) -> TokenStream {
-    match ty {
-        Type::None => quote! { LLVMVoidTypeInContext(#arg) },
-        Type::Integer => quote! { LLVMInt32TypeInContext(#arg) },
-        Type::Floating => quote! { LLVMFloatTypeInContext(#arg) },
-        Type::Boolean => quote! { LLVMInt1TypeInContext(#arg) },
-        Type::StrPtr => quote! { LLVMPointerTypeInContext(#arg, 0) },
-        Type::VVRT(vvrt) => {
-            let vvrt = syn::Ident::new(vvrt, arg.span());
-            quote! { #vvrt::llvm_type(#arg) }
-        }
-    }
-}
-
-fn get_asttype(ty: &Type) -> TokenStream {
-    match ty {
-        Type::None => quote! { ASTType::Nil },
-        Type::Integer => quote! { ASTType::Integer },
-        Type::Floating => quote! { ASTType::Floating },
-        Type::Boolean => quote! { ASTType::Boolean },
-        Type::StrPtr => quote! { ASTType::String },
-        Type::VVRT("VVRTString") => quote! { ASTType::String },
-        Type::VVRT("VVRTTable") => quote! { ASTType::AnyTable },
-        Type::VVRT("VVRTSeq") => quote! { ASTType::AnySequence },
-        Type::VVRT("VVRTAny") => quote! { ASTType::Any },
-        Type::VVRT("VVRTVariant") => quote! { ASTType::Variant },
-        Type::VVRT("VVRTType") => quote! { ASTType::Integer },
-        Type::VVRT("VVRTLine") => quote! { ASTType::Line },
-        Type::VVRT("VVRTSyllabe") => quote! { ASTType::Syllabe },
-        ty => unreachable!("unknown type {ty:?}"),
-    }
-}
-
 pub(crate) fn gen_method_infos(name: syn::Ident, infos: Vec<MethodInfo>) -> anyhow::Result<TokenStream> {
     macro_rules! get_manage {
         ($role: ident) => {
@@ -79,32 +46,11 @@ pub(crate) fn gen_method_infos(name: syn::Ident, infos: Vec<MethodInfo>) -> anyh
         _ => bail!("clone and drop functions must be present at the same time, or none of them"),
     };
 
-    let methods = infos.into_iter().map(|(name, _, args, returns)| {
-        let llvm_returns = gen_type_call(&returns, &arg);
-        let llvm_args_len: u32 = args.len().try_into().expect("too many arguments");
-        let llvm_args = quote_vec!(args
-            .iter()
-            .map(|ty| gen_type_call(ty, &arg))
-            .reduce(|acc, item| quote! { #acc, #item }));
-
-        let ast_returns = get_asttype(&returns);
-        let ast_args = quote_vec!(args
-            .into_iter()
-            .map(|ty| get_asttype(&ty))
-            .reduce(|acc, item| quote! { #acc, #item }));
-
+    let methods = infos.into_iter().map(|(name, ..)| {
         let func = syn::Ident::new(&name, arg.span());
-
         quote! {{
             let func: unsafe extern "C" fn() = unsafe { std::mem::transmute(#func as *const ()) };
-            let mut llvm_args = #llvm_args; // We compute the vector here for safety.
-            let ast_type = ASTType::Function(#ast_args, Box::new(#ast_returns)); // Also needs the ast type.
-            let functy = vvs_llvm::sys::LLVMFunctionType(
-                #llvm_returns,                          // Should be Ok there.
-                llvm_args.as_mut_ptr(), #llvm_args_len, // We pre-computed the length here.
-                0                                       // No variadic functions there.
-            );
-            (#name, (func, functy, ast_type))
+            (#name, func)
         }}
     });
     let methods = quote_vec!(methods.reduce(|acc, item| quote! { #acc, #item }));
@@ -121,7 +67,6 @@ pub(crate) fn gen_method_infos(name: syn::Ident, infos: Vec<MethodInfo>) -> anyh
             }
 
             unsafe fn llvm_properties(c: LLVMContextRef) -> Properties {
-                use vvs_lang::ast::ASTType;
                 Properties {
                     manage: #manage,
                     equality: #manage_eq,
diff --git a/src/Rust/vvs_runtime/Cargo.toml b/src/Rust/vvs_runtime/Cargo.toml
index fe6bd029..25ee1821 100644
--- a/src/Rust/vvs_runtime/Cargo.toml
+++ b/src/Rust/vvs_runtime/Cargo.toml
@@ -7,15 +7,16 @@ edition.workspace = true
 license.workspace = true
 
 [dependencies]
-log.workspace        = true
-anyhow.workspace     = true
-serde.workspace      = true
-serde_json.workspace = true
-
+log.workspace               = true
+anyhow.workspace            = true
+serde.workspace             = true
+serde_json.workspace        = true
 vvs_runtime_types.workspace = true
+vvs_ass.workspace           = true
 vvs_utils.workspace         = true
-vvs_llvm.workspace          = true
+
+vvs_llvm = { workspace = true, features = ["init", "bindings"] }
 
 [build-dependencies]
 anyhow.workspace = true
-vvs_llvm = { workspace = true, features = ["link"] }
+vvs_llvm = { workspace = true, features = ["init", "bindings", "link"] }
diff --git a/src/Rust/vvs_runtime/src/jit.rs b/src/Rust/vvs_runtime/src/jit.rs
index b642be58..411ad78e 100644
--- a/src/Rust/vvs_runtime/src/jit.rs
+++ b/src/Rust/vvs_runtime/src/jit.rs
@@ -1,5 +1,5 @@
 use crate::workers::Workers;
-use anyhow::{bail, Context};
+use anyhow::{bail, Context as _};
 use std::{
     ffi::{c_int, c_void, CStr, CString},
     ptr,
@@ -8,8 +8,10 @@ use std::{
         Arc,
     },
 };
+use vvs_ass::ASSContainer;
+use vvs_llvm::prelude::{Context, Module};
 use vvs_llvm::sys::*;
-use vvs_runtime_types::VVRTSymbol;
+use vvs_runtime_types::{types::VVRTTable, VVRTSymbol};
 
 #[allow(dead_code)]
 pub struct JIT {
@@ -65,10 +67,7 @@ extern "C" fn orc_sym_filter(_: *mut c_void, sym: LLVMOrcSymbolStringPoolEntryRe
 impl JIT {
     /// Create a new JIT thingy to execute Vivy Script code.
     pub fn new() -> anyhow::Result<JIT> {
-        if let Err(err) = vvs_llvm::init::initialize_llvm() {
-            log::error!("{err}");
-        }
-
+        let _ = vvs_llvm::init::initialize_llvm();
         unsafe {
             // Create the jit.
             let mut jit = ptr::null_mut();
@@ -115,21 +114,16 @@ impl JIT {
 
     /// Get the context out of the JIT thingy. Used to create a LLVM module to be used latter by
     /// the JIT.
-    pub fn ctx(&self) -> LLVMContextRef {
-        unsafe { LLVMOrcThreadSafeContextGetContext(self.tsctx) }
+    pub fn ctx(&self) -> Context {
+        unsafe { Context::from_ptr(LLVMOrcThreadSafeContextGetContext(self.tsctx)) }
     }
 
     /// Add a new module to the JIT engine.
-    ///
-    /// # Safety
-    /// The passed module ([LLVMModuleRef]) must not be a null pointer and must be a valid LLVM
-    /// module with valid code for the runtime. This module should be created by the [vvs_codegen]
-    /// crate or you can have problems executing it...
-    pub unsafe fn add_module(&self, module: LLVMModuleRef) -> anyhow::Result<()> {
-        let tsm = LLVMOrcCreateNewThreadSafeModule(module, self.tsctx);
-        let rc = LLVMOrcLLJITAddLLVMIRModule(self.jit, self.dylib, tsm);
-        llvm_expect!(rc, "failed to add the module into the jit");
-        Ok(())
+    pub fn with_module(&self, module: Module) -> anyhow::Result<&Self> {
+        let tsm = unsafe { LLVMOrcCreateNewThreadSafeModule(module.as_ptr(), self.tsctx) };
+        let rc = unsafe { LLVMOrcLLJITAddLLVMIRModule(self.jit, self.dylib, tsm) };
+        unsafe { llvm_expect!(rc, "failed to add the module into the jit") };
+        Ok(self)
     }
 
     /// LookUp a symbol defined in the JIT.
@@ -143,6 +137,11 @@ impl JIT {
         );
         Ok(symbol.with_addr(addr))
     }
+
+    /// Run the program on an ass file.
+    pub fn run_on_file(&self, ass: ASSContainer<VVRTTable>) -> anyhow::Result<&Self> {
+        unimplemented!("use the ASS container and insert it into the JIT: {ass:#?}")
+    }
 }
 
 impl Drop for JIT {
diff --git a/src/Rust/vvs_runtime_types/Cargo.toml b/src/Rust/vvs_runtime_types/Cargo.toml
index 7c652ec6..321d01d0 100644
--- a/src/Rust/vvs_runtime_types/Cargo.toml
+++ b/src/Rust/vvs_runtime_types/Cargo.toml
@@ -7,18 +7,15 @@ edition.workspace = true
 license.workspace = true
 
 [dependencies]
-log.workspace        = true
-serde.workspace      = true
-serde_json.workspace = true
-anyhow.workspace     = true
-hashbrown.workspace  = true
-
+log.workspace                  = true
+serde.workspace                = true
+serde_json.workspace           = true
+anyhow.workspace               = true
+hashbrown.workspace            = true
 unicode-segmentation.workspace = true
-
-vvs_procmacro.workspace = true
-vvs_utils.workspace     = true
-vvs_lang.workspace      = true
-vvs_ass.workspace       = true
+vvs_procmacro.workspace        = true
+vvs_utils.workspace            = true
+vvs_ass.workspace              = true
 
 vvs_llvm = { workspace = true, features = ["sys"] }
 
diff --git a/src/Rust/vvs_runtime_types/src/mangle.rs b/src/Rust/vvs_runtime_types/src/mangle.rs
index 3003f418..9e3bb2a5 100644
--- a/src/Rust/vvs_runtime_types/src/mangle.rs
+++ b/src/Rust/vvs_runtime_types/src/mangle.rs
@@ -1,6 +1,5 @@
 use anyhow::{anyhow, bail};
 use std::{ffi::CString, str::FromStr};
-use vvs_lang::ast::ASTType;
 use vvs_llvm::sys::*;
 
 /// Materialize which type of symbol we have.
@@ -70,20 +69,6 @@ impl<'a> VVRTSymbol<'a> {
         Ok(Self { sym: ty, module, name, addr: None })
     }
 
-    pub fn method(ty: &ASTType, name: &'a str) -> anyhow::Result<Self> {
-        let module = match ty {
-            ASTType::Any => "Any",
-            ASTType::Line => "Line",
-            ASTType::String => "String",
-            ASTType::Syllabe => "Syllabe",
-            ty if ty.is_variant() => "Variant",
-            ty if ty.is_table() => "Table",
-            ty if ty.is_sequence() => "Sequence",
-            ty => bail!("can't have methods for type `{ty}`"),
-        };
-        Ok(VVRTSymbol { sym: VVRTSymbolType::Method, module, name, addr: None })
-    }
-
     /// Builder-like syntax to take a symbol and associate it to an execution address gotten from
     /// the JIT engine. We ignore any previous address.
     pub fn with_addr(mut self, addr: LLVMOrcExecutorAddress) -> Self {
diff --git a/src/Rust/vvs_runtime_types/src/vvll.rs b/src/Rust/vvs_runtime_types/src/vvll.rs
index b10ea344..85650122 100644
--- a/src/Rust/vvs_runtime_types/src/vvll.rs
+++ b/src/Rust/vvs_runtime_types/src/vvll.rs
@@ -1,8 +1,7 @@
 #![allow(non_snake_case)]
 
 use hashbrown::{HashMap, HashSet};
-use std::{ffi::CString, sync::OnceLock};
-use vvs_lang::ast::ASTType;
+use std::sync::OnceLock;
 use vvs_llvm::sys::*;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -29,7 +28,7 @@ pub struct Properties {
     pub len: Option<&'static str>,
 
     /// Stores all the methods with some informations about them.
-    pub methods: HashMap<&'static str, (unsafe extern "C" fn(), LLVMTypeRef, ASTType)>,
+    pub methods: HashMap<&'static str, unsafe extern "C" fn()>,
 }
 
 /// Trait used to give to the codegen the layout and functions associated with a type that is
@@ -64,38 +63,3 @@ unsafe fn managed_types() -> &'static mut HashSet<LLVMTypeRef> {
     MANAGED_TYPES.get_or_init(HashSet::new);
     MANAGED_TYPES.get_mut().expect(" should have been created")
 }
-
-/// Register all the exported types and functions into a module.
-///
-/// # Safety
-/// - The [LLVMContextRef] must be valid
-/// - the [LLVMModuleRef] must be valid
-/// - This function is not thread-safe
-pub unsafe fn LLVMRegisterExportedIntoModule(
-    c: LLVMContextRef,
-    m: LLVMModuleRef,
-) -> Vec<(&'static str, ASTType, LLVMValueRef, LLVMTypeRef)> {
-    let mut ret = Vec::default();
-
-    macro_rules! handle {
-        ($ty: ty, $($tys: ty),+ $(,)?) => {
-            handle!($ty);
-            handle!($($tys),+);
-        };
-        ($ty: ty) => {
-            let Properties { manage, equality: _, len: _, methods } = <$ty>::llvm_properties(c);
-            if manage.is_some() {
-                managed_types().insert(<$ty>::llvm_type(c));
-            }
-            for (name, (_, ty, asttype)) in methods {
-                let cstr = CString::new(name).expect("invalid function name");
-                let function = unsafe { LLVMAddFunction(m, cstr.as_ptr(), ty) };
-                ret.push((name, asttype, function, ty));
-            }
-        };
-    }
-
-    use crate::types::*;
-    handle!(VVRTType, VVRTAny, VVRTSeq, VVRTString, VVRTTable);
-    ret
-}
diff --git a/src/Rust/vvs_shortstring/Cargo.toml b/src/Rust/vvs_shortstring/Cargo.toml
new file mode 100644
index 00000000..bd1e3222
--- /dev/null
+++ b/src/Rust/vvs_shortstring/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "vvs_shortstring"
+
+license.workspace = true
+version.workspace = true
+edition.workspace = true
+
+description = "A short string wrapper from full-moon initialy"
+
+authors = [
+    "Maëlle Martin <maelle.martin@proton.me>",
+    "Kampfkarren <kampfkarren@gmail.com>",
+]
+
+[dependencies]
+serde.workspace    = true
+smol_str.workspace = true
diff --git a/src/Rust/vvs_parser/src/short_string.rs b/src/Rust/vvs_shortstring/src/lib.rs
similarity index 100%
rename from src/Rust/vvs_parser/src/short_string.rs
rename to src/Rust/vvs_shortstring/src/lib.rs
diff --git a/src/Rust/vvs_utils/src/xdg/config.rs b/src/Rust/vvs_utils/src/xdg/config.rs
index 49339f5f..0c70a533 100644
--- a/src/Rust/vvs_utils/src/xdg/config.rs
+++ b/src/Rust/vvs_utils/src/xdg/config.rs
@@ -1,9 +1,8 @@
 //! Utilities to extend the [XDGFolder] thing with config files: take into account the
 //! deserialization, merge of configs and others.
 
-use crate::xdg::{MaybeFolderList, XDGError, XDGFindBehaviour, XDGFolder};
-use serde::{Deserialize, Serialize};
-use std::rc::Rc;
+use crate::xdg::{MaybeFolderList, XDGConfigFileSerde, XDGError, XDGFindBehaviour, XDGFolder};
+use std::{fs, marker};
 
 /// Search configurations in all config folders and merge them.
 #[derive(Debug)]
@@ -20,63 +19,46 @@ pub struct XDGConfigFirst;
 #[derive(Debug)]
 pub struct XDGConfigMergedSilent;
 
-pub type DeserializeFunctionPtr<'a, Format> =
-    Rc<dyn Fn(String) -> Result<Format, Box<dyn std::error::Error>> + 'static>;
-
 /// We will write one impl block for merged searches.
 mod private_merged {
-    use crate::xdg::*;
-    use serde::Deserialize;
-    use std::collections::VecDeque;
+    use super::*;
 
     /// Search with merging.
     pub trait Sealed: Sized {
-        fn try_read<'a, Format>(config: &XDGConfig<'a, Format, Self>) -> Result<Format, XDGError>
-        where
-            Format: for<'de> Deserialize<'de> + Extend<Format>;
+        fn try_read<Format: XDGConfigFileSerde>(config: &XDGConfig<Format, Self>) -> Result<Format, XDGError>;
     }
 
     impl Sealed for XDGConfigMergedSilent {
-        fn try_read<'a, Format>(config: &XDGConfig<'a, Format, Self>) -> Result<Format, XDGError>
-        where
-            Format: for<'de> Deserialize<'de> + Extend<Format>,
-        {
-            use XDGError::*;
-            let result = config.search_files()?.into_iter().filter_map(|file| {
-            let file = std::fs::read_to_string(file)
-                .map_err(|err| log::error!(target: "xdg", "{}", ConfigIO(config.app.to_string(), config.get_file().to_string(), err)))
-                .ok()?;
-            config.deserialize.as_ref()(file)
-                .map_err(|err| log::error!(target: "xdg", "{}", DeserializeError(config.app.to_string(), config.get_file().to_string(), err)))
-                .ok()
-        });
-
-            let mut result: VecDeque<Format> = result.collect();
+        fn try_read<Format: XDGConfigFileSerde>(config: &XDGConfig<Format, Self>) -> Result<Format, XDGError> {
+            let mut result = config.search_files()?.into_iter().filter_map(|file| {
+                let file = Result::ok(fs::read_to_string(file)
+                    .map_err(|err| log::error!(target: "xdg", "{}", XDGError::ConfigIO(config.app.to_string(), config.get_file().to_string(), err))))?;
+                Result::ok(Format::deserialize(&file)
+                    .map_err(|e| log::error!(target: "xdg", "deserialize error for {} on file {}: {e}", config.app, config.get_file())))
+            });
+
             let mut first = result
-                .pop_front()
-                .ok_or(ConfigNotFound(config.app.to_string(), config.get_file().to_string()))?;
+                .next()
+                .ok_or_else(|| XDGError::ConfigNotFound(config.app.to_string(), config.get_file().to_string()))?;
             first.extend(result);
             Ok(first)
         }
     }
 
     impl Sealed for XDGConfigMerged {
-        fn try_read<'a, Format>(config: &XDGConfig<'a, Format, Self>) -> Result<Format, XDGError>
-        where
-            Format: for<'de> Deserialize<'de> + Extend<Format>,
-        {
-            use XDGError::*;
-            let mut result: VecDeque<Format> = Default::default();
-            for file in config.search_files()?.into_iter() {
-                let file = std::fs::read_to_string(file)
-                    .map_err(|err| ConfigIO(config.app.to_string(), config.get_file().to_string(), err))?;
-                let file = config.deserialize.as_ref()(file)
-                    .map_err(|err| DeserializeError(config.app.to_string(), config.get_file().to_string(), err))?;
-                result.push_back(file);
-            }
+        fn try_read<Format: XDGConfigFileSerde>(config: &XDGConfig<Format, Self>) -> Result<Format, XDGError> {
+            let mut result = Iterator::collect::<Result<Vec<_>, _>>(config.search_files()?.into_iter().map(|file| {
+                let file = fs::read_to_string(file)
+                    .map_err(|err| XDGError::ConfigIO(config.app.to_string(), config.get_file().to_string(), err))?;
+                let file = Format::deserialize(&file).map_err(|err| {
+                    log::error!(target: "xdg", "deserialize error for application {} on file {}: {err}", config.app, config.get_file());
+                    XDGError::DeserializeError(config.app.to_string(), config.get_file().to_string())
+                })?;
+                Ok(file)
+            }))?.into_iter();
             let mut first = result
-                .pop_front()
-                .ok_or(ConfigNotFound(config.app.to_string(), config.get_file().to_string()))?;
+                .next()
+                .ok_or_else(|| XDGError::ConfigNotFound(config.app.to_string(), config.get_file().to_string()))?;
             first.extend(result);
             Ok(first)
         }
@@ -98,60 +80,30 @@ mod private_merged {
 /// - If the `Merged` parameter is [XDGConfigMerged] and `Format` implements [Extend] on itself,
 ///   then all the found files are parsed and then merged, an error is returned on the first
 ///   failure of the deserialization process.
-pub struct XDGConfig<'a, Format, Merged>
-where
-    Format: for<'de> Deserialize<'de>,
-{
+#[derive(Debug)]
+pub struct XDGConfig<'a, Format: XDGConfigFileSerde, Merged> {
     /// The application name.
     app: &'a str,
 
     /// The file name. If not present will be defaulted to `config` at resolution time.
     file: Option<&'a str>,
 
-    /// Deserializer function.
-    deserialize: DeserializeFunctionPtr<'a, Format>,
-
     /// Stores the format for deserialization.
-    _type: std::marker::PhantomData<Format>,
+    _type: marker::PhantomData<Format>,
 
     /// Stores the format for deserialization.
-    _merged: std::marker::PhantomData<Merged>,
+    _merged: marker::PhantomData<Merged>,
 }
 
-impl<'a, Format, Merged> std::fmt::Debug for XDGConfig<'a, Format, Merged>
-where
-    Format: for<'de> Deserialize<'de>,
-{
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        f.debug_struct("XDGConfig")
-            .field("app", &self.app)
-            .field("file", &self.get_file())
-            .field("merged", &self._merged)
-            .finish()
-    }
-}
-
-impl<'a, Format, Merged> XDGConfig<'a, Format, Merged>
-where
-    Format: for<'de> Deserialize<'de>,
-{
+impl<'a, Format: XDGConfigFileSerde, Merged> XDGConfig<'a, Format, Merged> {
     /// By default we say that the default config file is ${FOLDER}/${APP}/config like many
     /// applications do.
     const DEFAULT_FILE: &'static str = "config";
 
     /// Create a new [XDGConfig] helper.
     #[inline]
-    pub fn new(
-        app: &'a str,
-        deserialize: impl Fn(String) -> Result<Format, Box<dyn std::error::Error>> + 'static,
-    ) -> Self {
-        Self {
-            app,
-            deserialize: Rc::new(deserialize),
-            file: Default::default(),
-            _type: Default::default(),
-            _merged: Default::default(),
-        }
+    pub fn new(app: &'a str) -> Self {
+        Self { app, file: Default::default(), _type: Default::default(), _merged: Default::default() }
     }
 
     /// Change the file to resolve.
@@ -184,38 +136,31 @@ where
     }
 }
 
-impl<'a, Format> XDGConfig<'a, Format, XDGConfigFirst>
-where
-    Format: for<'de> Deserialize<'de>,
-{
+impl<'a, Format: XDGConfigFileSerde> XDGConfig<'a, Format, XDGConfigFirst> {
     /// Try to read the config file and deserialize it.
     pub fn try_read(&self) -> Result<Format, XDGError> {
         let Some(file) = self.search_files()?.into_first() else {
             return Err(XDGError::ConfigNotFound(self.app.to_string(), self.get_file().to_string()));
         };
-        let file = std::fs::read_to_string(file)
+        let file = fs::read_to_string(file)
             .map_err(|err| XDGError::ConfigIO(self.app.to_string(), self.get_file().to_string(), err))?;
-        self.deserialize.as_ref()(file)
-            .map_err(|err| XDGError::DeserializeError(self.app.to_string(), self.get_file().to_string(), err))
+        Format::deserialize(&file)
+            .map_err(|err| {
+                log::error!(target: "xdg", "deserialize error on application {} on file {}: {err}", self.app, self.get_file());
+                XDGError::DeserializeError(self.app.to_string(), self.get_file().to_string())
+            })
     }
 }
 
-impl<'a, Format> XDGConfig<'a, Format, XDGConfigFirst>
-where
-    Format: for<'de> Deserialize<'de> + Serialize,
-{
+impl<'a, Format: XDGConfigFileSerde> XDGConfig<'a, Format, XDGConfigFirst> {
     /// Try to read the config file and deserialize it. If an error is encountred at any point, log
     /// it and return the provided default. If needed the default value is written on the disk,
     /// note that this operation may fail silently.
     #[inline]
-    pub fn read_or(
-        &self,
-        serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
-        default: Format,
-    ) -> Format {
+    pub fn read_or(&self, default: Format) -> Format {
         self.try_read().unwrap_or_else(|err| {
             log::error!(target: "xdg", "read error, return default value to user: {err}");
-            self.write_silent(serialize, default)
+            self.write_silent(default)
         })
     }
 
@@ -223,36 +168,28 @@ where
     /// it and return the provided default. If needed the default value is written on the disk,
     /// note that this operation may fail silently.
     #[inline]
-    pub fn read_or_else(
-        &self,
-        serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
-        cb: impl FnOnce() -> Format,
-    ) -> Format {
+    pub fn read_or_else(&self, cb: impl FnOnce() -> Format) -> Format {
         self.try_read().unwrap_or_else(|err| {
             log::error!(target: "xdg", "read error, return default value to user: {err}");
-            self.write_silent(serialize, cb())
+            self.write_silent(cb())
         })
     }
 
     /// Write a value to the default config file location, the one with the higher priority
     /// (usually the user's one)
-    fn write(
-        &self,
-        serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
-        value: &Format,
-    ) -> Result<(), XDGError> {
-        let content = serialize(value)
-            .map_err(|err| XDGError::SerializeError(self.app.to_string(), self.get_file().to_string(), err))?;
-        let Some(path) = XDGFolder::ConfigDirs
+    fn write(&self, value: &Format) -> Result<(), XDGError> {
+        let content = Format::serialize(value)
+            .map_err(|err| {
+                log::error!(target: "xdg", "serialize error for application {} on file {}: {err}", self.app, self.get_file());
+                XDGError::SerializeError(self.app.to_string(), self.get_file().to_string())
+            })?;
+
+        let path = XDGFolder::ConfigDirs
             .find(self.app, self.get_file(), XDGFindBehaviour::FirstOrCreate)?
             .into_first()
-        else {
-            unreachable!(
-                "the user must have at least one location to place a config file, permission or fs quota problem?"
-            )
-        };
+            .expect("the user must have at least one location to place a config file, permission or fs quota problem?");
 
-        match std::fs::create_dir_all(
+        match fs::create_dir_all(
             path.parent()
                 .ok_or(XDGError::ConfigFileHasNoParentFolder(self.app.to_string(), self.get_file().to_string()))?,
         ) {
@@ -262,65 +199,44 @@ where
             _ => {}
         }
 
-        std::fs::write(path, content)
-            .map_err(|err| XDGError::ConfigIO(self.app.to_string(), self.get_file().to_string(), err))?;
-
-        Ok(())
+        fs::write(path, content)
+            .map_err(|err| XDGError::ConfigIO(self.app.to_string(), self.get_file().to_string(), err))
     }
 
     /// Same as [XDGConfig::write] but log any error and fail silently, returning the value that
     /// was attempted to be written to disk.
     #[inline]
-    fn write_silent(
-        &self,
-        serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
-        value: Format,
-    ) -> Format {
-        if let Err(err) = self.write(serialize, &value) {
+    fn write_silent(&self, value: Format) -> Format {
+        if let Err(err) = self.write(&value) {
             log::error!(target: "xdg", "failed to write default with err: {err}")
         }
         value
     }
 }
 
-impl<'a, Format> XDGConfig<'a, Format, XDGConfigFirst>
-where
-    Format: for<'de> Deserialize<'de> + Serialize + Default,
-{
+impl<'a, Format: XDGConfigFileSerde + Default> XDGConfig<'a, Format, XDGConfigFirst> {
     /// Try to read the config file and deserialize it. If an error is encountred at any point, log
     /// it and return the default. If needed the default value is written on the disk, note that
     /// this operation may fail silently.
     #[inline]
-    pub fn read_or_default(
-        &self,
-        serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
-    ) -> Format {
+    pub fn read_or_default(&self) -> Format {
         self.try_read().unwrap_or_else(|err| {
             log::error!(target: "xdg", "read error, return default value to user: {err}");
-            self.write_silent(serialize, Default::default())
+            self.write_silent(Default::default())
         })
     }
 }
 
 // XDGConfigMerged + XDGConfigMergedSilent
 
-impl<'a, Format, Merged> XDGConfig<'a, Format, Merged>
-where
-    Format: for<'de> Deserialize<'de> + Extend<Format>,
-    Merged: private_merged::Sealed,
-{
+impl<'a, Format: XDGConfigFileSerde, Merged: private_merged::Sealed> XDGConfig<'a, Format, Merged> {
     /// When trying to read or write the default, we write the file with the same logic as the
     /// [XDGConfigFirst] variant, we add this function to reduce the code to write for the write
     /// logic...
     #[inline]
     fn to_config_first(&self) -> XDGConfig<Format, XDGConfigFirst> {
-        XDGConfig::<Format, XDGConfigFirst> {
-            app: self.app,
-            file: self.file,
-            deserialize: self.deserialize.clone(),
-            _type: std::marker::PhantomData,
-            _merged: std::marker::PhantomData,
-        }
+        let Self { app, file, .. } = *self;
+        XDGConfig::<Format, XDGConfigFirst> { app, file, _type: marker::PhantomData, _merged: marker::PhantomData }
     }
 
     /// Try to read the config files and deserialize them. If one config file failed to be
@@ -334,24 +250,16 @@ where
     }
 }
 
-impl<'a, Format, Merged> XDGConfig<'a, Format, Merged>
-where
-    Format: for<'de> Deserialize<'de> + Extend<Format> + Serialize,
-    Merged: private_merged::Sealed,
-{
+impl<'a, Format: XDGConfigFileSerde, Merged: private_merged::Sealed> XDGConfig<'a, Format, Merged> {
     /// Try to read the config files and deserialize them. If an error is encountred at any point,
     /// log it and return the provided default if the merge was not silent, skip the file if it was
     /// silent. If needed the default value is written on the disk, note that this operation may
     /// fail silently.
     #[inline]
-    pub fn read_or(
-        &self,
-        serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
-        default: Format,
-    ) -> Format {
+    pub fn read_or(&self, default: Format) -> Format {
         self.try_read().unwrap_or_else(|err| {
             log::error!(target: "xdg", "read error, return default value to user: {err}");
-            self.to_config_first().write_silent(serialize, default)
+            self.to_config_first().write_silent(default)
         })
     }
 
@@ -360,35 +268,24 @@ where
     /// silent. If needed the default value is written on the disk, note that this operation may
     /// fail silently.
     #[inline]
-    pub fn read_or_else(
-        &self,
-        serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
-        cb: impl FnOnce() -> Format,
-    ) -> Format {
+    pub fn read_or_else(&self, cb: impl FnOnce() -> Format) -> Format {
         self.try_read().unwrap_or_else(|err| {
             log::error!(target: "xdg", "read error, return default value to user: {err}");
-            self.to_config_first().write_silent(serialize, cb())
+            self.to_config_first().write_silent(cb())
         })
     }
 }
 
-impl<'a, Format, Merged> XDGConfig<'a, Format, Merged>
-where
-    Format: for<'de> Deserialize<'de> + Extend<Format> + Serialize + Default,
-    Merged: private_merged::Sealed,
-{
+impl<'a, Format: XDGConfigFileSerde + Default, Merged: private_merged::Sealed> XDGConfig<'a, Format, Merged> {
     /// Try to read the config files and deserialize them. If an error is encountred at any point,
     /// log it and return the provided default if the merge was not silent, skip the file if it was
     /// silent. If needed the default value is written on the disk, note that this operation may
     /// fail silently.
     #[inline]
-    pub fn read_or_default(
-        &self,
-        serialize: impl FnOnce(&Format) -> Result<String, Box<dyn std::error::Error>>,
-    ) -> Format {
+    pub fn read_or_default(&self) -> Format {
         self.try_read().unwrap_or_else(|err| {
             log::error!(target: "xdg", "read error, return default value to user: {err}");
-            self.to_config_first().write_silent(serialize, Default::default())
+            self.to_config_first().write_silent(Default::default())
         })
     }
 }
diff --git a/src/Rust/vvs_utils/src/xdg/mod.rs b/src/Rust/vvs_utils/src/xdg/mod.rs
index 54ca2644..8435840a 100644
--- a/src/Rust/vvs_utils/src/xdg/mod.rs
+++ b/src/Rust/vvs_utils/src/xdg/mod.rs
@@ -8,11 +8,9 @@ mod config;
 mod folders;
 mod options;
 mod paths;
+mod traits;
 
-pub use config::*;
-pub use folders::*;
-pub use options::*;
-pub use paths::*;
+pub use self::{config::*, folders::*, options::*, paths::*, traits::*};
 
 use std::{io::Error as IoError, path::PathBuf};
 use thiserror::Error;
@@ -40,9 +38,9 @@ pub enum XDGError {
     #[error("io error for config file {1} for application {0}: {2}")]
     ConfigIO(String, String, IoError),
 
-    #[error("deserialization failed on file {1} for application {0} with: {2}")]
-    DeserializeError(String, String, Box<dyn std::error::Error>),
+    #[error("deserialization failed on file {1} for application {0}")]
+    DeserializeError(String, String),
 
-    #[error("serialization failed on file {1} for application {0} with: {2}")]
-    SerializeError(String, String, Box<dyn std::error::Error>),
+    #[error("serialization failed on file {1} for application {0}")]
+    SerializeError(String, String),
 }
diff --git a/src/Rust/vvs_utils/src/xdg/traits.rs b/src/Rust/vvs_utils/src/xdg/traits.rs
new file mode 100644
index 00000000..728ef7cf
--- /dev/null
+++ b/src/Rust/vvs_utils/src/xdg/traits.rs
@@ -0,0 +1,7 @@
+pub trait XDGConfigFileSerde: Sized + Extend<Self> {
+    type Error: std::error::Error;
+
+    fn deserialize(input: &str) -> Result<Self, Self::Error>;
+
+    fn serialize(&self) -> Result<String, Self::Error>;
+}
-- 
GitLab