@@ -3673,8 +3673,154 @@ static cb_tree build_evaluate(cb_tree subject_list, cb_tree case_list) {
36733673 }
36743674}
36753675
3676+ int cb_literal_to_int_for_switch_label (struct cb_literal * lit , int * result ) {
3677+ const char * min_num_abs =
3678+ "2147483648" ; // -1 * (the minimum value of int of Java)
3679+ const char * max_num = "2147483647" ; // the maximum value of int of Java
3680+ const int len_boundary =
3681+ 10 ; // string length of min_num_abs (== string length of max_num)
3682+ if (lit -> size > len_boundary ) {
3683+ // the value of the literal is out of range
3684+ * result = 0 ;
3685+ return 0 ;
3686+ }
3687+
3688+ size_t i ;
3689+ const char * boundary = lit -> sign < 0 ? min_num_abs : max_num ;
3690+ if (lit -> size == len_boundary ) {
3691+ for (i = 0 ; i < len_boundary ; ++ i ) {
3692+ if (boundary [i ] < lit -> data [i ]) {
3693+ // the value of the literal is out of range
3694+ * result = 0 ;
3695+ return 0 ;
3696+ }
3697+ }
3698+ }
3699+
3700+ int ret = 0 ;
3701+ for (i = 0 ; i < lit -> size ; ++ i ) {
3702+ ret = ret * 10 + lit -> data [i ] - '0' ;
3703+ }
3704+ * result = 1 ;
3705+ return lit -> sign < 0 ? - ret : ret ;
3706+ }
3707+
3708+ // Determine a given label exists in the list of existing labels
3709+ // If a given label exists in the list, return 1. Otherwise return 0;
3710+ static int is_switch_label_duplicate (int label , const int * existing_label_list ,
3711+ int list_len ) {
3712+ int i = 0 ;
3713+ for (; i < list_len ; ++ i ) {
3714+ if (existing_label_list [i ] == label ) {
3715+ return 1 ;
3716+ }
3717+ }
3718+ return 0 ;
3719+ }
3720+
3721+ static cb_tree convert_evaluate_stmt_to_switch_stmt (cb_tree subject_list ,
3722+ cb_tree case_list ) {
3723+ cb_tree subjs ;
3724+ cb_tree whens ;
3725+ cb_tree objs ;
3726+
3727+ cb_tree case_tree = case_list ;
3728+ int when_count = 0 ;
3729+ int other_exists = 0 ;
3730+
3731+ // The length of subject_list must be 1
3732+ if (subject_list == NULL || CB_CHAIN (subject_list )) {
3733+ return NULL ;
3734+ }
3735+
3736+ // Determine if a given evaluate statement can be converted to a switch
3737+ // statement
3738+ int case_count = 0 ;
3739+ for (; case_tree ; case_tree = CB_CHAIN (case_tree ), ++ case_count ) {
3740+ whens = CB_VALUE (case_tree );
3741+ /* for each WHEN sequence */
3742+ int flag_other_exists = 1 ;
3743+ for (; whens ; whens = CB_CHAIN (whens )) {
3744+ for (subjs = subject_list , objs = CB_VALUE (whens ); subjs && objs ;
3745+ subjs = CB_CHAIN (subjs ), objs = CB_CHAIN (objs )) {
3746+ cb_tree subj = CB_VALUE (subjs );
3747+ cb_tree obj = CB_VALUE (objs );
3748+ if (!subj || CB_TREE_CATEGORY (subj ) != CB_CATEGORY_NUMERIC ) {
3749+ return NULL ;
3750+ }
3751+ if (obj ) {
3752+ if (CB_LIST_P (obj )) {
3753+ flag_other_exists = 0 ;
3754+ }
3755+ if (CB_STATEMENT_P (obj )) {
3756+ continue ;
3757+ }
3758+ if (CB_PAIR_P (obj )) {
3759+ // WHEN NOT
3760+ if (CB_PURPOSE_INT (obj )) {
3761+ return NULL ;
3762+ }
3763+ cb_tree when_target = CB_PAIR_Y (obj );
3764+ if (CB_PAIR_P (when_target )) {
3765+ cb_tree primary_target = CB_PAIR_X (when_target );
3766+ cb_tree thru_target = CB_PAIR_Y (when_target );
3767+ if (!CB_LITERAL_P (primary_target ) || thru_target ) {
3768+ return NULL ;
3769+ }
3770+ struct cb_literal * lit = CB_LITERAL (primary_target );
3771+ if (lit -> data == NULL || lit -> scale != 0 ) {
3772+ return NULL ;
3773+ }
3774+ ++ when_count ;
3775+ }
3776+ }
3777+ }
3778+ }
3779+ }
3780+ other_exists |= flag_other_exists ;
3781+ }
3782+ // Build Switch statement
3783+ int * cases = malloc (when_count * sizeof (int ));
3784+ int case_index = 0 ;
3785+ for (case_tree = case_list ; case_tree ; case_tree = CB_CHAIN (case_tree )) {
3786+ whens = CB_VALUE (case_tree );
3787+ /* for each WHEN sequence */
3788+ for (; whens ; whens = CB_CHAIN (whens )) {
3789+ for (objs = CB_VALUE (whens ); objs ; objs = CB_CHAIN (objs )) {
3790+ cb_tree obj = CB_VALUE (objs );
3791+ if (obj && CB_PAIR_P (obj )) {
3792+ cb_tree when_target = CB_PAIR_Y (obj );
3793+ struct cb_literal * primary_target =
3794+ CB_LITERAL (CB_PAIR_X (when_target ));
3795+ int result ;
3796+ int label =
3797+ cb_literal_to_int_for_switch_label (primary_target , & result );
3798+ // If calculating a switch label fails, the evaluate statement cannot
3799+ // be converted to switch statement
3800+ if (!result ) {
3801+ return NULL ;
3802+ }
3803+ // If a duplicate label is found, the evaluate statement cannot be
3804+ // converted to switch statement
3805+ if (is_switch_label_duplicate (label , cases , case_index )) {
3806+ return NULL ;
3807+ }
3808+ cases [case_index ++ ] = label ;
3809+ }
3810+ }
3811+ }
3812+ }
3813+ return cb_build_switch (CB_VALUE (subject_list ), case_list );
3814+ }
3815+
36763816void cb_emit_evaluate (cb_tree subject_list , cb_tree case_list ) {
3677- cb_emit (build_evaluate (subject_list , case_list ));
3817+ cb_tree switch_stmt =
3818+ convert_evaluate_stmt_to_switch_stmt (subject_list , case_list );
3819+ if (switch_stmt ) {
3820+ cb_emit (switch_stmt );
3821+ } else {
3822+ cb_emit (build_evaluate (subject_list , case_list ));
3823+ }
36783824}
36793825
36803826/*
0 commit comments