1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-03 07:24:58 +03:00
inform7/inter/bytecode-module/Chapter 3/Definition.w

301 lines
10 KiB
OpenEdge ABL
Raw Normal View History

2019-02-05 02:44:07 +02:00
[Inter::Defn::] Definition.
Defining the Inter format.
@
@d MAX_INTER_CONSTRUCTS 100
=
typedef struct inter_line_parse {
struct text_stream *line;
struct match_results mr;
2019-07-26 10:59:23 +03:00
struct inter_annotation_set set;
2020-07-01 02:58:55 +03:00
inter_ti terminal_comment;
2019-02-05 02:44:07 +02:00
int indent_level;
} inter_line_parse;
typedef struct inter_construct {
2020-07-01 02:58:55 +03:00
inter_ti construct_ID;
2019-02-05 02:44:07 +02:00
wchar_t *construct_syntax;
int min_level;
int max_level;
int usage_permissions;
struct text_stream *singular_name;
struct text_stream *plural_name;
2020-05-09 15:07:39 +03:00
struct method_set *methods;
CLASS_DEFINITION
2019-02-05 02:44:07 +02:00
} inter_construct;
inter_construct *IC_lookup[MAX_INTER_CONSTRUCTS];
2020-07-01 02:58:55 +03:00
inter_construct *Inter::Defn::create_construct(inter_ti ID, wchar_t *syntax,
text_stream *sing,
text_stream *plur) {
2019-02-05 02:44:07 +02:00
inter_construct *IC = CREATE(inter_construct);
2020-05-09 15:07:39 +03:00
IC->methods = Methods::new_set();
2019-02-05 02:44:07 +02:00
IC->construct_ID = ID;
IC->construct_syntax = syntax;
if (ID >= MAX_INTER_CONSTRUCTS) internal_error("too many constructs");
IC->min_level = 0;
IC->max_level = 0;
IC_lookup[ID] = IC;
IC->usage_permissions = INSIDE_PLAIN_PACKAGE;
IC->singular_name = Str::duplicate(sing);
IC->plural_name = Str::duplicate(plur);
return IC;
}
@
2019-07-09 08:45:46 +03:00
@e CONSTRUCT_READ_MTID
@e CONSTRUCT_TRANSPOSE_MTID
2019-07-09 08:45:46 +03:00
@e CONSTRUCT_VERIFY_MTID
@e CONSTRUCT_WRITE_MTID
@e VERIFY_INTER_CHILDREN_MTID
2019-07-09 08:45:46 +03:00
=
2020-05-09 15:07:39 +03:00
VOID_METHOD_TYPE(CONSTRUCT_READ_MTID, inter_construct *IC, inter_bookmark *, inter_line_parse *, inter_error_location *, inter_error_message **E)
2020-07-01 02:58:55 +03:00
VOID_METHOD_TYPE(CONSTRUCT_TRANSPOSE_MTID, inter_construct *IC, inter_tree_node *P, inter_ti *grid, inter_ti max, inter_error_message **E)
2020-05-09 15:07:39 +03:00
VOID_METHOD_TYPE(CONSTRUCT_VERIFY_MTID, inter_construct *IC, inter_tree_node *P, inter_package *owner, inter_error_message **E)
VOID_METHOD_TYPE(CONSTRUCT_WRITE_MTID, inter_construct *IC, text_stream *OUT, inter_tree_node *P, inter_error_message **E)
VOID_METHOD_TYPE(VERIFY_INTER_CHILDREN_MTID, inter_construct *IC, inter_tree_node *P, inter_error_message **E)
2019-07-09 08:45:46 +03:00
@
2019-02-05 02:44:07 +02:00
@e INVALID_IST from 0
=
void Inter::Defn::create_language(void) {
for (int i=0; i<MAX_INTER_CONSTRUCTS; i++) IC_lookup[i] = NULL;
2019-07-09 08:45:46 +03:00
Inter::Defn::create_construct(INVALID_IST, NULL, I"nothing", I"nothings");
SymbolAnnotation::declare_canonical_annotations();
2019-02-05 02:44:07 +02:00
Inter::Nop::define();
Inter::Comment::define();
Inter::Symbol::define();
Inter::Version::define();
Inter::Pragma::define();
Inter::Link::define();
Inter::Append::define();
Inter::Kind::define();
Inter::DefaultValue::define();
Inter::Constant::define();
Inter::Instance::define();
Inter::Variable::define();
Inter::Property::define();
Inter::Permission::define();
Inter::PropertyValue::define();
Inter::Primitive::define();
2022-01-31 01:49:12 +02:00
InterPackage::define();
2019-02-05 02:44:07 +02:00
Inter::PackageType::define();
Inter::Label::define();
Inter::Local::define();
Inter::Inv::define();
Inter::Ref::define();
Inter::Val::define();
Inter::Lab::define();
2022-01-11 01:51:42 +02:00
Inter::Assembly::define();
2019-02-05 02:44:07 +02:00
Inter::Code::define();
Inter::Evaluation::define();
Inter::Reference::define();
2019-02-05 02:44:07 +02:00
Inter::Cast::define();
Inter::Splat::define();
}
2019-02-05 02:44:07 +02:00
@
@d OUTSIDE_OF_PACKAGES 1
@d INSIDE_PLAIN_PACKAGE 2
@d INSIDE_CODE_PACKAGE 4
@d CAN_HAVE_CHILDREN 8
2019-02-05 02:44:07 +02:00
=
2019-07-24 20:15:07 +03:00
inter_error_message *Inter::Defn::verify_construct(inter_package *owner, inter_tree_node *P) {
2019-02-05 02:44:07 +02:00
inter_construct *IC = NULL;
inter_error_message *E = Inter::Defn::get_construct(P, &IC);
if (E) return E;
2020-05-09 15:07:39 +03:00
VOID_METHOD_CALL(IC, CONSTRUCT_VERIFY_MTID, P, owner, &E);
2019-07-09 08:45:46 +03:00
return E;
2019-02-05 02:44:07 +02:00
}
2020-07-01 02:58:55 +03:00
inter_error_message *Inter::Defn::transpose_construct(inter_package *owner, inter_tree_node *P, inter_ti *grid, inter_ti max) {
inter_construct *IC = NULL;
inter_error_message *E = Inter::Defn::get_construct(P, &IC);
if (E) return E;
2020-05-09 15:07:39 +03:00
VOID_METHOD_CALL(IC, CONSTRUCT_TRANSPOSE_MTID, P, grid, max, &E);
return E;
}
2019-07-24 20:15:07 +03:00
inter_error_message *Inter::Defn::get_construct(inter_tree_node *P, inter_construct **to) {
2020-05-11 17:21:29 +03:00
if (P == NULL) return Inode::error(P, I"invalid frame", NULL);
2022-01-30 15:32:38 +02:00
if ((P->W.instruction[ID_IFLD] == INVALID_IST) || (P->W.instruction[ID_IFLD] >= MAX_INTER_CONSTRUCTS))
2020-05-11 17:21:29 +03:00
return Inode::error(P, I"no such construct", NULL);
2022-01-30 15:32:38 +02:00
inter_construct *IC = IC_lookup[P->W.instruction[ID_IFLD]];
2020-05-11 17:21:29 +03:00
if (IC == NULL) return Inode::error(P, I"bad construct", NULL);
2019-02-05 02:44:07 +02:00
if (to) *to = IC;
return NULL;
}
2019-07-24 20:15:07 +03:00
inter_error_message *Inter::Defn::write_construct_text(OUTPUT_STREAM, inter_tree_node *P) {
2022-01-30 15:32:38 +02:00
if (P->W.instruction[ID_IFLD] == NOP_IST) return NULL;
2019-07-13 13:03:54 +03:00
return Inter::Defn::write_construct_text_allowing_nop(OUT, P);
}
2019-07-24 20:15:07 +03:00
inter_error_message *Inter::Defn::write_construct_text_allowing_nop(OUTPUT_STREAM, inter_tree_node *P) {
2019-02-05 02:44:07 +02:00
inter_construct *IC = NULL;
inter_error_message *E = Inter::Defn::get_construct(P, &IC);
if (E) return E;
2022-01-30 15:32:38 +02:00
for (inter_ti L=0; L<P->W.instruction[LEVEL_IFLD]; L++) WRITE("\t");
2020-05-09 15:07:39 +03:00
VOID_METHOD_CALL(IC, CONSTRUCT_WRITE_MTID, OUT, P, &E);
2020-07-01 02:58:55 +03:00
inter_ti ID = Inode::get_comment(P);
2019-02-05 02:44:07 +02:00
if (ID != 0) {
2022-01-30 15:32:38 +02:00
if (P->W.instruction[ID_IFLD] != COMMENT_IST) WRITE(" ");
2020-05-11 17:21:29 +03:00
WRITE("# %S", Inode::ID_to_text(P, ID));
2019-02-05 02:44:07 +02:00
}
WRITE("\n");
2022-01-31 01:49:12 +02:00
if (P->W.instruction[ID_IFLD] == PACKAGE_IST) InterPackage::write_symbols(OUT, P);
2019-02-05 02:44:07 +02:00
return E;
}
inter_package *latest_block_package = NULL;
2019-02-05 02:44:07 +02:00
2019-07-14 12:44:07 +03:00
inter_error_message *Inter::Defn::read_construct_text(text_stream *line, inter_error_location *eloc, inter_bookmark *IBM) {
2019-02-05 02:44:07 +02:00
inter_line_parse ilp;
ilp.line = line;
ilp.mr = Regexp::create_mr();
ilp.terminal_comment = 0;
ilp.set = SymbolAnnotation::new_annotation_set();
2019-02-05 02:44:07 +02:00
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)) {
2022-01-30 15:32:38 +02:00
ilp.terminal_comment = InterWarehouse::create_text(InterBookmark::warehouse(IBM), InterBookmark::package(IBM));
2019-02-05 02:44:07 +02:00
int at = Str::index(P);
P = Str::forward(P);
while (Str::get(P) == ' ') P = Str::forward(P);
2022-01-30 15:32:38 +02:00
Str::substr(InterWarehouse::get_text(InterBookmark::warehouse(IBM), ilp.terminal_comment), P, Str::end(ilp.line));
2019-02-05 02:44:07 +02:00
Str::truncate(ilp.line, at);
break;
}
}
Str::trim_white_space(ilp.line);
if (ilp.indent_level == 0) latest_block_package = NULL;
2019-02-05 02:44:07 +02:00
2022-01-31 01:49:12 +02:00
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)));
2019-02-05 02:44:07 +02:00
}
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);
2019-02-05 02:44:07 +02:00
if (E) return E;
SymbolAnnotation::write_to_set(IA.annot->iatype, &(ilp.set), IA);
2019-02-05 02:44:07 +02:00
}
inter_construct *IC;
LOOP_OVER(IC, inter_construct)
2019-07-09 08:45:46 +03:00
if (IC->construct_syntax)
2019-02-05 02:44:07 +02:00
if (Regexp::match(&ilp.mr, ilp.line, IC->construct_syntax)) {
2019-07-09 08:45:46 +03:00
inter_error_message *E = NULL;
2020-05-09 15:07:39 +03:00
VOID_METHOD_CALL(IC, CONSTRUCT_READ_MTID, IBM, &ilp, eloc, &E);
2019-07-09 08:45:46 +03:00
return E;
2019-02-05 02:44:07 +02:00
}
return Inter::Errors::plain(I"bad inter line", eloc);
}
void Inter::Defn::set_latest_block_package(inter_package *F) {
latest_block_package = F;
2019-02-05 02:44:07 +02:00
}
inter_package *Inter::Defn::get_latest_block_package(void) {
return latest_block_package;
2019-02-05 02:44:07 +02:00
}
2020-07-01 02:58:55 +03:00
inter_error_message *Inter::Defn::vet_level(inter_bookmark *IBM, inter_ti cons, int level, inter_error_location *eloc) {
2019-07-14 02:33:50 +03:00
int actual = level;
2022-01-27 01:59:02 +02:00
if ((InterBookmark::package(IBM)) &&
2022-01-31 01:49:12 +02:00
(InterPackage::is_a_root_package(InterBookmark::package(IBM)) == FALSE))
2022-01-27 01:59:02 +02:00
actual = level - InterBookmark::baseline(IBM) - 1;
2019-02-05 02:44:07 +02:00
inter_construct *proposed = NULL;
LOOP_OVER(proposed, inter_construct)
if (proposed->construct_ID == cons) {
if (actual < 0) return Inter::Errors::plain(I"impossible level", eloc);
2019-07-14 10:36:06 +03:00
if ((actual < proposed->min_level) || (actual > proposed->max_level))
2019-02-05 02:44:07 +02:00
return Inter::Errors::plain(I"indentation error", eloc);
return NULL;
}
return Inter::Errors::plain(I"no such construct", eloc);
}
2019-07-24 20:15:07 +03:00
int Inter::Defn::get_level(inter_tree_node *P) {
2019-02-05 02:44:07 +02:00
inter_construct *IC = NULL;
inter_error_message *E = Inter::Defn::get_construct(P, &IC);
if (E) return 0;
2022-01-30 15:32:38 +02:00
return (int) P->W.instruction[LEVEL_IFLD];
2019-02-05 02:44:07 +02:00
}
2019-07-24 20:15:07 +03:00
inter_error_message *Inter::Defn::verify_children_inner(inter_tree_node *P) {
2019-02-05 02:44:07 +02:00
inter_construct *IC = NULL;
inter_error_message *E = Inter::Defn::get_construct(P, &IC);
if (E) return E;
2022-01-31 01:49:12 +02:00
inter_package *pack = InterPackage::container(P);
2019-07-11 22:38:01 +03:00
int need = INSIDE_PLAIN_PACKAGE;
if (pack == NULL) need = OUTSIDE_OF_PACKAGES;
2022-01-31 01:49:12 +02:00
else if (InterPackage::is_a_function_body(pack)) need = INSIDE_CODE_PACKAGE;
2019-07-11 22:38:01 +03:00
if ((IC->usage_permissions & need) != need) {
text_stream *M = Str::new();
2022-01-30 15:32:38 +02:00
WRITE_TO(M, "construct (%d) '", P->W.instruction[LEVEL_IFLD]);
2019-07-11 22:38:01 +03:00
Inter::Defn::write_construct_text(M, P);
WRITE_TO(M, "' (%d) cannot be used ", IC->construct_ID);
switch (need) {
case OUTSIDE_OF_PACKAGES: WRITE_TO(M, "outside packages"); break;
2022-01-31 01:49:12 +02:00
case INSIDE_PLAIN_PACKAGE: WRITE_TO(M, "inside non-code packages such as %S", InterPackage::name(pack)); break;
case INSIDE_CODE_PACKAGE: WRITE_TO(M, "inside code packages such as %S", InterPackage::name(pack)); break;
2019-07-11 22:38:01 +03:00
}
2020-05-11 17:21:29 +03:00
return Inode::error(P, M, NULL);
2019-07-11 22:38:01 +03:00
}
E = NULL;
2020-05-09 15:07:39 +03:00
VOID_METHOD_CALL(IC, VERIFY_INTER_CHILDREN_MTID, P, &E);
2019-07-24 22:29:29 +03:00
if (E) Inter::Errors::backtrace(STDERR, P);
return E;
2019-02-05 02:44:07 +02:00
}
2021-11-15 01:40:33 +02:00
void Inter::Defn::lint(inter_tree *I) {
InterTree::traverse(I, Inter::Defn::lint_visitor, NULL, NULL, -PACKAGE_IST);
}
void Inter::Defn::lint_visitor(inter_tree *I, inter_tree_node *P, void *state) {
2022-01-31 01:49:12 +02:00
inter_ti c = Inode::get_package(P)->resource_ID;
2022-01-29 02:21:23 +02:00
inter_ti a = Inode::get_package_slowly_getting_same_answer(P);
2021-11-15 01:40:33 +02:00
if (c != a) {
LOG("Frame gives package as $6, but its location is in package $6\n",
Inode::ID_to_package(P, c),
Inode::ID_to_package(P, a));
WRITE_TO(STDERR, "Frame gives package as %d, but its location is in package %d\n",
2022-01-31 01:49:12 +02:00
Inode::ID_to_package(P, c)->resource_ID,
Inode::ID_to_package(P, a)->resource_ID);
2021-11-15 01:40:33 +02:00
internal_error("misplaced package");
}
Produce::guard(Inter::Defn::verify_children_inner(P));
}