Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make GAP.EvalString more convenient #163

Merged
merged 1 commit into from
Nov 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion LibGAP.jl/src/ccalls.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@ function GET_FROM_GAP(ptr::Ptr{Cvoid})::Any
return ccall(:julia_gap,Any,(Ptr{Cvoid},),ptr)
end

function EvalString( cmd :: String )
function EvalStringEx( cmd :: String )
res = ccall( :GAP_EvalString, MPtr,
(Ptr{UInt8},),
cmd );
return res
end

function EvalString( cmd :: String )
res = EvalStringEx(cmd * ";")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this is an sensible convention?

I am not sure it makes sense here, but in GAP you can end statements with ; or ;;. If you now put ;; at the end of a statement, this command does not return a value. Is that intentional?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, quite intentional:

  • if you want to shoot yourself in the foot, you can always do that, and e.g. end the string with a command that returns nothing; or add ;;;;; to the end (which amounts more or less the same); or do something else that's crazy. You can do so with the existing EvalString command do
  • I though about doing something like "check if there is a trailing semicolon and only add one if there is not" -- but then you can continue this game, and ask "what if the user put three semicolons at the end, should I remove some" etc.
  • Adding a semicolon is also what GAP's own EvalString does, so now the two match in their behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree that more or less all solutions have pitfalls. If GAP's EvalString method behaves like this, it is okay. Stupid question, why don't we make EvalString just

EvalString( x ) = GAP.Globals.EvalString( julia_to_gap( x ) )

This way we can have the exact same behaviour?

return res[end][2]
end

function ValueGlobalVariable( name :: String )
gvar = ccall( :GAP_ValueGlobalVariable, Ptr{Cvoid},
(Ptr{UInt8},),name)
Expand Down
2 changes: 1 addition & 1 deletion LibGAP.jl/test/basics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
end

@testset "gapcalls" begin
f = GAP.EvalString("{x...} -> x;")[1][2]
f = GAP.EvalString("{x...} -> x")

@test GAP.julia_to_gap([]) == f()
@test GAP.julia_to_gap([1]) == f(1)
Expand Down
22 changes: 11 additions & 11 deletions LibGAP.jl/test/convenience.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
@testset "integer_arithmetics" begin

# Create some large integers
large_int = GAP.EvalString( "2^100;" )[1][2]
large_int_p1 = GAP.EvalString( "2^100 + 1;" )[1][2]
large_int_m1 = GAP.EvalString( "2^100 - 1;" )[1][2]
large_int_squared = GAP.EvalString( "2^200;" )[1][2]
large_int_t2 = GAP.EvalString( "2^101;" )[1][2]
large_int = GAP.EvalString( "2^100" )
large_int_p1 = GAP.EvalString( "2^100 + 1" )
large_int_m1 = GAP.EvalString( "2^100 - 1" )
large_int_squared = GAP.EvalString( "2^200" )
large_int_t2 = GAP.EvalString( "2^101" )

@test zero(large_int) == 0
@test one(large_int) == 1
Expand Down Expand Up @@ -42,9 +42,9 @@ end

@testset "ffe_arithmetics" begin

z3_gen = GAP.EvalString( "Z(3);" )[1][2]
z3_one = GAP.EvalString( "Z(3)^0;" )[1][2]
z3_zero = GAP.EvalString( "0 * Z(3);" )[1][2]
z3_gen = GAP.EvalString( "Z(3)" )
z3_one = GAP.EvalString( "Z(3)^0" )
z3_zero = GAP.EvalString( "0 * Z(3)" )

z3 = GAP.Globals.Z(3)

Expand All @@ -60,9 +60,9 @@ end
end

@testset "object_access" begin
list = GAP.EvalString( "[1,2,3];" )[1][2]
matrix = GAP.EvalString( "[[1,2],[3,4]];" )[1][2]
record = GAP.EvalString( "rec( one := 1 );" )[1][2]
list = GAP.EvalString( "[1,2,3]" )
matrix = GAP.EvalString( "[[1,2],[3,4]]" )
record = GAP.EvalString( "rec( one := 1 )" )

@test length(list) == 3
@test list[1] == 1
Expand Down
67 changes: 32 additions & 35 deletions LibGAP.jl/test/conversion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,49 +20,49 @@

## BigInts
@test GAP.gap_to_julia(BigInt,1) == BigInt(1)
x = GAP.EvalString("2^100;")[1][2]
x = GAP.EvalString("2^100")
@test GAP.gap_to_julia(BigInt,x) == BigInt(2)^100
@test GAP.gap_to_julia(x) == BigInt(2)^100
x = GAP.EvalString("1/2;")[1][2]
x = GAP.EvalString("1/2")
@test_throws ArgumentError GAP.gap_to_julia(BigInt,x)

## Rationals
@test GAP.gap_to_julia(Rational{Int64},1) == 1//1
x = GAP.EvalString("2^100;")[1][2]
x = GAP.EvalString("2^100")
@test GAP.gap_to_julia(Rational{BigInt},x) == BigInt(2)^100 // 1
x = GAP.EvalString("2^100/3;")[1][2]
x = GAP.EvalString("2^100/3")
@test GAP.gap_to_julia(Rational{BigInt},x) == BigInt(2)^100 // 3
@test GAP.gap_to_julia(x) == BigInt(2)^100 // 3
x = GAP.EvalString("(1,2,3);")[1][2]
x = GAP.EvalString("(1,2,3)")
@test_throws ArgumentError GAP.gap_to_julia(Rational{BigInt},x)

## Floats
x = GAP.EvalString("2.;")[1][2]
x = GAP.EvalString("2.")
@test GAP.gap_to_julia(Float64,x) == 2.
@test GAP.gap_to_julia(x) == 2.
@test GAP.gap_to_julia(Float32,x) == Float32(2.)
@test GAP.gap_to_julia(Float16,x) == Float16(2.)
@test GAP.gap_to_julia(BigFloat,x) == BigFloat(2.)
x = GAP.EvalString("(1,2,3);")[1][2]
x = GAP.EvalString("(1,2,3)")
@test_throws ArgumentError GAP.gap_to_julia(Float64,x)

## Chars
x = GAP.EvalString("'x';")[1][2]
x = GAP.EvalString("'x'")
@test GAP.gap_to_julia(Cuchar,x) == Cuchar('x')
@test GAP.gap_to_julia(x) == Cuchar('x')
x = GAP.EvalString("(1,2,3);")[1][2]
x = GAP.EvalString("(1,2,3)")
@test_throws ArgumentError GAP.gap_to_julia(Cuchar,x)

## Strings & Symbols
x = GAP.EvalString("\"foo\";")[1][2]
x = GAP.EvalString("\"foo\"")
@test GAP.gap_to_julia(AbstractString,x) == "foo"
@test GAP.gap_to_julia(x) == "foo"
@test GAP.gap_to_julia(Symbol,x) == :foo
x = GAP.EvalString("(1,2,3);")[1][2]
x = GAP.EvalString("(1,2,3)")
@test_throws ArgumentError GAP.gap_to_julia(AbstractString,x)
x = GAP.EvalString("\"foo\";")[1][2]
x = GAP.EvalString("\"foo\"")
@test GAP.gap_to_julia(Array{UInt8,1},x) == UInt8[0x66,0x6f,0x6f]
x = GAP.EvalString("[1,2,3];")[1][2]
x = GAP.EvalString("[1,2,3]")
@test GAP.gap_to_julia(Array{UInt8,1},x) == UInt8[1,2,3]

## Arrays
Expand All @@ -75,17 +75,17 @@
@test GAP.gap_to_julia(Tuple{Int64,Any,Int32},x) == Tuple{Int64,Any,Int32}([1,2,3])

## Dictionaries
x = GAP.EvalString(" rec( foo := 1, bar := \"foo\" );" )[1][2]
x = GAP.EvalString(" rec( foo := 1, bar := \"foo\" )" )
y = Dict{Symbol,Any}( :foo => 1, :bar => "foo" )
@test GAP.gap_to_julia(Dict{Symbol,Any},x) == y
@test GAP.gap_to_julia(x) == y

## Default
x = GAP.EvalString("(1,2,3);")[1][2]
x = GAP.EvalString("(1,2,3)")
@test GAP.gap_to_julia(x) == x

## Recursive conversions
xx = GAP.EvalString("l:=[1];x:=[l,l];")[2][2]
xx = GAP.EvalString("l:=[1];x:=[l,l];")
conv = GAP.gap_to_julia(xx)
@test conv[1] === conv[2]
conv = GAP.gap_to_julia(Tuple{Tuple{Int64},Tuple{Int64}},xx)
Expand Down Expand Up @@ -114,61 +114,58 @@ end

## BigInts
@test GAP.julia_to_gap(BigInt(1)) == 1
x = GAP.EvalString("2^100;")[1][2]
x = GAP.EvalString("2^100")
@test GAP.julia_to_gap(BigInt(2)^100) == x

## Rationals
x = GAP.EvalString("2^100;")[1][2]
x = GAP.EvalString("2^100")
@test GAP.julia_to_gap(Rational{BigInt}(2)^100 // 1) == x
x = GAP.EvalString("2^100/3;")[1][2]
x = GAP.EvalString("2^100/3")
@test GAP.julia_to_gap(Rational{BigInt}(2)^100 // 3) == x
@test GAP.julia_to_gap(Rational{Int64}(1) // 0) == GAP.Globals.infinity

## Floats
x = GAP.EvalString("2.;")[1][2]
x = GAP.EvalString("2.")
@test GAP.julia_to_gap(2.) == x
@test GAP.julia_to_gap(Float32(2.)) == x
@test GAP.julia_to_gap(Float16(2.)) == x

## Chars
x = GAP.EvalString("'x';")[1][2]
x = GAP.EvalString("'x'")
@test GAP.julia_to_gap('x') == x

## Strings & Symbols
x = GAP.EvalString("\"foo\";")[1][2]
x = GAP.EvalString("\"foo\"")
@test GAP.julia_to_gap("foo") == x
@test GAP.julia_to_gap(:foo) == x

## Arrays
x = GAP.EvalString("[1,\"foo\",2];")[1][2]
x = GAP.EvalString("[1,\"foo\",2]")
@test GAP.julia_to_gap([1,"foo",BigInt(2)],Val(true)) == x
x = GAP.EvalString("[1,JuliaEvalString(\"\\\"foo\\\"\"),2];")[1][2]
x = GAP.EvalString("[1,JuliaEvalString(\"\\\"foo\\\"\"),2]")
@test GAP.julia_to_gap([1,"foo",BigInt(2)]) == x

## Tuples
x = GAP.EvalString("[1,\"foo\",2];")[1][2]
x = GAP.EvalString("[1,\"foo\",2]")
@test GAP.julia_to_gap((1,"foo",2),Val(true)) == x
x = GAP.EvalString("[1,JuliaEvalString(\"\\\"foo\\\"\"),2];")[1][2]
x = GAP.EvalString("[1,JuliaEvalString(\"\\\"foo\\\"\"),2]")
@test GAP.julia_to_gap((1,"foo",2)) == x

## Dictionaries
x = GAP.EvalString(" rec( foo := 1, bar := \"foo\" );" )[1][2]
x = GAP.EvalString(" rec( foo := 1, bar := \"foo\" )" )
y = Dict{Symbol,Any}( :foo => 1, :bar => "foo" )
@test GAP.julia_to_gap(y,Val(true)) == x
x = GAP.EvalString(" rec( foo := 1, bar := JuliaEvalString(\"\\\"foo\\\"\") );" )[1][2]
x = GAP.EvalString(" rec( foo := 1, bar := JuliaEvalString(\"\\\"foo\\\"\") )" )
@test GAP.julia_to_gap(y) == x

## Recursive conversions
l = [1]
yy = [l,l]
xx = GAP.EvalString("l:=[1];x:=[l,l];")[2][2]
xx = GAP.EvalString("l:=[1];x:=[l,l];")
conv = GAP.julia_to_gap(xx)
@test GAP.Globals.IsIdenticalObj(conv[1],conv[2])
## FIXME: This test is broken because of
## infinite recursion in ViewString
# l = Any[1]
# l[1] = l
# xx = GAP.EvalString("l:=[];l[1]:=l;")[1][2];
# @test GAP.julia_to_gap(l) == xx

xx = GAP.EvalString("[~]");
@test xx === xx[1]

end