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  }