-
-
Notifications
You must be signed in to change notification settings - Fork 233
/
ifexpressionparser.go
142 lines (114 loc) · 4.15 KB
/
ifexpressionparser.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
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
package parser
import (
"github.com/a-h/parse"
)
var ifExpression ifExpressionParser
var untilElseIfElseOrEnd = parse.Any(StripType(elseIfExpression), StripType(elseExpression), StripType(closeBraceWithOptionalPadding))
type ifExpressionParser struct{}
func (ifExpressionParser) Parse(pi *parse.Input) (n Node, ok bool, err error) {
// Check the prefix first.
if _, ok, err = parse.String("if ").Parse(pi); err != nil || !ok {
return
}
// Once we've got a prefix, read until {\n.
// If there's no match, there's no {\n, which is an error.
var r IfExpression
until := parse.All(openBraceWithOptionalPadding, parse.NewLine)
if r.Expression, ok, err = ExpressionOf(parse.StringUntil(until)).Parse(pi); err != nil || !ok {
err = parse.Error("if: "+unterminatedMissingCurly, pi.Position())
return
}
// Eat " {\n".
if _, ok, err = until.Parse(pi); err != nil || !ok {
err = parse.Error("if: "+unterminatedMissingCurly, pi.Position())
return
}
// Once we've had the start of an if block, we must conclude the block.
// Read the 'Then' nodes.
// If there's no match, there's a problem in the template nodes.
np := newTemplateNodeParser(untilElseIfElseOrEnd, "else expression or closing brace")
var thenNodes Nodes
if thenNodes, ok, err = np.Parse(pi); err != nil || !ok {
err = parse.Error("if: expected nodes, but none were found", pi.Position())
return
}
r.Then = thenNodes.Nodes
r.Diagnostics = append(r.Diagnostics, thenNodes.Diagnostics...)
// Read the optional 'ElseIf' Nodes.
if r.ElseIfs, _, err = parse.ZeroOrMore(elseIfExpression).Parse(pi); err != nil {
return
}
// Read the optional 'Else' Nodes.
var elseNodes Nodes
if elseNodes, _, err = elseExpression.Parse(pi); err != nil {
return
}
r.Else = elseNodes.Nodes
r.Diagnostics = append(r.Diagnostics, elseNodes.Diagnostics...)
// Read the required closing brace.
if _, ok, err = closeBraceWithOptionalPadding.Parse(pi); err != nil || !ok {
err = parse.Error("if: "+unterminatedMissingEnd, pi.Position())
return
}
return r, true, nil
}
var elseIfExpression parse.Parser[ElseIfExpression] = elseIfExpressionParser{}
type elseIfExpressionParser struct{}
func (elseIfExpressionParser) Parse(pi *parse.Input) (r ElseIfExpression, ok bool, err error) {
// Check the prefix first.
if _, ok, err = parse.All(
parse.OptionalWhitespace,
closeBrace,
parse.OptionalWhitespace,
parse.String("else if"),
parse.Whitespace).Parse(pi); err != nil || !ok {
return
}
// Once we've got a prefix, read until {\n.
// If there's no match, there's no {\n, which is an error.
until := parse.All(openBraceWithOptionalPadding, parse.NewLine)
if r.Expression, ok, err = ExpressionOf(parse.StringUntil(until)).Parse(pi); err != nil || !ok {
err = parse.Error("if: unterminated else if (missing closing '{\n')", pi.Position())
return
}
// Eat " {\n".
if _, ok, err = until.Parse(pi); err != nil || !ok {
err = parse.Error("if: unterminated (missing closing '{')", pi.Position())
return
}
// Once we've had the start of an if block, we must conclude the block.
// Read the 'Then' nodes.
// If there's no match, there's a problem in the template nodes.
np := newTemplateNodeParser(untilElseIfElseOrEnd, "else expression or closing brace")
var thenNodes Nodes
if thenNodes, ok, err = np.Parse(pi); err != nil || !ok {
err = parse.Error("if: expected nodes, but none were found", pi.Position())
return
}
r.Then = thenNodes.Nodes
r.Diagnostics = append(r.Diagnostics, thenNodes.Diagnostics...)
return r, true, nil
}
var endElseParser = parse.All(
parse.Rune('}'),
parse.OptionalWhitespace,
parse.String("else"),
parse.OptionalWhitespace,
parse.Rune('{'),
parse.OptionalWhitespace)
var elseExpression parse.Parser[Nodes] = elseExpressionParser{}
type elseExpressionParser struct{}
func (elseExpressionParser) Parse(in *parse.Input) (r Nodes, ok bool, err error) {
start := in.Index()
// } else {
if _, ok, err = endElseParser.Parse(in); err != nil || !ok {
in.Seek(start)
return
}
// Else contents
if r, ok, err = newTemplateNodeParser(closeBraceWithOptionalPadding, "else expression closing brace").Parse(in); err != nil || !ok {
in.Seek(start)
return
}
return r, true, nil
}