1 ## our_shell: ysh
2 ## oils_failures_allowed: 2
3
4 #### New Obj API
5 shopt --set ysh:upgrade
6
7 try {
8 # TODO:
9 # - change arg order
10 # - second arg optional
11 var obj = Obj.new({x: 4}, null)
12 #var obj = Obj.new(null, {x:4})
13 pp test_ (obj)
14 }
15 echo $[_error.code]
16
17 try {
18 pp test_ (first(obj))
19 }
20 echo $[_error.code]
21
22 try {
23 pp test_ (rest(obj))
24 }
25 echo $[_error.code]
26
27 ## STDOUT:
28 (Obj) ("x":4)
29 0
30 (Dict) {"x":4}
31 0
32 (Null) null
33 0
34 ## END
35
36
37
38 #### Object() creates prototype chain
39
40 func Rect_area(this) {
41 return (this.x * this.y)
42 }
43
44 var Rect = Object(null, {area: Rect_area})
45
46 var rect1 = Object(Rect, {x: 3, y: 4})
47 var rect2 = Object(Rect, {x: 10, y: 20})
48
49 # This could change to show the object?
50 # pp test_ (rect)
51
52 # TODO: This should be a bound function
53 #pp asdl_ (rect)
54 #pp (rect.area)
55 #pp (rect->area)
56
57 var area1 = rect1.area()
58 var area2 = rect2.area()
59
60 pp test_ ([rect1.x, rect1.y])
61 echo "area1 = $area1"
62
63 pp test_ ([rect2.x, rect2.y])
64 echo "area2 = $area2"
65
66 #pp test_ (rect1.nonexistent)
67
68 ## STDOUT:
69 (List) [3,4]
70 area1 = 12
71 (List) [10,20]
72 area2 = 200
73 ## END
74
75 #### prototype()
76
77 func Rect_area(this) {
78 return (this.x * this.y)
79 }
80
81 var Rect = Object(null, {area: Rect_area})
82
83 var obj = Object(Rect, {x: 3, y: 4})
84
85 pp test_ (prototype(Rect))
86 pp test_ (prototype(obj))
87
88 ## STDOUT:
89 (Null) null
90 (Obj) ("area":<Func>)
91 ## END
92
93 #### propView()
94
95 var obj = Object(null, {x: 3, y: 4})
96 var props = propView(obj)
97
98 pp test_ (props)
99
100 # object can be mutated
101 setvar props.x = 99
102
103 pp test_ (props)
104
105 var e = propView(null) # error
106
107 ## status: 3
108 ## STDOUT:
109 (Dict) {"x":3,"y":4}
110 (Dict) {"x":99,"y":4}
111 ## END
112
113 #### Mutating method lookup with ->
114
115 func inc(self, n) {
116 setvar self.i += n
117 }
118 var Counter_methods = Object(null, {'M/inc': inc})
119
120 var c = Object(Counter_methods, {i: 5})
121
122 echo $[c.i]
123 call c->inc(3)
124 echo $[c.i]
125
126 ## STDOUT:
127 5
128 8
129 ## END
130
131 #### Mutating method must be up the prototype chain, not on the object
132
133 func inc(self, n) {
134 setvar self.i += n
135 }
136 var c = Object(null, {'M/inc': inc, i: 0})
137
138 call c->inc(3)
139
140 ## status: 3
141 ## STDOUT:
142 ## END
143
144
145 #### Copy to Dict with dict(), and mutate
146
147 var rect = Object(null, {x: 3, y: 4})
148 var d = dict(rect)
149
150 pp test_ (rect)
151 pp test_ (d)
152
153 setvar rect.x = 99
154 setvar d.x = 100
155
156 pp test_ (rect)
157 pp test_ (d)
158 ## STDOUT:
159 (Obj) ("x":3,"y":4)
160 (Dict) {"x":3,"y":4}
161 (Obj) ("x":99,"y":4)
162 (Dict) {"x":100,"y":4}
163 ## END
164
165 #### setvar obj.attr = and += and ...
166
167 var rect = Object(null, {x: 3, y: 4})
168 pp test_ (rect)
169
170 setvar rect.y = 99
171 pp test_ (rect)
172
173 setvar rect.y += 3
174 pp test_ (rect)
175
176 setvar rect.x *= 5
177 pp test_ (rect)
178
179 ## STDOUT:
180 (Obj) ("x":3,"y":4)
181 (Obj) ("x":3,"y":99)
182 (Obj) ("x":3,"y":102)
183 (Obj) ("x":15,"y":102)
184 ## END
185
186 #### obj['attr'] not allowed (for now)
187
188 var rect = Object(null, {x: 3, y: 4})
189
190 pp test_ ([rect['x'], rect['y']])
191
192 ## status: 3
193 ## STDOUT:
194 ## END
195
196 #### setvar obj['attr'] = 3 ?
197
198 var rect = Object(null, {x: 3, y: 4})
199
200 setvar rect['x'] = 99
201
202 pp test_ (rect)
203
204 # The reason this is allowed is because setvar does EvalLhsExpr(), which
205 # handles:
206 #
207 # - y_lhs.SubScript -> y_lvalue.Container
208 # - y_lhs.Attribute -> y_lvalue.Container
209 #
210 # So that means obj['x'] is allowed too?
211 # We could possible add y_lvalue.Container(is_subscript)
212
213 ## status: 3
214 ## STDOUT:
215 ## END
216
217 #### can't encode objects as JSON
218
219 var Rect = Object(null, {})
220
221 json write (Rect)
222 echo 'nope'
223
224 ## status: 1
225 ## STDOUT:
226 ## END
227
228 #### Can all builtin methods with s.upper()
229
230 var s = 'foo'
231 var x = s.upper()
232 var y = "--$[x.lower()]"
233
234 pp test_ (x)
235 pp test_ (y)
236
237 ## STDOUT:
238 (Str) "FOO"
239 (Str) "--foo"
240 ## END
241
242 #### invokable Obj must be have prototype containing __invoke__ of value.Proc - type -t
243
244 proc p (w; self) {
245 pp test_ ([w, self])
246 }
247 p a ({x: 5, y: 6})
248 echo
249
250 var methods = Object(null, {__invoke__: p})
251
252 var o1 = Object(methods, {})
253 type -t o1
254 echo
255
256 # errors
257
258 var o2 = Object(null, {})
259 if ! type -t o2 {
260 echo 'no prototype'
261 }
262
263 var o3 = Object(Object(null, {}), {})
264 if ! type -t o3 {
265 echo 'no __invoke__ method in prototype'
266 }
267
268 var bad_methods = Object(null, {__invoke__: 42})
269 var o4 = Object(bad_methods, {})
270 if ! type -t o4 {
271 echo '__invoke__ of wrong type'
272 }
273
274 ## STDOUT:
275 (List) ["a",{"x":5,"y":6}]
276
277 invokable
278
279 no prototype
280 no __invoke__ method in prototype
281 __invoke__ of wrong type
282 ## END
283
284 #### Object with longer prototype chain
285
286 # prototypal inheritance pattern
287 var superClassMethods = Object(null, {foo: 'zz'})
288 var methods = Object(superClassMethods, {foo: 42, bar: [1,2]})
289 var instance = Object(methods, {foo: 1, bar: 2, x: 3})
290
291 pp test_ (instance)
292 pp value (instance)
293
294 ## STDOUT:
295 (Obj) ("foo":1,"bar":2,"x":3) --> ("foo":42,"bar":[1,2]) --> ("foo":"zz")
296 (Obj) (foo: 1, bar: 2, x: 3) --> (foo: 42, bar: [1, 2]) --> (foo: 'zz')
297 ## END