Mercurial > vim
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 /* |