@@ -306,6 +306,13 @@ fn contextSymbol(self: *Self, typ: Type, context: ExprContext) ?Symbol {
306306 unreachable ;
307307}
308308
309+ fn contextHasSymbol (typ : Type , context : ExprContext ) bool {
310+ for (0.. context .arity ) | index | {
311+ if (context .arg_types [index ] == typ ) return true ;
312+ }
313+ return false ;
314+ }
315+
309316fn extendContext (context : ExprContext , arg : Symbol , typ : Type ) ExprContext {
310317 std .debug .assert (context .arity < max_context_values );
311318 var extended = context ;
@@ -376,7 +383,7 @@ fn writeBoolExpr(self: *Self, context: ExprContext, depth: u8, visible_methods:
376383}
377384
378385fn writeStrExpr (self : * Self , context : ExprContext , depth : u8 , visible_methods : usize ) std.mem.Allocator.Error ! void {
379- switch (self .reader .intRangeAtMost (u8 , 0 , 8 )) {
386+ switch (self .reader .intRangeAtMost (u8 , 0 , 9 )) {
380387 0 = > if (self .contextSymbol (.str , context )) | arg | try self .writeSymbol (arg ) else try self .writeStringLiteral (),
381388 1 = > if (! try self .writeMethodCall (.str , context , depth - 1 , visible_methods )) try self .writeStringLiteral (),
382389 2 = > try self .writeIfExpr (.str , context , depth - 1 , visible_methods ),
@@ -395,6 +402,7 @@ fn writeStrExpr(self: *Self, context: ExprContext, depth: u8, visible_methods: u
395402 6 = > try self .writeRootMatchExpr (.str , context , depth - 1 , visible_methods ),
396403 7 = > try self .writeTryErrOrExpr (context , depth - 1 , visible_methods ),
397404 8 = > try self .writeRecordMatchExpr (.str , context , depth - 1 , visible_methods ),
405+ 9 = > if (self .canWriteStringInterpolationPart (context , visible_methods )) try self .writeStringInterpolationExpr (context , visible_methods ) else try self .writeStringLiteral (),
398406 else = > unreachable ,
399407 }
400408}
@@ -829,6 +837,72 @@ fn writeTryErrOrExpr(self: *Self, context: ExprContext, depth: u8, visible_metho
829837 try self .write (")" );
830838}
831839
840+ fn writeStringInterpolationExpr (self : * Self , context : ExprContext , visible_methods : usize ) std.mem.Allocator.Error ! void {
841+ try self .write ("\" " );
842+ try self .writeStringLiteralChars (self .reader .intRangeAtMost (u8 , 0 , 4 ));
843+ const part_count = self .reader .intRangeAtMost (u8 , 1 , 3 );
844+ for (0.. part_count ) | _ | {
845+ try self .write ("${(" );
846+ try self .writeStringInterpolationPartExpr (context , visible_methods );
847+ try self .write (")}" );
848+ try self .writeStringLiteralChars (self .reader .intRangeAtMost (u8 , 0 , 4 ));
849+ }
850+ try self .write ("\" " );
851+ }
852+
853+ fn writeStringInterpolationPartExpr (self : * Self , context : ExprContext , visible_methods : usize ) std.mem.Allocator.Error ! void {
854+ if (self .contextSymbol (.str , context )) | arg | {
855+ if (self .reader .boolean ()) {
856+ try self .writeSymbol (arg );
857+ return ;
858+ }
859+ }
860+
861+ if (self .chooseRootUnaryMethod (.str , visible_methods )) | method | {
862+ try self .writeSymbol (self .symbols .typ );
863+ try self .write ("." );
864+ try self .writeSymbol (method .symbol );
865+ try self .write ("(" );
866+ try self .writeSymbol (self .symbols .tag0 );
867+ try self .write (")" );
868+ return ;
869+ }
870+
871+ if (self .contextSymbol (.str , context )) | arg | {
872+ try self .writeSymbol (arg );
873+ return ;
874+ }
875+
876+ unreachable ;
877+ }
878+
879+ fn canWriteStringInterpolationPart (self : * Self , context : ExprContext , visible_methods : usize ) bool {
880+ return contextHasSymbol (.str , context ) or self .hasRootUnaryMethod (.str , visible_methods );
881+ }
882+
883+ fn hasRootUnaryMethod (self : * Self , result_type : Type , visible_methods : usize ) bool {
884+ for (self .methods [0.. visible_methods ]) | method | {
885+ if (method .result_type == result_type and method .arity == 1 and method .param_types [0 ] == .root ) return true ;
886+ }
887+ return false ;
888+ }
889+
890+ fn chooseRootUnaryMethod (self : * Self , result_type : Type , visible_methods : usize ) ? Method {
891+ var count : usize = 0 ;
892+ for (self .methods [0.. visible_methods ]) | method | {
893+ if (method .result_type == result_type and method .arity == 1 and method .param_types [0 ] == .root ) count += 1 ;
894+ }
895+ if (count == 0 ) return null ;
896+
897+ var index = self .reader .intRangeLessThan (usize , 0 , count );
898+ for (self .methods [0.. visible_methods ]) | method | {
899+ if (method .result_type != result_type or method .arity != 1 or method .param_types [0 ] != .root ) continue ;
900+ if (index == 0 ) return method ;
901+ index -= 1 ;
902+ }
903+ unreachable ;
904+ }
905+
832906fn writeTupleFirstExpr (self : * Self , context : ExprContext , depth : u8 , visible_methods : usize ) std.mem.Allocator.Error ! void {
833907 try self .writeParenthesizedExpr (.tuple_bool_u64 , context , depth , visible_methods );
834908 try self .write (".0" );
@@ -999,11 +1073,15 @@ fn writeU64Literal(self: *Self) std.mem.Allocator.Error!void {
9991073fn writeStringLiteral (self : * Self ) std.mem.Allocator.Error ! void {
10001074 try self .write ("\" " );
10011075 const len = self .reader .intRangeAtMost (u8 , 0 , 8 );
1076+ try self .writeStringLiteralChars (len );
1077+ try self .write ("\" " );
1078+ }
1079+
1080+ fn writeStringLiteralChars (self : * Self , len : usize ) std.mem.Allocator.Error ! void {
10021081 for (0.. len ) | _ | {
10031082 const char = self .reader .intRangeAtMost (u8 , 'a' , 'z' );
10041083 try self .output .append (self .allocator , char );
10051084 }
1006- try self .write ("\" " );
10071085}
10081086
10091087fn fresh (self : * Self , kind : SymbolKind ) Symbol {
0 commit comments