Skip to content

Commit 51481ff

Browse files
committed
Generate string interpolation in typecheck fuzzer
1 parent ed65ede commit 51481ff

1 file changed

Lines changed: 80 additions & 2 deletions

File tree

test/fuzzing/TypedCodeGenerator.zig

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
309316
fn 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

378385
fn 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+
832906
fn 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 {
9991073
fn 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

10091087
fn fresh(self: *Self, kind: SymbolKind) Symbol {

0 commit comments

Comments
 (0)