builtin_function.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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 objectValue(builtinNewFunctionNative(call.runtime, call.ArgumentList))
  11. }
  12. func builtinNewFunction(obj *object, argumentList []Value) Value {
  13. return objectValue(builtinNewFunctionNative(obj.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(rt *runtime, argumentList []Value) *object {
  26. var parameterList, body string
  27. if count := len(argumentList); count > 0 {
  28. tmp := make([]string, 0, count-1)
  29. for _, value := range argumentList[0 : count-1] {
  30. tmp = append(tmp, value.string())
  31. }
  32. parameterList = strings.Join(tmp, ",")
  33. body = argumentList[count-1].string()
  34. }
  35. // FIXME
  36. function, err := parser.ParseFunction(parameterList, body)
  37. rt.parseThrow(err) // Will panic/throw appropriately
  38. cmpl := compiler{}
  39. cmplFunction := cmpl.parseExpression(function)
  40. return rt.newNodeFunction(cmplFunction.(*nodeFunctionLiteral), rt.globalStash)
  41. }
  42. func builtinFunctionToString(call FunctionCall) Value {
  43. obj := call.thisClassObject(classFunctionName) // Should throw a TypeError unless Function
  44. switch fn := obj.value.(type) {
  45. case nativeFunctionObject:
  46. return stringValue(fmt.Sprintf("function %s() { [native code] }", fn.name))
  47. case nodeFunctionObject:
  48. return stringValue(fn.node.source)
  49. case bindFunctionObject:
  50. return stringValue("function () { [native code] }")
  51. default:
  52. panic(call.runtime.panicTypeError("Function.toString unknown type %T", obj.value))
  53. }
  54. }
  55. func builtinFunctionApply(call FunctionCall) Value {
  56. if !call.This.isCallable() {
  57. panic(call.runtime.panicTypeError("Function.apply %q is not callable", call.This))
  58. }
  59. this := call.Argument(0)
  60. if this.IsUndefined() {
  61. // FIXME Not ECMA5
  62. this = objectValue(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("Function.apply unknown type %T for second argument"))
  71. }
  72. arrayObject := argumentList.object()
  73. thisObject := call.thisObject()
  74. length := int64(toUint32(arrayObject.get(propertyLength)))
  75. valueArray := make([]Value, length)
  76. for index := range length {
  77. valueArray[index] = arrayObject.get(arrayIndexToString(index))
  78. }
  79. return thisObject.call(this, valueArray, false, nativeFrame)
  80. }
  81. func builtinFunctionCall(call FunctionCall) Value {
  82. if !call.This.isCallable() {
  83. panic(call.runtime.panicTypeError("Function.call %q is not callable", call.This))
  84. }
  85. thisObject := call.thisObject()
  86. this := call.Argument(0)
  87. if this.IsUndefined() {
  88. // FIXME Not ECMA5
  89. this = objectValue(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 builtinFunctionBind(call FunctionCall) Value {
  97. target := call.This
  98. if !target.isCallable() {
  99. panic(call.runtime.panicTypeError("Function.bind %q is not callable", call.This))
  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 = objectValue(call.runtime.globalObject)
  107. }
  108. return objectValue(call.runtime.newBoundFunction(targetObject, this, argumentList))
  109. }