forked from google/grumpy
/
code.go
82 lines (73 loc) · 2.58 KB
/
code.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
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package grumpy
import (
"reflect"
)
// CodeType is the object representing the Python 'code' type.
var CodeType = newBasisType("code", reflect.TypeOf(Code{}), toCodeUnsafe, ObjectType)
// CodeFlag is a switch controlling the behavior of a Code object.
type CodeFlag int
const (
// CodeFlagVarArg means a Code object accepts *arg parameters.
CodeFlagVarArg CodeFlag = 4
// CodeFlagKWArg means a Code object accepts **kwarg parameters.
CodeFlagKWArg CodeFlag = 8
)
// Code represents Python 'code' objects.
type Code struct {
Object
name string `attr:"co_name"`
filename string `attr:"co_filename"`
// argc is the number of positional arguments.
argc int `attr:"co_argcount"`
flags CodeFlag `attr:"co_flags"`
paramSpec *ParamSpec
fn func(*Frame, []*Object) (*Object, *BaseException)
}
// NewCode creates a new Code object that executes the given fn.
func NewCode(name, filename string, params []Param, flags CodeFlag, fn func(*Frame, []*Object) (*Object, *BaseException)) *Code {
s := NewParamSpec(name, params, flags&CodeFlagVarArg != 0, flags&CodeFlagKWArg != 0)
return &Code{Object{typ: CodeType}, name, filename, len(params), flags, s, fn}
}
func toCodeUnsafe(o *Object) *Code {
return (*Code)(o.toPointer())
}
// Eval runs the code object c in the context of the given globals.
func (c *Code) Eval(f *Frame, globals *Dict, args Args, kwargs KWArgs) (*Object, *BaseException) {
validated := f.MakeArgs(c.paramSpec.Count)
if raised := c.paramSpec.Validate(f, validated, args, kwargs); raised != nil {
return nil, raised
}
oldExc, oldTraceback := f.ExcInfo()
next := newChildFrame(f)
next.code = c
next.globals = globals
ret, raised := c.fn(next, validated)
next.release()
f.FreeArgs(validated)
if raised == nil {
// Restore exc_info to what it was when we left the previous
// frame.
f.RestoreExc(oldExc, oldTraceback)
if ret == nil {
ret = None
}
} else {
_, tb := f.ExcInfo()
tb = newTraceback(f, tb)
f.RestoreExc(raised, tb)
}
return ret, raised
}