123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- 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 the callable takes.
- Parameters [ParametersPerSignature]Parameter
- // Returns results of the given types and names.
- Returns [ReturnsPerSignature]Returned
- // RequiresAtLeast is the required amount of parameters.
- // The callable may accept more than this amount, but not less.
- RequiresAtLeast int
- // ReturnsAtLeast is the minimal amount of return values for the
- // callable. The callable may return more than this amount, but not less.
- ReturnsAtLeast int
- }
- 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))
- }
- signature.ReturnsAtLeast = len(types)
- }
- 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))
- }
- signature.RequiresAtLeast = len(types)
- }
- 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++
- sign.RequiresAtLeast++
- }
- 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
- }
- }
- signature.RequiresAtLeast = len(arguments)
- 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
- }
- // TypeCheck checks if the arguments match the signature.
- // Returns nil if so, or an error if not.
- func (signature Signature) TypeCheck(arguments ...Value) error {
- if len(arguments) < signature.RequiresAtLeast {
- return fmt.Errorf("Too few arguments, expected %d: for %d", signature.RequiresAtLeast, len(arguments))
- }
-
- for i , arg := range arguments {
- if i >= len(signature.Parameters) {
- break
- }
- param := signature.Parameters[i]
- expectedType := param.Type
-
- if arg == nil {
- return fmt.Errorf("Nil argument %d, expected %s: %v for %v", i, expectedType, arguments, signature)
- }
- if !expectedType.IsMatch(arg.Type()) {
- return fmt.Errorf("Argument %d type mismatch: %s<->%s", i, expectedType, arg.Type())
- }
- }
- return nil
- }
|