| ... | @@ -1376,11 +1376,9 @@ pub const Parser = struct { | ... | @@ -1376,11 +1376,9 @@ pub const Parser = struct { |
| 1376 | } | 1376 | } |
| 1377 | | 1377 | |
| 1378 | fn parseString(p: *Parser, allocator: *Allocator, s: std.meta.TagPayloadType(Token, Token.String), input: []const u8, i: usize) !Value { | 1378 | fn parseString(p: *Parser, allocator: *Allocator, s: std.meta.TagPayloadType(Token, Token.String), input: []const u8, i: usize) !Value { |
| 1379 | // TODO: We don't strictly have to copy values which do not contain any escape | | |
| 1380 | // characters if flagged with the option. | | |
| 1381 | const slice = s.slice(input, i); | 1379 | const slice = s.slice(input, i); |
| 1382 | switch (s.escapes) { | 1380 | switch (s.escapes) { |
| 1383 | .None => return Value{ .String = try mem.dupe(allocator, u8, slice) }, | 1381 | .None => return Value{ .String = if (p.copy_strings) try mem.dupe(allocator, u8, slice) else slice }, |
| 1384 | .Some => |some_escapes| { | 1382 | .Some => |some_escapes| { |
| 1385 | const output = try allocator.alloc(u8, s.decodedLength()); | 1383 | const output = try allocator.alloc(u8, s.decodedLength()); |
| 1386 | errdefer allocator.free(output); | 1384 | errdefer allocator.free(output); |
| ... | @@ -1597,10 +1595,7 @@ test "escaped characters" { | ... | @@ -1597,10 +1595,7 @@ test "escaped characters" { |
| 1597 | \\} | 1595 | \\} |
| 1598 | ; | 1596 | ; |
| 1599 | | 1597 | |
| 1600 | var p = Parser.init(debug.global_allocator, false); | 1598 | const obj = (try test_parse(input)).Object; |
| 1601 | const tree = try p.parse(input); | | |
| 1602 | | | |
| 1603 | const obj = tree.root.Object; | | |
| 1604 | | 1599 | |
| 1605 | testing.expectEqualSlices(u8, obj.get("backslash").?.value.String, "\\"); | 1600 | testing.expectEqualSlices(u8, obj.get("backslash").?.value.String, "\\"); |
| 1606 | testing.expectEqualSlices(u8, obj.get("forwardslash").?.value.String, "/"); | 1601 | testing.expectEqualSlices(u8, obj.get("forwardslash").?.value.String, "/"); |
| ... | @@ -1613,3 +1608,36 @@ test "escaped characters" { | ... | @@ -1613,3 +1608,36 @@ test "escaped characters" { |
| 1613 | testing.expectEqualSlices(u8, obj.get("unicode").?.value.String, "ą"); | 1608 | testing.expectEqualSlices(u8, obj.get("unicode").?.value.String, "ą"); |
| 1614 | testing.expectEqualSlices(u8, obj.get("surrogatepair").?.value.String, "😂"); | 1609 | testing.expectEqualSlices(u8, obj.get("surrogatepair").?.value.String, "😂"); |
| 1615 | } | 1610 | } |
| | 1611 | |
| | 1612 | test "string copy option" { |
| | 1613 | const input = |
| | 1614 | \\{ |
| | 1615 | \\ "noescape": "aąðŸ˜‚", |
| | 1616 | \\ "simple": "\\\/\n\r\t\f\b\"", |
| | 1617 | \\ "unicode": "\u0105", |
| | 1618 | \\ "surrogatepair": "\ud83d\ude02" |
| | 1619 | \\} |
| | 1620 | ; |
| | 1621 | |
| | 1622 | const tree_nocopy = try Parser.init(debug.global_allocator, false).parse(input); |
| | 1623 | const obj_nocopy = tree_nocopy.root.Object; |
| | 1624 | |
| | 1625 | const tree_copy = try Parser.init(debug.global_allocator, true).parse(input); |
| | 1626 | const obj_copy = tree_copy.root.Object; |
| | 1627 | |
| | 1628 | for ([_][]const u8{ "noescape", "simple", "unicode", "surrogatepair" }) |field_name| { |
| | 1629 | testing.expectEqualSlices(u8, obj_nocopy.getValue(field_name).?.String, obj_copy.getValue(field_name).?.String); |
| | 1630 | } |
| | 1631 | |
| | 1632 | const nocopy_addr = &obj_nocopy.getValue("noescape").?.String[0]; |
| | 1633 | const copy_addr = &obj_copy.getValue("noescape").?.String[0]; |
| | 1634 | |
| | 1635 | var found_nocopy = false; |
| | 1636 | for (input) |_, index| { |
| | 1637 | testing.expect(copy_addr != &input[index]); |
| | 1638 | if (nocopy_addr == &input[index]) { |
| | 1639 | found_nocopy = true; |
| | 1640 | } |
| | 1641 | } |
| | 1642 | testing.expect(found_nocopy); |
| | 1643 | } |