From b4b5aeb72fda0b98cb409a3bdaec6ebc5efc3362 Mon Sep 17 00:00:00 2001 From: Daniel Stelzer Date: Wed, 16 Sep 2026 13:32:58 -0500 Subject: [PATCH 1/7] warn on duplicate meta definitions --- src/backend.c | 20 +++++++++++++------- src/frontend.c | 28 ++++++++++++++++++++-------- src/frontend.h | 2 +- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/backend.c b/src/backend.c index d1782ba3..0d22f117 100644 --- a/src/backend.c +++ b/src/backend.c @@ -300,7 +300,7 @@ int main(int argc, char **argv) { need_meta = prg->totallines > 100; - prg->meta_ifid = decode_metadata_str(BI_STORY_IFID, 0, prg, &prg->arena); + prg->meta_ifid = decode_metadata_str(BI_STORY_IFID, 0, prg, &prg->arena, "story ifid"); if(!prg->meta_ifid) { if(!strcmp(format, "zblorb")) { // Mandatory for zblorb, make it an error report(LVL_ERR, 0, "An IFID is mandatory for the blorb output format."); @@ -315,25 +315,25 @@ int main(int argc, char **argv) { prg->meta_ifid = 0; } - prg->meta_author = decode_metadata_str(BI_STORY_AUTHOR, 0, prg, &prg->arena); + prg->meta_author = decode_metadata_str(BI_STORY_AUTHOR, 0, prg, &prg->arena, "story author"); if(!prg->meta_author) { if(need_meta) { report(LVL_WARN, 0, "No author declared."); } prg->meta_author = "Anonymous"; } - prg->meta_title = decode_metadata_str(BI_STORY_TITLE, 0, prg, &prg->arena); + prg->meta_title = decode_metadata_str(BI_STORY_TITLE, 0, prg, &prg->arena, "story title"); if(!prg->meta_title) { if(need_meta) { report(LVL_WARN, 0, "No title declared."); } prg->meta_title = "An Interactive Fiction"; } - prg->meta_noun = decode_metadata_str(BI_STORY_NOUN, 0, prg, &prg->arena); + prg->meta_noun = decode_metadata_str(BI_STORY_NOUN, 0, prg, &prg->arena, "story noun"); if(!prg->meta_noun) { prg->meta_noun = "An Interactive Fiction"; } - prg->meta_blurb = decode_metadata_str(BI_STORY_BLURB, 0, prg, &prg->arena); + prg->meta_blurb = decode_metadata_str(BI_STORY_BLURB, 0, prg, &prg->arena, "story blurb"); predname = find_builtin(prg, BI_STORY_RELEASE); if(predname && (pred = predname->pred)->nclause) { @@ -342,8 +342,14 @@ int main(int argc, char **argv) { exit(1); } prg->meta_release = pred->clauses[0]->params[0]->value; - } else if(need_meta) { - report(LVL_WARN, 0, "No release number declared."); + if(pred->nclause > 1) { + report(LVL_WARN, pred->clauses[0]->line, "%d separate definitions found for (story release $). Only the first (at this line) will be used.", pred->nclause); + } + } else { + if(need_meta) { + report(LVL_WARN, 0, "No release number declared."); + } + prg->meta_release = 1; } if(serial_overridden) { diff --git a/src/frontend.c b/src/frontend.c index 1e2a7e90..c3b3a0fe 100644 --- a/src/frontend.c +++ b/src/frontend.c @@ -2399,26 +2399,38 @@ static void assign_select_statements(struct program *prg) { selectforms = 0; } -char *decode_metadata_str(int builtin, struct word *param, struct program *prg, struct arena *arena) { +char *decode_metadata_str(int builtin, struct word *param, struct program *prg, struct arena *arena, const char *report_as) { struct predname *predname; struct predicate *pred; - char *buf; + char *buf = 0; int i; + int nfound = 0; + line_t whichline = 0; predname = find_builtin(prg, builtin); pred = predname->pred; for(i = 0; i < pred->nclause; i++) { if(!param || (pred->clauses[i]->params[0]->kind == AN_DICTWORD && pred->clauses[i]->params[0]->word == param)) { - if(decode_output(&buf, pred->clauses[i]->body, 0, 0, arena, "Story metadata")) { - return buf; - } else { - return 0; + if(!nfound) { // First one found + if(!decode_output(&buf, pred->clauses[i]->body, 0, 0, arena, "Story metadata")) { + buf = 0; // Failed to decode into buf + } + whichline = pred->clauses[i]->line; } + nfound ++; } } - return 0; + if(nfound > 1) { + if(param) { + report(LVL_WARN, whichline, "%d separate definitions found for (%s @%s). Only the first (at this line) will be used.", nfound, report_as, param->name); + } else { + report(LVL_WARN, whichline, "%d separate definitions found for (%s). Only the first (at this line) will be used.", nfound, report_as); + } + } + + return buf; } int frontend(struct program *prg, int nfile, char **fname, dictmap_callback_t dictmap_callback) { @@ -2896,7 +2908,7 @@ int frontend(struct program *prg, int nfile, char **fname, dictmap_callback_t di for(i = 0; i < prg->nboxclass; i++) { struct boxclass *bc = &prg->boxclasses[i]; - char *css = decode_metadata_str(BI_STYLEDEF, bc->class, prg, &lexer.temp_arena); + char *css = decode_metadata_str(BI_STYLEDEF, bc->class, prg, &lexer.temp_arena, "style class"); char *param, *str; struct boxclassline *bcl, **bclptr; diff --git a/src/frontend.h b/src/frontend.h index 3843a824..8ca2ff45 100644 --- a/src/frontend.h +++ b/src/frontend.h @@ -16,7 +16,7 @@ int body_succeeds(struct astnode *an); int body_might_stop(struct astnode *an); int body_succeeds_at_most_once(struct astnode *an); void frontend_add_builtins(struct program *prg); -char *decode_metadata_str(int builtin, struct word *param, struct program *prg, struct arena *arena); +char *decode_metadata_str(int builtin, struct word *param, struct program *prg, struct arena *arena, const char *report_as); int frontend(struct program *prg, int nfile, char **fname, dictmap_callback_t dictmap_callback); int frontend_inject_query(struct program *prg, struct predname *predname, struct predname *tailpred, struct word *prompt, const uint8_t *str); From 94fccc0cbb860584b722f30d58d022205edb4dfe Mon Sep 17 00:00:00 2001 From: Daniel Stelzer Date: Wed, 16 Sep 2026 13:33:13 -0500 Subject: [PATCH 2/7] update stdlib to not produce warnings --- stdlib.dg | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/stdlib.dg b/stdlib.dg index 8250ee02..8cb532c0 100644 --- a/stdlib.dg +++ b/stdlib.dg @@ -5117,11 +5117,11 @@ (banner) (par) (div @title) (story title or default) - (story noun) by (story author or default). + (story noun or default) by (story author or default). (line) (additional banner text) (line) - (story release $RelNum) + (story release or default $RelNum) Release $RelNum. Serial number (serial number). (line) @@ -5148,18 +5148,19 @@ (story author or default) (story author) (story author or default) Anonymous +(story noun or default) (story noun) +(story noun or default) An interactive fiction + +(story release or default $N) (story release $N) +(story release or default 1) + %% Don't warn about querying these; however, this does not disable the warning %% about them not being defined (for a sufficiently large story): (story title) (fail) (story author) (fail) - -%% We can safely supply defaults for the following: - -(story release 1) - -(story noun) - An interactive fiction +(story noun) (fail) +(story release $) (fail) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Game over From 4d0463afbd2c97aab65bb4a2a3de34c96c9ed8c3 Mon Sep 17 00:00:00 2001 From: Daniel Stelzer Date: Wed, 16 Sep 2026 13:33:25 -0500 Subject: [PATCH 3/7] update test cases to match --- test/impossible/ImpossibleStairs.dg | 5 +++-- test/simple/warnings/ifid.gold | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/test/impossible/ImpossibleStairs.dg b/test/impossible/ImpossibleStairs.dg index 9e97de62..0feacf0d 100644 --- a/test/impossible/ImpossibleStairs.dg +++ b/test/impossible/ImpossibleStairs.dg @@ -189,8 +189,9 @@ %%===================================================Status Lines=================================================== -(style class @status) - height: 1em; +%% CHANGED DMS - Dialog now warns about duplicate definitions, and this one is unnecessary (stdlib contains exactly the same thing) +%% (style class @status) +%% height: 1em; (style class @timename) height: 1em; diff --git a/test/simple/warnings/ifid.gold b/test/simple/warnings/ifid.gold index ecb71b45..d1463fad 100644 --- a/test/simple/warnings/ifid.gold +++ b/test/simple/warnings/ifid.gold @@ -4,3 +4,4 @@ Warning: (story ifid) XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX Warning: Or get one at . Warning: No author declared. Warning: No title declared. +Warning: No release number declared. From be7611a5972547a3632004bdba69046a97d327a8 Mon Sep 17 00:00:00 2001 From: Daniel Stelzer Date: Wed, 16 Sep 2026 13:39:11 -0500 Subject: [PATCH 4/7] readme --- readme.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/readme.txt b/readme.txt index d0608888..66faf392 100644 --- a/readme.txt +++ b/readme.txt @@ -50,12 +50,15 @@ Release notes: 1c/04, Lib 1.2.4: + Compiler: multiple definitions for the same style class or + metadata predicate now produce a warning. + Compiler: improved dictionary word matching accuracy. - Compiler: Improved ordering of strings in WRIT chunk, which + Compiler: improved ordering of strings in WRIT chunk, which improves performance on slow platforms like 6502. - 1c/03, Lib 1.2.4: + 1c/03, Lib 1.2.3: Language: CSS text-decoration: reverse has been replaced with -iftf-reverse-video: reverse for compatibility reasons. From c6189654fcbaad2e7bc5ccf04c26b0fbe63985f6 Mon Sep 17 00:00:00 2001 From: Daniel Stelzer Date: Wed, 16 Sep 2026 13:44:51 -0500 Subject: [PATCH 5/7] bump library version --- stdlib.dg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib.dg b/stdlib.dg index 8cb532c0..faeb139d 100644 --- a/stdlib.dg +++ b/stdlib.dg @@ -1,5 +1,5 @@ -(library version) Library version 1.2.3. +(library version) Library version 1.2.4. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Global variables From 92a5d295e7e0aae069abaa8b582f8bad4e820cc9 Mon Sep 17 00:00:00 2001 From: Daniel Stelzer Date: Thu, 17 Sep 2026 11:32:56 -0500 Subject: [PATCH 6/7] disable warnings for meta predicates; keep them only for style classes --- src/frontend.c | 3 ++- stdlib.dg | 13 +++++++------ test/simple/warnings/ifid.gold | 1 - 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/frontend.c b/src/frontend.c index c3b3a0fe..75a3ebef 100644 --- a/src/frontend.c +++ b/src/frontend.c @@ -2426,7 +2426,8 @@ char *decode_metadata_str(int builtin, struct word *param, struct program *prg, if(param) { report(LVL_WARN, whichline, "%d separate definitions found for (%s @%s). Only the first (at this line) will be used.", nfound, report_as, param->name); } else { - report(LVL_WARN, whichline, "%d separate definitions found for (%s). Only the first (at this line) will be used.", nfound, report_as); + // Disabling the warnings for meta predicates, which can usefully have defaults given in the library. Now they will only exist for style classes. + // report(LVL_WARN, whichline, "%d separate definitions found for (%s). Only the first (at this line) will be used.", nfound, report_as); } } diff --git a/stdlib.dg b/stdlib.dg index faeb139d..d4add1c3 100644 --- a/stdlib.dg +++ b/stdlib.dg @@ -5117,11 +5117,11 @@ (banner) (par) (div @title) (story title or default) - (story noun or default) by (story author or default). + (story noun) by (story author or default). (line) (additional banner text) (line) - (story release or default $RelNum) + (story release $RelNum) Release $RelNum. Serial number (serial number). (line) @@ -5148,11 +5148,12 @@ (story author or default) (story author) (story author or default) Anonymous -(story noun or default) (story noun) -(story noun or default) An interactive fiction +%% We can safely supply defaults for the following: -(story release or default $N) (story release $N) -(story release or default 1) +(story release 1) + +(story noun) + An interactive fiction %% Don't warn about querying these; however, this does not disable the warning %% about them not being defined (for a sufficiently large story): diff --git a/test/simple/warnings/ifid.gold b/test/simple/warnings/ifid.gold index d1463fad..ecb71b45 100644 --- a/test/simple/warnings/ifid.gold +++ b/test/simple/warnings/ifid.gold @@ -4,4 +4,3 @@ Warning: (story ifid) XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX Warning: Or get one at . Warning: No author declared. Warning: No title declared. -Warning: No release number declared. From e333a3b64d8ff44206a90c93c2f8ab5201a3d211 Mon Sep 17 00:00:00 2001 From: Daniel Stelzer Date: Thu, 17 Sep 2026 11:46:41 -0500 Subject: [PATCH 7/7] don't warn about multiple definitions in library files --- src/backend.c | 10 +++++----- src/frontend.c | 12 ++++++++---- src/frontend.h | 2 +- test/impossible/ImpossibleStairs.dg | 5 ++--- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/backend.c b/src/backend.c index 0d22f117..5de64227 100644 --- a/src/backend.c +++ b/src/backend.c @@ -300,7 +300,7 @@ int main(int argc, char **argv) { need_meta = prg->totallines > 100; - prg->meta_ifid = decode_metadata_str(BI_STORY_IFID, 0, prg, &prg->arena, "story ifid"); + prg->meta_ifid = decode_metadata_str(BI_STORY_IFID, 0, prg, &prg->arena, "story ifid", -1); if(!prg->meta_ifid) { if(!strcmp(format, "zblorb")) { // Mandatory for zblorb, make it an error report(LVL_ERR, 0, "An IFID is mandatory for the blorb output format."); @@ -315,25 +315,25 @@ int main(int argc, char **argv) { prg->meta_ifid = 0; } - prg->meta_author = decode_metadata_str(BI_STORY_AUTHOR, 0, prg, &prg->arena, "story author"); + prg->meta_author = decode_metadata_str(BI_STORY_AUTHOR, 0, prg, &prg->arena, "story author", -1); if(!prg->meta_author) { if(need_meta) { report(LVL_WARN, 0, "No author declared."); } prg->meta_author = "Anonymous"; } - prg->meta_title = decode_metadata_str(BI_STORY_TITLE, 0, prg, &prg->arena, "story title"); + prg->meta_title = decode_metadata_str(BI_STORY_TITLE, 0, prg, &prg->arena, "story title", -1); if(!prg->meta_title) { if(need_meta) { report(LVL_WARN, 0, "No title declared."); } prg->meta_title = "An Interactive Fiction"; } - prg->meta_noun = decode_metadata_str(BI_STORY_NOUN, 0, prg, &prg->arena, "story noun"); + prg->meta_noun = decode_metadata_str(BI_STORY_NOUN, 0, prg, &prg->arena, "story noun", -1); if(!prg->meta_noun) { prg->meta_noun = "An Interactive Fiction"; } - prg->meta_blurb = decode_metadata_str(BI_STORY_BLURB, 0, prg, &prg->arena, "story blurb"); + prg->meta_blurb = decode_metadata_str(BI_STORY_BLURB, 0, prg, &prg->arena, "story blurb", -1); predname = find_builtin(prg, BI_STORY_RELEASE); if(predname && (pred = predname->pred)->nclause) { diff --git a/src/frontend.c b/src/frontend.c index 75a3ebef..c19830f7 100644 --- a/src/frontend.c +++ b/src/frontend.c @@ -2399,12 +2399,13 @@ static void assign_select_statements(struct program *prg) { selectforms = 0; } -char *decode_metadata_str(int builtin, struct word *param, struct program *prg, struct arena *arena, const char *report_as) { +char *decode_metadata_str(int builtin, struct word *param, struct program *prg, struct arena *arena, const char *report_as, int lib_file) { struct predname *predname; struct predicate *pred; char *buf = 0; int i; int nfound = 0; + int nlib = 0; line_t whichline = 0; predname = find_builtin(prg, builtin); @@ -2419,12 +2420,15 @@ char *decode_metadata_str(int builtin, struct word *param, struct program *prg, whichline = pred->clauses[i]->line; } nfound ++; + if(FILENUMPART(pred->clauses[i]->line) == lib_file) { // This one was in a library file + nlib ++; + } } } - if(nfound > 1) { + if(nfound - nlib > 1) { if(param) { - report(LVL_WARN, whichline, "%d separate definitions found for (%s @%s). Only the first (at this line) will be used.", nfound, report_as, param->name); + report(LVL_WARN, whichline, "%d separate definitions found for (%s @%s) outside of the library. Only the first (at this line) will be used.", nfound, report_as, param->name); } else { // Disabling the warnings for meta predicates, which can usefully have defaults given in the library. Now they will only exist for style classes. // report(LVL_WARN, whichline, "%d separate definitions found for (%s). Only the first (at this line) will be used.", nfound, report_as); @@ -2909,7 +2913,7 @@ int frontend(struct program *prg, int nfile, char **fname, dictmap_callback_t di for(i = 0; i < prg->nboxclass; i++) { struct boxclass *bc = &prg->boxclasses[i]; - char *css = decode_metadata_str(BI_STYLEDEF, bc->class, prg, &lexer.temp_arena, "style class"); + char *css = decode_metadata_str(BI_STYLEDEF, bc->class, prg, &lexer.temp_arena, "style class", lexer.lib_file); char *param, *str; struct boxclassline *bcl, **bclptr; diff --git a/src/frontend.h b/src/frontend.h index 8ca2ff45..90dd23e4 100644 --- a/src/frontend.h +++ b/src/frontend.h @@ -16,7 +16,7 @@ int body_succeeds(struct astnode *an); int body_might_stop(struct astnode *an); int body_succeeds_at_most_once(struct astnode *an); void frontend_add_builtins(struct program *prg); -char *decode_metadata_str(int builtin, struct word *param, struct program *prg, struct arena *arena, const char *report_as); +char *decode_metadata_str(int builtin, struct word *param, struct program *prg, struct arena *arena, const char *report_as, int lib_file); int frontend(struct program *prg, int nfile, char **fname, dictmap_callback_t dictmap_callback); int frontend_inject_query(struct program *prg, struct predname *predname, struct predname *tailpred, struct word *prompt, const uint8_t *str); diff --git a/test/impossible/ImpossibleStairs.dg b/test/impossible/ImpossibleStairs.dg index 0feacf0d..9e97de62 100644 --- a/test/impossible/ImpossibleStairs.dg +++ b/test/impossible/ImpossibleStairs.dg @@ -189,9 +189,8 @@ %%===================================================Status Lines=================================================== -%% CHANGED DMS - Dialog now warns about duplicate definitions, and this one is unnecessary (stdlib contains exactly the same thing) -%% (style class @status) -%% height: 1em; +(style class @status) + height: 1em; (style class @timename) height: 1em;