| author | |
| committer | |
| log | ad3f98c615e688387c2d3580321ab17965b21378 |
| tree | 41d6b7c5cee74b53fe112bbd1d7726925028f610 |
| parent | 174e58a05f94eaee6e04e858d916d28d3f5be3b7 |
6 files changed, 502 insertions(+), 82 deletions(-)
CMakeLists.txt+5| ... | @@ -16,6 +16,9 @@ find_package(llvm) | ... | @@ -16,6 +16,9 @@ find_package(llvm) |
| 16 | include_directories(${LLVM_INCLUDE_DIRS}) | 16 | include_directories(${LLVM_INCLUDE_DIRS}) |
| 17 | link_directories(${LLVM_LIBDIRS}) | 17 | link_directories(${LLVM_LIBDIRS}) |
| 18 | 18 | ||
| 19 | find_package(clang) | ||
| 20 | include_directories(${CLANG_INCLUDE_DIR}) | ||
| 21 | |||
| 19 | include_directories( | 22 | include_directories( |
| 20 | ${CMAKE_SOURCE_DIR} | 23 | ${CMAKE_SOURCE_DIR} |
| 21 | ${CMAKE_BINARY_DIR} | 24 | ${CMAKE_BINARY_DIR} |
| ... | @@ -33,6 +36,7 @@ set(ZIG_SOURCES | ... | @@ -33,6 +36,7 @@ set(ZIG_SOURCES |
| 33 | "${CMAKE_SOURCE_DIR}/src/util.cpp" | 36 | "${CMAKE_SOURCE_DIR}/src/util.cpp" |
| 34 | "${CMAKE_SOURCE_DIR}/src/errmsg.cpp" | 37 | "${CMAKE_SOURCE_DIR}/src/errmsg.cpp" |
| 35 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" | 38 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" |
| 39 | "${CMAKE_SOURCE_DIR}/src/parseh.cpp" | ||
| 36 | ) | 40 | ) |
| 37 | 41 | ||
| 38 | set(TEST_SOURCES | 42 | set(TEST_SOURCES |
| ... | @@ -64,6 +68,7 @@ set_target_properties(zig PROPERTIES | ... | @@ -64,6 +68,7 @@ set_target_properties(zig PROPERTIES |
| 64 | COMPILE_FLAGS ${EXE_CFLAGS}) | 68 | COMPILE_FLAGS ${EXE_CFLAGS}) |
| 65 | target_link_libraries(zig LINK_PUBLIC | 69 | target_link_libraries(zig LINK_PUBLIC |
| 66 | ${LLVM_LIBRARIES} | 70 | ${LLVM_LIBRARIES} |
| 71 | ${CLANG_LIBRARY} | ||
| 67 | ) | 72 | ) |
| 68 | install(TARGETS zig DESTINATION bin) | 73 | install(TARGETS zig DESTINATION bin) |
| 69 | 74 |
cmake/Findclang.cmake created+16| ... | @@ -0,0 +1,16 @@ | ||
| 1 | # Copyright (c) 2015 Andrew Kelley | ||
| 2 | # This file is MIT licensed. | ||
| 3 | # See http://opensource.org/licenses/MIT | ||
| 4 | |||
| 5 | # CLANG_FOUND | ||
| 6 | # CLANG_INCLUDE_DIR | ||
| 7 | # CLANG_LIBRARY | ||
| 8 | |||
| 9 | find_path(CLANG_INCLUDE_DIR NAMES clang-c/Index.h) | ||
| 10 | |||
| 11 | find_library(CLANG_LIBRARY NAMES clang) | ||
| 12 | |||
| 13 | include(FindPackageHandleStandardArgs) | ||
| 14 | find_package_handle_standard_args(CLANG DEFAULT_MSG CLANG_LIBRARY CLANG_INCLUDE_DIR) | ||
| 15 | |||
| 16 | mark_as_advanced(CLANG_INCLUDE_DIR CLANG_LIBRARY) | ||
src/buffer.hpp+6| ... | @@ -59,6 +59,7 @@ static inline void buf_deinit(Buf *buf) { | ... | @@ -59,6 +59,7 @@ static inline void buf_deinit(Buf *buf) { |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | static inline void buf_init_from_mem(Buf *buf, const char *ptr, int len) { | 61 | static inline void buf_init_from_mem(Buf *buf, const char *ptr, int len) { |
| 62 | assert(len >= 0); | ||
| 62 | buf->list.resize(len + 1); | 63 | buf->list.resize(len + 1); |
| 63 | memcpy(buf_ptr(buf), ptr, len); | 64 | memcpy(buf_ptr(buf), ptr, len); |
| 64 | buf->list.at(buf_len(buf)) = 0; | 65 | buf->list.at(buf_len(buf)) = 0; |
| ... | @@ -73,6 +74,7 @@ static inline void buf_init_from_buf(Buf *buf, Buf *other) { | ... | @@ -73,6 +74,7 @@ static inline void buf_init_from_buf(Buf *buf, Buf *other) { |
| 73 | } | 74 | } |
| 74 | 75 | ||
| 75 | static inline Buf *buf_create_from_mem(const char *ptr, int len) { | 76 | static inline Buf *buf_create_from_mem(const char *ptr, int len) { |
| 77 | assert(len >= 0); | ||
| 76 | Buf *buf = allocate<Buf>(1); | 78 | Buf *buf = allocate<Buf>(1); |
| 77 | buf_init_from_mem(buf, ptr, len); | 79 | buf_init_from_mem(buf, ptr, len); |
| 78 | return buf; | 80 | return buf; |
| ... | @@ -82,6 +84,10 @@ static inline Buf *buf_create_from_str(const char *str) { | ... | @@ -82,6 +84,10 @@ static inline Buf *buf_create_from_str(const char *str) { |
| 82 | return buf_create_from_mem(str, strlen(str)); | 84 | return buf_create_from_mem(str, strlen(str)); |
| 83 | } | 85 | } |
| 84 | 86 | ||
| 87 | static inline Buf *buf_create_from_buf(Buf *buf) { | ||
| 88 | return buf_create_from_mem(buf_ptr(buf), buf_len(buf)); | ||
| 89 | } | ||
| 90 | |||
| 85 | static inline Buf *buf_slice(Buf *in_buf, int start, int end) { | 91 | static inline Buf *buf_slice(Buf *in_buf, int start, int end) { |
| 86 | assert(in_buf->list.length); | 92 | assert(in_buf->list.length); |
| 87 | assert(start >= 0); | 93 | assert(start >= 0); |
src/main.cpp+106-82| ... | @@ -10,15 +10,17 @@ | ... | @@ -10,15 +10,17 @@ |
| 10 | #include "codegen.hpp" | 10 | #include "codegen.hpp" |
| 11 | #include "os.hpp" | 11 | #include "os.hpp" |
| 12 | #include "error.hpp" | 12 | #include "error.hpp" |
| 13 | #include "parseh.hpp" | ||
| 13 | 14 | ||
| 14 | #include <stdio.h> | 15 | #include <stdio.h> |
| 15 | 16 | ||
| 16 | static int usage(const char *arg0) { | 17 | static int usage(const char *arg0) { |
| 17 | fprintf(stderr, "Usage: %s [command] [options] target\n" | 18 | fprintf(stderr, "Usage: %s [command] [options]\n" |
| 18 | "Commands:\n" | 19 | "Commands:\n" |
| 19 | " build create executable, object, or library from target\n" | 20 | " build create executable, object, or library from target\n" |
| 20 | " version print version number and exit\n" | 21 | " version print version number and exit\n" |
| 21 | "Optional Options:\n" | 22 | " parseh convert a c header file to zig extern declarations\n" |
| 23 | "Command: build target\n" | ||
| 22 | " --release build with optimizations on and debug protection off\n" | 24 | " --release build with optimizations on and debug protection off\n" |
| 23 | " --static output will be statically linked\n" | 25 | " --static output will be statically linked\n" |
| 24 | " --strip exclude debug symbols\n" | 26 | " --strip exclude debug symbols\n" |
| ... | @@ -27,11 +29,15 @@ static int usage(const char *arg0) { | ... | @@ -27,11 +29,15 @@ static int usage(const char *arg0) { |
| 27 | " --output [file] override destination path\n" | 29 | " --output [file] override destination path\n" |
| 28 | " --verbose turn on compiler debug output\n" | 30 | " --verbose turn on compiler debug output\n" |
| 29 | " --color [auto|off|on] enable or disable colored error messages\n" | 31 | " --color [auto|off|on] enable or disable colored error messages\n" |
| 32 | "Command: parseh target\n" | ||
| 33 | " -isystem [dir] add additional search path for other .h files\n" | ||
| 34 | " -dirafter [dir] same as -isystem but do it last\n" | ||
| 35 | " -B[prefix] set the C compiler data path\n" | ||
| 30 | , arg0); | 36 | , arg0); |
| 31 | return EXIT_FAILURE; | 37 | return EXIT_FAILURE; |
| 32 | } | 38 | } |
| 33 | 39 | ||
| 34 | static int version(void) { | 40 | static int version(const char *arg0, int argc, char **argv) { |
| 35 | printf("%s\n", ZIG_VERSION_STRING); | 41 | printf("%s\n", ZIG_VERSION_STRING); |
| 36 | return EXIT_SUCCESS; | 42 | return EXIT_SUCCESS; |
| 37 | } | 43 | } |
| ... | @@ -48,62 +54,11 @@ struct Build { | ... | @@ -48,62 +54,11 @@ struct Build { |
| 48 | ErrColor color; | 54 | ErrColor color; |
| 49 | }; | 55 | }; |
| 50 | 56 | ||
| 51 | static int build(const char *arg0, Build *b) { | 57 | static int build(const char *arg0, int argc, char **argv) { |
| 52 | int err; | 58 | int err; |
| 53 | |||
| 54 | if (!b->in_file) | ||
| 55 | return usage(arg0); | ||
| 56 | |||
| 57 | Buf in_file_buf = BUF_INIT; | ||
| 58 | buf_init_from_str(&in_file_buf, b->in_file); | ||
| 59 | |||
| 60 | Buf root_source_dir = BUF_INIT; | ||
| 61 | Buf root_source_code = BUF_INIT; | ||
| 62 | Buf root_source_name = BUF_INIT; | ||
| 63 | if (buf_eql_str(&in_file_buf, "-")) { | ||
| 64 | os_get_cwd(&root_source_dir); | ||
| 65 | if ((err = os_fetch_file(stdin, &root_source_code))) { | ||
| 66 | fprintf(stderr, "unable to read stdin: %s\n", err_str(err)); | ||
| 67 | return 1; | ||
| 68 | } | ||
| 69 | buf_init_from_str(&root_source_name, ""); | ||
| 70 | } else { | ||
| 71 | os_path_split(&in_file_buf, &root_source_dir, &root_source_name); | ||
| 72 | if ((err = os_fetch_file_path(buf_create_from_str(b->in_file), &root_source_code))) { | ||
| 73 | fprintf(stderr, "unable to open '%s': %s\n", b->in_file, err_str(err)); | ||
| 74 | return 1; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | CodeGen *g = codegen_create(&root_source_dir); | ||
| 79 | codegen_set_build_type(g, b->release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug); | ||
| 80 | codegen_set_strip(g, b->strip); | ||
| 81 | codegen_set_is_static(g, b->is_static); | ||
| 82 | if (b->out_type != OutTypeUnknown) | ||
| 83 | codegen_set_out_type(g, b->out_type); | ||
| 84 | if (b->out_name) | ||
| 85 | codegen_set_out_name(g, buf_create_from_str(b->out_name)); | ||
| 86 | codegen_set_verbose(g, b->verbose); | ||
| 87 | codegen_set_errmsg_color(g, b->color); | ||
| 88 | codegen_add_root_code(g, &root_source_name, &root_source_code); | ||
| 89 | codegen_link(g, b->out_file); | ||
| 90 | |||
| 91 | return 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | enum Cmd { | ||
| 95 | CmdNone, | ||
| 96 | CmdBuild, | ||
| 97 | CmdVersion, | ||
| 98 | }; | ||
| 99 | |||
| 100 | int main(int argc, char **argv) { | ||
| 101 | char *arg0 = argv[0]; | ||
| 102 | |||
| 103 | Build b = {0}; | 59 | Build b = {0}; |
| 104 | Cmd cmd = CmdNone; | ||
| 105 | 60 | ||
| 106 | for (int i = 1; i < argc; i += 1) { | 61 | for (int i = 0; i < argc; i += 1) { |
| 107 | char *arg = argv[i]; | 62 | char *arg = argv[i]; |
| 108 | if (arg[0] == '-' && arg[1] == '-') { | 63 | if (arg[0] == '-' && arg[1] == '-') { |
| 109 | if (strcmp(arg, "--release") == 0) { | 64 | if (strcmp(arg, "--release") == 0) { |
| ... | @@ -148,40 +103,109 @@ int main(int argc, char **argv) { | ... | @@ -148,40 +103,109 @@ int main(int argc, char **argv) { |
| 148 | return usage(arg0); | 103 | return usage(arg0); |
| 149 | } | 104 | } |
| 150 | } | 105 | } |
| 151 | } else if (cmd == CmdNone) { | 106 | } else if (!b.in_file) { |
| 152 | if (strcmp(arg, "build") == 0) { | 107 | b.in_file = arg; |
| 153 | cmd = CmdBuild; | 108 | } else { |
| 154 | } else if (strcmp(arg, "version") == 0) { | 109 | return usage(arg0); |
| 155 | cmd = CmdVersion; | 110 | } |
| 111 | } | ||
| 112 | |||
| 113 | if (!b.in_file) | ||
| 114 | return usage(arg0); | ||
| 115 | |||
| 116 | Buf in_file_buf = BUF_INIT; | ||
| 117 | buf_init_from_str(&in_file_buf, b.in_file); | ||
| 118 | |||
| 119 | Buf root_source_dir = BUF_INIT; | ||
| 120 | Buf root_source_code = BUF_INIT; | ||
| 121 | Buf root_source_name = BUF_INIT; | ||
| 122 | if (buf_eql_str(&in_file_buf, "-")) { | ||
| 123 | os_get_cwd(&root_source_dir); | ||
| 124 | if ((err = os_fetch_file(stdin, &root_source_code))) { | ||
| 125 | fprintf(stderr, "unable to read stdin: %s\n", err_str(err)); | ||
| 126 | return 1; | ||
| 127 | } | ||
| 128 | buf_init_from_str(&root_source_name, ""); | ||
| 129 | } else { | ||
| 130 | os_path_split(&in_file_buf, &root_source_dir, &root_source_name); | ||
| 131 | if ((err = os_fetch_file_path(buf_create_from_str(b.in_file), &root_source_code))) { | ||
| 132 | fprintf(stderr, "unable to open '%s': %s\n", b.in_file, err_str(err)); | ||
| 133 | return 1; | ||
| 134 | } | ||
| 135 | } | ||
| 136 | |||
| 137 | CodeGen *g = codegen_create(&root_source_dir); | ||
| 138 | codegen_set_build_type(g, b.release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug); | ||
| 139 | codegen_set_strip(g, b.strip); | ||
| 140 | codegen_set_is_static(g, b.is_static); | ||
| 141 | if (b.out_type != OutTypeUnknown) | ||
| 142 | codegen_set_out_type(g, b.out_type); | ||
| 143 | if (b.out_name) | ||
| 144 | codegen_set_out_name(g, buf_create_from_str(b.out_name)); | ||
| 145 | codegen_set_verbose(g, b.verbose); | ||
| 146 | codegen_set_errmsg_color(g, b.color); | ||
| 147 | codegen_add_root_code(g, &root_source_name, &root_source_code); | ||
| 148 | codegen_link(g, b.out_file); | ||
| 149 | |||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | static int parseh(const char *arg0, int argc, char **argv) { | ||
| 154 | char *in_file = nullptr; | ||
| 155 | ZigList<const char *> clang_argv = {0}; | ||
| 156 | for (int i = 0; i < argc; i += 1) { | ||
| 157 | char *arg = argv[i]; | ||
| 158 | if (arg[0] == '-') { | ||
| 159 | if (arg[1] == 'I') { | ||
| 160 | clang_argv.append(arg); | ||
| 161 | } else if (strcmp(arg, "-isystem") == 0) { | ||
| 162 | if (i + 1 >= argc) { | ||
| 163 | return usage(arg0); | ||
| 164 | } | ||
| 165 | clang_argv.append("-isystem"); | ||
| 166 | clang_argv.append(argv[i + 1]); | ||
| 167 | } else if (arg[1] == 'B') { | ||
| 168 | clang_argv.append(arg); | ||
| 156 | } else { | 169 | } else { |
| 157 | fprintf(stderr, "Unrecognized command: %s\n", arg); | 170 | fprintf(stderr, "unrecognized argument: %s", arg); |
| 158 | return usage(arg0); | 171 | return usage(arg0); |
| 159 | } | 172 | } |
| 173 | } else if (!in_file) { | ||
| 174 | in_file = arg; | ||
| 160 | } else { | 175 | } else { |
| 161 | switch (cmd) { | 176 | return usage(arg0); |
| 162 | case CmdNone: | ||
| 163 | zig_unreachable(); | ||
| 164 | case CmdBuild: | ||
| 165 | if (!b.in_file) { | ||
| 166 | b.in_file = arg; | ||
| 167 | } else { | ||
| 168 | return usage(arg0); | ||
| 169 | } | ||
| 170 | break; | ||
| 171 | case CmdVersion: | ||
| 172 | return usage(arg0); | ||
| 173 | } | ||
| 174 | } | 177 | } |
| 175 | } | 178 | } |
| 179 | if (!in_file) { | ||
| 180 | fprintf(stderr, "missing target argument"); | ||
| 181 | return usage(arg0); | ||
| 182 | } | ||
| 183 | |||
| 184 | parse_h_file(in_file, &clang_argv, stdout); | ||
| 185 | return 0; | ||
| 186 | } | ||
| 176 | 187 | ||
| 177 | switch (cmd) { | 188 | int main(int argc, char **argv) { |
| 178 | case CmdNone: | 189 | char *arg0 = argv[0]; |
| 190 | int (*cmd)(const char *, int, char **) = nullptr; | ||
| 191 | for (int i = 1; i < argc; i += 1) { | ||
| 192 | char *arg = argv[i]; | ||
| 193 | if (arg[0] == '-' && arg[1] == '-') { | ||
| 179 | return usage(arg0); | 194 | return usage(arg0); |
| 180 | case CmdBuild: | 195 | } else { |
| 181 | return build(arg0, &b); | 196 | if (strcmp(arg, "build") == 0) { |
| 182 | case CmdVersion: | 197 | cmd = build; |
| 183 | return version(); | 198 | } else if (strcmp(arg, "version") == 0) { |
| 199 | cmd = version; | ||
| 200 | } else if (strcmp(arg, "parseh") == 0) { | ||
| 201 | cmd = parseh; | ||
| 202 | } else { | ||
| 203 | fprintf(stderr, "Unrecognized command: %s\n", arg); | ||
| 204 | return usage(arg0); | ||
| 205 | } | ||
| 206 | return cmd(arg0, argc - i - 1, &argv[i + 1]); | ||
| 207 | } | ||
| 184 | } | 208 | } |
| 185 | 209 | ||
| 186 | zig_unreachable(); | 210 | return usage(arg0); |
| 187 | } | 211 | } |
src/parseh.cpp created+351| ... | @@ -0,0 +1,351 @@ | ||
| 1 | #include "parseh.hpp" | ||
| 2 | |||
| 3 | #include <clang-c/Index.h> | ||
| 4 | |||
| 5 | #include <string.h> | ||
| 6 | |||
| 7 | struct Arg { | ||
| 8 | Buf name; | ||
| 9 | Buf *type; | ||
| 10 | }; | ||
| 11 | |||
| 12 | struct Fn { | ||
| 13 | Buf name; | ||
| 14 | Buf *return_type; | ||
| 15 | Arg *args; | ||
| 16 | int arg_count; | ||
| 17 | }; | ||
| 18 | |||
| 19 | struct ParseH { | ||
| 20 | FILE *f; | ||
| 21 | ZigList<Fn *> fn_list; | ||
| 22 | Fn *cur_fn; | ||
| 23 | int arg_index; | ||
| 24 | int cur_indent; | ||
| 25 | }; | ||
| 26 | |||
| 27 | static const int indent_size = 4; | ||
| 28 | |||
| 29 | static bool str_has_prefix(const char *str, const char *prefix) { | ||
| 30 | while (*prefix) { | ||
| 31 | if (*str && *str == *prefix) { | ||
| 32 | str += 1; | ||
| 33 | prefix += 1; | ||
| 34 | } else { | ||
| 35 | return false; | ||
| 36 | } | ||
| 37 | } | ||
| 38 | return true; | ||
| 39 | } | ||
| 40 | |||
| 41 | static const char *prefixes_stripped(CXType type) { | ||
| 42 | CXString name = clang_getTypeSpelling(type); | ||
| 43 | const char *c_name = clang_getCString(name); | ||
| 44 | |||
| 45 | static const char *prefixes[] = { | ||
| 46 | "struct ", | ||
| 47 | "enum ", | ||
| 48 | "const ", | ||
| 49 | }; | ||
| 50 | |||
| 51 | start_over: | ||
| 52 | |||
| 53 | for (int i = 0; i < array_length(prefixes); i += 1) { | ||
| 54 | const char *prefix = prefixes[i]; | ||
| 55 | if (str_has_prefix(c_name, prefix)) { | ||
| 56 | c_name += strlen(prefix); | ||
| 57 | goto start_over; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | return c_name; | ||
| 61 | } | ||
| 62 | |||
| 63 | static Buf *to_zig_type(CXType raw_type) { | ||
| 64 | CXType canonical = clang_getCanonicalType(raw_type); | ||
| 65 | switch (canonical.kind) { | ||
| 66 | case CXType_Invalid: | ||
| 67 | zig_unreachable(); | ||
| 68 | case CXType_Unexposed: | ||
| 69 | zig_panic("clang C api insufficient"); | ||
| 70 | case CXType_Void: | ||
| 71 | return buf_create_from_str("void"); | ||
| 72 | case CXType_Bool: | ||
| 73 | return buf_create_from_str("bool"); | ||
| 74 | case CXType_SChar: | ||
| 75 | return buf_create_from_str("i8"); | ||
| 76 | case CXType_Char_U: | ||
| 77 | case CXType_Char_S: | ||
| 78 | case CXType_UChar: | ||
| 79 | return buf_create_from_str("u8"); | ||
| 80 | case CXType_WChar: | ||
| 81 | zig_panic("TODO"); | ||
| 82 | case CXType_Char16: | ||
| 83 | zig_panic("TODO"); | ||
| 84 | case CXType_Char32: | ||
| 85 | zig_panic("TODO"); | ||
| 86 | case CXType_UShort: | ||
| 87 | return buf_create_from_str("c_ushort"); | ||
| 88 | case CXType_UInt: | ||
| 89 | return buf_create_from_str("c_uint"); | ||
| 90 | case CXType_ULong: | ||
| 91 | return buf_create_from_str("c_ulong"); | ||
| 92 | case CXType_ULongLong: | ||
| 93 | return buf_create_from_str("c_ulonglong"); | ||
| 94 | case CXType_UInt128: | ||
| 95 | zig_panic("TODO"); | ||
| 96 | case CXType_Short: | ||
| 97 | return buf_create_from_str("c_short"); | ||
| 98 | case CXType_Int: | ||
| 99 | return buf_create_from_str("c_int"); | ||
| 100 | case CXType_Long: | ||
| 101 | return buf_create_from_str("c_long"); | ||
| 102 | case CXType_LongLong: | ||
| 103 | return buf_create_from_str("c_longlong"); | ||
| 104 | case CXType_Int128: | ||
| 105 | zig_panic("TODO"); | ||
| 106 | case CXType_Float: | ||
| 107 | return buf_create_from_str("f32"); | ||
| 108 | case CXType_Double: | ||
| 109 | return buf_create_from_str("f64"); | ||
| 110 | case CXType_LongDouble: | ||
| 111 | return buf_create_from_str("f128"); | ||
| 112 | case CXType_NullPtr: | ||
| 113 | zig_panic("TODO"); | ||
| 114 | case CXType_Overload: | ||
| 115 | zig_panic("TODO"); | ||
| 116 | case CXType_Dependent: | ||
| 117 | zig_panic("TODO"); | ||
| 118 | case CXType_ObjCId: | ||
| 119 | zig_panic("TODO"); | ||
| 120 | case CXType_ObjCClass: | ||
| 121 | zig_panic("TODO"); | ||
| 122 | case CXType_ObjCSel: | ||
| 123 | zig_panic("TODO"); | ||
| 124 | case CXType_Complex: | ||
| 125 | zig_panic("TODO"); | ||
| 126 | case CXType_Pointer: | ||
| 127 | { | ||
| 128 | CXType pointee_type = clang_getPointeeType(canonical); | ||
| 129 | Buf *pointee_buf = to_zig_type(pointee_type); | ||
| 130 | if (clang_isConstQualifiedType(pointee_type)) { | ||
| 131 | return buf_sprintf("*const %s", buf_ptr(pointee_buf)); | ||
| 132 | } else { | ||
| 133 | return buf_sprintf("*mut %s", buf_ptr(pointee_buf)); | ||
| 134 | } | ||
| 135 | } | ||
| 136 | case CXType_BlockPointer: | ||
| 137 | zig_panic("TODO"); | ||
| 138 | case CXType_LValueReference: | ||
| 139 | zig_panic("TODO"); | ||
| 140 | case CXType_RValueReference: | ||
| 141 | zig_panic("TODO"); | ||
| 142 | case CXType_Record: | ||
| 143 | { | ||
| 144 | const char *name = prefixes_stripped(canonical); | ||
| 145 | return buf_sprintf("%s", name); | ||
| 146 | } | ||
| 147 | case CXType_Enum: | ||
| 148 | { | ||
| 149 | const char *name = prefixes_stripped(canonical); | ||
| 150 | return buf_sprintf("%s", name); | ||
| 151 | } | ||
| 152 | case CXType_Typedef: | ||
| 153 | zig_panic("TODO"); | ||
| 154 | case CXType_ObjCInterface: | ||
| 155 | zig_panic("TODO"); | ||
| 156 | case CXType_ObjCObjectPointer: | ||
| 157 | zig_panic("TODO"); | ||
| 158 | case CXType_FunctionNoProto: | ||
| 159 | zig_panic("TODO"); | ||
| 160 | case CXType_FunctionProto: | ||
| 161 | zig_panic("TODO"); | ||
| 162 | case CXType_ConstantArray: | ||
| 163 | zig_panic("TODO"); | ||
| 164 | case CXType_Vector: | ||
| 165 | zig_panic("TODO"); | ||
| 166 | case CXType_IncompleteArray: | ||
| 167 | zig_panic("TODO"); | ||
| 168 | case CXType_VariableArray: | ||
| 169 | zig_panic("TODO"); | ||
| 170 | case CXType_DependentSizedArray: | ||
| 171 | zig_panic("TODO"); | ||
| 172 | case CXType_MemberPointer: | ||
| 173 | zig_panic("TODO"); | ||
| 174 | } | ||
| 175 | |||
| 176 | zig_unreachable(); | ||
| 177 | } | ||
| 178 | |||
| 179 | static bool is_storage_class_export(CX_StorageClass storage_class) { | ||
| 180 | switch (storage_class) { | ||
| 181 | case CX_SC_Invalid: | ||
| 182 | zig_unreachable(); | ||
| 183 | case CX_SC_None: | ||
| 184 | case CX_SC_Extern: | ||
| 185 | case CX_SC_Auto: | ||
| 186 | return true; | ||
| 187 | case CX_SC_Static: | ||
| 188 | case CX_SC_PrivateExtern: | ||
| 189 | case CX_SC_OpenCLWorkGroupLocal: | ||
| 190 | case CX_SC_Register: | ||
| 191 | return false; | ||
| 192 | } | ||
| 193 | zig_unreachable(); | ||
| 194 | } | ||
| 195 | |||
| 196 | static void begin_fn(ParseH *p) { | ||
| 197 | assert(!p->cur_fn); | ||
| 198 | p->cur_fn = allocate<Fn>(1); | ||
| 199 | } | ||
| 200 | |||
| 201 | static void end_fn(ParseH *p) { | ||
| 202 | if (p->cur_fn) { | ||
| 203 | p->fn_list.append(p->cur_fn); | ||
| 204 | p->cur_fn = nullptr; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXClientData client_data) { | ||
| 209 | ParseH *p = (ParseH*)client_data; | ||
| 210 | enum CXCursorKind kind = clang_getCursorKind(cursor); | ||
| 211 | CXString name = clang_getCursorSpelling(cursor); | ||
| 212 | |||
| 213 | switch (kind) { | ||
| 214 | case CXCursor_FunctionDecl: | ||
| 215 | { | ||
| 216 | CX_StorageClass storage_class = clang_Cursor_getStorageClass(cursor); | ||
| 217 | if (!is_storage_class_export(storage_class)) | ||
| 218 | return CXChildVisit_Continue; | ||
| 219 | |||
| 220 | end_fn(p); | ||
| 221 | begin_fn(p); | ||
| 222 | |||
| 223 | CXType fn_type = clang_getCursorType(cursor); | ||
| 224 | if (clang_isFunctionTypeVariadic(fn_type)) { | ||
| 225 | zig_panic("TODO support variadic function"); | ||
| 226 | } | ||
| 227 | if (clang_getFunctionTypeCallingConv(fn_type) != CXCallingConv_C) { | ||
| 228 | zig_panic("TODO support non c calling convention"); | ||
| 229 | } | ||
| 230 | CXType return_type = clang_getResultType(fn_type); | ||
| 231 | p->cur_fn->return_type = to_zig_type(return_type); | ||
| 232 | |||
| 233 | buf_init_from_str(&p->cur_fn->name, clang_getCString(name)); | ||
| 234 | |||
| 235 | p->cur_fn->arg_count = clang_getNumArgTypes(fn_type); | ||
| 236 | p->cur_fn->args = allocate<Arg>(p->cur_fn->arg_count); | ||
| 237 | |||
| 238 | for (int i = 0; i < p->cur_fn->arg_count; i += 1) { | ||
| 239 | CXType param_type = clang_getArgType(fn_type, i); | ||
| 240 | p->cur_fn->args[i].type = to_zig_type(param_type); | ||
| 241 | } | ||
| 242 | |||
| 243 | p->arg_index = 0; | ||
| 244 | |||
| 245 | return CXChildVisit_Recurse; | ||
| 246 | } | ||
| 247 | case CXCursor_ParmDecl: | ||
| 248 | { | ||
| 249 | assert(p->cur_fn); | ||
| 250 | assert(p->arg_index < p->cur_fn->arg_count); | ||
| 251 | buf_init_from_str(&p->cur_fn->args[p->arg_index].name, clang_getCString(name)); | ||
| 252 | p->arg_index += 1; | ||
| 253 | return CXChildVisit_Continue; | ||
| 254 | } | ||
| 255 | case CXCursor_UnexposedAttr: | ||
| 256 | case CXCursor_CompoundStmt: | ||
| 257 | case CXCursor_FieldDecl: | ||
| 258 | return CXChildVisit_Continue; | ||
| 259 | default: | ||
| 260 | return CXChildVisit_Recurse; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 264 | static void print_indent(ParseH *p) { | ||
| 265 | for (int i = 0; i < p->cur_indent; i += 1) { | ||
| 266 | fprintf(p->f, " "); | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FILE *f) { | ||
| 271 | ParseH parse_h = {0}; | ||
| 272 | ParseH *p = &parse_h; | ||
| 273 | p->f = f; | ||
| 274 | CXTranslationUnit tu; | ||
| 275 | CXIndex index = clang_createIndex(1, 0); | ||
| 276 | |||
| 277 | char *ZIG_PARSEH_CFLAGS = getenv("ZIG_PARSEH_CFLAGS"); | ||
| 278 | if (ZIG_PARSEH_CFLAGS) { | ||
| 279 | Buf tmp_buf = {0}; | ||
| 280 | char *start = ZIG_PARSEH_CFLAGS; | ||
| 281 | char *space = strstr(start, " "); | ||
| 282 | while (space) { | ||
| 283 | if (space - start > 0) { | ||
| 284 | buf_init_from_mem(&tmp_buf, start, space - start); | ||
| 285 | clang_argv->append(buf_ptr(buf_create_from_buf(&tmp_buf))); | ||
| 286 | } | ||
| 287 | start = space + 1; | ||
| 288 | space = strstr(start, " "); | ||
| 289 | } | ||
| 290 | buf_init_from_str(&tmp_buf, start); | ||
| 291 | clang_argv->append(buf_ptr(buf_create_from_buf(&tmp_buf))); | ||
| 292 | } | ||
| 293 | |||
| 294 | clang_argv->append(nullptr); | ||
| 295 | |||
| 296 | enum CXErrorCode err_code; | ||
| 297 | if ((err_code = clang_parseTranslationUnit2(index, target_path, | ||
| 298 | clang_argv->items, clang_argv->length - 1, | ||
| 299 | NULL, 0, CXTranslationUnit_None, &tu))) | ||
| 300 | { | ||
| 301 | zig_panic("parse translation unit failure"); | ||
| 302 | } | ||
| 303 | |||
| 304 | |||
| 305 | unsigned diag_count = clang_getNumDiagnostics(tu); | ||
| 306 | |||
| 307 | if (diag_count > 0) { | ||
| 308 | for (unsigned i = 0; i < diag_count; i += 1) { | ||
| 309 | CXDiagnostic diagnostic = clang_getDiagnostic(tu, i); | ||
| 310 | CXSourceLocation location = clang_getDiagnosticLocation(diagnostic); | ||
| 311 | |||
| 312 | CXFile file; | ||
| 313 | unsigned line, column, offset; | ||
| 314 | clang_getSpellingLocation(location, &file, &line, &column, &offset); | ||
| 315 | CXString text = clang_getDiagnosticSpelling(diagnostic); | ||
| 316 | CXString file_name = clang_getFileName(file); | ||
| 317 | fprintf(stderr, "%s line %u, column %u: %s\n", clang_getCString(file_name), | ||
| 318 | line, column, clang_getCString(text)); | ||
| 319 | } | ||
| 320 | |||
| 321 | exit(1); | ||
| 322 | } | ||
| 323 | |||
| 324 | |||
| 325 | CXCursor cursor = clang_getTranslationUnitCursor(tu); | ||
| 326 | clang_visitChildren(cursor, fn_visitor, p); | ||
| 327 | end_fn(p); | ||
| 328 | |||
| 329 | if (p->fn_list.length) { | ||
| 330 | fprintf(f, "extern {\n"); | ||
| 331 | p->cur_indent += indent_size; | ||
| 332 | for (int fn_i = 0; fn_i < p->fn_list.length; fn_i += 1) { | ||
| 333 | Fn *fn = p->fn_list.at(fn_i); | ||
| 334 | print_indent(p); | ||
| 335 | fprintf(p->f, "fn %s(", buf_ptr(&fn->name)); | ||
| 336 | for (int arg_i = 0; arg_i < fn->arg_count; arg_i += 1) { | ||
| 337 | Arg *arg = &fn->args[arg_i]; | ||
| 338 | fprintf(p->f, "%s: %s", buf_ptr(&arg->name), buf_ptr(arg->type)); | ||
| 339 | if (arg_i + 1 < fn->arg_count) { | ||
| 340 | fprintf(p->f, ", "); | ||
| 341 | } | ||
| 342 | } | ||
| 343 | fprintf(p->f, ")"); | ||
| 344 | if (!buf_eql_str(fn->return_type, "void")) { | ||
| 345 | fprintf(p->f, " -> %s", buf_ptr(fn->return_type)); | ||
| 346 | } | ||
| 347 | fprintf(p->f, ";\n"); | ||
| 348 | } | ||
| 349 | fprintf(f, "}\n"); | ||
| 350 | } | ||
| 351 | } | ||
src/parseh.hpp created+18| ... | @@ -0,0 +1,18 @@ | ||
| 1 | /* | ||
| 2 | * Copyright (c) 2015 Andrew Kelley | ||
| 3 | * | ||
| 4 | * This file is part of zig, which is MIT licensed. | ||
| 5 | * See http://opensource.org/licenses/MIT | ||
| 6 | */ | ||
| 7 | |||
| 8 | |||
| 9 | #ifndef ZIG_PARSEH_HPP | ||
| 10 | #define ZIG_PARSEH_HPP | ||
| 11 | |||
| 12 | #include "buffer.hpp" | ||
| 13 | |||
| 14 | #include <stdio.h> | ||
| 15 | |||
| 16 | void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FILE *f); | ||
| 17 | |||
| 18 | #endif | ||