github.com/bytedance/go-tagexpr/v2@v2.9.8/spec_operand.go (about)

     1  // Copyright 2019 Bytedance Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package tagexpr
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"reflect"
    21  	"regexp"
    22  	"strconv"
    23  	"strings"
    24  
    25  	"github.com/andeya/ameda"
    26  )
    27  
    28  // --------------------------- Operand ---------------------------
    29  
    30  type groupExprNode struct {
    31  	exprBackground
    32  	boolOpposite *bool
    33  	signOpposite *bool
    34  }
    35  
    36  func newGroupExprNode() ExprNode { return &groupExprNode{} }
    37  
    38  func readGroupExprNode(expr *string) (grp ExprNode, subExprNode *string) {
    39  	last, boolOpposite, signOpposite := getBoolAndSignOpposite(expr)
    40  	sptr := readPairedSymbol(&last, '(', ')')
    41  	if sptr == nil {
    42  		return nil, nil
    43  	}
    44  	*expr = last
    45  	e := &groupExprNode{boolOpposite: boolOpposite, signOpposite: signOpposite}
    46  	return e, sptr
    47  }
    48  
    49  func (ge *groupExprNode) String() string {
    50  	return "()"
    51  }
    52  
    53  func (ge *groupExprNode) Run(ctx context.Context, currField string, tagExpr *TagExpr) interface{} {
    54  	if ge.rightOperand == nil {
    55  		return nil
    56  	}
    57  	return realValue(ge.rightOperand.Run(ctx, currField, tagExpr), ge.boolOpposite, ge.signOpposite)
    58  }
    59  
    60  type boolExprNode struct {
    61  	exprBackground
    62  	val bool
    63  }
    64  
    65  func (be *boolExprNode) String() string {
    66  	return fmt.Sprintf("%v", be.val)
    67  }
    68  
    69  var boolRegexp = regexp.MustCompile(`^!*(true|false)([\)\],\|&!= \t]{1}|$)`)
    70  
    71  func readBoolExprNode(expr *string) ExprNode {
    72  	s := boolRegexp.FindString(*expr)
    73  	if s == "" {
    74  		return nil
    75  	}
    76  	last := s[len(s)-1]
    77  	if last != 'e' {
    78  		s = s[:len(s)-1]
    79  	}
    80  	*expr = (*expr)[len(s):]
    81  	e := &boolExprNode{}
    82  	if strings.Contains(s, "t") {
    83  		e.val = (len(s)-4)&1 == 0
    84  	} else {
    85  		e.val = (len(s)-5)&1 == 1
    86  	}
    87  	return e
    88  }
    89  
    90  func (be *boolExprNode) Run(ctx context.Context, currField string, tagExpr *TagExpr) interface{} {
    91  	return be.val
    92  }
    93  
    94  type stringExprNode struct {
    95  	exprBackground
    96  	val interface{}
    97  }
    98  
    99  func (se *stringExprNode) String() string {
   100  	return fmt.Sprintf("%v", se.val)
   101  }
   102  
   103  func readStringExprNode(expr *string) ExprNode {
   104  	last, boolOpposite, _ := getBoolAndSignOpposite(expr)
   105  	sptr := readPairedSymbol(&last, '\'', '\'')
   106  	if sptr == nil {
   107  		return nil
   108  	}
   109  	*expr = last
   110  	e := &stringExprNode{val: realValue(*sptr, boolOpposite, nil)}
   111  	return e
   112  }
   113  
   114  func (se *stringExprNode) Run(ctx context.Context, currField string, tagExpr *TagExpr) interface{} {
   115  	return se.val
   116  }
   117  
   118  type digitalExprNode struct {
   119  	exprBackground
   120  	val interface{}
   121  }
   122  
   123  func (de *digitalExprNode) String() string {
   124  	return fmt.Sprintf("%v", de.val)
   125  }
   126  
   127  var digitalRegexp = regexp.MustCompile(`^[\+\-]?\d+(\.\d+)?([\)\],\+\-\*\/%><\|&!=\^ \t\\]|$)`)
   128  
   129  func readDigitalExprNode(expr *string) ExprNode {
   130  	last, boolOpposite := getOpposite(expr, "!")
   131  	s := digitalRegexp.FindString(last)
   132  	if s == "" {
   133  		return nil
   134  	}
   135  	if r := s[len(s)-1]; r < '0' || r > '9' {
   136  		s = s[:len(s)-1]
   137  	}
   138  	*expr = last[len(s):]
   139  	f64, _ := strconv.ParseFloat(s, 64)
   140  	return &digitalExprNode{val: realValue(f64, boolOpposite, nil)}
   141  }
   142  
   143  func (de *digitalExprNode) Run(ctx context.Context, currField string, tagExpr *TagExpr) interface{} {
   144  	return de.val
   145  }
   146  
   147  type nilExprNode struct {
   148  	exprBackground
   149  	val interface{}
   150  }
   151  
   152  func (ne *nilExprNode) String() string {
   153  	return "<nil>"
   154  }
   155  
   156  var nilRegexp = regexp.MustCompile(`^nil([\)\],\|&!= \t]{1}|$)`)
   157  
   158  func readNilExprNode(expr *string) ExprNode {
   159  	last, boolOpposite := getOpposite(expr, "!")
   160  	s := nilRegexp.FindString(last)
   161  	if s == "" {
   162  		return nil
   163  	}
   164  	*expr = last[3:]
   165  	return &nilExprNode{val: realValue(nil, boolOpposite, nil)}
   166  }
   167  
   168  func (ne *nilExprNode) Run(ctx context.Context, currField string, tagExpr *TagExpr) interface{} {
   169  	return ne.val
   170  }
   171  
   172  func getBoolAndSignOpposite(expr *string) (last string, boolOpposite *bool, signOpposite *bool) {
   173  	last = strings.TrimLeft(last, "+")
   174  	last, boolOpposite = getOpposite(expr, "!")
   175  	last = strings.TrimLeft(last, "+")
   176  	last, signOpposite = getOpposite(&last, "-")
   177  	last = strings.TrimLeft(last, "+")
   178  	return
   179  }
   180  
   181  func getOpposite(expr *string, cutset string) (string, *bool) {
   182  	last := strings.TrimLeft(*expr, cutset)
   183  	n := len(*expr) - len(last)
   184  	if n == 0 {
   185  		return last, nil
   186  	}
   187  	bol := n&1 == 1
   188  	return last, &bol
   189  }
   190  
   191  func toString(i interface{}, enforce bool) (string, bool) {
   192  	switch vv := i.(type) {
   193  	case string:
   194  		return vv, true
   195  	case nil:
   196  		return "", false
   197  	default:
   198  		rv := ameda.DereferenceValue(reflect.ValueOf(i))
   199  		if rv.Kind() == reflect.String {
   200  			return rv.String(), true
   201  		}
   202  		if enforce {
   203  			if rv.IsValid() && rv.CanInterface() {
   204  				return fmt.Sprint(rv.Interface()), true
   205  			} else {
   206  				return fmt.Sprint(i), true
   207  			}
   208  		}
   209  	}
   210  	return "", false
   211  }
   212  
   213  func toFloat64(i interface{}, tryParse bool) (float64, bool) {
   214  	var v float64
   215  	var ok = true
   216  	switch t := i.(type) {
   217  	case float64:
   218  		v = t
   219  	case float32:
   220  		v = float64(t)
   221  	case int:
   222  		v = float64(t)
   223  	case int8:
   224  		v = float64(t)
   225  	case int16:
   226  		v = float64(t)
   227  	case int32:
   228  		v = float64(t)
   229  	case int64:
   230  		v = float64(t)
   231  	case uint:
   232  		v = float64(t)
   233  	case uint8:
   234  		v = float64(t)
   235  	case uint16:
   236  		v = float64(t)
   237  	case uint32:
   238  		v = float64(t)
   239  	case uint64:
   240  		v = float64(t)
   241  	case nil:
   242  		ok = false
   243  	default:
   244  		rv := ameda.DereferenceValue(reflect.ValueOf(t))
   245  		switch rv.Kind() {
   246  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   247  			v = float64(rv.Int())
   248  		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   249  			v = float64(rv.Uint())
   250  		case reflect.Float32, reflect.Float64:
   251  			v = rv.Float()
   252  		default:
   253  			if tryParse {
   254  				if s, ok := toString(i, false); ok {
   255  					var err error
   256  					v, err = strconv.ParseFloat(s, 64)
   257  					return v, err == nil
   258  				}
   259  			}
   260  			ok = false
   261  		}
   262  	}
   263  	return v, ok
   264  }
   265  
   266  func realValue(v interface{}, boolOpposite *bool, signOpposite *bool) interface{} {
   267  	if boolOpposite != nil {
   268  		bol := FakeBool(v)
   269  		if *boolOpposite {
   270  			return !bol
   271  		}
   272  		return bol
   273  	}
   274  	switch t := v.(type) {
   275  	case float64, string:
   276  	case float32:
   277  		v = float64(t)
   278  	case int:
   279  		v = float64(t)
   280  	case int8:
   281  		v = float64(t)
   282  	case int16:
   283  		v = float64(t)
   284  	case int32:
   285  		v = float64(t)
   286  	case int64:
   287  		v = float64(t)
   288  	case uint:
   289  		v = float64(t)
   290  	case uint8:
   291  		v = float64(t)
   292  	case uint16:
   293  		v = float64(t)
   294  	case uint32:
   295  		v = float64(t)
   296  	case uint64:
   297  		v = float64(t)
   298  	case []interface{}:
   299  		for k, v := range t {
   300  			t[k] = realValue(v, boolOpposite, signOpposite)
   301  		}
   302  	default:
   303  		rv := ameda.DereferenceValue(reflect.ValueOf(v))
   304  		switch rv.Kind() {
   305  		case reflect.String:
   306  			v = rv.String()
   307  		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   308  			v = float64(rv.Int())
   309  		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   310  			v = float64(rv.Uint())
   311  		case reflect.Float32, reflect.Float64:
   312  			v = rv.Float()
   313  		}
   314  	}
   315  	if signOpposite != nil && *signOpposite {
   316  		if f, ok := v.(float64); ok {
   317  			v = -f
   318  		}
   319  	}
   320  	return v
   321  }