]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR modula2/122485: add spell checking to module names
authorGaius Mulley <gaiusmod2@gmail.com>
Thu, 30 Oct 2025 11:19:08 +0000 (11:19 +0000)
committerGaius Mulley <gaiusmod2@gmail.com>
Thu, 30 Oct 2025 11:19:08 +0000 (11:19 +0000)
This patch introduces spell checking during module imports.
If the correct module name has been seen prior to the incorrect import
then it will attempt to provide a hint during the error message.

gcc/m2/ChangeLog:

PR modula2/122485
* gm2-compiler/M2Comp.mod (Pass0CheckDef): Add spell check
format specifier filtering on module names.
* gm2-compiler/M2MetaError.mod (errorBlock): New field
filterDef.
(initErrorBlock): Initialize filterDef.
(continuation): Add 'D' filter on definition module specifier.
(SpellHint): Rewrite to check for filterDef and defimp symbols.
(FilterOnDefinitionModule): New procedure.
* gm2-compiler/M2Quads.mod (BuildSizeFunction): Rewrite to
ensure variables are initialized.
* gm2-compiler/M2StackSpell.def (GetDefModuleSpellHint): New
procedure function.
* gm2-compiler/M2StackSpell.mod (GetDefModuleSpellHint): New
procedure function.
(CandidatePushName): New procedure.
(BuildHintStr): New procedure.
(CheckForHintStr): Rewrite.

gcc/testsuite/ChangeLog:

PR modula2/122485
* gm2.dg/spell/iso/fail/badimport.mod: New test.

Signed-off-by: Gaius Mulley <gaiusmod2@gmail.com>
gcc/m2/gm2-compiler/M2Comp.mod
gcc/m2/gm2-compiler/M2MetaError.mod
gcc/m2/gm2-compiler/M2Quads.mod
gcc/m2/gm2-compiler/M2StackSpell.def
gcc/m2/gm2-compiler/M2StackSpell.mod
gcc/testsuite/gm2.dg/spell/iso/fail/badimport.mod [new file with mode: 0644]

index 741daeb036d0b91bbf4bd2064dada5ed8ad4d696..0190e016366429d508bbce79df2b670130e8ab1f 100644 (file)
@@ -851,12 +851,11 @@ BEGIN
             MergeDeps (DepContent, ChildDep, LibName)
          ELSE
             (* Unrecoverable error.  *)
-            MetaErrorString1 (Sprintf1 (InitString ('file {%%1EUAF%s} containing module {%%1a} cannot be found'),
+            MetaErrorString1 (Sprintf1 (InitString ('file {%%1EUAF%s} containing module {%%1a} cannot be found {%%1&Ds}'),
                                         FileName), sym)
          END
       ELSE
-         (* Unrecoverable error.  *)
-         MetaError1 ('the file containing the definition module {%1EMAa} cannot be found', sym)
+         MetaError1 ('the file containing the definition module {%1EMAa} cannot be found {%1&Ds}', sym)
       END ;
       ModuleType := Implementation
    ELSE
@@ -928,15 +927,15 @@ BEGIN
             qprintf0 ('\n') ;
             CloseSource
          ELSE
-            (* It is quite legitimate to implement a module in C (and pretend it was a M2
+            (* It is legitimate to implement a module in C (and pretend it was a M2
                implementation) providing that it is not the main program module and the
                definition module does not declare a hidden type when -fextended-opaque
                is used.  *)
             IF (NOT WholeProgram) OR (sym = Main) OR IsHiddenTypeDeclared (sym)
             THEN
                (* Unrecoverable error.  *)
-               MetaErrorString1 (Sprintf1 (InitString ('file {%%1EUAF%s} containing module {%%1a} cannot be found'),
-                                           FileName), sym) ;
+               MetaErrorString1 (Sprintf1 (InitString ('file {%%1EUAF%s} containing module {%%1a} cannot be found {%%1&Ds}'),
+                                           FileName), sym)
             END
          END
       END
index aae0f02eb100b478e7c0b2f1a4f87a7533463efa..22a155731ecd185e0f69248501344bcb697e0946 100644 (file)
@@ -42,7 +42,6 @@ FROM SYSTEM IMPORT ADDRESS ;
 FROM M2Error IMPORT MoveError ;
 FROM M2Debug IMPORT Assert ;
 FROM Storage IMPORT ALLOCATE ;
-FROM M2StackSpell IMPORT GetSpellHint ;
 
 FROM Indexing IMPORT Index, InitIndex, KillIndex, GetIndice, PutIndice,
                      DeleteIndice, HighIndice ;
@@ -74,6 +73,7 @@ IMPORT M2Error ;
 IMPORT FilterError ;
 
 FROM FilterError IMPORT Filter, AddSymError, IsSymError ;
+FROM M2StackSpell IMPORT GetDefModuleSpellHint, GetSpellHint ;
 
 
 CONST
@@ -100,6 +100,7 @@ TYPE
                    len,
                    ini       : INTEGER ;
                    vowel,
+                   filterDef,
                    importHint,
                    exportHint,
                    withStackHint,
@@ -533,6 +534,7 @@ BEGIN
       ini        := 0 ;
       glyph      := FALSE ;  (* Nothing to output yet.  *)
       vowel      := FALSE ;  (* Check for a vowel when outputing string?  *)
+      filterDef  := FALSE ;  (* Filter on definition module list?  *)
       importHint := FALSE;
       exportHint := FALSE ;
       withStackHint := FALSE ;
@@ -1840,7 +1842,7 @@ END op ;
 
 
 (*
-   continuation := {':'|'1'|'2'|'3'|'4'|'i'|'s'|'x'|'w'} =:
+   continuation := {':'|'1'|'2'|'3'|'4'|'i'|'s'|'x'|'w'|'D'} =:
 *)
 
 PROCEDURE continuation (VAR eb: errorBlock;
@@ -1860,7 +1862,8 @@ BEGIN
       'i':  AddImportsHint (eb) |
       's':  SpellHint (eb, sym, bol) |
       'x':  AddExportsHint (eb) |
-      'w':  AddWithStackHint (eb)
+      'w':  AddWithStackHint (eb) |
+      'D':  FilterOnDefinitionModule (eb)
 
       ELSE
          InternalFormat (eb, 'expecting one of [:1234isxw]',
@@ -1956,9 +1959,15 @@ END JoinSentances ;
 
 PROCEDURE SpellHint (VAR eb: errorBlock; sym: ARRAY OF CARDINAL; bol: CARDINAL) ;
 BEGIN
-   IF (bol <= HIGH (sym)) AND IsUnknown (sym[bol])
+   IF bol <= HIGH (sym)
    THEN
-      JoinSentances (eb, GetSpellHint (sym[bol]))
+      IF eb.filterDef AND IsDefImp (sym[bol])
+      THEN
+         JoinSentances (eb, GetDefModuleSpellHint (sym[bol]))
+      ELSIF IsUnknown (sym[bol])
+      THEN
+         JoinSentances (eb, GetSpellHint (sym[bol]))
+      END
    END
 END SpellHint ;
 
@@ -1993,6 +2002,16 @@ BEGIN
 END AddWithStackHint ;
 
 
+(*
+   FilterOnDefinitionModule - turn on filtering and include all the definition modules.
+*)
+
+PROCEDURE FilterOnDefinitionModule (VAR eb: errorBlock) ;
+BEGIN
+   eb.filterDef := TRUE
+END FilterOnDefinitionModule ;
+
+
 (*
    changeColor - changes to color, c.
 *)
index 5ceeb4f139ad58117dd1123e3221aa044fef16b4..a263ce36f72910a561de9f69ec4204e885513be7 100644 (file)
@@ -10697,44 +10697,43 @@ BEGIN
                    NoOfParam) ;
       resulttok := functok ;
       ReturnVar := MakeConstLit (resulttok, MakeKey('0'), Cardinal)
-   ELSIF IsAModula2Type (OperandT (1))
-   THEN
-      paramtok := OperandTok (1) ;
-      resulttok := MakeVirtualTok (functok, functok, paramtok) ;
-      BuildSizeCheckEnd (ProcSym) ;   (* Quadruple generation now on.  *)
-      ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
-      GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, OperandT(1), TRUE)
-   ELSIF IsVar (OperandT (1))
-   THEN
-      BuildSizeCheckEnd (ProcSym) ;   (* Quadruple generation now on.  *)
-      Type := GetSType (OperandT (1)) ;
+   ELSE
       paramtok := OperandTok (1) ;
       resulttok := MakeVirtualTok (functok, functok, paramtok) ;
-      IF IsUnbounded (Type)
+      IF IsAModula2Type (OperandT (1))
       THEN
-         (* Eg. SIZE(a) ; where a is unbounded dereference HIGH and multiply by the TYPE.  *)
-         dim := OperandD (1) ;
-         IF dim = 0
+         BuildSizeCheckEnd (ProcSym) ;   (* Quadruple generation now on.  *)
+         ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
+         GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, OperandT(1), TRUE)
+      ELSIF IsVar (OperandT (1))
+      THEN
+         BuildSizeCheckEnd (ProcSym) ;   (* Quadruple generation now on.  *)
+         Type := GetSType (OperandT (1)) ;
+         IF IsUnbounded (Type)
          THEN
-            ReturnVar := calculateMultipicand (resulttok, OperandT (1), Type, dim)
+            (* Eg. SIZE(a) ; where a is unbounded dereference HIGH and multiply by the TYPE.  *)
+            dim := OperandD (1) ;
+            IF dim = 0
+            THEN
+               ReturnVar := calculateMultipicand (resulttok, OperandT (1), Type, dim)
+            ELSE
+               ReturnVar := calculateMultipicand (resulttok, OperandA (1), Type, dim)
+            END
          ELSE
-            ReturnVar := calculateMultipicand (resulttok, OperandA (1), Type, dim)
+            ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
+            IF Type = NulSym
+            THEN
+               MetaErrorT1 (resulttok,
+                            'cannot get the type and size of {%1Ead}', OperandT (1))
+            END ;
+            GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, Type, TRUE)
          END
       ELSE
-         ReturnVar := MakeTemporary (resulttok, ImmediateValue) ;
-         IF Type = NulSym
-         THEN
-            MetaErrorT1 (resulttok,
-                         'cannot get the type and size of {%1Ead}', OperandT (1))
-         END ;
-         GenQuadO (resulttok, SizeOp, ReturnVar, NulSym, Type, TRUE)
+         MetaErrorT1 (paramtok,
+                      '{%E}SYSTEM procedure {%kSIZE} expects a variable or type as its parameter, seen {%1Ed} {%1&s}',
+                      OperandT (1)) ;
+         ReturnVar := MakeConstLit (paramtok, MakeKey('0'), Cardinal)
       END
-   ELSE
-      paramtok := OperandTok (1) ;
-      MetaErrorT1 (paramtok,
-                   '{%E}SYSTEM procedure {%kSIZE} expects a variable or type as its parameter, seen {%1Ed} {%1&s}',
-                   OperandT (1)) ;
-      ReturnVar := MakeConstLit (resulttok, MakeKey('0'), Cardinal)
    END ;
    PopN (NoOfParam+1) ;       (* Destroy the arguments and function.  *)
    PushTFtok (ReturnVar, GetSType(ProcSym), resulttok)
index 7c1d00b7b592da37c1797d45750c04593944f10f..c45074ae4c1f1d6612382147c7f77bb2f00caec8 100644 (file)
@@ -59,4 +59,14 @@ PROCEDURE GetRecordField (tokno: CARDINAL;
                           fieldName: Name) : CARDINAL ;
 
 
+(*
+   GetDefModuleSpellHint - return a string describing a spelling
+                           hint for the definition module name
+                           similiar to unknown.  NIL is returned
+                           if no hint can be given.
+*)
+
+PROCEDURE GetDefModuleSpellHint (defimp: CARDINAL) : String ;
+
+
 END M2StackSpell.
index 7a072ae95ece5aa3f3ebf36f4f9dbdc6159c4ba0..ac58c1c98d09aae65f31fc69161ba8468732206d 100644 (file)
@@ -31,7 +31,7 @@ FROM SymbolTable IMPORT NulSym, IsModule, IsDefImp, IsRecord,
 FROM SymbolKey IMPORT PerformOperation ;
 FROM DynamicStrings IMPORT InitStringCharStar, InitString, Mark, string, ConCat ;
 FROM FormatStrings IMPORT Sprintf1, Sprintf2, Sprintf3 ;
-FROM NameKey IMPORT KeyToCharStar ;
+FROM NameKey IMPORT KeyToCharStar, NulName ;
 FROM M2MetaError IMPORT MetaErrorStringT0 ;
 
 FROM M2StackWord IMPORT StackOfWord, PushWord, PopWord,
@@ -39,6 +39,7 @@ FROM M2StackWord IMPORT StackOfWord, PushWord, PopWord,
                         NoOfItemsInStackWord, PeepWord ;
 
 FROM CDataTypes IMPORT ConstCharStar ;
+FROM M2Batch IMPORT GetModuleNo ;
 
 IMPORT m2spellcheck ;
 FROM m2spellcheck IMPORT Candidates ;
@@ -96,6 +97,60 @@ BEGIN
 END GetRecordField ;
 
 
+(*
+   CandidatePushName - push a symbol name to the candidate list.
+*)
+
+PROCEDURE CandidatePushName (cand: Candidates; sym: CARDINAL) ;
+VAR
+   str: String ;
+BEGIN
+   str := InitStringCharStar (KeyToCharStar (GetSymName (sym))) ;
+   m2spellcheck.Push (cand, string (str)) ;
+   INC (PushCount)
+END CandidatePushName ;
+
+
+(*
+   GetDefModuleSpellHint - return a string describing a spelling
+                           hint for the definition module name
+                           similiar to defimp.  The premise is that
+                           defimp has been misspelt.  NIL is returned
+                           if no hint can be given.
+*)
+
+PROCEDURE GetDefModuleSpellHint (defimp: CARDINAL) : String ;
+VAR
+   i        : CARDINAL ;
+   sym      : CARDINAL ;
+   cand     : Candidates ;
+   misspell,
+   content  : ConstCharStar ;
+   HintStr  : String ;
+BEGIN
+   HintStr := NIL ;
+   IF GetSymName (defimp) # NulName
+   THEN
+      misspell := KeyToCharStar (GetSymName (defimp)) ;
+      i := 1 ;
+      sym := GetModuleNo (i) ;
+      cand := m2spellcheck.InitCandidates () ;
+      WHILE sym # NulSym DO
+         IF sym # defimp
+         THEN
+            CandidatePushName (cand, sym)
+         END ;
+         INC (i) ;
+         sym := GetModuleNo (i)
+      END ;
+      content := m2spellcheck.FindClosestCharStar (cand, misspell) ;
+      HintStr := BuildHintStr (HintStr, content) ;
+      m2spellcheck.KillCandidates (cand)
+   END ;
+   RETURN AddPunctuation (HintStr, '?')
+END GetDefModuleSpellHint ;
+
+
 (*
    Push - push a scope onto the spelling stack.
           sym might be a ModSym, DefImpSym or a varsym
@@ -183,6 +238,30 @@ BEGIN
 END PushCandidates ;
 
 
+(*
+   BuildHintStr - create the did you mean hint and return it
+                  if HintStr is NIL.  Otherwise append a hint
+                  to HintStr.  If content is NIL then return NIL.
+*)
+
+PROCEDURE BuildHintStr (HintStr: String; content: ConstCharStar) : String ;
+VAR
+   str: String ;
+BEGIN
+   IF content # NIL
+   THEN
+      str := InitStringCharStar (content) ;
+      IF HintStr = NIL
+      THEN
+         RETURN Sprintf1 (Mark (InitString (", did you mean %s")), str)
+      ELSE
+         RETURN Sprintf2 (Mark (InitString ("%s or %s")), HintStr, str)
+      END
+   END ;
+   RETURN NIL
+END BuildHintStr ;
+
+
 (*
    CheckForHintStr - lookup a spell hint matching misspelt.  If one exists
                      then append it to HintStr.  Return HintStr.
@@ -193,7 +272,6 @@ PROCEDURE CheckForHintStr (sym: CARDINAL;
 VAR
    cand   : Candidates ;
    content: ConstCharStar ;
-   str    : String ;
 BEGIN
    IF IsModule (sym) OR IsDefImp (sym) OR IsProcedure (sym) OR
       IsRecord (sym) OR IsEnumeration (sym)
@@ -206,16 +284,7 @@ BEGIN
          content := NIL
       END ;
       m2spellcheck.KillCandidates (cand) ;
-      IF content # NIL
-      THEN
-         str := InitStringCharStar (content) ;
-         IF HintStr = NIL
-         THEN
-            RETURN Sprintf1 (Mark (InitString (", did you mean %s")), str)
-         ELSE
-            RETURN Sprintf2 (Mark (InitString ("%s or %s")), HintStr, str)
-         END
-      END
+      HintStr := BuildHintStr (HintStr, content)
    END ;
    RETURN HintStr
 END CheckForHintStr ;
diff --git a/gcc/testsuite/gm2.dg/spell/iso/fail/badimport.mod b/gcc/testsuite/gm2.dg/spell/iso/fail/badimport.mod
new file mode 100644 (file)
index 0000000..337cf34
--- /dev/null
@@ -0,0 +1,14 @@
+
+(* { dg-do compile } *)
+(* { dg-options "-g -c" } *)
+
+MODULE badimport ;
+
+IMPORT ASCII ;
+FROM StrIO IMPORT WriteString ;
+FROM ASCIi IMPORT nul ;
+ (* { dg-error "error: the file containing the definition module 'ASCIi' cannot be found, did you mean ASCII" "ASCIi" { target *-*-* } 9 } *)
+
+BEGIN
+
+END badimport.