Branch data Line data Source code
1 : : /* do not edit automatically generated by mc from M2StackSpell. */
2 : : /* M2StackSpell.mod maintain a stack of scopes used in spell checks.
3 : :
4 : : Copyright (C) 2025 Free Software Foundation, Inc.
5 : : Contributed by Gaius Mulley <gaiusmod2@gmail.com>.
6 : :
7 : : This file is part of GNU Modula-2.
8 : :
9 : : GNU Modula-2 is free software; you can redistribute it and/or modify
10 : : it under the terms of the GNU General Public License as published by
11 : : the Free Software Foundation; either version 3, or (at your option)
12 : : any later version.
13 : :
14 : : GNU Modula-2 is distributed in the hope that it will be useful, but
15 : : WITHOUT ANY WARRANTY; without even the implied warranty of
16 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : : General Public License for more details.
18 : :
19 : : You should have received a copy of the GNU General Public License
20 : : along with GNU Modula-2; see the file COPYING3. If not see
21 : : <http://www.gnu.org/licenses/>. */
22 : :
23 : : #include "config.h"
24 : : #include "system.h"
25 : : #include "gcc-consolidation.h"
26 : :
27 : : #include <stdbool.h>
28 : : # if !defined (PROC_D)
29 : : # define PROC_D
30 : : typedef void (*PROC_t) (void);
31 : : typedef struct { PROC_t proc; } PROC;
32 : : # endif
33 : :
34 : : #if defined(__cplusplus)
35 : : # undef NULL
36 : : # define NULL 0
37 : : #endif
38 : : #define _M2StackSpell_C
39 : :
40 : : #include "GM2StackSpell.h"
41 : : # include "GSymbolTable.h"
42 : : # include "GSymbolKey.h"
43 : : # include "GDynamicStrings.h"
44 : : # include "GFormatStrings.h"
45 : : # include "GNameKey.h"
46 : : # include "GM2MetaError.h"
47 : : # include "GM2StackWord.h"
48 : : # include "GCDataTypes.h"
49 : : # include "GM2Batch.h"
50 : : # include "Gm2spellcheck.h"
51 : :
52 : : static M2StackWord_StackOfWord DefaultStack;
53 : : static unsigned int PushCount;
54 : : static m2spellcheck_Candidates PushCandidate;
55 : :
56 : : /*
57 : : GetSpellHint - return a string describing a spelling hint.
58 : : */
59 : :
60 : : extern "C" DynamicStrings_String M2StackSpell_GetSpellHint (unsigned int unknown);
61 : :
62 : : /*
63 : : Push - push a scope onto the spelling stack.
64 : : sym might be a ModSym, DefImpSym or a varsym
65 : : of a record type denoting a with statement.
66 : : */
67 : :
68 : : extern "C" void M2StackSpell_Push (unsigned int sym);
69 : :
70 : : /*
71 : : Pop - remove the top scope from the spelling stack.
72 : : */
73 : :
74 : : extern "C" void M2StackSpell_Pop (void);
75 : :
76 : : /*
77 : : GetRecordField - return the record field containing fieldName.
78 : : An error is generated if the fieldName is not
79 : : found in record.
80 : : */
81 : :
82 : : extern "C" unsigned int M2StackSpell_GetRecordField (unsigned int tokno, unsigned int record, NameKey_Name fieldName);
83 : :
84 : : /*
85 : : GetDefModuleSpellHint - return a string describing a spelling
86 : : hint for the definition module name
87 : : similiar to defimp. The premise is that
88 : : defimp has been misspelt. NIL is returned
89 : : if no hint can be given.
90 : : */
91 : :
92 : : extern "C" DynamicStrings_String M2StackSpell_GetDefModuleSpellHint (unsigned int defimp);
93 : :
94 : : /*
95 : : CandidatePushName - push a symbol name to the candidate list.
96 : : */
97 : :
98 : : static void CandidatePushName (m2spellcheck_Candidates cand, unsigned int sym);
99 : :
100 : : /*
101 : : PushName - push a name to the candidate vec.
102 : : */
103 : :
104 : : static void PushName (unsigned int sym);
105 : :
106 : : /*
107 : : ForeachRecordFieldDo -
108 : : */
109 : :
110 : : static void ForeachRecordFieldDo (unsigned int record, SymbolKey_PerformOperation op);
111 : :
112 : : /*
113 : : PushCandidates -
114 : : */
115 : :
116 : : static unsigned int PushCandidates (m2spellcheck_Candidates cand, unsigned int sym);
117 : :
118 : : /*
119 : : BuildHintStr - create the did you mean hint and return it
120 : : if HintStr is NIL. Otherwise append a hint
121 : : to HintStr. If content is NIL then return NIL.
122 : : */
123 : :
124 : : static DynamicStrings_String BuildHintStr (DynamicStrings_String HintStr, const char * content);
125 : :
126 : : /*
127 : : CheckForHintStr - lookup a spell hint matching misspelt. If one exists
128 : : then append it to HintStr. Return HintStr.
129 : : */
130 : :
131 : : static DynamicStrings_String CheckForHintStr (unsigned int sym, DynamicStrings_String HintStr, DynamicStrings_String misspelt);
132 : :
133 : : /*
134 : : AddPunctuation - adds punct to the end of str providing that str is non NIL.
135 : : */
136 : :
137 : : static DynamicStrings_String AddPunctuation (DynamicStrings_String str, const char *punct_, unsigned int _punct_high);
138 : :
139 : : /*
140 : : GetExportedSpellHint - return a string describing a spelling hint
141 : : using the module exported identifiers.
142 : : */
143 : :
144 : : static DynamicStrings_String GetExportedSpellHint (unsigned int unknown, unsigned int module);
145 : :
146 : : /*
147 : : GetScopeSpellHint - return a string describing a spelling hint
148 : : using the visible scopes.
149 : : */
150 : :
151 : : static DynamicStrings_String GetScopeSpellHint (unsigned int unknown);
152 : :
153 : : /*
154 : : Init -
155 : : */
156 : :
157 : : static void Init (void);
158 : :
159 : :
160 : : /*
161 : : CandidatePushName - push a symbol name to the candidate list.
162 : : */
163 : :
164 : 83 : static void CandidatePushName (m2spellcheck_Candidates cand, unsigned int sym)
165 : : {
166 : 83 : DynamicStrings_String str;
167 : :
168 : 83 : str = DynamicStrings_InitStringCharStar (NameKey_KeyToCharStar (SymbolTable_GetSymName (sym)));
169 : 83 : m2spellcheck_Push (cand, const_cast <const char * > (static_cast <char * > (DynamicStrings_string (str))));
170 : 83 : PushCount += 1;
171 : 83 : }
172 : :
173 : :
174 : : /*
175 : : PushName - push a name to the candidate vec.
176 : : */
177 : :
178 : 2774 : static void PushName (unsigned int sym)
179 : : {
180 : 2774 : DynamicStrings_String str;
181 : :
182 : 2774 : str = DynamicStrings_InitStringCharStar (NameKey_KeyToCharStar (SymbolTable_GetSymName (sym)));
183 : 2774 : m2spellcheck_Push (PushCandidate, const_cast <const char * > (static_cast <char * > (DynamicStrings_string (str))));
184 : : /* str := KillString (str) */
185 : 2774 : PushCount += 1;
186 : 2774 : }
187 : :
188 : :
189 : : /*
190 : : ForeachRecordFieldDo -
191 : : */
192 : :
193 : 12 : static void ForeachRecordFieldDo (unsigned int record, SymbolKey_PerformOperation op)
194 : : {
195 : 12 : unsigned int i;
196 : 12 : unsigned int field;
197 : :
198 : 12 : i = 1;
199 : 36 : do {
200 : 36 : field = SymbolTable_GetNth (record, i);
201 : 36 : if (field != SymbolTable_NulSym)
202 : : {
203 : 24 : (*op.proc) (field);
204 : : }
205 : 36 : i += 1;
206 : 36 : } while (! (field == SymbolTable_NulSym));
207 : 12 : }
208 : :
209 : :
210 : : /*
211 : : PushCandidates -
212 : : */
213 : :
214 : 192 : static unsigned int PushCandidates (m2spellcheck_Candidates cand, unsigned int sym)
215 : : {
216 : 192 : PushCount = 0;
217 : 192 : PushCandidate = cand;
218 : 192 : if ((SymbolTable_IsModule (sym)) || (SymbolTable_IsDefImp (sym)))
219 : : {
220 : 180 : SymbolTable_ForeachProcedureDo (sym, (SymbolKey_PerformOperation) {(SymbolKey_PerformOperation_t) PushName});
221 : 180 : SymbolTable_ForeachLocalSymDo (sym, (SymbolKey_PerformOperation) {(SymbolKey_PerformOperation_t) PushName});
222 : : }
223 : 12 : else if (SymbolTable_IsEnumeration (sym))
224 : : {
225 : : /* avoid dangling else. */
226 : 0 : SymbolTable_ForeachFieldEnumerationDo (sym, (SymbolKey_PerformOperation) {(SymbolKey_PerformOperation_t) PushName});
227 : : }
228 : 12 : else if (SymbolTable_IsRecord (sym))
229 : : {
230 : : /* avoid dangling else. */
231 : 12 : ForeachRecordFieldDo (sym, (SymbolKey_PerformOperation) {(SymbolKey_PerformOperation_t) PushName});
232 : : }
233 : 192 : return PushCount;
234 : : /* static analysis guarentees a RETURN statement will be used before here. */
235 : : __builtin_unreachable ();
236 : : }
237 : :
238 : :
239 : : /*
240 : : BuildHintStr - create the did you mean hint and return it
241 : : if HintStr is NIL. Otherwise append a hint
242 : : to HintStr. If content is NIL then return NIL.
243 : : */
244 : :
245 : 206 : static DynamicStrings_String BuildHintStr (DynamicStrings_String HintStr, const char * content)
246 : : {
247 : 206 : DynamicStrings_String str;
248 : :
249 : 206 : if (content != NULL)
250 : : {
251 : 64 : str = DynamicStrings_InitStringCharStar (static_cast <void *> (const_cast <char * > (content)));
252 : 64 : if (HintStr == NULL)
253 : : {
254 : 64 : return FormatStrings_Sprintf1 (DynamicStrings_Mark (DynamicStrings_InitString ((const char *) ", did you mean %s", 17)), (const unsigned char *) &str, (sizeof (str)-1));
255 : : }
256 : : else
257 : : {
258 : 0 : return FormatStrings_Sprintf2 (DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "%s or %s", 8)), (const unsigned char *) &HintStr, (sizeof (HintStr)-1), (const unsigned char *) &str, (sizeof (str)-1));
259 : : }
260 : : }
261 : : return static_cast<DynamicStrings_String> (NULL);
262 : : /* static analysis guarentees a RETURN statement will be used before here. */
263 : : __builtin_unreachable ();
264 : : }
265 : :
266 : :
267 : : /*
268 : : CheckForHintStr - lookup a spell hint matching misspelt. If one exists
269 : : then append it to HintStr. Return HintStr.
270 : : */
271 : :
272 : 186 : static DynamicStrings_String CheckForHintStr (unsigned int sym, DynamicStrings_String HintStr, DynamicStrings_String misspelt)
273 : : {
274 : 186 : m2spellcheck_Candidates cand;
275 : 186 : const char * content;
276 : :
277 : 186 : if (((((SymbolTable_IsModule (sym)) || (SymbolTable_IsDefImp (sym))) || (SymbolTable_IsProcedure (sym))) || (SymbolTable_IsRecord (sym))) || (SymbolTable_IsEnumeration (sym)))
278 : : {
279 : 186 : cand = m2spellcheck_InitCandidates ();
280 : 186 : if ((PushCandidates (cand, sym)) > 1)
281 : : {
282 : 186 : content = m2spellcheck_FindClosestCharStar (cand, const_cast <const char * > (static_cast <char * > (DynamicStrings_string (misspelt))));
283 : : }
284 : : else
285 : : {
286 : : content = static_cast<const char *> (NULL);
287 : : }
288 : 186 : m2spellcheck_KillCandidates (&cand);
289 : 186 : HintStr = BuildHintStr (HintStr, content);
290 : : }
291 : 186 : return HintStr;
292 : : /* static analysis guarentees a RETURN statement will be used before here. */
293 : : __builtin_unreachable ();
294 : : }
295 : :
296 : :
297 : : /*
298 : : AddPunctuation - adds punct to the end of str providing that str is non NIL.
299 : : */
300 : :
301 : 248 : static DynamicStrings_String AddPunctuation (DynamicStrings_String str, const char *punct_, unsigned int _punct_high)
302 : : {
303 : 248 : char punct[_punct_high+1];
304 : :
305 : : /* make a local copy of each unbounded array. */
306 : 248 : memcpy (punct, punct_, _punct_high+1);
307 : :
308 : 248 : if (str == NULL)
309 : : {
310 : : return static_cast<DynamicStrings_String> (NULL);
311 : : }
312 : : else
313 : : {
314 : 64 : return DynamicStrings_ConCat (str, DynamicStrings_Mark (DynamicStrings_InitString ((const char *) punct, _punct_high)));
315 : : }
316 : : /* static analysis guarentees a RETURN statement will be used before here. */
317 : : __builtin_unreachable ();
318 : 248 : }
319 : :
320 : :
321 : : /*
322 : : GetExportedSpellHint - return a string describing a spelling hint
323 : : using the module exported identifiers.
324 : : */
325 : :
326 : 3 : static DynamicStrings_String GetExportedSpellHint (unsigned int unknown, unsigned int module)
327 : : {
328 : 3 : const char * content;
329 : 3 : DynamicStrings_String misspell;
330 : 3 : DynamicStrings_String HintStr;
331 : :
332 : 3 : misspell = DynamicStrings_InitStringCharStar (NameKey_KeyToCharStar (SymbolTable_GetSymName (unknown)));
333 : 3 : HintStr = static_cast<DynamicStrings_String> (NULL);
334 : 3 : PushCount = 0;
335 : 3 : PushCandidate = m2spellcheck_InitCandidates ();
336 : 3 : SymbolTable_ForeachExportedDo (module, (SymbolKey_PerformOperation) {(SymbolKey_PerformOperation_t) PushName});
337 : 3 : SymbolTable_ForeachLocalSymDo (module, (SymbolKey_PerformOperation) {(SymbolKey_PerformOperation_t) PushName});
338 : 3 : if (PushCount > 0)
339 : : {
340 : 3 : content = m2spellcheck_FindClosestCharStar (PushCandidate, const_cast <const char * > (static_cast <char * > (DynamicStrings_string (misspell))));
341 : 3 : HintStr = BuildHintStr (HintStr, content);
342 : : }
343 : 3 : m2spellcheck_KillCandidates (&PushCandidate);
344 : 3 : return AddPunctuation (HintStr, (const char *) "?", 1);
345 : : /* static analysis guarentees a RETURN statement will be used before here. */
346 : : __builtin_unreachable ();
347 : : }
348 : :
349 : :
350 : : /*
351 : : GetScopeSpellHint - return a string describing a spelling hint
352 : : using the visible scopes.
353 : : */
354 : :
355 : 222 : static DynamicStrings_String GetScopeSpellHint (unsigned int unknown)
356 : : {
357 : 222 : unsigned int i;
358 : 222 : unsigned int n;
359 : 222 : unsigned int sym;
360 : 222 : DynamicStrings_String misspell;
361 : 222 : DynamicStrings_String HintStr;
362 : :
363 : 222 : misspell = DynamicStrings_InitStringCharStar (NameKey_KeyToCharStar (SymbolTable_GetSymName (unknown)));
364 : 222 : HintStr = static_cast<DynamicStrings_String> (NULL);
365 : 222 : n = M2StackWord_NoOfItemsInStackWord (DefaultStack);
366 : 222 : i = 1;
367 : 450 : while ((i <= n) && (HintStr == NULL))
368 : : {
369 : 186 : sym = static_cast<unsigned int> (M2StackWord_PeepWord (DefaultStack, i));
370 : 186 : HintStr = CheckForHintStr (sym, HintStr, misspell);
371 : 186 : if ((SymbolTable_IsModule (sym)) || (SymbolTable_IsDefImp (sym)))
372 : : {
373 : : /* Cannot see beyond a module scope. */
374 : 180 : return AddPunctuation (HintStr, (const char *) "?", 1);
375 : : }
376 : 6 : i += 1;
377 : : }
378 : 42 : return AddPunctuation (HintStr, (const char *) "?", 1);
379 : : /* static analysis guarentees a RETURN statement will be used before here. */
380 : : __builtin_unreachable ();
381 : : }
382 : :
383 : :
384 : : /*
385 : : Init -
386 : : */
387 : :
388 : 15229 : static void Init (void)
389 : : {
390 : 0 : DefaultStack = M2StackWord_InitStackWord ();
391 : 0 : }
392 : :
393 : :
394 : : /*
395 : : GetSpellHint - return a string describing a spelling hint.
396 : : */
397 : :
398 : 225 : extern "C" DynamicStrings_String M2StackSpell_GetSpellHint (unsigned int unknown)
399 : : {
400 : 225 : if (((SymbolTable_IsUnknown (unknown)) && (SymbolTable_GetUnknownOnImport (unknown))) && ((SymbolTable_GetUnknownDeclScope (unknown)) != (SymbolTable_GetScope (unknown))))
401 : : {
402 : : /* It was created during an import statement. */
403 : 3 : return GetExportedSpellHint (unknown, SymbolTable_GetUnknownDeclScope (unknown));
404 : : }
405 : 222 : return GetScopeSpellHint (unknown);
406 : : /* static analysis guarentees a RETURN statement will be used before here. */
407 : : __builtin_unreachable ();
408 : : }
409 : :
410 : :
411 : : /*
412 : : Push - push a scope onto the spelling stack.
413 : : sym might be a ModSym, DefImpSym or a varsym
414 : : of a record type denoting a with statement.
415 : : */
416 : :
417 : 5397138 : extern "C" void M2StackSpell_Push (unsigned int sym)
418 : : {
419 : 5397138 : M2StackWord_PushWord (DefaultStack, sym);
420 : 5397138 : }
421 : :
422 : :
423 : : /*
424 : : Pop - remove the top scope from the spelling stack.
425 : : */
426 : :
427 : 5396882 : extern "C" void M2StackSpell_Pop (void)
428 : : {
429 : 5396882 : if ((M2StackWord_PopWord (DefaultStack)) == 0)
430 : : {} /* empty. */
431 : 5396882 : }
432 : :
433 : :
434 : : /*
435 : : GetRecordField - return the record field containing fieldName.
436 : : An error is generated if the fieldName is not
437 : : found in record.
438 : : */
439 : :
440 : 26620 : extern "C" unsigned int M2StackSpell_GetRecordField (unsigned int tokno, unsigned int record, NameKey_Name fieldName)
441 : : {
442 : 26620 : DynamicStrings_String str;
443 : 26620 : unsigned int sym;
444 : 26620 : NameKey_Name recordName;
445 : 26620 : const char * content;
446 : 26620 : m2spellcheck_Candidates cand;
447 : 26620 : DynamicStrings_String fieldStr;
448 : 26620 : DynamicStrings_String recordStr;
449 : 26620 : DynamicStrings_String contentStr;
450 : :
451 : 26620 : sym = SymbolTable_GetLocalSym (record, fieldName);
452 : 26620 : if (sym == SymbolTable_NulSym)
453 : : {
454 : 6 : recordName = SymbolTable_GetSymName (record);
455 : 6 : content = static_cast<const char *> (NULL);
456 : 6 : cand = m2spellcheck_InitCandidates ();
457 : 6 : if ((PushCandidates (cand, record)) > 0)
458 : : {
459 : 6 : content = m2spellcheck_FindClosestCharStar (cand, const_cast <const char * > (static_cast <char * > (NameKey_KeyToCharStar (fieldName))));
460 : : }
461 : 6 : fieldStr = DynamicStrings_Mark (DynamicStrings_InitStringCharStar (NameKey_KeyToCharStar (fieldName)));
462 : 6 : recordStr = DynamicStrings_Mark (DynamicStrings_InitStringCharStar (NameKey_KeyToCharStar (recordName)));
463 : 6 : if (content == NULL)
464 : : {
465 : 0 : str = FormatStrings_Sprintf2 (DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "field %s does not exist within record %s", 40)), (const unsigned char *) &fieldStr, (sizeof (fieldStr)-1), (const unsigned char *) &recordStr, (sizeof (recordStr)-1));
466 : : }
467 : : else
468 : : {
469 : 6 : contentStr = DynamicStrings_Mark (DynamicStrings_InitStringCharStar (static_cast <void *> (const_cast <char * > (content))));
470 : 6 : str = FormatStrings_Sprintf3 (DynamicStrings_Mark (DynamicStrings_InitString ((const char *) "field %s does not exist within record %s, did you mean %s?", 58)), (const unsigned char *) &fieldStr, (sizeof (fieldStr)-1), (const unsigned char *) &recordStr, (sizeof (recordStr)-1), (const unsigned char *) &contentStr, (sizeof (contentStr)-1));
471 : : }
472 : 6 : M2MetaError_MetaErrorStringT0 (tokno, str);
473 : 6 : m2spellcheck_KillCandidates (&cand);
474 : : }
475 : 26620 : return sym;
476 : : /* static analysis guarentees a RETURN statement will be used before here. */
477 : : __builtin_unreachable ();
478 : : }
479 : :
480 : :
481 : : /*
482 : : GetDefModuleSpellHint - return a string describing a spelling
483 : : hint for the definition module name
484 : : similiar to defimp. The premise is that
485 : : defimp has been misspelt. NIL is returned
486 : : if no hint can be given.
487 : : */
488 : :
489 : 23 : extern "C" DynamicStrings_String M2StackSpell_GetDefModuleSpellHint (unsigned int defimp)
490 : : {
491 : 23 : unsigned int i;
492 : 23 : unsigned int sym;
493 : 23 : m2spellcheck_Candidates cand;
494 : 23 : const char * misspell;
495 : 23 : const char * content;
496 : 23 : DynamicStrings_String HintStr;
497 : :
498 : 23 : HintStr = static_cast<DynamicStrings_String> (NULL);
499 : 23 : if ((SymbolTable_GetSymName (defimp)) != NameKey_NulName)
500 : : {
501 : 17 : misspell = static_cast<const char *> (NameKey_KeyToCharStar (SymbolTable_GetSymName (defimp)));
502 : 17 : i = 1;
503 : 17 : sym = M2Batch_GetModuleNo (i);
504 : 17 : cand = m2spellcheck_InitCandidates ();
505 : 117 : while (sym != SymbolTable_NulSym)
506 : : {
507 : 100 : if (sym != defimp)
508 : : {
509 : 83 : CandidatePushName (cand, sym);
510 : : }
511 : 100 : i += 1;
512 : 100 : sym = M2Batch_GetModuleNo (i);
513 : : }
514 : 17 : content = m2spellcheck_FindClosestCharStar (cand, misspell);
515 : 17 : HintStr = BuildHintStr (HintStr, content);
516 : 17 : m2spellcheck_KillCandidates (&cand);
517 : : }
518 : 23 : return AddPunctuation (HintStr, (const char *) "?", 1);
519 : : /* static analysis guarentees a RETURN statement will be used before here. */
520 : : __builtin_unreachable ();
521 : : }
522 : :
523 : 15229 : extern "C" void _M2_M2StackSpell_init (__attribute__((unused)) int argc, __attribute__((unused)) char *argv[], __attribute__((unused)) char *envp[])
524 : : {
525 : 15229 : Init ();
526 : 15229 : }
527 : :
528 : 0 : extern "C" void _M2_M2StackSpell_fini (__attribute__((unused)) int argc, __attribute__((unused)) char *argv[], __attribute__((unused)) char *envp[])
529 : : {
530 : 0 : }
|