builtin_function.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package otto
  2. import (
  3. "fmt"
  4. "strings"
  5. "unicode"
  6. "github.com/robertkrimen/otto/parser"
  7. )
  8. // Function
  9. func builtinFunction(call FunctionCall) Value {
  10. return toValue_object(builtinNewFunctionNative(call.runtime, call.ArgumentList))
  11. }
  12. func builtinNewFunction(self *_object, argumentList []Value) Value {
  13. return toValue_object(builtinNewFunctionNative(self.runtime, argumentList))
  14. }
  15. func argumentList2parameterList(argumentList []Value) []string {
  16. parameterList := make([]string, 0, len(argumentList))
  17. for _, value := range argumentList {
  18. tmp := strings.FieldsFunc(value.string(), func(chr rune) bool {
  19. return chr == ',' || unicode.IsSpace(chr)
  20. })
  21. parameterList = append(parameterList, tmp...)
  22. }
  23. return parameterList
  24. }
  25. func builtinNewFunctionNative(runtime *_runtime, argumentList []Value) *_object {
  26. var parameterList, body string
  27. count := len(argumentList)
  28. if count > 0 {
  29. tmp := make([]string, 0, count-1)
  30. for _, value := range argumentList[0 : count-1] {
  31. tmp = append(tmp, value.string())
  32. }
  33. parameterList = strings.Join(tmp, ",")
  34. body = argumentList[count-1].string()
  35. }
  36. // FIXME
  37. function, err := parser.ParseFunction(parameterList, body)
  38. runtime.parseThrow(err) // Will panic/throw appropriately
  39. cmpl := _compiler{}
  40. cmpl_function := cmpl.parseExpression(function)
  41. return runtime.newNodeFunction(cmpl_function.(*_nodeFunctionLiteral), runtime.globalStash)
  42. }
  43. func builtinFunction_toString(call FunctionCall) Value {
  44. object := call.thisClassObject(classFunction) // Should throw a TypeError unless Function
  45. switch fn := object.value.(type) {
  46. case _nativeFunctionObject:
  47. return toValue_string(fmt.Sprintf("function %s() { [native code] }", fn.name))
  48. case _nodeFunctionObject:
  49. return toValue_string(fn.node.source)
  50. case _bindFunctionObject:
  51. return toValue_string("function () { [native code] }")
  52. }
  53. panic(call.runtime.panicTypeError("Function.toString()"))
  54. }
  55. func builtinFunction_apply(call FunctionCall) Value {
  56. if !call.This.isCallable() {
  57. panic(call.runtime.panicTypeError())
  58. }
  59. this := call.Argument(0)
  60. if this.IsUndefined() {
  61. // FIXME Not ECMA5
  62. this = toValue_object(call.runtime.globalObject)
  63. }
  64. argumentList := call.Argument(1)
  65. switch argumentList.kind {
  66. case valueUndefined, valueNull:
  67. return call.thisObject().call(this, nil, false, nativeFrame)
  68. case valueObject:
  69. default:
  70. panic(call.runtime.panicTypeError())
  71. }
  72. arrayObject := argumentList._object()
  73. thisObject := call.thisObject()
  74. length := int64(toUint32(arrayObject.get(propertyLength)))
  75. valueArray := make([]Value, length)
  76. for index := int64(0); index < length; index++ {
  77. valueArray[index] = arrayObject.get(arrayIndexToString(index))
  78. }
  79. return thisObject.call(this, valueArray, false, nativeFrame)
  80. }
  81. func builtinFunction_call(call FunctionCall) Value {
  82. if !call.This.isCallable() {
  83. panic(call.runtime.panicTypeError())
  84. }
  85. thisObject := call.thisObject()
  86. this := call.Argument(0)
  87. if this.IsUndefined() {
  88. // FIXME Not ECMA5
  89. this = toValue_object(call.runtime.globalObject)
  90. }
  91. if len(call.ArgumentList) >= 1 {
  92. return thisObject.call(this, call.ArgumentList[1:], false, nativeFrame)
  93. }
  94. return thisObject.call(this, nil, false, nativeFrame)
  95. }
  96. func builtinFunction_bind(call FunctionCall) Value {
  97. target := call.This
  98. if !target.isCallable() {
  99. panic(call.runtime.panicTypeError())
  100. }
  101. targetObject := target._object()
  102. this := call.Argument(0)
  103. argumentList := call.slice(1)
  104. if this.IsUndefined() {
  105. // FIXME Do this elsewhere?
  106. this = toValue_object(call.runtime.globalObject)
  107. }
  108. return toValue_object(call.runtime.newBoundFunction(targetObject, this, argumentList))
  109. }