Looking up metadata in special constants.

§1. This section is in some ways a postscript to The Constant Construct. If constants are created which have names matching...

int Metadata::valid_key(text_stream *key) {
    if (Str::get_at(key, 0) == '^') return TRUE;
    return FALSE;
}

§2. ...then their symbols are given the METADATA_KEY_ISYMF flag: see InterSymbol::new_for_symbols_table. These symbols never code-generate: see Vanilla Constants (in final). It follows that metadata cannot be part of the program at runtime. Nor can metadata be wired to anything else, either way round — see Wiring::wire_to.

So the only purpose metadata can serve is to annotate the program, to assist tools such as the pipeline module. Metadata helps with linking, optimisation, and similar tasks.

Since metadata exists solely so that other parts of the Inform tool chain can read its values, we clearly need an API for doing that, and this is the point of the present section.

§3. Some metadata keys are expected, and others are optional. The following determines whether a given package pack contains a value for metadata key:

inter_tree_node *Metadata::value_node(inter_package *pack, text_stream *key) {
    inter_symbol *md = InterSymbolsTable::symbol_from_name(InterPackage::scope(pack), key);
    if (md) return md->definition;
    return NULL;
}

int Metadata::exists(inter_package *pack, text_stream *key) {
    if (Metadata::value_node(pack, key)) return TRUE;
    return FALSE;
}

§4. So for each kind of data we allow, we provide a required and an optional version, which differ only in that the required version halts with an error if the key is missing.

inter_ti Metadata::read_numeric(inter_package *pack, text_stream *key) {
    inter_tree_node *D = Metadata::value_node(pack, key);
    if (D) Extract the numeric value4.1;
    Metadata::err("not defined", pack, key); return 0;
}

inter_ti Metadata::read_optional_numeric(inter_package *pack, text_stream *key) {
    inter_tree_node *D = Metadata::value_node(pack, key);
    if (D) Extract the numeric value4.1;
    return 0;
}

§4.1. Extract the numeric value4.1 =

    if (ConstantInstruction::list_format(D) == CONST_LIST_FORMAT_NONE) {
        inter_pair val = ConstantInstruction::constant(D);
        if (InterValuePairs::is_number(val) == FALSE)
            Metadata::err("not numeric", pack, key);
        return InterValuePairs::to_number(val);
    }

§5. A metadata key cannot be wired to a symbol; but it can have its value set to a symbol, so:

inter_symbol *Metadata::required_symbol(inter_package *pack, text_stream *key) {
    inter_tree_node *D = Metadata::value_node(pack, key);
    if (D) Extract the symbolic value5.1;
    Metadata::err("required symbolic metadata not supplied", pack, key);
    return NULL;
}

inter_symbol *Metadata::optional_symbol(inter_package *pack, text_stream *key) {
    inter_tree_node *D = Metadata::value_node(pack, key);
    if (D) Extract the symbolic value5.1;
    return NULL;
}

§5.1. Extract the symbolic value5.1 =

    if ((D) && (ConstantInstruction::list_format(D) == CONST_LIST_FORMAT_NONE)) {
        inter_pair val = ConstantInstruction::constant(D);
        if (InterValuePairs::is_symbolic(val) == FALSE)
            Metadata::err("not symbolic", pack, key);
        return InterValuePairs::to_symbol_in(val, pack);
    }

§6. Text:

text_stream *Metadata::required_textual(inter_package *pack, text_stream *key) {
    inter_tree_node *D = Metadata::value_node(pack, key);
    if (D) Extract the textual value6.1;
    Metadata::err("required textual metadata not supplied", pack, key);
    return NULL;
}

text_stream *Metadata::optional_textual(inter_package *pack, text_stream *key) {
    inter_tree_node *D = Metadata::value_node(pack, key);
    if (D) Extract the textual value6.1;
    return NULL;
}

§6.1. Extract the textual value6.1 =

    if (ConstantInstruction::list_format(D) == CONST_LIST_FORMAT_NONE) {
        inter_pair val = ConstantInstruction::constant(D);
        if (InterValuePairs::is_text(val) == FALSE)
            Metadata::err("not textual", pack, key);
        return InterValuePairs::to_text(InterPackage::tree(pack), val);
    }

§7. Lists (which are optional only, and return only as the node from which values must then be extracted):

inter_tree_node *Metadata::optional_list(inter_package *pack, text_stream *key) {
    inter_tree_node *D = Metadata::value_node(pack, key);
    if ((D) && (ConstantInstruction::list_format(D) == CONST_LIST_FORMAT_WORDS))
        return D;
    return NULL;
}

§8. Metadata errors are fatal:

void Metadata::err(char *err, inter_package *pack, text_stream *key) {
    WRITE_TO(STDERR, "Error on metadata '%S' in package '", key);
    InterPackage::write_URL(STDERR, pack);
    WRITE_TO(STDERR, "': %s\n", err);
    internal_error(err);
}