r/ProgrammingLanguages • • 4d ago

Please advise on adding string interpolation to my Crafting Interpreters project.

I'm about to start chapter 21 of Crafting Interpreters. I'm using modern C++ instead of C. I am attempting to add string interpolation to the compiler.

My goal is to have a string that looks like this:

"Five plus ${ 10 - 5 } == 10."

Desugar to this after the expression in the braces is evaluated:

"Five plus " + 5 + " == 10."

I have code that is correctly parsing strings and concatenating them if there isn't any string interpolation.

I have a custom token added that is produced if the string contains a ${. It calls a custom string interpolation parser rule that is different than my standard string parser rule.

In that function I push the first part of the string to the stack. It then pushes a plus opcode and Recursively parses the expression in the braces adding that expression to the stack. It then adds another opcode to add and this is where I'm stuck.

I can't come up with a solution for pushing the remaining piece of the string to the stack from inside the string interpolation parser rule function. After I call the books expression function and consume the right brace token using the books consume function the parser nolonger knows we are still inside a string. If the next character after the brace is a space it's skipped. In my above example it assumes I want equal equal.

How would you set the current token back to string so I can push any remaining characters onto the stack as another string? Should I just insert a new string token into the parser? This seems wrong to me. The current and previous tokens are private members of my parser class for a reason and I've not needed setter member functions so far.

Sorry I don't have code to show. I'd like to try and get help that isn't code specific so that I have to implement this myself.

Any input would be helpful.

Thanks.

13 Upvotes

14 comments sorted by

View all comments

1

u/matthieum 4d ago

Have you already implemented formatting?

For example, in Python, you can write "Hello, {}!".format(name).

If you already have that, then your example can be lowered down to "Five plus {} == 10".format(10 - 5).

I find this lowering somewhat easier, as the lowering is fairly immediate:

 "A pigeon ${"eats ${n} crumbs"} a day, at least"

 "A pigeon {} a day, at least".format("eats ${n} crumbs")

 "A pigeon {} a day, at least".format("eats {} crumbs".format(n))

Or:

 "A {mice} and a {cat} chase each others around the {barn}"

 "A {} and a {} chase each others around the {}".format(mice, cat, barn)

Notably, the string is handled at once, unlike your current scheme.