summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/gobwas/glob/syntax/ast/parser.go
blob: 429b4094303e4881c4735f7a8d87a519208efb48 (plain)
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package ast

import (
	"errors"
	"fmt"
	"github.com/gobwas/glob/syntax/lexer"
	"unicode/utf8"
)

type Lexer interface {
	Next() lexer.Token
}

type parseFn func(*Node, Lexer) (parseFn, *Node, error)

func Parse(lexer Lexer) (*Node, error) {
	var parser parseFn

	root := NewNode(KindPattern, nil)

	var (
		tree *Node
		err  error
	)
	for parser, tree = parserMain, root; parser != nil; {
		parser, tree, err = parser(tree, lexer)
		if err != nil {
			return nil, err
		}
	}

	return root, nil
}

func parserMain(tree *Node, lex Lexer) (parseFn, *Node, error) {
	for {
		token := lex.Next()
		switch token.Type {
		case lexer.EOF:
			return nil, tree, nil

		case lexer.Error:
			return nil, tree, errors.New(token.Raw)

		case lexer.Text:
			Insert(tree, NewNode(KindText, Text{token.Raw}))
			return parserMain, tree, nil

		case lexer.Any:
			Insert(tree, NewNode(KindAny, nil))
			return parserMain, tree, nil

		case lexer.Super:
			Insert(tree, NewNode(KindSuper, nil))
			return parserMain, tree, nil

		case lexer.Single:
			Insert(tree, NewNode(KindSingle, nil))
			return parserMain, tree, nil

		case lexer.RangeOpen:
			return parserRange, tree, nil

		case lexer.TermsOpen:
			a := NewNode(KindAnyOf, nil)
			Insert(tree, a)

			p := NewNode(KindPattern, nil)
			Insert(a, p)

			return parserMain, p, nil

		case lexer.Separator:
			p := NewNode(KindPattern, nil)
			Insert(tree.Parent, p)

			return parserMain, p, nil

		case lexer.TermsClose:
			return parserMain, tree.Parent.Parent, nil

		default:
			return nil, tree, fmt.Errorf("unexpected token: %s", token)
		}
	}
	return nil, tree, fmt.Errorf("unknown error")
}

func parserRange(tree *Node, lex Lexer) (parseFn, *Node, error) {
	var (
		not   bool
		lo    rune
		hi    rune
		chars string
	)
	for {
		token := lex.Next()
		switch token.Type {
		case lexer.EOF:
			return nil, tree, errors.New("unexpected end")

		case lexer.Error:
			return nil, tree, errors.New(token.Raw)

		case lexer.Not:
			not = true

		case lexer.RangeLo:
			r, w := utf8.DecodeRuneInString(token.Raw)
			if len(token.Raw) > w {
				return nil, tree, fmt.Errorf("unexpected length of lo character")
			}
			lo = r

		case lexer.RangeBetween:
			//

		case lexer.RangeHi:
			r, w := utf8.DecodeRuneInString(token.Raw)
			if len(token.Raw) > w {
				return nil, tree, fmt.Errorf("unexpected length of lo character")
			}

			hi = r

			if hi < lo {
				return nil, tree, fmt.Errorf("hi character '%s' should be greater than lo '%s'", string(hi), string(lo))
			}

		case lexer.Text:
			chars = token.Raw

		case lexer.RangeClose:
			isRange := lo != 0 && hi != 0
			isChars := chars != ""

			if isChars == isRange {
				return nil, tree, fmt.Errorf("could not parse range")
			}

			if isRange {
				Insert(tree, NewNode(KindRange, Range{
					Lo:  lo,
					Hi:  hi,
					Not: not,
				}))
			} else {
				Insert(tree, NewNode(KindList, List{
					Chars: chars,
					Not:   not,
				}))
			}

			return parserMain, tree, nil
		}
	}
}