| name | mps-aspect-dataflow |
| description | Use when defining or debugging MPS dataflow builders for a concept — control/data flow declarations that drive reachability analysis and variable-use checking. Covers DataFlowBuilderDeclaration, BuilderBlock, emit instructions (code for, jump, ifjump, label, read, write, ret, mayBeUnreachable), positions (AfterPosition, BeforePosition, LabelPosition), the jetbrains.mps.lang.dataFlow language, the NodeParameter implicit, BL+smodel usage inside builder bodies, and IBuilderMode for advanced analyses such as nullable/non-null tracking. |
| type | reference |
MPS Dataflow Aspect
The dataflow aspect (jetbrains.mps.lang.dataFlow, l:7fa12e9c-b949-4976-b4fa-19accbc320b4) lets a language describe how control and data flow through nodes of a concept. MPS uses that information for reachability analysis, uninitialised-variable checks, and (via IBuilderMode) richer flow analyses such as nullable tracking.
Mental Model
Each DataFlowBuilderDeclaration answers: given a node of concept X, in what order might execution visit its children, and which variables are read or written?
The builder body is a BL StatementList (inside a BuilderBlock). You use normal BL control flow (if, foreach, local variables) to compute which emit instructions to output at runtime. The node implicit parameter (concept NodeParameter) is always in scope — its type is the concept referenced by conceptDeclaration, giving smodel-typed access to children and references.
The MPS dataflow engine builds a control-flow graph from the emitted instructions, then runs analyses (unreachable code, uninitialised variable reads) on that graph. The engine only traces the paths you declare; if no builder exists for a concept, MPS falls back to delegating all children in declaration order.
Critical Directives
code for is delegation, not a call. Never use jump for child delegation. Use EmitCodeForStatement to inline a child's own builder at this point.
ifjump semantics: the jump is taken when the condition is FALSE. Use it after code for node.condition to model branching.
- Labels are node references, not string lookups.
EmitLabelStatement.name is display-only; jumps reference the label node via LabelPosition.label. Two labels with the same string are still distinct targets.
- Always null-guard
0..1 children with BL if (node.child != null) before emitting code for node.child.
write node vs write node.link: use write node (just NodeParameter as the variable expression) when the concept node is the variable being declared. Use write node.link (via SLinkAccess) when the node merely references the variable being written.
- Leaf concepts need no builder. The engine treats unbuilt concepts as no-ops, or for ordinary parents delegates to children in declaration order.
- Do not hand-edit serialized
.mps dataflow files. Use MPS MCP node tools.
Common-Path Workflow
- Add
jetbrains.mps.lang.dataFlow (and transitively jetbrains.mps.baseLanguage) as used languages on the dataflow model. Model is typically named <language>.dataFlow.
- Create a
DataFlowBuilderDeclaration root node; set conceptDeclaration to the concept being described; give it a name.
- Add a
BuilderBlock child with a body (BL StatementList).
- Emit instructions: delegate to children with
EmitCodeForStatement; model branches with EmitIfJumpStatement + EmitLabelStatement; record variable use with EmitReadStatement / EmitWriteStatement; mark exits with EmitRetStatement.
- For loops, use
BeforePosition/AfterPosition to encode loop-back/exit edges; wrap potentially-unreachable instructions in EmitMayBeUnreachable.
- Validate with
mps_mcp_check_root_node_problems. For tricky cases, inspect an existing baseLanguage builder via mps_mcp_print_node_json with deep: true.
Related Skills
mps-model-manipulation — BL + smodel code inside builder bodies (DotExpression, SLinkAccess, NodeParameter, behavior method calls).
mps-aspect-behavior — for behavior methods called from builders to compute target nodes (e.g. getLoopOrSwitch, getReturnJumpTarget).
mps-aspect-typesystem — when the dataflow you emit must agree with type checks.
mps-node-editing — generic JSON-blueprint node creation/replacement workflow.
Reference Index
- Concept catalog — open when you need exact concept names, properties, children, cardinalities, or abstract bases for
DataFlowBuilderDeclaration, BuilderBlock, every emit statement, every position type, and the abstract bases. See references/concept-catalog.md.
- Verified JSON patterns — open when constructing or editing a builder as JSON for
mps_mcp_* tools. Includes variable read, single-child delegation, return-with-finally, if/elsif/else, while loop, assignment, variable declaration, break to ancestor, and a custom inverted-condition statement. See references/json-patterns.md.
- Rules and pitfalls — open when a builder validates but the engine reports surprising reachability or variable-use results, when choosing between
AfterPosition and LabelPosition, or before using modes/IBuilderMode. See references/rules-and-pitfalls.md.
- Language setup and engine invocation — open when wiring a new dataflow model, or when debugging "why is my builder not being called". See references/setup-and-engine.md.
- BaseLanguage builder index — open when you want to study a known-good builder for
IfStatement, WhileStatement, ReturnStatement, BreakStatement, VariableDeclaration, TryFinallyStatement, SwitchStatement, ForStatement, etc. Lists builder names and persistent nodeReferences in r:00000000-0000-4000-0000-011c895902c2. See references/baselanguage-builder-index.md.
- Sample language reference — open when looking for a minimal complete builder for a custom language (
UnlessStatement_DataFlow). See references/sample-language-reference.md.