/
query.go
111 lines (96 loc) · 2.55 KB
/
query.go
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
package core
import (
"errors"
"strings"
"text/scanner"
)
type Query struct {
Kinds []string
Tags []string
Attributes map[string]interface{}
Path string
Terms []string
}
// NewQuery instantiates a new query.
func NewQuery() *Query {
return &Query{
Attributes: make(map[string]interface{}),
}
}
// ParseQuery parses a user query.
func ParseQuery(q string) (*Query, error) {
result := NewQuery()
var s scanner.Scanner
s.Init(strings.NewReader(q))
s.Filename = ""
for {
token := s.Scan()
if token == scanner.EOF {
return result, nil
}
switch s.TokenText() {
case "kind":
// Kind
colonToken := s.Scan()
if colonToken == scanner.EOF {
return nil, errors.New("unexpected EOF when : was expected")
}
kindToken := s.Scan()
if kindToken == scanner.EOF {
return nil, errors.New("unexpected EOF when a kind value was expected")
}
result.Kinds = append(result.Kinds, s.TokenText())
case "path":
// Path
colonToken := s.Scan()
if colonToken == scanner.EOF {
return nil, errors.New("unexpected EOF when : was expected")
}
pathToken := s.Scan()
if pathToken == scanner.EOF {
return nil, errors.New("unexpected EOF when a path was expected")
}
result.Path = strings.TrimRight(strings.TrimLeft(s.TokenText(), `"`), `"`)
case "#":
// Tag
tagNameToken := s.Scan()
if tagNameToken == scanner.EOF {
return nil, errors.New("unexpected EOF when a tag name was expected")
}
tag := s.TokenText()
for {
v := s.Peek()
if v == scanner.EOF || v != '-' {
break
}
s.Scan() // advance -
tagNameToken := s.Scan()
if tagNameToken == scanner.EOF {
return nil, errors.New("unexpected EOF in the middle of a tag name")
}
tag += "-" + s.TokenText()
}
result.Tags = append(result.Tags, tag)
case "@":
// Attribute
attributeNameToken := s.Scan()
if attributeNameToken == scanner.EOF {
return nil, errors.New("unexpected EOF when a tag name was expected")
}
attributeName := s.TokenText()
colonToken := s.Scan()
if colonToken == scanner.EOF {
return nil, errors.New("unexpected EOF when : was expected")
}
attributeValueToken := s.Scan()
if attributeValueToken == scanner.EOF {
return nil, errors.New("unexpected EOF when an attribute value was expected")
}
result.Attributes[attributeName] = strings.TrimRight(strings.TrimLeft(s.TokenText(), `"`), `"`)
default:
// Term
term := strings.TrimRight(strings.TrimLeft(s.TokenText(), `"`), `"`)
result.Terms = append(result.Terms, term)
}
}
}