1
1
"""Generate a class that represents a nested function.
2
2
3
- The class defines __call__ for calling the function and allows access to variables
4
- defined in outer scopes.
3
+ The class defines __call__ for calling the function and allows access to
4
+ non-local variables defined in outer scopes.
5
5
"""
6
6
7
7
from typing import List
20
20
21
21
22
22
def setup_callable_class (builder : IRBuilder ) -> None :
23
- """Generates a callable class representing a nested function or a function within a
24
- non-extension class and sets up the 'self' variable for that class.
23
+ """Generate an (incomplete) callable class representing function.
25
24
26
- This takes the most recently visited function and returns a ClassIR to represent that
27
- function. Each callable class contains an environment attribute with points to another
28
- ClassIR representing the environment class where some of its variables can be accessed.
29
- Note that its '__call__' method is not yet implemented, and is implemented in the
30
- add_call_to_callable_class function.
25
+ This can be a nested function or a function within a non-extension
26
+ class. Also set up the 'self' variable for that class.
31
27
32
- Returns a newly constructed ClassIR representing the callable class for the nested
33
- function.
34
- """
28
+ This takes the most recently visited function and returns a
29
+ ClassIR to represent that function. Each callable class contains
30
+ an environment attribute which points to another ClassIR
31
+ representing the environment class where some of its variables can
32
+ be accessed.
35
33
36
- # Check to see that the name has not already been taken. If so, rename the class. We allow
37
- # multiple uses of the same function name because this is valid in if-else blocks. Example:
34
+ Note that some methods, such as '__call__', are not yet
35
+ created here. Use additional functions, such as
36
+ add_call_to_callable_class(), to add them.
37
+
38
+ Return a newly constructed ClassIR representing the callable
39
+ class for the nested function.
40
+ """
41
+ # Check to see that the name has not already been taken. If so,
42
+ # rename the class. We allow multiple uses of the same function
43
+ # name because this is valid in if-else blocks. Example:
44
+ #
38
45
# if True:
39
46
# def foo(): ----> foo_obj()
40
47
# return True
@@ -48,12 +55,14 @@ def setup_callable_class(builder: IRBuilder) -> None:
48
55
count += 1
49
56
builder .callable_class_names .add (name )
50
57
51
- # Define the actual callable class ClassIR, and set its environment to point at the
52
- # previously defined environment class.
58
+ # Define the actual callable class ClassIR, and set its
59
+ # environment to point at the previously defined environment
60
+ # class.
53
61
callable_class_ir = ClassIR (name , builder .module_name , is_generated = True )
54
62
55
- # The functools @wraps decorator attempts to call setattr on nested functions, so
56
- # we create a dict for these nested functions.
63
+ # The functools @wraps decorator attempts to call setattr on
64
+ # nested functions, so we create a dict for these nested
65
+ # functions.
57
66
# https://github.com/python/cpython/blob/3.7/Lib/functools.py#L58
58
67
if builder .fn_info .is_nested :
59
68
callable_class_ir .has_dict = True
@@ -68,8 +77,8 @@ def setup_callable_class(builder: IRBuilder) -> None:
68
77
builder .fn_info .callable_class = ImplicitClass (callable_class_ir )
69
78
builder .classes .append (callable_class_ir )
70
79
71
- # Add a 'self' variable to the callable class' environment, and store that variable in a
72
- # register to be accessed later.
80
+ # Add a 'self' variable to the environment of the callable class,
81
+ # and store that variable in a register to be accessed later.
73
82
self_target = add_self_to_env (builder .environment , callable_class_ir )
74
83
builder .fn_info .callable_class .self_reg = builder .read (self_target , builder .fn_info .fitem .line )
75
84
@@ -79,13 +88,14 @@ def add_call_to_callable_class(builder: IRBuilder,
79
88
sig : FuncSignature ,
80
89
env : Environment ,
81
90
fn_info : FuncInfo ) -> FuncIR :
82
- """Generates a '__call__' method for a callable class representing a nested function.
91
+ """Generate a '__call__' method for a callable class representing a nested function.
83
92
84
- This takes the blocks, signature, and environment associated with a function definition and
85
- uses those to build the '__call__' method of a given callable class, used to represent that
86
- function. Note that a 'self' parameter is added to its list of arguments, as the nested
87
- function becomes a class method .
93
+ This takes the blocks, signature, and environment associated with
94
+ a function definition and uses those to build the '__call__'
95
+ method of a given callable class, used to represent that
96
+ function.
88
97
"""
98
+ # Since we create a method, we also add a 'self' parameter.
89
99
sig = FuncSignature ((RuntimeArg (SELF_NAME , object_rprimitive ),) + sig .args , sig .ret_type )
90
100
call_fn_decl = FuncDecl ('__call__' , fn_info .callable_class .ir .name , builder .module_name , sig )
91
101
call_fn_ir = FuncIR (call_fn_decl , blocks , env ,
@@ -95,7 +105,7 @@ def add_call_to_callable_class(builder: IRBuilder,
95
105
96
106
97
107
def add_get_to_callable_class (builder : IRBuilder , fn_info : FuncInfo ) -> None :
98
- """Generates the '__get__' method for a callable class."""
108
+ """Generate the '__get__' method for a callable class."""
99
109
line = fn_info .fitem .line
100
110
builder .enter (fn_info )
101
111
@@ -133,22 +143,30 @@ def add_get_to_callable_class(builder: IRBuilder, fn_info: FuncInfo) -> None:
133
143
134
144
135
145
def instantiate_callable_class (builder : IRBuilder , fn_info : FuncInfo ) -> Value :
136
- """
137
- Assigns a callable class to a register named after the given function definition. Note
138
- that fn_info refers to the function being assigned, whereas builder.fn_info refers to the
139
- function encapsulating the function being turned into a callable class.
146
+ """Create an instance of a callable class for a function.
147
+
148
+ Calls to the function will actually call this instance.
149
+
150
+ Note that fn_info refers to the function being assigned, whereas
151
+ builder.fn_info refers to the function encapsulating the function
152
+ being turned into a callable class.
140
153
"""
141
154
fitem = fn_info .fitem
142
155
func_reg = builder .add (Call (fn_info .callable_class .ir .ctor , [], fitem .line ))
143
156
144
- # Set the callable class' environment attribute to point at the environment class
145
- # defined in the callable class' immediate outer scope. Note that there are three possible
146
- # environment class registers we may use. If the encapsulating function is:
147
- # - a generator function, then the callable class is instantiated from the generator class'
148
- # __next__' function, and hence the generator class' environment register is used.
149
- # - a nested function, then the callable class is instantiated from the current callable
150
- # class' '__call__' function, and hence the callable class' environment register is used.
151
- # - neither, then we use the environment register of the original function.
157
+ # Set the environment attribute of the callable class to point at
158
+ # the environment class defined in the callable class' immediate
159
+ # outer scope. Note that there are three possible environment
160
+ # class registers we may use. This depends on what the encapsulating
161
+ # (parent) function is:
162
+ #
163
+ # - A nested function: the callable class is instantiated
164
+ # from the current callable class' '__call__' function, and hence
165
+ # the callable class' environment register is used.
166
+ # - A generator function: the callable class is instantiated
167
+ # from the '__next__' method of the generator class, and hence the
168
+ # environment of the generator class is used.
169
+ # - Regular function: we use the environment of the original function.
152
170
curr_env_reg = None
153
171
if builder .fn_info .is_generator :
154
172
curr_env_reg = builder .fn_info .generator_class .curr_env_reg
0 commit comments