Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

High-Level Architecture

System Layers

LFE is organized into nine architectural layers, from foundational utilities to user-facing applications:

┌─────────────────────────────────────────────────────────┐
│  Layer 9: Applications & CLI Tools                      │
│  lfec, lfescript, lfe (REPL)                            │
└─────────────────────────────────────────────────────────┘
                        ↓
┌─────────────────────────────────────────────────────────┐
│  Layer 8: Shell & Interactive Environment               │
│  lfe_shell, lfe_edlin_expand                            │
└─────────────────────────────────────────────────────────┘
                        ↓
┌─────────────────────────────────────────────────────────┐
│  Layer 7: Documentation System                          │
│  lfe_docs, lfe_shell_docs                               │
└─────────────────────────────────────────────────────────┘
                        ↓
┌─────────────────────────────────────────────────────────┐
│  Layer 6: Compilation Pipeline                          │
│  lfe_comp (orchestrator)                                │
│  lfe_scan → lfe_parse → lfe_macro → lfe_lint →          │
│  lfe_codegen → lfe_translate                            │
└─────────────────────────────────────────────────────────┘
                        ↓
┌─────────────────────────────────────────────────────────┐
│  Layer 5: Runtime & Evaluation                          │
│  lfe_eval, lfe_env                                      │
└─────────────────────────────────────────────────────────┘
                        ↓
┌─────────────────────────────────────────────────────────┐
│  Layer 4: Standard Library                              │
│  lfe_io, lfe_lib, lfe_gen, lfe_types                    │
│  lfe_bits, lfe_ms, lfe_qlc                              │
└─────────────────────────────────────────────────────────┘
                        ↓
┌─────────────────────────────────────────────────────────┐
│  Layer 3: Compatibility Layers                          │
│  cl (Common Lisp), clj (Clojure), scm (Scheme)          │
└─────────────────────────────────────────────────────────┘
                        ↓
┌─────────────────────────────────────────────────────────┐
│  Layer 2: Language Internals                            │
│  lfe_internal (core forms, special forms, intrinsics)   │
└─────────────────────────────────────────────────────────┘
                        ↓
┌─────────────────────────────────────────────────────────┐
│  Layer 1: Foundation                                    │
│  lfe.hrl, lfe_comp.hrl, lfe_macro.hrl (shared defs)     │
└─────────────────────────────────────────────────────────┘

Compilation Pipeline Architecture

The compilation pipeline is a linear, acyclic flow with distinct phases:

Source File (.lfe)
    ↓
┌──────────────────┐
│  lfe_scan.erl    │  Lexical Analysis: Text → Tokens
│  (897 LOC)       │  Handles: strings, atoms, numbers, symbols, sigils
└──────────────────┘
    ↓ Tokens
┌──────────────────┐
│  lfe_parse.erl   │  Syntactic Analysis: Tokens → S-expressions
│  (284 LOC)       │  LL(1) parser, trivial due to S-expr syntax
└──────────────────┘
    ↓ S-expressions
┌──────────────────┐
│  lfe_macro.erl   │  Macro Expansion: Transform AST
│  (1,432 LOC)     │  Recursive expansion, hygiene, quasiquotation
└──────────────────┘
    ↓ Expanded Forms
┌──────────────────┐
│  lfe_lint.erl    │  Semantic Analysis: Validate & Check
│  (2,532 LOC)     │  Variable binding, type checking, pattern validation
└──────────────────┘
    ↓ Validated Forms
┌──────────────────┐
│  lfe_docs.erl    │  Documentation Extraction: EEP-48 chunks
│  (362 LOC)       │  Extract docstrings, specs, metadata
└──────────────────┘
    ↓ Forms + Docs
┌──────────────────┐
│  lfe_codegen.erl │  Code Generation: Lambda lifting, AST building
│  (499 LOC)       │  Prepare Erlang Abstract Format
└──────────────────┘
    ↓ Erlang AST (pre-translation)
┌──────────────────┐
│ lfe_translate.erl│  AST Translation: LFE Forms → Erlang Abstract Format
│  (2,182 LOC)     │  Pattern/guard/expression translation
└──────────────────┘
    ↓ Complete Erlang AST
┌──────────────────┐
│ compile:forms/2  │  Erlang Compiler: AST → BEAM
│ (Erlang stdlib)  │  Optimizations, code generation, BEAM emission
└──────────────────┘
    ↓
BEAM Bytecode (.beam)

Key metrics:

  • Total compiler code: ~8,000 LOC (39.5% of codebase)
  • Largest module: lfe_lint.erl (2,532 LOC) - semantic analysis
  • Second largest: lfe_translate.erl (2,182 LOC) - AST translation
  • Macro system: lfe_macro.erl (1,432 LOC) - the heart of LFE's power
  • Parser simplicity: lfe_parse.erl (284 LOC) - S-expressions make parsing trivial

Runtime System Architecture

LFE provides a complete interpreter alongside its compiler, enabling dual execution modes:

┌─────────────────────────────────────────────────────────┐
│  Compiled Execution Path                                │
│  Source → Compile → BEAM → Execute on VM                │
│  (Fast, optimized, production)                          │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│  Interpreted Execution Path                             │
│  S-expr → Macro Expand → lfe_eval → Value               │
│  (Interactive, REPL, eval-when-compile)                 │
└─────────────────────────────────────────────────────────┘

Runtime components:

  • lfe_eval.erl (2,004 LOC): Complete interpreter with all special forms
  • lfe_env.erl (252 LOC): Environment management (bindings, scoping)
  • lfe_shell.erl (1,188 LOC): Interactive REPL with job control
  • lfe_edlin_expand.erl (175 LOC): Tab completion system

Shell architecture uses a two-process model:

┌──────────────────┐         ┌─────────────────────┐
│  Shell Process   │ <-----> │  Evaluator Process  │
│  - I/O handling  │  msgs   │  - Expression eval  │
│  - History       │         │  - Pattern matching │
│  - State mgmt    │         │  - Isolated crashes │
└──────────────────┘         └─────────────────────┘

This isolation ensures evaluator crashes don't kill the shell, enabling robust interactive development.