4 files changed, 55 insertions(+), 0 deletions(-)
CHANGELOG.md+1| ... | @@ -12,6 +12,7 @@ | ... | @@ -12,6 +12,7 @@ |
| 12 | - feat: rename `noreturn` to `never` | 12 | - feat: rename `noreturn` to `never` |
| 13 | - feat: allow instantiating `@extern` at compile time | 13 | - feat: allow instantiating `@extern` at compile time |
| 14 | - feat: implement tuples | 14 | - feat: implement tuples |
| 15 | - feat: implement multiline string literals | ||
| 15 | - fix: crash when printing unused struct declaration error | 16 | - fix: crash when printing unused struct declaration error |
| 16 | - fix: provide array result type to sema | 17 | - fix: provide array result type to sema |
| 17 | - fix: crash when analyzing an empty array without a result type | 18 | - fix: crash when analyzing an empty array without a result type |
src/core/Parse.zig+18| ... | @@ -819,6 +819,7 @@ fn isExpressionStart(p: *Parse) bool { | ... | @@ -819,6 +819,7 @@ fn isExpressionStart(p: *Parse) bool { |
| 819 | .kw_fn, | 819 | .kw_fn, |
| 820 | .kw_struct, | 820 | .kw_struct, |
| 821 | .kw_tuple, | 821 | .kw_tuple, |
| 822 | .multiline_string, | ||
| 822 | => true, | 823 | => true, |
| 823 | else => false, | 824 | else => false, |
| 824 | }; | 825 | }; |
| ... | @@ -877,6 +878,7 @@ fn parseExpressionPart(p: *Parse, mode: ParseExprMode) Error!NodeIndex { | ... | @@ -877,6 +878,7 @@ fn parseExpressionPart(p: *Parse, mode: ParseExprMode) Error!NodeIndex { |
| 877 | .number_int => try p.blankNode(.number_int), | 878 | .number_int => try p.blankNode(.number_int), |
| 878 | .number_float => try p.blankNode(.number_float), | 879 | .number_float => try p.blankNode(.number_float), |
| 879 | .string => try p.blankNode(.string), | 880 | .string => try p.blankNode(.string), |
| 881 | .multiline_string => try p.parseMultilineString(), | ||
| 880 | 882 | ||
| 881 | .builtin_id => try p.parseBuiltinCall(), | 883 | .builtin_id => try p.parseBuiltinCall(), |
| 882 | .dot => try p.parseAnonStructInit(), | 884 | .dot => try p.parseAnonStructInit(), |
| ... | @@ -1320,6 +1322,22 @@ fn parseTupleType(p: *Parse) Error!NodeIndex { | ... | @@ -1320,6 +1322,22 @@ fn parseTupleType(p: *Parse) Error!NodeIndex { |
| 1320 | }); | 1322 | }); |
| 1321 | } | 1323 | } |
| 1322 | 1324 | ||
| 1325 | fn parseMultilineString(p: *Parse) !NodeIndex { | ||
| 1326 | const start = p.assertToken(.multiline_string); | ||
| 1327 | |||
| 1328 | while (p.eatToken(.multiline_string) != null) {} | ||
| 1329 | |||
| 1330 | const len = p.pos - start; | ||
| 1331 | return p.addNode(.{ | ||
| 1332 | .tag = .multiline_string, | ||
| 1333 | .main_token = start, | ||
| 1334 | .data = .{ .list = .{ | ||
| 1335 | .start = start, | ||
| 1336 | .len = len, | ||
| 1337 | } }, | ||
| 1338 | }); | ||
| 1339 | } | ||
| 1340 | |||
| 1323 | // helpers | 1341 | // helpers |
| 1324 | 1342 | ||
| 1325 | /// Append a node and return its index. | 1343 | /// Append a node and return its index. |
src/core/Transform.zig+22| ... | @@ -1620,6 +1620,28 @@ fn transformExpression( | ... | @@ -1620,6 +1620,28 @@ fn transformExpression( |
| 1620 | }); | 1620 | }); |
| 1621 | }, | 1621 | }, |
| 1622 | 1622 | ||
| 1623 | .multiline_string => { | ||
| 1624 | const token_list = t.ast.nodeData(node).list; | ||
| 1625 | |||
| 1626 | assert(t.id_decode_buf.items.len == 0); | ||
| 1627 | defer t.id_decode_buf.clearRetainingCapacity(); | ||
| 1628 | |||
| 1629 | try t.id_decode_buf.appendSlice(t.ast.tokenSlice(token_list.start)[2..]); | ||
| 1630 | for (token_list.start + 1..token_list.start + token_list.len) |i| { | ||
| 1631 | try t.id_decode_buf.append('\n'); | ||
| 1632 | try t.id_decode_buf.appendSlice(t.ast.tokenSlice(@intCast(i))[2..]); | ||
| 1633 | } | ||
| 1634 | |||
| 1635 | return try t.addRef(.string, .{ | ||
| 1636 | .src_node = ctx.nodeOffset(node), | ||
| 1637 | .extra_index = try t.extra.append( | ||
| 1638 | t.gpa, | ||
| 1639 | SlicedString, | ||
| 1640 | try t.addSlicedString(t.id_decode_buf.items), | ||
| 1641 | ), | ||
| 1642 | }); | ||
| 1643 | }, | ||
| 1644 | |||
| 1623 | else => |tag| std.debug.panic("TODO: expr {s}", .{@tagName(tag)}), | 1645 | else => |tag| std.debug.panic("TODO: expr {s}", .{@tagName(tag)}), |
| 1624 | } | 1646 | } |
| 1625 | } | 1647 | } |
test/behavior/string created+14| ... | @@ -0,0 +1,14 @@ | ||
| 1 | let assertEqual = @extern("assertEqual"); | ||
| 2 | |||
| 3 | fn main { | ||
| 4 | assertEqual( | ||
| 5 | \\hello world | ||
| 6 | \\etc | ||
| 7 | \\ | ||
| 8 | , "hello world\netc\n" | ||
| 9 | ); | ||
| 10 | assertEqual( | ||
| 11 | \\language compiler | ||
| 12 | , "language compiler" | ||
| 13 | ); | ||
| 14 | } | ||