github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/docs/commands/expr.md (about)

     1  # `expr`
     2  
     3  > Expressions: mathematical, string comparisons, logical operators
     4  
     5  ## Description
     6  
     7  `expr` is the underlying builtin which handles all expression parsing and
     8  evaluation in Murex. Though typically that would happen transparently without
     9  you having to explicit call `expr`.
    10  
    11  For a full list of operators supported exclusively in expression, see the
    12  last section in this document.
    13  
    14  ## Usage
    15  
    16  ```
    17  expression -> <stdout>
    18  
    19  statement (expression)
    20  
    21  expr expression -> <stdout>
    22  ```
    23  
    24  ## Examples
    25  
    26  **Expressions:**
    27  
    28  ```
    29  » 3 * (3 + 1)
    30  12
    31  ```
    32  
    33  **Statements with inlined expressions:**
    34  
    35  Any parameter surrounded by parenthesis is first evaluated as an expression,
    36  then as a string.
    37  
    38  ```
    39  » out (3 * 2)
    40  6
    41  ```
    42  
    43  **Expressions with inlined statements:**
    44  
    45  Functions can be inlined as a statement using `function(parameters...)` syntax.
    46  
    47  ```
    48  » datetime(--in {now} --out {unix}) / 60
    49  28339115.783333335
    50  ```
    51  
    52  Please note that currently the only functions supported are ones who's names
    53  are comprised entirely of alpha, numeric, underscore and/or exclamation marks.
    54  
    55  **JSON array:**
    56  
    57  ```
    58  » %[apples oranges grapes]
    59  [
    60      "apples",
    61      "oranges",
    62      "grapes"
    63  ]
    64  ```
    65  
    66  ## Detail
    67  
    68  ### Order of Operations
    69  
    70  The order of operations follows the same rules as the C programming language,
    71  which itself is an extension of the order of operations in mathematics, often
    72  referred to as PEMDAS or MODMAS ([read more](https://en.wikipedia.org/wiki/Order_of_operations)).
    73  
    74  The [Wikipedia article](https://en.wikipedia.org/wiki/Order_of_operations#Programming_languages)
    75  summarises that order succinctly however the detailed specification is defined
    76  by its implementation, as seen in the code below:
    77  
    78  ```go
    79  package expressions
    80  
    81  import (
    82  	"fmt"
    83  
    84  	"github.com/lmorg/murex/lang/expressions/primitives"
    85  	"github.com/lmorg/murex/lang/expressions/symbols"
    86  	"github.com/lmorg/murex/utils/consts"
    87  )
    88  
    89  func (tree *ParserT) executeExpr() (*primitives.DataType, error) {
    90  	err := tree.validateExpression(true)
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  
    95  	for i := range orderOfOperations {
    96  		err = executeExpression(tree, orderOfOperations[i])
    97  		if err != nil {
    98  			return nil, err
    99  		}
   100  	}
   101  
   102  	if len(tree.ast) > 1 {
   103  		return nil, fmt.Errorf(
   104  			"expression failed to execute correctly (AST results > 1).\n%s",
   105  			consts.IssueTrackerURL)
   106  	}
   107  
   108  	return tree.ast[0].dt, nil
   109  }
   110  
   111  // To allow for extendability and developer expectations, the order of operations
   112  // will follow what is defined by (for example) C, as outlined in the following:
   113  // https://en.wikipedia.org/wiki/Order_of_operations#Programming_languages
   114  // Not all operations will be available in murex and some are likely to be added
   115  // in future versions of this package.
   116  //
   117  // Please also note that the slice below is just defining the groupings. Each
   118  // operator within the _same_ group will then be processed from left to right.
   119  // Read the `executeExpression` function further down this source file to view
   120  // every supported operator
   121  var orderOfOperations = []symbols.Exp{
   122  	// 01. Function call, scope, array/member access
   123  	// 02. (most) unary operators, sizeof and type casts (right to left)
   124  	// 03. Multiplication, division, modulo
   125  	symbols.Multiply,
   126  
   127  	// 04. Addition and subtraction
   128  	symbols.Add,
   129  
   130  	// 05. Bitwise shift left and right
   131  	// 06. Comparisons: less-than and greater-than
   132  	symbols.GreaterThan,
   133  
   134  	// 07. Comparisons: equal and not equal
   135  	symbols.EqualTo,
   136  
   137  	// 08. Bitwise AND
   138  	// 09. Bitwise exclusive OR (XOR)
   139  	// 10. Bitwise inclusive (normal) OR
   140  	// 11. Logical AND
   141  	symbols.LogicalAnd,
   142  
   143  	// 12. Logical OR
   144  	symbols.LogicalOr,
   145  
   146  	// 13. Conditional expression (ternary)
   147  	symbols.Elvis,
   148  
   149  	// 14. Assignment operators (right to left)
   150  	symbols.Assign,
   151  
   152  	// 15. Comma operator
   153  }
   154  
   155  func executeExpression(tree *ParserT, order symbols.Exp) (err error) {
   156  	for tree.astPos = 0; tree.astPos < len(tree.ast); tree.astPos++ {
   157  		node := tree.ast[tree.astPos]
   158  
   159  		if node.key < order {
   160  			continue
   161  		}
   162  
   163  		switch node.key {
   164  
   165  		// 15. Comma operator
   166  		// 14. Assignment operators (right to left)
   167  		case symbols.Assign:
   168  			err = expAssign(tree, true)
   169  		case symbols.AssignUpdate:
   170  			err = expAssign(tree, false)
   171  		case symbols.AssignAndAdd:
   172  			err = expAssignAdd(tree)
   173  		case symbols.AssignAndSubtract:
   174  			err = expAssignAndOperate(tree, _assSub)
   175  		case symbols.AssignAndDivide:
   176  			err = expAssignAndOperate(tree, _assDiv)
   177  		case symbols.AssignAndMultiply:
   178  			err = expAssignAndOperate(tree, _assMulti)
   179  		case symbols.AssignAndMerge:
   180  			err = expAssignMerge(tree)
   181  
   182  		// 13. Conditional expression (ternary)
   183  		case symbols.NullCoalescing:
   184  			err = expNullCoalescing(tree)
   185  		case symbols.Elvis:
   186  			err = expElvis(tree)
   187  
   188  		// 12. Logical OR
   189  		case symbols.LogicalOr:
   190  			err = expLogicalOr(tree)
   191  
   192  		// 11. Logical AND
   193  		case symbols.LogicalAnd:
   194  			err = expLogicalAnd(tree)
   195  
   196  		// 10. Bitwise inclusive (normal) OR
   197  		// 09. Bitwise exclusive OR (XOR)
   198  		// 08. Bitwise AND
   199  		// 07. Comparisons: equal and not equal
   200  		case symbols.EqualTo:
   201  			err = expEqualTo(tree)
   202  		case symbols.NotEqualTo:
   203  			err = expNotEqualTo(tree)
   204  		case symbols.Like:
   205  			err = expLike(tree, true)
   206  		case symbols.NotLike:
   207  			err = expLike(tree, false)
   208  		case symbols.Regexp:
   209  			err = expRegexp(tree, true)
   210  		case symbols.NotRegexp:
   211  			err = expRegexp(tree, false)
   212  
   213  		// 06. Comparisons: less-than and greater-than
   214  		case symbols.GreaterThan:
   215  			err = expGtLt(tree, _gtF, _gtS)
   216  		case symbols.GreaterThanOrEqual:
   217  			err = expGtLt(tree, _gtEqF, _gtEqS)
   218  		case symbols.LessThan:
   219  			err = expGtLt(tree, _ltF, _ltS)
   220  		case symbols.LessThanOrEqual:
   221  			err = expGtLt(tree, _ltEqF, _ltEqS)
   222  
   223  		// 05. Bitwise shift left and right
   224  		// 04. Addition and subtraction
   225  		case symbols.Add:
   226  			err = expAdd(tree)
   227  		case symbols.Subtract:
   228  			err = expSubtract(tree)
   229  		case symbols.MergeInto:
   230  			err = expMergeInto(tree)
   231  
   232  		// 03. Multiplication, division, modulo
   233  		case symbols.Multiply:
   234  			err = expMultiply(tree)
   235  		case symbols.Divide:
   236  			err = expDivide(tree)
   237  
   238  		// 02. (most) unary operators, sizeof and type casts (right to left)
   239  		// 01. Function call, scope, array/member access
   240  
   241  		default:
   242  			err = raiseError(tree.expression, node, 0, fmt.Sprintf(
   243  				"no code written to handle symbol (%s)",
   244  				consts.IssueTrackerURL))
   245  		}
   246  
   247  		if err != nil {
   248  			return err
   249  		}
   250  
   251  		tree.astPos = 0
   252  	}
   253  
   254  	return nil
   255  }
   256  ```
   257  
   258  ## See Also
   259  
   260  * [`%[]` Create Array](../parser/create-array.md):
   261    Quickly generate arrays
   262  * [`%{}` Create Map](../parser/create-object.md):
   263    Quickly generate objects and maps
   264  * [`*=` Multiply By Operator](../parser/multiply-by.md):
   265    Multiplies a variable by the right hand value (expression)
   266  * [`*` Multiplication Operator](../parser/multiplication.md):
   267    Multiplies one numeric value with another (expression)
   268  * [`+=` Add With Operator](../parser/add-with.md):
   269    Adds the right hand value to a variable (expression)
   270  * [`+` Addition Operator](../parser/addition.md):
   271    Adds two numeric values together (expression)
   272  * [`-=` Subtract By Operator](../parser/subtract-by.md):
   273    Subtracts a variable by the right hand value (expression)
   274  * [`-` Subtraction Operator](../parser/subtraction.md):
   275    Subtracts one numeric value from another (expression)
   276  * [`/=` Divide By Operator](../parser/divide-by.md):
   277    Divides a variable by the right hand value (expression)
   278  * [`/` Division Operator](../parser/division.md):
   279    Divides one numeric value from another (expression)
   280  * [`?:` Elvis Operator](../parser/elvis.md):
   281    Returns the right operand if the left operand is falsy (expression)
   282  * [`??` Null Coalescing Operator](../parser/null-coalescing.md):
   283    Returns the right operand if the left operand is empty / undefined (expression)
   284  
   285  <hr/>
   286  
   287  This document was generated from [builtins/core/expressions/expressions_doc.yaml](https://github.com/lmorg/murex/blob/master/builtins/core/expressions/expressions_doc.yaml).