adapter.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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. Run executes this function.
  25. */
  26. func (ea *ECALFunctionAdapter) Run(instanceID string, vs parser.Scope,
  27. is map[string]interface{}, args []interface{}) (ret interface{}, err error) {
  28. defer func() {
  29. if r := recover(); r != nil {
  30. err = fmt.Errorf("Error: %v", r)
  31. }
  32. }()
  33. funcType := ea.funcval.Type()
  34. // Build arguments
  35. fargs := make([]reflect.Value, 0, len(args))
  36. for i, arg := range args {
  37. if i == funcType.NumIn() {
  38. return nil, fmt.Errorf("Too many parameters - got %v expected %v",
  39. len(args), funcType.NumIn())
  40. }
  41. expectedType := funcType.In(i)
  42. // Try to convert into correct number types
  43. if float64Arg, ok := arg.(float64); ok {
  44. switch expectedType.Kind() {
  45. case reflect.Int:
  46. arg = int(float64Arg)
  47. case reflect.Int8:
  48. arg = int8(float64Arg)
  49. case reflect.Int16:
  50. arg = int16(float64Arg)
  51. case reflect.Int32:
  52. arg = int32(float64Arg)
  53. case reflect.Int64:
  54. arg = int64(float64Arg)
  55. case reflect.Uint:
  56. arg = uint(float64Arg)
  57. case reflect.Uint8:
  58. arg = uint8(float64Arg)
  59. case reflect.Uint16:
  60. arg = uint16(float64Arg)
  61. case reflect.Uint32:
  62. arg = uint32(float64Arg)
  63. case reflect.Uint64:
  64. arg = uint64(float64Arg)
  65. case reflect.Uintptr:
  66. arg = uintptr(float64Arg)
  67. case reflect.Float32:
  68. arg = float32(float64Arg)
  69. }
  70. }
  71. givenType := reflect.TypeOf(arg)
  72. // Check that the right types were given
  73. if givenType != expectedType &&
  74. !(expectedType.Kind() == reflect.Interface &&
  75. givenType.Kind() == reflect.Interface &&
  76. givenType.Implements(expectedType)) &&
  77. expectedType != reflect.TypeOf([]interface{}{}) {
  78. return nil, fmt.Errorf("Parameter %v should be of type %v but is of type %v",
  79. i+1, expectedType, givenType)
  80. }
  81. fargs = append(fargs, reflect.ValueOf(arg))
  82. }
  83. // Call the function
  84. vals := ea.funcval.Call(fargs)
  85. // Convert result value
  86. results := make([]interface{}, 0, len(vals))
  87. for i, v := range vals {
  88. res := v.Interface()
  89. if i == len(vals)-1 {
  90. // If the last item is an error then it is not part of the resutls
  91. // (it will be wrapped into a proper runtime error later)
  92. if funcType.Out(i) == reflect.TypeOf((*error)(nil)).Elem() {
  93. if res != nil {
  94. err = res.(error)
  95. }
  96. break
  97. }
  98. }
  99. // Convert result if it is a primitive type
  100. switch v.Kind() {
  101. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  102. res = float64(v.Int())
  103. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  104. res = float64(v.Uint())
  105. case reflect.Float32, reflect.Float64:
  106. res = v.Float()
  107. }
  108. results = append(results, res)
  109. }
  110. ret = results
  111. // Return a single value if results contains only a single item
  112. if len(results) == 1 {
  113. ret = results[0]
  114. }
  115. return ret, err
  116. }
  117. /*
  118. DocString returns the docstring of the wrapped function.
  119. */
  120. func (ea *ECALFunctionAdapter) DocString() (string, error) {
  121. return ea.docstring, nil
  122. }