github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/runtime/param.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  	"fmt"
    19  )
    20  
    21  // Param describes a parameter to a Python function.
    22  type Param struct {
    23  	// Name is the argument name.
    24  	Name string
    25  	// Def is the default value to use if the argument is not provided. If
    26  	// no default is specified then Def is nil.
    27  	Def *Object
    28  }
    29  
    30  // ParamSpec describes a Python function's parameters.
    31  type ParamSpec struct {
    32  	Count       int
    33  	name        string
    34  	minArgs     int
    35  	varArgIndex int
    36  	kwArgIndex  int
    37  	params      []Param
    38  }
    39  
    40  // NewParamSpec returns a new ParamSpec that accepts the given positional
    41  // parameters and optional vararg and/or kwarg parameter.
    42  func NewParamSpec(name string, params []Param, varArg bool, kwArg bool) *ParamSpec {
    43  	s := &ParamSpec{name: name, params: params, varArgIndex: -1, kwArgIndex: -1}
    44  	numParams := len(params)
    45  	for ; s.minArgs < numParams; s.minArgs++ {
    46  		if params[s.minArgs].Def != nil {
    47  			break
    48  		}
    49  	}
    50  	for _, p := range params[s.minArgs:numParams] {
    51  		if p.Def == nil {
    52  			format := "%s() non-keyword arg %s after keyword arg"
    53  			logFatal(fmt.Sprintf(format, name, p.Name))
    54  		}
    55  	}
    56  	s.Count = numParams
    57  	if varArg {
    58  		s.varArgIndex = s.Count
    59  		s.Count++
    60  	}
    61  	if kwArg {
    62  		s.kwArgIndex = s.Count
    63  		s.Count++
    64  	}
    65  	return s
    66  }
    67  
    68  // Validate ensures that a the args and kwargs passed are valid arguments for
    69  // the param spec s. The validated parameters are output to the validated slice
    70  // which must have len s.Count.
    71  func (s *ParamSpec) Validate(f *Frame, validated []*Object, args Args, kwargs KWArgs) *BaseException {
    72  	if nv := len(validated); nv != s.Count {
    73  		format := "%s(): validated slice was incorrect size: %d, want %d"
    74  		return f.RaiseType(SystemErrorType, fmt.Sprintf(format, s.name, nv, s.Count))
    75  	}
    76  	numParams := len(s.params)
    77  	argc := len(args)
    78  	if argc > numParams && s.varArgIndex == -1 {
    79  		format := "%s() takes %d arguments (%d given)"
    80  		return f.RaiseType(TypeErrorType, fmt.Sprintf(format, s.name, numParams, argc))
    81  	}
    82  	i := 0
    83  	for ; i < argc && i < numParams; i++ {
    84  		validated[i] = args[i]
    85  	}
    86  	if s.varArgIndex != -1 {
    87  		validated[s.varArgIndex] = NewTuple(args[i:].makeCopy()...).ToObject()
    88  	}
    89  	var kwargDict *Dict
    90  	if s.kwArgIndex != -1 {
    91  		kwargDict = NewDict()
    92  		validated[s.kwArgIndex] = kwargDict.ToObject()
    93  	}
    94  	for _, kw := range kwargs {
    95  		name := kw.Name
    96  		j := 0
    97  		for ; j < numParams; j++ {
    98  			if s.params[j].Name == name {
    99  				if validated[j] != nil {
   100  					format := "%s() got multiple values for keyword argument '%s'"
   101  					return f.RaiseType(TypeErrorType, fmt.Sprintf(format, s.name, name))
   102  				}
   103  				validated[j] = kw.Value
   104  				break
   105  			}
   106  		}
   107  		if j == numParams {
   108  			if kwargDict == nil {
   109  				format := "%s() got an unexpected keyword argument '%s'"
   110  				return f.RaiseType(TypeErrorType, fmt.Sprintf(format, s.name, name))
   111  			}
   112  			if raised := kwargDict.SetItemString(f, name, kw.Value); raised != nil {
   113  				return raised
   114  			}
   115  		}
   116  	}
   117  	for ; i < numParams; i++ {
   118  		p := s.params[i]
   119  		if validated[i] == nil {
   120  			if p.Def == nil {
   121  				format := "%s() takes at least %d arguments (%d given)"
   122  				return f.RaiseType(TypeErrorType, fmt.Sprintf(format, s.name, s.minArgs, argc))
   123  			}
   124  			validated[i] = p.Def
   125  		}
   126  	}
   127  	return nil
   128  }