patch 8.2.2124: Vim9: a range cannot be computed at runtime

Problem:    Vim9: a range cannot be computed at runtime.
Solution:   Add the ISN_RANGE instruction.
diff --git a/src/vim9compile.c b/src/vim9compile.c
index da069f4..ac8fb84 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -1888,6 +1888,26 @@
     return OK;
 }
 
+/*
+ * Generate ISN_RANGE.  Consumes "range".  Return OK/FAIL.
+ */
+    static int
+generate_RANGE(cctx_T *cctx, char_u *range)
+{
+    isn_T	*isn;
+    garray_T	*stack = &cctx->ctx_type_stack;
+
+    if ((isn = generate_instr(cctx, ISN_RANGE)) == NULL)
+	return FAIL;
+    isn->isn_arg.string = range;
+
+    if (ga_grow(stack, 1) == FAIL)
+	return FAIL;
+    ((type_T **)stack->ga_data)[stack->ga_len] = &t_number;
+    ++stack->ga_len;
+    return OK;
+}
+
     static int
 generate_UNPACK(cctx_T *cctx, int var_count, int semicolon)
 {
@@ -7099,6 +7119,22 @@
 }
 
 /*
+ * If "eap" has a range that is not a contstant generate an ISN_RANGE
+ * instruction to compute it and return OK.
+ * Otherwise return FAIL, the caller must deal with any range.
+ */
+    static int
+compile_variable_range(exarg_T *eap, cctx_T *cctx)
+{
+    char_u *range_end = skip_range(eap->cmd, TRUE, NULL);
+    char_u *p = skipdigits(eap->cmd);
+
+    if (p == range_end)
+	return FAIL;
+    return generate_RANGE(cctx, vim_strnsave(eap->cmd, range_end - eap->cmd));
+}
+
+/*
  * :put r
  * :put ={expr}
  */
@@ -7123,17 +7159,23 @@
     else if (eap->regname != NUL)
 	++line;
 
-    // "errormsg" will not be set because the range is ADDR_LINES.
-    // TODO: if the range contains something like "$" or "." need to evaluate
-    // at runtime
-    if (parse_cmd_address(eap, &errormsg, FALSE) == FAIL)
-	return NULL;
-    if (eap->addr_count == 0)
-	lnum = -1;
+    if (compile_variable_range(eap, cctx) == OK)
+    {
+	lnum = above ? LNUM_VARIABLE_RANGE_ABOVE : LNUM_VARIABLE_RANGE;
+    }
     else
-	lnum = eap->line2;
-    if (above)
-	--lnum;
+    {
+	// Either no range or a number.
+	// "errormsg" will not be set because the range is ADDR_LINES.
+	if (parse_cmd_address(eap, &errormsg, FALSE) == FAIL)
+	    return NULL;
+	if (eap->addr_count == 0)
+	    lnum = -1;
+	else
+	    lnum = eap->line2;
+	if (above)
+	    --lnum;
+    }
 
     generate_PUT(cctx, eap->regname, lnum);
     return line;
@@ -7960,6 +8002,7 @@
 	case ISN_PUSHEXC:
 	case ISN_PUSHFUNC:
 	case ISN_PUSHS:
+	case ISN_RANGE:
 	case ISN_STOREB:
 	case ISN_STOREENV:
 	case ISN_STOREG: