1########################################################################
2#                                                                      #
3#               This software is part of the ast package               #
4#          Copyright (c) 1982-2012 AT&T Intellectual Property          #
5#                      and is licensed under the                       #
6#                 Eclipse Public License, Version 1.0                  #
7#                    by AT&T Intellectual Property                     #
8#                                                                      #
9#                A copy of the License is available at                 #
10#          http://www.eclipse.org/org/documents/epl-v10.html           #
11#         (with md5 checksum b35adb5213ca9657e911e9befb180842)         #
12#                                                                      #
13#              Information and Software Systems Research               #
14#                            AT&T Research                             #
15#                           Florham Park NJ                            #
16#                                                                      #
17#                  David Korn <dgk@research.att.com>                   #
18#                                                                      #
19########################################################################
20function err_exit
21{
22	print -u2 -n "\t"
23	print -u2 -r ${Command}[$1]: "${@:2}"
24	(( Errors+=1 ))
25}
26alias err_exit='err_exit $LINENO'
27
28Command=${0##*/}
29integer Errors=0
30
31tmp=$(mktemp -dt) || { err_exit mktemp -dt failed; exit 1; }
32trap "cd /; rm -rf $tmp" EXIT
33
34integer n=2
35
36typeset -T Type_t=(
37	typeset name=foobar
38	typeset x=(hi=ok bar=yes)
39	typeset y=(xa=xx xq=89)
40	typeset -A aa=([one]=abc [two]=def)
41	typeset -a ia=(abc def)
42	typeset -i z=5
43)
44for ((i=0; i < 10; i++))
45do
46	Type_t r s
47	[[ $r == "$s" ]] || err_exit 'r is not equal to s'
48	typeset -C x=r.x
49	y=(xa=bb xq=cc)
50	y2=xyz
51	z2=xyz
52	typeset -C z=y
53	[[ $y == "$z" ]] || err_exit 'y is not equal to z'
54	typeset -C s.y=z
55	[[ $y == "${s.y}" ]] || err_exit 'y is not equal to s.y'
56	.sh.q=$y
57	typeset -C www=.sh.q
58	[[ $www == "$z" ]] || err_exit 'www is not equal to z'
59	typeset -C s.x=r.x
60	[[ ${s.x} == "${r.x}" ]] || err_exit 's.x is not equal to r.x'
61
62	function foo
63	{
64		nameref x=$1 y=$2
65		typeset z=$x
66		y=$x
67		[[ $x == "$y" ]] || err_exit "x is not equal to y with ${!x}"
68	}
69	foo r.y y
70	[[ $y == "${r.y}" ]] || err_exit 'y is not equal to r.y'
71	typeset -C y=z
72	foo y r.y
73	[[ $y == "${r.y}" ]] || err_exit 'y is not equal to r.y again'
74	typeset -C y=z
75	(
76		q=${z}
77		[[ $q == "$z" ]] || err_exit 'q is not equal to z'
78		z=abc
79	)
80	[[ $z == "$y" ]] || err_exit 'value of z not preserved after subshell'
81	unset z y r s x z2 y2 www .sh.q
82done
83typeset -T Frame_t=( typeset file lineno )
84Frame_t frame
85[[ $(typeset -p frame) == 'Frame_t frame=(typeset file;typeset lineno)' ]] || err_exit 'empty fields in type not displayed'
86x=( typeset -a arr=([2]=abc [4]=(x=1 y=def));zz=abc)
87typeset -C y=x
88[[ "$x" == "$y" ]] || print -u2 'y is not equal to x'
89Type_t z=(y=(xa=bb xq=cc))
90typeset -A arr=([foo]=one [bar]=2)
91typeset -A brr=([foo]=one [bar]=2)
92[[ "${arr[@]}" == "${brr[@]}" ]] || err_exit 'arr is not brr'
93for ((i=0; i < 1; i++))
94do	typeset -m zzz=x
95	[[ $zzz == "$y" ]] || err_exit 'zzz is not equal to y'
96	typeset -m x=zzz
97	[[ $x == "$y" ]] || err_exit 'x is not equal to y'
98	Type_t t=(y=(xa=bb xq=cc))
99	typeset -m r=t
100	[[ $r == "$z" ]] || err_exit 'r is not equal to z'
101	typeset -m t=r
102	[[ $t == "$z" ]] || err_exit 't is not equal to z'
103	typeset -m crr=arr
104	[[ "${crr[@]}" == "${brr[@]}" ]] || err_exit 'crr is not brr'
105	typeset -m arr=crr
106	[[ "${arr[@]}" == "${brr[@]}" ]] || err_exit 'brr is not arr'
107done
108typeset -m brr[foo]=brr[bar]
109[[ ${brr[foo]} == 2 ]] || err_exit 'move an associative array element fails'
110[[ ${brr[bar]} ]] && err_exit 'brr[bar] should be unset after move'
111unset x y zzz
112x=(a b c)
113typeset -m x[1]=x[2]
114[[ ${x[1]} == c ]] || err_exit 'move an indexed array element fails'
115[[ ${x[2]} ]] && err_exit 'x[2] should be unset after move'
116cat > $tmp/types <<- \+++
117	typeset -T Pt_t=(float x=1. y=0.)
118	Pt_t p=(y=2)
119	print -r -- ${p.y}
120+++
121expected=2
122got=$(. $tmp/types) 2>/dev/null
123[[ "$got" == "$expected" ]] || err_exit "typedefs in dot script failed -- expected '$expected', got '$got'"
124typeset -T X_t=(
125	typeset x=foo y=bar
126	typeset s=${_.x}
127	create()
128	{
129		_.y=bam
130	}
131)
132X_t x
133[[ ${x.x} == foo ]] || err_exit 'x.x should be foo'
134[[ ${x.y} == bam ]] || err_exit 'x.y should be bam'
135[[ ${x.s} == ${x.x} ]] || err_exit 'x.s should be x.x'
136typeset -T Y_t=( X_t r )
137Y_t z
138[[ ${z.r.x} == foo ]] || err_exit 'z.r.x should be foo'
139[[ ${z.r.y} == bam ]] || err_exit 'z.r.y should be bam'
140[[ ${z.r.s} == ${z.r.x} ]] || err_exit 'z.r.s should be z.r.x'
141
142unset xx yy
143typeset -T xx=(typeset yy=zz)
144xx=yy
145{ typeset -T xx=(typeset yy=zz) ;} 2>/dev/null && err_exit 'type redefinition should fail'
146$SHELL 2> /dev/null <<- +++ || err_exit 'typedef with only f(){} fails'
147	typeset -T X_t=(
148		f()
149		{
150			print ok
151		}
152	)
153+++
154$SHELL 2> /dev/null <<- +++ || err_exit 'unable to redefine f discipline function'
155	typeset -T X_t=(
156		x=1
157		f()
158		{
159			print ok
160		}
161	)
162	X_t z=(
163		function f
164		{
165			print override f
166		}
167	)
168+++
169$SHELL 2> /dev/null <<- +++ && err_exit 'invalid discipline name should be an error'
170	typeset -T X_t=(
171		x=1
172		f()
173		{
174			print ok
175		}
176	)
177	X_t z=(
178		function g
179		{
180			print override f
181		}
182	)
183+++
184# compound variables containing type variables
185Type_t r
186var=(
187	typeset x=foobar
188	Type_t	r
189	integer z=5
190)
191[[ ${var.r} == "$r" ]] || err_exit 'var.r != r'
192(( var.z == 5)) || err_exit 'var.z !=5'
193[[ "$var" == *x=foobar* ]] || err_exit '$var does not contain x=foobar'
194
195typeset -T A_t=(
196	typeset x=aha
197	typeset b=${_.x}
198)
199unset x
200A_t x
201expected=aha
202got=${x.b}
203[[ "$got" == "$expected" ]] || err_exit "type '_' reference failed -- expected '$expected', got '$got'"
204
205typeset -T Tst_t=(
206	 function f
207	 {
208	 	A_t a
209	 	print ${ _.g ${a.x}; }
210	 }
211	 function g
212	 {
213	 	print foo
214	 }
215)
216Tst_t tst
217expected=foo
218got=${ tst.f;}
219[[ "$got" == "$expected" ]] || err_exit "_.g where g is a function in type discipline method failed -- expected '$expected', got '$got'"
220
221typeset -T B_t=(
222	integer -a arr
223	function f
224	{
225		(( _.arr[0] = 0 ))
226		(( _.arr[1] = 1 ))
227		print ${_.arr[*]}
228	}
229)
230unset x
231B_t x
232expected='0 1'
233got=${ x.f;}
234[[ "$got" == "$expected" ]] || err_exit "array assignment of subscripts in type discipline arithmetic failed -- expected '$expected', got '$got'"
235
236typeset -T Fileinfo_t=(
237	size=-1
238	typeset -a text=()
239	integer mtime=-1
240)
241Fileinfo_t -A _Dbg_filenames
242Fileinfo_t finfo
243function bar
244{
245	finfo.text=(line1 line2 line3)
246	finfo.size=${#finfo.text[@]}
247	_Dbg_filenames[foo]=finfo
248}
249bar
250
251expected='Fileinfo_t -A _Dbg_filenames=([foo]=(size=3;typeset -a text=(line1 line2 line3);typeset -l -i mtime=-1))'
252got=$(typeset -p _Dbg_filenames)
253[[ "$got" == "$expected" ]] || {
254	got=$(printf %q "$got")
255	err_exit "copy to associative array of types in function failed -- expected '$expected', got $got"
256}
257
258$SHELL > /dev/null  <<- '+++++' || err_exit 'passing _ as nameref arg not working'
259	function f1
260	{
261	 	typeset -n v=$1
262	 	print -r -- "$v"
263	}
264	typeset -T A_t=(
265 		typeset blah=xxx
266	 	function f { f1 _ ;}
267	)
268	A_t a
269	[[ ${ a.f ./t1;} == "$a" ]]
270+++++
271expected='A_t b.a=(name=one)'
272[[ $( $SHELL << \+++
273	typeset -T A_t=(
274	     typeset name=aha
275	)
276	typeset -T B_t=(
277	 	typeset     arr
278	 	A_t         a
279	 	f()
280	 	{
281	 		_.a=(name=one)
282	 		typeset -p _.a
283	 	}
284	)
285	B_t b
286	b.f
287+++
288) ==  "$expected" ]] 2> /dev/null || err_exit  '_.a=(name=one) not expanding correctly'
289expected='A_t x=(name=xxx)'
290[[ $( $SHELL << \+++
291	typeset -T A_t=(
292		typeset name
293	)
294	A_t x=(name="xxx")
295	typeset -p x
296+++
297) ==  "$expected" ]] || err_exit  'empty field in definition does not expand correctly'
298
299typeset -T Foo_t=(
300	integer x=3
301	integer y=4
302	len() { print -r -- $(( sqrt(_.x**2 + _.y**2))) ;}
303)
304Foo_t foo
305[[ ${foo.len} == 5 ]] || err_exit "discipline function len not working"
306
307typeset -T benchmark_t=(
308	integer num_iterations
309)
310function do_benchmarks
311{
312	nameref tst=b
313	integer num_iterations
314	(( num_iterations= int(tst.num_iterations * 1.0) ))
315	printf "%d\n" num_iterations
316}
317benchmark_t b=(num_iterations=5)
318[[  $(do_benchmarks) == 5 ]] || err_exit 'scoping of nameref of type variables in arithmetic expressions not working'
319
320function cat_content
321{
322	cat <<- EOF
323	(
324		foo_t -a foolist=(
325			( val=3 )
326			( val=4 )
327			( val=5 )
328		)
329	)
330	EOF
331	return 0
332}
333typeset -T foo_t=(
334	integer val=-1
335	function print
336	{
337		print -- ${_.val}
338	}
339)
340function do_something
341{
342	nameref li=$1 # "li" may be an index or associative array
343	li[2].print
344}
345cat_content | read -C x
346[[ $(do_something x.foolist) == 5  ]] || err_exit 'subscripts not honored for arrays of type with disciplines'
347
348typeset -T benchcmd_t=(
349	float x=1
350	float y=2
351)
352unset x
353compound x=(
354	float o
355	benchcmd_t -a m
356	integer h
357)
358expected=$'(\n\ttypeset -l -i h=0\n\tbenchcmd_t -a m\n\ttypeset -l -E o=0\n)'
359[[ $x == "$expected" ]] || err_exit 'compound variable with array of types with no elements not working'
360
361expected=$'Std_file_t db.file[/etc/profile]=(action=preserve;typeset -A sum=([8242e663d6f7bb4c5427a0e58e2925f3]=1);)'
362{
363  got=$($SHELL <<- \EOF
364	MAGIC='stdinstall (at&t research) 2009-08-25'
365	typeset -T Std_file_t=(
366		typeset action
367		typeset -A sum
368	)
369	typeset -T Std_t=(
370		typeset magic=$MAGIC
371		Std_file_t -A file
372	)
373	Std_t db=(magic='stdinstall (at&t research) 2009-08-25';Std_file_t -A file=( [/./home/gsf/.env.sh]=(action=preserve;typeset -A sum=([9b67ab407d01a52b3e73e3945b9a3ee0]=1);)[/etc/profile]=(action=preserve;typeset -A sum=([8242e663d6f7bb4c5427a0e58e2925f3]=1);)[/home/gsf/.profile]=(action=preserve;typeset -A sum=([3ce23137335219672bf2865d003a098e]=1);));)
374	typeset -p db.file[/etc/profile]
375	EOF)
376} 2> /dev/null
377[[ $got == "$expected" ]] ||  err_exit 'types with arrays of types as members fails'
378
379typeset -T x_t=(
380	integer dummy
381	function set
382	{
383		[[ ${.sh.name} == v ]] || err_exit  "name=${.sh.name} should be v"
384		[[ ${.sh.subscript} == 4 ]] || err_exit "subscript=${.sh.subscript} should be 4"
385		[[ ${.sh.value} == hello ]] || err_exit  "value=${.sh.value} should be hello"
386	}
387)
388x_t -a v
389v[4]="hello"
390
391typeset -T oset=(
392    typeset -A s
393)
394oset foo bar
395: ${foo.s[a]:=foobar}
396: ${bar.s[d]:=foobar}
397[[ ${bar.s[a]} == foobar ]] && err_exit '${var:=val} for types assigns to type instead of type instance'
398
399typeset -T olist=(
400    typeset -a l
401)
402olist foo
403foo.l[1]=x
404[[  ${!foo.l[*]} == *0* ]] && '0-th elment of foo.l should not be set'
405
406typeset -T oset2=( typeset -A foo )
407oset2 bar
408: ${bar.foo[a]}
409bar.foo[a]=b
410[[ ${#bar.foo[*]} == 1 ]] || err_exit "bar.foo should have 1 element not  ${#bar.foo[*]}"
411[[ ${bar.foo[*]} == b ]] || err_exit "bar.foo[*] should be 'b'  not  ${bar.foo[*]}"
412[[ ${bar.foo[a]} == b ]] || err_exit "bar.foo[a] should be 'b'  not  ${bar.foo[*]}"
413
414{ x=$( $SHELL 2> /dev/null << \++EOF++
415    typeset -T ab_t=(
416        integer a=1 b=2
417        function increment
418        {
419                (( _.a++, _.b++ ))
420        }
421    )
422    function ar_n
423    {
424        nameref sn=$2
425        sn.increment
426        $1 && printf "a=%d, b=%d\n" sn.a sn.b
427    }
428    function ar
429    {
430        ab_t -S -a s
431        [[ -v s[5] ]] || s[5]=( )
432        ar_n $1 s[5]
433    }
434    x=$(ar false ; ar false ; ar true ; printf ";")
435    y=$(ar false ; ar false ; ar true ; printf ";")
436    print -r -- "\"$x\"" ==  "\"$y\""
437++EOF++
438) ;} 2> /dev/null
439[[ $x == *a=4*b=5* ]] || err_exit 'static types in a function not working'
440{ eval "[[ $x ]]";} 2> /dev/null || err_exit 'arrays of types leaving side effects in subshells'
441
442typeset -T y_t=(
443	typeset dummy
444	function print_b
445	{
446		print "B"
447	}
448)
449y_t a b=(
450	function print_b
451	{
452		print "1"
453	}
454)
455[[ $(a.print_b) == B ]] || err_exit 'default discipline not working'
456[[ $(b.print_b) == 1 ]] || err_exit 'discipline override not working'
457
458$SHELL 2> /dev/null -c 'true || { typeset -T Type_t=(typeset name=foo);
459	Type_t z=(name=bar) ;}' || err_exit 'unable to parse type command until typeset -T executes'
460
461cd "$tmp"
462FPATH=$PWD
463PATH=$PWD:$PATH
464cat > A_t <<-  \EOF
465	typeset -T A_t=(
466		B_t b
467	)
468EOF
469cat > B_t <<-  \EOF
470	typeset -T B_t=(
471		integer n=5
472	)
473EOF
474
475unset n
476if	n=$(FPATH=$PWD PATH=$PWD:$PATH $SHELL 2> /dev/null -c 'A_t a; print ${a.b.n}')
477then	(( n==5 )) || err_exit 'dynamic loading of types gives wrong result'
478else	err_exit 'unable to load types dynamically'
479fi
480
481# check that typeset -T reproduces a type.
482if	$SHELL  > /dev/null 2>&1  -c 'typeset -T'
483then	$SHELL > junk1 <<- \+++EOF
484		typeset -T foo_t=(
485			integer x=3 y=4
486			float z=1.2
487			len()
488			{
489				((.sh.value=sqrt(_.x**2 + _.y**2) ))
490			}
491			function count
492			{
493				print z=$z
494			}
495		)
496		typeset -T
497		print 'typeset -T'
498	+++EOF
499	$SHELL -c '. ./junk1;print "typeset -T"' > junk2
500	diff junk[12] > /dev/null || err_exit 'typeset -T not idempotent'
501	$SHELL -c '. ./junk1;print "typeset +f"' > junk2
502	[[ -s junk2 ]] || err_exit 'non-discipline-method functions found'
503else
504	err_exit 'typeset -T not supported'
505fi
506
507[[ $($SHELL -c 'typeset -T x=( typeset -a h ) ; x j; print -v j.h') ]] && err_exit 'type with indexed array without elements inserts element 0'
508
509[[ $($SHELL  -c 'typeset -T x=( integer -a s ) ; compound c ; x c.i ; c.i.s[4]=666 ; print -v c') == *'[0]'* ]] &&  err_exit 'type with indexed array with non-zero element inserts element 0'
510
511
512{ $SHELL -c '(sleep 3;kill $$)& typeset -T x=( typeset -a s );compound c;x c.i;c.i.s[7][5][3]=hello;x c.j=c.i;[[ ${c.i} == "${c.j}" ]]';} 2> /dev/null
513exitval=$?
514if	[[ $(kill -l $exitval) == TERM ]]
515then	err_exit 'clone of multi-dimensional array timed out'
516elif	((exitval))
517then	err_exit "c.i and c.j are not the same multi-dimensional array"
518fi
519
520typeset -T foobar_t=(
521	float x=1 y=0
522	slen()
523	{
524		print -r -- $((sqrt(_.x**2 + _.y**2)))
525	}
526	typeset -fS slen
527	len()
528	{
529		print -r -- $((sqrt(_.x**2 + _.y**2)))
530	}
531)
532unset z
533foobar_t z=(x=3 y=4)
534(( z.len == 5 )) || err_exit 'z.len should be 5'
535(( z.slen == 1 )) || err_exit 'z.slen should be 1'
536(( .sh.type.foobar_t.slen == 1 )) || err_exit '.sh.type.foobar_t.slen should be 1'
537(( .sh.type.foobar_t.len == 1 )) || err_exit '.sh.type.foobar_t.len should be 1'
538
539typeset -T z_t=( typeset -a ce )
540z_t x1
541x1.ce[3][4]=45
542compound c
543z_t -a c.x2
544c.x2[9]=x1
545got=$(typeset +p "c.x2[9].ce")
546exp='typeset -a c.x2[9].ce'
547[[ $got == "$exp" ]] || err_exit "typeset +p 'c.x2[9].ce' failed -- expected '$exp', got '$got'"
548
549unset b
550typeset -T a_t=(
551	typeset a="hello"
552)
553typeset -T b_t=(
554	a_t b
555)
556compound b
557compound -a b.ca
558b_t b.ca[4].b
559exp='typeset -C b=(typeset -C -a ca=( [4]=(b_t b=(a_t b=(a=hello))));)'
560got=$(typeset -p b)
561[[ $got == "$exp" ]] || err_exit 'typeset -p of nested type not correct'
562
563typeset -T u_t=(
564	integer dummy
565	unset()
566	{
567		print unset
568	}
569)
570unset z
571u_t -a x | read z
572[[ $z == unset ]]  && err_exit 'unset discipline called on type creation'
573
574{ z=$($SHELL 2> /dev/null 'typeset -T foo; typeset -T') ;} 2> /dev/null
575[[ $z == 'typeset -T foo' ]] || err_exit '"typeset -T foo; typeset -T" failed'
576
577{ z=$($SHELL 2> /dev/null 'typeset -T foo=bar; typeset -T') ;} 2> /dev/null
578[[ $z ]] && err_exit '"typeset -T foo=bar" should not creates type foo'
579
580{
581$SHELL << \EOF
582	typeset -T board_t=(
583		compound -a board_y
584		function binsert
585		{
586			nameref figure=$1
587			integer y=$2 x=$3
588			typeset -m "_.board_y[y].board_x[x].field=figure"
589		}
590	)
591	function main
592	{
593		compound c=(
594			 board_t b
595		)
596		for ((i=0 ; i < 2 ; i++ )) ; do
597			 compound p=( hello=world )
598			 c.b.binsert p 1 $i
599		done
600		exp='typeset -C c=(board_t b=(typeset -a board_y=( [1]=(typeset -a board_x=( [0]=(field=(hello=world;))[1]=(field=(hello=world)));));))'
601		[[ $(typeset -p c) == "$exp" ]] || exit 1
602	}
603	main
604EOF
605} 2> /dev/null
606if	(( exitval=$?))
607then	if	[[ $(kill -l $exitval) == SEGV ]]
608	then	err_exit 'typeset -m in type discipline causes exception'
609	else	err_exit 'typeset -m in type discipline gives wrong value'
610	fi
611fi
612
613typeset -T pawn_t=(
614	print_debug()
615	{
616		print 'PAWN'
617	}
618)
619function main
620{
621	compound c=(
622		compound -a board
623	)
624
625	for ((i=2 ; i < 8 ; i++ )) ; do
626		pawn_t c.board[1][$i]
627	done
628
629}
630main 2> /dev/null && err_exit 'type assignment to compound array instance should generate an error'
631
632{	$SHELL -c 'typeset -T Foo_t=(integer -a data=([0]=0) );Foo_t x=(data[0]=2);((x.data[0]==2))'
633} 2> /dev/null || err_exit 'type definition with integer array variable not working'
634
635typeset -T Bar_t=(
636	typeset -a foo
637)
638Bar_t bar
639bar.foo+=(bam)
640[[ ${bar.foo[0]} == bam ]] || err_exit 'appending to empty array variable in type does not create element 0'
641
642exit $((Errors<125?Errors:125))
643