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 }