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

Open comments for this post

3h 18m 7s logged

Devlog: Finishing Flower’s String Interop Bridge

The last round got string into Flower as a real type. This round was about making that foundation actually work lol.

The big problem was that once string became real, plain string literals started living in an in-between state: Flower wanted them to mean “Flower string,” but the compiler’s own source still has plenty of places that really mean “raw C string,” like:

RED: @char = "\033[0;31m"

if not strcmp(arg, "help") or not strcmp(arg, "h"):
    ...
end

Those cases worked before only because everything was basically pretending string literals were already @char. Once that stopped being true, bootstrap started throwing a fit (my spoiled child).

What changed

The main fix was to make string literal lowering contextual instead of all-or-nothing.

If a literal is being used as a real Flower string, it stays a string.

If a literal is being used in a C interop position, it gets lowered as a C string instead.

That meant tightening a few compiler rules so this kind of thing works cleanly again:

name: string = "Ivy" as string
raw: @char = name as @char

if strcmp(raw, "Ivy") == 0:
    print(name)
end

I also fixed top-level declarations so globals like:

RED: @char = "\033[0;31m"

no longer generate nonsense like:

char* RED = ((flower_string){ ... });

which, unsurprisingly, C does not appreciate.

The subtle compiler bug

The nastiest issue wasn’t even the globals. It was that builtin C calls like strcmp, strncmp, printf, snprintf, and friends are not real Flower functions.

That meant the typechecker could hit one of them inside a larger expression, fail early, and stop walking the rest of the tree. So something like:

if not strcmp(arg, "help") or not strcmp(arg, "h"):

could partially resolve one side, then leave the other side unprocessed. Very cool. Very stable. Definitely what I wanted.

The fix was to add a temporary builtin C-call bridge so the compiler can recognize these calls well enough to keep type resolution and literal lowering consistent during bootstrap.

I’m not happy with this fix by any means, but due to the limitations of emitting C, it was the only solution I found that made sense at the time.

Tests and examples

Once that stopped exploding, I finally wired string testing into the normal types suite instead of leaving it commented out and pretending I’d “get back to it later.”

The string tests now cover:

  • string <-> @char casts
  • string equality / inequality
  • .length
  • empty strings
  • printing strings
  • literal use in current interop cases

And the full test suite passed with string included as a first-class part of Types on its first try. Now that’s what I like to see :D

What this means

This does not mean Flower’s long-term answer is “hardcode libc into the compiler forever.”

It means Flower now has a temporary interop bridge that keeps self-hosting stable while string is worked on. The actual language semantics stay in Flower; the backend-specific weirdness is just being tolerated for now so progress does not stall. In the near, I’ll probably replace all of the necessary C libs with minimal Flower-equivalents.

Where this leaves v1.3

At this point, the string foundation feels much sturdier.

Not “done forever,” not backend-agnostic, and definitely not free of cursed bootstrap energy — but it works.

The next work is no longer rescue work. It is actual forward work: string operations, stdlib basics, and eventually replacing this temporary C bridge with something cleaner when Flower grows past the C backend.

0
0

Comments 0

No comments yet. Be the first!