From e2d7e250458accefa3dfc71290f7f83161549b33 Mon Sep 17 00:00:00 2001 From: Andrew Plotkin Date: Wed, 24 May 2023 17:36:02 -0400 Subject: [PATCH] Plumbing for the OrigSource construct. --- .../Chapter 5/Compile Blocks and Lines.w | 1 + inform7/runtime-module/Chapter 2/Emit Code.w | 8 ++ .../Chapter 3/Inter Constructs.w | 6 ++ .../Chapter 4/The OrigSource Construct.w | 102 ++++++++++++++++++ .../Chapter 5/The Code Construct.w | 1 + inter/bytecode-module/Contents.w | 1 + 6 files changed, 119 insertions(+) create mode 100644 inter/bytecode-module/Chapter 4/The OrigSource Construct.w diff --git a/inform7/imperative-module/Chapter 5/Compile Blocks and Lines.w b/inform7/imperative-module/Chapter 5/Compile Blocks and Lines.w index 7f29b236c..b7a74ed11 100644 --- a/inform7/imperative-module/Chapter 5/Compile Blocks and Lines.w +++ b/inform7/imperative-module/Chapter 5/Compile Blocks and Lines.w @@ -140,6 +140,7 @@ int CompileBlocksAndLines::code_line(int statement_count, parse_node *p, int as_ EmitCode::comment(C); DISCARD_TEXT(C) *last_loc = sl; + EmitCode::origsource(last_loc); } } diff --git a/inform7/runtime-module/Chapter 2/Emit Code.w b/inform7/runtime-module/Chapter 2/Emit Code.w index e9891e473..87d95c7d9 100644 --- a/inform7/runtime-module/Chapter 2/Emit Code.w +++ b/inform7/runtime-module/Chapter 2/Emit Code.w @@ -70,6 +70,14 @@ void EmitCode::comment(text_stream *text) { (inter_ti) EmitCode::level())); } +@h OrigSource directives. + += +void EmitCode::origsource(source_location *sl) { + Produce::guard(OrigSourceInstruction::new(EmitCode::at(), sl->file_of_origin->name, (unsigned int)sl->line_number, NULL, + (inter_ti) EmitCode::level())); +} + @h In value context. These functions all generate a |val| opcode: diff --git a/inter/bytecode-module/Chapter 3/Inter Constructs.w b/inter/bytecode-module/Chapter 3/Inter Constructs.w index 3578f974a..18b4a062c 100644 --- a/inter/bytecode-module/Chapter 3/Inter Constructs.w +++ b/inter/bytecode-module/Chapter 3/Inter Constructs.w @@ -334,6 +334,11 @@ instead specify something else about the tree: @e SOCKET_IST @e VERSION_IST +@ This can go inside or outside function bodies, like COMMENT_IST. I put it +at the end so that it wouldn't change //The Inter Version//. + +@e ORIGSOURCE_IST + @ 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: @@ -380,6 +385,7 @@ void InterInstruction::create_language(void) { InterInstruction::define_invalid_construct(); NopInstruction::define_construct(); CommentInstruction::define_construct(); + OrigSourceInstruction::define_construct(); PlugInstruction::define_construct(); SocketInstruction::define_construct(); VersionInstruction::define_construct(); diff --git a/inter/bytecode-module/Chapter 4/The OrigSource Construct.w b/inter/bytecode-module/Chapter 4/The OrigSource Construct.w new file mode 100644 index 000000000..8b98aafe2 --- /dev/null +++ b/inter/bytecode-module/Chapter 4/The OrigSource Construct.w @@ -0,0 +1,102 @@ +[OrigSourceInstruction::] The OrigSource Construct. + +Defining the OrigSource construct. + +@h Definition. +The OrigSource construct is a marker in the bytecode which indicates the +source location that generated that bytecode. + += +void OrigSourceInstruction::define_construct(void) { + inter_construct *IC = InterInstruction::create_construct(ORIGSOURCE_IST, I"origsource"); + InterInstruction::specify_syntax(IC, I"origsource TEXT NUMBER"); + InterInstruction::data_extent_always(IC, 2); + METHOD_ADD(IC, CONSTRUCT_TRANSPOSE_MTID, OrigSourceInstruction::transpose); + METHOD_ADD(IC, CONSTRUCT_VERIFY_MTID, OrigSourceInstruction::verify); + METHOD_ADD(IC, CONSTRUCT_READ_MTID, OrigSourceInstruction::read); + METHOD_ADD(IC, CONSTRUCT_WRITE_MTID, OrigSourceInstruction::write); + InterInstruction::allow_in_depth_range(IC, 0, INFINITELY_DEEP); + InterInstruction::permit(IC, OUTSIDE_OF_PACKAGES_ICUP); + InterInstruction::permit(IC, INSIDE_PLAIN_PACKAGE_ICUP); + InterInstruction::permit(IC, INSIDE_CODE_PACKAGE_ICUP); +} + +@h Instructions. +In bytecode, the frame of an |origsource| instruction is laid out with the +compulsory words -- see //Inter Nodes// -- followed by: + +@d PROVENANCEFILE_ORIGSOURCE_IFLD (DATA_IFLD + 0) +@d PROVENANCELINE_ORIGSOURCE_IFLD (DATA_IFLD + 1) + += +inter_error_message *OrigSourceInstruction::new(inter_bookmark *IBM, + filename *file, inter_ti line_number, + inter_error_location *eloc, inter_ti level) { + TEMPORARY_TEXT(file_as_text) + if (file) WRITE_TO(file_as_text, "%f", file); + inter_warehouse *warehouse = InterBookmark::warehouse(IBM); + inter_package *pack = InterBookmark::package(IBM); + inter_ti FID = InterWarehouse::create_text(warehouse, pack); + Str::copy(InterWarehouse::get_text(warehouse, FID), file_as_text); + inter_tree_node *P = Inode::new_with_2_data_fields(IBM, ORIGSOURCE_IST, + /* PROVENANCEFILE_ORIGSOURCE_IFLD: */ FID, + /* PROVENANCELINE_ORIGSOURCE_IFLD: */ line_number, + eloc, level); + inter_error_message *E = VerifyingInter::instruction(InterBookmark::package(IBM), P); + if (E) return E; + NodePlacement::move_to_moving_bookmark(P, IBM); + return NULL; +} + +void OrigSourceInstruction::transpose(inter_construct *IC, inter_tree_node *P, + inter_ti *grid, inter_ti grid_extent, inter_error_message **E) { + P->W.instruction[PROVENANCEFILE_ORIGSOURCE_IFLD] = grid[P->W.instruction[PROVENANCEFILE_ORIGSOURCE_IFLD]]; +} + +@ Verification consists only of sanity checks. + += +void OrigSourceInstruction::verify(inter_construct *IC, inter_tree_node *P, + inter_package *owner, inter_error_message **E) { + *E = VerifyingInter::text_field(owner, P, PROVENANCEFILE_ORIGSOURCE_IFLD); + if (*E) return; +} + +@h Creating from textual Inter syntax. + += +void OrigSourceInstruction::read(inter_construct *IC, inter_bookmark *IBM, inter_line_parse *ilp, + inter_error_location *eloc, inter_error_message **E) { + text_stream *fn = ilp->mr.exp[0]; + text_stream *lc = ilp->mr.exp[1]; + TEMPORARY_TEXT(file_as_text) + *E = TextualInter::parse_literal_text(file_as_text, fn, 0, Str::len(fn), eloc); + if (*E == NULL) { + filename *F = NULL; + if (Str::len(file_as_text) > 0) F = Filenames::from_text(file_as_text); + inter_ti line_number = 0; + if (Str::len(lc) > 0) line_number = (inter_ti) Str::atoi(lc, 0); + *E = OrigSourceInstruction::new(IBM, F, line_number, + eloc, (inter_ti) ilp->indent_level); + } + DISCARD_TEXT(file_as_text) +} + +@h Writing to textual Inter syntax. + += +void OrigSourceInstruction::write(inter_construct *IC, OUTPUT_STREAM, inter_tree_node *P) { + WRITE("origsource "); + Provenance::write(OUT, OrigSourceInstruction::provenance(P)); +} + +@h Access functions. + += +text_provenance OrigSourceInstruction::provenance(inter_tree_node *P) { + if (P == NULL) return Provenance::nowhere(); + if (Inode::isnt(P, ORIGSOURCE_IST)) return Provenance::nowhere(); + return Provenance::at_file_and_line( + Inode::ID_to_text(P, P->W.instruction[PROVENANCEFILE_ORIGSOURCE_IFLD]), + (int) P->W.instruction[PROVENANCELINE_ORIGSOURCE_IFLD]); +} diff --git a/inter/bytecode-module/Chapter 5/The Code Construct.w b/inter/bytecode-module/Chapter 5/The Code Construct.w index 2b832b1b9..3e8c898d3 100644 --- a/inter/bytecode-module/Chapter 5/The Code Construct.w +++ b/inter/bytecode-module/Chapter 5/The Code Construct.w @@ -45,6 +45,7 @@ void CodeInstruction::verify_children(inter_construct *IC, inter_tree_node *P, (C->W.instruction[0] != LABEL_IST) && (C->W.instruction[0] != VAL_IST) && (C->W.instruction[0] != COMMENT_IST) && + (C->W.instruction[0] != ORIGSOURCE_IST) && (C->W.instruction[0] != NOP_IST)) { *E = Inode::error(C, I"only executable matter can be below a code", NULL); return; diff --git a/inter/bytecode-module/Contents.w b/inter/bytecode-module/Contents.w index 3009e0f88..7b9534a14 100644 --- a/inter/bytecode-module/Contents.w +++ b/inter/bytecode-module/Contents.w @@ -42,6 +42,7 @@ Chapter 4: Void Constructs The Insert Construct The Instance Construct The Nop Construct + The OrigSource Construct The Package Construct The PackageType Construct The Permission Construct