You are browsing as a guest. Sign up (or log in) to start making projects!

2h 9m 1s logged

My language now defines a weapon in my shipped game

Phase 1 gave RaidenScript a lexer, parser, resolver, interpreter and REPL. Today it
got a design change of its own, and a way out of the terminal.

TWO KEYWORDS, AND WHY THE FIRST VERSION WAS WEAK

I had one keyword for pulling code in: use. I wanted hardware code to look different
from application code, so I proposed include for boards and import for everything
else. That rule was weak and I want to be honest about why. If include serial and
import math do exactly the same thing, nothing stops anyone writing include math. A
guide the compiler cannot check is not a guide, it is a convention with a syntax bill.

So the difference moved onto something the compiler can enforce:

import   resolved at runtime: std library, a git repo, a pinned version
include  resolved when the host builds you in

include now refuses quoted paths and @ “v0.3.1” version tags outright. On an ESP32
there is no filesystem and nothing to fetch, so a dependency needing the network at
load time simply cannot be an include. Hardware and software separate as a side
effect of a rule about resolution time — that is what earns two keywords instead of
one. A file may use both, and that is the point: that is what a bridge looks like.

29 keywords now, hard-capped at 30 until v1.0. One slot left, and I would rather
leave it empty than spend it on a synonym.

A BUG ONLY TURKISH COULD PRODUCE

Renaming use to import across 20 files, a bulk find-and-replace uppercased an i into
U+0130 — the Turkish dotted capital, because in Turkish that is what the uppercase of
i is. My editor did the case change in my own locale and handed C++ a character it
cannot compile.

The irony is sharp. RaidenScript deliberately accepts UTF-8 identifiers, so a Turkish
variable name is legal in the language I am building. The language I am building it
in has no such patience.

OUT OF THE TERMINAL

Then the embedding work: a C API, a WASM build, and one weapon.

The C API was not the hard part. Lifetime was. Function values hold RAW pointers into
the AST, and a host calls a script function long after loading it — so the VM has to
own the source, the tree and the interpreter, and destroy them in the right order. One
VM, one script; numbers across the boundary, not JSON.

Then WASM aborted on the first return statement. Emscripten disables C++ exceptions by
default, and this interpreter carries return, break and thrown errors on C++
exceptions. -fwasm-exceptions fixes it. The JS-based alternative would mean a trip to
JavaScript on every single function return — unusable for a tree-walker.

And the payoff: STAR BREAKER, the game I shipped last week, now has a weapon whose
definition is not in the game. scripts/plazma.rai holds its damage, fire rate, spread
and the shape of its shot. The engine calls fire(angle), the script calls back with
game.spawnBullet, and the engine makes the bullets. The script only says where.

Rarity, levels, reforges, evolution — all of it still works, untouched. The weapon is
an ordinary table entry that happens to be filled from a language I wrote.

I added a weapon rather than moving one: the game is shipped and its balance measured,
so adding risks nothing. If the WASM fails to load, the weapon simply is not there.

ON THE AI SPLIT

The design is mine — the two keywords, the bridge pattern, the decision to add rather
than move. I wrote the first pass of the rename; AI reviewed it, found what was
missing, and wrote most of the embedding layer with me directing. That is more AI than
my last devlog claimed, and I would rather correct it than let it stand.

Repo (MIT): github.com/RaidenTechnology/raidenscript

0
11

Comments 0

No comments yet. Be the first!