IutestPreprocessor.__strip_namespace()   A
last analyzed

Complexity

Conditions 4

Size

Total Lines 12
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 12
nop 3
dl 0
loc 12
rs 9.8
c 0
b 0
f 0
1
#!/usr/bin/env python
2
#
3
# iutest_pp_strip.py
4
#
5
# Copyright (C) 2018, Takazumi Shirayanagi
6
# This software is released under the new BSD License,
7
# see LICENSE
8
#
9
10
import re
11
import collections
12
13
RE_MACRO_SPLIT = re.compile('([\(\):;{} /%+\-=<>!&\|*#]+)')
14
RE_SPLIT_PAREN = re.compile('([\(\)])')
15
RE_FUNC_MACRO = re.compile('([\w_]+)\((.*?)\)')
16
RE_DEFINE = re.compile('#\s*define (\S+)\s*(.*)$')
17
RE_DEFINE_PARSE = re.compile('(.*)defined\((.*?)\)(.*)')
18
RE_HAS_INCLUDE = re.compile('(.*)__has_include\((.*?)\)(.*)')
19
RE_HAS_FEATURE = re.compile('(.*)__has_feature\((.*?)\)(.*)')
20
RE_SPLIT_OP = re.compile('(&&|\|\||!)')
21
RE_SYMBOLMARK = re.compile('([+\-=<>\(\)]+)')
22
RE_PPIF = re.compile('#\s*(ifdef|ifndef|if)\s*(.*)$')
23
RE_PPELIF = re.compile('#\s*elif\s*(.*)$')
24
RE_PPELSE = re.compile('#\s*else\s*$')
25
RE_PPENDIF = re.compile('#\s*endif')
26
RE_AND = re.compile('and')
27
RE_CPP_COMMENT = re.compile('^//.*')
28
RE_SYSTEM_INCLUDE_REGEX = re.compile(r'^\s*#\s*include\s*<(.*)>')
29
30
RE_STRIP_INCG_REGEX = re.compile(r'^INCG_\S*_[IH]PP_\S+\Z')
31
32
RE_EVAL_UNDEFINED_EXCEPTION = re.compile(r'^name \'(defined_.*)\' is not defined\Z')
33
34
UNUSED_ = "unused"
35
36
37
class IutestPreprocessor:
38
    macros = {}
39
    expands_macros = []
40
    expand_function_macros = []
41
    iutest_config_macro = []
42
    has_include = {}
43
    has_features = {}
44
    debug = False
45
46
    def __init__(self
47
            , predefined_macros
48
            , iutest_config_macro
49
            , expand_function_macros
50
            , expands_macros
51
            , has_features
52
            , has_include):
53
        self.set_predefined_macros(predefined_macros)
54
        self.set_iutest_config_macro(iutest_config_macro)
55
        self.set_expand_function_macros(expand_function_macros)
56
        self.set_expands_macros(expands_macros)
57
        self.set_has_features(has_features)
58
        self.set_has_include(has_include)
59
        self.unknowns = []
60
        self.included_path = [[]]
61
        self.depth_macros = [{}]
62
        self.depth = []
63
        self.brothers = []
64
        self.prev_line = None
65
66
67
    def set_predefined_macros(self, predefined_macros):
68
        self.macros = predefined_macros
69
70
    def set_iutest_config_macro(self, iutest_config_macro):
71
        self.iutest_config_macro = iutest_config_macro
72
        self.macros.update(iutest_config_macro)
73
74
    def set_expands_macros(self, expands_macros):
75
        self.expands_macros = expands_macros
76
77
    def set_expand_function_macros(self, expand_function_macros):
78
        self.expand_function_macros = expand_function_macros
79
80
    def set_has_include(self, has_include):
81
        self.has_include = has_include
82
83
    def set_has_features(self, has_features):
84
        self.has_features = has_features
85
86
    def set_debug_flag(self, flag):
87
        self.debug = flag
88
89
    def __none_or_unused(self, v):
90
        if v is None or v == UNUSED_:
91
            return True
92
        return False
93
94
    def __expand_macro(self, line):
95
        dst = ""
96
        for s in RE_MACRO_SPLIT.split(line):
97
            if s in self.expands_macros:
98
                expand = self.__get_current_macro(s)
99
                if expand is not None:
100
                    dst += expand
101
                    continue
102
            dst += s
103
        return self.__expand_function_macro(dst)
104
105
    def __expand_function_macro(self, line):
106
        dst = ""
107
        tokens = []
108
        prev = ""
109
        for s in RE_SPLIT_PAREN.split(line):
110
            if s == '(':
111
                tokens.append(prev)
112
            elif s == ')' and len(tokens) > 0:
113
                tokens[-1] += prev + s
114
                s = ""
115
                ss = tokens.pop()
116
                for m in RE_FUNC_MACRO.finditer(ss):
117
                    d = m.group(1)
118
                    if d in self.expand_function_macros:
119
                        if d not in self.macros or self.__none_or_unused(self.macros[d]):
120
                            ss = ss.replace(m.group(0), '')
121
                if len(tokens) > 0:
122
                    tokens[-1] += ss
123
                else:
124
                    dst += ss
125
            elif len(tokens) > 0:
126
                tokens[-1] += prev
127
            else:
128
                dst += prev
129
            prev = s
130
        for s in tokens:
131
            dst += s
132
        dst += prev
133
        return dst
134
135
    def __has_current_macro(self, name):
136
        if name in self.macros:
137
            return True
138
        for m in self.depth_macros:
139
            if name in m:
140
                return True
141
        return False
142
143
    def __get_current_macro(self, name):
144
        if name in self.macros:
145
            return self.macros[name]
146
        for m in self.depth_macros:
147
            if name in m:
148
                return m[name]
149
        return None
150
151
    def __append_define(self, line):
152
        def append(d, v, depth, macros, unknowns, current):
153
            d = re.sub('\(.*\)', '', d)
154
            if len(v) == 0:
155
                if RE_STRIP_INCG_REGEX.match(d):
156
                    self.expands_macros.append(d)
157
                v = 'defined'
158
            if any(x == -1 for x in depth):
159
                unknowns.append(d)
160
                current[d] = v
161
            else:
162
                macros[d] = v
163
            return d
164
        m = RE_DEFINE.match(line)
165
        if m:
166
            current_depth_macro = self.depth_macros[-1]
167
            return append(m.group(1), m.group(2), self.depth, self.macros, self.unknowns, current_depth_macro)
168
        return None
169
170
    def __expand_ppif_macro(self, expr):
171
        expand = ""
172
        for s in RE_SPLIT_OP.split(expr):
173
            if s == '&&':
174
                expand += ' and '
175
            elif s == '||':
176
                expand += ' or '
177
            elif s == '!':
178
                expand += " not "
179
            else:
180
                m = RE_DEFINE_PARSE.match(s)
181
                if m:
182
                    d = m.group(2)
183
                    if self.__has_current_macro(d):
184
                        expand += m.group(1)
185
                        if self.__get_current_macro(d) is None:
186
                            expand += ' (0) '
187
                        else:
188
                            expand += ' (1) '
189
                        expand += m.group(3)
190
                    elif d in self.unknowns:
191
                        expand += s
192
                    else:
193
                        expand += s
194
                        self.unknowns.append(d)
195
                    continue
196
                m = RE_HAS_INCLUDE.match(s)
197
                if m:
198
                    f = m.group(2)
199
                    if f in self.has_include:
200
                        expand += m.group(1) + self.has_include[f] + m.group(3)
201
                    else:
202
                        expand += s
203
                    continue
204
                m = RE_HAS_FEATURE.match(s)
205
                if m:
206
                    f = m.group(2)
207
                    if f in self.has_features:
208
                        expand += m.group(1) + self.has_features[f] + m.group(3)
209
                        continue
210
                for w in RE_SYMBOLMARK.split(s.strip()):
211
                    if RE_SYMBOLMARK.match(w) or w.isspace():
212
                        expand += w
213
                    elif len(w) > 0:
214
                        if w in self.unknowns:
215
                            expand += w
216
                        elif w in self.macros:
217
                            if self.macros[w] is None:
218
                                expand += '0'
219
                            else:
220
                                expand += self.__expand_ppif_macro(self.macros[w])
221
                        elif w.isdigit():
222
                            expand += w
223
                        else:
224
                            expand += w
225
226
        expand = expand.replace('0(0)', '(0)')
227
        expand = expand.replace('not =', '!=')
228
        expand = re.sub(r'not\s*\(0\)', '(1)', expand)
229
        return expand.strip()
230
231
    def __eval_ppif_unknown_defined(self, expand):
232
        if 'defined' not in expand:
233
            return -1
234
        expand = re.sub(r'defined\((.*?)\)', 'defined_\\1', expand)
235
        try:
236
            r = eval(expand)
237
        except Exception as e:
238
            r = self.__eval_ppif_unknown_defined_(str(e), expand)
239
        return r
240
241
    def __eval_ppif_unknown_defined_(self, exception_str, expand):
242
        def eval_x(d, x):
243
            try:
244
                expanded = expand.replace(d, str(x))
245
                return eval(expanded)
246
            except Exception:
247
                return -1
248
        m = RE_EVAL_UNDEFINED_EXCEPTION.match(exception_str)
249
        if m:
250
            d = m.group(1)
251
            r0 = eval_x(d, 0)
252
            r1 = eval_x(d, 1)
253
            if r0 == r1:
254
                return r0
255
        return -1
256
257
    def __eval_expanded_expr(self, expand_expr):
258
        error = None
259
        try:
260
            r = eval(expand_expr)
261
            if r:
262
                return (1, '1')
263
            else:
264
                return (0, '0')
265
        except Exception as e:
266
            error = e
267
268
        expand = expand_expr
269
        if 'or' not in expand:
270
            for expr in RE_AND.split(expand):
271
                try:
272
                    r = eval(expr)
273
                    if not r:
274
                        return (0, '0')
275
                except Exception as e:
276
                    error = e
277
        raise error
278
279
    def __eval_ppif(self, expr):
280
        expand = self.__expand_ppif_macro(expr)
281
        expand_expr = re.sub(r'([0-9])+L', r'\1', expand)
282
        try:
283
            return self.__eval_expanded_expr(expand_expr)
284
        except Exception as e:
285
            r = -1
286
            if len(expand.split()) > 1:
287
                # r = self.__eval_ppif_unknown_defined(expand_expr)
288
                if r == -1:
289
                    if self.debug:
290
                        print(expr)
291
                        print(expand)
292
                        print(e)
293
                # strip fixed condition
294
                if '(0)' in expand or '(1)' in expand:
295
                    expand = re.sub(r'\s*\(0\)\s*or\s*', '', expand)
296
                    expand = re.sub(r'\s*or\s*\(0\)\s*', '', expand)
297
                    expand = re.sub(r'\s*\(1\)\s*and\s*', '', expand)
298
                    expand = re.sub(r'\s*and\s*\(1\)\s*', '', expand)
299
                    expand = expand.replace(' and ', '&&')
300
                    expand = expand.replace(' or ' , '||')
301
                    expand = expand.replace(' not ', '!')
302
                    expand = expand.replace('(0)', '0')
303
                    expand = expand.replace('(1)', '1')
304
                    return (r, expand)
305
            return (r, None)
306
307
    def __check_ppif(self, ins, expr):
308
        if ins == "if" or ins == "elif":
309
            return self.__eval_ppif(expr)
310
        else:
311
            def other():
312
                if ins == "ifdef":
313
                    if expr in self.unknowns:
314
                        return -1
315
                    elif expr not in self.macros:
316
                        return -1
317
                    elif expr in self.macros:
318
                        if self.macros[expr] is None:
319
                            return 0
320
                        return 1
321
                elif ins == "ifndef":
322
                    if expr in self.unknowns:
323
                        return -1
324
                    elif expr in self.macros:
325
                        if self.macros[expr] is None:
326
                            return 1
327
                        return 0
328
                    elif expr in self.expands_macros:
329
                        return 0
330
                    else:
331
                        return -1
332
                return -1
333
            return other(), None
334
335
    # return line string or None
336
    def __check_pp(self, line):
337
        def ret(b):
338
            if b:
339
                return line
340
            return None
341
        m = RE_PPIF.match(line)
342
        if m:
343
            expr = m.group(2)
344
            f,expanded_expr = self.__check_ppif(m.group(1), expr)
345
            self.depth.append(f)
346
            self.depth_macros.append({})
347
            self.included_path.append([])
348
            self.brothers.append([])
349
            if expanded_expr is not None:
350
                line = line.replace(expr, expanded_expr)
351
            return ret(all(x != 0 for x in self.depth) and f == -1)
352
        m = RE_PPELIF.match(line)
353
        if m:
354
            brother = self.brothers[-1]
355
            prev_brother_f = self.depth[-1]
356
            if len(brother) == 0 and prev_brother_f == 0:
357
                # Convert to #if if the last is if and the result is False
358
                line = line.replace('#elif', '#if')
359
            else:
360
                brother.append(prev_brother_f)
361
            f = 0
362
            if not any(x == 1 for x in brother):
363
                expr = m.group(1)
364
                f,expanded_expr = self.__check_ppif("elif", expr)
365
                if expanded_expr is not None:
366
                    line = line.replace(expr, expanded_expr)
367
            self.depth[-1] = f
368
            if all(x != 0 for x in self.depth):
369
                if f == -1 or any(x == -1 for x in brother):
370
                    return line
371
            return None
372
        m = RE_PPELSE.match(line)
373
        if m:
374
            brother = self.brothers[-1]
375
            brother.append(self.depth[-1])
376
            f = -1
377
            if any(x == 1 for x in brother):
378
                f = 0
379
            elif all(x == 0 for x in brother):
380
                f = 1
381
            self.depth[-1] = f
382
            return ret(all(x != 0 for x in self.depth) and f == -1)
383
        if RE_PPENDIF.match(line):
384
            brother = self.brothers[-1]
385
            f = self.depth.pop()
386
            self.included_path.pop()
387
            poped_macros = self.depth_macros.pop()
388
            b1 = all(x != 0 for x in self.depth)
389
            b2 = any(x == -1 for x in brother)
390
            self.brothers.pop()
391
            need_endif = b1 and (f == -1 or b2)
392
            if need_endif:
393
                return line
394
            if len(self.depth_macros) > 0:
395
                current_depth_macros = self.depth_macros[-1]
396
                current_depth_macros.update(poped_macros)
397
            return None
398
        return ret(len(self.depth) == 0 or all(x != 0 for x in self.depth))
399
400
    def __check_include(self, line):
401
        m = RE_SYSTEM_INCLUDE_REGEX.match(line)
402
        if m:
403
            path = m.group(1)
404
            for include_paths in self.included_path:
405
                if path in include_paths:
406
                    return False
407
            self.included_path[-1].append(path)
408
        return True
409
410
    def __reduction(self, line):
411
        reduction_macros = {
412
            'IP_INC':    'IP_I',
413
            'IP_DEC':    'IP_D',
414
            'IP_BOOL':   'IP_B',
415
            'IP_ENUM':   'IP_E',
416
            'IP_REPEAT': 'IP_R',
417
            'IP_IS_EMPTY_': 'IP_IS_EMP_',
418
            'IP_EMPTY_TAG': 'IP_EMP_T',
419
            'IP_IS_BEGIN_PARENS': 'IP_IS_BGN_P',
420
            'IP_E_PARAMS_MACRO_': 'IP_E_P_M_',
421
            'IP_E_P_M_IN_BINARY_': 'IP_E_P_M_B_',
422
            'IP_E_BINARY_PARAMS_': 'IP_E_B_P_',
423
            'IP_E_B_P_MACRO_': 'IP_E_B_P_M_',
424
            'IP_R_PARAMS_MACRO_': 'IP_R_P_M_',
425
            'IP_R_P_M_IN_BINARY_': 'IP_R_P_M_B_',
426
            'IP_R_BINARY_PARAMS_': 'IP_R_B_P_',
427
            'IP_R_B_P_MACRO_': 'IP_R_B_P_M_',
428
            'II_SHOW_MACRO':  'II_S_M',
429
            'II_SHOW_ENABLE_MACRO':   'II_S_E_M',
430
            'II_SHOW_DISABLE_MACRO':  'II_S_D_M',
431
            'II_SHOW_FEATURE_MACROS': 'II_S_F_M',
432
            'II_ELEMENTSARE': 'II_EA',
433
            'II_EA_MATCHER_NAME': 'II_EA_M_N',
434
            'II_ANYOF_AND_ALLOF_MATCHER_NAME': 'II_AAA_M_N',
435
            'II_DECL_VALUEARRAY_': 'II_D_VA_',
436
            'II_DECL_CARTESIAN_PRODUCT_': 'II_D_C_P_',
437
            'II_DECL_PAIRWISE_': 'II_D_PW_',
438
            'II_DECL_IS_FUNCTION_PTR_': 'II_D_IS_FP_',
439
            'II_DECL_IS_MEMBER_FUNCTION_PTR_': 'II_D_IS_M_FP_',
440
            'II_DECL_FUNCTION_RETURN_TYPE_': 'II_D_F_R_T_',
441
            'II_DECL_EXPRESSION_': 'II_D_EP_',
442
            'II_DECL_ELEMENTSARE': 'II_D_EA',
443
            'II_DECL_TUPLE_PRINTTO': 'II_D_T_PT',
444
            'II_DECL_ANYOF_AND_ALLOF': 'II_D_AAA',
445
            'II_DECL_COMPARE_HELPER_': 'II_D_C_H_',
446
            'II_DECL_COMBINE_': 'II_D_C_',
447
            'II_DECL_VALUES_': 'II_D_V_',
448
            'II_DECL_TYPES_': 'II_D_T_',
449
            'II_DECL_TEMPLATES_': 'II_D_TPL_',
450
            'II_DECL_TYPELIST_': 'II_D_TL_',
451
            'II_DECL_TEMPLATETYPELIST_': 'II_D_TTL_',
452
            'II_DECL_PEEP_MEMBER_FUNC_': 'II_D_PE_M_F_',
453
            'II_DECL_COMPARE_MATCHER': 'II_D_COMP_M',
454
            'II_DECL_STR_COMPARE_MATCHER': 'II_D_S_COMP_M',
455
            'II_DECL_ALLOF_MATCHER': 'II_D_ALL_M',
456
            'II_DECL_ANYOF_MATCHER': 'II_D_ANY_M',
457
            'II_DECL_DEFAULT_ARG_': 'II_D_DEF_A_',
458
            'II_DECL_SPEC_NONE_': 'II_D_S_NN_',
459
            'II_SUCCEED': 'II_S',
460
            'II_FAIL': 'II_F',
461
            'II_ADD_FAILURE': 'II_ADD_F',
462
            'II_SCOPED_MESSAGE': 'II_S_MSG',
463
            'II_D_C_P_GENERATOR_': 'II_D_C_P_GEN_',
464
            'II_D_C_P_HOLDER_': 'II_D_C_P_HLR_',
465
            'II_D_PW_GENERATOR_': 'II_D_PW_GEN_',
466
            'II_D_PW_HOLDER_': 'II_D_PW_HLR_',
467
            'II_CONCAT_PACKAGE': 'II_CC_PKG',
468
            'II_PACKAGE_': 'II_PKG_',
469
            'II_PKG_CURRENT_NAMESPACE_': 'II_PKG_C_NS_',
470
            'II_PKG_PARENT_NAMESPACE_': 'II_PKG_P_NS_',
471
            'II_TEST_CLASS_NAME_': 'II_T_C_N_',
472
            'II_TEST_INSTANCE_NAME_': 'II_T_INST_N_',
473
            'II_TO_VARNAME_': 'II_TO_VN_',
474
            'II_TO_NAME_': 'II_TO_N_',
475
            'II_CHECK_TESTFIXTURE': 'II_CK_TF',
476
            'II_PMZ_TEST_CLASS_NAME_': 'II_PMZ_T_C_N_',
477
            'II_GETTESTCASEPATTERNHOLDER': 'II_GTCPH',
478
            'II_INSTANTIATE_TEST_CASE_P_': 'II_INST_TC_P_',
479
            'II_TEST_P_EVALGENERATOR_NAME_': 'II_T_P_EGEN_N_',
480
            'II_TEST_P_PARAMGENERATOR_NAME_': 'II_T_P_PGEN_N_',
481
            'II_TEST_P_INSTANTIATIONREGISTER_': 'II_T_P_INST_R_',
482
            'II_TEST_P_FIXTURE_DECL_': 'II_T_P_FX_D_',
483
            'II_TEST_P_BASE_FIXTURE': 'II_T_P_B_FX',
484
            'II_T_P_INST_R_NAME_': 'II_T_P_INST_R_N_',
485
            'II_ALIAS_TESTNAME_PP_': 'II_A_TN_PP_',
486
            'II_TEST_EXPRESSION_': 'II_T_EXPR_',
487
            'II_T_EXPR_EXPAND_EXPRESSION': 'II_T_EXPR_E_E',
488
            'II_EXPRESSION_DECOMPOSE': 'II_EXPR_DEC',
489
            'II_D_EP_RESULT_OP': 'II_D_EP_R_OP',
490
            'II_TYPED_TEST_': 'II_T_T_',
491
            'II_T_T_CASE_': 'II_T_TC_',
492
            'II_T_TC_PSTATE_NAME_': 'II_T_TC_PS_N_',
493
            'II_T_T_P_NAMESPACE_': 'II_T_T_P_NS_',
494
            'II_T_T_P_ADDTESTNAME': 'II_T_T_P_ADD_TN',
495
            'II_T_T_PARAMS_': 'II_T_T_PRMS_',
496
            'II_REGISTER_TYPED_TEST_CASE_P_': 'II_R_T_TC_P_',
497
            'II_INSTANTIATE_TYPED_TEST_CASE_P_': 'II_INST_T_TC_P_',
498
            'II_PEEP_TAG_NAME_': 'II_PE_T_N_',
499
            'II_PEEP_SETTER_NAME_': 'II_PE_S_N_',
500
            'II_GeTypeNameSpecialization': 'II_GTNS',
501
            'II_WORKAROUND_GENRAND': 'II_WA_GENRAND',
502
            'II_FILESYSTEM_INSTANTIATE_': 'II_FS_I_',
503
        }
504
        line = line.replace('IIUT_', 'II_')
505
        line = line.replace('II_PP_', 'IP_')
506
        line = line.replace('IUTEST_UNUSED_VAR', '(void)')
507
        line = line.replace('statement', 'st')
508
        line = line.replace('expected_exception', 'exp_e')
509
        line = line.replace('exp_e_value', 'exp_e_v')
510
        line = line.replace('expected_str', 'exp_s')
511
        line = line.replace('expected_value', 'exp_v')
512
        line = line.replace('actual_str', 'act_s')
513
        line = line.replace('regex_str', 'regex_s')
514
        line = line.replace('pred_formatter', 'pd_fmt')
515
        line = line.replace('on_failure', 'on_f')
516
        line = line.replace('testcasename_', 'tcn_')
517
        line = line.replace('testcase_', 't_c_')
518
        line = line.replace('testname_', 'tn_')
519
        line = line.replace('testfixture_', 'tf_')
520
        line = line.replace('result_type_', 'rt_')
521
        line = line.replace('parent_class_', 'p_c_')
522
        line = line.replace('type_id_', 'tid_')
523
        line = line.replace('methodName', 'mN_')
524
        line = line.replace('method_', 'mtd_')
525
        line = line.replace('prefix_', 'pfx_')
526
        line = line.replace('paramname_generator_', 'pn_gen_')
527
        line = line.replace('generator_', 'gen_')
528
        line = line.replace('dummy', 'dmy')
529
        # line = line.replace('value', 'val')
530
        # line = line.replace('macro', 'mcr')
531
        line = line.replace('EXTEND_POINT_', 'EX_P_')
532
        for k,v in reduction_macros.items():
533
            if collections.Counter(reduction_macros.values())[v] > 1:
534
                print('error: duplicated ' + v)
535
                continue
536
            line = line.replace(k, v)
537
        line = re.sub(r'(?<![\w\d_])NULL(?![\w\d_])', '0', line)
538
        # line = re.sub('\s+', ' ', line)
539
        line = re.sub('\s$', '', line)
540
        line = line.strip()
541
        return line
542
543
    def __strip_namespace(self, line, ns):
544
        s = ""
545
        e = ""
546
        for n in ns:
547
            s += "namespace " + n + "{"
548
            e += "}"
549
        def __is_namespace_open_close_line(x):
550
            return x.startswith(s) and x.endswith(e)
551
        if __is_namespace_open_close_line(line) and __is_namespace_open_close_line(self.prev_line):
552
            self.prev_line = self.prev_line[:-len(e)]
553
            line = line[len(s):]
554
        return line
555
556
    def __strip_namespace_iutest_detail(self, line):
557
        ns = ['iutest', 'detail']
558
        return self.__strip_namespace(line, ns)
559
560
    def __strip_namespace_iutest(self, line):
561
        ns = ['iutest']
562
        return self.__strip_namespace(line, ns)
563
564
    def __strip_namespaces(self, line):
565
        line = self.__strip_namespace_iutest_detail(line)
566
        line = self.__strip_namespace_iutest(line)
567
        return line
568
569
    def preprocess(self, code, add_macros):
570
        if add_macros is not None:
571
            self.macros.update(add_macros)
572
        dst = ""
573
        for line in code.splitlines():
574
            # c++ comment
575
            if RE_CPP_COMMENT.match(line):
576
                continue
577
            # if/ifdef/ifndef/elif/endif
578
            line = self.__check_pp(line)
579
            if line:
580
                # include
581
                if not self.__check_include(line):
582
                    continue
583
                # define
584
                d = self.__append_define(line)
585
                if d:
586
                    # config macro insert
587
                    if 'INCG_IRIS_IUTEST_CONFIG_HPP_' in d:
588
                        dst += self.prev_line + '\n'
589
                        self.prev_line = None
590
                        for k,v in self.iutest_config_macro.items():
591
                            dst += '#define ' + k + ' ' + str(v) + '\n'
592
                        self.iutest_config_macro = []
593
                    if d in self.expands_macros or d in self.expand_function_macros:
594
                        continue
595
                    if d in ['IUTEST_UNUSED_VAR']:
596
                        continue
597
                line = self.__expand_macro(line)
598
                if len(line) > 0:
599
                    line = self.__reduction(line)
600
                    if self.prev_line is not None:
601
                        line = self.__strip_namespaces(line)
602
                        if self.prev_line.startswith('#'):
603
                            self.prev_line += '\n'
604
                        elif line.startswith('#'):
605
                            self.prev_line += '\n'
606
                        dst += self.prev_line
607
                    self.prev_line = line
608
        dst += self.prev_line + '\n'
609
        return dst
610
611
    def __get_ppif_type(self, line):
612
        if RE_PPIF.match(line):
613
            return 'if'
614
        elif RE_PPELIF.match(line):
615
            return 'elif'
616
        elif RE_PPELSE.match(line):
617
            return 'else'
618
        elif RE_PPENDIF.match(line):
619
            return 'endif'
620
        return None
621
622
    def remove_empty_ppif(self, code):
623
        dst = ""
624
        prev = None
625
        cache_lines = []
626
        def cach_clear():
627
            ret = ""
628
            for s in cache_lines:
629
                if s is not None:
630
                    ret += s
631
            del cache_lines[:]
632
            return ret
633
634
        for line in code.splitlines():
635
            line += "\n"
636
            t = self.__get_ppif_type(line)
637
            if t == 'endif':
638
                if prev == 'if':
639
                    if len(cache_lines) > 0:
640
                        cache_lines = cache_lines[:-1]
641
                elif prev != 'endif':
642
                    if len(cache_lines) > 0:
643
                        cache_lines[-1] = line
644
                    else:
645
                        cache_lines.append(line)
646
                else:
647
                    dst += cach_clear()
648
                    dst += line
649
            elif t is not None:
650
                if prev is None:
651
                    cache_lines.append(line)
652
                else:
653
                    if t == 'else' and prev == 'elif':
654
                        cache_lines[-1] = line
655
                    elif t == 'elif' and prev == 'elif':
656
                        cache_lines[-1] = line
657
                    else:
658
                        cache_lines.append(line)
659
            else:
660
                dst += cach_clear()
661
                dst += line
662
            prev = t
663
        dst += cach_clear()
664
        return dst
665
666
    def trancate_line(self, code):
667
        dst = ""
668
        limit = 6000
669
        for line in code.splitlines():
670
            found = True
671
            while len(line) >= limit and found:
672
                found = False
673
                for sep in ['}}', '};', '";']:
674
                    idx = line.rfind(sep, 0, limit)
675
                    if idx >= 0:
676
                        idx += len(sep)
677
                        dst += line[:idx] + '\n'
678
                        line = line[idx:]
679
                        found = True
680
                        break
681
            line += "\n"
682
            dst += line
683
        return dst
684