Basic support for languages to recognise structure and function declarations.
§1. For each typedef struct we find, we will make one of these:
typedef struct language_type { struct text_stream *structure_name; int tangled; whether the structure definition has been tangled out struct source_line *structure_header_at; opening line of typedef struct source_line *typedef_ends; closing line, where } appears struct linked_list *incorporates; of language_type struct linked_list *elements; of structure_element struct language_type *next_cst_alphabetically; CLASS_DEFINITION } language_type;
- The structure language_type is accessed in 3/tw, 4/as, 4/cl, 6/cs, 6/cln and here.
language_type *first_cst_alphabetically = NULL; language_type *Functions::new_struct(web *W, text_stream *name, source_line *L) { language_type *str = CREATE(language_type); Initialise the language type structure2.1; Analyser::mark_reserved_word_at_line(L, str->structure_name, RESERVED_COLOUR); Add this to the lists for its web and its paragraph2.2; Insertion-sort this into the alphabetical list of all structures found2.3; return str; }
§2.1. Initialise the language type structure2.1 =
str->structure_name = Str::duplicate(name); str->structure_header_at = L; str->tangled = FALSE; str->typedef_ends = NULL; str->incorporates = NEW_LINKED_LIST(language_type); str->elements = NEW_LINKED_LIST(structure_element);
- This code is used in §2.
§2.2. Add this to the lists for its web and its paragraph2.2 =
Tags::add_by_name(L->owning_paragraph, I"Structures"); ADD_TO_LINKED_LIST(str, language_type, W->language_types); ADD_TO_LINKED_LIST(str, language_type, L->owning_paragraph->structures);
- This code is used in §2.
§2.3. Insertion-sort this into the alphabetical list of all structures found2.3 =
str->next_cst_alphabetically = NULL; if (first_cst_alphabetically == NULL) first_cst_alphabetically = str; else { int placed = FALSE; language_type *last = NULL; for (language_type *seq = first_cst_alphabetically; seq; seq = seq->next_cst_alphabetically) { if (Str::cmp(str->structure_name, seq->structure_name) < 0) { if (seq == first_cst_alphabetically) { str->next_cst_alphabetically = first_cst_alphabetically; first_cst_alphabetically = str; } else { last->next_cst_alphabetically = str; str->next_cst_alphabetically = seq; } placed = TRUE; break; } last = seq; } if (placed == FALSE) last->next_cst_alphabetically = str; }
- This code is used in §2.
§3. A language can also create an instance of structure_element to record the existence of the element val, and add it to the linked list of elements of the structure being defined.
In InC, only, certain element names used often in Inform's source code are given mildly special treatment. This doesn't amount to much. allow_sharing has no effect on tangling, so it doesn't change the program. It simply affects the reports in the woven code about where structures are used.
typedef struct structure_element { struct text_stream *element_name; struct source_line *element_created_at; int allow_sharing; CLASS_DEFINITION } structure_element;
- The structure structure_element is accessed in 3/tw, 4/as and here.
structure_element *Functions::new_element(language_type *str, text_stream *elname, source_line *L) { Analyser::mark_reserved_word_at_line(L, elname, ELEMENT_COLOUR); structure_element *elt = CREATE(structure_element); elt->element_name = Str::duplicate(elname); elt->allow_sharing = FALSE; elt->element_created_at = L; if (LanguageMethods::share_element(L->owning_section->sect_language, elname)) elt->allow_sharing = TRUE; ADD_TO_LINKED_LIST(elt, structure_element, str->elements); return elt; }
language_type *Functions::find_structure(web *W, text_stream *name) { language_type *str; LOOP_OVER_LINKED_LIST(str, language_type, W->language_types) if (Str::eq(name, str->structure_name)) return str; return NULL; }
§6. Functions. Each function definition found results in one of these structures being made:
typedef struct language_function { struct text_stream *function_name; e.g., "cultivate" struct text_stream *function_type; e.g., "tree *" struct text_stream *function_arguments; e.g., "int rainfall)": note ) struct source_line *function_header_at; where the first line of the header begins int within_namespace; written using InC namespace dividers int called_from_other_sections; int call_freely; int usage_described; int no_conditionals; struct source_line *within_conditionals[MAX_CONDITIONAL_COMPILATION_STACK]; CLASS_DEFINITION } language_function;
- The structure language_function is accessed in 3/tw, 3/twot, 4/as, 4/cl, 5/ptf, 5/tf, 5/hf, 5/df, 6/cs, 6/cln and here.
language_function *Functions::new_function(text_stream *fname, source_line *L) { Check the function is not a duplicate definition within the same paragraph7.2; hash_table_entry *hte = Analyser::mark_reserved_word_at_line(L, fname, FUNCTION_COLOUR); language_function *fn = CREATE(language_function); hte->as_function = fn; Initialise the function structure7.1; Add the function to its paragraph and line7.3; if (L->owning_section->sect_language->supports_namespaces) Check that the function has its namespace correctly declared7.4; return fn; }
§7.1. Note that we take a snapshot of the conditional compilation stack as part of the function structure. We'll need it when predeclaring the function.
Initialise the function structure7.1 =
fn->function_name = Str::duplicate(fname); fn->function_arguments = Str::new(); fn->function_type = Str::new(); fn->within_namespace = FALSE; fn->called_from_other_sections = FALSE; fn->call_freely = FALSE; fn->function_header_at = L; fn->usage_described = FALSE; if ((Str::eq_wide_string(fname, U"main")) && (L->owning_section->sect_language->C_like)) fn->usage_described = TRUE; fn->no_conditionals = 0;
- This code is used in §7.
§7.2. The following would become inefficient if there were enormous numbers of functions defined in the same paragraph, but for now the overhead of creating a dictionary with hash-lookup seems greater than the plausible saving of time. The point of this check is to handle situations where the code in the web is offering alternative definitions of the same function, within some form of conditional compilation preprocessing — if this, define f as this; otherwise, define f as that — which can otherwise be read as two declarations of f, leading to spurious extra text at the weaving stage.
Check the function is not a duplicate definition within the same paragraph7.2 =
paragraph *P = L->owning_paragraph; language_function *fn; LOOP_OVER_LINKED_LIST(fn, language_function, P->functions) if (Str::eq(fname, fn->function_name)) return fn;
- This code is used in §7.
§7.3. Add the function to its paragraph and line7.3 =
paragraph *P = L->owning_paragraph; if (P) ADD_TO_LINKED_LIST(fn, language_function, P->functions); L->function_defined = fn;
- This code is used in §7.
§7.4. Check that the function has its namespace correctly declared7.4 =
text_stream *declared_namespace = NULL; text_stream *ambient_namespace = L->owning_section->sect_namespace; match_results mr = Regexp::create_mr(); if (Regexp::match(&mr, fname, U"(%c+::)%c*")) { declared_namespace = mr.exp[0]; fn->within_namespace = TRUE; } else if ((Str::eq_wide_string(fname, U"main")) && (Str::eq_wide_string(ambient_namespace, U"Main::"))) declared_namespace = I"Main::"; if ((Str::ne(declared_namespace, ambient_namespace)) && (L->owning_paragraph->placed_very_early == FALSE)) { TEMPORARY_TEXT(err_mess) if (Str::len(declared_namespace) == 0) WRITE_TO(err_mess, "Function '%S' should have namespace prefix '%S'", fname, ambient_namespace); else if (Str::len(ambient_namespace) == 0) WRITE_TO(err_mess, "Function '%S' declared in a section with no namespace", fname); else WRITE_TO(err_mess, "Function '%S' declared in a section with the wrong namespace '%S'", fname, ambient_namespace); Main::error_in_web(err_mess, L); DISCARD_TEXT(err_mess) } Regexp::dispose_of(&mr);
- This code is used in §7.
§8. "Elsewhere" here means "in a paragraph of code other than the one in which the function's definition appears".
int Functions::used_elsewhere(language_function *fn) { paragraph *P = fn->function_header_at->owning_paragraph; hash_table_entry *hte = Analyser::find_hash_entry_for_section(fn->function_header_at->owning_section, fn->function_name, FALSE); hash_table_entry_usage *hteu = NULL; LOOP_OVER_LINKED_LIST(hteu, hash_table_entry_usage, hte->usages) if ((P != hteu->usage_recorded_at) && (P->under_section == hteu->usage_recorded_at->under_section)) return TRUE; LOOP_OVER_LINKED_LIST(hteu, hash_table_entry_usage, hte->usages) if (P->under_section != hteu->usage_recorded_at->under_section) return TRUE; return FALSE; }
§9. Cataloguing. This implements the additional information in the -structures and -functions forms of section catalogue.
void Functions::catalogue(section *S, int functions_too) { language_type *str; LOOP_OVER(str, language_type) if (str->structure_header_at->owning_section == S) PRINT(" %S ", str->structure_name); if (functions_too) { language_function *fn; LOOP_OVER(fn, language_function) if (fn->function_header_at->owning_section == S) PRINT("\n %S", fn->function_name); } }