github.com/pygolin/runtime@v0.0.0-20201208210830-a62e3cd39798/code.go (about) 1 // Copyright 2016 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package runtime 16 17 import ( 18 "reflect" 19 ) 20 21 // CodeType is the object representing the Python 'code' type. 22 var CodeType = newBasisType("code", reflect.TypeOf(Code{}), toCodeUnsafe, ObjectType) 23 24 // CodeFlag is a switch controlling the behavior of a Code object. 25 type CodeFlag int 26 27 const ( 28 // CodeFlagVarArg means a Code object accepts *arg parameters. 29 CodeFlagVarArg CodeFlag = 4 30 // CodeFlagKWArg means a Code object accepts **kwarg parameters. 31 CodeFlagKWArg CodeFlag = 8 32 ) 33 34 // Code represents Python 'code' objects. 35 type Code struct { 36 Object 37 name string `attr:"co_name"` 38 filename string `attr:"co_filename"` 39 // argc is the number of positional arguments. 40 argc int `attr:"co_argcount"` 41 flags CodeFlag `attr:"co_flags"` 42 paramSpec *ParamSpec 43 fn func(*Frame, []*Object) (*Object, *BaseException) 44 } 45 46 // NewCode creates a new Code object that executes the given fn. 47 func NewCode(name, filename string, params []Param, flags CodeFlag, fn func(*Frame, []*Object) (*Object, *BaseException)) *Code { 48 s := NewParamSpec(name, params, flags&CodeFlagVarArg != 0, flags&CodeFlagKWArg != 0) 49 return &Code{Object{typ: CodeType}, name, filename, len(params), flags, s, fn} 50 } 51 52 func toCodeUnsafe(o *Object) *Code { 53 return (*Code)(o.toPointer()) 54 } 55 56 // Eval runs the code object c in the context of the given globals. 57 func (c *Code) Eval(f *Frame, globals *Dict, args Args, kwargs KWArgs) (*Object, *BaseException) { 58 validated := f.MakeArgs(c.paramSpec.Count) 59 if raised := c.paramSpec.Validate(f, validated, args, kwargs); raised != nil { 60 return nil, raised 61 } 62 oldExc, oldTraceback := f.ExcInfo() 63 next := newChildFrame(f) 64 next.code = c 65 next.globals = globals 66 ret, raised := c.fn(next, validated) 67 next.release() 68 f.FreeArgs(validated) 69 if raised == nil { 70 // Restore exc_info to what it was when we left the previous 71 // frame. 72 f.RestoreExc(oldExc, oldTraceback) 73 if ret == nil { 74 ret = None 75 } 76 } else { 77 _, tb := f.ExcInfo() 78 if f.code != nil { 79 // The root frame has no code object so don't include it 80 // in the traceback. 81 tb = newTraceback(f, tb) 82 } 83 f.RestoreExc(raised, tb) 84 } 85 return ret, raised 86 }