2.5. RD-VBA Type System - Runtime

Note

This specification may be incomplete at this time.

If VBType is at the core of static semantics, then VBTypedValue is at the core of runtime semantics.


2.5.1 Runtime entities

A runtime entity is a simple abstraction that associates a VBType with a Symbol, which means every RD-VBA runtime entity is addressable with a Uri that is unique across the workspace.

2.5.1.1 Symbols

A symbol necessarily has a Uri and a Name, but also a ScopeKind and an (extended) LSP SymbolKind.

  • The Uri of a symbol is a semantic ID that uniquely identifies a symbol across an entire workspace; see RDCoreUriNamespaces. The Uri is assembled from the workspace root Uri and a relative Uri that may include a fragment. The content of the fragment is implementation-defined, but the relative Uri path should be that of the parent module or procedure scope.
  • The Name of a symbol defined in workspace source code must be a valid identifier name.
  • The Name of a static symbol corresponds to its identifier name if it has one.
  • Otherwise (e.g. operators), a static symbol should have a Name that clearly isn't a legal VBA name, to avoid any possible confusion.
Warning

While symbol Uri may look hierarchical (and they are!), they should never be used to rebuild a client-side tree-like structure.

The scope kind of a Symbol determines exactly how (and whether) it is allocated in memory, and can be one of the following:

Value Description
Unallocated A pseudo-scope for pseudo-symbols that aren't allocated in memory, like VBVoidValue.
Global StaticSymbol instances and symbols obtained from referenced libraries, mostly; lives in the globals heap.
Local Procedure level, scoped to the local ICallStackFrame.
Module Module level; lives in the workspace statics heap.
Instance Instance level; lives in the object heap.
External Allocated externally; lives out of process at a known address.

The symbol kind of a Symbol is as per specified in LSP 3.17. The values RD-VBA uses are as follows (see SymbolKindExt):

RD-VBA Value LSP Equivalence
Module SymbolKind.Module
Project SymbolKind.Namespace
Class SymbolKind.Class
Procedure SymbolKind.Method
Field SymbolKind.Field
Enum SymbolKind.Enum
Interface SymbolKind.Interface
Function SymbolKind.Function
Variable SymbolKind.Variable
Constant SymbolKind.Constant
StringLiteral SymbolKind.String
NumberLiteral SymbolKind.Number
BooleanLiteral SymbolKind.Boolean
Array SymbolKind.Array
Object SymbolKind.Object
Key SymbolKind.Key
Null SymbolKind.Null
EnumMember SymbolKind.EnumMember
UserDefinedType SymbolKind.Struct
Event SymbolKind.Event
Operator SymbolKind.Operator
Tip

LSP standard symbol kinds File, Constructor, and TypeParameter are not used in RD-VBA, and Namespace is being repurposed to a different meaning (there is no concept of a namespace in VBA). The Key symbol kind may end up being used for the token that follows the ! operator in dictionary access expressions, since it represents, in fact, a dictionary key.

RD-VBA additionally defines the following extension symbol kinds:

  • Ignored
  • Attribute
  • Directive
  • LineLabel
  • DateLiteral
  • VariantLiteral
  • TypeDescriptor

These extended symbol kinds may or may not be supported by a LSP client (editor), but can help supply more precise hover tips when they are.


2.5.2 VBTypedValue

RD-VBA defines MS-VBAL data values explicitly, using types inherited from a base VBTypedValue.

2.5.2.1 Intrinsic Type Values

The data values of the non-numeric intrinsic types are the following:

VBTypedValue VBType
VBArrayValue VBArrayType
VBFixedSizeArrayValue VBFixedSizeArrayType
VBResizableArrayValue VBResizableArrayType
VBResizableByteArrayValue VBResizableByteArrayType
VBBooleanValue VBBooleanType
VBDateValue VBDateType
VBEmptyValue VBEmptyType
VBErrorValue VBErrorType
VBLongPtrValue VBLongPtr_x64 or VBLongPtr_x86 depending on host environment
VBMissingValue VBMissingType
VBNullValue VBNullType
VBObjectValue VBObjectType
VBStringValue VBStringType
VBFixedStringValue VBFixedStringType
VBVariantValue VBVariantType

2.5.2.1.1 VBNumericTypedValue

All numeric data values inherit VBNumericTypedValue, which simplifies implementing semantics implicating "any numeric type" specifications. This base class implements INumericType, a non-generic base abstraction that ensures every numeric type minimally has a double managed representation.

Each numeric type of value minimally defines a typed representation of its MinValue, MaxValue, and Zero; other static values may be defined as required by runtime semantics.

Floating-point types also define a SignificantIntegerDigits that is used for correctly representing these values as VBStringValue in conversions and coercions to String:

Value Type Significant Digits
VBSingleValue 7
VBDoubleValue 15

A numeric data value can be one of the following:

Additionally, precompiler constants are interpreted as Integer values:

2.5.2.1.2 Array Values

An array declaration creates an array value of the appropriate array type in the scope of the declaration, depending on how its dimensions are declared:

  • An array declaration with dimension specifications creates a VBFixedSizeArrayValue;
  • An array declaration without dimension specifications creates a VBResizableArrayValue;
  • A resizable array declaration that specifies a Byte item type creates a VBResizableByteArrayValue.

The declaration provides the number and size of each dimension (up to 60). Array value dimensions are initialized with the default value of the declared item type of the array; the specialized array values exist to simplify pattern-matching in both static and runtime semantics.

👉 If no item type is specified in the declaration, then the declared item type of the array is Variant.

An array value is considered initialized when it has any number of dimensions defined; if no dimensions are defined, the array value is considered uninitialized.

  • The upper bound of an uninitialized array value is -1.
  • The lower bound of an uninitialized array value is dependent on the value of the Option Base directive, which is 0 by default but could be set to 1.

Each dimension of an array value encapsulates a managed array of the underlying managed type of the declared item type.

👉 Implementation may optimize certain specific array values for storage and performance. For example 2D arrays may be implemented in a way that optimizes their managed memory layout to avoid unnecessarily iterating individual dimensions for copy operations.

2.5.2.1.3 User-Defined Types (UDT) Values

An instance of a UDT is a VBUserDefinedTypeValue.

The data type of a UDT value is defined by the UDT declaration of its declared type.

👉 UDT values MUST be passed by reference (ByRef).

2.5.2.1.4 Object Values

An instance of a VBObjectType is always a VBObjectValue.

The underlying value of an object value is a unique addressable ID.

2.5.2.1.5 Variant Values

A VBVariantValue has an underlying managed value that is a managed struct type intended to eventually interop with actual COM (unmanaged) variant values.

The structure of this internal representation is defined as follows:

  • VBVariantValueType ValueType, a flag that identifies the variant value type (Empty, Integer, Dispatch, BString, etc.);
  • ScopeKind ValueAlloc, giving the host the allocation scope of the value;
  • long ValuePtr, a pointer to the value in the memory space specified by the ScopeKind.

A VBVariantValue is always allocated in the heap memory, in the same memory space as object values.

Note

The act of "unwrapping" a VBVariantValue value consists of looking up its allocated internal struct, retrieving its ValuePtr, then looking up that value in the appropriate memory space; this yields a scoped VBTypedValue that may or may not be an immediately usable intrinsic data type - it may be also be another VBVariantValue requiring a new unwrapping frame.


⏮️ RD-VBAL §2.4 Static Types | ⏮️ RD-VBAL §3.0 Syntax Tree