1#
2# Copyright 2021 Espressif Systems (Shanghai) CO LTD
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17import collections
18import os
19
20from fragments import Fragment
21from generation import GenerationException
22from pyparsing import ParseException, Suppress, White
23
24
25class LinkerScript:
26    """
27    Process a linker script template, which contains markers with grammar:
28
29    [<target>]
30
31    The <target> is where output commands (see output_commands.py) are placed.
32    """
33
34    Marker = collections.namedtuple('Marker', 'target indent rules')
35
36    def __init__(self, template_file):
37        self.members = []
38        self.file = os.path.realpath(template_file.name)
39
40        self._generate_members(template_file)
41
42    def _generate_members(self, template_file):
43        lines = template_file.readlines()
44
45        target = Fragment.IDENTIFIER
46        reference = Suppress('mapping') + Suppress('[') + target.setResultsName('target') + Suppress(']')
47        pattern = White(' \t').setResultsName('indent') + reference
48
49        # Find the markers in the template file line by line. If line does not match marker grammar,
50        # set it as a literal to be copied as is to the output file.
51        for line in lines:
52            try:
53                parsed = pattern.parseString(line)
54
55                indent = parsed.indent
56                target = parsed.target
57
58                marker = LinkerScript.Marker(target, indent, [])
59
60                self.members.append(marker)
61            except ParseException:
62                # Does not match marker syntax
63                self.members.append(line)
64
65    def fill(self, mapping_rules):
66        for member in self.members:
67            target = None
68            try:
69                target = member.target
70                rules = member.rules
71
72                del rules[:]
73
74                rules.extend(mapping_rules[target])
75            except KeyError:
76                message = GenerationException.UNDEFINED_REFERENCE + " to target '" + target + "'."
77                raise GenerationException(message)
78            except AttributeError:
79                pass
80
81    def write(self, output_file):
82        # Add information that this is a generated file.
83        output_file.write('/* Automatically generated file; DO NOT EDIT */\n')
84        output_file.write('/* Espressif IoT Development Framework Linker Script */\n')
85        output_file.write('/* Generated from: %s */\n' % self.file)
86        output_file.write('\n')
87
88        # Do the text replacement
89        for member in self.members:
90            try:
91                indent = member.indent
92                rules = member.rules
93
94                for rule in rules:
95                    generated_line = ''.join([indent, str(rule), '\n'])
96                    output_file.write(generated_line)
97            except AttributeError:
98                output_file.write(member)
99