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?


English

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?

VIVAT CUCUMIS

(English below)

Longue vie au concombre

Le 26 mai 2026 marquera le 10e anniversaire de la découverte par le contributeur historique @Comintern de ce message cryptique à la clé de resource 18089 de la librairie VBE7INTL.DLL:

STRINGTABLE
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
{
18080, "Tile Horizontally"
18081, "Tile Vertically"
18082, "Arrange Icons"
18083, "Microsoft Visual Basic for Applications Help Topics"
18084, "Search Reference Index..."
18085, "Obtaining Technical Support"
18088, "About Microsoft Visual Basic for Applications..."
18089, "Long Live the Cucumber"
18090, "Break On All"
18091, "Break In Ole Server"
18092, "Break On Unhandled"
}

Le projet Rubberduck a toujours voulu s’approprier cette phrase et s’en servir quelque part d’une façon ou d’une autre.

Rubberduck Core marine ce concombre depuis un certain temps, et fait de cette phrase son slogan, en latin:

Gravé dans la pierre, VIVAT CUCUMIS se lit en latin comme une prophétie ancienne.

Il y a plusieurs niveaux à cette imagerie: plongeons.

Gravé dans la pierre

Quand on dit de quelque chose qu’il est gravé dans la pierre, on décrit quelque chose d’immuable, ou qui n’est pas prêt de changer. Un peu comme les spécifications d’un certain langage de programmation.

La pierre taillée évoque l’antiquité et la renaissance, mais aussi les pierres tombales et les cimetières, où l’on pourrait s’attendre à retrouver une langue morte comme le latin… ou VBA. Ça dit “ceci existe depuis longtemps”, mais aussi “ceci fait partie de notre héritage”.

La pierre est une fondation solide, noble. Elle est aussi lourde, et peut être un fardeau tout comme le code hérité – ou pour Microsoft tout comme le support des librairies d’exécution de VBA. Elle dit malgré tout “ceci existera encore longtemps”.

VBA est mort, vive VBA!

Peut-être que le proverbial concombre se voulait réellement référer à Visual Basic même, mais c’est sans importance de toute façon parce que VBA a effectivement survécu, et donc le soulier fait, même si c’est a posteriori.

L’utilisation d’une image qui pourrait être interprétée comme une pierre tombale pour quelque chose qui est lié à VBA assume complètement la nature “intuable” du langage et la profonde ironie de le voir survivre à chaque produit ou technologie qui tente désespérément et successivement de le remplacer : VBA est mort, longue vie à VBA!

Modernisation

Rubberduck Core conserve les racines et fait évoluer le concept, alors on passera éventuellement de la pierre au métal – à l’acier :

Gravés au laser sur un médaillon en acier, les mêmes mots deviennent à la fois un hommage, une promesse, une réalisation, un… porte-clé sans doute.

L’acier est toujours la pierre, en quelque sorte. Cuisinée un peu certes (bon d’accord, carrément séparée du métal…), mais néanmoins il vient de la pierre. Brute, lourde et difficile à manier, maintenant raffinée, élégante et polie, relativement légère mais robuste et durable. Et brillante aussi. L’âme y est clairement toujours.

C’est précisément ce qui va se produire avec Rubberduck : le concombre ne fait que mariner encore un peu… parce qu’une décennie plus tard, celui-là n’est toujours pas un cornichon.

rubberduckvba.ca

Le site historique du projet rubberduckvba.com redirige désormais vers rubberduckvba.ca et le dépôt du projet Rubberduck sur GitHub est maintenant archivé en lecture seule. Les efforts de développement pour la prochaine évolution sont en cours dans un dépôt pour l’instant privé sous la même organisation rubberduck-vba; Rubberduck Core en sera bientôt le nouveau projet-phare en mode Open-Core, soutenu par 9562-7303 Québec inc., une société privée fondée à cet effet par le même auteur principal de Rubberduck et auteur de ce blogue depuis son commencement.

Être incorporé au Québec signifie que toutes les communications officielles seront publiées dans ce format en français d’abord, avec un lien immédiat vers le contenu équivalent en anglais. Ça signifie également que la disponibilité du contenu dans une langue autre que l’anglais n’est pas un ajout, mais une nécessité : tout comme Rubberduck, Rubberduck Core (ou RDCore pour faire plus court) sera assurément disponible en français et en anglais dès le jour un, et ensuite dans toutes les langues que la communauté rendra disponibles. Ce n’est pas un fardeau, mais une opportunité. Vos documents seront toujours envoyés dans la langue de votre choix.

(C) 2026 Mathieu Guindon pour 9562-7303 Québec inc.


English

Long Live the Cucumber

May 26, 2026 will mark the 10th anniversary of the discovery by core historical contributor @Comintern of this cryptic message at resource key 18089 of the VBE7INTL.DLL library:

STRINGTABLE
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
{
18080, "Tile Horizontally"
18081, "Tile Vertically"
18082, "Arrange Icons"
18083, "Microsoft Visual Basic for Applications Help Topics"
18084, "Search Reference Index..."
18085, "Obtaining Technical Support"
18088, "About Microsoft Visual Basic for Applications..."
18089, "Long Live the Cucumber"
18090, "Break On All"
18091, "Break In Ole Server"
18092, "Break On Unhandled"
}

The Rubberduck project always wanted to appropriate this phrase and use it somewhere, somehow.

Rubberduck Core marinates the cucumber and makes the quote its catchphrase, coined in Latin:

Carved in stone, Latin VIVAT CUCUMIS reads like some ancient prophecy.

There are a few layers to this imagery: let’s dive.

Carved in Stone

When we say something is carved in stone, we are describing something that is either immutable, or isn’t about to change – much like the specifications of a certain programming language.

Carved stone evokes Antiquity and Renaissance, but also cemeteries and headstones, like where you would expect to find a dead language like Latin… or VBA. It says “this has been around for a long time”, and also “this is part of our heritage”

Stone is rock solid, foundational, noble. It’s also heavy, and it can be a burden, like legacy code – or if we ask Microsoft, like runtime support for VBA. It nevertheless still says “this will be around for a long time”.

VBA is Dead, Long Live VBA!

Maybe “the cucumber” really did refer to Visual Basic itself, but it wouldn’t matter if it didn’t: VBA lived on, so the shoe fits even if a posteriori.

Using something that can be construed as a headstone to depict something related to VBA leans heavily onto its “unkillable” nature and the profound irony of it surviving every single one of its successive replacement attempts: VBA is dead, long live VBA!


Modernization

Rubberduck Core keeps the roots and evolves the concept, and so we will eventually grow out of stone, to metal – to steel:

Laser-engraved on a steel medallion, the same words become a tribute, a promise, a fulfillment, a… keychain, perhaps.

Steel is still the stone, in a way – crushed and cooked (narrator: fully separated from it, actually), but it came from the stone. Crude, heavy and unwieldy, it ultimately becomes refined, elegant and polished, relatively lightweight but extremely solid and reliable. And shiny. The soul is still there.

That’s exactly what’s going to happen with Rubberduck – the cucumber is only marinating a little longer… because a decade later, this one still hasn’t pickled yet.

rubberduckvba.ca

The historical project site rubberduckvba.com is now redirecting to rubberduckvba.ca and the Rubberduck repository on GitHub is now archived/read-only. Development efforts towards the next evolution are currently in progress in a private repository under the same rubberduck-vba organization; Rubberduck Core will soon be its flagship Open-Core project under 9562-7303 Québec inc., a private company founded for this specific purpose by the same primary author of Rubberduck and of this blog since its inception.

Being incorporated in Québec means all public communications are going to be issued in a French-first format, with an immediate link to the English content. It also means that localization isn’t an afterthought in this company, but a necessity: like Rubberduck before it, Rubberduck Core (or RDCore for short) shall be assuredly available in both French and English, and then every language it would end up being translated into. It’s not a burden, but an opportunity. Your documents will always be emailed in the language of your choosing.

(C) 2026 Mathieu Guindon on behalf of 9562-7303 Québec inc.