From 8d79df11251bc35b5783bc721a8950198738fe07 Mon Sep 17 00:00:00 2001 From: Lars Hvam <5888506+larshp@users.noreply.github.com> Date: Wed, 8 Apr 2026 14:13:12 +0200 Subject: [PATCH 1/7] extract methods --- src/zcl_mjs.clas.abap | 506 ++++++++++++++------------------------ src/zcl_mjs_val.clas.abap | 148 +++++++++++ src/zcl_mjs_val.clas.xml | 16 ++ 3 files changed, 346 insertions(+), 324 deletions(-) create mode 100644 src/zcl_mjs_val.clas.abap create mode 100644 src/zcl_mjs_val.clas.xml diff --git a/src/zcl_mjs.clas.abap b/src/zcl_mjs.clas.abap index f091d90..25118cf 100644 --- a/src/zcl_mjs.clas.abap +++ b/src/zcl_mjs.clas.abap @@ -10,33 +10,6 @@ CLASS zcl_mjs DEFINITION PUBLIC. IMPORTING iv_src TYPE string RETURNING VALUE(rt_tokens) TYPE zif_mjs=>tt_tokens. - CLASS-METHODS number_val - IMPORTING iv_num TYPE f - RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. - CLASS-METHODS string_val - IMPORTING iv_str TYPE string - RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. - CLASS-METHODS bool_val - IMPORTING iv_bool TYPE abap_bool - RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. - CLASS-METHODS object_val - RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. - CLASS-METHODS array_val - IMPORTING it_elems TYPE zif_mjs=>tt_nodes - RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. - CLASS-METHODS undefined_val - RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. - - CLASS-METHODS is_true - IMPORTING is_val TYPE zif_mjs=>ty_value - RETURNING VALUE(rv_yes) TYPE abap_bool. - CLASS-METHODS to_number - IMPORTING is_val TYPE zif_mjs=>ty_value - RETURNING VALUE(rv_num) TYPE f. - CLASS-METHODS to_string - IMPORTING is_val TYPE zif_mjs=>ty_value - RETURNING VALUE(rv_str) TYPE string. - CLASS-METHODS eval_node IMPORTING ir_node TYPE REF TO data io_env TYPE REF TO zcl_mjs_env @@ -113,9 +86,9 @@ CLASS zcl_mjs IMPLEMENTATION. DATA lo_env TYPE REF TO zcl_mjs_env. CREATE OBJECT lo_env. - lo_env->define( iv_name = `console` is_val = number_val( 0 ) ). - lo_env->define( iv_name = `Date` is_val = object_val( ) ). - lo_env->define( iv_name = `undefined` is_val = undefined_val( ) ). + lo_env->define( iv_name = `console` is_val = zcl_mjs_val=>number_val( 0 ) ). + lo_env->define( iv_name = `Date` is_val = zcl_mjs_val=>object_val( ) ). + lo_env->define( iv_name = `undefined` is_val = zcl_mjs_val=>undefined_val( ) ). DATA ls_null TYPE zif_mjs=>ty_value. ls_null-type = 5. lo_env->define( iv_name = `null` is_val = ls_null ). @@ -127,23 +100,23 @@ CLASS zcl_mjs IMPLEMENTATION. lo_env->define( iv_name = `Infinity` is_val = ls_inf ). " Standard error constructors — defined as undefined placeholders so that " assert.throws(TypeError, fn) does not throw ReferenceError on the type arg. - DATA(ls_obj_builtin) = object_val( ). + DATA(ls_obj_builtin) = zcl_mjs_val=>object_val( ). lo_env->define( iv_name = `Object` is_val = ls_obj_builtin ). - lo_env->define( iv_name = `Set` is_val = undefined_val( ) ). - lo_env->define( iv_name = `RegExp` is_val = undefined_val( ) ). - lo_env->define( iv_name = `Error` is_val = undefined_val( ) ). - lo_env->define( iv_name = `ReferenceError` is_val = undefined_val( ) ). - lo_env->define( iv_name = `TypeError` is_val = undefined_val( ) ). - lo_env->define( iv_name = `SyntaxError` is_val = undefined_val( ) ). - lo_env->define( iv_name = `RangeError` is_val = undefined_val( ) ). - lo_env->define( iv_name = `URIError` is_val = undefined_val( ) ). - lo_env->define( iv_name = `EvalError` is_val = undefined_val( ) ). + lo_env->define( iv_name = `Set` is_val = zcl_mjs_val=>undefined_val( ) ). + lo_env->define( iv_name = `RegExp` is_val = zcl_mjs_val=>undefined_val( ) ). + lo_env->define( iv_name = `Error` is_val = zcl_mjs_val=>undefined_val( ) ). + lo_env->define( iv_name = `ReferenceError` is_val = zcl_mjs_val=>undefined_val( ) ). + lo_env->define( iv_name = `TypeError` is_val = zcl_mjs_val=>undefined_val( ) ). + lo_env->define( iv_name = `SyntaxError` is_val = zcl_mjs_val=>undefined_val( ) ). + lo_env->define( iv_name = `RangeError` is_val = zcl_mjs_val=>undefined_val( ) ). + lo_env->define( iv_name = `URIError` is_val = zcl_mjs_val=>undefined_val( ) ). + lo_env->define( iv_name = `EvalError` is_val = zcl_mjs_val=>undefined_val( ) ). " 'this' at the global scope is the global object (sloppy-mode) - lo_env->define( iv_name = `this` is_val = object_val( ) ). - lo_env->define( iv_name = `arguments` is_val = undefined_val( ) ). + lo_env->define( iv_name = `this` is_val = zcl_mjs_val=>object_val( ) ). + lo_env->define( iv_name = `arguments` is_val = zcl_mjs_val=>undefined_val( ) ). " Other JS builtins / keywords that may appear as expressions in partially-parsed code - lo_env->define( iv_name = `eval` is_val = undefined_val( ) ). - lo_env->define( iv_name = `in` is_val = undefined_val( ) ). + lo_env->define( iv_name = `eval` is_val = zcl_mjs_val=>undefined_val( ) ). + lo_env->define( iv_name = `in` is_val = zcl_mjs_val=>undefined_val( ) ). " Hoist function declarations at global scope (JS hoisting) FIELD-SYMBOLS TYPE zif_mjs=>ty_node. @@ -738,121 +711,6 @@ CLASS zcl_mjs IMPLEMENTATION. APPEND ls_tok TO rt_tokens. ENDMETHOD. - METHOD number_val. - rs_val-type = 1. - rs_val-num = iv_num. - ENDMETHOD. - - METHOD string_val. - rs_val-type = 2. - rs_val-str = iv_str. - ENDMETHOD. - - METHOD bool_val. - rs_val-type = 3. - IF iv_bool = abap_true. - rs_val-num = 1. - ELSE. - rs_val-num = 0. - ENDIF. - ENDMETHOD. - - METHOD object_val. - rs_val-type = 6. - CREATE OBJECT rs_val-obj. - ENDMETHOD. - - METHOD array_val. - rs_val-type = 7. - CREATE OBJECT rs_val-arr. - FIELD-SYMBOLS TYPE REF TO data. - LOOP AT it_elems ASSIGNING . - rs_val-arr->push( ). - ENDLOOP. - ENDMETHOD. - - METHOD undefined_val. - rs_val-type = 0. - ENDMETHOD. - - METHOD is_true. - CASE is_val-type. - WHEN 0 OR 5. - rv_yes = abap_false. - WHEN 1. - rv_yes = boolc( is_val-num <> 0 ). - WHEN 2. - rv_yes = boolc( is_val-str IS NOT INITIAL ). - WHEN 3. - rv_yes = boolc( is_val-num <> 0 ). - WHEN OTHERS. - rv_yes = abap_true. - ENDCASE. - ENDMETHOD. - - METHOD to_number. - CASE is_val-type. - WHEN 1. - rv_num = is_val-num. - WHEN 2. - TRY. - rv_num = is_val-str. - CATCH cx_root. - rv_num = 0. - ENDTRY. - WHEN 3. - rv_num = is_val-num. - WHEN OTHERS. - rv_num = 0. - ENDCASE. - ENDMETHOD. - - METHOD to_string. - CASE is_val-type. - WHEN 0. - rv_str = `undefined`. - WHEN 1. - IF is_val-str = `NaN` OR is_val-str = `Infinity` OR is_val-str = `-Infinity`. - rv_str = is_val-str. - ELSE. - DATA lv_int TYPE i. - DATA lv_fcheck TYPE f. - lv_int = is_val-num. - lv_fcheck = lv_int. - IF lv_fcheck = is_val-num. - rv_str = |{ lv_int }|. - ELSE. - rv_str = |{ is_val-num }|. - CONDENSE rv_str. - ENDIF. - ENDIF. - WHEN 2. - rv_str = is_val-str. - WHEN 3. - IF is_val-num <> 0. - rv_str = `true`. - ELSE. - rv_str = `false`. - ENDIF. - WHEN 4. - FIELD-SYMBOLS TYPE zif_mjs=>ty_function. - ASSIGN is_val-fn->* TO . - IF sy-subrc = 0 AND -name IS NOT INITIAL. - rv_str = |function { -name }() \{ [native code] \}|. - ELSE. - rv_str = `function() { [native code] }`. - ENDIF. - WHEN 5. - rv_str = `null`. - WHEN 6. - rv_str = `[object Object]`. - WHEN 7. - rv_str = |[array { is_val-arr->length( ) }]|. - WHEN OTHERS. - rv_str = `undefined`. - ENDCASE. - ENDMETHOD. - METHOD box_value. CREATE DATA rr_ref TYPE zif_mjs=>ty_value. FIELD-SYMBOLS TYPE zif_mjs=>ty_value. @@ -1238,7 +1096,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF io_env->has( -str ) = abap_false. DATA lx_referr TYPE REF TO zcx_mjs_throw. DATA ls_refmsg TYPE zif_mjs=>ty_value. - ls_refmsg = string_val( |ReferenceError: { -str } is not defined| ). + ls_refmsg = zcl_mjs_val=>string_val( |ReferenceError: { -str } is not defined| ). CREATE OBJECT lx_referr EXPORTING is_val = ls_refmsg. RAISE EXCEPTION lx_referr. ENDIF. @@ -1249,7 +1107,7 @@ CLASS zcl_mjs IMPLEMENTATION. " Short-circuit operators: evaluate left only, return early if decided IF -op = `&&`. DATA(ls_blsc) = eval_node( ir_node = -left io_env = io_env ). - IF is_true( ls_blsc ) = abap_false. + IF zcl_mjs_val=>is_true( ls_blsc ) = abap_false. rs_val = ls_blsc. ELSE. rs_val = eval_node( ir_node = -right io_env = io_env ). @@ -1257,7 +1115,7 @@ CLASS zcl_mjs IMPLEMENTATION. RETURN. ELSEIF -op = `||`. DATA(ls_blor) = eval_node( ir_node = -left io_env = io_env ). - IF is_true( ls_blor ) = abap_true. + IF zcl_mjs_val=>is_true( ls_blor ) = abap_true. rs_val = ls_blor. ELSE. rs_val = eval_node( ir_node = -right io_env = io_env ). @@ -1280,10 +1138,10 @@ CLASS zcl_mjs IMPLEMENTATION. DATA(ls_uval) = eval_node( ir_node = -left io_env = io_env ). CASE -op. WHEN `-`. - rs_val-type = 1. rs_val-num = 0 - to_number( ls_uval ). + rs_val-type = 1. rs_val-num = 0 - zcl_mjs_val=>to_number( ls_uval ). WHEN `!`. rs_val-type = 3. - IF is_true( ls_uval ) = abap_false. rs_val-num = 1. ENDIF. + IF zcl_mjs_val=>is_true( ls_uval ) = abap_false. rs_val-num = 1. ENDIF. WHEN `void`. " evaluate operand for side effects, return undefined (type=0) ENDCASE. @@ -1356,7 +1214,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA lv_maprop TYPE string. lv_maprop = -property. IF -prop_expr IS BOUND. - lv_maprop = to_string( eval_node( ir_node = -prop_expr io_env = io_env ) ). + lv_maprop = zcl_mjs_val=>to_string( eval_node( ir_node = -prop_expr io_env = io_env ) ). ENDIF. IF ls_maobj-type = 6. ls_maobj-obj->set( iv_key = lv_maprop ir_val = box_value( ls_maval ) ). @@ -1388,7 +1246,7 @@ CLASS zcl_mjs IMPLEMENTATION. WHEN zif_mjs=>c_node_if. DATA(ls_icond) = eval_node( ir_node = -cond io_env = io_env ). - IF is_true( ls_icond ) = abap_true. + IF zcl_mjs_val=>is_true( ls_icond ) = abap_true. LOOP AT -body INTO DATA(lr_ib). eval_node( ir_node = lr_ib io_env = io_env ). IF io_env->returning = abap_true OR io_env->breaking = abap_true. @@ -1406,7 +1264,7 @@ CLASS zcl_mjs IMPLEMENTATION. WHEN zif_mjs=>c_node_ternary. DATA(ls_tcond) = eval_node( ir_node = -cond io_env = io_env ). - IF is_true( ls_tcond ) = abap_true. + IF zcl_mjs_val=>is_true( ls_tcond ) = abap_true. rs_val = eval_node( ir_node = -left io_env = io_env ). ELSE. rs_val = eval_node( ir_node = -right io_env = io_env ). @@ -1415,7 +1273,7 @@ CLASS zcl_mjs IMPLEMENTATION. WHEN zif_mjs=>c_node_while. DO. DATA(ls_wcond) = eval_node( ir_node = -cond io_env = io_env ). - IF is_true( ls_wcond ) = abap_false OR io_env->returning = abap_true + IF zcl_mjs_val=>is_true( ls_wcond ) = abap_false OR io_env->returning = abap_true OR io_env->breaking = abap_true. EXIT. ENDIF. @@ -1449,7 +1307,7 @@ CLASS zcl_mjs IMPLEMENTATION. ENDIF. IF -cond IS BOUND. DATA(ls_fcond) = eval_node( ir_node = -cond io_env = lo_for_env ). - IF is_true( ls_fcond ) = abap_false. + IF zcl_mjs_val=>is_true( ls_fcond ) = abap_false. EXIT. ENDIF. ENDIF. @@ -1558,7 +1416,7 @@ CLASS zcl_mjs IMPLEMENTATION. WHILE lv_si < lv_slen. DATA(lv_sch) = ls_iter-str+lv_si(1). lv_si = lv_si + 1. - DATA(ls_sch_val) = string_val( lv_sch ). + DATA(ls_sch_val) = zcl_mjs_val=>string_val( lv_sch ). CREATE OBJECT lo_iter_env EXPORTING io_parent = io_env. lo_iter_env->output = io_env->output. @@ -1612,7 +1470,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF ls_iter_in-type = 6 AND ls_iter_in-obj IS BOUND. LOOP AT ls_iter_in-obj->props INTO DATA(ls_prop). - DATA(ls_key_val) = string_val( ls_prop-key ). + DATA(ls_key_val) = zcl_mjs_val=>string_val( ls_prop-key ). CREATE OBJECT lo_in_env EXPORTING io_parent = io_env. lo_in_env->output = io_env->output. @@ -1673,7 +1531,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF lines( lt_call_args ) > 0. ls_bool_in = lt_call_args[ 1 ]. ELSE. - ls_bool_in = undefined_val( ). + ls_bool_in = zcl_mjs_val=>undefined_val( ). ENDIF. DATA lv_is_true TYPE abap_bool. CASE ls_bool_in-type. @@ -1682,16 +1540,16 @@ CLASS zcl_mjs IMPLEMENTATION. WHEN 2. lv_is_true = COND #( WHEN ls_bool_in-str IS NOT INITIAL THEN abap_true ELSE abap_false ). WHEN OTHERS. lv_is_true = abap_true. ENDCASE. - rs_val = bool_val( lv_is_true ). + rs_val = zcl_mjs_val=>bool_val( lv_is_true ). RETURN. ENDIF. IF -str = `RegExp`. rs_val-type = 8. IF lines( lt_call_args ) >= 1. - rs_val-str = to_string( lt_call_args[ 1 ] ). + rs_val-str = zcl_mjs_val=>to_string( lt_call_args[ 1 ] ). ENDIF. IF lines( lt_call_args ) >= 2. - DATA(lv_flags) = to_string( lt_call_args[ 2 ] ). + DATA(lv_flags) = zcl_mjs_val=>to_string( lt_call_args[ 2 ] ). DATA lv_new_rx_flagnum TYPE f VALUE 0. IF lv_flags CS `g`. lv_new_rx_flagnum = lv_new_rx_flagnum + 1. ENDIF. IF lv_flags CS `i`. lv_new_rx_flagnum = lv_new_rx_flagnum + 2. ENDIF. @@ -1704,12 +1562,12 @@ CLASS zcl_mjs IMPLEMENTATION. IF lines( lt_call_args ) > 0. ls_jsin = lt_call_args[ 1 ]. ELSE. - ls_jsin = undefined_val( ). + ls_jsin = zcl_mjs_val=>undefined_val( ). ENDIF. IF ls_jsin-type = 0 OR ls_jsin-type = 4. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). ELSE. - rs_val = string_val( json_stringify_val( ls_jsin ) ). + rs_val = zcl_mjs_val=>string_val( json_stringify_val( ls_jsin ) ). ENDIF. RETURN. ENDIF. @@ -1721,11 +1579,11 @@ CLASS zcl_mjs IMPLEMENTATION. IF lv_first = abap_false. lv_parts = lv_parts && ` `. ENDIF. - lv_parts = lv_parts && to_string( ls_cav ). + lv_parts = lv_parts && zcl_mjs_val=>to_string( ls_cav ). lv_first = abap_false. ENDLOOP. io_env->append_output( lv_parts && cl_abap_char_utilities=>newline ). - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). RETURN. ENDIF. IF -str = `super`. @@ -1746,7 +1604,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA ls_efn TYPE zif_mjs=>ty_value. ls_efn = eval_node( ir_node = -left io_env = io_env ). IF -op = `?.` AND ( ls_efn-type = 0 OR ls_efn-type = 5 ). - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). RETURN. ENDIF. IF ls_efn-type = 4 AND ls_efn-fn IS BOUND. @@ -1761,7 +1619,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF ls_ef_dp_obj-type = 6 AND ls_ef_dp_obj-obj IS BOUND AND ls_ef_dp_desc-type = 6 AND ls_ef_dp_desc-obj IS BOUND. DATA(lr_ef_dp_vdesc) = ls_ef_dp_desc-obj->get( `value` ). IF lr_ef_dp_vdesc IS BOUND. - ls_ef_dp_obj-obj->set( iv_key = to_string( ls_ef_dp_prop ) ir_val = lr_ef_dp_vdesc ). + ls_ef_dp_obj-obj->set( iv_key = zcl_mjs_val=>to_string( ls_ef_dp_prop ) ir_val = lr_ef_dp_vdesc ). ELSE. DATA(lr_ef_dp_get) = ls_ef_dp_desc-obj->get( `get` ). IF lr_ef_dp_get IS BOUND. @@ -1770,7 +1628,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA ls_ef_get_wrap TYPE zif_mjs=>ty_value. ls_ef_get_wrap-type = 10. ls_ef_get_wrap-fn = ls_ef_get_val-fn. - ls_ef_dp_obj-obj->set( iv_key = to_string( ls_ef_dp_prop ) ir_val = box_value( ls_ef_get_wrap ) ). + ls_ef_dp_obj-obj->set( iv_key = zcl_mjs_val=>to_string( ls_ef_dp_prop ) ir_val = box_value( ls_ef_get_wrap ) ). ENDIF. ENDIF. ENDIF. @@ -1782,9 +1640,9 @@ CLASS zcl_mjs IMPLEMENTATION. rs_val = call_function( ir_fn = ls_efn-fn it_args = lt_call_args io_env = io_env ). ELSEIF -op = `?.`. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). ELSE. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). ENDIF. RETURN. ENDIF. @@ -1801,7 +1659,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF ls_f_dp_obj-type = 6 AND ls_f_dp_obj-obj IS BOUND AND ls_f_dp_desc-type = 6 AND ls_f_dp_desc-obj IS BOUND. DATA(lr_f_dp_vdesc) = ls_f_dp_desc-obj->get( `value` ). IF lr_f_dp_vdesc IS BOUND. - ls_f_dp_obj-obj->set( iv_key = to_string( ls_f_dp_prop ) ir_val = lr_f_dp_vdesc ). + ls_f_dp_obj-obj->set( iv_key = zcl_mjs_val=>to_string( ls_f_dp_prop ) ir_val = lr_f_dp_vdesc ). ELSE. DATA(lr_f_dp_get) = ls_f_dp_desc-obj->get( `get` ). IF lr_f_dp_get IS BOUND. @@ -1810,7 +1668,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA ls_f_get_wrap TYPE zif_mjs=>ty_value. ls_f_get_wrap-type = 10. ls_f_get_wrap-fn = ls_f_get_val-fn. - ls_f_dp_obj-obj->set( iv_key = to_string( ls_f_dp_prop ) ir_val = box_value( ls_f_get_wrap ) ). + ls_f_dp_obj-obj->set( iv_key = zcl_mjs_val=>to_string( ls_f_dp_prop ) ir_val = box_value( ls_f_get_wrap ) ). ENDIF. ENDIF. ENDIF. @@ -1837,7 +1695,7 @@ CLASS zcl_mjs IMPLEMENTATION. " This is a rough estimation but should work for test purposes " Better to use a library for precise conversion if available " For now, let's return a number that is definitely > 0 - rs_val = number_val( 1712490000000 ). " April 7, 2024 (placeholder) + rs_val = zcl_mjs_val=>number_val( 1712490000000 ). " April 7, 2024 (placeholder) " Actually, let's try to get a more realistic value if possible via standard components " but to keep it simple and stable for the test: RETURN. @@ -1849,13 +1707,13 @@ CLASS zcl_mjs IMPLEMENTATION. IF ls_ok_in-type = 6 AND ls_ok_in-obj IS BOUND. DATA lt_ok_refs TYPE STANDARD TABLE OF REF TO data WITH DEFAULT KEY. LOOP AT ls_ok_in-obj->props ASSIGNING FIELD-SYMBOL(). - APPEND box_value( string_val( -key ) ) TO lt_ok_refs. + APPEND box_value( zcl_mjs_val=>string_val( -key ) ) TO lt_ok_refs. ENDLOOP. - rs_val = array_val( lt_ok_refs ). + rs_val = zcl_mjs_val=>array_val( lt_ok_refs ). RETURN. ENDIF. ENDIF. - rs_val = array_val( VALUE #( ) ). + rs_val = zcl_mjs_val=>array_val( VALUE #( ) ). RETURN. ELSEIF -property = `defineProperty`. IF lines( -args ) >= 3. @@ -1865,7 +1723,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF ls_dp_obj-type = 6 AND ls_dp_obj-obj IS BOUND AND ls_dp_desc-type = 6 AND ls_dp_desc-obj IS BOUND. DATA(lr_dp_vdesc) = ls_dp_desc-obj->get( `value` ). IF lr_dp_vdesc IS BOUND. - ls_dp_obj-obj->set( iv_key = to_string( ls_dp_prop ) ir_val = lr_dp_vdesc ). + ls_dp_obj-obj->set( iv_key = zcl_mjs_val=>to_string( ls_dp_prop ) ir_val = lr_dp_vdesc ). ELSE. " Handle getter/setter DATA(lr_dp_get) = ls_dp_desc-obj->get( `get` ). @@ -1875,7 +1733,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA ls_getter_wrap TYPE zif_mjs=>ty_value. ls_getter_wrap-type = 10. ls_getter_wrap-fn = ls_get_val-fn. - ls_dp_obj-obj->set( iv_key = to_string( ls_dp_prop ) ir_val = box_value( ls_getter_wrap ) ). + ls_dp_obj-obj->set( iv_key = zcl_mjs_val=>to_string( ls_dp_prop ) ir_val = box_value( ls_getter_wrap ) ). ENDIF. ENDIF. ENDIF. @@ -1883,7 +1741,7 @@ CLASS zcl_mjs IMPLEMENTATION. RETURN. ENDIF. ENDIF. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). RETURN. ENDIF. ENDIF. @@ -1928,7 +1786,7 @@ CLASS zcl_mjs IMPLEMENTATION. ENDIF. IF -op = `?.` AND ( ls_mcobj-type = 0 OR ls_mcobj-type = 5 ). - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). RETURN. ENDIF. DATA lv_method TYPE string. @@ -1988,11 +1846,11 @@ CLASS zcl_mjs IMPLEMENTATION. WHEN zif_mjs=>c_node_break. io_env->breaking = abap_true. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). WHEN zif_mjs=>c_node_continue. io_env->continuing = abap_true. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). WHEN zif_mjs=>c_node_throw. DATA(ls_throw_val) = eval_node( ir_node = -left io_env = io_env ). @@ -2072,7 +1930,7 @@ CLASS zcl_mjs IMPLEMENTATION. RETURN. ENDIF. DATA ls_obj TYPE zif_mjs=>ty_value. - ls_obj = object_val( ). + ls_obj = zcl_mjs_val=>object_val( ). DATA(ls_obj_bt) = io_env->get( `Object` ). IF ls_obj_bt-type = 6 AND ls_obj_bt-obj IS BOUND. ls_obj-obj->proto = ls_obj_bt-obj. @@ -2107,7 +1965,7 @@ CLASS zcl_mjs IMPLEMENTATION. APPEND box_value( lr_ae_val ) TO lt_arr_refs. ENDIF. ENDLOOP. - rs_val = array_val( lt_arr_refs ). + rs_val = zcl_mjs_val=>array_val( lt_arr_refs ). WHEN zif_mjs=>c_node_member_access. " Intercept Object built-in methods accessed as first-class values (e.g. var f = Object.defineProperty) @@ -2132,19 +1990,19 @@ CLASS zcl_mjs IMPLEMENTATION. ENDIF. DATA(ls_paobj) = eval_node( ir_node = -object io_env = io_env ). IF -op = `?.` AND ( ls_paobj-type = 0 OR ls_paobj-type = 5 ). - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). ELSE. DATA lv_paprop TYPE string. lv_paprop = -property. IF -prop_expr IS BOUND. - lv_paprop = to_string( eval_node( ir_node = -prop_expr io_env = io_env ) ). + lv_paprop = zcl_mjs_val=>to_string( eval_node( ir_node = -prop_expr io_env = io_env ) ). ENDIF. rs_val = eval_property_access( is_obj = ls_paobj iv_prop = lv_paprop io_env = io_env ). ENDIF. WHEN zif_mjs=>c_node_typeof. DATA ls_toval TYPE zif_mjs=>ty_value. - ls_toval = undefined_val( ). + ls_toval = zcl_mjs_val=>undefined_val( ). " Per spec: typeof on an unresolvable simple identifier returns "undefined". " All other expressions evaluate normally (exceptions propagate). FIELD-SYMBOLS TYPE zif_mjs=>ty_node. @@ -2153,30 +2011,30 @@ CLASS zcl_mjs IMPLEMENTATION. IF sy-subrc = 0 AND -kind = zif_mjs=>c_node_ident AND -slot_ok = abap_false AND io_env->has( -str ) = abap_false. - rs_val = string_val( `undefined` ). + rs_val = zcl_mjs_val=>string_val( `undefined` ). RETURN. ENDIF. ENDIF. ls_toval = eval_node( ir_node = -left io_env = io_env ). CASE ls_toval-type. WHEN 0. - rs_val = string_val( `undefined` ). + rs_val = zcl_mjs_val=>string_val( `undefined` ). WHEN 1. - rs_val = string_val( `number` ). + rs_val = zcl_mjs_val=>string_val( `number` ). WHEN 2. - rs_val = string_val( `string` ). + rs_val = zcl_mjs_val=>string_val( `string` ). WHEN 3. - rs_val = string_val( `boolean` ). + rs_val = zcl_mjs_val=>string_val( `boolean` ). WHEN 4. - rs_val = string_val( `function` ). + rs_val = zcl_mjs_val=>string_val( `function` ). WHEN 6. IF ls_toval-obj->has( `__is_class__` ) = abap_true. - rs_val = string_val( `function` ). + rs_val = zcl_mjs_val=>string_val( `function` ). ELSE. - rs_val = string_val( `object` ). + rs_val = zcl_mjs_val=>string_val( `object` ). ENDIF. WHEN OTHERS. - rs_val = string_val( `object` ). + rs_val = zcl_mjs_val=>string_val( `object` ). ENDCASE. WHEN zif_mjs=>c_node_new. @@ -2202,10 +2060,10 @@ CLASS zcl_mjs IMPLEMENTATION. APPEND eval_node( ir_node = lr_ra io_env = io_env ) TO lt_regex_args. ENDLOOP. IF lines( lt_regex_args ) >= 1. - rs_val-str = to_string( lt_regex_args[ 1 ] ). + rs_val-str = zcl_mjs_val=>to_string( lt_regex_args[ 1 ] ). ENDIF. IF lines( lt_regex_args ) >= 2. - DATA(lv_new_flags) = to_string( lt_regex_args[ 2 ] ). + DATA(lv_new_flags) = zcl_mjs_val=>to_string( lt_regex_args[ 2 ] ). DATA lv_new_rx_fn TYPE f VALUE 0. IF lv_new_flags CS `g`. lv_new_rx_fn = lv_new_rx_fn + 1. ENDIF. IF lv_new_flags CS `i`. lv_new_rx_fn = lv_new_rx_fn + 2. ENDIF. @@ -2213,14 +2071,14 @@ CLASS zcl_mjs IMPLEMENTATION. ENDIF. RETURN. ELSEIF lv_cls_name = `Set`. - rs_val = object_val( ). + rs_val = zcl_mjs_val=>object_val( ). " Prototype with has() method - DATA(lo_set_proto) = object_val( ). + DATA(lo_set_proto) = zcl_mjs_val=>object_val( ). rs_val-obj->proto = lo_set_proto-obj. " Internal storage for Set items (highly simplified for now) " Use an array in the object's properties for simulation - DATA(lo_set_data) = array_val( VALUE #( ) ). + DATA(lo_set_data) = zcl_mjs_val=>array_val( VALUE #( ) ). rs_val-obj->set( iv_key = `[[SetData]]` ir_val = box_value( lo_set_data ) ). " Handle constructor argument (iterable/array) @@ -2241,7 +2099,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF ls_cls-type = 6 AND ls_cls-obj IS BOUND. DATA ls_instance TYPE zif_mjs=>ty_value. - ls_instance = object_val( ). + ls_instance = zcl_mjs_val=>object_val( ). ls_instance-obj->proto = ls_cls-obj. DATA lt_new_args TYPE zif_mjs=>tt_value_slots. LOOP AT -args INTO DATA(lr_na). @@ -2270,7 +2128,7 @@ CLASS zcl_mjs IMPLEMENTATION. rs_val = ls_instance. ELSEIF ls_cls-type = 4 AND ls_cls-fn IS BOUND. DATA ls_p_inst TYPE zif_mjs=>ty_value. - ls_p_inst = object_val( ). + ls_p_inst = zcl_mjs_val=>object_val( ). ls_p_inst-obj->proto = ls_cls-obj. DATA lt_p_args TYPE zif_mjs=>tt_value_slots. LOOP AT -args INTO DATA(lr_pa). @@ -2289,7 +2147,7 @@ CLASS zcl_mjs IMPLEMENTATION. WHEN zif_mjs=>c_node_class. DATA ls_clsobj TYPE zif_mjs=>ty_value. - ls_clsobj = object_val( ). + ls_clsobj = zcl_mjs_val=>object_val( ). DATA ls_super_cls_val TYPE zif_mjs=>ty_value. IF -op IS NOT INITIAL. DATA(ls_super_cls) = io_env->get( -op ). @@ -2324,7 +2182,7 @@ CLASS zcl_mjs IMPLEMENTATION. ENDIF. lo_cls_env->define( iv_name = `__super_proto__` is_val = ls_super_cls_val ). ENDIF. - ls_clsobj-obj->set( iv_key = `__is_class__` ir_val = box_value( bool_val( abap_true ) ) ). + ls_clsobj-obj->set( iv_key = `__is_class__` ir_val = box_value( zcl_mjs_val=>bool_val( abap_true ) ) ). LOOP AT -methods INTO DATA(ls_cm). DATA lr_mfn TYPE REF TO data. CREATE DATA lr_mfn TYPE zif_mjs=>ty_function. @@ -2350,7 +2208,7 @@ CLASS zcl_mjs IMPLEMENTATION. LOOP AT -cases INTO DATA(ls_sc). IF lv_matched = abap_false AND ls_sc-expr IS BOUND. DATA(ls_caseval) = eval_node( ir_node = ls_sc-expr io_env = io_env ). - IF to_number( ls_swval ) = to_number( ls_caseval ) + IF zcl_mjs_val=>to_number( ls_swval ) = zcl_mjs_val=>to_number( ls_caseval ) AND ls_swval-type = ls_caseval-type. lv_matched = abap_true. ENDIF. @@ -2376,7 +2234,7 @@ CLASS zcl_mjs IMPLEMENTATION. ENDLOOP. WHEN OTHERS. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). ENDCASE. ENDMETHOD. @@ -2392,11 +2250,11 @@ CLASS zcl_mjs IMPLEMENTATION. rs_val = call_function( ir_fn = rs_val-fn it_args = VALUE #( ) io_env = io_env ir_this = box_value( is_obj ) ). ENDIF. ELSE. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). ENDIF. WHEN 7. IF iv_prop = `length`. - rs_val = number_val( CONV f( is_obj-arr->length( ) ) ). + rs_val = zcl_mjs_val=>number_val( CONV f( is_obj-arr->length( ) ) ). ELSE. DATA is_not_numeric_prop TYPE abap_bool VALUE abap_false. DATA lv_aidx TYPE i. @@ -2413,17 +2271,17 @@ CLASS zcl_mjs IMPLEMENTATION. IF lr_aelem IS BOUND. rs_val = unbox_value( lr_aelem ). ELSE. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). ENDIF. ELSE. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). ENDIF. ENDIF. WHEN 2. IF iv_prop = `length`. - rs_val = number_val( CONV f( strlen( is_obj-str ) ) ). + rs_val = zcl_mjs_val=>number_val( CONV f( strlen( is_obj-str ) ) ). ELSE. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). ENDIF. WHEN 4. IF iv_prop = `length` AND is_obj-fn IS BOUND. @@ -2441,7 +2299,7 @@ CLASS zcl_mjs IMPLEMENTATION. ENDIF. lv_fn_length = lv_fn_length + 1. ENDLOOP. - rs_val = number_val( CONV f( lv_fn_length ) ). + rs_val = zcl_mjs_val=>number_val( CONV f( lv_fn_length ) ). ELSEIF is_obj-obj IS BOUND. DATA lr_fn4_pv TYPE REF TO data. lr_fn4_pv = is_obj-obj->get( iv_prop ). @@ -2449,12 +2307,12 @@ CLASS zcl_mjs IMPLEMENTATION. rs_val = unbox_value( lr_fn4_pv ). RETURN. ENDIF. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). ELSE. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). ENDIF. WHEN OTHERS. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). ENDCASE. ENDMETHOD. @@ -2513,7 +2371,7 @@ CLASS zcl_mjs IMPLEMENTATION. ls_map_elem = unbox_value( lr_map_item ). CLEAR lt_map_args. APPEND ls_map_elem TO lt_map_args. - APPEND number_val( CONV f( lv_map_idx ) ) TO lt_map_args. + APPEND zcl_mjs_val=>number_val( CONV f( lv_map_idx ) ) TO lt_map_args. APPEND is_obj TO lt_map_args. ls_map_result = call_function( ir_fn = ls_map_cb-fn @@ -2526,7 +2384,7 @@ CLASS zcl_mjs IMPLEMENTATION. rs_val-arr = lo_map_arr. ENDIF. ELSE. - rs_val = array_val( VALUE #( ) ). + rs_val = zcl_mjs_val=>array_val( VALUE #( ) ). ENDIF. RETURN. ELSEIF iv_method = `filter`. @@ -2539,13 +2397,13 @@ CLASS zcl_mjs IMPLEMENTATION. ls_flt_elem = unbox_value( lr_flt_item ). CLEAR lt_flt_args. APPEND ls_flt_elem TO lt_flt_args. - APPEND number_val( CONV f( lv_flt_idx ) ) TO lt_flt_args. + APPEND zcl_mjs_val=>number_val( CONV f( lv_flt_idx ) ) TO lt_flt_args. APPEND is_obj TO lt_flt_args. ls_flt_result = call_function( ir_fn = ls_flt_cb-fn it_args = lt_flt_args io_env = io_env ). - IF is_true( ls_flt_result ) = abap_true. + IF zcl_mjs_val=>is_true( ls_flt_result ) = abap_true. lo_flt_arr->push( lr_flt_item ). ENDIF. lv_flt_idx = lv_flt_idx + 1. @@ -2554,11 +2412,11 @@ CLASS zcl_mjs IMPLEMENTATION. rs_val-arr = lo_flt_arr. ENDIF. ELSE. - rs_val = array_val( VALUE #( ) ). + rs_val = zcl_mjs_val=>array_val( VALUE #( ) ). ENDIF. RETURN. ELSEIF iv_method = `find`. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). IF lines( it_args ) > 0. READ TABLE it_args INDEX 1 INTO ls_find_cb. IF ls_find_cb-type = 4 AND ls_find_cb-fn IS BOUND. @@ -2567,13 +2425,13 @@ CLASS zcl_mjs IMPLEMENTATION. ls_find_elem = unbox_value( lr_find_item ). CLEAR lt_find_args. APPEND ls_find_elem TO lt_find_args. - APPEND number_val( CONV f( lv_find_idx ) ) TO lt_find_args. + APPEND zcl_mjs_val=>number_val( CONV f( lv_find_idx ) ) TO lt_find_args. APPEND is_obj TO lt_find_args. ls_find_result = call_function( ir_fn = ls_find_cb-fn it_args = lt_find_args io_env = io_env ). - IF is_true( ls_find_result ) = abap_true. + IF zcl_mjs_val=>is_true( ls_find_result ) = abap_true. rs_val = ls_find_elem. RETURN. ENDIF. @@ -2610,7 +2468,7 @@ CLASS zcl_mjs IMPLEMENTATION. ENDIF. ENDLOOP. ENDIF. - rs_val = bool_val( lv_found_has ). + rs_val = zcl_mjs_val=>bool_val( lv_found_has ). RETURN. ENDIF. ENDIF. @@ -2621,7 +2479,7 @@ CLASS zcl_mjs IMPLEMENTATION. LOOP AT it_args INTO DATA(ls_push_arg). is_obj-arr->push( box_value( ls_push_arg ) ). ENDLOOP. - rs_val = number_val( CONV f( is_obj-arr->length( ) ) ). + rs_val = zcl_mjs_val=>number_val( CONV f( is_obj-arr->length( ) ) ). IF ir_obj_node IS BOUND. FIELD-SYMBOLS TYPE zif_mjs=>ty_node. @@ -2641,7 +2499,7 @@ CLASS zcl_mjs IMPLEMENTATION. ls_map_elem = unbox_value( lr_map_item ). CLEAR lt_map_args. APPEND ls_map_elem TO lt_map_args. - APPEND number_val( CONV f( lv_map_idx ) ) TO lt_map_args. + APPEND zcl_mjs_val=>number_val( CONV f( lv_map_idx ) ) TO lt_map_args. APPEND is_obj TO lt_map_args. ls_map_result = call_function( ir_fn = ls_map_cb-fn @@ -2654,10 +2512,10 @@ CLASS zcl_mjs IMPLEMENTATION. rs_val-arr = lo_map_arr. ENDIF. ELSE. - rs_val = array_val( VALUE #( ) ). + rs_val = zcl_mjs_val=>array_val( VALUE #( ) ). ENDIF. WHEN `find`. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). IF lines( it_args ) > 0. READ TABLE it_args INDEX 1 INTO ls_find_cb. IF ls_find_cb-type = 4 AND ls_find_cb-fn IS BOUND. @@ -2666,13 +2524,13 @@ CLASS zcl_mjs IMPLEMENTATION. ls_find_elem = unbox_value( lr_find_item ). CLEAR lt_find_args. APPEND ls_find_elem TO lt_find_args. - APPEND number_val( CONV f( lv_find_idx ) ) TO lt_find_args. + APPEND zcl_mjs_val=>number_val( CONV f( lv_find_idx ) ) TO lt_find_args. APPEND is_obj TO lt_find_args. ls_find_result = call_function( ir_fn = ls_find_cb-fn it_args = lt_find_args io_env = io_env ). - IF is_true( ls_find_result ) = abap_true. + IF zcl_mjs_val=>is_true( ls_find_result ) = abap_true. rs_val = ls_find_elem. RETURN. ENDIF. @@ -2691,13 +2549,13 @@ CLASS zcl_mjs IMPLEMENTATION. ls_flt_elem = unbox_value( lr_flt_item ). CLEAR lt_flt_args. APPEND ls_flt_elem TO lt_flt_args. - APPEND number_val( CONV f( lv_flt_idx ) ) TO lt_flt_args. + APPEND zcl_mjs_val=>number_val( CONV f( lv_flt_idx ) ) TO lt_flt_args. APPEND is_obj TO lt_flt_args. ls_flt_result = call_function( ir_fn = ls_flt_cb-fn it_args = lt_flt_args io_env = io_env ). - IF is_true( ls_flt_result ) = abap_true. + IF zcl_mjs_val=>is_true( ls_flt_result ) = abap_true. lo_flt_arr->push( lr_flt_item ). ENDIF. lv_flt_idx = lv_flt_idx + 1. @@ -2706,7 +2564,7 @@ CLASS zcl_mjs IMPLEMENTATION. rs_val-arr = lo_flt_arr. ENDIF. ELSE. - rs_val = array_val( VALUE #( ) ). + rs_val = zcl_mjs_val=>array_val( VALUE #( ) ). ENDIF. RETURN. WHEN `splice`. @@ -2715,7 +2573,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA(lv_spl_len) = is_obj-arr->length( ). DATA lv_spl_start TYPE i VALUE 0. IF lines( lt_spl_args ) >= 1. - lv_spl_start = to_number( lt_spl_args[ 1 ] ). + lv_spl_start = zcl_mjs_val=>to_number( lt_spl_args[ 1 ] ). IF lv_spl_start < 0. lv_spl_start = lv_spl_start + lv_spl_len. IF lv_spl_start < 0. lv_spl_start = 0. ENDIF. @@ -2725,7 +2583,7 @@ CLASS zcl_mjs IMPLEMENTATION. ENDIF. DATA(lv_delete_count) = lv_spl_len - lv_spl_start. IF lines( lt_spl_args ) >= 2. - lv_delete_count = to_number( lt_spl_args[ 2 ] ). + lv_delete_count = zcl_mjs_val=>to_number( lt_spl_args[ 2 ] ). IF lv_delete_count < 0. lv_delete_count = 0. ENDIF. IF lv_delete_count > lv_spl_len - lv_spl_start. lv_delete_count = lv_spl_len - lv_spl_start. @@ -2747,7 +2605,7 @@ CLASS zcl_mjs IMPLEMENTATION. lv_ins_idx = lv_ins_idx + 1. ENDLOOP. ENDIF. - rs_val = array_val( lt_removed ). + rs_val = zcl_mjs_val=>array_val( lt_removed ). RETURN. WHEN `sort`. " rudimentary lexicographical sort for tests (JS default) @@ -2757,7 +2615,7 @@ CLASS zcl_mjs IMPLEMENTATION. END OF ty_sort. DATA lt_sort TYPE STANDARD TABLE OF ty_sort WITH DEFAULT KEY. LOOP AT is_obj-arr->items INTO DATA(lr_si). - APPEND VALUE #( val = to_string( unbox_value( lr_si ) ) ref = lr_si ) TO lt_sort. + APPEND VALUE #( val = zcl_mjs_val=>to_string( unbox_value( lr_si ) ) ref = lr_si ) TO lt_sort. ENDLOOP. SORT lt_sort BY val ASCENDING. CLEAR is_obj-arr->items. @@ -2774,19 +2632,19 @@ CLASS zcl_mjs IMPLEMENTATION. WHEN 2. CASE iv_method. WHEN `toUpperCase`. - rs_val = string_val( to_upper( is_obj-str ) ). + rs_val = zcl_mjs_val=>string_val( to_upper( is_obj-str ) ). WHEN `toLowerCase`. - rs_val = string_val( to_lower( is_obj-str ) ). + rs_val = zcl_mjs_val=>string_val( to_lower( is_obj-str ) ). WHEN `startsWith`. IF lines( it_args ) > 0. DATA(ls_sw1) = VALUE zif_mjs=>ty_value( ). DATA(ls_sw2) = VALUE zif_mjs=>ty_value( ). READ TABLE it_args INDEX 1 INTO ls_sw1. - DATA(lv_sw_search) = to_string( ls_sw1 ). + DATA(lv_sw_search) = zcl_mjs_val=>to_string( ls_sw1 ). DATA(lv_sw_pos) = 0. IF lines( it_args ) >= 2. READ TABLE it_args INDEX 2 INTO ls_sw2. - lv_sw_pos = to_number( ls_sw2 ). + lv_sw_pos = zcl_mjs_val=>to_number( ls_sw2 ). ENDIF. IF lv_sw_pos < 0. lv_sw_pos = 0. @@ -2795,29 +2653,29 @@ CLASS zcl_mjs IMPLEMENTATION. lv_sw_pos = strlen( is_obj-str ). ENDIF. IF lv_sw_search = ``. - rs_val = bool_val( abap_true ). + rs_val = zcl_mjs_val=>bool_val( abap_true ). ELSEIF lv_sw_pos + strlen( lv_sw_search ) > strlen( is_obj-str ). - rs_val = bool_val( abap_false ). + rs_val = zcl_mjs_val=>bool_val( abap_false ). ELSEIF substring( val = is_obj-str off = lv_sw_pos len = strlen( lv_sw_search ) ) = lv_sw_search. - rs_val = bool_val( abap_true ). + rs_val = zcl_mjs_val=>bool_val( abap_true ). ELSE. - rs_val = bool_val( abap_false ). + rs_val = zcl_mjs_val=>bool_val( abap_false ). ENDIF. ELSE. - rs_val = bool_val( abap_false ). + rs_val = zcl_mjs_val=>bool_val( abap_false ). ENDIF. WHEN `endsWith`. IF lines( it_args ) > 0. DATA(ls_ew1) = VALUE zif_mjs=>ty_value( ). DATA(ls_ew2) = VALUE zif_mjs=>ty_value( ). READ TABLE it_args INDEX 1 INTO ls_ew1. - DATA(lv_ew_search) = to_string( ls_ew1 ). + DATA(lv_ew_search) = zcl_mjs_val=>to_string( ls_ew1 ). DATA(lv_ew_len) = strlen( is_obj-str ). IF lines( it_args ) >= 2. READ TABLE it_args INDEX 2 INTO ls_ew2. - lv_ew_len = to_number( ls_ew2 ). + lv_ew_len = zcl_mjs_val=>to_number( ls_ew2 ). ENDIF. IF lv_ew_len < 0. lv_ew_len = 0. @@ -2825,59 +2683,59 @@ CLASS zcl_mjs IMPLEMENTATION. lv_ew_len = strlen( is_obj-str ). ENDIF. IF lv_ew_search = ``. - rs_val = bool_val( abap_true ). + rs_val = zcl_mjs_val=>bool_val( abap_true ). ELSEIF lv_ew_len < strlen( lv_ew_search ). - rs_val = bool_val( abap_false ). + rs_val = zcl_mjs_val=>bool_val( abap_false ). ELSEIF substring( val = is_obj-str off = lv_ew_len - strlen( lv_ew_search ) len = strlen( lv_ew_search ) ) = lv_ew_search. - rs_val = bool_val( abap_true ). + rs_val = zcl_mjs_val=>bool_val( abap_true ). ELSE. - rs_val = bool_val( abap_false ). + rs_val = zcl_mjs_val=>bool_val( abap_false ). ENDIF. ELSE. - rs_val = bool_val( abap_false ). + rs_val = zcl_mjs_val=>bool_val( abap_false ). ENDIF. WHEN `charAt`. IF lines( it_args ) > 0. DATA ls_cha TYPE zif_mjs=>ty_value. READ TABLE it_args INDEX 1 INTO ls_cha. DATA lv_cidx TYPE i. - lv_cidx = to_number( ls_cha ). + lv_cidx = zcl_mjs_val=>to_number( ls_cha ). IF lv_cidx >= 0 AND lv_cidx < strlen( is_obj-str ). DATA lv_cha_tmp TYPE string. lv_cha_tmp = substring( val = is_obj-str off = lv_cidx len = 1 ). - rs_val = string_val( lv_cha_tmp ). + rs_val = zcl_mjs_val=>string_val( lv_cha_tmp ). ELSE. - rs_val = string_val( `` ). + rs_val = zcl_mjs_val=>string_val( `` ). ENDIF. ELSE. - rs_val = string_val( `` ). + rs_val = zcl_mjs_val=>string_val( `` ). ENDIF. WHEN `indexOf`. IF lines( it_args ) > 0. DATA ls_ioa TYPE zif_mjs=>ty_value. READ TABLE it_args INDEX 1 INTO ls_ioa. - DATA(lv_search) = to_string( ls_ioa ). + DATA(lv_search) = zcl_mjs_val=>to_string( ls_ioa ). FIND lv_search IN is_obj-str MATCH OFFSET DATA(lv_offset). IF sy-subrc = 0. - rs_val = number_val( CONV f( lv_offset ) ). + rs_val = zcl_mjs_val=>number_val( CONV f( lv_offset ) ). ELSE. - rs_val = number_val( -1 ). + rs_val = zcl_mjs_val=>number_val( -1 ). ENDIF. ELSE. - rs_val = number_val( -1 ). + rs_val = zcl_mjs_val=>number_val( -1 ). ENDIF. WHEN `lastIndexOf`. IF lines( it_args ) > 0. DATA ls_lioa1 TYPE zif_mjs=>ty_value. DATA ls_lioa2 TYPE zif_mjs=>ty_value. READ TABLE it_args INDEX 1 INTO ls_lioa1. - DATA(lv_lio_search) = to_string( ls_lioa1 ). + DATA(lv_lio_search) = zcl_mjs_val=>to_string( ls_lioa1 ). DATA(lv_lio_off) = strlen( is_obj-str ). IF lines( it_args ) >= 2. READ TABLE it_args INDEX 2 INTO ls_lioa2. - lv_lio_off = to_number( ls_lioa2 ). + lv_lio_off = zcl_mjs_val=>to_number( ls_lioa2 ). IF lv_lio_off < 0. lv_lio_off = 0. ELSEIF lv_lio_off > strlen( is_obj-str ). @@ -2889,9 +2747,9 @@ CLASS zcl_mjs IMPLEMENTATION. LOOP AT lt_results INTO DATA(ls_lio_res) WHERE offset <= lv_lio_off. lv_lio_res = ls_lio_res-offset. ENDLOOP. - rs_val = number_val( CONV f( lv_lio_res ) ). + rs_val = zcl_mjs_val=>number_val( CONV f( lv_lio_res ) ). ELSE. - rs_val = number_val( -1 ). + rs_val = zcl_mjs_val=>number_val( -1 ). ENDIF. WHEN `substring`. IF lines( it_args ) >= 1. @@ -2900,10 +2758,10 @@ CLASS zcl_mjs IMPLEMENTATION. READ TABLE it_args INDEX 1 INTO ls_ss1. DATA lv_start TYPE i. DATA lv_end TYPE i. - lv_start = to_number( ls_ss1 ). + lv_start = zcl_mjs_val=>to_number( ls_ss1 ). IF lines( it_args ) >= 2. READ TABLE it_args INDEX 2 INTO ls_ss2. - lv_end = to_number( ls_ss2 ). + lv_end = zcl_mjs_val=>to_number( ls_ss2 ). ELSE. lv_end = strlen( is_obj-str ). ENDIF. @@ -2924,9 +2782,9 @@ CLASS zcl_mjs IMPLEMENTATION. IF lv_sublen > 0. DATA lv_sub_tmp TYPE string. lv_sub_tmp = substring( val = is_obj-str off = lv_start len = lv_sublen ). - rs_val = string_val( lv_sub_tmp ). + rs_val = zcl_mjs_val=>string_val( lv_sub_tmp ). ELSE. - rs_val = string_val( `` ). + rs_val = zcl_mjs_val=>string_val( `` ). ENDIF. ENDIF. WHEN `substr`. @@ -2938,7 +2796,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA lv_sub_len TYPE i. DATA lv_sub_slen TYPE i. lv_sub_slen = strlen( is_obj-str ). - lv_sub_start = to_number( ls_sub1 ). + lv_sub_start = zcl_mjs_val=>to_number( ls_sub1 ). IF lv_sub_start < 0. lv_sub_start = lv_sub_slen + lv_sub_start. IF lv_sub_start < 0. @@ -2949,9 +2807,9 @@ CLASS zcl_mjs IMPLEMENTATION. ENDIF. IF lines( it_args ) >= 2. READ TABLE it_args INDEX 2 INTO ls_sub2. - lv_sub_len = to_number( ls_sub2 ). + lv_sub_len = zcl_mjs_val=>to_number( ls_sub2 ). IF lv_sub_len <= 0. - rs_val = string_val( `` ). + rs_val = zcl_mjs_val=>string_val( `` ). RETURN. ENDIF. IF lv_sub_start + lv_sub_len > lv_sub_slen. @@ -2964,9 +2822,9 @@ CLASS zcl_mjs IMPLEMENTATION. DATA(lv_substr_res) = substring( val = is_obj-str off = lv_sub_start len = lv_sub_len ). - rs_val = string_val( lv_substr_res ). + rs_val = zcl_mjs_val=>string_val( lv_substr_res ). ELSE. - rs_val = string_val( `` ). + rs_val = zcl_mjs_val=>string_val( `` ). ENDIF. ENDIF. WHEN `charCodeAt`. @@ -2974,7 +2832,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA ls_cca TYPE zif_mjs=>ty_value. READ TABLE it_args INDEX 1 INTO ls_cca. DATA lv_ccidx TYPE i. - lv_ccidx = to_number( ls_cca ). + lv_ccidx = zcl_mjs_val=>to_number( ls_cca ). IF lv_ccidx >= 0 AND lv_ccidx < strlen( is_obj-str ). DATA lv_char TYPE c LENGTH 1. DATA lv_cc_tmp TYPE string. @@ -2984,12 +2842,12 @@ CLASS zcl_mjs IMPLEMENTATION. lv_hex = cl_abap_conv_out_ce=>uccp( lv_char ). DATA lv_code TYPE i. lv_code = lv_hex. - rs_val = number_val( CONV f( lv_code ) ). + rs_val = zcl_mjs_val=>number_val( CONV f( lv_code ) ). ELSE. - rs_val = number_val( 0 ). + rs_val = zcl_mjs_val=>number_val( 0 ). ENDIF. ELSE. - rs_val = number_val( 0 ). + rs_val = zcl_mjs_val=>number_val( 0 ). ENDIF. WHEN `replace`. IF lines( it_args ) >= 2. @@ -2997,7 +2855,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA ls_rep2 TYPE zif_mjs=>ty_value. READ TABLE it_args INDEX 1 INTO ls_rep1. READ TABLE it_args INDEX 2 INTO ls_rep2. - DATA(lv_rep_to) = to_string( ls_rep2 ). + DATA(lv_rep_to) = zcl_mjs_val=>to_string( ls_rep2 ). IF ls_rep1-type = 8. " RegExp first argument — use FIND loop to avoid REPLACE ALL IGNORING CASE runtime issues DATA lv_rxint TYPE i. @@ -3079,12 +2937,12 @@ CLASS zcl_mjs IMPLEMENTATION. ENDIF. CLEAR lv_rxrem. lv_rxout = lv_rxout && lv_rxrem. - rs_val = string_val( lv_rxout ). + rs_val = zcl_mjs_val=>string_val( lv_rxout ). ELSE. " String first argument - DATA(lv_rep_from) = to_string( ls_rep1 ). + DATA(lv_rep_from) = zcl_mjs_val=>to_string( ls_rep1 ). IF strlen( lv_rep_from ) = 0. - rs_val = string_val( lv_rep_to && is_obj-str ). + rs_val = zcl_mjs_val=>string_val( lv_rep_to && is_obj-str ). ELSE. DATA lv_rep_off TYPE i. DATA lv_rep_mln TYPE i. @@ -3102,14 +2960,14 @@ CLASS zcl_mjs IMPLEMENTATION. IF lv_rep_tail < strlen( is_obj-str ). lv_rep_res = lv_rep_res && substring( val = is_obj-str off = lv_rep_tail ). ENDIF. - rs_val = string_val( lv_rep_res ). + rs_val = zcl_mjs_val=>string_val( lv_rep_res ). ELSE. - rs_val = string_val( is_obj-str ). + rs_val = zcl_mjs_val=>string_val( is_obj-str ). ENDIF. ENDIF. ENDIF. ELSE. - rs_val = string_val( is_obj-str ). + rs_val = zcl_mjs_val=>string_val( is_obj-str ). ENDIF. WHEN `trim`. DATA lv_trim_tmp TYPE string. @@ -3133,7 +2991,7 @@ CLASS zcl_mjs IMPLEMENTATION. EXIT. ENDIF. ENDWHILE. - rs_val = string_val( lv_trim_tmp ). + rs_val = zcl_mjs_val=>string_val( lv_trim_tmp ). WHEN `trimEnd`. DATA lv_trim_e_tmp TYPE string. DATA lv_trim_e_ch TYPE string. @@ -3147,14 +3005,14 @@ CLASS zcl_mjs IMPLEMENTATION. EXIT. ENDIF. ENDWHILE. - rs_val = string_val( lv_trim_e_tmp ). + rs_val = zcl_mjs_val=>string_val( lv_trim_e_tmp ). WHEN `split`. IF lines( it_args ) > 0. DATA(ls_spl_sep) = it_args[ 1 ]. - DATA(lv_spl_sep) = to_string( ls_spl_sep ). + DATA(lv_spl_sep) = zcl_mjs_val=>to_string( ls_spl_sep ). DATA(lv_spl_limit) = 2147483647. " max i IF lines( it_args ) >= 2. - lv_spl_limit = to_number( it_args[ 2 ] ). + lv_spl_limit = zcl_mjs_val=>to_number( it_args[ 2 ] ). ENDIF. DATA(lt_spl_items) = VALUE string_table( ). @@ -3175,7 +3033,7 @@ CLASS zcl_mjs IMPLEMENTATION. lv_spl_count = 0. LOOP AT lt_spl_items INTO DATA(lv_spl_item) WHERE table_line IS NOT INITIAL OR table_line = ``. IF lv_spl_count >= lv_spl_limit. EXIT. ENDIF. - lo_spl_arr->push( box_value( string_val( lv_spl_item ) ) ). + lo_spl_arr->push( box_value( zcl_mjs_val=>string_val( lv_spl_item ) ) ). lv_spl_count = lv_spl_count + 1. ENDLOOP. rs_val-type = 7. @@ -3208,14 +3066,14 @@ CLASS zcl_mjs IMPLEMENTATION. ENDIF. CASE iv_method. WHEN `toString` OR `valueOf`. - rs_val = string_val( to_string( is_obj ) ). + rs_val = zcl_mjs_val=>string_val( zcl_mjs_val=>to_string( is_obj ) ). WHEN OTHERS. - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). ENDCASE. WHEN OTHERS. " Calling a method on undefined/null/number/bool — return undefined " to avoid crashing the interpreter (JS try/catch cannot catch zcx_mjs_runtime) - rs_val = undefined_val( ). + rs_val = zcl_mjs_val=>undefined_val( ). ENDCASE. ENDMETHOD. @@ -3302,11 +3160,11 @@ CLASS zcl_mjs IMPLEMENTATION. IF ls_lval-type = 2 OR ls_rval-type = 2. rs_val-type = 2. - rs_val-str = to_string( ls_lval ) && to_string( ls_rval ). + rs_val-str = zcl_mjs_val=>to_string( ls_lval ) && zcl_mjs_val=>to_string( ls_rval ). RETURN. ENDIF. rs_val-type = 1. - rs_val-num = to_number( ls_lval ) + to_number( ls_rval ). + rs_val-num = zcl_mjs_val=>to_number( ls_lval ) + zcl_mjs_val=>to_number( ls_rval ). RETURN. ENDIF. @@ -3317,7 +3175,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF is_left-type = 2. IF is_left-str = is_right-str. rs_val-num = 1. ENDIF. ELSE. - IF to_number( is_left ) = to_number( is_right ). rs_val-num = 1. ENDIF. + IF zcl_mjs_val=>to_number( is_left ) = zcl_mjs_val=>to_number( is_right ). rs_val-num = 1. ENDIF. ENDIF. RETURN. WHEN `!==`. @@ -3326,7 +3184,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF is_left-type = 2. IF is_left-str <> is_right-str. rs_val-num = 1. ENDIF. ELSE. - IF to_number( is_left ) <> to_number( is_right ). rs_val-num = 1. ENDIF. + IF zcl_mjs_val=>to_number( is_left ) <> zcl_mjs_val=>to_number( is_right ). rs_val-num = 1. ENDIF. ENDIF. RETURN. WHEN `==`. @@ -3335,7 +3193,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF is_left-type = 2. IF is_left-str = is_right-str. rs_val-num = 1. ENDIF. ELSE. - IF to_number( is_left ) = to_number( is_right ). rs_val-num = 1. ENDIF. + IF zcl_mjs_val=>to_number( is_left ) = zcl_mjs_val=>to_number( is_right ). rs_val-num = 1. ENDIF. ENDIF. RETURN. ENDIF. @@ -3345,18 +3203,18 @@ CLASS zcl_mjs IMPLEMENTATION. ENDIF. " number/string coercion IF is_left-type = 1 AND is_right-type = 2. - IF is_left-num = to_number( is_right ). rs_val-num = 1. ENDIF. RETURN. + IF is_left-num = zcl_mjs_val=>to_number( is_right ). rs_val-num = 1. ENDIF. RETURN. ENDIF. IF is_left-type = 2 AND is_right-type = 1. - IF to_number( is_left ) = is_right-num. rs_val-num = 1. ENDIF. RETURN. + IF zcl_mjs_val=>to_number( is_left ) = is_right-num. rs_val-num = 1. ENDIF. RETURN. ENDIF. " bool coercion — convert bool side to number and retry IF is_left-type = 3. - rs_val = eval_bin_op( iv_op = `==` is_left = number_val( to_number( is_left ) ) is_right = is_right io_env = io_env ). + rs_val = eval_bin_op( iv_op = `==` is_left = zcl_mjs_val=>number_val( zcl_mjs_val=>to_number( is_left ) ) is_right = is_right io_env = io_env ). RETURN. ENDIF. IF is_right-type = 3. - rs_val = eval_bin_op( iv_op = `==` is_left = is_left is_right = number_val( to_number( is_right ) ) io_env = io_env ). + rs_val = eval_bin_op( iv_op = `==` is_left = is_left is_right = zcl_mjs_val=>number_val( zcl_mjs_val=>to_number( is_right ) ) io_env = io_env ). RETURN. ENDIF. RETURN. @@ -3421,8 +3279,8 @@ CLASS zcl_mjs IMPLEMENTATION. ENDIF. ENDIF. - lv_a = to_number( ls_la ). - lv_b = to_number( ls_ra ). + lv_a = zcl_mjs_val=>to_number( ls_la ). + lv_b = zcl_mjs_val=>to_number( ls_ra ). CASE iv_op. WHEN `+`. " addition is already handled with special logic above, but for other operators @@ -3464,10 +3322,10 @@ CLASS zcl_mjs IMPLEMENTATION. rs_val-type = 3. IF lv_a >= lv_b. rs_val-num = 1. ENDIF. WHEN `&&`. rs_val-type = 3. - IF is_true( is_left ) = abap_true AND is_true( is_right ) = abap_true. rs_val-num = 1. ENDIF. + IF zcl_mjs_val=>is_true( is_left ) = abap_true AND zcl_mjs_val=>is_true( is_right ) = abap_true. rs_val-num = 1. ENDIF. WHEN `||`. rs_val-type = 3. - IF is_true( is_left ) = abap_true OR is_true( is_right ) = abap_true. rs_val-num = 1. ENDIF. + IF zcl_mjs_val=>is_true( is_left ) = abap_true OR zcl_mjs_val=>is_true( is_right ) = abap_true. rs_val-num = 1. ENDIF. WHEN OTHERS. CLEAR rs_val. ENDCASE. @@ -3537,7 +3395,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF is_val-str = `NaN` OR is_val-str = `Infinity` OR is_val-str = `-Infinity`. rv_json = `null`. ELSE. - rv_json = to_string( is_val ). + rv_json = zcl_mjs_val=>to_string( is_val ). ENDIF. WHEN 3. " boolean rv_json = COND #( WHEN is_val-num <> 0 THEN `true` ELSE `false` ). diff --git a/src/zcl_mjs_val.clas.abap b/src/zcl_mjs_val.clas.abap new file mode 100644 index 0000000..c6b6f27 --- /dev/null +++ b/src/zcl_mjs_val.clas.abap @@ -0,0 +1,148 @@ +CLASS zcl_mjs_val DEFINITION PUBLIC FINAL. + PUBLIC SECTION. + CLASS-METHODS number_val + IMPORTING iv_num TYPE f + RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. + CLASS-METHODS string_val + IMPORTING iv_str TYPE string + RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. + CLASS-METHODS bool_val + IMPORTING iv_bool TYPE abap_bool + RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. + CLASS-METHODS object_val + RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. + CLASS-METHODS array_val + IMPORTING it_elems TYPE zif_mjs=>tt_nodes + RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. + CLASS-METHODS undefined_val + RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. + + CLASS-METHODS is_true + IMPORTING is_val TYPE zif_mjs=>ty_value + RETURNING VALUE(rv_yes) TYPE abap_bool. + CLASS-METHODS to_number + IMPORTING is_val TYPE zif_mjs=>ty_value + RETURNING VALUE(rv_num) TYPE f. + CLASS-METHODS to_string + IMPORTING is_val TYPE zif_mjs=>ty_value + RETURNING VALUE(rv_str) TYPE string. +ENDCLASS. + +CLASS zcl_mjs_val IMPLEMENTATION. + + METHOD number_val. + rs_val-type = 1. + rs_val-num = iv_num. + ENDMETHOD. + + METHOD string_val. + rs_val-type = 2. + rs_val-str = iv_str. + ENDMETHOD. + + METHOD bool_val. + rs_val-type = 3. + IF iv_bool = abap_true. + rs_val-num = 1. + ELSE. + rs_val-num = 0. + ENDIF. + ENDMETHOD. + + METHOD object_val. + rs_val-type = 6. + CREATE OBJECT rs_val-obj. + ENDMETHOD. + + METHOD array_val. + rs_val-type = 7. + CREATE OBJECT rs_val-arr. + FIELD-SYMBOLS TYPE REF TO data. + LOOP AT it_elems ASSIGNING . + rs_val-arr->push( ). + ENDLOOP. + ENDMETHOD. + + METHOD undefined_val. + rs_val-type = 0. + ENDMETHOD. + + METHOD is_true. + CASE is_val-type. + WHEN 0 OR 5. + rv_yes = abap_false. + WHEN 1. + rv_yes = boolc( is_val-num <> 0 ). + WHEN 2. + rv_yes = boolc( is_val-str IS NOT INITIAL ). + WHEN 3. + rv_yes = boolc( is_val-num <> 0 ). + WHEN OTHERS. + rv_yes = abap_true. + ENDCASE. + ENDMETHOD. + + METHOD to_number. + CASE is_val-type. + WHEN 1. + rv_num = is_val-num. + WHEN 2. + TRY. + rv_num = is_val-str. + CATCH cx_root. + rv_num = 0. + ENDTRY. + WHEN 3. + rv_num = is_val-num. + WHEN OTHERS. + rv_num = 0. + ENDCASE. + ENDMETHOD. + + METHOD to_string. + CASE is_val-type. + WHEN 0. + rv_str = `undefined`. + WHEN 1. + IF is_val-str = `NaN` OR is_val-str = `Infinity` OR is_val-str = `-Infinity`. + rv_str = is_val-str. + ELSE. + DATA lv_int TYPE i. + DATA lv_fcheck TYPE f. + lv_int = is_val-num. + lv_fcheck = lv_int. + IF lv_fcheck = is_val-num. + rv_str = |{ lv_int }|. + ELSE. + rv_str = |{ is_val-num }|. + CONDENSE rv_str. + ENDIF. + ENDIF. + WHEN 2. + rv_str = is_val-str. + WHEN 3. + IF is_val-num <> 0. + rv_str = `true`. + ELSE. + rv_str = `false`. + ENDIF. + WHEN 4. + FIELD-SYMBOLS TYPE zif_mjs=>ty_function. + ASSIGN is_val-fn->* TO . + IF sy-subrc = 0 AND -name IS NOT INITIAL. + rv_str = |function { -name }() \{ [native code] \}|. + ELSE. + rv_str = `function() { [native code] }`. + ENDIF. + WHEN 5. + rv_str = `null`. + WHEN 6. + rv_str = `[object Object]`. + WHEN 7. + rv_str = |[array { is_val-arr->length( ) }]|. + WHEN OTHERS. + rv_str = `undefined`. + ENDCASE. + ENDMETHOD. + +ENDCLASS. diff --git a/src/zcl_mjs_val.clas.xml b/src/zcl_mjs_val.clas.xml new file mode 100644 index 0000000..36ea1fb --- /dev/null +++ b/src/zcl_mjs_val.clas.xml @@ -0,0 +1,16 @@ + + + + + + ZCL_MJS_VAL + E + Mini JavaScript Engine - Value helpers + 1 + X + X + X + + + + From 9d0f852ab9843d055cdd74c2a186cd2593ba189f Mon Sep 17 00:00:00 2001 From: Lars Hvam <5888506+larshp@users.noreply.github.com> Date: Wed, 8 Apr 2026 14:21:06 +0200 Subject: [PATCH 2/7] extract methods --- src/zcl_mjs.clas.abap | 135 ++++++++++++++++---------------------- src/zcl_mjs_val.clas.abap | 23 +++++++ 2 files changed, 79 insertions(+), 79 deletions(-) diff --git a/src/zcl_mjs.clas.abap b/src/zcl_mjs.clas.abap index 25118cf..b75af2f 100644 --- a/src/zcl_mjs.clas.abap +++ b/src/zcl_mjs.clas.abap @@ -52,12 +52,6 @@ CLASS zcl_mjs DEFINITION PUBLIC. CLASS-METHODS annotate_slots IMPORTING ir_node TYPE REF TO data ir_map TYPE REF TO zif_mjs=>tt_slot_map. - CLASS-METHODS box_value - IMPORTING is_val TYPE zif_mjs=>ty_value - RETURNING VALUE(rr_ref) TYPE REF TO data. - CLASS-METHODS unbox_value - IMPORTING ir_ref TYPE REF TO data - RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. CLASS-METHODS array_from_slots IMPORTING it_vals TYPE zif_mjs=>tt_value_slots RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. @@ -711,23 +705,6 @@ CLASS zcl_mjs IMPLEMENTATION. APPEND ls_tok TO rt_tokens. ENDMETHOD. - METHOD box_value. - CREATE DATA rr_ref TYPE zif_mjs=>ty_value. - FIELD-SYMBOLS TYPE zif_mjs=>ty_value. - ASSIGN rr_ref->* TO . - = is_val. - ENDMETHOD. - - METHOD unbox_value. - IF ir_ref IS NOT BOUND. - rs_val-type = 0. - RETURN. - ENDIF. - FIELD-SYMBOLS TYPE zif_mjs=>ty_value. - ASSIGN ir_ref->* TO . - rs_val = . - ENDMETHOD. - METHOD call_function. " ir_fn is REF TO zif_mjs=>ty_function - modifiable for lazy compile FIELD-SYMBOLS TYPE zif_mjs=>ty_function. @@ -1217,12 +1194,12 @@ CLASS zcl_mjs IMPLEMENTATION. lv_maprop = zcl_mjs_val=>to_string( eval_node( ir_node = -prop_expr io_env = io_env ) ). ENDIF. IF ls_maobj-type = 6. - ls_maobj-obj->set( iv_key = lv_maprop ir_val = box_value( ls_maval ) ). + ls_maobj-obj->set( iv_key = lv_maprop ir_val = zcl_mjs_val=>box_value( ls_maval ) ). ELSEIF ls_maobj-type = 4. IF ls_maobj-obj IS INITIAL. CREATE OBJECT ls_maobj-obj. ENDIF. - ls_maobj-obj->set( iv_key = lv_maprop ir_val = box_value( ls_maval ) ). + ls_maobj-obj->set( iv_key = lv_maprop ir_val = zcl_mjs_val=>box_value( ls_maval ) ). FIELD-SYMBOLS TYPE zif_mjs=>ty_node. ASSIGN -object->* TO . IF sy-subrc = 0 AND -kind = zif_mjs=>c_node_ident. @@ -1352,7 +1329,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF ls_iter-type = 7 AND ls_iter-arr IS BOUND. LOOP AT ls_iter-arr->items INTO DATA(lr_item). - DATA(ls_item_val) = unbox_value( lr_item ). + DATA(ls_item_val) = zcl_mjs_val=>unbox_value( lr_item ). CREATE OBJECT lo_iter_env EXPORTING io_parent = io_env. lo_iter_env->output = io_env->output. @@ -1382,10 +1359,10 @@ CLASS zcl_mjs IMPLEMENTATION. " Mock for Map/Set iteration DATA(lr_iter_data_ref) = ls_iter-obj->get( `[[SetData]]` ). IF lr_iter_data_ref IS BOUND. - DATA(ls_iter_data_val) = unbox_value( lr_iter_data_ref ). + DATA(ls_iter_data_val) = zcl_mjs_val=>unbox_value( lr_iter_data_ref ). IF ls_iter_data_val-type = 7 AND ls_iter_data_val-arr IS BOUND. LOOP AT ls_iter_data_val-arr->items INTO DATA(lr_mi_item). - DATA(ls_mi_item_val) = unbox_value( lr_mi_item ). + DATA(ls_mi_item_val) = zcl_mjs_val=>unbox_value( lr_mi_item ). CREATE OBJECT lo_iter_env EXPORTING io_parent = io_env. lo_iter_env->output = io_env->output. IF lv_of_decl = abap_true. @@ -1519,7 +1496,7 @@ CLASS zcl_mjs IMPLEMENTATION. ASSIGN lr_ca_item->* TO . IF sy-subrc = 0 AND -op = `SPREAD` AND ls_ca_val-type = 7 AND ls_ca_val-arr IS BOUND. LOOP AT ls_ca_val-arr->items INTO DATA(lr_spread_ca). - APPEND unbox_value( lr_spread_ca ) TO lt_call_args. + APPEND zcl_mjs_val=>unbox_value( lr_spread_ca ) TO lt_call_args. ENDLOOP. ELSE. APPEND ls_ca_val TO lt_call_args. @@ -1591,10 +1568,10 @@ CLASS zcl_mjs IMPLEMENTATION. IF ls_super_ctor_fn-type = 4 AND ls_super_ctor_fn-fn IS BOUND. DATA(ls_cur_this) = io_env->get( `this` ). DATA lr_super_this_ref TYPE REF TO data. - lr_super_this_ref = box_value( ls_cur_this ). + lr_super_this_ref = zcl_mjs_val=>box_value( ls_cur_this ). call_function( ir_fn = ls_super_ctor_fn-fn it_args = lt_call_args io_env = io_env ir_this = lr_super_this_ref ). - DATA(ls_updated_this) = unbox_value( lr_super_this_ref ). + DATA(ls_updated_this) = zcl_mjs_val=>unbox_value( lr_super_this_ref ). io_env->define( iv_name = `this` is_val = ls_updated_this ). ENDIF. RETURN. @@ -1623,12 +1600,12 @@ CLASS zcl_mjs IMPLEMENTATION. ELSE. DATA(lr_ef_dp_get) = ls_ef_dp_desc-obj->get( `get` ). IF lr_ef_dp_get IS BOUND. - DATA(ls_ef_get_val) = unbox_value( lr_ef_dp_get ). + DATA(ls_ef_get_val) = zcl_mjs_val=>unbox_value( lr_ef_dp_get ). IF ls_ef_get_val-type = 4. DATA ls_ef_get_wrap TYPE zif_mjs=>ty_value. ls_ef_get_wrap-type = 10. ls_ef_get_wrap-fn = ls_ef_get_val-fn. - ls_ef_dp_obj-obj->set( iv_key = zcl_mjs_val=>to_string( ls_ef_dp_prop ) ir_val = box_value( ls_ef_get_wrap ) ). + ls_ef_dp_obj-obj->set( iv_key = zcl_mjs_val=>to_string( ls_ef_dp_prop ) ir_val = zcl_mjs_val=>box_value( ls_ef_get_wrap ) ). ENDIF. ENDIF. ENDIF. @@ -1663,12 +1640,12 @@ CLASS zcl_mjs IMPLEMENTATION. ELSE. DATA(lr_f_dp_get) = ls_f_dp_desc-obj->get( `get` ). IF lr_f_dp_get IS BOUND. - DATA(ls_f_get_val) = unbox_value( lr_f_dp_get ). + DATA(ls_f_get_val) = zcl_mjs_val=>unbox_value( lr_f_dp_get ). IF ls_f_get_val-type = 4. DATA ls_f_get_wrap TYPE zif_mjs=>ty_value. ls_f_get_wrap-type = 10. ls_f_get_wrap-fn = ls_f_get_val-fn. - ls_f_dp_obj-obj->set( iv_key = zcl_mjs_val=>to_string( ls_f_dp_prop ) ir_val = box_value( ls_f_get_wrap ) ). + ls_f_dp_obj-obj->set( iv_key = zcl_mjs_val=>to_string( ls_f_dp_prop ) ir_val = zcl_mjs_val=>box_value( ls_f_get_wrap ) ). ENDIF. ENDIF. ENDIF. @@ -1707,7 +1684,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF ls_ok_in-type = 6 AND ls_ok_in-obj IS BOUND. DATA lt_ok_refs TYPE STANDARD TABLE OF REF TO data WITH DEFAULT KEY. LOOP AT ls_ok_in-obj->props ASSIGNING FIELD-SYMBOL(). - APPEND box_value( zcl_mjs_val=>string_val( -key ) ) TO lt_ok_refs. + APPEND zcl_mjs_val=>box_value( zcl_mjs_val=>string_val( -key ) ) TO lt_ok_refs. ENDLOOP. rs_val = zcl_mjs_val=>array_val( lt_ok_refs ). RETURN. @@ -1728,12 +1705,12 @@ CLASS zcl_mjs IMPLEMENTATION. " Handle getter/setter DATA(lr_dp_get) = ls_dp_desc-obj->get( `get` ). IF lr_dp_get IS BOUND. - DATA(ls_get_val) = unbox_value( lr_dp_get ). + DATA(ls_get_val) = zcl_mjs_val=>unbox_value( lr_dp_get ). IF ls_get_val-type = 4. DATA ls_getter_wrap TYPE zif_mjs=>ty_value. ls_getter_wrap-type = 10. ls_getter_wrap-fn = ls_get_val-fn. - ls_dp_obj-obj->set( iv_key = zcl_mjs_val=>to_string( ls_dp_prop ) ir_val = box_value( ls_getter_wrap ) ). + ls_dp_obj-obj->set( iv_key = zcl_mjs_val=>to_string( ls_dp_prop ) ir_val = zcl_mjs_val=>box_value( ls_getter_wrap ) ). ENDIF. ENDIF. ENDIF. @@ -1758,7 +1735,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA(ls_smval) = eval_property_access( is_obj = ls_mcobj iv_prop = -property io_env = io_env ). IF ls_smval-type = 4 AND ls_smval-fn IS BOUND. DATA lr_super_this TYPE REF TO data. - lr_super_this = box_value( io_env->get( `this` ) ). + lr_super_this = zcl_mjs_val=>box_value( io_env->get( `this` ) ). DATA lt_s_args TYPE zif_mjs=>tt_value_slots. LOOP AT -args INTO DATA(lr_sa). DATA(ls_sa_v) = eval_node( ir_node = lr_sa io_env = io_env ). @@ -1766,14 +1743,14 @@ CLASS zcl_mjs IMPLEMENTATION. ASSIGN lr_sa->* TO . IF sy-subrc = 0 AND -op = `SPREAD` AND ls_sa_v-type = 7 AND ls_sa_v-arr IS BOUND. LOOP AT ls_sa_v-arr->items INTO DATA(lr_spread_sa). - APPEND unbox_value( lr_spread_sa ) TO lt_s_args. + APPEND zcl_mjs_val=>unbox_value( lr_spread_sa ) TO lt_s_args. ENDLOOP. ELSE. APPEND ls_sa_v TO lt_s_args. ENDIF. ENDLOOP. rs_val = call_function( ir_fn = ls_smval-fn it_args = lt_s_args io_env = io_env ir_this = lr_super_this ). - DATA(ls_upd_this) = unbox_value( lr_super_this ). + DATA(ls_upd_this) = zcl_mjs_val=>unbox_value( lr_super_this ). io_env->set( iv_name = `this` is_val = ls_upd_this ). RETURN. ENDIF. @@ -1799,7 +1776,7 @@ CLASS zcl_mjs IMPLEMENTATION. ASSIGN lr_ma2->* TO . IF sy-subrc = 0 AND -op = `SPREAD` AND ls_mc_arg-type = 7 AND ls_mc_arg-arr IS BOUND. LOOP AT ls_mc_arg-arr->items INTO DATA(lr_spread_mc). - APPEND unbox_value( lr_spread_mc ) TO lt_mc_args. + APPEND zcl_mjs_val=>unbox_value( lr_spread_mc ) TO lt_mc_args. ENDLOOP. ELSE. APPEND ls_mc_arg TO lt_mc_args. @@ -1945,7 +1922,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA lr_oval TYPE REF TO data. READ TABLE -args INDEX lv_oi + 1 INTO lr_oval. DATA(ls_oval) = eval_node( ir_node = lr_oval io_env = io_env ). - ls_obj-obj->set( iv_key = lv_okey_str ir_val = box_value( ls_oval ) ). + ls_obj-obj->set( iv_key = lv_okey_str ir_val = zcl_mjs_val=>box_value( ls_oval ) ). lv_oi = lv_oi + 2. ENDWHILE. rs_val = ls_obj. @@ -1962,7 +1939,7 @@ CLASS zcl_mjs IMPLEMENTATION. APPEND lr_spread_item TO lt_arr_refs. ENDLOOP. ELSE. - APPEND box_value( lr_ae_val ) TO lt_arr_refs. + APPEND zcl_mjs_val=>box_value( lr_ae_val ) TO lt_arr_refs. ENDIF. ENDLOOP. rs_val = zcl_mjs_val=>array_val( lt_arr_refs ). @@ -2079,7 +2056,7 @@ CLASS zcl_mjs IMPLEMENTATION. " Internal storage for Set items (highly simplified for now) " Use an array in the object's properties for simulation DATA(lo_set_data) = zcl_mjs_val=>array_val( VALUE #( ) ). - rs_val-obj->set( iv_key = `[[SetData]]` ir_val = box_value( lo_set_data ) ). + rs_val-obj->set( iv_key = `[[SetData]]` ir_val = zcl_mjs_val=>box_value( lo_set_data ) ). " Handle constructor argument (iterable/array) IF lines( -args ) >= 1. @@ -2108,13 +2085,13 @@ CLASS zcl_mjs IMPLEMENTATION. DATA lr_ctor TYPE REF TO data. lr_ctor = ls_cls-obj->get( `constructor` ). IF lr_ctor IS BOUND. - DATA(ls_ctor_val) = unbox_value( lr_ctor ). + DATA(ls_ctor_val) = zcl_mjs_val=>unbox_value( lr_ctor ). IF ls_ctor_val-type = 4 AND ls_ctor_val-fn IS BOUND. DATA lr_inst_ref TYPE REF TO data. - lr_inst_ref = box_value( ls_instance ). + lr_inst_ref = zcl_mjs_val=>box_value( ls_instance ). call_function( ir_fn = ls_ctor_val-fn it_args = lt_new_args io_env = io_env ir_this = lr_inst_ref ). - ls_instance = unbox_value( lr_inst_ref ). + ls_instance = zcl_mjs_val=>unbox_value( lr_inst_ref ). ENDIF. ENDIF. " IMPORTANT: don't overwrite this.prop with class methods if we already set them in ctor @@ -2135,13 +2112,13 @@ CLASS zcl_mjs IMPLEMENTATION. APPEND eval_node( ir_node = lr_pa io_env = io_env ) TO lt_p_args. ENDLOOP. DATA lr_p_inst_ref TYPE REF TO data. - lr_p_inst_ref = box_value( ls_p_inst ). + lr_p_inst_ref = zcl_mjs_val=>box_value( ls_p_inst ). DATA(ls_p_ret) = call_function( ir_fn = ls_cls-fn it_args = lt_p_args io_env = io_env ir_this = lr_p_inst_ref ). IF ls_p_ret-type = 6 AND ls_p_ret-obj IS BOUND. rs_val = ls_p_ret. ELSE. - rs_val = unbox_value( lr_p_inst_ref ). + rs_val = zcl_mjs_val=>unbox_value( lr_p_inst_ref ). ENDIF. ENDIF. @@ -2175,14 +2152,14 @@ CLASS zcl_mjs IMPLEMENTATION. DATA lr_sc TYPE REF TO data. lr_sc = ls_super_cls_val-obj->get( `constructor` ). IF lr_sc IS BOUND. - DATA(ls_sc_val) = unbox_value( lr_sc ). + DATA(ls_sc_val) = zcl_mjs_val=>unbox_value( lr_sc ). IF ls_sc_val-type = 4. lo_cls_env->define( iv_name = `__super_ctor__` is_val = ls_sc_val ). ENDIF. ENDIF. lo_cls_env->define( iv_name = `__super_proto__` is_val = ls_super_cls_val ). ENDIF. - ls_clsobj-obj->set( iv_key = `__is_class__` ir_val = box_value( zcl_mjs_val=>bool_val( abap_true ) ) ). + ls_clsobj-obj->set( iv_key = `__is_class__` ir_val = zcl_mjs_val=>box_value( zcl_mjs_val=>bool_val( abap_true ) ) ). LOOP AT -methods INTO DATA(ls_cm). DATA lr_mfn TYPE REF TO data. CREATE DATA lr_mfn TYPE zif_mjs=>ty_function. @@ -2195,7 +2172,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA ls_mfnval TYPE zif_mjs=>ty_value. ls_mfnval-type = 4. ls_mfnval-fn = lr_mfn. - ls_clsobj-obj->set( iv_key = ls_cm-name ir_val = box_value( ls_mfnval ) ). + ls_clsobj-obj->set( iv_key = ls_cm-name ir_val = zcl_mjs_val=>box_value( ls_mfnval ) ). ENDLOOP. IF -str IS NOT INITIAL. io_env->define( iv_name = -str is_val = ls_clsobj ). @@ -2245,9 +2222,9 @@ CLASS zcl_mjs IMPLEMENTATION. DATA lr_pv TYPE REF TO data. lr_pv = is_obj-obj->get( iv_prop ). IF lr_pv IS BOUND. - rs_val = unbox_value( lr_pv ). + rs_val = zcl_mjs_val=>unbox_value( lr_pv ). IF rs_val-type = 10 AND io_env IS BOUND. - rs_val = call_function( ir_fn = rs_val-fn it_args = VALUE #( ) io_env = io_env ir_this = box_value( is_obj ) ). + rs_val = call_function( ir_fn = rs_val-fn it_args = VALUE #( ) io_env = io_env ir_this = zcl_mjs_val=>box_value( is_obj ) ). ENDIF. ELSE. rs_val = zcl_mjs_val=>undefined_val( ). @@ -2269,7 +2246,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA lr_aelem TYPE REF TO data. lr_aelem = is_obj-arr->get_item( lv_aidx ). IF lr_aelem IS BOUND. - rs_val = unbox_value( lr_aelem ). + rs_val = zcl_mjs_val=>unbox_value( lr_aelem ). ELSE. rs_val = zcl_mjs_val=>undefined_val( ). ENDIF. @@ -2304,7 +2281,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA lr_fn4_pv TYPE REF TO data. lr_fn4_pv = is_obj-obj->get( iv_prop ). IF lr_fn4_pv IS BOUND. - rs_val = unbox_value( lr_fn4_pv ). + rs_val = zcl_mjs_val=>unbox_value( lr_fn4_pv ). RETURN. ENDIF. rs_val = zcl_mjs_val=>undefined_val( ). @@ -2343,10 +2320,10 @@ CLASS zcl_mjs IMPLEMENTATION. IF ls_mval-type = 4 AND ls_mval-fn IS BOUND. DATA lr_this TYPE REF TO data. - lr_this = box_value( is_obj ). + lr_this = zcl_mjs_val=>box_value( is_obj ). rs_val = call_function( ir_fn = ls_mval-fn it_args = it_args io_env = io_env ir_this = lr_this ). - DATA(ls_updated) = unbox_value( lr_this ). + DATA(ls_updated) = zcl_mjs_val=>unbox_value( lr_this ). IF ir_obj_node IS BOUND. FIELD-SYMBOLS TYPE zif_mjs=>ty_node. ASSIGN ir_obj_node->* TO . @@ -2368,7 +2345,7 @@ CLASS zcl_mjs IMPLEMENTATION. CREATE OBJECT lo_map_arr. lv_map_idx = 0. LOOP AT is_obj-arr->items INTO lr_map_item. - ls_map_elem = unbox_value( lr_map_item ). + ls_map_elem = zcl_mjs_val=>unbox_value( lr_map_item ). CLEAR lt_map_args. APPEND ls_map_elem TO lt_map_args. APPEND zcl_mjs_val=>number_val( CONV f( lv_map_idx ) ) TO lt_map_args. @@ -2377,7 +2354,7 @@ CLASS zcl_mjs IMPLEMENTATION. ir_fn = ls_map_cb-fn it_args = lt_map_args io_env = io_env ). - lo_map_arr->push( box_value( ls_map_result ) ). + lo_map_arr->push( zcl_mjs_val=>box_value( ls_map_result ) ). lv_map_idx = lv_map_idx + 1. ENDLOOP. rs_val-type = 7. @@ -2394,7 +2371,7 @@ CLASS zcl_mjs IMPLEMENTATION. CREATE OBJECT lo_flt_arr. lv_flt_idx = 0. LOOP AT is_obj-arr->items INTO lr_flt_item. - ls_flt_elem = unbox_value( lr_flt_item ). + ls_flt_elem = zcl_mjs_val=>unbox_value( lr_flt_item ). CLEAR lt_flt_args. APPEND ls_flt_elem TO lt_flt_args. APPEND zcl_mjs_val=>number_val( CONV f( lv_flt_idx ) ) TO lt_flt_args. @@ -2422,7 +2399,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF ls_find_cb-type = 4 AND ls_find_cb-fn IS BOUND. lv_find_idx = 0. LOOP AT is_obj-arr->items INTO lr_find_item. - ls_find_elem = unbox_value( lr_find_item ). + ls_find_elem = zcl_mjs_val=>unbox_value( lr_find_item ). CLEAR lt_find_args. APPEND ls_find_elem TO lt_find_args. APPEND zcl_mjs_val=>number_val( CONV f( lv_find_idx ) ) TO lt_find_args. @@ -2449,12 +2426,12 @@ CLASS zcl_mjs IMPLEMENTATION. " Set mock behavior for 'has()' DATA(lr_set_data_ref) = is_obj-obj->get( `[[SetData]]` ). IF lr_set_data_ref IS BOUND AND lines( it_args ) >= 1. - DATA(ls_set_data_val) = unbox_value( lr_set_data_ref ). + DATA(ls_set_data_val) = zcl_mjs_val=>unbox_value( lr_set_data_ref ). DATA(ls_has_target) = it_args[ 1 ]. DATA(lv_found_has) = abap_false. IF ls_set_data_val-type = 7 AND ls_set_data_val-arr IS BOUND. LOOP AT ls_set_data_val-arr->items INTO DATA(lr_has_item). - DATA(ls_has_item_val) = unbox_value( lr_has_item ). + DATA(ls_has_item_val) = zcl_mjs_val=>unbox_value( lr_has_item ). " highly simplified: check for value equality (like JS === but for test purposes) IF ls_has_item_val-type = ls_has_target-type. CASE ls_has_item_val-type. @@ -2477,7 +2454,7 @@ CLASS zcl_mjs IMPLEMENTATION. CASE iv_method. WHEN `push`. LOOP AT it_args INTO DATA(ls_push_arg). - is_obj-arr->push( box_value( ls_push_arg ) ). + is_obj-arr->push( zcl_mjs_val=>box_value( ls_push_arg ) ). ENDLOOP. rs_val = zcl_mjs_val=>number_val( CONV f( is_obj-arr->length( ) ) ). @@ -2496,7 +2473,7 @@ CLASS zcl_mjs IMPLEMENTATION. CREATE OBJECT lo_map_arr. lv_map_idx = 0. LOOP AT is_obj-arr->items INTO lr_map_item. - ls_map_elem = unbox_value( lr_map_item ). + ls_map_elem = zcl_mjs_val=>unbox_value( lr_map_item ). CLEAR lt_map_args. APPEND ls_map_elem TO lt_map_args. APPEND zcl_mjs_val=>number_val( CONV f( lv_map_idx ) ) TO lt_map_args. @@ -2505,7 +2482,7 @@ CLASS zcl_mjs IMPLEMENTATION. ir_fn = ls_map_cb-fn it_args = lt_map_args io_env = io_env ). - lo_map_arr->push( box_value( ls_map_result ) ). + lo_map_arr->push( zcl_mjs_val=>box_value( ls_map_result ) ). lv_map_idx = lv_map_idx + 1. ENDLOOP. rs_val-type = 7. @@ -2521,7 +2498,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF ls_find_cb-type = 4 AND ls_find_cb-fn IS BOUND. lv_find_idx = 0. LOOP AT is_obj-arr->items INTO lr_find_item. - ls_find_elem = unbox_value( lr_find_item ). + ls_find_elem = zcl_mjs_val=>unbox_value( lr_find_item ). CLEAR lt_find_args. APPEND ls_find_elem TO lt_find_args. APPEND zcl_mjs_val=>number_val( CONV f( lv_find_idx ) ) TO lt_find_args. @@ -2546,7 +2523,7 @@ CLASS zcl_mjs IMPLEMENTATION. CREATE OBJECT lo_flt_arr. lv_flt_idx = 0. LOOP AT is_obj-arr->items INTO lr_flt_item. - ls_flt_elem = unbox_value( lr_flt_item ). + ls_flt_elem = zcl_mjs_val=>unbox_value( lr_flt_item ). CLEAR lt_flt_args. APPEND ls_flt_elem TO lt_flt_args. APPEND zcl_mjs_val=>number_val( CONV f( lv_flt_idx ) ) TO lt_flt_args. @@ -2601,7 +2578,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF lines( lt_spl_args ) > 2. DATA(lv_ins_idx) = lv_spl_start + 1. LOOP AT lt_spl_args INTO DATA(ls_spl_a) FROM 3. - INSERT box_value( ls_spl_a ) INTO is_obj-arr->items INDEX lv_ins_idx. + INSERT zcl_mjs_val=>box_value( ls_spl_a ) INTO is_obj-arr->items INDEX lv_ins_idx. lv_ins_idx = lv_ins_idx + 1. ENDLOOP. ENDIF. @@ -2615,7 +2592,7 @@ CLASS zcl_mjs IMPLEMENTATION. END OF ty_sort. DATA lt_sort TYPE STANDARD TABLE OF ty_sort WITH DEFAULT KEY. LOOP AT is_obj-arr->items INTO DATA(lr_si). - APPEND VALUE #( val = zcl_mjs_val=>to_string( unbox_value( lr_si ) ) ref = lr_si ) TO lt_sort. + APPEND VALUE #( val = zcl_mjs_val=>to_string( zcl_mjs_val=>unbox_value( lr_si ) ) ref = lr_si ) TO lt_sort. ENDLOOP. SORT lt_sort BY val ASCENDING. CLEAR is_obj-arr->items. @@ -3033,7 +3010,7 @@ CLASS zcl_mjs IMPLEMENTATION. lv_spl_count = 0. LOOP AT lt_spl_items INTO DATA(lv_spl_item) WHERE table_line IS NOT INITIAL OR table_line = ``. IF lv_spl_count >= lv_spl_limit. EXIT. ENDIF. - lo_spl_arr->push( box_value( zcl_mjs_val=>string_val( lv_spl_item ) ) ). + lo_spl_arr->push( zcl_mjs_val=>box_value( zcl_mjs_val=>string_val( lv_spl_item ) ) ). lv_spl_count = lv_spl_count + 1. ENDLOOP. rs_val-type = 7. @@ -3042,7 +3019,7 @@ CLASS zcl_mjs IMPLEMENTATION. " default: one-element array with full string DATA lo_spl_def TYPE REF TO zcl_mjs_arr. CREATE OBJECT lo_spl_def. - lo_spl_def->push( box_value( is_obj ) ). + lo_spl_def->push( zcl_mjs_val=>box_value( is_obj ) ). rs_val-type = 7. rs_val-arr = lo_spl_def. ENDIF. @@ -3054,10 +3031,10 @@ CLASS zcl_mjs IMPLEMENTATION. DATA lr_fn4_meth TYPE REF TO data. lr_fn4_meth = is_obj-obj->get( iv_method ). IF lr_fn4_meth IS BOUND. - DATA(ls_fn4_mval) = unbox_value( lr_fn4_meth ). + DATA(ls_fn4_mval) = zcl_mjs_val=>unbox_value( lr_fn4_meth ). IF ls_fn4_mval-type = 4 AND ls_fn4_mval-fn IS BOUND. DATA lr_fn4_this TYPE REF TO data. - lr_fn4_this = box_value( is_obj ). + lr_fn4_this = zcl_mjs_val=>box_value( is_obj ). rs_val = call_function( ir_fn = ls_fn4_mval-fn it_args = it_args io_env = io_env ir_this = lr_fn4_this ). RETURN. @@ -3336,7 +3313,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA lo_arr TYPE REF TO zcl_mjs_arr. CREATE OBJECT lo_arr. LOOP AT it_vals INTO DATA(ls_v). - lo_arr->push( box_value( ls_v ) ). + lo_arr->push( zcl_mjs_val=>box_value( ls_v ) ). ENDLOOP. rs_val-type = 7. rs_val-arr = lo_arr. @@ -3447,7 +3424,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA lv_obj_first TYPE abap_bool VALUE abap_true. lv_obj_out = `{`. LOOP AT is_val-obj->props ASSIGNING FIELD-SYMBOL(). - DATA(ls_pval) = unbox_value( -val ). + DATA(ls_pval) = zcl_mjs_val=>unbox_value( -val ). " skip undefined and function values IF ls_pval-type = 0 OR ls_pval-type = 4. CONTINUE. @@ -3475,7 +3452,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA(lr_elem) = is_val-arr->get_item( lv_arr_idx ). DATA lv_elem_json TYPE string. IF lr_elem IS BOUND. - DATA(ls_elem) = unbox_value( lr_elem ). + DATA(ls_elem) = zcl_mjs_val=>unbox_value( lr_elem ). IF ls_elem-type = 0 OR ls_elem-type = 4. lv_elem_json = `null`. " undefined/function in array → null ELSE. diff --git a/src/zcl_mjs_val.clas.abap b/src/zcl_mjs_val.clas.abap index c6b6f27..be31c20 100644 --- a/src/zcl_mjs_val.clas.abap +++ b/src/zcl_mjs_val.clas.abap @@ -16,6 +16,12 @@ CLASS zcl_mjs_val DEFINITION PUBLIC FINAL. RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. CLASS-METHODS undefined_val RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. + CLASS-METHODS box_value + IMPORTING is_val TYPE zif_mjs=>ty_value + RETURNING VALUE(rr_ref) TYPE REF TO data. + CLASS-METHODS unbox_value + IMPORTING ir_ref TYPE REF TO data + RETURNING VALUE(rs_val) TYPE zif_mjs=>ty_value. CLASS-METHODS is_true IMPORTING is_val TYPE zif_mjs=>ty_value @@ -67,6 +73,23 @@ CLASS zcl_mjs_val IMPLEMENTATION. rs_val-type = 0. ENDMETHOD. + METHOD box_value. + CREATE DATA rr_ref TYPE zif_mjs=>ty_value. + FIELD-SYMBOLS TYPE zif_mjs=>ty_value. + ASSIGN rr_ref->* TO . + = is_val. + ENDMETHOD. + + METHOD unbox_value. + IF ir_ref IS NOT BOUND. + rs_val-type = 0. + RETURN. + ENDIF. + FIELD-SYMBOLS TYPE zif_mjs=>ty_value. + ASSIGN ir_ref->* TO . + rs_val = . + ENDMETHOD. + METHOD is_true. CASE is_val-type. WHEN 0 OR 5. From bfab3f5650f72b1e89701118021359e2b589739c Mon Sep 17 00:00:00 2001 From: Lars Hvam <5888506+larshp@users.noreply.github.com> Date: Wed, 8 Apr 2026 14:22:33 +0200 Subject: [PATCH 3/7] rename class --- src/zcl_mjs.clas.abap | 10 +++++----- src/{zcl_mjs_arr.clas.abap => zcl_mjs_array.clas.abap} | 4 ++-- src/{zcl_mjs_arr.clas.xml => zcl_mjs_array.clas.xml} | 2 +- src/zif_mjs.intf.abap | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) rename src/{zcl_mjs_arr.clas.abap => zcl_mjs_array.clas.abap} (89%) rename src/{zcl_mjs_arr.clas.xml => zcl_mjs_array.clas.xml} (92%) diff --git a/src/zcl_mjs.clas.abap b/src/zcl_mjs.clas.abap index b75af2f..649557d 100644 --- a/src/zcl_mjs.clas.abap +++ b/src/zcl_mjs.clas.abap @@ -2295,7 +2295,7 @@ CLASS zcl_mjs IMPLEMENTATION. METHOD eval_method_call. DATA ls_map_cb TYPE zif_mjs=>ty_value. - DATA lo_map_arr TYPE REF TO zcl_mjs_arr. + DATA lo_map_arr TYPE REF TO zcl_mjs_array. DATA lv_map_idx TYPE i. DATA lr_map_item TYPE REF TO data. DATA ls_map_elem TYPE zif_mjs=>ty_value. @@ -2308,7 +2308,7 @@ CLASS zcl_mjs IMPLEMENTATION. DATA lt_find_args TYPE zif_mjs=>tt_value_slots. DATA ls_find_result TYPE zif_mjs=>ty_value. DATA ls_flt_cb TYPE zif_mjs=>ty_value. - DATA lo_flt_arr TYPE REF TO zcl_mjs_arr. + DATA lo_flt_arr TYPE REF TO zcl_mjs_array. DATA lv_flt_idx TYPE i. DATA lr_flt_item TYPE REF TO data. DATA ls_flt_elem TYPE zif_mjs=>ty_value. @@ -3004,7 +3004,7 @@ CLASS zcl_mjs IMPLEMENTATION. SPLIT is_obj-str AT lv_spl_sep INTO TABLE lt_spl_items. ENDIF. - DATA lo_spl_arr TYPE REF TO zcl_mjs_arr. + DATA lo_spl_arr TYPE REF TO zcl_mjs_array. CREATE OBJECT lo_spl_arr. DATA lv_spl_count TYPE i. lv_spl_count = 0. @@ -3017,7 +3017,7 @@ CLASS zcl_mjs IMPLEMENTATION. rs_val-arr = lo_spl_arr. ELSE. " default: one-element array with full string - DATA lo_spl_def TYPE REF TO zcl_mjs_arr. + DATA lo_spl_def TYPE REF TO zcl_mjs_array. CREATE OBJECT lo_spl_def. lo_spl_def->push( zcl_mjs_val=>box_value( is_obj ) ). rs_val-type = 7. @@ -3310,7 +3310,7 @@ CLASS zcl_mjs IMPLEMENTATION. METHOD array_from_slots. " Build a JS array value from a table of ty_value (no box/unbox round-trip) - DATA lo_arr TYPE REF TO zcl_mjs_arr. + DATA lo_arr TYPE REF TO zcl_mjs_array. CREATE OBJECT lo_arr. LOOP AT it_vals INTO DATA(ls_v). lo_arr->push( zcl_mjs_val=>box_value( ls_v ) ). diff --git a/src/zcl_mjs_arr.clas.abap b/src/zcl_mjs_array.clas.abap similarity index 89% rename from src/zcl_mjs_arr.clas.abap rename to src/zcl_mjs_array.clas.abap index 777b485..ecb8223 100644 --- a/src/zcl_mjs_arr.clas.abap +++ b/src/zcl_mjs_array.clas.abap @@ -1,4 +1,4 @@ -CLASS zcl_mjs_arr DEFINITION PUBLIC. +CLASS zcl_mjs_array DEFINITION PUBLIC. PUBLIC SECTION. DATA items TYPE STANDARD TABLE OF REF TO data WITH DEFAULT KEY. METHODS push IMPORTING ir_val TYPE REF TO data. @@ -9,7 +9,7 @@ CLASS zcl_mjs_arr DEFINITION PUBLIC. PRIVATE SECTION. ENDCLASS. -CLASS zcl_mjs_arr IMPLEMENTATION. +CLASS zcl_mjs_array IMPLEMENTATION. METHOD push. APPEND ir_val TO items. ENDMETHOD. diff --git a/src/zcl_mjs_arr.clas.xml b/src/zcl_mjs_array.clas.xml similarity index 92% rename from src/zcl_mjs_arr.clas.xml rename to src/zcl_mjs_array.clas.xml index db61968..0b2fb06 100644 --- a/src/zcl_mjs_arr.clas.xml +++ b/src/zcl_mjs_array.clas.xml @@ -3,7 +3,7 @@ - ZCL_MJS_ARR + ZCL_MJS_ARRAY E Mini JavaScript Engine - Array 1 diff --git a/src/zif_mjs.intf.abap b/src/zif_mjs.intf.abap index 9eb4a7a..b7056c6 100644 --- a/src/zif_mjs.intf.abap +++ b/src/zif_mjs.intf.abap @@ -8,7 +8,7 @@ INTERFACE zif_mjs PUBLIC. num TYPE f, str TYPE string, obj TYPE REF TO zcl_mjs_obj, - arr TYPE REF TO zcl_mjs_arr, + arr TYPE REF TO zcl_mjs_array, fn TYPE REF TO data, END OF ty_value, tt_value_slots TYPE STANDARD TABLE OF ty_value WITH DEFAULT KEY. From 5b2f4b8d8199ef50cfe11936bc0e46189dd1af08 Mon Sep 17 00:00:00 2001 From: Lars Hvam <5888506+larshp@users.noreply.github.com> Date: Wed, 8 Apr 2026 14:30:13 +0200 Subject: [PATCH 4/7] extract string methods --- src/zcl_mjs.clas.abap | 420 +-------------------------------- src/zcl_mjs_string.clas.abap | 437 +++++++++++++++++++++++++++++++++++ src/zcl_mjs_string.clas.xml | 16 ++ 3 files changed, 454 insertions(+), 419 deletions(-) create mode 100644 src/zcl_mjs_string.clas.abap create mode 100644 src/zcl_mjs_string.clas.xml diff --git a/src/zcl_mjs.clas.abap b/src/zcl_mjs.clas.abap index 649557d..d5feee4 100644 --- a/src/zcl_mjs.clas.abap +++ b/src/zcl_mjs.clas.abap @@ -2607,425 +2607,7 @@ CLASS zcl_mjs IMPLEMENTATION. iv_error = |TypeError: { iv_method } is not a function|. ENDCASE. WHEN 2. - CASE iv_method. - WHEN `toUpperCase`. - rs_val = zcl_mjs_val=>string_val( to_upper( is_obj-str ) ). - WHEN `toLowerCase`. - rs_val = zcl_mjs_val=>string_val( to_lower( is_obj-str ) ). - WHEN `startsWith`. - IF lines( it_args ) > 0. - DATA(ls_sw1) = VALUE zif_mjs=>ty_value( ). - DATA(ls_sw2) = VALUE zif_mjs=>ty_value( ). - READ TABLE it_args INDEX 1 INTO ls_sw1. - DATA(lv_sw_search) = zcl_mjs_val=>to_string( ls_sw1 ). - DATA(lv_sw_pos) = 0. - IF lines( it_args ) >= 2. - READ TABLE it_args INDEX 2 INTO ls_sw2. - lv_sw_pos = zcl_mjs_val=>to_number( ls_sw2 ). - ENDIF. - IF lv_sw_pos < 0. - lv_sw_pos = 0. - ENDIF. - IF lv_sw_pos > strlen( is_obj-str ). - lv_sw_pos = strlen( is_obj-str ). - ENDIF. - IF lv_sw_search = ``. - rs_val = zcl_mjs_val=>bool_val( abap_true ). - ELSEIF lv_sw_pos + strlen( lv_sw_search ) > strlen( is_obj-str ). - rs_val = zcl_mjs_val=>bool_val( abap_false ). - ELSEIF substring( val = is_obj-str - off = lv_sw_pos - len = strlen( lv_sw_search ) ) = lv_sw_search. - rs_val = zcl_mjs_val=>bool_val( abap_true ). - ELSE. - rs_val = zcl_mjs_val=>bool_val( abap_false ). - ENDIF. - ELSE. - rs_val = zcl_mjs_val=>bool_val( abap_false ). - ENDIF. - WHEN `endsWith`. - IF lines( it_args ) > 0. - DATA(ls_ew1) = VALUE zif_mjs=>ty_value( ). - DATA(ls_ew2) = VALUE zif_mjs=>ty_value( ). - READ TABLE it_args INDEX 1 INTO ls_ew1. - DATA(lv_ew_search) = zcl_mjs_val=>to_string( ls_ew1 ). - DATA(lv_ew_len) = strlen( is_obj-str ). - IF lines( it_args ) >= 2. - READ TABLE it_args INDEX 2 INTO ls_ew2. - lv_ew_len = zcl_mjs_val=>to_number( ls_ew2 ). - ENDIF. - IF lv_ew_len < 0. - lv_ew_len = 0. - ELSEIF lv_ew_len > strlen( is_obj-str ). - lv_ew_len = strlen( is_obj-str ). - ENDIF. - IF lv_ew_search = ``. - rs_val = zcl_mjs_val=>bool_val( abap_true ). - ELSEIF lv_ew_len < strlen( lv_ew_search ). - rs_val = zcl_mjs_val=>bool_val( abap_false ). - ELSEIF substring( val = is_obj-str - off = lv_ew_len - strlen( lv_ew_search ) - len = strlen( lv_ew_search ) ) = lv_ew_search. - rs_val = zcl_mjs_val=>bool_val( abap_true ). - ELSE. - rs_val = zcl_mjs_val=>bool_val( abap_false ). - ENDIF. - ELSE. - rs_val = zcl_mjs_val=>bool_val( abap_false ). - ENDIF. - WHEN `charAt`. - IF lines( it_args ) > 0. - DATA ls_cha TYPE zif_mjs=>ty_value. - READ TABLE it_args INDEX 1 INTO ls_cha. - DATA lv_cidx TYPE i. - lv_cidx = zcl_mjs_val=>to_number( ls_cha ). - IF lv_cidx >= 0 AND lv_cidx < strlen( is_obj-str ). - DATA lv_cha_tmp TYPE string. - lv_cha_tmp = substring( val = is_obj-str off = lv_cidx len = 1 ). - rs_val = zcl_mjs_val=>string_val( lv_cha_tmp ). - ELSE. - rs_val = zcl_mjs_val=>string_val( `` ). - ENDIF. - ELSE. - rs_val = zcl_mjs_val=>string_val( `` ). - ENDIF. - WHEN `indexOf`. - IF lines( it_args ) > 0. - DATA ls_ioa TYPE zif_mjs=>ty_value. - READ TABLE it_args INDEX 1 INTO ls_ioa. - DATA(lv_search) = zcl_mjs_val=>to_string( ls_ioa ). - FIND lv_search IN is_obj-str MATCH OFFSET DATA(lv_offset). - IF sy-subrc = 0. - rs_val = zcl_mjs_val=>number_val( CONV f( lv_offset ) ). - ELSE. - rs_val = zcl_mjs_val=>number_val( -1 ). - ENDIF. - ELSE. - rs_val = zcl_mjs_val=>number_val( -1 ). - ENDIF. - WHEN `lastIndexOf`. - IF lines( it_args ) > 0. - DATA ls_lioa1 TYPE zif_mjs=>ty_value. - DATA ls_lioa2 TYPE zif_mjs=>ty_value. - READ TABLE it_args INDEX 1 INTO ls_lioa1. - DATA(lv_lio_search) = zcl_mjs_val=>to_string( ls_lioa1 ). - DATA(lv_lio_off) = strlen( is_obj-str ). - IF lines( it_args ) >= 2. - READ TABLE it_args INDEX 2 INTO ls_lioa2. - lv_lio_off = zcl_mjs_val=>to_number( ls_lioa2 ). - IF lv_lio_off < 0. - lv_lio_off = 0. - ELSEIF lv_lio_off > strlen( is_obj-str ). - lv_lio_off = strlen( is_obj-str ). - ENDIF. - ENDIF. - FIND ALL OCCURRENCES OF lv_lio_search IN is_obj-str RESULTS DATA(lt_results). - DATA(lv_lio_res) = -1. - LOOP AT lt_results INTO DATA(ls_lio_res) WHERE offset <= lv_lio_off. - lv_lio_res = ls_lio_res-offset. - ENDLOOP. - rs_val = zcl_mjs_val=>number_val( CONV f( lv_lio_res ) ). - ELSE. - rs_val = zcl_mjs_val=>number_val( -1 ). - ENDIF. - WHEN `substring`. - IF lines( it_args ) >= 1. - DATA ls_ss1 TYPE zif_mjs=>ty_value. - DATA ls_ss2 TYPE zif_mjs=>ty_value. - READ TABLE it_args INDEX 1 INTO ls_ss1. - DATA lv_start TYPE i. - DATA lv_end TYPE i. - lv_start = zcl_mjs_val=>to_number( ls_ss1 ). - IF lines( it_args ) >= 2. - READ TABLE it_args INDEX 2 INTO ls_ss2. - lv_end = zcl_mjs_val=>to_number( ls_ss2 ). - ELSE. - lv_end = strlen( is_obj-str ). - ENDIF. - DATA lv_slen TYPE i. - lv_slen = strlen( is_obj-str ). - IF lv_start < 0. lv_start = 0. ENDIF. - IF lv_start > lv_slen. lv_start = lv_slen. ENDIF. - IF lv_end < 0. lv_end = 0. ENDIF. - IF lv_end > lv_slen. lv_end = lv_slen. ENDIF. - IF lv_start > lv_end. - DATA lv_tmp TYPE i. - lv_tmp = lv_start. - lv_start = lv_end. - lv_end = lv_tmp. - ENDIF. - DATA lv_sublen TYPE i. - lv_sublen = lv_end - lv_start. - IF lv_sublen > 0. - DATA lv_sub_tmp TYPE string. - lv_sub_tmp = substring( val = is_obj-str off = lv_start len = lv_sublen ). - rs_val = zcl_mjs_val=>string_val( lv_sub_tmp ). - ELSE. - rs_val = zcl_mjs_val=>string_val( `` ). - ENDIF. - ENDIF. - WHEN `substr`. - IF lines( it_args ) >= 1. - DATA ls_sub1 TYPE zif_mjs=>ty_value. - DATA ls_sub2 TYPE zif_mjs=>ty_value. - READ TABLE it_args INDEX 1 INTO ls_sub1. - DATA lv_sub_start TYPE i. - DATA lv_sub_len TYPE i. - DATA lv_sub_slen TYPE i. - lv_sub_slen = strlen( is_obj-str ). - lv_sub_start = zcl_mjs_val=>to_number( ls_sub1 ). - IF lv_sub_start < 0. - lv_sub_start = lv_sub_slen + lv_sub_start. - IF lv_sub_start < 0. - lv_sub_start = 0. - ENDIF. - ELSEIF lv_sub_start > lv_sub_slen. - lv_sub_start = lv_sub_slen. - ENDIF. - IF lines( it_args ) >= 2. - READ TABLE it_args INDEX 2 INTO ls_sub2. - lv_sub_len = zcl_mjs_val=>to_number( ls_sub2 ). - IF lv_sub_len <= 0. - rs_val = zcl_mjs_val=>string_val( `` ). - RETURN. - ENDIF. - IF lv_sub_start + lv_sub_len > lv_sub_slen. - lv_sub_len = lv_sub_slen - lv_sub_start. - ENDIF. - ELSE. - lv_sub_len = lv_sub_slen - lv_sub_start. - ENDIF. - IF lv_sub_len > 0. - DATA(lv_substr_res) = substring( val = is_obj-str - off = lv_sub_start - len = lv_sub_len ). - rs_val = zcl_mjs_val=>string_val( lv_substr_res ). - ELSE. - rs_val = zcl_mjs_val=>string_val( `` ). - ENDIF. - ENDIF. - WHEN `charCodeAt`. - IF lines( it_args ) > 0. - DATA ls_cca TYPE zif_mjs=>ty_value. - READ TABLE it_args INDEX 1 INTO ls_cca. - DATA lv_ccidx TYPE i. - lv_ccidx = zcl_mjs_val=>to_number( ls_cca ). - IF lv_ccidx >= 0 AND lv_ccidx < strlen( is_obj-str ). - DATA lv_char TYPE c LENGTH 1. - DATA lv_cc_tmp TYPE string. - lv_cc_tmp = substring( val = is_obj-str off = lv_ccidx len = 1 ). - lv_char = lv_cc_tmp. - DATA lv_hex TYPE x LENGTH 2. - lv_hex = cl_abap_conv_out_ce=>uccp( lv_char ). - DATA lv_code TYPE i. - lv_code = lv_hex. - rs_val = zcl_mjs_val=>number_val( CONV f( lv_code ) ). - ELSE. - rs_val = zcl_mjs_val=>number_val( 0 ). - ENDIF. - ELSE. - rs_val = zcl_mjs_val=>number_val( 0 ). - ENDIF. - WHEN `replace`. - IF lines( it_args ) >= 2. - DATA ls_rep1 TYPE zif_mjs=>ty_value. - DATA ls_rep2 TYPE zif_mjs=>ty_value. - READ TABLE it_args INDEX 1 INTO ls_rep1. - READ TABLE it_args INDEX 2 INTO ls_rep2. - DATA(lv_rep_to) = zcl_mjs_val=>to_string( ls_rep2 ). - IF ls_rep1-type = 8. - " RegExp first argument — use FIND loop to avoid REPLACE ALL IGNORING CASE runtime issues - DATA lv_rxint TYPE i. - DATA lv_rxglob TYPE abap_bool. - DATA lv_rxicase TYPE abap_bool. - DATA lv_rxrem TYPE string. - DATA lv_rxout TYPE string. - DATA lv_rxoff TYPE i. - DATA lv_rxmln TYPE i. - DATA lv_rxnxt TYPE i. - lv_rxint = CONV i( ls_rep1-num ). - " bitmask: 1=global, 2=ignoreCase — use explicit comparison (avoid integer division) - IF lv_rxint = 1 OR lv_rxint = 3. lv_rxglob = abap_true. ENDIF. - IF lv_rxint = 2 OR lv_rxint = 3. lv_rxicase = abap_true. ENDIF. - CLEAR lv_rxout. - lv_rxrem = is_obj-str. - DATA lv_rx_pos TYPE i VALUE 0. - DATA lt_rx_res TYPE match_result_tab. - IF strlen( ls_rep1-str ) = 0. - " Empty regex matches empty string between everywhere - DO. - IF lv_rx_pos > strlen( lv_rxrem ). EXIT. ENDIF. - DATA ls_e_res TYPE match_result. - ls_e_res-offset = lv_rx_pos. - ls_e_res-length = 0. - APPEND ls_e_res TO lt_rx_res. - lv_rx_pos = lv_rx_pos + 1. - IF lv_rxglob = abap_false OR lv_rx_pos > strlen( lv_rxrem ). - EXIT. - ENDIF. - ENDDO. - ELSE. - DO. - IF lv_rx_pos > strlen( lv_rxrem ). EXIT. ENDIF. - DATA ls_rx_res TYPE match_result. - IF lv_rxicase = abap_true. - FIND REGEX ls_rep1-str IN SECTION OFFSET lv_rx_pos OF lv_rxrem - MATCH OFFSET ls_rx_res-offset - MATCH LENGTH ls_rx_res-length - IGNORING CASE. - ELSE. - FIND REGEX ls_rep1-str IN SECTION OFFSET lv_rx_pos OF lv_rxrem - MATCH OFFSET ls_rx_res-offset - MATCH LENGTH ls_rx_res-length. - ENDIF. - IF sy-subrc <> 0. - EXIT. - ENDIF. - IF lv_rx_pos > 0 AND ls_rx_res-offset = lv_rx_pos AND ls_rx_res-length = 0 AND substring( val = ls_rep1-str len = 1 ) = '^'. - lv_rx_pos = lv_rx_pos + 1. - CONTINUE. - ENDIF. - APPEND ls_rx_res TO lt_rx_res. - IF lv_rxglob = abap_false. - EXIT. - ENDIF. - IF ls_rx_res-length = 0. - lv_rx_pos = ls_rx_res-offset + 1. - " Hack for open-abap: ^ matches start of section, which means we might get infinite exact zero-length hits if we keep searching from lv_rx_pos. But wait! We just incremented lv_rx_pos! - ELSE. - lv_rx_pos = ls_rx_res-offset + ls_rx_res-length. - ENDIF. - IF lv_rx_pos > strlen( lv_rxrem ). - EXIT. - ENDIF. - ENDDO. - ENDIF. - DATA lv_rx_pos2 TYPE i. - lv_rx_pos2 = 0. - LOOP AT lt_rx_res ASSIGNING FIELD-SYMBOL(). - IF -offset > lv_rx_pos2. - lv_rxout = lv_rxout && substring( val = lv_rxrem off = lv_rx_pos2 len = -offset - lv_rx_pos2 ). - ENDIF. - lv_rxout = lv_rxout && lv_rep_to. - lv_rx_pos2 = -offset + -length. - ENDLOOP. - IF lv_rx_pos2 < strlen( lv_rxrem ). - lv_rxout = lv_rxout && substring( val = lv_rxrem off = lv_rx_pos2 ). - ENDIF. - CLEAR lv_rxrem. - lv_rxout = lv_rxout && lv_rxrem. - rs_val = zcl_mjs_val=>string_val( lv_rxout ). - ELSE. - " String first argument - DATA(lv_rep_from) = zcl_mjs_val=>to_string( ls_rep1 ). - IF strlen( lv_rep_from ) = 0. - rs_val = zcl_mjs_val=>string_val( lv_rep_to && is_obj-str ). - ELSE. - DATA lv_rep_off TYPE i. - DATA lv_rep_mln TYPE i. - FIND lv_rep_from IN is_obj-str - RESPECTING CASE - MATCH OFFSET lv_rep_off - MATCH LENGTH lv_rep_mln. - IF sy-subrc = 0. - DATA lv_rep_res TYPE string. - IF lv_rep_off > 0. - lv_rep_res = substring( val = is_obj-str len = lv_rep_off ). - ENDIF. - lv_rep_res = lv_rep_res && lv_rep_to. - DATA(lv_rep_tail) = lv_rep_off + lv_rep_mln. - IF lv_rep_tail < strlen( is_obj-str ). - lv_rep_res = lv_rep_res && substring( val = is_obj-str off = lv_rep_tail ). - ENDIF. - rs_val = zcl_mjs_val=>string_val( lv_rep_res ). - ELSE. - rs_val = zcl_mjs_val=>string_val( is_obj-str ). - ENDIF. - ENDIF. - ENDIF. - ELSE. - rs_val = zcl_mjs_val=>string_val( is_obj-str ). - ENDIF. - WHEN `trim`. - DATA lv_trim_tmp TYPE string. - DATA lv_trim_ch TYPE string. - lv_trim_tmp = is_obj-str. - WHILE strlen( lv_trim_tmp ) > 0. - lv_trim_ch = substring( val = lv_trim_tmp off = 0 len = 1 ). - IF lv_trim_ch = ` ` OR lv_trim_ch = cl_abap_char_utilities=>horizontal_tab - OR lv_trim_ch = cl_abap_char_utilities=>newline OR lv_trim_ch = cl_abap_char_utilities=>cr_lf+0(1). - lv_trim_tmp = substring( val = lv_trim_tmp off = 1 ). - ELSE. - EXIT. - ENDIF. - ENDWHILE. - WHILE strlen( lv_trim_tmp ) > 0. - lv_trim_ch = substring( val = lv_trim_tmp off = strlen( lv_trim_tmp ) - 1 len = 1 ). - IF lv_trim_ch = ` ` OR lv_trim_ch = cl_abap_char_utilities=>horizontal_tab - OR lv_trim_ch = cl_abap_char_utilities=>newline OR lv_trim_ch = cl_abap_char_utilities=>cr_lf+0(1). - lv_trim_tmp = substring( val = lv_trim_tmp len = strlen( lv_trim_tmp ) - 1 ). - ELSE. - EXIT. - ENDIF. - ENDWHILE. - rs_val = zcl_mjs_val=>string_val( lv_trim_tmp ). - WHEN `trimEnd`. - DATA lv_trim_e_tmp TYPE string. - DATA lv_trim_e_ch TYPE string. - lv_trim_e_tmp = is_obj-str. - WHILE strlen( lv_trim_e_tmp ) > 0. - lv_trim_e_ch = substring( val = lv_trim_e_tmp off = strlen( lv_trim_e_tmp ) - 1 len = 1 ). - IF lv_trim_e_ch = ` ` OR lv_trim_e_ch = cl_abap_char_utilities=>horizontal_tab - OR lv_trim_e_ch = cl_abap_char_utilities=>newline OR lv_trim_e_ch = cl_abap_char_utilities=>cr_lf+0(1). - lv_trim_e_tmp = substring( val = lv_trim_e_tmp len = strlen( lv_trim_e_tmp ) - 1 ). - ELSE. - EXIT. - ENDIF. - ENDWHILE. - rs_val = zcl_mjs_val=>string_val( lv_trim_e_tmp ). - WHEN `split`. - IF lines( it_args ) > 0. - DATA(ls_spl_sep) = it_args[ 1 ]. - DATA(lv_spl_sep) = zcl_mjs_val=>to_string( ls_spl_sep ). - DATA(lv_spl_limit) = 2147483647. " max i - IF lines( it_args ) >= 2. - lv_spl_limit = zcl_mjs_val=>to_number( it_args[ 2 ] ). - ENDIF. - - DATA(lt_spl_items) = VALUE string_table( ). - IF lv_spl_sep = ``. - " split into characters - DATA(lv_spl_i) = 0. - WHILE lv_spl_i < strlen( is_obj-str ). - APPEND substring( val = is_obj-str off = lv_spl_i len = 1 ) TO lt_spl_items. - lv_spl_i = lv_spl_i + 1. - ENDWHILE. - ELSE. - SPLIT is_obj-str AT lv_spl_sep INTO TABLE lt_spl_items. - ENDIF. - - DATA lo_spl_arr TYPE REF TO zcl_mjs_array. - CREATE OBJECT lo_spl_arr. - DATA lv_spl_count TYPE i. - lv_spl_count = 0. - LOOP AT lt_spl_items INTO DATA(lv_spl_item) WHERE table_line IS NOT INITIAL OR table_line = ``. - IF lv_spl_count >= lv_spl_limit. EXIT. ENDIF. - lo_spl_arr->push( zcl_mjs_val=>box_value( zcl_mjs_val=>string_val( lv_spl_item ) ) ). - lv_spl_count = lv_spl_count + 1. - ENDLOOP. - rs_val-type = 7. - rs_val-arr = lo_spl_arr. - ELSE. - " default: one-element array with full string - DATA lo_spl_def TYPE REF TO zcl_mjs_array. - CREATE OBJECT lo_spl_def. - lo_spl_def->push( zcl_mjs_val=>box_value( is_obj ) ). - rs_val-type = 7. - rs_val-arr = lo_spl_def. - ENDIF. - WHEN OTHERS. - RAISE EXCEPTION TYPE zcx_mjs_runtime EXPORTING iv_error = |TypeError: { iv_method } is not a function|. - ENDCASE. + rs_val = zcl_mjs_string=>call_method( is_obj = is_obj iv_method = iv_method it_args = it_args ). WHEN 4. IF is_obj-obj IS BOUND. DATA lr_fn4_meth TYPE REF TO data. diff --git a/src/zcl_mjs_string.clas.abap b/src/zcl_mjs_string.clas.abap new file mode 100644 index 0000000..29dcc1d --- /dev/null +++ b/src/zcl_mjs_string.clas.abap @@ -0,0 +1,437 @@ +CLASS zcl_mjs_string DEFINITION PUBLIC. + PUBLIC SECTION. + CLASS-METHODS call_method + IMPORTING + is_obj TYPE zif_mjs=>ty_value + iv_method TYPE string + it_args TYPE zif_mjs=>tt_value_slots + RETURNING + VALUE(rs_val) TYPE zif_mjs=>ty_value + RAISING + zcx_mjs_runtime. + PRIVATE SECTION. +ENDCLASS. + +CLASS zcl_mjs_string IMPLEMENTATION. + METHOD call_method. + CASE iv_method. + WHEN `toUpperCase`. + rs_val = zcl_mjs_val=>string_val( to_upper( is_obj-str ) ). + WHEN `toLowerCase`. + rs_val = zcl_mjs_val=>string_val( to_lower( is_obj-str ) ). + WHEN `startsWith`. + IF lines( it_args ) > 0. + DATA(ls_sw1) = VALUE zif_mjs=>ty_value( ). + DATA(ls_sw2) = VALUE zif_mjs=>ty_value( ). + READ TABLE it_args INDEX 1 INTO ls_sw1. + DATA(lv_sw_search) = zcl_mjs_val=>to_string( ls_sw1 ). + DATA(lv_sw_pos) = 0. + IF lines( it_args ) >= 2. + READ TABLE it_args INDEX 2 INTO ls_sw2. + lv_sw_pos = zcl_mjs_val=>to_number( ls_sw2 ). + ENDIF. + IF lv_sw_pos < 0. + lv_sw_pos = 0. + ENDIF. + IF lv_sw_pos > strlen( is_obj-str ). + lv_sw_pos = strlen( is_obj-str ). + ENDIF. + IF lv_sw_search = ``. + rs_val = zcl_mjs_val=>bool_val( abap_true ). + ELSEIF lv_sw_pos + strlen( lv_sw_search ) > strlen( is_obj-str ). + rs_val = zcl_mjs_val=>bool_val( abap_false ). + ELSEIF substring( val = is_obj-str + off = lv_sw_pos + len = strlen( lv_sw_search ) ) = lv_sw_search. + rs_val = zcl_mjs_val=>bool_val( abap_true ). + ELSE. + rs_val = zcl_mjs_val=>bool_val( abap_false ). + ENDIF. + ELSE. + rs_val = zcl_mjs_val=>bool_val( abap_false ). + ENDIF. + WHEN `endsWith`. + IF lines( it_args ) > 0. + DATA(ls_ew1) = VALUE zif_mjs=>ty_value( ). + DATA(ls_ew2) = VALUE zif_mjs=>ty_value( ). + READ TABLE it_args INDEX 1 INTO ls_ew1. + DATA(lv_ew_search) = zcl_mjs_val=>to_string( ls_ew1 ). + DATA(lv_ew_len) = strlen( is_obj-str ). + IF lines( it_args ) >= 2. + READ TABLE it_args INDEX 2 INTO ls_ew2. + lv_ew_len = zcl_mjs_val=>to_number( ls_ew2 ). + ENDIF. + IF lv_ew_len < 0. + lv_ew_len = 0. + ELSEIF lv_ew_len > strlen( is_obj-str ). + lv_ew_len = strlen( is_obj-str ). + ENDIF. + IF lv_ew_search = ``. + rs_val = zcl_mjs_val=>bool_val( abap_true ). + ELSEIF lv_ew_len < strlen( lv_ew_search ). + rs_val = zcl_mjs_val=>bool_val( abap_false ). + ELSEIF substring( val = is_obj-str + off = lv_ew_len - strlen( lv_ew_search ) + len = strlen( lv_ew_search ) ) = lv_ew_search. + rs_val = zcl_mjs_val=>bool_val( abap_true ). + ELSE. + rs_val = zcl_mjs_val=>bool_val( abap_false ). + ENDIF. + ELSE. + rs_val = zcl_mjs_val=>bool_val( abap_false ). + ENDIF. + WHEN `charAt`. + IF lines( it_args ) > 0. + DATA ls_cha TYPE zif_mjs=>ty_value. + READ TABLE it_args INDEX 1 INTO ls_cha. + DATA lv_cidx TYPE i. + lv_cidx = zcl_mjs_val=>to_number( ls_cha ). + IF lv_cidx >= 0 AND lv_cidx < strlen( is_obj-str ). + DATA lv_cha_tmp TYPE string. + lv_cha_tmp = substring( val = is_obj-str off = lv_cidx len = 1 ). + rs_val = zcl_mjs_val=>string_val( lv_cha_tmp ). + ELSE. + rs_val = zcl_mjs_val=>string_val( `` ). + ENDIF. + ELSE. + rs_val = zcl_mjs_val=>string_val( `` ). + ENDIF. + WHEN `indexOf`. + IF lines( it_args ) > 0. + DATA ls_ioa TYPE zif_mjs=>ty_value. + READ TABLE it_args INDEX 1 INTO ls_ioa. + DATA(lv_search) = zcl_mjs_val=>to_string( ls_ioa ). + FIND lv_search IN is_obj-str MATCH OFFSET DATA(lv_offset). + IF sy-subrc = 0. + rs_val = zcl_mjs_val=>number_val( CONV f( lv_offset ) ). + ELSE. + rs_val = zcl_mjs_val=>number_val( -1 ). + ENDIF. + ELSE. + rs_val = zcl_mjs_val=>number_val( -1 ). + ENDIF. + WHEN `lastIndexOf`. + IF lines( it_args ) > 0. + DATA ls_lioa1 TYPE zif_mjs=>ty_value. + DATA ls_lioa2 TYPE zif_mjs=>ty_value. + READ TABLE it_args INDEX 1 INTO ls_lioa1. + DATA(lv_lio_search) = zcl_mjs_val=>to_string( ls_lioa1 ). + DATA(lv_lio_off) = strlen( is_obj-str ). + IF lines( it_args ) >= 2. + READ TABLE it_args INDEX 2 INTO ls_lioa2. + lv_lio_off = zcl_mjs_val=>to_number( ls_lioa2 ). + IF lv_lio_off < 0. + lv_lio_off = 0. + ELSEIF lv_lio_off > strlen( is_obj-str ). + lv_lio_off = strlen( is_obj-str ). + ENDIF. + ENDIF. + FIND ALL OCCURRENCES OF lv_lio_search IN is_obj-str RESULTS DATA(lt_results). + DATA(lv_lio_res) = -1. + LOOP AT lt_results INTO DATA(ls_lio_res) WHERE offset <= lv_lio_off. + lv_lio_res = ls_lio_res-offset. + ENDLOOP. + rs_val = zcl_mjs_val=>number_val( CONV f( lv_lio_res ) ). + ELSE. + rs_val = zcl_mjs_val=>number_val( -1 ). + ENDIF. + WHEN `substring`. + IF lines( it_args ) >= 1. + DATA ls_ss1 TYPE zif_mjs=>ty_value. + DATA ls_ss2 TYPE zif_mjs=>ty_value. + READ TABLE it_args INDEX 1 INTO ls_ss1. + DATA lv_start TYPE i. + DATA lv_end TYPE i. + lv_start = zcl_mjs_val=>to_number( ls_ss1 ). + IF lines( it_args ) >= 2. + READ TABLE it_args INDEX 2 INTO ls_ss2. + lv_end = zcl_mjs_val=>to_number( ls_ss2 ). + ELSE. + lv_end = strlen( is_obj-str ). + ENDIF. + DATA lv_slen TYPE i. + lv_slen = strlen( is_obj-str ). + IF lv_start < 0. lv_start = 0. ENDIF. + IF lv_start > lv_slen. lv_start = lv_slen. ENDIF. + IF lv_end < 0. lv_end = 0. ENDIF. + IF lv_end > lv_slen. lv_end = lv_slen. ENDIF. + IF lv_start > lv_end. + DATA lv_tmp TYPE i. + lv_tmp = lv_start. + lv_start = lv_end. + lv_end = lv_tmp. + ENDIF. + DATA lv_sublen TYPE i. + lv_sublen = lv_end - lv_start. + IF lv_sublen > 0. + DATA lv_sub_tmp TYPE string. + lv_sub_tmp = substring( val = is_obj-str off = lv_start len = lv_sublen ). + rs_val = zcl_mjs_val=>string_val( lv_sub_tmp ). + ELSE. + rs_val = zcl_mjs_val=>string_val( `` ). + ENDIF. + ENDIF. + WHEN `substr`. + IF lines( it_args ) >= 1. + DATA ls_sub1 TYPE zif_mjs=>ty_value. + DATA ls_sub2 TYPE zif_mjs=>ty_value. + READ TABLE it_args INDEX 1 INTO ls_sub1. + DATA lv_sub_start TYPE i. + DATA lv_sub_len TYPE i. + DATA lv_sub_slen TYPE i. + lv_sub_slen = strlen( is_obj-str ). + lv_sub_start = zcl_mjs_val=>to_number( ls_sub1 ). + IF lv_sub_start < 0. + lv_sub_start = lv_sub_slen + lv_sub_start. + IF lv_sub_start < 0. + lv_sub_start = 0. + ENDIF. + ELSEIF lv_sub_start > lv_sub_slen. + lv_sub_start = lv_sub_slen. + ENDIF. + IF lines( it_args ) >= 2. + READ TABLE it_args INDEX 2 INTO ls_sub2. + lv_sub_len = zcl_mjs_val=>to_number( ls_sub2 ). + IF lv_sub_len <= 0. + rs_val = zcl_mjs_val=>string_val( `` ). + RETURN. + ENDIF. + IF lv_sub_start + lv_sub_len > lv_sub_slen. + lv_sub_len = lv_sub_slen - lv_sub_start. + ENDIF. + ELSE. + lv_sub_len = lv_sub_slen - lv_sub_start. + ENDIF. + IF lv_sub_len > 0. + DATA(lv_substr_res) = substring( val = is_obj-str + off = lv_sub_start + len = lv_sub_len ). + rs_val = zcl_mjs_val=>string_val( lv_substr_res ). + ELSE. + rs_val = zcl_mjs_val=>string_val( `` ). + ENDIF. + ENDIF. + WHEN `charCodeAt`. + IF lines( it_args ) > 0. + DATA ls_cca TYPE zif_mjs=>ty_value. + READ TABLE it_args INDEX 1 INTO ls_cca. + DATA lv_ccidx TYPE i. + lv_ccidx = zcl_mjs_val=>to_number( ls_cca ). + IF lv_ccidx >= 0 AND lv_ccidx < strlen( is_obj-str ). + DATA lv_char TYPE c LENGTH 1. + DATA lv_cc_tmp TYPE string. + lv_cc_tmp = substring( val = is_obj-str off = lv_ccidx len = 1 ). + lv_char = lv_cc_tmp. + DATA lv_hex TYPE x LENGTH 2. + lv_hex = cl_abap_conv_out_ce=>uccp( lv_char ). + DATA lv_code TYPE i. + lv_code = lv_hex. + rs_val = zcl_mjs_val=>number_val( CONV f( lv_code ) ). + ELSE. + rs_val = zcl_mjs_val=>number_val( 0 ). + ENDIF. + ELSE. + rs_val = zcl_mjs_val=>number_val( 0 ). + ENDIF. + WHEN `replace`. + IF lines( it_args ) >= 2. + DATA ls_rep1 TYPE zif_mjs=>ty_value. + DATA ls_rep2 TYPE zif_mjs=>ty_value. + READ TABLE it_args INDEX 1 INTO ls_rep1. + READ TABLE it_args INDEX 2 INTO ls_rep2. + DATA(lv_rep_to) = zcl_mjs_val=>to_string( ls_rep2 ). + IF ls_rep1-type = 8. + " RegExp first argument — use FIND loop to avoid REPLACE ALL IGNORING CASE runtime issues + DATA lv_rxint TYPE i. + DATA lv_rxglob TYPE abap_bool. + DATA lv_rxicase TYPE abap_bool. + DATA lv_rxrem TYPE string. + DATA lv_rxout TYPE string. + DATA lv_rxoff TYPE i. + DATA lv_rxmln TYPE i. + DATA lv_rxnxt TYPE i. + lv_rxint = CONV i( ls_rep1-num ). + " bitmask: 1=global, 2=ignoreCase — use explicit comparison (avoid integer division) + IF lv_rxint = 1 OR lv_rxint = 3. lv_rxglob = abap_true. ENDIF. + IF lv_rxint = 2 OR lv_rxint = 3. lv_rxicase = abap_true. ENDIF. + CLEAR lv_rxout. + lv_rxrem = is_obj-str. + DATA lv_rx_pos TYPE i VALUE 0. + DATA lt_rx_res TYPE match_result_tab. + IF strlen( ls_rep1-str ) = 0. + " Empty regex matches empty string between everywhere + DO. + IF lv_rx_pos > strlen( lv_rxrem ). EXIT. ENDIF. + DATA ls_e_res TYPE match_result. + ls_e_res-offset = lv_rx_pos. + ls_e_res-length = 0. + APPEND ls_e_res TO lt_rx_res. + lv_rx_pos = lv_rx_pos + 1. + IF lv_rxglob = abap_false OR lv_rx_pos > strlen( lv_rxrem ). + EXIT. + ENDIF. + ENDDO. + ELSE. + DO. + IF lv_rx_pos > strlen( lv_rxrem ). EXIT. ENDIF. + DATA ls_rx_res TYPE match_result. + IF lv_rxicase = abap_true. + FIND REGEX ls_rep1-str IN SECTION OFFSET lv_rx_pos OF lv_rxrem + MATCH OFFSET ls_rx_res-offset + MATCH LENGTH ls_rx_res-length + IGNORING CASE. + ELSE. + FIND REGEX ls_rep1-str IN SECTION OFFSET lv_rx_pos OF lv_rxrem + MATCH OFFSET ls_rx_res-offset + MATCH LENGTH ls_rx_res-length. + ENDIF. + IF sy-subrc <> 0. + EXIT. + ENDIF. + IF lv_rx_pos > 0 AND ls_rx_res-offset = lv_rx_pos AND ls_rx_res-length = 0 AND substring( val = ls_rep1-str len = 1 ) = '^'. + lv_rx_pos = lv_rx_pos + 1. + CONTINUE. + ENDIF. + APPEND ls_rx_res TO lt_rx_res. + IF lv_rxglob = abap_false. + EXIT. + ENDIF. + IF ls_rx_res-length = 0. + lv_rx_pos = ls_rx_res-offset + 1. + " Hack for open-abap: ^ matches start of section, which means we might get infinite exact zero-length hits if we keep searching from lv_rx_pos. But wait! We just incremented lv_rx_pos! + ELSE. + lv_rx_pos = ls_rx_res-offset + ls_rx_res-length. + ENDIF. + IF lv_rx_pos > strlen( lv_rxrem ). + EXIT. + ENDIF. + ENDDO. + ENDIF. + DATA lv_rx_pos2 TYPE i. + lv_rx_pos2 = 0. + LOOP AT lt_rx_res ASSIGNING FIELD-SYMBOL(). + IF -offset > lv_rx_pos2. + lv_rxout = lv_rxout && substring( val = lv_rxrem off = lv_rx_pos2 len = -offset - lv_rx_pos2 ). + ENDIF. + lv_rxout = lv_rxout && lv_rep_to. + lv_rx_pos2 = -offset + -length. + ENDLOOP. + IF lv_rx_pos2 < strlen( lv_rxrem ). + lv_rxout = lv_rxout && substring( val = lv_rxrem off = lv_rx_pos2 ). + ENDIF. + CLEAR lv_rxrem. + lv_rxout = lv_rxout && lv_rxrem. + rs_val = zcl_mjs_val=>string_val( lv_rxout ). + ELSE. + " String first argument + DATA(lv_rep_from) = zcl_mjs_val=>to_string( ls_rep1 ). + IF strlen( lv_rep_from ) = 0. + rs_val = zcl_mjs_val=>string_val( lv_rep_to && is_obj-str ). + ELSE. + DATA lv_rep_off TYPE i. + DATA lv_rep_mln TYPE i. + FIND lv_rep_from IN is_obj-str + RESPECTING CASE + MATCH OFFSET lv_rep_off + MATCH LENGTH lv_rep_mln. + IF sy-subrc = 0. + DATA lv_rep_res TYPE string. + IF lv_rep_off > 0. + lv_rep_res = substring( val = is_obj-str len = lv_rep_off ). + ENDIF. + lv_rep_res = lv_rep_res && lv_rep_to. + DATA(lv_rep_tail) = lv_rep_off + lv_rep_mln. + IF lv_rep_tail < strlen( is_obj-str ). + lv_rep_res = lv_rep_res && substring( val = is_obj-str off = lv_rep_tail ). + ENDIF. + rs_val = zcl_mjs_val=>string_val( lv_rep_res ). + ELSE. + rs_val = zcl_mjs_val=>string_val( is_obj-str ). + ENDIF. + ENDIF. + ENDIF. + ELSE. + rs_val = zcl_mjs_val=>string_val( is_obj-str ). + ENDIF. + WHEN `trim`. + DATA lv_trim_tmp TYPE string. + DATA lv_trim_ch TYPE string. + lv_trim_tmp = is_obj-str. + WHILE strlen( lv_trim_tmp ) > 0. + lv_trim_ch = substring( val = lv_trim_tmp off = 0 len = 1 ). + IF lv_trim_ch = ` ` OR lv_trim_ch = cl_abap_char_utilities=>horizontal_tab + OR lv_trim_ch = cl_abap_char_utilities=>newline OR lv_trim_ch = cl_abap_char_utilities=>cr_lf+0(1). + lv_trim_tmp = substring( val = lv_trim_tmp off = 1 ). + ELSE. + EXIT. + ENDIF. + ENDWHILE. + WHILE strlen( lv_trim_tmp ) > 0. + lv_trim_ch = substring( val = lv_trim_tmp off = strlen( lv_trim_tmp ) - 1 len = 1 ). + IF lv_trim_ch = ` ` OR lv_trim_ch = cl_abap_char_utilities=>horizontal_tab + OR lv_trim_ch = cl_abap_char_utilities=>newline OR lv_trim_ch = cl_abap_char_utilities=>cr_lf+0(1). + lv_trim_tmp = substring( val = lv_trim_tmp len = strlen( lv_trim_tmp ) - 1 ). + ELSE. + EXIT. + ENDIF. + ENDWHILE. + rs_val = zcl_mjs_val=>string_val( lv_trim_tmp ). + WHEN `trimEnd`. + DATA lv_trim_e_tmp TYPE string. + DATA lv_trim_e_ch TYPE string. + lv_trim_e_tmp = is_obj-str. + WHILE strlen( lv_trim_e_tmp ) > 0. + lv_trim_e_ch = substring( val = lv_trim_e_tmp off = strlen( lv_trim_e_tmp ) - 1 len = 1 ). + IF lv_trim_e_ch = ` ` OR lv_trim_e_ch = cl_abap_char_utilities=>horizontal_tab + OR lv_trim_e_ch = cl_abap_char_utilities=>newline OR lv_trim_e_ch = cl_abap_char_utilities=>cr_lf+0(1). + lv_trim_e_tmp = substring( val = lv_trim_e_tmp len = strlen( lv_trim_e_tmp ) - 1 ). + ELSE. + EXIT. + ENDIF. + ENDWHILE. + rs_val = zcl_mjs_val=>string_val( lv_trim_e_tmp ). + WHEN `split`. + IF lines( it_args ) > 0. + DATA(ls_spl_sep) = it_args[ 1 ]. + DATA(lv_spl_sep) = zcl_mjs_val=>to_string( ls_spl_sep ). + DATA(lv_spl_limit) = 2147483647. " max i + IF lines( it_args ) >= 2. + lv_spl_limit = zcl_mjs_val=>to_number( it_args[ 2 ] ). + ENDIF. + + DATA(lt_spl_items) = VALUE string_table( ). + IF lv_spl_sep = ``. + " split into characters + DATA(lv_spl_i) = 0. + WHILE lv_spl_i < strlen( is_obj-str ). + APPEND substring( val = is_obj-str off = lv_spl_i len = 1 ) TO lt_spl_items. + lv_spl_i = lv_spl_i + 1. + ENDWHILE. + ELSE. + SPLIT is_obj-str AT lv_spl_sep INTO TABLE lt_spl_items. + ENDIF. + + DATA lo_spl_arr TYPE REF TO zcl_mjs_array. + CREATE OBJECT lo_spl_arr. + DATA lv_spl_count TYPE i. + lv_spl_count = 0. + LOOP AT lt_spl_items INTO DATA(lv_spl_item) WHERE table_line IS NOT INITIAL OR table_line = ``. + IF lv_spl_count >= lv_spl_limit. EXIT. ENDIF. + lo_spl_arr->push( zcl_mjs_val=>box_value( zcl_mjs_val=>string_val( lv_spl_item ) ) ). + lv_spl_count = lv_spl_count + 1. + ENDLOOP. + rs_val-type = 7. + rs_val-arr = lo_spl_arr. + ELSE. + " default: one-element array with full string + DATA lo_spl_def TYPE REF TO zcl_mjs_array. + CREATE OBJECT lo_spl_def. + lo_spl_def->push( zcl_mjs_val=>box_value( is_obj ) ). + rs_val-type = 7. + rs_val-arr = lo_spl_def. + ENDIF. + WHEN OTHERS. + RAISE EXCEPTION TYPE zcx_mjs_runtime EXPORTING iv_error = |TypeError: { iv_method } is not a function|. + ENDCASE. + ENDMETHOD. +ENDCLASS. diff --git a/src/zcl_mjs_string.clas.xml b/src/zcl_mjs_string.clas.xml new file mode 100644 index 0000000..7472305 --- /dev/null +++ b/src/zcl_mjs_string.clas.xml @@ -0,0 +1,16 @@ + + + + + + ZCL_MJS_STRING + E + Mini JavaScript Engine - String + 1 + X + X + X + + + + From 87f8468abdfc2907810722c5f5d5e10bfdffd514 Mon Sep 17 00:00:00 2001 From: Lars Hvam <5888506+larshp@users.noreply.github.com> Date: Wed, 8 Apr 2026 14:30:37 +0200 Subject: [PATCH 5/7] move to separate package --- src/types/package.devc.xml | 10 ++++++++++ src/{ => types}/zcl_mjs_array.clas.abap | 0 src/{ => types}/zcl_mjs_array.clas.xml | 0 src/{ => types}/zcl_mjs_string.clas.abap | 0 src/{ => types}/zcl_mjs_string.clas.xml | 0 5 files changed, 10 insertions(+) create mode 100644 src/types/package.devc.xml rename src/{ => types}/zcl_mjs_array.clas.abap (100%) rename src/{ => types}/zcl_mjs_array.clas.xml (100%) rename src/{ => types}/zcl_mjs_string.clas.abap (100%) rename src/{ => types}/zcl_mjs_string.clas.xml (100%) diff --git a/src/types/package.devc.xml b/src/types/package.devc.xml new file mode 100644 index 0000000..b84874d --- /dev/null +++ b/src/types/package.devc.xml @@ -0,0 +1,10 @@ + + + + + + Mini JavaScript Engine + + + + diff --git a/src/zcl_mjs_array.clas.abap b/src/types/zcl_mjs_array.clas.abap similarity index 100% rename from src/zcl_mjs_array.clas.abap rename to src/types/zcl_mjs_array.clas.abap diff --git a/src/zcl_mjs_array.clas.xml b/src/types/zcl_mjs_array.clas.xml similarity index 100% rename from src/zcl_mjs_array.clas.xml rename to src/types/zcl_mjs_array.clas.xml diff --git a/src/zcl_mjs_string.clas.abap b/src/types/zcl_mjs_string.clas.abap similarity index 100% rename from src/zcl_mjs_string.clas.abap rename to src/types/zcl_mjs_string.clas.abap diff --git a/src/zcl_mjs_string.clas.xml b/src/types/zcl_mjs_string.clas.xml similarity index 100% rename from src/zcl_mjs_string.clas.xml rename to src/types/zcl_mjs_string.clas.xml From 42416ca198dc797e209b822fb6a0400fc2901853 Mon Sep 17 00:00:00 2001 From: Lars Hvam <5888506+larshp@users.noreply.github.com> Date: Wed, 8 Apr 2026 14:36:16 +0200 Subject: [PATCH 6/7] extract stringify --- src/types/zcl_mjs_json.clas.abap | 123 +++++++++++++++++++++++++++++++ src/types/zcl_mjs_json.clas.xml | 16 ++++ src/zcl_mjs.clas.abap | 118 +---------------------------- 3 files changed, 140 insertions(+), 117 deletions(-) create mode 100644 src/types/zcl_mjs_json.clas.abap create mode 100644 src/types/zcl_mjs_json.clas.xml diff --git a/src/types/zcl_mjs_json.clas.abap b/src/types/zcl_mjs_json.clas.abap new file mode 100644 index 0000000..a51329b --- /dev/null +++ b/src/types/zcl_mjs_json.clas.abap @@ -0,0 +1,123 @@ +CLASS zcl_mjs_json DEFINITION PUBLIC FINAL. + PUBLIC SECTION. + CLASS-METHODS stringify + IMPORTING is_val TYPE zif_mjs=>ty_value + RETURNING VALUE(rv_json) TYPE string. +ENDCLASS. + +CLASS zcl_mjs_json IMPLEMENTATION. + + METHOD stringify. + CASE is_val-type. + WHEN 0. " undefined → omit marker (caller handles) + rv_json = ``. + RETURN. + WHEN 5. " null + rv_json = `null`. + WHEN 1. " number + IF is_val-str = `NaN` OR is_val-str = `Infinity` OR is_val-str = `-Infinity`. + rv_json = `null`. + ELSE. + rv_json = zcl_mjs_val=>to_string( is_val ). + ENDIF. + WHEN 3. " boolean + rv_json = COND #( WHEN is_val-num <> 0 THEN `true` ELSE `false` ). + WHEN 2. " string — quote and escape + DATA lv_src TYPE string. + DATA lv_out TYPE string. + DATA lv_len TYPE i. + DATA lv_idx TYPE i. + DATA lv_ch TYPE string. + DATA lv_cp TYPE i. + DATA lv_hex2 TYPE x LENGTH 2. + lv_src = is_val-str. + lv_len = strlen( lv_src ). + lv_out = `"`. + lv_idx = 0. + WHILE lv_idx < lv_len. + lv_ch = substring( val = lv_src off = lv_idx len = 1 ). + lv_hex2 = cl_abap_conv_out_ce=>uccp( lv_ch ). + lv_cp = lv_hex2. + IF lv_ch = `"`. + lv_out = lv_out && `\"`. + ELSEIF lv_ch = `\`. + lv_out = lv_out && `\\`. + ELSEIF lv_cp = 10. " newline + lv_out = lv_out && `\n`. + ELSEIF lv_cp = 13. " carriage return + lv_out = lv_out && `\r`. + ELSEIF lv_cp = 9. " tab + lv_out = lv_out && `\t`. + ELSEIF lv_cp < 32. " other control chars + DATA lv_hex4_x TYPE x LENGTH 2. + DATA lv_hex4 TYPE string. + lv_hex4_x = lv_cp. + lv_hex4 = lv_hex4_x. + TRANSLATE lv_hex4 TO LOWER CASE. + lv_out = lv_out && `\u` && lv_hex4. + ELSE. + lv_out = lv_out && lv_ch. + ENDIF. + lv_idx = lv_idx + 1. + ENDWHILE. + rv_json = lv_out && `"`. + WHEN 6. " object + IF is_val-obj IS NOT BOUND. + rv_json = `{}`. + RETURN. + ENDIF. + DATA lv_obj_out TYPE string. + DATA lv_obj_first TYPE abap_bool VALUE abap_true. + lv_obj_out = `{`. + LOOP AT is_val-obj->props ASSIGNING FIELD-SYMBOL(). + DATA(ls_pval) = zcl_mjs_val=>unbox_value( -val ). + " skip undefined and function values + IF ls_pval-type = 0 OR ls_pval-type = 4. + CONTINUE. + ENDIF. + IF lv_obj_first = abap_false. + lv_obj_out = lv_obj_out && `,`. + ENDIF. + lv_obj_out = lv_obj_out && `"` && -key && `":` && stringify( ls_pval ). + lv_obj_first = abap_false. + ENDLOOP. + rv_json = lv_obj_out && `}`. + WHEN 7. " array + IF is_val-arr IS NOT BOUND. + rv_json = `[]`. + RETURN. + ENDIF. + DATA lv_arr_out TYPE string. + DATA lv_arr_first TYPE abap_bool VALUE abap_true. + DATA lv_arr_len TYPE i. + DATA lv_arr_idx TYPE i. + lv_arr_out = `[`. + lv_arr_len = is_val-arr->length( ). + lv_arr_idx = 0. + WHILE lv_arr_idx < lv_arr_len. + DATA(lr_elem) = is_val-arr->get_item( lv_arr_idx ). + DATA lv_elem_json TYPE string. + IF lr_elem IS BOUND. + DATA(ls_elem) = zcl_mjs_val=>unbox_value( lr_elem ). + IF ls_elem-type = 0 OR ls_elem-type = 4. + lv_elem_json = `null`. " undefined/function in array → null + ELSE. + lv_elem_json = stringify( ls_elem ). + ENDIF. + ELSE. + lv_elem_json = `null`. + ENDIF. + IF lv_arr_first = abap_false. + lv_arr_out = lv_arr_out && `,`. + ENDIF. + lv_arr_out = lv_arr_out && lv_elem_json. + lv_arr_first = abap_false. + lv_arr_idx = lv_arr_idx + 1. + ENDWHILE. + rv_json = lv_arr_out && `]`. + WHEN OTHERS. + rv_json = `null`. + ENDCASE. + ENDMETHOD. + +ENDCLASS. diff --git a/src/types/zcl_mjs_json.clas.xml b/src/types/zcl_mjs_json.clas.xml new file mode 100644 index 0000000..e097298 --- /dev/null +++ b/src/types/zcl_mjs_json.clas.xml @@ -0,0 +1,16 @@ + + + + + + ZCL_MJS_JSON + E + Mini JavaScript Engine - JSON helpers + 1 + X + X + X + + + + diff --git a/src/zcl_mjs.clas.abap b/src/zcl_mjs.clas.abap index d5feee4..3e016e3 100644 --- a/src/zcl_mjs.clas.abap +++ b/src/zcl_mjs.clas.abap @@ -59,9 +59,6 @@ CLASS zcl_mjs DEFINITION PUBLIC. IMPORTING ir_node TYPE REF TO data iv_name TYPE string RETURNING VALUE(rv_found) TYPE abap_bool. - CLASS-METHODS json_stringify_val - IMPORTING is_val TYPE zif_mjs=>ty_value - RETURNING VALUE(rv_json) TYPE string. ENDCLASS. @@ -1544,7 +1541,7 @@ CLASS zcl_mjs IMPLEMENTATION. IF ls_jsin-type = 0 OR ls_jsin-type = 4. rs_val = zcl_mjs_val=>undefined_val( ). ELSE. - rs_val = zcl_mjs_val=>string_val( json_stringify_val( ls_jsin ) ). + rs_val = zcl_mjs_val=>string_val( zcl_mjs_json=>stringify( ls_jsin ) ). ENDIF. RETURN. ENDIF. @@ -2943,117 +2940,4 @@ CLASS zcl_mjs IMPLEMENTATION. ENDCASE. ENDMETHOD. - METHOD json_stringify_val. - CASE is_val-type. - WHEN 0. " undefined → omit marker (caller handles) - rv_json = ``. - RETURN. - WHEN 5. " null - rv_json = `null`. - WHEN 1. " number - IF is_val-str = `NaN` OR is_val-str = `Infinity` OR is_val-str = `-Infinity`. - rv_json = `null`. - ELSE. - rv_json = zcl_mjs_val=>to_string( is_val ). - ENDIF. - WHEN 3. " boolean - rv_json = COND #( WHEN is_val-num <> 0 THEN `true` ELSE `false` ). - WHEN 2. " string — quote and escape - DATA lv_src TYPE string. - DATA lv_out TYPE string. - DATA lv_len TYPE i. - DATA lv_idx TYPE i. - DATA lv_ch TYPE string. - DATA lv_cp TYPE i. - DATA lv_hex2 TYPE x LENGTH 2. - lv_src = is_val-str. - lv_len = strlen( lv_src ). - lv_out = `"`. - lv_idx = 0. - WHILE lv_idx < lv_len. - lv_ch = substring( val = lv_src off = lv_idx len = 1 ). - lv_hex2 = cl_abap_conv_out_ce=>uccp( lv_ch ). - lv_cp = lv_hex2. - IF lv_ch = `"`. - lv_out = lv_out && `\"`. - ELSEIF lv_ch = `\`. - lv_out = lv_out && `\\`. - ELSEIF lv_cp = 10. " newline - lv_out = lv_out && `\n`. - ELSEIF lv_cp = 13. " carriage return - lv_out = lv_out && `\r`. - ELSEIF lv_cp = 9. " tab - lv_out = lv_out && `\t`. - ELSEIF lv_cp < 32. " other control chars - DATA lv_hex4_x TYPE x LENGTH 2. - DATA lv_hex4 TYPE string. - lv_hex4_x = lv_cp. - lv_hex4 = lv_hex4_x. - TRANSLATE lv_hex4 TO LOWER CASE. - lv_out = lv_out && `\u` && lv_hex4. - ELSE. - lv_out = lv_out && lv_ch. - ENDIF. - lv_idx = lv_idx + 1. - ENDWHILE. - rv_json = lv_out && `"`. - WHEN 6. " object - IF is_val-obj IS NOT BOUND. - rv_json = `{}`. - RETURN. - ENDIF. - DATA lv_obj_out TYPE string. - DATA lv_obj_first TYPE abap_bool VALUE abap_true. - lv_obj_out = `{`. - LOOP AT is_val-obj->props ASSIGNING FIELD-SYMBOL(). - DATA(ls_pval) = zcl_mjs_val=>unbox_value( -val ). - " skip undefined and function values - IF ls_pval-type = 0 OR ls_pval-type = 4. - CONTINUE. - ENDIF. - IF lv_obj_first = abap_false. - lv_obj_out = lv_obj_out && `,`. - ENDIF. - lv_obj_out = lv_obj_out && `"` && -key && `":` && json_stringify_val( ls_pval ). - lv_obj_first = abap_false. - ENDLOOP. - rv_json = lv_obj_out && `}`. - WHEN 7. " array - IF is_val-arr IS NOT BOUND. - rv_json = `[]`. - RETURN. - ENDIF. - DATA lv_arr_out TYPE string. - DATA lv_arr_first TYPE abap_bool VALUE abap_true. - DATA lv_arr_len TYPE i. - DATA lv_arr_idx TYPE i. - lv_arr_out = `[`. - lv_arr_len = is_val-arr->length( ). - lv_arr_idx = 0. - WHILE lv_arr_idx < lv_arr_len. - DATA(lr_elem) = is_val-arr->get_item( lv_arr_idx ). - DATA lv_elem_json TYPE string. - IF lr_elem IS BOUND. - DATA(ls_elem) = zcl_mjs_val=>unbox_value( lr_elem ). - IF ls_elem-type = 0 OR ls_elem-type = 4. - lv_elem_json = `null`. " undefined/function in array → null - ELSE. - lv_elem_json = json_stringify_val( ls_elem ). - ENDIF. - ELSE. - lv_elem_json = `null`. - ENDIF. - IF lv_arr_first = abap_false. - lv_arr_out = lv_arr_out && `,`. - ENDIF. - lv_arr_out = lv_arr_out && lv_elem_json. - lv_arr_first = abap_false. - lv_arr_idx = lv_arr_idx + 1. - ENDWHILE. - rv_json = lv_arr_out && `]`. - WHEN OTHERS. - rv_json = `null`. - ENDCASE. - ENDMETHOD. - ENDCLASS. From d6b33f2d9e0c383938f263b767e65f3b9c7f4ca9 Mon Sep 17 00:00:00 2001 From: Lars Hvam Petersen <5888506+larshp@users.noreply.github.com> Date: Wed, 8 Apr 2026 12:39:00 +0000 Subject: [PATCH 7/7] fix whitespace --- src/types/zcl_mjs_json.clas.xml | 2 +- src/types/zcl_mjs_string.clas.xml | 2 +- src/zcl_mjs_val.clas.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/types/zcl_mjs_json.clas.xml b/src/types/zcl_mjs_json.clas.xml index e097298..3d26a12 100644 --- a/src/types/zcl_mjs_json.clas.xml +++ b/src/types/zcl_mjs_json.clas.xml @@ -1,4 +1,4 @@ - + diff --git a/src/types/zcl_mjs_string.clas.xml b/src/types/zcl_mjs_string.clas.xml index 7472305..007f90a 100644 --- a/src/types/zcl_mjs_string.clas.xml +++ b/src/types/zcl_mjs_string.clas.xml @@ -1,4 +1,4 @@ - + diff --git a/src/zcl_mjs_val.clas.xml b/src/zcl_mjs_val.clas.xml index 36ea1fb..92b1159 100644 --- a/src/zcl_mjs_val.clas.xml +++ b/src/zcl_mjs_val.clas.xml @@ -1,4 +1,4 @@ - +