| author | |
| committer | |
| log | 0278468479d52d6ea64521ab78574b593a6832ae |
| tree | d7438d5c45de76b453efa7d3fab5a33ea27db347 |
| parent | ac085a869d068ca60548ad5298682ff054e91141 |
c_import creates a tmp .h file and parses it with libclang,
reporting any errors found.
See #8816 files changed, 373 insertions(+), 684 deletions(-)
CMakeLists.txt+2-2| ... | @@ -17,7 +17,7 @@ include_directories(${LLVM_INCLUDE_DIRS}) | ... | @@ -17,7 +17,7 @@ include_directories(${LLVM_INCLUDE_DIRS}) |
| 17 | link_directories(${LLVM_LIBDIRS}) | 17 | link_directories(${LLVM_LIBDIRS}) |
| 18 | 18 | ||
| 19 | find_package(clang) | 19 | find_package(clang) |
| 20 | include_directories(${CLANG_INCLUDE_DIR}) | 20 | include_directories(${CLANG_INCLUDE_DIRS}) |
| 21 | 21 | ||
| 22 | include_directories( | 22 | include_directories( |
| 23 | ${CMAKE_SOURCE_DIR} | 23 | ${CMAKE_SOURCE_DIR} |
| ... | @@ -148,7 +148,7 @@ set_target_properties(zig PROPERTIES | ... | @@ -148,7 +148,7 @@ set_target_properties(zig PROPERTIES |
| 148 | COMPILE_FLAGS ${EXE_CFLAGS}) | 148 | COMPILE_FLAGS ${EXE_CFLAGS}) |
| 149 | target_link_libraries(zig LINK_PUBLIC | 149 | target_link_libraries(zig LINK_PUBLIC |
| 150 | ${LLVM_LIBRARIES} | 150 | ${LLVM_LIBRARIES} |
| 151 | ${CLANG_LIBRARY} | 151 | ${CLANG_LIBRARIES} |
| 152 | ) | 152 | ) |
| 153 | install(TARGETS zig DESTINATION bin) | 153 | install(TARGETS zig DESTINATION bin) |
| 154 | 154 |
README.md+1-1| ... | @@ -75,7 +75,7 @@ be set to (example below). | ... | @@ -75,7 +75,7 @@ be set to (example below). |
| 75 | ``` | 75 | ``` |
| 76 | mkdir build | 76 | mkdir build |
| 77 | cd build | 77 | cd build |
| 78 | cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_DIR=$(dirname $(cc -print-file-name=crt1.o)) | 78 | cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_DIR=$(dirname $(dirname $(cc -print-file-name=crt1.o))) |
| 79 | make | 79 | make |
| 80 | make install | 80 | make install |
| 81 | ./run_tests | 81 | ./run_tests |
cmake/Findclang.cmake+25-7| ... | @@ -1,16 +1,34 @@ | ... | @@ -1,16 +1,34 @@ |
| 1 | # Copyright (c) 2015 Andrew Kelley | 1 | # Copyright (c) 2016 Andrew Kelley |
| 2 | # This file is MIT licensed. | 2 | # This file is MIT licensed. |
| 3 | # See http://opensource.org/licenses/MIT | 3 | # See http://opensource.org/licenses/MIT |
| 4 | 4 | ||
| 5 | # CLANG_FOUND | 5 | # CLANG_FOUND |
| 6 | # CLANG_INCLUDE_DIR | 6 | # CLANG_INCLUDE_DIRS |
| 7 | # CLANG_LIBRARY | 7 | # CLANG_LIBRARIES |
| 8 | 8 | ||
| 9 | find_path(CLANG_INCLUDE_DIR NAMES clang-c/Index.h PATHS /usr/lib/llvm-3.7/include/) | 9 | find_path(CLANG_INCLUDE_DIRS NAMES clang/Frontend/ASTUnit.h) |
| 10 | 10 | ||
| 11 | find_library(CLANG_LIBRARY NAMES clang PATHS /usr/lib/llvm-3.7/lib/) | 11 | macro(FIND_AND_ADD_CLANG_LIB _libname_) |
| 12 | string(TOUPPER ${_libname_} _prettylibname_) | ||
| 13 | find_library(CLANG_${_prettylibname_}_LIB NAMES ${_libname_}) | ||
| 14 | if(CLANG_${_prettylibname_}_LIB) | ||
| 15 | set(CLANG_LIBRARIES ${CLANG_LIBRARIES} ${CLANG_${_prettylibname_}_LIB}) | ||
| 16 | endif() | ||
| 17 | endmacro(FIND_AND_ADD_CLANG_LIB) | ||
| 18 | |||
| 19 | FIND_AND_ADD_CLANG_LIB(clangFrontend) | ||
| 20 | FIND_AND_ADD_CLANG_LIB(clangDriver) | ||
| 21 | FIND_AND_ADD_CLANG_LIB(clangSerialization) | ||
| 22 | FIND_AND_ADD_CLANG_LIB(clangSema) | ||
| 23 | FIND_AND_ADD_CLANG_LIB(clangAnalysis) | ||
| 24 | FIND_AND_ADD_CLANG_LIB(clangAST) | ||
| 25 | FIND_AND_ADD_CLANG_LIB(clangParse) | ||
| 26 | FIND_AND_ADD_CLANG_LIB(clangSema) | ||
| 27 | FIND_AND_ADD_CLANG_LIB(clangBasic) | ||
| 28 | FIND_AND_ADD_CLANG_LIB(clangEdit) | ||
| 29 | FIND_AND_ADD_CLANG_LIB(clangLex) | ||
| 12 | 30 | ||
| 13 | include(FindPackageHandleStandardArgs) | 31 | include(FindPackageHandleStandardArgs) |
| 14 | find_package_handle_standard_args(CLANG DEFAULT_MSG CLANG_LIBRARY CLANG_INCLUDE_DIR) | 32 | find_package_handle_standard_args(CLANG DEFAULT_MSG CLANG_LIBRARIES CLANG_INCLUDE_DIRS) |
| 15 | 33 | ||
| 16 | mark_as_advanced(CLANG_INCLUDE_DIR CLANG_LIBRARY) | 34 | mark_as_advanced(CLANG_INCLUDE_DIRS CLANG_LIBRARIES) |
src/all_types.hpp+10| ... | @@ -995,6 +995,8 @@ struct CodeGen { | ... | @@ -995,6 +995,8 @@ struct CodeGen { |
| 995 | bool have_exported_main; | 995 | bool have_exported_main; |
| 996 | bool link_libc; | 996 | bool link_libc; |
| 997 | Buf *libc_path; | 997 | Buf *libc_path; |
| 998 | Buf *libc_lib_path; | ||
| 999 | Buf *libc_include_path; | ||
| 998 | CodeGenBuildType build_type; | 1000 | CodeGenBuildType build_type; |
| 999 | LLVMTargetMachineRef target_machine; | 1001 | LLVMTargetMachineRef target_machine; |
| 1000 | LLVMZigDIFile *dummy_di_file; | 1002 | LLVMZigDIFile *dummy_di_file; |
| ... | @@ -1068,4 +1070,12 @@ struct BlockContext { | ... | @@ -1068,4 +1070,12 @@ struct BlockContext { |
| 1068 | Buf *c_import_buf; | 1070 | Buf *c_import_buf; |
| 1069 | }; | 1071 | }; |
| 1070 | 1072 | ||
| 1073 | struct ParseH { | ||
| 1074 | ZigList<ErrorMsg*> errors; | ||
| 1075 | ZigList<AstNode *> fn_list; | ||
| 1076 | ZigList<AstNode *> struct_list; | ||
| 1077 | ZigList<AstNode *> var_list; | ||
| 1078 | ZigList<AstNode *> incomplete_struct_list; | ||
| 1079 | }; | ||
| 1080 | |||
| 1071 | #endif | 1081 | #endif |
src/analyze.cpp+43-14| ... | @@ -10,6 +10,8 @@ | ... | @@ -10,6 +10,8 @@ |
| 10 | #include "error.hpp" | 10 | #include "error.hpp" |
| 11 | #include "zig_llvm.hpp" | 11 | #include "zig_llvm.hpp" |
| 12 | #include "os.hpp" | 12 | #include "os.hpp" |
| 13 | #include "parseh.hpp" | ||
| 14 | #include "config.h" | ||
| 13 | 15 | ||
| 14 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 16 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 15 | TypeTableEntry *expected_type, AstNode *node); | 17 | TypeTableEntry *expected_type, AstNode *node); |
| ... | @@ -83,18 +85,12 @@ static AstNode *first_executing_node(AstNode *node) { | ... | @@ -83,18 +85,12 @@ static AstNode *first_executing_node(AstNode *node) { |
| 83 | zig_unreachable(); | 85 | zig_unreachable(); |
| 84 | } | 86 | } |
| 85 | 87 | ||
| 86 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg) { | 88 | ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { |
| 87 | ErrorMsg *err = allocate<ErrorMsg>(1); | 89 | ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column, |
| 88 | err->line_start = node->line; | 90 | node->owner->source_code, node->owner->line_offsets, msg); |
| 89 | err->column_start = node->column; | ||
| 90 | err->line_end = -1; | ||
| 91 | err->column_end = -1; | ||
| 92 | err->msg = msg; | ||
| 93 | err->path = node->owner->path; | ||
| 94 | err->source = node->owner->source_code; | ||
| 95 | err->line_offsets = node->owner->line_offsets; | ||
| 96 | 91 | ||
| 97 | g->errors.append(err); | 92 | g->errors.append(err); |
| 93 | return err; | ||
| 98 | } | 94 | } |
| 99 | 95 | ||
| 100 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id) { | 96 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id) { |
| ... | @@ -1036,8 +1032,22 @@ static void resolve_c_import_decl(CodeGen *g, ImportTableEntry *import, AstNode | ... | @@ -1036,8 +1032,22 @@ static void resolve_c_import_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 1036 | return; | 1032 | return; |
| 1037 | } | 1033 | } |
| 1038 | 1034 | ||
| 1039 | fprintf(stderr, "c import buf:\n%s\n", buf_ptr(child_context->c_import_buf)); | 1035 | find_libc_path(g); |
| 1040 | zig_panic("TODO"); | 1036 | int err; |
| 1037 | ParseH parse_h = {{0}}; | ||
| 1038 | if ((err = parse_h_buf(&parse_h, child_context->c_import_buf, buf_ptr(g->libc_include_path)))) { | ||
| 1039 | zig_panic("unable to parse h file: %s\n", err_str(err)); | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | if (parse_h.errors.length > 0) { | ||
| 1043 | ErrorMsg *parent_err_msg = add_node_error(g, node, buf_sprintf("C import failed")); | ||
| 1044 | for (int i = 0; i < parse_h.errors.length; i += 1) { | ||
| 1045 | ErrorMsg *err_msg = parse_h.errors.at(i); | ||
| 1046 | err_msg_add_note(parent_err_msg, err_msg); | ||
| 1047 | } | ||
| 1048 | } else { | ||
| 1049 | zig_panic("TODO integrate the parsed AST"); | ||
| 1050 | } | ||
| 1041 | } | 1051 | } |
| 1042 | 1052 | ||
| 1043 | static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) { | 1053 | static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| ... | @@ -3444,7 +3454,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry | ... | @@ -3444,7 +3454,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 3444 | return g->builtin_types.entry_void; | 3454 | return g->builtin_types.entry_void; |
| 3445 | } | 3455 | } |
| 3446 | 3456 | ||
| 3447 | buf_appendf(context->c_import_buf, "#include \""); | 3457 | buf_appendf(context->c_import_buf, "#include <"); |
| 3448 | ConstExprValue *ptr_field = const_str_val->data.x_struct.fields[0]; | 3458 | ConstExprValue *ptr_field = const_str_val->data.x_struct.fields[0]; |
| 3449 | uint64_t len = ptr_field->data.x_ptr.len; | 3459 | uint64_t len = ptr_field->data.x_ptr.len; |
| 3450 | for (uint64_t i = 0; i < len; i += 1) { | 3460 | for (uint64_t i = 0; i < len; i += 1) { |
| ... | @@ -3454,7 +3464,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry | ... | @@ -3454,7 +3464,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry |
| 3454 | uint8_t c = big_c; | 3464 | uint8_t c = big_c; |
| 3455 | buf_appendf(context->c_import_buf, "%c", c); | 3465 | buf_appendf(context->c_import_buf, "%c", c); |
| 3456 | } | 3466 | } |
| 3457 | buf_appendf(context->c_import_buf, "\"\n"); | 3467 | buf_appendf(context->c_import_buf, ">\n"); |
| 3458 | 3468 | ||
| 3459 | return g->builtin_types.entry_void; | 3469 | return g->builtin_types.entry_void; |
| 3460 | } | 3470 | } |
| ... | @@ -4976,3 +4986,22 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { | ... | @@ -4976,3 +4986,22 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { |
| 4976 | } | 4986 | } |
| 4977 | zig_unreachable(); | 4987 | zig_unreachable(); |
| 4978 | } | 4988 | } |
| 4989 | |||
| 4990 | void find_libc_path(CodeGen *g) { | ||
| 4991 | if (!g->libc_path || buf_len(g->libc_path) == 0) { | ||
| 4992 | g->libc_path = buf_create_from_str(ZIG_LIBC_DIR); | ||
| 4993 | if (!g->libc_path || buf_len(g->libc_path) == 0) { | ||
| 4994 | // later we can handle this better by reporting an error via the normal mechanism | ||
| 4995 | zig_panic("Unable to determine libc path. You can use `--libc-path`"); | ||
| 4996 | } | ||
| 4997 | } | ||
| 4998 | if (!g->libc_lib_path) { | ||
| 4999 | g->libc_lib_path = buf_alloc(); | ||
| 5000 | os_path_join(g->libc_path, buf_create_from_str("lib"), g->libc_lib_path); | ||
| 5001 | } | ||
| 5002 | if (!g->libc_include_path) { | ||
| 5003 | g->libc_include_path = buf_alloc(); | ||
| 5004 | os_path_join(g->libc_path, buf_create_from_str("include"), g->libc_include_path); | ||
| 5005 | } | ||
| 5006 | } | ||
| 5007 |
src/analyze.hpp+3-1| ... | @@ -11,7 +11,7 @@ | ... | @@ -11,7 +11,7 @@ |
| 11 | #include "all_types.hpp" | 11 | #include "all_types.hpp" |
| 12 | 12 | ||
| 13 | void semantic_analyze(CodeGen *g); | 13 | void semantic_analyze(CodeGen *g); |
| 14 | void add_node_error(CodeGen *g, AstNode *node, Buf *msg); | 14 | ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg); |
| 15 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id); | 15 | TypeTableEntry *new_type_table_entry(TypeTableEntryId id); |
| 16 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); | 16 | TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const); |
| 17 | VariableTableEntry *find_variable(BlockContext *context, Buf *name); | 17 | VariableTableEntry *find_variable(BlockContext *context, Buf *name); |
| ... | @@ -23,4 +23,6 @@ bool is_node_void_expr(AstNode *node); | ... | @@ -23,4 +23,6 @@ bool is_node_void_expr(AstNode *node); |
| 23 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits); | 23 | TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits); |
| 24 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits); | 24 | TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits); |
| 25 | bool handle_is_ptr(TypeTableEntry *type_entry); | 25 | bool handle_is_ptr(TypeTableEntry *type_entry); |
| 26 | void find_libc_path(CodeGen *g); | ||
| 27 | |||
| 26 | #endif | 28 | #endif |
src/codegen.cpp+3-20| ... | @@ -3051,15 +3051,8 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path, | ... | @@ -3051,15 +3051,8 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path, |
| 3051 | tokenize(source_code, &tokenization); | 3051 | tokenize(source_code, &tokenization); |
| 3052 | 3052 | ||
| 3053 | if (tokenization.err) { | 3053 | if (tokenization.err) { |
| 3054 | ErrorMsg *err = allocate<ErrorMsg>(1); | 3054 | ErrorMsg *err = err_msg_create_with_line(full_path, tokenization.err_line, tokenization.err_column, |
| 3055 | err->line_start = tokenization.err_line; | 3055 | source_code, tokenization.line_offsets, tokenization.err); |
| 3056 | err->column_start = tokenization.err_column; | ||
| 3057 | err->line_end = -1; | ||
| 3058 | err->column_end = -1; | ||
| 3059 | err->msg = tokenization.err; | ||
| 3060 | err->path = full_path; | ||
| 3061 | err->source = source_code; | ||
| 3062 | err->line_offsets = tokenization.line_offsets; | ||
| 3063 | 3056 | ||
| 3064 | print_err_msg(err, g->err_color); | 3057 | print_err_msg(err, g->err_color); |
| 3065 | exit(1); | 3058 | exit(1); |
| ... | @@ -3401,19 +3394,9 @@ static void generate_h_file(CodeGen *g) { | ... | @@ -3401,19 +3394,9 @@ static void generate_h_file(CodeGen *g) { |
| 3401 | zig_panic("unable to close h file: %s", strerror(errno)); | 3394 | zig_panic("unable to close h file: %s", strerror(errno)); |
| 3402 | } | 3395 | } |
| 3403 | 3396 | ||
| 3404 | static void find_libc_path(CodeGen *g) { | ||
| 3405 | if (g->libc_path && buf_len(g->libc_path)) | ||
| 3406 | return; | ||
| 3407 | g->libc_path = buf_create_from_str(ZIG_LIBC_DIR); | ||
| 3408 | if (g->libc_path && buf_len(g->libc_path)) | ||
| 3409 | return; | ||
| 3410 | fprintf(stderr, "Unable to determine libc path. Consider using `--libc-path [path]`\n"); | ||
| 3411 | exit(1); | ||
| 3412 | } | ||
| 3413 | |||
| 3414 | static const char *get_libc_file(CodeGen *g, const char *file) { | 3397 | static const char *get_libc_file(CodeGen *g, const char *file) { |
| 3415 | Buf *out_buf = buf_alloc(); | 3398 | Buf *out_buf = buf_alloc(); |
| 3416 | os_path_join(g->libc_path, buf_create_from_str(file), out_buf); | 3399 | os_path_join(g->libc_lib_path, buf_create_from_str(file), out_buf); |
| 3417 | return buf_ptr(out_buf); | 3400 | return buf_ptr(out_buf); |
| 3418 | } | 3401 | } |
| 3419 | 3402 |
src/errmsg.cpp+58-10| ... | @@ -15,16 +15,7 @@ void print_err_msg(ErrorMsg *err, ErrColor color) { | ... | @@ -15,16 +15,7 @@ void print_err_msg(ErrorMsg *err, ErrColor color) { |
| 15 | err->line_start + 1, err->column_start + 1, | 15 | err->line_start + 1, err->column_start + 1, |
| 16 | buf_ptr(err->msg)); | 16 | buf_ptr(err->msg)); |
| 17 | 17 | ||
| 18 | assert(err->source); | 18 | fprintf(stderr, "%s\n", buf_ptr(&err->line_buf)); |
| 19 | assert(err->line_offsets); | ||
| 20 | |||
| 21 | int line_start_offset = err->line_offsets->at(err->line_start); | ||
| 22 | int end_line = err->line_start + 1; | ||
| 23 | int line_end_offset = (end_line >= err->line_offsets->length) ? | ||
| 24 | buf_len(err->source) : err->line_offsets->at(err->line_start + 1); | ||
| 25 | |||
| 26 | fwrite(buf_ptr(err->source) + line_start_offset, 1, line_end_offset - line_start_offset - 1, stderr); | ||
| 27 | fprintf(stderr, "\n"); | ||
| 28 | for (int i = 0; i < err->column_start; i += 1) { | 19 | for (int i = 0; i < err->column_start; i += 1) { |
| 29 | fprintf(stderr, " "); | 20 | fprintf(stderr, " "); |
| 30 | } | 21 | } |
| ... | @@ -36,5 +27,62 @@ void print_err_msg(ErrorMsg *err, ErrColor color) { | ... | @@ -36,5 +27,62 @@ void print_err_msg(ErrorMsg *err, ErrColor color) { |
| 36 | err->line_start + 1, err->column_start + 1, | 27 | err->line_start + 1, err->column_start + 1, |
| 37 | buf_ptr(err->msg)); | 28 | buf_ptr(err->msg)); |
| 38 | } | 29 | } |
| 30 | |||
| 31 | for (int i = 0; i < err->notes.length; i += 1) { | ||
| 32 | ErrorMsg *note = err->notes.at(i); | ||
| 33 | print_err_msg(note, color); | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | void err_msg_add_note(ErrorMsg *parent, ErrorMsg *note) { | ||
| 38 | parent->notes.append(note); | ||
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | ErrorMsg *err_msg_create_with_offset(Buf *path, int line, int column, int offset, | ||
| 42 | const char *source, Buf *msg) | ||
| 43 | { | ||
| 44 | ErrorMsg *err_msg = allocate<ErrorMsg>(1); | ||
| 45 | err_msg->path = path; | ||
| 46 | err_msg->line_start = line; | ||
| 47 | err_msg->column_start = column; | ||
| 48 | err_msg->msg = msg; | ||
| 49 | |||
| 50 | int line_start_offset = offset; | ||
| 51 | for (;;) { | ||
| 52 | if (line_start_offset == 0) { | ||
| 53 | break; | ||
| 54 | } else if (source[line_start_offset] == '\n') { | ||
| 55 | line_start_offset += 1; | ||
| 56 | break; | ||
| 57 | } | ||
| 58 | line_start_offset -= 1; | ||
| 59 | } | ||
| 60 | |||
| 61 | int line_end_offset = offset; | ||
| 62 | while (source[line_end_offset] && source[line_end_offset] != '\n') { | ||
| 63 | line_end_offset += 1; | ||
| 64 | } | ||
| 65 | |||
| 66 | buf_init_from_mem(&err_msg->line_buf, source + line_start_offset, line_end_offset - line_start_offset); | ||
| 67 | |||
| 68 | return err_msg; | ||
| 69 | } | ||
| 70 | |||
| 71 | ErrorMsg *err_msg_create_with_line(Buf *path, int line, int column, | ||
| 72 | Buf *source, ZigList<int> *line_offsets, Buf *msg) | ||
| 73 | { | ||
| 74 | ErrorMsg *err_msg = allocate<ErrorMsg>(1); | ||
| 75 | err_msg->path = path; | ||
| 76 | err_msg->line_start = line; | ||
| 77 | err_msg->column_start = column; | ||
| 78 | err_msg->msg = msg; | ||
| 79 | |||
| 80 | int line_start_offset = line_offsets->at(line); | ||
| 81 | int end_line = line + 1; | ||
| 82 | int line_end_offset = (end_line >= line_offsets->length) ? buf_len(source) : line_offsets->at(line + 1); | ||
| 83 | |||
| 84 | buf_init_from_mem(&err_msg->line_buf, buf_ptr(source) + line_start_offset, | ||
| 85 | line_end_offset - line_start_offset - 1); | ||
| 86 | |||
| 87 | return err_msg; | ||
| 88 | } |
src/errmsg.hpp+10-4| ... | @@ -20,14 +20,20 @@ enum ErrColor { | ... | @@ -20,14 +20,20 @@ enum ErrColor { |
| 20 | struct ErrorMsg { | 20 | struct ErrorMsg { |
| 21 | int line_start; | 21 | int line_start; |
| 22 | int column_start; | 22 | int column_start; |
| 23 | int line_end; | ||
| 24 | int column_end; | ||
| 25 | Buf *msg; | 23 | Buf *msg; |
| 26 | Buf *path; | 24 | Buf *path; |
| 27 | Buf *source; | 25 | Buf line_buf; |
| 28 | ZigList<int> *line_offsets; | 26 | |
| 27 | ZigList<ErrorMsg *> notes; | ||
| 29 | }; | 28 | }; |
| 30 | 29 | ||
| 31 | void print_err_msg(ErrorMsg *msg, ErrColor color); | 30 | void print_err_msg(ErrorMsg *msg, ErrColor color); |
| 32 | 31 | ||
| 32 | void err_msg_add_note(ErrorMsg *parent, ErrorMsg *note); | ||
| 33 | ErrorMsg *err_msg_create_with_offset(Buf *path, int line, int column, int offset, | ||
| 34 | const char *source, Buf *msg); | ||
| 35 | |||
| 36 | ErrorMsg *err_msg_create_with_line(Buf *path, int line, int column, | ||
| 37 | Buf *source, ZigList<int> *line_offsets, Buf *msg); | ||
| 38 | |||
| 33 | #endif | 39 | #endif |
src/main.cpp+86-1| ... | @@ -156,6 +156,25 @@ static int build(const char *arg0, int argc, char **argv) { | ... | @@ -156,6 +156,25 @@ static int build(const char *arg0, int argc, char **argv) { |
| 156 | return 0; | 156 | return 0; |
| 157 | } | 157 | } |
| 158 | 158 | ||
| 159 | struct ParseHPrint { | ||
| 160 | ParseH parse_h; | ||
| 161 | FILE *f; | ||
| 162 | int cur_indent; | ||
| 163 | }; | ||
| 164 | |||
| 165 | static const int indent_size = 4; | ||
| 166 | |||
| 167 | static void print_indent(ParseHPrint *p) { | ||
| 168 | for (int i = 0; i < p->cur_indent; i += 1) { | ||
| 169 | fprintf(p->f, " "); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | static const char *type_node_to_name(AstNode *type_node) { | ||
| 174 | assert(type_node->type == NodeTypeSymbol); | ||
| 175 | return buf_ptr(&type_node->data.symbol_expr.symbol); | ||
| 176 | } | ||
| 177 | |||
| 159 | static int parseh(const char *arg0, int argc, char **argv) { | 178 | static int parseh(const char *arg0, int argc, char **argv) { |
| 160 | char *in_file = nullptr; | 179 | char *in_file = nullptr; |
| 161 | ZigList<const char *> clang_argv = {0}; | 180 | ZigList<const char *> clang_argv = {0}; |
| ... | @@ -187,7 +206,73 @@ static int parseh(const char *arg0, int argc, char **argv) { | ... | @@ -187,7 +206,73 @@ static int parseh(const char *arg0, int argc, char **argv) { |
| 187 | return usage(arg0); | 206 | return usage(arg0); |
| 188 | } | 207 | } |
| 189 | 208 | ||
| 190 | parse_h_file(in_file, &clang_argv, stdout); | 209 | clang_argv.append(in_file); |
| 210 | |||
| 211 | ParseHPrint parse_h_print = {{{0}}}; | ||
| 212 | ParseHPrint *p = &parse_h_print; | ||
| 213 | p->f = stdout; | ||
| 214 | p->cur_indent = 0; | ||
| 215 | |||
| 216 | parse_h_file(&p->parse_h, &clang_argv); | ||
| 217 | |||
| 218 | if (p->parse_h.errors.length > 0) { | ||
| 219 | for (int i = 0; i < p->parse_h.errors.length; i += 1) { | ||
| 220 | ErrorMsg *err_msg = p->parse_h.errors.at(i); | ||
| 221 | // TODO respect --color arg | ||
| 222 | print_err_msg(err_msg, ErrColorAuto); | ||
| 223 | } | ||
| 224 | return EXIT_FAILURE; | ||
| 225 | } | ||
| 226 | |||
| 227 | for (int struct_i = 0; struct_i < p->parse_h.struct_list.length; struct_i += 1) { | ||
| 228 | AstNode *struct_decl = p->parse_h.struct_list.at(struct_i); | ||
| 229 | assert(struct_decl->type == NodeTypeStructDecl); | ||
| 230 | const char *struct_name = buf_ptr(&struct_decl->data.struct_decl.name); | ||
| 231 | print_indent(p); | ||
| 232 | fprintf(p->f, "struct %s {\n", struct_name); | ||
| 233 | p->cur_indent += indent_size; | ||
| 234 | for (int field_i = 0; field_i < struct_decl->data.struct_decl.fields.length; field_i += 1) { | ||
| 235 | AstNode *field_node = struct_decl->data.struct_decl.fields.at(field_i); | ||
| 236 | assert(field_node->type == NodeTypeStructField); | ||
| 237 | const char *field_name = buf_ptr(&field_node->data.struct_field.name); | ||
| 238 | const char *type_name = type_node_to_name(field_node->data.struct_field.type); | ||
| 239 | print_indent(p); | ||
| 240 | fprintf(p->f, "%s: %s,\n", field_name, type_name); | ||
| 241 | } | ||
| 242 | |||
| 243 | p->cur_indent -= indent_size; | ||
| 244 | fprintf(p->f, "}\n\n"); | ||
| 245 | } | ||
| 246 | |||
| 247 | for (int fn_i = 0; fn_i < p->parse_h.fn_list.length; fn_i += 1) { | ||
| 248 | AstNode *fn_proto = p->parse_h.fn_list.at(fn_i); | ||
| 249 | assert(fn_proto->type == NodeTypeFnProto); | ||
| 250 | print_indent(p); | ||
| 251 | const char *fn_name = buf_ptr(&fn_proto->data.fn_proto.name); | ||
| 252 | fprintf(p->f, "extern fn %s(", fn_name); | ||
| 253 | int arg_count = fn_proto->data.fn_proto.params.length; | ||
| 254 | bool is_var_args = fn_proto->data.fn_proto.is_var_args; | ||
| 255 | for (int arg_i = 0; arg_i < arg_count; arg_i += 1) { | ||
| 256 | AstNode *param_decl = fn_proto->data.fn_proto.params.at(arg_i); | ||
| 257 | assert(param_decl->type == NodeTypeParamDecl); | ||
| 258 | const char *arg_name = buf_ptr(&param_decl->data.param_decl.name); | ||
| 259 | const char *arg_type = type_node_to_name(param_decl->data.param_decl.type); | ||
| 260 | fprintf(p->f, "%s: %s", arg_name, arg_type); | ||
| 261 | if (arg_i + 1 < arg_count || is_var_args) { | ||
| 262 | fprintf(p->f, ", "); | ||
| 263 | } | ||
| 264 | } | ||
| 265 | if (is_var_args) { | ||
| 266 | fprintf(p->f, "..."); | ||
| 267 | } | ||
| 268 | fprintf(p->f, ")"); | ||
| 269 | const char *return_type_name = type_node_to_name(fn_proto->data.fn_proto.return_type); | ||
| 270 | if (strcmp(return_type_name, "void") != 0) { | ||
| 271 | fprintf(p->f, " -> %s", return_type_name); | ||
| 272 | } | ||
| 273 | fprintf(p->f, ";\n"); | ||
| 274 | } | ||
| 275 | |||
| 191 | return 0; | 276 | return 0; |
| 192 | } | 277 | } |
| 193 | 278 |
src/os.cpp+26| ... | @@ -208,3 +208,29 @@ int os_get_cwd(Buf *out_cwd) { | ... | @@ -208,3 +208,29 @@ int os_get_cwd(Buf *out_cwd) { |
| 208 | bool os_stderr_tty(void) { | 208 | bool os_stderr_tty(void) { |
| 209 | return isatty(STDERR_FILENO); | 209 | return isatty(STDERR_FILENO); |
| 210 | } | 210 | } |
| 211 | |||
| 212 | int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) { | ||
| 213 | buf_resize(out_tmp_path, 0); | ||
| 214 | buf_appendf(out_tmp_path, "/tmp/XXXXXX%s", buf_ptr(suffix)); | ||
| 215 | |||
| 216 | int fd = mkstemps(buf_ptr(out_tmp_path), buf_len(suffix)); | ||
| 217 | if (fd < 0) { | ||
| 218 | return ErrorFileSystem; | ||
| 219 | } | ||
| 220 | |||
| 221 | ssize_t amt_written = write(fd, buf_ptr(contents), buf_len(contents)); | ||
| 222 | if (amt_written != buf_len(contents)) | ||
| 223 | zig_panic("write failed: %s", strerror(errno)); | ||
| 224 | if (close(fd) == -1) | ||
| 225 | zig_panic("close failed"); | ||
| 226 | |||
| 227 | return 0; | ||
| 228 | } | ||
| 229 | |||
| 230 | int os_delete_file(Buf *path) { | ||
| 231 | if (remove(buf_ptr(path))) { | ||
| 232 | return ErrorFileSystem; | ||
| 233 | } else { | ||
| 234 | return 0; | ||
| 235 | } | ||
| 236 | } |
src/os.hpp+3-1| ... | @@ -29,7 +29,9 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents); | ... | @@ -29,7 +29,9 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents); |
| 29 | 29 | ||
| 30 | int os_get_cwd(Buf *out_cwd); | 30 | int os_get_cwd(Buf *out_cwd); |
| 31 | 31 | ||
| 32 | |||
| 33 | bool os_stderr_tty(void); | 32 | bool os_stderr_tty(void); |
| 34 | 33 | ||
| 34 | int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path); | ||
| 35 | int os_delete_file(Buf *path); | ||
| 36 | |||
| 35 | #endif | 37 | #endif |
src/parseh.cpp+84-599| ... | @@ -7,540 +7,52 @@ | ... | @@ -7,540 +7,52 @@ |
| 7 | 7 | ||
| 8 | #include "parseh.hpp" | 8 | #include "parseh.hpp" |
| 9 | #include "config.h" | 9 | #include "config.h" |
| 10 | #include "os.hpp" | ||
| 11 | #include "error.hpp" | ||
| 10 | 12 | ||
| 11 | #include <clang-c/Index.h> | 13 | #include <clang/Frontend/ASTUnit.h> |
| 14 | #include <clang/Frontend/CompilerInstance.h> | ||
| 12 | 15 | ||
| 13 | #include <string.h> | 16 | #include <string.h> |
| 14 | 17 | ||
| 15 | struct TypeDef { | 18 | using namespace clang; |
| 16 | Buf alias; | ||
| 17 | Buf target; | ||
| 18 | }; | ||
| 19 | |||
| 20 | struct Arg { | ||
| 21 | Buf name; | ||
| 22 | Buf *type; | ||
| 23 | }; | ||
| 24 | |||
| 25 | struct Fn { | ||
| 26 | Buf name; | ||
| 27 | Buf *return_type; | ||
| 28 | Arg *args; | ||
| 29 | int arg_count; | ||
| 30 | bool is_variadic; | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct Field { | ||
| 34 | Buf name; | ||
| 35 | Buf *type; | ||
| 36 | }; | ||
| 37 | |||
| 38 | struct Struct { | ||
| 39 | Buf name; | ||
| 40 | ZigList<Field*> fields; | ||
| 41 | bool have_def; | ||
| 42 | }; | ||
| 43 | |||
| 44 | struct ParseH { | ||
| 45 | CXTranslationUnit tu; | ||
| 46 | FILE *f; | ||
| 47 | ZigList<Fn *> fn_list; | ||
| 48 | ZigList<Struct *> struct_list; | ||
| 49 | ZigList<TypeDef *> type_def_list; | ||
| 50 | ZigList<Struct *> incomplete_struct_list; | ||
| 51 | Fn *cur_fn; | ||
| 52 | Struct *cur_struct; | ||
| 53 | int arg_index; | ||
| 54 | int cur_indent; | ||
| 55 | CXSourceRange range; | ||
| 56 | CXSourceLocation location; | ||
| 57 | }; | ||
| 58 | |||
| 59 | static const int indent_size = 4; | ||
| 60 | 19 | ||
| 61 | struct TypeMapping { | 20 | struct Context { |
| 62 | const char *c_name; | 21 | ParseH *parse_h; |
| 63 | const char *zig_name; | ||
| 64 | }; | 22 | }; |
| 65 | 23 | ||
| 66 | static const TypeMapping type_mappings[] = { | 24 | static bool decl_visitor(void *context, const Decl *decl) { |
| 67 | { | 25 | //Context *c = (Context*)context; |
| 68 | "int8_t", | ||
| 69 | "i8", | ||
| 70 | }, | ||
| 71 | { | ||
| 72 | "uint8_t", | ||
| 73 | "u8", | ||
| 74 | }, | ||
| 75 | { | ||
| 76 | "uint16_t", | ||
| 77 | "u16", | ||
| 78 | }, | ||
| 79 | { | ||
| 80 | "uint32_t", | ||
| 81 | "u32", | ||
| 82 | }, | ||
| 83 | { | ||
| 84 | "uint64_t", | ||
| 85 | "u64", | ||
| 86 | }, | ||
| 87 | { | ||
| 88 | "int16_t", | ||
| 89 | "i16", | ||
| 90 | }, | ||
| 91 | { | ||
| 92 | "int32_t", | ||
| 93 | "i32", | ||
| 94 | }, | ||
| 95 | { | ||
| 96 | "int64_t", | ||
| 97 | "i64", | ||
| 98 | }, | ||
| 99 | { | ||
| 100 | "intptr_t", | ||
| 101 | "isize", | ||
| 102 | }, | ||
| 103 | { | ||
| 104 | "uintptr_t", | ||
| 105 | "usize", | ||
| 106 | }, | ||
| 107 | }; | ||
| 108 | |||
| 109 | static bool have_struct_def(ParseH *p, Buf *name) { | ||
| 110 | for (int i = 0; i < p->struct_list.length; i += 1) { | ||
| 111 | Struct *struc = p->struct_list.at(i); | ||
| 112 | if (struc->fields.length > 0 && buf_eql_buf(&struc->name, name)) { | ||
| 113 | return true; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | return false; | ||
| 117 | } | ||
| 118 | 26 | ||
| 119 | static const char *c_to_zig_name(const char *name) { | 27 | fprintf(stderr, "got top level decl\n"); |
| 120 | for (int i = 0; i < array_length(type_mappings); i += 1) { | ||
| 121 | const TypeMapping *mapping = &type_mappings[i]; | ||
| 122 | if (strcmp(mapping->c_name, name) == 0) | ||
| 123 | return mapping->zig_name; | ||
| 124 | } | ||
| 125 | return nullptr; | ||
| 126 | } | ||
| 127 | 28 | ||
| 128 | static bool str_has_prefix(const char *str, const char *prefix) { | ||
| 129 | while (*prefix) { | ||
| 130 | if (*str && *str == *prefix) { | ||
| 131 | str += 1; | ||
| 132 | prefix += 1; | ||
| 133 | } else { | ||
| 134 | return false; | ||
| 135 | } | ||
| 136 | } | ||
| 137 | return true; | 29 | return true; |
| 138 | } | 30 | } |
| 139 | 31 | ||
| 140 | static const char *prefixes_stripped(CXType type) { | 32 | int parse_h_buf(ParseH *parse_h, Buf *source, const char *libc_include_path) { |
| 141 | CXString name = clang_getTypeSpelling(type); | 33 | int err; |
| 142 | const char *c_name = clang_getCString(name); | 34 | Buf tmp_file_path = BUF_INIT; |
| 143 | 35 | if ((err = os_buf_to_tmp_file(source, buf_create_from_str(".h"), &tmp_file_path))) { | |
| 144 | static const char *prefixes[] = { | 36 | return err; |
| 145 | "struct ", | ||
| 146 | "enum ", | ||
| 147 | "const ", | ||
| 148 | }; | ||
| 149 | |||
| 150 | start_over: | ||
| 151 | |||
| 152 | for (int i = 0; i < array_length(prefixes); i += 1) { | ||
| 153 | const char *prefix = prefixes[i]; | ||
| 154 | if (str_has_prefix(c_name, prefix)) { | ||
| 155 | c_name += strlen(prefix); | ||
| 156 | goto start_over; | ||
| 157 | } | ||
| 158 | } | ||
| 159 | return c_name; | ||
| 160 | } | ||
| 161 | |||
| 162 | static void print_location(ParseH *p) { | ||
| 163 | CXFile file; | ||
| 164 | unsigned line, column, offset; | ||
| 165 | clang_getFileLocation(p->location, &file, &line, &column, &offset); | ||
| 166 | CXString file_name = clang_getFileName(file); | ||
| 167 | |||
| 168 | fprintf(stderr, "%s line %u, column %u\n", clang_getCString(file_name), line, column); | ||
| 169 | } | ||
| 170 | |||
| 171 | static bool resolves_to_void(ParseH *p, CXType raw_type) { | ||
| 172 | if (raw_type.kind == CXType_Unexposed) { | ||
| 173 | CXType canonical = clang_getCanonicalType(raw_type); | ||
| 174 | if (canonical.kind == CXType_Unexposed) | ||
| 175 | zig_panic("clang C api insufficient"); | ||
| 176 | else | ||
| 177 | return resolves_to_void(p, canonical); | ||
| 178 | } | ||
| 179 | if (raw_type.kind == CXType_Void) { | ||
| 180 | return true; | ||
| 181 | } else if (raw_type.kind == CXType_Typedef) { | ||
| 182 | CXCursor typedef_cursor = clang_getTypeDeclaration(raw_type); | ||
| 183 | CXType underlying_type = clang_getTypedefDeclUnderlyingType(typedef_cursor); | ||
| 184 | return resolves_to_void(p, underlying_type); | ||
| 185 | } | ||
| 186 | return false; | ||
| 187 | } | ||
| 188 | |||
| 189 | static Buf *to_zig_type(ParseH *p, CXType raw_type) { | ||
| 190 | if (raw_type.kind == CXType_Unexposed) { | ||
| 191 | CXType canonical = clang_getCanonicalType(raw_type); | ||
| 192 | if (canonical.kind == CXType_Unexposed) | ||
| 193 | zig_panic("clang C api insufficient"); | ||
| 194 | else | ||
| 195 | return to_zig_type(p, canonical); | ||
| 196 | } | ||
| 197 | switch (raw_type.kind) { | ||
| 198 | case CXType_Invalid: | ||
| 199 | case CXType_Unexposed: | ||
| 200 | zig_unreachable(); | ||
| 201 | case CXType_Void: | ||
| 202 | zig_panic("void type encountered"); | ||
| 203 | case CXType_Bool: | ||
| 204 | return buf_create_from_str("bool"); | ||
| 205 | case CXType_SChar: | ||
| 206 | return buf_create_from_str("i8"); | ||
| 207 | case CXType_UChar: | ||
| 208 | case CXType_Char_U: | ||
| 209 | case CXType_Char_S: | ||
| 210 | return buf_create_from_str("u8"); | ||
| 211 | case CXType_WChar: | ||
| 212 | print_location(p); | ||
| 213 | zig_panic("TODO wchar"); | ||
| 214 | case CXType_Char16: | ||
| 215 | print_location(p); | ||
| 216 | zig_panic("TODO char16"); | ||
| 217 | case CXType_Char32: | ||
| 218 | print_location(p); | ||
| 219 | zig_panic("TODO char32"); | ||
| 220 | case CXType_UShort: | ||
| 221 | return buf_create_from_str("c_ushort"); | ||
| 222 | case CXType_UInt: | ||
| 223 | return buf_create_from_str("c_uint"); | ||
| 224 | case CXType_ULong: | ||
| 225 | return buf_create_from_str("c_ulong"); | ||
| 226 | case CXType_ULongLong: | ||
| 227 | return buf_create_from_str("c_ulonglong"); | ||
| 228 | case CXType_UInt128: | ||
| 229 | print_location(p); | ||
| 230 | zig_panic("TODO uint128"); | ||
| 231 | case CXType_Short: | ||
| 232 | return buf_create_from_str("c_short"); | ||
| 233 | case CXType_Int: | ||
| 234 | return buf_create_from_str("c_int"); | ||
| 235 | case CXType_Long: | ||
| 236 | return buf_create_from_str("c_long"); | ||
| 237 | case CXType_LongLong: | ||
| 238 | return buf_create_from_str("c_longlong"); | ||
| 239 | case CXType_Int128: | ||
| 240 | print_location(p); | ||
| 241 | zig_panic("TODO int128"); | ||
| 242 | case CXType_Float: | ||
| 243 | return buf_create_from_str("f32"); | ||
| 244 | case CXType_Double: | ||
| 245 | return buf_create_from_str("f64"); | ||
| 246 | case CXType_LongDouble: | ||
| 247 | return buf_create_from_str("f128"); | ||
| 248 | case CXType_IncompleteArray: | ||
| 249 | { | ||
| 250 | CXType pointee_type = clang_getArrayElementType(raw_type); | ||
| 251 | Buf *pointee_buf = to_zig_type(p, pointee_type); | ||
| 252 | if (clang_isConstQualifiedType(pointee_type)) { | ||
| 253 | return buf_sprintf("&const %s", buf_ptr(pointee_buf)); | ||
| 254 | } else { | ||
| 255 | return buf_sprintf("&%s", buf_ptr(pointee_buf)); | ||
| 256 | } | ||
| 257 | } | ||
| 258 | case CXType_Pointer: | ||
| 259 | { | ||
| 260 | CXType pointee_type = clang_getPointeeType(raw_type); | ||
| 261 | Buf *pointee_buf; | ||
| 262 | if (resolves_to_void(p, pointee_type)) { | ||
| 263 | pointee_buf = buf_create_from_str("u8"); | ||
| 264 | } else { | ||
| 265 | pointee_buf = to_zig_type(p, pointee_type); | ||
| 266 | } | ||
| 267 | if (clang_isConstQualifiedType(pointee_type)) { | ||
| 268 | return buf_sprintf("&const %s", buf_ptr(pointee_buf)); | ||
| 269 | } else { | ||
| 270 | return buf_sprintf("&%s", buf_ptr(pointee_buf)); | ||
| 271 | } | ||
| 272 | } | ||
| 273 | case CXType_Record: | ||
| 274 | { | ||
| 275 | const char *name = prefixes_stripped(raw_type); | ||
| 276 | return buf_sprintf("%s", name); | ||
| 277 | } | ||
| 278 | case CXType_Enum: | ||
| 279 | { | ||
| 280 | const char *name = prefixes_stripped(raw_type); | ||
| 281 | return buf_sprintf("%s", name); | ||
| 282 | } | ||
| 283 | case CXType_Typedef: | ||
| 284 | { | ||
| 285 | const char *name = prefixes_stripped(raw_type); | ||
| 286 | const char *zig_name = c_to_zig_name(name); | ||
| 287 | if (zig_name) { | ||
| 288 | return buf_create_from_str(zig_name); | ||
| 289 | } else { | ||
| 290 | CXCursor typedef_cursor = clang_getTypeDeclaration(raw_type); | ||
| 291 | CXType underlying_type = clang_getTypedefDeclUnderlyingType(typedef_cursor); | ||
| 292 | if (resolves_to_void(p, underlying_type)) { | ||
| 293 | return buf_create_from_str("u8"); | ||
| 294 | } else { | ||
| 295 | return buf_create_from_str(name); | ||
| 296 | } | ||
| 297 | } | ||
| 298 | } | ||
| 299 | case CXType_ConstantArray: | ||
| 300 | { | ||
| 301 | CXType child_type = clang_getArrayElementType(raw_type); | ||
| 302 | Buf *zig_child_type = to_zig_type(p, child_type); | ||
| 303 | long size = (long)clang_getArraySize(raw_type); | ||
| 304 | return buf_sprintf("[%s; %ld]", buf_ptr(zig_child_type), size); | ||
| 305 | } | ||
| 306 | case CXType_FunctionProto: | ||
| 307 | fprintf(stderr, "warning: TODO function proto\n"); | ||
| 308 | print_location(p); | ||
| 309 | return buf_create_from_str("u8"); | ||
| 310 | case CXType_FunctionNoProto: | ||
| 311 | print_location(p); | ||
| 312 | zig_panic("TODO function no proto"); | ||
| 313 | case CXType_BlockPointer: | ||
| 314 | print_location(p); | ||
| 315 | zig_panic("TODO block pointer"); | ||
| 316 | case CXType_Vector: | ||
| 317 | print_location(p); | ||
| 318 | zig_panic("TODO vector"); | ||
| 319 | case CXType_LValueReference: | ||
| 320 | case CXType_RValueReference: | ||
| 321 | case CXType_VariableArray: | ||
| 322 | case CXType_DependentSizedArray: | ||
| 323 | case CXType_MemberPointer: | ||
| 324 | case CXType_ObjCInterface: | ||
| 325 | case CXType_ObjCObjectPointer: | ||
| 326 | case CXType_NullPtr: | ||
| 327 | case CXType_Overload: | ||
| 328 | case CXType_Dependent: | ||
| 329 | case CXType_ObjCId: | ||
| 330 | case CXType_ObjCClass: | ||
| 331 | case CXType_ObjCSel: | ||
| 332 | case CXType_Complex: | ||
| 333 | print_location(p); | ||
| 334 | zig_panic("TODO"); | ||
| 335 | } | ||
| 336 | |||
| 337 | zig_unreachable(); | ||
| 338 | } | ||
| 339 | |||
| 340 | static bool is_storage_class_export(CX_StorageClass storage_class) { | ||
| 341 | switch (storage_class) { | ||
| 342 | case CX_SC_Invalid: | ||
| 343 | zig_unreachable(); | ||
| 344 | case CX_SC_None: | ||
| 345 | case CX_SC_Extern: | ||
| 346 | case CX_SC_Auto: | ||
| 347 | return true; | ||
| 348 | case CX_SC_Static: | ||
| 349 | case CX_SC_PrivateExtern: | ||
| 350 | case CX_SC_OpenCLWorkGroupLocal: | ||
| 351 | case CX_SC_Register: | ||
| 352 | return false; | ||
| 353 | } | ||
| 354 | zig_unreachable(); | ||
| 355 | } | ||
| 356 | |||
| 357 | static enum CXChildVisitResult visit_fn_children(CXCursor cursor, CXCursor parent, CXClientData client_data) { | ||
| 358 | ParseH *p = (ParseH*)client_data; | ||
| 359 | enum CXCursorKind kind = clang_getCursorKind(cursor); | ||
| 360 | |||
| 361 | switch (kind) { | ||
| 362 | case CXCursor_ParmDecl: | ||
| 363 | { | ||
| 364 | assert(p->cur_fn); | ||
| 365 | assert(p->arg_index < p->cur_fn->arg_count); | ||
| 366 | CXString name = clang_getCursorSpelling(cursor); | ||
| 367 | Buf *arg_name = &p->cur_fn->args[p->arg_index].name; | ||
| 368 | buf_init_from_str(arg_name, clang_getCString(name)); | ||
| 369 | if (buf_len(arg_name) == 0) { | ||
| 370 | buf_appendf(arg_name, "arg%d", p->arg_index); | ||
| 371 | } | ||
| 372 | |||
| 373 | p->arg_index += 1; | ||
| 374 | return CXChildVisit_Continue; | ||
| 375 | } | ||
| 376 | default: | ||
| 377 | return CXChildVisit_Recurse; | ||
| 378 | } | ||
| 379 | } | ||
| 380 | |||
| 381 | static enum CXChildVisitResult visit_struct_children(CXCursor cursor, CXCursor parent, CXClientData client_data) { | ||
| 382 | ParseH *p = (ParseH*)client_data; | ||
| 383 | enum CXCursorKind kind = clang_getCursorKind(cursor); | ||
| 384 | |||
| 385 | switch (kind) { | ||
| 386 | case CXCursor_FieldDecl: | ||
| 387 | { | ||
| 388 | assert(p->cur_struct); | ||
| 389 | CXString name = clang_getCursorSpelling(cursor); | ||
| 390 | Field *field = allocate<Field>(1); | ||
| 391 | buf_init_from_str(&field->name, clang_getCString(name)); | ||
| 392 | CXType cursor_type = clang_getCursorType(cursor); | ||
| 393 | field->type = to_zig_type(p, cursor_type); | ||
| 394 | |||
| 395 | p->cur_struct->fields.append(field); | ||
| 396 | |||
| 397 | return CXChildVisit_Continue; | ||
| 398 | } | ||
| 399 | default: | ||
| 400 | return CXChildVisit_Recurse; | ||
| 401 | } | ||
| 402 | } | ||
| 403 | |||
| 404 | static bool handle_struct_cursor(ParseH *p, CXCursor cursor, const char *name, bool expect_name) { | ||
| 405 | p->cur_struct = allocate<Struct>(1); | ||
| 406 | |||
| 407 | buf_init_from_str(&p->cur_struct->name, name); | ||
| 408 | |||
| 409 | bool got_name = (buf_len(&p->cur_struct->name) != 0); | ||
| 410 | if (expect_name != got_name) | ||
| 411 | return false; | ||
| 412 | |||
| 413 | clang_visitChildren(cursor, visit_struct_children, p); | ||
| 414 | |||
| 415 | if (p->cur_struct->fields.length > 0) { | ||
| 416 | p->struct_list.append(p->cur_struct); | ||
| 417 | } else { | ||
| 418 | p->incomplete_struct_list.append(p->cur_struct); | ||
| 419 | } | 37 | } |
| 38 | ZigList<const char *> clang_argv = {0}; | ||
| 39 | clang_argv.append(buf_ptr(&tmp_file_path)); | ||
| 420 | 40 | ||
| 421 | p->cur_struct = nullptr; | 41 | clang_argv.append("-isystem"); |
| 422 | 42 | clang_argv.append(libc_include_path); | |
| 423 | return true; | ||
| 424 | } | ||
| 425 | |||
| 426 | |||
| 427 | static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXClientData client_data) { | ||
| 428 | ParseH *p = (ParseH*)client_data; | ||
| 429 | enum CXCursorKind kind = clang_getCursorKind(cursor); | ||
| 430 | CXString name = clang_getCursorSpelling(cursor); | ||
| 431 | |||
| 432 | p->range = clang_getCursorExtent(cursor); | ||
| 433 | p->location = clang_getRangeStart(p->range); | ||
| 434 | |||
| 435 | switch (kind) { | ||
| 436 | case CXCursor_FunctionDecl: | ||
| 437 | { | ||
| 438 | CX_StorageClass storage_class = clang_Cursor_getStorageClass(cursor); | ||
| 439 | if (!is_storage_class_export(storage_class)) | ||
| 440 | return CXChildVisit_Continue; | ||
| 441 | |||
| 442 | CXType fn_type = clang_getCursorType(cursor); | ||
| 443 | if (clang_getFunctionTypeCallingConv(fn_type) != CXCallingConv_C) { | ||
| 444 | print_location(p); | ||
| 445 | fprintf(stderr, "warning: skipping non c calling convention function, not yet supported\n"); | ||
| 446 | return CXChildVisit_Continue; | ||
| 447 | } | ||
| 448 | |||
| 449 | assert(!p->cur_fn); | ||
| 450 | p->cur_fn = allocate<Fn>(1); | ||
| 451 | |||
| 452 | p->cur_fn->is_variadic = clang_isFunctionTypeVariadic(fn_type); | ||
| 453 | |||
| 454 | CXType return_type = clang_getResultType(fn_type); | ||
| 455 | if (!resolves_to_void(p, return_type)) { | ||
| 456 | p->cur_fn->return_type = to_zig_type(p, return_type); | ||
| 457 | } | ||
| 458 | |||
| 459 | buf_init_from_str(&p->cur_fn->name, clang_getCString(name)); | ||
| 460 | |||
| 461 | p->cur_fn->arg_count = clang_getNumArgTypes(fn_type); | ||
| 462 | p->cur_fn->args = allocate<Arg>(p->cur_fn->arg_count); | ||
| 463 | |||
| 464 | for (int i = 0; i < p->cur_fn->arg_count; i += 1) { | ||
| 465 | CXType param_type = clang_getArgType(fn_type, i); | ||
| 466 | p->cur_fn->args[i].type = to_zig_type(p, param_type); | ||
| 467 | } | ||
| 468 | |||
| 469 | p->arg_index = 0; | ||
| 470 | |||
| 471 | clang_visitChildren(cursor, visit_fn_children, p); | ||
| 472 | |||
| 473 | p->fn_list.append(p->cur_fn); | ||
| 474 | p->cur_fn = nullptr; | ||
| 475 | |||
| 476 | return CXChildVisit_Recurse; | ||
| 477 | } | ||
| 478 | case CXCursor_CompoundStmt: | ||
| 479 | case CXCursor_FieldDecl: | ||
| 480 | case CXCursor_TypedefDecl: | ||
| 481 | { | ||
| 482 | CXType underlying_type = clang_getTypedefDeclUnderlyingType(cursor); | ||
| 483 | |||
| 484 | if (resolves_to_void(p, underlying_type)) { | ||
| 485 | return CXChildVisit_Continue; | ||
| 486 | } | ||
| 487 | |||
| 488 | if (underlying_type.kind == CXType_Unexposed) { | ||
| 489 | underlying_type = clang_getCanonicalType(underlying_type); | ||
| 490 | } | ||
| 491 | bool skip_typedef; | ||
| 492 | if (underlying_type.kind == CXType_Unexposed) { | ||
| 493 | fprintf(stderr, "warning: unexposed type\n"); | ||
| 494 | print_location(p); | ||
| 495 | skip_typedef = true; | ||
| 496 | } else if (underlying_type.kind == CXType_Record) { | ||
| 497 | CXCursor decl_cursor = clang_getTypeDeclaration(underlying_type); | ||
| 498 | skip_typedef = handle_struct_cursor(p, decl_cursor, clang_getCString(name), false); | ||
| 499 | } else if (underlying_type.kind == CXType_Invalid) { | ||
| 500 | fprintf(stderr, "warning: invalid type\n"); | ||
| 501 | print_location(p); | ||
| 502 | skip_typedef = true; | ||
| 503 | } else { | ||
| 504 | skip_typedef = false; | ||
| 505 | } | ||
| 506 | |||
| 507 | CXType typedef_type = clang_getCursorType(cursor); | ||
| 508 | const char *name_str = prefixes_stripped(typedef_type); | ||
| 509 | if (!skip_typedef && c_to_zig_name(name_str)) { | ||
| 510 | skip_typedef = true; | ||
| 511 | } | ||
| 512 | 43 | ||
| 513 | if (!skip_typedef) { | 44 | err = parse_h_file(parse_h, &clang_argv); |
| 514 | TypeDef *type_def = allocate<TypeDef>(1); | ||
| 515 | buf_init_from_str(&type_def->alias, name_str); | ||
| 516 | buf_init_from_buf(&type_def->target, to_zig_type(p, underlying_type)); | ||
| 517 | p->type_def_list.append(type_def); | ||
| 518 | } | ||
| 519 | |||
| 520 | return CXChildVisit_Continue; | ||
| 521 | } | ||
| 522 | case CXCursor_StructDecl: | ||
| 523 | { | ||
| 524 | handle_struct_cursor(p, cursor, clang_getCString(name), true); | ||
| 525 | 45 | ||
| 526 | return CXChildVisit_Continue; | 46 | os_delete_file(&tmp_file_path); |
| 527 | } | ||
| 528 | default: | ||
| 529 | return CXChildVisit_Recurse; | ||
| 530 | } | ||
| 531 | } | ||
| 532 | 47 | ||
| 533 | static void print_indent(ParseH *p) { | 48 | return err; |
| 534 | for (int i = 0; i < p->cur_indent; i += 1) { | 49 | // write to temp file, parse it, delete it |
| 535 | fprintf(p->f, " "); | ||
| 536 | } | ||
| 537 | } | 50 | } |
| 538 | 51 | ||
| 539 | void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FILE *f) { | 52 | int parse_h_file(ParseH *parse_h, ZigList<const char *> *clang_argv) { |
| 540 | ParseH parse_h = {0}; | 53 | Context context = {0}; |
| 541 | ParseH *p = &parse_h; | 54 | Context *c = &context; |
| 542 | p->f = f; | 55 | c->parse_h = parse_h; |
| 543 | CXIndex index = clang_createIndex(1, 0); | ||
| 544 | 56 | ||
| 545 | char *ZIG_PARSEH_CFLAGS = getenv("ZIG_PARSEH_CFLAGS"); | 57 | char *ZIG_PARSEH_CFLAGS = getenv("ZIG_PARSEH_CFLAGS"); |
| 546 | if (ZIG_PARSEH_CFLAGS) { | 58 | if (ZIG_PARSEH_CFLAGS) { |
| ... | @@ -558,105 +70,78 @@ void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FI | ... | @@ -558,105 +70,78 @@ void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FI |
| 558 | buf_init_from_str(&tmp_buf, start); | 70 | buf_init_from_str(&tmp_buf, start); |
| 559 | clang_argv->append(buf_ptr(buf_create_from_buf(&tmp_buf))); | 71 | clang_argv->append(buf_ptr(buf_create_from_buf(&tmp_buf))); |
| 560 | } | 72 | } |
| 73 | |||
| 561 | clang_argv->append("-isystem"); | 74 | clang_argv->append("-isystem"); |
| 562 | clang_argv->append(ZIG_HEADERS_DIR); | 75 | clang_argv->append(ZIG_HEADERS_DIR); |
| 563 | 76 | ||
| 77 | // we don't need spell checking and it slows things down | ||
| 78 | clang_argv->append("-fno-spell-checking"); | ||
| 79 | // to make the end argument work | ||
| 564 | clang_argv->append(nullptr); | 80 | clang_argv->append(nullptr); |
| 565 | 81 | ||
| 566 | enum CXErrorCode err_code; | 82 | IntrusiveRefCntPtr<DiagnosticsEngine> diags(CompilerInstance::createDiagnostics(new DiagnosticOptions)); |
| 567 | if ((err_code = clang_parseTranslationUnit2(index, target_path, | ||
| 568 | clang_argv->items, clang_argv->length - 1, | ||
| 569 | NULL, 0, CXTranslationUnit_None, &p->tu))) | ||
| 570 | { | ||
| 571 | zig_panic("parse translation unit failure"); | ||
| 572 | } | ||
| 573 | |||
| 574 | |||
| 575 | unsigned diag_count = clang_getNumDiagnostics(p->tu); | ||
| 576 | 83 | ||
| 577 | if (diag_count > 0) { | 84 | std::shared_ptr<PCHContainerOperations> pch_container_ops = std::make_shared<PCHContainerOperations>(); |
| 578 | for (unsigned i = 0; i < diag_count; i += 1) { | ||
| 579 | CXDiagnostic diagnostic = clang_getDiagnostic(p->tu, i); | ||
| 580 | CXSourceLocation location = clang_getDiagnosticLocation(diagnostic); | ||
| 581 | |||
| 582 | CXFile file; | ||
| 583 | unsigned line, column, offset; | ||
| 584 | clang_getSpellingLocation(location, &file, &line, &column, &offset); | ||
| 585 | CXString text = clang_getDiagnosticSpelling(diagnostic); | ||
| 586 | CXString file_name = clang_getFileName(file); | ||
| 587 | fprintf(stderr, "%s line %u, column %u: %s\n", clang_getCString(file_name), | ||
| 588 | line, column, clang_getCString(text)); | ||
| 589 | } | ||
| 590 | |||
| 591 | exit(1); | ||
| 592 | } | ||
| 593 | 85 | ||
| 86 | bool skip_function_bodies = true; | ||
| 87 | bool only_local_decls = true; | ||
| 88 | bool capture_diagnostics = true; | ||
| 89 | bool user_files_are_volatile = true; | ||
| 90 | bool allow_pch_with_compiler_errors = false; | ||
| 91 | const char *resources_path = ZIG_HEADERS_DIR; | ||
| 92 | std::unique_ptr<ASTUnit> err_unit; | ||
| 93 | std::unique_ptr<ASTUnit> ast_unit(ASTUnit::LoadFromCommandLine( | ||
| 94 | &clang_argv->at(0), &clang_argv->last(), | ||
| 95 | pch_container_ops, diags, resources_path, | ||
| 96 | only_local_decls, capture_diagnostics, None, true, false, TU_Complete, | ||
| 97 | false, false, allow_pch_with_compiler_errors, skip_function_bodies, | ||
| 98 | user_files_are_volatile, false, &err_unit)); | ||
| 594 | 99 | ||
| 595 | CXCursor cursor = clang_getTranslationUnitCursor(p->tu); | ||
| 596 | clang_visitChildren(cursor, fn_visitor, p); | ||
| 597 | |||
| 598 | for (int struct_i = 0; struct_i < p->struct_list.length; struct_i += 1) { | ||
| 599 | Struct *struc = p->struct_list.at(struct_i); | ||
| 600 | fprintf(f, "struct %s {\n", buf_ptr(&struc->name)); | ||
| 601 | p->cur_indent += indent_size; | ||
| 602 | for (int field_i = 0; field_i < struc->fields.length; field_i += 1) { | ||
| 603 | Field *field = struc->fields.at(field_i); | ||
| 604 | print_indent(p); | ||
| 605 | fprintf(f, "%s: %s,\n", buf_ptr(&field->name), buf_ptr(field->type)); | ||
| 606 | } | ||
| 607 | |||
| 608 | p->cur_indent -= indent_size; | ||
| 609 | fprintf(f, "}\n\n"); | ||
| 610 | } | ||
| 611 | 100 | ||
| 612 | int total_typedef_count = p->type_def_list.length; | 101 | // Early failures in LoadFromCommandLine may return with ErrUnit unset. |
| 613 | for (int i = 0; i < p->incomplete_struct_list.length; i += 1) { | 102 | if (!ast_unit && !err_unit) { |
| 614 | Struct *struc = p->incomplete_struct_list.at(i); | 103 | return ErrorFileSystem; |
| 615 | struc->have_def = have_struct_def(p, &struc->name); | ||
| 616 | total_typedef_count += (int)!struc->have_def; | ||
| 617 | } | 104 | } |
| 618 | 105 | ||
| 619 | if (total_typedef_count) { | 106 | if (diags->getClient()->getNumErrors() > 0) { |
| 620 | for (int i = 0; i < p->incomplete_struct_list.length; i += 1) { | 107 | if (ast_unit) { |
| 621 | Struct *struc = p->incomplete_struct_list.at(i); | 108 | err_unit = std::move(ast_unit); |
| 622 | if (struc->have_def) | ||
| 623 | continue; | ||
| 624 | |||
| 625 | fprintf(f, "struct %s;\n", buf_ptr(&struc->name)); | ||
| 626 | } | 109 | } |
| 627 | 110 | ||
| 628 | for (int type_def_i = 0; type_def_i < p->type_def_list.length; type_def_i += 1) { | 111 | for (ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(), |
| 629 | TypeDef *type_def = p->type_def_list.at(type_def_i); | 112 | it_end = err_unit->stored_diag_end(); |
| 630 | fprintf(f, "type %s = %s;\n", buf_ptr(&type_def->alias), buf_ptr(&type_def->target)); | 113 | it != it_end; ++it) |
| 114 | { | ||
| 115 | switch (it->getLevel()) { | ||
| 116 | case DiagnosticsEngine::Ignored: | ||
| 117 | case DiagnosticsEngine::Note: | ||
| 118 | case DiagnosticsEngine::Remark: | ||
| 119 | case DiagnosticsEngine::Warning: | ||
| 120 | continue; | ||
| 121 | case DiagnosticsEngine::Error: | ||
| 122 | case DiagnosticsEngine::Fatal: | ||
| 123 | break; | ||
| 124 | } | ||
| 125 | StringRef msg_str_ref = it->getMessage(); | ||
| 126 | FullSourceLoc fsl = it->getLocation(); | ||
| 127 | FileID file_id = fsl.getManager().getFileID(fsl); | ||
| 128 | StringRef filename = fsl.getManager().getFilename(fsl); | ||
| 129 | unsigned line = fsl.getSpellingLineNumber() - 1; | ||
| 130 | unsigned column = fsl.getSpellingColumnNumber() - 1; | ||
| 131 | unsigned offset = fsl.getManager().getFileOffset(fsl); | ||
| 132 | const char *source = (const char *)fsl.getManager().getBufferData(file_id).bytes_begin(); | ||
| 133 | Buf *msg = buf_create_from_str((const char *)msg_str_ref.bytes_begin()); | ||
| 134 | Buf *path = buf_create_from_str((const char *)filename.bytes_begin()); | ||
| 135 | |||
| 136 | ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg); | ||
| 137 | |||
| 138 | parse_h->errors.append(err_msg); | ||
| 631 | } | 139 | } |
| 632 | 140 | ||
| 633 | fprintf(f, "\n"); | 141 | return 0; |
| 634 | } | 142 | } |
| 635 | 143 | ||
| 636 | if (p->fn_list.length) { | 144 | ast_unit->visitLocalTopLevelDecls(c, decl_visitor); |
| 637 | fprintf(f, "extern {\n"); | 145 | |
| 638 | p->cur_indent += indent_size; | 146 | return 0; |
| 639 | for (int fn_i = 0; fn_i < p->fn_list.length; fn_i += 1) { | ||
| 640 | Fn *fn = p->fn_list.at(fn_i); | ||
| 641 | print_indent(p); | ||
| 642 | fprintf(p->f, "fn %s(", buf_ptr(&fn->name)); | ||
| 643 | for (int arg_i = 0; arg_i < fn->arg_count; arg_i += 1) { | ||
| 644 | Arg *arg = &fn->args[arg_i]; | ||
| 645 | fprintf(p->f, "%s: %s", buf_ptr(&arg->name), buf_ptr(arg->type)); | ||
| 646 | if (arg_i + 1 < fn->arg_count || fn->is_variadic) { | ||
| 647 | fprintf(p->f, ", "); | ||
| 648 | } | ||
| 649 | } | ||
| 650 | if (fn->is_variadic) { | ||
| 651 | fprintf(p->f, "..."); | ||
| 652 | } | ||
| 653 | fprintf(p->f, ")"); | ||
| 654 | if (fn->return_type) { | ||
| 655 | fprintf(p->f, " -> %s", buf_ptr(fn->return_type)); | ||
| 656 | } | ||
| 657 | fprintf(p->f, ";\n"); | ||
| 658 | } | ||
| 659 | p->cur_indent -= indent_size; | ||
| 660 | fprintf(f, "}\n"); | ||
| 661 | } | ||
| 662 | } | 147 | } |
src/parseh.hpp+3-4| ... | @@ -9,10 +9,9 @@ | ... | @@ -9,10 +9,9 @@ |
| 9 | #ifndef ZIG_PARSEH_HPP | 9 | #ifndef ZIG_PARSEH_HPP |
| 10 | #define ZIG_PARSEH_HPP | 10 | #define ZIG_PARSEH_HPP |
| 11 | 11 | ||
| 12 | #include "buffer.hpp" | 12 | #include "all_types.hpp" |
| 13 | 13 | ||
| 14 | #include <stdio.h> | 14 | int parse_h_file(ParseH *parse_h, ZigList<const char *> *clang_argv); |
| 15 | 15 | int parse_h_buf(ParseH *parse_h, Buf *buf, const char *libc_include_path); | |
| 16 | void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FILE *f); | ||
| 17 | 16 | ||
| 18 | #endif | 17 | #endif |
src/parser.cpp+9-20| ... | @@ -488,23 +488,16 @@ __attribute__ ((noreturn)) | ... | @@ -488,23 +488,16 @@ __attribute__ ((noreturn)) |
| 488 | static void ast_asm_error(ParseContext *pc, AstNode *node, int offset, const char *format, ...) { | 488 | static void ast_asm_error(ParseContext *pc, AstNode *node, int offset, const char *format, ...) { |
| 489 | assert(node->type == NodeTypeAsmExpr); | 489 | assert(node->type == NodeTypeAsmExpr); |
| 490 | 490 | ||
| 491 | ErrorMsg *err = allocate<ErrorMsg>(1); | ||
| 492 | 491 | ||
| 493 | SrcPos pos = node->data.asm_expr.offset_map.at(offset); | 492 | SrcPos pos = node->data.asm_expr.offset_map.at(offset); |
| 494 | 493 | ||
| 495 | err->line_start = pos.line; | ||
| 496 | err->column_start = pos.column; | ||
| 497 | err->line_end = -1; | ||
| 498 | err->column_end = -1; | ||
| 499 | |||
| 500 | va_list ap; | 494 | va_list ap; |
| 501 | va_start(ap, format); | 495 | va_start(ap, format); |
| 502 | err->msg = buf_vprintf(format, ap); | 496 | Buf *msg = buf_vprintf(format, ap); |
| 503 | va_end(ap); | 497 | va_end(ap); |
| 504 | 498 | ||
| 505 | err->path = pc->owner->path; | 499 | ErrorMsg *err = err_msg_create_with_line(pc->owner->path, pos.line, pos.column, |
| 506 | err->source = pc->owner->source_code; | 500 | pc->owner->source_code, pc->owner->line_offsets, msg); |
| 507 | err->line_offsets = pc->owner->line_offsets; | ||
| 508 | 501 | ||
| 509 | print_err_msg(err, pc->err_color); | 502 | print_err_msg(err, pc->err_color); |
| 510 | exit(EXIT_FAILURE); | 503 | exit(EXIT_FAILURE); |
| ... | @@ -513,20 +506,16 @@ static void ast_asm_error(ParseContext *pc, AstNode *node, int offset, const cha | ... | @@ -513,20 +506,16 @@ static void ast_asm_error(ParseContext *pc, AstNode *node, int offset, const cha |
| 513 | __attribute__ ((format (printf, 3, 4))) | 506 | __attribute__ ((format (printf, 3, 4))) |
| 514 | __attribute__ ((noreturn)) | 507 | __attribute__ ((noreturn)) |
| 515 | static void ast_error(ParseContext *pc, Token *token, const char *format, ...) { | 508 | static void ast_error(ParseContext *pc, Token *token, const char *format, ...) { |
| 516 | ErrorMsg *err = allocate<ErrorMsg>(1); | ||
| 517 | err->line_start = token->start_line; | ||
| 518 | err->column_start = token->start_column; | ||
| 519 | err->line_end = -1; | ||
| 520 | err->column_end = -1; | ||
| 521 | |||
| 522 | va_list ap; | 509 | va_list ap; |
| 523 | va_start(ap, format); | 510 | va_start(ap, format); |
| 524 | err->msg = buf_vprintf(format, ap); | 511 | Buf *msg = buf_vprintf(format, ap); |
| 525 | va_end(ap); | 512 | va_end(ap); |
| 526 | 513 | ||
| 527 | err->path = pc->owner->path; | 514 | |
| 528 | err->source = pc->owner->source_code; | 515 | ErrorMsg *err = err_msg_create_with_line(pc->owner->path, token->start_line, token->start_column, |
| 529 | err->line_offsets = pc->owner->line_offsets; | 516 | pc->owner->source_code, pc->owner->line_offsets, msg); |
| 517 | err->line_start = token->start_line; | ||
| 518 | err->column_start = token->start_column; | ||
| 530 | 519 | ||
| 531 | print_err_msg(err, pc->err_color); | 520 | print_err_msg(err, pc->err_color); |
| 532 | exit(EXIT_FAILURE); | 521 | exit(EXIT_FAILURE); |
test/run_tests.cpp+7| ... | @@ -1673,6 +1673,13 @@ fn f(s: []u8) -> []u8 { | ... | @@ -1673,6 +1673,13 @@ fn f(s: []u8) -> []u8 { |
| 1673 | } | 1673 | } |
| 1674 | )SOURCE", 1, ".tmp_source.zig:3:5: error: string concatenation requires constant expression"); | 1674 | )SOURCE", 1, ".tmp_source.zig:3:5: error: string concatenation requires constant expression"); |
| 1675 | 1675 | ||
| 1676 | add_compile_fail_case("c_import with bogus include", R"SOURCE( | ||
| 1677 | c_import { | ||
| 1678 | @c_include("bogus.h"); | ||
| 1679 | } | ||
| 1680 | )SOURCE", 2, ".tmp_source.zig:2:1: error: C import failed", | ||
| 1681 | ".h:1:10: error: 'bogus.h' file not found"); | ||
| 1682 | |||
| 1676 | } | 1683 | } |
| 1677 | 1684 | ||
| 1678 | static void print_compiler_invocation(TestCase *test_case) { | 1685 | static void print_compiler_invocation(TestCase *test_case) { |