forked from rockintest/rocktest-go
/
stringSubstitutor.go
148 lines (129 loc) · 2.7 KB
/
stringSubstitutor.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
143
144
145
146
147
148
package text
import (
"bytes"
)
const (
START = iota
DOLLAR
BRACKET
DOLLARBRACKET
ANTISLASH
ANTISLASHBRACKET
)
type StringSubstitutor struct {
lookup Lookuper
state int
level int
}
func (subst *StringSubstitutor) Replace(s string) (string, error) {
subst.state = START
subst.level = -1
var ret bytes.Buffer
var varName []bytes.Buffer = make([]bytes.Buffer, 10)
for _, r := range s {
c := string(r)
switch subst.state {
case START:
switch c {
case "$":
subst.state = DOLLAR
case "\\":
subst.state = ANTISLASH
default:
ret.WriteString(c)
}
case ANTISLASH:
switch c {
case "$":
subst.state = START
ret.WriteString(c)
default:
subst.state = START
ret.WriteString("\\" + c)
}
case DOLLAR:
switch c {
case "{":
subst.level++
subst.state = BRACKET
case "$":
ret.WriteString(c)
subst.state = START
default:
ret.WriteString("$")
ret.WriteString(c)
subst.state = START
}
case DOLLARBRACKET:
switch c {
case "{":
subst.level++
subst.state = BRACKET
case "$":
varName[subst.level].WriteString(c)
subst.state = BRACKET
default:
varName[subst.level].WriteString("$")
varName[subst.level].WriteString(c)
subst.state = BRACKET
}
case ANTISLASHBRACKET:
switch c {
case "{", "}":
varName[subst.level].WriteString(c)
subst.state = BRACKET
default:
varName[subst.level].WriteString("\\" + c)
subst.state = BRACKET
}
case BRACKET:
switch c {
case "$":
subst.state = DOLLARBRACKET
case "\\":
subst.state = ANTISLASHBRACKET
case "}":
varNameString := varName[subst.level].String()
varName[subst.level].Reset()
subst.level--
// Last closing bracket ?
if subst.level == -1 {
varValue, ok, err := subst.lookup.Lookup(varNameString)
if err != nil {
return "", err
}
if ok {
ret.WriteString(varValue)
} else {
ret.WriteString("${" + varNameString + "}")
}
subst.state = START
} else {
varValue, ok, err := subst.lookup.Lookup(varNameString)
if err != nil {
return "", err
}
if ok {
varName[subst.level].WriteString(varValue)
} else {
varName[subst.level].WriteString("${" + varNameString + "}")
}
}
default:
varName[subst.level].WriteString(c)
}
}
}
return ret.String(), nil
}
func NewStringSubstitutorByLookuper(lookup Lookuper) *StringSubstitutor {
ret := new(StringSubstitutor)
ret.state = START
ret.lookup = lookup
return ret
}
func NewStringSubstitutorByMap(themap map[string]string) *StringSubstitutor {
mapLookup := NewMapLookup(themap)
ret := NewStringSubstitutorByLookuper(mapLookup)
return ret
}