1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-06-30 22:14:58 +03:00

Merge pull request #97 from erkyrath/origsource

Origsource directive
This commit is contained in:
Graham Nelson 2023-06-05 09:32:33 +01:00 committed by GitHub
commit 8e4b0d14c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
35 changed files with 330 additions and 28 deletions

View file

@ -1,16 +1,17 @@
Inform 7 v10.2.0 has started.
I've now read your source text, which is 12 words long.
I've also read Basic Inform by Graham Nelson, which is 7792 words long.
I've also read English Language by Graham Nelson, which is 2330 words long.
I've also read Standard Rules by Graham Nelson, which is 34311 words long.
I've also read version 1 of Basic Inform by Graham Nelson, which is 7888 words long.
I've also read version 1 of English Language by Graham Nelson, which is 2330 words long.
I've also read version 6 of Standard Rules by Graham Nelson, which is 34398 words long.
Problem__ PM_I6SyntaxError
>--> Inform 6 syntax error near here (source text, line 24): this is not an
Inform 6 directive.
Problem__ PM_I6SyntaxError
>--> Inform 6 syntax error near here (source text, line 25): this Inform 6
directive is not supported in kits or '(-' inclusions: 'Link;' (only
#Ifdef, #Ifndef, #Iftrue, #Ifnot, #Endif, #Stub, Constant, Global, Array,
Attribute, Property, Verb, Fake_action, Object, Default are supported).
#Ifdef, #Ifndef, #Iftrue, #Ifnot, #Endif, #OrigSource, #Stub, Constant,
Global, Array, Attribute, Property, Verb, Fake_action, Object, Default are
supported).
Problem__ PM_I6SyntaxError
>--> Inform 6 syntax error near here (source text, line 36): in a +namespace
annotation, the 'access' must be 'private' or 'public', not 'whimsical'.

View file

@ -46,7 +46,12 @@ always hangs from a single top-level |CODE_BLOCK_NT|.
=
void CompileBlocksAndLines::full_definition_body(int statement_count, parse_node *body,
int allow_implied_newlines) {
CompileBlocksAndLines::code_block(statement_count, body, TRUE, allow_implied_newlines);
text_provenance last_loc = Provenance::nowhere();
CompileBlocksAndLines::code_block(statement_count, body, TRUE, allow_implied_newlines, &last_loc);
if (Provenance::is_somewhere(last_loc)) {
last_loc = Provenance::nowhere();
EmitCode::origsource(&last_loc);
}
}
@ See //words: Nonterminals// for an explanation of what it means for a nonterminal
@ -57,7 +62,7 @@ most "likely" interpretation.
=
int CompileBlocksAndLines::code_block(int statement_count, parse_node *block, int top_level,
int allow_implied_newlines) {
int allow_implied_newlines, text_provenance *last_loc) {
if (block) {
if (Node::get_type(block) != CODE_BLOCK_NT) internal_error("not a code block");
int saved_mult = <s-value-uncached>->multiplicitous;
@ -68,7 +73,7 @@ int CompileBlocksAndLines::code_block(int statement_count, parse_node *block, in
for (parse_node *p = block->down; p; p = p->next)
statement_count =
CompileBlocksAndLines::code_line(statement_count, p, singleton,
allow_implied_newlines);
allow_implied_newlines, last_loc);
<s-value-uncached>->multiplicitous = saved_mult;
}
return statement_count;
@ -97,7 +102,7 @@ So, then, this is called on each child node of a |CODE_BLOCK_NT| in turn:
=
int CompileBlocksAndLines::code_line(int statement_count, parse_node *p, int as_singleton,
int allow_implied_newlines) {
int allow_implied_newlines, text_provenance *last_loc) {
compiling_single_line_block = as_singleton;
control_structure_phrase *csp = Node::get_control_structure_used(p);
parse_node *to_compile = p;
@ -107,6 +112,7 @@ int CompileBlocksAndLines::code_line(int statement_count, parse_node *p, int as_
}
statement_count++;
@<Compile a comment about this line@>;
@<Compile a location reference for this line@>;
int L = EmitCode::level();
@<Compile the head@>;
@<Compile the midriff@>;
@ -125,6 +131,19 @@ int CompileBlocksAndLines::code_line(int statement_count, parse_node *p, int as_
DISCARD_TEXT(C)
}
@<Compile a location reference for this line@> =
source_location sl = Wordings::location(Node::get_text(to_compile));
if (sl.file_of_origin) {
TEMPORARY_TEXT(fname);
WRITE_TO(fname, "%f", sl.file_of_origin->name);
text_provenance loc = Provenance::at_file_and_line(fname, sl.line_number);
DISCARD_TEXT(fname);
if (Str::ne(loc.textual_filename, last_loc->textual_filename) || loc.line_number != last_loc->line_number) {
*last_loc = loc;
EmitCode::origsource(last_loc);
}
}
@h Head code for lines.
We divide the work of compiling the line into "head" code, "midriff" code
and then "tail" code. For the head, there's usually nothing to do, except
@ -260,14 +279,14 @@ is false:
EmitCode::down();
CodeBlocks::open_code_block();
statement_count = CompileBlocksAndLines::code_block(statement_count,
p->down->next, FALSE, allow_implied_newlines);
p->down->next, FALSE, allow_implied_newlines, last_loc);
if (p->down->next->next) {
EmitCode::up();
EmitCode::code();
EmitCode::down();
CodeBlocks::divide_code_block();
statement_count = CompileBlocksAndLines::code_block(statement_count,
p->down->next->next, FALSE, allow_implied_newlines);
p->down->next->next, FALSE, allow_implied_newlines, last_loc);
}
CodeBlocks::close_code_block();
EmitCode::up();
@ -417,7 +436,7 @@ of |downs| is how many times we have called |Produce::down|.
EmitCode::code();
EmitCode::down();
statement_count = CompileBlocksAndLines::code_block(statement_count,
ow_node, FALSE, allow_implied_newlines);
ow_node, FALSE, allow_implied_newlines, last_loc);
if (final_flag == FALSE) {
EmitCode::up();
EmitCode::code();
@ -429,7 +448,7 @@ of |downs| is how many times we have called |Produce::down|.
@<Handle a pointery default@> =
statement_count = CompileBlocksAndLines::code_block(statement_count, ow_node,
FALSE, allow_implied_newlines);
FALSE, allow_implied_newlines, last_loc);
@<End a pointery switch@> =
while (downs-- > 0) EmitCode::up();
@ -452,7 +471,7 @@ of |downs| is how many times we have called |Produce::down|.
EmitCode::code();
EmitCode::down();
statement_count = CompileBlocksAndLines::code_block(statement_count,
ow_node, FALSE, allow_implied_newlines);
ow_node, FALSE, allow_implied_newlines, last_loc);
EmitCode::up();
EmitCode::up();
@ -462,7 +481,7 @@ of |downs| is how many times we have called |Produce::down|.
EmitCode::code();
EmitCode::down();
statement_count = CompileBlocksAndLines::code_block(statement_count,
ow_node, FALSE, allow_implied_newlines);
ow_node, FALSE, allow_implied_newlines, last_loc);
EmitCode::up();
EmitCode::up();
@ -522,7 +541,7 @@ inline definitions for "say if" and similar.
@<Compile a say tail@> =
statement_count = CompileBlocksAndLines::code_block(statement_count, p,
FALSE, allow_implied_newlines);
FALSE, allow_implied_newlines, last_loc);
TEMPORARY_TEXT(SAYL)
WRITE_TO(SAYL, ".");
@ -546,7 +565,7 @@ inline definitions for "say if" and similar.
@<Compile a loop tail@> =
CodeBlocks::open_code_block();
statement_count = CompileBlocksAndLines::code_block(statement_count, p->down->next,
FALSE, allow_implied_newlines);
FALSE, allow_implied_newlines, last_loc);
while (EmitCode::level() > L) EmitCode::up();
CodeBlocks::close_code_block();

View file

@ -70,6 +70,14 @@ void EmitCode::comment(text_stream *text) {
(inter_ti) EmitCode::level()));
}
@h OrigSource directives.
=
void EmitCode::origsource(text_provenance *from) {
Produce::guard(OrigSourceInstruction::new_from_provenance(EmitCode::at(), *from,
(inter_ti) EmitCode::level(), NULL));
}
@h In value context.
These functions all generate a |val| opcode:

View file

@ -30,17 +30,21 @@ package main _plain
package Falsity_fn _function
package Falsity _code
code
origsource "inter/Tests/General/Assim.intert" 10
inv !return
val 0
origsource
package Demo_fn _function
package Demo _code
local x
local y
code
origsource "inter/Tests/General/Assim.intert" 11
inv !return
inv !plus
val x
val y
origsource
package arrays _submodule
package XA_arr _plain
constant (list of unchecked) XA = { 2, 4, 56 } __assimilated
@ -65,13 +69,17 @@ package main _plain
local x1
local x2
code
origsource "inter/Tests/General/Assim.intert" 23
inv !return
val 0
origsource
package Peach_fn _function
package Peach _code
code
origsource "inter/Tests/General/Assim.intert" 24
inv !return
val 0
origsource
package marmorial_prop _property
constant property_id = 0
property (int2) marmorial __assimilated

View file

@ -11,6 +11,7 @@ Constant Budger = 32738;
Constant Danza = (2 + 34);
Constant Sahara = (Danza + Bidger + 1);
#Ifdef TARGET_ZCODE;
#OrigSource "inter/final-module/Chapter 4/Final Inform 6.w" 155;
Global max_z_object;
#Ifdef Z__Region;
[ OC__Cl obj cla j a n objflag;
@ -75,6 +76,7 @@ Global max_z_object;
rfalse;
];
#Endif;
#OrigSource;
#Endif;
[ DebugAttribute a anames str;
print "<attribute ", a, ">";

View file

@ -22,6 +22,7 @@ Class K_mica
class K_stone
;
#Ifdef TARGET_ZCODE;
#OrigSource "inter/final-module/Chapter 4/Final Inform 6.w" 155;
Global max_z_object;
#Ifdef Z__Region;
[ OC__Cl obj cla j a n objflag;
@ -86,6 +87,7 @@ Global max_z_object;
rfalse;
];
#Endif;
#OrigSource;
#Endif;
[ DebugAttribute a anames str;
print "<attribute ", a, ">";

View file

@ -7,6 +7,7 @@ Global or_tmp_var;
Constant Banana = 2;
Constant Peach = Banana;
#Ifdef TARGET_ZCODE;
#OrigSource "inter/final-module/Chapter 4/Final Inform 6.w" 155;
Global max_z_object;
#Ifdef Z__Region;
[ OC__Cl obj cla j a n objflag;
@ -71,6 +72,7 @@ Global max_z_object;
rfalse;
];
#Endif;
#OrigSource;
#Endif;
[ DebugAttribute a anames str;
print "<attribute ", a, ">";

View file

@ -5,6 +5,7 @@ Constant Grammar__Version 2;
Global debug_flag;
Global or_tmp_var;
#Ifdef TARGET_ZCODE;
#OrigSource "inter/final-module/Chapter 4/Final Inform 6.w" 155;
Global max_z_object;
#Ifdef Z__Region;
[ OC__Cl obj cla j a n objflag;
@ -69,6 +70,7 @@ Global max_z_object;
rfalse;
];
#Endif;
#OrigSource;
#Endif;
[ MyRoutine x y;
return x;

View file

@ -7,6 +7,7 @@ Global or_tmp_var;
Constant I_green = 1;
Constant I_red = 17;
#Ifdef TARGET_ZCODE;
#OrigSource "inter/final-module/Chapter 4/Final Inform 6.w" 155;
Global max_z_object;
#Ifdef Z__Region;
[ OC__Cl obj cla j a n objflag;
@ -71,6 +72,7 @@ Global max_z_object;
rfalse;
];
#Endif;
#OrigSource;
#Endif;
[ DebugAttribute a anames str;
print "<attribute ", a, ">";

View file

@ -5,6 +5,7 @@ Constant Grammar__Version 2;
Global debug_flag;
Global or_tmp_var;
#Ifdef TARGET_ZCODE;
#OrigSource "inter/final-module/Chapter 4/Final Inform 6.w" 155;
Global max_z_object;
#Ifdef Z__Region;
[ OC__Cl obj cla j a n objflag;
@ -69,6 +70,7 @@ Global max_z_object;
rfalse;
];
#Endif;
#OrigSource;
#Endif;
[ Falsity;
return false;];

View file

@ -1,2 +1,2 @@
inter: inter/Tests/Invalid/inversion.intert, line 1: file holds Inter written for specification v0.1.2, but I expect v5.0.0
inter: inter/Tests/Invalid/inversion.intert, line 1: file holds Inter written for specification v0.1.2, but I expect v6.0.0
>--> version 0.1.2

View file

@ -495,13 +495,31 @@ more natural |{ ... }|.
}
if (node->unopened) Produce::set_level_to_current_code_block_plus(I, 0);
@ Note that conditional directives have already been taken care of, and that
other Inform 6 directives are not valid inside function bodies, which is the
only part of I6 syntax covered by schemas. Therefore:
@ Note that conditional directives have already been taken care of. The
only other Inform 6 directive valid inside a function body is OrigSource.
Therefore:
@<Non-conditional directive@> =
I6Errors::issue_at_node(node, I"misplaced directive");
return;
if (node->dir_clarifier == ORIGSOURCE_I6RW) {
@<OrigSource directive@>;
}
else {
I6Errors::issue_at_node(node, I"misplaced directive");
return;
}
@<OrigSource directive@> =
text_stream *origfilename = NULL;
int origlinenum = 0;
if (node->child_node) {
origfilename = node->child_node->expression_tokens->material;
if (node->child_node->expression_tokens->next) {
origlinenum = Str::atoi(node->child_node->expression_tokens->next->material, 0);
}
}
inter_bookmark *IBM = Produce::at(I);
Produce::guard(OrigSourceInstruction::new(IBM, origfilename, (unsigned int)origlinenum, (inter_ti) Produce::level(I), NULL));
@ An |EVAL_ISNT| node can have any number of children, they are sequentially
evaluated for their potential side-effects, but only the last produces a value.

View file

@ -314,6 +314,7 @@ inter_schema_token *InterSchemas::new_token(int type, text_stream *material,
@e IFFALSE_I6RW
@e IFNOT_I6RW
@e ENDIF_I6RW
@e ORIGSOURCE_I6RW
@ The value of |inline_command|, in an |INLINE_ISTT| node, must be one of:
@ -506,6 +507,7 @@ void InterSchemas::log_just(inter_schema_node *isn, int depth) {
case IFFALSE_I6RW: LOG("#iffalse"); break;
case IFNOT_I6RW: LOG("#ifnot"); break;
case ENDIF_I6RW: LOG("#endif"); break;
case ORIGSOURCE_I6RW: LOG("#origsource"); break;
default: LOG("<unknown>"); break;
}
LOG("\n");

View file

@ -778,6 +778,7 @@ but speed is not quite important enough to make it worthwhile.
if (Str::eq_insensitive(T, I"#IFFALSE")) { is = DIRECTIVE_ISTT; which_rw = IFFALSE_I6RW; }
if (Str::eq_insensitive(T, I"#IFNOT")) { is = DIRECTIVE_ISTT; which_rw = IFNOT_I6RW; }
if (Str::eq_insensitive(T, I"#ENDIF")) { is = DIRECTIVE_ISTT; which_rw = ENDIF_I6RW; }
if (Str::eq_insensitive(T, I"#ORIGSOURCE")) { is = DIRECTIVE_ISTT; which_rw = ORIGSOURCE_I6RW; }
if (Str::eq(T, I",")) is = COMMA_ISTT;
if (Str::eq(T, I":")) is = COLON_ISTT;

View file

@ -58,11 +58,13 @@ in Inform kits.
5.0.0 (24 April 2023) added (further) new fields to |SPLAT_IST| instructions, to
record their provenance and so make better error reporting possible.
6.0.0 (25 May 2023) added the |ORIGSOURCE_IST| instruction.
@ Anyway, the implementation, such as it is:
=
semantic_version_number InterVersion::current(void) {
semantic_version_number V = VersionNumbers::from_text(I"5.0.0");
semantic_version_number V = VersionNumbers::from_text(I"6.0.0");
if (VersionNumbers::is_null(V)) internal_error("malformed version number");
return V;
}

View file

@ -302,6 +302,7 @@ These are constructs used for instructions outside function bodies:
@e INSTANCE_IST
@e INSERT_IST
@e NOP_IST
@e ORIGSOURCE_IST
@e PACKAGE_IST
@e PACKAGETYPE_IST
@e PERMISSION_IST
@ -380,6 +381,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();

View file

@ -0,0 +1,124 @@
[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)
If |PROVENANCEFILE| is zero, the instruction means "Following bytecode is not
from any specific source location." The line number is ignored in this case.
=
inter_error_message *OrigSourceInstruction::new(inter_bookmark *IBM,
text_stream *file_name, inter_ti line_number,
inter_ti level, inter_error_location *eloc) {
inter_ti FID = 0;
if (Str::len(file_name) > 0) {
inter_warehouse *warehouse = InterBookmark::warehouse(IBM);
inter_package *pack = InterBookmark::package(IBM);
FID = InterWarehouse::create_text(warehouse, pack);
Str::copy(InterWarehouse::get_text(warehouse, FID), file_name);
}
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;
}
inter_error_message *OrigSourceInstruction::new_from_provenance(inter_bookmark *IBM,
text_provenance prov,
inter_ti level, inter_error_location *eloc) {
return OrigSourceInstruction::new(IBM, prov.textual_filename, (unsigned int)prov.line_number, level, eloc);
}
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) {
if (!P->W.instruction[PROVENANCEFILE_ORIGSOURCE_IFLD]) {
/* (0,anything) is valid */
}
else {
*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) {
text_stream *temp_filename = NULL;
if (Str::len(file_as_text) > 0) temp_filename = 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, temp_filename, line_number,
(inter_ti) ilp->indent_level, eloc);
}
DISCARD_TEXT(file_as_text)
}
@h Writing to textual Inter syntax.
=
void OrigSourceInstruction::write(inter_construct *IC, OUTPUT_STREAM, inter_tree_node *P) {
if (!P->W.instruction[PROVENANCEFILE_ORIGSOURCE_IFLD]) {
WRITE("origsource");
}
else {
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();
if (!P->W.instruction[PROVENANCEFILE_ORIGSOURCE_IFLD])
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]);
}

View file

@ -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;

View file

@ -180,6 +180,7 @@ The other names here are taken from their corresponding I6 directives.
@e IFNOT_PLM
@e ENDIF_PLM
@e IFTRUE_PLM
@e ORIGSOURCE_PLM
@e CONSTANT_PLM
@e ARRAY_PLM
@e GLOBAL_PLM

View file

@ -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

View file

@ -245,6 +245,18 @@ void Generators::evaluate_label(code_generation *gen, text_stream *label_name) {
VOID_METHOD_CALL(gen->generator, EVALUATE_LABEL_MTID, gen, label_name);
}
@ OrigSource directives. These identify the original source location that
generated the current code.
@e PLACE_ORIGSOURCE_MTID
=
VOID_METHOD_TYPE(PLACE_ORIGSOURCE_MTID, code_generator *generator, code_generation *gen,
text_provenance *source_loc)
void Generators::place_origsource(code_generation *gen, text_provenance *source_loc) {
VOID_METHOD_CALL(gen->generator, PLACE_ORIGSOURCE_MTID, gen, source_loc);
}
@ The three ways to invoke (and a doohickey for assembly opcodes):
@e INVOKE_PRIMITIVE_MTID

View file

@ -144,3 +144,12 @@ void VanillaCode::assembly(code_generation *gen, inter_tree_node *P) {
inter_ti which = AssemblyInstruction::which_marker(P);
Generators::assembly_marker(gen, which);
}
@ OrigSource directives are passed through to the generator.
=
void VanillaCode::place_origsource(code_generation *gen, inter_tree_node *P) {
text_provenance prov = OrigSourceInstruction::provenance(P);
Generators::place_origsource(gen, &prov);
}

View file

@ -112,6 +112,7 @@ void Vanilla::node(code_generation *gen, inter_tree_node *P) {
case LOCAL_IST: break;
case NOP_IST: break;
case COMMENT_IST: break;
case ORIGSOURCE_IST: VanillaCode::place_origsource(gen, P); break;
case INVALID_IST: InterErrors::backtrace(DL, P);
internal_error("INVALID node type in Inter tree");

View file

@ -152,6 +152,7 @@ Document for a specification.
segmentation_pos saved = CodeGen::select(gen, functions_I7CGS);
text_stream *OUT = CodeGen::current(gen);
WRITE("#Ifdef TARGET_ZCODE;\n");
WRITE("#OrigSource \"%s\" %d;\n", __FILE__, __LINE__);
WRITE("Global max_z_object;\n");
WRITE("#Ifdef Z__Region;\n");
WRITE("[ OC__Cl obj cla j a n objflag;\n"); INDENT;
@ -216,6 +217,7 @@ Document for a specification.
WRITE("rfalse;\n");
OUTDENT; WRITE("];\n");
WRITE("#Endif;\n");
WRITE("#OrigSource;\n");
WRITE("#Endif;\n");
CodeGen::deselect(gen, saved);

View file

@ -7,6 +7,7 @@ void I6TargetCode::create_generator(code_generator *gtr) {
METHOD_ADD(gtr, DECLARE_FUNCTION_MTID, I6TargetCode::declare_function);
METHOD_ADD(gtr, PLACE_LABEL_MTID, I6TargetCode::place_label);
METHOD_ADD(gtr, EVALUATE_LABEL_MTID, I6TargetCode::evaluate_label);
METHOD_ADD(gtr, PLACE_ORIGSOURCE_MTID, I6TargetCode::place_origsource);
METHOD_ADD(gtr, INVOKE_PRIMITIVE_MTID, I6TargetCode::invoke_primitive);
METHOD_ADD(gtr, INVOKE_FUNCTION_MTID, I6TargetCode::invoke_function);
METHOD_ADD(gtr, INVOKE_OPCODE_MTID, I6TargetCode::invoke_opcode);
@ -176,6 +177,29 @@ void I6TargetCode::evaluate_label(code_generator *gtr, code_generation *gen,
PUT(Str::get(pos));
}
@h Origsource references.
The conversion of filenames to I6 string literals doesn't really account
for special characters. We're leaving it up to the end user to decode all
of I6's confusing escape sequences. But at least we guarantee that the
I6 compiler won't choke on the directive.
=
void I6TargetCode::place_origsource(code_generator *gtr, code_generation *gen,
text_provenance *source_loc) {
text_stream *OUT = CodeGen::current(gen);
if (Provenance::is_somewhere(*source_loc)) {
WRITE("#OrigSource ");
Generators::compile_literal_text(gen, source_loc->textual_filename, TRUE);
if (source_loc->line_number > 0)
WRITE(" %d;\n", source_loc->line_number);
else
WRITE(";\n");
}
else {
WRITE("#OrigSource;\n");
}
}
@h Function invocations.
Or in other words, function calls. These are easy: the syntax is exactly what
it would be for C.

View file

@ -11,7 +11,7 @@ the conditional compilation splats gone, we are left with these:
= (text)
ARRAY_PLM ATTRIBUTE_PLM CONSTANT_PLM DEFAULT_PLM
FAKEACTION_PLM GLOBAL_PLM OBJECT_PLM PROPERTY_PLM
ROUTINE_PLM STUB_PLM VERB_PLM
ROUTINE_PLM STUB_PLM VERB_PLM ORIGSOURCE_PLM
=
And we must turn those into splatless Inter code with the same effect. In some
cases, notably |ROUTINE_PLM| which contains an entire Inform 6-notation
@ -86,6 +86,9 @@ void CompileSplatsStage::visitor1(inter_tree *I, inter_tree_node *P, void *state
case STUB_PLM:
@<Assimilate routine@>;
break;
case ORIGSOURCE_PLM:
@<Assimilate origsource directive@>;
break;
}
}
}
@ -133,6 +136,32 @@ void CompileSplatsStage::visitor3(inter_tree *I, inter_tree_node *P, void *state
}
}
@h How OrigSource definitions are assimilated.
@ Note that the #OrigSource directive (with hash sign) is also valid
within a function body. We will handle that case later; see
//Emitting Inter Schemas//.
This is not yet useful. It converts a top-level #Origsource directive
to a top-level ORIGSOURCE_IST node, but it doesn't put it anywhere
meaningful; the node just winds up tacked onto the end of the kit.
@<Assimilate origsource directive@> =
I6Errors::set_current_location_near_splat(P);
match_results mr = Regexp::create_mr();
text_stream *origfilestr = NULL;
int origline = 0;
int proceed = TRUE;
@<Parse text of splat for optional string and number@>;
if (proceed) {
inter_bookmark content_at = InterBookmark::after_this_node(P);
inter_bookmark *IBM = &content_at;
inter_ti B = (inter_ti) InterBookmark::baseline(IBM) + 1;
Produce::guard(OrigSourceInstruction::new(IBM, origfilestr, (unsigned int)origline, B, NULL));
NodePlacement::remove(P);
}
Regexp::dispose_of(&mr);
@h How definitions are assimilated.
@<Assimilate definition@> =
@ -191,6 +220,28 @@ meaningfully have a value, even though a third token is present.
}
Str::trim_all_white_space_at_end(raw_identifier);
@ The following finds |"STRING" NUMBER|, or |"STRING"|, or nothing.
(In its pocketses.) This is needed for the |OrigSource| directive.
In I6 that directive can accept a second number, but we won't
worry about that here.
@<Parse text of splat for optional string and number@> =
text_stream *S = SplatInstruction::splatter(P);
if (Regexp::match(&mr, S, L" *%C+ \"(%C*)\" (%d+) *; *")) {
origfilestr = mr.exp[0];
origline = Str::atoi(mr.exp[1], 0);
}
else if (Regexp::match(&mr, S, L" *%C+ \"(%C*)\" *; *")) {
origfilestr = mr.exp[0];
}
else if (Regexp::match(&mr, S, L" *%C+ *; *")) {
/* bare "Origsource;" is okay */
}
else {
I6Errors::issue("Unable to parse ORIGSOURCE_PLM: '%S'", S);
proceed = FALSE;
}
@ An eccentricity of Inform 6 syntax is that fake action names ought to be given
in the form |Fake_Action ##Bake|, but are not. The constant created by |Fake_Action Bake|
is nevertheless |##Bake|, so we take care of that here.
@ -229,7 +280,7 @@ But in fact it's easier to handle it here.
@ So if we're here, we have reduced the possibilities to:
= (text)
ARRAY_PLM ATTRIBUTE_PLM CONSTANT_PLM FAKEACTION_PLM
GLOBAL_PLM OBJECT_PLM PROPERTY_PLM VERB_PLM
GLOBAL_PLM OBJECT_PLM PROPERTY_PLM VERB_PLM
=
We basically do the same thing in all of these cases: decide where to put
the result, declare a symbol for it, and then define that symbol.
@ -1436,7 +1487,9 @@ int CompileSplatsStage::function_bodies(pipeline_step *step, compile_splats_stat
IdentifierFinders::next_priority(&finder, scope1);
IdentifierFinders::next_priority(&finder, scope2);
IdentifierFinders::set_namespace(&finder, req->namespace);
Produce::guard(OrigSourceInstruction::new_from_provenance(Produce::at(I), req->provenance, (inter_ti) Produce::level(I), NULL));
EmitInterSchemas::emit(I, &VH, sch, finder, NULL, NULL, NULL);
Produce::guard(OrigSourceInstruction::new(Produce::at(I), NULL, 0, (inter_ti) Produce::level(I), NULL));
CompileSplatsStage::report_kit_errors(sch, req);
Produce::pop_code_position(I);
Produce::set_function(I, NULL);

View file

@ -368,6 +368,7 @@ the directive type as 0.
else if (Str::eq_insensitive(mr.exp[0], I"Iftrue")) I6_dir = IFTRUE_PLM;
else if (Str::eq_insensitive(mr.exp[0], I"Ifnot")) I6_dir = IFNOT_PLM;
else if (Str::eq_insensitive(mr.exp[0], I"Endif")) I6_dir = ENDIF_PLM;
else if (Str::eq_insensitive(mr.exp[0], I"OrigSource")) I6_dir = ORIGSOURCE_PLM;
else if (Str::eq_insensitive(mr.exp[0], I"Stub")) I6_dir = STUB_PLM;
else if (Str::eq_insensitive(mr.exp[0], I"Constant")) I6_dir = CONSTANT_PLM;
else if (Str::eq_insensitive(mr.exp[0], I"Global")) I6_dir = GLOBAL_PLM;
@ -397,7 +398,7 @@ the directive type as 0.
else if (Str::eq_insensitive(mr.exp[0], I"Import")) known = TRUE;
else if (Str::eq_insensitive(mr.exp[0], I"Link")) known = TRUE;
else if (Str::eq_insensitive(mr.exp[0], I"Lowstring")) known = TRUE;
else if (Str::eq_insensitive(mr.exp[0], I"Origsource")) known = TRUE;
else if (Str::eq_insensitive(mr.exp[0], I"Message")) known = TRUE;
else if (Str::eq_insensitive(mr.exp[0], I"Replace")) known = TRUE;
else if (Str::eq_insensitive(mr.exp[0], I"Switches")) known = TRUE;
else if (Str::eq_insensitive(mr.exp[0], I"Trace")) known = TRUE;
@ -406,7 +407,7 @@ the directive type as 0.
if (known)
I6Errors::issue(
"this Inform 6 directive is not supported in kits or '(-' inclusions: '%S' "
"(only #Ifdef, #Ifndef, #Iftrue, #Ifnot, #Endif, #Stub, Constant, Global, "
"(only #Ifdef, #Ifndef, #Iftrue, #Ifnot, #Endif, #OrigSource, #Stub, Constant, Global, "
"Array, Attribute, Property, Verb, Fake_action, Object, Default are "
"supported)", R);
else