stash.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. package otto
  2. import (
  3. "fmt"
  4. )
  5. // ======
  6. // _stash
  7. // ======
  8. type _stash interface {
  9. hasBinding(string) bool //
  10. createBinding(string, bool, Value) // CreateMutableBinding
  11. setBinding(string, Value, bool) // SetMutableBinding
  12. getBinding(string, bool) Value // GetBindingValue
  13. deleteBinding(string) bool //
  14. setValue(string, Value, bool) // createBinding + setBinding
  15. outer() _stash
  16. runtime() *_runtime
  17. newReference(string, bool, _at) _reference
  18. clone(clone *_clone) _stash
  19. }
  20. // ==========
  21. // _objectStash
  22. // ==========
  23. type _objectStash struct {
  24. _runtime *_runtime
  25. _outer _stash
  26. object *_object
  27. }
  28. func (self *_objectStash) runtime() *_runtime {
  29. return self._runtime
  30. }
  31. func (runtime *_runtime) newObjectStash(object *_object, outer _stash) *_objectStash {
  32. if object == nil {
  33. object = runtime.newBaseObject()
  34. object.class = "environment"
  35. }
  36. return &_objectStash{
  37. _runtime: runtime,
  38. _outer: outer,
  39. object: object,
  40. }
  41. }
  42. func (in *_objectStash) clone(clone *_clone) _stash {
  43. out, exists := clone.objectStash(in)
  44. if exists {
  45. return out
  46. }
  47. *out = _objectStash{
  48. clone.runtime,
  49. clone.stash(in._outer),
  50. clone.object(in.object),
  51. }
  52. return out
  53. }
  54. func (self *_objectStash) hasBinding(name string) bool {
  55. return self.object.hasProperty(name)
  56. }
  57. func (self *_objectStash) createBinding(name string, deletable bool, value Value) {
  58. if self.object.hasProperty(name) {
  59. panic(hereBeDragons())
  60. }
  61. mode := _propertyMode(0111)
  62. if !deletable {
  63. mode = _propertyMode(0110)
  64. }
  65. // TODO False?
  66. self.object.defineProperty(name, value, mode, false)
  67. }
  68. func (self *_objectStash) setBinding(name string, value Value, strict bool) {
  69. self.object.put(name, value, strict)
  70. }
  71. func (self *_objectStash) setValue(name string, value Value, throw bool) {
  72. if !self.hasBinding(name) {
  73. self.createBinding(name, true, value) // Configurable by default
  74. } else {
  75. self.setBinding(name, value, throw)
  76. }
  77. }
  78. func (self *_objectStash) getBinding(name string, throw bool) Value {
  79. if self.object.hasProperty(name) {
  80. return self.object.get(name)
  81. }
  82. if throw { // strict?
  83. panic(self._runtime.panicReferenceError("Not Defined", name))
  84. }
  85. return Value{}
  86. }
  87. func (self *_objectStash) deleteBinding(name string) bool {
  88. return self.object.delete(name, false)
  89. }
  90. func (self *_objectStash) outer() _stash {
  91. return self._outer
  92. }
  93. func (self *_objectStash) newReference(name string, strict bool, at _at) _reference {
  94. return newPropertyReference(self._runtime, self.object, name, strict, at)
  95. }
  96. // =========
  97. // _dclStash
  98. // =========
  99. type _dclStash struct {
  100. _runtime *_runtime
  101. _outer _stash
  102. property map[string]_dclProperty
  103. }
  104. type _dclProperty struct {
  105. value Value
  106. mutable bool
  107. deletable bool
  108. readable bool
  109. }
  110. func (runtime *_runtime) newDeclarationStash(outer _stash) *_dclStash {
  111. return &_dclStash{
  112. _runtime: runtime,
  113. _outer: outer,
  114. property: map[string]_dclProperty{},
  115. }
  116. }
  117. func (in *_dclStash) clone(clone *_clone) _stash {
  118. out, exists := clone.dclStash(in)
  119. if exists {
  120. return out
  121. }
  122. property := make(map[string]_dclProperty, len(in.property))
  123. for index, value := range in.property {
  124. property[index] = clone.dclProperty(value)
  125. }
  126. *out = _dclStash{
  127. clone.runtime,
  128. clone.stash(in._outer),
  129. property,
  130. }
  131. return out
  132. }
  133. func (self *_dclStash) hasBinding(name string) bool {
  134. _, exists := self.property[name]
  135. return exists
  136. }
  137. func (self *_dclStash) runtime() *_runtime {
  138. return self._runtime
  139. }
  140. func (self *_dclStash) createBinding(name string, deletable bool, value Value) {
  141. _, exists := self.property[name]
  142. if exists {
  143. panic(fmt.Errorf("createBinding: %s: already exists", name))
  144. }
  145. self.property[name] = _dclProperty{
  146. value: value,
  147. mutable: true,
  148. deletable: deletable,
  149. readable: false,
  150. }
  151. }
  152. func (self *_dclStash) setBinding(name string, value Value, strict bool) {
  153. property, exists := self.property[name]
  154. if !exists {
  155. panic(fmt.Errorf("setBinding: %s: missing", name))
  156. }
  157. if property.mutable {
  158. property.value = value
  159. self.property[name] = property
  160. } else {
  161. self._runtime.typeErrorResult(strict)
  162. }
  163. }
  164. func (self *_dclStash) setValue(name string, value Value, throw bool) {
  165. if !self.hasBinding(name) {
  166. self.createBinding(name, false, value) // NOT deletable by default
  167. } else {
  168. self.setBinding(name, value, throw)
  169. }
  170. }
  171. // FIXME This is called a __lot__
  172. func (self *_dclStash) getBinding(name string, throw bool) Value {
  173. property, exists := self.property[name]
  174. if !exists {
  175. panic(fmt.Errorf("getBinding: %s: missing", name))
  176. }
  177. if !property.mutable && !property.readable {
  178. if throw { // strict?
  179. panic(self._runtime.panicTypeError())
  180. }
  181. return Value{}
  182. }
  183. return property.value
  184. }
  185. func (self *_dclStash) deleteBinding(name string) bool {
  186. property, exists := self.property[name]
  187. if !exists {
  188. return true
  189. }
  190. if !property.deletable {
  191. return false
  192. }
  193. delete(self.property, name)
  194. return true
  195. }
  196. func (self *_dclStash) outer() _stash {
  197. return self._outer
  198. }
  199. func (self *_dclStash) newReference(name string, strict bool, _ _at) _reference {
  200. return &_stashReference{
  201. name: name,
  202. base: self,
  203. }
  204. }
  205. // ========
  206. // _fnStash
  207. // ========
  208. type _fnStash struct {
  209. _dclStash
  210. arguments *_object
  211. indexOfArgumentName map[string]string
  212. }
  213. func (runtime *_runtime) newFunctionStash(outer _stash) *_fnStash {
  214. return &_fnStash{
  215. _dclStash: _dclStash{
  216. _runtime: runtime,
  217. _outer: outer,
  218. property: map[string]_dclProperty{},
  219. },
  220. }
  221. }
  222. func (in *_fnStash) clone(clone *_clone) _stash {
  223. out, exists := clone.fnStash(in)
  224. if exists {
  225. return out
  226. }
  227. dclStash := in._dclStash.clone(clone).(*_dclStash)
  228. index := make(map[string]string, len(in.indexOfArgumentName))
  229. for name, value := range in.indexOfArgumentName {
  230. index[name] = value
  231. }
  232. *out = _fnStash{
  233. _dclStash: *dclStash,
  234. arguments: clone.object(in.arguments),
  235. indexOfArgumentName: index,
  236. }
  237. return out
  238. }
  239. func getStashProperties(stash _stash) (keys []string) {
  240. switch vars := stash.(type) {
  241. case *_dclStash:
  242. for k := range vars.property {
  243. keys = append(keys, k)
  244. }
  245. case *_fnStash:
  246. for k := range vars.property {
  247. keys = append(keys, k)
  248. }
  249. case *_objectStash:
  250. for k := range vars.object.property {
  251. keys = append(keys, k)
  252. }
  253. default:
  254. panic("unknown stash type")
  255. }
  256. return
  257. }