authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-28 20:26:40-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-28 20:26:40-07:00
loga5c2de5fee67e35c8173b7051675d49648086cbb
treee6ee63d6daca6d6456e58f866d47e2c426cd9315
parent2bb2e61ee288a02e184e5b8422859a4afcbb4813

ability to specify function type

closes #14

5 files changed, 170 insertions(+), 70 deletions(-)

doc/langref.md+1-1
...@@ -141,7 +141,7 @@ StructLiteralField = "." "Symbol" "=" Expression...@@ -141,7 +141,7 @@ StructLiteralField = "." "Symbol" "=" Expression
141141
142PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%"142PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%"
143143
144PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." "Symbol")144PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." "Symbol")
145145
146ArrayType = "[" option(Expression) "]" option("const") PrefixOpExpression146ArrayType = "[" option(Expression) "]" option("const") PrefixOpExpression
147147
src/all_types.hpp+2
...@@ -189,6 +189,7 @@ struct AstNodeFnProto {...@@ -189,6 +189,7 @@ struct AstNodeFnProto {
189 FnTableEntry *fn_table_entry;189 FnTableEntry *fn_table_entry;
190 bool skip;190 bool skip;
191 TopLevelDecl top_level_decl;191 TopLevelDecl top_level_decl;
192 Expr resolved_expr;
192};193};
193194
194struct AstNodeFnDef {195struct AstNodeFnDef {
...@@ -828,6 +829,7 @@ struct TypeTableEntryFn {...@@ -828,6 +829,7 @@ struct TypeTableEntryFn {
828 bool is_var_args;829 bool is_var_args;
829 int gen_param_count;830 int gen_param_count;
830 LLVMCallConv calling_convention;831 LLVMCallConv calling_convention;
832 bool is_extern;
831 bool is_naked;833 bool is_naked;
832};834};
833835
src/analyze.cpp+114-50
...@@ -451,44 +451,20 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B...@@ -451,44 +451,20 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B
451 return resolve_type(g, *node_ptr);451 return resolve_type(g, *node_ptr);
452}452}
453453
454static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,454static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
455 ImportTableEntry *import)455 TypeTableEntry *expected_type, AstNode *node, bool is_naked)
456{456{
457 assert(node->type == NodeTypeFnProto);457 assert(node->type == NodeTypeFnProto);
458 AstNodeFnProto *fn_proto = &node->data.fn_proto;458 AstNodeFnProto *fn_proto = &node->data.fn_proto;
459459
460 if (fn_proto->skip) {460 if (fn_proto->skip) {
461 return;461 return g->builtin_types.entry_invalid;
462 }462 }
463463
464 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);464 TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
465 fn_table_entry->type_entry = fn_type;465 fn_type->data.fn.is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport);
466 fn_type->data.fn.calling_convention = fn_table_entry->internal_linkage ? LLVMFastCallConv : LLVMCCallConv;466 fn_type->data.fn.is_naked = is_naked;
467467 fn_type->data.fn.calling_convention = fn_proto->is_extern ? LLVMCCallConv : LLVMFastCallConv;
468 for (int i = 0; i < fn_proto->directives->length; i += 1) {
469 AstNode *directive_node = fn_proto->directives->at(i);
470 Buf *name = &directive_node->data.directive.name;
471
472 if (buf_eql_str(name, "attribute")) {
473 Buf *attr_name = &directive_node->data.directive.param;
474 if (fn_table_entry->fn_def_node) {
475 if (buf_eql_str(attr_name, "naked")) {
476 fn_type->data.fn.is_naked = true;
477 } else if (buf_eql_str(attr_name, "inline")) {
478 fn_table_entry->is_inline = true;
479 } else {
480 add_node_error(g, directive_node,
481 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
482 }
483 } else {
484 add_node_error(g, directive_node,
485 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
486 }
487 } else {
488 add_node_error(g, directive_node,
489 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
490 }
491 }
492468
493 int src_param_count = node->data.fn_proto.params.length;469 int src_param_count = node->data.fn_proto.params.length;
494 fn_type->size_in_bits = g->pointer_size_bytes * 8;470 fn_type->size_in_bits = g->pointer_size_bytes * 8;
...@@ -499,10 +475,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -499,10 +475,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
499 // first, analyze the parameters and return type in order they appear in475 // first, analyze the parameters and return type in order they appear in
500 // source code in order for error messages to be in the best order.476 // source code in order for error messages to be in the best order.
501 buf_resize(&fn_type->name, 0);477 buf_resize(&fn_type->name, 0);
502 const char *export_str = fn_table_entry->internal_linkage ? "" : "export ";478 const char *extern_str = fn_type->data.fn.is_extern ? "extern " : "";
503 const char *inline_str = fn_table_entry->is_inline ? "inline " : "";
504 const char *naked_str = fn_type->data.fn.is_naked ? "naked " : "";479 const char *naked_str = fn_type->data.fn.is_naked ? "naked " : "";
505 buf_appendf(&fn_type->name, "%s%s%sfn(", export_str, inline_str, naked_str);480 buf_appendf(&fn_type->name, "%s%sfn(", extern_str, naked_str);
506 for (int i = 0; i < src_param_count; i += 1) {481 for (int i = 0; i < src_param_count; i += 1) {
507 AstNode *child = node->data.fn_proto.params.at(i);482 AstNode *child = node->data.fn_proto.params.at(i);
508 assert(child->type == NodeTypeParamDecl);483 assert(child->type == NodeTypeParamDecl);
...@@ -525,10 +500,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -525,10 +500,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
525 const char *comma = (src_param_count == 0) ? "" : ", ";500 const char *comma = (src_param_count == 0) ? "" : ", ";
526 buf_appendf(&fn_type->name, "%s...", comma);501 buf_appendf(&fn_type->name, "%s...", comma);
527 }502 }
528
529 buf_appendf(&fn_type->name, ")");503 buf_appendf(&fn_type->name, ")");
530 if (return_type->id != TypeTableEntryIdVoid) {504 if (return_type->id != TypeTableEntryIdVoid) {
531 buf_appendf(&fn_type->name, " %s", buf_ptr(&return_type->name));505 buf_appendf(&fn_type->name, " -> %s", buf_ptr(&return_type->name));
532 }506 }
533507
534508
...@@ -593,13 +567,12 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -593,13 +567,12 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
593 fn_type->data.fn.gen_param_count = gen_param_index;567 fn_type->data.fn.gen_param_count = gen_param_index;
594568
595 if (fn_proto->skip) {569 if (fn_proto->skip) {
596 return;570 return g->builtin_types.entry_invalid;
597 }571 }
598572
599 auto table_entry = import->fn_type_table.maybe_get(&fn_type->name);573 auto table_entry = import->fn_type_table.maybe_get(&fn_type->name);
600 if (table_entry) {574 if (table_entry) {
601 fn_type = table_entry->value;575 return table_entry->value;
602 fn_table_entry->type_entry = fn_type;
603 } else {576 } else {
604 fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref,577 fn_type->data.fn.raw_type_ref = LLVMFunctionType(gen_return_type->type_ref,
605 gen_param_types, gen_param_index, fn_type->data.fn.is_var_args);578 gen_param_types, gen_param_index, fn_type->data.fn.is_var_args);
...@@ -608,8 +581,56 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -608,8 +581,56 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
608 param_di_types, gen_param_index + 1, 0);581 param_di_types, gen_param_index + 1, 0);
609582
610 import->fn_type_table.put(&fn_type->name, fn_type);583 import->fn_type_table.put(&fn_type->name, fn_type);
584
585 return fn_type;
586 }
587}
588
589
590static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,
591 ImportTableEntry *import)
592{
593 assert(node->type == NodeTypeFnProto);
594 AstNodeFnProto *fn_proto = &node->data.fn_proto;
595
596 if (fn_proto->skip) {
597 return;
611 }598 }
612599
600 bool is_naked = false;
601 for (int i = 0; i < fn_proto->directives->length; i += 1) {
602 AstNode *directive_node = fn_proto->directives->at(i);
603 Buf *name = &directive_node->data.directive.name;
604
605 if (buf_eql_str(name, "attribute")) {
606 Buf *attr_name = &directive_node->data.directive.param;
607 if (fn_table_entry->fn_def_node) {
608 if (buf_eql_str(attr_name, "naked")) {
609 is_naked = true;
610 } else if (buf_eql_str(attr_name, "inline")) {
611 fn_table_entry->is_inline = true;
612 } else {
613 add_node_error(g, directive_node,
614 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
615 }
616 } else {
617 add_node_error(g, directive_node,
618 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
619 }
620 } else {
621 add_node_error(g, directive_node,
622 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
623 }
624 }
625
626 TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, import->block_context, nullptr, node, is_naked);
627
628 if (fn_type->id == TypeTableEntryIdInvalid) {
629 fn_proto->skip = true;
630 return;
631 }
632
633 fn_table_entry->type_entry = fn_type;
613634
614 fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(&fn_table_entry->symbol_name),635 fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(&fn_table_entry->symbol_name),
615 fn_type->data.fn.raw_type_ref);636 fn_type->data.fn.raw_type_ref);
...@@ -624,7 +645,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -624,7 +645,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
624 LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ?645 LLVMSetLinkage(fn_table_entry->fn_value, fn_table_entry->internal_linkage ?
625 LLVMInternalLinkage : LLVMExternalLinkage);646 LLVMInternalLinkage : LLVMExternalLinkage);
626647
627 if (return_type->id == TypeTableEntryIdUnreachable) {648 if (fn_type->data.fn.src_return_type->id == TypeTableEntryIdUnreachable) {
628 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute);649 LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoReturnAttribute);
629 }650 }
630 LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention);651 LLVMSetFunctionCallConv(fn_table_entry->fn_value, fn_type->data.fn.calling_convention);
...@@ -1353,7 +1374,29 @@ static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTable...@@ -1353,7 +1374,29 @@ static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTable
1353 if (expected_type->id == TypeTableEntryIdFn &&1374 if (expected_type->id == TypeTableEntryIdFn &&
1354 actual_type->id == TypeTableEntryIdFn)1375 actual_type->id == TypeTableEntryIdFn)
1355 {1376 {
1356 zig_panic("TODO types_match_const_cast_only for fns");1377 if (expected_type->data.fn.is_extern != actual_type->data.fn.is_extern) {
1378 return false;
1379 }
1380 if (expected_type->data.fn.is_naked != actual_type->data.fn.is_naked) {
1381 return false;
1382 }
1383 if (!types_match_const_cast_only(expected_type->data.fn.src_return_type,
1384 actual_type->data.fn.src_return_type))
1385 {
1386 return false;
1387 }
1388 if (expected_type->data.fn.src_param_count != actual_type->data.fn.src_param_count) {
1389 return false;
1390 }
1391 for (int i = 0; i < expected_type->data.fn.src_param_count; i += 1) {
1392 // note it's reversed for parameters
1393 if (types_match_const_cast_only(actual_type->data.fn.param_types[i],
1394 expected_type->data.fn.param_types[i]))
1395 {
1396 return false;
1397 }
1398 }
1399 return true;
1357 }1400 }
13581401
13591402
...@@ -2902,6 +2945,18 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import,...@@ -2902,6 +2945,18 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import,
2902 }2945 }
2903}2946}
29042947
2948static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
2949 TypeTableEntry *expected_type, AstNode *node)
2950{
2951 TypeTableEntry *type_entry = analyze_fn_proto_type(g, import, context, expected_type, node, false);
2952
2953 if (type_entry->id == TypeTableEntryIdInvalid) {
2954 return type_entry;
2955 }
2956
2957 return resolve_expr_const_val_as_type(g, node, type_entry);
2958}
2959
2905static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,2960static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
2906 TypeTableEntry *expected_type, AstNode *node)2961 TypeTableEntry *expected_type, AstNode *node)
2907{2962{
...@@ -4240,6 +4295,9 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -4240,6 +4295,9 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
4240 case NodeTypeArrayType:4295 case NodeTypeArrayType:
4241 return_type = analyze_array_type(g, import, context, expected_type, node);4296 return_type = analyze_array_type(g, import, context, expected_type, node);
4242 break;4297 break;
4298 case NodeTypeFnProto:
4299 return_type = analyze_fn_proto_expr(g, import, context, expected_type, node);
4300 break;
4243 case NodeTypeErrorType:4301 case NodeTypeErrorType:
4244 return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_pure_error);4302 return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_pure_error);
4245 break;4303 break;
...@@ -4250,7 +4308,6 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -4250,7 +4308,6 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
4250 case NodeTypeSwitchRange:4308 case NodeTypeSwitchRange:
4251 case NodeTypeDirective:4309 case NodeTypeDirective:
4252 case NodeTypeFnDecl:4310 case NodeTypeFnDecl:
4253 case NodeTypeFnProto:
4254 case NodeTypeParamDecl:4311 case NodeTypeParamDecl:
4255 case NodeTypeRoot:4312 case NodeTypeRoot:
4256 case NodeTypeRootExportDecl:4313 case NodeTypeRootExportDecl:
...@@ -4555,13 +4612,23 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode...@@ -4555,13 +4612,23 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
4555 collect_expr_decl_deps(g, import, node->data.switch_range.start, decl_node);4612 collect_expr_decl_deps(g, import, node->data.switch_range.start, decl_node);
4556 collect_expr_decl_deps(g, import, node->data.switch_range.end, decl_node);4613 collect_expr_decl_deps(g, import, node->data.switch_range.end, decl_node);
4557 break;4614 break;
4558 case NodeTypeVariableDeclaration:
4559 case NodeTypeFnProto:4615 case NodeTypeFnProto:
4616 // remember that fn proto node is used for function definitions as well
4617 // as types
4618 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
4619 AstNode *param = node->data.fn_proto.params.at(i);
4620 collect_expr_decl_deps(g, import, param, decl_node);
4621 }
4622 collect_expr_decl_deps(g, import, node->data.fn_proto.return_type, decl_node);
4623 break;
4624 case NodeTypeParamDecl:
4625 collect_expr_decl_deps(g, import, node->data.param_decl.type, decl_node);
4626 break;
4627 case NodeTypeVariableDeclaration:
4560 case NodeTypeRootExportDecl:4628 case NodeTypeRootExportDecl:
4561 case NodeTypeFnDef:4629 case NodeTypeFnDef:
4562 case NodeTypeRoot:4630 case NodeTypeRoot:
4563 case NodeTypeFnDecl:4631 case NodeTypeFnDecl:
4564 case NodeTypeParamDecl:
4565 case NodeTypeDirective:4632 case NodeTypeDirective:
4566 case NodeTypeImport:4633 case NodeTypeImport:
4567 case NodeTypeCImport:4634 case NodeTypeCImport:
...@@ -4705,12 +4772,8 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast...@@ -4705,12 +4772,8 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
4705 // determine which other top level declarations this function prototype depends on.4772 // determine which other top level declarations this function prototype depends on.
4706 TopLevelDecl *decl_node = &node->data.fn_proto.top_level_decl;4773 TopLevelDecl *decl_node = &node->data.fn_proto.top_level_decl;
4707 decl_node->deps.init(1);4774 decl_node->deps.init(1);
4708 for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {4775
4709 AstNode *param_node = node->data.fn_proto.params.at(i);4776 collect_expr_decl_deps(g, import, node, decl_node);
4710 assert(param_node->type == NodeTypeParamDecl);
4711 collect_expr_decl_deps(g, import, param_node->data.param_decl.type, decl_node);
4712 }
4713 collect_expr_decl_deps(g, import, node->data.fn_proto.return_type, decl_node);
47144777
4715 decl_node->name = name;4778 decl_node->name = name;
4716 decl_node->import = import;4779 decl_node->import = import;
...@@ -4999,11 +5062,12 @@ Expr *get_resolved_expr(AstNode *node) {...@@ -4999,11 +5062,12 @@ Expr *get_resolved_expr(AstNode *node) {
4999 return &node->data.error_type.resolved_expr;5062 return &node->data.error_type.resolved_expr;
5000 case NodeTypeSwitchExpr:5063 case NodeTypeSwitchExpr:
5001 return &node->data.switch_expr.resolved_expr;5064 return &node->data.switch_expr.resolved_expr;
5065 case NodeTypeFnProto:
5066 return &node->data.fn_proto.resolved_expr;
5002 case NodeTypeSwitchProng:5067 case NodeTypeSwitchProng:
5003 case NodeTypeSwitchRange:5068 case NodeTypeSwitchRange:
5004 case NodeTypeRoot:5069 case NodeTypeRoot:
5005 case NodeTypeRootExportDecl:5070 case NodeTypeRootExportDecl:
5006 case NodeTypeFnProto:
5007 case NodeTypeFnDef:5071 case NodeTypeFnDef:
5008 case NodeTypeFnDecl:5072 case NodeTypeFnDecl:
5009 case NodeTypeParamDecl:5073 case NodeTypeParamDecl:
src/parser.cpp+36-19
...@@ -503,6 +503,8 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda...@@ -503,6 +503,8 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
503static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory);503static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory);
504static AstNode *ast_parse_unwrap_expr(ParseContext *pc, int *token_index, bool mandatory);504static AstNode *ast_parse_unwrap_expr(ParseContext *pc, int *token_index, bool mandatory);
505static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory);505static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory);
506static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory,
507 ZigList<AstNode*> *directives, VisibMod visib_mod);
506508
507static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {509static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
508 if (token->id == token_id) {510 if (token->id == token_id) {
...@@ -671,7 +673,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool...@@ -671,7 +673,7 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool
671 Token *l_paren = &pc->tokens->at(*token_index);673 Token *l_paren = &pc->tokens->at(*token_index);
672 if (l_paren->id != TokenIdLParen) {674 if (l_paren->id != TokenIdLParen) {
673 if (mandatory) {675 if (mandatory) {
674 ast_invalid_token_error(pc, l_paren);676 ast_expect_token(pc, l_paren, TokenIdLParen);
675 } else {677 } else {
676 return nullptr;678 return nullptr;
677 }679 }
...@@ -695,7 +697,7 @@ static AstNode *ast_parse_array_type_expr(ParseContext *pc, int *token_index, bo...@@ -695,7 +697,7 @@ static AstNode *ast_parse_array_type_expr(ParseContext *pc, int *token_index, bo
695 Token *l_bracket = &pc->tokens->at(*token_index);697 Token *l_bracket = &pc->tokens->at(*token_index);
696 if (l_bracket->id != TokenIdLBracket) {698 if (l_bracket->id != TokenIdLBracket) {
697 if (mandatory) {699 if (mandatory) {
698 ast_invalid_token_error(pc, l_bracket);700 ast_expect_token(pc, l_bracket, TokenIdLBracket);
699 } else {701 } else {
700 return nullptr;702 return nullptr;
701 }703 }
...@@ -865,7 +867,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand...@@ -865,7 +867,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
865867
866 if (asm_token->id != TokenIdKeywordAsm) {868 if (asm_token->id != TokenIdKeywordAsm) {
867 if (mandatory) {869 if (mandatory) {
868 ast_invalid_token_error(pc, asm_token);870 ast_expect_token(pc, asm_token, TokenIdKeywordAsm);
869 } else {871 } else {
870 return nullptr;872 return nullptr;
871 }873 }
...@@ -905,7 +907,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand...@@ -905,7 +907,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
905}907}
906908
907/*909/*
908PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("error" "." "Symbol")910PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." "Symbol")
909KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined" | "error"911KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined" | "error"
910*/912*/
911static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {913static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
...@@ -956,6 +958,11 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool...@@ -956,6 +958,11 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
956 AstNode *node = ast_create_node(pc, NodeTypeErrorType, token);958 AstNode *node = ast_create_node(pc, NodeTypeErrorType, token);
957 *token_index += 1;959 *token_index += 1;
958 return node;960 return node;
961 } else if (token->id == TokenIdKeywordExtern) {
962 *token_index += 1;
963 AstNode *node = ast_parse_fn_proto(pc, token_index, true, nullptr, VisibModPrivate);
964 node->data.fn_proto.is_extern = true;
965 return node;
959 } else if (token->id == TokenIdAtSign) {966 } else if (token->id == TokenIdAtSign) {
960 *token_index += 1;967 *token_index += 1;
961 Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);968 Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
...@@ -1002,6 +1009,11 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool...@@ -1002,6 +1009,11 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
1002 return array_type_node;1009 return array_type_node;
1003 }1010 }
10041011
1012 AstNode *fn_proto_node = ast_parse_fn_proto(pc, token_index, false, nullptr, VisibModPrivate);
1013 if (fn_proto_node) {
1014 return fn_proto_node;
1015 }
1016
1005 AstNode *asm_expr = ast_parse_asm_expr(pc, token_index, false);1017 AstNode *asm_expr = ast_parse_asm_expr(pc, token_index, false);
1006 if (asm_expr) {1018 if (asm_expr) {
1007 return asm_expr;1019 return asm_expr;
...@@ -1055,7 +1067,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, int *token_index,...@@ -1055,7 +1067,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, int *token_index,
1055 token = &pc->tokens->at(*token_index);1067 token = &pc->tokens->at(*token_index);
1056 continue;1068 continue;
1057 } else if (comma_tok->id != TokenIdRBrace) {1069 } else if (comma_tok->id != TokenIdRBrace) {
1058 ast_invalid_token_error(pc, comma_tok);1070 ast_expect_token(pc, comma_tok, TokenIdRBrace);
1059 } else {1071 } else {
1060 *token_index += 1;1072 *token_index += 1;
1061 break;1073 break;
...@@ -1084,7 +1096,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, int *token_index,...@@ -1084,7 +1096,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, int *token_index,
1084 token = &pc->tokens->at(*token_index);1096 token = &pc->tokens->at(*token_index);
1085 continue;1097 continue;
1086 } else if (comma_tok->id != TokenIdRBrace) {1098 } else if (comma_tok->id != TokenIdRBrace) {
1087 ast_invalid_token_error(pc, comma_tok);1099 ast_expect_token(pc, comma_tok, TokenIdRBrace);
1088 } else {1100 } else {
1089 *token_index += 1;1101 *token_index += 1;
1090 break;1102 break;
...@@ -1555,7 +1567,7 @@ static AstNode *ast_parse_else(ParseContext *pc, int *token_index, bool mandator...@@ -1555,7 +1567,7 @@ static AstNode *ast_parse_else(ParseContext *pc, int *token_index, bool mandator
15551567
1556 if (else_token->id != TokenIdKeywordElse) {1568 if (else_token->id != TokenIdKeywordElse) {
1557 if (mandatory) {1569 if (mandatory) {
1558 ast_invalid_token_error(pc, else_token);1570 ast_expect_token(pc, else_token, TokenIdKeywordElse);
1559 } else {1571 } else {
1560 return nullptr;1572 return nullptr;
1561 }1573 }
...@@ -1574,7 +1586,7 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda...@@ -1574,7 +1586,7 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
1574 Token *if_tok = &pc->tokens->at(*token_index);1586 Token *if_tok = &pc->tokens->at(*token_index);
1575 if (if_tok->id != TokenIdKeywordIf) {1587 if (if_tok->id != TokenIdKeywordIf) {
1576 if (mandatory) {1588 if (mandatory) {
1577 ast_invalid_token_error(pc, if_tok);1589 ast_expect_token(pc, if_tok, TokenIdKeywordIf);
1578 } else {1590 } else {
1579 return nullptr;1591 return nullptr;
1580 }1592 }
...@@ -1637,7 +1649,8 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m...@@ -1637,7 +1649,8 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
1637 kind = ReturnKindError;1649 kind = ReturnKindError;
1638 *token_index += 2;1650 *token_index += 2;
1639 } else if (mandatory) {1651 } else if (mandatory) {
1640 ast_invalid_token_error(pc, token);1652 ast_expect_token(pc, next_token, TokenIdKeywordReturn);
1653 zig_unreachable();
1641 } else {1654 } else {
1642 return nullptr;1655 return nullptr;
1643 }1656 }
...@@ -1647,7 +1660,8 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m...@@ -1647,7 +1660,8 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
1647 kind = ReturnKindMaybe;1660 kind = ReturnKindMaybe;
1648 *token_index += 2;1661 *token_index += 2;
1649 } else if (mandatory) {1662 } else if (mandatory) {
1650 ast_invalid_token_error(pc, token);1663 ast_expect_token(pc, next_token, TokenIdKeywordReturn);
1664 zig_unreachable();
1651 } else {1665 } else {
1652 return nullptr;1666 return nullptr;
1653 }1667 }
...@@ -1655,7 +1669,8 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m...@@ -1655,7 +1669,8 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
1655 kind = ReturnKindUnconditional;1669 kind = ReturnKindUnconditional;
1656 *token_index += 1;1670 *token_index += 1;
1657 } else if (mandatory) {1671 } else if (mandatory) {
1658 ast_invalid_token_error(pc, token);1672 ast_expect_token(pc, token, TokenIdKeywordReturn);
1673 zig_unreachable();
1659 } else {1674 } else {
1660 return nullptr;1675 return nullptr;
1661 }1676 }
...@@ -1756,7 +1771,7 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool ma...@@ -1756,7 +1771,7 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool ma
17561771
1757 if (token->id != TokenIdKeywordWhile) {1772 if (token->id != TokenIdKeywordWhile) {
1758 if (mandatory) {1773 if (mandatory) {
1759 ast_invalid_token_error(pc, token);1774 ast_expect_token(pc, token, TokenIdKeywordWhile);
1760 } else {1775 } else {
1761 return nullptr;1776 return nullptr;
1762 }1777 }
...@@ -1791,7 +1806,7 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, int *token_index, bool mand...@@ -1791,7 +1806,7 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, int *token_index, bool mand
17911806
1792 if (token->id != TokenIdKeywordFor) {1807 if (token->id != TokenIdKeywordFor) {
1793 if (mandatory) {1808 if (mandatory) {
1794 ast_invalid_token_error(pc, token);1809 ast_expect_token(pc, token, TokenIdKeywordFor);
1795 } else {1810 } else {
1796 return nullptr;1811 return nullptr;
1797 }1812 }
...@@ -1829,7 +1844,7 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, int *token_index, bool m...@@ -1829,7 +1844,7 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, int *token_index, bool m
18291844
1830 if (token->id != TokenIdKeywordSwitch) {1845 if (token->id != TokenIdKeywordSwitch) {
1831 if (mandatory) {1846 if (mandatory) {
1832 ast_invalid_token_error(pc, token);1847 ast_expect_token(pc, token, TokenIdKeywordSwitch);
1833 } else {1848 } else {
1834 return nullptr;1849 return nullptr;
1835 }1850 }
...@@ -2082,7 +2097,7 @@ static AstNode *ast_parse_label(ParseContext *pc, int *token_index, bool mandato...@@ -2082,7 +2097,7 @@ static AstNode *ast_parse_label(ParseContext *pc, int *token_index, bool mandato
2082 Token *symbol_token = &pc->tokens->at(*token_index);2097 Token *symbol_token = &pc->tokens->at(*token_index);
2083 if (symbol_token->id != TokenIdSymbol) {2098 if (symbol_token->id != TokenIdSymbol) {
2084 if (mandatory) {2099 if (mandatory) {
2085 ast_invalid_token_error(pc, symbol_token);2100 ast_expect_token(pc, symbol_token, TokenIdSymbol);
2086 } else {2101 } else {
2087 return nullptr;2102 return nullptr;
2088 }2103 }
...@@ -2091,7 +2106,7 @@ static AstNode *ast_parse_label(ParseContext *pc, int *token_index, bool mandato...@@ -2091,7 +2106,7 @@ static AstNode *ast_parse_label(ParseContext *pc, int *token_index, bool mandato
2091 Token *colon_token = &pc->tokens->at(*token_index + 1);2106 Token *colon_token = &pc->tokens->at(*token_index + 1);
2092 if (colon_token->id != TokenIdColon) {2107 if (colon_token->id != TokenIdColon) {
2093 if (mandatory) {2108 if (mandatory) {
2094 ast_invalid_token_error(pc, colon_token);2109 ast_expect_token(pc, colon_token, TokenIdColon);
2095 } else {2110 } else {
2096 return nullptr;2111 return nullptr;
2097 }2112 }
...@@ -2122,7 +2137,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato...@@ -2122,7 +2137,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
21222137
2123 if (last_token->id != TokenIdLBrace) {2138 if (last_token->id != TokenIdLBrace) {
2124 if (mandatory) {2139 if (mandatory) {
2125 ast_invalid_token_error(pc, last_token);2140 ast_expect_token(pc, last_token, TokenIdLBrace);
2126 } else {2141 } else {
2127 return nullptr;2142 return nullptr;
2128 }2143 }
...@@ -2245,7 +2260,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, int *token_index, bool m...@@ -2245,7 +2260,7 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, int *token_index, bool m
2245 Token *extern_kw = &pc->tokens->at(*token_index);2260 Token *extern_kw = &pc->tokens->at(*token_index);
2246 if (extern_kw->id != TokenIdKeywordExtern) {2261 if (extern_kw->id != TokenIdKeywordExtern) {
2247 if (mandatory) {2262 if (mandatory) {
2248 ast_invalid_token_error(pc, extern_kw);2263 ast_expect_token(pc, extern_kw, TokenIdKeywordExtern);
2249 } else {2264 } else {
2250 return nullptr;2265 return nullptr;
2251 }2266 }
...@@ -2591,7 +2606,9 @@ void normalize_parent_ptrs(AstNode *node) {...@@ -2591,7 +2606,9 @@ void normalize_parent_ptrs(AstNode *node) {
2591 break;2606 break;
2592 case NodeTypeFnProto:2607 case NodeTypeFnProto:
2593 set_field(&node->data.fn_proto.return_type);2608 set_field(&node->data.fn_proto.return_type);
2594 set_list_fields(node->data.fn_proto.directives);2609 if (node->data.fn_proto.directives) {
2610 set_list_fields(node->data.fn_proto.directives);
2611 }
2595 set_list_fields(&node->data.fn_proto.params);2612 set_list_fields(&node->data.fn_proto.params);
2596 break;2613 break;
2597 case NodeTypeFnDef:2614 case NodeTypeFnDef:
test/run_tests.cpp+17
...@@ -1866,6 +1866,23 @@ fn f(i32) {}...@@ -1866,6 +1866,23 @@ fn f(i32) {}
1866 )SOURCE", 2,1866 )SOURCE", 2,
1867 ".tmp_source.zig:2:1: error: missing function name",1867 ".tmp_source.zig:2:1: error: missing function name",
1868 ".tmp_source.zig:3:6: error: missing parameter name");1868 ".tmp_source.zig:3:6: error: missing parameter name");
1869
1870 add_compile_fail_case("wrong function type", R"SOURCE(
1871const fns = []fn(){ a, b, c };
1872fn a() -> i32 {0}
1873fn b() -> i32 {1}
1874fn c() -> i32 {2}
1875 )SOURCE", 3,
1876 ".tmp_source.zig:2:21: error: expected type 'fn()', got 'fn() -> i32'",
1877 ".tmp_source.zig:2:24: error: expected type 'fn()', got 'fn() -> i32'",
1878 ".tmp_source.zig:2:27: error: expected type 'fn()', got 'fn() -> i32'");
1879
1880 add_compile_fail_case("extern function pointer mismatch", R"SOURCE(
1881const fns = [](fn(i32)->i32){ a, b, c };
1882pub fn a(x: i32) -> i32 {x + 0}
1883pub fn b(x: i32) -> i32 {x + 1}
1884export fn c(x: i32) -> i32 {x + 2}
1885 )SOURCE", 1, ".tmp_source.zig:2:37: error: expected type 'fn(i32) -> i32', got 'extern fn(i32) -> i32'");
1869}1886}
18701887
1871//////////////////////////////////////////////////////////////////////////////1888//////////////////////////////////////////////////////////////////////////////