asn2aadlPlus.py 22.2 KB
Newer Older
1
#!/usr/bin/env python3
2
3
4
5
6
7
8
"""
ASN.1 Importer

This is one of the tools that Semantix develops for the European
research project ASSERT. It parses an ASN.1 grammar and generates
references (in AADL) to all the existing types.
"""
9
10
11
12
13
14
import os
import re
import sys
import copy
import shutil
import getopt
15
import hashlib
16
17
import tempfile
import platform
18
19
from subprocess import Popen, PIPE
import distutils.spawn as spawn
20

21
22
from .commonPy import configMT
from .commonPy import asnParser
23
from .commonPy import __version__
24

25
from .commonPy.asnAST import (
26
27
28
    AsnBasicNode, AsnBool, AsnReal, AsnInt,
    AsnEnumerated, AsnString, AsnChoice, AsnSequence,
    AsnSequenceOf, AsnSet, AsnSetOf)
29
30


31
from .commonPy.utility import inform, panic, mysystem
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

# Ada package names per type
g_AdaPackageNameOfType = {}


def cleanNameAsAADLWants(name):
    return re.sub(r'[^a-zA-Z0-9_]', '_', name)


def cleanNameAsAsn1cWants(name):
    return cleanNameAsAADLWants(name)


g_lowerFloat = -1e350
g_upperFloat = 1e350


def verifyNodeRange(node):
    assert isinstance(node, AsnBasicNode)
    if isinstance(node, AsnInt):
52
        if not node._range:
53
54
55
56
57
58
59
60
61
            panic("INTEGER (in %s) must have a range constraint inside ASN.1,\n"
                  "or else we might lose accuracy during runtime!" % node.Location())
        # else:
        #     # asn1c uses C long for ASN.1 INTEGER. Assuming that our platform is 32 bit,
        #     # this allows values from -2147483648 to 2147483647
        #     if node._range[0] < -2147483648L:
        #        panic("INTEGER (in %s) must have a low limit >= -2147483648\n" % node.Location())
        #     if node._range[1] > 2147483647L:
        #        panic("INTEGER (in %s) must have a high limit <= 2147483647\n" % node.Location())
62
63

    if isinstance(node, AsnReal):
64
        if not node._range:
65
            panic(
66
                "REAL (in %s) must have a range constraint inside ASN.1,\n"
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
                "or else we might lose accuracy during runtime!" % node.Location())
        else:
            # asn1c uses C double for ASN.1 REAL.
            # this allows values from -1.7976931348623157E308 to 1.7976931348623157E308
            if node._range[0] == g_lowerFloat:
                panic(
                    "REAL (in %s) must have a low limit >= -1.7976931348623157E308\n"
                    % node.Location())
            if node._range[1] == g_upperFloat:
                panic(
                    "REAL (in %s) must have a high limit <= 1.7976931348623157E308\n"
                    % node.Location())


def calculateForNativeAndASN1SCC(absASN1SCCpath, autosrc, names, inputFiles):
    base = "ShowNativeBuffers"

    acn = " -ACN " if any(x.lower().endswith(".acn") for x in inputFiles) else ""
    inputASN1files = [x for x in inputFiles if not x.lower().endswith('.acn')]

87
88
    # Spawn ASN1SCC.exe compiler - for MacOS define a new sh file calling mono Asn1f2.exe
    if platform.system() == "Windows" or platform.system() == "Darwin":
89
        mysystem("%s -c -uPER -o \"%s\" %s %s" % (absASN1SCCpath, autosrc, acn, '"' + '" "'.join(inputFiles) + '"'))
90
91
92
        for line in os.popen("%s -AdaUses %s" % (absASN1SCCpath, '" "'.join(inputASN1files))):
            g_AdaPackageNameOfType[line.split(':')[0]] = line.split(':')[1].rstrip()
    else:
Maxime Perrotin's avatar
Maxime Perrotin committed
93
        cmd = "mono %s -c -uPER -fp AUTO -typePrefix asn1Scc -o \"%s\" %s %s" % (absASN1SCCpath, autosrc, acn, '"' + '" "'.join(inputFiles) + '"')
94
        res = mysystem(cmd)
95
96
        if res != 0:
            panic("This command failed: %s\n" % cmd)
Maxime Perrotin's avatar
Maxime Perrotin committed
97
        for line in os.popen('mono  %s -fp AUTO -typePrefix asn1Scc -AdaUses "%s"' % (absASN1SCCpath, '" "'.join(inputASN1files))):
98
99
100
101
            g_AdaPackageNameOfType[line.split(':')[0]] = line.split(':')[1].rstrip()

    msgEncoderFile = open(autosrc + os.sep + base + ".stats.c", 'w')

102
    # msgEncoderFile.write('#include "DumpableTypes.h"\n')
103
104
105
106
107
108
109

    for a in inputASN1files:
        msgEncoderFile.write('#include "%s.h"\n' % os.path.splitext(os.path.basename(a))[0])

    uniqueASNfiles = {}
    for asnFile in inputASN1files:
        tmpNames = {}
110
111
        for name in asnParser.g_typesOfFile[asnFile]:
            tmpNames[name] = asnParser.g_names[name]
112
113
114

        uniqueASNfiles[asnFile] = [
            copy.copy(tmpNames),                            # map Typename to type definition class from asnAST
115
116
            copy.copy(asnParser.g_astOfFile[asnFile]),    # list of nameless type definitions
            copy.copy(asnParser.g_leafTypeDict)]   # map from Typename to leafType
117

118
    configMT.outputDir = autosrc + os.sep
119
    # dumpable.CreateDumpableCtypes(uniqueASNfiles)
120

121
    for asnTypename in sorted(list(names.keys())):
122
123
124
125
        node = names[asnTypename]
        if node._isArtificial:
            continue
        cleaned = cleanNameAsAsn1cWants(asnTypename)
Maxime Perrotin's avatar
Maxime Perrotin committed
126
127
        msgEncoderFile.write('static asn1Scc%s sizeof_%s;\n' % (cleaned, cleaned))
        msgEncoderFile.write('char bytesEncoding_%s[asn1Scc%s_REQUIRED_BYTES_FOR_ENCODING];\n' % (cleaned, cleaned))
128
        if acn != "":
Maxime Perrotin's avatar
Maxime Perrotin committed
129
            msgEncoderFile.write('char bytesAcnEncoding_%s[asn1Scc%s_REQUIRED_BYTES_FOR_ACN_ENCODING];\n' % (cleaned, cleaned))
130
    msgEncoderFile.close()
131

132
133
134
    # Code generation - asn1c part
    # Create a dictionary to lookup the asn-types from their corresponding c-type
    namesDict = {}
135
    for asnTypename in sorted(list(names.keys())):
136
137
138
139
140
141
        node = names[asnTypename]
        if node._isArtificial:
            continue
        namesDict[cleanNameAsAsn1cWants(asnTypename)] = asnTypename

    # Get a list of all available compilers
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
142
    platformCompilers = ['gcc']
143
144
    try:
        pipe = Popen("find-supported-compilers", stdout=PIPE).stdout
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
145
        platformCompilers = pipe.read().splitlines()
146
    except OSError as err:
147
        print('Not running in a TASTE Environment: {}\nUsing GCC only for computing sizeofs'.format(str(err)))
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
148
        platformCompilers = ['gcc'.encode()]
149
    # Get the maximum size of each asn1type from all platform compilers
150
    messageSizes = {}
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
151
    for cc in platformCompilers:
152
153
154
        # Compile the generated C-file with each compiler
        pwd = os.getcwd()
        os.chdir(autosrc)
155
        path_to_compiler = spawn.find_executable(cc.decode('utf-8'))
156
        if path_to_compiler is None:
157
            os.chdir(pwd)
158
159
160
            continue
        for cfile in os.listdir("."):
            if cfile.endswith(".c"):
161
                if mysystem('%s -c -std=c99 -I. "%s" 2>"%s.stats.err"' % (path_to_compiler, cfile, base)) != 0:
162
                    panic("Compilation of generated sources failed - is %s installed?\n"
163
                          "(report inside '%s')\n" % (cc, os.path.join(autosrc, base + ".stats.err")))
164
165
166
        os.chdir(pwd)

        # Receive the size information for each value from the compiled object file
167
168
169
170
        if platform.system() == "Darwin":
            nm = "gnm"
        else:
            nm = "nm"
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
171
        for line in os.popen(nm + " --print-size " + autosrc + os.sep + base + ".stats.o").readlines():
172
173
174
175
            try:
                (dummy, size, dummy2, msg) = line.split()
            except ValueError:
                # Ignore lines that are not well-formatted
Maxime Perrotin's avatar
Maxime Perrotin committed
176
                continue
177

178
            # Remove prefix
179
180
181
            asnType = msg.split('_', 1)[1]
            # get asn-type from cleaned type
            asnType = namesDict[asnType]
182
            assert asnType in list(names.keys())
183
184
185
186
            # Find maximum
            messageSizes.setdefault(asnType, 0)
            messageSizes[asnType] = max(int(size, 16), messageSizes[asnType])

187
    return messageSizes
188
189
190
191
192
193
194
195
196


def ASNtoACN(asnFilename):
    replaces = {
        ".asn": ".acn",
        ".asn1": ".acn",
        ".ASN": ".ACN",
        ".ASN1": ".ACN",
    }
197
    for k, v in list(replaces.items()):
198
199
200
201
202
203
        if asnFilename.endswith(k):
            return asnFilename.replace(k, v)
    return asnFilename + ".acn"


def usage():
204
205
    panic("""\
Usage: asn2aadlPlus.py <options> <files> outputDataSpec.aadl
206
207
208
209
210
211
212
213

Where <files> is a list of ASN.1 and ACN files, and options can be:

    -k, --keep	    Don't delete temporary files
    -a, --aadlv2    Generate AADLv2 compliant output
    -v, --version   Show version number
    -d, --debug	    Enable debug output
    -p, --platform  Comma seperated list of platform compilers (default: gcc)
214
    -h, --help	    This help message""")
215
216
217


def main():
218
219
220
221
222
    if "-pdb" in sys.argv:
        sys.argv.remove("-pdb")  # pragma: no cover
        import pdb  # pragma: no cover pylint: disable=wrong-import-position,wrong-import-order
        pdb.set_trace()  # pragma: no cover

223
    if "-v" in sys.argv:
224
225
226
227
        import pkg_resources  # pragma: no cover
        version = pkg_resources.require("dmt")[0].version  # pragma: no cover
        print("asn2aadlPlus v" + str(version))  # pragma: no cover
        sys.exit(1)  # pragma: no cover
228

Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
229
230
231
232
    keepFiles = False

    projectCache = os.getenv("PROJECT_CACHE")
    if projectCache is not None and not os.path.isdir(projectCache):
233
234
235
236
        try:
            os.mkdir(projectCache)
        except:
            panic("The configured cache folder:\n\n\t" + projectCache + "\n\n...is not there!\n")
237
238
239
240
241
242
243
244
245
246
247

    # Backwards compatibility - the '-acn' option is no longer necessary
    # (we auto-detect ACN files via their extension)
    while "-acn" in sys.argv:
        ofs = sys.argv.index("-acn")
        del sys.argv[ofs]
    if "-aadlv2" in sys.argv:
        ofs = sys.argv.index("-aadlv2")
        sys.argv[ofs] = '--aadlv2'

    try:
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
248
249
        optlist, args = getopt.gnu_getopt(sys.argv[1:], "hvkad", ['help', 'version', 'keep', 'aadlv2', 'debug', 'platform='])
    except getopt.GetoptError:
250
251
252
        usage()

    bAADLv2 = False
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
253
    keepFiles = False
254

Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
255
    for opt, unused_arg in optlist:
256
257
258
        if opt in ("-h", "--help"):
            usage()
        elif opt in ("-v", "--version"):
259
            print("ASN2AADL v%s" % __version__)
260
261
            sys.exit(0)
        elif opt in ("-d", "--debug"):
262
            configMT.debugParser = True
263
264
265
266
        elif opt in ("-a", "--aadlv2"):
            # Updated, June 2011: AADLv1 no longer supported.
            bAADLv2 = True
        elif opt in ("-k", "--keep"):
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
267
            keepFiles = True
268

269
270
271
    if len(args) < 2:
        usage()

272
    if 'PATH' not in os.environ or os.environ['PATH'] == '':
273
274
275
276
277
278
279
280
281
282
283
        p = os.defpath
    else:
        p = os.environ['PATH']
    for dirent in p.split(os.pathsep):
        if platform.system() == "Windows":
            f = os.path.join(dirent, 'gcc.exe')
        else:
            f = os.path.join(dirent, 'gcc')
        if os.access(f, os.X_OK):
            break
    else:
284
285
        panic("No '%s' found in your PATH... Aborting..." %
              "gcc.exe" if platform.version() == "Windows" else "gcc")
286
287
288
289
290
291
292

    # Check that the ASN.1/ACN files that are passed-in, do in fact exist.
    for x in args[:-1]:
        if not os.path.isfile(x):
            panic("'%s' is not a file!\n" % x)

    aadlFile = args[-1]
293
    inputFiles = [os.path.abspath(x) for x in args[:-1]]
294

295
296
297
298
299
300
301
302
    def md5(filename):
        hash_md5 = hashlib.md5()
        with open(filename, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                hash_md5.update(chunk)
        return hash_md5.hexdigest()

    def checkIfNoWorkIsNeeded(asnfiles, aadlfile):
303
        oldMD5s = {}
304
305
306
        for line in open(aadlfile):
            if 'InputASN1FileChecksum' in line:
                md5sum, asnfile = line.split(':')[1:3]
307
308
309
310
311
                oldMD5s[asnfile] = md5sum
        # if the output AADL file contained MD5 checksums of the input ASN.1 files
        if oldMD5s:
            def ok(f):
                return os.path.exists(f) and md5(f) == oldMD5s[f]
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
312
            # ...and all the current input ASN.1 files exist in the 'burned' list
313
314
315
316
317
318
319
320
            # that was built inside the previous version of the output AADL file,
            # AND
            # all the current input ASN.1 files exist and their MD5 checksum
            # has remained identical to that burned in the previous version of
            # the output AADL file...
            if all(f in oldMD5s for f in asnfiles) and \
                    all(ok(x) for x in asnfiles):
                # ...then there's no need to redo anything.
321
322
323
324
325
326
327
                inform("No AADL dataview generation is necessary.")
                sys.exit(0)

    if os.path.exists(aadlFile) and all(os.path.exists(x) for x in inputFiles):
        checkIfNoWorkIsNeeded([x for x in inputFiles if not x.lower().endswith(".acn")],
                              aadlFile)

328
329
    # Check if we can skip the work altogether!

330
    # Parse the ASN.1 files (skip the ACN ones)
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
331
332
    asnFiles = [x for x in inputFiles if not x.lower().endswith('.acn')]
    asnParser.ParseAsnFileList(asnFiles)
333
334
335
    autosrc = tempfile.mkdtemp(".asn1c")
    inform("Created temporary directory (%s) for auto-generated files...", autosrc)
    absPathOfAADLfile = os.path.abspath(aadlFile)
336
    asn1SccPath = spawn.find_executable('asn1.exe')
337
    if asn1SccPath is None:
338
        panic("ASN1SCC seems not installed on your system (asn1.exe not found in PATH).\n")
339
340
341
342
343
344
345
    absASN1SCCpath = os.path.abspath(asn1SccPath)

    # A, those good old days... I could calculate the buffer size for BER (SIZ), and then compare
    # it to the size for Native (SIZ2, see above) and the max of the two suffices for any conf of the message.
    # CHOICEs, however, changed the picture...  what to put in?
    # Time to use the maximum of Native (SIZ2) and UPER (SIZE) and ACN (SIZ3)...

346
    messageSizes = calculateForNativeAndASN1SCC(absASN1SCCpath, autosrc, asnParser.g_names, inputFiles)
347
348
    for nodeTypename in list(messageSizes.keys()):
        messageSizes[nodeTypename] = [messageSizes[nodeTypename], (8 * (int((messageSizes[nodeTypename] - 1) / 8)) + 8)]
349
350
351
352
353
354
355

    base = os.path.basename(aadlFile)
    base = re.sub(r'\..*$', '', base)

    # AADL creation
    o = open(absPathOfAADLfile, 'w')
    o.write('--------------------------------------------------------\n')
356
    o.write('--! File generated by asn2aadl v%s: DO NOT EDIT !\n' % __version__)
357
358
359
    o.write('--------------------------------------------------------\n')

    for f in [x for x in inputFiles if not x.lower().endswith(".acn")]:
360
        o.write('--! InputASN1FileChecksum:' + md5(f) + ':' + f + ':\n')
361
362
363
364
365
366
367
    o.write('--------------------------------------------------------\n\n')
    o.write('package DataView\n\npublic\n\n')
    if bAADLv2:
        o.write('  with Data_Model;\n')
        o.write('  with Taste;\n')
        o.write('  with Base_Types;\n')
        o.write('  with Deployment;\n')
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
368
    typesUnusableAsInterfaceParameters = []
369
    if bAADLv2:
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
370
371
        directiveTypes = [
            "Simulink_Tunable_Parameter", "Timer", "Taste_directive"]
372
373
374
375
        for typeName in directiveTypes:
            sourceText = ""
            adaPackageName = "TASTE_Directives"
            moduleName = "TASTE-Directives"
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
376
377
378
379
380
381
382
383
384
385
386
387
            o.write('DATA {typeName}\n'
                    'PROPERTIES\n'
                    '   TASTE::Ada_Package_Name => "{adaPackageName}";\n'
                    '   Type_Source_Name => "{typeNameASN}";\n'
                    '   Deployment::ASN1_Module_Name => "{moduleName}";{sourceText}\n'
                    '   TASTE::Forbid_in_PI => true;\n'
                    'END {typeName};\n'.format(
                        typeName=typeName,
                        typeNameASN=typeName.replace('_', '-'),
                        sourceText=sourceText,
                        adaPackageName=adaPackageName,
                        moduleName=moduleName))
388

389
390
391
392
393
        typesUnusableAsInterfaceParameters = []
        for line in os.popen("badTypes '" + "' '".join(asnFiles) + "'").readlines():
            line = line.strip().replace('-', '_')
            typesUnusableAsInterfaceParameters.append(line)

394
395
396
397
398
399
400
        o.write('''
data Stream_Element_Buffer
    -- Root type for buffer elements
properties
    Data_Model::Data_Representation => Character;
end Stream_Element_Buffer;
''')
401
    for asnTypename in sorted(list(asnParser.g_names.keys())):
402
        node = asnParser.g_names[asnTypename]
403
404
405
406
407
408
        if node._isArtificial:
            continue
        cleanName = cleanNameAsAADLWants(asnTypename)
        o.write('DATA ' + cleanName + '\n')
        o.write('PROPERTIES\n')
        o.write('    -- name of the ASN.1 source file:\n')
409
410
        # o.write('    Source_Text => ("%s");\n' % os.path.basename(asnParser.g_names[asnTypename]._asnFilename))
        o.write('    Source_Text => ("%s");\n' % asnParser.g_names[asnTypename]._asnFilename)
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
411
        prefix = "TASTE::" if bAADLv2 else ""
412
        possibleACN = ASNtoACN(asnParser.g_names[asnTypename]._asnFilename)
413
        if bAADLv2 and os.path.exists(possibleACN):
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
414
            prefix2 = "TASTE::" if bAADLv2 else "assert_properties::"
415
416
417
418
419
420
            base = os.path.splitext(os.path.basename(possibleACN))[0]
            fname = base.replace("-", "_")
            o.write('    %sEncodingDefinitionFile => classifier(DataView::ACN_%s);\n' % (prefix2, fname))
        o.write('    %sAda_Package_Name => "%s";\n' % (prefix, g_AdaPackageNameOfType[asnTypename]))
        if bAADLv2:
            o.write('    Deployment::ASN1_Module_Name => "%s";\n' % g_AdaPackageNameOfType[asnTypename].replace('_', '-'))
421
        if os.getenv('UPD') is None:
422
            o.write('    Source_Language => (ASN1);\n')
423
        o.write('    -- Size of a buffer to cover all forms of message representation:\n')
Maxime Perrotin's avatar
Maxime Perrotin committed
424
425
426
427
        le_size = 0 if asnTypename not in messageSizes else messageSizes[asnTypename][0]
        o.write('    -- Real message size is %d; suggested aligned message buffer is...\n' % le_size)
        le_size_rounded = 0 if asnTypename not in messageSizes else messageSizes[asnTypename][1]
        o.write('    Source_Data_Size => %d B%s;\n' % (le_size_rounded, bAADLv2 and "ytes" or ""))
428
429
        o.write('    -- name of the corresponding data type in the source file:\n')
        o.write('    Type_Source_Name => "%s";\n' % asnTypename)
430
        o.write('    TASTE::Position_In_File => [ line => %s ; column => 1 ; ];\n' % node._lineno)
431
        o.write('    -- what kind of type is this?\n')
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
432
        prefix = "TASTE" if bAADLv2 else "assert_properties"
433
        o.write('    %s::ASN1_Basic_Type =>' % prefix)
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
        if isinstance(node, AsnBool):
            o.write('aBOOLEAN;\n')
        elif isinstance(node, AsnInt):
            o.write('aINTEGER;\n')
        elif isinstance(node, AsnReal):
            o.write('aREAL;\n')
        elif isinstance(node, AsnEnumerated):
            o.write('aENUMERATED;\n')
        elif isinstance(node, AsnString):
            o.write('aSTRING;\n')
        elif isinstance(node, AsnChoice):
            o.write('aCHOICE;\n')
        elif isinstance(node, AsnSequence):
            o.write('aSEQUENCE;\n')
        elif isinstance(node, AsnSequenceOf):
            o.write('aSEQUENCEOF;\n')
        elif isinstance(node, AsnSet):
            o.write('aSET;\n')
        elif isinstance(node, AsnSetOf):
            o.write('aSETOF;\n')
        else:
            panic("Unsupported ASN.1 type: %s" % node._leafType)
456
457
        if asnTypename in typesUnusableAsInterfaceParameters:
            o.write('    TASTE::Forbid_in_PI => true;\n')
458
        o.write('END ' + cleanName + ';\n\n')
459
460
        o.write('DATA IMPLEMENTATION ' + cleanName + '.impl\n')
        o.write('END ' + cleanName + '.impl;\n\n')
461
        if os.getenv('UPD') is None:
462
463
464
465
466
467
468
            o.write('DATA ' + cleanName + '_Buffer_Max\n')
            o.write('END ' + cleanName + '_Buffer_Max;\n\n')

            o.write('DATA IMPLEMENTATION ' + cleanName + '_Buffer_Max.impl\n')
            o.write('    -- Buffer to hold a marshalled data of type ' + cleanName + "\n")
            o.write('PROPERTIES\n')
            o.write('    Data_Model::Data_Representation => array;\n')
Maxime Perrotin's avatar
Maxime Perrotin committed
469
            o.write('    Data_Model::Dimension => (%d); -- Size of the buffer\n' % le_size_rounded)
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
470
            o.write('    Source_Data_Size => %d Bytes; -- Size of the buffer in bytes\n' % le_size_rounded)
471
472
473
474
475
476
477
478
479
480
481
482
483
            if bAADLv2:
                o.write('    Data_Model::Base_Type => (classifier (DataView::Stream_Element_Buffer));\n')
            else:
                o.write('    Data_Model::Base_Type => (data ASSERT_Types::Stream_Element);\n')
            o.write('END ' + cleanName + '_Buffer_Max.impl;\n\n')

            o.write('DATA ' + cleanName + '_Buffer\n')
            o.write('END ' + cleanName + '_Buffer;\n\n')

            o.write('DATA IMPLEMENTATION ' + cleanName + '_Buffer.impl\n')
            o.write('    -- Buffer to hold a marshalled data of type ' + cleanName + "\n")
            o.write('SUBCOMPONENTS\n')
            o.write('    Buffer : data ' + cleanName + '_Buffer_Max.impl;\n')
484
            o.write('    Length : data Base_Types::%s;\n' % (bAADLv2 and "Unsigned_32" or "uint32"))
485
486
487
488
            o.write('PROPERTIES\n')
            o.write('    Data_Model::Data_Representation => Struct;\n')
            o.write('END ' + cleanName + '_Buffer.impl;\n\n')

489
490
491
492
493
494
495
496
    # Generate a SYSTEM in the DataView, otherwise Ocarina cannot parse it
    # standalone. This allows buildsupport to get the list of ASN.1 files
    # and modules, which is otherwise not visible unless those for which
    # at least one type is referenced in a provided interface.
    o.write('SYSTEM Taste_DataView\n')
    o.write('END    Taste_DataView;\n\n')
    o.write('SYSTEM IMPLEMENTATION Taste_DataView.others\n')
    o.write('SUBCOMPONENTS\n')
497
    for asnTypename in sorted(list(asnParser.g_names.keys())):
498
499
500
501
        node = asnParser.g_names[asnTypename]
        if node._isArtificial:
            continue
        cleanName = cleanNameAsAADLWants(asnTypename)
502
        o.write('   %s : DATA %s.impl;\n' % (cleanName, cleanName))
503
504
    o.write('END Taste_DataView.others;\n')

505
    listOfAsn1Files = {}
506
    for asnTypename in sorted(list(asnParser.g_names.keys())):
507
        listOfAsn1Files[asnParser.g_names[asnTypename]._asnFilename] = 1
508
509

    if bAADLv2:
510
        for asnFilename in sorted(list(listOfAsn1Files.keys())):
511
512
513
514
515
516
517
            base = os.path.splitext(os.path.basename(asnFilename))[0]
            possibleACN = ASNtoACN(asnFilename)
            if os.path.exists(possibleACN):
                fname = base.replace("-", "_")
                o.write('DATA ACN_' + fname + '\n')
                o.write('PROPERTIES\n')
                o.write('    Source_Text => ("' + possibleACN + '");\n')
518
                o.write('    Source_Language => (ACN);\n')
519
520
521
522
523
524
                o.write('END ACN_' + fname + ';\n\n')

    o.write('end DataView;\n')
    o.close()

    # Remove generated code
Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
525
    if not keepFiles:
526
527
        shutil.rmtree(autosrc)
    else:
528
529
        print("Generated message buffers in '%s'" % autosrc)
    # os.chdir(pwd)
530

Thanassis Tsiodras's avatar
Thanassis Tsiodras committed
531

532
if __name__ == "__main__":
533
    main()
534
535

# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4