1package ast
2
3import (
4	"errors"
5	"fmt"
6	"github.com/gobwas/glob/syntax/lexer"
7	"unicode/utf8"
8)
9
10type Lexer interface {
11	Next() lexer.Token
12}
13
14type parseFn func(*Node, Lexer) (parseFn, *Node, error)
15
16func Parse(lexer Lexer) (*Node, error) {
17	var parser parseFn
18
19	root := NewNode(KindPattern, nil)
20
21	var (
22		tree *Node
23		err  error
24	)
25	for parser, tree = parserMain, root; parser != nil; {
26		parser, tree, err = parser(tree, lexer)
27		if err != nil {
28			return nil, err
29		}
30	}
31
32	return root, nil
33}
34
35func parserMain(tree *Node, lex Lexer) (parseFn, *Node, error) {
36	for {
37		token := lex.Next()
38		switch token.Type {
39		case lexer.EOF:
40			return nil, tree, nil
41
42		case lexer.Error:
43			return nil, tree, errors.New(token.Raw)
44
45		case lexer.Text:
46			Insert(tree, NewNode(KindText, Text{token.Raw}))
47			return parserMain, tree, nil
48
49		case lexer.Any:
50			Insert(tree, NewNode(KindAny, nil))
51			return parserMain, tree, nil
52
53		case lexer.Super:
54			Insert(tree, NewNode(KindSuper, nil))
55			return parserMain, tree, nil
56
57		case lexer.Single:
58			Insert(tree, NewNode(KindSingle, nil))
59			return parserMain, tree, nil
60
61		case lexer.RangeOpen:
62			return parserRange, tree, nil
63
64		case lexer.TermsOpen:
65			a := NewNode(KindAnyOf, nil)
66			Insert(tree, a)
67
68			p := NewNode(KindPattern, nil)
69			Insert(a, p)
70
71			return parserMain, p, nil
72
73		case lexer.Separator:
74			p := NewNode(KindPattern, nil)
75			Insert(tree.Parent, p)
76
77			return parserMain, p, nil
78
79		case lexer.TermsClose:
80			return parserMain, tree.Parent.Parent, nil
81
82		default:
83			return nil, tree, fmt.Errorf("unexpected token: %s", token)
84		}
85	}
86	return nil, tree, fmt.Errorf("unknown error")
87}
88
89func parserRange(tree *Node, lex Lexer) (parseFn, *Node, error) {
90	var (
91		not   bool
92		lo    rune
93		hi    rune
94		chars string
95	)
96	for {
97		token := lex.Next()
98		switch token.Type {
99		case lexer.EOF:
100			return nil, tree, errors.New("unexpected end")
101
102		case lexer.Error:
103			return nil, tree, errors.New(token.Raw)
104
105		case lexer.Not:
106			not = true
107
108		case lexer.RangeLo:
109			r, w := utf8.DecodeRuneInString(token.Raw)
110			if len(token.Raw) > w {
111				return nil, tree, fmt.Errorf("unexpected length of lo character")
112			}
113			lo = r
114
115		case lexer.RangeBetween:
116			//
117
118		case lexer.RangeHi:
119			r, w := utf8.DecodeRuneInString(token.Raw)
120			if len(token.Raw) > w {
121				return nil, tree, fmt.Errorf("unexpected length of lo character")
122			}
123
124			hi = r
125
126			if hi < lo {
127				return nil, tree, fmt.Errorf("hi character '%s' should be greater than lo '%s'", string(hi), string(lo))
128			}
129
130		case lexer.Text:
131			chars = token.Raw
132
133		case lexer.RangeClose:
134			isRange := lo != 0 && hi != 0
135			isChars := chars != ""
136
137			if isChars == isRange {
138				return nil, tree, fmt.Errorf("could not parse range")
139			}
140
141			if isRange {
142				Insert(tree, NewNode(KindRange, Range{
143					Lo:  lo,
144					Hi:  hi,
145					Not: not,
146				}))
147			} else {
148				Insert(tree, NewNode(KindList, List{
149					Chars: chars,
150					Not:   not,
151				}))
152			}
153
154			return parserMain, tree, nil
155		}
156	}
157}
158