package muesli import "fmt" /* ParametersPerSignature is the amount of parameters that will be checked when type checking a signature. Limited mosty to allow hashability, that is, Signature is a map key. */ const ParametersPerSignature = 32 /* ReturnsPerSignature is the amount of parameters that will be checked when type checking a signature. Limited mosty to allow hashability, that is, Signature is a map key. */ const ReturnsPerSignature = 8 /* NamedWithType describes something that is named and that has a type. */ type NamedWithType struct { Name WordValue Type TypeValue } /* Parameter describes the name and type of a parameter of a command. */ type Parameter NamedWithType /* Returned describes the name and type of a value returned by a command. * It is in essence the same as a Parameter, the type is redefined to * avoid confounding the two. */ type Returned NamedWithType /* Signature describes the types of the arguments that a callable takes, as well as the returned values.*/ type Signature struct { Parameters [ParametersPerSignature]Parameter Returns [ReturnsPerSignature]Returned } func (s Signature) String() string { res := "[" sep := "" for _, param := range s.Parameters { typ := param.Type if typ != ZeroType { res = res + sep + typ.String() sep = ", " } } res = res + "] -> [" sep = "" for _, param := range s.Returns { typ := param.Type if typ != ZeroType { res = res + sep + typ.String() sep = ", " } } res = res + "]" return res } func (s Signature) StringWithNames() string { res := "[" sep := "" for _, param := range s.Parameters { typ := param.Type if typ != ZeroType { res = res + sep + string(param.Name) + " " + typ.String() sep = ", " } } res = res + "] -> [" sep = "" for _, param := range s.Returns { typ := param.Type if typ != ZeroType { res = res + sep + string(param.Name) + " " + typ.String() sep = ", " } } res = res + "]" return res } func (signature * Signature) SetReturns(types ... TypeValue) { for i := 0 ; i < len(types) && i < len(signature.Returns) ; i ++ { signature.Returns[i].Type = types[i] signature.Returns[i].Name = WordValue(fmt.Sprintf("res%d", i)) } } func (signature * Signature) SetParameters(types ... TypeValue) { for i := 0 ; i < len(types) && i < len(signature.Parameters) ; i ++ { signature.Parameters[i].Type = types[i] signature.Parameters[i].Name = WordValue(fmt.Sprintf("arg%d", i)) } } func NewSignature(types ... TypeValue) Signature { signature := Signature{} signature.SetParameters(types...) return signature } func NewSignatureWithNames(param ...Value) (Signature, error) { sign := Signature{} for i, j := 1, 0 ; i < len(param) ; i += 2 { name := param[i-1] typ := param[i] var ok bool var nv WordValue var tv TypeValue if nv, ok = name.(WordValue); !ok { return sign, fmt.Errorf("Not a word value: %v", name) } if tv, ok = typ.(TypeValue); !ok { return sign, fmt.Errorf("Not a type value: %v", typ) } sign.Parameters[j].Type = tv sign.Parameters[j].Name = nv j++ } return sign, nil } // NoSignature is the default signature which means the VM will not do // any argument type checking when the callable is called. func NoSignature() Signature { return Signature{} } func CalculateSignature(arguments ...Value) Signature { signature := Signature{} for i := 0; i < len(signature.Parameters); i++ { if i < len(arguments) { signature.Parameters[i].Type = arguments[i].Type() } else { signature.Parameters[i].Type = AnyType } } return signature } func (tv TypeValue) IsMatch(other TypeValue) bool { if tv == AnyType || other == AnyType { return true } if tv == ZeroType || other == ZeroType { return true } return tv == other } func (signature Signature) IsMatch(other Signature) bool { for i, param := range signature.Parameters { t1 := param.Type t2 := other.Parameters[i].Type if !t1.IsMatch(t2) { return false } } return true }