Code Generation: From Tree Back to Text
This level opened with a pipeline: parse, rewrite, regenerate. You have now seen five different rewrites, and every one of them ended at the same final stage without comment. Time to give that stage its due. Code generation, in this source-to-source setting often called printing or unparsing, walks the finished tree and emits source text that any interpreter will accept. It is the mirror image of parsing, and its quirks explain a lot about how transformed code looks.
What the tree remembers
A syntax tree stores structure and nothing else. An assignment node knows its target and its expression. A while node knows its condition and its body. Nowhere in the tree is your blank line between sections, your comment explaining the tax rate, your choice to align three assignments, or the redundant parentheses you added for your own peace of mind. The parser judged all of that irrelevant to meaning and dropped it at the door.
It is like taking dictation of a speech. The transcript keeps every word, but the speaker's pauses, gestures, and handwriting are simply not the kind of thing a transcript stores. When someone later reads the speech aloud from the transcript, they supply their own pacing. A code printer does exactly that with your program.
So when the printer walks the tree, it cannot restore what was never stored. It emits one canonical style: its own indentation, its own spacing, no comments, no blank lines. This is why regenerated code from any source-to-source tool has that unmistakable uniform look, and it happens before any deliberate obfuscation is applied at all. The machine-made look is not a disguise. It is an absence.
Watch text become tree
The tree is the printer's only input, so the best way to build intuition is to see exactly what survives parsing. Edit the code below and watch the tree respond. Add spaces, blank lines, or a comment, and notice the tree does not change at all: the printer regenerating from this tree could never know they were there.
The one thing a printer must never botch
Printing looks trivial, walk the tree and emit words, until precedence enters. The tree for (2 + 4) * 3 has the addition as a child of the multiplication. Print it naively, left child then operator then right child, and you get 2 + 4 * 3, which parses back with the multiplication binding tighter and computes 14 instead of 18. The structure was in the tree, and careless printing lost it in the text.
A correct printer therefore inserts parentheses wherever a child's operator binds more loosely than its parent's, and can skip them everywhere else. That is why regenerated code often has parentheses in different places than you wrote them: yours were dropped at parse time, and the printer re-derives only the necessary ones from the tree's actual shape.
The formal contract is the round trip: parsing the printed text must rebuild exactly the tree that was printed. Printers are tested by feeding programs through parse, print, parse and checking the two trees match, which catches precedence slips, missing braces, and string escaping bugs, the printer's other classic failure, where a quote inside a string must be re-escaped on the way out or the text will not even parse. Real-world printers also choose a point on the spectrum from minimal output, every optional character dropped to save bytes, to pretty output tuned for human reading. Same tree, many faithful texts.
Fix a printer's precedence bug
This program came out of a buggy printer that dropped parentheses it actually needed. The original tree computed the sum first, then multiplied. Repair the text so it matches the original tree's meaning.
The full circle
You can now see the entire journey a program takes through any transforming tool, with no gaps left. Click through every stage below: source text, tokens, tree, a rewrite pass, and finally the printer's regenerated text. This pipeline is the complete architecture of formatters, minifiers, source-to-source compilers, and obfuscators alike. From here on, the course only changes what happens in the rewrite box.
Code generation prints structure, and only structure: comments, spacing, and stylistic choices were never in the tree, which is why regenerated code looks uniform and stripped. The printer's real job is faithfulness, re-deriving parentheses from the tree's shape so the text parses back to the identical tree. With parse, rewrite, and print all understood, you hold the complete machinery that Level 5 attacks and Level 6 weaponises.
Frequently asked questions
If formatting is lost, how do code formatters work at all?
A pure formatter is a parser plus an opinionated printer: it reads your code into a tree and prints it in one house style. Tools that preserve your comments and selected formatting use a heavier design that carries the dropped material alongside the tree and weaves it back in during printing, which is real engineering effort precisely because the plain pipeline discards it.
Does obfuscated output look machine-made because of a deliberate style choice?
Mostly no. The uniform, comment-free, densely printed look is the natural output of any tree printer, and a minifying printer makes it denser still. Deliberate obfuscation adds hostile names and transformed structure on top, but the baseline strangeness is just what regeneration looks like.