1package parser 2 3import ( 4 "strings" 5 "unicode" 6) 7 8// A MakeString is a string that may contain variable substitutions in it. 9// It can be considered as an alternating list of raw Strings and variable 10// substitutions, where the first and last entries in the list must be raw 11// Strings (possibly empty). A MakeString that starts with a variable 12// will have an empty first raw string, and a MakeString that ends with a 13// variable will have an empty last raw string. Two sequential Variables 14// will have an empty raw string between them. 15// 16// The MakeString is stored as two lists, a list of raw Strings and a list 17// of Variables. The raw string list is always one longer than the variable 18// list. 19type MakeString struct { 20 StringPos Pos 21 Strings []string 22 Variables []Variable 23} 24 25func SimpleMakeString(s string, pos Pos) *MakeString { 26 return &MakeString{ 27 StringPos: pos, 28 Strings: []string{s}, 29 } 30} 31 32func (ms *MakeString) Pos() Pos { 33 return ms.StringPos 34} 35 36func (ms *MakeString) End() Pos { 37 pos := ms.StringPos 38 if len(ms.Strings) > 1 { 39 pos = ms.Variables[len(ms.Variables)-1].End() 40 } 41 return Pos(int(pos) + len(ms.Strings[len(ms.Strings)-1])) 42} 43 44func (ms *MakeString) appendString(s string) { 45 if len(ms.Strings) == 0 { 46 ms.Strings = []string{s} 47 return 48 } else { 49 ms.Strings[len(ms.Strings)-1] += s 50 } 51} 52 53func (ms *MakeString) appendVariable(v Variable) { 54 if len(ms.Strings) == 0 { 55 ms.Strings = []string{"", ""} 56 ms.Variables = []Variable{v} 57 } else { 58 ms.Strings = append(ms.Strings, "") 59 ms.Variables = append(ms.Variables, v) 60 } 61} 62 63func (ms *MakeString) appendMakeString(other *MakeString) { 64 last := len(ms.Strings) - 1 65 ms.Strings[last] += other.Strings[0] 66 ms.Strings = append(ms.Strings, other.Strings[1:]...) 67 ms.Variables = append(ms.Variables, other.Variables...) 68} 69 70func (ms *MakeString) Value(scope Scope) string { 71 if len(ms.Strings) == 0 { 72 return "" 73 } else { 74 ret := ms.Strings[0] 75 for i := range ms.Strings[1:] { 76 ret += ms.Variables[i].Value(scope) 77 ret += ms.Strings[i+1] 78 } 79 return ret 80 } 81} 82 83func (ms *MakeString) Dump() string { 84 if len(ms.Strings) == 0 { 85 return "" 86 } else { 87 ret := ms.Strings[0] 88 for i := range ms.Strings[1:] { 89 ret += ms.Variables[i].Dump() 90 ret += ms.Strings[i+1] 91 } 92 return ret 93 } 94} 95 96func (ms *MakeString) Const() bool { 97 return len(ms.Strings) <= 1 98} 99 100func (ms *MakeString) Empty() bool { 101 return len(ms.Strings) == 0 || (len(ms.Strings) == 1 && ms.Strings[0] == "") 102} 103 104func (ms *MakeString) Split(sep string) []*MakeString { 105 return ms.SplitN(sep, -1) 106} 107 108func (ms *MakeString) SplitN(sep string, n int) []*MakeString { 109 ret := []*MakeString{} 110 111 curMs := SimpleMakeString("", ms.Pos()) 112 113 var i int 114 var s string 115 for i, s = range ms.Strings { 116 if n != 0 { 117 split := splitAnyN(s, sep, n) 118 if n != -1 { 119 if len(split) > n { 120 panic("oops!") 121 } else { 122 n -= len(split) 123 } 124 } 125 curMs.appendString(split[0]) 126 127 for _, r := range split[1:] { 128 ret = append(ret, curMs) 129 curMs = SimpleMakeString(r, ms.Pos()) 130 } 131 } else { 132 curMs.appendString(s) 133 } 134 135 if i < len(ms.Strings)-1 { 136 curMs.appendVariable(ms.Variables[i]) 137 } 138 } 139 140 ret = append(ret, curMs) 141 return ret 142} 143 144func (ms *MakeString) TrimLeftSpaces() { 145 l := len(ms.Strings[0]) 146 ms.Strings[0] = strings.TrimLeftFunc(ms.Strings[0], unicode.IsSpace) 147 ms.StringPos += Pos(len(ms.Strings[0]) - l) 148} 149 150func (ms *MakeString) TrimRightSpaces() { 151 last := len(ms.Strings) - 1 152 ms.Strings[last] = strings.TrimRightFunc(ms.Strings[last], unicode.IsSpace) 153} 154 155func (ms *MakeString) TrimRightOne() { 156 last := len(ms.Strings) - 1 157 if len(ms.Strings[last]) > 1 { 158 ms.Strings[last] = ms.Strings[last][0 : len(ms.Strings[last])-1] 159 } 160} 161 162func (ms *MakeString) EndsWith(ch rune) bool { 163 s := ms.Strings[len(ms.Strings)-1] 164 return s[len(s)-1] == uint8(ch) 165} 166 167func splitAnyN(s, sep string, n int) []string { 168 ret := []string{} 169 for n == -1 || n > 1 { 170 index := strings.IndexAny(s, sep) 171 if index >= 0 { 172 ret = append(ret, s[0:index]) 173 s = s[index+1:] 174 if n > 0 { 175 n-- 176 } 177 } else { 178 break 179 } 180 } 181 ret = append(ret, s) 182 return ret 183} 184