| author | |
| committer | |
| log | 0ea96c11ef5eca9cfd19233b6d51b00ba33da716 |
| tree | db54183a1c733a3e69da728cb4bc1501297bdf93 |
| parent | 0a410519559788598fcf698013c1b6389d80c67c |
6 files changed, 38 insertions(+), 59 deletions(-)
doc/langref.html.in+5-5| ... | ... | @@ -10212,13 +10212,13 @@ ContainerMembers |
| 10212 | 10212 | / ContainerField |
| 10213 | 10213 | / |
| 10214 | 10214 | |
| 10215 | TestDecl <- KEYWORD_test STRINGLITERAL Block | |
| 10215 | TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block | |
| 10216 | 10216 | |
| 10217 | 10217 | TopLevelComptime <- KEYWORD_comptime BlockExpr |
| 10218 | 10218 | |
| 10219 | 10219 | TopLevelDecl |
| 10220 | <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / KEYWORD_inline)? FnProto (SEMICOLON / Block) | |
| 10221 | / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl | |
| 10220 | <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / KEYWORD_inline)? FnProto (SEMICOLON / Block) | |
| 10221 | / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl | |
| 10222 | 10222 | / KEYWORD_usingnamespace Expr SEMICOLON |
| 10223 | 10223 | |
| 10224 | 10224 | FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr) |
| ... | ... | @@ -10561,10 +10561,10 @@ INTEGER |
| 10561 | 10561 | / "0o" [0-7]+ skip |
| 10562 | 10562 | / "0x" hex+ skip |
| 10563 | 10563 | / [0-9]+ skip |
| 10564 | STRINGLITERALSINGLE <- "\"" string_char* "\"" skip | |
| 10564 | 10565 | STRINGLITERAL |
| 10565 | <- "\"" string_char* "\"" skip | |
| 10566 | <- STRINGLITERALSINGLE | |
| 10566 | 10567 | / line_string skip |
| 10567 | / line_cstring skip | |
| 10568 | 10568 | IDENTIFIER |
| 10569 | 10569 | <- !keyword [A-Za-z_] [A-Za-z0-9_]* skip |
| 10570 | 10570 | / "@\"" string_char* "\"" skip |
lib/std/zig/parse.zig+13-13| ... | ... | @@ -183,10 +183,10 @@ fn parseContainerDocComments(arena: *Allocator, it: *TokenIterator, tree: *Tree) |
| 183 | 183 | return &node.base; |
| 184 | 184 | } |
| 185 | 185 | |
| 186 | /// TestDecl <- KEYWORD_test STRINGLITERAL Block | |
| 186 | /// TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block | |
| 187 | 187 | fn parseTestDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 188 | 188 | const test_token = eatToken(it, .Keyword_test) orelse return null; |
| 189 | const name_node = try expectNode(arena, it, tree, parseStringLiteral, AstError{ | |
| 189 | const name_node = try expectNode(arena, it, tree, parseStringLiteralSingle, AstError{ | |
| 190 | 190 | .ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index }, |
| 191 | 191 | }); |
| 192 | 192 | const block_node = try expectNode(arena, it, tree, parseBlock, AstError{ |
| ... | ... | @@ -225,15 +225,15 @@ fn parseTopLevelComptime(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?* |
| 225 | 225 | } |
| 226 | 226 | |
| 227 | 227 | /// TopLevelDecl |
| 228 | /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) | |
| 229 | /// / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl | |
| 228 | /// <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) | |
| 229 | /// / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl | |
| 230 | 230 | /// / KEYWORD_usingnamespace Expr SEMICOLON |
| 231 | 231 | fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 232 | 232 | var lib_name: ?*Node = null; |
| 233 | 233 | const extern_export_inline_token = blk: { |
| 234 | 234 | if (eatToken(it, .Keyword_export)) |token| break :blk token; |
| 235 | 235 | if (eatToken(it, .Keyword_extern)) |token| { |
| 236 | lib_name = try parseStringLiteral(arena, it, tree); | |
| 236 | lib_name = try parseStringLiteralSingle(arena, it, tree); | |
| 237 | 237 | break :blk token; |
| 238 | 238 | } |
| 239 | 239 | if (eatToken(it, .Keyword_inline)) |token| break :blk token; |
| ... | ... | @@ -285,12 +285,7 @@ fn parseTopLevelDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node |
| 285 | 285 | |
| 286 | 286 | if (extern_export_inline_token) |token| { |
| 287 | 287 | if (lib_name) |string_literal_node| |
| 288 | if (string_literal_node.cast(Node.StringLiteral)) |single| { | |
| 289 | putBackToken(it, single.token); | |
| 290 | } else if (string_literal_node.cast(Node.MultilineStringLiteral)) |multi| { | |
| 291 | while (multi.lines.pop()) |line| | |
| 292 | putBackToken(it, line); | |
| 293 | } else unreachable; | |
| 288 | putBackToken(it, string_literal_node.cast(Node.StringLiteral).?.token); | |
| 294 | 289 | putBackToken(it, token); |
| 295 | 290 | return null; |
| 296 | 291 | } |
| ... | ... | @@ -2776,8 +2771,7 @@ fn createLiteral(arena: *Allocator, comptime T: type, token: TokenIndex) !*Node |
| 2776 | 2771 | return &result.base; |
| 2777 | 2772 | } |
| 2778 | 2773 | |
| 2779 | // string literal or multiline string literal | |
| 2780 | fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | |
| 2774 | fn parseStringLiteralSingle(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | |
| 2781 | 2775 | if (eatToken(it, .StringLiteral)) |token| { |
| 2782 | 2776 | const node = try arena.create(Node.StringLiteral); |
| 2783 | 2777 | node.* = Node.StringLiteral{ |
| ... | ... | @@ -2785,6 +2779,12 @@ fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Nod |
| 2785 | 2779 | }; |
| 2786 | 2780 | return &node.base; |
| 2787 | 2781 | } |
| 2782 | return null; | |
| 2783 | } | |
| 2784 | ||
| 2785 | // string literal or multiline string literal | |
| 2786 | fn parseStringLiteral(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | |
| 2787 | if (try parseStringLiteralSingle(arena, it, tree)) |node| return node; | |
| 2788 | 2788 | |
| 2789 | 2789 | if (eatToken(it, .MultilineStringLiteralLine)) |first_line| { |
| 2790 | 2790 | const node = try arena.create(Node.MultilineStringLiteral); |
lib/std/zig/parser_test.zig-10| ... | ... | @@ -2721,16 +2721,6 @@ test "zig fmt: extern without container keyword returns error" { |
| 2721 | 2721 | ); |
| 2722 | 2722 | } |
| 2723 | 2723 | |
| 2724 | test "zig fmt: extern multiline lib name" { | |
| 2725 | try testError( | |
| 2726 | \\extern \\super | |
| 2727 | \\ \\long | |
| 2728 | \\ \\library | |
| 2729 | \\ \\name | |
| 2730 | \\ | |
| 2731 | ); | |
| 2732 | } | |
| 2733 | ||
| 2734 | 2724 | const std = @import("std"); |
| 2735 | 2725 | const mem = std.mem; |
| 2736 | 2726 | const warn = std.debug.warn; |
src/parser.cpp+15-14| ... | ... | @@ -141,16 +141,9 @@ static void ast_error(ParseContext *pc, Token *token, const char *format, ...) { |
| 141 | 141 | exit(EXIT_FAILURE); |
| 142 | 142 | } |
| 143 | 143 | |
| 144 | static Buf ast_token_str(Buf *input, Token *token) { | |
| 145 | Buf str = BUF_INIT; | |
| 146 | buf_init_from_mem(&str, buf_ptr(input) + token->start_pos, token->end_pos - token->start_pos); | |
| 147 | return str; | |
| 148 | } | |
| 149 | ||
| 150 | 144 | ATTRIBUTE_NORETURN |
| 151 | 145 | static void ast_invalid_token_error(ParseContext *pc, Token *token) { |
| 152 | Buf token_value = ast_token_str(pc->buf, token); | |
| 153 | ast_error(pc, token, "invalid token: '%s'", buf_ptr(&token_value)); | |
| 146 | ast_error(pc, token, "invalid token: '%s'", token_name(token->id)); | |
| 154 | 147 | } |
| 155 | 148 | |
| 156 | 149 | static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) { |
| ... | ... | @@ -213,7 +206,7 @@ static void put_back_token(ParseContext *pc) { |
| 213 | 206 | static Buf *token_buf(Token *token) { |
| 214 | 207 | if (token == nullptr) |
| 215 | 208 | return nullptr; |
| 216 | assert(token->id == TokenIdStringLiteral || token->id == TokenIdSymbol); | |
| 209 | assert(token->id == TokenIdStringLiteral || token->id == TokenIdMultilineStringLiteral || token->id == TokenIdSymbol); | |
| 217 | 210 | return &token->data.str_lit.str; |
| 218 | 211 | } |
| 219 | 212 | |
| ... | ... | @@ -596,7 +589,7 @@ static AstNodeContainerDecl ast_parse_container_members(ParseContext *pc) { |
| 596 | 589 | return res; |
| 597 | 590 | } |
| 598 | 591 | |
| 599 | // TestDecl <- KEYWORD_test STRINGLITERAL Block | |
| 592 | // TestDecl <- KEYWORD_test STRINGLITERALSINGLE Block | |
| 600 | 593 | static AstNode *ast_parse_test_decl(ParseContext *pc) { |
| 601 | 594 | Token *test = eat_token_if(pc, TokenIdKeywordTest); |
| 602 | 595 | if (test == nullptr) |
| ... | ... | @@ -630,8 +623,8 @@ static AstNode *ast_parse_top_level_comptime(ParseContext *pc) { |
| 630 | 623 | } |
| 631 | 624 | |
| 632 | 625 | // TopLevelDecl |
| 633 | // <- (KEYWORD_export / KEYWORD_extern STRINGLITERAL? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) | |
| 634 | // / (KEYWORD_export / KEYWORD_extern STRINGLITERAL?)? KEYWORD_threadlocal? VarDecl | |
| 626 | // <- (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE? / (KEYWORD_inline / KEYWORD_noinline))? FnProto (SEMICOLON / Block) | |
| 627 | // / (KEYWORD_export / KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl | |
| 635 | 628 | // / KEYWORD_use Expr SEMICOLON |
| 636 | 629 | static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, Buf *doc_comments) { |
| 637 | 630 | Token *first = eat_token_if(pc, TokenIdKeywordExport); |
| ... | ... | @@ -1729,6 +1722,8 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { |
| 1729 | 1722 | return ast_create_node(pc, NodeTypeUnreachable, unreachable); |
| 1730 | 1723 | |
| 1731 | 1724 | Token *string_lit = eat_token_if(pc, TokenIdStringLiteral); |
| 1725 | if (string_lit == nullptr) | |
| 1726 | string_lit = eat_token_if(pc, TokenIdMultilineStringLiteral); | |
| 1732 | 1727 | if (string_lit != nullptr) { |
| 1733 | 1728 | AstNode *res = ast_create_node(pc, NodeTypeStringLiteral, string_lit); |
| 1734 | 1729 | res->data.string_literal.buf = token_buf(string_lit); |
| ... | ... | @@ -1957,7 +1952,9 @@ static AsmOutput *ast_parse_asm_output_item(ParseContext *pc) { |
| 1957 | 1952 | Token *sym_name = expect_token(pc, TokenIdSymbol); |
| 1958 | 1953 | expect_token(pc, TokenIdRBracket); |
| 1959 | 1954 | |
| 1960 | Token *str = expect_token(pc, TokenIdStringLiteral); | |
| 1955 | Token *str = eat_token_if(pc, TokenIdMultilineStringLiteral); | |
| 1956 | if (str == nullptr) | |
| 1957 | str = expect_token(pc, TokenIdStringLiteral); | |
| 1961 | 1958 | expect_token(pc, TokenIdLParen); |
| 1962 | 1959 | |
| 1963 | 1960 | Token *var_name = eat_token_if(pc, TokenIdSymbol); |
| ... | ... | @@ -1999,7 +1996,9 @@ static AsmInput *ast_parse_asm_input_item(ParseContext *pc) { |
| 1999 | 1996 | Token *sym_name = expect_token(pc, TokenIdSymbol); |
| 2000 | 1997 | expect_token(pc, TokenIdRBracket); |
| 2001 | 1998 | |
| 2002 | Token *constraint = expect_token(pc, TokenIdStringLiteral); | |
| 1999 | Token *constraint = eat_token_if(pc, TokenIdMultilineStringLiteral); | |
| 2000 | if (constraint == nullptr) | |
| 2001 | constraint = expect_token(pc, TokenIdStringLiteral); | |
| 2003 | 2002 | expect_token(pc, TokenIdLParen); |
| 2004 | 2003 | AstNode *expr = ast_expect(pc, ast_parse_expr); |
| 2005 | 2004 | expect_token(pc, TokenIdRParen); |
| ... | ... | @@ -2018,6 +2017,8 @@ static AstNode *ast_parse_asm_clobbers(ParseContext *pc) { |
| 2018 | 2017 | |
| 2019 | 2018 | ZigList<Buf *> clobber_list = ast_parse_list<Buf>(pc, TokenIdComma, [](ParseContext *context) { |
| 2020 | 2019 | Token *str = eat_token_if(context, TokenIdStringLiteral); |
| 2020 | if (str == nullptr) | |
| 2021 | str = eat_token_if(context, TokenIdMultilineStringLiteral); | |
| 2021 | 2022 | if (str != nullptr) |
| 2022 | 2023 | return token_buf(str); |
| 2023 | 2024 | return (Buf*)nullptr; |
src/tokenizer.cpp+3-16| ... | ... | @@ -209,7 +209,6 @@ enum TokenizeState { |
| 209 | 209 | TokenizeStateLineString, |
| 210 | 210 | TokenizeStateLineStringEnd, |
| 211 | 211 | TokenizeStateLineStringContinue, |
| 212 | TokenizeStateLineStringContinueC, | |
| 213 | 212 | TokenizeStateSawEq, |
| 214 | 213 | TokenizeStateSawBang, |
| 215 | 214 | TokenizeStateSawLessThan, |
| ... | ... | @@ -266,7 +265,7 @@ static void set_token_id(Tokenize *t, Token *token, TokenId id) { |
| 266 | 265 | } else if (id == TokenIdFloatLiteral) { |
| 267 | 266 | bigfloat_init_32(&token->data.float_lit.bigfloat, 0.0f); |
| 268 | 267 | token->data.float_lit.overflow = false; |
| 269 | } else if (id == TokenIdStringLiteral || id == TokenIdSymbol) { | |
| 268 | } else if (id == TokenIdStringLiteral || id == TokenIdMultilineStringLiteral || id == TokenIdSymbol) { | |
| 270 | 269 | memset(&token->data.str_lit.str, 0, sizeof(Buf)); |
| 271 | 270 | buf_resize(&token->data.str_lit.str, 0); |
| 272 | 271 | } |
| ... | ... | @@ -503,7 +502,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 503 | 502 | t.state = TokenizeStateSawSlash; |
| 504 | 503 | break; |
| 505 | 504 | case '\\': |
| 506 | begin_token(&t, TokenIdStringLiteral); | |
| 505 | begin_token(&t, TokenIdMultilineStringLiteral); | |
| 507 | 506 | t.state = TokenizeStateSawBackslash; |
| 508 | 507 | break; |
| 509 | 508 | case '%': |
| ... | ... | @@ -945,18 +944,6 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 945 | 944 | continue; |
| 946 | 945 | } |
| 947 | 946 | break; |
| 948 | case TokenizeStateLineStringContinueC: | |
| 949 | switch (c) { | |
| 950 | case '\\': | |
| 951 | t.state = TokenizeStateLineStringContinue; | |
| 952 | break; | |
| 953 | default: | |
| 954 | t.pos -= 1; | |
| 955 | end_token(&t); | |
| 956 | t.state = TokenizeStateStart; | |
| 957 | continue; | |
| 958 | } | |
| 959 | break; | |
| 960 | 947 | case TokenizeStateLineStringContinue: |
| 961 | 948 | switch (c) { |
| 962 | 949 | case '\\': |
| ... | ... | @@ -1471,7 +1458,6 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 1471 | 1458 | case TokenizeStateSawDotDot: |
| 1472 | 1459 | case TokenizeStateSawBackslash: |
| 1473 | 1460 | case TokenizeStateLineStringContinue: |
| 1474 | case TokenizeStateLineStringContinueC: | |
| 1475 | 1461 | tokenize_error(&t, "unexpected EOF"); |
| 1476 | 1462 | break; |
| 1477 | 1463 | case TokenizeStateLineComment: |
| ... | ... | @@ -1607,6 +1593,7 @@ const char * token_name(TokenId id) { |
| 1607 | 1593 | case TokenIdStar: return "*"; |
| 1608 | 1594 | case TokenIdStarStar: return "**"; |
| 1609 | 1595 | case TokenIdStringLiteral: return "StringLiteral"; |
| 1596 | case TokenIdMultilineStringLiteral: return "MultilineStringLiteral"; | |
| 1610 | 1597 | case TokenIdSymbol: return "Symbol"; |
| 1611 | 1598 | case TokenIdTilde: return "~"; |
| 1612 | 1599 | case TokenIdTimesEq: return "*="; |
src/tokenizer.hpp+2-1| ... | ... | @@ -124,6 +124,7 @@ enum TokenId { |
| 124 | 124 | TokenIdStar, |
| 125 | 125 | TokenIdStarStar, |
| 126 | 126 | TokenIdStringLiteral, |
| 127 | TokenIdMultilineStringLiteral, | |
| 127 | 128 | TokenIdSymbol, |
| 128 | 129 | TokenIdTilde, |
| 129 | 130 | TokenIdTimesEq, |
| ... | ... | @@ -165,7 +166,7 @@ struct Token { |
| 165 | 166 | // TokenIdFloatLiteral |
| 166 | 167 | TokenFloatLit float_lit; |
| 167 | 168 | |
| 168 | // TokenIdStringLiteral or TokenIdSymbol | |
| 169 | // TokenIdStringLiteral, TokenIdMultilineStringLiteral or TokenIdSymbol | |
| 169 | 170 | TokenStrLit str_lit; |
| 170 | 171 | |
| 171 | 172 | // TokenIdCharLiteral |