I Taught My Programming Language to Think in Blocks

In Week 22 of Project52, I evolved PebbleLang from a flat, single-line interpreter into a structured, block-aware language by adding support for conditionals and loops. This meant rewriting the parser to detect and group if ... then ... end and repeat ... times: ... end blocks, and updating the interpreter to evaluate nested logic. With these additions, PebbleLang can now make decisions and repeat actions - core capabilities of any real programming language. While still minimal, this version introduces control flow, making the language feel far more expressive and complete.

Last week, I built my own programming language.

It was minimal: plain-English syntax, variable storage, basic math.
You could set x to 5, increase x by 3, and show x.

But that was it.

There were no decisions. No loops. No logic.
The language executed one line after another, like a calculator with a memory.

This week, I gave it structure.

What Changed

In Week 22, I added two features that make any programming language feel real:

  • Conditional execution (if … then … end)

  • Looping (repeat … times: … end)

These additions required a shift in how the interpreter worked. Instead of evaluating one line at a time, PebbleLang now has to understand blocks of code. Blocks that start, end, and sometimes don’t run at all.

That shift made the whole language more alive. It’s no longer just a list of instructions — it’s a series of decisions.

Example: Conditionals and Loops

Here’s a valid PebbleLang program now:

set x to 2 set y to 5 if y is greater than x then show y end repeat 3 times: increase x by 1 show x end

The output is:

5 3 4 5

Line by line:

  • It checks if y > x (5 > 2) — true, so it shows y

  • Then it runs the repeat block 3 times, incrementing and printing x each time

Under the Hood: What Had to Change

To support these features, I rewrote the parser and interpreter to work with nested blocks.

The parser:

  • Detects repeat …: or if … then

  • Groups everything up to the corresponding end

  • Stores those grouped lines as the body of a block

The interpreter:

  • Checks conditions using a simple evaluator

  • Executes block bodies only if the condition is met

  • Tracks loop counts and executes bodies multiple times

The design is primitive. There’s no indentation, no scope, and only a few comparison operators. But it’s solid enough to handle structured logic, and easy enough to modify later.

Why This Matters

This felt like the turning point where PebbleLang started acting like a real language.

I could now write:

  • A conditional branch

  • A loop over multiple lines

  • A reusable structure for future control flow

It’s not Turing-complete, but it’s logically complete for the kinds of thinking humans naturally do.

What I Learned

  • Block parsing forces you to think like a compiler

  • You can do a surprising amount with just if, repeat, and end

  • Line-by-line interpreters break down quickly once you introduce logic

  • You have to choose: will your language care about indentation, tokens, or both?

And most of all:

  • Every new keyword introduces complexity, both for the machine and the human

Adding repeat meant handling scope.
Adding if meant managing branching.
Both required new rules — but rules are what make language feel like language.

What’s Next (Week 23?)

There’s a lot I could do from here:

  • Add while loops or break

  • Add functions (define double n:)

  • Support strings or lists

  • Add indentation-based block detection

But I think I’ll pause PebbleLang for now and let it live where it is:
A small, structured, honest language.

Try It Yourself

To run:

python3 pebble.py example2.peb 

It’s fully open, documented, and under 200 lines of Python.
You can fork it, break it, or turn it into something entirely your own.

Thanks for following along.

This was Week 22 of Project52 —
One tiny language, now slightly smarter.