diff --git a/CMakeLists.txt b/CMakeLists.txt index b2f70b5d3c..0e7e68078b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,6 @@ include_directories( ) set(ZIG_SOURCES - "${CMAKE_SOURCE_DIR}/src/ir.cpp" "${CMAKE_SOURCE_DIR}/src/analyze.cpp" "${CMAKE_SOURCE_DIR}/src/ast_render.cpp" "${CMAKE_SOURCE_DIR}/src/bignum.cpp" @@ -48,6 +47,7 @@ set(ZIG_SOURCES "${CMAKE_SOURCE_DIR}/src/errmsg.cpp" "${CMAKE_SOURCE_DIR}/src/error.cpp" "${CMAKE_SOURCE_DIR}/src/eval.cpp" + "${CMAKE_SOURCE_DIR}/src/ir.cpp" "${CMAKE_SOURCE_DIR}/src/ir_print.cpp" "${CMAKE_SOURCE_DIR}/src/link.cpp" "${CMAKE_SOURCE_DIR}/src/main.cpp" diff --git a/doc/langref.md b/doc/langref.md index 74bbcf48da..d3e0dd63d7 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -7,7 +7,7 @@ Root = many(TopLevelItem) "EOF" TopLevelItem = ErrorValueDecl | Block | TopLevelDecl -TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | ContainerDecl | GlobalVarDecl | TypeDecl | UseDecl) +TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | GlobalVarDecl | TypeDecl | UseDecl) TypeDecl = "type" Symbol "=" TypeExpr ";" @@ -17,9 +17,7 @@ GlobalVarDecl = VariableDeclaration ";" VariableDeclaration = option("inline") ("var" | "const") Symbol option(":" TypeExpr) "=" Expression -ContainerDecl = ("struct" | "enum" | "union") Symbol option(ParamDeclList) "{" many(StructMember) "}" - -StructMember = (StructField | FnDef | GlobalVarDecl | ContainerDecl) +StructMember = (StructField | FnDef | GlobalVarDecl) StructField = Symbol option(":" Expression) ",") @@ -143,7 +141,7 @@ StructLiteralField = "." Symbol "=" Expression PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | "??" | "-%" -PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) +PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl ArrayType = "[" option(Expression) "]" option("const") TypeExpr @@ -152,6 +150,9 @@ GotoExpression = option("inline") "goto" Symbol GroupedExpression = "(" Expression ")" KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "zeroes" | "error" | "type" | "this" + +ContainerDecl = ("struct" | "enum" | "union") "{" many(StructMember) "}" + ``` ## Operator Precedence diff --git a/src/all_types.hpp b/src/all_types.hpp index 549fecfbed..74f25fc32b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -44,6 +44,7 @@ struct IrGotoItem { struct IrExecutable { ZigList basic_block_list; + Buf *name; size_t mem_slot_count; size_t next_debug_id; size_t *backward_branch_count; @@ -195,7 +196,6 @@ struct Tld { // set this flag temporarily to detect infinite loops bool dep_loop_flag; TldResolution resolution; - Tld *parent_tld; }; struct TldVar { @@ -594,12 +594,8 @@ enum ContainerKind { ContainerKindUnion, }; -struct AstNodeStructDecl { - VisibMod visib_mod; - Buf *name; +struct AstNodeContainerDecl { ContainerKind kind; - ZigList generic_params; - bool generic_params_is_var_args; // always an error but it can happen from parsing ZigList fields; ZigList decls; }; @@ -722,7 +718,7 @@ struct AstNode { AstNodeGoto goto_expr; AstNodeAsmExpr asm_expr; AstNodeFieldAccessExpr field_access_expr; - AstNodeStructDecl struct_decl; + AstNodeContainerDecl container_decl; AstNodeStructField struct_field; AstNodeStringLiteral string_literal; AstNodeCharLiteral char_literal; diff --git a/src/analyze.cpp b/src/analyze.cpp index 4bb1d76d85..ea3ba4aa7f 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -831,10 +831,7 @@ static TypeTableEntryId container_to_type(ContainerKind kind) { zig_unreachable(); } -TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, Scope *scope, - ContainerKind kind, AstNode *decl_node, const char *name) -{ - +TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind, AstNode *decl_node, const char *name) { TypeTableEntryId type_id = container_to_type(kind); TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, scope); @@ -852,6 +849,7 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, unsigned line = decl_node->line; + ImportTableEntry *import = get_scope_import(scope); entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name); entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, ZigLLVMTag_DW_structure_type(), name, @@ -862,15 +860,6 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, return entry; } -static TypeTableEntry *get_partial_container_type_tld(CodeGen *g, Scope *scope, TldContainer *tld_container) { - ImportTableEntry *import = tld_container->base.import; - AstNode *container_node = tld_container->base.source_node; - assert(container_node->type == NodeTypeContainerDecl); - ContainerKind kind = container_node->data.struct_decl.kind; - return get_partial_container_type(g, import, scope, kind, container_node, buf_ptr(tld_container->base.name)); -} - - TypeTableEntry *get_underlying_type(TypeTableEntry *type_entry) { if (type_entry->id == TypeTableEntryIdTypeDecl) { return type_entry->data.type_decl.canonical_type; @@ -879,15 +868,15 @@ TypeTableEntry *get_underlying_type(TypeTableEntry *type_entry) { } } -static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, TypeTableEntry *type_entry) { +static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, TypeTableEntry *type_entry, Buf *type_name) { size_t backward_branch_count = 0; return ir_eval_const_value(g, scope, node, type_entry, &backward_branch_count, default_backward_branch_quota, - nullptr, nullptr, node); + nullptr, nullptr, node, type_name); } TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { - IrInstruction *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type); + IrInstruction *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr); if (result->type_entry->id == TypeTableEntryIdInvalid) return g->builtin_types.entry_invalid; @@ -1069,7 +1058,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { assert(decl_node->type == NodeTypeContainerDecl); assert(enum_type->di_type); - uint32_t field_count = decl_node->data.struct_decl.fields.length; + uint32_t field_count = decl_node->data.container_decl.fields.length; enum_type->data.enumeration.src_field_count = field_count; enum_type->data.enumeration.fields = allocate(field_count); @@ -1091,7 +1080,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { size_t gen_field_index = 0; for (uint32_t i = 0; i < field_count; i += 1) { - AstNode *field_node = decl_node->data.struct_decl.fields.at(i); + AstNode *field_node = decl_node->data.container_decl.fields.at(i); TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i]; type_enum_field->name = field_node->data.struct_field.name; TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); @@ -1201,7 +1190,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref); ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, ZigLLVMFileToScope(import->di_file), - buf_ptr(decl_node->data.struct_decl.name), + buf_ptr(&enum_type->name), import->di_file, decl_node->line + 1, debug_size_in_bits, debug_align_in_bits, @@ -1217,7 +1206,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref); uint64_t tag_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, tag_type_entry->type_ref); ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, - ZigLLVMFileToScope(import->di_file), buf_ptr(decl_node->data.struct_decl.name), + ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name), import->di_file, decl_node->line + 1, tag_debug_size_in_bits, tag_debug_align_in_bits, @@ -1257,7 +1246,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { assert(decl_node->type == NodeTypeContainerDecl); assert(struct_type->di_type); - size_t field_count = decl_node->data.struct_decl.fields.length; + size_t field_count = decl_node->data.container_decl.fields.length; struct_type->data.structure.src_field_count = field_count; struct_type->data.structure.fields = allocate(field_count); @@ -1274,7 +1263,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { size_t gen_field_index = 0; for (size_t i = 0; i < field_count; i += 1) { - AstNode *field_node = decl_node->data.struct_decl.fields.at(i); + AstNode *field_node = decl_node->data.container_decl.fields.at(i); TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; type_struct_field->name = field_node->data.struct_field.name; TypeTableEntry *field_type = analyze_type_expr(g, scope, @@ -1316,7 +1305,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { ZigLLVMDIType **di_element_types = allocate(gen_field_count); for (size_t i = 0; i < field_count; i += 1) { - AstNode *field_node = decl_node->data.struct_decl.fields.at(i); + AstNode *field_node = decl_node->data.container_decl.fields.at(i); TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; gen_field_index = type_struct_field->gen_index; if (gen_field_index == SIZE_MAX) { @@ -1348,7 +1337,7 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, struct_type->type_ref); ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, ZigLLVMFileToScope(import->di_file), - buf_ptr(decl_node->data.struct_decl.name), + buf_ptr(&struct_type->name), import->di_file, decl_node->line + 1, debug_size_in_bits, debug_align_in_bits, @@ -1364,14 +1353,28 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { zig_panic("TODO"); } -static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) { - if (tld->parent_tld) { - get_fully_qualified_decl_name(buf, tld->parent_tld, sep); - buf_append_char(buf, sep); - buf_append_buf(buf, tld->name); - } else { - buf_init_from_buf(buf, tld->name); +static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) { + if (!scope) + return; + + if (scope->id == ScopeIdDecls) { + get_fully_qualified_decl_name_internal(buf, scope->parent, sep); + + ScopeDecls *scope_decls = (ScopeDecls *)scope; + if (scope_decls->container_type) { + buf_append_buf(buf, &scope_decls->container_type->name); + buf_append_char(buf, sep); + } + return; } + + get_fully_qualified_decl_name_internal(buf, scope->parent, sep); +} + +static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) { + buf_resize(buf, 0); + get_fully_qualified_decl_name_internal(buf, tld->parent_scope, sep); + buf_append_buf(buf, tld->name); } FnTableEntry *create_fn_raw(FnInline inline_value, bool internal_linkage) { @@ -1401,6 +1404,17 @@ FnTableEntry *create_fn(AstNode *proto_node) { return fn_entry; } +static bool scope_is_root_decls(Scope *scope) { + while (scope) { + if (scope->id == ScopeIdDecls) { + ScopeDecls *scope_decls = (ScopeDecls *)scope; + return (scope_decls->container_type == nullptr); + } + scope = scope->parent; + } + zig_unreachable(); +} + static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { ImportTableEntry *import = tld_fn->base.import; AstNode *proto_node = tld_fn->base.source_node; @@ -1448,9 +1462,8 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { if (fn_def_node) g->fn_defs.append(fn_table_entry); - Tld *parent_tld = tld_fn->base.parent_tld; - bool is_main_fn = !parent_tld && (import == g->root_import) && - buf_eql_str(&fn_table_entry->symbol_name, "main"); + bool is_main_fn = scope_is_root_decls(tld_fn->base.parent_scope) && + (import == g->root_import) && buf_eql_str(&fn_table_entry->symbol_name, "main"); if (is_main_fn) g->main_fn = fn_table_entry; @@ -1480,23 +1493,6 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { } } -static void scan_struct_decl(CodeGen *g, ScopeDecls *decls_scope, TldContainer *tld_container) { - assert(!tld_container->type_entry); - - AstNode *container_node = tld_container->base.source_node; - assert(container_node->type == NodeTypeContainerDecl); - - TypeTableEntry *container_type = get_partial_container_type_tld(g, &decls_scope->base, tld_container); - tld_container->type_entry = container_type; - - // handle the member function definitions independently - for (size_t i = 0; i < container_node->data.struct_decl.decls.length; i += 1) { - AstNode *child_node = container_node->data.struct_decl.decls.at(i); - ScopeDecls *child_scope = get_container_scope(container_type); - scan_decls(g, tld_container->base.import, child_scope, child_node, &tld_container->base); - } -} - static void preview_error_value_decl(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeErrorValueDecl); @@ -1525,7 +1521,7 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) { } void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, - Scope *parent_scope, Tld *parent_tld) + Scope *parent_scope) { tld->id = id; tld->name = name; @@ -1533,40 +1529,25 @@ void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source tld->source_node = source_node; tld->import = source_node->owner; tld->parent_scope = parent_scope; - tld->parent_tld = parent_tld; } -void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, AstNode *node, Tld *parent_tld) { +void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { switch (node->type) { case NodeTypeRoot: - for (size_t i = 0; i < import->root->data.root.top_level_decls.length; i += 1) { - AstNode *child = import->root->data.root.top_level_decls.at(i); - scan_decls(g, import, decls_scope, child, parent_tld); - } - break; - case NodeTypeContainerDecl: - { - Buf *name = node->data.struct_decl.name; - VisibMod visib_mod = node->data.struct_decl.visib_mod; - TldContainer *tld_container = allocate(1); - init_tld(&tld_container->base, TldIdContainer, name, visib_mod, node, &decls_scope->base, parent_tld); - add_top_level_decl(g, decls_scope, &tld_container->base); - if (node->data.struct_decl.generic_params.length == 0) { - scan_struct_decl(g, decls_scope, tld_container); - } else { - zig_panic("TODO all structs anonymous?"); - } + for (size_t i = 0; i < node->data.root.top_level_decls.length; i += 1) { + AstNode *child = node->data.root.top_level_decls.at(i); + scan_decls(g, decls_scope, child); } break; case NodeTypeFnDef: - scan_decls(g, import, decls_scope, node->data.fn_def.fn_proto, parent_tld); + scan_decls(g, decls_scope, node->data.fn_def.fn_proto); break; case NodeTypeVariableDeclaration: { Buf *name = node->data.variable_declaration.symbol; VisibMod visib_mod = node->data.variable_declaration.visib_mod; TldVar *tld_var = allocate(1); - init_tld(&tld_var->base, TldIdVar, name, visib_mod, node, &decls_scope->base, parent_tld); + init_tld(&tld_var->base, TldIdVar, name, visib_mod, node, &decls_scope->base); add_top_level_decl(g, decls_scope, &tld_var->base); break; } @@ -1575,7 +1556,7 @@ void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, A Buf *name = node->data.type_decl.symbol; VisibMod visib_mod = node->data.type_decl.visib_mod; TldTypeDef *tld_typedef = allocate(1); - init_tld(&tld_typedef->base, TldIdTypeDef, name, visib_mod, node, &decls_scope->base, parent_tld); + init_tld(&tld_typedef->base, TldIdTypeDef, name, visib_mod, node, &decls_scope->base); add_top_level_decl(g, decls_scope, &tld_typedef->base); break; } @@ -1590,13 +1571,14 @@ void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, A VisibMod visib_mod = node->data.fn_proto.visib_mod; TldFn *tld_fn = allocate(1); - init_tld(&tld_fn->base, TldIdFn, fn_name, visib_mod, node, &decls_scope->base, parent_tld); + init_tld(&tld_fn->base, TldIdFn, fn_name, visib_mod, node, &decls_scope->base); add_top_level_decl(g, decls_scope, &tld_fn->base); break; } case NodeTypeUse: { g->use_queue.append(node); + ImportTableEntry *import = get_scope_import(&decls_scope->base); import->use_decls.append(node); break; } @@ -1604,6 +1586,7 @@ void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, A // error value declarations do not depend on other top level decls preview_error_value_decl(g, node); break; + case NodeTypeContainerDecl: case NodeTypeParamDecl: case NodeTypeFnDecl: case NodeTypeReturnExpr: @@ -1787,7 +1770,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { if (explicit_type && explicit_type->id == TypeTableEntryIdInvalid) { implicit_type = explicit_type; } else if (var_decl->expr) { - init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type); + init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol); assert(init_value); implicit_type = init_value->type_entry; @@ -1837,13 +1820,6 @@ static void resolve_decl_typedef(CodeGen *g, TldTypeDef *tld_typedef) { void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only) { if (tld->resolution != TldResolutionUnresolved) return; - if (pointer_only && tld->id == TldIdContainer) { - g->resolve_queue.append(tld); - return; - } - - ImportTableEntry *import = tld->import; - assert(import); if (tld->dep_loop_flag) { add_node_error(g, tld->source_node, buf_sprintf("'%s' depends on itself", buf_ptr(tld->name))); @@ -2222,7 +2198,6 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { FnTypeParamInfo *param_info = &fn_type_id->param_info[i]; AstNode *param_decl_node = get_param_decl_node(fn_table_entry, i); AstNodeParamDecl *param_decl = ¶m_decl_node->data.param_decl; - TypeTableEntry *param_type = param_info->type; bool is_noalias = param_info->is_noalias; @@ -2350,7 +2325,7 @@ void preview_use_decl(CodeGen *g, AstNode *node) { assert(node->type == NodeTypeUse); IrInstruction *result = analyze_const_value(g, &node->owner->decls_scope->base, - node->data.use.expr, g->builtin_types.entry_namespace); + node->data.use.expr, g->builtin_types.entry_namespace, nullptr); if (result->type_entry->id == TypeTableEntryIdInvalid) node->owner->any_imports_failed = true; @@ -2438,7 +2413,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, void semantic_analyze(CodeGen *g) { for (; g->import_queue_index < g->import_queue.length; g->import_queue_index += 1) { ImportTableEntry *import = g->import_queue.at(g->import_queue_index); - scan_decls(g, import, import->decls_scope, import->root, nullptr); + scan_decls(g, import->decls_scope, import->root); } for (; g->use_queue_index < g->use_queue.length; g->use_queue_index += 1) { diff --git a/src/analyze.hpp b/src/analyze.hpp index 6bb0818251..bfad92a7bc 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -26,8 +26,7 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id); TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type); TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size); TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); -TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, Scope *scope, - ContainerKind kind, AstNode *decl_node, const char *name); +TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind, AstNode *decl_node, const char *name); TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x); TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type); TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry); @@ -60,13 +59,12 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name); ScopeDecls *get_container_scope(TypeTableEntry *type_entry); TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name); bool is_container_ref(TypeTableEntry *type_entry); -void scan_decls(CodeGen *g, ImportTableEntry *import, ScopeDecls *decls_scope, AstNode *node, Tld *parent_tld); +void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); void preview_use_decl(CodeGen *g, AstNode *node); void resolve_use_decl(CodeGen *g, AstNode *node); FnTableEntry *scope_fn_entry(Scope *scope); ImportTableEntry *get_scope_import(Scope *scope); -void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, - Scope *parent_scope, Tld *parent_tld); +void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source_node, Scope *parent_scope); VariableTableEntry *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf *name, TypeTableEntry *type_entry, bool is_const, ConstExprValue *init_value); TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node); diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 1134d6674e..5391d2d4aa 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -585,13 +585,11 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { break; case NodeTypeContainerDecl: { - const char *struct_name = buf_ptr(node->data.struct_decl.name); - const char *pub_str = visib_mod_string(node->data.struct_decl.visib_mod); - const char *container_str = container_string(node->data.struct_decl.kind); - fprintf(ar->f, "%s%s %s {\n", pub_str, container_str, struct_name); + const char *container_str = container_string(node->data.container_decl.kind); + fprintf(ar->f, "%s {\n", container_str); ar->indent += ar->indent_size; - for (size_t field_i = 0; field_i < node->data.struct_decl.fields.length; field_i += 1) { - AstNode *field_node = node->data.struct_decl.fields.at(field_i); + for (size_t field_i = 0; field_i < node->data.container_decl.fields.length; field_i += 1) { + AstNode *field_node = node->data.container_decl.fields.at(field_i); assert(field_node->type == NodeTypeStructField); print_indent(ar); print_symbol(ar, field_node->data.struct_field.name); diff --git a/src/ir.cpp b/src/ir.cpp index b920ee2f70..d2729d8ed1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2306,6 +2306,8 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, Tld return irb->codegen->invalid_instruction; switch (tld->id) { + case TldIdContainer: + zig_unreachable(); case TldIdVar: { TldVar *tld_var = (TldVar *)tld; @@ -2327,16 +2329,6 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, Tld else return ref_instruction; } - case TldIdContainer: - { - TldContainer *tld_container = (TldContainer *)tld; - - IrInstruction *ref_instruction = ir_build_const_type(irb, scope, source_node, tld_container->type_entry); - if (lval != LValPurposeNone) - return ir_build_ref(irb, scope, source_node, ref_instruction); - else - return ref_instruction; - } case TldIdTypeDef: { TldTypeDef *tld_typedef = (TldTypeDef *)tld; @@ -3861,6 +3853,52 @@ static IrInstruction *ir_gen_err_ok_or(IrBuilder *irb, Scope *parent_scope, AstN return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values); } +static const char *container_string(ContainerKind kind) { + switch (kind) { + case ContainerKindEnum: return "enum"; + case ContainerKindStruct: return "struct"; + case ContainerKindUnion: return "union"; + } + zig_unreachable(); +} + +static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope, AstNode *node) { + assert(node->type == NodeTypeContainerDecl); + + ContainerKind kind = node->data.container_decl.kind; + Buf *name; + if (irb->exec->name) { + name = irb->exec->name; + } else { + FnTableEntry *fn_entry = exec_fn_entry(irb->exec); + if (fn_entry) { + zig_panic("TODO name the container inside the function"); + } else { + name = buf_sprintf("(anonymous %s at %s:%zu:%zu)", container_string(kind), + buf_ptr(node->owner->path), node->line + 1, node->column + 1); + } + } + + + VisibMod visib_mod = VisibModPub; + TldContainer *tld_container = allocate(1); + init_tld(&tld_container->base, TldIdContainer, name, visib_mod, node, parent_scope); + + TypeTableEntry *container_type = get_partial_container_type(irb->codegen, parent_scope, kind, node, buf_ptr(name)); + ScopeDecls *child_scope = get_container_scope(container_type); + + tld_container->type_entry = container_type; + tld_container->decls_scope = child_scope; + + for (size_t i = 0; i < node->data.container_decl.decls.length; i += 1) { + AstNode *child_node = node->data.container_decl.decls.at(i); + scan_decls(irb->codegen, child_scope, child_node); + } + irb->codegen->resolve_queue.append(&tld_container->base); + + return ir_build_const_type(irb, parent_scope, node, container_type); +} + static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, LValPurpose lval) { @@ -3872,6 +3910,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeUse: case NodeTypeSwitchProng: case NodeTypeSwitchRange: + case NodeTypeStructField: zig_unreachable(); case NodeTypeBlock: return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval); @@ -3941,11 +3980,11 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval); case NodeTypeUnwrapErrorExpr: return ir_lval_wrap(irb, scope, ir_gen_err_ok_or(irb, scope, node), lval); + case NodeTypeContainerDecl: + return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); case NodeTypeFnProto: case NodeTypeFnDef: case NodeTypeFnDecl: - case NodeTypeContainerDecl: - case NodeTypeStructField: case NodeTypeErrorValueDecl: case NodeTypeTypeDecl: zig_panic("TODO more IR gen for node types"); @@ -4558,9 +4597,10 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, TypeTableEntry *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, - FnTableEntry *fn_entry, Buf *c_import_buf, AstNode *source_node) + FnTableEntry *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name) { IrExecutable ir_executable = {0}; + ir_executable.name = exec_name; ir_executable.is_inline = true; ir_executable.fn_entry = fn_entry; ir_executable.c_import_buf = c_import_buf; @@ -4577,6 +4617,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node fprintf(stderr, "}\n"); } IrExecutable analyzed_executable = {0}; + analyzed_executable.name = exec_name; analyzed_executable.is_inline = true; analyzed_executable.fn_entry = fn_entry; analyzed_executable.c_import_buf = c_import_buf; @@ -6017,7 +6058,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal AstNode *body_node = fn_entry->fn_def_node->data.fn_def.body; IrInstruction *result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, - nullptr, call_instruction->base.source_node); + nullptr, call_instruction->base.source_node, nullptr); if (result->type_entry->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; @@ -6772,6 +6813,8 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source return ira->codegen->builtin_types.entry_invalid; switch (tld->id) { + case TldIdContainer: + zig_unreachable(); case TldIdVar: { TldVar *tld_var = (TldVar *)tld; @@ -6794,21 +6837,6 @@ static TypeTableEntry *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source return ir_analyze_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry, depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const); } - case TldIdContainer: - { - TldContainer *tld_container = (TldContainer *)tld; - assert(tld_container->type_entry); - - // TODO instead of allocating this every time, put it in the tld value and we can reference - // the same one every time - ConstExprValue *const_val = allocate(1); - const_val->special = ConstValSpecialStatic; - const_val->data.x_type = tld_container->type_entry; - - bool ptr_is_const = true; - return ir_analyze_const_ptr(ira, source_instruction, const_val, ira->codegen->builtin_types.entry_type, - depends_on_compile_var, ConstPtrSpecialNone, ptr_is_const); - } case TldIdTypeDef: { TldTypeDef *tld_typedef = (TldTypeDef *)tld; @@ -7928,7 +7956,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi ImportTableEntry *target_import = add_source_file(ira->codegen, target_package, abs_full_path, search_dir, import_target_path, import_code); - scan_decls(ira->codegen, target_import, target_import->decls_scope, target_import->root, nullptr); + scan_decls(ira->codegen, target_import->decls_scope, target_import->root); ConstExprValue *out_val = ir_build_const_from(ira, &import_instruction->base, depends_on_compile_var); out_val->data.x_import = target_import; @@ -8303,7 +8331,7 @@ static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruc TypeTableEntry *void_type = ira->codegen->builtin_types.entry_void; IrInstruction *result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, - &cimport_scope->buf, block_node); + &cimport_scope->buf, block_node, nullptr); if (result->type_entry->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; diff --git a/src/ir.hpp b/src/ir.hpp index bb79a6ed53..69e8115bf8 100644 --- a/src/ir.hpp +++ b/src/ir.hpp @@ -15,7 +15,7 @@ IrInstruction *ir_gen_fn(CodeGen *g, FnTableEntry *fn_entry); IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, TypeTableEntry *expected_type, size_t *backward_branch_count, size_t backward_branch_quota, - FnTableEntry *fn_entry, Buf *c_import_buf, AstNode *source_node); + FnTableEntry *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name); TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable, TypeTableEntry *expected_type, AstNode *expected_type_source_node); diff --git a/src/parseh.cpp b/src/parseh.cpp index d22a1c3fd7..3c31a9c564 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -120,7 +120,7 @@ static const char *decl_name(const Decl *decl) { } static void parseh_init_tld(Context *c, Tld *tld, TldId id, Buf *name) { - init_tld(tld, id, name, c->visib_mod, c->source_node, &c->import->decls_scope->base, nullptr); + init_tld(tld, id, name, c->visib_mod, c->source_node, &c->import->decls_scope->base); tld->resolution = TldResolutionOk; } @@ -184,7 +184,7 @@ static Tld *create_global_num_lit_ap(Context *c, const Decl *source_decl, Buf *n } -static void add_const_type(Context *c, Buf *name, TypeTableEntry *type_entry) { +static Tld *add_const_type(Context *c, Buf *name, TypeTableEntry *type_entry) { ConstExprValue *var_value = allocate(1); var_value->special = ConstValSpecialStatic; var_value->data.x_type = type_entry; @@ -192,15 +192,11 @@ static void add_const_type(Context *c, Buf *name, TypeTableEntry *type_entry) { add_global(c, &tld_var->base); c->global_type_table.put(name, type_entry); + return &tld_var->base; } static Tld *add_container_tld(Context *c, TypeTableEntry *type_entry) { - TldContainer *tld_container = allocate(1); - parseh_init_tld(c, &tld_container->base, TldIdContainer, &type_entry->name); - tld_container->type_entry = type_entry; - - add_global(c, &tld_container->base); - return &tld_container->base; + return add_const_type(c, &type_entry->name, type_entry); } static Tld *add_typedef_tld(Context *c, TypeTableEntry *type_decl) { @@ -690,8 +686,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) const EnumDecl *enum_def = enum_decl->getDefinition(); if (!enum_def) { - TypeTableEntry *enum_type = get_partial_container_type(c->codegen, c->import, - &c->import->decls_scope->base, + TypeTableEntry *enum_type = get_partial_container_type(c->codegen, &c->import->decls_scope->base, ContainerKindEnum, c->source_node, buf_ptr(full_type_name)); c->enum_type_table.put(bare_name, enum_type); c->decl_table.put(enum_decl, enum_type); @@ -715,8 +710,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) TypeTableEntry *tag_type_entry = resolve_qual_type(c, enum_decl->getIntegerType(), enum_decl); if (pure_enum) { - TypeTableEntry *enum_type = get_partial_container_type(c->codegen, c->import, - &c->import->decls_scope->base, + TypeTableEntry *enum_type = get_partial_container_type(c->codegen, &c->import->decls_scope->base, ContainerKindEnum, c->source_node, buf_ptr(full_type_name)); c->enum_type_table.put(bare_name, enum_type); c->decl_table.put(enum_decl, enum_type); @@ -855,8 +849,8 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_ Buf *full_type_name = buf_sprintf("struct_%s", buf_ptr(bare_name)); - TypeTableEntry *struct_type = get_partial_container_type(c->codegen, c->import, - &c->import->decls_scope->base, ContainerKindStruct, c->source_node, buf_ptr(full_type_name)); + TypeTableEntry *struct_type = get_partial_container_type(c->codegen, &c->import->decls_scope->base, + ContainerKindStruct, c->source_node, buf_ptr(full_type_name)); c->struct_type_table.put(bare_name, struct_type); c->decl_table.put(record_decl, struct_type); diff --git a/src/parser.cpp b/src/parser.cpp index 2f4824ad39..0ee984d7fa 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -216,6 +216,7 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, size_t *token_index, static AstNode *ast_parse_fn_proto(ParseContext *pc, size_t *token_index, bool mandatory, VisibMod visib_mod); static AstNode *ast_parse_return_expr(ParseContext *pc, size_t *token_index); static AstNode *ast_parse_grouped_expr(ParseContext *pc, size_t *token_index, bool mandatory); +static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory); static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) { if (token->id == token_id) { @@ -618,7 +619,7 @@ static AstNode *ast_parse_goto_expr(ParseContext *pc, size_t *token_index, bool return node; } /* -PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | FnProto | AsmExpression | ("error" "." "Symbol") +PrimaryExpression = Number | String | CharLiteral | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | Symbol | ("@" Symbol FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." Symbol) | ContainerDecl KeywordLiteral = "true" | "false" | "null" | "break" | "continue" | "undefined" | "zeroes" | "error" | "type" | "this" */ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bool mandatory) { @@ -737,6 +738,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, size_t *token_index, bo return asm_expr; } + AstNode *container_decl = ast_parse_container_decl(pc, token_index, false); + if (container_decl) + return container_decl; + if (!mandatory) return nullptr; @@ -2219,43 +2224,31 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi } /* -ContainerDecl = ("struct" | "enum" | "union") Symbol option(ParamDeclList) "{" many(StructMember) "}" -StructMember = (StructField | FnDef | GlobalVarDecl | ContainerDecl) +ContainerDecl = ("struct" | "enum" | "union") "{" many(StructMember) "}" +StructMember = (StructField | FnDef | GlobalVarDecl) StructField = Symbol option(":" Expression) ",") */ -static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, VisibMod visib_mod) { +static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory) { Token *first_token = &pc->tokens->at(*token_index); ContainerKind kind; - if (first_token->id == TokenIdKeywordStruct) { kind = ContainerKindStruct; } else if (first_token->id == TokenIdKeywordEnum) { kind = ContainerKindEnum; } else if (first_token->id == TokenIdKeywordUnion) { kind = ContainerKindUnion; + } else if (mandatory) { + ast_invalid_token_error(pc, first_token); } else { return nullptr; } *token_index += 1; - Token *struct_name = ast_eat_token(pc, token_index, TokenIdSymbol); - AstNode *node = ast_create_node(pc, NodeTypeContainerDecl, first_token); - node->data.struct_decl.kind = kind; - node->data.struct_decl.name = token_buf(struct_name); - node->data.struct_decl.visib_mod = visib_mod; + node->data.container_decl.kind = kind; - Token *paren_or_brace = &pc->tokens->at(*token_index); - if (paren_or_brace->id == TokenIdLParen) { - ast_parse_param_decl_list(pc, token_index, &node->data.struct_decl.generic_params, - &node->data.struct_decl.generic_params_is_var_args); - ast_eat_token(pc, token_index, TokenIdLBrace); - } else if (paren_or_brace->id == TokenIdLBrace) { - *token_index += 1; - } else { - ast_invalid_token_error(pc, paren_or_brace); - } + ast_eat_token(pc, token_index, TokenIdLBrace); for (;;) { Token *visib_tok = &pc->tokens->at(*token_index); @@ -2272,20 +2265,14 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, AstNode *fn_def_node = ast_parse_fn_def(pc, token_index, false, visib_mod); if (fn_def_node) { - node->data.struct_decl.decls.append(fn_def_node); + node->data.container_decl.decls.append(fn_def_node); continue; } AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod); if (var_decl_node) { ast_eat_token(pc, token_index, TokenIdSemicolon); - node->data.struct_decl.decls.append(var_decl_node); - continue; - } - - AstNode *container_decl_node = ast_parse_container_decl(pc, token_index, visib_mod); - if (container_decl_node) { - node->data.struct_decl.decls.append(container_decl_node); + node->data.container_decl.decls.append(var_decl_node); continue; } @@ -2311,7 +2298,7 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, ast_eat_token(pc, token_index, TokenIdComma); } - node->data.struct_decl.fields.append(field_node); + node->data.container_decl.fields.append(field_node); } else { ast_invalid_token_error(pc, token); } @@ -2368,7 +2355,7 @@ static AstNode *ast_parse_type_decl(ParseContext *pc, size_t *token_index, Visib /* TopLevelItem = ErrorValueDecl | Block | TopLevelDecl -TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | ContainerDecl | GlobalVarDecl | TypeDecl | UseDecl) +TopLevelDecl = option(VisibleMod) (FnDef | ExternDecl | GlobalVarDecl | TypeDecl | UseDecl) */ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, ZigList *top_level_decls) { for (;;) { @@ -2402,12 +2389,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, size_t *token_index, Zig continue; } - AstNode *struct_node = ast_parse_container_decl(pc, token_index, visib_mod); - if (struct_node) { - top_level_decls->append(struct_node); - continue; - } - AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, visib_mod); if (var_decl_node) { ast_eat_token(pc, token_index, TokenIdSemicolon); @@ -2630,8 +2611,8 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont } break; case NodeTypeContainerDecl: - visit_node_list(&node->data.struct_decl.fields, visit, context); - visit_node_list(&node->data.struct_decl.decls, visit, context); + visit_node_list(&node->data.container_decl.fields, visit, context); + visit_node_list(&node->data.container_decl.decls, visit, context); break; case NodeTypeStructField: visit_field(&node->data.struct_field.type, visit, context); diff --git a/test/self_hosted2.zig b/test/self_hosted2.zig index 517567271e..8692f51e17 100644 --- a/test/self_hosted2.zig +++ b/test/self_hosted2.zig @@ -87,9 +87,9 @@ var goto_counter: i32 = 0; -struct FooA { +const FooA = struct { fn add(a: i32, b: i32) -> i32 { a + b } -} +}; const foo_a = FooA {}; fn testStructStatic() {