github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/runtime/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 grumpy
    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  }