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
Uriof a symbol is a semantic ID that uniquely identifies a symbol across an entire workspace; see RDCoreUriNamespaces. TheUriis assembled from the workspace rootUriand a relativeUrithat may include a fragment. The content of the fragment is implementation-defined, but the relativeUripath should be that of the parent module or procedure scope. - The
Nameof a symbol defined in workspace source code must be a valid identifier name. - The
Nameof a static symbol corresponds to its identifier name if it has one. - Otherwise (e.g. operators), a static symbol should have a
Namethat 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:
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:
- VBByteValue
- VBIntegerValue
- VBLongValue
- VBLongLongValue
- VBSingleValue
- VBDoubleValue
- VBCurrencyValue
- VBDecimalValue
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
Byteitem type creates aVBResizableByteArrayValue.
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 Basedirective, which is0by default but could be set to1.
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 theScopeKind.
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.