2017-05-08 13:37:48 +08:00
|
|
|
#! /usr/bin/python
|
|
|
|
|
|
|
|
"""
|
|
|
|
Find all .g4 files and generate parsers in the same directory.
|
|
|
|
the antlr used should be the one located at user's mvn directory
|
|
|
|
the filename is antlr4-ANTLR_VERSION-SNAPSHOT.jar. You can get it
|
|
|
|
by running: "mvn install"
|
|
|
|
|
|
|
|
NOTE: In case of customized location of .m2 folder, you can change the
|
|
|
|
USER_M2 constant below.
|
|
|
|
|
|
|
|
the java version is used according to environment variable $JAVA_HOME.
|
|
|
|
"""
|
2017-05-10 12:31:32 +08:00
|
|
|
import glob
|
2017-05-09 13:06:31 +08:00
|
|
|
import shutil
|
|
|
|
import argparse
|
2017-05-08 13:37:48 +08:00
|
|
|
import fnmatch
|
|
|
|
import os.path
|
2017-05-09 13:06:31 +08:00
|
|
|
import time
|
2017-05-08 13:37:48 +08:00
|
|
|
from subprocess import call
|
|
|
|
|
2017-05-10 12:31:32 +08:00
|
|
|
|
|
|
|
# ANTLR Version, here we only care about major version.
|
|
|
|
MAJOR_VERSION = "4"
|
|
|
|
|
|
|
|
# Note: User defines their own M2_HOME should change this variable.
|
|
|
|
USER_M2 = os.path.expanduser("~") + "/.m2"
|
2017-05-08 13:48:36 +08:00
|
|
|
TMP_FOLDER = "/tmp/"
|
2017-05-10 12:31:32 +08:00
|
|
|
|
|
|
|
# The directory contains this script.
|
2017-05-09 13:06:31 +08:00
|
|
|
DIR = os.path.dirname(os.path.realpath(__file__))
|
|
|
|
|
2017-05-10 12:31:32 +08:00
|
|
|
# The following two are using glob syntax.
|
|
|
|
ANTLR4_FOLDER = USER_M2 + "/repository/org/antlr/antlr4/*-SNAPSHOT"
|
|
|
|
ANTLR4 = ANTLR4_FOLDER + "/antlr4-*-SNAPSHOT-complete.jar"
|
|
|
|
|
2017-05-09 13:06:31 +08:00
|
|
|
# Colors
|
|
|
|
RED = "\033[91;1m"
|
|
|
|
GREEN = "\033[32;1m"
|
|
|
|
YELLOW = "\033[93;1m"
|
|
|
|
CYAN = "\033[36;1m"
|
|
|
|
GREY = "\033[38;2;127;127;127m"
|
|
|
|
RESET = "\033[0m"
|
2017-05-08 13:37:48 +08:00
|
|
|
|
|
|
|
|
2017-05-10 12:31:32 +08:00
|
|
|
def find_a4_jar():
|
2017-05-08 13:37:48 +08:00
|
|
|
"""
|
|
|
|
Finds the antlr4 jar.
|
|
|
|
"""
|
2017-05-10 12:31:32 +08:00
|
|
|
matches = glob.glob(ANTLR4)
|
|
|
|
if len(matches) == 0:
|
|
|
|
return None
|
|
|
|
sorted(matches, reverse=True)
|
|
|
|
return matches[0]
|
2017-05-08 13:37:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
def find_g4():
|
|
|
|
"""
|
|
|
|
Find all g4 files and return a list of them.
|
|
|
|
The recursive search starts from the directory containing
|
|
|
|
this python file.
|
|
|
|
"""
|
|
|
|
file_path = os.path.realpath(__file__)
|
|
|
|
parent_folder = file_path[0:file_path.rindex("/") + 1]
|
|
|
|
res = []
|
|
|
|
for cur, _, filenames in os.walk(parent_folder):
|
|
|
|
cur_files = fnmatch.filter(filenames, "*.g4")
|
|
|
|
res += [cur + "/" + cur_file for cur_file in cur_files]
|
|
|
|
return res
|
|
|
|
|
|
|
|
|
2017-05-10 12:31:32 +08:00
|
|
|
def gen_parser(grammar, a4):
|
2017-05-08 13:37:48 +08:00
|
|
|
"""
|
|
|
|
Generate parser for the input g4 file.
|
2017-05-10 12:31:32 +08:00
|
|
|
:param grammar: grammar file
|
|
|
|
:param a4: antlr4 runtime
|
|
|
|
:return: None
|
2017-05-08 13:37:48 +08:00
|
|
|
"""
|
|
|
|
grammar_folder = grammar[0:grammar.rindex("/") + 1]
|
|
|
|
java_home = os.environ["JAVA_HOME"]
|
|
|
|
java = java_home + "/bin/java"
|
|
|
|
if not os.path.exists(java):
|
2017-05-09 13:06:31 +08:00
|
|
|
antlr_complains("Cannot find java. Check your JAVA_HOME setting.")
|
2017-05-08 13:37:48 +08:00
|
|
|
return
|
|
|
|
|
2017-05-10 12:31:32 +08:00
|
|
|
call([java, "-jar", a4,
|
2017-05-08 13:37:48 +08:00
|
|
|
"-Dlanguage=Swift", grammar, "-visitor",
|
|
|
|
"-o", grammar_folder + "/gen"])
|
|
|
|
|
|
|
|
|
|
|
|
def swift_test():
|
|
|
|
"""
|
|
|
|
Run unit tests.
|
|
|
|
"""
|
2017-05-09 13:35:36 +08:00
|
|
|
generate_parser()
|
2017-05-08 13:37:48 +08:00
|
|
|
call(["swift", "test"])
|
|
|
|
|
|
|
|
|
|
|
|
def get_argument_parser():
|
2017-05-08 13:48:36 +08:00
|
|
|
"""
|
|
|
|
Initialize argument parser.
|
|
|
|
:return: the argument parser
|
|
|
|
"""
|
|
|
|
p = argparse.ArgumentParser(description="Helper script for ANTLR4 Swift target. "
|
|
|
|
"<DEVELOPER> flag means the command is mostly used by a developer. "
|
|
|
|
"<USER> flag means the command should be used by user. ")
|
2017-05-08 13:37:48 +08:00
|
|
|
p.add_argument("--gen-spm-module",
|
|
|
|
action="store_true",
|
2017-05-08 13:48:36 +08:00
|
|
|
help="<USER> Generates a Swift Package Manager flavored module. "
|
2017-05-08 13:37:48 +08:00
|
|
|
"Use this command if you want to include ANTLR4 as SPM dependency.", )
|
|
|
|
p.add_argument("--gen-xcodeproj",
|
|
|
|
action="store_true",
|
2017-05-08 13:48:36 +08:00
|
|
|
help="<DEVELOPER> Generates an Xcode project for ANTLR4 Swift runtime. "
|
|
|
|
"This directive will generate all the required parsers for the project. "
|
|
|
|
"Feel free to re-run whenever you updated the test grammar files.")
|
2017-05-08 13:37:48 +08:00
|
|
|
p.add_argument("--test",
|
|
|
|
action="store_true",
|
2017-05-08 13:48:36 +08:00
|
|
|
help="<DEVELOPER> Run unit tests.")
|
2017-05-08 13:37:48 +08:00
|
|
|
return p
|
|
|
|
|
|
|
|
|
2017-05-08 13:48:36 +08:00
|
|
|
def generate_spm_module(in_folder=TMP_FOLDER):
|
|
|
|
"""
|
|
|
|
Generate spm module in the specified folder, default
|
|
|
|
to the system's tmp folder.
|
|
|
|
|
|
|
|
After generation, user can simply use the prompt SPM
|
|
|
|
code to include the ANTLR4 Swift runtime package.
|
2017-05-09 13:06:31 +08:00
|
|
|
:param in_folder: the folder where we generate the SPM module.
|
2017-05-08 13:48:36 +08:00
|
|
|
:return: None
|
|
|
|
"""
|
2017-05-09 13:06:31 +08:00
|
|
|
|
|
|
|
tmp_antlr_folder = in_folder + "Antlr4-tmp-" + str(int(time.time()))
|
|
|
|
os.mkdir(tmp_antlr_folder)
|
|
|
|
|
|
|
|
# Copy folders and SPM manifest file.
|
|
|
|
dirs_to_copy = ["Sources", "Tests"]
|
|
|
|
for dir_to_copy in dirs_to_copy:
|
|
|
|
shutil.copytree(DIR + "/" + dir_to_copy, tmp_antlr_folder + "/" + dir_to_copy)
|
|
|
|
|
|
|
|
shutil.copy("Package.swift", tmp_antlr_folder)
|
|
|
|
|
|
|
|
os.chdir(tmp_antlr_folder)
|
|
|
|
call(["git", "init"])
|
|
|
|
call(["git", "add", "*"])
|
|
|
|
call(["git", "commit", "-m", "Initial commit."])
|
2017-05-10 12:31:32 +08:00
|
|
|
call(["git", "tag", "{}.0.0".format(MAJOR_VERSION)])
|
2017-05-09 13:06:31 +08:00
|
|
|
|
|
|
|
antlr_says("Created local repository.")
|
2017-05-10 12:31:32 +08:00
|
|
|
antlr_says("Put .Package(url: \"{}\", majorVersion: {}) in Package.swift.".format(os.getcwd(), MAJOR_VERSION))
|
2017-05-08 13:37:48 +08:00
|
|
|
|
|
|
|
|
|
|
|
def generate_xcodeproj():
|
2017-05-08 13:48:36 +08:00
|
|
|
"""
|
|
|
|
Generates the ANTLR4 Swift runtime Xcode project.
|
|
|
|
|
|
|
|
This method will also generate parsers required by
|
|
|
|
the runtime tests.
|
|
|
|
:return:
|
|
|
|
"""
|
2017-05-09 13:35:36 +08:00
|
|
|
generate_parser()
|
|
|
|
call(["swift", "package", "generate-xcodeproj"])
|
|
|
|
|
|
|
|
|
|
|
|
def generate_parser():
|
2017-05-10 12:31:32 +08:00
|
|
|
antlr = find_a4_jar()
|
|
|
|
if antlr is None:
|
2017-05-09 13:35:36 +08:00
|
|
|
antlr_complains("Run \"mvn install\" in antlr4 project root first or check mvn settings")
|
|
|
|
exit()
|
|
|
|
|
2017-05-10 12:31:32 +08:00
|
|
|
_ = [gen_parser(f, antlr) for f in find_g4()]
|
2017-05-08 13:37:48 +08:00
|
|
|
|
|
|
|
|
2017-05-09 13:06:31 +08:00
|
|
|
def antlr_says(msg):
|
|
|
|
print GREEN + "[ANTLR] " + msg + RESET
|
|
|
|
|
|
|
|
|
|
|
|
def antlr_complains(msg):
|
|
|
|
print RED + "[ANTLR] " + msg + RESET
|
|
|
|
|
|
|
|
|
2017-05-08 13:37:48 +08:00
|
|
|
if __name__ == "__main__":
|
|
|
|
parser = get_argument_parser()
|
|
|
|
args = parser.parse_args()
|
|
|
|
if args.gen_spm_module:
|
|
|
|
generate_spm_module()
|
|
|
|
elif args.gen_xcodeproj:
|
|
|
|
generate_xcodeproj()
|
|
|
|
elif args.test:
|
|
|
|
swift_test()
|
|
|
|
else:
|
|
|
|
parser.print_help()
|