@@ -7312,6 +7312,7 @@ final class Parser(AST) : Lexer
73127312 auto s = token.ustring;
73137313 auto len = token.len;
73147314 auto postfix = token.postfix;
7315+ auto interpolate = token.interpolate;
73157316 while (1 )
73167317 {
73177318 const prev = token;
@@ -7324,6 +7325,11 @@ final class Parser(AST) : Lexer
73247325 error(" mismatched string literal postfixes `'%c'` and `'%c'`" , postfix, token.postfix);
73257326 postfix = token.postfix;
73267327 }
7328+ if (interpolate != token.interpolate)
7329+ {
7330+ error(" cannot concatenate interpolated strings with non-interpolated strings" );
7331+ interpolate = true ;
7332+ }
73277333
73287334 deprecation(" Implicit string concatenation is deprecated, use %s ~ %s instead" ,
73297335 prev.toChars(), token.toChars());
@@ -7339,7 +7345,10 @@ final class Parser(AST) : Lexer
73397345 else
73407346 break ;
73417347 }
7342- e = new AST .StringExp(loc, cast (char * )s, len, postfix);
7348+ if (interpolate)
7349+ e = new AST .TupleExp(loc, parseInterpolatedString(loc, s, len, postfix));
7350+ else
7351+ e = new AST .StringExp(loc, cast (char * )s, len, postfix);
73437352 break ;
73447353 }
73457354 case TOK .void_:
@@ -8560,6 +8569,95 @@ final class Parser(AST) : Lexer
85608569 token.lineComment = null ;
85618570 }
85628571 }
8572+
8573+ /**
8574+ Parse the given interpolated string `str` into an array of expressions.
8575+
8576+ Params:
8577+ str = the interpolated string to parse
8578+
8579+ Returns:
8580+ An array of expressions representing the interpolated string.
8581+ */
8582+ AST .Expressions* parseInterpolatedString (ref const (Loc) loc, const (char )* str, uint len, ubyte postfix)
8583+ {
8584+ // printf("parseInterpolatedString '%.*s'\n", len, str);
8585+ auto parts = new AST .Expressions();
8586+
8587+ auto mark = 0 ;
8588+ auto next = 0 ;
8589+ void addMarkToNext ()
8590+ {
8591+ if (next > mark)
8592+ parts.push(new AST .StringExp(loc, cast (char * )str + mark, next - mark, postfix));
8593+ }
8594+ MainLoop:
8595+ for (; next < len;)
8596+ {
8597+ // printf("[DEBUG] str[%d] = '%c'\n", next, str[next]);
8598+ if (str[next] != ' $' )
8599+ {
8600+ next++ ;
8601+ }
8602+ else
8603+ {
8604+ addMarkToNext();
8605+ if (next + 1 >= len)
8606+ {
8607+ error(" unfinished interpolated string expression '$'" );
8608+ mark = next;
8609+ break ;
8610+ }
8611+ if (str[next + 1 ] == ' (' )
8612+ {
8613+ next += 2 ;
8614+ mark = next;
8615+ for (uint depth = 1 ;; next++ )
8616+ {
8617+ if (next >= len)
8618+ {
8619+ error(" unfinished interpolated string expression '$(...)'" );
8620+ mark = next;
8621+ break MainLoop;
8622+ }
8623+ auto c = str[next];
8624+ if (c == ' )' )
8625+ {
8626+ depth-- ;
8627+ if (depth == 0 )
8628+ break ;
8629+ }
8630+ else if (c == ' (' )
8631+ {
8632+ depth++ ;
8633+ }
8634+ }
8635+ {
8636+ auto expr = str[mark .. next];
8637+ // printf("[DEBUG] parsing the expression '%.*s'\n", expr.length, expr.ptr);
8638+ scope tempParser = new Parser! AST (/* loc, */ mod, expr, false );
8639+ tempParser.nextToken();
8640+ auto result = tempParser.parseExpression();
8641+ // printf("[DEBUG] parsed to '%s'\n", result.toChars());
8642+ if (tempParser.token.value != TOK .rightParentheses)
8643+ {
8644+ error(" invalid expression '%.*s' inside interpolated string" , expr.length, expr.ptr);
8645+ }
8646+ parts.push(result);
8647+ }
8648+ next++ ;
8649+ mark = next;
8650+ }
8651+ else
8652+ {
8653+ assert (0 , " not implemented" );
8654+ }
8655+ }
8656+ }
8657+ addMarkToNext();
8658+
8659+ return parts;
8660+ }
85638661}
85648662
85658663enum PREC : int
0 commit comments