117 lines
6.3 KiB
Markdown
117 lines
6.3 KiB
Markdown
# mdt Internal Code Documentation
|
|
|
|
This document provides a detailed overview of the `mdt` codebase architecture and internal components.
|
|
|
|
## Architecture Overview
|
|
|
|
`mdt` is built as a modular system where core functionalities are separated into internal packages. The data flow typically follows this pattern:
|
|
|
|
1. **Parsing**: Source code is parsed into an Abstract Syntax Tree (AST).
|
|
2. **Indexing**: ASTs from multiple files are aggregated into a unified `ProjectTree`.
|
|
3. **Processing**: The `ProjectTree` is used by the Validator, Builder, and LSP server to perform their respective tasks.
|
|
|
|
## Package Structure
|
|
|
|
```
|
|
cmd/
|
|
mdt/ # Application entry point (CLI)
|
|
internal/
|
|
builder/ # Logic for merging and building configurations
|
|
formatter/ # Code formatting engine
|
|
index/ # Symbol table and project structure management
|
|
logger/ # Centralized logging
|
|
lsp/ # Language Server Protocol implementation
|
|
parser/ # Lexer, Parser, and AST definitions
|
|
schema/ # CUE schema loading and integration
|
|
validator/ # Semantic analysis and validation logic
|
|
```
|
|
|
|
## Core Packages
|
|
|
|
### 1. `internal/parser`
|
|
|
|
Responsible for converting MARTe configuration text into structured data.
|
|
|
|
* **Lexer (`lexer.go`)**: Tokenizes the input stream. Handles MARTe specific syntax like `#package`, `//!` pragmas, and `//#` docstrings. Supports standard identifiers and `#`-prefixed identifiers.
|
|
* **Parser (`parser.go`)**: Recursive descent parser. Converts tokens into a `Configuration` object containing definitions, comments, and pragmas.
|
|
* **AST (`ast.go`)**: Defines the node types (`ObjectNode`, `Field`, `Value`, `VariableDefinition`, etc.). All nodes implement the `Node` interface providing position information.
|
|
|
|
### 2. `internal/index`
|
|
|
|
The brain of the system. It maintains a holistic view of the project.
|
|
|
|
* **ProjectTree**: The central data structure. It holds the root of the configuration hierarchy (`Root`), references, and isolated files.
|
|
* **ProjectNode**: Represents a logical node in the configuration. Since a node can be defined across multiple files (fragments), `ProjectNode` aggregates these fragments. It also stores locally defined variables in its `Variables` map.
|
|
* **NodeMap**: A hash map index (`map[string][]*ProjectNode`) for $O(1)$ symbol lookups, optimizing `FindNode` operations.
|
|
* **Reference Resolution**: The `ResolveReferences` method links `Reference` objects to their target `ProjectNode` or `VariableDefinition`. It uses `resolveScopedName` to respect lexical scoping rules, searching up the hierarchy from the reference's container.
|
|
|
|
### 3. `internal/validator`
|
|
|
|
Ensures configuration correctness.
|
|
|
|
* **Validator**: Iterates over the `ProjectTree` to check rules.
|
|
* **Checks**:
|
|
* **Structure**: Duplicate fields, invalid content.
|
|
* **Schema**: Unifies nodes with CUE schemas (loaded via `internal/schema`) to validate types and mandatory fields.
|
|
* **Signals**: Verifies that signals referenced in GAMs exist in DataSources and match types.
|
|
* **Threading**: Checks `CheckDataSourceThreading` to ensure non-multithreaded DataSources are not shared across threads in the same state.
|
|
* **Ordering**: `CheckINOUTOrdering` verifies that for `INOUT` signals, the producing GAM appears before the consuming GAM in the thread's execution list.
|
|
* **Variables**: `CheckVariables` validates variable values against their defined CUE types (e.g. `uint`, regex). `CheckUnresolvedVariables` ensures all used variables are defined.
|
|
* **Unused**: Detects unused GAMs and Signals (suppressible via pragmas).
|
|
|
|
### 4. `internal/lsp`
|
|
|
|
Implements the Language Server Protocol.
|
|
|
|
* **Server (`server.go`)**: Handles JSON-RPC messages over stdio.
|
|
* **Incremental Sync**: Supports `textDocumentSync: 2`. `HandleDidChange` applies patches to the in-memory document buffers using `offsetAt` logic.
|
|
* **Features**:
|
|
* `HandleCompletion`: Context-aware suggestions (Schema fields, Signal references, Class names).
|
|
* `HandleHover`: Shows documentation, signal types, and usage analysis (e.g., "Used in GAMs: Controller (Input)").
|
|
* `HandleDefinition` / `HandleReferences`: specific lookup using the `index`.
|
|
|
|
### 5. `internal/builder`
|
|
|
|
Merges multiple MARTe files into a single output.
|
|
|
|
* **Logic**: It parses all input files, builds a temporary `ProjectTree`, and then reconstructs the source code.
|
|
* **Merging**: It interleaves fields and subnodes from different file fragments to produce a coherent single-file configuration, respecting the `#package` hierarchy.
|
|
|
|
### 6. `internal/schema`
|
|
|
|
Manages CUE schemas.
|
|
|
|
* **Loading**: Loads the embedded default schema (`marte.cue`) and merges it with any user-provided `.marte_schema.cue`.
|
|
* **Metadata**: Handles the `#meta` field in schemas to extract properties like `direction` and `multithreaded` support for the validator.
|
|
|
|
## Key Data Flows
|
|
|
|
### Reference Resolution
|
|
1. **Scan**: Files are parsed and added to the `ProjectTree`.
|
|
2. **Index**: `RebuildIndex` populates `NodeMap`.
|
|
3. **Resolve**: `ResolveReferences` iterates all recorded references (values) and calls `FindNode`.
|
|
4. **Link**: If found, `ref.Target` is set to the `ProjectNode`.
|
|
|
|
### Validation Lifecycle
|
|
1. `mdt check` or LSP `didChange` triggers validation.
|
|
2. A new `Validator` is created with the current `Tree`.
|
|
3. `ValidateProject` is called.
|
|
4. It walks the tree, runs checks, and populates `Diagnostics`.
|
|
5. Diagnostics are printed (CLI) or published via `textDocument/publishDiagnostics` (LSP).
|
|
|
|
### Threading Check Logic
|
|
1. Finds the `RealTimeApplication` node.
|
|
2. Iterates through `States` and `Threads`.
|
|
3. For each Thread, resolves the `Functions` (GAMs).
|
|
4. For each GAM, resolves connected `DataSources` via Input/Output signals.
|
|
5. Maps `DataSource -> Thread` within the context of a State.
|
|
6. If a DataSource is seen in >1 Thread, it checks the `#meta.multithreaded` property. If false (default), an error is raised.
|
|
|
|
### INOUT Ordering Logic
|
|
1. Iterates Threads.
|
|
2. Iterates GAMs in execution order.
|
|
3. Tracks `producedSignals` and `consumedSignals`.
|
|
4. For each GAM, checks Inputs. If Input is `INOUT` (and not multithreaded) and not in `producedSignals`, reports "Consumed before Produced" error.
|
|
5. Registers Outputs in `producedSignals`.
|
|
6. At end of thread, checks for signals that were produced but never consumed, reporting a warning.
|