authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-15 23:30:05-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-02-16 16:41:56-07:00
log77ffb5075bd550893b9f6ac99f151b1d55a8040e
treed7cde8b3527f2458f216562f42b5957fefc477e9
parent91101f08c24a931e8e0ecbe46d80df759135332c

update bootstrap to work for macos too

* Directives can have arbitrary expressions as parameters * Fix switch statement not generating code sometimes * Rename "main" fn in bootstrap.zig to "zig_user_main" to avoid name collisions * codegen: fix badref when unreachable is last thing in an expression * support #condition directive on exported functions

8 files changed, 208 insertions(+), 141 deletions(-)

doc/langref.md+1-1
...@@ -31,7 +31,7 @@ ExternDecl = "extern" (FnProto | VariableDeclaration) ";"...@@ -31,7 +31,7 @@ ExternDecl = "extern" (FnProto | VariableDeclaration) ";"
3131
32FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr)32FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr)
3333
34Directive = "#" "Symbol" "(" "String" ")"34Directive = "#" "Symbol" "(" Expression ")"
3535
36VisibleMod = "pub" | "export"36VisibleMod = "pub" | "export"
3737
src/all_types.hpp+2-1
...@@ -427,7 +427,7 @@ struct AstNodeFieldAccessExpr {...@@ -427,7 +427,7 @@ struct AstNodeFieldAccessExpr {
427427
428struct AstNodeDirective {428struct AstNodeDirective {
429 Buf name;429 Buf name;
430 Buf param;430 AstNode *expr;
431};431};
432432
433struct AstNodeRootExportDecl {433struct AstNodeRootExportDecl {
...@@ -526,6 +526,7 @@ struct AstNodeSwitchExpr {...@@ -526,6 +526,7 @@ struct AstNodeSwitchExpr {
526526
527 // populated by semantic analyzer527 // populated by semantic analyzer
528 Expr resolved_expr;528 Expr resolved_expr;
529 int const_chosen_prong_index;
529};530};
530531
531struct AstNodeSwitchProng {532struct AstNodeSwitchProng {
src/analyze.cpp+110-56
...@@ -816,6 +816,53 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor...@@ -816,6 +816,53 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
816 return get_fn_type(g, &fn_type_id);816 return get_fn_type(g, &fn_type_id);
817}817}
818818
819static Buf *resolve_const_expr_str(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode **node) {
820 TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);
821 TypeTableEntry *resolved_type = analyze_expression(g, import, context, str_type, *node);
822
823 if (resolved_type->id == TypeTableEntryIdInvalid) {
824 return nullptr;
825 }
826
827 ConstExprValue *const_str_val = &get_resolved_expr(*node)->const_val;
828
829 if (!const_str_val->ok) {
830 add_node_error(g, *node, buf_sprintf("unable to resolve constant expression"));
831 return nullptr;
832 }
833
834 ConstExprValue *ptr_field = const_str_val->data.x_struct.fields[0];
835 uint64_t len = ptr_field->data.x_ptr.len;
836 Buf *result = buf_alloc();
837 for (uint64_t i = 0; i < len; i += 1) {
838 ConstExprValue *char_val = ptr_field->data.x_ptr.ptr[i];
839 uint64_t big_c = char_val->data.x_bignum.data.x_uint;
840 assert(big_c <= UINT8_MAX);
841 uint8_t c = big_c;
842 buf_append_char(result, c);
843 }
844 return result;
845}
846
847static bool resolve_const_expr_bool(CodeGen *g, ImportTableEntry *import, BlockContext *context,
848 AstNode **node, bool *value)
849{
850 TypeTableEntry *resolved_type = analyze_expression(g, import, context, g->builtin_types.entry_bool, *node);
851
852 if (resolved_type->id == TypeTableEntryIdInvalid) {
853 return false;
854 }
855
856 ConstExprValue *const_bool_val = &get_resolved_expr(*node)->const_val;
857
858 if (!const_bool_val->ok) {
859 add_node_error(g, *node, buf_sprintf("unable to resolve constant expression"));
860 return false;
861 }
862
863 *value = const_bool_val->data.x_bool;
864 return true;
865}
819866
820static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,867static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,
821 ImportTableEntry *import)868 ImportTableEntry *import)
...@@ -839,23 +886,38 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -839,23 +886,38 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
839 Buf *name = &directive_node->data.directive.name;886 Buf *name = &directive_node->data.directive.name;
840887
841 if (buf_eql_str(name, "attribute")) {888 if (buf_eql_str(name, "attribute")) {
842 Buf *attr_name = &directive_node->data.directive.param;
843 if (fn_table_entry->fn_def_node) {889 if (fn_table_entry->fn_def_node) {
844 if (buf_eql_str(attr_name, "naked")) {890 Buf *attr_name = resolve_const_expr_str(g, import, import->block_context,
845 is_naked = true;891 &directive_node->data.directive.expr);
846 } else if (buf_eql_str(attr_name, "cold")) {892 if (attr_name) {
847 is_cold = true;893 if (buf_eql_str(attr_name, "naked")) {
848 } else if (buf_eql_str(attr_name, "test")) {894 is_naked = true;
849 is_test = true;895 } else if (buf_eql_str(attr_name, "cold")) {
850 g->test_fn_count += 1;896 is_cold = true;
851 } else {897 } else if (buf_eql_str(attr_name, "test")) {
852 add_node_error(g, directive_node,898 is_test = true;
853 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));899 g->test_fn_count += 1;
900 } else {
901 add_node_error(g, directive_node,
902 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
903 }
854 }904 }
855 } else {905 } else {
856 add_node_error(g, directive_node,906 add_node_error(g, directive_node,
857 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));907 buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
858 }908 }
909 } else if (buf_eql_str(name, "condition")) {
910 if (fn_proto->visib_mod == VisibModExport) {
911 bool include;
912 bool ok = resolve_const_expr_bool(g, import, import->block_context,
913 &directive_node->data.directive.expr, &include);
914 if (ok && !include) {
915 fn_proto->visib_mod = VisibModPub;
916 }
917 } else {
918 add_node_error(g, directive_node,
919 buf_sprintf("#condition valid only on exported symbols"));
920 }
859 } else {921 } else {
860 add_node_error(g, directive_node,922 add_node_error(g, directive_node,
861 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));923 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
...@@ -863,6 +925,15 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t...@@ -863,6 +925,15 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
863 }925 }
864 }926 }
865927
928 bool is_internal = (fn_proto->visib_mod != VisibModExport);
929 bool is_c_compat = !is_internal || fn_proto->is_extern;
930 fn_table_entry->internal_linkage = !is_c_compat;
931 if (!is_internal) {
932 fn_table_entry->ref_count += 1;
933 }
934
935
936
866 TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, import->block_context, nullptr, node,937 TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, import->block_context, nullptr, node,
867 is_naked, is_cold);938 is_naked, is_cold);
868939
...@@ -1242,8 +1313,6 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,...@@ -1242,8 +1313,6 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
12421313
1243 auto entry = fn_table->maybe_get(proto_name);1314 auto entry = fn_table->maybe_get(proto_name);
1244 bool skip = false;1315 bool skip = false;
1245 bool is_internal = (proto_node->data.fn_proto.visib_mod != VisibModExport);
1246 bool is_c_compat = !is_internal || is_extern;
1247 bool is_pub = (proto_node->data.fn_proto.visib_mod != VisibModPrivate);1316 bool is_pub = (proto_node->data.fn_proto.visib_mod != VisibModPrivate);
1248 if (entry) {1317 if (entry) {
1249 add_node_error(g, proto_node,1318 add_node_error(g, proto_node,
...@@ -1263,10 +1332,8 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,...@@ -1263,10 +1332,8 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
1263 fn_table_entry->import_entry = import;1332 fn_table_entry->import_entry = import;
1264 fn_table_entry->proto_node = proto_node;1333 fn_table_entry->proto_node = proto_node;
1265 fn_table_entry->fn_def_node = fn_def_node;1334 fn_table_entry->fn_def_node = fn_def_node;
1266 fn_table_entry->internal_linkage = !is_c_compat;
1267 fn_table_entry->is_extern = is_extern;1335 fn_table_entry->is_extern = is_extern;
1268 fn_table_entry->member_of_struct = struct_type;1336 fn_table_entry->member_of_struct = struct_type;
1269 fn_table_entry->ref_count = (proto_node->data.fn_proto.visib_mod == VisibModExport) ? 1 : 0;
12701337
1271 if (struct_type) {1338 if (struct_type) {
1272 buf_resize(&fn_table_entry->symbol_name, 0);1339 buf_resize(&fn_table_entry->symbol_name, 0);
...@@ -1290,7 +1357,7 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,...@@ -1290,7 +1357,7 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
1290 g->main_fn = fn_table_entry;1357 g->main_fn = fn_table_entry;
12911358
1292 if (g->bootstrap_import && !g->is_test_build) {1359 if (g->bootstrap_import && !g->is_test_build) {
1293 g->bootstrap_import->fn_table.put(proto_name, fn_table_entry);1360 g->bootstrap_import->fn_table.put(buf_create_from_str("zig_user_main"), fn_table_entry);
1294 }1361 }
1295 }1362 }
1296 bool is_test_main_fn = !struct_type && (import == g->test_runner_import) && buf_eql_str(proto_name, "main");1363 bool is_test_main_fn = !struct_type && (import == g->test_runner_import) && buf_eql_str(proto_name, "main");
...@@ -4246,54 +4313,33 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry...@@ -4246,54 +4313,33 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
4246 {4313 {
4247 AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field;4314 AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field;
42484315
4249 TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true);4316 Buf *var_name = resolve_const_expr_str(g, import, context, str_node);
4250 TypeTableEntry *resolved_type = analyze_expression(g, import, context, str_type, *str_node);4317 if (!var_name) {
42514318 return g->builtin_types.entry_invalid;
4252 if (resolved_type->id == TypeTableEntryIdInvalid) {
4253 return resolved_type;
4254 }
4255
4256 ConstExprValue *const_str_val = &get_resolved_expr(*str_node)->const_val;
4257
4258 if (!const_str_val->ok) {
4259 add_node_error(g, *str_node, buf_sprintf("@compile_var requires constant expression"));
4260 return g->builtin_types.entry_void;
4261 }
4262
4263 ConstExprValue *ptr_field = const_str_val->data.x_struct.fields[0];
4264 uint64_t len = ptr_field->data.x_ptr.len;
4265 Buf var_name = BUF_INIT;
4266 buf_resize(&var_name, 0);
4267 for (uint64_t i = 0; i < len; i += 1) {
4268 ConstExprValue *char_val = ptr_field->data.x_ptr.ptr[i];
4269 uint64_t big_c = char_val->data.x_bignum.data.x_uint;
4270 assert(big_c <= UINT8_MAX);
4271 uint8_t c = big_c;
4272 buf_append_char(&var_name, c);
4273 }4319 }
42744320
4275 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;4321 ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
4276 const_val->ok = true;4322 const_val->ok = true;
4277 const_val->depends_on_compile_var = true;4323 const_val->depends_on_compile_var = true;
42784324
4279 if (buf_eql_str(&var_name, "is_big_endian")) {4325 if (buf_eql_str(var_name, "is_big_endian")) {
4280 return resolve_expr_const_val_as_bool(g, node, g->is_big_endian, true);4326 return resolve_expr_const_val_as_bool(g, node, g->is_big_endian, true);
4281 } else if (buf_eql_str(&var_name, "is_release")) {4327 } else if (buf_eql_str(var_name, "is_release")) {
4282 return resolve_expr_const_val_as_bool(g, node, g->is_release_build, true);4328 return resolve_expr_const_val_as_bool(g, node, g->is_release_build, true);
4283 } else if (buf_eql_str(&var_name, "is_test")) {4329 } else if (buf_eql_str(var_name, "is_test")) {
4284 return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true);4330 return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true);
4285 } else if (buf_eql_str(&var_name, "os")) {4331 } else if (buf_eql_str(var_name, "os")) {
4286 const_val->data.x_enum.tag = g->target_os_index;4332 const_val->data.x_enum.tag = g->target_os_index;
4287 return g->builtin_types.entry_os_enum;4333 return g->builtin_types.entry_os_enum;
4288 } else if (buf_eql_str(&var_name, "arch")) {4334 } else if (buf_eql_str(var_name, "arch")) {
4289 const_val->data.x_enum.tag = g->target_arch_index;4335 const_val->data.x_enum.tag = g->target_arch_index;
4290 return g->builtin_types.entry_arch_enum;4336 return g->builtin_types.entry_arch_enum;
4291 } else if (buf_eql_str(&var_name, "environ")) {4337 } else if (buf_eql_str(var_name, "environ")) {
4292 const_val->data.x_enum.tag = g->target_environ_index;4338 const_val->data.x_enum.tag = g->target_environ_index;
4293 return g->builtin_types.entry_environ_enum;4339 return g->builtin_types.entry_environ_enum;
4294 } else {4340 } else {
4295 add_node_error(g, *str_node,4341 add_node_error(g, *str_node,
4296 buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(&var_name)));4342 buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(var_name)));
4297 return g->builtin_types.entry_invalid;4343 return g->builtin_types.entry_invalid;
4298 }4344 }
4299 }4345 }
...@@ -4740,7 +4786,8 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,...@@ -4740,7 +4786,8 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
4740 field_use_counts = allocate<int>(expr_type->data.enumeration.field_count);4786 field_use_counts = allocate<int>(expr_type->data.enumeration.field_count);
4741 }4787 }
47424788
4743 int const_chosen_prong_index = -1;4789 int *const_chosen_prong_index = &node->data.switch_expr.const_chosen_prong_index;
4790 *const_chosen_prong_index = -1;
4744 AstNode *else_prong = nullptr;4791 AstNode *else_prong = nullptr;
4745 for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {4792 for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
4746 AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);4793 AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
...@@ -4756,8 +4803,8 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,...@@ -4756,8 +4803,8 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
4756 }4803 }
4757 var_type = expr_type;4804 var_type = expr_type;
4758 var_is_target_expr = true;4805 var_is_target_expr = true;
4759 if (const_chosen_prong_index == -1) {4806 if (*const_chosen_prong_index == -1 && expr_val->ok) {
4760 const_chosen_prong_index = prong_i;4807 *const_chosen_prong_index = prong_i;
4761 }4808 }
4762 } else {4809 } else {
4763 bool all_agree_on_var_type = true;4810 bool all_agree_on_var_type = true;
...@@ -4792,7 +4839,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,...@@ -4792,7 +4839,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
4792 }4839 }
4793 if (!any_errors && expr_val->ok) {4840 if (!any_errors && expr_val->ok) {
4794 if (expr_val->data.x_enum.tag == type_enum_field->value) {4841 if (expr_val->data.x_enum.tag == type_enum_field->value) {
4795 const_chosen_prong_index = prong_i;4842 *const_chosen_prong_index = prong_i;
4796 }4843 }
4797 }4844 }
4798 } else {4845 } else {
...@@ -4844,7 +4891,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,...@@ -4844,7 +4891,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
4844 for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {4891 for (int prong_i = 0; prong_i < prong_count; prong_i += 1) {
4845 AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);4892 AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i);
4846 BlockContext *child_context = prong_node->data.switch_prong.block_context;4893 BlockContext *child_context = prong_node->data.switch_prong.block_context;
4847 child_context->codegen_excluded = expr_val->ok && (const_chosen_prong_index != prong_i);4894 child_context->codegen_excluded = expr_val->ok && (*const_chosen_prong_index != prong_i);
48484895
4849 peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type,4896 peer_types[prong_i] = analyze_expression(g, import, child_context, expected_type,
4850 prong_node->data.switch_prong.expr);4897 prong_node->data.switch_prong.expr);
...@@ -4872,10 +4919,9 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,...@@ -4872,10 +4919,9 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
4872 }4919 }
48734920
4874 if (expr_val->ok) {4921 if (expr_val->ok) {
4875 assert(const_chosen_prong_index != -1);4922 assert(*const_chosen_prong_index != -1);
48764923
4877 *const_val = get_resolved_expr(peer_nodes[const_chosen_prong_index])->const_val;4924 *const_val = get_resolved_expr(peer_nodes[*const_chosen_prong_index])->const_val;
4878 const_val->ok = true;
4879 // the target expr depends on a compile var,4925 // the target expr depends on a compile var,
4880 // so the entire if statement does too4926 // so the entire if statement does too
4881 const_val->depends_on_compile_var = true;4927 const_val->depends_on_compile_var = true;
...@@ -5490,6 +5536,12 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode...@@ -5490,6 +5536,12 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
5490 AstNode *param = node->data.fn_proto.params.at(i);5536 AstNode *param = node->data.fn_proto.params.at(i);
5491 collect_expr_decl_deps(g, import, param, decl_node);5537 collect_expr_decl_deps(g, import, param, decl_node);
5492 }5538 }
5539 if (node->data.fn_proto.directives) {
5540 for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) {
5541 AstNode *directive = node->data.fn_proto.directives->at(i);
5542 collect_expr_decl_deps(g, import, directive, decl_node);
5543 }
5544 }
5493 collect_expr_decl_deps(g, import, node->data.fn_proto.return_type, decl_node);5545 collect_expr_decl_deps(g, import, node->data.fn_proto.return_type, decl_node);
5494 break;5546 break;
5495 case NodeTypeParamDecl:5547 case NodeTypeParamDecl:
...@@ -5498,12 +5550,14 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode...@@ -5498,12 +5550,14 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
5498 case NodeTypeTypeDecl:5550 case NodeTypeTypeDecl:
5499 collect_expr_decl_deps(g, import, node->data.type_decl.child_type, decl_node);5551 collect_expr_decl_deps(g, import, node->data.type_decl.child_type, decl_node);
5500 break;5552 break;
5553 case NodeTypeDirective:
5554 collect_expr_decl_deps(g, import, node->data.directive.expr, decl_node);
5555 break;
5501 case NodeTypeVariableDeclaration:5556 case NodeTypeVariableDeclaration:
5502 case NodeTypeRootExportDecl:5557 case NodeTypeRootExportDecl:
5503 case NodeTypeFnDef:5558 case NodeTypeFnDef:
5504 case NodeTypeRoot:5559 case NodeTypeRoot:
5505 case NodeTypeFnDecl:5560 case NodeTypeFnDecl:
5506 case NodeTypeDirective:
5507 case NodeTypeImport:5561 case NodeTypeImport:
5508 case NodeTypeCImport:5562 case NodeTypeCImport:
5509 case NodeTypeLabel:5563 case NodeTypeLabel:
src/ast_render.cpp+4-2
...@@ -339,6 +339,7 @@ void ast_print(FILE *f, AstNode *node, int indent) {...@@ -339,6 +339,7 @@ void ast_print(FILE *f, AstNode *node, int indent) {
339 break;339 break;
340 case NodeTypeDirective:340 case NodeTypeDirective:
341 fprintf(f, "%s\n", node_type_str(node->type));341 fprintf(f, "%s\n", node_type_str(node->type));
342 ast_print(f, node->data.directive.expr, indent + 2);
342 break;343 break;
343 case NodeTypePrefixOpExpr:344 case NodeTypePrefixOpExpr:
344 fprintf(f, "%s %s\n", node_type_str(node->type),345 fprintf(f, "%s %s\n", node_type_str(node->type),
...@@ -631,8 +632,9 @@ static void render_node(AstRender *ar, AstNode *node) {...@@ -631,8 +632,9 @@ static void render_node(AstRender *ar, AstNode *node) {
631 fprintf(ar->f, "}");632 fprintf(ar->f, "}");
632 break;633 break;
633 case NodeTypeDirective:634 case NodeTypeDirective:
634 fprintf(ar->f, "#%s(\"%s\")\n", buf_ptr(&node->data.directive.name),635 fprintf(ar->f, "#%s(", buf_ptr(&node->data.directive.name));
635 buf_ptr(&node->data.directive.param));636 render_node(ar, node->data.directive.expr);
637 fprintf(ar->f, ")\n");
636 break;638 break;
637 case NodeTypeReturnExpr:639 case NodeTypeReturnExpr:
638 zig_panic("TODO");640 zig_panic("TODO");
src/codegen.cpp+24-11
...@@ -2150,7 +2150,8 @@ static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {...@@ -2150,7 +2150,8 @@ static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {
2150 if (!g->is_release_build) {2150 if (!g->is_release_build) {
2151 LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, "");2151 LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, "");
2152 }2152 }
2153 return LLVMBuildUnreachable(g->builder);2153 LLVMBuildUnreachable(g->builder);
2154 return nullptr;
2154 } else if (type_entry->id == TypeTableEntryIdVoid) {2155 } else if (type_entry->id == TypeTableEntryIdVoid) {
2155 assert(node->data.container_init_expr.entries.length == 0);2156 assert(node->data.container_init_expr.entries.length == 0);
2156 return nullptr;2157 return nullptr;
...@@ -2487,6 +2488,13 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {...@@ -2487,6 +2488,13 @@ static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
2487static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {2488static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
2488 assert(node->type == NodeTypeSwitchExpr);2489 assert(node->type == NodeTypeSwitchExpr);
24892490
2491 if (node->data.switch_expr.const_chosen_prong_index >= 0) {
2492 AstNode *prong_node = node->data.switch_expr.prongs.at(node->data.switch_expr.const_chosen_prong_index);
2493 assert(prong_node->type == NodeTypeSwitchProng);
2494 AstNode *prong_expr = prong_node->data.switch_prong.expr;
2495 return gen_expr(g, prong_expr);
2496 }
2497
2490 TypeTableEntry *target_type = get_expr_type(node->data.switch_expr.expr);2498 TypeTableEntry *target_type = get_expr_type(node->data.switch_expr.expr);
2491 LLVMValueRef target_value_handle = gen_expr(g, node->data.switch_expr.expr);2499 LLVMValueRef target_value_handle = gen_expr(g, node->data.switch_expr.expr);
2492 LLVMValueRef target_value;2500 LLVMValueRef target_value;
...@@ -3877,18 +3885,23 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,...@@ -3877,18 +3885,23 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
3877 for (int i = 0; i < directives->length; i += 1) {3885 for (int i = 0; i < directives->length; i += 1) {
3878 AstNode *directive_node = directives->at(i);3886 AstNode *directive_node = directives->at(i);
3879 Buf *name = &directive_node->data.directive.name;3887 Buf *name = &directive_node->data.directive.name;
3880 Buf *param = &directive_node->data.directive.param;3888 AstNode *param_node = directive_node->data.directive.expr;
3881 if (buf_eql_str(name, "version")) {3889 assert(param_node->type == NodeTypeStringLiteral);
3882 set_root_export_version(g, param, directive_node);3890 Buf *param = &param_node->data.string_literal.buf;
3883 } else if (buf_eql_str(name, "link")) {3891
3884 if (buf_eql_str(param, "c")) {3892 if (param) {
3885 g->link_libc = true;3893 if (buf_eql_str(name, "version")) {
3894 set_root_export_version(g, param, directive_node);
3895 } else if (buf_eql_str(name, "link")) {
3896 if (buf_eql_str(param, "c")) {
3897 g->link_libc = true;
3898 } else {
3899 g->link_libs.append(param);
3900 }
3886 } else {3901 } else {
3887 g->link_libs.append(param);3902 add_node_error(g, directive_node,
3903 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
3888 }3904 }
3889 } else {
3890 add_node_error(g, directive_node,
3891 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
3892 }3905 }
3893 }3906 }
3894 }3907 }
src/link.cpp+39-44
...@@ -580,35 +580,33 @@ static void construct_linker_job_darwin(LinkJob *lj) {...@@ -580,35 +580,33 @@ static void construct_linker_job_darwin(LinkJob *lj) {
580 lj->args.append("-o");580 lj->args.append("-o");
581 lj->args.append(buf_ptr(&lj->out_file));581 lj->args.append(buf_ptr(&lj->out_file));
582582
583 if (lj->link_in_crt) {583 if (shared) {
584 if (shared) {584 zig_panic("TODO");
585 zig_panic("TODO");585 } else if (g->is_static) {
586 } else if (g->is_static) {586 lj->args.append("-lcrt0.o");
587 lj->args.append("-lcrt0.o");587 } else {
588 } else {588 switch (platform.kind) {
589 switch (platform.kind) {589 case MacOS:
590 case MacOS:590 if (darwin_version_lt(&platform, 10, 5)) {
591 if (darwin_version_lt(&platform, 10, 5)) {591 lj->args.append("-lcrt1.o");
592 lj->args.append("-lcrt1.o");592 } else if (darwin_version_lt(&platform, 10, 6)) {
593 } else if (darwin_version_lt(&platform, 10, 6)) {593 lj->args.append("-lcrt1.10.5.o");
594 lj->args.append("-lcrt1.10.5.o");594 } else if (darwin_version_lt(&platform, 10, 8)) {
595 } else if (darwin_version_lt(&platform, 10, 8)) {595 lj->args.append("-lcrt1.10.6.o");
596 lj->args.append("-lcrt1.10.6.o");596 }
597 }597 break;
598 break;598 case IPhoneOS:
599 case IPhoneOS:599 if (g->zig_target.arch.arch == ZigLLVM_aarch64) {
600 if (g->zig_target.arch.arch == ZigLLVM_aarch64) {600 // iOS does not need any crt1 files for arm64
601 // iOS does not need any crt1 files for arm64601 } else if (darwin_version_lt(&platform, 3, 1)) {
602 } else if (darwin_version_lt(&platform, 3, 1)) {602 lj->args.append("-lcrt1.o");
603 lj->args.append("-lcrt1.o");603 } else if (darwin_version_lt(&platform, 6, 0)) {
604 } else if (darwin_version_lt(&platform, 6, 0)) {604 lj->args.append("-lcrt1.3.1.o");
605 lj->args.append("-lcrt1.3.1.o");605 }
606 }606 break;
607 break;607 case IPhoneOSSimulator:
608 case IPhoneOSSimulator:608 // no crt1.o needed
609 // no crt1.o needed609 break;
610 break;
611 }
612 }610 }
613 }611 }
614612
...@@ -620,29 +618,26 @@ static void construct_linker_job_darwin(LinkJob *lj) {...@@ -620,29 +618,26 @@ static void construct_linker_job_darwin(LinkJob *lj) {
620618
621 lj->args.append((const char *)buf_ptr(&lj->out_file_o));619 lj->args.append((const char *)buf_ptr(&lj->out_file_o));
622620
623 if (!g->link_libc && (g->out_type == OutTypeExe || g->out_type == OutTypeLib)) {
624 Buf *builtin_o_path = build_o(g, "builtin");
625 lj->args.append(buf_ptr(builtin_o_path));
626 }
627
628 for (int i = 0; i < g->link_libs.length; i += 1) {621 for (int i = 0; i < g->link_libs.length; i += 1) {
629 Buf *link_lib = g->link_libs.at(i);622 Buf *link_lib = g->link_libs.at(i);
630 Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib));623 Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib));
631 lj->args.append(buf_ptr(arg));624 lj->args.append(buf_ptr(arg));
632 }625 }
633626
634 if (g->link_libc) {627 // on Darwin, libSystem has libc in it, but also you have to use it
635 lj->args.append("-lSystem");628 // to make syscalls because the syscall numbers are not documented
629 // and change between versions.
630 // so we always link against libSystem
631 lj->args.append("-lSystem");
636632
637 if (platform.kind == MacOS) {633 if (platform.kind == MacOS) {
638 if (darwin_version_lt(&platform, 10, 5)) {634 if (darwin_version_lt(&platform, 10, 5)) {
639 lj->args.append("-lgcc_s.10.4");635 lj->args.append("-lgcc_s.10.4");
640 } else if (darwin_version_lt(&platform, 10, 6)) {636 } else if (darwin_version_lt(&platform, 10, 6)) {
641 lj->args.append("-lgcc_s.10.5");637 lj->args.append("-lgcc_s.10.5");
642 }
643 } else {
644 zig_panic("TODO");
645 }638 }
639 } else {
640 zig_panic("TODO");
646 }641 }
647642
648}643}
src/parser.cpp+8-21
...@@ -499,6 +499,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo...@@ -499,6 +499,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo
499static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory,499static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory,
500 ZigList<AstNode*> *directives, VisibMod visib_mod);500 ZigList<AstNode*> *directives, VisibMod visib_mod);
501static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index);501static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index);
502static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool mandatory);
502503
503static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {504static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
504 if (token->id == token_id) {505 if (token->id == token_id) {
...@@ -517,33 +518,19 @@ static Token *ast_eat_token(ParseContext *pc, int *token_index, TokenId token_id...@@ -517,33 +518,19 @@ static Token *ast_eat_token(ParseContext *pc, int *token_index, TokenId token_id
517 return token;518 return token;
518}519}
519520
520521/*
522Directive = "#" "Symbol" "(" Expression ")"
523*/
521static AstNode *ast_parse_directive(ParseContext *pc, int *token_index) {524static AstNode *ast_parse_directive(ParseContext *pc, int *token_index) {
522 Token *number_sign = &pc->tokens->at(*token_index);525 Token *number_sign = ast_eat_token(pc, token_index, TokenIdNumberSign);
523 *token_index += 1;
524 ast_expect_token(pc, number_sign, TokenIdNumberSign);
525526
526 AstNode *node = ast_create_node(pc, NodeTypeDirective, number_sign);527 AstNode *node = ast_create_node(pc, NodeTypeDirective, number_sign);
527528
528 Token *name_symbol = &pc->tokens->at(*token_index);529 Token *name_symbol = ast_eat_token(pc, token_index, TokenIdSymbol);
529 *token_index += 1;
530 ast_expect_token(pc, name_symbol, TokenIdSymbol);
531530
532 ast_buf_from_token(pc, name_symbol, &node->data.directive.name);531 ast_buf_from_token(pc, name_symbol, &node->data.directive.name);
533532
534 Token *l_paren = &pc->tokens->at(*token_index);533 node->data.directive.expr = ast_parse_grouped_expr(pc, token_index, true);
535 *token_index += 1;
536 ast_expect_token(pc, l_paren, TokenIdLParen);
537
538 Token *param_str = &pc->tokens->at(*token_index);
539 *token_index += 1;
540 ast_expect_token(pc, param_str, TokenIdStringLiteral);
541
542 parse_string_literal(pc, param_str, &node->data.directive.param, nullptr, nullptr);
543
544 Token *r_paren = &pc->tokens->at(*token_index);
545 *token_index += 1;
546 ast_expect_token(pc, r_paren, TokenIdRParen);
547534
548 normalize_parent_ptrs(node);535 normalize_parent_ptrs(node);
549 return node;536 return node;
...@@ -2741,7 +2728,7 @@ void normalize_parent_ptrs(AstNode *node) {...@@ -2741,7 +2728,7 @@ void normalize_parent_ptrs(AstNode *node) {
2741 set_list_fields(&node->data.block.statements);2728 set_list_fields(&node->data.block.statements);
2742 break;2729 break;
2743 case NodeTypeDirective:2730 case NodeTypeDirective:
2744 // none2731 set_field(&node->data.directive.expr);
2745 break;2732 break;
2746 case NodeTypeReturnExpr:2733 case NodeTypeReturnExpr:
2747 set_field(&node->data.return_expr.expr);2734 set_field(&node->data.return_expr.expr);
std/bootstrap.zig+20-5
...@@ -1,24 +1,28 @@...@@ -1,24 +1,28 @@
1import "syscall.zig";1import "syscall.zig";
22
3// The compiler treats this file special by implicitly importing the function `main`3// The compiler treats this file special by implicitly importing the function `main`
4// from the root source file.4// from the root source file as the symbol `zig_user_main`.
5
6const want_start_symbol = switch(@compile_var("os")) {
7 linux => true,
8 else => false,
9};
10const want_main_symbol = !want_start_symbol;
511
6var argc: isize = undefined;12var argc: isize = undefined;
7var argv: &&u8 = undefined;13var argv: &&u8 = undefined;
8var env: &&u8 = undefined;
914
10#attribute("naked")15#attribute("naked")
16#condition(want_start_symbol)
11export fn _start() -> unreachable {17export fn _start() -> unreachable {
12 switch (@compile_var("arch")) {18 switch (@compile_var("arch")) {
13 x86_64 => {19 x86_64 => {
14 argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> isize));20 argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> isize));
15 argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));21 argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
16 env = asm("lea 0x10(%%rsp,[argc],8), %[env]": [env] "=r" (-> &&u8): [argc] "r" (argc));
17 },22 },
18 i386 => {23 i386 => {
19 argc = asm("mov (%%esp), %[argc]": [argc] "=r" (-> isize));24 argc = asm("mov (%%esp), %[argc]": [argc] "=r" (-> isize));
20 argv = asm("lea 0x4(%%esp), %[argv]": [argv] "=r" (-> &&u8));25 argv = asm("lea 0x4(%%esp), %[argv]": [argv] "=r" (-> &&u8));
21 env = asm("lea 0x8(%%esp,%[argc],4), %[env]": [env] "=r" (-> &&u8): [argc] "r" (argc));
22 },26 },
23 else => unreachable{},27 else => unreachable{},
24 }28 }
...@@ -39,6 +43,17 @@ fn call_main() -> unreachable {...@@ -39,6 +43,17 @@ fn call_main() -> unreachable {
39 const ptr = argv[i];43 const ptr = argv[i];
40 args[i] = ptr[0...strlen(ptr)];44 args[i] = ptr[0...strlen(ptr)];
41 }45 }
42 main(args) %% exit(1);46 zig_user_main(args) %% exit(1);
43 exit(0);47 exit(0);
44}48}
49
50#condition(want_main_symbol)
51export fn main(argc: i32, argv: &&u8) -> i32 {
52 var args: [argc][]u8 = undefined;
53 for (args) |arg, i| {
54 const ptr = argv[i];
55 args[i] = ptr[0...strlen(ptr)];
56 }
57 zig_user_main(args) %% return 1;
58 return 0;
59}