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

Extend parsing of documentation #150

Merged
merged 38 commits into from
May 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
3bb8908
Update parser to handle more files
Joel-Dahne Mar 24, 2022
04f3439
Reparse Arb documentation on tag 2.22.0
Joel-Dahne Mar 25, 2022
472504d
add support for fpwrap module
kalmarek Mar 25, 2022
9d93723
add flag=0 to automatic kwargs in arbcall
kalmarek Mar 25, 2022
e84cabd
formatting
kalmarek Mar 25, 2022
5319f67
Add special parsing for fpwrap methods (WIP)
Joel-Dahne Mar 26, 2022
7f168a7
Mover parsing to ArbCall submodule
Joel-Dahne Mar 27, 2022
5118328
ArbCall: Cleanup Carg code
Joel-Dahne Apr 3, 2022
450e513
ArbCall: Add some documentation to ArbArgTypes
Joel-Dahne Apr 3, 2022
40a74ec
ArbCall: Restructure tests
Joel-Dahne Apr 5, 2022
b50b2f0
ArbCall: Fix jltype
Joel-Dahne Apr 5, 2022
2450650
ArbCall: Move handling of keyword arguments to Carg
Joel-Dahne Apr 7, 2022
c8f615a
ArbCall: Add arbsignature method for Carg
Joel-Dahne Apr 9, 2022
f68a966
ArbCall: Rename Arbfunction to ArbFunction
Joel-Dahne Apr 9, 2022
7776ec1
ArbCall: Update arbsignature(::ArbFunction)
Joel-Dahne Apr 9, 2022
f8a5832
ArbCall: Extract jlfname prefixes and suffixes
Joel-Dahne Apr 9, 2022
173aabc
ArbCall: Rename type parameter for ArbFunction
Joel-Dahne Apr 9, 2022
b49b51e
ArbCall: Reorganise ArbFunction file
Joel-Dahne Apr 10, 2022
3a09b2c
ArbCall: Rename ArbFPWrapfunction to ArbFPwrapFunction
Joel-Dahne Apr 10, 2022
e1a7dd2
ArbCall: Minor formatting changes to ArbFunction
Joel-Dahne Apr 12, 2022
9a4917b
ArbCall: Updates to ArbFPWrapFunction
Joel-Dahne Apr 15, 2022
b9f6bb6
ArbCall.ArbFPWrapFunction: Add support for multiple return values
Joel-Dahne Apr 17, 2022
b920a19
ArbCall: Fix not importing @arbfpwrapcall_str
Joel-Dahne Apr 17, 2022
0d86d4d
ArbCall: Update parsing and add tests for it
Joel-Dahne Apr 18, 2022
62aef9a
Formatting
Joel-Dahne Apr 18, 2022
7d2efb1
ArbCall: Remove unused methods for ArbFPWrapFunction
Joel-Dahne Apr 19, 2022
dcbfd0c
ArbCall: Reformat ispredicate(af::ArbFunction)
Joel-Dahne Apr 19, 2022
e85fc8f
ArbCall: Rewrite parsing using regex
Joel-Dahne Apr 19, 2022
702abf1
ArbCall: Add more tests
Joel-Dahne Apr 20, 2022
e0482f7
ArbCall: Update constructor for ArbArgTypes
Joel-Dahne Apr 20, 2022
ff173fc
ArbCall: Add more tests to ArbFPwrapFunction and fix failure
Joel-Dahne Apr 20, 2022
e00e7e9
Update JuliaFormatter to v0.22.10
Joel-Dahne May 3, 2022
a71fac2
ArbFPWrapFunction: Rename kwarg from safe to error_on_failure
Joel-Dahne May 3, 2022
a42dcc6
ArbArgTypes: Remove specialised constructor
Joel-Dahne May 3, 2022
923a423
ArbCall: Add method for setting error_on_failure for fpwrap methods
Joel-Dahne May 3, 2022
a0aa692
Remove formatting of non-existing parse directory
Joel-Dahne May 3, 2022
8340808
ArbFPWrapFunction: Add tests for error_on_failure
Joel-Dahne May 3, 2022
8ca4499
Bump to version 0.7.0
Joel-Dahne May 4, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/format.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ jobs:
- uses: actions/checkout@v2
- name: Install JuliaFormatter and format
run: |
julia -e 'using Pkg; Pkg.add(PackageSpec(name="JuliaFormatter", version="0.21.1"))'
julia -e 'using JuliaFormatter; format(["./src", "./test", "./parse"], verbose=true)'
julia -e 'using Pkg; Pkg.add(PackageSpec(name="JuliaFormatter", version="0.22.10"))'
julia -e 'using JuliaFormatter; format(["./src", "./test"], verbose=true)'
- name: Format check
run: |
julia -e '
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Arblib"
uuid = "fb37089c-8514-4489-9461-98f9c8763369"
authors = ["Marek Kaluba <kalmar@amu.edu.pl>", "Sascha Timme <Sascha Timme <timme@math.tu-berlin.de>", "Joel Dahne <joel@dahne.eu>"]
version = "0.6.4"
version = "0.7.0"

[deps]
Arb_jll = "d9960996-1013-53c9-9ba4-74a4155039c3"
Expand Down
84 changes: 84 additions & 0 deletions src/ArbCall/ArbArgTypes.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
struct UnsupportedArgumentType <: Exception
key::String
end

"""
ArbArgTypes(supported, unsupported, supported_reversed)

Struct for conversion between C argument types in the Arb
documentation and Julia types.
"""
struct ArbArgTypes
supported::Dict{String,DataType}
unsupported::Set{String}
supported_reversed::Dict{DataType,String}
end

function Base.getindex(arbargtypes::ArbArgTypes, key::AbstractString)
haskey(arbargtypes.supported, key) && return arbargtypes.supported[key]
key in arbargtypes.unsupported && throw(UnsupportedArgumentType(key))
throw(KeyError(key))
end

# Define the conversions we use for the rest of the code
const arbargtypes = ArbArgTypes(
Dict{String,DataType}(
"void" => Cvoid,
"void *" => Ptr{Cvoid},
"int" => Cint,
"slong" => Int,
"ulong" => UInt,
"double" => Cdouble,
"double *" => Vector{Float64},
"complex_double" => ComplexF64,
"complex_double *" => Vector{ComplexF64},
"arf_t" => Arf,
"arb_t" => Arb,
"acb_t" => Acb,
"mag_t" => Mag,
"arb_srcptr" => ArbVector,
"arb_ptr" => ArbVector,
"acb_srcptr" => AcbVector,
"acb_ptr" => AcbVector,
"arb_poly_t" => ArbPoly,
"acb_poly_t" => AcbPoly,
"arb_mat_t" => ArbMatrix,
"acb_mat_t" => AcbMatrix,
"arf_rnd_t" => arb_rnd,
"mpfr_t" => BigFloat,
"mpfr_rnd_t" => Base.MPFR.MPFRRoundingMode,
"mpz_t" => BigInt,
"char *" => Cstring,
"slong *" => Vector{Int},
"ulong *" => Vector{UInt},
),
Set(["FILE *", "fmpr_t", "fmpr_rnd_t", "flint_rand_t", "bool_mat_t"]),
Dict{DataType,String}(
Cvoid => "void",
Ptr{Cvoid} => "void *",
Cint => "int",
Int => "slong",
UInt => "ulong",
Cdouble => "double",
Vector{Float64} => "double *",
ComplexF64 => "complex_double",
Vector{ComplexF64} => "complex_double *",
Arf => "arf_t",
Arb => "arb_t",
Acb => "acb_t",
Mag => "mag_t",
ArbVector => "arb_ptr",
AcbVector => "acb_ptr",
ArbPoly => "arb_poly_t",
AcbPoly => "acb_poly_t",
ArbMatrix => "arb_mat_t",
AcbMatrix => "acb_mat_t",
arb_rnd => "arf_rnd_t",
BigFloat => "mpfr_t",
Base.MPFR.MPFRRoundingMode => "mpfr_rnd_t",
BigInt => "mpz_t",
Cstring => "char *",
Vector{Int} => "slong *",
Vector{UInt} => "ulong *",
),
)
37 changes: 37 additions & 0 deletions src/ArbCall/ArbCall.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module ArbCall

using ..Arblib

import ..Arblib:
cstructtype,
arb_rnd,
mag_struct,
arf_struct,
arb_struct,
acb_struct,
arb_vec_struct,
acb_vec_struct,
arb_poly_struct,
acb_poly_struct,
arb_mat_struct,
acb_mat_struct,
MagLike,
ArfLike,
ArbLike,
AcbLike,
ArbVectorLike,
AcbVectorLike,
ArbMatrixLike,
AcbMatrixLike,
ArbPolyLike,
AcbPolyLike,
ArbTypes

include("ArbArgTypes.jl")
include("Carg.jl")
include("ArbFunction.jl")
include("ArbFPWrapFunction.jl")

include("parse.jl")

end
177 changes: 177 additions & 0 deletions src/ArbCall/ArbFPWrapFunction.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
"""
ArbFPWrapFunction{T}(fname, args)
ArbFPWrapFunction(str)

Struct representing an Arb function from the `arb_fpwrap.h` module.
"""
struct ArbFPWrapFunction{T<:Union{Float64,ComplexF64}}
fname::String
args::Vector{Carg}
end

function ArbFPWrapFunction(str::AbstractString)
m = match(r"(?<returnflag>\w+(\s\*)?)\s+(?<arbfunction>[\w_]+)\((?<args>.*)\)", str)
isnothing(m) &&
throw(ArgumentError("string doesn't match arblib function signature pattern"))

# Check that it has the correct return type
m[:returnflag] == "int" ||
throw(ArgumentError("expected function to return int, got $(m[:returnflag])"))

# Determine if it returns double or cdouble
type_str = split(m[:arbfunction], "_", limit = 4)[3]
if type_str == "double"
T = Float64
elseif type_str == "cdouble"
T = ComplexF64
else
throw(ArgumentError("type is not double or cdouble, got $type_str"))
end

args = Carg.(strip.(split(m[:args], ",")))

# Check that at least the first argument is a result argument
is_fpwrap_res_argument(first(args), T) || throw(
ArgumentError(
"expected first argument to be a result argument, got $(first(args))",
),
)

return ArbFPWrapFunction{T}(m[:arbfunction], args)
end

basetype(::ArbFPWrapFunction{T}) where {T} = T
arbfname(af::ArbFPWrapFunction) = af.fname
arguments(af::ArbFPWrapFunction) = af.args

function count_res_arguments(af::ArbFPWrapFunction{T}) where {T}
i = findfirst(ca -> !is_fpwrap_res_argument(ca, T), arguments(af))
return i - 1
end

function returntype(af::ArbFPWrapFunction{T}) where {T}
n = count_res_arguments(af)
if n == 1
return basetype(af)
else
return NTuple{n,basetype(af)}
end
end

function arbsignature(af::ArbFPWrapFunction)
c_args = join(arbsignature.(arguments(af)), ", ")

return "int $(arbfname(af))($c_args)"
end

jlfname(af::ArbFPWrapFunction) = Symbol(:fpwrap_, split(arbfname(af), "_", limit = 4)[4])

# See https://github.com/kalmarek/Arblib.jl/issues/138 for some
# discussions related to this approach for default arguments
"""
fpwrap_error_on_failure_default()

Function giving the default value for the argument `error_on_failure`.
See also [`fpwrap_error_on_failure_default_set`](@ref).
"""
fpwrap_error_on_failure_default() = false

"""
fpwrap_error_on_failure_default_set(value::Bool)

Set the default value for the argument `error_on_failure` for `fpwrap`
methods. See also [`fpwrap_error_on_failure_default`](@ref).
"""
function fpwrap_error_on_failure_default_set(value::Bool)
if fpwrap_error_on_failure_default() != value
@eval fpwrap_error_on_failure_default() = $value
end
end

# TODO: Improve support for vector arguments
function jlargs(af::ArbFPWrapFunction)
cargs = arguments(af)

# Skip return arguments

# Count res arguments
n = count_res_arguments(af)
n >= 1 || throw(ArgumentError("expected at least one result argument"))
# last argument is flag, skip this
cargs[end] == Carg{Cint}(:flags, false) ||
throw(ArgumentError("expected last argument to be flags::Cint, got $(cargs[end])"))

args = [:($(name(carg))::$(jltype(carg))) for carg in cargs[n+1:end-1]]

if basetype(af) == Float64
kwargs = [
Expr(
:kw,
:(error_on_failure::Bool),
:(Arblib.ArbCall.fpwrap_error_on_failure_default()),
),
Expr(:kw, :(correct_rounding::Bool), :(false)),
Expr(:kw, :(work_limit::Integer), :(8)),
]
else
kwargs = [
Expr(
:kw,
:(error_on_failure::Bool),
:(Arblib.ArbCall.fpwrap_error_on_failure_default()),
),
Expr(:kw, :(accurate_parts::Bool), :(false)),
Expr(:kw, :(correct_rounding::Bool), :(false)),
Expr(:kw, :(work_limit::Integer), :(8)),
]
end

return args, kwargs
end

function jlcode(af::ArbFPWrapFunction, jl_fname = jlfname(af))
T = basetype(af)
cargs = arguments(af)
n = count_res_arguments(af)
jl_args, jl_kwargs = jlargs(af)

return_variables = Expr(:block, [:($(name(ca)) = Ref{$T}()) for ca in cargs[1:n]]...)
if n == 1
return_expr = :($(name(cargs[1]))[])
else
return_expr = Expr(:tuple, [:($(name(ca))[]) for ca in cargs[1:n]]...)
end

func = :(
function $jl_fname($(jl_args...); $(jl_kwargs...))
$return_variables

# Set accurate_parts if it is not included as a kwarg
$(ifelse(T == Float64, :(accurate_parts = false), :nothing))

flags::Cint = accurate_parts + correct_rounding * 2 + work_limit * 65536

return_flag = ccall(
Arblib.@libarb($(arbfname(af))),
Cint,
$(Expr(:tuple, ctype.(cargs)...)),
$(name.(cargs)...),
)

if iszero(return_flag) || !error_on_failure
return $return_expr
elseif isone(return_flag)
error("unable to evaluate accurately")
else
error("unknown return flag $return_flag")
end
end
)

return func
end

macro arbfpwrapcall_str(str)
af = ArbFPWrapFunction(str)
return esc(jlcode(af))
end