Devlog: Building Flower’s String Type Foundation
The core goal was to make this work in a meaningful, compiler-owned way:
name: string = "Ivy" as string
raw: @char = name as @char
other: string = raw as string
if name == other:
print("same\n")
end
print(name.length)
That meant Flower needed more than a typedef in generated C. It needed actual type rules, actual lowering rules, and I needed enough hairs on my head to not be bald after the amount of scares that occurred.
What changed
The first step was giving string real compiler support without going too far too fast.
I added support for:
- explicit casts between
stringand@char - string equality / inequality
string.length- runtime helpers in generated C for:
flower_string_from_cstr(...)flower_string_eq(...)flower_print_string(...)
That gave Flower a usable string foundation while still keeping literals conservative for self-hosting. Right now, string literals are not fully “native string values everywhere” yet; the compiler still uses explicit casts like "Ivy" as string as the safe bridge.
The reason for this “safe bridge” is because when I got too ambitious, the compiler would break since everywhere @char was used with a string literal it’d break due to no implicity being allowed.
I had to comment out the following new changes and keep the legacy support so it’d compile:
else if ast.kind == AST_STRING_LIT:
// fprintf(out, "flowe_string_from_cst(")
// fprintf(out, "%.*s", ast.data._string.str_length, src + ast.data._string.str_start)
// fprintf(out, ")")
// LEGACY CODE HERE
and
else if expr.kind == AST_STRING_LIT:
// set_plain_type(out, TOKEN_STRING)
// LEGACY CODE HERE
return 1
The part that broke
The most annoying issue was not string equality or .length. It was print.
Originally, non-string print(...) was basically lowered like this:
printf(expr);
That only works when expr is already a C format string. So something like:
print(name.length)
generated invalid C:
printf(name.length);
The fix was to make print(...) type-aware. Typecheck now records the operand type, and codegen lowers print differently for string, @char, char, floats/doubles, and integer-like values.
That sounds small, but it matters a lot: once string became real, print could no longer get away with pretending every printable value was already a C string.
An Unsolved Bootstrap Mystery
Somehow Flower’s bootstrap process was breaking, and it will probably break again. Despite the bootstrap requiring it to compile itself, somehow afterwords the binary could become corrupted.
l-2: ~/Documents/GitHub/FloC % make bootstrap
=== Building new version ===
Compiled ./bin/Flower_new.c → ./bin/Flower_new
=== Testing new compiler ===
Compiled ./bin/Flower_test.c → ./bin/Flower_test
Verified bootstrap build complete
l-2: ~/Documents/GitHub/FloC % make bootstrap
=== Building new version ===
Luckily, I always make sure to keep a backup Flower bin stored under /bin/Flower_backup so I used that to compile the new binary and then it worked.
Where this leaves v1.3
What still remains is the bigger ergonomic question: how fully native string literals should behave, and how to migrate the compiler’s own source to that world without setting bootstrap on fire again. I’m not sure yet how I want to approach this question, or what the goals for it should even be, but I guess I’ll have to find out soon enough!
That is the next fight. But at least now, it is a fight on solid ground.
Comments 2
That’s pretty funny that your file extension is .flo lol, as that’s the same as my audio format (https://github.com/Audiflo/flo). Probs won’t conflict but kinda funny 🤣
I LOVE the name AudiFlo! Maybe in the future there will be an audiflo.flo library… 😊
Sign in to join the conversation.