comparison src/vim9compile.c @ 20324:23188ef99fc2 v8.2.0717

patch 8.2.0717: Vim9: postponed constant expressions does not scale Commit: https://github.com/vim/vim/commit/7d131b071539e73e4f8a1e6ffbb4d7bfc69a57ec Author: Bram Moolenaar <Bram@vim.org> Date: Fri May 8 19:10:34 2020 +0200 patch 8.2.0717: Vim9: postponed constant expressions does not scale Problem: Vim9: postponed constant expressions does not scale. Solution: Add a structure to pass around postponed constants.
author Bram Moolenaar <Bram@vim.org>
date Fri, 08 May 2020 19:15:03 +0200
parents a3e78893a90b
children 445c2b2ea44b
comparison
equal deleted inserted replaced
20323:ee129fd509b1 20324:23188ef99fc2
1035 RETURN_OK_IF_SKIP(cctx); 1035 RETURN_OK_IF_SKIP(cctx);
1036 if ((isn = generate_instr_type(cctx, ISN_PUSHFUNC, type)) == NULL) 1036 if ((isn = generate_instr_type(cctx, ISN_PUSHFUNC, type)) == NULL)
1037 return FAIL; 1037 return FAIL;
1038 isn->isn_arg.string = name; 1038 isn->isn_arg.string = name;
1039 1039
1040 return OK;
1041 }
1042
1043 /*
1044 * Generate a PUSH instruction for "tv".
1045 * "tv" will be consumed or cleared. "tv" may be NULL;
1046 */
1047 static int
1048 generate_tv_PUSH(cctx_T *cctx, typval_T *tv)
1049 {
1050 if (tv != NULL)
1051 {
1052 switch (tv->v_type)
1053 {
1054 case VAR_UNKNOWN:
1055 break;
1056 case VAR_BOOL:
1057 generate_PUSHBOOL(cctx, tv->vval.v_number);
1058 break;
1059 case VAR_SPECIAL:
1060 generate_PUSHSPEC(cctx, tv->vval.v_number);
1061 break;
1062 case VAR_NUMBER:
1063 generate_PUSHNR(cctx, tv->vval.v_number);
1064 break;
1065 #ifdef FEAT_FLOAT
1066 case VAR_FLOAT:
1067 generate_PUSHF(cctx, tv->vval.v_float);
1068 break;
1069 #endif
1070 case VAR_BLOB:
1071 generate_PUSHBLOB(cctx, tv->vval.v_blob);
1072 tv->vval.v_blob = NULL;
1073 break;
1074 case VAR_STRING:
1075 generate_PUSHS(cctx, tv->vval.v_string);
1076 tv->vval.v_string = NULL;
1077 break;
1078 default:
1079 iemsg("constant type not supported");
1080 clear_tv(tv);
1081 return FAIL;
1082 }
1083 tv->v_type = VAR_UNKNOWN;
1084 }
1085 return OK; 1040 return OK;
1086 } 1041 }
1087 1042
1088 /* 1043 /*
1089 * Generate an ISN_STORE instruction. 1044 * Generate an ISN_STORE instruction.
3669 } 3624 }
3670 } 3625 }
3671 return OK; 3626 return OK;
3672 } 3627 }
3673 3628
3629 // Structure passed between the compile_expr* functions to keep track of
3630 // constants that have been parsed but for which no code was produced yet. If
3631 // possible expressions on these constants are applied at compile time. If
3632 // that is not possible, the code to push the constants needs to be generated
3633 // before other instructions.
3634 typedef struct {
3635 typval_T pp_tv[10]; // stack of ppconst constants
3636 int pp_used; // active entries in pp_tv[]
3637 } ppconst_T;
3638
3639 /*
3640 * Generate a PUSH instruction for "tv".
3641 * "tv" will be consumed or cleared.
3642 * Nothing happens if "tv" is NULL or of type VAR_UNKNOWN;
3643 */
3644 static int
3645 generate_tv_PUSH(cctx_T *cctx, typval_T *tv)
3646 {
3647 if (tv != NULL)
3648 {
3649 switch (tv->v_type)
3650 {
3651 case VAR_UNKNOWN:
3652 break;
3653 case VAR_BOOL:
3654 generate_PUSHBOOL(cctx, tv->vval.v_number);
3655 break;
3656 case VAR_SPECIAL:
3657 generate_PUSHSPEC(cctx, tv->vval.v_number);
3658 break;
3659 case VAR_NUMBER:
3660 generate_PUSHNR(cctx, tv->vval.v_number);
3661 break;
3662 #ifdef FEAT_FLOAT
3663 case VAR_FLOAT:
3664 generate_PUSHF(cctx, tv->vval.v_float);
3665 break;
3666 #endif
3667 case VAR_BLOB:
3668 generate_PUSHBLOB(cctx, tv->vval.v_blob);
3669 tv->vval.v_blob = NULL;
3670 break;
3671 case VAR_STRING:
3672 generate_PUSHS(cctx, tv->vval.v_string);
3673 tv->vval.v_string = NULL;
3674 break;
3675 default:
3676 iemsg("constant type not supported");
3677 clear_tv(tv);
3678 return FAIL;
3679 }
3680 tv->v_type = VAR_UNKNOWN;
3681 }
3682 return OK;
3683 }
3684
3685 /*
3686 * Generate code for any ppconst entries.
3687 */
3688 static int
3689 generate_ppconst(cctx_T *cctx, ppconst_T *ppconst)
3690 {
3691 int i;
3692 int ret = OK;
3693
3694 for (i = 0; i < ppconst->pp_used; ++i)
3695 if (generate_tv_PUSH(cctx, &ppconst->pp_tv[i]) == FAIL)
3696 ret = FAIL;
3697 ppconst->pp_used = 0;
3698 return ret;
3699 }
3700
3701 /*
3702 * Clear ppconst constants. Used when failing.
3703 */
3704 static void
3705 clear_ppconst(ppconst_T *ppconst)
3706 {
3707 int i;
3708
3709 for (i = 0; i < ppconst->pp_used; ++i)
3710 clear_tv(&ppconst->pp_tv[i]);
3711 ppconst->pp_used = 0;
3712 }
3713
3674 /* 3714 /*
3675 * Compile code to apply '-', '+' and '!'. 3715 * Compile code to apply '-', '+' and '!'.
3676 */ 3716 */
3677 static int 3717 static int
3678 compile_leader(cctx_T *cctx, char_u *start, char_u *end) 3718 compile_leader(cctx_T *cctx, char_u *start, char_u *end)
3726 compile_subscript( 3766 compile_subscript(
3727 char_u **arg, 3767 char_u **arg,
3728 cctx_T *cctx, 3768 cctx_T *cctx,
3729 char_u **start_leader, 3769 char_u **start_leader,
3730 char_u *end_leader, 3770 char_u *end_leader,
3731 typval_T *bef1_tv, 3771 ppconst_T *ppconst)
3732 typval_T *bef2_tv,
3733 typval_T *new_tv)
3734 { 3772 {
3735 for (;;) 3773 for (;;)
3736 { 3774 {
3737 if (**arg == '(') 3775 if (**arg == '(')
3738 { 3776 {
3739 garray_T *stack = &cctx->ctx_type_stack; 3777 garray_T *stack = &cctx->ctx_type_stack;
3740 type_T *type; 3778 type_T *type;
3741 int argcount = 0; 3779 int argcount = 0;
3742 3780
3743 if (generate_tv_PUSH(cctx, bef1_tv) == FAIL 3781 if (generate_ppconst(cctx, ppconst) == FAIL)
3744 || generate_tv_PUSH(cctx, bef2_tv) == FAIL
3745 || generate_tv_PUSH(cctx, new_tv) == FAIL)
3746 return FAIL; 3782 return FAIL;
3747 3783
3748 // funcref(arg) 3784 // funcref(arg)
3749 type = ((type_T **)stack->ga_data)[stack->ga_len - 1]; 3785 type = ((type_T **)stack->ga_data)[stack->ga_len - 1];
3750 3786
3756 } 3792 }
3757 else if (**arg == '-' && (*arg)[1] == '>') 3793 else if (**arg == '-' && (*arg)[1] == '>')
3758 { 3794 {
3759 char_u *p; 3795 char_u *p;
3760 3796
3761 if (generate_tv_PUSH(cctx, bef1_tv) == FAIL 3797 if (generate_ppconst(cctx, ppconst) == FAIL)
3762 || generate_tv_PUSH(cctx, bef2_tv) == FAIL
3763 || generate_tv_PUSH(cctx, new_tv) == FAIL)
3764 return FAIL; 3798 return FAIL;
3765 3799
3766 // something->method() 3800 // something->method()
3767 // Apply the '!', '-' and '+' first: 3801 // Apply the '!', '-' and '+' first:
3768 // -1.0->func() works like (-1.0)->func() 3802 // -1.0->func() works like (-1.0)->func()
3798 else if (**arg == '[') 3832 else if (**arg == '[')
3799 { 3833 {
3800 garray_T *stack; 3834 garray_T *stack;
3801 type_T **typep; 3835 type_T **typep;
3802 3836
3803 if (generate_tv_PUSH(cctx, bef1_tv) == FAIL 3837 if (generate_ppconst(cctx, ppconst) == FAIL)
3804 || generate_tv_PUSH(cctx, bef2_tv) == FAIL
3805 || generate_tv_PUSH(cctx, new_tv) == FAIL)
3806 return FAIL; 3838 return FAIL;
3807 3839
3808 // list index: list[123] 3840 // list index: list[123]
3809 // TODO: more arguments 3841 // TODO: more arguments
3810 // TODO: dict member dict['name'] 3842 // TODO: dict member dict['name']
3833 } 3865 }
3834 else if (**arg == '.' && (*arg)[1] != '.') 3866 else if (**arg == '.' && (*arg)[1] != '.')
3835 { 3867 {
3836 char_u *p; 3868 char_u *p;
3837 3869
3838 if (generate_tv_PUSH(cctx, bef1_tv) == FAIL 3870 if (generate_ppconst(cctx, ppconst) == FAIL)
3839 || generate_tv_PUSH(cctx, bef2_tv) == FAIL
3840 || generate_tv_PUSH(cctx, new_tv) == FAIL)
3841 return FAIL; 3871 return FAIL;
3842 3872
3843 ++*arg; 3873 ++*arg;
3844 p = *arg; 3874 p = *arg;
3845 // dictionary member: dict.name 3875 // dictionary member: dict.name
3869 3899
3870 /* 3900 /*
3871 * Compile an expression at "*arg" and add instructions to "cctx->ctx_instr". 3901 * Compile an expression at "*arg" and add instructions to "cctx->ctx_instr".
3872 * "arg" is advanced until after the expression, skipping white space. 3902 * "arg" is advanced until after the expression, skipping white space.
3873 * 3903 *
3874 * If the value is a constant "new_tv" will be set. 3904 * If the value is a constant "ppconst->pp_ret" will be set.
3875 * Before instructions are generated, any "bef_tv" will generated. 3905 * Before instructions are generated, any values in "ppconst" will generated.
3876 * 3906 *
3877 * This is the compiling equivalent of eval1(), eval2(), etc. 3907 * This is the compiling equivalent of eval1(), eval2(), etc.
3878 */ 3908 */
3879 3909
3880 /* 3910 /*
3903 */ 3933 */
3904 static int 3934 static int
3905 compile_expr7( 3935 compile_expr7(
3906 char_u **arg, 3936 char_u **arg,
3907 cctx_T *cctx, 3937 cctx_T *cctx,
3908 typval_T *bef1_tv, 3938 ppconst_T *ppconst)
3909 typval_T *bef2_tv, 3939 {
3910 typval_T *new_tv)
3911 {
3912 typval_T rettv;
3913 char_u *start_leader, *end_leader; 3940 char_u *start_leader, *end_leader;
3914 int ret = OK; 3941 int ret = OK;
3942 typval_T *rettv = &ppconst->pp_tv[ppconst->pp_used];
3915 3943
3916 /* 3944 /*
3917 * Skip '!', '-' and '+' characters. They are handled later. 3945 * Skip '!', '-' and '+' characters. They are handled later.
3918 */ 3946 */
3919 start_leader = *arg; 3947 start_leader = *arg;
3920 while (**arg == '!' || **arg == '-' || **arg == '+') 3948 while (**arg == '!' || **arg == '-' || **arg == '+')
3921 *arg = skipwhite(*arg + 1); 3949 *arg = skipwhite(*arg + 1);
3922 end_leader = *arg; 3950 end_leader = *arg;
3923 3951
3924 rettv.v_type = VAR_UNKNOWN; 3952 rettv->v_type = VAR_UNKNOWN;
3925 switch (**arg) 3953 switch (**arg)
3926 { 3954 {
3927 /* 3955 /*
3928 * Number constant. 3956 * Number constant.
3929 */ 3957 */
3935 case '5': 3963 case '5':
3936 case '6': 3964 case '6':
3937 case '7': 3965 case '7':
3938 case '8': 3966 case '8':
3939 case '9': 3967 case '9':
3940 case '.': if (get_number_tv(arg, &rettv, TRUE, FALSE) == FAIL) 3968 case '.': if (get_number_tv(arg, rettv, TRUE, FALSE) == FAIL)
3941 return FAIL; 3969 return FAIL;
3942 break; 3970 break;
3943 3971
3944 /* 3972 /*
3945 * String constant: "string". 3973 * String constant: "string".
3946 */ 3974 */
3947 case '"': if (get_string_tv(arg, &rettv, TRUE) == FAIL) 3975 case '"': if (get_string_tv(arg, rettv, TRUE) == FAIL)
3948 return FAIL; 3976 return FAIL;
3949 break; 3977 break;
3950 3978
3951 /* 3979 /*
3952 * Literal string constant: 'str''ing'. 3980 * Literal string constant: 'str''ing'.
3953 */ 3981 */
3954 case '\'': if (get_lit_string_tv(arg, &rettv, TRUE) == FAIL) 3982 case '\'': if (get_lit_string_tv(arg, rettv, TRUE) == FAIL)
3955 return FAIL; 3983 return FAIL;
3956 break; 3984 break;
3957 3985
3958 /* 3986 /*
3959 * Constant Vim variable. 3987 * Constant Vim variable.
3960 */ 3988 */
3961 case 'v': get_vim_constant(arg, &rettv); 3989 case 'v': get_vim_constant(arg, rettv);
3962 ret = NOTDONE; 3990 ret = NOTDONE;
3963 break; 3991 break;
3964 3992
3965 /* 3993 /*
3966 * List: [expr, expr] 3994 * List: [expr, expr]
4034 break; 4062 break;
4035 } 4063 }
4036 if (ret == FAIL) 4064 if (ret == FAIL)
4037 return FAIL; 4065 return FAIL;
4038 4066
4039 if (rettv.v_type != VAR_UNKNOWN) 4067 if (rettv->v_type != VAR_UNKNOWN)
4040 { 4068 {
4041 // apply the '!', '-' and '+' before the constant 4069 // apply the '!', '-' and '+' before the constant
4042 if (apply_leader(&rettv, start_leader, end_leader) == FAIL) 4070 if (apply_leader(rettv, start_leader, end_leader) == FAIL)
4043 { 4071 {
4044 clear_tv(&rettv); 4072 clear_tv(rettv);
4045 return FAIL; 4073 return FAIL;
4046 } 4074 }
4047 start_leader = end_leader; // don't apply again below 4075 start_leader = end_leader; // don't apply again below
4048 4076
4049 // A constant expression can possibly be handled compile time. 4077 // A constant expression can possibly be handled compile time, return
4050 *new_tv = rettv; 4078 // the value instead of generating code.
4079 ++ppconst->pp_used;
4051 } 4080 }
4052 else if (ret == NOTDONE) 4081 else if (ret == NOTDONE)
4053 { 4082 {
4054 char_u *p; 4083 char_u *p;
4055 int r; 4084 int r;
4056 4085
4057 if (generate_tv_PUSH(cctx, bef1_tv) == FAIL 4086 if (generate_ppconst(cctx, ppconst) == FAIL)
4058 || generate_tv_PUSH(cctx, bef2_tv) == FAIL)
4059 return FAIL; 4087 return FAIL;
4060 4088
4061 if (!eval_isnamec1(**arg)) 4089 if (!eval_isnamec1(**arg))
4062 { 4090 {
4063 semsg(_("E1015: Name expected: %s"), *arg); 4091 semsg(_("E1015: Name expected: %s"), *arg);
4075 } 4103 }
4076 4104
4077 // Handle following "[]", ".member", etc. 4105 // Handle following "[]", ".member", etc.
4078 // Then deal with prefixed '-', '+' and '!', if not done already. 4106 // Then deal with prefixed '-', '+' and '!', if not done already.
4079 if (compile_subscript(arg, cctx, &start_leader, end_leader, 4107 if (compile_subscript(arg, cctx, &start_leader, end_leader,
4080 bef1_tv, bef2_tv, new_tv) == FAIL 4108 ppconst) == FAIL
4081 || compile_leader(cctx, start_leader, end_leader) == FAIL) 4109 || compile_leader(cctx, start_leader, end_leader) == FAIL)
4082 { 4110 return FAIL;
4083 clear_tv(new_tv);
4084 return FAIL;
4085 }
4086 return OK; 4111 return OK;
4087 } 4112 }
4088 4113
4089 /* 4114 /*
4090 * * number multiplication 4115 * * number multiplication
4091 * / number division 4116 * / number division
4092 * % number modulo 4117 * % number modulo
4093 */ 4118 */
4094 static int 4119 static int
4095 compile_expr6( 4120 compile_expr6(
4096 char_u **arg, 4121 char_u **arg,
4097 cctx_T *cctx, 4122 cctx_T *cctx,
4098 typval_T *bef_tv, 4123 ppconst_T *ppconst)
4099 typval_T *new_tv)
4100 { 4124 {
4101 char_u *op; 4125 char_u *op;
4126 int ppconst_used = ppconst->pp_used;
4102 4127
4103 // get the first expression 4128 // get the first expression
4104 if (compile_expr7(arg, cctx, NULL, bef_tv, new_tv) == FAIL) 4129 if (compile_expr7(arg, cctx, ppconst) == FAIL)
4105 return FAIL; 4130 return FAIL;
4106 4131
4107 /* 4132 /*
4108 * Repeat computing, until no "*", "/" or "%" is following. 4133 * Repeat computing, until no "*", "/" or "%" is following.
4109 */ 4134 */
4110 for (;;) 4135 for (;;)
4111 { 4136 {
4112 typval_T tv2;
4113
4114 op = skipwhite(*arg); 4137 op = skipwhite(*arg);
4115 if (*op != '*' && *op != '/' && *op != '%') 4138 if (*op != '*' && *op != '/' && *op != '%')
4116 break; 4139 break;
4117 4140
4118 if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(op[1])) 4141 if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(op[1]))
4126 *arg = skipwhite(op + 1); 4149 *arg = skipwhite(op + 1);
4127 if (may_get_next_line(op + 1, arg, cctx) == FAIL) 4150 if (may_get_next_line(op + 1, arg, cctx) == FAIL)
4128 return FAIL; 4151 return FAIL;
4129 4152
4130 // get the second expression 4153 // get the second expression
4131 tv2.v_type = VAR_UNKNOWN; 4154 if (compile_expr7(arg, cctx, ppconst) == FAIL)
4132 if (compile_expr7(arg, cctx, bef_tv, new_tv, &tv2) == FAIL)
4133 return FAIL; 4155 return FAIL;
4134 if (new_tv->v_type == VAR_NUMBER && tv2.v_type == VAR_NUMBER) 4156
4135 { 4157 if (ppconst->pp_used == ppconst_used + 2
4158 && ppconst->pp_tv[ppconst_used].v_type == VAR_NUMBER
4159 && ppconst->pp_tv[ppconst_used + 1].v_type == VAR_NUMBER)
4160 {
4161 typval_T *tv1 = &ppconst->pp_tv[ppconst_used];
4162 typval_T *tv2 = &ppconst->pp_tv[ppconst_used + 1];
4136 varnumber_T res = 0; 4163 varnumber_T res = 0;
4137 4164
4138 // both are numbers: compute the result 4165 // both are numbers: compute the result
4139 switch (*op) 4166 switch (*op)
4140 { 4167 {
4141 case '*': res = new_tv->vval.v_number * tv2.vval.v_number; 4168 case '*': res = tv1->vval.v_number * tv2->vval.v_number;
4142 break; 4169 break;
4143 case '/': res = new_tv->vval.v_number / tv2.vval.v_number; 4170 case '/': res = tv1->vval.v_number / tv2->vval.v_number;
4144 break; 4171 break;
4145 case '%': res = new_tv->vval.v_number % tv2.vval.v_number; 4172 case '%': res = tv1->vval.v_number % tv2->vval.v_number;
4146 break; 4173 break;
4147 } 4174 }
4148 new_tv->vval.v_number = res; 4175 tv1->vval.v_number = res;
4176 --ppconst->pp_used;
4149 } 4177 }
4150 else 4178 else
4151 { 4179 {
4152 generate_tv_PUSH(cctx, new_tv); 4180 generate_ppconst(cctx, ppconst);
4153 generate_tv_PUSH(cctx, &tv2);
4154 generate_two_op(cctx, op); 4181 generate_two_op(cctx, op);
4155 } 4182 }
4156 } 4183 }
4157 4184
4158 return OK; 4185 return OK;
4164 * .. string concatenation 4191 * .. string concatenation
4165 */ 4192 */
4166 static int 4193 static int
4167 compile_expr5(char_u **arg, cctx_T *cctx) 4194 compile_expr5(char_u **arg, cctx_T *cctx)
4168 { 4195 {
4169 typval_T tv1;
4170 char_u *op; 4196 char_u *op;
4171 int oplen; 4197 int oplen;
4198 ppconst_T ppconst;
4199 int ppconst_used = 0;
4200
4201 CLEAR_FIELD(ppconst);
4172 4202
4173 // get the first variable 4203 // get the first variable
4174 tv1.v_type = VAR_UNKNOWN; 4204 if (compile_expr6(arg, cctx, &ppconst) == FAIL)
4175 if (compile_expr6(arg, cctx, NULL, &tv1) == FAIL) 4205 {
4176 return FAIL; 4206 clear_ppconst(&ppconst);
4207 return FAIL;
4208 }
4177 4209
4178 /* 4210 /*
4179 * Repeat computing, until no "+", "-" or ".." is following. 4211 * Repeat computing, until no "+", "-" or ".." is following.
4180 */ 4212 */
4181 for (;;) 4213 for (;;)
4182 { 4214 {
4183 typval_T tv2;
4184
4185 op = skipwhite(*arg); 4215 op = skipwhite(*arg);
4186 if (*op != '+' && *op != '-' && !(*op == '.' && (*(*arg + 1) == '.'))) 4216 if (*op != '+' && *op != '-' && !(*op == '.' && (*(*arg + 1) == '.')))
4187 break; 4217 break;
4188 oplen = (*op == '.' ? 2 : 1); 4218 oplen = (*op == '.' ? 2 : 1);
4189 4219
4190 if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(op[oplen])) 4220 if (!IS_WHITE_OR_NUL(**arg) || !IS_WHITE_OR_NUL(op[oplen]))
4191 { 4221 {
4192 char_u buf[3]; 4222 char_u buf[3];
4193 4223
4194 clear_tv(&tv1); 4224 clear_ppconst(&ppconst);
4195 vim_strncpy(buf, op, oplen); 4225 vim_strncpy(buf, op, oplen);
4196 semsg(_(e_white_both), buf); 4226 semsg(_(e_white_both), buf);
4197 return FAIL; 4227 return FAIL;
4198 } 4228 }
4199 4229
4200 *arg = skipwhite(op + oplen); 4230 *arg = skipwhite(op + oplen);
4201 if (may_get_next_line(op + oplen, arg, cctx) == FAIL) 4231 if (may_get_next_line(op + oplen, arg, cctx) == FAIL)
4202 { 4232 {
4203 clear_tv(&tv1); 4233 clear_ppconst(&ppconst);
4204 return FAIL; 4234 return FAIL;
4205 } 4235 }
4206 4236
4207 // get the second expression 4237 // get the second expression
4208 tv2.v_type = VAR_UNKNOWN; 4238 if (compile_expr6(arg, cctx, &ppconst) == FAIL)
4209 if (compile_expr6(arg, cctx, &tv1, &tv2) == FAIL) 4239 {
4210 { 4240 clear_ppconst(&ppconst);
4211 clear_tv(&tv1);
4212 return FAIL; 4241 return FAIL;
4213 } 4242 }
4214 4243
4215 if (*op == '+' && tv1.v_type == VAR_NUMBER && tv2.v_type == VAR_NUMBER) 4244 if (ppconst.pp_used == ppconst_used + 2
4216 { 4245 && (*op == '.'
4217 // add constant numbers 4246 ? (ppconst.pp_tv[ppconst_used].v_type == VAR_STRING
4218 tv1.vval.v_number = tv1.vval.v_number + tv2.vval.v_number; 4247 && ppconst.pp_tv[ppconst_used + 1].v_type == VAR_STRING)
4219 } 4248 : (ppconst.pp_tv[ppconst_used].v_type == VAR_NUMBER
4220 else if (*op == '-' && tv1.v_type == VAR_NUMBER 4249 && ppconst.pp_tv[ppconst_used + 1].v_type == VAR_NUMBER)))
4221 && tv2.v_type == VAR_NUMBER) 4250 {
4222 { 4251 typval_T *tv1 = &ppconst.pp_tv[ppconst_used];
4223 // subtract constant numbers 4252 typval_T *tv2 = &ppconst.pp_tv[ppconst_used + 1];
4224 tv1.vval.v_number = tv1.vval.v_number - tv2.vval.v_number; 4253
4225 } 4254 // concat/subtract/add constant numbers
4226 else if (*op == '.' && tv1.v_type == VAR_STRING 4255 if (*op == '+')
4227 && tv2.v_type == VAR_STRING) 4256 tv1->vval.v_number = tv1->vval.v_number + tv2->vval.v_number;
4228 { 4257 else if (*op == '-')
4229 // concatenate constant strings 4258 tv1->vval.v_number = tv1->vval.v_number - tv2->vval.v_number;
4230 char_u *s1 = tv1.vval.v_string; 4259 else
4231 char_u *s2 = tv2.vval.v_string; 4260 {
4232 size_t len1 = STRLEN(s1); 4261 // concatenate constant strings
4233 4262 char_u *s1 = tv1->vval.v_string;
4234 tv1.vval.v_string = alloc((int)(len1 + STRLEN(s2) + 1)); 4263 char_u *s2 = tv2->vval.v_string;
4235 if (tv1.vval.v_string == NULL) 4264 size_t len1 = STRLEN(s1);
4236 { 4265
4266 tv1->vval.v_string = alloc((int)(len1 + STRLEN(s2) + 1));
4267 if (tv1->vval.v_string == NULL)
4268 {
4269 clear_ppconst(&ppconst);
4270 return FAIL;
4271 }
4272 mch_memmove(tv1->vval.v_string, s1, len1);
4273 STRCPY(tv1->vval.v_string + len1, s2);
4237 vim_free(s1); 4274 vim_free(s1);
4238 vim_free(s2); 4275 vim_free(s2);
4239 return FAIL; 4276 }
4240 } 4277 --ppconst.pp_used;
4241 mch_memmove(tv1.vval.v_string, s1, len1);
4242 STRCPY(tv1.vval.v_string + len1, s2);
4243 vim_free(s1);
4244 vim_free(s2);
4245 } 4278 }
4246 else 4279 else
4247 { 4280 {
4248 generate_tv_PUSH(cctx, &tv1); 4281 generate_ppconst(cctx, &ppconst);
4249 generate_tv_PUSH(cctx, &tv2);
4250 if (*op == '.') 4282 if (*op == '.')
4251 { 4283 {
4252 if (may_generate_2STRING(-2, cctx) == FAIL 4284 if (may_generate_2STRING(-2, cctx) == FAIL
4253 || may_generate_2STRING(-1, cctx) == FAIL) 4285 || may_generate_2STRING(-1, cctx) == FAIL)
4286 {
4287 clear_ppconst(&ppconst);
4254 return FAIL; 4288 return FAIL;
4289 }
4255 generate_instr_drop(cctx, ISN_CONCAT, 1); 4290 generate_instr_drop(cctx, ISN_CONCAT, 1);
4256 } 4291 }
4257 else 4292 else
4258 generate_two_op(cctx, op); 4293 generate_two_op(cctx, op);
4259 } 4294 }
4260 } 4295 }
4261 4296
4262 // TODO: move to caller 4297 // TODO: move to caller
4263 generate_tv_PUSH(cctx, &tv1); 4298 generate_ppconst(cctx, &ppconst);
4264 4299
4265 return OK; 4300 return OK;
4266 } 4301 }
4267 4302
4268 /* 4303 /*