| author | |
| committer | |
| log | 5a25505668bac9aed0ad8f3b23fe81c6aff29b71 |
| tree | bd5cea1c33ca7d272690f5c13f97a97612a7a3e6 |
| parent | afbbdb2c67127985cadae7244348665ece8b2f25 |
16 files changed, 4491 insertions(+), 4491 deletions(-)
CMakeLists.txt+1-1| ... | ... | @@ -339,7 +339,7 @@ set(ZIG_SOURCES |
| 339 | 339 | "${CMAKE_SOURCE_DIR}/src/target.cpp" |
| 340 | 340 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" |
| 341 | 341 | "${CMAKE_SOURCE_DIR}/src/util.cpp" |
| 342 | "${CMAKE_SOURCE_DIR}/src/parsec.cpp" | |
| 342 | "${CMAKE_SOURCE_DIR}/src/translate_c.cpp" | |
| 343 | 343 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" |
| 344 | 344 | ) |
| 345 | 345 |
build.zig+1-1| ... | ... | @@ -58,5 +58,5 @@ pub fn build(b: &Builder) { |
| 58 | 58 | test_step.dependOn(tests.addCompileErrorTests(b, test_filter)); |
| 59 | 59 | test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter)); |
| 60 | 60 | test_step.dependOn(tests.addDebugSafetyTests(b, test_filter)); |
| 61 | test_step.dependOn(tests.addParseCTests(b, test_filter)); | |
| 61 | test_step.dependOn(tests.addTranslateCTests(b, test_filter)); | |
| 62 | 62 | } |
ci/travis_osx_script+1-1| ... | ... | @@ -22,4 +22,4 @@ make install |
| 22 | 22 | ./zig build --build-file ../build.zig test-compile-errors --verbose |
| 23 | 23 | ./zig build --build-file ../build.zig test-asm-link --verbose |
| 24 | 24 | ./zig build --build-file ../build.zig test-debug-safety --verbose |
| 25 | ./zig build --build-file ../build.zig test-parsec --verbose | |
| 25 | ./zig build --build-file ../build.zig test-translate-c --verbose |
src-self-hosted/main.zig+1-1| ... | ... | @@ -208,7 +208,7 @@ fn printUsage(outstream: &io.OutStream) -> %void { |
| 208 | 208 | \\ build-exe [source] create executable from source or object files |
| 209 | 209 | \\ build-lib [source] create library from source or object files |
| 210 | 210 | \\ build-obj [source] create object from source or assembly |
| 211 | \\ parsec [source] convert c code to zig code | |
| 211 | \\ translate-c [source] convert c code to zig code | |
| 212 | 212 | \\ targets list available compilation targets |
| 213 | 213 | \\ test [source] create and run a test build |
| 214 | 214 | \\ version print version number and exit |
src/analyze.cpp+2-2| ... | ... | @@ -28,7 +28,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type); |
| 28 | 28 | |
| 29 | 29 | ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { |
| 30 | 30 | if (node->owner->c_import_node != nullptr) { |
| 31 | // if this happens, then parsec generated code that | |
| 31 | // if this happens, then translate_c generated code that | |
| 32 | 32 | // failed semantic analysis, which isn't supposed to happen |
| 33 | 33 | ErrorMsg *err = add_node_error(g, node->owner->c_import_node, |
| 34 | 34 | buf_sprintf("compiler bug: @cImport generated invalid zig code")); |
| ... | ... | @@ -48,7 +48,7 @@ ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { |
| 48 | 48 | |
| 49 | 49 | ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) { |
| 50 | 50 | if (node->owner->c_import_node != nullptr) { |
| 51 | // if this happens, then parsec generated code that | |
| 51 | // if this happens, then translate_c generated code that | |
| 52 | 52 | // failed semantic analysis, which isn't supposed to happen |
| 53 | 53 | |
| 54 | 54 | Buf *note_path = buf_create_from_str("?.c"); |
src/codegen.cpp+2-2| ... | ... | @@ -15,7 +15,7 @@ |
| 15 | 15 | #include "ir.hpp" |
| 16 | 16 | #include "link.hpp" |
| 17 | 17 | #include "os.hpp" |
| 18 | #include "parsec.hpp" | |
| 18 | #include "translate_c.hpp" | |
| 19 | 19 | #include "target.hpp" |
| 20 | 20 | #include "zig_llvm.hpp" |
| 21 | 21 | |
| ... | ... | @@ -5353,7 +5353,7 @@ static void init(CodeGen *g) { |
| 5353 | 5353 | define_builtin_compile_vars(g); |
| 5354 | 5354 | } |
| 5355 | 5355 | |
| 5356 | void codegen_parsec(CodeGen *g, Buf *full_path) { | |
| 5356 | void codegen_translate_c(CodeGen *g, Buf *full_path) { | |
| 5357 | 5357 | find_libc_include_path(g); |
| 5358 | 5358 | |
| 5359 | 5359 | Buf *src_basename = buf_alloc(); |
src/codegen.hpp+1-1| ... | ... | @@ -56,7 +56,7 @@ PackageTableEntry *codegen_create_package(CodeGen *g, const char *root_src_dir, |
| 56 | 56 | void codegen_add_assembly(CodeGen *g, Buf *path); |
| 57 | 57 | void codegen_add_object(CodeGen *g, Buf *object_path); |
| 58 | 58 | |
| 59 | void codegen_parsec(CodeGen *g, Buf *path); | |
| 59 | void codegen_translate_c(CodeGen *g, Buf *path); | |
| 60 | 60 | |
| 61 | 61 | |
| 62 | 62 | #endif |
src/ir.cpp+1-1| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | #include "ir.hpp" |
| 12 | 12 | #include "ir_print.hpp" |
| 13 | 13 | #include "os.hpp" |
| 14 | #include "parsec.hpp" | |
| 14 | #include "translate_c.hpp" | |
| 15 | 15 | #include "range_set.hpp" |
| 16 | 16 | #include "softfloat.hpp" |
| 17 | 17 |
src/main.cpp+11-11| ... | ... | @@ -23,7 +23,7 @@ static int usage(const char *arg0) { |
| 23 | 23 | " build-exe [source] create executable from source or object files\n" |
| 24 | 24 | " build-lib [source] create library from source or object files\n" |
| 25 | 25 | " build-obj [source] create object from source or assembly\n" |
| 26 | " parsec [source] convert c code to zig code\n" | |
| 26 | " translate-c [source] convert c code to zig code\n" | |
| 27 | 27 | " targets list available compilation targets\n" |
| 28 | 28 | " test [source] create and run a test build\n" |
| 29 | 29 | " version print version number and exit\n" |
| ... | ... | @@ -229,7 +229,7 @@ enum Cmd { |
| 229 | 229 | CmdTest, |
| 230 | 230 | CmdVersion, |
| 231 | 231 | CmdZen, |
| 232 | CmdParseC, | |
| 232 | CmdTranslateC, | |
| 233 | 233 | CmdTargets, |
| 234 | 234 | }; |
| 235 | 235 | |
| ... | ... | @@ -632,8 +632,8 @@ int main(int argc, char **argv) { |
| 632 | 632 | cmd = CmdVersion; |
| 633 | 633 | } else if (strcmp(arg, "zen") == 0) { |
| 634 | 634 | cmd = CmdZen; |
| 635 | } else if (strcmp(arg, "parsec") == 0) { | |
| 636 | cmd = CmdParseC; | |
| 635 | } else if (strcmp(arg, "translate-c") == 0) { | |
| 636 | cmd = CmdTranslateC; | |
| 637 | 637 | } else if (strcmp(arg, "test") == 0) { |
| 638 | 638 | cmd = CmdTest; |
| 639 | 639 | out_type = OutTypeExe; |
| ... | ... | @@ -646,7 +646,7 @@ int main(int argc, char **argv) { |
| 646 | 646 | } else { |
| 647 | 647 | switch (cmd) { |
| 648 | 648 | case CmdBuild: |
| 649 | case CmdParseC: | |
| 649 | case CmdTranslateC: | |
| 650 | 650 | case CmdTest: |
| 651 | 651 | if (!in_file) { |
| 652 | 652 | in_file = arg; |
| ... | ... | @@ -703,13 +703,13 @@ int main(int argc, char **argv) { |
| 703 | 703 | |
| 704 | 704 | switch (cmd) { |
| 705 | 705 | case CmdBuild: |
| 706 | case CmdParseC: | |
| 706 | case CmdTranslateC: | |
| 707 | 707 | case CmdTest: |
| 708 | 708 | { |
| 709 | 709 | if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) { |
| 710 | 710 | fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n"); |
| 711 | 711 | return usage(arg0); |
| 712 | } else if ((cmd == CmdParseC || cmd == CmdTest) && !in_file) { | |
| 712 | } else if ((cmd == CmdTranslateC || cmd == CmdTest) && !in_file) { | |
| 713 | 713 | fprintf(stderr, "Expected source file argument.\n"); |
| 714 | 714 | return usage(arg0); |
| 715 | 715 | } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) { |
| ... | ... | @@ -719,7 +719,7 @@ int main(int argc, char **argv) { |
| 719 | 719 | |
| 720 | 720 | assert(cmd != CmdBuild || out_type != OutTypeUnknown); |
| 721 | 721 | |
| 722 | bool need_name = (cmd == CmdBuild || cmd == CmdParseC); | |
| 722 | bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC); | |
| 723 | 723 | |
| 724 | 724 | Buf *in_file_buf = nullptr; |
| 725 | 725 | |
| ... | ... | @@ -742,7 +742,7 @@ int main(int argc, char **argv) { |
| 742 | 742 | return usage(arg0); |
| 743 | 743 | } |
| 744 | 744 | |
| 745 | Buf *zig_root_source_file = (cmd == CmdParseC) ? nullptr : in_file_buf; | |
| 745 | Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf; | |
| 746 | 746 | |
| 747 | 747 | Buf *full_cache_dir = buf_alloc(); |
| 748 | 748 | os_path_resolve(buf_create_from_str("."), |
| ... | ... | @@ -841,8 +841,8 @@ int main(int argc, char **argv) { |
| 841 | 841 | if (timing_info) |
| 842 | 842 | codegen_print_timing_report(g, stdout); |
| 843 | 843 | return EXIT_SUCCESS; |
| 844 | } else if (cmd == CmdParseC) { | |
| 845 | codegen_parsec(g, in_file_buf); | |
| 844 | } else if (cmd == CmdTranslateC) { | |
| 845 | codegen_translate_c(g, in_file_buf); | |
| 846 | 846 | ast_render(g, stdout, g->root_import->root, 4); |
| 847 | 847 | if (timing_info) |
| 848 | 848 | codegen_print_timing_report(g, stdout); |
src/parsec.cpp deleted-3527| ... | ... | @@ -1,3527 +0,0 @@ |
| 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 | #include "all_types.hpp" | |
| 9 | #include "analyze.hpp" | |
| 10 | #include "c_tokenizer.hpp" | |
| 11 | #include "error.hpp" | |
| 12 | #include "ir.hpp" | |
| 13 | #include "os.hpp" | |
| 14 | #include "parsec.hpp" | |
| 15 | #include "parser.hpp" | |
| 16 | ||
| 17 | ||
| 18 | #include <clang/Frontend/ASTUnit.h> | |
| 19 | #include <clang/Frontend/CompilerInstance.h> | |
| 20 | #include <clang/AST/Expr.h> | |
| 21 | ||
| 22 | #include <string.h> | |
| 23 | ||
| 24 | using namespace clang; | |
| 25 | ||
| 26 | struct MacroSymbol { | |
| 27 | Buf *name; | |
| 28 | Buf *value; | |
| 29 | }; | |
| 30 | ||
| 31 | struct Alias { | |
| 32 | Buf *new_name; | |
| 33 | Buf *canon_name; | |
| 34 | }; | |
| 35 | ||
| 36 | struct Context { | |
| 37 | ImportTableEntry *import; | |
| 38 | ZigList<ErrorMsg *> *errors; | |
| 39 | VisibMod visib_mod; | |
| 40 | VisibMod export_visib_mod; | |
| 41 | AstNode *root; | |
| 42 | HashMap<const void *, AstNode *, ptr_hash, ptr_eq> decl_table; | |
| 43 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table; | |
| 44 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> global_table; | |
| 45 | SourceManager *source_manager; | |
| 46 | ZigList<Alias> aliases; | |
| 47 | ZigList<MacroSymbol> macro_symbols; | |
| 48 | AstNode *source_node; | |
| 49 | bool warnings_on; | |
| 50 | ||
| 51 | CodeGen *codegen; | |
| 52 | ASTContext *ctx; | |
| 53 | ||
| 54 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> ptr_params; | |
| 55 | }; | |
| 56 | ||
| 57 | static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl); | |
| 58 | static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl); | |
| 59 | static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl); | |
| 60 | ||
| 61 | ||
| 62 | ATTRIBUTE_PRINTF(3, 4) | |
| 63 | static void emit_warning(Context *c, const SourceLocation &sl, const char *format, ...) { | |
| 64 | if (!c->warnings_on) { | |
| 65 | return; | |
| 66 | } | |
| 67 | ||
| 68 | va_list ap; | |
| 69 | va_start(ap, format); | |
| 70 | Buf *msg = buf_vprintf(format, ap); | |
| 71 | va_end(ap); | |
| 72 | ||
| 73 | StringRef filename = c->source_manager->getFilename(sl); | |
| 74 | const char *filename_bytes = (const char *)filename.bytes_begin(); | |
| 75 | Buf *path; | |
| 76 | if (filename_bytes) { | |
| 77 | path = buf_create_from_str(filename_bytes); | |
| 78 | } else { | |
| 79 | path = buf_sprintf("(no file)"); | |
| 80 | } | |
| 81 | unsigned line = c->source_manager->getSpellingLineNumber(sl); | |
| 82 | unsigned column = c->source_manager->getSpellingColumnNumber(sl); | |
| 83 | fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg)); | |
| 84 | } | |
| 85 | ||
| 86 | static void add_global_weak_alias(Context *c, Buf *new_name, Buf *canon_name) { | |
| 87 | Alias *alias = c->aliases.add_one(); | |
| 88 | alias->new_name = new_name; | |
| 89 | alias->canon_name = canon_name; | |
| 90 | } | |
| 91 | ||
| 92 | static AstNode * trans_create_node(Context *c, NodeType id) { | |
| 93 | AstNode *node = allocate<AstNode>(1); | |
| 94 | node->type = id; | |
| 95 | node->owner = c->import; | |
| 96 | // TODO line/column. mapping to C file?? | |
| 97 | return node; | |
| 98 | } | |
| 99 | ||
| 100 | static AstNode *trans_create_node_float_lit(Context *c, double value) { | |
| 101 | AstNode *node = trans_create_node(c, NodeTypeFloatLiteral); | |
| 102 | node->data.float_literal.bigfloat = allocate<BigFloat>(1); | |
| 103 | bigfloat_init_64(node->data.float_literal.bigfloat, value); | |
| 104 | return node; | |
| 105 | } | |
| 106 | ||
| 107 | static AstNode *trans_create_node_symbol(Context *c, Buf *name) { | |
| 108 | AstNode *node = trans_create_node(c, NodeTypeSymbol); | |
| 109 | node->data.symbol_expr.symbol = name; | |
| 110 | return node; | |
| 111 | } | |
| 112 | ||
| 113 | static AstNode *trans_create_node_symbol_str(Context *c, const char *name) { | |
| 114 | return trans_create_node_symbol(c, buf_create_from_str(name)); | |
| 115 | } | |
| 116 | ||
| 117 | static AstNode *trans_create_node_builtin_fn_call(Context *c, Buf *name) { | |
| 118 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 119 | node->data.fn_call_expr.fn_ref_expr = trans_create_node_symbol(c, name); | |
| 120 | node->data.fn_call_expr.is_builtin = true; | |
| 121 | return node; | |
| 122 | } | |
| 123 | ||
| 124 | static AstNode *trans_create_node_builtin_fn_call_str(Context *c, const char *name) { | |
| 125 | return trans_create_node_builtin_fn_call(c, buf_create_from_str(name)); | |
| 126 | } | |
| 127 | ||
| 128 | static AstNode *trans_create_node_opaque(Context *c) { | |
| 129 | return trans_create_node_builtin_fn_call_str(c, "OpaqueType"); | |
| 130 | } | |
| 131 | ||
| 132 | static AstNode *trans_create_node_fn_call_1(Context *c, AstNode *fn_ref_expr, AstNode *arg1) { | |
| 133 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 134 | node->data.fn_call_expr.fn_ref_expr = fn_ref_expr; | |
| 135 | node->data.fn_call_expr.params.append(arg1); | |
| 136 | return node; | |
| 137 | } | |
| 138 | ||
| 139 | static AstNode *trans_create_node_field_access(Context *c, AstNode *container, Buf *field_name) { | |
| 140 | AstNode *node = trans_create_node(c, NodeTypeFieldAccessExpr); | |
| 141 | if (container->type == NodeTypeSymbol) { | |
| 142 | assert(container->data.symbol_expr.symbol != nullptr); | |
| 143 | } | |
| 144 | node->data.field_access_expr.struct_expr = container; | |
| 145 | node->data.field_access_expr.field_name = field_name; | |
| 146 | return node; | |
| 147 | } | |
| 148 | ||
| 149 | static AstNode *trans_create_node_field_access_str(Context *c, AstNode *container, const char *field_name) { | |
| 150 | return trans_create_node_field_access(c, container, buf_create_from_str(field_name)); | |
| 151 | } | |
| 152 | ||
| 153 | static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *child_node) { | |
| 154 | AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); | |
| 155 | node->data.prefix_op_expr.prefix_op = op; | |
| 156 | node->data.prefix_op_expr.primary_expr = child_node; | |
| 157 | return node; | |
| 158 | } | |
| 159 | ||
| 160 | static AstNode *trans_create_node_bin_op(Context *c, AstNode *lhs_node, BinOpType op, AstNode *rhs_node) { | |
| 161 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 162 | node->data.bin_op_expr.op1 = lhs_node; | |
| 163 | node->data.bin_op_expr.bin_op = op; | |
| 164 | node->data.bin_op_expr.op2 = rhs_node; | |
| 165 | return node; | |
| 166 | } | |
| 167 | ||
| 168 | static AstNode *maybe_suppress_result(Context *c, bool result_used, AstNode *node) { | |
| 169 | if (result_used) return node; | |
| 170 | return trans_create_node_bin_op(c, | |
| 171 | trans_create_node_symbol_str(c, "_"), | |
| 172 | BinOpTypeAssign, | |
| 173 | node); | |
| 174 | } | |
| 175 | ||
| 176 | static AstNode *trans_create_node_addr_of(Context *c, bool is_const, bool is_volatile, AstNode *child_node) { | |
| 177 | AstNode *node = trans_create_node(c, NodeTypeAddrOfExpr); | |
| 178 | node->data.addr_of_expr.is_const = is_const; | |
| 179 | node->data.addr_of_expr.is_volatile = is_volatile; | |
| 180 | node->data.addr_of_expr.op_expr = child_node; | |
| 181 | return node; | |
| 182 | } | |
| 183 | ||
| 184 | static AstNode *trans_create_node_str_lit_c(Context *c, Buf *buf) { | |
| 185 | AstNode *node = trans_create_node(c, NodeTypeStringLiteral); | |
| 186 | node->data.string_literal.buf = buf; | |
| 187 | node->data.string_literal.c = true; | |
| 188 | return node; | |
| 189 | } | |
| 190 | ||
| 191 | static AstNode *trans_create_node_str_lit_non_c(Context *c, Buf *buf) { | |
| 192 | AstNode *node = trans_create_node(c, NodeTypeStringLiteral); | |
| 193 | node->data.string_literal.buf = buf; | |
| 194 | node->data.string_literal.c = false; | |
| 195 | return node; | |
| 196 | } | |
| 197 | ||
| 198 | static AstNode *trans_create_node_unsigned_negative(Context *c, uint64_t x, bool is_negative) { | |
| 199 | AstNode *node = trans_create_node(c, NodeTypeIntLiteral); | |
| 200 | node->data.int_literal.bigint = allocate<BigInt>(1); | |
| 201 | bigint_init_data(node->data.int_literal.bigint, &x, 1, is_negative); | |
| 202 | return node; | |
| 203 | } | |
| 204 | ||
| 205 | static AstNode *trans_create_node_unsigned(Context *c, uint64_t x) { | |
| 206 | return trans_create_node_unsigned_negative(c, x, false); | |
| 207 | } | |
| 208 | ||
| 209 | static AstNode *trans_create_node_cast(Context *c, AstNode *dest, AstNode *src) { | |
| 210 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 211 | node->data.fn_call_expr.fn_ref_expr = dest; | |
| 212 | node->data.fn_call_expr.params.resize(1); | |
| 213 | node->data.fn_call_expr.params.items[0] = src; | |
| 214 | return node; | |
| 215 | } | |
| 216 | ||
| 217 | static AstNode *trans_create_node_unsigned_negative_type(Context *c, uint64_t x, bool is_negative, | |
| 218 | const char *type_name) | |
| 219 | { | |
| 220 | AstNode *lit_node = trans_create_node_unsigned_negative(c, x, is_negative); | |
| 221 | return trans_create_node_cast(c, trans_create_node_symbol_str(c, type_name), lit_node); | |
| 222 | } | |
| 223 | ||
| 224 | static AstNode *trans_create_node_array_type(Context *c, AstNode *size_node, AstNode *child_type_node) { | |
| 225 | AstNode *node = trans_create_node(c, NodeTypeArrayType); | |
| 226 | node->data.array_type.size = size_node; | |
| 227 | node->data.array_type.child_type = child_type_node; | |
| 228 | return node; | |
| 229 | } | |
| 230 | ||
| 231 | static AstNode *trans_create_node_var_decl(Context *c, VisibMod visib_mod, bool is_const, Buf *var_name, | |
| 232 | AstNode *type_node, AstNode *init_node) | |
| 233 | { | |
| 234 | AstNode *node = trans_create_node(c, NodeTypeVariableDeclaration); | |
| 235 | node->data.variable_declaration.visib_mod = visib_mod; | |
| 236 | node->data.variable_declaration.symbol = var_name; | |
| 237 | node->data.variable_declaration.is_const = is_const; | |
| 238 | node->data.variable_declaration.type = type_node; | |
| 239 | node->data.variable_declaration.expr = init_node; | |
| 240 | return node; | |
| 241 | } | |
| 242 | ||
| 243 | static AstNode *trans_create_node_var_decl_global(Context *c, bool is_const, Buf *var_name, AstNode *type_node, | |
| 244 | AstNode *init_node) | |
| 245 | { | |
| 246 | return trans_create_node_var_decl(c, c->visib_mod, is_const, var_name, type_node, init_node); | |
| 247 | } | |
| 248 | ||
| 249 | static AstNode *trans_create_node_var_decl_local(Context *c, bool is_const, Buf *var_name, AstNode *type_node, | |
| 250 | AstNode *init_node) | |
| 251 | { | |
| 252 | return trans_create_node_var_decl(c, VisibModPrivate, is_const, var_name, type_node, init_node); | |
| 253 | } | |
| 254 | ||
| 255 | ||
| 256 | static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_name, AstNode *src_proto_node) { | |
| 257 | AstNode *fn_def = trans_create_node(c, NodeTypeFnDef); | |
| 258 | AstNode *fn_proto = trans_create_node(c, NodeTypeFnProto); | |
| 259 | fn_proto->data.fn_proto.visib_mod = c->visib_mod; | |
| 260 | fn_proto->data.fn_proto.name = fn_name; | |
| 261 | fn_proto->data.fn_proto.is_inline = true; | |
| 262 | fn_proto->data.fn_proto.return_type = src_proto_node->data.fn_proto.return_type; // TODO ok for these to alias? | |
| 263 | ||
| 264 | fn_def->data.fn_def.fn_proto = fn_proto; | |
| 265 | fn_proto->data.fn_proto.fn_def_node = fn_def; | |
| 266 | ||
| 267 | AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, trans_create_node_symbol(c, var_name)); | |
| 268 | AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 269 | fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node; | |
| 270 | ||
| 271 | for (size_t i = 0; i < src_proto_node->data.fn_proto.params.length; i += 1) { | |
| 272 | AstNode *src_param_node = src_proto_node->data.fn_proto.params.at(i); | |
| 273 | Buf *param_name = src_param_node->data.param_decl.name; | |
| 274 | if (!param_name) param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i); | |
| 275 | ||
| 276 | AstNode *dest_param_node = trans_create_node(c, NodeTypeParamDecl); | |
| 277 | dest_param_node->data.param_decl.name = param_name; | |
| 278 | dest_param_node->data.param_decl.type = src_param_node->data.param_decl.type; | |
| 279 | dest_param_node->data.param_decl.is_noalias = src_param_node->data.param_decl.is_noalias; | |
| 280 | fn_proto->data.fn_proto.params.append(dest_param_node); | |
| 281 | ||
| 282 | fn_call_node->data.fn_call_expr.params.append(trans_create_node_symbol(c, param_name)); | |
| 283 | ||
| 284 | } | |
| 285 | ||
| 286 | AstNode *block = trans_create_node(c, NodeTypeBlock); | |
| 287 | block->data.block.statements.resize(1); | |
| 288 | block->data.block.statements.items[0] = fn_call_node; | |
| 289 | block->data.block.last_statement_is_result_expression = true; | |
| 290 | ||
| 291 | fn_def->data.fn_def.body = block; | |
| 292 | return fn_def; | |
| 293 | } | |
| 294 | ||
| 295 | static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child) { | |
| 296 | return trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, child); | |
| 297 | } | |
| 298 | ||
| 299 | static AstNode *get_global(Context *c, Buf *name) { | |
| 300 | { | |
| 301 | auto entry = c->global_table.maybe_get(name); | |
| 302 | if (entry) { | |
| 303 | return entry->value; | |
| 304 | } | |
| 305 | } | |
| 306 | { | |
| 307 | auto entry = c->macro_table.maybe_get(name); | |
| 308 | if (entry) | |
| 309 | return entry->value; | |
| 310 | } | |
| 311 | return nullptr; | |
| 312 | } | |
| 313 | ||
| 314 | static void add_top_level_decl(Context *c, Buf *name, AstNode *node) { | |
| 315 | c->global_table.put(name, node); | |
| 316 | c->root->data.root.top_level_decls.append(node); | |
| 317 | } | |
| 318 | ||
| 319 | static AstNode *add_global_var(Context *c, Buf *var_name, AstNode *value_node) { | |
| 320 | bool is_const = true; | |
| 321 | AstNode *type_node = nullptr; | |
| 322 | AstNode *node = trans_create_node_var_decl_global(c, is_const, var_name, type_node, value_node); | |
| 323 | add_top_level_decl(c, var_name, node); | |
| 324 | return node; | |
| 325 | } | |
| 326 | ||
| 327 | static const char *decl_name(const Decl *decl) { | |
| 328 | const NamedDecl *named_decl = static_cast<const NamedDecl *>(decl); | |
| 329 | return (const char *)named_decl->getName().bytes_begin(); | |
| 330 | } | |
| 331 | ||
| 332 | static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int) { | |
| 333 | AstNode *node = trans_create_node(c, NodeTypeIntLiteral); | |
| 334 | node->data.int_literal.bigint = allocate<BigInt>(1); | |
| 335 | bigint_init_data(node->data.int_literal.bigint, aps_int.getRawData(), aps_int.getNumWords(), aps_int.isNegative()); | |
| 336 | return node; | |
| 337 | ||
| 338 | } | |
| 339 | ||
| 340 | static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc); | |
| 341 | ||
| 342 | static bool is_c_void_type(AstNode *node) { | |
| 343 | return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void")); | |
| 344 | } | |
| 345 | ||
| 346 | static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, const QualType &qt, AstNode *expr) { | |
| 347 | // TODO: maybe widen to increase size | |
| 348 | // TODO: maybe bitcast to change sign | |
| 349 | // TODO: maybe truncate to reduce size | |
| 350 | return trans_create_node_fn_call_1(c, trans_qual_type(c, qt, source_location), expr); | |
| 351 | } | |
| 352 | ||
| 353 | static bool qual_type_is_fn_ptr(Context *c, const QualType &qt) { | |
| 354 | const Type *ty = qt.getTypePtr(); | |
| 355 | if (ty->getTypeClass() != Type::Pointer) { | |
| 356 | return false; | |
| 357 | } | |
| 358 | const PointerType *pointer_ty = static_cast<const PointerType*>(ty); | |
| 359 | QualType child_qt = pointer_ty->getPointeeType(); | |
| 360 | const Type *child_ty = child_qt.getTypePtr(); | |
| 361 | if (child_ty->getTypeClass() != Type::Paren) { | |
| 362 | return false; | |
| 363 | } | |
| 364 | const ParenType *paren_ty = static_cast<const ParenType *>(child_ty); | |
| 365 | return paren_ty->getInnerType().getTypePtr()->getTypeClass() == Type::FunctionProto; | |
| 366 | } | |
| 367 | ||
| 368 | static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) { | |
| 369 | const Type *ty = qt.getTypePtr(); | |
| 370 | switch (ty->getTypeClass()) { | |
| 371 | case Type::Builtin: | |
| 372 | { | |
| 373 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty); | |
| 374 | switch (builtin_ty->getKind()) { | |
| 375 | case BuiltinType::Char_U: | |
| 376 | case BuiltinType::UChar: | |
| 377 | case BuiltinType::Char_S: | |
| 378 | case BuiltinType::SChar: | |
| 379 | return 8; | |
| 380 | case BuiltinType::UInt128: | |
| 381 | case BuiltinType::Int128: | |
| 382 | return 128; | |
| 383 | default: | |
| 384 | return 0; | |
| 385 | } | |
| 386 | zig_unreachable(); | |
| 387 | } | |
| 388 | case Type::Typedef: | |
| 389 | { | |
| 390 | const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); | |
| 391 | const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); | |
| 392 | const char *type_name = decl_name(typedef_decl); | |
| 393 | if (strcmp(type_name, "uint8_t") == 0 || strcmp(type_name, "int8_t") == 0) { | |
| 394 | return 8; | |
| 395 | } else if (strcmp(type_name, "uint16_t") == 0 || strcmp(type_name, "int16_t") == 0) { | |
| 396 | return 16; | |
| 397 | } else if (strcmp(type_name, "uint32_t") == 0 || strcmp(type_name, "int32_t") == 0) { | |
| 398 | return 32; | |
| 399 | } else if (strcmp(type_name, "uint64_t") == 0 || strcmp(type_name, "int64_t") == 0) { | |
| 400 | return 64; | |
| 401 | } else { | |
| 402 | return 0; | |
| 403 | } | |
| 404 | } | |
| 405 | default: | |
| 406 | return 0; | |
| 407 | } | |
| 408 | zig_unreachable(); | |
| 409 | } | |
| 410 | ||
| 411 | ||
| 412 | static AstNode *qual_type_to_log2_int_ref(Context *c, const QualType &qt, | |
| 413 | const SourceLocation &source_loc) | |
| 414 | { | |
| 415 | uint32_t int_bit_width = qual_type_int_bit_width(c, qt, source_loc); | |
| 416 | if (int_bit_width != 0) { | |
| 417 | // we can perform the log2 now. | |
| 418 | uint64_t cast_bit_width = log2_u64(int_bit_width); | |
| 419 | return trans_create_node_symbol(c, buf_sprintf("u%" ZIG_PRI_u64, cast_bit_width)); | |
| 420 | } | |
| 421 | ||
| 422 | AstNode *zig_type_node = trans_qual_type(c, qt, source_loc); | |
| 423 | ||
| 424 | // @import("std").math.Log2Int(c_long); | |
| 425 | // | |
| 426 | // FnCall | |
| 427 | // FieldAccess | |
| 428 | // FieldAccess | |
| 429 | // FnCall (.builtin = true) | |
| 430 | // Symbol "import" | |
| 431 | // StringLiteral "std" | |
| 432 | // Symbol "math" | |
| 433 | // Symbol "Log2Int" | |
| 434 | // zig_type_node | |
| 435 | ||
| 436 | AstNode *import_fn_call = trans_create_node_builtin_fn_call_str(c, "import"); | |
| 437 | import_fn_call->data.fn_call_expr.params.append(trans_create_node_str_lit_non_c(c, buf_create_from_str("std"))); | |
| 438 | AstNode *inner_field_access = trans_create_node_field_access_str(c, import_fn_call, "math"); | |
| 439 | AstNode *outer_field_access = trans_create_node_field_access_str(c, inner_field_access, "Log2Int"); | |
| 440 | AstNode *log2int_fn_call = trans_create_node_fn_call_1(c, outer_field_access, zig_type_node); | |
| 441 | ||
| 442 | return log2int_fn_call; | |
| 443 | } | |
| 444 | ||
| 445 | static bool qual_type_child_is_fn_proto(const QualType &qt) { | |
| 446 | if (qt.getTypePtr()->getTypeClass() == Type::Paren) { | |
| 447 | const ParenType *paren_type = static_cast<const ParenType *>(qt.getTypePtr()); | |
| 448 | if (paren_type->getInnerType()->getTypeClass() == Type::FunctionProto) { | |
| 449 | return true; | |
| 450 | } | |
| 451 | } else if (qt.getTypePtr()->getTypeClass() == Type::Attributed) { | |
| 452 | const AttributedType *attr_type = static_cast<const AttributedType *>(qt.getTypePtr()); | |
| 453 | return qual_type_child_is_fn_proto(attr_type->getEquivalentType()); | |
| 454 | } | |
| 455 | return false; | |
| 456 | } | |
| 457 | ||
| 458 | static QualType resolve_any_typedef(Context *c, QualType qt) { | |
| 459 | const Type * ty = qt.getTypePtr(); | |
| 460 | if (ty->getTypeClass() != Type::Typedef) | |
| 461 | return qt; | |
| 462 | const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); | |
| 463 | const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); | |
| 464 | return typedef_decl->getUnderlyingType(); | |
| 465 | } | |
| 466 | ||
| 467 | static bool c_is_signed_integer(Context *c, QualType qt) { | |
| 468 | const Type *c_type = resolve_any_typedef(c, qt).getTypePtr(); | |
| 469 | if (c_type->getTypeClass() != Type::Builtin) | |
| 470 | return false; | |
| 471 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | |
| 472 | switch (builtin_ty->getKind()) { | |
| 473 | case BuiltinType::SChar: | |
| 474 | case BuiltinType::Short: | |
| 475 | case BuiltinType::Int: | |
| 476 | case BuiltinType::Long: | |
| 477 | case BuiltinType::LongLong: | |
| 478 | case BuiltinType::Int128: | |
| 479 | case BuiltinType::WChar_S: | |
| 480 | return true; | |
| 481 | default: | |
| 482 | return false; | |
| 483 | } | |
| 484 | } | |
| 485 | ||
| 486 | static bool c_is_unsigned_integer(Context *c, QualType qt) { | |
| 487 | const Type *c_type = resolve_any_typedef(c, qt).getTypePtr(); | |
| 488 | if (c_type->getTypeClass() != Type::Builtin) | |
| 489 | return false; | |
| 490 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | |
| 491 | switch (builtin_ty->getKind()) { | |
| 492 | case BuiltinType::Char_U: | |
| 493 | case BuiltinType::UChar: | |
| 494 | case BuiltinType::Char_S: | |
| 495 | case BuiltinType::UShort: | |
| 496 | case BuiltinType::UInt: | |
| 497 | case BuiltinType::ULong: | |
| 498 | case BuiltinType::ULongLong: | |
| 499 | case BuiltinType::UInt128: | |
| 500 | case BuiltinType::WChar_U: | |
| 501 | return true; | |
| 502 | default: | |
| 503 | return false; | |
| 504 | } | |
| 505 | } | |
| 506 | ||
| 507 | static bool c_is_float(Context *c, QualType qt) { | |
| 508 | const Type *c_type = qt.getTypePtr(); | |
| 509 | if (c_type->getTypeClass() != Type::Builtin) | |
| 510 | return false; | |
| 511 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | |
| 512 | switch (builtin_ty->getKind()) { | |
| 513 | case BuiltinType::Half: | |
| 514 | case BuiltinType::Float: | |
| 515 | case BuiltinType::Double: | |
| 516 | case BuiltinType::Float128: | |
| 517 | case BuiltinType::LongDouble: | |
| 518 | return true; | |
| 519 | default: | |
| 520 | return false; | |
| 521 | } | |
| 522 | } | |
| 523 | ||
| 524 | static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) { | |
| 525 | if (c_is_signed_integer(c, qt) || c_is_float(c, qt)) { | |
| 526 | // float and signed integer overflow is undefined behavior. | |
| 527 | return false; | |
| 528 | } else { | |
| 529 | // unsigned integer overflow wraps around. | |
| 530 | return true; | |
| 531 | } | |
| 532 | } | |
| 533 | ||
| 534 | enum TransLRValue { | |
| 535 | TransLValue, | |
| 536 | TransRValue, | |
| 537 | }; | |
| 538 | ||
| 539 | static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrval); | |
| 540 | static AstNode *const skip_add_to_block_node = (AstNode *) 0x2; | |
| 541 | ||
| 542 | static AstNode *trans_expr(Context *c, bool result_used, AstNode *block, Expr *expr, TransLRValue lrval) { | |
| 543 | return trans_stmt(c, result_used, block, expr, lrval); | |
| 544 | } | |
| 545 | ||
| 546 | static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) { | |
| 547 | switch (ty->getTypeClass()) { | |
| 548 | case Type::Builtin: | |
| 549 | { | |
| 550 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty); | |
| 551 | switch (builtin_ty->getKind()) { | |
| 552 | case BuiltinType::Void: | |
| 553 | return trans_create_node_symbol_str(c, "c_void"); | |
| 554 | case BuiltinType::Bool: | |
| 555 | return trans_create_node_symbol_str(c, "bool"); | |
| 556 | case BuiltinType::Char_U: | |
| 557 | case BuiltinType::UChar: | |
| 558 | case BuiltinType::Char_S: | |
| 559 | return trans_create_node_symbol_str(c, "u8"); | |
| 560 | case BuiltinType::SChar: | |
| 561 | return trans_create_node_symbol_str(c, "i8"); | |
| 562 | case BuiltinType::UShort: | |
| 563 | return trans_create_node_symbol_str(c, "c_ushort"); | |
| 564 | case BuiltinType::UInt: | |
| 565 | return trans_create_node_symbol_str(c, "c_uint"); | |
| 566 | case BuiltinType::ULong: | |
| 567 | return trans_create_node_symbol_str(c, "c_ulong"); | |
| 568 | case BuiltinType::ULongLong: | |
| 569 | return trans_create_node_symbol_str(c, "c_ulonglong"); | |
| 570 | case BuiltinType::Short: | |
| 571 | return trans_create_node_symbol_str(c, "c_short"); | |
| 572 | case BuiltinType::Int: | |
| 573 | return trans_create_node_symbol_str(c, "c_int"); | |
| 574 | case BuiltinType::Long: | |
| 575 | return trans_create_node_symbol_str(c, "c_long"); | |
| 576 | case BuiltinType::LongLong: | |
| 577 | return trans_create_node_symbol_str(c, "c_longlong"); | |
| 578 | case BuiltinType::UInt128: | |
| 579 | return trans_create_node_symbol_str(c, "u128"); | |
| 580 | case BuiltinType::Int128: | |
| 581 | return trans_create_node_symbol_str(c, "i128"); | |
| 582 | case BuiltinType::Float: | |
| 583 | return trans_create_node_symbol_str(c, "f32"); | |
| 584 | case BuiltinType::Double: | |
| 585 | return trans_create_node_symbol_str(c, "f64"); | |
| 586 | case BuiltinType::Float128: | |
| 587 | return trans_create_node_symbol_str(c, "f128"); | |
| 588 | case BuiltinType::LongDouble: | |
| 589 | return trans_create_node_symbol_str(c, "c_longdouble"); | |
| 590 | case BuiltinType::WChar_U: | |
| 591 | case BuiltinType::Char16: | |
| 592 | case BuiltinType::Char32: | |
| 593 | case BuiltinType::WChar_S: | |
| 594 | case BuiltinType::Half: | |
| 595 | case BuiltinType::NullPtr: | |
| 596 | case BuiltinType::ObjCId: | |
| 597 | case BuiltinType::ObjCClass: | |
| 598 | case BuiltinType::ObjCSel: | |
| 599 | case BuiltinType::OMPArraySection: | |
| 600 | case BuiltinType::Dependent: | |
| 601 | case BuiltinType::Overload: | |
| 602 | case BuiltinType::BoundMember: | |
| 603 | case BuiltinType::PseudoObject: | |
| 604 | case BuiltinType::UnknownAny: | |
| 605 | case BuiltinType::BuiltinFn: | |
| 606 | case BuiltinType::ARCUnbridgedCast: | |
| 607 | ||
| 608 | case BuiltinType::OCLImage1dRO: | |
| 609 | case BuiltinType::OCLImage1dArrayRO: | |
| 610 | case BuiltinType::OCLImage1dBufferRO: | |
| 611 | case BuiltinType::OCLImage2dRO: | |
| 612 | case BuiltinType::OCLImage2dArrayRO: | |
| 613 | case BuiltinType::OCLImage2dDepthRO: | |
| 614 | case BuiltinType::OCLImage2dArrayDepthRO: | |
| 615 | case BuiltinType::OCLImage2dMSAARO: | |
| 616 | case BuiltinType::OCLImage2dArrayMSAARO: | |
| 617 | case BuiltinType::OCLImage2dMSAADepthRO: | |
| 618 | case BuiltinType::OCLImage2dArrayMSAADepthRO: | |
| 619 | case BuiltinType::OCLImage3dRO: | |
| 620 | case BuiltinType::OCLImage1dWO: | |
| 621 | case BuiltinType::OCLImage1dArrayWO: | |
| 622 | case BuiltinType::OCLImage1dBufferWO: | |
| 623 | case BuiltinType::OCLImage2dWO: | |
| 624 | case BuiltinType::OCLImage2dArrayWO: | |
| 625 | case BuiltinType::OCLImage2dDepthWO: | |
| 626 | case BuiltinType::OCLImage2dArrayDepthWO: | |
| 627 | case BuiltinType::OCLImage2dMSAAWO: | |
| 628 | case BuiltinType::OCLImage2dArrayMSAAWO: | |
| 629 | case BuiltinType::OCLImage2dMSAADepthWO: | |
| 630 | case BuiltinType::OCLImage2dArrayMSAADepthWO: | |
| 631 | case BuiltinType::OCLImage3dWO: | |
| 632 | case BuiltinType::OCLImage1dRW: | |
| 633 | case BuiltinType::OCLImage1dArrayRW: | |
| 634 | case BuiltinType::OCLImage1dBufferRW: | |
| 635 | case BuiltinType::OCLImage2dRW: | |
| 636 | case BuiltinType::OCLImage2dArrayRW: | |
| 637 | case BuiltinType::OCLImage2dDepthRW: | |
| 638 | case BuiltinType::OCLImage2dArrayDepthRW: | |
| 639 | case BuiltinType::OCLImage2dMSAARW: | |
| 640 | case BuiltinType::OCLImage2dArrayMSAARW: | |
| 641 | case BuiltinType::OCLImage2dMSAADepthRW: | |
| 642 | case BuiltinType::OCLImage2dArrayMSAADepthRW: | |
| 643 | case BuiltinType::OCLImage3dRW: | |
| 644 | case BuiltinType::OCLSampler: | |
| 645 | case BuiltinType::OCLEvent: | |
| 646 | case BuiltinType::OCLClkEvent: | |
| 647 | case BuiltinType::OCLQueue: | |
| 648 | case BuiltinType::OCLReserveID: | |
| 649 | emit_warning(c, source_loc, "unsupported builtin type"); | |
| 650 | return nullptr; | |
| 651 | } | |
| 652 | break; | |
| 653 | } | |
| 654 | case Type::Pointer: | |
| 655 | { | |
| 656 | const PointerType *pointer_ty = static_cast<const PointerType*>(ty); | |
| 657 | QualType child_qt = pointer_ty->getPointeeType(); | |
| 658 | AstNode *child_node = trans_qual_type(c, child_qt, source_loc); | |
| 659 | if (child_node == nullptr) { | |
| 660 | emit_warning(c, source_loc, "pointer to unsupported type"); | |
| 661 | return nullptr; | |
| 662 | } | |
| 663 | ||
| 664 | if (qual_type_child_is_fn_proto(child_qt)) { | |
| 665 | return trans_create_node_prefix_op(c, PrefixOpMaybe, child_node); | |
| 666 | } | |
| 667 | ||
| 668 | AstNode *pointer_node = trans_create_node_addr_of(c, child_qt.isConstQualified(), | |
| 669 | child_qt.isVolatileQualified(), child_node); | |
| 670 | return trans_create_node_prefix_op(c, PrefixOpMaybe, pointer_node); | |
| 671 | } | |
| 672 | case Type::Typedef: | |
| 673 | { | |
| 674 | const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); | |
| 675 | const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); | |
| 676 | return resolve_typedef_decl(c, typedef_decl); | |
| 677 | } | |
| 678 | case Type::Elaborated: | |
| 679 | { | |
| 680 | const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty); | |
| 681 | switch (elaborated_ty->getKeyword()) { | |
| 682 | case ETK_Struct: | |
| 683 | case ETK_Enum: | |
| 684 | case ETK_Union: | |
| 685 | return trans_qual_type(c, elaborated_ty->getNamedType(), source_loc); | |
| 686 | case ETK_Interface: | |
| 687 | case ETK_Class: | |
| 688 | case ETK_Typename: | |
| 689 | case ETK_None: | |
| 690 | emit_warning(c, source_loc, "unsupported elaborated type"); | |
| 691 | return nullptr; | |
| 692 | } | |
| 693 | } | |
| 694 | case Type::FunctionProto: | |
| 695 | { | |
| 696 | const FunctionProtoType *fn_proto_ty = static_cast<const FunctionProtoType*>(ty); | |
| 697 | ||
| 698 | AstNode *proto_node = trans_create_node(c, NodeTypeFnProto); | |
| 699 | switch (fn_proto_ty->getCallConv()) { | |
| 700 | case CC_C: // __attribute__((cdecl)) | |
| 701 | proto_node->data.fn_proto.cc = CallingConventionC; | |
| 702 | proto_node->data.fn_proto.is_extern = true; | |
| 703 | break; | |
| 704 | case CC_X86StdCall: // __attribute__((stdcall)) | |
| 705 | proto_node->data.fn_proto.cc = CallingConventionStdcall; | |
| 706 | break; | |
| 707 | case CC_X86FastCall: // __attribute__((fastcall)) | |
| 708 | emit_warning(c, source_loc, "unsupported calling convention: x86 fastcall"); | |
| 709 | return nullptr; | |
| 710 | case CC_X86ThisCall: // __attribute__((thiscall)) | |
| 711 | emit_warning(c, source_loc, "unsupported calling convention: x86 thiscall"); | |
| 712 | return nullptr; | |
| 713 | case CC_X86VectorCall: // __attribute__((vectorcall)) | |
| 714 | emit_warning(c, source_loc, "unsupported calling convention: x86 vectorcall"); | |
| 715 | return nullptr; | |
| 716 | case CC_X86Pascal: // __attribute__((pascal)) | |
| 717 | emit_warning(c, source_loc, "unsupported calling convention: x86 pascal"); | |
| 718 | return nullptr; | |
| 719 | case CC_Win64: // __attribute__((ms_abi)) | |
| 720 | emit_warning(c, source_loc, "unsupported calling convention: win64"); | |
| 721 | return nullptr; | |
| 722 | case CC_X86_64SysV: // __attribute__((sysv_abi)) | |
| 723 | emit_warning(c, source_loc, "unsupported calling convention: x86 64sysv"); | |
| 724 | return nullptr; | |
| 725 | case CC_X86RegCall: | |
| 726 | emit_warning(c, source_loc, "unsupported calling convention: x86 reg"); | |
| 727 | return nullptr; | |
| 728 | case CC_AAPCS: // __attribute__((pcs("aapcs"))) | |
| 729 | emit_warning(c, source_loc, "unsupported calling convention: aapcs"); | |
| 730 | return nullptr; | |
| 731 | case CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp"))) | |
| 732 | emit_warning(c, source_loc, "unsupported calling convention: aapcs-vfp"); | |
| 733 | return nullptr; | |
| 734 | case CC_IntelOclBicc: // __attribute__((intel_ocl_bicc)) | |
| 735 | emit_warning(c, source_loc, "unsupported calling convention: intel_ocl_bicc"); | |
| 736 | return nullptr; | |
| 737 | case CC_SpirFunction: // default for OpenCL functions on SPIR target | |
| 738 | emit_warning(c, source_loc, "unsupported calling convention: SPIR function"); | |
| 739 | return nullptr; | |
| 740 | case CC_OpenCLKernel: | |
| 741 | emit_warning(c, source_loc, "unsupported calling convention: OpenCLKernel"); | |
| 742 | return nullptr; | |
| 743 | case CC_Swift: | |
| 744 | emit_warning(c, source_loc, "unsupported calling convention: Swift"); | |
| 745 | return nullptr; | |
| 746 | case CC_PreserveMost: | |
| 747 | emit_warning(c, source_loc, "unsupported calling convention: PreserveMost"); | |
| 748 | return nullptr; | |
| 749 | case CC_PreserveAll: | |
| 750 | emit_warning(c, source_loc, "unsupported calling convention: PreserveAll"); | |
| 751 | return nullptr; | |
| 752 | } | |
| 753 | ||
| 754 | proto_node->data.fn_proto.is_var_args = fn_proto_ty->isVariadic(); | |
| 755 | size_t param_count = fn_proto_ty->getNumParams(); | |
| 756 | ||
| 757 | if (fn_proto_ty->getNoReturnAttr()) { | |
| 758 | proto_node->data.fn_proto.return_type = trans_create_node_symbol_str(c, "noreturn"); | |
| 759 | } else { | |
| 760 | proto_node->data.fn_proto.return_type = trans_qual_type(c, fn_proto_ty->getReturnType(), | |
| 761 | source_loc); | |
| 762 | if (proto_node->data.fn_proto.return_type == nullptr) { | |
| 763 | emit_warning(c, source_loc, "unsupported function proto return type"); | |
| 764 | return nullptr; | |
| 765 | } | |
| 766 | // convert c_void to actual void (only for return type) | |
| 767 | if (is_c_void_type(proto_node->data.fn_proto.return_type)) { | |
| 768 | proto_node->data.fn_proto.return_type = nullptr; | |
| 769 | } | |
| 770 | } | |
| 771 | ||
| 772 | //emit_warning(c, source_loc, "TODO figure out fn prototype fn name"); | |
| 773 | const char *fn_name = nullptr; | |
| 774 | if (fn_name != nullptr) { | |
| 775 | proto_node->data.fn_proto.name = buf_create_from_str(fn_name); | |
| 776 | } | |
| 777 | ||
| 778 | for (size_t i = 0; i < param_count; i += 1) { | |
| 779 | QualType qt = fn_proto_ty->getParamType(i); | |
| 780 | AstNode *param_type_node = trans_qual_type(c, qt, source_loc); | |
| 781 | ||
| 782 | if (param_type_node == nullptr) { | |
| 783 | emit_warning(c, source_loc, "unresolved function proto parameter type"); | |
| 784 | return nullptr; | |
| 785 | } | |
| 786 | ||
| 787 | AstNode *param_node = trans_create_node(c, NodeTypeParamDecl); | |
| 788 | //emit_warning(c, source_loc, "TODO figure out fn prototype param name"); | |
| 789 | const char *param_name = nullptr; | |
| 790 | if (param_name != nullptr) { | |
| 791 | param_node->data.param_decl.name = buf_create_from_str(param_name); | |
| 792 | } | |
| 793 | param_node->data.param_decl.is_noalias = qt.isRestrictQualified(); | |
| 794 | param_node->data.param_decl.type = param_type_node; | |
| 795 | proto_node->data.fn_proto.params.append(param_node); | |
| 796 | } | |
| 797 | // TODO check for always_inline attribute | |
| 798 | // TODO check for align attribute | |
| 799 | ||
| 800 | return proto_node; | |
| 801 | } | |
| 802 | case Type::Record: | |
| 803 | { | |
| 804 | const RecordType *record_ty = static_cast<const RecordType*>(ty); | |
| 805 | return resolve_record_decl(c, record_ty->getDecl()); | |
| 806 | } | |
| 807 | case Type::Enum: | |
| 808 | { | |
| 809 | const EnumType *enum_ty = static_cast<const EnumType*>(ty); | |
| 810 | return resolve_enum_decl(c, enum_ty->getDecl()); | |
| 811 | } | |
| 812 | case Type::ConstantArray: | |
| 813 | { | |
| 814 | const ConstantArrayType *const_arr_ty = static_cast<const ConstantArrayType *>(ty); | |
| 815 | AstNode *child_type_node = trans_qual_type(c, const_arr_ty->getElementType(), source_loc); | |
| 816 | if (child_type_node == nullptr) { | |
| 817 | emit_warning(c, source_loc, "unresolved array element type"); | |
| 818 | return nullptr; | |
| 819 | } | |
| 820 | uint64_t size = const_arr_ty->getSize().getLimitedValue(); | |
| 821 | AstNode *size_node = trans_create_node_unsigned(c, size); | |
| 822 | return trans_create_node_array_type(c, size_node, child_type_node); | |
| 823 | } | |
| 824 | case Type::Paren: | |
| 825 | { | |
| 826 | const ParenType *paren_ty = static_cast<const ParenType *>(ty); | |
| 827 | return trans_qual_type(c, paren_ty->getInnerType(), source_loc); | |
| 828 | } | |
| 829 | case Type::Decayed: | |
| 830 | { | |
| 831 | const DecayedType *decayed_ty = static_cast<const DecayedType *>(ty); | |
| 832 | return trans_qual_type(c, decayed_ty->getDecayedType(), source_loc); | |
| 833 | } | |
| 834 | case Type::Attributed: | |
| 835 | { | |
| 836 | const AttributedType *attributed_ty = static_cast<const AttributedType *>(ty); | |
| 837 | return trans_qual_type(c, attributed_ty->getEquivalentType(), source_loc); | |
| 838 | } | |
| 839 | case Type::BlockPointer: | |
| 840 | case Type::LValueReference: | |
| 841 | case Type::RValueReference: | |
| 842 | case Type::MemberPointer: | |
| 843 | case Type::IncompleteArray: | |
| 844 | case Type::VariableArray: | |
| 845 | case Type::DependentSizedArray: | |
| 846 | case Type::DependentSizedExtVector: | |
| 847 | case Type::Vector: | |
| 848 | case Type::ExtVector: | |
| 849 | case Type::FunctionNoProto: | |
| 850 | case Type::UnresolvedUsing: | |
| 851 | case Type::Adjusted: | |
| 852 | case Type::TypeOfExpr: | |
| 853 | case Type::TypeOf: | |
| 854 | case Type::Decltype: | |
| 855 | case Type::UnaryTransform: | |
| 856 | case Type::TemplateTypeParm: | |
| 857 | case Type::SubstTemplateTypeParm: | |
| 858 | case Type::SubstTemplateTypeParmPack: | |
| 859 | case Type::TemplateSpecialization: | |
| 860 | case Type::Auto: | |
| 861 | case Type::InjectedClassName: | |
| 862 | case Type::DependentName: | |
| 863 | case Type::DependentTemplateSpecialization: | |
| 864 | case Type::PackExpansion: | |
| 865 | case Type::ObjCObject: | |
| 866 | case Type::ObjCInterface: | |
| 867 | case Type::Complex: | |
| 868 | case Type::ObjCObjectPointer: | |
| 869 | case Type::Atomic: | |
| 870 | case Type::Pipe: | |
| 871 | case Type::ObjCTypeParam: | |
| 872 | case Type::DeducedTemplateSpecialization: | |
| 873 | emit_warning(c, source_loc, "unsupported type: '%s'", ty->getTypeClassName()); | |
| 874 | return nullptr; | |
| 875 | } | |
| 876 | zig_unreachable(); | |
| 877 | } | |
| 878 | ||
| 879 | static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc) { | |
| 880 | return trans_type(c, qt.getTypePtr(), source_loc); | |
| 881 | } | |
| 882 | ||
| 883 | static AstNode *trans_compound_stmt(Context *c, AstNode *parent, CompoundStmt *stmt) { | |
| 884 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 885 | for (CompoundStmt::body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) { | |
| 886 | AstNode *child_node = trans_stmt(c, false, child_block, *it, TransRValue); | |
| 887 | if (child_node == nullptr) | |
| 888 | return nullptr; | |
| 889 | if (child_node != skip_add_to_block_node) | |
| 890 | child_block->data.block.statements.append(child_node); | |
| 891 | } | |
| 892 | return child_block; | |
| 893 | } | |
| 894 | ||
| 895 | static AstNode *trans_return_stmt(Context *c, AstNode *block, ReturnStmt *stmt) { | |
| 896 | Expr *value_expr = stmt->getRetValue(); | |
| 897 | if (value_expr == nullptr) { | |
| 898 | emit_warning(c, stmt->getLocStart(), "TODO handle C return void"); | |
| 899 | return nullptr; | |
| 900 | } else { | |
| 901 | AstNode *return_node = trans_create_node(c, NodeTypeReturnExpr); | |
| 902 | return_node->data.return_expr.expr = trans_expr(c, true, block, value_expr, TransRValue); | |
| 903 | if (return_node->data.return_expr.expr == nullptr) | |
| 904 | return nullptr; | |
| 905 | return return_node; | |
| 906 | } | |
| 907 | } | |
| 908 | ||
| 909 | static AstNode *trans_integer_literal(Context *c, IntegerLiteral *stmt) { | |
| 910 | llvm::APSInt result; | |
| 911 | if (!stmt->EvaluateAsInt(result, *c->ctx)) { | |
| 912 | emit_warning(c, stmt->getLocStart(), "invalid integer literal"); | |
| 913 | return nullptr; | |
| 914 | } | |
| 915 | return trans_create_node_apint(c, result); | |
| 916 | } | |
| 917 | ||
| 918 | static AstNode *trans_conditional_operator(Context *c, bool result_used, AstNode *block, ConditionalOperator *stmt) { | |
| 919 | AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr); | |
| 920 | ||
| 921 | Expr *cond_expr = stmt->getCond(); | |
| 922 | Expr *true_expr = stmt->getTrueExpr(); | |
| 923 | Expr *false_expr = stmt->getFalseExpr(); | |
| 924 | ||
| 925 | node->data.if_bool_expr.condition = trans_expr(c, true, block, cond_expr, TransRValue); | |
| 926 | if (node->data.if_bool_expr.condition == nullptr) | |
| 927 | return nullptr; | |
| 928 | ||
| 929 | node->data.if_bool_expr.then_block = trans_expr(c, result_used, block, true_expr, TransRValue); | |
| 930 | if (node->data.if_bool_expr.then_block == nullptr) | |
| 931 | return nullptr; | |
| 932 | ||
| 933 | node->data.if_bool_expr.else_node = trans_expr(c, result_used, block, false_expr, TransRValue); | |
| 934 | if (node->data.if_bool_expr.else_node == nullptr) | |
| 935 | return nullptr; | |
| 936 | ||
| 937 | return maybe_suppress_result(c, result_used, node); | |
| 938 | } | |
| 939 | ||
| 940 | static AstNode *trans_create_bin_op(Context *c, AstNode *block, Expr *lhs, BinOpType bin_op, Expr *rhs) { | |
| 941 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 942 | node->data.bin_op_expr.bin_op = bin_op; | |
| 943 | ||
| 944 | node->data.bin_op_expr.op1 = trans_expr(c, true, block, lhs, TransRValue); | |
| 945 | if (node->data.bin_op_expr.op1 == nullptr) | |
| 946 | return nullptr; | |
| 947 | ||
| 948 | node->data.bin_op_expr.op2 = trans_expr(c, true, block, rhs, TransRValue); | |
| 949 | if (node->data.bin_op_expr.op2 == nullptr) | |
| 950 | return nullptr; | |
| 951 | ||
| 952 | return node; | |
| 953 | } | |
| 954 | ||
| 955 | static AstNode *trans_create_assign(Context *c, bool result_used, AstNode *block, Expr *lhs, Expr *rhs) { | |
| 956 | if (!result_used) { | |
| 957 | // common case | |
| 958 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 959 | node->data.bin_op_expr.bin_op = BinOpTypeAssign; | |
| 960 | ||
| 961 | node->data.bin_op_expr.op1 = trans_expr(c, true, block, lhs, TransLValue); | |
| 962 | if (node->data.bin_op_expr.op1 == nullptr) | |
| 963 | return nullptr; | |
| 964 | ||
| 965 | node->data.bin_op_expr.op2 = trans_expr(c, true, block, rhs, TransRValue); | |
| 966 | if (node->data.bin_op_expr.op2 == nullptr) | |
| 967 | return nullptr; | |
| 968 | ||
| 969 | return node; | |
| 970 | } else { | |
| 971 | // worst case | |
| 972 | // c: lhs = rhs | |
| 973 | // zig: { | |
| 974 | // zig: const _tmp = rhs; | |
| 975 | // zig: lhs = _tmp; | |
| 976 | // zig: _tmp | |
| 977 | // zig: } | |
| 978 | ||
| 979 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 980 | ||
| 981 | // const _tmp = rhs; | |
| 982 | AstNode *rhs_node = trans_expr(c, true, child_block, rhs, TransRValue); | |
| 983 | if (rhs_node == nullptr) return nullptr; | |
| 984 | // TODO: avoid name collisions with generated variable names | |
| 985 | Buf* tmp_var_name = buf_create_from_str("_tmp"); | |
| 986 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, rhs_node); | |
| 987 | child_block->data.block.statements.append(tmp_var_decl); | |
| 988 | ||
| 989 | // lhs = _tmp; | |
| 990 | AstNode *lhs_node = trans_expr(c, true, child_block, lhs, TransLValue); | |
| 991 | if (lhs_node == nullptr) return nullptr; | |
| 992 | child_block->data.block.statements.append( | |
| 993 | trans_create_node_bin_op(c, lhs_node, BinOpTypeAssign, | |
| 994 | trans_create_node_symbol(c, tmp_var_name))); | |
| 995 | ||
| 996 | // _tmp | |
| 997 | child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name)); | |
| 998 | child_block->data.block.last_statement_is_result_expression = true; | |
| 999 | ||
| 1000 | return child_block; | |
| 1001 | } | |
| 1002 | } | |
| 1003 | ||
| 1004 | static AstNode *trans_create_shift_op(Context *c, AstNode *block, QualType result_type, Expr *lhs_expr, BinOpType bin_op, Expr *rhs_expr) { | |
| 1005 | const SourceLocation &rhs_location = rhs_expr->getLocStart(); | |
| 1006 | AstNode *rhs_type = qual_type_to_log2_int_ref(c, result_type, rhs_location); | |
| 1007 | // lhs >> u5(rh) | |
| 1008 | ||
| 1009 | AstNode *lhs = trans_expr(c, true, block, lhs_expr, TransLValue); | |
| 1010 | if (lhs == nullptr) return nullptr; | |
| 1011 | ||
| 1012 | AstNode *rhs = trans_expr(c, true, block, rhs_expr, TransRValue); | |
| 1013 | if (rhs == nullptr) return nullptr; | |
| 1014 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); | |
| 1015 | ||
| 1016 | return trans_create_node_bin_op(c, lhs, bin_op, coerced_rhs); | |
| 1017 | } | |
| 1018 | ||
| 1019 | static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *block, BinaryOperator *stmt) { | |
| 1020 | switch (stmt->getOpcode()) { | |
| 1021 | case BO_PtrMemD: | |
| 1022 | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_PtrMemD"); | |
| 1023 | return nullptr; | |
| 1024 | case BO_PtrMemI: | |
| 1025 | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_PtrMemI"); | |
| 1026 | return nullptr; | |
| 1027 | case BO_Mul: | |
| 1028 | return trans_create_bin_op(c, block, stmt->getLHS(), | |
| 1029 | qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeMultWrap : BinOpTypeMult, | |
| 1030 | stmt->getRHS()); | |
| 1031 | case BO_Div: | |
| 1032 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) { | |
| 1033 | // unsigned/float division uses the operator | |
| 1034 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeDiv, stmt->getRHS()); | |
| 1035 | } else { | |
| 1036 | // signed integer division uses @divTrunc | |
| 1037 | AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "divTrunc"); | |
| 1038 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); | |
| 1039 | if (lhs == nullptr) return nullptr; | |
| 1040 | fn_call->data.fn_call_expr.params.append(lhs); | |
| 1041 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransLValue); | |
| 1042 | if (rhs == nullptr) return nullptr; | |
| 1043 | fn_call->data.fn_call_expr.params.append(rhs); | |
| 1044 | return fn_call; | |
| 1045 | } | |
| 1046 | case BO_Rem: | |
| 1047 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) { | |
| 1048 | // unsigned/float division uses the operator | |
| 1049 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeMod, stmt->getRHS()); | |
| 1050 | } else { | |
| 1051 | // signed integer division uses @rem | |
| 1052 | AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem"); | |
| 1053 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); | |
| 1054 | if (lhs == nullptr) return nullptr; | |
| 1055 | fn_call->data.fn_call_expr.params.append(lhs); | |
| 1056 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransLValue); | |
| 1057 | if (rhs == nullptr) return nullptr; | |
| 1058 | fn_call->data.fn_call_expr.params.append(rhs); | |
| 1059 | return fn_call; | |
| 1060 | } | |
| 1061 | case BO_Add: | |
| 1062 | return trans_create_bin_op(c, block, stmt->getLHS(), | |
| 1063 | qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeAddWrap : BinOpTypeAdd, | |
| 1064 | stmt->getRHS()); | |
| 1065 | case BO_Sub: | |
| 1066 | return trans_create_bin_op(c, block, stmt->getLHS(), | |
| 1067 | qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeSubWrap : BinOpTypeSub, | |
| 1068 | stmt->getRHS()); | |
| 1069 | case BO_Shl: | |
| 1070 | return trans_create_shift_op(c, block, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftLeft, stmt->getRHS()); | |
| 1071 | case BO_Shr: | |
| 1072 | return trans_create_shift_op(c, block, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftRight, stmt->getRHS()); | |
| 1073 | case BO_LT: | |
| 1074 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS()); | |
| 1075 | case BO_GT: | |
| 1076 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpGreaterThan, stmt->getRHS()); | |
| 1077 | case BO_LE: | |
| 1078 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpLessOrEq, stmt->getRHS()); | |
| 1079 | case BO_GE: | |
| 1080 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpGreaterOrEq, stmt->getRHS()); | |
| 1081 | case BO_EQ: | |
| 1082 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpEq, stmt->getRHS()); | |
| 1083 | case BO_NE: | |
| 1084 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpNotEq, stmt->getRHS()); | |
| 1085 | case BO_And: | |
| 1086 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinAnd, stmt->getRHS()); | |
| 1087 | case BO_Xor: | |
| 1088 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinXor, stmt->getRHS()); | |
| 1089 | case BO_Or: | |
| 1090 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinOr, stmt->getRHS()); | |
| 1091 | case BO_LAnd: | |
| 1092 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS()); | |
| 1093 | case BO_LOr: | |
| 1094 | // TODO: int vs bool | |
| 1095 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS()); | |
| 1096 | case BO_Assign: | |
| 1097 | return trans_create_assign(c, result_used, block, stmt->getLHS(), stmt->getRHS()); | |
| 1098 | case BO_Comma: | |
| 1099 | { | |
| 1100 | block = trans_create_node(c, NodeTypeBlock); | |
| 1101 | AstNode *lhs = trans_expr(c, false, block, stmt->getLHS(), TransRValue); | |
| 1102 | if (lhs == nullptr) return nullptr; | |
| 1103 | block->data.block.statements.append(maybe_suppress_result(c, false, lhs)); | |
| 1104 | AstNode *rhs = trans_expr(c, result_used, block, stmt->getRHS(), TransRValue); | |
| 1105 | if (rhs == nullptr) return nullptr; | |
| 1106 | block->data.block.statements.append(maybe_suppress_result(c, result_used, rhs)); | |
| 1107 | block->data.block.last_statement_is_result_expression = true; | |
| 1108 | return block; | |
| 1109 | } | |
| 1110 | case BO_MulAssign: | |
| 1111 | case BO_DivAssign: | |
| 1112 | case BO_RemAssign: | |
| 1113 | case BO_AddAssign: | |
| 1114 | case BO_SubAssign: | |
| 1115 | case BO_ShlAssign: | |
| 1116 | case BO_ShrAssign: | |
| 1117 | case BO_AndAssign: | |
| 1118 | case BO_XorAssign: | |
| 1119 | case BO_OrAssign: | |
| 1120 | zig_unreachable(); | |
| 1121 | } | |
| 1122 | ||
| 1123 | zig_unreachable(); | |
| 1124 | } | |
| 1125 | ||
| 1126 | static AstNode *trans_create_compound_assign_shift(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) { | |
| 1127 | const SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); | |
| 1128 | AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); | |
| 1129 | ||
| 1130 | bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr(); | |
| 1131 | if (!use_intermediate_casts && !result_used) { | |
| 1132 | // simple common case, where the C and Zig are identical: | |
| 1133 | // lhs >>= rhs | |
| 1134 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); | |
| 1135 | if (lhs == nullptr) return nullptr; | |
| 1136 | ||
| 1137 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue); | |
| 1138 | if (rhs == nullptr) return nullptr; | |
| 1139 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); | |
| 1140 | ||
| 1141 | return trans_create_node_bin_op(c, lhs, assign_op, coerced_rhs); | |
| 1142 | } else { | |
| 1143 | // need more complexity. worst case, this looks like this: | |
| 1144 | // c: lhs >>= rhs | |
| 1145 | // zig: { | |
| 1146 | // zig: const _ref = &lhs; | |
| 1147 | // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs)); | |
| 1148 | // zig: *_ref | |
| 1149 | // zig: } | |
| 1150 | // where u5 is the appropriate type | |
| 1151 | ||
| 1152 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 1153 | ||
| 1154 | // const _ref = &lhs; | |
| 1155 | AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue); | |
| 1156 | if (lhs == nullptr) return nullptr; | |
| 1157 | AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs); | |
| 1158 | // TODO: avoid name collisions with generated variable names | |
| 1159 | Buf* tmp_var_name = buf_create_from_str("_ref"); | |
| 1160 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); | |
| 1161 | child_block->data.block.statements.append(tmp_var_decl); | |
| 1162 | ||
| 1163 | // *_ref = result_type(operation_type(*_ref) >> u5(rhs)); | |
| 1164 | ||
| 1165 | AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue); | |
| 1166 | if (rhs == nullptr) return nullptr; | |
| 1167 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); | |
| 1168 | ||
| 1169 | AstNode *assign_statement = trans_create_node_bin_op(c, | |
| 1170 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1171 | trans_create_node_symbol(c, tmp_var_name)), | |
| 1172 | BinOpTypeAssign, | |
| 1173 | trans_c_cast(c, rhs_location, | |
| 1174 | stmt->getComputationResultType(), | |
| 1175 | trans_create_node_bin_op(c, | |
| 1176 | trans_c_cast(c, rhs_location, | |
| 1177 | stmt->getComputationLHSType(), | |
| 1178 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1179 | trans_create_node_symbol(c, tmp_var_name))), | |
| 1180 | bin_op, | |
| 1181 | coerced_rhs))); | |
| 1182 | child_block->data.block.statements.append(assign_statement); | |
| 1183 | ||
| 1184 | if (result_used) { | |
| 1185 | // *_ref | |
| 1186 | child_block->data.block.statements.append( | |
| 1187 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1188 | trans_create_node_symbol(c, tmp_var_name))); | |
| 1189 | child_block->data.block.last_statement_is_result_expression = true; | |
| 1190 | } | |
| 1191 | ||
| 1192 | return child_block; | |
| 1193 | } | |
| 1194 | } | |
| 1195 | ||
| 1196 | static AstNode *trans_create_compound_assign(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) { | |
| 1197 | if (!result_used) { | |
| 1198 | // simple common case, where the C and Zig are identical: | |
| 1199 | // lhs += rhs | |
| 1200 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); | |
| 1201 | if (lhs == nullptr) return nullptr; | |
| 1202 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue); | |
| 1203 | if (rhs == nullptr) return nullptr; | |
| 1204 | return trans_create_node_bin_op(c, lhs, assign_op, rhs); | |
| 1205 | } else { | |
| 1206 | // need more complexity. worst case, this looks like this: | |
| 1207 | // c: lhs += rhs | |
| 1208 | // zig: { | |
| 1209 | // zig: const _ref = &lhs; | |
| 1210 | // zig: *_ref = *_ref + rhs; | |
| 1211 | // zig: *_ref | |
| 1212 | // zig: } | |
| 1213 | ||
| 1214 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 1215 | ||
| 1216 | // const _ref = &lhs; | |
| 1217 | AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue); | |
| 1218 | if (lhs == nullptr) return nullptr; | |
| 1219 | AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs); | |
| 1220 | // TODO: avoid name collisions with generated variable names | |
| 1221 | Buf* tmp_var_name = buf_create_from_str("_ref"); | |
| 1222 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); | |
| 1223 | child_block->data.block.statements.append(tmp_var_decl); | |
| 1224 | ||
| 1225 | // *_ref = *_ref + rhs; | |
| 1226 | ||
| 1227 | AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue); | |
| 1228 | if (rhs == nullptr) return nullptr; | |
| 1229 | ||
| 1230 | AstNode *assign_statement = trans_create_node_bin_op(c, | |
| 1231 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1232 | trans_create_node_symbol(c, tmp_var_name)), | |
| 1233 | BinOpTypeAssign, | |
| 1234 | trans_create_node_bin_op(c, | |
| 1235 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1236 | trans_create_node_symbol(c, tmp_var_name)), | |
| 1237 | bin_op, | |
| 1238 | rhs)); | |
| 1239 | child_block->data.block.statements.append(assign_statement); | |
| 1240 | ||
| 1241 | // *_ref | |
| 1242 | child_block->data.block.statements.append( | |
| 1243 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1244 | trans_create_node_symbol(c, tmp_var_name))); | |
| 1245 | child_block->data.block.last_statement_is_result_expression = true; | |
| 1246 | ||
| 1247 | return child_block; | |
| 1248 | } | |
| 1249 | } | |
| 1250 | ||
| 1251 | ||
| 1252 | static AstNode *trans_compound_assign_operator(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt) { | |
| 1253 | switch (stmt->getOpcode()) { | |
| 1254 | case BO_MulAssign: | |
| 1255 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1256 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimesWrap, BinOpTypeMultWrap); | |
| 1257 | else | |
| 1258 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimes, BinOpTypeMult); | |
| 1259 | case BO_DivAssign: | |
| 1260 | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign"); | |
| 1261 | return nullptr; | |
| 1262 | case BO_RemAssign: | |
| 1263 | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign"); | |
| 1264 | return nullptr; | |
| 1265 | case BO_AddAssign: | |
| 1266 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1267 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlusWrap, BinOpTypeAddWrap); | |
| 1268 | else | |
| 1269 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlus, BinOpTypeAdd); | |
| 1270 | case BO_SubAssign: | |
| 1271 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1272 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinusWrap, BinOpTypeSubWrap); | |
| 1273 | else | |
| 1274 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinus, BinOpTypeSub); | |
| 1275 | case BO_ShlAssign: | |
| 1276 | return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftLeft, BinOpTypeBitShiftLeft); | |
| 1277 | case BO_ShrAssign: | |
| 1278 | return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftRight, BinOpTypeBitShiftRight); | |
| 1279 | case BO_AndAssign: | |
| 1280 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitAnd, BinOpTypeBinAnd); | |
| 1281 | case BO_XorAssign: | |
| 1282 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitXor, BinOpTypeBinXor); | |
| 1283 | case BO_OrAssign: | |
| 1284 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitOr, BinOpTypeBinOr); | |
| 1285 | case BO_PtrMemD: | |
| 1286 | case BO_PtrMemI: | |
| 1287 | case BO_Assign: | |
| 1288 | case BO_Mul: | |
| 1289 | case BO_Div: | |
| 1290 | case BO_Rem: | |
| 1291 | case BO_Add: | |
| 1292 | case BO_Sub: | |
| 1293 | case BO_Shl: | |
| 1294 | case BO_Shr: | |
| 1295 | case BO_LT: | |
| 1296 | case BO_GT: | |
| 1297 | case BO_LE: | |
| 1298 | case BO_GE: | |
| 1299 | case BO_EQ: | |
| 1300 | case BO_NE: | |
| 1301 | case BO_And: | |
| 1302 | case BO_Xor: | |
| 1303 | case BO_Or: | |
| 1304 | case BO_LAnd: | |
| 1305 | case BO_LOr: | |
| 1306 | case BO_Comma: | |
| 1307 | zig_unreachable(); | |
| 1308 | } | |
| 1309 | ||
| 1310 | zig_unreachable(); | |
| 1311 | } | |
| 1312 | ||
| 1313 | static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCastExpr *stmt) { | |
| 1314 | switch (stmt->getCastKind()) { | |
| 1315 | case CK_LValueToRValue: | |
| 1316 | return trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); | |
| 1317 | case CK_IntegralCast: | |
| 1318 | { | |
| 1319 | AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); | |
| 1320 | if (target_node == nullptr) | |
| 1321 | return nullptr; | |
| 1322 | return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), target_node); | |
| 1323 | } | |
| 1324 | case CK_FunctionToPointerDecay: | |
| 1325 | case CK_ArrayToPointerDecay: | |
| 1326 | { | |
| 1327 | AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); | |
| 1328 | if (target_node == nullptr) | |
| 1329 | return nullptr; | |
| 1330 | return target_node; | |
| 1331 | } | |
| 1332 | case CK_BitCast: | |
| 1333 | { | |
| 1334 | AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); | |
| 1335 | if (target_node == nullptr) | |
| 1336 | return nullptr; | |
| 1337 | ||
| 1338 | AstNode *dest_type_node = trans_qual_type(c, stmt->getType(), stmt->getLocStart()); | |
| 1339 | ||
| 1340 | AstNode *node = trans_create_node_builtin_fn_call_str(c, "ptrCast"); | |
| 1341 | node->data.fn_call_expr.params.append(dest_type_node); | |
| 1342 | node->data.fn_call_expr.params.append(target_node); | |
| 1343 | return node; | |
| 1344 | } | |
| 1345 | case CK_NullToPointer: | |
| 1346 | return trans_create_node(c, NodeTypeNullLiteral); | |
| 1347 | case CK_Dependent: | |
| 1348 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent"); | |
| 1349 | return nullptr; | |
| 1350 | case CK_LValueBitCast: | |
| 1351 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_LValueBitCast"); | |
| 1352 | return nullptr; | |
| 1353 | case CK_NoOp: | |
| 1354 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NoOp"); | |
| 1355 | return nullptr; | |
| 1356 | case CK_BaseToDerived: | |
| 1357 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BaseToDerived"); | |
| 1358 | return nullptr; | |
| 1359 | case CK_DerivedToBase: | |
| 1360 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_DerivedToBase"); | |
| 1361 | return nullptr; | |
| 1362 | case CK_UncheckedDerivedToBase: | |
| 1363 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_UncheckedDerivedToBase"); | |
| 1364 | return nullptr; | |
| 1365 | case CK_Dynamic: | |
| 1366 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dynamic"); | |
| 1367 | return nullptr; | |
| 1368 | case CK_ToUnion: | |
| 1369 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ToUnion"); | |
| 1370 | return nullptr; | |
| 1371 | case CK_NullToMemberPointer: | |
| 1372 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NullToMemberPointer"); | |
| 1373 | return nullptr; | |
| 1374 | case CK_BaseToDerivedMemberPointer: | |
| 1375 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BaseToDerivedMemberPointer"); | |
| 1376 | return nullptr; | |
| 1377 | case CK_DerivedToBaseMemberPointer: | |
| 1378 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_DerivedToBaseMemberPointer"); | |
| 1379 | return nullptr; | |
| 1380 | case CK_MemberPointerToBoolean: | |
| 1381 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_MemberPointerToBoolean"); | |
| 1382 | return nullptr; | |
| 1383 | case CK_ReinterpretMemberPointer: | |
| 1384 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ReinterpretMemberPointer"); | |
| 1385 | return nullptr; | |
| 1386 | case CK_UserDefinedConversion: | |
| 1387 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_UserDefinedConversion"); | |
| 1388 | return nullptr; | |
| 1389 | case CK_ConstructorConversion: | |
| 1390 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ConstructorConversion"); | |
| 1391 | return nullptr; | |
| 1392 | case CK_IntegralToPointer: | |
| 1393 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToPointer"); | |
| 1394 | return nullptr; | |
| 1395 | case CK_PointerToIntegral: | |
| 1396 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_PointerToIntegral"); | |
| 1397 | return nullptr; | |
| 1398 | case CK_PointerToBoolean: | |
| 1399 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_PointerToBoolean"); | |
| 1400 | return nullptr; | |
| 1401 | case CK_ToVoid: | |
| 1402 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ToVoid"); | |
| 1403 | return nullptr; | |
| 1404 | case CK_VectorSplat: | |
| 1405 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_VectorSplat"); | |
| 1406 | return nullptr; | |
| 1407 | case CK_IntegralToBoolean: | |
| 1408 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToBoolean"); | |
| 1409 | return nullptr; | |
| 1410 | case CK_IntegralToFloating: | |
| 1411 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToFloating"); | |
| 1412 | return nullptr; | |
| 1413 | case CK_FloatingToIntegral: | |
| 1414 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingToIntegral"); | |
| 1415 | return nullptr; | |
| 1416 | case CK_FloatingToBoolean: | |
| 1417 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingToBoolean"); | |
| 1418 | return nullptr; | |
| 1419 | case CK_BooleanToSignedIntegral: | |
| 1420 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BooleanToSignedIntegral"); | |
| 1421 | return nullptr; | |
| 1422 | case CK_FloatingCast: | |
| 1423 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingCast"); | |
| 1424 | return nullptr; | |
| 1425 | case CK_CPointerToObjCPointerCast: | |
| 1426 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_CPointerToObjCPointerCast"); | |
| 1427 | return nullptr; | |
| 1428 | case CK_BlockPointerToObjCPointerCast: | |
| 1429 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BlockPointerToObjCPointerCast"); | |
| 1430 | return nullptr; | |
| 1431 | case CK_AnyPointerToBlockPointerCast: | |
| 1432 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AnyPointerToBlockPointerCast"); | |
| 1433 | return nullptr; | |
| 1434 | case CK_ObjCObjectLValueCast: | |
| 1435 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ObjCObjectLValueCast"); | |
| 1436 | return nullptr; | |
| 1437 | case CK_FloatingRealToComplex: | |
| 1438 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingRealToComplex"); | |
| 1439 | return nullptr; | |
| 1440 | case CK_FloatingComplexToReal: | |
| 1441 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToReal"); | |
| 1442 | return nullptr; | |
| 1443 | case CK_FloatingComplexToBoolean: | |
| 1444 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToBoolean"); | |
| 1445 | return nullptr; | |
| 1446 | case CK_FloatingComplexCast: | |
| 1447 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexCast"); | |
| 1448 | return nullptr; | |
| 1449 | case CK_FloatingComplexToIntegralComplex: | |
| 1450 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToIntegralComplex"); | |
| 1451 | return nullptr; | |
| 1452 | case CK_IntegralRealToComplex: | |
| 1453 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralRealToComplex"); | |
| 1454 | return nullptr; | |
| 1455 | case CK_IntegralComplexToReal: | |
| 1456 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToReal"); | |
| 1457 | return nullptr; | |
| 1458 | case CK_IntegralComplexToBoolean: | |
| 1459 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToBoolean"); | |
| 1460 | return nullptr; | |
| 1461 | case CK_IntegralComplexCast: | |
| 1462 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexCast"); | |
| 1463 | return nullptr; | |
| 1464 | case CK_IntegralComplexToFloatingComplex: | |
| 1465 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToFloatingComplex"); | |
| 1466 | return nullptr; | |
| 1467 | case CK_ARCProduceObject: | |
| 1468 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCProduceObject"); | |
| 1469 | return nullptr; | |
| 1470 | case CK_ARCConsumeObject: | |
| 1471 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCConsumeObject"); | |
| 1472 | return nullptr; | |
| 1473 | case CK_ARCReclaimReturnedObject: | |
| 1474 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCReclaimReturnedObject"); | |
| 1475 | return nullptr; | |
| 1476 | case CK_ARCExtendBlockObject: | |
| 1477 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCExtendBlockObject"); | |
| 1478 | return nullptr; | |
| 1479 | case CK_AtomicToNonAtomic: | |
| 1480 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AtomicToNonAtomic"); | |
| 1481 | return nullptr; | |
| 1482 | case CK_NonAtomicToAtomic: | |
| 1483 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NonAtomicToAtomic"); | |
| 1484 | return nullptr; | |
| 1485 | case CK_CopyAndAutoreleaseBlockObject: | |
| 1486 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_CopyAndAutoreleaseBlockObject"); | |
| 1487 | return nullptr; | |
| 1488 | case CK_BuiltinFnToFnPtr: | |
| 1489 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BuiltinFnToFnPtr"); | |
| 1490 | return nullptr; | |
| 1491 | case CK_ZeroToOCLEvent: | |
| 1492 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ZeroToOCLEvent"); | |
| 1493 | return nullptr; | |
| 1494 | case CK_ZeroToOCLQueue: | |
| 1495 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ZeroToOCLQueue"); | |
| 1496 | return nullptr; | |
| 1497 | case CK_AddressSpaceConversion: | |
| 1498 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AddressSpaceConversion"); | |
| 1499 | return nullptr; | |
| 1500 | case CK_IntToOCLSampler: | |
| 1501 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntToOCLSampler"); | |
| 1502 | return nullptr; | |
| 1503 | } | |
| 1504 | zig_unreachable(); | |
| 1505 | } | |
| 1506 | ||
| 1507 | static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue lrval) { | |
| 1508 | ValueDecl *value_decl = stmt->getDecl(); | |
| 1509 | Buf *symbol_name = buf_create_from_str(decl_name(value_decl)); | |
| 1510 | if (lrval == TransLValue) { | |
| 1511 | c->ptr_params.put(symbol_name, true); | |
| 1512 | } | |
| 1513 | return trans_create_node_symbol(c, symbol_name); | |
| 1514 | } | |
| 1515 | ||
| 1516 | static AstNode *trans_create_post_crement(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt, BinOpType assign_op) { | |
| 1517 | Expr *op_expr = stmt->getSubExpr(); | |
| 1518 | ||
| 1519 | if (!result_used) { | |
| 1520 | // common case | |
| 1521 | // c: expr++ | |
| 1522 | // zig: expr += 1 | |
| 1523 | return trans_create_node_bin_op(c, | |
| 1524 | trans_expr(c, true, block, op_expr, TransLValue), | |
| 1525 | assign_op, | |
| 1526 | trans_create_node_unsigned(c, 1)); | |
| 1527 | } else { | |
| 1528 | // worst case | |
| 1529 | // c: expr++ | |
| 1530 | // zig: { | |
| 1531 | // zig: const _ref = &expr; | |
| 1532 | // zig: const _tmp = *_ref; | |
| 1533 | // zig: *_ref += 1; | |
| 1534 | // zig: _tmp | |
| 1535 | // zig: } | |
| 1536 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 1537 | ||
| 1538 | // const _ref = &expr; | |
| 1539 | AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue); | |
| 1540 | if (expr == nullptr) return nullptr; | |
| 1541 | AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr); | |
| 1542 | // TODO: avoid name collisions with generated variable names | |
| 1543 | Buf* ref_var_name = buf_create_from_str("_ref"); | |
| 1544 | AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr); | |
| 1545 | child_block->data.block.statements.append(ref_var_decl); | |
| 1546 | ||
| 1547 | // const _tmp = *_ref; | |
| 1548 | Buf* tmp_var_name = buf_create_from_str("_tmp"); | |
| 1549 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, | |
| 1550 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1551 | trans_create_node_symbol(c, ref_var_name))); | |
| 1552 | child_block->data.block.statements.append(tmp_var_decl); | |
| 1553 | ||
| 1554 | // *_ref += 1; | |
| 1555 | AstNode *assign_statement = trans_create_node_bin_op(c, | |
| 1556 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1557 | trans_create_node_symbol(c, ref_var_name)), | |
| 1558 | assign_op, | |
| 1559 | trans_create_node_unsigned(c, 1)); | |
| 1560 | child_block->data.block.statements.append(assign_statement); | |
| 1561 | ||
| 1562 | // _tmp | |
| 1563 | child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name)); | |
| 1564 | child_block->data.block.last_statement_is_result_expression = true; | |
| 1565 | ||
| 1566 | return child_block; | |
| 1567 | } | |
| 1568 | } | |
| 1569 | ||
| 1570 | static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) { | |
| 1571 | switch (stmt->getOpcode()) { | |
| 1572 | case UO_PostInc: | |
| 1573 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1574 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlusWrap); | |
| 1575 | else | |
| 1576 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlus); | |
| 1577 | case UO_PostDec: | |
| 1578 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1579 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinusWrap); | |
| 1580 | else | |
| 1581 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus); | |
| 1582 | case UO_PreInc: | |
| 1583 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreInc"); | |
| 1584 | return nullptr; | |
| 1585 | case UO_PreDec: | |
| 1586 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreDec"); | |
| 1587 | return nullptr; | |
| 1588 | case UO_AddrOf: | |
| 1589 | { | |
| 1590 | AstNode *value_node = trans_expr(c, result_used, block, stmt->getSubExpr(), TransLValue); | |
| 1591 | if (value_node == nullptr) | |
| 1592 | return value_node; | |
| 1593 | return trans_create_node_addr_of(c, false, false, value_node); | |
| 1594 | } | |
| 1595 | case UO_Deref: | |
| 1596 | { | |
| 1597 | AstNode *value_node = trans_expr(c, result_used, block, stmt->getSubExpr(), TransRValue); | |
| 1598 | if (value_node == nullptr) | |
| 1599 | return nullptr; | |
| 1600 | bool is_fn_ptr = qual_type_is_fn_ptr(c, stmt->getSubExpr()->getType()); | |
| 1601 | if (is_fn_ptr) | |
| 1602 | return value_node; | |
| 1603 | AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node); | |
| 1604 | return trans_create_node_prefix_op(c, PrefixOpDereference, unwrapped); | |
| 1605 | } | |
| 1606 | case UO_Plus: | |
| 1607 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus"); | |
| 1608 | return nullptr; | |
| 1609 | case UO_Minus: | |
| 1610 | { | |
| 1611 | Expr *op_expr = stmt->getSubExpr(); | |
| 1612 | if (!qual_type_has_wrapping_overflow(c, op_expr->getType())) { | |
| 1613 | AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); | |
| 1614 | node->data.prefix_op_expr.prefix_op = PrefixOpNegation; | |
| 1615 | ||
| 1616 | node->data.prefix_op_expr.primary_expr = trans_expr(c, true, block, op_expr, TransRValue); | |
| 1617 | if (node->data.prefix_op_expr.primary_expr == nullptr) | |
| 1618 | return nullptr; | |
| 1619 | ||
| 1620 | return node; | |
| 1621 | } else if (c_is_unsigned_integer(c, op_expr->getType())) { | |
| 1622 | // we gotta emit 0 -% x | |
| 1623 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 1624 | node->data.bin_op_expr.op1 = trans_create_node_unsigned(c, 0); | |
| 1625 | ||
| 1626 | node->data.bin_op_expr.op2 = trans_expr(c, true, block, op_expr, TransRValue); | |
| 1627 | if (node->data.bin_op_expr.op2 == nullptr) | |
| 1628 | return nullptr; | |
| 1629 | ||
| 1630 | node->data.bin_op_expr.bin_op = BinOpTypeSubWrap; | |
| 1631 | return node; | |
| 1632 | } else { | |
| 1633 | emit_warning(c, stmt->getLocStart(), "C negation with non float non integer"); | |
| 1634 | return nullptr; | |
| 1635 | } | |
| 1636 | } | |
| 1637 | case UO_Not: | |
| 1638 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Not"); | |
| 1639 | return nullptr; | |
| 1640 | case UO_LNot: | |
| 1641 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_LNot"); | |
| 1642 | return nullptr; | |
| 1643 | case UO_Real: | |
| 1644 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Real"); | |
| 1645 | return nullptr; | |
| 1646 | case UO_Imag: | |
| 1647 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Imag"); | |
| 1648 | return nullptr; | |
| 1649 | case UO_Extension: | |
| 1650 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Extension"); | |
| 1651 | return nullptr; | |
| 1652 | case UO_Coawait: | |
| 1653 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Coawait"); | |
| 1654 | return nullptr; | |
| 1655 | } | |
| 1656 | zig_unreachable(); | |
| 1657 | } | |
| 1658 | ||
| 1659 | static AstNode *trans_local_declaration(Context *c, AstNode *block, DeclStmt *stmt) { | |
| 1660 | for (auto iter = stmt->decl_begin(); iter != stmt->decl_end(); iter++) { | |
| 1661 | Decl *decl = *iter; | |
| 1662 | switch (decl->getKind()) { | |
| 1663 | case Decl::Var: { | |
| 1664 | VarDecl *var_decl = (VarDecl *)decl; | |
| 1665 | QualType qual_type = var_decl->getTypeSourceInfo()->getType(); | |
| 1666 | AstNode *init_node = nullptr; | |
| 1667 | if (var_decl->hasInit()) { | |
| 1668 | init_node = trans_expr(c, true, block, var_decl->getInit(), TransRValue); | |
| 1669 | if (init_node == nullptr) | |
| 1670 | return nullptr; | |
| 1671 | ||
| 1672 | } | |
| 1673 | AstNode *type_node = trans_qual_type(c, qual_type, stmt->getLocStart()); | |
| 1674 | if (type_node == nullptr) | |
| 1675 | return nullptr; | |
| 1676 | ||
| 1677 | Buf *symbol_name = buf_create_from_str(decl_name(var_decl)); | |
| 1678 | ||
| 1679 | AstNode *node = trans_create_node_var_decl_local(c, qual_type.isConstQualified(), | |
| 1680 | symbol_name, type_node, init_node); | |
| 1681 | block->data.block.statements.append(node); | |
| 1682 | continue; | |
| 1683 | } | |
| 1684 | case Decl::AccessSpec: | |
| 1685 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind AccessSpec"); | |
| 1686 | return nullptr; | |
| 1687 | case Decl::Block: | |
| 1688 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Block"); | |
| 1689 | return nullptr; | |
| 1690 | case Decl::Captured: | |
| 1691 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Captured"); | |
| 1692 | return nullptr; | |
| 1693 | case Decl::ClassScopeFunctionSpecialization: | |
| 1694 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassScopeFunctionSpecialization"); | |
| 1695 | return nullptr; | |
| 1696 | case Decl::Empty: | |
| 1697 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Empty"); | |
| 1698 | return nullptr; | |
| 1699 | case Decl::Export: | |
| 1700 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Export"); | |
| 1701 | return nullptr; | |
| 1702 | case Decl::ExternCContext: | |
| 1703 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ExternCContext"); | |
| 1704 | return nullptr; | |
| 1705 | case Decl::FileScopeAsm: | |
| 1706 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FileScopeAsm"); | |
| 1707 | return nullptr; | |
| 1708 | case Decl::Friend: | |
| 1709 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Friend"); | |
| 1710 | return nullptr; | |
| 1711 | case Decl::FriendTemplate: | |
| 1712 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FriendTemplate"); | |
| 1713 | return nullptr; | |
| 1714 | case Decl::Import: | |
| 1715 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Import"); | |
| 1716 | return nullptr; | |
| 1717 | case Decl::LinkageSpec: | |
| 1718 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind LinkageSpec"); | |
| 1719 | return nullptr; | |
| 1720 | case Decl::Label: | |
| 1721 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Label"); | |
| 1722 | return nullptr; | |
| 1723 | case Decl::Namespace: | |
| 1724 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Namespace"); | |
| 1725 | return nullptr; | |
| 1726 | case Decl::NamespaceAlias: | |
| 1727 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind NamespaceAlias"); | |
| 1728 | return nullptr; | |
| 1729 | case Decl::ObjCCompatibleAlias: | |
| 1730 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCompatibleAlias"); | |
| 1731 | return nullptr; | |
| 1732 | case Decl::ObjCCategory: | |
| 1733 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCategory"); | |
| 1734 | return nullptr; | |
| 1735 | case Decl::ObjCCategoryImpl: | |
| 1736 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCategoryImpl"); | |
| 1737 | return nullptr; | |
| 1738 | case Decl::ObjCImplementation: | |
| 1739 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCImplementation"); | |
| 1740 | return nullptr; | |
| 1741 | case Decl::ObjCInterface: | |
| 1742 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCInterface"); | |
| 1743 | return nullptr; | |
| 1744 | case Decl::ObjCProtocol: | |
| 1745 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCProtocol"); | |
| 1746 | return nullptr; | |
| 1747 | case Decl::ObjCMethod: | |
| 1748 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCMethod"); | |
| 1749 | return nullptr; | |
| 1750 | case Decl::ObjCProperty: | |
| 1751 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCProperty"); | |
| 1752 | return nullptr; | |
| 1753 | case Decl::BuiltinTemplate: | |
| 1754 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind BuiltinTemplate"); | |
| 1755 | return nullptr; | |
| 1756 | case Decl::ClassTemplate: | |
| 1757 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplate"); | |
| 1758 | return nullptr; | |
| 1759 | case Decl::FunctionTemplate: | |
| 1760 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FunctionTemplate"); | |
| 1761 | return nullptr; | |
| 1762 | case Decl::TypeAliasTemplate: | |
| 1763 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TypeAliasTemplate"); | |
| 1764 | return nullptr; | |
| 1765 | case Decl::VarTemplate: | |
| 1766 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplate"); | |
| 1767 | return nullptr; | |
| 1768 | case Decl::TemplateTemplateParm: | |
| 1769 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TemplateTemplateParm"); | |
| 1770 | return nullptr; | |
| 1771 | case Decl::Enum: | |
| 1772 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Enum"); | |
| 1773 | return nullptr; | |
| 1774 | case Decl::Record: | |
| 1775 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Record"); | |
| 1776 | return nullptr; | |
| 1777 | case Decl::CXXRecord: | |
| 1778 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXRecord"); | |
| 1779 | return nullptr; | |
| 1780 | case Decl::ClassTemplateSpecialization: | |
| 1781 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplateSpecialization"); | |
| 1782 | return nullptr; | |
| 1783 | case Decl::ClassTemplatePartialSpecialization: | |
| 1784 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplatePartialSpecialization"); | |
| 1785 | return nullptr; | |
| 1786 | case Decl::TemplateTypeParm: | |
| 1787 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TemplateTypeParm"); | |
| 1788 | return nullptr; | |
| 1789 | case Decl::ObjCTypeParam: | |
| 1790 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCTypeParam"); | |
| 1791 | return nullptr; | |
| 1792 | case Decl::TypeAlias: | |
| 1793 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TypeAlias"); | |
| 1794 | return nullptr; | |
| 1795 | case Decl::Typedef: | |
| 1796 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Typedef"); | |
| 1797 | return nullptr; | |
| 1798 | case Decl::UnresolvedUsingTypename: | |
| 1799 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UnresolvedUsingTypename"); | |
| 1800 | return nullptr; | |
| 1801 | case Decl::Using: | |
| 1802 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Using"); | |
| 1803 | return nullptr; | |
| 1804 | case Decl::UsingDirective: | |
| 1805 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingDirective"); | |
| 1806 | return nullptr; | |
| 1807 | case Decl::UsingPack: | |
| 1808 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingPack"); | |
| 1809 | return nullptr; | |
| 1810 | case Decl::UsingShadow: | |
| 1811 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingShadow"); | |
| 1812 | return nullptr; | |
| 1813 | case Decl::ConstructorUsingShadow: | |
| 1814 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ConstructorUsingShadow"); | |
| 1815 | return nullptr; | |
| 1816 | case Decl::Binding: | |
| 1817 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Binding"); | |
| 1818 | return nullptr; | |
| 1819 | case Decl::Field: | |
| 1820 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Field"); | |
| 1821 | return nullptr; | |
| 1822 | case Decl::ObjCAtDefsField: | |
| 1823 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCAtDefsField"); | |
| 1824 | return nullptr; | |
| 1825 | case Decl::ObjCIvar: | |
| 1826 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCIvar"); | |
| 1827 | return nullptr; | |
| 1828 | case Decl::Function: | |
| 1829 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Function"); | |
| 1830 | return nullptr; | |
| 1831 | case Decl::CXXDeductionGuide: | |
| 1832 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXDeductionGuide"); | |
| 1833 | return nullptr; | |
| 1834 | case Decl::CXXMethod: | |
| 1835 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXMethod"); | |
| 1836 | return nullptr; | |
| 1837 | case Decl::CXXConstructor: | |
| 1838 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXConstructor"); | |
| 1839 | return nullptr; | |
| 1840 | case Decl::CXXConversion: | |
| 1841 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXConversion"); | |
| 1842 | return nullptr; | |
| 1843 | case Decl::CXXDestructor: | |
| 1844 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXDestructor"); | |
| 1845 | return nullptr; | |
| 1846 | case Decl::MSProperty: | |
| 1847 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind MSProperty"); | |
| 1848 | return nullptr; | |
| 1849 | case Decl::NonTypeTemplateParm: | |
| 1850 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind NonTypeTemplateParm"); | |
| 1851 | return nullptr; | |
| 1852 | case Decl::Decomposition: | |
| 1853 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Decomposition"); | |
| 1854 | return nullptr; | |
| 1855 | case Decl::ImplicitParam: | |
| 1856 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ImplicitParam"); | |
| 1857 | return nullptr; | |
| 1858 | case Decl::OMPCapturedExpr: | |
| 1859 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPCapturedExpr"); | |
| 1860 | return nullptr; | |
| 1861 | case Decl::ParmVar: | |
| 1862 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ParmVar"); | |
| 1863 | return nullptr; | |
| 1864 | case Decl::VarTemplateSpecialization: | |
| 1865 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplateSpecialization"); | |
| 1866 | return nullptr; | |
| 1867 | case Decl::VarTemplatePartialSpecialization: | |
| 1868 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplatePartialSpecialization"); | |
| 1869 | return nullptr; | |
| 1870 | case Decl::EnumConstant: | |
| 1871 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind EnumConstant"); | |
| 1872 | return nullptr; | |
| 1873 | case Decl::IndirectField: | |
| 1874 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind IndirectField"); | |
| 1875 | return nullptr; | |
| 1876 | case Decl::OMPDeclareReduction: | |
| 1877 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPDeclareReduction"); | |
| 1878 | return nullptr; | |
| 1879 | case Decl::UnresolvedUsingValue: | |
| 1880 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UnresolvedUsingValue"); | |
| 1881 | return nullptr; | |
| 1882 | case Decl::OMPThreadPrivate: | |
| 1883 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPThreadPrivate"); | |
| 1884 | return nullptr; | |
| 1885 | case Decl::ObjCPropertyImpl: | |
| 1886 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCPropertyImpl"); | |
| 1887 | return nullptr; | |
| 1888 | case Decl::PragmaComment: | |
| 1889 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind PragmaComment"); | |
| 1890 | return nullptr; | |
| 1891 | case Decl::PragmaDetectMismatch: | |
| 1892 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind PragmaDetectMismatch"); | |
| 1893 | return nullptr; | |
| 1894 | case Decl::StaticAssert: | |
| 1895 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind StaticAssert"); | |
| 1896 | return nullptr; | |
| 1897 | case Decl::TranslationUnit: | |
| 1898 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TranslationUnit"); | |
| 1899 | return nullptr; | |
| 1900 | } | |
| 1901 | zig_unreachable(); | |
| 1902 | } | |
| 1903 | ||
| 1904 | // declarations were already added | |
| 1905 | return skip_add_to_block_node; | |
| 1906 | } | |
| 1907 | ||
| 1908 | static AstNode *trans_while_loop(Context *c, AstNode *block, WhileStmt *stmt) { | |
| 1909 | AstNode *while_node = trans_create_node(c, NodeTypeWhileExpr); | |
| 1910 | ||
| 1911 | while_node->data.while_expr.condition = trans_expr(c, true, block, stmt->getCond(), TransRValue); | |
| 1912 | if (while_node->data.while_expr.condition == nullptr) | |
| 1913 | return nullptr; | |
| 1914 | ||
| 1915 | while_node->data.while_expr.body = trans_stmt(c, false, block, stmt->getBody(), TransRValue); | |
| 1916 | if (while_node->data.while_expr.body == nullptr) | |
| 1917 | return nullptr; | |
| 1918 | ||
| 1919 | return while_node; | |
| 1920 | } | |
| 1921 | ||
| 1922 | static AstNode *trans_if_statement(Context *c, AstNode *block, IfStmt *stmt) { | |
| 1923 | // if (c) t | |
| 1924 | // if (c) t else e | |
| 1925 | AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr); | |
| 1926 | ||
| 1927 | // TODO: condition != 0 | |
| 1928 | AstNode *condition_node = trans_expr(c, true, block, stmt->getCond(), TransRValue); | |
| 1929 | if (condition_node == nullptr) | |
| 1930 | return nullptr; | |
| 1931 | if_node->data.if_bool_expr.condition = condition_node; | |
| 1932 | ||
| 1933 | if_node->data.if_bool_expr.then_block = trans_stmt(c, false, block, stmt->getThen(), TransRValue); | |
| 1934 | if (if_node->data.if_bool_expr.then_block == nullptr) | |
| 1935 | return nullptr; | |
| 1936 | ||
| 1937 | if (stmt->getElse() != nullptr) { | |
| 1938 | if_node->data.if_bool_expr.else_node = trans_stmt(c, false, block, stmt->getElse(), TransRValue); | |
| 1939 | if (if_node->data.if_bool_expr.else_node == nullptr) | |
| 1940 | return nullptr; | |
| 1941 | } | |
| 1942 | ||
| 1943 | return if_node; | |
| 1944 | } | |
| 1945 | ||
| 1946 | static AstNode *trans_call_expr(Context *c, bool result_used, AstNode *block, CallExpr *stmt) { | |
| 1947 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 1948 | ||
| 1949 | AstNode *callee_raw_node = trans_expr(c, true, block, stmt->getCallee(), TransRValue); | |
| 1950 | if (callee_raw_node == nullptr) | |
| 1951 | return nullptr; | |
| 1952 | ||
| 1953 | AstNode *callee_node; | |
| 1954 | if (qual_type_is_fn_ptr(c, stmt->getCallee()->getType())) { | |
| 1955 | callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, callee_raw_node); | |
| 1956 | } else { | |
| 1957 | callee_node = callee_raw_node; | |
| 1958 | } | |
| 1959 | ||
| 1960 | node->data.fn_call_expr.fn_ref_expr = callee_node; | |
| 1961 | ||
| 1962 | unsigned num_args = stmt->getNumArgs(); | |
| 1963 | Expr **args = stmt->getArgs(); | |
| 1964 | for (unsigned i = 0; i < num_args; i += 1) { | |
| 1965 | AstNode *arg_node = trans_expr(c, true, block, args[i], TransRValue); | |
| 1966 | if (arg_node == nullptr) | |
| 1967 | return nullptr; | |
| 1968 | ||
| 1969 | node->data.fn_call_expr.params.append(arg_node); | |
| 1970 | } | |
| 1971 | ||
| 1972 | return node; | |
| 1973 | } | |
| 1974 | ||
| 1975 | static AstNode *trans_member_expr(Context *c, AstNode *block, MemberExpr *stmt) { | |
| 1976 | AstNode *container_node = trans_expr(c, true, block, stmt->getBase(), TransRValue); | |
| 1977 | if (container_node == nullptr) | |
| 1978 | return nullptr; | |
| 1979 | ||
| 1980 | if (stmt->isArrow()) { | |
| 1981 | container_node = trans_create_node_unwrap_null(c, container_node); | |
| 1982 | } | |
| 1983 | ||
| 1984 | const char *name = decl_name(stmt->getMemberDecl()); | |
| 1985 | ||
| 1986 | AstNode *node = trans_create_node_field_access_str(c, container_node, name); | |
| 1987 | return node; | |
| 1988 | } | |
| 1989 | ||
| 1990 | static AstNode *trans_array_subscript_expr(Context *c, AstNode *block, ArraySubscriptExpr *stmt) { | |
| 1991 | AstNode *container_node = trans_expr(c, true, block, stmt->getBase(), TransRValue); | |
| 1992 | if (container_node == nullptr) | |
| 1993 | return nullptr; | |
| 1994 | ||
| 1995 | AstNode *idx_node = trans_expr(c, true, block, stmt->getIdx(), TransRValue); | |
| 1996 | if (idx_node == nullptr) | |
| 1997 | return nullptr; | |
| 1998 | ||
| 1999 | ||
| 2000 | AstNode *node = trans_create_node(c, NodeTypeArrayAccessExpr); | |
| 2001 | node->data.array_access_expr.array_ref_expr = container_node; | |
| 2002 | node->data.array_access_expr.subscript = idx_node; | |
| 2003 | return node; | |
| 2004 | } | |
| 2005 | ||
| 2006 | static AstNode *trans_c_style_cast_expr(Context *c, bool result_used, AstNode *block, | |
| 2007 | CStyleCastExpr *stmt, TransLRValue lrvalue) | |
| 2008 | { | |
| 2009 | AstNode *sub_expr_node = trans_expr(c, result_used, block, stmt->getSubExpr(), lrvalue); | |
| 2010 | if (sub_expr_node == nullptr) | |
| 2011 | return nullptr; | |
| 2012 | ||
| 2013 | return trans_c_cast(c, stmt->getLocStart(), stmt->getType(), sub_expr_node); | |
| 2014 | } | |
| 2015 | ||
| 2016 | static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, AstNode *block, UnaryExprOrTypeTraitExpr *stmt) { | |
| 2017 | AstNode *type_node = trans_qual_type(c, stmt->getTypeOfArgument(), stmt->getLocStart()); | |
| 2018 | if (type_node == nullptr) | |
| 2019 | return nullptr; | |
| 2020 | ||
| 2021 | AstNode *node = trans_create_node_builtin_fn_call_str(c, "sizeOf"); | |
| 2022 | node->data.fn_call_expr.params.append(type_node); | |
| 2023 | return node; | |
| 2024 | } | |
| 2025 | ||
| 2026 | static AstNode *trans_do_loop(Context *c, AstNode *block, DoStmt *stmt) { | |
| 2027 | stmt->getBody(); | |
| 2028 | stmt->getCond(); | |
| 2029 | ||
| 2030 | AstNode *while_node = trans_create_node(c, NodeTypeWhileExpr); | |
| 2031 | ||
| 2032 | AstNode *true_node = trans_create_node(c, NodeTypeBoolLiteral); | |
| 2033 | true_node->data.bool_literal.value = true; | |
| 2034 | while_node->data.while_expr.condition = true_node; | |
| 2035 | ||
| 2036 | AstNode *body_node; | |
| 2037 | if (stmt->getBody()->getStmtClass() == Stmt::CompoundStmtClass) { | |
| 2038 | // there's already a block in C, so we'll append our condition to it. | |
| 2039 | // c: do { | |
| 2040 | // c: a; | |
| 2041 | // c: b; | |
| 2042 | // c: } while(c); | |
| 2043 | // zig: while (true) { | |
| 2044 | // zig: a; | |
| 2045 | // zig: b; | |
| 2046 | // zig: if (!cond) break; | |
| 2047 | // zig: } | |
| 2048 | body_node = trans_stmt(c, false, block, stmt->getBody(), TransRValue); | |
| 2049 | if (body_node == nullptr) return nullptr; | |
| 2050 | assert(body_node->type == NodeTypeBlock); | |
| 2051 | } else { | |
| 2052 | // the C statement is without a block, so we need to create a block to contain it. | |
| 2053 | // c: do | |
| 2054 | // c: a; | |
| 2055 | // c: while(c); | |
| 2056 | // zig: while (true) { | |
| 2057 | // zig: a; | |
| 2058 | // zig: if (!cond) break; | |
| 2059 | // zig: } | |
| 2060 | body_node = trans_create_node(c, NodeTypeBlock); | |
| 2061 | AstNode *child_statement = trans_stmt(c, false, body_node, stmt->getBody(), TransRValue); | |
| 2062 | if (child_statement == nullptr) return nullptr; | |
| 2063 | body_node->data.block.statements.append(child_statement); | |
| 2064 | } | |
| 2065 | ||
| 2066 | // if (!cond) break; | |
| 2067 | AstNode *condition_node = trans_expr(c, true, body_node, stmt->getCond(), TransRValue); | |
| 2068 | if (condition_node == nullptr) return nullptr; | |
| 2069 | AstNode *terminator_node = trans_create_node(c, NodeTypeIfBoolExpr); | |
| 2070 | terminator_node->data.if_bool_expr.condition = trans_create_node_prefix_op(c, PrefixOpBoolNot, condition_node); | |
| 2071 | terminator_node->data.if_bool_expr.then_block = trans_create_node(c, NodeTypeBreak); | |
| 2072 | body_node->data.block.statements.append(terminator_node); | |
| 2073 | ||
| 2074 | while_node->data.while_expr.body = body_node; | |
| 2075 | ||
| 2076 | return while_node; | |
| 2077 | } | |
| 2078 | ||
| 2079 | static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) { | |
| 2080 | Stmt::StmtClass sc = stmt->getStmtClass(); | |
| 2081 | switch (sc) { | |
| 2082 | case Stmt::ReturnStmtClass: | |
| 2083 | return trans_return_stmt(c, block, (ReturnStmt *)stmt); | |
| 2084 | case Stmt::CompoundStmtClass: | |
| 2085 | return trans_compound_stmt(c, block, (CompoundStmt *)stmt); | |
| 2086 | case Stmt::IntegerLiteralClass: | |
| 2087 | return trans_integer_literal(c, (IntegerLiteral *)stmt); | |
| 2088 | case Stmt::ConditionalOperatorClass: | |
| 2089 | return trans_conditional_operator(c, result_used, block, (ConditionalOperator *)stmt); | |
| 2090 | case Stmt::BinaryOperatorClass: | |
| 2091 | return trans_binary_operator(c, result_used, block, (BinaryOperator *)stmt); | |
| 2092 | case Stmt::CompoundAssignOperatorClass: | |
| 2093 | return trans_compound_assign_operator(c, result_used, block, (CompoundAssignOperator *)stmt); | |
| 2094 | case Stmt::ImplicitCastExprClass: | |
| 2095 | return trans_implicit_cast_expr(c, block, (ImplicitCastExpr *)stmt); | |
| 2096 | case Stmt::DeclRefExprClass: | |
| 2097 | return trans_decl_ref_expr(c, (DeclRefExpr *)stmt, lrvalue); | |
| 2098 | case Stmt::UnaryOperatorClass: | |
| 2099 | return trans_unary_operator(c, result_used, block, (UnaryOperator *)stmt); | |
| 2100 | case Stmt::DeclStmtClass: | |
| 2101 | return trans_local_declaration(c, block, (DeclStmt *)stmt); | |
| 2102 | case Stmt::WhileStmtClass: | |
| 2103 | return trans_while_loop(c, block, (WhileStmt *)stmt); | |
| 2104 | case Stmt::IfStmtClass: | |
| 2105 | return trans_if_statement(c, block, (IfStmt *)stmt); | |
| 2106 | case Stmt::CallExprClass: | |
| 2107 | return trans_call_expr(c, result_used, block, (CallExpr *)stmt); | |
| 2108 | case Stmt::NullStmtClass: | |
| 2109 | return skip_add_to_block_node; | |
| 2110 | case Stmt::MemberExprClass: | |
| 2111 | return trans_member_expr(c, block, (MemberExpr *)stmt); | |
| 2112 | case Stmt::ArraySubscriptExprClass: | |
| 2113 | return trans_array_subscript_expr(c, block, (ArraySubscriptExpr *)stmt); | |
| 2114 | case Stmt::CStyleCastExprClass: | |
| 2115 | return trans_c_style_cast_expr(c, result_used, block, (CStyleCastExpr *)stmt, lrvalue); | |
| 2116 | case Stmt::UnaryExprOrTypeTraitExprClass: | |
| 2117 | return trans_unary_expr_or_type_trait_expr(c, block, (UnaryExprOrTypeTraitExpr *)stmt); | |
| 2118 | case Stmt::DoStmtClass: | |
| 2119 | return trans_do_loop(c, block, (DoStmt *)stmt); | |
| 2120 | case Stmt::CaseStmtClass: | |
| 2121 | emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass"); | |
| 2122 | return nullptr; | |
| 2123 | case Stmt::DefaultStmtClass: | |
| 2124 | emit_warning(c, stmt->getLocStart(), "TODO handle C DefaultStmtClass"); | |
| 2125 | return nullptr; | |
| 2126 | case Stmt::SwitchStmtClass: | |
| 2127 | emit_warning(c, stmt->getLocStart(), "TODO handle C SwitchStmtClass"); | |
| 2128 | return nullptr; | |
| 2129 | case Stmt::NoStmtClass: | |
| 2130 | emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass"); | |
| 2131 | return nullptr; | |
| 2132 | case Stmt::GCCAsmStmtClass: | |
| 2133 | emit_warning(c, stmt->getLocStart(), "TODO handle C GCCAsmStmtClass"); | |
| 2134 | return nullptr; | |
| 2135 | case Stmt::MSAsmStmtClass: | |
| 2136 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSAsmStmtClass"); | |
| 2137 | return nullptr; | |
| 2138 | case Stmt::AttributedStmtClass: | |
| 2139 | emit_warning(c, stmt->getLocStart(), "TODO handle C AttributedStmtClass"); | |
| 2140 | return nullptr; | |
| 2141 | case Stmt::BreakStmtClass: | |
| 2142 | emit_warning(c, stmt->getLocStart(), "TODO handle C BreakStmtClass"); | |
| 2143 | return nullptr; | |
| 2144 | case Stmt::CXXCatchStmtClass: | |
| 2145 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXCatchStmtClass"); | |
| 2146 | return nullptr; | |
| 2147 | case Stmt::CXXForRangeStmtClass: | |
| 2148 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXForRangeStmtClass"); | |
| 2149 | return nullptr; | |
| 2150 | case Stmt::CXXTryStmtClass: | |
| 2151 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTryStmtClass"); | |
| 2152 | return nullptr; | |
| 2153 | case Stmt::CapturedStmtClass: | |
| 2154 | emit_warning(c, stmt->getLocStart(), "TODO handle C CapturedStmtClass"); | |
| 2155 | return nullptr; | |
| 2156 | case Stmt::ContinueStmtClass: | |
| 2157 | emit_warning(c, stmt->getLocStart(), "TODO handle C ContinueStmtClass"); | |
| 2158 | return nullptr; | |
| 2159 | case Stmt::CoreturnStmtClass: | |
| 2160 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoreturnStmtClass"); | |
| 2161 | return nullptr; | |
| 2162 | case Stmt::CoroutineBodyStmtClass: | |
| 2163 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoroutineBodyStmtClass"); | |
| 2164 | return nullptr; | |
| 2165 | case Stmt::BinaryConditionalOperatorClass: | |
| 2166 | emit_warning(c, stmt->getLocStart(), "TODO handle C BinaryConditionalOperatorClass"); | |
| 2167 | return nullptr; | |
| 2168 | case Stmt::AddrLabelExprClass: | |
| 2169 | emit_warning(c, stmt->getLocStart(), "TODO handle C AddrLabelExprClass"); | |
| 2170 | return nullptr; | |
| 2171 | case Stmt::ArrayInitIndexExprClass: | |
| 2172 | emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitIndexExprClass"); | |
| 2173 | return nullptr; | |
| 2174 | case Stmt::ArrayInitLoopExprClass: | |
| 2175 | emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitLoopExprClass"); | |
| 2176 | return nullptr; | |
| 2177 | case Stmt::ArrayTypeTraitExprClass: | |
| 2178 | emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayTypeTraitExprClass"); | |
| 2179 | return nullptr; | |
| 2180 | case Stmt::AsTypeExprClass: | |
| 2181 | emit_warning(c, stmt->getLocStart(), "TODO handle C AsTypeExprClass"); | |
| 2182 | return nullptr; | |
| 2183 | case Stmt::AtomicExprClass: | |
| 2184 | emit_warning(c, stmt->getLocStart(), "TODO handle C AtomicExprClass"); | |
| 2185 | return nullptr; | |
| 2186 | case Stmt::BlockExprClass: | |
| 2187 | emit_warning(c, stmt->getLocStart(), "TODO handle C BlockExprClass"); | |
| 2188 | return nullptr; | |
| 2189 | case Stmt::CXXBindTemporaryExprClass: | |
| 2190 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXBindTemporaryExprClass"); | |
| 2191 | return nullptr; | |
| 2192 | case Stmt::CXXBoolLiteralExprClass: | |
| 2193 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXBoolLiteralExprClass"); | |
| 2194 | return nullptr; | |
| 2195 | case Stmt::CXXConstructExprClass: | |
| 2196 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXConstructExprClass"); | |
| 2197 | return nullptr; | |
| 2198 | case Stmt::CXXTemporaryObjectExprClass: | |
| 2199 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTemporaryObjectExprClass"); | |
| 2200 | return nullptr; | |
| 2201 | case Stmt::CXXDefaultArgExprClass: | |
| 2202 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDefaultArgExprClass"); | |
| 2203 | return nullptr; | |
| 2204 | case Stmt::CXXDefaultInitExprClass: | |
| 2205 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDefaultInitExprClass"); | |
| 2206 | return nullptr; | |
| 2207 | case Stmt::CXXDeleteExprClass: | |
| 2208 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDeleteExprClass"); | |
| 2209 | return nullptr; | |
| 2210 | case Stmt::CXXDependentScopeMemberExprClass: | |
| 2211 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDependentScopeMemberExprClass"); | |
| 2212 | return nullptr; | |
| 2213 | case Stmt::CXXFoldExprClass: | |
| 2214 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFoldExprClass"); | |
| 2215 | return nullptr; | |
| 2216 | case Stmt::CXXInheritedCtorInitExprClass: | |
| 2217 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXInheritedCtorInitExprClass"); | |
| 2218 | return nullptr; | |
| 2219 | case Stmt::CXXNewExprClass: | |
| 2220 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNewExprClass"); | |
| 2221 | return nullptr; | |
| 2222 | case Stmt::CXXNoexceptExprClass: | |
| 2223 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNoexceptExprClass"); | |
| 2224 | return nullptr; | |
| 2225 | case Stmt::CXXNullPtrLiteralExprClass: | |
| 2226 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNullPtrLiteralExprClass"); | |
| 2227 | return nullptr; | |
| 2228 | case Stmt::CXXPseudoDestructorExprClass: | |
| 2229 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXPseudoDestructorExprClass"); | |
| 2230 | return nullptr; | |
| 2231 | case Stmt::CXXScalarValueInitExprClass: | |
| 2232 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXScalarValueInitExprClass"); | |
| 2233 | return nullptr; | |
| 2234 | case Stmt::CXXStdInitializerListExprClass: | |
| 2235 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXStdInitializerListExprClass"); | |
| 2236 | return nullptr; | |
| 2237 | case Stmt::CXXThisExprClass: | |
| 2238 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXThisExprClass"); | |
| 2239 | return nullptr; | |
| 2240 | case Stmt::CXXThrowExprClass: | |
| 2241 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXThrowExprClass"); | |
| 2242 | return nullptr; | |
| 2243 | case Stmt::CXXTypeidExprClass: | |
| 2244 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTypeidExprClass"); | |
| 2245 | return nullptr; | |
| 2246 | case Stmt::CXXUnresolvedConstructExprClass: | |
| 2247 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUnresolvedConstructExprClass"); | |
| 2248 | return nullptr; | |
| 2249 | case Stmt::CXXUuidofExprClass: | |
| 2250 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUuidofExprClass"); | |
| 2251 | return nullptr; | |
| 2252 | case Stmt::CUDAKernelCallExprClass: | |
| 2253 | emit_warning(c, stmt->getLocStart(), "TODO handle C CUDAKernelCallExprClass"); | |
| 2254 | return nullptr; | |
| 2255 | case Stmt::CXXMemberCallExprClass: | |
| 2256 | (void)result_used; | |
| 2257 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXMemberCallExprClass"); | |
| 2258 | return nullptr; | |
| 2259 | case Stmt::CXXOperatorCallExprClass: | |
| 2260 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXOperatorCallExprClass"); | |
| 2261 | return nullptr; | |
| 2262 | case Stmt::UserDefinedLiteralClass: | |
| 2263 | emit_warning(c, stmt->getLocStart(), "TODO handle C UserDefinedLiteralClass"); | |
| 2264 | return nullptr; | |
| 2265 | case Stmt::CXXFunctionalCastExprClass: | |
| 2266 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFunctionalCastExprClass"); | |
| 2267 | return nullptr; | |
| 2268 | case Stmt::CXXConstCastExprClass: | |
| 2269 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXConstCastExprClass"); | |
| 2270 | return nullptr; | |
| 2271 | case Stmt::CXXDynamicCastExprClass: | |
| 2272 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDynamicCastExprClass"); | |
| 2273 | return nullptr; | |
| 2274 | case Stmt::CXXReinterpretCastExprClass: | |
| 2275 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXReinterpretCastExprClass"); | |
| 2276 | return nullptr; | |
| 2277 | case Stmt::CXXStaticCastExprClass: | |
| 2278 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXStaticCastExprClass"); | |
| 2279 | return nullptr; | |
| 2280 | case Stmt::ObjCBridgedCastExprClass: | |
| 2281 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBridgedCastExprClass"); | |
| 2282 | return nullptr; | |
| 2283 | case Stmt::CharacterLiteralClass: | |
| 2284 | emit_warning(c, stmt->getLocStart(), "TODO handle C CharacterLiteralClass"); | |
| 2285 | return nullptr; | |
| 2286 | case Stmt::ChooseExprClass: | |
| 2287 | emit_warning(c, stmt->getLocStart(), "TODO handle C ChooseExprClass"); | |
| 2288 | return nullptr; | |
| 2289 | case Stmt::CompoundLiteralExprClass: | |
| 2290 | emit_warning(c, stmt->getLocStart(), "TODO handle C CompoundLiteralExprClass"); | |
| 2291 | return nullptr; | |
| 2292 | case Stmt::ConvertVectorExprClass: | |
| 2293 | emit_warning(c, stmt->getLocStart(), "TODO handle C ConvertVectorExprClass"); | |
| 2294 | return nullptr; | |
| 2295 | case Stmt::CoawaitExprClass: | |
| 2296 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoawaitExprClass"); | |
| 2297 | return nullptr; | |
| 2298 | case Stmt::CoyieldExprClass: | |
| 2299 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoyieldExprClass"); | |
| 2300 | return nullptr; | |
| 2301 | case Stmt::DependentCoawaitExprClass: | |
| 2302 | emit_warning(c, stmt->getLocStart(), "TODO handle C DependentCoawaitExprClass"); | |
| 2303 | return nullptr; | |
| 2304 | case Stmt::DependentScopeDeclRefExprClass: | |
| 2305 | emit_warning(c, stmt->getLocStart(), "TODO handle C DependentScopeDeclRefExprClass"); | |
| 2306 | return nullptr; | |
| 2307 | case Stmt::DesignatedInitExprClass: | |
| 2308 | emit_warning(c, stmt->getLocStart(), "TODO handle C DesignatedInitExprClass"); | |
| 2309 | return nullptr; | |
| 2310 | case Stmt::DesignatedInitUpdateExprClass: | |
| 2311 | emit_warning(c, stmt->getLocStart(), "TODO handle C DesignatedInitUpdateExprClass"); | |
| 2312 | return nullptr; | |
| 2313 | case Stmt::ExprWithCleanupsClass: | |
| 2314 | emit_warning(c, stmt->getLocStart(), "TODO handle C ExprWithCleanupsClass"); | |
| 2315 | return nullptr; | |
| 2316 | case Stmt::ExpressionTraitExprClass: | |
| 2317 | emit_warning(c, stmt->getLocStart(), "TODO handle C ExpressionTraitExprClass"); | |
| 2318 | return nullptr; | |
| 2319 | case Stmt::ExtVectorElementExprClass: | |
| 2320 | emit_warning(c, stmt->getLocStart(), "TODO handle C ExtVectorElementExprClass"); | |
| 2321 | return nullptr; | |
| 2322 | case Stmt::FloatingLiteralClass: | |
| 2323 | emit_warning(c, stmt->getLocStart(), "TODO handle C FloatingLiteralClass"); | |
| 2324 | return nullptr; | |
| 2325 | case Stmt::FunctionParmPackExprClass: | |
| 2326 | emit_warning(c, stmt->getLocStart(), "TODO handle C FunctionParmPackExprClass"); | |
| 2327 | return nullptr; | |
| 2328 | case Stmt::GNUNullExprClass: | |
| 2329 | emit_warning(c, stmt->getLocStart(), "TODO handle C GNUNullExprClass"); | |
| 2330 | return nullptr; | |
| 2331 | case Stmt::GenericSelectionExprClass: | |
| 2332 | emit_warning(c, stmt->getLocStart(), "TODO handle C GenericSelectionExprClass"); | |
| 2333 | return nullptr; | |
| 2334 | case Stmt::ImaginaryLiteralClass: | |
| 2335 | emit_warning(c, stmt->getLocStart(), "TODO handle C ImaginaryLiteralClass"); | |
| 2336 | return nullptr; | |
| 2337 | case Stmt::ImplicitValueInitExprClass: | |
| 2338 | emit_warning(c, stmt->getLocStart(), "TODO handle C ImplicitValueInitExprClass"); | |
| 2339 | return nullptr; | |
| 2340 | case Stmt::InitListExprClass: | |
| 2341 | emit_warning(c, stmt->getLocStart(), "TODO handle C InitListExprClass"); | |
| 2342 | return nullptr; | |
| 2343 | case Stmt::LambdaExprClass: | |
| 2344 | emit_warning(c, stmt->getLocStart(), "TODO handle C LambdaExprClass"); | |
| 2345 | return nullptr; | |
| 2346 | case Stmt::MSPropertyRefExprClass: | |
| 2347 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSPropertyRefExprClass"); | |
| 2348 | return nullptr; | |
| 2349 | case Stmt::MSPropertySubscriptExprClass: | |
| 2350 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSPropertySubscriptExprClass"); | |
| 2351 | return nullptr; | |
| 2352 | case Stmt::MaterializeTemporaryExprClass: | |
| 2353 | emit_warning(c, stmt->getLocStart(), "TODO handle C MaterializeTemporaryExprClass"); | |
| 2354 | return nullptr; | |
| 2355 | case Stmt::NoInitExprClass: | |
| 2356 | emit_warning(c, stmt->getLocStart(), "TODO handle C NoInitExprClass"); | |
| 2357 | return nullptr; | |
| 2358 | case Stmt::OMPArraySectionExprClass: | |
| 2359 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPArraySectionExprClass"); | |
| 2360 | return nullptr; | |
| 2361 | case Stmt::ObjCArrayLiteralClass: | |
| 2362 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCArrayLiteralClass"); | |
| 2363 | return nullptr; | |
| 2364 | case Stmt::ObjCAvailabilityCheckExprClass: | |
| 2365 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAvailabilityCheckExprClass"); | |
| 2366 | return nullptr; | |
| 2367 | case Stmt::ObjCBoolLiteralExprClass: | |
| 2368 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBoolLiteralExprClass"); | |
| 2369 | return nullptr; | |
| 2370 | case Stmt::ObjCBoxedExprClass: | |
| 2371 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBoxedExprClass"); | |
| 2372 | return nullptr; | |
| 2373 | case Stmt::ObjCDictionaryLiteralClass: | |
| 2374 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCDictionaryLiteralClass"); | |
| 2375 | return nullptr; | |
| 2376 | case Stmt::ObjCEncodeExprClass: | |
| 2377 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCEncodeExprClass"); | |
| 2378 | return nullptr; | |
| 2379 | case Stmt::ObjCIndirectCopyRestoreExprClass: | |
| 2380 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIndirectCopyRestoreExprClass"); | |
| 2381 | return nullptr; | |
| 2382 | case Stmt::ObjCIsaExprClass: | |
| 2383 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIsaExprClass"); | |
| 2384 | return nullptr; | |
| 2385 | case Stmt::ObjCIvarRefExprClass: | |
| 2386 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIvarRefExprClass"); | |
| 2387 | return nullptr; | |
| 2388 | case Stmt::ObjCMessageExprClass: | |
| 2389 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCMessageExprClass"); | |
| 2390 | return nullptr; | |
| 2391 | case Stmt::ObjCPropertyRefExprClass: | |
| 2392 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCPropertyRefExprClass"); | |
| 2393 | return nullptr; | |
| 2394 | case Stmt::ObjCProtocolExprClass: | |
| 2395 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCProtocolExprClass"); | |
| 2396 | return nullptr; | |
| 2397 | case Stmt::ObjCSelectorExprClass: | |
| 2398 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCSelectorExprClass"); | |
| 2399 | return nullptr; | |
| 2400 | case Stmt::ObjCStringLiteralClass: | |
| 2401 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCStringLiteralClass"); | |
| 2402 | return nullptr; | |
| 2403 | case Stmt::ObjCSubscriptRefExprClass: | |
| 2404 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCSubscriptRefExprClass"); | |
| 2405 | return nullptr; | |
| 2406 | case Stmt::OffsetOfExprClass: | |
| 2407 | emit_warning(c, stmt->getLocStart(), "TODO handle C OffsetOfExprClass"); | |
| 2408 | return nullptr; | |
| 2409 | case Stmt::OpaqueValueExprClass: | |
| 2410 | emit_warning(c, stmt->getLocStart(), "TODO handle C OpaqueValueExprClass"); | |
| 2411 | return nullptr; | |
| 2412 | case Stmt::UnresolvedLookupExprClass: | |
| 2413 | emit_warning(c, stmt->getLocStart(), "TODO handle C UnresolvedLookupExprClass"); | |
| 2414 | return nullptr; | |
| 2415 | case Stmt::UnresolvedMemberExprClass: | |
| 2416 | emit_warning(c, stmt->getLocStart(), "TODO handle C UnresolvedMemberExprClass"); | |
| 2417 | return nullptr; | |
| 2418 | case Stmt::PackExpansionExprClass: | |
| 2419 | emit_warning(c, stmt->getLocStart(), "TODO handle C PackExpansionExprClass"); | |
| 2420 | return nullptr; | |
| 2421 | case Stmt::ParenExprClass: | |
| 2422 | return trans_expr(c, result_used, block, ((ParenExpr*)stmt)->getSubExpr(), lrvalue); | |
| 2423 | case Stmt::ParenListExprClass: | |
| 2424 | emit_warning(c, stmt->getLocStart(), "TODO handle C ParenListExprClass"); | |
| 2425 | return nullptr; | |
| 2426 | case Stmt::PredefinedExprClass: | |
| 2427 | emit_warning(c, stmt->getLocStart(), "TODO handle C PredefinedExprClass"); | |
| 2428 | return nullptr; | |
| 2429 | case Stmt::PseudoObjectExprClass: | |
| 2430 | emit_warning(c, stmt->getLocStart(), "TODO handle C PseudoObjectExprClass"); | |
| 2431 | return nullptr; | |
| 2432 | case Stmt::ShuffleVectorExprClass: | |
| 2433 | emit_warning(c, stmt->getLocStart(), "TODO handle C ShuffleVectorExprClass"); | |
| 2434 | return nullptr; | |
| 2435 | case Stmt::SizeOfPackExprClass: | |
| 2436 | emit_warning(c, stmt->getLocStart(), "TODO handle C SizeOfPackExprClass"); | |
| 2437 | return nullptr; | |
| 2438 | case Stmt::StmtExprClass: | |
| 2439 | emit_warning(c, stmt->getLocStart(), "TODO handle C StmtExprClass"); | |
| 2440 | return nullptr; | |
| 2441 | case Stmt::StringLiteralClass: | |
| 2442 | emit_warning(c, stmt->getLocStart(), "TODO handle C StringLiteralClass"); | |
| 2443 | return nullptr; | |
| 2444 | case Stmt::SubstNonTypeTemplateParmExprClass: | |
| 2445 | emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmExprClass"); | |
| 2446 | return nullptr; | |
| 2447 | case Stmt::SubstNonTypeTemplateParmPackExprClass: | |
| 2448 | emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmPackExprClass"); | |
| 2449 | return nullptr; | |
| 2450 | case Stmt::TypeTraitExprClass: | |
| 2451 | emit_warning(c, stmt->getLocStart(), "TODO handle C TypeTraitExprClass"); | |
| 2452 | return nullptr; | |
| 2453 | case Stmt::TypoExprClass: | |
| 2454 | emit_warning(c, stmt->getLocStart(), "TODO handle C TypoExprClass"); | |
| 2455 | return nullptr; | |
| 2456 | case Stmt::VAArgExprClass: | |
| 2457 | emit_warning(c, stmt->getLocStart(), "TODO handle C VAArgExprClass"); | |
| 2458 | return nullptr; | |
| 2459 | case Stmt::ForStmtClass: | |
| 2460 | emit_warning(c, stmt->getLocStart(), "TODO handle C ForStmtClass"); | |
| 2461 | return nullptr; | |
| 2462 | case Stmt::GotoStmtClass: | |
| 2463 | emit_warning(c, stmt->getLocStart(), "TODO handle C GotoStmtClass"); | |
| 2464 | return nullptr; | |
| 2465 | case Stmt::IndirectGotoStmtClass: | |
| 2466 | emit_warning(c, stmt->getLocStart(), "TODO handle C IndirectGotoStmtClass"); | |
| 2467 | return nullptr; | |
| 2468 | case Stmt::LabelStmtClass: | |
| 2469 | emit_warning(c, stmt->getLocStart(), "TODO handle C LabelStmtClass"); | |
| 2470 | return nullptr; | |
| 2471 | case Stmt::MSDependentExistsStmtClass: | |
| 2472 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSDependentExistsStmtClass"); | |
| 2473 | return nullptr; | |
| 2474 | case Stmt::OMPAtomicDirectiveClass: | |
| 2475 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPAtomicDirectiveClass"); | |
| 2476 | return nullptr; | |
| 2477 | case Stmt::OMPBarrierDirectiveClass: | |
| 2478 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPBarrierDirectiveClass"); | |
| 2479 | return nullptr; | |
| 2480 | case Stmt::OMPCancelDirectiveClass: | |
| 2481 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCancelDirectiveClass"); | |
| 2482 | return nullptr; | |
| 2483 | case Stmt::OMPCancellationPointDirectiveClass: | |
| 2484 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCancellationPointDirectiveClass"); | |
| 2485 | return nullptr; | |
| 2486 | case Stmt::OMPCriticalDirectiveClass: | |
| 2487 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCriticalDirectiveClass"); | |
| 2488 | return nullptr; | |
| 2489 | case Stmt::OMPFlushDirectiveClass: | |
| 2490 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPFlushDirectiveClass"); | |
| 2491 | return nullptr; | |
| 2492 | case Stmt::OMPDistributeDirectiveClass: | |
| 2493 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeDirectiveClass"); | |
| 2494 | return nullptr; | |
| 2495 | case Stmt::OMPDistributeParallelForDirectiveClass: | |
| 2496 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeParallelForDirectiveClass"); | |
| 2497 | return nullptr; | |
| 2498 | case Stmt::OMPDistributeParallelForSimdDirectiveClass: | |
| 2499 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeParallelForSimdDirectiveClass"); | |
| 2500 | return nullptr; | |
| 2501 | case Stmt::OMPDistributeSimdDirectiveClass: | |
| 2502 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeSimdDirectiveClass"); | |
| 2503 | return nullptr; | |
| 2504 | case Stmt::OMPForDirectiveClass: | |
| 2505 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPForDirectiveClass"); | |
| 2506 | return nullptr; | |
| 2507 | case Stmt::OMPForSimdDirectiveClass: | |
| 2508 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPForSimdDirectiveClass"); | |
| 2509 | return nullptr; | |
| 2510 | case Stmt::OMPParallelForDirectiveClass: | |
| 2511 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelForDirectiveClass"); | |
| 2512 | return nullptr; | |
| 2513 | case Stmt::OMPParallelForSimdDirectiveClass: | |
| 2514 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelForSimdDirectiveClass"); | |
| 2515 | return nullptr; | |
| 2516 | case Stmt::OMPSimdDirectiveClass: | |
| 2517 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSimdDirectiveClass"); | |
| 2518 | return nullptr; | |
| 2519 | case Stmt::OMPTargetParallelForSimdDirectiveClass: | |
| 2520 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelForSimdDirectiveClass"); | |
| 2521 | return nullptr; | |
| 2522 | case Stmt::OMPTargetSimdDirectiveClass: | |
| 2523 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetSimdDirectiveClass"); | |
| 2524 | return nullptr; | |
| 2525 | case Stmt::OMPTargetTeamsDistributeDirectiveClass: | |
| 2526 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeDirectiveClass"); | |
| 2527 | return nullptr; | |
| 2528 | case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: | |
| 2529 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeParallelForDirectiveClass"); | |
| 2530 | return nullptr; | |
| 2531 | case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: | |
| 2532 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeParallelForSimdDirectiveClass"); | |
| 2533 | return nullptr; | |
| 2534 | case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: | |
| 2535 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeSimdDirectiveClass"); | |
| 2536 | return nullptr; | |
| 2537 | case Stmt::OMPTaskLoopDirectiveClass: | |
| 2538 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskLoopDirectiveClass"); | |
| 2539 | return nullptr; | |
| 2540 | case Stmt::OMPTaskLoopSimdDirectiveClass: | |
| 2541 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskLoopSimdDirectiveClass"); | |
| 2542 | return nullptr; | |
| 2543 | case Stmt::OMPTeamsDistributeDirectiveClass: | |
| 2544 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeDirectiveClass"); | |
| 2545 | return nullptr; | |
| 2546 | case Stmt::OMPTeamsDistributeParallelForDirectiveClass: | |
| 2547 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeParallelForDirectiveClass"); | |
| 2548 | return nullptr; | |
| 2549 | case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: | |
| 2550 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeParallelForSimdDirectiveClass"); | |
| 2551 | return nullptr; | |
| 2552 | case Stmt::OMPTeamsDistributeSimdDirectiveClass: | |
| 2553 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeSimdDirectiveClass"); | |
| 2554 | return nullptr; | |
| 2555 | case Stmt::OMPMasterDirectiveClass: | |
| 2556 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPMasterDirectiveClass"); | |
| 2557 | return nullptr; | |
| 2558 | case Stmt::OMPOrderedDirectiveClass: | |
| 2559 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPOrderedDirectiveClass"); | |
| 2560 | return nullptr; | |
| 2561 | case Stmt::OMPParallelDirectiveClass: | |
| 2562 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelDirectiveClass"); | |
| 2563 | return nullptr; | |
| 2564 | case Stmt::OMPParallelSectionsDirectiveClass: | |
| 2565 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelSectionsDirectiveClass"); | |
| 2566 | return nullptr; | |
| 2567 | case Stmt::OMPSectionDirectiveClass: | |
| 2568 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSectionDirectiveClass"); | |
| 2569 | return nullptr; | |
| 2570 | case Stmt::OMPSectionsDirectiveClass: | |
| 2571 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSectionsDirectiveClass"); | |
| 2572 | return nullptr; | |
| 2573 | case Stmt::OMPSingleDirectiveClass: | |
| 2574 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSingleDirectiveClass"); | |
| 2575 | return nullptr; | |
| 2576 | case Stmt::OMPTargetDataDirectiveClass: | |
| 2577 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetDataDirectiveClass"); | |
| 2578 | return nullptr; | |
| 2579 | case Stmt::OMPTargetDirectiveClass: | |
| 2580 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetDirectiveClass"); | |
| 2581 | return nullptr; | |
| 2582 | case Stmt::OMPTargetEnterDataDirectiveClass: | |
| 2583 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetEnterDataDirectiveClass"); | |
| 2584 | return nullptr; | |
| 2585 | case Stmt::OMPTargetExitDataDirectiveClass: | |
| 2586 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetExitDataDirectiveClass"); | |
| 2587 | return nullptr; | |
| 2588 | case Stmt::OMPTargetParallelDirectiveClass: | |
| 2589 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelDirectiveClass"); | |
| 2590 | return nullptr; | |
| 2591 | case Stmt::OMPTargetParallelForDirectiveClass: | |
| 2592 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelForDirectiveClass"); | |
| 2593 | return nullptr; | |
| 2594 | case Stmt::OMPTargetTeamsDirectiveClass: | |
| 2595 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDirectiveClass"); | |
| 2596 | return nullptr; | |
| 2597 | case Stmt::OMPTargetUpdateDirectiveClass: | |
| 2598 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetUpdateDirectiveClass"); | |
| 2599 | return nullptr; | |
| 2600 | case Stmt::OMPTaskDirectiveClass: | |
| 2601 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskDirectiveClass"); | |
| 2602 | return nullptr; | |
| 2603 | case Stmt::OMPTaskgroupDirectiveClass: | |
| 2604 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskgroupDirectiveClass"); | |
| 2605 | return nullptr; | |
| 2606 | case Stmt::OMPTaskwaitDirectiveClass: | |
| 2607 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskwaitDirectiveClass"); | |
| 2608 | return nullptr; | |
| 2609 | case Stmt::OMPTaskyieldDirectiveClass: | |
| 2610 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskyieldDirectiveClass"); | |
| 2611 | return nullptr; | |
| 2612 | case Stmt::OMPTeamsDirectiveClass: | |
| 2613 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDirectiveClass"); | |
| 2614 | return nullptr; | |
| 2615 | case Stmt::ObjCAtCatchStmtClass: | |
| 2616 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtCatchStmtClass"); | |
| 2617 | return nullptr; | |
| 2618 | case Stmt::ObjCAtFinallyStmtClass: | |
| 2619 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtFinallyStmtClass"); | |
| 2620 | return nullptr; | |
| 2621 | case Stmt::ObjCAtSynchronizedStmtClass: | |
| 2622 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtSynchronizedStmtClass"); | |
| 2623 | return nullptr; | |
| 2624 | case Stmt::ObjCAtThrowStmtClass: | |
| 2625 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtThrowStmtClass"); | |
| 2626 | return nullptr; | |
| 2627 | case Stmt::ObjCAtTryStmtClass: | |
| 2628 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtTryStmtClass"); | |
| 2629 | return nullptr; | |
| 2630 | case Stmt::ObjCAutoreleasePoolStmtClass: | |
| 2631 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAutoreleasePoolStmtClass"); | |
| 2632 | return nullptr; | |
| 2633 | case Stmt::ObjCForCollectionStmtClass: | |
| 2634 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCForCollectionStmtClass"); | |
| 2635 | return nullptr; | |
| 2636 | case Stmt::SEHExceptStmtClass: | |
| 2637 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHExceptStmtClass"); | |
| 2638 | return nullptr; | |
| 2639 | case Stmt::SEHFinallyStmtClass: | |
| 2640 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHFinallyStmtClass"); | |
| 2641 | return nullptr; | |
| 2642 | case Stmt::SEHLeaveStmtClass: | |
| 2643 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHLeaveStmtClass"); | |
| 2644 | return nullptr; | |
| 2645 | case Stmt::SEHTryStmtClass: | |
| 2646 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHTryStmtClass"); | |
| 2647 | return nullptr; | |
| 2648 | } | |
| 2649 | zig_unreachable(); | |
| 2650 | } | |
| 2651 | ||
| 2652 | static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { | |
| 2653 | Buf *fn_name = buf_create_from_str(decl_name(fn_decl)); | |
| 2654 | ||
| 2655 | if (get_global(c, fn_name)) { | |
| 2656 | // we already saw this function | |
| 2657 | return; | |
| 2658 | } | |
| 2659 | ||
| 2660 | AstNode *proto_node = trans_qual_type(c, fn_decl->getType(), fn_decl->getLocation()); | |
| 2661 | if (proto_node == nullptr) { | |
| 2662 | emit_warning(c, fn_decl->getLocation(), "unable to resolve prototype of function '%s'", buf_ptr(fn_name)); | |
| 2663 | return; | |
| 2664 | } | |
| 2665 | ||
| 2666 | proto_node->data.fn_proto.name = fn_name; | |
| 2667 | proto_node->data.fn_proto.is_extern = !fn_decl->hasBody(); | |
| 2668 | ||
| 2669 | StorageClass sc = fn_decl->getStorageClass(); | |
| 2670 | if (sc == SC_None) { | |
| 2671 | proto_node->data.fn_proto.visib_mod = fn_decl->hasBody() ? c->export_visib_mod : c->visib_mod; | |
| 2672 | } else if (sc == SC_Extern || sc == SC_Static) { | |
| 2673 | proto_node->data.fn_proto.visib_mod = c->visib_mod; | |
| 2674 | } else if (sc == SC_PrivateExtern) { | |
| 2675 | emit_warning(c, fn_decl->getLocation(), "unsupported storage class: private extern"); | |
| 2676 | return; | |
| 2677 | } else { | |
| 2678 | emit_warning(c, fn_decl->getLocation(), "unsupported storage class: unknown"); | |
| 2679 | return; | |
| 2680 | } | |
| 2681 | ||
| 2682 | for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { | |
| 2683 | AstNode *param_node = proto_node->data.fn_proto.params.at(i); | |
| 2684 | const ParmVarDecl *param = fn_decl->getParamDecl(i); | |
| 2685 | const char *name = decl_name(param); | |
| 2686 | Buf *proto_param_name; | |
| 2687 | if (strlen(name) != 0) { | |
| 2688 | proto_param_name = buf_create_from_str(name); | |
| 2689 | } else { | |
| 2690 | proto_param_name = param_node->data.param_decl.name; | |
| 2691 | if (proto_param_name == nullptr) { | |
| 2692 | proto_param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i); | |
| 2693 | } | |
| 2694 | } | |
| 2695 | param_node->data.param_decl.name = proto_param_name; | |
| 2696 | } | |
| 2697 | ||
| 2698 | if (!fn_decl->hasBody()) { | |
| 2699 | // just a prototype | |
| 2700 | add_top_level_decl(c, proto_node->data.fn_proto.name, proto_node); | |
| 2701 | return; | |
| 2702 | } | |
| 2703 | ||
| 2704 | // actual function definition with body | |
| 2705 | c->ptr_params.clear(); | |
| 2706 | Stmt *body = fn_decl->getBody(); | |
| 2707 | AstNode *actual_body_node = trans_stmt(c, false, nullptr, body, TransRValue); | |
| 2708 | assert(actual_body_node != skip_add_to_block_node); | |
| 2709 | if (actual_body_node == nullptr) { | |
| 2710 | emit_warning(c, fn_decl->getLocation(), "unable to translate function"); | |
| 2711 | return; | |
| 2712 | } | |
| 2713 | ||
| 2714 | // it worked | |
| 2715 | ||
| 2716 | assert(actual_body_node->type == NodeTypeBlock); | |
| 2717 | AstNode *body_node_with_param_inits = trans_create_node(c, NodeTypeBlock); | |
| 2718 | ||
| 2719 | for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { | |
| 2720 | AstNode *param_node = proto_node->data.fn_proto.params.at(i); | |
| 2721 | Buf *good_name = param_node->data.param_decl.name; | |
| 2722 | ||
| 2723 | if (c->ptr_params.maybe_get(good_name) != nullptr) { | |
| 2724 | // TODO: avoid name collisions | |
| 2725 | Buf *mangled_name = buf_sprintf("_arg_%s", buf_ptr(good_name)); | |
| 2726 | param_node->data.param_decl.name = mangled_name; | |
| 2727 | ||
| 2728 | // var c_name = _mangled_name; | |
| 2729 | AstNode *parameter_init = trans_create_node_var_decl_local(c, false, good_name, nullptr, trans_create_node_symbol(c, mangled_name)); | |
| 2730 | ||
| 2731 | body_node_with_param_inits->data.block.statements.append(parameter_init); | |
| 2732 | } | |
| 2733 | } | |
| 2734 | ||
| 2735 | for (size_t i = 0; i < actual_body_node->data.block.statements.length; i += 1) { | |
| 2736 | body_node_with_param_inits->data.block.statements.append(actual_body_node->data.block.statements.at(i)); | |
| 2737 | } | |
| 2738 | ||
| 2739 | AstNode *fn_def_node = trans_create_node(c, NodeTypeFnDef); | |
| 2740 | fn_def_node->data.fn_def.fn_proto = proto_node; | |
| 2741 | fn_def_node->data.fn_def.body = body_node_with_param_inits; | |
| 2742 | ||
| 2743 | proto_node->data.fn_proto.fn_def_node = fn_def_node; | |
| 2744 | add_top_level_decl(c, fn_def_node->data.fn_def.fn_proto->data.fn_proto.name, fn_def_node); | |
| 2745 | } | |
| 2746 | ||
| 2747 | static AstNode *resolve_typdef_as_builtin(Context *c, const TypedefNameDecl *typedef_decl, const char *primitive_name) { | |
| 2748 | AstNode *node = trans_create_node_symbol_str(c, primitive_name); | |
| 2749 | c->decl_table.put(typedef_decl, node); | |
| 2750 | return node; | |
| 2751 | } | |
| 2752 | ||
| 2753 | static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) { | |
| 2754 | auto existing_entry = c->decl_table.maybe_get((void*)typedef_decl->getCanonicalDecl()); | |
| 2755 | if (existing_entry) { | |
| 2756 | return existing_entry->value; | |
| 2757 | } | |
| 2758 | QualType child_qt = typedef_decl->getUnderlyingType(); | |
| 2759 | Buf *type_name = buf_create_from_str(decl_name(typedef_decl)); | |
| 2760 | ||
| 2761 | if (buf_eql_str(type_name, "uint8_t")) { | |
| 2762 | return resolve_typdef_as_builtin(c, typedef_decl, "u8"); | |
| 2763 | } else if (buf_eql_str(type_name, "int8_t")) { | |
| 2764 | return resolve_typdef_as_builtin(c, typedef_decl, "i8"); | |
| 2765 | } else if (buf_eql_str(type_name, "uint16_t")) { | |
| 2766 | return resolve_typdef_as_builtin(c, typedef_decl, "u16"); | |
| 2767 | } else if (buf_eql_str(type_name, "int16_t")) { | |
| 2768 | return resolve_typdef_as_builtin(c, typedef_decl, "i16"); | |
| 2769 | } else if (buf_eql_str(type_name, "uint32_t")) { | |
| 2770 | return resolve_typdef_as_builtin(c, typedef_decl, "u32"); | |
| 2771 | } else if (buf_eql_str(type_name, "int32_t")) { | |
| 2772 | return resolve_typdef_as_builtin(c, typedef_decl, "i32"); | |
| 2773 | } else if (buf_eql_str(type_name, "uint64_t")) { | |
| 2774 | return resolve_typdef_as_builtin(c, typedef_decl, "u64"); | |
| 2775 | } else if (buf_eql_str(type_name, "int64_t")) { | |
| 2776 | return resolve_typdef_as_builtin(c, typedef_decl, "i64"); | |
| 2777 | } else if (buf_eql_str(type_name, "intptr_t")) { | |
| 2778 | return resolve_typdef_as_builtin(c, typedef_decl, "isize"); | |
| 2779 | } else if (buf_eql_str(type_name, "uintptr_t")) { | |
| 2780 | return resolve_typdef_as_builtin(c, typedef_decl, "usize"); | |
| 2781 | } else if (buf_eql_str(type_name, "ssize_t")) { | |
| 2782 | return resolve_typdef_as_builtin(c, typedef_decl, "isize"); | |
| 2783 | } else if (buf_eql_str(type_name, "size_t")) { | |
| 2784 | return resolve_typdef_as_builtin(c, typedef_decl, "usize"); | |
| 2785 | } | |
| 2786 | ||
| 2787 | // if the underlying type is anonymous, we can special case it to just | |
| 2788 | // use the name of this typedef | |
| 2789 | // TODO | |
| 2790 | ||
| 2791 | AstNode *type_node = trans_qual_type(c, child_qt, typedef_decl->getLocation()); | |
| 2792 | if (type_node == nullptr) { | |
| 2793 | emit_warning(c, typedef_decl->getLocation(), "typedef %s - unresolved child type", buf_ptr(type_name)); | |
| 2794 | c->decl_table.put(typedef_decl, nullptr); | |
| 2795 | return nullptr; | |
| 2796 | } | |
| 2797 | add_global_var(c, type_name, type_node); | |
| 2798 | ||
| 2799 | AstNode *symbol_node = trans_create_node_symbol(c, type_name); | |
| 2800 | c->decl_table.put(typedef_decl->getCanonicalDecl(), symbol_node); | |
| 2801 | return symbol_node; | |
| 2802 | } | |
| 2803 | ||
| 2804 | struct AstNode *demote_enum_to_opaque(Context *c, const EnumDecl *enum_decl, | |
| 2805 | Buf *full_type_name, Buf *bare_name) | |
| 2806 | { | |
| 2807 | AstNode *opaque_node = trans_create_node_opaque(c); | |
| 2808 | if (full_type_name == nullptr) { | |
| 2809 | c->decl_table.put(enum_decl->getCanonicalDecl(), opaque_node); | |
| 2810 | return opaque_node; | |
| 2811 | } | |
| 2812 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 2813 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 2814 | add_global_var(c, full_type_name, opaque_node); | |
| 2815 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); | |
| 2816 | return symbol_node; | |
| 2817 | } | |
| 2818 | ||
| 2819 | static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { | |
| 2820 | auto existing_entry = c->decl_table.maybe_get((void*)enum_decl->getCanonicalDecl()); | |
| 2821 | if (existing_entry) { | |
| 2822 | return existing_entry->value; | |
| 2823 | } | |
| 2824 | ||
| 2825 | const char *raw_name = decl_name(enum_decl); | |
| 2826 | bool is_anonymous = (raw_name[0] == 0); | |
| 2827 | Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); | |
| 2828 | Buf *full_type_name = is_anonymous ? nullptr : buf_sprintf("enum_%s", buf_ptr(bare_name)); | |
| 2829 | ||
| 2830 | const EnumDecl *enum_def = enum_decl->getDefinition(); | |
| 2831 | if (!enum_def) { | |
| 2832 | return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name); | |
| 2833 | } | |
| 2834 | ||
| 2835 | bool pure_enum = true; | |
| 2836 | uint32_t field_count = 0; | |
| 2837 | for (auto it = enum_def->enumerator_begin(), | |
| 2838 | it_end = enum_def->enumerator_end(); | |
| 2839 | it != it_end; ++it, field_count += 1) | |
| 2840 | { | |
| 2841 | const EnumConstantDecl *enum_const = *it; | |
| 2842 | if (enum_const->getInitExpr()) { | |
| 2843 | pure_enum = false; | |
| 2844 | } | |
| 2845 | } | |
| 2846 | ||
| 2847 | AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation()); | |
| 2848 | assert(tag_int_type); | |
| 2849 | ||
| 2850 | if (pure_enum) { | |
| 2851 | AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl); | |
| 2852 | enum_node->data.container_decl.kind = ContainerKindEnum; | |
| 2853 | enum_node->data.container_decl.layout = ContainerLayoutExtern; | |
| 2854 | enum_node->data.container_decl.init_arg_expr = tag_int_type; | |
| 2855 | ||
| 2856 | enum_node->data.container_decl.fields.resize(field_count); | |
| 2857 | uint32_t i = 0; | |
| 2858 | for (auto it = enum_def->enumerator_begin(), | |
| 2859 | it_end = enum_def->enumerator_end(); | |
| 2860 | it != it_end; ++it, i += 1) | |
| 2861 | { | |
| 2862 | const EnumConstantDecl *enum_const = *it; | |
| 2863 | ||
| 2864 | Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); | |
| 2865 | Buf *field_name; | |
| 2866 | if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) { | |
| 2867 | field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name)); | |
| 2868 | } else { | |
| 2869 | field_name = enum_val_name; | |
| 2870 | } | |
| 2871 | ||
| 2872 | AstNode *field_node = trans_create_node(c, NodeTypeStructField); | |
| 2873 | field_node->data.struct_field.name = field_name; | |
| 2874 | field_node->data.struct_field.type = nullptr; | |
| 2875 | enum_node->data.container_decl.fields.items[i] = field_node; | |
| 2876 | ||
| 2877 | // in C each enum value is in the global namespace. so we put them there too. | |
| 2878 | // at this point we can rely on the enum emitting successfully | |
| 2879 | if (is_anonymous) { | |
| 2880 | AstNode *lit_node = trans_create_node_unsigned(c, i); | |
| 2881 | add_global_var(c, enum_val_name, lit_node); | |
| 2882 | } else { | |
| 2883 | AstNode *field_access_node = trans_create_node_field_access(c, | |
| 2884 | trans_create_node_symbol(c, full_type_name), field_name); | |
| 2885 | add_global_var(c, enum_val_name, field_access_node); | |
| 2886 | } | |
| 2887 | } | |
| 2888 | ||
| 2889 | if (is_anonymous) { | |
| 2890 | c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node); | |
| 2891 | return enum_node; | |
| 2892 | } else { | |
| 2893 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 2894 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 2895 | add_global_var(c, full_type_name, enum_node); | |
| 2896 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); | |
| 2897 | return enum_node; | |
| 2898 | } | |
| 2899 | } | |
| 2900 | ||
| 2901 | // TODO after issue #305 is solved, make this be an enum with tag_int_type | |
| 2902 | // as the integer type and set the custom enum values | |
| 2903 | AstNode *enum_node = tag_int_type; | |
| 2904 | ||
| 2905 | ||
| 2906 | // add variables for all the values with enum_node | |
| 2907 | for (auto it = enum_def->enumerator_begin(), | |
| 2908 | it_end = enum_def->enumerator_end(); | |
| 2909 | it != it_end; ++it) | |
| 2910 | { | |
| 2911 | const EnumConstantDecl *enum_const = *it; | |
| 2912 | ||
| 2913 | Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); | |
| 2914 | AstNode *int_node = trans_create_node_apint(c, enum_const->getInitVal()); | |
| 2915 | AstNode *var_node = add_global_var(c, enum_val_name, int_node); | |
| 2916 | var_node->data.variable_declaration.type = tag_int_type; | |
| 2917 | } | |
| 2918 | ||
| 2919 | if (is_anonymous) { | |
| 2920 | c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node); | |
| 2921 | return enum_node; | |
| 2922 | } else { | |
| 2923 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 2924 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 2925 | add_global_var(c, full_type_name, enum_node); | |
| 2926 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); | |
| 2927 | return symbol_node; | |
| 2928 | } | |
| 2929 | } | |
| 2930 | ||
| 2931 | static AstNode *demote_struct_to_opaque(Context *c, const RecordDecl *record_decl, | |
| 2932 | Buf *full_type_name, Buf *bare_name) | |
| 2933 | { | |
| 2934 | AstNode *opaque_node = trans_create_node_opaque(c); | |
| 2935 | if (full_type_name == nullptr) { | |
| 2936 | c->decl_table.put(record_decl->getCanonicalDecl(), opaque_node); | |
| 2937 | return opaque_node; | |
| 2938 | } | |
| 2939 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 2940 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 2941 | add_global_var(c, full_type_name, opaque_node); | |
| 2942 | c->decl_table.put(record_decl->getCanonicalDecl(), symbol_node); | |
| 2943 | return symbol_node; | |
| 2944 | } | |
| 2945 | ||
| 2946 | static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { | |
| 2947 | auto existing_entry = c->decl_table.maybe_get((void*)record_decl->getCanonicalDecl()); | |
| 2948 | if (existing_entry) { | |
| 2949 | return existing_entry->value; | |
| 2950 | } | |
| 2951 | ||
| 2952 | const char *raw_name = decl_name(record_decl); | |
| 2953 | ||
| 2954 | const char *container_kind_name; | |
| 2955 | ContainerKind container_kind; | |
| 2956 | if (record_decl->isUnion()) { | |
| 2957 | container_kind_name = "union"; | |
| 2958 | container_kind = ContainerKindUnion; | |
| 2959 | } else if (record_decl->isStruct()) { | |
| 2960 | container_kind_name = "struct"; | |
| 2961 | container_kind = ContainerKindStruct; | |
| 2962 | } else { | |
| 2963 | emit_warning(c, record_decl->getLocation(), "skipping record %s, not a struct or union", raw_name); | |
| 2964 | c->decl_table.put(record_decl->getCanonicalDecl(), nullptr); | |
| 2965 | return nullptr; | |
| 2966 | } | |
| 2967 | ||
| 2968 | bool is_anonymous = record_decl->isAnonymousStructOrUnion() || raw_name[0] == 0; | |
| 2969 | Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); | |
| 2970 | Buf *full_type_name = (bare_name == nullptr) ? | |
| 2971 | nullptr : buf_sprintf("%s_%s", container_kind_name, buf_ptr(bare_name)); | |
| 2972 | ||
| 2973 | RecordDecl *record_def = record_decl->getDefinition(); | |
| 2974 | if (record_def == nullptr) { | |
| 2975 | return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); | |
| 2976 | } | |
| 2977 | ||
| 2978 | // count fields and validate | |
| 2979 | uint32_t field_count = 0; | |
| 2980 | for (auto it = record_def->field_begin(), | |
| 2981 | it_end = record_def->field_end(); | |
| 2982 | it != it_end; ++it, field_count += 1) | |
| 2983 | { | |
| 2984 | const FieldDecl *field_decl = *it; | |
| 2985 | ||
| 2986 | if (field_decl->isBitField()) { | |
| 2987 | emit_warning(c, field_decl->getLocation(), "%s %s demoted to opaque type - has bitfield", | |
| 2988 | container_kind_name, | |
| 2989 | is_anonymous ? "(anon)" : buf_ptr(bare_name)); | |
| 2990 | return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); | |
| 2991 | } | |
| 2992 | } | |
| 2993 | ||
| 2994 | AstNode *struct_node = trans_create_node(c, NodeTypeContainerDecl); | |
| 2995 | struct_node->data.container_decl.kind = container_kind; | |
| 2996 | struct_node->data.container_decl.layout = ContainerLayoutExtern; | |
| 2997 | ||
| 2998 | // TODO handle attribute packed | |
| 2999 | ||
| 3000 | struct_node->data.container_decl.fields.resize(field_count); | |
| 3001 | ||
| 3002 | // must be before fields in case a circular reference happens | |
| 3003 | if (is_anonymous) { | |
| 3004 | c->decl_table.put(record_decl->getCanonicalDecl(), struct_node); | |
| 3005 | } else { | |
| 3006 | c->decl_table.put(record_decl->getCanonicalDecl(), trans_create_node_symbol(c, full_type_name)); | |
| 3007 | } | |
| 3008 | ||
| 3009 | uint32_t i = 0; | |
| 3010 | for (auto it = record_def->field_begin(), | |
| 3011 | it_end = record_def->field_end(); | |
| 3012 | it != it_end; ++it, i += 1) | |
| 3013 | { | |
| 3014 | const FieldDecl *field_decl = *it; | |
| 3015 | ||
| 3016 | AstNode *field_node = trans_create_node(c, NodeTypeStructField); | |
| 3017 | field_node->data.struct_field.name = buf_create_from_str(decl_name(field_decl)); | |
| 3018 | field_node->data.struct_field.type = trans_qual_type(c, field_decl->getType(), field_decl->getLocation()); | |
| 3019 | ||
| 3020 | if (field_node->data.struct_field.type == nullptr) { | |
| 3021 | emit_warning(c, field_decl->getLocation(), | |
| 3022 | "%s %s demoted to opaque type - unresolved type", | |
| 3023 | container_kind_name, | |
| 3024 | is_anonymous ? "(anon)" : buf_ptr(bare_name)); | |
| 3025 | ||
| 3026 | return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); | |
| 3027 | } | |
| 3028 | ||
| 3029 | struct_node->data.container_decl.fields.items[i] = field_node; | |
| 3030 | } | |
| 3031 | ||
| 3032 | if (is_anonymous) { | |
| 3033 | return struct_node; | |
| 3034 | } else { | |
| 3035 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 3036 | add_global_var(c, full_type_name, struct_node); | |
| 3037 | return trans_create_node_symbol(c, full_type_name); | |
| 3038 | } | |
| 3039 | } | |
| 3040 | ||
| 3041 | static void visit_var_decl(Context *c, const VarDecl *var_decl) { | |
| 3042 | Buf *name = buf_create_from_str(decl_name(var_decl)); | |
| 3043 | ||
| 3044 | switch (var_decl->getTLSKind()) { | |
| 3045 | case VarDecl::TLS_None: | |
| 3046 | break; | |
| 3047 | case VarDecl::TLS_Static: | |
| 3048 | emit_warning(c, var_decl->getLocation(), | |
| 3049 | "ignoring variable '%s' - static thread local storage", buf_ptr(name)); | |
| 3050 | return; | |
| 3051 | case VarDecl::TLS_Dynamic: | |
| 3052 | emit_warning(c, var_decl->getLocation(), | |
| 3053 | "ignoring variable '%s' - dynamic thread local storage", buf_ptr(name)); | |
| 3054 | return; | |
| 3055 | } | |
| 3056 | ||
| 3057 | QualType qt = var_decl->getType(); | |
| 3058 | AstNode *var_type = trans_qual_type(c, qt, var_decl->getLocation()); | |
| 3059 | if (var_type == nullptr) { | |
| 3060 | emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - unresolved type", buf_ptr(name)); | |
| 3061 | return; | |
| 3062 | } | |
| 3063 | ||
| 3064 | bool is_extern = var_decl->hasExternalStorage(); | |
| 3065 | bool is_static = var_decl->isFileVarDecl(); | |
| 3066 | bool is_const = qt.isConstQualified(); | |
| 3067 | ||
| 3068 | if (is_static && !is_extern) { | |
| 3069 | AstNode *init_node; | |
| 3070 | if (var_decl->hasInit()) { | |
| 3071 | APValue *ap_value = var_decl->evaluateValue(); | |
| 3072 | if (ap_value == nullptr) { | |
| 3073 | emit_warning(c, var_decl->getLocation(), | |
| 3074 | "ignoring variable '%s' - unable to evaluate initializer", buf_ptr(name)); | |
| 3075 | return; | |
| 3076 | } | |
| 3077 | switch (ap_value->getKind()) { | |
| 3078 | case APValue::Int: | |
| 3079 | init_node = trans_create_node_apint(c, ap_value->getInt()); | |
| 3080 | break; | |
| 3081 | case APValue::Uninitialized: | |
| 3082 | init_node = trans_create_node(c, NodeTypeUndefinedLiteral); | |
| 3083 | break; | |
| 3084 | case APValue::Float: | |
| 3085 | case APValue::ComplexInt: | |
| 3086 | case APValue::ComplexFloat: | |
| 3087 | case APValue::LValue: | |
| 3088 | case APValue::Vector: | |
| 3089 | case APValue::Array: | |
| 3090 | case APValue::Struct: | |
| 3091 | case APValue::Union: | |
| 3092 | case APValue::MemberPointer: | |
| 3093 | case APValue::AddrLabelDiff: | |
| 3094 | emit_warning(c, var_decl->getLocation(), | |
| 3095 | "ignoring variable '%s' - unrecognized initializer value kind", buf_ptr(name)); | |
| 3096 | return; | |
| 3097 | } | |
| 3098 | } else { | |
| 3099 | init_node = trans_create_node(c, NodeTypeUndefinedLiteral); | |
| 3100 | } | |
| 3101 | ||
| 3102 | AstNode *var_node = trans_create_node_var_decl_global(c, is_const, name, var_type, init_node); | |
| 3103 | add_top_level_decl(c, name, var_node); | |
| 3104 | return; | |
| 3105 | } | |
| 3106 | ||
| 3107 | if (is_extern) { | |
| 3108 | AstNode *var_node = trans_create_node_var_decl_global(c, is_const, name, var_type, nullptr); | |
| 3109 | var_node->data.variable_declaration.is_extern = true; | |
| 3110 | add_top_level_decl(c, name, var_node); | |
| 3111 | return; | |
| 3112 | } | |
| 3113 | ||
| 3114 | emit_warning(c, var_decl->getLocation(), | |
| 3115 | "ignoring variable '%s' - non-extern, non-static variable", buf_ptr(name)); | |
| 3116 | return; | |
| 3117 | } | |
| 3118 | ||
| 3119 | static bool decl_visitor(void *context, const Decl *decl) { | |
| 3120 | Context *c = (Context*)context; | |
| 3121 | ||
| 3122 | switch (decl->getKind()) { | |
| 3123 | case Decl::Function: | |
| 3124 | visit_fn_decl(c, static_cast<const FunctionDecl*>(decl)); | |
| 3125 | break; | |
| 3126 | case Decl::Typedef: | |
| 3127 | resolve_typedef_decl(c, static_cast<const TypedefNameDecl *>(decl)); | |
| 3128 | break; | |
| 3129 | case Decl::Enum: | |
| 3130 | resolve_enum_decl(c, static_cast<const EnumDecl *>(decl)); | |
| 3131 | break; | |
| 3132 | case Decl::Record: | |
| 3133 | resolve_record_decl(c, static_cast<const RecordDecl *>(decl)); | |
| 3134 | break; | |
| 3135 | case Decl::Var: | |
| 3136 | visit_var_decl(c, static_cast<const VarDecl *>(decl)); | |
| 3137 | break; | |
| 3138 | default: | |
| 3139 | emit_warning(c, decl->getLocation(), "ignoring %s decl", decl->getDeclKindName()); | |
| 3140 | } | |
| 3141 | ||
| 3142 | return true; | |
| 3143 | } | |
| 3144 | ||
| 3145 | static bool name_exists(Context *c, Buf *name) { | |
| 3146 | return get_global(c, name) != nullptr; | |
| 3147 | } | |
| 3148 | ||
| 3149 | static void render_aliases(Context *c) { | |
| 3150 | for (size_t i = 0; i < c->aliases.length; i += 1) { | |
| 3151 | Alias *alias = &c->aliases.at(i); | |
| 3152 | if (name_exists(c, alias->new_name)) | |
| 3153 | continue; | |
| 3154 | ||
| 3155 | add_global_var(c, alias->new_name, trans_create_node_symbol(c, alias->canon_name)); | |
| 3156 | } | |
| 3157 | } | |
| 3158 | ||
| 3159 | static void render_macros(Context *c) { | |
| 3160 | auto it = c->macro_table.entry_iterator(); | |
| 3161 | for (;;) { | |
| 3162 | auto *entry = it.next(); | |
| 3163 | if (!entry) | |
| 3164 | break; | |
| 3165 | ||
| 3166 | AstNode *value_node = entry->value; | |
| 3167 | if (value_node->type == NodeTypeFnDef) { | |
| 3168 | add_top_level_decl(c, value_node->data.fn_def.fn_proto->data.fn_proto.name, value_node); | |
| 3169 | } else { | |
| 3170 | add_global_var(c, entry->key, value_node); | |
| 3171 | } | |
| 3172 | } | |
| 3173 | } | |
| 3174 | ||
| 3175 | static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, bool negate) { | |
| 3176 | CTok *tok = &ctok->tokens.at(*tok_i); | |
| 3177 | if (tok->id == CTokIdNumLitInt) { | |
| 3178 | *tok_i += 1; | |
| 3179 | switch (tok->data.num_lit_int.suffix) { | |
| 3180 | case CNumLitSuffixNone: | |
| 3181 | return trans_create_node_unsigned_negative(c, tok->data.num_lit_int.x, negate); | |
| 3182 | case CNumLitSuffixL: | |
| 3183 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_long"); | |
| 3184 | case CNumLitSuffixU: | |
| 3185 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_uint"); | |
| 3186 | case CNumLitSuffixLU: | |
| 3187 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_ulong"); | |
| 3188 | case CNumLitSuffixLL: | |
| 3189 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_longlong"); | |
| 3190 | case CNumLitSuffixLLU: | |
| 3191 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_ulonglong"); | |
| 3192 | } | |
| 3193 | zig_unreachable(); | |
| 3194 | } else if (tok->id == CTokIdNumLitFloat) { | |
| 3195 | *tok_i += 1; | |
| 3196 | double value = negate ? -tok->data.num_lit_float : tok->data.num_lit_float; | |
| 3197 | return trans_create_node_float_lit(c, value); | |
| 3198 | } | |
| 3199 | return nullptr; | |
| 3200 | } | |
| 3201 | ||
| 3202 | static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) { | |
| 3203 | CTok *tok = &ctok->tokens.at(*tok_i); | |
| 3204 | switch (tok->id) { | |
| 3205 | case CTokIdCharLit: | |
| 3206 | *tok_i += 1; | |
| 3207 | return trans_create_node_unsigned(c, tok->data.char_lit); | |
| 3208 | case CTokIdStrLit: | |
| 3209 | *tok_i += 1; | |
| 3210 | return trans_create_node_str_lit_c(c, buf_create_from_buf(&tok->data.str_lit)); | |
| 3211 | case CTokIdMinus: | |
| 3212 | *tok_i += 1; | |
| 3213 | return parse_ctok_num_lit(c, ctok, tok_i, true); | |
| 3214 | case CTokIdNumLitInt: | |
| 3215 | case CTokIdNumLitFloat: | |
| 3216 | return parse_ctok_num_lit(c, ctok, tok_i, false); | |
| 3217 | case CTokIdSymbol: | |
| 3218 | { | |
| 3219 | *tok_i += 1; | |
| 3220 | Buf *symbol_name = buf_create_from_buf(&tok->data.symbol); | |
| 3221 | return trans_create_node_symbol(c, symbol_name); | |
| 3222 | } | |
| 3223 | case CTokIdLParen: | |
| 3224 | { | |
| 3225 | *tok_i += 1; | |
| 3226 | AstNode *inner_node = parse_ctok(c, ctok, tok_i); | |
| 3227 | ||
| 3228 | CTok *next_tok = &ctok->tokens.at(*tok_i); | |
| 3229 | if (next_tok->id != CTokIdRParen) { | |
| 3230 | return nullptr; | |
| 3231 | } | |
| 3232 | *tok_i += 1; | |
| 3233 | return inner_node; | |
| 3234 | } | |
| 3235 | case CTokIdEOF: | |
| 3236 | case CTokIdRParen: | |
| 3237 | // not able to make sense of this | |
| 3238 | return nullptr; | |
| 3239 | } | |
| 3240 | zig_unreachable(); | |
| 3241 | } | |
| 3242 | ||
| 3243 | static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) { | |
| 3244 | tokenize_c_macro(ctok, (const uint8_t *)char_ptr); | |
| 3245 | ||
| 3246 | if (ctok->error) { | |
| 3247 | return; | |
| 3248 | } | |
| 3249 | ||
| 3250 | size_t tok_i = 0; | |
| 3251 | CTok *name_tok = &ctok->tokens.at(tok_i); | |
| 3252 | assert(name_tok->id == CTokIdSymbol && buf_eql_buf(&name_tok->data.symbol, name)); | |
| 3253 | tok_i += 1; | |
| 3254 | ||
| 3255 | AstNode *result_node = parse_ctok(c, ctok, &tok_i); | |
| 3256 | if (result_node == nullptr) { | |
| 3257 | return; | |
| 3258 | } | |
| 3259 | CTok *eof_tok = &ctok->tokens.at(tok_i); | |
| 3260 | if (eof_tok->id != CTokIdEOF) { | |
| 3261 | return; | |
| 3262 | } | |
| 3263 | if (result_node->type == NodeTypeSymbol) { | |
| 3264 | // if it equals itself, ignore. for example, from stdio.h: | |
| 3265 | // #define stdin stdin | |
| 3266 | Buf *symbol_name = result_node->data.symbol_expr.symbol; | |
| 3267 | if (buf_eql_buf(name, symbol_name)) { | |
| 3268 | return; | |
| 3269 | } | |
| 3270 | c->macro_symbols.append({name, symbol_name}); | |
| 3271 | } else { | |
| 3272 | c->macro_table.put(name, result_node); | |
| 3273 | } | |
| 3274 | } | |
| 3275 | ||
| 3276 | static void process_symbol_macros(Context *c) { | |
| 3277 | for (size_t i = 0; i < c->macro_symbols.length; i += 1) { | |
| 3278 | MacroSymbol ms = c->macro_symbols.at(i); | |
| 3279 | ||
| 3280 | // Check if this macro aliases another top level declaration | |
| 3281 | AstNode *existing_node = get_global(c, ms.value); | |
| 3282 | if (!existing_node || name_exists(c, ms.name)) | |
| 3283 | continue; | |
| 3284 | ||
| 3285 | // If a macro aliases a global variable which is a function pointer, we conclude that | |
| 3286 | // the macro is intended to represent a function that assumes the function pointer | |
| 3287 | // variable is non-null and calls it. | |
| 3288 | if (existing_node->type == NodeTypeVariableDeclaration) { | |
| 3289 | AstNode *var_type = existing_node->data.variable_declaration.type; | |
| 3290 | if (var_type != nullptr && var_type->type == NodeTypePrefixOpExpr && | |
| 3291 | var_type->data.prefix_op_expr.prefix_op == PrefixOpMaybe) | |
| 3292 | { | |
| 3293 | AstNode *fn_proto_node = var_type->data.prefix_op_expr.primary_expr; | |
| 3294 | if (fn_proto_node->type == NodeTypeFnProto) { | |
| 3295 | AstNode *inline_fn_node = trans_create_node_inline_fn(c, ms.name, ms.value, fn_proto_node); | |
| 3296 | c->macro_table.put(ms.name, inline_fn_node); | |
| 3297 | continue; | |
| 3298 | } | |
| 3299 | } | |
| 3300 | } | |
| 3301 | ||
| 3302 | add_global_var(c, ms.name, trans_create_node_symbol(c, ms.value)); | |
| 3303 | } | |
| 3304 | } | |
| 3305 | ||
| 3306 | static void process_preprocessor_entities(Context *c, ASTUnit &unit) { | |
| 3307 | CTokenize ctok = {{0}}; | |
| 3308 | ||
| 3309 | // TODO if we see #undef, delete it from the table | |
| 3310 | ||
| 3311 | for (PreprocessedEntity *entity : unit.getLocalPreprocessingEntities()) { | |
| 3312 | switch (entity->getKind()) { | |
| 3313 | case PreprocessedEntity::InvalidKind: | |
| 3314 | case PreprocessedEntity::InclusionDirectiveKind: | |
| 3315 | case PreprocessedEntity::MacroExpansionKind: | |
| 3316 | continue; | |
| 3317 | case PreprocessedEntity::MacroDefinitionKind: | |
| 3318 | { | |
| 3319 | MacroDefinitionRecord *macro = static_cast<MacroDefinitionRecord *>(entity); | |
| 3320 | const char *raw_name = macro->getName()->getNameStart(); | |
| 3321 | SourceRange range = macro->getSourceRange(); | |
| 3322 | SourceLocation begin_loc = range.getBegin(); | |
| 3323 | SourceLocation end_loc = range.getEnd(); | |
| 3324 | ||
| 3325 | if (begin_loc == end_loc) { | |
| 3326 | // this means it is a macro without a value | |
| 3327 | // we don't care about such things | |
| 3328 | continue; | |
| 3329 | } | |
| 3330 | Buf *name = buf_create_from_str(raw_name); | |
| 3331 | if (name_exists(c, name)) { | |
| 3332 | continue; | |
| 3333 | } | |
| 3334 | ||
| 3335 | const char *begin_c = c->source_manager->getCharacterData(begin_loc); | |
| 3336 | process_macro(c, &ctok, name, begin_c); | |
| 3337 | } | |
| 3338 | } | |
| 3339 | } | |
| 3340 | } | |
| 3341 | ||
| 3342 | int parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source, | |
| 3343 | CodeGen *codegen, AstNode *source_node) | |
| 3344 | { | |
| 3345 | int err; | |
| 3346 | Buf tmp_file_path = BUF_INIT; | |
| 3347 | if ((err = os_buf_to_tmp_file(source, buf_create_from_str(".h"), &tmp_file_path))) { | |
| 3348 | return err; | |
| 3349 | } | |
| 3350 | ||
| 3351 | err = parse_h_file(import, errors, buf_ptr(&tmp_file_path), codegen, source_node); | |
| 3352 | ||
| 3353 | os_delete_file(&tmp_file_path); | |
| 3354 | ||
| 3355 | return err; | |
| 3356 | } | |
| 3357 | ||
| 3358 | int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file, | |
| 3359 | CodeGen *codegen, AstNode *source_node) | |
| 3360 | { | |
| 3361 | Context context = {0}; | |
| 3362 | Context *c = &context; | |
| 3363 | c->warnings_on = codegen->verbose_cimport; | |
| 3364 | c->import = import; | |
| 3365 | c->errors = errors; | |
| 3366 | if (buf_ends_with_str(buf_create_from_str(target_file), ".h")) { | |
| 3367 | c->visib_mod = VisibModPub; | |
| 3368 | c->export_visib_mod = VisibModPub; | |
| 3369 | } else { | |
| 3370 | c->visib_mod = VisibModPub; | |
| 3371 | c->export_visib_mod = VisibModExport; | |
| 3372 | } | |
| 3373 | c->decl_table.init(8); | |
| 3374 | c->macro_table.init(8); | |
| 3375 | c->global_table.init(8); | |
| 3376 | c->ptr_params.init(8); | |
| 3377 | c->codegen = codegen; | |
| 3378 | c->source_node = source_node; | |
| 3379 | ||
| 3380 | ZigList<const char *> clang_argv = {0}; | |
| 3381 | ||
| 3382 | clang_argv.append("-x"); | |
| 3383 | clang_argv.append("c"); | |
| 3384 | ||
| 3385 | if (c->codegen->is_native_target) { | |
| 3386 | char *ZIG_PARSEC_CFLAGS = getenv("ZIG_NATIVE_PARSEC_CFLAGS"); | |
| 3387 | if (ZIG_PARSEC_CFLAGS) { | |
| 3388 | Buf tmp_buf = BUF_INIT; | |
| 3389 | char *start = ZIG_PARSEC_CFLAGS; | |
| 3390 | char *space = strstr(start, " "); | |
| 3391 | while (space) { | |
| 3392 | if (space - start > 0) { | |
| 3393 | buf_init_from_mem(&tmp_buf, start, space - start); | |
| 3394 | clang_argv.append(buf_ptr(buf_create_from_buf(&tmp_buf))); | |
| 3395 | } | |
| 3396 | start = space + 1; | |
| 3397 | space = strstr(start, " "); | |
| 3398 | } | |
| 3399 | buf_init_from_str(&tmp_buf, start); | |
| 3400 | clang_argv.append(buf_ptr(buf_create_from_buf(&tmp_buf))); | |
| 3401 | } | |
| 3402 | } | |
| 3403 | ||
| 3404 | clang_argv.append("-isystem"); | |
| 3405 | clang_argv.append(buf_ptr(codegen->zig_c_headers_dir)); | |
| 3406 | ||
| 3407 | clang_argv.append("-isystem"); | |
| 3408 | clang_argv.append(buf_ptr(codegen->libc_include_dir)); | |
| 3409 | ||
| 3410 | // windows c runtime requires -D_DEBUG if using debug libraries | |
| 3411 | if (codegen->build_mode == BuildModeDebug) { | |
| 3412 | clang_argv.append("-D_DEBUG"); | |
| 3413 | } | |
| 3414 | ||
| 3415 | for (size_t i = 0; i < codegen->clang_argv_len; i += 1) { | |
| 3416 | clang_argv.append(codegen->clang_argv[i]); | |
| 3417 | } | |
| 3418 | ||
| 3419 | // we don't need spell checking and it slows things down | |
| 3420 | clang_argv.append("-fno-spell-checking"); | |
| 3421 | ||
| 3422 | // this gives us access to preprocessing entities, presumably at | |
| 3423 | // the cost of performance | |
| 3424 | clang_argv.append("-Xclang"); | |
| 3425 | clang_argv.append("-detailed-preprocessing-record"); | |
| 3426 | ||
| 3427 | if (!c->codegen->is_native_target) { | |
| 3428 | clang_argv.append("-target"); | |
| 3429 | clang_argv.append(buf_ptr(&c->codegen->triple_str)); | |
| 3430 | } | |
| 3431 | ||
| 3432 | clang_argv.append(target_file); | |
| 3433 | ||
| 3434 | // to make the [start...end] argument work | |
| 3435 | clang_argv.append(nullptr); | |
| 3436 | ||
| 3437 | IntrusiveRefCntPtr<DiagnosticsEngine> diags(CompilerInstance::createDiagnostics(new DiagnosticOptions)); | |
| 3438 | ||
| 3439 | std::shared_ptr<PCHContainerOperations> pch_container_ops = std::make_shared<PCHContainerOperations>(); | |
| 3440 | ||
| 3441 | bool skip_function_bodies = false; | |
| 3442 | bool only_local_decls = true; | |
| 3443 | bool capture_diagnostics = true; | |
| 3444 | bool user_files_are_volatile = true; | |
| 3445 | bool allow_pch_with_compiler_errors = false; | |
| 3446 | bool single_file_parse = false; | |
| 3447 | bool for_serialization = false; | |
| 3448 | const char *resources_path = buf_ptr(codegen->zig_c_headers_dir); | |
| 3449 | std::unique_ptr<ASTUnit> err_unit; | |
| 3450 | std::unique_ptr<ASTUnit> ast_unit(ASTUnit::LoadFromCommandLine( | |
| 3451 | &clang_argv.at(0), &clang_argv.last(), | |
| 3452 | pch_container_ops, diags, resources_path, | |
| 3453 | only_local_decls, capture_diagnostics, None, true, 0, TU_Complete, | |
| 3454 | false, false, allow_pch_with_compiler_errors, skip_function_bodies, | |
| 3455 | single_file_parse, user_files_are_volatile, for_serialization, None, &err_unit, | |
| 3456 | nullptr)); | |
| 3457 | ||
| 3458 | // Early failures in LoadFromCommandLine may return with ErrUnit unset. | |
| 3459 | if (!ast_unit && !err_unit) { | |
| 3460 | return ErrorFileSystem; | |
| 3461 | } | |
| 3462 | ||
| 3463 | if (diags->getClient()->getNumErrors() > 0) { | |
| 3464 | if (ast_unit) { | |
| 3465 | err_unit = std::move(ast_unit); | |
| 3466 | } | |
| 3467 | ||
| 3468 | for (ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(), | |
| 3469 | it_end = err_unit->stored_diag_end(); | |
| 3470 | it != it_end; ++it) | |
| 3471 | { | |
| 3472 | switch (it->getLevel()) { | |
| 3473 | case DiagnosticsEngine::Ignored: | |
| 3474 | case DiagnosticsEngine::Note: | |
| 3475 | case DiagnosticsEngine::Remark: | |
| 3476 | case DiagnosticsEngine::Warning: | |
| 3477 | continue; | |
| 3478 | case DiagnosticsEngine::Error: | |
| 3479 | case DiagnosticsEngine::Fatal: | |
| 3480 | break; | |
| 3481 | } | |
| 3482 | StringRef msg_str_ref = it->getMessage(); | |
| 3483 | Buf *msg = buf_create_from_str((const char *)msg_str_ref.bytes_begin()); | |
| 3484 | FullSourceLoc fsl = it->getLocation(); | |
| 3485 | if (fsl.hasManager()) { | |
| 3486 | FileID file_id = fsl.getFileID(); | |
| 3487 | StringRef filename = fsl.getManager().getFilename(fsl); | |
| 3488 | unsigned line = fsl.getSpellingLineNumber() - 1; | |
| 3489 | unsigned column = fsl.getSpellingColumnNumber() - 1; | |
| 3490 | unsigned offset = fsl.getManager().getFileOffset(fsl); | |
| 3491 | const char *source = (const char *)fsl.getManager().getBufferData(file_id).bytes_begin(); | |
| 3492 | Buf *path; | |
| 3493 | if (filename.empty()) { | |
| 3494 | path = buf_alloc(); | |
| 3495 | } else { | |
| 3496 | path = buf_create_from_mem((const char *)filename.bytes_begin(), filename.size()); | |
| 3497 | } | |
| 3498 | ||
| 3499 | ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg); | |
| 3500 | ||
| 3501 | c->errors->append(err_msg); | |
| 3502 | } else { | |
| 3503 | // NOTE the only known way this gets triggered right now is if you have a lot of errors | |
| 3504 | // clang emits "too many errors emitted, stopping now" | |
| 3505 | fprintf(stderr, "unexpected error from clang: %s\n", buf_ptr(msg)); | |
| 3506 | } | |
| 3507 | } | |
| 3508 | ||
| 3509 | return 0; | |
| 3510 | } | |
| 3511 | ||
| 3512 | c->ctx = &ast_unit->getASTContext(); | |
| 3513 | c->source_manager = &ast_unit->getSourceManager(); | |
| 3514 | c->root = trans_create_node(c, NodeTypeRoot); | |
| 3515 | ||
| 3516 | ast_unit->visitLocalTopLevelDecls(c, decl_visitor); | |
| 3517 | ||
| 3518 | process_preprocessor_entities(c, *ast_unit); | |
| 3519 | ||
| 3520 | process_symbol_macros(c); | |
| 3521 | render_macros(c); | |
| 3522 | render_aliases(c); | |
| 3523 | ||
| 3524 | import->root = c->root; | |
| 3525 | ||
| 3526 | return 0; | |
| 3527 | } |
src/parsec.hpp deleted-20| ... | ... | @@ -1,20 +0,0 @@ |
| 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_PARSEC_HPP | |
| 10 | #define ZIG_PARSEC_HPP | |
| 11 | ||
| 12 | #include "all_types.hpp" | |
| 13 | ||
| 14 | int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file, | |
| 15 | CodeGen *codegen, AstNode *source_node); | |
| 16 | ||
| 17 | int parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source, | |
| 18 | CodeGen *codegen, AstNode *source_node); | |
| 19 | ||
| 20 | #endif |
src/translate_c.cpp created+3527| ... | ... | @@ -0,0 +1,3527 @@ |
| 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 | #include "all_types.hpp" | |
| 9 | #include "analyze.hpp" | |
| 10 | #include "c_tokenizer.hpp" | |
| 11 | #include "error.hpp" | |
| 12 | #include "ir.hpp" | |
| 13 | #include "os.hpp" | |
| 14 | #include "translate_c.hpp" | |
| 15 | #include "parser.hpp" | |
| 16 | ||
| 17 | ||
| 18 | #include <clang/Frontend/ASTUnit.h> | |
| 19 | #include <clang/Frontend/CompilerInstance.h> | |
| 20 | #include <clang/AST/Expr.h> | |
| 21 | ||
| 22 | #include <string.h> | |
| 23 | ||
| 24 | using namespace clang; | |
| 25 | ||
| 26 | struct MacroSymbol { | |
| 27 | Buf *name; | |
| 28 | Buf *value; | |
| 29 | }; | |
| 30 | ||
| 31 | struct Alias { | |
| 32 | Buf *new_name; | |
| 33 | Buf *canon_name; | |
| 34 | }; | |
| 35 | ||
| 36 | struct Context { | |
| 37 | ImportTableEntry *import; | |
| 38 | ZigList<ErrorMsg *> *errors; | |
| 39 | VisibMod visib_mod; | |
| 40 | VisibMod export_visib_mod; | |
| 41 | AstNode *root; | |
| 42 | HashMap<const void *, AstNode *, ptr_hash, ptr_eq> decl_table; | |
| 43 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> macro_table; | |
| 44 | HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> global_table; | |
| 45 | SourceManager *source_manager; | |
| 46 | ZigList<Alias> aliases; | |
| 47 | ZigList<MacroSymbol> macro_symbols; | |
| 48 | AstNode *source_node; | |
| 49 | bool warnings_on; | |
| 50 | ||
| 51 | CodeGen *codegen; | |
| 52 | ASTContext *ctx; | |
| 53 | ||
| 54 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> ptr_params; | |
| 55 | }; | |
| 56 | ||
| 57 | static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl); | |
| 58 | static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl); | |
| 59 | static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl); | |
| 60 | ||
| 61 | ||
| 62 | ATTRIBUTE_PRINTF(3, 4) | |
| 63 | static void emit_warning(Context *c, const SourceLocation &sl, const char *format, ...) { | |
| 64 | if (!c->warnings_on) { | |
| 65 | return; | |
| 66 | } | |
| 67 | ||
| 68 | va_list ap; | |
| 69 | va_start(ap, format); | |
| 70 | Buf *msg = buf_vprintf(format, ap); | |
| 71 | va_end(ap); | |
| 72 | ||
| 73 | StringRef filename = c->source_manager->getFilename(sl); | |
| 74 | const char *filename_bytes = (const char *)filename.bytes_begin(); | |
| 75 | Buf *path; | |
| 76 | if (filename_bytes) { | |
| 77 | path = buf_create_from_str(filename_bytes); | |
| 78 | } else { | |
| 79 | path = buf_sprintf("(no file)"); | |
| 80 | } | |
| 81 | unsigned line = c->source_manager->getSpellingLineNumber(sl); | |
| 82 | unsigned column = c->source_manager->getSpellingColumnNumber(sl); | |
| 83 | fprintf(stderr, "%s:%u:%u: warning: %s\n", buf_ptr(path), line, column, buf_ptr(msg)); | |
| 84 | } | |
| 85 | ||
| 86 | static void add_global_weak_alias(Context *c, Buf *new_name, Buf *canon_name) { | |
| 87 | Alias *alias = c->aliases.add_one(); | |
| 88 | alias->new_name = new_name; | |
| 89 | alias->canon_name = canon_name; | |
| 90 | } | |
| 91 | ||
| 92 | static AstNode * trans_create_node(Context *c, NodeType id) { | |
| 93 | AstNode *node = allocate<AstNode>(1); | |
| 94 | node->type = id; | |
| 95 | node->owner = c->import; | |
| 96 | // TODO line/column. mapping to C file?? | |
| 97 | return node; | |
| 98 | } | |
| 99 | ||
| 100 | static AstNode *trans_create_node_float_lit(Context *c, double value) { | |
| 101 | AstNode *node = trans_create_node(c, NodeTypeFloatLiteral); | |
| 102 | node->data.float_literal.bigfloat = allocate<BigFloat>(1); | |
| 103 | bigfloat_init_64(node->data.float_literal.bigfloat, value); | |
| 104 | return node; | |
| 105 | } | |
| 106 | ||
| 107 | static AstNode *trans_create_node_symbol(Context *c, Buf *name) { | |
| 108 | AstNode *node = trans_create_node(c, NodeTypeSymbol); | |
| 109 | node->data.symbol_expr.symbol = name; | |
| 110 | return node; | |
| 111 | } | |
| 112 | ||
| 113 | static AstNode *trans_create_node_symbol_str(Context *c, const char *name) { | |
| 114 | return trans_create_node_symbol(c, buf_create_from_str(name)); | |
| 115 | } | |
| 116 | ||
| 117 | static AstNode *trans_create_node_builtin_fn_call(Context *c, Buf *name) { | |
| 118 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 119 | node->data.fn_call_expr.fn_ref_expr = trans_create_node_symbol(c, name); | |
| 120 | node->data.fn_call_expr.is_builtin = true; | |
| 121 | return node; | |
| 122 | } | |
| 123 | ||
| 124 | static AstNode *trans_create_node_builtin_fn_call_str(Context *c, const char *name) { | |
| 125 | return trans_create_node_builtin_fn_call(c, buf_create_from_str(name)); | |
| 126 | } | |
| 127 | ||
| 128 | static AstNode *trans_create_node_opaque(Context *c) { | |
| 129 | return trans_create_node_builtin_fn_call_str(c, "OpaqueType"); | |
| 130 | } | |
| 131 | ||
| 132 | static AstNode *trans_create_node_fn_call_1(Context *c, AstNode *fn_ref_expr, AstNode *arg1) { | |
| 133 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 134 | node->data.fn_call_expr.fn_ref_expr = fn_ref_expr; | |
| 135 | node->data.fn_call_expr.params.append(arg1); | |
| 136 | return node; | |
| 137 | } | |
| 138 | ||
| 139 | static AstNode *trans_create_node_field_access(Context *c, AstNode *container, Buf *field_name) { | |
| 140 | AstNode *node = trans_create_node(c, NodeTypeFieldAccessExpr); | |
| 141 | if (container->type == NodeTypeSymbol) { | |
| 142 | assert(container->data.symbol_expr.symbol != nullptr); | |
| 143 | } | |
| 144 | node->data.field_access_expr.struct_expr = container; | |
| 145 | node->data.field_access_expr.field_name = field_name; | |
| 146 | return node; | |
| 147 | } | |
| 148 | ||
| 149 | static AstNode *trans_create_node_field_access_str(Context *c, AstNode *container, const char *field_name) { | |
| 150 | return trans_create_node_field_access(c, container, buf_create_from_str(field_name)); | |
| 151 | } | |
| 152 | ||
| 153 | static AstNode *trans_create_node_prefix_op(Context *c, PrefixOp op, AstNode *child_node) { | |
| 154 | AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); | |
| 155 | node->data.prefix_op_expr.prefix_op = op; | |
| 156 | node->data.prefix_op_expr.primary_expr = child_node; | |
| 157 | return node; | |
| 158 | } | |
| 159 | ||
| 160 | static AstNode *trans_create_node_bin_op(Context *c, AstNode *lhs_node, BinOpType op, AstNode *rhs_node) { | |
| 161 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 162 | node->data.bin_op_expr.op1 = lhs_node; | |
| 163 | node->data.bin_op_expr.bin_op = op; | |
| 164 | node->data.bin_op_expr.op2 = rhs_node; | |
| 165 | return node; | |
| 166 | } | |
| 167 | ||
| 168 | static AstNode *maybe_suppress_result(Context *c, bool result_used, AstNode *node) { | |
| 169 | if (result_used) return node; | |
| 170 | return trans_create_node_bin_op(c, | |
| 171 | trans_create_node_symbol_str(c, "_"), | |
| 172 | BinOpTypeAssign, | |
| 173 | node); | |
| 174 | } | |
| 175 | ||
| 176 | static AstNode *trans_create_node_addr_of(Context *c, bool is_const, bool is_volatile, AstNode *child_node) { | |
| 177 | AstNode *node = trans_create_node(c, NodeTypeAddrOfExpr); | |
| 178 | node->data.addr_of_expr.is_const = is_const; | |
| 179 | node->data.addr_of_expr.is_volatile = is_volatile; | |
| 180 | node->data.addr_of_expr.op_expr = child_node; | |
| 181 | return node; | |
| 182 | } | |
| 183 | ||
| 184 | static AstNode *trans_create_node_str_lit_c(Context *c, Buf *buf) { | |
| 185 | AstNode *node = trans_create_node(c, NodeTypeStringLiteral); | |
| 186 | node->data.string_literal.buf = buf; | |
| 187 | node->data.string_literal.c = true; | |
| 188 | return node; | |
| 189 | } | |
| 190 | ||
| 191 | static AstNode *trans_create_node_str_lit_non_c(Context *c, Buf *buf) { | |
| 192 | AstNode *node = trans_create_node(c, NodeTypeStringLiteral); | |
| 193 | node->data.string_literal.buf = buf; | |
| 194 | node->data.string_literal.c = false; | |
| 195 | return node; | |
| 196 | } | |
| 197 | ||
| 198 | static AstNode *trans_create_node_unsigned_negative(Context *c, uint64_t x, bool is_negative) { | |
| 199 | AstNode *node = trans_create_node(c, NodeTypeIntLiteral); | |
| 200 | node->data.int_literal.bigint = allocate<BigInt>(1); | |
| 201 | bigint_init_data(node->data.int_literal.bigint, &x, 1, is_negative); | |
| 202 | return node; | |
| 203 | } | |
| 204 | ||
| 205 | static AstNode *trans_create_node_unsigned(Context *c, uint64_t x) { | |
| 206 | return trans_create_node_unsigned_negative(c, x, false); | |
| 207 | } | |
| 208 | ||
| 209 | static AstNode *trans_create_node_cast(Context *c, AstNode *dest, AstNode *src) { | |
| 210 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 211 | node->data.fn_call_expr.fn_ref_expr = dest; | |
| 212 | node->data.fn_call_expr.params.resize(1); | |
| 213 | node->data.fn_call_expr.params.items[0] = src; | |
| 214 | return node; | |
| 215 | } | |
| 216 | ||
| 217 | static AstNode *trans_create_node_unsigned_negative_type(Context *c, uint64_t x, bool is_negative, | |
| 218 | const char *type_name) | |
| 219 | { | |
| 220 | AstNode *lit_node = trans_create_node_unsigned_negative(c, x, is_negative); | |
| 221 | return trans_create_node_cast(c, trans_create_node_symbol_str(c, type_name), lit_node); | |
| 222 | } | |
| 223 | ||
| 224 | static AstNode *trans_create_node_array_type(Context *c, AstNode *size_node, AstNode *child_type_node) { | |
| 225 | AstNode *node = trans_create_node(c, NodeTypeArrayType); | |
| 226 | node->data.array_type.size = size_node; | |
| 227 | node->data.array_type.child_type = child_type_node; | |
| 228 | return node; | |
| 229 | } | |
| 230 | ||
| 231 | static AstNode *trans_create_node_var_decl(Context *c, VisibMod visib_mod, bool is_const, Buf *var_name, | |
| 232 | AstNode *type_node, AstNode *init_node) | |
| 233 | { | |
| 234 | AstNode *node = trans_create_node(c, NodeTypeVariableDeclaration); | |
| 235 | node->data.variable_declaration.visib_mod = visib_mod; | |
| 236 | node->data.variable_declaration.symbol = var_name; | |
| 237 | node->data.variable_declaration.is_const = is_const; | |
| 238 | node->data.variable_declaration.type = type_node; | |
| 239 | node->data.variable_declaration.expr = init_node; | |
| 240 | return node; | |
| 241 | } | |
| 242 | ||
| 243 | static AstNode *trans_create_node_var_decl_global(Context *c, bool is_const, Buf *var_name, AstNode *type_node, | |
| 244 | AstNode *init_node) | |
| 245 | { | |
| 246 | return trans_create_node_var_decl(c, c->visib_mod, is_const, var_name, type_node, init_node); | |
| 247 | } | |
| 248 | ||
| 249 | static AstNode *trans_create_node_var_decl_local(Context *c, bool is_const, Buf *var_name, AstNode *type_node, | |
| 250 | AstNode *init_node) | |
| 251 | { | |
| 252 | return trans_create_node_var_decl(c, VisibModPrivate, is_const, var_name, type_node, init_node); | |
| 253 | } | |
| 254 | ||
| 255 | ||
| 256 | static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, Buf *var_name, AstNode *src_proto_node) { | |
| 257 | AstNode *fn_def = trans_create_node(c, NodeTypeFnDef); | |
| 258 | AstNode *fn_proto = trans_create_node(c, NodeTypeFnProto); | |
| 259 | fn_proto->data.fn_proto.visib_mod = c->visib_mod; | |
| 260 | fn_proto->data.fn_proto.name = fn_name; | |
| 261 | fn_proto->data.fn_proto.is_inline = true; | |
| 262 | fn_proto->data.fn_proto.return_type = src_proto_node->data.fn_proto.return_type; // TODO ok for these to alias? | |
| 263 | ||
| 264 | fn_def->data.fn_def.fn_proto = fn_proto; | |
| 265 | fn_proto->data.fn_proto.fn_def_node = fn_def; | |
| 266 | ||
| 267 | AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, trans_create_node_symbol(c, var_name)); | |
| 268 | AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 269 | fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node; | |
| 270 | ||
| 271 | for (size_t i = 0; i < src_proto_node->data.fn_proto.params.length; i += 1) { | |
| 272 | AstNode *src_param_node = src_proto_node->data.fn_proto.params.at(i); | |
| 273 | Buf *param_name = src_param_node->data.param_decl.name; | |
| 274 | if (!param_name) param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i); | |
| 275 | ||
| 276 | AstNode *dest_param_node = trans_create_node(c, NodeTypeParamDecl); | |
| 277 | dest_param_node->data.param_decl.name = param_name; | |
| 278 | dest_param_node->data.param_decl.type = src_param_node->data.param_decl.type; | |
| 279 | dest_param_node->data.param_decl.is_noalias = src_param_node->data.param_decl.is_noalias; | |
| 280 | fn_proto->data.fn_proto.params.append(dest_param_node); | |
| 281 | ||
| 282 | fn_call_node->data.fn_call_expr.params.append(trans_create_node_symbol(c, param_name)); | |
| 283 | ||
| 284 | } | |
| 285 | ||
| 286 | AstNode *block = trans_create_node(c, NodeTypeBlock); | |
| 287 | block->data.block.statements.resize(1); | |
| 288 | block->data.block.statements.items[0] = fn_call_node; | |
| 289 | block->data.block.last_statement_is_result_expression = true; | |
| 290 | ||
| 291 | fn_def->data.fn_def.body = block; | |
| 292 | return fn_def; | |
| 293 | } | |
| 294 | ||
| 295 | static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child) { | |
| 296 | return trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, child); | |
| 297 | } | |
| 298 | ||
| 299 | static AstNode *get_global(Context *c, Buf *name) { | |
| 300 | { | |
| 301 | auto entry = c->global_table.maybe_get(name); | |
| 302 | if (entry) { | |
| 303 | return entry->value; | |
| 304 | } | |
| 305 | } | |
| 306 | { | |
| 307 | auto entry = c->macro_table.maybe_get(name); | |
| 308 | if (entry) | |
| 309 | return entry->value; | |
| 310 | } | |
| 311 | return nullptr; | |
| 312 | } | |
| 313 | ||
| 314 | static void add_top_level_decl(Context *c, Buf *name, AstNode *node) { | |
| 315 | c->global_table.put(name, node); | |
| 316 | c->root->data.root.top_level_decls.append(node); | |
| 317 | } | |
| 318 | ||
| 319 | static AstNode *add_global_var(Context *c, Buf *var_name, AstNode *value_node) { | |
| 320 | bool is_const = true; | |
| 321 | AstNode *type_node = nullptr; | |
| 322 | AstNode *node = trans_create_node_var_decl_global(c, is_const, var_name, type_node, value_node); | |
| 323 | add_top_level_decl(c, var_name, node); | |
| 324 | return node; | |
| 325 | } | |
| 326 | ||
| 327 | static const char *decl_name(const Decl *decl) { | |
| 328 | const NamedDecl *named_decl = static_cast<const NamedDecl *>(decl); | |
| 329 | return (const char *)named_decl->getName().bytes_begin(); | |
| 330 | } | |
| 331 | ||
| 332 | static AstNode *trans_create_node_apint(Context *c, const llvm::APSInt &aps_int) { | |
| 333 | AstNode *node = trans_create_node(c, NodeTypeIntLiteral); | |
| 334 | node->data.int_literal.bigint = allocate<BigInt>(1); | |
| 335 | bigint_init_data(node->data.int_literal.bigint, aps_int.getRawData(), aps_int.getNumWords(), aps_int.isNegative()); | |
| 336 | return node; | |
| 337 | ||
| 338 | } | |
| 339 | ||
| 340 | static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc); | |
| 341 | ||
| 342 | static bool is_c_void_type(AstNode *node) { | |
| 343 | return (node->type == NodeTypeSymbol && buf_eql_str(node->data.symbol_expr.symbol, "c_void")); | |
| 344 | } | |
| 345 | ||
| 346 | static AstNode* trans_c_cast(Context *c, const SourceLocation &source_location, const QualType &qt, AstNode *expr) { | |
| 347 | // TODO: maybe widen to increase size | |
| 348 | // TODO: maybe bitcast to change sign | |
| 349 | // TODO: maybe truncate to reduce size | |
| 350 | return trans_create_node_fn_call_1(c, trans_qual_type(c, qt, source_location), expr); | |
| 351 | } | |
| 352 | ||
| 353 | static bool qual_type_is_fn_ptr(Context *c, const QualType &qt) { | |
| 354 | const Type *ty = qt.getTypePtr(); | |
| 355 | if (ty->getTypeClass() != Type::Pointer) { | |
| 356 | return false; | |
| 357 | } | |
| 358 | const PointerType *pointer_ty = static_cast<const PointerType*>(ty); | |
| 359 | QualType child_qt = pointer_ty->getPointeeType(); | |
| 360 | const Type *child_ty = child_qt.getTypePtr(); | |
| 361 | if (child_ty->getTypeClass() != Type::Paren) { | |
| 362 | return false; | |
| 363 | } | |
| 364 | const ParenType *paren_ty = static_cast<const ParenType *>(child_ty); | |
| 365 | return paren_ty->getInnerType().getTypePtr()->getTypeClass() == Type::FunctionProto; | |
| 366 | } | |
| 367 | ||
| 368 | static uint32_t qual_type_int_bit_width(Context *c, const QualType &qt, const SourceLocation &source_loc) { | |
| 369 | const Type *ty = qt.getTypePtr(); | |
| 370 | switch (ty->getTypeClass()) { | |
| 371 | case Type::Builtin: | |
| 372 | { | |
| 373 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty); | |
| 374 | switch (builtin_ty->getKind()) { | |
| 375 | case BuiltinType::Char_U: | |
| 376 | case BuiltinType::UChar: | |
| 377 | case BuiltinType::Char_S: | |
| 378 | case BuiltinType::SChar: | |
| 379 | return 8; | |
| 380 | case BuiltinType::UInt128: | |
| 381 | case BuiltinType::Int128: | |
| 382 | return 128; | |
| 383 | default: | |
| 384 | return 0; | |
| 385 | } | |
| 386 | zig_unreachable(); | |
| 387 | } | |
| 388 | case Type::Typedef: | |
| 389 | { | |
| 390 | const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); | |
| 391 | const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); | |
| 392 | const char *type_name = decl_name(typedef_decl); | |
| 393 | if (strcmp(type_name, "uint8_t") == 0 || strcmp(type_name, "int8_t") == 0) { | |
| 394 | return 8; | |
| 395 | } else if (strcmp(type_name, "uint16_t") == 0 || strcmp(type_name, "int16_t") == 0) { | |
| 396 | return 16; | |
| 397 | } else if (strcmp(type_name, "uint32_t") == 0 || strcmp(type_name, "int32_t") == 0) { | |
| 398 | return 32; | |
| 399 | } else if (strcmp(type_name, "uint64_t") == 0 || strcmp(type_name, "int64_t") == 0) { | |
| 400 | return 64; | |
| 401 | } else { | |
| 402 | return 0; | |
| 403 | } | |
| 404 | } | |
| 405 | default: | |
| 406 | return 0; | |
| 407 | } | |
| 408 | zig_unreachable(); | |
| 409 | } | |
| 410 | ||
| 411 | ||
| 412 | static AstNode *qual_type_to_log2_int_ref(Context *c, const QualType &qt, | |
| 413 | const SourceLocation &source_loc) | |
| 414 | { | |
| 415 | uint32_t int_bit_width = qual_type_int_bit_width(c, qt, source_loc); | |
| 416 | if (int_bit_width != 0) { | |
| 417 | // we can perform the log2 now. | |
| 418 | uint64_t cast_bit_width = log2_u64(int_bit_width); | |
| 419 | return trans_create_node_symbol(c, buf_sprintf("u%" ZIG_PRI_u64, cast_bit_width)); | |
| 420 | } | |
| 421 | ||
| 422 | AstNode *zig_type_node = trans_qual_type(c, qt, source_loc); | |
| 423 | ||
| 424 | // @import("std").math.Log2Int(c_long); | |
| 425 | // | |
| 426 | // FnCall | |
| 427 | // FieldAccess | |
| 428 | // FieldAccess | |
| 429 | // FnCall (.builtin = true) | |
| 430 | // Symbol "import" | |
| 431 | // StringLiteral "std" | |
| 432 | // Symbol "math" | |
| 433 | // Symbol "Log2Int" | |
| 434 | // zig_type_node | |
| 435 | ||
| 436 | AstNode *import_fn_call = trans_create_node_builtin_fn_call_str(c, "import"); | |
| 437 | import_fn_call->data.fn_call_expr.params.append(trans_create_node_str_lit_non_c(c, buf_create_from_str("std"))); | |
| 438 | AstNode *inner_field_access = trans_create_node_field_access_str(c, import_fn_call, "math"); | |
| 439 | AstNode *outer_field_access = trans_create_node_field_access_str(c, inner_field_access, "Log2Int"); | |
| 440 | AstNode *log2int_fn_call = trans_create_node_fn_call_1(c, outer_field_access, zig_type_node); | |
| 441 | ||
| 442 | return log2int_fn_call; | |
| 443 | } | |
| 444 | ||
| 445 | static bool qual_type_child_is_fn_proto(const QualType &qt) { | |
| 446 | if (qt.getTypePtr()->getTypeClass() == Type::Paren) { | |
| 447 | const ParenType *paren_type = static_cast<const ParenType *>(qt.getTypePtr()); | |
| 448 | if (paren_type->getInnerType()->getTypeClass() == Type::FunctionProto) { | |
| 449 | return true; | |
| 450 | } | |
| 451 | } else if (qt.getTypePtr()->getTypeClass() == Type::Attributed) { | |
| 452 | const AttributedType *attr_type = static_cast<const AttributedType *>(qt.getTypePtr()); | |
| 453 | return qual_type_child_is_fn_proto(attr_type->getEquivalentType()); | |
| 454 | } | |
| 455 | return false; | |
| 456 | } | |
| 457 | ||
| 458 | static QualType resolve_any_typedef(Context *c, QualType qt) { | |
| 459 | const Type * ty = qt.getTypePtr(); | |
| 460 | if (ty->getTypeClass() != Type::Typedef) | |
| 461 | return qt; | |
| 462 | const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); | |
| 463 | const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); | |
| 464 | return typedef_decl->getUnderlyingType(); | |
| 465 | } | |
| 466 | ||
| 467 | static bool c_is_signed_integer(Context *c, QualType qt) { | |
| 468 | const Type *c_type = resolve_any_typedef(c, qt).getTypePtr(); | |
| 469 | if (c_type->getTypeClass() != Type::Builtin) | |
| 470 | return false; | |
| 471 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | |
| 472 | switch (builtin_ty->getKind()) { | |
| 473 | case BuiltinType::SChar: | |
| 474 | case BuiltinType::Short: | |
| 475 | case BuiltinType::Int: | |
| 476 | case BuiltinType::Long: | |
| 477 | case BuiltinType::LongLong: | |
| 478 | case BuiltinType::Int128: | |
| 479 | case BuiltinType::WChar_S: | |
| 480 | return true; | |
| 481 | default: | |
| 482 | return false; | |
| 483 | } | |
| 484 | } | |
| 485 | ||
| 486 | static bool c_is_unsigned_integer(Context *c, QualType qt) { | |
| 487 | const Type *c_type = resolve_any_typedef(c, qt).getTypePtr(); | |
| 488 | if (c_type->getTypeClass() != Type::Builtin) | |
| 489 | return false; | |
| 490 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | |
| 491 | switch (builtin_ty->getKind()) { | |
| 492 | case BuiltinType::Char_U: | |
| 493 | case BuiltinType::UChar: | |
| 494 | case BuiltinType::Char_S: | |
| 495 | case BuiltinType::UShort: | |
| 496 | case BuiltinType::UInt: | |
| 497 | case BuiltinType::ULong: | |
| 498 | case BuiltinType::ULongLong: | |
| 499 | case BuiltinType::UInt128: | |
| 500 | case BuiltinType::WChar_U: | |
| 501 | return true; | |
| 502 | default: | |
| 503 | return false; | |
| 504 | } | |
| 505 | } | |
| 506 | ||
| 507 | static bool c_is_float(Context *c, QualType qt) { | |
| 508 | const Type *c_type = qt.getTypePtr(); | |
| 509 | if (c_type->getTypeClass() != Type::Builtin) | |
| 510 | return false; | |
| 511 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(c_type); | |
| 512 | switch (builtin_ty->getKind()) { | |
| 513 | case BuiltinType::Half: | |
| 514 | case BuiltinType::Float: | |
| 515 | case BuiltinType::Double: | |
| 516 | case BuiltinType::Float128: | |
| 517 | case BuiltinType::LongDouble: | |
| 518 | return true; | |
| 519 | default: | |
| 520 | return false; | |
| 521 | } | |
| 522 | } | |
| 523 | ||
| 524 | static bool qual_type_has_wrapping_overflow(Context *c, QualType qt) { | |
| 525 | if (c_is_signed_integer(c, qt) || c_is_float(c, qt)) { | |
| 526 | // float and signed integer overflow is undefined behavior. | |
| 527 | return false; | |
| 528 | } else { | |
| 529 | // unsigned integer overflow wraps around. | |
| 530 | return true; | |
| 531 | } | |
| 532 | } | |
| 533 | ||
| 534 | enum TransLRValue { | |
| 535 | TransLValue, | |
| 536 | TransRValue, | |
| 537 | }; | |
| 538 | ||
| 539 | static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrval); | |
| 540 | static AstNode *const skip_add_to_block_node = (AstNode *) 0x2; | |
| 541 | ||
| 542 | static AstNode *trans_expr(Context *c, bool result_used, AstNode *block, Expr *expr, TransLRValue lrval) { | |
| 543 | return trans_stmt(c, result_used, block, expr, lrval); | |
| 544 | } | |
| 545 | ||
| 546 | static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &source_loc) { | |
| 547 | switch (ty->getTypeClass()) { | |
| 548 | case Type::Builtin: | |
| 549 | { | |
| 550 | const BuiltinType *builtin_ty = static_cast<const BuiltinType*>(ty); | |
| 551 | switch (builtin_ty->getKind()) { | |
| 552 | case BuiltinType::Void: | |
| 553 | return trans_create_node_symbol_str(c, "c_void"); | |
| 554 | case BuiltinType::Bool: | |
| 555 | return trans_create_node_symbol_str(c, "bool"); | |
| 556 | case BuiltinType::Char_U: | |
| 557 | case BuiltinType::UChar: | |
| 558 | case BuiltinType::Char_S: | |
| 559 | return trans_create_node_symbol_str(c, "u8"); | |
| 560 | case BuiltinType::SChar: | |
| 561 | return trans_create_node_symbol_str(c, "i8"); | |
| 562 | case BuiltinType::UShort: | |
| 563 | return trans_create_node_symbol_str(c, "c_ushort"); | |
| 564 | case BuiltinType::UInt: | |
| 565 | return trans_create_node_symbol_str(c, "c_uint"); | |
| 566 | case BuiltinType::ULong: | |
| 567 | return trans_create_node_symbol_str(c, "c_ulong"); | |
| 568 | case BuiltinType::ULongLong: | |
| 569 | return trans_create_node_symbol_str(c, "c_ulonglong"); | |
| 570 | case BuiltinType::Short: | |
| 571 | return trans_create_node_symbol_str(c, "c_short"); | |
| 572 | case BuiltinType::Int: | |
| 573 | return trans_create_node_symbol_str(c, "c_int"); | |
| 574 | case BuiltinType::Long: | |
| 575 | return trans_create_node_symbol_str(c, "c_long"); | |
| 576 | case BuiltinType::LongLong: | |
| 577 | return trans_create_node_symbol_str(c, "c_longlong"); | |
| 578 | case BuiltinType::UInt128: | |
| 579 | return trans_create_node_symbol_str(c, "u128"); | |
| 580 | case BuiltinType::Int128: | |
| 581 | return trans_create_node_symbol_str(c, "i128"); | |
| 582 | case BuiltinType::Float: | |
| 583 | return trans_create_node_symbol_str(c, "f32"); | |
| 584 | case BuiltinType::Double: | |
| 585 | return trans_create_node_symbol_str(c, "f64"); | |
| 586 | case BuiltinType::Float128: | |
| 587 | return trans_create_node_symbol_str(c, "f128"); | |
| 588 | case BuiltinType::LongDouble: | |
| 589 | return trans_create_node_symbol_str(c, "c_longdouble"); | |
| 590 | case BuiltinType::WChar_U: | |
| 591 | case BuiltinType::Char16: | |
| 592 | case BuiltinType::Char32: | |
| 593 | case BuiltinType::WChar_S: | |
| 594 | case BuiltinType::Half: | |
| 595 | case BuiltinType::NullPtr: | |
| 596 | case BuiltinType::ObjCId: | |
| 597 | case BuiltinType::ObjCClass: | |
| 598 | case BuiltinType::ObjCSel: | |
| 599 | case BuiltinType::OMPArraySection: | |
| 600 | case BuiltinType::Dependent: | |
| 601 | case BuiltinType::Overload: | |
| 602 | case BuiltinType::BoundMember: | |
| 603 | case BuiltinType::PseudoObject: | |
| 604 | case BuiltinType::UnknownAny: | |
| 605 | case BuiltinType::BuiltinFn: | |
| 606 | case BuiltinType::ARCUnbridgedCast: | |
| 607 | ||
| 608 | case BuiltinType::OCLImage1dRO: | |
| 609 | case BuiltinType::OCLImage1dArrayRO: | |
| 610 | case BuiltinType::OCLImage1dBufferRO: | |
| 611 | case BuiltinType::OCLImage2dRO: | |
| 612 | case BuiltinType::OCLImage2dArrayRO: | |
| 613 | case BuiltinType::OCLImage2dDepthRO: | |
| 614 | case BuiltinType::OCLImage2dArrayDepthRO: | |
| 615 | case BuiltinType::OCLImage2dMSAARO: | |
| 616 | case BuiltinType::OCLImage2dArrayMSAARO: | |
| 617 | case BuiltinType::OCLImage2dMSAADepthRO: | |
| 618 | case BuiltinType::OCLImage2dArrayMSAADepthRO: | |
| 619 | case BuiltinType::OCLImage3dRO: | |
| 620 | case BuiltinType::OCLImage1dWO: | |
| 621 | case BuiltinType::OCLImage1dArrayWO: | |
| 622 | case BuiltinType::OCLImage1dBufferWO: | |
| 623 | case BuiltinType::OCLImage2dWO: | |
| 624 | case BuiltinType::OCLImage2dArrayWO: | |
| 625 | case BuiltinType::OCLImage2dDepthWO: | |
| 626 | case BuiltinType::OCLImage2dArrayDepthWO: | |
| 627 | case BuiltinType::OCLImage2dMSAAWO: | |
| 628 | case BuiltinType::OCLImage2dArrayMSAAWO: | |
| 629 | case BuiltinType::OCLImage2dMSAADepthWO: | |
| 630 | case BuiltinType::OCLImage2dArrayMSAADepthWO: | |
| 631 | case BuiltinType::OCLImage3dWO: | |
| 632 | case BuiltinType::OCLImage1dRW: | |
| 633 | case BuiltinType::OCLImage1dArrayRW: | |
| 634 | case BuiltinType::OCLImage1dBufferRW: | |
| 635 | case BuiltinType::OCLImage2dRW: | |
| 636 | case BuiltinType::OCLImage2dArrayRW: | |
| 637 | case BuiltinType::OCLImage2dDepthRW: | |
| 638 | case BuiltinType::OCLImage2dArrayDepthRW: | |
| 639 | case BuiltinType::OCLImage2dMSAARW: | |
| 640 | case BuiltinType::OCLImage2dArrayMSAARW: | |
| 641 | case BuiltinType::OCLImage2dMSAADepthRW: | |
| 642 | case BuiltinType::OCLImage2dArrayMSAADepthRW: | |
| 643 | case BuiltinType::OCLImage3dRW: | |
| 644 | case BuiltinType::OCLSampler: | |
| 645 | case BuiltinType::OCLEvent: | |
| 646 | case BuiltinType::OCLClkEvent: | |
| 647 | case BuiltinType::OCLQueue: | |
| 648 | case BuiltinType::OCLReserveID: | |
| 649 | emit_warning(c, source_loc, "unsupported builtin type"); | |
| 650 | return nullptr; | |
| 651 | } | |
| 652 | break; | |
| 653 | } | |
| 654 | case Type::Pointer: | |
| 655 | { | |
| 656 | const PointerType *pointer_ty = static_cast<const PointerType*>(ty); | |
| 657 | QualType child_qt = pointer_ty->getPointeeType(); | |
| 658 | AstNode *child_node = trans_qual_type(c, child_qt, source_loc); | |
| 659 | if (child_node == nullptr) { | |
| 660 | emit_warning(c, source_loc, "pointer to unsupported type"); | |
| 661 | return nullptr; | |
| 662 | } | |
| 663 | ||
| 664 | if (qual_type_child_is_fn_proto(child_qt)) { | |
| 665 | return trans_create_node_prefix_op(c, PrefixOpMaybe, child_node); | |
| 666 | } | |
| 667 | ||
| 668 | AstNode *pointer_node = trans_create_node_addr_of(c, child_qt.isConstQualified(), | |
| 669 | child_qt.isVolatileQualified(), child_node); | |
| 670 | return trans_create_node_prefix_op(c, PrefixOpMaybe, pointer_node); | |
| 671 | } | |
| 672 | case Type::Typedef: | |
| 673 | { | |
| 674 | const TypedefType *typedef_ty = static_cast<const TypedefType*>(ty); | |
| 675 | const TypedefNameDecl *typedef_decl = typedef_ty->getDecl(); | |
| 676 | return resolve_typedef_decl(c, typedef_decl); | |
| 677 | } | |
| 678 | case Type::Elaborated: | |
| 679 | { | |
| 680 | const ElaboratedType *elaborated_ty = static_cast<const ElaboratedType*>(ty); | |
| 681 | switch (elaborated_ty->getKeyword()) { | |
| 682 | case ETK_Struct: | |
| 683 | case ETK_Enum: | |
| 684 | case ETK_Union: | |
| 685 | return trans_qual_type(c, elaborated_ty->getNamedType(), source_loc); | |
| 686 | case ETK_Interface: | |
| 687 | case ETK_Class: | |
| 688 | case ETK_Typename: | |
| 689 | case ETK_None: | |
| 690 | emit_warning(c, source_loc, "unsupported elaborated type"); | |
| 691 | return nullptr; | |
| 692 | } | |
| 693 | } | |
| 694 | case Type::FunctionProto: | |
| 695 | { | |
| 696 | const FunctionProtoType *fn_proto_ty = static_cast<const FunctionProtoType*>(ty); | |
| 697 | ||
| 698 | AstNode *proto_node = trans_create_node(c, NodeTypeFnProto); | |
| 699 | switch (fn_proto_ty->getCallConv()) { | |
| 700 | case CC_C: // __attribute__((cdecl)) | |
| 701 | proto_node->data.fn_proto.cc = CallingConventionC; | |
| 702 | proto_node->data.fn_proto.is_extern = true; | |
| 703 | break; | |
| 704 | case CC_X86StdCall: // __attribute__((stdcall)) | |
| 705 | proto_node->data.fn_proto.cc = CallingConventionStdcall; | |
| 706 | break; | |
| 707 | case CC_X86FastCall: // __attribute__((fastcall)) | |
| 708 | emit_warning(c, source_loc, "unsupported calling convention: x86 fastcall"); | |
| 709 | return nullptr; | |
| 710 | case CC_X86ThisCall: // __attribute__((thiscall)) | |
| 711 | emit_warning(c, source_loc, "unsupported calling convention: x86 thiscall"); | |
| 712 | return nullptr; | |
| 713 | case CC_X86VectorCall: // __attribute__((vectorcall)) | |
| 714 | emit_warning(c, source_loc, "unsupported calling convention: x86 vectorcall"); | |
| 715 | return nullptr; | |
| 716 | case CC_X86Pascal: // __attribute__((pascal)) | |
| 717 | emit_warning(c, source_loc, "unsupported calling convention: x86 pascal"); | |
| 718 | return nullptr; | |
| 719 | case CC_Win64: // __attribute__((ms_abi)) | |
| 720 | emit_warning(c, source_loc, "unsupported calling convention: win64"); | |
| 721 | return nullptr; | |
| 722 | case CC_X86_64SysV: // __attribute__((sysv_abi)) | |
| 723 | emit_warning(c, source_loc, "unsupported calling convention: x86 64sysv"); | |
| 724 | return nullptr; | |
| 725 | case CC_X86RegCall: | |
| 726 | emit_warning(c, source_loc, "unsupported calling convention: x86 reg"); | |
| 727 | return nullptr; | |
| 728 | case CC_AAPCS: // __attribute__((pcs("aapcs"))) | |
| 729 | emit_warning(c, source_loc, "unsupported calling convention: aapcs"); | |
| 730 | return nullptr; | |
| 731 | case CC_AAPCS_VFP: // __attribute__((pcs("aapcs-vfp"))) | |
| 732 | emit_warning(c, source_loc, "unsupported calling convention: aapcs-vfp"); | |
| 733 | return nullptr; | |
| 734 | case CC_IntelOclBicc: // __attribute__((intel_ocl_bicc)) | |
| 735 | emit_warning(c, source_loc, "unsupported calling convention: intel_ocl_bicc"); | |
| 736 | return nullptr; | |
| 737 | case CC_SpirFunction: // default for OpenCL functions on SPIR target | |
| 738 | emit_warning(c, source_loc, "unsupported calling convention: SPIR function"); | |
| 739 | return nullptr; | |
| 740 | case CC_OpenCLKernel: | |
| 741 | emit_warning(c, source_loc, "unsupported calling convention: OpenCLKernel"); | |
| 742 | return nullptr; | |
| 743 | case CC_Swift: | |
| 744 | emit_warning(c, source_loc, "unsupported calling convention: Swift"); | |
| 745 | return nullptr; | |
| 746 | case CC_PreserveMost: | |
| 747 | emit_warning(c, source_loc, "unsupported calling convention: PreserveMost"); | |
| 748 | return nullptr; | |
| 749 | case CC_PreserveAll: | |
| 750 | emit_warning(c, source_loc, "unsupported calling convention: PreserveAll"); | |
| 751 | return nullptr; | |
| 752 | } | |
| 753 | ||
| 754 | proto_node->data.fn_proto.is_var_args = fn_proto_ty->isVariadic(); | |
| 755 | size_t param_count = fn_proto_ty->getNumParams(); | |
| 756 | ||
| 757 | if (fn_proto_ty->getNoReturnAttr()) { | |
| 758 | proto_node->data.fn_proto.return_type = trans_create_node_symbol_str(c, "noreturn"); | |
| 759 | } else { | |
| 760 | proto_node->data.fn_proto.return_type = trans_qual_type(c, fn_proto_ty->getReturnType(), | |
| 761 | source_loc); | |
| 762 | if (proto_node->data.fn_proto.return_type == nullptr) { | |
| 763 | emit_warning(c, source_loc, "unsupported function proto return type"); | |
| 764 | return nullptr; | |
| 765 | } | |
| 766 | // convert c_void to actual void (only for return type) | |
| 767 | if (is_c_void_type(proto_node->data.fn_proto.return_type)) { | |
| 768 | proto_node->data.fn_proto.return_type = nullptr; | |
| 769 | } | |
| 770 | } | |
| 771 | ||
| 772 | //emit_warning(c, source_loc, "TODO figure out fn prototype fn name"); | |
| 773 | const char *fn_name = nullptr; | |
| 774 | if (fn_name != nullptr) { | |
| 775 | proto_node->data.fn_proto.name = buf_create_from_str(fn_name); | |
| 776 | } | |
| 777 | ||
| 778 | for (size_t i = 0; i < param_count; i += 1) { | |
| 779 | QualType qt = fn_proto_ty->getParamType(i); | |
| 780 | AstNode *param_type_node = trans_qual_type(c, qt, source_loc); | |
| 781 | ||
| 782 | if (param_type_node == nullptr) { | |
| 783 | emit_warning(c, source_loc, "unresolved function proto parameter type"); | |
| 784 | return nullptr; | |
| 785 | } | |
| 786 | ||
| 787 | AstNode *param_node = trans_create_node(c, NodeTypeParamDecl); | |
| 788 | //emit_warning(c, source_loc, "TODO figure out fn prototype param name"); | |
| 789 | const char *param_name = nullptr; | |
| 790 | if (param_name != nullptr) { | |
| 791 | param_node->data.param_decl.name = buf_create_from_str(param_name); | |
| 792 | } | |
| 793 | param_node->data.param_decl.is_noalias = qt.isRestrictQualified(); | |
| 794 | param_node->data.param_decl.type = param_type_node; | |
| 795 | proto_node->data.fn_proto.params.append(param_node); | |
| 796 | } | |
| 797 | // TODO check for always_inline attribute | |
| 798 | // TODO check for align attribute | |
| 799 | ||
| 800 | return proto_node; | |
| 801 | } | |
| 802 | case Type::Record: | |
| 803 | { | |
| 804 | const RecordType *record_ty = static_cast<const RecordType*>(ty); | |
| 805 | return resolve_record_decl(c, record_ty->getDecl()); | |
| 806 | } | |
| 807 | case Type::Enum: | |
| 808 | { | |
| 809 | const EnumType *enum_ty = static_cast<const EnumType*>(ty); | |
| 810 | return resolve_enum_decl(c, enum_ty->getDecl()); | |
| 811 | } | |
| 812 | case Type::ConstantArray: | |
| 813 | { | |
| 814 | const ConstantArrayType *const_arr_ty = static_cast<const ConstantArrayType *>(ty); | |
| 815 | AstNode *child_type_node = trans_qual_type(c, const_arr_ty->getElementType(), source_loc); | |
| 816 | if (child_type_node == nullptr) { | |
| 817 | emit_warning(c, source_loc, "unresolved array element type"); | |
| 818 | return nullptr; | |
| 819 | } | |
| 820 | uint64_t size = const_arr_ty->getSize().getLimitedValue(); | |
| 821 | AstNode *size_node = trans_create_node_unsigned(c, size); | |
| 822 | return trans_create_node_array_type(c, size_node, child_type_node); | |
| 823 | } | |
| 824 | case Type::Paren: | |
| 825 | { | |
| 826 | const ParenType *paren_ty = static_cast<const ParenType *>(ty); | |
| 827 | return trans_qual_type(c, paren_ty->getInnerType(), source_loc); | |
| 828 | } | |
| 829 | case Type::Decayed: | |
| 830 | { | |
| 831 | const DecayedType *decayed_ty = static_cast<const DecayedType *>(ty); | |
| 832 | return trans_qual_type(c, decayed_ty->getDecayedType(), source_loc); | |
| 833 | } | |
| 834 | case Type::Attributed: | |
| 835 | { | |
| 836 | const AttributedType *attributed_ty = static_cast<const AttributedType *>(ty); | |
| 837 | return trans_qual_type(c, attributed_ty->getEquivalentType(), source_loc); | |
| 838 | } | |
| 839 | case Type::BlockPointer: | |
| 840 | case Type::LValueReference: | |
| 841 | case Type::RValueReference: | |
| 842 | case Type::MemberPointer: | |
| 843 | case Type::IncompleteArray: | |
| 844 | case Type::VariableArray: | |
| 845 | case Type::DependentSizedArray: | |
| 846 | case Type::DependentSizedExtVector: | |
| 847 | case Type::Vector: | |
| 848 | case Type::ExtVector: | |
| 849 | case Type::FunctionNoProto: | |
| 850 | case Type::UnresolvedUsing: | |
| 851 | case Type::Adjusted: | |
| 852 | case Type::TypeOfExpr: | |
| 853 | case Type::TypeOf: | |
| 854 | case Type::Decltype: | |
| 855 | case Type::UnaryTransform: | |
| 856 | case Type::TemplateTypeParm: | |
| 857 | case Type::SubstTemplateTypeParm: | |
| 858 | case Type::SubstTemplateTypeParmPack: | |
| 859 | case Type::TemplateSpecialization: | |
| 860 | case Type::Auto: | |
| 861 | case Type::InjectedClassName: | |
| 862 | case Type::DependentName: | |
| 863 | case Type::DependentTemplateSpecialization: | |
| 864 | case Type::PackExpansion: | |
| 865 | case Type::ObjCObject: | |
| 866 | case Type::ObjCInterface: | |
| 867 | case Type::Complex: | |
| 868 | case Type::ObjCObjectPointer: | |
| 869 | case Type::Atomic: | |
| 870 | case Type::Pipe: | |
| 871 | case Type::ObjCTypeParam: | |
| 872 | case Type::DeducedTemplateSpecialization: | |
| 873 | emit_warning(c, source_loc, "unsupported type: '%s'", ty->getTypeClassName()); | |
| 874 | return nullptr; | |
| 875 | } | |
| 876 | zig_unreachable(); | |
| 877 | } | |
| 878 | ||
| 879 | static AstNode *trans_qual_type(Context *c, QualType qt, const SourceLocation &source_loc) { | |
| 880 | return trans_type(c, qt.getTypePtr(), source_loc); | |
| 881 | } | |
| 882 | ||
| 883 | static AstNode *trans_compound_stmt(Context *c, AstNode *parent, CompoundStmt *stmt) { | |
| 884 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 885 | for (CompoundStmt::body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) { | |
| 886 | AstNode *child_node = trans_stmt(c, false, child_block, *it, TransRValue); | |
| 887 | if (child_node == nullptr) | |
| 888 | return nullptr; | |
| 889 | if (child_node != skip_add_to_block_node) | |
| 890 | child_block->data.block.statements.append(child_node); | |
| 891 | } | |
| 892 | return child_block; | |
| 893 | } | |
| 894 | ||
| 895 | static AstNode *trans_return_stmt(Context *c, AstNode *block, ReturnStmt *stmt) { | |
| 896 | Expr *value_expr = stmt->getRetValue(); | |
| 897 | if (value_expr == nullptr) { | |
| 898 | emit_warning(c, stmt->getLocStart(), "TODO handle C return void"); | |
| 899 | return nullptr; | |
| 900 | } else { | |
| 901 | AstNode *return_node = trans_create_node(c, NodeTypeReturnExpr); | |
| 902 | return_node->data.return_expr.expr = trans_expr(c, true, block, value_expr, TransRValue); | |
| 903 | if (return_node->data.return_expr.expr == nullptr) | |
| 904 | return nullptr; | |
| 905 | return return_node; | |
| 906 | } | |
| 907 | } | |
| 908 | ||
| 909 | static AstNode *trans_integer_literal(Context *c, IntegerLiteral *stmt) { | |
| 910 | llvm::APSInt result; | |
| 911 | if (!stmt->EvaluateAsInt(result, *c->ctx)) { | |
| 912 | emit_warning(c, stmt->getLocStart(), "invalid integer literal"); | |
| 913 | return nullptr; | |
| 914 | } | |
| 915 | return trans_create_node_apint(c, result); | |
| 916 | } | |
| 917 | ||
| 918 | static AstNode *trans_conditional_operator(Context *c, bool result_used, AstNode *block, ConditionalOperator *stmt) { | |
| 919 | AstNode *node = trans_create_node(c, NodeTypeIfBoolExpr); | |
| 920 | ||
| 921 | Expr *cond_expr = stmt->getCond(); | |
| 922 | Expr *true_expr = stmt->getTrueExpr(); | |
| 923 | Expr *false_expr = stmt->getFalseExpr(); | |
| 924 | ||
| 925 | node->data.if_bool_expr.condition = trans_expr(c, true, block, cond_expr, TransRValue); | |
| 926 | if (node->data.if_bool_expr.condition == nullptr) | |
| 927 | return nullptr; | |
| 928 | ||
| 929 | node->data.if_bool_expr.then_block = trans_expr(c, result_used, block, true_expr, TransRValue); | |
| 930 | if (node->data.if_bool_expr.then_block == nullptr) | |
| 931 | return nullptr; | |
| 932 | ||
| 933 | node->data.if_bool_expr.else_node = trans_expr(c, result_used, block, false_expr, TransRValue); | |
| 934 | if (node->data.if_bool_expr.else_node == nullptr) | |
| 935 | return nullptr; | |
| 936 | ||
| 937 | return maybe_suppress_result(c, result_used, node); | |
| 938 | } | |
| 939 | ||
| 940 | static AstNode *trans_create_bin_op(Context *c, AstNode *block, Expr *lhs, BinOpType bin_op, Expr *rhs) { | |
| 941 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 942 | node->data.bin_op_expr.bin_op = bin_op; | |
| 943 | ||
| 944 | node->data.bin_op_expr.op1 = trans_expr(c, true, block, lhs, TransRValue); | |
| 945 | if (node->data.bin_op_expr.op1 == nullptr) | |
| 946 | return nullptr; | |
| 947 | ||
| 948 | node->data.bin_op_expr.op2 = trans_expr(c, true, block, rhs, TransRValue); | |
| 949 | if (node->data.bin_op_expr.op2 == nullptr) | |
| 950 | return nullptr; | |
| 951 | ||
| 952 | return node; | |
| 953 | } | |
| 954 | ||
| 955 | static AstNode *trans_create_assign(Context *c, bool result_used, AstNode *block, Expr *lhs, Expr *rhs) { | |
| 956 | if (!result_used) { | |
| 957 | // common case | |
| 958 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 959 | node->data.bin_op_expr.bin_op = BinOpTypeAssign; | |
| 960 | ||
| 961 | node->data.bin_op_expr.op1 = trans_expr(c, true, block, lhs, TransLValue); | |
| 962 | if (node->data.bin_op_expr.op1 == nullptr) | |
| 963 | return nullptr; | |
| 964 | ||
| 965 | node->data.bin_op_expr.op2 = trans_expr(c, true, block, rhs, TransRValue); | |
| 966 | if (node->data.bin_op_expr.op2 == nullptr) | |
| 967 | return nullptr; | |
| 968 | ||
| 969 | return node; | |
| 970 | } else { | |
| 971 | // worst case | |
| 972 | // c: lhs = rhs | |
| 973 | // zig: { | |
| 974 | // zig: const _tmp = rhs; | |
| 975 | // zig: lhs = _tmp; | |
| 976 | // zig: _tmp | |
| 977 | // zig: } | |
| 978 | ||
| 979 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 980 | ||
| 981 | // const _tmp = rhs; | |
| 982 | AstNode *rhs_node = trans_expr(c, true, child_block, rhs, TransRValue); | |
| 983 | if (rhs_node == nullptr) return nullptr; | |
| 984 | // TODO: avoid name collisions with generated variable names | |
| 985 | Buf* tmp_var_name = buf_create_from_str("_tmp"); | |
| 986 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, rhs_node); | |
| 987 | child_block->data.block.statements.append(tmp_var_decl); | |
| 988 | ||
| 989 | // lhs = _tmp; | |
| 990 | AstNode *lhs_node = trans_expr(c, true, child_block, lhs, TransLValue); | |
| 991 | if (lhs_node == nullptr) return nullptr; | |
| 992 | child_block->data.block.statements.append( | |
| 993 | trans_create_node_bin_op(c, lhs_node, BinOpTypeAssign, | |
| 994 | trans_create_node_symbol(c, tmp_var_name))); | |
| 995 | ||
| 996 | // _tmp | |
| 997 | child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name)); | |
| 998 | child_block->data.block.last_statement_is_result_expression = true; | |
| 999 | ||
| 1000 | return child_block; | |
| 1001 | } | |
| 1002 | } | |
| 1003 | ||
| 1004 | static AstNode *trans_create_shift_op(Context *c, AstNode *block, QualType result_type, Expr *lhs_expr, BinOpType bin_op, Expr *rhs_expr) { | |
| 1005 | const SourceLocation &rhs_location = rhs_expr->getLocStart(); | |
| 1006 | AstNode *rhs_type = qual_type_to_log2_int_ref(c, result_type, rhs_location); | |
| 1007 | // lhs >> u5(rh) | |
| 1008 | ||
| 1009 | AstNode *lhs = trans_expr(c, true, block, lhs_expr, TransLValue); | |
| 1010 | if (lhs == nullptr) return nullptr; | |
| 1011 | ||
| 1012 | AstNode *rhs = trans_expr(c, true, block, rhs_expr, TransRValue); | |
| 1013 | if (rhs == nullptr) return nullptr; | |
| 1014 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); | |
| 1015 | ||
| 1016 | return trans_create_node_bin_op(c, lhs, bin_op, coerced_rhs); | |
| 1017 | } | |
| 1018 | ||
| 1019 | static AstNode *trans_binary_operator(Context *c, bool result_used, AstNode *block, BinaryOperator *stmt) { | |
| 1020 | switch (stmt->getOpcode()) { | |
| 1021 | case BO_PtrMemD: | |
| 1022 | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_PtrMemD"); | |
| 1023 | return nullptr; | |
| 1024 | case BO_PtrMemI: | |
| 1025 | emit_warning(c, stmt->getLocStart(), "TODO handle more C binary operators: BO_PtrMemI"); | |
| 1026 | return nullptr; | |
| 1027 | case BO_Mul: | |
| 1028 | return trans_create_bin_op(c, block, stmt->getLHS(), | |
| 1029 | qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeMultWrap : BinOpTypeMult, | |
| 1030 | stmt->getRHS()); | |
| 1031 | case BO_Div: | |
| 1032 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) { | |
| 1033 | // unsigned/float division uses the operator | |
| 1034 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeDiv, stmt->getRHS()); | |
| 1035 | } else { | |
| 1036 | // signed integer division uses @divTrunc | |
| 1037 | AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "divTrunc"); | |
| 1038 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); | |
| 1039 | if (lhs == nullptr) return nullptr; | |
| 1040 | fn_call->data.fn_call_expr.params.append(lhs); | |
| 1041 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransLValue); | |
| 1042 | if (rhs == nullptr) return nullptr; | |
| 1043 | fn_call->data.fn_call_expr.params.append(rhs); | |
| 1044 | return fn_call; | |
| 1045 | } | |
| 1046 | case BO_Rem: | |
| 1047 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) { | |
| 1048 | // unsigned/float division uses the operator | |
| 1049 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeMod, stmt->getRHS()); | |
| 1050 | } else { | |
| 1051 | // signed integer division uses @rem | |
| 1052 | AstNode *fn_call = trans_create_node_builtin_fn_call_str(c, "rem"); | |
| 1053 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); | |
| 1054 | if (lhs == nullptr) return nullptr; | |
| 1055 | fn_call->data.fn_call_expr.params.append(lhs); | |
| 1056 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransLValue); | |
| 1057 | if (rhs == nullptr) return nullptr; | |
| 1058 | fn_call->data.fn_call_expr.params.append(rhs); | |
| 1059 | return fn_call; | |
| 1060 | } | |
| 1061 | case BO_Add: | |
| 1062 | return trans_create_bin_op(c, block, stmt->getLHS(), | |
| 1063 | qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeAddWrap : BinOpTypeAdd, | |
| 1064 | stmt->getRHS()); | |
| 1065 | case BO_Sub: | |
| 1066 | return trans_create_bin_op(c, block, stmt->getLHS(), | |
| 1067 | qual_type_has_wrapping_overflow(c, stmt->getType()) ? BinOpTypeSubWrap : BinOpTypeSub, | |
| 1068 | stmt->getRHS()); | |
| 1069 | case BO_Shl: | |
| 1070 | return trans_create_shift_op(c, block, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftLeft, stmt->getRHS()); | |
| 1071 | case BO_Shr: | |
| 1072 | return trans_create_shift_op(c, block, stmt->getType(), stmt->getLHS(), BinOpTypeBitShiftRight, stmt->getRHS()); | |
| 1073 | case BO_LT: | |
| 1074 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpLessThan, stmt->getRHS()); | |
| 1075 | case BO_GT: | |
| 1076 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpGreaterThan, stmt->getRHS()); | |
| 1077 | case BO_LE: | |
| 1078 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpLessOrEq, stmt->getRHS()); | |
| 1079 | case BO_GE: | |
| 1080 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpGreaterOrEq, stmt->getRHS()); | |
| 1081 | case BO_EQ: | |
| 1082 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpEq, stmt->getRHS()); | |
| 1083 | case BO_NE: | |
| 1084 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeCmpNotEq, stmt->getRHS()); | |
| 1085 | case BO_And: | |
| 1086 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinAnd, stmt->getRHS()); | |
| 1087 | case BO_Xor: | |
| 1088 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinXor, stmt->getRHS()); | |
| 1089 | case BO_Or: | |
| 1090 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBinOr, stmt->getRHS()); | |
| 1091 | case BO_LAnd: | |
| 1092 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolAnd, stmt->getRHS()); | |
| 1093 | case BO_LOr: | |
| 1094 | // TODO: int vs bool | |
| 1095 | return trans_create_bin_op(c, block, stmt->getLHS(), BinOpTypeBoolOr, stmt->getRHS()); | |
| 1096 | case BO_Assign: | |
| 1097 | return trans_create_assign(c, result_used, block, stmt->getLHS(), stmt->getRHS()); | |
| 1098 | case BO_Comma: | |
| 1099 | { | |
| 1100 | block = trans_create_node(c, NodeTypeBlock); | |
| 1101 | AstNode *lhs = trans_expr(c, false, block, stmt->getLHS(), TransRValue); | |
| 1102 | if (lhs == nullptr) return nullptr; | |
| 1103 | block->data.block.statements.append(maybe_suppress_result(c, false, lhs)); | |
| 1104 | AstNode *rhs = trans_expr(c, result_used, block, stmt->getRHS(), TransRValue); | |
| 1105 | if (rhs == nullptr) return nullptr; | |
| 1106 | block->data.block.statements.append(maybe_suppress_result(c, result_used, rhs)); | |
| 1107 | block->data.block.last_statement_is_result_expression = true; | |
| 1108 | return block; | |
| 1109 | } | |
| 1110 | case BO_MulAssign: | |
| 1111 | case BO_DivAssign: | |
| 1112 | case BO_RemAssign: | |
| 1113 | case BO_AddAssign: | |
| 1114 | case BO_SubAssign: | |
| 1115 | case BO_ShlAssign: | |
| 1116 | case BO_ShrAssign: | |
| 1117 | case BO_AndAssign: | |
| 1118 | case BO_XorAssign: | |
| 1119 | case BO_OrAssign: | |
| 1120 | zig_unreachable(); | |
| 1121 | } | |
| 1122 | ||
| 1123 | zig_unreachable(); | |
| 1124 | } | |
| 1125 | ||
| 1126 | static AstNode *trans_create_compound_assign_shift(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) { | |
| 1127 | const SourceLocation &rhs_location = stmt->getRHS()->getLocStart(); | |
| 1128 | AstNode *rhs_type = qual_type_to_log2_int_ref(c, stmt->getComputationLHSType(), rhs_location); | |
| 1129 | ||
| 1130 | bool use_intermediate_casts = stmt->getComputationLHSType().getTypePtr() != stmt->getComputationResultType().getTypePtr(); | |
| 1131 | if (!use_intermediate_casts && !result_used) { | |
| 1132 | // simple common case, where the C and Zig are identical: | |
| 1133 | // lhs >>= rhs | |
| 1134 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); | |
| 1135 | if (lhs == nullptr) return nullptr; | |
| 1136 | ||
| 1137 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue); | |
| 1138 | if (rhs == nullptr) return nullptr; | |
| 1139 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); | |
| 1140 | ||
| 1141 | return trans_create_node_bin_op(c, lhs, assign_op, coerced_rhs); | |
| 1142 | } else { | |
| 1143 | // need more complexity. worst case, this looks like this: | |
| 1144 | // c: lhs >>= rhs | |
| 1145 | // zig: { | |
| 1146 | // zig: const _ref = &lhs; | |
| 1147 | // zig: *_ref = result_type(operation_type(*_ref) >> u5(rhs)); | |
| 1148 | // zig: *_ref | |
| 1149 | // zig: } | |
| 1150 | // where u5 is the appropriate type | |
| 1151 | ||
| 1152 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 1153 | ||
| 1154 | // const _ref = &lhs; | |
| 1155 | AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue); | |
| 1156 | if (lhs == nullptr) return nullptr; | |
| 1157 | AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs); | |
| 1158 | // TODO: avoid name collisions with generated variable names | |
| 1159 | Buf* tmp_var_name = buf_create_from_str("_ref"); | |
| 1160 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); | |
| 1161 | child_block->data.block.statements.append(tmp_var_decl); | |
| 1162 | ||
| 1163 | // *_ref = result_type(operation_type(*_ref) >> u5(rhs)); | |
| 1164 | ||
| 1165 | AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue); | |
| 1166 | if (rhs == nullptr) return nullptr; | |
| 1167 | AstNode *coerced_rhs = trans_create_node_fn_call_1(c, rhs_type, rhs); | |
| 1168 | ||
| 1169 | AstNode *assign_statement = trans_create_node_bin_op(c, | |
| 1170 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1171 | trans_create_node_symbol(c, tmp_var_name)), | |
| 1172 | BinOpTypeAssign, | |
| 1173 | trans_c_cast(c, rhs_location, | |
| 1174 | stmt->getComputationResultType(), | |
| 1175 | trans_create_node_bin_op(c, | |
| 1176 | trans_c_cast(c, rhs_location, | |
| 1177 | stmt->getComputationLHSType(), | |
| 1178 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1179 | trans_create_node_symbol(c, tmp_var_name))), | |
| 1180 | bin_op, | |
| 1181 | coerced_rhs))); | |
| 1182 | child_block->data.block.statements.append(assign_statement); | |
| 1183 | ||
| 1184 | if (result_used) { | |
| 1185 | // *_ref | |
| 1186 | child_block->data.block.statements.append( | |
| 1187 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1188 | trans_create_node_symbol(c, tmp_var_name))); | |
| 1189 | child_block->data.block.last_statement_is_result_expression = true; | |
| 1190 | } | |
| 1191 | ||
| 1192 | return child_block; | |
| 1193 | } | |
| 1194 | } | |
| 1195 | ||
| 1196 | static AstNode *trans_create_compound_assign(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt, BinOpType assign_op, BinOpType bin_op) { | |
| 1197 | if (!result_used) { | |
| 1198 | // simple common case, where the C and Zig are identical: | |
| 1199 | // lhs += rhs | |
| 1200 | AstNode *lhs = trans_expr(c, true, block, stmt->getLHS(), TransLValue); | |
| 1201 | if (lhs == nullptr) return nullptr; | |
| 1202 | AstNode *rhs = trans_expr(c, true, block, stmt->getRHS(), TransRValue); | |
| 1203 | if (rhs == nullptr) return nullptr; | |
| 1204 | return trans_create_node_bin_op(c, lhs, assign_op, rhs); | |
| 1205 | } else { | |
| 1206 | // need more complexity. worst case, this looks like this: | |
| 1207 | // c: lhs += rhs | |
| 1208 | // zig: { | |
| 1209 | // zig: const _ref = &lhs; | |
| 1210 | // zig: *_ref = *_ref + rhs; | |
| 1211 | // zig: *_ref | |
| 1212 | // zig: } | |
| 1213 | ||
| 1214 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 1215 | ||
| 1216 | // const _ref = &lhs; | |
| 1217 | AstNode *lhs = trans_expr(c, true, child_block, stmt->getLHS(), TransLValue); | |
| 1218 | if (lhs == nullptr) return nullptr; | |
| 1219 | AstNode *addr_of_lhs = trans_create_node_addr_of(c, false, false, lhs); | |
| 1220 | // TODO: avoid name collisions with generated variable names | |
| 1221 | Buf* tmp_var_name = buf_create_from_str("_ref"); | |
| 1222 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, addr_of_lhs); | |
| 1223 | child_block->data.block.statements.append(tmp_var_decl); | |
| 1224 | ||
| 1225 | // *_ref = *_ref + rhs; | |
| 1226 | ||
| 1227 | AstNode *rhs = trans_expr(c, true, child_block, stmt->getRHS(), TransRValue); | |
| 1228 | if (rhs == nullptr) return nullptr; | |
| 1229 | ||
| 1230 | AstNode *assign_statement = trans_create_node_bin_op(c, | |
| 1231 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1232 | trans_create_node_symbol(c, tmp_var_name)), | |
| 1233 | BinOpTypeAssign, | |
| 1234 | trans_create_node_bin_op(c, | |
| 1235 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1236 | trans_create_node_symbol(c, tmp_var_name)), | |
| 1237 | bin_op, | |
| 1238 | rhs)); | |
| 1239 | child_block->data.block.statements.append(assign_statement); | |
| 1240 | ||
| 1241 | // *_ref | |
| 1242 | child_block->data.block.statements.append( | |
| 1243 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1244 | trans_create_node_symbol(c, tmp_var_name))); | |
| 1245 | child_block->data.block.last_statement_is_result_expression = true; | |
| 1246 | ||
| 1247 | return child_block; | |
| 1248 | } | |
| 1249 | } | |
| 1250 | ||
| 1251 | ||
| 1252 | static AstNode *trans_compound_assign_operator(Context *c, bool result_used, AstNode *block, CompoundAssignOperator *stmt) { | |
| 1253 | switch (stmt->getOpcode()) { | |
| 1254 | case BO_MulAssign: | |
| 1255 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1256 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimesWrap, BinOpTypeMultWrap); | |
| 1257 | else | |
| 1258 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignTimes, BinOpTypeMult); | |
| 1259 | case BO_DivAssign: | |
| 1260 | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_DivAssign"); | |
| 1261 | return nullptr; | |
| 1262 | case BO_RemAssign: | |
| 1263 | emit_warning(c, stmt->getLocStart(), "TODO handle more C compound assign operators: BO_RemAssign"); | |
| 1264 | return nullptr; | |
| 1265 | case BO_AddAssign: | |
| 1266 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1267 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlusWrap, BinOpTypeAddWrap); | |
| 1268 | else | |
| 1269 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignPlus, BinOpTypeAdd); | |
| 1270 | case BO_SubAssign: | |
| 1271 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1272 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinusWrap, BinOpTypeSubWrap); | |
| 1273 | else | |
| 1274 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignMinus, BinOpTypeSub); | |
| 1275 | case BO_ShlAssign: | |
| 1276 | return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftLeft, BinOpTypeBitShiftLeft); | |
| 1277 | case BO_ShrAssign: | |
| 1278 | return trans_create_compound_assign_shift(c, result_used, block, stmt, BinOpTypeAssignBitShiftRight, BinOpTypeBitShiftRight); | |
| 1279 | case BO_AndAssign: | |
| 1280 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitAnd, BinOpTypeBinAnd); | |
| 1281 | case BO_XorAssign: | |
| 1282 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitXor, BinOpTypeBinXor); | |
| 1283 | case BO_OrAssign: | |
| 1284 | return trans_create_compound_assign(c, result_used, block, stmt, BinOpTypeAssignBitOr, BinOpTypeBinOr); | |
| 1285 | case BO_PtrMemD: | |
| 1286 | case BO_PtrMemI: | |
| 1287 | case BO_Assign: | |
| 1288 | case BO_Mul: | |
| 1289 | case BO_Div: | |
| 1290 | case BO_Rem: | |
| 1291 | case BO_Add: | |
| 1292 | case BO_Sub: | |
| 1293 | case BO_Shl: | |
| 1294 | case BO_Shr: | |
| 1295 | case BO_LT: | |
| 1296 | case BO_GT: | |
| 1297 | case BO_LE: | |
| 1298 | case BO_GE: | |
| 1299 | case BO_EQ: | |
| 1300 | case BO_NE: | |
| 1301 | case BO_And: | |
| 1302 | case BO_Xor: | |
| 1303 | case BO_Or: | |
| 1304 | case BO_LAnd: | |
| 1305 | case BO_LOr: | |
| 1306 | case BO_Comma: | |
| 1307 | zig_unreachable(); | |
| 1308 | } | |
| 1309 | ||
| 1310 | zig_unreachable(); | |
| 1311 | } | |
| 1312 | ||
| 1313 | static AstNode *trans_implicit_cast_expr(Context *c, AstNode *block, ImplicitCastExpr *stmt) { | |
| 1314 | switch (stmt->getCastKind()) { | |
| 1315 | case CK_LValueToRValue: | |
| 1316 | return trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); | |
| 1317 | case CK_IntegralCast: | |
| 1318 | { | |
| 1319 | AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); | |
| 1320 | if (target_node == nullptr) | |
| 1321 | return nullptr; | |
| 1322 | return trans_c_cast(c, stmt->getExprLoc(), stmt->getType(), target_node); | |
| 1323 | } | |
| 1324 | case CK_FunctionToPointerDecay: | |
| 1325 | case CK_ArrayToPointerDecay: | |
| 1326 | { | |
| 1327 | AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); | |
| 1328 | if (target_node == nullptr) | |
| 1329 | return nullptr; | |
| 1330 | return target_node; | |
| 1331 | } | |
| 1332 | case CK_BitCast: | |
| 1333 | { | |
| 1334 | AstNode *target_node = trans_expr(c, true, block, stmt->getSubExpr(), TransRValue); | |
| 1335 | if (target_node == nullptr) | |
| 1336 | return nullptr; | |
| 1337 | ||
| 1338 | AstNode *dest_type_node = trans_qual_type(c, stmt->getType(), stmt->getLocStart()); | |
| 1339 | ||
| 1340 | AstNode *node = trans_create_node_builtin_fn_call_str(c, "ptrCast"); | |
| 1341 | node->data.fn_call_expr.params.append(dest_type_node); | |
| 1342 | node->data.fn_call_expr.params.append(target_node); | |
| 1343 | return node; | |
| 1344 | } | |
| 1345 | case CK_NullToPointer: | |
| 1346 | return trans_create_node(c, NodeTypeNullLiteral); | |
| 1347 | case CK_Dependent: | |
| 1348 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dependent"); | |
| 1349 | return nullptr; | |
| 1350 | case CK_LValueBitCast: | |
| 1351 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_LValueBitCast"); | |
| 1352 | return nullptr; | |
| 1353 | case CK_NoOp: | |
| 1354 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NoOp"); | |
| 1355 | return nullptr; | |
| 1356 | case CK_BaseToDerived: | |
| 1357 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BaseToDerived"); | |
| 1358 | return nullptr; | |
| 1359 | case CK_DerivedToBase: | |
| 1360 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_DerivedToBase"); | |
| 1361 | return nullptr; | |
| 1362 | case CK_UncheckedDerivedToBase: | |
| 1363 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_UncheckedDerivedToBase"); | |
| 1364 | return nullptr; | |
| 1365 | case CK_Dynamic: | |
| 1366 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_Dynamic"); | |
| 1367 | return nullptr; | |
| 1368 | case CK_ToUnion: | |
| 1369 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ToUnion"); | |
| 1370 | return nullptr; | |
| 1371 | case CK_NullToMemberPointer: | |
| 1372 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NullToMemberPointer"); | |
| 1373 | return nullptr; | |
| 1374 | case CK_BaseToDerivedMemberPointer: | |
| 1375 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BaseToDerivedMemberPointer"); | |
| 1376 | return nullptr; | |
| 1377 | case CK_DerivedToBaseMemberPointer: | |
| 1378 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_DerivedToBaseMemberPointer"); | |
| 1379 | return nullptr; | |
| 1380 | case CK_MemberPointerToBoolean: | |
| 1381 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_MemberPointerToBoolean"); | |
| 1382 | return nullptr; | |
| 1383 | case CK_ReinterpretMemberPointer: | |
| 1384 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ReinterpretMemberPointer"); | |
| 1385 | return nullptr; | |
| 1386 | case CK_UserDefinedConversion: | |
| 1387 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_UserDefinedConversion"); | |
| 1388 | return nullptr; | |
| 1389 | case CK_ConstructorConversion: | |
| 1390 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ConstructorConversion"); | |
| 1391 | return nullptr; | |
| 1392 | case CK_IntegralToPointer: | |
| 1393 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToPointer"); | |
| 1394 | return nullptr; | |
| 1395 | case CK_PointerToIntegral: | |
| 1396 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_PointerToIntegral"); | |
| 1397 | return nullptr; | |
| 1398 | case CK_PointerToBoolean: | |
| 1399 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_PointerToBoolean"); | |
| 1400 | return nullptr; | |
| 1401 | case CK_ToVoid: | |
| 1402 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ToVoid"); | |
| 1403 | return nullptr; | |
| 1404 | case CK_VectorSplat: | |
| 1405 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_VectorSplat"); | |
| 1406 | return nullptr; | |
| 1407 | case CK_IntegralToBoolean: | |
| 1408 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToBoolean"); | |
| 1409 | return nullptr; | |
| 1410 | case CK_IntegralToFloating: | |
| 1411 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralToFloating"); | |
| 1412 | return nullptr; | |
| 1413 | case CK_FloatingToIntegral: | |
| 1414 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingToIntegral"); | |
| 1415 | return nullptr; | |
| 1416 | case CK_FloatingToBoolean: | |
| 1417 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingToBoolean"); | |
| 1418 | return nullptr; | |
| 1419 | case CK_BooleanToSignedIntegral: | |
| 1420 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BooleanToSignedIntegral"); | |
| 1421 | return nullptr; | |
| 1422 | case CK_FloatingCast: | |
| 1423 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingCast"); | |
| 1424 | return nullptr; | |
| 1425 | case CK_CPointerToObjCPointerCast: | |
| 1426 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_CPointerToObjCPointerCast"); | |
| 1427 | return nullptr; | |
| 1428 | case CK_BlockPointerToObjCPointerCast: | |
| 1429 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BlockPointerToObjCPointerCast"); | |
| 1430 | return nullptr; | |
| 1431 | case CK_AnyPointerToBlockPointerCast: | |
| 1432 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AnyPointerToBlockPointerCast"); | |
| 1433 | return nullptr; | |
| 1434 | case CK_ObjCObjectLValueCast: | |
| 1435 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ObjCObjectLValueCast"); | |
| 1436 | return nullptr; | |
| 1437 | case CK_FloatingRealToComplex: | |
| 1438 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingRealToComplex"); | |
| 1439 | return nullptr; | |
| 1440 | case CK_FloatingComplexToReal: | |
| 1441 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToReal"); | |
| 1442 | return nullptr; | |
| 1443 | case CK_FloatingComplexToBoolean: | |
| 1444 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToBoolean"); | |
| 1445 | return nullptr; | |
| 1446 | case CK_FloatingComplexCast: | |
| 1447 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexCast"); | |
| 1448 | return nullptr; | |
| 1449 | case CK_FloatingComplexToIntegralComplex: | |
| 1450 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_FloatingComplexToIntegralComplex"); | |
| 1451 | return nullptr; | |
| 1452 | case CK_IntegralRealToComplex: | |
| 1453 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralRealToComplex"); | |
| 1454 | return nullptr; | |
| 1455 | case CK_IntegralComplexToReal: | |
| 1456 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToReal"); | |
| 1457 | return nullptr; | |
| 1458 | case CK_IntegralComplexToBoolean: | |
| 1459 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToBoolean"); | |
| 1460 | return nullptr; | |
| 1461 | case CK_IntegralComplexCast: | |
| 1462 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexCast"); | |
| 1463 | return nullptr; | |
| 1464 | case CK_IntegralComplexToFloatingComplex: | |
| 1465 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntegralComplexToFloatingComplex"); | |
| 1466 | return nullptr; | |
| 1467 | case CK_ARCProduceObject: | |
| 1468 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCProduceObject"); | |
| 1469 | return nullptr; | |
| 1470 | case CK_ARCConsumeObject: | |
| 1471 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCConsumeObject"); | |
| 1472 | return nullptr; | |
| 1473 | case CK_ARCReclaimReturnedObject: | |
| 1474 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCReclaimReturnedObject"); | |
| 1475 | return nullptr; | |
| 1476 | case CK_ARCExtendBlockObject: | |
| 1477 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ARCExtendBlockObject"); | |
| 1478 | return nullptr; | |
| 1479 | case CK_AtomicToNonAtomic: | |
| 1480 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AtomicToNonAtomic"); | |
| 1481 | return nullptr; | |
| 1482 | case CK_NonAtomicToAtomic: | |
| 1483 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_NonAtomicToAtomic"); | |
| 1484 | return nullptr; | |
| 1485 | case CK_CopyAndAutoreleaseBlockObject: | |
| 1486 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_CopyAndAutoreleaseBlockObject"); | |
| 1487 | return nullptr; | |
| 1488 | case CK_BuiltinFnToFnPtr: | |
| 1489 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_BuiltinFnToFnPtr"); | |
| 1490 | return nullptr; | |
| 1491 | case CK_ZeroToOCLEvent: | |
| 1492 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ZeroToOCLEvent"); | |
| 1493 | return nullptr; | |
| 1494 | case CK_ZeroToOCLQueue: | |
| 1495 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_ZeroToOCLQueue"); | |
| 1496 | return nullptr; | |
| 1497 | case CK_AddressSpaceConversion: | |
| 1498 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_AddressSpaceConversion"); | |
| 1499 | return nullptr; | |
| 1500 | case CK_IntToOCLSampler: | |
| 1501 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation cast CK_IntToOCLSampler"); | |
| 1502 | return nullptr; | |
| 1503 | } | |
| 1504 | zig_unreachable(); | |
| 1505 | } | |
| 1506 | ||
| 1507 | static AstNode *trans_decl_ref_expr(Context *c, DeclRefExpr *stmt, TransLRValue lrval) { | |
| 1508 | ValueDecl *value_decl = stmt->getDecl(); | |
| 1509 | Buf *symbol_name = buf_create_from_str(decl_name(value_decl)); | |
| 1510 | if (lrval == TransLValue) { | |
| 1511 | c->ptr_params.put(symbol_name, true); | |
| 1512 | } | |
| 1513 | return trans_create_node_symbol(c, symbol_name); | |
| 1514 | } | |
| 1515 | ||
| 1516 | static AstNode *trans_create_post_crement(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt, BinOpType assign_op) { | |
| 1517 | Expr *op_expr = stmt->getSubExpr(); | |
| 1518 | ||
| 1519 | if (!result_used) { | |
| 1520 | // common case | |
| 1521 | // c: expr++ | |
| 1522 | // zig: expr += 1 | |
| 1523 | return trans_create_node_bin_op(c, | |
| 1524 | trans_expr(c, true, block, op_expr, TransLValue), | |
| 1525 | assign_op, | |
| 1526 | trans_create_node_unsigned(c, 1)); | |
| 1527 | } else { | |
| 1528 | // worst case | |
| 1529 | // c: expr++ | |
| 1530 | // zig: { | |
| 1531 | // zig: const _ref = &expr; | |
| 1532 | // zig: const _tmp = *_ref; | |
| 1533 | // zig: *_ref += 1; | |
| 1534 | // zig: _tmp | |
| 1535 | // zig: } | |
| 1536 | AstNode *child_block = trans_create_node(c, NodeTypeBlock); | |
| 1537 | ||
| 1538 | // const _ref = &expr; | |
| 1539 | AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue); | |
| 1540 | if (expr == nullptr) return nullptr; | |
| 1541 | AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr); | |
| 1542 | // TODO: avoid name collisions with generated variable names | |
| 1543 | Buf* ref_var_name = buf_create_from_str("_ref"); | |
| 1544 | AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr); | |
| 1545 | child_block->data.block.statements.append(ref_var_decl); | |
| 1546 | ||
| 1547 | // const _tmp = *_ref; | |
| 1548 | Buf* tmp_var_name = buf_create_from_str("_tmp"); | |
| 1549 | AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr, | |
| 1550 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1551 | trans_create_node_symbol(c, ref_var_name))); | |
| 1552 | child_block->data.block.statements.append(tmp_var_decl); | |
| 1553 | ||
| 1554 | // *_ref += 1; | |
| 1555 | AstNode *assign_statement = trans_create_node_bin_op(c, | |
| 1556 | trans_create_node_prefix_op(c, PrefixOpDereference, | |
| 1557 | trans_create_node_symbol(c, ref_var_name)), | |
| 1558 | assign_op, | |
| 1559 | trans_create_node_unsigned(c, 1)); | |
| 1560 | child_block->data.block.statements.append(assign_statement); | |
| 1561 | ||
| 1562 | // _tmp | |
| 1563 | child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name)); | |
| 1564 | child_block->data.block.last_statement_is_result_expression = true; | |
| 1565 | ||
| 1566 | return child_block; | |
| 1567 | } | |
| 1568 | } | |
| 1569 | ||
| 1570 | static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) { | |
| 1571 | switch (stmt->getOpcode()) { | |
| 1572 | case UO_PostInc: | |
| 1573 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1574 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlusWrap); | |
| 1575 | else | |
| 1576 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignPlus); | |
| 1577 | case UO_PostDec: | |
| 1578 | if (qual_type_has_wrapping_overflow(c, stmt->getType())) | |
| 1579 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinusWrap); | |
| 1580 | else | |
| 1581 | return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus); | |
| 1582 | case UO_PreInc: | |
| 1583 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreInc"); | |
| 1584 | return nullptr; | |
| 1585 | case UO_PreDec: | |
| 1586 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreDec"); | |
| 1587 | return nullptr; | |
| 1588 | case UO_AddrOf: | |
| 1589 | { | |
| 1590 | AstNode *value_node = trans_expr(c, result_used, block, stmt->getSubExpr(), TransLValue); | |
| 1591 | if (value_node == nullptr) | |
| 1592 | return value_node; | |
| 1593 | return trans_create_node_addr_of(c, false, false, value_node); | |
| 1594 | } | |
| 1595 | case UO_Deref: | |
| 1596 | { | |
| 1597 | AstNode *value_node = trans_expr(c, result_used, block, stmt->getSubExpr(), TransRValue); | |
| 1598 | if (value_node == nullptr) | |
| 1599 | return nullptr; | |
| 1600 | bool is_fn_ptr = qual_type_is_fn_ptr(c, stmt->getSubExpr()->getType()); | |
| 1601 | if (is_fn_ptr) | |
| 1602 | return value_node; | |
| 1603 | AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node); | |
| 1604 | return trans_create_node_prefix_op(c, PrefixOpDereference, unwrapped); | |
| 1605 | } | |
| 1606 | case UO_Plus: | |
| 1607 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Plus"); | |
| 1608 | return nullptr; | |
| 1609 | case UO_Minus: | |
| 1610 | { | |
| 1611 | Expr *op_expr = stmt->getSubExpr(); | |
| 1612 | if (!qual_type_has_wrapping_overflow(c, op_expr->getType())) { | |
| 1613 | AstNode *node = trans_create_node(c, NodeTypePrefixOpExpr); | |
| 1614 | node->data.prefix_op_expr.prefix_op = PrefixOpNegation; | |
| 1615 | ||
| 1616 | node->data.prefix_op_expr.primary_expr = trans_expr(c, true, block, op_expr, TransRValue); | |
| 1617 | if (node->data.prefix_op_expr.primary_expr == nullptr) | |
| 1618 | return nullptr; | |
| 1619 | ||
| 1620 | return node; | |
| 1621 | } else if (c_is_unsigned_integer(c, op_expr->getType())) { | |
| 1622 | // we gotta emit 0 -% x | |
| 1623 | AstNode *node = trans_create_node(c, NodeTypeBinOpExpr); | |
| 1624 | node->data.bin_op_expr.op1 = trans_create_node_unsigned(c, 0); | |
| 1625 | ||
| 1626 | node->data.bin_op_expr.op2 = trans_expr(c, true, block, op_expr, TransRValue); | |
| 1627 | if (node->data.bin_op_expr.op2 == nullptr) | |
| 1628 | return nullptr; | |
| 1629 | ||
| 1630 | node->data.bin_op_expr.bin_op = BinOpTypeSubWrap; | |
| 1631 | return node; | |
| 1632 | } else { | |
| 1633 | emit_warning(c, stmt->getLocStart(), "C negation with non float non integer"); | |
| 1634 | return nullptr; | |
| 1635 | } | |
| 1636 | } | |
| 1637 | case UO_Not: | |
| 1638 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Not"); | |
| 1639 | return nullptr; | |
| 1640 | case UO_LNot: | |
| 1641 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_LNot"); | |
| 1642 | return nullptr; | |
| 1643 | case UO_Real: | |
| 1644 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Real"); | |
| 1645 | return nullptr; | |
| 1646 | case UO_Imag: | |
| 1647 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Imag"); | |
| 1648 | return nullptr; | |
| 1649 | case UO_Extension: | |
| 1650 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Extension"); | |
| 1651 | return nullptr; | |
| 1652 | case UO_Coawait: | |
| 1653 | emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_Coawait"); | |
| 1654 | return nullptr; | |
| 1655 | } | |
| 1656 | zig_unreachable(); | |
| 1657 | } | |
| 1658 | ||
| 1659 | static AstNode *trans_local_declaration(Context *c, AstNode *block, DeclStmt *stmt) { | |
| 1660 | for (auto iter = stmt->decl_begin(); iter != stmt->decl_end(); iter++) { | |
| 1661 | Decl *decl = *iter; | |
| 1662 | switch (decl->getKind()) { | |
| 1663 | case Decl::Var: { | |
| 1664 | VarDecl *var_decl = (VarDecl *)decl; | |
| 1665 | QualType qual_type = var_decl->getTypeSourceInfo()->getType(); | |
| 1666 | AstNode *init_node = nullptr; | |
| 1667 | if (var_decl->hasInit()) { | |
| 1668 | init_node = trans_expr(c, true, block, var_decl->getInit(), TransRValue); | |
| 1669 | if (init_node == nullptr) | |
| 1670 | return nullptr; | |
| 1671 | ||
| 1672 | } | |
| 1673 | AstNode *type_node = trans_qual_type(c, qual_type, stmt->getLocStart()); | |
| 1674 | if (type_node == nullptr) | |
| 1675 | return nullptr; | |
| 1676 | ||
| 1677 | Buf *symbol_name = buf_create_from_str(decl_name(var_decl)); | |
| 1678 | ||
| 1679 | AstNode *node = trans_create_node_var_decl_local(c, qual_type.isConstQualified(), | |
| 1680 | symbol_name, type_node, init_node); | |
| 1681 | block->data.block.statements.append(node); | |
| 1682 | continue; | |
| 1683 | } | |
| 1684 | case Decl::AccessSpec: | |
| 1685 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind AccessSpec"); | |
| 1686 | return nullptr; | |
| 1687 | case Decl::Block: | |
| 1688 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Block"); | |
| 1689 | return nullptr; | |
| 1690 | case Decl::Captured: | |
| 1691 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Captured"); | |
| 1692 | return nullptr; | |
| 1693 | case Decl::ClassScopeFunctionSpecialization: | |
| 1694 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassScopeFunctionSpecialization"); | |
| 1695 | return nullptr; | |
| 1696 | case Decl::Empty: | |
| 1697 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Empty"); | |
| 1698 | return nullptr; | |
| 1699 | case Decl::Export: | |
| 1700 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Export"); | |
| 1701 | return nullptr; | |
| 1702 | case Decl::ExternCContext: | |
| 1703 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ExternCContext"); | |
| 1704 | return nullptr; | |
| 1705 | case Decl::FileScopeAsm: | |
| 1706 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FileScopeAsm"); | |
| 1707 | return nullptr; | |
| 1708 | case Decl::Friend: | |
| 1709 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Friend"); | |
| 1710 | return nullptr; | |
| 1711 | case Decl::FriendTemplate: | |
| 1712 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FriendTemplate"); | |
| 1713 | return nullptr; | |
| 1714 | case Decl::Import: | |
| 1715 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Import"); | |
| 1716 | return nullptr; | |
| 1717 | case Decl::LinkageSpec: | |
| 1718 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind LinkageSpec"); | |
| 1719 | return nullptr; | |
| 1720 | case Decl::Label: | |
| 1721 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Label"); | |
| 1722 | return nullptr; | |
| 1723 | case Decl::Namespace: | |
| 1724 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Namespace"); | |
| 1725 | return nullptr; | |
| 1726 | case Decl::NamespaceAlias: | |
| 1727 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind NamespaceAlias"); | |
| 1728 | return nullptr; | |
| 1729 | case Decl::ObjCCompatibleAlias: | |
| 1730 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCompatibleAlias"); | |
| 1731 | return nullptr; | |
| 1732 | case Decl::ObjCCategory: | |
| 1733 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCategory"); | |
| 1734 | return nullptr; | |
| 1735 | case Decl::ObjCCategoryImpl: | |
| 1736 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCCategoryImpl"); | |
| 1737 | return nullptr; | |
| 1738 | case Decl::ObjCImplementation: | |
| 1739 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCImplementation"); | |
| 1740 | return nullptr; | |
| 1741 | case Decl::ObjCInterface: | |
| 1742 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCInterface"); | |
| 1743 | return nullptr; | |
| 1744 | case Decl::ObjCProtocol: | |
| 1745 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCProtocol"); | |
| 1746 | return nullptr; | |
| 1747 | case Decl::ObjCMethod: | |
| 1748 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCMethod"); | |
| 1749 | return nullptr; | |
| 1750 | case Decl::ObjCProperty: | |
| 1751 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCProperty"); | |
| 1752 | return nullptr; | |
| 1753 | case Decl::BuiltinTemplate: | |
| 1754 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind BuiltinTemplate"); | |
| 1755 | return nullptr; | |
| 1756 | case Decl::ClassTemplate: | |
| 1757 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplate"); | |
| 1758 | return nullptr; | |
| 1759 | case Decl::FunctionTemplate: | |
| 1760 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind FunctionTemplate"); | |
| 1761 | return nullptr; | |
| 1762 | case Decl::TypeAliasTemplate: | |
| 1763 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TypeAliasTemplate"); | |
| 1764 | return nullptr; | |
| 1765 | case Decl::VarTemplate: | |
| 1766 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplate"); | |
| 1767 | return nullptr; | |
| 1768 | case Decl::TemplateTemplateParm: | |
| 1769 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TemplateTemplateParm"); | |
| 1770 | return nullptr; | |
| 1771 | case Decl::Enum: | |
| 1772 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Enum"); | |
| 1773 | return nullptr; | |
| 1774 | case Decl::Record: | |
| 1775 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Record"); | |
| 1776 | return nullptr; | |
| 1777 | case Decl::CXXRecord: | |
| 1778 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXRecord"); | |
| 1779 | return nullptr; | |
| 1780 | case Decl::ClassTemplateSpecialization: | |
| 1781 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplateSpecialization"); | |
| 1782 | return nullptr; | |
| 1783 | case Decl::ClassTemplatePartialSpecialization: | |
| 1784 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ClassTemplatePartialSpecialization"); | |
| 1785 | return nullptr; | |
| 1786 | case Decl::TemplateTypeParm: | |
| 1787 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TemplateTypeParm"); | |
| 1788 | return nullptr; | |
| 1789 | case Decl::ObjCTypeParam: | |
| 1790 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCTypeParam"); | |
| 1791 | return nullptr; | |
| 1792 | case Decl::TypeAlias: | |
| 1793 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TypeAlias"); | |
| 1794 | return nullptr; | |
| 1795 | case Decl::Typedef: | |
| 1796 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Typedef"); | |
| 1797 | return nullptr; | |
| 1798 | case Decl::UnresolvedUsingTypename: | |
| 1799 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UnresolvedUsingTypename"); | |
| 1800 | return nullptr; | |
| 1801 | case Decl::Using: | |
| 1802 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Using"); | |
| 1803 | return nullptr; | |
| 1804 | case Decl::UsingDirective: | |
| 1805 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingDirective"); | |
| 1806 | return nullptr; | |
| 1807 | case Decl::UsingPack: | |
| 1808 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingPack"); | |
| 1809 | return nullptr; | |
| 1810 | case Decl::UsingShadow: | |
| 1811 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UsingShadow"); | |
| 1812 | return nullptr; | |
| 1813 | case Decl::ConstructorUsingShadow: | |
| 1814 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ConstructorUsingShadow"); | |
| 1815 | return nullptr; | |
| 1816 | case Decl::Binding: | |
| 1817 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Binding"); | |
| 1818 | return nullptr; | |
| 1819 | case Decl::Field: | |
| 1820 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Field"); | |
| 1821 | return nullptr; | |
| 1822 | case Decl::ObjCAtDefsField: | |
| 1823 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCAtDefsField"); | |
| 1824 | return nullptr; | |
| 1825 | case Decl::ObjCIvar: | |
| 1826 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCIvar"); | |
| 1827 | return nullptr; | |
| 1828 | case Decl::Function: | |
| 1829 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Function"); | |
| 1830 | return nullptr; | |
| 1831 | case Decl::CXXDeductionGuide: | |
| 1832 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXDeductionGuide"); | |
| 1833 | return nullptr; | |
| 1834 | case Decl::CXXMethod: | |
| 1835 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXMethod"); | |
| 1836 | return nullptr; | |
| 1837 | case Decl::CXXConstructor: | |
| 1838 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXConstructor"); | |
| 1839 | return nullptr; | |
| 1840 | case Decl::CXXConversion: | |
| 1841 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXConversion"); | |
| 1842 | return nullptr; | |
| 1843 | case Decl::CXXDestructor: | |
| 1844 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind CXXDestructor"); | |
| 1845 | return nullptr; | |
| 1846 | case Decl::MSProperty: | |
| 1847 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind MSProperty"); | |
| 1848 | return nullptr; | |
| 1849 | case Decl::NonTypeTemplateParm: | |
| 1850 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind NonTypeTemplateParm"); | |
| 1851 | return nullptr; | |
| 1852 | case Decl::Decomposition: | |
| 1853 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind Decomposition"); | |
| 1854 | return nullptr; | |
| 1855 | case Decl::ImplicitParam: | |
| 1856 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ImplicitParam"); | |
| 1857 | return nullptr; | |
| 1858 | case Decl::OMPCapturedExpr: | |
| 1859 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPCapturedExpr"); | |
| 1860 | return nullptr; | |
| 1861 | case Decl::ParmVar: | |
| 1862 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ParmVar"); | |
| 1863 | return nullptr; | |
| 1864 | case Decl::VarTemplateSpecialization: | |
| 1865 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplateSpecialization"); | |
| 1866 | return nullptr; | |
| 1867 | case Decl::VarTemplatePartialSpecialization: | |
| 1868 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind VarTemplatePartialSpecialization"); | |
| 1869 | return nullptr; | |
| 1870 | case Decl::EnumConstant: | |
| 1871 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind EnumConstant"); | |
| 1872 | return nullptr; | |
| 1873 | case Decl::IndirectField: | |
| 1874 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind IndirectField"); | |
| 1875 | return nullptr; | |
| 1876 | case Decl::OMPDeclareReduction: | |
| 1877 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPDeclareReduction"); | |
| 1878 | return nullptr; | |
| 1879 | case Decl::UnresolvedUsingValue: | |
| 1880 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind UnresolvedUsingValue"); | |
| 1881 | return nullptr; | |
| 1882 | case Decl::OMPThreadPrivate: | |
| 1883 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind OMPThreadPrivate"); | |
| 1884 | return nullptr; | |
| 1885 | case Decl::ObjCPropertyImpl: | |
| 1886 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind ObjCPropertyImpl"); | |
| 1887 | return nullptr; | |
| 1888 | case Decl::PragmaComment: | |
| 1889 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind PragmaComment"); | |
| 1890 | return nullptr; | |
| 1891 | case Decl::PragmaDetectMismatch: | |
| 1892 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind PragmaDetectMismatch"); | |
| 1893 | return nullptr; | |
| 1894 | case Decl::StaticAssert: | |
| 1895 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind StaticAssert"); | |
| 1896 | return nullptr; | |
| 1897 | case Decl::TranslationUnit: | |
| 1898 | emit_warning(c, stmt->getLocStart(), "TODO handle decl kind TranslationUnit"); | |
| 1899 | return nullptr; | |
| 1900 | } | |
| 1901 | zig_unreachable(); | |
| 1902 | } | |
| 1903 | ||
| 1904 | // declarations were already added | |
| 1905 | return skip_add_to_block_node; | |
| 1906 | } | |
| 1907 | ||
| 1908 | static AstNode *trans_while_loop(Context *c, AstNode *block, WhileStmt *stmt) { | |
| 1909 | AstNode *while_node = trans_create_node(c, NodeTypeWhileExpr); | |
| 1910 | ||
| 1911 | while_node->data.while_expr.condition = trans_expr(c, true, block, stmt->getCond(), TransRValue); | |
| 1912 | if (while_node->data.while_expr.condition == nullptr) | |
| 1913 | return nullptr; | |
| 1914 | ||
| 1915 | while_node->data.while_expr.body = trans_stmt(c, false, block, stmt->getBody(), TransRValue); | |
| 1916 | if (while_node->data.while_expr.body == nullptr) | |
| 1917 | return nullptr; | |
| 1918 | ||
| 1919 | return while_node; | |
| 1920 | } | |
| 1921 | ||
| 1922 | static AstNode *trans_if_statement(Context *c, AstNode *block, IfStmt *stmt) { | |
| 1923 | // if (c) t | |
| 1924 | // if (c) t else e | |
| 1925 | AstNode *if_node = trans_create_node(c, NodeTypeIfBoolExpr); | |
| 1926 | ||
| 1927 | // TODO: condition != 0 | |
| 1928 | AstNode *condition_node = trans_expr(c, true, block, stmt->getCond(), TransRValue); | |
| 1929 | if (condition_node == nullptr) | |
| 1930 | return nullptr; | |
| 1931 | if_node->data.if_bool_expr.condition = condition_node; | |
| 1932 | ||
| 1933 | if_node->data.if_bool_expr.then_block = trans_stmt(c, false, block, stmt->getThen(), TransRValue); | |
| 1934 | if (if_node->data.if_bool_expr.then_block == nullptr) | |
| 1935 | return nullptr; | |
| 1936 | ||
| 1937 | if (stmt->getElse() != nullptr) { | |
| 1938 | if_node->data.if_bool_expr.else_node = trans_stmt(c, false, block, stmt->getElse(), TransRValue); | |
| 1939 | if (if_node->data.if_bool_expr.else_node == nullptr) | |
| 1940 | return nullptr; | |
| 1941 | } | |
| 1942 | ||
| 1943 | return if_node; | |
| 1944 | } | |
| 1945 | ||
| 1946 | static AstNode *trans_call_expr(Context *c, bool result_used, AstNode *block, CallExpr *stmt) { | |
| 1947 | AstNode *node = trans_create_node(c, NodeTypeFnCallExpr); | |
| 1948 | ||
| 1949 | AstNode *callee_raw_node = trans_expr(c, true, block, stmt->getCallee(), TransRValue); | |
| 1950 | if (callee_raw_node == nullptr) | |
| 1951 | return nullptr; | |
| 1952 | ||
| 1953 | AstNode *callee_node; | |
| 1954 | if (qual_type_is_fn_ptr(c, stmt->getCallee()->getType())) { | |
| 1955 | callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, callee_raw_node); | |
| 1956 | } else { | |
| 1957 | callee_node = callee_raw_node; | |
| 1958 | } | |
| 1959 | ||
| 1960 | node->data.fn_call_expr.fn_ref_expr = callee_node; | |
| 1961 | ||
| 1962 | unsigned num_args = stmt->getNumArgs(); | |
| 1963 | Expr **args = stmt->getArgs(); | |
| 1964 | for (unsigned i = 0; i < num_args; i += 1) { | |
| 1965 | AstNode *arg_node = trans_expr(c, true, block, args[i], TransRValue); | |
| 1966 | if (arg_node == nullptr) | |
| 1967 | return nullptr; | |
| 1968 | ||
| 1969 | node->data.fn_call_expr.params.append(arg_node); | |
| 1970 | } | |
| 1971 | ||
| 1972 | return node; | |
| 1973 | } | |
| 1974 | ||
| 1975 | static AstNode *trans_member_expr(Context *c, AstNode *block, MemberExpr *stmt) { | |
| 1976 | AstNode *container_node = trans_expr(c, true, block, stmt->getBase(), TransRValue); | |
| 1977 | if (container_node == nullptr) | |
| 1978 | return nullptr; | |
| 1979 | ||
| 1980 | if (stmt->isArrow()) { | |
| 1981 | container_node = trans_create_node_unwrap_null(c, container_node); | |
| 1982 | } | |
| 1983 | ||
| 1984 | const char *name = decl_name(stmt->getMemberDecl()); | |
| 1985 | ||
| 1986 | AstNode *node = trans_create_node_field_access_str(c, container_node, name); | |
| 1987 | return node; | |
| 1988 | } | |
| 1989 | ||
| 1990 | static AstNode *trans_array_subscript_expr(Context *c, AstNode *block, ArraySubscriptExpr *stmt) { | |
| 1991 | AstNode *container_node = trans_expr(c, true, block, stmt->getBase(), TransRValue); | |
| 1992 | if (container_node == nullptr) | |
| 1993 | return nullptr; | |
| 1994 | ||
| 1995 | AstNode *idx_node = trans_expr(c, true, block, stmt->getIdx(), TransRValue); | |
| 1996 | if (idx_node == nullptr) | |
| 1997 | return nullptr; | |
| 1998 | ||
| 1999 | ||
| 2000 | AstNode *node = trans_create_node(c, NodeTypeArrayAccessExpr); | |
| 2001 | node->data.array_access_expr.array_ref_expr = container_node; | |
| 2002 | node->data.array_access_expr.subscript = idx_node; | |
| 2003 | return node; | |
| 2004 | } | |
| 2005 | ||
| 2006 | static AstNode *trans_c_style_cast_expr(Context *c, bool result_used, AstNode *block, | |
| 2007 | CStyleCastExpr *stmt, TransLRValue lrvalue) | |
| 2008 | { | |
| 2009 | AstNode *sub_expr_node = trans_expr(c, result_used, block, stmt->getSubExpr(), lrvalue); | |
| 2010 | if (sub_expr_node == nullptr) | |
| 2011 | return nullptr; | |
| 2012 | ||
| 2013 | return trans_c_cast(c, stmt->getLocStart(), stmt->getType(), sub_expr_node); | |
| 2014 | } | |
| 2015 | ||
| 2016 | static AstNode *trans_unary_expr_or_type_trait_expr(Context *c, AstNode *block, UnaryExprOrTypeTraitExpr *stmt) { | |
| 2017 | AstNode *type_node = trans_qual_type(c, stmt->getTypeOfArgument(), stmt->getLocStart()); | |
| 2018 | if (type_node == nullptr) | |
| 2019 | return nullptr; | |
| 2020 | ||
| 2021 | AstNode *node = trans_create_node_builtin_fn_call_str(c, "sizeOf"); | |
| 2022 | node->data.fn_call_expr.params.append(type_node); | |
| 2023 | return node; | |
| 2024 | } | |
| 2025 | ||
| 2026 | static AstNode *trans_do_loop(Context *c, AstNode *block, DoStmt *stmt) { | |
| 2027 | stmt->getBody(); | |
| 2028 | stmt->getCond(); | |
| 2029 | ||
| 2030 | AstNode *while_node = trans_create_node(c, NodeTypeWhileExpr); | |
| 2031 | ||
| 2032 | AstNode *true_node = trans_create_node(c, NodeTypeBoolLiteral); | |
| 2033 | true_node->data.bool_literal.value = true; | |
| 2034 | while_node->data.while_expr.condition = true_node; | |
| 2035 | ||
| 2036 | AstNode *body_node; | |
| 2037 | if (stmt->getBody()->getStmtClass() == Stmt::CompoundStmtClass) { | |
| 2038 | // there's already a block in C, so we'll append our condition to it. | |
| 2039 | // c: do { | |
| 2040 | // c: a; | |
| 2041 | // c: b; | |
| 2042 | // c: } while(c); | |
| 2043 | // zig: while (true) { | |
| 2044 | // zig: a; | |
| 2045 | // zig: b; | |
| 2046 | // zig: if (!cond) break; | |
| 2047 | // zig: } | |
| 2048 | body_node = trans_stmt(c, false, block, stmt->getBody(), TransRValue); | |
| 2049 | if (body_node == nullptr) return nullptr; | |
| 2050 | assert(body_node->type == NodeTypeBlock); | |
| 2051 | } else { | |
| 2052 | // the C statement is without a block, so we need to create a block to contain it. | |
| 2053 | // c: do | |
| 2054 | // c: a; | |
| 2055 | // c: while(c); | |
| 2056 | // zig: while (true) { | |
| 2057 | // zig: a; | |
| 2058 | // zig: if (!cond) break; | |
| 2059 | // zig: } | |
| 2060 | body_node = trans_create_node(c, NodeTypeBlock); | |
| 2061 | AstNode *child_statement = trans_stmt(c, false, body_node, stmt->getBody(), TransRValue); | |
| 2062 | if (child_statement == nullptr) return nullptr; | |
| 2063 | body_node->data.block.statements.append(child_statement); | |
| 2064 | } | |
| 2065 | ||
| 2066 | // if (!cond) break; | |
| 2067 | AstNode *condition_node = trans_expr(c, true, body_node, stmt->getCond(), TransRValue); | |
| 2068 | if (condition_node == nullptr) return nullptr; | |
| 2069 | AstNode *terminator_node = trans_create_node(c, NodeTypeIfBoolExpr); | |
| 2070 | terminator_node->data.if_bool_expr.condition = trans_create_node_prefix_op(c, PrefixOpBoolNot, condition_node); | |
| 2071 | terminator_node->data.if_bool_expr.then_block = trans_create_node(c, NodeTypeBreak); | |
| 2072 | body_node->data.block.statements.append(terminator_node); | |
| 2073 | ||
| 2074 | while_node->data.while_expr.body = body_node; | |
| 2075 | ||
| 2076 | return while_node; | |
| 2077 | } | |
| 2078 | ||
| 2079 | static AstNode *trans_stmt(Context *c, bool result_used, AstNode *block, Stmt *stmt, TransLRValue lrvalue) { | |
| 2080 | Stmt::StmtClass sc = stmt->getStmtClass(); | |
| 2081 | switch (sc) { | |
| 2082 | case Stmt::ReturnStmtClass: | |
| 2083 | return trans_return_stmt(c, block, (ReturnStmt *)stmt); | |
| 2084 | case Stmt::CompoundStmtClass: | |
| 2085 | return trans_compound_stmt(c, block, (CompoundStmt *)stmt); | |
| 2086 | case Stmt::IntegerLiteralClass: | |
| 2087 | return trans_integer_literal(c, (IntegerLiteral *)stmt); | |
| 2088 | case Stmt::ConditionalOperatorClass: | |
| 2089 | return trans_conditional_operator(c, result_used, block, (ConditionalOperator *)stmt); | |
| 2090 | case Stmt::BinaryOperatorClass: | |
| 2091 | return trans_binary_operator(c, result_used, block, (BinaryOperator *)stmt); | |
| 2092 | case Stmt::CompoundAssignOperatorClass: | |
| 2093 | return trans_compound_assign_operator(c, result_used, block, (CompoundAssignOperator *)stmt); | |
| 2094 | case Stmt::ImplicitCastExprClass: | |
| 2095 | return trans_implicit_cast_expr(c, block, (ImplicitCastExpr *)stmt); | |
| 2096 | case Stmt::DeclRefExprClass: | |
| 2097 | return trans_decl_ref_expr(c, (DeclRefExpr *)stmt, lrvalue); | |
| 2098 | case Stmt::UnaryOperatorClass: | |
| 2099 | return trans_unary_operator(c, result_used, block, (UnaryOperator *)stmt); | |
| 2100 | case Stmt::DeclStmtClass: | |
| 2101 | return trans_local_declaration(c, block, (DeclStmt *)stmt); | |
| 2102 | case Stmt::WhileStmtClass: | |
| 2103 | return trans_while_loop(c, block, (WhileStmt *)stmt); | |
| 2104 | case Stmt::IfStmtClass: | |
| 2105 | return trans_if_statement(c, block, (IfStmt *)stmt); | |
| 2106 | case Stmt::CallExprClass: | |
| 2107 | return trans_call_expr(c, result_used, block, (CallExpr *)stmt); | |
| 2108 | case Stmt::NullStmtClass: | |
| 2109 | return skip_add_to_block_node; | |
| 2110 | case Stmt::MemberExprClass: | |
| 2111 | return trans_member_expr(c, block, (MemberExpr *)stmt); | |
| 2112 | case Stmt::ArraySubscriptExprClass: | |
| 2113 | return trans_array_subscript_expr(c, block, (ArraySubscriptExpr *)stmt); | |
| 2114 | case Stmt::CStyleCastExprClass: | |
| 2115 | return trans_c_style_cast_expr(c, result_used, block, (CStyleCastExpr *)stmt, lrvalue); | |
| 2116 | case Stmt::UnaryExprOrTypeTraitExprClass: | |
| 2117 | return trans_unary_expr_or_type_trait_expr(c, block, (UnaryExprOrTypeTraitExpr *)stmt); | |
| 2118 | case Stmt::DoStmtClass: | |
| 2119 | return trans_do_loop(c, block, (DoStmt *)stmt); | |
| 2120 | case Stmt::CaseStmtClass: | |
| 2121 | emit_warning(c, stmt->getLocStart(), "TODO handle C CaseStmtClass"); | |
| 2122 | return nullptr; | |
| 2123 | case Stmt::DefaultStmtClass: | |
| 2124 | emit_warning(c, stmt->getLocStart(), "TODO handle C DefaultStmtClass"); | |
| 2125 | return nullptr; | |
| 2126 | case Stmt::SwitchStmtClass: | |
| 2127 | emit_warning(c, stmt->getLocStart(), "TODO handle C SwitchStmtClass"); | |
| 2128 | return nullptr; | |
| 2129 | case Stmt::NoStmtClass: | |
| 2130 | emit_warning(c, stmt->getLocStart(), "TODO handle C NoStmtClass"); | |
| 2131 | return nullptr; | |
| 2132 | case Stmt::GCCAsmStmtClass: | |
| 2133 | emit_warning(c, stmt->getLocStart(), "TODO handle C GCCAsmStmtClass"); | |
| 2134 | return nullptr; | |
| 2135 | case Stmt::MSAsmStmtClass: | |
| 2136 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSAsmStmtClass"); | |
| 2137 | return nullptr; | |
| 2138 | case Stmt::AttributedStmtClass: | |
| 2139 | emit_warning(c, stmt->getLocStart(), "TODO handle C AttributedStmtClass"); | |
| 2140 | return nullptr; | |
| 2141 | case Stmt::BreakStmtClass: | |
| 2142 | emit_warning(c, stmt->getLocStart(), "TODO handle C BreakStmtClass"); | |
| 2143 | return nullptr; | |
| 2144 | case Stmt::CXXCatchStmtClass: | |
| 2145 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXCatchStmtClass"); | |
| 2146 | return nullptr; | |
| 2147 | case Stmt::CXXForRangeStmtClass: | |
| 2148 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXForRangeStmtClass"); | |
| 2149 | return nullptr; | |
| 2150 | case Stmt::CXXTryStmtClass: | |
| 2151 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTryStmtClass"); | |
| 2152 | return nullptr; | |
| 2153 | case Stmt::CapturedStmtClass: | |
| 2154 | emit_warning(c, stmt->getLocStart(), "TODO handle C CapturedStmtClass"); | |
| 2155 | return nullptr; | |
| 2156 | case Stmt::ContinueStmtClass: | |
| 2157 | emit_warning(c, stmt->getLocStart(), "TODO handle C ContinueStmtClass"); | |
| 2158 | return nullptr; | |
| 2159 | case Stmt::CoreturnStmtClass: | |
| 2160 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoreturnStmtClass"); | |
| 2161 | return nullptr; | |
| 2162 | case Stmt::CoroutineBodyStmtClass: | |
| 2163 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoroutineBodyStmtClass"); | |
| 2164 | return nullptr; | |
| 2165 | case Stmt::BinaryConditionalOperatorClass: | |
| 2166 | emit_warning(c, stmt->getLocStart(), "TODO handle C BinaryConditionalOperatorClass"); | |
| 2167 | return nullptr; | |
| 2168 | case Stmt::AddrLabelExprClass: | |
| 2169 | emit_warning(c, stmt->getLocStart(), "TODO handle C AddrLabelExprClass"); | |
| 2170 | return nullptr; | |
| 2171 | case Stmt::ArrayInitIndexExprClass: | |
| 2172 | emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitIndexExprClass"); | |
| 2173 | return nullptr; | |
| 2174 | case Stmt::ArrayInitLoopExprClass: | |
| 2175 | emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayInitLoopExprClass"); | |
| 2176 | return nullptr; | |
| 2177 | case Stmt::ArrayTypeTraitExprClass: | |
| 2178 | emit_warning(c, stmt->getLocStart(), "TODO handle C ArrayTypeTraitExprClass"); | |
| 2179 | return nullptr; | |
| 2180 | case Stmt::AsTypeExprClass: | |
| 2181 | emit_warning(c, stmt->getLocStart(), "TODO handle C AsTypeExprClass"); | |
| 2182 | return nullptr; | |
| 2183 | case Stmt::AtomicExprClass: | |
| 2184 | emit_warning(c, stmt->getLocStart(), "TODO handle C AtomicExprClass"); | |
| 2185 | return nullptr; | |
| 2186 | case Stmt::BlockExprClass: | |
| 2187 | emit_warning(c, stmt->getLocStart(), "TODO handle C BlockExprClass"); | |
| 2188 | return nullptr; | |
| 2189 | case Stmt::CXXBindTemporaryExprClass: | |
| 2190 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXBindTemporaryExprClass"); | |
| 2191 | return nullptr; | |
| 2192 | case Stmt::CXXBoolLiteralExprClass: | |
| 2193 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXBoolLiteralExprClass"); | |
| 2194 | return nullptr; | |
| 2195 | case Stmt::CXXConstructExprClass: | |
| 2196 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXConstructExprClass"); | |
| 2197 | return nullptr; | |
| 2198 | case Stmt::CXXTemporaryObjectExprClass: | |
| 2199 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTemporaryObjectExprClass"); | |
| 2200 | return nullptr; | |
| 2201 | case Stmt::CXXDefaultArgExprClass: | |
| 2202 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDefaultArgExprClass"); | |
| 2203 | return nullptr; | |
| 2204 | case Stmt::CXXDefaultInitExprClass: | |
| 2205 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDefaultInitExprClass"); | |
| 2206 | return nullptr; | |
| 2207 | case Stmt::CXXDeleteExprClass: | |
| 2208 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDeleteExprClass"); | |
| 2209 | return nullptr; | |
| 2210 | case Stmt::CXXDependentScopeMemberExprClass: | |
| 2211 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDependentScopeMemberExprClass"); | |
| 2212 | return nullptr; | |
| 2213 | case Stmt::CXXFoldExprClass: | |
| 2214 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFoldExprClass"); | |
| 2215 | return nullptr; | |
| 2216 | case Stmt::CXXInheritedCtorInitExprClass: | |
| 2217 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXInheritedCtorInitExprClass"); | |
| 2218 | return nullptr; | |
| 2219 | case Stmt::CXXNewExprClass: | |
| 2220 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNewExprClass"); | |
| 2221 | return nullptr; | |
| 2222 | case Stmt::CXXNoexceptExprClass: | |
| 2223 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNoexceptExprClass"); | |
| 2224 | return nullptr; | |
| 2225 | case Stmt::CXXNullPtrLiteralExprClass: | |
| 2226 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXNullPtrLiteralExprClass"); | |
| 2227 | return nullptr; | |
| 2228 | case Stmt::CXXPseudoDestructorExprClass: | |
| 2229 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXPseudoDestructorExprClass"); | |
| 2230 | return nullptr; | |
| 2231 | case Stmt::CXXScalarValueInitExprClass: | |
| 2232 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXScalarValueInitExprClass"); | |
| 2233 | return nullptr; | |
| 2234 | case Stmt::CXXStdInitializerListExprClass: | |
| 2235 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXStdInitializerListExprClass"); | |
| 2236 | return nullptr; | |
| 2237 | case Stmt::CXXThisExprClass: | |
| 2238 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXThisExprClass"); | |
| 2239 | return nullptr; | |
| 2240 | case Stmt::CXXThrowExprClass: | |
| 2241 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXThrowExprClass"); | |
| 2242 | return nullptr; | |
| 2243 | case Stmt::CXXTypeidExprClass: | |
| 2244 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXTypeidExprClass"); | |
| 2245 | return nullptr; | |
| 2246 | case Stmt::CXXUnresolvedConstructExprClass: | |
| 2247 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUnresolvedConstructExprClass"); | |
| 2248 | return nullptr; | |
| 2249 | case Stmt::CXXUuidofExprClass: | |
| 2250 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXUuidofExprClass"); | |
| 2251 | return nullptr; | |
| 2252 | case Stmt::CUDAKernelCallExprClass: | |
| 2253 | emit_warning(c, stmt->getLocStart(), "TODO handle C CUDAKernelCallExprClass"); | |
| 2254 | return nullptr; | |
| 2255 | case Stmt::CXXMemberCallExprClass: | |
| 2256 | (void)result_used; | |
| 2257 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXMemberCallExprClass"); | |
| 2258 | return nullptr; | |
| 2259 | case Stmt::CXXOperatorCallExprClass: | |
| 2260 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXOperatorCallExprClass"); | |
| 2261 | return nullptr; | |
| 2262 | case Stmt::UserDefinedLiteralClass: | |
| 2263 | emit_warning(c, stmt->getLocStart(), "TODO handle C UserDefinedLiteralClass"); | |
| 2264 | return nullptr; | |
| 2265 | case Stmt::CXXFunctionalCastExprClass: | |
| 2266 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXFunctionalCastExprClass"); | |
| 2267 | return nullptr; | |
| 2268 | case Stmt::CXXConstCastExprClass: | |
| 2269 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXConstCastExprClass"); | |
| 2270 | return nullptr; | |
| 2271 | case Stmt::CXXDynamicCastExprClass: | |
| 2272 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXDynamicCastExprClass"); | |
| 2273 | return nullptr; | |
| 2274 | case Stmt::CXXReinterpretCastExprClass: | |
| 2275 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXReinterpretCastExprClass"); | |
| 2276 | return nullptr; | |
| 2277 | case Stmt::CXXStaticCastExprClass: | |
| 2278 | emit_warning(c, stmt->getLocStart(), "TODO handle C CXXStaticCastExprClass"); | |
| 2279 | return nullptr; | |
| 2280 | case Stmt::ObjCBridgedCastExprClass: | |
| 2281 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBridgedCastExprClass"); | |
| 2282 | return nullptr; | |
| 2283 | case Stmt::CharacterLiteralClass: | |
| 2284 | emit_warning(c, stmt->getLocStart(), "TODO handle C CharacterLiteralClass"); | |
| 2285 | return nullptr; | |
| 2286 | case Stmt::ChooseExprClass: | |
| 2287 | emit_warning(c, stmt->getLocStart(), "TODO handle C ChooseExprClass"); | |
| 2288 | return nullptr; | |
| 2289 | case Stmt::CompoundLiteralExprClass: | |
| 2290 | emit_warning(c, stmt->getLocStart(), "TODO handle C CompoundLiteralExprClass"); | |
| 2291 | return nullptr; | |
| 2292 | case Stmt::ConvertVectorExprClass: | |
| 2293 | emit_warning(c, stmt->getLocStart(), "TODO handle C ConvertVectorExprClass"); | |
| 2294 | return nullptr; | |
| 2295 | case Stmt::CoawaitExprClass: | |
| 2296 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoawaitExprClass"); | |
| 2297 | return nullptr; | |
| 2298 | case Stmt::CoyieldExprClass: | |
| 2299 | emit_warning(c, stmt->getLocStart(), "TODO handle C CoyieldExprClass"); | |
| 2300 | return nullptr; | |
| 2301 | case Stmt::DependentCoawaitExprClass: | |
| 2302 | emit_warning(c, stmt->getLocStart(), "TODO handle C DependentCoawaitExprClass"); | |
| 2303 | return nullptr; | |
| 2304 | case Stmt::DependentScopeDeclRefExprClass: | |
| 2305 | emit_warning(c, stmt->getLocStart(), "TODO handle C DependentScopeDeclRefExprClass"); | |
| 2306 | return nullptr; | |
| 2307 | case Stmt::DesignatedInitExprClass: | |
| 2308 | emit_warning(c, stmt->getLocStart(), "TODO handle C DesignatedInitExprClass"); | |
| 2309 | return nullptr; | |
| 2310 | case Stmt::DesignatedInitUpdateExprClass: | |
| 2311 | emit_warning(c, stmt->getLocStart(), "TODO handle C DesignatedInitUpdateExprClass"); | |
| 2312 | return nullptr; | |
| 2313 | case Stmt::ExprWithCleanupsClass: | |
| 2314 | emit_warning(c, stmt->getLocStart(), "TODO handle C ExprWithCleanupsClass"); | |
| 2315 | return nullptr; | |
| 2316 | case Stmt::ExpressionTraitExprClass: | |
| 2317 | emit_warning(c, stmt->getLocStart(), "TODO handle C ExpressionTraitExprClass"); | |
| 2318 | return nullptr; | |
| 2319 | case Stmt::ExtVectorElementExprClass: | |
| 2320 | emit_warning(c, stmt->getLocStart(), "TODO handle C ExtVectorElementExprClass"); | |
| 2321 | return nullptr; | |
| 2322 | case Stmt::FloatingLiteralClass: | |
| 2323 | emit_warning(c, stmt->getLocStart(), "TODO handle C FloatingLiteralClass"); | |
| 2324 | return nullptr; | |
| 2325 | case Stmt::FunctionParmPackExprClass: | |
| 2326 | emit_warning(c, stmt->getLocStart(), "TODO handle C FunctionParmPackExprClass"); | |
| 2327 | return nullptr; | |
| 2328 | case Stmt::GNUNullExprClass: | |
| 2329 | emit_warning(c, stmt->getLocStart(), "TODO handle C GNUNullExprClass"); | |
| 2330 | return nullptr; | |
| 2331 | case Stmt::GenericSelectionExprClass: | |
| 2332 | emit_warning(c, stmt->getLocStart(), "TODO handle C GenericSelectionExprClass"); | |
| 2333 | return nullptr; | |
| 2334 | case Stmt::ImaginaryLiteralClass: | |
| 2335 | emit_warning(c, stmt->getLocStart(), "TODO handle C ImaginaryLiteralClass"); | |
| 2336 | return nullptr; | |
| 2337 | case Stmt::ImplicitValueInitExprClass: | |
| 2338 | emit_warning(c, stmt->getLocStart(), "TODO handle C ImplicitValueInitExprClass"); | |
| 2339 | return nullptr; | |
| 2340 | case Stmt::InitListExprClass: | |
| 2341 | emit_warning(c, stmt->getLocStart(), "TODO handle C InitListExprClass"); | |
| 2342 | return nullptr; | |
| 2343 | case Stmt::LambdaExprClass: | |
| 2344 | emit_warning(c, stmt->getLocStart(), "TODO handle C LambdaExprClass"); | |
| 2345 | return nullptr; | |
| 2346 | case Stmt::MSPropertyRefExprClass: | |
| 2347 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSPropertyRefExprClass"); | |
| 2348 | return nullptr; | |
| 2349 | case Stmt::MSPropertySubscriptExprClass: | |
| 2350 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSPropertySubscriptExprClass"); | |
| 2351 | return nullptr; | |
| 2352 | case Stmt::MaterializeTemporaryExprClass: | |
| 2353 | emit_warning(c, stmt->getLocStart(), "TODO handle C MaterializeTemporaryExprClass"); | |
| 2354 | return nullptr; | |
| 2355 | case Stmt::NoInitExprClass: | |
| 2356 | emit_warning(c, stmt->getLocStart(), "TODO handle C NoInitExprClass"); | |
| 2357 | return nullptr; | |
| 2358 | case Stmt::OMPArraySectionExprClass: | |
| 2359 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPArraySectionExprClass"); | |
| 2360 | return nullptr; | |
| 2361 | case Stmt::ObjCArrayLiteralClass: | |
| 2362 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCArrayLiteralClass"); | |
| 2363 | return nullptr; | |
| 2364 | case Stmt::ObjCAvailabilityCheckExprClass: | |
| 2365 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAvailabilityCheckExprClass"); | |
| 2366 | return nullptr; | |
| 2367 | case Stmt::ObjCBoolLiteralExprClass: | |
| 2368 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBoolLiteralExprClass"); | |
| 2369 | return nullptr; | |
| 2370 | case Stmt::ObjCBoxedExprClass: | |
| 2371 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCBoxedExprClass"); | |
| 2372 | return nullptr; | |
| 2373 | case Stmt::ObjCDictionaryLiteralClass: | |
| 2374 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCDictionaryLiteralClass"); | |
| 2375 | return nullptr; | |
| 2376 | case Stmt::ObjCEncodeExprClass: | |
| 2377 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCEncodeExprClass"); | |
| 2378 | return nullptr; | |
| 2379 | case Stmt::ObjCIndirectCopyRestoreExprClass: | |
| 2380 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIndirectCopyRestoreExprClass"); | |
| 2381 | return nullptr; | |
| 2382 | case Stmt::ObjCIsaExprClass: | |
| 2383 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIsaExprClass"); | |
| 2384 | return nullptr; | |
| 2385 | case Stmt::ObjCIvarRefExprClass: | |
| 2386 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCIvarRefExprClass"); | |
| 2387 | return nullptr; | |
| 2388 | case Stmt::ObjCMessageExprClass: | |
| 2389 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCMessageExprClass"); | |
| 2390 | return nullptr; | |
| 2391 | case Stmt::ObjCPropertyRefExprClass: | |
| 2392 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCPropertyRefExprClass"); | |
| 2393 | return nullptr; | |
| 2394 | case Stmt::ObjCProtocolExprClass: | |
| 2395 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCProtocolExprClass"); | |
| 2396 | return nullptr; | |
| 2397 | case Stmt::ObjCSelectorExprClass: | |
| 2398 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCSelectorExprClass"); | |
| 2399 | return nullptr; | |
| 2400 | case Stmt::ObjCStringLiteralClass: | |
| 2401 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCStringLiteralClass"); | |
| 2402 | return nullptr; | |
| 2403 | case Stmt::ObjCSubscriptRefExprClass: | |
| 2404 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCSubscriptRefExprClass"); | |
| 2405 | return nullptr; | |
| 2406 | case Stmt::OffsetOfExprClass: | |
| 2407 | emit_warning(c, stmt->getLocStart(), "TODO handle C OffsetOfExprClass"); | |
| 2408 | return nullptr; | |
| 2409 | case Stmt::OpaqueValueExprClass: | |
| 2410 | emit_warning(c, stmt->getLocStart(), "TODO handle C OpaqueValueExprClass"); | |
| 2411 | return nullptr; | |
| 2412 | case Stmt::UnresolvedLookupExprClass: | |
| 2413 | emit_warning(c, stmt->getLocStart(), "TODO handle C UnresolvedLookupExprClass"); | |
| 2414 | return nullptr; | |
| 2415 | case Stmt::UnresolvedMemberExprClass: | |
| 2416 | emit_warning(c, stmt->getLocStart(), "TODO handle C UnresolvedMemberExprClass"); | |
| 2417 | return nullptr; | |
| 2418 | case Stmt::PackExpansionExprClass: | |
| 2419 | emit_warning(c, stmt->getLocStart(), "TODO handle C PackExpansionExprClass"); | |
| 2420 | return nullptr; | |
| 2421 | case Stmt::ParenExprClass: | |
| 2422 | return trans_expr(c, result_used, block, ((ParenExpr*)stmt)->getSubExpr(), lrvalue); | |
| 2423 | case Stmt::ParenListExprClass: | |
| 2424 | emit_warning(c, stmt->getLocStart(), "TODO handle C ParenListExprClass"); | |
| 2425 | return nullptr; | |
| 2426 | case Stmt::PredefinedExprClass: | |
| 2427 | emit_warning(c, stmt->getLocStart(), "TODO handle C PredefinedExprClass"); | |
| 2428 | return nullptr; | |
| 2429 | case Stmt::PseudoObjectExprClass: | |
| 2430 | emit_warning(c, stmt->getLocStart(), "TODO handle C PseudoObjectExprClass"); | |
| 2431 | return nullptr; | |
| 2432 | case Stmt::ShuffleVectorExprClass: | |
| 2433 | emit_warning(c, stmt->getLocStart(), "TODO handle C ShuffleVectorExprClass"); | |
| 2434 | return nullptr; | |
| 2435 | case Stmt::SizeOfPackExprClass: | |
| 2436 | emit_warning(c, stmt->getLocStart(), "TODO handle C SizeOfPackExprClass"); | |
| 2437 | return nullptr; | |
| 2438 | case Stmt::StmtExprClass: | |
| 2439 | emit_warning(c, stmt->getLocStart(), "TODO handle C StmtExprClass"); | |
| 2440 | return nullptr; | |
| 2441 | case Stmt::StringLiteralClass: | |
| 2442 | emit_warning(c, stmt->getLocStart(), "TODO handle C StringLiteralClass"); | |
| 2443 | return nullptr; | |
| 2444 | case Stmt::SubstNonTypeTemplateParmExprClass: | |
| 2445 | emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmExprClass"); | |
| 2446 | return nullptr; | |
| 2447 | case Stmt::SubstNonTypeTemplateParmPackExprClass: | |
| 2448 | emit_warning(c, stmt->getLocStart(), "TODO handle C SubstNonTypeTemplateParmPackExprClass"); | |
| 2449 | return nullptr; | |
| 2450 | case Stmt::TypeTraitExprClass: | |
| 2451 | emit_warning(c, stmt->getLocStart(), "TODO handle C TypeTraitExprClass"); | |
| 2452 | return nullptr; | |
| 2453 | case Stmt::TypoExprClass: | |
| 2454 | emit_warning(c, stmt->getLocStart(), "TODO handle C TypoExprClass"); | |
| 2455 | return nullptr; | |
| 2456 | case Stmt::VAArgExprClass: | |
| 2457 | emit_warning(c, stmt->getLocStart(), "TODO handle C VAArgExprClass"); | |
| 2458 | return nullptr; | |
| 2459 | case Stmt::ForStmtClass: | |
| 2460 | emit_warning(c, stmt->getLocStart(), "TODO handle C ForStmtClass"); | |
| 2461 | return nullptr; | |
| 2462 | case Stmt::GotoStmtClass: | |
| 2463 | emit_warning(c, stmt->getLocStart(), "TODO handle C GotoStmtClass"); | |
| 2464 | return nullptr; | |
| 2465 | case Stmt::IndirectGotoStmtClass: | |
| 2466 | emit_warning(c, stmt->getLocStart(), "TODO handle C IndirectGotoStmtClass"); | |
| 2467 | return nullptr; | |
| 2468 | case Stmt::LabelStmtClass: | |
| 2469 | emit_warning(c, stmt->getLocStart(), "TODO handle C LabelStmtClass"); | |
| 2470 | return nullptr; | |
| 2471 | case Stmt::MSDependentExistsStmtClass: | |
| 2472 | emit_warning(c, stmt->getLocStart(), "TODO handle C MSDependentExistsStmtClass"); | |
| 2473 | return nullptr; | |
| 2474 | case Stmt::OMPAtomicDirectiveClass: | |
| 2475 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPAtomicDirectiveClass"); | |
| 2476 | return nullptr; | |
| 2477 | case Stmt::OMPBarrierDirectiveClass: | |
| 2478 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPBarrierDirectiveClass"); | |
| 2479 | return nullptr; | |
| 2480 | case Stmt::OMPCancelDirectiveClass: | |
| 2481 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCancelDirectiveClass"); | |
| 2482 | return nullptr; | |
| 2483 | case Stmt::OMPCancellationPointDirectiveClass: | |
| 2484 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCancellationPointDirectiveClass"); | |
| 2485 | return nullptr; | |
| 2486 | case Stmt::OMPCriticalDirectiveClass: | |
| 2487 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPCriticalDirectiveClass"); | |
| 2488 | return nullptr; | |
| 2489 | case Stmt::OMPFlushDirectiveClass: | |
| 2490 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPFlushDirectiveClass"); | |
| 2491 | return nullptr; | |
| 2492 | case Stmt::OMPDistributeDirectiveClass: | |
| 2493 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeDirectiveClass"); | |
| 2494 | return nullptr; | |
| 2495 | case Stmt::OMPDistributeParallelForDirectiveClass: | |
| 2496 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeParallelForDirectiveClass"); | |
| 2497 | return nullptr; | |
| 2498 | case Stmt::OMPDistributeParallelForSimdDirectiveClass: | |
| 2499 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeParallelForSimdDirectiveClass"); | |
| 2500 | return nullptr; | |
| 2501 | case Stmt::OMPDistributeSimdDirectiveClass: | |
| 2502 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPDistributeSimdDirectiveClass"); | |
| 2503 | return nullptr; | |
| 2504 | case Stmt::OMPForDirectiveClass: | |
| 2505 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPForDirectiveClass"); | |
| 2506 | return nullptr; | |
| 2507 | case Stmt::OMPForSimdDirectiveClass: | |
| 2508 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPForSimdDirectiveClass"); | |
| 2509 | return nullptr; | |
| 2510 | case Stmt::OMPParallelForDirectiveClass: | |
| 2511 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelForDirectiveClass"); | |
| 2512 | return nullptr; | |
| 2513 | case Stmt::OMPParallelForSimdDirectiveClass: | |
| 2514 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelForSimdDirectiveClass"); | |
| 2515 | return nullptr; | |
| 2516 | case Stmt::OMPSimdDirectiveClass: | |
| 2517 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSimdDirectiveClass"); | |
| 2518 | return nullptr; | |
| 2519 | case Stmt::OMPTargetParallelForSimdDirectiveClass: | |
| 2520 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelForSimdDirectiveClass"); | |
| 2521 | return nullptr; | |
| 2522 | case Stmt::OMPTargetSimdDirectiveClass: | |
| 2523 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetSimdDirectiveClass"); | |
| 2524 | return nullptr; | |
| 2525 | case Stmt::OMPTargetTeamsDistributeDirectiveClass: | |
| 2526 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeDirectiveClass"); | |
| 2527 | return nullptr; | |
| 2528 | case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: | |
| 2529 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeParallelForDirectiveClass"); | |
| 2530 | return nullptr; | |
| 2531 | case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: | |
| 2532 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeParallelForSimdDirectiveClass"); | |
| 2533 | return nullptr; | |
| 2534 | case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: | |
| 2535 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDistributeSimdDirectiveClass"); | |
| 2536 | return nullptr; | |
| 2537 | case Stmt::OMPTaskLoopDirectiveClass: | |
| 2538 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskLoopDirectiveClass"); | |
| 2539 | return nullptr; | |
| 2540 | case Stmt::OMPTaskLoopSimdDirectiveClass: | |
| 2541 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskLoopSimdDirectiveClass"); | |
| 2542 | return nullptr; | |
| 2543 | case Stmt::OMPTeamsDistributeDirectiveClass: | |
| 2544 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeDirectiveClass"); | |
| 2545 | return nullptr; | |
| 2546 | case Stmt::OMPTeamsDistributeParallelForDirectiveClass: | |
| 2547 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeParallelForDirectiveClass"); | |
| 2548 | return nullptr; | |
| 2549 | case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: | |
| 2550 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeParallelForSimdDirectiveClass"); | |
| 2551 | return nullptr; | |
| 2552 | case Stmt::OMPTeamsDistributeSimdDirectiveClass: | |
| 2553 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDistributeSimdDirectiveClass"); | |
| 2554 | return nullptr; | |
| 2555 | case Stmt::OMPMasterDirectiveClass: | |
| 2556 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPMasterDirectiveClass"); | |
| 2557 | return nullptr; | |
| 2558 | case Stmt::OMPOrderedDirectiveClass: | |
| 2559 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPOrderedDirectiveClass"); | |
| 2560 | return nullptr; | |
| 2561 | case Stmt::OMPParallelDirectiveClass: | |
| 2562 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelDirectiveClass"); | |
| 2563 | return nullptr; | |
| 2564 | case Stmt::OMPParallelSectionsDirectiveClass: | |
| 2565 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPParallelSectionsDirectiveClass"); | |
| 2566 | return nullptr; | |
| 2567 | case Stmt::OMPSectionDirectiveClass: | |
| 2568 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSectionDirectiveClass"); | |
| 2569 | return nullptr; | |
| 2570 | case Stmt::OMPSectionsDirectiveClass: | |
| 2571 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSectionsDirectiveClass"); | |
| 2572 | return nullptr; | |
| 2573 | case Stmt::OMPSingleDirectiveClass: | |
| 2574 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPSingleDirectiveClass"); | |
| 2575 | return nullptr; | |
| 2576 | case Stmt::OMPTargetDataDirectiveClass: | |
| 2577 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetDataDirectiveClass"); | |
| 2578 | return nullptr; | |
| 2579 | case Stmt::OMPTargetDirectiveClass: | |
| 2580 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetDirectiveClass"); | |
| 2581 | return nullptr; | |
| 2582 | case Stmt::OMPTargetEnterDataDirectiveClass: | |
| 2583 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetEnterDataDirectiveClass"); | |
| 2584 | return nullptr; | |
| 2585 | case Stmt::OMPTargetExitDataDirectiveClass: | |
| 2586 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetExitDataDirectiveClass"); | |
| 2587 | return nullptr; | |
| 2588 | case Stmt::OMPTargetParallelDirectiveClass: | |
| 2589 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelDirectiveClass"); | |
| 2590 | return nullptr; | |
| 2591 | case Stmt::OMPTargetParallelForDirectiveClass: | |
| 2592 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetParallelForDirectiveClass"); | |
| 2593 | return nullptr; | |
| 2594 | case Stmt::OMPTargetTeamsDirectiveClass: | |
| 2595 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetTeamsDirectiveClass"); | |
| 2596 | return nullptr; | |
| 2597 | case Stmt::OMPTargetUpdateDirectiveClass: | |
| 2598 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTargetUpdateDirectiveClass"); | |
| 2599 | return nullptr; | |
| 2600 | case Stmt::OMPTaskDirectiveClass: | |
| 2601 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskDirectiveClass"); | |
| 2602 | return nullptr; | |
| 2603 | case Stmt::OMPTaskgroupDirectiveClass: | |
| 2604 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskgroupDirectiveClass"); | |
| 2605 | return nullptr; | |
| 2606 | case Stmt::OMPTaskwaitDirectiveClass: | |
| 2607 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskwaitDirectiveClass"); | |
| 2608 | return nullptr; | |
| 2609 | case Stmt::OMPTaskyieldDirectiveClass: | |
| 2610 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTaskyieldDirectiveClass"); | |
| 2611 | return nullptr; | |
| 2612 | case Stmt::OMPTeamsDirectiveClass: | |
| 2613 | emit_warning(c, stmt->getLocStart(), "TODO handle C OMPTeamsDirectiveClass"); | |
| 2614 | return nullptr; | |
| 2615 | case Stmt::ObjCAtCatchStmtClass: | |
| 2616 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtCatchStmtClass"); | |
| 2617 | return nullptr; | |
| 2618 | case Stmt::ObjCAtFinallyStmtClass: | |
| 2619 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtFinallyStmtClass"); | |
| 2620 | return nullptr; | |
| 2621 | case Stmt::ObjCAtSynchronizedStmtClass: | |
| 2622 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtSynchronizedStmtClass"); | |
| 2623 | return nullptr; | |
| 2624 | case Stmt::ObjCAtThrowStmtClass: | |
| 2625 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtThrowStmtClass"); | |
| 2626 | return nullptr; | |
| 2627 | case Stmt::ObjCAtTryStmtClass: | |
| 2628 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAtTryStmtClass"); | |
| 2629 | return nullptr; | |
| 2630 | case Stmt::ObjCAutoreleasePoolStmtClass: | |
| 2631 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCAutoreleasePoolStmtClass"); | |
| 2632 | return nullptr; | |
| 2633 | case Stmt::ObjCForCollectionStmtClass: | |
| 2634 | emit_warning(c, stmt->getLocStart(), "TODO handle C ObjCForCollectionStmtClass"); | |
| 2635 | return nullptr; | |
| 2636 | case Stmt::SEHExceptStmtClass: | |
| 2637 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHExceptStmtClass"); | |
| 2638 | return nullptr; | |
| 2639 | case Stmt::SEHFinallyStmtClass: | |
| 2640 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHFinallyStmtClass"); | |
| 2641 | return nullptr; | |
| 2642 | case Stmt::SEHLeaveStmtClass: | |
| 2643 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHLeaveStmtClass"); | |
| 2644 | return nullptr; | |
| 2645 | case Stmt::SEHTryStmtClass: | |
| 2646 | emit_warning(c, stmt->getLocStart(), "TODO handle C SEHTryStmtClass"); | |
| 2647 | return nullptr; | |
| 2648 | } | |
| 2649 | zig_unreachable(); | |
| 2650 | } | |
| 2651 | ||
| 2652 | static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) { | |
| 2653 | Buf *fn_name = buf_create_from_str(decl_name(fn_decl)); | |
| 2654 | ||
| 2655 | if (get_global(c, fn_name)) { | |
| 2656 | // we already saw this function | |
| 2657 | return; | |
| 2658 | } | |
| 2659 | ||
| 2660 | AstNode *proto_node = trans_qual_type(c, fn_decl->getType(), fn_decl->getLocation()); | |
| 2661 | if (proto_node == nullptr) { | |
| 2662 | emit_warning(c, fn_decl->getLocation(), "unable to resolve prototype of function '%s'", buf_ptr(fn_name)); | |
| 2663 | return; | |
| 2664 | } | |
| 2665 | ||
| 2666 | proto_node->data.fn_proto.name = fn_name; | |
| 2667 | proto_node->data.fn_proto.is_extern = !fn_decl->hasBody(); | |
| 2668 | ||
| 2669 | StorageClass sc = fn_decl->getStorageClass(); | |
| 2670 | if (sc == SC_None) { | |
| 2671 | proto_node->data.fn_proto.visib_mod = fn_decl->hasBody() ? c->export_visib_mod : c->visib_mod; | |
| 2672 | } else if (sc == SC_Extern || sc == SC_Static) { | |
| 2673 | proto_node->data.fn_proto.visib_mod = c->visib_mod; | |
| 2674 | } else if (sc == SC_PrivateExtern) { | |
| 2675 | emit_warning(c, fn_decl->getLocation(), "unsupported storage class: private extern"); | |
| 2676 | return; | |
| 2677 | } else { | |
| 2678 | emit_warning(c, fn_decl->getLocation(), "unsupported storage class: unknown"); | |
| 2679 | return; | |
| 2680 | } | |
| 2681 | ||
| 2682 | for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { | |
| 2683 | AstNode *param_node = proto_node->data.fn_proto.params.at(i); | |
| 2684 | const ParmVarDecl *param = fn_decl->getParamDecl(i); | |
| 2685 | const char *name = decl_name(param); | |
| 2686 | Buf *proto_param_name; | |
| 2687 | if (strlen(name) != 0) { | |
| 2688 | proto_param_name = buf_create_from_str(name); | |
| 2689 | } else { | |
| 2690 | proto_param_name = param_node->data.param_decl.name; | |
| 2691 | if (proto_param_name == nullptr) { | |
| 2692 | proto_param_name = buf_sprintf("arg%" ZIG_PRI_usize "", i); | |
| 2693 | } | |
| 2694 | } | |
| 2695 | param_node->data.param_decl.name = proto_param_name; | |
| 2696 | } | |
| 2697 | ||
| 2698 | if (!fn_decl->hasBody()) { | |
| 2699 | // just a prototype | |
| 2700 | add_top_level_decl(c, proto_node->data.fn_proto.name, proto_node); | |
| 2701 | return; | |
| 2702 | } | |
| 2703 | ||
| 2704 | // actual function definition with body | |
| 2705 | c->ptr_params.clear(); | |
| 2706 | Stmt *body = fn_decl->getBody(); | |
| 2707 | AstNode *actual_body_node = trans_stmt(c, false, nullptr, body, TransRValue); | |
| 2708 | assert(actual_body_node != skip_add_to_block_node); | |
| 2709 | if (actual_body_node == nullptr) { | |
| 2710 | emit_warning(c, fn_decl->getLocation(), "unable to translate function"); | |
| 2711 | return; | |
| 2712 | } | |
| 2713 | ||
| 2714 | // it worked | |
| 2715 | ||
| 2716 | assert(actual_body_node->type == NodeTypeBlock); | |
| 2717 | AstNode *body_node_with_param_inits = trans_create_node(c, NodeTypeBlock); | |
| 2718 | ||
| 2719 | for (size_t i = 0; i < proto_node->data.fn_proto.params.length; i += 1) { | |
| 2720 | AstNode *param_node = proto_node->data.fn_proto.params.at(i); | |
| 2721 | Buf *good_name = param_node->data.param_decl.name; | |
| 2722 | ||
| 2723 | if (c->ptr_params.maybe_get(good_name) != nullptr) { | |
| 2724 | // TODO: avoid name collisions | |
| 2725 | Buf *mangled_name = buf_sprintf("_arg_%s", buf_ptr(good_name)); | |
| 2726 | param_node->data.param_decl.name = mangled_name; | |
| 2727 | ||
| 2728 | // var c_name = _mangled_name; | |
| 2729 | AstNode *parameter_init = trans_create_node_var_decl_local(c, false, good_name, nullptr, trans_create_node_symbol(c, mangled_name)); | |
| 2730 | ||
| 2731 | body_node_with_param_inits->data.block.statements.append(parameter_init); | |
| 2732 | } | |
| 2733 | } | |
| 2734 | ||
| 2735 | for (size_t i = 0; i < actual_body_node->data.block.statements.length; i += 1) { | |
| 2736 | body_node_with_param_inits->data.block.statements.append(actual_body_node->data.block.statements.at(i)); | |
| 2737 | } | |
| 2738 | ||
| 2739 | AstNode *fn_def_node = trans_create_node(c, NodeTypeFnDef); | |
| 2740 | fn_def_node->data.fn_def.fn_proto = proto_node; | |
| 2741 | fn_def_node->data.fn_def.body = body_node_with_param_inits; | |
| 2742 | ||
| 2743 | proto_node->data.fn_proto.fn_def_node = fn_def_node; | |
| 2744 | add_top_level_decl(c, fn_def_node->data.fn_def.fn_proto->data.fn_proto.name, fn_def_node); | |
| 2745 | } | |
| 2746 | ||
| 2747 | static AstNode *resolve_typdef_as_builtin(Context *c, const TypedefNameDecl *typedef_decl, const char *primitive_name) { | |
| 2748 | AstNode *node = trans_create_node_symbol_str(c, primitive_name); | |
| 2749 | c->decl_table.put(typedef_decl, node); | |
| 2750 | return node; | |
| 2751 | } | |
| 2752 | ||
| 2753 | static AstNode *resolve_typedef_decl(Context *c, const TypedefNameDecl *typedef_decl) { | |
| 2754 | auto existing_entry = c->decl_table.maybe_get((void*)typedef_decl->getCanonicalDecl()); | |
| 2755 | if (existing_entry) { | |
| 2756 | return existing_entry->value; | |
| 2757 | } | |
| 2758 | QualType child_qt = typedef_decl->getUnderlyingType(); | |
| 2759 | Buf *type_name = buf_create_from_str(decl_name(typedef_decl)); | |
| 2760 | ||
| 2761 | if (buf_eql_str(type_name, "uint8_t")) { | |
| 2762 | return resolve_typdef_as_builtin(c, typedef_decl, "u8"); | |
| 2763 | } else if (buf_eql_str(type_name, "int8_t")) { | |
| 2764 | return resolve_typdef_as_builtin(c, typedef_decl, "i8"); | |
| 2765 | } else if (buf_eql_str(type_name, "uint16_t")) { | |
| 2766 | return resolve_typdef_as_builtin(c, typedef_decl, "u16"); | |
| 2767 | } else if (buf_eql_str(type_name, "int16_t")) { | |
| 2768 | return resolve_typdef_as_builtin(c, typedef_decl, "i16"); | |
| 2769 | } else if (buf_eql_str(type_name, "uint32_t")) { | |
| 2770 | return resolve_typdef_as_builtin(c, typedef_decl, "u32"); | |
| 2771 | } else if (buf_eql_str(type_name, "int32_t")) { | |
| 2772 | return resolve_typdef_as_builtin(c, typedef_decl, "i32"); | |
| 2773 | } else if (buf_eql_str(type_name, "uint64_t")) { | |
| 2774 | return resolve_typdef_as_builtin(c, typedef_decl, "u64"); | |
| 2775 | } else if (buf_eql_str(type_name, "int64_t")) { | |
| 2776 | return resolve_typdef_as_builtin(c, typedef_decl, "i64"); | |
| 2777 | } else if (buf_eql_str(type_name, "intptr_t")) { | |
| 2778 | return resolve_typdef_as_builtin(c, typedef_decl, "isize"); | |
| 2779 | } else if (buf_eql_str(type_name, "uintptr_t")) { | |
| 2780 | return resolve_typdef_as_builtin(c, typedef_decl, "usize"); | |
| 2781 | } else if (buf_eql_str(type_name, "ssize_t")) { | |
| 2782 | return resolve_typdef_as_builtin(c, typedef_decl, "isize"); | |
| 2783 | } else if (buf_eql_str(type_name, "size_t")) { | |
| 2784 | return resolve_typdef_as_builtin(c, typedef_decl, "usize"); | |
| 2785 | } | |
| 2786 | ||
| 2787 | // if the underlying type is anonymous, we can special case it to just | |
| 2788 | // use the name of this typedef | |
| 2789 | // TODO | |
| 2790 | ||
| 2791 | AstNode *type_node = trans_qual_type(c, child_qt, typedef_decl->getLocation()); | |
| 2792 | if (type_node == nullptr) { | |
| 2793 | emit_warning(c, typedef_decl->getLocation(), "typedef %s - unresolved child type", buf_ptr(type_name)); | |
| 2794 | c->decl_table.put(typedef_decl, nullptr); | |
| 2795 | return nullptr; | |
| 2796 | } | |
| 2797 | add_global_var(c, type_name, type_node); | |
| 2798 | ||
| 2799 | AstNode *symbol_node = trans_create_node_symbol(c, type_name); | |
| 2800 | c->decl_table.put(typedef_decl->getCanonicalDecl(), symbol_node); | |
| 2801 | return symbol_node; | |
| 2802 | } | |
| 2803 | ||
| 2804 | struct AstNode *demote_enum_to_opaque(Context *c, const EnumDecl *enum_decl, | |
| 2805 | Buf *full_type_name, Buf *bare_name) | |
| 2806 | { | |
| 2807 | AstNode *opaque_node = trans_create_node_opaque(c); | |
| 2808 | if (full_type_name == nullptr) { | |
| 2809 | c->decl_table.put(enum_decl->getCanonicalDecl(), opaque_node); | |
| 2810 | return opaque_node; | |
| 2811 | } | |
| 2812 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 2813 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 2814 | add_global_var(c, full_type_name, opaque_node); | |
| 2815 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); | |
| 2816 | return symbol_node; | |
| 2817 | } | |
| 2818 | ||
| 2819 | static AstNode *resolve_enum_decl(Context *c, const EnumDecl *enum_decl) { | |
| 2820 | auto existing_entry = c->decl_table.maybe_get((void*)enum_decl->getCanonicalDecl()); | |
| 2821 | if (existing_entry) { | |
| 2822 | return existing_entry->value; | |
| 2823 | } | |
| 2824 | ||
| 2825 | const char *raw_name = decl_name(enum_decl); | |
| 2826 | bool is_anonymous = (raw_name[0] == 0); | |
| 2827 | Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); | |
| 2828 | Buf *full_type_name = is_anonymous ? nullptr : buf_sprintf("enum_%s", buf_ptr(bare_name)); | |
| 2829 | ||
| 2830 | const EnumDecl *enum_def = enum_decl->getDefinition(); | |
| 2831 | if (!enum_def) { | |
| 2832 | return demote_enum_to_opaque(c, enum_decl, full_type_name, bare_name); | |
| 2833 | } | |
| 2834 | ||
| 2835 | bool pure_enum = true; | |
| 2836 | uint32_t field_count = 0; | |
| 2837 | for (auto it = enum_def->enumerator_begin(), | |
| 2838 | it_end = enum_def->enumerator_end(); | |
| 2839 | it != it_end; ++it, field_count += 1) | |
| 2840 | { | |
| 2841 | const EnumConstantDecl *enum_const = *it; | |
| 2842 | if (enum_const->getInitExpr()) { | |
| 2843 | pure_enum = false; | |
| 2844 | } | |
| 2845 | } | |
| 2846 | ||
| 2847 | AstNode *tag_int_type = trans_qual_type(c, enum_decl->getIntegerType(), enum_decl->getLocation()); | |
| 2848 | assert(tag_int_type); | |
| 2849 | ||
| 2850 | if (pure_enum) { | |
| 2851 | AstNode *enum_node = trans_create_node(c, NodeTypeContainerDecl); | |
| 2852 | enum_node->data.container_decl.kind = ContainerKindEnum; | |
| 2853 | enum_node->data.container_decl.layout = ContainerLayoutExtern; | |
| 2854 | enum_node->data.container_decl.init_arg_expr = tag_int_type; | |
| 2855 | ||
| 2856 | enum_node->data.container_decl.fields.resize(field_count); | |
| 2857 | uint32_t i = 0; | |
| 2858 | for (auto it = enum_def->enumerator_begin(), | |
| 2859 | it_end = enum_def->enumerator_end(); | |
| 2860 | it != it_end; ++it, i += 1) | |
| 2861 | { | |
| 2862 | const EnumConstantDecl *enum_const = *it; | |
| 2863 | ||
| 2864 | Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); | |
| 2865 | Buf *field_name; | |
| 2866 | if (bare_name != nullptr && buf_starts_with_buf(enum_val_name, bare_name)) { | |
| 2867 | field_name = buf_slice(enum_val_name, buf_len(bare_name), buf_len(enum_val_name)); | |
| 2868 | } else { | |
| 2869 | field_name = enum_val_name; | |
| 2870 | } | |
| 2871 | ||
| 2872 | AstNode *field_node = trans_create_node(c, NodeTypeStructField); | |
| 2873 | field_node->data.struct_field.name = field_name; | |
| 2874 | field_node->data.struct_field.type = nullptr; | |
| 2875 | enum_node->data.container_decl.fields.items[i] = field_node; | |
| 2876 | ||
| 2877 | // in C each enum value is in the global namespace. so we put them there too. | |
| 2878 | // at this point we can rely on the enum emitting successfully | |
| 2879 | if (is_anonymous) { | |
| 2880 | AstNode *lit_node = trans_create_node_unsigned(c, i); | |
| 2881 | add_global_var(c, enum_val_name, lit_node); | |
| 2882 | } else { | |
| 2883 | AstNode *field_access_node = trans_create_node_field_access(c, | |
| 2884 | trans_create_node_symbol(c, full_type_name), field_name); | |
| 2885 | add_global_var(c, enum_val_name, field_access_node); | |
| 2886 | } | |
| 2887 | } | |
| 2888 | ||
| 2889 | if (is_anonymous) { | |
| 2890 | c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node); | |
| 2891 | return enum_node; | |
| 2892 | } else { | |
| 2893 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 2894 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 2895 | add_global_var(c, full_type_name, enum_node); | |
| 2896 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); | |
| 2897 | return enum_node; | |
| 2898 | } | |
| 2899 | } | |
| 2900 | ||
| 2901 | // TODO after issue #305 is solved, make this be an enum with tag_int_type | |
| 2902 | // as the integer type and set the custom enum values | |
| 2903 | AstNode *enum_node = tag_int_type; | |
| 2904 | ||
| 2905 | ||
| 2906 | // add variables for all the values with enum_node | |
| 2907 | for (auto it = enum_def->enumerator_begin(), | |
| 2908 | it_end = enum_def->enumerator_end(); | |
| 2909 | it != it_end; ++it) | |
| 2910 | { | |
| 2911 | const EnumConstantDecl *enum_const = *it; | |
| 2912 | ||
| 2913 | Buf *enum_val_name = buf_create_from_str(decl_name(enum_const)); | |
| 2914 | AstNode *int_node = trans_create_node_apint(c, enum_const->getInitVal()); | |
| 2915 | AstNode *var_node = add_global_var(c, enum_val_name, int_node); | |
| 2916 | var_node->data.variable_declaration.type = tag_int_type; | |
| 2917 | } | |
| 2918 | ||
| 2919 | if (is_anonymous) { | |
| 2920 | c->decl_table.put(enum_decl->getCanonicalDecl(), enum_node); | |
| 2921 | return enum_node; | |
| 2922 | } else { | |
| 2923 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 2924 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 2925 | add_global_var(c, full_type_name, enum_node); | |
| 2926 | c->decl_table.put(enum_decl->getCanonicalDecl(), symbol_node); | |
| 2927 | return symbol_node; | |
| 2928 | } | |
| 2929 | } | |
| 2930 | ||
| 2931 | static AstNode *demote_struct_to_opaque(Context *c, const RecordDecl *record_decl, | |
| 2932 | Buf *full_type_name, Buf *bare_name) | |
| 2933 | { | |
| 2934 | AstNode *opaque_node = trans_create_node_opaque(c); | |
| 2935 | if (full_type_name == nullptr) { | |
| 2936 | c->decl_table.put(record_decl->getCanonicalDecl(), opaque_node); | |
| 2937 | return opaque_node; | |
| 2938 | } | |
| 2939 | AstNode *symbol_node = trans_create_node_symbol(c, full_type_name); | |
| 2940 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 2941 | add_global_var(c, full_type_name, opaque_node); | |
| 2942 | c->decl_table.put(record_decl->getCanonicalDecl(), symbol_node); | |
| 2943 | return symbol_node; | |
| 2944 | } | |
| 2945 | ||
| 2946 | static AstNode *resolve_record_decl(Context *c, const RecordDecl *record_decl) { | |
| 2947 | auto existing_entry = c->decl_table.maybe_get((void*)record_decl->getCanonicalDecl()); | |
| 2948 | if (existing_entry) { | |
| 2949 | return existing_entry->value; | |
| 2950 | } | |
| 2951 | ||
| 2952 | const char *raw_name = decl_name(record_decl); | |
| 2953 | ||
| 2954 | const char *container_kind_name; | |
| 2955 | ContainerKind container_kind; | |
| 2956 | if (record_decl->isUnion()) { | |
| 2957 | container_kind_name = "union"; | |
| 2958 | container_kind = ContainerKindUnion; | |
| 2959 | } else if (record_decl->isStruct()) { | |
| 2960 | container_kind_name = "struct"; | |
| 2961 | container_kind = ContainerKindStruct; | |
| 2962 | } else { | |
| 2963 | emit_warning(c, record_decl->getLocation(), "skipping record %s, not a struct or union", raw_name); | |
| 2964 | c->decl_table.put(record_decl->getCanonicalDecl(), nullptr); | |
| 2965 | return nullptr; | |
| 2966 | } | |
| 2967 | ||
| 2968 | bool is_anonymous = record_decl->isAnonymousStructOrUnion() || raw_name[0] == 0; | |
| 2969 | Buf *bare_name = is_anonymous ? nullptr : buf_create_from_str(raw_name); | |
| 2970 | Buf *full_type_name = (bare_name == nullptr) ? | |
| 2971 | nullptr : buf_sprintf("%s_%s", container_kind_name, buf_ptr(bare_name)); | |
| 2972 | ||
| 2973 | RecordDecl *record_def = record_decl->getDefinition(); | |
| 2974 | if (record_def == nullptr) { | |
| 2975 | return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); | |
| 2976 | } | |
| 2977 | ||
| 2978 | // count fields and validate | |
| 2979 | uint32_t field_count = 0; | |
| 2980 | for (auto it = record_def->field_begin(), | |
| 2981 | it_end = record_def->field_end(); | |
| 2982 | it != it_end; ++it, field_count += 1) | |
| 2983 | { | |
| 2984 | const FieldDecl *field_decl = *it; | |
| 2985 | ||
| 2986 | if (field_decl->isBitField()) { | |
| 2987 | emit_warning(c, field_decl->getLocation(), "%s %s demoted to opaque type - has bitfield", | |
| 2988 | container_kind_name, | |
| 2989 | is_anonymous ? "(anon)" : buf_ptr(bare_name)); | |
| 2990 | return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); | |
| 2991 | } | |
| 2992 | } | |
| 2993 | ||
| 2994 | AstNode *struct_node = trans_create_node(c, NodeTypeContainerDecl); | |
| 2995 | struct_node->data.container_decl.kind = container_kind; | |
| 2996 | struct_node->data.container_decl.layout = ContainerLayoutExtern; | |
| 2997 | ||
| 2998 | // TODO handle attribute packed | |
| 2999 | ||
| 3000 | struct_node->data.container_decl.fields.resize(field_count); | |
| 3001 | ||
| 3002 | // must be before fields in case a circular reference happens | |
| 3003 | if (is_anonymous) { | |
| 3004 | c->decl_table.put(record_decl->getCanonicalDecl(), struct_node); | |
| 3005 | } else { | |
| 3006 | c->decl_table.put(record_decl->getCanonicalDecl(), trans_create_node_symbol(c, full_type_name)); | |
| 3007 | } | |
| 3008 | ||
| 3009 | uint32_t i = 0; | |
| 3010 | for (auto it = record_def->field_begin(), | |
| 3011 | it_end = record_def->field_end(); | |
| 3012 | it != it_end; ++it, i += 1) | |
| 3013 | { | |
| 3014 | const FieldDecl *field_decl = *it; | |
| 3015 | ||
| 3016 | AstNode *field_node = trans_create_node(c, NodeTypeStructField); | |
| 3017 | field_node->data.struct_field.name = buf_create_from_str(decl_name(field_decl)); | |
| 3018 | field_node->data.struct_field.type = trans_qual_type(c, field_decl->getType(), field_decl->getLocation()); | |
| 3019 | ||
| 3020 | if (field_node->data.struct_field.type == nullptr) { | |
| 3021 | emit_warning(c, field_decl->getLocation(), | |
| 3022 | "%s %s demoted to opaque type - unresolved type", | |
| 3023 | container_kind_name, | |
| 3024 | is_anonymous ? "(anon)" : buf_ptr(bare_name)); | |
| 3025 | ||
| 3026 | return demote_struct_to_opaque(c, record_decl, full_type_name, bare_name); | |
| 3027 | } | |
| 3028 | ||
| 3029 | struct_node->data.container_decl.fields.items[i] = field_node; | |
| 3030 | } | |
| 3031 | ||
| 3032 | if (is_anonymous) { | |
| 3033 | return struct_node; | |
| 3034 | } else { | |
| 3035 | add_global_weak_alias(c, bare_name, full_type_name); | |
| 3036 | add_global_var(c, full_type_name, struct_node); | |
| 3037 | return trans_create_node_symbol(c, full_type_name); | |
| 3038 | } | |
| 3039 | } | |
| 3040 | ||
| 3041 | static void visit_var_decl(Context *c, const VarDecl *var_decl) { | |
| 3042 | Buf *name = buf_create_from_str(decl_name(var_decl)); | |
| 3043 | ||
| 3044 | switch (var_decl->getTLSKind()) { | |
| 3045 | case VarDecl::TLS_None: | |
| 3046 | break; | |
| 3047 | case VarDecl::TLS_Static: | |
| 3048 | emit_warning(c, var_decl->getLocation(), | |
| 3049 | "ignoring variable '%s' - static thread local storage", buf_ptr(name)); | |
| 3050 | return; | |
| 3051 | case VarDecl::TLS_Dynamic: | |
| 3052 | emit_warning(c, var_decl->getLocation(), | |
| 3053 | "ignoring variable '%s' - dynamic thread local storage", buf_ptr(name)); | |
| 3054 | return; | |
| 3055 | } | |
| 3056 | ||
| 3057 | QualType qt = var_decl->getType(); | |
| 3058 | AstNode *var_type = trans_qual_type(c, qt, var_decl->getLocation()); | |
| 3059 | if (var_type == nullptr) { | |
| 3060 | emit_warning(c, var_decl->getLocation(), "ignoring variable '%s' - unresolved type", buf_ptr(name)); | |
| 3061 | return; | |
| 3062 | } | |
| 3063 | ||
| 3064 | bool is_extern = var_decl->hasExternalStorage(); | |
| 3065 | bool is_static = var_decl->isFileVarDecl(); | |
| 3066 | bool is_const = qt.isConstQualified(); | |
| 3067 | ||
| 3068 | if (is_static && !is_extern) { | |
| 3069 | AstNode *init_node; | |
| 3070 | if (var_decl->hasInit()) { | |
| 3071 | APValue *ap_value = var_decl->evaluateValue(); | |
| 3072 | if (ap_value == nullptr) { | |
| 3073 | emit_warning(c, var_decl->getLocation(), | |
| 3074 | "ignoring variable '%s' - unable to evaluate initializer", buf_ptr(name)); | |
| 3075 | return; | |
| 3076 | } | |
| 3077 | switch (ap_value->getKind()) { | |
| 3078 | case APValue::Int: | |
| 3079 | init_node = trans_create_node_apint(c, ap_value->getInt()); | |
| 3080 | break; | |
| 3081 | case APValue::Uninitialized: | |
| 3082 | init_node = trans_create_node(c, NodeTypeUndefinedLiteral); | |
| 3083 | break; | |
| 3084 | case APValue::Float: | |
| 3085 | case APValue::ComplexInt: | |
| 3086 | case APValue::ComplexFloat: | |
| 3087 | case APValue::LValue: | |
| 3088 | case APValue::Vector: | |
| 3089 | case APValue::Array: | |
| 3090 | case APValue::Struct: | |
| 3091 | case APValue::Union: | |
| 3092 | case APValue::MemberPointer: | |
| 3093 | case APValue::AddrLabelDiff: | |
| 3094 | emit_warning(c, var_decl->getLocation(), | |
| 3095 | "ignoring variable '%s' - unrecognized initializer value kind", buf_ptr(name)); | |
| 3096 | return; | |
| 3097 | } | |
| 3098 | } else { | |
| 3099 | init_node = trans_create_node(c, NodeTypeUndefinedLiteral); | |
| 3100 | } | |
| 3101 | ||
| 3102 | AstNode *var_node = trans_create_node_var_decl_global(c, is_const, name, var_type, init_node); | |
| 3103 | add_top_level_decl(c, name, var_node); | |
| 3104 | return; | |
| 3105 | } | |
| 3106 | ||
| 3107 | if (is_extern) { | |
| 3108 | AstNode *var_node = trans_create_node_var_decl_global(c, is_const, name, var_type, nullptr); | |
| 3109 | var_node->data.variable_declaration.is_extern = true; | |
| 3110 | add_top_level_decl(c, name, var_node); | |
| 3111 | return; | |
| 3112 | } | |
| 3113 | ||
| 3114 | emit_warning(c, var_decl->getLocation(), | |
| 3115 | "ignoring variable '%s' - non-extern, non-static variable", buf_ptr(name)); | |
| 3116 | return; | |
| 3117 | } | |
| 3118 | ||
| 3119 | static bool decl_visitor(void *context, const Decl *decl) { | |
| 3120 | Context *c = (Context*)context; | |
| 3121 | ||
| 3122 | switch (decl->getKind()) { | |
| 3123 | case Decl::Function: | |
| 3124 | visit_fn_decl(c, static_cast<const FunctionDecl*>(decl)); | |
| 3125 | break; | |
| 3126 | case Decl::Typedef: | |
| 3127 | resolve_typedef_decl(c, static_cast<const TypedefNameDecl *>(decl)); | |
| 3128 | break; | |
| 3129 | case Decl::Enum: | |
| 3130 | resolve_enum_decl(c, static_cast<const EnumDecl *>(decl)); | |
| 3131 | break; | |
| 3132 | case Decl::Record: | |
| 3133 | resolve_record_decl(c, static_cast<const RecordDecl *>(decl)); | |
| 3134 | break; | |
| 3135 | case Decl::Var: | |
| 3136 | visit_var_decl(c, static_cast<const VarDecl *>(decl)); | |
| 3137 | break; | |
| 3138 | default: | |
| 3139 | emit_warning(c, decl->getLocation(), "ignoring %s decl", decl->getDeclKindName()); | |
| 3140 | } | |
| 3141 | ||
| 3142 | return true; | |
| 3143 | } | |
| 3144 | ||
| 3145 | static bool name_exists(Context *c, Buf *name) { | |
| 3146 | return get_global(c, name) != nullptr; | |
| 3147 | } | |
| 3148 | ||
| 3149 | static void render_aliases(Context *c) { | |
| 3150 | for (size_t i = 0; i < c->aliases.length; i += 1) { | |
| 3151 | Alias *alias = &c->aliases.at(i); | |
| 3152 | if (name_exists(c, alias->new_name)) | |
| 3153 | continue; | |
| 3154 | ||
| 3155 | add_global_var(c, alias->new_name, trans_create_node_symbol(c, alias->canon_name)); | |
| 3156 | } | |
| 3157 | } | |
| 3158 | ||
| 3159 | static void render_macros(Context *c) { | |
| 3160 | auto it = c->macro_table.entry_iterator(); | |
| 3161 | for (;;) { | |
| 3162 | auto *entry = it.next(); | |
| 3163 | if (!entry) | |
| 3164 | break; | |
| 3165 | ||
| 3166 | AstNode *value_node = entry->value; | |
| 3167 | if (value_node->type == NodeTypeFnDef) { | |
| 3168 | add_top_level_decl(c, value_node->data.fn_def.fn_proto->data.fn_proto.name, value_node); | |
| 3169 | } else { | |
| 3170 | add_global_var(c, entry->key, value_node); | |
| 3171 | } | |
| 3172 | } | |
| 3173 | } | |
| 3174 | ||
| 3175 | static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, bool negate) { | |
| 3176 | CTok *tok = &ctok->tokens.at(*tok_i); | |
| 3177 | if (tok->id == CTokIdNumLitInt) { | |
| 3178 | *tok_i += 1; | |
| 3179 | switch (tok->data.num_lit_int.suffix) { | |
| 3180 | case CNumLitSuffixNone: | |
| 3181 | return trans_create_node_unsigned_negative(c, tok->data.num_lit_int.x, negate); | |
| 3182 | case CNumLitSuffixL: | |
| 3183 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_long"); | |
| 3184 | case CNumLitSuffixU: | |
| 3185 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_uint"); | |
| 3186 | case CNumLitSuffixLU: | |
| 3187 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_ulong"); | |
| 3188 | case CNumLitSuffixLL: | |
| 3189 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_longlong"); | |
| 3190 | case CNumLitSuffixLLU: | |
| 3191 | return trans_create_node_unsigned_negative_type(c, tok->data.num_lit_int.x, negate, "c_ulonglong"); | |
| 3192 | } | |
| 3193 | zig_unreachable(); | |
| 3194 | } else if (tok->id == CTokIdNumLitFloat) { | |
| 3195 | *tok_i += 1; | |
| 3196 | double value = negate ? -tok->data.num_lit_float : tok->data.num_lit_float; | |
| 3197 | return trans_create_node_float_lit(c, value); | |
| 3198 | } | |
| 3199 | return nullptr; | |
| 3200 | } | |
| 3201 | ||
| 3202 | static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) { | |
| 3203 | CTok *tok = &ctok->tokens.at(*tok_i); | |
| 3204 | switch (tok->id) { | |
| 3205 | case CTokIdCharLit: | |
| 3206 | *tok_i += 1; | |
| 3207 | return trans_create_node_unsigned(c, tok->data.char_lit); | |
| 3208 | case CTokIdStrLit: | |
| 3209 | *tok_i += 1; | |
| 3210 | return trans_create_node_str_lit_c(c, buf_create_from_buf(&tok->data.str_lit)); | |
| 3211 | case CTokIdMinus: | |
| 3212 | *tok_i += 1; | |
| 3213 | return parse_ctok_num_lit(c, ctok, tok_i, true); | |
| 3214 | case CTokIdNumLitInt: | |
| 3215 | case CTokIdNumLitFloat: | |
| 3216 | return parse_ctok_num_lit(c, ctok, tok_i, false); | |
| 3217 | case CTokIdSymbol: | |
| 3218 | { | |
| 3219 | *tok_i += 1; | |
| 3220 | Buf *symbol_name = buf_create_from_buf(&tok->data.symbol); | |
| 3221 | return trans_create_node_symbol(c, symbol_name); | |
| 3222 | } | |
| 3223 | case CTokIdLParen: | |
| 3224 | { | |
| 3225 | *tok_i += 1; | |
| 3226 | AstNode *inner_node = parse_ctok(c, ctok, tok_i); | |
| 3227 | ||
| 3228 | CTok *next_tok = &ctok->tokens.at(*tok_i); | |
| 3229 | if (next_tok->id != CTokIdRParen) { | |
| 3230 | return nullptr; | |
| 3231 | } | |
| 3232 | *tok_i += 1; | |
| 3233 | return inner_node; | |
| 3234 | } | |
| 3235 | case CTokIdEOF: | |
| 3236 | case CTokIdRParen: | |
| 3237 | // not able to make sense of this | |
| 3238 | return nullptr; | |
| 3239 | } | |
| 3240 | zig_unreachable(); | |
| 3241 | } | |
| 3242 | ||
| 3243 | static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) { | |
| 3244 | tokenize_c_macro(ctok, (const uint8_t *)char_ptr); | |
| 3245 | ||
| 3246 | if (ctok->error) { | |
| 3247 | return; | |
| 3248 | } | |
| 3249 | ||
| 3250 | size_t tok_i = 0; | |
| 3251 | CTok *name_tok = &ctok->tokens.at(tok_i); | |
| 3252 | assert(name_tok->id == CTokIdSymbol && buf_eql_buf(&name_tok->data.symbol, name)); | |
| 3253 | tok_i += 1; | |
| 3254 | ||
| 3255 | AstNode *result_node = parse_ctok(c, ctok, &tok_i); | |
| 3256 | if (result_node == nullptr) { | |
| 3257 | return; | |
| 3258 | } | |
| 3259 | CTok *eof_tok = &ctok->tokens.at(tok_i); | |
| 3260 | if (eof_tok->id != CTokIdEOF) { | |
| 3261 | return; | |
| 3262 | } | |
| 3263 | if (result_node->type == NodeTypeSymbol) { | |
| 3264 | // if it equals itself, ignore. for example, from stdio.h: | |
| 3265 | // #define stdin stdin | |
| 3266 | Buf *symbol_name = result_node->data.symbol_expr.symbol; | |
| 3267 | if (buf_eql_buf(name, symbol_name)) { | |
| 3268 | return; | |
| 3269 | } | |
| 3270 | c->macro_symbols.append({name, symbol_name}); | |
| 3271 | } else { | |
| 3272 | c->macro_table.put(name, result_node); | |
| 3273 | } | |
| 3274 | } | |
| 3275 | ||
| 3276 | static void process_symbol_macros(Context *c) { | |
| 3277 | for (size_t i = 0; i < c->macro_symbols.length; i += 1) { | |
| 3278 | MacroSymbol ms = c->macro_symbols.at(i); | |
| 3279 | ||
| 3280 | // Check if this macro aliases another top level declaration | |
| 3281 | AstNode *existing_node = get_global(c, ms.value); | |
| 3282 | if (!existing_node || name_exists(c, ms.name)) | |
| 3283 | continue; | |
| 3284 | ||
| 3285 | // If a macro aliases a global variable which is a function pointer, we conclude that | |
| 3286 | // the macro is intended to represent a function that assumes the function pointer | |
| 3287 | // variable is non-null and calls it. | |
| 3288 | if (existing_node->type == NodeTypeVariableDeclaration) { | |
| 3289 | AstNode *var_type = existing_node->data.variable_declaration.type; | |
| 3290 | if (var_type != nullptr && var_type->type == NodeTypePrefixOpExpr && | |
| 3291 | var_type->data.prefix_op_expr.prefix_op == PrefixOpMaybe) | |
| 3292 | { | |
| 3293 | AstNode *fn_proto_node = var_type->data.prefix_op_expr.primary_expr; | |
| 3294 | if (fn_proto_node->type == NodeTypeFnProto) { | |
| 3295 | AstNode *inline_fn_node = trans_create_node_inline_fn(c, ms.name, ms.value, fn_proto_node); | |
| 3296 | c->macro_table.put(ms.name, inline_fn_node); | |
| 3297 | continue; | |
| 3298 | } | |
| 3299 | } | |
| 3300 | } | |
| 3301 | ||
| 3302 | add_global_var(c, ms.name, trans_create_node_symbol(c, ms.value)); | |
| 3303 | } | |
| 3304 | } | |
| 3305 | ||
| 3306 | static void process_preprocessor_entities(Context *c, ASTUnit &unit) { | |
| 3307 | CTokenize ctok = {{0}}; | |
| 3308 | ||
| 3309 | // TODO if we see #undef, delete it from the table | |
| 3310 | ||
| 3311 | for (PreprocessedEntity *entity : unit.getLocalPreprocessingEntities()) { | |
| 3312 | switch (entity->getKind()) { | |
| 3313 | case PreprocessedEntity::InvalidKind: | |
| 3314 | case PreprocessedEntity::InclusionDirectiveKind: | |
| 3315 | case PreprocessedEntity::MacroExpansionKind: | |
| 3316 | continue; | |
| 3317 | case PreprocessedEntity::MacroDefinitionKind: | |
| 3318 | { | |
| 3319 | MacroDefinitionRecord *macro = static_cast<MacroDefinitionRecord *>(entity); | |
| 3320 | const char *raw_name = macro->getName()->getNameStart(); | |
| 3321 | SourceRange range = macro->getSourceRange(); | |
| 3322 | SourceLocation begin_loc = range.getBegin(); | |
| 3323 | SourceLocation end_loc = range.getEnd(); | |
| 3324 | ||
| 3325 | if (begin_loc == end_loc) { | |
| 3326 | // this means it is a macro without a value | |
| 3327 | // we don't care about such things | |
| 3328 | continue; | |
| 3329 | } | |
| 3330 | Buf *name = buf_create_from_str(raw_name); | |
| 3331 | if (name_exists(c, name)) { | |
| 3332 | continue; | |
| 3333 | } | |
| 3334 | ||
| 3335 | const char *begin_c = c->source_manager->getCharacterData(begin_loc); | |
| 3336 | process_macro(c, &ctok, name, begin_c); | |
| 3337 | } | |
| 3338 | } | |
| 3339 | } | |
| 3340 | } | |
| 3341 | ||
| 3342 | int parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source, | |
| 3343 | CodeGen *codegen, AstNode *source_node) | |
| 3344 | { | |
| 3345 | int err; | |
| 3346 | Buf tmp_file_path = BUF_INIT; | |
| 3347 | if ((err = os_buf_to_tmp_file(source, buf_create_from_str(".h"), &tmp_file_path))) { | |
| 3348 | return err; | |
| 3349 | } | |
| 3350 | ||
| 3351 | err = parse_h_file(import, errors, buf_ptr(&tmp_file_path), codegen, source_node); | |
| 3352 | ||
| 3353 | os_delete_file(&tmp_file_path); | |
| 3354 | ||
| 3355 | return err; | |
| 3356 | } | |
| 3357 | ||
| 3358 | int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file, | |
| 3359 | CodeGen *codegen, AstNode *source_node) | |
| 3360 | { | |
| 3361 | Context context = {0}; | |
| 3362 | Context *c = &context; | |
| 3363 | c->warnings_on = codegen->verbose_cimport; | |
| 3364 | c->import = import; | |
| 3365 | c->errors = errors; | |
| 3366 | if (buf_ends_with_str(buf_create_from_str(target_file), ".h")) { | |
| 3367 | c->visib_mod = VisibModPub; | |
| 3368 | c->export_visib_mod = VisibModPub; | |
| 3369 | } else { | |
| 3370 | c->visib_mod = VisibModPub; | |
| 3371 | c->export_visib_mod = VisibModExport; | |
| 3372 | } | |
| 3373 | c->decl_table.init(8); | |
| 3374 | c->macro_table.init(8); | |
| 3375 | c->global_table.init(8); | |
| 3376 | c->ptr_params.init(8); | |
| 3377 | c->codegen = codegen; | |
| 3378 | c->source_node = source_node; | |
| 3379 | ||
| 3380 | ZigList<const char *> clang_argv = {0}; | |
| 3381 | ||
| 3382 | clang_argv.append("-x"); | |
| 3383 | clang_argv.append("c"); | |
| 3384 | ||
| 3385 | if (c->codegen->is_native_target) { | |
| 3386 | char *ZIG_PARSEC_CFLAGS = getenv("ZIG_NATIVE_PARSEC_CFLAGS"); | |
| 3387 | if (ZIG_PARSEC_CFLAGS) { | |
| 3388 | Buf tmp_buf = BUF_INIT; | |
| 3389 | char *start = ZIG_PARSEC_CFLAGS; | |
| 3390 | char *space = strstr(start, " "); | |
| 3391 | while (space) { | |
| 3392 | if (space - start > 0) { | |
| 3393 | buf_init_from_mem(&tmp_buf, start, space - start); | |
| 3394 | clang_argv.append(buf_ptr(buf_create_from_buf(&tmp_buf))); | |
| 3395 | } | |
| 3396 | start = space + 1; | |
| 3397 | space = strstr(start, " "); | |
| 3398 | } | |
| 3399 | buf_init_from_str(&tmp_buf, start); | |
| 3400 | clang_argv.append(buf_ptr(buf_create_from_buf(&tmp_buf))); | |
| 3401 | } | |
| 3402 | } | |
| 3403 | ||
| 3404 | clang_argv.append("-isystem"); | |
| 3405 | clang_argv.append(buf_ptr(codegen->zig_c_headers_dir)); | |
| 3406 | ||
| 3407 | clang_argv.append("-isystem"); | |
| 3408 | clang_argv.append(buf_ptr(codegen->libc_include_dir)); | |
| 3409 | ||
| 3410 | // windows c runtime requires -D_DEBUG if using debug libraries | |
| 3411 | if (codegen->build_mode == BuildModeDebug) { | |
| 3412 | clang_argv.append("-D_DEBUG"); | |
| 3413 | } | |
| 3414 | ||
| 3415 | for (size_t i = 0; i < codegen->clang_argv_len; i += 1) { | |
| 3416 | clang_argv.append(codegen->clang_argv[i]); | |
| 3417 | } | |
| 3418 | ||
| 3419 | // we don't need spell checking and it slows things down | |
| 3420 | clang_argv.append("-fno-spell-checking"); | |
| 3421 | ||
| 3422 | // this gives us access to preprocessing entities, presumably at | |
| 3423 | // the cost of performance | |
| 3424 | clang_argv.append("-Xclang"); | |
| 3425 | clang_argv.append("-detailed-preprocessing-record"); | |
| 3426 | ||
| 3427 | if (!c->codegen->is_native_target) { | |
| 3428 | clang_argv.append("-target"); | |
| 3429 | clang_argv.append(buf_ptr(&c->codegen->triple_str)); | |
| 3430 | } | |
| 3431 | ||
| 3432 | clang_argv.append(target_file); | |
| 3433 | ||
| 3434 | // to make the [start...end] argument work | |
| 3435 | clang_argv.append(nullptr); | |
| 3436 | ||
| 3437 | IntrusiveRefCntPtr<DiagnosticsEngine> diags(CompilerInstance::createDiagnostics(new DiagnosticOptions)); | |
| 3438 | ||
| 3439 | std::shared_ptr<PCHContainerOperations> pch_container_ops = std::make_shared<PCHContainerOperations>(); | |
| 3440 | ||
| 3441 | bool skip_function_bodies = false; | |
| 3442 | bool only_local_decls = true; | |
| 3443 | bool capture_diagnostics = true; | |
| 3444 | bool user_files_are_volatile = true; | |
| 3445 | bool allow_pch_with_compiler_errors = false; | |
| 3446 | bool single_file_parse = false; | |
| 3447 | bool for_serialization = false; | |
| 3448 | const char *resources_path = buf_ptr(codegen->zig_c_headers_dir); | |
| 3449 | std::unique_ptr<ASTUnit> err_unit; | |
| 3450 | std::unique_ptr<ASTUnit> ast_unit(ASTUnit::LoadFromCommandLine( | |
| 3451 | &clang_argv.at(0), &clang_argv.last(), | |
| 3452 | pch_container_ops, diags, resources_path, | |
| 3453 | only_local_decls, capture_diagnostics, None, true, 0, TU_Complete, | |
| 3454 | false, false, allow_pch_with_compiler_errors, skip_function_bodies, | |
| 3455 | single_file_parse, user_files_are_volatile, for_serialization, None, &err_unit, | |
| 3456 | nullptr)); | |
| 3457 | ||
| 3458 | // Early failures in LoadFromCommandLine may return with ErrUnit unset. | |
| 3459 | if (!ast_unit && !err_unit) { | |
| 3460 | return ErrorFileSystem; | |
| 3461 | } | |
| 3462 | ||
| 3463 | if (diags->getClient()->getNumErrors() > 0) { | |
| 3464 | if (ast_unit) { | |
| 3465 | err_unit = std::move(ast_unit); | |
| 3466 | } | |
| 3467 | ||
| 3468 | for (ASTUnit::stored_diag_iterator it = err_unit->stored_diag_begin(), | |
| 3469 | it_end = err_unit->stored_diag_end(); | |
| 3470 | it != it_end; ++it) | |
| 3471 | { | |
| 3472 | switch (it->getLevel()) { | |
| 3473 | case DiagnosticsEngine::Ignored: | |
| 3474 | case DiagnosticsEngine::Note: | |
| 3475 | case DiagnosticsEngine::Remark: | |
| 3476 | case DiagnosticsEngine::Warning: | |
| 3477 | continue; | |
| 3478 | case DiagnosticsEngine::Error: | |
| 3479 | case DiagnosticsEngine::Fatal: | |
| 3480 | break; | |
| 3481 | } | |
| 3482 | StringRef msg_str_ref = it->getMessage(); | |
| 3483 | Buf *msg = buf_create_from_str((const char *)msg_str_ref.bytes_begin()); | |
| 3484 | FullSourceLoc fsl = it->getLocation(); | |
| 3485 | if (fsl.hasManager()) { | |
| 3486 | FileID file_id = fsl.getFileID(); | |
| 3487 | StringRef filename = fsl.getManager().getFilename(fsl); | |
| 3488 | unsigned line = fsl.getSpellingLineNumber() - 1; | |
| 3489 | unsigned column = fsl.getSpellingColumnNumber() - 1; | |
| 3490 | unsigned offset = fsl.getManager().getFileOffset(fsl); | |
| 3491 | const char *source = (const char *)fsl.getManager().getBufferData(file_id).bytes_begin(); | |
| 3492 | Buf *path; | |
| 3493 | if (filename.empty()) { | |
| 3494 | path = buf_alloc(); | |
| 3495 | } else { | |
| 3496 | path = buf_create_from_mem((const char *)filename.bytes_begin(), filename.size()); | |
| 3497 | } | |
| 3498 | ||
| 3499 | ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg); | |
| 3500 | ||
| 3501 | c->errors->append(err_msg); | |
| 3502 | } else { | |
| 3503 | // NOTE the only known way this gets triggered right now is if you have a lot of errors | |
| 3504 | // clang emits "too many errors emitted, stopping now" | |
| 3505 | fprintf(stderr, "unexpected error from clang: %s\n", buf_ptr(msg)); | |
| 3506 | } | |
| 3507 | } | |
| 3508 | ||
| 3509 | return 0; | |
| 3510 | } | |
| 3511 | ||
| 3512 | c->ctx = &ast_unit->getASTContext(); | |
| 3513 | c->source_manager = &ast_unit->getSourceManager(); | |
| 3514 | c->root = trans_create_node(c, NodeTypeRoot); | |
| 3515 | ||
| 3516 | ast_unit->visitLocalTopLevelDecls(c, decl_visitor); | |
| 3517 | ||
| 3518 | process_preprocessor_entities(c, *ast_unit); | |
| 3519 | ||
| 3520 | process_symbol_macros(c); | |
| 3521 | render_macros(c); | |
| 3522 | render_aliases(c); | |
| 3523 | ||
| 3524 | import->root = c->root; | |
| 3525 | ||
| 3526 | return 0; | |
| 3527 | } |
src/translate_c.hpp created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 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_PARSEC_HPP | |
| 10 | #define ZIG_PARSEC_HPP | |
| 11 | ||
| 12 | #include "all_types.hpp" | |
| 13 | ||
| 14 | int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const char *target_file, | |
| 15 | CodeGen *codegen, AstNode *source_node); | |
| 16 | ||
| 17 | int parse_h_buf(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, Buf *source, | |
| 18 | CodeGen *codegen, AstNode *source_node); | |
| 19 | ||
| 20 | #endif |
test/parsec.zig deleted-899| ... | ... | @@ -1,899 +0,0 @@ |
| 1 | const tests = @import("tests.zig"); | |
| 2 | ||
| 3 | pub fn addCases(cases: &tests.ParseCContext) { | |
| 4 | cases.addAllowWarnings("simple data types", | |
| 5 | \\#include <stdint.h> | |
| 6 | \\int foo(char a, unsigned char b, signed char c); | |
| 7 | \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype | |
| 8 | \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d); | |
| 9 | \\void baz(int8_t a, int16_t b, int32_t c, int64_t d); | |
| 10 | , | |
| 11 | \\pub extern fn foo(a: u8, b: u8, c: i8) -> c_int; | |
| 12 | , | |
| 13 | \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64); | |
| 14 | , | |
| 15 | \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64); | |
| 16 | ); | |
| 17 | ||
| 18 | cases.add("noreturn attribute", | |
| 19 | \\void foo(void) __attribute__((noreturn)); | |
| 20 | , | |
| 21 | \\pub extern fn foo() -> noreturn; | |
| 22 | ); | |
| 23 | ||
| 24 | cases.addC("simple function", | |
| 25 | \\int abs(int a) { | |
| 26 | \\ return a < 0 ? -a : a; | |
| 27 | \\} | |
| 28 | , | |
| 29 | \\export fn abs(a: c_int) -> c_int { | |
| 30 | \\ return if (a < 0) -a else a; | |
| 31 | \\} | |
| 32 | ); | |
| 33 | ||
| 34 | cases.add("enums", | |
| 35 | \\enum Foo { | |
| 36 | \\ FooA, | |
| 37 | \\ FooB, | |
| 38 | \\ Foo1, | |
| 39 | \\}; | |
| 40 | , | |
| 41 | \\pub const enum_Foo = extern enum { | |
| 42 | \\ A, | |
| 43 | \\ B, | |
| 44 | \\ @"1", | |
| 45 | \\}; | |
| 46 | , | |
| 47 | \\pub const FooA = enum_Foo.A; | |
| 48 | , | |
| 49 | \\pub const FooB = enum_Foo.B; | |
| 50 | , | |
| 51 | \\pub const Foo1 = enum_Foo.@"1"; | |
| 52 | , | |
| 53 | \\pub const Foo = enum_Foo; | |
| 54 | ); | |
| 55 | ||
| 56 | cases.add("restrict -> noalias", | |
| 57 | \\void foo(void *restrict bar, void *restrict); | |
| 58 | , | |
| 59 | \\pub extern fn foo(noalias bar: ?&c_void, noalias arg1: ?&c_void); | |
| 60 | ); | |
| 61 | ||
| 62 | cases.add("simple struct", | |
| 63 | \\struct Foo { | |
| 64 | \\ int x; | |
| 65 | \\ char *y; | |
| 66 | \\}; | |
| 67 | , | |
| 68 | \\const struct_Foo = extern struct { | |
| 69 | \\ x: c_int, | |
| 70 | \\ y: ?&u8, | |
| 71 | \\}; | |
| 72 | , | |
| 73 | \\pub const Foo = struct_Foo; | |
| 74 | ); | |
| 75 | ||
| 76 | cases.add("qualified struct and enum", | |
| 77 | \\struct Foo { | |
| 78 | \\ int x; | |
| 79 | \\ int y; | |
| 80 | \\}; | |
| 81 | \\enum Bar { | |
| 82 | \\ BarA, | |
| 83 | \\ BarB, | |
| 84 | \\}; | |
| 85 | \\void func(struct Foo *a, enum Bar **b); | |
| 86 | , | |
| 87 | \\pub const struct_Foo = extern struct { | |
| 88 | \\ x: c_int, | |
| 89 | \\ y: c_int, | |
| 90 | \\}; | |
| 91 | , | |
| 92 | \\pub const enum_Bar = extern enum { | |
| 93 | \\ A, | |
| 94 | \\ B, | |
| 95 | \\}; | |
| 96 | , | |
| 97 | \\pub const BarA = enum_Bar.A; | |
| 98 | , | |
| 99 | \\pub const BarB = enum_Bar.B; | |
| 100 | , | |
| 101 | \\pub extern fn func(a: ?&struct_Foo, b: ?&(?&enum_Bar)); | |
| 102 | , | |
| 103 | \\pub const Foo = struct_Foo; | |
| 104 | , | |
| 105 | \\pub const Bar = enum_Bar; | |
| 106 | ); | |
| 107 | ||
| 108 | cases.add("constant size array", | |
| 109 | \\void func(int array[20]); | |
| 110 | , | |
| 111 | \\pub extern fn func(array: ?&c_int); | |
| 112 | ); | |
| 113 | ||
| 114 | cases.add("self referential struct with function pointer", | |
| 115 | \\struct Foo { | |
| 116 | \\ void (*derp)(struct Foo *foo); | |
| 117 | \\}; | |
| 118 | , | |
| 119 | \\pub const struct_Foo = extern struct { | |
| 120 | \\ derp: ?extern fn(?&struct_Foo), | |
| 121 | \\}; | |
| 122 | , | |
| 123 | \\pub const Foo = struct_Foo; | |
| 124 | ); | |
| 125 | ||
| 126 | cases.add("struct prototype used in func", | |
| 127 | \\struct Foo; | |
| 128 | \\struct Foo *some_func(struct Foo *foo, int x); | |
| 129 | , | |
| 130 | \\pub const struct_Foo = @OpaqueType(); | |
| 131 | , | |
| 132 | \\pub extern fn some_func(foo: ?&struct_Foo, x: c_int) -> ?&struct_Foo; | |
| 133 | , | |
| 134 | \\pub const Foo = struct_Foo; | |
| 135 | ); | |
| 136 | ||
| 137 | cases.add("#define a char literal", | |
| 138 | \\#define A_CHAR 'a' | |
| 139 | , | |
| 140 | \\pub const A_CHAR = 97; | |
| 141 | ); | |
| 142 | ||
| 143 | cases.add("#define an unsigned integer literal", | |
| 144 | \\#define CHANNEL_COUNT 24 | |
| 145 | , | |
| 146 | \\pub const CHANNEL_COUNT = 24; | |
| 147 | ); | |
| 148 | ||
| 149 | cases.add("#define referencing another #define", | |
| 150 | \\#define THING2 THING1 | |
| 151 | \\#define THING1 1234 | |
| 152 | , | |
| 153 | \\pub const THING1 = 1234; | |
| 154 | , | |
| 155 | \\pub const THING2 = THING1; | |
| 156 | ); | |
| 157 | ||
| 158 | cases.add("variables", | |
| 159 | \\extern int extern_var; | |
| 160 | \\static const int int_var = 13; | |
| 161 | , | |
| 162 | \\pub extern var extern_var: c_int; | |
| 163 | , | |
| 164 | \\pub const int_var: c_int = 13; | |
| 165 | ); | |
| 166 | ||
| 167 | cases.add("circular struct definitions", | |
| 168 | \\struct Bar; | |
| 169 | \\ | |
| 170 | \\struct Foo { | |
| 171 | \\ struct Bar *next; | |
| 172 | \\}; | |
| 173 | \\ | |
| 174 | \\struct Bar { | |
| 175 | \\ struct Foo *next; | |
| 176 | \\}; | |
| 177 | , | |
| 178 | \\pub const struct_Bar = extern struct { | |
| 179 | \\ next: ?&struct_Foo, | |
| 180 | \\}; | |
| 181 | , | |
| 182 | \\pub const struct_Foo = extern struct { | |
| 183 | \\ next: ?&struct_Bar, | |
| 184 | \\}; | |
| 185 | ); | |
| 186 | ||
| 187 | cases.add("typedef void", | |
| 188 | \\typedef void Foo; | |
| 189 | \\Foo fun(Foo *a); | |
| 190 | , | |
| 191 | \\pub const Foo = c_void; | |
| 192 | , | |
| 193 | \\pub extern fn fun(a: ?&Foo) -> Foo; | |
| 194 | ); | |
| 195 | ||
| 196 | cases.add("generate inline func for #define global extern fn", | |
| 197 | \\extern void (*fn_ptr)(void); | |
| 198 | \\#define foo fn_ptr | |
| 199 | \\ | |
| 200 | \\extern char (*fn_ptr2)(int, float); | |
| 201 | \\#define bar fn_ptr2 | |
| 202 | , | |
| 203 | \\pub extern var fn_ptr: ?extern fn(); | |
| 204 | , | |
| 205 | \\pub inline fn foo() { | |
| 206 | \\ (??fn_ptr)() | |
| 207 | \\} | |
| 208 | , | |
| 209 | \\pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8; | |
| 210 | , | |
| 211 | \\pub inline fn bar(arg0: c_int, arg1: f32) -> u8 { | |
| 212 | \\ (??fn_ptr2)(arg0, arg1) | |
| 213 | \\} | |
| 214 | ); | |
| 215 | ||
| 216 | cases.add("#define string", | |
| 217 | \\#define foo "a string" | |
| 218 | , | |
| 219 | \\pub const foo = c"a string"; | |
| 220 | ); | |
| 221 | ||
| 222 | cases.add("__cdecl doesn't mess up function pointers", | |
| 223 | \\void foo(void (__cdecl *fn_ptr)(void)); | |
| 224 | , | |
| 225 | \\pub extern fn foo(fn_ptr: ?extern fn()); | |
| 226 | ); | |
| 227 | ||
| 228 | cases.add("comment after integer literal", | |
| 229 | \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 230 | , | |
| 231 | \\pub const SDL_INIT_VIDEO = 32; | |
| 232 | ); | |
| 233 | ||
| 234 | cases.add("u integer suffix after hex literal", | |
| 235 | \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 236 | , | |
| 237 | \\pub const SDL_INIT_VIDEO = c_uint(32); | |
| 238 | ); | |
| 239 | ||
| 240 | cases.add("l integer suffix after hex literal", | |
| 241 | \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 242 | , | |
| 243 | \\pub const SDL_INIT_VIDEO = c_long(32); | |
| 244 | ); | |
| 245 | ||
| 246 | cases.add("ul integer suffix after hex literal", | |
| 247 | \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 248 | , | |
| 249 | \\pub const SDL_INIT_VIDEO = c_ulong(32); | |
| 250 | ); | |
| 251 | ||
| 252 | cases.add("lu integer suffix after hex literal", | |
| 253 | \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 254 | , | |
| 255 | \\pub const SDL_INIT_VIDEO = c_ulong(32); | |
| 256 | ); | |
| 257 | ||
| 258 | cases.add("ll integer suffix after hex literal", | |
| 259 | \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 260 | , | |
| 261 | \\pub const SDL_INIT_VIDEO = c_longlong(32); | |
| 262 | ); | |
| 263 | ||
| 264 | cases.add("ull integer suffix after hex literal", | |
| 265 | \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 266 | , | |
| 267 | \\pub const SDL_INIT_VIDEO = c_ulonglong(32); | |
| 268 | ); | |
| 269 | ||
| 270 | cases.add("llu integer suffix after hex literal", | |
| 271 | \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 272 | , | |
| 273 | \\pub const SDL_INIT_VIDEO = c_ulonglong(32); | |
| 274 | ); | |
| 275 | ||
| 276 | cases.add("zig keywords in C code", | |
| 277 | \\struct comptime { | |
| 278 | \\ int defer; | |
| 279 | \\}; | |
| 280 | , | |
| 281 | \\pub const struct_comptime = extern struct { | |
| 282 | \\ @"defer": c_int, | |
| 283 | \\}; | |
| 284 | , | |
| 285 | \\pub const @"comptime" = struct_comptime; | |
| 286 | ); | |
| 287 | ||
| 288 | cases.add("macro defines string literal with hex", | |
| 289 | \\#define FOO "aoeu\xab derp" | |
| 290 | \\#define FOO2 "aoeu\x0007a derp" | |
| 291 | \\#define FOO_CHAR '\xfF' | |
| 292 | , | |
| 293 | \\pub const FOO = c"aoeu\xab derp"; | |
| 294 | , | |
| 295 | \\pub const FOO2 = c"aoeuz derp"; | |
| 296 | , | |
| 297 | \\pub const FOO_CHAR = 255; | |
| 298 | ); | |
| 299 | ||
| 300 | cases.add("macro defines string literal with octal", | |
| 301 | \\#define FOO "aoeu\023 derp" | |
| 302 | \\#define FOO2 "aoeu\0234 derp" | |
| 303 | \\#define FOO_CHAR '\077' | |
| 304 | , | |
| 305 | \\pub const FOO = c"aoeu\x13 derp"; | |
| 306 | , | |
| 307 | \\pub const FOO2 = c"aoeu\x134 derp"; | |
| 308 | , | |
| 309 | \\pub const FOO_CHAR = 63; | |
| 310 | ); | |
| 311 | ||
| 312 | cases.add("macro with parens around negative number", | |
| 313 | \\#define LUA_GLOBALSINDEX (-10002) | |
| 314 | , | |
| 315 | \\pub const LUA_GLOBALSINDEX = -10002; | |
| 316 | ); | |
| 317 | ||
| 318 | cases.addC("post increment", | |
| 319 | \\unsigned foo1(unsigned a) { | |
| 320 | \\ a++; | |
| 321 | \\ return a; | |
| 322 | \\} | |
| 323 | \\int foo2(int a) { | |
| 324 | \\ a++; | |
| 325 | \\ return a; | |
| 326 | \\} | |
| 327 | , | |
| 328 | \\export fn foo1(_arg_a: c_uint) -> c_uint { | |
| 329 | \\ var a = _arg_a; | |
| 330 | \\ a +%= 1; | |
| 331 | \\ return a; | |
| 332 | \\} | |
| 333 | \\export fn foo2(_arg_a: c_int) -> c_int { | |
| 334 | \\ var a = _arg_a; | |
| 335 | \\ a += 1; | |
| 336 | \\ return a; | |
| 337 | \\} | |
| 338 | ); | |
| 339 | ||
| 340 | cases.addC("shift right assign", | |
| 341 | \\int log2(unsigned a) { | |
| 342 | \\ int i = 0; | |
| 343 | \\ while (a > 0) { | |
| 344 | \\ a >>= 1; | |
| 345 | \\ } | |
| 346 | \\ return i; | |
| 347 | \\} | |
| 348 | , | |
| 349 | \\export fn log2(_arg_a: c_uint) -> c_int { | |
| 350 | \\ var a = _arg_a; | |
| 351 | \\ var i: c_int = 0; | |
| 352 | \\ while (a > c_uint(0)) { | |
| 353 | \\ a >>= @import("std").math.Log2Int(c_uint)(1); | |
| 354 | \\ }; | |
| 355 | \\ return i; | |
| 356 | \\} | |
| 357 | ); | |
| 358 | ||
| 359 | cases.addC("if statement", | |
| 360 | \\int max(int a, int b) { | |
| 361 | \\ if (a < b) | |
| 362 | \\ return b; | |
| 363 | \\ | |
| 364 | \\ if (a < b) | |
| 365 | \\ return b; | |
| 366 | \\ else | |
| 367 | \\ return a; | |
| 368 | \\} | |
| 369 | , | |
| 370 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 371 | \\ if (a < b) return b; | |
| 372 | \\ if (a < b) return b else return a; | |
| 373 | \\} | |
| 374 | ); | |
| 375 | ||
| 376 | cases.addC("==, !=", | |
| 377 | \\int max(int a, int b) { | |
| 378 | \\ if (a == b) | |
| 379 | \\ return a; | |
| 380 | \\ if (a != b) | |
| 381 | \\ return b; | |
| 382 | \\ return a; | |
| 383 | \\} | |
| 384 | , | |
| 385 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 386 | \\ if (a == b) return a; | |
| 387 | \\ if (a != b) return b; | |
| 388 | \\ return a; | |
| 389 | \\} | |
| 390 | ); | |
| 391 | ||
| 392 | cases.addC("add, sub, mul, div, rem", | |
| 393 | \\int s(int a, int b) { | |
| 394 | \\ int c; | |
| 395 | \\ c = a + b; | |
| 396 | \\ c = a - b; | |
| 397 | \\ c = a * b; | |
| 398 | \\ c = a / b; | |
| 399 | \\ c = a % b; | |
| 400 | \\} | |
| 401 | \\unsigned u(unsigned a, unsigned b) { | |
| 402 | \\ unsigned c; | |
| 403 | \\ c = a + b; | |
| 404 | \\ c = a - b; | |
| 405 | \\ c = a * b; | |
| 406 | \\ c = a / b; | |
| 407 | \\ c = a % b; | |
| 408 | \\} | |
| 409 | , | |
| 410 | \\export fn s(a: c_int, b: c_int) -> c_int { | |
| 411 | \\ var c: c_int; | |
| 412 | \\ c = (a + b); | |
| 413 | \\ c = (a - b); | |
| 414 | \\ c = (a * b); | |
| 415 | \\ c = @divTrunc(a, b); | |
| 416 | \\ c = @rem(a, b); | |
| 417 | \\} | |
| 418 | \\export fn u(a: c_uint, b: c_uint) -> c_uint { | |
| 419 | \\ var c: c_uint; | |
| 420 | \\ c = (a +% b); | |
| 421 | \\ c = (a -% b); | |
| 422 | \\ c = (a *% b); | |
| 423 | \\ c = (a / b); | |
| 424 | \\ c = (a % b); | |
| 425 | \\} | |
| 426 | ); | |
| 427 | ||
| 428 | cases.addC("bitwise binary operators", | |
| 429 | \\int max(int a, int b) { | |
| 430 | \\ return (a & b) ^ (a | b); | |
| 431 | \\} | |
| 432 | , | |
| 433 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 434 | \\ return (a & b) ^ (a | b); | |
| 435 | \\} | |
| 436 | ); | |
| 437 | ||
| 438 | cases.addC("logical and, logical or", | |
| 439 | \\int max(int a, int b) { | |
| 440 | \\ if (a < b || a == b) | |
| 441 | \\ return b; | |
| 442 | \\ if (a >= b && a == b) | |
| 443 | \\ return a; | |
| 444 | \\ return a; | |
| 445 | \\} | |
| 446 | , | |
| 447 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 448 | \\ if ((a < b) or (a == b)) return b; | |
| 449 | \\ if ((a >= b) and (a == b)) return a; | |
| 450 | \\ return a; | |
| 451 | \\} | |
| 452 | ); | |
| 453 | ||
| 454 | cases.addC("assign", | |
| 455 | \\int max(int a) { | |
| 456 | \\ int tmp; | |
| 457 | \\ tmp = a; | |
| 458 | \\ a = tmp; | |
| 459 | \\} | |
| 460 | , | |
| 461 | \\export fn max(_arg_a: c_int) -> c_int { | |
| 462 | \\ var a = _arg_a; | |
| 463 | \\ var tmp: c_int; | |
| 464 | \\ tmp = a; | |
| 465 | \\ a = tmp; | |
| 466 | \\} | |
| 467 | ); | |
| 468 | ||
| 469 | cases.addC("chaining assign", | |
| 470 | \\void max(int a) { | |
| 471 | \\ int b, c; | |
| 472 | \\ c = b = a; | |
| 473 | \\} | |
| 474 | , | |
| 475 | \\export fn max(a: c_int) { | |
| 476 | \\ var b: c_int; | |
| 477 | \\ var c: c_int; | |
| 478 | \\ c = { | |
| 479 | \\ const _tmp = a; | |
| 480 | \\ b = _tmp; | |
| 481 | \\ _tmp | |
| 482 | \\ }; | |
| 483 | \\} | |
| 484 | ); | |
| 485 | ||
| 486 | cases.addC("shift right assign with a fixed size type", | |
| 487 | \\#include <stdint.h> | |
| 488 | \\int log2(uint32_t a) { | |
| 489 | \\ int i = 0; | |
| 490 | \\ while (a > 0) { | |
| 491 | \\ a >>= 1; | |
| 492 | \\ } | |
| 493 | \\ return i; | |
| 494 | \\} | |
| 495 | , | |
| 496 | \\export fn log2(_arg_a: u32) -> c_int { | |
| 497 | \\ var a = _arg_a; | |
| 498 | \\ var i: c_int = 0; | |
| 499 | \\ while (a > c_uint(0)) { | |
| 500 | \\ a >>= u5(1); | |
| 501 | \\ }; | |
| 502 | \\ return i; | |
| 503 | \\} | |
| 504 | ); | |
| 505 | ||
| 506 | cases.add("anonymous enum", | |
| 507 | \\enum { | |
| 508 | \\ One, | |
| 509 | \\ Two, | |
| 510 | \\}; | |
| 511 | , | |
| 512 | \\pub const One = 0; | |
| 513 | \\pub const Two = 1; | |
| 514 | ); | |
| 515 | ||
| 516 | cases.addC("function call", | |
| 517 | \\static void bar(void) { } | |
| 518 | \\void foo(void) { bar(); } | |
| 519 | , | |
| 520 | \\pub fn bar() {} | |
| 521 | \\export fn foo() { | |
| 522 | \\ bar(); | |
| 523 | \\} | |
| 524 | ); | |
| 525 | ||
| 526 | cases.addC("field access expression", | |
| 527 | \\struct Foo { | |
| 528 | \\ int field; | |
| 529 | \\}; | |
| 530 | \\int read_field(struct Foo *foo) { | |
| 531 | \\ return foo->field; | |
| 532 | \\} | |
| 533 | , | |
| 534 | \\pub const struct_Foo = extern struct { | |
| 535 | \\ field: c_int, | |
| 536 | \\}; | |
| 537 | \\export fn read_field(foo: ?&struct_Foo) -> c_int { | |
| 538 | \\ return (??foo).field; | |
| 539 | \\} | |
| 540 | ); | |
| 541 | ||
| 542 | cases.addC("null statements", | |
| 543 | \\void foo(void) { | |
| 544 | \\ ;;;;; | |
| 545 | \\} | |
| 546 | , | |
| 547 | \\export fn foo() {} | |
| 548 | ); | |
| 549 | ||
| 550 | cases.add("undefined array global", | |
| 551 | \\int array[100]; | |
| 552 | , | |
| 553 | \\pub var array: [100]c_int = undefined; | |
| 554 | ); | |
| 555 | ||
| 556 | cases.addC("array access", | |
| 557 | \\int array[100]; | |
| 558 | \\int foo(int index) { | |
| 559 | \\ return array[index]; | |
| 560 | \\} | |
| 561 | , | |
| 562 | \\pub var array: [100]c_int = undefined; | |
| 563 | \\export fn foo(index: c_int) -> c_int { | |
| 564 | \\ return array[index]; | |
| 565 | \\} | |
| 566 | ); | |
| 567 | ||
| 568 | ||
| 569 | cases.addC("c style cast", | |
| 570 | \\int float_to_int(float a) { | |
| 571 | \\ return (int)a; | |
| 572 | \\} | |
| 573 | , | |
| 574 | \\export fn float_to_int(a: f32) -> c_int { | |
| 575 | \\ return c_int(a); | |
| 576 | \\} | |
| 577 | ); | |
| 578 | ||
| 579 | cases.addC("implicit cast to void *", | |
| 580 | \\void *foo(unsigned short *x) { | |
| 581 | \\ return x; | |
| 582 | \\} | |
| 583 | , | |
| 584 | \\export fn foo(x: ?&c_ushort) -> ?&c_void { | |
| 585 | \\ return @ptrCast(?&c_void, x); | |
| 586 | \\} | |
| 587 | ); | |
| 588 | ||
| 589 | cases.addC("sizeof", | |
| 590 | \\#include <stddef.h> | |
| 591 | \\size_t size_of(void) { | |
| 592 | \\ return sizeof(int); | |
| 593 | \\} | |
| 594 | , | |
| 595 | \\export fn size_of() -> usize { | |
| 596 | \\ return @sizeOf(c_int); | |
| 597 | \\} | |
| 598 | ); | |
| 599 | ||
| 600 | cases.addC("null pointer implicit cast", | |
| 601 | \\int* foo(void) { | |
| 602 | \\ return 0; | |
| 603 | \\} | |
| 604 | , | |
| 605 | \\export fn foo() -> ?&c_int { | |
| 606 | \\ return null; | |
| 607 | \\} | |
| 608 | ); | |
| 609 | ||
| 610 | cases.addC("comma operator", | |
| 611 | \\int foo(void) { | |
| 612 | \\ return 1, 2; | |
| 613 | \\} | |
| 614 | , | |
| 615 | \\export fn foo() -> c_int { | |
| 616 | \\ return { | |
| 617 | \\ _ = 1; | |
| 618 | \\ 2 | |
| 619 | \\ }; | |
| 620 | \\} | |
| 621 | ); | |
| 622 | ||
| 623 | cases.addC("bitshift", | |
| 624 | \\int foo(void) { | |
| 625 | \\ return (1 << 2) >> 1; | |
| 626 | \\} | |
| 627 | , | |
| 628 | \\export fn foo() -> c_int { | |
| 629 | \\ return (1 << @import("std").math.Log2Int(c_int)(2)) >> @import("std").math.Log2Int(c_int)(1); | |
| 630 | \\} | |
| 631 | ); | |
| 632 | ||
| 633 | cases.addC("compound assignment operators", | |
| 634 | \\void foo(void) { | |
| 635 | \\ int a = 0; | |
| 636 | \\ a += (a += 1); | |
| 637 | \\ a -= (a -= 1); | |
| 638 | \\ a *= (a *= 1); | |
| 639 | \\ a &= (a &= 1); | |
| 640 | \\ a |= (a |= 1); | |
| 641 | \\ a ^= (a ^= 1); | |
| 642 | \\ a >>= (a >>= 1); | |
| 643 | \\ a <<= (a <<= 1); | |
| 644 | \\} | |
| 645 | , | |
| 646 | \\export fn foo() { | |
| 647 | \\ var a: c_int = 0; | |
| 648 | \\ a += { | |
| 649 | \\ const _ref = &a; | |
| 650 | \\ (*_ref) = ((*_ref) + 1); | |
| 651 | \\ *_ref | |
| 652 | \\ }; | |
| 653 | \\ a -= { | |
| 654 | \\ const _ref = &a; | |
| 655 | \\ (*_ref) = ((*_ref) - 1); | |
| 656 | \\ *_ref | |
| 657 | \\ }; | |
| 658 | \\ a *= { | |
| 659 | \\ const _ref = &a; | |
| 660 | \\ (*_ref) = ((*_ref) * 1); | |
| 661 | \\ *_ref | |
| 662 | \\ }; | |
| 663 | \\ a &= { | |
| 664 | \\ const _ref = &a; | |
| 665 | \\ (*_ref) = ((*_ref) & 1); | |
| 666 | \\ *_ref | |
| 667 | \\ }; | |
| 668 | \\ a |= { | |
| 669 | \\ const _ref = &a; | |
| 670 | \\ (*_ref) = ((*_ref) | 1); | |
| 671 | \\ *_ref | |
| 672 | \\ }; | |
| 673 | \\ a ^= { | |
| 674 | \\ const _ref = &a; | |
| 675 | \\ (*_ref) = ((*_ref) ^ 1); | |
| 676 | \\ *_ref | |
| 677 | \\ }; | |
| 678 | \\ a >>= @import("std").math.Log2Int(c_int)({ | |
| 679 | \\ const _ref = &a; | |
| 680 | \\ (*_ref) = c_int(c_int(*_ref) >> @import("std").math.Log2Int(c_int)(1)); | |
| 681 | \\ *_ref | |
| 682 | \\ }); | |
| 683 | \\ a <<= @import("std").math.Log2Int(c_int)({ | |
| 684 | \\ const _ref = &a; | |
| 685 | \\ (*_ref) = c_int(c_int(*_ref) << @import("std").math.Log2Int(c_int)(1)); | |
| 686 | \\ *_ref | |
| 687 | \\ }); | |
| 688 | \\} | |
| 689 | ); | |
| 690 | ||
| 691 | cases.addC("compound assignment operators unsigned", | |
| 692 | \\void foo(void) { | |
| 693 | \\ unsigned a = 0; | |
| 694 | \\ a += (a += 1); | |
| 695 | \\ a -= (a -= 1); | |
| 696 | \\ a *= (a *= 1); | |
| 697 | \\ a &= (a &= 1); | |
| 698 | \\ a |= (a |= 1); | |
| 699 | \\ a ^= (a ^= 1); | |
| 700 | \\ a >>= (a >>= 1); | |
| 701 | \\ a <<= (a <<= 1); | |
| 702 | \\} | |
| 703 | , | |
| 704 | \\export fn foo() { | |
| 705 | \\ var a: c_uint = c_uint(0); | |
| 706 | \\ a +%= { | |
| 707 | \\ const _ref = &a; | |
| 708 | \\ (*_ref) = ((*_ref) +% c_uint(1)); | |
| 709 | \\ *_ref | |
| 710 | \\ }; | |
| 711 | \\ a -%= { | |
| 712 | \\ const _ref = &a; | |
| 713 | \\ (*_ref) = ((*_ref) -% c_uint(1)); | |
| 714 | \\ *_ref | |
| 715 | \\ }; | |
| 716 | \\ a *%= { | |
| 717 | \\ const _ref = &a; | |
| 718 | \\ (*_ref) = ((*_ref) *% c_uint(1)); | |
| 719 | \\ *_ref | |
| 720 | \\ }; | |
| 721 | \\ a &= { | |
| 722 | \\ const _ref = &a; | |
| 723 | \\ (*_ref) = ((*_ref) & c_uint(1)); | |
| 724 | \\ *_ref | |
| 725 | \\ }; | |
| 726 | \\ a |= { | |
| 727 | \\ const _ref = &a; | |
| 728 | \\ (*_ref) = ((*_ref) | c_uint(1)); | |
| 729 | \\ *_ref | |
| 730 | \\ }; | |
| 731 | \\ a ^= { | |
| 732 | \\ const _ref = &a; | |
| 733 | \\ (*_ref) = ((*_ref) ^ c_uint(1)); | |
| 734 | \\ *_ref | |
| 735 | \\ }; | |
| 736 | \\ a >>= @import("std").math.Log2Int(c_uint)({ | |
| 737 | \\ const _ref = &a; | |
| 738 | \\ (*_ref) = c_uint(c_uint(*_ref) >> @import("std").math.Log2Int(c_uint)(1)); | |
| 739 | \\ *_ref | |
| 740 | \\ }); | |
| 741 | \\ a <<= @import("std").math.Log2Int(c_uint)({ | |
| 742 | \\ const _ref = &a; | |
| 743 | \\ (*_ref) = c_uint(c_uint(*_ref) << @import("std").math.Log2Int(c_uint)(1)); | |
| 744 | \\ *_ref | |
| 745 | \\ }); | |
| 746 | \\} | |
| 747 | ); | |
| 748 | ||
| 749 | cases.addC("duplicate typedef", | |
| 750 | \\typedef long foo; | |
| 751 | \\typedef int bar; | |
| 752 | \\typedef long foo; | |
| 753 | \\typedef int baz; | |
| 754 | , | |
| 755 | \\pub const foo = c_long; | |
| 756 | \\pub const bar = c_int; | |
| 757 | \\pub const baz = c_int; | |
| 758 | ); | |
| 759 | ||
| 760 | cases.addC("post increment/decrement", | |
| 761 | \\void foo(void) { | |
| 762 | \\ int i = 0; | |
| 763 | \\ unsigned u = 0; | |
| 764 | \\ i++; | |
| 765 | \\ i--; | |
| 766 | \\ u++; | |
| 767 | \\ u--; | |
| 768 | \\ i = i++; | |
| 769 | \\ i = i--; | |
| 770 | \\ u = u++; | |
| 771 | \\ u = u--; | |
| 772 | \\} | |
| 773 | , | |
| 774 | \\export fn foo() { | |
| 775 | \\ var i: c_int = 0; | |
| 776 | \\ var u: c_uint = c_uint(0); | |
| 777 | \\ i += 1; | |
| 778 | \\ i -= 1; | |
| 779 | \\ u +%= 1; | |
| 780 | \\ u -%= 1; | |
| 781 | \\ i = { | |
| 782 | \\ const _ref = &i; | |
| 783 | \\ const _tmp = *_ref; | |
| 784 | \\ (*_ref) += 1; | |
| 785 | \\ _tmp | |
| 786 | \\ }; | |
| 787 | \\ i = { | |
| 788 | \\ const _ref = &i; | |
| 789 | \\ const _tmp = *_ref; | |
| 790 | \\ (*_ref) -= 1; | |
| 791 | \\ _tmp | |
| 792 | \\ }; | |
| 793 | \\ u = { | |
| 794 | \\ const _ref = &u; | |
| 795 | \\ const _tmp = *_ref; | |
| 796 | \\ (*_ref) +%= 1; | |
| 797 | \\ _tmp | |
| 798 | \\ }; | |
| 799 | \\ u = { | |
| 800 | \\ const _ref = &u; | |
| 801 | \\ const _tmp = *_ref; | |
| 802 | \\ (*_ref) -%= 1; | |
| 803 | \\ _tmp | |
| 804 | \\ }; | |
| 805 | \\} | |
| 806 | ); | |
| 807 | ||
| 808 | cases.addC("do loop", | |
| 809 | \\void foo(void) { | |
| 810 | \\ int a = 2; | |
| 811 | \\ do { | |
| 812 | \\ a--; | |
| 813 | \\ } while (a != 0); | |
| 814 | \\ | |
| 815 | \\ int b = 2; | |
| 816 | \\ do | |
| 817 | \\ b--; | |
| 818 | \\ while (b != 0); | |
| 819 | \\} | |
| 820 | , | |
| 821 | \\export fn foo() { | |
| 822 | \\ var a: c_int = 2; | |
| 823 | \\ while (true) { | |
| 824 | \\ a -= 1; | |
| 825 | \\ if (!(a != 0)) break; | |
| 826 | \\ }; | |
| 827 | \\ var b: c_int = 2; | |
| 828 | \\ while (true) { | |
| 829 | \\ b -= 1; | |
| 830 | \\ if (!(b != 0)) break; | |
| 831 | \\ }; | |
| 832 | \\} | |
| 833 | ); | |
| 834 | ||
| 835 | cases.addC("deref function pointer", | |
| 836 | \\void foo(void) {} | |
| 837 | \\void bar(void) { | |
| 838 | \\ void(*f)(void) = foo; | |
| 839 | \\ f(); | |
| 840 | \\ (*(f))(); | |
| 841 | \\} | |
| 842 | , | |
| 843 | \\export fn foo() {} | |
| 844 | \\export fn bar() { | |
| 845 | \\ var f: ?extern fn() = foo; | |
| 846 | \\ (??f)(); | |
| 847 | \\ (??f)(); | |
| 848 | \\} | |
| 849 | ); | |
| 850 | ||
| 851 | cases.addC("normal deref", | |
| 852 | \\void foo(int *x) { | |
| 853 | \\ *x = 1; | |
| 854 | \\} | |
| 855 | , | |
| 856 | \\export fn foo(x: ?&c_int) { | |
| 857 | \\ (*(??x)) = 1; | |
| 858 | \\} | |
| 859 | ); | |
| 860 | ||
| 861 | cases.add("simple union", | |
| 862 | \\union Foo { | |
| 863 | \\ int x; | |
| 864 | \\ double y; | |
| 865 | \\}; | |
| 866 | , | |
| 867 | \\pub const union_Foo = extern union { | |
| 868 | \\ x: c_int, | |
| 869 | \\ y: f64, | |
| 870 | \\}; | |
| 871 | , | |
| 872 | \\pub const Foo = union_Foo; | |
| 873 | ); | |
| 874 | ||
| 875 | cases.add("address of operator", | |
| 876 | \\int foo(void) { | |
| 877 | \\ int x = 1234; | |
| 878 | \\ int *ptr = &x; | |
| 879 | \\ return *ptr; | |
| 880 | \\} | |
| 881 | , | |
| 882 | \\pub fn foo() -> c_int { | |
| 883 | \\ var x: c_int = 1234; | |
| 884 | \\ var ptr: ?&c_int = &x; | |
| 885 | \\ return *(??ptr); | |
| 886 | \\} | |
| 887 | ); | |
| 888 | } | |
| 889 | ||
| 890 | ||
| 891 | ||
| 892 | // TODO | |
| 893 | //float *ptrcast(int *a) { | |
| 894 | // return (float *)a; | |
| 895 | //} | |
| 896 | // should translate to | |
| 897 | // fn ptrcast(a: ?&c_int) -> ?&f32 { | |
| 898 | // return @ptrCast(?&f32, a); | |
| 899 | // } |
test/tests.zig+24-24| ... | ... | @@ -18,7 +18,7 @@ const build_examples = @import("build_examples.zig"); |
| 18 | 18 | const compile_errors = @import("compile_errors.zig"); |
| 19 | 19 | const assemble_and_link = @import("assemble_and_link.zig"); |
| 20 | 20 | const debug_safety = @import("debug_safety.zig"); |
| 21 | const parsec = @import("parsec.zig"); | |
| 21 | const translate_c = @import("translate_c.zig"); | |
| 22 | 22 | |
| 23 | 23 | const TestTarget = struct { |
| 24 | 24 | os: builtin.Os, |
| ... | ... | @@ -123,16 +123,16 @@ pub fn addAssembleAndLinkTests(b: &build.Builder, test_filter: ?[]const u8) -> & |
| 123 | 123 | return cases.step; |
| 124 | 124 | } |
| 125 | 125 | |
| 126 | pub fn addParseCTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step { | |
| 127 | const cases = %%b.allocator.create(ParseCContext); | |
| 128 | *cases = ParseCContext { | |
| 126 | pub fn addTranslateCTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step { | |
| 127 | const cases = %%b.allocator.create(TranslateCContext); | |
| 128 | *cases = TranslateCContext { | |
| 129 | 129 | .b = b, |
| 130 | .step = b.step("test-parsec", "Run the C header file parsing tests"), | |
| 130 | .step = b.step("test-translate-c", "Run the C header file parsing tests"), | |
| 131 | 131 | .test_index = 0, |
| 132 | 132 | .test_filter = test_filter, |
| 133 | 133 | }; |
| 134 | 134 | |
| 135 | parsec.addCases(cases); | |
| 135 | translate_c.addCases(cases); | |
| 136 | 136 | |
| 137 | 137 | return cases.step; |
| 138 | 138 | } |
| ... | ... | @@ -770,7 +770,7 @@ pub const BuildExamplesContext = struct { |
| 770 | 770 | } |
| 771 | 771 | }; |
| 772 | 772 | |
| 773 | pub const ParseCContext = struct { | |
| 773 | pub const TranslateCContext = struct { | |
| 774 | 774 | b: &build.Builder, |
| 775 | 775 | step: &build.Step, |
| 776 | 776 | test_index: usize, |
| ... | ... | @@ -799,17 +799,17 @@ pub const ParseCContext = struct { |
| 799 | 799 | } |
| 800 | 800 | }; |
| 801 | 801 | |
| 802 | const ParseCCmpOutputStep = struct { | |
| 802 | const TranslateCCmpOutputStep = struct { | |
| 803 | 803 | step: build.Step, |
| 804 | context: &ParseCContext, | |
| 804 | context: &TranslateCContext, | |
| 805 | 805 | name: []const u8, |
| 806 | 806 | test_index: usize, |
| 807 | 807 | case: &const TestCase, |
| 808 | 808 | |
| 809 | pub fn create(context: &ParseCContext, name: []const u8, case: &const TestCase) -> &ParseCCmpOutputStep { | |
| 809 | pub fn create(context: &TranslateCContext, name: []const u8, case: &const TestCase) -> &TranslateCCmpOutputStep { | |
| 810 | 810 | const allocator = context.b.allocator; |
| 811 | const ptr = %%allocator.create(ParseCCmpOutputStep); | |
| 812 | *ptr = ParseCCmpOutputStep { | |
| 811 | const ptr = %%allocator.create(TranslateCCmpOutputStep); | |
| 812 | *ptr = TranslateCCmpOutputStep { | |
| 813 | 813 | .step = build.Step.init("ParseCCmpOutput", allocator, make), |
| 814 | 814 | .context = context, |
| 815 | 815 | .name = name, |
| ... | ... | @@ -821,7 +821,7 @@ pub const ParseCContext = struct { |
| 821 | 821 | } |
| 822 | 822 | |
| 823 | 823 | fn make(step: &build.Step) -> %void { |
| 824 | const self = @fieldParentPtr(ParseCCmpOutputStep, "step", step); | |
| 824 | const self = @fieldParentPtr(TranslateCCmpOutputStep, "step", step); | |
| 825 | 825 | const b = self.context.b; |
| 826 | 826 | |
| 827 | 827 | const root_src = %%os.path.join(b.allocator, b.cache_root, self.case.sources.items[0].filename); |
| ... | ... | @@ -829,7 +829,7 @@ pub const ParseCContext = struct { |
| 829 | 829 | var zig_args = ArrayList([]const u8).init(b.allocator); |
| 830 | 830 | %%zig_args.append(b.zig_exe); |
| 831 | 831 | |
| 832 | %%zig_args.append("parsec"); | |
| 832 | %%zig_args.append("translate-c"); | |
| 833 | 833 | %%zig_args.append(b.pathFromRoot(root_src)); |
| 834 | 834 | |
| 835 | 835 | warn("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); |
| ... | ... | @@ -882,7 +882,7 @@ pub const ParseCContext = struct { |
| 882 | 882 | |
| 883 | 883 | if (stderr.len != 0 and !self.case.allow_warnings) { |
| 884 | 884 | warn( |
| 885 | \\====== parsec emitted warnings: ============ | |
| 885 | \\====== translate-c emitted warnings: ======= | |
| 886 | 886 | \\{} |
| 887 | 887 | \\============================================ |
| 888 | 888 | \\ |
| ... | ... | @@ -914,7 +914,7 @@ pub const ParseCContext = struct { |
| 914 | 914 | warn("\n"); |
| 915 | 915 | } |
| 916 | 916 | |
| 917 | pub fn create(self: &ParseCContext, allow_warnings: bool, filename: []const u8, name: []const u8, | |
| 917 | pub fn create(self: &TranslateCContext, allow_warnings: bool, filename: []const u8, name: []const u8, | |
| 918 | 918 | source: []const u8, expected_lines: ...) -> &TestCase |
| 919 | 919 | { |
| 920 | 920 | const tc = %%self.b.allocator.create(TestCase); |
| ... | ... | @@ -932,37 +932,37 @@ pub const ParseCContext = struct { |
| 932 | 932 | return tc; |
| 933 | 933 | } |
| 934 | 934 | |
| 935 | pub fn add(self: &ParseCContext, name: []const u8, source: []const u8, expected_lines: ...) { | |
| 935 | pub fn add(self: &TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) { | |
| 936 | 936 | const tc = self.create(false, "source.h", name, source, expected_lines); |
| 937 | 937 | self.addCase(tc); |
| 938 | 938 | } |
| 939 | 939 | |
| 940 | pub fn addC(self: &ParseCContext, name: []const u8, source: []const u8, expected_lines: ...) { | |
| 940 | pub fn addC(self: &TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) { | |
| 941 | 941 | const tc = self.create(false, "source.c", name, source, expected_lines); |
| 942 | 942 | self.addCase(tc); |
| 943 | 943 | } |
| 944 | 944 | |
| 945 | pub fn addAllowWarnings(self: &ParseCContext, name: []const u8, source: []const u8, expected_lines: ...) { | |
| 945 | pub fn addAllowWarnings(self: &TranslateCContext, name: []const u8, source: []const u8, expected_lines: ...) { | |
| 946 | 946 | const tc = self.create(true, "source.h", name, source, expected_lines); |
| 947 | 947 | self.addCase(tc); |
| 948 | 948 | } |
| 949 | 949 | |
| 950 | pub fn addCase(self: &ParseCContext, case: &const TestCase) { | |
| 950 | pub fn addCase(self: &TranslateCContext, case: &const TestCase) { | |
| 951 | 951 | const b = self.b; |
| 952 | 952 | |
| 953 | const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "parsec {}", case.name); | |
| 953 | const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "translate-c {}", case.name); | |
| 954 | 954 | if (self.test_filter) |filter| { |
| 955 | 955 | if (mem.indexOf(u8, annotated_case_name, filter) == null) |
| 956 | 956 | return; |
| 957 | 957 | } |
| 958 | 958 | |
| 959 | const parsec_and_cmp = ParseCCmpOutputStep.create(self, annotated_case_name, case); | |
| 960 | self.step.dependOn(&parsec_and_cmp.step); | |
| 959 | const translate_c_and_cmp = TranslateCCmpOutputStep.create(self, annotated_case_name, case); | |
| 960 | self.step.dependOn(&translate_c_and_cmp.step); | |
| 961 | 961 | |
| 962 | 962 | for (case.sources.toSliceConst()) |src_file| { |
| 963 | 963 | const expanded_src_path = %%os.path.join(b.allocator, b.cache_root, src_file.filename); |
| 964 | 964 | const write_src = b.addWriteFile(expanded_src_path, src_file.source); |
| 965 | parsec_and_cmp.step.dependOn(&write_src.step); | |
| 965 | translate_c_and_cmp.step.dependOn(&write_src.step); | |
| 966 | 966 | } |
| 967 | 967 | } |
| 968 | 968 | }; |
test/translate_c.zig created+899| ... | ... | @@ -0,0 +1,899 @@ |
| 1 | const tests = @import("tests.zig"); | |
| 2 | ||
| 3 | pub fn addCases(cases: &tests.TranslateCContext) { | |
| 4 | cases.addAllowWarnings("simple data types", | |
| 5 | \\#include <stdint.h> | |
| 6 | \\int foo(char a, unsigned char b, signed char c); | |
| 7 | \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype | |
| 8 | \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d); | |
| 9 | \\void baz(int8_t a, int16_t b, int32_t c, int64_t d); | |
| 10 | , | |
| 11 | \\pub extern fn foo(a: u8, b: u8, c: i8) -> c_int; | |
| 12 | , | |
| 13 | \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64); | |
| 14 | , | |
| 15 | \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64); | |
| 16 | ); | |
| 17 | ||
| 18 | cases.add("noreturn attribute", | |
| 19 | \\void foo(void) __attribute__((noreturn)); | |
| 20 | , | |
| 21 | \\pub extern fn foo() -> noreturn; | |
| 22 | ); | |
| 23 | ||
| 24 | cases.addC("simple function", | |
| 25 | \\int abs(int a) { | |
| 26 | \\ return a < 0 ? -a : a; | |
| 27 | \\} | |
| 28 | , | |
| 29 | \\export fn abs(a: c_int) -> c_int { | |
| 30 | \\ return if (a < 0) -a else a; | |
| 31 | \\} | |
| 32 | ); | |
| 33 | ||
| 34 | cases.add("enums", | |
| 35 | \\enum Foo { | |
| 36 | \\ FooA, | |
| 37 | \\ FooB, | |
| 38 | \\ Foo1, | |
| 39 | \\}; | |
| 40 | , | |
| 41 | \\pub const enum_Foo = extern enum { | |
| 42 | \\ A, | |
| 43 | \\ B, | |
| 44 | \\ @"1", | |
| 45 | \\}; | |
| 46 | , | |
| 47 | \\pub const FooA = enum_Foo.A; | |
| 48 | , | |
| 49 | \\pub const FooB = enum_Foo.B; | |
| 50 | , | |
| 51 | \\pub const Foo1 = enum_Foo.@"1"; | |
| 52 | , | |
| 53 | \\pub const Foo = enum_Foo; | |
| 54 | ); | |
| 55 | ||
| 56 | cases.add("restrict -> noalias", | |
| 57 | \\void foo(void *restrict bar, void *restrict); | |
| 58 | , | |
| 59 | \\pub extern fn foo(noalias bar: ?&c_void, noalias arg1: ?&c_void); | |
| 60 | ); | |
| 61 | ||
| 62 | cases.add("simple struct", | |
| 63 | \\struct Foo { | |
| 64 | \\ int x; | |
| 65 | \\ char *y; | |
| 66 | \\}; | |
| 67 | , | |
| 68 | \\const struct_Foo = extern struct { | |
| 69 | \\ x: c_int, | |
| 70 | \\ y: ?&u8, | |
| 71 | \\}; | |
| 72 | , | |
| 73 | \\pub const Foo = struct_Foo; | |
| 74 | ); | |
| 75 | ||
| 76 | cases.add("qualified struct and enum", | |
| 77 | \\struct Foo { | |
| 78 | \\ int x; | |
| 79 | \\ int y; | |
| 80 | \\}; | |
| 81 | \\enum Bar { | |
| 82 | \\ BarA, | |
| 83 | \\ BarB, | |
| 84 | \\}; | |
| 85 | \\void func(struct Foo *a, enum Bar **b); | |
| 86 | , | |
| 87 | \\pub const struct_Foo = extern struct { | |
| 88 | \\ x: c_int, | |
| 89 | \\ y: c_int, | |
| 90 | \\}; | |
| 91 | , | |
| 92 | \\pub const enum_Bar = extern enum { | |
| 93 | \\ A, | |
| 94 | \\ B, | |
| 95 | \\}; | |
| 96 | , | |
| 97 | \\pub const BarA = enum_Bar.A; | |
| 98 | , | |
| 99 | \\pub const BarB = enum_Bar.B; | |
| 100 | , | |
| 101 | \\pub extern fn func(a: ?&struct_Foo, b: ?&(?&enum_Bar)); | |
| 102 | , | |
| 103 | \\pub const Foo = struct_Foo; | |
| 104 | , | |
| 105 | \\pub const Bar = enum_Bar; | |
| 106 | ); | |
| 107 | ||
| 108 | cases.add("constant size array", | |
| 109 | \\void func(int array[20]); | |
| 110 | , | |
| 111 | \\pub extern fn func(array: ?&c_int); | |
| 112 | ); | |
| 113 | ||
| 114 | cases.add("self referential struct with function pointer", | |
| 115 | \\struct Foo { | |
| 116 | \\ void (*derp)(struct Foo *foo); | |
| 117 | \\}; | |
| 118 | , | |
| 119 | \\pub const struct_Foo = extern struct { | |
| 120 | \\ derp: ?extern fn(?&struct_Foo), | |
| 121 | \\}; | |
| 122 | , | |
| 123 | \\pub const Foo = struct_Foo; | |
| 124 | ); | |
| 125 | ||
| 126 | cases.add("struct prototype used in func", | |
| 127 | \\struct Foo; | |
| 128 | \\struct Foo *some_func(struct Foo *foo, int x); | |
| 129 | , | |
| 130 | \\pub const struct_Foo = @OpaqueType(); | |
| 131 | , | |
| 132 | \\pub extern fn some_func(foo: ?&struct_Foo, x: c_int) -> ?&struct_Foo; | |
| 133 | , | |
| 134 | \\pub const Foo = struct_Foo; | |
| 135 | ); | |
| 136 | ||
| 137 | cases.add("#define a char literal", | |
| 138 | \\#define A_CHAR 'a' | |
| 139 | , | |
| 140 | \\pub const A_CHAR = 97; | |
| 141 | ); | |
| 142 | ||
| 143 | cases.add("#define an unsigned integer literal", | |
| 144 | \\#define CHANNEL_COUNT 24 | |
| 145 | , | |
| 146 | \\pub const CHANNEL_COUNT = 24; | |
| 147 | ); | |
| 148 | ||
| 149 | cases.add("#define referencing another #define", | |
| 150 | \\#define THING2 THING1 | |
| 151 | \\#define THING1 1234 | |
| 152 | , | |
| 153 | \\pub const THING1 = 1234; | |
| 154 | , | |
| 155 | \\pub const THING2 = THING1; | |
| 156 | ); | |
| 157 | ||
| 158 | cases.add("variables", | |
| 159 | \\extern int extern_var; | |
| 160 | \\static const int int_var = 13; | |
| 161 | , | |
| 162 | \\pub extern var extern_var: c_int; | |
| 163 | , | |
| 164 | \\pub const int_var: c_int = 13; | |
| 165 | ); | |
| 166 | ||
| 167 | cases.add("circular struct definitions", | |
| 168 | \\struct Bar; | |
| 169 | \\ | |
| 170 | \\struct Foo { | |
| 171 | \\ struct Bar *next; | |
| 172 | \\}; | |
| 173 | \\ | |
| 174 | \\struct Bar { | |
| 175 | \\ struct Foo *next; | |
| 176 | \\}; | |
| 177 | , | |
| 178 | \\pub const struct_Bar = extern struct { | |
| 179 | \\ next: ?&struct_Foo, | |
| 180 | \\}; | |
| 181 | , | |
| 182 | \\pub const struct_Foo = extern struct { | |
| 183 | \\ next: ?&struct_Bar, | |
| 184 | \\}; | |
| 185 | ); | |
| 186 | ||
| 187 | cases.add("typedef void", | |
| 188 | \\typedef void Foo; | |
| 189 | \\Foo fun(Foo *a); | |
| 190 | , | |
| 191 | \\pub const Foo = c_void; | |
| 192 | , | |
| 193 | \\pub extern fn fun(a: ?&Foo) -> Foo; | |
| 194 | ); | |
| 195 | ||
| 196 | cases.add("generate inline func for #define global extern fn", | |
| 197 | \\extern void (*fn_ptr)(void); | |
| 198 | \\#define foo fn_ptr | |
| 199 | \\ | |
| 200 | \\extern char (*fn_ptr2)(int, float); | |
| 201 | \\#define bar fn_ptr2 | |
| 202 | , | |
| 203 | \\pub extern var fn_ptr: ?extern fn(); | |
| 204 | , | |
| 205 | \\pub inline fn foo() { | |
| 206 | \\ (??fn_ptr)() | |
| 207 | \\} | |
| 208 | , | |
| 209 | \\pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8; | |
| 210 | , | |
| 211 | \\pub inline fn bar(arg0: c_int, arg1: f32) -> u8 { | |
| 212 | \\ (??fn_ptr2)(arg0, arg1) | |
| 213 | \\} | |
| 214 | ); | |
| 215 | ||
| 216 | cases.add("#define string", | |
| 217 | \\#define foo "a string" | |
| 218 | , | |
| 219 | \\pub const foo = c"a string"; | |
| 220 | ); | |
| 221 | ||
| 222 | cases.add("__cdecl doesn't mess up function pointers", | |
| 223 | \\void foo(void (__cdecl *fn_ptr)(void)); | |
| 224 | , | |
| 225 | \\pub extern fn foo(fn_ptr: ?extern fn()); | |
| 226 | ); | |
| 227 | ||
| 228 | cases.add("comment after integer literal", | |
| 229 | \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 230 | , | |
| 231 | \\pub const SDL_INIT_VIDEO = 32; | |
| 232 | ); | |
| 233 | ||
| 234 | cases.add("u integer suffix after hex literal", | |
| 235 | \\#define SDL_INIT_VIDEO 0x00000020u /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 236 | , | |
| 237 | \\pub const SDL_INIT_VIDEO = c_uint(32); | |
| 238 | ); | |
| 239 | ||
| 240 | cases.add("l integer suffix after hex literal", | |
| 241 | \\#define SDL_INIT_VIDEO 0x00000020l /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 242 | , | |
| 243 | \\pub const SDL_INIT_VIDEO = c_long(32); | |
| 244 | ); | |
| 245 | ||
| 246 | cases.add("ul integer suffix after hex literal", | |
| 247 | \\#define SDL_INIT_VIDEO 0x00000020ul /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 248 | , | |
| 249 | \\pub const SDL_INIT_VIDEO = c_ulong(32); | |
| 250 | ); | |
| 251 | ||
| 252 | cases.add("lu integer suffix after hex literal", | |
| 253 | \\#define SDL_INIT_VIDEO 0x00000020lu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 254 | , | |
| 255 | \\pub const SDL_INIT_VIDEO = c_ulong(32); | |
| 256 | ); | |
| 257 | ||
| 258 | cases.add("ll integer suffix after hex literal", | |
| 259 | \\#define SDL_INIT_VIDEO 0x00000020ll /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 260 | , | |
| 261 | \\pub const SDL_INIT_VIDEO = c_longlong(32); | |
| 262 | ); | |
| 263 | ||
| 264 | cases.add("ull integer suffix after hex literal", | |
| 265 | \\#define SDL_INIT_VIDEO 0x00000020ull /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 266 | , | |
| 267 | \\pub const SDL_INIT_VIDEO = c_ulonglong(32); | |
| 268 | ); | |
| 269 | ||
| 270 | cases.add("llu integer suffix after hex literal", | |
| 271 | \\#define SDL_INIT_VIDEO 0x00000020llu /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */ | |
| 272 | , | |
| 273 | \\pub const SDL_INIT_VIDEO = c_ulonglong(32); | |
| 274 | ); | |
| 275 | ||
| 276 | cases.add("zig keywords in C code", | |
| 277 | \\struct comptime { | |
| 278 | \\ int defer; | |
| 279 | \\}; | |
| 280 | , | |
| 281 | \\pub const struct_comptime = extern struct { | |
| 282 | \\ @"defer": c_int, | |
| 283 | \\}; | |
| 284 | , | |
| 285 | \\pub const @"comptime" = struct_comptime; | |
| 286 | ); | |
| 287 | ||
| 288 | cases.add("macro defines string literal with hex", | |
| 289 | \\#define FOO "aoeu\xab derp" | |
| 290 | \\#define FOO2 "aoeu\x0007a derp" | |
| 291 | \\#define FOO_CHAR '\xfF' | |
| 292 | , | |
| 293 | \\pub const FOO = c"aoeu\xab derp"; | |
| 294 | , | |
| 295 | \\pub const FOO2 = c"aoeuz derp"; | |
| 296 | , | |
| 297 | \\pub const FOO_CHAR = 255; | |
| 298 | ); | |
| 299 | ||
| 300 | cases.add("macro defines string literal with octal", | |
| 301 | \\#define FOO "aoeu\023 derp" | |
| 302 | \\#define FOO2 "aoeu\0234 derp" | |
| 303 | \\#define FOO_CHAR '\077' | |
| 304 | , | |
| 305 | \\pub const FOO = c"aoeu\x13 derp"; | |
| 306 | , | |
| 307 | \\pub const FOO2 = c"aoeu\x134 derp"; | |
| 308 | , | |
| 309 | \\pub const FOO_CHAR = 63; | |
| 310 | ); | |
| 311 | ||
| 312 | cases.add("macro with parens around negative number", | |
| 313 | \\#define LUA_GLOBALSINDEX (-10002) | |
| 314 | , | |
| 315 | \\pub const LUA_GLOBALSINDEX = -10002; | |
| 316 | ); | |
| 317 | ||
| 318 | cases.addC("post increment", | |
| 319 | \\unsigned foo1(unsigned a) { | |
| 320 | \\ a++; | |
| 321 | \\ return a; | |
| 322 | \\} | |
| 323 | \\int foo2(int a) { | |
| 324 | \\ a++; | |
| 325 | \\ return a; | |
| 326 | \\} | |
| 327 | , | |
| 328 | \\export fn foo1(_arg_a: c_uint) -> c_uint { | |
| 329 | \\ var a = _arg_a; | |
| 330 | \\ a +%= 1; | |
| 331 | \\ return a; | |
| 332 | \\} | |
| 333 | \\export fn foo2(_arg_a: c_int) -> c_int { | |
| 334 | \\ var a = _arg_a; | |
| 335 | \\ a += 1; | |
| 336 | \\ return a; | |
| 337 | \\} | |
| 338 | ); | |
| 339 | ||
| 340 | cases.addC("shift right assign", | |
| 341 | \\int log2(unsigned a) { | |
| 342 | \\ int i = 0; | |
| 343 | \\ while (a > 0) { | |
| 344 | \\ a >>= 1; | |
| 345 | \\ } | |
| 346 | \\ return i; | |
| 347 | \\} | |
| 348 | , | |
| 349 | \\export fn log2(_arg_a: c_uint) -> c_int { | |
| 350 | \\ var a = _arg_a; | |
| 351 | \\ var i: c_int = 0; | |
| 352 | \\ while (a > c_uint(0)) { | |
| 353 | \\ a >>= @import("std").math.Log2Int(c_uint)(1); | |
| 354 | \\ }; | |
| 355 | \\ return i; | |
| 356 | \\} | |
| 357 | ); | |
| 358 | ||
| 359 | cases.addC("if statement", | |
| 360 | \\int max(int a, int b) { | |
| 361 | \\ if (a < b) | |
| 362 | \\ return b; | |
| 363 | \\ | |
| 364 | \\ if (a < b) | |
| 365 | \\ return b; | |
| 366 | \\ else | |
| 367 | \\ return a; | |
| 368 | \\} | |
| 369 | , | |
| 370 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 371 | \\ if (a < b) return b; | |
| 372 | \\ if (a < b) return b else return a; | |
| 373 | \\} | |
| 374 | ); | |
| 375 | ||
| 376 | cases.addC("==, !=", | |
| 377 | \\int max(int a, int b) { | |
| 378 | \\ if (a == b) | |
| 379 | \\ return a; | |
| 380 | \\ if (a != b) | |
| 381 | \\ return b; | |
| 382 | \\ return a; | |
| 383 | \\} | |
| 384 | , | |
| 385 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 386 | \\ if (a == b) return a; | |
| 387 | \\ if (a != b) return b; | |
| 388 | \\ return a; | |
| 389 | \\} | |
| 390 | ); | |
| 391 | ||
| 392 | cases.addC("add, sub, mul, div, rem", | |
| 393 | \\int s(int a, int b) { | |
| 394 | \\ int c; | |
| 395 | \\ c = a + b; | |
| 396 | \\ c = a - b; | |
| 397 | \\ c = a * b; | |
| 398 | \\ c = a / b; | |
| 399 | \\ c = a % b; | |
| 400 | \\} | |
| 401 | \\unsigned u(unsigned a, unsigned b) { | |
| 402 | \\ unsigned c; | |
| 403 | \\ c = a + b; | |
| 404 | \\ c = a - b; | |
| 405 | \\ c = a * b; | |
| 406 | \\ c = a / b; | |
| 407 | \\ c = a % b; | |
| 408 | \\} | |
| 409 | , | |
| 410 | \\export fn s(a: c_int, b: c_int) -> c_int { | |
| 411 | \\ var c: c_int; | |
| 412 | \\ c = (a + b); | |
| 413 | \\ c = (a - b); | |
| 414 | \\ c = (a * b); | |
| 415 | \\ c = @divTrunc(a, b); | |
| 416 | \\ c = @rem(a, b); | |
| 417 | \\} | |
| 418 | \\export fn u(a: c_uint, b: c_uint) -> c_uint { | |
| 419 | \\ var c: c_uint; | |
| 420 | \\ c = (a +% b); | |
| 421 | \\ c = (a -% b); | |
| 422 | \\ c = (a *% b); | |
| 423 | \\ c = (a / b); | |
| 424 | \\ c = (a % b); | |
| 425 | \\} | |
| 426 | ); | |
| 427 | ||
| 428 | cases.addC("bitwise binary operators", | |
| 429 | \\int max(int a, int b) { | |
| 430 | \\ return (a & b) ^ (a | b); | |
| 431 | \\} | |
| 432 | , | |
| 433 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 434 | \\ return (a & b) ^ (a | b); | |
| 435 | \\} | |
| 436 | ); | |
| 437 | ||
| 438 | cases.addC("logical and, logical or", | |
| 439 | \\int max(int a, int b) { | |
| 440 | \\ if (a < b || a == b) | |
| 441 | \\ return b; | |
| 442 | \\ if (a >= b && a == b) | |
| 443 | \\ return a; | |
| 444 | \\ return a; | |
| 445 | \\} | |
| 446 | , | |
| 447 | \\export fn max(a: c_int, b: c_int) -> c_int { | |
| 448 | \\ if ((a < b) or (a == b)) return b; | |
| 449 | \\ if ((a >= b) and (a == b)) return a; | |
| 450 | \\ return a; | |
| 451 | \\} | |
| 452 | ); | |
| 453 | ||
| 454 | cases.addC("assign", | |
| 455 | \\int max(int a) { | |
| 456 | \\ int tmp; | |
| 457 | \\ tmp = a; | |
| 458 | \\ a = tmp; | |
| 459 | \\} | |
| 460 | , | |
| 461 | \\export fn max(_arg_a: c_int) -> c_int { | |
| 462 | \\ var a = _arg_a; | |
| 463 | \\ var tmp: c_int; | |
| 464 | \\ tmp = a; | |
| 465 | \\ a = tmp; | |
| 466 | \\} | |
| 467 | ); | |
| 468 | ||
| 469 | cases.addC("chaining assign", | |
| 470 | \\void max(int a) { | |
| 471 | \\ int b, c; | |
| 472 | \\ c = b = a; | |
| 473 | \\} | |
| 474 | , | |
| 475 | \\export fn max(a: c_int) { | |
| 476 | \\ var b: c_int; | |
| 477 | \\ var c: c_int; | |
| 478 | \\ c = { | |
| 479 | \\ const _tmp = a; | |
| 480 | \\ b = _tmp; | |
| 481 | \\ _tmp | |
| 482 | \\ }; | |
| 483 | \\} | |
| 484 | ); | |
| 485 | ||
| 486 | cases.addC("shift right assign with a fixed size type", | |
| 487 | \\#include <stdint.h> | |
| 488 | \\int log2(uint32_t a) { | |
| 489 | \\ int i = 0; | |
| 490 | \\ while (a > 0) { | |
| 491 | \\ a >>= 1; | |
| 492 | \\ } | |
| 493 | \\ return i; | |
| 494 | \\} | |
| 495 | , | |
| 496 | \\export fn log2(_arg_a: u32) -> c_int { | |
| 497 | \\ var a = _arg_a; | |
| 498 | \\ var i: c_int = 0; | |
| 499 | \\ while (a > c_uint(0)) { | |
| 500 | \\ a >>= u5(1); | |
| 501 | \\ }; | |
| 502 | \\ return i; | |
| 503 | \\} | |
| 504 | ); | |
| 505 | ||
| 506 | cases.add("anonymous enum", | |
| 507 | \\enum { | |
| 508 | \\ One, | |
| 509 | \\ Two, | |
| 510 | \\}; | |
| 511 | , | |
| 512 | \\pub const One = 0; | |
| 513 | \\pub const Two = 1; | |
| 514 | ); | |
| 515 | ||
| 516 | cases.addC("function call", | |
| 517 | \\static void bar(void) { } | |
| 518 | \\void foo(void) { bar(); } | |
| 519 | , | |
| 520 | \\pub fn bar() {} | |
| 521 | \\export fn foo() { | |
| 522 | \\ bar(); | |
| 523 | \\} | |
| 524 | ); | |
| 525 | ||
| 526 | cases.addC("field access expression", | |
| 527 | \\struct Foo { | |
| 528 | \\ int field; | |
| 529 | \\}; | |
| 530 | \\int read_field(struct Foo *foo) { | |
| 531 | \\ return foo->field; | |
| 532 | \\} | |
| 533 | , | |
| 534 | \\pub const struct_Foo = extern struct { | |
| 535 | \\ field: c_int, | |
| 536 | \\}; | |
| 537 | \\export fn read_field(foo: ?&struct_Foo) -> c_int { | |
| 538 | \\ return (??foo).field; | |
| 539 | \\} | |
| 540 | ); | |
| 541 | ||
| 542 | cases.addC("null statements", | |
| 543 | \\void foo(void) { | |
| 544 | \\ ;;;;; | |
| 545 | \\} | |
| 546 | , | |
| 547 | \\export fn foo() {} | |
| 548 | ); | |
| 549 | ||
| 550 | cases.add("undefined array global", | |
| 551 | \\int array[100]; | |
| 552 | , | |
| 553 | \\pub var array: [100]c_int = undefined; | |
| 554 | ); | |
| 555 | ||
| 556 | cases.addC("array access", | |
| 557 | \\int array[100]; | |
| 558 | \\int foo(int index) { | |
| 559 | \\ return array[index]; | |
| 560 | \\} | |
| 561 | , | |
| 562 | \\pub var array: [100]c_int = undefined; | |
| 563 | \\export fn foo(index: c_int) -> c_int { | |
| 564 | \\ return array[index]; | |
| 565 | \\} | |
| 566 | ); | |
| 567 | ||
| 568 | ||
| 569 | cases.addC("c style cast", | |
| 570 | \\int float_to_int(float a) { | |
| 571 | \\ return (int)a; | |
| 572 | \\} | |
| 573 | , | |
| 574 | \\export fn float_to_int(a: f32) -> c_int { | |
| 575 | \\ return c_int(a); | |
| 576 | \\} | |
| 577 | ); | |
| 578 | ||
| 579 | cases.addC("implicit cast to void *", | |
| 580 | \\void *foo(unsigned short *x) { | |
| 581 | \\ return x; | |
| 582 | \\} | |
| 583 | , | |
| 584 | \\export fn foo(x: ?&c_ushort) -> ?&c_void { | |
| 585 | \\ return @ptrCast(?&c_void, x); | |
| 586 | \\} | |
| 587 | ); | |
| 588 | ||
| 589 | cases.addC("sizeof", | |
| 590 | \\#include <stddef.h> | |
| 591 | \\size_t size_of(void) { | |
| 592 | \\ return sizeof(int); | |
| 593 | \\} | |
| 594 | , | |
| 595 | \\export fn size_of() -> usize { | |
| 596 | \\ return @sizeOf(c_int); | |
| 597 | \\} | |
| 598 | ); | |
| 599 | ||
| 600 | cases.addC("null pointer implicit cast", | |
| 601 | \\int* foo(void) { | |
| 602 | \\ return 0; | |
| 603 | \\} | |
| 604 | , | |
| 605 | \\export fn foo() -> ?&c_int { | |
| 606 | \\ return null; | |
| 607 | \\} | |
| 608 | ); | |
| 609 | ||
| 610 | cases.addC("comma operator", | |
| 611 | \\int foo(void) { | |
| 612 | \\ return 1, 2; | |
| 613 | \\} | |
| 614 | , | |
| 615 | \\export fn foo() -> c_int { | |
| 616 | \\ return { | |
| 617 | \\ _ = 1; | |
| 618 | \\ 2 | |
| 619 | \\ }; | |
| 620 | \\} | |
| 621 | ); | |
| 622 | ||
| 623 | cases.addC("bitshift", | |
| 624 | \\int foo(void) { | |
| 625 | \\ return (1 << 2) >> 1; | |
| 626 | \\} | |
| 627 | , | |
| 628 | \\export fn foo() -> c_int { | |
| 629 | \\ return (1 << @import("std").math.Log2Int(c_int)(2)) >> @import("std").math.Log2Int(c_int)(1); | |
| 630 | \\} | |
| 631 | ); | |
| 632 | ||
| 633 | cases.addC("compound assignment operators", | |
| 634 | \\void foo(void) { | |
| 635 | \\ int a = 0; | |
| 636 | \\ a += (a += 1); | |
| 637 | \\ a -= (a -= 1); | |
| 638 | \\ a *= (a *= 1); | |
| 639 | \\ a &= (a &= 1); | |
| 640 | \\ a |= (a |= 1); | |
| 641 | \\ a ^= (a ^= 1); | |
| 642 | \\ a >>= (a >>= 1); | |
| 643 | \\ a <<= (a <<= 1); | |
| 644 | \\} | |
| 645 | , | |
| 646 | \\export fn foo() { | |
| 647 | \\ var a: c_int = 0; | |
| 648 | \\ a += { | |
| 649 | \\ const _ref = &a; | |
| 650 | \\ (*_ref) = ((*_ref) + 1); | |
| 651 | \\ *_ref | |
| 652 | \\ }; | |
| 653 | \\ a -= { | |
| 654 | \\ const _ref = &a; | |
| 655 | \\ (*_ref) = ((*_ref) - 1); | |
| 656 | \\ *_ref | |
| 657 | \\ }; | |
| 658 | \\ a *= { | |
| 659 | \\ const _ref = &a; | |
| 660 | \\ (*_ref) = ((*_ref) * 1); | |
| 661 | \\ *_ref | |
| 662 | \\ }; | |
| 663 | \\ a &= { | |
| 664 | \\ const _ref = &a; | |
| 665 | \\ (*_ref) = ((*_ref) & 1); | |
| 666 | \\ *_ref | |
| 667 | \\ }; | |
| 668 | \\ a |= { | |
| 669 | \\ const _ref = &a; | |
| 670 | \\ (*_ref) = ((*_ref) | 1); | |
| 671 | \\ *_ref | |
| 672 | \\ }; | |
| 673 | \\ a ^= { | |
| 674 | \\ const _ref = &a; | |
| 675 | \\ (*_ref) = ((*_ref) ^ 1); | |
| 676 | \\ *_ref | |
| 677 | \\ }; | |
| 678 | \\ a >>= @import("std").math.Log2Int(c_int)({ | |
| 679 | \\ const _ref = &a; | |
| 680 | \\ (*_ref) = c_int(c_int(*_ref) >> @import("std").math.Log2Int(c_int)(1)); | |
| 681 | \\ *_ref | |
| 682 | \\ }); | |
| 683 | \\ a <<= @import("std").math.Log2Int(c_int)({ | |
| 684 | \\ const _ref = &a; | |
| 685 | \\ (*_ref) = c_int(c_int(*_ref) << @import("std").math.Log2Int(c_int)(1)); | |
| 686 | \\ *_ref | |
| 687 | \\ }); | |
| 688 | \\} | |
| 689 | ); | |
| 690 | ||
| 691 | cases.addC("compound assignment operators unsigned", | |
| 692 | \\void foo(void) { | |
| 693 | \\ unsigned a = 0; | |
| 694 | \\ a += (a += 1); | |
| 695 | \\ a -= (a -= 1); | |
| 696 | \\ a *= (a *= 1); | |
| 697 | \\ a &= (a &= 1); | |
| 698 | \\ a |= (a |= 1); | |
| 699 | \\ a ^= (a ^= 1); | |
| 700 | \\ a >>= (a >>= 1); | |
| 701 | \\ a <<= (a <<= 1); | |
| 702 | \\} | |
| 703 | , | |
| 704 | \\export fn foo() { | |
| 705 | \\ var a: c_uint = c_uint(0); | |
| 706 | \\ a +%= { | |
| 707 | \\ const _ref = &a; | |
| 708 | \\ (*_ref) = ((*_ref) +% c_uint(1)); | |
| 709 | \\ *_ref | |
| 710 | \\ }; | |
| 711 | \\ a -%= { | |
| 712 | \\ const _ref = &a; | |
| 713 | \\ (*_ref) = ((*_ref) -% c_uint(1)); | |
| 714 | \\ *_ref | |
| 715 | \\ }; | |
| 716 | \\ a *%= { | |
| 717 | \\ const _ref = &a; | |
| 718 | \\ (*_ref) = ((*_ref) *% c_uint(1)); | |
| 719 | \\ *_ref | |
| 720 | \\ }; | |
| 721 | \\ a &= { | |
| 722 | \\ const _ref = &a; | |
| 723 | \\ (*_ref) = ((*_ref) & c_uint(1)); | |
| 724 | \\ *_ref | |
| 725 | \\ }; | |
| 726 | \\ a |= { | |
| 727 | \\ const _ref = &a; | |
| 728 | \\ (*_ref) = ((*_ref) | c_uint(1)); | |
| 729 | \\ *_ref | |
| 730 | \\ }; | |
| 731 | \\ a ^= { | |
| 732 | \\ const _ref = &a; | |
| 733 | \\ (*_ref) = ((*_ref) ^ c_uint(1)); | |
| 734 | \\ *_ref | |
| 735 | \\ }; | |
| 736 | \\ a >>= @import("std").math.Log2Int(c_uint)({ | |
| 737 | \\ const _ref = &a; | |
| 738 | \\ (*_ref) = c_uint(c_uint(*_ref) >> @import("std").math.Log2Int(c_uint)(1)); | |
| 739 | \\ *_ref | |
| 740 | \\ }); | |
| 741 | \\ a <<= @import("std").math.Log2Int(c_uint)({ | |
| 742 | \\ const _ref = &a; | |
| 743 | \\ (*_ref) = c_uint(c_uint(*_ref) << @import("std").math.Log2Int(c_uint)(1)); | |
| 744 | \\ *_ref | |
| 745 | \\ }); | |
| 746 | \\} | |
| 747 | ); | |
| 748 | ||
| 749 | cases.addC("duplicate typedef", | |
| 750 | \\typedef long foo; | |
| 751 | \\typedef int bar; | |
| 752 | \\typedef long foo; | |
| 753 | \\typedef int baz; | |
| 754 | , | |
| 755 | \\pub const foo = c_long; | |
| 756 | \\pub const bar = c_int; | |
| 757 | \\pub const baz = c_int; | |
| 758 | ); | |
| 759 | ||
| 760 | cases.addC("post increment/decrement", | |
| 761 | \\void foo(void) { | |
| 762 | \\ int i = 0; | |
| 763 | \\ unsigned u = 0; | |
| 764 | \\ i++; | |
| 765 | \\ i--; | |
| 766 | \\ u++; | |
| 767 | \\ u--; | |
| 768 | \\ i = i++; | |
| 769 | \\ i = i--; | |
| 770 | \\ u = u++; | |
| 771 | \\ u = u--; | |
| 772 | \\} | |
| 773 | , | |
| 774 | \\export fn foo() { | |
| 775 | \\ var i: c_int = 0; | |
| 776 | \\ var u: c_uint = c_uint(0); | |
| 777 | \\ i += 1; | |
| 778 | \\ i -= 1; | |
| 779 | \\ u +%= 1; | |
| 780 | \\ u -%= 1; | |
| 781 | \\ i = { | |
| 782 | \\ const _ref = &i; | |
| 783 | \\ const _tmp = *_ref; | |
| 784 | \\ (*_ref) += 1; | |
| 785 | \\ _tmp | |
| 786 | \\ }; | |
| 787 | \\ i = { | |
| 788 | \\ const _ref = &i; | |
| 789 | \\ const _tmp = *_ref; | |
| 790 | \\ (*_ref) -= 1; | |
| 791 | \\ _tmp | |
| 792 | \\ }; | |
| 793 | \\ u = { | |
| 794 | \\ const _ref = &u; | |
| 795 | \\ const _tmp = *_ref; | |
| 796 | \\ (*_ref) +%= 1; | |
| 797 | \\ _tmp | |
| 798 | \\ }; | |
| 799 | \\ u = { | |
| 800 | \\ const _ref = &u; | |
| 801 | \\ const _tmp = *_ref; | |
| 802 | \\ (*_ref) -%= 1; | |
| 803 | \\ _tmp | |
| 804 | \\ }; | |
| 805 | \\} | |
| 806 | ); | |
| 807 | ||
| 808 | cases.addC("do loop", | |
| 809 | \\void foo(void) { | |
| 810 | \\ int a = 2; | |
| 811 | \\ do { | |
| 812 | \\ a--; | |
| 813 | \\ } while (a != 0); | |
| 814 | \\ | |
| 815 | \\ int b = 2; | |
| 816 | \\ do | |
| 817 | \\ b--; | |
| 818 | \\ while (b != 0); | |
| 819 | \\} | |
| 820 | , | |
| 821 | \\export fn foo() { | |
| 822 | \\ var a: c_int = 2; | |
| 823 | \\ while (true) { | |
| 824 | \\ a -= 1; | |
| 825 | \\ if (!(a != 0)) break; | |
| 826 | \\ }; | |
| 827 | \\ var b: c_int = 2; | |
| 828 | \\ while (true) { | |
| 829 | \\ b -= 1; | |
| 830 | \\ if (!(b != 0)) break; | |
| 831 | \\ }; | |
| 832 | \\} | |
| 833 | ); | |
| 834 | ||
| 835 | cases.addC("deref function pointer", | |
| 836 | \\void foo(void) {} | |
| 837 | \\void bar(void) { | |
| 838 | \\ void(*f)(void) = foo; | |
| 839 | \\ f(); | |
| 840 | \\ (*(f))(); | |
| 841 | \\} | |
| 842 | , | |
| 843 | \\export fn foo() {} | |
| 844 | \\export fn bar() { | |
| 845 | \\ var f: ?extern fn() = foo; | |
| 846 | \\ (??f)(); | |
| 847 | \\ (??f)(); | |
| 848 | \\} | |
| 849 | ); | |
| 850 | ||
| 851 | cases.addC("normal deref", | |
| 852 | \\void foo(int *x) { | |
| 853 | \\ *x = 1; | |
| 854 | \\} | |
| 855 | , | |
| 856 | \\export fn foo(x: ?&c_int) { | |
| 857 | \\ (*(??x)) = 1; | |
| 858 | \\} | |
| 859 | ); | |
| 860 | ||
| 861 | cases.add("simple union", | |
| 862 | \\union Foo { | |
| 863 | \\ int x; | |
| 864 | \\ double y; | |
| 865 | \\}; | |
| 866 | , | |
| 867 | \\pub const union_Foo = extern union { | |
| 868 | \\ x: c_int, | |
| 869 | \\ y: f64, | |
| 870 | \\}; | |
| 871 | , | |
| 872 | \\pub const Foo = union_Foo; | |
| 873 | ); | |
| 874 | ||
| 875 | cases.add("address of operator", | |
| 876 | \\int foo(void) { | |
| 877 | \\ int x = 1234; | |
| 878 | \\ int *ptr = &x; | |
| 879 | \\ return *ptr; | |
| 880 | \\} | |
| 881 | , | |
| 882 | \\pub fn foo() -> c_int { | |
| 883 | \\ var x: c_int = 1234; | |
| 884 | \\ var ptr: ?&c_int = &x; | |
| 885 | \\ return *(??ptr); | |
| 886 | \\} | |
| 887 | ); | |
| 888 | } | |
| 889 | ||
| 890 | ||
| 891 | ||
| 892 | // TODO | |
| 893 | //float *ptrcast(int *a) { | |
| 894 | // return (float *)a; | |
| 895 | //} | |
| 896 | // should translate to | |
| 897 | // fn ptrcast(a: ?&c_int) -> ?&f32 { | |
| 898 | // return @ptrCast(?&f32, a); | |
| 899 | // } |