|
5 | 5 | # 2. Dictionary
|
6 | 6 | # 3. Callback: takes arguments Dictionary × Number of elements matched
|
7 | 7 | #
|
| 8 | + |
8 | 9 | function matcher(val::Any)
|
9 |
| - iscall(val) && return term_matcher(val) |
| 10 | + # if val is a call (like an operation) creates a term matcher or term matcher with defslot |
| 11 | + if iscall(val) |
| 12 | + # if has two arguments and one of them is a DefSlot, create a term matcher with defslot |
| 13 | + if length(arguments(val)) == 2 && any(x -> isa(x, DefSlot), arguments(val)) |
| 14 | + return term_matcher_defslot(val) |
| 15 | + # else return a normal term matcher |
| 16 | + else |
| 17 | + return term_matcher(val) |
| 18 | + end |
| 19 | + end |
| 20 | + |
10 | 21 | function literal_matcher(next, data, bindings)
|
| 22 | + # car data is the first element of data |
11 | 23 | islist(data) && isequal(car(data), val) ? next(bindings, 1) : nothing
|
12 | 24 | end
|
13 | 25 | end
|
14 | 26 |
|
15 | 27 | function matcher(slot::Slot)
|
16 | 28 | function slot_matcher(next, data, bindings)
|
17 |
| - !islist(data) && return |
| 29 | + !islist(data) && return nothing |
18 | 30 | val = get(bindings, slot.name, nothing)
|
| 31 | + # if slot name already is in bindings, check if it matches |
19 | 32 | if val !== nothing
|
20 | 33 | if isequal(val, car(data))
|
21 | 34 | return next(bindings, 1)
|
22 | 35 | end
|
23 |
| - else |
24 |
| - if slot.predicate(car(data)) |
25 |
| - next(assoc(bindings, slot.name, car(data)), 1) |
| 36 | + # elseif the first element of data matches the slot predicate, add it to bindings and call next |
| 37 | + elseif slot.predicate(car(data)) |
| 38 | + next(assoc(bindings, slot.name, car(data)), 1) |
| 39 | + end |
| 40 | + end |
| 41 | +end |
| 42 | + |
| 43 | +function matcher(defslot::DefSlot) |
| 44 | + function defslot_matcher(next, data, bindings) |
| 45 | + !islist(data) && return |
| 46 | + val = get(bindings, defslot.name, nothing) |
| 47 | + if val !== nothing |
| 48 | + if isequal(val, car(data)) |
| 49 | + return next(bindings, 1) |
26 | 50 | end
|
| 51 | + elseif defslot.predicate(car(data)) |
| 52 | + next(assoc(bindings, defslot.name, car(data)), 1) |
27 | 53 | end
|
28 | 54 | end
|
29 | 55 | end
|
|
86 | 112 |
|
87 | 113 | function term_matcher(term)
|
88 | 114 | matchers = (matcher(operation(term)), map(matcher, arguments(term))...,)
|
| 115 | + |
89 | 116 | function term_matcher(success, data, bindings)
|
| 117 | + !islist(data) && return nothing # if data is not a list, return nothing |
| 118 | + !iscall(car(data)) && return nothing # if first element is not a call, return nothing |
90 | 119 |
|
91 |
| - !islist(data) && return nothing |
92 |
| - !iscall(car(data)) && return nothing |
| 120 | + function loop(term, bindings′, matchers′) # Get it to compile faster |
| 121 | + if !islist(matchers′) |
| 122 | + if !islist(term) |
| 123 | + return success(bindings′, 1) |
| 124 | + end |
| 125 | + return nothing |
| 126 | + end |
| 127 | + car(matchers′)(term, bindings′) do b, n |
| 128 | + loop(drop_n(term, n), b, cdr(matchers′)) |
| 129 | + end |
| 130 | + # explenation of above 3 lines: |
| 131 | + # car(matchers′)(b,n -> loop(drop_n(term, n), b, cdr(matchers′)), term, bindings′) |
| 132 | + # ------- next(b,n) ----------------------------- |
| 133 | + # car = first element of list, cdr = rest of the list, drop_n = drop first n elements of list |
| 134 | + # Calls the first matcher, with the "next" function being loop again but with n terms dropepd from term |
| 135 | + # Term is a linked list (a list and a index). drop n advances the index. when the index sorpasses |
| 136 | + # the length of the list, is considered empty |
| 137 | + end |
| 138 | + |
| 139 | + loop(car(data), bindings, matchers) # Try to eat exactly one term |
| 140 | + end |
| 141 | +end |
| 142 | + |
| 143 | + |
| 144 | +# ~x + ~!y |
| 145 | +function term_matcher_defslot(term) |
| 146 | + matchers = (matcher(operation(term)), map(matcher, arguments(term))...) # create matchers for the operation and arguments of the term |
| 147 | + |
| 148 | + function term_matcher(success, data, bindings) |
| 149 | + |
| 150 | + !islist(data) && return nothing # if data is not a list, return nothing |
| 151 | + if !iscall(car(data)) |
| 152 | + a = arguments(term) |
| 153 | + slot = a[findfirst(x -> isa(x, Slot), a)] # find the first slot in the term |
| 154 | + defslot = a[findfirst(x -> isa(x, DefSlot), a)] # find the first defslot in the term |
| 155 | + |
| 156 | + bindings = assoc(bindings, slot.name, car(data)) |
| 157 | + bindings = assoc(bindings, defslot.name, defslot.default) |
| 158 | + |
| 159 | + return success(bindings, 1) # if first element is not a call, return success with bindings and 1 |
| 160 | + end |
93 | 161 |
|
94 | 162 | function loop(term, bindings′, matchers′) # Get it to compile faster
|
95 | 163 | if !islist(matchers′)
|
|
0 commit comments