Simple Things Pt.1: Values

Sometimes, simple things are just very effective abstractions that are very good at hiding the giant rabbit hole underneath.

Like an innocent little literal value for example:

Debug.Print 42

This 42 is just that, a plain integer value – isn’t it?

One could reasonably set out and write a parser that produces an abstract syntax tree (AST) here that would include some LiteralExpression node, that necessarily evaluates to 42.

But the node itself isn’t the value. In fact – perhaps surprisingly – it doesn’t even know what or where that value is. It knows where it is defined in the source code, but that’s not what I meant with where that value is.

So where does the 42 actually live? Where is it stored? And why does it even matter?

The answer is… not in the expression node: the node evaluates to a value, but is not that value.

For starters, the specifications dictate that 42 must be an Integer literal. Not a Long, not a Double – although a different value might yield either semantic data type. The grammar however, only distinguishes integer numbers from floating-point numbers: it’s token semantics specified in MS-VBAL that ultimately determines the semantic data type.

It also states very plainly that an integer value should be a 16-bit signed integer, and also defines such internal representations for each intrinsic data type: clearly we can’t just make everything a double and run with it, or we’ll almost certainly break something downstream.

Why is that?

More Than Values

If we stop and think about the type system in VBA, we quickly realize that we don’t just need values for literals, and that many other things evaluate to, or represent a value – like functions, parameters, and if we squint a little even a class instance (object) could be coerced into a value.

And that’s a problem if we model a semantic type system that embeds values directly, because then the assignment of a ByRef parameter can only behave as a value, not as a reference. Besides we also want to be able to represent values that exist and must be usable but aren’t defined anywhere in source code.

This is why RDCore introduced binding handles as an indirection layer between a VBTypedValue and the underlying binary value it represents.

Back to the literal 42 integer value: we have a value binding that yields the 42, and so the VBIntegerValue type knows it has a binding that can get the value, and it doesn’t need to know where that value actually is.

An integer parameter passed by reference would also be a VBIntegerValue, but its binding would be a reference binding rather than a value one, likely pointing to a symbol defined somewhere in the call stack: changing the value of this reference binding would necessarily affect the value everywhere it’s referenced, because its runtime value is associated to its declaration symbol within the program memory.

The RDCore semantic type system explicitly differentiates types and values, such that a VBIntegerValue represents a value of type VBInteger. This is slightly different from other models, where a value might be an instance of a given data type. Beyond that, a type might also be described by a value that represents a data type: VBTypeDescValue. This special meta-value is useful in a number of scenarios (notably TypeOf operators), and enables reflection-like capabilities and semantics that may or may not end up exposed at the language level, possibly through platform extensions.

This differentiation is necessary to correctly model arrays, UDT, and custom class types – that’s a whole other rabbit hole that deserves its own post, but for now this is what matters:

VBInteger:VBType
👇describes
VBIntegerValue:VBTypedValue
👇bound to
42:System.Int16

If an instance of a given VBType represented a value of that type, then we would need to generate the complex types on the fly, and that would be way more complicated than things need to be: we don’t need dynamic types when everything is statically defined – what we need is just a model that makes it work, and conceptually separating data types from typed values does exactly that.

Runtime Values

The RDCore SDK defines an entire type system that supports everything (and more!) VBA can do, using .net types to represent all underlying runtime values.

While several data types work pretty well as-is, others like Boolean, Currency, and Decimal don’t really map 1:1 and need a special type that correctly represents the value. For example an Integer value easily maps to a .net Int16, but mapping a .net Boolean to a VBA Boolean would introduce bit alignment issues (notably in UDT types), because it’s a 16-bit integer under the hood but a .net Boolean is only a single byte! Decimal is another, perhaps less consequential since it’s not declarable, but MS-VBAL specifies it as fitted across 14 bytes (3x Int32 +Int16), yet the corresponding .net type is 16 bytes wide (4x Int32); Variant is another data type that needs its own interop value, a 24-byte struct that can hold anything, value or reference.

The Debug.Print 42 instruction parses the 42 as a literal expression that evaluates to a VBIntegerValue that has a ValueBindingHandle that holds the managed Int16 value 42.

If it were Debug.Print “Hello, world!”, we would’ve had a VBStringValue with a ReferenceBindingHandle instead, holding a reference to a managed string holding the literal value. Concretely, this means a reference binding is really just a wrapper around a managed object; this makes it possible to box value types and use them as references in ByRef scenarios.

But it’s just a literal!

And it is. But to be useful, the semantic model must be able to tell a Variant from a Long from a Double, and a unified semantic type system that doesn’t care whether a value came from source code or is the result of an operation, and isn’t concerned about the internal memory representation of that value: that’s what the semantic model abstraction level does, and that’s where the AST belongs.

Constantly wrapping and unwrapping runtime values into semantic ones would be terribly inefficient, for run-time though. If it doesn’t sound so bad, try looping a million times into an array and adding one to each element, and the overhead should become obvious: it’ll interpret nodes all right, but something else must be able to actually run things without caring for the semantic layer.


Progress Status

As of this writing, the parser produces an AST containing all the expected nodes in an initial declaration pass: module directives and attributes, as well as everything in the declarations section, and procedure member signatures (including parameters) – but no executable statement nodes yet, although many of these have already been defined.

These nodes will be introduced in the AST alongside their respective evaluation semantics in an evaluation engine that’ll become the interpreter that will eventually evaluate nodes in break mode, while a separate execution engine will operate at a lower level, working directly with the underlying runtime types.

This will all be tested and benchmarked (and adjusted as needed) in due time, of course.

For now the development focus is turning to the LSP client/server SDK, which is what underpins cross-process communications across the entire RDCore platform. Once that’s in place, the language server can start implementing LSP handlers that an IDE can use, for everything a declaration pass already unlocks – but that work will be ticketed and not completed right away (not by me anyway), because then focus will have to shift to the semantic evaluation engine and the statement nodes, because GoTo and GoSub/Return, not to mention error states, are an interesting twist on what would otherwise be a rather straightforward AST traversal.

RDCore™

(English version follows)

Il y a certaines choses qui doivent tout simplement être accomplies.

Parfois, c’est de graver avec vos propres mains dans un morceau de pierre le logo de votre compagnie nouvellement enregistrée.

Je peux le toucher (si lisse!) – il est là, il est réel. Je l’ai fait moi-même et je suis très fier du résultat!

D’autres fois, c’est de modéliser puis implémenter une spécification de langage depuis sa fondation.

J’ai, euh, fait quelque chose

Cette histoire débute à peu près à ce temps-ci de l’année (mai/juin) en 2014, mais le bout qui nous intéresse ici nous ramène il y a tout juste quelques mois à l’hiver 2026, au moment où je me suis réveillé un matin en me disant “et si RD3 était nettoyé un peu, et redémarré ?”

Armé d’une redoutable cafetière, j’ai ouvert Visual Studio et parti un projet tout neuf que j’ai nommé RDCore, puis j’ai commencé à y déplacer le système de typage – j’avais vraiment quelque chose d’intéressant dans RD3, il fallait juste débroussailler un peu.

J’ai ensuite suivi la documentation MS-VBAL (la spécification officielle du langage VBA) et… j’ai rapidement conclu que je détenais autre chose, que ceci n’allait pas, en fait, aboutir avec juste un redémarrage de RD3.

Rubberduck v3 a toujours été ambitieux, mais là c’était en train de devenir un véritable SDK… pour une plateforme de langage moderne.

Pour VBA.

Pleinement open-source et désormais officiellement sous la gestion d’une entité corporative, le projet est tout juste rendu public et toujours en phase de développement actif, donc ne cherchez pas un installateur pour l’instant, mais…

RDCore.SDK

La librairie principale de la solution RDCore encapsule le cœur de langage de la plateforme (le système de typage, les règles sémantiques, les abstractions de la librairie standard… Ça sera tout VBA mis en boîte), mais aussi (pour l’instant du moins) toute l’extensibilité liée au Language Server Protocol (LSP) pour bâtir une constellation de plug-ins hors-processus pour des analyseurs sémantiques, entre autres idées d’extensions.

Il s’agit d’un framework pour construire des applications .net 10 (donc théoriquement indépendantes de l’OS) qui peuvent construire sur ces nouvelles fondations flambant neuves, tout ce que la communauté VBA a toujours rêvé de pouvoir faire avec ce langage.

VBA est mort, non?

Voici ici une ré-implémentation (en cours) partie des spécifications, traduisant un ensemble inconfortable de règles souvent partielles et qui semblent contradictoires en un design honnêtement très élégant qui… change complètement la donne.

Et si on avait Roslyn, mais pour VBA?

Ceci place VBA à une véritable fourche dans son histoire : une branche représentant de plus en plus un risque opérationnel, l’autre se plaçant solidement comme un chemin vers l’avant.

One does not simply… sortir de VBA

Si vous n’étiez pas là vers la fin des années 90, vous ne savez peut-être pas à quel point VB était pratiquement partout. C’est peut-être aujourd’hui un langage un peu bizarre qui automatise quelques fichiers Excel pour votre compagnie, mais pour d’autres il exécute des fonctions critiques, ou alors il implémente un moteur de calculs physiques propriétaire qu’aucun n’a osé toucher en 25 ans sans avoir la sécurité d’une solide suite de tests unitaires : la migration de ce code hérité (“legacy”) coûtera plusieurs dizaines sinon des centaines de milliers de dollars pour aboutir avec quelque chose qui fonctionne peut-être aussi bien que la macro de Dave, mais maintenant avec un portail web et des micro-services distribués sur AWS avec un API et oh, voici votre nouvelle facture mensuelle pour toute cette infonuagique, bienvenue sur le cloud!

Cette même histoire se répète un peu partout dans chaque recoin de chaque secteur de chaque économie sur cette planète, et l’industrie de la modernisation du code hérité est énorme… et tous les joueurs majeurs semblent convaincus qu’un autocomplete glorifié et mis sur un piédestal saura régler tous ces problèmes, avec une approche approximative qui fonctionne en surface, mais tient rarement la route par elle-même, car le diable est dans les détails.

À moins que quelque chose ne vienne déranger l’industrie avec une approche radicalement différente.

RDCore pourrait (éventuellement) prendre en charge la macro de Dave et soudainement, celle-ci serait pérenne et observable, de la même façon que si elle avait été complètement réécrite sur une plateforme de langage moderne… parce que c’est exactement ce dont il s’agit ici.

Ce que signifie l’existence de RDCore

C’est un énoncé, un pied à terre. Ça signifie qu’il existe désormais une plateforme de serveur de langage avec des capacités d’analyse sémantique extrêmement détaillées en développement actif sous la direction de 9562-7303 Québec inc., et qu’il existe une communauté de développeurs qui refuse d’abandonner VBA et qui a décidé que le temps était venu de le prendre en main. MS-VBA ne sera probablement jamais open-source, alors notre réponse est “d’accord. nous le rendrons donc par nous-même à sa communauté“.

Ça signifie que soudainement, les capacités d’analyse sémantique de VBA deviennent comparables à celles de Roslyn (l’impeccable compilateur de C#) – entre toutes les choses avec quoi VBA aurait pu rêver d’être favorablement comparé.

Ça implique des possibilités d’extensions qui vont bien au-delà de ma propre débordante imagination : il existe désormais un chemin où la communauté peut façonner l’avenir de VBA de toutes les façons qui lui chantent.

Ça signifie beaucoup, beaucoup de choses.

Qu’advient-il de Rubberduck?

Il ne deviendra pas un nouveau plug-in pour VBA, c’est plus gros que ça. Pas non plus une version client LSP – c’est plus gros que ça.

Rubberduck va plutôt fusionner et ne devenir qu’un avec le langage qu’il tentait de mieux comprendre : la prochaine itération de Rubberduck en sera une du langage même, et il s’agit d’un nouveau paradigme pour Rubberduck, pour VBA, et pour l’industrie de la modernisation du code hérité en général.

J’aimerais voir RDCore devenir un vibrant écosystème bourré d’excitantes extensions officielles et de tierces parties ouvrant des possibilités jamais même envisagées auparavant qui démontent complètement l’idée que VBA est une langue morte. Une langue n’est pas morte tant qu’elle a des locuteurs, et d’ailleurs VBA est une spécification, et une spécification ne meurt pas – elle se retrouve plutôt fossilisée, gravée dans la pierre, puis implémentée des siècles plus tard d’une façon dont les auteurs originaux n’auraient  pu imaginer.

Il y a une possibilité qu’RDCore passe à l’Histoire comme la plateforme qui a finalement succédé à VBA. Et ce n’était pas Microsoft. C’était nous. C’était Rubberduck. C’était RDCore.

VIVAT CUCUMIS™ ❤️

Consultez la documentation officielle pour tous les détails.


English

Some things you just need to do.

Sometimes it’s carving your recently-incorporated company’s logo with your own hands in a limestone slab.

Now I can touch it (so smooth!): it’s here, it’s real. I made it myself and I’m proud of the results!

Some other times it’s just waking up and implementing a language specification.

So uh, I did a thing.

This story could start at just about exactly this time of the year (May/June) in 2014, but that’s not why you’re here, so I’m going to skip ahead to winter 2026 – just a few months ago when I thought “hey what if RD3 was actually sorted out and rebooted”, and set out to do just that.

I started a new solution and called it RDCore, then started the migration with the type system. I had something interesting in RD3, it just needed to be expanded on and cleaned up a little.

I grabbed the MS-VBAL specifications and found myself just organically but rather quickly reaching the conclusion that I was onto something else, this wasn’t just a reboot of RD3 anymore.

It was becoming a SDK. For a language platform.

For VBA.

Fully open-sourced and under corporate stewardship, now officially in Public Open-Core Phase II after a few months in a private development phase – the project is still very much pre-launch so don’t go looking for an installer yet, but

RDCore.SDK

The main library in the RDCore solution encapsulates the platform’s language core (the type system, semantics, standard library abstractions, … it’s VBA wrapped up in a box), but also (for now anyway) everything around extensibility and wiring up the Language Server Protocol to make a constellation of out-of-process semantic analyzer plug-ins… among other extension ideas.

It’s a framework for building .net 10 applications (so at least theoretically platform-agnostic) that can extend this shiny new language platform with everything the VBA community ever dreamed of extending the language with.

VBA is dead, right?

The ironic thing is that, this is what might ultimately become its actual successor: a ground-up reimplementation of the language specifications (in progress), turning an uncomfortable mess of seemingly contradictory rules and exceptions into a honestly very elegant object-oriented design that …completely flips the script.

What if Roslyn, but for VBA?

This basically puts VBA at a literal fork in the road: one path is increasingly becoming a liability, the other is emerging as an increasingly compelling way forward.

One does not simply… Exit VBA

If you weren’t around in the late 90s you might not understand just how ubiquitous Visual Basic was. Maybe it’s a funny language that scripts a handful of worksheets at your company, but elsewhere it runs complex proprietary physics calculations that nobody in 25 years dared refactoring without the safety net of a good unit test coverage, let alone extracting clear specifications from it: migrating it would cost hundreds of thousands of dollars, only to get something that maybe will work just as well as Dave’s macro, but in a web app now, with AWS-hosted micro services and API and oh here’s your updated cloud services monthly bill for all that. Welcome to the cloud!

And that same story is in every conceivable corner of every sector of every economy on this planet, and the modernization of this legacy code is a gigantic business with major players apparently all convinced that a masterfully concocted glorified auto-completion engine can solve all their problems, with an approximative approach that works fine on the surface, but often falls apart under scrutiny because the devil is in the details.

Unless something comes along and… disrupts the industry, that is.

RDCore could (eventually) run Dave’s macro and, just like that, it becomes sustainable and observable, as if it had been completely rewritten to run on a modern language platform... because it’s exactly what it is.

What RDCore’s existence means

It’s a statement. It means that there’s now a language server platform with extremely detailed semantic analysis capabilities, in active public development under the stewardship of 9562-7303 Québec inc., and that there’s a developer community that is refusing to let go of VBA and has decided that the time has come to take it into our own hands: MS-VBA will likely never be open-sourced, but RD-VBA says “fine, we’re open-sourcing VBA on our terms then”.

And then it means that suddenly, the semantic analysis capabilities of VBA are comparable to Roslyn (the pristine C# compiler itself), of all things VBA could ever dream to be favorably comparable to.

It means extensibility well beyond my own admittedly quite creatively artistic imagination:  there’s now a path where a dev community gets to shape the future of VBA in just about any way they like.

What happens to Rubberduck?

It’s not becoming a better VBIDE addin. Bigger. Nor even a LSP-enabled version of it. Bigger.

Instead, Rubberduck is becometh one with the language it always tried to understand: the next iteration of Rubberduck is going to be an iteration of the entire language itself, and it’s a complete paradigm shift for Rubberduck, for VBA, and for legacy software modernization.

I would like the RDCore platform to spawn a thriving ecosystem of exciting never-thought-even-possible-before first and third party extensions that really challenge the notion that VBA is a dead language. A language isn’t dead as long as it’s spoken, and besides VBA is a language specification, and specs don’t die; they just get carved in stone, and then centuries later implemented in a way the original authors couldn’t even imagine.

There’s a chance RDCore goes down in History as the language platform that finally did replace VBA. And it wasn’t Microsoft that did it. It was us. It was Rubberduck. It was RDCore.

VIVAT CUCUMIS™ ❤️

See the official documentation for all the details.