Table of Contents

5.4.2.3 For Statement

Note

This section describes the implementation of MS-VBAL §5.4.2.3 For Statement.

Syntax

AST node Instruction kind(s) Notes
ForStatementNode ForOpener The For opener. Its End is the offset right past the Next closer.
— (synthesized) ForNext The Next closer; Node is null. Its Target is the body's first instruction; its Matching is the offset of its ForOpener.

Next has no AST node of its own: the whole For...Next construct is one ForStatementNode with a Body (RD-VBAL §3.4.1 Block Statements). The instruction fields are described in RD-VBAL §3.5.2 Instruction.

Static Semantics

Reassigning a For loop counter inside the loop body is legal VBA.

Performance-related diagnostics should be issued when a VBCollectionType is accessed by index within the body of a For...Next loop (RD-VBAL §2.4.2 Non-intrinsic Types).

Runtime Semantics

A For loop needs per-activation state. Its opener stores a ForLoopState on the activation, and its closer reads it back.

ForOpener

  1. Evaluate start-value, end-value and step-increment once each, in that order. A missing step-clause defaults to the integer value 1; that default is never itself evaluated as a source expression.
  2. Let-assign the counter to start-value, through the same Let-assignment machinery a Let statement uses (RD-VBAL §5.4.3.8 Let Statement).
  3. Store end and step, together with the counter symbol and the counter's own expression node, as a ForLoopState, for every later step to reuse.
  4. Check steps 1 and 2 of the MS-VBAL §5.4.2.3 algorithm immediately: "if step is zero or positive and the counter already exceeds end", and "if step is negative and the counter already falls short".
  5. When the counter is already out of range, branch to Instruction.End, right past the loop. Otherwise, fall through into the body.

ForNext

  1. Read the stored ForLoopState back via Instruction.Matching.
  2. Read the counter's current value. The body may have reassigned the counter directly.
  3. Add step to it through the addition operator (MS-VBAL §5.6.9.3 Arithmetic Operators; RD-VBAL §5.6.9.3 Arithmetic Operators). The addition is an overflow-checked operation, not an unchecked CLR addition.
  4. Let-assign the sum back to the counter.
  5. Re-test the counter in the same way as ForOpener: branch back to the body (Instruction.Target) while the counter is still in range, and fall through past the loop otherwise.

Range Test

The range checks of ForOpener and ForNext use the relational operators > and < (MS-VBAL §5.6.9.5 Relational Operators; RD-VBAL §5.6.9.5 Relational Operators), not a raw numeric comparison. The counter's declared type (Currency, Decimal, Date as Double, …) has comparison semantics specified by MS-VBAL, which a CLR > or < comparison does not implement.

Only the sign of step is read directly from its numeric value. The MS-VBAL §5.4.2.3 algorithm treats the step's sign as a classification, not as a VBA-visible comparison expression.

Step Out of range when
Zero or positive The counter exceeds end (counter > end).
Negative The counter falls short of end (counter < end).

Errors

A label is scoped to the whole procedure, so a GoTo can land directly on the Next closer (RD-VBAL §5.4.1.1 Statement Labels). When ForNext finds no stored state for its Matching offset, its ForOpener never ran in this activation.

Condition Run-time error
ForNext finds no stored ForLoopState for its Matching offset (a GoTo landed directly on the closer). 92 — For loop not initialized
The addition of step to the counter overflows. 6 — Overflow

Run-time error 92 is VBRuntimeErrorId.ForLoopNotInitialized (RD-VBAL §2.6.3 Runtime Errors).

Implementation

  • ProcedureExecutor dispatches ForOpener and ForNext.
  • The Next closer increments and tests the counter, so lowering synthesizes an instruction (Node = null) to hold that work (RD-VBAL §3.5.3 Lowering Block Statements).
  • ForOpener stores end, step, the counter symbol and the counter's own expression node as a RDCore.SDK.Runtime.Shared.ForLoopState. The state is read back via ICallStackFrame.TryGetForLoopState, and written via CallStackFrame.SetForLoopState.
  • A For loop's state holds more than a single value: counter symbol, counter expression, end and step. It therefore has its own SDK type, ForLoopState, rather than the single block-state value that With and Select Case use (RD-VBAL §3.5.4 Execution).
  • ForNext uses the same Instruction.Matching field that a Case header uses for its back-reference to its Select (RD-VBAL §5.4.2.10 Select Case Statement).
  • The range test uses RDCore.Runtime.Semantics.Operators.Relational.BinaryGtRelationalOperatorRuntimeSemantics and BinaryLtRelationalOperatorRuntimeSemantics. The increment uses RDCore.Runtime.Semantics.Operators.Arithmetic.BinaryAdditionOperatorRuntimeSemantics.
  • Every location-bearing node passed to the loop's operator calls is a node the loop already has, never a synthesized one: the counter's own expression or, for the first assignment, the loop's start expression. The same rule applies to Case clause matching, which relies on the operator node parameter being typed ExpressionNode (RD-VBAL §5.4.2.10 Select Case Statement).
  • The verbose message of ForLoopNotInitialized, when a Next closer runs without its opener, is the resx entry VBForLoopNotInitialized_Verbose, provided in both languages.

⏮️ RD-VBAL §5.4.2.2 While Statement | ⏭️ RD-VBAL §5.4.2.4 For Each Statement