Architecture and Flow


This document is meant to explain the inner workings on the Loop interpreter. It provides an overview and a flowchart to give a detailed but concise picture of the whole interpreter; Including its sub-components.

It is expected that the reader has basic knowledge about interpreters and compilers, since terms like lexer and parsing will be mentioned.

Loop is a Just-In-Time compiled programming language, which compiles to an intermediate representation called Arc, before to its targeted language.

Interpreter walkthrough

This paragraph explains how your code goes from loop to an actual running program.


  1. Picasso get Loop code as input. It lexes, parses and than compiles it into Arc code.

  2. Vinci receives Arc code as input. It lexes and parses that into a abstract syntax tree (AST), which it exposes for others to use.

  3. Sanzio uses the exposed AST and generates Lua code.

  4. Loop takes that generated Lua code and executes it with the LuaJIT interpreter.

In short: Loop → Arc → AST → Lua → Execution


The Loop Intermediate Representation (LIR), code named Arc, is mainly designed to represent Loop source code. It is easily parsable for further optimisations and eventually execution. LIR Is generic and not dependant on any source, target or platform. As a side benefit, it makes LIR a great fit as a target for other languages.

Go to the Arc specification for more information.

Dependency Diagram

This paragraph is about the different components inside the interpreter and how they depent on each other. They are made and depend on eachother in such a way that it should be relativly easy for someone to write their own code generator for example.

Virtually every part of the compiler is written in Rust, that might change in the future if we decide to write certain things in C or maybe even Loop itself. The only major external dependency that Loop has is the LuaJIT compiler; its targeted language.


Loop is the encompassing package that holds all the sub-packages. It has three main goals:

  • Parsing command-line-arguments: Debug mode, turning on optimization

  • Input of source-code: Could also be the REPL

  • Calling the packages: Think of Sanzio of Picasso

  • Executing generated code


The task of Picasso is to compile Loop to an intermediate representation called Arc, this has two main purposes:

  • Type inference: Loop is type-safe but it is not necessary to explicitly give variables a type.

  • Desugaring: Removing syntax sugar, think of certain loops. ****

  • Syntax errors: Finding and throwing syntax error.


Lexing and parsing Arc intermediate language to an exposed AST:

  • Parsing Arc to AST: This AST is exposed so you can write your own code generator.

  • Optimizing code: Here is where optimization of code happens, although a lot is also done by LuaJIT.


First-party code generation package its targets Lua, and it uses the LuaJIT interpreter to blazing fast interpretation.

  • Transpilation to Lua: Generating Lua Code.

Last updated