RDCore @ 20260915

Français (English below)

Si on m’avait demandé il y a quelques mois pourquoi rien n’est codé avec l’assistance d’une IA dans RDCore, j’aurais répondu que l’architecture, pourtant bien ciblée, était toujours en mouvement. Je ne voulais pas qu’un LLM décide de cette architecture, notamment parce que RDCore fait un certain nombre de choses à sa propre façon, et parce que coordonner 5 processus n’est pas exactement simple.

Tout au long, on me demandait pourquoi je refusais d’utiliser l’IA pour accélérer les choses.

La vitesse de la mise en place initiale était tout simplement sans importance : c’était à propos de l’architecture et du modèle – concevoir ces éléments avec mes propres mains et mon propre cerveau ont permis d’atteindre une solide fondation – et oui, avec l’aide de l’IA pour débattre d’idées et évaluer les options.

L’IA générative est excellente pour accélérer une implémentation, mais beaucoup moins pour décider ce qui doit être implémenté – sauf que maintenant, la colonne vertébrale est solidement en place.

Pendant le dernier mois, quelque chose s’est produit : le cœur et l’architecture sont suffisamment avancés, et j’ai donc décidé de donner une nouvelle chance à l’IA, cette fois-ci avec Claude Code. Si nous n’étions pas en 2026, vous ne pourriez croire ce qu’il a fait du backlog.

Comme il s’agit d’un énorme projet, il est découpé en plusieurs jalons. Voici donc…

Jalon : Communications JSON-RPC

Les connexions LSP/JSON-RPC sont désormais fonctionnelles au niveau du SDK – donc pour l’ensemble de la plateforme : toutes les composantes démarrent, échangent leurs capacités, et se ferment proprement.

Ce jalon a été rapidement fermé, puisqu’il était pratiquement complet – mais ça signifie quoi?

La plupart des serveurs de langage sont des monolithes qui se chargent de tout. RDCore est conçu différemment, et sépare ses responsabilités dans des processus distincts.

Il en résulte un parsing server entièrement stateless, la mémoire applicative qui vit dans l’hôte d’environnement, une librairie runtime dédiée à l’exécution, les sémantiques statiques du cœur de langage définies au niveau du SDK, et un serveur de langage qui se consacre donc pour l’essentiel au protocole LSP.

Chacune de ces composantes peut donc évoluer indépendamment des autres.

Capacités de la Plateforme

L’idée est la suivante : peu importe ce que fait une composante, elle l’appelle “capacité” et décrit à la plateforme ce qu’elle peut faire.

Plusieurs choses dans la plateforme sont fournies, et donc une extension peut définir et enregistrer un fournisseur et ainsi contribuer à l’expérience de l’utilisateur.

Tout démarre avec un client LSP (IDE) qui démarre le serveur de langage : ils établissent une connexion bidirectionnelle à travers une named pipe, puis le serveur RDCore fait quelque chose que peu d’autres font, et démarre une poignée de processus :

  • rdc.exe, l’hôte d’environnement qui coordonne l’exécution et la mémoire.
  • RDCore.ParseServer.exe, un serveur stateless qui s’occupe exclusivement de la syntaxe; il ne produit une arborescence (AST) que pour un document complet pour l’instant, mais supporte déjà un ancrage et bientôt des fragments de code.
  • RDCore.Diagnostics.exe, une extension chargée de produire les diagnostics (erreurs de syntaxe pour l’instant).

Avec rdc.exe en tant que client, nous observons donc 5 processus à l’exécution :

Task Manager montrant les processus RDCore à l’exécution. Le plus petit des deux rdc.exe est le client, l’autre est l’hôte d’environnement RD-VBA.

Jalon : AST Bidirectionnel

Une arborescence qui conserve l’emplacement du code source – incluant ce qu’il ne comprend pas, lui permet de correctement être exprimée en code source. Ceci implique des refactorings et code actions chirurgicaux à l’horizon.

Une chose que l’AST fait déjà que le parser de Rubberduck ne faisait pas donc, est de préserver la source. Les blocs “morts” de compilation conditionnelle étaient pour Rubberduck des espaces blancs – maintenant, des nœuds trivia renseignent sur ce contenu et permettront, une fois l’interpréteur en place, de discerner les définitions “vives” des définitions “mortes”, et ainsi une action refactor/renommer qui ne laisse pas derrière une définition inactive.

Une arborescence immuable représentant la pure syntaxe est l’élément clé dont Rubberduck a toujours eu besoin, et n’a jamais eu.

Jalon: Déclarations

Avec la plateforme qui prend vie, une autre étape a été franchie : tout ce qui produit un symbole est désormais dans la sortie (AST) du parser.

Quand le serveur de langage reçoit l’arborescence d’un module, un fournisseur en extrait les symboles, qui sont ensuite relayés à l’hôte d’environnement, lequel les gère en mémoire.

Tout ceci n’est pas tout à fait entièrement en place: les types complexes (tableaux/arrays, UDT et objets) ne sont pas encore gérés – mais ils sont les suivants. Ensuite on pourra créer des instances de classes et en allouer l’espace mémoire nécessaire, et des outils CLI pourront renseigner sur l’état de la mémoire.

Les tableaux et UDT sont représentés par des blocs de mémoire contiguës, conçus avec LSet/RSet et les tableaux 2D Variant en tête.

Le mécanisme d’allocations est assez complexe et bénéficie d’une importante couverture de tests. On y trouve un chemin “rapide” qui trouve rapidement le plus petit bloc de mémoire disponible à réutiliser, ainsi qu’un chemin plus “lent” qui va jusqu’à réserver de nouveaux segments au besoin. La mémoire libérée devient disponible pour réutilisation ultérieure, et l’idée de compacter la mémoire est pour l’instant écartée. Il s’agit d’un mécanisme où la planète arrête de tourner pour qu’en quelques cycles tous les objets déplacés obtiennent une nouvelle adresse, pour réclamer l’espace fragmenté laissé derrière le pointeur d’allocation – le programme peut ensuite poursuivre son cours. Si vous êtes familiers avec le garbage collector (GC) de .net, ces mécanismes ne doivent pas vous surprendre.

Les travaux à venir y intégreront l’adressage des paramètres et variables locales, qui vivent sur leur tranche de la pile d’exécution (stack frame): pour l’instant seules les déclarations statiques sont allouées.

Jalon : Résolution

Avec les symboles définis en mémoire, l’étape suivante était évidemment d’en permettre la résolution à partir d’un nom et d’un périmètre (scope)… et ainsi une autre importante étape est franchie.

Le ticket #973 du projet legacy Rubberduck demeure le dernier boss, mais comme la résolution fonctionne exactement telle que spécifiée, je n’ai aucun doute que RDCore saura manœuvrer à travers tout le Thundercode qu’on lui enverra. Ceci requiert évidemment les sémantiques d’exécution des expressions d’accès de membre, qui sont maintenant débloquées, donc l’implémentation ne saurait tarder.

Ouvert il y a plus de 11 ans par notre cher ami ThunderFrame, #973 (legacy Rubberduck) demeure le dragon à abattre. Peu importe où tu es Andrew, tu restes dans l’équipe et tu continues d’y contribuer!

Jalon : Sémantiques Statiques

MS-VBAL distingue clairement les règles s’appliquant à l’exécution de celles s’appliquant à la compilation. Les sémantiques statiques déterminent les types impliqués, alors qu’à l’exécution on parle généralement d’effets secondaires en mémoire ou ailleurs.

La plupart de ces règles au cœur du langage sont définies depuis un certain temps et attendaient ce moment. Avec la gestion de la mémoire en place, ce jalon peut maintenant être atteint et les travaux peuvent démarrer au niveau du moteur d’analyse.

La phase d’analyse prévue comprend un mécanisme d‘exécution simulée, lequel exerce les sémantiques d’exécution, mais sans affecter l’état global. Une fois en place, ceci permettra d’identifier des boucles infinies, récursion incontrôlée, code inatteignable, et tout ce dont Rubberduck a toujours rêvé pouvoir accomplir. RDCore ne devine pas ce que fait le code: il l’exerce et rapporte les faits produits par le moteur d’exécution.

Il se trouve que devenir le langage donne à Rubberduck des capacités que comprendre le langage n’ont jamais pu matérialiser.

Jalon: Moteur d’exécution

Le moteur en lui-même n’a pas encore fait l’objet d’un focus particulier, mais les travaux sur la résolution de symboles viennent débloquer l’implémentation des sémantiques statiques et d’exécution telles que les expressions d’accès à un membre, et l’opérateur de comparaison Is.

Ce jalon constitue le travail à longue-haleine vers lequel je vais bientôt me tourner. Il inclut l’implémentation complète de la librairie standard, avec les fonctions de conversion, arithmétique, finance, dates et strings, et des implémentations indépendantes de Windows pour MsgBox, InputBox, et autres fonctions traditionnellement liées à Windows.

Les projets RD-VBA ne réfèreront pas à VBA7.DLL, libérant VBA de son hôte historique.

Jalon: Serveur de Language

Ce jalon a progressé de façon significative et plusieurs tickets sont maintenant ouverts, et d’autres suivront à mesure que les capacités de la plateforme deviendront disponibles.

Il s’agit de tickets ouverts à tous, pour l’implémentation de chacun des points de terminaison LSP, et chacun d’entre eux débloque instantanément des fonctionnalités client/IDE:

De nombreux autres tickets semblables seront créés à mesure que de nouvelles capacités deviennent disponibles au niveau LSP.

Jalon: Application CLI

RDCore.CLI s’exécute en différents modes, selon les paramètres qui lui sont passés :

  • Avec un ClientProcessId, l’application tient le rôle de l’hôte d’environnement, tel que spécifié dans MS-VBAL.
  • Avec un workspace URI, l’application devient un client LSP en mode CLI, qui exécute une commande puis démonte la plateforme.
  • Sans paramètres, l’application sort présentement avec un code d’erreur, mais un client LSP en mode programme est prévu; d’autres détails suivront.

Le plus intéressant est la façon dont l’application branche ses commandes: l’hôte charge les extensions, ensuite de nouvelles commandes peuvent être fournies par ces extensions.

Cela signifie que la commande rdc –test fonctionnera exactement comme elle semble vouloir fonctionner, avec la commande test fournie et gérée par RDCore.UnitTesting, la 2e extension officielle prévue de la plateforme, à venir (elle aura son propre repository). Pour l’instant, la commande rdc –new crée un nouvel espace de travail / projet.


Feuille de route : intégration HexIDE

Une application CLI client LSP c’est bien, mais un client LSP qui est un IDE, c’est objectivement mieux. C’est d’ailleurs ce qui a coulé RD3, et tel que promis, rien dans RDCore n’est un IDE.

Par contre…

Une collègue (@imojenisys) travaille en parallèle depuis un certain temps sur son propre IDE pour VB6 – une expérience familière comme dans le VBE, mais avec des thèmes et un client LSP… qui parvient déjà à communiquer avec RDCore :

L’onglet HexIDE Protocol Conversations affiche l’initialisation LSP et les communications subséquentes avec le serveur de langage de RDCore, incluant le contenu de chacun de ces messages.

Le repository de HexIDE a été recopié (forked) sous l’organisation rubberduck-vba, avec pour but de positionner cet IDE comme L’IDE officiel de la plateforme, en contribuant les modifications au projet source.

Gestion des Attentes

Il est clair depuis le tout début, que RDCore vise à implémenter MS-VBAL indépendamment de Microsoft Windows.

Historiquement, VB fut conçu dans l’autre sens (à l’envers), à partir d’un designer glisser-déposer pour une conception UI “WYSIWYG”, sur lequel est venu se greffer un langage et un moteur d’exécution. RDCore renversé tout ça et part des spécifications du langage, et la notion de UI est très loin dans le futur.

Ceci sera sans aucun doute un peu frustrant pour la communauté VB, parce qu’il semble impossible de proposer une alternative à VB sans UI, c’est impensable!

En 30 ans, on a vu plusieurs tentatives commencer avec un UI pour ensuite s’effondrer : si partir d’un UI pour se rendre tranquillement vers un langage et un moteur d’exécution était une approche viable, on l’aurait vu fonctionner depuis. Il y a tout un cimetière de projets “IDE VB6” abandonnés qui ont pris ce chemin.

RDCore est différent. Il laisse délibérément tomber MSForms et ActiveX, et tout ce qui lierait la plateforme au destin de Windows.

Les fonctions de la librairie standard telles que MsgBox vont avoir un fournisseur permettant une configuration; afficher une boîte de dialogue sera une capacité de l’hôte comme une autre, laissant le tout sain et sauf pour une exécution en pipeline CI/CD.

La Suite

Le projet donne aujourd’hui une impression nettement différente d’il y a tout juste un mois à peine. Pour la première fois, le nouveau code débloque non plus de nouveaux éléments architecturaux, mais de nouvelles capacités. Le parser produit un AST, l’AST produit des symboles, les symboles sont placés en mémoire et les sémantiques peuvent les résoudre, et tout ceci débloque de véritables fonctionnalités du cœur de langage et du serveur LSP.

Je n’ai aucune idée de ce dont aura l’air la prochaine mise à jour, puisqu’il y a un effet boule de neige ici et donc il y aura bientôt une explosion de fonctionnalités débloquées. Mon focus sera sur le moteur d’exécution et tout ce qui permettra de débloquer l’interpréteur – incluant des fonctionnalités de déboguage (exécution pas à pas, points d’arrêt, etc.), via le protocole DAP.


RDCore @ 2026-09-15


English

If you asked me a few months ago why there’s nothing AI-assisted in RDCore, I would have said it’s because the architecture was, despite a clear target, still moving. I did not want a LLM to come up with whatever they “think” the thing should look like, notably because RDCore does a number of things its own way, and because designing a 5-process architecture isn’t exactly trivial.

All along the way, I kept getting questions about why I wasn’t leveraging AI to get some speed.

It wasn’t about speed though: it was about the architecture and the model – crafting this with my own hands and thinking things through, sure using AI to brainstorm ideas and weight options, but I didn’t want to generate the implementation without a solid backbone in place.

Generative AI is very good at accelerating implementation. Deciding what should be implemented, much less so – except now the backbone is in place.

So here we are now, and during the last month something happened: the core architecture is satisfyingly far enough along that I decided to give AI another shot, and went with Claude Code this time, and if it wasn’t 2026 you wouldn’t believe what it did to the backlog.

Since this is a very large project, it breaks down into multiple milestones. Let’s have a look.


Milestone: JSON-RPC Plumbing

The LSP handshake and formalization of a platform-wide RPC protocol is completed at the SDK level, and now all core platform components come alive, exchange information, and cleanly tear down.

This milestone was quickly knocked down since it was almost complete already, so what does it mean?

Most language servers are a giant monolith that does everything. RDCore is built differently, and cleanly separates and layers concerns across multiple different processes.

It means a parser that’s entirely stateless, program memory that lives in an environment host, runtime semantics implemented in a dedicated runtime library, static semantics in the language core SDK, and a language server that only needs to be concerned about LSP.

This makes completely decoupled components that can all evolve independently and scale without bloat.

Platform Capabilities

The idea is that whatever a component does, it calls it a capability and tells the platform what it can do. Many things in the platform are provided, and so components (and/or extensions) can register providers and contribute to the user experience.

Everything begins with a LSP client starting the language server: they establish a 2-way named pipe connection, and then the language server does something most language servers don’t – it spawns a handful of child processes:

  • rdc.exe runs the environment host, which coordinates runtime and memory operations;
  • RDCore.ParseServer.exe runs a stateless parser that cares for absolutely nothing beyond syntax; the language server can ask it to produce a syntax tree for any module, currently only supporting full document parsing, with anchored-offset code fragments planned.
  • RDCore.Diagnostics.exe runs the core semantic analyzers (currently none) and produces all the core diagnostics (currently only syntax errors)

With the console application rdc.exe running in client mode (or an IDE client), that makes 5 processes alive and ready to work.

Running RDCore processes, as seen in Task Manager; the smaller RDCore.CLI process is acting as the LSP client, the larger one is the RD-VBA host.

Milestone: Round-tripping AST

Having a syntax tree that preserves the location of everything – including tokens that don’t make sense, makes an AST that can round-trip back to source code. This means surgical refactorings and code actions on the horizon.

One thing the AST already does that the Rubberduck parser didn’t do, is it preserves the source. Conditionally compiled “dead code” blocks appeared to Rubberduck as plain whitespace – in RDCore we get a trivia node with that content, and the declaration pass picks up all the declarations, and that means we can now not only tell you which branch is dead or alive, we can also know that a given symbol has a definition that is inactive, and an eventual refactor/rename refactoring will no longer leave behind the code in a dead precompiler branch.

Having a real, immutable abstract syntax tree that represents pure syntax, is something Rubberduck never had – and always wanted.

Milestone: Declaration Pass

With the platform coming alive, another milestone was knocked down at the parser level: everything that represents a symbol that defines anything, is now in the syntax tree output of the parser.

When the language server receives the trees for all source documents in the workspace, a symbol provider traverses them and generates symbols that are then relayed to the environment host, which manages them in program memory space.

This isn’t fully implemented yet: the complex types remain (arrays, UDT, objects), but they’re next – then the runtime can start allocating instance fields for class instances, and CLI tooling can be written to track and monitor runtime memory.

Arrays and UDT are represented in memory by contiguous address space, which was designed with LSet / RSet semantics and 2D Variant arrays in mind.

The allocator is a rather advanced (and thoroughly tested) mechanism with a “fast path” that quickly finds the smallest free memory block that can accept the required bytes, and a “slow path” that can extend program memory space with a new segment as necessary; deallocated memory becomes free blocks that are instantly available to be reused, and then compacting the available space is a feature that’s shelved with a “let’s see how it goes” plan: if the fragmentation of program memory is generally under control, we may get away with no need for compaction – which is a heavy-handed “stop the world” mechanism that moves all allocated pointers to a new address, eliminating unusable fragmented memory space left behind the “current address” pointer. If you know anything about the .net garbage collector (GC), these concepts are nothing new.

Pending work includes unifying address space with stack-allocated locals and parameters: currently only static declarations are allocated.

Milestone: Resolver

With the symbols defined in the host, the next obvious step is to be able to resolve them by name and scope, and that’s another critical milestone knocked down.

Legacy Rubberduck issue #973 remains the final boss here: the goal is to have identifier resolution work exactly to spec, so I expect it to ace every single Thundercode stress-test we throw at it. This cannot be completed however, until the runtime semantics for member access expressions are implemented, but now that all symbols are properly allocated, this is work that’s unlocked now, and will be implemented shortly.

Legacy Rubberduck issue #973 was filed 11 years ago by our dear friend ThunderFrame, and remains the ultimate test case for RDCore’s own resolver. Wherever you are Andrew, you’re still part of the team, and actively helping.

Milestone: Static Semantics

The MS-VBAL specifications distinguish static and runtime semantics, as it should: static semantics are concerned about data types, and the runtime semantics actually do stuff, usually involving side effects in program memory.

Much of the static semantics have been implemented and waiting for this moment for some time, and while statements’ static semantics remain to be written, everything the parser produces can now be resolved, so this milestone is now unlocked and work can theoretically begin on the analysis pipeline.

The planned analysis phase ultimately includes simulated execution, where the runtime semantics are to be exercised, but sandboxed: once this is implemented, we can issue semantic flags for unreachable code, infinite loops, unbounded recursion, and so much more – everything Rubberduck ever dreamed of is becoming reality. RDCore doesn’t guess what the language does, it exercises the code and reports back knowing exactly what the runtime does.

This isn’t just a wish: the RDCore platform was specifically designed to enable this. Becoming the language, it turns out, gives us way more power than understanding the language ever could.

Milestone: Runtime

The runtime milestone hasn’t been the main focus last month, but work on symbol resolution is directly unlocking both static and runtime semantics that need a symbol resolver, such as member access expressions and the Is operator.

This milestone is the real long-haul work that I’ll be turning to, and includes a complete implementation of the standard library, from type conversions to string and date helpers to math and finance, platform-agnostic MsgBox and InputBox functions; the RD-VBA standard library will not be constrained to the Windows operating system.

RD-VBA projects will not be referencing Microsoft’s VBA7.DLL, effectively breaking VBA free from its historical host.

Milestone: Language Server

This milestone has moved forward significantly, and is now ready to be worked on and actively contributed to by adding LSP handlers for the requests and notifications that can be served, as per the available capabilities.

The server is currently acting as the platform’s orchestrator and everything is wired up. As of this writing, the following tickets are up-for-grabs:

More such tickets will be created (many have already been) as the language server and the platform as a whole starts enabling more LSP handlers. Note that foldings are already being provided, as an initial proof of concept and perhaps as a template for the many LSP handlers to come.

Milestone: CLI App

RDCore.CLI runs in various modes, depending on its command-line arguments:

  • Given a ClientProcessId, it acts as the environment host as specified in MS-VBAL.
  • Given a workspace URI, it acts as a LSP client in CLI mode, accepting and executing a command and then tearing down.
  • Given no command-line arguments, it currently exits with an error code – but the plan is for it to run as a lightweight LSP client in program mode; more details to follow.

The interesting part is how it wires up its verbs: the platform discovers its extensions, and extensions can register capabilities that the CLI app understands as CLI commands it can support and forward to the extension that provides it.

This means `rdc –workspace <path> –test` will work exactly as advertised, with the `test` verb provided by an eventual RDCore.UnitTesting extension (planned to ship as the second platform extension, after core diagnostics; will be its own repository). For now though, it means `rdc –new` can create a .rdproj out of any given folder location.


Roadmap: HexIDE Integration

A CLI app with a lightweight LSP client is nice, but a full-fledged IDE is objectively nicer. This is what sunk RD3 and as promised, nothing in RDCore is an IDE.

However

A colleague (@imojenisys) has been working in parallel on her own project – a VB6 IDE that feels just like the VBE (with theming!), but runs a LSP client… and can already interact with the RDCore language server.

Shown: HexIDE Protocol Conversations tab, depicting the LSP initialization handshake and subsequent communications with the RDCore language server, including each message’s payload.

The HexIDE repository has been forked under the rubberduck-vba GitHub organization, and the plan is to position it as the platform’s official IDE, back-contributing any enhancements or features to the upstream repository.


Setting Expectations

It has been clear from the very beginning that RDCore would build MS-VBAL from the ground up and implement it independently of Windows. Historically, VB started the other way around (backwards): from the UI designer as a starting point it went on to events and language design and ultimately to a runtime. RDCore is completely flipping this around, starting with the language core, and UI being a distant future.

This will probably upset the VB community a bit, because how are you a credible VB alternative without a form designer, right?

It’s been over 30 years: if building a VB alternative from the UI working towards a runtime was a viable approach, it would have worked by now. It’s not, and there’s a whole graveyard of abandoned “VB6 IDE” projects out there that did exactly this.

RDCore is different: it deliberately dismisses MSForms, ActiveX, UI designers, and everything that inherently ties it to Windows.

Standard library functions such as MsgBox will have providers that depend on platform configuration settings: the ability to display an interactive dialog will be a host capability like any other, keeping everything sane and safe for headless execution in a CI/CD pipeline.


Forward

The project feels materially different than it did just a month ago. For the first time, newly implemented components primarily unlock more components, not just new architecture. Parser produces an AST, AST produces symbols, symbols get allocated and resolved, and this unlocks real language core and LSP features.

I have no idea what the next update will be like, because things are starting to snowball now. I’ll be working on the runtime semantics for executable statement nodes, primarily: the current epic/objective being to knock down the blockers that will unlock getting an actual interpreter under way, including debugger features (step through , step over, break/continue, etc.) in HexIDE via DAP.

Leave a comment