otto_.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. package otto
  2. import (
  3. "fmt"
  4. "regexp"
  5. goruntime "runtime"
  6. "strconv"
  7. )
  8. var isIdentifierRegexp *regexp.Regexp = regexp.MustCompile(`^[a-zA-Z\$][a-zA-Z0-9\$]*$`)
  9. func isIdentifier(value string) bool {
  10. return isIdentifierRegexp.MatchString(value)
  11. }
  12. func (rt *runtime) toValueArray(arguments ...interface{}) []Value {
  13. length := len(arguments)
  14. if length == 1 {
  15. if valueArray, ok := arguments[0].([]Value); ok {
  16. return valueArray
  17. }
  18. return []Value{rt.toValue(arguments[0])}
  19. }
  20. valueArray := make([]Value, length)
  21. for index, value := range arguments {
  22. valueArray[index] = rt.toValue(value)
  23. }
  24. return valueArray
  25. }
  26. func stringToArrayIndex(name string) int64 {
  27. index, err := strconv.ParseInt(name, 10, 64)
  28. if err != nil {
  29. return -1
  30. }
  31. if index < 0 {
  32. return -1
  33. }
  34. if index >= maxUint32 {
  35. // The value 2^32 (or above) is not a valid index because
  36. // you cannot store a uint32 length for an index of uint32
  37. return -1
  38. }
  39. return index
  40. }
  41. func isUint32(value int64) bool {
  42. return value >= 0 && value <= maxUint32
  43. }
  44. func arrayIndexToString(index int64) string {
  45. return strconv.FormatInt(index, 10)
  46. }
  47. func valueOfArrayIndex(array []Value, index int) Value {
  48. value, _ := getValueOfArrayIndex(array, index)
  49. return value
  50. }
  51. func getValueOfArrayIndex(array []Value, index int) (Value, bool) {
  52. if index >= 0 && index < len(array) {
  53. value := array[index]
  54. if !value.isEmpty() {
  55. return value, true
  56. }
  57. }
  58. return Value{}, false
  59. }
  60. // A range index can be anything from 0 up to length. It is NOT safe to use as an index
  61. // to an array, but is useful for slicing and in some ECMA algorithms.
  62. func valueToRangeIndex(indexValue Value, length int64, negativeIsZero bool) int64 {
  63. index := indexValue.number().int64
  64. if negativeIsZero {
  65. if index < 0 {
  66. index = 0
  67. }
  68. // minimum(index, length)
  69. if index >= length {
  70. index = length
  71. }
  72. return index
  73. }
  74. if index < 0 {
  75. index += length
  76. if index < 0 {
  77. index = 0
  78. }
  79. } else if index > length {
  80. index = length
  81. }
  82. return index
  83. }
  84. func rangeStartEnd(array []Value, size int64, negativeIsZero bool) (start, end int64) { //nolint:nonamedreturns
  85. start = valueToRangeIndex(valueOfArrayIndex(array, 0), size, negativeIsZero)
  86. if len(array) == 1 {
  87. // If there is only the start argument, then end = size
  88. end = size
  89. return
  90. }
  91. // Assuming the argument is undefined...
  92. end = size
  93. endValue := valueOfArrayIndex(array, 1)
  94. if !endValue.IsUndefined() {
  95. // Which it is not, so get the value as an array index
  96. end = valueToRangeIndex(endValue, size, negativeIsZero)
  97. }
  98. return
  99. }
  100. func rangeStartLength(source []Value, size int64) (start, length int64) { //nolint:nonamedreturns
  101. start = valueToRangeIndex(valueOfArrayIndex(source, 0), size, false)
  102. // Assume the second argument is missing or undefined
  103. length = size
  104. if len(source) == 1 {
  105. // If there is only the start argument, then length = size
  106. return start, length
  107. }
  108. lengthValue := valueOfArrayIndex(source, 1)
  109. if !lengthValue.IsUndefined() {
  110. // Which it is not, so get the value as an array index
  111. length = lengthValue.number().int64
  112. }
  113. return start, length
  114. }
  115. func hereBeDragons(arguments ...interface{}) string {
  116. pc, _, _, _ := goruntime.Caller(1) //nolint:dogsled
  117. name := goruntime.FuncForPC(pc).Name()
  118. message := "Here be dragons -- " + name
  119. if len(arguments) > 0 {
  120. message += ": "
  121. argument0 := fmt.Sprintf("%s", arguments[0])
  122. if len(arguments) == 1 {
  123. message += argument0
  124. } else {
  125. message += fmt.Sprintf(argument0, arguments[1:]...)
  126. }
  127. } else {
  128. message += "."
  129. }
  130. return message
  131. }