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

WIP: Get fieldtypes from defaults #138

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
37 changes: 30 additions & 7 deletions src/Parameters.jl
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@ function _pack_new(T, fields)
Expr(:call, T, fields...)
end

const macro_hidden_nargs = length(:(@m).args) - 1 # ==1 on Julia 0.6, ==2 on Julia 0.7
"The symbol to use to indicate that `typeof(default_value)` is used."
const TYPEOF=:typeof

"""
This function is called by the `@with_kw` macro and does the syntax
Expand Down Expand Up @@ -341,10 +342,10 @@ function with_kw(typedef, mod::Module, withshow=true)
l, i = next(lns, start(lns))
if l isa Expr && l.head == :macrocall && l.args[1] == Symbol("@deftype")
has_deftyp = true
if length(l.args) != (2 + macro_hidden_nargs)
if length(l.args) != 3
error("Malformed `@deftype` line $l")
end
deftyp = l.args[2 + macro_hidden_nargs]
deftyp = l.args[3]
if done(lns, i)
error("@with_kw only supported for types which have at least one field.")
end
Expand Down Expand Up @@ -385,7 +386,7 @@ function with_kw(typedef, mod::Module, withshow=true)
unpack_vars = Any[]
# the type def
fielddefs = quote end # holds r::R etc
fielddefs.args = Any[] # in julia 0.5 this is [:( # /home/mauro/.julia/v0.5/Parameters/src/Parameters.jl, line 228:)]
fielddefs.args = Any[]
kws = OrderedDict{Any, Any}()
# assertions in the body
asserts = Any[]
Expand All @@ -395,7 +396,7 @@ function with_kw(typedef, mod::Module, withshow=true)
continue
end
if l isa Symbol # no default value and no type annotation
if has_deftyp
if has_deftyp && deftyp!=TYPEOF # doesn't work to do ::typeof(default_value) here
push!(fielddefs.args, :($l::$deftyp))
else
push!(fielddefs.args, l)
Expand All @@ -407,16 +408,22 @@ function with_kw(typedef, mod::Module, withshow=true)
push!(unpack_vars, sym)
elseif l isa String # doc-string
push!(fielddefs.args, l)
elseif l.head==:(=) # default value and with or without type annotation
elseif l.head==:(=)
if l.args[1] isa Expr && (l.args[1].head==:call || # inner constructor
l.args[1].head==:where && l.args[1].args[1].head==:call) # inner constructor with `where`
check_inner_constructor(l)
push!(inner_constructors, l)
else
else # default value and with or without type annotation
fld = l.args[1]
if fld isa Symbol && has_deftyp # no type annotation
fld = :($fld::$deftyp)
end
# process TYPEOF
if !(fld isa Symbol) && fld.args[2]==TYPEOF
# replace with typeof(default_value)
fld.args[2] = :(typeof($(l.args[2])))
end

# add field doc-strings
docstring = string("Default: ", l.args[2])
if i > 1 && lns[i-1] isa String
Expand All @@ -426,6 +433,7 @@ function with_kw(typedef, mod::Module, withshow=true)
# otherwise add a new line
push!(fielddefs.args, docstring)
end
# add to output
push!(fielddefs.args, fld)
kws[decolon2(fld)] = l.args[2]
# unwrap-macro
Expand All @@ -440,6 +448,7 @@ function with_kw(typedef, mod::Module, withshow=true)
elseif l.head==:block
error("No nested begin-end allowed in type defintion")
else # no default value but with type annotation
l.args[2]==TYPEOF && error("Cannot infer type from default if there is no default.")
push!(fielddefs.args, l)
sym = decolon2(l.args[1])
syms = string(sym)
Expand Down Expand Up @@ -523,6 +532,20 @@ function with_kw(typedef, mod::Module, withshow=true)
# constructors are to allow both calls:
# `MT4(r=4, a=5.0)` (outer kwarg-constructor) and
# `MT4{Float32, Int}(r=4, a=5.)` (inner kwarg constructor).
#
# NOTE to above NOTE: this is probably not the case (anymore?),
# as Base.@kwdef does not define inner constructors:
# julia> Base.@kwdef struct MT4_{R,I}
# r::R=5
# a::I
# end
#
# julia> MT4_(r=4, a=5.0)
# MT4_{Int64,Float64}(4, 5.0)
#
# julia> MT4_{Float32, Int}(r=4, a=5.)
# MT4_{Float32,Int64}(4.0f0, 5)


## outer copy constructor
###
Expand Down