mirror of
https://forge.sourceware.org/marek/gcc.git
synced 2026-02-22 12:00:11 -05:00
399 lines
10 KiB
Modula-2
399 lines
10 KiB
Modula-2
(* M2StackSpell.mod maintain a stack of scopes used in spell checks.
|
|
|
|
Copyright (C) 2025-2026 Free Software Foundation, Inc.
|
|
Contributed by Gaius Mulley <gaiusmod2@gmail.com>.
|
|
|
|
This file is part of GNU Modula-2.
|
|
|
|
GNU Modula-2 is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3, or (at your option)
|
|
any later version.
|
|
|
|
GNU Modula-2 is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GNU Modula-2; see the file COPYING3. If not see
|
|
<http://www.gnu.org/licenses/>. *)
|
|
|
|
IMPLEMENTATION MODULE M2StackSpell ;
|
|
|
|
FROM SymbolTable IMPORT NulSym, IsModule, IsDefImp, IsRecord,
|
|
IsEnumeration, IsProcedure, GetNth,
|
|
GetSymName, GetSym, GetLocalSym, GetScope,
|
|
UnknownReported, IsUnknown,
|
|
GetUnknownOnImport, GetUnknownDeclScope,
|
|
ForeachExportedDo,
|
|
ForeachProcedureDo, ForeachLocalSymDo,
|
|
ForeachFieldEnumerationDo ;
|
|
|
|
FROM SymbolKey IMPORT PerformOperation ;
|
|
FROM DynamicStrings IMPORT InitStringCharStar, InitString, Mark, string, ConCat ;
|
|
FROM FormatStrings IMPORT Sprintf1, Sprintf2, Sprintf3 ;
|
|
FROM NameKey IMPORT KeyToCharStar, NulName ;
|
|
FROM M2MetaError IMPORT MetaErrorStringT0 ;
|
|
|
|
FROM M2StackWord IMPORT StackOfWord, PushWord, PopWord,
|
|
InitStackWord, KillStackWord,
|
|
NoOfItemsInStackWord, PeepWord ;
|
|
|
|
FROM CDataTypes IMPORT ConstCharStar ;
|
|
FROM M2Batch IMPORT GetModuleNo ;
|
|
|
|
IMPORT m2spellcheck ;
|
|
FROM m2spellcheck IMPORT Candidates ;
|
|
|
|
|
|
VAR
|
|
DefaultStack: StackOfWord ;
|
|
|
|
|
|
(*
|
|
GetRecordField - return the record field containing fieldName.
|
|
An error is generated if the fieldName is not
|
|
found in record.
|
|
*)
|
|
|
|
PROCEDURE GetRecordField (tokno: CARDINAL;
|
|
record: CARDINAL;
|
|
fieldName: Name) : CARDINAL ;
|
|
VAR
|
|
str : String ;
|
|
sym : CARDINAL ;
|
|
recordName: Name ;
|
|
content : ConstCharStar ;
|
|
cand : Candidates ;
|
|
fieldStr,
|
|
recordStr,
|
|
contentStr: String ;
|
|
BEGIN
|
|
sym := GetLocalSym (record, fieldName) ;
|
|
IF sym = NulSym
|
|
THEN
|
|
recordName := GetSymName (record) ;
|
|
content := NIL ;
|
|
cand := m2spellcheck.InitCandidates () ;
|
|
IF PushCandidates (cand, record) > 0
|
|
THEN
|
|
content := m2spellcheck.FindClosestCharStar (cand,
|
|
KeyToCharStar (fieldName))
|
|
END ;
|
|
fieldStr := Mark (InitStringCharStar (KeyToCharStar (fieldName))) ;
|
|
recordStr := Mark (InitStringCharStar (KeyToCharStar (recordName))) ;
|
|
IF content = NIL
|
|
THEN
|
|
str := Sprintf2 (Mark (InitString ("field %s does not exist within record %s")),
|
|
fieldStr, recordStr)
|
|
ELSE
|
|
contentStr := Mark (InitStringCharStar (content)) ;
|
|
str := Sprintf3 (Mark (InitString ("field %s does not exist within record %s, did you mean %s?")),
|
|
fieldStr, recordStr, contentStr)
|
|
END ;
|
|
MetaErrorStringT0 (tokno, str) ;
|
|
m2spellcheck.KillCandidates (cand)
|
|
END ;
|
|
RETURN sym
|
|
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
|
|
of a record type denoting a with statement.
|
|
*)
|
|
|
|
PROCEDURE Push (sym: CARDINAL) ;
|
|
BEGIN
|
|
PushWord (DefaultStack, sym)
|
|
END Push ;
|
|
|
|
|
|
(*
|
|
Pop - remove the top scope from the spelling stack.
|
|
*)
|
|
|
|
PROCEDURE Pop ;
|
|
BEGIN
|
|
IF PopWord (DefaultStack) = 0
|
|
THEN
|
|
END
|
|
END Pop ;
|
|
|
|
|
|
VAR
|
|
PushCount : CARDINAL ;
|
|
PushCandidate: Candidates ;
|
|
|
|
|
|
(*
|
|
PushName - push a name to the candidate vec.
|
|
*)
|
|
|
|
PROCEDURE PushName (sym: CARDINAL) ;
|
|
VAR
|
|
str: String ;
|
|
BEGIN
|
|
str := InitStringCharStar (KeyToCharStar (GetSymName (sym))) ;
|
|
m2spellcheck.Push (PushCandidate, string (str)) ;
|
|
(* str := KillString (str) *)
|
|
INC (PushCount)
|
|
END PushName ;
|
|
|
|
|
|
(*
|
|
ForeachRecordFieldDo -
|
|
*)
|
|
|
|
PROCEDURE ForeachRecordFieldDo (record: CARDINAL; op: PerformOperation) ;
|
|
VAR
|
|
i : CARDINAL ;
|
|
field: CARDINAL ;
|
|
BEGIN
|
|
i := 1 ;
|
|
REPEAT
|
|
field := GetNth (record, i) ;
|
|
IF field # NulSym
|
|
THEN
|
|
op (field)
|
|
END ;
|
|
INC (i)
|
|
UNTIL field = NulSym
|
|
END ForeachRecordFieldDo ;
|
|
|
|
|
|
(*
|
|
PushCandidates -
|
|
*)
|
|
|
|
PROCEDURE PushCandidates (cand: Candidates; sym: CARDINAL) : CARDINAL ;
|
|
BEGIN
|
|
PushCount := 0 ;
|
|
PushCandidate := cand ;
|
|
IF IsModule (sym) OR IsDefImp (sym)
|
|
THEN
|
|
ForeachProcedureDo (sym, PushName) ;
|
|
ForeachLocalSymDo (sym, PushName)
|
|
ELSIF IsEnumeration (sym)
|
|
THEN
|
|
ForeachFieldEnumerationDo (sym, PushName)
|
|
ELSIF IsRecord (sym)
|
|
THEN
|
|
ForeachRecordFieldDo (sym, PushName)
|
|
END ;
|
|
RETURN PushCount
|
|
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.
|
|
*)
|
|
|
|
PROCEDURE CheckForHintStr (sym: CARDINAL;
|
|
HintStr, misspelt: String) : String ;
|
|
VAR
|
|
cand : Candidates ;
|
|
content: ConstCharStar ;
|
|
BEGIN
|
|
IF IsModule (sym) OR IsDefImp (sym) OR IsProcedure (sym) OR
|
|
IsRecord (sym) OR IsEnumeration (sym)
|
|
THEN
|
|
cand := m2spellcheck.InitCandidates () ;
|
|
IF PushCandidates (cand, sym) > 1
|
|
THEN
|
|
content := m2spellcheck.FindClosestCharStar (cand, string (misspelt))
|
|
ELSE
|
|
content := NIL
|
|
END ;
|
|
m2spellcheck.KillCandidates (cand) ;
|
|
HintStr := BuildHintStr (HintStr, content)
|
|
END ;
|
|
RETURN HintStr
|
|
END CheckForHintStr ;
|
|
|
|
|
|
(*
|
|
AddPunctuation - adds punct to the end of str providing that str is non NIL.
|
|
*)
|
|
|
|
PROCEDURE AddPunctuation (str: String; punct: ARRAY OF CHAR) : String ;
|
|
BEGIN
|
|
IF str = NIL
|
|
THEN
|
|
RETURN NIL
|
|
ELSE
|
|
RETURN ConCat (str, Mark (InitString (punct)))
|
|
END
|
|
END AddPunctuation ;
|
|
|
|
|
|
(*
|
|
GetSpellHint - return a string describing a spelling hint.
|
|
*)
|
|
|
|
PROCEDURE GetSpellHint (unknown: CARDINAL) : String ;
|
|
BEGIN
|
|
IF IsUnknown (unknown) AND
|
|
GetUnknownOnImport (unknown) AND
|
|
(GetUnknownDeclScope (unknown) # GetScope (unknown))
|
|
THEN
|
|
(* It was created during an import statement. *)
|
|
RETURN GetExportedSpellHint (unknown, GetUnknownDeclScope (unknown))
|
|
END ;
|
|
RETURN GetScopeSpellHint (unknown)
|
|
END GetSpellHint ;
|
|
|
|
|
|
(*
|
|
GetExportedSpellHint - return a string describing a spelling hint
|
|
using the module exported identifiers.
|
|
*)
|
|
|
|
PROCEDURE GetExportedSpellHint (unknown, module: CARDINAL) : String ;
|
|
VAR
|
|
content : ConstCharStar ;
|
|
misspell,
|
|
HintStr : String ;
|
|
BEGIN
|
|
misspell := InitStringCharStar (KeyToCharStar (GetSymName (unknown))) ;
|
|
HintStr := NIL ;
|
|
PushCount := 0 ;
|
|
PushCandidate := m2spellcheck.InitCandidates () ;
|
|
ForeachExportedDo (module, PushName) ;
|
|
ForeachLocalSymDo (module, PushName) ;
|
|
IF PushCount > 0
|
|
THEN
|
|
content := m2spellcheck.FindClosestCharStar (PushCandidate,
|
|
string (misspell)) ;
|
|
HintStr := BuildHintStr (HintStr, content)
|
|
END ;
|
|
m2spellcheck.KillCandidates (PushCandidate) ;
|
|
RETURN AddPunctuation (HintStr, '?')
|
|
END GetExportedSpellHint ;
|
|
|
|
|
|
(*
|
|
GetScopeSpellHint - return a string describing a spelling hint
|
|
using the visible scopes.
|
|
*)
|
|
|
|
PROCEDURE GetScopeSpellHint (unknown: CARDINAL) : String ;
|
|
VAR
|
|
i, n : CARDINAL ;
|
|
sym : CARDINAL ;
|
|
misspell,
|
|
HintStr : String ;
|
|
BEGIN
|
|
misspell := InitStringCharStar (KeyToCharStar (GetSymName (unknown))) ;
|
|
HintStr := NIL ;
|
|
n := NoOfItemsInStackWord (DefaultStack) ;
|
|
i := 1 ;
|
|
WHILE (i <= n) AND (HintStr = NIL) DO
|
|
sym := PeepWord (DefaultStack, i) ;
|
|
HintStr := CheckForHintStr (sym, HintStr, misspell) ;
|
|
IF IsModule (sym) OR IsDefImp (sym)
|
|
THEN
|
|
(* Cannot see beyond a module scope. *)
|
|
RETURN AddPunctuation (HintStr, '?')
|
|
END ;
|
|
INC (i)
|
|
END ;
|
|
RETURN AddPunctuation (HintStr, '?')
|
|
END GetScopeSpellHint ;
|
|
|
|
|
|
(*
|
|
Init -
|
|
*)
|
|
|
|
PROCEDURE Init ;
|
|
BEGIN
|
|
DefaultStack := InitStackWord ()
|
|
END Init ;
|
|
|
|
|
|
BEGIN
|
|
Init
|
|
END M2StackSpell.
|