signature.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. package muesli
  2. import "fmt"
  3. /*
  4. ParametersPerSignature is the amount of parameters that will be
  5. checked when type checking a signature. Limited mosty to allow hashability,
  6. that is, Signature is a map key.
  7. */
  8. const ParametersPerSignature = 32
  9. /*
  10. ReturnsPerSignature is the amount of parameters that will be
  11. checked when type checking a signature. Limited mosty to allow hashability,
  12. that is, Signature is a map key.
  13. */
  14. const ReturnsPerSignature = 8
  15. /* NamedWithType describes something that is named and that has a type. */
  16. type NamedWithType struct {
  17. Name WordValue
  18. Type TypeValue
  19. }
  20. /* Parameter describes the name and type of a parameter of a command. */
  21. type Parameter NamedWithType
  22. /* Returned describes the name and type of a value returned by a command.
  23. * It is in essence the same as a Parameter, the type is redefined to
  24. * avoid confounding the two.
  25. */
  26. type Returned NamedWithType
  27. /* Signature describes the types of the arguments that a callable takes,
  28. as well as the returned values.*/
  29. type Signature struct {
  30. // Parameters the callable takes.
  31. Parameters [ParametersPerSignature]Parameter
  32. // Returns results of the given types and names.
  33. Returns [ReturnsPerSignature]Returned
  34. // RequiresAtLeast is the required amount of parameters.
  35. // The callable may accept more than this amount, but not less.
  36. RequiresAtLeast int
  37. // ReturnsAtLeast is the minimal amount of return values for the
  38. // callable. The callable may return more than this amount, but not less.
  39. ReturnsAtLeast int
  40. }
  41. func (s Signature) String() string {
  42. res := "["
  43. sep := ""
  44. for _, param := range s.Parameters {
  45. typ := param.Type
  46. if typ != ZeroType {
  47. res = res + sep + typ.String()
  48. sep = ", "
  49. }
  50. }
  51. res = res + "] -> ["
  52. sep = ""
  53. for _, param := range s.Returns {
  54. typ := param.Type
  55. if typ != ZeroType {
  56. res = res + sep + typ.String()
  57. sep = ", "
  58. }
  59. }
  60. res = res + "]"
  61. return res
  62. }
  63. func (s Signature) StringWithNames() string {
  64. res := "["
  65. sep := ""
  66. for _, param := range s.Parameters {
  67. typ := param.Type
  68. if typ != ZeroType {
  69. res = res + sep + string(param.Name) + " " + typ.String()
  70. sep = ", "
  71. }
  72. }
  73. res = res + "] -> ["
  74. sep = ""
  75. for _, param := range s.Returns {
  76. typ := param.Type
  77. if typ != ZeroType {
  78. res = res + sep + string(param.Name) + " " + typ.String()
  79. sep = ", "
  80. }
  81. }
  82. res = res + "]"
  83. return res
  84. }
  85. func (signature * Signature) SetReturns(types ... TypeValue) {
  86. for i := 0 ; i < len(types) && i < len(signature.Returns) ; i ++ {
  87. signature.Returns[i].Type = types[i]
  88. signature.Returns[i].Name = WordValue(fmt.Sprintf("res%d", i))
  89. }
  90. signature.ReturnsAtLeast = len(types)
  91. }
  92. func (signature * Signature) SetParameters(types ... TypeValue) {
  93. for i := 0 ; i < len(types) && i < len(signature.Parameters) ; i ++ {
  94. signature.Parameters[i].Type = types[i]
  95. signature.Parameters[i].Name = WordValue(fmt.Sprintf("arg%d", i))
  96. }
  97. signature.RequiresAtLeast = len(types)
  98. }
  99. func NewSignature(types ... TypeValue) Signature {
  100. signature := Signature{}
  101. signature.SetParameters(types...)
  102. return signature
  103. }
  104. func NewSignatureWithNames(param ...Value) (Signature, error) {
  105. sign := Signature{}
  106. for i, j := 1, 0 ; i < len(param) ; i += 2 {
  107. name := param[i-1]
  108. typ := param[i]
  109. var ok bool
  110. var nv WordValue
  111. var tv TypeValue
  112. if nv, ok = name.(WordValue); !ok {
  113. return sign, fmt.Errorf("Not a word value: %v", name)
  114. }
  115. if tv, ok = typ.(TypeValue); !ok {
  116. return sign, fmt.Errorf("Not a type value: %v", typ)
  117. }
  118. sign.Parameters[j].Type = tv
  119. sign.Parameters[j].Name = nv
  120. j++
  121. sign.RequiresAtLeast++
  122. }
  123. return sign, nil
  124. }
  125. // NoSignature is the default signature which means the VM will not do
  126. // any argument type checking when the callable is called.
  127. func NoSignature() Signature {
  128. return Signature{}
  129. }
  130. func CalculateSignature(arguments ...Value) Signature {
  131. signature := Signature{}
  132. for i := 0; i < len(signature.Parameters); i++ {
  133. if i < len(arguments) {
  134. signature.Parameters[i].Type = arguments[i].Type()
  135. } else {
  136. signature.Parameters[i].Type = AnyType
  137. }
  138. }
  139. signature.RequiresAtLeast = len(arguments)
  140. return signature
  141. }
  142. func (tv TypeValue) IsMatch(other TypeValue) bool {
  143. if tv == AnyType || other == AnyType {
  144. return true
  145. }
  146. if tv == ZeroType || other == ZeroType {
  147. return true
  148. }
  149. return tv == other
  150. }
  151. func (signature Signature) IsMatch(other Signature) bool {
  152. for i, param := range signature.Parameters {
  153. t1 := param.Type
  154. t2 := other.Parameters[i].Type
  155. if !t1.IsMatch(t2) {
  156. return false
  157. }
  158. }
  159. return true
  160. }
  161. // TypeCheck checks if the arguments match the signature.
  162. // Returns nil if so, or an error if not.
  163. func (signature Signature) TypeCheck(arguments ...Value) error {
  164. if len(arguments) < signature.RequiresAtLeast {
  165. return fmt.Errorf("Too few arguments, expected %d: for %d", signature.RequiresAtLeast, len(arguments))
  166. }
  167. for i , arg := range arguments {
  168. if i >= len(signature.Parameters) {
  169. break
  170. }
  171. param := signature.Parameters[i]
  172. expectedType := param.Type
  173. if arg == nil {
  174. return fmt.Errorf("Nil argument %d, expected %s: %v for %v", i, expectedType, arguments, signature)
  175. }
  176. if !expectedType.IsMatch(arg.Type()) {
  177. return fmt.Errorf("Argument %d type mismatch: %s<->%s", i, expectedType, arg.Type())
  178. }
  179. }
  180. return nil
  181. }