github.com/bytedance/go-tagexpr@v2.7.5-0.20210114074101-de5b8743ad85+incompatible/tagparser.go (about) 1 package tagexpr 2 3 import ( 4 "fmt" 5 "strings" 6 "unicode" 7 ) 8 9 type namedTagExpr struct { 10 exprSelector string 11 expr *Expr 12 } 13 14 const ( 15 tagOmit = "-" 16 tagOmitNil = "?" 17 ) 18 19 func (f *fieldVM) parseExprs(tag string) error { 20 switch tag { 21 case tagOmit, tagOmitNil: 22 f.tagOp = tag 23 return nil 24 } 25 26 kvs, err := parseTag(tag) 27 if err != nil { 28 return err 29 } 30 exprSelectorPrefix := f.structField.Name 31 32 for exprSelector, exprString := range kvs { 33 expr, err := parseExpr(exprString) 34 if err != nil { 35 return err 36 } 37 if exprSelector == ExprNameSeparator { 38 exprSelector = exprSelectorPrefix 39 } else { 40 exprSelector = exprSelectorPrefix + ExprNameSeparator + exprSelector 41 } 42 f.exprs[exprSelector] = expr 43 f.origin.exprs[exprSelector] = expr 44 f.origin.exprSelectorList = append(f.origin.exprSelectorList, exprSelector) 45 } 46 return nil 47 } 48 49 func parseTag(tag string) (map[string]string, error) { 50 s := tag 51 ptr := &s 52 kvs := make(map[string]string) 53 for { 54 one, err := readOneExpr(ptr) 55 if err != nil { 56 return nil, err 57 } 58 if one == "" { 59 return kvs, nil 60 } 61 key, val := splitExpr(one) 62 if val == "" { 63 return nil, fmt.Errorf("%q (syntax error): expression string can not be empty", tag) 64 } 65 if _, ok := kvs[key]; ok { 66 return nil, fmt.Errorf("%q (syntax error): duplicate expression name %q", tag, key) 67 } 68 kvs[key] = val 69 } 70 } 71 72 func splitExpr(one string) (key, val string) { 73 one = strings.TrimSpace(one) 74 if one == "" { 75 return DefaultExprName, "" 76 } 77 var rs []rune 78 for _, r := range one { 79 if r == '@' || 80 r == '_' || 81 (r >= '0' && r <= '9') || 82 (r >= 'A' && r <= 'Z') || 83 (r >= 'a' && r <= 'z') { 84 rs = append(rs, r) 85 } else { 86 break 87 } 88 } 89 key = string(rs) 90 val = strings.TrimSpace(one[len(key):]) 91 if val == "" || val[0] != ':' { 92 return DefaultExprName, one 93 } 94 val = val[1:] 95 if key == "" { 96 key = DefaultExprName 97 } 98 return key, val 99 } 100 101 func readOneExpr(tag *string) (string, error) { 102 var s = *(trimRightSpace(trimLeftSpace(tag))) 103 s = strings.TrimLeft(s, ";") 104 if s == "" { 105 return "", nil 106 } 107 if s[len(s)-1] != ';' { 108 s += ";" 109 } 110 a := strings.SplitAfter(strings.Replace(s, "\\'", "##", -1), ";") 111 var idx = -1 112 var patch int 113 for _, v := range a { 114 idx += len(v) 115 count := strings.Count(v, "'") 116 if (count+patch)%2 == 0 { 117 *tag = s[idx+1:] 118 return s[:idx], nil 119 } 120 if count > 0 { 121 patch++ 122 } 123 } 124 return "", fmt.Errorf("%q (syntax error): unclosed single quote \"'\"", s) 125 } 126 127 func trimLeftSpace(p *string) *string { 128 *p = strings.TrimLeftFunc(*p, unicode.IsSpace) 129 return p 130 } 131 132 func trimRightSpace(p *string) *string { 133 *p = strings.TrimRightFunc(*p, unicode.IsSpace) 134 return p 135 } 136 137 func readPairedSymbol(p *string, left, right rune) *string { 138 s := *p 139 if len(s) == 0 || rune(s[0]) != left { 140 return nil 141 } 142 s = s[1:] 143 var last1 = left 144 var last2 rune 145 var leftLevel, rightLevel int 146 var escapeIndexes = make(map[int]bool) 147 var realEqual, escapeEqual bool 148 for i, r := range s { 149 if realEqual, escapeEqual = equalRune(right, r, last1, last2); realEqual { 150 if leftLevel == rightLevel { 151 *p = s[i+1:] 152 var sub = make([]rune, 0, i) 153 for k, v := range s[:i] { 154 if !escapeIndexes[k] { 155 sub = append(sub, v) 156 } 157 } 158 s = string(sub) 159 return &s 160 } 161 rightLevel++ 162 } else if escapeEqual { 163 escapeIndexes[i-1] = true 164 } else if realEqual, escapeEqual = equalRune(left, r, last1, last2); realEqual { 165 leftLevel++ 166 } else if escapeEqual { 167 escapeIndexes[i-1] = true 168 } 169 last2 = last1 170 last1 = r 171 } 172 return nil 173 } 174 175 func equalRune(a, b, last1, last2 rune) (real, escape bool) { 176 if a == b { 177 real = last1 != '\\' || last2 == '\\' 178 escape = last1 == '\\' && last2 != '\\' 179 } 180 return 181 }