-
-
Notifications
You must be signed in to change notification settings - Fork 273
/
scripttemplateparser.go
121 lines (99 loc) · 3.48 KB
/
scripttemplateparser.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
package parser
import (
"io"
"strings"
"github.com/a-h/lexical/parse"
)
func newScriptTemplateParser() scriptTemplateParser {
return scriptTemplateParser{}
}
type scriptTemplateParser struct {
}
var endScriptParser = createEndParser("endscript") // {% endscript %}
func (p scriptTemplateParser) Parse(pi parse.Input) parse.Result {
var r ScriptTemplate
// Parse the name.
pr := newScriptExpressionParser().Parse(pi)
if !pr.Success {
return pr
}
r.Name = pr.Item.(scriptExpression).Name
r.Parameters = pr.Item.(scriptExpression).Parameters
from := NewPositionFromInput(pi)
// Read until {% endscript %}
sr := parse.StringUntil(endScriptParser)(pi)
if sr.Error != nil {
return sr
}
if sr.Success {
r.Value = sr.Item.(string)
}
// Eat the final {% endscript %}
if endScriptParser(pi).Success {
return parse.Success("script", r, nil)
}
return parse.Failure("script", newParseError("expected {% endscript %} not found", from, NewPositionFromInput(pi)))
}
// {% script Func() %}
type scriptExpression struct {
Name Expression
Parameters Expression
}
func newScriptExpressionParser() scriptExpressionParser {
return scriptExpressionParser{}
}
type scriptExpressionParser struct {
}
var scriptExpressionNameParser = parse.All(parse.WithStringConcatCombiner,
parse.Letter,
parse.Many(parse.WithStringConcatCombiner, 0, 1000, parse.Any(parse.Letter, parse.ZeroToNine)),
)
var scriptExpressionStartParser = createStartParser("script")
func (p scriptExpressionParser) Parse(pi parse.Input) parse.Result {
var r scriptExpression
// Check the prefix first.
prefixResult := scriptExpressionStartParser(pi)
if !prefixResult.Success {
return prefixResult
}
// Once we have the prefix, we must have a name and parameters.
// Read the name of the function.
from := NewPositionFromInput(pi)
pr := scriptExpressionNameParser(pi)
if pr.Error != nil && pr.Error != io.EOF {
return pr
}
// If there's no match, the name wasn't correctly terminated.
if !pr.Success {
return parse.Failure("scriptExpressionParser", newParseError("script expression: invalid name", from, NewPositionFromInput(pi)))
}
to := NewPositionFromInput(pi)
r.Name = NewExpression(pr.Item.(string), from, to)
from = to
// Eat the open bracket.
if lb := parse.Rune('(')(pi); !lb.Success {
return parse.Failure("scriptExpressionParser", newParseError("script expression: parameters missing open bracket", from, NewPositionFromInput(pi)))
}
// Read the parameters.
from = NewPositionFromInput(pi)
pr = parse.StringUntil(parse.Rune(')'))(pi) // p Person, other Other, t thing.Thing)
if pr.Error != nil && pr.Error != io.EOF {
return pr
}
// If there's no match, the name wasn't correctly terminated.
if !pr.Success {
return parse.Failure("scriptExpressionParser", newParseError("script expression: parameters missing close bracket", from, NewPositionFromInput(pi)))
}
r.Parameters = NewExpression(strings.TrimSuffix(pr.Item.(string), ")"), from, NewPositionFromInput(pi))
// Eat ") %}".
from = NewPositionFromInput(pi)
if lb := expressionFuncEnd(pi); !lb.Success {
return parse.Failure("scriptExpressionParser", newParseError("script expression: unterminated (missing ') %}')", from, NewPositionFromInput(pi)))
}
// Expect a newline.
from = NewPositionFromInput(pi)
if lb := newLine(pi); !lb.Success {
return parse.Failure("scriptExpressionParser", newParseError("script expression: missing terminating newline", from, NewPositionFromInput(pi)))
}
return parse.Success("scriptExpressionParser", r, nil)
}