Skip to content
This repository was archived by the owner on Feb 7, 2019. It is now read-only.

Commit 943a3a2

Browse files
committed
refactored tratidef.jl
1 parent e962317 commit 943a3a2

File tree

3 files changed

+84
-49
lines changed

3 files changed

+84
-49
lines changed

src/Traits.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ function istrait{T<:Trait}(Tr::Type{T}; verbose=false)
113113
if isa(meth, Function)
114114
if !method_exists(meth, sigg) # I think this does the right thing.
115115
if verbose
116-
println("Method $meth with signature $sig not defined for $T")
116+
println("Method $meth with call signature $(sig[1]) not defined for $T")
117117
end
118118
out = false
119119
end

src/traitdef.jl

+72-46
Original file line numberDiff line numberDiff line change
@@ -91,59 +91,20 @@ function parsebody(body::Expr)
9191
# :([f1 => ((X,Y), (Int,Int)),
9292
# f2 => ((Y,), (X,)) ] )
9393
# :(Bool[X==Y])
94+
isassoc(ex::Expr) = ex.head==:(=) # associated types
95+
isconstraints(ex::Expr) = ex.head==:macrocall # constraints
96+
9497
outfns = Expr(:dict)
9598
constr = :(Bool[])
9699
assoc = quote end
97100
for ln in Lines(body)
98-
if ln.head==:macrocall # constraints
101+
if isconstraints(ln)
99102
parseconstraints!(constr, ln)
100-
elseif ln.head==:(=) # associated types
103+
elseif isassoc(ln)
101104
push!(assoc.args, ln)
102-
else
103-
argtype = :()
104-
rettype = :()
105-
106-
if ln.head==:tuple
107-
# several ret-types:
108-
# f1(X,Y) -> x,y
109-
append!(rettype.args, ln.args[2:end])
110-
ln = ln.args[1]
111-
end
112-
113-
if ln.head==:(->)
114-
# f1(X,Y) -> x
115-
fn = ln.args[1].args[1]
116-
append!(argtype.args, ln.args[1].args[2:end])
117-
tmp = rettype
118-
rettype = :()
119-
push!(rettype.args, ln.args[2].args[2])
120-
append!(rettype.args, tmp.args)
121-
elseif ln.head==:call
122-
# f1(X,Y) or X + Y -> Z
123-
if isa(ln.args[end], Expr) && ln.args[end].head==:(->) # X + Y -> Z
124-
fn = ln.args[1]
125-
append!(argtype.args, ln.args[2:end-1])
126-
if isa(ln.args[end].args[1], Expr)
127-
append!(argtype.args, ln.args[end].args[1].args)
128-
else
129-
push!(argtype.args, ln.args[end].args[1])
130-
end
131-
tmp = rettype
132-
rettype = :()
133-
push!(rettype.args, ln.args[end].args[2].args[2])
134-
append!(rettype.args, tmp.args)
135-
else # f1(X,Y)
136-
fn = ln.args[1]
137-
append!(argtype.args, ln.args[2:end])
138-
rettype = :((Any...))
139-
end
140-
else
141-
throw(TraitException(
142-
"Something went wrong parsing the trait definition body with line:\n$ln"))
143-
end
144-
push!(outfns.args, :($fn => ($argtype, $rettype)))
105+
else # the rest of the body are function signatures
106+
parsefnstypes!(outfns, ln)
145107
end
146-
147108
end
148109
# store associated types:
149110
tmp = :(TypeVar[])
@@ -170,6 +131,71 @@ function parseconstraints!(constr, block)
170131
end
171132
end
172133

134+
function parsefnstypes!(outfns, ln)
135+
function parsefn(def)
136+
# Parse to get function signature.
137+
# parses f(X,Y), f{X <:T}(X,Y) and X+Y
138+
if isa(def.args[1], Symbol)
139+
fn = def.args[1]
140+
elseif def.args[1].head==:curly
141+
fn = def.args[1].args[1]
142+
# todo
143+
else
144+
throw(TraitException(
145+
"Something went wrong parsing the trait definition body with line:\n$ln"))
146+
end
147+
argtype = :()
148+
append!(argtype.args, def.args[2:end])
149+
return fn, argtype # typvars
150+
end
151+
function parseret!(rettype, ln)
152+
# parse to get return types
153+
while ln.head!=:block
154+
ln = ln.args[end]
155+
end
156+
tmp = rettype.args
157+
rettype.args = Any[]
158+
push!(rettype.args, ln.args[end])
159+
append!(rettype.args, tmp)
160+
end
161+
162+
163+
rettype = :()
164+
if ln.head==:tuple
165+
# several ret-types:
166+
# f1(X,Y) -> X,Y
167+
append!(rettype.args, ln.args[2:end])
168+
ln = ln.args[1]
169+
end
170+
171+
if ln.head==:(->) # f1(X,Y) -> x
172+
parseret!(rettype, ln)
173+
fn, argtype = parsefn(ln.args[1])
174+
elseif ln.head==:call # either f1(X,Y) or X + Y -> Z
175+
if isa(ln.args[end], Expr) && ln.args[end].head==:(->) # X + Y -> Z
176+
def = Expr(:call)
177+
append!(def.args, ln.args[1:end-1])
178+
if length(ln.args)==2
179+
append!(def.args, ln.args[end].args[1].args)
180+
else
181+
push!(def.args, ln.args[end].args[1])
182+
end
183+
parseret!(rettype, ln)
184+
else # f1(X,Y)
185+
def = ln
186+
rettype = :((Any...))
187+
end
188+
fn, argtype = parsefn(def)
189+
else
190+
throw(TraitException(
191+
"Something went wrong parsing the trait definition body with line:\n$ln"))
192+
end
193+
# replace types with constraints by TypeVars
194+
#...
195+
196+
push!(outfns.args, :($fn => ($argtype, $rettype)))
197+
end
198+
173199
# 3) piece it together
174200
###
175201

test/traitdef.jl

+11-2
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,32 @@ a,b = Traits.parsebody(td1.args[end])
3030

3131
td2 = :(@traitdef Cr20{X,Y} begin
3232
X + Y -> Int,Float64
33+
-(X,Y) -> Int
34+
(/)(X,Y) -> Int
3335

3436
@constraints begin
3537
string(X.name)[1]=='I'
3638
end
3739
end)
3840
a,b,c = Traits.parsebody(td2.args[end])
39-
@test a==Expr(:dict, :((+) => ((X,Y),(Int,Float64))))
41+
@test a==Expr(:dict, :((+) => ((X,Y),(Int,Float64))),
42+
:((-) => ((X,Y),(Int,))),
43+
:((/) => ((X,Y),(Int,))))
4044
@test b==:(Bool[(string(X.name))[1] == 'I'])
4145
@test c.head==:block
4246

47+
td3 = :(@traitdef Cr20{X,Y} begin
48+
fn(X) -> Type{X}
49+
end)
50+
a,b,c = Traits.parsebody(td3.args[end])
51+
@test a==Expr(:dict, :((fn) => ((X,),(Type{X},))))
52+
4353
## test making traits
4454

4555
@traitdef MyIter{X} begin
4656
start(X)
4757
end
4858

49-
5059
## Testing trait definitions
5160
@test istrait(Cmp{Int,Int})
5261
@test istrait(Cmp{Int,Float64})

0 commit comments

Comments
 (0)