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