• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

idaholab / MontePy / 15498666780

06 Jun 2025 07:56PM UTC coverage: 97.825% (-0.3%) from 98.168%
15498666780

push

github

web-flow
Merge pull request #767 from idaholab/755-parser-is-confused-by-x-and-y-in-sdef

Fixed parser bug with SDEF with X and Y

24 of 24 new or added lines in 3 files covered. (100.0%)

29 existing lines in 1 file now uncovered.

7870 of 8045 relevant lines covered (97.82%)

0.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.46
/montepy/input_parser/data_parser.py
1
# Copyright 2024, Battelle Energy Alliance, LLC All Rights Reserved.
2
from montepy.errors import *
1✔
3
from montepy.input_parser.tokens import DataLexer
1✔
4
from montepy.input_parser.parser_base import MCNP_Parser, MetaBuilder
1✔
5
from montepy.input_parser import syntax_node
1✔
6

7

8
class DataParser(MCNP_Parser):
1✔
9
    """A parser for almost all data inputs.
10

11
    Returns
12
    -------
13
    SyntaxNode
14
        a syntax tree for the data input.
15
    """
16

17
    debugfile = None
1✔
18

19
    @_(
1✔
20
        "introduction",
21
        "introduction data",
22
        "introduction data parameters",
23
        "introduction parameters",
24
    )
25
    def data_input(self, p):
1✔
26
        ret = {}
1✔
27
        for key, node in p.introduction.nodes.items():
1✔
28
            ret[key] = node
1✔
29
        if hasattr(p, "data"):
1✔
30
            ret["data"] = p.data
1✔
31
        else:
32
            ret["data"] = syntax_node.ListNode("empty data")
1✔
33
        if hasattr(p, "parameters"):
1✔
34
            ret["parameters"] = p.parameters
1✔
35
        return syntax_node.SyntaxNode("data", ret)
1✔
36

37
    @_(
1✔
38
        "classifier_phrase",
39
        "classifier_phrase MODIFIER padding",
40
        "padding classifier_phrase",
41
        "padding classifier_phrase MODIFIER padding",
42
    )
43
    def introduction(self, p):
1✔
44
        ret = {}
1✔
45
        if isinstance(p[0], syntax_node.PaddingNode):
1✔
46
            ret["start_pad"] = p[0]
1✔
47
        else:
48
            ret["start_pad"] = syntax_node.PaddingNode()
1✔
49
        ret["classifier"] = p.classifier_phrase
1✔
50
        if hasattr(p, "MODIFIER"):
1✔
51
            ret["keyword"] = syntax_node.ValueNode(p.MODIFIER, str, padding=p[-1])
1✔
52
        else:
53
            ret["keyword"] = syntax_node.ValueNode(None, str, padding=None)
1✔
54
        return syntax_node.SyntaxNode("data intro", ret)
1✔
55

56
    @_(
1✔
57
        "number_sequence",
58
        "isotope_fractions",
59
        "particle_sequence",
60
        "text_sequence",
61
        "kitchen_sink",
62
    )
63
    def data(self, p):
1✔
64
        return p[0]
1✔
65

66
    @_("zaid_phrase number_phrase")
1✔
67
    def isotope_fraction(self, p):
1✔
68
        return p
1✔
69

70
    @_("isotope_fraction", "isotope_fractions isotope_fraction")
1✔
71
    def isotope_fractions(self, p):
1✔
72
        if hasattr(p, "isotope_fractions"):
1✔
73
            fractions = p.isotope_fractions
×
74
        else:
75
            fractions = syntax_node.MaterialsNode("isotope list")
1✔
76
        fractions.append_nuclide(p.isotope_fraction)
1✔
77
        return fractions
1✔
78

79
    @_("ZAID", "ZAID padding")
1✔
80
    def zaid_phrase(self, p):
1✔
81
        return self._flush_phrase(p, str)
1✔
82

83
    @_("particle_phrase", "particle_sequence particle_phrase")
1✔
84
    def particle_sequence(self, p):
1✔
85
        if len(p) == 1:
1✔
86
            sequence = syntax_node.ListNode("particle sequence")
1✔
87
            sequence.append(p[0], True)
1✔
88
        else:
89
            sequence = p[0]
1✔
90
            sequence.append(p[1], True)
1✔
91
        return sequence
1✔
92

93
    @_("PARTICLE", "SURFACE_TYPE", "PARTICLE_SPECIAL")
1✔
94
    def particle_text(self, p):
1✔
95
        return p[0]
1✔
96

97
    @_("particle_text padding", "particle_text")
1✔
98
    def particle_phrase(self, p):
1✔
99
        return self._flush_phrase(p, str)
1✔
100

101
    # Manually specifying because more levels break SLY. Might be hitting some hard coded limit.
102
    @_(
1✔
103
        "NUMBER_WORD",
104
        "NUM_MULTIPLY",
105
        "NUMBER_WORD padding ",
106
        "NUM_MULTIPLY padding",
107
    )
108
    def text_phrase(self, p):
1✔
109
        self._flush_phrase(p, str)
1✔
110

111
    @_("text_phrase", "text_sequence text_phrase")
1✔
112
    def text_sequence(self, p):
1✔
113
        if len(p) == 1:
1✔
114
            sequence = syntax_node.ListNode("text sequence")
1✔
115
            sequence.append(p[0], True)
1✔
116
        else:
117
            sequence = p[0]
×
118
            sequence.append(p[1], True)
×
119
        return sequence
1✔
120

121
    @_("kitchen_junk", "kitchen_sink kitchen_junk")
1✔
122
    def kitchen_sink(self, p):
1✔
123
        sequence = p[0]
1✔
124
        if len(p) != 1:
1✔
125
            for node in p[1].nodes:
1✔
126
                sequence.append(node, True)
1✔
127
        return sequence
1✔
128

129
    @_("number_sequence", "text_sequence", "particle_sequence")
1✔
130
    def kitchen_junk(self, p):
1✔
131
        return p[0]
1✔
132

133
    @_("classifier param_seperator NUMBER text_phrase")
1✔
134
    def parameter(self, p):
1✔
135
        return syntax_node.SyntaxNode(
×
136
            p.classifier.prefix.value,
137
            {
138
                "classifier": p.classifier,
139
                "seperator": p.param_seperator,
140
                "data": syntax_node.ValueNode(p.NUMBER + p.text_phrase, str),
141
            },
142
        )
143

144

145
class ClassifierParser(DataParser):
1✔
146
    """A parser for parsing the first word or classifier of a data input.
147

148
    Returns
149
    -------
150
    ClassifierNode
151
        the classifier of the data input.
152
    """
153

154
    debugfile = None
1✔
155

156
    @_("classifier", "padding classifier")
1✔
157
    def data_classifier(self, p):
1✔
158
        if hasattr(p, "padding"):
1✔
159
            padding = p.padding
1✔
160
        else:
161
            padding = syntax_node.PaddingNode(None)
1✔
162
        return syntax_node.SyntaxNode(
1✔
163
            "data input classifier", {"start_pad": padding, "classifier": p.classifier}
164
        )
165

166

167
class ParamOnlyDataParser(DataParser):
1✔
168
    """A parser for parsing parameter (key-value pair) only data inputs.
169

170
    .e.g., SDEF
171

172
    .. versionadded:: 0.3.0
173

174
    Returns
175
    -------
176
    SyntaxNode
177
        a syntax tree for the data input.
178
    """
179

180
    debugfile = None
1✔
181

182
    @_(
1✔
183
        "param_introduction",
184
        "param_introduction spec_parameters",
185
    )
186
    def param_data_input(self, p):
1✔
UNCOV
187
        ret = {}
×
UNCOV
188
        for key, node in p.param_introduction.nodes.items():
×
UNCOV
189
            ret[key] = node
×
UNCOV
190
        if hasattr(p, "spec_parameters"):
×
UNCOV
191
            ret["parameters"] = p.spec_parameters
×
UNCOV
192
        return syntax_node.SyntaxNode("data", ret)
×
193

194
    @_(
1✔
195
        "classifier_phrase",
196
        "padding classifier_phrase",
197
    )
198
    def param_introduction(self, p):
1✔
UNCOV
199
        ret = {}
×
UNCOV
200
        if isinstance(p[0], syntax_node.PaddingNode):
×
201
            ret["start_pad"] = p[0]
×
202
        else:
UNCOV
203
            ret["start_pad"] = syntax_node.PaddingNode()
×
UNCOV
204
        ret["classifier"] = p.classifier_phrase
×
UNCOV
205
        ret["keyword"] = syntax_node.ValueNode(None, str, padding=None)
×
UNCOV
206
        return syntax_node.SyntaxNode("data intro", ret)
×
207

208
    @_("spec_parameter", "spec_parameters spec_parameter")
1✔
209
    def spec_parameters(self, p):
1✔
210
        """A list of the parameters (key, value pairs) for this input.
211

212
        Returns
213
        -------
214
        ParametersNode
215
            all parameters
216
        """
UNCOV
217
        if len(p) == 1:
×
UNCOV
218
            params = syntax_node.ParametersNode()
×
UNCOV
219
            param = p[0]
×
220
        else:
UNCOV
221
            params = p[0]
×
UNCOV
222
            param = p[1]
×
UNCOV
223
        params.append(param)
×
UNCOV
224
        return params
×
225

226
    @_("spec_classifier param_seperator data")
1✔
227
    def spec_parameter(self, p):
1✔
UNCOV
228
        return syntax_node.SyntaxNode(
×
229
            p.spec_classifier.prefix.value,
230
            {
231
                "classifier": p.spec_classifier,
232
                "seperator": p.param_seperator,
233
                "data": p.data,
234
            },
235
        )
236

237
    @_(
1✔
238
        "KEYWORD",
239
    )
240
    def spec_data_prefix(self, p):
1✔
UNCOV
241
        return syntax_node.ValueNode(p[0], str)
×
242

243
    @_(
1✔
244
        "modifier spec_data_prefix",
245
        "spec_data_prefix",
246
        "spec_classifier NUMBER",
247
        "spec_classifier particle_type",
248
    )
249
    def spec_classifier(self, p):
1✔
250
        """The classifier of a data input.
251

252
        This represents the first word of the data input.
253
        E.g.: ``M4``, `IMP:N`, ``F104:p``
254

255
        Returns
256
        -------
257
        ClassifierNode
258
        """
UNCOV
259
        if hasattr(p, "spec_classifier"):
×
260
            classifier = p.spec_classifier
×
261
        else:
UNCOV
262
            classifier = syntax_node.ClassifierNode()
×
263

UNCOV
264
        if hasattr(p, "modifier"):
×
265
            classifier.modifier = syntax_node.ValueNode(p.modifier, str)
×
UNCOV
266
        if hasattr(p, "spec_data_prefix"):
×
UNCOV
267
            classifier.prefix = p.spec_data_prefix
×
UNCOV
268
        if hasattr(p, "NUMBER"):
×
269
            classifier.number = syntax_node.ValueNode(p.NUMBER, int)
×
UNCOV
270
        if hasattr(p, "particle_type"):
×
271
            classifier.particles = p.particle_type
×
UNCOV
272
        return classifier
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc