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