Aims: 

- Describe the pipeline, and components getting from aiken to uplc. 

## Air 

Aiken compiles aiken code to uplc via _air_: 
Aiken Intermediate Representation. 

## Trace

Running  `aiken build`...

The cli (See `aiken/src/cmd/mod.rs`) parses the command, 
finds the context and calls `Project::build` (`crates/aiken-project/src/lib.rs`),
which in turn calls `Project::compile`. 

#### `Project::compile`

1. Check dependencies are available _eg_ aiken stdlib. 
2. Read source files.  
  1. Walk over `./lib` and `./validators` and push aiken modules onto `Project.sources`.
3. Parse each source in sources: 
  1. Generate a `ParsedModule` containing the `ast`, `docs`, _etc_.
  The `ast` here is an `UntypedModule`, which contains untyped definitions.
4. Type check each parsed module.
  1. For each untyped module, create a `CheckedModule`. 
  This includes typed definitions. 
5. `compile` forks into two depending on whether it's been called with `build` or `check`. 
6. From `CheckModules` construct a `CodeGenerator`
7. Pass the generator to construct a new `Blueprints`.
  1. Blueprints finds validators from checked modules. 
  2. From each it constructs a `Validator` with the constructor `Validator::from_checked_module` (which returns a vector of validators)
      1. Its here that the magic happens: The method `generator.generate(def)` is called, 
        where `def` is the typed validator(s). 
        This method outputs a `Program<Name>` which contains the UPLC.
      2. These are collected together.
  3. The rest is collecting and handling the errors and warnings and writing the blueprint.


#### `CodeGenerator::generate`

1. Create a new `AirStack`.


#### `AirStack`

Consists of:
1. An Id
2. A `Scope`
3. A vector of `Air` 

The Scope keeps track of ... [TODO]

#### Air 

Air is a typed language... [TODO]
