Skip to content

Commit

Permalink
Merge 95faaad into 213dc97
Browse files Browse the repository at this point in the history
  • Loading branch information
ferraith committed Jul 28, 2018
2 parents 213dc97 + 95faaad commit 219ba8b
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 37 deletions.
18 changes: 11 additions & 7 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ See ``python setup.py antlr --help`` for available command line options:
...
Options for 'AntlrCommand' command:
--grammars (-g) specify grammars to generate parsers for
--output (-o) specify output directories where output is generated
--output (-o) specify directories where output is generated
--dependencies (-d) generate parser for every grammar a passed grammar depends on
--atn generate rule augmented transition network diagrams
--encoding specify grammar file encoding e.g. euc-jp
--message-format specify output style for messages in antlr, gnu, vs2005
Expand All @@ -124,7 +125,7 @@ See ``python setup.py antlr --help`` for available command line options:
--no-listener don't generate parse tree listener
--visitor generate parse tree visitor
--no-visitor don't generate parse tree visitor (default)
--depend generate file dependencies
--file-dependencies generate list of file dependencies instead of parsers
--grammar-options set/override a grammar-level option
--w-error treat warnings as error
--x-dbg-st launch StringTemplate visualizer on generated code
Expand All @@ -142,9 +143,12 @@ Apart from passing options on the command line it's also possible to add a dedic
[antlr]
# Specify grammars to generate parsers for; default: None
#grammars = <root-level grammar> [<root-level-grammar> ...]
# Specify output directories where all output is generated; default: ./
output = default=gen
#grammars = <grammar> [<grammar> ...]
# Specify directories where output is generated; default: ./
#output = [default=<output path>]
# [<grammar>=<output path> ...]
# Generate parser for every grammar a passed grammar depends on (yes|no); default: no
#dependencies = no
# Generate DOT graph files that represent the internal ATN data structures (yes|no); default: no
#atn = no
# Specify grammar file encoding; default: utf-8
Expand All @@ -157,8 +161,8 @@ Apart from passing options on the command line it's also possible to add a dedic
#listener = yes
# Generate parse tree visitor (yes|no); default: no
visitor = yes
# Generate file dependencies (yes|no); default: no
#depend = no
# Generate list of file dependencies instead of parsers (yes|no); default: no
#file-dependencies = no
# Set/override grammar-level options (<option>=<value> [<option>=value ...]); default: language=Python3
grammar-options = superClass=Abc
tokenVocab=SomeLexer
Expand Down
12 changes: 7 additions & 5 deletions example/setup.cfg
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
[antlr]
# Specify grammars to generate parsers for; default: None
#grammars = <root-level grammar> [<root-level-grammar> ...]
# Specify output directories where output is generated; default: ./
#grammars = <grammar> [<grammar> ...]
# Specify directories where output is generated; default: ./
#output = [default=<output path>]
# [<root-level grammar>=<output path> ...]
# [<grammar>=<output path> ...]
# Generate parser for every grammar a passed grammar depends on (yes|no); default: no
#dependencies = no
# Generate DOT graph files that represent the internal ATN data structures (yes|no); default: no
#atn = no
# Specify grammar file encoding; default: utf-8
Expand All @@ -16,8 +18,8 @@
#listener = yes
# Generate parse tree visitor (yes|no); default: no
#visitor = no
# Generate file dependencies (yes|no); default: no
#depend = no
# Generate list of file dependencies instead of parsers (yes|no); default: no
#file-dependencies = no
# Set/override grammar-level options (<option>=<value> [<option>=value ...]); default: language=Python3
# Documentation of all grammar-level options
# See https://github.com/antlr/antlr4/blob/master/doc/options.md
Expand Down
33 changes: 17 additions & 16 deletions setuptools_antlr/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ class AntlrCommand(setuptools.Command):

user_options = [
('grammars=', 'g', 'specify grammars to generate parsers for'),
('output=', 'o', 'specify output directories where output is generated'),
('output=', 'o', 'specify directories where output is generated'),
('dependencies=', 'd', 'generate parser for every grammar a passed grammar depends on'),
('atn', None, 'generate rule augmented transition network diagrams'),
('encoding=', None, 'specify grammar file encoding e.g. euc-jp'),
('message-format=', None, 'specify output style for messages in antlr, gnu, vs2005'),
Expand All @@ -119,7 +120,7 @@ class AntlrCommand(setuptools.Command):
('no-listener', None, 'don\'t generate parse tree listener'),
('visitor', None, 'generate parse tree visitor'),
('no-visitor', None, 'don\'t generate parse tree visitor (default)'),
('depend', None, 'generate file dependencies'),
('file-dependencies', None, 'generate list of file dependencies instead of parsers'),
('grammar-options=', None, "set/override a grammar-level options"),
('w-error', None, 'treat warnings as error'),
('x-dbg-st', None, 'launch StringTemplate visualizer on generated code'),
Expand All @@ -130,8 +131,8 @@ class AntlrCommand(setuptools.Command):
]

boolean_options = ['atn', 'long-messages', 'listener', 'no-listener', 'visitor', 'no-visitor',
'depend', 'w-error', 'x-dbg-st', 'x-dbg-st-wait', 'x-exact-output-dir',
'x-force-atn', 'x-log']
'file-dependencies', 'w-error', 'x-dbg-st', 'x-dbg-st-wait',
'x-exact-output-dir', 'x-force-atn', 'x-log']

negative_opt = {'no-listener': 'listener', 'no-visitor': 'visitor'}

Expand All @@ -142,13 +143,14 @@ def initialize_options(self):
"""
self.grammars = None
self.output = {}
self.dependencies = 0
self.atn = 0
self.encoding = None
self.message_format = None
self.long_messages = 0
self.listener = 1
self.visitor = 0
self.depend = 0
self.file_dependencies = 0
self.grammar_options = {}
self.w_error = 0
self.x_dbg_st = 0
Expand Down Expand Up @@ -245,7 +247,6 @@ def _find_antlr_log(cls, log_path: pathlib.Path) -> pathlib.Path:

def _find_grammars(self, base_path: pathlib.Path=pathlib.Path('.')) -> typing.List[AntlrGrammar]:
"""Searches for all ANTLR grammars starting from base directory and returns a list of it.
Only grammars which aren't included by other grammars are part of this list.
:param base_path: base path to search for ANTLR grammars
:return: a list of all found ANTLR grammars
Expand All @@ -270,7 +271,6 @@ def get_grammar(name: str) -> AntlrGrammar:
grammars.append(AntlrGrammar(pathlib.Path(root, fb)))

# generate a dependency tree for each grammar
grammar_tree = []
try:
for grammar in grammars:
imports = grammar.read_imports()
Expand All @@ -284,12 +284,8 @@ def get_grammar(name: str) -> AntlrGrammar:
raise distutils.errors.DistutilsFileError('Imported grammar "{}" in file "{}" isn\'t '
'present in package source directory.'.format(
str(e), str(e.parent.path)))
else:
# remove all grammars which aren't the root of a dependency tree
grammar_tree[:] = filter(lambda r: all(r not in g.dependencies for g in grammars),
grammars)

return grammar_tree
return grammars

@classmethod
def _create_init_file(cls, path: pathlib.Path) -> bool:
Expand Down Expand Up @@ -318,10 +314,15 @@ def run(self):
if not antlr_jar:
raise distutils.errors.DistutilsExecError('no ANTLR jar was found in lib directory')

# find grammars and filter result if grammars are passed by user
# find grammars
grammars = self._find_grammars()

# remove all grammars which aren't the root of a dependency tree
grammars[:] = filter(lambda r: all(r not in g.dependencies for g in grammars), grammars)

# filter found grammars if grammars are passed by user
if self.grammars:
grammars = filter(lambda g: g.name in self.grammars, grammars)
grammars[:] = filter(lambda g: g.name in self.grammars, grammars)

# generate parser for each grammar
for grammar in grammars:
Expand All @@ -337,7 +338,7 @@ def run(self):
run_args.append('-long-messages')
run_args.append('-listener' if self.listener else '-no-listener')
run_args.append('-visitor' if self.visitor else '-no-visitor')
if self.depend:
if self.file_dependencies:
run_args.append('-depend')
run_args.extend(['-D{}={}'.format(option, value) for option, value in
self.grammar_options.items()])
Expand Down Expand Up @@ -384,7 +385,7 @@ def run(self):
grammar_file = grammar.path.name
run_args.append(str(grammar_file))

if self.depend:
if self.file_dependencies:
dependency_file = pathlib.Path(package_dir, 'dependencies.txt')
distutils.log.info('generating {} file dependencies -> {}'.format(grammar_file,
dependency_file))
Expand Down
28 changes: 19 additions & 9 deletions test/test_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,15 +132,25 @@ def test_find_grammars_standalone(self, command):
def test_find_grammars_distributed(self, command):
g = command._find_grammars(pathlib.Path('distributed'))

assert len(g) == 1
assert g[0].name == 'SomeGrammar'
assert len(g) == 3

assert g[0].name == 'CommonTerminals'
d = g[0].dependencies
assert len(d) == 0

assert g[1].name == 'SharedRules'
d = g[1].dependencies
assert len(d) == 1
assert d[0].name == 'CommonTerminals'

assert g[2].name == 'SomeGrammar'
d = g[2].dependencies
assert len(d) == 2
assert d[0].name == 'CommonTerminals'
assert d[1].name == 'SharedRules'
dd = g[0].dependencies[0].dependencies
dd = g[2].dependencies[0].dependencies
assert len(dd) == 0
dd = g[0].dependencies[1].dependencies
dd = g[2].dependencies[1].dependencies
assert len(dd) == 1
assert dd[0].name == 'CommonTerminals'

Expand Down Expand Up @@ -183,7 +193,7 @@ def test_finalize_options_default(self, command):
assert command.long_messages == 0
assert command.listener == 1
assert command.visitor == 0
assert command.depend == 0
assert command.file_dependencies == 0
assert command.grammar_options['language'] == 'Python3'
assert command.w_error == 0
assert command.x_dbg_st == 0
Expand Down Expand Up @@ -553,10 +563,10 @@ def test_run_grammar_options_not_specified(self, mock_run, configured_command):

@pytest.mark.usefixtures('configured_command')
@unittest.mock.patch('subprocess.run')
def test_run_depend_enabled(self, mock_run, configured_command):
def test_run_file_dependencies_enabled(self, mock_run, configured_command):
mock_run.return_value = unittest.mock.Mock(returncode=0, stdout='FooParser.py : Foo.g4')

configured_command.depend = 1
configured_command.file_dependencies = 1
configured_command.run()

args, _ = mock_run.call_args
Expand All @@ -565,9 +575,9 @@ def test_run_depend_enabled(self, mock_run, configured_command):

@pytest.mark.usefixtures('configured_command')
@unittest.mock.patch('subprocess.run')
def test_run_depend_disabled(self, mock_run, configured_command):
def test_run_file_dependencies_disabled(self, mock_run, configured_command):
mock_run.return_value = unittest.mock.Mock(returncode=0)
configured_command.depend = 0
configured_command.file_dependencies = 0
configured_command.run()

args, _ = mock_run.call_args
Expand Down

0 comments on commit 219ba8b

Please sign in to comment.