-
Notifications
You must be signed in to change notification settings - Fork 13
/
builder.go
108 lines (92 loc) · 1.99 KB
/
builder.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
package variable
import (
"strings"
"github.com/eolinker/eosc"
)
const (
dollarSign = 36 // $
leftSign = 123 // {
rightSign = 125 // }
)
const (
//CurrentStatus 普通状态
CurrentStatus = iota
//ReadyStatus 预备状态
ReadyStatus
//InputStatus 输入状态
InputStatus
//EndInputStatus 结束输入状态
EndInputStatus
)
func NewBuilder(str string) *Builder {
return &Builder{str: str}
}
type Builder struct {
str string
//separator string
//defaultSuffix string
}
func (b *Builder) Replace(variables eosc.IVariable) (string, []string, bool) {
strBuilder := strings.Builder{}
varBuilder := strings.Builder{}
status := CurrentStatus
startIndex := 0
useVariable := make([]string, 0, variables.Len())
for i, s := range b.str {
oldStatus := status
status = toggleStatus(status, s)
switch status {
case CurrentStatus:
if oldStatus == ReadyStatus {
strBuilder.WriteString(b.str[startIndex : i+1])
startIndex = i + 1
continue
}
strBuilder.WriteRune(s)
case ReadyStatus:
startIndex = i
case InputStatus:
if oldStatus == ReadyStatus {
// 刚切换状态,忽略此时的字符
continue
}
varBuilder.WriteRune(s)
case EndInputStatus:
id := varBuilder.String()
v, ok := variables.Get(id)
if !ok {
// 变量不存在,报错
return "", nil, false
}
useVariable = append(useVariable, id)
strBuilder.WriteString(v)
varBuilder.Reset()
startIndex = i + 1
status = CurrentStatus
}
}
if status == InputStatus || status == ReadyStatus {
strBuilder.WriteString(b.str[startIndex:])
}
return strBuilder.String(), useVariable, true
}
func toggleStatus(status int, c rune) int {
switch status {
case CurrentStatus, EndInputStatus:
if c == dollarSign {
return ReadyStatus
}
return CurrentStatus
case ReadyStatus:
if c == leftSign {
return InputStatus
}
return CurrentStatus
case InputStatus:
if c == rightSign {
return EndInputStatus
}
return InputStatus
}
return status
}