# loki.expression.parser

Module Attributes

`FORTRAN_INTRINSIC_PROCEDURES` | list of intrinsic fortran procedure(s) names
`parse_expr` | An instance of `ExpressionParser` that allows parsing expression strings into a Loki expression tree.

Classes

`ExpressionParser`() | String Parser based on `pymbolic.parser.Parser` for parsing expressions from strings.
`PymbolicMapper`() | Pymbolic expression to Loki expression mapper.

class ExpressionParser

  Bases: `Parser`

  String Parser based on `pymbolic.parser.Parser` for parsing expressions from strings.

  The Loki String Parser utilises and extends pymbolic’s parser to incorporate Fortran specific syntax and to map pymbolic expressions to Loki expressions, utilising the mapper `PymbolicMapper`.

  Further, in order to ensure correct ordering of Fortran Statements as documented in ‘WD 1539-1 J3/23-007r1 (Draft Fortran 2023)’, pymbolic’s parsing logic needed to be slightly adapted.

  Pymbolic references:

  - GitHub: pymbolic

  - pymbolic/parser.py

  - pymbolic’s parser documentation

  Note

  Example:

    Using the expression parser and possibly evaluate them

        >>> from loki import parse_expr
        >>> # parse numerical expressions
        >>> ir = parse_expr('3 + 2**4')
        >>> ir
        Sum((IntLiteral(3, None), Power(IntLiteral(2, None), IntLiteral(4, None))))
        >>> # or expressions with variables
        >>> ir = parse_expr('a*b')
        >>> ir
        Product((DeferredTypeSymbol('a', None, None, <SymbolAttributes BasicType.DEFERRED>),                    DeferredTypeSymbol('b', None, None, <SymbolAttributes BasicType.DEFERRED>)))
        >>> # and provide a scope e.g, with some routine defining a and b as 'real's
        >>> ir = parse_expr('a*b', scope=routine)
        >>> ir
        Product((Scalar('a', None, None, None), Scalar('b', None, None, None)))
        >>> # further, it is possible to evaluate expressions
        >>> ir = parse_expr('a*b + 1', evaluate=True, context={'a': 2, 'b': 3})
        >>> ir
        >>> IntLiteral(7, None)
        >>> # even with functions implemented in Python
        >>> def add(a, b):
        >>>     return a + b
        >>> ir = parse_expr('a + add(a, b)', evaluate=True, context={'a': 2, 'b': 3, 'add': add})
        >>> ir
        >>> IntLiteral(7, None)

  __call__(expr_str, scope=None, evaluate=False, strict=False, context=None)

    Call Loki String Parser to convert expression(s) represented in a string to Loki expression(s)/IR.

    Parameters:

      - expr_str (str) – The expression as a string

      - scope (`Scope`) – The scope to which symbol names inside the expression belong

      - evaluate (bool, optional) – Whether to evaluate the expression or not (default: False)

      - strict (bool, optional) – Whether to raise exception for unknown variables/symbols when evaluating an expression (default: False)

      - context (dict, optional) – Symbol context, defining variables/symbols/procedures to help/support evaluating an expression

    Returns:

      The expression tree corresponding to the expression

    Return type:

      `Expression`

  lex_table = [('f_true', RE(\.true\.)), ('f_false', RE(\.false\.)), ('_f_lessequal', RE(\.le\.)), ('_f_less', RE(\.lt\.)), ('_f_greaterequal', RE(\.ge\.)), ('_f_greater', RE(\.gt\.)), ('_f_equal', RE(\.eq\.)), ('_f_notequal', ('|', RE(\.ne\.), RE(/=))), ('and', RE(\.and\.)), ('or', RE(\.or\.)), ('not', RE(\.not\.)), ('f_float', ('|', RE([0-9]+\.[0-9]*([eEdD][+-]?[0-9]+)?(_([\w$]+|[0-9]+))+$))), ('f_int', RE([0-9]+?(_[a-zA-Z]*))), ('f_string', ('|', RE(\".*\"), RE(\'.*\'))), ('openbracket', RE(\(/)), ('closebracket', RE(/\))), ('dot', RE(\%)), ('equal', RE(==)), ('notequal', RE(!=)), ('equal', RE(==)), ('leftshift', RE(\<\<)), ('rightshift', RE(\>\>)), ('lessequal', RE(\<=)), ('greaterequal', RE(\>=)), ('less', RE(\<)), ('greater', RE(\>)), ('assign', RE(=)), ('and', RE(and\b)), ('or', RE(or\b)), ('not', RE(not\b)), ('if', RE(if\b)), ('else', RE(else\b)), ('imaginary', ('float', RE(j))), ('float', ('|', RE([0-9]+\.[0-9]*([eEdD][+-]?[0-9]+)?([a-zA-Z]*)), RE([0-9]+(\.[0-9]*)?[eEdD][+-]?[0-9]+([a-zA-Z]*)\b), RE([0-9]*\.[0-9]+([eEdD][+-]?[0-9]+)?([a-zA-Z]*)), RE([0-9]*\.[0-9]+[eEdD][+-]?[0-9]+([a-zA-Z]*)\b), RE([0-9]+([a-zA-Z]+)))), ('int', RE([0-9]+)), ('plus', RE(\+)), ('minus', RE(-)), ('exp', RE(\*\*)), ('times', RE(\*)), ('floordiv', RE(//)), ('over', RE(/)), ('modulo', RE(%)), ('bitwiseand', RE(\&)), ('bitwiseor', RE(\|)), ('bitwisenot', RE(\~)), ('bitwisexor', RE(\^)), ('openpar', RE(\()), ('closepar', RE(\))), ('openbracket', RE(\[)), ('closebracket', RE(\])), ('True', RE(True)), ('False', RE(False)), ('identifier', RE([@$a-z_A-Z_][@$a-zA-Z_0-9]*)), ('whitespace', RE([ ]*)), ('comma', RE(,)), ('dot', RE(\.)), ('colon', RE(\:))]

    Extend `pymbolic.parser.Parser.lex_table` to accomodate for Fortran specifix syntax/expressions.

  parse_prefix(pstate)
  parse_postfix(pstate, min_precedence, left_exp)
  parse_terminal(pstate)
  parse_float(s)

    Parse float literals.

    Do not cast to float via ‘float()’ in order to keep the original notation, e.g., do not convert 1E-3 to 0.003.

  parse_f_float(s)

    Parse “Fortran-style” float literals.

    E.g., `3.1415_my_real_kind`.

  parse_f_int(s)

    Parse “Fortran-style” int literals.

    E.g., `1_my_int_kind`.

  parse_f_string(s)

    Parse string literals.

parse_expr = <loki.expression.parser.ExpressionParser object>

  An instance of `ExpressionParser` that allows parsing expression strings into a Loki expression tree. See `ExpressionParser.__call__` for a description of the available arguments.

FORTRAN_INTRINSIC_PROCEDURES = ['ABS', 'AIMAG', 'AINT', 'ANINT', 'CEILING', 'CMPLX', 'CONJG', 'DBLE', 'DIM', 'DPROD', 'FLOOR', 'INT', 'MAX', 'MIN', 'MOD', 'MODULO', 'NINT', 'REAL', 'SIGN', 'ACOS', 'ASIN', 'ATAN', 'ATAN2', 'COS', 'COSH', 'EXP', 'LOG', 'LOG10', 'SIN', 'SINH', 'SQRT', 'TAN', 'TANH', 'ACHAR', 'ADJUSTL', 'ADJUSTR', 'CHAR', 'IACHAR', 'ICHAR', 'INDEX', 'LEN_TRIM', 'LGE', 'LGT', 'LLE', 'LLT', 'REPEAT', 'SCAN', 'TRIM', 'VERIFY', 'KIND', 'SELECTED_CHAR_KIND', 'SELECTED_INT_KIND', 'SELECTED_REAL_KIND', 'LOGICAL', 'TRANSFER', 'DIGITS', 'EPSILON', 'HUGE', 'MAXEXPONENT', 'MINEXPONENT', 'PRECISION', 'RADIX', 'RANGE', 'TINY', 'LBOUND', 'SHAPE', 'SIZE', 'UBOUND', 'ALLOCATED', 'ASSOCIATED', 'BIT_SIZE', 'EXTENDS_TYPE_OF', 'LEN', 'NEW_LINE', 'PRESENT', 'SAME_TYPE_AS', 'BTEST', 'IAND', 'IBCLR', 'IBITS', 'IBSET', 'IEOR', 'IOR', 'ISHFT', 'ISHFTC', 'MVBITS', 'NOT', 'EXPONENT', 'FRACTION', 'NEAREST', 'RRSPACING', 'SCALE', 'SET_EXPONENT', 'SPACING', 'DOT_PRODUCT', 'MATMUL', 'ALL', 'ANY', 'COUNT', 'MAXVAL', 'MINVAL', 'PRODUCT', 'SUM', 'CSHIFT', 'EOSHIFT', 'MERGE', 'PACK', 'RESHAPE', 'SPREAD', 'TRANSPOSE', 'UNPACK', 'MAXLOC', 'MINLOC', 'NULL', 'MOVE_ALLOC', 'RANDOM_NUMBER', 'RANDOM_SEED', 'COMMAND_ARGUMENT_COUNT', 'CPU_TIME', 'DATE_AND_TIME', 'GET_COMMAND', 'GET_COMMAND_ARGUMENT', 'GET_ENVIRONMENT_VARIABLE', 'IS_IOSTAT_END', 'IS_IOSTAT_EOR', 'SYSTEM_CLOCK', 'ALOG', 'ALOG10', 'AMAX0', 'AMAX1', 'AMIN0', 'AMIN1', 'AMOD', 'CABS', 'CCOS', 'CEXP', 'CLOG', 'CSIN', 'CSQRT', 'DABS', 'DACOS', 'DASIN', 'DATAN', 'DATAN2', 'DCOS', 'DCOSH', 'DDIM', 'DEXP', 'DINT', 'DLOG', 'DLOG10', 'DMAX1', 'DMIN1', 'DMOD', 'DNINT', 'DSIGN', 'DSIN', 'DSINH', 'DSQRT', 'DTAN', 'DTANH', 'FLOAT', 'IABS', 'IDIM', 'IDINT', 'IDNINT', 'IFIX', 'ISIGN', 'MAX0', 'MAX1', 'MIN0', 'MIN1', 'SNGL']

  list of intrinsic fortran procedure(s) names