Skip to content

Commit

Permalink
Implement string interpolation.
Browse files Browse the repository at this point in the history
Merge pull request #45 from haroldo-ok/string-interpolation
Now it is possible to use print a numeric variable in the middle of a text line by using `${expression}`.
  • Loading branch information
haroldo-ok committed Sep 27, 2022
2 parents 2192188 + 0207676 commit c02a345
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 9 deletions.
13 changes: 7 additions & 6 deletions examples/test/project/startup.choice
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* create boolVar, true
* temp localInt, 2

* set intVar, 3
* set localInt, intVar + 3

* create playingMusic, false
Expand Down Expand Up @@ -33,14 +32,16 @@
* image "Smiley.png", at(30, 3)
OK... showing a smiley!
# Fourth choice
You chose the last one
This is a test.
Second line.
Third line.
* choice
# Yet another choice
You chose this.
# One more choice
You chose that.
# Increment a number
* set intVar, intVar + 1
The value is now ${intVar}!
# Go to another scene
* goto_scene test
This is a test.
Second line.
Third line.
* goto_scene test
18 changes: 16 additions & 2 deletions examples/test/src/vn_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ void VN_init() {
XGM_setLoopNumber(-1);
XGM_setForceDelayDMA(TRUE);

VDP_drawText("choice4genesis v0.4.0", 18, 27);
VDP_drawText("choice4genesis v0.5.0", 18, 27);
}


Expand Down Expand Up @@ -117,11 +117,25 @@ void VN_clearWindow() {
VDP_clearTextAreaEx(BG_A, TILE_ATTR_FULL(PAL0, FALSE, FALSE, FALSE, 0x05A0), window.x, window.y, window.w, window.h, DMA);
}

void VN_text(char *text) {
void VN_textStart() {
if (textBuffer[0]) strcat(textBuffer, "\n");
}

void VN_textString(char *text) {
strcat(textBuffer, text);
}

void VN_textInt(int number) {
char number_buffer[12];
sprintf(number_buffer, "%d", number);
VN_textString(number_buffer);
}

void VN_text(char *text) {
VN_textStart();
VN_textString(text);
}

void VN_flushText() {
if (!textBuffer[0]) return;

Expand Down
3 changes: 3 additions & 0 deletions examples/test/src/vn_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ extern void VN_music(const u8 *music);
extern void VN_sound(const u8 *sound, const u16 length);
extern void VN_stop(const u8 flags);

extern void VN_textStart();
extern void VN_textString(char *text);
extern void VN_textInt(int number);
extern void VN_text(char *text);
extern void VN_flushText();
extern void VN_wait(u16 duration);
Expand Down
13 changes: 13 additions & 0 deletions generator/generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,19 @@ const COMMAND_GENERATORS = {
generateFromBody = (body, context) =>
compact((body || []).map(entity => {
if (entity.type === 'text') {
if (entity.expressions) {
return [
'VN_textStart();',
...entity.expressions.map(o => {
if (o.params && o.params.positional && o.params.positional.expression) {
const expr = getExpression(entity, o.params.positional.expression, context, 'Expression');
return `VN_textInt(${expr.code});`;
}
return `VN_textString("${o}");`;
})
].join('\n');
}

return `VN_text("${entity.text}");`
}
if (entity.type === 'option') {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "choice4genesis",
"version": "0.4.0",
"version": "0.5.0",
"description": "A ChoiceScript clone that generates SGDK-compatible C source for the Sega Genesis ",
"main": "index.js",
"scripts": {
Expand Down
14 changes: 14 additions & 0 deletions parser/syntax-full.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,23 @@ const COMMANDS = {

const COMMAND_PARSERS = Object.fromEntries(Object.entries(COMMANDS).map(([command, config]) => [command, createExpressionParser(config)]));

const stringInterpolationParser = createExpressionParser({ positional: ['expression'] });


const checkOnlyAfter = (body, errors) =>
body.map((element, index) => {
if (element.type === 'text') {
const interpRegex = /\$\{(.*?)\}/g;
const parts = element.text.replace(interpRegex, a => '\n' + a + '\n').split('\n');
if (parts.length > 1 || interpRegex.test(parts[0] || '')) {
const expressions = parts.map(part => interpRegex.test(part) ?
stringInterpolationParser(part.replace(interpRegex, '$1')) :
part);
return { ...element, expressions };
}
return element;
}

if (element.type !== 'command') {
return element;
}
Expand Down

0 comments on commit c02a345

Please sign in to comment.