How alan-d-mitchell/vypr works
Vypr is organized as a Rust workspace with one executable crate and several library crates that form a source-to-VM pipeline.
1. Entry point: cli
- cli/src/main.rs is the user-facing command line binary.
- It likely reads a .vypr source file, invokes the compiler pipeline, and runs the program on the VM.
2. Shared error model: crates/error
- This is a common dependency used across the workspace for diagnostics and failure handling.
- It provides the repository-wide error type so lexer, parser, semantic analysis, IR builders, and VM can report issues consistently.
3. Front end: crates/lexer
- Converts Vypr source text into tokens.
- The presence of token.rs and lexer.rs indicates a standalone lexical stage before parsing.
4. Syntax layer: crates/parser
- Turns tokens into an AST (ast.rs).
- This is the language’s structural model for statements, expressions, literals, function definitions, and other Python-like constructs.
5. Semantic analysis: crates/semantic
- Responsible for scope handling, method resolution, and type-related checks.
- scope.rs and methods.rs show that this crate manages lexical scoping, symbol resolution, and the rules behind gradual typing.
- This is where annotated variables are distinguished from dynamic ones, and where many static errors are detected before execution.
6. First IR layer: crates/vir
- Vypr has an intermediate representation called VIR.
- builder.rs suggests AST-to-VIR lowering, while context.rs likely carries symbol/type state across lowering passes.
- This layer is an architectural boundary between language semantics and VM-oriented representation.
7. Second IR layer: crates/mir
- MIR is a lower-level intermediate form than VIR.
- builder.rs and display.rs indicate another lowering pass plus debugging/inspection support.
- The two-stage IR design suggests the compiler separates high-level language structure from execution-friendly operations.
8. Runtime backend: crates/vm
- This is the execution engine: a custom stack-based virtual machine.
- bytecode.rs, compiler.rs, and vm.rs show the path from lowered IR into executable bytecode and then into runtime interpretation.
- value.rs likely defines the VM’s runtime value model, including typed and dynamic values.
9. Built-ins and standard library: crates/vm/src/stdlib
- Vypr includes native modules for math, time, os, and canvas.
- builtins.rs and methods.rs indicate intrinsic functions and type-specific methods are implemented inside the VM/runtime boundary, not in userland code.
- This is the main external-facing runtime extension surface.
10. Bytecode persistence/support: serializer.rs
- The VM includes serialization support for bytecode or compiled artifacts.
- That implies the runtime can likely persist or reload compiled forms, even if the primary workflow is direct compile-and-run.
11. End-to-end data flow
- Source file → lexer tokens → parser AST → semantic analysis → VIR → MIR → VM bytecode → stack-based execution.
- Type enforcement is split across compile-time semantic checks and runtime enforcement for annotated values, matching the gradual typing model described in the README.
12. Repository boundary and examples
- The examples/ directory is not part of the runtime, but it is important for understanding intended language behavior.
- The sample programs cover gradual typing, coercion, data pipelines, fractals, and error cases, which makes them useful reference points for the language features exercised by the compiler and VM.
13. Diagramming implication
- The cleanest architecture diagram is a left-to-right compiler pipeline feeding a runtime box.
- Keep the compiler frontend, IR lowering stages, and VM/runtime as separate layers, with error and stdlib shown as cross-cutting support components.
Main entry points: vm.rs VM · lib.rs Errors · analyzer.rs Analyzer · lexer.rs Lexer
Components 21
Tooling
Workspace entrypoint and user-facing command line
- CLI · Command-line entrypoint that drives the compile-and-run flow
cli/src/main.rs
Front end
Source parsing and semantic checks
- Lexer · Converts source text into tokens
crates/lexer/src/lexer.rs - Tokens · Lexical token definitions used by the parser
crates/lexer/src/token.rs - Parser · Builds the AST from token streams
crates/parser/src/parser.rs - AST · Language structure for statements, expressions, and definitions
crates/parser/src/ast.rs - Analyzer · Performs scope and type-related validation
crates/semantic/src/analyzer.rs - Scope · Tracks lexical scopes and bindings during analysis
crates/semantic/src/scope.rs - Methods · Handles method lookup and related semantic rules
crates/semantic/src/methods.rs
IR
Intermediate representations between language and runtime
- VIR Builder · Lowers analyzed AST into the higher-level intermediate form
crates/vir/src/builder.rs - VIR · Higher-level intermediate representation used between semantics and codegen
crates/vir/src/vir.rs - MIR Builder · Lowers VIR into the lower-level intermediate form
crates/mir/src/builder.rs - MIR · Execution-oriented intermediate representation
crates/mir/src/mir.rs
Runtime
Virtual machine, bytecode, and built-in modules
- Compiler · Converts lowered IR into VM bytecode
crates/vm/src/compiler.rs - Bytecode · Executable form consumed by the virtual machine
crates/vm/src/bytecode.rs - VM · Runtime execution engine for compiled programs
crates/vm/src/vm.rs - Value · Represents runtime values and typed data
crates/vm/src/value.rs - Stdlib · Built-in modules and intrinsic runtime functions
crates/vm/src/stdlib/mod.rs - Builtins · Core built-in functions exposed by the runtime
crates/vm/src/builtins.rs - Serializer · Persists or reloads compiled bytecode artifacts
crates/vm/src/serializer.rs
Connections 24
- CLI → Lexer: starts with · CLI feeds source text into lexical analysis
- Lexer → Tokens: produces · Lexer emits token streams using token definitions
- Tokens → Parser: consumed by · Parser reads tokens to build syntax
- Parser → AST: produces · Parser outputs the AST
- AST → Analyzer: analyzed by · AST is validated for scope and semantic rules
- Analyzer → Scope: uses · Analyzer depends on scope tracking
- Analyzer → Methods: uses · Analyzer relies on method resolution rules
- Analyzer → VIR Builder: lowers to · Validated program is lowered into VIR
- VIR Builder → VIR: produces · Builder emits the higher-level IR
- VIR → MIR Builder: lowers to · VIR is transformed into MIR
- MIR Builder → MIR: produces · Builder emits the lower-level IR
- MIR → Compiler: feeds · MIR is compiled into bytecode
- Compiler → Bytecode: produces · Compiler outputs executable bytecode
- Bytecode → VM: runs on · Bytecode is interpreted by the VM
- VM → Value: manages · VM evaluates and stores runtime values
- VM → Stdlib: loads · VM exposes native standard library modules
- VM → Builtins: exposes · Runtime provides built-in functions and methods
- VM → Serializer: supports · VM can serialize compiled artifacts
- Errors → Lexer: shared by · Lexing reports failures through the common error model
- Errors → Parser: shared by · Parsing reports failures through the common error model
- Errors → Analyzer: shared by · Semantic analysis reports failures through the common error model
- Errors → Compiler: shared by · Compilation reports failures through the common error model
- Errors → VM: shared by · Runtime errors use the common error model
- Examples → CLI: exercises · Examples demonstrate the end-to-end toolchain