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

feihoo87 / waveforms / 6785769682

07 Nov 2023 02:17PM UTC coverage: 39.8%. First build
6785769682

push

github

feihoo87
add multy_drag

110 of 115 new or added lines in 4 files covered. (95.65%)

6768 of 17005 relevant lines covered (39.8%)

3.58 hits per line

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

85.93
/waveforms/waveform_parser.py
1
import tempfile
9✔
2
from ast import literal_eval
9✔
3
from functools import lru_cache
9✔
4

5
import ply.lex as lex
9✔
6
import ply.yacc as yacc
9✔
7

8
from . import multy_drag, waveform
9✔
9

10

11
class _WaveLexer:
9✔
12
    """Waveform Lexer.
13
    """
14

15
    def __init__(self):
9✔
16
        """Create a PLY lexer."""
17
        self.lexer = lex.lex(module=self, debug=False)
9✔
18

19
    def input(self, data):
9✔
20
        self.lexer.input(data)
9✔
21

22
    def token(self):
9✔
23
        """Return the next token."""
24
        ret = self.lexer.token()
9✔
25
        return ret
9✔
26

27
    literals = r'=()[]<>,.+-/*^'
9✔
28
    functions = [
9✔
29
        'D', 'chirp', 'const', 'cos', 'cosh', 'coshPulse', 'cosPulse', 'cut',
30
        'drag', 'drag_sin', 'drag_sinx', 'exp', 'gaussian', 'general_cosine',
31
        'hanning', 'interp', 'mixing', 'one', 'poly', 'samplingPoints', 'sign',
32
        'sin', 'sinc', 'sinh', 'square', 'step', 't', 'zero'
33
    ]
34
    tokens = [
9✔
35
        'REAL', 'IMAG', 'INT', 'STRING', 'ID', 'LSHIFT', 'RSHIFT', 'POW',
36
        'CONST', 'FUNCTION'
37
    ]
38

39
    def t_ID(self, t):
9✔
40
        r'[a-zA-Z_][a-zA-Z_0-9]*'
41
        if t.value in ['pi', 'e', 'inf']:
9✔
42
            t.type = 'CONST'
9✔
43
            return t
9✔
44
        if t.value in self.functions:
9✔
45
            t.type = 'FUNCTION'
9✔
46
            return t
9✔
47
        else:
48
            return t
9✔
49

50
    def t_IMAG(self, t):
9✔
51
        r'((([0-9]+|([0-9]+)?\.[0-9]+|[0-9]+\.)[eE][+-]?[0-9]+)|(([0-9]+)?\.[0-9]+|[0-9]+\.)|[1-9][0-9]*|0)j'
52
        return t
×
53

54
    def t_REAL(self, t):
9✔
55
        r'(([0-9]+|([0-9]+)?\.[0-9]+|[0-9]+\.)[eE][+-]?[0-9]+)|(([0-9]+)?\.[0-9]+|[0-9]+\.)'
56
        return t
9✔
57

58
    def t_INT(self, t):
9✔
59
        r'[1-9][0-9]*|0'
60
        return t
9✔
61

62
    def t_STRING(self, t):
9✔
63
        r'(".*")|(\'.*\')'
64
        return t
9✔
65

66
    def t_LSHIFT(self, t):
9✔
67
        '<<'
68
        return t
9✔
69

70
    def t_RSHIFT(self, t):
9✔
71
        '>>'
72
        return t
9✔
73

74
    def t_POW(self, t):
9✔
75
        r'\*\*'
76
        return t
×
77

78
    def t_eof(self, _):
9✔
79
        return None
9✔
80

81
    t_ignore = ' \t\r\n'
9✔
82

83
    def t_error(self, t):
9✔
84
        raise SyntaxError("Unable to match any token rule, got -->%s<-- " %
×
85
                          t.value)
86

87

88
class _WaveParser:
9✔
89

90
    def __init__(self):
9✔
91
        self.lexer = _WaveLexer()
9✔
92
        self.tokens = self.lexer.tokens
9✔
93
        self.parse_dir = tempfile.mkdtemp(prefix='waveforms')
9✔
94
        self.precedence = (('left', 'RSHIFT', 'LSHIFT'), ('left', '+', '-'),
9✔
95
                           ('left', '*', '/'), ('left', 'POW',
96
                                                '^'), ('right', 'UMINUS'))
97
        self.parser = yacc.yacc(module=self,
9✔
98
                                debug=False,
99
                                outputdir=self.parse_dir)
100
        self.waveform = None
9✔
101

102
    def parse(self, data):
9✔
103
        #self.waveform = None
104
        self.parser.parse(data, lexer=self.lexer, debug=False)
9✔
105
        if self.waveform is None:
9✔
106
            raise SyntaxError("Uncaught exception in parser; " +
×
107
                              "see previous messages for details.")
108
        if isinstance(self.waveform, (float, int)):
9✔
109
            self.waveform = waveform.const(self.waveform)
×
110
        return self.waveform.simplify()
9✔
111

112
    def getFunction(self, name):
9✔
113
        for mod in [waveform, multy_drag]:
9✔
114
            try:
9✔
115
                return getattr(waveform, name)
9✔
NEW
116
            except AttributeError:
×
NEW
117
                pass
×
NEW
118
        raise SyntaxError(f"Unknown function '{name}'")
×
119

120
    # ---- Begin the PLY parser ----
121
    start = 'main'
9✔
122

123
    def p_main(self, p):
9✔
124
        """
125
        main : expression
126
        """
127
        self.waveform = p[1]
9✔
128

129
    def p_const(self, p):
9✔
130
        """
131
        expression : CONST
132
        """
133
        p[0] = {'pi': waveform.pi, 'e': waveform.e, 'inf': waveform.inf}[p[1]]
9✔
134

135
    def p_real_imag_int_string(self, p):
9✔
136
        """
137
        expression : REAL
138
                   | IMAG
139
                   | INT
140
                   | STRING
141
        """
142
        p[0] = literal_eval(p[1])
9✔
143

144
    def p_tuple_list(self, p):
9✔
145
        """
146
        expression : tuple
147
                   | list
148
        """
149
        p[0] = p[1]
9✔
150

151
    def p_expr_uminus(self, p):
9✔
152
        """
153
        expression : '-' expression %prec UMINUS
154
        """
155
        p[0] = -p[2]
9✔
156

157
    def p_function_call(self, p):
9✔
158
        """
159
        expression : FUNCTION '(' ')'
160
        """
161
        p[0] = self.getFunction(p[1])()
×
162

163
    def p_function_call_2(self, p):
9✔
164
        """
165
        expression :  FUNCTION '(' args ')'
166
        """
167
        p[0] = self.getFunction(p[1])(*p[3])
9✔
168

169
    def p_function_call_3(self, p):
9✔
170
        """
171
        expression :  FUNCTION '(' kwds ')'
172
        """
173
        p[0] = self.getFunction(p[1])(**p[3])
×
174

175
    def p_function_call_4(self, p):
9✔
176
        """
177
        expression :  FUNCTION '(' args ',' kwds ')'
178
        """
179
        p[0] = self.getFunction(p[1])(*p[3], **p[5])
9✔
180

181
    def p_bracket(self, p):
9✔
182
        """
183
        expression :  '(' expression ')'
184
        """
185
        p[0] = p[2]
9✔
186

187
    def p_binary_operators(self, p):
9✔
188
        """
189
        expression : expression '+' expression
190
                   | expression '-' expression
191
                   | expression '*' expression
192
                   | expression '/' expression
193
                   | expression LSHIFT expression
194
                   | expression RSHIFT expression
195
                   | expression '^' expression
196
                   | expression POW expression
197
        """
198
        if p[2] == '+':
9✔
199
            p[0] = p[1] + p[3]
9✔
200
        elif p[2] == '-':
9✔
201
            p[0] = p[1] - p[3]
×
202
        elif p[2] == '*':
9✔
203
            p[0] = p[1] * p[3]
9✔
204
        elif p[2] == '/':
9✔
205
            p[0] = p[1] / p[3]
9✔
206
        elif p[2] == '>>':
9✔
207
            p[0] = p[1] >> p[3]
9✔
208
        elif p[2] == '<<':
9✔
209
            p[0] = p[1] << p[3]
9✔
210
        elif p[2] == '^':
×
211
            p[0] = p[1]**p[3]
×
212
        else:
213
            p[0] = p[1]**p[3]
×
214

215
    def p_expr_list_2(self, p):
9✔
216
        """
217
        expr_list : expression ',' expression
218
        """
219
        p[0] = [p[1], p[3]]
9✔
220

221
    def p_expr_list_3(self, p):
9✔
222
        """
223
        expr_list : expr_list ',' expression
224
        """
225
        p[0] = [*p[1], p[3]]
9✔
226

227
    def p_tuple(self, p):
9✔
228
        """
229
        tuple : '(' expression ',' ')'
230
              | '(' expr_list ')'
231
        """
232
        if len(p) == 5:
9✔
233
            p[0] = (p[2], )
×
234
        else:
235
            p[0] = tuple(p[2])
9✔
236

237
    def p_list_1(self, p):
9✔
238
        """
239
        list : '[' expression ']'
240
        """
241
        p[0] = [p[2]]
×
242

243
    def p_list_2(self, p):
9✔
244
        """
245
        list : '[' expr_list ']'
246
        """
247
        p[0] = p[2]
9✔
248

249
    def p_args(self, p):
9✔
250
        """
251
        args : expression
252
             | args ',' expression
253
        """
254
        if len(p) == 2:
9✔
255
            p[0] = (p[1], )
9✔
256
        else:
257
            p[0] = p[1] + (p[3], )
9✔
258

259
    def p_kwds(self, p):
9✔
260
        """
261
        kwds : ID '=' expression
262
             | kwds ',' ID '=' expression
263
        """
264
        if len(p) == 4:
9✔
265
            p[0] = {p[1]: p[3]}
9✔
266
        else:
267
            kwds = {}
9✔
268
            kwds.update(p[1])
9✔
269
            kwds[p[3]] = p[5]
9✔
270
            p[0] = kwds
9✔
271
            # p[0] = p[1] | {p[3]: p[5]}   # only works on Python>=3.9
272

273
    def p_error(self, p):
9✔
274
        raise SyntaxError("Syntax error in input!")
×
275

276

277
_wave_parser = _WaveParser()
9✔
278

279

280
@lru_cache(maxsize=1024)
9✔
281
def wave_eval(expr: str) -> waveform.Waveform:
9✔
282
    try:
9✔
283
        return _wave_parser.parse(expr)
9✔
284
    except:
×
285
        raise SyntaxError(f"Illegal expression '{expr}'")
×
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

© 2025 Coveralls, Inc