global.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. package otto
  2. import (
  3. "strconv"
  4. "time"
  5. )
  6. var (
  7. prototypeValueObject = interface{}(nil)
  8. prototypeValueFunction = nativeFunctionObject{
  9. call: func(_ FunctionCall) Value {
  10. return Value{}
  11. },
  12. }
  13. prototypeValueString = stringASCII("")
  14. // TODO Make this just false?
  15. prototypeValueBoolean = Value{
  16. kind: valueBoolean,
  17. value: false,
  18. }
  19. prototypeValueNumber = Value{
  20. kind: valueNumber,
  21. value: 0,
  22. }
  23. prototypeValueDate = dateObject{
  24. epoch: 0,
  25. isNaN: false,
  26. time: time.Unix(0, 0).UTC(),
  27. value: Value{
  28. kind: valueNumber,
  29. value: 0,
  30. },
  31. }
  32. prototypeValueRegExp = regExpObject{
  33. regularExpression: nil,
  34. global: false,
  35. ignoreCase: false,
  36. multiline: false,
  37. source: "",
  38. flags: "",
  39. }
  40. )
  41. func newContext() *runtime {
  42. rt := &runtime{}
  43. rt.globalStash = rt.newObjectStash(nil, nil)
  44. rt.globalObject = rt.globalStash.object
  45. rt.newContext()
  46. rt.eval = rt.globalObject.property["eval"].value.(Value).value.(*object)
  47. rt.globalObject.prototype = rt.global.ObjectPrototype
  48. return rt
  49. }
  50. func (rt *runtime) newBaseObject() *object {
  51. return newObject(rt, "")
  52. }
  53. func (rt *runtime) newClassObject(class string) *object {
  54. return newObject(rt, class)
  55. }
  56. func (rt *runtime) newPrimitiveObject(class string, value Value) *object {
  57. o := rt.newClassObject(class)
  58. o.value = value
  59. return o
  60. }
  61. func (o *object) primitiveValue() Value {
  62. switch value := o.value.(type) {
  63. case Value:
  64. return value
  65. case stringObjecter:
  66. return stringValue(value.String())
  67. }
  68. return Value{}
  69. }
  70. func (o *object) hasPrimitive() bool { //nolint:unused
  71. switch o.value.(type) {
  72. case Value, stringObjecter:
  73. return true
  74. }
  75. return false
  76. }
  77. func (rt *runtime) newObject() *object {
  78. o := rt.newClassObject(classObjectName)
  79. o.prototype = rt.global.ObjectPrototype
  80. return o
  81. }
  82. func (rt *runtime) newArray(length uint32) *object {
  83. o := rt.newArrayObject(length)
  84. o.prototype = rt.global.ArrayPrototype
  85. return o
  86. }
  87. func (rt *runtime) newArrayOf(valueArray []Value) *object {
  88. o := rt.newArray(uint32(len(valueArray)))
  89. for index, value := range valueArray {
  90. if value.isEmpty() {
  91. continue
  92. }
  93. o.defineProperty(strconv.FormatInt(int64(index), 10), value, 0o111, false)
  94. }
  95. return o
  96. }
  97. func (rt *runtime) newString(value Value) *object {
  98. o := rt.newStringObject(value)
  99. o.prototype = rt.global.StringPrototype
  100. return o
  101. }
  102. func (rt *runtime) newBoolean(value Value) *object {
  103. o := rt.newBooleanObject(value)
  104. o.prototype = rt.global.BooleanPrototype
  105. return o
  106. }
  107. func (rt *runtime) newNumber(value Value) *object {
  108. o := rt.newNumberObject(value)
  109. o.prototype = rt.global.NumberPrototype
  110. return o
  111. }
  112. func (rt *runtime) newRegExp(patternValue Value, flagsValue Value) *object {
  113. pattern := ""
  114. flags := ""
  115. if obj := patternValue.object(); obj != nil && obj.class == classRegExpName {
  116. if flagsValue.IsDefined() {
  117. panic(rt.panicTypeError("Cannot supply flags when constructing one RegExp from another"))
  118. }
  119. regExp := obj.regExpValue()
  120. pattern = regExp.source
  121. flags = regExp.flags
  122. } else {
  123. if patternValue.IsDefined() {
  124. pattern = patternValue.string()
  125. }
  126. if flagsValue.IsDefined() {
  127. flags = flagsValue.string()
  128. }
  129. }
  130. return rt.newRegExpDirect(pattern, flags)
  131. }
  132. func (rt *runtime) newRegExpDirect(pattern string, flags string) *object {
  133. o := rt.newRegExpObject(pattern, flags)
  134. o.prototype = rt.global.RegExpPrototype
  135. return o
  136. }
  137. // TODO Should (probably) be one argument, right? This is redundant.
  138. func (rt *runtime) newDate(epoch float64) *object {
  139. o := rt.newDateObject(epoch)
  140. o.prototype = rt.global.DatePrototype
  141. return o
  142. }
  143. func (rt *runtime) newError(name string, message Value, stackFramesToPop int) *object {
  144. switch name {
  145. case "EvalError":
  146. return rt.newEvalError(message)
  147. case "TypeError":
  148. return rt.newTypeError(message)
  149. case "RangeError":
  150. return rt.newRangeError(message)
  151. case "ReferenceError":
  152. return rt.newReferenceError(message)
  153. case "SyntaxError":
  154. return rt.newSyntaxError(message)
  155. case "URIError":
  156. return rt.newURIError(message)
  157. }
  158. obj := rt.newErrorObject(name, message, stackFramesToPop)
  159. obj.prototype = rt.global.ErrorPrototype
  160. if name != "" {
  161. obj.defineProperty("name", stringValue(name), 0o111, false)
  162. }
  163. return obj
  164. }
  165. func (rt *runtime) newNativeFunction(name, file string, line int, fn nativeFunction) *object {
  166. o := rt.newNativeFunctionObject(name, file, line, fn, 0)
  167. o.prototype = rt.global.FunctionPrototype
  168. prototype := rt.newObject()
  169. o.defineProperty("prototype", objectValue(prototype), 0o100, false)
  170. prototype.defineProperty("constructor", objectValue(o), 0o100, false)
  171. return o
  172. }
  173. func (rt *runtime) newNodeFunction(node *nodeFunctionLiteral, scopeEnvironment stasher) *object {
  174. // TODO Implement 13.2 fully
  175. o := rt.newNodeFunctionObject(node, scopeEnvironment)
  176. o.prototype = rt.global.FunctionPrototype
  177. prototype := rt.newObject()
  178. o.defineProperty("prototype", objectValue(prototype), 0o100, false)
  179. prototype.defineProperty("constructor", objectValue(o), 0o101, false)
  180. return o
  181. }
  182. // FIXME Only in one place...
  183. func (rt *runtime) newBoundFunction(target *object, this Value, argumentList []Value) *object {
  184. o := rt.newBoundFunctionObject(target, this, argumentList)
  185. o.prototype = rt.global.FunctionPrototype
  186. prototype := rt.newObject()
  187. o.defineProperty("prototype", objectValue(prototype), 0o100, false)
  188. prototype.defineProperty("constructor", objectValue(o), 0o100, false)
  189. return o
  190. }