Skip to content

Commit

Permalink
Yet more functionality in DecFileParser, with tests - take 3
Browse files Browse the repository at this point in the history
  • Loading branch information
eduardo-rodrigues committed Apr 24, 2019
1 parent eef69d7 commit 55c575b
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 19 deletions.
85 changes: 66 additions & 19 deletions decaylanguage/dec/dec.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class DecFileParser(object):

__slots__ = ("_grammar",
"_grammar_info",
"_decay_file",
"_dec_file_name",
"_parsed_dec_file",
"_parsed_decays")

Expand All @@ -53,7 +53,7 @@ def __init__(self, filename):
self._grammar_info = None # Name of Lark grammar definition file

# Conversion to handle pathlib on Python < 3.6:
self._decay_file = str(filename) # Name of the input decay file
self._dec_file_name = str(filename) # Name of the input decay file
self._parsed_dec_file = None # Parsed decay file

self._parsed_decays = None # Particle decays found in the decay file
Expand All @@ -65,7 +65,7 @@ def from_file(cls, filename):
Parameters
----------
decay_file: str
filename: str
Input .dec decay file name.
"""
# Conversion to handle pathlib on Python < 3.6:
Expand All @@ -79,12 +79,13 @@ def from_file(cls, filename):

def parse(self):
"""
Parse the given .dec decay file according to default Lark options
parser = 'lalr'
lexer = 'standard'
Parse the given .dec decay file according to default Lark parser
and specified options, i.e.,
parser = 'lalr',
lexer = 'standard'.
See method 'load_grammar' for how to explicitly set the Lark parser
and the parsing options.
See method 'load_grammar' for how to explicitly define the grammar
and set the Lark parsing options.
"""
# Has a file been parsed already?
if self._parsed_decays is not None:
Expand All @@ -94,16 +95,18 @@ def parse(self):
# effectively loading it
opts = self.grammar_info()

# Instantiate the Lark parser according to chosen settings
parser = Lark(self.grammar(), parser=opts['parser'], lexer=opts['lexer'])

decay_file = open(self._decay_file).read()
self._parsed_dec_file = parser.parse(decay_file)
dec_file = open(self._dec_file_name).read()
self._parsed_dec_file = parser.parse(dec_file)

# At last, find all particle decays defined in the .dec decay file
self._find_parsed_decays()

def grammar(self):
"""
This accesses the internal Lark grammar definition file,
Access the internal Lark grammar definition file,
loading it from the default location if needed.
Returns
Expand All @@ -118,7 +121,13 @@ def grammar(self):

def grammar_info(self):
"""
Access the internal Lark grammar definition file name and
parser options, loading the grammar from the default location if needed.
Returns
-------
out: dict
The Lark grammar definition file name and parser options.
"""
if not self.grammar_loaded:
self.load_grammar()
Expand All @@ -127,7 +136,8 @@ def grammar_info(self):

def load_grammar(self, filename=None, parser='lalr', lexer='standard', **options):
"""
Load a Lark grammar definition file.
Load a Lark grammar definition file, either the default one,
or a user-specified one, optionally setting Lark parsing options.
Parameters
----------
Expand All @@ -139,6 +149,7 @@ def load_grammar(self, filename=None, parser='lalr', lexer='standard', **options
The Lark parser lexer mode to use.
options: keyword arguments, optional
Extra options to pass on to the parsing algorithm.
See Lark's Lark class for a description of available options
for parser, lexer and options.
"""
Expand Down Expand Up @@ -237,15 +248,24 @@ def list_charge_conjugate_decays(self):
return get_charge_conjugate_decays(self._parsed_dec_file)

def _find_parsed_decays(self):
"""Find all Tree instances of Tree.data='decay'."""
"""
Return a tuple of all decay definitions in the input parsed file,
of the form
"Decay <MOTHER>",
as a tuple of Lark Tree instances with Tree.data=='decay', i.e.,
(Tree(decay, [Tree(particle, [Token(LABEL, <MOTHER1>]), ...),
Tree(decay, [Tree(particle, [Token(LABEL, <MOTHER2>]), ...)).
Note
----
Method not meant to be used directly!
"""
if self._parsed_dec_file is not None:
self._parsed_decays = tuple(self._parsed_dec_file.find_data('decay'))
self._parsed_decays = get_decays(self._parsed_dec_file)

# Check for duplicates - should be considered a bug in the .dec file!
self._check_parsed_decays()

return self._parsed_decays

def _check_parsing(self):
"""Has the .parse() method been called already?"""
if self._parsed_dec_file is None:
Expand Down Expand Up @@ -393,10 +413,10 @@ def build_decay_chain(self, mother, stable_particles=[]):
def __repr__(self):
if self._parsed_dec_file is not None:
return "<{self.__class__.__name__}: decfile='{decfile}', n_decays={n_decays}>".format(
self=self, decfile=self._decay_file, n_decays=self.number_of_decays)
self=self, decfile=self._dec_file_name, n_decays=self.number_of_decays)
else:
return "<{self.__class__.__name__}: decfile='{decfile}'>"\
.format(self=self, decfile=self._decay_file)
.format(self=self, decfile=self._dec_file_name)

def __str__(self):
return repr(self)
Expand Down Expand Up @@ -456,6 +476,29 @@ def get_model_parameters(decay_mode):
return [float(tree.children[0].value) for tree in lmo[0].children] if len(lmo) == 1 else ''


def get_decays(parsed_file):
"""
Return a tuple of all decay definitions in the input parsed file,
of the form
"Decay <MOTHER>",
as a tuple of Lark Tree instances with Tree.data=='decay', i.e.,
(Tree(decay, [Tree(particle, [Token(LABEL, <MOTHER1>]), ...),
Tree(decay, [Tree(particle, [Token(LABEL, <MOTHER2>]), ...)).
Parameters
----------
parsed_file: Lark Tree instance
Input parsed file.
"""
if not isinstance(parsed_file, Tree) :
raise RuntimeError("Input not an instance of a Tree!")

try:
return tuple(parsed_file.find_data('decay'))
except:
RuntimeError("Input parsed file does not seem to have the expected structure.")


def get_definitions(parsed_file):
"""
Return a dictionary of all definitions in the input parsed file, of the form
Expand Down Expand Up @@ -599,8 +642,12 @@ def get_global_photos_flag(parsed_file):

# Check if the flag is not set more than once, just in case ...
tree = tuple(parsed_file.find_data('global_photos'))
if len(tree) != 1:
print('TREE:', tree)
if len(tree) == 0:
return PhotosEnum.no
elif len(tree) > 1:
warnings.warn("PHOTOS flag re-set! Using flag set in last ...")

tree = tree[-1]

try:
Expand Down
5 changes: 5 additions & 0 deletions tests/test_dec.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ def test_global_photos_flag():

assert p.global_photos_flag() == True

def test_missing_global_photos_flag():
p = DecFileParser.from_file(DIR / 'data/test_example_Dst.dec')
p.parse()

assert p.global_photos_flag() == False

def test_list_charge_conjugate_decays():
p = DecFileParser.from_file(DIR / 'data/test_Bd2DmTauNu_Dm23PiPi0_Tau2MuNu.dec')
Expand Down

0 comments on commit 55c575b

Please sign in to comment.