github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/internal/pattern/machine.go (about) 1 package pattern 2 3 import "strings" 4 5 type machine struct { 6 saved []Capture 7 } 8 9 func (m *machine) match(p *Pattern, input string, base int) bool { 10 if len(p.prefix) > len(input)-base { 11 return false 12 } 13 14 if p.typ&matchPrefix != 0 { 15 if strings.HasPrefix(input[base:], p.prefix) { 16 return m.matchThere(p, input, base) 17 } 18 return false 19 } 20 21 for off := base; off <= len(input)-len(p.prefix); off++ { 22 if strings.HasPrefix(input[off:], p.prefix) { 23 if m.matchThere(p, input, off) { 24 return true 25 } 26 } 27 } 28 29 return false 30 } 31 32 func (m *machine) matchThere(p *Pattern, input string, off int) bool { 33 m.saved[0].Begin = off 34 35 if len(p.code) == 0 { 36 m.saved[0].End = off + len(p.prefix) 37 return true 38 } 39 40 return m.recursiveMatch(p, input, 0, off+len(p.prefix)) 41 } 42 43 func (m *machine) recursiveMatch(p *Pattern, input string, pc, sp int) bool { 44 for { 45 inst := p.code[pc] 46 47 switch inst.op { 48 case opMatch: 49 if p.typ&matchSuffix != 0 { 50 r, _ := decodeRune(input, sp) 51 if r == eos { 52 m.saved[0].End = sp 53 return true 54 } 55 return false 56 } 57 58 m.saved[0].End = sp 59 return true 60 case opJmp: 61 pc = inst.x 62 case opSplit: 63 if m.recursiveMatch(p, input, inst.x, sp) { 64 return true 65 } 66 pc = inst.y 67 case opBeginSave: 68 cap := &m.saved[inst.x] 69 old := cap.Begin 70 cap.Begin = sp 71 if m.recursiveMatch(p, input, pc+1, sp) { 72 return true 73 } 74 cap.Begin = old 75 return false 76 case opEndSave: 77 cap := &m.saved[inst.x] 78 old := cap.End 79 pred := cap.IsEmpty 80 cap.End = sp 81 cap.IsEmpty = inst.y != 0 82 if m.recursiveMatch(p, input, pc+1, sp) { 83 return true 84 } 85 cap.End = old 86 cap.IsEmpty = pred 87 return false 88 case opCapture: 89 loc := m.saved[inst.x] 90 cap := input[loc.Begin:loc.End] 91 92 if !strings.HasPrefix(input[sp:], cap) { 93 return false 94 } 95 96 pc++ 97 sp += len(cap) 98 case opSet: 99 r, rsize := decodeRune(input, sp) 100 if r == eos { 101 return false 102 } 103 104 if !p.sets[inst.x].match(r) { 105 return false 106 } 107 108 pc++ 109 sp += rsize 110 case opBalance: 111 x := rune(inst.x) 112 y := rune(inst.y) 113 114 r, rsize := decodeRune(input, sp) 115 if r == eos { 116 return false 117 } 118 119 if x != r { 120 return false 121 } 122 123 sp += rsize 124 125 balance := 1 126 127 L: 128 for { 129 r, rsize := decodeRune(input, sp) 130 131 sp += rsize 132 133 switch r { 134 case y: 135 balance-- 136 if balance == 0 { 137 break L 138 } 139 case x: 140 balance++ 141 case eos: 142 return false 143 } 144 } 145 146 pc++ 147 case opFrontier: 148 r, _ := lastDecodeRune(input, sp) 149 if r == sos { 150 r = 0x00 151 } 152 if p.sets[inst.x].match(r) { 153 return false 154 } 155 156 r, _ = decodeRune(input, sp) 157 if r == eos { 158 r = 0x00 159 } 160 if !p.sets[inst.x].match(r) { 161 return false 162 } 163 164 pc++ 165 default: 166 r, rsize := decodeRune(input, sp) 167 if r == eos { 168 return false 169 } 170 171 if !simpleMatch(inst.op, r) { 172 return false 173 } 174 175 pc++ 176 sp += rsize 177 } 178 } 179 }