summaryrefslogtreecommitdiff
path: root/src/vim9compile.c
diff options
context:
space:
mode:
authorLemonBoy <thatlemon@gmail.com>2022-05-06 13:14:50 +0100
committerBram Moolenaar <Bram@vim.org>2022-05-06 13:14:50 +0100
commit2eaef106e4a7fc9dc74a7e672b5f550ec1f9786e (patch)
tree543832333e5ef90b9e51477457a7e65572274227 /src/vim9compile.c
parente7d6dbc5721342e3d6b04cf285e4510b5569e707 (diff)
downloadvim-git-2eaef106e4a7fc9dc74a7e672b5f550ec1f9786e.tar.gz
patch 8.2.4883: string interpolation only works in heredocv8.2.4883
Problem: String interpolation only works in heredoc. Solution: Support interpolated strings. Use syntax for heredoc consistent with strings, similar to C#. (closes #10327)
Diffstat (limited to 'src/vim9compile.c')
-rw-r--r--src/vim9compile.c133
1 files changed, 78 insertions, 55 deletions
diff --git a/src/vim9compile.c b/src/vim9compile.c
index b0cf6a787..9b7108b83 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -969,80 +969,103 @@ theend:
}
/*
- * Compile a heredoc string "str" (either containing a literal string or a mix
- * of literal strings and Vim expressions of the form `=<expr>`). This is used
- * when compiling a heredoc assignment to a variable in a Vim9 def function.
- * Vim9 instructions are generated to push strings, evaluate expressions,
- * concatenate them and create a list of lines. When "evalstr" is TRUE, Vim
- * expressions in "str" are evaluated.
+ * Compile a string "str" (either containing a literal string or a mix of
+ * literal strings and Vim expressions of the form `{expr}`). This is used
+ * when compiling a heredoc assignment to a variable or an interpolated string
+ * in a Vim9 def function. Vim9 instructions are generated to push strings,
+ * evaluate expressions, concatenate them and create a list of lines. When
+ * "evalstr" is TRUE, Vim expressions in "str" are evaluated.
*/
int
-compile_heredoc_string(char_u *str, int evalstr, cctx_T *cctx)
+compile_all_expr_in_str(char_u *str, int evalstr, cctx_T *cctx)
{
- char_u *p;
+ char_u *p = str;
char_u *val;
+ char_u save_c;
+ int count = 0;
if (cctx->ctx_skip == SKIP_YES)
return OK;
- if (evalstr && (p = (char_u *)strstr((char *)str, "`=")) != NULL)
+ if (!evalstr || *str == NUL)
{
- char_u *start = str;
- int count = 0;
+ // Literal string, possibly empty.
+ val = *str != NUL ? vim_strsave(str) : NULL;
+ return generate_PUSHS(cctx, &val);
+ }
- // Need to evaluate expressions of the form `=<expr>` in the string.
- // Split the string into literal strings and Vim expressions and
- // generate instructions to concatenate the literal strings and the
- // result of evaluating the Vim expressions.
- for (;;)
+ // Push all the string pieces to the stack, followed by a ISN_CONCAT.
+ while (*p != NUL)
+ {
+ char_u *lit_start;
+ char_u *block_start;
+ char_u *block_end;
+ int escaped_brace = FALSE;
+
+ // Look for a block start.
+ lit_start = p;
+ while (*p != '{' && *p != '}' && *p != NUL)
+ ++p;
+
+ if (*p != NUL && *p == p[1])
{
- if (p > start)
- {
- // literal string before the expression
- val = vim_strnsave(start, p - start);
- generate_PUSHS(cctx, &val);
- count++;
- }
- p += 2;
+ // Escaped brace, unescape and continue.
+ // Include the brace in the literal string.
+ ++p;
+ escaped_brace = TRUE;
+ }
+ else if (*p == '}')
+ {
+ semsg(_(e_stray_closing_curly_str), str);
+ return FAIL;
+ }
- // evaluate the Vim expression and convert the result to string.
- if (compile_expr0(&p, cctx) == FAIL)
+ // Append the literal part.
+ if (p != lit_start)
+ {
+ val = vim_strnsave(lit_start, (size_t)(p - lit_start));
+ if (generate_PUSHS(cctx, &val) == FAIL)
return FAIL;
- may_generate_2STRING(-1, TRUE, cctx);
- count++;
+ ++count;
+ }
- p = skipwhite(p);
- if (*p != '`')
- {
- emsg(_(e_missing_backtick));
- return FAIL;
- }
- start = p + 1;
+ if (*p == NUL)
+ break;
- p = (char_u *)strstr((char *)start, "`=");
- if (p == NULL)
- {
- // no more Vim expressions left to process
- if (*skipwhite(start) != NUL)
- {
- val = vim_strsave(start);
- generate_PUSHS(cctx, &val);
- count++;
- }
- break;
- }
+ if (escaped_brace)
+ {
+ // Skip the second brace.
+ ++p;
+ continue;
}
- if (count > 1)
- generate_CONCAT(cctx, count);
- }
- else
- {
- // literal string
- val = vim_strsave(str);
- generate_PUSHS(cctx, &val);
+ // Skip the opening {.
+ block_start = skipwhite(p + 1);
+ block_end = block_start;
+ if (*block_start != NUL &&skip_expr(&block_end, NULL) == FAIL)
+ return FAIL;
+ block_end = skipwhite(block_end);
+ // The block must be closed by a }.
+ if (*block_end != '}')
+ {
+ semsg(_(e_missing_close_curly_str), str);
+ return FAIL;
+ }
+ save_c = *block_end;
+ *block_end = NUL;
+ if (compile_expr0(&block_start, cctx) == FAIL)
+ return FAIL;
+ *block_end = save_c;
+ may_generate_2STRING(-1, TRUE, cctx);
+ ++count;
+
+ p = block_end + 1;
}
+ // Small optimization, if there's only a single piece skip the ISN_CONCAT.
+ if (count != 1)
+ return generate_CONCAT(cctx, count);
+
return OK;
}