bf74795e01
Introduces a new `RecordLayout` system for efficient and type-safe record handling. Key changes: - `RecordLayout` struct with `O(1)` field lookup using FMap optimization. - Field accessors (`.name`) are now first-class callable values. - Parser recognizes dot-prefixed identifiers as field accessors. - Binder and TypeChecker handle field accessors. - Optimizer transforms field accessor calls into specialized `GetField` nodes. - VM executes `GetField` efficiently by directly accessing record values. - Adds a new `records.myc` example showcasing record features. - Improves comparison logic for records to use pointer equality for layout.
56 lines
2.7 KiB
Markdown
56 lines
2.7 KiB
Markdown
# Plan: Record Layout & Optimized Field Access
|
|
|
|
This document outlines the implementation plan for porting Delphi's `TKeywordMappingRegistry` optimizations to the Rust-based Myc AST compiler and integrating first-class field accessors.
|
|
|
|
## 1. Core Data Structures (`src/ast/types.rs`)
|
|
|
|
### RecordLayout (The Schema)
|
|
- **Concept:** Replaces `IKeywordMapping<IStaticType>`.
|
|
- **Interning:** Managed via a global `OnceLock<Mutex<HashMap<..., Arc<RecordLayout>>>>`.
|
|
- **FMap Optimization:**
|
|
- Stores `fields: Vec<(Keyword, StaticType)>`.
|
|
- Maintains a lookup array `Vec<i32>` mapping `Keyword.idx - first_key` to the index in the fields array.
|
|
- Provides `index_of(Keyword) -> Option<usize>` with **O(1)** complexity.
|
|
- **Thread Safety:** Uses `Arc` for global sharing across script threads.
|
|
|
|
### Value & StaticType Updates
|
|
- `Value::Record` points to an `Arc<RecordLayout>` and a flat `Rc<Vec<Value>>`.
|
|
- `Value::FieldAccessor(Keyword)` added as a first-class callable value (e.g., `.name`).
|
|
- `StaticType::Record` now holds `Arc<RecordLayout>`.
|
|
|
|
## 2. Compiler Pipeline
|
|
|
|
### Parser (`src/ast/parser.rs`)
|
|
- Identifiers starting with `.` (e.g., `.age`) are parsed as `UntypedKind::FieldAccessor(Keyword)`.
|
|
- This ensures interning happens immediately; strings are never used for field access in subsequent phases.
|
|
|
|
### Binder (`src/ast/compiler/binder.rs`)
|
|
- Maps `UntypedKind::FieldAccessor` to `BoundKind::FieldAccessor`.
|
|
|
|
### TypeChecker (`src/ast/compiler/type_checker.rs`)
|
|
- **Analysis Only:** When encountering `Call { callee: FieldAccessor, args: [rec] }`:
|
|
- Validates that `rec` is a Record.
|
|
- Uses `RecordLayout::index_of` to find the field's type.
|
|
- Sets the call's return type accordingly.
|
|
- **Crucial:** Does NOT modify the AST structure. It remains a `Call`.
|
|
|
|
### Optimizer (`src/ast/compiler/optimizer/engine.rs`)
|
|
- **Transformation:** Recognizes the `Call { callee: FieldAccessor, ... }` pattern.
|
|
- Transforms it into a specialized `BoundKind::GetField { rec, field: Keyword }` node.
|
|
|
|
## 3. Execution (`src/ast/vm.rs`)
|
|
|
|
### Optimized Path (`GetField`)
|
|
- The VM executes `GetField` by:
|
|
1. Evaluating the record.
|
|
2. Calling `layout.index_of(field)` (O(1)).
|
|
3. Fetching the value from the flat array.
|
|
|
|
### Functional Path (`FieldAccessor`)
|
|
- If `.field` is passed as a value (e.g., `(map .name users)`), the VM treats the `FieldAccessor` value as a standard function that takes one argument and performs the lookup.
|
|
|
|
## 4. Benefits
|
|
- **Type Identity:** `Arc::ptr_eq` allows instant type comparison.
|
|
- **Performance:** Field access in loops is O(1) without hash lookups.
|
|
- **Safety:** The TypeChecker remains a pure analysis phase as per design requirements.
|