static const char *container_string(ContainerKind kind) { switch (kind) { case ContainerKindEnum: return "enum"; case ContainerKindStruct: return "struct"; } zig_unreachable(); }
static const char *visib_mod_string(VisibMod mod) { switch (mod) { case VisibModPub: return "pub "; case VisibModPrivate: return ""; case VisibModExport: return "export "; } zig_unreachable(); }
static const char *return_prefix_str(ReturnKind kind) { switch (kind) { case ReturnKindError: return "%"; case ReturnKindMaybe: return "?"; case ReturnKindUnconditional: return ""; } zig_unreachable(); }
static int get_arch_pointer_bit_width(ZigLLVM_ArchType arch) { switch (arch) { case ZigLLVM_UnknownArch: return 0; case ZigLLVM_msp430: return 16; case ZigLLVM_arm: case ZigLLVM_armeb: case ZigLLVM_hexagon: case ZigLLVM_le32: case ZigLLVM_mips: case ZigLLVM_mipsel: case ZigLLVM_nvptx: case ZigLLVM_ppc: case ZigLLVM_r600: case ZigLLVM_sparc: case ZigLLVM_sparcel: case ZigLLVM_tce: case ZigLLVM_thumb: case ZigLLVM_thumbeb: case ZigLLVM_x86: case ZigLLVM_xcore: case ZigLLVM_amdil: case ZigLLVM_hsail: case ZigLLVM_spir: case ZigLLVM_kalimba: case ZigLLVM_shave: case ZigLLVM_wasm32: return 32; case ZigLLVM_aarch64: case ZigLLVM_aarch64_be: case ZigLLVM_amdgcn: case ZigLLVM_bpfel: case ZigLLVM_bpfeb: case ZigLLVM_le64: case ZigLLVM_mips64: case ZigLLVM_mips64el: case ZigLLVM_nvptx64: case ZigLLVM_ppc64: case ZigLLVM_ppc64le: case ZigLLVM_sparcv9: case ZigLLVM_systemz: case ZigLLVM_x86_64: case ZigLLVM_amdil64: case ZigLLVM_hsail64: case ZigLLVM_spir64: case ZigLLVM_wasm64: return 64; } zig_unreachable(); }
static void print_err_msg_type(ErrorMsg *err, ErrColor color, ErrType err_type) { const char *path = buf_ptr(err->path); size_t line = err->line_start + 1; size_t col = err->column_start + 1; const char *text = buf_ptr(err->msg); if (color == ErrColorOn || (color == ErrColorAuto && os_stderr_tty())) { if (err_type == ErrTypeError) { fprintf(stderr, WHITE "%s:%zu:%zu: " RED "error:" WHITE " %s" RESET "\n", path, line, col, text); } else if (err_type == ErrTypeNote) { fprintf(stderr, WHITE "%s:%zu:%zu: " CYAN "note:" WHITE " %s" RESET "\n", path, line, col, text); } else { zig_unreachable(); } fprintf(stderr, "%s\n", buf_ptr(&err->line_buf)); for (size_t i = 0; i < err->column_start; i += 1) { fprintf(stderr, " "); } fprintf(stderr, GREEN "^" RESET "\n"); } else { if (err_type == ErrTypeError) { fprintf(stderr, "%s:%zu:%zu: error: %s\n", path, line, col, text); } else if (err_type == ErrTypeNote) { fprintf(stderr, " %s:%zu:%zu: note: %s\n", path, line, col, text); } else { zig_unreachable(); } } for (size_t i = 0; i < err->notes.length; i += 1) { ErrorMsg *note = err->notes.at(i); print_err_msg_type(note, color, ErrTypeNote); } }
static const char *prefix_op_str(PrefixOp prefix_op) { switch (prefix_op) { case PrefixOpInvalid: return "(invalid)"; case PrefixOpNegation: return "-"; case PrefixOpBoolNot: return "!"; case PrefixOpBinNot: return "~"; case PrefixOpAddressOf: return "&"; case PrefixOpConstAddressOf: return "&const "; case PrefixOpDereference: return "*"; case PrefixOpMaybe: return "?"; case PrefixOpError: return "%"; case PrefixOpUnwrapError: return "%%"; case PrefixOpUnwrapMaybe: return "??"; } zig_unreachable(); }
int os_fetch_file(FILE *f, Buf *out_buf) { static const ssize_t buf_size = 0x2000; buf_resize(out_buf, buf_size); ssize_t actual_buf_len = 0; for (;;) { size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f); actual_buf_len += amt_read; if (amt_read != buf_size) { if (feof(f)) { buf_resize(out_buf, actual_buf_len); return 0; } else { return ErrorFileSystem; } } buf_resize(out_buf, actual_buf_len + buf_size); } zig_unreachable(); }
static const char *bin_op_str(BinOpType bin_op) { switch (bin_op) { case BinOpTypeInvalid: return "(invalid)"; case BinOpTypeBoolOr: return "||"; case BinOpTypeBoolAnd: return "&&"; case BinOpTypeCmpEq: return "=="; case BinOpTypeCmpNotEq: return "!="; case BinOpTypeCmpLessThan: return "<"; case BinOpTypeCmpGreaterThan: return ">"; case BinOpTypeCmpLessOrEq: return "<="; case BinOpTypeCmpGreaterOrEq: return ">="; case BinOpTypeBinOr: return "|"; case BinOpTypeBinXor: return "^"; case BinOpTypeBinAnd: return "&"; case BinOpTypeBitShiftLeft: return "<<"; case BinOpTypeBitShiftRight: return ">>"; case BinOpTypeAdd: return "+"; case BinOpTypeSub: return "-"; case BinOpTypeMult: return "*"; case BinOpTypeDiv: return "/"; case BinOpTypeMod: return "%"; case BinOpTypeAssign: return "="; case BinOpTypeAssignTimes: return "*="; case BinOpTypeAssignDiv: return "/="; case BinOpTypeAssignMod: return "%="; case BinOpTypeAssignPlus: return "+="; case BinOpTypeAssignMinus: return "-="; case BinOpTypeAssignBitShiftLeft: return "<<="; case BinOpTypeAssignBitShiftRight: return ">>="; case BinOpTypeAssignBitAnd: return "&="; case BinOpTypeAssignBitXor: return "^="; case BinOpTypeAssignBitOr: return "|="; case BinOpTypeAssignBoolAnd: return "&&="; case BinOpTypeAssignBoolOr: return "||="; case BinOpTypeUnwrapMaybe: return "??"; case BinOpTypeStrCat: return "++"; } zig_unreachable(); }
int os_fetch_file_path(Buf *full_path, Buf *out_contents) { FILE *f = fopen(buf_ptr(full_path), "rb"); if (!f) { switch (errno) { case EACCES: return ErrorAccess; case EINTR: return ErrorInterrupted; case EINVAL: zig_unreachable(); case ENFILE: case ENOMEM: return ErrorSystemResources; case ENOENT: return ErrorFileNotFound; default: return ErrorFileSystem; } } int result = os_fetch_file(f, out_contents); fclose(f); return result; }
int main(int argc, char **argv) { os_init(); char *arg0 = argv[0]; Cmd cmd = CmdInvalid; const char *in_file = nullptr; const char *out_file = nullptr; bool is_release_build = false; bool strip = false; bool is_static = false; OutType out_type = OutTypeUnknown; const char *out_name = nullptr; bool verbose = false; ErrColor color = ErrColorAuto; const char *libc_lib_dir = nullptr; const char *libc_static_lib_dir = nullptr; const char *libc_include_dir = nullptr; const char *zig_std_dir = nullptr; const char *dynamic_linker = nullptr; const char *linker_path = nullptr; const char *ar_path = nullptr; ZigList<const char *> clang_argv = {0}; ZigList<const char *> lib_dirs = {0}; ZigList<const char *> link_libs = {0}; int err; const char *target_arch = nullptr; const char *target_os = nullptr; const char *target_environ = nullptr; bool mwindows = false; bool mconsole = false; bool municode = false; const char *mlinker_version = nullptr; bool rdynamic = false; const char *mmacosx_version_min = nullptr; const char *mios_version_min = nullptr; bool check_unused = false; for (int i = 1; i < argc; i += 1) { char *arg = argv[i]; if (arg[0] == '-') { if (strcmp(arg, "--release") == 0) { is_release_build = true; } else if (strcmp(arg, "--strip") == 0) { strip = true; } else if (strcmp(arg, "--static") == 0) { is_static = true; } else if (strcmp(arg, "--verbose") == 0) { verbose = true; } else if (strcmp(arg, "-mwindows") == 0) { mwindows = true; } else if (strcmp(arg, "-mconsole") == 0) { mconsole = true; } else if (strcmp(arg, "-municode") == 0) { municode = true; } else if (strcmp(arg, "-rdynamic") == 0) { rdynamic = true; } else if (strcmp(arg, "--check-unused") == 0) { check_unused = true; } else if (i + 1 >= argc) { return usage(arg0); } else { i += 1; if (i >= argc) { return usage(arg0); } else if (strcmp(arg, "--output") == 0) { out_file = argv[i]; } else if (strcmp(arg, "--export") == 0) { if (strcmp(argv[i], "exe") == 0) { out_type = OutTypeExe; } else if (strcmp(argv[i], "lib") == 0) { out_type = OutTypeLib; } else if (strcmp(argv[i], "obj") == 0) { out_type = OutTypeObj; } else { return usage(arg0); } } else if (strcmp(arg, "--color") == 0) { if (strcmp(argv[i], "auto") == 0) { color = ErrColorAuto; } else if (strcmp(argv[i], "on") == 0) { color = ErrColorOn; } else if (strcmp(argv[i], "off") == 0) { color = ErrColorOff; } else { return usage(arg0); } } else if (strcmp(arg, "--name") == 0) { out_name = argv[i]; } else if (strcmp(arg, "--libc-lib-dir") == 0) { libc_lib_dir = argv[i]; } else if (strcmp(arg, "--libc-static-lib-dir") == 0) { libc_static_lib_dir = argv[i]; } else if (strcmp(arg, "--libc-include-dir") == 0) { libc_include_dir = argv[i]; } else if (strcmp(arg, "--zig-std-dir") == 0) { zig_std_dir = argv[i]; } else if (strcmp(arg, "--dynamic-linker") == 0) { dynamic_linker = argv[i]; } else if (strcmp(arg, "--ld-path") == 0) { linker_path = argv[i]; } else if (strcmp(arg, "--ar-path") == 0) { ar_path = argv[i]; } else if (strcmp(arg, "-isystem") == 0) { clang_argv.append("-isystem"); clang_argv.append(argv[i]); } else if (strcmp(arg, "-dirafter") == 0) { clang_argv.append("-dirafter"); clang_argv.append(argv[i]); } else if (strcmp(arg, "--library-path") == 0) { lib_dirs.append(argv[i]); } else if (strcmp(arg, "--library") == 0) { link_libs.append(argv[i]); } else if (strcmp(arg, "--target-arch") == 0) { target_arch = argv[i]; } else if (strcmp(arg, "--target-os") == 0) { target_os = argv[i]; } else if (strcmp(arg, "--target-environ") == 0) { target_environ = argv[i]; } else if (strcmp(arg, "-mlinker-version") == 0) { mlinker_version = argv[i]; } else if (strcmp(arg, "-mmacosx-version-min") == 0) { mmacosx_version_min = argv[i]; } else if (strcmp(arg, "-mios-version-min") == 0) { mios_version_min = argv[i]; } else { fprintf(stderr, "Invalid argument: %s\n", arg); return usage(arg0); } } } else if (cmd == CmdInvalid) { if (strcmp(arg, "build") == 0) { cmd = CmdBuild; } else if (strcmp(arg, "version") == 0) { cmd = CmdVersion; } else if (strcmp(arg, "parseh") == 0) { cmd = CmdParseH; } else if (strcmp(arg, "test") == 0) { cmd = CmdTest; } else if (strcmp(arg, "targets") == 0) { cmd = CmdTargets; } else { fprintf(stderr, "Unrecognized command: %s\n", arg); return usage(arg0); } } else { switch (cmd) { case CmdBuild: case CmdParseH: case CmdTest: if (!in_file) { in_file = arg; } else { return usage(arg0); } break; case CmdVersion: case CmdTargets: return usage(arg0); case CmdInvalid: zig_unreachable(); } } } switch (cmd) { case CmdBuild: case CmdParseH: case CmdTest: { if (!in_file) return usage(arg0); if (cmd == CmdBuild && !out_name) { fprintf(stderr, "--name [name] not provided\n\n"); return usage(arg0); } if (cmd == CmdBuild && out_type == OutTypeUnknown) { fprintf(stderr, "--export [exe|lib|obj] not provided\n\n"); return usage(arg0); } init_all_targets(); ZigTarget alloc_target; ZigTarget *target; if (!target_arch && !target_os && !target_environ) { target = nullptr; } else { target = &alloc_target; get_unknown_target(target); if (target_arch) { if (parse_target_arch(target_arch, &target->arch)) { fprintf(stderr, "invalid --target-arch argument\n"); return usage(arg0); } } if (target_os) { if (parse_target_os(target_os, &target->os)) { fprintf(stderr, "invalid --target-os argument\n"); return usage(arg0); } } if (target_environ) { if (parse_target_environ(target_environ, &target->env_type)) { fprintf(stderr, "invalid --target-environ argument\n"); return usage(arg0); } } } Buf in_file_buf = BUF_INIT; buf_init_from_str(&in_file_buf, in_file); Buf root_source_dir = BUF_INIT; Buf root_source_code = BUF_INIT; Buf root_source_name = BUF_INIT; if (buf_eql_str(&in_file_buf, "-")) { os_get_cwd(&root_source_dir); if ((err = os_fetch_file(stdin, &root_source_code))) { fprintf(stderr, "unable to read stdin: %s\n", err_str(err)); return 1; } buf_init_from_str(&root_source_name, ""); } else { os_path_split(&in_file_buf, &root_source_dir, &root_source_name); if ((err = os_fetch_file_path(buf_create_from_str(in_file), &root_source_code))) { fprintf(stderr, "unable to open '%s': %s\n", in_file, err_str(err)); return 1; } } CodeGen *g = codegen_create(&root_source_dir, target); codegen_set_is_release(g, is_release_build); codegen_set_is_test(g, cmd == CmdTest); codegen_set_check_unused(g, check_unused); codegen_set_clang_argv(g, clang_argv.items, clang_argv.length); codegen_set_strip(g, strip); codegen_set_is_static(g, is_static); if (out_type != OutTypeUnknown) { codegen_set_out_type(g, out_type); } else if (cmd == CmdTest) { codegen_set_out_type(g, OutTypeExe); } if (out_name) { codegen_set_out_name(g, buf_create_from_str(out_name)); } else if (cmd == CmdTest) { codegen_set_out_name(g, buf_create_from_str("test")); } if (libc_lib_dir) codegen_set_libc_lib_dir(g, buf_create_from_str(libc_lib_dir)); if (libc_static_lib_dir) codegen_set_libc_static_lib_dir(g, buf_create_from_str(libc_static_lib_dir)); if (libc_include_dir) codegen_set_libc_include_dir(g, buf_create_from_str(libc_include_dir)); if (zig_std_dir) codegen_set_zig_std_dir(g, buf_create_from_str(zig_std_dir)); if (dynamic_linker) codegen_set_dynamic_linker(g, buf_create_from_str(dynamic_linker)); if (linker_path) codegen_set_linker_path(g, buf_create_from_str(linker_path)); if (ar_path) codegen_set_ar_path(g, buf_create_from_str(ar_path)); codegen_set_verbose(g, verbose); codegen_set_errmsg_color(g, color); for (int i = 0; i < lib_dirs.length; i += 1) { codegen_add_lib_dir(g, lib_dirs.at(i)); } for (int i = 0; i < link_libs.length; i += 1) { codegen_add_link_lib(g, link_libs.at(i)); } codegen_set_windows_subsystem(g, mwindows, mconsole); codegen_set_windows_unicode(g, municode); codegen_set_rdynamic(g, rdynamic); if (mlinker_version) { codegen_set_mlinker_version(g, buf_create_from_str(mlinker_version)); } if (mmacosx_version_min && mios_version_min) { fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n"); return EXIT_FAILURE; } if (mmacosx_version_min) { codegen_set_mmacosx_version_min(g, buf_create_from_str(mmacosx_version_min)); } if (mios_version_min) { codegen_set_mios_version_min(g, buf_create_from_str(mios_version_min)); } if (cmd == CmdBuild) { codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code); codegen_link(g, out_file); return EXIT_SUCCESS; } else if (cmd == CmdParseH) { codegen_parseh(g, &root_source_dir, &root_source_name, &root_source_code); codegen_render_ast(g, stdout, 4); return EXIT_SUCCESS; } else if (cmd == CmdTest) { codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code); codegen_link(g, "./test"); ZigList<const char *> args = {0}; Termination term; os_spawn_process("./test", args, &term); if (term.how != TerminationIdClean || term.code != 0) { fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n"); fprintf(stderr, "./test\n"); } return (term.how == TerminationIdClean) ? term.code : -1; } else { zig_unreachable(); } } case CmdVersion: printf("%s\n", ZIG_VERSION_STRING); return EXIT_SUCCESS; case CmdTargets: return print_target_list(stdout); case CmdInvalid: return usage(arg0); } }
int get_c_type_size_in_bits(const ZigTarget *target, CIntType id) { switch (target->os) { case ZigLLVM_UnknownOS: zig_unreachable(); case ZigLLVM_Linux: case ZigLLVM_Darwin: switch (id) { case CIntTypeShort: case CIntTypeUShort: return 16; case CIntTypeInt: case CIntTypeUInt: return 32; case CIntTypeLong: case CIntTypeULong: return get_arch_pointer_bit_width(target->arch.arch); case CIntTypeLongLong: case CIntTypeULongLong: return 64; case CIntTypeCount: zig_unreachable(); } case ZigLLVM_Win32: switch (id) { case CIntTypeShort: case CIntTypeUShort: return 16; case CIntTypeInt: case CIntTypeUInt: case CIntTypeLong: case CIntTypeULong: return 32; case CIntTypeLongLong: case CIntTypeULongLong: return 64; case CIntTypeCount: zig_unreachable(); } case ZigLLVM_CloudABI: case ZigLLVM_DragonFly: case ZigLLVM_FreeBSD: case ZigLLVM_IOS: case ZigLLVM_KFreeBSD: case ZigLLVM_Lv2: case ZigLLVM_MacOSX: case ZigLLVM_NetBSD: case ZigLLVM_OpenBSD: case ZigLLVM_Solaris: case ZigLLVM_Haiku: case ZigLLVM_Minix: case ZigLLVM_RTEMS: case ZigLLVM_NaCl: case ZigLLVM_CNK: case ZigLLVM_Bitrig: case ZigLLVM_AIX: case ZigLLVM_CUDA: case ZigLLVM_NVCL: case ZigLLVM_AMDHSA: case ZigLLVM_PS4: zig_panic("TODO c type size in bits for this target"); } zig_unreachable(); }
static const char *node_type_str(NodeType node_type) { switch (node_type) { case NodeTypeRoot: return "Root"; case NodeTypeRootExportDecl: return "RootExportDecl"; case NodeTypeFnDef: return "FnDef"; case NodeTypeFnDecl: return "FnDecl"; case NodeTypeFnProto: return "FnProto"; case NodeTypeParamDecl: return "ParamDecl"; case NodeTypeBlock: return "Block"; case NodeTypeBinOpExpr: return "BinOpExpr"; case NodeTypeUnwrapErrorExpr: return "UnwrapErrorExpr"; case NodeTypeFnCallExpr: return "FnCallExpr"; case NodeTypeArrayAccessExpr: return "ArrayAccessExpr"; case NodeTypeSliceExpr: return "SliceExpr"; case NodeTypeDirective: return "Directive"; case NodeTypeReturnExpr: return "ReturnExpr"; case NodeTypeDefer: return "Defer"; case NodeTypeVariableDeclaration: return "VariableDeclaration"; case NodeTypeTypeDecl: return "TypeDecl"; case NodeTypeErrorValueDecl: return "ErrorValueDecl"; case NodeTypeNumberLiteral: return "NumberLiteral"; case NodeTypeStringLiteral: return "StringLiteral"; case NodeTypeCharLiteral: return "CharLiteral"; case NodeTypeSymbol: return "Symbol"; case NodeTypePrefixOpExpr: return "PrefixOpExpr"; case NodeTypeImport: return "Import"; case NodeTypeCImport: return "CImport"; case NodeTypeBoolLiteral: return "BoolLiteral"; case NodeTypeNullLiteral: return "NullLiteral"; case NodeTypeUndefinedLiteral: return "UndefinedLiteral"; case NodeTypeIfBoolExpr: return "IfBoolExpr"; case NodeTypeIfVarExpr: return "IfVarExpr"; case NodeTypeWhileExpr: return "WhileExpr"; case NodeTypeForExpr: return "ForExpr"; case NodeTypeSwitchExpr: return "SwitchExpr"; case NodeTypeSwitchProng: return "SwitchProng"; case NodeTypeSwitchRange: return "SwitchRange"; case NodeTypeLabel: return "Label"; case NodeTypeGoto: return "Goto"; case NodeTypeBreak: return "Break"; case NodeTypeContinue: return "Continue"; case NodeTypeAsmExpr: return "AsmExpr"; case NodeTypeFieldAccessExpr: return "FieldAccessExpr"; case NodeTypeStructDecl: return "StructDecl"; case NodeTypeStructField: return "StructField"; case NodeTypeStructValueField: return "StructValueField"; case NodeTypeContainerInitExpr: return "ContainerInitExpr"; case NodeTypeArrayType: return "ArrayType"; case NodeTypeErrorType: return "ErrorType"; case NodeTypeTypeLiteral: return "TypeLiteral"; } zig_unreachable(); }