1 /* testoxy.i
2 * $Id: testoxy.i,v 1.2 2010-07-17 22:44:56 dhmunro Exp $
3 * test object extensions to yorick
4 */
5 /* Copyright (c) 2010, David H. Munro.
6 * All rights reserved.
7 * This file is part of yorick (http://yorick.sourceforge.net).
8 * Read the accompanying LICENSE file for details.
9 */
10
11 /* intentionally create some items which conflict with object members */
test1(x)12 func test1(x)
13 {
14 goof = (data1 != 27);
15 d = x(data1);
16 if (d != -10) goof |= 2;
17 x, test1;
18 if (x("data1")!=-9 || data1!=27) goof |= 4;
19 x, "test1";
20 if (x(data1)!=-8 || data1!=27) goof |= 8;
21 data2 = x(5);
22 save, x, "data1", d, data2;
23 if (x(data1)!=-10 || data1!=27) goof |= 0x10;
24 if (x(*)!=6 ||
25 anyof(x(*,)!=["test1", "test2", "test3", "data1", "data2", "data3"]) ||
26 x(*,5)!="data2" || anyof(x(*,3::-2)!=["test3","test1"]) ||
27 x(*,0)!="data3" || anyof(x(*,[-1,3,5])!=["data2","test3","data2"]) ||
28 x(*,"data1")!=4 || anyof(x(*,["test1","data3","data1"])!=[1,6,4]))
29 goof |= 0x20;
30 d = x(data2,-,::-1);
31 a = x(-1,-,::-1);
32 if (anyof(dimsof(d)!=[2,1,5]) || anyof(d!=indgen(5:1:-1)(-,)) ||
33 anyof(dimsof(a)!=[2,1,5]) || anyof(a!=indgen(5:1:-1)(-,)))
34 goof |= 0x40;
35 a = x([-1,2]);
36 save,a, [], x(2:4);
37 if (anyof(a(*,)!=["data2","test2","test3","data1"])) goof |= 0x80;
38 save,a, , span(0,1,3), string(0), x;
39 if (anyof(a(*,)!=["data2","test2","test3",
40 "data1",string(0),string(0)])) goof |= 0x100;
41 if (is_obj(d) || !is_obj(a) || is_obj(a)!=3 ||
42 anyof(is_obj(a,)!=[0,0,0,0,0,3]) || is_obj(a,"test2") ||
43 anyof(is_obj(a,0:2:-2)!=[3,0,0]) || anyof(is_obj(a,[0,-5,6])!=[3,0,3]) ||
44 anyof(is_obj(a,["test2","data1"])))
45 goof |= 0x200;
46 if (is_obj(d,"x",1)!=-2 || anyof(is_obj(a,[0,-5,6],1)!=[3,0,3]) ||
47 is_obj(a,[0,-5,10],1)!=-1 ||is_obj(a,"oops",1)!=-1|| is_obj(a,9,1)!=-1 ||
48 anyof(is_obj(a,["test2","oops","data1"],1)!=[0,-1,0]))
49 goof |= 0x200;
50 b = x();
51 if (b(*)!=6 || anyof(b(*,)!=x(*,))) goof |= 0x400;
52 b = x(0:2:-2);
53 if (b(*)!=3 || anyof(b(*,)!=["data3","data1","test2"])) goof |= 0x400;
54 b = x([6,-2,0]); /* note repeat handling feature ?? */
55 if (b(*)!=2 || anyof(b(*,)!=["data3","data1"])) goof |= 0x400;
56 b = x(["data3","data1","data3"]);
57 if (b(*)!=2 || anyof(b(*,)!=["data3","data1"])) goof |= 0x400;
58 if (is_func(x(data3)) != 4) goof |= 0x800;
59 b = x(data3,d,data2);
60 if (anyof(vunpack(b,-)!=d) || anyof(vunpack(b,-)!=data2)) goof |= 0x800;
61 b = x.data3(d,data2);
62 if (anyof(vunpack(b,-)!=d) || anyof(vunpack(b,-)!=data2)) goof |= 0x800;
63 b = x(4:6);
64 save, b, y=cos, data1=[4.5,-1.5];
65 if (b(*)!=4 || anyof(b(*,)!=["data1","data2","data3","y"]) ||
66 anyof(b(data1)!=[4.5,-1.5]) || b(y)!=cos) goof |= 0x1000;
67 b, data1=b(data1,2), z=tan;
68 if (b(*)!=5 || anyof(b(*,)!=["data1","data2","data3","y","z"]) ||
69 b(data1)!=-1.5 || b(z)!=tan) goof |= 0x1000;
70 if (!goof) write, "PASSED oxy test1";
71 else write, format="***FAILED oxy test1, goof=%04lx\n", goof;
72 }
73 data1 = 27;
74
75 /* begin yorick idiom for creating an object
76 * first save saves the original values of testoxy members to be defined here
77 * second save save original values of incidental variables used to construct
78 * the data members of the object, but not part of the object itself
79 */
80 testoxy = save(test1, test2, test3, data1, data2, data3);
81 scratch = save(scratch, x, y, z);
82 /* now define the object members */
83
84 data1 = -10;
85 data2 = indgen(5);
86 data3 = vpack; /* try something not an array */
87
88 func test1
89 {
90 use, data1;
91 data1++;
92 }
93
94 func test2(x, &data3, z)
95 {
96 if (x==use(data1)) restore, use, data3;
97 if (z==use(4)) save, use, data1=use("data1")+12;
98 return save(wow=use(3:5), , use([1,2]));
99 }
100
101 func test3(a, .., key=)
102 {
103 while (more_args()) save, a, string(0), next_arg();
104 return (key==use(data1));
105 }
106
107 /* first restore puts back scratch variables (including scratch object)
108 * second restore puts back original member values, creating the new
109 * object from the values we just defined
110 * this completes yorick idiom for creating an object
111 */
112 restore, scratch;
113 testoxy = restore(testoxy);
114
115 test1, testoxy;
116 y = 7;
117 x = testoxy(test2, -10, y, -10);
118 if (y!=vpack || testoxy.data1!=2 || x(*)!=3 ||
119 anyof(x(*,)!=["wow","test1","test2"])) {
120 write, format="***FAILED oxy test2%s\n", "";
121 } else {
122 write, "PASSED oxy test2";
123 }
124 y = save(cos);
125 x = x(wow,test3, key=2, y,6,7,8);
126 if (!x || y(*)!=4 || y(cos)!=cos || anyof([y(2),y(3),y(4)]!=[6,7,8])) {
127 write, format="***FAILED oxy test3%s\n", "";
128 } else {
129 write, "PASSED oxy test3";
130 }
131
132 /* ---------------------- test closures */
133
cl_assert(test,msg)134 func cl_assert(test, msg) { if (!test) error, msg; }
135 errs2caller, cl_assert;
136
cl_op_extern1(data,arg)137 func cl_op_extern1(data, arg)
138 {
139 result = data;
140 if (!is_void(arg)) result += arg;
141 if (am_subroutine()) write, result;
142 else return result;
143 }
144
cl_op_extern2(data,arg)145 func cl_op_extern2(data, arg)
146 {
147 result = data + arg + 1;
148 if (am_subroutine()) write, result;
149 else return result;
150 }
151
cl_op_extern3(data,arg)152 func cl_op_extern3(data, arg)
153 {
154 return data + arg + 1;
155 }
156
157 func cl_test1
158 {
159 /* check that closure properly unreferences its "data" */
160 dat1 = m = "PASSED closure called with no arguments";
161 c = closure("cl_op_extern1", dat1);
162 dat1 = [1,2,-5];
163 c;
164 cl_assert,c.data == m, "expected static data";
165
166 /* check that closure properly solve its "function" at runtime */
167 c = closure("cl_op1", 42.0);
168 f = c.function;
169 cl_assert, is_void(f), "expecting a nil result";
170 cl_assert, is_closure(c) == 2, "expecting a runtime closure";
171 cl_op1 = cl_op_extern1;
172 cl_assert, is_func(c.function), "expecting a function";
173 cl_assert, c(1) == 43, "unexpected result";
174 cl_op1 = cl_op_extern2;
175 cl_assert, c(1) == 44, "unexpected result";
176 c = closure(cl_op_extern1, 42.0);
177 cl_assert, c.function_name == string(0), "bad function_name";
178 cl_assert, is_closure(c) == 1, "expecting an immutable closure";
179 cl_assert, c.data == 42.0, "bad data extract";
180
181 /* check closure with object argument */
182 data2 = -1;
183 c = closure(testoxy, data2);
184 cl_assert, is_closure(c) == 1, "expecting an immutable closure";
185 cl_assert, allof(c() == indgen(5)), "unexpected result";
186 cl_assert, allof(c.data == -1), "expected runtime data";
187 c = closure("o:testoxy", data2);
188 cl_assert, is_closure(c) == 2, "expecting a runtime closure";
189 cl_assert, c.data_name == "data2", "bad data name";
190 cl_assert, allof(c() == indgen(5)), "unexpected result";
191 cl_assert, allof(c.data == -1), "expected runtime data";
192 c = closure("testoxy", data2);
193 cl_assert, allof(c() == indgen(5)), "unexpected result";
194
195 write, "PASSED all closure tests";
196 }
197
198 /* normally, is_func(x)==5 should be adequate (even that rarely needed) */
is_closure(x)199 func is_closure(x)
200 {
201 if (is_func(x) != 5) return 0n;
202 if (x.function_name) return 2n;
203 return 1n;
204 }
205
206 if (is_func(closure)==5) closure = closure.data;
207 cl_test1;
208
209 func cl_test2
210 {
211 /* check that closure properly solve its "function" at runtime */
212 local cl_op1;
213 c = closure(cl_op1, 42.0);
214 f = c.function;
215 cl_assert, is_void(f), "expecting a nil result";
216 cl_assert, is_closure(c) == 2, "expecting a runtime closure";
217 cl_op1 = cl_op_extern1;
218 cl_assert, is_func(c.function), "expecting a function";
219 cl_assert, c(1) == 43, "unexpected result";
220 cl_op1 = cl_op_extern2;
221 cl_assert, c(1) == 44, "unexpected result";
222 c = closure(cl_op_extern1, 42.0);
223 cl_assert, c.function_name == "cl_op_extern1", "bad function_name";
224 cl_assert, is_closure(c) == 2, "expecting a runtime closure";
225 cl_assert, c.data == 42.0, "bad data extract";
226 write, "PASSED alternate closure tests";
227 }
228
229 /* create an alternate form of closure for which
230 * first argument simple variable reference is treated as
231 * resolve at runtime
232 * - may be useful for debugging
233 */
234 c = save(c, closure);
closure(args)235 func closure(args)
236 {
237 return args(1)((args(0,2)? args(2) : args(-,2)), args(3));
238 }
239 wrap_args, closure;
240 if (is_func(c(closure))==2) { /* be sure c(closure) is original builtin */
241 closure = c(closure, closure, c(closure)); /* you gotta love this */
242 restore, c, c;
243 } else { /* ... otherwise abort */
244 restore, c;
245 }
246
247 cl_test2;
248
249 /* put back built-in closure */
250 closure = closure.data;
251
252 /* ---------------------- test friend and sibling calls */
253
254 func test5
255 {
256 use, data1;
257 data1++;
258 }
259 save, testoxy, test5;
260
261 func test4(&x)
262 {
263 use, data1;
264 x = data1;
265 use_method, test5;
266 return data1++;
267 }
268
269 testoxy, data1=12;
270 x = testoxy(noop(test4), y);
271 if (y!=12 || x!=13 || testoxy(data1)!=14) {
272 write, format="***FAILED oxy %s test\n", "friend";
273 } else {
274 write, "PASSED oxy friend test";
275 }
276
277 save, testoxy, test4;
278 testoxy, data1=12;
279 x = testoxy(test4, y);
280 if (y!=12 || x!=13 || testoxy(data1)!=14) {
281 write, format="***FAILED oxy %s test\n", "sibling";
282 } else {
283 write, "PASSED oxy sibling test";
284 }
285