Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: toivoh/julia-pattern-dispatch
base: f00b7cdbe0
...
head fork: toivoh/julia-pattern-dispatch
compare: b238ad36b2
  • 4 commits
  • 6 files changed
  • 0 commit comments
  • 1 contributor
View
8 dev/patterns.jl
@@ -1,4 +1,7 @@
+load("utils/req.jl")
+req("utils/utils.jl")
+
# -- Atoms --------------------------------------------------------------------
# provisional atom definition
@@ -25,9 +28,10 @@ is_container(x) = is_containertype(typeof(x))
get_containertype{T}(::Type{T}) = error("not a container type: ", T)
get_containertype(x) = get_containertype(typeof(x))
+isequal_type(S,T) = (S <: T)&&(T <: S) # todo: better way to implement this?
function isequiv_containers(x,y)
- (is(get_containertype(x),get_containertype(y)) &&
- isequal(container_shape(x),container_shape(y)))
+ (isequal_type(get_containertype(x),get_containertype(y)) &&
+ isequal(container_shape(x),container_shape(y)))
end
map_container(f) = error("need at least one container to know container type!")
View
91 dev/pdispatch.jl
@@ -57,3 +57,94 @@ function code_patmethod(fdef)
# evaluates the pattern expression inline
:( patmethod(($pattern_ex), ($quotevalue(body))) )
end
+
+
+# -- @pattern -----------------------------------------------------------------
+
+type PatternMethodTable
+ fname::Symbol
+ methods::Vector{PatternMethod}
+
+ PatternMethodTable(fname::Symbol) = new(fname, PatternMethod[])
+end
+
+#add(mt::PatternMethodTable, m::PatternMethod) = push(mt.methods, m)
+function add(mt::PatternMethodTable, m::PatternMethod)
+ ms = mt.methods
+ n = length(ms)
+
+ # insert the pattern in ascending topological order, as late as possible
+ i = n+1
+ for k=1:n
+ if pattern_le(m.pattern, ms[k].pattern)
+ if pattern_ge(m.pattern, ms[k].pattern)
+ # equal signature ==> replace
+ mt.methods[k] = m
+ return
+ else
+ i = k
+ break
+ end
+ end
+ end
+
+ ms = mt.methods = PatternMethod[ms[1:i-1]..., m, ms[i:n]...]
+
+ # warn if new signature is ambiguous with an old one
+ for m0 in ms
+ lb, s = unify(m0.pattern, m.pattern)
+ if !(is(lb,nonematch) || any({pattern_eq(lb,mk.pattern) for mk in ms}))
+ # todo:
+ # o disambiguate pvars in lb (might have same name)
+ # o print x::Int instead of pvar(x,Int)?
+ println("Warning: New @pattern method ", mt.fname, m.pattern)
+ println(" is ambiguous with ", mt.fname, m0.pattern)
+ println(" Make sure ", mt.fname, lb, " is defined first")
+ end
+ end
+
+ nothing
+end
+
+
+function dispatch(mt::PatternMethodTable, args::Tuple)
+ for m in mt.methods
+ matched, result = m.dispfun(args...)
+ if matched; return result; end
+ end
+ error("no dispatch found for pattern function $(m.fname)$args")
+end
+
+
+const __patmethod_tables = Dict{Function,PatternMethodTable}()
+
+macro pattern(fdef)
+ code_pattern_fdef(fdef)
+end
+function code_pattern_fdef(fdef)
+ method_ex = code_patmethod(fdef)
+
+ signature, body = split_fdef(fdef)
+ fname = signature.args[1]
+ qfname = quotevalue(fname)
+ @gensym fun mtable
+ quote
+ ($fun) = nothing
+ try
+ ($fun) = ($fname)
+ end
+ if is(($fun), nothing)
+ ($mtable) = PatternMethodTable($qfname)
+# const ($fname) = create_pattern_function(($mtable))
+ const ($fname) = (args...)->dispatch(($mtable), args)
+ __patmethod_tables[$fname] = ($mtable)
+ else
+ if !(isa(($fun),Function) && has(__patmethod_tables, ($fun)))
+ error("\nin @pattern method definition: ", ($string(fname)),
+ " is not a pattern function")
+ end
+ ($mtable) = __patmethod_tables[$fun]
+ end
+ add(($mtable), ($method_ex))
+ end
+end
View
51 dev/test/test_ambiguity_warning.jl
@@ -0,0 +1,51 @@
+
+load("utils/req.jl")
+load("pdispatch.jl")
+
+## should work ##
+
+# # right order: shouldn't give a warning
+# @pattern r(x::Int,y::Int) = 1
+# @pattern r(x::Int,y) = 2
+# @pattern r(x,y::Int) = 3
+
+# no finite unification ==> ok
+@pattern r2(x,{1,x}) = 2
+@pattern r2(y,y) = 3
+
+@pattern r3({x,y},{z,w}) = 1
+@pattern r3(x,{y,z}) = 2
+@pattern r3({x,y},z) = 3
+
+@pattern r4(1)=1
+@pattern r4(x)=x
+
+@pattern r5(x)=x
+@pattern r5(1)=1
+
+# @pattern r4(1,x,y::Int) = 2
+# @pattern r4(2,x::Int,y) = 3
+
+#@pattern r5(x::None, y) = 2 # never matches ==> error
+#@pattern r5(x, y::Int) = 3
+
+## should warn ##
+
+# # should warn about g(::Int,::Int)
+# @pattern f1(x::Int,y) = 2
+# @pattern f1(x,y::Int) = 3
+
+@pattern f2({1,x},y) = 2
+@pattern f2(z,{2,w}) = 3
+
+# @pattern f3(x::Union(Int,String)) = 2
+# @pattern f3(x::Real) = 3
+
+@pattern f4(x,2) = x
+@pattern f4(1,y) = y
+
+@pattern f6(y,{x,x},{y,y}) = 2
+@pattern f6(y,y,z) = 3
+
+@pattern f7(x,y,1,x,y) = 2
+@pattern f7(x,y,x,y,1) = 3
View
26 dev/test/test_code_pmatch.jl
@@ -18,4 +18,28 @@ pprintln()
println()
@pshowln code_pmatch((1, X), :args)
println()
-@pshowln code_pmatch({1, X}, :args)
+@pshowln code_pmatch({1, X}, :args)
+
+
+function show_code_pmatch(p,vars::PVar...)
+ println()
+ println("pattern = ", p)
+
+ c = PMContext()
+ code_pmatch(c, p,:x)
+ println("vars = ", c.assigned_vars)
+# println("code:")
+# foreach(x->println("\t", x), c.code)
+ pprintln(expr(:block, c.code))
+end
+
+#@pvar X, Xi::Int
+X = pvar(:X)
+
+show_code_pmatch(1)
+show_code_pmatch(X, X)
+#show_code_pmatch(Xi, Xi)
+show_code_pmatch((1,X), X)
+show_code_pmatch((X,X), X)
+
+
View
36 dev/test/test_pdisp.jl
@@ -0,0 +1,36 @@
+
+load("utils/req.jl")
+load("pdispatch.jl")
+
+mtable = PatternMethodTable(:f)
+add(mtable, (@patmethod f(1) = 42))
+add(mtable, (@patmethod f(x) = x))
+
+f = (args...)->(dispatch(mtable, args))
+
+println()
+@show f(0)
+@show f(1)
+@show f(2)
+@show f(3)
+
+@pattern ff(x) = x
+@pattern ff(1) = 42
+
+println()
+@show ff(0)
+@show ff(1)
+@show ff(2)
+@show ff(3)
+
+
+println("(g=1;@pattern g(x)=1) throws: ", @assert_fails begin
+ g = 1
+ @pattern g(x)=1
+end)
+
+println("(h(x)=x;@pattern h(x)=1) throws: ", @assert_fails begin
+ h(x)=x
+ @pattern h(x)=1
+end)
+
View
41 dev/test/test_unify_vectors.jl
@@ -0,0 +1,41 @@
+
+load("utils/req.jl")
+req("pmatch.jl")
+req("utils/utils.jl")
+
+let
+ X, Y, Z = map(pvar, (:X, :Y, :Z))
+
+ @symshowln unify(X, {1,2})
+ @symshowln unify({X,2}, {1,2})
+ @symshowln unify({X,1}, {1,2})
+ @symshowln unify({1,X}, {1,2})
+ @symshowln unify({1,X}, {Y,2})
+ @symshowln unify({1,X}, {1,2,3})
+ @symshowln unify({1,X,Y}, {1,2,3})
+ @symshowln unify({1,X}, {1,{2,3}})
+
+ println()
+ @symshowln unify({1,X}, {X,Y})
+ @symshowln unify({1,X,Y}, {X,Y,Z})
+ @symshowln unify({1,X,Y}, {X,Y,1})
+ @symshowln unify({1,X,Y}, {X,Y,2})
+ @symshowln unify({1,Y,X}, {X,Z,Y})
+ @symshowln unify(X, {1,X})
+
+# println()
+# @pvar Xi::Int, Xa::Array, Xv::Vector, Xm::Matrix
+# @symshowln unify(Xi, {1,2})
+# @symshowln unify(Xa, {1,2})
+# @symshowln unify(Xv, {1,2})
+# @symshowln unify(Xm, {1,2})
+
+# println()
+# @pvar Xai::Array{Int}
+# @symshowln unify(Xai, {1,2})
+# @symshowln unify(Xai, [1,2])
+# @symshowln unify(Xa, [1,2,X])
+
+# # consider: Should this work? And force X to be an Int.
+# @symshowln unify(Xai, [1,2,X])
+end

No commit comments for this range

Something went wrong with that request. Please try again.