xref: /aosp_15_r20/external/mbedtls/tests/scripts/generate_test_code.py (revision 62c56f9862f102b96d72393aff6076c951fb8148)
1*62c56f98SSadaf Ebrahimi#!/usr/bin/env python3
2*62c56f98SSadaf Ebrahimi# Test suites code generator.
3*62c56f98SSadaf Ebrahimi#
4*62c56f98SSadaf Ebrahimi# Copyright The Mbed TLS Contributors
5*62c56f98SSadaf Ebrahimi# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6*62c56f98SSadaf Ebrahimi
7*62c56f98SSadaf Ebrahimi"""
8*62c56f98SSadaf EbrahimiThis script is a key part of Mbed TLS test suites framework. For
9*62c56f98SSadaf Ebrahimiunderstanding the script it is important to understand the
10*62c56f98SSadaf Ebrahimiframework. This doc string contains a summary of the framework
11*62c56f98SSadaf Ebrahimiand explains the function of this script.
12*62c56f98SSadaf Ebrahimi
13*62c56f98SSadaf EbrahimiMbed TLS test suites:
14*62c56f98SSadaf Ebrahimi=====================
15*62c56f98SSadaf EbrahimiScope:
16*62c56f98SSadaf Ebrahimi------
17*62c56f98SSadaf EbrahimiThe test suites focus on unit testing the crypto primitives and also
18*62c56f98SSadaf Ebrahimiinclude x509 parser tests. Tests can be added to test any Mbed TLS
19*62c56f98SSadaf Ebrahimimodule. However, the framework is not capable of testing SSL
20*62c56f98SSadaf Ebrahimiprotocol, since that requires full stack execution and that is best
21*62c56f98SSadaf Ebrahimitested as part of the system test.
22*62c56f98SSadaf Ebrahimi
23*62c56f98SSadaf EbrahimiTest case definition:
24*62c56f98SSadaf Ebrahimi---------------------
25*62c56f98SSadaf EbrahimiTests are defined in a test_suite_<module>[.<optional sub module>].data
26*62c56f98SSadaf Ebrahimifile. A test definition contains:
27*62c56f98SSadaf Ebrahimi test name
28*62c56f98SSadaf Ebrahimi optional build macro dependencies
29*62c56f98SSadaf Ebrahimi test function
30*62c56f98SSadaf Ebrahimi test parameters
31*62c56f98SSadaf Ebrahimi
32*62c56f98SSadaf EbrahimiTest dependencies are build macros that can be specified to indicate
33*62c56f98SSadaf Ebrahimithe build config in which the test is valid. For example if a test
34*62c56f98SSadaf Ebrahimidepends on a feature that is only enabled by defining a macro. Then
35*62c56f98SSadaf Ebrahimithat macro should be specified as a dependency of the test.
36*62c56f98SSadaf Ebrahimi
37*62c56f98SSadaf EbrahimiTest function is the function that implements the test steps. This
38*62c56f98SSadaf Ebrahimifunction is specified for different tests that perform same steps
39*62c56f98SSadaf Ebrahimiwith different parameters.
40*62c56f98SSadaf Ebrahimi
41*62c56f98SSadaf EbrahimiTest parameters are specified in string form separated by ':'.
42*62c56f98SSadaf EbrahimiParameters can be of type string, binary data specified as hex
43*62c56f98SSadaf Ebrahimistring and integer constants specified as integer, macro or
44*62c56f98SSadaf Ebrahimias an expression. Following is an example test definition:
45*62c56f98SSadaf Ebrahimi
46*62c56f98SSadaf Ebrahimi AES 128 GCM Encrypt and decrypt 8 bytes
47*62c56f98SSadaf Ebrahimi depends_on:MBEDTLS_AES_C:MBEDTLS_GCM_C
48*62c56f98SSadaf Ebrahimi enc_dec_buf:MBEDTLS_CIPHER_AES_128_GCM:"AES-128-GCM":128:8:-1
49*62c56f98SSadaf Ebrahimi
50*62c56f98SSadaf EbrahimiTest functions:
51*62c56f98SSadaf Ebrahimi---------------
52*62c56f98SSadaf EbrahimiTest functions are coded in C in test_suite_<module>.function files.
53*62c56f98SSadaf EbrahimiFunctions file is itself not compilable and contains special
54*62c56f98SSadaf Ebrahimiformat patterns to specify test suite dependencies, start and end
55*62c56f98SSadaf Ebrahimiof functions and function dependencies. Check any existing functions
56*62c56f98SSadaf Ebrahimifile for example.
57*62c56f98SSadaf Ebrahimi
58*62c56f98SSadaf EbrahimiExecution:
59*62c56f98SSadaf Ebrahimi----------
60*62c56f98SSadaf EbrahimiTests are executed in 3 steps:
61*62c56f98SSadaf Ebrahimi- Generating test_suite_<module>[.<optional sub module>].c file
62*62c56f98SSadaf Ebrahimi  for each corresponding .data file.
63*62c56f98SSadaf Ebrahimi- Building each source file into executables.
64*62c56f98SSadaf Ebrahimi- Running each executable and printing report.
65*62c56f98SSadaf Ebrahimi
66*62c56f98SSadaf EbrahimiGenerating C test source requires more than just the test functions.
67*62c56f98SSadaf EbrahimiFollowing extras are required:
68*62c56f98SSadaf Ebrahimi- Process main()
69*62c56f98SSadaf Ebrahimi- Reading .data file and dispatching test cases.
70*62c56f98SSadaf Ebrahimi- Platform specific test case execution
71*62c56f98SSadaf Ebrahimi- Dependency checking
72*62c56f98SSadaf Ebrahimi- Integer expression evaluation
73*62c56f98SSadaf Ebrahimi- Test function dispatch
74*62c56f98SSadaf Ebrahimi
75*62c56f98SSadaf EbrahimiBuild dependencies and integer expressions (in the test parameters)
76*62c56f98SSadaf Ebrahimiare specified as strings in the .data file. Their run time value is
77*62c56f98SSadaf Ebrahiminot known at the generation stage. Hence, they need to be translated
78*62c56f98SSadaf Ebrahimiinto run time evaluations. This script generates the run time checks
79*62c56f98SSadaf Ebrahimifor dependencies and integer expressions.
80*62c56f98SSadaf Ebrahimi
81*62c56f98SSadaf EbrahimiSimilarly, function names have to be translated into function calls.
82*62c56f98SSadaf EbrahimiThis script also generates code for function dispatch.
83*62c56f98SSadaf Ebrahimi
84*62c56f98SSadaf EbrahimiThe extra code mentioned here is either generated by this script
85*62c56f98SSadaf Ebrahimior it comes from the input files: helpers file, platform file and
86*62c56f98SSadaf Ebrahimithe template file.
87*62c56f98SSadaf Ebrahimi
88*62c56f98SSadaf EbrahimiHelper file:
89*62c56f98SSadaf Ebrahimi------------
90*62c56f98SSadaf EbrahimiHelpers file contains common helper/utility functions and data.
91*62c56f98SSadaf Ebrahimi
92*62c56f98SSadaf EbrahimiPlatform file:
93*62c56f98SSadaf Ebrahimi--------------
94*62c56f98SSadaf EbrahimiPlatform file contains platform specific setup code and test case
95*62c56f98SSadaf Ebrahimidispatch code. For example, host_test.function reads test data
96*62c56f98SSadaf Ebrahimifile from host's file system and dispatches tests.
97*62c56f98SSadaf Ebrahimi
98*62c56f98SSadaf EbrahimiTemplate file:
99*62c56f98SSadaf Ebrahimi---------
100*62c56f98SSadaf EbrahimiTemplate file for example main_test.function is a template C file in
101*62c56f98SSadaf Ebrahimiwhich generated code and code from input files is substituted to
102*62c56f98SSadaf Ebrahimigenerate a compilable C file. It also contains skeleton functions for
103*62c56f98SSadaf Ebrahimidependency checks, expression evaluation and function dispatch. These
104*62c56f98SSadaf Ebrahimifunctions are populated with checks and return codes by this script.
105*62c56f98SSadaf Ebrahimi
106*62c56f98SSadaf EbrahimiTemplate file contains "replacement" fields that are formatted
107*62c56f98SSadaf Ebrahimistrings processed by Python string.Template.substitute() method.
108*62c56f98SSadaf Ebrahimi
109*62c56f98SSadaf EbrahimiThis script:
110*62c56f98SSadaf Ebrahimi============
111*62c56f98SSadaf EbrahimiCore function of this script is to fill the template file with
112*62c56f98SSadaf Ebrahimicode that is generated or read from helpers and platform files.
113*62c56f98SSadaf Ebrahimi
114*62c56f98SSadaf EbrahimiThis script replaces following fields in the template and generates
115*62c56f98SSadaf Ebrahimithe test source file:
116*62c56f98SSadaf Ebrahimi
117*62c56f98SSadaf Ebrahimi__MBEDTLS_TEST_TEMPLATE__TEST_COMMON_HELPERS
118*62c56f98SSadaf Ebrahimi            All common code from helpers.function
119*62c56f98SSadaf Ebrahimi            is substituted here.
120*62c56f98SSadaf Ebrahimi__MBEDTLS_TEST_TEMPLATE__FUNCTIONS_CODE
121*62c56f98SSadaf Ebrahimi            Test functions are substituted here
122*62c56f98SSadaf Ebrahimi            from the input test_suit_xyz.function
123*62c56f98SSadaf Ebrahimi            file. C preprocessor checks are generated
124*62c56f98SSadaf Ebrahimi            for the build dependencies specified
125*62c56f98SSadaf Ebrahimi            in the input file. This script also
126*62c56f98SSadaf Ebrahimi            generates wrappers for the test
127*62c56f98SSadaf Ebrahimi            functions with code to expand the
128*62c56f98SSadaf Ebrahimi            string parameters read from the data
129*62c56f98SSadaf Ebrahimi            file.
130*62c56f98SSadaf Ebrahimi__MBEDTLS_TEST_TEMPLATE__EXPRESSION_CODE
131*62c56f98SSadaf Ebrahimi            This script enumerates the
132*62c56f98SSadaf Ebrahimi            expressions in the .data file and
133*62c56f98SSadaf Ebrahimi            generates code to handle enumerated
134*62c56f98SSadaf Ebrahimi            expression Ids and return the values.
135*62c56f98SSadaf Ebrahimi__MBEDTLS_TEST_TEMPLATE__DEP_CHECK_CODE
136*62c56f98SSadaf Ebrahimi            This script enumerates all
137*62c56f98SSadaf Ebrahimi            build dependencies and generate
138*62c56f98SSadaf Ebrahimi            code to handle enumerated build
139*62c56f98SSadaf Ebrahimi            dependency Id and return status: if
140*62c56f98SSadaf Ebrahimi            the dependency is defined or not.
141*62c56f98SSadaf Ebrahimi__MBEDTLS_TEST_TEMPLATE__DISPATCH_CODE
142*62c56f98SSadaf Ebrahimi            This script enumerates the functions
143*62c56f98SSadaf Ebrahimi            specified in the input test data file
144*62c56f98SSadaf Ebrahimi            and generates the initializer for the
145*62c56f98SSadaf Ebrahimi            function table in the template
146*62c56f98SSadaf Ebrahimi            file.
147*62c56f98SSadaf Ebrahimi__MBEDTLS_TEST_TEMPLATE__PLATFORM_CODE
148*62c56f98SSadaf Ebrahimi            Platform specific setup and test
149*62c56f98SSadaf Ebrahimi            dispatch code.
150*62c56f98SSadaf Ebrahimi
151*62c56f98SSadaf Ebrahimi"""
152*62c56f98SSadaf Ebrahimi
153*62c56f98SSadaf Ebrahimi
154*62c56f98SSadaf Ebrahimiimport os
155*62c56f98SSadaf Ebrahimiimport re
156*62c56f98SSadaf Ebrahimiimport sys
157*62c56f98SSadaf Ebrahimiimport string
158*62c56f98SSadaf Ebrahimiimport argparse
159*62c56f98SSadaf Ebrahimi
160*62c56f98SSadaf Ebrahimi
161*62c56f98SSadaf Ebrahimi# Types recognized as signed integer arguments in test functions.
162*62c56f98SSadaf EbrahimiSIGNED_INTEGER_TYPES = frozenset([
163*62c56f98SSadaf Ebrahimi    'char',
164*62c56f98SSadaf Ebrahimi    'short',
165*62c56f98SSadaf Ebrahimi    'short int',
166*62c56f98SSadaf Ebrahimi    'int',
167*62c56f98SSadaf Ebrahimi    'int8_t',
168*62c56f98SSadaf Ebrahimi    'int16_t',
169*62c56f98SSadaf Ebrahimi    'int32_t',
170*62c56f98SSadaf Ebrahimi    'int64_t',
171*62c56f98SSadaf Ebrahimi    'intmax_t',
172*62c56f98SSadaf Ebrahimi    'long',
173*62c56f98SSadaf Ebrahimi    'long int',
174*62c56f98SSadaf Ebrahimi    'long long int',
175*62c56f98SSadaf Ebrahimi    'mbedtls_mpi_sint',
176*62c56f98SSadaf Ebrahimi    'psa_status_t',
177*62c56f98SSadaf Ebrahimi])
178*62c56f98SSadaf Ebrahimi# Types recognized as string arguments in test functions.
179*62c56f98SSadaf EbrahimiSTRING_TYPES = frozenset(['char*', 'const char*', 'char const*'])
180*62c56f98SSadaf Ebrahimi# Types recognized as hex data arguments in test functions.
181*62c56f98SSadaf EbrahimiDATA_TYPES = frozenset(['data_t*', 'const data_t*', 'data_t const*'])
182*62c56f98SSadaf Ebrahimi
183*62c56f98SSadaf EbrahimiBEGIN_HEADER_REGEX = r'/\*\s*BEGIN_HEADER\s*\*/'
184*62c56f98SSadaf EbrahimiEND_HEADER_REGEX = r'/\*\s*END_HEADER\s*\*/'
185*62c56f98SSadaf Ebrahimi
186*62c56f98SSadaf EbrahimiBEGIN_SUITE_HELPERS_REGEX = r'/\*\s*BEGIN_SUITE_HELPERS\s*\*/'
187*62c56f98SSadaf EbrahimiEND_SUITE_HELPERS_REGEX = r'/\*\s*END_SUITE_HELPERS\s*\*/'
188*62c56f98SSadaf Ebrahimi
189*62c56f98SSadaf EbrahimiBEGIN_DEP_REGEX = r'BEGIN_DEPENDENCIES'
190*62c56f98SSadaf EbrahimiEND_DEP_REGEX = r'END_DEPENDENCIES'
191*62c56f98SSadaf Ebrahimi
192*62c56f98SSadaf EbrahimiBEGIN_CASE_REGEX = r'/\*\s*BEGIN_CASE\s*(?P<depends_on>.*?)\s*\*/'
193*62c56f98SSadaf EbrahimiEND_CASE_REGEX = r'/\*\s*END_CASE\s*\*/'
194*62c56f98SSadaf Ebrahimi
195*62c56f98SSadaf EbrahimiDEPENDENCY_REGEX = r'depends_on:(?P<dependencies>.*)'
196*62c56f98SSadaf EbrahimiC_IDENTIFIER_REGEX = r'!?[a-z_][a-z0-9_]*'
197*62c56f98SSadaf EbrahimiCONDITION_OPERATOR_REGEX = r'[!=]=|[<>]=?'
198*62c56f98SSadaf Ebrahimi# forbid 0ddd which might be accidentally octal or accidentally decimal
199*62c56f98SSadaf EbrahimiCONDITION_VALUE_REGEX = r'[-+]?(0x[0-9a-f]+|0|[1-9][0-9]*)'
200*62c56f98SSadaf EbrahimiCONDITION_REGEX = r'({})(?:\s*({})\s*({}))?$'.format(C_IDENTIFIER_REGEX,
201*62c56f98SSadaf Ebrahimi                                                     CONDITION_OPERATOR_REGEX,
202*62c56f98SSadaf Ebrahimi                                                     CONDITION_VALUE_REGEX)
203*62c56f98SSadaf EbrahimiTEST_FUNCTION_VALIDATION_REGEX = r'\s*void\s+(?P<func_name>\w+)\s*\('
204*62c56f98SSadaf EbrahimiFUNCTION_ARG_LIST_END_REGEX = r'.*\)'
205*62c56f98SSadaf EbrahimiEXIT_LABEL_REGEX = r'^exit:'
206*62c56f98SSadaf Ebrahimi
207*62c56f98SSadaf Ebrahimi
208*62c56f98SSadaf Ebrahimiclass GeneratorInputError(Exception):
209*62c56f98SSadaf Ebrahimi    """
210*62c56f98SSadaf Ebrahimi    Exception to indicate error in the input files to this script.
211*62c56f98SSadaf Ebrahimi    This includes missing patterns, test function names and other
212*62c56f98SSadaf Ebrahimi    parsing errors.
213*62c56f98SSadaf Ebrahimi    """
214*62c56f98SSadaf Ebrahimi    pass
215*62c56f98SSadaf Ebrahimi
216*62c56f98SSadaf Ebrahimi
217*62c56f98SSadaf Ebrahimiclass FileWrapper:
218*62c56f98SSadaf Ebrahimi    """
219*62c56f98SSadaf Ebrahimi    This class extends the file object with attribute line_no,
220*62c56f98SSadaf Ebrahimi    that indicates line number for the line that is read.
221*62c56f98SSadaf Ebrahimi    """
222*62c56f98SSadaf Ebrahimi
223*62c56f98SSadaf Ebrahimi    def __init__(self, file_name) -> None:
224*62c56f98SSadaf Ebrahimi        """
225*62c56f98SSadaf Ebrahimi        Instantiate the file object and initialize the line number to 0.
226*62c56f98SSadaf Ebrahimi
227*62c56f98SSadaf Ebrahimi        :param file_name: File path to open.
228*62c56f98SSadaf Ebrahimi        """
229*62c56f98SSadaf Ebrahimi        # private mix-in file object
230*62c56f98SSadaf Ebrahimi        self._f = open(file_name, 'rb')
231*62c56f98SSadaf Ebrahimi        self._line_no = 0
232*62c56f98SSadaf Ebrahimi
233*62c56f98SSadaf Ebrahimi    def __iter__(self):
234*62c56f98SSadaf Ebrahimi        return self
235*62c56f98SSadaf Ebrahimi
236*62c56f98SSadaf Ebrahimi    def __next__(self):
237*62c56f98SSadaf Ebrahimi        """
238*62c56f98SSadaf Ebrahimi        This method makes FileWrapper iterable.
239*62c56f98SSadaf Ebrahimi        It counts the line numbers as each line is read.
240*62c56f98SSadaf Ebrahimi
241*62c56f98SSadaf Ebrahimi        :return: Line read from file.
242*62c56f98SSadaf Ebrahimi        """
243*62c56f98SSadaf Ebrahimi        line = self._f.__next__()
244*62c56f98SSadaf Ebrahimi        self._line_no += 1
245*62c56f98SSadaf Ebrahimi        # Convert byte array to string with correct encoding and
246*62c56f98SSadaf Ebrahimi        # strip any whitespaces added in the decoding process.
247*62c56f98SSadaf Ebrahimi        return line.decode(sys.getdefaultencoding()).rstrip()+ '\n'
248*62c56f98SSadaf Ebrahimi
249*62c56f98SSadaf Ebrahimi    def __enter__(self):
250*62c56f98SSadaf Ebrahimi        return self
251*62c56f98SSadaf Ebrahimi
252*62c56f98SSadaf Ebrahimi    def __exit__(self, exc_type, exc_val, exc_tb):
253*62c56f98SSadaf Ebrahimi        self._f.__exit__(exc_type, exc_val, exc_tb)
254*62c56f98SSadaf Ebrahimi
255*62c56f98SSadaf Ebrahimi    @property
256*62c56f98SSadaf Ebrahimi    def line_no(self):
257*62c56f98SSadaf Ebrahimi        """
258*62c56f98SSadaf Ebrahimi        Property that indicates line number for the line that is read.
259*62c56f98SSadaf Ebrahimi        """
260*62c56f98SSadaf Ebrahimi        return self._line_no
261*62c56f98SSadaf Ebrahimi
262*62c56f98SSadaf Ebrahimi    @property
263*62c56f98SSadaf Ebrahimi    def name(self):
264*62c56f98SSadaf Ebrahimi        """
265*62c56f98SSadaf Ebrahimi        Property that indicates name of the file that is read.
266*62c56f98SSadaf Ebrahimi        """
267*62c56f98SSadaf Ebrahimi        return self._f.name
268*62c56f98SSadaf Ebrahimi
269*62c56f98SSadaf Ebrahimi
270*62c56f98SSadaf Ebrahimidef split_dep(dep):
271*62c56f98SSadaf Ebrahimi    """
272*62c56f98SSadaf Ebrahimi    Split NOT character '!' from dependency. Used by gen_dependencies()
273*62c56f98SSadaf Ebrahimi
274*62c56f98SSadaf Ebrahimi    :param dep: Dependency list
275*62c56f98SSadaf Ebrahimi    :return: string tuple. Ex: ('!', MACRO) for !MACRO and ('', MACRO) for
276*62c56f98SSadaf Ebrahimi             MACRO.
277*62c56f98SSadaf Ebrahimi    """
278*62c56f98SSadaf Ebrahimi    return ('!', dep[1:]) if dep[0] == '!' else ('', dep)
279*62c56f98SSadaf Ebrahimi
280*62c56f98SSadaf Ebrahimi
281*62c56f98SSadaf Ebrahimidef gen_dependencies(dependencies):
282*62c56f98SSadaf Ebrahimi    """
283*62c56f98SSadaf Ebrahimi    Test suite data and functions specifies compile time dependencies.
284*62c56f98SSadaf Ebrahimi    This function generates C preprocessor code from the input
285*62c56f98SSadaf Ebrahimi    dependency list. Caller uses the generated preprocessor code to
286*62c56f98SSadaf Ebrahimi    wrap dependent code.
287*62c56f98SSadaf Ebrahimi    A dependency in the input list can have a leading '!' character
288*62c56f98SSadaf Ebrahimi    to negate a condition. '!' is separated from the dependency using
289*62c56f98SSadaf Ebrahimi    function split_dep() and proper preprocessor check is generated
290*62c56f98SSadaf Ebrahimi    accordingly.
291*62c56f98SSadaf Ebrahimi
292*62c56f98SSadaf Ebrahimi    :param dependencies: List of dependencies.
293*62c56f98SSadaf Ebrahimi    :return: if defined and endif code with macro annotations for
294*62c56f98SSadaf Ebrahimi             readability.
295*62c56f98SSadaf Ebrahimi    """
296*62c56f98SSadaf Ebrahimi    dep_start = ''.join(['#if %sdefined(%s)\n' % (x, y) for x, y in
297*62c56f98SSadaf Ebrahimi                         map(split_dep, dependencies)])
298*62c56f98SSadaf Ebrahimi    dep_end = ''.join(['#endif /* %s */\n' %
299*62c56f98SSadaf Ebrahimi                       x for x in reversed(dependencies)])
300*62c56f98SSadaf Ebrahimi
301*62c56f98SSadaf Ebrahimi    return dep_start, dep_end
302*62c56f98SSadaf Ebrahimi
303*62c56f98SSadaf Ebrahimi
304*62c56f98SSadaf Ebrahimidef gen_dependencies_one_line(dependencies):
305*62c56f98SSadaf Ebrahimi    """
306*62c56f98SSadaf Ebrahimi    Similar to gen_dependencies() but generates dependency checks in one line.
307*62c56f98SSadaf Ebrahimi    Useful for generating code with #else block.
308*62c56f98SSadaf Ebrahimi
309*62c56f98SSadaf Ebrahimi    :param dependencies: List of dependencies.
310*62c56f98SSadaf Ebrahimi    :return: Preprocessor check code
311*62c56f98SSadaf Ebrahimi    """
312*62c56f98SSadaf Ebrahimi    defines = '#if ' if dependencies else ''
313*62c56f98SSadaf Ebrahimi    defines += ' && '.join(['%sdefined(%s)' % (x, y) for x, y in map(
314*62c56f98SSadaf Ebrahimi        split_dep, dependencies)])
315*62c56f98SSadaf Ebrahimi    return defines
316*62c56f98SSadaf Ebrahimi
317*62c56f98SSadaf Ebrahimi
318*62c56f98SSadaf Ebrahimidef gen_function_wrapper(name, local_vars, args_dispatch):
319*62c56f98SSadaf Ebrahimi    """
320*62c56f98SSadaf Ebrahimi    Creates test function wrapper code. A wrapper has the code to
321*62c56f98SSadaf Ebrahimi    unpack parameters from parameters[] array.
322*62c56f98SSadaf Ebrahimi
323*62c56f98SSadaf Ebrahimi    :param name: Test function name
324*62c56f98SSadaf Ebrahimi    :param local_vars: Local variables declaration code
325*62c56f98SSadaf Ebrahimi    :param args_dispatch: List of dispatch arguments.
326*62c56f98SSadaf Ebrahimi           Ex: ['(char *) params[0]', '*((int *) params[1])']
327*62c56f98SSadaf Ebrahimi    :return: Test function wrapper.
328*62c56f98SSadaf Ebrahimi    """
329*62c56f98SSadaf Ebrahimi    # Then create the wrapper
330*62c56f98SSadaf Ebrahimi    wrapper = '''
331*62c56f98SSadaf Ebrahimivoid {name}_wrapper( void ** params )
332*62c56f98SSadaf Ebrahimi{{
333*62c56f98SSadaf Ebrahimi{unused_params}{locals}
334*62c56f98SSadaf Ebrahimi    {name}( {args} );
335*62c56f98SSadaf Ebrahimi}}
336*62c56f98SSadaf Ebrahimi'''.format(name=name,
337*62c56f98SSadaf Ebrahimi           unused_params='' if args_dispatch else '    (void)params;\n',
338*62c56f98SSadaf Ebrahimi           args=', '.join(args_dispatch),
339*62c56f98SSadaf Ebrahimi           locals=local_vars)
340*62c56f98SSadaf Ebrahimi    return wrapper
341*62c56f98SSadaf Ebrahimi
342*62c56f98SSadaf Ebrahimi
343*62c56f98SSadaf Ebrahimidef gen_dispatch(name, dependencies):
344*62c56f98SSadaf Ebrahimi    """
345*62c56f98SSadaf Ebrahimi    Test suite code template main_test.function defines a C function
346*62c56f98SSadaf Ebrahimi    array to contain test case functions. This function generates an
347*62c56f98SSadaf Ebrahimi    initializer entry for a function in that array. The entry is
348*62c56f98SSadaf Ebrahimi    composed of a compile time check for the test function
349*62c56f98SSadaf Ebrahimi    dependencies. At compile time the test function is assigned when
350*62c56f98SSadaf Ebrahimi    dependencies are met, else NULL is assigned.
351*62c56f98SSadaf Ebrahimi
352*62c56f98SSadaf Ebrahimi    :param name: Test function name
353*62c56f98SSadaf Ebrahimi    :param dependencies: List of dependencies
354*62c56f98SSadaf Ebrahimi    :return: Dispatch code.
355*62c56f98SSadaf Ebrahimi    """
356*62c56f98SSadaf Ebrahimi    if dependencies:
357*62c56f98SSadaf Ebrahimi        preprocessor_check = gen_dependencies_one_line(dependencies)
358*62c56f98SSadaf Ebrahimi        dispatch_code = '''
359*62c56f98SSadaf Ebrahimi{preprocessor_check}
360*62c56f98SSadaf Ebrahimi    {name}_wrapper,
361*62c56f98SSadaf Ebrahimi#else
362*62c56f98SSadaf Ebrahimi    NULL,
363*62c56f98SSadaf Ebrahimi#endif
364*62c56f98SSadaf Ebrahimi'''.format(preprocessor_check=preprocessor_check, name=name)
365*62c56f98SSadaf Ebrahimi    else:
366*62c56f98SSadaf Ebrahimi        dispatch_code = '''
367*62c56f98SSadaf Ebrahimi    {name}_wrapper,
368*62c56f98SSadaf Ebrahimi'''.format(name=name)
369*62c56f98SSadaf Ebrahimi
370*62c56f98SSadaf Ebrahimi    return dispatch_code
371*62c56f98SSadaf Ebrahimi
372*62c56f98SSadaf Ebrahimi
373*62c56f98SSadaf Ebrahimidef parse_until_pattern(funcs_f, end_regex):
374*62c56f98SSadaf Ebrahimi    """
375*62c56f98SSadaf Ebrahimi    Matches pattern end_regex to the lines read from the file object.
376*62c56f98SSadaf Ebrahimi    Returns the lines read until end pattern is matched.
377*62c56f98SSadaf Ebrahimi
378*62c56f98SSadaf Ebrahimi    :param funcs_f: file object for .function file
379*62c56f98SSadaf Ebrahimi    :param end_regex: Pattern to stop parsing
380*62c56f98SSadaf Ebrahimi    :return: Lines read before the end pattern
381*62c56f98SSadaf Ebrahimi    """
382*62c56f98SSadaf Ebrahimi    headers = '#line %d "%s"\n' % (funcs_f.line_no + 1, funcs_f.name)
383*62c56f98SSadaf Ebrahimi    for line in funcs_f:
384*62c56f98SSadaf Ebrahimi        if re.search(end_regex, line):
385*62c56f98SSadaf Ebrahimi            break
386*62c56f98SSadaf Ebrahimi        headers += line
387*62c56f98SSadaf Ebrahimi    else:
388*62c56f98SSadaf Ebrahimi        raise GeneratorInputError("file: %s - end pattern [%s] not found!" %
389*62c56f98SSadaf Ebrahimi                                  (funcs_f.name, end_regex))
390*62c56f98SSadaf Ebrahimi
391*62c56f98SSadaf Ebrahimi    return headers
392*62c56f98SSadaf Ebrahimi
393*62c56f98SSadaf Ebrahimi
394*62c56f98SSadaf Ebrahimidef validate_dependency(dependency):
395*62c56f98SSadaf Ebrahimi    """
396*62c56f98SSadaf Ebrahimi    Validates a C macro and raises GeneratorInputError on invalid input.
397*62c56f98SSadaf Ebrahimi    :param dependency: Input macro dependency
398*62c56f98SSadaf Ebrahimi    :return: input dependency stripped of leading & trailing white spaces.
399*62c56f98SSadaf Ebrahimi    """
400*62c56f98SSadaf Ebrahimi    dependency = dependency.strip()
401*62c56f98SSadaf Ebrahimi    if not re.match(CONDITION_REGEX, dependency, re.I):
402*62c56f98SSadaf Ebrahimi        raise GeneratorInputError('Invalid dependency %s' % dependency)
403*62c56f98SSadaf Ebrahimi    return dependency
404*62c56f98SSadaf Ebrahimi
405*62c56f98SSadaf Ebrahimi
406*62c56f98SSadaf Ebrahimidef parse_dependencies(inp_str):
407*62c56f98SSadaf Ebrahimi    """
408*62c56f98SSadaf Ebrahimi    Parses dependencies out of inp_str, validates them and returns a
409*62c56f98SSadaf Ebrahimi    list of macros.
410*62c56f98SSadaf Ebrahimi
411*62c56f98SSadaf Ebrahimi    :param inp_str: Input string with macros delimited by ':'.
412*62c56f98SSadaf Ebrahimi    :return: list of dependencies
413*62c56f98SSadaf Ebrahimi    """
414*62c56f98SSadaf Ebrahimi    dependencies = list(map(validate_dependency, inp_str.split(':')))
415*62c56f98SSadaf Ebrahimi    return dependencies
416*62c56f98SSadaf Ebrahimi
417*62c56f98SSadaf Ebrahimi
418*62c56f98SSadaf Ebrahimidef parse_suite_dependencies(funcs_f):
419*62c56f98SSadaf Ebrahimi    """
420*62c56f98SSadaf Ebrahimi    Parses test suite dependencies specified at the top of a
421*62c56f98SSadaf Ebrahimi    .function file, that starts with pattern BEGIN_DEPENDENCIES
422*62c56f98SSadaf Ebrahimi    and end with END_DEPENDENCIES. Dependencies are specified
423*62c56f98SSadaf Ebrahimi    after pattern 'depends_on:' and are delimited by ':'.
424*62c56f98SSadaf Ebrahimi
425*62c56f98SSadaf Ebrahimi    :param funcs_f: file object for .function file
426*62c56f98SSadaf Ebrahimi    :return: List of test suite dependencies.
427*62c56f98SSadaf Ebrahimi    """
428*62c56f98SSadaf Ebrahimi    dependencies = []
429*62c56f98SSadaf Ebrahimi    for line in funcs_f:
430*62c56f98SSadaf Ebrahimi        match = re.search(DEPENDENCY_REGEX, line.strip())
431*62c56f98SSadaf Ebrahimi        if match:
432*62c56f98SSadaf Ebrahimi            try:
433*62c56f98SSadaf Ebrahimi                dependencies = parse_dependencies(match.group('dependencies'))
434*62c56f98SSadaf Ebrahimi            except GeneratorInputError as error:
435*62c56f98SSadaf Ebrahimi                raise GeneratorInputError(
436*62c56f98SSadaf Ebrahimi                    str(error) + " - %s:%d" % (funcs_f.name, funcs_f.line_no))
437*62c56f98SSadaf Ebrahimi        if re.search(END_DEP_REGEX, line):
438*62c56f98SSadaf Ebrahimi            break
439*62c56f98SSadaf Ebrahimi    else:
440*62c56f98SSadaf Ebrahimi        raise GeneratorInputError("file: %s - end dependency pattern [%s]"
441*62c56f98SSadaf Ebrahimi                                  " not found!" % (funcs_f.name,
442*62c56f98SSadaf Ebrahimi                                                   END_DEP_REGEX))
443*62c56f98SSadaf Ebrahimi
444*62c56f98SSadaf Ebrahimi    return dependencies
445*62c56f98SSadaf Ebrahimi
446*62c56f98SSadaf Ebrahimi
447*62c56f98SSadaf Ebrahimidef parse_function_dependencies(line):
448*62c56f98SSadaf Ebrahimi    """
449*62c56f98SSadaf Ebrahimi    Parses function dependencies, that are in the same line as
450*62c56f98SSadaf Ebrahimi    comment BEGIN_CASE. Dependencies are specified after pattern
451*62c56f98SSadaf Ebrahimi    'depends_on:' and are delimited by ':'.
452*62c56f98SSadaf Ebrahimi
453*62c56f98SSadaf Ebrahimi    :param line: Line from .function file that has dependencies.
454*62c56f98SSadaf Ebrahimi    :return: List of dependencies.
455*62c56f98SSadaf Ebrahimi    """
456*62c56f98SSadaf Ebrahimi    dependencies = []
457*62c56f98SSadaf Ebrahimi    match = re.search(BEGIN_CASE_REGEX, line)
458*62c56f98SSadaf Ebrahimi    dep_str = match.group('depends_on')
459*62c56f98SSadaf Ebrahimi    if dep_str:
460*62c56f98SSadaf Ebrahimi        match = re.search(DEPENDENCY_REGEX, dep_str)
461*62c56f98SSadaf Ebrahimi        if match:
462*62c56f98SSadaf Ebrahimi            dependencies += parse_dependencies(match.group('dependencies'))
463*62c56f98SSadaf Ebrahimi
464*62c56f98SSadaf Ebrahimi    return dependencies
465*62c56f98SSadaf Ebrahimi
466*62c56f98SSadaf Ebrahimi
467*62c56f98SSadaf EbrahimiARGUMENT_DECLARATION_REGEX = re.compile(r'(.+?) ?(?:\bconst\b)? ?(\w+)\Z', re.S)
468*62c56f98SSadaf Ebrahimidef parse_function_argument(arg, arg_idx, args, local_vars, args_dispatch):
469*62c56f98SSadaf Ebrahimi    """
470*62c56f98SSadaf Ebrahimi    Parses one test function's argument declaration.
471*62c56f98SSadaf Ebrahimi
472*62c56f98SSadaf Ebrahimi    :param arg: argument declaration.
473*62c56f98SSadaf Ebrahimi    :param arg_idx: current wrapper argument index.
474*62c56f98SSadaf Ebrahimi    :param args: accumulator of arguments' internal types.
475*62c56f98SSadaf Ebrahimi    :param local_vars: accumulator of internal variable declarations.
476*62c56f98SSadaf Ebrahimi    :param args_dispatch: accumulator of argument usage expressions.
477*62c56f98SSadaf Ebrahimi    :return: the number of new wrapper arguments,
478*62c56f98SSadaf Ebrahimi             or None if the argument declaration is invalid.
479*62c56f98SSadaf Ebrahimi    """
480*62c56f98SSadaf Ebrahimi    # Normalize whitespace
481*62c56f98SSadaf Ebrahimi    arg = arg.strip()
482*62c56f98SSadaf Ebrahimi    arg = re.sub(r'\s*\*\s*', r'*', arg)
483*62c56f98SSadaf Ebrahimi    arg = re.sub(r'\s+', r' ', arg)
484*62c56f98SSadaf Ebrahimi    # Extract name and type
485*62c56f98SSadaf Ebrahimi    m = ARGUMENT_DECLARATION_REGEX.search(arg)
486*62c56f98SSadaf Ebrahimi    if not m:
487*62c56f98SSadaf Ebrahimi        # E.g. "int x[42]"
488*62c56f98SSadaf Ebrahimi        return None
489*62c56f98SSadaf Ebrahimi    typ, _ = m.groups()
490*62c56f98SSadaf Ebrahimi    if typ in SIGNED_INTEGER_TYPES:
491*62c56f98SSadaf Ebrahimi        args.append('int')
492*62c56f98SSadaf Ebrahimi        args_dispatch.append('((mbedtls_test_argument_t *) params[%d])->sint' % arg_idx)
493*62c56f98SSadaf Ebrahimi        return 1
494*62c56f98SSadaf Ebrahimi    if typ in STRING_TYPES:
495*62c56f98SSadaf Ebrahimi        args.append('char*')
496*62c56f98SSadaf Ebrahimi        args_dispatch.append('(char *) params[%d]' % arg_idx)
497*62c56f98SSadaf Ebrahimi        return 1
498*62c56f98SSadaf Ebrahimi    if typ in DATA_TYPES:
499*62c56f98SSadaf Ebrahimi        args.append('hex')
500*62c56f98SSadaf Ebrahimi        # create a structure
501*62c56f98SSadaf Ebrahimi        pointer_initializer = '(uint8_t *) params[%d]' % arg_idx
502*62c56f98SSadaf Ebrahimi        len_initializer = '((mbedtls_test_argument_t *) params[%d])->len' % (arg_idx+1)
503*62c56f98SSadaf Ebrahimi        local_vars.append('    data_t data%d = {%s, %s};\n' %
504*62c56f98SSadaf Ebrahimi                          (arg_idx, pointer_initializer, len_initializer))
505*62c56f98SSadaf Ebrahimi        args_dispatch.append('&data%d' % arg_idx)
506*62c56f98SSadaf Ebrahimi        return 2
507*62c56f98SSadaf Ebrahimi    return None
508*62c56f98SSadaf Ebrahimi
509*62c56f98SSadaf EbrahimiARGUMENT_LIST_REGEX = re.compile(r'\((.*?)\)', re.S)
510*62c56f98SSadaf Ebrahimidef parse_function_arguments(line):
511*62c56f98SSadaf Ebrahimi    """
512*62c56f98SSadaf Ebrahimi    Parses test function signature for validation and generates
513*62c56f98SSadaf Ebrahimi    a dispatch wrapper function that translates input test vectors
514*62c56f98SSadaf Ebrahimi    read from the data file into test function arguments.
515*62c56f98SSadaf Ebrahimi
516*62c56f98SSadaf Ebrahimi    :param line: Line from .function file that has a function
517*62c56f98SSadaf Ebrahimi                 signature.
518*62c56f98SSadaf Ebrahimi    :return: argument list, local variables for
519*62c56f98SSadaf Ebrahimi             wrapper function and argument dispatch code.
520*62c56f98SSadaf Ebrahimi    """
521*62c56f98SSadaf Ebrahimi    # Process arguments, ex: <type> arg1, <type> arg2 )
522*62c56f98SSadaf Ebrahimi    # This script assumes that the argument list is terminated by ')'
523*62c56f98SSadaf Ebrahimi    # i.e. the test functions will not have a function pointer
524*62c56f98SSadaf Ebrahimi    # argument.
525*62c56f98SSadaf Ebrahimi    m = ARGUMENT_LIST_REGEX.search(line)
526*62c56f98SSadaf Ebrahimi    arg_list = m.group(1).strip()
527*62c56f98SSadaf Ebrahimi    if arg_list in ['', 'void']:
528*62c56f98SSadaf Ebrahimi        return [], '', []
529*62c56f98SSadaf Ebrahimi    args = []
530*62c56f98SSadaf Ebrahimi    local_vars = []
531*62c56f98SSadaf Ebrahimi    args_dispatch = []
532*62c56f98SSadaf Ebrahimi    arg_idx = 0
533*62c56f98SSadaf Ebrahimi    for arg in arg_list.split(','):
534*62c56f98SSadaf Ebrahimi        indexes = parse_function_argument(arg, arg_idx,
535*62c56f98SSadaf Ebrahimi                                          args, local_vars, args_dispatch)
536*62c56f98SSadaf Ebrahimi        if indexes is None:
537*62c56f98SSadaf Ebrahimi            raise ValueError("Test function arguments can only be 'int', "
538*62c56f98SSadaf Ebrahimi                             "'char *' or 'data_t'\n%s" % line)
539*62c56f98SSadaf Ebrahimi        arg_idx += indexes
540*62c56f98SSadaf Ebrahimi
541*62c56f98SSadaf Ebrahimi    return args, ''.join(local_vars), args_dispatch
542*62c56f98SSadaf Ebrahimi
543*62c56f98SSadaf Ebrahimi
544*62c56f98SSadaf Ebrahimidef generate_function_code(name, code, local_vars, args_dispatch,
545*62c56f98SSadaf Ebrahimi                           dependencies):
546*62c56f98SSadaf Ebrahimi    """
547*62c56f98SSadaf Ebrahimi    Generate function code with preprocessor checks and parameter dispatch
548*62c56f98SSadaf Ebrahimi    wrapper.
549*62c56f98SSadaf Ebrahimi
550*62c56f98SSadaf Ebrahimi    :param name: Function name
551*62c56f98SSadaf Ebrahimi    :param code: Function code
552*62c56f98SSadaf Ebrahimi    :param local_vars: Local variables for function wrapper
553*62c56f98SSadaf Ebrahimi    :param args_dispatch: Argument dispatch code
554*62c56f98SSadaf Ebrahimi    :param dependencies: Preprocessor dependencies list
555*62c56f98SSadaf Ebrahimi    :return: Final function code
556*62c56f98SSadaf Ebrahimi    """
557*62c56f98SSadaf Ebrahimi    # Add exit label if not present
558*62c56f98SSadaf Ebrahimi    if code.find('exit:') == -1:
559*62c56f98SSadaf Ebrahimi        split_code = code.rsplit('}', 1)
560*62c56f98SSadaf Ebrahimi        if len(split_code) == 2:
561*62c56f98SSadaf Ebrahimi            code = """exit:
562*62c56f98SSadaf Ebrahimi    ;
563*62c56f98SSadaf Ebrahimi}""".join(split_code)
564*62c56f98SSadaf Ebrahimi
565*62c56f98SSadaf Ebrahimi    code += gen_function_wrapper(name, local_vars, args_dispatch)
566*62c56f98SSadaf Ebrahimi    preprocessor_check_start, preprocessor_check_end = \
567*62c56f98SSadaf Ebrahimi        gen_dependencies(dependencies)
568*62c56f98SSadaf Ebrahimi    return preprocessor_check_start + code + preprocessor_check_end
569*62c56f98SSadaf Ebrahimi
570*62c56f98SSadaf EbrahimiCOMMENT_START_REGEX = re.compile(r'/[*/]')
571*62c56f98SSadaf Ebrahimi
572*62c56f98SSadaf Ebrahimidef skip_comments(line, stream):
573*62c56f98SSadaf Ebrahimi    """Remove comments in line.
574*62c56f98SSadaf Ebrahimi
575*62c56f98SSadaf Ebrahimi    If the line contains an unfinished comment, read more lines from stream
576*62c56f98SSadaf Ebrahimi    until the line that contains the comment.
577*62c56f98SSadaf Ebrahimi
578*62c56f98SSadaf Ebrahimi    :return: The original line with inner comments replaced by spaces.
579*62c56f98SSadaf Ebrahimi             Trailing comments and whitespace may be removed completely.
580*62c56f98SSadaf Ebrahimi    """
581*62c56f98SSadaf Ebrahimi    pos = 0
582*62c56f98SSadaf Ebrahimi    while True:
583*62c56f98SSadaf Ebrahimi        opening = COMMENT_START_REGEX.search(line, pos)
584*62c56f98SSadaf Ebrahimi        if not opening:
585*62c56f98SSadaf Ebrahimi            break
586*62c56f98SSadaf Ebrahimi        if line[opening.start(0) + 1] == '/': # //...
587*62c56f98SSadaf Ebrahimi            continuation = line
588*62c56f98SSadaf Ebrahimi            # Count the number of line breaks, to keep line numbers aligned
589*62c56f98SSadaf Ebrahimi            # in the output.
590*62c56f98SSadaf Ebrahimi            line_count = 1
591*62c56f98SSadaf Ebrahimi            while continuation.endswith('\\\n'):
592*62c56f98SSadaf Ebrahimi                # This errors out if the file ends with an unfinished line
593*62c56f98SSadaf Ebrahimi                # comment. That's acceptable to not complicate the code further.
594*62c56f98SSadaf Ebrahimi                continuation = next(stream)
595*62c56f98SSadaf Ebrahimi                line_count += 1
596*62c56f98SSadaf Ebrahimi            return line[:opening.start(0)].rstrip() + '\n' * line_count
597*62c56f98SSadaf Ebrahimi        # Parsing /*...*/, looking for the end
598*62c56f98SSadaf Ebrahimi        closing = line.find('*/', opening.end(0))
599*62c56f98SSadaf Ebrahimi        while closing == -1:
600*62c56f98SSadaf Ebrahimi            # This errors out if the file ends with an unfinished block
601*62c56f98SSadaf Ebrahimi            # comment. That's acceptable to not complicate the code further.
602*62c56f98SSadaf Ebrahimi            line += next(stream)
603*62c56f98SSadaf Ebrahimi            closing = line.find('*/', opening.end(0))
604*62c56f98SSadaf Ebrahimi        pos = closing + 2
605*62c56f98SSadaf Ebrahimi        # Replace inner comment by spaces. There needs to be at least one space
606*62c56f98SSadaf Ebrahimi        # for things like 'int/*ihatespaces*/foo'. Go further and preserve the
607*62c56f98SSadaf Ebrahimi        # width of the comment and line breaks, this way positions in error
608*62c56f98SSadaf Ebrahimi        # messages remain correct.
609*62c56f98SSadaf Ebrahimi        line = (line[:opening.start(0)] +
610*62c56f98SSadaf Ebrahimi                re.sub(r'.', r' ', line[opening.start(0):pos]) +
611*62c56f98SSadaf Ebrahimi                line[pos:])
612*62c56f98SSadaf Ebrahimi    # Strip whitespace at the end of lines (it's irrelevant to error messages).
613*62c56f98SSadaf Ebrahimi    return re.sub(r' +(\n|\Z)', r'\1', line)
614*62c56f98SSadaf Ebrahimi
615*62c56f98SSadaf Ebrahimidef parse_function_code(funcs_f, dependencies, suite_dependencies):
616*62c56f98SSadaf Ebrahimi    """
617*62c56f98SSadaf Ebrahimi    Parses out a function from function file object and generates
618*62c56f98SSadaf Ebrahimi    function and dispatch code.
619*62c56f98SSadaf Ebrahimi
620*62c56f98SSadaf Ebrahimi    :param funcs_f: file object of the functions file.
621*62c56f98SSadaf Ebrahimi    :param dependencies: List of dependencies
622*62c56f98SSadaf Ebrahimi    :param suite_dependencies: List of test suite dependencies
623*62c56f98SSadaf Ebrahimi    :return: Function name, arguments, function code and dispatch code.
624*62c56f98SSadaf Ebrahimi    """
625*62c56f98SSadaf Ebrahimi    line_directive = '#line %d "%s"\n' % (funcs_f.line_no + 1, funcs_f.name)
626*62c56f98SSadaf Ebrahimi    code = ''
627*62c56f98SSadaf Ebrahimi    has_exit_label = False
628*62c56f98SSadaf Ebrahimi    for line in funcs_f:
629*62c56f98SSadaf Ebrahimi        # Check function signature. Function signature may be split
630*62c56f98SSadaf Ebrahimi        # across multiple lines. Here we try to find the start of
631*62c56f98SSadaf Ebrahimi        # arguments list, then remove '\n's and apply the regex to
632*62c56f98SSadaf Ebrahimi        # detect function start.
633*62c56f98SSadaf Ebrahimi        line = skip_comments(line, funcs_f)
634*62c56f98SSadaf Ebrahimi        up_to_arg_list_start = code + line[:line.find('(') + 1]
635*62c56f98SSadaf Ebrahimi        match = re.match(TEST_FUNCTION_VALIDATION_REGEX,
636*62c56f98SSadaf Ebrahimi                         up_to_arg_list_start.replace('\n', ' '), re.I)
637*62c56f98SSadaf Ebrahimi        if match:
638*62c56f98SSadaf Ebrahimi            # check if we have full signature i.e. split in more lines
639*62c56f98SSadaf Ebrahimi            name = match.group('func_name')
640*62c56f98SSadaf Ebrahimi            if not re.match(FUNCTION_ARG_LIST_END_REGEX, line):
641*62c56f98SSadaf Ebrahimi                for lin in funcs_f:
642*62c56f98SSadaf Ebrahimi                    line += skip_comments(lin, funcs_f)
643*62c56f98SSadaf Ebrahimi                    if re.search(FUNCTION_ARG_LIST_END_REGEX, line):
644*62c56f98SSadaf Ebrahimi                        break
645*62c56f98SSadaf Ebrahimi            args, local_vars, args_dispatch = parse_function_arguments(
646*62c56f98SSadaf Ebrahimi                line)
647*62c56f98SSadaf Ebrahimi            code += line
648*62c56f98SSadaf Ebrahimi            break
649*62c56f98SSadaf Ebrahimi        code += line
650*62c56f98SSadaf Ebrahimi    else:
651*62c56f98SSadaf Ebrahimi        raise GeneratorInputError("file: %s - Test functions not found!" %
652*62c56f98SSadaf Ebrahimi                                  funcs_f.name)
653*62c56f98SSadaf Ebrahimi
654*62c56f98SSadaf Ebrahimi    # Prefix test function name with 'test_'
655*62c56f98SSadaf Ebrahimi    code = code.replace(name, 'test_' + name, 1)
656*62c56f98SSadaf Ebrahimi    name = 'test_' + name
657*62c56f98SSadaf Ebrahimi
658*62c56f98SSadaf Ebrahimi    # If a test function has no arguments then add 'void' argument to
659*62c56f98SSadaf Ebrahimi    # avoid "-Wstrict-prototypes" warnings from clang
660*62c56f98SSadaf Ebrahimi    if len(args) == 0:
661*62c56f98SSadaf Ebrahimi        code = code.replace('()', '(void)', 1)
662*62c56f98SSadaf Ebrahimi
663*62c56f98SSadaf Ebrahimi    for line in funcs_f:
664*62c56f98SSadaf Ebrahimi        if re.search(END_CASE_REGEX, line):
665*62c56f98SSadaf Ebrahimi            break
666*62c56f98SSadaf Ebrahimi        if not has_exit_label:
667*62c56f98SSadaf Ebrahimi            has_exit_label = \
668*62c56f98SSadaf Ebrahimi                re.search(EXIT_LABEL_REGEX, line.strip()) is not None
669*62c56f98SSadaf Ebrahimi        code += line
670*62c56f98SSadaf Ebrahimi    else:
671*62c56f98SSadaf Ebrahimi        raise GeneratorInputError("file: %s - end case pattern [%s] not "
672*62c56f98SSadaf Ebrahimi                                  "found!" % (funcs_f.name, END_CASE_REGEX))
673*62c56f98SSadaf Ebrahimi
674*62c56f98SSadaf Ebrahimi    code = line_directive + code
675*62c56f98SSadaf Ebrahimi    code = generate_function_code(name, code, local_vars, args_dispatch,
676*62c56f98SSadaf Ebrahimi                                  dependencies)
677*62c56f98SSadaf Ebrahimi    dispatch_code = gen_dispatch(name, suite_dependencies + dependencies)
678*62c56f98SSadaf Ebrahimi    return (name, args, code, dispatch_code)
679*62c56f98SSadaf Ebrahimi
680*62c56f98SSadaf Ebrahimi
681*62c56f98SSadaf Ebrahimidef parse_functions(funcs_f):
682*62c56f98SSadaf Ebrahimi    """
683*62c56f98SSadaf Ebrahimi    Parses a test_suite_xxx.function file and returns information
684*62c56f98SSadaf Ebrahimi    for generating a C source file for the test suite.
685*62c56f98SSadaf Ebrahimi
686*62c56f98SSadaf Ebrahimi    :param funcs_f: file object of the functions file.
687*62c56f98SSadaf Ebrahimi    :return: List of test suite dependencies, test function dispatch
688*62c56f98SSadaf Ebrahimi             code, function code and a dict with function identifiers
689*62c56f98SSadaf Ebrahimi             and arguments info.
690*62c56f98SSadaf Ebrahimi    """
691*62c56f98SSadaf Ebrahimi    suite_helpers = ''
692*62c56f98SSadaf Ebrahimi    suite_dependencies = []
693*62c56f98SSadaf Ebrahimi    suite_functions = ''
694*62c56f98SSadaf Ebrahimi    func_info = {}
695*62c56f98SSadaf Ebrahimi    function_idx = 0
696*62c56f98SSadaf Ebrahimi    dispatch_code = ''
697*62c56f98SSadaf Ebrahimi    for line in funcs_f:
698*62c56f98SSadaf Ebrahimi        if re.search(BEGIN_HEADER_REGEX, line):
699*62c56f98SSadaf Ebrahimi            suite_helpers += parse_until_pattern(funcs_f, END_HEADER_REGEX)
700*62c56f98SSadaf Ebrahimi        elif re.search(BEGIN_SUITE_HELPERS_REGEX, line):
701*62c56f98SSadaf Ebrahimi            suite_helpers += parse_until_pattern(funcs_f,
702*62c56f98SSadaf Ebrahimi                                                 END_SUITE_HELPERS_REGEX)
703*62c56f98SSadaf Ebrahimi        elif re.search(BEGIN_DEP_REGEX, line):
704*62c56f98SSadaf Ebrahimi            suite_dependencies += parse_suite_dependencies(funcs_f)
705*62c56f98SSadaf Ebrahimi        elif re.search(BEGIN_CASE_REGEX, line):
706*62c56f98SSadaf Ebrahimi            try:
707*62c56f98SSadaf Ebrahimi                dependencies = parse_function_dependencies(line)
708*62c56f98SSadaf Ebrahimi            except GeneratorInputError as error:
709*62c56f98SSadaf Ebrahimi                raise GeneratorInputError(
710*62c56f98SSadaf Ebrahimi                    "%s:%d: %s" % (funcs_f.name, funcs_f.line_no,
711*62c56f98SSadaf Ebrahimi                                   str(error)))
712*62c56f98SSadaf Ebrahimi            func_name, args, func_code, func_dispatch =\
713*62c56f98SSadaf Ebrahimi                parse_function_code(funcs_f, dependencies, suite_dependencies)
714*62c56f98SSadaf Ebrahimi            suite_functions += func_code
715*62c56f98SSadaf Ebrahimi            # Generate dispatch code and enumeration info
716*62c56f98SSadaf Ebrahimi            if func_name in func_info:
717*62c56f98SSadaf Ebrahimi                raise GeneratorInputError(
718*62c56f98SSadaf Ebrahimi                    "file: %s - function %s re-declared at line %d" %
719*62c56f98SSadaf Ebrahimi                    (funcs_f.name, func_name, funcs_f.line_no))
720*62c56f98SSadaf Ebrahimi            func_info[func_name] = (function_idx, args)
721*62c56f98SSadaf Ebrahimi            dispatch_code += '/* Function Id: %d */\n' % function_idx
722*62c56f98SSadaf Ebrahimi            dispatch_code += func_dispatch
723*62c56f98SSadaf Ebrahimi            function_idx += 1
724*62c56f98SSadaf Ebrahimi
725*62c56f98SSadaf Ebrahimi    func_code = (suite_helpers +
726*62c56f98SSadaf Ebrahimi                 suite_functions).join(gen_dependencies(suite_dependencies))
727*62c56f98SSadaf Ebrahimi    return suite_dependencies, dispatch_code, func_code, func_info
728*62c56f98SSadaf Ebrahimi
729*62c56f98SSadaf Ebrahimi
730*62c56f98SSadaf Ebrahimidef escaped_split(inp_str, split_char):
731*62c56f98SSadaf Ebrahimi    """
732*62c56f98SSadaf Ebrahimi    Split inp_str on character split_char but ignore if escaped.
733*62c56f98SSadaf Ebrahimi    Since, return value is used to write back to the intermediate
734*62c56f98SSadaf Ebrahimi    data file, any escape characters in the input are retained in the
735*62c56f98SSadaf Ebrahimi    output.
736*62c56f98SSadaf Ebrahimi
737*62c56f98SSadaf Ebrahimi    :param inp_str: String to split
738*62c56f98SSadaf Ebrahimi    :param split_char: Split character
739*62c56f98SSadaf Ebrahimi    :return: List of splits
740*62c56f98SSadaf Ebrahimi    """
741*62c56f98SSadaf Ebrahimi    if len(split_char) > 1:
742*62c56f98SSadaf Ebrahimi        raise ValueError('Expected split character. Found string!')
743*62c56f98SSadaf Ebrahimi    out = re.sub(r'(\\.)|' + split_char,
744*62c56f98SSadaf Ebrahimi                 lambda m: m.group(1) or '\n', inp_str,
745*62c56f98SSadaf Ebrahimi                 len(inp_str)).split('\n')
746*62c56f98SSadaf Ebrahimi    out = [x for x in out if x]
747*62c56f98SSadaf Ebrahimi    return out
748*62c56f98SSadaf Ebrahimi
749*62c56f98SSadaf Ebrahimi
750*62c56f98SSadaf Ebrahimidef parse_test_data(data_f):
751*62c56f98SSadaf Ebrahimi    """
752*62c56f98SSadaf Ebrahimi    Parses .data file for each test case name, test function name,
753*62c56f98SSadaf Ebrahimi    test dependencies and test arguments. This information is
754*62c56f98SSadaf Ebrahimi    correlated with the test functions file for generating an
755*62c56f98SSadaf Ebrahimi    intermediate data file replacing the strings for test function
756*62c56f98SSadaf Ebrahimi    names, dependencies and integer constant expressions with
757*62c56f98SSadaf Ebrahimi    identifiers. Mainly for optimising space for on-target
758*62c56f98SSadaf Ebrahimi    execution.
759*62c56f98SSadaf Ebrahimi
760*62c56f98SSadaf Ebrahimi    :param data_f: file object of the data file.
761*62c56f98SSadaf Ebrahimi    :return: Generator that yields line number, test name, function name,
762*62c56f98SSadaf Ebrahimi             dependency list and function argument list.
763*62c56f98SSadaf Ebrahimi    """
764*62c56f98SSadaf Ebrahimi    __state_read_name = 0
765*62c56f98SSadaf Ebrahimi    __state_read_args = 1
766*62c56f98SSadaf Ebrahimi    state = __state_read_name
767*62c56f98SSadaf Ebrahimi    dependencies = []
768*62c56f98SSadaf Ebrahimi    name = ''
769*62c56f98SSadaf Ebrahimi    for line in data_f:
770*62c56f98SSadaf Ebrahimi        line = line.strip()
771*62c56f98SSadaf Ebrahimi        # Skip comments
772*62c56f98SSadaf Ebrahimi        if line.startswith('#'):
773*62c56f98SSadaf Ebrahimi            continue
774*62c56f98SSadaf Ebrahimi
775*62c56f98SSadaf Ebrahimi        # Blank line indicates end of test
776*62c56f98SSadaf Ebrahimi        if not line:
777*62c56f98SSadaf Ebrahimi            if state == __state_read_args:
778*62c56f98SSadaf Ebrahimi                raise GeneratorInputError("[%s:%d] Newline before arguments. "
779*62c56f98SSadaf Ebrahimi                                          "Test function and arguments "
780*62c56f98SSadaf Ebrahimi                                          "missing for %s" %
781*62c56f98SSadaf Ebrahimi                                          (data_f.name, data_f.line_no, name))
782*62c56f98SSadaf Ebrahimi            continue
783*62c56f98SSadaf Ebrahimi
784*62c56f98SSadaf Ebrahimi        if state == __state_read_name:
785*62c56f98SSadaf Ebrahimi            # Read test name
786*62c56f98SSadaf Ebrahimi            name = line
787*62c56f98SSadaf Ebrahimi            state = __state_read_args
788*62c56f98SSadaf Ebrahimi        elif state == __state_read_args:
789*62c56f98SSadaf Ebrahimi            # Check dependencies
790*62c56f98SSadaf Ebrahimi            match = re.search(DEPENDENCY_REGEX, line)
791*62c56f98SSadaf Ebrahimi            if match:
792*62c56f98SSadaf Ebrahimi                try:
793*62c56f98SSadaf Ebrahimi                    dependencies = parse_dependencies(
794*62c56f98SSadaf Ebrahimi                        match.group('dependencies'))
795*62c56f98SSadaf Ebrahimi                except GeneratorInputError as error:
796*62c56f98SSadaf Ebrahimi                    raise GeneratorInputError(
797*62c56f98SSadaf Ebrahimi                        str(error) + " - %s:%d" %
798*62c56f98SSadaf Ebrahimi                        (data_f.name, data_f.line_no))
799*62c56f98SSadaf Ebrahimi            else:
800*62c56f98SSadaf Ebrahimi                # Read test vectors
801*62c56f98SSadaf Ebrahimi                parts = escaped_split(line, ':')
802*62c56f98SSadaf Ebrahimi                test_function = parts[0]
803*62c56f98SSadaf Ebrahimi                args = parts[1:]
804*62c56f98SSadaf Ebrahimi                yield data_f.line_no, name, test_function, dependencies, args
805*62c56f98SSadaf Ebrahimi                dependencies = []
806*62c56f98SSadaf Ebrahimi                state = __state_read_name
807*62c56f98SSadaf Ebrahimi    if state == __state_read_args:
808*62c56f98SSadaf Ebrahimi        raise GeneratorInputError("[%s:%d] Newline before arguments. "
809*62c56f98SSadaf Ebrahimi                                  "Test function and arguments missing for "
810*62c56f98SSadaf Ebrahimi                                  "%s" % (data_f.name, data_f.line_no, name))
811*62c56f98SSadaf Ebrahimi
812*62c56f98SSadaf Ebrahimi
813*62c56f98SSadaf Ebrahimidef gen_dep_check(dep_id, dep):
814*62c56f98SSadaf Ebrahimi    """
815*62c56f98SSadaf Ebrahimi    Generate code for checking dependency with the associated
816*62c56f98SSadaf Ebrahimi    identifier.
817*62c56f98SSadaf Ebrahimi
818*62c56f98SSadaf Ebrahimi    :param dep_id: Dependency identifier
819*62c56f98SSadaf Ebrahimi    :param dep: Dependency macro
820*62c56f98SSadaf Ebrahimi    :return: Dependency check code
821*62c56f98SSadaf Ebrahimi    """
822*62c56f98SSadaf Ebrahimi    if dep_id < 0:
823*62c56f98SSadaf Ebrahimi        raise GeneratorInputError("Dependency Id should be a positive "
824*62c56f98SSadaf Ebrahimi                                  "integer.")
825*62c56f98SSadaf Ebrahimi    _not, dep = ('!', dep[1:]) if dep[0] == '!' else ('', dep)
826*62c56f98SSadaf Ebrahimi    if not dep:
827*62c56f98SSadaf Ebrahimi        raise GeneratorInputError("Dependency should not be an empty string.")
828*62c56f98SSadaf Ebrahimi
829*62c56f98SSadaf Ebrahimi    dependency = re.match(CONDITION_REGEX, dep, re.I)
830*62c56f98SSadaf Ebrahimi    if not dependency:
831*62c56f98SSadaf Ebrahimi        raise GeneratorInputError('Invalid dependency %s' % dep)
832*62c56f98SSadaf Ebrahimi
833*62c56f98SSadaf Ebrahimi    _defined = '' if dependency.group(2) else 'defined'
834*62c56f98SSadaf Ebrahimi    _cond = dependency.group(2) if dependency.group(2) else ''
835*62c56f98SSadaf Ebrahimi    _value = dependency.group(3) if dependency.group(3) else ''
836*62c56f98SSadaf Ebrahimi
837*62c56f98SSadaf Ebrahimi    dep_check = '''
838*62c56f98SSadaf Ebrahimi        case {id}:
839*62c56f98SSadaf Ebrahimi            {{
840*62c56f98SSadaf Ebrahimi#if {_not}{_defined}({macro}{_cond}{_value})
841*62c56f98SSadaf Ebrahimi                ret = DEPENDENCY_SUPPORTED;
842*62c56f98SSadaf Ebrahimi#else
843*62c56f98SSadaf Ebrahimi                ret = DEPENDENCY_NOT_SUPPORTED;
844*62c56f98SSadaf Ebrahimi#endif
845*62c56f98SSadaf Ebrahimi            }}
846*62c56f98SSadaf Ebrahimi            break;'''.format(_not=_not, _defined=_defined,
847*62c56f98SSadaf Ebrahimi                             macro=dependency.group(1), id=dep_id,
848*62c56f98SSadaf Ebrahimi                             _cond=_cond, _value=_value)
849*62c56f98SSadaf Ebrahimi    return dep_check
850*62c56f98SSadaf Ebrahimi
851*62c56f98SSadaf Ebrahimi
852*62c56f98SSadaf Ebrahimidef gen_expression_check(exp_id, exp):
853*62c56f98SSadaf Ebrahimi    """
854*62c56f98SSadaf Ebrahimi    Generates code for evaluating an integer expression using
855*62c56f98SSadaf Ebrahimi    associated expression Id.
856*62c56f98SSadaf Ebrahimi
857*62c56f98SSadaf Ebrahimi    :param exp_id: Expression Identifier
858*62c56f98SSadaf Ebrahimi    :param exp: Expression/Macro
859*62c56f98SSadaf Ebrahimi    :return: Expression check code
860*62c56f98SSadaf Ebrahimi    """
861*62c56f98SSadaf Ebrahimi    if exp_id < 0:
862*62c56f98SSadaf Ebrahimi        raise GeneratorInputError("Expression Id should be a positive "
863*62c56f98SSadaf Ebrahimi                                  "integer.")
864*62c56f98SSadaf Ebrahimi    if not exp:
865*62c56f98SSadaf Ebrahimi        raise GeneratorInputError("Expression should not be an empty string.")
866*62c56f98SSadaf Ebrahimi    exp_code = '''
867*62c56f98SSadaf Ebrahimi        case {exp_id}:
868*62c56f98SSadaf Ebrahimi            {{
869*62c56f98SSadaf Ebrahimi                *out_value = {expression};
870*62c56f98SSadaf Ebrahimi            }}
871*62c56f98SSadaf Ebrahimi            break;'''.format(exp_id=exp_id, expression=exp)
872*62c56f98SSadaf Ebrahimi    return exp_code
873*62c56f98SSadaf Ebrahimi
874*62c56f98SSadaf Ebrahimi
875*62c56f98SSadaf Ebrahimidef write_dependencies(out_data_f, test_dependencies, unique_dependencies):
876*62c56f98SSadaf Ebrahimi    """
877*62c56f98SSadaf Ebrahimi    Write dependencies to intermediate test data file, replacing
878*62c56f98SSadaf Ebrahimi    the string form with identifiers. Also, generates dependency
879*62c56f98SSadaf Ebrahimi    check code.
880*62c56f98SSadaf Ebrahimi
881*62c56f98SSadaf Ebrahimi    :param out_data_f: Output intermediate data file
882*62c56f98SSadaf Ebrahimi    :param test_dependencies: Dependencies
883*62c56f98SSadaf Ebrahimi    :param unique_dependencies: Mutable list to track unique dependencies
884*62c56f98SSadaf Ebrahimi           that are global to this re-entrant function.
885*62c56f98SSadaf Ebrahimi    :return: returns dependency check code.
886*62c56f98SSadaf Ebrahimi    """
887*62c56f98SSadaf Ebrahimi    dep_check_code = ''
888*62c56f98SSadaf Ebrahimi    if test_dependencies:
889*62c56f98SSadaf Ebrahimi        out_data_f.write('depends_on')
890*62c56f98SSadaf Ebrahimi        for dep in test_dependencies:
891*62c56f98SSadaf Ebrahimi            if dep not in unique_dependencies:
892*62c56f98SSadaf Ebrahimi                unique_dependencies.append(dep)
893*62c56f98SSadaf Ebrahimi                dep_id = unique_dependencies.index(dep)
894*62c56f98SSadaf Ebrahimi                dep_check_code += gen_dep_check(dep_id, dep)
895*62c56f98SSadaf Ebrahimi            else:
896*62c56f98SSadaf Ebrahimi                dep_id = unique_dependencies.index(dep)
897*62c56f98SSadaf Ebrahimi            out_data_f.write(':' + str(dep_id))
898*62c56f98SSadaf Ebrahimi        out_data_f.write('\n')
899*62c56f98SSadaf Ebrahimi    return dep_check_code
900*62c56f98SSadaf Ebrahimi
901*62c56f98SSadaf Ebrahimi
902*62c56f98SSadaf EbrahimiINT_VAL_REGEX = re.compile(r'-?(\d+|0x[0-9a-f]+)$', re.I)
903*62c56f98SSadaf Ebrahimidef val_is_int(val: str) -> bool:
904*62c56f98SSadaf Ebrahimi    """Whether val is suitable as an 'int' parameter in the .datax file."""
905*62c56f98SSadaf Ebrahimi    if not INT_VAL_REGEX.match(val):
906*62c56f98SSadaf Ebrahimi        return False
907*62c56f98SSadaf Ebrahimi    # Limit the range to what is guaranteed to get through strtol()
908*62c56f98SSadaf Ebrahimi    return abs(int(val, 0)) <= 0x7fffffff
909*62c56f98SSadaf Ebrahimi
910*62c56f98SSadaf Ebrahimidef write_parameters(out_data_f, test_args, func_args, unique_expressions):
911*62c56f98SSadaf Ebrahimi    """
912*62c56f98SSadaf Ebrahimi    Writes test parameters to the intermediate data file, replacing
913*62c56f98SSadaf Ebrahimi    the string form with identifiers. Also, generates expression
914*62c56f98SSadaf Ebrahimi    check code.
915*62c56f98SSadaf Ebrahimi
916*62c56f98SSadaf Ebrahimi    :param out_data_f: Output intermediate data file
917*62c56f98SSadaf Ebrahimi    :param test_args: Test parameters
918*62c56f98SSadaf Ebrahimi    :param func_args: Function arguments
919*62c56f98SSadaf Ebrahimi    :param unique_expressions: Mutable list to track unique
920*62c56f98SSadaf Ebrahimi           expressions that are global to this re-entrant function.
921*62c56f98SSadaf Ebrahimi    :return: Returns expression check code.
922*62c56f98SSadaf Ebrahimi    """
923*62c56f98SSadaf Ebrahimi    expression_code = ''
924*62c56f98SSadaf Ebrahimi    for i, _ in enumerate(test_args):
925*62c56f98SSadaf Ebrahimi        typ = func_args[i]
926*62c56f98SSadaf Ebrahimi        val = test_args[i]
927*62c56f98SSadaf Ebrahimi
928*62c56f98SSadaf Ebrahimi        # Pass small integer constants literally. This reduces the size of
929*62c56f98SSadaf Ebrahimi        # the C code. Register anything else as an expression.
930*62c56f98SSadaf Ebrahimi        if typ == 'int' and not val_is_int(val):
931*62c56f98SSadaf Ebrahimi            typ = 'exp'
932*62c56f98SSadaf Ebrahimi            if val not in unique_expressions:
933*62c56f98SSadaf Ebrahimi                unique_expressions.append(val)
934*62c56f98SSadaf Ebrahimi                # exp_id can be derived from len(). But for
935*62c56f98SSadaf Ebrahimi                # readability and consistency with case of existing
936*62c56f98SSadaf Ebrahimi                # let's use index().
937*62c56f98SSadaf Ebrahimi                exp_id = unique_expressions.index(val)
938*62c56f98SSadaf Ebrahimi                expression_code += gen_expression_check(exp_id, val)
939*62c56f98SSadaf Ebrahimi                val = exp_id
940*62c56f98SSadaf Ebrahimi            else:
941*62c56f98SSadaf Ebrahimi                val = unique_expressions.index(val)
942*62c56f98SSadaf Ebrahimi        out_data_f.write(':' + typ + ':' + str(val))
943*62c56f98SSadaf Ebrahimi    out_data_f.write('\n')
944*62c56f98SSadaf Ebrahimi    return expression_code
945*62c56f98SSadaf Ebrahimi
946*62c56f98SSadaf Ebrahimi
947*62c56f98SSadaf Ebrahimidef gen_suite_dep_checks(suite_dependencies, dep_check_code, expression_code):
948*62c56f98SSadaf Ebrahimi    """
949*62c56f98SSadaf Ebrahimi    Generates preprocessor checks for test suite dependencies.
950*62c56f98SSadaf Ebrahimi
951*62c56f98SSadaf Ebrahimi    :param suite_dependencies: Test suite dependencies read from the
952*62c56f98SSadaf Ebrahimi            .function file.
953*62c56f98SSadaf Ebrahimi    :param dep_check_code: Dependency check code
954*62c56f98SSadaf Ebrahimi    :param expression_code: Expression check code
955*62c56f98SSadaf Ebrahimi    :return: Dependency and expression code guarded by test suite
956*62c56f98SSadaf Ebrahimi             dependencies.
957*62c56f98SSadaf Ebrahimi    """
958*62c56f98SSadaf Ebrahimi    if suite_dependencies:
959*62c56f98SSadaf Ebrahimi        preprocessor_check = gen_dependencies_one_line(suite_dependencies)
960*62c56f98SSadaf Ebrahimi        dep_check_code = '''
961*62c56f98SSadaf Ebrahimi{preprocessor_check}
962*62c56f98SSadaf Ebrahimi{code}
963*62c56f98SSadaf Ebrahimi#endif
964*62c56f98SSadaf Ebrahimi'''.format(preprocessor_check=preprocessor_check, code=dep_check_code)
965*62c56f98SSadaf Ebrahimi        expression_code = '''
966*62c56f98SSadaf Ebrahimi{preprocessor_check}
967*62c56f98SSadaf Ebrahimi{code}
968*62c56f98SSadaf Ebrahimi#endif
969*62c56f98SSadaf Ebrahimi'''.format(preprocessor_check=preprocessor_check, code=expression_code)
970*62c56f98SSadaf Ebrahimi    return dep_check_code, expression_code
971*62c56f98SSadaf Ebrahimi
972*62c56f98SSadaf Ebrahimi
973*62c56f98SSadaf Ebrahimidef get_function_info(func_info, function_name, line_no):
974*62c56f98SSadaf Ebrahimi    """Look up information about a test function by name.
975*62c56f98SSadaf Ebrahimi
976*62c56f98SSadaf Ebrahimi    Raise an informative expression if function_name is not found.
977*62c56f98SSadaf Ebrahimi
978*62c56f98SSadaf Ebrahimi    :param func_info: dictionary mapping function names to their information.
979*62c56f98SSadaf Ebrahimi    :param function_name: the function name as written in the .function and
980*62c56f98SSadaf Ebrahimi                          .data files.
981*62c56f98SSadaf Ebrahimi    :param line_no: line number for error messages.
982*62c56f98SSadaf Ebrahimi    :return Function information (id, args).
983*62c56f98SSadaf Ebrahimi    """
984*62c56f98SSadaf Ebrahimi    test_function_name = 'test_' + function_name
985*62c56f98SSadaf Ebrahimi    if test_function_name not in func_info:
986*62c56f98SSadaf Ebrahimi        raise GeneratorInputError("%d: Function %s not found!" %
987*62c56f98SSadaf Ebrahimi                                  (line_no, test_function_name))
988*62c56f98SSadaf Ebrahimi    return func_info[test_function_name]
989*62c56f98SSadaf Ebrahimi
990*62c56f98SSadaf Ebrahimi
991*62c56f98SSadaf Ebrahimidef gen_from_test_data(data_f, out_data_f, func_info, suite_dependencies):
992*62c56f98SSadaf Ebrahimi    """
993*62c56f98SSadaf Ebrahimi    This function reads test case name, dependencies and test vectors
994*62c56f98SSadaf Ebrahimi    from the .data file. This information is correlated with the test
995*62c56f98SSadaf Ebrahimi    functions file for generating an intermediate data file replacing
996*62c56f98SSadaf Ebrahimi    the strings for test function names, dependencies and integer
997*62c56f98SSadaf Ebrahimi    constant expressions with identifiers. Mainly for optimising
998*62c56f98SSadaf Ebrahimi    space for on-target execution.
999*62c56f98SSadaf Ebrahimi    It also generates test case dependency check code and expression
1000*62c56f98SSadaf Ebrahimi    evaluation code.
1001*62c56f98SSadaf Ebrahimi
1002*62c56f98SSadaf Ebrahimi    :param data_f: Data file object
1003*62c56f98SSadaf Ebrahimi    :param out_data_f: Output intermediate data file
1004*62c56f98SSadaf Ebrahimi    :param func_info: Dict keyed by function and with function id
1005*62c56f98SSadaf Ebrahimi           and arguments info
1006*62c56f98SSadaf Ebrahimi    :param suite_dependencies: Test suite dependencies
1007*62c56f98SSadaf Ebrahimi    :return: Returns dependency and expression check code
1008*62c56f98SSadaf Ebrahimi    """
1009*62c56f98SSadaf Ebrahimi    unique_dependencies = []
1010*62c56f98SSadaf Ebrahimi    unique_expressions = []
1011*62c56f98SSadaf Ebrahimi    dep_check_code = ''
1012*62c56f98SSadaf Ebrahimi    expression_code = ''
1013*62c56f98SSadaf Ebrahimi    for line_no, test_name, function_name, test_dependencies, test_args in \
1014*62c56f98SSadaf Ebrahimi            parse_test_data(data_f):
1015*62c56f98SSadaf Ebrahimi        out_data_f.write(test_name + '\n')
1016*62c56f98SSadaf Ebrahimi
1017*62c56f98SSadaf Ebrahimi        # Write dependencies
1018*62c56f98SSadaf Ebrahimi        dep_check_code += write_dependencies(out_data_f, test_dependencies,
1019*62c56f98SSadaf Ebrahimi                                             unique_dependencies)
1020*62c56f98SSadaf Ebrahimi
1021*62c56f98SSadaf Ebrahimi        # Write test function name
1022*62c56f98SSadaf Ebrahimi        func_id, func_args = \
1023*62c56f98SSadaf Ebrahimi            get_function_info(func_info, function_name, line_no)
1024*62c56f98SSadaf Ebrahimi        out_data_f.write(str(func_id))
1025*62c56f98SSadaf Ebrahimi
1026*62c56f98SSadaf Ebrahimi        # Write parameters
1027*62c56f98SSadaf Ebrahimi        if len(test_args) != len(func_args):
1028*62c56f98SSadaf Ebrahimi            raise GeneratorInputError("%d: Invalid number of arguments in test "
1029*62c56f98SSadaf Ebrahimi                                      "%s. See function %s signature." %
1030*62c56f98SSadaf Ebrahimi                                      (line_no, test_name, function_name))
1031*62c56f98SSadaf Ebrahimi        expression_code += write_parameters(out_data_f, test_args, func_args,
1032*62c56f98SSadaf Ebrahimi                                            unique_expressions)
1033*62c56f98SSadaf Ebrahimi
1034*62c56f98SSadaf Ebrahimi        # Write a newline as test case separator
1035*62c56f98SSadaf Ebrahimi        out_data_f.write('\n')
1036*62c56f98SSadaf Ebrahimi
1037*62c56f98SSadaf Ebrahimi    dep_check_code, expression_code = gen_suite_dep_checks(
1038*62c56f98SSadaf Ebrahimi        suite_dependencies, dep_check_code, expression_code)
1039*62c56f98SSadaf Ebrahimi    return dep_check_code, expression_code
1040*62c56f98SSadaf Ebrahimi
1041*62c56f98SSadaf Ebrahimi
1042*62c56f98SSadaf Ebrahimidef add_input_info(funcs_file, data_file, template_file,
1043*62c56f98SSadaf Ebrahimi                   c_file, snippets):
1044*62c56f98SSadaf Ebrahimi    """
1045*62c56f98SSadaf Ebrahimi    Add generator input info in snippets.
1046*62c56f98SSadaf Ebrahimi
1047*62c56f98SSadaf Ebrahimi    :param funcs_file: Functions file object
1048*62c56f98SSadaf Ebrahimi    :param data_file: Data file object
1049*62c56f98SSadaf Ebrahimi    :param template_file: Template file object
1050*62c56f98SSadaf Ebrahimi    :param c_file: Output C file object
1051*62c56f98SSadaf Ebrahimi    :param snippets: Dictionary to contain code pieces to be
1052*62c56f98SSadaf Ebrahimi                     substituted in the template.
1053*62c56f98SSadaf Ebrahimi    :return:
1054*62c56f98SSadaf Ebrahimi    """
1055*62c56f98SSadaf Ebrahimi    snippets['test_file'] = c_file
1056*62c56f98SSadaf Ebrahimi    snippets['test_main_file'] = template_file
1057*62c56f98SSadaf Ebrahimi    snippets['test_case_file'] = funcs_file
1058*62c56f98SSadaf Ebrahimi    snippets['test_case_data_file'] = data_file
1059*62c56f98SSadaf Ebrahimi
1060*62c56f98SSadaf Ebrahimi
1061*62c56f98SSadaf Ebrahimidef read_code_from_input_files(platform_file, helpers_file,
1062*62c56f98SSadaf Ebrahimi                               out_data_file, snippets):
1063*62c56f98SSadaf Ebrahimi    """
1064*62c56f98SSadaf Ebrahimi    Read code from input files and create substitutions for replacement
1065*62c56f98SSadaf Ebrahimi    strings in the template file.
1066*62c56f98SSadaf Ebrahimi
1067*62c56f98SSadaf Ebrahimi    :param platform_file: Platform file object
1068*62c56f98SSadaf Ebrahimi    :param helpers_file: Helper functions file object
1069*62c56f98SSadaf Ebrahimi    :param out_data_file: Output intermediate data file object
1070*62c56f98SSadaf Ebrahimi    :param snippets: Dictionary to contain code pieces to be
1071*62c56f98SSadaf Ebrahimi                     substituted in the template.
1072*62c56f98SSadaf Ebrahimi    :return:
1073*62c56f98SSadaf Ebrahimi    """
1074*62c56f98SSadaf Ebrahimi    # Read helpers
1075*62c56f98SSadaf Ebrahimi    with open(helpers_file, 'r') as help_f, open(platform_file, 'r') as \
1076*62c56f98SSadaf Ebrahimi            platform_f:
1077*62c56f98SSadaf Ebrahimi        snippets['test_common_helper_file'] = helpers_file
1078*62c56f98SSadaf Ebrahimi        snippets['test_common_helpers'] = help_f.read()
1079*62c56f98SSadaf Ebrahimi        snippets['test_platform_file'] = platform_file
1080*62c56f98SSadaf Ebrahimi        snippets['platform_code'] = platform_f.read().replace(
1081*62c56f98SSadaf Ebrahimi            'DATA_FILE', out_data_file.replace('\\', '\\\\'))  # escape '\'
1082*62c56f98SSadaf Ebrahimi
1083*62c56f98SSadaf Ebrahimi
1084*62c56f98SSadaf Ebrahimidef write_test_source_file(template_file, c_file, snippets):
1085*62c56f98SSadaf Ebrahimi    """
1086*62c56f98SSadaf Ebrahimi    Write output source file with generated source code.
1087*62c56f98SSadaf Ebrahimi
1088*62c56f98SSadaf Ebrahimi    :param template_file: Template file name
1089*62c56f98SSadaf Ebrahimi    :param c_file: Output source file
1090*62c56f98SSadaf Ebrahimi    :param snippets: Generated and code snippets
1091*62c56f98SSadaf Ebrahimi    :return:
1092*62c56f98SSadaf Ebrahimi    """
1093*62c56f98SSadaf Ebrahimi
1094*62c56f98SSadaf Ebrahimi    # Create a placeholder pattern with the correct named capture groups
1095*62c56f98SSadaf Ebrahimi    # to override the default provided with Template.
1096*62c56f98SSadaf Ebrahimi    # Match nothing (no way of escaping placeholders).
1097*62c56f98SSadaf Ebrahimi    escaped = "(?P<escaped>(?!))"
1098*62c56f98SSadaf Ebrahimi    # Match the "__MBEDTLS_TEST_TEMPLATE__PLACEHOLDER_NAME" pattern.
1099*62c56f98SSadaf Ebrahimi    named = "__MBEDTLS_TEST_TEMPLATE__(?P<named>[A-Z][_A-Z0-9]*)"
1100*62c56f98SSadaf Ebrahimi    # Match nothing (no braced placeholder syntax).
1101*62c56f98SSadaf Ebrahimi    braced = "(?P<braced>(?!))"
1102*62c56f98SSadaf Ebrahimi    # If not already matched, a "__MBEDTLS_TEST_TEMPLATE__" prefix is invalid.
1103*62c56f98SSadaf Ebrahimi    invalid = "(?P<invalid>__MBEDTLS_TEST_TEMPLATE__)"
1104*62c56f98SSadaf Ebrahimi    placeholder_pattern = re.compile("|".join([escaped, named, braced, invalid]))
1105*62c56f98SSadaf Ebrahimi
1106*62c56f98SSadaf Ebrahimi    with open(template_file, 'r') as template_f, open(c_file, 'w') as c_f:
1107*62c56f98SSadaf Ebrahimi        for line_no, line in enumerate(template_f.readlines(), 1):
1108*62c56f98SSadaf Ebrahimi            # Update line number. +1 as #line directive sets next line number
1109*62c56f98SSadaf Ebrahimi            snippets['line_no'] = line_no + 1
1110*62c56f98SSadaf Ebrahimi            template = string.Template(line)
1111*62c56f98SSadaf Ebrahimi            template.pattern = placeholder_pattern
1112*62c56f98SSadaf Ebrahimi            snippets = {k.upper():v for (k, v) in snippets.items()}
1113*62c56f98SSadaf Ebrahimi            code = template.substitute(**snippets)
1114*62c56f98SSadaf Ebrahimi            c_f.write(code)
1115*62c56f98SSadaf Ebrahimi
1116*62c56f98SSadaf Ebrahimi
1117*62c56f98SSadaf Ebrahimidef parse_function_file(funcs_file, snippets):
1118*62c56f98SSadaf Ebrahimi    """
1119*62c56f98SSadaf Ebrahimi    Parse function file and generate function dispatch code.
1120*62c56f98SSadaf Ebrahimi
1121*62c56f98SSadaf Ebrahimi    :param funcs_file: Functions file name
1122*62c56f98SSadaf Ebrahimi    :param snippets: Dictionary to contain code pieces to be
1123*62c56f98SSadaf Ebrahimi                     substituted in the template.
1124*62c56f98SSadaf Ebrahimi    :return:
1125*62c56f98SSadaf Ebrahimi    """
1126*62c56f98SSadaf Ebrahimi    with FileWrapper(funcs_file) as funcs_f:
1127*62c56f98SSadaf Ebrahimi        suite_dependencies, dispatch_code, func_code, func_info = \
1128*62c56f98SSadaf Ebrahimi            parse_functions(funcs_f)
1129*62c56f98SSadaf Ebrahimi        snippets['functions_code'] = func_code
1130*62c56f98SSadaf Ebrahimi        snippets['dispatch_code'] = dispatch_code
1131*62c56f98SSadaf Ebrahimi        return suite_dependencies, func_info
1132*62c56f98SSadaf Ebrahimi
1133*62c56f98SSadaf Ebrahimi
1134*62c56f98SSadaf Ebrahimidef generate_intermediate_data_file(data_file, out_data_file,
1135*62c56f98SSadaf Ebrahimi                                    suite_dependencies, func_info, snippets):
1136*62c56f98SSadaf Ebrahimi    """
1137*62c56f98SSadaf Ebrahimi    Generates intermediate data file from input data file and
1138*62c56f98SSadaf Ebrahimi    information read from functions file.
1139*62c56f98SSadaf Ebrahimi
1140*62c56f98SSadaf Ebrahimi    :param data_file: Data file name
1141*62c56f98SSadaf Ebrahimi    :param out_data_file: Output/Intermediate data file
1142*62c56f98SSadaf Ebrahimi    :param suite_dependencies: List of suite dependencies.
1143*62c56f98SSadaf Ebrahimi    :param func_info: Function info parsed from functions file.
1144*62c56f98SSadaf Ebrahimi    :param snippets: Dictionary to contain code pieces to be
1145*62c56f98SSadaf Ebrahimi                     substituted in the template.
1146*62c56f98SSadaf Ebrahimi    :return:
1147*62c56f98SSadaf Ebrahimi    """
1148*62c56f98SSadaf Ebrahimi    with FileWrapper(data_file) as data_f, \
1149*62c56f98SSadaf Ebrahimi            open(out_data_file, 'w') as out_data_f:
1150*62c56f98SSadaf Ebrahimi        dep_check_code, expression_code = gen_from_test_data(
1151*62c56f98SSadaf Ebrahimi            data_f, out_data_f, func_info, suite_dependencies)
1152*62c56f98SSadaf Ebrahimi        snippets['dep_check_code'] = dep_check_code
1153*62c56f98SSadaf Ebrahimi        snippets['expression_code'] = expression_code
1154*62c56f98SSadaf Ebrahimi
1155*62c56f98SSadaf Ebrahimi
1156*62c56f98SSadaf Ebrahimidef generate_code(**input_info):
1157*62c56f98SSadaf Ebrahimi    """
1158*62c56f98SSadaf Ebrahimi    Generates C source code from test suite file, data file, common
1159*62c56f98SSadaf Ebrahimi    helpers file and platform file.
1160*62c56f98SSadaf Ebrahimi
1161*62c56f98SSadaf Ebrahimi    input_info expands to following parameters:
1162*62c56f98SSadaf Ebrahimi    funcs_file: Functions file object
1163*62c56f98SSadaf Ebrahimi    data_file: Data file object
1164*62c56f98SSadaf Ebrahimi    template_file: Template file object
1165*62c56f98SSadaf Ebrahimi    platform_file: Platform file object
1166*62c56f98SSadaf Ebrahimi    helpers_file: Helper functions file object
1167*62c56f98SSadaf Ebrahimi    suites_dir: Test suites dir
1168*62c56f98SSadaf Ebrahimi    c_file: Output C file object
1169*62c56f98SSadaf Ebrahimi    out_data_file: Output intermediate data file object
1170*62c56f98SSadaf Ebrahimi    :return:
1171*62c56f98SSadaf Ebrahimi    """
1172*62c56f98SSadaf Ebrahimi    funcs_file = input_info['funcs_file']
1173*62c56f98SSadaf Ebrahimi    data_file = input_info['data_file']
1174*62c56f98SSadaf Ebrahimi    template_file = input_info['template_file']
1175*62c56f98SSadaf Ebrahimi    platform_file = input_info['platform_file']
1176*62c56f98SSadaf Ebrahimi    helpers_file = input_info['helpers_file']
1177*62c56f98SSadaf Ebrahimi    suites_dir = input_info['suites_dir']
1178*62c56f98SSadaf Ebrahimi    c_file = input_info['c_file']
1179*62c56f98SSadaf Ebrahimi    out_data_file = input_info['out_data_file']
1180*62c56f98SSadaf Ebrahimi    for name, path in [('Functions file', funcs_file),
1181*62c56f98SSadaf Ebrahimi                       ('Data file', data_file),
1182*62c56f98SSadaf Ebrahimi                       ('Template file', template_file),
1183*62c56f98SSadaf Ebrahimi                       ('Platform file', platform_file),
1184*62c56f98SSadaf Ebrahimi                       ('Helpers code file', helpers_file),
1185*62c56f98SSadaf Ebrahimi                       ('Suites dir', suites_dir)]:
1186*62c56f98SSadaf Ebrahimi        if not os.path.exists(path):
1187*62c56f98SSadaf Ebrahimi            raise IOError("ERROR: %s [%s] not found!" % (name, path))
1188*62c56f98SSadaf Ebrahimi
1189*62c56f98SSadaf Ebrahimi    snippets = {'generator_script': os.path.basename(__file__)}
1190*62c56f98SSadaf Ebrahimi    read_code_from_input_files(platform_file, helpers_file,
1191*62c56f98SSadaf Ebrahimi                               out_data_file, snippets)
1192*62c56f98SSadaf Ebrahimi    add_input_info(funcs_file, data_file, template_file,
1193*62c56f98SSadaf Ebrahimi                   c_file, snippets)
1194*62c56f98SSadaf Ebrahimi    suite_dependencies, func_info = parse_function_file(funcs_file, snippets)
1195*62c56f98SSadaf Ebrahimi    generate_intermediate_data_file(data_file, out_data_file,
1196*62c56f98SSadaf Ebrahimi                                    suite_dependencies, func_info, snippets)
1197*62c56f98SSadaf Ebrahimi    write_test_source_file(template_file, c_file, snippets)
1198*62c56f98SSadaf Ebrahimi
1199*62c56f98SSadaf Ebrahimi
1200*62c56f98SSadaf Ebrahimidef main():
1201*62c56f98SSadaf Ebrahimi    """
1202*62c56f98SSadaf Ebrahimi    Command line parser.
1203*62c56f98SSadaf Ebrahimi
1204*62c56f98SSadaf Ebrahimi    :return:
1205*62c56f98SSadaf Ebrahimi    """
1206*62c56f98SSadaf Ebrahimi    parser = argparse.ArgumentParser(
1207*62c56f98SSadaf Ebrahimi        description='Dynamically generate test suite code.')
1208*62c56f98SSadaf Ebrahimi
1209*62c56f98SSadaf Ebrahimi    parser.add_argument("-f", "--functions-file",
1210*62c56f98SSadaf Ebrahimi                        dest="funcs_file",
1211*62c56f98SSadaf Ebrahimi                        help="Functions file",
1212*62c56f98SSadaf Ebrahimi                        metavar="FUNCTIONS_FILE",
1213*62c56f98SSadaf Ebrahimi                        required=True)
1214*62c56f98SSadaf Ebrahimi
1215*62c56f98SSadaf Ebrahimi    parser.add_argument("-d", "--data-file",
1216*62c56f98SSadaf Ebrahimi                        dest="data_file",
1217*62c56f98SSadaf Ebrahimi                        help="Data file",
1218*62c56f98SSadaf Ebrahimi                        metavar="DATA_FILE",
1219*62c56f98SSadaf Ebrahimi                        required=True)
1220*62c56f98SSadaf Ebrahimi
1221*62c56f98SSadaf Ebrahimi    parser.add_argument("-t", "--template-file",
1222*62c56f98SSadaf Ebrahimi                        dest="template_file",
1223*62c56f98SSadaf Ebrahimi                        help="Template file",
1224*62c56f98SSadaf Ebrahimi                        metavar="TEMPLATE_FILE",
1225*62c56f98SSadaf Ebrahimi                        required=True)
1226*62c56f98SSadaf Ebrahimi
1227*62c56f98SSadaf Ebrahimi    parser.add_argument("-s", "--suites-dir",
1228*62c56f98SSadaf Ebrahimi                        dest="suites_dir",
1229*62c56f98SSadaf Ebrahimi                        help="Suites dir",
1230*62c56f98SSadaf Ebrahimi                        metavar="SUITES_DIR",
1231*62c56f98SSadaf Ebrahimi                        required=True)
1232*62c56f98SSadaf Ebrahimi
1233*62c56f98SSadaf Ebrahimi    parser.add_argument("--helpers-file",
1234*62c56f98SSadaf Ebrahimi                        dest="helpers_file",
1235*62c56f98SSadaf Ebrahimi                        help="Helpers file",
1236*62c56f98SSadaf Ebrahimi                        metavar="HELPERS_FILE",
1237*62c56f98SSadaf Ebrahimi                        required=True)
1238*62c56f98SSadaf Ebrahimi
1239*62c56f98SSadaf Ebrahimi    parser.add_argument("-p", "--platform-file",
1240*62c56f98SSadaf Ebrahimi                        dest="platform_file",
1241*62c56f98SSadaf Ebrahimi                        help="Platform code file",
1242*62c56f98SSadaf Ebrahimi                        metavar="PLATFORM_FILE",
1243*62c56f98SSadaf Ebrahimi                        required=True)
1244*62c56f98SSadaf Ebrahimi
1245*62c56f98SSadaf Ebrahimi    parser.add_argument("-o", "--out-dir",
1246*62c56f98SSadaf Ebrahimi                        dest="out_dir",
1247*62c56f98SSadaf Ebrahimi                        help="Dir where generated code and scripts are copied",
1248*62c56f98SSadaf Ebrahimi                        metavar="OUT_DIR",
1249*62c56f98SSadaf Ebrahimi                        required=True)
1250*62c56f98SSadaf Ebrahimi
1251*62c56f98SSadaf Ebrahimi    args = parser.parse_args()
1252*62c56f98SSadaf Ebrahimi
1253*62c56f98SSadaf Ebrahimi    data_file_name = os.path.basename(args.data_file)
1254*62c56f98SSadaf Ebrahimi    data_name = os.path.splitext(data_file_name)[0]
1255*62c56f98SSadaf Ebrahimi
1256*62c56f98SSadaf Ebrahimi    out_c_file = os.path.join(args.out_dir, data_name + '.c')
1257*62c56f98SSadaf Ebrahimi    out_data_file = os.path.join(args.out_dir, data_name + '.datax')
1258*62c56f98SSadaf Ebrahimi
1259*62c56f98SSadaf Ebrahimi    out_c_file_dir = os.path.dirname(out_c_file)
1260*62c56f98SSadaf Ebrahimi    out_data_file_dir = os.path.dirname(out_data_file)
1261*62c56f98SSadaf Ebrahimi    for directory in [out_c_file_dir, out_data_file_dir]:
1262*62c56f98SSadaf Ebrahimi        if not os.path.exists(directory):
1263*62c56f98SSadaf Ebrahimi            os.makedirs(directory)
1264*62c56f98SSadaf Ebrahimi
1265*62c56f98SSadaf Ebrahimi    generate_code(funcs_file=args.funcs_file, data_file=args.data_file,
1266*62c56f98SSadaf Ebrahimi                  template_file=args.template_file,
1267*62c56f98SSadaf Ebrahimi                  platform_file=args.platform_file,
1268*62c56f98SSadaf Ebrahimi                  helpers_file=args.helpers_file, suites_dir=args.suites_dir,
1269*62c56f98SSadaf Ebrahimi                  c_file=out_c_file, out_data_file=out_data_file)
1270*62c56f98SSadaf Ebrahimi
1271*62c56f98SSadaf Ebrahimi
1272*62c56f98SSadaf Ebrahimiif __name__ == "__main__":
1273*62c56f98SSadaf Ebrahimi    try:
1274*62c56f98SSadaf Ebrahimi        main()
1275*62c56f98SSadaf Ebrahimi    except GeneratorInputError as err:
1276*62c56f98SSadaf Ebrahimi        sys.exit("%s: input error: %s" %
1277*62c56f98SSadaf Ebrahimi                 (os.path.basename(sys.argv[0]), str(err)))
1278