1

I need to evaluate a dynamic logical expression and I know that in ABAP it is not possible. I found the class cl_java_script and with this class I could achieve my requeriment. I've try something like this:

result = cl_java_script=>create( )->evaluate( `( 1 + 2 + 3 ) == 6 ;` ).

After the method evaluate execution result = true as espected. But my happiness is over when I look into the class documentation that says This class is obsolete.

My question is, there is another way to achieve this?

Ronaldo
  • 21
  • 4
  • Not directly. You have (very) low-performing workarounds like creating programs dynamically (`GENERATE SUBROUTINE-POOL`), and some application-specific components like function module `EVAL_FORMULA`, class `CL_FOBU_FORMULA`, etc. But I'd recommend to code your own formula parser as it's quite simple logic. – Sandra Rossi May 14 '22 at 06:20
  • 1
    "This class is obsolete" - it doesn't matter. If it works, just use it – alezhu May 15 '22 at 12:09

2 Answers2

4

Using any turing complete language to parse a "dynamic logical expression" is a terrible idea, as an attacker might be able to run any program inside your expression, i.e. while(true) { } will crash your variant using cl_java_script. Also although I don't know the details of cl_java_script, I assume it launches a separate JS runtime in a separate thread somewhere, this does not seem to be the most efficient choice to calculate such a small dynamic expression.

Instead you could implement your own small parser. This has the advantage that you can limit what it supports to the bare minimum whilst being able to extend it to everything you need in your usecase. Here's a small example using reverse polish notation which is able to correctly evaluate the expression you've shown (using RPN simplifies parsing a lot, though for sure one can also build a full fledged expression parser):

REPORT z_expr_parser.

TYPES:
 BEGIN OF multi_value,
  integer TYPE REF TO i,
  boolean TYPE REF TO bool,
 END OF multi_value.

CLASS lcl_rpn_parser DEFINITION.
  PUBLIC SECTION.
    METHODS:
      constructor
        IMPORTING
          text TYPE string,
      parse
        RETURNING VALUE(result) TYPE multi_value.
   PRIVATE SECTION.
     DATA:
       tokens TYPE STANDARD TABLE OF string,
       stack  TYPE STANDARD TABLE OF multi_value.

     METHODS pop_int
       RETURNING VALUE(result) TYPE i.
     METHODS pop_bool
       RETURNING VALUE(result) TYPE abap_bool.
ENDCLASS.

CLASS lcl_rpn_parser IMPLEMENTATION.
  METHOD constructor.
    " a most simple lexer:
    SPLIT text AT ' ' INTO TABLE tokens.
    ASSERT lines( tokens ) > 0.
  ENDMETHOD.

  METHOD pop_int.
    DATA(peek) = stack[ lines( stack ) ].
    ASSERT peek-integer IS BOUND.
    result = peek-integer->*.
    DELETE stack INDEX lines( stack ).
  ENDMETHOD.


  METHOD pop_bool.
    DATA(peek) = stack[ lines( stack ) ].
    ASSERT peek-boolean IS BOUND.
    result = peek-boolean->*.
    DELETE stack INDEX lines( stack ).
  ENDMETHOD.

  METHOD parse.
    LOOP AT tokens INTO DATA(token).
      IF token = '='.
        DATA(comparison) = xsdbool( pop_int( ) = pop_int( ) ).
        APPEND VALUE #( boolean = NEW #( comparison ) ) TO stack.
      ELSEIF token = '+'.
        DATA(addition) = pop_int( ) + pop_int( ).
        APPEND VALUE #( integer = NEW #( addition ) ) TO stack.
      ELSE.
        " assumption: token is integer
        DATA value TYPE i.
        value = token.
        APPEND VALUE #( integer = NEW #( value ) ) TO stack.
      ENDIF.
    ENDLOOP.

    ASSERT lines( stack ) = 1.
    result = stack[ 1 ].
  ENDMETHOD.
ENDCLASS.


START-OF-SELECTION.

" 1 + 2 + 3 = 6 in RPN:
DATA(program) = |1 2 3 + + 6 =|.
DATA(parser) = NEW lcl_rpn_parser( program ).
DATA(result) = parser->parse( ).
ASSERT result-boolean IS BOUND.
ASSERT result-boolean->* = abap_true.
Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
  • When did you knock that Jonas? Not bad at all. At least people have a starting point if they wanted to right their own parser. Ill give that a thumbs up. – phil soady May 17 '22 at 20:13
1

SAPs BRF is an option, but potentially massive overkill in your scenario.
Here is a blog on calling BRF from abap. And here is how Rules/Expressions can be defined dynamically.

BUT, if you know enough about the source problem to generate 1 + 2 + 3 = 6

Then it is hard to imagine why a simple custom parser cant be used. Just how complex should the expressions be ?
Id probably write my own parser before investing in calling BRF.

Since some/many BSPs use server side JAVAscript and not ABAP as the scripting language, i cant see SAP removing the Kernel routine anytime soon. SYSTEM-CALL JAVA SCRIPT EVALUATE.
SO maybe consider Just calling the cl_java_script anyway until it is an issue. Then worry about a parser if and when it is really no longer a valid call.

But definitely some movement in the obsolete space here. SAP is pushing/forcing you to cloud with the SDK, to execute such things.

https://sap.github.io/cloud-sdk/docs/js/overview-cloud-sdk-for-javascript

phil soady
  • 11,043
  • 5
  • 50
  • 95
  • Thanks for your answer. Actually what really worries me is what it says in these links: https://help.sap.com/docs/SAP_NETWEAVER_702/fe1d31bb6c551014b75bc66f0328fefe/808676416e805958e10000000a1550b0.html?version=7.02.19&locale=en-US https://help.sap.com/docs/SAP_NETWEAVER_702/fe1d31bb6c551014b75bc66f0328fefe/49a8e3c8d59811d4b2e90050dadfb92b.html?version=7.02.19&locale=en-US – Ronaldo May 18 '22 at 16:50
  • then copy the code with the system call inside. `SYSTEM-CALL JAVA SCRIPT EVALUATE`. Removing that is a kernel update with breaking downwards compatibility. That is less likely. I have seen sap delete classes and remove functionality before. The kernel feature would be the last to go. – phil soady May 19 '22 at 03:10
  • Hello @Phil Soady, I'm just tryed to do the copy, but I had a warning message that I believe I'm unable to solve and actually, I don't know if this copy will work properly or not. The message says: The global class "ZCL_JAVA_SCRIPT" is not registred in Memory Inspector for the attribute "CONTEXT". Refer to the file include/abmikernelclasses.h – Ronaldo Jun 14 '22 at 19:25
  • Oh, wow... so they are trying to kill it off and make you use the cloud sdk. – phil soady Jun 14 '22 at 21:38