Skip to content

Instantly share code, notes, and snippets.

@inkydragon
Last active May 1, 2019 10:39
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save inkydragon/0787b44eb41461c3e6c5898f6042a2dd to your computer and use it in GitHub Desktop.
Save inkydragon/0787b44eb41461c3e6c5898f6042a2dd to your computer and use it in GitHub Desktop.
patch for `MLStyle.jl`
# test driven development
# TestSet for `@when` + `@otherwise`
using MLStyle
using Test
using Random
#=
Test help macro/functions
=#
## PPAP
# I have a macro
# I have a @test_throws
# Eh~
# LoadError!
# no more LoadError! Get the real error.
macro test_macro_throws(errortype, m)
:(
@test_throws $errortype try
@eval $m
catch err
while err isa LoadError
err = err.error
end
throw(err)
end
)
end
function genRandVal(;
hasInt::Bool=true,
hasBool::Bool=true,
hasFloat::Bool=true,
hasNumber::Bool=true,
hasString::Bool=true,
hasSymbol::Bool=true
)
if hasNumber; hasInt = hasFloat = true; end
rnd = []
if hasInt; push!(rnd, rand(Int)); end
if hasBool; push!(rnd, bitrand()[1]); end
if hasFloat; push!(rnd, rand()); end
if hasString; push!(rnd, randstring()); end
if hasSymbol; push!(rnd, randstring('a':'z') |> Symbol); end
shuffle(rnd)[1]
end
macro rand_test_eq(f, times)
# TODO
end
#=
TestSet
=#
@testset "@when" begin
@testset "Only @when" begin
@test 2 == @when let (a, 1) = (2, 1)
a
end
# @match (2, 1) begin
# (a, 1) => a
# _ => nothing
# end
# for more test, see `test\when.jl`
end
@testset "@when in @when" begin
function f1(args)
x = Tuple(args)
@when (a, 1) = x begin
a
@when (b, 2)
(2, b)
end
# @match x begin
# (a, 1) => a
# (b, 2) => (2, b)
# _ => nothing
# end
end
# case: a
@test f1(111, 1) == 111
@test f1(222, 1) == 222
# case: (2, b)
@test f1(111, 2) == (2, 111)
@test f1(222, 2) == (2, 222)
function f2(args)
x = Tuple(args)
@when (a, 1) = x begin
a
@when (b, 2)
(:b, b)
@when (c, 3)
(:c, c)
end
# @match x begin
# (a, 1) => a
# (b, 2) => (:b, b)
# (c, 3) => (:c, c)
# _ => nothing
# end
end
@test f2(10, 1) == 10 # case: a
@test f2(20, 2) == (:b, 20) # case: (:b, b)
@test f2(30, 3) == (:c, 30) # case: (:c, c)
end
@testet "@when + @otherwise" begin
function f1(args)
x = Tuple(args)
@when (a, 1) = x begin
a
@otherwise
x
end
# @match x begin
# (a, 1) => a
# _ => x
# end
end
@test f1(1) == (1, ) # case: x
@test f1(1, 2) == (1, 2)# case: x
@test f1(2, 1) == 2 # case: a
function f2(args)
x = Tuple(args)
@when (a, 1) = x begin
a
@when (b, 2)
(:b, b)
@when (c, 3)
(:c, c)
@otherwise
x
end
# @match x begin
# (a, 1) => a
# (b, 2) => (:b, b)
# (c, 3) => (:c, c)
# _ => x
# end
end
@test f2(1) == (1, ) # case: x
@test f2(1, 2) == (1, 2) # case: x
@test f2(10, 1) == 10 # case: a
@test f2(20, 2) == (:b, 20) # case: (:b, b)
@test f2(30, 3) == (:c, 30) # case: (:c, c)
end
@testet "@when + @otherwise with many bidings" begin
function f1(xy, z)
@when let (a, 1) = xy,
5 = z
a
@otherwise
0 # default value
end
# @match xy begin
# (a, 1) => begin
# @match z begin
# 5 => a
# _ => 0 # Always return the default value
# end
# end
# _ => 0 # Always return the default value
# end
end
@test f1((123, 1), 5) => 123 # case: a
@test f1((123, 3), 5) => 0 # not match `(a, 1) = xy`
@test f1((123, 1), 1) => 0 # not match `5 = z`
#=
TODO: Need discuss!!!!
In fact I would like to throw a syntax_err for the following situations.
=#
function f11(xy, z)
@when let (a, 3) = xy,
5 = z
a
@when (a, 4) # ambiguous!
4
@otherwise
0
end
# @syntax_err "Syntax is ambiguous!"
end
function f2(xy, z)
@when let (a, 3) = xy,
5 = z
a
@when (a, 4) = xy
4
@otherwise
0
end
# @match xy begin
# (a, 1) => begin
# @match z begin
# 5 => a
# _ =>
# @match xy begin
# (a, 4) => 4
# _ => 0
# end
# end
# end
# (a, 4) => 4
# _ => 0
# end
end
function f3(xy, z)
@when let (a, 3) = xy,
5 = z
a
@when 6 = z
6
@otherwise
0
end
# @match xy begin
# (a, 1) =>
# @match z begin
# 5 => a
# 6 => 6
# _ =>
# @match z begin
# 6 => 6
# _ => 0
# end
# end
# _ =>
# @match z begin
# 6 => 6
# _ => 0
# end
# end
end
function f23(xy, z)
@when let (a, 3) = xy,
5 = z
a
@when (a, 4) = xy
4
@when 6 = z
4
@otherwise
0
end
# Too complex...
end
function f32(xy, z)
@when let (a, 3) = xy,
5 = z
a
@when 6 = z
4
@when (a, 4) = xy
4
@otherwise
0
end
# Too complex...
end
end
#=
Test case
=#
x = (5, 2)
y = (6, 1)
# simple `@when`
syntax01 = :(# @when
let (a, 2) = x
a
end)
# syntax02 = :(@when (a, 2) = x begin a; end)
function m0(syntax)
@match syntax begin
Expr(:let, bd, ret) =>
@match bd begin
:($a = $b) =>
@format [a, b, ret] quote
@match b begin
a => ret
_ => nothing
end
end
a => :(let $a; $ret end)
end
_ => error("[m0] nothing matched")
end
end
res01 = :(
@match x begin
(a, 2) => a
_ => nothing
end)
# `@when` + `let`
syntax11 = :(# @when
let (a, 2) = x,
(b, 1) = y
a, b
end)
function m1(syntax)
@match syntax begin
Expr(:let, Expr(:block, bds...), ret) =>
foldr(bds, init=ret) do each, last
@match each begin
:($a = $b) =>
@format [a, b, last] quote
@match b begin
a => last
_ => nothing
end
end
a => :(let $a; $last end)
end
end
_ => error("[m1] nothing matched")
end
end
res11 = :(
@match x begin
(a, 2) => begin
@match y begin
(b, 1) => (a, b)
_ => nothing
end
end
_ => nothing
end)
# `@when` in `@when`
syntax21 = :(# @when
let (a, 2) = x
a, a, a
@when (b, 1) = x
b
end)
syntax22 = :(# @when
let (a, 1) = x
a
@when (b, 2) = x
b
@when (c, 3) = x
c
end)
function m2(syntax)
@match syntax begin
Expr(:let,
bd,
Expr(:block,
::LineNumberNode,
ret1 || Expr(:block, ret1),
::LineNumberNode,
Expr(:macrocall,
name,
::LineNumberNode,
Expr(:(=), case2, val2)
), ::LineNumberNode,
ret2 || Expr(:block, ret2)
)
) =>
# @show bd ret1 ret2 " "
@match bd begin
:($a = $b) => begin
@format [a, b, ret1, ret2, case2, val2] quote
@match b begin
a => ret1
case2 => val2
_ => nothing
end
end
end
a => :(let $a; $last end)
end
_ => error("[m3] nothing matched")
end
end
res21 = :(
@match x begin
(a, 2) => a
(b, 2) => b
_ => nothing
end)
res22 = :(
@match x begin
(a, 2) => a
(b, 2) => b
(c, 3) => c
_ => nothing
end)
# `@otherwise`
syntax31 = :(# @when
let (a, 2) = x
a
@otherwise
x
end)
function m3(syntax)
@match syntax begin
Expr(:let,
bd,
Expr(:block,
::LineNumberNode,
ret1 || Expr(:block, ret1),
::LineNumberNode,
Expr(:macrocall, name, ::LineNumberNode), ::LineNumberNode,
ret2 || Expr(:block, ret2)
)
) =>
# @show bd ret1 ret2 " "
@match bd begin
:($a = $b) => begin
@format [a, b, ret1, ret2] quote
@match b begin
a => ret1
_ => ret2
end
end
end
a => :(let $a; $last end)
end
_ => error("[m3] nothing matched")
end
end
res31 = :(
@match x begin
(a, 2) => a
_ => x
end)
# `@when` + `@otherwise`
syntax41 = :(# @when
let (a, 2) = x
a
@when (b, 2) = x
b
@otherwise
x
end)
# TODO
res41 = :(
@match x begin
(a, 2) => a
(b, 2) => b
_ => x
end)
#=
match macro with specific name???
=#
syntax50 = :(@when x begin end)
@when Expr(:macrocall, name, body...) = syntax50 begin @show name; end
@when Expr(:macrocall, Symbol("@when"), body...) = syntax50 begin @show name; end # error
@when :(@when para body) = syntax50 begin @show para body; end # ret nothing
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment