Skip to content

Commit

Permalink
Make GAP.jl usable as a Julia module with precompilation
Browse files Browse the repository at this point in the history
* Move *.jl files from JuliaInterface to module itself
* Add GAPTypes.jl package as dependency
* Replaced MPtr by GapObj
* Removed unnecessary libgap.jl
* Moved MPtr call definition into init, eval into Main
  to not eval into a closed module
  • Loading branch information
sebasguts authored and fingolfin committed Jun 17, 2019
1 parent 52a83df commit 7e4cfd1
Show file tree
Hide file tree
Showing 9 changed files with 79 additions and 78 deletions.
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ authors = ["Thomas Breuer <[email protected]>", "Sebastian Gutsche <gutsch
version = "0.1.0"

[deps]
GAPTypes = "cd4130c4-8d21-11e9-2a29-61e008680c2d"
Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
REPL = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
Expand Down
21 changes: 0 additions & 21 deletions pkg/GAPJulia/JuliaInterface/julia/libgap.jl

This file was deleted.

2 changes: 0 additions & 2 deletions pkg/GAPJulia/JuliaInterface/read.g
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ dirs_julia := DirectoriesPackageLibrary( "JuliaInterface", "julia" );

JuliaIncludeFile( Filename( dirs_julia, "gaptypes.jl" ) );

JuliaEvalString( Concatenation( "__JULIAGAPMODULE.include( \"", Filename( dirs_julia, "libgap.jl" ), "\")" ) );

_JULIAINTERFACE_INTERNAL_INIT();

## The GAP module is also bound to the variable __JULIAGAPMODULE,
Expand Down
20 changes: 20 additions & 0 deletions src/GAP.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ import Base: length, convert, finalize

import Libdl

using GAPTypes

export GapObj

const Obj = Union{GapObj,FFE,Int64,Bool,Nothing}

sysinfo = missing

function read_sysinfo_gap(dir::String)
Expand Down Expand Up @@ -108,6 +114,20 @@ function __init__()
if ! isdefined(Main, :__GAPINTERNAL_LOADED_FROM_GAP) || Main.__GAPINTERNAL_LOADED_FROM_GAP != true
run_it(GAPROOT, error_handler_func)
end

## FIXME: Hack because abstract types cannot be endowed with methods in Julia 1.1.
## With Julia 1.2, this will be possible and this hack could then be replaced with the
## corresponding function call in in ccalls.jl (func::GapObj)(...)
MPtr = Base.MainInclude.eval(:(ForeignGAP.MPtr))
Base.MainInclude.eval(:(
(func::$MPtr)(args...; kwargs...) = call_gap_func(func, args...; kwargs...)
))
end

include( "ccalls.jl" )
include( "gap2.jl" )
include( "macros.jl" )
include( "gap_to_julia.jl" )
include( "julia_to_gap.jl" )

end
21 changes: 12 additions & 9 deletions pkg/GAPJulia/JuliaInterface/julia/ccalls.jl → src/ccalls.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,21 @@ function AssignGlobalVariable(name::String, value::Obj)
(Ptr{UInt8}, Ptr{Cvoid}), name, tmp)
end

function MakeString( val::String )::MPtr
function MakeString( val::String )::GapObj
string = ccall( :GAP_MakeString, Any,
( Ptr{UInt8}, ),
val )
return string
end

function CSTR_STRING( val::MPtr )::String
function CSTR_STRING( val::GapObj )::String
char_ptr = ccall( :GAP_CSTR_STRING, Ptr{UInt8},
( Any, ),
val )
return deepcopy(unsafe_string(char_ptr))
end

function UNSAFE_CSTR_STRING( val::MPtr )::Array{UInt8,1}
function UNSAFE_CSTR_STRING( val::GapObj )::Array{UInt8,1}
string_len = Int64( ccall( :GAP_LenString, Cuint,
( Any, ),
val ) )
Expand Down Expand Up @@ -91,7 +91,7 @@ function NEW_MACFLOAT(x::Float64)
return o
end

function ValueMacFloat(x::MPtr)
function ValueMacFloat(x::GapObj)
o = ccall( :GAP_ValueMacFloat,
Cdouble,
(Any,),
Expand All @@ -107,7 +107,7 @@ function CharWithValue(x::Cuchar)
return o
end

function ElmList(x::MPtr,position)
function ElmList(x::GapObj,position)
o = ccall( :GAP_ElmList,
Ptr{Cvoid},
(Any,Culong),
Expand All @@ -124,15 +124,18 @@ function NewJuliaFunc(x::Function)
end

"""
(func::MPtr)(args...)
(func::GapObj)(args...)
> This function makes it possible to call MPtr objects as functions.
> This function makes it possible to call GapObjs as functions.
> There is no argument number checking here, all checks on the arguments
> are done by GAP itself.
"""
(func::MPtr)(args...; kwargs...) = call_gap_func(func, args...; kwargs...)
# # The (func::GapObj) function (commented out below) needs to be instantiated for `MPtr`
# # and is therefore moved to the init function
# (func::GapObj)(args...; kwargs...) where T <: GapObj = call_gap_func(func, args...; kwargs...)

function call_gap_func(func::MPtr, args...; kwargs...)

function call_gap_func(func::GapObj, args...; kwargs...)
global Globals
options = false
if length(kwargs) > 0
Expand Down
48 changes: 24 additions & 24 deletions pkg/GAPJulia/JuliaInterface/julia/gap.jl → src/gap2.jl
Original file line number Diff line number Diff line change
@@ -1,53 +1,53 @@
import Base: convert, getindex, setindex!, length, show

function Base.show( io::IO, obj::Union{MPtr,FFE} )
function Base.show( io::IO, obj::Union{GapObj,FFE} )
str = Globals.String( obj )
stri = CSTR_STRING( str )
print(io,"GAP: $stri")
end

function Base.string( obj::Union{MPtr,FFE} )
function Base.string( obj::Union{GapObj,FFE} )
str = Globals.String( obj )
return CSTR_STRING( str )
end

## implement indexing interface
Base.getindex(x::MPtr, i::Int64) = Globals.ELM_LIST(x, i)
Base.setindex!(x::MPtr, v::Any, i::Int64 ) = Globals.ASS_LIST( x, i, v )
Base.length(x::MPtr) = Globals.Length(x)
Base.firstindex(x::MPtr) = 1
Base.lastindex(x::MPtr) = Globals.Length(x)
Base.getindex(x::GapObj, i::Int64) = Globals.ELM_LIST(x, i)
Base.setindex!(x::GapObj, v::Any, i::Int64 ) = Globals.ASS_LIST( x, i, v )
Base.length(x::GapObj) = Globals.Length(x)
Base.firstindex(x::GapObj) = 1
Base.lastindex(x::GapObj) = Globals.Length(x)

# matrix
Base.getindex(x::MPtr, i::Int64, j::Int64) = Globals.ELM_LIST(x, i, j)
Base.setindex!(x::MPtr, v::Any, i::Int64, j::Int64) = Globals.ASS_LIST(x, i, j, v)
Base.getindex(x::GapObj, i::Int64, j::Int64) = Globals.ELM_LIST(x, i, j)
Base.setindex!(x::GapObj, v::Any, i::Int64, j::Int64) = Globals.ASS_LIST(x, i, j, v)

# records
RNamObj(f::Union{Symbol,Int64,AbstractString}) = Globals.RNamObj(MakeString(string(f)))
# note: we don't use Union{Symbol,Int64,AbstractString} below to avoid
# ambiguity between these methods and method `getproperty(x, f::Symbol)`
# from Julia's Base module
Base.getproperty(x::MPtr, f::Symbol) = Globals.ELM_REC(x, RNamObj(f))
Base.getproperty(x::MPtr, f::Union{AbstractString,Int64}) = Globals.ELM_REC(x, RNamObj(f))
Base.setproperty!(x::MPtr, f::Symbol, v) = Globals.ASS_REC(x, RNamObj(f), v)
Base.setproperty!(x::MPtr, f::Union{AbstractString,Int64}, v) = Globals.ASS_REC(x, RNamObj(f), v)
Base.getproperty(x::GapObj, f::Symbol) = Globals.ELM_REC(x, RNamObj(f))
Base.getproperty(x::GapObj, f::Union{AbstractString,Int64}) = Globals.ELM_REC(x, RNamObj(f))
Base.setproperty!(x::GapObj, f::Symbol, v) = Globals.ASS_REC(x, RNamObj(f), v)
Base.setproperty!(x::GapObj, f::Union{AbstractString,Int64}, v) = Globals.ASS_REC(x, RNamObj(f), v)

#
Base.zero(x::Union{MPtr,FFE}) = Globals.ZERO(x)
Base.one(x::Union{MPtr,FFE}) = Globals.ONE(x)
Base.:-(x::Union{MPtr,FFE}) = Globals.AINV(x)
Base.zero(x::Union{GapObj,FFE}) = Globals.ZERO(x)
Base.one(x::Union{GapObj,FFE}) = Globals.ONE(x)
Base.:-(x::Union{GapObj,FFE}) = Globals.AINV(x)

#
typecombinations = ((:MPtr,:MPtr),
typecombinations = ((:GapObj,:GapObj),
(:FFE,:FFE),
(:MPtr,:FFE),
(:FFE,:MPtr),
(:MPtr,:Int64),
(:Int64,:MPtr),
(:GapObj,:FFE),
(:FFE,:GapObj),
(:GapObj,:Int64),
(:Int64,:GapObj),
(:FFE,:Int64),
(:Int64,:FFE),
(:MPtr,:Bool),
(:Bool,:MPtr),
(:GapObj,:Bool),
(:Bool,:GapObj),
(:FFE,:Bool),
(:Bool,:FFE))
function_combinations = ((:+,:SUM),
Expand Down Expand Up @@ -131,7 +131,7 @@ end

export LoadPackageAndExposeGlobals

function Display(x::MPtr)
function Display(x::GapObj)
## FIXME: Get rid of this horrible hack
## once GAP offers a consistent
## DisplayString function
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ of converted objects and should never be given by the user.
## Julia object x to type T, provided that the type of x is a subtype of T;
## otherwise, explicitly reject the conversion.
## As an example why this is useful, suppose you have a GAP list x (i.e., an
## object of type MPtr) containing a bunch of Julia tuples. Then this method
## object of type GapObj) containing a bunch of Julia tuples. Then this method
## enables conversion of that list to a Julia array of type Array{Tuple,1},
## like this:
## gap_to_julia(Array{Tuple{Int64},1},xx)
## This works because first the gap_to_julia method with signature
## (::Type{Array{T,1}}, :: MPtr) is invoked, with T = Tuple{Int64}; this then
## (::Type{Array{T,1}}, :: GapObj) is invoked, with T = Tuple{Int64}; this then
## invokes gap_to_julia recursively with signature (::Tuple{Int64},::Any),
## which ends up selecting the method below.
function gap_to_julia(t::T, x::Any) where T <: Type
Expand All @@ -30,7 +30,7 @@ function gap_to_julia(t::T, x::Any) where T <: Type
end

## Default
gap_to_julia(::Type{Any}, x::MPtr) = gap_to_julia(x)
gap_to_julia(::Type{Any}, x::GapObj) = gap_to_julia(x)
gap_to_julia(::Type{Any}, x::Any) = x
gap_to_julia(::T, x::Nothing) where T <: Type = nothing
gap_to_julia(::Type{Any}, x::Nothing) = nothing
Expand All @@ -52,7 +52,7 @@ gap_to_julia(::Type{UInt8} ,x::Int64) = trunc(UInt8 ,x)
## BigInts
gap_to_julia(::Type{BigInt}, x::Int64) = BigInt( x )

function gap_to_julia(::Type{BigInt}, x::MPtr)
function gap_to_julia(::Type{BigInt}, x::GapObj)
## Check for correct type
if ! Globals.IsInt(x)
throw(ArgumentError("GAP object is not a large integer"))
Expand All @@ -77,7 +77,7 @@ function gap_to_julia(::Type{Rational{T}}, x::Int64) where T <: Integer
return numerator // T(1)
end

function gap_to_julia(::Type{Rational{T}}, x::MPtr) where T <: Integer
function gap_to_julia(::Type{Rational{T}}, x::GapObj) where T <: Integer
if Globals.IsInt(x)
return gap_to_julia(T,x) // T(1)
end
Expand All @@ -90,39 +90,39 @@ function gap_to_julia(::Type{Rational{T}}, x::MPtr) where T <: Integer
end

## Floats
function gap_to_julia( ::Type{Float64}, obj::MPtr)
function gap_to_julia( ::Type{Float64}, obj::GapObj)
if ! Globals.IsFloat(obj)
throw(ArgumentError("<obj> is not a MacFloat"))
end
return ValueMacFloat(obj)
end

gap_to_julia( ::Type{Float32}, obj::MPtr) = Float32(gap_to_julia(Float64,obj))
gap_to_julia( ::Type{Float16}, obj::MPtr) = Float16(gap_to_julia(Float64,obj))
gap_to_julia( ::Type{BigFloat}, obj::MPtr) = BigFloat(gap_to_julia(Float64,obj))
gap_to_julia( ::Type{Float32}, obj::GapObj) = Float32(gap_to_julia(Float64,obj))
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{Cuchar}, obj::MPtr)
function gap_to_julia( ::Type{Cuchar}, obj::GapObj)
if ! Globals.IsChar( obj )
throw(ArgumentError("argument is not a character object"))
end
return trunc( Cuchar, Globals.INT_CHAR(obj ) )
end

## Strings and symbols
function gap_to_julia(::Type{String},obj::MPtr)
function gap_to_julia(::Type{String},obj::GapObj)
if ! Globals.IsStringRep(obj)
throw(ArgumentError("<obj> is not a string"))
end
return CSTR_STRING(obj)
end
gap_to_julia(::Type{AbstractString},obj::MPtr) = gap_to_julia(String,obj)
gap_to_julia(::Type{Symbol},obj::MPtr) = Symbol(gap_to_julia(String,obj))
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))

gap_to_julia(type_obj,obj,recursion_dict) = gap_to_julia(type_obj,obj)

## Convert GAP string to Array{UInt8,1}
function gap_to_julia( ::Type{Array{UInt8,1}}, obj :: MPtr )
function gap_to_julia( ::Type{Array{UInt8,1}}, obj :: GapObj )
## convert strings to uint8 lists, if requested
if Globals.IsStringRep( obj )
array = UNSAFE_CSTR_STRING( obj )
Expand All @@ -135,7 +135,7 @@ function gap_to_julia( ::Type{Array{UInt8,1}}, obj :: MPtr )
end

## Arrays
function gap_to_julia( ::Type{Array{Obj,1}}, obj :: MPtr , recursion_dict = IdDict() )
function gap_to_julia( ::Type{Array{Obj,1}}, obj :: GapObj , recursion_dict = IdDict() )
if ! Globals.IsList( obj )
throw(ArgumentError("<obj> is not a list"))
end
Expand All @@ -157,7 +157,7 @@ function gap_to_julia( ::Type{Array{Obj,1}}, obj :: MPtr , recursion_dict = IdDi
return new_array
end

function gap_to_julia( ::Type{Array{T,1}}, obj :: MPtr, recursion_dict = IdDict() ) where T
function gap_to_julia( ::Type{Array{T,1}}, obj :: GapObj, recursion_dict = IdDict() ) where T
if ! Globals.IsList( obj )
throw(ArgumentError("<obj> is not a list"))
end
Expand All @@ -180,7 +180,7 @@ function gap_to_julia( ::Type{Array{T,1}}, obj :: MPtr, recursion_dict = IdDict(
end

## Special case for conversion of lists with holes; these are converted into 'nothing'
function gap_to_julia( ::Type{Array{Union{Nothing,T},1}}, obj :: MPtr, recursion_dict = IdDict() ) where T
function gap_to_julia( ::Type{Array{Union{Nothing,T},1}}, obj :: GapObj, recursion_dict = IdDict() ) where T
if ! Globals.IsList( obj )
throw(ArgumentError("<obj> is not a list"))
end
Expand All @@ -202,7 +202,7 @@ function gap_to_julia( ::Type{Array{Union{Nothing,T},1}}, obj :: MPtr, recursion
return new_array
end

function gap_to_julia( ::Type{Array{T,2}}, obj :: MPtr, recursion_dict = IdDict() ) where T
function gap_to_julia( ::Type{Array{T,2}}, obj :: GapObj, recursion_dict = IdDict() ) where T
if ! Globals.IsList( obj )
throw(ArgumentError("<obj> is not a list"))
end
Expand All @@ -227,7 +227,7 @@ function gap_to_julia( ::Type{Array{T,2}}, obj :: MPtr, recursion_dict = IdDict(
return new_array
end

function gap_to_julia( ::Type{Array{Union{Nothing,T},2}}, obj :: MPtr, recursion_dict = IdDict() ) where T
function gap_to_julia( ::Type{Array{Union{Nothing,T},2}}, obj :: GapObj, recursion_dict = IdDict() ) where T
if ! Globals.IsList( obj )
throw(ArgumentError("<obj> is not a list"))
end
Expand All @@ -253,7 +253,7 @@ function gap_to_julia( ::Type{Array{Union{Nothing,T},2}}, obj :: MPtr, recursion
end

## Tuples
function gap_to_julia( ::Type{T}, obj::MPtr, recursion_dict = IdDict() ) where T <: Tuple
function gap_to_julia( ::Type{T}, obj::GapObj, recursion_dict = IdDict() ) where T <: Tuple
if ! Globals.IsList(obj)
throw(ArgumentError("<obj> is not a list"))
end
Expand All @@ -267,7 +267,7 @@ function gap_to_julia( ::Type{T}, obj::MPtr, recursion_dict = IdDict() ) where T
end

## Dictionaries
function gap_to_julia( ::Type{Dict{Symbol,T}}, obj :: MPtr, recursion_dict = IdDict() ) where T
function gap_to_julia( ::Type{Dict{Symbol,T}}, obj :: GapObj, recursion_dict = IdDict() ) where T
if ! Globals.IsRecord( obj )
throw(ArgumentError("first argument is not a record"))
end
Expand Down Expand Up @@ -297,7 +297,7 @@ end

gap_to_julia(x::Any) = x

function gap_to_julia(x::MPtr)
function gap_to_julia(x::GapObj)
if Globals.IsInt(x)
return gap_to_julia(BigInt,x)
elseif Globals.IsRat(x)
Expand Down
File renamed without changes.
File renamed without changes.

0 comments on commit 7e4cfd1

Please sign in to comment.