| author | |
| committer | |
| log | 67152f729431d58a9cd140498d50c1e9d795c34b |
| tree | 7997511873fe650e71f5efb527103688f62271b3 |
| parent | e144ddab249af3737f04267c7f1f0f0e093ed314 |
9 files changed, 428 insertions(+), 418 deletions(-)
doc/langref.md+1-1| ... | ... | @@ -25,7 +25,7 @@ UseDecl = "use" Expression ";" |
| 25 | 25 | |
| 26 | 26 | ExternDecl = "extern" (FnProto | VariableDeclaration) ";" |
| 27 | 27 | |
| 28 | FnProto = "fn" option("Symbol") ParamDeclList option("->" TypeExpr) | |
| 28 | FnProto = "fn" option("Symbol") option(ParamDeclList) ParamDeclList option("->" TypeExpr) | |
| 29 | 29 | |
| 30 | 30 | Directive = "#" "Symbol" "(" Expression ")" |
| 31 | 31 |
src/all_types.hpp+29-1| ... | ... | @@ -193,8 +193,10 @@ struct AstNodeRoot { |
| 193 | 193 | struct AstNodeFnProto { |
| 194 | 194 | TopLevelDecl top_level_decl; |
| 195 | 195 | Buf name; |
| 196 | ZigList<AstNode *> generic_params; | |
| 196 | 197 | ZigList<AstNode *> params; |
| 197 | 198 | AstNode *return_type; |
| 199 | bool generic_params_is_var_args; | |
| 198 | 200 | bool is_var_args; |
| 199 | 201 | bool is_extern; |
| 200 | 202 | bool is_inline; |
| ... | ... | @@ -206,6 +208,7 @@ struct AstNodeFnProto { |
| 206 | 208 | FnTableEntry *fn_table_entry; |
| 207 | 209 | bool skip; |
| 208 | 210 | Expr resolved_expr; |
| 211 | TypeTableEntry *generic_fn_type; | |
| 209 | 212 | }; |
| 210 | 213 | |
| 211 | 214 | struct AstNodeFnDef { |
| ... | ... | @@ -797,6 +800,21 @@ struct FnTypeParamInfo { |
| 797 | 800 | TypeTableEntry *type; |
| 798 | 801 | }; |
| 799 | 802 | |
| 803 | struct GenericParamValue { | |
| 804 | TypeTableEntry *type; | |
| 805 | AstNode *node; | |
| 806 | }; | |
| 807 | ||
| 808 | struct GenericFnTypeId { | |
| 809 | AstNode *decl_node; // the generic fn or container decl node | |
| 810 | GenericParamValue *generic_params; | |
| 811 | int generic_param_count; | |
| 812 | }; | |
| 813 | ||
| 814 | uint32_t generic_fn_type_id_hash(GenericFnTypeId *id); | |
| 815 | bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b); | |
| 816 | ||
| 817 | ||
| 800 | 818 | static const int fn_type_id_prealloc_param_info_count = 4; |
| 801 | 819 | struct FnTypeId { |
| 802 | 820 | TypeTableEntry *return_type; |
| ... | ... | @@ -812,7 +830,6 @@ struct FnTypeId { |
| 812 | 830 | uint32_t fn_type_id_hash(FnTypeId*); |
| 813 | 831 | bool fn_type_id_eql(FnTypeId *a, FnTypeId *b); |
| 814 | 832 | |
| 815 | ||
| 816 | 833 | struct TypeTableEntryPointer { |
| 817 | 834 | TypeTableEntry *child_type; |
| 818 | 835 | bool is_const; |
| ... | ... | @@ -899,6 +916,10 @@ struct TypeTableEntryFn { |
| 899 | 916 | LLVMCallConv calling_convention; |
| 900 | 917 | }; |
| 901 | 918 | |
| 919 | struct TypeTableEntryGenericFn { | |
| 920 | AstNode *decl_node; | |
| 921 | }; | |
| 922 | ||
| 902 | 923 | struct TypeTableEntryTypeDecl { |
| 903 | 924 | TypeTableEntry *child_type; |
| 904 | 925 | TypeTableEntry *canonical_type; |
| ... | ... | @@ -925,6 +946,7 @@ enum TypeTableEntryId { |
| 925 | 946 | TypeTableEntryIdFn, |
| 926 | 947 | TypeTableEntryIdTypeDecl, |
| 927 | 948 | TypeTableEntryIdNamespace, |
| 949 | TypeTableEntryIdGenericFn, | |
| 928 | 950 | }; |
| 929 | 951 | |
| 930 | 952 | struct TypeTableEntry { |
| ... | ... | @@ -947,6 +969,7 @@ struct TypeTableEntry { |
| 947 | 969 | TypeTableEntryEnum enumeration; |
| 948 | 970 | TypeTableEntryFn fn; |
| 949 | 971 | TypeTableEntryTypeDecl type_decl; |
| 972 | TypeTableEntryGenericFn generic_fn; | |
| 950 | 973 | } data; |
| 951 | 974 | |
| 952 | 975 | // use these fields to make sure we don't duplicate type table entries for the same type |
| ... | ... | @@ -992,6 +1015,7 @@ struct FnTableEntry { |
| 992 | 1015 | bool internal_linkage; |
| 993 | 1016 | bool is_extern; |
| 994 | 1017 | bool is_test; |
| 1018 | BlockContext *parent_block_context; | |
| 995 | 1019 | |
| 996 | 1020 | ZigList<AstNode *> cast_alloca_list; |
| 997 | 1021 | ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list; |
| ... | ... | @@ -1047,6 +1071,7 @@ struct CodeGen { |
| 1047 | 1071 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table; |
| 1048 | 1072 | HashMap<FnTypeId *, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table; |
| 1049 | 1073 | HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table; |
| 1074 | HashMap<GenericFnTypeId *, AstNode *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table; | |
| 1050 | 1075 | |
| 1051 | 1076 | ZigList<ImportTableEntry *> import_queue; |
| 1052 | 1077 | int import_queue_index; |
| ... | ... | @@ -1172,7 +1197,10 @@ struct VariableTableEntry { |
| 1172 | 1197 | LLVMValueRef value_ref; |
| 1173 | 1198 | bool is_const; |
| 1174 | 1199 | bool is_ptr; // if true, value_ref is a pointer |
| 1200 | // which node is the declaration of the variable | |
| 1175 | 1201 | AstNode *decl_node; |
| 1202 | // which node contains the ConstExprValue for this variable's value | |
| 1203 | AstNode *val_node; | |
| 1176 | 1204 | LLVMZigDILocalVariable *di_loc_var; |
| 1177 | 1205 | int src_arg_index; |
| 1178 | 1206 | int gen_arg_index; |
src/analyze.cpp+250-31| ... | ... | @@ -41,6 +41,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa |
| 41 | 41 | AstNodeVariableDeclaration *variable_declaration, |
| 42 | 42 | bool expr_is_maybe, AstNode *decl_node); |
| 43 | 43 | static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node); |
| 44 | static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry); | |
| 44 | 45 | |
| 45 | 46 | static AstNode *first_executing_node(AstNode *node) { |
| 46 | 47 | switch (node->type) { |
| ... | ... | @@ -192,6 +193,7 @@ static bool type_is_complete(TypeTableEntry *type_entry) { |
| 192 | 193 | case TypeTableEntryIdFn: |
| 193 | 194 | case TypeTableEntryIdTypeDecl: |
| 194 | 195 | case TypeTableEntryIdNamespace: |
| 196 | case TypeTableEntryIdGenericFn: | |
| 195 | 197 | return true; |
| 196 | 198 | } |
| 197 | 199 | zig_unreachable(); |
| ... | ... | @@ -201,6 +203,14 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { |
| 201 | 203 | return get_int_type(g, false, bits_needed_for_unsigned(x)); |
| 202 | 204 | } |
| 203 | 205 | |
| 206 | static TypeTableEntry *get_generic_fn_type(CodeGen *g, AstNode *decl_node) { | |
| 207 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdGenericFn); | |
| 208 | buf_init_from_str(&entry->name, "(generic function)"); | |
| 209 | entry->zero_bits = true; | |
| 210 | entry->data.generic_fn.decl_node = decl_node; | |
| 211 | return entry; | |
| 212 | } | |
| 213 | ||
| 204 | 214 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { |
| 205 | 215 | assert(child_type->id != TypeTableEntryIdInvalid); |
| 206 | 216 | TypeTableEntry **parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)]; |
| ... | ... | @@ -776,7 +786,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor |
| 776 | 786 | } |
| 777 | 787 | |
| 778 | 788 | fn_type_id.is_var_args = fn_proto->is_var_args; |
| 779 | fn_type_id.return_type = analyze_type_expr(g, import, import->block_context, node->data.fn_proto.return_type); | |
| 789 | fn_type_id.return_type = analyze_type_expr(g, import, context, node->data.fn_proto.return_type); | |
| 780 | 790 | |
| 781 | 791 | if (fn_type_id.return_type->id == TypeTableEntryIdInvalid) { |
| 782 | 792 | fn_proto->skip = true; |
| ... | ... | @@ -785,7 +795,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor |
| 785 | 795 | for (int i = 0; i < fn_type_id.param_count; i += 1) { |
| 786 | 796 | AstNode *child = node->data.fn_proto.params.at(i); |
| 787 | 797 | assert(child->type == NodeTypeParamDecl); |
| 788 | TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context, | |
| 798 | TypeTableEntry *type_entry = analyze_type_expr(g, import, context, | |
| 789 | 799 | child->data.param_decl.type); |
| 790 | 800 | switch (type_entry->id) { |
| 791 | 801 | case TypeTableEntryIdInvalid: |
| ... | ... | @@ -797,6 +807,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor |
| 797 | 807 | case TypeTableEntryIdMetaType: |
| 798 | 808 | case TypeTableEntryIdUnreachable: |
| 799 | 809 | case TypeTableEntryIdNamespace: |
| 810 | case TypeTableEntryIdGenericFn: | |
| 800 | 811 | fn_proto->skip = true; |
| 801 | 812 | add_node_error(g, child->data.param_decl.type, |
| 802 | 813 | buf_sprintf("parameter of type '%s' not allowed'", buf_ptr(&type_entry->name))); |
| ... | ... | @@ -880,7 +891,7 @@ static bool resolve_const_expr_bool(CodeGen *g, ImportTableEntry *import, BlockC |
| 880 | 891 | } |
| 881 | 892 | |
| 882 | 893 | static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry, |
| 883 | ImportTableEntry *import) | |
| 894 | ImportTableEntry *import, BlockContext *containing_context) | |
| 884 | 895 | { |
| 885 | 896 | assert(node->type == NodeTypeFnProto); |
| 886 | 897 | AstNodeFnProto *fn_proto = &node->data.fn_proto; |
| ... | ... | @@ -946,7 +957,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 946 | 957 | |
| 947 | 958 | |
| 948 | 959 | |
| 949 | TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, import->block_context, nullptr, node, | |
| 960 | TypeTableEntry *fn_type = analyze_fn_proto_type(g, import, containing_context, nullptr, node, | |
| 950 | 961 | is_naked, is_cold); |
| 951 | 962 | |
| 952 | 963 | fn_table_entry->type_entry = fn_type; |
| ... | ... | @@ -963,6 +974,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 963 | 974 | } else { |
| 964 | 975 | symbol_name = buf_sprintf("_%s", buf_ptr(&fn_table_entry->symbol_name)); |
| 965 | 976 | } |
| 977 | // TODO mangle the name if it's a generic instance | |
| 978 | ||
| 966 | 979 | fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), |
| 967 | 980 | fn_type->data.fn.raw_type_ref); |
| 968 | 981 | |
| ... | ... | @@ -992,12 +1005,12 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 992 | 1005 | unsigned flags = 0; |
| 993 | 1006 | bool is_optimized = g->is_release_build; |
| 994 | 1007 | LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, |
| 995 | import->block_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "", | |
| 1008 | containing_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "", | |
| 996 | 1009 | import->di_file, line_number, |
| 997 | 1010 | fn_type->di_type, fn_table_entry->internal_linkage, |
| 998 | 1011 | is_definition, scope_line, flags, is_optimized, nullptr); |
| 999 | 1012 | |
| 1000 | BlockContext *context = new_block_context(fn_table_entry->fn_def_node, import->block_context); | |
| 1013 | BlockContext *context = new_block_context(fn_table_entry->fn_def_node, containing_context); | |
| 1001 | 1014 | fn_table_entry->fn_def_node->data.fn_def.block_context = context; |
| 1002 | 1015 | context->di_scope = LLVMZigSubprogramToScope(subprogram); |
| 1003 | 1016 | } |
| ... | ... | @@ -1321,17 +1334,35 @@ static void get_fully_qualified_decl_name(Buf *buf, AstNode *decl_node, uint8_t |
| 1321 | 1334 | } |
| 1322 | 1335 | } |
| 1323 | 1336 | |
| 1324 | static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *proto_node) { | |
| 1337 | static void preview_generic_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *node) { | |
| 1338 | assert(node->type == NodeTypeFnProto); | |
| 1339 | ||
| 1340 | if (node->data.fn_proto.generic_params_is_var_args) { | |
| 1341 | add_node_error(g, node, buf_sprintf("generic parameters cannot be var args")); | |
| 1342 | node->data.fn_proto.skip = true; | |
| 1343 | node->data.fn_proto.generic_fn_type = g->builtin_types.entry_invalid; | |
| 1344 | return; | |
| 1345 | } | |
| 1346 | ||
| 1347 | node->data.fn_proto.generic_fn_type = get_generic_fn_type(g, node); | |
| 1348 | } | |
| 1349 | ||
| 1350 | static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstNode *proto_node, | |
| 1351 | BlockContext *containing_context) | |
| 1352 | { | |
| 1325 | 1353 | if (proto_node->data.fn_proto.skip) { |
| 1326 | 1354 | return; |
| 1327 | 1355 | } |
| 1328 | 1356 | |
| 1357 | bool is_generic_instance = (proto_node->data.fn_proto.generic_params.length > 0); | |
| 1358 | ||
| 1329 | 1359 | AstNode *parent_decl = proto_node->data.fn_proto.top_level_decl.parent_decl; |
| 1360 | Buf *proto_name = &proto_node->data.fn_proto.name; | |
| 1330 | 1361 | |
| 1331 | 1362 | AstNode *fn_def_node = proto_node->data.fn_proto.fn_def_node; |
| 1332 | 1363 | bool is_extern = proto_node->data.fn_proto.is_extern; |
| 1333 | 1364 | |
| 1334 | Buf *proto_name = &proto_node->data.fn_proto.name; | |
| 1365 | assert(!is_extern || !is_generic_instance); | |
| 1335 | 1366 | |
| 1336 | 1367 | if (!is_extern && proto_node->data.fn_proto.is_var_args) { |
| 1337 | 1368 | add_node_error(g, proto_node, |
| ... | ... | @@ -1352,13 +1383,24 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *prot |
| 1352 | 1383 | g->fn_defs.append(fn_table_entry); |
| 1353 | 1384 | } |
| 1354 | 1385 | |
| 1355 | bool is_main_fn = !parent_decl && (import == g->root_import) && buf_eql_str(proto_name, "main"); | |
| 1386 | bool is_main_fn = !is_generic_instance && | |
| 1387 | !parent_decl && (import == g->root_import) && | |
| 1388 | buf_eql_str(proto_name, "main"); | |
| 1356 | 1389 | if (is_main_fn) { |
| 1357 | 1390 | g->main_fn = fn_table_entry; |
| 1358 | 1391 | } |
| 1359 | 1392 | |
| 1360 | 1393 | proto_node->data.fn_proto.fn_table_entry = fn_table_entry; |
| 1361 | resolve_function_proto(g, proto_node, fn_table_entry, import); | |
| 1394 | resolve_function_proto(g, proto_node, fn_table_entry, import, containing_context); | |
| 1395 | } | |
| 1396 | ||
| 1397 | static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *proto_node) { | |
| 1398 | if (proto_node->data.fn_proto.generic_params.length > 0) { | |
| 1399 | return preview_generic_fn_proto(g, import, proto_node); | |
| 1400 | } else { | |
| 1401 | return preview_fn_proto_instance(g, import, proto_node, import->block_context); | |
| 1402 | } | |
| 1403 | ||
| 1362 | 1404 | } |
| 1363 | 1405 | |
| 1364 | 1406 | static void preview_error_value_decl(CodeGen *g, AstNode *node) { |
| ... | ... | @@ -1539,6 +1581,7 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) { |
| 1539 | 1581 | case TypeTableEntryIdNumLitInt: |
| 1540 | 1582 | case TypeTableEntryIdUndefLit: |
| 1541 | 1583 | case TypeTableEntryIdNamespace: |
| 1584 | case TypeTableEntryIdGenericFn: | |
| 1542 | 1585 | return false; |
| 1543 | 1586 | |
| 1544 | 1587 | case TypeTableEntryIdBool: |
| ... | ... | @@ -2433,6 +2476,15 @@ static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, F |
| 2433 | 2476 | return fn->type_entry; |
| 2434 | 2477 | } |
| 2435 | 2478 | |
| 2479 | static TypeTableEntry *resolve_expr_const_val_as_generic_fn(CodeGen *g, AstNode *node, | |
| 2480 | TypeTableEntry *type_entry) | |
| 2481 | { | |
| 2482 | Expr *expr = get_resolved_expr(node); | |
| 2483 | expr->const_val.ok = true; | |
| 2484 | expr->const_val.data.x_type = type_entry; | |
| 2485 | return type_entry; | |
| 2486 | } | |
| 2487 | ||
| 2436 | 2488 | static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node, ErrorTableEntry *err) { |
| 2437 | 2489 | Expr *expr = get_resolved_expr(node); |
| 2438 | 2490 | expr->const_val.ok = true; |
| ... | ... | @@ -2570,14 +2622,10 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry * |
| 2570 | 2622 | |
| 2571 | 2623 | static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var) { |
| 2572 | 2624 | get_resolved_expr(source_node)->variable = var; |
| 2573 | if (var->is_const) { | |
| 2574 | AstNode *decl_node = var->decl_node; | |
| 2575 | if (decl_node->type == NodeTypeVariableDeclaration) { | |
| 2576 | AstNode *expr_node = decl_node->data.variable_declaration.expr; | |
| 2577 | ConstExprValue *other_const_val = &get_resolved_expr(expr_node)->const_val; | |
| 2578 | if (other_const_val->ok) { | |
| 2579 | return resolve_expr_const_val_as_other_expr(g, source_node, expr_node); | |
| 2580 | } | |
| 2625 | if (var->is_const && var->val_node) { | |
| 2626 | ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val; | |
| 2627 | if (other_const_val->ok) { | |
| 2628 | return resolve_expr_const_val_as_other_expr(g, source_node, var->val_node); | |
| 2581 | 2629 | } |
| 2582 | 2630 | } |
| 2583 | 2631 | return var->type; |
| ... | ... | @@ -2596,9 +2644,15 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod |
| 2596 | 2644 | VariableTableEntry *var = decl_node->data.variable_declaration.variable; |
| 2597 | 2645 | return analyze_var_ref(g, source_node, var); |
| 2598 | 2646 | } else if (decl_node->type == NodeTypeFnProto) { |
| 2599 | FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry; | |
| 2600 | assert(fn_entry->type_entry); | |
| 2601 | return resolve_expr_const_val_as_fn(g, source_node, fn_entry); | |
| 2647 | if (decl_node->data.fn_proto.generic_params.length > 0) { | |
| 2648 | TypeTableEntry *type_entry = decl_node->data.fn_proto.generic_fn_type; | |
| 2649 | assert(type_entry); | |
| 2650 | return resolve_expr_const_val_as_generic_fn(g, source_node, type_entry); | |
| 2651 | } else { | |
| 2652 | FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry; | |
| 2653 | assert(fn_entry->type_entry); | |
| 2654 | return resolve_expr_const_val_as_fn(g, source_node, fn_entry); | |
| 2655 | } | |
| 2602 | 2656 | } else if (decl_node->type == NodeTypeStructDecl) { |
| 2603 | 2657 | return resolve_expr_const_val_as_type(g, source_node, decl_node->data.struct_decl.type_entry); |
| 2604 | 2658 | } else if (decl_node->type == NodeTypeTypeDecl) { |
| ... | ... | @@ -3113,7 +3167,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 3113 | 3167 | |
| 3114 | 3168 | // Set name to nullptr to make the variable anonymous (not visible to programmer). |
| 3115 | 3169 | static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, ImportTableEntry *import, |
| 3116 | BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const) | |
| 3170 | BlockContext *context, Buf *name, TypeTableEntry *type_entry, bool is_const, AstNode *val_node) | |
| 3117 | 3171 | { |
| 3118 | 3172 | VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); |
| 3119 | 3173 | variable_entry->type = type_entry; |
| ... | ... | @@ -3160,6 +3214,8 @@ static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, Impor |
| 3160 | 3214 | variable_entry->is_const = is_const; |
| 3161 | 3215 | variable_entry->is_ptr = true; |
| 3162 | 3216 | variable_entry->decl_node = source_node; |
| 3217 | variable_entry->val_node = val_node; | |
| 3218 | ||
| 3163 | 3219 | |
| 3164 | 3220 | return variable_entry; |
| 3165 | 3221 | } |
| ... | ... | @@ -3182,7 +3238,7 @@ static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *i |
| 3182 | 3238 | var_node->block_context = child_context; |
| 3183 | 3239 | Buf *var_name = &var_node->data.symbol_expr.symbol; |
| 3184 | 3240 | node->data.unwrap_err_expr.var = add_local_var(g, var_node, import, child_context, var_name, |
| 3185 | g->builtin_types.entry_pure_error, true); | |
| 3241 | g->builtin_types.entry_pure_error, true, nullptr); | |
| 3186 | 3242 | } else { |
| 3187 | 3243 | child_context = parent_context; |
| 3188 | 3244 | } |
| ... | ... | @@ -3260,7 +3316,8 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa |
| 3260 | 3316 | assert(type != nullptr); // should have been caught by the parser |
| 3261 | 3317 | |
| 3262 | 3318 | VariableTableEntry *var = add_local_var(g, source_node, import, context, |
| 3263 | &variable_declaration->symbol, type, is_const); | |
| 3319 | &variable_declaration->symbol, type, is_const, | |
| 3320 | expr_is_maybe ? nullptr : variable_declaration->expr); | |
| 3264 | 3321 | |
| 3265 | 3322 | variable_declaration->variable = var; |
| 3266 | 3323 | |
| ... | ... | @@ -3453,17 +3510,17 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl |
| 3453 | 3510 | elem_var_node->block_context = child_context; |
| 3454 | 3511 | Buf *elem_var_name = &elem_var_node->data.symbol_expr.symbol; |
| 3455 | 3512 | node->data.for_expr.elem_var = add_local_var(g, elem_var_node, import, child_context, elem_var_name, |
| 3456 | child_type, true); | |
| 3513 | child_type, true, nullptr); | |
| 3457 | 3514 | |
| 3458 | 3515 | AstNode *index_var_node = node->data.for_expr.index_node; |
| 3459 | 3516 | if (index_var_node) { |
| 3460 | 3517 | Buf *index_var_name = &index_var_node->data.symbol_expr.symbol; |
| 3461 | 3518 | index_var_node->block_context = child_context; |
| 3462 | 3519 | node->data.for_expr.index_var = add_local_var(g, index_var_node, import, child_context, index_var_name, |
| 3463 | g->builtin_types.entry_isize, true); | |
| 3520 | g->builtin_types.entry_isize, true, nullptr); | |
| 3464 | 3521 | } else { |
| 3465 | 3522 | node->data.for_expr.index_var = add_local_var(g, node, import, child_context, nullptr, |
| 3466 | g->builtin_types.entry_isize, true); | |
| 3523 | g->builtin_types.entry_isize, true, nullptr); | |
| 3467 | 3524 | } |
| 3468 | 3525 | |
| 3469 | 3526 | AstNode *for_body_node = node->data.for_expr.body; |
| ... | ... | @@ -4330,6 +4387,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 4330 | 4387 | case TypeTableEntryIdNumLitInt: |
| 4331 | 4388 | case TypeTableEntryIdUndefLit: |
| 4332 | 4389 | case TypeTableEntryIdNamespace: |
| 4390 | case TypeTableEntryIdGenericFn: | |
| 4333 | 4391 | add_node_error(g, expr_node, |
| 4334 | 4392 | buf_sprintf("type '%s' not eligible for @typeof", buf_ptr(&type_entry->name))); |
| 4335 | 4393 | return g->builtin_types.entry_invalid; |
| ... | ... | @@ -4541,6 +4599,92 @@ static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, |
| 4541 | 4599 | return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_type); |
| 4542 | 4600 | } |
| 4543 | 4601 | |
| 4602 | static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, | |
| 4603 | TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *generic_fn_type) | |
| 4604 | { | |
| 4605 | assert(node->type == NodeTypeFnCallExpr); | |
| 4606 | assert(generic_fn_type->id == TypeTableEntryIdGenericFn); | |
| 4607 | ||
| 4608 | AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node; | |
| 4609 | assert(decl_node->type == NodeTypeFnProto); | |
| 4610 | ||
| 4611 | int expected_param_count = decl_node->data.fn_proto.generic_params.length; | |
| 4612 | int actual_param_count = node->data.fn_call_expr.params.length; | |
| 4613 | ||
| 4614 | if (actual_param_count != expected_param_count) { | |
| 4615 | add_node_error(g, first_executing_node(node), | |
| 4616 | buf_sprintf("expected %d arguments, got %d", expected_param_count, actual_param_count)); | |
| 4617 | return g->builtin_types.entry_invalid; | |
| 4618 | } | |
| 4619 | ||
| 4620 | GenericFnTypeId *generic_fn_type_id = allocate<GenericFnTypeId>(1); | |
| 4621 | generic_fn_type_id->decl_node = decl_node; | |
| 4622 | generic_fn_type_id->generic_param_count = actual_param_count; | |
| 4623 | generic_fn_type_id->generic_params = allocate<GenericParamValue>(actual_param_count); | |
| 4624 | ||
| 4625 | BlockContext *child_context = import->block_context; | |
| 4626 | for (int i = 0; i < actual_param_count; i += 1) { | |
| 4627 | AstNode *generic_param_decl_node = decl_node->data.fn_proto.generic_params.at(i); | |
| 4628 | assert(generic_param_decl_node->type == NodeTypeParamDecl); | |
| 4629 | ||
| 4630 | AstNode **generic_param_type_node = &generic_param_decl_node->data.param_decl.type; | |
| 4631 | ||
| 4632 | TypeTableEntry *expected_param_type = analyze_expression(g, decl_node->owner, | |
| 4633 | decl_node->owner->block_context, nullptr, *generic_param_type_node); | |
| 4634 | if (expected_param_type->id == TypeTableEntryIdInvalid) { | |
| 4635 | return expected_param_type; | |
| 4636 | } | |
| 4637 | AstNode **param_node = &node->data.fn_call_expr.params.at(i); | |
| 4638 | ||
| 4639 | TypeTableEntry *param_type = analyze_expression(g, import, child_context, expected_param_type, | |
| 4640 | *param_node); | |
| 4641 | if (param_type->id == TypeTableEntryIdInvalid) { | |
| 4642 | return param_type; | |
| 4643 | } | |
| 4644 | ||
| 4645 | // set child_context so that the previous param is in scope | |
| 4646 | child_context = new_block_context(generic_param_decl_node, child_context); | |
| 4647 | ||
| 4648 | ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val; | |
| 4649 | if (const_val->ok) { | |
| 4650 | add_local_var(g, generic_param_decl_node, decl_node->owner, child_context, | |
| 4651 | &generic_param_decl_node->data.param_decl.name, param_type, true, *param_node); | |
| 4652 | } else { | |
| 4653 | add_node_error(g, *param_node, buf_sprintf("unable to resolve constant expression")); | |
| 4654 | ||
| 4655 | add_local_var(g, generic_param_decl_node, decl_node->owner, child_context, | |
| 4656 | &generic_param_decl_node->data.param_decl.name, g->builtin_types.entry_invalid, | |
| 4657 | true, nullptr); | |
| 4658 | ||
| 4659 | return g->builtin_types.entry_invalid; | |
| 4660 | } | |
| 4661 | ||
| 4662 | GenericParamValue *generic_param_value = &generic_fn_type_id->generic_params[i]; | |
| 4663 | generic_param_value->type = param_type; | |
| 4664 | generic_param_value->node = *param_node; | |
| 4665 | } | |
| 4666 | ||
| 4667 | ||
| 4668 | auto entry = g->generic_table.maybe_get(generic_fn_type_id); | |
| 4669 | if (entry) { | |
| 4670 | AstNode *impl_decl_node = entry->value; | |
| 4671 | assert(impl_decl_node->type == NodeTypeFnProto); | |
| 4672 | FnTableEntry *fn_table_entry = impl_decl_node->data.fn_proto.fn_table_entry; | |
| 4673 | return resolve_expr_const_val_as_fn(g, node, fn_table_entry); | |
| 4674 | } | |
| 4675 | ||
| 4676 | // make a type from the generic parameters supplied | |
| 4677 | assert(decl_node->type == NodeTypeFnProto); | |
| 4678 | AstNode *impl_decl_node = ast_clone_subtree(decl_node); | |
| 4679 | ||
| 4680 | preview_fn_proto_instance(g, import, decl_node, child_context); | |
| 4681 | ||
| 4682 | g->generic_table.put(generic_fn_type_id, impl_decl_node); | |
| 4683 | ||
| 4684 | FnTableEntry *fn_table_entry = decl_node->data.fn_proto.fn_table_entry; | |
| 4685 | return resolve_expr_const_val_as_fn(g, node, fn_table_entry); | |
| 4686 | } | |
| 4687 | ||
| 4544 | 4688 | static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 4545 | 4689 | TypeTableEntry *expected_type, AstNode *node) |
| 4546 | 4690 | { |
| ... | ... | @@ -4627,6 +4771,8 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 4627 | 4771 | |
| 4628 | 4772 | return analyze_fn_call_raw(g, import, context, expected_type, node, |
| 4629 | 4773 | const_val->data.x_fn, bare_struct_type); |
| 4774 | } else if (invoke_type_entry->id == TypeTableEntryIdGenericFn) { | |
| 4775 | return analyze_generic_fn_call(g, import, context, expected_type, node, const_val->data.x_type); | |
| 4630 | 4776 | } else { |
| 4631 | 4777 | add_node_error(g, fn_ref_expr, |
| 4632 | 4778 | buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name))); |
| ... | ... | @@ -4971,7 +5117,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, |
| 4971 | 5117 | Buf *var_name = &var_node->data.symbol_expr.symbol; |
| 4972 | 5118 | var_node->block_context = child_context; |
| 4973 | 5119 | prong_node->data.switch_prong.var = add_local_var(g, var_node, import, |
| 4974 | child_context, var_name, var_type, true); | |
| 5120 | child_context, var_name, var_type, true, nullptr); | |
| 4975 | 5121 | prong_node->data.switch_prong.var_is_target_expr = var_is_target_expr; |
| 4976 | 5122 | } |
| 4977 | 5123 | } |
| ... | ... | @@ -5391,7 +5537,7 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 5391 | 5537 | } |
| 5392 | 5538 | |
| 5393 | 5539 | VariableTableEntry *var = add_local_var(g, param_decl_node, import, context, &param_decl->name, |
| 5394 | type, true); | |
| 5540 | type, true, nullptr); | |
| 5395 | 5541 | var->src_arg_index = i; |
| 5396 | 5542 | param_decl_node->data.param_decl.variable = var; |
| 5397 | 5543 | |
| ... | ... | @@ -5413,7 +5559,9 @@ static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContex |
| 5413 | 5559 | tld->import = import; |
| 5414 | 5560 | tld->name = name; |
| 5415 | 5561 | |
| 5416 | if (g->check_unused || g->is_test_build || tld->visib_mod == VisibModExport) { | |
| 5562 | bool want_as_export = (g->check_unused || g->is_test_build || tld->visib_mod == VisibModExport); | |
| 5563 | bool is_generic = (node->type == NodeTypeFnProto && node->data.fn_proto.generic_params.length > 0); | |
| 5564 | if (!is_generic && want_as_export) { | |
| 5417 | 5565 | g->export_queue.append(node); |
| 5418 | 5566 | } |
| 5419 | 5567 | |
| ... | ... | @@ -5909,6 +6057,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 5909 | 6057 | case TypeTableEntryIdNumLitInt: |
| 5910 | 6058 | case TypeTableEntryIdUndefLit: |
| 5911 | 6059 | case TypeTableEntryIdNamespace: |
| 6060 | case TypeTableEntryIdGenericFn: | |
| 5912 | 6061 | zig_unreachable(); |
| 5913 | 6062 | case TypeTableEntryIdUnreachable: |
| 5914 | 6063 | case TypeTableEntryIdVoid: |
| ... | ... | @@ -5965,7 +6114,6 @@ uint32_t fn_type_id_hash(FnTypeId *id) { |
| 5965 | 6114 | result += id->is_cold ? 3605523458 : 0; |
| 5966 | 6115 | result += id->is_var_args ? 1931444534 : 0; |
| 5967 | 6116 | result += hash_ptr(id->return_type); |
| 5968 | result += id->param_count; | |
| 5969 | 6117 | for (int i = 0; i < id->param_count; i += 1) { |
| 5970 | 6118 | FnTypeParamInfo *info = &id->param_info[i]; |
| 5971 | 6119 | result += info->is_noalias ? 892356923 : 0; |
| ... | ... | @@ -5999,6 +6147,76 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { |
| 5999 | 6147 | return true; |
| 6000 | 6148 | } |
| 6001 | 6149 | |
| 6150 | static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val) { | |
| 6151 | switch (type->id) { | |
| 6152 | case TypeTableEntryIdBool: | |
| 6153 | return const_val->data.x_bool ? 127863866 : 215080464; | |
| 6154 | case TypeTableEntryIdMetaType: | |
| 6155 | return hash_ptr(const_val->data.x_type); | |
| 6156 | case TypeTableEntryIdVoid: | |
| 6157 | return 4149439618; | |
| 6158 | case TypeTableEntryIdInt: | |
| 6159 | case TypeTableEntryIdNumLitInt: | |
| 6160 | return ((uint32_t)(bignum_to_twos_complement(&const_val->data.x_bignum) % UINT32_MAX)) * 1331471175; | |
| 6161 | case TypeTableEntryIdFloat: | |
| 6162 | case TypeTableEntryIdNumLitFloat: | |
| 6163 | return const_val->data.x_bignum.data.x_float * UINT32_MAX; | |
| 6164 | case TypeTableEntryIdPointer: | |
| 6165 | return hash_ptr(const_val->data.x_ptr.ptr); | |
| 6166 | case TypeTableEntryIdUndefLit: | |
| 6167 | return 162837799; | |
| 6168 | case TypeTableEntryIdArray: | |
| 6169 | // TODO better hashing algorithm | |
| 6170 | return 1166190605; | |
| 6171 | case TypeTableEntryIdStruct: | |
| 6172 | // TODO better hashing algorithm | |
| 6173 | return 1532530855; | |
| 6174 | case TypeTableEntryIdMaybe: | |
| 6175 | if (const_val->data.x_maybe) { | |
| 6176 | TypeTableEntry *child_type = type->data.maybe.child_type; | |
| 6177 | return hash_const_val(child_type, const_val->data.x_maybe) * 1992916303; | |
| 6178 | } else { | |
| 6179 | return 4016830364; | |
| 6180 | } | |
| 6181 | case TypeTableEntryIdErrorUnion: | |
| 6182 | // TODO better hashing algorithm | |
| 6183 | return 3415065496; | |
| 6184 | case TypeTableEntryIdPureError: | |
| 6185 | // TODO better hashing algorithm | |
| 6186 | return 2630160122; | |
| 6187 | case TypeTableEntryIdEnum: | |
| 6188 | // TODO better hashing algorithm | |
| 6189 | return 31643936; | |
| 6190 | case TypeTableEntryIdFn: | |
| 6191 | return hash_ptr(const_val->data.x_fn); | |
| 6192 | case TypeTableEntryIdTypeDecl: | |
| 6193 | return hash_ptr(const_val->data.x_type); | |
| 6194 | case TypeTableEntryIdNamespace: | |
| 6195 | return hash_ptr(const_val->data.x_import); | |
| 6196 | case TypeTableEntryIdGenericFn: | |
| 6197 | case TypeTableEntryIdInvalid: | |
| 6198 | case TypeTableEntryIdUnreachable: | |
| 6199 | zig_unreachable(); | |
| 6200 | } | |
| 6201 | } | |
| 6202 | ||
| 6203 | uint32_t generic_fn_type_id_hash(GenericFnTypeId *id) { | |
| 6204 | uint32_t result = 0; | |
| 6205 | result += hash_ptr(id->decl_node); | |
| 6206 | for (int i = 0; i < id->generic_param_count; i += 1) { | |
| 6207 | GenericParamValue *generic_param = &id->generic_params[i]; | |
| 6208 | ConstExprValue *const_val = &get_resolved_expr(generic_param->node)->const_val; | |
| 6209 | assert(const_val->ok); | |
| 6210 | result += hash_const_val(generic_param->type, const_val); | |
| 6211 | } | |
| 6212 | return result; | |
| 6213 | } | |
| 6214 | ||
| 6215 | bool generic_fn_type_id_eql(GenericFnTypeId *a, GenericFnTypeId *b) { | |
| 6216 | // TODO | |
| 6217 | return true; | |
| 6218 | } | |
| 6219 | ||
| 6002 | 6220 | bool type_has_bits(TypeTableEntry *type_entry) { |
| 6003 | 6221 | assert(type_entry); |
| 6004 | 6222 | assert(type_entry->id != TypeTableEntryIdInvalid); |
| ... | ... | @@ -6027,6 +6245,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry) |
| 6027 | 6245 | case TypeTableEntryIdMetaType: |
| 6028 | 6246 | case TypeTableEntryIdVoid: |
| 6029 | 6247 | case TypeTableEntryIdNamespace: |
| 6248 | case TypeTableEntryIdGenericFn: | |
| 6030 | 6249 | zig_unreachable(); |
| 6031 | 6250 | case TypeTableEntryIdArray: |
| 6032 | 6251 | return type_of_first_thing_in_memory(type_entry->data.array.child_type); |
src/ast_render.cpp+22-311| ... | ... | @@ -59,15 +59,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) { |
| 59 | 59 | zig_unreachable(); |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | static const char *return_prefix_str(ReturnKind kind) { | |
| 63 | switch (kind) { | |
| 64 | case ReturnKindError: return "%"; | |
| 65 | case ReturnKindMaybe: return "?"; | |
| 66 | case ReturnKindUnconditional: return ""; | |
| 67 | } | |
| 68 | zig_unreachable(); | |
| 69 | } | |
| 70 | ||
| 71 | 62 | static const char *visib_mod_string(VisibMod mod) { |
| 72 | 63 | switch (mod) { |
| 73 | 64 | case VisibModPub: return "pub "; |
| ... | ... | @@ -195,316 +186,36 @@ static const char *node_type_str(NodeType node_type) { |
| 195 | 186 | zig_unreachable(); |
| 196 | 187 | } |
| 197 | 188 | |
| 189 | struct AstPrint { | |
| 190 | int indent; | |
| 191 | FILE *f; | |
| 192 | }; | |
| 198 | 193 | |
| 199 | void ast_print(FILE *f, AstNode *node, int indent) { | |
| 200 | for (int i = 0; i < indent; i += 1) { | |
| 201 | fprintf(f, " "); | |
| 202 | } | |
| 203 | assert(node->type == NodeTypeRoot || *node->parent_field == node); | |
| 204 | ||
| 205 | switch (node->type) { | |
| 206 | case NodeTypeRoot: | |
| 207 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 208 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { | |
| 209 | AstNode *child = node->data.root.top_level_decls.at(i); | |
| 210 | ast_print(f, child, indent + 2); | |
| 211 | } | |
| 212 | break; | |
| 213 | case NodeTypeFnDef: | |
| 214 | { | |
| 215 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 216 | AstNode *child = node->data.fn_def.fn_proto; | |
| 217 | ast_print(f, child, indent + 2); | |
| 218 | ast_print(f, node->data.fn_def.body, indent + 2); | |
| 219 | break; | |
| 220 | } | |
| 221 | case NodeTypeFnProto: | |
| 222 | { | |
| 223 | Buf *name_buf = &node->data.fn_proto.name; | |
| 224 | fprintf(f, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf)); | |
| 194 | static void ast_print_visit(AstNode **node_ptr, void *context) { | |
| 195 | AstNode *node = *node_ptr; | |
| 196 | AstPrint *ap = (AstPrint *)context; | |
| 225 | 197 | |
| 226 | for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { | |
| 227 | AstNode *child = node->data.fn_proto.params.at(i); | |
| 228 | ast_print(f, child, indent + 2); | |
| 229 | } | |
| 198 | for (int i = 0; i < ap->indent; i += 1) { | |
| 199 | fprintf(ap->f, " "); | |
| 200 | } | |
| 230 | 201 | |
| 231 | ast_print(f, node->data.fn_proto.return_type, indent + 2); | |
| 202 | fprintf(ap->f, "%s\n", node_type_str(node->type)); | |
| 232 | 203 | |
| 233 | break; | |
| 234 | } | |
| 235 | case NodeTypeBlock: | |
| 236 | { | |
| 237 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 238 | for (int i = 0; i < node->data.block.statements.length; i += 1) { | |
| 239 | AstNode *child = node->data.block.statements.at(i); | |
| 240 | ast_print(f, child, indent + 2); | |
| 241 | } | |
| 242 | break; | |
| 243 | } | |
| 244 | case NodeTypeParamDecl: | |
| 245 | { | |
| 246 | Buf *name_buf = &node->data.param_decl.name; | |
| 247 | fprintf(f, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf)); | |
| 204 | AstPrint new_ap; | |
| 205 | new_ap.indent = ap->indent + 2; | |
| 206 | new_ap.f = ap->f; | |
| 248 | 207 | |
| 249 | ast_print(f, node->data.param_decl.type, indent + 2); | |
| 208 | ast_visit_node_children(node, ast_print_visit, &new_ap); | |
| 209 | } | |
| 250 | 210 | |
| 251 | break; | |
| 252 | } | |
| 253 | case NodeTypeReturnExpr: | |
| 254 | { | |
| 255 | const char *prefix_str = return_prefix_str(node->data.return_expr.kind); | |
| 256 | fprintf(f, "%s%s\n", prefix_str, node_type_str(node->type)); | |
| 257 | if (node->data.return_expr.expr) | |
| 258 | ast_print(f, node->data.return_expr.expr, indent + 2); | |
| 259 | break; | |
| 260 | } | |
| 261 | case NodeTypeDefer: | |
| 262 | { | |
| 263 | const char *prefix_str = return_prefix_str(node->data.defer.kind); | |
| 264 | fprintf(f, "%s%s\n", prefix_str, node_type_str(node->type)); | |
| 265 | if (node->data.defer.expr) | |
| 266 | ast_print(f, node->data.defer.expr, indent + 2); | |
| 267 | break; | |
| 268 | } | |
| 269 | case NodeTypeVariableDeclaration: | |
| 270 | { | |
| 271 | Buf *name_buf = &node->data.variable_declaration.symbol; | |
| 272 | fprintf(f, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf)); | |
| 273 | if (node->data.variable_declaration.type) | |
| 274 | ast_print(f, node->data.variable_declaration.type, indent + 2); | |
| 275 | if (node->data.variable_declaration.expr) | |
| 276 | ast_print(f, node->data.variable_declaration.expr, indent + 2); | |
| 277 | break; | |
| 278 | } | |
| 279 | case NodeTypeTypeDecl: | |
| 280 | { | |
| 281 | Buf *name_buf = &node->data.type_decl.symbol; | |
| 282 | fprintf(f, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf)); | |
| 283 | ast_print(f, node->data.type_decl.child_type, indent + 2); | |
| 284 | break; | |
| 285 | } | |
| 286 | case NodeTypeErrorValueDecl: | |
| 287 | { | |
| 288 | Buf *name_buf = &node->data.error_value_decl.name; | |
| 289 | fprintf(f, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf)); | |
| 290 | break; | |
| 291 | } | |
| 292 | case NodeTypeFnDecl: | |
| 293 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 294 | ast_print(f, node->data.fn_decl.fn_proto, indent + 2); | |
| 295 | break; | |
| 296 | case NodeTypeBinOpExpr: | |
| 297 | fprintf(f, "%s %s\n", node_type_str(node->type), | |
| 298 | bin_op_str(node->data.bin_op_expr.bin_op)); | |
| 299 | ast_print(f, node->data.bin_op_expr.op1, indent + 2); | |
| 300 | ast_print(f, node->data.bin_op_expr.op2, indent + 2); | |
| 301 | break; | |
| 302 | case NodeTypeUnwrapErrorExpr: | |
| 303 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 304 | ast_print(f, node->data.unwrap_err_expr.op1, indent + 2); | |
| 305 | if (node->data.unwrap_err_expr.symbol) { | |
| 306 | ast_print(f, node->data.unwrap_err_expr.symbol, indent + 2); | |
| 307 | } | |
| 308 | ast_print(f, node->data.unwrap_err_expr.op2, indent + 2); | |
| 309 | break; | |
| 310 | case NodeTypeFnCallExpr: | |
| 311 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 312 | ast_print(f, node->data.fn_call_expr.fn_ref_expr, indent + 2); | |
| 313 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { | |
| 314 | AstNode *child = node->data.fn_call_expr.params.at(i); | |
| 315 | ast_print(f, child, indent + 2); | |
| 316 | } | |
| 317 | break; | |
| 318 | case NodeTypeArrayAccessExpr: | |
| 319 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 320 | ast_print(f, node->data.array_access_expr.array_ref_expr, indent + 2); | |
| 321 | ast_print(f, node->data.array_access_expr.subscript, indent + 2); | |
| 322 | break; | |
| 323 | case NodeTypeSliceExpr: | |
| 324 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 325 | ast_print(f, node->data.slice_expr.array_ref_expr, indent + 2); | |
| 326 | ast_print(f, node->data.slice_expr.start, indent + 2); | |
| 327 | if (node->data.slice_expr.end) { | |
| 328 | ast_print(f, node->data.slice_expr.end, indent + 2); | |
| 329 | } | |
| 330 | break; | |
| 331 | case NodeTypeDirective: | |
| 332 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 333 | ast_print(f, node->data.directive.expr, indent + 2); | |
| 334 | break; | |
| 335 | case NodeTypePrefixOpExpr: | |
| 336 | fprintf(f, "%s %s\n", node_type_str(node->type), | |
| 337 | prefix_op_str(node->data.prefix_op_expr.prefix_op)); | |
| 338 | ast_print(f, node->data.prefix_op_expr.primary_expr, indent + 2); | |
| 339 | break; | |
| 340 | case NodeTypeNumberLiteral: | |
| 341 | { | |
| 342 | NumLit kind = node->data.number_literal.kind; | |
| 343 | const char *name = node_type_str(node->type); | |
| 344 | if (kind == NumLitUInt) { | |
| 345 | fprintf(f, "%s uint %" PRIu64 "\n", name, node->data.number_literal.data.x_uint); | |
| 346 | } else { | |
| 347 | fprintf(f, "%s float %f\n", name, node->data.number_literal.data.x_float); | |
| 348 | } | |
| 349 | break; | |
| 350 | } | |
| 351 | case NodeTypeStringLiteral: | |
| 352 | { | |
| 353 | const char *c = node->data.string_literal.c ? "c" : ""; | |
| 354 | fprintf(f, "StringLiteral %s'%s'\n", c, | |
| 355 | buf_ptr(&node->data.string_literal.buf)); | |
| 356 | break; | |
| 357 | } | |
| 358 | case NodeTypeCharLiteral: | |
| 359 | { | |
| 360 | fprintf(f, "%s '%c'\n", node_type_str(node->type), node->data.char_literal.value); | |
| 361 | break; | |
| 362 | } | |
| 363 | case NodeTypeSymbol: | |
| 364 | fprintf(f, "Symbol %s\n", buf_ptr(&node->data.symbol_expr.symbol)); | |
| 365 | break; | |
| 366 | case NodeTypeUse: | |
| 367 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 368 | ast_print(f, node->data.use.expr, indent + 2); | |
| 369 | break; | |
| 370 | case NodeTypeBoolLiteral: | |
| 371 | fprintf(f, "%s '%s'\n", node_type_str(node->type), | |
| 372 | node->data.bool_literal.value ? "true" : "false"); | |
| 373 | break; | |
| 374 | case NodeTypeNullLiteral: | |
| 375 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 376 | break; | |
| 377 | case NodeTypeIfBoolExpr: | |
| 378 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 379 | if (node->data.if_bool_expr.condition) | |
| 380 | ast_print(f, node->data.if_bool_expr.condition, indent + 2); | |
| 381 | ast_print(f, node->data.if_bool_expr.then_block, indent + 2); | |
| 382 | if (node->data.if_bool_expr.else_node) | |
| 383 | ast_print(f, node->data.if_bool_expr.else_node, indent + 2); | |
| 384 | break; | |
| 385 | case NodeTypeIfVarExpr: | |
| 386 | { | |
| 387 | Buf *name_buf = &node->data.if_var_expr.var_decl.symbol; | |
| 388 | fprintf(f, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf)); | |
| 389 | if (node->data.if_var_expr.var_decl.type) | |
| 390 | ast_print(f, node->data.if_var_expr.var_decl.type, indent + 2); | |
| 391 | if (node->data.if_var_expr.var_decl.expr) | |
| 392 | ast_print(f, node->data.if_var_expr.var_decl.expr, indent + 2); | |
| 393 | ast_print(f, node->data.if_var_expr.then_block, indent + 2); | |
| 394 | if (node->data.if_var_expr.else_node) | |
| 395 | ast_print(f, node->data.if_var_expr.else_node, indent + 2); | |
| 396 | break; | |
| 397 | } | |
| 398 | case NodeTypeWhileExpr: | |
| 399 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 400 | ast_print(f, node->data.while_expr.condition, indent + 2); | |
| 401 | ast_print(f, node->data.while_expr.body, indent + 2); | |
| 402 | break; | |
| 403 | case NodeTypeForExpr: | |
| 404 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 405 | ast_print(f, node->data.for_expr.elem_node, indent + 2); | |
| 406 | ast_print(f, node->data.for_expr.array_expr, indent + 2); | |
| 407 | if (node->data.for_expr.index_node) { | |
| 408 | ast_print(f, node->data.for_expr.index_node, indent + 2); | |
| 409 | } | |
| 410 | ast_print(f, node->data.for_expr.body, indent + 2); | |
| 411 | break; | |
| 412 | case NodeTypeSwitchExpr: | |
| 413 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 414 | ast_print(f, node->data.switch_expr.expr, indent + 2); | |
| 415 | for (int i = 0; i < node->data.switch_expr.prongs.length; i += 1) { | |
| 416 | AstNode *child_node = node->data.switch_expr.prongs.at(i); | |
| 417 | ast_print(f, child_node, indent + 2); | |
| 418 | } | |
| 419 | break; | |
| 420 | case NodeTypeSwitchProng: | |
| 421 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 422 | for (int i = 0; i < node->data.switch_prong.items.length; i += 1) { | |
| 423 | AstNode *child_node = node->data.switch_prong.items.at(i); | |
| 424 | ast_print(f, child_node, indent + 2); | |
| 425 | } | |
| 426 | if (node->data.switch_prong.var_symbol) { | |
| 427 | ast_print(f, node->data.switch_prong.var_symbol, indent + 2); | |
| 428 | } | |
| 429 | ast_print(f, node->data.switch_prong.expr, indent + 2); | |
| 430 | break; | |
| 431 | case NodeTypeSwitchRange: | |
| 432 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 433 | ast_print(f, node->data.switch_range.start, indent + 2); | |
| 434 | ast_print(f, node->data.switch_range.end, indent + 2); | |
| 435 | break; | |
| 436 | case NodeTypeLabel: | |
| 437 | fprintf(f, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.label.name)); | |
| 438 | break; | |
| 439 | case NodeTypeGoto: | |
| 440 | fprintf(f, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.goto_expr.name)); | |
| 441 | break; | |
| 442 | case NodeTypeBreak: | |
| 443 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 444 | break; | |
| 445 | case NodeTypeContinue: | |
| 446 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 447 | break; | |
| 448 | case NodeTypeUndefinedLiteral: | |
| 449 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 450 | break; | |
| 451 | case NodeTypeAsmExpr: | |
| 452 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 453 | break; | |
| 454 | case NodeTypeFieldAccessExpr: | |
| 455 | fprintf(f, "%s '%s'\n", node_type_str(node->type), | |
| 456 | buf_ptr(&node->data.field_access_expr.field_name)); | |
| 457 | ast_print(f, node->data.field_access_expr.struct_expr, indent + 2); | |
| 458 | break; | |
| 459 | case NodeTypeStructDecl: | |
| 460 | fprintf(f, "%s '%s'\n", | |
| 461 | node_type_str(node->type), buf_ptr(&node->data.struct_decl.name)); | |
| 462 | for (int i = 0; i < node->data.struct_decl.fields.length; i += 1) { | |
| 463 | AstNode *child = node->data.struct_decl.fields.at(i); | |
| 464 | ast_print(f, child, indent + 2); | |
| 465 | } | |
| 466 | for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) { | |
| 467 | AstNode *child = node->data.struct_decl.fns.at(i); | |
| 468 | ast_print(f, child, indent + 2); | |
| 469 | } | |
| 470 | break; | |
| 471 | case NodeTypeStructField: | |
| 472 | fprintf(f, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_field.name)); | |
| 473 | if (node->data.struct_field.type) { | |
| 474 | ast_print(f, node->data.struct_field.type, indent + 2); | |
| 475 | } | |
| 476 | break; | |
| 477 | case NodeTypeStructValueField: | |
| 478 | fprintf(f, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_val_field.name)); | |
| 479 | ast_print(f, node->data.struct_val_field.expr, indent + 2); | |
| 480 | break; | |
| 481 | case NodeTypeContainerInitExpr: | |
| 482 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 483 | ast_print(f, node->data.container_init_expr.type, indent + 2); | |
| 484 | for (int i = 0; i < node->data.container_init_expr.entries.length; i += 1) { | |
| 485 | AstNode *child = node->data.container_init_expr.entries.at(i); | |
| 486 | ast_print(f, child, indent + 2); | |
| 487 | } | |
| 488 | break; | |
| 489 | case NodeTypeArrayType: | |
| 490 | { | |
| 491 | const char *const_str = node->data.array_type.is_const ? "const" : "var"; | |
| 492 | fprintf(f, "%s %s\n", node_type_str(node->type), const_str); | |
| 493 | if (node->data.array_type.size) { | |
| 494 | ast_print(f, node->data.array_type.size, indent + 2); | |
| 495 | } | |
| 496 | ast_print(f, node->data.array_type.child_type, indent + 2); | |
| 497 | break; | |
| 498 | } | |
| 499 | case NodeTypeErrorType: | |
| 500 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 501 | break; | |
| 502 | case NodeTypeTypeLiteral: | |
| 503 | fprintf(f, "%s\n", node_type_str(node->type)); | |
| 504 | break; | |
| 505 | } | |
| 211 | void ast_print(FILE *f, AstNode *node, int indent) { | |
| 212 | AstPrint ap; | |
| 213 | ap.indent = indent; | |
| 214 | ap.f = f; | |
| 215 | ast_visit_node_children(node, ast_print_visit, &ap); | |
| 506 | 216 | } |
| 507 | 217 | |
| 218 | ||
| 508 | 219 | struct AstRender { |
| 509 | 220 | int indent; |
| 510 | 221 | int indent_size; |
src/ast_render.hpp+1| ... | ... | @@ -9,6 +9,7 @@ |
| 9 | 9 | #define ZIG_AST_RENDER_HPP |
| 10 | 10 | |
| 11 | 11 | #include "all_types.hpp" |
| 12 | #include "parser.hpp" | |
| 12 | 13 | |
| 13 | 14 | #include <stdio.h> |
| 14 | 15 |
src/codegen.cpp+2| ... | ... | @@ -62,6 +62,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { |
| 62 | 62 | g->primitive_type_table.init(32); |
| 63 | 63 | g->fn_type_table.init(32); |
| 64 | 64 | g->error_table.init(16); |
| 65 | g->generic_table.init(16); | |
| 65 | 66 | g->is_release_build = false; |
| 66 | 67 | g->is_test_build = false; |
| 67 | 68 | g->error_value_count = 1; |
| ... | ... | @@ -2927,6 +2928,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE |
| 2927 | 2928 | case TypeTableEntryIdUndefLit: |
| 2928 | 2929 | case TypeTableEntryIdVoid: |
| 2929 | 2930 | case TypeTableEntryIdNamespace: |
| 2931 | case TypeTableEntryIdGenericFn: | |
| 2930 | 2932 | zig_unreachable(); |
| 2931 | 2933 | |
| 2932 | 2934 | } |
src/parser.cpp+110-72| ... | ... | @@ -2243,7 +2243,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato |
| 2243 | 2243 | } |
| 2244 | 2244 | |
| 2245 | 2245 | /* |
| 2246 | FnProto : "fn" option("Symbol") ParamDeclList option("->" PrefixOpExpression) | |
| 2246 | FnProto = "fn" option("Symbol") option(ParamDeclList) ParamDeclList option("->" TypeExpr) | |
| 2247 | 2247 | */ |
| 2248 | 2248 | static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory, |
| 2249 | 2249 | ZigList<AstNode*> *directives, VisibMod visib_mod) |
| ... | ... | @@ -2273,6 +2273,17 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand |
| 2273 | 2273 | |
| 2274 | 2274 | ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args); |
| 2275 | 2275 | |
| 2276 | Token *maybe_lparen = &pc->tokens->at(*token_index); | |
| 2277 | if (maybe_lparen->id == TokenIdLParen) { | |
| 2278 | for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { | |
| 2279 | node->data.fn_proto.generic_params.append(node->data.fn_proto.params.at(i)); | |
| 2280 | } | |
| 2281 | node->data.fn_proto.generic_params_is_var_args = node->data.fn_proto.is_var_args; | |
| 2282 | ||
| 2283 | node->data.fn_proto.params.resize(0); | |
| 2284 | ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args); | |
| 2285 | } | |
| 2286 | ||
| 2276 | 2287 | Token *next_token = &pc->tokens->at(*token_index); |
| 2277 | 2288 | if (next_token->id == TokenIdArrow) { |
| 2278 | 2289 | *token_index += 1; |
| ... | ... | @@ -2626,72 +2637,73 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, |
| 2626 | 2637 | return pc.root; |
| 2627 | 2638 | } |
| 2628 | 2639 | |
| 2629 | static void set_field(AstNode **field) { | |
| 2630 | if (*field) { | |
| 2631 | (*field)->parent_field = field; | |
| 2640 | static void visit_field(AstNode **node, void (*visit)(AstNode **, void *context), void *context) { | |
| 2641 | if (*node) { | |
| 2642 | visit(node, context); | |
| 2632 | 2643 | } |
| 2633 | 2644 | } |
| 2634 | 2645 | |
| 2635 | static void set_list_fields(ZigList<AstNode*> *list) { | |
| 2646 | static void visit_node_list(ZigList<AstNode *> *list, void (*visit)(AstNode **, void *context), void *context) { | |
| 2636 | 2647 | if (list) { |
| 2637 | 2648 | for (int i = 0; i < list->length; i += 1) { |
| 2638 | set_field(&list->at(i)); | |
| 2649 | visit(&list->at(i), context); | |
| 2639 | 2650 | } |
| 2640 | 2651 | } |
| 2641 | 2652 | } |
| 2642 | 2653 | |
| 2643 | void normalize_parent_ptrs(AstNode *node) { | |
| 2654 | void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context) { | |
| 2644 | 2655 | switch (node->type) { |
| 2645 | 2656 | case NodeTypeRoot: |
| 2646 | set_list_fields(&node->data.root.top_level_decls); | |
| 2657 | visit_node_list(&node->data.root.top_level_decls, visit, context); | |
| 2647 | 2658 | break; |
| 2648 | 2659 | case NodeTypeFnProto: |
| 2649 | set_field(&node->data.fn_proto.return_type); | |
| 2650 | set_list_fields(node->data.fn_proto.top_level_decl.directives); | |
| 2651 | set_list_fields(&node->data.fn_proto.params); | |
| 2660 | visit_field(&node->data.fn_proto.return_type, visit, context); | |
| 2661 | visit_node_list(node->data.fn_proto.top_level_decl.directives, visit, context); | |
| 2662 | visit_node_list(&node->data.fn_proto.generic_params, visit, context); | |
| 2663 | visit_node_list(&node->data.fn_proto.params, visit, context); | |
| 2652 | 2664 | break; |
| 2653 | 2665 | case NodeTypeFnDef: |
| 2654 | set_field(&node->data.fn_def.fn_proto); | |
| 2655 | set_field(&node->data.fn_def.body); | |
| 2666 | visit_field(&node->data.fn_def.fn_proto, visit, context); | |
| 2667 | visit_field(&node->data.fn_def.body, visit, context); | |
| 2656 | 2668 | break; |
| 2657 | 2669 | case NodeTypeFnDecl: |
| 2658 | set_field(&node->data.fn_decl.fn_proto); | |
| 2670 | visit_field(&node->data.fn_decl.fn_proto, visit, context); | |
| 2659 | 2671 | break; |
| 2660 | 2672 | case NodeTypeParamDecl: |
| 2661 | set_field(&node->data.param_decl.type); | |
| 2673 | visit_field(&node->data.param_decl.type, visit, context); | |
| 2662 | 2674 | break; |
| 2663 | 2675 | case NodeTypeBlock: |
| 2664 | set_list_fields(&node->data.block.statements); | |
| 2676 | visit_node_list(&node->data.block.statements, visit, context); | |
| 2665 | 2677 | break; |
| 2666 | 2678 | case NodeTypeDirective: |
| 2667 | set_field(&node->data.directive.expr); | |
| 2679 | visit_field(&node->data.directive.expr, visit, context); | |
| 2668 | 2680 | break; |
| 2669 | 2681 | case NodeTypeReturnExpr: |
| 2670 | set_field(&node->data.return_expr.expr); | |
| 2682 | visit_field(&node->data.return_expr.expr, visit, context); | |
| 2671 | 2683 | break; |
| 2672 | 2684 | case NodeTypeDefer: |
| 2673 | set_field(&node->data.defer.expr); | |
| 2685 | visit_field(&node->data.defer.expr, visit, context); | |
| 2674 | 2686 | break; |
| 2675 | 2687 | case NodeTypeVariableDeclaration: |
| 2676 | set_list_fields(node->data.variable_declaration.top_level_decl.directives); | |
| 2677 | set_field(&node->data.variable_declaration.type); | |
| 2678 | set_field(&node->data.variable_declaration.expr); | |
| 2688 | visit_node_list(node->data.variable_declaration.top_level_decl.directives, visit, context); | |
| 2689 | visit_field(&node->data.variable_declaration.type, visit, context); | |
| 2690 | visit_field(&node->data.variable_declaration.expr, visit, context); | |
| 2679 | 2691 | break; |
| 2680 | 2692 | case NodeTypeTypeDecl: |
| 2681 | set_list_fields(node->data.type_decl.top_level_decl.directives); | |
| 2682 | set_field(&node->data.type_decl.child_type); | |
| 2693 | visit_node_list(node->data.type_decl.top_level_decl.directives, visit, context); | |
| 2694 | visit_field(&node->data.type_decl.child_type, visit, context); | |
| 2683 | 2695 | break; |
| 2684 | 2696 | case NodeTypeErrorValueDecl: |
| 2685 | 2697 | // none |
| 2686 | 2698 | break; |
| 2687 | 2699 | case NodeTypeBinOpExpr: |
| 2688 | set_field(&node->data.bin_op_expr.op1); | |
| 2689 | set_field(&node->data.bin_op_expr.op2); | |
| 2700 | visit_field(&node->data.bin_op_expr.op1, visit, context); | |
| 2701 | visit_field(&node->data.bin_op_expr.op2, visit, context); | |
| 2690 | 2702 | break; |
| 2691 | 2703 | case NodeTypeUnwrapErrorExpr: |
| 2692 | set_field(&node->data.unwrap_err_expr.op1); | |
| 2693 | set_field(&node->data.unwrap_err_expr.symbol); | |
| 2694 | set_field(&node->data.unwrap_err_expr.op2); | |
| 2704 | visit_field(&node->data.unwrap_err_expr.op1, visit, context); | |
| 2705 | visit_field(&node->data.unwrap_err_expr.symbol, visit, context); | |
| 2706 | visit_field(&node->data.unwrap_err_expr.op2, visit, context); | |
| 2695 | 2707 | break; |
| 2696 | 2708 | case NodeTypeNumberLiteral: |
| 2697 | 2709 | // none |
| ... | ... | @@ -2706,27 +2718,27 @@ void normalize_parent_ptrs(AstNode *node) { |
| 2706 | 2718 | // none |
| 2707 | 2719 | break; |
| 2708 | 2720 | case NodeTypePrefixOpExpr: |
| 2709 | set_field(&node->data.prefix_op_expr.primary_expr); | |
| 2721 | visit_field(&node->data.prefix_op_expr.primary_expr, visit, context); | |
| 2710 | 2722 | break; |
| 2711 | 2723 | case NodeTypeFnCallExpr: |
| 2712 | set_field(&node->data.fn_call_expr.fn_ref_expr); | |
| 2713 | set_list_fields(&node->data.fn_call_expr.params); | |
| 2724 | visit_field(&node->data.fn_call_expr.fn_ref_expr, visit, context); | |
| 2725 | visit_node_list(&node->data.fn_call_expr.params, visit, context); | |
| 2714 | 2726 | break; |
| 2715 | 2727 | case NodeTypeArrayAccessExpr: |
| 2716 | set_field(&node->data.array_access_expr.array_ref_expr); | |
| 2717 | set_field(&node->data.array_access_expr.subscript); | |
| 2728 | visit_field(&node->data.array_access_expr.array_ref_expr, visit, context); | |
| 2729 | visit_field(&node->data.array_access_expr.subscript, visit, context); | |
| 2718 | 2730 | break; |
| 2719 | 2731 | case NodeTypeSliceExpr: |
| 2720 | set_field(&node->data.slice_expr.array_ref_expr); | |
| 2721 | set_field(&node->data.slice_expr.start); | |
| 2722 | set_field(&node->data.slice_expr.end); | |
| 2732 | visit_field(&node->data.slice_expr.array_ref_expr, visit, context); | |
| 2733 | visit_field(&node->data.slice_expr.start, visit, context); | |
| 2734 | visit_field(&node->data.slice_expr.end, visit, context); | |
| 2723 | 2735 | break; |
| 2724 | 2736 | case NodeTypeFieldAccessExpr: |
| 2725 | set_field(&node->data.field_access_expr.struct_expr); | |
| 2737 | visit_field(&node->data.field_access_expr.struct_expr, visit, context); | |
| 2726 | 2738 | break; |
| 2727 | 2739 | case NodeTypeUse: |
| 2728 | set_field(&node->data.use.expr); | |
| 2729 | set_list_fields(node->data.use.top_level_decl.directives); | |
| 2740 | visit_field(&node->data.use.expr, visit, context); | |
| 2741 | visit_node_list(node->data.use.top_level_decl.directives, visit, context); | |
| 2730 | 2742 | break; |
| 2731 | 2743 | case NodeTypeBoolLiteral: |
| 2732 | 2744 | // none |
| ... | ... | @@ -2738,38 +2750,38 @@ void normalize_parent_ptrs(AstNode *node) { |
| 2738 | 2750 | // none |
| 2739 | 2751 | break; |
| 2740 | 2752 | case NodeTypeIfBoolExpr: |
| 2741 | set_field(&node->data.if_bool_expr.condition); | |
| 2742 | set_field(&node->data.if_bool_expr.then_block); | |
| 2743 | set_field(&node->data.if_bool_expr.else_node); | |
| 2753 | visit_field(&node->data.if_bool_expr.condition, visit, context); | |
| 2754 | visit_field(&node->data.if_bool_expr.then_block, visit, context); | |
| 2755 | visit_field(&node->data.if_bool_expr.else_node, visit, context); | |
| 2744 | 2756 | break; |
| 2745 | 2757 | case NodeTypeIfVarExpr: |
| 2746 | set_field(&node->data.if_var_expr.var_decl.type); | |
| 2747 | set_field(&node->data.if_var_expr.var_decl.expr); | |
| 2748 | set_field(&node->data.if_var_expr.then_block); | |
| 2749 | set_field(&node->data.if_var_expr.else_node); | |
| 2758 | visit_field(&node->data.if_var_expr.var_decl.type, visit, context); | |
| 2759 | visit_field(&node->data.if_var_expr.var_decl.expr, visit, context); | |
| 2760 | visit_field(&node->data.if_var_expr.then_block, visit, context); | |
| 2761 | visit_field(&node->data.if_var_expr.else_node, visit, context); | |
| 2750 | 2762 | break; |
| 2751 | 2763 | case NodeTypeWhileExpr: |
| 2752 | set_field(&node->data.while_expr.condition); | |
| 2753 | set_field(&node->data.while_expr.body); | |
| 2764 | visit_field(&node->data.while_expr.condition, visit, context); | |
| 2765 | visit_field(&node->data.while_expr.body, visit, context); | |
| 2754 | 2766 | break; |
| 2755 | 2767 | case NodeTypeForExpr: |
| 2756 | set_field(&node->data.for_expr.elem_node); | |
| 2757 | set_field(&node->data.for_expr.array_expr); | |
| 2758 | set_field(&node->data.for_expr.index_node); | |
| 2759 | set_field(&node->data.for_expr.body); | |
| 2768 | visit_field(&node->data.for_expr.elem_node, visit, context); | |
| 2769 | visit_field(&node->data.for_expr.array_expr, visit, context); | |
| 2770 | visit_field(&node->data.for_expr.index_node, visit, context); | |
| 2771 | visit_field(&node->data.for_expr.body, visit, context); | |
| 2760 | 2772 | break; |
| 2761 | 2773 | case NodeTypeSwitchExpr: |
| 2762 | set_field(&node->data.switch_expr.expr); | |
| 2763 | set_list_fields(&node->data.switch_expr.prongs); | |
| 2774 | visit_field(&node->data.switch_expr.expr, visit, context); | |
| 2775 | visit_node_list(&node->data.switch_expr.prongs, visit, context); | |
| 2764 | 2776 | break; |
| 2765 | 2777 | case NodeTypeSwitchProng: |
| 2766 | set_list_fields(&node->data.switch_prong.items); | |
| 2767 | set_field(&node->data.switch_prong.var_symbol); | |
| 2768 | set_field(&node->data.switch_prong.expr); | |
| 2778 | visit_node_list(&node->data.switch_prong.items, visit, context); | |
| 2779 | visit_field(&node->data.switch_prong.var_symbol, visit, context); | |
| 2780 | visit_field(&node->data.switch_prong.expr, visit, context); | |
| 2769 | 2781 | break; |
| 2770 | 2782 | case NodeTypeSwitchRange: |
| 2771 | set_field(&node->data.switch_range.start); | |
| 2772 | set_field(&node->data.switch_range.end); | |
| 2783 | visit_field(&node->data.switch_range.start, visit, context); | |
| 2784 | visit_field(&node->data.switch_range.end, visit, context); | |
| 2773 | 2785 | break; |
| 2774 | 2786 | case NodeTypeLabel: |
| 2775 | 2787 | // none |
| ... | ... | @@ -2786,32 +2798,32 @@ void normalize_parent_ptrs(AstNode *node) { |
| 2786 | 2798 | case NodeTypeAsmExpr: |
| 2787 | 2799 | for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) { |
| 2788 | 2800 | AsmInput *asm_input = node->data.asm_expr.input_list.at(i); |
| 2789 | set_field(&asm_input->expr); | |
| 2801 | visit_field(&asm_input->expr, visit, context); | |
| 2790 | 2802 | } |
| 2791 | 2803 | for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) { |
| 2792 | 2804 | AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); |
| 2793 | set_field(&asm_output->return_type); | |
| 2805 | visit_field(&asm_output->return_type, visit, context); | |
| 2794 | 2806 | } |
| 2795 | 2807 | break; |
| 2796 | 2808 | case NodeTypeStructDecl: |
| 2797 | set_list_fields(&node->data.struct_decl.fields); | |
| 2798 | set_list_fields(&node->data.struct_decl.fns); | |
| 2799 | set_list_fields(node->data.struct_decl.top_level_decl.directives); | |
| 2809 | visit_node_list(&node->data.struct_decl.fields, visit, context); | |
| 2810 | visit_node_list(&node->data.struct_decl.fns, visit, context); | |
| 2811 | visit_node_list(node->data.struct_decl.top_level_decl.directives, visit, context); | |
| 2800 | 2812 | break; |
| 2801 | 2813 | case NodeTypeStructField: |
| 2802 | set_field(&node->data.struct_field.type); | |
| 2803 | set_list_fields(node->data.struct_field.top_level_decl.directives); | |
| 2814 | visit_field(&node->data.struct_field.type, visit, context); | |
| 2815 | visit_node_list(node->data.struct_field.top_level_decl.directives, visit, context); | |
| 2804 | 2816 | break; |
| 2805 | 2817 | case NodeTypeContainerInitExpr: |
| 2806 | set_field(&node->data.container_init_expr.type); | |
| 2807 | set_list_fields(&node->data.container_init_expr.entries); | |
| 2818 | visit_field(&node->data.container_init_expr.type, visit, context); | |
| 2819 | visit_node_list(&node->data.container_init_expr.entries, visit, context); | |
| 2808 | 2820 | break; |
| 2809 | 2821 | case NodeTypeStructValueField: |
| 2810 | set_field(&node->data.struct_val_field.expr); | |
| 2822 | visit_field(&node->data.struct_val_field.expr, visit, context); | |
| 2811 | 2823 | break; |
| 2812 | 2824 | case NodeTypeArrayType: |
| 2813 | set_field(&node->data.array_type.size); | |
| 2814 | set_field(&node->data.array_type.child_type); | |
| 2825 | visit_field(&node->data.array_type.size, visit, context); | |
| 2826 | visit_field(&node->data.array_type.child_type, visit, context); | |
| 2815 | 2827 | break; |
| 2816 | 2828 | case NodeTypeErrorType: |
| 2817 | 2829 | // none |
| ... | ... | @@ -2821,3 +2833,29 @@ void normalize_parent_ptrs(AstNode *node) { |
| 2821 | 2833 | break; |
| 2822 | 2834 | } |
| 2823 | 2835 | } |
| 2836 | ||
| 2837 | static void normalize_parent_ptrs_visit(AstNode **node, void *context) { | |
| 2838 | (*node)->parent_field = node; | |
| 2839 | } | |
| 2840 | ||
| 2841 | void normalize_parent_ptrs(AstNode *node) { | |
| 2842 | ast_visit_node_children(node, normalize_parent_ptrs_visit, nullptr); | |
| 2843 | } | |
| 2844 | ||
| 2845 | static AstNode *clone_node(AstNode *old_node) { | |
| 2846 | AstNode *new_node = allocate_nonzero<AstNode>(1); | |
| 2847 | memcpy(new_node, old_node, sizeof(AstNode)); | |
| 2848 | return new_node; | |
| 2849 | } | |
| 2850 | ||
| 2851 | static void ast_clone_subtree_visit(AstNode **node, void *context) { | |
| 2852 | *node = clone_node(*node); | |
| 2853 | (*node)->parent_field = node; | |
| 2854 | ast_visit_node_children(*node, ast_clone_subtree_visit, nullptr); | |
| 2855 | } | |
| 2856 | ||
| 2857 | AstNode *ast_clone_subtree(AstNode *old_node) { | |
| 2858 | AstNode *new_node = clone_node(old_node); | |
| 2859 | ast_visit_node_children(new_node, ast_clone_subtree_visit, nullptr); | |
| 2860 | return new_node; | |
| 2861 | } |
src/parser.hpp+3-2| ... | ... | @@ -20,10 +20,11 @@ void ast_token_error(Token *token, const char *format, ...); |
| 20 | 20 | AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color, |
| 21 | 21 | uint32_t *next_node_index); |
| 22 | 22 | |
| 23 | const char *node_type_str(NodeType node_type); | |
| 24 | ||
| 25 | 23 | void ast_print(AstNode *node, int indent); |
| 26 | 24 | |
| 27 | 25 | void normalize_parent_ptrs(AstNode *node); |
| 28 | 26 | |
| 27 | AstNode *ast_clone_subtree(AstNode *node); | |
| 28 | void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *context), void *context); | |
| 29 | ||
| 29 | 30 | #endif |
test/self_hosted.zig+10| ... | ... | @@ -512,6 +512,16 @@ three)"; |
| 512 | 512 | |
| 513 | 513 | |
| 514 | 514 | |
| 515 | #attribute("test") | |
| 516 | fn simple_generic_fn() { | |
| 517 | assert(max(i32)(3, -1) == 3); | |
| 518 | } | |
| 519 | ||
| 520 | fn max(T: type)(a: T, b: T) -> T { | |
| 521 | return if (a > b) a else b; | |
| 522 | } | |
| 523 | ||
| 524 | ||
| 515 | 525 | fn assert(b: bool) { |
| 516 | 526 | if (!b) unreachable{} |
| 517 | 527 | } |