File: parse.go

package info (click to toggle)
elvish 0.21.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 6,372 kB
  • sloc: javascript: 236; sh: 130; python: 104; makefile: 88; xml: 9
file content (92 lines) | stat: -rw-r--r-- 1,429 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package glob

import (
	"bytes"
	"unicode/utf8"
)

// Parse parses a pattern.
func Parse(s string) Pattern {
	segments := []Segment{}
	add := func(seg Segment) {
		segments = append(segments, seg)
	}
	p := &parser{s, 0, 0}

rune:
	for {
		r := p.next()
		switch r {
		case eof:
			break rune
		case '?':
			add(Wild{Question, false, nil})
		case '*':
			n := 1
			for p.next() == '*' {
				n++
			}
			p.backup()
			if n == 1 {
				add(Wild{Star, false, nil})
			} else {
				add(Wild{StarStar, false, nil})
			}
		case '/':
			for p.next() == '/' {
			}
			p.backup()
			add(Slash{})
		default:
			var literal bytes.Buffer
		literal:
			for {
				switch r {
				case '?', '*', '/', eof:
					break literal
				case '\\':
					r = p.next()
					if r == eof {
						break literal
					}
					literal.WriteRune(r)
				default:
					literal.WriteRune(r)
				}
				r = p.next()
			}
			p.backup()
			add(Literal{literal.String()})
		}
	}
	return Pattern{segments, ""}
}

// TODO(xiaq): Contains duplicate code with parse/parser.go.

type parser struct {
	src     string
	pos     int
	overEOF int
}

const eof rune = -1

func (ps *parser) next() rune {
	if ps.pos == len(ps.src) {
		ps.overEOF++
		return eof
	}
	r, s := utf8.DecodeRuneInString(ps.src[ps.pos:])
	ps.pos += s
	return r
}

func (ps *parser) backup() {
	if ps.overEOF > 0 {
		ps.overEOF--
		return
	}
	_, s := utf8.DecodeLastRuneInString(ps.src[:ps.pos])
	ps.pos -= s
}