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 <[email protected]>
---
gcc/m2/gm2-compiler/M2Comp.mod | 11 +--
gcc/m2/gm2-compiler/M2MetaError.mod | 29 +++++-
gcc/m2/gm2-compiler/M2Quads.mod | 59 ++++++------
gcc/m2/gm2-compiler/M2StackSpell.def | 10 ++
gcc/m2/gm2-compiler/M2StackSpell.mod | 93 ++++++++++++++++---
.../gm2.dg/spell/iso/fail/badimport.mod | 14 +++
6 files changed, 163 insertions(+), 53 deletions(-)
create mode 100644 gcc/testsuite/gm2.dg/spell/iso/fail/badimport.mod
diff --git a/gcc/m2/gm2-compiler/M2Comp.mod b/gcc/m2/gm2-compiler/M2Comp.mod
index 741daeb036d..0190e016366 100644
--- a/gcc/m2/gm2-compiler/M2Comp.mod
+++ b/gcc/m2/gm2-compiler/M2Comp.mod
@@ -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
diff --git a/gcc/m2/gm2-compiler/M2MetaError.mod
b/gcc/m2/gm2-compiler/M2MetaError.mod
index aae0f02eb10..22a155731ec 100644
--- a/gcc/m2/gm2-compiler/M2MetaError.mod
+++ b/gcc/m2/gm2-compiler/M2MetaError.mod
@@ -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.
*)
diff --git a/gcc/m2/gm2-compiler/M2Quads.mod b/gcc/m2/gm2-compiler/M2Quads.mod
index 5ceeb4f139a..a263ce36f72 100644
--- a/gcc/m2/gm2-compiler/M2Quads.mod
+++ b/gcc/m2/gm2-compiler/M2Quads.mod
@@ -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)
diff --git a/gcc/m2/gm2-compiler/M2StackSpell.def
b/gcc/m2/gm2-compiler/M2StackSpell.def
index 7c1d00b7b59..c45074ae4c1 100644
--- a/gcc/m2/gm2-compiler/M2StackSpell.def
+++ b/gcc/m2/gm2-compiler/M2StackSpell.def
@@ -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.
diff --git a/gcc/m2/gm2-compiler/M2StackSpell.mod
b/gcc/m2/gm2-compiler/M2StackSpell.mod
index 7a072ae95ec..ac58c1c98d0 100644
--- a/gcc/m2/gm2-compiler/M2StackSpell.mod
+++ b/gcc/m2/gm2-compiler/M2StackSpell.mod
@@ -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
index 00000000000..337cf346d50
--- /dev/null
+++ b/gcc/testsuite/gm2.dg/spell/iso/fail/badimport.mod
@@ -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.
--
2.39.5