Mercurial > vim
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. |