The mechanism by which Inform records the characteristics of different kinds.
- §11. Creation
- §12. The noun
- §14. Transformations
- §17. For construction purposes
- §18. Questions about constructors
- §20. Cast and instance lists
- §23. Tedious access functions
- §24. Compatibility
define PUNCTUATION_GRP 1 /* used in the construction of other kinds only */
define PROTOCOL_GRP 2 /* such as arithmetic value */
define BASE_CONSTRUCTOR_GRP 3 /* such as number */
define PROPER_CONSTRUCTOR_GRP 4 /* with positive arity, such as "list of ..." */
§2. Besides all the properties of kinds used in this module, Inform also needs to store further metadata in order to be able to make the extensive run-time code needed to support all these kinds in actual programs. All of this means that a kind_constructor object is a great big rag-bag of properties, some set by commands in Neptune files, others set by calls from Inform.
So, deep breath:
define MAX_KIND_CONSTRUCTION_ARITY 2
typedef struct kind_constructor { struct noun *dt_tag; /* text of name */ int group; /* one of the four values above */ /* A: how this came into being */ int is_incompletely_defined; /* newly defined and ambiguous as yet */ struct parse_node *where_defined_in_source_text; /* if so */ /* B: constructing kinds */ int constructor_arity; /* 0 for base, 1 for unary, 2 for binary */ int variance[MAX_KIND_CONSTRUCTION_ARITY]; /* must beCOVARIANTorCONTRAVARIANT*/ int tupling[MAX_KIND_CONSTRUCTION_ARITY]; /* extent to which tupling is permitted */ struct kind *cached_kind; /* cached result ofKinds::base_construction*/ /* C: compatibility with other kinds */ struct parse_node *superkind_set_at; /* where it says, e.g., "A rabbit is a kind of animal" */ struct kind_constructor_casting_rule *first_casting_rule; /* list of these */ struct kind_constructor_instance_rule *first_instance_rule; /* list of these */ /* D: how constant values of this kind are expressed */ struct literal_pattern *ways_to_write_literals; /* list of ways to write this */ struct table *named_values_created_with_table; /* alternatively... */ int next_free_value; /* to make distinguishable instances of this kind */ int constant_compilation_method; /* one of the*_CCMvalues */ int forbid_assertion_creation; /* an enumeration which cannot be explicitly created? */ /* E: knowledge about values of this kind */ struct inference_subject *base_as_infs; /* inferences about properties */ struct text_stream *default_value; /* used for built-in types only */ /* F: behaviour as a property as well */ int can_coincide_with_property; /* allowed to coincide in name with a property */ struct property *coinciding_property; /* property of the same name, if any */ /* G: performing arithmetic */ struct text_stream *comparison_routine; /* for instance, when sorting table or list entries */ int dimensionless; struct dimensional_rules dim_rules; /* how arithmetic operations work here */ struct unit_sequence dimensional_form; /* dimensions of this kind */ int dimensional_form_fixed; /* whether they are derived */ struct kind_constructor *relative_kind; /* H: representing this kind at run-time */ struct text_stream *explicit_identifier; /* to become an Inter identifier */ int class_number; /* for classes of object */ #ifdef CORE_MODULE struct kind_constructor_compilation_data compilation_data; #endif /* I: storing values at run-time */ int short_block_size; /* if stored as a block value, size in words of the SB */ int long_block_size; /* if stored as a block value, minimum number of LB fields */ int flexible_long_block_size; /* if stored as a block value, typical number of LB fields */ int can_exchange; /* with external files and therefore other story files */ struct text_stream *distinguish_function; /* Inter routine to see if values distinguishable */ struct kind_constructor_comparison_schema *first_comparison_schema; /* list of these */ struct text_stream *loop_domain_schema; /* how to compile a loop over the instances */ struct linked_list *instances; /* if enumerated explicitly in a Neptune file */ /* J: printing and parsing values at run-time */ struct text_stream *print_identifier; /* an Inter identifier used for compiling printing rules */ struct text_stream *ACTIONS_identifier; /* ditto but for ACTIONS testing command */ struct command_grammar *understand_as_values; /* used when parsing such values */ struct text_stream *understand_function; /* routine name, when not compiled automatically */ struct text_stream *recognise_function; /* for recognising an explicit value as preposition */ /* K: pointer-value handling functions at run-time */ struct text_stream *create_function; struct text_stream *cast_function; struct text_stream *copy_function; struct text_stream *copy_short_block_function; struct text_stream *quick_copy_function; struct text_stream *destroy_function; struct text_stream *make_mutable_function; struct text_stream *hash_function; struct text_stream *long_block_size_function; struct text_stream *serialise_function; struct text_stream *unserialise_function; struct linked_list *arithmetic_schemas[NO_DEFINED_OPERATION_VALUES]; /* ofarithmetic_schema*/ int arithmetic_modulus; /* L: indexing and documentation */ struct text_stream *specification_text; /* text for pseudo-property */ struct text_stream *index_default_value; /* and its description in the Kinds index */ struct text_stream *index_maximum_value; /* ditto */ struct text_stream *index_minimum_value; /* ditto */ int index_priority; /* from 1 (highest) toLOWEST_INDEX_PRIORITY(lowest) */ int linguistic; /* divide off as having linguistics content */ int indexed_grey_if_empty; /* shaded grey in the Kinds index */ struct text_stream *documentation_reference; /* documentation symbol, if any */ CLASS_DEFINITION } kind_constructor;
- The structure kind_constructor is accessed in 2/tlok, 2/dk, 2/uk, 3/dmn, 4/mcr, 4/st, 4/kc and here.
§3. A few of the settings connect pairs of kinds together, so structures like the following are also needed.
typedef struct kind_constructor_casting_rule { struct text_stream *cast_from_kind_unparsed; /* to the one which has the rule */ struct kind_constructor *cast_from_kind; /* to the one which has the rule */ struct kind_constructor_casting_rule *next_casting_rule; } kind_constructor_casting_rule;
- The structure kind_constructor_casting_rule is accessed in 4/kc and here.
typedef struct kind_constructor_instance_rule { struct text_stream *instance_of_this_unparsed; struct kind_constructor *instance_of_this; struct kind_constructor_instance_rule *next_instance_rule; } kind_constructor_instance_rule;
- The structure kind_constructor_instance_rule is accessed in 4/kc and here.
§5. And this is the analogous structure for giving Inter schemas to compare data of two different kinds:
typedef struct kind_constructor_comparison_schema { struct text_stream *comparator_unparsed; struct kind_constructor *comparator; struct text_stream *comparison_schema; struct kind_constructor_comparison_schema *next_comparison_schema; } kind_constructor_comparison_schema;
- The structure kind_constructor_comparison_schema is accessed in 4/kc.
typedef struct kind_constructor_instance { struct text_stream *natural_language_name; struct text_stream *identifier; int value; int value_specified; } kind_constructor_instance;
- The structure kind_constructor_instance is accessed in 4/kc.
§7. The "tupling" of an argument is the extent to which an argument can be allowed to hold a variable-length list of kinds, rather than a single one. There aren't actually many possibilities.
define NO_TUPLING 0 /* a single kind */
define ALLOW_NOTHING_TUPLING 1 /* a single kind, or "nothing" */
define ARBITRARY_TUPLING 10000 /* a list of kinds of any length */
define NONE_CCM 1 /* constant values of this kind cannot exist */
define LITERAL_CCM 2 /* a numerical annotation decides the value */
define NAMED_CONSTANT_CCM 3 /* an instance annotation decides the value */
define SPECIAL_CCM 4 /* special code specific to the kind of value is needed */
kind *latest_base_kind_of_value = NULL;
typedef struct arithmetic_schema { struct text_stream *operands_unparsed[2]; struct kind_constructor *operands[2]; struct text_stream *schema; CLASS_DEFINITION } arithmetic_schema;
- The structure arithmetic_schema is accessed in 4/kc and here.
§11. Creation. Constructors come from two sources. Built-in ones like number or
list of K come from commands in Neptune Files, while source-created
ones ("Air pressure is a kind of value") result in calls here from
Kinds::new_base -- which, as the name suggests, can only make
base kinds, not proper constructors.
Here super will be the super-constructor, the one which this will construct
subkinds of. In practice this will be NULL when CON_VALUE is created, and
then CON_VALUE for kinds like "number" or this one:
Weight is a kind of value.
but will be the constructor for "door" for kinds like this one:
Portal is a kind of door.
kind_constructor *KindConstructors::new(kind_constructor *super, text_stream *source_name, text_stream *initialisation_macro, int group) { kind_constructor *con = CREATE(kind_constructor); kind_constructor **pC = FamiliarKinds::known_con(source_name); if (pC) *pC = con; int copied = FALSE; if (super == Kinds::get_construct(K_value)) Fill in a new constructor11.1 else { Copy the new constructor from its superconstructor11.2; copied = TRUE; } con->group = group; con->explicit_identifier = Str::duplicate(source_name); #ifdef CORE_MODULE con->compilation_data = RTKindConstructors::new_compilation_data(con); KindSubjects::new(con); #endif con->where_defined_in_source_text = current_sentence; kind **pK = FamiliarKinds::known_kind(source_name); if (pK) *pK = Kinds::base_construction(con); return con; }
§11.1. If our new constructor is wholly new, and isn't a subkind of something else, we need to initialise the entire data structure; but note that, having done so, we apply any defaults set in Neptune files.
default LOWEST_INDEX_PRIORITY 100
Fill in a new constructor11.1 =
con->dt_tag = NULL; con->group = 0; /* which is invalid, so the interpreter needs to set it */ /* A: how this came into being */ con->is_incompletely_defined = FALSE; con->where_defined_in_source_text = NULL; /* but will be filled in imminently */ /* B: constructing kinds */ con->constructor_arity = 0; /* by default a base constructor */ for (int i=0; i<MAX_KIND_CONSTRUCTION_ARITY; i++) { con->variance[i] = COVARIANT; con->tupling[i] = NO_TUPLING; } con->cached_kind = NULL; /* C: compatibility with other kinds */ con->superkind_set_at = NULL; con->first_casting_rule = NULL; con->first_instance_rule = NULL; /* D: how constant values of this kind are expressed */ con->ways_to_write_literals = NULL; con->named_values_created_with_table = NULL; con->next_free_value = 1; con->constant_compilation_method = NONE_CCM; con->forbid_assertion_creation = FALSE; /* E: knowledge about values of this kind */ con->base_as_infs = NULL; /* but will be filled in imminently, in almost all cases */ con->default_value = Str::new(); /* F: behaviour as a property as well */ con->can_coincide_with_property = FALSE; con->coinciding_property = NULL; /* G: performing arithmetic */ con->dimensionless = TRUE; con->comparison_routine = Str::new(); WRITE_TO(con->comparison_routine, "UnsignedCompare"); if ((con == CON_KIND_VARIABLE) || (con == CON_INTERMEDIATE) || ((Str::eq_wide_string(source_name, U"NUMBER_TY")) || (Str::eq_wide_string(source_name, U"REAL_NUMBER_TY")))) con->dimensional_form = Kinds::Dimensions::fundamental_unit_sequence(NULL); else con->dimensional_form = Kinds::Dimensions::fundamental_unit_sequence(Kinds::base_construction(con)); con->dimensional_form_fixed = FALSE; Kinds::Dimensions::dim_initialise(&(con->dim_rules)); con->relative_kind = NULL; /* H: representing this kind at run-time */ con->explicit_identifier = Str::new(); con->class_number = 0; /* I: storing values at run-time */ con->long_block_size = 0; con->flexible_long_block_size = 0; con->short_block_size = 1; con->can_exchange = FALSE; con->first_comparison_schema = NULL; con->distinguish_function = NULL; con->loop_domain_schema = NULL; con->instances = NEW_LINKED_LIST(kind_constructor_instance); /* J: printing and parsing values at run-time */ con->print_identifier = Str::new(); con->ACTIONS_identifier = Str::new(); con->understand_as_values = NULL; con->understand_function = NULL; con->recognise_function = NULL; /* K: pointer-value handling functions at run-time */ con->create_function = NULL; con->cast_function = NULL; con->copy_function = NULL; con->copy_short_block_function = NULL; con->quick_copy_function = NULL; con->destroy_function = NULL; con->make_mutable_function = NULL; con->hash_function = NULL; con->long_block_size_function = NULL; con->serialise_function = NULL; con->unserialise_function = NULL; for (int op=0; op<NO_DEFINED_OPERATION_VALUES; op++) con->arithmetic_schemas[op] = NEW_LINKED_LIST(arithmetic_schema); con->arithmetic_modulus = 0; /* L: indexing and documentation */ con->specification_text = NULL; con->index_default_value = I"--"; con->index_maximum_value = I"--"; con->index_minimum_value = I"--"; con->index_priority = LOWEST_INDEX_PRIORITY; if ((group == PUNCTUATION_GRP) || (group == PROTOCOL_GRP)) con->index_priority = 0; con->linguistic = FALSE; con->indexed_grey_if_empty = FALSE; con->documentation_reference = NULL; kind_macro_definition *set_defaults = NULL; switch (group) { case PUNCTUATION_GRP: set_defaults = NeptuneMacros::parse_name(I"#PUNCTUATION"); break; case PROTOCOL_GRP: set_defaults = NeptuneMacros::parse_name(I"#PROTOCOL"); break; case BASE_CONSTRUCTOR_GRP: set_defaults = NeptuneMacros::parse_name(I"#BASE"); break; case PROPER_CONSTRUCTOR_GRP: set_defaults = NeptuneMacros::parse_name(I"#CONSTRUCTOR"); break; } if (set_defaults) NeptuneMacros::play_back(set_defaults, con, NULL); if (Str::len(initialisation_macro) > 0) NeptuneMacros::play_back(NeptuneMacros::parse_name(initialisation_macro), con, NULL);
- This code is used in §11.
§11.2. However, if we create our constructor as a subkind, like so:
A turtle is a kind of animal.
then we copy the entire "animal" constructor to initialise the "turtle" one.
Note that the weak ID number is one of the things copied; this is deliberate. It means that all kinds of object share the same weak ID as "object".
Copy the new constructor from its superconstructor11.2 =
int I = con->allocation_id;
void *N = con->next_structure;
void *P = con->prev_structure;
*con = *super;
con->allocation_id = I;
con->next_structure = N;
con->prev_structure = P;
con->cached_kind = NULL; /* otherwise the superkind's cache is used by mistake */
con->explicit_identifier = Str::new(); /* otherwise this will be called OBJECT_TY by mistake */
- This code is used in §11.
§12. The noun. It's a requirement that the following be called soon after the creation of the constructor:
void KindConstructors::attach_noun(kind_constructor *con, noun *nt) { if ((con == NULL) || (nt == NULL)) internal_error("bad noun attachment"); con->dt_tag = nt; } wording KindConstructors::get_name(kind_constructor *con, int plural_form) { if (con->dt_tag) { noun *nt = con->dt_tag; if (nt) return Nouns::nominative(nt, plural_form); } return EMPTY_WORDING; } wording KindConstructors::get_name_in_play(kind_constructor *con, int plural_form, NATURAL_LANGUAGE_WORDS_TYPE *nl) { if (con->dt_tag) { noun *nt = con->dt_tag; if (nt) return Nouns::nominative_in_language(nt, plural_form, nl); } return EMPTY_WORDING; } noun *KindConstructors::get_noun(kind_constructor *con) { if (con == NULL) return NULL; return con->dt_tag; } text_stream *KindConstructors::name_in_template_code(kind_constructor *con) { return con->explicit_identifier; }
§13. We also need to parse this, occasionally (if we needed this more than a small and bounded number of times we'd want a faster method, but we don't):
kind_constructor *KindConstructors::parse(text_stream *sn) { if (sn == NULL) return NULL; kind_constructor *con; LOOP_OVER(con, kind_constructor) if (Str::eq(sn, con->explicit_identifier)) return con; return NULL; }
§14. Transformations. Conversions of an existing constructor to make it a unit or enumeration also require running macros in the kind interpreter:
int KindConstructors::convert_to_unit(kind_constructor *con) { if (con->is_incompletely_defined == TRUE) { NeptuneMacros::play_back(NeptuneMacros::parse_name(I"#UNIT"), con, NULL); return TRUE; } if (KindConstructors::is_arithmetic(con)) return TRUE; /* i.e., if it succeeded */ return FALSE; } int KindConstructors::convert_to_enumeration(kind_constructor *con) { if (con->is_incompletely_defined == TRUE) { NeptuneMacros::play_back(NeptuneMacros::parse_name(I"#ENUMERATION"), con, NULL); if (con->linguistic) NeptuneMacros::play_back(NeptuneMacros::parse_name(I"#LINGUISTIC"), con, NULL); return TRUE; } if (KindConstructors::is_an_enumeration(con)) return TRUE; /* i.e., if it succeeded */ return FALSE; }
void KindConstructors::convert_to_real(kind_constructor *con) { NeptuneMacros::play_back(NeptuneMacros::parse_name(I"#REAL"), con, NULL); }
§16. A few base kinds are marked as "linguistic", which simply enables us to fence them tidily off in the index.
void KindConstructors::mark_as_linguistic(kind_constructor *con) { con->linguistic = TRUE; }
§17. For construction purposes.
kind **KindConstructors::cache_location(kind_constructor *con) { if (con) return &(con->cached_kind); return NULL; } int KindConstructors::arity(kind_constructor *con) { if (con == NULL) return 0; if (con->group == PROPER_CONSTRUCTOR_GRP) return con->constructor_arity; return 0; } int KindConstructors::tupling(kind_constructor *con, int b) { return con->tupling[b]; } int KindConstructors::variance(kind_constructor *con, int b) { return con->variance[b]; } int KindConstructors::is_base(kind_constructor *con) { if (con == NULL) return FALSE; if (con->group == BASE_CONSTRUCTOR_GRP) return TRUE; return FALSE; } int KindConstructors::is_proper_constructor(kind_constructor *con) { if (con == NULL) return FALSE; if (con->group == PROPER_CONSTRUCTOR_GRP) return TRUE; return FALSE; }
§18. Questions about constructors. The rest of Inform is not encouraged to poke at constructors directly; it ought to ask questions about kinds instead (see "Using Kinds"). However:
int KindConstructors::is_definite(kind_constructor *con) { if ((con->group == BASE_CONSTRUCTOR_GRP) || (con->group == PROPER_CONSTRUCTOR_GRP)) return TRUE; if ((con == CON_VOID) || (con == CON_NIL) || (con == CON_INTERMEDIATE)) return TRUE; return FALSE; } int KindConstructors::is_understandable(kind_constructor *con) { if (con == NULL) return FALSE; if ((KindConstructors::is_definite(con)) && (KindConstructors::compatible(con, Kinds::get_construct(K_understandable_value), FALSE))) return TRUE; return FALSE; } int KindConstructors::is_arithmetic(kind_constructor *con) { if (con == NULL) return FALSE; if ((KindConstructors::is_definite(con)) && (KindConstructors::compatible(con, Kinds::get_construct(K_arithmetic_value), FALSE))) return TRUE; return FALSE; } int KindConstructors::is_arithmetic_and_real(kind_constructor *con) { if (con == NULL) return FALSE; if ((KindConstructors::is_definite(con)) && (KindConstructors::compatible(con, Kinds::get_construct(K_real_arithmetic_value), FALSE))) return TRUE; return FALSE; } int KindConstructors::is_an_enumeration(kind_constructor *con) { if (con == NULL) return FALSE; if ((KindConstructors::is_definite(con)) && (KindConstructors::compatible(con, Kinds::get_construct(K_enumerated_value), FALSE))) return TRUE; return FALSE; }
int KindConstructors::uses_signed_comparisons(kind_constructor *kc) { if (kc == NULL) return FALSE; if (Str::eq_wide_string(kc->comparison_routine, U"signed")) return TRUE; return FALSE; } text_stream *KindConstructors::get_comparison_fn_identifier(kind_constructor *kc) { if (kc == NULL) return NULL; if ((KindConstructors::is_arithmetic_and_real(kc)) && (K_real_number)) return K_real_number->construct->comparison_routine; if (Str::eq_wide_string(kc->comparison_routine, U"signed")) return NULL; return kc->comparison_routine; }
§20. Cast and instance lists. Each constructor has a list of other constructors (all of the PROTOCOL_GRP
group) which it's an instance of: value, word value, arithmetic value, and so on.
int KindConstructors::find_cast(kind_constructor *from, kind_constructor *to) { if (to) { kind_constructor_casting_rule *dtcr; for (dtcr = to->first_casting_rule; dtcr; dtcr = dtcr->next_casting_rule) { if (Str::len(dtcr->cast_from_kind_unparsed) > 0) { dtcr->cast_from_kind = KindConstructors::parse(dtcr->cast_from_kind_unparsed); Str::clear(dtcr->cast_from_kind_unparsed); } if (from == dtcr->cast_from_kind) return TRUE; } } return FALSE; }
§21. Each constructor has a list of other constructors (all of the BASE_CONSTRUCTOR_GRP
group or PROPER_CONSTRUCTOR_GRP) which it can cast to.
int KindConstructors::find_instance(kind_constructor *from, kind_constructor *to) { kind_constructor_instance_rule *dti; for (dti = from->first_instance_rule; dti; dti = dti->next_instance_rule) { if (Str::len(dti->instance_of_this_unparsed) > 0) { dti->instance_of_this = KindConstructors::parse(dti->instance_of_this_unparsed); Str::clear(dti->instance_of_this_unparsed); } if (dti->instance_of_this == to) return TRUE; if (KindConstructors::find_instance(dti->instance_of_this, to)) return TRUE; } return FALSE; }
§22. Each constructor has a list of explicitly-named instances from the Neptune file creating it (if any were: by default this will be empty):
linked_list *KindConstructors::instances(kind_constructor *kc) { if (kc == NULL) return FALSE; return kc->instances; }
§23. Tedious access functions.
text_stream *KindConstructors::get_create_fn_identifier(kind_constructor *kc) { if (kc == NULL) return NULL; return kc->create_function; } text_stream *KindConstructors::get_cast_fn_identifier(kind_constructor *kc) { if (kc == NULL) return NULL; return kc->cast_function; } text_stream *KindConstructors::get_copy_fn_identifier(kind_constructor *kc) { if (kc == NULL) return NULL; return kc->copy_function; } text_stream *KindConstructors::get_copy_short_block_fn_identifier(kind_constructor *kc) { if (kc == NULL) return NULL; return kc->copy_short_block_function; } text_stream *KindConstructors::get_quick_copy_fn_identifier(kind_constructor *kc) { if (kc == NULL) return NULL; return kc->quick_copy_function; } text_stream *KindConstructors::get_destroy_fn_identifier(kind_constructor *kc) { if (kc == NULL) return NULL; return kc->destroy_function; } text_stream *KindConstructors::get_make_mutable_fn_identifier(kind_constructor *kc) { if (kc == NULL) return NULL; return kc->make_mutable_function; } text_stream *KindConstructors::get_hash_fn_identifier(kind_constructor *kc) { if (kc == NULL) return NULL; return kc->hash_function; } text_stream *KindConstructors::get_long_block_size_fn_identifier(kind_constructor *kc) { if (kc == NULL) return NULL; return kc->long_block_size_function; } text_stream *KindConstructors::get_serialise_fn_identifier(kind_constructor *kc) { if (kc == NULL) return NULL; return kc->serialise_function; } text_stream *KindConstructors::get_unserialise_fn_identifier(kind_constructor *kc) { if (kc == NULL) return NULL; return kc->unserialise_function; } text_stream *KindConstructors::get_arithmetic_schema(int op, kind_constructor *kc1, kind_constructor *kc2) { if ((op < 0) || (op >= NO_DEFINED_OPERATION_VALUES)) return NULL; text_stream *candidate; candidate = KindConstructors::get_arithmetic_schema_from(kc1, op, kc1, kc2); if (Str::len(candidate) > 0) return candidate; candidate = KindConstructors::get_arithmetic_schema_from(kc2, op, kc1, kc2); if (Str::len(candidate) > 0) return candidate; return NULL; } text_stream *KindConstructors::get_arithmetic_schema_from(kind_constructor *from, int op, kind_constructor *kc1, kind_constructor *kc2) { if (from == NULL) return NULL; arithmetic_schema *ars; LOOP_OVER_LINKED_LIST(ars, arithmetic_schema, from->arithmetic_schemas[op]) { for (int i=0; i<2; i++) { if (Str::len(ars->operands_unparsed[i]) > 0) { ars->operands[i] = KindConstructors::parse(ars->operands_unparsed[i]); Str::clear(ars->operands_unparsed[i]); } } if (((kc1 == ars->operands[0]) || ((kc1 == from) && (ars->operands[0] == NULL))) && ((kc2 == ars->operands[1]) || ((kc2 == from) && (ars->operands[1] == NULL)))) return ars->schema; } return NULL; } int KindConstructors::get_arithmetic_modulus(kind_constructor *kc) { if (kc == NULL) return 0; return kc->arithmetic_modulus; } int KindConstructors::is_dimensionless(kind_constructor *kc) { if (kc == NULL) return TRUE; return kc->dimensionless; }
int KindConstructors::compatible(kind_constructor *from, kind_constructor *to, int allow_casts) { if (to == from) return TRUE; if ((to == NULL) || (from == NULL)) return FALSE; if ((allow_casts) && (KindConstructors::find_cast(from, to))) return TRUE; if (KindConstructors::find_instance(from, to)) return TRUE; return FALSE; }
int KindConstructors::uses_block_values(kind_constructor *con) { if (con == NULL) return FALSE; if ((KindConstructors::is_definite(con)) && (KindConstructors::compatible(con, Kinds::get_construct(K_pointer_value), FALSE))) return TRUE; return FALSE; } int KindConstructors::allow_word_as_pointer(kind_constructor *left, kind_constructor *right) { if (KindConstructors::uses_block_values(left) == FALSE) return FALSE; if (KindConstructors::uses_block_values(right) == TRUE) return FALSE; if (KindConstructors::compatible(right, left, TRUE)) return TRUE; return FALSE; }