Vim script で match 文 その2

前回の続き。
もうちょっと拡張し易いようにしてみました。
id:tyru さんの書き方に近いかな。

[ソース]

function! s:equal(a, b)
    return a:a.equal(a:b)
endfunction

function! s:apply(expr, value)
    return a:expr.apply(a:value)
endfunction

function! s:match_expr(...)
    let self = {}
    let self.cases = a:000
    
    function! self.apply(value)
        for case in self.cases
            if s:equal(case, a:value)
                return s:apply(case, a:value)
            endif
        endfor
    endfunction

    return self
endfunction


function! s:match(value, ...)
    return s:apply(call("s:match_expr", a:000), a:value)
endfunction


function! s:case(value, expr)
    let self = {}
    let self.value = a:value
    let self.expr  = a:expr
    
    function! self.equal(value)
        return self.value == a:value
    endfunction

    function! self.apply(...)
        return self.expr
    endfunction

    return self
endfunction

function! s:default(expr)
    let self = {}
    let self.expr = a:expr
    
    function! self.equal(value)
        return !0
    endfunction

    function! self.apply(...)
        return self.expr
    endfunction

    return self
endfunction


function! s:main()
    for n in range(1, 30)
        echo s:match([n%3==0, n%5==0],
\           s:case([1,0], "Fizz"),
\           s:case([0,1], "Buzz"),
\           s:case([1,1], "FizzBuzz"),
\           s:default(n)
\       )
    endfor
endfunction
call s:main()

[出力]

1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
17
Fizz
19
Buzz
Fizz
22
23
Fizz
Buzz
26
Fizz
28
29
FizzBuzz