grammar_nanny.nim 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. ## Simple tool to check for obvious mistakes in Nim's
  2. ## grammar.txt file.
  3. import std / [strutils, sets]
  4. when defined(nimPreviewSlimSystem):
  5. import std/syncio
  6. import ".." / compiler / [
  7. llstream, lexer, options, msgs, idents,
  8. lineinfos, pathutils]
  9. proc checkGrammarFileImpl(cache: IdentCache, config: ConfigRef) =
  10. var f = AbsoluteFile"doc/grammar.txt"
  11. let data = readFile(f.string).multiReplace({"IND{=}": "SAME_IND", "'": "\""})
  12. var stream = llStreamOpen(data)
  13. var declaredSyms = initHashSet[string]()
  14. var usedSyms = initHashSet[string]()
  15. usedSyms.incl "module" # 'module' is the start rule.
  16. if stream != nil:
  17. declaredSyms.incl "section" # special case for 'section(RULE)' in the grammar
  18. var
  19. L: Lexer
  20. tok: Token
  21. openLexer(L, f, stream, cache, config)
  22. # load the first token:
  23. rawGetTok(L, tok)
  24. var word = ""
  25. while tok.tokType != tkEof:
  26. #printTok(config, tok)
  27. if isKeyword(tok.tokType) or tok.tokType == tkSymbol:
  28. word = tok.ident.s
  29. rawGetTok(L, tok)
  30. if tok.tokType == tkEquals:
  31. declaredSyms.incl word
  32. rawGetTok(L, tok)
  33. elif not allCharsInSet(word, {'A'..'Z', '0'..'9', '_'}):
  34. usedSyms.incl word
  35. else:
  36. rawGetTok(L, tok)
  37. for u in declaredSyms:
  38. if u notin usedSyms:
  39. echo "Unused non-terminal: ", u
  40. for u in usedSyms:
  41. if u notin declaredSyms:
  42. echo "Undeclared non-terminal: ", u
  43. closeLexer(L)
  44. else:
  45. rawMessage(config, errGenerated, "cannot open file: " & f.string)
  46. proc checkGrammarFile* =
  47. checkGrammarFileImpl(newIdentCache(), newConfigRef())