To: vim_dev@googlegroups.com Subject: Patch 8.2.2063 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2063 Problem: Vim9: only one level of indexing supported. Solution: Handle more than one index in an assignment. Files: src/vim9compile.c, src/errors.h, src/testdir/test_vim9_assign.vim *** ../vim-8.2.2062/src/vim9compile.c 2020-11-23 08:31:14.097789125 +0100 --- src/vim9compile.c 2020-11-28 18:11:22.207332958 +0100 *************** *** 4961,4966 **** --- 4961,4967 ---- dest_vimvar, dest_script, dest_reg, + dest_expr, } assign_dest_T; /* *************** *** 5013,5019 **** --- 5014,5045 ---- else generate_LOAD(cctx, ISN_LOAD, lvar->lv_idx, NULL, type); break; + case dest_expr: + // list or dict value should already be on the stack. + break; + } + } + + /* + * Skip over "[expr]" or ".member". + * Does not check for any errors. + */ + static char_u * + skip_index(char_u *start) + { + char_u *p = start; + + if (*p == '[') + { + p = skipwhite(p + 1); + (void)skip_expr(&p, NULL); + p = skipwhite(p); + if (*p == ']') + return p + 1; + return p; } + // if (*p == '.') + return to_name_end(p + 1, TRUE); } void *************** *** 5069,5074 **** --- 5095,5101 ---- int heredoc = FALSE; type_T *type = &t_any; type_T *member_type = &t_any; + type_T *rhs_type = &t_any; char_u *name = NULL; char_u *sp; int is_decl = cmdidx == CMD_let || cmdidx == CMD_var *************** *** 5157,5162 **** --- 5184,5191 ---- // TODO: check the length of a constant list here generate_CHECKLEN(cctx, semicolon ? var_count - 1 : var_count, semicolon); + if (stacktype->tt_member != NULL) + rhs_type = stacktype->tt_member; } } *************** *** 5467,5472 **** --- 5496,5502 ---- if (var_end > var_start + varlen) { // Something follows after the variable: "var[idx]" or "var.key". + // TODO: should we also handle "->func()" here? if (is_decl) { emsg(_(e_cannot_use_index_when_declaring_variable)); *************** *** 5475,5480 **** --- 5505,5531 ---- if (var_start[varlen] == '[' || var_start[varlen] == '.') { + char_u *after = var_start + varlen; + + // Only the last index is used below, if there are others + // before it generate code for the expression. Thus for + // "ll[1][2]" the expression is "ll[1]" and "[2]" is the index. + for (;;) + { + p = skip_index(after); + if (*p != '[' && *p != '.') + break; + after = p; + } + if (after > var_start + varlen) + { + varlen = after - var_start; + dest = dest_expr; + // We don't know the type before evaluating the expression, + // use "any" until then. + type = &t_any; + } + has_index = TRUE; if (type->tt_member == NULL) member_type = &t_any; *************** *** 5511,5517 **** } else if (oplen > 0) { - type_T *stacktype; int is_const = FALSE; // For "var = expr" evaluate the expression. --- 5562,5567 ---- *************** *** 5558,5575 **** return FAIL; } ! stacktype = stack->ga_len == 0 ? &t_void : ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (lvar != NULL && (is_decl || !has_type)) { ! if ((stacktype->tt_type == VAR_FUNC ! || stacktype->tt_type == VAR_PARTIAL) && var_wrong_func_name(name, TRUE)) goto theend; if (new_local && !has_type) { ! if (stacktype->tt_type == VAR_VOID) { emsg(_(e_cannot_use_void_value)); goto theend; --- 5608,5625 ---- return FAIL; } ! rhs_type = stack->ga_len == 0 ? &t_void : ((type_T **)stack->ga_data)[stack->ga_len - 1]; if (lvar != NULL && (is_decl || !has_type)) { ! if ((rhs_type->tt_type == VAR_FUNC ! || rhs_type->tt_type == VAR_PARTIAL) && var_wrong_func_name(name, TRUE)) goto theend; if (new_local && !has_type) { ! if (rhs_type->tt_type == VAR_VOID) { emsg(_(e_cannot_use_void_value)); goto theend; *************** *** 5578,5591 **** { // An empty list or dict has a &t_unknown member, // for a variable that implies &t_any. ! if (stacktype == &t_list_empty) lvar->lv_type = &t_list_any; ! else if (stacktype == &t_dict_empty) lvar->lv_type = &t_dict_any; ! else if (stacktype == &t_unknown) lvar->lv_type = &t_any; else ! lvar->lv_type = stacktype; } } else if (*op == '=') --- 5628,5641 ---- { // An empty list or dict has a &t_unknown member, // for a variable that implies &t_any. ! if (rhs_type == &t_list_empty) lvar->lv_type = &t_list_any; ! else if (rhs_type == &t_dict_empty) lvar->lv_type = &t_dict_any; ! else if (rhs_type == &t_unknown) lvar->lv_type = &t_any; else ! lvar->lv_type = rhs_type; } } else if (*op == '=') *************** *** 5595,5611 **** // without operator check type here, otherwise below if (has_index) { ! use_type = use_type->tt_member; ! if (use_type == NULL) // could be indexing "any" use_type = &t_any; } ! if (need_type(stacktype, use_type, -1, cctx, FALSE, is_const) == FAIL) goto theend; } } ! else if (*p != '=' && need_type(stacktype, member_type, -1, cctx, FALSE, FALSE) == FAIL) goto theend; } --- 5645,5661 ---- // without operator check type here, otherwise below if (has_index) { ! use_type = member_type; ! if (member_type == NULL) // could be indexing "any" use_type = &t_any; } ! if (need_type(rhs_type, use_type, -1, cctx, FALSE, is_const) == FAIL) goto theend; } } ! else if (*p != '=' && need_type(rhs_type, member_type, -1, cctx, FALSE, FALSE) == FAIL) goto theend; } *************** *** 5771,5777 **** // - value // - index // - variable ! generate_loadvar(cctx, dest, name, lvar, type); if (type->tt_type == VAR_LIST) { --- 5821,5851 ---- // - value // - index // - variable ! if (dest == dest_expr) ! { ! int c = var_start[varlen]; ! ! // Evaluate "ll[expr]" of "ll[expr][idx]" ! p = var_start; ! var_start[varlen] = NUL; ! if (compile_expr0(&p, cctx) == OK && p != var_start + varlen) ! { ! // this should not happen ! emsg(_(e_missbrac)); ! goto theend; ! } ! var_start[varlen] = c; ! ! type = stack->ga_len == 0 ? &t_void ! : ((type_T **)stack->ga_data)[stack->ga_len - 1]; ! // now we can properly check the type ! if (type->tt_member != NULL ! && need_type(rhs_type, type->tt_member, -2, cctx, ! FALSE, FALSE) == FAIL) ! goto theend; ! } ! else ! generate_loadvar(cctx, dest, name, lvar, type); if (type->tt_type == VAR_LIST) { *************** *** 5785,5791 **** } else { ! emsg(_(e_listreq)); goto theend; } } --- 5859,5865 ---- } else { ! emsg(_(e_indexable_type_required)); goto theend; } } *************** *** 5882,5887 **** --- 5956,5964 ---- generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL); } break; + case dest_expr: + // cannot happen + break; } } *** ../vim-8.2.2062/src/errors.h 2020-11-23 08:31:14.101789113 +0100 --- src/errors.h 2020-11-28 18:00:34.709736698 +0100 *************** *** 311,313 **** --- 311,315 ---- INIT(= N_("E1139: Missing matching bracket after dict key")); EXTERN char e_for_argument_must_be_sequence_of_lists[] INIT(= N_("E1140: For argument must be a sequence of lists")); + EXTERN char e_indexable_type_required[] + INIT(= N_("E1141: Indexable type required")); *** ../vim-8.2.2062/src/testdir/test_vim9_assign.vim 2020-11-16 22:11:39.625599176 +0100 --- src/testdir/test_vim9_assign.vim 2020-11-28 18:50:41.476298895 +0100 *************** *** 225,230 **** --- 225,302 ---- END enddef + def Test_assign_index() + # list of list + var l1: list + l1[0] = 123 + assert_equal([123], l1) + + var l2: list> + l2[0] = [] + l2[0][0] = 123 + assert_equal([[123]], l2) + + var l3: list>> + l3[0] = [] + l3[0][0] = [] + l3[0][0][0] = 123 + assert_equal([[[123]]], l3) + + var lines =<< trim END + var l3: list> + l3[0] = [] + l3[0][0] = [] + END + CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got list', 3) + + # dict of dict + var d1: dict + d1.one = 1 + assert_equal({one: 1}, d1) + + var d2: dict> + d2.one = {} + d2.one.two = 123 + assert_equal({one: {two: 123}}, d2) + + var d3: dict>> + d3.one = {} + d3.one.two = {} + d3.one.two.three = 123 + assert_equal({one: {two: {three: 123}}}, d3) + + lines =<< trim END + var d3: dict> + d3.one = {} + d3.one.two = {} + END + CheckDefFailure(lines, 'E1012: Type mismatch; expected number but got dict', 3) + + # list of dict + var ld: list> + ld[0] = {} + ld[0].one = 123 + assert_equal([{one: 123}], ld) + + lines =<< trim END + var ld: list> + ld[0] = [] + END + CheckDefFailure(lines, 'E1012: Type mismatch; expected dict but got list', 2) + + # dict of list + var dl: dict> + dl.one = [] + dl.one[0] = 123 + assert_equal({one: [123]}, dl) + + lines =<< trim END + var dl: dict> + dl.one = {} + END + CheckDefFailure(lines, 'E1012: Type mismatch; expected list but got dict', 2) + enddef + def Test_extend_list() var lines =<< trim END vim9script *** ../vim-8.2.2062/src/version.c 2020-11-28 14:43:23.950237798 +0100 --- src/version.c 2020-11-28 18:01:31.801550593 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2063, /**/ -- The question is: What do you do with your life? The wrong answer is: Become the richest guy in the graveyard. (billionaire and Oracle founder Larry Ellison) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///