This section draws inferences from assertions which seem to be about the properties of things, independent of their location.


§1. Asserting global variable values.

void Assertions::PropertyKnowledge::initialise_global_variable(nonlocal_variable *q, parse_node *val) {
    if (q == NULL) internal_error("tried to initialise null variable");
    VariableSubjects::typecheck_initial_value(q, val, FALSE);

    parse_node *var = Lvalues::new_actual_NONLOCAL_VARIABLE(q);
    pcalc_prop *prop = Propositions::Abstract::to_set_relation(R_equality, NULL, var, NULL, val);
    Assert::true(prop, prevailing_mood);
}

§2. Asserting properties, three different ways. In these three alternative functions, we can assert that a given owner — specified either as an object, a value or a subtree — should have

void Assertions::PropertyKnowledge::assert_property_value_from_property_subtree_infs(property *prn,
    inference_subject *owner, parse_node *val_subtree) {
    pcalc_prop *prop = Propositions::Abstract::from_property_subtree(prn, val_subtree);
    if (owner == NULL) Issue a problem for an unrecognised property owner2.3;
    if (prevailing_mood < UNKNOWN_CE) Issue a problem for a negative certainty2.4;
    Assert::true_about(prop, owner, prevailing_mood);
}

void Assertions::PropertyKnowledge::assert_property_list(parse_node *owner_subtree,
    parse_node *list_subtree) {
    Check that the owner subtree isn't dangerously elaborate2.2;
    inference_subject *owner = Node::get_subject(owner_subtree);
    if (owner == NULL) {
        parse_node *owner_spec = NULL;
        if (<s-type-expression>(Node::get_text(owner_subtree)))
            owner_spec = <<rp>>;
        if ((Specifications::is_description(owner_spec)) &&
            (Descriptions::is_qualified(owner_spec) == FALSE)) {
            kind *K = Specifications::to_kind(owner_spec);
            if (K) owner = KindSubjects::from_kind(K);
        }
    }
    if (owner == NULL) {
        LOG("OS is: $T\n", owner_subtree);
        Issue a problem for an unrecognised property owner2.3;
    }
    kind *kind_clue = NULL;
    Work out the clue kind2.1;
    pcalc_prop *prop = Propositions::Abstract::from_property_list(list_subtree, kind_clue);
    Assert::true_about(prop, owner, prevailing_mood);
}

§2.1. We pass the "clue kind" to obtain a proposition which includes an atom setting the kind of the free variable — not because we need to assert this, although it does no harm to, but because this enables the proposition asserter to know the kind of the free variable, which in turn affects the interpretation placed on adjectives which have different meanings in different domains. (Within "object", we needn't narrow down, though, because adjectives are typechecked at run-time rather than compile-time in that domain.)

Work out the clue kind2.1 =

    if (owner) {
        kind_clue = KindSubjects::to_kind(owner);
        if (kind_clue == NULL)
            kind_clue = KindSubjects::to_kind(InferenceSubjects::narrowest_broader_subject(owner));
        if ((InferenceSubjects::is_an_object(owner)) ||
            (InferenceSubjects::is_a_kind_of_object(owner)))
            kind_clue = K_object;
    }

§2.2. Check that the owner subtree isn't dangerously elaborate2.2 =

    parse_node *owner_spec = Node::get_evaluation(owner_subtree);
    if (Specifications::is_description(owner_spec)) {
        if ((Propositions::contains_binary_predicate(Specifications::to_proposition(owner_spec))) ||
            (Descriptions::number_of_adjectives_applied_to(owner_spec) > 0) ||
            (Propositions::contains_adjective(Specifications::to_proposition(owner_spec)))) {
            Problems::quote_source(1, current_sentence);
            Problems::quote_spec(2, owner_spec);
            StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_RelationAPL));
            Problems::issue_problem_segment(
                "The sentence %1 looked to me as if it might be trying to assign certain "
                "properties to something described in a way (%2) which involved a clause "
                "which can't be properly determined until the game is running, so that at "
                "this point it's impossible to act upon.");
            Problems::issue_problem_end();
            return;
        }
    }

§2.3. Issue a problem for an unrecognised property owner2.3 =

    Problems::quote_source(1, current_sentence);
    StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_PropForBadKOV));
    Problems::issue_problem_segment(
        "The sentence %1 looked to me as if it might be trying to assign certain properties "
        "to something which is not allowed to have them.");
    Problems::issue_problem_end();
    return;

§2.4. Issue a problem for a negative certainty2.4 =

    Problems::quote_source(1, current_sentence);
    StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_PropWithNegativeCertainty));
    Problems::issue_problem_segment(
        "The sentence %1 looked to me as if it might be trying to say what a "
        "property value is not, rather than what it is, by using 'never', or "
        "'seldom'. You can only say what it is, or for properties of kinds, what "
        "it 'usually' is.");
    Problems::issue_problem_end();
    return;

§3. The following assumes that the subtree py describes a value which the prn property of something will have; it issues problem messages if this would be impossible, returning NULL, or else silently returns the value. It's used both above and by the tree-conversion code in the predicate calculus engine.

Here there's no need to perform any typechecking; all of that is done by the proposition machinery. But we do look for empty lists, whose implied kind can only be deduced from a wider context than that proposition describes.

parse_node *Assertions::PropertyKnowledge::property_value_from_property_subtree(property *prn, parse_node *py) {
    if (Properties::is_either_or(prn)) {
        if (py == NULL) Issue a problem, as this uses a bare adjective as if a value-property3.2;
        Issue a problem, as this makes sense only for value properties3.3;
    }
    Check that the subtree does indeed express a property value3.4;

    parse_node *val = NonlocalVariables::substitute_constants(
        Node::get_evaluation(py));
    kind *property_kind = ValueProperties::kind(prn);

    Cast the empty list to whatever kind of list is expected3.1;

    if ((Specifications::is_value(val)) && (Node::is(val, CONSTANT_NT) == FALSE))
        Issue a problem for a property value which isn't a constant3.5;

    return val;
}

§3.1. Cast the empty list to whatever kind of list is expected3.1 =

    kind *constant_kind = Specifications::to_kind(val);
    if ((Kinds::get_construct(constant_kind) == CON_list_of) &&
        (Kinds::eq(Kinds::unary_construction_material(constant_kind), K_nil)) &&
        (Lists::length_of_ll(Node::get_text(val)) == 0) &&
        (Kinds::get_construct(property_kind) == CON_list_of)) {
        Lists::set_kind_of_list_at(Node::get_text(val), property_kind);
        Node::set_kind_of_value(val, property_kind);
        constant_kind = property_kind;
    }

§3.2. Issue a problem, as this uses a bare adjective as if a value-property3.2 =

    Problems::quote_source(1, current_sentence);
    Problems::quote_property(3, prn);
    StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_HasBareAdjective));
    Problems::issue_problem_segment(
        "In %1 you write about the %3 property as if it were some kind of value "
        "or possession, but %3 is an either/or property - something is either "
        "%3 or not. (For example, it's incorrect to say 'The glass box has "
        "transparent'; the right way is just 'The glass box is transparent.')");
    Problems::issue_problem_end();
    return NULL;

§3.3. Issue a problem, as this makes sense only for value properties3.3 =

    Problems::quote_source(1, current_sentence);
    Problems::quote_wording(2, Node::get_text(py));
    Problems::quote_property(3, prn);
    StandardProblems::handmade_problem(Task::syntax_tree(), _p_(BelievedImpossible));
    Problems::issue_problem_segment(
        "In %1 you give a value of the %3 property as '%2', but %3 is an either/or "
        "property - something is either %3 or not, so there is no value involved.");
    Problems::issue_problem_end();
    return NULL;

§3.4. Check that the subtree does indeed express a property value3.4 =

    Refiner::nominalise_adjective(py);
    switch(Node::get_type(py)) {
        case PROPER_NOUN_NT:
            if ((Node::get_evaluation(py) == NULL) ||
                (Node::is(Node::get_evaluation(py), UNKNOWN_NT))) {
                Problems::quote_source(1, current_sentence);
                Problems::quote_wording(2, Node::get_text(py));
                Problems::quote_property(3, prn);
                StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_PropertyValueUnknown));
                Problems::issue_problem_segment(
                    "You wrote %1, but that seems to set a property %3 to the "
                    "value '%2', which I don't recognise as meaning anything.");
                Problems::issue_problem_end();
                return NULL;
            }
            break;  (this is fine — there's a well-expressed value)
        case COMMON_NOUN_NT:
            StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_PropertyInstance),
                "this property value makes no sense to me",
                "since it looks as if it contains a relative clause. Sometimes this "
                "happens if a clause follows directly on, and I have misunderstood to "
                "what it belongs. For instance: 'The widget is a door with matching "
                "key a thing in the Ballroom' is read with 'a thing in the Ballroom' as "
                "the value of the 'matching key' property, not with 'in the Ballroom' "
                "applying to the door.");
            return NULL;
        case X_OF_Y_NT:
            StandardProblems::sentence_problem(Task::syntax_tree(), _p_(BelievedImpossible),
                "something grammatically odd has happened here",
                "possibly to do with the unexpected 'of' in what seems to be a list of "
                "property values?");
            return NULL;
        case WITH_NT:
            StandardProblems::sentence_problem(Task::syntax_tree(), _p_(PM_MisplacedFrom),
                "something grammatically odd has happened here",
                "possibly to do with the unexpected 'with' in what seems "
                "to be a list of property values? Maybe there is some punctuation missing.");
            return NULL;
        default:
            Problems::quote_source(1, current_sentence);
            Problems::quote_wording(2, Node::get_text(py));
            Problems::quote_property(3, prn);
            StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_PeculiarPropertyValue));
            Problems::issue_problem_segment(
                "You wrote %1, but that seems to set a property %3 to the "
                "value '%2', which really doesn't make sense.");
            Problems::issue_problem_end();
            return NULL;
    }

§3.5. Issue a problem for a property value which isn't a constant3.5 =

    Problems::quote_source(1, current_sentence);
    Problems::quote_wording(2, Node::get_text(py));
    Problems::quote_kind(3, property_kind);
    Problems::quote_property(4, prn);
    StandardProblems::handmade_problem(Task::syntax_tree(), _p_(PM_PropertyNonConstant));
    Problems::issue_problem_segment(
        "In %1 you give a value of the %4 property as '%2', "
        "and while this does make sense as %3, it is a value which "
        "exists and changes during play, and which doesn't make sense to "
        "use when setting up the initial state of things.");
    Problems::issue_problem_end();
    return NULL;