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  }