1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-17 14:34:25 +03:00
inform7/inter/bytecode-module/Chapter 4/The Primitive Construct.w

136 lines
4.8 KiB
OpenEdge ABL
Raw Normal View History

2019-02-05 02:44:07 +02:00
[Inter::Primitive::] The Primitive Construct.
Defining the primitive construct.
@
@e PRIMITIVE_IST
=
void Inter::Primitive::define(void) {
inter_construct *IC = InterConstruct::create_construct(PRIMITIVE_IST, I"primitive");
InterConstruct::defines_symbol_in_fields(IC, DEFN_PRIM_IFLD, -1);
InterConstruct::specify_syntax(IC, I"primitive !IDENTIFIER TOKENS -> TOKEN");
InterConstruct::permit(IC, OUTSIDE_OF_PACKAGES_ICUP);
2019-07-09 08:45:46 +03:00
METHOD_ADD(IC, CONSTRUCT_READ_MTID, Inter::Primitive::read);
METHOD_ADD(IC, CONSTRUCT_VERIFY_MTID, Inter::Primitive::verify);
METHOD_ADD(IC, CONSTRUCT_WRITE_MTID, Inter::Primitive::write);
2019-02-05 02:44:07 +02:00
}
@
@d DEFN_PRIM_IFLD 2
@d CAT_PRIM_IFLD 3
@d MIN_EXTENT_PRIM_IFR 4
@d VAL_PRIM_CAT 1
@d REF_PRIM_CAT 2
@d LAB_PRIM_CAT 3
@d CODE_PRIM_CAT 4
=
2019-07-14 12:44:07 +03:00
void Inter::Primitive::read(inter_construct *IC, inter_bookmark *IBM, inter_line_parse *ilp, inter_error_location *eloc, inter_error_message **E) {
2022-02-09 12:33:49 +02:00
*E = InterConstruct::check_level_in_package(IBM, PRIMITIVE_IST, ilp->indent_level, eloc);
2019-07-09 08:45:46 +03:00
if (*E) return;
2019-02-05 02:44:07 +02:00
if (SymbolAnnotation::nonempty(&(ilp->set))) { *E = Inter::Errors::plain(I"__annotations are not allowed", eloc); return; }
2019-02-05 02:44:07 +02:00
inter_symbol *prim_name = TextualInter::new_symbol(eloc, InterBookmark::scope(IBM), ilp->mr.exp[0], E);
2019-07-09 08:45:46 +03:00
if (*E) return;
2019-02-05 02:44:07 +02:00
2022-02-03 17:51:44 +02:00
inter_tree_node *F = Inode::new_with_1_data_field(IBM, PRIMITIVE_IST, InterSymbolsTable::id_from_symbol_at_bookmark(IBM, prim_name), eloc, (inter_ti) ilp->indent_level);
2019-02-05 02:44:07 +02:00
text_stream *in = ilp->mr.exp[1];
match_results mr2 = Regexp::create_mr();
while (Regexp::match(&mr2, in, L" *(%i+) *(%c*)")) {
2020-07-01 02:58:55 +03:00
inter_ti lcat = Inter::Primitive::category(eloc, mr2.exp[0], E);
2019-07-09 08:45:46 +03:00
if (*E) return;
2019-02-05 02:44:07 +02:00
if (lcat == 0) break;
2022-01-30 15:32:38 +02:00
Inode::extend_instruction_by(F, 1);
F->W.instruction[F->W.extent - 1] = lcat;
2019-02-05 02:44:07 +02:00
Str::copy(in, mr2.exp[1]);
}
2020-07-01 02:58:55 +03:00
inter_ti rcat = Inter::Primitive::category(eloc, ilp->mr.exp[2], E);
2019-07-09 08:45:46 +03:00
if (*E) return;
2022-01-30 15:32:38 +02:00
Inode::extend_instruction_by(F, 1);
F->W.instruction[F->W.extent - 1] = rcat;
2019-02-05 02:44:07 +02:00
2022-02-07 00:33:07 +02:00
*E = InterConstruct::verify_construct(InterBookmark::package(IBM), F); if (*E) return;
2022-01-27 01:59:02 +02:00
NodePlacement::move_to_moving_bookmark(F, IBM);
2019-02-05 02:44:07 +02:00
}
2020-07-01 02:58:55 +03:00
inter_ti Inter::Primitive::category(inter_error_location *eloc, text_stream *T, inter_error_message **E) {
2019-02-05 02:44:07 +02:00
*E = NULL;
if (Str::eq(T, I"void")) return 0;
if (Str::eq(T, I"val")) return VAL_PRIM_CAT;
if (Str::eq(T, I"ref")) return REF_PRIM_CAT;
if (Str::eq(T, I"lab")) return LAB_PRIM_CAT;
if (Str::eq(T, I"code")) return CODE_PRIM_CAT;
*E = Inter::Errors::quoted(I"no such category", T, eloc);
return VAL_PRIM_CAT;
}
2020-07-01 02:58:55 +03:00
void Inter::Primitive::write_category(OUTPUT_STREAM, inter_ti cat) {
2019-02-05 02:44:07 +02:00
switch (cat) {
case VAL_PRIM_CAT: WRITE("val"); break;
case REF_PRIM_CAT: WRITE("ref"); break;
case LAB_PRIM_CAT: WRITE("lab"); break;
case CODE_PRIM_CAT: WRITE("code"); break;
case 0: WRITE("void"); break;
default: internal_error("bad category");
}
}
2019-07-24 20:15:07 +03:00
void Inter::Primitive::verify(inter_construct *IC, inter_tree_node *P, inter_package *owner, inter_error_message **E) {
2020-05-11 17:21:29 +03:00
if (P->W.extent < MIN_EXTENT_PRIM_IFR) { *E = Inode::error(P, I"primitive extent wrong", NULL); return; }
2022-02-03 17:51:44 +02:00
inter_symbol *prim_name = InterSymbolsTable::symbol_from_ID(Inode::globals(P), P->W.instruction[DEFN_PRIM_IFLD]);
if ((prim_name == NULL) || (Str::get_first_char(InterSymbol::identifier(prim_name)) != '!'))
2020-05-11 17:21:29 +03:00
{ *E = Inode::error(P, I"primitive not beginning with '!'", NULL); return; }
2019-02-05 02:44:07 +02:00
int voids = 0, args = 0;
2019-07-24 20:15:07 +03:00
for (int i=CAT_PRIM_IFLD; i<P->W.extent-1; i++) {
2022-01-30 15:32:38 +02:00
if (P->W.instruction[i] == 0) voids++;
2019-02-05 02:44:07 +02:00
args++;
}
if ((voids > 1) || ((voids == 1) && (args > 1)))
2020-05-11 17:21:29 +03:00
{ *E = Inode::error(P, I"if used on the left, 'void' must be the only argument", NULL); return; }
2019-02-05 02:44:07 +02:00
}
2019-07-24 20:15:07 +03:00
void Inter::Primitive::write(inter_construct *IC, OUTPUT_STREAM, inter_tree_node *P, inter_error_message **E) {
2022-02-03 17:51:44 +02:00
inter_symbol *prim_name = InterSymbolsTable::symbol_from_ID_at_node(P, DEFN_PRIM_IFLD);
2019-02-05 02:44:07 +02:00
if (prim_name) {
WRITE("primitive %S", InterSymbol::identifier(prim_name));
2019-02-05 02:44:07 +02:00
int cats = 0;
2019-07-24 20:15:07 +03:00
for (int i=CAT_PRIM_IFLD; i<P->W.extent-1; i++) {
2019-02-05 02:44:07 +02:00
WRITE(" ");
2022-01-30 15:32:38 +02:00
Inter::Primitive::write_category(OUT, P->W.instruction[i]);
2019-02-05 02:44:07 +02:00
cats++;
}
if (cats == 0) WRITE(" void");
WRITE(" -> ");
2022-01-30 15:32:38 +02:00
Inter::Primitive::write_category(OUT, P->W.instruction[P->W.extent-1]);
2020-05-11 17:21:29 +03:00
} else { *E = Inode::error(P, I"cannot write primitive", NULL); return; }
2019-02-05 02:44:07 +02:00
}
int Inter::Primitive::arity(inter_symbol *prim) {
if (prim == NULL) return 0;
inter_tree_node *D = InterSymbol::definition(prim);
if (D == NULL) return 0;
2019-07-24 20:15:07 +03:00
return D->W.extent - CAT_PRIM_IFLD - 1;
2019-02-05 02:44:07 +02:00
}
2020-07-01 02:58:55 +03:00
inter_ti Inter::Primitive::operand_category(inter_symbol *prim, int i) {
2019-02-05 02:44:07 +02:00
if (prim == NULL) return 0;
inter_tree_node *D = InterSymbol::definition(prim);
if (D == NULL) return 0;
2022-01-30 15:32:38 +02:00
return D->W.instruction[CAT_PRIM_IFLD + i];
2019-02-05 02:44:07 +02:00
}
2020-07-01 02:58:55 +03:00
inter_ti Inter::Primitive::result_category(inter_symbol *prim) {
2019-02-05 02:44:07 +02:00
if (prim == NULL) return 0;
inter_tree_node *D = InterSymbol::definition(prim);
if (D == NULL) return 0;
2022-01-30 15:32:38 +02:00
return D->W.instruction[D->W.extent - 1];
2019-02-05 02:44:07 +02:00
}