Coverage for src/pyensae/languages/antlr_grammar_build.py: 7%
70 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-03 02:16 +0200
« prev ^ index » next coverage.py v7.2.7, created at 2023-07-03 02:16 +0200
1"""
2@file
3@brief Helpers to build grammars
4This module requires `antlr4 <http://www.antlr.org/>`_.
5and `antlr4-python3-runtime <https://pypi.python.org/pypi/antlr4-python3-runtime/>`_.
6"""
7import os
8import sys
9from pyquickhelper.loghelper import noLOG
12def _is_syntax_is_missing(language):
13 """
14 Downloads the grammar for a specific language if
15 the files is missing.
17 @param language language: python, sqlite, ...
18 @return grammar file
19 """
20 locations = {
21 "R": "https://github.com/antlr/grammars-v4/tree/master/r/",
22 "SQLite": "https://github.com/antlr/grammars-v4/blob/master/sqlite/",
23 "CSharp": "https://github.com/antlr/grammars-v4/tree/master/csharp",
24 }
26 folder = os.path.dirname(__file__)
27 filename = os.path.join(folder, language + ".g4")
28 if os.path.exists(filename):
29 return filename
30 if language in locations:
31 raise FileNotFoundError(
32 "The grammar '{0}' is not available, you should get "
33 "it from {1}".format(language, locations[language]))
34 raise KeyError(
35 "Unexpected language: '{0}', not in '{1}'".format(
36 language, ",".join(locations.keys())))
39def build_grammar(g4, version="4.10.1", fLOG=noLOG):
40 """
41 Compiles the grammar for a specific file.
43 @param g4 grammar format antlr4
44 @param version version of *antlr4* to use, 4.9
45 @param fLOG logging function
46 @return list of files
48 The compilation must be done with `antlr4 <http://www.antlr.org/>`_.
49 It generates a lexer and a parser which can be imported in Python.
50 The options for the command line are described at:
51 `antlr4 options
52 <https://theantlrguy.atlassian.net/wiki/display/ANTLR4/Options>`_.
54 .. exref::
55 :title: Builds a Antlr4 grammar
57 See `grammars-v4 <https://github.com/antlr/grammars-v4>`_
59 ::
61 build_grammar("R.g4")
62 """
63 if not g4.endswith(".g4"):
64 fold = os.path.abspath(os.path.dirname(__file__))
65 g4 = os.path.join(fold, g4 + ".g4")
67 url = "http://www.antlr.org/download/antlr-{0}-complete.jar".format(
68 version)
69 spl = url.split("/")
70 domain, name = "/".join(spl[:-1]) + "/", spl[-1]
71 folder = os.path.abspath(os.path.dirname(__file__))
72 final = os.path.join(folder, name)
74 if not os.path.exists(final):
75 from ..datasource.http_retrieve import download_data
76 name = download_data(name, website=domain, whereTo=folder)
77 if not os.path.exists(name):
78 raise FileNotFoundError("unable to download: " + url)
80 path = os.environ.get("CLASSPATH", "")
81 if name not in path:
82 path = ".;{0}\\antlr-{1}-complete.jar".format(folder, version)
83 else:
84 path = ".;{0}\\antlr-{1}-complete.jar;{2}".format(
85 folder,
86 version,
87 os.environ["CLASSPATH"])
89 os.environ["CLASSPATH"] = path
90 fLOG("CLASSPATH", os.environ["CLASSPATH"])
92 # we remove -rc...
93 version = version.split("-")[0]
95 cmd = "org.antlr.v4.Tool "
96 cmd += "-Dlanguage=Python3 "
97 cmd += g4
98 from pyquickhelper.loghelper import run_cmd
99 out, err = run_cmd("java " + cmd, wait=True, fLOG=fLOG)
101 def compiled():
102 if "Lexer" in g4:
103 lexer = g4.replace(".g4", ".tokens")
104 else:
105 lexer = g4.replace(".g4", ".py")
106 return os.path.exists(lexer)
108 if not compiled() or (len(err) > 0 and "error" in err):
110 javapath = r'C:\Program Files\Java\jre7\bin\java.exe'
111 os.environ["PATH"] = os.environ["PATH"] + ";" + javapath
112 if sys.platform.startswith("win") and os.path.exists(javapath):
113 out, err = run_cmd(
114 '"' + javapath + '" ' + cmd, wait=True, fLOG=fLOG)
115 if not compiled() or (len(err) > 0 and "error" in err):
116 raise Exception(
117 "unable to compile: " +
118 final +
119 "\nCLASSPATH:\n" +
120 os.environ["CLASSPATH"] +
121 "\nERR:\n" +
122 err +
123 "\nCMD:\njava " +
124 cmd +
125 "\nYou should do it manually.")
126 elif err:
127 err_lines = err.split(err)
128 err_lines = [_ for _ in err_lines if not _.startswith("warning(")]
129 err2 = "\n".join(err_lines).strip("\n ")
130 if len(err2) > 0:
131 raise Exception(
132 "unable to compile: " +
133 final +
134 "\nCLASSPATH:\n" +
135 os.environ["CLASSPATH"] +
136 "\nERR:\n" +
137 err +
138 "\nCMD:\njava " +
139 cmd)
141 if os.environ.get("USERNAME", os.environ.get("USER", "")) in g4:
142 dest = os.path.dirname(g4)
143 for name in os.listdir(dest):
144 if "Parser" not in name and "Lexer" not in name and \
145 "Token" not in name and "Listener" not in name:
146 continue
147 full = os.path.join(dest, name)
148 with open(full, "r", encoding="utf-8") as f:
149 content = f.read()
150 content1 = content.replace(dest, "")
151 if content1 != content:
152 fLOG("[build_grammar] modified", name)
153 with open(full, "w", encoding="utf-8") as f:
154 f.write(content1)
156 return out + "\n---ERR---\n" + err