To define the predicates causing instances to be created.


§1. This predicate plays a very special role in our calculus, and must always exist.

up_family *calling_up_family = NULL;
up_family *is_a_var_up_family = NULL;
up_family *is_a_const_up_family = NULL;
up_family *is_a_kind_up_family = NULL;

unary_predicate *is_a_var_up = NULL;
unary_predicate *is_a_const_up = NULL;

§2. Family. This is a minimal representation only: Inform adds other methods to the equality family to handle its typechecking and so on.

void CreationPredicates::start(void) {
    calling_up_family = UnaryPredicateFamilies::new();
    METHOD_ADD(calling_up_family, LOG_UPF_MTID, CreationPredicates::log_calling);
    #ifdef CORE_MODULE
    METHOD_ADD(calling_up_family, TYPECHECK_UPF_MTID, CreationPredicates::typecheck_calling);
    METHOD_ADD(calling_up_family, SCHEMA_UPF_MTID, CreationPredicates::schema_calling);
    #endif
    is_a_var_up_family = UnaryPredicateFamilies::new();
    METHOD_ADD(is_a_var_up_family, STOCK_UPF_MTID, CreationPredicates::stock_is_a_var);
    METHOD_ADD(is_a_var_up_family, LOG_UPF_MTID, CreationPredicates::log_is_a_var);
    is_a_const_up_family = UnaryPredicateFamilies::new();
    METHOD_ADD(is_a_const_up_family, STOCK_UPF_MTID, CreationPredicates::stock_is_a_const);
    METHOD_ADD(is_a_const_up_family, LOG_UPF_MTID, CreationPredicates::log_is_a_const);
    is_a_kind_up_family = UnaryPredicateFamilies::new();
    METHOD_ADD(is_a_kind_up_family, LOG_UPF_MTID, CreationPredicates::log_is_a_kind);
    #ifdef CORE_MODULE
    METHOD_ADD(is_a_var_up_family, TYPECHECK_UPF_MTID, CreationPredicates::typecheck_is_a_var);
    METHOD_ADD(is_a_const_up_family, TYPECHECK_UPF_MTID, CreationPredicates::typecheck_is_a_const);
    METHOD_ADD(is_a_kind_up_family, TYPECHECK_UPF_MTID, CreationPredicates::typecheck_is_a_kind);
    #endif
}

§3. CALLED atoms are interesting because they exist only for their side-effects: they have no effect at all on the logical status of a proposition (well, except that they should not be applied to free variables referred to nowhere else). They can therefore be added or removed freely. In the phrase

if a woman is in a lighted room (called the den), ...

we need to note that the value of the bound variable corresponding to the lighted room will need to be kept and to have a name ("the den"): this will probably mean the inclusion of a CALLED=den(y) atom.

The calling data for a CALLED atom is the textual name by which the variable will be called.

int CreationPredicates::is_calling_up_atom(pcalc_prop *prop) {
    if ((prop->element == PREDICATE_ATOM) && (prop->arity == 1)) {
        unary_predicate *up = RETRIEVE_POINTER_unary_predicate(prop->predicate);
        if (up->family == calling_up_family) return TRUE;
    }
    return FALSE;
}

kind *CreationPredicates::what_kind_of_calling(pcalc_prop *prop) {
    if ((prop) && (prop->element == PREDICATE_ATOM) && (prop->arity == 1)) {
        unary_predicate *up = RETRIEVE_POINTER_unary_predicate(prop->predicate);
        if (up->family == calling_up_family) return up->assert_kind;
    }
    return NULL;
}

pcalc_prop *CreationPredicates::calling_up(wording W, pcalc_term t, kind *K) {
    unary_predicate *up = UnaryPredicates::new(calling_up_family);
    up->calling_name = W;
    up->assert_kind = K;
    return Atoms::unary_PREDICATE_new(up, t);
}

wording CreationPredicates::get_calling_name(pcalc_prop *prop) {
    if ((prop->element == PREDICATE_ATOM) && (prop->arity == 1)) {
        unary_predicate *up = RETRIEVE_POINTER_unary_predicate(prop->predicate);
        if (up->family == calling_up_family) return up->calling_name;
    }
    return EMPTY_WORDING;
}

§4. Initial stock. This relation is hard-wired in, and it is made in a slightly special way since (alone among binary predicates) it has no distinct reversal.

void CreationPredicates::stock_is_a_var(up_family *self, int n) {
    if (n == 1) {
        is_a_var_up = UnaryPredicates::new(is_a_var_up_family);
    }
}

void CreationPredicates::stock_is_a_const(up_family *self, int n) {
    if (n == 1) {
        is_a_const_up = UnaryPredicates::new(is_a_const_up_family);
    }
}

pcalc_prop *CreationPredicates::is_a_var_up(pcalc_term t) {
    return Atoms::unary_PREDICATE_new(is_a_var_up, t);
}

pcalc_prop *CreationPredicates::is_a_const_up(pcalc_term t) {
    return Atoms::unary_PREDICATE_new(is_a_const_up, t);
}

pcalc_prop *CreationPredicates::is_a_kind_up(pcalc_term t, kind *K) {
    unary_predicate *up = UnaryPredicates::new(is_a_kind_up_family);
    up->assert_kind = K;
    return Atoms::unary_PREDICATE_new(up, t);
}

kind *CreationPredicates::what_kind(pcalc_prop *prop) {
    if ((prop) && (prop->element == PREDICATE_ATOM) && (prop->arity == 1)) {
        unary_predicate *up = RETRIEVE_POINTER_unary_predicate(prop->predicate);
        if (up->family == is_a_kind_up_family) return up->assert_kind;
    }
    return NULL;
}

#ifdef CORE_MODULE
int CreationPredicates::typecheck_calling(up_family *self, unary_predicate *up,
    pcalc_prop *prop, variable_type_assignment *vta, tc_problem_kit *tck) {
    return ALWAYS_MATCH;
}
int CreationPredicates::typecheck_is_a_var(up_family *self, unary_predicate *up,
    pcalc_prop *prop, variable_type_assignment *vta, tc_problem_kit *tck) {
    return ALWAYS_MATCH;
}
int CreationPredicates::typecheck_is_a_const(up_family *self, unary_predicate *up,
    pcalc_prop *prop, variable_type_assignment *vta, tc_problem_kit *tck) {
    return ALWAYS_MATCH;
}
int CreationPredicates::typecheck_is_a_kind(up_family *self, unary_predicate *up,
    pcalc_prop *prop, variable_type_assignment *vta, tc_problem_kit *tck) {
    kind *actually_find = TypecheckPropositions::kind_of_term(&(prop->terms[0]), vta, tck);
    if (Kinds::compatible(actually_find, K_object) == NEVER_MATCH)
        internal_error("is_a_kind predicate misapplied");
    return ALWAYS_MATCH;
}
#endif

§5. "Called" predicates cannot be asserted, and to test them, we simply copy the value into the local variable of the given name. Note then that here the I6 = (set equal) operator is being used in a condition context: there's a good chance that the value set is non-zero (since all objects and enumerated values are non-zero), but it isn't necessarily so — in Inform it's legal to quantify over times and truth states, for instance, where 0 is a legal I6 value. So we use the comma operator to throw away the result of the assignment, and evaluate the condition to true.

#ifdef CORE_MODULE
void CreationPredicates::schema_calling(up_family *self, int task, unary_predicate *up,
    annotated_i6_schema *asch, kind *K) {
    switch(task) {
        case TEST_ATOM_TASK:
            Calculus::Schemas::modify(asch->schema, "(%L=(*1), true)",
                LocalVariables::ensure_calling(up->calling_name, up->assert_kind));
            break;
        default:
            asch->schema = NULL;
            break;
    }
}
#endif

void CreationPredicates::log_calling(up_family *self, OUTPUT_STREAM, unary_predicate *up) {
    WRITE("called='%W'", up->calling_name);
    if (up->assert_kind) WRITE(":%u", up->assert_kind);
}

void CreationPredicates::log_is_a_var(up_family *self, OUTPUT_STREAM, unary_predicate *up) {
    WRITE("is-a-var");
}

void CreationPredicates::log_is_a_const(up_family *self, OUTPUT_STREAM, unary_predicate *up) {
    WRITE("is-a-const");
}

void CreationPredicates::log_is_a_kind(up_family *self, OUTPUT_STREAM, unary_predicate *up) {
    WRITE("is-a-kind");
    if (up->assert_kind) WRITE("=%u", up->assert_kind);
}

int CreationPredicates::contains_callings(pcalc_prop *prop) {
    for (pcalc_prop *p = prop; p; p = p->next)
        if (CreationPredicates::is_calling_up_atom(p))
            return TRUE;
    return FALSE;
}