aboutsummaryrefslogtreecommitdiffstats
path: root/core/pattern.moon
blob: 13497af22d2c8957d62b4b5d1bbe2e4b7c51b1ac (plain)
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
unpack or= table.unpack

class Pattern
  new: (opts) =>
    if 'string' == type opts
      splat, const, type, opt = opts\match '^(%*?)(=?)([%w%-%_%/]+)(%??)$'
      assert type, "couldn't parse type pattern '#{opts}'"
      opts = {
        :type
        splat: splat == '*'
        const: const == '='
        opt: opt == '?'
      }

    @type = opts.type
    @const = opts.const
    @opt = opts.opt
    @splat = opts.splat

  matches: (result) =>
    return false unless result

    if @const
      return false unless result\is_const!

    if not result.value
      return @type == 'nil'

    return true if @type == 'any'

    result.value.type == @type

  match: (results) =>
    if @splat
      matched = while @matches results[1]
        table.remove results, 1

      assert @opt or #matched > 0, "expected at least one argument for spread"
      matched
    else
      matches = @matches results[1]
      assert @opt or matches, "couldn't match argument #{results[1]} as #{@}"
      if matches then table.remove results, 1

  __tostring: =>
    str = @type
    str = '*' .. str if @splat
    str = '=' .. str if @const
    str = str .. '?' if @opt
    str

match = (pattern, results) ->
  patterns = while pattern
    pat, rest = pattern\match '^([^ ]+) (.*)$'
    pat = pattern unless pat
    pattern = rest
    Pattern pat
  values = [p\match results for p in *patterns]
  assert #results == 0, "#{#results} extra arguments given!"
  values

{
  :Pattern
  :match
}