summary refs log tree commit diff stats
path: root/tools/grammar_nanny.nim
diff options
context:
space:
mode:
Diffstat (limited to 'tools/grammar_nanny.nim')
-rw-r--r--tools/grammar_nanny.nim54
1 files changed, 54 insertions, 0 deletions
diff --git a/tools/grammar_nanny.nim b/tools/grammar_nanny.nim
new file mode 100644
index 000000000..cbdc51efc
--- /dev/null
+++ b/tools/grammar_nanny.nim
@@ -0,0 +1,54 @@
+## Simple tool to check for obvious mistakes in Nim's
+## grammar.txt file.
+
+import std / [strutils, sets]
+
+when defined(nimPreviewSlimSystem):
+  import std/syncio
+
+import ".." / compiler / [
+  llstream, lexer, options, msgs, idents,
+  lineinfos, pathutils]
+
+proc checkGrammarFileImpl(cache: IdentCache, config: ConfigRef) =
+  var f = AbsoluteFile"doc/grammar.txt"
+  let data = readFile(f.string).multiReplace({"IND{=}": "SAME_IND", "'": "\""})
+  var stream = llStreamOpen(data)
+  var declaredSyms = initHashSet[string]()
+  var usedSyms = initHashSet[string]()
+  usedSyms.incl "module" # 'module' is the start rule.
+  if stream != nil:
+    declaredSyms.incl "section" # special case for 'section(RULE)' in the grammar
+    var
+      L: Lexer
+      tok: Token
+    openLexer(L, f, stream, cache, config)
+    # load the first token:
+    rawGetTok(L, tok)
+    var word = ""
+    while tok.tokType != tkEof:
+      #printTok(config, tok)
+      if isKeyword(tok.tokType) or tok.tokType == tkSymbol:
+        word = tok.ident.s
+        rawGetTok(L, tok)
+        if tok.tokType == tkEquals:
+          declaredSyms.incl word
+          rawGetTok(L, tok)
+        elif not allCharsInSet(word, {'A'..'Z', '0'..'9', '_'}):
+          usedSyms.incl word
+      else:
+        rawGetTok(L, tok)
+    for u in declaredSyms:
+      if u notin usedSyms:
+        echo "Unused non-terminal: ", u
+
+    for u in usedSyms:
+      if u notin declaredSyms:
+        echo "Undeclared non-terminal: ", u
+
+    closeLexer(L)
+  else:
+    rawMessage(config, errGenerated, "cannot open file: " & f.string)
+
+proc checkGrammarFile* =
+  checkGrammarFileImpl(newIdentCache(), newConfigRef())