2 # Tests for scripts/glibcpp.py
3 # Copyright (C) 2022-2023 Free Software Foundation, Inc.
4 # This file is part of the GNU C Library.
6 # The GNU C Library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
11 # The GNU C Library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with the GNU C Library; if not, see
18 # <https://www.gnu.org/licenses/>.
28 class TokenizerErrors:
29 """Used as the error reporter during tokenization."""
34 def error(self, token, message):
35 self.errors.append((token, message))
37 def check_macro_definitions(source, expected):
38 reporter = TokenizerErrors()
39 tokens = glibcpp.tokenize_c(source, reporter)
42 for md in glibcpp.macro_definitions(tokens):
44 md_name = '{}({})'.format(md.name, ','.join(md.args_lowered))
47 actual.append((md_name, md.body_lowered))
49 if actual != expected or reporter.errors:
52 # Obtain python source line information.
53 frame = inspect.stack(2)[1]
54 print('{}:{}: error: macro definition mismatch, actual definitions:'
55 .format(frame[1], frame[2]))
57 print('note: {} {!r}'.format(md[0], md[1]))
60 for err in reporter.errors:
61 print('note: tokenizer error: {}: {}'.format(
64 def check_macro_eval(source, expected, expected_errors=''):
65 reporter = TokenizerErrors()
66 tokens = list(glibcpp.tokenize_c(source, reporter))
69 # Obtain python source line information.
70 frame = inspect.stack(2)[1]
71 for err in reporter.errors:
72 print('{}:{}: tokenizer error: {}: {}'.format(
73 frame[1], frame[2], err[0].line, err[1]))
77 """Used as the error reporter during evaluation."""
82 def error(self, line, message):
83 self.lines.append('{}: error: {}\n'.format(line, message))
85 def note(self, line, message):
86 self.lines.append('{}: note: {}\n'.format(line, message))
88 reporter = EvalReporter()
89 actual = glibcpp.macro_eval(glibcpp.macro_definitions(tokens), reporter)
90 actual_errors = ''.join(reporter.lines)
91 if actual != expected or actual_errors != expected_errors:
94 # Obtain python source line information.
95 frame = inspect.stack(2)[1]
96 print('{}:{}: error: macro evaluation mismatch, actual results:'
97 .format(frame[1], frame[2]))
98 for k, v in actual.items():
99 print(' {}: {!r}'.format(k, v))
100 for msg in reporter.lines:
101 sys.stdout.write(' | ' + msg)
103 # Individual test cases follow.
105 check_macro_definitions('', [])
106 check_macro_definitions('int main()\n{\n{\n', [])
107 check_macro_definitions("""
109 #define B 2 /* ignored */
110 #define C 3 // also ignored
113 #define STRING "string"
114 #define FUNCLIKE(a, b) (a + b)
115 #define FUNCLIKE2(a, b) (a + \
121 ('STRING', ['"string"']),
122 ('FUNCLIKE(a,b)', list('(a+b)')),
123 ('FUNCLIKE2(a,b)', list('(a+b)')),
125 check_macro_definitions('#define MACRO', [('MACRO', [])])
126 check_macro_definitions('#define MACRO\n', [('MACRO', [])])
127 check_macro_definitions('#define MACRO()', [('MACRO()', [])])
128 check_macro_definitions('#define MACRO()\n', [('MACRO()', [])])
130 check_macro_eval('#define A 1', {'A': 1})
131 check_macro_eval('#define A (1)', {'A': 1})
132 check_macro_eval('#define A (1 + 1)', {'A': 2})
133 check_macro_eval('#define A (1U << 31)', {'A': 1 << 31})
134 check_macro_eval('#define A (1 | 2)', {'A': 1 | 2})
135 check_macro_eval('''\
139 #define C "not ignored"
143 'C': '"not ignored"',
146 # Checking for evaluation errors.
147 check_macro_eval('''\
153 2: error: macro A redefined
154 1: note: location of previous definition
157 check_macro_eval('''\
164 1: error: macro definition A refers to itself
167 check_macro_eval('''\
174 1: error: macro definition A refers to itself
175 2: note: evaluated from B
178 check_macro_eval('''\
187 1: error: macro definition A refers to itself
188 3: note: evaluated from C
189 2: note: evaluated from B
192 check_macro_eval('''\
197 1: error: uninterpretable macro token sequence: 1 +
200 check_macro_eval('''\
205 1: error: uninterpretable macro token sequence: 3 * 5
208 check_macro_eval('''\
213 1: error: missing parentheses around + expression
214 1: note: in definition of macro A