-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.go
104 lines (87 loc) · 2.88 KB
/
parser.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
package cronlex
import (
"github.com/zalgonoise/parse"
)
// ParseFunc is the second and middle phase of the parser, which consumes a parse.Tree scoped to Token and byte,
// in tandem with StateFunc, as a lexer-parser state-machine strategy.
//
// This function continuously consumes tokens emitted by the StateFunc lexer portion of the logic, and organizes them
// in an abstract syntax tree. This AST is then processed into a Schedule through the ProcessFunc sequence, as a
// parse.Run function call.
//
// The AST keeps a top-level node that branches into several nodes, representative of the number of top-level child
// nodes in the cron string ("* * * * *" means there are 5 top-level child nodes; "@weekly" means there is 1 top-level
// child node). If a given top-level child node contains more information than a single value (e.g. ranges, sets), then
// the top-level child node will be the parent to more nodes containing any Token chained to that top-level child node.
func ParseFunc(t *parse.Tree[Token, byte]) parse.ParseFn[Token, byte] {
switch t.Peek().Type {
case TokenAt:
return parseAt
case TokenStar:
return parseStar
case TokenAlphaNum:
return parseAlphanum
case TokenEOF:
return nil
default:
return nil
}
}
func parseAt(t *parse.Tree[Token, byte]) parse.ParseFn[Token, byte] {
t.Node(t.Next())
switch t.Peek().Type {
case TokenAlphaNum:
return parseAlphanum
default:
//nolint:errcheck // call will not return a meaningful error; tree is still validated in the end
_ = t.Set(t.Parent())
return ParseFunc
}
}
func parseStar(t *parse.Tree[Token, byte]) parse.ParseFn[Token, byte] {
t.Node(t.Next())
switch t.Peek().Type {
case TokenSpace:
//nolint:errcheck // call will not return a meaningful error; tree is still validated in the end
_ = t.Set(t.Parent())
t.Next()
return ParseFunc
case TokenSlash:
return parseAlphanum
default:
//nolint:errcheck // call will not return a meaningful error; tree is still validated in the end
_ = t.Set(t.Parent())
return nil
}
}
func parseAlphanumSymbols(t *parse.Tree[Token, byte]) parse.ParseFn[Token, byte] {
t.Node(t.Next())
switch t.Peek().Type {
case TokenAlphaNum:
t.Node(t.Next())
//nolint:errcheck // call will not return a meaningful error; tree is still validated in the end
_ = t.Set(t.Parent().Parent)
return parseAlphanum
default:
item := t.Next()
item.Type = TokenError
t.Node(item)
return ParseFunc
}
}
func parseAlphanum(t *parse.Tree[Token, byte]) parse.ParseFn[Token, byte] {
//nolint:exhaustive // no need to check on all token types
switch t.Peek().Type {
case TokenAlphaNum:
t.Node(t.Next())
return parseAlphanum
case TokenComma, TokenDash, TokenSlash:
return parseAlphanumSymbols
case TokenSpace:
//nolint:errcheck // call will not return a meaningful error; tree is still validated in the end
_ = t.Set(t.Parent())
t.Next()
return ParseFunc
}
return nil
}