RD-VBA CLI

(English below)

Un jalon majeur a été franchi la semaine dernière : la plateforme RDCore dispose désormais d’un interpréteur qui assemble toutes les pièces du puzzle en quelque chose de traçable, configurable et extensible, qui ressemble aux débuts d’un runtime.

Là où tout ceci devient très concret : l’application console exécute maintenant une boucle REPL interactive où vous exécutez une session runtime en mode immédiat :

Ne vous laissez pas avoir par le look C64-BASIC : il s’agit d’un client LSP avec une session RD-VBA.

Les 4 octets alloués sont pris par le module et la procédure synthétique où vit le code source de votre programme. Tapez une instruction VBA, elle s’évalue et affiche son résultat; précédez-la d’un numéro de ligne, et vous venez d’inscrire cette instruction à cette ligne dans votre programme RD-VBA. Le nom de ce module synthétique est Program, et le nom de la procédure est Main. Vous verrez régulièrement ces identifiants dans les traces de la pile d’exécution (stack trace) des erreurs rencontrées – qui seront ici toujours sous Main, mais vous comprendrez que ce même mécanisme fonctionnera peu importe la profondeur de la pile dans un véritable client (IDE), avec un vrai projet et plusieurs modules et procédures.

L’idée ici n’est pas de faire évoluer cette application en un IDE non plus – mais ça fait une façon très divertissante de tester la plateforme, le cœur de langage et ses sémantiques. Le rôle de cette application est de simplement permettre de tester la plateforme de bout en bout. Étant un client LSP, nous verrons fort probablement apparaître un surlignage sémantique de la syntaxe au niveau de la sortie de LIST par exemple, ou alors des listes de complétion interactives; les diagnostics sont déjà branchés et ANALYZE en affichera les détails dès que ceux-ci deviendront disponibles. PEEK/POKE ne sont que pure lecture/écriture directe en mémoire à la Commodore64.

RUN exécute le programme de haut en bas, à moins que vous lui construisiez un parcours avec GoTo et GoSub/Return, auquel cas vous savez probablement ce que vous faites… sinon les diagnostics seront bientôt là pour vous guider.

Sémantiques

Toute la plomberie est en place; ce qu’il reste, c’est l’implémentation : les instructions I/O comme Open, Close, Print#, Write#, Put#, Get# sont implémentées; les déclarations, boucles, conditions, sauts et gestion d’erreurs sont fonctionnels. Beaucoup reste à faire: chacune des instructions doit avoir une implémentation, sans quoi les exécuter sera toujours en erreur.

L’implémentation de la librairie standard a débuté : Len et LenB sont les premiers consommateurs des données de stockage des UDT, et bien que LSet fonctionne tel que spécifié sur une String ou un UDT, la très vaste majorité de la librairie demeure à implémenter. Il s’agit de travail relativement simple qui n’a pas à traverser plusieurs couches d’abstraction et peuvent être des gains rapides; c’est pourquoi j’ai préféré donner les plus gros morceaux à Claude, les fonctions pures de la librairie peuvent être implémentées plus tard.

Ceci dit l’exécution et la gestion d’erreurs en place donnent déjà un bon aperçu :

Un programme RD-VBA qui ne contient pas d’instructions non-implémentées se complète.

Le retrait de l’instruction On Error GoTo révèle quelques faits intéressants :

D’abord, il y a une différence entre une erreur lancée explicitement par l’application, et une erreur d’exécution. Ensuite on remarque le numéro de ligne, puis la stack trace.

Ce que ces images ne montrent pas, c’est que le numéro de ligne est un symbole ici, seulement parce qu’il s’agit du mode programme – mais dans un document, la configuration par défaut fait de ce numéro l’emplacement L1C1 exact de l’erreur dans le document.

Une erreur d’application (VBA00000) est une erreur lancée par le code source (via Error, ou Err.Raise); une erreur d’exécution (VBR00000) est une erreur lancée par l’interpréteur. MS-VBA ne différencie pas réellement ces deux types d’erreurs – il y a donc désormais une distinction claire entre les deux, et ça ne brise rien du tout!

Aucune erreur d’application ne peut être confondue avec une erreur d’exécution, et il y aura toujours une trace de la pile d’exécution, même en mode immédiat!

Limitations

Certaines limitations sont inhérentes au fait qu’il s’agisse d’une application console: en effet il serait surprenant d’y voir une fonctionnalité affichant des info-bulles au survol d’un symbole.

D’autres limitations sont plutôt liées au design:

  • Le module Program et la procédure Main sont intrinsèques et ne peuvent pas être renommés.
  • Une commande sans numéro de ligne s’exécute immédiatement; les numéros de ligne sont donc obligatoires pour tout programme dans ce client.
  • Les numéros de lignes ne devraient pas empêcher l’utilisation de libellés, mais ceux-ci ne fonctionnent pas actuellement avec un numéro de ligne; GoTo/GoSub doivent donc référer à un numéro de ligne.
  • Les continuations sont invalides: un numéro de ligne ne peut pas être situé en plein milieu d’une instruction.
  • Limitation éventuelle du jeu de syntaxe valide en mode BASIC (configurable).
  • Limitation éventuelle à 10,000 lignes de la longueur permise d’une procédure; l’erreur procedure too long devrait alors être lancée à la compilation, mais possible que le mode BASIC fonctionne différemment.
  • Exit Sub termine le programme; Exit Function et Exit Property sont statiquement invalides.
  • Sub Main() et End Sub sont implicites: le corps du programme constitue le corps de cette procédure.
  • L’ajout de procédures additionnelles n’est pas supporté (les numéros de ligne étant invalides au niveau des déclarations d’un module); utilisez plutôt GoSub/Return avec de larges sauts de numérotation pour coder des sous-routines.

D’autres limitations sont ponctuelles et seront résolues avant le lancement de la v1 :

  • L’instruction REM qui explose à l’exécution est objectivement comique, mais ne restera vraisemblablement pas brisée longtemps.
  • L’invocation de membres de la librairie standard qui ne sont pas encore implémentés sera également en erreur.

Manipulation de Mémoire

Les commandes PEEK et POKE ne sont pas (encore?) implémentées en tant que mots-clés et donc pas utilisables dans du code source RD-VBA, mais les commandes fonctionnent et permettent donc une lecture/écriture directe d’octets en mémoire applicative – opération évidemment très risquée, mais la nostalgie l’a emportée.

Ceci dit les opérations LSet fonctionnent dans le code source sur des String et UDT.

Jalons

L’évolution du cœur de langage est complètement découplée de celle de l’application CLI, donc celle-ci fonctionnera de mieux en mieux et de façon de plus en plus complète à mesure que s’ajouteront les sémantiques du cœur de langage, et ce sans rien devoir corriger ou modifier dans l’application même.

Cela ne signifie pas pour autant que le travail est terminé!

L’application supporte notamment des thèmes, donc si le bleu C64-BASIC ne vous plaît pas, vous pouvez toujours passer à un thème foncé moderne. Ce n’est donc qu’une question de temps avant que la sortie de LIST affiche un surlignage sémantique issu du serveur de langage!

Exploiter cette connexion LSP constitue la façon dont cette application deviendra ultimement beaucoup plus qu’un éditeur BASIC. ANALYZE est déjà prêt à afficher les diagnostics, dès qu’ils commenceront à apparaître dans la plateforme.

Le mode REPL est bien pour une démo, mais le véritable outil est le mode CLI non interactif.

Les outils modernes s’exécutent dans des pipelines CI/CD (intégration et livraison continues) dans le cloud. rdc.exe sera à terme en mesure de compiler un projet, d’en exécuter les tests, et de bloquer une livraison qui dévie des conventions établies, le tout complètement en-dehors de l’écosystème MS-VBA.

Êtes-vous READY?


Mise à jour | Update 2026-10-02:

English

Si seulement 1986 avait eu LSP…
If only 1986 had LSP…

A major milestone was knocked down in the last week: the RDCore platform now has an interpreter that puts all the previous pieces together into a traceable, configurable, and extensible beginning of a runtime.

Where this gets very real, is with the CLI app now running an interactive REPL program mode where you’re basically running a runtime session in immediate mode:

Don’t be fooled by the C64-BASIC look; this CLI app is a full-fledged LSP client with an active RD-VBA runtime session.

The 4 bytes taken are allocated for the synthesized module and procedure scope your program space lives in. Type a VBA expression, and you get its result; precede it with a line number, and now you’ve written that instruction at that specified line number in your program. The name of this synthesized module is Program, and the name of the enclosing procedure is Main. This matters, because you’ll see these identifiers in error stack traces – here only ever inside Main, but you can see what this means for error handling with an actual IDE client, and a project with real procedure scopes.

The idea is not to evolve this app into one, either; it’s just to make a fun way to test the language core and semantics… and diagnostics – the platform, basically. The role of RD-VBA CLI mode is to test the platform end-to-end, hands-on – and being a LSP client means we’ll probably get to write old-school BASIC programs with semantic syntax highlighting in LIST outputs, completion lists for the REPL inputs. Diagnostics are already wired, ANALYZE will start showing meaningful output when providers/extensions issue diagnostics. PEEK/POKE is just C64-like pure unsafe program memory read/write.

RUN runs the program top to bottom, unless you make it do funny things like GoSub, in which case you probably know what you’re doing. If you don’t, …RDCore diagnostics will eventually have your back covered.

Semantics

So the plumbing is in place; what remains is semantics: file I/O statements like Open, Write, Print#, are implemented at the language core layer. Declarations, control flow, error handling as well. Still a lot remains TODO – every single statement keyword must have its semantics implemented, otherwise running them gets you an internal error.

Standard library implementation has begun as well; Len and LenB are the first consumers of the UDT member storage data, and while all the symbols are defined and LSet works as specified on UDT and strings, the vast majority of the standard library remains to be implemented; this is mechanical work that doesn’t need to reach across multiple layers to be a quick gain – so I let Claude/Opus focus on the more meaty parts that do cross into the runtime and memory layout, leaving the simpler, pure functions for later.

Control flow and error handling is fully functional:

BASIC-like RD-VBA code runs end-to-end in the app, …as long as the program doesn’t involve unimplemented semantics.

Removing the On Error GoTo instruction reveals a number of interesting facts about RD-VBA:

First, there’s a difference between an error you raise and an error the runtime raises. Second, errors have a source location pointing to the line number of the faulting instruction, and then there’s a stack trace.

What this doesn’t tell you, is that the platform is showing symbolic line numbers here only because it has no workspace document proper (the internal buffer just simulates one), but in an IDE client the default configuration would be reporting the actual L1C1 document location.

An application error (“VBA00000”) is a run-time error that is raised by the workspace code; a runtime error (“VBR00000”) is a run-time error that is raised in the language core runtime semantics. MS-VBA historically did not really differentiate between these errors; now there’s a structural distinction between them, and it doesn’t break anything!

No Error or Err.Raise statement can ever be mistaken for a runtime error, and we always get a stack trace, even in immediate command mode.

Limitations

Some limitations are inherent to the CLI app being a CLI app: hover tooltips aren’t going to be available, and that’s a given.

Others are design decisions. These include:

  • Program.Main project and procedure scope; intrinsic, cannot be renamed.
  • C64-style program interface, using line numbers as markers for instructions that are stored in the source buffer rather than immediately piped to the interpreter; this makes line numbers inherently mandatory in this client.
  • Line numbers should not prevent the use of line labels, however labels do not currently parse with line numbers. GoTo must therefore refer to line numbers.
  • Line continuations cannot be used; a line number isn’t a valid statement to continue into.
  • Eventually artificially limiting the valid RD-VBA syntax (including comments) in CLI program mode to the BASIC subset of VB, via appsettings.json platform configuration.
  • Eventually limiting the number of logical lines to 10,000; procedure too long compile-time error ought to be raised then, but BASIC mode will probably end up working differently.
  • Exit Sub terminates the program; Exit Function and Exit Property are statically illegal.
  • Sub Main() and End Sub are implicit; the program body is that procedure’s body.
  • Additional Sub procedures cannot be defined (line numbers are illegal on declaration members); use GoSub/Return with wide line numbering gaps to denote subroutines instead.

Other limitations are temporary pre-alpha missing implementations that will definitely be implemented before a v1.0 can ship:

  • REM statements (BASIC-style comments) throwing statement not implemented is objectively funny, but will probably not take too long to get working as the no-op instruction it is.
  • Standard library implementation being incomplete, any function call that refers to a symbol defined there throws not implemented as well.

Unsafe Program Memory Ops

Not (yet?) implemented as keywords, the PEEK and POKE immediate commands allow byte-level unsafe reads and writes (!) from/to a specified address in program memory space. This is obviously dangerous and may lead to crashes, but nostalgia won.

That said LSet and RSet semantics are both implemented, including against UDT values.

🎯 Milestones

The evolution of the RD-VBA language core and runtime implementation is architecturally decoupled from the CLI application, so it’ll automatically throw fewer errors as the language core progresses, without fixing or changing anything anywhere in the CLI app.

That doesn’t mean the work is done, however.

The app supports themes, so if you don’t like C64-style BASIC blue, you might like a modern dark theme instead. It’s only a matter of time before LIST output gets semantic syntax highlighting from the language server!

Leveraging this LSP connection is how the app will turn into something more than a BASIC console. ANALYZE is already wired up to report diagnostics as soon as they start coming.

A BASIC immediate/command/program mode is nice for a platform demo, but the real tool is the non-interactive CLI mode.

Modern tools run in the cloud, from CI/CD scripts that build a project, run its tests, inspect its vulnerabilities and deviations from established coding practices; rdc.exe supports an extensible set of command-line tools exactly for this. Extensions can supply a provider for various commands such as test or analyze, and a CI/CD script could be configured to gate a build on tests passing and diagnostics showing no warnings or errors.

Are you READY?

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.