#@local f,r,l
#
# Tests for the GAP coder logic.
#
# For now this mostly focuses on testing edge cases and error
# handling in the coder.
#
# The files coder.tst and interpreter.tst closely mirror each other.
#
gap> START_TEST("coder.tst");

#
# non boolean expression as condition
#
gap> function() if 1 then fi; end();
Error, <expr> must be 'true' or 'false' (not the integer 1)

#
# return is allowed in functions
#
gap> function() return; end();
gap> function() return 1; end();
1

#
# help system
#
gap> function() ?qwert_asdf end;
Syntax error: '?' cannot be used in this context in stream:1
function() ?qwert_asdf end;
           ^^^^^^^^^^^^^^^^
Syntax error: while parsing a function: statement or 'end' expected in stream:\
2

#
# function call with options
#
gap> f:=x->ValueOption("a");;
gap> ({}-> f(1) )();
fail
gap> ({}-> f(1 : a) )();
true
gap> ({}-> f(1 : ("a") ) )();
true
gap> ({}-> f(1 : a := 23) )();
23
gap> ({}-> f(1 : ("a") := 23 ) )();
23

#
# records
#
gap> r := ({}-> rec(a:=1) )();
rec( a := 1 )

#
gap> function() r.a := 1; end();
gap> ({}-> r.a )();
1
gap> ({}-> IsBound(r.a) )();
true
gap> function() Unbind(r.a); end();
gap> ({}-> r )();
rec(  )

#
gap> function() r!.a := 1; end();
gap> ({}-> r!.a )();
1
gap> ({}-> IsBound(r!.a) )();
true
gap> function() Unbind(r!.a); end();
gap> ({}-> r )();
rec(  )

#
gap> function() r.("a") := 1; end();
gap> ({}-> r.("a") )();
1
gap> ({}-> IsBound(r.("a")) )();
true
gap> function() Unbind(r.("a")); end();
gap> ({}-> r )();
rec(  )

#
gap> function() r!.("a") := 1; end();
gap> ({}-> r!.("a") )();
1
gap> ({}-> IsBound(r!.("a")) )();
true
gap> function() Unbind(r!.("a")); end();
gap> ({}-> r )();
rec(  )

# test special case in CodeRecExprBeginElmExpr
gap> f:=x-> rec( x:= 1, ("y") := 2, 42 := 3, (43) := 4);; Display(f); f(0);
function ( x )
    return rec(
        x := 1,
         ("y") := 2,
        42 := 3,
        43 := 4 );
end
rec( 42 := 3, 43 := 4, x := 1, y := 2 )

#
# component objects (atomic by default in HPC-GAP)
#
gap> r := Objectify(NewType(NewFamily("MockFamily"), IsComponentObjectRep), rec());;

#
gap> function() r!.a := 1; end();
gap> ({}-> r!.a )();
1
gap> ({}-> IsBound(r!.a) )();
true
gap> function() Unbind(r!.a); end();

#
gap> function() r!.("a") := 1; end();
gap> ({}-> r!.("a") )();
1
gap> ({}-> IsBound(r!.("a")) )();
true
gap> function() Unbind(r!.("a")); end();

#
# lists
#
gap> l := ({}-> [1,2,3] )();
[ 1, 2, 3 ]
gap> function()
>   local l;
>   l:=[1,2,3];
>   Display(l);
>   l[1] := 42;
>   Display(l[1]);
>   Display(IsBound(l[1]));
>   Unbind(l[1]);
>   Display(l);
>   l{[1,3]} := [42, 23];
>   Display(l);
>   Display(l{[3,1]});
> end();
[ 1, 2, 3 ]
42
true
[ , 2, 3 ]
[ 42, 2, 23 ]
[ 23, 42 ]
gap> function()
>   local l;
>   l:=[1,2,3];
>   IsBound(l{[1,3]});
> end;
Syntax error: statement expected in stream:4
  IsBound(l{[1,3]});
  ^^^^^^^
gap> function()
>   local l;
>   l:=[1,2,3];
>   Unbind(l{[1,3]});
> end;
Syntax error: Illegal operand for 'Unbind' in stream:4
  Unbind(l{[1,3]});
                 ^

#
gap> f:=function()
>   local l;
>   l:=[1,2,3];
>   Display(l);
>   l![1] := 42;
>   Display(l![1]);
>   Display(IsBound(l![1]));
>   Unbind(l![1]);
>   Display(l);
> end;;
gap> Display(f);
function (  )
    local l;
    l := [ 1, 2, 3 ];
    Display( l );
    l![1] := 42;
    Display( l![1] );
    Display( IsBound( l![1] ) );
    Unbind( l![1] );
    Display( l );
    return;
end
gap> f();
[ 1, 2, 3 ]
42
true
[ , 2, 3 ]

#
gap> l := [1,2,3];;
gap> function() l![fail] := 42; end();
Error, PosObj Assignment: <position> must be a positive small integer (not the\
 value 'fail')
gap> function() return l![fail]; end();
Error, PosObj Element: <position> must be a positive small integer (not the va\
lue 'fail')
gap> function() return IsBound(l![fail]); end();
Error, PosObj Element: <position> must be a positive small integer (not the va\
lue 'fail')
gap> function() Unbind(l![fail]); end();
Error, PosObj Assignment: <position> must be a positive small integer (not the\
 value 'fail')

#
# posobj
#
gap> l := Objectify(NewType(NewFamily("MockFamily"), IsPositionalObjectRep),[]);;

#
gap> function()
>   l![1] := 42;
>   Display(l![1]);
>   Display(IsBound(l![1]));
>   Unbind(l![1]);
>   Display(IsBound(l![1]));
> end();
42
true
false

#
gap> function() l![fail] := 42; end();
Error, PosObj Assignment: <position> must be a positive small integer (not the\
 value 'fail')
gap> function() return l![fail]; end();
Error, PosObj Element: <position> must be a positive small integer (not the va\
lue 'fail')
gap> function() return IsBound(l![fail]); end();
Error, PosObj Element: <position> must be a positive small integer (not the va\
lue 'fail')
gap> function() Unbind(l![fail]); end();
Error, PosObj Assignment: <position> must be a positive small integer (not the\
 value 'fail')

#
# atomic posobj (HPC-GAP)
#
gap> l := Objectify(NewType(NewFamily("MockFamily"), IsAtomicPositionalObjectRep),[23]);;

#
gap> function()
>   l![1] := 42;
>   Display(l![1]);
>   Display(IsBound(l![1]));
>   Unbind(l![1]);
>   Display(IsBound(l![1]));
> end();
42
true
false

#
gap> function() l![fail] := 42; end();
Error, PosObj Assignment: <position> must be a positive small integer (not the\
 value 'fail')
gap> function() return l![fail]; end();
Error, PosObj Element: <position> must be a positive small integer (not the va\
lue 'fail')
gap> function() return IsBound(l![fail]); end();
Error, PosObj Element: <position> must be a positive small integer (not the va\
lue 'fail')
gap> function() Unbind(l![fail]); end();
Error, PosObj Assignment: <position> must be a positive small integer (not the\
 value 'fail')

#
# weird corner cases in for loop index variables
#
gap> function() for + in [1,2,3] do od; end();
Syntax error: Identifier expected in stream:1
function() for + in [1,2,3] do od; end();
               ^
gap> function() local x; for x[1] in [1,2,3] do od; end();
Syntax error: in expected in stream:1
function() local x; for x[1] in [1,2,3] do od; end();
                         ^
gap> function() local x; for x{[1]} in [1,2,3] do od; end();
Syntax error: in expected in stream:1
function() local x; for x{[1]} in [1,2,3] do od; end();
                         ^
gap> function() for IsHPCGAP in [1,2,3] do od; end();
Error, Variable: 'IsHPCGAP' is constant
gap> function() for IsHPCGAP[1] in [1,2,3] do od; end();
Syntax error: in expected in stream:1
function() for IsHPCGAP[1] in [1,2,3] do od; end();
                       ^
gap> function() for IsHPCGAP{[1]} in [1,2,3] do od; end();
Syntax error: in expected in stream:1
function() for IsHPCGAP{[1]} in [1,2,3] do od; end();
                       ^
gap> function() for PrintObj in [1,2,3] do od; end();
Error, Variable: 'PrintObj' is read only
gap> function() for PrintObj[1] in [1,2,3] do od; end();
Syntax error: in expected in stream:1
function() for PrintObj[1] in [1,2,3] do od; end();
                       ^
gap> function() for PrintObj{[1]} in [1,2,3] do od; end();
Syntax error: in expected in stream:1
function() for PrintObj{[1]} in [1,2,3] do od; end();
                       ^

#
gap> STOP_TEST("coder.tst");
