upgrade to the libclang C++ API
c_import creates a tmp .h file and parses it with libclang, reporting any errors found. See #88master
parent
ac085a869d
commit
0278468479
|
@ -17,7 +17,7 @@ include_directories(${LLVM_INCLUDE_DIRS})
|
|||
link_directories(${LLVM_LIBDIRS})
|
||||
|
||||
find_package(clang)
|
||||
include_directories(${CLANG_INCLUDE_DIR})
|
||||
include_directories(${CLANG_INCLUDE_DIRS})
|
||||
|
||||
include_directories(
|
||||
${CMAKE_SOURCE_DIR}
|
||||
|
@ -148,7 +148,7 @@ set_target_properties(zig PROPERTIES
|
|||
COMPILE_FLAGS ${EXE_CFLAGS})
|
||||
target_link_libraries(zig LINK_PUBLIC
|
||||
${LLVM_LIBRARIES}
|
||||
${CLANG_LIBRARY}
|
||||
${CLANG_LIBRARIES}
|
||||
)
|
||||
install(TARGETS zig DESTINATION bin)
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ be set to (example below).
|
|||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_DIR=$(dirname $(cc -print-file-name=crt1.o))
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_DIR=$(dirname $(dirname $(cc -print-file-name=crt1.o)))
|
||||
make
|
||||
make install
|
||||
./run_tests
|
||||
|
|
|
@ -1,16 +1,34 @@
|
|||
# Copyright (c) 2015 Andrew Kelley
|
||||
# Copyright (c) 2016 Andrew Kelley
|
||||
# This file is MIT licensed.
|
||||
# See http://opensource.org/licenses/MIT
|
||||
|
||||
# CLANG_FOUND
|
||||
# CLANG_INCLUDE_DIR
|
||||
# CLANG_LIBRARY
|
||||
# CLANG_INCLUDE_DIRS
|
||||
# CLANG_LIBRARIES
|
||||
|
||||
find_path(CLANG_INCLUDE_DIR NAMES clang-c/Index.h PATHS /usr/lib/llvm-3.7/include/)
|
||||
find_path(CLANG_INCLUDE_DIRS NAMES clang/Frontend/ASTUnit.h)
|
||||
|
||||
find_library(CLANG_LIBRARY NAMES clang PATHS /usr/lib/llvm-3.7/lib/)
|
||||
macro(FIND_AND_ADD_CLANG_LIB _libname_)
|
||||
string(TOUPPER ${_libname_} _prettylibname_)
|
||||
find_library(CLANG_${_prettylibname_}_LIB NAMES ${_libname_})
|
||||
if(CLANG_${_prettylibname_}_LIB)
|
||||
set(CLANG_LIBRARIES ${CLANG_LIBRARIES} ${CLANG_${_prettylibname_}_LIB})
|
||||
endif()
|
||||
endmacro(FIND_AND_ADD_CLANG_LIB)
|
||||
|
||||
FIND_AND_ADD_CLANG_LIB(clangFrontend)
|
||||
FIND_AND_ADD_CLANG_LIB(clangDriver)
|
||||
FIND_AND_ADD_CLANG_LIB(clangSerialization)
|
||||
FIND_AND_ADD_CLANG_LIB(clangSema)
|
||||
FIND_AND_ADD_CLANG_LIB(clangAnalysis)
|
||||
FIND_AND_ADD_CLANG_LIB(clangAST)
|
||||
FIND_AND_ADD_CLANG_LIB(clangParse)
|
||||
FIND_AND_ADD_CLANG_LIB(clangSema)
|
||||
FIND_AND_ADD_CLANG_LIB(clangBasic)
|
||||
FIND_AND_ADD_CLANG_LIB(clangEdit)
|
||||
FIND_AND_ADD_CLANG_LIB(clangLex)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(CLANG DEFAULT_MSG CLANG_LIBRARY CLANG_INCLUDE_DIR)
|
||||
find_package_handle_standard_args(CLANG DEFAULT_MSG CLANG_LIBRARIES CLANG_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(CLANG_INCLUDE_DIR CLANG_LIBRARY)
|
||||
mark_as_advanced(CLANG_INCLUDE_DIRS CLANG_LIBRARIES)
|
||||
|
|
|
@ -995,6 +995,8 @@ struct CodeGen {
|
|||
bool have_exported_main;
|
||||
bool link_libc;
|
||||
Buf *libc_path;
|
||||
Buf *libc_lib_path;
|
||||
Buf *libc_include_path;
|
||||
CodeGenBuildType build_type;
|
||||
LLVMTargetMachineRef target_machine;
|
||||
LLVMZigDIFile *dummy_di_file;
|
||||
|
@ -1068,4 +1070,12 @@ struct BlockContext {
|
|||
Buf *c_import_buf;
|
||||
};
|
||||
|
||||
struct ParseH {
|
||||
ZigList<ErrorMsg*> errors;
|
||||
ZigList<AstNode *> fn_list;
|
||||
ZigList<AstNode *> struct_list;
|
||||
ZigList<AstNode *> var_list;
|
||||
ZigList<AstNode *> incomplete_struct_list;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "error.hpp"
|
||||
#include "zig_llvm.hpp"
|
||||
#include "os.hpp"
|
||||
#include "parseh.hpp"
|
||||
#include "config.h"
|
||||
|
||||
static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
TypeTableEntry *expected_type, AstNode *node);
|
||||
|
@ -83,18 +85,12 @@ static AstNode *first_executing_node(AstNode *node) {
|
|||
zig_unreachable();
|
||||
}
|
||||
|
||||
void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
|
||||
ErrorMsg *err = allocate<ErrorMsg>(1);
|
||||
err->line_start = node->line;
|
||||
err->column_start = node->column;
|
||||
err->line_end = -1;
|
||||
err->column_end = -1;
|
||||
err->msg = msg;
|
||||
err->path = node->owner->path;
|
||||
err->source = node->owner->source_code;
|
||||
err->line_offsets = node->owner->line_offsets;
|
||||
ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
|
||||
ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column,
|
||||
node->owner->source_code, node->owner->line_offsets, msg);
|
||||
|
||||
g->errors.append(err);
|
||||
return err;
|
||||
}
|
||||
|
||||
TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
|
||||
|
@ -1036,8 +1032,22 @@ static void resolve_c_import_decl(CodeGen *g, ImportTableEntry *import, AstNode
|
|||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "c import buf:\n%s\n", buf_ptr(child_context->c_import_buf));
|
||||
zig_panic("TODO");
|
||||
find_libc_path(g);
|
||||
int err;
|
||||
ParseH parse_h = {{0}};
|
||||
if ((err = parse_h_buf(&parse_h, child_context->c_import_buf, buf_ptr(g->libc_include_path)))) {
|
||||
zig_panic("unable to parse h file: %s\n", err_str(err));
|
||||
}
|
||||
|
||||
if (parse_h.errors.length > 0) {
|
||||
ErrorMsg *parent_err_msg = add_node_error(g, node, buf_sprintf("C import failed"));
|
||||
for (int i = 0; i < parse_h.errors.length; i += 1) {
|
||||
ErrorMsg *err_msg = parse_h.errors.at(i);
|
||||
err_msg_add_note(parent_err_msg, err_msg);
|
||||
}
|
||||
} else {
|
||||
zig_panic("TODO integrate the parsed AST");
|
||||
}
|
||||
}
|
||||
|
||||
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
|
|||
return g->builtin_types.entry_void;
|
||||
}
|
||||
|
||||
buf_appendf(context->c_import_buf, "#include \"");
|
||||
buf_appendf(context->c_import_buf, "#include <");
|
||||
ConstExprValue *ptr_field = const_str_val->data.x_struct.fields[0];
|
||||
uint64_t len = ptr_field->data.x_ptr.len;
|
||||
for (uint64_t i = 0; i < len; i += 1) {
|
||||
|
@ -3454,7 +3464,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
|
|||
uint8_t c = big_c;
|
||||
buf_appendf(context->c_import_buf, "%c", c);
|
||||
}
|
||||
buf_appendf(context->c_import_buf, "\"\n");
|
||||
buf_appendf(context->c_import_buf, ">\n");
|
||||
|
||||
return g->builtin_types.entry_void;
|
||||
}
|
||||
|
@ -4976,3 +4986,22 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
|
|||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
void find_libc_path(CodeGen *g) {
|
||||
if (!g->libc_path || buf_len(g->libc_path) == 0) {
|
||||
g->libc_path = buf_create_from_str(ZIG_LIBC_DIR);
|
||||
if (!g->libc_path || buf_len(g->libc_path) == 0) {
|
||||
// later we can handle this better by reporting an error via the normal mechanism
|
||||
zig_panic("Unable to determine libc path. You can use `--libc-path`");
|
||||
}
|
||||
}
|
||||
if (!g->libc_lib_path) {
|
||||
g->libc_lib_path = buf_alloc();
|
||||
os_path_join(g->libc_path, buf_create_from_str("lib"), g->libc_lib_path);
|
||||
}
|
||||
if (!g->libc_include_path) {
|
||||
g->libc_include_path = buf_alloc();
|
||||
os_path_join(g->libc_path, buf_create_from_str("include"), g->libc_include_path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include "all_types.hpp"
|
||||
|
||||
void semantic_analyze(CodeGen *g);
|
||||
void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
|
||||
ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg);
|
||||
TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
|
||||
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
|
||||
VariableTableEntry *find_variable(BlockContext *context, Buf *name);
|
||||
|
@ -23,4 +23,6 @@ bool is_node_void_expr(AstNode *node);
|
|||
TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits);
|
||||
TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits);
|
||||
bool handle_is_ptr(TypeTableEntry *type_entry);
|
||||
void find_libc_path(CodeGen *g);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3051,15 +3051,8 @@ static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
|
|||
tokenize(source_code, &tokenization);
|
||||
|
||||
if (tokenization.err) {
|
||||
ErrorMsg *err = allocate<ErrorMsg>(1);
|
||||
err->line_start = tokenization.err_line;
|
||||
err->column_start = tokenization.err_column;
|
||||
err->line_end = -1;
|
||||
err->column_end = -1;
|
||||
err->msg = tokenization.err;
|
||||
err->path = full_path;
|
||||
err->source = source_code;
|
||||
err->line_offsets = tokenization.line_offsets;
|
||||
ErrorMsg *err = err_msg_create_with_line(full_path, tokenization.err_line, tokenization.err_column,
|
||||
source_code, tokenization.line_offsets, tokenization.err);
|
||||
|
||||
print_err_msg(err, g->err_color);
|
||||
exit(1);
|
||||
|
@ -3401,19 +3394,9 @@ static void generate_h_file(CodeGen *g) {
|
|||
zig_panic("unable to close h file: %s", strerror(errno));
|
||||
}
|
||||
|
||||
static void find_libc_path(CodeGen *g) {
|
||||
if (g->libc_path && buf_len(g->libc_path))
|
||||
return;
|
||||
g->libc_path = buf_create_from_str(ZIG_LIBC_DIR);
|
||||
if (g->libc_path && buf_len(g->libc_path))
|
||||
return;
|
||||
fprintf(stderr, "Unable to determine libc path. Consider using `--libc-path [path]`\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static const char *get_libc_file(CodeGen *g, const char *file) {
|
||||
Buf *out_buf = buf_alloc();
|
||||
os_path_join(g->libc_path, buf_create_from_str(file), out_buf);
|
||||
os_path_join(g->libc_lib_path, buf_create_from_str(file), out_buf);
|
||||
return buf_ptr(out_buf);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,16 +15,7 @@ void print_err_msg(ErrorMsg *err, ErrColor color) {
|
|||
err->line_start + 1, err->column_start + 1,
|
||||
buf_ptr(err->msg));
|
||||
|
||||
assert(err->source);
|
||||
assert(err->line_offsets);
|
||||
|
||||
int line_start_offset = err->line_offsets->at(err->line_start);
|
||||
int end_line = err->line_start + 1;
|
||||
int line_end_offset = (end_line >= err->line_offsets->length) ?
|
||||
buf_len(err->source) : err->line_offsets->at(err->line_start + 1);
|
||||
|
||||
fwrite(buf_ptr(err->source) + line_start_offset, 1, line_end_offset - line_start_offset - 1, stderr);
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "%s\n", buf_ptr(&err->line_buf));
|
||||
for (int i = 0; i < err->column_start; i += 1) {
|
||||
fprintf(stderr, " ");
|
||||
}
|
||||
|
@ -36,5 +27,62 @@ void print_err_msg(ErrorMsg *err, ErrColor color) {
|
|||
err->line_start + 1, err->column_start + 1,
|
||||
buf_ptr(err->msg));
|
||||
}
|
||||
|
||||
for (int i = 0; i < err->notes.length; i += 1) {
|
||||
ErrorMsg *note = err->notes.at(i);
|
||||
print_err_msg(note, color);
|
||||
}
|
||||
}
|
||||
|
||||
void err_msg_add_note(ErrorMsg *parent, ErrorMsg *note) {
|
||||
parent->notes.append(note);
|
||||
}
|
||||
|
||||
ErrorMsg *err_msg_create_with_offset(Buf *path, int line, int column, int offset,
|
||||
const char *source, Buf *msg)
|
||||
{
|
||||
ErrorMsg *err_msg = allocate<ErrorMsg>(1);
|
||||
err_msg->path = path;
|
||||
err_msg->line_start = line;
|
||||
err_msg->column_start = column;
|
||||
err_msg->msg = msg;
|
||||
|
||||
int line_start_offset = offset;
|
||||
for (;;) {
|
||||
if (line_start_offset == 0) {
|
||||
break;
|
||||
} else if (source[line_start_offset] == '\n') {
|
||||
line_start_offset += 1;
|
||||
break;
|
||||
}
|
||||
line_start_offset -= 1;
|
||||
}
|
||||
|
||||
int line_end_offset = offset;
|
||||
while (source[line_end_offset] && source[line_end_offset] != '\n') {
|
||||
line_end_offset += 1;
|
||||
}
|
||||
|
||||
buf_init_from_mem(&err_msg->line_buf, source + line_start_offset, line_end_offset - line_start_offset);
|
||||
|
||||
return err_msg;
|
||||
}
|
||||
|
||||
ErrorMsg *err_msg_create_with_line(Buf *path, int line, int column,
|
||||
Buf *source, ZigList<int> *line_offsets, Buf *msg)
|
||||
{
|
||||
ErrorMsg *err_msg = allocate<ErrorMsg>(1);
|
||||
err_msg->path = path;
|
||||
err_msg->line_start = line;
|
||||
err_msg->column_start = column;
|
||||
err_msg->msg = msg;
|
||||
|
||||
int line_start_offset = line_offsets->at(line);
|
||||
int end_line = line + 1;
|
||||
int line_end_offset = (end_line >= line_offsets->length) ? buf_len(source) : line_offsets->at(line + 1);
|
||||
|
||||
buf_init_from_mem(&err_msg->line_buf, buf_ptr(source) + line_start_offset,
|
||||
line_end_offset - line_start_offset - 1);
|
||||
|
||||
return err_msg;
|
||||
}
|
||||
|
|
|
@ -20,14 +20,20 @@ enum ErrColor {
|
|||
struct ErrorMsg {
|
||||
int line_start;
|
||||
int column_start;
|
||||
int line_end;
|
||||
int column_end;
|
||||
Buf *msg;
|
||||
Buf *path;
|
||||
Buf *source;
|
||||
ZigList<int> *line_offsets;
|
||||
Buf line_buf;
|
||||
|
||||
ZigList<ErrorMsg *> notes;
|
||||
};
|
||||
|
||||
void print_err_msg(ErrorMsg *msg, ErrColor color);
|
||||
|
||||
void err_msg_add_note(ErrorMsg *parent, ErrorMsg *note);
|
||||
ErrorMsg *err_msg_create_with_offset(Buf *path, int line, int column, int offset,
|
||||
const char *source, Buf *msg);
|
||||
|
||||
ErrorMsg *err_msg_create_with_line(Buf *path, int line, int column,
|
||||
Buf *source, ZigList<int> *line_offsets, Buf *msg);
|
||||
|
||||
#endif
|
||||
|
|
87
src/main.cpp
87
src/main.cpp
|
@ -156,6 +156,25 @@ static int build(const char *arg0, int argc, char **argv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct ParseHPrint {
|
||||
ParseH parse_h;
|
||||
FILE *f;
|
||||
int cur_indent;
|
||||
};
|
||||
|
||||
static const int indent_size = 4;
|
||||
|
||||
static void print_indent(ParseHPrint *p) {
|
||||
for (int i = 0; i < p->cur_indent; i += 1) {
|
||||
fprintf(p->f, " ");
|
||||
}
|
||||
}
|
||||
|
||||
static const char *type_node_to_name(AstNode *type_node) {
|
||||
assert(type_node->type == NodeTypeSymbol);
|
||||
return buf_ptr(&type_node->data.symbol_expr.symbol);
|
||||
}
|
||||
|
||||
static int parseh(const char *arg0, int argc, char **argv) {
|
||||
char *in_file = nullptr;
|
||||
ZigList<const char *> clang_argv = {0};
|
||||
|
@ -187,7 +206,73 @@ static int parseh(const char *arg0, int argc, char **argv) {
|
|||
return usage(arg0);
|
||||
}
|
||||
|
||||
parse_h_file(in_file, &clang_argv, stdout);
|
||||
clang_argv.append(in_file);
|
||||
|
||||
ParseHPrint parse_h_print = {{{0}}};
|
||||
ParseHPrint *p = &parse_h_print;
|
||||
p->f = stdout;
|
||||
p->cur_indent = 0;
|
||||
|
||||
parse_h_file(&p->parse_h, &clang_argv);
|
||||
|
||||
if (p->parse_h.errors.length > 0) {
|
||||
for (int i = 0; i < p->parse_h.errors.length; i += 1) {
|
||||
ErrorMsg *err_msg = p->parse_h.errors.at(i);
|
||||
// TODO respect --color arg
|
||||
print_err_msg(err_msg, ErrColorAuto);
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
for (int struct_i = 0; struct_i < p->parse_h.struct_list.length; struct_i += 1) {
|
||||
AstNode *struct_decl = p->parse_h.struct_list.at(struct_i);
|
||||
assert(struct_decl->type == NodeTypeStructDecl);
|
||||
const char *struct_name = buf_ptr(&struct_decl->data.struct_decl.name);
|
||||
print_indent(p);
|
||||
fprintf(p->f, "struct %s {\n", struct_name);
|
||||
p->cur_indent += indent_size;
|
||||
for (int field_i = 0; field_i < struct_decl->data.struct_decl.fields.length; field_i += 1) {
|
||||
AstNode *field_node = struct_decl->data.struct_decl.fields.at(field_i);
|
||||
assert(field_node->type == NodeTypeStructField);
|
||||
const char *field_name = buf_ptr(&field_node->data.struct_field.name);
|
||||
const char *type_name = type_node_to_name(field_node->data.struct_field.type);
|
||||
print_indent(p);
|
||||
fprintf(p->f, "%s: %s,\n", field_name, type_name);
|
||||
}
|
||||
|
||||
p->cur_indent -= indent_size;
|
||||
fprintf(p->f, "}\n\n");
|
||||
}
|
||||
|
||||
for (int fn_i = 0; fn_i < p->parse_h.fn_list.length; fn_i += 1) {
|
||||
AstNode *fn_proto = p->parse_h.fn_list.at(fn_i);
|
||||
assert(fn_proto->type == NodeTypeFnProto);
|
||||
print_indent(p);
|
||||
const char *fn_name = buf_ptr(&fn_proto->data.fn_proto.name);
|
||||
fprintf(p->f, "extern fn %s(", fn_name);
|
||||
int arg_count = fn_proto->data.fn_proto.params.length;
|
||||
bool is_var_args = fn_proto->data.fn_proto.is_var_args;
|
||||
for (int arg_i = 0; arg_i < arg_count; arg_i += 1) {
|
||||
AstNode *param_decl = fn_proto->data.fn_proto.params.at(arg_i);
|
||||
assert(param_decl->type == NodeTypeParamDecl);
|
||||
const char *arg_name = buf_ptr(¶m_decl->data.param_decl.name);
|
||||
const char *arg_type = type_node_to_name(param_decl->data.param_decl.type);
|
||||
fprintf(p->f, "%s: %s", arg_name, arg_type);
|
||||
if (arg_i + 1 < arg_count || is_var_args) {
|
||||
fprintf(p->f, ", ");
|
||||
}
|
||||
}
|
||||
if (is_var_args) {
|
||||
fprintf(p->f, "...");
|
||||
}
|
||||
fprintf(p->f, ")");
|
||||
const char *return_type_name = type_node_to_name(fn_proto->data.fn_proto.return_type);
|
||||
if (strcmp(return_type_name, "void") != 0) {
|
||||
fprintf(p->f, " -> %s", return_type_name);
|
||||
}
|
||||
fprintf(p->f, ";\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
26
src/os.cpp
26
src/os.cpp
|
@ -208,3 +208,29 @@ int os_get_cwd(Buf *out_cwd) {
|
|||
bool os_stderr_tty(void) {
|
||||
return isatty(STDERR_FILENO);
|
||||
}
|
||||
|
||||
int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
|
||||
buf_resize(out_tmp_path, 0);
|
||||
buf_appendf(out_tmp_path, "/tmp/XXXXXX%s", buf_ptr(suffix));
|
||||
|
||||
int fd = mkstemps(buf_ptr(out_tmp_path), buf_len(suffix));
|
||||
if (fd < 0) {
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
|
||||
ssize_t amt_written = write(fd, buf_ptr(contents), buf_len(contents));
|
||||
if (amt_written != buf_len(contents))
|
||||
zig_panic("write failed: %s", strerror(errno));
|
||||
if (close(fd) == -1)
|
||||
zig_panic("close failed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int os_delete_file(Buf *path) {
|
||||
if (remove(buf_ptr(path))) {
|
||||
return ErrorFileSystem;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,9 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents);
|
|||
|
||||
int os_get_cwd(Buf *out_cwd);
|
||||
|
||||
|
||||
bool os_stderr_tty(void);
|
||||
|
||||
int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path);
|
||||
int os_delete_file(Buf *path);
|
||||
|
||||
#endif
|
||||
|
|
703
src/parseh.cpp
703
src/parseh.cpp
|
@ -7,540 +7,52 @@
|
|||
|
||||
#include "parseh.hpp"
|
||||
#include "config.h"
|
||||
#include "os.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
#include <clang-c/Index.h>
|
||||
#include <clang/Frontend/ASTUnit.h>
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
struct TypeDef {
|
||||
Buf alias;
|
||||
Buf target;
|
||||
using namespace clang;
|
||||
|
||||
struct Context {
|
||||
ParseH *parse_h;
|
||||
};
|
||||
|
||||
struct Arg {
|
||||
Buf name;
|
||||
Buf *type;
|
||||
};
|
||||
static bool decl_visitor(void *context, const Decl *decl) {
|
||||
//Context *c = (Context*)context;
|
||||
|
||||
struct Fn {
|
||||
Buf name;
|
||||
Buf *return_type;
|
||||
Arg *args;
|
||||
int arg_count;
|
||||
bool is_variadic;
|
||||
};
|
||||
|
||||
struct Field {
|
||||
Buf name;
|
||||
Buf *type;
|
||||
};
|
||||
|
||||
struct Struct {
|
||||
Buf name;
|
||||
ZigList<Field*> fields;
|
||||
bool have_def;
|
||||
};
|
||||
|
||||
struct ParseH {
|
||||
CXTranslationUnit tu;
|
||||
FILE *f;
|
||||
ZigList<Fn *> fn_list;
|
||||
ZigList<Struct *> struct_list;
|
||||
ZigList<TypeDef *> type_def_list;
|
||||
ZigList<Struct *> incomplete_struct_list;
|
||||
Fn *cur_fn;
|
||||
Struct *cur_struct;
|
||||
int arg_index;
|
||||
int cur_indent;
|
||||
CXSourceRange range;
|
||||
CXSourceLocation location;
|
||||
};
|
||||
|
||||
static const int indent_size = 4;
|
||||
|
||||
struct TypeMapping {
|
||||
const char *c_name;
|
||||
const char *zig_name;
|
||||
};
|
||||
|
||||
static const TypeMapping type_mappings[] = {
|
||||
{
|
||||
"int8_t",
|
||||
"i8",
|
||||
},
|
||||
{
|
||||
"uint8_t",
|
||||
"u8",
|
||||
},
|
||||
{
|
||||
"uint16_t",
|
||||
"u16",
|
||||
},
|
||||
{
|
||||
"uint32_t",
|
||||
"u32",
|
||||
},
|
||||
{
|
||||
"uint64_t",
|
||||
"u64",
|
||||
},
|
||||
{
|
||||
"int16_t",
|
||||
"i16",
|
||||
},
|
||||
{
|
||||
"int32_t",
|
||||
"i32",
|
||||
},
|
||||
{
|
||||
"int64_t",
|
||||
"i64",
|
||||
},
|
||||
{
|
||||
"intptr_t",
|
||||
"isize",
|
||||
},
|
||||
{
|
||||
"uintptr_t",
|
||||
"usize",
|
||||
},
|
||||
};
|
||||
|
||||
static bool have_struct_def(ParseH *p, Buf *name) {
|
||||
for (int i = 0; i < p->struct_list.length; i += 1) {
|
||||
Struct *struc = p->struct_list.at(i);
|
||||
if (struc->fields.length > 0 && buf_eql_buf(&struc->name, name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char *c_to_zig_name(const char *name) {
|
||||
for (int i = 0; i < array_length(type_mappings); i += 1) {
|
||||
const TypeMapping *mapping = &type_mappings[i];
|
||||
if (strcmp(mapping->c_name, name) == 0)
|
||||
return mapping->zig_name;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool str_has_prefix(const char *str, const char *prefix) {
|
||||
while (*prefix) {
|
||||
if (*str && *str == *prefix) {
|
||||
str += 1;
|
||||
prefix += 1;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char *prefixes_stripped(CXType type) {
|
||||
CXString name = clang_getTypeSpelling(type);
|
||||
const char *c_name = clang_getCString(name);
|
||||
|
||||
static const char *prefixes[] = {
|
||||
"struct ",
|
||||
"enum ",
|
||||
"const ",
|
||||
};
|
||||
|
||||
start_over:
|
||||
|
||||
for (int i = 0; i < array_length(prefixes); i += 1) {
|
||||
const char *prefix = prefixes[i];
|
||||
if (str_has_prefix(c_name, prefix)) {
|
||||
c_name += strlen(prefix);
|
||||
goto start_over;
|
||||
}
|
||||
}
|
||||
return c_name;
|
||||
}
|
||||
|
||||
static void print_location(ParseH *p) {
|
||||
CXFile file;
|
||||
unsigned line, column, offset;
|
||||
clang_getFileLocation(p->location, &file, &line, &column, &offset);
|
||||
CXString file_name = clang_getFileName(file);
|
||||
|
||||
fprintf(stderr, "%s line %u, column %u\n", clang_getCString(file_name), line, column);
|
||||
}
|
||||
|
||||
static bool resolves_to_void(ParseH *p, CXType raw_type) {
|
||||
if (raw_type.kind == CXType_Unexposed) {
|
||||
CXType canonical = clang_getCanonicalType(raw_type);
|
||||
if (canonical.kind == CXType_Unexposed)
|
||||
zig_panic("clang C api insufficient");
|
||||
else
|
||||
return resolves_to_void(p, canonical);
|
||||
}
|
||||
if (raw_type.kind == CXType_Void) {
|
||||
return true;
|
||||
} else if (raw_type.kind == CXType_Typedef) {
|
||||
CXCursor typedef_cursor = clang_getTypeDeclaration(raw_type);
|
||||
CXType underlying_type = clang_getTypedefDeclUnderlyingType(typedef_cursor);
|
||||
return resolves_to_void(p, underlying_type);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Buf *to_zig_type(ParseH *p, CXType raw_type) {
|
||||
if (raw_type.kind == CXType_Unexposed) {
|
||||
CXType canonical = clang_getCanonicalType(raw_type);
|
||||
if (canonical.kind == CXType_Unexposed)
|
||||
zig_panic("clang C api insufficient");
|
||||
else
|
||||
return to_zig_type(p, canonical);
|
||||
}
|
||||
switch (raw_type.kind) {
|
||||
case CXType_Invalid:
|
||||
case CXType_Unexposed:
|
||||
zig_unreachable();
|
||||
case CXType_Void:
|
||||
zig_panic("void type encountered");
|
||||
case CXType_Bool:
|
||||
return buf_create_from_str("bool");
|
||||
case CXType_SChar:
|
||||
return buf_create_from_str("i8");
|
||||
case CXType_UChar:
|
||||
case CXType_Char_U:
|
||||
case CXType_Char_S:
|
||||
return buf_create_from_str("u8");
|
||||
case CXType_WChar:
|
||||
print_location(p);
|
||||
zig_panic("TODO wchar");
|
||||
case CXType_Char16:
|
||||
print_location(p);
|
||||
zig_panic("TODO char16");
|
||||
case CXType_Char32:
|
||||
print_location(p);
|
||||
zig_panic("TODO char32");
|
||||
case CXType_UShort:
|
||||
return buf_create_from_str("c_ushort");
|
||||
case CXType_UInt:
|
||||
return buf_create_from_str("c_uint");
|
||||
case CXType_ULong:
|
||||
return buf_create_from_str("c_ulong");
|
||||
case CXType_ULongLong:
|
||||
return buf_create_from_str("c_ulonglong");
|
||||
case CXType_UInt128:
|
||||
print_location(p);
|
||||
zig_panic("TODO uint128");
|
||||
case CXType_Short:
|
||||
return buf_create_from_str("c_short");
|
||||
case CXType_Int:
|
||||
return buf_create_from_str("c_int");
|
||||
case CXType_Long:
|
||||
return buf_create_from_str("c_long");
|
||||
case CXType_LongLong:
|
||||
return buf_create_from_str("c_longlong");
|
||||
case CXType_Int128:
|
||||
print_location(p);
|
||||
zig_panic("TODO int128");
|
||||
case CXType_Float:
|
||||
return buf_create_from_str("f32");
|
||||
case CXType_Double:
|
||||
return buf_create_from_str("f64");
|
||||
case CXType_LongDouble:
|
||||
return buf_create_from_str("f128");
|
||||
case CXType_IncompleteArray:
|
||||
{
|
||||
CXType pointee_type = clang_getArrayElementType(raw_type);
|
||||
Buf *pointee_buf = to_zig_type(p, pointee_type);
|
||||
if (clang_isConstQualifiedType(pointee_type)) {
|
||||
return buf_sprintf("&const %s", buf_ptr(pointee_buf));
|
||||
} else {
|
||||
return buf_sprintf("&%s", buf_ptr(pointee_buf));
|
||||
}
|
||||
}
|
||||
case CXType_Pointer:
|
||||
{
|
||||
CXType pointee_type = clang_getPointeeType(raw_type);
|
||||
Buf *pointee_buf;
|
||||
if (resolves_to_void(p, pointee_type)) {
|
||||
pointee_buf = buf_create_from_str("u8");
|
||||
} else {
|
||||
pointee_buf = to_zig_type(p, pointee_type);
|
||||
}
|
||||
if (clang_isConstQualifiedType(pointee_type)) {
|
||||
return buf_sprintf("&const %s", buf_ptr(pointee_buf));
|
||||
} else {
|
||||
return buf_sprintf("&%s", buf_ptr(pointee_buf));
|
||||
}
|
||||
}
|
||||
case CXType_Record:
|
||||
{
|
||||
const char *name = prefixes_stripped(raw_type);
|
||||
return buf_sprintf("%s", name);
|
||||
}
|
||||
case CXType_Enum:
|
||||
{
|
||||
const char *name = prefixes_stripped(raw_type);
|
||||
return buf_sprintf("%s", name);
|
||||
}
|
||||
case CXType_Typedef:
|
||||
{
|
||||
const char *name = prefixes_stripped(raw_type);
|
||||
const char *zig_name = c_to_zig_name(name);
|
||||
if (zig_name) {
|
||||
return buf_create_from_str(zig_name);
|
||||
} else {
|
||||
CXCursor typedef_cursor = clang_getTypeDeclaration(raw_type);
|
||||
CXType underlying_type = clang_getTypedefDeclUnderlyingType(typedef_cursor);
|
||||
if (resolves_to_void(p, underlying_type)) {
|
||||
return buf_create_from_str("u8");
|
||||
} else {
|
||||
return buf_create_from_str(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
case CXType_ConstantArray:
|
||||
{
|
||||
CXType child_type = clang_getArrayElementType(raw_type);
|
||||
Buf *zig_child_type = to_zig_type(p, child_type);
|
||||
long size = (long)clang_getArraySize(raw_type);
|
||||
return buf_sprintf("[%s; %ld]", buf_ptr(zig_child_type), size);
|
||||
}
|
||||
case CXType_FunctionProto:
|
||||
fprintf(stderr, "warning: TODO function proto\n");
|
||||
print_location(p);
|
||||
return buf_create_from_str("u8");
|
||||
case CXType_FunctionNoProto:
|
||||
print_location(p);
|
||||
zig_panic("TODO function no proto");
|
||||
case CXType_BlockPointer:
|
||||
print_location(p);
|
||||
zig_panic("TODO block pointer");
|
||||
case CXType_Vector:
|
||||
print_location(p);
|
||||
zig_panic("TODO vector");
|
||||
case CXType_LValueReference:
|
||||
case CXType_RValueReference:
|
||||
case CXType_VariableArray:
|
||||
case CXType_DependentSizedArray:
|
||||
case CXType_MemberPointer:
|
||||
case CXType_ObjCInterface:
|
||||
case CXType_ObjCObjectPointer:
|
||||
case CXType_NullPtr:
|
||||
case CXType_Overload:
|
||||
case CXType_Dependent:
|
||||
case CXType_ObjCId:
|
||||
case CXType_ObjCClass:
|
||||
case CXType_ObjCSel:
|
||||
case CXType_Complex:
|
||||
print_location(p);
|
||||
zig_panic("TODO");
|
||||
}
|
||||
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static bool is_storage_class_export(CX_StorageClass storage_class) {
|
||||
switch (storage_class) {
|
||||
case CX_SC_Invalid:
|
||||
zig_unreachable();
|
||||
case CX_SC_None:
|
||||
case CX_SC_Extern:
|
||||
case CX_SC_Auto:
|
||||
return true;
|
||||
case CX_SC_Static:
|
||||
case CX_SC_PrivateExtern:
|
||||
case CX_SC_OpenCLWorkGroupLocal:
|
||||
case CX_SC_Register:
|
||||
return false;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static enum CXChildVisitResult visit_fn_children(CXCursor cursor, CXCursor parent, CXClientData client_data) {
|
||||
ParseH *p = (ParseH*)client_data;
|
||||
enum CXCursorKind kind = clang_getCursorKind(cursor);
|
||||
|
||||
switch (kind) {
|
||||
case CXCursor_ParmDecl:
|
||||
{
|
||||
assert(p->cur_fn);
|
||||
assert(p->arg_index < p->cur_fn->arg_count);
|
||||
CXString name = clang_getCursorSpelling(cursor);
|
||||
Buf *arg_name = &p->cur_fn->args[p->arg_index].name;
|
||||
buf_init_from_str(arg_name, clang_getCString(name));
|
||||
if (buf_len(arg_name) == 0) {
|
||||
buf_appendf(arg_name, "arg%d", p->arg_index);
|
||||
}
|
||||
|
||||
p->arg_index += 1;
|
||||
return CXChildVisit_Continue;
|
||||
}
|
||||
default:
|
||||
return CXChildVisit_Recurse;
|
||||
}
|
||||
}
|
||||
|
||||
static enum CXChildVisitResult visit_struct_children(CXCursor cursor, CXCursor parent, CXClientData client_data) {
|
||||
ParseH *p = (ParseH*)client_data;
|
||||
enum CXCursorKind kind = clang_getCursorKind(cursor);
|
||||
|
||||
switch (kind) {
|
||||
case CXCursor_FieldDecl:
|
||||
{
|
||||
assert(p->cur_struct);
|
||||
CXString name = clang_getCursorSpelling(cursor);
|
||||
Field *field = allocate<Field>(1);
|
||||
buf_init_from_str(&field->name, clang_getCString(name));
|
||||
CXType cursor_type = clang_getCursorType(cursor);
|
||||
field->type = to_zig_type(p, cursor_type);
|
||||
|
||||
p->cur_struct->fields.append(field);
|
||||
|
||||
return CXChildVisit_Continue;
|
||||
}
|
||||
default:
|
||||
return CXChildVisit_Recurse;
|
||||
}
|
||||
}
|
||||
|
||||
static bool handle_struct_cursor(ParseH *p, CXCursor cursor, const char *name, bool expect_name) {
|
||||
p->cur_struct = allocate<Struct>(1);
|
||||
|
||||
buf_init_from_str(&p->cur_struct->name, name);
|
||||
|
||||
bool got_name = (buf_len(&p->cur_struct->name) != 0);
|
||||
if (expect_name != got_name)
|
||||
return false;
|
||||
|
||||
clang_visitChildren(cursor, visit_struct_children, p);
|
||||
|
||||
if (p->cur_struct->fields.length > 0) {
|
||||
p->struct_list.append(p->cur_struct);
|
||||
} else {
|
||||
p->incomplete_struct_list.append(p->cur_struct);
|
||||
}
|
||||
|
||||
p->cur_struct = nullptr;
|
||||
fprintf(stderr, "got top level decl\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static enum CXChildVisitResult fn_visitor(CXCursor cursor, CXCursor parent, CXClientData client_data) {
|
||||
ParseH *p = (ParseH*)client_data;
|
||||
enum CXCursorKind kind = clang_getCursorKind(cursor);
|
||||
CXString name = clang_getCursorSpelling(cursor);
|
||||
|
||||
p->range = clang_getCursorExtent(cursor);
|
||||
p->location = clang_getRangeStart(p->range);
|
||||
|
||||
switch (kind) {
|
||||
case CXCursor_FunctionDecl:
|
||||
{
|
||||
CX_StorageClass storage_class = clang_Cursor_getStorageClass(cursor);
|
||||
if (!is_storage_class_export(storage_class))
|
||||
return CXChildVisit_Continue;
|
||||
|
||||
CXType fn_type = clang_getCursorType(cursor);
|
||||
if (clang_getFunctionTypeCallingConv(fn_type) != CXCallingConv_C) {
|
||||
print_location(p);
|
||||
fprintf(stderr, "warning: skipping non c calling convention function, not yet supported\n");
|
||||
return CXChildVisit_Continue;
|
||||
}
|
||||
|
||||
assert(!p->cur_fn);
|
||||
p->cur_fn = allocate<Fn>(1);
|
||||
|
||||
p->cur_fn->is_variadic = clang_isFunctionTypeVariadic(fn_type);
|
||||
|
||||
CXType return_type = clang_getResultType(fn_type);
|
||||
if (!resolves_to_void(p, return_type)) {
|
||||
p->cur_fn->return_type = to_zig_type(p, return_type);
|
||||
}
|
||||
|
||||
buf_init_from_str(&p->cur_fn->name, clang_getCString(name));
|
||||
|
||||
p->cur_fn->arg_count = clang_getNumArgTypes(fn_type);
|
||||
p->cur_fn->args = allocate<Arg>(p->cur_fn->arg_count);
|
||||
|
||||
for (int i = 0; i < p->cur_fn->arg_count; i += 1) {
|
||||
CXType param_type = clang_getArgType(fn_type, i);
|
||||
p->cur_fn->args[i].type = to_zig_type(p, param_type);
|
||||
}
|
||||
|
||||
p->arg_index = 0;
|
||||
|
||||
clang_visitChildren(cursor, visit_fn_children, p);
|
||||
|
||||
p->fn_list.append(p->cur_fn);
|
||||
p->cur_fn = nullptr;
|
||||
|
||||
return CXChildVisit_Recurse;
|
||||
}
|
||||
case CXCursor_CompoundStmt:
|
||||
case CXCursor_FieldDecl:
|
||||
case CXCursor_TypedefDecl:
|
||||
{
|
||||
CXType underlying_type = clang_getTypedefDeclUnderlyingType(cursor);
|
||||
|
||||
if (resolves_to_void(p, underlying_type)) {
|
||||
return CXChildVisit_Continue;
|
||||
}
|
||||
|
||||
if (underlying_type.kind == CXType_Unexposed) {
|
||||
underlying_type = clang_getCanonicalType(underlying_type);
|
||||
}
|
||||
bool skip_typedef;
|
||||
if (underlying_type.kind == CXType_Unexposed) {
|
||||
fprintf(stderr, "warning: unexposed type\n");
|
||||
print_location(p);
|
||||
skip_typedef = true;
|
||||
} else if (underlying_type.kind == CXType_Record) {
|
||||
CXCursor decl_cursor = clang_getTypeDeclaration(underlying_type);
|
||||
skip_typedef = handle_struct_cursor(p, decl_cursor, clang_getCString(name), false);
|
||||
} else if (underlying_type.kind == CXType_Invalid) {
|
||||
fprintf(stderr, "warning: invalid type\n");
|
||||
print_location(p);
|
||||
skip_typedef = true;
|
||||
} else {
|
||||
skip_typedef = false;
|
||||
}
|
||||
|
||||
CXType typedef_type = clang_getCursorType(cursor);
|
||||
const char *name_str = prefixes_stripped(typedef_type);
|
||||
if (!skip_typedef && c_to_zig_name(name_str)) {
|
||||
skip_typedef = true;
|
||||
}
|
||||
|
||||
if (!skip_typedef) {
|
||||
TypeDef *type_def = allocate<TypeDef>(1);
|
||||
buf_init_from_str(&type_def->alias, name_str);
|
||||
buf_init_from_buf(&type_def->target, to_zig_type(p, underlying_type));
|
||||
p->type_def_list.append(type_def);
|
||||
}
|
||||
|
||||
return CXChildVisit_Continue;
|
||||
}
|
||||
case CXCursor_StructDecl:
|
||||
{
|
||||
handle_struct_cursor(p, cursor, clang_getCString(name), true);
|
||||
|
||||
return CXChildVisit_Continue;
|
||||
}
|
||||
default:
|
||||
return CXChildVisit_Recurse;
|
||||
int parse_h_buf(ParseH *parse_h, Buf *source, const char *libc_include_path) {
|
||||
int err;
|
||||
Buf tmp_file_path = BUF_INIT;
|
||||
if ((err = os_buf_to_tmp_file(source, buf_create_from_str(".h"), &tmp_file_path))) {
|
||||
return err;
|
||||
}
|
||||
ZigList<const char *> clang_argv = {0};
|
||||
clang_argv.append(buf_ptr(&tmp_file_path));
|
||||
|
||||
clang_argv.append("-isystem");
|
||||
clang_argv.append(libc_include_path);
|
||||
|
||||
err = parse_h_file(parse_h, &clang_argv);
|
||||
|
||||
os_delete_file(&tmp_file_path);
|
||||
|
||||
return err;
|
||||
// write to temp file, parse it, delete it
|
||||
}
|
||||
|
||||
static void print_indent(ParseH *p) {
|
||||
for (int i = 0; i < p->cur_indent; i += 1) {
|
||||
fprintf(p->f, " ");
|
||||
}
|
||||
}
|
||||
|
||||
void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FILE *f) {
|
||||
ParseH parse_h = {0};
|
||||
ParseH *p = &parse_h;
|
||||
p->f = f;
|
||||
CXIndex index = clang_createIndex(1, 0);
|
||||
int parse_h_file(ParseH *parse_h, ZigList<const char *> *clang_argv) {
|
||||
Context context = {0};
|
||||
Context *c = &context;
|
||||
c->parse_h = parse_h;
|
||||
|
||||
char *ZIG_PARSEH_CFLAGS = getenv("ZIG_PARSEH_CFLAGS");
|
||||
if (ZIG_PARSEH_CFLAGS) {
|
||||
|
@ -558,105 +70,78 @@ void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FI
|
|||
buf_init_from_str(&tmp_buf, start);
|
||||
clang_argv->append(buf_ptr(buf_create_from_buf(&tmp_buf)));
|
||||
}
|
||||
|
||||
clang_argv->append("-isystem");
|
||||
clang_argv->append(ZIG_HEADERS_DIR);
|
||||
|
||||
// we don't need spell checking and it slows things down
|
||||
clang_argv->append("-fno-spell-checking");
|
||||
// to make the end argument work
|
||||
clang_argv->append(nullptr);
|
||||
|
||||
enum CXErrorCode err_code;
|
||||
if ((err_code = clang_parseTranslationUnit2(index, target_path,
|
||||
clang_argv->items, clang_argv->length - 1,
|
||||
NULL, 0, CXTranslationUnit_None, &p->tu)))
|
||||
{
|
||||
zig_panic("parse translation unit failure");
|
||||
IntrusiveRefCntPtr<DiagnosticsEngine> diags(CompilerInstance::createDiagnostics(new DiagnosticOptions));
|
||||
|
||||
std::shared_ptr<PCHContainerOperations> pch_container_ops = std::make_shared<PCHContainerOperations>();
|
||||
|
||||
bool skip_function_bodies = true;
|
||||
bool only_local_decls = true;
|
||||
bool capture_diagnostics = true;
|
||||
bool user_files_are_volatile = true;
|
||||
bool allow_pch_with_compiler_errors = false;
|
||||
const char *resources_path = ZIG_HEADERS_DIR;
|
||||
std::unique_ptr<ASTUnit> err_unit;
|
||||
std::unique_ptr<ASTUnit> ast_unit(ASTUnit::LoadFromCommandLine(
|
||||
&clang_argv->at(0), &clang_argv->last(),
|
||||
pch_container_ops, diags, resources_path,
|
||||
only_local_decls, capture_diagnostics, None, true, false, TU_Complete,
|
||||
false, false, allow_pch_with_compiler_errors, skip_function_bodies,
|
||||
user_files_are_volatile, false, &err_unit));
|
||||
|
||||
|
||||
// Early failures in LoadFromCommandLine may return with ErrUnit unset.
|
||||
if (!ast_unit && !err_unit) {
|
||||
return ErrorFileSystem;
|
||||
}
|
||||
|
||||
|
||||
unsigned diag_count = clang_getNumDiagnostics(p->tu);
|
||||
|
||||
if (diag_count > 0) {
|
||||
for (unsigned i = 0; i < diag_count; i += 1) {
|
||||
CXDiagnostic diagnostic = clang_getDiagnostic(p->tu, i);
|
||||
CXSourceLocation location = clang_getDiagnosticLocation(diagnostic);
|
||||
|
||||
CXFile file;
|
||||
unsigned line, column, offset;
|
||||
clang_getSpellingLocation(location, &file, &line, &column, &offset);
|
||||
CXString text = clang_getDiagnosticSpelling(diagnostic);
|
||||
CXString file_name = clang_getFileName(file);
|
||||
fprintf(stderr, "%s line %u, column %u: %s\n", clang_getCString(file_name),
|
||||
line, column, clang_getCString(text));
|
||||
if (diags->getClient()->getNumErrors() > 0) {
|
||||
if (ast_unit) {
|
||||
err_unit = std::move(ast_unit);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
CXCursor cursor = clang_getTranslationUnitCursor(p->tu);
|
||||
clang_visitChildren(cursor, fn_visitor, p);
|
||||
|
||||
for (int struct_i = 0; struct_i < p->struct_list.length; struct_i += 1) {
|
||||
Struct *struc = p->struct_list.at(struct_i);
|
||||
fprintf(f, "struct %s {\n", buf_ptr(&struc->name));
|
||||
p->cur_indent += indent_size;
|
||||
for (int field_i = 0; field_i < struc->fields.length; field_i += 1) {
|
||||
Field *field = struc->fields.at(field_i);
|
||||
print_indent(p);
|
||||
fprintf(f, "%s: %s,\n", buf_ptr(&field->name), buf_ptr(field->type));
|
||||
}
|
||||
|
||||
p->cur_indent -= indent_size;
|
||||
fprintf(f, "}\n\n");
|
||||
}
|
||||
|
||||
int total_typedef_count = p->type_def_list.length;
|
||||
for (int i = 0; i < p->incomplete_struct_list.length; i += 1) {
|
||||
Struct *struc = p->incomplete_struct_list.at(i);
|
||||
struc->have_def = have_struct_def(p, &struc->name);
|
||||
total_typedef_count += (int)!struc->have_def;
|
||||
}
|
||||
|
||||
if (total_typedef_count) {
|
||||
for (int i = 0; i < p->incomplete_struct_list.length; i += 1) {
|
||||
Struct *struc = p->incomplete_struct_list.at(i);
|
||||
if (struc->have_def)
|
||||
continue;
|
||||
|
||||
fprintf(f, "struct %s;\n", buf_ptr(&struc->name));
|
||||
}
|
||||
|
||||
for (int type_def_i = 0; type_def_i < p->type_def_list.length; type_def_i += 1) {
|
||||
TypeDef *type_def = p->type_def_list.at(type_def_i);
|
||||
fprintf(f, "type %s = %s;\n", buf_ptr(&type_def->alias), buf_ptr(&type_def->target));
|
||||
}
|
||||
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
if (p->fn_list.length) {
|
||||
fprintf(f, "extern {\n");
|
||||
p->cur_indent += indent_size;
|
||||
for (int fn_i = 0; fn_i < p->fn_list.length; fn_i += 1) {
|
||||
Fn *fn = p->fn_list.at(fn_i);
|
||||
print_indent(p);
|
||||
fprintf(p->f, "fn %s(", buf_ptr(&fn->name));
|
||||
for (int arg_i = 0; arg_i < fn->arg_count; arg_i += 1) {
|
||||
Arg *arg = &fn->args[arg_i];
|
||||
fprintf(p->f, "%s: %s", buf_ptr(&arg->name), buf_ptr(arg->type));
|
||||
if (arg_i + 1 < fn->arg_count || fn->is_variadic) {
|
||||
fprintf(p->f, ", ");
|
||||
}
|
||||
for (ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(),
|
||||
it_end = err_unit->stored_diag_end();
|
||||
it != it_end; ++it)
|
||||
{
|
||||
switch (it->getLevel()) {
|
||||
case DiagnosticsEngine::Ignored:
|
||||
case DiagnosticsEngine::Note:
|
||||
case DiagnosticsEngine::Remark:
|
||||
case DiagnosticsEngine::Warning:
|
||||
continue;
|
||||
case DiagnosticsEngine::Error:
|
||||
case DiagnosticsEngine::Fatal:
|
||||
break;
|
||||
}
|
||||
if (fn->is_variadic) {
|
||||
fprintf(p->f, "...");
|
||||
}
|
||||
fprintf(p->f, ")");
|
||||
if (fn->return_type) {
|
||||
fprintf(p->f, " -> %s", buf_ptr(fn->return_type));
|
||||
}
|
||||
fprintf(p->f, ";\n");
|
||||
StringRef msg_str_ref = it->getMessage();
|
||||
FullSourceLoc fsl = it->getLocation();
|
||||
FileID file_id = fsl.getManager().getFileID(fsl);
|
||||
StringRef filename = fsl.getManager().getFilename(fsl);
|
||||
unsigned line = fsl.getSpellingLineNumber() - 1;
|
||||
unsigned column = fsl.getSpellingColumnNumber() - 1;
|
||||
unsigned offset = fsl.getManager().getFileOffset(fsl);
|
||||
const char *source = (const char *)fsl.getManager().getBufferData(file_id).bytes_begin();
|
||||
Buf *msg = buf_create_from_str((const char *)msg_str_ref.bytes_begin());
|
||||
Buf *path = buf_create_from_str((const char *)filename.bytes_begin());
|
||||
|
||||
ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg);
|
||||
|
||||
parse_h->errors.append(err_msg);
|
||||
}
|
||||
p->cur_indent -= indent_size;
|
||||
fprintf(f, "}\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_unit->visitLocalTopLevelDecls(c, decl_visitor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -9,10 +9,9 @@
|
|||
#ifndef ZIG_PARSEH_HPP
|
||||
#define ZIG_PARSEH_HPP
|
||||
|
||||
#include "buffer.hpp"
|
||||
#include "all_types.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void parse_h_file(const char *target_path, ZigList<const char *> *clang_argv, FILE *f);
|
||||
int parse_h_file(ParseH *parse_h, ZigList<const char *> *clang_argv);
|
||||
int parse_h_buf(ParseH *parse_h, Buf *buf, const char *libc_include_path);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -488,23 +488,16 @@ __attribute__ ((noreturn))
|
|||
static void ast_asm_error(ParseContext *pc, AstNode *node, int offset, const char *format, ...) {
|
||||
assert(node->type == NodeTypeAsmExpr);
|
||||
|
||||
ErrorMsg *err = allocate<ErrorMsg>(1);
|
||||
|
||||
SrcPos pos = node->data.asm_expr.offset_map.at(offset);
|
||||
|
||||
err->line_start = pos.line;
|
||||
err->column_start = pos.column;
|
||||
err->line_end = -1;
|
||||
err->column_end = -1;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
err->msg = buf_vprintf(format, ap);
|
||||
Buf *msg = buf_vprintf(format, ap);
|
||||
va_end(ap);
|
||||
|
||||
err->path = pc->owner->path;
|
||||
err->source = pc->owner->source_code;
|
||||
err->line_offsets = pc->owner->line_offsets;
|
||||
ErrorMsg *err = err_msg_create_with_line(pc->owner->path, pos.line, pos.column,
|
||||
pc->owner->source_code, pc->owner->line_offsets, msg);
|
||||
|
||||
print_err_msg(err, pc->err_color);
|
||||
exit(EXIT_FAILURE);
|
||||
|
@ -513,20 +506,16 @@ static void ast_asm_error(ParseContext *pc, AstNode *node, int offset, const cha
|
|||
__attribute__ ((format (printf, 3, 4)))
|
||||
__attribute__ ((noreturn))
|
||||
static void ast_error(ParseContext *pc, Token *token, const char *format, ...) {
|
||||
ErrorMsg *err = allocate<ErrorMsg>(1);
|
||||
err->line_start = token->start_line;
|
||||
err->column_start = token->start_column;
|
||||
err->line_end = -1;
|
||||
err->column_end = -1;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
err->msg = buf_vprintf(format, ap);
|
||||
Buf *msg = buf_vprintf(format, ap);
|
||||
va_end(ap);
|
||||
|
||||
err->path = pc->owner->path;
|
||||
err->source = pc->owner->source_code;
|
||||
err->line_offsets = pc->owner->line_offsets;
|
||||
|
||||
ErrorMsg *err = err_msg_create_with_line(pc->owner->path, token->start_line, token->start_column,
|
||||
pc->owner->source_code, pc->owner->line_offsets, msg);
|
||||
err->line_start = token->start_line;
|
||||
err->column_start = token->start_column;
|
||||
|
||||
print_err_msg(err, pc->err_color);
|
||||
exit(EXIT_FAILURE);
|
||||
|
|
|
@ -1673,6 +1673,13 @@ fn f(s: []u8) -> []u8 {
|
|||
}
|
||||
)SOURCE", 1, ".tmp_source.zig:3:5: error: string concatenation requires constant expression");
|
||||
|
||||
add_compile_fail_case("c_import with bogus include", R"SOURCE(
|
||||
c_import {
|
||||
@c_include("bogus.h");
|
||||
}
|
||||
)SOURCE", 2, ".tmp_source.zig:2:1: error: C import failed",
|
||||
".h:1:10: error: 'bogus.h' file not found");
|
||||
|
||||
}
|
||||
|
||||
static void print_compiler_invocation(TestCase *test_case) {
|
||||
|
|
Loading…
Reference in New Issue