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_arr.clas.abap b/src/types/zcl_mjs_array.clas.abap
similarity index 89%
rename from src/zcl_mjs_arr.clas.abap
rename to src/types/zcl_mjs_array.clas.abap
index 777b485..ecb8223 100644
--- a/src/zcl_mjs_arr.clas.abap
+++ b/src/types/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/types/zcl_mjs_array.clas.xml
similarity index 92%
rename from src/zcl_mjs_arr.clas.xml
rename to src/types/zcl_mjs_array.clas.xml
index db61968..0b2fb06 100644
--- a/src/zcl_mjs_arr.clas.xml
+++ b/src/types/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/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..3d26a12
--- /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/types/zcl_mjs_string.clas.abap b/src/types/zcl_mjs_string.clas.abap
new file mode 100644
index 0000000..29dcc1d
--- /dev/null
+++ b/src/types/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/types/zcl_mjs_string.clas.xml b/src/types/zcl_mjs_string.clas.xml
new file mode 100644
index 0000000..007f90a
--- /dev/null
+++ b/src/types/zcl_mjs_string.clas.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+ ZCL_MJS_STRING
+ E
+ Mini JavaScript Engine - String
+ 1
+ X
+ X
+ X
+
+
+
+
diff --git a/src/zcl_mjs.clas.abap b/src/zcl_mjs.clas.abap
index f091d90..3e016e3 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
@@ -79,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.
@@ -92,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.
@@ -113,9 +77,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 +91,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,138 +702,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.
- 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.
@@ -1238,7 +1070,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 +1081,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 +1089,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 +1112,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,15 +1188,15 @@ 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 ) ).
+ 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.
@@ -1388,7 +1220,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 +1238,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 +1247,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 +1281,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.
@@ -1494,7 +1326,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.
@@ -1524,10 +1356,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.
@@ -1558,7 +1390,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 +1444,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.
@@ -1661,7 +1493,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.
@@ -1673,7 +1505,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 +1514,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 +1536,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( zcl_mjs_json=>stringify( ls_jsin ) ).
ENDIF.
RETURN.
ENDIF.
@@ -1721,11 +1553,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`.
@@ -1733,10 +1565,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.
@@ -1746,7 +1578,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,16 +1593,16 @@ 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.
- 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 = 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.
@@ -1782,9 +1614,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,16 +1633,16 @@ 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.
- 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 = 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.
@@ -1837,7 +1669,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 +1681,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 zcl_mjs_val=>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,17 +1697,17 @@ 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` ).
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 = 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.
@@ -1883,7 +1715,7 @@ CLASS zcl_mjs IMPLEMENTATION.
RETURN.
ENDIF.
ENDIF.
- rs_val = undefined_val( ).
+ rs_val = zcl_mjs_val=>undefined_val( ).
RETURN.
ENDIF.
ENDIF.
@@ -1900,7 +1732,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 ).
@@ -1908,14 +1740,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.
@@ -1928,7 +1760,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.
@@ -1941,7 +1773,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.
@@ -1988,11 +1820,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 +1904,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.
@@ -2087,7 +1919,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.
@@ -2104,10 +1936,10 @@ 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 = 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 +1964,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 +1985,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 +2034,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,15 +2045,15 @@ 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 #( ) ).
- rs_val-obj->set( iv_key = `[[SetData]]` ir_val = box_value( lo_set_data ) ).
+ DATA(lo_set_data) = zcl_mjs_val=>array_val( VALUE #( ) ).
+ 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.
@@ -2241,7 +2073,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).
@@ -2250,13 +2082,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
@@ -2270,26 +2102,26 @@ 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).
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.
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 ).
@@ -2317,14 +2149,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( 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.
@@ -2337,7 +2169,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 ).
@@ -2350,7 +2182,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 +2208,7 @@ CLASS zcl_mjs IMPLEMENTATION.
ENDLOOP.
WHEN OTHERS.
- rs_val = undefined_val( ).
+ rs_val = zcl_mjs_val=>undefined_val( ).
ENDCASE.
ENDMETHOD.
@@ -2387,16 +2219,16 @@ 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 = 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.
@@ -2411,19 +2243,19 @@ 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 = 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,26 +2273,26 @@ 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 ).
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 = 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.
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.
@@ -2473,7 +2305,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.
@@ -2485,10 +2317,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 .
@@ -2510,23 +2342,23 @@ 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 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
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.
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`.
@@ -2536,16 +2368,16 @@ 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 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,26 +2386,26 @@ 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.
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 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.
@@ -2591,12 +2423,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.
@@ -2610,7 +2442,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.
@@ -2619,9 +2451,9 @@ 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 = 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.
@@ -2638,41 +2470,41 @@ 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 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
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.
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.
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 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.
@@ -2688,16 +2520,16 @@ 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 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 +2538,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 +2547,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 +2557,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.
@@ -2743,11 +2575,11 @@ 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.
- 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 +2589,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( 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.
@@ -2772,434 +2604,16 @@ CLASS zcl_mjs IMPLEMENTATION.
iv_error = |TypeError: { iv_method } is not a function|.
ENDCASE.
WHEN 2.
- CASE iv_method.
- WHEN `toUpperCase`.
- rs_val = string_val( to_upper( is_obj-str ) ).
- WHEN `toLowerCase`.
- rs_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_pos) = 0.
- IF lines( it_args ) >= 2.
- READ TABLE it_args INDEX 2 INTO ls_sw2.
- lv_sw_pos = 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 = bool_val( abap_true ).
- ELSEIF lv_sw_pos + strlen( lv_sw_search ) > strlen( is_obj-str ).
- rs_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 ).
- ELSE.
- rs_val = bool_val( abap_false ).
- ENDIF.
- ELSE.
- rs_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_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 ).
- 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 = bool_val( abap_true ).
- ELSEIF lv_ew_len < strlen( lv_ew_search ).
- rs_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 ).
- ELSE.
- rs_val = bool_val( abap_false ).
- ENDIF.
- ELSE.
- rs_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 ).
- 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 ).
- ELSE.
- rs_val = string_val( `` ).
- ENDIF.
- ELSE.
- rs_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 ).
- FIND lv_search IN is_obj-str MATCH OFFSET DATA(lv_offset).
- IF sy-subrc = 0.
- rs_val = number_val( CONV f( lv_offset ) ).
- ELSE.
- rs_val = number_val( -1 ).
- ENDIF.
- ELSE.
- rs_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_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 ).
- 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 = number_val( CONV f( lv_lio_res ) ).
- ELSE.
- rs_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 = to_number( ls_ss1 ).
- IF lines( it_args ) >= 2.
- READ TABLE it_args INDEX 2 INTO ls_ss2.
- lv_end = 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 = string_val( lv_sub_tmp ).
- ELSE.
- rs_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 = 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 = to_number( ls_sub2 ).
- IF lv_sub_len <= 0.
- rs_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 = string_val( lv_substr_res ).
- ELSE.
- rs_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 = 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 = number_val( CONV f( lv_code ) ).
- ELSE.
- rs_val = number_val( 0 ).
- ENDIF.
- ELSE.
- rs_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) = 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 = string_val( lv_rxout ).
- ELSE.
- " String first argument
- DATA(lv_rep_from) = to_string( ls_rep1 ).
- IF strlen( lv_rep_from ) = 0.
- rs_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 = string_val( lv_rep_res ).
- ELSE.
- rs_val = string_val( is_obj-str ).
- ENDIF.
- ENDIF.
- ENDIF.
- ELSE.
- rs_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 = 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 = 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_limit) = 2147483647. " max i
- IF lines( it_args ) >= 2.
- lv_spl_limit = 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_arr.
- 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( box_value( 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_arr.
- CREATE OBJECT lo_spl_def.
- lo_spl_def->push( 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.
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.
@@ -3208,14 +2622,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 +2716,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 +2731,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 +2740,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 +2749,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 +2759,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 +2835,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 +2878,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.
@@ -3475,10 +2889,10 @@ 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( box_value( ls_v ) ).
+ lo_arr->push( zcl_mjs_val=>box_value( ls_v ) ).
ENDLOOP.
rs_val-type = 7.
rs_val-arr = lo_arr.
@@ -3526,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 = 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) = 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) = 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.
diff --git a/src/zcl_mjs_val.clas.abap b/src/zcl_mjs_val.clas.abap
new file mode 100644
index 0000000..be31c20
--- /dev/null
+++ b/src/zcl_mjs_val.clas.abap
@@ -0,0 +1,171 @@
+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 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
+ 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 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.
+ 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..92b1159
--- /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
+
+
+
+
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.
]