| 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 | 16 | include_directories(${LLVM_INCLUDE_DIRS}) |
| 17 | 17 | link_directories(${LLVM_LIBDIRS}) |
| 18 | 18 | |
| 19 | find_package(clang) | |
| 20 | include_directories(${CLANG_INCLUDE_DIR}) | |
| 21 | ||
| 19 | 22 | include_directories( |
| 20 | 23 | ${CMAKE_SOURCE_DIR} |
| 21 | 24 | ${CMAKE_BINARY_DIR} |
| ... | ... | @@ -33,6 +36,7 @@ set(ZIG_SOURCES |
| 33 | 36 | "${CMAKE_SOURCE_DIR}/src/util.cpp" |
| 34 | 37 | "${CMAKE_SOURCE_DIR}/src/errmsg.cpp" |
| 35 | 38 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" |
| 39 | "${CMAKE_SOURCE_DIR}/src/parseh.cpp" | |
| 36 | 40 | ) |
| 37 | 41 | |
| 38 | 42 | set(TEST_SOURCES |
| ... | ... | @@ -64,6 +68,7 @@ set_target_properties(zig PROPERTIES |
| 64 | 68 | COMPILE_FLAGS ${EXE_CFLAGS}) |
| 65 | 69 | target_link_libraries(zig LINK_PUBLIC |
| 66 | 70 | ${LLVM_LIBRARIES} |
| 71 | ${CLANG_LIBRARY} | |
| 67 | 72 | ) |
| 68 | 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 | 59 | } |
| 60 | 60 | |
| 61 | 61 | static inline void buf_init_from_mem(Buf *buf, const char *ptr, int len) { |
| 62 | assert(len >= 0); | |
| 62 | 63 | buf->list.resize(len + 1); |
| 63 | 64 | memcpy(buf_ptr(buf), ptr, len); |
| 64 | 65 | buf->list.at(buf_len(buf)) = 0; |
| ... | ... | @@ -73,6 +74,7 @@ static inline void buf_init_from_buf(Buf *buf, Buf *other) { |
| 73 | 74 | } |
| 74 | 75 | |
| 75 | 76 | static inline Buf *buf_create_from_mem(const char *ptr, int len) { |
| 77 | assert(len >= 0); | |
| 76 | 78 | Buf *buf = allocate<Buf>(1); |
| 77 | 79 | buf_init_from_mem(buf, ptr, len); |
| 78 | 80 | return buf; |
| ... | ... | @@ -82,6 +84,10 @@ static inline Buf *buf_create_from_str(const char *str) { |
| 82 | 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 | 91 | static inline Buf *buf_slice(Buf *in_buf, int start, int end) { |
| 86 | 92 | assert(in_buf->list.length); |
| 87 | 93 | assert(start >= 0); |
src/main.cpp+106-82| ... | ... | @@ -10,15 +10,17 @@ |
| 10 | 10 | #include "codegen.hpp" |
| 11 | 11 | #include "os.hpp" |
| 12 | 12 | #include "error.hpp" |
| 13 | #include "parseh.hpp" | |
| 13 | 14 | |
| 14 | 15 | #include <stdio.h> |
| 15 | 16 | |
| 16 | 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 | 19 | "Commands:\n" |
| 19 | 20 | " build create executable, object, or library from target\n" |
| 20 | 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 | 24 | " --release build with optimizations on and debug protection off\n" |
| 23 | 25 | " --static output will be statically linked\n" |
| 24 | 26 | " --strip exclude debug symbols\n" |
| ... | ... | @@ -27,11 +29,15 @@ static int usage(const char *arg0) { |
| 27 | 29 | " --output [file] override destination path\n" |
| 28 | 30 | " --verbose turn on compiler debug output\n" |
| 29 | 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 | 36 | , arg0); |
| 31 | 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 | 41 | printf("%s\n", ZIG_VERSION_STRING); |
| 36 | 42 | return EXIT_SUCCESS; |
| 37 | 43 | } |
| ... | ... | @@ -48,62 +54,11 @@ struct Build { |
| 48 | 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 | 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 | 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 | 62 | char *arg = argv[i]; |
| 108 | 63 | if (arg[0] == '-' && arg[1] == '-') { |
| 109 | 64 | if (strcmp(arg, "--release") == 0) { |
| ... | ... | @@ -148,40 +103,109 @@ int main(int argc, char **argv) { |
| 148 | 103 | return usage(arg0); |
| 149 | 104 | } |
| 150 | 105 | } |
| 151 | } else if (cmd == CmdNone) { | |
| 152 | if (strcmp(arg, "build") == 0) { | |
| 153 | cmd = CmdBuild; | |
| 154 | } else if (strcmp(arg, "version") == 0) { | |
| 155 | cmd = CmdVersion; | |
| 106 | } else if (!b.in_file) { | |
| 107 | b.in_file = arg; | |
| 108 | } else { | |
| 109 | return usage(arg0); | |
| 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 | 169 | } else { |
| 157 | fprintf(stderr, "Unrecognized command: %s\n", arg); | |
| 170 | fprintf(stderr, "unrecognized argument: %s", arg); | |
| 158 | 171 | return usage(arg0); |
| 159 | 172 | } |
| 173 | } else if (!in_file) { | |
| 174 | in_file = arg; | |
| 160 | 175 | } else { |
| 161 | switch (cmd) { | |
| 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 | } | |
| 176 | return usage(arg0); | |
| 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) { | |
| 178 | case CmdNone: | |
| 188 | int main(int argc, char **argv) { | |
| 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 | 194 | return usage(arg0); |
| 180 | case CmdBuild: | |
| 181 | return build(arg0, &b); | |
| 182 | case CmdVersion: | |
| 183 | return version(); | |
| 195 | } else { | |
| 196 | if (strcmp(arg, "build") == 0) { | |
| 197 | cmd = build; | |
| 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 |