// add adds an entry to q for pc, unless the q already has such an entry. // It also recursively adds an entry for all instructions reachable from pc by following // empty-width conditions satisfied by cond. pos gives the current position // in the input. func (m *machine) add(q *queue, pc uint32, pos int, cap []int, cond syntax.EmptyOp) { if pc == 0 { return } if j := q.sparse[pc]; j < uint32(len(q.dense)) && q.dense[j].pc == pc { return } j := len(q.dense) q.dense = q.dense[:j+1] d := &q.dense[j] d.t = nil d.pc = pc q.sparse[pc] = uint32(j) i := &m.p.Inst[pc] switch i.Op { default: panic("unhandled") case syntax.InstFail: // nothing case syntax.InstAlt, syntax.InstAltMatch: m.add(q, i.Out, pos, cap, cond) m.add(q, i.Arg, pos, cap, cond) case syntax.InstEmptyWidth: if syntax.EmptyOp(i.Arg)&^cond == 0 { m.add(q, i.Out, pos, cap, cond) } case syntax.InstNop: m.add(q, i.Out, pos, cap, cond) case syntax.InstCapture: if int(i.Arg) < len(cap) { opos := cap[i.Arg] cap[i.Arg] = pos m.add(q, i.Out, pos, cap, cond) cap[i.Arg] = opos } else { m.add(q, i.Out, pos, cap, cond) } case syntax.InstMatch, syntax.InstRune: t := m.alloc(i) if len(t.cap) > 0 { copy(t.cap, cap) } d.t = t } }
// match runs the machine over the input starting at pos. // It reports whether a match was found. // If so, m.matchcap holds the submatch information. func (m *machine) match(i input, pos int) bool { startCond := m.re.cond if startCond == ^syntax.EmptyOp(0) { // impossible return false } m.matched = false for i := range m.matchcap { m.matchcap[i] = -1 } runq, nextq := &m.q0, &m.q1 rune, rune1 := endOfText, endOfText width, width1 := 0, 0 rune, width = i.step(pos) if rune != endOfText { rune1, width1 = i.step(pos + width) } // TODO: Let caller specify the initial flag setting. // For now assume pos == 0 is beginning of text and // pos != 0 is not even beginning of line. // TODO: Word boundary. var flag syntax.EmptyOp if pos == 0 { flag = syntax.EmptyBeginText | syntax.EmptyBeginLine } // Update flag using lookahead rune. if rune1 == '\n' { flag |= syntax.EmptyEndLine } if rune1 == endOfText { flag |= syntax.EmptyEndText } for { if len(runq.dense) == 0 { if startCond&syntax.EmptyBeginText != 0 && pos != 0 { // Anchored match, past beginning of text. break } if m.matched { // Have match; finished exploring alternatives. break } if len(m.re.prefix) > 0 && rune1 != m.re.prefixRune && i.canCheckPrefix() { // Match requires literal prefix; fast search for it. advance := i.index(m.re, pos) if advance < 0 { break } pos += advance rune, width = i.step(pos) rune1, width1 = i.step(pos + width) } } if !m.matched { if len(m.matchcap) > 0 { m.matchcap[0] = pos } m.add(runq, uint32(m.p.Start), pos, m.matchcap, flag) } // TODO: word boundary flag = 0 if rune == '\n' { flag |= syntax.EmptyBeginLine } if rune1 == '\n' { flag |= syntax.EmptyEndLine } if rune1 == endOfText { flag |= syntax.EmptyEndText } m.step(runq, nextq, pos, pos+width, rune, flag) if width == 0 { break } pos += width rune, width = rune1, width1 if rune != endOfText { rune1, width1 = i.step(pos + width) } runq, nextq = nextq, runq } m.clear(nextq) return m.matched }