To: vim_dev@googlegroups.com Subject: Patch 8.2.0350 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0350 Problem: Vim9: expression tests don't use recognized constants. Solution: Recognize "true" and "false" as constants. Make skipping work for assignment and expression evaluation. Files: src/vim9compile.c *** ../vim-8.2.0349/src/vim9compile.c 2020-03-02 22:53:28.460549750 +0100 --- src/vim9compile.c 2020-03-03 21:51:38.377388231 +0100 *************** *** 260,265 **** --- 260,268 ---- ///////////////////////////////////////////////////////////////////// // Following generate_ functions expect the caller to call ga_grow(). + #define RETURN_NULL_IF_SKIP(cctx) if (cctx->ctx_skip == TRUE) return NULL + #define RETURN_OK_IF_SKIP(cctx) if (cctx->ctx_skip == TRUE) return OK + /* * Generate an instruction without arguments. * Returns a pointer to the new instruction, NULL if failed. *************** *** 270,275 **** --- 273,279 ---- garray_T *instr = &cctx->ctx_instr; isn_T *isn; + RETURN_NULL_IF_SKIP(cctx); if (ga_grow(instr, 1) == FAIL) return NULL; isn = ((isn_T *)instr->ga_data) + instr->ga_len; *************** *** 290,295 **** --- 294,300 ---- { garray_T *stack = &cctx->ctx_type_stack; + RETURN_NULL_IF_SKIP(cctx); stack->ga_len -= drop; return generate_instr(cctx, isn_type); } *************** *** 364,369 **** --- 369,376 ---- vartype_T vartype; isn_T *isn; + RETURN_OK_IF_SKIP(cctx); + // Get the known type of the two items on the stack. If they are matching // use a type-specific instruction. Otherwise fall back to runtime type // checking. *************** *** 461,466 **** --- 468,475 ---- vartype_T type1; vartype_T type2; + RETURN_OK_IF_SKIP(cctx); + // Get the known type of the two items on the stack. If they are matching // use a type-specific instruction. Otherwise fall back to runtime type // checking. *************** *** 536,541 **** --- 545,551 ---- isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_2BOOL)) == NULL) return FAIL; isn->isn_arg.number = invert; *************** *** 552,557 **** --- 562,568 ---- isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_CHECKTYPE)) == NULL) return FAIL; isn->isn_arg.type.ct_type = vartype->tt_type; // TODO: whole type *************** *** 571,576 **** --- 582,588 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr_type(cctx, ISN_PUSHNR, &t_number)) == NULL) return FAIL; isn->isn_arg.number = number; *************** *** 586,591 **** --- 598,604 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr_type(cctx, ISN_PUSHBOOL, &t_bool)) == NULL) return FAIL; isn->isn_arg.number = number; *************** *** 601,606 **** --- 614,620 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr_type(cctx, ISN_PUSHSPEC, &t_special)) == NULL) return FAIL; isn->isn_arg.number = number; *************** *** 617,622 **** --- 631,637 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr_type(cctx, ISN_PUSHF, &t_float)) == NULL) return FAIL; isn->isn_arg.fnumber = fnumber; *************** *** 634,639 **** --- 649,655 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr_type(cctx, ISN_PUSHS, &t_string)) == NULL) return FAIL; isn->isn_arg.string = str; *************** *** 650,655 **** --- 666,672 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr_type(cctx, ISN_PUSHCHANNEL, &t_channel)) == NULL) return FAIL; isn->isn_arg.channel = channel; *************** *** 666,671 **** --- 683,689 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr_type(cctx, ISN_PUSHJOB, &t_channel)) == NULL) return FAIL; isn->isn_arg.job = job; *************** *** 682,687 **** --- 700,706 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr_type(cctx, ISN_PUSHBLOB, &t_blob)) == NULL) return FAIL; isn->isn_arg.blob = blob; *************** *** 698,703 **** --- 717,723 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr_type(cctx, ISN_PUSHFUNC, &t_func_void)) == NULL) return FAIL; isn->isn_arg.string = name; *************** *** 714,719 **** --- 734,740 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr_type(cctx, ISN_PUSHPARTIAL, &t_partial_any)) == NULL) return FAIL; *************** *** 730,735 **** --- 751,757 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr_drop(cctx, isn_type, 1)) == NULL) return FAIL; if (name != NULL) *************** *** 748,753 **** --- 770,776 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_STORENR)) == NULL) return FAIL; isn->isn_arg.storenr.str_idx = idx; *************** *** 764,769 **** --- 787,793 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_STOREOPT)) == NULL) return FAIL; isn->isn_arg.storeopt.so_name = vim_strsave(name); *************** *** 785,790 **** --- 809,815 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr_type(cctx, isn_type, type)) == NULL) return FAIL; if (name != NULL) *************** *** 807,812 **** --- 832,838 ---- // load v:var int vidx = find_vim_var(name); + RETURN_OK_IF_SKIP(cctx); if (vidx < 0) { if (error) *************** *** 831,836 **** --- 857,863 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if (isn_type == ISN_LOADS) isn = generate_instr_type(cctx, isn_type, type); else *************** *** 856,861 **** --- 883,889 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if (isn_type == ISN_LOADSCRIPT) isn = generate_instr_type(cctx, isn_type, type); else *************** *** 879,884 **** --- 907,913 ---- type_T *type; type_T *member; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_NEWLIST)) == NULL) return FAIL; isn->isn_arg.number = count; *************** *** 915,920 **** --- 944,950 ---- type_T *type; type_T *member; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_NEWDICT)) == NULL) return FAIL; isn->isn_arg.number = count; *************** *** 948,953 **** --- 978,984 ---- isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL) return FAIL; isn->isn_arg.number = dfunc_idx; *************** *** 970,975 **** --- 1001,1007 ---- isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_JUMP)) == NULL) return FAIL; isn->isn_arg.jump.jump_when = when; *************** *** 987,992 **** --- 1019,1025 ---- isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_FOR)) == NULL) return FAIL; isn->isn_arg.forloop.for_idx = loop_idx; *************** *** 1012,1017 **** --- 1045,1051 ---- type_T *argtypes[MAX_FUNC_ARGS]; int i; + RETURN_OK_IF_SKIP(cctx); if (check_internal_func(func_idx, argcount) == FAIL) return FAIL; *************** *** 1045,1050 **** --- 1079,1085 ---- int regular_args = ufunc->uf_args.ga_len; int argcount = pushed_argcount; + RETURN_OK_IF_SKIP(cctx); if (argcount > regular_args && !has_varargs(ufunc)) { semsg(_(e_toomanyarg), ufunc->uf_name); *************** *** 1105,1110 **** --- 1140,1146 ---- isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_UCALL)) == NULL) return FAIL; isn->isn_arg.ufunc.cuf_name = vim_strsave(name); *************** *** 1129,1134 **** --- 1165,1171 ---- isn_T *isn; garray_T *stack = &cctx->ctx_type_stack; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_PCALL)) == NULL) return FAIL; isn->isn_arg.pfunc.cpf_top = at_top; *************** *** 1152,1157 **** --- 1189,1195 ---- garray_T *stack = &cctx->ctx_type_stack; type_T *type; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_MEMBER)) == NULL) return FAIL; isn->isn_arg.string = vim_strnsave(name, (int)len); *************** *** 1178,1183 **** --- 1216,1222 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr_drop(cctx, ISN_ECHO, count)) == NULL) return FAIL; isn->isn_arg.echo.echo_with_white = with_white; *************** *** 1206,1211 **** --- 1245,1251 ---- { isn_T *isn; + RETURN_OK_IF_SKIP(cctx); if ((isn = generate_instr(cctx, ISN_EXEC)) == NULL) return FAIL; isn->isn_arg.string = vim_strsave(line); *************** *** 2878,2914 **** return OK; } ! /* ! * expr5a == expr5b ! * expr5a =~ expr5b ! * expr5a != expr5b ! * expr5a !~ expr5b ! * expr5a > expr5b ! * expr5a >= expr5b ! * expr5a < expr5b ! * expr5a <= expr5b ! * expr5a is expr5b ! * expr5a isnot expr5b ! * ! * Produces instructions: ! * EVAL expr5a Push result of "expr5a" ! * EVAL expr5b Push result of "expr5b" ! * COMPARE one of the compare instructions ! */ ! static int ! compile_expr4(char_u **arg, cctx_T *cctx) { exptype_T type = EXPR_UNKNOWN; - char_u *p; - int len = 2; int i; - int type_is = FALSE; - - // get the first variable - if (compile_expr5(arg, cctx) == FAIL) - return FAIL; - p = skipwhite(*arg); switch (p[0]) { case '=': if (p[1] == '=') --- 2918,2929 ---- return OK; } ! static exptype_T ! get_compare_type(char_u *p, int *len, int *type_is) { exptype_T type = EXPR_UNKNOWN; int i; switch (p[0]) { case '=': if (p[1] == '=') *************** *** 2924,2930 **** case '>': if (p[1] != '=') { type = EXPR_GREATER; ! len = 1; } else type = EXPR_GEQUAL; --- 2939,2945 ---- case '>': if (p[1] != '=') { type = EXPR_GREATER; ! *len = 1; } else type = EXPR_GEQUAL; *************** *** 2932,2938 **** case '<': if (p[1] != '=') { type = EXPR_SMALLER; ! len = 1; } else type = EXPR_SEQUAL; --- 2947,2953 ---- case '<': if (p[1] != '=') { type = EXPR_SMALLER; ! *len = 1; } else type = EXPR_SEQUAL; *************** *** 2941,2956 **** { // "is" and "isnot"; but not a prefix of a name if (p[2] == 'n' && p[3] == 'o' && p[4] == 't') ! len = 5; ! i = p[len]; if (!isalnum(i) && i != '_') { ! type = len == 2 ? EXPR_IS : EXPR_ISNOT; ! type_is = TRUE; } } break; } /* * If there is a comparative operator, use it. --- 2956,3005 ---- { // "is" and "isnot"; but not a prefix of a name if (p[2] == 'n' && p[3] == 'o' && p[4] == 't') ! *len = 5; ! i = p[*len]; if (!isalnum(i) && i != '_') { ! type = *len == 2 ? EXPR_IS : EXPR_ISNOT; ! *type_is = TRUE; } } break; } + return type; + } + + /* + * expr5a == expr5b + * expr5a =~ expr5b + * expr5a != expr5b + * expr5a !~ expr5b + * expr5a > expr5b + * expr5a >= expr5b + * expr5a < expr5b + * expr5a <= expr5b + * expr5a is expr5b + * expr5a isnot expr5b + * + * Produces instructions: + * EVAL expr5a Push result of "expr5a" + * EVAL expr5b Push result of "expr5b" + * COMPARE one of the compare instructions + */ + static int + compile_expr4(char_u **arg, cctx_T *cctx) + { + exptype_T type = EXPR_UNKNOWN; + char_u *p; + int len = 2; + int type_is = FALSE; + + // get the first variable + if (compile_expr5(arg, cctx) == FAIL) + return FAIL; + + p = skipwhite(*arg); + type = get_compare_type(p, &len, &type_is); /* * If there is a comparative operator, use it. *************** *** 3324,3451 **** if (name == NULL) return NULL; ! if (*arg == '&') { ! int cc; ! long numval; ! char_u *stringval = NULL; ! ! dest = dest_option; ! if (cmdidx == CMD_const) ! { ! emsg(_(e_const_option)); ! return NULL; ! } ! if (is_decl) ! { ! semsg(_("E1052: Cannot declare an option: %s"), arg); ! goto theend; ! } ! p = arg; ! p = find_option_end(&p, &opt_flags); ! if (p == NULL) { ! emsg(_(e_letunexp)); ! return NULL; ! } ! cc = *p; ! *p = NUL; ! opt_type = get_option_value(arg + 1, &numval, &stringval, opt_flags); ! *p = cc; ! if (opt_type == -3) ! { ! semsg(_(e_unknown_option), *arg); ! return NULL; ! } ! if (opt_type == -2 || opt_type == 0) ! type = &t_string; ! else ! type = &t_number; // both number and boolean option ! } ! else if (*arg == '$') ! { ! dest = dest_env; ! if (is_decl) ! { ! semsg(_("E1065: Cannot declare an environment variable: %s"), name); ! goto theend; ! } ! } ! else if (*arg == '@') ! { ! if (!valid_yank_reg(arg[1], TRUE)) ! { ! emsg_invreg(arg[1]); ! return FAIL; } ! dest = dest_reg; ! if (is_decl) { ! semsg(_("E1066: Cannot declare a register: %s"), name); ! goto theend; } ! } ! else if (STRNCMP(arg, "g:", 2) == 0) ! { ! dest = dest_global; ! if (is_decl) { ! semsg(_("E1016: Cannot declare a global variable: %s"), name); ! goto theend; } ! } ! else if (STRNCMP(arg, "v:", 2) == 0) ! { ! vimvaridx = find_vim_var(name + 2); ! if (vimvaridx < 0) { ! semsg(_(e_var_notfound), arg); ! goto theend; } ! dest = dest_vimvar; ! if (is_decl) { ! semsg(_("E1064: Cannot declare a v: variable: %s"), name); ! goto theend; ! } ! } ! else ! { ! for (idx = 0; reserved[idx] != NULL; ++idx) ! if (STRCMP(reserved[idx], name) == 0) { ! semsg(_("E1034: Cannot use reserved name %s"), name); goto theend; } ! ! idx = lookup_local(arg, varlen, cctx); ! if (idx >= 0) ! { if (is_decl) { ! semsg(_("E1017: Variable already declared: %s"), name); goto theend; } ! else { ! lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx; ! if (lvar->lv_const) { ! semsg(_("E1018: Cannot assign to a constant: %s"), name); goto theend; } } ! } ! else if (STRNCMP(arg, "s:", 2) == 0 ! || lookup_script(arg, varlen) == OK ! || find_imported(arg, varlen, cctx) != NULL) ! { ! dest = dest_script; ! if (is_decl) { ! semsg(_("E1054: Variable already declared in the script: %s"), ! name); ! goto theend; } } } --- 3373,3503 ---- if (name == NULL) return NULL; ! if (cctx->ctx_skip != TRUE) { ! if (*arg == '&') { ! int cc; ! long numval; ! char_u *stringval = NULL; ! ! dest = dest_option; ! if (cmdidx == CMD_const) ! { ! emsg(_(e_const_option)); ! return NULL; ! } ! if (is_decl) ! { ! semsg(_("E1052: Cannot declare an option: %s"), arg); ! goto theend; ! } ! p = arg; ! p = find_option_end(&p, &opt_flags); ! if (p == NULL) ! { ! emsg(_(e_letunexp)); ! return NULL; ! } ! cc = *p; ! *p = NUL; ! opt_type = get_option_value(arg + 1, &numval, &stringval, opt_flags); ! *p = cc; ! if (opt_type == -3) ! { ! semsg(_(e_unknown_option), *arg); ! return NULL; ! } ! if (opt_type == -2 || opt_type == 0) ! type = &t_string; ! else ! type = &t_number; // both number and boolean option } ! else if (*arg == '$') { ! dest = dest_env; ! if (is_decl) ! { ! semsg(_("E1065: Cannot declare an environment variable: %s"), name); ! goto theend; ! } } ! else if (*arg == '@') { ! if (!valid_yank_reg(arg[1], TRUE)) ! { ! emsg_invreg(arg[1]); ! return FAIL; ! } ! dest = dest_reg; ! if (is_decl) ! { ! semsg(_("E1066: Cannot declare a register: %s"), name); ! goto theend; ! } } ! else if (STRNCMP(arg, "g:", 2) == 0) { ! dest = dest_global; ! if (is_decl) ! { ! semsg(_("E1016: Cannot declare a global variable: %s"), name); ! goto theend; ! } } ! else if (STRNCMP(arg, "v:", 2) == 0) { ! vimvaridx = find_vim_var(name + 2); ! if (vimvaridx < 0) { ! semsg(_(e_var_notfound), arg); goto theend; } ! dest = dest_vimvar; if (is_decl) { ! semsg(_("E1064: Cannot declare a v: variable: %s"), name); goto theend; } ! } ! else ! { ! for (idx = 0; reserved[idx] != NULL; ++idx) ! if (STRCMP(reserved[idx], name) == 0) ! { ! semsg(_("E1034: Cannot use reserved name %s"), name); ! goto theend; ! } ! ! idx = lookup_local(arg, varlen, cctx); ! if (idx >= 0) { ! if (is_decl) { ! semsg(_("E1017: Variable already declared: %s"), name); goto theend; } + else + { + lvar = ((lvar_T *)cctx->ctx_locals.ga_data) + idx; + if (lvar->lv_const) + { + semsg(_("E1018: Cannot assign to a constant: %s"), name); + goto theend; + } + } } ! else if (STRNCMP(arg, "s:", 2) == 0 ! || lookup_script(arg, varlen) == OK ! || find_imported(arg, varlen, cctx) != NULL) { ! dest = dest_script; ! if (is_decl) ! { ! semsg(_("E1054: Variable already declared in the script: %s"), ! name); ! goto theend; ! } } } } *************** *** 3493,3499 **** } // +=, /=, etc. require an existing variable ! if (idx < 0 && dest == dest_local) { if (oplen > 1 && !heredoc) { --- 3545,3551 ---- } // +=, /=, etc. require an existing variable ! if (idx < 0 && dest == dest_local && cctx->ctx_skip != TRUE) { if (oplen > 1 && !heredoc) { *************** *** 3840,3847 **** end_leader = *arg; /* ! * Recognize only has() for now. */ if (STRNCMP("has(", *arg, 4) != 0) return FAIL; *arg = skipwhite(*arg + 4); --- 3892,3914 ---- end_leader = *arg; /* ! * Recognize only a few types of constants for now. */ + if (STRNCMP("true", *arg, 4) == 0 && !ASCII_ISALNUM((*arg)[4])) + { + tv->v_type = VAR_SPECIAL; + tv->vval.v_number = VVAL_TRUE; + *arg += 4; + return OK; + } + if (STRNCMP("false", *arg, 5) == 0 && !ASCII_ISALNUM((*arg)[5])) + { + tv->v_type = VAR_SPECIAL; + tv->vval.v_number = VVAL_FALSE; + *arg += 5; + return OK; + } + if (STRNCMP("has(", *arg, 4) != 0) return FAIL; *arg = skipwhite(*arg + 4); *************** *** 3881,3886 **** --- 3948,3980 ---- return OK; } + static int + evaluate_const_expr4(char_u **arg, cctx_T *cctx UNUSED, typval_T *tv) + { + exptype_T type = EXPR_UNKNOWN; + char_u *p; + int len = 2; + int type_is = FALSE; + + // get the first variable + if (evaluate_const_expr7(arg, cctx, tv) == FAIL) + return FAIL; + + p = skipwhite(*arg); + type = get_compare_type(p, &len, &type_is); + + /* + * If there is a comparative operator, use it. + */ + if (type != EXPR_UNKNOWN) + { + // TODO + return FAIL; + } + + return OK; + } + static int evaluate_const_expr3(char_u **arg, cctx_T *cctx, typval_T *tv); /* *************** *** 3911,3917 **** tv2.v_type = VAR_UNKNOWN; tv2.v_lock = 0; if ((opchar == '|' ? evaluate_const_expr3(arg, cctx, &tv2) ! : evaluate_const_expr7(arg, cctx, &tv2)) == FAIL) { clear_tv(&tv2); return FAIL; --- 4005,4011 ---- tv2.v_type = VAR_UNKNOWN; tv2.v_lock = 0; if ((opchar == '|' ? evaluate_const_expr3(arg, cctx, &tv2) ! : evaluate_const_expr4(arg, cctx, &tv2)) == FAIL) { clear_tv(&tv2); return FAIL; *************** *** 3940,3946 **** evaluate_const_expr3(char_u **arg, cctx_T *cctx, typval_T *tv) { // evaluate the first expression ! if (evaluate_const_expr7(arg, cctx, tv) == FAIL) return FAIL; // || and && work almost the same --- 4034,4040 ---- evaluate_const_expr3(char_u **arg, cctx_T *cctx, typval_T *tv) { // evaluate the first expression ! if (evaluate_const_expr4(arg, cctx, tv) == FAIL) return FAIL; // || and && work almost the same *** ../vim-8.2.0349/src/version.c 2020-03-03 19:02:09.185924967 +0100 --- src/version.c 2020-03-03 20:58:52.605719249 +0100 *************** *** 740,741 **** --- 740,743 ---- { /* Add new patch number below this line */ + /**/ + 350, /**/ -- Apathy Error: Don't bother striking any key. /// 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 ///