go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/mqlc/parser/operators.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package parser
     5  
     6  import "errors"
     7  
     8  // Operator list
     9  type Operator int
    10  
    11  const (
    12  	// strictly following the javascript operator precedence
    13  	OpAssignment Operator = iota + 30
    14  	OpOr         Operator = iota + 60
    15  	OpAnd        Operator = iota + 70
    16  	OpEqual      Operator = iota + 100
    17  	OpCmp
    18  	OpNotEqual
    19  	OpNotCmp
    20  	OpSmaller Operator = iota + 110
    21  	OpSmallerEqual
    22  	OpGreater
    23  	OpGreaterEqual
    24  	OpAdd Operator = iota + 130
    25  	OpSubtract
    26  	OpMultiply Operator = iota + 140
    27  	OpDivide
    28  	OpRemainder
    29  )
    30  
    31  var operatorsMap = map[string]Operator{
    32  	"=":  OpAssignment,
    33  	"&&": OpAnd,
    34  	"||": OpOr,
    35  	"==": OpEqual,
    36  	"=~": OpCmp,
    37  	"!=": OpNotEqual,
    38  	"!~": OpNotCmp,
    39  	"<":  OpSmaller,
    40  	"<=": OpSmallerEqual,
    41  	">":  OpGreater,
    42  	">=": OpGreaterEqual,
    43  	"+":  OpAdd,
    44  	"-":  OpSubtract,
    45  	"*":  OpMultiply,
    46  	"/":  OpDivide,
    47  	"%":  OpRemainder,
    48  }
    49  
    50  var operatorsStrings map[Operator]string
    51  
    52  func init() {
    53  	operatorsStrings = make(map[Operator]string)
    54  	for k, v := range operatorsMap {
    55  		operatorsStrings[v] = k
    56  	}
    57  }
    58  
    59  // Capture an operator in participle
    60  func (o *Operator) Capture(s []string) error {
    61  	// capture both tokens
    62  	sop := s[0]
    63  	if len(s) == 2 {
    64  		sop += s[1]
    65  	}
    66  
    67  	*o = operatorsMap[sop]
    68  	return nil
    69  }
    70  
    71  func (o *Operator) String() string {
    72  	r, ok := operatorsStrings[*o]
    73  	if !ok {
    74  		return "unknown operator"
    75  	}
    76  	return r
    77  }
    78  
    79  // processOperators handles simple ops like ==, >=, *, ...
    80  // and turns them into functions; only on the level of this expression and its
    81  // Operations children, not deeper function calls
    82  func (e *Expression) processOperators() error {
    83  	if len(e.Operations) == 0 {
    84  		return nil
    85  	}
    86  
    87  	if e.Operand == nil {
    88  		return errors.New("expression doesn't have any operand, i.e. it has been parsed without a body")
    89  	}
    90  
    91  	// group operators into precedence (matchOp as the cut-off line)
    92  	// check if every value has an operator (since they are all linked)
    93  	// and cycle through all calls and process their parameters too
    94  	maxOp := 0
    95  	for idx := range e.Operations {
    96  		v := e.Operations[idx]
    97  		if maxOp < int(v.Operator) {
    98  			maxOp = int(v.Operator)
    99  		}
   100  	}
   101  	matchOp := maxOp - (maxOp % 10)
   102  
   103  	first := []*Operation{{Operand: e.Operand}}
   104  	allOps := append(first, e.Operations...)
   105  	nuOps := first
   106  	for idx := 1; idx < len(allOps); idx++ {
   107  		v := allOps[idx]
   108  		if int(v.Operator) < matchOp {
   109  			nuOps = append(nuOps, allOps[idx])
   110  			continue
   111  		}
   112  
   113  		prevIdx := len(nuOps) - 1
   114  		prev := nuOps[prevIdx]
   115  		op := v.Operator.String()
   116  		cur := &Operation{
   117  			Operator: prev.Operator,
   118  			Operand: &Operand{
   119  				Value: &Value{Ident: &op},
   120  				Calls: []*Call{{Function: []*Arg{
   121  					{Value: &Expression{Operand: prev.Operand}},
   122  					{Value: &Expression{Operand: v.Operand}},
   123  				}}},
   124  			},
   125  		}
   126  		nuOps[prevIdx] = cur
   127  	}
   128  
   129  	e.Operand = nuOps[0].Operand
   130  	e.Operations = nuOps[1:]
   131  	return e.processOperators()
   132  }
   133  
   134  // processChildOperators of all block, accessor, and function child calls
   135  func (e *Expression) processChildOperators() error {
   136  	ops := append([]*Operation{{Operand: e.Operand}}, e.Operations...)
   137  
   138  	// tackle all command calls recursively
   139  	for i := range ops {
   140  		v := ops[i].Operand
   141  		if v == nil {
   142  			return errors.New("missing operand in child block")
   143  		}
   144  
   145  		if v.Value != nil {
   146  			for j := range v.Value.Array {
   147  				if err := v.Value.Array[j].ProcessOperators(); err != nil {
   148  					return err
   149  				}
   150  			}
   151  
   152  			for _, vv := range v.Value.Map {
   153  				if err := vv.ProcessOperators(); err != nil {
   154  					return err
   155  				}
   156  			}
   157  		}
   158  
   159  		for fi := range v.Block {
   160  			if err := v.Block[fi].ProcessOperators(); err != nil {
   161  				return err
   162  			}
   163  		}
   164  
   165  		for fi := range v.Calls {
   166  			if err := v.Calls[fi].Accessor.ProcessOperators(); err != nil {
   167  				return err
   168  			}
   169  
   170  			args := v.Calls[fi].Function
   171  			for ffi := range args {
   172  				if err := args[ffi].Value.ProcessOperators(); err != nil {
   173  					return err
   174  				}
   175  			}
   176  		}
   177  	}
   178  	return nil
   179  }
   180  
   181  // ProcessOperators of this expression and all its children recursively
   182  // and make everything be a flat expression with function calls only
   183  func (e *Expression) ProcessOperators() error {
   184  	if e == nil {
   185  		return nil
   186  	}
   187  	if err := e.processChildOperators(); err != nil {
   188  		return err
   189  	}
   190  	return e.processOperators()
   191  }