match.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. // Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
  2. //
  3. // This program is free software; you can redistribute it and/or
  4. // modify it under the terms of The BSD 3-Clause License
  5. // that can be found in the LICENSE file.
  6. package uritemplate
  7. import (
  8. "bytes"
  9. "unicode"
  10. "unicode/utf8"
  11. )
  12. type matcher struct {
  13. prog *prog
  14. list1 threadList
  15. list2 threadList
  16. matched bool
  17. cap map[string][]int
  18. input string
  19. }
  20. func (m *matcher) at(pos int) (rune, int, bool) {
  21. if l := len(m.input); pos < l {
  22. c := m.input[pos]
  23. if c < utf8.RuneSelf {
  24. return rune(c), 1, pos+1 < l
  25. }
  26. r, size := utf8.DecodeRuneInString(m.input[pos:])
  27. return r, size, pos+size < l
  28. }
  29. return -1, 0, false
  30. }
  31. func (m *matcher) add(list *threadList, pc uint32, pos int, next bool, cap map[string][]int) {
  32. if i := list.sparse[pc]; i < uint32(len(list.dense)) && list.dense[i].pc == pc {
  33. return
  34. }
  35. n := len(list.dense)
  36. list.dense = list.dense[:n+1]
  37. list.sparse[pc] = uint32(n)
  38. e := &list.dense[n]
  39. e.pc = pc
  40. e.t = nil
  41. op := &m.prog.op[pc]
  42. switch op.code {
  43. default:
  44. panic("unhandled opcode")
  45. case opRune, opRuneClass, opEnd:
  46. e.t = &thread{
  47. op: &m.prog.op[pc],
  48. cap: make(map[string][]int, len(m.cap)),
  49. }
  50. for k, v := range cap {
  51. e.t.cap[k] = make([]int, len(v))
  52. copy(e.t.cap[k], v)
  53. }
  54. case opLineBegin:
  55. if pos == 0 {
  56. m.add(list, pc+1, pos, next, cap)
  57. }
  58. case opLineEnd:
  59. if !next {
  60. m.add(list, pc+1, pos, next, cap)
  61. }
  62. case opCapStart, opCapEnd:
  63. ocap := make(map[string][]int, len(m.cap))
  64. for k, v := range cap {
  65. ocap[k] = make([]int, len(v))
  66. copy(ocap[k], v)
  67. }
  68. ocap[op.name] = append(ocap[op.name], pos)
  69. m.add(list, pc+1, pos, next, ocap)
  70. case opSplit:
  71. m.add(list, pc+1, pos, next, cap)
  72. m.add(list, op.i, pos, next, cap)
  73. case opJmp:
  74. m.add(list, op.i, pos, next, cap)
  75. case opJmpIfNotDefined:
  76. m.add(list, pc+1, pos, next, cap)
  77. m.add(list, op.i, pos, next, cap)
  78. case opJmpIfNotFirst:
  79. m.add(list, pc+1, pos, next, cap)
  80. m.add(list, op.i, pos, next, cap)
  81. case opJmpIfNotEmpty:
  82. m.add(list, op.i, pos, next, cap)
  83. m.add(list, pc+1, pos, next, cap)
  84. case opNoop:
  85. m.add(list, pc+1, pos, next, cap)
  86. }
  87. }
  88. func (m *matcher) step(clist *threadList, nlist *threadList, r rune, pos int, nextPos int, next bool) {
  89. debug.Printf("===== %q =====", string(r))
  90. for i := 0; i < len(clist.dense); i++ {
  91. e := clist.dense[i]
  92. if debug {
  93. var buf bytes.Buffer
  94. dumpProg(&buf, m.prog, e.pc)
  95. debug.Printf("\n%s", buf.String())
  96. }
  97. if e.t == nil {
  98. continue
  99. }
  100. t := e.t
  101. op := t.op
  102. switch op.code {
  103. default:
  104. panic("unhandled opcode")
  105. case opRune:
  106. if op.r == r {
  107. m.add(nlist, e.pc+1, nextPos, next, t.cap)
  108. }
  109. case opRuneClass:
  110. ret := false
  111. if !ret && op.rc&runeClassU == runeClassU {
  112. ret = ret || unicode.Is(rangeUnreserved, r)
  113. }
  114. if !ret && op.rc&runeClassR == runeClassR {
  115. ret = ret || unicode.Is(rangeReserved, r)
  116. }
  117. if !ret && op.rc&runeClassPctE == runeClassPctE {
  118. ret = ret || unicode.Is(unicode.ASCII_Hex_Digit, r)
  119. }
  120. if ret {
  121. m.add(nlist, e.pc+1, nextPos, next, t.cap)
  122. }
  123. case opEnd:
  124. m.matched = true
  125. for k, v := range t.cap {
  126. m.cap[k] = make([]int, len(v))
  127. copy(m.cap[k], v)
  128. }
  129. clist.dense = clist.dense[:0]
  130. }
  131. }
  132. clist.dense = clist.dense[:0]
  133. }
  134. func (m *matcher) match() bool {
  135. pos := 0
  136. clist, nlist := &m.list1, &m.list2
  137. for {
  138. if len(clist.dense) == 0 && m.matched {
  139. break
  140. }
  141. r, width, next := m.at(pos)
  142. if !m.matched {
  143. m.add(clist, 0, pos, next, m.cap)
  144. }
  145. m.step(clist, nlist, r, pos, pos+width, next)
  146. if width < 1 {
  147. break
  148. }
  149. pos += width
  150. clist, nlist = nlist, clist
  151. }
  152. return m.matched
  153. }
  154. func (tmpl *Template) Match(expansion string) Values {
  155. tmpl.mu.Lock()
  156. if tmpl.prog == nil {
  157. c := compiler{}
  158. c.init()
  159. c.compile(tmpl)
  160. tmpl.prog = c.prog
  161. }
  162. prog := tmpl.prog
  163. tmpl.mu.Unlock()
  164. n := len(prog.op)
  165. m := matcher{
  166. prog: prog,
  167. list1: threadList{
  168. dense: make([]threadEntry, 0, n),
  169. sparse: make([]uint32, n),
  170. },
  171. list2: threadList{
  172. dense: make([]threadEntry, 0, n),
  173. sparse: make([]uint32, n),
  174. },
  175. cap: make(map[string][]int, prog.numCap),
  176. input: expansion,
  177. }
  178. if !m.match() {
  179. return nil
  180. }
  181. match := make(Values, len(m.cap))
  182. for name, indices := range m.cap {
  183. v := Value{V: make([]string, len(indices)/2)}
  184. for i := range v.V {
  185. v.V[i] = pctDecode(expansion[indices[2*i]:indices[2*i+1]])
  186. }
  187. if len(v.V) == 1 {
  188. v.T = ValueTypeString
  189. } else {
  190. v.T = ValueTypeList
  191. }
  192. match[name] = v
  193. }
  194. return match
  195. }