github.com/oweisse/u-root@v0.0.0-20181109060735-d005ad25fef1/cmds/elvish/glob/parse.go (about)

     1  package glob
     2  
     3  import (
     4  	"bytes"
     5  	"unicode/utf8"
     6  )
     7  
     8  // Parse parses a pattern.
     9  func Parse(s string) Pattern {
    10  	segments := []Segment{}
    11  	add := func(seg Segment) {
    12  		segments = append(segments, seg)
    13  	}
    14  	p := &parser{s, 0, 0}
    15  
    16  rune:
    17  	for {
    18  		r := p.next()
    19  		switch r {
    20  		case eof:
    21  			break rune
    22  		case '?':
    23  			add(Wild{Question, false, nil})
    24  		case '*':
    25  			n := 1
    26  			for p.next() == '*' {
    27  				n++
    28  			}
    29  			p.backup()
    30  			if n == 1 {
    31  				add(Wild{Star, false, nil})
    32  			} else {
    33  				add(Wild{StarStar, false, nil})
    34  			}
    35  		case '/':
    36  			for p.next() == '/' {
    37  			}
    38  			p.backup()
    39  			add(Slash{})
    40  		default:
    41  			var literal bytes.Buffer
    42  		literal:
    43  			for {
    44  				switch r {
    45  				case '?', '*', '/', eof:
    46  					break literal
    47  				case '\\':
    48  					r = p.next()
    49  					if r == eof {
    50  						break literal
    51  					}
    52  					literal.WriteRune(r)
    53  				default:
    54  					literal.WriteRune(r)
    55  				}
    56  				r = p.next()
    57  			}
    58  			p.backup()
    59  			add(Literal{literal.String()})
    60  		}
    61  	}
    62  	return Pattern{segments, ""}
    63  }
    64  
    65  // XXX Contains duplicate code with parse/parser.go.
    66  
    67  type parser struct {
    68  	src     string
    69  	pos     int
    70  	overEOF int
    71  }
    72  
    73  const eof rune = -1
    74  
    75  func (ps *parser) next() rune {
    76  	if ps.pos == len(ps.src) {
    77  		ps.overEOF++
    78  		return eof
    79  	}
    80  	r, s := utf8.DecodeRuneInString(ps.src[ps.pos:])
    81  	ps.pos += s
    82  	return r
    83  }
    84  
    85  func (ps *parser) backup() {
    86  	if ps.overEOF > 0 {
    87  		ps.overEOF--
    88  		return
    89  	}
    90  	_, s := utf8.DecodeLastRuneInString(ps.src[:ps.pos])
    91  	ps.pos -= s
    92  }