2022-02-10 01:48:51 +02:00
|
|
|
[TextualInter::] Inter in Text Files.
|
2019-02-05 02:44:07 +02:00
|
|
|
|
2022-02-10 01:48:51 +02:00
|
|
|
To read a tree from a file written in the plain text version of Inter.
|
2019-02-05 02:44:07 +02:00
|
|
|
|
|
|
|
@h Reading textual inter.
|
|
|
|
|
|
|
|
=
|
2022-02-10 01:48:51 +02:00
|
|
|
void TextualInter::read(inter_tree *I, filename *F) {
|
|
|
|
LOGIF(INTER_FILE_READ, "Reading textual inter file %f\n", F);
|
|
|
|
irl_state irl;
|
|
|
|
irl.no_blank_lines_stacked = 0;
|
2022-01-27 01:59:02 +02:00
|
|
|
inter_bookmark IBM = InterBookmark::at_start_of_this_repository(I);
|
2022-02-10 01:48:51 +02:00
|
|
|
irl.write_pos = &IBM;
|
|
|
|
TextFiles::read(F, FALSE, "can't open inter file", FALSE,
|
|
|
|
TextualInter::read_line, 0, &irl);
|
|
|
|
TextualInter::resolve_forward_references(I);
|
2022-02-09 12:33:49 +02:00
|
|
|
InterConstruct::tree_lint(I);
|
2022-01-14 12:56:42 +02:00
|
|
|
Primitives::index_primitives_in_tree(I);
|
2019-07-08 13:21:00 +03:00
|
|
|
}
|
|
|
|
|
2022-02-10 01:48:51 +02:00
|
|
|
@ This fussy little mechanism passes each line of the text file to
|
|
|
|
//TextualInter::parse_single_line//, except that it omits any run of blank
|
|
|
|
lines at the end. (Most text files technically have one blank line at the end
|
|
|
|
without anyone realising it.)
|
|
|
|
|
|
|
|
=
|
|
|
|
typedef struct irl_state {
|
|
|
|
int no_blank_lines_stacked;
|
|
|
|
struct inter_bookmark *write_pos;
|
|
|
|
} irl_state;
|
|
|
|
|
|
|
|
void TextualInter::read_line(text_stream *line, text_file_position *tfp, void *state) {
|
|
|
|
irl_state *irl = (irl_state *) state;
|
|
|
|
inter_error_location eloc = Inter::Errors::file_location(line, tfp);
|
|
|
|
if (Str::len(line) == 0) { irl->no_blank_lines_stacked++; return; }
|
|
|
|
for (int i=0; i<irl->no_blank_lines_stacked; i++) {
|
|
|
|
inter_error_location b_eloc = Inter::Errors::file_location(I"", tfp);
|
|
|
|
inter_error_message *E =
|
|
|
|
TextualInter::parse_single_line(I"#", &b_eloc, irl->write_pos);
|
|
|
|
if (E) Inter::Errors::issue(E);
|
|
|
|
}
|
|
|
|
irl->no_blank_lines_stacked = 0;
|
|
|
|
inter_error_message *E =
|
|
|
|
TextualInter::parse_single_line(line, &eloc, irl->write_pos);
|
|
|
|
if (E) Inter::Errors::issue(E);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct inter_line_parse {
|
|
|
|
struct text_stream *line;
|
|
|
|
struct match_results mr;
|
|
|
|
struct inter_annotation_set set;
|
|
|
|
inter_ti terminal_comment;
|
|
|
|
int indent_level;
|
|
|
|
} inter_line_parse;
|
|
|
|
|
|
|
|
inter_error_message *TextualInter::parse_single_line(text_stream *line, inter_error_location *eloc, inter_bookmark *IBM) {
|
|
|
|
inter_line_parse ilp;
|
|
|
|
ilp.line = line;
|
|
|
|
ilp.mr = Regexp::create_mr();
|
|
|
|
ilp.terminal_comment = 0;
|
|
|
|
ilp.set = SymbolAnnotation::new_annotation_set();
|
|
|
|
ilp.indent_level = 0;
|
|
|
|
|
|
|
|
LOOP_THROUGH_TEXT(P, ilp.line) {
|
|
|
|
wchar_t c = Str::get(P);
|
|
|
|
if (c == '\t') ilp.indent_level++;
|
|
|
|
else if (c == ' ')
|
|
|
|
return Inter::Errors::plain(I"spaces (rather than tabs) at the beginning of this line", eloc);
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* int quoted = FALSE, literal = FALSE;
|
|
|
|
LOOP_THROUGH_TEXT(P, ilp.line) {
|
|
|
|
wchar_t c = Str::get(P);
|
|
|
|
if ((literal == FALSE) && (c == '"')) quoted = (quoted)?FALSE:TRUE;
|
|
|
|
literal = FALSE;
|
|
|
|
if (c == '\\') literal = TRUE;
|
|
|
|
if ((c == '#') && ((P.index == 0) || (Str::get_at(ilp.line, P.index-1) != '#')) && (Str::get_at(ilp.line, P.index+1) != '#') && (quoted == FALSE)) {
|
|
|
|
ilp.terminal_comment = InterWarehouse::create_text(InterBookmark::warehouse(IBM), InterBookmark::package(IBM));
|
|
|
|
int at = Str::index(P);
|
|
|
|
P = Str::forward(P);
|
|
|
|
while (Str::get(P) == ' ') P = Str::forward(P);
|
|
|
|
Str::substr(InterWarehouse::get_text(InterBookmark::warehouse(IBM), ilp.terminal_comment), P, Str::end(ilp.line));
|
|
|
|
Str::truncate(ilp.line, at);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
Str::trim_white_space(ilp.line);
|
|
|
|
|
|
|
|
if (ilp.indent_level == 0) TextualInter::set_latest_block_package(NULL);
|
|
|
|
|
|
|
|
while ((InterBookmark::package(IBM)) && (InterPackage::is_a_root_package(InterBookmark::package(IBM)) == FALSE) && (ilp.indent_level <= InterBookmark::baseline(IBM))) {
|
|
|
|
InterBookmark::move_into_package(IBM, InterPackage::parent(InterBookmark::package(IBM)));
|
|
|
|
}
|
|
|
|
|
|
|
|
while (Regexp::match(&ilp.mr, ilp.line, L"(%c+) (__%c+) *")) {
|
|
|
|
Str::copy(ilp.line, ilp.mr.exp[0]);
|
|
|
|
inter_error_message *E = NULL;
|
|
|
|
inter_annotation IA = SymbolAnnotation::read_annotation(InterBookmark::tree(IBM), ilp.mr.exp[1], eloc, &E);
|
|
|
|
if (E) return E;
|
|
|
|
SymbolAnnotation::write_to_set(IA.annot->iatype, &(ilp.set), IA);
|
|
|
|
}
|
|
|
|
|
|
|
|
return InterConstruct::match(&ilp, eloc, IBM);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inter_symbol *TextualInter::new_symbol(inter_error_location *eloc, inter_symbols_table *T, text_stream *name, inter_error_message **E) {
|
2019-02-05 02:44:07 +02:00
|
|
|
*E = NULL;
|
2022-02-03 17:51:44 +02:00
|
|
|
inter_symbol *symb = InterSymbolsTable::symbol_from_name(T, name);
|
2019-02-05 02:44:07 +02:00
|
|
|
if (symb) {
|
2022-02-10 01:48:51 +02:00
|
|
|
if (InterSymbol::misc_but_undefined(symb)) return symb;
|
2019-02-05 02:44:07 +02:00
|
|
|
*E = Inter::Errors::quoted(I"symbol already exists", name, eloc);
|
|
|
|
return NULL;
|
|
|
|
}
|
2022-02-03 17:51:44 +02:00
|
|
|
return InterSymbolsTable::symbol_from_name_creating(T, name);
|
2019-02-05 02:44:07 +02:00
|
|
|
}
|
|
|
|
|
2022-02-10 01:48:51 +02:00
|
|
|
inter_symbol *TextualInter::find_symbol(inter_tree *I, inter_error_location *eloc, inter_symbols_table *T, text_stream *name, inter_ti construct, inter_error_message **E) {
|
2019-02-05 02:44:07 +02:00
|
|
|
*E = NULL;
|
2022-02-03 17:51:44 +02:00
|
|
|
inter_symbol *symb = InterSymbolsTable::symbol_from_name(T, name);
|
2019-02-05 02:44:07 +02:00
|
|
|
if (symb == NULL) { *E = Inter::Errors::quoted(I"no such symbol", name, eloc); return NULL; }
|
2022-02-03 21:44:57 +02:00
|
|
|
inter_tree_node *D = InterSymbol::definition(symb);
|
2022-02-04 02:55:12 +02:00
|
|
|
if (InterSymbol::defined_elsewhere(symb)) return symb;
|
2022-02-04 12:04:41 +02:00
|
|
|
if (InterSymbol::misc_but_undefined(symb)) return symb;
|
2019-07-24 17:19:38 +03:00
|
|
|
if (D == NULL) { *E = Inter::Errors::quoted(I"undefined symbol", name, eloc); return NULL; }
|
2022-02-04 12:04:41 +02:00
|
|
|
if ((D->W.instruction[ID_IFLD] != construct) && (InterSymbol::misc_but_undefined(symb) == FALSE)) {
|
2019-02-05 02:44:07 +02:00
|
|
|
*E = Inter::Errors::quoted(I"symbol of wrong type", name, eloc); return NULL;
|
|
|
|
}
|
|
|
|
return symb;
|
|
|
|
}
|
|
|
|
|
2022-02-10 01:48:51 +02:00
|
|
|
inter_symbol *TextualInter::find_undefined_symbol(inter_bookmark *IBM, inter_error_location *eloc, inter_symbols_table *T, text_stream *name, inter_error_message **E) {
|
2019-02-05 02:44:07 +02:00
|
|
|
*E = NULL;
|
2022-02-03 17:51:44 +02:00
|
|
|
inter_symbol *symb = InterSymbolsTable::symbol_from_name(T, name);
|
2019-02-05 02:44:07 +02:00
|
|
|
if (symb == NULL) { *E = Inter::Errors::quoted(I"no such symbol", name, eloc); return NULL; }
|
2022-02-04 12:04:41 +02:00
|
|
|
if (InterSymbol::is_defined(symb)) {
|
|
|
|
WRITE_TO(STDERR, "Symbol is: %S\n", symb->symbol_name);
|
2022-02-03 21:44:57 +02:00
|
|
|
inter_tree_node *D = InterSymbol::definition(symb);
|
2022-02-07 00:33:07 +02:00
|
|
|
InterConstruct::write_construct_text(STDERR, D);
|
2019-02-05 02:44:07 +02:00
|
|
|
*E = Inter::Errors::quoted(I"symbol already defined", name, eloc);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return symb;
|
|
|
|
}
|
|
|
|
|
2022-02-10 01:48:51 +02:00
|
|
|
inter_symbol *TextualInter::find_KOI(inter_error_location *eloc, inter_symbols_table *T, text_stream *name, inter_error_message **E) {
|
2019-02-05 02:44:07 +02:00
|
|
|
*E = NULL;
|
2022-02-03 17:51:44 +02:00
|
|
|
inter_symbol *symb = InterSymbolsTable::symbol_from_name(T, name);
|
2019-02-05 02:44:07 +02:00
|
|
|
if (symb == NULL) { *E = Inter::Errors::quoted(I"no such symbol", name, eloc); return NULL; }
|
2022-02-03 21:44:57 +02:00
|
|
|
inter_tree_node *D = InterSymbol::definition(symb);
|
2019-07-24 17:19:38 +03:00
|
|
|
if (D == NULL) { *E = Inter::Errors::quoted(I"undefined symbol", name, eloc); return NULL; }
|
2022-01-30 15:32:38 +02:00
|
|
|
if ((D->W.instruction[ID_IFLD] != KIND_IST) &&
|
|
|
|
(D->W.instruction[ID_IFLD] != INSTANCE_IST)) { *E = Inter::Errors::quoted(I"symbol of wrong type", name, eloc); return NULL; }
|
2019-02-05 02:44:07 +02:00
|
|
|
return symb;
|
|
|
|
}
|
|
|
|
|
2022-02-10 01:48:51 +02:00
|
|
|
inter_data_type *TextualInter::data_type(inter_error_location *eloc, text_stream *name, inter_error_message **E) {
|
2019-02-05 02:44:07 +02:00
|
|
|
inter_data_type *idt = Inter::Types::find_by_name(name);
|
|
|
|
if (idt == NULL) *E = Inter::Errors::quoted(I"no such data type", name, eloc);
|
|
|
|
return idt;
|
|
|
|
}
|
|
|
|
|
|
|
|
@h Writing textual inter.
|
|
|
|
|
|
|
|
=
|
2022-02-10 01:48:51 +02:00
|
|
|
void TextualInter::writer(OUTPUT_STREAM, char *format_string, void *vI) {
|
2019-07-22 02:01:18 +03:00
|
|
|
inter_tree *I = (inter_tree *) vI;
|
2022-02-10 01:48:51 +02:00
|
|
|
TextualInter::write(OUT, I, NULL, 1);
|
2019-02-05 02:44:07 +02:00
|
|
|
}
|
|
|
|
|
2019-07-08 13:21:00 +03:00
|
|
|
typedef struct textual_write_state {
|
|
|
|
struct text_stream *to;
|
2019-07-24 20:15:07 +03:00
|
|
|
int (*filter)(inter_tree_node, int);
|
2019-07-08 13:21:00 +03:00
|
|
|
int pass;
|
|
|
|
} textual_write_state;
|
|
|
|
|
2022-02-10 01:48:51 +02:00
|
|
|
void TextualInter::write(OUTPUT_STREAM, inter_tree *I, int (*filter)(inter_tree_node, int), int pass) {
|
2019-02-05 02:44:07 +02:00
|
|
|
if (I == NULL) { WRITE("<no-inter>\n"); return; }
|
2019-07-08 13:21:00 +03:00
|
|
|
textual_write_state tws;
|
|
|
|
tws.to = OUT;
|
|
|
|
tws.filter = filter;
|
|
|
|
tws.pass = pass;
|
2022-02-10 01:48:51 +02:00
|
|
|
InterTree::traverse_root_only(I, TextualInter::visitor, &tws, -PACKAGE_IST);
|
|
|
|
InterTree::traverse(I, TextualInter::visitor, &tws, NULL, 0);
|
2019-07-08 13:21:00 +03:00
|
|
|
}
|
2022-02-10 01:48:51 +02:00
|
|
|
void TextualInter::visitor(inter_tree *I, inter_tree_node *P, void *state) {
|
2019-07-08 13:21:00 +03:00
|
|
|
textual_write_state *tws = (textual_write_state *) state;
|
2019-07-24 17:19:38 +03:00
|
|
|
if ((tws->filter) && ((*(tws->filter))(*P, tws->pass) == FALSE)) return;
|
2022-02-07 00:33:07 +02:00
|
|
|
inter_error_message *E = InterConstruct::write_construct_text(tws->to, P);
|
2019-07-08 13:21:00 +03:00
|
|
|
if (E) Inter::Errors::issue(E);
|
2019-02-05 02:44:07 +02:00
|
|
|
}
|
2022-02-03 17:51:44 +02:00
|
|
|
|
|
|
|
@h Forward references.
|
|
|
|
|
|
|
|
=
|
2022-02-10 01:48:51 +02:00
|
|
|
void TextualInter::resolve_forward_references(inter_tree *I) {
|
|
|
|
inter_error_location eloc = Inter::Errors::file_location(NULL, NULL);
|
|
|
|
InterTree::traverse(I, TextualInter::rfr_visitor, &eloc, NULL, PACKAGE_IST);
|
2022-02-03 17:51:44 +02:00
|
|
|
}
|
|
|
|
|
2022-02-10 01:48:51 +02:00
|
|
|
void TextualInter::rfr_visitor(inter_tree *I, inter_tree_node *P, void *state) {
|
2022-02-03 17:51:44 +02:00
|
|
|
inter_error_location *eloc = (inter_error_location *) state;
|
|
|
|
inter_package *pack = InterPackage::at_this_head(P);
|
|
|
|
if (pack == NULL) internal_error("no package defined here");
|
|
|
|
inter_symbols_table *T = InterPackage::scope(pack);
|
|
|
|
if (T == NULL) internal_error("package with no symbols");
|
|
|
|
for (int i=0; i<T->symbol_array_size; i++) {
|
|
|
|
inter_symbol *symb = T->symbol_array[i];
|
|
|
|
if (Wiring::is_wired_to_name(symb)) {
|
|
|
|
text_stream *N = Wiring::wired_to_name(symb);
|
2022-02-04 12:04:41 +02:00
|
|
|
if (InterSymbol::is_plug(symb)) continue;
|
2022-02-03 17:51:44 +02:00
|
|
|
inter_symbol *S_to = InterSymbolsTable::URL_to_symbol(InterPackage::tree(pack), N);
|
|
|
|
if (S_to == NULL) S_to = InterSymbolsTable::symbol_from_name(T, N);
|
|
|
|
if (S_to == NULL) Inter::Errors::issue(Inter::Errors::quoted(I"unable to locate symbol", N, eloc));
|
2022-02-04 12:04:41 +02:00
|
|
|
else if (InterSymbol::is_socket(symb))
|
|
|
|
Wiring::make_socket_to(symb, S_to);
|
2022-02-03 17:51:44 +02:00
|
|
|
else Wiring::wire_to(symb, S_to);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-09 12:33:49 +02:00
|
|
|
inter_package *latest_block_package = NULL;
|
|
|
|
|
2022-02-10 01:48:51 +02:00
|
|
|
void TextualInter::set_latest_block_package(inter_package *F) {
|
2022-02-09 12:33:49 +02:00
|
|
|
latest_block_package = F;
|
|
|
|
}
|
|
|
|
|
2022-02-10 01:48:51 +02:00
|
|
|
inter_package *TextualInter::get_latest_block_package(void) {
|
2022-02-09 12:33:49 +02:00
|
|
|
return latest_block_package;
|
|
|
|
}
|