Skip to content

Commit

Permalink
fixed and extended GAP <-> Julia conversions
Browse files Browse the repository at this point in the history
- fixed the GAP -> Julia conversion for strings
- added the GAP <-> Julia conversion for ranges
- added the GAP -> Julia conversion for Blists (to BitArrays);
  note that the Julia -> GAP conversion to Blists happens automatically)
- changed the generic GAP -> Julia conversions for GAP strings, ranges, blists
- added tests for all this

(Why is Cuchar and not Char the default type for the conversion
of GAP characters to Julia?)
  • Loading branch information
ThomasBreuer authored and fingolfin committed Mar 3, 2020
1 parent d945292 commit 640702a
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 13 deletions.
77 changes: 72 additions & 5 deletions src/gap_to_julia.jl
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ gap_to_julia( ::Type{Float16}, obj::GapObj) = Float16(gap_to_julia(Float64,obj)
gap_to_julia( ::Type{BigFloat}, obj::GapObj) = BigFloat(gap_to_julia(Float64,obj))

## Chars
function gap_to_julia( ::Type{Char}, obj::GapObj)
if ! Globals.IsChar( obj )
throw(ArgumentError("argument is not a character object"))
end
return Char( Globals.INT_CHAR(obj ) )
end

function gap_to_julia( ::Type{Cuchar}, obj::GapObj)
if ! Globals.IsChar( obj )
throw(ArgumentError("argument is not a character object"))
Expand All @@ -112,10 +119,13 @@ end

## Strings and symbols
function gap_to_julia(::Type{String},obj::GapObj)
if ! Globals.IsStringRep(obj)
if Globals.IsStringRep(obj)
return CSTR_STRING(obj)
elseif Globals.IsString(obj)
return CSTR_STRING( Globals.CopyToStringRep( obj ) )
else
throw(ArgumentError("<obj> is not a string"))
end
return CSTR_STRING(obj)
end
gap_to_julia(::Type{AbstractString},obj::GapObj) = gap_to_julia(String,obj)
gap_to_julia(::Type{Symbol},obj::GapObj) = Symbol(gap_to_julia(String,obj))
Expand All @@ -135,6 +145,19 @@ function gap_to_julia( ::Type{Array{UInt8,1}}, obj :: GapObj )
end
end

## BitArrays
function gap_to_julia( ::Type{BitArray{1}}, obj :: GapObj )
if ! Globals.IsBlist( obj )
throw(ArgumentError("<obj> is not a boolean list"))
end
len = Globals.Length( obj )
result = BitArray( undef, len )
for i in 1:len
result[i] = obj[i]
end
return result
end

## Arrays
function gap_to_julia( ::Type{Array{Obj,1}}, obj :: GapObj , recursion_dict = IdDict() )
if ! Globals.IsList( obj )
Expand Down Expand Up @@ -208,6 +231,43 @@ function gap_to_julia( ::Type{T}, obj::GapObj, recursion_dict = IdDict() ) where
return T(list)
end

## Ranges
function gap_to_julia( ::Type{T}, obj::GapObj ) where T <: UnitRange
if ! Globals.IsRange( obj )
throw(ArgumentError("first argument is not a range"))
end
len = Globals.Length( obj )
if len == 0
# construct an empty UnitRange object
result = 1:0
elseif len == 1
result = obj[1]:obj[1]
elseif obj[2] != obj[1] + 1
throw(ArgumentError("step width of first argument is not 1"))
else
result = obj[1]:obj[len]
end

return T( result )
end

function gap_to_julia( ::Type{T}, obj::GapObj ) where T <: StepRange
if ! Globals.IsRange( obj )
throw(ArgumentError("first argument is not a range"))
end
len = Globals.Length( obj )
if len == 0
# construct an empty StepRange object
result = 1:1:0
elseif len == 1
result = obj[1]:1:obj[1]
else
result = obj[1]:(obj[2]-obj[1]):obj[len]
end

return T( result )
end

## Dictionaries
function gap_to_julia( ::Type{Dict{Symbol,T}}, obj :: GapObj, recursion_dict = IdDict() ) where T
if ! Globals.IsRecord( obj )
Expand All @@ -229,8 +289,6 @@ function gap_to_julia( ::Type{Dict{Symbol,T}}, obj :: GapObj, recursion_dict = I
return dict
end

## TODO: BitArray <-> blist; ranges; ...

## Generic conversions

gap_to_julia(x::Any) = x
Expand All @@ -243,9 +301,18 @@ function gap_to_julia(x::GapObj)
elseif Globals.IsFloat(x)
return gap_to_julia(Float64,x)
elseif Globals.IsChar(x)
#T why Cuchar not Char?
return gap_to_julia(Cuchar,x)
elseif Globals.IsString(x)
elseif Globals.IsStringRep(x)
# Do not choose this conversion for other lists in 'IsString'.
return gap_to_julia(AbstractString,x)
elseif Globals.IsRangeRep(x)
# Do not choose this conversion for other lists in 'IsRange'.
# Note that the entries are always small GAP integers.
return gap_to_julia(StepRange{Int64,Int64},x)
elseif Globals.IsBlistRep(x)
# Do not choose this conversion for other lists in 'IsBlist'.
return gap_to_julia(BitArray{1},x)
elseif Globals.IsList(x)
return gap_to_julia(Array{Union{Any,Nothing},1},x)
elseif Globals.IsRecord(x)
Expand Down
17 changes: 14 additions & 3 deletions src/julia_to_gap.jl
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ julia_to_gap(x::Symbol) = MakeString(string(x))
## Generic caller for optional arguments
julia_to_gap(obj::Any, recursive, recursion_dict ) = julia_to_gap(obj)

## Arrays
## Arrays (including BitArray{1})
function julia_to_gap(obj::Array{T,1}, recursive::Val{Recursive}=Val(false), recursion_dict = IdDict()) where Recursive where T
len = length(obj)
ret_val = NewPlist(len)
Expand Down Expand Up @@ -118,6 +118,19 @@ function julia_to_gap(obj::Tuple, recursive::Val{Recursive}=Val(false), recursio
return julia_to_gap(array, recursive, recursion_dict)
end

## Ranges
# FIXME: eventually check that the values are valid for GAP ranges
function julia_to_gap( range::UnitRange{T} ) where T <: Integer
return EvalString( "[" * string( range.start ) *
".." * string( range.stop ) * "]" )
end

function julia_to_gap( range::StepRange{T1,T2} ) where { T1 <: Integer,T2 <: Integer }
return EvalString( "[" * string( range.start ) *
"," * string( range.start + range.step ) *
".." * string( range.stop ) * "]" )
end

## Dictionaries
function julia_to_gap(obj::Dict{T,S}, recursive::Val{Recursive}=Val(false), recursion_dict = IdDict()) where Recursive where S where T <: Union{Symbol,AbstractString}

Expand Down Expand Up @@ -150,5 +163,3 @@ end

julia_to_gap(func::Function) = NewJuliaFunc(func)


## TODO: BitArray <-> blist; ranges; ...
65 changes: 60 additions & 5 deletions test/conversion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
@test GAP.gap_to_julia(Any, true ) == true
@test GAP.gap_to_julia(GAP.Obj, true ) == true
@test GAP.gap_to_julia(Any, "foo" ) == "foo"

## Integers
@test GAP.gap_to_julia(Int128,1) == Int128(1)
@test GAP.gap_to_julia(Int64 ,1) == Int64(1)
Expand Down Expand Up @@ -55,6 +55,14 @@
@test_throws ArgumentError GAP.gap_to_julia(Cuchar,x)

## Strings & Symbols
x = GAP.EvalString("[]")
@test GAP.Globals.IsString( x ) == true
@test GAP.Globals.IsStringRep( x ) == false
@test GAP.gap_to_julia(String,x) == ""
x = GAP.EvalString("[ 'a', 'b', 'c' ]")
@test GAP.Globals.IsString( x ) == true
@test GAP.Globals.IsStringRep( x ) == false
@test GAP.gap_to_julia(String,x) == "abc"
x = GAP.EvalString("\"foo\"")
@test GAP.gap_to_julia(String,x) == "foo"
@test GAP.gap_to_julia(AbstractString,x) == "foo"
Expand Down Expand Up @@ -86,11 +94,38 @@
n = GAP.EvalString("[[1,2],[,4]]")
@test GAP.gap_to_julia(Array{Union{Int64,Nothing},2},n) == [1 2; nothing 4]

## BitArrays
x = GAP.EvalString( "[ true, false, false, true ]" )
@test GAP.gap_to_julia( BitArray{1}, x ) == [ true, false, false, true ]
x = GAP.EvalString( "[ 1, 0, 0, 1 ]" )
@test_throws ArgumentError GAP.gap_to_julia( BitArray{1}, x )

## Tuples
x = GAP.julia_to_gap([1,2,3])
@test GAP.gap_to_julia(Tuple{Int64,Any,Int32},x) == Tuple{Int64,Any,Int32}([1,2,3])
n = GAP.julia_to_gap(big(2)^100)
@test_throws ArgumentError GAP.gap_to_julia(Tuple{Int64,Any,Int32},n)


## Ranges
r = GAP.EvalString( "[]" )
@test GAP.gap_to_julia( UnitRange{Int64}, r ) == 1:0
@test GAP.gap_to_julia( StepRange{Int64,Int64}, r ) == 1:1:0
r = GAP.EvalString( "[ 1 ]" )
@test GAP.gap_to_julia( UnitRange{Int64}, r ) == 1:1
@test GAP.gap_to_julia( StepRange{Int64,Int64}, r ) == 1:1:1
r = GAP.EvalString( "[ 4 .. 13 ]" )
@test GAP.gap_to_julia( UnitRange{Int64}, r ) == 4:13
@test GAP.gap_to_julia( StepRange{Int64,Int64}, r ) == 4:1:13
r = GAP.EvalString( "[ 1, 4 .. 10 ]" )
@test_throws ArgumentError GAP.gap_to_julia( UnitRange{Int64}, r )
@test GAP.gap_to_julia( StepRange{Int64,Int64}, r ) == 1:3:10
r = GAP.EvalString( "[ 1, 2, 4 ]" )
@test_throws ArgumentError GAP.gap_to_julia( UnitRange{Int64}, r )
@test_throws ArgumentError GAP.gap_to_julia( StepRange{Int64,Int64}, r )
r = GAP.EvalString( "rec()" )
@test_throws ArgumentError GAP.gap_to_julia( UnitRange{Int64}, r )
@test_throws ArgumentError GAP.gap_to_julia( StepRange{Int64,Int64}, r )

## Dictionaries
x = GAP.EvalString(" rec( foo := 1, bar := \"foo\" )" )
y = Dict{Symbol,Any}( :foo => 1, :bar => "foo" )
Expand Down Expand Up @@ -142,7 +177,7 @@ end

## Defaults
@test GAP.julia_to_gap( true )

## Integers
@test GAP.julia_to_gap(Int128(1)) == 1
@test GAP.julia_to_gap(Int64(1)) == 1
Expand Down Expand Up @@ -192,13 +227,33 @@ end
@test GAP.julia_to_gap([1,"foo",BigInt(2)]) == x
x = GAP.EvalString("[[1,2],[3,4]]")
@test GAP.julia_to_gap([ 1 2 ; 3 4 ]) == x


## BitArrays
x = GAP.EvalString("BlistList([1,2],[1])")
y = GAP.julia_to_gap([true,false])
@test y == x
@test GAP.gap_to_julia( GAP.Globals.TNAM_OBJ( y ) ) == "list (boolean)"

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


## Ranges
r = GAP.EvalString( "[]" )
@test GAP.julia_to_gap( 1:0 ) == r
@test GAP.julia_to_gap( 1:1:0 ) == r
r = GAP.EvalString( "[ 1 ]" )
@test GAP.julia_to_gap( 1:1 ) == r
@test GAP.julia_to_gap( 1:1:1 ) == r
r = GAP.EvalString( "[ 4 .. 13 ]" )
@test GAP.julia_to_gap( 4:13 ) == r
@test GAP.julia_to_gap( 4:1:13 ) == r
r = GAP.EvalString( "[ 1, 4 .. 10 ]" )
@test GAP.julia_to_gap( 1:3:10 ) == r
@test_throws ErrorException GAP.julia_to_gap( 1:2^62 )

## Dictionaries
x = GAP.EvalString(" rec( foo := 1, bar := \"foo\" )" )
# ... recursive conversion
Expand Down

0 comments on commit 640702a

Please sign in to comment.