| author | |
| committer | |
| log | 37b9a2e6a4aa59494406d38495768778502fbcda |
| tree | 677755d9a870b29311cc834dea7f09ad44c55549 |
| parent | 237dfdbdc6f83071cff88489cc66cb83a2d65b00 |
12 files changed, 1023 insertions(+), 481 deletions(-)
build.zig created+36| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | const Builder = @import("std").build.Builder; | |
| 2 | const tests = @import("test/tests.zig"); | |
| 3 | ||
| 4 | pub fn build(b: &Builder) { | |
| 5 | const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter"); | |
| 6 | const test_step = b.step("test", "Run all the tests"); | |
| 7 | ||
| 8 | const run_tests_exe = b.addExecutable("run_tests", "test/run_tests.zig"); | |
| 9 | ||
| 10 | const run_tests_cmd = b.addCommand(b.out_dir, b.env_map, "./run_tests", [][]const u8{}); | |
| 11 | run_tests_cmd.step.dependOn(&run_tests_exe.step); | |
| 12 | ||
| 13 | const self_hosted_tests_debug_nolibc = b.addTest("test/self_hosted.zig"); | |
| 14 | ||
| 15 | const self_hosted_tests_release_nolibc = b.addTest("test/self_hosted.zig"); | |
| 16 | self_hosted_tests_release_nolibc.setRelease(true); | |
| 17 | ||
| 18 | const self_hosted_tests_debug_libc = b.addTest("test/self_hosted.zig"); | |
| 19 | self_hosted_tests_debug_libc.linkLibrary("c"); | |
| 20 | ||
| 21 | const self_hosted_tests_release_libc = b.addTest("test/self_hosted.zig"); | |
| 22 | self_hosted_tests_release_libc.setRelease(true); | |
| 23 | self_hosted_tests_release_libc.linkLibrary("c"); | |
| 24 | ||
| 25 | const self_hosted_tests = b.step("test-self-hosted", "Run the self-hosted tests"); | |
| 26 | self_hosted_tests.dependOn(&self_hosted_tests_debug_nolibc.step); | |
| 27 | self_hosted_tests.dependOn(&self_hosted_tests_release_nolibc.step); | |
| 28 | self_hosted_tests.dependOn(&self_hosted_tests_debug_libc.step); | |
| 29 | self_hosted_tests.dependOn(&self_hosted_tests_release_libc.step); | |
| 30 | ||
| 31 | test_step.dependOn(self_hosted_tests); | |
| 32 | //test_step.dependOn(&run_tests_cmd.step); | |
| 33 | ||
| 34 | test_step.dependOn(tests.addCompareOutputTests(b, test_filter)); | |
| 35 | //test_step.dependOn(tests.addBuildExampleTests(b, test_filter)); | |
| 36 | } |
src/main.cpp+3| ... | ... | @@ -168,6 +168,7 @@ int main(int argc, char **argv) { |
| 168 | 168 | |
| 169 | 169 | ZigList<const char *> args = {0}; |
| 170 | 170 | args.append(zig_exe_path); |
| 171 | args.append(NULL); // placeholder | |
| 171 | 172 | for (int i = 2; i < argc; i += 1) { |
| 172 | 173 | if (strcmp(argv[i], "--debug-build-verbose") == 0) { |
| 173 | 174 | verbose = true; |
| ... | ... | @@ -202,6 +203,8 @@ int main(int argc, char **argv) { |
| 202 | 203 | Buf build_file_dirname = BUF_INIT; |
| 203 | 204 | os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename); |
| 204 | 205 | |
| 206 | args.items[1] = buf_ptr(&build_file_dirname); | |
| 207 | ||
| 205 | 208 | bool build_file_exists; |
| 206 | 209 | if ((err = os_file_exists(&build_file_abs, &build_file_exists))) { |
| 207 | 210 | fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&build_file_abs), err_str(err)); |
std/build.zig+215-38| ... | ... | @@ -38,6 +38,7 @@ pub const Builder = struct { |
| 38 | 38 | lib_dir: []const u8, |
| 39 | 39 | out_dir: []u8, |
| 40 | 40 | installed_files: List([]const u8), |
| 41 | build_root: []const u8, | |
| 41 | 42 | |
| 42 | 43 | const UserInputOptionsMap = HashMap([]const u8, UserInputOption, mem.hash_slice_u8, mem.eql_slice_u8); |
| 43 | 44 | const AvailableOptionsMap = HashMap([]const u8, AvailableOption, mem.hash_slice_u8, mem.eql_slice_u8); |
| ... | ... | @@ -73,8 +74,10 @@ pub const Builder = struct { |
| 73 | 74 | description: []const u8, |
| 74 | 75 | }; |
| 75 | 76 | |
| 76 | pub fn init(allocator: &Allocator) -> Builder { | |
| 77 | pub fn init(allocator: &Allocator, zig_exe: []const u8, build_root: []const u8) -> Builder { | |
| 77 | 78 | var self = Builder { |
| 79 | .zig_exe = zig_exe, | |
| 80 | .build_root = build_root, | |
| 78 | 81 | .verbose = false, |
| 79 | 82 | .invalid_user_input = false, |
| 80 | 83 | .allocator = allocator, |
| ... | ... | @@ -85,7 +88,6 @@ pub const Builder = struct { |
| 85 | 88 | .available_options_map = AvailableOptionsMap.init(allocator), |
| 86 | 89 | .available_options_list = List(AvailableOption).init(allocator), |
| 87 | 90 | .top_level_steps = List(&TopLevelStep).init(allocator), |
| 88 | .zig_exe = undefined, | |
| 89 | 91 | .default_step = undefined, |
| 90 | 92 | .env_map = %%os.getEnvMap(allocator), |
| 91 | 93 | .prefix = undefined, |
| ... | ... | @@ -123,6 +125,12 @@ pub const Builder = struct { |
| 123 | 125 | return exe; |
| 124 | 126 | } |
| 125 | 127 | |
| 128 | pub fn addTest(self: &Builder, root_src: []const u8) -> &TestStep { | |
| 129 | const test_step = %%self.allocator.create(TestStep); | |
| 130 | *test_step = TestStep.init(self, root_src); | |
| 131 | return test_step; | |
| 132 | } | |
| 133 | ||
| 126 | 134 | pub fn addCStaticLibrary(self: &Builder, name: []const u8) -> &CLibrary { |
| 127 | 135 | const lib = %%self.allocator.create(CLibrary); |
| 128 | 136 | *lib = CLibrary.initStatic(self, name); |
| ... | ... | @@ -149,6 +157,19 @@ pub const Builder = struct { |
| 149 | 157 | return cmd; |
| 150 | 158 | } |
| 151 | 159 | |
| 160 | pub fn addWriteFile(self: &Builder, file_path: []const u8, data: []const u8) -> &WriteFileStep { | |
| 161 | const write_file_step = %%self.allocator.create(WriteFileStep); | |
| 162 | *write_file_step = WriteFileStep.init(self, file_path, data); | |
| 163 | return write_file_step; | |
| 164 | } | |
| 165 | ||
| 166 | pub fn addLog(self: &Builder, comptime format: []const u8, args: ...) -> &LogStep { | |
| 167 | const data = %%fmt.allocPrint(self.allocator, format, args); | |
| 168 | const log_step = %%self.allocator.create(LogStep); | |
| 169 | *log_step = LogStep.init(self, data); | |
| 170 | return log_step; | |
| 171 | } | |
| 172 | ||
| 152 | 173 | pub fn version(self: &const Builder, major: u32, minor: u32, patch: u32) -> Version { |
| 153 | 174 | Version { |
| 154 | 175 | .major = major, |
| ... | ... | @@ -197,9 +218,8 @@ pub const Builder = struct { |
| 197 | 218 | } |
| 198 | 219 | |
| 199 | 220 | fn makeUninstall(uninstall_step: &Step) -> %void { |
| 200 | // TODO | |
| 201 | // const self = @fieldParentPtr(Exe, "step", step); | |
| 202 | const self = @ptrcast(&Builder, uninstall_step); | |
| 221 | const uninstall_tls = @fieldParentPtr(TopLevelStep, "step", uninstall_step); | |
| 222 | const self = @fieldParentPtr(Builder, "uninstall_tls", uninstall_tls); | |
| 203 | 223 | |
| 204 | 224 | for (self.installed_files.toSliceConst()) |installed_file| { |
| 205 | 225 | _ = os.deleteFile(self.allocator, installed_file); |
| ... | ... | @@ -278,7 +298,7 @@ pub const Builder = struct { |
| 278 | 298 | } |
| 279 | 299 | |
| 280 | 300 | pub fn option(self: &Builder, comptime T: type, name: []const u8, description: []const u8) -> ?T { |
| 281 | const type_id = typeToEnum(T); | |
| 301 | const type_id = comptime typeToEnum(T); | |
| 282 | 302 | const available_option = AvailableOption { |
| 283 | 303 | .name = name, |
| 284 | 304 | .type_id = type_id, |
| ... | ... | @@ -313,7 +333,19 @@ pub const Builder = struct { |
| 313 | 333 | }, |
| 314 | 334 | TypeId.Int => debug.panic("TODO integer options to build script"), |
| 315 | 335 | TypeId.Float => debug.panic("TODO float options to build script"), |
| 316 | TypeId.String => debug.panic("TODO string options to build script"), | |
| 336 | TypeId.String => switch (entry.value.value) { | |
| 337 | UserValue.Flag => { | |
| 338 | %%io.stderr.printf("Expected -D{} to be a string, but received a boolean.\n", name); | |
| 339 | self.markInvalidUserInput(); | |
| 340 | return null; | |
| 341 | }, | |
| 342 | UserValue.List => { | |
| 343 | %%io.stderr.printf("Expected -D{} to be a string, but received a list.\n", name); | |
| 344 | self.markInvalidUserInput(); | |
| 345 | return null; | |
| 346 | }, | |
| 347 | UserValue.Scalar => |s| return s, | |
| 348 | }, | |
| 317 | 349 | TypeId.List => debug.panic("TODO list options to build script"), |
| 318 | 350 | } |
| 319 | 351 | } |
| ... | ... | @@ -482,6 +514,10 @@ pub const Builder = struct { |
| 482 | 514 | debug.panic("Unable to copy {} to {}: {}", source_path, dest_path, @errorName(err)); |
| 483 | 515 | }; |
| 484 | 516 | } |
| 517 | ||
| 518 | fn pathFromRoot(self: &Builder, rel_path: []const u8) -> []u8 { | |
| 519 | return %%os.path.join(self.allocator, self.build_root, rel_path); | |
| 520 | } | |
| 485 | 521 | }; |
| 486 | 522 | |
| 487 | 523 | const Version = struct { |
| ... | ... | @@ -518,7 +554,7 @@ const LinkerScript = enum { |
| 518 | 554 | Path: []const u8, |
| 519 | 555 | }; |
| 520 | 556 | |
| 521 | const Exe = struct { | |
| 557 | pub const Exe = struct { | |
| 522 | 558 | step: Step, |
| 523 | 559 | builder: &Builder, |
| 524 | 560 | root_src: []const u8, |
| ... | ... | @@ -528,6 +564,7 @@ const Exe = struct { |
| 528 | 564 | link_libs: BufSet, |
| 529 | 565 | verbose: bool, |
| 530 | 566 | release: bool, |
| 567 | output_path: ?[]const u8, | |
| 531 | 568 | |
| 532 | 569 | pub fn init(builder: &Builder, name: []const u8, root_src: []const u8) -> Exe { |
| 533 | 570 | Exe { |
| ... | ... | @@ -540,6 +577,7 @@ const Exe = struct { |
| 540 | 577 | .linker_script = LinkerScript.None, |
| 541 | 578 | .link_libs = BufSet.init(builder.allocator), |
| 542 | 579 | .step = Step.init(name, builder.allocator, make), |
| 580 | .output_path = null, | |
| 543 | 581 | } |
| 544 | 582 | } |
| 545 | 583 | |
| ... | ... | @@ -579,6 +617,10 @@ const Exe = struct { |
| 579 | 617 | self.release = value; |
| 580 | 618 | } |
| 581 | 619 | |
| 620 | pub fn setOutputPath(self: &Exe, value: []const u8) { | |
| 621 | self.output_path = value; | |
| 622 | } | |
| 623 | ||
| 582 | 624 | fn make(step: &Step) -> %void { |
| 583 | 625 | const exe = @fieldParentPtr(Exe, "step", step); |
| 584 | 626 | const builder = exe.builder; |
| ... | ... | @@ -586,31 +628,36 @@ const Exe = struct { |
| 586 | 628 | var zig_args = List([]const u8).init(builder.allocator); |
| 587 | 629 | defer zig_args.deinit(); |
| 588 | 630 | |
| 589 | %return zig_args.append("build_exe"); | |
| 590 | %return zig_args.append(exe.root_src); | |
| 631 | %%zig_args.append("build_exe"); | |
| 632 | %%zig_args.append(builder.pathFromRoot(exe.root_src)); | |
| 591 | 633 | |
| 592 | 634 | if (exe.verbose) { |
| 593 | %return zig_args.append("--verbose"); | |
| 635 | %%zig_args.append("--verbose"); | |
| 594 | 636 | } |
| 595 | 637 | |
| 596 | 638 | if (exe.release) { |
| 597 | %return zig_args.append("--release"); | |
| 639 | %%zig_args.append("--release"); | |
| 598 | 640 | } |
| 599 | 641 | |
| 600 | %return zig_args.append("--name"); | |
| 601 | %return zig_args.append(exe.name); | |
| 642 | if (const output_path ?= exe.output_path) { | |
| 643 | %%zig_args.append("--output"); | |
| 644 | %%zig_args.append(builder.pathFromRoot(output_path)); | |
| 645 | } | |
| 646 | ||
| 647 | %%zig_args.append("--name"); | |
| 648 | %%zig_args.append(exe.name); | |
| 602 | 649 | |
| 603 | 650 | switch (exe.target) { |
| 604 | 651 | Target.Native => {}, |
| 605 | 652 | Target.Cross => |cross_target| { |
| 606 | %return zig_args.append("--target-arch"); | |
| 607 | %return zig_args.append(@enumTagName(cross_target.arch)); | |
| 653 | %%zig_args.append("--target-arch"); | |
| 654 | %%zig_args.append(@enumTagName(cross_target.arch)); | |
| 608 | 655 | |
| 609 | %return zig_args.append("--target-os"); | |
| 610 | %return zig_args.append(@enumTagName(cross_target.os)); | |
| 656 | %%zig_args.append("--target-os"); | |
| 657 | %%zig_args.append(@enumTagName(cross_target.os)); | |
| 611 | 658 | |
| 612 | %return zig_args.append("--target-environ"); | |
| 613 | %return zig_args.append(@enumTagName(cross_target.environ)); | |
| 659 | %%zig_args.append("--target-environ"); | |
| 660 | %%zig_args.append(@enumTagName(cross_target.environ)); | |
| 614 | 661 | }, |
| 615 | 662 | } |
| 616 | 663 | |
| ... | ... | @@ -620,12 +667,12 @@ const Exe = struct { |
| 620 | 667 | const tmp_file_name = "linker.ld.tmp"; // TODO issue #298 |
| 621 | 668 | io.writeFile(tmp_file_name, script, builder.allocator) |
| 622 | 669 | %% |err| debug.panic("unable to write linker script: {}\n", @errorName(err)); |
| 623 | %return zig_args.append("--linker-script"); | |
| 624 | %return zig_args.append(tmp_file_name); | |
| 670 | %%zig_args.append("--linker-script"); | |
| 671 | %%zig_args.append(tmp_file_name); | |
| 625 | 672 | }, |
| 626 | 673 | LinkerScript.Path => |path| { |
| 627 | %return zig_args.append("--linker-script"); | |
| 628 | %return zig_args.append(path); | |
| 674 | %%zig_args.append("--linker-script"); | |
| 675 | %%zig_args.append(path); | |
| 629 | 676 | }, |
| 630 | 677 | } |
| 631 | 678 | |
| ... | ... | @@ -633,31 +680,109 @@ const Exe = struct { |
| 633 | 680 | var it = exe.link_libs.iterator(); |
| 634 | 681 | while (true) { |
| 635 | 682 | const entry = it.next() ?? break; |
| 636 | %return zig_args.append("--library"); | |
| 637 | %return zig_args.append(entry.key); | |
| 683 | %%zig_args.append("--library"); | |
| 684 | %%zig_args.append(entry.key); | |
| 685 | } | |
| 686 | } | |
| 687 | ||
| 688 | for (builder.include_paths.toSliceConst()) |include_path| { | |
| 689 | %%zig_args.append("-isystem"); | |
| 690 | %%zig_args.append(include_path); | |
| 691 | } | |
| 692 | ||
| 693 | for (builder.rpaths.toSliceConst()) |rpath| { | |
| 694 | %%zig_args.append("-rpath"); | |
| 695 | %%zig_args.append(rpath); | |
| 696 | } | |
| 697 | ||
| 698 | for (builder.lib_paths.toSliceConst()) |lib_path| { | |
| 699 | %%zig_args.append("--library-path"); | |
| 700 | %%zig_args.append(lib_path); | |
| 701 | } | |
| 702 | ||
| 703 | builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); | |
| 704 | } | |
| 705 | }; | |
| 706 | ||
| 707 | pub const TestStep = struct { | |
| 708 | step: Step, | |
| 709 | builder: &Builder, | |
| 710 | root_src: []const u8, | |
| 711 | release: bool, | |
| 712 | verbose: bool, | |
| 713 | link_libs: BufSet, | |
| 714 | ||
| 715 | pub fn init(builder: &Builder, root_src: []const u8) -> TestStep { | |
| 716 | const step_name = %%fmt.allocPrint(builder.allocator, "test {}", root_src); | |
| 717 | TestStep { | |
| 718 | .step = Step.init(step_name, builder.allocator, make), | |
| 719 | .builder = builder, | |
| 720 | .root_src = root_src, | |
| 721 | .release = false, | |
| 722 | .verbose = false, | |
| 723 | .link_libs = BufSet.init(builder.allocator), | |
| 724 | } | |
| 725 | } | |
| 726 | ||
| 727 | pub fn setVerbose(self: &TestStep, value: bool) { | |
| 728 | self.verbose = value; | |
| 729 | } | |
| 730 | ||
| 731 | pub fn setRelease(self: &TestStep, value: bool) { | |
| 732 | self.release = value; | |
| 733 | } | |
| 734 | ||
| 735 | pub fn linkLibrary(self: &TestStep, name: []const u8) { | |
| 736 | %%self.link_libs.put(name); | |
| 737 | } | |
| 738 | ||
| 739 | fn make(step: &Step) -> %void { | |
| 740 | const self = @fieldParentPtr(TestStep, "step", step); | |
| 741 | const builder = self.builder; | |
| 742 | ||
| 743 | var zig_args = List([]const u8).init(builder.allocator); | |
| 744 | defer zig_args.deinit(); | |
| 745 | ||
| 746 | %%zig_args.append("test"); | |
| 747 | %%zig_args.append(builder.pathFromRoot(self.root_src)); | |
| 748 | ||
| 749 | if (self.verbose) { | |
| 750 | %%zig_args.append("--verbose"); | |
| 751 | } | |
| 752 | ||
| 753 | if (self.release) { | |
| 754 | %%zig_args.append("--release"); | |
| 755 | } | |
| 756 | ||
| 757 | { | |
| 758 | var it = self.link_libs.iterator(); | |
| 759 | while (true) { | |
| 760 | const entry = it.next() ?? break; | |
| 761 | %%zig_args.append("--library"); | |
| 762 | %%zig_args.append(entry.key); | |
| 638 | 763 | } |
| 639 | 764 | } |
| 640 | 765 | |
| 641 | 766 | for (builder.include_paths.toSliceConst()) |include_path| { |
| 642 | %return zig_args.append("-isystem"); | |
| 643 | %return zig_args.append(include_path); | |
| 767 | %%zig_args.append("-isystem"); | |
| 768 | %%zig_args.append(include_path); | |
| 644 | 769 | } |
| 645 | 770 | |
| 646 | 771 | for (builder.rpaths.toSliceConst()) |rpath| { |
| 647 | %return zig_args.append("-rpath"); | |
| 648 | %return zig_args.append(rpath); | |
| 772 | %%zig_args.append("-rpath"); | |
| 773 | %%zig_args.append(rpath); | |
| 649 | 774 | } |
| 650 | 775 | |
| 651 | 776 | for (builder.lib_paths.toSliceConst()) |lib_path| { |
| 652 | %return zig_args.append("--library-path"); | |
| 653 | %return zig_args.append(lib_path); | |
| 777 | %%zig_args.append("--library-path"); | |
| 778 | %%zig_args.append(lib_path); | |
| 654 | 779 | } |
| 655 | 780 | |
| 656 | 781 | builder.spawnChild(builder.zig_exe, zig_args.toSliceConst()); |
| 657 | 782 | } |
| 658 | 783 | }; |
| 659 | 784 | |
| 660 | const CLibrary = struct { | |
| 785 | pub const CLibrary = struct { | |
| 661 | 786 | step: Step, |
| 662 | 787 | name: []const u8, |
| 663 | 788 | out_filename: []const u8, |
| ... | ... | @@ -829,7 +954,7 @@ const CLibrary = struct { |
| 829 | 954 | } |
| 830 | 955 | }; |
| 831 | 956 | |
| 832 | const CExecutable = struct { | |
| 957 | pub const CExecutable = struct { | |
| 833 | 958 | step: Step, |
| 834 | 959 | builder: &Builder, |
| 835 | 960 | name: []const u8, |
| ... | ... | @@ -959,7 +1084,7 @@ const CExecutable = struct { |
| 959 | 1084 | } |
| 960 | 1085 | }; |
| 961 | 1086 | |
| 962 | const CommandStep = struct { | |
| 1087 | pub const CommandStep = struct { | |
| 963 | 1088 | step: Step, |
| 964 | 1089 | builder: &Builder, |
| 965 | 1090 | exe_path: []const u8, |
| ... | ... | @@ -988,7 +1113,7 @@ const CommandStep = struct { |
| 988 | 1113 | } |
| 989 | 1114 | }; |
| 990 | 1115 | |
| 991 | const InstallCLibraryStep = struct { | |
| 1116 | pub const InstallCLibraryStep = struct { | |
| 992 | 1117 | step: Step, |
| 993 | 1118 | builder: &Builder, |
| 994 | 1119 | lib: &CLibrary, |
| ... | ... | @@ -1023,7 +1148,7 @@ const InstallCLibraryStep = struct { |
| 1023 | 1148 | } |
| 1024 | 1149 | }; |
| 1025 | 1150 | |
| 1026 | const InstallFileStep = struct { | |
| 1151 | pub const InstallFileStep = struct { | |
| 1027 | 1152 | step: Step, |
| 1028 | 1153 | builder: &Builder, |
| 1029 | 1154 | src_path: []const u8, |
| ... | ... | @@ -1047,7 +1172,59 @@ const InstallFileStep = struct { |
| 1047 | 1172 | } |
| 1048 | 1173 | }; |
| 1049 | 1174 | |
| 1050 | const Step = struct { | |
| 1175 | pub const WriteFileStep = struct { | |
| 1176 | step: Step, | |
| 1177 | builder: &Builder, | |
| 1178 | file_path: []const u8, | |
| 1179 | data: []const u8, | |
| 1180 | ||
| 1181 | pub fn init(builder: &Builder, file_path: []const u8, data: []const u8) -> WriteFileStep { | |
| 1182 | return WriteFileStep { | |
| 1183 | .builder = builder, | |
| 1184 | .step = Step.init( | |
| 1185 | %%fmt.allocPrint(builder.allocator, "writefile {}", file_path), | |
| 1186 | builder.allocator, make), | |
| 1187 | .file_path = file_path, | |
| 1188 | .data = data, | |
| 1189 | }; | |
| 1190 | } | |
| 1191 | ||
| 1192 | fn make(step: &Step) -> %void { | |
| 1193 | const self = @fieldParentPtr(WriteFileStep, "step", step); | |
| 1194 | const full_path = self.builder.pathFromRoot(self.file_path); | |
| 1195 | const full_path_dir = %%os.path.dirname(self.builder.allocator, full_path); | |
| 1196 | os.makePath(self.builder.allocator, full_path_dir) %% |err| { | |
| 1197 | debug.panic("unable to make path {}: {}\n", full_path_dir, @errorName(err)); | |
| 1198 | }; | |
| 1199 | io.writeFile(full_path, self.data, self.builder.allocator) %% |err| { | |
| 1200 | debug.panic("unable to write {}: {}\n", full_path, @errorName(err)); | |
| 1201 | }; | |
| 1202 | } | |
| 1203 | }; | |
| 1204 | ||
| 1205 | pub const LogStep = struct { | |
| 1206 | step: Step, | |
| 1207 | builder: &Builder, | |
| 1208 | data: []const u8, | |
| 1209 | ||
| 1210 | pub fn init(builder: &Builder, data: []const u8) -> LogStep { | |
| 1211 | return LogStep { | |
| 1212 | .builder = builder, | |
| 1213 | .step = Step.init( | |
| 1214 | %%fmt.allocPrint(builder.allocator, "log {}", data), | |
| 1215 | builder.allocator, make), | |
| 1216 | .data = data, | |
| 1217 | }; | |
| 1218 | } | |
| 1219 | ||
| 1220 | fn make(step: &Step) -> %void { | |
| 1221 | const self = @fieldParentPtr(LogStep, "step", step); | |
| 1222 | %%io.stderr.write(self.data); | |
| 1223 | %%io.stderr.flush(); | |
| 1224 | } | |
| 1225 | }; | |
| 1226 | ||
| 1227 | pub const Step = struct { | |
| 1051 | 1228 | name: []const u8, |
| 1052 | 1229 | makeFn: fn(self: &Step) -> %void, |
| 1053 | 1230 | dependencies: List(&Step), |
std/mem.zig+28| ... | ... | @@ -134,6 +134,13 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) -> bool { |
| 134 | 134 | return true; |
| 135 | 135 | } |
| 136 | 136 | |
| 137 | /// Copies ::m to newly allocated memory. Caller is responsible to free it. | |
| 138 | pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) -> %[]T { | |
| 139 | const new_buf = %return allocator.alloc(T, m.len); | |
| 140 | copy(T, new_buf, m); | |
| 141 | return new_buf; | |
| 142 | } | |
| 143 | ||
| 137 | 144 | /// Linear search for the index of a scalar value inside a slice. |
| 138 | 145 | pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) -> ?usize { |
| 139 | 146 | for (slice) |item, i| { |
| ... | ... | @@ -144,6 +151,27 @@ pub fn indexOfScalar(comptime T: type, slice: []const T, value: T) -> ?usize { |
| 144 | 151 | return null; |
| 145 | 152 | } |
| 146 | 153 | |
| 154 | // TODO boyer-moore algorithm | |
| 155 | pub fn indexOf(comptime T: type, haystack: []const T, needle: []const T) -> ?usize { | |
| 156 | if (needle.len > haystack.len) | |
| 157 | return null; | |
| 158 | ||
| 159 | var i: usize = 0; | |
| 160 | const end = haystack.len - needle.len; | |
| 161 | while (i <= end; i += 1) { | |
| 162 | if (eql(T, haystack[i...i + needle.len], needle)) | |
| 163 | return i; | |
| 164 | } | |
| 165 | return null; | |
| 166 | } | |
| 167 | ||
| 168 | test "mem.indexOf" { | |
| 169 | assert(??indexOf(u8, "one two three four", "four") == 14); | |
| 170 | assert(indexOf(u8, "one two three four", "gour") == null); | |
| 171 | assert(??indexOf(u8, "foo", "foo") == 0); | |
| 172 | assert(indexOf(u8, "foo", "fool") == null); | |
| 173 | } | |
| 174 | ||
| 147 | 175 | /// Reads an integer from memory with size equal to bytes.len. |
| 148 | 176 | /// T specifies the return type, which must be large enough to store |
| 149 | 177 | /// the result. |
std/os/index.zig+61-4| ... | ... | @@ -12,6 +12,11 @@ pub const max_noalloc_path_len = 1024; |
| 12 | 12 | pub const ChildProcess = @import("child_process.zig").ChildProcess; |
| 13 | 13 | pub const path = @import("path.zig"); |
| 14 | 14 | |
| 15 | pub const line_sep = switch (@compileVar("os")) { | |
| 16 | Os.windows => "\r\n", | |
| 17 | else => "\n", | |
| 18 | }; | |
| 19 | ||
| 15 | 20 | const debug = @import("../debug.zig"); |
| 16 | 21 | const assert = debug.assert; |
| 17 | 22 | |
| ... | ... | @@ -319,7 +324,8 @@ fn posixExecveErrnoToErr(err: usize) -> error { |
| 319 | 324 | errno.EINVAL, errno.ENOEXEC => error.InvalidExe, |
| 320 | 325 | errno.EIO, errno.ELOOP => error.FileSystem, |
| 321 | 326 | errno.EISDIR => error.IsDir, |
| 322 | errno.ENOENT, errno.ENOTDIR => error.FileNotFound, | |
| 327 | errno.ENOENT => error.FileNotFound, | |
| 328 | errno.ENOTDIR => error.NotDir, | |
| 323 | 329 | errno.ETXTBSY => error.FileBusy, |
| 324 | 330 | else => error.Unexpected, |
| 325 | 331 | }; |
| ... | ... | @@ -413,7 +419,8 @@ pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []con |
| 413 | 419 | errno.EIO => error.FileSystem, |
| 414 | 420 | errno.ELOOP => error.SymLinkLoop, |
| 415 | 421 | errno.ENAMETOOLONG => error.NameTooLong, |
| 416 | errno.ENOENT, errno.ENOTDIR => error.FileNotFound, | |
| 422 | errno.ENOENT => error.FileNotFound, | |
| 423 | errno.ENOTDIR => error.NotDir, | |
| 417 | 424 | errno.ENOMEM => error.SystemResources, |
| 418 | 425 | errno.ENOSPC => error.NoSpaceLeft, |
| 419 | 426 | errno.EROFS => error.ReadOnlyFileSystem, |
| ... | ... | @@ -471,7 +478,8 @@ pub fn deleteFile(allocator: &Allocator, file_path: []const u8) -> %void { |
| 471 | 478 | errno.EISDIR => error.IsDir, |
| 472 | 479 | errno.ELOOP => error.SymLinkLoop, |
| 473 | 480 | errno.ENAMETOOLONG => error.NameTooLong, |
| 474 | errno.ENOENT, errno.ENOTDIR => error.FileNotFound, | |
| 481 | errno.ENOENT => error.FileNotFound, | |
| 482 | errno.ENOTDIR => error.NotDir, | |
| 475 | 483 | errno.ENOMEM => error.SystemResources, |
| 476 | 484 | errno.EROFS => error.ReadOnlyFileSystem, |
| 477 | 485 | else => error.Unexpected, |
| ... | ... | @@ -518,7 +526,8 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) |
| 518 | 526 | errno.ELOOP => error.SymLinkLoop, |
| 519 | 527 | errno.EMLINK => error.LinkQuotaExceeded, |
| 520 | 528 | errno.ENAMETOOLONG => error.NameTooLong, |
| 521 | errno.ENOENT, errno.ENOTDIR => error.FileNotFound, | |
| 529 | errno.ENOENT => error.FileNotFound, | |
| 530 | errno.ENOTDIR => error.NotDir, | |
| 522 | 531 | errno.ENOMEM => error.SystemResources, |
| 523 | 532 | errno.ENOSPC => error.NoSpaceLeft, |
| 524 | 533 | errno.EEXIST, errno.ENOTEMPTY => error.PathAlreadyExists, |
| ... | ... | @@ -528,3 +537,51 @@ pub fn rename(allocator: &Allocator, old_path: []const u8, new_path: []const u8) |
| 528 | 537 | }; |
| 529 | 538 | } |
| 530 | 539 | } |
| 540 | ||
| 541 | pub fn makeDir(allocator: &Allocator, dir_path: []const u8) -> %void { | |
| 542 | const path_buf = %return allocator.alloc(u8, dir_path.len + 1); | |
| 543 | defer allocator.free(path_buf); | |
| 544 | ||
| 545 | mem.copy(u8, path_buf, dir_path); | |
| 546 | path_buf[dir_path.len] = 0; | |
| 547 | ||
| 548 | const err = posix.getErrno(posix.mkdir(path_buf.ptr, 0o755)); | |
| 549 | if (err > 0) { | |
| 550 | return switch (err) { | |
| 551 | errno.EACCES, errno.EPERM => error.AccessDenied, | |
| 552 | errno.EDQUOT => error.DiskQuota, | |
| 553 | errno.EEXIST => error.PathAlreadyExists, | |
| 554 | errno.EFAULT => unreachable, | |
| 555 | errno.ELOOP => error.SymLinkLoop, | |
| 556 | errno.EMLINK => error.LinkQuotaExceeded, | |
| 557 | errno.ENAMETOOLONG => error.NameTooLong, | |
| 558 | errno.ENOENT => error.FileNotFound, | |
| 559 | errno.ENOMEM => error.SystemResources, | |
| 560 | errno.ENOSPC => error.NoSpaceLeft, | |
| 561 | errno.ENOTDIR => error.NotDir, | |
| 562 | errno.EROFS => error.ReadOnlyFileSystem, | |
| 563 | else => error.Unexpected, | |
| 564 | }; | |
| 565 | } | |
| 566 | } | |
| 567 | ||
| 568 | /// Calls makeDir recursively to make an entire path. Returns success if the path | |
| 569 | /// already exists and is a directory. | |
| 570 | pub fn makePath(allocator: &Allocator, full_path: []const u8) -> %void { | |
| 571 | const child_dir = %return path.dirname(allocator, full_path); | |
| 572 | defer allocator.free(child_dir); | |
| 573 | ||
| 574 | if (mem.eql(u8, child_dir, full_path)) | |
| 575 | return; | |
| 576 | ||
| 577 | makePath(allocator, child_dir) %% |err| { | |
| 578 | if (err != error.PathAlreadyExists) | |
| 579 | return err; | |
| 580 | }; | |
| 581 | ||
| 582 | makeDir(allocator, full_path) %% |err| { | |
| 583 | if (err != error.PathAlreadyExists) | |
| 584 | return err; | |
| 585 | // TODO stat the file and return an error if it's not a directory | |
| 586 | }; | |
| 587 | } |
std/os/linux.zig+4| ... | ... | @@ -273,6 +273,10 @@ pub fn getcwd(buf: &u8, size: usize) -> usize { |
| 273 | 273 | arch.syscall2(arch.SYS_getcwd, usize(buf), size) |
| 274 | 274 | } |
| 275 | 275 | |
| 276 | pub fn mkdir(path: &const u8, mode: usize) -> usize { | |
| 277 | arch.syscall2(arch.SYS_mkdir, usize(path), mode) | |
| 278 | } | |
| 279 | ||
| 276 | 280 | pub fn mmap(address: ?&u8, length: usize, prot: usize, flags: usize, fd: i32, offset: usize) |
| 277 | 281 | -> usize |
| 278 | 282 | { |
std/os/path.zig+49-10| ... | ... | @@ -4,22 +4,61 @@ const mem = @import("../mem.zig"); |
| 4 | 4 | const Allocator = mem.Allocator; |
| 5 | 5 | |
| 6 | 6 | /// Allocates memory for the result, which must be freed by the caller. |
| 7 | pub fn join(allocator: &Allocator, dirname: []const u8, basename: []const u8) -> %[]const u8 { | |
| 8 | const buf = %return allocator.alloc(u8, dirname.len + basename.len + 1); | |
| 7 | pub fn join(allocator: &Allocator, paths: ...) -> %[]u8 { | |
| 8 | assert(paths.len >= 2); | |
| 9 | var total_paths_len: usize = paths.len; // 1 slash per path | |
| 10 | { | |
| 11 | comptime var path_i = 0; | |
| 12 | inline while (path_i < paths.len; path_i += 1) { | |
| 13 | const arg = ([]const u8)(paths[path_i]); | |
| 14 | total_paths_len += arg.len; | |
| 15 | } | |
| 16 | } | |
| 17 | ||
| 18 | const buf = %return allocator.alloc(u8, total_paths_len); | |
| 9 | 19 | %defer allocator.free(buf); |
| 10 | 20 | |
| 11 | mem.copy(u8, buf, dirname); | |
| 12 | if (dirname[dirname.len - 1] == '/') { | |
| 13 | mem.copy(u8, buf[dirname.len...], basename); | |
| 14 | return buf[0...buf.len - 1]; | |
| 15 | } else { | |
| 16 | buf[dirname.len] = '/'; | |
| 17 | mem.copy(u8, buf[dirname.len + 1 ...], basename); | |
| 18 | return buf; | |
| 21 | var buf_index: usize = 0; | |
| 22 | comptime var path_i = 0; | |
| 23 | inline while (true) { | |
| 24 | const arg = ([]const u8)(paths[path_i]); | |
| 25 | path_i += 1; | |
| 26 | mem.copy(u8, buf[buf_index...], arg); | |
| 27 | buf_index += arg.len; | |
| 28 | if (path_i >= paths.len) break; | |
| 29 | if (arg[arg.len - 1] != '/') { | |
| 30 | buf[buf_index] = '/'; | |
| 31 | buf_index += 1; | |
| 32 | } | |
| 19 | 33 | } |
| 34 | ||
| 35 | return buf[0...buf_index]; | |
| 20 | 36 | } |
| 21 | 37 | |
| 22 | 38 | test "os.path.join" { |
| 23 | 39 | assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b", "c"), "/a/b/c")); |
| 24 | 40 | assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/b/", "c"), "/a/b/c")); |
| 41 | ||
| 42 | assert(mem.eql(u8, %%join(&debug.global_allocator, "/", "a", "b/", "c"), "/a/b/c")); | |
| 43 | assert(mem.eql(u8, %%join(&debug.global_allocator, "/a/", "b/", "c"), "/a/b/c")); | |
| 44 | } | |
| 45 | ||
| 46 | pub fn dirname(allocator: &Allocator, path: []const u8) -> %[]u8 { | |
| 47 | if (path.len != 0) { | |
| 48 | var last_index: usize = path.len - 1; | |
| 49 | if (path[last_index] == '/') | |
| 50 | last_index -= 1; | |
| 51 | ||
| 52 | var i: usize = last_index; | |
| 53 | while (true) { | |
| 54 | const c = path[i]; | |
| 55 | if (c == '/') | |
| 56 | return mem.dupe(allocator, u8, path[0...i]); | |
| 57 | if (i == 0) | |
| 58 | break; | |
| 59 | i -= 1; | |
| 60 | } | |
| 61 | } | |
| 62 | ||
| 63 | return mem.dupe(allocator, u8, "."); | |
| 25 | 64 | } |
std/special/build_file_template.zig+3-1| ... | ... | @@ -3,6 +3,8 @@ const Builder = @import("std").build.Builder; |
| 3 | 3 | pub fn build(b: &Builder) { |
| 4 | 4 | const release = b.option(bool, "release", "optimizations on and safety off") ?? false; |
| 5 | 5 | |
| 6 | var exe = b.addExe("src/main.zig", "YOUR_NAME_HERE"); | |
| 6 | const exe = b.addExecutable("YOUR_NAME_HERE", "src/main.zig"); | |
| 7 | 7 | exe.setRelease(release); |
| 8 | ||
| 9 | b.default_step.dependOn(&exe.step); | |
| 8 | 10 | } |
std/special/build_runner.zig+32-21| ... | ... | @@ -10,74 +10,85 @@ const List = std.list.List; |
| 10 | 10 | error InvalidArgs; |
| 11 | 11 | |
| 12 | 12 | pub fn main() -> %void { |
| 13 | var arg_i: usize = 1; | |
| 14 | ||
| 15 | const zig_exe = { | |
| 16 | if (arg_i >= os.args.count()) { | |
| 17 | %%io.stderr.printf("Expected first argument to be path to zig compiler\n"); | |
| 18 | return error.InvalidArgs; | |
| 19 | } | |
| 20 | const result = os.args.at(arg_i); | |
| 21 | arg_i += 1; | |
| 22 | result | |
| 23 | }; | |
| 24 | ||
| 25 | const build_root = { | |
| 26 | if (arg_i >= os.args.count()) { | |
| 27 | %%io.stderr.printf("Expected second argument to be build root directory path\n"); | |
| 28 | return error.InvalidArgs; | |
| 29 | } | |
| 30 | const result = os.args.at(arg_i); | |
| 31 | arg_i += 1; | |
| 32 | result | |
| 33 | }; | |
| 34 | ||
| 13 | 35 | // TODO use a more general purpose allocator here |
| 14 | 36 | var inc_allocator = %%mem.IncrementingAllocator.init(10 * 1024 * 1024); |
| 15 | 37 | defer inc_allocator.deinit(); |
| 16 | 38 | |
| 17 | 39 | const allocator = &inc_allocator.allocator; |
| 18 | 40 | |
| 19 | var builder = Builder.init(allocator); | |
| 41 | var builder = Builder.init(allocator, zig_exe, build_root); | |
| 20 | 42 | defer builder.deinit(); |
| 21 | 43 | |
| 22 | var maybe_zig_exe: ?[]const u8 = null; | |
| 23 | 44 | var targets = List([]const u8).init(allocator); |
| 24 | 45 | |
| 25 | 46 | var prefix: ?[]const u8 = null; |
| 26 | 47 | |
| 27 | var arg_i: usize = 1; | |
| 28 | 48 | while (arg_i < os.args.count(); arg_i += 1) { |
| 29 | 49 | const arg = os.args.at(arg_i); |
| 30 | 50 | if (mem.startsWith(u8, arg, "-D")) { |
| 31 | 51 | const option_contents = arg[2...]; |
| 32 | 52 | if (option_contents.len == 0) { |
| 33 | 53 | %%io.stderr.printf("Expected option name after '-D'\n\n"); |
| 34 | return usage(&builder, maybe_zig_exe, false, &io.stderr); | |
| 54 | return usage(&builder, false, &io.stderr); | |
| 35 | 55 | } |
| 36 | 56 | if (const name_end ?= mem.indexOfScalar(u8, option_contents, '=')) { |
| 37 | 57 | const option_name = option_contents[0...name_end]; |
| 38 | const option_value = option_contents[name_end...]; | |
| 58 | const option_value = option_contents[name_end + 1...]; | |
| 39 | 59 | if (builder.addUserInputOption(option_name, option_value)) |
| 40 | return usage(&builder, maybe_zig_exe, false, &io.stderr); | |
| 60 | return usage(&builder, false, &io.stderr); | |
| 41 | 61 | } else { |
| 42 | 62 | if (builder.addUserInputFlag(option_contents)) |
| 43 | return usage(&builder, maybe_zig_exe, false, &io.stderr); | |
| 63 | return usage(&builder, false, &io.stderr); | |
| 44 | 64 | } |
| 45 | 65 | } else if (mem.startsWith(u8, arg, "-")) { |
| 46 | 66 | if (mem.eql(u8, arg, "--verbose")) { |
| 47 | 67 | builder.verbose = true; |
| 48 | 68 | } else if (mem.eql(u8, arg, "--help")) { |
| 49 | return usage(&builder, maybe_zig_exe, false, &io.stdout); | |
| 69 | return usage(&builder, false, &io.stdout); | |
| 50 | 70 | } else if (mem.eql(u8, arg, "--prefix") and arg_i + 1 < os.args.count()) { |
| 51 | 71 | arg_i += 1; |
| 52 | 72 | prefix = os.args.at(arg_i); |
| 53 | 73 | } else { |
| 54 | 74 | %%io.stderr.printf("Unrecognized argument: {}\n\n", arg); |
| 55 | return usage(&builder, maybe_zig_exe, false, &io.stderr); | |
| 75 | return usage(&builder, false, &io.stderr); | |
| 56 | 76 | } |
| 57 | } else if (maybe_zig_exe == null) { | |
| 58 | maybe_zig_exe = arg; | |
| 59 | 77 | } else { |
| 60 | 78 | %%targets.append(arg); |
| 61 | 79 | } |
| 62 | 80 | } |
| 63 | 81 | |
| 64 | builder.zig_exe = maybe_zig_exe ?? return usage(&builder, null, false, &io.stderr); | |
| 65 | 82 | builder.setInstallPrefix(prefix); |
| 66 | ||
| 67 | 83 | root.build(&builder); |
| 68 | 84 | |
| 69 | 85 | if (builder.validateUserInputDidItFail()) |
| 70 | return usage(&builder, maybe_zig_exe, true, &io.stderr); | |
| 86 | return usage(&builder, true, &io.stderr); | |
| 71 | 87 | |
| 72 | 88 | %return builder.make(targets.toSliceConst()); |
| 73 | 89 | } |
| 74 | 90 | |
| 75 | fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool, out_stream: &io.OutStream) -> %void { | |
| 76 | const zig_exe = maybe_zig_exe ?? { | |
| 77 | %%out_stream.printf("Expected first argument to be path to zig compiler\n"); | |
| 78 | return error.InvalidArgs; | |
| 79 | }; | |
| 80 | ||
| 91 | fn usage(builder: &Builder, already_ran_build: bool, out_stream: &io.OutStream) -> %void { | |
| 81 | 92 | // run the build script to collect the options |
| 82 | 93 | if (!already_ran_build) { |
| 83 | 94 | builder.setInstallPrefix(null); |
| ... | ... | @@ -90,7 +101,7 @@ fn usage(builder: &Builder, maybe_zig_exe: ?[]const u8, already_ran_build: bool, |
| 90 | 101 | \\ |
| 91 | 102 | \\Steps: |
| 92 | 103 | \\ |
| 93 | , zig_exe); | |
| 104 | , builder.zig_exe); | |
| 94 | 105 | |
| 95 | 106 | const allocator = builder.allocator; |
| 96 | 107 | for (builder.top_level_steps.toSliceConst()) |top_level_step| { |
test/run_tests.cpp-407| ... | ... | @@ -270,412 +270,6 @@ static TestCase *add_example_compile_libc(const char *root_source_file) { |
| 270 | 270 | return add_example_compile_extra(root_source_file, true); |
| 271 | 271 | } |
| 272 | 272 | |
| 273 | static void add_compiling_test_cases(void) { | |
| 274 | add_simple_case_libc("hello world with libc", R"SOURCE( | |
| 275 | const c = @cImport(@cInclude("stdio.h")); | |
| 276 | export fn main(argc: c_int, argv: &&u8) -> c_int { | |
| 277 | _ = c.puts(c"Hello, world!"); | |
| 278 | return 0; | |
| 279 | } | |
| 280 | )SOURCE", "Hello, world!" NL); | |
| 281 | ||
| 282 | { | |
| 283 | TestCase *tc = add_simple_case("multiple files with private function", R"SOURCE( | |
| 284 | use @import("std").io; | |
| 285 | use @import("foo.zig"); | |
| 286 | ||
| 287 | pub fn main() -> %void { | |
| 288 | privateFunction(); | |
| 289 | %%stdout.printf("OK 2\n"); | |
| 290 | } | |
| 291 | ||
| 292 | fn privateFunction() { | |
| 293 | printText(); | |
| 294 | } | |
| 295 | )SOURCE", "OK 1\nOK 2\n"); | |
| 296 | ||
| 297 | add_source_file(tc, "foo.zig", R"SOURCE( | |
| 298 | use @import("std").io; | |
| 299 | ||
| 300 | // purposefully conflicting function with main.zig | |
| 301 | // but it's private so it should be OK | |
| 302 | fn privateFunction() { | |
| 303 | %%stdout.printf("OK 1\n"); | |
| 304 | } | |
| 305 | ||
| 306 | pub fn printText() { | |
| 307 | privateFunction(); | |
| 308 | } | |
| 309 | )SOURCE"); | |
| 310 | } | |
| 311 | ||
| 312 | { | |
| 313 | TestCase *tc = add_simple_case("import segregation", R"SOURCE( | |
| 314 | use @import("foo.zig"); | |
| 315 | use @import("bar.zig"); | |
| 316 | ||
| 317 | pub fn main() -> %void { | |
| 318 | foo_function(); | |
| 319 | bar_function(); | |
| 320 | } | |
| 321 | )SOURCE", "OK\nOK\n"); | |
| 322 | ||
| 323 | add_source_file(tc, "foo.zig", R"SOURCE( | |
| 324 | use @import("std").io; | |
| 325 | pub fn foo_function() { | |
| 326 | %%stdout.printf("OK\n"); | |
| 327 | } | |
| 328 | )SOURCE"); | |
| 329 | ||
| 330 | add_source_file(tc, "bar.zig", R"SOURCE( | |
| 331 | use @import("other.zig"); | |
| 332 | use @import("std").io; | |
| 333 | ||
| 334 | pub fn bar_function() { | |
| 335 | if (foo_function()) { | |
| 336 | %%stdout.printf("OK\n"); | |
| 337 | } | |
| 338 | } | |
| 339 | )SOURCE"); | |
| 340 | ||
| 341 | add_source_file(tc, "other.zig", R"SOURCE( | |
| 342 | pub fn foo_function() -> bool { | |
| 343 | // this one conflicts with the one from foo | |
| 344 | return true; | |
| 345 | } | |
| 346 | )SOURCE"); | |
| 347 | } | |
| 348 | ||
| 349 | { | |
| 350 | TestCase *tc = add_simple_case("two files use import each other", R"SOURCE( | |
| 351 | use @import("a.zig"); | |
| 352 | ||
| 353 | pub fn main() -> %void { | |
| 354 | ok(); | |
| 355 | } | |
| 356 | )SOURCE", "OK\n"); | |
| 357 | ||
| 358 | add_source_file(tc, "a.zig", R"SOURCE( | |
| 359 | use @import("b.zig"); | |
| 360 | const io = @import("std").io; | |
| 361 | ||
| 362 | pub const a_text = "OK\n"; | |
| 363 | ||
| 364 | pub fn ok() { | |
| 365 | %%io.stdout.printf(b_text); | |
| 366 | } | |
| 367 | )SOURCE"); | |
| 368 | ||
| 369 | add_source_file(tc, "b.zig", R"SOURCE( | |
| 370 | use @import("a.zig"); | |
| 371 | ||
| 372 | pub const b_text = a_text; | |
| 373 | )SOURCE"); | |
| 374 | } | |
| 375 | ||
| 376 | ||
| 377 | ||
| 378 | add_simple_case("hello world without libc", R"SOURCE( | |
| 379 | const io = @import("std").io; | |
| 380 | ||
| 381 | pub fn main() -> %void { | |
| 382 | %%io.stdout.printf("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')); | |
| 383 | } | |
| 384 | )SOURCE", "Hello, world!\n0012 012 a\n"); | |
| 385 | ||
| 386 | ||
| 387 | add_simple_case_libc("number literals", R"SOURCE( | |
| 388 | const c = @cImport(@cInclude("stdio.h")); | |
| 389 | ||
| 390 | export fn main(argc: c_int, argv: &&u8) -> c_int { | |
| 391 | _ = c.printf(c"\n"); | |
| 392 | ||
| 393 | _ = c.printf(c"0: %llu\n", | |
| 394 | u64(0)); | |
| 395 | _ = c.printf(c"320402575052271: %llu\n", | |
| 396 | u64(320402575052271)); | |
| 397 | _ = c.printf(c"0x01236789abcdef: %llu\n", | |
| 398 | u64(0x01236789abcdef)); | |
| 399 | _ = c.printf(c"0xffffffffffffffff: %llu\n", | |
| 400 | u64(0xffffffffffffffff)); | |
| 401 | _ = c.printf(c"0x000000ffffffffffffffff: %llu\n", | |
| 402 | u64(0x000000ffffffffffffffff)); | |
| 403 | _ = c.printf(c"0o1777777777777777777777: %llu\n", | |
| 404 | u64(0o1777777777777777777777)); | |
| 405 | _ = c.printf(c"0o0000001777777777777777777777: %llu\n", | |
| 406 | u64(0o0000001777777777777777777777)); | |
| 407 | _ = c.printf(c"0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n", | |
| 408 | u64(0b1111111111111111111111111111111111111111111111111111111111111111)); | |
| 409 | _ = c.printf(c"0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n", | |
| 410 | u64(0b0000001111111111111111111111111111111111111111111111111111111111111111)); | |
| 411 | ||
| 412 | _ = c.printf(c"\n"); | |
| 413 | ||
| 414 | _ = c.printf(c"0.0: %a\n", | |
| 415 | f64(0.0)); | |
| 416 | _ = c.printf(c"0e0: %a\n", | |
| 417 | f64(0e0)); | |
| 418 | _ = c.printf(c"0.0e0: %a\n", | |
| 419 | f64(0.0e0)); | |
| 420 | _ = c.printf(c"000000000000000000000000000000000000000000000000000000000.0e0: %a\n", | |
| 421 | f64(000000000000000000000000000000000000000000000000000000000.0e0)); | |
| 422 | _ = c.printf(c"0.000000000000000000000000000000000000000000000000000000000e0: %a\n", | |
| 423 | f64(0.000000000000000000000000000000000000000000000000000000000e0)); | |
| 424 | _ = c.printf(c"0.0e000000000000000000000000000000000000000000000000000000000: %a\n", | |
| 425 | f64(0.0e000000000000000000000000000000000000000000000000000000000)); | |
| 426 | _ = c.printf(c"1.0: %a\n", | |
| 427 | f64(1.0)); | |
| 428 | _ = c.printf(c"10.0: %a\n", | |
| 429 | f64(10.0)); | |
| 430 | _ = c.printf(c"10.5: %a\n", | |
| 431 | f64(10.5)); | |
| 432 | _ = c.printf(c"10.5e5: %a\n", | |
| 433 | f64(10.5e5)); | |
| 434 | _ = c.printf(c"10.5e+5: %a\n", | |
| 435 | f64(10.5e+5)); | |
| 436 | _ = c.printf(c"50.0e-2: %a\n", | |
| 437 | f64(50.0e-2)); | |
| 438 | _ = c.printf(c"50e-2: %a\n", | |
| 439 | f64(50e-2)); | |
| 440 | ||
| 441 | _ = c.printf(c"\n"); | |
| 442 | ||
| 443 | _ = c.printf(c"0x1.0: %a\n", | |
| 444 | f64(0x1.0)); | |
| 445 | _ = c.printf(c"0x10.0: %a\n", | |
| 446 | f64(0x10.0)); | |
| 447 | _ = c.printf(c"0x100.0: %a\n", | |
| 448 | f64(0x100.0)); | |
| 449 | _ = c.printf(c"0x103.0: %a\n", | |
| 450 | f64(0x103.0)); | |
| 451 | _ = c.printf(c"0x103.7: %a\n", | |
| 452 | f64(0x103.7)); | |
| 453 | _ = c.printf(c"0x103.70: %a\n", | |
| 454 | f64(0x103.70)); | |
| 455 | _ = c.printf(c"0x103.70p4: %a\n", | |
| 456 | f64(0x103.70p4)); | |
| 457 | _ = c.printf(c"0x103.70p5: %a\n", | |
| 458 | f64(0x103.70p5)); | |
| 459 | _ = c.printf(c"0x103.70p+5: %a\n", | |
| 460 | f64(0x103.70p+5)); | |
| 461 | _ = c.printf(c"0x103.70p-5: %a\n", | |
| 462 | f64(0x103.70p-5)); | |
| 463 | ||
| 464 | _ = c.printf(c"\n"); | |
| 465 | ||
| 466 | _ = c.printf(c"0b10100.00010e0: %a\n", | |
| 467 | f64(0b10100.00010e0)); | |
| 468 | _ = c.printf(c"0o10700.00010e0: %a\n", | |
| 469 | f64(0o10700.00010e0)); | |
| 470 | ||
| 471 | return 0; | |
| 472 | } | |
| 473 | )SOURCE", R"OUTPUT( | |
| 474 | 0: 0 | |
| 475 | 320402575052271: 320402575052271 | |
| 476 | 0x01236789abcdef: 320402575052271 | |
| 477 | 0xffffffffffffffff: 18446744073709551615 | |
| 478 | 0x000000ffffffffffffffff: 18446744073709551615 | |
| 479 | 0o1777777777777777777777: 18446744073709551615 | |
| 480 | 0o0000001777777777777777777777: 18446744073709551615 | |
| 481 | 0b1111111111111111111111111111111111111111111111111111111111111111: 18446744073709551615 | |
| 482 | 0b0000001111111111111111111111111111111111111111111111111111111111111111: 18446744073709551615 | |
| 483 | ||
| 484 | 0.0: 0x0p+0 | |
| 485 | 0e0: 0x0p+0 | |
| 486 | 0.0e0: 0x0p+0 | |
| 487 | 000000000000000000000000000000000000000000000000000000000.0e0: 0x0p+0 | |
| 488 | 0.000000000000000000000000000000000000000000000000000000000e0: 0x0p+0 | |
| 489 | 0.0e000000000000000000000000000000000000000000000000000000000: 0x0p+0 | |
| 490 | 1.0: 0x1p+0 | |
| 491 | 10.0: 0x1.4p+3 | |
| 492 | 10.5: 0x1.5p+3 | |
| 493 | 10.5e5: 0x1.0059p+20 | |
| 494 | 10.5e+5: 0x1.0059p+20 | |
| 495 | 50.0e-2: 0x1p-1 | |
| 496 | 50e-2: 0x1p-1 | |
| 497 | ||
| 498 | 0x1.0: 0x1p+0 | |
| 499 | 0x10.0: 0x1p+4 | |
| 500 | 0x100.0: 0x1p+8 | |
| 501 | 0x103.0: 0x1.03p+8 | |
| 502 | 0x103.7: 0x1.037p+8 | |
| 503 | 0x103.70: 0x1.037p+8 | |
| 504 | 0x103.70p4: 0x1.037p+12 | |
| 505 | 0x103.70p5: 0x1.037p+13 | |
| 506 | 0x103.70p+5: 0x1.037p+13 | |
| 507 | 0x103.70p-5: 0x1.037p+3 | |
| 508 | ||
| 509 | 0b10100.00010e0: 0x1.41p+4 | |
| 510 | 0o10700.00010e0: 0x1.1c0001p+12 | |
| 511 | )OUTPUT"); | |
| 512 | ||
| 513 | add_simple_case("order-independent declarations", R"SOURCE( | |
| 514 | const io = @import("std").io; | |
| 515 | const z = io.stdin_fileno; | |
| 516 | const x : @typeOf(y) = 1234; | |
| 517 | const y : u16 = 5678; | |
| 518 | pub fn main() -> %void { | |
| 519 | var x_local : i32 = print_ok(x); | |
| 520 | } | |
| 521 | fn print_ok(val: @typeOf(x)) -> @typeOf(foo) { | |
| 522 | %%io.stdout.printf("OK\n"); | |
| 523 | return 0; | |
| 524 | } | |
| 525 | const foo : i32 = 0; | |
| 526 | )SOURCE", "OK\n"); | |
| 527 | ||
| 528 | add_simple_case_libc("expose function pointer to C land", R"SOURCE( | |
| 529 | const c = @cImport(@cInclude("stdlib.h")); | |
| 530 | ||
| 531 | export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { | |
| 532 | const a_int = @ptrcast(&i32, a ?? unreachable); | |
| 533 | const b_int = @ptrcast(&i32, b ?? unreachable); | |
| 534 | if (*a_int < *b_int) { | |
| 535 | -1 | |
| 536 | } else if (*a_int > *b_int) { | |
| 537 | 1 | |
| 538 | } else { | |
| 539 | c_int(0) | |
| 540 | } | |
| 541 | } | |
| 542 | ||
| 543 | export fn main() -> c_int { | |
| 544 | var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; | |
| 545 | ||
| 546 | c.qsort(@ptrcast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn); | |
| 547 | ||
| 548 | for (array) |item, i| { | |
| 549 | if (item != i) { | |
| 550 | c.abort(); | |
| 551 | } | |
| 552 | } | |
| 553 | ||
| 554 | return 0; | |
| 555 | } | |
| 556 | )SOURCE", ""); | |
| 557 | ||
| 558 | ||
| 559 | ||
| 560 | add_simple_case_libc("casting between float and integer types", R"SOURCE( | |
| 561 | const c = @cImport(@cInclude("stdio.h")); | |
| 562 | export fn main(argc: c_int, argv: &&u8) -> c_int { | |
| 563 | const small: f32 = 3.25; | |
| 564 | const x: f64 = small; | |
| 565 | const y = i32(x); | |
| 566 | const z = f64(y); | |
| 567 | _ = c.printf(c"%.2f\n%d\n%.2f\n%.2f\n", x, y, z, f64(-0.4)); | |
| 568 | return 0; | |
| 569 | } | |
| 570 | )SOURCE", "3.25\n3\n3.00\n-0.40\n"); | |
| 571 | ||
| 572 | ||
| 573 | add_simple_case("same named methods in incomplete struct", R"SOURCE( | |
| 574 | const io = @import("std").io; | |
| 575 | ||
| 576 | const Foo = struct { | |
| 577 | field1: Bar, | |
| 578 | ||
| 579 | fn method(a: &const Foo) -> bool { true } | |
| 580 | }; | |
| 581 | ||
| 582 | const Bar = struct { | |
| 583 | field2: i32, | |
| 584 | ||
| 585 | fn method(b: &const Bar) -> bool { true } | |
| 586 | }; | |
| 587 | ||
| 588 | pub fn main() -> %void { | |
| 589 | const bar = Bar {.field2 = 13,}; | |
| 590 | const foo = Foo {.field1 = bar,}; | |
| 591 | if (!foo.method()) { | |
| 592 | %%io.stdout.printf("BAD\n"); | |
| 593 | } | |
| 594 | if (!bar.method()) { | |
| 595 | %%io.stdout.printf("BAD\n"); | |
| 596 | } | |
| 597 | %%io.stdout.printf("OK\n"); | |
| 598 | } | |
| 599 | )SOURCE", "OK\n"); | |
| 600 | ||
| 601 | ||
| 602 | add_simple_case("defer with only fallthrough", R"SOURCE( | |
| 603 | const io = @import("std").io; | |
| 604 | pub fn main() -> %void { | |
| 605 | %%io.stdout.printf("before\n"); | |
| 606 | defer %%io.stdout.printf("defer1\n"); | |
| 607 | defer %%io.stdout.printf("defer2\n"); | |
| 608 | defer %%io.stdout.printf("defer3\n"); | |
| 609 | %%io.stdout.printf("after\n"); | |
| 610 | } | |
| 611 | )SOURCE", "before\nafter\ndefer3\ndefer2\ndefer1\n"); | |
| 612 | ||
| 613 | ||
| 614 | add_simple_case("defer with return", R"SOURCE( | |
| 615 | const io = @import("std").io; | |
| 616 | const os = @import("std").os; | |
| 617 | pub fn main() -> %void { | |
| 618 | %%io.stdout.printf("before\n"); | |
| 619 | defer %%io.stdout.printf("defer1\n"); | |
| 620 | defer %%io.stdout.printf("defer2\n"); | |
| 621 | if (os.args.count() == 1) return; | |
| 622 | defer %%io.stdout.printf("defer3\n"); | |
| 623 | %%io.stdout.printf("after\n"); | |
| 624 | } | |
| 625 | )SOURCE", "before\ndefer2\ndefer1\n"); | |
| 626 | ||
| 627 | ||
| 628 | add_simple_case("%defer and it fails", R"SOURCE( | |
| 629 | const io = @import("std").io; | |
| 630 | pub fn main() -> %void { | |
| 631 | do_test() %% return; | |
| 632 | } | |
| 633 | fn do_test() -> %void { | |
| 634 | %%io.stdout.printf("before\n"); | |
| 635 | defer %%io.stdout.printf("defer1\n"); | |
| 636 | %defer %%io.stdout.printf("deferErr\n"); | |
| 637 | %return its_gonna_fail(); | |
| 638 | defer %%io.stdout.printf("defer3\n"); | |
| 639 | %%io.stdout.printf("after\n"); | |
| 640 | } | |
| 641 | error IToldYouItWouldFail; | |
| 642 | fn its_gonna_fail() -> %void { | |
| 643 | return error.IToldYouItWouldFail; | |
| 644 | } | |
| 645 | )SOURCE", "before\ndeferErr\ndefer1\n"); | |
| 646 | ||
| 647 | ||
| 648 | add_simple_case("%defer and it passes", R"SOURCE( | |
| 649 | const io = @import("std").io; | |
| 650 | pub fn main() -> %void { | |
| 651 | do_test() %% return; | |
| 652 | } | |
| 653 | fn do_test() -> %void { | |
| 654 | %%io.stdout.printf("before\n"); | |
| 655 | defer %%io.stdout.printf("defer1\n"); | |
| 656 | %defer %%io.stdout.printf("deferErr\n"); | |
| 657 | %return its_gonna_pass(); | |
| 658 | defer %%io.stdout.printf("defer3\n"); | |
| 659 | %%io.stdout.printf("after\n"); | |
| 660 | } | |
| 661 | fn its_gonna_pass() -> %void { } | |
| 662 | )SOURCE", "before\nafter\ndefer3\ndefer1\n"); | |
| 663 | ||
| 664 | ||
| 665 | { | |
| 666 | TestCase *tc = add_simple_case("@embedFile", R"SOURCE( | |
| 667 | const foo_txt = @embedFile("foo.txt"); | |
| 668 | const io = @import("std").io; | |
| 669 | ||
| 670 | pub fn main() -> %void { | |
| 671 | %%io.stdout.printf(foo_txt); | |
| 672 | } | |
| 673 | )SOURCE", "1234\nabcd\n"); | |
| 674 | ||
| 675 | add_source_file(tc, "foo.txt", "1234\nabcd\n"); | |
| 676 | } | |
| 677 | } | |
| 678 | ||
| 679 | 273 | //////////////////////////////////////////////////////////////////////////////////// |
| 680 | 274 | |
| 681 | 275 | static void add_build_examples(void) { |
| ... | ... | @@ -3021,7 +2615,6 @@ int main(int argc, char **argv) { |
| 3021 | 2615 | } |
| 3022 | 2616 | } |
| 3023 | 2617 | } |
| 3024 | add_compiling_test_cases(); | |
| 3025 | 2618 | add_build_examples(); |
| 3026 | 2619 | add_debug_safety_test_cases(); |
| 3027 | 2620 | add_compile_failure_test_cases(); |
test/run_tests.zig created+5| ... | ... | @@ -0,0 +1,5 @@ |
| 1 | const io = @import("std").io; | |
| 2 | ||
| 3 | pub fn main() -> %void { | |
| 4 | %%io.stderr.printf("TODO run tests\n"); | |
| 5 | } |
test/tests.zig created+587| ... | ... | @@ -0,0 +1,587 @@ |
| 1 | const std = @import("std"); | |
| 2 | const debug = std.debug; | |
| 3 | const build = std.build; | |
| 4 | const os = std.os; | |
| 5 | const StdIo = os.ChildProcess.StdIo; | |
| 6 | const Term = os.ChildProcess.Term; | |
| 7 | const Buffer0 = std.cstr.Buffer0; | |
| 8 | const io = std.io; | |
| 9 | const mem = std.mem; | |
| 10 | const fmt = std.fmt; | |
| 11 | const List = std.list.List; | |
| 12 | ||
| 13 | error TestFailed; | |
| 14 | ||
| 15 | pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step { | |
| 16 | const cases = %%b.allocator.create(CompareOutputContext); | |
| 17 | *cases = CompareOutputContext { | |
| 18 | .b = b, | |
| 19 | .compare_output_tests = b.step("test-compare-output", "Run the compare output tests"), | |
| 20 | .test_index = 0, | |
| 21 | .test_filter = test_filter, | |
| 22 | }; | |
| 23 | ||
| 24 | cases.addC("hello world with libc", | |
| 25 | \\const c = @cImport(@cInclude("stdio.h")); | |
| 26 | \\export fn main(argc: c_int, argv: &&u8) -> c_int { | |
| 27 | \\ _ = c.puts(c"Hello, world!"); | |
| 28 | \\ return 0; | |
| 29 | \\} | |
| 30 | , "Hello, world!" ++ os.line_sep); | |
| 31 | ||
| 32 | cases.addCase({ | |
| 33 | var tc = cases.create("multiple files with private function", | |
| 34 | \\use @import("std").io; | |
| 35 | \\use @import("foo.zig"); | |
| 36 | \\ | |
| 37 | \\pub fn main() -> %void { | |
| 38 | \\ privateFunction(); | |
| 39 | \\ %%stdout.printf("OK 2\n"); | |
| 40 | \\} | |
| 41 | \\ | |
| 42 | \\fn privateFunction() { | |
| 43 | \\ printText(); | |
| 44 | \\} | |
| 45 | , "OK 1\nOK 2\n"); | |
| 46 | ||
| 47 | tc.addSourceFile("foo.zig", | |
| 48 | \\use @import("std").io; | |
| 49 | \\ | |
| 50 | \\// purposefully conflicting function with main.zig | |
| 51 | \\// but it's private so it should be OK | |
| 52 | \\fn privateFunction() { | |
| 53 | \\ %%stdout.printf("OK 1\n"); | |
| 54 | \\} | |
| 55 | \\ | |
| 56 | \\pub fn printText() { | |
| 57 | \\ privateFunction(); | |
| 58 | \\} | |
| 59 | ); | |
| 60 | ||
| 61 | tc | |
| 62 | }); | |
| 63 | ||
| 64 | cases.addCase({ | |
| 65 | var tc = cases.create("import segregation", | |
| 66 | \\use @import("foo.zig"); | |
| 67 | \\use @import("bar.zig"); | |
| 68 | \\ | |
| 69 | \\pub fn main() -> %void { | |
| 70 | \\ foo_function(); | |
| 71 | \\ bar_function(); | |
| 72 | \\} | |
| 73 | , "OK\nOK\n"); | |
| 74 | ||
| 75 | tc.addSourceFile("foo.zig", | |
| 76 | \\use @import("std").io; | |
| 77 | \\pub fn foo_function() { | |
| 78 | \\ %%stdout.printf("OK\n"); | |
| 79 | \\} | |
| 80 | ); | |
| 81 | ||
| 82 | tc.addSourceFile("bar.zig", | |
| 83 | \\use @import("other.zig"); | |
| 84 | \\use @import("std").io; | |
| 85 | \\ | |
| 86 | \\pub fn bar_function() { | |
| 87 | \\ if (foo_function()) { | |
| 88 | \\ %%stdout.printf("OK\n"); | |
| 89 | \\ } | |
| 90 | \\} | |
| 91 | ); | |
| 92 | ||
| 93 | tc.addSourceFile("other.zig", | |
| 94 | \\pub fn foo_function() -> bool { | |
| 95 | \\ // this one conflicts with the one from foo | |
| 96 | \\ return true; | |
| 97 | \\} | |
| 98 | ); | |
| 99 | ||
| 100 | tc | |
| 101 | }); | |
| 102 | ||
| 103 | cases.addCase({ | |
| 104 | var tc = cases.create("two files use import each other", | |
| 105 | \\use @import("a.zig"); | |
| 106 | \\ | |
| 107 | \\pub fn main() -> %void { | |
| 108 | \\ ok(); | |
| 109 | \\} | |
| 110 | , "OK\n"); | |
| 111 | ||
| 112 | tc.addSourceFile("a.zig", | |
| 113 | \\use @import("b.zig"); | |
| 114 | \\const io = @import("std").io; | |
| 115 | \\ | |
| 116 | \\pub const a_text = "OK\n"; | |
| 117 | \\ | |
| 118 | \\pub fn ok() { | |
| 119 | \\ %%io.stdout.printf(b_text); | |
| 120 | \\} | |
| 121 | ); | |
| 122 | ||
| 123 | tc.addSourceFile("b.zig", | |
| 124 | \\use @import("a.zig"); | |
| 125 | \\ | |
| 126 | \\pub const b_text = a_text; | |
| 127 | ); | |
| 128 | ||
| 129 | tc | |
| 130 | }); | |
| 131 | ||
| 132 | cases.add("hello world without libc", | |
| 133 | \\const io = @import("std").io; | |
| 134 | \\ | |
| 135 | \\pub fn main() -> %void { | |
| 136 | \\ %%io.stdout.printf("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a')); | |
| 137 | \\} | |
| 138 | , "Hello, world!\n0012 012 a\n"); | |
| 139 | ||
| 140 | cases.addC("number literals", | |
| 141 | \\const c = @cImport(@cInclude("stdio.h")); | |
| 142 | \\ | |
| 143 | \\export fn main(argc: c_int, argv: &&u8) -> c_int { | |
| 144 | \\ _ = c.printf(c"0: %llu\n", | |
| 145 | \\ u64(0)); | |
| 146 | \\ _ = c.printf(c"320402575052271: %llu\n", | |
| 147 | \\ u64(320402575052271)); | |
| 148 | \\ _ = c.printf(c"0x01236789abcdef: %llu\n", | |
| 149 | \\ u64(0x01236789abcdef)); | |
| 150 | \\ _ = c.printf(c"0xffffffffffffffff: %llu\n", | |
| 151 | \\ u64(0xffffffffffffffff)); | |
| 152 | \\ _ = c.printf(c"0x000000ffffffffffffffff: %llu\n", | |
| 153 | \\ u64(0x000000ffffffffffffffff)); | |
| 154 | \\ _ = c.printf(c"0o1777777777777777777777: %llu\n", | |
| 155 | \\ u64(0o1777777777777777777777)); | |
| 156 | \\ _ = c.printf(c"0o0000001777777777777777777777: %llu\n", | |
| 157 | \\ u64(0o0000001777777777777777777777)); | |
| 158 | \\ _ = c.printf(c"0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n", | |
| 159 | \\ u64(0b1111111111111111111111111111111111111111111111111111111111111111)); | |
| 160 | \\ _ = c.printf(c"0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n", | |
| 161 | \\ u64(0b0000001111111111111111111111111111111111111111111111111111111111111111)); | |
| 162 | \\ | |
| 163 | \\ _ = c.printf(c"\n"); | |
| 164 | \\ | |
| 165 | \\ _ = c.printf(c"0.0: %a\n", | |
| 166 | \\ f64(0.0)); | |
| 167 | \\ _ = c.printf(c"0e0: %a\n", | |
| 168 | \\ f64(0e0)); | |
| 169 | \\ _ = c.printf(c"0.0e0: %a\n", | |
| 170 | \\ f64(0.0e0)); | |
| 171 | \\ _ = c.printf(c"000000000000000000000000000000000000000000000000000000000.0e0: %a\n", | |
| 172 | \\ f64(000000000000000000000000000000000000000000000000000000000.0e0)); | |
| 173 | \\ _ = c.printf(c"0.000000000000000000000000000000000000000000000000000000000e0: %a\n", | |
| 174 | \\ f64(0.000000000000000000000000000000000000000000000000000000000e0)); | |
| 175 | \\ _ = c.printf(c"0.0e000000000000000000000000000000000000000000000000000000000: %a\n", | |
| 176 | \\ f64(0.0e000000000000000000000000000000000000000000000000000000000)); | |
| 177 | \\ _ = c.printf(c"1.0: %a\n", | |
| 178 | \\ f64(1.0)); | |
| 179 | \\ _ = c.printf(c"10.0: %a\n", | |
| 180 | \\ f64(10.0)); | |
| 181 | \\ _ = c.printf(c"10.5: %a\n", | |
| 182 | \\ f64(10.5)); | |
| 183 | \\ _ = c.printf(c"10.5e5: %a\n", | |
| 184 | \\ f64(10.5e5)); | |
| 185 | \\ _ = c.printf(c"10.5e+5: %a\n", | |
| 186 | \\ f64(10.5e+5)); | |
| 187 | \\ _ = c.printf(c"50.0e-2: %a\n", | |
| 188 | \\ f64(50.0e-2)); | |
| 189 | \\ _ = c.printf(c"50e-2: %a\n", | |
| 190 | \\ f64(50e-2)); | |
| 191 | \\ | |
| 192 | \\ _ = c.printf(c"\n"); | |
| 193 | \\ | |
| 194 | \\ _ = c.printf(c"0x1.0: %a\n", | |
| 195 | \\ f64(0x1.0)); | |
| 196 | \\ _ = c.printf(c"0x10.0: %a\n", | |
| 197 | \\ f64(0x10.0)); | |
| 198 | \\ _ = c.printf(c"0x100.0: %a\n", | |
| 199 | \\ f64(0x100.0)); | |
| 200 | \\ _ = c.printf(c"0x103.0: %a\n", | |
| 201 | \\ f64(0x103.0)); | |
| 202 | \\ _ = c.printf(c"0x103.7: %a\n", | |
| 203 | \\ f64(0x103.7)); | |
| 204 | \\ _ = c.printf(c"0x103.70: %a\n", | |
| 205 | \\ f64(0x103.70)); | |
| 206 | \\ _ = c.printf(c"0x103.70p4: %a\n", | |
| 207 | \\ f64(0x103.70p4)); | |
| 208 | \\ _ = c.printf(c"0x103.70p5: %a\n", | |
| 209 | \\ f64(0x103.70p5)); | |
| 210 | \\ _ = c.printf(c"0x103.70p+5: %a\n", | |
| 211 | \\ f64(0x103.70p+5)); | |
| 212 | \\ _ = c.printf(c"0x103.70p-5: %a\n", | |
| 213 | \\ f64(0x103.70p-5)); | |
| 214 | \\ | |
| 215 | \\ _ = c.printf(c"\n"); | |
| 216 | \\ | |
| 217 | \\ _ = c.printf(c"0b10100.00010e0: %a\n", | |
| 218 | \\ f64(0b10100.00010e0)); | |
| 219 | \\ _ = c.printf(c"0o10700.00010e0: %a\n", | |
| 220 | \\ f64(0o10700.00010e0)); | |
| 221 | \\ | |
| 222 | \\ return 0; | |
| 223 | \\} | |
| 224 | , | |
| 225 | \\0: 0 | |
| 226 | \\320402575052271: 320402575052271 | |
| 227 | \\0x01236789abcdef: 320402575052271 | |
| 228 | \\0xffffffffffffffff: 18446744073709551615 | |
| 229 | \\0x000000ffffffffffffffff: 18446744073709551615 | |
| 230 | \\0o1777777777777777777777: 18446744073709551615 | |
| 231 | \\0o0000001777777777777777777777: 18446744073709551615 | |
| 232 | \\0b1111111111111111111111111111111111111111111111111111111111111111: 18446744073709551615 | |
| 233 | \\0b0000001111111111111111111111111111111111111111111111111111111111111111: 18446744073709551615 | |
| 234 | \\ | |
| 235 | \\0.0: 0x0p+0 | |
| 236 | \\0e0: 0x0p+0 | |
| 237 | \\0.0e0: 0x0p+0 | |
| 238 | \\000000000000000000000000000000000000000000000000000000000.0e0: 0x0p+0 | |
| 239 | \\0.000000000000000000000000000000000000000000000000000000000e0: 0x0p+0 | |
| 240 | \\0.0e000000000000000000000000000000000000000000000000000000000: 0x0p+0 | |
| 241 | \\1.0: 0x1p+0 | |
| 242 | \\10.0: 0x1.4p+3 | |
| 243 | \\10.5: 0x1.5p+3 | |
| 244 | \\10.5e5: 0x1.0059p+20 | |
| 245 | \\10.5e+5: 0x1.0059p+20 | |
| 246 | \\50.0e-2: 0x1p-1 | |
| 247 | \\50e-2: 0x1p-1 | |
| 248 | \\ | |
| 249 | \\0x1.0: 0x1p+0 | |
| 250 | \\0x10.0: 0x1p+4 | |
| 251 | \\0x100.0: 0x1p+8 | |
| 252 | \\0x103.0: 0x1.03p+8 | |
| 253 | \\0x103.7: 0x1.037p+8 | |
| 254 | \\0x103.70: 0x1.037p+8 | |
| 255 | \\0x103.70p4: 0x1.037p+12 | |
| 256 | \\0x103.70p5: 0x1.037p+13 | |
| 257 | \\0x103.70p+5: 0x1.037p+13 | |
| 258 | \\0x103.70p-5: 0x1.037p+3 | |
| 259 | \\ | |
| 260 | \\0b10100.00010e0: 0x1.41p+4 | |
| 261 | \\0o10700.00010e0: 0x1.1c0001p+12 | |
| 262 | \\ | |
| 263 | ); | |
| 264 | ||
| 265 | cases.add("order-independent declarations", | |
| 266 | \\const io = @import("std").io; | |
| 267 | \\const z = io.stdin_fileno; | |
| 268 | \\const x : @typeOf(y) = 1234; | |
| 269 | \\const y : u16 = 5678; | |
| 270 | \\pub fn main() -> %void { | |
| 271 | \\ var x_local : i32 = print_ok(x); | |
| 272 | \\} | |
| 273 | \\fn print_ok(val: @typeOf(x)) -> @typeOf(foo) { | |
| 274 | \\ %%io.stdout.printf("OK\n"); | |
| 275 | \\ return 0; | |
| 276 | \\} | |
| 277 | \\const foo : i32 = 0; | |
| 278 | , "OK\n"); | |
| 279 | ||
| 280 | cases.addC("expose function pointer to C land", | |
| 281 | \\const c = @cImport(@cInclude("stdlib.h")); | |
| 282 | \\ | |
| 283 | \\export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int { | |
| 284 | \\ const a_int = @ptrcast(&i32, a ?? unreachable); | |
| 285 | \\ const b_int = @ptrcast(&i32, b ?? unreachable); | |
| 286 | \\ if (*a_int < *b_int) { | |
| 287 | \\ -1 | |
| 288 | \\ } else if (*a_int > *b_int) { | |
| 289 | \\ 1 | |
| 290 | \\ } else { | |
| 291 | \\ c_int(0) | |
| 292 | \\ } | |
| 293 | \\} | |
| 294 | \\ | |
| 295 | \\export fn main() -> c_int { | |
| 296 | \\ var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 }; | |
| 297 | \\ | |
| 298 | \\ c.qsort(@ptrcast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn); | |
| 299 | \\ | |
| 300 | \\ for (array) |item, i| { | |
| 301 | \\ if (item != i) { | |
| 302 | \\ c.abort(); | |
| 303 | \\ } | |
| 304 | \\ } | |
| 305 | \\ | |
| 306 | \\ return 0; | |
| 307 | \\} | |
| 308 | , ""); | |
| 309 | ||
| 310 | cases.addC("casting between float and integer types", | |
| 311 | \\const c = @cImport(@cInclude("stdio.h")); | |
| 312 | \\export fn main(argc: c_int, argv: &&u8) -> c_int { | |
| 313 | \\ const small: f32 = 3.25; | |
| 314 | \\ const x: f64 = small; | |
| 315 | \\ const y = i32(x); | |
| 316 | \\ const z = f64(y); | |
| 317 | \\ _ = c.printf(c"%.2f\n%d\n%.2f\n%.2f\n", x, y, z, f64(-0.4)); | |
| 318 | \\ return 0; | |
| 319 | \\} | |
| 320 | , "3.25\n3\n3.00\n-0.40\n"); | |
| 321 | ||
| 322 | cases.add("same named methods in incomplete struct", | |
| 323 | \\const io = @import("std").io; | |
| 324 | \\ | |
| 325 | \\const Foo = struct { | |
| 326 | \\ field1: Bar, | |
| 327 | \\ | |
| 328 | \\ fn method(a: &const Foo) -> bool { true } | |
| 329 | \\}; | |
| 330 | \\ | |
| 331 | \\const Bar = struct { | |
| 332 | \\ field2: i32, | |
| 333 | \\ | |
| 334 | \\ fn method(b: &const Bar) -> bool { true } | |
| 335 | \\}; | |
| 336 | \\ | |
| 337 | \\pub fn main() -> %void { | |
| 338 | \\ const bar = Bar {.field2 = 13,}; | |
| 339 | \\ const foo = Foo {.field1 = bar,}; | |
| 340 | \\ if (!foo.method()) { | |
| 341 | \\ %%io.stdout.printf("BAD\n"); | |
| 342 | \\ } | |
| 343 | \\ if (!bar.method()) { | |
| 344 | \\ %%io.stdout.printf("BAD\n"); | |
| 345 | \\ } | |
| 346 | \\ %%io.stdout.printf("OK\n"); | |
| 347 | \\} | |
| 348 | , "OK\n"); | |
| 349 | ||
| 350 | cases.add("defer with only fallthrough", | |
| 351 | \\const io = @import("std").io; | |
| 352 | \\pub fn main() -> %void { | |
| 353 | \\ %%io.stdout.printf("before\n"); | |
| 354 | \\ defer %%io.stdout.printf("defer1\n"); | |
| 355 | \\ defer %%io.stdout.printf("defer2\n"); | |
| 356 | \\ defer %%io.stdout.printf("defer3\n"); | |
| 357 | \\ %%io.stdout.printf("after\n"); | |
| 358 | \\} | |
| 359 | , "before\nafter\ndefer3\ndefer2\ndefer1\n"); | |
| 360 | ||
| 361 | cases.add("defer with return", | |
| 362 | \\const io = @import("std").io; | |
| 363 | \\const os = @import("std").os; | |
| 364 | \\pub fn main() -> %void { | |
| 365 | \\ %%io.stdout.printf("before\n"); | |
| 366 | \\ defer %%io.stdout.printf("defer1\n"); | |
| 367 | \\ defer %%io.stdout.printf("defer2\n"); | |
| 368 | \\ if (os.args.count() == 1) return; | |
| 369 | \\ defer %%io.stdout.printf("defer3\n"); | |
| 370 | \\ %%io.stdout.printf("after\n"); | |
| 371 | \\} | |
| 372 | , "before\ndefer2\ndefer1\n"); | |
| 373 | ||
| 374 | cases.add("%defer and it fails", | |
| 375 | \\const io = @import("std").io; | |
| 376 | \\pub fn main() -> %void { | |
| 377 | \\ do_test() %% return; | |
| 378 | \\} | |
| 379 | \\fn do_test() -> %void { | |
| 380 | \\ %%io.stdout.printf("before\n"); | |
| 381 | \\ defer %%io.stdout.printf("defer1\n"); | |
| 382 | \\ %defer %%io.stdout.printf("deferErr\n"); | |
| 383 | \\ %return its_gonna_fail(); | |
| 384 | \\ defer %%io.stdout.printf("defer3\n"); | |
| 385 | \\ %%io.stdout.printf("after\n"); | |
| 386 | \\} | |
| 387 | \\error IToldYouItWouldFail; | |
| 388 | \\fn its_gonna_fail() -> %void { | |
| 389 | \\ return error.IToldYouItWouldFail; | |
| 390 | \\} | |
| 391 | , "before\ndeferErr\ndefer1\n"); | |
| 392 | ||
| 393 | cases.add("%defer and it passes", | |
| 394 | \\const io = @import("std").io; | |
| 395 | \\pub fn main() -> %void { | |
| 396 | \\ do_test() %% return; | |
| 397 | \\} | |
| 398 | \\fn do_test() -> %void { | |
| 399 | \\ %%io.stdout.printf("before\n"); | |
| 400 | \\ defer %%io.stdout.printf("defer1\n"); | |
| 401 | \\ %defer %%io.stdout.printf("deferErr\n"); | |
| 402 | \\ %return its_gonna_pass(); | |
| 403 | \\ defer %%io.stdout.printf("defer3\n"); | |
| 404 | \\ %%io.stdout.printf("after\n"); | |
| 405 | \\} | |
| 406 | \\fn its_gonna_pass() -> %void { } | |
| 407 | , "before\nafter\ndefer3\ndefer1\n"); | |
| 408 | ||
| 409 | cases.addCase({ | |
| 410 | var tc = cases.create("@embedFile", | |
| 411 | \\const foo_txt = @embedFile("foo.txt"); | |
| 412 | \\const io = @import("std").io; | |
| 413 | \\ | |
| 414 | \\pub fn main() -> %void { | |
| 415 | \\ %%io.stdout.printf(foo_txt); | |
| 416 | \\} | |
| 417 | , "1234\nabcd\n"); | |
| 418 | ||
| 419 | tc.addSourceFile("foo.txt", "1234\nabcd\n"); | |
| 420 | ||
| 421 | tc | |
| 422 | }); | |
| 423 | ||
| 424 | return cases.compare_output_tests; | |
| 425 | } | |
| 426 | ||
| 427 | const CompareOutputContext = struct { | |
| 428 | b: &build.Builder, | |
| 429 | compare_output_tests: &build.Step, | |
| 430 | test_index: usize, | |
| 431 | test_filter: ?[]const u8, | |
| 432 | ||
| 433 | const TestCase = struct { | |
| 434 | name: []const u8, | |
| 435 | sources: List(SourceFile), | |
| 436 | expected_output: []const u8, | |
| 437 | link_libc: bool, | |
| 438 | ||
| 439 | const SourceFile = struct { | |
| 440 | filename: []const u8, | |
| 441 | source: []const u8, | |
| 442 | }; | |
| 443 | ||
| 444 | pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) { | |
| 445 | %%self.sources.append(SourceFile { | |
| 446 | .filename = filename, | |
| 447 | .source = source, | |
| 448 | }); | |
| 449 | } | |
| 450 | }; | |
| 451 | ||
| 452 | pub fn create(self: &CompareOutputContext, name: []const u8, source: []const u8, | |
| 453 | expected_output: []const u8) -> TestCase | |
| 454 | { | |
| 455 | var tc = TestCase { | |
| 456 | .name = name, | |
| 457 | .sources = List(TestCase.SourceFile).init(self.b.allocator), | |
| 458 | .expected_output = expected_output, | |
| 459 | .link_libc = false, | |
| 460 | }; | |
| 461 | tc.addSourceFile("source.zig", source); | |
| 462 | return tc; | |
| 463 | } | |
| 464 | ||
| 465 | pub fn addC(self: &CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) { | |
| 466 | var tc = self.create(name, source, expected_output); | |
| 467 | tc.link_libc = true; | |
| 468 | self.addCase(tc); | |
| 469 | } | |
| 470 | ||
| 471 | pub fn add(self: &CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) { | |
| 472 | const tc = self.create(name, source, expected_output); | |
| 473 | self.addCase(tc); | |
| 474 | } | |
| 475 | ||
| 476 | pub fn addCase(self: &CompareOutputContext, case: &const TestCase) { | |
| 477 | const b = self.b; | |
| 478 | ||
| 479 | const root_src = %%os.path.join(b.allocator, "test_artifacts", case.sources.items[0].filename); | |
| 480 | const exe_path = %%os.path.join(b.allocator, "test_artifacts", "test"); | |
| 481 | ||
| 482 | for ([]bool{false, true}) |release| { | |
| 483 | const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "{} ({})", | |
| 484 | case.name, if (release) "release" else "debug"); | |
| 485 | if (const filter ?= self.test_filter) { | |
| 486 | if (mem.indexOf(u8, annotated_case_name, filter) == null) | |
| 487 | continue; | |
| 488 | } | |
| 489 | ||
| 490 | const exe = b.addExecutable("test", root_src); | |
| 491 | exe.setOutputPath(exe_path); | |
| 492 | exe.setRelease(release); | |
| 493 | if (case.link_libc) { | |
| 494 | exe.linkLibrary("c"); | |
| 495 | } | |
| 496 | ||
| 497 | for (case.sources.toSliceConst()) |src_file| { | |
| 498 | const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename); | |
| 499 | const write_src = b.addWriteFile(expanded_src_path, src_file.source); | |
| 500 | exe.step.dependOn(&write_src.step); | |
| 501 | } | |
| 502 | ||
| 503 | const run_and_cmp_output = RunCompareOutputStep.create(self, exe_path, annotated_case_name, | |
| 504 | case.expected_output); | |
| 505 | run_and_cmp_output.step.dependOn(&exe.step); | |
| 506 | ||
| 507 | self.compare_output_tests.dependOn(&run_and_cmp_output.step); | |
| 508 | } | |
| 509 | } | |
| 510 | }; | |
| 511 | ||
| 512 | const RunCompareOutputStep = struct { | |
| 513 | step: build.Step, | |
| 514 | context: &CompareOutputContext, | |
| 515 | exe_path: []const u8, | |
| 516 | name: []const u8, | |
| 517 | expected_output: []const u8, | |
| 518 | test_index: usize, | |
| 519 | ||
| 520 | pub fn create(context: &CompareOutputContext, exe_path: []const u8, | |
| 521 | name: []const u8, expected_output: []const u8) -> &RunCompareOutputStep | |
| 522 | { | |
| 523 | const allocator = context.b.allocator; | |
| 524 | const ptr = %%allocator.create(RunCompareOutputStep); | |
| 525 | *ptr = RunCompareOutputStep { | |
| 526 | .context = context, | |
| 527 | .exe_path = exe_path, | |
| 528 | .name = name, | |
| 529 | .expected_output = expected_output, | |
| 530 | .test_index = context.test_index, | |
| 531 | .step = build.Step.init("RunCompareOutput", allocator, make), | |
| 532 | }; | |
| 533 | context.test_index += 1; | |
| 534 | return ptr; | |
| 535 | } | |
| 536 | ||
| 537 | fn make(step: &build.Step) -> %void { | |
| 538 | const self = @fieldParentPtr(RunCompareOutputStep, "step", step); | |
| 539 | const b = self.context.b; | |
| 540 | ||
| 541 | const full_exe_path = b.pathFromRoot(self.exe_path); | |
| 542 | ||
| 543 | %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name); | |
| 544 | ||
| 545 | var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, &b.env_map, | |
| 546 | StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err| | |
| 547 | { | |
| 548 | debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); | |
| 549 | }; | |
| 550 | ||
| 551 | const term = child.wait() %% |err| { | |
| 552 | debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err)); | |
| 553 | }; | |
| 554 | switch (term) { | |
| 555 | Term.Clean => |code| { | |
| 556 | if (code != 0) { | |
| 557 | %%io.stderr.printf("Process {} exited with error code {}\n", full_exe_path, code); | |
| 558 | return error.TestFailed; | |
| 559 | } | |
| 560 | }, | |
| 561 | else => { | |
| 562 | %%io.stderr.printf("Process {} terminated unexpectedly\n", full_exe_path); | |
| 563 | return error.TestFailed; | |
| 564 | }, | |
| 565 | }; | |
| 566 | ||
| 567 | var stdout = %%Buffer0.initEmpty(b.allocator); | |
| 568 | var stderr = %%Buffer0.initEmpty(b.allocator); | |
| 569 | ||
| 570 | %%(??child.stdout).readAll(&stdout); | |
| 571 | %%(??child.stderr).readAll(&stderr); | |
| 572 | ||
| 573 | if (!mem.eql(u8, self.expected_output, stdout.toSliceConst())) { | |
| 574 | %%io.stderr.printf( | |
| 575 | \\ | |
| 576 | \\========= Expected this output: ========= | |
| 577 | \\{} | |
| 578 | \\================================================ | |
| 579 | \\{} | |
| 580 | \\ | |
| 581 | , self.expected_output, stdout.toSliceConst()); | |
| 582 | return error.TestFailed; | |
| 583 | } | |
| 584 | %%io.stderr.printf("OK\n"); | |
| 585 | } | |
| 586 | }; | |
| 587 |