Example #1
0
// 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
	}
}
Example #2
0
// 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
}