adapter.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * ECAL
  3. *
  4. * Copyright 2020 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package stdlib
  11. import (
  12. "fmt"
  13. "reflect"
  14. "devt.de/krotik/ecal/parser"
  15. )
  16. /*
  17. ECALFunctionAdapter models a bridge adapter between an ECAL function to a Go function.
  18. */
  19. type ECALFunctionAdapter struct {
  20. funcval reflect.Value
  21. docstring string
  22. }
  23. /*
  24. NewECALFunctionAdapter creates a new ECALFunctionAdapter.
  25. */
  26. func NewECALFunctionAdapter(funcval reflect.Value, docstring string) *ECALFunctionAdapter {
  27. return &ECALFunctionAdapter{funcval, docstring}
  28. }
  29. /*
  30. Run executes this function.
  31. */
  32. func (ea *ECALFunctionAdapter) Run(instanceID string, vs parser.Scope,
  33. is map[string]interface{}, tid uint64, args []interface{}) (ret interface{}, err error) {
  34. defer func() {
  35. if r := recover(); r != nil {
  36. err = fmt.Errorf("Error: %v", r)
  37. }
  38. }()
  39. funcType := ea.funcval.Type()
  40. // Build arguments
  41. fargs := make([]reflect.Value, 0, len(args))
  42. for i, arg := range args {
  43. if i == funcType.NumIn() {
  44. return nil, fmt.Errorf("Too many parameters - got %v expected %v",
  45. len(args), funcType.NumIn())
  46. }
  47. expectedType := funcType.In(i)
  48. // Try to convert into correct number types
  49. if float64Arg, ok := arg.(float64); ok {
  50. arg = ea.convertNumber(arg, float64Arg, expectedType)
  51. }
  52. givenType := reflect.TypeOf(arg)
  53. // Check that the right types were given
  54. if givenType != expectedType &&
  55. !(expectedType.Kind() == reflect.Interface &&
  56. givenType.Kind() == reflect.Interface &&
  57. givenType.Implements(expectedType)) &&
  58. expectedType != reflect.TypeOf([]interface{}{}) {
  59. return nil, fmt.Errorf("Parameter %v should be of type %v but is of type %v",
  60. i+1, expectedType, givenType)
  61. }
  62. fargs = append(fargs, reflect.ValueOf(arg))
  63. }
  64. // Call the function
  65. vals := ea.funcval.Call(fargs)
  66. // Convert result value
  67. results := make([]interface{}, 0, len(vals))
  68. for i, v := range vals {
  69. res := v.Interface()
  70. if i == len(vals)-1 {
  71. // If the last item is an error then it is not part of the resutls
  72. // (it will be wrapped into a proper runtime error later)
  73. if funcType.Out(i) == reflect.TypeOf((*error)(nil)).Elem() {
  74. if res != nil {
  75. err = res.(error)
  76. }
  77. break
  78. }
  79. }
  80. // Convert result if it is a primitive type
  81. results = append(results, ea.convertResultNumber(res, v))
  82. }
  83. ret = results
  84. // Return a single value if results contains only a single item
  85. if len(results) == 1 {
  86. ret = results[0]
  87. }
  88. return ret, err
  89. }
  90. /*
  91. convertNumber converts number arguments into the right type.
  92. */
  93. func (ea *ECALFunctionAdapter) convertNumber(arg interface{}, float64Arg float64, expectedType reflect.Type) interface{} {
  94. switch expectedType.Kind() {
  95. case reflect.Int:
  96. arg = int(float64Arg)
  97. case reflect.Int8:
  98. arg = int8(float64Arg)
  99. case reflect.Int16:
  100. arg = int16(float64Arg)
  101. case reflect.Int32:
  102. arg = int32(float64Arg)
  103. case reflect.Int64:
  104. arg = int64(float64Arg)
  105. case reflect.Uint:
  106. arg = uint(float64Arg)
  107. case reflect.Uint8:
  108. arg = uint8(float64Arg)
  109. case reflect.Uint16:
  110. arg = uint16(float64Arg)
  111. case reflect.Uint32:
  112. arg = uint32(float64Arg)
  113. case reflect.Uint64:
  114. arg = uint64(float64Arg)
  115. case reflect.Uintptr:
  116. arg = uintptr(float64Arg)
  117. case reflect.Float32:
  118. arg = float32(float64Arg)
  119. }
  120. return arg
  121. }
  122. /*
  123. convertResultNumber converts result numbers into the right type.
  124. */
  125. func (ea *ECALFunctionAdapter) convertResultNumber(res interface{}, v reflect.Value) interface{} {
  126. switch v.Kind() {
  127. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  128. res = float64(v.Int())
  129. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  130. res = float64(v.Uint())
  131. case reflect.Float32, reflect.Float64:
  132. res = v.Float()
  133. }
  134. return res
  135. }
  136. /*
  137. DocString returns the docstring of the wrapped function.
  138. */
  139. func (ea *ECALFunctionAdapter) DocString() (string, error) {
  140. return ea.docstring, nil
  141. }