Formulas

Parses setup expressions, validates token sequences, and exposes Excel-compatible formulas for linelist and analysis contexts. The class tokenises incoming pseudo-formulas, resolves variable references through an LLdictionary, and delegates to CaseWhen, ChoiceFormula, and ValueOfFormula for custom function conversion. Grouped formulas are detected and rewritten as aggregated Excel expressions.

Depends on: BetterArray, Checking, LLdictionary, LLVariables, LLSheets, CaseWhen, ChoiceFormula, ValueOfFormula

Version: 1.0 (2026-02-09)

Factory

create #

Instantiate a Formulas helper ready to parse the provided setup expression

Signature:

Public Function Create(ByVal dict As ILLdictionary, _
                       ByVal formData As IFormulaData, _
                       ByVal setupForm As String) As IFormulas

Provides the single entry point to instantiate the parser and initialise core state. Validates that the required dictionary and formula data objects are present, then stores them in a new instance alongside the setup expression. No eager parsing occurs; the formula is parsed lazily on first access to Valid, Varlists, or any parsed formula property.

Parameters:

  • dict: ILLdictionary. Variable metadata provider.
  • formData: IFormulaData. Catalogue of approved Excel functions and separators.
  • setupForm: String. Pseudo-formula to parse and validate.

Returns: IFormulas. Initialised instance.

Throws:

  • ProjectError.ObjectNotInitialized When dict is Nothing.
  • ProjectError.ObjectNotInitialized When formData is Nothing.

PublicAccessors

has-setup-variables #

Determine if the parsed formula contains literal values

Signature:

Public Property Get HasSetupVariables() As Boolean

Returns True when numeric or text literals were encountered during tokenisation. The flag is set during EvaluateFormula.

Returns: Boolean. True when literals are present.


is-grouped #

Indicate whether the parsed formula targets grouped evaluation

Signature:

Public Property Get IsGrouped() As String

Forces evaluation in the "simple" context, then inspects the captured group metadata. Returns "Yes" when grouped logic applies, "No" otherwise.

Returns: String. "Yes" for grouped formulas, "No" otherwise.


reason #

Retrieve the last validation message associated with the given context

Signature:

Public Property Get Reason(Optional ByVal formulaType As String = "analysis") As String

Returns a human-readable explanation of the current validity state. When the formula is valid the default success message is returned; otherwise the recorded invalidation reason is returned.

Parameters:

  • formulaType: Optional String. Context (analysis/simple).

Returns: String. Explanation of the current validity state.


valid #

Check whether the formula is valid for the supplied context

Signature:

Public Property Get Valid(Optional ByVal formulaType As String = "analysis") As Boolean

Triggers a lazy evaluation for the requested context, then returns the cached validity flag.

Parameters:

  • formulaType: Optional String. Context (analysis/simple).

Returns: Boolean. True when parsing succeeded.


varlists #

Provide a clone of the variables detected in the expression

Signature:

Public Property Get Varlists(Optional ByVal formulaType As String = "analysis") As BetterArray

Returns a BetterArray containing the variable names encountered during tokenisation. The result is always a clone so callers cannot mutate the internal cache.

Parameters:

  • formulaType: Optional String. Context (analysis/simple).

Returns: BetterArray. Variable names.


parsed-linelist-formula #

Build the Excel expression for linelist worksheets

Signature:

Public Property Get ParsedLinelistFormula(Optional ByVal useTableName As Boolean = False, _
                                          Optional ByVal tablePrefix As String = vbNullString) As String

Iterates through the cached token list and replaces variable tokens with worksheet addresses or structured references depending on the useTableName flag. Grouped formulas are delegated to BuildGroupedFormula. Custom tokens MEAN and N are mapped to their Excel equivalents (AVERAGE, COUNT).

Parameters:

  • useTableName: Optional Boolean. Toggles structured references.
  • tablePrefix: Optional String. Prefixed to structured references.

Returns: String. Excel formula referencing linelist variables.


parsed-analysis-formula #

Build the Excel expression for aggregated analysis results

Signature:

Public Property Get ParsedAnalysisFormula(ByVal formCond As IFormulaCondition, _
                                          Optional ByVal tablePrefix As String = vbNullString, _
                                          Optional ByVal Connector As String = "*") As String

Iterates through the cached token list and replaces variable tokens with conditional aggregation fragments supplied by formCond. Custom formula tokens are delegated to ParsedCustomFormula. Grouped formulas are delegated to BuildGroupedFormula.

Parameters:

  • formCond: IFormulaCondition. Provides conditional aggregation logic.
  • tablePrefix: Optional String. Prefix for table references.
  • Connector: Optional String. Connector between conditional fragments.

Returns: String. Excel expression ready for analysis worksheets.


Checkings

has-checkings #

Indicate whether any diagnostic entries were recorded

Signature:

Private Property Get HasCheckings() As Boolean

Returns the module-level flag set by LogCheck.

Returns: Boolean. True when checkings exist.


checking-values #

Expose the collected checking entries if available

Signature:

Private Property Get CheckingValues() As IChecking

Returns the internal IChecking store when at least one entry has been recorded. Returns Nothing otherwise.

Returns: IChecking. Logged diagnostics.


Internal members (not exported)

PublicAccessors

self #

Return the interface pointer for the current instance

Signature:

Public Property Get Self() As IFormulas

Exposes configured dependencies, cached evaluation results, and parsed Excel expressions. Returns the current instance cast to its interface. Used internally by the factory method to return an IFormulas reference.

Returns: IFormulas. Reference to the current object.


dictionary #

Retrieve the underlying dictionary used during parsing

Signature:

Public Property Get Dictionary() As ILLdictionary

Returns the ILLdictionary previously supplied during Create or Initialise. Used by downstream helpers to resolve variable metadata.

Returns: ILLdictionary. Dictionary backing metadata lookups.


dictionary-set #

Assign a new dictionary and reset dependent caches

Signature:

Public Property Set Dictionary(ByVal dict As ILLdictionary)

Replaces the current dictionary and invalidates all lazily resolved dependencies so subsequent property accesses trigger a fresh parse.

Parameters:

Throws:


data #

Retrieve the formula configuration catalogue

Signature:

Public Property Get Data() As IFormulaData

Returns the IFormulaData describing available Excel tokens, operators, and special characters used during tokenisation.

Returns: IFormulaData. Configuration catalogue.


data-set #

Update the formula configuration catalogue and invalidate caches

Signature:

Public Property Set Data(ByVal formData As IFormulaData)

Replaces the current formula data and invalidates all cached parsing results so subsequent accesses trigger a fresh evaluation.

Parameters:

Throws:


setup-formula #

Retrieve the original setup pseudo-formula

Signature:

Public Property Get SetupFormula() As String

Returns the raw expression as captured from the setup sheet during Create or the last assignment.

Returns: String. Raw expression.


setup-formula-set #

Store the setup pseudo-formula and reset computed caches

Signature:

Public Property Let SetupFormula(ByVal setupForm As String)

Replaces the stored expression and invalidates all cached parsing results so subsequent accesses trigger a fresh evaluation.

Parameters:


PrivateHelpers

initialise #

Store incoming dependencies and prepare caches

Signature:

Public Sub Initialise(ByVal dict As ILLdictionary, _
                       ByVal formData As IFormulaData, _
                       ByVal setupForm As String)

Internal utilities for dependency management, cache invalidation, and token resolution. Assigns the dictionary, formula data, and setup expression, then invalidates all caches and registers the default custom formulas recognised during analysis parsing.

Parameters:


reset-dependencies #

Clear lazily instantiated dependencies and invalidate token caches

Signature:

Private Sub ResetDependencies()

Sets variables and sheets providers to Nothing and re-initialises the custom formulas list when absent. Triggers InvalidateCaches to ensure downstream properties reparse.


register-default-custom-formulas #

Seed built-in custom formulas recognised by analysis parsing

Signature:

Private Sub RegisterDefaultCustomFormulas()

Replaces the custom formulas list and registers MEAN, N, and N() as known tokens that receive special handling during analysis formula construction.


register-custom-formula #

Add a custom formula identifier if not already registered

Signature:

Private Sub RegisterCustomFormula(ByVal customFormula As String)

Initialises the custom formulas list when absent, then pushes the token if it is not already present.

Parameters:


invalidate-caches #

Reset cached parsing results and computed flags

Signature:

Private Sub InvalidateCaches()

Clears the token list, variable list, validity flags, and group context so the next access triggers a full reparse from the stored setup expression.


reset-group-context #

Clear any grouped-formula metadata captured during previous evaluations

Signature:

Private Sub ResetGroupContext()

Resets all fields of the TGroupContext UDT to their default values.


variables #

Lazily instantiate the LLVariables helper from the dictionary

Signature:

Private Function Variables() As ILLVariables

Creates the LLVariables wrapper on first access and caches it for subsequent calls.

Returns: ILLVariables. Bound to the current dictionary.


sheet-provider #

Lazily instantiate the LLSheets helper for address resolution

Signature:

Private Function SheetProvider() As ILLSheets

Creates the LLSheets wrapper on first access and caches it for subsequent calls.

Returns: ILLSheets. Bound to the current dictionary.


ensure-evaluation #

Guarantee that a parsing/validation run exists for the requested context

Signature:

Private Function EnsureEvaluation(ByVal formulaType As String) As Boolean

Checks whether the cached evaluation matches the requested context. When a mismatch is detected or no evaluation has been performed, a full EvaluateFormula pass is triggered.

Parameters:

Returns: Boolean. True when the cached evaluation is valid.


evaluate-formula #

Parse the setup expression, populate tokens, and capture validation results

Signature:

Private Sub EvaluateFormula(ByVal formulaType As String)

Converts the stored setup formula through custom function handlers, then tokenises the result while validating parentheses and literals. Short-circuits for single-variable or single-custom-function expressions. Delegates grouped formula detection to GroupContexExtractionSucceed.

Parameters:


GroupFormula

group-context-extraction #

Analyse the tokenised expression and record grouped metadata when relevant

Signature:

Private Function GroupContexExtractionSucceed(ByVal tokens As BetterArray, _
                                       ByVal variableTokens As BetterArray, _
                                       ByVal vars As ILLVariables, _
                                       ByVal dataSource As IFormulaData) As Boolean

Detects grouped formulas, validates arguments, and prepares metadata for downstream builders. Inspects the root function name to determine whether the formula targets grouped evaluation. When grouped, validates that exactly three variable arguments are present and that the first and third variables belong to the same table. Records the captured metadata in the TGroupContext UDT for BuildGroupedFormula.

Parameters:

Returns: Boolean. True when grouped context is captured or not required.


root-function-name #

Retrieve the entry token corresponding to the root function

Signature:

Private Function RootFunctionName(ByVal tokens As BetterArray) As String

Returns the first token from the tokenised expression, which is expected to be the function name when the formula is function-based.

Parameters:

Returns: String. Root token or empty string when unavailable.


is-generic-group-function #

Determine whether a function uses the GROUP prefix for grouped evaluation

Signature:

Private Function IsGenericGroupFunction(ByVal functionName As String) As Boolean

Returns True when the token starts with "GROUP" (case-insensitive).

Parameters:

Returns: Boolean. True when the token starts with "GROUP".


extract-generic-aggregator #

Parse the aggregator portion from a GROUP-prefixed function

Signature:

Private Function ExtractGenericAggregator(ByVal functionName As String) As String

Splits the function name at the underscore separator and returns the trailing portion as the aggregator token. When no underscore is present, strips the "GROUP" prefix directly.

Parameters:

Returns: String. Aggregator token to apply when building the Excel formula.


build-grouped-formula #

Construct the grouped Excel expression using captured metadata

Signature:

Private Function BuildGroupedFormula(ByVal useTableName As Boolean, _
                                     ByVal tablePrefix As String) As String

Uses the TGroupContext UDT to resolve variable ranges and emit the appropriate aggregation expression. Native *IFS functions produce direct SUMIFS/COUNTIFS calls; non-native functions wrap the result in an IF-based array formula.

Parameters:

Returns: String. Grouped Excel formula ready for consumption.


grouped-data-range #

Resolve the appropriate range reference for a grouped variable

Signature:

Private Function GroupedDataRange(ByVal variableName As String, _
                                  ByVal useTableName As Boolean, _
                                  ByVal tablePrefix As String, _
                                  ByVal sheets As ILLSheets) As String

Emits either a structured table reference or a sheet-level address depending on the useTableName flag.

Parameters:

Returns: String. Excel reference targeting the grouped variable.


Tokenisation

tokenise-formula #

Break the converted formula into tokens while validating parentheses and literals

Signature:

Private Function TokeniseFormula(ByVal formula As String, _
                                 ByVal formulaType As String, _
                                 ByVal tokens As BetterArray, _
                                 ByVal variableTokens As BetterArray, _
                                 ByRef HasSetupVariables As Boolean, _
                                 ByRef failureReason As String) As Boolean

Breaks expressions into tokens, validates each chunk, and handles custom formula expansion. Walks the formula character by character, splitting on special characters defined by the IFormulaData configuration. Tracks parenthesis depth and quotation state. Each extracted chunk is validated through AppendToken.

Parameters:

Returns: Boolean. True when parsing succeeds.


append-token #

Validate and append the provided chunk to the tokens collection

Signature:

Private Function AppendToken(ByVal chunk As String, _
                             ByRef formulaType As String, _
                             ByRef tokens As BetterArray, _
                             ByRef variableTokens As BetterArray, _
                             ByRef vars As ILLVariables, _
                             ByRef dataSource As IFormulaData, _
                             ByRef HasSetupVariables As Boolean, _
                             ByRef failureReason As String) As Boolean

Classifies the chunk as a grouped function, known variable, boolean literal, registered Excel formula, custom formula, numeric literal, or quoted string. Unknown chunks cause a validation failure.

Parameters:

Returns: Boolean. True when the chunk is accepted.


is-quoted-string #

Determine whether the supplied value is wrapped in quotes

Signature:

Private Function IsQuotedString(ByVal value As String) As Boolean

Returns True when the string starts and ends with a double-quote character and has a length of at least two.

Parameters:

Returns: Boolean. True when the string is quoted.


clean-string #

Normalise the incoming token by removing control characters and duplicate spaces

Signature:

Private Function CleanString(ByVal value As String) As String

Replaces non-breaking spaces, strips control characters via Application.WorksheetFunction.Clean, and trims whitespace.

Parameters:

Returns: String. Trimmed and cleaned representation.


parsed-custom-formula #

Delegate parsing to custom functions when present in analysis context

Signature:

Private Function ParsedCustomFormula(ByVal customFunction As String, _
                                     ByVal formCond As IFormulaCondition, _
                                     Optional ByVal TableName As String = vbNullString, _
                                     Optional ByVal tablePrefix As String = vbNullString) As String

Handles MEAN (mapped to AVERAGE), N/N() (mapped to COUNTIFS), and passes through unknown custom identifiers unchanged. The COUNTIFS expansion builds criteria pairs from the IFormulaCondition.

Parameters:

Returns: String. Excel fragment produced by the custom handler.


remove-empty-invocation-tokens #

Strip trailing empty parentheses after replacing custom formulas

Signature:

Private Sub RemoveEmptyInvocationTokens(ByRef tokens As BetterArray, _
                                        ByVal functionIndex As Long)

When a custom formula token is replaced inline, the following "(" and ")" tokens may become redundant. This helper removes them when they immediately follow the replaced token.

Parameters:


clear-count-if #

Remove equality fragments from COUNTIF-style conditions

Signature:

Private Function ClearCountIf(ByVal value As String) As String

Sanitises predicate fragments by stripping equality operators and normalising less-than and greater-than comparisons for COUNTIFS compatibility.

Parameters:

Returns: String. Sanitised predicate suitable for COUNTIFS.


quoted #

Wrap a value in Excel double quotes

Signature:

Private Function Quoted(ByVal value As String) As String

Prepends and appends a double-quote character to the supplied value.

Parameters:

Returns: String. Quoted representation.


converted-setup-formula #

Convert higher-level setup directives into plain Excel expressions

Signature:

Private Function ConvertedSetupFormula() As String

Detects CASE_WHEN, CHOICE_FORMULA, and VALUE_OF prefixes in the stored setup expression and delegates to the corresponding parser class. Returns the original expression when no prefix matches.

Returns: String. Converted formula ready for tokenising.


set-invalid #

Record an invalidation reason and log the associated checking entry

Signature:

Private Sub SetInvalid(ByVal message As String, Optional ByVal scope As Byte = checkingError)

Stores the failure message, marks the formula as invalid, and logs the message through the internal Checking store.

Parameters:


Checkings

log-check #

Record a diagnostic entry within the internal checking store

Signature:

Private Sub LogCheck(ByVal label As String, _
                     Optional ByVal scope As Byte = checkingNote)

Aggregates informational and error traces emitted during parsing. Lazily creates the Checking instance on first use, then appends the labelled entry with the given severity scope.

Parameters:


ErrorHandling

throw-error #

Raise a VBA error with the class signature

Signature:

Private Sub ThrowError(ByVal errNumb As Long, ByVal errorMessage As String)

Centralises the error raising pattern for consistent ProjectError usage. Wrapper around Err.Raise that standardises the source to the class constant CLASSNAME for consistent stack traces.

Parameters:

Throws:


Interface

IFormulas_Varlists #

Signature:

Private Property Get IFormulas_Varlists(Optional ByVal formulaType As String = "analysis") As BetterArray

Delegated members satisfying the IFormulas contract.


formula-table-list #

Signature:

Private Property Get IFormulas_FormulaTableList() As BetterArray

Used in (11 file(s))