parseh handles self referential structs and fn pointers
This commit is contained in:
parent
a5c2de5fee
commit
c3516b8004
@ -509,7 +509,8 @@ static void render_node(AstRender *ar, AstNode *node) {
|
|||||||
|
|
||||||
if (child->type == NodeTypeImport ||
|
if (child->type == NodeTypeImport ||
|
||||||
child->type == NodeTypeVariableDeclaration ||
|
child->type == NodeTypeVariableDeclaration ||
|
||||||
child->type == NodeTypeErrorValueDecl)
|
child->type == NodeTypeErrorValueDecl ||
|
||||||
|
child->type == NodeTypeFnProto)
|
||||||
{
|
{
|
||||||
fprintf(ar->f, ";");
|
fprintf(ar->f, ";");
|
||||||
}
|
}
|
||||||
@ -530,8 +531,10 @@ static void render_node(AstRender *ar, AstNode *node) {
|
|||||||
AstNode *param_decl = node->data.fn_proto.params.at(arg_i);
|
AstNode *param_decl = node->data.fn_proto.params.at(arg_i);
|
||||||
assert(param_decl->type == NodeTypeParamDecl);
|
assert(param_decl->type == NodeTypeParamDecl);
|
||||||
const char *arg_name = buf_ptr(¶m_decl->data.param_decl.name);
|
const char *arg_name = buf_ptr(¶m_decl->data.param_decl.name);
|
||||||
const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : "";
|
if (buf_len(¶m_decl->data.param_decl.name) > 0) {
|
||||||
fprintf(ar->f, "%s%s: ", noalias_str, arg_name);
|
const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : "";
|
||||||
|
fprintf(ar->f, "%s%s: ", noalias_str, arg_name);
|
||||||
|
}
|
||||||
render_node(ar, param_decl->data.param_decl.type);
|
render_node(ar, param_decl->data.param_decl.type);
|
||||||
|
|
||||||
if (arg_i + 1 < arg_count || is_var_args) {
|
if (arg_i + 1 < arg_count || is_var_args) {
|
||||||
@ -548,7 +551,6 @@ static void render_node(AstRender *ar, AstNode *node) {
|
|||||||
fprintf(ar->f, " -> ");
|
fprintf(ar->f, " -> ");
|
||||||
render_node(ar, return_type_node);
|
render_node(ar, return_type_node);
|
||||||
}
|
}
|
||||||
fprintf(ar->f, ";");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NodeTypeFnDef:
|
case NodeTypeFnDef:
|
||||||
|
@ -121,6 +121,17 @@ static AstNode *create_struct_field_node(Context *c, const char *name, AstNode *
|
|||||||
return 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);
|
||||||
|
buf_init_from_str(&node->data.param_decl.name, name);
|
||||||
|
node->data.param_decl.type = type_node;
|
||||||
|
node->data.param_decl.is_noalias = is_noalias;
|
||||||
|
|
||||||
|
normalize_parent_ptrs(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
static AstNode *create_num_lit_unsigned(Context *c, uint64_t x) {
|
static AstNode *create_num_lit_unsigned(Context *c, uint64_t x) {
|
||||||
AstNode *node = create_node(c, NodeTypeNumberLiteral);
|
AstNode *node = create_node(c, NodeTypeNumberLiteral);
|
||||||
node->data.number_literal.kind = NumLitUInt;
|
node->data.number_literal.kind = NumLitUInt;
|
||||||
@ -255,6 +266,12 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl,
|
|||||||
const PointerType *pointer_ty = static_cast<const PointerType*>(ty);
|
const PointerType *pointer_ty = static_cast<const PointerType*>(ty);
|
||||||
QualType child_qt = pointer_ty->getPointeeType();
|
QualType child_qt = pointer_ty->getPointeeType();
|
||||||
AstNode *type_node = make_qual_type_node(c, child_qt, decl);
|
AstNode *type_node = make_qual_type_node(c, child_qt, decl);
|
||||||
|
if (child_qt.getTypePtr()->getTypeClass() == Type::Paren) {
|
||||||
|
const ParenType *paren_type = static_cast<const ParenType *>(child_qt.getTypePtr());
|
||||||
|
if (paren_type->getInnerType()->getTypeClass() == Type::FunctionProto) {
|
||||||
|
return create_prefix_node(c, PrefixOpMaybe, type_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
return pointer_to_type(c, type_node, child_qt.isConstQualified());
|
return pointer_to_type(c, type_node, child_qt.isConstQualified());
|
||||||
}
|
}
|
||||||
case Type::Typedef:
|
case Type::Typedef:
|
||||||
@ -311,8 +328,32 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case Type::FunctionProto:
|
case Type::FunctionProto:
|
||||||
emit_warning(c, decl, "ignoring function type");
|
{
|
||||||
return nullptr;
|
const FunctionProtoType *fn_proto_ty = static_cast<const FunctionProtoType*>(ty);
|
||||||
|
AstNode *node = create_node(c, NodeTypeFnProto);
|
||||||
|
buf_resize(&node->data.fn_proto.name, 0);
|
||||||
|
node->data.fn_proto.is_extern = true;
|
||||||
|
node->data.fn_proto.is_var_args = fn_proto_ty->isVariadic();
|
||||||
|
node->data.fn_proto.return_type = make_qual_type_node(c, fn_proto_ty->getReturnType(), decl);
|
||||||
|
|
||||||
|
if (!node->data.fn_proto.return_type) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arg_count = fn_proto_ty->getNumParams();
|
||||||
|
for (int i = 0; i < arg_count; i += 1) {
|
||||||
|
QualType qt = fn_proto_ty->getParamType(i);
|
||||||
|
bool is_noalias = qt.isRestrictQualified();
|
||||||
|
AstNode *type_node = make_qual_type_node(c, qt, decl);
|
||||||
|
if (!type_node) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
node->data.fn_proto.params.append(create_param_decl_node(c, "", type_node, is_noalias));
|
||||||
|
}
|
||||||
|
|
||||||
|
normalize_parent_ptrs(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
case Type::Record:
|
case Type::Record:
|
||||||
{
|
{
|
||||||
const RecordType *record_ty = static_cast<const RecordType*>(ty);
|
const RecordType *record_ty = static_cast<const RecordType*>(ty);
|
||||||
@ -356,6 +397,11 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl,
|
|||||||
uint64_t size = const_arr_ty->getSize().getLimitedValue();
|
uint64_t size = const_arr_ty->getSize().getLimitedValue();
|
||||||
return create_array_type_node(c, child_type_node, size, false);
|
return create_array_type_node(c, child_type_node, size, false);
|
||||||
}
|
}
|
||||||
|
case Type::Paren:
|
||||||
|
{
|
||||||
|
const ParenType *paren_ty = static_cast<const ParenType *>(ty);
|
||||||
|
return make_qual_type_node(c, paren_ty->getInnerType(), decl);
|
||||||
|
}
|
||||||
case Type::BlockPointer:
|
case Type::BlockPointer:
|
||||||
case Type::LValueReference:
|
case Type::LValueReference:
|
||||||
case Type::RValueReference:
|
case Type::RValueReference:
|
||||||
@ -368,7 +414,6 @@ static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl,
|
|||||||
case Type::ExtVector:
|
case Type::ExtVector:
|
||||||
case Type::FunctionNoProto:
|
case Type::FunctionNoProto:
|
||||||
case Type::UnresolvedUsing:
|
case Type::UnresolvedUsing:
|
||||||
case Type::Paren:
|
|
||||||
case Type::Adjusted:
|
case Type::Adjusted:
|
||||||
case Type::Decayed:
|
case Type::Decayed:
|
||||||
case Type::TypeOfExpr:
|
case Type::TypeOfExpr:
|
||||||
@ -423,23 +468,19 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
|
|||||||
int arg_count = fn_decl->getNumParams();
|
int arg_count = fn_decl->getNumParams();
|
||||||
for (int i = 0; i < arg_count; i += 1) {
|
for (int i = 0; i < arg_count; i += 1) {
|
||||||
const ParmVarDecl *param = fn_decl->getParamDecl(i);
|
const ParmVarDecl *param = fn_decl->getParamDecl(i);
|
||||||
AstNode *param_decl_node = create_node(c, NodeTypeParamDecl);
|
|
||||||
const char *name = decl_name(param);
|
const char *name = decl_name(param);
|
||||||
if (strlen(name) == 0) {
|
if (strlen(name) == 0) {
|
||||||
name = buf_ptr(buf_sprintf("arg%d", i));
|
name = buf_ptr(buf_sprintf("arg%d", i));
|
||||||
}
|
}
|
||||||
buf_init_from_str(¶m_decl_node->data.param_decl.name, name);
|
|
||||||
QualType qt = param->getOriginalType();
|
QualType qt = param->getOriginalType();
|
||||||
param_decl_node->data.param_decl.is_noalias = qt.isRestrictQualified();
|
bool is_noalias = qt.isRestrictQualified();
|
||||||
param_decl_node->data.param_decl.type = make_qual_type_node(c, qt, fn_decl);
|
AstNode *type_node = make_qual_type_node(c, qt, fn_decl);
|
||||||
if (!param_decl_node->data.param_decl.type) {
|
if (!type_node) {
|
||||||
emit_warning(c, param, "skipping function %s, unresolved param type\n",
|
emit_warning(c, param, "skipping function %s, unresolved param type\n", name);
|
||||||
buf_ptr(&node->data.fn_proto.name));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
normalize_parent_ptrs(param_decl_node);
|
node->data.fn_proto.params.append(create_param_decl_node(c, name, type_node, is_noalias));
|
||||||
node->data.fn_proto.params.append(param_decl_node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fn_decl->isNoReturn()) {
|
if (fn_decl->isNoReturn()) {
|
||||||
@ -512,6 +553,11 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
|
|||||||
node->data.struct_decl.visib_mod = VisibModExport;
|
node->data.struct_decl.visib_mod = VisibModExport;
|
||||||
node->data.struct_decl.directives = create_empty_directives(c);
|
node->data.struct_decl.directives = create_empty_directives(c);
|
||||||
|
|
||||||
|
// eagerly put the name in the table, but we need to remember to remove it if it fails
|
||||||
|
// boy it would be nice to have defer here wouldn't it
|
||||||
|
c->enum_type_table.put(bare_name, true);
|
||||||
|
|
||||||
|
|
||||||
ZigList<AstNode *> var_decls = {0};
|
ZigList<AstNode *> var_decls = {0};
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto it = enum_def->enumerator_begin(),
|
for (auto it = enum_def->enumerator_begin(),
|
||||||
@ -520,6 +566,7 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
|
|||||||
{
|
{
|
||||||
const EnumConstantDecl *enum_const = *it;
|
const EnumConstantDecl *enum_const = *it;
|
||||||
if (enum_const->getInitExpr()) {
|
if (enum_const->getInitExpr()) {
|
||||||
|
c->enum_type_table.remove(bare_name);
|
||||||
emit_warning(c, enum_const, "skipping enum %s - has init expression\n", buf_ptr(bare_name));
|
emit_warning(c, enum_const, "skipping enum %s - has init expression\n", buf_ptr(bare_name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -549,8 +596,6 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
|
|||||||
var_decls.append(var_node);
|
var_decls.append(var_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
c->enum_type_table.put(bare_name, true);
|
|
||||||
|
|
||||||
normalize_parent_ptrs(node);
|
normalize_parent_ptrs(node);
|
||||||
c->root->data.root.top_level_decls.append(node);
|
c->root->data.root.top_level_decls.append(node);
|
||||||
|
|
||||||
@ -594,6 +639,10 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
|
|||||||
node->data.struct_decl.visib_mod = VisibModExport;
|
node->data.struct_decl.visib_mod = VisibModExport;
|
||||||
node->data.struct_decl.directives = create_empty_directives(c);
|
node->data.struct_decl.directives = create_empty_directives(c);
|
||||||
|
|
||||||
|
// eagerly put the name in the table, but we need to remember to remove it if it fails
|
||||||
|
// boy it would be nice to have defer here wouldn't it
|
||||||
|
c->struct_type_table.put(bare_name, true);
|
||||||
|
|
||||||
for (auto it = record_def->field_begin(),
|
for (auto it = record_def->field_begin(),
|
||||||
it_end = record_def->field_end();
|
it_end = record_def->field_end();
|
||||||
it != it_end; ++it)
|
it != it_end; ++it)
|
||||||
@ -601,12 +650,14 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
|
|||||||
const FieldDecl *field_decl = *it;
|
const FieldDecl *field_decl = *it;
|
||||||
|
|
||||||
if (field_decl->isBitField()) {
|
if (field_decl->isBitField()) {
|
||||||
|
c->struct_type_table.remove(bare_name);
|
||||||
emit_warning(c, field_decl, "skipping struct %s - has bitfield\n", buf_ptr(bare_name));
|
emit_warning(c, field_decl, "skipping struct %s - has bitfield\n", buf_ptr(bare_name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode *type_node = make_qual_type_node(c, field_decl->getType(), field_decl);
|
AstNode *type_node = make_qual_type_node(c, field_decl->getType(), field_decl);
|
||||||
if (!type_node) {
|
if (!type_node) {
|
||||||
|
c->struct_type_table.remove(bare_name);
|
||||||
emit_warning(c, field_decl, "skipping struct %s - unhandled type\n", buf_ptr(bare_name));
|
emit_warning(c, field_decl, "skipping struct %s - unhandled type\n", buf_ptr(bare_name));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -615,7 +666,6 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
|
|||||||
node->data.struct_decl.fields.append(field_node);
|
node->data.struct_decl.fields.append(field_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
c->struct_type_table.put(bare_name, true);
|
|
||||||
normalize_parent_ptrs(node);
|
normalize_parent_ptrs(node);
|
||||||
c->root->data.root.top_level_decls.append(node);
|
c->root->data.root.top_level_decls.append(node);
|
||||||
|
|
||||||
|
@ -1961,6 +1961,15 @@ pub const Bar = enum_Bar;)OUTPUT");
|
|||||||
add_parseh_case("constant size array", R"SOURCE(
|
add_parseh_case("constant size array", R"SOURCE(
|
||||||
void func(int array[20]);
|
void func(int array[20]);
|
||||||
)SOURCE", R"OUTPUT(pub extern fn func(array: [20]c_int);)OUTPUT");
|
)SOURCE", R"OUTPUT(pub extern fn func(array: [20]c_int);)OUTPUT");
|
||||||
|
|
||||||
|
add_parseh_case("self referential struct with function pointer", R"SOURCE(
|
||||||
|
struct Foo {
|
||||||
|
void (*derp)(struct Foo *foo);
|
||||||
|
};
|
||||||
|
)SOURCE", R"OUTPUT(export struct struct_Foo {
|
||||||
|
derp: ?extern fn (?&struct_Foo),
|
||||||
|
}
|
||||||
|
pub const Foo = struct_Foo;)OUTPUT");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_compiler_invocation(TestCase *test_case) {
|
static void print_compiler_invocation(TestCase *test_case) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user