2022-02-03 21:44:57 +02:00
|
|
|
[InterSymbol::] Symbols.
|
2019-02-05 02:44:07 +02:00
|
|
|
|
|
|
|
To manage named symbols in inter code.
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
@h Creation.
|
|
|
|
Each symbol belongs to exactly one symbols table, and thus to exactly one
|
|
|
|
package; its ID is unique within that table, and therefore package.
|
|
|
|
|
|
|
|
Given that design, it might seem a cleaner solution simply to make the
|
|
|
|
|symbol_array| of a symbols table be an array of |inter_symbol| structures,
|
|
|
|
rather than (as it actually is) an array of |inter_symbol *| pointers which
|
|
|
|
point to |inter_symbol| structures stored elsewhere. However:
|
|
|
|
|
|
|
|
(a) It makes binary loading easier to use this indirection, and
|
|
|
|
(b) It means that pointers to symbols remain valid when symbols tables expand
|
|
|
|
and then have to dynamically resize their |symbol_array| arrays, which may
|
|
|
|
in some cases move them in memory.
|
|
|
|
|
|
|
|
This all means we have to be careful. The following statements are true:
|
|
|
|
|
|
|
|
(1) Symbols are created only by symbols tables, and only as a response to
|
|
|
|
the "creating" version of name lookups.
|
|
|
|
(2) No symbol is ever moved from one table to another.
|
|
|
|
(3) No symbol ever occurs more than once in any table.
|
|
|
|
(4) No symbol ever occurs in more than one table.
|
|
|
|
|
|
|
|
But this is false:
|
|
|
|
|
|
|
|
(5) Every symbol belongs to a table.
|
|
|
|
|
|
|
|
Although it is true that every symbol is created in a table, it might later
|
|
|
|
be struck out with the //InterSymbolsTable::remove_symbol// function. If so,
|
|
|
|
it cannot be reinserted into that or any other table: it is gone forever.
|
2019-02-05 02:44:07 +02:00
|
|
|
|
|
|
|
=
|
|
|
|
typedef struct inter_symbol {
|
|
|
|
struct inter_symbols_table *owning_table;
|
2022-02-04 02:55:12 +02:00
|
|
|
inter_ti symbol_ID;
|
|
|
|
int symbol_status;
|
2022-02-14 01:44:50 +02:00
|
|
|
struct text_stream *identifier;
|
2022-02-04 02:55:12 +02:00
|
|
|
|
2019-07-24 20:15:07 +03:00
|
|
|
struct inter_tree_node *definition;
|
2022-02-04 02:55:12 +02:00
|
|
|
struct inter_annotation_set annotations;
|
2022-01-04 01:40:23 +02:00
|
|
|
struct wiring_data wiring;
|
2022-02-04 02:55:12 +02:00
|
|
|
struct transmigration_data transmigration;
|
2021-08-06 21:48:18 +03:00
|
|
|
struct general_pointer translation_data;
|
2019-02-05 02:44:07 +02:00
|
|
|
} inter_symbol;
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
@ For the reasons given above, this function must only be called from
|
|
|
|
//InterSymbolsTable::search_inner//. If what you want is just to create a
|
|
|
|
symbol with a particular name, call //InterSymbolsTable::symbol_from_name_creating//,
|
|
|
|
not this.
|
|
|
|
|
|
|
|
Note that any symbol whose name matches //Metadata::valid_key// is made a
|
|
|
|
metadata symbol: in practice that means if its name begins with |^|.
|
2019-02-05 02:44:07 +02:00
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
=
|
|
|
|
inter_symbol *InterSymbol::new_for_symbols_table(text_stream *name, inter_symbols_table *T,
|
|
|
|
inter_ti ID) {
|
|
|
|
if (Str::len(name) == 0) internal_error("proposed symbol has empty name");
|
|
|
|
if (ID < SYMBOL_BASE_VAL) internal_error("proposed symbol ID invalid");
|
|
|
|
|
|
|
|
inter_symbol *S = CREATE(inter_symbol);
|
|
|
|
S->owning_table = T;
|
|
|
|
S->symbol_ID = ID;
|
|
|
|
S->symbol_status = 0;
|
2022-02-14 01:44:50 +02:00
|
|
|
S->identifier = Str::duplicate(name);
|
2022-02-04 02:55:12 +02:00
|
|
|
|
|
|
|
if (Metadata::valid_key(name)) InterSymbol::make_metadata_key(S);
|
|
|
|
else InterSymbol::make_miscellaneous(S);
|
|
|
|
|
|
|
|
S->definition = NULL;
|
2022-02-05 14:27:28 +02:00
|
|
|
S->annotations = SymbolAnnotation::new_annotation_set();
|
2022-02-04 02:55:12 +02:00
|
|
|
S->wiring = Wiring::new_wiring_data(S);
|
2022-02-06 03:12:01 +02:00
|
|
|
S->transmigration = Transmigration::new_transmigration_data(S);
|
2022-02-04 02:55:12 +02:00
|
|
|
S->translation_data = NULL_GENERAL_POINTER;
|
|
|
|
|
|
|
|
LOGIF(INTER_SYMBOLS, "Created symbol $3 in $4\n", S, T);
|
|
|
|
return S;
|
2019-02-05 02:44:07 +02:00
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
@ =
|
2022-02-03 21:44:57 +02:00
|
|
|
inter_package *InterSymbol::package(inter_symbol *S) {
|
2022-02-03 17:51:44 +02:00
|
|
|
if (S == NULL) return NULL;
|
|
|
|
return InterSymbolsTable::package(S->owning_table);
|
|
|
|
}
|
|
|
|
|
2022-02-07 00:33:07 +02:00
|
|
|
int InterSymbol::defined_inside(inter_symbol *S, inter_package *M) {
|
|
|
|
inter_package *P = InterSymbol::package(S);
|
|
|
|
while (P) {
|
|
|
|
if (P == M) return TRUE;
|
|
|
|
P = InterPackage::parent(P);
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
@ This is used only as a final criterion in sorting algorithms for symbols.
|
|
|
|
It assumes no table contains more than 100,000 symbols, which I think is a
|
|
|
|
pretty safe assumption, but in fact a violation of this would make no real
|
|
|
|
difference.
|
|
|
|
|
|
|
|
=
|
|
|
|
int InterSymbol::sort_number(const inter_symbol *S) {
|
|
|
|
if (S == NULL) return 0;
|
|
|
|
return 100000 * (S->owning_table->allocation_id) +
|
|
|
|
(int) (S->symbol_ID - SYMBOL_BASE_VAL);
|
2022-02-03 21:44:57 +02:00
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
@h Status.
|
|
|
|
The //inter_symbol// structure could not really be called concise, but we
|
|
|
|
do make some effort, by packing various flags into a single |symbol_status| field.
|
|
|
|
|
2022-02-04 12:04:41 +02:00
|
|
|
First, the "type" of a symbol is enumerated in these 3 bits:
|
2022-02-04 02:55:12 +02:00
|
|
|
|
2022-02-04 12:04:41 +02:00
|
|
|
@d MISC_ISYMT 0x00000000
|
|
|
|
@d PLUG_ISYMT 0x00000001
|
|
|
|
@d SOCKET_ISYMT 0x00000002
|
|
|
|
@d LABEL_ISYMT 0x00000003
|
|
|
|
@d LOCAL_ISYMT 0x00000004
|
2022-02-04 02:55:12 +02:00
|
|
|
|
2022-02-04 12:04:41 +02:00
|
|
|
@d SYMBOL_TYPE_STATUS_MASK 0x00000007
|
2022-02-04 02:55:12 +02:00
|
|
|
|
|
|
|
=
|
2022-02-03 21:44:57 +02:00
|
|
|
int InterSymbol::get_type(inter_symbol *S) {
|
2022-02-04 02:55:12 +02:00
|
|
|
return S->symbol_status & SYMBOL_TYPE_STATUS_MASK;
|
2019-07-26 10:59:23 +03:00
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
void InterSymbol::set_type(inter_symbol *S, int V) {
|
|
|
|
S->symbol_status = S->symbol_status - (S->symbol_status & SYMBOL_TYPE_STATUS_MASK) + V;
|
2019-07-26 10:59:23 +03:00
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
@ Subsequent bits are used for miscellaneous persistent flags, and then after
|
|
|
|
that for some transient flags:
|
2019-02-05 02:44:07 +02:00
|
|
|
|
2022-02-04 12:04:41 +02:00
|
|
|
@d MAKE_NAME_UNIQUE_ISYMF 0x00000008
|
2022-04-19 02:29:00 +03:00
|
|
|
@d PERMIT_NAME_CLASH_ISYMF 0x00000010
|
|
|
|
@d METADATA_KEY_ISYMF 0x00000020
|
2022-02-04 02:55:12 +02:00
|
|
|
|
2022-04-19 02:29:00 +03:00
|
|
|
@d SYMBOL_FLAGS_STATUS_MASK 0x00000038
|
2022-02-04 02:55:12 +02:00
|
|
|
|
2022-04-19 02:29:00 +03:00
|
|
|
@d TRAVERSE_MARK_ISYMF 0x00000040
|
|
|
|
@d ATTRIBUTE_MARK_ISYMF 0x00000080
|
|
|
|
@d USED_MARK_ISYMF 0x00000100
|
|
|
|
@d SPECULATIVE_ISYMF 0x00000200
|
2022-02-04 02:55:12 +02:00
|
|
|
|
|
|
|
=
|
|
|
|
int InterSymbol::get_flag(inter_symbol *S, int f) {
|
|
|
|
if (S == NULL) internal_error("no symbol");
|
|
|
|
return (S->symbol_status & f)?TRUE:FALSE;
|
2019-07-26 10:59:23 +03:00
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
void InterSymbol::set_flag(inter_symbol *S, int f) {
|
|
|
|
if (S == NULL) internal_error("no symbol");
|
|
|
|
S->symbol_status = S->symbol_status | f;
|
2019-02-05 02:44:07 +02:00
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
void InterSymbol::clear_flag(inter_symbol *S, int f) {
|
2019-02-05 02:44:07 +02:00
|
|
|
if (S == NULL) internal_error("no symbol");
|
2022-02-04 02:55:12 +02:00
|
|
|
if (S->symbol_status & f) S->symbol_status = S->symbol_status - f;
|
2019-02-05 02:44:07 +02:00
|
|
|
}
|
|
|
|
|
2022-02-14 01:44:50 +02:00
|
|
|
@ These are used when reading and writing binary Inter files: because of course
|
|
|
|
the data in the flags must persist when files are written out and read back again.
|
|
|
|
|
|
|
|
=
|
|
|
|
int InterSymbol::get_persistent_flags(inter_symbol *S) {
|
|
|
|
if (S == NULL) internal_error("no symbol");
|
|
|
|
return S->symbol_status & SYMBOL_FLAGS_STATUS_MASK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InterSymbol::set_persistent_flags(inter_symbol *S, int x) {
|
|
|
|
if (S == NULL) internal_error("no symbol");
|
|
|
|
S->symbol_status =
|
|
|
|
(S->symbol_status & (~SYMBOL_FLAGS_STATUS_MASK)) | (x & SYMBOL_FLAGS_STATUS_MASK);
|
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
@ Transient flags convey no lasting meaning: they're used as workspace during
|
|
|
|
optimisations. The part of the word which must be preserved is:
|
|
|
|
|
2022-02-04 12:04:41 +02:00
|
|
|
@d NONTRANSIENT_SYMBOL_BITS (SYMBOL_FLAGS_STATUS_MASK + SYMBOL_TYPE_STATUS_MASK)
|
2022-02-04 02:55:12 +02:00
|
|
|
|
|
|
|
=
|
|
|
|
void InterSymbol::clear_transient_flags(inter_symbol *S) {
|
|
|
|
S->symbol_status = (S->symbol_status) & NONTRANSIENT_SYMBOL_BITS;
|
|
|
|
}
|
|
|
|
|
|
|
|
@h Various sorts of symbol.
|
|
|
|
By far the most common symbols are the miscellaneous ones, which are destined
|
2022-02-04 12:04:41 +02:00
|
|
|
to be defined as constants, variables and the like.
|
2022-02-04 02:55:12 +02:00
|
|
|
|
|
|
|
=
|
|
|
|
void InterSymbol::make_miscellaneous(inter_symbol *S) {
|
|
|
|
InterSymbol::set_type(S, MISC_ISYMT);
|
|
|
|
}
|
|
|
|
|
2022-02-04 12:04:41 +02:00
|
|
|
int InterSymbol::misc_but_undefined(inter_symbol *S) {
|
|
|
|
if ((S) &&
|
|
|
|
(InterSymbol::get_type(S) == MISC_ISYMT) &&
|
|
|
|
(InterSymbol::is_defined(S) == FALSE))
|
|
|
|
return TRUE;
|
|
|
|
return FALSE;
|
2022-02-04 02:55:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@ Symbols whose names begin |^| are metadata keys. Those should always be defined
|
|
|
|
as constants, cannot be wired, and are never compiled. See //Metadata// for more.
|
|
|
|
|
|
|
|
=
|
|
|
|
int InterSymbol::is_metadata_key(inter_symbol *S) {
|
|
|
|
return InterSymbol::get_flag(S, METADATA_KEY_ISYMF);
|
|
|
|
}
|
|
|
|
|
|
|
|
void InterSymbol::make_metadata_key(inter_symbol *S) {
|
|
|
|
InterSymbol::set_type(S, MISC_ISYMT);
|
|
|
|
InterSymbol::set_flag(S, METADATA_KEY_ISYMF);
|
|
|
|
}
|
|
|
|
|
|
|
|
@ Labels are special symbols used to mark positions in function bodies to which
|
|
|
|
execution of code can jump. Their names must begin with a |.|.
|
|
|
|
|
|
|
|
=
|
|
|
|
int InterSymbol::is_label(inter_symbol *S) {
|
2022-02-04 12:04:41 +02:00
|
|
|
if ((S) && (InterSymbol::get_type(S) == LABEL_ISYMT)) return TRUE;
|
|
|
|
return FALSE;
|
2022-02-04 02:55:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void InterSymbol::make_label(inter_symbol *S) {
|
2022-02-14 01:44:50 +02:00
|
|
|
if (Str::get_first_char(InterSymbol::identifier(S)) != '.')
|
2022-02-04 02:55:12 +02:00
|
|
|
internal_error("not a label name");
|
|
|
|
InterSymbol::set_type(S, LABEL_ISYMT);
|
|
|
|
S->definition = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
@ Local variable names behave very similarly, but have no naming convention.
|
|
|
|
|
|
|
|
=
|
|
|
|
int InterSymbol::is_local(inter_symbol *S) {
|
2022-02-04 12:04:41 +02:00
|
|
|
if ((S) && (InterSymbol::get_type(S) == LOCAL_ISYMT)) return TRUE;
|
|
|
|
return FALSE;
|
2022-02-04 02:55:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void InterSymbol::make_local(inter_symbol *S) {
|
2022-02-04 12:04:41 +02:00
|
|
|
InterSymbol::set_type(S, LOCAL_ISYMT);
|
2022-02-04 02:55:12 +02:00
|
|
|
S->definition = NULL;
|
2019-02-05 02:44:07 +02:00
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
@ Connectors are symbols used either as plugs or sockets. These only appear
|
|
|
|
in one special package, and are used to link different trees together.
|
2022-02-06 03:12:01 +02:00
|
|
|
See //The Wiring//.
|
2022-02-04 02:55:12 +02:00
|
|
|
|
|
|
|
=
|
2022-02-04 12:04:41 +02:00
|
|
|
int InterSymbol::is_plug(inter_symbol *S) {
|
|
|
|
if ((S) && (InterSymbol::get_type(S) == PLUG_ISYMT)) return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InterSymbol::make_plug(inter_symbol *S) {
|
|
|
|
InterSymbol::set_type(S, PLUG_ISYMT);
|
|
|
|
S->definition = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
int InterSymbol::is_socket(inter_symbol *S) {
|
|
|
|
if ((S) && (InterSymbol::get_type(S) == SOCKET_ISYMT)) return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InterSymbol::make_socket(inter_symbol *S) {
|
|
|
|
InterSymbol::set_type(S, SOCKET_ISYMT);
|
|
|
|
S->definition = NULL;
|
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
int InterSymbol::is_connector(inter_symbol *S) {
|
2022-02-04 12:04:41 +02:00
|
|
|
if ((InterSymbol::is_plug(S)) || (InterSymbol::is_socket(S))) return TRUE;
|
2022-02-04 02:55:12 +02:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2022-02-04 12:04:41 +02:00
|
|
|
@ A symbol is "private" if it cannot be seen from outside the package, that is,
|
|
|
|
if no external symbol is allowed to be wired to it. For example, local variables
|
|
|
|
in a function body have this property.
|
|
|
|
|
|
|
|
=
|
|
|
|
int InterSymbol::private(inter_symbol *S) {
|
|
|
|
if (InterSymbol::get_type(S) == LABEL_ISYMT) return TRUE;
|
|
|
|
if (InterSymbol::get_type(S) == LOCAL_ISYMT) return TRUE;
|
|
|
|
if (InterSymbol::is_metadata_key(S)) return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
@h Definition of a symbol.
|
|
|
|
When created, a symbol is "undefined": it has no meaning as yet, though it is
|
|
|
|
usually given one very soon after creation. Even then, though, definitions are
|
|
|
|
sometimes changed later on.
|
|
|
|
|
|
|
|
Giving a symbol a definition says that it means something right here, in the
|
|
|
|
package to which it belongs. The alternative is to wire it, which says that the
|
2022-02-06 03:12:01 +02:00
|
|
|
meaning is far away, in another package: see //The Wiring//.
|
2022-02-04 02:55:12 +02:00
|
|
|
|
|
|
|
A definition in this sense is a pointer to an //inter_tree_node// holding an
|
|
|
|
instruction which creates the symbol. For example, the definition of |magic_number|
|
|
|
|
might be the node holding the instruction:
|
|
|
|
= (text as Inter)
|
|
|
|
constant magic_number K_int32 = 27
|
|
|
|
=
|
|
|
|
|
|
|
|
=
|
2022-02-03 21:44:57 +02:00
|
|
|
void InterSymbol::define(inter_symbol *S, inter_tree_node *P) {
|
2019-02-05 02:44:07 +02:00
|
|
|
if (S == NULL) internal_error("tried to define null symbol");
|
|
|
|
S->definition = P;
|
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
void InterSymbol::undefine(inter_symbol *S) {
|
|
|
|
if (S) InterSymbol::define(S, NULL);
|
|
|
|
}
|
|
|
|
|
2022-02-03 21:44:57 +02:00
|
|
|
inter_tree_node *InterSymbol::definition(inter_symbol *S) {
|
2019-02-05 02:44:07 +02:00
|
|
|
if (S == NULL) internal_error("tried to find definition of null symbol");
|
|
|
|
return S->definition;
|
|
|
|
}
|
|
|
|
|
2022-02-03 21:44:57 +02:00
|
|
|
int InterSymbol::is_defined(inter_symbol *S) {
|
2019-02-05 02:44:07 +02:00
|
|
|
if (S == NULL) return FALSE;
|
2022-02-03 21:44:57 +02:00
|
|
|
if (InterSymbol::definition(S)) return TRUE;
|
2019-02-05 02:44:07 +02:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
@ This is rather more violent than simply undefining |S|. It does do that,
|
|
|
|
but also deletes the instruction which had defined |S| from the tree entirely.
|
2019-05-05 16:54:24 +03:00
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
Note that it does not go to the even more extreme lengths of removing the
|
|
|
|
symbol from the symbols table. For that, see //InterSymbolsTable::remove_symbol//,
|
|
|
|
but see also the warnings attached to it.
|
2021-05-03 16:39:21 +03:00
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
=
|
2022-02-03 21:44:57 +02:00
|
|
|
void InterSymbol::strike_definition(inter_symbol *S) {
|
2019-02-05 02:44:07 +02:00
|
|
|
if (S) {
|
2022-02-03 21:44:57 +02:00
|
|
|
inter_tree_node *D = InterSymbol::definition(S);
|
2022-01-27 01:59:02 +02:00
|
|
|
if (D) NodePlacement::remove(D);
|
2022-02-03 21:44:57 +02:00
|
|
|
InterSymbol::undefine(S);
|
2019-02-05 02:44:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
@ Symbols which define integer constants occasionally need to be evaluated or
|
|
|
|
modified, which of course means looking into their defining instructions.
|
2019-02-05 02:44:07 +02:00
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
=
|
|
|
|
int InterSymbol::evaluate_to_int(inter_symbol *S) {
|
|
|
|
inter_tree_node *P = InterSymbol::definition(S);
|
2022-03-14 00:08:41 +02:00
|
|
|
if (Inode::is(P, CONSTANT_IST))
|
2022-03-01 02:41:22 +02:00
|
|
|
return ConstantInstruction::evaluate_to_int(S);
|
2022-02-04 02:55:12 +02:00
|
|
|
return -1;
|
2019-02-05 02:44:07 +02:00
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
void InterSymbol::set_int(inter_symbol *S, int N) {
|
|
|
|
inter_tree_node *P = InterSymbol::definition(S);
|
2022-03-14 00:08:41 +02:00
|
|
|
if ((Inode::is(P, CONSTANT_IST)) && (ConstantInstruction::set_int(S, N))) return;
|
2022-05-01 16:47:54 +03:00
|
|
|
if (P == NULL) LOG("Symbol $3 is undefined\n", S);
|
|
|
|
LOG("Symbol $3 cannot be set to %d\n", S, N);
|
2022-02-04 02:55:12 +02:00
|
|
|
internal_error("unable to set symbol");
|
2019-02-05 02:44:07 +02:00
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
@ A symbol wired to something in another package, or a plug -- which is not
|
|
|
|
yet wired, but will be later on, when linking takes place -- has no definition
|
|
|
|
in the current package. So:
|
2019-02-05 02:44:07 +02:00
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
=
|
|
|
|
int InterSymbol::defined_elsewhere(inter_symbol *S) {
|
|
|
|
if (S == NULL) return FALSE;
|
|
|
|
if (Wiring::is_wired(S)) return TRUE;
|
2022-02-04 12:04:41 +02:00
|
|
|
if (InterSymbol::get_type(S) == PLUG_ISYMT) return TRUE;
|
2022-02-04 02:55:12 +02:00
|
|
|
return FALSE;
|
2019-02-05 02:44:07 +02:00
|
|
|
}
|
|
|
|
|
2022-02-14 01:44:50 +02:00
|
|
|
@h Identifier name.
|
|
|
|
|
|
|
|
=
|
|
|
|
text_stream *InterSymbol::identifier(inter_symbol *S) {
|
|
|
|
if (S == NULL) return NULL;
|
|
|
|
return S->identifier;
|
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
@h Translation.
|
|
|
|
Any symbol can be marked with a "translation", which is the textual identifier
|
|
|
|
to use when compiling final code which refers to it. For example, if our
|
|
|
|
example constant is defined by:
|
|
|
|
= (text as Inter)
|
|
|
|
constant magic_number K_int32 = 27
|
|
|
|
=
|
|
|
|
then its translated form would normally just be |"magic_number"| -- the same
|
|
|
|
as its identifier name in Inter. Any Inform 6 code generated to refer to this
|
|
|
|
might then read:
|
|
|
|
= (text as Inform 6)
|
|
|
|
print "The magic number is ", magic_number, ".";
|
|
|
|
=
|
|
|
|
But if the |magic_number| had been given the translation text |"SHAZAM"|, that
|
|
|
|
same Inter would compile instead to:
|
|
|
|
= (text as Inform 6)
|
|
|
|
print "The magic number is ", SHAZAM, ".";
|
|
|
|
=
|
2019-02-05 02:44:07 +02:00
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
There is something a little disorienting about storing this data as part of
|
|
|
|
an //inter_symbol//. One might reasonably say: It's no business of the Inter
|
|
|
|
tree what the //final// module chooses to call its identifiers, and anyway,
|
|
|
|
maybe the target language compiled to doesn't even have identifiers in any
|
|
|
|
recognisable way, or insists that they follow COBOL naming conventions, or
|
|
|
|
something equally annoying.
|
|
|
|
|
|
|
|
However, we have to store translations within the Inter tree because the
|
|
|
|
Inform 7 language includes low-level features which cannot be expressed any
|
|
|
|
other way:
|
|
|
|
= (text as Inform 7)
|
|
|
|
The tally is a number that varies.
|
|
|
|
The tally translates into Inter as "SHAZAM".
|
|
|
|
=
|
|
|
|
In order for this instruction to reach the //final// code generators, this
|
|
|
|
data clearly has to be expressed in the Inter tree. Well, this is where.
|
2019-06-11 21:12:34 +03:00
|
|
|
|
2022-02-14 01:44:50 +02:00
|
|
|
With that apologia out of the way, the translation text is held in the
|
|
|
|
annotation |_translation|:
|
2019-02-05 02:44:07 +02:00
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
=
|
|
|
|
void InterSymbol::set_translate(inter_symbol *S, text_stream *identifier) {
|
|
|
|
if (S == NULL) internal_error("no symbol");
|
2022-03-22 01:44:15 +02:00
|
|
|
if (InterSymbol::is_metadata_key(S) == FALSE)
|
|
|
|
SymbolAnnotation::set_t(InterPackage::tree(InterSymbol::package(S)),
|
|
|
|
InterSymbol::package(S), S, TRANSLATION_IANN, identifier);
|
2019-02-05 02:44:07 +02:00
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
text_stream *InterSymbol::get_translate(inter_symbol *S) {
|
|
|
|
if (S == NULL) internal_error("no symbol");
|
2022-02-14 01:44:50 +02:00
|
|
|
return SymbolAnnotation::get_t(S,
|
|
|
|
InterPackage::tree(InterSymbol::package(S)), TRANSLATION_IANN);
|
2019-02-05 02:44:07 +02:00
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
text_stream *InterSymbol::trans(inter_symbol *S) {
|
|
|
|
if (S == NULL) return NULL;
|
|
|
|
if (InterSymbol::get_translate(S)) return InterSymbol::get_translate(S);
|
2022-02-14 01:44:50 +02:00
|
|
|
return InterSymbol::identifier(S);
|
2019-02-05 02:44:07 +02:00
|
|
|
}
|
|
|
|
|
2022-10-10 01:26:03 +03:00
|
|
|
@h Replacement.
|
|
|
|
|
|
|
|
=
|
|
|
|
void InterSymbol::set_replacement(inter_symbol *S, text_stream *from) {
|
|
|
|
if (S == NULL) internal_error("no symbol");
|
|
|
|
if (InterSymbol::is_metadata_key(S) == FALSE)
|
|
|
|
SymbolAnnotation::set_t(InterPackage::tree(InterSymbol::package(S)),
|
|
|
|
InterSymbol::package(S), S, REPLACING_IANN, from);
|
|
|
|
}
|
|
|
|
|
|
|
|
text_stream *InterSymbol::get_replacement(inter_symbol *S) {
|
|
|
|
if (S == NULL) internal_error("no symbol");
|
|
|
|
return SymbolAnnotation::get_t(S,
|
|
|
|
InterPackage::tree(InterSymbol::package(S)), REPLACING_IANN);
|
|
|
|
}
|
|
|
|
|
2022-10-13 01:53:21 +03:00
|
|
|
@h Namespace.
|
|
|
|
|
|
|
|
=
|
|
|
|
void InterSymbol::set_namespace(inter_symbol *S, text_stream *from) {
|
|
|
|
if (S == NULL) internal_error("no symbol");
|
|
|
|
if (InterSymbol::is_metadata_key(S) == FALSE)
|
|
|
|
SymbolAnnotation::set_t(InterPackage::tree(InterSymbol::package(S)),
|
|
|
|
InterSymbol::package(S), S, NAMESPACE_IANN, from);
|
|
|
|
}
|
|
|
|
|
|
|
|
text_stream *InterSymbol::get_namespace(inter_symbol *S) {
|
|
|
|
if (S == NULL) internal_error("no symbol");
|
|
|
|
return SymbolAnnotation::get_t(S,
|
|
|
|
InterPackage::tree(InterSymbol::package(S)), NAMESPACE_IANN);
|
|
|
|
}
|
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
@h Logging.
|
2021-09-26 13:01:13 +03:00
|
|
|
|
2022-02-04 02:55:12 +02:00
|
|
|
=
|
|
|
|
void InterSymbol::log(OUTPUT_STREAM, void *vs) {
|
|
|
|
inter_symbol *S = (inter_symbol *) vs;
|
|
|
|
if (S == NULL) {
|
|
|
|
WRITE("<no-symbol>");
|
|
|
|
} else {
|
|
|
|
InterSymbolsTable::write_symbol_URL(DL, S);
|
|
|
|
WRITE("{%d}", S->symbol_ID - SYMBOL_BASE_VAL);
|
2022-02-14 01:44:50 +02:00
|
|
|
text_stream *trans = InterSymbol::get_translate(S);
|
|
|
|
if (Str::len(trans) > 0) WRITE("'%S'", trans);
|
2022-02-04 02:55:12 +02:00
|
|
|
}
|
2021-09-26 13:01:13 +03:00
|
|
|
}
|