forked from cytisan/pattern-js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pattern.coffee
106 lines (94 loc) · 2.97 KB
/
pattern.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# match =
# value: (obj)
# success: (boolean)
_ = require 'underscore'
isArray= _.isArray
isEqual = _.isEqual
class PatternMatching
constructor: (@_f) ->
PatternMatching::when = (predicates, exp) ->
new PatternMatching (inner) =>
match = @_f(inner)
if match.success
match
else
fail = () ->
value: match.value
success: false
ps = if isArray(predicates) then predicates else [predicates]
if ps.length is match.value.length
for i in [0...ps.length]
if ps[i].apply(this, [match.value[i]]) isnt true
return fail()
value: exp.apply(this, match.value)
success: true
else
fail()
PatternMatching::any = (valExp) ->
new PatternMatching (inner) =>
match = @_f(inner)
if match.success
match
else
value: valExp()
success: true
PatternMatching::matching = PatternMatching::end = ->
(inner...) =>
ret = @_f(inner)
if ret.success
ret.value
else
undefined
PatternMatching::value = (expected, valExp) ->
predicates = []
if isArray(expected)
for e in expected
predicates.push (val) -> isEqual val, e
else
predicates.push (val) -> isEqual val, expected
@.when(predicates, (val) -> valExp(val))
PatternMatching::direct = (directExp) ->
new PatternMatching (inner) =>
match = @_f(inner)
if match.success
match
else
if match.value.length is directExp.length
value: directExp.apply(this, match.value)
success: true
else
value: match.value
success: false
PatternMatching::some = (patterns, exp) ->
getPredicate = (pattern) ->
if typeof(pattern) is 'undefined'
(val) -> true
else if typeof(pattern) is 'function'
pattern
else if isArray(pattern)
(val) ->
p = () ->
for v in val
if !getPredicate(v)
return false
return true
isArray(val) \
and val.length is pattern.length \
and p()
else if (typeof(pattern) is 'object') \
and (typeof(pattern._wrapped___func) is 'function')
(val) -> isEqual val, pattern._wrapped___func
else
(val) -> isEqual val, pattern
predicates = (getPredicate p for p in patterns)
@.when(predicates, (val) -> exp(val))
pattern = () ->
new PatternMatching (inner) ->
value: inner
success: false
pattern.constfunc = (func) ->
_wrapped___func: func
root = this
if typeof(exports) isnt 'undefined' then exports.pattern = pattern
if typeof(module) isnt 'undefined' then module.exports = pattern
root.pattern = pattern