§1. Requirements. Inform's code for compiling resources to different positions in the Inter hierarchy is quite defensively written, in order to keep everything to a fairly tightly specified schema.

The following is really a union: a requirement should have exactly one of the following fields set.

typedef struct location_requirement {
    struct submodule_identity *any_submodule_package_of_this_identity;
    struct package_request *this_exact_package;
    int this_exact_package_not_yet_created;
    struct text_stream *any_package_of_this_type;
    int any_enclosure;
    int must_be_plug;
    int must_be_main_source_text;
} location_requirement;

location_requirement HierarchyLocations::blank(void) {
    location_requirement req;
    req.any_submodule_package_of_this_identity = NULL;
    req.this_exact_package = NULL;
    req.this_exact_package_not_yet_created = -1;
    req.any_package_of_this_type = NULL;
    req.any_enclosure = FALSE;
    req.must_be_plug = FALSE;
    req.must_be_main_source_text = FALSE;
    return req;
}

§2. Here are the functions to create requirements:

location_requirement HierarchyLocations::local_submodule(submodule_identity *sid) {
    location_requirement req = HierarchyLocations::blank();
    req.any_submodule_package_of_this_identity = sid;
    return req;
}

location_requirement HierarchyLocations::completion_submodule(inter_tree *I, submodule_identity *sid) {
    location_requirement req = HierarchyLocations::blank();
    req.this_exact_package = Packaging::completion_submodule(I, sid);
    req.must_be_main_source_text = TRUE;
    return req;
}

location_requirement HierarchyLocations::generic_submodule(inter_tree *I, submodule_identity *sid) {
    location_requirement req = HierarchyLocations::blank();
    req.this_exact_package = Packaging::generic_submodule(I, sid);
    return req;
}

location_requirement HierarchyLocations::synoptic_submodule(inter_tree *I, submodule_identity *sid) {
    location_requirement req = HierarchyLocations::blank();
    req.this_exact_package = Packaging::synoptic_submodule(I, sid);
    return req;
}

location_requirement HierarchyLocations::any_package_of_type(text_stream *ptype_name) {
    location_requirement req = HierarchyLocations::blank();
    req.any_package_of_this_type = Str::duplicate(ptype_name);
    return req;
}

location_requirement HierarchyLocations::any_enclosure(void) {
    location_requirement req = HierarchyLocations::blank();
    req.any_enclosure = TRUE;
    return req;
}

location_requirement HierarchyLocations::the_veneer(inter_tree *I) {
    return HierarchyLocations::this_package(Site::veneer_request(I));
}

location_requirement HierarchyLocations::this_package(package_request *P) {
    location_requirement req = HierarchyLocations::blank();
    req.this_exact_package = P;
    return req;
}

location_requirement HierarchyLocations::this_exotic_package(int N) {
    location_requirement req = HierarchyLocations::blank();
    req.this_exact_package_not_yet_created = N;
    return req;
}

location_requirement HierarchyLocations::plug(void) {
    location_requirement req = HierarchyLocations::blank();
    req.must_be_plug = TRUE;
    return req;
}

§3. Hierarchy locations.

typedef struct hierarchy_location {
    int access_number;
    struct text_stream *access_name;
    struct text_stream *function_package_name;
    struct text_stream *datum_package_name;
    struct location_requirement requirements;
    struct inter_name *equates_to_iname;
    struct text_stream *package_type;
    struct name_translation trans;
    CLASS_DEFINITION
} hierarchy_location;

hierarchy_location *HierarchyLocations::new(void) {
    hierarchy_location *hl = CREATE(hierarchy_location);
    hl->access_number = -1;
    hl->access_name = NULL;
    hl->function_package_name = NULL;
    hl->datum_package_name = NULL;
    hl->equates_to_iname = NULL;
    hl->package_type = NULL;
    hl->trans = Translation::same();
    hl->requirements = HierarchyLocations::blank();
    return hl;
}

hierarchy_location *HierarchyLocations::ctr(inter_tree *I, int id, text_stream *name, name_translation nt, location_requirement req) {
    hierarchy_location *hl = HierarchyLocations::new();
    hl->access_number = id;
    hl->access_name = Str::duplicate(name);
    hl->requirements = req;
    hl->trans = nt;
    HierarchyLocations::index(I, hl);
    return hl;
}

hierarchy_location *HierarchyLocations::con(inter_tree *I, int id, text_stream *name, location_requirement req) {
    hierarchy_location *hl = HierarchyLocations::new();
    hl->access_number = id;
    hl->access_name = Str::duplicate(name);
    hl->requirements = req;
    hl->trans = Translation::same();
    HierarchyLocations::index(I, hl);
    return hl;
}

hierarchy_location *HierarchyLocations::pkg(inter_tree *I, int id, text_stream *name, text_stream *ptype_name, location_requirement req) {
    hierarchy_location *hl = HierarchyLocations::new();
    hl->access_number = id;
    hl->access_name = Str::duplicate(name);
    hl->requirements = req;
    hl->package_type = Str::duplicate(ptype_name);
    HierarchyLocations::index(I, hl);
    return hl;
}

hierarchy_location *HierarchyLocations::make_as(inter_tree *I, int id, text_stream *name, inter_name *iname) {
    hierarchy_location *hl = HierarchyLocations::new();
    hl->access_number = id;
    hl->access_name = Str::duplicate(name);
    hl->requirements = HierarchyLocations::this_package(InterNames::location(iname));
    hl->equates_to_iname = iname;
    HierarchyLocations::index(I, hl);
    return hl;
}

hierarchy_location *HierarchyLocations::fun(inter_tree *I, int id, text_stream *name, name_translation nt, location_requirement req) {
    hierarchy_location *hl = CREATE(hierarchy_location);
    hl->access_number = id;
    hl->access_name = Str::duplicate(nt.translate_to);
    hl->function_package_name = Str::duplicate(name);
    hl->requirements = req;
    hl->trans = nt;
    HierarchyLocations::index(I, hl);
    return hl;
}

hierarchy_location *HierarchyLocations::dat(inter_tree *I, int id, text_stream *name, name_translation nt, location_requirement req) {
    hierarchy_location *hl = CREATE(hierarchy_location);
    hl->access_number = id;
    hl->access_name = Str::duplicate(nt.translate_to);
    hl->datum_package_name = Str::duplicate(name);
    hl->requirements = req;
    hl->trans = nt;
    HierarchyLocations::index(I, hl);
    return hl;
}

void HierarchyLocations::index(inter_tree *I, hierarchy_location *hl) {
    if (hl->access_number >= 0) I->site.hls_indexed_by_id[hl->access_number] = hl;
    if (hl->requirements.any_package_of_this_type == NULL) {
        Dictionaries::create(I->site.hls_indexed_by_name, hl->access_name);
        Dictionaries::write_value(I->site.hls_indexed_by_name, hl->access_name, (void *) hl);
    }
}

inter_name *HierarchyLocations::find(inter_tree *I, int id) {
    if ((id < 0) || (id >= NO_DEFINED_HL_VALUES) || (I->site.hls_indexed_by_id[id] == NULL))
        internal_error("bad hl ID");
    return HierarchyLocations::hl_to_iname(I, I->site.hls_indexed_by_id[id]);
}

inter_name *HierarchyLocations::find_by_name(inter_tree *I, text_stream *name) {
    if (Str::len(name) == 0) internal_error("bad hl name");
    if (Dictionaries::find(I->site.hls_indexed_by_name, name))
        return HierarchyLocations::hl_to_iname(I,
            (hierarchy_location *)
                Dictionaries::read_value(I->site.hls_indexed_by_name, name));
    return NULL;
}

inter_name *HierarchyLocations::function(inter_tree *I, package_request *R, text_stream *name, text_stream *trans) {
    inter_name *iname = Packaging::function(I, InterNames::explicitly_named(name, R), NULL);
    if (trans) Produce::change_translation(iname, trans);
    return iname;
}

inter_name *HierarchyLocations::hl_to_iname(inter_tree *I, hierarchy_location *hl) {
    if (hl->requirements.any_package_of_this_type) internal_error("NRL accessed inappropriately");
    if (hl->equates_to_iname == NULL) {
        if (hl->requirements.must_be_plug) {
            hl->equates_to_iname = InterNames::explicitly_named_in_template(I, hl->access_name);
        } else {
            if (hl->requirements.this_exact_package == NULL) {
                if (hl->requirements.this_exact_package_not_yet_created >= 0) {
                    #ifdef CORE_MODULE
                    hl->requirements.this_exact_package = Hierarchy::exotic_package(hl->requirements.this_exact_package_not_yet_created);
                    #endif
                    #ifndef CORE_MODULE
                    internal_error("feature not available in inter");
                    #endif
                } else internal_error("package can't be found");
            }
            if (Str::len(hl->function_package_name) > 0) {
                hl->equates_to_iname = Packaging::function_text(I,
                    InterNames::explicitly_named(hl->function_package_name, hl->requirements.this_exact_package),
                    hl->access_name);
            } else if (Str::len(hl->datum_package_name) > 0) {
                hl->equates_to_iname = Packaging::datum_text(I,
                    InterNames::explicitly_named(hl->datum_package_name, hl->requirements.this_exact_package),
                    hl->access_name);
            } else if ((hl->requirements.this_exact_package) && (hl->equates_to_iname == NULL)) {
                hl->equates_to_iname = InterNames::explicitly_named(hl->access_name, hl->requirements.this_exact_package);
            }
        }
        hl->requirements.this_exact_package = InterNames::location(hl->equates_to_iname);

        if (hl->trans.translate_to) Produce::change_translation(hl->equates_to_iname, hl->trans.translate_to);
    }
    return hl->equates_to_iname;
}

inter_name *HierarchyLocations::find_in_package(inter_tree *I, int id, package_request *P, wording W, inter_name *derive_from, int fix, text_stream *imposed_name) {
    if ((id < 0) || (id >= NO_DEFINED_HL_VALUES) || (I->site.hls_indexed_by_id[id] == NULL))
        internal_error("bad hl ID");
    hierarchy_location *hl = I->site.hls_indexed_by_id[id];
    if ((hl->requirements.any_package_of_this_type == NULL) &&
        (hl->requirements.any_enclosure == FALSE)) internal_error("NRL accessed inappropriately");
    if (hl->requirements.any_enclosure) {
        if (Inter::Symbols::read_annotation(P->eventual_type, ENCLOSING_IANN) != 1)
            internal_error("subpackage not in enclosing superpackage");
    } else if (P == NULL) {
        internal_error("constant in null package");
    } else if (P->eventual_type != PackageTypes::get(I, hl->requirements.any_package_of_this_type)) {
        LOG("AN: %S, FPN: %S\n", hl->access_name, hl->function_package_name);
        LOG("Have type: $3, required: %S\n", P->eventual_type, hl->requirements.any_package_of_this_type);
        internal_error("constant in wrong superpackage");
    }

    inter_name *iname = NULL;
    if (hl->trans.translate_to)  {
        text_stream *T = hl->trans.translate_to;
        Make the actual iname3.1;
    } else if (hl->trans.by_imposition) {
        text_stream *T = NULL;
        Make the actual iname3.1;
    } else if (hl->trans.name_generator) {
        TEMPORARY_TEXT(T)
        inter_name *temp_iname = NULL;
        if (derive_from) {
            temp_iname = InterNames::derived(hl->trans.name_generator, derive_from, W);
        } else {
            temp_iname = InterNames::generated(hl->trans.name_generator, fix, W);
        }
        W = EMPTY_WORDING;
        WRITE_TO(T, "%n", temp_iname);
        Make the actual iname3.1;
        DISCARD_TEXT(T)
    } else {
        text_stream *T = NULL;
        Make the actual iname3.1;
    }

    if (hl->trans.then_make_unique) Produce::set_flag(iname, MAKE_NAME_UNIQUE);
    return iname;
}

§3.1. Make the actual iname3.1 =

    if (Str::len(hl->function_package_name) > 0) {
        iname = Packaging::function(I,
            InterNames::explicitly_named(hl->function_package_name, P), NULL);
    } else {
        if (hl->trans.by_imposition) iname = InterNames::explicitly_named_with_memo(imposed_name, P, W);
        else if (Str::len(hl->access_name) == 0) iname = InterNames::explicitly_named_with_memo(T, P, W);
        else iname = InterNames::explicitly_named_with_memo(hl->access_name, P, W);
    }
    if ((Str::len(T) > 0) && (hl->access_name)) Produce::change_translation(iname, T);

§4.

package_request *HierarchyLocations::package_in_package(inter_tree *I, int id, package_request *P) {
    if ((id < 0) || (id >= NO_DEFINED_HL_VALUES) || (I->site.hls_indexed_by_id[id] == NULL))
        internal_error("bad hl ID");
    hierarchy_location *hl = I->site.hls_indexed_by_id[id];

    if (P == NULL) internal_error("no superpackage");
    if (hl->package_type == NULL) internal_error("package_in_package used wrongly");
    if (hl->requirements.any_package_of_this_type) {
        if (P->eventual_type != PackageTypes::get(I, hl->requirements.any_package_of_this_type))
            internal_error("subpackage in wrong superpackage");
    } else if (hl->requirements.any_enclosure) {
        if (Inter::Symbols::read_annotation(P->eventual_type, ENCLOSING_IANN) != 1)
            internal_error("subpackage not in enclosing superpackage");
    } else internal_error("NRL accessed inappropriately");

    return Packaging::request(I, InterNames::explicitly_named(hl->access_name, P), PackageTypes::get(I, hl->package_type));
}

§5. Hierarchy locations.

typedef struct hierarchy_attachment_point {
    int hap_id;
    struct text_stream *name_stem;
    struct text_stream *type;
    struct location_requirement requirements;
    CLASS_DEFINITION
} hierarchy_attachment_point;

void HierarchyLocations::index_ap(inter_tree *I, hierarchy_attachment_point *hap) {
    if (hap->hap_id >= 0) I->site.haps_indexed_by_id[hap->hap_id] = hap;
}

hierarchy_attachment_point *HierarchyLocations::att(inter_tree *I, int hap_id, text_stream *iterated_text, text_stream *ptype_name, location_requirement req) {
    hierarchy_attachment_point *hap = CREATE(hierarchy_attachment_point);
    hap->hap_id = hap_id;
    hap->requirements = req;
    hap->name_stem = Str::duplicate(iterated_text);
    hap->type = Str::duplicate(ptype_name);
    HierarchyLocations::index_ap(I, hap);
    return hap;
}

#ifdef CORE_MODULE
package_request *HierarchyLocations::attach_new_package(inter_tree *I, compilation_unit *C, package_request *R, int hap_id) {
    if ((hap_id < 0) || (hap_id >= NO_DEFINED_HAP_VALUES) || (I->site.haps_indexed_by_id[hap_id] == NULL))
        internal_error("invalid HAP request");
    hierarchy_attachment_point *hap = I->site.haps_indexed_by_id[hap_id];
    if (hap->requirements.must_be_main_source_text) {
        R = hap->requirements.this_exact_package;
    } else if (hap->requirements.any_submodule_package_of_this_identity) {
        R = Packaging::request_submodule(I, C, hap->requirements.any_submodule_package_of_this_identity);
    } else if (hap->requirements.this_exact_package) {
        R = hap->requirements.this_exact_package;
    } else if (hap->requirements.this_exact_package_not_yet_created >= 0) {
        R = Hierarchy::exotic_package(hap->requirements.this_exact_package_not_yet_created);
    } else if (hap->requirements.any_package_of_this_type) {
        if ((R == NULL) || (R->eventual_type != PackageTypes::get(I, hap->requirements.any_package_of_this_type)))
            internal_error("subpackage in wrong superpackage");
    }

    return Packaging::request(I, Packaging::make_iname_within(R, hap->name_stem), PackageTypes::get(I, hap->type));
}
#endif