comparison src/vim9compile.c @ 24357:108a6e2497f6 v8.2.2719

patch 8.2.2719: Vim9: appending to dict item doesn't work in a :def function Commit: https://github.com/vim/vim/commit/e42939af87be3adad8c08ceb454e3a31114d7165 Author: Bram Moolenaar <Bram@vim.org> Date: Mon Apr 5 17:11:17 2021 +0200 patch 8.2.2719: Vim9: appending to dict item doesn't work in a :def function Problem: Vim9: appending to dict item doesn't work in a :def function. Solution: Implement assignment with operator on indexed item.
author Bram Moolenaar <Bram@vim.org>
date Mon, 05 Apr 2021 17:15:06 +0200
parents 236e9ebdb30e
children f76398d79c2e
comparison
equal deleted inserted replaced
24356:03088264506d 24357:108a6e2497f6
2645 int i; 2645 int i;
2646 2646
2647 for (i = 0; i < ppconst->pp_used; ++i) 2647 for (i = 0; i < ppconst->pp_used; ++i)
2648 clear_tv(&ppconst->pp_tv[i]); 2648 clear_tv(&ppconst->pp_tv[i]);
2649 ppconst->pp_used = 0; 2649 ppconst->pp_used = 0;
2650 }
2651
2652 /*
2653 * Compile getting a member from a list/dict/string/blob. Stack has the
2654 * indexable value and the index.
2655 */
2656 static int
2657 compile_member(int is_slice, cctx_T *cctx)
2658 {
2659 type_T **typep;
2660 garray_T *stack = &cctx->ctx_type_stack;
2661 vartype_T vtype;
2662 type_T *valtype;
2663
2664 // We can index a list and a dict. If we don't know the type
2665 // we can use the index value type.
2666 // TODO: If we don't know use an instruction to figure it out at
2667 // runtime.
2668 typep = ((type_T **)stack->ga_data) + stack->ga_len
2669 - (is_slice ? 3 : 2);
2670 vtype = (*typep)->tt_type;
2671 valtype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
2672 // If the index is a string, the variable must be a Dict.
2673 if (*typep == &t_any && valtype == &t_string)
2674 vtype = VAR_DICT;
2675 if (vtype == VAR_STRING || vtype == VAR_LIST || vtype == VAR_BLOB)
2676 {
2677 if (need_type(valtype, &t_number, -1, 0, cctx, FALSE, FALSE) == FAIL)
2678 return FAIL;
2679 if (is_slice)
2680 {
2681 valtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
2682 if (need_type(valtype, &t_number, -2, 0, cctx,
2683 FALSE, FALSE) == FAIL)
2684 return FAIL;
2685 }
2686 }
2687
2688 if (vtype == VAR_DICT)
2689 {
2690 if (is_slice)
2691 {
2692 emsg(_(e_cannot_slice_dictionary));
2693 return FAIL;
2694 }
2695 if ((*typep)->tt_type == VAR_DICT)
2696 {
2697 *typep = (*typep)->tt_member;
2698 if (*typep == &t_unknown)
2699 // empty dict was used
2700 *typep = &t_any;
2701 }
2702 else
2703 {
2704 if (need_type(*typep, &t_dict_any, -2, 0, cctx,
2705 FALSE, FALSE) == FAIL)
2706 return FAIL;
2707 *typep = &t_any;
2708 }
2709 if (may_generate_2STRING(-1, cctx) == FAIL)
2710 return FAIL;
2711 if (generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL)
2712 return FAIL;
2713 }
2714 else if (vtype == VAR_STRING)
2715 {
2716 *typep = &t_string;
2717 if ((is_slice
2718 ? generate_instr_drop(cctx, ISN_STRSLICE, 2)
2719 : generate_instr_drop(cctx, ISN_STRINDEX, 1)) == FAIL)
2720 return FAIL;
2721 }
2722 else if (vtype == VAR_BLOB)
2723 {
2724 emsg("Sorry, blob index and slice not implemented yet");
2725 return FAIL;
2726 }
2727 else if (vtype == VAR_LIST || *typep == &t_any)
2728 {
2729 if (is_slice)
2730 {
2731 if (generate_instr_drop(cctx,
2732 vtype == VAR_LIST ? ISN_LISTSLICE : ISN_ANYSLICE,
2733 2) == FAIL)
2734 return FAIL;
2735 }
2736 else
2737 {
2738 if ((*typep)->tt_type == VAR_LIST)
2739 {
2740 *typep = (*typep)->tt_member;
2741 if (*typep == &t_unknown)
2742 // empty list was used
2743 *typep = &t_any;
2744 }
2745 if (generate_instr_drop(cctx,
2746 vtype == VAR_LIST ? ISN_LISTINDEX : ISN_ANYINDEX, 1) == FAIL)
2747 return FAIL;
2748 }
2749 }
2750 else
2751 {
2752 emsg(_(e_string_list_dict_or_blob_required));
2753 return FAIL;
2754 }
2755 return OK;
2650 } 2756 }
2651 2757
2652 /* 2758 /*
2653 * Generate an instruction to load script-local variable "name", without the 2759 * Generate an instruction to load script-local variable "name", without the
2654 * leading "s:". 2760 * leading "s:".
3932 return FAIL; 4038 return FAIL;
3933 } 4039 }
3934 } 4040 }
3935 else if (**arg == '[') 4041 else if (**arg == '[')
3936 { 4042 {
3937 garray_T *stack = &cctx->ctx_type_stack;
3938 type_T **typep;
3939 type_T *valtype;
3940 vartype_T vtype;
3941 int is_slice = FALSE; 4043 int is_slice = FALSE;
3942 4044
3943 // list index: list[123] 4045 // list index: list[123]
3944 // dict member: dict[key] 4046 // dict member: dict[key]
3945 // string index: text[123] 4047 // string index: text[123]
4002 emsg(_(e_missbrac)); 4104 emsg(_(e_missbrac));
4003 return FAIL; 4105 return FAIL;
4004 } 4106 }
4005 *arg = *arg + 1; 4107 *arg = *arg + 1;
4006 4108
4007 // We can index a list and a dict. If we don't know the type 4109 if (compile_member(is_slice, cctx) == FAIL)
4008 // we can use the index value type.
4009 // TODO: If we don't know use an instruction to figure it out at
4010 // runtime.
4011 typep = ((type_T **)stack->ga_data) + stack->ga_len
4012 - (is_slice ? 3 : 2);
4013 vtype = (*typep)->tt_type;
4014 valtype = ((type_T **)stack->ga_data)[stack->ga_len - 1];
4015 // If the index is a string, the variable must be a Dict.
4016 if (*typep == &t_any && valtype == &t_string)
4017 vtype = VAR_DICT;
4018 if (vtype == VAR_STRING || vtype == VAR_LIST || vtype == VAR_BLOB)
4019 {
4020 if (need_type(valtype, &t_number, -1, 0, cctx,
4021 FALSE, FALSE) == FAIL)
4022 return FAIL;
4023 if (is_slice)
4024 {
4025 valtype = ((type_T **)stack->ga_data)[stack->ga_len - 2];
4026 if (need_type(valtype, &t_number, -2, 0, cctx,
4027 FALSE, FALSE) == FAIL)
4028 return FAIL;
4029 }
4030 }
4031
4032 if (vtype == VAR_DICT)
4033 {
4034 if (is_slice)
4035 {
4036 emsg(_(e_cannot_slice_dictionary));
4037 return FAIL;
4038 }
4039 if ((*typep)->tt_type == VAR_DICT)
4040 {
4041 *typep = (*typep)->tt_member;
4042 if (*typep == &t_unknown)
4043 // empty dict was used
4044 *typep = &t_any;
4045 }
4046 else
4047 {
4048 if (need_type(*typep, &t_dict_any, -2, 0, cctx,
4049 FALSE, FALSE) == FAIL)
4050 return FAIL;
4051 *typep = &t_any;
4052 }
4053 if (may_generate_2STRING(-1, cctx) == FAIL)
4054 return FAIL;
4055 if (generate_instr_drop(cctx, ISN_MEMBER, 1) == FAIL)
4056 return FAIL;
4057 }
4058 else if (vtype == VAR_STRING)
4059 {
4060 *typep = &t_string;
4061 if ((is_slice
4062 ? generate_instr_drop(cctx, ISN_STRSLICE, 2)
4063 : generate_instr_drop(cctx, ISN_STRINDEX, 1)) == FAIL)
4064 return FAIL;
4065 }
4066 else if (vtype == VAR_BLOB)
4067 {
4068 emsg("Sorry, blob index and slice not implemented yet");
4069 return FAIL; 4110 return FAIL;
4070 }
4071 else if (vtype == VAR_LIST || *typep == &t_any)
4072 {
4073 if (is_slice)
4074 {
4075 if (generate_instr_drop(cctx,
4076 vtype == VAR_LIST ? ISN_LISTSLICE : ISN_ANYSLICE,
4077 2) == FAIL)
4078 return FAIL;
4079 }
4080 else
4081 {
4082 if ((*typep)->tt_type == VAR_LIST)
4083 {
4084 *typep = (*typep)->tt_member;
4085 if (*typep == &t_unknown)
4086 // empty list was used
4087 *typep = &t_any;
4088 }
4089 if (generate_instr_drop(cctx,
4090 vtype == VAR_LIST ? ISN_LISTINDEX : ISN_ANYINDEX,
4091 1) == FAIL)
4092 return FAIL;
4093 }
4094 }
4095 else
4096 {
4097 emsg(_(e_string_list_dict_or_blob_required));
4098 return FAIL;
4099 }
4100 } 4111 }
4101 else if (*p == '.' && p[1] != '.') 4112 else if (*p == '.' && p[1] != '.')
4102 { 4113 {
4103 // dictionary member: dict.name 4114 // dictionary member: dict.name
4104 if (generate_ppconst(cctx, ppconst) == FAIL) 4115 if (generate_ppconst(cctx, ppconst) == FAIL)
5903 } 5914 }
5904 else if (lhs->lhs_lvar != NULL) 5915 else if (lhs->lhs_lvar != NULL)
5905 lhs->lhs_type = lhs->lhs_lvar->lv_type; 5916 lhs->lhs_type = lhs->lhs_lvar->lv_type;
5906 } 5917 }
5907 5918
5908 if (oplen == 3 && !heredoc && lhs->lhs_dest != dest_global 5919 if (oplen == 3 && !heredoc
5909 && lhs->lhs_type->tt_type != VAR_STRING 5920 && lhs->lhs_dest != dest_global
5910 && lhs->lhs_type->tt_type != VAR_ANY) 5921 && !lhs->lhs_has_index
5922 && lhs->lhs_type->tt_type != VAR_STRING
5923 && lhs->lhs_type->tt_type != VAR_ANY)
5911 { 5924 {
5912 emsg(_(e_can_only_concatenate_to_string)); 5925 emsg(_(e_can_only_concatenate_to_string));
5913 return FAIL; 5926 return FAIL;
5914 } 5927 }
5915 5928
5991 } 6004 }
5992 return OK; 6005 return OK;
5993 } 6006 }
5994 6007
5995 /* 6008 /*
6009 * For an assignment with an index, compile the "idx" in "var[idx]" or "key" in
6010 * "var.key".
6011 */
6012 static int
6013 compile_assign_index(
6014 char_u *var_start,
6015 lhs_T *lhs,
6016 int is_assign,
6017 int *range,
6018 cctx_T *cctx)
6019 {
6020 size_t varlen = lhs->lhs_varlen;
6021 char_u *p;
6022 int r = OK;
6023
6024 p = var_start + varlen;
6025 if (*p == '[')
6026 {
6027 p = skipwhite(p + 1);
6028 r = compile_expr0(&p, cctx);
6029
6030 if (r == OK && *skipwhite(p) == ':')
6031 {
6032 // unlet var[idx : idx]
6033 if (is_assign)
6034 {
6035 semsg(_(e_cannot_use_range_with_assignment_str), p);
6036 return FAIL;
6037 }
6038 *range = TRUE;
6039 p = skipwhite(p);
6040 if (!IS_WHITE_OR_NUL(p[-1]) || !IS_WHITE_OR_NUL(p[1]))
6041 {
6042 semsg(_(e_white_space_required_before_and_after_str_at_str),
6043 ":", p);
6044 return FAIL;
6045 }
6046 p = skipwhite(p + 1);
6047 r = compile_expr0(&p, cctx);
6048 }
6049
6050 if (r == OK && *skipwhite(p) != ']')
6051 {
6052 // this should not happen
6053 emsg(_(e_missbrac));
6054 r = FAIL;
6055 }
6056 }
6057 else // if (*p == '.')
6058 {
6059 char_u *key_end = to_name_end(p + 1, TRUE);
6060 char_u *key = vim_strnsave(p + 1, key_end - p - 1);
6061
6062 r = generate_PUSHS(cctx, key);
6063 }
6064 return r;
6065 }
6066
6067 /*
5996 * Assignment to a list or dict member, or ":unlet" for the item, using the 6068 * Assignment to a list or dict member, or ":unlet" for the item, using the
5997 * information in "lhs". 6069 * information in "lhs".
5998 * Returns OK or FAIL. 6070 * Returns OK or FAIL.
5999 */ 6071 */
6000 static int 6072 static int
6004 int is_assign, 6076 int is_assign,
6005 type_T *rhs_type, 6077 type_T *rhs_type,
6006 cctx_T *cctx) 6078 cctx_T *cctx)
6007 { 6079 {
6008 char_u *p; 6080 char_u *p;
6009 int r;
6010 vartype_T dest_type; 6081 vartype_T dest_type;
6011 size_t varlen = lhs->lhs_varlen; 6082 size_t varlen = lhs->lhs_varlen;
6012 garray_T *stack = &cctx->ctx_type_stack; 6083 garray_T *stack = &cctx->ctx_type_stack;
6013 int range = FALSE; 6084 int range = FALSE;
6014 6085
6015 // Compile the "idx" in "var[idx]" or "key" in "var.key". 6086 if (compile_assign_index(var_start, lhs, is_assign, &range, cctx) == FAIL)
6016 p = var_start + varlen;
6017 if (*p == '[')
6018 {
6019 p = skipwhite(p + 1);
6020 r = compile_expr0(&p, cctx);
6021
6022 if (r == OK && *skipwhite(p) == ':')
6023 {
6024 // unlet var[idx : idx]
6025 if (is_assign)
6026 {
6027 semsg(_(e_cannot_use_range_with_assignment_str), p);
6028 return FAIL;
6029 }
6030 range = TRUE;
6031 p = skipwhite(p);
6032 if (!IS_WHITE_OR_NUL(p[-1]) || !IS_WHITE_OR_NUL(p[1]))
6033 {
6034 semsg(_(e_white_space_required_before_and_after_str_at_str),
6035 ":", p);
6036 return FAIL;
6037 }
6038 p = skipwhite(p + 1);
6039 r = compile_expr0(&p, cctx);
6040 }
6041
6042 if (r == OK && *skipwhite(p) != ']')
6043 {
6044 // this should not happen
6045 emsg(_(e_missbrac));
6046 r = FAIL;
6047 }
6048 }
6049 else // if (*p == '.')
6050 {
6051 char_u *key_end = to_name_end(p + 1, TRUE);
6052 char_u *key = vim_strnsave(p + 1, key_end - p - 1);
6053
6054 r = generate_PUSHS(cctx, key);
6055 }
6056 if (r == FAIL)
6057 return FAIL; 6087 return FAIL;
6058 6088
6059 if (lhs->lhs_type == &t_any) 6089 if (lhs->lhs_type == &t_any)
6060 { 6090 {
6061 // Index on variable of unknown type: check at runtime. 6091 // Index on variable of unknown type: check at runtime.
6328 generate_loadvar(cctx, lhs.lhs_dest, lhs.lhs_name, 6358 generate_loadvar(cctx, lhs.lhs_dest, lhs.lhs_name,
6329 lhs.lhs_lvar, lhs.lhs_type); 6359 lhs.lhs_lvar, lhs.lhs_type);
6330 6360
6331 if (lhs.lhs_has_index) 6361 if (lhs.lhs_has_index)
6332 { 6362 {
6333 // TODO: get member from list or dict 6363 int range = FALSE;
6334 emsg("Index with operation not supported yet"); 6364
6335 goto theend; 6365 // Get member from list or dict. First compile the
6366 // index value.
6367 if (compile_assign_index(var_start, &lhs,
6368 TRUE, &range, cctx) == FAIL)
6369 goto theend;
6370
6371 // Get the member.
6372 if (compile_member(FALSE, cctx) == FAIL)
6373 goto theend;
6336 } 6374 }
6337 } 6375 }
6338 6376
6339 // Compile the expression. Temporarily hide the new local 6377 // Compile the expression. Temporarily hide the new local
6340 // variable here, it is not available to this expression. 6378 // variable here, it is not available to this expression.