authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-28 16:04:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-04-28 16:04:44-07:00
log46b0b84b90119a1eb70a30f78baa8239cafb2524
tree8dc295fa3eb52dc966444b381724206eb4e445ff
parenta299de2265ae1fc2da31214725ea5bf399848319

ability to specify body of an extern function

closes #101

4 files changed, 32 insertions(+), 13 deletions(-)

doc/langref.md+1-1
...@@ -31,7 +31,7 @@ Directive = "#" "Symbol" "(" Expression ")"...@@ -31,7 +31,7 @@ Directive = "#" "Symbol" "(" Expression ")"
3131
32VisibleMod = "pub" | "export"32VisibleMod = "pub" | "export"
3333
34FnDef = option("inline") FnProto Block34FnDef = option("inline" | "extern") FnProto Block
3535
36ParamDeclList = "(" list(ParamDecl, ",") ")"36ParamDeclList = "(" list(ParamDecl, ",") ")"
3737
src/analyze.cpp+8-8
...@@ -994,9 +994,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -994,9 +994,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
994 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));994 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
995 }995 }
996 } else if (buf_eql_str(name, "debug_safety")) {996 } else if (buf_eql_str(name, "debug_safety")) {
997 if (fn_table_entry->is_extern) {997 if (!fn_table_entry->fn_def_node) {
998 add_node_error(g, directive_node,998 add_node_error(g, directive_node,
999 buf_sprintf("#debug_safety invalid on extern functions"));999 buf_sprintf("#debug_safety valid only on function definitions"));
1000 } else {1000 } else {
1001 bool enable;1001 bool enable;
1002 bool ok = resolve_const_expr_bool(g, import, import->block_context,1002 bool ok = resolve_const_expr_bool(g, import, import->block_context,
...@@ -1018,9 +1018,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -1018,9 +1018,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
1018 buf_sprintf("#condition valid only on exported symbols"));1018 buf_sprintf("#condition valid only on exported symbols"));
1019 }1019 }
1020 } else if (buf_eql_str(name, "static_eval_enable")) {1020 } else if (buf_eql_str(name, "static_eval_enable")) {
1021 if (fn_table_entry->is_extern) {1021 if (!fn_table_entry->fn_def_node) {
1022 add_node_error(g, directive_node,1022 add_node_error(g, directive_node,
1023 buf_sprintf("#static_val_enable invalid on extern functions"));1023 buf_sprintf("#static_val_enable valid only on function definitions"));
1024 } else {1024 } else {
1025 bool enable;1025 bool enable;
1026 bool ok = resolve_const_expr_bool(g, import, import->block_context,1026 bool ok = resolve_const_expr_bool(g, import, import->block_context,
...@@ -1470,9 +1470,9 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN...@@ -1470,9 +1470,9 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
14701470
1471 assert(!is_extern || !is_generic_instance);1471 assert(!is_extern || !is_generic_instance);
14721472
1473 if (!is_extern && proto_node->data.fn_proto.is_var_args) {1473 if (fn_def_node && proto_node->data.fn_proto.is_var_args) {
1474 add_node_error(g, proto_node,1474 add_node_error(g, proto_node,
1475 buf_sprintf("variadic arguments only allowed in extern functions"));1475 buf_sprintf("variadic arguments only allowed in extern function declarations"));
1476 }1476 }
14771477
1478 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);1478 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
...@@ -1480,13 +1480,13 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN...@@ -1480,13 +1480,13 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN
1480 fn_table_entry->proto_node = proto_node;1480 fn_table_entry->proto_node = proto_node;
1481 fn_table_entry->fn_def_node = fn_def_node;1481 fn_table_entry->fn_def_node = fn_def_node;
1482 fn_table_entry->is_extern = is_extern;1482 fn_table_entry->is_extern = is_extern;
1483 fn_table_entry->is_pure = !is_extern;1483 fn_table_entry->is_pure = fn_def_node != nullptr;
14841484
1485 get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_');1485 get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_');
14861486
1487 g->fn_protos.append(fn_table_entry);1487 g->fn_protos.append(fn_table_entry);
14881488
1489 if (!is_extern) {1489 if (fn_def_node) {
1490 g->fn_defs.append(fn_table_entry);1490 g->fn_defs.append(fn_table_entry);
1491 }1491 }
14921492
src/parser.cpp+22-3
...@@ -2414,27 +2414,46 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand...@@ -2414,27 +2414,46 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand
2414}2414}
24152415
2416/*2416/*
2417FnDef = option("inline") FnProto Block2417FnDef = option("inline" | "extern") FnProto Block
2418*/2418*/
2419static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandatory,2419static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandatory,
2420 ZigList<AstNode*> *directives, VisibMod visib_mod)2420 ZigList<AstNode*> *directives, VisibMod visib_mod)
2421{2421{
2422 Token *first_token = &pc->tokens->at(*token_index);2422 Token *first_token = &pc->tokens->at(*token_index);
2423 bool is_inline;2423 bool is_inline;
2424 bool is_extern;
2424 if (first_token->id == TokenIdKeywordInline) {2425 if (first_token->id == TokenIdKeywordInline) {
2425 *token_index += 1;2426 *token_index += 1;
2426 is_inline = true;2427 is_inline = true;
2428 is_extern = false;
2429 } else if (first_token->id == TokenIdKeywordExtern) {
2430 *token_index += 1;
2431 is_extern = true;
2432 is_inline = false;
2427 } else {2433 } else {
2428 is_inline = false;2434 is_inline = false;
2435 is_extern = false;
2429 }2436 }
24302437
2431 AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory, directives, visib_mod);2438 AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory, directives, visib_mod);
2432 if (!fn_proto)2439 if (!fn_proto) {
2440 if (is_inline || is_extern) {
2441 *token_index -= 1;
2442 }
2433 return nullptr;2443 return nullptr;
2434 AstNode *node = ast_create_node(pc, NodeTypeFnDef, first_token);2444 }
24352445
2436 fn_proto->data.fn_proto.is_inline = is_inline;2446 fn_proto->data.fn_proto.is_inline = is_inline;
2447 fn_proto->data.fn_proto.is_extern = is_extern;
24372448
2449 Token *semi_token = &pc->tokens->at(*token_index);
2450 if (semi_token->id == TokenIdSemicolon) {
2451 *token_index += 1;
2452 normalize_parent_ptrs(fn_proto);
2453 return fn_proto;
2454 }
2455
2456 AstNode *node = ast_create_node(pc, NodeTypeFnDef, first_token);
2438 node->data.fn_def.fn_proto = fn_proto;2457 node->data.fn_def.fn_proto = fn_proto;
2439 node->data.fn_def.body = ast_parse_block(pc, token_index, true);2458 node->data.fn_def.body = ast_parse_block(pc, token_index, true);
2440 normalize_parent_ptrs(node);2459 normalize_parent_ptrs(node);
test/run_tests.cpp+1-1
...@@ -819,7 +819,7 @@ fn f() {...@@ -819,7 +819,7 @@ fn f() {
819819
820 add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE(820 add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE(
821fn f(...) {}821fn f(...) {}
822 )SOURCE", 1, ".tmp_source.zig:2:1: error: variadic arguments only allowed in extern functions");822 )SOURCE", 1, ".tmp_source.zig:2:1: error: variadic arguments only allowed in extern function declarations");
823823
824 add_compile_fail_case("write to const global variable", R"SOURCE(824 add_compile_fail_case("write to const global variable", R"SOURCE(
825const x : i32 = 99;825const x : i32 = 99;