The code for invoking new segmented substitutions from I7 appears to be one of the more arcane and unstable features of the remaining non-deprecated interfaces between I6 and I7 (I’m going from the dire warnings in the documentation against attempting to use undocumented syntaxes evident in the Standard Rules).
However, there seems to be an outdated ‘supported’ usage still extant in Documentation 27.29, which states:
{-counter:NAME}
{-counter-up:NAME}
{-zero-counter:NAME}
{-counter-makes-array:NAME}create (if one does not already exist) a counter called NAME. This is initially zero, and can be reset back to zero using “{-zero-counter:NAME}”, which expands into no text. The token “{-counter:NAME}” expands into the current value of the counter, as a literal decimal number. The token “{-counter-up:NAME}” does the same, but then also increases it by one. Finally, the token “{-counter-makes-array:NAME}” expands to nothing, but tells Inform to create an “–>” array called “I7_ST_NAME” which includes entries from 0 up to the final value of the NAME counter.
This allows each instance in the source text of a given phrase to have both (i) a unique ID number for that invocation, and (ii) its own word of run-time storage, which can allow it to have a state preserved in between times when it is executed. For example:
To say once only -- beginning say_once_only:
(- {-counter-makes-array:say_once_only}if (I7_ST_say_once_only-->{-counter:say_once_only} == false) {-open-brace} I7_ST_say_once_only-->{-counter-up:say_once_only} = true; -).
To say end once only -- ending say_once_only:
(- {-close-brace} -).
The text and the example imply that {-counter-up:NAME} expands to the literal numeral held in the compiler’s internal counter NAME as well as incrementing the compiler’s counter NAME by 1. However, attempting to compile the example (which fails with a numeral missing from the I6 code where {-counter-up:say_once_only} occurs) and examining Standard Rules and the examples given in 27.30 indicates that this is no longer the case- {-counter-up:NAME} increments the compiler’s internal counter for NAME but no longer expands to any text in the I6 code. The correct version of the above example is therefore now:
To say once only -- beginning say_once_only:
(- {-counter-makes-array:say_once_only}if (I7_ST_say_once_only-->{-counter:say_once_only} == false) {-open-brace} I7_ST_say_once_only-->{-counter:say_once_only}{-counter-up:say_once_only} = true; -).
To say end once only -- ending say_once_only:
(- {-close-brace} -).
As an aside, for anyone interested in this subject, there is also not allowed to be any whitespace before or after the colon in {-counter-up:say_once_only}. {-counter-up :say_once_only} doesn’t compile, but {-counter-up: say_once_only} does compile but doesn’t increment the counter, leading to incorrect I6 code.
Finally, in the more complex example in 27.30 can anyone explain the arcane reason for the insertion of @nop op-codes into the I6 output of the switch statement, and the invocation of a second (flag) array and reference to a say__comp global not mentioned in the documentation. The I7 code given (and the Standard Rules) definitively do NOT compile to the pattern of I6 code suggested in the Documentation:
I7_ST_say_one_of-->2 = I7_SOO_PAR(I7_ST_say_one_of-->2, 4);
switch((I7_ST_say_one_of-->2)%5 - 1) {
0: ... first text ...
1: ... second text ...
2: ... third text ...
3: ... fourth text ...
}
but rather (in the case of e.g. ‘say “[one of]one pig[or]two pigs[or]three pigs[or]four pigs[purely at random]!”;’) to the following (cleaned up of confusing comments and layout):
say__p=1;
ParaContent();
if (I7_ST_say_one_flag-->2 == false) {
I7_ST_say_one_of-->2 = I7_SOO_PAR(I7_ST_say_one_of-->2, 4);
I7_ST_say_one_flag-->2 = true;
}
if (say__comp == false) I7_ST_say_one_flag-->2 = false;
switch ((I7_ST_say_part_of-->2)%(4+1)-1)
{
0: ParaContent(); print "one pig"; ParaContent(); @nop;
1: ParaContent(); print "two pigs"; ParaContent(); @nop;
2: ParaContent(); print "three pigs"; ParaContent(); @nop;
3: ParaContent(); print "four pigs"; ParaContent();
}
ParaContent(); print "!"; new_line;