7.2 KiB
7.2 KiB
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:
- Parsing: Source code is parsed into an Abstract Syntax Tree (AST).
- Indexing: ASTs from multiple files are aggregated into a unified
ProjectTree. - Processing: The
ProjectTreeis 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,#let,//!pragmas, and//#docstrings. Supports standard identifiers and#-prefixed identifiers. Recognizes advanced number formats (hex0x, binary0b). - Parser (
parser.go): Recursive descent parser. Converts tokens into aConfigurationobject containing definitions, comments, and pragmas. Implements expression parsing with precedence. - AST (
ast.go): Defines the node types (ObjectNode,Field,Value,VariableDefinition,BinaryExpression, etc.). All nodes implement theNodeinterface 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. - ScanDirectory: Recursively walks the project directory to find all
.martefiles, adding them to the tree even if they contain partial syntax errors. - ProjectNode: Represents a logical node in the configuration. Since a node can be defined across multiple files (fragments),
ProjectNodeaggregates these fragments. It also stores locally defined variables and constants in itsVariablesmap. - NodeMap: A hash map index (
map[string][]*ProjectNode) forO(1)symbol lookups, optimizingFindNodeoperations. - Reference Resolution: The
ResolveReferencesmethod linksReferenceobjects to their targetProjectNodeorVariableDefinition. It usesResolveName(exported) which respects lexical scoping rules by searching the hierarchy upwards from the reference's container, usingFindNodefor deep searches within each scope.
3. internal/validator
Ensures configuration correctness.
- Validator: Iterates over the
ProjectTreeto 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. Performs project-wide consistency checks for implicit signals.
- Threading: Checks
CheckDataSourceThreadingto ensure non-multithreaded DataSources are not shared across threads in the same state. - Ordering:
CheckINOUTOrderingverifies that forINOUTsignals, the producing GAM appears before the consuming GAM in the thread's execution list. - Variables:
CheckVariablesvalidates variable values against their defined CUE types. Prevents external overrides of#letconstants.CheckUnresolvedVariablesensures 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. - Evaluation: Implements a lightweight expression evaluator to show evaluated values in Hover and completion snippets.
- Incremental Sync: Supports
textDocumentSync: 2.HandleDidChangeapplies patches to the in-memory document buffers usingoffsetAtlogic. - Features:
HandleCompletion: Context-aware suggestions (Macros, Schema fields, Signal references, Class names).HandleHover: Shows documentation (including docstrings for variables), evaluated signal types/dimensions, and usage analysis.HandleDefinition/HandleReferences: specific lookup using theindex.HandleRename: Project-wide renaming supporting objects, fields, and signals (including implicit ones).
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
#packagehierarchy. - Evaluation: Evaluates all expressions and variable references into concrete MARTe values in the final output. Prevents overrides of
#letconstants.
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
#metafield in schemas to extract properties likedirectionandmultithreadedsupport for the validator.
Key Data Flows
Reference Resolution
- Scan: Files are parsed and added to the
ProjectTree. - Index:
RebuildIndexpopulatesNodeMap. - Resolve:
ResolveReferencesiterates all recorded references (values) and callsFindNode. - Link: If found,
ref.Targetis set to theProjectNode.
Validation Lifecycle
mdt checkor LSPdidChangetriggers validation.- A new
Validatoris created with the currentTree. ValidateProjectis called.- It walks the tree, runs checks, and populates
Diagnostics. - Diagnostics are printed (CLI) or published via
textDocument/publishDiagnostics(LSP).
Threading Check Logic
- Iterates all
RealTimeApplicationnodes found in the project. - For each App:
- Finds
StatesandThreads. - For each Thread, resolves the
Functions(GAMs). - For each GAM, resolves connected
DataSourcesvia Input/Output signals. - Maps
DataSource -> Threadwithin the context of a State. - If a DataSource is seen in >1 Thread, it checks the
#meta.multithreadedproperty. If false (default), an error is raised.
- Finds
INOUT Ordering Logic
- Iterates Threads.
- Iterates GAMs in execution order.
- Tracks
producedSignalsandconsumedSignals. - For each GAM, checks Inputs. If Input is
INOUT(and not multithreaded) and not inproducedSignals, reports "Consumed before Produced" error. - Registers Outputs in
producedSignals. - At end of thread, checks for signals that were produced but never consumed, reporting a warning.