object_class.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. package otto
  2. import (
  3. "encoding/json"
  4. )
  5. type objectClass struct {
  6. getOwnProperty func(*object, string) *property
  7. getProperty func(*object, string) *property
  8. get func(*object, string) Value
  9. canPut func(*object, string) bool
  10. put func(*object, string, Value, bool)
  11. hasProperty func(*object, string) bool
  12. hasOwnProperty func(*object, string) bool
  13. defineOwnProperty func(*object, string, property, bool) bool
  14. delete func(*object, string, bool) bool
  15. enumerate func(*object, bool, func(string) bool)
  16. clone func(*object, *object, *cloner) *object
  17. marshalJSON func(*object) json.Marshaler
  18. }
  19. func objectEnumerate(obj *object, all bool, each func(string) bool) {
  20. for _, name := range obj.propertyOrder {
  21. if all || obj.property[name].enumerable() {
  22. if !each(name) {
  23. return
  24. }
  25. }
  26. }
  27. }
  28. var classObject,
  29. classArray,
  30. classString,
  31. classArguments,
  32. classGoStruct,
  33. classGoMap,
  34. classGoArray,
  35. classGoSlice *objectClass
  36. func init() {
  37. classObject = &objectClass{
  38. objectGetOwnProperty,
  39. objectGetProperty,
  40. objectGet,
  41. objectCanPut,
  42. objectPut,
  43. objectHasProperty,
  44. objectHasOwnProperty,
  45. objectDefineOwnProperty,
  46. objectDelete,
  47. objectEnumerate,
  48. objectClone,
  49. nil,
  50. }
  51. classArray = &objectClass{
  52. objectGetOwnProperty,
  53. objectGetProperty,
  54. objectGet,
  55. objectCanPut,
  56. objectPut,
  57. objectHasProperty,
  58. objectHasOwnProperty,
  59. arrayDefineOwnProperty,
  60. objectDelete,
  61. objectEnumerate,
  62. objectClone,
  63. nil,
  64. }
  65. classString = &objectClass{
  66. stringGetOwnProperty,
  67. objectGetProperty,
  68. objectGet,
  69. objectCanPut,
  70. objectPut,
  71. objectHasProperty,
  72. objectHasOwnProperty,
  73. objectDefineOwnProperty,
  74. objectDelete,
  75. stringEnumerate,
  76. objectClone,
  77. nil,
  78. }
  79. classArguments = &objectClass{
  80. argumentsGetOwnProperty,
  81. objectGetProperty,
  82. argumentsGet,
  83. objectCanPut,
  84. objectPut,
  85. objectHasProperty,
  86. objectHasOwnProperty,
  87. argumentsDefineOwnProperty,
  88. argumentsDelete,
  89. objectEnumerate,
  90. objectClone,
  91. nil,
  92. }
  93. classGoStruct = &objectClass{
  94. goStructGetOwnProperty,
  95. objectGetProperty,
  96. objectGet,
  97. goStructCanPut,
  98. goStructPut,
  99. objectHasProperty,
  100. objectHasOwnProperty,
  101. objectDefineOwnProperty,
  102. objectDelete,
  103. goStructEnumerate,
  104. objectClone,
  105. goStructMarshalJSON,
  106. }
  107. classGoMap = &objectClass{
  108. goMapGetOwnProperty,
  109. objectGetProperty,
  110. objectGet,
  111. objectCanPut,
  112. objectPut,
  113. objectHasProperty,
  114. objectHasOwnProperty,
  115. goMapDefineOwnProperty,
  116. goMapDelete,
  117. goMapEnumerate,
  118. objectClone,
  119. nil,
  120. }
  121. classGoArray = &objectClass{
  122. goArrayGetOwnProperty,
  123. objectGetProperty,
  124. objectGet,
  125. objectCanPut,
  126. objectPut,
  127. objectHasProperty,
  128. objectHasOwnProperty,
  129. goArrayDefineOwnProperty,
  130. goArrayDelete,
  131. goArrayEnumerate,
  132. objectClone,
  133. nil,
  134. }
  135. classGoSlice = &objectClass{
  136. goSliceGetOwnProperty,
  137. objectGetProperty,
  138. objectGet,
  139. objectCanPut,
  140. objectPut,
  141. objectHasProperty,
  142. objectHasOwnProperty,
  143. goSliceDefineOwnProperty,
  144. goSliceDelete,
  145. goSliceEnumerate,
  146. objectClone,
  147. nil,
  148. }
  149. }
  150. // Allons-y
  151. // 8.12.1.
  152. func objectGetOwnProperty(obj *object, name string) *property {
  153. // Return a _copy_ of the prop
  154. prop, exists := obj.readProperty(name)
  155. if !exists {
  156. return nil
  157. }
  158. return &prop
  159. }
  160. // 8.12.2.
  161. func objectGetProperty(obj *object, name string) *property {
  162. prop := obj.getOwnProperty(name)
  163. if prop != nil {
  164. return prop
  165. }
  166. if obj.prototype != nil {
  167. return obj.prototype.getProperty(name)
  168. }
  169. return nil
  170. }
  171. // 8.12.3.
  172. func objectGet(obj *object, name string) Value {
  173. if prop := obj.getProperty(name); prop != nil {
  174. return prop.get(obj)
  175. }
  176. return Value{}
  177. }
  178. // 8.12.4.
  179. func objectCanPut(obj *object, name string) bool {
  180. canPut, _, _ := objectCanPutDetails(obj, name)
  181. return canPut
  182. }
  183. func objectCanPutDetails(obj *object, name string) (canPut bool, prop *property, setter *object) { //nolint:nonamedreturns
  184. prop = obj.getOwnProperty(name)
  185. if prop != nil {
  186. switch propertyValue := prop.value.(type) {
  187. case Value:
  188. return prop.writable(), prop, nil
  189. case propertyGetSet:
  190. setter = propertyValue[1]
  191. return setter != nil, prop, setter
  192. default:
  193. panic(obj.runtime.panicTypeError("unexpected type %T to Object.CanPutDetails", prop.value))
  194. }
  195. }
  196. if obj.prototype == nil {
  197. return obj.extensible, nil, nil
  198. }
  199. prop = obj.prototype.getProperty(name)
  200. if prop == nil {
  201. return obj.extensible, nil, nil
  202. }
  203. switch propertyValue := prop.value.(type) {
  204. case Value:
  205. if !obj.extensible {
  206. return false, nil, nil
  207. }
  208. return prop.writable(), nil, nil
  209. case propertyGetSet:
  210. setter = propertyValue[1]
  211. return setter != nil, prop, setter
  212. default:
  213. panic(obj.runtime.panicTypeError("unexpected type %T to Object.CanPutDetails", prop.value))
  214. }
  215. }
  216. // 8.12.5.
  217. func objectPut(obj *object, name string, value Value, throw bool) {
  218. if true {
  219. // Shortcut...
  220. //
  221. // So, right now, every class is using objectCanPut and every class
  222. // is using objectPut.
  223. //
  224. // If that were to no longer be the case, we would have to have
  225. // something to detect that here, so that we do not use an
  226. // incompatible canPut routine
  227. canPut, prop, setter := objectCanPutDetails(obj, name)
  228. switch {
  229. case !canPut:
  230. obj.runtime.typeErrorResult(throw)
  231. case setter != nil:
  232. setter.call(toValue(obj), []Value{value}, false, nativeFrame)
  233. case prop != nil:
  234. prop.value = value
  235. obj.defineOwnProperty(name, *prop, throw)
  236. default:
  237. obj.defineProperty(name, value, 0o111, throw)
  238. }
  239. return
  240. }
  241. // The long way...
  242. //
  243. // Right now, code should never get here, see above
  244. if !obj.canPut(name) {
  245. obj.runtime.typeErrorResult(throw)
  246. return
  247. }
  248. prop := obj.getOwnProperty(name)
  249. if prop == nil {
  250. prop = obj.getProperty(name)
  251. if prop != nil {
  252. if getSet, isAccessor := prop.value.(propertyGetSet); isAccessor {
  253. getSet[1].call(toValue(obj), []Value{value}, false, nativeFrame)
  254. return
  255. }
  256. }
  257. obj.defineProperty(name, value, 0o111, throw)
  258. return
  259. }
  260. switch propertyValue := prop.value.(type) {
  261. case Value:
  262. prop.value = value
  263. obj.defineOwnProperty(name, *prop, throw)
  264. case propertyGetSet:
  265. if propertyValue[1] != nil {
  266. propertyValue[1].call(toValue(obj), []Value{value}, false, nativeFrame)
  267. return
  268. }
  269. if throw {
  270. panic(obj.runtime.panicTypeError("Object.Put nil second parameter to propertyGetSet"))
  271. }
  272. default:
  273. panic(obj.runtime.panicTypeError("Object.Put unexpected type %T", prop.value))
  274. }
  275. }
  276. // 8.12.6.
  277. func objectHasProperty(obj *object, name string) bool {
  278. return obj.getProperty(name) != nil
  279. }
  280. func objectHasOwnProperty(obj *object, name string) bool {
  281. return obj.getOwnProperty(name) != nil
  282. }
  283. // 8.12.9.
  284. func objectDefineOwnProperty(obj *object, name string, descriptor property, throw bool) bool {
  285. reject := func(reason string) bool {
  286. if throw {
  287. panic(obj.runtime.panicTypeError("Object.DefineOwnProperty: %s", reason))
  288. }
  289. return false
  290. }
  291. prop, exists := obj.readProperty(name)
  292. if !exists {
  293. if !obj.extensible {
  294. return reject("not exists and not extensible")
  295. }
  296. if newGetSet, isAccessor := descriptor.value.(propertyGetSet); isAccessor {
  297. if newGetSet[0] == &nilGetSetObject {
  298. newGetSet[0] = nil
  299. }
  300. if newGetSet[1] == &nilGetSetObject {
  301. newGetSet[1] = nil
  302. }
  303. descriptor.value = newGetSet
  304. }
  305. obj.writeProperty(name, descriptor.value, descriptor.mode)
  306. return true
  307. }
  308. if descriptor.isEmpty() {
  309. return true
  310. }
  311. // TODO Per 8.12.9.6 - We should shortcut here (returning true) if
  312. // the current and new (define) properties are the same
  313. configurable := prop.configurable()
  314. if !configurable {
  315. if descriptor.configurable() {
  316. return reject("property and descriptor not configurable")
  317. }
  318. // Test that, if enumerable is set on the property descriptor, then it should
  319. // be the same as the existing property
  320. if descriptor.enumerateSet() && descriptor.enumerable() != prop.enumerable() {
  321. return reject("property not configurable and enumerable miss match")
  322. }
  323. }
  324. value, isDataDescriptor := prop.value.(Value)
  325. getSet, _ := prop.value.(propertyGetSet)
  326. switch {
  327. case descriptor.isGenericDescriptor():
  328. // GenericDescriptor
  329. case isDataDescriptor != descriptor.isDataDescriptor():
  330. // DataDescriptor <=> AccessorDescriptor
  331. if !configurable {
  332. return reject("property descriptor not configurable")
  333. }
  334. case isDataDescriptor && descriptor.isDataDescriptor():
  335. // DataDescriptor <=> DataDescriptor
  336. if !configurable {
  337. if !prop.writable() && descriptor.writable() {
  338. return reject("property not configurable or writeable and descriptor not writeable")
  339. }
  340. if !prop.writable() {
  341. if descriptor.value != nil && !sameValue(value, descriptor.value.(Value)) {
  342. return reject("property not configurable or writeable and descriptor not the same")
  343. }
  344. }
  345. }
  346. default:
  347. // AccessorDescriptor <=> AccessorDescriptor
  348. newGetSet, _ := descriptor.value.(propertyGetSet)
  349. presentGet, presentSet := true, true
  350. if newGetSet[0] == &nilGetSetObject {
  351. // Present, but nil
  352. newGetSet[0] = nil
  353. } else if newGetSet[0] == nil {
  354. // Missing, not even nil
  355. newGetSet[0] = getSet[0]
  356. presentGet = false
  357. }
  358. if newGetSet[1] == &nilGetSetObject {
  359. // Present, but nil
  360. newGetSet[1] = nil
  361. } else if newGetSet[1] == nil {
  362. // Missing, not even nil
  363. newGetSet[1] = getSet[1]
  364. presentSet = false
  365. }
  366. if !configurable {
  367. if (presentGet && (getSet[0] != newGetSet[0])) || (presentSet && (getSet[1] != newGetSet[1])) {
  368. return reject("access descriptor not configurable")
  369. }
  370. }
  371. descriptor.value = newGetSet
  372. }
  373. // This section will preserve attributes of
  374. // the original property, if necessary
  375. value1 := descriptor.value
  376. if value1 == nil {
  377. value1 = prop.value
  378. } else if newGetSet, isAccessor := descriptor.value.(propertyGetSet); isAccessor {
  379. if newGetSet[0] == &nilGetSetObject {
  380. newGetSet[0] = nil
  381. }
  382. if newGetSet[1] == &nilGetSetObject {
  383. newGetSet[1] = nil
  384. }
  385. value1 = newGetSet
  386. }
  387. mode1 := descriptor.mode
  388. if mode1&0o222 != 0 {
  389. // TODO Factor this out into somewhere testable
  390. // (Maybe put into switch ...)
  391. mode0 := prop.mode
  392. if mode1&0o200 != 0 {
  393. if descriptor.isDataDescriptor() {
  394. mode1 &= ^0o200 // Turn off "writable" missing
  395. mode1 |= (mode0 & 0o100)
  396. }
  397. }
  398. if mode1&0o20 != 0 {
  399. mode1 |= (mode0 & 0o10)
  400. }
  401. if mode1&0o2 != 0 {
  402. mode1 |= (mode0 & 0o1)
  403. }
  404. mode1 &= 0o311 // 0311 to preserve the non-setting on "writable"
  405. }
  406. obj.writeProperty(name, value1, mode1)
  407. return true
  408. }
  409. func objectDelete(obj *object, name string, throw bool) bool {
  410. prop := obj.getOwnProperty(name)
  411. if prop == nil {
  412. return true
  413. }
  414. if prop.configurable() {
  415. obj.deleteProperty(name)
  416. return true
  417. }
  418. return obj.runtime.typeErrorResult(throw)
  419. }
  420. func objectClone(in *object, out *object, clone *cloner) *object {
  421. *out = *in
  422. out.runtime = clone.runtime
  423. if out.prototype != nil {
  424. out.prototype = clone.object(in.prototype)
  425. }
  426. out.property = make(map[string]property, len(in.property))
  427. out.propertyOrder = make([]string, len(in.propertyOrder))
  428. copy(out.propertyOrder, in.propertyOrder)
  429. for index, prop := range in.property {
  430. out.property[index] = clone.property(prop)
  431. }
  432. switch value := in.value.(type) {
  433. case nativeFunctionObject:
  434. out.value = value
  435. case bindFunctionObject:
  436. out.value = bindFunctionObject{
  437. target: clone.object(value.target),
  438. this: clone.value(value.this),
  439. argumentList: clone.valueArray(value.argumentList),
  440. }
  441. case nodeFunctionObject:
  442. out.value = nodeFunctionObject{
  443. node: value.node,
  444. stash: clone.stash(value.stash),
  445. }
  446. case argumentsObject:
  447. out.value = value.clone(clone)
  448. }
  449. return out
  450. }