To summarise wordings into alphanumeric identifiers of the kind used by standard programming languages.
§1. Validity of identifiers.In code compiled by I7, a valid identifier is a sequence of 1 to 31 characters, which must be alphanumeric or else underscores, except that the leading character must not be a 0:
int Identifiers::valid(inchar32_t *p) { if ((Wide::len(p) == 0) || (Wide::len(p) > 31)) return FALSE; for (int i=0; p[i]; i++) if ((Characters::isdigit(p[i]) == 0) && (Characters::isalpha(p[i]) == 0) && (p[i] != '_')) return FALSE; if (Characters::isdigit(p[0])) return FALSE; return TRUE; }
§2. The following flattens characters into shape:
void Identifiers::purify(text_stream *identifier) { LOOP_THROUGH_TEXT(pos, identifier) { inchar32_t x = Str::get(pos); if (!(((x >= '0') && (x <= '9')) || ((x >= 'a') && (x <= 'z')) || ((x >= 'A') && (x <= 'Z')) || (x == '_'))) Str::put(pos, '_'); } }
§3. Automatically composed identifiers.The following routines are no longer used by Inform, but retained in case useful for other projects.
The idea here is that we want an identifier based on a natural language wording, but which passed the above validity tests, and which does not lead to namespace collisions. Such identifiers are composed in a pattern which uses an identifying letter (e.g., A for Action), a unique ID number (preventing name-clashes) and then a truncated alphanumeric-safe form of the words used in the textual description, if any. For example, an object called "apple crumble" might have identifier O100_apple_crumble. Any other object also called "apple crumble" would have a different identifier since the number parts would be different.
Beginning with the identifying letter ensures that we do not open with a 0 digit.
We truncate to 28 characters in length so that other routines can concatenate our identifier with up to 3 further characters, if they choose.
void Identifiers::compose(text_stream *identifier, int nature_character, int id_number, wording W) { Str::clear(identifier); WRITE_TO(identifier, "%c%d", nature_character, id_number); if (Wordings::nonempty(W)) { LOOP_THROUGH_WORDING(j, W) { identifier is at this point 32 chars or fewer in length: add at most 30 more if (Wide::len(Lexer::word_text(j)) > 30) WRITE_TO(identifier, " etc"); else WRITE_TO(identifier, " %N", j); if (Str::len(identifier) > 32) break; } } Str::truncate(identifier, 28); it was at worst 62 chars in size, but is now truncated to 28 Identifiers::purify(identifier); } void Identifiers::compose_numberless(text_stream *identifier, text_stream *prefix, wording W) { Str::copy(identifier, prefix); if (Wordings::nonempty(W)) { LOOP_THROUGH_WORDING(j, W) { identifier is at this point 32 chars or fewer in length: add at most 30 more if (Wide::len(Lexer::word_text(j)) > 30) WRITE_TO(identifier, " etc"); else WRITE_TO(identifier, " %N", j); if (Str::len(identifier) > 32) break; } } Str::truncate(identifier, 28); it was at worst 62 chars in size, but is now truncated to 28 Identifiers::purify(identifier); }