github.com/Rookout/GoSDK@v0.1.48/pkg/processor/paths/nodes.go (about)

     1  package paths
     2  
     3  import (
     4  	"fmt"
     5  	"go/constant"
     6  	"go/token"
     7  	"go/types"
     8  	"math/big"
     9  	"reflect"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/Rookout/GoSDK/pkg/processor/namespaces"
    14  	"github.com/Rookout/GoSDK/pkg/rookoutErrors"
    15  )
    16  
    17  type Kind = reflect.Kind
    18  
    19  const (
    20  	None = iota + reflect.UnsafePointer + 1
    21  	List
    22  	NamespaceResult
    23  )
    24  
    25  type node interface {
    26  }
    27  
    28  type executableNode interface {
    29  	node
    30  	Execute(namespace namespaces.Namespace) (valueNode, rookoutErrors.RookoutError)
    31  }
    32  
    33  type valueNode interface {
    34  	node
    35  	Kind() Kind
    36  	Interface() interface{}
    37  }
    38  
    39  type optNode struct {
    40  	optStr string
    41  	level  optLevel
    42  	token  token.Token
    43  }
    44  
    45  func newOpt(optStr string) (node, rookoutErrors.RookoutError) {
    46  	o := &optNode{}
    47  	o.optStr = optStr
    48  
    49  	optUpper := strings.ToUpper(o.optStr)
    50  	for key, value := range ArithmeticExpressions {
    51  		if key == optUpper {
    52  			o.optStr = value
    53  			break
    54  		}
    55  	}
    56  
    57  	found := false
    58  	for i := optLevel(0); i < NUM_OF_LEVELS; i++ {
    59  		for j := 0; j < len(optLevelToStr[i]); j++ {
    60  			if o.optStr == optLevelToStr[i][j] {
    61  				o.level = i
    62  				found = true
    63  				break
    64  			}
    65  		}
    66  	}
    67  	if !found {
    68  		return nil, rookoutErrors.NewRookInvalidArithmeticPathException("condition could not be resolved: "+optStr, nil)
    69  	}
    70  
    71  	o.token, _ = strToToken[o.optStr]
    72  
    73  	return o, nil
    74  }
    75  
    76  func newValueNode(val interface{}) valueNode {
    77  	switch val.(type) {
    78  	case nil:
    79  		return newNoneNode()
    80  	case *big.Rat:
    81  		val, _ = val.(*big.Rat).Float64()
    82  		return reflect.ValueOf(val)
    83  	case int64:
    84  		return reflect.ValueOf(int(val.(int64)))
    85  	default:
    86  		return reflect.ValueOf(val)
    87  	}
    88  }
    89  
    90  func valueNodeToConstantValue(val valueNode) (constant.Value, bool) {
    91  	switch val.Kind() {
    92  	case NamespaceResult:
    93  		return valueNodeToConstantValue(newValueNode(val.Interface()))
    94  	case reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8:
    95  		return constant.MakeInt64(val.(reflect.Value).Int()), true
    96  	case reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8:
    97  		return constant.MakeUint64(val.(reflect.Value).Uint()), true
    98  	case reflect.String:
    99  		return constant.MakeString(val.(reflect.Value).String()), true
   100  	case reflect.Float64, reflect.Float32:
   101  		return constant.MakeFloat64(val.(reflect.Value).Float()), true
   102  	case reflect.Bool:
   103  		return constant.MakeBool(val.(reflect.Value).Bool()), true
   104  	default:
   105  		return nil, false
   106  	}
   107  }
   108  
   109  func isOperable(a valueNode, b valueNode) (res bool) {
   110  	defer func() {
   111  		if v := recover(); v != nil {
   112  			res = false
   113  		}
   114  	}()
   115  
   116  	aValue := reflect.ValueOf(a.Interface())
   117  	bValue := reflect.ValueOf(b.Interface())
   118  	aValue.Convert(bValue.Type())
   119  	bValue.Convert(aValue.Type())
   120  	return true
   121  }
   122  
   123  func (o *optNode) evalExpression(a valueNode, b valueNode) (v valueNode, err rookoutErrors.RookoutError) {
   124  	defer func() {
   125  		r := recover()
   126  		if r != nil {
   127  			msg := fmt.Sprintf("unable to evaluate %v %s %v (%v)", a, o.optStr, b, r)
   128  			v = nil
   129  			err = rookoutErrors.NewRookInvalidArithmeticPathException(msg, nil)
   130  		}
   131  	}()
   132  
   133  	aValue, aIsPrimitive := valueNodeToConstantValue(a)
   134  	bValue, bIsPrimitive := valueNodeToConstantValue(b)
   135  
   136  	if !aIsPrimitive || !bIsPrimitive || !isOperable(a, b) {
   137  		aObj := a.Interface()
   138  		bObj := b.Interface()
   139  
   140  		if (aObj == namespaces.ReferenceTypeInstance && bObj != nil) || (bObj == namespaces.ReferenceTypeInstance && aObj != nil) {
   141  			msg := "Comparison of reference types to something other than nil is not supported"
   142  			return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, nil)
   143  		}
   144  
   145  		if aObj == namespaces.StructTypeInstance || bObj == namespaces.StructTypeInstance {
   146  			msg := "Comparison of structs is not supported"
   147  			return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, nil)
   148  		}
   149  
   150  		eq := reflect.DeepEqual(aObj, bObj)
   151  		if (o.optStr == "==" && eq) ||
   152  			(o.optStr == "!=" && !eq) {
   153  			return newValueNode(true), nil
   154  		} else if (o.optStr == "!=" && eq) ||
   155  			(o.optStr == "==" && !eq) {
   156  			return newValueNode(false), nil
   157  		}
   158  
   159  		evaluation := fmt.Sprintf("%v%s%v", a.Interface(), o.optStr, b.Interface())
   160  		res, evalErr := types.Eval(token.NewFileSet(), nil, token.NoPos, evaluation)
   161  		if evalErr != nil {
   162  			msg := fmt.Sprintf("unable to evaluate %s", evaluation)
   163  			return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, evalErr)
   164  		}
   165  		return newValueNode(constant.Val(res.Value)), nil
   166  	}
   167  
   168  	if o.level == COMP {
   169  		res := constant.Compare(aValue, o.token, bValue)
   170  		return newValueNode(res), nil
   171  	} else {
   172  		resVal := constant.BinaryOp(aValue, o.token, bValue)
   173  		return newValueNode(constant.Val(resVal)), nil
   174  	}
   175  }
   176  
   177  func (o *optNode) inExpression(a valueNode, b valueNode) (valueNode, rookoutErrors.RookoutError) {
   178  	switch b.Interface().(type) {
   179  	case []interface{}:
   180  		list := b.Interface().([]interface{})
   181  		for _, v := range list {
   182  			if a.Interface() == v {
   183  				return newValueNode(true), nil
   184  			}
   185  		}
   186  		return newValueNode(false), nil
   187  	case string:
   188  		aStr, ok := a.Interface().(string)
   189  		if !ok {
   190  			return newValueNode(false), nil
   191  		}
   192  
   193  		unquoted, err := strconv.Unquote(aStr)
   194  		if err == nil {
   195  			aStr = unquoted
   196  		}
   197  
   198  		if strings.Contains(b.Interface().(string), aStr) {
   199  			return newValueNode(true), nil
   200  		}
   201  		return newValueNode(false), nil
   202  	default:
   203  		msg := fmt.Sprintf("can't use `in` expression on %v of type %#v", b, b)
   204  		return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, nil)
   205  	}
   206  }
   207  
   208  func (o *optNode) Execute(a valueNode, b valueNode) (valueNode, rookoutErrors.RookoutError) {
   209  	switch o.level {
   210  	case MULDIV, ADDSUB, COMP, AND, OR:
   211  		return o.evalExpression(a, b)
   212  	case IN:
   213  		return o.inExpression(a, b)
   214  	}
   215  	msg := fmt.Sprintf("invalid opt level: %d (%s)", o.level, o.optStr)
   216  	return nil, rookoutErrors.NewRookInvalidArithmeticPathException(msg, nil)
   217  }
   218  
   219  type listNode struct {
   220  	nodes []node
   221  }
   222  
   223  func newListNode(nodes []node) *listNode {
   224  	l := &listNode{}
   225  	l.nodes = nodes
   226  	return l
   227  }
   228  
   229  func (l *listNode) Execute(namespace namespaces.Namespace) (valueNode, rookoutErrors.RookoutError) {
   230  	var err rookoutErrors.RookoutError
   231  	for i, n := range l.nodes {
   232  		if executable, ok := n.(executableNode); ok {
   233  			l.nodes[i], err = executable.Execute(namespace)
   234  			if err != nil {
   235  				return nil, err
   236  			}
   237  		}
   238  	}
   239  	return l, nil
   240  }
   241  
   242  func (l *listNode) Interface() interface{} {
   243  	values := make([]interface{}, 0, len(l.nodes))
   244  	for _, n := range l.nodes {
   245  		if val, ok := n.(valueNode); ok {
   246  			values = append(values, val.Interface())
   247  		}
   248  	}
   249  	return values
   250  }
   251  
   252  func (l *listNode) Kind() Kind {
   253  	return List
   254  }
   255  
   256  type comparisonNode struct {
   257  	left  node
   258  	opt   *optNode
   259  	right node
   260  }
   261  
   262  func newComparisonNode(left node, opt *optNode, right node) node {
   263  	return &comparisonNode{
   264  		left:  left,
   265  		opt:   opt,
   266  		right: right,
   267  	}
   268  }
   269  
   270  func (c *comparisonNode) Execute(namespace namespaces.Namespace) (n valueNode, err rookoutErrors.RookoutError) {
   271  	left := c.left
   272  	right := c.right
   273  	if executable, ok := left.(executableNode); ok {
   274  		left, err = executable.Execute(namespace)
   275  		if err != nil {
   276  			return nil, err
   277  		}
   278  	}
   279  	if executable, ok := right.(executableNode); ok {
   280  		right, err = executable.Execute(namespace)
   281  		if err != nil {
   282  			return nil, err
   283  		}
   284  	}
   285  	return c.opt.Execute(left.(valueNode), right.(valueNode))
   286  }
   287  
   288  type namespaceNode struct {
   289  	operations []pathOperation
   290  }
   291  
   292  func newNamespaceNode(operations []pathOperation) *namespaceNode {
   293  	n := &namespaceNode{}
   294  	n.operations = operations
   295  	return n
   296  }
   297  
   298  func (n *namespaceNode) Execute(namespace namespaces.Namespace) (valueNode, rookoutErrors.RookoutError) {
   299  	if namespace == nil {
   300  		return nil, rookoutErrors.NewRookInvalidArithmeticPathException("unable to Execute namespace operations on nil", nil)
   301  	}
   302  
   303  	var err rookoutErrors.RookoutError
   304  	res := namespace
   305  	for _, path := range n.operations {
   306  		res, err = path.Read(res, false)
   307  		if err != nil {
   308  			return nil, err
   309  		}
   310  	}
   311  
   312  	return newNamespaceResultNode(res), nil
   313  }
   314  
   315  type namespaceResultNode struct {
   316  	namespace namespaces.Namespace
   317  }
   318  
   319  func newNamespaceResultNode(namespace namespaces.Namespace) *namespaceResultNode {
   320  	n := &namespaceResultNode{}
   321  	n.namespace = namespace
   322  	return n
   323  }
   324  
   325  func (n *namespaceResultNode) Kind() Kind {
   326  	return NamespaceResult
   327  }
   328  
   329  func (n *namespaceResultNode) Interface() interface{} {
   330  	return n.namespace.GetObject()
   331  }
   332  
   333  type noneNode struct {
   334  }
   335  
   336  func newNoneNode() *noneNode {
   337  	return &noneNode{}
   338  }
   339  
   340  func (n *noneNode) Kind() Kind {
   341  	return None
   342  }
   343  
   344  func (n *noneNode) Interface() interface{} {
   345  	return nil
   346  }