File: block_compiler.py

package info (click to toggle)
python-enaml 0.19.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 13,284 kB
  • sloc: python: 31,443; cpp: 4,499; makefile: 140; javascript: 68; lisp: 53; sh: 20
file content (196 lines) | stat: -rw-r--r-- 6,618 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#------------------------------------------------------------------------------
# Copyright (c) 2013-2025, Nucleic Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file LICENSE, distributed with this software.
#------------------------------------------------------------------------------
from atom.api import Typed

from . import compiler_common as cmn
from .enaml_ast import TemplateInst, ChildDef
from ..compat import PY311, PY313


class BaseBlockCompiler(cmn.CompilerBase):
    """ The base class of the block compilers.

    """
    #: The set of local names for the compiler.
    local_names = Typed(set, ())

    #: A mapping of ast node -> compiler node index for the block.
    index_map = Typed(dict, ())

    def parent_index(self):
        """ Get the node index for the parent node.

        Returns
        -------
        result : int
            The compiler node index for the node represented by the
            current parent ast node.

        """
        return self.index_map[self.ancestor()]


class FirstPassBlockCompiler(BaseBlockCompiler):
    """ The first pass block compiler.

    This is a base class for the first pass compilers for the enamldef
    and template block definitions.

    """
    #: A mapping of auxiliary ast node -> compiler node index.
    aux_index_map = Typed(dict, ())

    def visit_ChildDef(self, node: ChildDef):
        # Claim the index for the compiler node.
        index = len(self.index_map)
        self.index_map[node] = index

        # Setup the line number for the child def.
        cg = self.code_generator
        cg.set_lineno(node.lineno)

        # Generate the child def compiler node.
        cmn.gen_child_def_node(cg, node, self.local_names)

        # Store the compiler node in the node list.
        cmn.store_node(cg, index)

        # Append the compiler node to the parent node.
        cmn.append_node(cg, self.parent_index(), index)

        # Visit the body of the child def.
        for item in node.body:
            self.visit(item)

    def visit_TemplateInst(self, node: TemplateInst):
        # No pragmas are supported yet for template inst nodes.
        cmn.warn_pragmas(node, self.filename)

        # Claim the index for the compiler node.
        index = len(self.index_map)
        self.index_map[node] = index

        # Setup the line number for the template inst.
        cg = self.code_generator
        cg.set_lineno(node.lineno)

        # Generate the template inst compiler node.
        cmn.gen_template_inst_node(cg, node, self.local_names)

        # Store the compiler node in the node list.
        cmn.store_node(cg, index)

        # Append the compiler node to the parent node.
        cmn.append_node(cg, self.parent_index(), index)

        # Visit the body of the template inst.
        for item in node.body:
            self.visit(item)

    def visit_TemplateInstBinding(self, node):
        # Grab the index of the parent node for later use.
        self.aux_index_map[node] = self.parent_index()

    def visit_Binding(self, node):
        # Grab the index of the parent node for later use.
        self.aux_index_map[node] = self.parent_index()

    def visit_ExBinding(self, node):
        # Grab the index of the parent node for later use.
        self.aux_index_map[node] = self.parent_index()

    def visit_AliasExpr(self, node):
        # Grab the index of the parent node for later use.
        self.aux_index_map[node] = self.parent_index()

    def visit_StorageExpr(self, node):
        # Grab the index of the parent node for later use.
        self.aux_index_map[node] = self.parent_index()

    def visit_FuncDef(self, node):
        # Grab the index of the parent node for later use.
        self.aux_index_map[node] = self.parent_index()

    def visit_AsyncFuncDef(self, node):
        # Grab the index of the parent node for later use.
        self.aux_index_map[node] = self.parent_index()


class SecondPassBlockCompiler(BaseBlockCompiler):
    """ The second pass block compiler.

    This is a base class for the second pass compilers for the enamldef
    and template block definitions.

    """
    def visit_ChildDef(self, node):
        # Visit the body of the child def.
        for item in node.body:
            self.visit(item)

    def visit_TemplateInst(self, node):
        if node.body:
            # Create the unpack map.
            cg = self.code_generator
            index = self.index_map[node]
            # Python 3.11 and 3.12 requires a NULL before a function that is not a method
            # Python 3.13 one after
            if not PY313 and PY311:
                cg.push_null()
            cmn.load_helper(cg, 'make_unpack_map')
            if PY313:
                cg.push_null()
            cmn.load_node(cg, index)
            cg.call_function(1)
            cg.store_fast(cmn.UNPACK_MAP)

            # Visit the body of the template inst.
            for item in node.body:
                self.visit(item)

    def visit_TemplateInstBinding(self, node):
        # Generate the code for the template inst binding.
        cg = self.code_generator
        index = self.parent_index()
        cmn.gen_template_inst_binding(cg, node, index)

    def visit_Binding(self, node):
        # Generate the code for the operator binding.
        cg = self.code_generator
        index = self.parent_index()
        cmn.gen_operator_binding(cg, node.expr, index, node.name)

    def visit_ExBinding(self, node):
        # Generate the code for the operator binding.
        cg = self.code_generator
        index = self.parent_index()
        cmn.gen_operator_binding(cg, node.expr, index, node.chain)

    def visit_AliasExpr(self, node):
        # Generate the code for the alias expression.
        cg = self.code_generator
        index = self.parent_index()
        cmn.gen_alias_expr(cg, node, index)

    def visit_StorageExpr(self, node):
        # Generate the code for the storage expression.
        cg = self.code_generator
        index = self.parent_index()
        cmn.gen_storage_expr(cg, node, index, self.local_names)
        if node.expr is not None:
            cmn.gen_operator_binding(cg, node.expr, index, node.name)

    def visit_FuncDef(self, node):
        # Generate the code for the function declaration.
        cg = self.code_generator
        index = self.parent_index()
        cmn.gen_decl_funcdef(cg, node, index)

    def visit_AsyncFuncDef(self, node):
        # Generate the code for the async function declaration.
        self.visit_FuncDef(node)