| ... | ... | @@ -11,6 +11,7 @@ |
| 11 | 11 | #include "error.hpp" |
| 12 | 12 | #include "parser.hpp" |
| 13 | 13 | #include "all_types.hpp" |
| 14 | #include "tokenizer.hpp" |
| 14 | 15 | |
| 15 | 16 | #include <clang/Frontend/ASTUnit.h> |
| 16 | 17 | #include <clang/Frontend/CompilerInstance.h> |
| ... | ... | @@ -24,11 +25,12 @@ struct Context { |
| 24 | 25 | ZigList<ErrorMsg *> *errors; |
| 25 | 26 | bool warnings_on; |
| 26 | 27 | VisibMod visib_mod; |
| 27 | | AstNode *c_void_decl_node; |
| 28 | bool have_c_void_decl_node; |
| 28 | 29 | AstNode *root; |
| 29 | 30 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> type_table; |
| 30 | 31 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> fn_table; |
| 31 | 32 | SourceManager *source_manager; |
| 33 | ZigList<AstNode *> aliases; |
| 32 | 34 | }; |
| 33 | 35 | |
| 34 | 36 | __attribute__ ((format (printf, 3, 4))) |
| ... | ... | @@ -57,7 +59,7 @@ static void emit_warning(Context *c, const Decl *decl, const char *format, ...) |
| 57 | 59 | fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg)); |
| 58 | 60 | } |
| 59 | 61 | |
| 60 | | static AstNode *make_qual_type_node(Context *c, QualType qt, Decl *decl); |
| 62 | static AstNode *make_qual_type_node(Context *c, QualType qt, const Decl *decl); |
| 61 | 63 | |
| 62 | 64 | static AstNode *create_node(Context *c, NodeType type) { |
| 63 | 65 | AstNode *node = allocate<AstNode>(1); |
| ... | ... | @@ -66,33 +68,48 @@ static AstNode *create_node(Context *c, NodeType type) { |
| 66 | 68 | return node; |
| 67 | 69 | } |
| 68 | 70 | |
| 69 | | static AstNode *simple_type_node(Context *c, const char *type_name) { |
| 71 | static AstNode *create_symbol_node(Context *c, const char *type_name) { |
| 70 | 72 | AstNode *node = create_node(c, NodeTypeSymbol); |
| 71 | 73 | buf_init_from_str(&node->data.symbol_expr.symbol, type_name); |
| 72 | 74 | return node; |
| 73 | 75 | } |
| 74 | 76 | |
| 75 | | static const char *decl_name(const Decl *decl) { |
| 76 | | const NamedDecl *named_decl = static_cast<const NamedDecl *>(decl); |
| 77 | | return (const char *)named_decl->getName().bytes_begin(); |
| 77 | static AstNode *create_field_access_node(Context *c, const char *lhs, const char *rhs) { |
| 78 | AstNode *node = create_node(c, NodeTypeFieldAccessExpr); |
| 79 | node->data.field_access_expr.struct_expr = create_symbol_node(c, lhs); |
| 80 | buf_init_from_str(&node->data.field_access_expr.field_name, rhs); |
| 81 | normalize_parent_ptrs(node); |
| 82 | return node; |
| 78 | 83 | } |
| 79 | 84 | |
| 80 | 85 | static ZigList<AstNode *> *create_empty_directives(Context *c) { |
| 81 | 86 | return allocate<ZigList<AstNode*>>(1); |
| 82 | 87 | } |
| 83 | 88 | |
| 84 | | static AstNode *create_typedef_node(Context *c, Buf *new_name, AstNode *target_node) { |
| 85 | | if (!target_node) { |
| 86 | | return nullptr; |
| 87 | | } |
| 89 | static AstNode *create_var_decl_node(Context *c, const char *var_name, AstNode *expr_node) { |
| 88 | 90 | AstNode *node = create_node(c, NodeTypeVariableDeclaration); |
| 89 | | buf_init_from_buf(&node->data.variable_declaration.symbol, new_name); |
| 91 | buf_init_from_str(&node->data.variable_declaration.symbol, var_name); |
| 90 | 92 | node->data.variable_declaration.is_const = true; |
| 91 | 93 | node->data.variable_declaration.visib_mod = c->visib_mod; |
| 92 | | node->data.variable_declaration.expr = target_node; |
| 94 | node->data.variable_declaration.expr = expr_node; |
| 93 | 95 | node->data.variable_declaration.directives = create_empty_directives(c); |
| 94 | 96 | normalize_parent_ptrs(node); |
| 97 | return node; |
| 98 | } |
| 99 | |
| 100 | static const char *decl_name(const Decl *decl) { |
| 101 | const NamedDecl *named_decl = static_cast<const NamedDecl *>(decl); |
| 102 | return (const char *)named_decl->getName().bytes_begin(); |
| 103 | } |
| 104 | |
| 95 | 105 | |
| 106 | static AstNode *add_typedef_node(Context *c, Buf *new_name, AstNode *target_node) { |
| 107 | if (!target_node) { |
| 108 | return nullptr; |
| 109 | } |
| 110 | AstNode *node = create_var_decl_node(c, buf_ptr(new_name), target_node); |
| 111 | |
| 112 | c->type_table.put(new_name, true); |
| 96 | 113 | c->root->data.root.top_level_decls.append(node); |
| 97 | 114 | return node; |
| 98 | 115 | } |
| ... | ... | @@ -101,12 +118,11 @@ static AstNode *convert_to_c_void(Context *c, AstNode *type_node) { |
| 101 | 118 | if (type_node->type == NodeTypeSymbol && |
| 102 | 119 | buf_eql_str(&type_node->data.symbol_expr.symbol, "void")) |
| 103 | 120 | { |
| 104 | | if (!c->c_void_decl_node) { |
| 105 | | c->c_void_decl_node = create_typedef_node(c, buf_create_from_str("c_void"), |
| 106 | | simple_type_node(c, "u8")); |
| 107 | | assert(c->c_void_decl_node); |
| 121 | if (!c->have_c_void_decl_node) { |
| 122 | add_typedef_node(c, buf_create_from_str("c_void"), create_symbol_node(c, "u8")); |
| 123 | c->have_c_void_decl_node = true; |
| 108 | 124 | } |
| 109 | | return simple_type_node(c, "c_void"); |
| 125 | return create_symbol_node(c, "c_void"); |
| 110 | 126 | } else { |
| 111 | 127 | return type_node; |
| 112 | 128 | } |
| ... | ... | @@ -123,42 +139,42 @@ static AstNode *pointer_to_type(Context *c, AstNode *type_node, bool is_const) { |
| 123 | 139 | return node; |
| 124 | 140 | } |
| 125 | 141 | |
| 126 | | static AstNode *make_type_node(Context *c, const Type *ty, Decl *decl) { |
| 142 | static AstNode *make_type_node(Context *c, const Type *ty, const Decl *decl) { |
| 127 | 143 | switch (ty->getTypeClass()) { |
| 128 | 144 | case Type::Builtin: |
| 129 | 145 | { |
| 130 | 146 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty); |
| 131 | 147 | switch (builtin_ty->getKind()) { |
| 132 | 148 | case BuiltinType::Void: |
| 133 | | return simple_type_node(c, "void"); |
| 149 | return create_symbol_node(c, "void"); |
| 134 | 150 | case BuiltinType::Bool: |
| 135 | | return simple_type_node(c, "bool"); |
| 151 | return create_symbol_node(c, "bool"); |
| 136 | 152 | case BuiltinType::Char_U: |
| 137 | 153 | case BuiltinType::UChar: |
| 138 | 154 | case BuiltinType::Char_S: |
| 139 | | return simple_type_node(c, "u8"); |
| 155 | return create_symbol_node(c, "u8"); |
| 140 | 156 | case BuiltinType::SChar: |
| 141 | | return simple_type_node(c, "i8"); |
| 157 | return create_symbol_node(c, "i8"); |
| 142 | 158 | case BuiltinType::UShort: |
| 143 | | return simple_type_node(c, "c_ushort"); |
| 159 | return create_symbol_node(c, "c_ushort"); |
| 144 | 160 | case BuiltinType::UInt: |
| 145 | | return simple_type_node(c, "c_uint"); |
| 161 | return create_symbol_node(c, "c_uint"); |
| 146 | 162 | case BuiltinType::ULong: |
| 147 | | return simple_type_node(c, "c_ulong"); |
| 163 | return create_symbol_node(c, "c_ulong"); |
| 148 | 164 | case BuiltinType::ULongLong: |
| 149 | | return simple_type_node(c, "c_ulonglong"); |
| 165 | return create_symbol_node(c, "c_ulonglong"); |
| 150 | 166 | case BuiltinType::Short: |
| 151 | | return simple_type_node(c, "c_short"); |
| 167 | return create_symbol_node(c, "c_short"); |
| 152 | 168 | case BuiltinType::Int: |
| 153 | | return simple_type_node(c, "c_int"); |
| 169 | return create_symbol_node(c, "c_int"); |
| 154 | 170 | case BuiltinType::Long: |
| 155 | | return simple_type_node(c, "c_long"); |
| 171 | return create_symbol_node(c, "c_long"); |
| 156 | 172 | case BuiltinType::LongLong: |
| 157 | | return simple_type_node(c, "c_longlong"); |
| 173 | return create_symbol_node(c, "c_longlong"); |
| 158 | 174 | case BuiltinType::Float: |
| 159 | | return simple_type_node(c, "f32"); |
| 175 | return create_symbol_node(c, "f32"); |
| 160 | 176 | case BuiltinType::Double: |
| 161 | | return simple_type_node(c, "f64"); |
| 177 | return create_symbol_node(c, "f64"); |
| 162 | 178 | case BuiltinType::LongDouble: |
| 163 | 179 | case BuiltinType::WChar_U: |
| 164 | 180 | case BuiltinType::Char16: |
| ... | ... | @@ -204,29 +220,29 @@ static AstNode *make_type_node(Context *c, const Type *ty, Decl *decl) { |
| 204 | 220 | const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); |
| 205 | 221 | Buf *type_name = buf_create_from_str(decl_name(typedef_decl)); |
| 206 | 222 | if (buf_eql_str(type_name, "uint8_t")) { |
| 207 | | return simple_type_node(c, "u8"); |
| 223 | return create_symbol_node(c, "u8"); |
| 208 | 224 | } else if (buf_eql_str(type_name, "int8_t")) { |
| 209 | | return simple_type_node(c, "i8"); |
| 225 | return create_symbol_node(c, "i8"); |
| 210 | 226 | } else if (buf_eql_str(type_name, "uint16_t")) { |
| 211 | | return simple_type_node(c, "u16"); |
| 227 | return create_symbol_node(c, "u16"); |
| 212 | 228 | } else if (buf_eql_str(type_name, "int16_t")) { |
| 213 | | return simple_type_node(c, "i16"); |
| 229 | return create_symbol_node(c, "i16"); |
| 214 | 230 | } else if (buf_eql_str(type_name, "uint32_t")) { |
| 215 | | return simple_type_node(c, "u32"); |
| 231 | return create_symbol_node(c, "u32"); |
| 216 | 232 | } else if (buf_eql_str(type_name, "int32_t")) { |
| 217 | | return simple_type_node(c, "i32"); |
| 233 | return create_symbol_node(c, "i32"); |
| 218 | 234 | } else if (buf_eql_str(type_name, "uint64_t")) { |
| 219 | | return simple_type_node(c, "u64"); |
| 235 | return create_symbol_node(c, "u64"); |
| 220 | 236 | } else if (buf_eql_str(type_name, "int64_t")) { |
| 221 | | return simple_type_node(c, "i64"); |
| 237 | return create_symbol_node(c, "i64"); |
| 222 | 238 | } else if (buf_eql_str(type_name, "intptr_t")) { |
| 223 | | return simple_type_node(c, "isize"); |
| 239 | return create_symbol_node(c, "isize"); |
| 224 | 240 | } else if (buf_eql_str(type_name, "uintptr_t")) { |
| 225 | | return simple_type_node(c, "usize"); |
| 241 | return create_symbol_node(c, "usize"); |
| 226 | 242 | } else { |
| 227 | 243 | auto entry = c->type_table.maybe_get(type_name); |
| 228 | 244 | if (entry) { |
| 229 | | return simple_type_node(c, buf_ptr(type_name)); |
| 245 | return create_symbol_node(c, buf_ptr(type_name)); |
| 230 | 246 | } else { |
| 231 | 247 | return nullptr; |
| 232 | 248 | } |
| ... | ... | @@ -280,7 +296,7 @@ static AstNode *make_type_node(Context *c, const Type *ty, Decl *decl) { |
| 280 | 296 | } |
| 281 | 297 | } |
| 282 | 298 | |
| 283 | | static AstNode *make_qual_type_node(Context *c, QualType qt, Decl *decl) { |
| 299 | static AstNode *make_qual_type_node(Context *c, QualType qt, const Decl *decl) { |
| 284 | 300 | return make_type_node(c, qt.getTypePtr(), decl); |
| 285 | 301 | } |
| 286 | 302 | |
| ... | ... | @@ -311,7 +327,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { |
| 311 | 327 | buf_init_from_str(&param_decl_node->data.param_decl.name, name); |
| 312 | 328 | QualType qt = param->getOriginalType(); |
| 313 | 329 | param_decl_node->data.param_decl.is_noalias = qt.isRestrictQualified(); |
| 314 | | param_decl_node->data.param_decl.type = make_qual_type_node(c, qt, (Decl*)fn_decl); |
| 330 | param_decl_node->data.param_decl.type = make_qual_type_node(c, qt, fn_decl); |
| 315 | 331 | if (!param_decl_node->data.param_decl.type) { |
| 316 | 332 | all_ok = false; |
| 317 | 333 | break; |
| ... | ... | @@ -322,9 +338,9 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { |
| 322 | 338 | } |
| 323 | 339 | |
| 324 | 340 | if (fn_decl->isNoReturn()) { |
| 325 | | node->data.fn_proto.return_type = simple_type_node(c, "unreachable"); |
| 341 | node->data.fn_proto.return_type = create_symbol_node(c, "unreachable"); |
| 326 | 342 | } else { |
| 327 | | node->data.fn_proto.return_type = make_qual_type_node(c, fn_decl->getReturnType(), (Decl*)fn_decl); |
| 343 | node->data.fn_proto.return_type = make_qual_type_node(c, fn_decl->getReturnType(), fn_decl); |
| 328 | 344 | } |
| 329 | 345 | |
| 330 | 346 | if (!node->data.fn_proto.return_type) { |
| ... | ... | @@ -332,7 +348,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { |
| 332 | 348 | } |
| 333 | 349 | if (!all_ok) { |
| 334 | 350 | // not all the types could be resolved, so we give up on the function decl |
| 335 | | emit_warning(c, (Decl*)fn_decl, "skipping function %s\n", buf_ptr(&node->data.fn_proto.name)); |
| 351 | emit_warning(c, fn_decl, "skipping function %s\n", buf_ptr(&node->data.fn_proto.name)); |
| 336 | 352 | return; |
| 337 | 353 | } |
| 338 | 354 | |
| ... | ... | @@ -361,12 +377,92 @@ static void visit_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) |
| 361 | 377 | return; |
| 362 | 378 | } |
| 363 | 379 | |
| 364 | | AstNode *node = create_typedef_node(c, type_name, make_qual_type_node(c, child_qt, (Decl*)typedef_decl)); |
| 380 | add_typedef_node(c, type_name, make_qual_type_node(c, child_qt, typedef_decl)); |
| 381 | } |
| 382 | |
| 383 | static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) { |
| 384 | Buf bare_name = BUF_INIT; |
| 385 | buf_init_from_str(&bare_name, decl_name(enum_decl)); |
| 386 | |
| 387 | Buf *type_name = buf_alloc(); |
| 388 | buf_appendf(type_name, "enum_%s", buf_ptr(&bare_name)); |
| 389 | |
| 390 | if (c->type_table.maybe_get(type_name)) { |
| 391 | // we've already seen it |
| 392 | return; |
| 393 | } |
| 394 | |
| 395 | const EnumDecl *enum_def = enum_decl->getDefinition(); |
| 396 | |
| 397 | if (!enum_def) { |
| 398 | // this is a type that we can point to but that's it, same as `struct Foo;`. |
| 399 | add_typedef_node(c, type_name, create_symbol_node(c, "u8")); |
| 400 | return; |
| 401 | } |
| 402 | |
| 403 | AstNode *node = create_node(c, NodeTypeStructDecl); |
| 404 | buf_init_from_buf(&node->data.struct_decl.name, type_name); |
| 405 | |
| 406 | node->data.struct_decl.kind = ContainerKindEnum; |
| 407 | node->data.struct_decl.visib_mod = c->visib_mod; |
| 408 | node->data.struct_decl.directives = create_empty_directives(c); |
| 409 | |
| 410 | ZigList<AstNode *> var_decls = {0}; |
| 411 | int i = 0; |
| 412 | for (auto it = enum_def->enumerator_begin(), |
| 413 | it_end = enum_def->enumerator_end(); |
| 414 | it != it_end; ++it, i += 1) |
| 415 | { |
| 416 | const EnumConstantDecl *enum_const = *it; |
| 417 | if (enum_const->getInitExpr()) { |
| 418 | emit_warning(c, enum_const, "skipping enum %s - has init expression\n", buf_ptr(type_name)); |
| 419 | return; |
| 420 | } |
| 421 | AstNode *field_node = create_node(c, NodeTypeStructField); |
| 422 | Buf enum_val_name = BUF_INIT; |
| 423 | buf_init_from_str(&enum_val_name, decl_name(enum_const)); |
| 424 | |
| 425 | if (buf_starts_with_buf(&enum_val_name, &bare_name)) { |
| 426 | Buf *slice = buf_slice(&enum_val_name, buf_len(&bare_name), buf_len(&enum_val_name)); |
| 427 | if (valid_symbol_starter(buf_ptr(slice)[0])) { |
| 428 | buf_init_from_buf(&field_node->data.struct_field.name, slice); |
| 429 | } else { |
| 430 | buf_resize(&field_node->data.struct_field.name, 0); |
| 431 | buf_appendf(&field_node->data.struct_field.name, "_%s", buf_ptr(slice)); |
| 432 | } |
| 433 | } else { |
| 434 | buf_init_from_buf(&field_node->data.struct_field.name, &enum_val_name); |
| 435 | } |
| 436 | |
| 437 | field_node->data.struct_field.directives = create_empty_directives(c); |
| 438 | field_node->data.struct_field.visib_mod = VisibModPub; |
| 439 | field_node->data.struct_field.type = create_symbol_node(c, "void"); |
| 440 | |
| 441 | normalize_parent_ptrs(field_node); |
| 442 | node->data.struct_decl.fields.append(field_node); |
| 443 | |
| 444 | // in C each enum value is in the global namespace. so we put them there too. |
| 445 | AstNode *field_access_node = create_field_access_node(c, buf_ptr(type_name), |
| 446 | buf_ptr(&field_node->data.struct_field.name)); |
| 447 | AstNode *var_node = create_var_decl_node(c, buf_ptr(&enum_val_name), field_access_node); |
| 448 | var_decls.append(var_node); |
| 449 | } |
| 450 | |
| 451 | c->type_table.put(type_name, true); |
| 365 | 452 | |
| 366 | | if (node) { |
| 367 | | normalize_parent_ptrs(node); |
| 368 | | c->type_table.put(type_name, true); |
| 453 | normalize_parent_ptrs(node); |
| 454 | c->root->data.root.top_level_decls.append(node); |
| 455 | |
| 456 | for (int i = 0; i < var_decls.length; i += 1) { |
| 457 | AstNode *var_node = var_decls.at(i); |
| 458 | c->root->data.root.top_level_decls.append(var_node); |
| 369 | 459 | } |
| 460 | |
| 461 | // make an alias without the "enum_" prefix. this will get emitted at the |
| 462 | // end if it doesn't conflict with anything else |
| 463 | AstNode *alias_node = create_var_decl_node(c, buf_ptr(&bare_name), create_symbol_node(c, buf_ptr(type_name))); |
| 464 | c->aliases.append(alias_node); |
| 465 | |
| 370 | 466 | } |
| 371 | 467 | |
| 372 | 468 | static bool decl_visitor(void *context, const Decl *decl) { |
| ... | ... | @@ -379,6 +475,9 @@ static bool decl_visitor(void *context, const Decl *decl) { |
| 379 | 475 | case Decl::Typedef: |
| 380 | 476 | visit_typedef_decl(c, static_cast<const TypedefNameDecl *>(decl)); |
| 381 | 477 | break; |
| 478 | case Decl::Enum: |
| 479 | visit_enum_decl(c, static_cast<const EnumDecl *>(decl)); |
| 480 | break; |
| 382 | 481 | default: |
| 383 | 482 | emit_warning(c, decl, "ignoring %s decl\n", decl->getDeclKindName()); |
| 384 | 483 | } |
| ... | ... | @@ -386,6 +485,21 @@ static bool decl_visitor(void *context, const Decl *decl) { |
| 386 | 485 | return true; |
| 387 | 486 | } |
| 388 | 487 | |
| 488 | static void render_aliases(Context *c) { |
| 489 | for (int i = 0; i < c->aliases.length; i += 1) { |
| 490 | AstNode *alias_node = c->aliases.at(i); |
| 491 | assert(alias_node->type == NodeTypeVariableDeclaration); |
| 492 | Buf *name = &alias_node->data.variable_declaration.symbol; |
| 493 | if (c->type_table.maybe_get(name)) { |
| 494 | continue; |
| 495 | } |
| 496 | if (c->fn_table.maybe_get(name)) { |
| 497 | continue; |
| 498 | } |
| 499 | c->root->data.root.top_level_decls.append(alias_node); |
| 500 | } |
| 501 | } |
| 502 | |
| 389 | 503 | int parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source, |
| 390 | 504 | const char **args, int args_len, const char *libc_include_path, bool warnings_on) |
| 391 | 505 | { |
| ... | ... | @@ -514,8 +628,10 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, |
| 514 | 628 | |
| 515 | 629 | c->root = create_node(c, NodeTypeRoot); |
| 516 | 630 | ast_unit->visitLocalTopLevelDecls(c, decl_visitor); |
| 517 | | normalize_parent_ptrs(c->root); |
| 518 | 631 | |
| 632 | render_aliases(c); |
| 633 | |
| 634 | normalize_parent_ptrs(c->root); |
| 519 | 635 | import->root = c->root; |
| 520 | 636 | |
| 521 | 637 | return 0; |