diff --git a/docs/bytecode-module/1-bm.html b/docs/bytecode-module/1-bm.html index a5b6f77ea..e791e9606 100644 --- a/docs/bytecode-module/1-bm.html +++ b/docs/bytecode-module/1-bm.html @@ -118,7 +118,7 @@ which use this module: Register this module's debugging log aspects3.5; Register this module's debugging log writers3.6; - InterConstruct::create_language(); + InterConstruct::create_language(); InterTypes::initialise_constructors(); } void BytecodeModule::end(void) { @@ -146,7 +146,7 @@ which use this module:
     Writers::register_writer('t', &TextualInter::writer);
-    Writers::register_writer('F', &Inter::Verify::writer);
+    Writers::register_writer('F', &InterConstruct::instruction_writer);
 

§3.4.

diff --git a/docs/bytecode-module/2-ann.html b/docs/bytecode-module/2-ann.html index c03ea6ba8..86f90bc45 100644 --- a/docs/bytecode-module/2-ann.html +++ b/docs/bytecode-module/2-ann.html @@ -175,7 +175,7 @@ any symbol: it's used to mean "do not make an annotation".

-void SymbolAnnotation::declare_canonical_annotations(void) {
+void SymbolAnnotation::declare_canonical_annotations(void) {
     SymbolAnnotation::declare(INVALID_IANN,  I"__invalid", INTEGER_IATYPE);
 
     SymbolAnnotation::declare(ACTION_IANN,              I"__action",              BOOLEAN_IATYPE);
diff --git a/docs/bytecode-module/2-bkm.html b/docs/bytecode-module/2-bkm.html
index 5fc310917..b62165996 100644
--- a/docs/bytecode-module/2-bkm.html
+++ b/docs/bytecode-module/2-bkm.html
@@ -200,7 +200,7 @@ equal to P.
 

-inter_package *InterBookmark::package(inter_bookmark *IBM) {
+inter_package *InterBookmark::package(inter_bookmark *IBM) {
     if (IBM == NULL) return NULL;
     inter_package *pack = IBM->R->package;
     if ((IBM->placement_wrt_R == AS_FIRST_CHILD_OF_NODEPLACEMENT) ||
@@ -224,7 +224,7 @@ equal to P.
     return InterTree::warehouse(InterBookmark::tree(IBM));
 }
 
-int InterBookmark::baseline(inter_bookmark *IBM) {
+int InterBookmark::baseline(inter_bookmark *IBM) {
     inter_package *pack = InterBookmark::package(IBM);
     if (pack) return InterPackage::baseline(pack);
     return 0;
diff --git a/docs/bytecode-module/2-in.html b/docs/bytecode-module/2-in.html
index d9670b869..8baa3eb9a 100644
--- a/docs/bytecode-module/2-in.html
+++ b/docs/bytecode-module/2-in.html
@@ -119,7 +119,7 @@ of access matters more.
     struct warehouse_floor_space W;
 } inter_tree_node;
 
- +

§2. Do not call this directly in order to create a node.

@@ -138,7 +138,7 @@ of access matters more. itn->previous_itn = NULL; itn->next_itn = NULL; itn->W = W; - if (eloc) Inode::attach_error_location(itn, eloc); + if (eloc) Inode::attach_error_location(itn, eloc); return itn; }
@@ -183,7 +183,7 @@ call those creator functions, not these.

-inter_tree_node *Inode::new_with_0_data_fields(inter_bookmark *IBM, int S,
+inter_tree_node *Inode::new_with_0_data_fields(inter_bookmark *IBM, int S,
     inter_error_location *eloc, inter_ti level) {
     inter_tree *I = InterBookmark::tree(IBM);
     inter_tree_node *P = Inode::new_node(InterTree::warehouse(I), I, 2,
@@ -193,7 +193,7 @@ call those creator functions, not these.
     return P;
 }
 
-inter_tree_node *Inode::new_with_1_data_field(inter_bookmark *IBM, int S,
+inter_tree_node *Inode::new_with_1_data_field(inter_bookmark *IBM, int S,
     inter_ti V, inter_error_location *eloc, inter_ti level) {
     inter_tree *I = InterBookmark::tree(IBM);
     inter_tree_node *P = Inode::new_node(InterTree::warehouse(I), I, 3,
@@ -317,17 +317,17 @@ call those creator functions, not these.
 

§6. The package and tree of a node.

-inter_package *Inode::get_package(inter_tree_node *F) {
+inter_package *Inode::get_package(inter_tree_node *F) {
     if (F) return F->package;
     return NULL;
 }
 
-inter_tree *Inode::tree(inter_tree_node *F) {
+inter_tree *Inode::tree(inter_tree_node *F) {
     if (F) return F->tree;
     return NULL;
 }
 
-inter_symbols_table *Inode::globals(inter_tree_node *F) {
+inter_symbols_table *Inode::globals(inter_tree_node *F) {
     if (F) return InterTree::global_scope(Inode::tree(F));
     return NULL;
 }
@@ -343,45 +343,38 @@ structure, but in warehouse memory.
 

-......+------+----------+--------+----+-------+-------------+........
-      | Skip | Verified | Origin | ID | Level | Data        |
-......+------+----------+--------+----+-------+-------------+........
-       <------------------------> <------------------------>
+......+------+-----------------+----+-------+-------------+........
+      | Skip | Origin/Verified | ID | Level | Data        |
+......+------+-----------------+----+-------+-------------+........
+       <----------------------> <------------------------>
         Preframe                             Frame
 

This stretch of memory is divided into a "preframe" and a "frame": the frame holds the words of data described above, with position 0 being the ID, and -so on. The frame is of variable size, depending on the instruction (and in +so on. Unlike the frame, the preframe data is not part of the instruction, and +is not saved out when Inter is stored in a binary file. +

+ +

The frame is of variable size, depending on the instruction (and in some cases its particular content: a constant definition for a list can be almost any length). But the preframe is of fixed size:

-
define PREFRAME_SIZE 3
+
define PREFRAME_SIZE 2
 define PREFRAME_SKIP_AMOUNT 0
-define PREFRAME_VERIFICATION_COUNT 1
-define PREFRAME_ORIGIN 2
+define PREFRAME_ORIGIN_AND_VFLAG 1
 

§8. PREFRAME_SKIP_AMOUNT is the offset (in words) to the next instruction. Since the preframe has fixed length, this is both the offset from one preframe to the next and also from one frame to the next.

-

§9. PREFRAME_VERIFICATION_COUNT is the number of times the instruction has -been "verified". This is not always a passive process of checking, which is why -we need to track whether it has happened. See Inter Constructs. +

§9. PREFRAME_ORIGIN_AND_VFLAG contains two unrelated pieces of data. One is bit 31, +which is set if the instruction in the frame has been verified, and is otherwise +clear.

-

This function effectively performs v++, where v is the count. -

- -
-inter_ti Inode::bump_verification_count(inter_tree_node *F) {
-    inter_ti v = Inode::get_preframe(F, PREFRAME_VERIFICATION_COUNT);
-    Inode::set_preframe(F, PREFRAME_VERIFICATION_COUNT, v + 1);
-    return v;
-}
-
-

§10. PREFRAME_ORIGIN allows the origin of the instruction, in source code, +

The other, in bits 0-30, allows the origin of the instruction, in source code, to be preserved: for example, to show that this came from line 14 of a file called whatever.intert. It is 0 if no origin is recorded; it is used only for better reporting of any errors which arise. For how the location is @@ -389,27 +382,42 @@ actually encoded in the word, see The Wareh

-inter_error_location *Inode::get_error_location(inter_tree_node *F) {
+inter_error_location *Inode::get_error_location(inter_tree_node *F) {
     if (F == NULL) return NULL;
-    inter_ti L = Inode::get_preframe(F, PREFRAME_ORIGIN);
+    inter_ti L = (Inode::get_preframe(F, PREFRAME_ORIGIN_AND_VFLAG)) & 0x7fffffff;
     return InterTree::origin_word_to_eloc(Inode::tree(F), L);
 }
 
-void Inode::attach_error_location(inter_tree_node *F, inter_error_location *eloc) {
-    Inode::set_preframe(F, PREFRAME_ORIGIN,
-        InterTree::eloc_to_origin_word(Inode::tree(F), eloc));
+void Inode::attach_error_location(inter_tree_node *F, inter_error_location *eloc) {
+    inter_ti val = InterTree::eloc_to_origin_word(Inode::tree(F), eloc);
+    if ((Inode::get_preframe(F, PREFRAME_ORIGIN_AND_VFLAG)) & 0x80000000)
+        val |= 0x80000000;
+    Inode::set_preframe(F, PREFRAME_ORIGIN_AND_VFLAG, val);
+}
+
+

§10. Note that the vflag can never be cleared, once set. +

+ +
+int Inode::get_vflag(inter_tree_node *F) {
+    return ((Inode::get_preframe(F, PREFRAME_ORIGIN_AND_VFLAG)) & 0x80000000)?TRUE:FALSE;
+}
+
+void Inode::set_vflag(inter_tree_node *F) {
+    Inode::set_preframe(F, PREFRAME_ORIGIN_AND_VFLAG,
+        (Inode::get_preframe(F, PREFRAME_ORIGIN_AND_VFLAG)) | 0x80000000);
 }
 

§11. The following gets and sets from the preframe:

-inter_ti Inode::get_preframe(inter_tree_node *F, int at) {
+inter_ti Inode::get_preframe(inter_tree_node *F, int at) {
     if (F == NULL) return 0;
     return F->W.in_room->bytecode[F->W.index + at];
 }
 
-void Inode::set_preframe(inter_tree_node *F, int at, inter_ti V) {
+void Inode::set_preframe(inter_tree_node *F, int at, inter_ti V) {
     if (F) F->W.in_room->bytecode[F->W.index + at] = V;
 }
 
@@ -438,7 +446,7 @@ if the system is out of memory.

-void Inode::extend_instruction_by(inter_tree_node *F, inter_ti by) {
+void Inode::extend_instruction_by(inter_tree_node *F, inter_ti by) {
     if (by > 0) F->W = InterWarehouse::enlarge_floor_space(F->W, by);
 }
 
@@ -446,7 +454,7 @@ if the system is out of memory.

-int Inode::get_level(inter_tree_node *P) {
+int Inode::get_level(inter_tree_node *P) {
     if (P == NULL) return 0;
     return (int) P->W.instruction[LEVEL_IFLD];
 }
@@ -466,20 +474,20 @@ and sometimes also on the local symbols table (which depends on the package
 we are in, which in turn depends on the node).
 
 
-inter_symbols_table *Inode::ID_to_symbols_table(inter_tree_node *F, inter_ti ID) {
+inter_symbols_table *Inode::ID_to_symbols_table(inter_tree_node *F, inter_ti ID) {
     return InterWarehouse::get_symbols_table(Inode::warehouse(F), ID);
 }
 
-text_stream *Inode::ID_to_text(inter_tree_node *F, inter_ti ID) {
+text_stream *Inode::ID_to_text(inter_tree_node *F, inter_ti ID) {
     return InterWarehouse::get_text(Inode::warehouse(F), ID);
 }
 
-inter_package *Inode::ID_to_package(inter_tree_node *F, inter_ti ID) {
+inter_package *Inode::ID_to_package(inter_tree_node *F, inter_ti ID) {
     if (ID == 0) return NULL;
     return InterWarehouse::get_package(Inode::warehouse(F), ID);
 }
 
-inter_node_list *Inode::ID_to_frame_list(inter_tree_node *F, inter_ti N) {
+inter_node_list *Inode::ID_to_frame_list(inter_tree_node *F, inter_ti N) {
     return InterWarehouse::get_node_list(Inode::warehouse(F), N);
 }
 
@@ -488,9 +496,9 @@ to identify it as occurring at a particular node. We can get one thus:

-inter_error_message *Inode::error(inter_tree_node *F, text_stream *err, text_stream *quote) {
+inter_error_message *Inode::error(inter_tree_node *F, text_stream *err, text_stream *quote) {
     inter_error_message *iem = CREATE(inter_error_message);
-    inter_error_location *eloc = Inode::get_error_location(F);
+    inter_error_location *eloc = Inode::get_error_location(F);
     if (eloc)
         iem->error_at = *eloc;
     else
diff --git a/docs/bytecode-module/2-it.html b/docs/bytecode-module/2-it.html
index e0950fe6c..7daf23b12 100644
--- a/docs/bytecode-module/2-it.html
+++ b/docs/bytecode-module/2-it.html
@@ -385,17 +385,21 @@ in the preframe for an instruction (see Int
 
 

By convention, an origin value below INTER_ERROR_ORIGIN_OFFSET is a line number; an origin above that is a binary address within a file (plus -INTER_ERROR_ORIGIN_OFFSET). +INTER_ERROR_ORIGIN_OFFSET). We record such addresses only up to a file +position equivalent to about 179 megabytes; in practice the largest binary +inter files now in existence are about 8 megabytes, so this seems fine for now.

define INTER_ERROR_ORIGIN_OFFSET 0x10000000
 
-inter_ti InterTree::eloc_to_origin_word(inter_tree *tree, inter_error_location *eloc) {
+inter_ti InterTree::eloc_to_origin_word(inter_tree *tree, inter_error_location *eloc) {
     if (eloc) {
         if (eloc->error_interb) {
             tree->blame_errors_on_this_file = eloc->error_interb;
-            return (inter_ti) (INTER_ERROR_ORIGIN_OFFSET + eloc->error_offset);
+            inter_ti w = (inter_ti) (INTER_ERROR_ORIGIN_OFFSET + eloc->error_offset);
+            if (w & 0x80000000) w = 0;
+            return w;
         }
         if (eloc->error_tfp) {
             tree->blame_errors_on_this_file = eloc->error_tfp->text_file_filename;
@@ -421,7 +425,7 @@ data, not the position data itself. So:
 

§14.

-inter_error_location *InterTree::origin_word_to_eloc(inter_tree *tree, inter_ti C) {
+inter_error_location *InterTree::origin_word_to_eloc(inter_tree *tree, inter_ti C) {
     if ((tree) && (tree->blame_errors_on_this_file)) {
         inter_error_stash *stash = CREATE(inter_error_stash);
         stash->stashed_tfp = TextFiles::nowhere();
diff --git a/docs/bytecode-module/2-pck.html b/docs/bytecode-module/2-pck.html
index e4e4e2f28..03c79bf16 100644
--- a/docs/bytecode-module/2-pck.html
+++ b/docs/bytecode-module/2-pck.html
@@ -208,7 +208,7 @@ extracted from the bytecode of its 
-text_stream *InterPackage::name(inter_package *pack) {
+text_stream *InterPackage::name(inter_package *pack) {
     if (pack) {
         inter_symbol *S = InterPackage::name_symbol(pack);
         if (S) return InterSymbol::identifier(S);
@@ -230,7 +230,7 @@ extracted from the bytecode of its 
-inter_symbols_table *InterPackage::scope(inter_package *pack) {
+inter_symbols_table *InterPackage::scope(inter_package *pack) {
     if (pack == NULL) return NULL;
     return pack->package_scope;
 }
@@ -261,7 +261,7 @@ equal to the special root package.
 

-inter_package *InterPackage::container(inter_tree_node *P) {
+inter_package *InterPackage::container(inter_tree_node *P) {
     if (P == NULL) return NULL;
     inter_package *pack = Inode::get_package(P);
     if (InterPackage::is_a_root_package(pack)) return NULL;
@@ -322,7 +322,7 @@ will only ever be one of these in any given tree.
 

-int InterPackage::is_a_root_package(inter_package *pack) {
+int InterPackage::is_a_root_package(inter_package *pack) {
     if ((pack) && (pack->package_flags & ROOT_PACKAGE_FLAG)) return TRUE;
     return FALSE;
 }
@@ -338,7 +338,7 @@ loop bodies — are not subpackages of this: a code package has no subpackag
 

-int InterPackage::is_a_function_body(inter_package *pack) {
+int InterPackage::is_a_function_body(inter_package *pack) {
     if ((pack) && (pack->package_flags & FUNCTION_BODY_PACKAGE_FLAG)) return TRUE;
     return FALSE;
 }
@@ -380,7 +380,7 @@ to its URL, which is particularly handy for the debugging log:
 

-void InterPackage::write_URL(OUTPUT_STREAM, inter_package *P) {
+void InterPackage::write_URL(OUTPUT_STREAM, inter_package *P) {
     if (P == NULL) { WRITE("<none>"); return; }
     inter_package *chain[MAX_URL_SYMBOL_NAME_DEPTH];
     int chain_length = 0;
diff --git a/docs/bytecode-module/2-st.html b/docs/bytecode-module/2-st.html
index 46b346295..d9d593638 100644
--- a/docs/bytecode-module/2-st.html
+++ b/docs/bytecode-module/2-st.html
@@ -369,7 +369,7 @@ to access this: one following equations, the other not.
 

-inter_symbol *InterSymbolsTable::symbol_from_ID_not_following(inter_symbols_table *T,
+inter_symbol *InterSymbolsTable::symbol_from_ID_not_following(inter_symbols_table *T,
     inter_ti ID) {
     if (T == NULL) return NULL;
     int index = (int) ID - (int) SYMBOL_BASE_VAL;
@@ -378,7 +378,7 @@ to access this: one following equations, the other not.
     return T->symbol_array[index];
 }
 
-inter_symbol *InterSymbolsTable::symbol_from_ID(inter_symbols_table *T, inter_ti ID) {
+inter_symbol *InterSymbolsTable::symbol_from_ID(inter_symbols_table *T, inter_ti ID) {
     inter_symbol *S = InterSymbolsTable::symbol_from_ID_not_following(T, ID);
     return Wiring::cable_end(S);
 }
diff --git a/docs/bytecode-module/2-sym.html b/docs/bytecode-module/2-sym.html
index a78fa1fd9..5555d1a96 100644
--- a/docs/bytecode-module/2-sym.html
+++ b/docs/bytecode-module/2-sym.html
@@ -225,7 +225,7 @@ that for some transient flags:
 define SPECULATIVE_ISYMF        0x00000100
 
-int InterSymbol::get_flag(inter_symbol *S, int f) {
+int InterSymbol::get_flag(inter_symbol *S, int f) {
     if (S == NULL) internal_error("no symbol");
     return (S->symbol_status & f)?TRUE:FALSE;
 }
@@ -276,7 +276,7 @@ to be defined as constants, variables and the like.
     InterSymbol::set_type(S, MISC_ISYMT);
 }
 
-int InterSymbol::misc_but_undefined(inter_symbol *S) {
+int InterSymbol::misc_but_undefined(inter_symbol *S) {
     if ((S) &&
         (InterSymbol::get_type(S) == MISC_ISYMT) &&
         (InterSymbol::is_defined(S) == FALSE))
@@ -392,7 +392,7 @@ might be the node holding the instruction:
     constant magic_number K_int32 = 27
 
-void InterSymbol::define(inter_symbol *S, inter_tree_node *P) {
+void InterSymbol::define(inter_symbol *S, inter_tree_node *P) {
     if (S == NULL) internal_error("tried to define null symbol");
     S->definition = P;
 }
@@ -401,12 +401,12 @@ might be the node holding the instruction:
     if (S) InterSymbol::define(S, NULL);
 }
 
-inter_tree_node *InterSymbol::definition(inter_symbol *S) {
+inter_tree_node *InterSymbol::definition(inter_symbol *S) {
     if (S == NULL) internal_error("tried to find definition of null symbol");
     return S->definition;
 }
 
-int InterSymbol::is_defined(inter_symbol *S) {
+int InterSymbol::is_defined(inter_symbol *S) {
     if (S == NULL) return FALSE;
     if (InterSymbol::definition(S)) return TRUE;
     return FALSE;
@@ -457,7 +457,7 @@ in the current package. So:
 

-int InterSymbol::defined_elsewhere(inter_symbol *S) {
+int InterSymbol::defined_elsewhere(inter_symbol *S) {
     if (S == NULL) return FALSE;
     if (Wiring::is_wired(S)) return TRUE;
     if (InterSymbol::get_type(S) == PLUG_ISYMT) return TRUE;
@@ -467,7 +467,7 @@ in the current package. So:
 

§19. Identifier name.

-text_stream *InterSymbol::identifier(inter_symbol *S) {
+text_stream *InterSymbol::identifier(inter_symbol *S) {
     if (S == NULL) return NULL;
     return S->identifier;
 }
@@ -527,7 +527,7 @@ annotation _translation        InterSymbol::package(S), S, TRANSLATION_IANN, identifier);
 }
 
-text_stream *InterSymbol::get_translate(inter_symbol *S) {
+text_stream *InterSymbol::get_translate(inter_symbol *S) {
     if (S == NULL) internal_error("no symbol");
     return SymbolAnnotation::get_t(S,
         InterPackage::tree(InterSymbol::package(S)), TRANSLATION_IANN);
diff --git a/docs/bytecode-module/2-trn.html b/docs/bytecode-module/2-trn.html
index 2f74f6fab..b2161ff71 100644
--- a/docs/bytecode-module/2-trn.html
+++ b/docs/bytecode-module/2-trn.html
@@ -391,7 +391,7 @@ the root package of the origin.
         Inode::extend_instruction_by(D, 1);
         D->W.instruction[i] = old_D->W.instruction[i];
     }
-    inter_error_message *E = InterConstruct::verify_construct(
+    inter_error_message *E = Inter::Verify::instruction(
         InterBookmark::package(&(det->primitives_point)), D);
     if (E) {
         Inter::Errors::issue(E);
@@ -440,7 +440,7 @@ to matching declarations in the destination.
         InterTree::global_scope(det->destination_tree), InterSymbol::identifier(original_ptype));
     inter_tree_node *D = Inode::new_with_1_data_field(&(det->ptypes_point), PACKAGETYPE_IST,
         InterSymbolsTable::id_from_symbol(det->destination_tree, NULL, equivalent_ptype), NULL, 0);
-    inter_error_message *E = InterConstruct::verify_construct(
+    inter_error_message *E = Inter::Verify::instruction(
         InterBookmark::package(&(det->ptypes_point)), D);
     if (E) {
         Inter::Errors::issue(E);
diff --git a/docs/bytecode-module/2-tw.html b/docs/bytecode-module/2-tw.html
index e16969e98..658dd6792 100644
--- a/docs/bytecode-module/2-tw.html
+++ b/docs/bytecode-module/2-tw.html
@@ -405,7 +405,7 @@ in order to cache the results of those two calculations.
     int extent;
 } warehouse_floor_space;
 
-
  • The structure warehouse_floor_space is accessed in 2/it, 2/in, 2/bkm, 2/np, 2/pck, 2/st, 2/sym, 2/ann, 2/trn, 3/ic, 3/iibf, 3/iitf, 3/vi, 3/ivp, 3/idt, 3/mtd, 4/tcc, 4/tpc, 4/tlc, 4/tac, 4/tpc2, 4/tpc3, 4/ttc, 4/tdc, 4/tvc, 4/tcc2, 4/tic, 4/tpc4, 4/tpc5, 4/tpc6, 4/tpc7, 5/tlc, 5/tlc2, 5/tic, 5/trc, 5/tvc, 5/tlc3, 5/tac, 5/tcc, 5/tec, 5/trc2, 5/tcc2, 5/tsc and here.
+
  • The structure warehouse_floor_space is accessed in 2/it, 2/in, 2/bkm, 2/np, 2/pck, 2/st, 2/sym, 2/ann, 2/trn, 3/ic, 3/iibf, 3/iitf, 3/vi, 3/ivp, 3/idt, 3/mtd, 4/tcc, 4/tpc, 4/tlc, 4/tac, 4/tpc3, 4/ttc, 4/tdc, 4/tvc, 4/tcc2, 4/tic, 4/tpc4, 4/tpc5, 4/tpc6, 4/tpc7, 5/tlc, 5/tlc2, 5/tic, 5/trc, 5/tvc, 5/tlc3, 5/tac, 5/tcc, 5/tec, 5/trc2, 5/tcc2, 5/tsc and here.

§15. We provide an API of just two functions to handle all this. Firstly, InterWarehouse::make_floor_space makes room for an instruction of n words. (This is the frame extent, and does not include the PREFRAME_SIZE.) diff --git a/docs/bytecode-module/2-tw2.html b/docs/bytecode-module/2-tw2.html index bda9627a7..fdf1299f6 100644 --- a/docs/bytecode-module/2-tw2.html +++ b/docs/bytecode-module/2-tw2.html @@ -125,7 +125,7 @@ can wire to at most one other.

-int Wiring::is_wired(inter_symbol *S) {
+int Wiring::is_wired(inter_symbol *S) {
     if (Wiring::wired_to(S)) return TRUE;
     return FALSE;
 }
@@ -145,7 +145,7 @@ reach an end. On all these symbols, Wi
 

-inter_symbol *Wiring::cable_end(inter_symbol *S) {
+inter_symbol *Wiring::cable_end(inter_symbol *S) {
     while ((S) && (S->wiring.connects_to)) S = S->wiring.connects_to;
     return S;
 }
diff --git a/docs/bytecode-module/3-ic.html b/docs/bytecode-module/3-ic.html
index d2f8958a5..3bffc8923 100644
--- a/docs/bytecode-module/3-ic.html
+++ b/docs/bytecode-module/3-ic.html
@@ -88,6 +88,8 @@ function togglePopup(material_id) {
     int max_level;  max node tree depth within its package
     int usage_permissions;  a bitmap of the *_ICUP values
 
+    int min_extent;  min number of words in the frame for this instruction
+    int max_extent;  max number of words in the frame for this instruction
     int symbol_defn_field;  if this instruction declares a symbol, -1 otherwise
     int TID_field;  if this instruction declares a symbol with a type, -1 otherwise
 
@@ -96,7 +98,7 @@ function togglePopup(material_id) {
     CLASS_DEFINITION
 } inter_construct;
 
-inter_construct *InterConstruct::create_construct(inter_ti ID, text_stream *name) {
+inter_construct *InterConstruct::create_construct(inter_ti ID, text_stream *name) {
     inter_construct *IC = CREATE(inter_construct);
     IC->construct_ID = ID;
     IC->construct_name = Str::duplicate(name);
@@ -106,17 +108,18 @@ function togglePopup(material_id) {
     IC->min_level = 0;
     IC->max_level = 0;
     IC->usage_permissions = INSIDE_PLAIN_PACKAGE_ICUP;
+    IC->min_extent = 1; IC->max_extent = UNLIMITED_INSTRUCTION_FRAME_LENGTH;
 
     IC->symbol_defn_field = -1;
     IC->TID_field = -1;
 
     IC->methods = Methods::new_set();
 
-    InterConstruct::set_construct_for_ID(ID, IC);
+    InterConstruct::set_construct_for_ID(ID, IC);
     return IC;
 }
 
-
  • The structure inter_construct is accessed in 3/idt and here.
+
  • The structure inter_construct is accessed in 3/vi, 3/idt and here.

§2. Numerous constructs are for instructions which define symbols, and sometimes those have a data type attached. If so, the symbol ID will live in one field of an instruction made with that construct, and the data type (in TID form — @@ -124,7 +127,7 @@ see Inter Data Types) will live in ano

-void InterConstruct::defines_symbol_in_fields(inter_construct *IC, int s, int t) {
+void InterConstruct::defines_symbol_in_fields(inter_construct *IC, int s, int t) {
     IC->symbol_defn_field = s;
     IC->TID_field = t;
 }
@@ -151,17 +154,29 @@ Those must be explicitly granted when a new construct is created.
     IC->usage_permissions |= usage;
 }
 
-void InterConstruct::allow_in_depth_range(inter_construct *IC, int l1, int l2) {
+void InterConstruct::allow_in_depth_range(inter_construct *IC, int l1, int l2) {
     IC->min_level = l1;
     IC->max_level = l2;
 }
 
-

§4. So here is the code to police those restrictions. First, for a node already +

§4. The instruction can be constrained to have a given length, in terms of the +number of words of bytecode it occupies: +

+ +
define UNLIMITED_INSTRUCTION_FRAME_LENGTH 0x7fffffff
+
+
+void InterConstruct::fix_instruction_length_between(inter_construct *IC, int l1, int l2) {
+    IC->min_extent = l1;
+    IC->max_extent = l2;
+}
+
+

§5. So here is the code to police those restrictions. First, for a node already in position:

-inter_error_message *InterConstruct::check_permissions(inter_construct *IC,
+inter_error_message *InterConstruct::check_permissions(inter_construct *IC,
     inter_package *pack, inter_error_location *eloc) {
     int need = INSIDE_PLAIN_PACKAGE_ICUP;
     if (pack == NULL) need = OUTSIDE_OF_PACKAGES_ICUP;
@@ -182,14 +197,14 @@ in position:
     return NULL;
 }
 
-

§5. Second, for a proposed use of node not yet in position — this is used when +

§6. Second, for a proposed use of node not yet in position — this is used when reading textual inter, hence the message about indentation:

-inter_error_message *InterConstruct::check_level_in_package(inter_bookmark *IBM,
+inter_error_message *InterConstruct::check_level_in_package(inter_bookmark *IBM,
     inter_ti ID, int level, inter_error_location *eloc) {
-    inter_construct *proposed = InterConstruct::get_construct_for_ID(ID);
+    inter_construct *proposed = InterConstruct::get_construct_for_ID(ID);
     if (proposed == NULL) return Inter::Errors::plain(I"no such construct", eloc);
     inter_package *pack = InterBookmark::package(IBM);
     int actual = level;
@@ -198,10 +213,10 @@ reading textual inter, hence the message about indentation:
     if (actual < 0) return Inter::Errors::plain(I"impossible level", eloc);
     if ((actual < proposed->min_level) || (actual > proposed->max_level))
         return Inter::Errors::plain(I"indentation error", eloc);
-    return InterConstruct::check_permissions(proposed, pack, eloc);
+    return InterConstruct::check_permissions(proposed, pack, eloc);
 }
 
-

§6. A much more formidable check. This traverses an entire tree, and verifies +

§7. A much more formidable check. This traverses an entire tree, and verifies that every construct is legally used:

@@ -211,11 +226,11 @@ that every construct is legally used: inter_ti package_level; } tree_lint_state; -void InterConstruct::tree_lint(inter_tree *I) { +void InterConstruct::tree_lint(inter_tree *I) { tree_lint_state tls; tls.package = I->root_package; tls.package_level = 0; - InterConstruct::tree_lint_r(I, I->root_node, &tls); + InterConstruct::tree_lint_r(I, I->root_node, &tls); } void InterConstruct::tree_lint_r(inter_tree *I, inter_tree_node *P, tree_lint_state *tls) { @@ -229,13 +244,13 @@ that every construct is legally used: internal_error("node in wrong package"); } inter_construct *IC = NULL; - inter_error_message *E = InterConstruct::get_construct(C, &IC); + inter_error_message *E = InterConstruct::get_construct(C, &IC); if (E) Inter::Errors::issue(E); if (IC) { - inter_error_location *eloc = Inode::get_error_location(C); - E = InterConstruct::check_permissions(IC, tls->package, eloc); + inter_error_location *eloc = Inode::get_error_location(C); + E = InterConstruct::check_permissions(IC, tls->package, eloc); if (E) Inter::Errors::issue(E); - E = InterConstruct::verify_children(C); + E = InterConstruct::verify_children(C); if (E) { Inter::Errors::issue(E); Inter::Errors::backtrace(STDERR, C); @@ -256,7 +271,7 @@ that every construct is legally used: tree_lint_state inner_tls; inner_tls.package = InterPackage::at_this_head(C); inner_tls.package_level = level + 1; - InterConstruct::tree_lint_r(I, C, &inner_tls); + InterConstruct::tree_lint_r(I, C, &inner_tls); LOOP_OVER_SYMBOLS_TABLE(S, InterPackage::scope(inner_tls.package)) if ((InterSymbol::get_flag(S, SPECULATIVE_ISYMF)) && (InterSymbol::is_defined(S) == FALSE)) { @@ -265,14 +280,14 @@ that every construct is legally used: InterSymbol::identifier(S), eloc)); } } else { - InterConstruct::tree_lint_r(I, C, tls); + InterConstruct::tree_lint_r(I, C, tls); } } } }
  • The structure tree_lint_state is accessed in 2/it, 2/in, 2/bkm, 2/trn, 4/tac, 4/tcc2 and here.
-

§7. So much for a construct's invariants. Now we turn to the textual syntax for it, +

§8. So much for a construct's invariants. Now we turn to the textual syntax for it, which of course applies only to the textual form of Inter. Moreover, the syntax fields of an inter_construct are used only for parsing, and not for printing instructions out again; it's just not worth the bother of doing it that way, @@ -295,7 +310,7 @@ but give it no syntax. If so, it will be inexpressible in textual Inter code.

define MAX_RECOGNITION_REGEXP_LENGTH 64
 
-void InterConstruct::specify_syntax(inter_construct *IC, text_stream *syntax) {
+void InterConstruct::specify_syntax(inter_construct *IC, text_stream *syntax) {
     IC->syntax = syntax;
     TEMPORARY_TEXT(regexp)
     for (int i = 0; i < Str::len(syntax); i++) {
@@ -337,7 +352,7 @@ but give it no syntax. If so, it will be inexpressible in textual Inter code.
     DISCARD_TEXT(regexp)
 }
 
-

§8. There isn't really a construct with ID 0: this is used only as a sort of "not +

§9. There isn't really a construct with ID 0: this is used only as a sort of "not a legal construct" value. Notice the way we give it no syntax, grant it no permissions, and allow it only in an impossible range. So this cannot be expressed in textual Inter, and cannot be stored in bytecode binary Inter either. @@ -346,12 +361,12 @@ in textual Inter, and cannot be stored in bytecode binary Inter either.

enum INVALID_IST from 0
 
-void InterConstruct::define_invalid_construct(void) {
+void InterConstruct::define_invalid_construct(void) {
     inter_construct *IC = InterConstruct::create_construct(INVALID_IST, I"invalid");
     InterConstruct::allow_in_depth_range(IC, 0, -1);
 }
 
-

§9. The valid construct IDs then count upwards from there. Since these IDs are +

§10. The valid construct IDs then count upwards from there. Since these IDs are stored in the bytecode for an instruction, in fact in the 0th word of the frame, we will need to convert them to their inter_construct equivalents quickly. So we store a lookup table: @@ -363,7 +378,7 @@ So we store a lookup table: int inter_construct_by_ID_ready = FALSE; inter_construct *inter_construct_by_ID[MAX_INTER_CONSTRUCTS]; -void InterConstruct::set_construct_for_ID(inter_ti ID, inter_construct *IC) { +void InterConstruct::set_construct_for_ID(inter_ti ID, inter_construct *IC) { if (inter_construct_by_ID_ready == FALSE) { inter_construct_by_ID_ready = TRUE; for (int i=0; i<MAX_INTER_CONSTRUCTS; i++) inter_construct_by_ID[i] = NULL; @@ -372,33 +387,33 @@ So we store a lookup table: inter_construct_by_ID[ID] = IC; } -inter_construct *InterConstruct::get_construct_for_ID(inter_ti ID) { +inter_construct *InterConstruct::get_construct_for_ID(inter_ti ID) { if ((ID == INVALID_IST) || (ID >= MAX_INTER_CONSTRUCTS) || (inter_construct_by_ID_ready == FALSE)) return NULL; return inter_construct_by_ID[ID]; }

-

§10. Whence, in a faintly paranoid way: +

§11. Whence, in a faintly paranoid way:

-inter_error_message *InterConstruct::get_construct(inter_tree_node *P, inter_construct **to) {
+inter_error_message *InterConstruct::get_construct(inter_tree_node *P, inter_construct **to) {
     if (P == NULL) return Inode::error(P, I"invalid node", NULL);
-    inter_construct *IC = InterConstruct::get_construct_for_ID(P->W.instruction[ID_IFLD]);
+    inter_construct *IC = InterConstruct::get_construct_for_ID(P->W.instruction[ID_IFLD]);
     if (IC == NULL) return Inode::error(P, I"no such construct", NULL);
     if (to) *to = IC;
     return NULL;
 }
 
-

§11. Each construct is managed by its own section of code, and that includes +

§12. Each construct is managed by its own section of code, and that includes the creation of the constructs: so we poll those sections in turn.

-void InterConstruct::create_language(void) {
+void InterConstruct::create_language(void) {
     SymbolAnnotation::declare_canonical_annotations();
-    InterConstruct::define_invalid_construct();
+    InterConstruct::define_invalid_construct();
     Inter::Nop::define();
     Inter::Comment::define();
     Inter::Plug::define();
@@ -432,7 +447,7 @@ the creation of the constructs: so we poll those sections in turn.
     Inter::Splat::define();
 }
 
-

§12. The result is printed when inter is run with the -constructs switch. +

§13. The result is printed when inter is run with the -constructs switch.

@@ -448,7 +463,7 @@ the creation of the constructs: so we poll those sections in turn.
     }
 }
 
-

§13. Okay then! We have our constructs: what shall we do with them? +

§14. Okay then! We have our constructs: what shall we do with them?

The answer is that each construct behaves differently, in ways specified by @@ -460,6 +475,12 @@ a self-consistent way by the given instruction, and (ii) that it can see child nodes to that instruction of a kind it expects.

+

InterConstruct::verify should be called only by Inter::Verify::instruction, +which ensures that InterConstruct::verify is never called twice on the same +instruction. CONSTRUCT_VERIFY_MTID methods for the constructs can therefore +safely assume that. +

+
enum CONSTRUCT_VERIFY_MTID
 enum CONSTRUCT_VERIFY_CHILDREN_MTID
 
@@ -469,38 +490,22 @@ nodes to that instruction of a kind it expects. VOID_METHOD_TYPE(CONSTRUCT_VERIFY_CHILDREN_MTID, inter_construct *IC, inter_tree_node *P, inter_error_message **E) -inter_error_message *InterConstruct::verify_construct(inter_package *owner, - inter_tree_node *P) { - inter_construct *IC = NULL; - inter_error_message *E = InterConstruct::get_construct(P, &IC); - if (E) return E; - - if (IC->symbol_defn_field >= 0) { - if (P->W.extent < IC->symbol_defn_field) - return Inode::error(P, I"extent wrong", NULL); - if (IC->construct_ID == LOCAL_IST) { - inter_symbols_table *locals = InterPackage::scope(owner); - if (locals == NULL) return Inode::error(P, I"no symbols table in function", NULL); - E = Inter::Verify::local_defn(P, IC->symbol_defn_field, locals); - } else { - E = Inter::Verify::defn(owner, P, IC->symbol_defn_field); - } - if (E) return E; - } - +inter_error_message *InterConstruct::verify(inter_package *owner, + inter_construct *IC, inter_tree_node *P) { + inter_error_message *E = NULL; VOID_METHOD_CALL(IC, CONSTRUCT_VERIFY_MTID, P, owner, &E); return E; } -inter_error_message *InterConstruct::verify_children(inter_tree_node *P) { +inter_error_message *InterConstruct::verify_children(inter_tree_node *P) { inter_construct *IC = NULL; - inter_error_message *E = InterConstruct::get_construct(P, &IC); + inter_error_message *E = InterConstruct::get_construct(P, &IC); if (E) return E; VOID_METHOD_CALL(IC, CONSTRUCT_VERIFY_CHILDREN_MTID, P, &E); return E; }
-

§14. This method writes out an instruction in textual Inter format, and this is +

§15. This method writes out an instruction in textual Inter format, and this is handled differently by each construct.

@@ -510,15 +515,15 @@ handled differently by each construct. VOID_METHOD_TYPE(CONSTRUCT_WRITE_MTID, inter_construct *IC, text_stream *OUT, inter_tree_node *P, inter_error_message **E) -inter_error_message *InterConstruct::write_construct_text(OUTPUT_STREAM, inter_tree_node *P) { +inter_error_message *InterConstruct::write_construct_text(OUTPUT_STREAM, inter_tree_node *P) { if (P->W.instruction[ID_IFLD] == NOP_IST) return NULL; - return InterConstruct::write_construct_text_allowing_nop(OUT, P); + return InterConstruct::write_construct_text_allowing_nop(OUT, P); } -inter_error_message *InterConstruct::write_construct_text_allowing_nop(OUTPUT_STREAM, +inter_error_message *InterConstruct::write_construct_text_allowing_nop(OUTPUT_STREAM, inter_tree_node *P) { inter_construct *IC = NULL; - inter_error_message *E = InterConstruct::get_construct(P, &IC); + inter_error_message *E = InterConstruct::get_construct(P, &IC); if (E) return E; for (inter_ti L=0; L<P->W.instruction[LEVEL_IFLD]; L++) WRITE("\t"); VOID_METHOD_CALL(IC, CONSTRUCT_WRITE_MTID, OUT, P, &E); @@ -527,7 +532,21 @@ handled differently by each construct. return E; }
-

§15. Conversely, the function InterConstruct::match takes a line of textual Inter +

§16. A much less elegant presentation is just to dump the hexadecimal bytecode, +and this is used only for debugging or to show errors in binary Inter files. +

+ +
+void InterConstruct::instruction_writer(OUTPUT_STREAM, char *format_string, void *vI) {
+    inter_tree_node *F = (inter_tree_node *) vI;
+    if (F == NULL) { WRITE("<no frame>"); return; }
+    WRITE("%05d -> ", F->W.index);
+    WRITE("%d {", F->W.extent);
+    for (int i=0; i<F->W.extent; i++) WRITE(" %08x", F->W.instruction[i]);
+    WRITE(" }");
+}
+
+

§17. Conversely, the function InterConstruct::match takes a line of textual Inter source code, uses the regular expressions for each construct to find which one is being used, and then calls its CONSTRUCT_READ_MTID method to ask for the job to be completed. @@ -539,7 +558,7 @@ job to be completed. VOID_METHOD_TYPE(CONSTRUCT_READ_MTID, inter_construct *IC, inter_bookmark *, inter_line_parse *, inter_error_location *, inter_error_message **E) -inter_error_message *InterConstruct::match(inter_line_parse *ilp, inter_error_location *eloc, +inter_error_message *InterConstruct::match(inter_line_parse *ilp, inter_error_location *eloc, inter_bookmark *IBM) { inter_construct *IC; LOOP_OVER(IC, inter_construct) @@ -552,7 +571,7 @@ job to be completed. return Inter::Errors::plain(I"bad inter line", eloc); }

-

§16. Transposition is an awkward necessity when binary Inter is read in from a file, +

§18. Transposition is an awkward necessity when binary Inter is read in from a file, and some references in its instruction bytecode need to be modified: this is not the place to explain it. See Inter in Binary Files.

@@ -563,10 +582,10 @@ not the place to explain it. See Inter in VOID_METHOD_TYPE(CONSTRUCT_TRANSPOSE_MTID, inter_construct *IC, inter_tree_node *P, inter_ti *grid, inter_ti max, inter_error_message **E) -inter_error_message *InterConstruct::transpose_construct(inter_package *owner, +inter_error_message *InterConstruct::transpose_construct(inter_package *owner, inter_tree_node *P, inter_ti *grid, inter_ti max) { inter_construct *IC = NULL; - inter_error_message *E = InterConstruct::get_construct(P, &IC); + inter_error_message *E = InterConstruct::get_construct(P, &IC); if (E) return E; VOID_METHOD_CALL(IC, CONSTRUCT_TRANSPOSE_MTID, P, grid, max, &E); return E; diff --git a/docs/bytecode-module/3-idt.html b/docs/bytecode-module/3-idt.html index 9d5fe33bf..6b8a25b3d 100644 --- a/docs/bytecode-module/3-idt.html +++ b/docs/bytecode-module/3-idt.html @@ -117,7 +117,7 @@ whereas list, f define MIN_INTER_TYPE_CONSTRUCTOR UNCHECKED_ITCONC define MAX_INTER_TYPE_CONSTRUCTOR VOID_ITCONC -int InterTypes::is_valid_constructor_code(inter_ti constructor) { +int InterTypes::is_valid_constructor_code(inter_ti constructor) { if ((constructor < MIN_INTER_TYPE_CONSTRUCTOR) || (constructor > MAX_INTER_TYPE_CONSTRUCTOR)) return FALSE; return TRUE; @@ -355,7 +355,7 @@ in which all data is unchecke return InterTypes::untyped(); } -inter_type InterTypes::from_TID_in_field(inter_tree_node *P, int field) { +inter_type InterTypes::from_TID_in_field(inter_tree_node *P, int field) { return InterTypes::from_TID(InterPackage::scope(Inode::get_package(P)), P->W.instruction[field]); }
@@ -802,7 +802,7 @@ in which all data is unchecke if (D == NULL) return InterTypes::untyped(); if (InterSymbol::defined_elsewhere(symb)) return InterTypes::untyped(); inter_construct *IC = NULL; - if (InterConstruct::get_construct(D, &IC)) return InterTypes::untyped(); + if (InterConstruct::get_construct(D, &IC)) return InterTypes::untyped(); if (IC->TID_field >= 0) return InterTypes::from_TID_in_field(D, IC->TID_field); return InterTypes::untyped(); } @@ -811,7 +811,7 @@ in which all data is unchecke inter_tree_node *D = InterSymbol::definition(symb); if (D) { inter_construct *IC = NULL; - if (InterConstruct::get_construct(D, &IC)) return FALSE; + if (InterConstruct::get_construct(D, &IC)) return FALSE; if (IC->construct_ID == TYPENAME_IST) return TRUE; if (IC->TID_field >= 0) return TRUE; } diff --git a/docs/bytecode-module/3-ie.html b/docs/bytecode-module/3-ie.html index 1c50fa7ab..9be02d39f 100644 --- a/docs/bytecode-module/3-ie.html +++ b/docs/bytecode-module/3-ie.html @@ -111,13 +111,13 @@ function togglePopup(material_id) { CLASS_DEFINITION } inter_error_message; -inter_error_message *Inter::Errors::quoted(text_stream *err, text_stream *quote, inter_error_location *eloc) { +inter_error_message *Inter::Errors::quoted(text_stream *err, text_stream *quote, inter_error_location *eloc) { inter_error_message *iem = Inter::Errors::plain(err, eloc); iem->error_quote = Str::duplicate(quote); return iem; } -inter_error_message *Inter::Errors::plain(text_stream *err, inter_error_location *eloc) { +inter_error_message *Inter::Errors::plain(text_stream *err, inter_error_location *eloc) { inter_error_message *iem = CREATE(inter_error_message); iem->error_body = Str::duplicate(err); iem->error_quote = NULL; @@ -125,7 +125,7 @@ function togglePopup(material_id) { return iem; } -void Inter::Errors::issue(inter_error_message *iem) { +void Inter::Errors::issue(inter_error_message *iem) { if (iem == NULL) internal_error("no error to issue"); Inter::Errors::issue_to(STDERR, iem); #ifdef CORE_MODULE @@ -161,7 +161,7 @@ function togglePopup(material_id) {

§2.

-void Inter::Errors::backtrace(OUTPUT_STREAM, inter_tree_node *F) {
+void Inter::Errors::backtrace(OUTPUT_STREAM, inter_tree_node *F) {
     inter_tree_node *X = F;
     int n = 0;
     while (TRUE) {
@@ -181,7 +181,7 @@ function togglePopup(material_id) {
                 } else {
                     WRITE("%2d.    ", (n-i));
                 }
-                InterConstruct::write_construct_text_allowing_nop(OUT, X);
+                InterConstruct::write_construct_text_allowing_nop(OUT, X);
                 break;
             }
             X = Y;
@@ -190,7 +190,7 @@ function togglePopup(material_id) {
     }
     LOOP_THROUGH_INTER_CHILDREN(C, F) {
         WRITE("%2d.    ", (n+1));
-        InterConstruct::write_construct_text_allowing_nop(OUT, C);
+        InterConstruct::write_construct_text_allowing_nop(OUT, C);
     }
 }
 
diff --git a/docs/bytecode-module/3-iibf.html b/docs/bytecode-module/3-iibf.html index e81e9e2d1..d1e100556 100644 --- a/docs/bytecode-module/3-iibf.html +++ b/docs/bytecode-module/3-iibf.html @@ -1018,9 +1018,9 @@ the definition of any symbol created in the instruction to inter_error_message *E = NULL; - if (grid) E = InterConstruct::transpose_construct(owner, P, grid, grid_extent); + if (grid) E = InterConstruct::transpose_construct(owner, P, grid, grid_extent); if (E) { Inter::Errors::issue(E); exit(1); } - E = InterConstruct::verify_construct(owner, P); + E = Inter::Verify::instruction(owner, P); if (E) { Inter::Errors::issue(E); exit(1); }
diff --git a/docs/bytecode-module/3-iitf.html b/docs/bytecode-module/3-iitf.html index 52879e13a..458af9944 100644 --- a/docs/bytecode-module/3-iitf.html +++ b/docs/bytecode-module/3-iitf.html @@ -90,7 +90,7 @@ tree I. TextFiles::read(F, FALSE, "can't open inter file", FALSE, TextualInter::read_line, 0, &irl); TextualInter::resolve_forward_references(I); - InterConstruct::tree_lint(I); + InterConstruct::tree_lint(I); Primitives::index_primitives_in_tree(I); }
@@ -146,7 +146,7 @@ See Inter Primitives (in Find indentation3.1; If the indentation is now lower than expected, move the write position up the tree3.2; Parse any annotations at the end of the line3.3; - return InterConstruct::match(&ilp, eloc, write_pos); + return InterConstruct::match(&ilp, eloc, write_pos); }
  • The structure inter_line_parse is accessed in 3/ic, 4/tcc, 4/tpc, 4/tlc, 4/tac, 4/tpc2, 4/tpc3, 4/ttc, 4/tdc, 4/tvc, 4/tcc2, 4/tic, 4/tpc4, 4/tpc5, 4/tpc6, 4/tpc7, 5/tlc, 5/tlc2, 5/tic, 5/trc, 5/tvc, 5/tlc3, 5/tac, 5/tcc, 5/tec, 5/trc2, 5/tcc2, 5/tsc, 6/tpc, 6/tsc, 6/tvc and here.
@@ -460,7 +460,7 @@ the filter test. void TextualInter::visitor(inter_tree *I, inter_tree_node *P, void *state) { textual_write_state *tws = (textual_write_state *) state; if ((tws->filter) && ((*(tws->filter))(P) == FALSE)) return; - inter_error_message *E = InterConstruct::write_construct_text(tws->to, P); + inter_error_message *E = InterConstruct::write_construct_text(tws->to, P); if (E) Inter::Errors::issue(E); }
diff --git a/docs/bytecode-module/3-ivp.html b/docs/bytecode-module/3-ivp.html index 7f0282427..709c01682 100644 --- a/docs/bytecode-module/3-ivp.html +++ b/docs/bytecode-module/3-ivp.html @@ -312,9 +312,7 @@ function togglePopup(material_id) { return V2; } -inter_error_message *InterValuePairs::validate(inter_package *owner, inter_tree_node *P, int index, inter_type type) { - inter_ti V1 = P->W.instruction[index]; - inter_ti V2 = P->W.instruction[index+1]; +inter_error_message *InterValuePairs::verify(inter_package *owner, inter_tree_node *P, inter_ti V1, inter_ti V2, inter_type type) { inter_symbols_table *scope = InterPackage::scope(owner); if (scope == NULL) scope = Inode::globals(P); switch (V1) { @@ -332,7 +330,7 @@ function togglePopup(material_id) { if (InterTypes::expresses_value(symb) == FALSE) return Inode::error(P, I"nonconstant symbol", InterSymbol::identifier(symb)); inter_type symbol_type = InterTypes::of_symbol(symb); - return InterTypes::can_be_used_as(symbol_type, type, InterSymbol::identifier(symb), Inode::get_error_location(P)); + return InterTypes::can_be_used_as(symbol_type, type, InterSymbol::identifier(symb), Inode::get_error_location(P)); } case DWORD_IVAL: case PDWORD_IVAL: diff --git a/docs/bytecode-module/3-vi.html b/docs/bytecode-module/3-vi.html index 6489201b5..d766e3fdd 100644 --- a/docs/bytecode-module/3-vi.html +++ b/docs/bytecode-module/3-vi.html @@ -71,138 +71,245 @@ function togglePopup(material_id) { -

Verifying that a chunk of inter is correct and consistent.

+

Verifying that a new Inter instruction is correct and consistent.

-

§1.

+

§1. Each time a new instruction is created within inter, or loaded in +from a binary Inter file, it is "verified". We use a flag in the preframe for +the instruction to ensure that it is verified only once, for the sake both of +speed and to ensure that certain one-time-only operations are indeed done +one time only. +

+ +

As this implies, "verification" is not quite the passive business which the +name makes it seem. Verification does indeed perform many sanity checks on +an instruction, but it also cross-references the Inter tree to accommodate +the new instruction. (Because of this, unverified instructions may not work, +and this is why the code to create instructions automatically calls us.) +

-inter_error_message *Inter::Verify::defn(inter_package *owner, inter_tree_node *P, int index) {
+inter_error_message *Inter::Verify::instruction(inter_package *owner, inter_tree_node *P) {
+    if (Inode::get_vflag(P) == FALSE) {
+        Inode::set_vflag(P);
+        inter_construct *IC = NULL;
+        inter_error_message *E = InterConstruct::get_construct(P, &IC);
+        if (E) return E;
+        Check the extent of the instruction1.1;
+        if (IC->symbol_defn_field >= 0) Set the symbol definition to this instruction1.2;
+        Apply construct-specific checks1.3;
+        return E;
+    }
+    return NULL;
+}
+
+

§1.1. Check the extent of the instruction1.1 = +

+ +
+    if ((P->W.extent < IC->min_extent) || (P->W.extent > IC->max_extent)) {
+        text_stream *msg = Str::new();
+        WRITE_TO(msg, "%S instruction has extent %d words, which is not between %d and %d",
+            IC->construct_name, P->W.extent, IC->min_extent, IC->max_extent);
+        return Inode::error(P, msg, NULL);
+    }
+
+
  • This code is used in §1.
+

§1.2. Some instructions create new symbols, giving them definitions: for example, +if P is constant bakers_dozen = 13 then a new bakers_dozen symbol must +be created and given the node P as its definition. +

+ +

We have to do this in verification, because if we did it only when an instruction +is created, that would then not be done bytecode is read in from a binary Inter file. +

+ +

Set the symbol definition to this instruction1.2 = +

+ +
+    if (P->W.extent < IC->symbol_defn_field) return Inode::error(P, I"extent wrong", NULL);
     inter_symbols_table *T = InterPackage::scope(owner);
-    if (T == NULL) T = Inode::globals(P);
-    inter_symbol *S = InterSymbolsTable::symbol_from_ID_not_following(T, P->W.instruction[index]);
-    if (S == NULL) return Inode::error(P, I"no symbol for ID (case 1)", NULL);
-    if (Wiring::is_wired(S)) {
-        inter_symbol *E = Wiring::cable_end(S);
-        LOG("This is $6 but $3 is wired to $3 in $6\n",
-            InterPackage::container(P), S, E, InterPackage::container(E->definition));
-        return Inode::error(P, I"symbol defined outside its native scope",
+    inter_ti SID = P->W.instruction[IC->symbol_defn_field];
+    inter_symbol *S = InterSymbolsTable::symbol_from_ID_not_following(T, SID);
+    if ((IC->construct_ID == LOCAL_IST) || (IC->construct_ID == LABEL_IST)) {
+        if (T == NULL) return Inode::error(P, I"no symbols table in function", NULL);
+        Make a local definition1.2.2;
+    } else {
+        if (T == NULL) T = Inode::globals(P);
+        Make a global definition1.2.1;
+    }
+    if (E) return E;
+
+
  • This code is used in §1.
+

§1.2.1. Make a global definition1.2.1 = +

+ +
+    if (S == NULL) {
+        E = Inode::error(P, I"no symbol for global definition ID", NULL);
+    } else if (Wiring::is_wired(S)) {
+        inter_symbol *CE = Wiring::cable_end(S);
+        LOG("This is $6 but $3 ~~> $3 in $6\n",
+            InterPackage::container(P), S, CE, InterPackage::container(CE->definition));
+        E = Inode::error(P, I"symbol defined outside its native scope",
             InterSymbol::identifier(S));
-    }
-    if (InterSymbol::misc_but_undefined(S)) {
+    } else if (InterSymbol::misc_but_undefined(S)) {
         InterSymbol::define(S, P);
-    } else if (P != InterSymbol::definition(S)) {
-        LOG("So S ---> %S\n", InterSymbol::get_translate(S));
-        return Inode::error(P, I"duplicated symbol", InterSymbol::identifier(S));
+    } else /* if (P != InterSymbol::definition(S)) */ {
+        E = Inode::error(P, I"duplicated symbol", InterSymbol::identifier(S));
     }
-    return NULL;
+
+
  • This code is used in §1.2.
+

§1.2.2. Make a local definition1.2.2 = +

+ +
+    if (S == NULL) {
+        E = Inode::error(P, I"no symbol for local variable ID", NULL);
+    } else if (InterSymbol::is_defined(S) == FALSE) {
+        InterSymbol::define(S, P);
+    } else /* if (P != InterSymbol::definition(S)) */ {
+        E = Inode::error(P, I"duplicated local symbol", InterSymbol::identifier(S));
+    }
+
+
  • This code is used in §1.2.
+

§1.3. Finally we will check, where we can do so speedily, that the bytecode for the +instruction passes various sanity checks. This is partly to catch errors in our +own work (i.e. bugs in the code generating instructions), but also because raw +bytecode read in by Inter in Binary Files is not trustworthy. There's less +chance of garbage bytecode crashing the compiler if we take precautions. +

+ +

All that InterConstruct::verify does is to call the CONSTRUCT_VERIFY_MTID +method for the construct of the instruction. So, for example, for PROPERTY_IST +instructions this is done by Inter::Property::verify, and so on. +

+ +

Apply construct-specific checks1.3 = +

+ +
+    E = InterConstruct::verify(owner, IC, P);
+
+
  • This code is used in §1.
+

§2. Although that work is delegated to the implementation of each construct, it's +convenient for those implementations to use the functions below for some common +sorts of check. +

+ +

Firstly, this tests that a field in a bytecode instruction which purportedly +holds a symbol ID, SID, actually does so: and that the symbol if defined +is defined by a given construct. It can still be undefined (this allows for, +e.g., the symbol to be wired to a plug for definition in some other compilation +block, or for it not to be defined yet because the rest of the bytecode for +the program has not yet been loaded); but it cannot be the wrong sort of thing. +

+ +
+inter_error_message *Inter::Verify::SID_field(inter_package *owner, inter_tree_node *P,
+    int field, inter_ti construct) {
+    return Inter::Verify::SID(owner, P, P->W.instruction[field], construct);
 }
 
-inter_error_message *Inter::Verify::local_defn(inter_tree_node *P, int index, inter_symbols_table *T) {
-    inter_symbol *S = InterSymbolsTable::symbol_from_ID(T, P->W.instruction[index]);
-    if (S == NULL) return Inode::error(P, I"no symbol for ID (case 2)", NULL);
-    if (InterSymbol::is_defined(S))
-        return Inode::error(P, I"duplicated local symbol", InterSymbol::identifier(S));
-    InterSymbol::define(S, P);
-    return NULL;
-}
-
-inter_error_message *Inter::Verify::symbol(inter_package *owner, inter_tree_node *P, inter_ti ID, inter_ti construct) {
+inter_error_message *Inter::Verify::SID(inter_package *owner, inter_tree_node *P,
+    inter_ti SID, inter_ti construct) {
     inter_symbols_table *T = InterPackage::scope(owner);
     if (T == NULL) T = Inode::globals(P);
-    inter_symbol *S = InterSymbolsTable::symbol_from_ID(T, ID);
-    if (S == NULL) return Inode::error(P, I"no symbol for ID (case 3)", NULL);
+    inter_symbol *S = InterSymbolsTable::symbol_from_ID(T, SID);
+    if (S == NULL) return Inode::error(P, I"no symbol for SID (case 3)", NULL);
     inter_tree_node *D = InterSymbol::definition(S);
     if (InterSymbol::defined_elsewhere(S)) return NULL;
     if (InterSymbol::misc_but_undefined(S)) return NULL;
     if (D == NULL) return Inode::error(P, I"undefined symbol", InterSymbol::identifier(S));
     if ((D->W.instruction[ID_IFLD] != construct) &&
         (InterSymbol::defined_elsewhere(S) == FALSE) &&
-        (InterSymbol::misc_but_undefined(S) == FALSE)) {
+        (InterSymbol::misc_but_undefined(S) == FALSE))
         return Inode::error(P, I"symbol of wrong type", InterSymbol::identifier(S));
-    }
     return NULL;
 }
+
+

§3. The same, but where the ID refers to a symbol in the tree's global symbols +table (such as a primitive invocation): +

-inter_error_message *Inter::Verify::TID(inter_package *owner, inter_tree_node *P, inter_ti TID) { - if (TID == 0) return NULL; - if (InterTypes::is_valid_constructor_code(TID)) return NULL; - return Inter::Verify::symbol(owner, P, TID, TYPENAME_IST); -} - -inter_error_message *Inter::Verify::constructor_code(inter_tree_node *P, int index) { - inter_ti ID = P->W.instruction[index]; - if (InterTypes::is_valid_constructor_code(ID) == FALSE) - return Inode::error(P, I"unknown type constructor", NULL); - return NULL; -} - -void Inter::Verify::typed_data(inter_package *owner, inter_tree_node *P, - int field, int data_field, inter_error_message **E) { - if (P->W.instruction[field]) { - *E = Inter::Verify::TID(owner, P, P->W.instruction[field]); - if (*E) return; - if (data_field >= 0) { - inter_type type = InterTypes::from_TID_in_field(P, field); - *E = InterValuePairs::validate(owner, P, data_field, type); - if (*E) return; - } - } -} - -inter_error_message *Inter::Verify::global_symbol(inter_tree_node *P, inter_ti ID, inter_ti construct) { - inter_symbol *S = InterSymbolsTable::symbol_from_ID(Inode::globals(P), ID); - if (S == NULL) { internal_error("IO"); return Inode::error(P, I"3no symbol for ID", NULL); } +
+inter_error_message *Inter::Verify::GSID_field(inter_tree_node *P, int field,
+    inter_ti construct) {
+    inter_ti GSID = P->W.instruction[field];
+    inter_symbol *S = InterSymbolsTable::symbol_from_ID(Inode::globals(P), GSID);
+    if (S == NULL) return Inode::error(P, I"no global symbol for GSID", NULL);
     inter_tree_node *D = InterSymbol::definition(S);
     if (InterSymbol::defined_elsewhere(S)) return NULL;
     if (InterSymbol::misc_but_undefined(S)) return NULL;
-    if (D == NULL) return Inode::error(P, I"undefined symbol", InterSymbol::identifier(S));
+    if (D == NULL) return Inode::error(P, I"undefined global symbol", InterSymbol::identifier(S));
     if ((D->W.instruction[ID_IFLD] != construct) &&
         (InterSymbol::defined_elsewhere(S) == FALSE) &&
-        (InterSymbol::misc_but_undefined(S) == FALSE)) {
-        return Inode::error(P, I"symbol of wrong type", InterSymbol::identifier(S));
-    }
+        (InterSymbol::misc_but_undefined(S) == FALSE))
+        return Inode::error(P, I"global symbol of wrong type", InterSymbol::identifier(S));
     return NULL;
 }
+
+

§4. This checks an ID for a symbol which has to represent a property owner — so, +either the typename for an enumerated type, or an instance. +

-inter_error_message *Inter::Verify::local_symbol(inter_tree_node *P, inter_ti ID, inter_ti construct, inter_symbols_table *T) { - inter_symbol *S = InterSymbolsTable::symbol_from_ID(T, ID); - if (S == NULL) return Inode::error(P, I"4no symbol for ID", NULL); - inter_tree_node *D = InterSymbol::definition(S); - if (InterSymbol::defined_elsewhere(S)) return NULL; - if (InterSymbol::misc_but_undefined(S)) return NULL; - if (D == NULL) return Inode::error(P, I"undefined symbol", InterSymbol::identifier(S)); - if ((D->W.instruction[ID_IFLD] != construct) && - (InterSymbol::defined_elsewhere(S) == FALSE) && - (InterSymbol::misc_but_undefined(S) == FALSE)) { - return Inode::error(P, I"symbol of wrong type", InterSymbol::identifier(S)); - } - return NULL; -} - -inter_error_message *Inter::Verify::symbol_KOI(inter_package *owner, inter_tree_node *P, inter_ti ID) { +
+inter_error_message *Inter::Verify::POID_field(inter_package *owner, inter_tree_node *P,
+    int field) {
+    inter_ti POID = P->W.instruction[field];
     inter_symbols_table *T = InterPackage::scope(owner);
     if (T == NULL) T = Inode::globals(P);
-    inter_symbol *S = InterSymbolsTable::symbol_from_ID(T, ID);
-    if (S == NULL) return Inode::error(P, I"5no symbol for ID", NULL);
+    inter_symbol *S = InterSymbolsTable::symbol_from_ID(T, POID);
+    if (S == NULL) return Inode::error(P, I"no symbol for property-owner ID", NULL);
     inter_tree_node *D = InterSymbol::definition(S);
     if (InterSymbol::defined_elsewhere(S)) return NULL;
     if (InterSymbol::misc_but_undefined(S)) return NULL;
-    if (D == NULL) return Inode::error(P, I"undefined symbol", InterSymbol::identifier(S));
+    if (D == NULL)
+        return Inode::error(P, I"undefined property-owner symbol", InterSymbol::identifier(S));
     if ((D->W.instruction[ID_IFLD] != TYPENAME_IST) &&
         (InterSymbol::defined_elsewhere(S) == FALSE) &&
         (D->W.instruction[ID_IFLD] != INSTANCE_IST) &&
         (InterSymbol::misc_but_undefined(S) == FALSE))
-            return Inode::error(P, I"symbol of wrong type", InterSymbol::identifier(S));
+            return Inode::error(P, I"property-owner symbol of wrong type",
+                InterSymbol::identifier(S));
     return NULL;
 }
+
+

§5. Next, a field which purportedly holds a type constructor such as INT32_ITCONC +or FUNCTION_ITCONC: see Inter Data Types. +

-void Inter::Verify::writer(OUTPUT_STREAM, char *format_string, void *vI) { - inter_tree_node *F = (inter_tree_node *) vI; - if (F == NULL) { WRITE("<no frame>"); return; } - WRITE("%05d -> ", F->W.index); - WRITE("%d {", F->W.extent); - for (int i=0; i<F->W.extent; i++) WRITE(" %08x", F->W.instruction[i]); - WRITE(" }"); +
+inter_error_message *Inter::Verify::constructor_field(inter_tree_node *P, int field) {
+    inter_ti ID = P->W.instruction[field];
+    if (InterTypes::is_valid_constructor_code(ID) == FALSE)
+        return Inode::error(P, I"unknown type constructor", NULL);
+    return NULL;
+}
+
+

§6. Next, a field which purportedly holds a valid type ID (TID): again, see +Inter Data Types. +

+ +
+inter_error_message *Inter::Verify::TID_field(inter_package *owner, inter_tree_node *P,
+    int field) {
+    inter_ti TID = P->W.instruction[field];
+    if (TID == 0) return NULL;
+    if (InterTypes::is_valid_constructor_code(TID)) return NULL;
+    return Inter::Verify::SID(owner, P, TID, TYPENAME_IST);
+}
+
+

§7. Finally, two consecutive fields which purportedly hold a valid data pair in +the context of the current package: +

+ +
+inter_error_message *Inter::Verify::data_pair_fields(inter_package *owner,
+    inter_tree_node *P, int first_field, inter_type type) {
+    inter_ti V1 = P->W.instruction[first_field];
+    inter_ti V2 = P->W.instruction[first_field+1];
+    return InterValuePairs::verify(owner, P, V1, V2, type);
 }