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

rjfarmer / gfModParser / 19041620429

03 Nov 2025 04:27PM UTC coverage: 88.116% (+0.02%) from 88.099%
19041620429

push

github

rjfarmer
Remove line limits

1001 of 1136 relevant lines covered (88.12%)

0.88 hits per line

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

87.76
/gfModParser/modules/expressions.py
1
# SPDX-License-Identifier: GPL-2.0+
2
from packaging.version import Version
1✔
3

4
import numpy as np
1✔
5

6
from .. import utils
1✔
7

8
from . import procedures
1✔
9

10

11
class ExpGeneric:
1✔
12
    def __init__(self, type, kind, args, *, version: Version) -> None:
1✔
13
        self._args = args
1✔
14
        self.version = version
1✔
15
        self._type = type
1✔
16
        self.kind = kind
1✔
17

18
    def __str__(self):
1✔
19
        return self._type
×
20

21
    def __repr__(self):
1✔
22
        return self._type
1✔
23

24
    @property
1✔
25
    def value(self):
1✔
26
        return None
×
27

28
    def __eq__(self, key) -> bool:
1✔
29
        return self._type == key
1✔
30

31

32
class Expression:
1✔
33
    def __init__(self, expression, *, version: Version) -> None:
1✔
34
        self._expression = expression
1✔
35
        self.version = version
1✔
36
        t = self._expression[0]
1✔
37

38
        map = {
1✔
39
            "OP": ExpOp,
40
            "FUNCTION": ExpFunction,
41
            "CONSTANT": ExpConstant,
42
            "VARIABLE": ExpVariable,
43
            "SUBSTRING": ExpSubString,
44
            "STRUCTURE": ExpStructure,
45
            "ARRAY": ExpArray,
46
            "NULL": ExpNull,
47
            "COMPCALL": ExpCompCall,
48
            "PPC": ExpPPC,
49
            "CONDITIONAL": ExpConditional,
50
            "UNKNOWN": ExpUnknown,
51
        }
52

53
        self._exp = map[t](
1✔
54
            self.typespec.type,
55
            self.typespec.kind,
56
            self._expression,
57
            version=self.version,
58
        )
59

60
    @property
1✔
61
    def type(self) -> ExpGeneric:
1✔
62
        return self._exp
1✔
63

64
    @property
1✔
65
    def typespec(self) -> "typespec":
1✔
66
        return typespec(self._expression[1], version=self.version)
1✔
67

68
    @property
1✔
69
    def rank(self) -> int:
1✔
70
        return int(self._expression[2])
1✔
71

72
    @property
1✔
73
    def arglist(self) -> list:
1✔
74
        raise NotImplementedError
×
75
        # if len(self._exp._args) == 7:
76
        #     return procedures.actual_arglist(self._exp._args[6])
77
        # return []
78

79
    @property
1✔
80
    def value(self):
1✔
81
        return self._exp.value
1✔
82

83
    def __str__(self):
1✔
84
        return self._exp.__str__()
1✔
85

86
    def __repr__(self):
1✔
87
        return self._exp.__repr__()
1✔
88

89
    @property
1✔
90
    def len(self) -> int:
1✔
91
        return self._exp.len
1✔
92

93
    @property
1✔
94
    def kind(self) -> int:
1✔
95
        return self.typespec.kind
1✔
96

97

98
class ExpOp(ExpGeneric):
1✔
99

100
    @property
1✔
101
    def unary_op(self):
1✔
102
        return self._args[3]
×
103

104
    @property
1✔
105
    def unary_args(self) -> tuple[Expression, Expression]:
1✔
106
        return Expression(self._args[4], version=self.version), Expression(
×
107
            self._args[5], version=self.version
108
        )
109

110

111
class ExpNotImplemented(ExpGeneric):
1✔
112
    @property
1✔
113
    def value(self):
1✔
114
        raise NotImplementedError
×
115

116

117
class ExpFunction(ExpGeneric):
1✔
118
    @property
1✔
119
    def value(self):
1✔
120
        return self._args[3]
×
121

122
    @property
1✔
123
    def args(self):
1✔
124
        return Expression(self._args[4], version=self.version)
×
125

126

127
class ExpConstant(ExpGeneric):
1✔
128
    @property
1✔
129
    def value(self):
1✔
130
        if self._type == "REAL":
1✔
131
            return utils.hextofloat(utils.string_clean(self._args[3]), self.kind)
1✔
132
        elif self._type == "INTEGER" or self._type == "UNSIGNED":
1✔
133
            return int(utils.string_clean(self._args[3]))
1✔
134
        elif self._type == "CHARACTER":
1✔
135
            v = utils.string_clean(self._args[4])
1✔
136
            if self.kind == 4:
1✔
137
                return (
1✔
138
                    v.encode("latin1")
139
                    .decode("unicode_escape")
140
                    .encode("latin1")
141
                    .decode("utf8")
142
                )
143
            else:
144
                return v
1✔
145
        elif self._type == "COMPLEX":
1✔
146
            return complex(
1✔
147
                utils.hextofloat(utils.string_clean(self._args[3]), self.kind),
148
                utils.hextofloat(utils.string_clean(self._args[4]), self.kind),
149
            )
150
        elif self._type == "LOGICAL":
1✔
151
            return int(self._args[3]) == 1
1✔
152
        else:
153
            raise NotImplementedError(f"Type={self._type} args3={self._args[3]}")
×
154

155
    @property
1✔
156
    def len(self) -> int:
1✔
157
        if self._type == "CHARACTER":
1✔
158
            return int(self._args[3])
1✔
159
        return -1
1✔
160

161
    def __str__(self):
1✔
162
        if self._type == "CHARACTER":
1✔
163
            return f"CHARACTER(kind={self.kind},len={self.len})"
1✔
164
        else:
165
            return f"{self.type}(kind={self.kind})"
1✔
166

167
    @property
1✔
168
    def type(self) -> str:
1✔
169
        return self._type
1✔
170

171
    @property
1✔
172
    def raw(self) -> str:
1✔
173
        return utils.string_clean(self._args[3])
×
174

175

176
class ExpVariable(ExpGeneric):
1✔
177
    @property
1✔
178
    def value(self):
1✔
179
        return self._args[3]
×
180

181
    def __str__(self):
1✔
182
        if self._type == "CHARACTER":
×
183
            return f"CHARACTER(kind={self.kind},len={self.len})"
×
184
        else:
185
            return f"{self._type}"
×
186

187

188
class ExpArray(ExpGeneric):
1✔
189
    def __init__(self, *args, **kwargs):
1✔
190
        super().__init__(*args, **kwargs)
1✔
191
        self._value = None
1✔
192

193
    @property
1✔
194
    def value(self) -> np.ndarray:
1✔
195
        if self._value is None:
1✔
196
            self._value = []
1✔
197
            for i in self._args[3]:
1✔
198
                self._value.append(Expression(i[0], version=self.version))
1✔
199

200
        value = []
1✔
201

202
        for v in self._value:
1✔
203
            value.append(v.value)
1✔
204

205
        return np.array(value, dtype=self.dtype).reshape(self.shape)
1✔
206

207
    @property
1✔
208
    def shape(self) -> tuple[int, ...]:
1✔
209
        return tuple([int(utils.string_clean(i)) for i in self._args[4]])
1✔
210

211
    @property
1✔
212
    def dtype(self) -> np.dtype:
1✔
213
        v = Expression(self._args[3][0][0], version=self.version)
1✔
214
        return utils.dtype(v.type, self.kind, len=v.len)
1✔
215

216
    def __str__(self):
1✔
217
        v = Expression(self._args[3][0][0], version=self.version)
1✔
218
        if v.type == "CHARACTER":
1✔
219
            return f"CHARACTER(kind={v.kind},len={v.len}),dimension{self.shape}"
1✔
220
        else:
221
            return f"{v.type},dimension{self.shape}"
1✔
222

223

224
class ExpSubString(ExpNotImplemented):
1✔
225
    pass
1✔
226

227

228
class ExpStructure(ExpNotImplemented):
1✔
229
    pass
1✔
230

231

232
class ExpNull(ExpNotImplemented):
1✔
233
    pass
1✔
234

235

236
class ExpCompCall(ExpNotImplemented):
1✔
237
    pass
1✔
238

239

240
class ExpPPC(ExpNotImplemented):
1✔
241
    pass
1✔
242

243

244
class ExpConditional(ExpNotImplemented):
1✔
245
    pass
1✔
246

247

248
class ExpUnknown(ExpNotImplemented):
1✔
249
    pass
1✔
250

251

252
# Need to store this here as we get a cyclic dependency
253
# between expressions and typespec
254
class typespec:
1✔
255
    def __init__(self, typespec, *, version: Version) -> None:
1✔
256
        self._typespec = typespec
1✔
257
        self.version = version
1✔
258

259
    @property
1✔
260
    def type(self) -> str:
1✔
261
        return self._typespec[0]
1✔
262

263
    def _isclass(self) -> bool:
1✔
264
        return self.type == "CLASS" or self.is_dt
1✔
265

266
    @property
1✔
267
    def is_dt(self) -> bool:
1✔
268
        return self.type == "DERIVED"
1✔
269

270
    @property
1✔
271
    def kind(self) -> int:
1✔
272
        if not self._isclass():
1✔
273
            return int(self._typespec[1])
1✔
274
        return -1
×
275

276
    @property
1✔
277
    def class_ref(self) -> int:
1✔
278
        if self._isclass():
×
279
            return int(self._typespec[1])
×
280
        return -1
×
281

282
    @property
1✔
283
    def interface(self):
1✔
284
        return self._typespec[2]
×
285

286
    @property
1✔
287
    def is_c_interop(self) -> bool:
1✔
288
        return int(self._typespec[3]) == 1
1✔
289

290
    @property
1✔
291
    def is_iso_c(self) -> bool:
1✔
292
        return int(self._typespec[4]) == 1
1✔
293

294
    @property
1✔
295
    def type2(self):
1✔
296
        # Whats this?
297
        return self._typespec[5]
×
298

299
    @property
1✔
300
    def charlen(self) -> Expression:
1✔
301
        if len(self._typespec[6]):
1✔
302
            if len(self._typespec[6][0]) == 0:
1✔
303
                # Fake a negative string length for defered length chars
304
                t = [
1✔
305
                    "CONSTANT",
306
                    ["INTEGER", "4", "0", "0", "0", "INTEGER", []],
307
                    "0",
308
                    "-1",
309
                    [],
310
                ]
311
            else:
312
                t = self._typespec[6][0]
1✔
313

314
            return Expression(t, version=self.version)
1✔
315
        raise AttributeError("Object does not have a character length")
×
316

317
    @property
1✔
318
    def deferred_cl(self) -> bool:
1✔
319
        if len(self._typespec) == 8:
×
320
            return self._typespec[7] == "DEFERRED_CL"
×
321

322
        return False
×
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