Update to Inform v6.42
[inform.git] / src / errors.c
index 73fa1be7430d277998fd9c070b003bc96bf7fabb..c7ec13dc29587d2a5f1ccf5ce4947127573c0076 100644 (file)
@@ -2,9 +2,8 @@
 /*   "errors" : Warnings, errors and fatal errors                            */
 /*              (with error throwback code for RISC OS machines)             */
 /*                                                                           */
-/* Copyright (c) Graham Nelson 1993 - 2020                                   */
-/*                                                                           */
-/* This file is part of Inform.                                              */
+/*   Part of Inform 6.42                                                     */
+/*   copyright (c) Graham Nelson 1993 - 2024                                 */
 /*                                                                           */
 /* Inform is free software: you can redistribute it and/or modify            */
 /* it under the terms of the GNU General Public License as published by      */
@@ -32,6 +31,8 @@ static char error_message_buff[ERROR_BUFLEN+4]; /* room for ellipsis */
 
 ErrorPosition ErrorReport;             /*  Maintained by "lexer.c"           */
 
+static char other_pos_buff[ERROR_BUFLEN+1];       /* Used by location_text() */
+
 static void print_preamble(void)
 {
     /*  Only really prints the preamble to an error or warning message:
@@ -55,6 +56,7 @@ static void print_preamble(void)
 
             if (!(ErrorReport.main_flag)) printf("\"%s\", ", p);
             printf("line %d: ", ErrorReport.line_number);
+            
             if (ErrorReport.orig_file) {
                 char *op;
                 if (ErrorReport.orig_file <= 0 || ErrorReport.orig_file > total_files)
@@ -80,16 +82,103 @@ static void print_preamble(void)
             }
             printf("%s", p);
             if (with_extension_flag) printf("%s", Source_Extension);
-            printf("(%d): ", ErrorReport.line_number);
+            printf("(%d)", ErrorReport.line_number);
+            
+            if (ErrorReport.orig_file) {
+                char *op;
+                if (ErrorReport.orig_file <= 0 || ErrorReport.orig_file > total_files)
+                    op = ErrorReport.orig_source;
+                else
+                    op = InputFiles[ErrorReport.orig_file-1].filename;
+                printf("|%s", op);
+                if (ErrorReport.orig_line) {
+                    printf("(%d", ErrorReport.orig_line);
+                    if (ErrorReport.orig_char) {
+                        printf(":%d", ErrorReport.orig_char);
+                    }
+                    printf(")");
+                }
+            }
+            
+            printf(": ");
             break;
 
         case 2:  /* Macintosh Programmer's Workshop error message format */
 
-            printf("File \"%s\"; Line %d\t# ", p, ErrorReport.line_number);
+            printf("File \"%s\"; Line %d", p, ErrorReport.line_number);
+            
+            if (ErrorReport.orig_file) {
+                char *op;
+                if (ErrorReport.orig_file <= 0 || ErrorReport.orig_file > total_files)
+                    op = ErrorReport.orig_source;
+                else
+                    op = InputFiles[ErrorReport.orig_file-1].filename;
+                printf(": (\"%s\"", op);
+                if (ErrorReport.orig_line) {
+                    printf("; Line %d", ErrorReport.orig_line);
+                    if (ErrorReport.orig_char) {
+                        printf("; Char %d", ErrorReport.orig_char);
+                    }
+                }
+                printf(")");
+            }
+
+            printf("\t# ");
             break;
     }
 }
 
+static char *location_text(brief_location report_line)
+{
+    int j;
+    char *p;
+    int len;
+
+    /* Convert the location to a brief string. 
+       (Some error messages need to report a secondary location.)
+       This uses the static buffer other_pos_buff. */
+    
+    ErrorPosition errpos;
+    errpos.file_number = -1;
+    errpos.source = NULL;
+    errpos.line_number = 0;
+    errpos.main_flag = 0;
+    errpos.orig_source = NULL;
+    export_brief_location(report_line, &errpos);
+    
+    j = errpos.file_number;
+    if (j <= 0 || j > total_files) p = errpos.source;
+    else p = InputFiles[j-1].filename;
+    
+    if (!p && errpos.line_number == 0) {
+        /* Special case */
+        strcpy(other_pos_buff, "compiler setup");
+        return other_pos_buff;
+    }
+    
+    if (!p) p = "";
+
+    len = 0;
+    
+    if (!(errpos.main_flag)) {
+        snprintf(other_pos_buff+len, ERROR_BUFLEN-len,
+                 "\"%s\", ", p);
+        len = strlen(other_pos_buff);
+    }
+    snprintf(other_pos_buff+len, ERROR_BUFLEN-len,
+             "line %d", errpos.line_number);
+
+    return other_pos_buff;
+}
+
+char *current_location_text(void)
+{
+    /* Convert the current lexer location to a brief string.
+       (Called by some trace messages.)
+       This uses the static buffer other_pos_buff. */
+    return location_text(get_brief_location(&ErrorReport));
+}
+
 static void ellipsize_error_message_buff(void)
 {
     /* If the error buffer was actually filled up by a message, it was
@@ -116,23 +205,30 @@ extern void fatalerror(char *s)
 #endif
 #ifdef MAC_FACE
     close_all_source();
-    if (temporary_files_switch) remove_temp_files();
     abort_transcript_file();
     free_arrays();
-    if (store_the_text)
-        my_free(&all_text,"transcription text");
     longjmp(g_fallback, 1);
 #endif
     exit(1);
 }
 
+extern void fatalerror_fmt(const char *format, ...)
+{
+    va_list argument_pointer;
+    va_start(argument_pointer, format);
+    vsnprintf(error_message_buff, ERROR_BUFLEN, format, argument_pointer);
+    va_end(argument_pointer);
+    ellipsize_error_message_buff();
+    fatalerror(error_message_buff);
+}
+
 extern void fatalerror_named(char *m, char *fn)
 {   snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\"", m, fn);
     ellipsize_error_message_buff();
     fatalerror(error_message_buff);
 }
 
-extern void memory_out_error(int32 size, int32 howmany, char *name)
+extern void fatalerror_memory_out(int32 size, int32 howmany, char *name)
 {   if (howmany == 1)
         snprintf(error_message_buff, ERROR_BUFLEN,
             "Run out of memory allocating %d bytes for %s", size, name);
@@ -144,58 +240,41 @@ extern void memory_out_error(int32 size, int32 howmany, char *name)
     fatalerror(error_message_buff);
 }
 
-extern void memoryerror(char *s, int32 size)
-{
-    snprintf(error_message_buff, ERROR_BUFLEN,
-        "The memory setting %s (which is %ld at present) has been \
-exceeded.  Try running Inform again with $%s=<some-larger-number> on the \
-command line.",s,(long int) size,s);
-    ellipsize_error_message_buff();
-    fatalerror(error_message_buff);
-}
-
 /* ------------------------------------------------------------------------- */
 /*   Survivable diagnostics:                                                 */
 /*      compilation errors   style 1                                         */
 /*      warnings             style 2                                         */
-/*      linkage errors       style 3                                         */
+/*      linkage errors       style 3 (no longer used)                        */
 /*      compiler errors      style 4 (these should never happen and          */
 /*                                    indicate a bug in Inform)              */
 /* ------------------------------------------------------------------------- */
 
-static int errors[MAX_ERRORS];
-
-int no_errors, no_warnings, no_suppressed_warnings, no_link_errors,
-    no_compiler_errors;
+int no_errors, no_warnings, no_suppressed_warnings, no_compiler_errors;
 
 char *forerrors_buff;
 int  forerrors_pointer;
 
 static void message(int style, char *s)
-{   int throw_style = style;
+{
     if (hash_printed_since_newline) printf("\n");
     hash_printed_since_newline = FALSE;
     print_preamble();
     switch(style)
     {   case 1: printf("Error: "); no_errors++; break;
         case 2: printf("Warning: "); no_warnings++; break;
-        case 3: printf("Error:  [linking '%s']  ", current_module_filename);
-                no_link_errors++; no_errors++; throw_style=1; break;
+        case 3: printf("Error:  [linking]  "); no_errors++; break;
         case 4: printf("*** Compiler error: ");
-                no_compiler_errors++; throw_style=1; break;
+                no_compiler_errors++; break;
     }
     printf(" %s\n", s);
 #ifdef ARC_THROWBACK
-    throwback(throw_style, s);
+    throwback(((style <= 2) ? style : 1), s);
 #endif
 #ifdef MAC_FACE
     ProcessEvents (&g_proc);
     if (g_proc != true)
     {   free_arrays();
-        if (store_the_text)
-            my_free(&all_text,"transcription text");
         close_all_source ();
-        if (temporary_files_switch) remove_temp_files();
         abort_transcript_file();
         longjmp (g_fallback, 1);
     }
@@ -214,19 +293,21 @@ static void message(int style, char *s)
 extern void error(char *s)
 {   if (no_errors == MAX_ERRORS)
         fatalerror("Too many errors: giving up");
-    errors[no_errors] = no_syntax_lines;
     message(1,s);
 }
 
-extern void error_named(char *s1, char *s2)
-{   snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
+extern void error_fmt(const char *format, ...)
+{
+    va_list argument_pointer;
+    va_start(argument_pointer, format);
+    vsnprintf(error_message_buff, ERROR_BUFLEN, format, argument_pointer);
+    va_end(argument_pointer);
     ellipsize_error_message_buff();
     error(error_message_buff);
 }
 
-extern void error_numbered(char *s1, int val)
-{
-    snprintf(error_message_buff, ERROR_BUFLEN,"%s %d.",s1,val);
+extern void error_named(char *s1, char *s2)
+{   snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
     ellipsize_error_message_buff();
     error(error_message_buff);
 }
@@ -245,16 +326,41 @@ extern void error_named_at(char *s1, char *s2, brief_location report_line)
     ErrorReport = E; concise_switch = i;
 }
 
-extern void no_such_label(char *lname)
-{   error_named("No such label as",lname);
-}
-
 extern void ebf_error(char *s1, char *s2)
 {   snprintf(error_message_buff, ERROR_BUFLEN, "Expected %s but found %s", s1, s2);
     ellipsize_error_message_buff();
     error(error_message_buff);
 }
 
+extern void ebf_curtoken_error(char *s)
+{
+    /* This is "Expected (s) but found (the current token_text)". We use
+       token_type as a hint for how to display token_text. */
+    
+    if (token_type == DQ_TT) {
+        snprintf(error_message_buff, ERROR_BUFLEN, "Expected %s but found string \"%s\"", s, token_text);
+    }
+    else if (token_type == SQ_TT && strlen(token_text)==1) {
+        snprintf(error_message_buff, ERROR_BUFLEN, "Expected %s but found char '%s'", s, token_text);
+    }
+    else if (token_type == SQ_TT) {
+        snprintf(error_message_buff, ERROR_BUFLEN, "Expected %s but found dict word '%s'", s, token_text);
+    }
+    else {
+        /* Symbols, unquoted strings, and numbers can be printed directly. EOF will have "<end of file>" in token_text. */
+        snprintf(error_message_buff, ERROR_BUFLEN, "Expected %s but found %s", s, token_text);
+    }
+    
+    ellipsize_error_message_buff();
+    error(error_message_buff);
+}
+
+extern void ebf_symbol_error(char *s1, char *name, char *type, brief_location report_line)
+{   snprintf(error_message_buff, ERROR_BUFLEN, "\"%s\" is a name already in use and may not be used as a %s (%s \"%s\" was defined at %s)", name, s1, type, name, location_text(report_line));
+    ellipsize_error_message_buff();
+    error(error_message_buff);
+}
+
 extern void char_error(char *s, int ch)
 {   int32 uni;
 
@@ -308,6 +414,30 @@ extern void unicode_char_error(char *s, int32 uni)
     error(error_message_buff);
 }
 
+extern void error_max_dynamic_strings(int index)
+{
+    if (index >= 96 && !glulx_mode)
+        snprintf(error_message_buff, ERROR_BUFLEN, "Only dynamic strings @(00) to @(95) may be used in Z-code");
+    else if (MAX_DYNAMIC_STRINGS == 0)
+        snprintf(error_message_buff, ERROR_BUFLEN, "Dynamic strings may not be used, because $MAX_DYNAMIC_STRINGS has been set to 0. Increase MAX_DYNAMIC_STRINGS.");
+    else if (MAX_DYNAMIC_STRINGS == 32 && !glulx_mode)
+        snprintf(error_message_buff, ERROR_BUFLEN, "Only dynamic strings @(00) to @(%02d) may be used, because $MAX_DYNAMIC_STRINGS has its default value of %d. Increase MAX_DYNAMIC_STRINGS.", MAX_DYNAMIC_STRINGS-1, MAX_DYNAMIC_STRINGS);
+    else
+        snprintf(error_message_buff, ERROR_BUFLEN, "Only dynamic strings @(00) to @(%02d) may be used, because $MAX_DYNAMIC_STRINGS has been set to %d. Increase MAX_DYNAMIC_STRINGS.", MAX_DYNAMIC_STRINGS-1, MAX_DYNAMIC_STRINGS);
+
+    ellipsize_error_message_buff();
+    error(error_message_buff);
+}
+
+extern void error_max_abbreviations(int index)
+{
+    /* This is only called for Z-code. */
+    if (index >= 96)
+        error("The number of abbreviations has exceeded 96, the limit in Z-code");
+    else
+        error("The number of abbreviations has exceeded MAX_ABBREVS. Increase MAX_ABBREVS.");
+}
+
 /* ------------------------------------------------------------------------- */
 /*   Style 2: Warning message routines                                       */
 /* ------------------------------------------------------------------------- */
@@ -317,9 +447,13 @@ extern void warning(char *s1)
     message(2,s1);
 }
 
-extern void warning_numbered(char *s1, int val)
-{   if (nowarnings_switch) { no_suppressed_warnings++; return; }
-    snprintf(error_message_buff, ERROR_BUFLEN,"%s %d.", s1, val);
+extern void warning_fmt(const char *format, ...)
+{
+    va_list argument_pointer;
+    if (nowarnings_switch) { no_suppressed_warnings++; return; }
+    va_start(argument_pointer, format);
+    vsnprintf(error_message_buff, ERROR_BUFLEN, format, argument_pointer);
+    va_end(argument_pointer);
     ellipsize_error_message_buff();
     message(2,error_message_buff);
 }
@@ -332,6 +466,30 @@ extern void warning_named(char *s1, char *s2)
     message(2,error_message_buff);
 }
 
+extern void warning_at(char *name, brief_location report_line)
+{   int i;
+    ErrorPosition E = ErrorReport;
+    if (nowarnings_switch) { no_suppressed_warnings++; return; }
+    export_brief_location(report_line, &ErrorReport);
+    snprintf(error_message_buff, ERROR_BUFLEN, "%s", name);
+    ellipsize_error_message_buff();
+    i = concise_switch; concise_switch = TRUE;
+    message(2,error_message_buff);
+    concise_switch = i;
+    ErrorReport = E;
+}
+
+extern void symtype_warning(char *context, char *name, char *type, char *wanttype)
+{
+    if (nowarnings_switch) { no_suppressed_warnings++; return; }
+    if (name)
+        snprintf(error_message_buff, ERROR_BUFLEN, "In %s, expected %s but found %s \"%s\"", context, wanttype, type, name);
+    else
+        snprintf(error_message_buff, ERROR_BUFLEN, "In %s, expected %s but found %s", context, wanttype, type);
+    ellipsize_error_message_buff();
+    message(2,error_message_buff);
+}
+
 extern void dbnu_warning(char *type, char *name, brief_location report_line)
 {   int i;
     ErrorPosition E = ErrorReport;
@@ -374,22 +532,6 @@ extern void obsolete_warning(char *s1)
     message(2,error_message_buff);
 }
 
-/* ------------------------------------------------------------------------- */
-/*   Style 3: Link error message routines                                    */
-/* ------------------------------------------------------------------------- */
-
-extern void link_error(char *s)
-{   if (no_errors==MAX_ERRORS) fatalerror("Too many errors: giving up");
-    errors[no_errors] = no_syntax_lines;
-    message(3,s);
-}
-
-extern void link_error_named(char *s1, char *s2)
-{   snprintf(error_message_buff, ERROR_BUFLEN,"%s \"%s\"",s1,s2);
-    ellipsize_error_message_buff();
-    link_error(error_message_buff);
-}
-
 /* ------------------------------------------------------------------------- */
 /*   Style 4: Compiler error message routines                                */
 /* ------------------------------------------------------------------------- */
@@ -397,16 +539,16 @@ extern void link_error_named(char *s1, char *s2)
 extern void print_sorry_message(void)
 {   printf(
 "***********************************************************************\n\
-Compiler errors should never occur if Inform is working properly.\n\
-Check to see if there is a more recent version available, from which\n\
-the problem may have been removed. If not, please report this fault\n\
-and if at all possible, please include your source code, as faults\n\
-such as these are rare and often difficult to reproduce. Sorry.\n\
+* 'Compiler errors' should never occur if Inform is working properly.  *\n\
+* Check to see if there is a more recent version available, from which *\n\
+* the problem may have been removed. If not, please report this fault  *\n\
+* and if at all possible, please include your source code, as faults   *\n\
+* such as these are rare  and often difficult to reproduce. Sorry.     *\n\
 ***********************************************************************\n");
 }
 
 extern int compiler_error(char *s)
-{   if (no_link_errors > 0) return FALSE;
+{
     if (no_errors > 0) return FALSE;
     if (no_compiler_errors==MAX_ERRORS)
         fatalerror("Too many compiler errors: giving up");
@@ -415,7 +557,7 @@ extern int compiler_error(char *s)
 }
 
 extern int compiler_error_named(char *s1, char *s2)
-{   if (no_link_errors > 0) return FALSE;
+{
     if (no_errors > 0) return FALSE;
     snprintf(error_message_buff, ERROR_BUFLEN, "%s \"%s\"",s1,s2);
     ellipsize_error_message_buff();
@@ -493,7 +635,7 @@ extern void errors_begin_pass(void)
 }
 
 extern void errors_allocate_arrays(void)
-{   forerrors_buff = my_malloc(512, "errors buffer");
+{   forerrors_buff = my_malloc(FORERRORS_SIZE, "errors buffer");
 }
 
 extern void errors_free_arrays(void)