| 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,7 +25,7 @@ UseDecl = "use" Expression ";" |
| 25 | 25 | ||
| 26 | ExternDecl = "extern" (FnProto | VariableDeclaration) ";" | 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 | Directive = "#" "Symbol" "(" Expression ")" | 30 | Directive = "#" "Symbol" "(" Expression ")" |
| 31 | 31 |
src/all_types.hpp+29-1| ... | @@ -193,8 +193,10 @@ struct AstNodeRoot { | ... | @@ -193,8 +193,10 @@ struct AstNodeRoot { |
| 193 | struct AstNodeFnProto { | 193 | struct AstNodeFnProto { |
| 194 | TopLevelDecl top_level_decl; | 194 | TopLevelDecl top_level_decl; |
| 195 | Buf name; | 195 | Buf name; |
| 196 | ZigList<AstNode *> generic_params; | ||
| 196 | ZigList<AstNode *> params; | 197 | ZigList<AstNode *> params; |
| 197 | AstNode *return_type; | 198 | AstNode *return_type; |
| 199 | bool generic_params_is_var_args; | ||
| 198 | bool is_var_args; | 200 | bool is_var_args; |
| 199 | bool is_extern; | 201 | bool is_extern; |
| 200 | bool is_inline; | 202 | bool is_inline; |
| ... | @@ -206,6 +208,7 @@ struct AstNodeFnProto { | ... | @@ -206,6 +208,7 @@ struct AstNodeFnProto { |
| 206 | FnTableEntry *fn_table_entry; | 208 | FnTableEntry *fn_table_entry; |
| 207 | bool skip; | 209 | bool skip; |
| 208 | Expr resolved_expr; | 210 | Expr resolved_expr; |
| 211 | TypeTableEntry *generic_fn_type; | ||
| 209 | }; | 212 | }; |
| 210 | 213 | ||
| 211 | struct AstNodeFnDef { | 214 | struct AstNodeFnDef { |
| ... | @@ -797,6 +800,21 @@ struct FnTypeParamInfo { | ... | @@ -797,6 +800,21 @@ struct FnTypeParamInfo { |
| 797 | TypeTableEntry *type; | 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 | static const int fn_type_id_prealloc_param_info_count = 4; | 818 | static const int fn_type_id_prealloc_param_info_count = 4; |
| 801 | struct FnTypeId { | 819 | struct FnTypeId { |
| 802 | TypeTableEntry *return_type; | 820 | TypeTableEntry *return_type; |
| ... | @@ -812,7 +830,6 @@ struct FnTypeId { | ... | @@ -812,7 +830,6 @@ struct FnTypeId { |
| 812 | uint32_t fn_type_id_hash(FnTypeId*); | 830 | uint32_t fn_type_id_hash(FnTypeId*); |
| 813 | bool fn_type_id_eql(FnTypeId *a, FnTypeId *b); | 831 | bool fn_type_id_eql(FnTypeId *a, FnTypeId *b); |
| 814 | 832 | ||
| 815 | |||
| 816 | struct TypeTableEntryPointer { | 833 | struct TypeTableEntryPointer { |
| 817 | TypeTableEntry *child_type; | 834 | TypeTableEntry *child_type; |
| 818 | bool is_const; | 835 | bool is_const; |
| ... | @@ -899,6 +916,10 @@ struct TypeTableEntryFn { | ... | @@ -899,6 +916,10 @@ struct TypeTableEntryFn { |
| 899 | LLVMCallConv calling_convention; | 916 | LLVMCallConv calling_convention; |
| 900 | }; | 917 | }; |
| 901 | 918 | ||
| 919 | struct TypeTableEntryGenericFn { | ||
| 920 | AstNode *decl_node; | ||
| 921 | }; | ||
| 922 | |||
| 902 | struct TypeTableEntryTypeDecl { | 923 | struct TypeTableEntryTypeDecl { |
| 903 | TypeTableEntry *child_type; | 924 | TypeTableEntry *child_type; |
| 904 | TypeTableEntry *canonical_type; | 925 | TypeTableEntry *canonical_type; |
| ... | @@ -925,6 +946,7 @@ enum TypeTableEntryId { | ... | @@ -925,6 +946,7 @@ enum TypeTableEntryId { |
| 925 | TypeTableEntryIdFn, | 946 | TypeTableEntryIdFn, |
| 926 | TypeTableEntryIdTypeDecl, | 947 | TypeTableEntryIdTypeDecl, |
| 927 | TypeTableEntryIdNamespace, | 948 | TypeTableEntryIdNamespace, |
| 949 | TypeTableEntryIdGenericFn, | ||
| 928 | }; | 950 | }; |
| 929 | 951 | ||
| 930 | struct TypeTableEntry { | 952 | struct TypeTableEntry { |
| ... | @@ -947,6 +969,7 @@ struct TypeTableEntry { | ... | @@ -947,6 +969,7 @@ struct TypeTableEntry { |
| 947 | TypeTableEntryEnum enumeration; | 969 | TypeTableEntryEnum enumeration; |
| 948 | TypeTableEntryFn fn; | 970 | TypeTableEntryFn fn; |
| 949 | TypeTableEntryTypeDecl type_decl; | 971 | TypeTableEntryTypeDecl type_decl; |
| 972 | TypeTableEntryGenericFn generic_fn; | ||
| 950 | } data; | 973 | } data; |
| 951 | 974 | ||
| 952 | // use these fields to make sure we don't duplicate type table entries for the same type | 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,6 +1015,7 @@ struct FnTableEntry { |
| 992 | bool internal_linkage; | 1015 | bool internal_linkage; |
| 993 | bool is_extern; | 1016 | bool is_extern; |
| 994 | bool is_test; | 1017 | bool is_test; |
| 1018 | BlockContext *parent_block_context; | ||
| 995 | 1019 | ||
| 996 | ZigList<AstNode *> cast_alloca_list; | 1020 | ZigList<AstNode *> cast_alloca_list; |
| 997 | ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list; | 1021 | ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list; |
| ... | @@ -1047,6 +1071,7 @@ struct CodeGen { | ... | @@ -1047,6 +1071,7 @@ struct CodeGen { |
| 1047 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table; | 1071 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table; |
| 1048 | HashMap<FnTypeId *, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table; | 1072 | HashMap<FnTypeId *, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table; |
| 1049 | HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table; | 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 | ZigList<ImportTableEntry *> import_queue; | 1076 | ZigList<ImportTableEntry *> import_queue; |
| 1052 | int import_queue_index; | 1077 | int import_queue_index; |
| ... | @@ -1172,7 +1197,10 @@ struct VariableTableEntry { | ... | @@ -1172,7 +1197,10 @@ struct VariableTableEntry { |
| 1172 | LLVMValueRef value_ref; | 1197 | LLVMValueRef value_ref; |
| 1173 | bool is_const; | 1198 | bool is_const; |
| 1174 | bool is_ptr; // if true, value_ref is a pointer | 1199 | bool is_ptr; // if true, value_ref is a pointer |
| 1200 | // which node is the declaration of the variable | ||
| 1175 | AstNode *decl_node; | 1201 | AstNode *decl_node; |
| 1202 | // which node contains the ConstExprValue for this variable's value | ||
| 1203 | AstNode *val_node; | ||
| 1176 | LLVMZigDILocalVariable *di_loc_var; | 1204 | LLVMZigDILocalVariable *di_loc_var; |
| 1177 | int src_arg_index; | 1205 | int src_arg_index; |
| 1178 | int gen_arg_index; | 1206 | int gen_arg_index; |
src/analyze.cpp+250-31| ... | @@ -41,6 +41,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa | ... | @@ -41,6 +41,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa |
| 41 | AstNodeVariableDeclaration *variable_declaration, | 41 | AstNodeVariableDeclaration *variable_declaration, |
| 42 | bool expr_is_maybe, AstNode *decl_node); | 42 | bool expr_is_maybe, AstNode *decl_node); |
| 43 | static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node); | 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 | static AstNode *first_executing_node(AstNode *node) { | 46 | static AstNode *first_executing_node(AstNode *node) { |
| 46 | switch (node->type) { | 47 | switch (node->type) { |
| ... | @@ -192,6 +193,7 @@ static bool type_is_complete(TypeTableEntry *type_entry) { | ... | @@ -192,6 +193,7 @@ static bool type_is_complete(TypeTableEntry *type_entry) { |
| 192 | case TypeTableEntryIdFn: | 193 | case TypeTableEntryIdFn: |
| 193 | case TypeTableEntryIdTypeDecl: | 194 | case TypeTableEntryIdTypeDecl: |
| 194 | case TypeTableEntryIdNamespace: | 195 | case TypeTableEntryIdNamespace: |
| 196 | case TypeTableEntryIdGenericFn: | ||
| 195 | return true; | 197 | return true; |
| 196 | } | 198 | } |
| 197 | zig_unreachable(); | 199 | zig_unreachable(); |
| ... | @@ -201,6 +203,14 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { | ... | @@ -201,6 +203,14 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { |
| 201 | return get_int_type(g, false, bits_needed_for_unsigned(x)); | 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 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { | 214 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) { |
| 205 | assert(child_type->id != TypeTableEntryIdInvalid); | 215 | assert(child_type->id != TypeTableEntryIdInvalid); |
| 206 | TypeTableEntry **parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)]; | 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,7 +786,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor |
| 776 | } | 786 | } |
| 777 | 787 | ||
| 778 | fn_type_id.is_var_args = fn_proto->is_var_args; | 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 | if (fn_type_id.return_type->id == TypeTableEntryIdInvalid) { | 791 | if (fn_type_id.return_type->id == TypeTableEntryIdInvalid) { |
| 782 | fn_proto->skip = true; | 792 | fn_proto->skip = true; |
| ... | @@ -785,7 +795,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor | ... | @@ -785,7 +795,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor |
| 785 | for (int i = 0; i < fn_type_id.param_count; i += 1) { | 795 | for (int i = 0; i < fn_type_id.param_count; i += 1) { |
| 786 | AstNode *child = node->data.fn_proto.params.at(i); | 796 | AstNode *child = node->data.fn_proto.params.at(i); |
| 787 | assert(child->type == NodeTypeParamDecl); | 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 | child->data.param_decl.type); | 799 | child->data.param_decl.type); |
| 790 | switch (type_entry->id) { | 800 | switch (type_entry->id) { |
| 791 | case TypeTableEntryIdInvalid: | 801 | case TypeTableEntryIdInvalid: |
| ... | @@ -797,6 +807,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor | ... | @@ -797,6 +807,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor |
| 797 | case TypeTableEntryIdMetaType: | 807 | case TypeTableEntryIdMetaType: |
| 798 | case TypeTableEntryIdUnreachable: | 808 | case TypeTableEntryIdUnreachable: |
| 799 | case TypeTableEntryIdNamespace: | 809 | case TypeTableEntryIdNamespace: |
| 810 | case TypeTableEntryIdGenericFn: | ||
| 800 | fn_proto->skip = true; | 811 | fn_proto->skip = true; |
| 801 | add_node_error(g, child->data.param_decl.type, | 812 | add_node_error(g, child->data.param_decl.type, |
| 802 | buf_sprintf("parameter of type '%s' not allowed'", buf_ptr(&type_entry->name))); | 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,7 +891,7 @@ static bool resolve_const_expr_bool(CodeGen *g, ImportTableEntry *import, BlockC |
| 880 | } | 891 | } |
| 881 | 892 | ||
| 882 | static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry, | 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 | assert(node->type == NodeTypeFnProto); | 896 | assert(node->type == NodeTypeFnProto); |
| 886 | AstNodeFnProto *fn_proto = &node->data.fn_proto; | 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,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 | is_naked, is_cold); | 961 | is_naked, is_cold); |
| 951 | 962 | ||
| 952 | fn_table_entry->type_entry = fn_type; | 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,6 +974,8 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 963 | } else { | 974 | } else { |
| 964 | symbol_name = buf_sprintf("_%s", buf_ptr(&fn_table_entry->symbol_name)); | 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 | fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), | 979 | fn_table_entry->fn_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), |
| 967 | fn_type->data.fn.raw_type_ref); | 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,12 +1005,12 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t |
| 992 | unsigned flags = 0; | 1005 | unsigned flags = 0; |
| 993 | bool is_optimized = g->is_release_build; | 1006 | bool is_optimized = g->is_release_build; |
| 994 | LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, | 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 | import->di_file, line_number, | 1009 | import->di_file, line_number, |
| 997 | fn_type->di_type, fn_table_entry->internal_linkage, | 1010 | fn_type->di_type, fn_table_entry->internal_linkage, |
| 998 | is_definition, scope_line, flags, is_optimized, nullptr); | 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 | fn_table_entry->fn_def_node->data.fn_def.block_context = context; | 1014 | fn_table_entry->fn_def_node->data.fn_def.block_context = context; |
| 1002 | context->di_scope = LLVMZigSubprogramToScope(subprogram); | 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,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 | if (proto_node->data.fn_proto.skip) { | 1353 | if (proto_node->data.fn_proto.skip) { |
| 1326 | return; | 1354 | return; |
| 1327 | } | 1355 | } |
| 1328 | 1356 | ||
| 1357 | bool is_generic_instance = (proto_node->data.fn_proto.generic_params.length > 0); | ||
| 1358 | |||
| 1329 | AstNode *parent_decl = proto_node->data.fn_proto.top_level_decl.parent_decl; | 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 | AstNode *fn_def_node = proto_node->data.fn_proto.fn_def_node; | 1362 | AstNode *fn_def_node = proto_node->data.fn_proto.fn_def_node; |
| 1332 | bool is_extern = proto_node->data.fn_proto.is_extern; | 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 | if (!is_extern && proto_node->data.fn_proto.is_var_args) { | 1367 | if (!is_extern && proto_node->data.fn_proto.is_var_args) { |
| 1337 | add_node_error(g, proto_node, | 1368 | add_node_error(g, proto_node, |
| ... | @@ -1352,13 +1383,24 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *prot | ... | @@ -1352,13 +1383,24 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *prot |
| 1352 | g->fn_defs.append(fn_table_entry); | 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 | if (is_main_fn) { | 1389 | if (is_main_fn) { |
| 1357 | g->main_fn = fn_table_entry; | 1390 | g->main_fn = fn_table_entry; |
| 1358 | } | 1391 | } |
| 1359 | 1392 | ||
| 1360 | proto_node->data.fn_proto.fn_table_entry = fn_table_entry; | 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 | static void preview_error_value_decl(CodeGen *g, AstNode *node) { | 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,6 +1581,7 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) { |
| 1539 | case TypeTableEntryIdNumLitInt: | 1581 | case TypeTableEntryIdNumLitInt: |
| 1540 | case TypeTableEntryIdUndefLit: | 1582 | case TypeTableEntryIdUndefLit: |
| 1541 | case TypeTableEntryIdNamespace: | 1583 | case TypeTableEntryIdNamespace: |
| 1584 | case TypeTableEntryIdGenericFn: | ||
| 1542 | return false; | 1585 | return false; |
| 1543 | 1586 | ||
| 1544 | case TypeTableEntryIdBool: | 1587 | case TypeTableEntryIdBool: |
| ... | @@ -2433,6 +2476,15 @@ static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, F | ... | @@ -2433,6 +2476,15 @@ static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, F |
| 2433 | return fn->type_entry; | 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 | static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node, ErrorTableEntry *err) { | 2488 | static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node, ErrorTableEntry *err) { |
| 2437 | Expr *expr = get_resolved_expr(node); | 2489 | Expr *expr = get_resolved_expr(node); |
| 2438 | expr->const_val.ok = true; | 2490 | expr->const_val.ok = true; |
| ... | @@ -2570,14 +2622,10 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry * | ... | @@ -2570,14 +2622,10 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry * |
| 2570 | 2622 | ||
| 2571 | static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var) { | 2623 | static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var) { |
| 2572 | get_resolved_expr(source_node)->variable = var; | 2624 | get_resolved_expr(source_node)->variable = var; |
| 2573 | if (var->is_const) { | 2625 | if (var->is_const && var->val_node) { |
| 2574 | AstNode *decl_node = var->decl_node; | 2626 | ConstExprValue *other_const_val = &get_resolved_expr(var->val_node)->const_val; |
| 2575 | if (decl_node->type == NodeTypeVariableDeclaration) { | 2627 | if (other_const_val->ok) { |
| 2576 | AstNode *expr_node = decl_node->data.variable_declaration.expr; | 2628 | return resolve_expr_const_val_as_other_expr(g, source_node, var->val_node); |
| 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 | } | ||
| 2581 | } | 2629 | } |
| 2582 | } | 2630 | } |
| 2583 | return var->type; | 2631 | return var->type; |
| ... | @@ -2596,9 +2644,15 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod | ... | @@ -2596,9 +2644,15 @@ static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNod |
| 2596 | VariableTableEntry *var = decl_node->data.variable_declaration.variable; | 2644 | VariableTableEntry *var = decl_node->data.variable_declaration.variable; |
| 2597 | return analyze_var_ref(g, source_node, var); | 2645 | return analyze_var_ref(g, source_node, var); |
| 2598 | } else if (decl_node->type == NodeTypeFnProto) { | 2646 | } else if (decl_node->type == NodeTypeFnProto) { |
| 2599 | FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry; | 2647 | if (decl_node->data.fn_proto.generic_params.length > 0) { |
| 2600 | assert(fn_entry->type_entry); | 2648 | TypeTableEntry *type_entry = decl_node->data.fn_proto.generic_fn_type; |
| 2601 | return resolve_expr_const_val_as_fn(g, source_node, fn_entry); | 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 | } else if (decl_node->type == NodeTypeStructDecl) { | 2656 | } else if (decl_node->type == NodeTypeStructDecl) { |
| 2603 | return resolve_expr_const_val_as_type(g, source_node, decl_node->data.struct_decl.type_entry); | 2657 | return resolve_expr_const_val_as_type(g, source_node, decl_node->data.struct_decl.type_entry); |
| 2604 | } else if (decl_node->type == NodeTypeTypeDecl) { | 2658 | } else if (decl_node->type == NodeTypeTypeDecl) { |
| ... | @@ -3113,7 +3167,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, | ... | @@ -3113,7 +3167,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 3113 | 3167 | ||
| 3114 | // Set name to nullptr to make the variable anonymous (not visible to programmer). | 3168 | // Set name to nullptr to make the variable anonymous (not visible to programmer). |
| 3115 | static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, ImportTableEntry *import, | 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 | VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); | 3172 | VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); |
| 3119 | variable_entry->type = type_entry; | 3173 | variable_entry->type = type_entry; |
| ... | @@ -3160,6 +3214,8 @@ static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, Impor | ... | @@ -3160,6 +3214,8 @@ static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, Impor |
| 3160 | variable_entry->is_const = is_const; | 3214 | variable_entry->is_const = is_const; |
| 3161 | variable_entry->is_ptr = true; | 3215 | variable_entry->is_ptr = true; |
| 3162 | variable_entry->decl_node = source_node; | 3216 | variable_entry->decl_node = source_node; |
| 3217 | variable_entry->val_node = val_node; | ||
| 3218 | |||
| 3163 | 3219 | ||
| 3164 | return variable_entry; | 3220 | return variable_entry; |
| 3165 | } | 3221 | } |
| ... | @@ -3182,7 +3238,7 @@ static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *i | ... | @@ -3182,7 +3238,7 @@ static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *i |
| 3182 | var_node->block_context = child_context; | 3238 | var_node->block_context = child_context; |
| 3183 | Buf *var_name = &var_node->data.symbol_expr.symbol; | 3239 | Buf *var_name = &var_node->data.symbol_expr.symbol; |
| 3184 | node->data.unwrap_err_expr.var = add_local_var(g, var_node, import, child_context, var_name, | 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 | } else { | 3242 | } else { |
| 3187 | child_context = parent_context; | 3243 | child_context = parent_context; |
| 3188 | } | 3244 | } |
| ... | @@ -3260,7 +3316,8 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa | ... | @@ -3260,7 +3316,8 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa |
| 3260 | assert(type != nullptr); // should have been caught by the parser | 3316 | assert(type != nullptr); // should have been caught by the parser |
| 3261 | 3317 | ||
| 3262 | VariableTableEntry *var = add_local_var(g, source_node, import, context, | 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 | variable_declaration->variable = var; | 3322 | variable_declaration->variable = var; |
| 3266 | 3323 | ||
| ... | @@ -3453,17 +3510,17 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl | ... | @@ -3453,17 +3510,17 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl |
| 3453 | elem_var_node->block_context = child_context; | 3510 | elem_var_node->block_context = child_context; |
| 3454 | Buf *elem_var_name = &elem_var_node->data.symbol_expr.symbol; | 3511 | Buf *elem_var_name = &elem_var_node->data.symbol_expr.symbol; |
| 3455 | node->data.for_expr.elem_var = add_local_var(g, elem_var_node, import, child_context, elem_var_name, | 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 | AstNode *index_var_node = node->data.for_expr.index_node; | 3515 | AstNode *index_var_node = node->data.for_expr.index_node; |
| 3459 | if (index_var_node) { | 3516 | if (index_var_node) { |
| 3460 | Buf *index_var_name = &index_var_node->data.symbol_expr.symbol; | 3517 | Buf *index_var_name = &index_var_node->data.symbol_expr.symbol; |
| 3461 | index_var_node->block_context = child_context; | 3518 | index_var_node->block_context = child_context; |
| 3462 | node->data.for_expr.index_var = add_local_var(g, index_var_node, import, child_context, index_var_name, | 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 | } else { | 3521 | } else { |
| 3465 | node->data.for_expr.index_var = add_local_var(g, node, import, child_context, nullptr, | 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 | AstNode *for_body_node = node->data.for_expr.body; | 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,6 +4387,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 4330 | case TypeTableEntryIdNumLitInt: | 4387 | case TypeTableEntryIdNumLitInt: |
| 4331 | case TypeTableEntryIdUndefLit: | 4388 | case TypeTableEntryIdUndefLit: |
| 4332 | case TypeTableEntryIdNamespace: | 4389 | case TypeTableEntryIdNamespace: |
| 4390 | case TypeTableEntryIdGenericFn: | ||
| 4333 | add_node_error(g, expr_node, | 4391 | add_node_error(g, expr_node, |
| 4334 | buf_sprintf("type '%s' not eligible for @typeof", buf_ptr(&type_entry->name))); | 4392 | buf_sprintf("type '%s' not eligible for @typeof", buf_ptr(&type_entry->name))); |
| 4335 | return g->builtin_types.entry_invalid; | 4393 | return g->builtin_types.entry_invalid; |
| ... | @@ -4541,6 +4599,92 @@ static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, | ... | @@ -4541,6 +4599,92 @@ static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, |
| 4541 | return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_type); | 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 | static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 4688 | static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 4545 | TypeTableEntry *expected_type, AstNode *node) | 4689 | TypeTableEntry *expected_type, AstNode *node) |
| 4546 | { | 4690 | { |
| ... | @@ -4627,6 +4771,8 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import | ... | @@ -4627,6 +4771,8 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import |
| 4627 | 4771 | ||
| 4628 | return analyze_fn_call_raw(g, import, context, expected_type, node, | 4772 | return analyze_fn_call_raw(g, import, context, expected_type, node, |
| 4629 | const_val->data.x_fn, bare_struct_type); | 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 | } else { | 4776 | } else { |
| 4631 | add_node_error(g, fn_ref_expr, | 4777 | add_node_error(g, fn_ref_expr, |
| 4632 | buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name))); | 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,7 +5117,7 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import, |
| 4971 | Buf *var_name = &var_node->data.symbol_expr.symbol; | 5117 | Buf *var_name = &var_node->data.symbol_expr.symbol; |
| 4972 | var_node->block_context = child_context; | 5118 | var_node->block_context = child_context; |
| 4973 | prong_node->data.switch_prong.var = add_local_var(g, var_node, import, | 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 | prong_node->data.switch_prong.var_is_target_expr = var_is_target_expr; | 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,7 +5537,7 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { |
| 5391 | } | 5537 | } |
| 5392 | 5538 | ||
| 5393 | VariableTableEntry *var = add_local_var(g, param_decl_node, import, context, &param_decl->name, | 5539 | VariableTableEntry *var = add_local_var(g, param_decl_node, import, context, &param_decl->name, |
| 5394 | type, true); | 5540 | type, true, nullptr); |
| 5395 | var->src_arg_index = i; | 5541 | var->src_arg_index = i; |
| 5396 | param_decl_node->data.param_decl.variable = var; | 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,7 +5559,9 @@ static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContex |
| 5413 | tld->import = import; | 5559 | tld->import = import; |
| 5414 | tld->name = name; | 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 | g->export_queue.append(node); | 5565 | g->export_queue.append(node); |
| 5418 | } | 5566 | } |
| 5419 | 5567 | ||
| ... | @@ -5909,6 +6057,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { | ... | @@ -5909,6 +6057,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 5909 | case TypeTableEntryIdNumLitInt: | 6057 | case TypeTableEntryIdNumLitInt: |
| 5910 | case TypeTableEntryIdUndefLit: | 6058 | case TypeTableEntryIdUndefLit: |
| 5911 | case TypeTableEntryIdNamespace: | 6059 | case TypeTableEntryIdNamespace: |
| 6060 | case TypeTableEntryIdGenericFn: | ||
| 5912 | zig_unreachable(); | 6061 | zig_unreachable(); |
| 5913 | case TypeTableEntryIdUnreachable: | 6062 | case TypeTableEntryIdUnreachable: |
| 5914 | case TypeTableEntryIdVoid: | 6063 | case TypeTableEntryIdVoid: |
| ... | @@ -5965,7 +6114,6 @@ uint32_t fn_type_id_hash(FnTypeId *id) { | ... | @@ -5965,7 +6114,6 @@ uint32_t fn_type_id_hash(FnTypeId *id) { |
| 5965 | result += id->is_cold ? 3605523458 : 0; | 6114 | result += id->is_cold ? 3605523458 : 0; |
| 5966 | result += id->is_var_args ? 1931444534 : 0; | 6115 | result += id->is_var_args ? 1931444534 : 0; |
| 5967 | result += hash_ptr(id->return_type); | 6116 | result += hash_ptr(id->return_type); |
| 5968 | result += id->param_count; | ||
| 5969 | for (int i = 0; i < id->param_count; i += 1) { | 6117 | for (int i = 0; i < id->param_count; i += 1) { |
| 5970 | FnTypeParamInfo *info = &id->param_info[i]; | 6118 | FnTypeParamInfo *info = &id->param_info[i]; |
| 5971 | result += info->is_noalias ? 892356923 : 0; | 6119 | result += info->is_noalias ? 892356923 : 0; |
| ... | @@ -5999,6 +6147,76 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { | ... | @@ -5999,6 +6147,76 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { |
| 5999 | return true; | 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 | bool type_has_bits(TypeTableEntry *type_entry) { | 6220 | bool type_has_bits(TypeTableEntry *type_entry) { |
| 6003 | assert(type_entry); | 6221 | assert(type_entry); |
| 6004 | assert(type_entry->id != TypeTableEntryIdInvalid); | 6222 | assert(type_entry->id != TypeTableEntryIdInvalid); |
| ... | @@ -6027,6 +6245,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry) | ... | @@ -6027,6 +6245,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry) |
| 6027 | case TypeTableEntryIdMetaType: | 6245 | case TypeTableEntryIdMetaType: |
| 6028 | case TypeTableEntryIdVoid: | 6246 | case TypeTableEntryIdVoid: |
| 6029 | case TypeTableEntryIdNamespace: | 6247 | case TypeTableEntryIdNamespace: |
| 6248 | case TypeTableEntryIdGenericFn: | ||
| 6030 | zig_unreachable(); | 6249 | zig_unreachable(); |
| 6031 | case TypeTableEntryIdArray: | 6250 | case TypeTableEntryIdArray: |
| 6032 | return type_of_first_thing_in_memory(type_entry->data.array.child_type); | 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,15 +59,6 @@ static const char *prefix_op_str(PrefixOp prefix_op) { |
| 59 | zig_unreachable(); | 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 | static const char *visib_mod_string(VisibMod mod) { | 62 | static const char *visib_mod_string(VisibMod mod) { |
| 72 | switch (mod) { | 63 | switch (mod) { |
| 73 | case VisibModPub: return "pub "; | 64 | case VisibModPub: return "pub "; |
| ... | @@ -195,316 +186,36 @@ static const char *node_type_str(NodeType node_type) { | ... | @@ -195,316 +186,36 @@ static const char *node_type_str(NodeType node_type) { |
| 195 | zig_unreachable(); | 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) { | 194 | static void ast_print_visit(AstNode **node_ptr, void *context) { |
| 200 | for (int i = 0; i < indent; i += 1) { | 195 | AstNode *node = *node_ptr; |
| 201 | fprintf(f, " "); | 196 | AstPrint *ap = (AstPrint *)context; |
| 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)); | ||
| 225 | 197 | ||
| 226 | for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { | 198 | for (int i = 0; i < ap->indent; i += 1) { |
| 227 | AstNode *child = node->data.fn_proto.params.at(i); | 199 | fprintf(ap->f, " "); |
| 228 | ast_print(f, child, indent + 2); | 200 | } |
| 229 | } | ||
| 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; | 204 | AstPrint new_ap; |
| 234 | } | 205 | new_ap.indent = ap->indent + 2; |
| 235 | case NodeTypeBlock: | 206 | new_ap.f = ap->f; |
| 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)); | ||
| 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; | 211 | void ast_print(FILE *f, AstNode *node, int indent) { |
| 252 | } | 212 | AstPrint ap; |
| 253 | case NodeTypeReturnExpr: | 213 | ap.indent = indent; |
| 254 | { | 214 | ap.f = f; |
| 255 | const char *prefix_str = return_prefix_str(node->data.return_expr.kind); | 215 | ast_visit_node_children(node, ast_print_visit, &ap); |
| 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 | } | ||
| 506 | } | 216 | } |
| 507 | 217 | ||
| 218 | |||
| 508 | struct AstRender { | 219 | struct AstRender { |
| 509 | int indent; | 220 | int indent; |
| 510 | int indent_size; | 221 | int indent_size; |
src/ast_render.hpp+1| ... | @@ -9,6 +9,7 @@ | ... | @@ -9,6 +9,7 @@ |
| 9 | #define ZIG_AST_RENDER_HPP | 9 | #define ZIG_AST_RENDER_HPP |
| 10 | 10 | ||
| 11 | #include "all_types.hpp" | 11 | #include "all_types.hpp" |
| 12 | #include "parser.hpp" | ||
| 12 | 13 | ||
| 13 | #include <stdio.h> | 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,6 +62,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { |
| 62 | g->primitive_type_table.init(32); | 62 | g->primitive_type_table.init(32); |
| 63 | g->fn_type_table.init(32); | 63 | g->fn_type_table.init(32); |
| 64 | g->error_table.init(16); | 64 | g->error_table.init(16); |
| 65 | g->generic_table.init(16); | ||
| 65 | g->is_release_build = false; | 66 | g->is_release_build = false; |
| 66 | g->is_test_build = false; | 67 | g->is_test_build = false; |
| 67 | g->error_value_count = 1; | 68 | g->error_value_count = 1; |
| ... | @@ -2927,6 +2928,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE | ... | @@ -2927,6 +2928,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE |
| 2927 | case TypeTableEntryIdUndefLit: | 2928 | case TypeTableEntryIdUndefLit: |
| 2928 | case TypeTableEntryIdVoid: | 2929 | case TypeTableEntryIdVoid: |
| 2929 | case TypeTableEntryIdNamespace: | 2930 | case TypeTableEntryIdNamespace: |
| 2931 | case TypeTableEntryIdGenericFn: | ||
| 2930 | zig_unreachable(); | 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,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 | static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory, | 2248 | static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory, |
| 2249 | ZigList<AstNode*> *directives, VisibMod visib_mod) | 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,6 +2273,17 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand |
| 2273 | 2273 | ||
| 2274 | ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args); | 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 | Token *next_token = &pc->tokens->at(*token_index); | 2287 | Token *next_token = &pc->tokens->at(*token_index); |
| 2277 | if (next_token->id == TokenIdArrow) { | 2288 | if (next_token->id == TokenIdArrow) { |
| 2278 | *token_index += 1; | 2289 | *token_index += 1; |
| ... | @@ -2626,72 +2637,73 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, | ... | @@ -2626,72 +2637,73 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, |
| 2626 | return pc.root; | 2637 | return pc.root; |
| 2627 | } | 2638 | } |
| 2628 | 2639 | ||
| 2629 | static void set_field(AstNode **field) { | 2640 | static void visit_field(AstNode **node, void (*visit)(AstNode **, void *context), void *context) { |
| 2630 | if (*field) { | 2641 | if (*node) { |
| 2631 | (*field)->parent_field = field; | 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 | if (list) { | 2647 | if (list) { |
| 2637 | for (int i = 0; i < list->length; i += 1) { | 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 | switch (node->type) { | 2655 | switch (node->type) { |
| 2645 | case NodeTypeRoot: | 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 | break; | 2658 | break; |
| 2648 | case NodeTypeFnProto: | 2659 | case NodeTypeFnProto: |
| 2649 | set_field(&node->data.fn_proto.return_type); | 2660 | visit_field(&node->data.fn_proto.return_type, visit, context); |
| 2650 | set_list_fields(node->data.fn_proto.top_level_decl.directives); | 2661 | visit_node_list(node->data.fn_proto.top_level_decl.directives, visit, context); |
| 2651 | set_list_fields(&node->data.fn_proto.params); | 2662 | visit_node_list(&node->data.fn_proto.generic_params, visit, context); |
| 2663 | visit_node_list(&node->data.fn_proto.params, visit, context); | ||
| 2652 | break; | 2664 | break; |
| 2653 | case NodeTypeFnDef: | 2665 | case NodeTypeFnDef: |
| 2654 | set_field(&node->data.fn_def.fn_proto); | 2666 | visit_field(&node->data.fn_def.fn_proto, visit, context); |
| 2655 | set_field(&node->data.fn_def.body); | 2667 | visit_field(&node->data.fn_def.body, visit, context); |
| 2656 | break; | 2668 | break; |
| 2657 | case NodeTypeFnDecl: | 2669 | case NodeTypeFnDecl: |
| 2658 | set_field(&node->data.fn_decl.fn_proto); | 2670 | visit_field(&node->data.fn_decl.fn_proto, visit, context); |
| 2659 | break; | 2671 | break; |
| 2660 | case NodeTypeParamDecl: | 2672 | case NodeTypeParamDecl: |
| 2661 | set_field(&node->data.param_decl.type); | 2673 | visit_field(&node->data.param_decl.type, visit, context); |
| 2662 | break; | 2674 | break; |
| 2663 | case NodeTypeBlock: | 2675 | case NodeTypeBlock: |
| 2664 | set_list_fields(&node->data.block.statements); | 2676 | visit_node_list(&node->data.block.statements, visit, context); |
| 2665 | break; | 2677 | break; |
| 2666 | case NodeTypeDirective: | 2678 | case NodeTypeDirective: |
| 2667 | set_field(&node->data.directive.expr); | 2679 | visit_field(&node->data.directive.expr, visit, context); |
| 2668 | break; | 2680 | break; |
| 2669 | case NodeTypeReturnExpr: | 2681 | case NodeTypeReturnExpr: |
| 2670 | set_field(&node->data.return_expr.expr); | 2682 | visit_field(&node->data.return_expr.expr, visit, context); |
| 2671 | break; | 2683 | break; |
| 2672 | case NodeTypeDefer: | 2684 | case NodeTypeDefer: |
| 2673 | set_field(&node->data.defer.expr); | 2685 | visit_field(&node->data.defer.expr, visit, context); |
| 2674 | break; | 2686 | break; |
| 2675 | case NodeTypeVariableDeclaration: | 2687 | case NodeTypeVariableDeclaration: |
| 2676 | set_list_fields(node->data.variable_declaration.top_level_decl.directives); | 2688 | visit_node_list(node->data.variable_declaration.top_level_decl.directives, visit, context); |
| 2677 | set_field(&node->data.variable_declaration.type); | 2689 | visit_field(&node->data.variable_declaration.type, visit, context); |
| 2678 | set_field(&node->data.variable_declaration.expr); | 2690 | visit_field(&node->data.variable_declaration.expr, visit, context); |
| 2679 | break; | 2691 | break; |
| 2680 | case NodeTypeTypeDecl: | 2692 | case NodeTypeTypeDecl: |
| 2681 | set_list_fields(node->data.type_decl.top_level_decl.directives); | 2693 | visit_node_list(node->data.type_decl.top_level_decl.directives, visit, context); |
| 2682 | set_field(&node->data.type_decl.child_type); | 2694 | visit_field(&node->data.type_decl.child_type, visit, context); |
| 2683 | break; | 2695 | break; |
| 2684 | case NodeTypeErrorValueDecl: | 2696 | case NodeTypeErrorValueDecl: |
| 2685 | // none | 2697 | // none |
| 2686 | break; | 2698 | break; |
| 2687 | case NodeTypeBinOpExpr: | 2699 | case NodeTypeBinOpExpr: |
| 2688 | set_field(&node->data.bin_op_expr.op1); | 2700 | visit_field(&node->data.bin_op_expr.op1, visit, context); |
| 2689 | set_field(&node->data.bin_op_expr.op2); | 2701 | visit_field(&node->data.bin_op_expr.op2, visit, context); |
| 2690 | break; | 2702 | break; |
| 2691 | case NodeTypeUnwrapErrorExpr: | 2703 | case NodeTypeUnwrapErrorExpr: |
| 2692 | set_field(&node->data.unwrap_err_expr.op1); | 2704 | visit_field(&node->data.unwrap_err_expr.op1, visit, context); |
| 2693 | set_field(&node->data.unwrap_err_expr.symbol); | 2705 | visit_field(&node->data.unwrap_err_expr.symbol, visit, context); |
| 2694 | set_field(&node->data.unwrap_err_expr.op2); | 2706 | visit_field(&node->data.unwrap_err_expr.op2, visit, context); |
| 2695 | break; | 2707 | break; |
| 2696 | case NodeTypeNumberLiteral: | 2708 | case NodeTypeNumberLiteral: |
| 2697 | // none | 2709 | // none |
| ... | @@ -2706,27 +2718,27 @@ void normalize_parent_ptrs(AstNode *node) { | ... | @@ -2706,27 +2718,27 @@ void normalize_parent_ptrs(AstNode *node) { |
| 2706 | // none | 2718 | // none |
| 2707 | break; | 2719 | break; |
| 2708 | case NodeTypePrefixOpExpr: | 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 | break; | 2722 | break; |
| 2711 | case NodeTypeFnCallExpr: | 2723 | case NodeTypeFnCallExpr: |
| 2712 | set_field(&node->data.fn_call_expr.fn_ref_expr); | 2724 | visit_field(&node->data.fn_call_expr.fn_ref_expr, visit, context); |
| 2713 | set_list_fields(&node->data.fn_call_expr.params); | 2725 | visit_node_list(&node->data.fn_call_expr.params, visit, context); |
| 2714 | break; | 2726 | break; |
| 2715 | case NodeTypeArrayAccessExpr: | 2727 | case NodeTypeArrayAccessExpr: |
| 2716 | set_field(&node->data.array_access_expr.array_ref_expr); | 2728 | visit_field(&node->data.array_access_expr.array_ref_expr, visit, context); |
| 2717 | set_field(&node->data.array_access_expr.subscript); | 2729 | visit_field(&node->data.array_access_expr.subscript, visit, context); |
| 2718 | break; | 2730 | break; |
| 2719 | case NodeTypeSliceExpr: | 2731 | case NodeTypeSliceExpr: |
| 2720 | set_field(&node->data.slice_expr.array_ref_expr); | 2732 | visit_field(&node->data.slice_expr.array_ref_expr, visit, context); |
| 2721 | set_field(&node->data.slice_expr.start); | 2733 | visit_field(&node->data.slice_expr.start, visit, context); |
| 2722 | set_field(&node->data.slice_expr.end); | 2734 | visit_field(&node->data.slice_expr.end, visit, context); |
| 2723 | break; | 2735 | break; |
| 2724 | case NodeTypeFieldAccessExpr: | 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 | break; | 2738 | break; |
| 2727 | case NodeTypeUse: | 2739 | case NodeTypeUse: |
| 2728 | set_field(&node->data.use.expr); | 2740 | visit_field(&node->data.use.expr, visit, context); |
| 2729 | set_list_fields(node->data.use.top_level_decl.directives); | 2741 | visit_node_list(node->data.use.top_level_decl.directives, visit, context); |
| 2730 | break; | 2742 | break; |
| 2731 | case NodeTypeBoolLiteral: | 2743 | case NodeTypeBoolLiteral: |
| 2732 | // none | 2744 | // none |
| ... | @@ -2738,38 +2750,38 @@ void normalize_parent_ptrs(AstNode *node) { | ... | @@ -2738,38 +2750,38 @@ void normalize_parent_ptrs(AstNode *node) { |
| 2738 | // none | 2750 | // none |
| 2739 | break; | 2751 | break; |
| 2740 | case NodeTypeIfBoolExpr: | 2752 | case NodeTypeIfBoolExpr: |
| 2741 | set_field(&node->data.if_bool_expr.condition); | 2753 | visit_field(&node->data.if_bool_expr.condition, visit, context); |
| 2742 | set_field(&node->data.if_bool_expr.then_block); | 2754 | visit_field(&node->data.if_bool_expr.then_block, visit, context); |
| 2743 | set_field(&node->data.if_bool_expr.else_node); | 2755 | visit_field(&node->data.if_bool_expr.else_node, visit, context); |
| 2744 | break; | 2756 | break; |
| 2745 | case NodeTypeIfVarExpr: | 2757 | case NodeTypeIfVarExpr: |
| 2746 | set_field(&node->data.if_var_expr.var_decl.type); | 2758 | visit_field(&node->data.if_var_expr.var_decl.type, visit, context); |
| 2747 | set_field(&node->data.if_var_expr.var_decl.expr); | 2759 | visit_field(&node->data.if_var_expr.var_decl.expr, visit, context); |
| 2748 | set_field(&node->data.if_var_expr.then_block); | 2760 | visit_field(&node->data.if_var_expr.then_block, visit, context); |
| 2749 | set_field(&node->data.if_var_expr.else_node); | 2761 | visit_field(&node->data.if_var_expr.else_node, visit, context); |
| 2750 | break; | 2762 | break; |
| 2751 | case NodeTypeWhileExpr: | 2763 | case NodeTypeWhileExpr: |
| 2752 | set_field(&node->data.while_expr.condition); | 2764 | visit_field(&node->data.while_expr.condition, visit, context); |
| 2753 | set_field(&node->data.while_expr.body); | 2765 | visit_field(&node->data.while_expr.body, visit, context); |
| 2754 | break; | 2766 | break; |
| 2755 | case NodeTypeForExpr: | 2767 | case NodeTypeForExpr: |
| 2756 | set_field(&node->data.for_expr.elem_node); | 2768 | visit_field(&node->data.for_expr.elem_node, visit, context); |
| 2757 | set_field(&node->data.for_expr.array_expr); | 2769 | visit_field(&node->data.for_expr.array_expr, visit, context); |
| 2758 | set_field(&node->data.for_expr.index_node); | 2770 | visit_field(&node->data.for_expr.index_node, visit, context); |
| 2759 | set_field(&node->data.for_expr.body); | 2771 | visit_field(&node->data.for_expr.body, visit, context); |
| 2760 | break; | 2772 | break; |
| 2761 | case NodeTypeSwitchExpr: | 2773 | case NodeTypeSwitchExpr: |
| 2762 | set_field(&node->data.switch_expr.expr); | 2774 | visit_field(&node->data.switch_expr.expr, visit, context); |
| 2763 | set_list_fields(&node->data.switch_expr.prongs); | 2775 | visit_node_list(&node->data.switch_expr.prongs, visit, context); |
| 2764 | break; | 2776 | break; |
| 2765 | case NodeTypeSwitchProng: | 2777 | case NodeTypeSwitchProng: |
| 2766 | set_list_fields(&node->data.switch_prong.items); | 2778 | visit_node_list(&node->data.switch_prong.items, visit, context); |
| 2767 | set_field(&node->data.switch_prong.var_symbol); | 2779 | visit_field(&node->data.switch_prong.var_symbol, visit, context); |
| 2768 | set_field(&node->data.switch_prong.expr); | 2780 | visit_field(&node->data.switch_prong.expr, visit, context); |
| 2769 | break; | 2781 | break; |
| 2770 | case NodeTypeSwitchRange: | 2782 | case NodeTypeSwitchRange: |
| 2771 | set_field(&node->data.switch_range.start); | 2783 | visit_field(&node->data.switch_range.start, visit, context); |
| 2772 | set_field(&node->data.switch_range.end); | 2784 | visit_field(&node->data.switch_range.end, visit, context); |
| 2773 | break; | 2785 | break; |
| 2774 | case NodeTypeLabel: | 2786 | case NodeTypeLabel: |
| 2775 | // none | 2787 | // none |
| ... | @@ -2786,32 +2798,32 @@ void normalize_parent_ptrs(AstNode *node) { | ... | @@ -2786,32 +2798,32 @@ void normalize_parent_ptrs(AstNode *node) { |
| 2786 | case NodeTypeAsmExpr: | 2798 | case NodeTypeAsmExpr: |
| 2787 | for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) { | 2799 | for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) { |
| 2788 | AsmInput *asm_input = node->data.asm_expr.input_list.at(i); | 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 | for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) { | 2803 | for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) { |
| 2792 | AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); | 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 | break; | 2807 | break; |
| 2796 | case NodeTypeStructDecl: | 2808 | case NodeTypeStructDecl: |
| 2797 | set_list_fields(&node->data.struct_decl.fields); | 2809 | visit_node_list(&node->data.struct_decl.fields, visit, context); |
| 2798 | set_list_fields(&node->data.struct_decl.fns); | 2810 | visit_node_list(&node->data.struct_decl.fns, visit, context); |
| 2799 | set_list_fields(node->data.struct_decl.top_level_decl.directives); | 2811 | visit_node_list(node->data.struct_decl.top_level_decl.directives, visit, context); |
| 2800 | break; | 2812 | break; |
| 2801 | case NodeTypeStructField: | 2813 | case NodeTypeStructField: |
| 2802 | set_field(&node->data.struct_field.type); | 2814 | visit_field(&node->data.struct_field.type, visit, context); |
| 2803 | set_list_fields(node->data.struct_field.top_level_decl.directives); | 2815 | visit_node_list(node->data.struct_field.top_level_decl.directives, visit, context); |
| 2804 | break; | 2816 | break; |
| 2805 | case NodeTypeContainerInitExpr: | 2817 | case NodeTypeContainerInitExpr: |
| 2806 | set_field(&node->data.container_init_expr.type); | 2818 | visit_field(&node->data.container_init_expr.type, visit, context); |
| 2807 | set_list_fields(&node->data.container_init_expr.entries); | 2819 | visit_node_list(&node->data.container_init_expr.entries, visit, context); |
| 2808 | break; | 2820 | break; |
| 2809 | case NodeTypeStructValueField: | 2821 | case NodeTypeStructValueField: |
| 2810 | set_field(&node->data.struct_val_field.expr); | 2822 | visit_field(&node->data.struct_val_field.expr, visit, context); |
| 2811 | break; | 2823 | break; |
| 2812 | case NodeTypeArrayType: | 2824 | case NodeTypeArrayType: |
| 2813 | set_field(&node->data.array_type.size); | 2825 | visit_field(&node->data.array_type.size, visit, context); |
| 2814 | set_field(&node->data.array_type.child_type); | 2826 | visit_field(&node->data.array_type.child_type, visit, context); |
| 2815 | break; | 2827 | break; |
| 2816 | case NodeTypeErrorType: | 2828 | case NodeTypeErrorType: |
| 2817 | // none | 2829 | // none |
| ... | @@ -2821,3 +2833,29 @@ void normalize_parent_ptrs(AstNode *node) { | ... | @@ -2821,3 +2833,29 @@ void normalize_parent_ptrs(AstNode *node) { |
| 2821 | break; | 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,10 +20,11 @@ void ast_token_error(Token *token, const char *format, ...); |
| 20 | AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color, | 20 | AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color, |
| 21 | uint32_t *next_node_index); | 21 | uint32_t *next_node_index); |
| 22 | 22 | ||
| 23 | const char *node_type_str(NodeType node_type); | ||
| 24 | |||
| 25 | void ast_print(AstNode *node, int indent); | 23 | void ast_print(AstNode *node, int indent); |
| 26 | 24 | ||
| 27 | void normalize_parent_ptrs(AstNode *node); | 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 | #endif | 30 | #endif |
test/self_hosted.zig+10| ... | @@ -512,6 +512,16 @@ three)"; | ... | @@ -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 | fn assert(b: bool) { | 525 | fn assert(b: bool) { |
| 516 | if (!b) unreachable{} | 526 | if (!b) unreachable{} |
| 517 | } | 527 | } |