1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4#
5# Copyright 2017, Data61
6# Commonwealth Scientific and Industrial Research Organisation (CSIRO)
7# ABN 41 687 119 230.
8#
9# This software may be distributed and modified according to the terms of
10# the BSD 2-Clause license. Note that NO WARRANTY is provided.
11# See "LICENSE_BSD2.txt" for details.
12#
13# @TAG(DATA61_BSD)
14#
15
16'''
17Stage 5 parser. The following parser is designed to accept a stage 4 parser,
18whose output it consumes. This parser's purpose is to remove Groups from the
19lifted AST, adding their implied information as the address space of component
20instances.
21'''
22
23from __future__ import absolute_import, division, print_function, \
24    unicode_literals
25from camkes.internal.seven import cmp, filter, map, zip
26
27from .base import Transformer
28from camkes.ast import Composition, Group, Instance, Reference, TraversalAction
29
30def precondition(ast_lifted):
31    '''
32    Precondition of this transformation. At this point, no references should be
33    left in the AST.
34    '''
35    return all(not isinstance(x, Reference) for x in ast_lifted)
36
37def postcondition(ast_lifted):
38    '''
39    Postcondition of this transformation. Afterwards, no groups should remain
40    and every instance should have an assigned address space.
41    '''
42    return all(not isinstance(x, Group) and
43        (not isinstance(x, Instance) or x.address_space is not None) for
44        x in ast_lifted)
45
46def collapse_groups(ast_lifted):
47    class Collapser(TraversalAction):
48        def __init__(self):
49            self.counter = 0
50        def __call__(self, item):
51            if isinstance(item, Composition):
52                # Remove the groups which should have all been resolved.
53                [item.instances.extend(g.instances) for g in item.groups]
54                item.groups = []
55                item.claim_children()
56            elif isinstance(item, Group):
57                # Assign an address space to all instances in this group.
58                if item.name is None:
59                    name = 'unamed_group_%d' % self.counter
60                    self.counter += 1
61                else:
62                    name = item.name
63                for i in item.instances:
64                    i.address_space = name
65            return item
66
67    c = Collapser()
68    ast_lifted.postorder(c)
69
70    return ast_lifted
71
72class Parse5(Transformer):
73    def precondition(self, ast_lifted, _):
74        return precondition(ast_lifted)
75
76    def postcondition(self, ast_lifted, _):
77        return postcondition(ast_lifted)
78
79    def transform(self, ast_lifted, read):
80        return collapse_groups(ast_lifted), read
81