diff --git a/src/all_types.hpp b/src/all_types.hpp index c939113e6e..2a9a115282 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -53,6 +53,7 @@ struct IrExecutable { ZigList goto_list; bool is_inline; FnTableEntry *fn_entry; + Buf *c_import_buf; }; enum OutType { @@ -1226,6 +1227,7 @@ struct VariableTableEntry { size_t mem_slot_index; size_t ref_count; ConstExprValue *value; + bool is_extern; }; struct ErrorTableEntry { @@ -1307,7 +1309,7 @@ struct ScopeVarDecl { struct ScopeCImport { Scope base; - Buf c_import_buf; + Buf buf; }; // This scope is created for a loop such as for or while in order to @@ -1394,6 +1396,10 @@ enum IrInstructionId { IrInstructionIdCtz, IrInstructionIdStaticEval, IrInstructionIdImport, + IrInstructionIdCImport, + IrInstructionIdCInclude, + IrInstructionIdCDefine, + IrInstructionIdCUndef, IrInstructionIdArrayLen, IrInstructionIdRef, IrInstructionIdMinValue, @@ -1823,6 +1829,29 @@ struct IrInstructionErrName { IrInstruction *value; }; +struct IrInstructionCImport { + IrInstruction base; +}; + +struct IrInstructionCInclude { + IrInstruction base; + + IrInstruction *name; +}; + +struct IrInstructionCDefine { + IrInstruction base; + + IrInstruction *name; + IrInstruction *value; +}; + +struct IrInstructionCUndef { + IrInstruction base; + + IrInstruction *name; +}; + enum LValPurpose { LValPurposeNone, LValPurposeAssign, diff --git a/src/analyze.cpp b/src/analyze.cpp index f5feb14b33..d0ba3f9972 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -13,7 +13,6 @@ #include "ir.hpp" #include "ir_print.hpp" #include "os.hpp" -#include "parseh.hpp" #include "parser.hpp" #include "zig_llvm.hpp" @@ -136,8 +135,8 @@ void init_scope(Scope *dest, ScopeId id, AstNode *source_node, Scope *parent) { dest->parent = parent; } -static ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import) { - assert(node->type == NodeTypeRoot || node->type == NodeTypeContainerDecl); +ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import) { + assert(node == nullptr || node->type == NodeTypeRoot || node->type == NodeTypeContainerDecl || node->type == NodeTypeFnCallExpr); ScopeDecls *scope = allocate(1); init_scope(&scope->base, ScopeIdDecls, node, parent); scope->decl_table.init(4); @@ -168,12 +167,12 @@ Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var) { return &scope->base; } -Scope *create_cimport_scope(AstNode *node, Scope *parent) { +ScopeCImport *create_cimport_scope(AstNode *node, Scope *parent) { assert(node->type == NodeTypeFnCallExpr); ScopeCImport *scope = allocate(1); init_scope(&scope->base, ScopeIdCImport, node, parent); - buf_resize(&scope->c_import_buf, 0); - return &scope->base; + buf_resize(&scope->buf, 0); + return scope; } Scope *create_loop_scope(AstNode *node, Scope *parent) { @@ -877,7 +876,7 @@ static IrInstruction *analyze_const_value(CodeGen *g, Scope *scope, AstNode *nod 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, nullptr); } TypeTableEntry *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { @@ -1367,21 +1366,31 @@ static void get_fully_qualified_decl_name(Buf *buf, Tld *tld, uint8_t sep) { } } -FnTableEntry *create_fn(CodeGen *g, AstNode *proto_node) { +FnTableEntry *create_fn_raw(FnInline inline_value, bool internal_linkage) { + FnTableEntry *fn_entry = allocate(1); + + fn_entry->analyzed_executable.backward_branch_count = &fn_entry->prealloc_bbc; + fn_entry->analyzed_executable.backward_branch_quota = default_backward_branch_quota; + fn_entry->analyzed_executable.fn_entry = fn_entry; + fn_entry->ir_executable.fn_entry = fn_entry; + fn_entry->fn_inline = inline_value; + fn_entry->internal_linkage = internal_linkage; + + return fn_entry; +} + +FnTableEntry *create_fn(AstNode *proto_node) { assert(proto_node->type == NodeTypeFnProto); AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; - FnTableEntry *fn_table_entry = allocate(1); - fn_table_entry->analyzed_executable.backward_branch_count = &fn_table_entry->prealloc_bbc; - fn_table_entry->analyzed_executable.backward_branch_quota = default_backward_branch_quota; - fn_table_entry->analyzed_executable.fn_entry = fn_table_entry; - fn_table_entry->ir_executable.fn_entry = fn_table_entry; - fn_table_entry->proto_node = proto_node; - fn_table_entry->fn_def_node = proto_node->data.fn_proto.fn_def_node; - fn_table_entry->fn_inline = fn_proto->is_inline ? FnInlineAlways : FnInlineAuto; - fn_table_entry->internal_linkage = (fn_proto->visib_mod != VisibModExport); + FnInline inline_value = fn_proto->is_inline ? FnInlineAlways : FnInlineAuto; + bool internal_linkage = (fn_proto->visib_mod != VisibModExport); + FnTableEntry *fn_entry = create_fn_raw(inline_value, internal_linkage); - return fn_table_entry; + fn_entry->proto_node = proto_node; + fn_entry->fn_def_node = proto_node->data.fn_proto.fn_def_node; + + return fn_entry; } static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { @@ -1399,7 +1408,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { return; } - FnTableEntry *fn_table_entry = create_fn(g, tld_fn->base.source_node); + FnTableEntry *fn_table_entry = create_fn(tld_fn->base.source_node); get_fully_qualified_decl_name(&fn_table_entry->symbol_name, &tld_fn->base, '_'); tld_fn->fn_entry = fn_table_entry; @@ -1801,6 +1810,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol, type, is_const, &init_value->static_value); + tld_var->var->is_extern = is_extern; g->global_vars.append(tld_var->var); } @@ -2736,3 +2746,55 @@ uint64_t get_memcpy_align(CodeGen *g, TypeTableEntry *type_entry) { TypeTableEntry *first_type_in_mem = type_of_first_thing_in_memory(type_entry); return LLVMABISizeOfType(g->target_data_ref, first_type_in_mem->type_ref); } + +void init_const_str_lit(ConstExprValue *const_val, Buf *str) { + const_val->special = ConstValSpecialStatic; + const_val->data.x_array.elements = allocate(buf_len(str)); + const_val->data.x_array.size = buf_len(str); + + for (size_t i = 0; i < buf_len(str); i += 1) { + ConstExprValue *this_char = &const_val->data.x_array.elements[i]; + this_char->special = ConstValSpecialStatic; + bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]); + } +} + +ConstExprValue *create_const_str_lit(Buf *str) { + ConstExprValue *const_val = allocate(1); + init_const_str_lit(const_val, str); + return const_val; +} + +void init_const_unsigned_negative(ConstExprValue *const_val, uint64_t x, bool negative) { + const_val->special = ConstValSpecialStatic; + bignum_init_unsigned(&const_val->data.x_bignum, x); + const_val->data.x_bignum.is_negative = negative; +} + +ConstExprValue *create_const_unsigned_negative(uint64_t x, bool negative) { + ConstExprValue *const_val = allocate(1); + init_const_unsigned_negative(const_val, x, negative); + return const_val; +} + +void init_const_signed(ConstExprValue *const_val, int64_t x) { + const_val->special = ConstValSpecialStatic; + bignum_init_signed(&const_val->data.x_bignum, x); +} + +ConstExprValue *create_const_signed(int64_t x) { + ConstExprValue *const_val = allocate(1); + init_const_signed(const_val, x); + return const_val; +} + +void init_const_float(ConstExprValue *const_val, double value) { + const_val->special = ConstValSpecialStatic; + bignum_init_float(&const_val->data.x_bignum, value); +} + +ConstExprValue *create_const_float(double value) { + ConstExprValue *const_val = allocate(1); + init_const_float(const_val, value); + return const_val; +} diff --git a/src/analyze.hpp b/src/analyze.hpp index c8f5853a65..7868c940ef 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -70,15 +70,29 @@ void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source 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); -FnTableEntry *create_fn(CodeGen *g, AstNode *proto_node); +FnTableEntry *create_fn(AstNode *proto_node); +FnTableEntry *create_fn_raw(FnInline inline_value, bool internal_linkage); void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node); AstNode *get_param_decl_node(FnTableEntry *fn_entry, size_t index); Scope *create_block_scope(AstNode *node, Scope *parent); ScopeDefer *create_defer_scope(AstNode *node, Scope *parent); Scope *create_var_scope(AstNode *node, Scope *parent, VariableTableEntry *var); -Scope *create_cimport_scope(AstNode *node, Scope *parent); +ScopeCImport *create_cimport_scope(AstNode *node, Scope *parent); Scope *create_loop_scope(AstNode *node, Scope *parent); ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_entry); +ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import); + +void init_const_str_lit(ConstExprValue *const_val, Buf *str); +ConstExprValue *create_const_str_lit(Buf *str); + +void init_const_unsigned_negative(ConstExprValue *const_val, uint64_t x, bool negative); +ConstExprValue *create_const_unsigned_negative(uint64_t x, bool negative); + +void init_const_signed(ConstExprValue *const_val, int64_t x); +ConstExprValue *create_const_signed(int64_t x); + +void init_const_float(ConstExprValue *const_val, double value); +ConstExprValue *create_const_float(double value); #endif diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 15d9b6b8bb..929aa17c6f 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -870,3 +870,4 @@ void ast_render(FILE *f, AstNode *node, int indent_size) { render_node_grouped(&ar, node); } + diff --git a/src/codegen.cpp b/src/codegen.cpp index c828b42ed1..e3e162173b 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1868,12 +1868,16 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdSizeOf: case IrInstructionIdSwitchTarget: case IrInstructionIdStaticEval: - case IrInstructionIdImport: case IrInstructionIdContainerInitFields: case IrInstructionIdMinValue: case IrInstructionIdMaxValue: case IrInstructionIdCompileErr: case IrInstructionIdArrayLen: + case IrInstructionIdImport: + case IrInstructionIdCImport: + case IrInstructionIdCInclude: + case IrInstructionIdCDefine: + case IrInstructionIdCUndef: zig_unreachable(); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); @@ -2346,7 +2350,7 @@ static void do_code_gen(CodeGen *g) { assert(var->decl_node->type == NodeTypeVariableDeclaration); LLVMValueRef global_value; - if (var->decl_node->data.variable_declaration.is_extern) { + if (var->is_extern) { global_value = LLVMAddGlobal(g->module, var->type->type_ref, buf_ptr(&var->name)); // TODO debug info for the extern variable diff --git a/src/ir.cpp b/src/ir.cpp index a97156e13a..09342123ac 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12,6 +12,7 @@ #include "ir.hpp" #include "ir_print.hpp" #include "os.hpp" +#include "parseh.hpp" struct IrExecContext { ConstExprValue *mem_slot_list; @@ -88,6 +89,10 @@ static FnTableEntry *exec_fn_entry(IrExecutable *exec) { return exec->fn_entry; } +static Buf *exec_c_import_buf(IrExecutable *exec) { + return exec->c_import_buf; +} + static void ir_link_new_instruction(IrInstruction *new_instruction, IrInstruction *old_instruction) { new_instruction->other = old_instruction; old_instruction->other = new_instruction; @@ -294,6 +299,22 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionImport *) { return IrInstructionIdImport; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionCImport *) { + return IrInstructionIdCImport; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionCInclude *) { + return IrInstructionIdCInclude; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionCDefine *) { + return IrInstructionIdCDefine; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionCUndef *) { + return IrInstructionIdCUndef; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionArrayLen *) { return IrInstructionIdArrayLen; } @@ -512,18 +533,6 @@ static IrInstruction *ir_build_const_bound_fn(IrBuilder *irb, Scope *scope, AstN return &const_instruction->base; } -static void init_const_str_lit(ConstExprValue *const_val, Buf *str) { - const_val->special = ConstValSpecialStatic; - const_val->data.x_array.elements = allocate(buf_len(str)); - const_val->data.x_array.size = buf_len(str); - - for (size_t i = 0; i < buf_len(str); i += 1) { - ConstExprValue *this_char = &const_val->data.x_array.elements[i]; - this_char->special = ConstValSpecialStatic; - bignum_init_unsigned(&this_char->data.x_bignum, buf_ptr(str)[i]); - } -} - static IrInstruction *ir_create_const_str_lit(IrBuilder *irb, Scope *scope, AstNode *source_node, Buf *str) { IrInstructionConst *const_instruction = ir_create_instruction(irb->exec, scope, source_node); TypeTableEntry *u8_type = irb->codegen->builtin_types.entry_u8; @@ -1301,6 +1310,39 @@ static IrInstruction *ir_build_err_name_from(IrBuilder *irb, IrInstruction *old_ return new_instruction; } +static IrInstruction *ir_build_c_import(IrBuilder *irb, Scope *scope, AstNode *source_node) { + IrInstructionCImport *instruction = ir_build_instruction(irb, scope, source_node); + return &instruction->base; +} + +static IrInstruction *ir_build_c_include(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *name) { + IrInstructionCInclude *instruction = ir_build_instruction(irb, scope, source_node); + instruction->name = name; + + ir_ref_instruction(name); + + return &instruction->base; +} + +static IrInstruction *ir_build_c_define(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *name, IrInstruction *value) { + IrInstructionCDefine *instruction = ir_build_instruction(irb, scope, source_node); + instruction->name = name; + instruction->value = value; + + ir_ref_instruction(name); + ir_ref_instruction(value); + + return &instruction->base; +} + +static IrInstruction *ir_build_c_undef(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *name) { + IrInstructionCUndef *instruction = ir_build_instruction(irb, scope, source_node); + instruction->name = name; + + ir_ref_instruction(name); + + return &instruction->base; +} static void ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers, bool gen_maybe_defers) @@ -1934,12 +1976,68 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; if (exec_fn_entry(irb->exec)) { - add_node_error(irb->codegen, node, buf_sprintf("import valid only at top level scope")); + add_node_error(irb->codegen, node, buf_sprintf("import valid only at global scope")); return irb->codegen->invalid_instruction; } return ir_build_import(irb, scope, node, arg0_value); } + case BuiltinFnIdCImport: + { + if (exec_fn_entry(irb->exec)) { + add_node_error(irb->codegen, node, buf_sprintf("C import valid only at global scope")); + return irb->codegen->invalid_instruction; + } + + return ir_build_c_import(irb, scope, node); + } + case BuiltinFnIdCInclude: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + if (!exec_c_import_buf(irb->exec)) { + add_node_error(irb->codegen, node, buf_sprintf("C include valid only inside C import block")); + return irb->codegen->invalid_instruction; + } + + return ir_build_c_include(irb, scope, node, arg0_value); + } + case BuiltinFnIdCDefine: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + if (!exec_c_import_buf(irb->exec)) { + add_node_error(irb->codegen, node, buf_sprintf("C define valid only inside C import block")); + return irb->codegen->invalid_instruction; + } + + return ir_build_c_define(irb, scope, node, arg0_value, arg1_value); + } + case BuiltinFnIdCUndef: + { + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + if (!exec_c_import_buf(irb->exec)) { + add_node_error(irb->codegen, node, buf_sprintf("C undef valid only inside C import block")); + return irb->codegen->invalid_instruction; + } + + return ir_build_c_undef(irb, scope, node, arg0_value); + } case BuiltinFnIdMaxValue: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -1984,10 +2082,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo case BuiltinFnIdSubWithOverflow: case BuiltinFnIdMulWithOverflow: case BuiltinFnIdShlWithOverflow: - case BuiltinFnIdCInclude: - case BuiltinFnIdCDefine: - case BuiltinFnIdCUndef: - case BuiltinFnIdCImport: case BuiltinFnIdBreakpoint: case BuiltinFnIdReturnAddress: case BuiltinFnIdFrameAddress: @@ -3507,11 +3601,12 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value) { 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) + FnTableEntry *fn_entry, Buf *c_import_buf) { IrExecutable ir_executable = {0}; ir_executable.is_inline = true; ir_executable.fn_entry = fn_entry; + ir_executable.c_import_buf = c_import_buf; ir_gen(codegen, node, scope, &ir_executable); if (ir_executable.invalid) @@ -3527,6 +3622,7 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node IrExecutable analyzed_executable = {0}; analyzed_executable.is_inline = true; analyzed_executable.fn_entry = fn_entry; + analyzed_executable.c_import_buf = c_import_buf; analyzed_executable.backward_branch_count = backward_branch_count; analyzed_executable.backward_branch_quota = backward_branch_quota; TypeTableEntry *result_type = ir_analyze(codegen, &ir_executable, &analyzed_executable, expected_type, node); @@ -4641,7 +4737,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal // Analyze the fn body block like any other constant expression. 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); + ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, nullptr); if (result->type_entry->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; @@ -4658,7 +4754,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal // Fork a scope of the function with known values for the parameters. Scope *parent_scope = fn_entry->fndef_scope->base.parent; - FnTableEntry *impl_fn = create_fn(ira->codegen, fn_proto_node); + FnTableEntry *impl_fn = create_fn(fn_proto_node); impl_fn->param_source_nodes = allocate(call_param_count); buf_init_from_buf(&impl_fn->symbol_name, &fn_entry->symbol_name); impl_fn->fndef_scope = create_fndef_scope(impl_fn->fn_def_node, parent_scope, impl_fn); @@ -6929,6 +7025,124 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc return str_type; } +static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) { + AstNode *node = instruction->base.source_node; + assert(node->type == NodeTypeFnCallExpr); + AstNode *block_node = node->data.fn_call_expr.params.at(0); + + ScopeCImport *cimport_scope = create_cimport_scope(node, instruction->base.scope); + + // Execute the C import block like an inline function + 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); + if (result->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + find_libc_include_path(ira->codegen); + + ImportTableEntry *child_import = allocate(1); + child_import->decls_scope = create_decls_scope(child_import->root, nullptr, nullptr, child_import); + child_import->c_import_node = node; + + ZigList errors = {0}; + + int err; + if ((err = parse_h_buf(child_import, &errors, &cimport_scope->buf, ira->codegen, node))) { + zig_panic("unable to parse h file: %s\n", err_str(err)); + } + + if (errors.length > 0) { + ErrorMsg *parent_err_msg = add_node_error(ira->codegen, node, buf_sprintf("C import failed")); + for (size_t i = 0; i < errors.length; i += 1) { + ErrorMsg *err_msg = errors.at(i); + err_msg_add_note(parent_err_msg, err_msg); + } + + return ira->codegen->builtin_types.entry_invalid; + } + + if (ira->codegen->verbose) { + fprintf(stderr, "\nC imports:\n"); + fprintf(stderr, "-----------\n"); + ir_print_decls(stderr, child_import); + } + + // TODO to get fewer false negatives on this, we would need to track this value in + // the ir executable + bool depends_on_compile_var = true; + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var); + out_val->data.x_import = child_import; + return ira->codegen->builtin_types.entry_namespace; +} + +static TypeTableEntry *ir_analyze_instruction_c_include(IrAnalyze *ira, IrInstructionCInclude *instruction) { + IrInstruction *name_value = instruction->name->other; + if (name_value->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + Buf *include_name = ir_resolve_str(ira, name_value); + if (!include_name) + return ira->codegen->builtin_types.entry_invalid; + + Buf *c_import_buf = exec_c_import_buf(ira->new_irb.exec); + // We check for this error in pass1 + assert(c_import_buf); + + buf_appendf(c_import_buf, "#include <%s>\n", buf_ptr(include_name)); + + ir_build_const_from(ira, &instruction->base, false); + return ira->codegen->builtin_types.entry_void; +} + +static TypeTableEntry *ir_analyze_instruction_c_define(IrAnalyze *ira, IrInstructionCDefine *instruction) { + IrInstruction *name = instruction->name->other; + if (name->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + Buf *define_name = ir_resolve_str(ira, name); + if (!define_name) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *value = instruction->value->other; + if (value->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + Buf *define_value = ir_resolve_str(ira, value); + if (!define_value) + return ira->codegen->builtin_types.entry_invalid; + + Buf *c_import_buf = exec_c_import_buf(ira->new_irb.exec); + // We check for this error in pass1 + assert(c_import_buf); + + buf_appendf(c_import_buf, "#define %s %s\n", buf_ptr(define_name), buf_ptr(define_value)); + + ir_build_const_from(ira, &instruction->base, false); + return ira->codegen->builtin_types.entry_void; +} + +static TypeTableEntry *ir_analyze_instruction_c_undef(IrAnalyze *ira, IrInstructionCUndef *instruction) { + IrInstruction *name = instruction->name->other; + if (name->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + Buf *undef_name = ir_resolve_str(ira, name); + if (!undef_name) + return ira->codegen->builtin_types.entry_invalid; + + Buf *c_import_buf = exec_c_import_buf(ira->new_irb.exec); + // We check for this error in pass1 + assert(c_import_buf); + + buf_appendf(c_import_buf, "#undef %s\n", buf_ptr(undef_name)); + + ir_build_const_from(ira, &instruction->base, false); + return ira->codegen->builtin_types.entry_void; +} + + + static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -7021,6 +7235,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_compile_err(ira, (IrInstructionCompileErr *)instruction); case IrInstructionIdErrName: return ir_analyze_instruction_err_name(ira, (IrInstructionErrName *)instruction); + case IrInstructionIdCImport: + return ir_analyze_instruction_c_import(ira, (IrInstructionCImport *)instruction); + case IrInstructionIdCInclude: + return ir_analyze_instruction_c_include(ira, (IrInstructionCInclude *)instruction); + case IrInstructionIdCDefine: + return ir_analyze_instruction_c_define(ira, (IrInstructionCDefine *)instruction); + case IrInstructionIdCUndef: + return ir_analyze_instruction_c_undef(ira, (IrInstructionCUndef *)instruction); case IrInstructionIdCast: case IrInstructionIdStructFieldPtr: case IrInstructionIdEnumFieldPtr: @@ -7116,6 +7338,10 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdSetDebugSafety: case IrInstructionIdImport: case IrInstructionIdCompileErr: + case IrInstructionIdCImport: + case IrInstructionIdCInclude: + case IrInstructionIdCDefine: + case IrInstructionIdCUndef: return true; case IrInstructionIdPhi: case IrInstructionIdUnOp: @@ -7164,63 +7390,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // TODO port over all this commented out code into new IR way of doing things -//static TypeTableEntry *analyze_c_import(CodeGen *g, ImportTableEntry *parent_import, -// BlockContext *parent_context, AstNode *node) -//{ -// assert(node->type == NodeTypeFnCallExpr); -// -// if (parent_context->fn_entry) { -// add_node_error(g, node, buf_sprintf("@c_import invalid inside function bodies")); -// return g->builtin_types.entry_invalid; -// } -// -// AstNode *block_node = node->data.fn_call_expr.params.at(0); -// -// BlockContext *child_context = new_block_context(node, parent_context); -// child_context->c_import_buf = buf_alloc(); -// -// TypeTableEntry *resolved_type = analyze_expression(g, parent_import, child_context, -// g->builtin_types.entry_void, block_node); -// -// if (resolved_type->id == TypeTableEntryIdInvalid) { -// return resolved_type; -// } -// -// find_libc_include_path(g); -// -// ImportTableEntry *child_import = allocate(1); -// child_import->c_import_node = node; -// -// ZigList errors = {0}; -// -// int err; -// if ((err = parse_h_buf(child_import, &errors, child_context->c_import_buf, g, node))) { -// zig_panic("unable to parse h file: %s\n", err_str(err)); -// } -// -// if (errors.length > 0) { -// ErrorMsg *parent_err_msg = add_node_error(g, node, buf_sprintf("C import failed")); -// for (size_t i = 0; i < errors.length; i += 1) { -// ErrorMsg *err_msg = errors.at(i); -// err_msg_add_note(parent_err_msg, err_msg); -// } -// -// return g->builtin_types.entry_invalid; -// } -// -// if (g->verbose) { -// fprintf(stderr, "\nc_import:\n"); -// fprintf(stderr, "-----------\n"); -// ast_render(stderr, child_import->root, 4); -// } -// -// child_import->di_file = parent_import->di_file; -// child_import->block_context = new_block_context(child_import->root, nullptr); -// -// scan_decls(g, child_import, child_import->block_context, child_import->root); -// return resolve_expr_const_val_as_import(g, node, child_import); -//} -// //static TypeTableEntry *analyze_embed_file(CodeGen *g, ImportTableEntry *import, // BlockContext *context, AstNode *node) //{ @@ -7587,51 +7756,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { // return g->builtin_types.entry_invalid; // } // } -// case BuiltinFnIdCInclude: -// { -// if (!context->c_import_buf) { -// add_node_error(g, node, buf_sprintf("@c_include valid only in c_import blocks")); -// return g->builtin_types.entry_invalid; -// } -// -// AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field; -// TypeTableEntry *str_type = get_slice_type(g, g->builtin_types.entry_u8, true); -// TypeTableEntry *resolved_type = analyze_expression(g, import, context, str_type, *str_node); -// -// if (resolved_type->id == TypeTableEntryIdInvalid) { -// return resolved_type; -// } -// -// ConstExprValue *const_str_val = &get_resolved_expr(*str_node)->const_val; -// -// if (!const_str_val->ok) { -// add_node_error(g, *str_node, buf_sprintf("@c_include requires constant expression")); -// return g->builtin_types.entry_void; -// } -// -// buf_appendf(context->c_import_buf, "#include <"); -// ConstExprValue *ptr_field = const_str_val->data.x_struct.fields[0]; -// uint64_t len = ptr_field->data.x_ptr.len; -// for (uint64_t i = 0; i < len; i += 1) { -// ConstExprValue *char_val = ptr_field->data.x_ptr.ptr[i]; -// uint64_t big_c = char_val->data.x_bignum.data.x_uint; -// assert(big_c <= UINT8_MAX); -// uint8_t c = big_c; -// buf_append_char(context->c_import_buf, c); -// } -// buf_appendf(context->c_import_buf, ">\n"); -// -// return g->builtin_types.entry_void; -// } -// case BuiltinFnIdCDefine: -// zig_panic("TODO"); -// case BuiltinFnIdCUndef: -// zig_panic("TODO"); -// // case BuiltinFnIdImport: // return analyze_import(g, import, context, node); -// case BuiltinFnIdCImport: -// return analyze_c_import(g, import, context, node); // case BuiltinFnIdBreakpoint: // mark_impure_fn(g, context, node); // return g->builtin_types.entry_void; @@ -8121,9 +8247,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { // switch (builtin_fn->id) { // case BuiltinFnIdInvalid: // case BuiltinFnIdTypeof: -// case BuiltinFnIdCInclude: -// case BuiltinFnIdCDefine: -// case BuiltinFnIdCUndef: // case BuiltinFnIdImport: // case BuiltinFnIdCImport: // case BuiltinFnIdCompileErr: diff --git a/src/ir.hpp b/src/ir.hpp index c996e28d2f..d3445e3364 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); + FnTableEntry *fn_entry, Buf *c_import_buf); TypeTableEntry *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable, TypeTableEntry *expected_type, AstNode *expected_type_source_node); diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 28246cc0f8..738ec8cf4c 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -144,7 +144,11 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const case TypeTableEntryIdNamespace: { ImportTableEntry *import = const_val->data.x_import; - fprintf(irp->f, "(namespace: %s)", buf_ptr(import->path)); + if (import->c_import_node) { + fprintf(irp->f, "(namespace from C import)"); + } else { + fprintf(irp->f, "(namespace: %s)", buf_ptr(import->path)); + } return; } case TypeTableEntryIdBoundFn: @@ -685,6 +689,30 @@ static void ir_print_err_name(IrPrint *irp, IrInstructionErrName *instruction) { fprintf(irp->f, ")"); } +static void ir_print_c_import(IrPrint *irp, IrInstructionCImport *instruction) { + fprintf(irp->f, "@cImport(...)"); +} + +static void ir_print_c_include(IrPrint *irp, IrInstructionCInclude *instruction) { + fprintf(irp->f, "@cInclude("); + ir_print_other_instruction(irp, instruction->name); + fprintf(irp->f, ")"); +} + +static void ir_print_c_define(IrPrint *irp, IrInstructionCDefine *instruction) { + fprintf(irp->f, "@cDefine("); + ir_print_other_instruction(irp, instruction->name); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ")"); +} + +static void ir_print_c_undef(IrPrint *irp, IrInstructionCUndef *instruction) { + fprintf(irp->f, "@cUndef("); + ir_print_other_instruction(irp, instruction->name); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -834,6 +862,18 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdErrName: ir_print_err_name(irp, (IrInstructionErrName *)instruction); break; + case IrInstructionIdCImport: + ir_print_c_import(irp, (IrInstructionCImport *)instruction); + break; + case IrInstructionIdCInclude: + ir_print_c_include(irp, (IrInstructionCInclude *)instruction); + break; + case IrInstructionIdCDefine: + ir_print_c_define(irp, (IrInstructionCDefine *)instruction); + break; + case IrInstructionIdCUndef: + ir_print_c_undef(irp, (IrInstructionCUndef *)instruction); + break; } fprintf(irp->f, "\n"); } @@ -854,3 +894,67 @@ void ir_print(FILE *f, IrExecutable *executable, int indent_size) { } } } + +static void print_tld_var(IrPrint *irp, TldVar *tld_var) { + const char *const_or_var = tld_var->var->src_is_const ? "const" : "var"; + fprintf(irp->f, "%s %s", const_or_var, buf_ptr(tld_var->base.name)); + bool omit_type = (tld_var->var->type->id == TypeTableEntryIdNumLitFloat || + tld_var->var->type->id == TypeTableEntryIdNumLitInt); + if (!omit_type) { + fprintf(irp->f, ": %s", buf_ptr(&tld_var->var->type->name)); + } + if (tld_var->var->value) { + fprintf(irp->f, " = "); + ir_print_const_value(irp, tld_var->var->type, tld_var->var->value); + } + fprintf(irp->f, ";\n"); +} + +static void print_tld_fn(IrPrint *irp, TldFn *tld_fn) { + fprintf(irp->f, "// %s = TODO (function)\n", buf_ptr(tld_fn->base.name)); +} + +static void print_tld_container(IrPrint *irp, TldContainer *tld_container) { + fprintf(irp->f, "// %s = TODO (container)\n", buf_ptr(tld_container->base.name)); +} + +static void print_tld_typedef(IrPrint *irp, TldTypeDef *tld_typedef) { + fprintf(irp->f, "// %s = TODO (typedef)\n", buf_ptr(tld_typedef->base.name)); +} + +void ir_print_decls(FILE *f, ImportTableEntry *import) { + IrPrint ir_print = {}; + IrPrint *irp = &ir_print; + irp->f = f; + irp->indent = 0; + irp->indent_size = 2; + + auto it = import->decls_scope->decl_table.entry_iterator(); + for (;;) { + auto *entry = it.next(); + if (!entry) + break; + + Tld *tld = entry->value; + if (!buf_eql_buf(entry->key, tld->name)) { + fprintf(f, "// alias: %s = %s\n", buf_ptr(entry->key), buf_ptr(tld->name)); + continue; + } + + switch (tld->id) { + case TldIdVar: + print_tld_var(irp, (TldVar *)tld); + continue; + case TldIdFn: + print_tld_fn(irp, (TldFn *)tld); + continue; + case TldIdContainer: + print_tld_container(irp, (TldContainer *)tld); + continue; + case TldIdTypeDef: + print_tld_typedef(irp, (TldTypeDef *)tld); + continue; + } + zig_unreachable(); + } +} diff --git a/src/ir_print.hpp b/src/ir_print.hpp index 7126b1e57f..3510187476 100644 --- a/src/ir_print.hpp +++ b/src/ir_print.hpp @@ -14,4 +14,7 @@ void ir_print(FILE *f, IrExecutable *executable, int indent_size); +void ir_print_decls(FILE *f, ImportTableEntry *import); + + #endif diff --git a/src/parseh.cpp b/src/parseh.cpp index 4a72a0ee70..d22a1c3fd7 100644 --- a/src/parseh.cpp +++ b/src/parseh.cpp @@ -31,27 +31,28 @@ struct GlobalValue { bool is_const; }; +struct Alias { + Buf *name; + Tld *tld; +}; + struct Context { ImportTableEntry *import; ZigList *errors; bool warnings_on; VisibMod visib_mod; - AstNode *root; HashMap global_type_table; - HashMap global_value_table; HashMap struct_type_table; - HashMap struct_decl_table; HashMap enum_type_table; HashMap decl_table; - HashMap fn_table; - HashMap macro_table; + HashMap macro_table; SourceManager *source_manager; - ZigList aliases; + ZigList aliases; ZigList macro_symbols; AstNode *source_node; + uint32_t next_anon_index; CodeGen *codegen; - bool transform_extern_fn_ptr; }; static TypeTableEntry *resolve_qual_type_with_table(Context *c, QualType qt, const Decl *decl, @@ -88,235 +89,134 @@ static void emit_warning(Context *c, const Decl *decl, const char *format, ...) fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg)); } -static uint32_t get_next_node_index(Context *c) { - uint32_t result = c->codegen->next_node_index; - c->codegen->next_node_index += 1; +static uint32_t get_next_anon_index(Context *c) { + uint32_t result = c->next_anon_index; + c->next_anon_index += 1; return result; } -static AstNode *create_node(Context *c, NodeType type) { - AstNode *node = allocate(1); - node->type = type; - node->owner = c->import; - node->create_index = get_next_node_index(c); - return node; +static void add_global_alias(Context *c, Buf *name, Tld *tld) { + c->import->decls_scope->decl_table.put(name, tld); } -static AstNode *create_symbol_node(Context *c, const char *type_name) { - AstNode *node = create_node(c, NodeTypeSymbol); - node->data.symbol_expr.symbol = buf_create_from_str(type_name); - return node; +static void add_global_weak_alias(Context *c, Buf *name, Tld *tld) { + Alias *alias = c->aliases.add_one(); + alias->name = name; + alias->tld = tld; } -static AstNode *create_field_access_node(Context *c, const char *lhs, const char *rhs) { - AstNode *node = create_node(c, NodeTypeFieldAccessExpr); - node->data.field_access_expr.struct_expr = create_symbol_node(c, lhs); - node->data.field_access_expr.field_name = buf_create_from_str(rhs); - return node; +static void add_global(Context *c, Tld *tld) { + return add_global_alias(c, tld->name, tld); } -static AstNode *create_typed_var_decl_node(Context *c, bool is_const, const char *var_name, - AstNode *type_node, AstNode *init_node) -{ - AstNode *node = create_node(c, NodeTypeVariableDeclaration); - node->data.variable_declaration.symbol = buf_create_from_str(var_name); - node->data.variable_declaration.is_const = is_const; - node->data.variable_declaration.visib_mod = c->visib_mod; - node->data.variable_declaration.expr = init_node; - node->data.variable_declaration.type = type_node; - return node; +static Tld *get_global(Context *c, Buf *name) { + auto entry = c->import->decls_scope->decl_table.maybe_get(name); + return entry ? entry->value : nullptr; } -static AstNode *create_var_decl_node(Context *c, const char *var_name, AstNode *expr_node) { - return create_typed_var_decl_node(c, true, var_name, nullptr, expr_node); -} - -static AstNode *create_prefix_node(Context *c, PrefixOp op, AstNode *child_node) { - assert(child_node); - AstNode *node = create_node(c, NodeTypePrefixOpExpr); - node->data.prefix_op_expr.prefix_op = op; - node->data.prefix_op_expr.primary_expr = child_node; - return node; -} - -static AstNode *create_param_decl_node(Context *c, const char *name, AstNode *type_node, bool is_noalias) { - assert(type_node); - AstNode *node = create_node(c, NodeTypeParamDecl); - node->data.param_decl.name = buf_create_from_str(name); - node->data.param_decl.type = type_node; - node->data.param_decl.is_noalias = is_noalias; - - return node; -} - -static AstNode *create_char_lit_node(Context *c, uint8_t value) { - AstNode *node = create_node(c, NodeTypeCharLiteral); - node->data.char_literal.value = value; - return node; -} - -// accepts ownership of buf -static AstNode *create_str_lit_node(Context *c, Buf *buf) { - AstNode *node = create_node(c, NodeTypeStringLiteral); - node->data.string_literal.buf = buf; - node->data.string_literal.c = true; - return node; -} - -static AstNode *create_num_lit_float(Context *c, double x) { - AstNode *node = create_node(c, NodeTypeNumberLiteral); - node->data.number_literal.bignum = allocate_nonzero(1); - bignum_init_float(node->data.number_literal.bignum, x); - return node; -} - -static AstNode *create_num_lit_float_negative(Context *c, double x, bool negative) { - AstNode *num_lit_node = create_num_lit_float(c, x); - if (!negative) return num_lit_node; - return create_prefix_node(c, PrefixOpNegation, num_lit_node); -} - -static AstNode *create_num_lit_unsigned(Context *c, uint64_t x) { - AstNode *node = create_node(c, NodeTypeNumberLiteral); - node->data.number_literal.bignum = allocate_nonzero(1); - bignum_init_unsigned(node->data.number_literal.bignum, x); - return node; -} - -static AstNode *create_num_lit_unsigned_negative(Context *c, uint64_t x, bool negative) { - AstNode *num_lit_node = create_num_lit_unsigned(c, x); - if (!negative) return num_lit_node; - return create_prefix_node(c, PrefixOpNegation, num_lit_node); -} - -static AstNode *create_num_lit_signed(Context *c, int64_t x) { - if (x >= 0) { - return create_num_lit_unsigned(c, x); - } - BigNum bn_orig; - bignum_init_signed(&bn_orig, x); - - BigNum bn_negated; - bignum_negate(&bn_negated, &bn_orig); - - uint64_t uint = bignum_to_twos_complement(&bn_negated); - AstNode *num_lit_node = create_num_lit_unsigned(c, uint); - return create_prefix_node(c, PrefixOpNegation, num_lit_node); -} - -static AstNode *make_type_node(Context *c, TypeTableEntry *type_entry) { - zig_panic("TODO bypass AST in parseh"); -} - -static AstNode *create_fn_proto_node(Context *c, Buf *name, TypeTableEntry *fn_type) { - assert(fn_type->id == TypeTableEntryIdFn); - AstNode *node = create_node(c, NodeTypeFnProto); - node->data.fn_proto.is_inline = true; - node->data.fn_proto.visib_mod = c->visib_mod; - node->data.fn_proto.name = name; - node->data.fn_proto.return_type = make_type_node(c, fn_type->data.fn.fn_type_id.return_type); - - for (size_t i = 0; i < fn_type->data.fn.fn_type_id.param_count; i += 1) { - FnTypeParamInfo *info = &fn_type->data.fn.fn_type_id.param_info[i]; - char arg_name[20]; - sprintf(arg_name, "arg_%zu", i); - node->data.fn_proto.params.append(create_param_decl_node(c, arg_name, - make_type_node(c, info->type), info->is_noalias)); - } - - return node; -} - -static AstNode *create_one_statement_block(Context *c, AstNode *statement) { - AstNode *node = create_node(c, NodeTypeBlock); - node->data.block.statements.append(statement); - - return node; -} - -static AstNode *create_inline_fn_node(Context *c, Buf *fn_name, Buf *var_name, TypeTableEntry *fn_type) { - AstNode *node = create_node(c, NodeTypeFnDef); - node->data.fn_def.fn_proto = create_fn_proto_node(c, fn_name, fn_type); - - AstNode *unwrap_node = create_prefix_node(c, PrefixOpUnwrapMaybe, create_symbol_node(c, buf_ptr(var_name))); - - AstNode *fn_call_node = create_node(c, NodeTypeFnCallExpr); - fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node; - for (size_t i = 0; i < fn_type->data.fn.fn_type_id.param_count; i += 1) { - AstNode *decl_node = node->data.fn_def.fn_proto->data.fn_proto.params.at(i); - Buf *param_name = decl_node->data.param_decl.name; - fn_call_node->data.fn_call_expr.params.append(create_symbol_node(c, buf_ptr(param_name))); - } - - - node->data.fn_def.body = create_one_statement_block(c, fn_call_node); - - return node; -} - - - static const char *decl_name(const Decl *decl) { const NamedDecl *named_decl = static_cast(decl); return (const char *)named_decl->getName().bytes_begin(); } -static void add_typedef_node(Context *c, TypeTableEntry *type_decl) { - assert(type_decl); - assert(type_decl->id == TypeTableEntryIdTypeDecl); - - ScopeDecls *decls_scope = c->import->decls_scope; - TldTypeDef *tld_typedef = allocate(1); - init_tld(&tld_typedef->base, TldIdTypeDef, &type_decl->name, c->visib_mod, c->source_node, &decls_scope->base, nullptr); - tld_typedef->type_entry = type_decl; - - decls_scope->decl_table.put(&type_decl->name, &tld_typedef->base); - c->global_type_table.put(&type_decl->name, type_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); + tld->resolution = TldResolutionOk; } -static void add_const_var_node(Context *c, Buf *name, TypeTableEntry *type_entry) { - ScopeDecls *decls_scope = c->import->decls_scope; +static TldVar *create_global_var(Context *c, Buf *name, TypeTableEntry *var_type, ConstExprValue *var_value, bool is_const) { TldVar *tld_var = allocate(1); - init_tld(&tld_var->base, TldIdVar, name, c->visib_mod, c->source_node, &decls_scope->base, nullptr); - bool is_const = true; - ConstExprValue *init_value = allocate(1); - init_value->special = ConstValSpecialStatic; - init_value->data.x_type = type_entry; - tld_var->var = add_variable(c->codegen, c->source_node, &decls_scope->base, name, type_entry, is_const, init_value); - - decls_scope->decl_table.put(name, &tld_var->base); - c->global_type_table.put(name, type_entry); + parseh_init_tld(c, &tld_var->base, TldIdVar, name); + tld_var->var = add_variable(c->codegen, c->source_node, &c->import->decls_scope->base, name, var_type, is_const, var_value); + return tld_var; } -static void add_container_tld(Context *c, TypeTableEntry *type_entry) { - ScopeDecls *decls_scope = c->import->decls_scope; - TldContainer *tld_container = allocate(1); - init_tld(&tld_container->base, TldIdContainer, &type_entry->name, c->visib_mod, c->source_node, &decls_scope->base, nullptr); - tld_container->type_entry = type_entry; - - decls_scope->decl_table.put(&type_entry->name, &tld_container->base); +static Tld *create_global_char_lit_var(Context *c, Buf *name, uint8_t value) { + TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_u8, + create_const_unsigned_negative(value, false), true); + return &tld_var->base; } -static AstNode *create_ap_num_lit_node(Context *c, const Decl *source_decl, - const llvm::APSInt &aps_int) -{ +static Tld *create_global_str_lit_var(Context *c, Buf *name, Buf *value) { + TypeTableEntry *str_type = get_array_type(c->codegen, c->codegen->builtin_types.entry_u8, buf_len(value)); + TldVar *tld_var = create_global_var(c, name, str_type, create_const_str_lit(value), true); + return &tld_var->base; +} + +static Tld *create_global_num_lit_unsigned_negative(Context *c, Buf *name, uint64_t x, bool negative) { + TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_num_lit_int, + create_const_unsigned_negative(x, negative), true); + return &tld_var->base; +} + +static Tld *create_global_num_lit_float(Context *c, Buf *name, double value) { + TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_num_lit_float, + create_const_float(value), true); + return &tld_var->base; +} + +static ConstExprValue *create_const_num_lit_ap(Context *c, const Decl *source_decl, const llvm::APSInt &aps_int) { if (aps_int.isSigned()) { if (aps_int > INT64_MAX || aps_int < INT64_MIN) { emit_warning(c, source_decl, "integer overflow\n"); return nullptr; } else { - return create_num_lit_signed(c, aps_int.getExtValue()); + return create_const_signed(aps_int.getExtValue()); } } else { if (aps_int > INT64_MAX) { emit_warning(c, source_decl, "integer overflow\n"); return nullptr; } else { - return create_num_lit_unsigned(c, aps_int.getExtValue()); + return create_const_unsigned_negative(aps_int.getExtValue(), false); } } } +static Tld *create_global_num_lit_ap(Context *c, const Decl *source_decl, Buf *name, + const llvm::APSInt &aps_int) +{ + ConstExprValue *const_value = create_const_num_lit_ap(c, source_decl, aps_int); + if (!const_value) + return nullptr; + TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_num_lit_int, const_value, true); + return &tld_var->base; +} + + +static void 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; + TldVar *tld_var = create_global_var(c, name, c->codegen->builtin_types.entry_type, var_value, true); + add_global(c, &tld_var->base); + + c->global_type_table.put(name, type_entry); +} + +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; +} + +static Tld *add_typedef_tld(Context *c, TypeTableEntry *type_decl) { + assert(type_decl); + assert(type_decl->id == TypeTableEntryIdTypeDecl); + + TldTypeDef *tld_typedef = allocate(1); + parseh_init_tld(c, &tld_typedef->base, TldIdTypeDef, &type_decl->name); + tld_typedef->type_entry = type_decl; + + add_global(c, &tld_typedef->base); + c->global_type_table.put(&type_decl->name, type_decl); + + return &tld_typedef->base; +} + static bool is_c_void_type(Context *c, TypeTableEntry *type_entry) { while (type_entry->id == TypeTableEntryIdTypeDecl) { if (type_entry == c->codegen->builtin_types.entry_c_void) { @@ -702,7 +602,7 @@ static TypeTableEntry *resolve_qual_type(Context *c, QualType qt, const Decl *de static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { Buf *fn_name = buf_create_from_str(decl_name(fn_decl)); - if (c->fn_table.maybe_get(fn_name)) { + if (get_global(c, fn_name)) { // we already saw this function return; } @@ -715,36 +615,19 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { } assert(fn_type->id == TypeTableEntryIdFn); - - AstNode *node = create_node(c, NodeTypeFnProto); - node->data.fn_proto.name = fn_name; - - node->data.fn_proto.is_extern = fn_type->data.fn.fn_type_id.is_extern; - node->data.fn_proto.visib_mod = c->visib_mod; - node->data.fn_proto.is_var_args = fn_type->data.fn.fn_type_id.is_var_args; - node->data.fn_proto.return_type = make_type_node(c, fn_type->data.fn.fn_type_id.return_type); + bool internal_linkage = false; + FnTableEntry *fn_entry = create_fn_raw(FnInlineAuto, internal_linkage); + buf_init_from_buf(&fn_entry->symbol_name, fn_name); + fn_entry->type_entry = fn_type; assert(!fn_type->data.fn.fn_type_id.is_naked); - size_t arg_count = fn_type->data.fn.fn_type_id.param_count; - Buf name_buf = BUF_INIT; - for (size_t i = 0; i < arg_count; i += 1) { - FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[i]; - AstNode *type_node = make_type_node(c, param_info->type); - const ParmVarDecl *param = fn_decl->getParamDecl(i); - const char *name = decl_name(param); - if (strlen(name) == 0) { - buf_resize(&name_buf, 0); - buf_appendf(&name_buf, "arg%zu", i); - name = buf_ptr(&name_buf); - } + TldFn *tld_fn = allocate(1); + parseh_init_tld(c, &tld_fn->base, TldIdFn, fn_name); + tld_fn->fn_entry = fn_entry; + add_global(c, &tld_fn->base); - node->data.fn_proto.params.append(create_param_decl_node(c, name, type_node, param_info->is_noalias)); - } - - - c->fn_table.put(buf_create_from_buf(fn_name), true); - c->root->data.root.top_level_decls.append(node); + c->codegen->fn_protos.append(fn_entry); } static void visit_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) { @@ -775,18 +658,13 @@ static void visit_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) emit_warning(c, typedef_decl, "typedef %s - unresolved child type", buf_ptr(type_name)); return; } - add_const_var_node(c, type_name, child_type); -} - -static void add_alias(Context *c, const char *new_name, const char *target_name) { - AstNode *alias_node = create_var_decl_node(c, new_name, create_symbol_node(c, target_name)); - c->aliases.append(alias_node); + add_const_type(c, type_name, child_type); } static void replace_with_fwd_decl(Context *c, TypeTableEntry *struct_type, Buf *full_type_name) { unsigned line = c->source_node ? c->source_node->line : 0; ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugForwardDeclType(c->codegen->dbuilder, - ZigLLVMTag_DW_structure_type(), buf_ptr(full_type_name), + ZigLLVMTag_DW_structure_type(), buf_ptr(full_type_name), ZigLLVMFileToScope(c->import->di_file), c->import->di_file, line); ZigLLVMReplaceTemporary(c->codegen->dbuilder, struct_type->di_type, replacement_di_type); @@ -803,7 +681,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) Buf *bare_name; if (raw_name[0] == 0) { - bare_name = buf_sprintf("anon_$%" PRIu32, get_next_node_index(c)); + bare_name = buf_sprintf("anon_$%" PRIu32, get_next_anon_index(c)); } else { bare_name = buf_create_from_str(raw_name); } @@ -876,11 +754,7 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) // in C each enum value is in the global namespace. so we put them there too. // at this point we can rely on the enum emitting successfully - AstNode *field_access_node = create_field_access_node(c, buf_ptr(full_type_name), buf_ptr(field_name)); - AstNode *var_node = create_var_decl_node(c, buf_ptr(enum_val_name), field_access_node); - c->root->data.root.top_level_decls.append(var_node); - - c->global_value_table.put(enum_val_name, {enum_type, true}); + add_global(c, create_global_num_lit_unsigned_negative(c, enum_val_name, i, false)); } // create llvm type for root struct @@ -912,20 +786,14 @@ static TypeTableEntry *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) it != it_end; ++it) { const EnumConstantDecl *enum_const = *it; - AstNode *num_lit_node = create_ap_num_lit_node(c, enum_decl, enum_const->getInitVal()); - if (!num_lit_node) { - return c->codegen->builtin_types.entry_invalid; - } Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); - AstNode *type_node = make_type_node(c, enum_type); - AstNode *var_decl_node = create_typed_var_decl_node(c, true, buf_ptr(enum_val_name), - type_node, num_lit_node); - - c->root->data.root.top_level_decls.append(var_decl_node); - c->global_value_table.put(enum_val_name, {enum_type, true}); + Tld *tld = create_global_num_lit_ap(c, enum_decl, enum_val_name, enum_const->getInitVal()); + if (!tld) + return c->codegen->builtin_types.entry_invalid; + add_global(c, tld); } return enum_type; @@ -940,20 +808,25 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { // make an alias without the "enum_" prefix. this will get emitted at the // end if it doesn't conflict with anything else - if (decl_name(enum_decl)[0] != 0) { - add_alias(c, decl_name(enum_decl), buf_ptr(&enum_type->name)); - } + bool is_anonymous = (decl_name(enum_decl)[0] == 0); + if (is_anonymous) + return; + + Buf *bare_name = buf_create_from_str(decl_name(enum_decl)); if (enum_type->id == TypeTableEntryIdEnum) { if (enum_type->data.enumeration.complete) { - add_container_tld(c, enum_type); + Tld *tld = add_container_tld(c, enum_type); + add_global_weak_alias(c, bare_name, tld); } else { TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(&enum_type->name), c->codegen->builtin_types.entry_u8); - add_typedef_node(c, typedecl_type); + Tld *tld = add_typedef_tld(c, typedecl_type); + add_global_weak_alias(c, bare_name, tld); } } else if (enum_type->id == TypeTableEntryIdTypeDecl) { - add_typedef_node(c, enum_type); + Tld *tld = add_typedef_tld(c, enum_type); + add_global_weak_alias(c, bare_name, tld); } else { zig_unreachable(); } @@ -974,7 +847,7 @@ static TypeTableEntry *resolve_record_decl(Context *c, const RecordDecl *record_ Buf *bare_name; if (record_decl->isAnonymousStructOrUnion() || raw_name[0] == 0) { - bare_name = buf_sprintf("anon_$%" PRIu32, get_next_node_index(c)); + bare_name = buf_sprintf("anon_$%" PRIu32, get_next_anon_index(c)); } else { bare_name = buf_create_from_str(raw_name); } @@ -1096,23 +969,20 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) { assert(struct_type->id == TypeTableEntryIdStruct); - if (c->struct_decl_table.maybe_get(&struct_type->name)) { + bool is_anonymous = (record_decl->isAnonymousStructOrUnion() || decl_name(record_decl)[0] == 0); + if (is_anonymous) return; - } - c->struct_decl_table.put(&struct_type->name, struct_type); - // make an alias without the "struct_" prefix. this will get emitted at the - // end if it doesn't conflict with anything else - if (decl_name(record_decl)[0] != 0) { - add_alias(c, decl_name(record_decl), buf_ptr(&struct_type->name)); - } + Buf *bare_name = buf_create_from_str(decl_name(record_decl)); if (struct_type->data.structure.complete) { - add_container_tld(c, struct_type); + Tld *tld = add_container_tld(c, struct_type); + add_global_weak_alias(c, bare_name, tld); } else { TypeTableEntry *typedecl_type = get_typedecl_type(c->codegen, buf_ptr(&struct_type->name), c->codegen->builtin_types.entry_u8); - add_typedef_node(c, typedecl_type); + Tld *tld = add_typedef_tld(c, typedecl_type); + add_global_weak_alias(c, bare_name, tld); } } @@ -1151,7 +1021,7 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { emit_warning(c, var_decl, "ignoring variable '%s' - unable to evaluate initializer\n", buf_ptr(name)); return; } - AstNode *init_node = nullptr; + ConstExprValue *init_value = nullptr; switch (ap_value->getKind()) { case APValue::Int: { @@ -1161,10 +1031,10 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { "ignoring variable '%s' - int initializer for non int type\n", buf_ptr(name)); return; } - init_node = create_ap_num_lit_node(c, var_decl, ap_value->getInt()); - if (!init_node) { + init_value = create_const_num_lit_ap(c, var_decl, ap_value->getInt()); + if (!init_value) return; - } + break; } case APValue::Uninitialized: @@ -1183,19 +1053,15 @@ static void visit_var_decl(Context *c, const VarDecl *var_decl) { return; } - AstNode *type_node = make_type_node(c, var_type); - AstNode *var_node = create_typed_var_decl_node(c, true, buf_ptr(name), type_node, init_node); - c->root->data.root.top_level_decls.append(var_node); - c->global_value_table.put(name, {var_type, true}); + TldVar *tld_var = create_global_var(c, name, var_type, init_value, true); + add_global(c, &tld_var->base); return; } if (is_extern) { - AstNode *type_node = make_type_node(c, var_type); - AstNode *var_node = create_typed_var_decl_node(c, is_const, buf_ptr(name), type_node, nullptr); - var_node->data.variable_declaration.is_extern = true; - c->root->data.root.top_level_decls.append(var_node); - c->global_value_table.put(name, {var_type, is_const}); + TldVar *tld_var = create_global_var(c, name, var_type, nullptr, is_const); + tld_var->var->is_extern = true; + add_global(c, &tld_var->base); return; } @@ -1233,10 +1099,7 @@ static bool name_exists(Context *c, Buf *name) { if (c->global_type_table.maybe_get(name)) { return true; } - if (c->global_value_table.maybe_get(name)) { - return true; - } - if (c->fn_table.maybe_get(name)) { + if (get_global(c, name)) { return true; } if (c->macro_table.maybe_get(name)) { @@ -1245,31 +1108,13 @@ static bool name_exists(Context *c, Buf *name) { return false; } -static bool name_exists_and_const(Context *c, Buf *name) { - if (c->global_type_table.maybe_get(name)) { - return true; - } - if (c->fn_table.maybe_get(name)) { - return true; - } - if (c->macro_table.maybe_get(name)) { - return true; - } - if (auto entry = c->global_value_table.maybe_get(name)) { - return entry->value.is_const; - } - return false; -} - static void render_aliases(Context *c) { for (size_t i = 0; i < c->aliases.length; i += 1) { - AstNode *alias_node = c->aliases.at(i); - assert(alias_node->type == NodeTypeVariableDeclaration); - Buf *name = alias_node->data.variable_declaration.symbol; - if (name_exists(c, name)) { + Alias *alias = &c->aliases.at(i); + if (name_exists(c, alias->name)) continue; - } - c->root->data.root.top_level_decls.append(alias_node); + + add_global_alias(c, alias->name, alias->tld); } } @@ -1280,8 +1125,8 @@ static void render_macros(Context *c) { if (!entry) break; - AstNode *var_node = entry->value; - c->root->data.root.top_level_decls.append(var_node); + Tld *var_tld = entry->value; + add_global(c, var_tld); } } @@ -1300,30 +1145,27 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch switch (tok->id) { case CTokIdCharLit: if (is_last && is_first) { - AstNode *var_node = create_var_decl_node(c, buf_ptr(name), - create_char_lit_node(c, tok->data.char_lit)); - c->macro_table.put(name, var_node); + Tld *tld = create_global_char_lit_var(c, name, tok->data.char_lit); + c->macro_table.put(name, tld); } return; case CTokIdStrLit: if (is_last && is_first) { - AstNode *var_node = create_var_decl_node(c, buf_ptr(name), - create_str_lit_node(c, buf_create_from_buf(&tok->data.str_lit))); - c->macro_table.put(name, var_node); + Tld *tld = create_global_str_lit_var(c, name, buf_create_from_buf(&tok->data.str_lit)); + c->macro_table.put(name, tld); } return; case CTokIdNumLitInt: if (is_last) { - AstNode *var_node = create_var_decl_node(c, buf_ptr(name), - create_num_lit_unsigned_negative(c, tok->data.num_lit_int, negate)); - c->macro_table.put(name, var_node); + Tld *tld = create_global_num_lit_unsigned_negative(c, name, tok->data.num_lit_int, negate); + c->macro_table.put(name, tld); } return; case CTokIdNumLitFloat: if (is_last) { - AstNode *var_node = create_var_decl_node(c, buf_ptr(name), - create_num_lit_float_negative(c, tok->data.num_lit_float, negate)); - c->macro_table.put(name, var_node); + double value = negate ? -tok->data.num_lit_float : tok->data.num_lit_float; + Tld *tld = create_global_num_lit_float(c, name, value); + c->macro_table.put(name, tld); } return; case CTokIdSymbol: @@ -1351,22 +1193,31 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch static void process_symbol_macros(Context *c) { for (size_t i = 0; i < c->macro_symbols.length; i += 1) { MacroSymbol ms = c->macro_symbols.at(i); - if (name_exists_and_const(c, ms.value)) { - AstNode *var_node = create_var_decl_node(c, buf_ptr(ms.name), - create_symbol_node(c, buf_ptr(ms.value))); - c->macro_table.put(ms.name, var_node); - } else if (c->transform_extern_fn_ptr || true) { // TODO take off the || true - if (auto entry = c->global_value_table.maybe_get(ms.value)) { - TypeTableEntry *maybe_type = entry->value.type; - if (maybe_type->id == TypeTableEntryIdMaybe) { - TypeTableEntry *fn_type = maybe_type->data.maybe.child_type; - if (fn_type->id == TypeTableEntryIdFn) { - AstNode *fn_node = create_inline_fn_node(c, ms.name, ms.value, fn_type); - c->macro_table.put(ms.name, fn_node); - } + + // If this macro aliases another top level declaration, we can make that happen by + // putting another entry in the decl table pointing to the same top level decl. + Tld *existing_tld = get_global(c, ms.value); + if (!existing_tld) + continue; + + // If a macro aliases a global variable which is a function pointer, we conclude that + // the macro is intended to represent a function that assumes the function pointer + // variable is non-null and calls it. + if (existing_tld->id == TldIdVar) { + TldVar *tld_var = (TldVar *)existing_tld; + TypeTableEntry *var_type = tld_var->var->type; + if (var_type->id == TypeTableEntryIdMaybe && !tld_var->var->src_is_const) { + TypeTableEntry *child_type = var_type->data.maybe.child_type; + if (child_type->id == TypeTableEntryIdFn) { + zig_panic("TODO"); + //Tld *fn_tld = create_inline_fn_alias(c, ms.name, tld_var->var); + //c->macro_table.put(ms.name, fn_tld); + continue; } } } + + add_global_alias(c, ms.value, existing_tld); } } @@ -1430,12 +1281,9 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch c->errors = errors; c->visib_mod = VisibModPub; c->global_type_table.init(8); - c->global_value_table.init(8); c->enum_type_table.init(8); c->struct_type_table.init(8); - c->struct_decl_table.init(8); c->decl_table.init(8); - c->fn_table.init(8); c->macro_table.init(8); c->codegen = codegen; c->source_node = source_node; @@ -1521,7 +1369,7 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch err_unit = std::move(ast_unit); } - for (ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(), + for (ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(), it_end = err_unit->stored_diag_end(); it != it_end; ++it) { @@ -1561,7 +1409,6 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch c->source_manager = &ast_unit->getSourceManager(); - c->root = create_node(c, NodeTypeRoot); ast_unit->visitLocalTopLevelDecls(c, decl_visitor); process_preprocessor_entities(c, *ast_unit); @@ -1571,7 +1418,5 @@ int parse_h_file(ImportTableEntry *import, ZigList *errors, const ch render_macros(c); render_aliases(c); - import->root = c->root; - return 0; }