| author | |
| committer | |
| log | dfda85e870df1b0620c418940db3b946fdd3d620 |
| tree | 94d4d7e158f62ee2cd153b002165bc3ef7aa7c47 |
| parent | 4eff5f114b463ddd887665129f2e1d29b0f13b7f |
10 files changed, 121 insertions(+), 29 deletions(-)
README.md+4-2| ... | @@ -58,7 +58,6 @@ compromises backward compatibility. | ... | @@ -58,7 +58,6 @@ compromises backward compatibility. |
| 58 | * structs | 58 | * structs |
| 59 | * loops | 59 | * loops |
| 60 | * enums | 60 | * enums |
| 61 | * calling external variadic functions and exporting variadic functions | ||
| 62 | * inline assembly and syscalls | 61 | * inline assembly and syscalls |
| 63 | * conditional compilation and ability to check target platform and architecture | 62 | * conditional compilation and ability to check target platform and architecture |
| 64 | * main function with command line arguments | 63 | * main function with command line arguments |
| ... | @@ -69,6 +68,9 @@ compromises backward compatibility. | ... | @@ -69,6 +68,9 @@ compromises backward compatibility. |
| 69 | * static initializers | 68 | * static initializers |
| 70 | * assert | 69 | * assert |
| 71 | * function pointers | 70 | * function pointers |
| 71 | * hex literal, binary literal, float literal, hex float literal | ||
| 72 | * += and -= operators | ||
| 73 | * fix a + b + c | ||
| 72 | * running code at compile time | 74 | * running code at compile time |
| 73 | * standard library print functions | 75 | * standard library print functions |
| 74 | * panic! macro or statement that prints a stack trace to stderr in debug mode | 76 | * panic! macro or statement that prints a stack trace to stderr in debug mode |
| ... | @@ -144,7 +146,7 @@ FnDef : FnProto Block | ... | @@ -144,7 +146,7 @@ FnDef : FnProto Block |
| 144 | 146 | ||
| 145 | ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen) | 147 | ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen) |
| 146 | 148 | ||
| 147 | ParamDecl : token(Symbol) token(Colon) Type | 149 | ParamDecl : token(Symbol) token(Colon) Type | token(Ellipse) |
| 148 | 150 | ||
| 149 | Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | 151 | Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType |
| 150 | 152 |
example/hello_world/hello.zig+3-3| ... | @@ -2,11 +2,11 @@ export executable "hello"; | ... | @@ -2,11 +2,11 @@ export executable "hello"; |
| 2 | 2 | ||
| 3 | #link("c") | 3 | #link("c") |
| 4 | extern { | 4 | extern { |
| 5 | fn puts(s: *const u8) -> i32; | 5 | fn printf(__format: *const u8, ...) -> i32; |
| 6 | fn exit(code: i32) -> unreachable; | 6 | fn exit(__status: i32) -> unreachable; |
| 7 | } | 7 | } |
| 8 | 8 | ||
| 9 | export fn _start() -> unreachable { | 9 | export fn _start() -> unreachable { |
| 10 | puts("Hello, world!"); | 10 | printf("Hello, world!\n"); |
| 11 | exit(0); | 11 | exit(0); |
| 12 | } | 12 | } |
src/analyze.cpp+14-1| ... | @@ -163,9 +163,12 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) { | ... | @@ -163,9 +163,12 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) { |
| 163 | { | 163 | { |
| 164 | resolve_type(g, node->data.type.child_type); | 164 | resolve_type(g, node->data.type.child_type); |
| 165 | TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; | 165 | TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; |
| 166 | assert(child_type); | ||
| 166 | if (child_type == g->builtin_types.entry_unreachable) { | 167 | if (child_type == g->builtin_types.entry_unreachable) { |
| 167 | add_node_error(g, node, | 168 | add_node_error(g, node, |
| 168 | buf_create_from_str("pointer to unreachable not allowed")); | 169 | buf_create_from_str("pointer to unreachable not allowed")); |
| 170 | } else if (child_type->id == TypeTableEntryIdInvalid) { | ||
| 171 | return child_type; | ||
| 169 | } | 172 | } |
| 170 | type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const); | 173 | type_node->entry = get_pointer_to_type(g, child_type, node->data.type.is_const); |
| 171 | return type_node->entry; | 174 | return type_node->entry; |
| ... | @@ -312,6 +315,10 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, | ... | @@ -312,6 +315,10 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, |
| 312 | skip = true; | 315 | skip = true; |
| 313 | } | 316 | } |
| 314 | } | 317 | } |
| 318 | if (proto_node->data.fn_proto.is_var_args) { | ||
| 319 | add_node_error(g, node, | ||
| 320 | buf_sprintf("variadic arguments only allowed in extern functions")); | ||
| 321 | } | ||
| 315 | if (!skip) { | 322 | if (!skip) { |
| 316 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); | 323 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); |
| 317 | fn_table_entry->import_entry = import; | 324 | fn_table_entry->import_entry = import; |
| ... | @@ -743,7 +750,13 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, | ... | @@ -743,7 +750,13 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 743 | // count parameters | 750 | // count parameters |
| 744 | int expected_param_count = fn_proto->params.length; | 751 | int expected_param_count = fn_proto->params.length; |
| 745 | int actual_param_count = node->data.fn_call_expr.params.length; | 752 | int actual_param_count = node->data.fn_call_expr.params.length; |
| 746 | if (expected_param_count != actual_param_count) { | 753 | if (fn_proto->is_var_args) { |
| 754 | if (actual_param_count < expected_param_count) { | ||
| 755 | add_node_error(g, node, | ||
| 756 | buf_sprintf("wrong number of arguments. Expected at least %d, got %d.", | ||
| 757 | expected_param_count, actual_param_count)); | ||
| 758 | } | ||
| 759 | } else if (expected_param_count != actual_param_count) { | ||
| 747 | add_node_error(g, node, | 760 | add_node_error(g, node, |
| 748 | buf_sprintf("wrong number of arguments. Expected %d, got %d.", | 761 | buf_sprintf("wrong number of arguments. Expected %d, got %d.", |
| 749 | expected_param_count, actual_param_count)); | 762 | expected_param_count, actual_param_count)); |
src/codegen.cpp+19-6| ... | @@ -138,19 +138,32 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { | ... | @@ -138,19 +138,32 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 138 | fn_table_entry = g->fn_table.get(name); | 138 | fn_table_entry = g->fn_table.get(name); |
| 139 | 139 | ||
| 140 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); | 140 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); |
| 141 | int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length; | 141 | AstNodeFnProto *fn_proto_data = &fn_table_entry->proto_node->data.fn_proto; |
| 142 | |||
| 143 | int expected_param_count = fn_proto_data->params.length; | ||
| 142 | int actual_param_count = node->data.fn_call_expr.params.length; | 144 | int actual_param_count = node->data.fn_call_expr.params.length; |
| 143 | assert(expected_param_count == actual_param_count); | 145 | bool is_var_args = fn_proto_data->is_var_args; |
| 146 | assert((is_var_args && actual_param_count >= expected_param_count) || | ||
| 147 | actual_param_count == expected_param_count); | ||
| 144 | 148 | ||
| 145 | // don't really include void values | 149 | // don't really include void values |
| 146 | int gen_param_count = count_non_void_params(g, &fn_table_entry->proto_node->data.fn_proto.params); | 150 | int gen_param_count; |
| 151 | if (is_var_args) { | ||
| 152 | gen_param_count = actual_param_count; | ||
| 153 | } else { | ||
| 154 | gen_param_count = count_non_void_params(g, &fn_table_entry->proto_node->data.fn_proto.params); | ||
| 155 | } | ||
| 147 | LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(gen_param_count); | 156 | LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(gen_param_count); |
| 148 | 157 | ||
| 158 | int loop_end = max(gen_param_count, actual_param_count); | ||
| 159 | |||
| 149 | int gen_param_index = 0; | 160 | int gen_param_index = 0; |
| 150 | for (int i = 0; i < actual_param_count; i += 1) { | 161 | for (int i = 0; i < loop_end; i += 1) { |
| 151 | AstNode *expr_node = node->data.fn_call_expr.params.at(i); | 162 | AstNode *expr_node = node->data.fn_call_expr.params.at(i); |
| 152 | LLVMValueRef param_value = gen_expr(g, expr_node); | 163 | LLVMValueRef param_value = gen_expr(g, expr_node); |
| 153 | if (!is_param_decl_type_void(g, fn_table_entry->proto_node->data.fn_proto.params.at(i))) { | 164 | if (is_var_args || |
| 165 | !is_param_decl_type_void(g, fn_table_entry->proto_node->data.fn_proto.params.at(i))) | ||
| 166 | { | ||
| 154 | gen_param_values[gen_param_index] = param_value; | 167 | gen_param_values[gen_param_index] = param_value; |
| 155 | gen_param_index += 1; | 168 | gen_param_index += 1; |
| 156 | } | 169 | } |
| ... | @@ -773,7 +786,7 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -773,7 +786,7 @@ static void do_code_gen(CodeGen *g) { |
| 773 | param_types[gen_param_index] = to_llvm_type(type_node); | 786 | param_types[gen_param_index] = to_llvm_type(type_node); |
| 774 | gen_param_index += 1; | 787 | gen_param_index += 1; |
| 775 | } | 788 | } |
| 776 | LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, param_count, 0); | 789 | LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, param_count, fn_proto->is_var_args); |
| 777 | LLVMValueRef fn = LLVMAddFunction(g->module, buf_ptr(&fn_proto->name), function_type); | 790 | LLVMValueRef fn = LLVMAddFunction(g->module, buf_ptr(&fn_proto->name), function_type); |
| 778 | 791 | ||
| 779 | LLVMSetLinkage(fn, fn_table_entry->internal_linkage ? LLVMInternalLinkage : LLVMExternalLinkage); | 792 | LLVMSetLinkage(fn, fn_table_entry->internal_linkage ? LLVMInternalLinkage : LLVMExternalLinkage); |
src/parseh.cpp+7-3| ... | @@ -132,10 +132,10 @@ static bool resolves_to_void(ParseH *p, CXType raw_type) { | ... | @@ -132,10 +132,10 @@ static bool resolves_to_void(ParseH *p, CXType raw_type) { |
| 132 | static Buf *to_zig_type(ParseH *p, CXType raw_type) { | 132 | static Buf *to_zig_type(ParseH *p, CXType raw_type) { |
| 133 | if (raw_type.kind == CXType_Unexposed) { | 133 | if (raw_type.kind == CXType_Unexposed) { |
| 134 | CXType canonical = clang_getCanonicalType(raw_type); | 134 | CXType canonical = clang_getCanonicalType(raw_type); |
| 135 | if (canonical.kind != CXType_Unexposed) | 135 | if (canonical.kind == CXType_Unexposed) |
| 136 | return to_zig_type(p, canonical); | ||
| 137 | else | ||
| 138 | zig_panic("clang C api insufficient"); | 136 | zig_panic("clang C api insufficient"); |
| 137 | else | ||
| 138 | return to_zig_type(p, canonical); | ||
| 139 | } | 139 | } |
| 140 | switch (raw_type.kind) { | 140 | switch (raw_type.kind) { |
| 141 | case CXType_Invalid: | 141 | case CXType_Invalid: |
| ... | @@ -453,6 +453,10 @@ static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXCl | ... | @@ -453,6 +453,10 @@ static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXCl |
| 453 | } else if (underlying_type.kind == CXType_Record) { | 453 | } else if (underlying_type.kind == CXType_Record) { |
| 454 | CXCursor decl_cursor = clang_getTypeDeclaration(underlying_type); | 454 | CXCursor decl_cursor = clang_getTypeDeclaration(underlying_type); |
| 455 | skip_typedef = handle_struct_cursor(p, decl_cursor, clang_getCString(name), false); | 455 | skip_typedef = handle_struct_cursor(p, decl_cursor, clang_getCString(name), false); |
| 456 | } else if (underlying_type.kind == CXType_Invalid) { | ||
| 457 | fprintf(stderr, "warning: invalid type\n"); | ||
| 458 | print_location(p); | ||
| 459 | skip_typedef = true; | ||
| 456 | } else { | 460 | } else { |
| 457 | skip_typedef = false; | 461 | skip_typedef = false; |
| 458 | } | 462 | } |
src/parser.cpp+30-14| ... | @@ -517,32 +517,39 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token | ... | @@ -517,32 +517,39 @@ static AstNode *ast_parse_type(ParseContext *pc, int token_index, int *new_token |
| 517 | } | 517 | } |
| 518 | 518 | ||
| 519 | /* | 519 | /* |
| 520 | ParamDecl : token(Symbol) token(Colon) Type | 520 | ParamDecl : token(Symbol) token(Colon) Type | token(Ellipse) |
| 521 | */ | 521 | */ |
| 522 | static AstNode *ast_parse_param_decl(ParseContext *pc, int token_index, int *new_token_index) { | 522 | static AstNode *ast_parse_param_decl(ParseContext *pc, int token_index, int *new_token_index) { |
| 523 | Token *param_name = &pc->tokens->at(token_index); | 523 | Token *param_name = &pc->tokens->at(token_index); |
| 524 | token_index += 1; | 524 | token_index += 1; |
| 525 | ast_expect_token(pc, param_name, TokenIdSymbol); | ||
| 526 | 525 | ||
| 527 | AstNode *node = ast_create_node(pc, NodeTypeParamDecl, param_name); | 526 | if (param_name->id == TokenIdSymbol) { |
| 527 | AstNode *node = ast_create_node(pc, NodeTypeParamDecl, param_name); | ||
| 528 | 528 | ||
| 529 | ast_buf_from_token(pc, param_name, &node->data.param_decl.name); | ||
| 529 | 530 | ||
| 530 | ast_buf_from_token(pc, param_name, &node->data.param_decl.name); | 531 | Token *colon = &pc->tokens->at(token_index); |
| 531 | 532 | token_index += 1; | |
| 532 | Token *colon = &pc->tokens->at(token_index); | 533 | ast_expect_token(pc, colon, TokenIdColon); |
| 533 | token_index += 1; | ||
| 534 | ast_expect_token(pc, colon, TokenIdColon); | ||
| 535 | 534 | ||
| 536 | node->data.param_decl.type = ast_parse_type(pc, token_index, &token_index); | 535 | node->data.param_decl.type = ast_parse_type(pc, token_index, &token_index); |
| 537 | 536 | ||
| 538 | *new_token_index = token_index; | 537 | *new_token_index = token_index; |
| 539 | return node; | 538 | return node; |
| 539 | } else if (param_name->id == TokenIdEllipse) { | ||
| 540 | *new_token_index = token_index; | ||
| 541 | return nullptr; | ||
| 542 | } else { | ||
| 543 | ast_invalid_token_error(pc, param_name); | ||
| 544 | } | ||
| 540 | } | 545 | } |
| 541 | 546 | ||
| 542 | 547 | ||
| 543 | static void ast_parse_param_decl_list(ParseContext *pc, int token_index, int *new_token_index, | 548 | static void ast_parse_param_decl_list(ParseContext *pc, int token_index, int *new_token_index, |
| 544 | ZigList<AstNode *> *params) | 549 | ZigList<AstNode *> *params, bool *is_var_args) |
| 545 | { | 550 | { |
| 551 | *is_var_args = false; | ||
| 552 | |||
| 546 | Token *l_paren = &pc->tokens->at(token_index); | 553 | Token *l_paren = &pc->tokens->at(token_index); |
| 547 | token_index += 1; | 554 | token_index += 1; |
| 548 | ast_expect_token(pc, l_paren, TokenIdLParen); | 555 | ast_expect_token(pc, l_paren, TokenIdLParen); |
| ... | @@ -556,13 +563,21 @@ static void ast_parse_param_decl_list(ParseContext *pc, int token_index, int *ne | ... | @@ -556,13 +563,21 @@ static void ast_parse_param_decl_list(ParseContext *pc, int token_index, int *ne |
| 556 | 563 | ||
| 557 | for (;;) { | 564 | for (;;) { |
| 558 | AstNode *param_decl_node = ast_parse_param_decl(pc, token_index, &token_index); | 565 | AstNode *param_decl_node = ast_parse_param_decl(pc, token_index, &token_index); |
| 559 | params->append(param_decl_node); | 566 | bool expect_end = false; |
| 567 | if (param_decl_node) { | ||
| 568 | params->append(param_decl_node); | ||
| 569 | } else { | ||
| 570 | *is_var_args = true; | ||
| 571 | expect_end = true; | ||
| 572 | } | ||
| 560 | 573 | ||
| 561 | Token *token = &pc->tokens->at(token_index); | 574 | Token *token = &pc->tokens->at(token_index); |
| 562 | token_index += 1; | 575 | token_index += 1; |
| 563 | if (token->id == TokenIdRParen) { | 576 | if (token->id == TokenIdRParen) { |
| 564 | *new_token_index = token_index; | 577 | *new_token_index = token_index; |
| 565 | return; | 578 | return; |
| 579 | } else if (expect_end) { | ||
| 580 | ast_invalid_token_error(pc, token); | ||
| 566 | } else { | 581 | } else { |
| 567 | ast_expect_token(pc, token, TokenIdComma); | 582 | ast_expect_token(pc, token, TokenIdComma); |
| 568 | } | 583 | } |
| ... | @@ -1421,7 +1436,8 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand | ... | @@ -1421,7 +1436,8 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand |
| 1421 | ast_buf_from_token(pc, fn_name, &node->data.fn_proto.name); | 1436 | ast_buf_from_token(pc, fn_name, &node->data.fn_proto.name); |
| 1422 | 1437 | ||
| 1423 | 1438 | ||
| 1424 | ast_parse_param_decl_list(pc, *token_index, token_index, &node->data.fn_proto.params); | 1439 | ast_parse_param_decl_list(pc, *token_index, token_index, |
| 1440 | &node->data.fn_proto.params, &node->data.fn_proto.is_var_args); | ||
| 1425 | 1441 | ||
| 1426 | Token *arrow = &pc->tokens->at(*token_index); | 1442 | Token *arrow = &pc->tokens->at(*token_index); |
| 1427 | if (arrow->id == TokenIdArrow) { | 1443 | if (arrow->id == TokenIdArrow) { |
src/parser.hpp+1| ... | @@ -63,6 +63,7 @@ struct AstNodeFnProto { | ... | @@ -63,6 +63,7 @@ struct AstNodeFnProto { |
| 63 | Buf name; | 63 | Buf name; |
| 64 | ZigList<AstNode *> params; | 64 | ZigList<AstNode *> params; |
| 65 | AstNode *return_type; | 65 | AstNode *return_type; |
| 66 | bool is_var_args; | ||
| 66 | }; | 67 | }; |
| 67 | 68 | ||
| 68 | struct AstNodeFnDef { | 69 | struct AstNodeFnDef { |
src/tokenizer.cpp+36| ... | @@ -104,6 +104,8 @@ enum TokenizeState { | ... | @@ -104,6 +104,8 @@ enum TokenizeState { |
| 104 | TokenizeStateBang, | 104 | TokenizeStateBang, |
| 105 | TokenizeStateLessThan, | 105 | TokenizeStateLessThan, |
| 106 | TokenizeStateGreaterThan, | 106 | TokenizeStateGreaterThan, |
| 107 | TokenizeStateDot, | ||
| 108 | TokenizeStateDotDot, | ||
| 107 | TokenizeStateError, | 109 | TokenizeStateError, |
| 108 | }; | 110 | }; |
| 109 | 111 | ||
| ... | @@ -323,10 +325,40 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -323,10 +325,40 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 323 | begin_token(&t, TokenIdCmpGreaterThan); | 325 | begin_token(&t, TokenIdCmpGreaterThan); |
| 324 | t.state = TokenizeStateGreaterThan; | 326 | t.state = TokenizeStateGreaterThan; |
| 325 | break; | 327 | break; |
| 328 | case '.': | ||
| 329 | begin_token(&t, TokenIdDot); | ||
| 330 | t.state = TokenizeStateDot; | ||
| 331 | break; | ||
| 326 | default: | 332 | default: |
| 327 | tokenize_error(&t, "invalid character: '%c'", c); | 333 | tokenize_error(&t, "invalid character: '%c'", c); |
| 328 | } | 334 | } |
| 329 | break; | 335 | break; |
| 336 | case TokenizeStateDot: | ||
| 337 | switch (c) { | ||
| 338 | case '.': | ||
| 339 | t.state = TokenizeStateDotDot; | ||
| 340 | t.cur_tok->id = TokenIdEllipse; | ||
| 341 | break; | ||
| 342 | default: | ||
| 343 | t.pos -= 1; | ||
| 344 | end_token(&t); | ||
| 345 | t.state = TokenizeStateStart; | ||
| 346 | continue; | ||
| 347 | } | ||
| 348 | break; | ||
| 349 | case TokenizeStateDotDot: | ||
| 350 | switch (c) { | ||
| 351 | case '.': | ||
| 352 | t.state = TokenizeStateStart; | ||
| 353 | end_token(&t); | ||
| 354 | break; | ||
| 355 | default: | ||
| 356 | t.pos -= 1; | ||
| 357 | end_token(&t); | ||
| 358 | t.state = TokenizeStateStart; | ||
| 359 | continue; | ||
| 360 | } | ||
| 361 | break; | ||
| 330 | case TokenizeStateGreaterThan: | 362 | case TokenizeStateGreaterThan: |
| 331 | switch (c) { | 363 | switch (c) { |
| 332 | case '=': | 364 | case '=': |
| ... | @@ -561,9 +593,11 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -561,9 +593,11 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 561 | case TokenizeStateBang: | 593 | case TokenizeStateBang: |
| 562 | case TokenizeStateLessThan: | 594 | case TokenizeStateLessThan: |
| 563 | case TokenizeStateGreaterThan: | 595 | case TokenizeStateGreaterThan: |
| 596 | case TokenizeStateDot: | ||
| 564 | end_token(&t); | 597 | end_token(&t); |
| 565 | break; | 598 | break; |
| 566 | case TokenizeStateSawSlash: | 599 | case TokenizeStateSawSlash: |
| 600 | case TokenizeStateDotDot: | ||
| 567 | tokenize_error(&t, "unexpected EOF"); | 601 | tokenize_error(&t, "unexpected EOF"); |
| 568 | break; | 602 | break; |
| 569 | case TokenizeStateLineComment: | 603 | case TokenizeStateLineComment: |
| ... | @@ -637,6 +671,8 @@ static const char * token_name(Token *token) { | ... | @@ -637,6 +671,8 @@ static const char * token_name(Token *token) { |
| 637 | case TokenIdBitShiftRight: return "BitShiftRight"; | 671 | case TokenIdBitShiftRight: return "BitShiftRight"; |
| 638 | case TokenIdSlash: return "Slash"; | 672 | case TokenIdSlash: return "Slash"; |
| 639 | case TokenIdPercent: return "Percent"; | 673 | case TokenIdPercent: return "Percent"; |
| 674 | case TokenIdDot: return "Dot"; | ||
| 675 | case TokenIdEllipse: return "Ellipse"; | ||
| 640 | } | 676 | } |
| 641 | return "(invalid token)"; | 677 | return "(invalid token)"; |
| 642 | } | 678 | } |
src/tokenizer.hpp+2| ... | @@ -64,6 +64,8 @@ enum TokenId { | ... | @@ -64,6 +64,8 @@ enum TokenId { |
| 64 | TokenIdBitShiftRight, | 64 | TokenIdBitShiftRight, |
| 65 | TokenIdSlash, | 65 | TokenIdSlash, |
| 66 | TokenIdPercent, | 66 | TokenIdPercent, |
| 67 | TokenIdDot, | ||
| 68 | TokenIdEllipse, | ||
| 67 | }; | 69 | }; |
| 68 | 70 | ||
| 69 | struct Token { | 71 | struct Token { |
test/run_tests.cpp+5| ... | @@ -577,6 +577,11 @@ fn f() { | ... | @@ -577,6 +577,11 @@ fn f() { |
| 577 | ".tmp_source.zig:5:8: error: array subscripts must be integers", | 577 | ".tmp_source.zig:5:8: error: array subscripts must be integers", |
| 578 | ".tmp_source.zig:5:19: error: array access of non-array", | 578 | ".tmp_source.zig:5:19: error: array access of non-array", |
| 579 | ".tmp_source.zig:5:19: error: array subscripts must be integers"); | 579 | ".tmp_source.zig:5:19: error: array subscripts must be integers"); |
| 580 | |||
| 581 | add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE( | ||
| 582 | fn f(...) {} | ||
| 583 | )SOURCE", 1, ".tmp_source.zig:2:1: error: variadic arguments only allowed in extern functions"); | ||
| 584 | |||
| 580 | } | 585 | } |
| 581 | 586 | ||
| 582 | static void print_compiler_invocation(TestCase *test_case, Buf *zig_stderr) { | 587 | static void print_compiler_invocation(TestCase *test_case, Buf *zig_stderr) { |