PARSERS & TRANSPILERS · TRANSPILER DEVELOPMENT

Transpilers: your codebase rewritten by a machine that understands both languages.

A transpiler translates a whole codebase from one language into another, by rule rather than by hand. The rules are written once, reviewed once, and applied identically to line 1 and line 1,900,000 — which is the only reason moving a system of that size is possible at all.

Hand-rewriting a large legacy system is a project with a famously poor record: a September 2024 Forrester survey, cited by IBM, found that nine in ten rewrite projects fail at the first attempt. The reason is rarely a shortage of talent. It is that a person reading a million lines makes a different decision on Tuesday than on Monday, and there is no way to review a million individual decisions.

A transpiler moves the decisions into one place. You review the rule, not the output of the rule, and when you change your mind you re-run it. The old system keeps running in production the entire time.

A transpiler is a language implementation, not a converter

This distinction decides whether you get a system or a very large pile of code that happens to compile.

SYNTAX CONVERSION

Rewrites the text

WHAT IT MODELS

Tokens and shapes. Pattern in, pattern out, one statement at a time, with no idea what any name in the file refers to.

WHAT COMES OUT

Code in the target language that preserves the structure, the volume and the accidents of the original — including the ones you were migrating to escape.

HOW IT FAILS

Silently. It compiles, it passes the tests you wrote for it, and it disagrees with the old system on the cases nobody thought to test.

LANGUAGE IMPLEMENTATION

Models the semantics

WHAT IT MODELS

Types, scopes, control flow, state and arithmetic behavior. Every name resolved to its declaration before a single line of target code is emitted.

WHAT COMES OUT

Idiomatic code in the target language, tuned against your own codebase until your developers accept it as something they could have written.

HOW IT FAILS

Loudly and early, at a specific line, where you can look at it. That is the whole point of building the semantic layer.

Talk to us about a transpiler →

THE PIPELINE

Five stages, and none of them is optional.

Every transpiler we build has the same spine. The languages change, the rules change, the target architecture changes. The order does not.

01Parse. The source is read by a real parser — column-position rules and all — into a parse tree. For the languages in our catalog this stage is already built and paid for.
02Build the source model. The parse tree becomes a typed abstract syntax tree, and every reference is resolved: a variable to its declaration, a field to the file that defines it, a call to the program it reaches.
03Transform. The source model is mapped onto a model of the target language. This is where the rules live, and where the semantics of the two languages are reconciled rather than assumed to match.
04Generate. The target model is printed as source code, through a library that knows the target language, so the output is formatted and structured the way that language is normally written.
05Verify and re-run. The output is checked against the behavior of the original, the rules are corrected, and the whole codebase is regenerated. Not patched — regenerated.

The middle of it, in the open

Stage 03 is the part clients most often ask to see, because it is where the claim “we translate at the pattern level” either means something or does not. Below is the target model from an RPG-to-Java transpiler we publish as a teaching example: typed classes with names, not a bag of strings, defined on top of our open-source Starlasu framework.

The model, as code

intermediateast.kt

data class GProgram(
    override val name: String,
    val globalVariables:
        MutableList<GGlobalVariable> = mutableListOf(),
    val mainFunction:
        GFunction = GFunction("executeProgram"),
    val otherFunctions:
        MutableList<GFunction> = mutableListOf()
) : Node(), GNamed
Node is the Starlasu base class: it carries positions, parent links and tree traversal, so every downstream tool gets those for free.

The model, as a tree

IntermediateToJavaTest.kt

GProgram name=Test
├── GGlobalVariable NBR : GIntegerType
└── GFunction executeProgram
    └── GAssignment
        ├── GGlobalVariableTarget → NBR
        └── GIntegerLiteral value=123
Every node name here is a class in that repository, and this is the exact model asserted by one of its unit tests. Stage 04 walks a tree of these and emits Java.

Both are from Strumenta/rpg-to-java-transpiler, published alongside the tutorial How to write a transpiler. It is deliberately small and it is not the tooling we run on client work — but the architecture is the same one, and you can read all of it instead of taking our description on trust.

Where the difficulty actually is

Grammar coverage is the part everyone worries about and the part that gets solved. What decides whether the migrated system behaves like the old one is the semantic layer, and in legacy languages it concentrates in three places.

The rule you can review is worth more than the output you cannot. That is the whole argument for building a transpiler instead of hiring forty developers.

Transpilers we have built

“Strumenta’s team demonstrated deep expertise in Transpiler implementation and legacy and modern programming languages. Strumenta expertise in transpiler-based migration strategies was evident throughout the engagement.”

Paulo Jorge DiasDirector Consulting Expert, IT Modernization, CGI

“Strumenta has been a great partner in pursuing our objective of building a custom transpiler. They have been professional and collaborative. I would absolutely recommend them. They have been an excellent business partner, true to their word, consistent in their delivery, and consummate professionals.”

Robin WayFounder and President, Corios LLC

More testimonials are on the clients page, and individual projects are written up as case studies.

Why the Strumenta approach works

Four things make the difference, and all four are checkable rather than adjectival.

What a transpiler does not do for you

Name the pair source language, target language

Tell us what you are translating, and what into.

We will tell you whether we already have an engine for the source, what the semantic hard parts are for that particular pair, and whether a transpiler is the right instrument at all. If it is not, we will say so.

Scroll to Top