summaryrefslogtreecommitdiffstats
path: root/src/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/eval.c')
-rw-r--r--src/eval.c98
1 files changed, 54 insertions, 44 deletions
diff --git a/src/eval.c b/src/eval.c
index c8c4f6e5f4..911f0abc67 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2110,6 +2110,7 @@ eval0(
/*
* Handle top level expression:
* expr2 ? expr1 : expr1
+ * expr2 ?? expr1
*
* "arg" must point to the first non-white of the expression.
* "arg" is advanced to just after the recognized expression.
@@ -2135,6 +2136,7 @@ eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
p = eval_next_non_blank(*arg, evalarg, &getnext);
if (*p == '?')
{
+ int op_falsy = p[1] == '?';
int result;
typval_T var2;
evalarg_T *evalarg_used = evalarg;
@@ -2168,11 +2170,12 @@ eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
{
int error = FALSE;
- if (in_vim9script())
+ if (in_vim9script() || op_falsy)
result = tv2bool(rettv);
else if (tv_get_number_chk(rettv, &error) != 0)
result = TRUE;
- clear_tv(rettv);
+ if (error || !op_falsy || !result)
+ clear_tv(rettv);
if (error)
return FAIL;
}
@@ -2180,6 +2183,8 @@ eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
/*
* Get the second variable. Recursive!
*/
+ if (op_falsy)
+ ++*arg;
if (evaluate && in_vim9script() && !IS_WHITE_OR_NUL((*arg)[1]))
{
error_white_both(p, 1);
@@ -2187,62 +2192,67 @@ eval1(char_u **arg, typval_T *rettv, evalarg_T *evalarg)
return FAIL;
}
*arg = skipwhite_and_linebreak(*arg + 1, evalarg_used);
- evalarg_used->eval_flags = result ? orig_flags
- : orig_flags & ~EVAL_EVALUATE;
- if (eval1(arg, rettv, evalarg_used) == FAIL)
+ evalarg_used->eval_flags = (op_falsy ? !result : result)
+ ? orig_flags : orig_flags & ~EVAL_EVALUATE;
+ if (eval1(arg, &var2, evalarg_used) == FAIL)
{
evalarg_used->eval_flags = orig_flags;
return FAIL;
}
+ if (!op_falsy || !result)
+ *rettv = var2;
- /*
- * Check for the ":".
- */
- p = eval_next_non_blank(*arg, evalarg_used, &getnext);
- if (*p != ':')
- {
- emsg(_(e_missing_colon));
- if (evaluate && result)
- clear_tv(rettv);
- evalarg_used->eval_flags = orig_flags;
- return FAIL;
- }
- if (getnext)
- *arg = eval_next_line(evalarg_used);
- else
+ if (!op_falsy)
{
- if (evaluate && in_vim9script() && !VIM_ISWHITE(p[-1]))
+ /*
+ * Check for the ":".
+ */
+ p = eval_next_non_blank(*arg, evalarg_used, &getnext);
+ if (*p != ':')
+ {
+ emsg(_(e_missing_colon));
+ if (evaluate && result)
+ clear_tv(rettv);
+ evalarg_used->eval_flags = orig_flags;
+ return FAIL;
+ }
+ if (getnext)
+ *arg = eval_next_line(evalarg_used);
+ else
+ {
+ if (evaluate && in_vim9script() && !VIM_ISWHITE(p[-1]))
+ {
+ error_white_both(p, 1);
+ clear_tv(rettv);
+ evalarg_used->eval_flags = orig_flags;
+ return FAIL;
+ }
+ *arg = p;
+ }
+
+ /*
+ * Get the third variable. Recursive!
+ */
+ if (evaluate && in_vim9script() && !IS_WHITE_OR_NUL((*arg)[1]))
{
error_white_both(p, 1);
clear_tv(rettv);
evalarg_used->eval_flags = orig_flags;
return FAIL;
}
- *arg = p;
- }
-
- /*
- * Get the third variable. Recursive!
- */
- if (evaluate && in_vim9script() && !IS_WHITE_OR_NUL((*arg)[1]))
- {
- error_white_both(p, 1);
- clear_tv(rettv);
- evalarg_used->eval_flags = orig_flags;
- return FAIL;
- }
- *arg = skipwhite_and_linebreak(*arg + 1, evalarg_used);
- evalarg_used->eval_flags = !result ? orig_flags
+ *arg = skipwhite_and_linebreak(*arg + 1, evalarg_used);
+ evalarg_used->eval_flags = !result ? orig_flags
: orig_flags & ~EVAL_EVALUATE;
- if (eval1(arg, &var2, evalarg_used) == FAIL)
- {
- if (evaluate && result)
- clear_tv(rettv);
- evalarg_used->eval_flags = orig_flags;
- return FAIL;
+ if (eval1(arg, &var2, evalarg_used) == FAIL)
+ {
+ if (evaluate && result)
+ clear_tv(rettv);
+ evalarg_used->eval_flags = orig_flags;
+ return FAIL;
+ }
+ if (evaluate && !result)
+ *rettv = var2;
}
- if (evaluate && !result)
- *rettv = var2;
if (evalarg == NULL)
clear_evalarg(&local_evalarg, NULL);