tmedwards / sugarcube-2

SugarCube is a free (gratis and libre) story format for Twine/Twee.
https://www.motoslave.net/sugarcube/2/
BSD 2-Clause "Simplified" License
177 stars 41 forks source link

Problem: quoted strings don't fully evaluate array indices #35

Closed selden closed 4 years ago

selden commented 4 years ago

See the inline comments in the code below and the attached screengrab showing the problem.

:: Start
<<silently>> /* used just to make the screen readable */
/*
 * Problem:
 * When indirect indexing is used within a quoted string
 * the index doesn't get properly evaluated.
 * 
 * Trying to be more specific in my description:
 *
 * If one has an array of indices ( _pIndex below),
 * and uses another index ( _i below)
 * to obtain from that array the desired index into
 * another array ($pasageName below)
 * then quoted strings containing them get very confused.
 *
 * Instead of displaying the single desired element of the array,
 * the quoted string incorrectly contains the contents of the entire array
 * followed by the desired index in brackets.
 *
 * However, if one uses an intermediate variable ( _myIndex below)
 * the quoted string is OK.
 *
 * In other words, quoted strings work fine
 * when they are provided with an array indexed by just a single variable.
 *
 * I believe quoted strings should be able to work with an "indirect" index
 * just as link references do.
 *
 */

/* the code below demonstrates this problem with quoted strings
 * in both link and print statements.
 */

/* create an array containing 3 indices */

<<set _pIndex = [] >>
<<set _pIndex[0] = 1 >>
<<set _pIndex[1] = 3 >>
<<set _pIndex[2] = 5 >>

/* now attempt to link to and list the passageNames
 * corresponding to those 3 indices
 */

<</silently>>

/* indirect indexing in this "for" loop fails in quoted strings */
incorrect:
<<for _i = 0; _i<3; _i++>>
link:      <<link "passage # _pIndex[_i] = $passageName[_pIndex[_i]]" $passageName[_pIndex[_i]]>> <</link>>
print:     <<print "$passageName[_pIndex[_i]]">>
<</for>>

/* but using an intermediate variable works fine with quoted strings in both link and print */
correct:
<<for _i = 0; _i<3; _i++>>
          <<set _myIndex = _pIndex[_i]>>
link:     <<link "passage # _myIndex = $passageName[_myIndex]" $passageName[_pIndex[_i]]>> <</link>>
print:    <<print "$passageName[_myIndex]">>
<</for>>

----
''Story Compiler:'' <<= $('tw-storydata').attr('creator') + " v" + $('tw-storydata').attr('creator-version')>>
''Story Format:'' <<= $('tw-storydata').attr('format') + " v" + $('tw-storydata').attr('format-version')>>
''Browser:'' <<= navigator.userAgent>>

/* the corresponding passages */

:: upright0
!! Passage  upright0

:: upright1
!! Passage  upright1

:: upright2
!! Passage  upright2

:: reversed3
!! Passage  reversed3

:: upright4
!! Passage  upright4

:: upright5
!! Passage  upright5

:: upright6
!! Passage  upright6

:: StoryInit

/* create an array of passage names
 *
 * I'm aware I could do the initialization with a single set command
 * but using explicit index numbers helps me to understand
 * what I want to be happening.
 */

<<set $passageName = []>>
<<set $passageName[0] = "upright0">>
<<set $passageName[1] = "upright1">>
<<set $passageName[2] = "upright2">>
<<set $passageName[3] = "reversed3">>
<<set $passageName[4] = "upright4">>
<<set $passageName[5] = "upright5">>
<<set $passageName[6] = "upright6">>

:: StoryData
{
        "ifid": "C31A5464-60FC-4937-A550-C7D75F7692AF"
}

:: StoryTitle
Test Indexing

test_indexing

tmedwards commented 4 years ago

You have two problems:

  1. You're attempting to use the naked variable markup in ways that it does not support—as you can see if you look carefully at the output.
  2. You're passing a bare expression to a macro as an argument.

You didn't show what you were actually attempting to do, so I can't provide a specific recommendation for that. Instead, here's a corrected version of your demonstration example using backquote expressions, which hopefully makes clear what you should be doing: (line-broken for clarity)

<<link
    `"passage #" + _pIndex[_i] + " = " + $passageName[_pIndex[_i]]`
    `$passageName[_pIndex[_i]]`
>><</link>>

SEE: