IR: fix implementation of parseh
libc hello world works now
This commit is contained in:
parent
3cfbec3eef
commit
2dd85d52cc
@ -53,6 +53,7 @@ struct IrExecutable {
|
||||
ZigList<IrGotoItem> 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,
|
||||
|
100
src/analyze.cpp
100
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<ScopeDecls>(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<ScopeCImport>(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<FnTableEntry>(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<FnTableEntry>(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<ConstExprValue>(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<ConstExprValue>(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<ConstExprValue>(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<ConstExprValue>(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<ConstExprValue>(1);
|
||||
init_const_float(const_val, value);
|
||||
return const_val;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -870,3 +870,4 @@ void ast_render(FILE *f, AstNode *node, int indent_size) {
|
||||
|
||||
render_node_grouped(&ar, node);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
369
src/ir.cpp
369
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<ConstExprValue>(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<IrInstructionConst>(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<IrInstructionCImport>(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<IrInstructionCInclude>(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<IrInstructionCDefine>(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<IrInstructionCUndef>(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<AstNode *>(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<ImportTableEntry>(1);
|
||||
child_import->decls_scope = create_decls_scope(child_import->root, nullptr, nullptr, child_import);
|
||||
child_import->c_import_node = node;
|
||||
|
||||
ZigList<ErrorMsg *> 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<ImportTableEntry>(1);
|
||||
// child_import->c_import_node = node;
|
||||
//
|
||||
// ZigList<ErrorMsg *> 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:
|
||||
|
@ -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);
|
||||
|
106
src/ir_print.cpp
106
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();
|
||||
}
|
||||
}
|
||||
|
@ -14,4 +14,7 @@
|
||||
|
||||
void ir_print(FILE *f, IrExecutable *executable, int indent_size);
|
||||
|
||||
void ir_print_decls(FILE *f, ImportTableEntry *import);
|
||||
|
||||
|
||||
#endif
|
||||
|
521
src/parseh.cpp
521
src/parseh.cpp
@ -31,27 +31,28 @@ struct GlobalValue {
|
||||
bool is_const;
|
||||
};
|
||||
|
||||
struct Alias {
|
||||
Buf *name;
|
||||
Tld *tld;
|
||||
};
|
||||
|
||||
struct Context {
|
||||
ImportTableEntry *import;
|
||||
ZigList<ErrorMsg *> *errors;
|
||||
bool warnings_on;
|
||||
VisibMod visib_mod;
|
||||
AstNode *root;
|
||||
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> global_type_table;
|
||||
HashMap<Buf *, GlobalValue, buf_hash, buf_eql_buf> global_value_table;
|
||||
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> struct_type_table;
|
||||
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> struct_decl_table;
|
||||
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> enum_type_table;
|
||||
HashMap<const void *, TypeTableEntry *, ptr_hash, ptr_eq> decl_table;
|
||||
HashMap<Buf *, bool, buf_hash, buf_eql_buf> fn_table;
|
||||
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table;
|
||||
HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> macro_table;
|
||||
SourceManager *source_manager;
|
||||
ZigList<AstNode *> aliases;
|
||||
ZigList<Alias> aliases;
|
||||
ZigList<MacroSymbol> 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<AstNode>(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<BigNum>(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<BigNum>(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<const NamedDecl *>(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<TldTypeDef>(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<TldVar>(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<ConstExprValue>(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<TldContainer>(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<ConstExprValue>(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<TldContainer>(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<TldTypeDef>(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<TldFn>(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<ErrorMsg *> *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<ErrorMsg *> *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<ErrorMsg *> *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<ErrorMsg *> *errors, const ch
|
||||
render_macros(c);
|
||||
render_aliases(c);
|
||||
|
||||
import->root = c->root;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user