-
Notifications
You must be signed in to change notification settings - Fork 95
/
Copy pathfunction.go
226 lines (214 loc) · 6.47 KB
/
function.go
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
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
// Copyright 2018 The go-python Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Function objects
//
// Function objects and code objects should not be confused with each other:
//
// Function objects are created by the execution of the 'def' statement.
// They reference a code object in their __code__ attribute, which is a
// purely syntactic object, i.e. nothing more than a compiled version of some
// source code lines. There is one code object per source code "fragment",
// but each code object can be referenced by zero or many function objects
// depending only on how many times the 'def' statement in the source was
// executed so far.
package py
// A python Function object
type Function struct {
Code *Code // A code object, the __code__ attribute
Context Context // Host VM context
Globals StringDict // A dictionary (other mappings won't do)
Defaults Tuple // NULL or a tuple
KwDefaults StringDict // NULL or a dict
Closure Tuple // NULL or a tuple of cell objects
Doc Object // The __doc__ attribute, can be anything
Name string // The __name__ attribute, a string object
Dict StringDict // The __dict__ attribute, a dict or NULL
Weakreflist List // List of weak references
Annotations StringDict // Annotations, a dict or NULL
Qualname string // The qualified name
}
var FunctionType = NewType("function", "A python function")
// Type of this object
func (o *Function) Type() *Type {
return FunctionType
}
// Get the Dict
func (f *Function) GetDict() StringDict {
return f.Dict
}
// Define a new function
//
// Return a new function object associated with the code object
// code. globals must be a dictionary with the global variables
// accessible to the function.
//
// The function’s docstring, name and __module__ are retrieved from
// the code object, the argument defaults and closure are set to NULL.
//
// Allows to set the function object’s __qualname__
// attribute. qualname should be a unicode object or ""; if "", the
// __qualname__ attribute is set to the same value as its __name__
// attribute.
func NewFunction(ctx Context, code *Code, globals StringDict, qualname string) *Function {
var doc Object
if len(code.Consts) >= 1 {
doc = code.Consts[0]
if _, ok := doc.(String); !ok {
doc = None
}
} else {
doc = None
}
if qualname == "" {
qualname = code.Name
}
return &Function{
Code: code,
Context: ctx,
Qualname: qualname,
Globals: globals,
Name: code.Name,
Doc: doc,
Dict: make(StringDict),
}
}
// Call a function
func (f *Function) M__call__(args Tuple, kwargs StringDict) (Object, error) {
result, err := VmEvalCode(f.Context, f.Code, f.Globals, NewStringDict(), args, kwargs, f.Defaults, f.KwDefaults, f.Closure)
if err != nil {
return nil, err
}
return result, nil
}
// Read a function from a class which makes a bound method
func (f *Function) M__get__(instance, owner Object) (Object, error) {
if instance != None {
return NewBoundMethod(instance, f), nil
}
return f, nil
}
// Properties
func init() {
FunctionType.Dict["__code__"] = &Property{
Fget: func(self Object) (Object, error) {
return self.(*Function).Code, nil
},
Fset: func(self, value Object) error {
f := self.(*Function)
// Not legal to set f.func_code to anything other than a code object.
code, ok := value.(*Code)
if !ok {
return ExceptionNewf(TypeError, "__code__ must be set to a code object")
}
nfree := len(code.Freevars)
nclosure := len(f.Closure)
if nfree != nclosure {
return ExceptionNewf(ValueError, "%s() requires a code object with %d free vars, not %d", f.Name, nclosure, nfree)
}
f.Code = code
return nil
},
}
FunctionType.Dict["__defaults__"] = &Property{
Fget: func(self Object) (Object, error) {
return self.(*Function).Defaults, nil
},
Fset: func(self, value Object) error {
f := self.(*Function)
defaults, ok := value.(Tuple)
if !ok {
return ExceptionNewf(TypeError, "__defaults__ must be set to a tuple object")
}
f.Defaults = defaults
return nil
},
Fdel: func(self Object) error {
self.(*Function).Defaults = nil
return nil
},
}
FunctionType.Dict["__kwdefaults__"] = &Property{
Fget: func(self Object) (Object, error) {
return self.(*Function).KwDefaults, nil
},
Fset: func(self, value Object) error {
f := self.(*Function)
kwdefaults, ok := value.(StringDict)
if !ok {
return ExceptionNewf(TypeError, "__kwdefaults__ must be set to a dict object")
}
f.KwDefaults = kwdefaults
return nil
},
Fdel: func(self Object) error {
self.(*Function).KwDefaults = nil
return nil
},
}
FunctionType.Dict["__annotations__"] = &Property{
Fget: func(self Object) (Object, error) {
return self.(*Function).Annotations, nil
},
Fset: func(self, value Object) error {
f := self.(*Function)
annotations, ok := value.(StringDict)
if !ok {
return ExceptionNewf(TypeError, "__annotations__ must be set to a dict object")
}
f.Annotations = annotations
return nil
},
Fdel: func(self Object) error {
self.(*Function).Annotations = nil
return nil
},
}
FunctionType.Dict["__dict__"] = &Property{
Fget: func(self Object) (Object, error) {
return self.(*Function).Dict, nil
},
Fset: func(self, value Object) error {
f := self.(*Function)
dict, ok := value.(StringDict)
if !ok {
return ExceptionNewf(TypeError, "__dict__ must be set to a dict object")
}
f.Dict = dict
return nil
},
}
FunctionType.Dict["__name__"] = &Property{
Fget: func(self Object) (Object, error) {
return String(self.(*Function).Name), nil
},
Fset: func(self, value Object) error {
f := self.(*Function)
name, ok := value.(String)
if !ok {
return ExceptionNewf(TypeError, "__name__ must be set to a string object")
}
f.Name = string(name)
return nil
},
}
FunctionType.Dict["__qualname__"] = &Property{
Fget: func(self Object) (Object, error) {
return String(self.(*Function).Qualname), nil
},
Fset: func(self, value Object) error {
f := self.(*Function)
qualname, ok := value.(String)
if !ok {
return ExceptionNewf(TypeError, "__qualname__ must be set to a string object")
}
f.Qualname = string(qualname)
return nil
},
}
}
// Make sure it satisfies the interface
var _ Object = (*Function)(nil)
var _ I__call__ = (*Function)(nil)
var _ IGetDict = (*Function)(nil)
var _ I__get__ = (*Function)(nil)